From d624a5f895a918a3825dacb242288b0f4317a5f7 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Wed, 7 Aug 2024 23:30:53 +0200 Subject: [PATCH] Added more tests --- README.md | 2 + src/arch/arm64/Registers.go | 2 +- src/arch/arm64/Registers_test.go | 12 +++++ src/arch/riscv/Registers.go | 2 +- src/arch/riscv/Registers_test.go | 12 +++++ src/arch/x64/Add.go | 8 +-- src/arch/x64/And.go | 8 +-- src/arch/x64/And_test.go | 88 ++++++++++++++++++++++++++++++++ src/arch/x64/Mul.go | 8 +-- src/arch/x64/Or.go | 8 +-- src/arch/x64/Or_test.go | 88 ++++++++++++++++++++++++++++++++ src/arch/x64/Registers_test.go | 12 +++++ src/arch/x64/Shift_test.go | 71 ++++++++++++++++++++++++++ src/arch/x64/Sub.go | 8 +-- src/arch/x64/Xor.go | 8 +-- src/arch/x64/Xor_test.go | 88 ++++++++++++++++++++++++++++++++ 16 files changed, 399 insertions(+), 26 deletions(-) create mode 100644 src/arch/arm64/Registers_test.go create mode 100644 src/arch/riscv/Registers_test.go create mode 100644 src/arch/x64/And_test.go create mode 100644 src/arch/x64/Or_test.go create mode 100644 src/arch/x64/Registers_test.go create mode 100644 src/arch/x64/Shift_test.go create mode 100644 src/arch/x64/Xor_test.go diff --git a/README.md b/README.md index 695e702..0a34d68 100644 --- a/README.md +++ b/README.md @@ -67,8 +67,10 @@ Build a Linux x86-64 ELF executable from `examples/hello` and run it: - [x] Exclude unused functions - [x] Constant folding +- [ ] Constant propagation - [ ] Function call inlining - [ ] Loop unrolls +- [ ] Assembler optimization backend ### Linter diff --git a/src/arch/arm64/Registers.go b/src/arch/arm64/Registers.go index 3fd4f57..cf8c5db 100644 --- a/src/arch/arm64/Registers.go +++ b/src/arch/arm64/Registers.go @@ -36,4 +36,4 @@ const ( X30 ) -var SyscallArgs = []cpu.Register{X8, X0, X1, X2, X3, X4, X5} +var SyscallInputRegisters = []cpu.Register{X8, X0, X1, X2, X3, X4, X5} diff --git a/src/arch/arm64/Registers_test.go b/src/arch/arm64/Registers_test.go new file mode 100644 index 0000000..75f5b7c --- /dev/null +++ b/src/arch/arm64/Registers_test.go @@ -0,0 +1,12 @@ +package arm64_test + +import ( + "testing" + + "git.akyoto.dev/cli/q/src/arch/arm64" + "git.akyoto.dev/go/assert" +) + +func TestRegisters(t *testing.T) { + assert.NotNil(t, arm64.SyscallInputRegisters) +} diff --git a/src/arch/riscv/Registers.go b/src/arch/riscv/Registers.go index e9436d2..5267be3 100644 --- a/src/arch/riscv/Registers.go +++ b/src/arch/riscv/Registers.go @@ -37,4 +37,4 @@ const ( X31 ) -var SyscallArgs = []cpu.Register{X10, X11, X12, X13, X14, X15, X16} +var SyscallInputRegisters = []cpu.Register{X10, X11, X12, X13, X14, X15, X16} diff --git a/src/arch/riscv/Registers_test.go b/src/arch/riscv/Registers_test.go new file mode 100644 index 0000000..bc74568 --- /dev/null +++ b/src/arch/riscv/Registers_test.go @@ -0,0 +1,12 @@ +package riscv_test + +import ( + "testing" + + "git.akyoto.dev/cli/q/src/arch/riscv" + "git.akyoto.dev/go/assert" +) + +func TestRegisters(t *testing.T) { + assert.NotNil(t, riscv.SyscallInputRegisters) +} diff --git a/src/arch/x64/Add.go b/src/arch/x64/Add.go index a487a3b..fb70735 100644 --- a/src/arch/x64/Add.go +++ b/src/arch/x64/Add.go @@ -5,11 +5,11 @@ import ( ) // AddRegisterNumber adds a number to the given register. -func AddRegisterNumber(code []byte, destination cpu.Register, number int) []byte { - return encodeNum(code, AddressDirect, 0, destination, number, 0x83, 0x81) +func AddRegisterNumber(code []byte, register cpu.Register, number int) []byte { + return encodeNum(code, AddressDirect, 0, register, number, 0x83, 0x81) } // AddRegisterRegister adds a register value into another register. -func AddRegisterRegister(code []byte, destination cpu.Register, operand cpu.Register) []byte { - return encode(code, AddressDirect, operand, destination, 8, 0x01) +func AddRegisterRegister(code []byte, register cpu.Register, operand cpu.Register) []byte { + return encode(code, AddressDirect, operand, register, 8, 0x01) } diff --git a/src/arch/x64/And.go b/src/arch/x64/And.go index a20c3c3..8556507 100644 --- a/src/arch/x64/And.go +++ b/src/arch/x64/And.go @@ -5,11 +5,11 @@ import ( ) // AndRegisterNumber performs a bitwise AND using a register and a number. -func AndRegisterNumber(code []byte, destination cpu.Register, number int) []byte { - return encodeNum(code, AddressDirect, 0b100, destination, number, 0x83, 0x81) +func AndRegisterNumber(code []byte, register cpu.Register, number int) []byte { + return encodeNum(code, AddressDirect, 0b100, register, number, 0x83, 0x81) } // AndRegisterRegister performs a bitwise AND using two registers. -func AndRegisterRegister(code []byte, destination cpu.Register, operand cpu.Register) []byte { - return encode(code, AddressDirect, operand, destination, 8, 0x21) +func AndRegisterRegister(code []byte, register cpu.Register, operand cpu.Register) []byte { + return encode(code, AddressDirect, operand, register, 8, 0x21) } diff --git a/src/arch/x64/And_test.go b/src/arch/x64/And_test.go new file mode 100644 index 0000000..e0e60c8 --- /dev/null +++ b/src/arch/x64/And_test.go @@ -0,0 +1,88 @@ +package x64_test + +import ( + "testing" + + "git.akyoto.dev/cli/q/src/arch/x64" + "git.akyoto.dev/cli/q/src/cpu" + "git.akyoto.dev/go/assert" +) + +func TestAndRegisterNumber(t *testing.T) { + usagePatterns := []struct { + Register cpu.Register + Number int + Code []byte + }{ + {x64.RAX, 1, []byte{0x48, 0x83, 0xE0, 0x01}}, + {x64.RCX, 1, []byte{0x48, 0x83, 0xE1, 0x01}}, + {x64.RDX, 1, []byte{0x48, 0x83, 0xE2, 0x01}}, + {x64.RBX, 1, []byte{0x48, 0x83, 0xE3, 0x01}}, + {x64.RSP, 1, []byte{0x48, 0x83, 0xE4, 0x01}}, + {x64.RBP, 1, []byte{0x48, 0x83, 0xE5, 0x01}}, + {x64.RSI, 1, []byte{0x48, 0x83, 0xE6, 0x01}}, + {x64.RDI, 1, []byte{0x48, 0x83, 0xE7, 0x01}}, + {x64.R8, 1, []byte{0x49, 0x83, 0xE0, 0x01}}, + {x64.R9, 1, []byte{0x49, 0x83, 0xE1, 0x01}}, + {x64.R10, 1, []byte{0x49, 0x83, 0xE2, 0x01}}, + {x64.R11, 1, []byte{0x49, 0x83, 0xE3, 0x01}}, + {x64.R12, 1, []byte{0x49, 0x83, 0xE4, 0x01}}, + {x64.R13, 1, []byte{0x49, 0x83, 0xE5, 0x01}}, + {x64.R14, 1, []byte{0x49, 0x83, 0xE6, 0x01}}, + {x64.R15, 1, []byte{0x49, 0x83, 0xE7, 0x01}}, + + {x64.RAX, 0x7FFFFFFF, []byte{0x48, 0x81, 0xE0, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RCX, 0x7FFFFFFF, []byte{0x48, 0x81, 0xE1, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RDX, 0x7FFFFFFF, []byte{0x48, 0x81, 0xE2, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RBX, 0x7FFFFFFF, []byte{0x48, 0x81, 0xE3, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RSP, 0x7FFFFFFF, []byte{0x48, 0x81, 0xE4, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RBP, 0x7FFFFFFF, []byte{0x48, 0x81, 0xE5, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RSI, 0x7FFFFFFF, []byte{0x48, 0x81, 0xE6, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RDI, 0x7FFFFFFF, []byte{0x48, 0x81, 0xE7, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R8, 0x7FFFFFFF, []byte{0x49, 0x81, 0xE0, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R9, 0x7FFFFFFF, []byte{0x49, 0x81, 0xE1, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R10, 0x7FFFFFFF, []byte{0x49, 0x81, 0xE2, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R11, 0x7FFFFFFF, []byte{0x49, 0x81, 0xE3, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R12, 0x7FFFFFFF, []byte{0x49, 0x81, 0xE4, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R13, 0x7FFFFFFF, []byte{0x49, 0x81, 0xE5, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R14, 0x7FFFFFFF, []byte{0x49, 0x81, 0xE6, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R15, 0x7FFFFFFF, []byte{0x49, 0x81, 0xE7, 0xFF, 0xFF, 0xFF, 0x7F}}, + } + + for _, pattern := range usagePatterns { + t.Logf("and %s, %x", pattern.Register, pattern.Number) + code := x64.AndRegisterNumber(nil, pattern.Register, pattern.Number) + assert.DeepEqual(t, code, pattern.Code) + } +} + +func TestAndRegisterRegister(t *testing.T) { + usagePatterns := []struct { + Left cpu.Register + Right cpu.Register + Code []byte + }{ + {x64.RAX, x64.R15, []byte{0x4C, 0x21, 0xF8}}, + {x64.RCX, x64.R14, []byte{0x4C, 0x21, 0xF1}}, + {x64.RDX, x64.R13, []byte{0x4C, 0x21, 0xEA}}, + {x64.RBX, x64.R12, []byte{0x4C, 0x21, 0xE3}}, + {x64.RSP, x64.R11, []byte{0x4C, 0x21, 0xDC}}, + {x64.RBP, x64.R10, []byte{0x4C, 0x21, 0xD5}}, + {x64.RSI, x64.R9, []byte{0x4C, 0x21, 0xCE}}, + {x64.RDI, x64.R8, []byte{0x4C, 0x21, 0xC7}}, + {x64.R8, x64.RDI, []byte{0x49, 0x21, 0xF8}}, + {x64.R9, x64.RSI, []byte{0x49, 0x21, 0xF1}}, + {x64.R10, x64.RBP, []byte{0x49, 0x21, 0xEA}}, + {x64.R11, x64.RSP, []byte{0x49, 0x21, 0xE3}}, + {x64.R12, x64.RBX, []byte{0x49, 0x21, 0xDC}}, + {x64.R13, x64.RDX, []byte{0x49, 0x21, 0xD5}}, + {x64.R14, x64.RCX, []byte{0x49, 0x21, 0xCE}}, + {x64.R15, x64.RAX, []byte{0x49, 0x21, 0xC7}}, + } + + for _, pattern := range usagePatterns { + t.Logf("and %s, %s", pattern.Left, pattern.Right) + code := x64.AndRegisterRegister(nil, pattern.Left, pattern.Right) + assert.DeepEqual(t, code, pattern.Code) + } +} diff --git a/src/arch/x64/Mul.go b/src/arch/x64/Mul.go index 6c0cbea..1d11da3 100644 --- a/src/arch/x64/Mul.go +++ b/src/arch/x64/Mul.go @@ -3,11 +3,11 @@ package x64 import "git.akyoto.dev/cli/q/src/cpu" // MulRegisterNumber multiplies a register with a number. -func MulRegisterNumber(code []byte, destination cpu.Register, number int) []byte { - return encodeNum(code, AddressDirect, destination, destination, number, 0x6B, 0x69) +func MulRegisterNumber(code []byte, register cpu.Register, number int) []byte { + return encodeNum(code, AddressDirect, register, register, number, 0x6B, 0x69) } // MulRegisterRegister multiplies a register with another register. -func MulRegisterRegister(code []byte, destination cpu.Register, operand cpu.Register) []byte { - return encode(code, AddressDirect, destination, operand, 8, 0x0F, 0xAF) +func MulRegisterRegister(code []byte, register cpu.Register, operand cpu.Register) []byte { + return encode(code, AddressDirect, register, operand, 8, 0x0F, 0xAF) } diff --git a/src/arch/x64/Or.go b/src/arch/x64/Or.go index fec37da..fa5b440 100644 --- a/src/arch/x64/Or.go +++ b/src/arch/x64/Or.go @@ -5,11 +5,11 @@ import ( ) // OrRegisterNumber performs a bitwise OR using a register and a number. -func OrRegisterNumber(code []byte, destination cpu.Register, number int) []byte { - return encodeNum(code, AddressDirect, 0b001, destination, number, 0x83, 0x81) +func OrRegisterNumber(code []byte, register cpu.Register, number int) []byte { + return encodeNum(code, AddressDirect, 0b001, register, number, 0x83, 0x81) } // OrRegisterRegister performs a bitwise OR using two registers. -func OrRegisterRegister(code []byte, destination cpu.Register, operand cpu.Register) []byte { - return encode(code, AddressDirect, operand, destination, 8, 0x09) +func OrRegisterRegister(code []byte, register cpu.Register, operand cpu.Register) []byte { + return encode(code, AddressDirect, operand, register, 8, 0x09) } diff --git a/src/arch/x64/Or_test.go b/src/arch/x64/Or_test.go new file mode 100644 index 0000000..89bdc5d --- /dev/null +++ b/src/arch/x64/Or_test.go @@ -0,0 +1,88 @@ +package x64_test + +import ( + "testing" + + "git.akyoto.dev/cli/q/src/arch/x64" + "git.akyoto.dev/cli/q/src/cpu" + "git.akyoto.dev/go/assert" +) + +func TestOrRegisterNumber(t *testing.T) { + usagePatterns := []struct { + Register cpu.Register + Number int + Code []byte + }{ + {x64.RAX, 1, []byte{0x48, 0x83, 0xC8, 0x01}}, + {x64.RCX, 1, []byte{0x48, 0x83, 0xC9, 0x01}}, + {x64.RDX, 1, []byte{0x48, 0x83, 0xCA, 0x01}}, + {x64.RBX, 1, []byte{0x48, 0x83, 0xCB, 0x01}}, + {x64.RSP, 1, []byte{0x48, 0x83, 0xCC, 0x01}}, + {x64.RBP, 1, []byte{0x48, 0x83, 0xCD, 0x01}}, + {x64.RSI, 1, []byte{0x48, 0x83, 0xCE, 0x01}}, + {x64.RDI, 1, []byte{0x48, 0x83, 0xCF, 0x01}}, + {x64.R8, 1, []byte{0x49, 0x83, 0xC8, 0x01}}, + {x64.R9, 1, []byte{0x49, 0x83, 0xC9, 0x01}}, + {x64.R10, 1, []byte{0x49, 0x83, 0xCA, 0x01}}, + {x64.R11, 1, []byte{0x49, 0x83, 0xCB, 0x01}}, + {x64.R12, 1, []byte{0x49, 0x83, 0xCC, 0x01}}, + {x64.R13, 1, []byte{0x49, 0x83, 0xCD, 0x01}}, + {x64.R14, 1, []byte{0x49, 0x83, 0xCE, 0x01}}, + {x64.R15, 1, []byte{0x49, 0x83, 0xCF, 0x01}}, + + {x64.RAX, 0x7FFFFFFF, []byte{0x48, 0x81, 0xC8, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RCX, 0x7FFFFFFF, []byte{0x48, 0x81, 0xC9, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RDX, 0x7FFFFFFF, []byte{0x48, 0x81, 0xCA, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RBX, 0x7FFFFFFF, []byte{0x48, 0x81, 0xCB, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RSP, 0x7FFFFFFF, []byte{0x48, 0x81, 0xCC, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RBP, 0x7FFFFFFF, []byte{0x48, 0x81, 0xCD, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RSI, 0x7FFFFFFF, []byte{0x48, 0x81, 0xCE, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RDI, 0x7FFFFFFF, []byte{0x48, 0x81, 0xCF, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R8, 0x7FFFFFFF, []byte{0x49, 0x81, 0xC8, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R9, 0x7FFFFFFF, []byte{0x49, 0x81, 0xC9, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R10, 0x7FFFFFFF, []byte{0x49, 0x81, 0xCA, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R11, 0x7FFFFFFF, []byte{0x49, 0x81, 0xCB, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R12, 0x7FFFFFFF, []byte{0x49, 0x81, 0xCC, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R13, 0x7FFFFFFF, []byte{0x49, 0x81, 0xCD, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R14, 0x7FFFFFFF, []byte{0x49, 0x81, 0xCE, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R15, 0x7FFFFFFF, []byte{0x49, 0x81, 0xCF, 0xFF, 0xFF, 0xFF, 0x7F}}, + } + + for _, pattern := range usagePatterns { + t.Logf("or %s, %x", pattern.Register, pattern.Number) + code := x64.OrRegisterNumber(nil, pattern.Register, pattern.Number) + assert.DeepEqual(t, code, pattern.Code) + } +} + +func TestOrRegisterRegister(t *testing.T) { + usagePatterns := []struct { + Left cpu.Register + Right cpu.Register + Code []byte + }{ + {x64.RAX, x64.R15, []byte{0x4C, 0x09, 0xF8}}, + {x64.RCX, x64.R14, []byte{0x4C, 0x09, 0xF1}}, + {x64.RDX, x64.R13, []byte{0x4C, 0x09, 0xEA}}, + {x64.RBX, x64.R12, []byte{0x4C, 0x09, 0xE3}}, + {x64.RSP, x64.R11, []byte{0x4C, 0x09, 0xDC}}, + {x64.RBP, x64.R10, []byte{0x4C, 0x09, 0xD5}}, + {x64.RSI, x64.R9, []byte{0x4C, 0x09, 0xCE}}, + {x64.RDI, x64.R8, []byte{0x4C, 0x09, 0xC7}}, + {x64.R8, x64.RDI, []byte{0x49, 0x09, 0xF8}}, + {x64.R9, x64.RSI, []byte{0x49, 0x09, 0xF1}}, + {x64.R10, x64.RBP, []byte{0x49, 0x09, 0xEA}}, + {x64.R11, x64.RSP, []byte{0x49, 0x09, 0xE3}}, + {x64.R12, x64.RBX, []byte{0x49, 0x09, 0xDC}}, + {x64.R13, x64.RDX, []byte{0x49, 0x09, 0xD5}}, + {x64.R14, x64.RCX, []byte{0x49, 0x09, 0xCE}}, + {x64.R15, x64.RAX, []byte{0x49, 0x09, 0xC7}}, + } + + for _, pattern := range usagePatterns { + t.Logf("or %s, %s", pattern.Left, pattern.Right) + code := x64.OrRegisterRegister(nil, pattern.Left, pattern.Right) + assert.DeepEqual(t, code, pattern.Code) + } +} diff --git a/src/arch/x64/Registers_test.go b/src/arch/x64/Registers_test.go new file mode 100644 index 0000000..bb8ff19 --- /dev/null +++ b/src/arch/x64/Registers_test.go @@ -0,0 +1,12 @@ +package x64_test + +import ( + "testing" + + "git.akyoto.dev/cli/q/src/arch/x64" + "git.akyoto.dev/go/assert" +) + +func TestRegisters(t *testing.T) { + assert.NotContains(t, x64.GeneralRegisters, x64.RSP) +} diff --git a/src/arch/x64/Shift_test.go b/src/arch/x64/Shift_test.go new file mode 100644 index 0000000..926c98d --- /dev/null +++ b/src/arch/x64/Shift_test.go @@ -0,0 +1,71 @@ +package x64_test + +import ( + "testing" + + "git.akyoto.dev/cli/q/src/arch/x64" + "git.akyoto.dev/cli/q/src/cpu" + "git.akyoto.dev/go/assert" +) + +func TestShiftLeftNumber(t *testing.T) { + usagePatterns := []struct { + Register cpu.Register + Number int + Code []byte + }{ + {x64.RAX, 1, []byte{0x48, 0xC1, 0xE0, 0x01}}, + {x64.RCX, 1, []byte{0x48, 0xC1, 0xE1, 0x01}}, + {x64.RDX, 1, []byte{0x48, 0xC1, 0xE2, 0x01}}, + {x64.RBX, 1, []byte{0x48, 0xC1, 0xE3, 0x01}}, + {x64.RSP, 1, []byte{0x48, 0xC1, 0xE4, 0x01}}, + {x64.RBP, 1, []byte{0x48, 0xC1, 0xE5, 0x01}}, + {x64.RSI, 1, []byte{0x48, 0xC1, 0xE6, 0x01}}, + {x64.RDI, 1, []byte{0x48, 0xC1, 0xE7, 0x01}}, + {x64.R8, 1, []byte{0x49, 0xC1, 0xE0, 0x01}}, + {x64.R9, 1, []byte{0x49, 0xC1, 0xE1, 0x01}}, + {x64.R10, 1, []byte{0x49, 0xC1, 0xE2, 0x01}}, + {x64.R11, 1, []byte{0x49, 0xC1, 0xE3, 0x01}}, + {x64.R12, 1, []byte{0x49, 0xC1, 0xE4, 0x01}}, + {x64.R13, 1, []byte{0x49, 0xC1, 0xE5, 0x01}}, + {x64.R14, 1, []byte{0x49, 0xC1, 0xE6, 0x01}}, + {x64.R15, 1, []byte{0x49, 0xC1, 0xE7, 0x01}}, + } + + for _, pattern := range usagePatterns { + t.Logf("shl %s, %x", pattern.Register, pattern.Number) + code := x64.ShiftLeftNumber(nil, pattern.Register, byte(pattern.Number)) + assert.DeepEqual(t, code, pattern.Code) + } +} + +func TestShiftRightSignedNumber(t *testing.T) { + usagePatterns := []struct { + Register cpu.Register + Number int + Code []byte + }{ + {x64.RAX, 1, []byte{0x48, 0xC1, 0xF8, 0x01}}, + {x64.RCX, 1, []byte{0x48, 0xC1, 0xF9, 0x01}}, + {x64.RDX, 1, []byte{0x48, 0xC1, 0xFA, 0x01}}, + {x64.RBX, 1, []byte{0x48, 0xC1, 0xFB, 0x01}}, + {x64.RSP, 1, []byte{0x48, 0xC1, 0xFC, 0x01}}, + {x64.RBP, 1, []byte{0x48, 0xC1, 0xFD, 0x01}}, + {x64.RSI, 1, []byte{0x48, 0xC1, 0xFE, 0x01}}, + {x64.RDI, 1, []byte{0x48, 0xC1, 0xFF, 0x01}}, + {x64.R8, 1, []byte{0x49, 0xC1, 0xF8, 0x01}}, + {x64.R9, 1, []byte{0x49, 0xC1, 0xF9, 0x01}}, + {x64.R10, 1, []byte{0x49, 0xC1, 0xFA, 0x01}}, + {x64.R11, 1, []byte{0x49, 0xC1, 0xFB, 0x01}}, + {x64.R12, 1, []byte{0x49, 0xC1, 0xFC, 0x01}}, + {x64.R13, 1, []byte{0x49, 0xC1, 0xFD, 0x01}}, + {x64.R14, 1, []byte{0x49, 0xC1, 0xFE, 0x01}}, + {x64.R15, 1, []byte{0x49, 0xC1, 0xFF, 0x01}}, + } + + for _, pattern := range usagePatterns { + t.Logf("sar %s, %x", pattern.Register, pattern.Number) + code := x64.ShiftRightSignedNumber(nil, pattern.Register, byte(pattern.Number)) + assert.DeepEqual(t, code, pattern.Code) + } +} diff --git a/src/arch/x64/Sub.go b/src/arch/x64/Sub.go index fb9a649..57332fd 100644 --- a/src/arch/x64/Sub.go +++ b/src/arch/x64/Sub.go @@ -5,11 +5,11 @@ import ( ) // SubRegisterNumber subtracts a number from the given register. -func SubRegisterNumber(code []byte, destination cpu.Register, number int) []byte { - return encodeNum(code, AddressDirect, 0b101, destination, number, 0x83, 0x81) +func SubRegisterNumber(code []byte, register cpu.Register, number int) []byte { + return encodeNum(code, AddressDirect, 0b101, register, number, 0x83, 0x81) } // SubRegisterRegister subtracts a register value from another register. -func SubRegisterRegister(code []byte, destination cpu.Register, operand cpu.Register) []byte { - return encode(code, AddressDirect, operand, destination, 8, 0x29) +func SubRegisterRegister(code []byte, register cpu.Register, operand cpu.Register) []byte { + return encode(code, AddressDirect, operand, register, 8, 0x29) } diff --git a/src/arch/x64/Xor.go b/src/arch/x64/Xor.go index 8a469eb..c36a805 100644 --- a/src/arch/x64/Xor.go +++ b/src/arch/x64/Xor.go @@ -5,11 +5,11 @@ import ( ) // XorRegisterNumber performs a bitwise XOR using a register and a number. -func XorRegisterNumber(code []byte, destination cpu.Register, number int) []byte { - return encodeNum(code, AddressDirect, 0b110, destination, number, 0x83, 0x81) +func XorRegisterNumber(code []byte, register cpu.Register, number int) []byte { + return encodeNum(code, AddressDirect, 0b110, register, number, 0x83, 0x81) } // XorRegisterRegister performs a bitwise XOR using two registers. -func XorRegisterRegister(code []byte, destination cpu.Register, operand cpu.Register) []byte { - return encode(code, AddressDirect, operand, destination, 8, 0x31) +func XorRegisterRegister(code []byte, register cpu.Register, operand cpu.Register) []byte { + return encode(code, AddressDirect, operand, register, 8, 0x31) } diff --git a/src/arch/x64/Xor_test.go b/src/arch/x64/Xor_test.go new file mode 100644 index 0000000..c9e0744 --- /dev/null +++ b/src/arch/x64/Xor_test.go @@ -0,0 +1,88 @@ +package x64_test + +import ( + "testing" + + "git.akyoto.dev/cli/q/src/arch/x64" + "git.akyoto.dev/cli/q/src/cpu" + "git.akyoto.dev/go/assert" +) + +func TestXorRegisterNumber(t *testing.T) { + usagePatterns := []struct { + Register cpu.Register + Number int + Code []byte + }{ + {x64.RAX, 1, []byte{0x48, 0x83, 0xF0, 0x01}}, + {x64.RCX, 1, []byte{0x48, 0x83, 0xF1, 0x01}}, + {x64.RDX, 1, []byte{0x48, 0x83, 0xF2, 0x01}}, + {x64.RBX, 1, []byte{0x48, 0x83, 0xF3, 0x01}}, + {x64.RSP, 1, []byte{0x48, 0x83, 0xF4, 0x01}}, + {x64.RBP, 1, []byte{0x48, 0x83, 0xF5, 0x01}}, + {x64.RSI, 1, []byte{0x48, 0x83, 0xF6, 0x01}}, + {x64.RDI, 1, []byte{0x48, 0x83, 0xF7, 0x01}}, + {x64.R8, 1, []byte{0x49, 0x83, 0xF0, 0x01}}, + {x64.R9, 1, []byte{0x49, 0x83, 0xF1, 0x01}}, + {x64.R10, 1, []byte{0x49, 0x83, 0xF2, 0x01}}, + {x64.R11, 1, []byte{0x49, 0x83, 0xF3, 0x01}}, + {x64.R12, 1, []byte{0x49, 0x83, 0xF4, 0x01}}, + {x64.R13, 1, []byte{0x49, 0x83, 0xF5, 0x01}}, + {x64.R14, 1, []byte{0x49, 0x83, 0xF6, 0x01}}, + {x64.R15, 1, []byte{0x49, 0x83, 0xF7, 0x01}}, + + {x64.RAX, 0x7FFFFFFF, []byte{0x48, 0x81, 0xF0, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RCX, 0x7FFFFFFF, []byte{0x48, 0x81, 0xF1, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RDX, 0x7FFFFFFF, []byte{0x48, 0x81, 0xF2, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RBX, 0x7FFFFFFF, []byte{0x48, 0x81, 0xF3, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RSP, 0x7FFFFFFF, []byte{0x48, 0x81, 0xF4, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RBP, 0x7FFFFFFF, []byte{0x48, 0x81, 0xF5, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RSI, 0x7FFFFFFF, []byte{0x48, 0x81, 0xF6, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RDI, 0x7FFFFFFF, []byte{0x48, 0x81, 0xF7, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R8, 0x7FFFFFFF, []byte{0x49, 0x81, 0xF0, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R9, 0x7FFFFFFF, []byte{0x49, 0x81, 0xF1, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R10, 0x7FFFFFFF, []byte{0x49, 0x81, 0xF2, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R11, 0x7FFFFFFF, []byte{0x49, 0x81, 0xF3, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R12, 0x7FFFFFFF, []byte{0x49, 0x81, 0xF4, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R13, 0x7FFFFFFF, []byte{0x49, 0x81, 0xF5, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R14, 0x7FFFFFFF, []byte{0x49, 0x81, 0xF6, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R15, 0x7FFFFFFF, []byte{0x49, 0x81, 0xF7, 0xFF, 0xFF, 0xFF, 0x7F}}, + } + + for _, pattern := range usagePatterns { + t.Logf("xor %s, %x", pattern.Register, pattern.Number) + code := x64.XorRegisterNumber(nil, pattern.Register, pattern.Number) + assert.DeepEqual(t, code, pattern.Code) + } +} + +func TestXorRegisterRegister(t *testing.T) { + usagePatterns := []struct { + Left cpu.Register + Right cpu.Register + Code []byte + }{ + {x64.RAX, x64.R15, []byte{0x4C, 0x31, 0xF8}}, + {x64.RCX, x64.R14, []byte{0x4C, 0x31, 0xF1}}, + {x64.RDX, x64.R13, []byte{0x4C, 0x31, 0xEA}}, + {x64.RBX, x64.R12, []byte{0x4C, 0x31, 0xE3}}, + {x64.RSP, x64.R11, []byte{0x4C, 0x31, 0xDC}}, + {x64.RBP, x64.R10, []byte{0x4C, 0x31, 0xD5}}, + {x64.RSI, x64.R9, []byte{0x4C, 0x31, 0xCE}}, + {x64.RDI, x64.R8, []byte{0x4C, 0x31, 0xC7}}, + {x64.R8, x64.RDI, []byte{0x49, 0x31, 0xF8}}, + {x64.R9, x64.RSI, []byte{0x49, 0x31, 0xF1}}, + {x64.R10, x64.RBP, []byte{0x49, 0x31, 0xEA}}, + {x64.R11, x64.RSP, []byte{0x49, 0x31, 0xE3}}, + {x64.R12, x64.RBX, []byte{0x49, 0x31, 0xDC}}, + {x64.R13, x64.RDX, []byte{0x49, 0x31, 0xD5}}, + {x64.R14, x64.RCX, []byte{0x49, 0x31, 0xCE}}, + {x64.R15, x64.RAX, []byte{0x49, 0x31, 0xC7}}, + } + + for _, pattern := range usagePatterns { + t.Logf("xor %s, %s", pattern.Left, pattern.Right) + code := x64.XorRegisterRegister(nil, pattern.Left, pattern.Right) + assert.DeepEqual(t, code, pattern.Code) + } +}