1package operand
2
3import "github.com/mmcloughlin/avo/reg"
4
5// Pure type assertion checks:
6
7// IsRegister returns whether op has type reg.Register.
8func IsRegister(op Op) bool { _, ok := op.(reg.Register); return ok }
9
10// IsMem returns whether op has type Mem.
11func IsMem(op Op) bool { _, ok := op.(Mem); return ok }
12
13// IsRel returns whether op has type Rel.
14func IsRel(op Op) bool { _, ok := op.(Rel); return ok }
15
16// Checks corresponding to specific operand types in the Intel Manual:
17
18// Is1 returns true if op is the immediate constant 1.
19func Is1(op Op) bool {
20	i, ok := op.(U8)
21	return ok && i == 1
22}
23
24// Is3 returns true if op is the immediate constant 3.
25func Is3(op Op) bool {
26	i, ok := op.(U8)
27	return ok && i == 3
28}
29
30// IsIMM2U returns true if op is a 2-bit unsigned immediate (less than 4).
31func IsIMM2U(op Op) bool {
32	i, ok := op.(U8)
33	return ok && i < 4
34}
35
36// IsIMM8 returns true is op is an 8-bit immediate.
37func IsIMM8(op Op) bool {
38	_, ok := op.(U8)
39	return ok
40}
41
42// IsIMM16 returns true is op is a 16-bit immediate.
43func IsIMM16(op Op) bool {
44	_, ok := op.(U16)
45	return ok
46}
47
48// IsIMM32 returns true is op is a 32-bit immediate.
49func IsIMM32(op Op) bool {
50	_, ok := op.(U32)
51	return ok
52}
53
54// IsIMM64 returns true is op is a 64-bit immediate.
55func IsIMM64(op Op) bool {
56	_, ok := op.(U64)
57	return ok
58}
59
60// IsAL returns true if op is the AL register.
61func IsAL(op Op) bool {
62	return op == reg.AL
63}
64
65// IsCL returns true if op is the CL register.
66func IsCL(op Op) bool {
67	return op == reg.CL
68}
69
70// IsAX returns true if op is the 16-bit AX register.
71func IsAX(op Op) bool {
72	return op == reg.AX
73}
74
75// IsEAX returns true if op is the 32-bit EAX register.
76func IsEAX(op Op) bool {
77	return op == reg.EAX
78}
79
80// IsRAX returns true if op is the 64-bit RAX register.
81func IsRAX(op Op) bool {
82	return op == reg.RAX
83}
84
85// IsR8 returns true if op is an 8-bit general-purpose register.
86func IsR8(op Op) bool {
87	return IsGP(op, 1)
88}
89
90// IsR16 returns true if op is a 16-bit general-purpose register.
91func IsR16(op Op) bool {
92	return IsGP(op, 2)
93}
94
95// IsR32 returns true if op is a 32-bit general-purpose register.
96func IsR32(op Op) bool {
97	return IsGP(op, 4)
98}
99
100// IsR64 returns true if op is a 64-bit general-purpose register.
101func IsR64(op Op) bool {
102	return IsGP(op, 8)
103}
104
105// IsPseudo returns true if op is a pseudo register.
106func IsPseudo(op Op) bool {
107	return IsRegisterKind(op, reg.KindPseudo)
108}
109
110// IsGP returns true if op is a general-purpose register of size n bytes.
111func IsGP(op Op, n uint) bool {
112	return IsRegisterKindSize(op, reg.KindGP, n)
113}
114
115// IsXMM0 returns true if op is the X0 register.
116func IsXMM0(op Op) bool {
117	return op == reg.X0
118}
119
120// IsXMM returns true if op is a 128-bit XMM register.
121func IsXMM(op Op) bool {
122	return IsRegisterKindSize(op, reg.KindVector, 16)
123}
124
125// IsYMM returns true if op is a 256-bit YMM register.
126func IsYMM(op Op) bool {
127	return IsRegisterKindSize(op, reg.KindVector, 32)
128}
129
130// IsRegisterKindSize returns true if op is a register of the given kind and size in bytes.
131func IsRegisterKindSize(op Op, k reg.Kind, n uint) bool {
132	r, ok := op.(reg.Register)
133	return ok && r.Kind() == k && r.Size() == n
134}
135
136// IsRegisterKind returns true if op is a register of the given kind.
137func IsRegisterKind(op Op, k reg.Kind) bool {
138	r, ok := op.(reg.Register)
139	return ok && r.Kind() == k
140}
141
142// IsM returns true if op is a 16-, 32- or 64-bit memory operand.
143func IsM(op Op) bool {
144	// TODO(mbm): confirm "m" check is defined correctly
145	// Intel manual: "A 16-, 32- or 64-bit operand in memory."
146	return IsM16(op) || IsM32(op) || IsM64(op)
147}
148
149// IsM8 returns true if op is an 8-bit memory operand.
150func IsM8(op Op) bool {
151	// TODO(mbm): confirm "m8" check is defined correctly
152	// Intel manual: "A byte operand in memory, usually expressed as a variable or
153	// array name, but pointed to by the DS:(E)SI or ES:(E)DI registers. In 64-bit
154	// mode, it is pointed to by the RSI or RDI registers."
155	return IsMSize(op, 1)
156}
157
158// IsM16 returns true if op is a 16-bit memory operand.
159func IsM16(op Op) bool {
160	return IsMSize(op, 2)
161}
162
163// IsM32 returns true if op is a 16-bit memory operand.
164func IsM32(op Op) bool {
165	return IsMSize(op, 4)
166}
167
168// IsM64 returns true if op is a 64-bit memory operand.
169func IsM64(op Op) bool {
170	return IsMSize(op, 8)
171}
172
173// IsMSize returns true if op is a memory operand using general-purpose address
174// registers of the given size in bytes.
175func IsMSize(op Op, n uint) bool {
176	// TODO(mbm): should memory operands have a size attribute as well?
177	// TODO(mbm): m8,m16,m32,m64 checks do not actually check size
178	m, ok := op.(Mem)
179	return ok && IsMReg(m.Base) && (m.Index == nil || IsMReg(m.Index))
180}
181
182// IsMReg returns true if op is a register that can be used in a memory operand.
183func IsMReg(op Op) bool {
184	return IsPseudo(op) || IsRegisterKind(op, reg.KindGP)
185}
186
187// IsM128 returns true if op is a 128-bit memory operand.
188func IsM128(op Op) bool {
189	// TODO(mbm): should "m128" be the same as "m64"?
190	return IsM64(op)
191}
192
193// IsM256 returns true if op is a 256-bit memory operand.
194func IsM256(op Op) bool {
195	// TODO(mbm): should "m256" be the same as "m64"?
196	return IsM64(op)
197}
198
199// IsVM32X returns true if op is a vector memory operand with 32-bit XMM index.
200func IsVM32X(op Op) bool {
201	return IsVmx(op)
202}
203
204// IsVM64X returns true if op is a vector memory operand with 64-bit XMM index.
205func IsVM64X(op Op) bool {
206	return IsVmx(op)
207}
208
209// IsVmx returns true if op is a vector memory operand with XMM index.
210func IsVmx(op Op) bool {
211	return isvm(op, IsXMM)
212}
213
214// IsVM32Y returns true if op is a vector memory operand with 32-bit YMM index.
215func IsVM32Y(op Op) bool {
216	return IsVmy(op)
217}
218
219// IsVM64Y returns true if op is a vector memory operand with 64-bit YMM index.
220func IsVM64Y(op Op) bool {
221	return IsVmy(op)
222}
223
224// IsVmy returns true if op is a vector memory operand with YMM index.
225func IsVmy(op Op) bool {
226	return isvm(op, IsYMM)
227}
228
229func isvm(op Op, idx func(Op) bool) bool {
230	m, ok := op.(Mem)
231	return ok && IsR64(m.Base) && idx(m.Index)
232}
233
234// IsREL8 returns true if op is an 8-bit offset relative to instruction pointer.
235func IsREL8(op Op) bool {
236	r, ok := op.(Rel)
237	return ok && r == Rel(int8(r))
238}
239
240// IsREL32 returns true if op is an offset relative to instruction pointer, or a
241// label reference.
242func IsREL32(op Op) bool {
243	// TODO(mbm): should labels be considered separately?
244	_, rel := op.(Rel)
245	_, label := op.(LabelRef)
246	return rel || label
247}
248