From bf80551a15b8a04f09f5c390cd2c1293265c82af Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Fri, 26 Jul 2024 16:19:13 +0200 Subject: [PATCH] Implemented 64-bit move --- examples/itoa/itoa.q | 4 ++-- lib/{io/io.q => log/number.q} | 2 +- src/build/arch/x64/Move.go | 30 +++++++++++++++++++++++------- src/build/arch/x64/Move_test.go | 21 +++++++++++++++++++-- src/build/arch/x64/x64_test.go | 4 ++-- src/build/asm/Finalize.go | 6 +++--- src/build/asm/divide.go | 22 +++++++++++----------- tests/examples_test.go | 2 +- 8 files changed, 62 insertions(+), 29 deletions(-) rename lib/{io/io.q => log/number.q} (95%) diff --git a/examples/itoa/itoa.q b/examples/itoa/itoa.q index 6bfac19..ee4d224 100644 --- a/examples/itoa/itoa.q +++ b/examples/itoa/itoa.q @@ -1,5 +1,5 @@ -import io +import log main() { - io.printNum(2147483647) + log.number(9223372036854775807) } \ No newline at end of file diff --git a/lib/io/io.q b/lib/log/number.q similarity index 95% rename from lib/io/io.q rename to lib/log/number.q index 1f6e8fe..58456ad 100644 --- a/lib/io/io.q +++ b/lib/log/number.q @@ -1,7 +1,7 @@ import mem import sys -printNum(x) { +number(x) { length := 20 buffer := mem.alloc(length) end := buffer + length diff --git a/src/build/arch/x64/Move.go b/src/build/arch/x64/Move.go index 3ebf470..ad6dbda 100644 --- a/src/build/arch/x64/Move.go +++ b/src/build/arch/x64/Move.go @@ -6,18 +6,34 @@ import ( "git.akyoto.dev/cli/q/src/build/cpu" ) -// MoveRegisterNumber32 moves a 32 bit integer into the given register. -func MoveRegisterNumber32(code []byte, destination cpu.Register, number uint32) []byte { +// MoveRegisterNumber moves an integer into the given register. +func MoveRegisterNumber(code []byte, destination cpu.Register, number int) []byte { + w := byte(0) + b := byte(0) + + if SizeOf(int64(number)) == 8 { + w = 1 + } + if destination > 0b111 { - code = append(code, REX(0, 0, 0, 1)) + b = 1 destination &= 0b111 } - code = append(code, 0xb8+byte(destination)) - return binary.LittleEndian.AppendUint32(code, number) + if w != 0 || b != 0 { + code = append(code, REX(w, 0, 0, b)) + } + + code = append(code, 0xB8+byte(destination)) + + if w == 1 { + return binary.LittleEndian.AppendUint64(code, uint64(number)) + } else { + return binary.LittleEndian.AppendUint32(code, uint32(number)) + } } -// MoveRegisterRegister64 moves a register value into another register. -func MoveRegisterRegister64(code []byte, destination cpu.Register, source cpu.Register) []byte { +// MoveRegisterRegister moves a register value into another register. +func MoveRegisterRegister(code []byte, destination cpu.Register, source cpu.Register) []byte { return encode(code, AddressDirect, source, destination, 8, 0x89) } diff --git a/src/build/arch/x64/Move_test.go b/src/build/arch/x64/Move_test.go index 7d5251e..cbbe134 100644 --- a/src/build/arch/x64/Move_test.go +++ b/src/build/arch/x64/Move_test.go @@ -30,11 +30,28 @@ func TestMoveRegisterNumber(t *testing.T) { {x64.R13, 0x7FFFFFFF, []byte{0x41, 0xBD, 0xFF, 0xFF, 0xFF, 0x7F}}, {x64.R14, 0x7FFFFFFF, []byte{0x41, 0xBE, 0xFF, 0xFF, 0xFF, 0x7F}}, {x64.R15, 0x7FFFFFFF, []byte{0x41, 0xBF, 0xFF, 0xFF, 0xFF, 0x7F}}, + + {x64.RAX, 0x7FFFFFFFFFFFFFFF, []byte{0x48, 0xB8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RCX, 0x7FFFFFFFFFFFFFFF, []byte{0x48, 0xB9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RDX, 0x7FFFFFFFFFFFFFFF, []byte{0x48, 0xBA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RBX, 0x7FFFFFFFFFFFFFFF, []byte{0x48, 0xBB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RSP, 0x7FFFFFFFFFFFFFFF, []byte{0x48, 0xBC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RBP, 0x7FFFFFFFFFFFFFFF, []byte{0x48, 0xBD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RSI, 0x7FFFFFFFFFFFFFFF, []byte{0x48, 0xBE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RDI, 0x7FFFFFFFFFFFFFFF, []byte{0x48, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R8, 0x7FFFFFFFFFFFFFFF, []byte{0x49, 0xB8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R9, 0x7FFFFFFFFFFFFFFF, []byte{0x49, 0xB9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R10, 0x7FFFFFFFFFFFFFFF, []byte{0x49, 0xBA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R11, 0x7FFFFFFFFFFFFFFF, []byte{0x49, 0xBB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R12, 0x7FFFFFFFFFFFFFFF, []byte{0x49, 0xBC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R13, 0x7FFFFFFFFFFFFFFF, []byte{0x49, 0xBD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R14, 0x7FFFFFFFFFFFFFFF, []byte{0x49, 0xBE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R15, 0x7FFFFFFFFFFFFFFF, []byte{0x49, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}}, } for _, pattern := range usagePatterns { t.Logf("mov %s, %x", pattern.Register, pattern.Number) - code := x64.MoveRegisterNumber32(nil, pattern.Register, uint32(pattern.Number)) + code := x64.MoveRegisterNumber(nil, pattern.Register, pattern.Number) assert.DeepEqual(t, code, pattern.Code) } } @@ -65,7 +82,7 @@ func TestMoveRegisterRegister(t *testing.T) { for _, pattern := range usagePatterns { t.Logf("mov %s, %s", pattern.Left, pattern.Right) - code := x64.MoveRegisterRegister64(nil, pattern.Left, pattern.Right) + code := x64.MoveRegisterRegister(nil, pattern.Left, pattern.Right) assert.DeepEqual(t, code, pattern.Code) } } diff --git a/src/build/arch/x64/x64_test.go b/src/build/arch/x64/x64_test.go index bcbf45b..cdde6cf 100644 --- a/src/build/arch/x64/x64_test.go +++ b/src/build/arch/x64/x64_test.go @@ -9,8 +9,8 @@ import ( func TestX64(t *testing.T) { assert.DeepEqual(t, x64.Call(nil, 1), []byte{0xe8, 0x01, 0x00, 0x00, 0x00}) - assert.DeepEqual(t, x64.MoveRegisterNumber32(nil, 0, 1), []byte{0xb8, 0x01, 0x00, 0x00, 0x00}) - assert.DeepEqual(t, x64.MoveRegisterNumber32(nil, 1, 1), []byte{0xb9, 0x01, 0x00, 0x00, 0x00}) + assert.DeepEqual(t, x64.MoveRegisterNumber(nil, 0, 1), []byte{0xb8, 0x01, 0x00, 0x00, 0x00}) + assert.DeepEqual(t, x64.MoveRegisterNumber(nil, 1, 1), []byte{0xb9, 0x01, 0x00, 0x00, 0x00}) assert.DeepEqual(t, x64.Return(nil), []byte{0xc3}) assert.DeepEqual(t, x64.Syscall(nil), []byte{0x0f, 0x05}) assert.DeepEqual(t, x64.ExtendRAXToRDX(nil), []byte{0x48, 0x99}) diff --git a/src/build/asm/Finalize.go b/src/build/asm/Finalize.go index e2adf3f..df8e4ac 100644 --- a/src/build/asm/Finalize.go +++ b/src/build/asm/Finalize.go @@ -133,14 +133,14 @@ func (a Assembler) Finalize() ([]byte, []byte) { case MOVE: switch operands := x.Data.(type) { case *RegisterNumber: - code = x64.MoveRegisterNumber32(code, operands.Register, uint32(operands.Number)) + code = x64.MoveRegisterNumber(code, operands.Register, operands.Number) case *RegisterRegister: - code = x64.MoveRegisterRegister64(code, operands.Destination, operands.Source) + code = x64.MoveRegisterRegister(code, operands.Destination, operands.Source) case *RegisterLabel: start := len(code) - code = x64.MoveRegisterNumber32(code, operands.Register, 0x00_00_00_00) + code = x64.MoveRegisterNumber(code, operands.Register, 0x00_00_00_00) size := 4 opSize := len(code) - size - start regLabel := x.Data.(*RegisterLabel) diff --git a/src/build/asm/divide.go b/src/build/asm/divide.go index 9c42a08..a916cad 100644 --- a/src/build/asm/divide.go +++ b/src/build/asm/divide.go @@ -7,15 +7,15 @@ func divide(code []byte, data any) []byte { switch operands := data.(type) { case *RegisterNumber: if operands.Register == x64.RAX { - code = x64.MoveRegisterNumber32(code, x64.RCX, uint32(operands.Number)) + code = x64.MoveRegisterNumber(code, x64.RCX, operands.Number) code = x64.ExtendRAXToRDX(code) code = x64.DivRegister(code, x64.RCX) } else { - code = x64.MoveRegisterRegister64(code, x64.RAX, operands.Register) - code = x64.MoveRegisterNumber32(code, operands.Register, uint32(operands.Number)) + code = x64.MoveRegisterRegister(code, x64.RAX, operands.Register) + code = x64.MoveRegisterNumber(code, operands.Register, operands.Number) code = x64.ExtendRAXToRDX(code) code = x64.DivRegister(code, operands.Register) - code = x64.MoveRegisterRegister64(code, operands.Register, x64.RAX) + code = x64.MoveRegisterRegister(code, operands.Register, x64.RAX) } case *RegisterRegister: @@ -23,11 +23,11 @@ func divide(code []byte, data any) []byte { code = x64.ExtendRAXToRDX(code) code = x64.DivRegister(code, operands.Source) } else { - code = x64.MoveRegisterRegister64(code, x64.RAX, operands.Destination) + code = x64.MoveRegisterRegister(code, x64.RAX, operands.Destination) code = x64.ExtendRAXToRDX(code) code = x64.DivRegister(code, operands.Source) - code = x64.MoveRegisterRegister64(code, operands.Destination, x64.RAX) + code = x64.MoveRegisterRegister(code, operands.Destination, x64.RAX) } } return code @@ -37,17 +37,17 @@ func divide(code []byte, data any) []byte { func modulo(code []byte, data any) []byte { switch operands := data.(type) { case *RegisterNumber: - code = x64.MoveRegisterRegister64(code, x64.RAX, operands.Register) - code = x64.MoveRegisterNumber32(code, operands.Register, uint32(operands.Number)) + code = x64.MoveRegisterRegister(code, x64.RAX, operands.Register) + code = x64.MoveRegisterNumber(code, operands.Register, operands.Number) code = x64.ExtendRAXToRDX(code) code = x64.DivRegister(code, operands.Register) - code = x64.MoveRegisterRegister64(code, operands.Register, x64.RDX) + code = x64.MoveRegisterRegister(code, operands.Register, x64.RDX) case *RegisterRegister: - code = x64.MoveRegisterRegister64(code, x64.RAX, operands.Destination) + code = x64.MoveRegisterRegister(code, x64.RAX, operands.Destination) code = x64.ExtendRAXToRDX(code) code = x64.DivRegister(code, operands.Source) - code = x64.MoveRegisterRegister64(code, operands.Destination, x64.RDX) + code = x64.MoveRegisterRegister(code, operands.Destination, x64.RDX) } return code diff --git a/tests/examples_test.go b/tests/examples_test.go index 94c223a..2a5b41b 100644 --- a/tests/examples_test.go +++ b/tests/examples_test.go @@ -18,7 +18,7 @@ var examples = []struct { {"factorial", "", "", 120}, {"fibonacci", "", "", 55}, {"array", "", "Hello", 0}, - {"itoa", "", "2147483647", 0}, + {"itoa", "", "9223372036854775807", 0}, } func TestExamples(t *testing.T) {