Files
avo/operand/checks_test.go

188 lines
5.0 KiB
Go
Raw Normal View History

package operand
import (
2018-11-27 22:08:11 -08:00
"math"
"reflect"
"runtime"
"testing"
2018-11-26 23:35:26 -08:00
"github.com/mmcloughlin/avo/reg"
)
func TestChecks(t *testing.T) {
cases := []struct {
2018-12-02 12:28:33 -08:00
Predicate func(Op) bool
Operand Op
Expect bool
}{
// Immediates
{Is1, Imm(1), true},
{Is1, Imm(23), false},
2018-11-26 23:35:26 -08:00
{Is3, Imm(3), true},
{Is3, Imm(23), false},
2018-11-26 23:35:26 -08:00
{IsIMM2U, Imm(3), true},
{IsIMM2U, Imm(4), false},
2018-11-26 23:35:26 -08:00
{IsIMM8, Imm(255), true},
{IsIMM8, Imm(256), false},
2018-11-26 23:35:26 -08:00
{IsIMM16, Imm((1 << 16) - 1), true},
{IsIMM16, Imm(1 << 16), false},
2018-11-26 23:35:26 -08:00
{IsIMM32, Imm((1 << 32) - 1), true},
{IsIMM32, Imm(1 << 32), false},
2018-11-26 23:35:26 -08:00
{IsIMM64, Imm((1 << 64) - 1), true},
// Signed Immediates
{IsIMM8, I8(-1), true},
{IsIMM16, I16(-1), true},
{IsIMM32, I32(-1), true},
{IsIMM64, I64(-1), true},
// Specific registers
{IsAL, reg.AL, true},
{IsAL, reg.CL, false},
2018-11-26 23:35:26 -08:00
{IsCL, reg.CL, true},
{IsCL, reg.DH, false},
2018-11-26 23:35:26 -08:00
{IsAX, reg.AX, true},
{IsAX, reg.DX, false},
2018-11-26 23:35:26 -08:00
{IsEAX, reg.EAX, true},
{IsEAX, reg.ECX, false},
2018-11-26 23:35:26 -08:00
{IsRAX, reg.RAX, true},
{IsRAX, reg.R13, false},
// General-purpose registers
{IsR8, reg.AL, true},
{IsR8, reg.CH, true},
{IsR8, reg.EAX, false},
2018-11-26 23:35:26 -08:00
{IsR16, reg.DX, true},
{IsR16, reg.R10W, true},
{IsR16, reg.R10B, false},
2018-11-26 23:35:26 -08:00
{IsR32, reg.EBP, true},
{IsR32, reg.R14L, true},
{IsR32, reg.R8, false},
2018-11-26 23:35:26 -08:00
{IsR64, reg.RDX, true},
{IsR64, reg.R10, true},
{IsR64, reg.EBX, false},
2018-11-26 23:35:26 -08:00
// Vector registers
{IsXMM0, reg.X0, true},
{IsXMM0, reg.X13, false},
{IsXMM0, reg.Y3, false},
2018-11-26 23:35:26 -08:00
{IsXMM, reg.X0, true},
{IsXMM, reg.X13, true},
{IsXMM, reg.Y3, false},
{IsXMM, reg.Z23, false},
2018-11-26 23:35:26 -08:00
{IsYMM, reg.Y0, true},
{IsYMM, reg.Y13, true},
{IsYMM, reg.Y31, true},
{IsYMM, reg.X3, false},
{IsYMM, reg.Z3, false},
2018-11-26 23:35:26 -08:00
// Pseudo registers.
{IsPseudo, reg.FramePointer, true},
{IsPseudo, reg.ProgramCounter, true},
{IsPseudo, reg.StaticBase, true},
{IsPseudo, reg.StackPointer, true},
{IsPseudo, reg.ECX, false},
{IsPseudo, reg.X9, false},
2018-11-26 23:35:26 -08:00
// Memory operands
{IsM, Mem{Base: reg.CX}, true},
{IsM, Mem{Base: reg.ECX}, true},
{IsM, Mem{Base: reg.RCX}, true},
2018-12-14 22:12:28 -08:00
{IsM, Mem{Base: reg.X0}, false},
2018-11-26 23:35:26 -08:00
{IsM8, Mem{Disp: 8, Base: reg.CL}, true},
{IsM8, Mem{Disp: 8, Base: reg.CL, Index: reg.AH, Scale: 2}, true},
2018-12-14 22:12:28 -08:00
{IsM8, Mem{Disp: 8, Base: reg.X0, Index: reg.AH, Scale: 2}, false},
{IsM8, Mem{Disp: 8, Base: reg.CL, Index: reg.X0, Scale: 2}, false},
2018-11-26 23:35:26 -08:00
{IsM16, Mem{Disp: 4, Base: reg.DX}, true},
{IsM16, Mem{Disp: 4, Base: reg.R13W, Index: reg.R8W, Scale: 2}, true},
2018-12-14 22:12:28 -08:00
{IsM16, Mem{Disp: 4, Base: reg.X0, Index: reg.R8W, Scale: 2}, false},
{IsM16, Mem{Disp: 4, Base: reg.R13W, Index: reg.X0, Scale: 2}, false},
2018-11-26 23:35:26 -08:00
{IsM32, Mem{Base: reg.R13L, Index: reg.EBX, Scale: 2}, true},
2018-12-14 22:12:28 -08:00
{IsM32, Mem{Base: reg.X0}, false},
2018-11-26 23:35:26 -08:00
{IsM64, Mem{Base: reg.RBX, Index: reg.R12, Scale: 2}, true},
2018-12-14 22:12:28 -08:00
{IsM64, Mem{Base: reg.X0}, false},
2018-11-26 23:35:26 -08:00
{IsM128, Mem{Base: reg.RBX, Index: reg.R12, Scale: 2}, true},
2018-12-14 22:12:28 -08:00
{IsM128, Mem{Base: reg.X0}, false},
2018-11-26 23:35:26 -08:00
{IsM256, Mem{Base: reg.RBX, Index: reg.R12, Scale: 2}, true},
2018-12-14 22:12:28 -08:00
{IsM256, Mem{Base: reg.X0}, false},
all: AVX-512 (#217) Extends avo to support most AVX-512 instruction sets. The instruction type is extended to support suffixes. The K family of opmask registers is added to the register package, and the operand package is updated to support the new operand types. Move instruction deduction in `Load` and `Store` is extended to support KMOV* and VMOV* forms. Internal code generation packages were overhauled. Instruction database loading required various messy changes to account for the additional complexities of the AVX-512 instruction sets. The internal/api package was added to introduce a separation between instruction forms in the database, and the functions avo provides to create them. This was required since with instruction suffixes there is no longer a one-to-one mapping between instruction constructors and opcodes. AVX-512 bloated generated source code size substantially, initially increasing compilation and CI test times to an unacceptable level. Two changes were made to address this: 1. Instruction constructors in the `x86` package moved to an optab-based approach. This compiles substantially faster than the verbose code generation we had before. 2. The most verbose code-generated tests are moved under build tags and limited to a stress test mode. Stress test builds are run on schedule but not in regular CI. An example of AVX-512 accelerated 16-lane MD5 is provided to demonstrate and test the new functionality. Updates #20 #163 #229 Co-authored-by: Vaughn Iverson <vsivsi@yahoo.com>
2021-11-12 18:35:36 -08:00
{IsM512, Mem{Base: reg.RBX, Index: reg.R12, Scale: 2}, true},
{IsM512, Mem{Base: reg.X0}, false},
// Argument references (special cases of memory operands)
{IsM, NewParamAddr("foo", 4), true},
{IsM8, NewParamAddr("foo", 4), true},
{IsM16, NewParamAddr("foo", 4), true},
{IsM32, NewParamAddr("foo", 4), true},
{IsM64, NewParamAddr("foo", 4), true},
// Vector memory operands
{IsVM32X, Mem{Base: reg.R14, Index: reg.X11}, true},
{IsVM32X, Mem{Base: reg.R14L, Index: reg.X11}, false},
{IsVM32X, Mem{Base: reg.R14, Index: reg.Y11}, false},
{IsVM64X, Mem{Base: reg.R14, Index: reg.X11}, true},
{IsVM64X, Mem{Base: reg.R14L, Index: reg.X11}, false},
{IsVM64X, Mem{Base: reg.R14, Index: reg.Y11}, false},
{IsVM32Y, Mem{Base: reg.R9, Index: reg.Y11}, true},
{IsVM32Y, Mem{Base: reg.R11L, Index: reg.Y11}, false},
{IsVM32Y, Mem{Base: reg.R8, Index: reg.Z11}, false},
{IsVM64Y, Mem{Base: reg.R9, Index: reg.Y11}, true},
{IsVM64Y, Mem{Base: reg.R11L, Index: reg.Y11}, false},
{IsVM64Y, Mem{Base: reg.R8, Index: reg.Z11}, false},
2018-11-27 22:08:11 -08:00
all: AVX-512 (#217) Extends avo to support most AVX-512 instruction sets. The instruction type is extended to support suffixes. The K family of opmask registers is added to the register package, and the operand package is updated to support the new operand types. Move instruction deduction in `Load` and `Store` is extended to support KMOV* and VMOV* forms. Internal code generation packages were overhauled. Instruction database loading required various messy changes to account for the additional complexities of the AVX-512 instruction sets. The internal/api package was added to introduce a separation between instruction forms in the database, and the functions avo provides to create them. This was required since with instruction suffixes there is no longer a one-to-one mapping between instruction constructors and opcodes. AVX-512 bloated generated source code size substantially, initially increasing compilation and CI test times to an unacceptable level. Two changes were made to address this: 1. Instruction constructors in the `x86` package moved to an optab-based approach. This compiles substantially faster than the verbose code generation we had before. 2. The most verbose code-generated tests are moved under build tags and limited to a stress test mode. Stress test builds are run on schedule but not in regular CI. An example of AVX-512 accelerated 16-lane MD5 is provided to demonstrate and test the new functionality. Updates #20 #163 #229 Co-authored-by: Vaughn Iverson <vsivsi@yahoo.com>
2021-11-12 18:35:36 -08:00
{IsVM32Z, Mem{Base: reg.R9, Index: reg.Z11}, true},
{IsVM32Z, Mem{Base: reg.R11L, Index: reg.Z11}, false},
{IsVM32Z, Mem{Base: reg.R8, Index: reg.Y11}, false},
{IsVM64Z, Mem{Base: reg.R9, Index: reg.Z11}, true},
{IsVM64Z, Mem{Base: reg.R11L, Index: reg.Z11}, false},
{IsVM64Z, Mem{Base: reg.R8, Index: reg.X11}, false},
2018-11-27 22:08:11 -08:00
// Relative operands
{IsREL8, Rel(math.MinInt8), true},
{IsREL8, Rel(math.MaxInt8), true},
{IsREL8, Rel(math.MinInt8 - 1), false},
{IsREL8, Rel(math.MaxInt8 + 1), false},
{IsREL8, reg.R9B, false},
{IsREL32, Rel(math.MinInt32), true},
{IsREL32, Rel(math.MaxInt32), true},
{IsREL32, LabelRef("label"), true},
{IsREL32, reg.R9L, false},
}
2018-11-26 23:35:26 -08:00
for _, c := range cases {
if c.Predicate(c.Operand) != c.Expect {
t.Errorf("%s( %#v ) != %v", funcname(c.Predicate), c.Operand, c.Expect)
}
}
}
func funcname(f any) string {
return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
}