1package operand
2
3import (
4	"math"
5	"reflect"
6	"runtime"
7	"testing"
8
9	"github.com/mmcloughlin/avo/reg"
10)
11
12func TestChecks(t *testing.T) {
13	cases := []struct {
14		Predicate func(Op) bool
15		Operand   Op
16		Expect    bool
17	}{
18		// Immediates
19		{Is1, Imm(1), true},
20		{Is1, Imm(23), false},
21
22		{Is3, Imm(3), true},
23		{Is3, Imm(23), false},
24
25		{IsIMM2U, Imm(3), true},
26		{IsIMM2U, Imm(4), false},
27
28		{IsIMM8, Imm(255), true},
29		{IsIMM8, Imm(256), false},
30
31		{IsIMM16, Imm((1 << 16) - 1), true},
32		{IsIMM16, Imm(1 << 16), false},
33
34		{IsIMM32, Imm((1 << 32) - 1), true},
35		{IsIMM32, Imm(1 << 32), false},
36
37		{IsIMM64, Imm((1 << 64) - 1), true},
38
39		// Specific registers
40		{IsAL, reg.AL, true},
41		{IsAL, reg.CL, false},
42
43		{IsCL, reg.CL, true},
44		{IsCL, reg.DH, false},
45
46		{IsAX, reg.AX, true},
47		{IsAX, reg.DX, false},
48
49		{IsEAX, reg.EAX, true},
50		{IsEAX, reg.ECX, false},
51
52		{IsRAX, reg.RAX, true},
53		{IsRAX, reg.R13, false},
54
55		// General-purpose registers
56		{IsR8, reg.AL, true},
57		{IsR8, reg.CH, true},
58		{IsR8, reg.EAX, false},
59
60		{IsR16, reg.DX, true},
61		{IsR16, reg.R10W, true},
62		{IsR16, reg.R10B, false},
63
64		{IsR32, reg.EBP, true},
65		{IsR32, reg.R14L, true},
66		{IsR32, reg.R8, false},
67
68		{IsR64, reg.RDX, true},
69		{IsR64, reg.R10, true},
70		{IsR64, reg.EBX, false},
71
72		// Vector registers
73		{IsXMM0, reg.X0, true},
74		{IsXMM0, reg.X13, false},
75		{IsXMM0, reg.Y3, false},
76
77		{IsXMM, reg.X0, true},
78		{IsXMM, reg.X13, true},
79		{IsXMM, reg.Y3, false},
80		{IsXMM, reg.Z23, false},
81
82		{IsYMM, reg.Y0, true},
83		{IsYMM, reg.Y13, true},
84		{IsYMM, reg.Y31, true},
85		{IsYMM, reg.X3, false},
86		{IsYMM, reg.Z3, false},
87
88		// Pseudo registers.
89		{IsPseudo, reg.FramePointer, true},
90		{IsPseudo, reg.ProgramCounter, true},
91		{IsPseudo, reg.StaticBase, true},
92		{IsPseudo, reg.StackPointer, true},
93		{IsPseudo, reg.ECX, false},
94		{IsPseudo, reg.X9, false},
95
96		// Memory operands
97		{IsM, Mem{Base: reg.CX}, true},
98		{IsM, Mem{Base: reg.ECX}, true},
99		{IsM, Mem{Base: reg.RCX}, true},
100		{IsM, Mem{Base: reg.X0}, false},
101
102		{IsM8, Mem{Disp: 8, Base: reg.CL}, true},
103		{IsM8, Mem{Disp: 8, Base: reg.CL, Index: reg.AH, Scale: 2}, true},
104		{IsM8, Mem{Disp: 8, Base: reg.X0, Index: reg.AH, Scale: 2}, false},
105		{IsM8, Mem{Disp: 8, Base: reg.CL, Index: reg.X0, Scale: 2}, false},
106
107		{IsM16, Mem{Disp: 4, Base: reg.DX}, true},
108		{IsM16, Mem{Disp: 4, Base: reg.R13W, Index: reg.R8W, Scale: 2}, true},
109		{IsM16, Mem{Disp: 4, Base: reg.X0, Index: reg.R8W, Scale: 2}, false},
110		{IsM16, Mem{Disp: 4, Base: reg.R13W, Index: reg.X0, Scale: 2}, false},
111
112		{IsM32, Mem{Base: reg.R13L, Index: reg.EBX, Scale: 2}, true},
113		{IsM32, Mem{Base: reg.X0}, false},
114
115		{IsM64, Mem{Base: reg.RBX, Index: reg.R12, Scale: 2}, true},
116		{IsM64, Mem{Base: reg.X0}, false},
117
118		{IsM128, Mem{Base: reg.RBX, Index: reg.R12, Scale: 2}, true},
119		{IsM128, Mem{Base: reg.X0}, false},
120
121		{IsM256, Mem{Base: reg.RBX, Index: reg.R12, Scale: 2}, true},
122		{IsM256, Mem{Base: reg.X0}, false},
123
124		// Argument references (special cases of memory operands)
125		{IsM, NewParamAddr("foo", 4), true},
126		{IsM8, NewParamAddr("foo", 4), true},
127		{IsM16, NewParamAddr("foo", 4), true},
128		{IsM32, NewParamAddr("foo", 4), true},
129		{IsM64, NewParamAddr("foo", 4), true},
130
131		// Vector memory operands
132		{IsVM32X, Mem{Base: reg.R14, Index: reg.X11}, true},
133		{IsVM32X, Mem{Base: reg.R14L, Index: reg.X11}, false},
134		{IsVM32X, Mem{Base: reg.R14, Index: reg.Y11}, false},
135
136		{IsVM64X, Mem{Base: reg.R14, Index: reg.X11}, true},
137		{IsVM64X, Mem{Base: reg.R14L, Index: reg.X11}, false},
138		{IsVM64X, Mem{Base: reg.R14, Index: reg.Y11}, false},
139
140		{IsVM32Y, Mem{Base: reg.R9, Index: reg.Y11}, true},
141		{IsVM32Y, Mem{Base: reg.R11L, Index: reg.Y11}, false},
142		{IsVM32Y, Mem{Base: reg.R8, Index: reg.Z11}, false},
143
144		{IsVM64Y, Mem{Base: reg.R9, Index: reg.Y11}, true},
145		{IsVM64Y, Mem{Base: reg.R11L, Index: reg.Y11}, false},
146		{IsVM64Y, Mem{Base: reg.R8, Index: reg.Z11}, false},
147
148		// Relative operands
149		{IsREL8, Rel(math.MinInt8), true},
150		{IsREL8, Rel(math.MaxInt8), true},
151		{IsREL8, Rel(math.MinInt8 - 1), false},
152		{IsREL8, Rel(math.MaxInt8 + 1), false},
153		{IsREL8, reg.R9B, false},
154
155		{IsREL32, Rel(math.MinInt32), true},
156		{IsREL32, Rel(math.MaxInt32), true},
157		{IsREL32, LabelRef("label"), true},
158		{IsREL32, reg.R9L, false},
159	}
160
161	for _, c := range cases {
162		if c.Predicate(c.Operand) != c.Expect {
163			t.Errorf("%s( %#v ) != %v", funcname(c.Predicate), c.Operand, c.Expect)
164		}
165	}
166}
167
168func funcname(f interface{}) string {
169	return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
170}
171