From 625e8d5e2e79502a5bf2e2e8cd444c53165115ec Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Mon, 24 Jun 2024 21:54:03 +0200 Subject: [PATCH] Improved x64 encoder --- src/build/Function.go | 12 +++++----- src/build/arch/x64/Add.go | 2 +- src/build/arch/x64/Sub.go | 2 +- src/build/arch/x64/numberToRegister.go | 33 ++++++++++++++------------ src/build/arch/x64/sizeOf.go | 20 ++++++++++++++++ 5 files changed, 46 insertions(+), 23 deletions(-) create mode 100644 src/build/arch/x64/sizeOf.go diff --git a/src/build/Function.go b/src/build/Function.go index 58e7cee..cc86f47 100644 --- a/src/build/Function.go +++ b/src/build/Function.go @@ -114,17 +114,17 @@ func (f *Function) CompileInstruction(line token.List) error { } if expr.Token.Kind == token.Operator { + name := expr.Children[0].Token.Text() + number, _ := strconv.Atoi(expr.Children[1].Token.Text()) + register := f.Variables[name].Register + switch expr.Token.Text() { case "+=": - name := expr.Children[0].Token.Text() - number, _ := strconv.Atoi(expr.Children[1].Token.Text()) - f.Assembler.AddRegisterNumber(f.Variables[name].Register, number) + f.Assembler.AddRegisterNumber(register, number) return nil case "-=": - name := expr.Children[0].Token.Text() - number, _ := strconv.Atoi(expr.Children[1].Token.Text()) - f.Assembler.SubRegisterNumber(f.Variables[name].Register, number) + f.Assembler.SubRegisterNumber(register, number) return nil } } diff --git a/src/build/arch/x64/Add.go b/src/build/arch/x64/Add.go index d394968..f67094d 100644 --- a/src/build/arch/x64/Add.go +++ b/src/build/arch/x64/Add.go @@ -6,5 +6,5 @@ import ( // AddRegNum adds a number to the given register. func AddRegNum(code []byte, destination cpu.Register, number int) []byte { - return numberToRegister(0x83, 0x81, 0b000, code, destination, number) + return numRegReg(code, 0x83, 0x81, 0, byte(destination), number) } diff --git a/src/build/arch/x64/Sub.go b/src/build/arch/x64/Sub.go index af9511c..f2d5e9b 100644 --- a/src/build/arch/x64/Sub.go +++ b/src/build/arch/x64/Sub.go @@ -6,5 +6,5 @@ import ( // SubRegNum subtracts a number from the given register. func SubRegNum(code []byte, destination cpu.Register, number int) []byte { - return numberToRegister(0x83, 0x81, 0b101, code, destination, number) + return numRegReg(code, 0x83, 0x81, 0b101, byte(destination), number) } diff --git a/src/build/arch/x64/numberToRegister.go b/src/build/arch/x64/numberToRegister.go index 025a2ec..c67889e 100644 --- a/src/build/arch/x64/numberToRegister.go +++ b/src/build/arch/x64/numberToRegister.go @@ -1,24 +1,27 @@ package x64 -import ( - "math" +// numRegReg encodes an instruction with up to two registers and a number parameter. +func numRegReg(code []byte, opCode8 byte, opCode32 byte, reg byte, rm byte, number int) []byte { + w := byte(1) // Indicates a 64-bit register. + r := byte(0) // Extension to the "reg" field in ModRM. + x := byte(0) // Extension to the SIB index field. + b := byte(0) // Extension to the "rm" field in ModRM or the SIB base (r8 up to r15 use this). + mod := byte(0b11) // Direct addressing mode, no register offsets. - "git.akyoto.dev/cli/q/src/build/cpu" -) - -// numberToRegister encodes an instruction with a register and a number parameter. -func numberToRegister(opCode8 byte, opCode32 byte, reg byte, code []byte, destination cpu.Register, number int) []byte { - b := byte(0) - - if destination >= 8 { - b = 1 - destination -= 8 + if reg > 0b111 { + r = 1 + reg &= 0b111 } - rex := REX(1, 0, 0, b) - modRM := ModRM(0b11, reg, byte(destination)) + if rm > 0b111 { + b = 1 + rm &= 0b111 + } - if number >= math.MinInt8 && number <= math.MaxInt8 { + rex := REX(w, r, x, b) + modRM := ModRM(mod, reg, rm) + + if sizeOf(number) == 1 { return append( code, rex, diff --git a/src/build/arch/x64/sizeOf.go b/src/build/arch/x64/sizeOf.go new file mode 100644 index 0000000..8e6533b --- /dev/null +++ b/src/build/arch/x64/sizeOf.go @@ -0,0 +1,20 @@ +package x64 + +import "math" + +// sizeOf tells you how many bytes are needed to encode this number. +func sizeOf(number int) int { + switch { + case number >= math.MinInt8 && number <= math.MaxInt8: + return 1 + + case number >= math.MinInt16 && number <= math.MaxInt16: + return 2 + + case number >= math.MinInt32 && number <= math.MaxInt32: + return 4 + + default: + return 8 + } +}