Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
0999f28
Refactored base instruction types
RealA10N May 9, 2025
43e7457
Fixed AArch64 `adds` definition to use new instruction API
RealA10N May 9, 2025
27dfe5c
(Hopefully) fixed AArch64 `add` and `adds` tests
RealA10N May 9, 2025
4b46a38
Updated `b` AArch64 instruction to new instruction API
RealA10N May 9, 2025
b6b9424
Fixed `b.cond`
RealA10N May 31, 2025
8b4d0e6
Fixed `bl`
RealA10N May 31, 2025
627e458
Fixed `movz`
RealA10N May 31, 2025
9be7356
Fixed `ret`
RealA10N May 31, 2025
9804586
Fixed `sub`
RealA10N May 31, 2025
9deea86
Added internal validation to `b`
RealA10N May 31, 2025
4fb0057
Added `New` functions for instruction definitions
RealA10N May 31, 2025
cc5ae72
Fixed all aarch64 isa instructions
RealA10N May 31, 2025
2bb1316
Fixed `gen` package tests
RealA10N May 31, 2025
538483a
Moved general asserts to `gen` package
RealA10N May 31, 2025
51e1dbd
Added `AssertArgumentIsTyped`
RealA10N May 31, 2025
00cedb7
Added basic `usm` isa
RealA10N May 31, 2025
768c326
`usm` isa now supports all integer types
RealA10N May 31, 2025
83b4d14
Added `ret` instruction to `usm` isa
RealA10N May 31, 2025
1e8b7f9
Fixed `add` AArch64 generation tests
RealA10N May 31, 2025
d4ccb1d
Separated validation step from generation step
RealA10N May 31, 2025
937f72c
Added `IsCritical` to existing usm instructions
RealA10N May 31, 2025
ae6c7bf
Added `call` usm instruction
RealA10N May 31, 2025
035e55b
Fixed DCE tests
RealA10N Jun 1, 2025
d620279
DCE optimization now supported
RealA10N Jun 1, 2025
42a8891
Renamed `ArgumentToType`
RealA10N Jun 2, 2025
64671ea
Added the `jz` instruction to `usm` ISA
RealA10N Jun 2, 2025
f49bab8
Fixed error message
RealA10N Jun 2, 2025
962e24f
Added `phi` instruction to `usm` ISA
RealA10N Jun 2, 2025
e8b9608
Added `j` instruction to `usm` ISA
RealA10N Jun 2, 2025
b93664e
Refactored SSA code, Added strict validation to `ret`
RealA10N Jun 2, 2025
bdf0085
Added `usm` ssa transformation
RealA10N Jun 2, 2025
7c3ea64
Removed old `usm64` isa
RealA10N Jun 2, 2025
89dfd2d
Update gen/assert.go
RealA10N Jun 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@

# build files
build
usm

