From 99ef02bbd678f34380d192b49710a04b946b6fae Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Fri, 14 Mar 2025 21:16:35 +0100 Subject: [PATCH] Implemented more move instructions on arm64 --- src/arm/Move.go | 40 ++++++++++++++++++++++++++++++++++------ src/arm/Move_test.go | 25 +++++++++++++++++++++++-- src/arm/arm_test.go | 1 - src/asmc/compileARM.go | 15 ++++++++------- src/asmc/movARM.go | 16 ++++++++++++++++ 5 files changed, 81 insertions(+), 16 deletions(-) create mode 100644 src/asmc/movARM.go diff --git a/src/arm/Move.go b/src/arm/Move.go index e18e81d..c687c2a 100644 --- a/src/arm/Move.go +++ b/src/arm/Move.go @@ -2,6 +2,7 @@ package arm import ( "git.urbach.dev/cli/q/src/cpu" + "git.urbach.dev/cli/q/src/sizeof" ) // MoveRegisterRegister copies a register to another register. @@ -13,18 +14,45 @@ func MoveRegisterRegister(destination cpu.Register, source cpu.Register) uint32 return OrRegisterRegister(destination, ZR, source) } -// MoveRegisterNumber moves an integer into the given register. -func MoveRegisterNumber(destination cpu.Register, number int) uint32 { +// MoveRegisterNumber moves a number into the given register. +func MoveRegisterNumber(destination cpu.Register, number int) (uint32, bool) { if number < 0 { - return MoveInvertedWideImmediate(destination, ^number) + return MoveInvertedWideImmediate(destination, ^number, 0), true } - return MoveZero(destination, 0, uint16(number)) + if sizeof.Signed(number) <= 2 { + return MoveZero(destination, 0, uint16(number)), true + } + + if (number&0xFFFFFFFFFFFF == 0xFFFFFFFFFFFF) && sizeof.Signed(number>>48) <= 2 { + return MoveInvertedWideImmediate(destination, (^number)>>48, 3), true + } + + code, encodable := MoveBitmaskImmediate(destination, number) + + if encodable { + return code, true + } + + if (number&0xFFFFFFFF == 0xFFFFFFFF) && sizeof.Signed(number>>32) <= 2 { + return MoveInvertedWideImmediate(destination, (^number)>>32, 2), true + } + + if (number&0xFFFF == 0xFFFF) && sizeof.Signed(number>>16) <= 2 { + return MoveInvertedWideImmediate(destination, (^number)>>16, 1), true + } + + return 0, false +} + +// MoveBitmaskImmediate moves a bitmask immediate value to a register. +func MoveBitmaskImmediate(destination cpu.Register, number int) (uint32, bool) { + return OrRegisterNumber(destination, ZR, number) } // MoveInvertedWideImmediate moves an inverted 16-bit immediate value to a register. -func MoveInvertedWideImmediate(destination cpu.Register, number int) uint32 { - return 0b100100101<<23 | regImm(destination, number) +func MoveInvertedWideImmediate(destination cpu.Register, number int, shift uint32) uint32 { + return 0b100100101<<23 | shift<<21 | regImm(destination, number) } // MoveKeep moves a 16-bit integer into the given register and keeps all other bits. diff --git a/src/arm/Move_test.go b/src/arm/Move_test.go index ba8e5cc..6e02a4e 100644 --- a/src/arm/Move_test.go +++ b/src/arm/Move_test.go @@ -33,15 +33,36 @@ func TestMoveRegisterNumber(t *testing.T) { Number int Code uint32 }{ + // MOVZ {arm.X0, 0, 0xD2800000}, {arm.X0, 1, 0xD2800020}, + + // MOV (bitmask immediate) + {arm.X0, 0x1FFFF, 0xB24043E0}, + {arm.X0, 0x7FFFFFFF, 0xB2407BE0}, + {arm.X0, 0xFFFFFFFF, 0xB2407FE0}, + + // MOV (inverted wide immediate) {arm.X0, -1, 0x92800000}, + {arm.X0, 0x7FFFFFFFFFFFFFFF, 0x92F00000}, + {arm.X0, 0x2FFFFFFFF, 0x92DFFFA0}, // not encodable in the GNU assembler + {arm.X0, 0x2FFFF, 0x92BFFFA0}, // not encodable in the GNU assembler + + // Not encodable + {arm.X0, 0xCAFEBABE, 0}, + {arm.X0, 0xDEADC0DE, 0}, } for _, pattern := range usagePatterns { t.Logf("mov %s, %d", pattern.Register, pattern.Number) - code := arm.MoveRegisterNumber(pattern.Register, pattern.Number) - assert.DeepEqual(t, code, pattern.Code) + code, encodable := arm.MoveRegisterNumber(pattern.Register, pattern.Number) + + if pattern.Code != 0 { + assert.True(t, encodable) + assert.DeepEqual(t, code, pattern.Code) + } else { + assert.False(t, encodable) + } } } diff --git a/src/arm/arm_test.go b/src/arm/arm_test.go index 948f869..43ef207 100644 --- a/src/arm/arm_test.go +++ b/src/arm/arm_test.go @@ -9,7 +9,6 @@ import ( func TestARM(t *testing.T) { assert.DeepEqual(t, arm.Call(0), 0x94000000) - assert.DeepEqual(t, arm.MoveRegisterNumber(arm.X0, 42), arm.MoveZero(arm.X0, 0, 42)) assert.DeepEqual(t, arm.Nop(), 0xD503201F) assert.DeepEqual(t, arm.Return(), 0xD65F03C0) assert.DeepEqual(t, arm.Syscall(), 0xD4000001) diff --git a/src/asmc/compileARM.go b/src/asmc/compileARM.go index 111c708..a5b8e05 100644 --- a/src/asmc/compileARM.go +++ b/src/asmc/compileARM.go @@ -76,8 +76,9 @@ func (c *compiler) compileARM(x asm.Instruction) { operands := c.assembler.Param.MemoryNumber[x.Index] if operands.Address.OffsetRegister < 0 { - c.append(arm.MoveRegisterNumber(arm.X0, operands.Number)) - c.append(arm.StoreRegister(arm.X0, operands.Address.Base, int(operands.Address.Offset), operands.Address.Length)) + tmp := arm.X28 + c.moveRegisterNumberARM(tmp, operands.Number) + c.append(arm.StoreRegister(tmp, operands.Address.Base, int(operands.Address.Offset), operands.Address.Length)) } else { panic("not implemented") } @@ -109,7 +110,7 @@ func (c *compiler) compileARM(x asm.Instruction) { c.append(code) } else { tmp := arm.X28 - c.append(arm.MoveRegisterNumber(tmp, operand.Number)) + c.moveRegisterNumberARM(tmp, operand.Number) c.append(arm.AndRegisterRegister(operand.Register, operand.Register, tmp)) } case asm.TypeRegisterRegister: @@ -127,7 +128,7 @@ func (c *compiler) compileARM(x asm.Instruction) { c.append(code) } else { tmp := arm.X28 - c.append(arm.MoveRegisterNumber(tmp, operand.Number)) + c.moveRegisterNumberARM(tmp, operand.Number) c.append(arm.OrRegisterRegister(operand.Register, operand.Register, tmp)) } case asm.TypeRegisterRegister: @@ -145,7 +146,7 @@ func (c *compiler) compileARM(x asm.Instruction) { c.append(code) } else { tmp := arm.X28 - c.append(arm.MoveRegisterNumber(tmp, operand.Number)) + c.moveRegisterNumberARM(tmp, operand.Number) c.append(arm.XorRegisterRegister(operand.Register, operand.Register, tmp)) } case asm.TypeRegisterRegister: @@ -200,7 +201,7 @@ func (c *compiler) compileARM(x asm.Instruction) { case asm.TypeRegisterNumber: operand := c.assembler.Param.RegisterNumber[x.Index] tmp := arm.X28 - c.append(arm.MoveRegisterNumber(tmp, operand.Number)) + c.moveRegisterNumberARM(tmp, operand.Number) c.append(arm.MulRegisterRegister(operand.Register, operand.Register, tmp)) } @@ -226,7 +227,7 @@ func (c *compiler) compileARM(x asm.Instruction) { case asm.TypeRegisterNumber: operands := c.assembler.Param.RegisterNumber[x.Index] - c.append(arm.MoveRegisterNumber(operands.Register, operands.Number)) + c.moveRegisterNumberARM(operands.Register, operands.Number) case asm.TypeRegisterLabel: operands := c.assembler.Param.RegisterLabel[x.Index] diff --git a/src/asmc/movARM.go b/src/asmc/movARM.go new file mode 100644 index 0000000..e34fb0e --- /dev/null +++ b/src/asmc/movARM.go @@ -0,0 +1,16 @@ +package asmc + +import ( + "git.urbach.dev/cli/q/src/arm" + "git.urbach.dev/cli/q/src/cpu" +) + +func (c *compiler) moveRegisterNumberARM(register cpu.Register, number int) { + code, encodable := arm.MoveRegisterNumber(register, number) + + if encodable { + c.append(code) + } else { + panic("not implemented") // movz movk + } +}