1 //===- subzero/unittest/AssemblerX8632/GPRArith.cpp -----------------------===//
2 //
3 // The Subzero Code Generator
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 #include "AssemblerX8632/TestUtil.h"
10
11 namespace Ice {
12 namespace X8632 {
13 namespace Test {
14 namespace {
15
TEST_F(AssemblerX8632LowLevelTest,PushalPopal)16 TEST_F(AssemblerX8632LowLevelTest, PushalPopal) {
17 // These are invalid in x86-64, so we can't write tests which will execute
18 // these instructions.
19 __ pushal();
20 __ popal();
21
22 constexpr size_t ByteCount = 2;
23 ASSERT_EQ(ByteCount, codeBytesSize());
24
25 constexpr uint8_t Pushal = 0x60;
26 constexpr uint8_t Popal = 0x61;
27
28 verifyBytes<ByteCount>(codeBytes(), Pushal, Popal);
29 }
30
TEST_F(AssemblerX8632Test,PopAddr)31 TEST_F(AssemblerX8632Test, PopAddr) {
32 const uint32_t T0 = allocateDword();
33 constexpr uint32_t V0 = 0xEFAB;
34
35 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(0xC0FFEE));
36 __ pushl(GPRRegister::Encoded_Reg_eax);
37 __ popl(dwordAddress(T0));
38
39 AssembledTest test = assemble();
40 test.setDwordTo(T0, V0);
41
42 test.run();
43
44 ASSERT_EQ(0xC0FFEEul, test.contentsOfDword(T0));
45 }
46
TEST_F(AssemblerX8632Test,SetCC)47 TEST_F(AssemblerX8632Test, SetCC) {
48 #define TestSetCC(C, Src0, Value0, Src1, Value1, Dest, IsTrue) \
49 do { \
50 const uint32_t T0 = allocateDword(); \
51 constexpr uint32_t V0 = 0xF00F00; \
52 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Src0, Immediate(Value0)); \
53 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Src1, Immediate(Value1)); \
54 __ cmp(IceType_i32, GPRRegister::Encoded_Reg_##Src0, \
55 GPRRegister::Encoded_Reg_##Src1); \
56 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dest, Immediate(0)); \
57 __ setcc(Cond::Br_##C, ByteRegister(GPRRegister::Encoded_Reg_##Dest)); \
58 __ setcc(Cond::Br_##C, dwordAddress(T0)); \
59 \
60 AssembledTest test = assemble(); \
61 test.setDwordTo(T0, V0); \
62 \
63 test.run(); \
64 \
65 EXPECT_EQ(IsTrue, test.Dest()) \
66 << "(" #C ", " #Src0 ", " #Value0 ", " #Src1 ", " #Value1 ", " #Dest \
67 ", " #IsTrue ")"; \
68 EXPECT_EQ((0xF00F00 | IsTrue), test.contentsOfDword(T0)) \
69 << "(" #C ", " #Src0 ", " #Value0 ", " #Src1 ", " #Value1 ", " #Dest \
70 ", " #IsTrue ")"; \
71 \
72 reset(); \
73 } while (0)
74
75 TestSetCC(o, eax, 0x80000000u, ebx, 0x1u, ecx, 1u);
76 TestSetCC(o, eax, 0x1u, ebx, 0x10000000u, ecx, 0u);
77
78 TestSetCC(no, ebx, 0x1u, ecx, 0x10000000u, edx, 1u);
79 TestSetCC(no, ebx, 0x80000000u, ecx, 0x1u, edx, 0u);
80
81 TestSetCC(b, ecx, 0x1, edx, 0x80000000u, eax, 1u);
82 TestSetCC(b, ecx, 0x80000000u, edx, 0x1u, eax, 0u);
83
84 TestSetCC(ae, edx, 0x80000000u, edi, 0x1u, ebx, 1u);
85 TestSetCC(ae, edx, 0x1u, edi, 0x80000000u, ebx, 0u);
86
87 TestSetCC(e, edi, 0x1u, esi, 0x1u, ecx, 1u);
88 TestSetCC(e, edi, 0x1u, esi, 0x11111u, ecx, 0u);
89
90 TestSetCC(ne, esi, 0x80000000u, eax, 0x1u, edx, 1u);
91 TestSetCC(ne, esi, 0x1u, eax, 0x1u, edx, 0u);
92
93 TestSetCC(be, eax, 0x1u, ebx, 0x80000000u, eax, 1u);
94 TestSetCC(be, eax, 0x80000000u, ebx, 0x1u, eax, 0u);
95
96 TestSetCC(a, ebx, 0x80000000u, ecx, 0x1u, ebx, 1u);
97 TestSetCC(a, ebx, 0x1u, ecx, 0x80000000u, ebx, 0u);
98
99 TestSetCC(s, ecx, 0x1u, edx, 0x80000000u, ecx, 1u);
100 TestSetCC(s, ecx, 0x80000000u, edx, 0x1u, ecx, 0u);
101
102 TestSetCC(ns, edx, 0x80000000u, edi, 0x1u, ecx, 1u);
103 TestSetCC(ns, edx, 0x1u, edi, 0x80000000u, ecx, 0u);
104
105 TestSetCC(p, edi, 0x80000000u, esi, 0x1u, edx, 1u);
106 TestSetCC(p, edi, 0x1u, esi, 0x80000000u, edx, 0u);
107
108 TestSetCC(np, esi, 0x1u, edi, 0x80000000u, eax, 1u);
109 TestSetCC(np, esi, 0x80000000u, edi, 0x1u, eax, 0u);
110
111 TestSetCC(l, edi, 0x80000000u, eax, 0x1u, ebx, 1u);
112 TestSetCC(l, edi, 0x1u, eax, 0x80000000u, ebx, 0u);
113
114 TestSetCC(ge, eax, 0x1u, ebx, 0x80000000u, ecx, 1u);
115 TestSetCC(ge, eax, 0x80000000u, ebx, 0x1u, ecx, 0u);
116
117 TestSetCC(le, ebx, 0x80000000u, ecx, 0x1u, edx, 1u);
118 TestSetCC(le, ebx, 0x1u, ecx, 0x80000000u, edx, 0u);
119
120 #undef TestSetCC
121 }
122
TEST_F(AssemblerX8632Test,Lea)123 TEST_F(AssemblerX8632Test, Lea) {
124 #define TestLeaBaseDisp(Base, BaseValue, Disp, Dst) \
125 do { \
126 static constexpr char TestString[] = \
127 "(" #Base ", " #BaseValue ", " #Dst ")"; \
128 if (GPRRegister::Encoded_Reg_##Base != GPRRegister::Encoded_Reg_esp && \
129 GPRRegister::Encoded_Reg_##Base != GPRRegister::Encoded_Reg_ebp) { \
130 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Base, \
131 Immediate(BaseValue)); \
132 } \
133 __ lea(IceType_i32, GPRRegister::Encoded_Reg_##Dst, \
134 Address(GPRRegister::Encoded_Reg_##Base, Disp, \
135 AssemblerFixup::NoFixup)); \
136 AssembledTest test = assemble(); \
137 test.run(); \
138 ASSERT_EQ(test.Base() + (Disp), test.Dst()) \
139 << TestString << " with Disp " << Disp; \
140 reset(); \
141 } while (0)
142
143 #define TestLeaIndex32bitDisp(Index, IndexValue, Disp, Dst0, Dst1, Dst2, Dst3) \
144 do { \
145 static constexpr char TestString[] = \
146 "(" #Index ", " #IndexValue ", " #Dst0 ", " #Dst1 ", " #Dst2 \
147 ", " #Dst3 ")"; \
148 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Index, \
149 Immediate(IndexValue)); \
150 __ lea(IceType_i32, GPRRegister::Encoded_Reg_##Dst0, \
151 Address(GPRRegister::Encoded_Reg_##Index, Traits::TIMES_1, Disp, \
152 AssemblerFixup::NoFixup)); \
153 __ lea(IceType_i32, GPRRegister::Encoded_Reg_##Dst1, \
154 Address(GPRRegister::Encoded_Reg_##Index, Traits::TIMES_2, Disp, \
155 AssemblerFixup::NoFixup)); \
156 __ lea(IceType_i32, GPRRegister::Encoded_Reg_##Dst2, \
157 Address(GPRRegister::Encoded_Reg_##Index, Traits::TIMES_4, Disp, \
158 AssemblerFixup::NoFixup)); \
159 __ lea(IceType_i32, GPRRegister::Encoded_Reg_##Dst3, \
160 Address(GPRRegister::Encoded_Reg_##Index, Traits::TIMES_8, Disp, \
161 AssemblerFixup::NoFixup)); \
162 AssembledTest test = assemble(); \
163 test.run(); \
164 ASSERT_EQ((test.Index() << Traits::TIMES_1) + (Disp), test.Dst0()) \
165 << TestString << " " << Disp; \
166 ASSERT_EQ((test.Index() << Traits::TIMES_2) + (Disp), test.Dst1()) \
167 << TestString << " " << Disp; \
168 ASSERT_EQ((test.Index() << Traits::TIMES_4) + (Disp), test.Dst2()) \
169 << TestString << " " << Disp; \
170 ASSERT_EQ((test.Index() << Traits::TIMES_8) + (Disp), test.Dst3()) \
171 << TestString << " " << Disp; \
172 reset(); \
173 } while (0)
174
175 #define TestLeaBaseIndexDisp(Base, BaseValue, Index, IndexValue, Disp, Dst0, \
176 Dst1, Dst2, Dst3) \
177 do { \
178 static constexpr char TestString[] = \
179 "(" #Base ", " #BaseValue ", " #Index ", " #IndexValue ", " #Dst0 \
180 ", " #Dst1 ", " #Dst2 ", " #Dst3 ")"; \
181 if (GPRRegister::Encoded_Reg_##Base != GPRRegister::Encoded_Reg_esp && \
182 GPRRegister::Encoded_Reg_##Base != GPRRegister::Encoded_Reg_ebp) { \
183 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Base, \
184 Immediate(BaseValue)); \
185 } \
186 /* esp is not a valid index register. */ \
187 if (GPRRegister::Encoded_Reg_##Index != GPRRegister::Encoded_Reg_ebp) { \
188 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Index, \
189 Immediate(IndexValue)); \
190 } \
191 __ lea(IceType_i32, GPRRegister::Encoded_Reg_##Dst0, \
192 Address(GPRRegister::Encoded_Reg_##Base, \
193 GPRRegister::Encoded_Reg_##Index, Traits::TIMES_1, Disp, \
194 AssemblerFixup::NoFixup)); \
195 __ lea(IceType_i32, GPRRegister::Encoded_Reg_##Dst1, \
196 Address(GPRRegister::Encoded_Reg_##Base, \
197 GPRRegister::Encoded_Reg_##Index, Traits::TIMES_2, Disp, \
198 AssemblerFixup::NoFixup)); \
199 __ lea(IceType_i32, GPRRegister::Encoded_Reg_##Dst2, \
200 Address(GPRRegister::Encoded_Reg_##Base, \
201 GPRRegister::Encoded_Reg_##Index, Traits::TIMES_4, Disp, \
202 AssemblerFixup::NoFixup)); \
203 __ lea(IceType_i32, GPRRegister::Encoded_Reg_##Dst3, \
204 Address(GPRRegister::Encoded_Reg_##Base, \
205 GPRRegister::Encoded_Reg_##Index, Traits::TIMES_8, Disp, \
206 AssemblerFixup::NoFixup)); \
207 AssembledTest test = assemble(); \
208 test.run(); \
209 uint32_t ExpectedIndexValue = test.Index(); \
210 if (GPRRegister::Encoded_Reg_##Index == GPRRegister::Encoded_Reg_esp) { \
211 ExpectedIndexValue = 0; \
212 } \
213 ASSERT_EQ(test.Base() + (ExpectedIndexValue << Traits::TIMES_1) + (Disp), \
214 test.Dst0()) \
215 << TestString << " " << Disp; \
216 ASSERT_EQ(test.Base() + (ExpectedIndexValue << Traits::TIMES_2) + (Disp), \
217 test.Dst1()) \
218 << TestString << " " << Disp; \
219 ASSERT_EQ(test.Base() + (ExpectedIndexValue << Traits::TIMES_4) + (Disp), \
220 test.Dst2()) \
221 << TestString << " " << Disp; \
222 ASSERT_EQ(test.Base() + (ExpectedIndexValue << Traits::TIMES_8) + (Disp), \
223 test.Dst3()) \
224 << TestString << " " << Disp; \
225 reset(); \
226 } while (0)
227
228 for (const int32_t Disp :
229 {0x00, 0x06, -0x06, 0x0600, -0x6000, 0x6000000, -0x6000000}) {
230 TestLeaBaseDisp(eax, 0x10000Fu, Disp, ebx);
231 TestLeaBaseDisp(ebx, 0x20000Fu, Disp, ecx);
232 TestLeaBaseDisp(ecx, 0x30000Fu, Disp, edx);
233 TestLeaBaseDisp(edx, 0x40000Fu, Disp, esi);
234 TestLeaBaseDisp(esi, 0x50000Fu, Disp, edi);
235 TestLeaBaseDisp(edi, 0x60000Fu, Disp, eax);
236 TestLeaBaseDisp(esp, 0x11000Fu, Disp, eax);
237 TestLeaBaseDisp(ebp, 0x22000Fu, Disp, ecx);
238 }
239
240 // esp is not a valid index register.
241 // ebp is not valid in this addressing mode (rm = 0).
242 for (const int32_t Disp :
243 {0x00, 0x06, -0x06, 0x0600, -0x6000, 0x6000000, -0x6000000}) {
244 TestLeaIndex32bitDisp(eax, 0x2000u, Disp, ebx, ecx, edx, esi);
245 TestLeaIndex32bitDisp(ebx, 0x4000u, Disp, ecx, edx, esi, edi);
246 TestLeaIndex32bitDisp(ecx, 0x6000u, Disp, edx, esi, edi, eax);
247 TestLeaIndex32bitDisp(edx, 0x8000u, Disp, esi, edi, eax, ebx);
248 TestLeaIndex32bitDisp(esi, 0xA000u, Disp, edi, eax, ebx, ecx);
249 TestLeaIndex32bitDisp(edi, 0xC000u, Disp, eax, ebx, ecx, edx);
250 }
251
252 for (const int32_t Disp :
253 {0x00, 0x06, -0x06, 0x0600, -0x6000, 0x6000000, -0x6000000}) {
254 TestLeaBaseIndexDisp(eax, 0x100000u, ebx, 0x600u, Disp, ecx, edx, esi, edi);
255 TestLeaBaseIndexDisp(ebx, 0x200000u, ecx, 0x500u, Disp, edx, esi, edi, eax);
256 TestLeaBaseIndexDisp(ecx, 0x300000u, edx, 0x400u, Disp, esi, edi, eax, ebx);
257 TestLeaBaseIndexDisp(edx, 0x400000u, esi, 0x300u, Disp, edi, eax, ebx, ecx);
258 TestLeaBaseIndexDisp(esi, 0x500000u, edi, 0x200u, Disp, eax, ebx, ecx, edx);
259 TestLeaBaseIndexDisp(edi, 0x600000u, eax, 0x100u, Disp, ebx, ecx, edx, esi);
260
261 /* Initializers are ignored when Src[01] is ebp/esp. */
262 TestLeaBaseIndexDisp(esp, 0, ebx, 0x6000u, Disp, ecx, edx, esi, edi);
263 TestLeaBaseIndexDisp(esp, 0, ecx, 0x5000u, Disp, edx, esi, edi, eax);
264 TestLeaBaseIndexDisp(esp, 0, edx, 0x4000u, Disp, esi, edi, eax, ebx);
265 TestLeaBaseIndexDisp(esp, 0, esi, 0x3000u, Disp, edi, eax, ebx, ecx);
266 TestLeaBaseIndexDisp(esp, 0, edi, 0x2000u, Disp, eax, ebx, ecx, edx);
267 TestLeaBaseIndexDisp(esp, 0, eax, 0x1000u, Disp, ebx, ecx, edx, esi);
268
269 TestLeaBaseIndexDisp(ebp, 0, ebx, 0x6000u, Disp, ecx, edx, esi, edi);
270 TestLeaBaseIndexDisp(ebp, 0, ecx, 0x5000u, Disp, edx, esi, edi, eax);
271 TestLeaBaseIndexDisp(ebp, 0, edx, 0x4000u, Disp, esi, edi, eax, ebx);
272 TestLeaBaseIndexDisp(ebp, 0, esi, 0x3000u, Disp, edi, eax, ebx, ecx);
273 TestLeaBaseIndexDisp(ebp, 0, edi, 0x2000u, Disp, eax, ebx, ecx, edx);
274 TestLeaBaseIndexDisp(ebp, 0, eax, 0x1000u, Disp, ebx, ecx, edx, esi);
275
276 TestLeaBaseIndexDisp(eax, 0x1000000u, ebp, 0, Disp, ecx, edx, esi, edi);
277 TestLeaBaseIndexDisp(ebx, 0x2000000u, ebp, 0, Disp, edx, esi, edi, eax);
278 TestLeaBaseIndexDisp(ecx, 0x3000000u, ebp, 0, Disp, esi, edi, eax, ebx);
279 TestLeaBaseIndexDisp(edx, 0x4000000u, ebp, 0, Disp, edi, eax, ebx, ecx);
280 TestLeaBaseIndexDisp(esi, 0x5000000u, ebp, 0, Disp, eax, ebx, ecx, edx);
281 TestLeaBaseIndexDisp(edi, 0x6000000u, ebp, 0, Disp, ebx, ecx, edx, esi);
282
283 TestLeaBaseIndexDisp(esp, 0, ebp, 0, Disp, ebx, ecx, edx, esi);
284 }
285
286 // Absolute addressing mode is tested in the Low Level tests. The encoding used
287 // by the assembler has different meanings in x86-32 and x86-64.
288 #undef TestLeaBaseIndexDisp
289 #undef TestLeaScaled32bitDisp
290 #undef TestLeaBaseDisp
291 }
292
TEST_F(AssemblerX8632LowLevelTest,LeaAbsolute)293 TEST_F(AssemblerX8632LowLevelTest, LeaAbsolute) {
294 #define TestLeaAbsolute(Dst, Value) \
295 do { \
296 static constexpr char TestString[] = "(" #Dst ", " #Value ")"; \
297 __ lea(IceType_i32, GPRRegister::Encoded_Reg_##Dst, \
298 Address(Value, AssemblerFixup::NoFixup)); \
299 static constexpr uint32_t ByteCount = 6; \
300 ASSERT_EQ(ByteCount, codeBytesSize()) << TestString; \
301 static constexpr uint8_t Opcode = 0x8D; \
302 static constexpr uint8_t ModRM = \
303 /*mod=*/0x00 | /*reg*/ (GPRRegister::Encoded_Reg_##Dst << 3) | \
304 /*rm*/ GPRRegister::Encoded_Reg_ebp; \
305 verifyBytes<ByteCount>(codeBytes(), Opcode, ModRM, (Value)&0xFF, \
306 (Value >> 8) & 0xFF, (Value >> 16) & 0xFF, \
307 (Value >> 24) & 0xFF); \
308 reset(); \
309 } while (0)
310
311 TestLeaAbsolute(eax, 0x11BEEF22);
312 TestLeaAbsolute(ebx, 0x33BEEF44);
313 TestLeaAbsolute(ecx, 0x55BEEF66);
314 TestLeaAbsolute(edx, 0x77BEEF88);
315 TestLeaAbsolute(esi, 0x99BEEFAA);
316 TestLeaAbsolute(edi, 0xBBBEEFBB);
317
318 #undef TesLeaAbsolute
319 }
320
TEST_F(AssemblerX8632Test,Test)321 TEST_F(AssemblerX8632Test, Test) {
322 static constexpr uint32_t Mask8 = 0xFF;
323 static constexpr uint32_t Mask16 = 0xFFFF;
324 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
325
326 #define TestImplRegReg(Dst, Value0, Src, Value1, Size) \
327 do { \
328 static constexpr bool NearJump = true; \
329 static constexpr char TestString[] = \
330 "(" #Dst ", " #Value0 ", " #Src ", " #Value1 ", " #Size ")"; \
331 static constexpr uint32_t ValueIfTrue = 0xBEEFFEEB; \
332 static constexpr uint32_t ValueIfFalse = 0x11111111; \
333 \
334 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
335 Immediate(Value0)); \
336 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
337 Immediate(Value1)); \
338 __ test(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
339 GPRRegister::Encoded_Reg_##Src); \
340 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dst, \
341 Immediate(ValueIfFalse)); \
342 Label Done; \
343 __ j(Cond::Br_e, &Done, NearJump); \
344 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dst, \
345 Immediate(ValueIfTrue)); \
346 __ bind(&Done); \
347 \
348 AssembledTest test = assemble(); \
349 test.run(); \
350 \
351 ASSERT_EQ(((Value0)&Mask##Size) & ((Value1)&Mask##Size) ? ValueIfTrue \
352 : ValueIfFalse, \
353 test.Dst()) \
354 << TestString; \
355 reset(); \
356 } while (0)
357
358 #define TestImplRegImm(Dst, Value0, Imm, Size) \
359 do { \
360 static constexpr bool NearJump = true; \
361 static constexpr char TestString[] = \
362 "(" #Dst ", " #Value0 ", " #Imm ", " #Size ")"; \
363 static constexpr uint32_t ValueIfTrue = 0xBEEFFEEB; \
364 static constexpr uint32_t ValueIfFalse = 0x11111111; \
365 \
366 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
367 Immediate(Value0)); \
368 __ test(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
369 Immediate((Imm)&Mask##Size)); \
370 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dst, \
371 Immediate(ValueIfFalse)); \
372 Label Done; \
373 __ j(Cond::Br_e, &Done, NearJump); \
374 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dst, \
375 Immediate(ValueIfTrue)); \
376 __ bind(&Done); \
377 \
378 AssembledTest test = assemble(); \
379 test.run(); \
380 \
381 ASSERT_EQ(((Value0)&Mask##Size) & ((Imm)&Mask##Size) ? ValueIfTrue \
382 : ValueIfFalse, \
383 test.Dst()) \
384 << TestString; \
385 reset(); \
386 } while (0)
387
388 #define TestImplAddrReg(Value0, Src, Value1, Size) \
389 do { \
390 static constexpr bool NearJump = true; \
391 static constexpr char TestString[] = \
392 "(Addr, " #Value0 ", " #Src ", " #Value1 ", " #Size ")"; \
393 static constexpr uint32_t ValueIfTrue = 0xBEEFFEEB; \
394 static constexpr uint32_t ValueIfFalse = 0x11111111; \
395 const uint32_t T0 = allocateDword(); \
396 \
397 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
398 Immediate(Value1)); \
399 __ test(IceType_i##Size, dwordAddress(T0), \
400 GPRRegister::Encoded_Reg_##Src); \
401 __ mov(IceType_i32, dwordAddress(T0), Immediate(ValueIfFalse)); \
402 Label Done; \
403 __ j(Cond::Br_e, &Done, NearJump); \
404 __ mov(IceType_i32, dwordAddress(T0), Immediate(ValueIfTrue)); \
405 __ bind(&Done); \
406 \
407 AssembledTest test = assemble(); \
408 test.setDwordTo(T0, uint32_t(Value0)); \
409 test.run(); \
410 \
411 ASSERT_EQ(((Value0)&Mask##Size) & ((Value1)&Mask##Size) ? ValueIfTrue \
412 : ValueIfFalse, \
413 test.contentsOfDword(T0)) \
414 << TestString; \
415 reset(); \
416 } while (0)
417
418 #define TestImplAddrImm(Value0, Value1, Size) \
419 do { \
420 static constexpr bool NearJump = true; \
421 static constexpr char TestString[] = \
422 "(Addr, " #Value0 ", " #Value1 ", " #Size ")"; \
423 static constexpr uint32_t ValueIfTrue = 0xBEEFFEEB; \
424 static constexpr uint32_t ValueIfFalse = 0x11111111; \
425 const uint32_t T0 = allocateDword(); \
426 \
427 __ test(IceType_i##Size, dwordAddress(T0), \
428 Immediate((Value1)&Mask##Size)); \
429 __ mov(IceType_i32, dwordAddress(T0), Immediate(ValueIfFalse)); \
430 Label Done; \
431 __ j(Cond::Br_e, &Done, NearJump); \
432 __ mov(IceType_i32, dwordAddress(T0), Immediate(ValueIfTrue)); \
433 __ bind(&Done); \
434 \
435 AssembledTest test = assemble(); \
436 test.setDwordTo(T0, uint32_t(Value0)); \
437 test.run(); \
438 \
439 ASSERT_EQ(((Value0)&Mask##Size) & ((Value1)&Mask##Size) ? ValueIfTrue \
440 : ValueIfFalse, \
441 test.contentsOfDword(T0)) \
442 << TestString; \
443 reset(); \
444 } while (0)
445
446 #define TestImplValues(Dst, Value0, Src, Value1, Size) \
447 do { \
448 TestImplRegReg(Dst, Value0, Src, Value1, Size); \
449 TestImplRegImm(Dst, Value0, Value1, Size); \
450 TestImplAddrReg(Value0, Src, Value1, Size); \
451 TestImplAddrImm(Value0, Value1, Size); \
452 } while (0)
453
454 #define TestImplSize(Dst, Src, Size) \
455 do { \
456 TestImplValues(Dst, 0xF0F12101, Src, 0x00000000, Size); \
457 TestImplValues(Dst, 0xF0000000, Src, 0xF0000000, Size); \
458 TestImplValues(Dst, 0x0F00000F, Src, 0xF00000F0, Size); \
459 } while (0)
460
461 #define TestImpl(Dst, Src) \
462 do { \
463 TestImplSize(Dst, Src, 8); \
464 TestImplSize(Dst, Src, 16); \
465 TestImplSize(Dst, Src, 32); \
466 } while (0)
467
468 TestImpl(eax, ebx);
469 TestImpl(ebx, ecx);
470 TestImpl(ecx, edx);
471 TestImpl(edx, esi);
472 TestImpl(esi, edi);
473 TestImpl(edi, eax);
474
475 #undef TestImpl
476 #undef TestImplSize
477 #undef TestImplValues
478 #undef TestImplAddrImm
479 #undef TestImplAddrReg
480 #undef TestImplRegImm
481 #undef TestImplRegReg
482 }
483
484 // No mull/div because x86.
485 // No shift because x86.
TEST_F(AssemblerX8632Test,Arith_most)486 TEST_F(AssemblerX8632Test, Arith_most) {
487 static constexpr uint32_t Mask8 = 0xFF;
488 static constexpr uint32_t Mask16 = 0xFFFF;
489 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
490
491 #define TestImplRegReg(Inst, Dst, Value0, Src, Value1, Type, Size, Op) \
492 do { \
493 static constexpr char TestString[] = \
494 "(" #Inst ", " #Dst ", " #Value0 ", " #Src ", " #Value1 \
495 ", " #Type #Size "_t, " #Op ")"; \
496 \
497 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
498 Immediate(Value0)); \
499 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
500 Immediate(Value1)); \
501 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
502 GPRRegister::Encoded_Reg_##Src); \
503 \
504 AssembledTest test = assemble(); \
505 test.run(); \
506 \
507 ASSERT_EQ(Mask##Size &static_cast<uint32_t>( \
508 static_cast<Type##Size##_t>((Value0)&Mask##Size) \
509 Op static_cast<Type##Size##_t>((Value1)&Mask##Size)), \
510 Mask##Size &test.Dst()) \
511 << TestString; \
512 reset(); \
513 } while (0)
514
515 #define TestImplRegAddr(Inst, Dst, Value0, Value1, Type, Size, Op) \
516 do { \
517 static constexpr char TestString[] = \
518 "(" #Inst ", " #Dst ", " #Value0 ", Addr, " #Value1 ", " #Type #Size \
519 "_t, " #Op ")"; \
520 const uint32_t T0 = allocateDword(); \
521 const uint32_t V0 = Value1; \
522 \
523 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
524 Immediate(Value0)); \
525 __ mov(IceType_i##Size, dwordAddress(T0), Immediate(Value1)); \
526 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
527 dwordAddress(T0)); \
528 \
529 AssembledTest test = assemble(); \
530 test.setDwordTo(T0, V0); \
531 test.run(); \
532 \
533 ASSERT_EQ(Mask##Size &static_cast<uint32_t>( \
534 static_cast<Type##Size##_t>((Value0)&Mask##Size) \
535 Op static_cast<Type##Size##_t>((Value1)&Mask##Size)), \
536 Mask##Size &test.Dst()) \
537 << TestString; \
538 reset(); \
539 } while (0)
540
541 #define TestImplRegImm(Inst, Dst, Value0, Imm, Type, Size, Op) \
542 do { \
543 static constexpr char TestString[] = \
544 "(" #Inst ", " #Dst ", " #Value0 ", Imm(" #Imm "), " #Type #Size \
545 "_t, " #Op ")"; \
546 \
547 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
548 Immediate(Value0)); \
549 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
550 Immediate((Imm)&Mask##Size)); \
551 \
552 AssembledTest test = assemble(); \
553 test.run(); \
554 \
555 ASSERT_EQ(Mask##Size &static_cast<uint32_t>( \
556 static_cast<Type##Size##_t>((Value0)&Mask##Size) \
557 Op static_cast<Type##Size##_t>((Imm)&Mask##Size)), \
558 Mask##Size &test.Dst()) \
559 << TestString; \
560 reset(); \
561 } while (0)
562
563 #define TestImplAddrReg(Inst, Value0, Src, Value1, Type, Size, Op) \
564 do { \
565 static constexpr char TestString[] = \
566 "(" #Inst ", Addr, " #Value0 ", " #Src ", " #Value1 ", " #Type #Size \
567 "_t, " #Op ")"; \
568 const uint32_t T0 = allocateDword(); \
569 const uint32_t V0 = Value0; \
570 \
571 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
572 Immediate(Value1)); \
573 __ Inst(IceType_i##Size, dwordAddress(T0), \
574 GPRRegister::Encoded_Reg_##Src); \
575 \
576 AssembledTest test = assemble(); \
577 test.setDwordTo(T0, V0); \
578 test.run(); \
579 \
580 ASSERT_EQ(Mask##Size &static_cast<uint32_t>( \
581 static_cast<Type##Size##_t>((Value0)&Mask##Size) \
582 Op static_cast<Type##Size##_t>((Value1)&Mask##Size)), \
583 Mask##Size &test.contentsOfDword(T0)) \
584 << TestString; \
585 reset(); \
586 } while (0)
587
588 #define TestImplAddrImm(Inst, Value0, Imm, Type, Size, Op) \
589 do { \
590 static constexpr char TestString[] = \
591 "(" #Inst ", Addr, " #Value0 ", Imm, " #Imm ", " #Type #Size \
592 "_t, " #Op ")"; \
593 const uint32_t T0 = allocateDword(); \
594 const uint32_t V0 = Value0; \
595 \
596 __ Inst(IceType_i##Size, dwordAddress(T0), Immediate((Imm)&Mask##Size)); \
597 \
598 AssembledTest test = assemble(); \
599 test.setDwordTo(T0, V0); \
600 test.run(); \
601 \
602 ASSERT_EQ(Mask##Size &static_cast<uint32_t>( \
603 static_cast<Type##Size##_t>((Value0)&Mask##Size) \
604 Op static_cast<Type##Size##_t>((Imm)&Mask##Size)), \
605 Mask##Size &test.contentsOfDword(T0)) \
606 << TestString; \
607 reset(); \
608 } while (0)
609
610 #define TestImplOp(Inst, Dst, Value0, Src, Value1, Type, Size, Op) \
611 do { \
612 TestImplRegReg(Inst, Dst, Value0, Src, Value1, Type, Size, Op); \
613 TestImplRegAddr(Inst, Dst, Value0, Value1, Type, Size, Op); \
614 TestImplRegImm(Inst, Dst, Value0, Value1, Type, Size, Op); \
615 TestImplAddrReg(Inst, Value0, Src, Value1, Type, Size, Op); \
616 TestImplAddrImm(Inst, Value0, Value1, Type, Size, Op); \
617 } while (0)
618
619 #define TestImplValues(Dst, Value0, Src, Value1, Size) \
620 do { \
621 TestImplOp(And, Dst, Value0, Src, Value1, int, Size, &); \
622 TestImplOp(And, Dst, Value0, Src, Value1, uint, Size, &); \
623 TestImplOp(Or, Dst, Value0, Src, Value1, int, Size, |); \
624 TestImplOp(Or, Dst, Value0, Src, Value1, uint, Size, |); \
625 TestImplOp(Xor, Dst, Value0, Src, Value1, int, Size, ^); \
626 TestImplOp(Xor, Dst, Value0, Src, Value1, uint, Size, ^); \
627 TestImplOp(add, Dst, Value0, Src, Value1, int, Size, +); \
628 TestImplOp(add, Dst, Value0, Src, Value1, uint, Size, +); \
629 TestImplOp(sub, Dst, Value0, Src, Value1, int, Size, -); \
630 TestImplOp(sub, Dst, Value0, Src, Value1, uint, Size, -); \
631 } while (0)
632
633 #define TestImplSize(Dst, Src, Size) \
634 do { \
635 TestImplValues(Dst, 0xF0F12101, Src, 0x00000000, Size); \
636 TestImplValues(Dst, 0xF0000000, Src, 0xF0000000, Size); \
637 TestImplValues(Dst, 0x0F00000F, Src, 0xF0000070, Size); \
638 TestImplValues(Dst, 0x0F00F00F, Src, 0xF000F070, Size); \
639 } while (0)
640
641 #define TestImpl(Dst, Src) \
642 do { \
643 if (GPRRegister::Encoded_Reg_##Src <= 3 && \
644 GPRRegister::Encoded_Reg_##Dst <= 3) { \
645 TestImplSize(Dst, Src, 8); \
646 } \
647 TestImplSize(Dst, Src, 16); \
648 TestImplSize(Dst, Src, 32); \
649 } while (0)
650
651 TestImpl(eax, ebx);
652 TestImpl(ebx, ecx);
653 TestImpl(ecx, edx);
654 TestImpl(edx, esi);
655 TestImpl(esi, edi);
656 TestImpl(edi, eax);
657
658 #undef TestImpl
659 #undef TestImplSize
660 #undef TestImplValues
661 #undef TestImplOp
662 #undef TestImplAddrImm
663 #undef TestImplAddrReg
664 #undef TestImplRegImm
665 #undef TestImplRegAddr
666 #undef TestImplRegReg
667 }
668
TEST_F(AssemblerX8632Test,Arith_BorrowNCarry)669 TEST_F(AssemblerX8632Test, Arith_BorrowNCarry) {
670 const uint32_t Mask8 = 0x000000FF;
671 const uint32_t Mask16 = 0x0000FFFF;
672 const uint32_t Mask32 = 0xFFFFFFFF;
673
674 const uint64_t ResultMask8 = 0x000000000000FFFFull;
675 const uint64_t ResultMask16 = 0x00000000FFFFFFFFull;
676 const uint64_t ResultMask32 = 0xFFFFFFFFFFFFFFFFull;
677
678 #define TestImplRegReg(Inst0, Inst1, Dst0, Dst1, Value0, Src0, Src1, Value1, \
679 Op, Size) \
680 do { \
681 static_assert(Size == 8 || Size == 16 || Size == 32, \
682 "Invalid size " #Size); \
683 static constexpr char TestString[] = \
684 "(" #Inst0 ", " #Inst1 ", " #Dst0 ", " #Dst1 ", " #Value0 ", " #Src0 \
685 ", " #Src1 ", " #Value1 ", " #Op ", " #Size ")"; \
686 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst0, \
687 Immediate(uint64_t(Value0) & Mask##Size)); \
688 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst1, \
689 Immediate((uint64_t(Value0) >> Size) & Mask##Size)); \
690 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src0, \
691 Immediate(uint64_t(Value1) & Mask##Size)); \
692 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src1, \
693 Immediate((uint64_t(Value1) >> Size) & Mask##Size)); \
694 __ Inst0(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst0, \
695 GPRRegister::Encoded_Reg_##Src0); \
696 __ Inst1(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst1, \
697 GPRRegister::Encoded_Reg_##Src1); \
698 \
699 AssembledTest test = assemble(); \
700 test.run(); \
701 \
702 static constexpr uint64_t Result = (uint64_t(Value0) & ResultMask##Size) \
703 Op(uint64_t(Value1) & ResultMask##Size); \
704 static constexpr uint32_t Expected0 = Result & Mask##Size; \
705 static constexpr uint32_t Expected1 = (Result >> Size) & Mask##Size; \
706 ASSERT_EQ(Expected0, test.Dst0()) << TestString << ": 0"; \
707 ASSERT_EQ(Expected1, test.Dst1()) << TestString << ": 1"; \
708 reset(); \
709 } while (0)
710
711 #define TestImplRegAddr(Inst0, Inst1, Dst0, Dst1, Value0, Value1, Op, Size) \
712 do { \
713 static_assert(Size == 8 || Size == 16 || Size == 32, \
714 "Invalid size " #Size); \
715 static constexpr char TestString[] = \
716 "(" #Inst0 ", " #Inst1 ", " #Dst0 ", " #Dst1 ", " #Value0 \
717 ", Addr, " #Value1 ", " #Op ", " #Size ")"; \
718 const uint32_t T0 = allocateDword(); \
719 const uint32_t V0 = uint64_t(Value1) & Mask##Size; \
720 const uint32_t T1 = allocateDword(); \
721 const uint32_t V1 = (uint64_t(Value1) >> Size) & Mask##Size; \
722 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst0, \
723 Immediate(uint64_t(Value0) & Mask##Size)); \
724 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst1, \
725 Immediate((uint64_t(Value0) >> Size) & Mask##Size)); \
726 __ Inst0(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst0, \
727 dwordAddress(T0)); \
728 __ Inst1(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst1, \
729 dwordAddress(T1)); \
730 \
731 AssembledTest test = assemble(); \
732 test.setDwordTo(T0, V0); \
733 test.setDwordTo(T1, V1); \
734 test.run(); \
735 \
736 static constexpr uint64_t Result = (uint64_t(Value0) & ResultMask##Size) \
737 Op(uint64_t(Value1) & ResultMask##Size); \
738 static constexpr uint32_t Expected0 = Result & Mask##Size; \
739 static constexpr uint32_t Expected1 = (Result >> Size) & Mask##Size; \
740 ASSERT_EQ(Expected0, test.Dst0()) << TestString << ": 0"; \
741 ASSERT_EQ(Expected1, test.Dst1()) << TestString << ": 1"; \
742 reset(); \
743 } while (0)
744
745 #define TestImplRegImm(Inst0, Inst1, Dst0, Dst1, Value0, Imm, Op, Size) \
746 do { \
747 static_assert(Size == 8 || Size == 16 || Size == 32, \
748 "Invalid size " #Size); \
749 static constexpr char TestString[] = \
750 "(" #Inst0 ", " #Inst1 ", " #Dst0 ", " #Dst1 ", " #Value0 \
751 ", Imm(" #Imm "), " #Op ", " #Size ")"; \
752 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst0, \
753 Immediate(uint64_t(Value0) & Mask##Size)); \
754 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst1, \
755 Immediate((uint64_t(Value0) >> Size) & Mask##Size)); \
756 __ Inst0(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst0, \
757 Immediate(uint64_t(Imm) & Mask##Size)); \
758 __ Inst1(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst1, \
759 Immediate((uint64_t(Imm) >> Size) & Mask##Size)); \
760 \
761 AssembledTest test = assemble(); \
762 test.run(); \
763 \
764 static constexpr uint64_t Result = (uint64_t(Value0) & ResultMask##Size) \
765 Op(uint64_t(Imm) & ResultMask##Size); \
766 static constexpr uint32_t Expected0 = Result & Mask##Size; \
767 static constexpr uint32_t Expected1 = (Result >> Size) & Mask##Size; \
768 ASSERT_EQ(Expected0, test.Dst0()) << TestString << ": 0"; \
769 ASSERT_EQ(Expected1, test.Dst1()) << TestString << ": 1"; \
770 reset(); \
771 } while (0)
772
773 #define TestImplAddrReg(Inst0, Inst1, Value0, Src0, Src1, Value1, Op, Size) \
774 do { \
775 static_assert(Size == 8 || Size == 16 || Size == 32, \
776 "Invalid size " #Size); \
777 static constexpr char TestString[] = \
778 "(" #Inst0 ", " #Inst1 ", Addr, " #Value0 ", " #Src0 ", " #Src1 \
779 ", " #Value1 ", " #Op ", " #Size ")"; \
780 const uint32_t T0 = allocateDword(); \
781 const uint32_t V0 = uint64_t(Value0) & Mask##Size; \
782 const uint32_t T1 = allocateDword(); \
783 const uint32_t V1 = (uint64_t(Value0) >> Size) & Mask##Size; \
784 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src0, \
785 Immediate(uint64_t(Value1) & Mask##Size)); \
786 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src1, \
787 Immediate((uint64_t(Value1) >> Size) & Mask##Size)); \
788 __ Inst0(IceType_i##Size, dwordAddress(T0), \
789 GPRRegister::Encoded_Reg_##Src0); \
790 __ Inst1(IceType_i##Size, dwordAddress(T1), \
791 GPRRegister::Encoded_Reg_##Src1); \
792 \
793 AssembledTest test = assemble(); \
794 test.setDwordTo(T0, V0); \
795 test.setDwordTo(T1, V1); \
796 test.run(); \
797 \
798 static constexpr uint64_t Result = (uint64_t(Value0) & ResultMask##Size) \
799 Op(uint64_t(Value1) & ResultMask##Size); \
800 static constexpr uint32_t Expected0 = Result & Mask##Size; \
801 static constexpr uint32_t Expected1 = (Result >> Size) & Mask##Size; \
802 ASSERT_EQ(Expected0, test.contentsOfDword(T0)) << TestString << ": 0"; \
803 ASSERT_EQ(Expected1, test.contentsOfDword(T1)) << TestString << ": 1"; \
804 reset(); \
805 } while (0)
806
807 #define TestImplAddrImm(Inst0, Inst1, Value0, Imm, Op, Size) \
808 do { \
809 static_assert(Size == 8 || Size == 16 || Size == 32, \
810 "Invalid size " #Size); \
811 static constexpr char TestString[] = \
812 "(" #Inst0 ", " #Inst1 ", Addr, " #Value0 ", Imm(" #Imm "), " #Op \
813 ", " #Size ")"; \
814 const uint32_t T0 = allocateDword(); \
815 const uint32_t V0 = uint64_t(Value0) & Mask##Size; \
816 const uint32_t T1 = allocateDword(); \
817 const uint32_t V1 = (uint64_t(Value0) >> Size) & Mask##Size; \
818 __ Inst0(IceType_i##Size, dwordAddress(T0), \
819 Immediate(uint64_t(Imm) & Mask##Size)); \
820 __ Inst1(IceType_i##Size, dwordAddress(T1), \
821 Immediate((uint64_t(Imm) >> Size) & Mask##Size)); \
822 \
823 AssembledTest test = assemble(); \
824 test.setDwordTo(T0, V0); \
825 test.setDwordTo(T1, V1); \
826 test.run(); \
827 \
828 static constexpr uint64_t Result = (uint64_t(Value0) & ResultMask##Size) \
829 Op(uint64_t(Imm) & ResultMask##Size); \
830 static constexpr uint32_t Expected0 = Result & Mask##Size; \
831 static constexpr uint32_t Expected1 = (Result >> Size) & Mask##Size; \
832 ASSERT_EQ(Expected0, test.contentsOfDword(T0)) << TestString << ": 0"; \
833 ASSERT_EQ(Expected1, test.contentsOfDword(T1)) << TestString << ": 1"; \
834 reset(); \
835 } while (0)
836
837 #define TestImplOp(Inst0, Inst1, Dst0, Dst1, Value0, Src0, Src1, Value1, Op, \
838 Size) \
839 do { \
840 TestImplRegReg(Inst0, Inst1, Dst0, Dst1, Value0, Src0, Src1, Value1, Op, \
841 Size); \
842 TestImplRegAddr(Inst0, Inst1, Dst0, Dst1, Value0, Value1, Op, Size); \
843 TestImplRegImm(Inst0, Inst1, Dst0, Dst1, Value0, Value1, Op, Size); \
844 TestImplAddrReg(Inst0, Inst1, Value0, Src0, Src1, Value1, Op, Size); \
845 TestImplAddrImm(Inst0, Inst1, Value0, Value1, Op, Size); \
846 } while (0)
847
848 #define TestImplValues(Dst0, Dst1, Value0, Src0, Src1, Value1, Size) \
849 do { \
850 TestImplOp(add, adc, Dst0, Dst1, Value0, Src0, Src1, Value1, +, Size); \
851 TestImplOp(sub, sbb, Dst0, Dst1, Value0, Src0, Src1, Value1, -, Size); \
852 } while (0)
853
854 #define TestImplSize(Dst0, Dst1, Src0, Src1, Size) \
855 do { \
856 TestImplValues(Dst0, Dst1, 0xFFFFFFFFFFFFFF00ull, Src0, Src1, \
857 0xFFFFFFFF0000017Full, Size); \
858 } while (0)
859
860 #define TestImpl(Dst0, Dst1, Src0, Src1) \
861 do { \
862 if (GPRRegister::Encoded_Reg_##Dst0 <= 3 && \
863 GPRRegister::Encoded_Reg_##Dst1 <= 3 && \
864 GPRRegister::Encoded_Reg_##Src0 <= 3 && \
865 GPRRegister::Encoded_Reg_##Src1 <= 3) { \
866 TestImplSize(Dst0, Dst1, Src0, Src1, 8); \
867 } \
868 TestImplSize(Dst0, Dst1, Src0, Src1, 16); \
869 TestImplSize(Dst0, Dst1, Src0, Src1, 32); \
870 } while (0)
871
872 TestImpl(eax, ebx, ecx, edx);
873 TestImpl(ebx, ecx, edx, esi);
874 TestImpl(ecx, edx, esi, edi);
875 TestImpl(edx, esi, edi, eax);
876 TestImpl(esi, edi, eax, ebx);
877 TestImpl(edi, eax, ebx, ecx);
878
879 #undef TestImpl
880 #undef TestImplSize
881 #undef TestImplValues
882 #undef TestImplOp
883 #undef TestImplAddrImm
884 #undef TestImplAddrReg
885 #undef TestImplRegImm
886 #undef TestImplRegAddr
887 #undef TestImplRegReg
888 }
889
TEST_F(AssemblerX8632LowLevelTest,Cbw_Cwd_Cdq)890 TEST_F(AssemblerX8632LowLevelTest, Cbw_Cwd_Cdq) {
891 #define TestImpl(Inst, BytesSize, ...) \
892 do { \
893 __ Inst(); \
894 ASSERT_EQ(BytesSize, codeBytesSize()) << #Inst; \
895 verifyBytes<BytesSize>(codeBytes(), __VA_ARGS__); \
896 reset(); \
897 } while (0)
898
899 TestImpl(cbw, 2u, 0x66, 0x98);
900 TestImpl(cwd, 2u, 0x66, 0x99);
901 TestImpl(cdq, 1u, 0x99);
902
903 #undef TestImpl
904 }
905
TEST_F(AssemblerX8632Test,SingleOperandMul)906 TEST_F(AssemblerX8632Test, SingleOperandMul) {
907 static constexpr uint32_t Mask8 = 0x000000FF;
908 static constexpr uint32_t Mask16 = 0x0000FFFF;
909 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
910
911 #define TestImplReg(Inst, Value0, Src, Value1, Type, Size) \
912 do { \
913 static_assert(GPRRegister::Encoded_Reg_eax != \
914 GPRRegister::Encoded_Reg_##Src, \
915 "eax can not be src1."); \
916 \
917 static constexpr char TestString[] = \
918 "(" #Inst ", " #Value0 ", " #Src ", " #Value1 ", " #Type ", " #Size \
919 ")"; \
920 static constexpr Type##64_t OperandEax = \
921 static_cast<Type##Size##_t>((Value0)&Mask##Size); \
922 static constexpr Type##64_t OperandOther = \
923 static_cast<Type##Size##_t>((Value1)&Mask##Size); \
924 static constexpr uint32_t ExpectedEax = \
925 Mask##Size & (OperandEax * OperandOther); \
926 static constexpr uint32_t ExpectedEdx = \
927 Mask##Size & ((OperandEax * OperandOther) >> Size); \
928 \
929 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_eax, \
930 Immediate((Value0)&Mask##Size)); \
931 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
932 Immediate((Value1)&Mask##Size)); \
933 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Src); \
934 \
935 if (Size == 8) { \
936 /* mov %ah, %dl */ \
937 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
938 GPRRegister::Encoded_Reg_esp); \
939 __ And(IceType_i16, GPRRegister::Encoded_Reg_eax, Immediate(0x00FF)); \
940 if (GPRRegister::Encoded_Reg_##Src == GPRRegister::Encoded_Reg_esi) { \
941 /* src == dh; clear dx's upper 8 bits. */ \
942 __ And(IceType_i16, GPRRegister::Encoded_Reg_edx, Immediate(0x00FF)); \
943 } \
944 } \
945 \
946 AssembledTest test = assemble(); \
947 test.run(); \
948 \
949 ASSERT_EQ(ExpectedEax, test.eax()) << TestString; \
950 ASSERT_EQ(ExpectedEdx, test.edx()) << TestString; \
951 reset(); \
952 } while (0)
953
954 #define TestImplAddr(Inst, Value0, Value1, Type, Size) \
955 do { \
956 static constexpr char TestString[] = \
957 "(" #Inst ", " #Value0 ", Addr, " #Value1 ", " #Type ", " #Size ")"; \
958 static const uint32_t T0 = allocateDword(); \
959 static constexpr uint32_t V0 = Value1; \
960 static constexpr Type##64_t OperandEax = \
961 static_cast<Type##Size##_t>((Value0)&Mask##Size); \
962 static constexpr Type##64_t OperandOther = \
963 static_cast<Type##Size##_t>((Value1)&Mask##Size); \
964 static constexpr uint32_t ExpectedEax = \
965 Mask##Size & (OperandEax * OperandOther); \
966 static constexpr uint32_t ExpectedEdx = \
967 Mask##Size & ((OperandEax * OperandOther) >> Size); \
968 \
969 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_eax, \
970 Immediate((Value0)&Mask##Size)); \
971 __ Inst(IceType_i##Size, dwordAddress(T0)); \
972 \
973 if (Size == 8) { \
974 /* mov %ah, %dl */ \
975 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
976 GPRRegister::Encoded_Reg_esp); \
977 __ And(IceType_i16, GPRRegister::Encoded_Reg_eax, Immediate(0x00FF)); \
978 } \
979 \
980 AssembledTest test = assemble(); \
981 test.setDwordTo(T0, V0); \
982 test.run(); \
983 \
984 ASSERT_EQ(ExpectedEax, test.eax()) << TestString; \
985 ASSERT_EQ(ExpectedEdx, test.edx()) << TestString; \
986 reset(); \
987 } while (0)
988
989 #define TestImplOp(Inst, Value0, Src, Value1, Type, Size) \
990 do { \
991 TestImplReg(Inst, Value0, Src, Value1, Type, Size); \
992 TestImplAddr(Inst, Value0, Value1, Type, Size); \
993 } while (0)
994
995 #define TestImplValue(Value0, Src, Value1, Size) \
996 do { \
997 TestImplOp(mul, Value0, Src, Value1, uint, Size); \
998 TestImplOp(imul, Value0, Src, Value1, int, Size); \
999 } while (0)
1000
1001 #define TestImplSize(Src, Size) \
1002 do { \
1003 TestImplValue(10, Src, 1, Size); \
1004 TestImplValue(10, Src, -1, Size); \
1005 TestImplValue(-10, Src, 37, Size); \
1006 TestImplValue(-10, Src, -15, Size); \
1007 } while (0)
1008
1009 #define TestImpl(Src) \
1010 do { \
1011 TestImplSize(Src, 8); \
1012 TestImplSize(Src, 16); \
1013 TestImplSize(Src, 32); \
1014 } while (0)
1015
1016 TestImpl(ebx);
1017 TestImpl(ecx);
1018 TestImpl(edx);
1019 TestImpl(esi);
1020 TestImpl(edi);
1021
1022 #undef TestImpl
1023 #undef TestImplSize
1024 #undef TestImplValue
1025 #undef TestImplOp
1026 #undef TestImplAddr
1027 #undef TestImplReg
1028 }
1029
TEST_F(AssemblerX8632Test,TwoOperandImul)1030 TEST_F(AssemblerX8632Test, TwoOperandImul) {
1031 static constexpr uint32_t Mask16 = 0x0000FFFF;
1032 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
1033
1034 #define TestImplRegReg(Dst, Value0, Src, Value1, Size) \
1035 do { \
1036 static constexpr char TestString[] = \
1037 "(" #Dst ", " #Value0 ", " #Src ", " #Value1 ", " #Size ")"; \
1038 static constexpr int64_t Operand0 = \
1039 static_cast<int##Size##_t>((Value0)&Mask##Size); \
1040 static constexpr int64_t Operand1 = \
1041 static_cast<int##Size##_t>((Value1)&Mask##Size); \
1042 static constexpr uint32_t Expected = Mask##Size & (Operand0 * Operand1); \
1043 \
1044 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1045 Immediate((Value0)&Mask##Size)); \
1046 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
1047 Immediate((Value1)&Mask##Size)); \
1048 __ imul(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1049 GPRRegister::Encoded_Reg_##Src); \
1050 \
1051 if (Size == 8) { \
1052 /* mov %ah, %dl */ \
1053 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
1054 GPRRegister::Encoded_Reg_esp); \
1055 __ And(IceType_i16, GPRRegister::Encoded_Reg_eax, Immediate(0x00FF)); \
1056 if (GPRRegister::Encoded_Reg_##Src == GPRRegister::Encoded_Reg_esi) { \
1057 /* src == dh; clear dx's upper 8 bits. */ \
1058 __ And(IceType_i16, GPRRegister::Encoded_Reg_edx, Immediate(0x00FF)); \
1059 } \
1060 } \
1061 \
1062 AssembledTest test = assemble(); \
1063 test.run(); \
1064 \
1065 ASSERT_EQ(Expected, test.Dst()) << TestString; \
1066 reset(); \
1067 } while (0)
1068
1069 #define TestImplRegImm(Dst, Value0, Imm, Size) \
1070 do { \
1071 static constexpr char TestString[] = \
1072 "(" #Dst ", " #Value0 ", Imm(" #Imm "), " #Size ")"; \
1073 static constexpr int64_t Operand0 = \
1074 static_cast<int##Size##_t>((Value0)&Mask##Size); \
1075 static constexpr int64_t Operand1 = \
1076 static_cast<int##Size##_t>((Imm)&Mask##Size); \
1077 static constexpr uint32_t Expected = Mask##Size & (Operand0 * Operand1); \
1078 \
1079 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1080 Immediate((Value0)&Mask##Size)); \
1081 __ imul(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, Immediate(Imm)); \
1082 \
1083 if (Size == 8) { \
1084 /* mov %ah, %dl */ \
1085 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
1086 GPRRegister::Encoded_Reg_esp); \
1087 __ And(IceType_i16, GPRRegister::Encoded_Reg_eax, Immediate(0x00FF)); \
1088 } \
1089 \
1090 AssembledTest test = assemble(); \
1091 test.run(); \
1092 \
1093 ASSERT_EQ(Expected, test.Dst()) << TestString; \
1094 reset(); \
1095 } while (0)
1096
1097 #define TestImplRegAddr(Dst, Value0, Value1, Size) \
1098 do { \
1099 static constexpr char TestString[] = \
1100 "(" #Dst ", " #Value0 ", Addr," #Value1 ", " #Size ")"; \
1101 static constexpr int64_t Operand0 = \
1102 static_cast<int##Size##_t>((Value0)&Mask##Size); \
1103 static constexpr int64_t Operand1 = \
1104 static_cast<int##Size##_t>((Value1)&Mask##Size); \
1105 static constexpr uint32_t Expected = Mask##Size & (Operand0 * Operand1); \
1106 const uint32_t T0 = allocateDword(); \
1107 \
1108 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1109 Immediate((Value0)&Mask##Size)); \
1110 __ imul(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1111 dwordAddress(T0)); \
1112 \
1113 if (Size == 8) { \
1114 /* mov %ah, %dl */ \
1115 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
1116 GPRRegister::Encoded_Reg_esp); \
1117 __ And(IceType_i16, GPRRegister::Encoded_Reg_eax, Immediate(0x00FF)); \
1118 } \
1119 \
1120 AssembledTest test = assemble(); \
1121 test.setDwordTo(T0, static_cast<uint32_t>(Operand1)); \
1122 test.run(); \
1123 \
1124 ASSERT_EQ(Expected, test.Dst()) << TestString; \
1125 reset(); \
1126 } while (0)
1127
1128 #define TestImplValue(Dst, Value0, Src, Value1, Size) \
1129 do { \
1130 TestImplRegReg(Dst, Value0, Src, Value1, Size); \
1131 TestImplRegImm(Dst, Value0, Value1, Size); \
1132 TestImplRegAddr(Dst, Value0, Value1, Size); \
1133 } while (0)
1134
1135 #define TestImplSize(Dst, Src, Size) \
1136 do { \
1137 TestImplValue(Dst, 1, Src, 1, Size); \
1138 TestImplValue(Dst, -10, Src, 0x4050AA20, Size); \
1139 TestImplValue(Dst, -2, Src, -55, Size); \
1140 } while (0)
1141
1142 #define TestImpl(Dst, Src) \
1143 do { \
1144 TestImplSize(Dst, Src, 16); \
1145 TestImplSize(Dst, Src, 32); \
1146 } while (0)
1147
1148 TestImpl(eax, ebx);
1149 TestImpl(ebx, ecx);
1150 TestImpl(ecx, edx);
1151 TestImpl(edx, esi);
1152 TestImpl(esi, edi);
1153 TestImpl(edi, eax);
1154
1155 #undef TestImpl
1156 #undef TestImplSize
1157 #undef TestImplValue
1158 #undef TestImplRegAddr
1159 #undef TestImplRegImm
1160 #undef TestImplRegReg
1161 }
1162
TEST_F(AssemblerX8632Test,Div)1163 TEST_F(AssemblerX8632Test, Div) {
1164 static constexpr uint32_t Mask8 = 0x000000FF;
1165 static constexpr uint32_t Mask16 = 0x0000FFFF;
1166 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
1167
1168 static constexpr uint64_t Operand0Mask8 = 0x00000000000000FFull;
1169 static constexpr uint64_t Operand0Mask16 = 0x00000000FFFFFFFFull;
1170 static constexpr uint64_t Operand0Mask32 = 0xFFFFFFFFFFFFFFFFull;
1171
1172 using Operand0Type_int8 = int16_t;
1173 using Operand0Type_uint8 = uint16_t;
1174 using Operand0Type_int16 = int32_t;
1175 using Operand0Type_uint16 = uint32_t;
1176 using Operand0Type_int32 = int64_t;
1177 using Operand0Type_uint32 = uint64_t;
1178
1179 #define TestImplReg(Inst, Value0, Src, Value1, Type, Size) \
1180 do { \
1181 static_assert(GPRRegister::Encoded_Reg_eax != \
1182 GPRRegister::Encoded_Reg_##Src, \
1183 "eax can not be src1."); \
1184 static_assert(GPRRegister::Encoded_Reg_edx != \
1185 GPRRegister::Encoded_Reg_##Src, \
1186 "edx can not be src1."); \
1187 \
1188 static constexpr char TestString[] = \
1189 "(" #Inst ", " #Value0 ", " #Src ", " #Value1 ", " #Type ", " #Size \
1190 ")"; \
1191 static constexpr Operand0Type_##Type##Size Operand0 = \
1192 static_cast<Type##64_t>(Value0) & Operand0Mask##Size; \
1193 static constexpr Type##Size##_t Operand0Lo = Operand0 & Mask##Size; \
1194 static constexpr Type##Size##_t Operand0Hi = \
1195 (Operand0 >> Size) & Mask##Size; \
1196 static constexpr Type##Size##_t Operand1 = \
1197 static_cast<Type##Size##_t>(Value1) & Mask##Size; \
1198 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_eax, \
1199 Immediate(Operand0Lo)); \
1200 if (Size == 8) { \
1201 /* mov Operand0Hi, %ah */ \
1202 __ mov(IceType_i8, GPRRegister::Encoded_Reg_esp, Immediate(Operand0Hi)); \
1203 } else { \
1204 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
1205 Immediate(Operand0Hi)); \
1206 } \
1207 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
1208 Immediate(Operand1)); \
1209 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Src); \
1210 if (Size == 8) { \
1211 /* mov %ah, %dl */ \
1212 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
1213 GPRRegister::Encoded_Reg_esp); \
1214 __ And(IceType_i16, GPRRegister::Encoded_Reg_eax, Immediate(0x00FF)); \
1215 if (GPRRegister::Encoded_Reg_##Src == GPRRegister::Encoded_Reg_esi) { \
1216 __ And(IceType_i16, GPRRegister::Encoded_Reg_edx, Immediate(0x00FF)); \
1217 } \
1218 } \
1219 \
1220 AssembledTest test = assemble(); \
1221 test.run(); \
1222 \
1223 static constexpr uint32_t Quocient = (Operand0 / Operand1) & Mask##Size; \
1224 static constexpr uint32_t Reminder = (Operand0 % Operand1) & Mask##Size; \
1225 EXPECT_EQ(Quocient, test.eax()) << TestString; \
1226 EXPECT_EQ(Reminder, test.edx()) << TestString; \
1227 reset(); \
1228 } while (0)
1229
1230 #define TestImplAddr(Inst, Value0, Value1, Type, Size) \
1231 do { \
1232 static constexpr char TestString[] = \
1233 "(" #Inst ", " #Value0 ", Addr, " #Value1 ", " #Type ", " #Size ")"; \
1234 static constexpr Operand0Type_##Type##Size Operand0 = \
1235 static_cast<Type##64_t>(Value0) & Operand0Mask##Size; \
1236 static constexpr Type##Size##_t Operand0Lo = Operand0 & Mask##Size; \
1237 static constexpr Type##Size##_t Operand0Hi = \
1238 (Operand0 >> Size) & Mask##Size; \
1239 const uint32_t T0 = allocateDword(); \
1240 static constexpr Type##Size##_t V0 = \
1241 static_cast<Type##Size##_t>(Value1) & Mask##Size; \
1242 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_eax, \
1243 Immediate(Operand0Lo)); \
1244 if (Size == 8) { \
1245 /* mov Operand0Hi, %ah */ \
1246 __ mov(IceType_i8, GPRRegister::Encoded_Reg_esp, Immediate(Operand0Hi)); \
1247 } else { \
1248 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
1249 Immediate(Operand0Hi)); \
1250 } \
1251 __ Inst(IceType_i##Size, dwordAddress(T0)); \
1252 if (Size == 8) { \
1253 /* mov %ah, %dl */ \
1254 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
1255 GPRRegister::Encoded_Reg_esp); \
1256 __ And(IceType_i16, GPRRegister::Encoded_Reg_eax, Immediate(0x00FF)); \
1257 } \
1258 \
1259 AssembledTest test = assemble(); \
1260 test.setDwordTo(T0, static_cast<uint32_t>(V0)); \
1261 test.run(); \
1262 \
1263 static constexpr uint32_t Quocient = (Operand0 / V0) & Mask##Size; \
1264 static constexpr uint32_t Reminder = (Operand0 % V0) & Mask##Size; \
1265 EXPECT_EQ(Quocient, test.eax()) << TestString; \
1266 EXPECT_EQ(Reminder, test.edx()) << TestString; \
1267 reset(); \
1268 } while (0)
1269
1270 #define TestImplOp(Inst, Value0, Src, Value1, Type, Size) \
1271 do { \
1272 TestImplReg(Inst, Value0, Src, Value1, Type, Size); \
1273 TestImplAddr(Inst, Value0, Value1, Type, Size); \
1274 } while (0)
1275
1276 #define TestImplValue(Value0, Src, Value1, Size) \
1277 do { \
1278 TestImplOp(div, Value0, Src, Value1, uint, Size); \
1279 TestImplOp(idiv, Value0, Src, Value1, int, Size); \
1280 } while (0)
1281
1282 #define TestImplSize(Src, Size) \
1283 do { \
1284 TestImplValue(10, Src, 1, Size); \
1285 TestImplValue(10, Src, -1, Size); \
1286 } while (0)
1287
1288 #define TestImpl(Src) \
1289 do { \
1290 TestImplSize(Src, 8); \
1291 TestImplSize(Src, 16); \
1292 TestImplSize(Src, 32); \
1293 } while (0)
1294
1295 TestImpl(ebx);
1296 TestImpl(ecx);
1297 TestImpl(esi);
1298 TestImpl(edi);
1299
1300 #undef TestImpl
1301 #undef TestImplSize
1302 #undef TestImplValue
1303 #undef TestImplOp
1304 #undef TestImplAddr
1305 #undef TestImplReg
1306 }
1307
1308 // This is not executable in x86-64 because the one byte inc/dec instructions
1309 // became the REX prefixes. Therefore, these are tested with the low-level test
1310 // infrastructure.
TEST_F(AssemblerX8632LowLevelTest,Incl_Decl_Reg)1311 TEST_F(AssemblerX8632LowLevelTest, Incl_Decl_Reg) {
1312 #define TestImpl(Inst, Dst, BaseOpcode) \
1313 do { \
1314 __ Inst(GPRRegister::Encoded_Reg_##Dst); \
1315 static constexpr uint8_t ByteCount = 1; \
1316 ASSERT_EQ(ByteCount, codeBytesSize()); \
1317 verifyBytes<ByteCount>(codeBytes(), \
1318 BaseOpcode | GPRRegister::Encoded_Reg_##Dst); \
1319 reset(); \
1320 } while (0)
1321
1322 #define TestInc(Dst) \
1323 do { \
1324 constexpr uint8_t InclOpcode = 0x40; \
1325 TestImpl(incl, Dst, InclOpcode); \
1326 } while (0)
1327
1328 #define TestDec(Dst) \
1329 do { \
1330 constexpr uint8_t DeclOpcode = 0x48; \
1331 TestImpl(decl, Dst, DeclOpcode); \
1332 } while (0)
1333
1334 TestInc(eax);
1335 TestInc(ecx);
1336 TestInc(edx);
1337 TestInc(ebx);
1338 TestInc(esp);
1339 TestInc(ebp);
1340 TestInc(esi);
1341 TestInc(esi);
1342
1343 TestDec(eax);
1344 TestDec(ecx);
1345 TestDec(edx);
1346 TestDec(ebx);
1347 TestDec(esp);
1348 TestDec(ebp);
1349 TestDec(esi);
1350 TestDec(esi);
1351
1352 #undef TestInc
1353 #undef TestDec
1354 #undef TestImpl
1355 }
1356
TEST_F(AssemblerX8632Test,Incl_Decl_Addr)1357 TEST_F(AssemblerX8632Test, Incl_Decl_Addr) {
1358 #define TestImpl(Inst, Value0) \
1359 do { \
1360 const bool IsInc = std::string(#Inst).find("incl") != std::string::npos; \
1361 const uint32_t T0 = allocateDword(); \
1362 const uint32_t V0 = Value0; \
1363 \
1364 __ Inst(dwordAddress(T0)); \
1365 \
1366 AssembledTest test = assemble(); \
1367 test.setDwordTo(T0, V0); \
1368 test.run(); \
1369 \
1370 ASSERT_EQ(static_cast<uint32_t>(Value0 + (IsInc ? 1 : -1)), \
1371 test.contentsOfDword(T0)); \
1372 reset(); \
1373 } while (0)
1374
1375 #define TestInc(Value0) \
1376 do { \
1377 TestImpl(incl, Value0); \
1378 } while (0)
1379
1380 #define TestDec(Value0) \
1381 do { \
1382 TestImpl(decl, Value0); \
1383 } while (0)
1384
1385 TestInc(230);
1386
1387 TestDec(30);
1388
1389 #undef TestInc
1390 #undef TestDec
1391 #undef TestImpl
1392 }
1393
TEST_F(AssemblerX8632Test,Shifts)1394 TEST_F(AssemblerX8632Test, Shifts) {
1395 static constexpr uint32_t Mask8 = 0x000000FF;
1396 static constexpr uint32_t Mask16 = 0x0000FFFF;
1397 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
1398
1399 #define TestImplRegImm(Inst, Dst, Value0, Imm, Op, Type, Size) \
1400 do { \
1401 static constexpr char TestString[] = \
1402 "(" #Inst ", " #Dst ", " #Value0 ", Imm(" #Imm "), " #Op ", " #Type \
1403 ", " #Size ")"; \
1404 const bool IsRol = std::string(#Inst).find("rol") != std::string::npos; \
1405 const uint##Size##_t Expected = \
1406 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op(Imm) | \
1407 (!IsRol ? 0 : (Value0) >> (Size - Imm))); \
1408 \
1409 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1410 Immediate((Value0)&Mask##Size)); \
1411 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1412 Immediate((Imm)&Mask##Size)); \
1413 \
1414 AssembledTest test = assemble(); \
1415 test.run(); \
1416 \
1417 ASSERT_EQ(static_cast<uint32_t>(Expected), test.Dst()) << TestString; \
1418 reset(); \
1419 } while (0)
1420
1421 #define TestImplRegRegImm(Inst, Dst, Value0, Src, Value1, Count, Op0, Op1, \
1422 Type, Size) \
1423 do { \
1424 static constexpr char TestString[] = \
1425 "(" #Inst ", " #Dst ", " #Value0 ", " #Src ", " #Value1 \
1426 ", Imm(" #Count "), " #Op0 ", " #Op1 ", " #Type ", " #Size ")"; \
1427 const uint##Size##_t Expected = \
1428 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op0(Count) | \
1429 (static_cast<Type##64_t>(Value1) Op1(Size - Count))); \
1430 \
1431 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1432 Immediate((Value0)&Mask##Size)); \
1433 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
1434 Immediate((Value1)&Mask##Size)); \
1435 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1436 GPRRegister::Encoded_Reg_##Src, Immediate(Count)); \
1437 \
1438 AssembledTest test = assemble(); \
1439 test.run(); \
1440 \
1441 ASSERT_EQ(static_cast<uint32_t>(Expected), test.Dst()) << TestString; \
1442 reset(); \
1443 } while (0)
1444
1445 #define TestImplRegCl(Inst, Dst, Value0, Count, Op, Type, Size) \
1446 do { \
1447 static constexpr char TestString[] = \
1448 "(" #Inst ", " #Dst ", " #Value0 ", " #Count ", " #Op ", " #Type \
1449 ", " #Size ")"; \
1450 const bool IsRol = std::string(#Inst).find("rol") != std::string::npos; \
1451 const uint##Size##_t Expected = \
1452 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op(Count) | \
1453 (!IsRol ? 0 : Value0 >> (Size - Count))); \
1454 \
1455 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1456 Immediate((Value0)&Mask##Size)); \
1457 __ mov(IceType_i8, GPRRegister::Encoded_Reg_ecx, \
1458 Immediate((Count)&Mask##Size)); \
1459 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1460 GPRRegister::Encoded_Reg_ecx); \
1461 \
1462 AssembledTest test = assemble(); \
1463 test.run(); \
1464 \
1465 ASSERT_EQ(static_cast<uint32_t>(Expected), test.Dst()) << TestString; \
1466 reset(); \
1467 } while (0)
1468
1469 #define TestImplRegRegCl(Inst, Dst, Value0, Src, Value1, Count, Op0, Op1, \
1470 Type, Size) \
1471 do { \
1472 static constexpr char TestString[] = \
1473 "(" #Inst ", " #Dst ", " #Value0 ", " #Src ", " #Value1 ", " #Count \
1474 ", " #Op0 ", " #Op1 ", " #Type ", " #Size ")"; \
1475 const uint##Size##_t Expected = \
1476 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op0(Count) | \
1477 (static_cast<Type##64_t>(Value1) Op1(Size - Count))); \
1478 \
1479 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1480 Immediate((Value0)&Mask##Size)); \
1481 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
1482 Immediate((Value1)&Mask##Size)); \
1483 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_ecx, \
1484 Immediate((Count)&0x7F)); \
1485 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1486 GPRRegister::Encoded_Reg_##Src); \
1487 \
1488 AssembledTest test = assemble(); \
1489 test.run(); \
1490 \
1491 ASSERT_EQ(static_cast<uint32_t>(Expected), test.Dst()) << TestString; \
1492 reset(); \
1493 } while (0)
1494
1495 #define TestImplAddrCl(Inst, Value0, Count, Op, Type, Size) \
1496 do { \
1497 static constexpr char TestString[] = \
1498 "(" #Inst ", Addr, " #Value0 ", " #Count ", " #Op ", " #Type \
1499 ", " #Size ")"; \
1500 const bool IsRol = std::string(#Inst).find("rol") != std::string::npos; \
1501 const uint##Size##_t Expected = \
1502 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op(Count) | \
1503 (!IsRol ? 0 : Value0 >> (Size - Count))); \
1504 const uint32_t T0 = allocateDword(); \
1505 const uint32_t V0 = Value0; \
1506 \
1507 __ mov(IceType_i8, GPRRegister::Encoded_Reg_ecx, \
1508 Immediate((Count)&Mask##Size)); \
1509 __ Inst(IceType_i##Size, dwordAddress(T0), GPRRegister::Encoded_Reg_ecx); \
1510 \
1511 AssembledTest test = assemble(); \
1512 test.setDwordTo(T0, V0); \
1513 test.run(); \
1514 \
1515 ASSERT_EQ(static_cast<uint32_t>(Expected), \
1516 Mask##Size &test.contentsOfDword(T0)) \
1517 << TestString; \
1518 reset(); \
1519 } while (0)
1520
1521 #define TestImplAddrRegCl(Inst, Value0, Src, Value1, Count, Op0, Op1, Type, \
1522 Size) \
1523 do { \
1524 static constexpr char TestString[] = \
1525 "(" #Inst ", Addr, " #Value0 ", " #Src ", " #Value1 ", " #Count \
1526 ", " #Op0 ", " #Op1 ", " #Type ", " #Size ")"; \
1527 const uint##Size##_t Expected = \
1528 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op0(Count) | \
1529 (static_cast<Type##64_t>(Value1) Op1(Size - Count))); \
1530 const uint32_t T0 = allocateDword(); \
1531 \
1532 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
1533 Immediate((Value1)&Mask##Size)); \
1534 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_ecx, \
1535 Immediate((Count)&0x7F)); \
1536 __ Inst(IceType_i##Size, dwordAddress(T0), \
1537 GPRRegister::Encoded_Reg_##Src); \
1538 \
1539 AssembledTest test = assemble(); \
1540 test.setDwordTo(T0, static_cast<uint32_t>(Value0)); \
1541 test.run(); \
1542 \
1543 ASSERT_EQ(static_cast<uint32_t>(Expected), test.contentsOfDword(T0)) \
1544 << TestString; \
1545 reset(); \
1546 } while (0)
1547
1548 #define TestImplOp(Inst, Dst, Value0, Count, Op, Type, Size) \
1549 do { \
1550 static_assert(GPRRegister::Encoded_Reg_##Dst != \
1551 GPRRegister::Encoded_Reg_ecx, \
1552 "ecx should not be specified as Dst"); \
1553 TestImplRegImm(Inst, Dst, Value0, Count, Op, Type, Size); \
1554 TestImplRegImm(Inst, ecx, Value0, Count, Op, Type, Size); \
1555 TestImplRegCl(Inst, Dst, Value0, Count, Op, Type, Size); \
1556 TestImplAddrCl(Inst, Value0, Count, Op, Type, Size); \
1557 } while (0)
1558
1559 #define TestImplThreeOperandOp(Inst, Dst, Value0, Src, Value1, Count, Op0, \
1560 Op1, Type, Size) \
1561 do { \
1562 static_assert(GPRRegister::Encoded_Reg_##Dst != \
1563 GPRRegister::Encoded_Reg_ecx, \
1564 "ecx should not be specified as Dst"); \
1565 static_assert(GPRRegister::Encoded_Reg_##Src != \
1566 GPRRegister::Encoded_Reg_ecx, \
1567 "ecx should not be specified as Src"); \
1568 TestImplRegRegImm(Inst, Dst, Value0, Src, Value1, Count, Op0, Op1, Type, \
1569 Size); \
1570 TestImplRegRegCl(Inst, Dst, Value0, Src, Value1, Count, Op0, Op1, Type, \
1571 Size); \
1572 TestImplAddrRegCl(Inst, Value0, Src, Value1, Count, Op0, Op1, Type, Size); \
1573 } while (0)
1574
1575 #define TestImplValue(Dst, Value0, Count, Size) \
1576 do { \
1577 TestImplOp(rol, Dst, Value0, Count, <<, uint, Size); \
1578 TestImplOp(shl, Dst, Value0, Count, <<, uint, Size); \
1579 TestImplOp(shr, Dst, Value0, Count, >>, uint, Size); \
1580 TestImplOp(sar, Dst, Value0, Count, >>, int, Size); \
1581 } while (0)
1582
1583 #define TestImplThreeOperandValue(Dst, Value0, Src, Value1, Count, Size) \
1584 do { \
1585 TestImplThreeOperandOp(shld, Dst, Value0, Src, Value1, Count, <<, >>, \
1586 uint, Size); \
1587 TestImplThreeOperandOp(shrd, Dst, Value0, Src, Value1, Count, >>, <<, \
1588 uint, Size); \
1589 } while (0)
1590
1591 #define TestImplSize(Dst, Size) \
1592 do { \
1593 TestImplValue(Dst, 0x8F, 3, Size); \
1594 TestImplValue(Dst, 0x8FFF, 7, Size); \
1595 TestImplValue(Dst, 0x8FFFF, 7, Size); \
1596 } while (0)
1597
1598 #define TestImplThreeOperandSize(Dst, Src, Size) \
1599 do { \
1600 TestImplThreeOperandValue(Dst, 0xFFF3, Src, 0xA000, 8, Size); \
1601 } while (0)
1602
1603 #define TestImpl(Dst, Src) \
1604 do { \
1605 if (GPRRegister::Encoded_Reg_##Dst < 4) { \
1606 TestImplSize(Dst, 8); \
1607 } \
1608 TestImplSize(Dst, 16); \
1609 TestImplThreeOperandSize(Dst, Src, 16); \
1610 TestImplSize(Dst, 32); \
1611 TestImplThreeOperandSize(Dst, Src, 32); \
1612 } while (0)
1613
1614 TestImpl(eax, ebx);
1615 TestImpl(ebx, edx);
1616 TestImpl(edx, esi);
1617 TestImpl(esi, edi);
1618 TestImpl(edi, eax);
1619
1620 #undef TestImpl
1621 #undef TestImplThreeOperandSize
1622 #undef TestImplSize
1623 #undef TestImplValue
1624 #undef TestImplThreeOperandValue
1625 #undef TestImplOp
1626 #undef TestImplThreeOperandOp
1627 #undef TestImplAddrCl
1628 #undef TestImplRegRegCl
1629 #undef TestImplRegCl
1630 #undef TestImplRegRegImm
1631 #undef TestImplRegImm
1632 }
1633
TEST_F(AssemblerX8632Test,Neg)1634 TEST_F(AssemblerX8632Test, Neg) {
1635 static constexpr uint32_t Mask8 = 0x000000ff;
1636 static constexpr uint32_t Mask16 = 0x0000ffff;
1637 static constexpr uint32_t Mask32 = 0xffffffff;
1638
1639 #define TestImplReg(Dst, Size) \
1640 do { \
1641 static constexpr int32_t Value = 0xFF00A543; \
1642 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1643 Immediate(static_cast<int##Size##_t>(Value) & Mask##Size)); \
1644 __ neg(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst); \
1645 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_eax, \
1646 GPRRegister::Encoded_Reg_##Dst); \
1647 __ And(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(Mask##Size)); \
1648 \
1649 AssembledTest test = assemble(); \
1650 test.run(); \
1651 \
1652 ASSERT_EQ(1 + (~static_cast<int##Size##_t>(Value) & Mask##Size), \
1653 test.eax()) \
1654 << "(" #Dst ", " #Size ")"; \
1655 reset(); \
1656 } while (0)
1657
1658 #define TestImplAddr(Size) \
1659 do { \
1660 static constexpr int32_t Value = 0xFF00A543; \
1661 const uint32_t T0 = allocateDword(); \
1662 __ neg(IceType_i##Size, dwordAddress(T0)); \
1663 \
1664 AssembledTest test = assemble(); \
1665 test.setDwordTo(T0, Value &Mask##Size); \
1666 test.run(); \
1667 \
1668 ASSERT_EQ(1 + (~static_cast<int##Size##_t>(Value) & Mask##Size), \
1669 test.contentsOfDword(T0)) \
1670 << "(Addr, " #Size ")"; \
1671 reset(); \
1672 } while (0)
1673
1674 #define TestImpl(Size) \
1675 do { \
1676 TestImplAddr(Size); \
1677 TestImplReg(eax, Size); \
1678 TestImplReg(ebx, Size); \
1679 TestImplReg(ecx, Size); \
1680 TestImplReg(edx, Size); \
1681 TestImplReg(esi, Size); \
1682 TestImplReg(edi, Size); \
1683 } while (0)
1684
1685 TestImpl(8);
1686 TestImpl(16);
1687 TestImpl(32);
1688
1689 #undef TestImpl
1690 #undef TestImplAddr
1691 #undef TestImplReg
1692 }
1693
TEST_F(AssemblerX8632Test,Not)1694 TEST_F(AssemblerX8632Test, Not) {
1695 #define TestImpl(Dst) \
1696 do { \
1697 static constexpr uint32_t Value = 0xFF00A543; \
1698 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dst, Immediate(Value)); \
1699 __ notl(GPRRegister::Encoded_Reg_##Dst); \
1700 \
1701 AssembledTest test = assemble(); \
1702 test.run(); \
1703 \
1704 ASSERT_EQ(~Value, test.Dst()) << "(" #Dst ")"; \
1705 reset(); \
1706 } while (0)
1707
1708 TestImpl(eax);
1709 TestImpl(ebx);
1710 TestImpl(ecx);
1711 TestImpl(edx);
1712 TestImpl(esi);
1713 TestImpl(edi);
1714
1715 #undef TestImpl
1716 }
1717
TEST_F(AssemblerX8632Test,Bswap)1718 TEST_F(AssemblerX8632Test, Bswap) {
1719 #define TestImpl(Dst) \
1720 do { \
1721 static constexpr uint32_t Value = 0xFF00A543; \
1722 static constexpr uint32_t Expected = 0x43A500FF; \
1723 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dst, Immediate(Value)); \
1724 __ bswap(IceType_i32, GPRRegister::Encoded_Reg_##Dst); \
1725 \
1726 AssembledTest test = assemble(); \
1727 test.run(); \
1728 \
1729 ASSERT_EQ(Expected, test.Dst()) << "(" #Dst ")"; \
1730 reset(); \
1731 } while (0)
1732
1733 TestImpl(eax);
1734 TestImpl(ebx);
1735 TestImpl(ecx);
1736 TestImpl(edx);
1737 TestImpl(esi);
1738 TestImpl(edi);
1739
1740 #undef TestImpl
1741 }
1742
TEST_F(AssemblerX8632Test,Bt)1743 TEST_F(AssemblerX8632Test, Bt) {
1744 #define TestImpl(Dst, Value0, Src, Value1) \
1745 do { \
1746 static constexpr char TestString[] = \
1747 "(" #Dst ", " #Value0 ", " #Src ", " #Value1 ")"; \
1748 static constexpr uint32_t Expected = ((Value0) & (1u << (Value1))) != 0; \
1749 \
1750 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dst, Immediate(Value0)); \
1751 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Src, Immediate(Value1)); \
1752 __ bt(GPRRegister::Encoded_Reg_##Dst, GPRRegister::Encoded_Reg_##Src); \
1753 __ setcc(Cond::Br_b, ByteRegister::Encoded_8_Reg_al); \
1754 __ And(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(0xFFu)); \
1755 \
1756 AssembledTest test = assemble(); \
1757 test.run(); \
1758 \
1759 ASSERT_EQ(Expected, test.eax()) << TestString; \
1760 reset(); \
1761 } while (0)
1762
1763 TestImpl(eax, 0x08000000, ebx, 27u);
1764 TestImpl(ebx, 0x08000000, ecx, 23u);
1765 TestImpl(ecx, 0x00000000, edx, 1u);
1766 TestImpl(edx, 0x08000300, esi, 9u);
1767 TestImpl(esi, 0x08000300, edi, 10u);
1768 TestImpl(edi, 0x7FFFEFFF, eax, 13u);
1769
1770 #undef TestImpl
1771 }
1772
1773 template <uint32_t Value, uint32_t Bits> class BitScanHelper {
1774 BitScanHelper() = delete;
1775
1776 public:
1777 static_assert(Bits == 16 || Bits == 32, "Bits must be 16 or 32");
1778 using ValueType =
1779 typename std::conditional<Bits == 16, uint16_t, uint32_t>::type;
1780
1781 private:
BitIndex(bool Forward,ValueType Index)1782 static constexpr ValueType BitIndex(bool Forward, ValueType Index) {
1783 return (Value == 0)
1784 ? BitScanHelper<Value, Bits>::NoBitSet
1785 : (Value & (1u << Index)
1786 ? Index
1787 : BitIndex(Forward, (Forward ? Index + 1 : Index - 1)));
1788 }
1789
1790 public:
1791 static constexpr ValueType NoBitSet = static_cast<ValueType>(-1);
1792 static constexpr ValueType bsf = BitIndex(/*Forward*/ true, /*Index=*/0);
1793 static constexpr ValueType bsr =
1794 BitIndex(/*Forward*/ false, /*Index=*/Bits - 1);
1795 };
1796
TEST_F(AssemblerX8632Test,BitScanOperations)1797 TEST_F(AssemblerX8632Test, BitScanOperations) {
1798 #define TestImplRegReg(Inst, Dst, Src, Value1, Size) \
1799 do { \
1800 static constexpr char TestString[] = \
1801 "(" #Inst ", " #Dst ", " #Src ", " #Value1 ", " #Size ")"; \
1802 static constexpr uint32_t Expected = BitScanHelper<Value1, Size>::Inst; \
1803 const uint32_t ZeroFlag = allocateDword(); \
1804 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
1805 Immediate(Value1)); \
1806 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1807 GPRRegister::Encoded_Reg_##Src); \
1808 __ setcc(Cond::Br_e, dwordAddress(ZeroFlag)); \
1809 \
1810 AssembledTest test = assemble(); \
1811 test.setDwordTo(ZeroFlag, 0u); \
1812 test.run(); \
1813 \
1814 ASSERT_EQ((Expected == BitScanHelper<Value1, Size>::NoBitSet), \
1815 test.contentsOfDword(ZeroFlag)) \
1816 << TestString; \
1817 if ((Expected != BitScanHelper<Value1, Size>::NoBitSet)) { \
1818 ASSERT_EQ(Expected, test.Dst()) << TestString; \
1819 } \
1820 reset(); \
1821 } while (0)
1822
1823 #define TestImplRegAddr(Inst, Dst, Value1, Size) \
1824 do { \
1825 static constexpr char TestString[] = \
1826 "(" #Inst ", " #Dst ", Addr, " #Value1 ", " #Size ")"; \
1827 static constexpr uint32_t Expected = BitScanHelper<Value1, Size>::Inst; \
1828 const uint32_t T0 = allocateDword(); \
1829 const uint32_t ZeroFlag = allocateDword(); \
1830 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1831 dwordAddress(T0)); \
1832 __ setcc(Cond::Br_e, dwordAddress(ZeroFlag)); \
1833 \
1834 AssembledTest test = assemble(); \
1835 test.setDwordTo(T0, Value1); \
1836 test.setDwordTo(ZeroFlag, 0u); \
1837 test.run(); \
1838 \
1839 ASSERT_EQ((Expected == BitScanHelper<Value1, Size>::NoBitSet), \
1840 test.contentsOfDword(ZeroFlag)) \
1841 << TestString; \
1842 if (Expected != BitScanHelper<Value1, Size>::NoBitSet) { \
1843 ASSERT_EQ(Expected, test.Dst()) << TestString; \
1844 } \
1845 reset(); \
1846 } while (0)
1847
1848 #define TestImplSize(Dst, Src, Value1, Size) \
1849 do { \
1850 TestImplRegReg(bsf, Dst, Src, Value1, Size); \
1851 TestImplRegAddr(bsf, Dst, Value1, Size); \
1852 TestImplRegReg(bsr, Dst, Src, Value1, Size); \
1853 TestImplRegAddr(bsf, Dst, Value1, Size); \
1854 } while (0)
1855
1856 #define TestImplValue(Dst, Src, Value1) \
1857 do { \
1858 TestImplSize(Dst, Src, Value1, 16); \
1859 TestImplSize(Dst, Src, Value1, 32); \
1860 } while (0)
1861
1862 #define TestImpl(Dst, Src) \
1863 do { \
1864 TestImplValue(Dst, Src, 0x80000001); \
1865 TestImplValue(Dst, Src, 0x00000000); \
1866 TestImplValue(Dst, Src, 0x80001000); \
1867 TestImplValue(Dst, Src, 0x00FFFF00); \
1868 } while (0)
1869
1870 TestImpl(eax, ebx);
1871 TestImpl(ebx, ecx);
1872 TestImpl(ecx, edx);
1873 TestImpl(edx, esi);
1874 TestImpl(esi, edi);
1875 TestImpl(edi, eax);
1876
1877 #undef TestImpl
1878 #undef TestImplValue
1879 #undef TestImplSize
1880 #undef TestImplRegAddr
1881 #undef TestImplRegReg
1882 }
1883
1884 } // end of anonymous namespace
1885 } // end of namespace Test
1886 } // end of namespace X8632
1887 } // end of namespace Ice
1888