# coverage
coverage.txt
Expand Down
7 changes: 5 additions & 2 deletions aarch64/codegen/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,17 @@ func NewFileCodegenContext(file *gen.FileInfo) *FileCodegenContext {
functionIndices := make(map[*gen.FunctionInfo]uint32, len(file.Functions))

offset := uint64(0)
for idx, function := range file.Functions {
idx := uint32(0)
for _, function := range file.Functions {
if function.IsDefined() {
functionOffsets[function] = offset
functionIndices[function] = uint32(idx)
functionIndices[function] = idx

functionSize := uint64(function.Size()) * 4 // TODO: handle overflow?
offset += functionSize
}

idx++
}

return &FileCodegenContext{
Expand Down
10 changes: 5 additions & 5 deletions aarch64/codegen/instruction.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ import (
)

type Instruction interface {
gen.BaseInstruction
gen.InstructionDefinition

// Converts the abstract instruction representation into a concrete binary
// instruction.
Generate(
*InstructionCodegenContext,
Codegen(
ctx *InstructionCodegenContext,
) (instructions.Instruction, core.ResultList)
}

Expand All @@ -34,7 +34,7 @@ func (ctx *InstructionCodegenContext) InstructionOffsetInFile() uint64 {
func (ctx *InstructionCodegenContext) Codegen(
buffer *bytes.Buffer,
) core.ResultList {
instruction, ok := ctx.Instruction.(Instruction)
instruction, ok := ctx.InstructionInfo.Definition.(Instruction)
if !ok {
return list.FromSingle(core.Result{
{
Expand All @@ -45,7 +45,7 @@ func (ctx *InstructionCodegenContext) Codegen(
})
}

binaryInst, results := instruction.Generate(ctx)
binaryInst, results := instruction.Codegen(ctx)
if !results.IsEmpty() {
return results
}
Expand Down
77 changes: 32 additions & 45 deletions aarch64/isa/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,79 +9,59 @@ import (
"alon.kr/x/usm/gen"
)

type BaseAdd struct {
NonBranchingInstruction
type Add struct {
gen.NonBranchingInstruction
}

func (BaseAdd) Operator() string {
return "add"
}

type AddReg struct {
BaseAdd
instructions.AddShiftedRegister
}

func (i AddReg) Generate(
*aarch64codegen.InstructionCodegenContext,
) (instructions.Instruction, core.ResultList) {
return i, core.ResultList{}
}

type AddImm struct {
BaseAdd
instructions.AddImmediate
func NewAdd() gen.InstructionDefinition {
return Add{}
}

func (i AddImm) Generate(
*aarch64codegen.InstructionCodegenContext,
) (instructions.Instruction, core.ResultList) {
return i, core.ResultList{}
func (Add) Operator(*gen.InstructionInfo) string {
return "add"
}

type AddDefinition struct{}

func (d AddDefinition) buildRegisterVariant(
func (add Add) codegenRegisterVariant(
info *gen.InstructionInfo,
) (gen.BaseInstruction, core.ResultList) {
) (instructions.Instruction, core.ResultList) {
Xd, Xn, Xm, results := aarch64translation.BinaryInstructionToAarch64(info)
if !results.IsEmpty() {
return nil, results
}

return AddReg{
AddShiftedRegister: instructions.NewAddShiftedRegister(Xd, Xn, Xm),
}, core.ResultList{}
inst := instructions.NewAddShiftedRegister(Xd, Xn, Xm)
return inst, core.ResultList{}
}

func (AddDefinition) buildImmediateVariant(
func (add Add) codegenImmediateVariant(
info *gen.InstructionInfo,
) (gen.BaseInstruction, core.ResultList) {
) (instructions.Instruction, core.ResultList) {
Xd, Xn, imm, results := aarch64translation.Immediate12InstructionToAarch64(info)
if !results.IsEmpty() {
return nil, results
}

return AddImm{
AddImmediate: instructions.NewAddImmediate(Xd, Xn, imm),
}, core.ResultList{}
inst := instructions.NewAddImmediate(Xd, Xn, imm)
return inst, core.ResultList{}
}

func (d AddDefinition) BuildInstruction(
info *gen.InstructionInfo,
) (gen.BaseInstruction, core.ResultList) {
func (add Add) Codegen(
ctx *aarch64codegen.InstructionCodegenContext,
) (instructions.Instruction, core.ResultList) {
// TODO: this implementation is very similar to the one in adds.go, and possibly
// other binary arithmetic instructions. Consider refactoring this.

info := ctx.InstructionInfo
results := aarch64translation.ValidateBinaryInstruction(info)
if !results.IsEmpty() {
return nil, results
}

switch info.Arguments[1].(type) {
case *gen.RegisterArgumentInfo:
return d.buildRegisterVariant(info)

return add.codegenRegisterVariant(info)
case *gen.ImmediateInfo:
return d.buildImmediateVariant(info)

return add.codegenImmediateVariant(info)
default:
return nil, list.FromSingle(core.Result{
{
Expand All @@ -93,6 +73,13 @@ func (d AddDefinition) BuildInstruction(
}
}

func NewAddInstructionDefinition() gen.InstructionDefinition {
return AddDefinition{}
func (add Add) Validate(
info *gen.InstructionInfo,
) core.ResultList {
// TODO: this is a pretty hacky way to validate the instruction: we create
// a "mock" generation context, and then try to generate the binary
// representation of the instruction.
ctx := aarch64codegen.InstructionCodegenContext{InstructionInfo: info}
_, results := add.Codegen(&ctx)
return results
}
25 changes: 12 additions & 13 deletions aarch64/isa/add_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func buildInstructionFromSource(
t *testing.T,
def gen.InstructionDefinition,
src string,
) aarch64codegen.Instruction {
) (*gen.InstructionInfo, aarch64codegen.Instruction) {
srcView := core.NewSourceView(src)

tokenizer := lex.NewTokenizer()
Expand All @@ -39,18 +39,14 @@ func buildInstructionFromSource(
NewFunctionGenerationContext()

generator := gen.NewInstructionGenerator()
baseInfo, results := generator.Generate(ctx, node)
info, results := generator.Generate(ctx, node)
assert.True(t, results.IsEmpty())
assert.NotNil(t, baseInfo)
assert.NotNil(t, info)

baseInst, results := def.BuildInstruction(baseInfo)
assert.True(t, results.IsEmpty())
assert.NotNil(t, baseInst)

inst, ok := baseInst.(aarch64codegen.Instruction)
inst, ok := info.Definition.(aarch64codegen.Instruction)
assert.True(t, ok)

return inst
return info, inst
}

func assertExpectedCodegen(
Expand All @@ -59,17 +55,20 @@ func assertExpectedCodegen(
expected instructions.Instruction,
src string,
) {
inst := buildInstructionFromSource(t, def, src)
info, inst := buildInstructionFromSource(t, def, src)

generationContext := &aarch64codegen.InstructionCodegenContext{
InstructionInfo: info,
}

generationContext := &aarch64codegen.InstructionCodegenContext{}
code, results := inst.Generate(generationContext)
code, results := inst.Codegen(generationContext)
assert.True(t, results.IsEmpty())

assert.Equal(t, expected.Binary(), code.Binary())
}

func TestAddExpectedCodegen(t *testing.T) {
def := aarch64isa.NewAddInstructionDefinition()
def := aarch64isa.NewAdd()

testCases := []struct {
src string
Expand Down
73 changes: 30 additions & 43 deletions aarch64/isa/adds.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,78 +9,58 @@ import (
"alon.kr/x/usm/gen"
)

type BaseAdds struct {
NonBranchingInstruction
type Adds struct {
gen.NonBranchingInstruction
}

func (BaseAdds) Operator() string {
return "adds"
}

type AddsReg struct {
BaseAdd
instructions.AddShiftedRegister
func NewAdds() gen.InstructionDefinition {
return Adds{}
}

func (i AddsReg) Generate(
*aarch64codegen.InstructionCodegenContext,
) (instructions.Instruction, core.ResultList) {
return i, core.ResultList{}
}

type AddsImm struct {
BaseAdd
instructions.AddsImmediate
}

func (i AddsImm) Generate(
*aarch64codegen.InstructionCodegenContext,
) (instructions.Instruction, core.ResultList) {
return i, core.ResultList{}
func (Adds) Operator(*gen.InstructionInfo) string {
return "adds"
}

type AddsDefinition struct{}

func (d AddsDefinition) buildRegisterVariant(
func (adds Adds) codegenRegisterVariant(
info *gen.InstructionInfo,
) (gen.BaseInstruction, core.ResultList) {
) (instructions.Instruction, core.ResultList) {
Xd, Xn, Xm, results := aarch64translation.BinaryInstructionToAarch64(info)
if !results.IsEmpty() {
return nil, results
}

return AddReg{
AddShiftedRegister: instructions.NewAddsShiftedRegister(Xd, Xn, Xm),
}, core.ResultList{}
inst := instructions.NewAddsShiftedRegister(Xd, Xn, Xm)
return inst, core.ResultList{}
}

func (AddsDefinition) buildImmediateVariant(
func (adds Adds) codegenImmediateVariant(
info *gen.InstructionInfo,
) (gen.BaseInstruction, core.ResultList) {
) (instructions.Instruction, core.ResultList) {
Xd, Xn, imm, results := aarch64translation.Immediate12GPRegisterTargetInstructionToAarch64(info)
if !results.IsEmpty() {
return nil, results
}

return AddsImm{
AddsImmediate: instructions.NewAddsImmediate(Xd, Xn, imm),
}, core.ResultList{}
inst := instructions.NewAddsImmediate(Xd, Xn, imm)
return inst, core.ResultList{}
}

func (d AddsDefinition) BuildInstruction(
info *gen.InstructionInfo,
) (gen.BaseInstruction, core.ResultList) {
func (adds Adds) Codegen(
ctx *aarch64codegen.InstructionCodegenContext,
) (instructions.Instruction, core.ResultList) {
info := ctx.InstructionInfo

results := aarch64translation.ValidateBinaryInstruction(info)
if !results.IsEmpty() {
return nil, results
}

switch info.Arguments[1].(type) {
case *gen.RegisterArgumentInfo:
return d.buildRegisterVariant(info)
return adds.codegenRegisterVariant(info)

case *gen.ImmediateInfo:
return d.buildImmediateVariant(info)
return adds.codegenImmediateVariant(info)

default:
return nil, list.FromSingle(core.Result{
Expand All @@ -93,6 +73,13 @@ func (d AddsDefinition) BuildInstruction(
}
}

func NewAddsInstructionDefinition() gen.InstructionDefinition {
return AddsDefinition{}
func (adds Adds) Validate(
info *gen.InstructionInfo,
) core.ResultList {
// TODO: this is a pretty hacky way to validate the instruction: we create
// a "mock" generation context, and then try to generate the binary
// representation of the instruction.
ctx := aarch64codegen.InstructionCodegenContext{InstructionInfo: info}
_, results := adds.Codegen(&ctx)
return results
}
Loading