Added more tests

This commit is contained in:
Eduard Urbach 2024-08-07 23:30:53 +02:00
parent 66569446b1
commit d624a5f895
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
16 changed files with 399 additions and 26 deletions

View File

@ -67,8 +67,10 @@ Build a Linux x86-64 ELF executable from `examples/hello` and run it:
- [x] Exclude unused functions - [x] Exclude unused functions
- [x] Constant folding - [x] Constant folding
- [ ] Constant propagation
- [ ] Function call inlining - [ ] Function call inlining
- [ ] Loop unrolls - [ ] Loop unrolls
- [ ] Assembler optimization backend
### Linter ### Linter

View File

@ -36,4 +36,4 @@ const (
X30 X30
) )
var SyscallArgs = []cpu.Register{X8, X0, X1, X2, X3, X4, X5} var SyscallInputRegisters = []cpu.Register{X8, X0, X1, X2, X3, X4, X5}

View File

@ -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)
}

View File

@ -37,4 +37,4 @@ const (
X31 X31
) )
var SyscallArgs = []cpu.Register{X10, X11, X12, X13, X14, X15, X16} var SyscallInputRegisters = []cpu.Register{X10, X11, X12, X13, X14, X15, X16}

View File

@ -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)
}

View File

@ -5,11 +5,11 @@ import (
) )
// AddRegisterNumber adds a number to the given register. // AddRegisterNumber adds a number to the given register.
func AddRegisterNumber(code []byte, destination cpu.Register, number int) []byte { func AddRegisterNumber(code []byte, register cpu.Register, number int) []byte {
return encodeNum(code, AddressDirect, 0, destination, number, 0x83, 0x81) return encodeNum(code, AddressDirect, 0, register, number, 0x83, 0x81)
} }
// AddRegisterRegister adds a register value into another register. // AddRegisterRegister adds a register value into another register.
func AddRegisterRegister(code []byte, destination cpu.Register, operand cpu.Register) []byte { func AddRegisterRegister(code []byte, register cpu.Register, operand cpu.Register) []byte {
return encode(code, AddressDirect, operand, destination, 8, 0x01) return encode(code, AddressDirect, operand, register, 8, 0x01)
} }

View File

@ -5,11 +5,11 @@ import (
) )
// AndRegisterNumber performs a bitwise AND using a register and a number. // AndRegisterNumber performs a bitwise AND using a register and a number.
func AndRegisterNumber(code []byte, destination cpu.Register, number int) []byte { func AndRegisterNumber(code []byte, register cpu.Register, number int) []byte {
return encodeNum(code, AddressDirect, 0b100, destination, number, 0x83, 0x81) return encodeNum(code, AddressDirect, 0b100, register, number, 0x83, 0x81)
} }
// AndRegisterRegister performs a bitwise AND using two registers. // AndRegisterRegister performs a bitwise AND using two registers.
func AndRegisterRegister(code []byte, destination cpu.Register, operand cpu.Register) []byte { func AndRegisterRegister(code []byte, register cpu.Register, operand cpu.Register) []byte {
return encode(code, AddressDirect, operand, destination, 8, 0x21) return encode(code, AddressDirect, operand, register, 8, 0x21)
} }

88
src/arch/x64/And_test.go Normal file
View File

@ -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)
}
}

View File

@ -3,11 +3,11 @@ package x64
import "git.akyoto.dev/cli/q/src/cpu" import "git.akyoto.dev/cli/q/src/cpu"
// MulRegisterNumber multiplies a register with a number. // MulRegisterNumber multiplies a register with a number.
func MulRegisterNumber(code []byte, destination cpu.Register, number int) []byte { func MulRegisterNumber(code []byte, register cpu.Register, number int) []byte {
return encodeNum(code, AddressDirect, destination, destination, number, 0x6B, 0x69) return encodeNum(code, AddressDirect, register, register, number, 0x6B, 0x69)
} }
// MulRegisterRegister multiplies a register with another register. // MulRegisterRegister multiplies a register with another register.
func MulRegisterRegister(code []byte, destination cpu.Register, operand cpu.Register) []byte { func MulRegisterRegister(code []byte, register cpu.Register, operand cpu.Register) []byte {
return encode(code, AddressDirect, destination, operand, 8, 0x0F, 0xAF) return encode(code, AddressDirect, register, operand, 8, 0x0F, 0xAF)
} }

View File

@ -5,11 +5,11 @@ import (
) )
// OrRegisterNumber performs a bitwise OR using a register and a number. // OrRegisterNumber performs a bitwise OR using a register and a number.
func OrRegisterNumber(code []byte, destination cpu.Register, number int) []byte { func OrRegisterNumber(code []byte, register cpu.Register, number int) []byte {
return encodeNum(code, AddressDirect, 0b001, destination, number, 0x83, 0x81) return encodeNum(code, AddressDirect, 0b001, register, number, 0x83, 0x81)
} }
// OrRegisterRegister performs a bitwise OR using two registers. // OrRegisterRegister performs a bitwise OR using two registers.
func OrRegisterRegister(code []byte, destination cpu.Register, operand cpu.Register) []byte { func OrRegisterRegister(code []byte, register cpu.Register, operand cpu.Register) []byte {
return encode(code, AddressDirect, operand, destination, 8, 0x09) return encode(code, AddressDirect, operand, register, 8, 0x09)
} }

88
src/arch/x64/Or_test.go Normal file
View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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)
}
}

View File

@ -5,11 +5,11 @@ import (
) )
// SubRegisterNumber subtracts a number from the given register. // SubRegisterNumber subtracts a number from the given register.
func SubRegisterNumber(code []byte, destination cpu.Register, number int) []byte { func SubRegisterNumber(code []byte, register cpu.Register, number int) []byte {
return encodeNum(code, AddressDirect, 0b101, destination, number, 0x83, 0x81) return encodeNum(code, AddressDirect, 0b101, register, number, 0x83, 0x81)
} }
// SubRegisterRegister subtracts a register value from another register. // SubRegisterRegister subtracts a register value from another register.
func SubRegisterRegister(code []byte, destination cpu.Register, operand cpu.Register) []byte { func SubRegisterRegister(code []byte, register cpu.Register, operand cpu.Register) []byte {
return encode(code, AddressDirect, operand, destination, 8, 0x29) return encode(code, AddressDirect, operand, register, 8, 0x29)
} }

View File

@ -5,11 +5,11 @@ import (
) )
// XorRegisterNumber performs a bitwise XOR using a register and a number. // XorRegisterNumber performs a bitwise XOR using a register and a number.
func XorRegisterNumber(code []byte, destination cpu.Register, number int) []byte { func XorRegisterNumber(code []byte, register cpu.Register, number int) []byte {
return encodeNum(code, AddressDirect, 0b110, destination, number, 0x83, 0x81) return encodeNum(code, AddressDirect, 0b110, register, number, 0x83, 0x81)
} }
// XorRegisterRegister performs a bitwise XOR using two registers. // XorRegisterRegister performs a bitwise XOR using two registers.
func XorRegisterRegister(code []byte, destination cpu.Register, operand cpu.Register) []byte { func XorRegisterRegister(code []byte, register cpu.Register, operand cpu.Register) []byte {
return encode(code, AddressDirect, operand, destination, 8, 0x31) return encode(code, AddressDirect, operand, register, 8, 0x31)
} }

88
src/arch/x64/Xor_test.go Normal file
View File

@ -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)
}
}