diff --git a/src/arm/Add.go b/src/arm/Add.go index ba641a0..6881689 100644 --- a/src/arm/Add.go +++ b/src/arm/Add.go @@ -3,7 +3,7 @@ package arm import "git.urbach.dev/cli/q/src/cpu" // AddRegisterNumber adds a number to a register. -func AddRegisterNumber(destination cpu.Register, source cpu.Register, number int) uint32 { +func AddRegisterNumber(destination cpu.Register, source cpu.Register, number int) (code uint32, encodable bool) { return addRegisterNumber(destination, source, number, 0) } @@ -13,23 +13,23 @@ func AddRegisterRegister(destination cpu.Register, source cpu.Register, operand } // addRegisterNumber adds the register and optionally updates the condition flags based on the result. -func addRegisterNumber(destination cpu.Register, source cpu.Register, number int, flags uint32) uint32 { +func addRegisterNumber(destination cpu.Register, source cpu.Register, number int, flags uint32) (code uint32, encodable bool) { shift := uint32(0) if number > mask12 { if number&mask12 != 0 { - panic("number can't be encoded") + return 0, false } shift = 1 number >>= 12 if number > mask12 { - panic("number can't be encoded") + return 0, false } } - return flags<<29 | 0b100100010<<23 | shift<<22 | reg2Imm(destination, source, number) + return flags<<29 | 0b100100010<<23 | shift<<22 | reg2Imm(destination, source, number), true } // addRegisterRegister adds the registers and optionally updates the condition flags based on the result. diff --git a/src/arm/Add_test.go b/src/arm/Add_test.go index 3c75ecc..d00d9f6 100644 --- a/src/arm/Add_test.go +++ b/src/arm/Add_test.go @@ -21,7 +21,8 @@ func TestAddRegisterNumber(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("add %s, %s, %d", pattern.Destination, pattern.Source, pattern.Number) - code := arm.AddRegisterNumber(pattern.Destination, pattern.Source, pattern.Number) + code, encodable := arm.AddRegisterNumber(pattern.Destination, pattern.Source, pattern.Number) + assert.True(t, encodable) assert.DeepEqual(t, code, pattern.Code) } } diff --git a/src/arm/Compare.go b/src/arm/Compare.go index eb5a97e..5d4cf78 100644 --- a/src/arm/Compare.go +++ b/src/arm/Compare.go @@ -3,7 +3,7 @@ package arm import "git.urbach.dev/cli/q/src/cpu" // CompareRegisterNumber is an alias for a subtraction that updates the conditional flags and discards the result. -func CompareRegisterNumber(register cpu.Register, number int) uint32 { +func CompareRegisterNumber(register cpu.Register, number int) (code uint32, encodable bool) { if number < 0 { return addRegisterNumber(ZR, register, -number, 1) } diff --git a/src/arm/Compare_test.go b/src/arm/Compare_test.go index 4580aea..16cecdd 100644 --- a/src/arm/Compare_test.go +++ b/src/arm/Compare_test.go @@ -22,7 +22,8 @@ func TestCompareRegisterNumber(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("cmp %s, %d", pattern.Source, pattern.Number) - code := arm.CompareRegisterNumber(pattern.Source, pattern.Number) + code, encodable := arm.CompareRegisterNumber(pattern.Source, pattern.Number) + assert.True(t, encodable) assert.DeepEqual(t, code, pattern.Code) } } diff --git a/src/arm/Move.go b/src/arm/Move.go index e1bfcb3..3c52b9c 100644 --- a/src/arm/Move.go +++ b/src/arm/Move.go @@ -72,7 +72,8 @@ func MoveRegisterNumberSI(destination cpu.Register, number int) (uint32, bool) { // MoveRegisterRegister copies a register to another register. func MoveRegisterRegister(destination cpu.Register, source cpu.Register) uint32 { if source == SP || destination == SP { - return AddRegisterNumber(destination, source, 0) + code, _ := AddRegisterNumber(destination, source, 0) + return code } return OrRegisterRegister(destination, ZR, source) diff --git a/src/arm/Sub.go b/src/arm/Sub.go index 37d0a9e..39982a8 100644 --- a/src/arm/Sub.go +++ b/src/arm/Sub.go @@ -3,7 +3,7 @@ package arm import "git.urbach.dev/cli/q/src/cpu" // SubRegisterNumber subtracts a number from the given register. -func SubRegisterNumber(destination cpu.Register, source cpu.Register, number int) uint32 { +func SubRegisterNumber(destination cpu.Register, source cpu.Register, number int) (code uint32, encodable bool) { return subRegisterNumber(destination, source, number, 0) } @@ -13,23 +13,23 @@ func SubRegisterRegister(destination cpu.Register, source cpu.Register, operand } // subRegisterNumber subtracts the register and optionally updates the condition flags based on the result. -func subRegisterNumber(destination cpu.Register, source cpu.Register, number int, flags uint32) uint32 { +func subRegisterNumber(destination cpu.Register, source cpu.Register, number int, flags uint32) (code uint32, encodable bool) { shift := uint32(0) if number > mask12 { if number&mask12 != 0 { - panic("number can't be encoded") + return 0, false } shift = 1 number >>= 12 if number > mask12 { - panic("number can't be encoded") + return 0, false } } - return flags<<29 | 0b110100010<<23 | shift<<22 | reg2Imm(destination, source, number) + return flags<<29 | 0b110100010<<23 | shift<<22 | reg2Imm(destination, source, number), true } // subRegisterRegister subtracts the registers and optionally updates the condition flags based on the result. diff --git a/src/arm/Sub_test.go b/src/arm/Sub_test.go index e508c75..2256704 100644 --- a/src/arm/Sub_test.go +++ b/src/arm/Sub_test.go @@ -22,7 +22,8 @@ func TestSubRegisterNumber(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("sub %s, %s, %d", pattern.Destination, pattern.Source, pattern.Number) - code := arm.SubRegisterNumber(pattern.Destination, pattern.Source, pattern.Number) + code, encodable := arm.SubRegisterNumber(pattern.Destination, pattern.Source, pattern.Number) + assert.True(t, encodable) assert.DeepEqual(t, code, pattern.Code) } } diff --git a/src/asmc/compileARM.go b/src/asmc/ARM.go similarity index 88% rename from src/asmc/compileARM.go rename to src/asmc/ARM.go index 6f0c122..c6439b3 100644 --- a/src/asmc/compileARM.go +++ b/src/asmc/ARM.go @@ -8,8 +8,45 @@ import ( "git.urbach.dev/cli/q/src/asm" ) -func (c *compiler) compileARM(x asm.Instruction) { +func (c *compiler) ARM(x asm.Instruction) { switch x.Mnemonic { + case asm.MOVE: + switch x.Type { + case asm.TypeRegisterRegister: + operands := c.assembler.Param.RegisterRegister[x.Index] + c.append(arm.MoveRegisterRegister(operands.Destination, operands.Source)) + + case asm.TypeRegisterNumber: + operands := c.assembler.Param.RegisterNumber[x.Index] + c.code = arm.MoveRegisterNumber(c.code, operands.Register, operands.Number) + + case asm.TypeRegisterLabel: + operands := c.assembler.Param.RegisterLabel[x.Index] + position := Address(len(c.code)) + c.append(arm.LoadAddress(operands.Register, 0)) + + if operands.Label.Type == asm.DataLabel { + c.dataPointers = append(c.dataPointers, &pointer{ + Position: position, + OpSize: 0, + Size: 4, + Resolve: func() Address { + destination, exists := c.dataLabels[operands.Label.Name] + + if !exists { + panic("unknown label") + } + + destination += c.dataStart - c.codeStart + distance := destination - position + 8 + return arm.LoadAddress(operands.Register, int(distance)) + }, + }) + } else { + panic("not implemented") + } + } + case asm.CALL: switch x.Type { case asm.TypeLabel: @@ -84,11 +121,19 @@ func (c *compiler) compileARM(x asm.Instruction) { } } + case asm.RETURN: + c.append(arm.LoadPair(arm.FP, arm.LR, arm.SP, 16)) + c.append(arm.Return()) + + case asm.SYSCALL: + c.append(arm.Syscall()) + case asm.PUSH: switch x.Type { case asm.TypeRegister: operand := c.assembler.Param.Register[x.Index] - c.append(arm.SubRegisterNumber(arm.SP, arm.SP, 16)) + code, _ := arm.SubRegisterNumber(arm.SP, arm.SP, 16) + c.append(code) c.append(arm.StoreRegister(operand.Register, arm.SP, 0, 8)) } @@ -97,7 +142,8 @@ func (c *compiler) compileARM(x asm.Instruction) { case asm.TypeRegister: operand := c.assembler.Param.Register[x.Index] c.append(arm.LoadRegister(operand.Register, arm.SP, 0, 8)) - c.append(arm.AddRegisterNumber(arm.SP, arm.SP, 16)) + code, _ := arm.AddRegisterNumber(arm.SP, arm.SP, 16) + c.append(code) } case asm.AND: @@ -158,7 +204,15 @@ func (c *compiler) compileARM(x asm.Instruction) { switch x.Type { case asm.TypeRegisterNumber: operand := c.assembler.Param.RegisterNumber[x.Index] - c.append(arm.AddRegisterNumber(operand.Register, operand.Register, operand.Number)) + code, encodable := arm.AddRegisterNumber(operand.Register, operand.Register, operand.Number) + + if encodable { + c.append(code) + } else { + tmp := arm.X28 + c.code = arm.MoveRegisterNumber(c.code, tmp, operand.Number) + c.append(arm.AddRegisterRegister(operand.Register, operand.Register, tmp)) + } case asm.TypeRegisterRegister: operand := c.assembler.Param.RegisterRegister[x.Index] c.append(arm.AddRegisterRegister(operand.Destination, operand.Destination, operand.Source)) @@ -168,7 +222,15 @@ func (c *compiler) compileARM(x asm.Instruction) { switch x.Type { case asm.TypeRegisterNumber: operand := c.assembler.Param.RegisterNumber[x.Index] - c.append(arm.SubRegisterNumber(operand.Register, operand.Register, operand.Number)) + code, encodable := arm.SubRegisterNumber(operand.Register, operand.Register, operand.Number) + + if encodable { + c.append(code) + } else { + tmp := arm.X28 + c.code = arm.MoveRegisterNumber(c.code, tmp, operand.Number) + c.append(arm.SubRegisterRegister(operand.Register, operand.Register, tmp)) + } case asm.TypeRegisterRegister: operand := c.assembler.Param.RegisterRegister[x.Index] c.append(arm.SubRegisterRegister(operand.Destination, operand.Destination, operand.Source)) @@ -178,7 +240,15 @@ func (c *compiler) compileARM(x asm.Instruction) { switch x.Type { case asm.TypeRegisterNumber: operand := c.assembler.Param.RegisterNumber[x.Index] - c.append(arm.CompareRegisterNumber(operand.Register, operand.Number)) + code, encodable := arm.CompareRegisterNumber(operand.Register, operand.Number) + + if encodable { + c.append(code) + } else { + tmp := arm.X28 + c.code = arm.MoveRegisterNumber(c.code, tmp, operand.Number) + c.append(arm.CompareRegisterRegister(operand.Register, tmp)) + } case asm.TypeRegisterRegister: operand := c.assembler.Param.RegisterRegister[x.Index] c.append(arm.CompareRegisterRegister(operand.Destination, operand.Source)) @@ -219,43 +289,6 @@ func (c *compiler) compileARM(x asm.Instruction) { case asm.JE, asm.JNE, asm.JG, asm.JGE, asm.JL, asm.JLE, asm.JUMP: c.jumpARM(x) - case asm.MOVE: - switch x.Type { - case asm.TypeRegisterRegister: - operands := c.assembler.Param.RegisterRegister[x.Index] - c.append(arm.MoveRegisterRegister(operands.Destination, operands.Source)) - - case asm.TypeRegisterNumber: - operands := c.assembler.Param.RegisterNumber[x.Index] - c.code = arm.MoveRegisterNumber(c.code, operands.Register, operands.Number) - - case asm.TypeRegisterLabel: - operands := c.assembler.Param.RegisterLabel[x.Index] - position := Address(len(c.code)) - c.append(arm.LoadAddress(operands.Register, 0)) - - if operands.Label.Type == asm.DataLabel { - c.dataPointers = append(c.dataPointers, &pointer{ - Position: position, - OpSize: 0, - Size: 4, - Resolve: func() Address { - destination, exists := c.dataLabels[operands.Label.Name] - - if !exists { - panic("unknown label") - } - - destination += c.dataStart - c.codeStart - distance := destination - position + 8 - return arm.LoadAddress(operands.Register, int(distance)) - }, - }) - } else { - panic("not implemented") - } - } - case asm.SHIFTL: switch x.Type { case asm.TypeRegisterNumber: @@ -274,13 +307,6 @@ func (c *compiler) compileARM(x asm.Instruction) { panic("not implemented") } - case asm.RETURN: - c.append(arm.LoadPair(arm.FP, arm.LR, arm.SP, 16)) - c.append(arm.Return()) - - case asm.SYSCALL: - c.append(arm.Syscall()) - default: panic("unknown mnemonic: " + x.Mnemonic.String()) } diff --git a/src/asmc/Finalize.go b/src/asmc/Finalize.go index e2b935c..ec9e678 100644 --- a/src/asmc/Finalize.go +++ b/src/asmc/Finalize.go @@ -28,12 +28,12 @@ func Finalize(a *asm.Assembler, dlls dll.List) ([]byte, []byte) { switch config.TargetArch { case config.ARM: for _, x := range a.Instructions { - c.compileARM(x) + c.ARM(x) } case config.X86: for _, x := range a.Instructions { - c.compileX86(x) + c.X86(x) } } diff --git a/src/asmc/compileX86.go b/src/asmc/X86.go similarity index 99% rename from src/asmc/compileX86.go rename to src/asmc/X86.go index e54435a..448ec41 100644 --- a/src/asmc/compileX86.go +++ b/src/asmc/X86.go @@ -5,8 +5,30 @@ import ( "git.urbach.dev/cli/q/src/x86" ) -func (c *compiler) compileX86(x asm.Instruction) { +func (c *compiler) X86(x asm.Instruction) { switch x.Mnemonic { + case asm.MOVE: + c.move(x) + + case asm.CALL: + c.call(x) + + case asm.LABEL: + label := c.assembler.Param.Label[x.Index] + c.codeLabels[label.Name] = Address(len(c.code)) + + case asm.LOAD: + c.load(x) + + case asm.STORE: + c.store(x) + + case asm.RETURN: + c.code = x86.Return(c.code) + + case asm.SYSCALL: + c.code = x86.Syscall(c.code) + case asm.ADD: switch x.Type { case asm.TypeRegisterNumber: @@ -81,9 +103,6 @@ func (c *compiler) compileX86(x asm.Instruction) { } } - case asm.CALL: - c.call(x) - case asm.COMMENT: return @@ -103,16 +122,6 @@ func (c *compiler) compileX86(x asm.Instruction) { case asm.JE, asm.JNE, asm.JG, asm.JGE, asm.JL, asm.JLE, asm.JUMP: c.jumpX86(x) - case asm.LABEL: - label := c.assembler.Param.Label[x.Index] - c.codeLabels[label.Name] = Address(len(c.code)) - - case asm.LOAD: - c.load(x) - - case asm.MOVE: - c.move(x) - case asm.NEGATE: switch x.Type { case asm.TypeRegister: @@ -147,9 +156,6 @@ func (c *compiler) compileX86(x asm.Instruction) { c.code = x86.PushRegister(c.code, operands.Register) } - case asm.RETURN: - c.code = x86.Return(c.code) - case asm.SHIFTL: switch x.Type { case asm.TypeRegisterNumber: @@ -168,12 +174,6 @@ func (c *compiler) compileX86(x asm.Instruction) { panic("not implemented") } - case asm.STORE: - c.store(x) - - case asm.SYSCALL: - c.code = x86.Syscall(c.code) - case asm.XOR: switch x.Type { case asm.TypeRegisterNumber: diff --git a/src/asmc/bench_test.go b/src/asmc/bench_test.go new file mode 100644 index 0000000..179c6c1 --- /dev/null +++ b/src/asmc/bench_test.go @@ -0,0 +1,18 @@ +package asmc_test + +import ( + "testing" + + "git.urbach.dev/cli/q/src/asm" + "git.urbach.dev/cli/q/src/asmc" + "git.urbach.dev/cli/q/src/cpu" +) + +func BenchmarkFinalize(b *testing.B) { + a := asm.Assembler{} + a.RegisterNumber(asm.MOVE, cpu.Register(0), 0) + + for b.Loop() { + asmc.Finalize(&a, nil) + } +}