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()) << TestString << " with Disp " \
139 << 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 = \
703 (uint64_t(Value0) & ResultMask##Size)Op(uint64_t(Value1) & \
704 ResultMask##Size); \
705 static constexpr uint32_t Expected0 = Result & Mask##Size; \
706 static constexpr uint32_t Expected1 = (Result >> Size) & Mask##Size; \
707 ASSERT_EQ(Expected0, test.Dst0()) << TestString << ": 0"; \
708 ASSERT_EQ(Expected1, test.Dst1()) << TestString << ": 1"; \
709 reset(); \
710 } while (0)
711
712 #define TestImplRegAddr(Inst0, Inst1, Dst0, Dst1, Value0, Value1, Op, Size) \
713 do { \
714 static_assert(Size == 8 || Size == 16 || Size == 32, \
715 "Invalid size " #Size); \
716 static constexpr char TestString[] = \
717 "(" #Inst0 ", " #Inst1 ", " #Dst0 ", " #Dst1 ", " #Value0 \
718 ", Addr, " #Value1 ", " #Op ", " #Size ")"; \
719 const uint32_t T0 = allocateDword(); \
720 const uint32_t V0 = uint64_t(Value1) & Mask##Size; \
721 const uint32_t T1 = allocateDword(); \
722 const uint32_t V1 = (uint64_t(Value1) >> Size) & Mask##Size; \
723 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst0, \
724 Immediate(uint64_t(Value0) & Mask##Size)); \
725 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst1, \
726 Immediate((uint64_t(Value0) >> Size) & Mask##Size)); \
727 __ Inst0(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst0, \
728 dwordAddress(T0)); \
729 __ Inst1(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst1, \
730 dwordAddress(T1)); \
731 \
732 AssembledTest test = assemble(); \
733 test.setDwordTo(T0, V0); \
734 test.setDwordTo(T1, V1); \
735 test.run(); \
736 \
737 static constexpr uint64_t Result = \
738 (uint64_t(Value0) & ResultMask##Size)Op(uint64_t(Value1) & \
739 ResultMask##Size); \
740 static constexpr uint32_t Expected0 = Result & Mask##Size; \
741 static constexpr uint32_t Expected1 = (Result >> Size) & Mask##Size; \
742 ASSERT_EQ(Expected0, test.Dst0()) << TestString << ": 0"; \
743 ASSERT_EQ(Expected1, test.Dst1()) << TestString << ": 1"; \
744 reset(); \
745 } while (0)
746
747 #define TestImplRegImm(Inst0, Inst1, Dst0, Dst1, Value0, Imm, Op, Size) \
748 do { \
749 static_assert(Size == 8 || Size == 16 || Size == 32, \
750 "Invalid size " #Size); \
751 static constexpr char TestString[] = \
752 "(" #Inst0 ", " #Inst1 ", " #Dst0 ", " #Dst1 ", " #Value0 \
753 ", Imm(" #Imm "), " #Op ", " #Size ")"; \
754 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst0, \
755 Immediate(uint64_t(Value0) & Mask##Size)); \
756 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst1, \
757 Immediate((uint64_t(Value0) >> Size) & Mask##Size)); \
758 __ Inst0(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst0, \
759 Immediate(uint64_t(Imm) & Mask##Size)); \
760 __ Inst1(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst1, \
761 Immediate((uint64_t(Imm) >> Size) & Mask##Size)); \
762 \
763 AssembledTest test = assemble(); \
764 test.run(); \
765 \
766 static constexpr uint64_t Result = \
767 (uint64_t(Value0) & ResultMask##Size)Op(uint64_t(Imm) & \
768 ResultMask##Size); \
769 static constexpr uint32_t Expected0 = Result & Mask##Size; \
770 static constexpr uint32_t Expected1 = (Result >> Size) & Mask##Size; \
771 ASSERT_EQ(Expected0, test.Dst0()) << TestString << ": 0"; \
772 ASSERT_EQ(Expected1, test.Dst1()) << TestString << ": 1"; \
773 reset(); \
774 } while (0)
775
776 #define TestImplAddrReg(Inst0, Inst1, Value0, Src0, Src1, Value1, Op, Size) \
777 do { \
778 static_assert(Size == 8 || Size == 16 || Size == 32, \
779 "Invalid size " #Size); \
780 static constexpr char TestString[] = \
781 "(" #Inst0 ", " #Inst1 ", Addr, " #Value0 ", " #Src0 ", " #Src1 \
782 ", " #Value1 ", " #Op ", " #Size ")"; \
783 const uint32_t T0 = allocateDword(); \
784 const uint32_t V0 = uint64_t(Value0) & Mask##Size; \
785 const uint32_t T1 = allocateDword(); \
786 const uint32_t V1 = (uint64_t(Value0) >> Size) & Mask##Size; \
787 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src0, \
788 Immediate(uint64_t(Value1) & Mask##Size)); \
789 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src1, \
790 Immediate((uint64_t(Value1) >> Size) & Mask##Size)); \
791 __ Inst0(IceType_i##Size, dwordAddress(T0), \
792 GPRRegister::Encoded_Reg_##Src0); \
793 __ Inst1(IceType_i##Size, dwordAddress(T1), \
794 GPRRegister::Encoded_Reg_##Src1); \
795 \
796 AssembledTest test = assemble(); \
797 test.setDwordTo(T0, V0); \
798 test.setDwordTo(T1, V1); \
799 test.run(); \
800 \
801 static constexpr uint64_t Result = \
802 (uint64_t(Value0) & ResultMask##Size)Op(uint64_t(Value1) & \
803 ResultMask##Size); \
804 static constexpr uint32_t Expected0 = Result & Mask##Size; \
805 static constexpr uint32_t Expected1 = (Result >> Size) & Mask##Size; \
806 ASSERT_EQ(Expected0, test.contentsOfDword(T0)) << TestString << ": 0"; \
807 ASSERT_EQ(Expected1, test.contentsOfDword(T1)) << TestString << ": 1"; \
808 reset(); \
809 } while (0)
810
811 #define TestImplAddrImm(Inst0, Inst1, Value0, Imm, Op, Size) \
812 do { \
813 static_assert(Size == 8 || Size == 16 || Size == 32, \
814 "Invalid size " #Size); \
815 static constexpr char TestString[] = \
816 "(" #Inst0 ", " #Inst1 ", Addr, " #Value0 ", Imm(" #Imm "), " #Op \
817 ", " #Size ")"; \
818 const uint32_t T0 = allocateDword(); \
819 const uint32_t V0 = uint64_t(Value0) & Mask##Size; \
820 const uint32_t T1 = allocateDword(); \
821 const uint32_t V1 = (uint64_t(Value0) >> Size) & Mask##Size; \
822 __ Inst0(IceType_i##Size, dwordAddress(T0), \
823 Immediate(uint64_t(Imm) & Mask##Size)); \
824 __ Inst1(IceType_i##Size, dwordAddress(T1), \
825 Immediate((uint64_t(Imm) >> Size) & Mask##Size)); \
826 \
827 AssembledTest test = assemble(); \
828 test.setDwordTo(T0, V0); \
829 test.setDwordTo(T1, V1); \
830 test.run(); \
831 \
832 static constexpr uint64_t Result = \
833 (uint64_t(Value0) & ResultMask##Size)Op(uint64_t(Imm) & \
834 ResultMask##Size); \
835 static constexpr uint32_t Expected0 = Result & Mask##Size; \
836 static constexpr uint32_t Expected1 = (Result >> Size) & Mask##Size; \
837 ASSERT_EQ(Expected0, test.contentsOfDword(T0)) << TestString << ": 0"; \
838 ASSERT_EQ(Expected1, test.contentsOfDword(T1)) << TestString << ": 1"; \
839 reset(); \
840 } while (0)
841
842 #define TestImplOp(Inst0, Inst1, Dst0, Dst1, Value0, Src0, Src1, Value1, Op, \
843 Size) \
844 do { \
845 TestImplRegReg(Inst0, Inst1, Dst0, Dst1, Value0, Src0, Src1, Value1, Op, \
846 Size); \
847 TestImplRegAddr(Inst0, Inst1, Dst0, Dst1, Value0, Value1, Op, Size); \
848 TestImplRegImm(Inst0, Inst1, Dst0, Dst1, Value0, Value1, Op, Size); \
849 TestImplAddrReg(Inst0, Inst1, Value0, Src0, Src1, Value1, Op, Size); \
850 TestImplAddrImm(Inst0, Inst1, Value0, Value1, Op, Size); \
851 } while (0)
852
853 #define TestImplValues(Dst0, Dst1, Value0, Src0, Src1, Value1, Size) \
854 do { \
855 TestImplOp(add, adc, Dst0, Dst1, Value0, Src0, Src1, Value1, +, Size); \
856 TestImplOp(sub, sbb, Dst0, Dst1, Value0, Src0, Src1, Value1, -, Size); \
857 } while (0)
858
859 #define TestImplSize(Dst0, Dst1, Src0, Src1, Size) \
860 do { \
861 TestImplValues(Dst0, Dst1, 0xFFFFFFFFFFFFFF00ull, Src0, Src1, \
862 0xFFFFFFFF0000017Full, Size); \
863 } while (0)
864
865 #define TestImpl(Dst0, Dst1, Src0, Src1) \
866 do { \
867 if (GPRRegister::Encoded_Reg_##Dst0 <= 3 && \
868 GPRRegister::Encoded_Reg_##Dst1 <= 3 && \
869 GPRRegister::Encoded_Reg_##Src0 <= 3 && \
870 GPRRegister::Encoded_Reg_##Src1 <= 3) { \
871 TestImplSize(Dst0, Dst1, Src0, Src1, 8); \
872 } \
873 TestImplSize(Dst0, Dst1, Src0, Src1, 16); \
874 TestImplSize(Dst0, Dst1, Src0, Src1, 32); \
875 } while (0)
876
877 TestImpl(eax, ebx, ecx, edx);
878 TestImpl(ebx, ecx, edx, esi);
879 TestImpl(ecx, edx, esi, edi);
880 TestImpl(edx, esi, edi, eax);
881 TestImpl(esi, edi, eax, ebx);
882 TestImpl(edi, eax, ebx, ecx);
883
884 #undef TestImpl
885 #undef TestImplSize
886 #undef TestImplValues
887 #undef TestImplOp
888 #undef TestImplAddrImm
889 #undef TestImplAddrReg
890 #undef TestImplRegImm
891 #undef TestImplRegAddr
892 #undef TestImplRegReg
893 }
894
TEST_F(AssemblerX8632LowLevelTest,Cbw_Cwd_Cdq)895 TEST_F(AssemblerX8632LowLevelTest, Cbw_Cwd_Cdq) {
896 #define TestImpl(Inst, BytesSize, ...) \
897 do { \
898 __ Inst(); \
899 ASSERT_EQ(BytesSize, codeBytesSize()) << #Inst; \
900 verifyBytes<BytesSize>(codeBytes(), __VA_ARGS__); \
901 reset(); \
902 } while (0)
903
904 TestImpl(cbw, 2u, 0x66, 0x98);
905 TestImpl(cwd, 2u, 0x66, 0x99);
906 TestImpl(cdq, 1u, 0x99);
907
908 #undef TestImpl
909 }
910
TEST_F(AssemblerX8632Test,SingleOperandMul)911 TEST_F(AssemblerX8632Test, SingleOperandMul) {
912 static constexpr uint32_t Mask8 = 0x000000FF;
913 static constexpr uint32_t Mask16 = 0x0000FFFF;
914 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
915
916 #define TestImplReg(Inst, Value0, Src, Value1, Type, Size) \
917 do { \
918 static_assert(GPRRegister::Encoded_Reg_eax != \
919 GPRRegister::Encoded_Reg_##Src, \
920 "eax can not be src1."); \
921 \
922 static constexpr char TestString[] = \
923 "(" #Inst ", " #Value0 ", " #Src ", " #Value1 ", " #Type ", " #Size \
924 ")"; \
925 static constexpr Type##64_t OperandEax = \
926 static_cast<Type##Size##_t>((Value0)&Mask##Size); \
927 static constexpr Type##64_t OperandOther = \
928 static_cast<Type##Size##_t>((Value1)&Mask##Size); \
929 static constexpr uint32_t ExpectedEax = \
930 Mask##Size & (OperandEax * OperandOther); \
931 static constexpr uint32_t ExpectedEdx = \
932 Mask##Size & ((OperandEax * OperandOther) >> Size); \
933 \
934 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_eax, \
935 Immediate((Value0)&Mask##Size)); \
936 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
937 Immediate((Value1)&Mask##Size)); \
938 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Src); \
939 \
940 if (Size == 8) { \
941 /* mov %ah, %dl */ \
942 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
943 GPRRegister::Encoded_Reg_esp); \
944 __ And(IceType_i16, GPRRegister::Encoded_Reg_eax, Immediate(0x00FF)); \
945 if (GPRRegister::Encoded_Reg_##Src == GPRRegister::Encoded_Reg_esi) { \
946 /* src == dh; clear dx's upper 8 bits. */ \
947 __ And(IceType_i16, GPRRegister::Encoded_Reg_edx, Immediate(0x00FF)); \
948 } \
949 } \
950 \
951 AssembledTest test = assemble(); \
952 test.run(); \
953 \
954 ASSERT_EQ(ExpectedEax, test.eax()) << TestString; \
955 ASSERT_EQ(ExpectedEdx, test.edx()) << TestString; \
956 reset(); \
957 } while (0)
958
959 #define TestImplAddr(Inst, Value0, Value1, Type, Size) \
960 do { \
961 static constexpr char TestString[] = \
962 "(" #Inst ", " #Value0 ", Addr, " #Value1 ", " #Type ", " #Size ")"; \
963 static const uint32_t T0 = allocateDword(); \
964 static constexpr uint32_t V0 = Value1; \
965 static constexpr Type##64_t OperandEax = \
966 static_cast<Type##Size##_t>((Value0)&Mask##Size); \
967 static constexpr Type##64_t OperandOther = \
968 static_cast<Type##Size##_t>((Value1)&Mask##Size); \
969 static constexpr uint32_t ExpectedEax = \
970 Mask##Size & (OperandEax * OperandOther); \
971 static constexpr uint32_t ExpectedEdx = \
972 Mask##Size & ((OperandEax * OperandOther) >> Size); \
973 \
974 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_eax, \
975 Immediate((Value0)&Mask##Size)); \
976 __ Inst(IceType_i##Size, dwordAddress(T0)); \
977 \
978 if (Size == 8) { \
979 /* mov %ah, %dl */ \
980 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
981 GPRRegister::Encoded_Reg_esp); \
982 __ And(IceType_i16, GPRRegister::Encoded_Reg_eax, Immediate(0x00FF)); \
983 } \
984 \
985 AssembledTest test = assemble(); \
986 test.setDwordTo(T0, V0); \
987 test.run(); \
988 \
989 ASSERT_EQ(ExpectedEax, test.eax()) << TestString; \
990 ASSERT_EQ(ExpectedEdx, test.edx()) << TestString; \
991 reset(); \
992 } while (0)
993
994 #define TestImplOp(Inst, Value0, Src, Value1, Type, Size) \
995 do { \
996 TestImplReg(Inst, Value0, Src, Value1, Type, Size); \
997 TestImplAddr(Inst, Value0, Value1, Type, Size); \
998 } while (0)
999
1000 #define TestImplValue(Value0, Src, Value1, Size) \
1001 do { \
1002 TestImplOp(mul, Value0, Src, Value1, uint, Size); \
1003 TestImplOp(imul, Value0, Src, Value1, int, Size); \
1004 } while (0)
1005
1006 #define TestImplSize(Src, Size) \
1007 do { \
1008 TestImplValue(10, Src, 1, Size); \
1009 TestImplValue(10, Src, -1, Size); \
1010 TestImplValue(-10, Src, 37, Size); \
1011 TestImplValue(-10, Src, -15, Size); \
1012 } while (0)
1013
1014 #define TestImpl(Src) \
1015 do { \
1016 TestImplSize(Src, 8); \
1017 TestImplSize(Src, 16); \
1018 TestImplSize(Src, 32); \
1019 } while (0)
1020
1021 TestImpl(ebx);
1022 TestImpl(ecx);
1023 TestImpl(edx);
1024 TestImpl(esi);
1025 TestImpl(edi);
1026
1027 #undef TestImpl
1028 #undef TestImplSize
1029 #undef TestImplValue
1030 #undef TestImplOp
1031 #undef TestImplAddr
1032 #undef TestImplReg
1033 }
1034
TEST_F(AssemblerX8632Test,TwoOperandImul)1035 TEST_F(AssemblerX8632Test, TwoOperandImul) {
1036 static constexpr uint32_t Mask16 = 0x0000FFFF;
1037 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
1038
1039 #define TestImplRegReg(Dst, Value0, Src, Value1, Size) \
1040 do { \
1041 static constexpr char TestString[] = \
1042 "(" #Dst ", " #Value0 ", " #Src ", " #Value1 ", " #Size ")"; \
1043 static constexpr int64_t Operand0 = \
1044 static_cast<int##Size##_t>((Value0)&Mask##Size); \
1045 static constexpr int64_t Operand1 = \
1046 static_cast<int##Size##_t>((Value1)&Mask##Size); \
1047 static constexpr uint32_t Expected = Mask##Size & (Operand0 * Operand1); \
1048 \
1049 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1050 Immediate((Value0)&Mask##Size)); \
1051 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
1052 Immediate((Value1)&Mask##Size)); \
1053 __ imul(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1054 GPRRegister::Encoded_Reg_##Src); \
1055 \
1056 if (Size == 8) { \
1057 /* mov %ah, %dl */ \
1058 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
1059 GPRRegister::Encoded_Reg_esp); \
1060 __ And(IceType_i16, GPRRegister::Encoded_Reg_eax, Immediate(0x00FF)); \
1061 if (GPRRegister::Encoded_Reg_##Src == GPRRegister::Encoded_Reg_esi) { \
1062 /* src == dh; clear dx's upper 8 bits. */ \
1063 __ And(IceType_i16, GPRRegister::Encoded_Reg_edx, Immediate(0x00FF)); \
1064 } \
1065 } \
1066 \
1067 AssembledTest test = assemble(); \
1068 test.run(); \
1069 \
1070 ASSERT_EQ(Expected, test.Dst()) << TestString; \
1071 reset(); \
1072 } while (0)
1073
1074 #define TestImplRegImm(Dst, Value0, Imm, Size) \
1075 do { \
1076 static constexpr char TestString[] = \
1077 "(" #Dst ", " #Value0 ", Imm(" #Imm "), " #Size ")"; \
1078 static constexpr int64_t Operand0 = \
1079 static_cast<int##Size##_t>((Value0)&Mask##Size); \
1080 static constexpr int64_t Operand1 = \
1081 static_cast<int##Size##_t>((Imm)&Mask##Size); \
1082 static constexpr uint32_t Expected = Mask##Size & (Operand0 * Operand1); \
1083 \
1084 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1085 Immediate((Value0)&Mask##Size)); \
1086 __ imul(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, Immediate(Imm)); \
1087 \
1088 if (Size == 8) { \
1089 /* mov %ah, %dl */ \
1090 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
1091 GPRRegister::Encoded_Reg_esp); \
1092 __ And(IceType_i16, GPRRegister::Encoded_Reg_eax, Immediate(0x00FF)); \
1093 } \
1094 \
1095 AssembledTest test = assemble(); \
1096 test.run(); \
1097 \
1098 ASSERT_EQ(Expected, test.Dst()) << TestString; \
1099 reset(); \
1100 } while (0)
1101
1102 #define TestImplRegAddr(Dst, Value0, Value1, Size) \
1103 do { \
1104 static constexpr char TestString[] = \
1105 "(" #Dst ", " #Value0 ", Addr," #Value1 ", " #Size ")"; \
1106 static constexpr int64_t Operand0 = \
1107 static_cast<int##Size##_t>((Value0)&Mask##Size); \
1108 static constexpr int64_t Operand1 = \
1109 static_cast<int##Size##_t>((Value1)&Mask##Size); \
1110 static constexpr uint32_t Expected = Mask##Size & (Operand0 * Operand1); \
1111 const uint32_t T0 = allocateDword(); \
1112 \
1113 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1114 Immediate((Value0)&Mask##Size)); \
1115 __ imul(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1116 dwordAddress(T0)); \
1117 \
1118 if (Size == 8) { \
1119 /* mov %ah, %dl */ \
1120 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
1121 GPRRegister::Encoded_Reg_esp); \
1122 __ And(IceType_i16, GPRRegister::Encoded_Reg_eax, Immediate(0x00FF)); \
1123 } \
1124 \
1125 AssembledTest test = assemble(); \
1126 test.setDwordTo(T0, static_cast<uint32_t>(Operand1)); \
1127 test.run(); \
1128 \
1129 ASSERT_EQ(Expected, test.Dst()) << TestString; \
1130 reset(); \
1131 } while (0)
1132
1133 #define TestImplValue(Dst, Value0, Src, Value1, Size) \
1134 do { \
1135 TestImplRegReg(Dst, Value0, Src, Value1, Size); \
1136 TestImplRegImm(Dst, Value0, Value1, Size); \
1137 TestImplRegAddr(Dst, Value0, Value1, Size); \
1138 } while (0)
1139
1140 #define TestImplSize(Dst, Src, Size) \
1141 do { \
1142 TestImplValue(Dst, 1, Src, 1, Size); \
1143 TestImplValue(Dst, -10, Src, 0x4050AA20, Size); \
1144 TestImplValue(Dst, -2, Src, -55, Size); \
1145 } while (0)
1146
1147 #define TestImpl(Dst, Src) \
1148 do { \
1149 TestImplSize(Dst, Src, 16); \
1150 TestImplSize(Dst, Src, 32); \
1151 } while (0)
1152
1153 TestImpl(eax, ebx);
1154 TestImpl(ebx, ecx);
1155 TestImpl(ecx, edx);
1156 TestImpl(edx, esi);
1157 TestImpl(esi, edi);
1158 TestImpl(edi, eax);
1159
1160 #undef TestImpl
1161 #undef TestImplSize
1162 #undef TestImplValue
1163 #undef TestImplRegAddr
1164 #undef TestImplRegImm
1165 #undef TestImplRegReg
1166 }
1167
TEST_F(AssemblerX8632Test,Div)1168 TEST_F(AssemblerX8632Test, Div) {
1169 static constexpr uint32_t Mask8 = 0x000000FF;
1170 static constexpr uint32_t Mask16 = 0x0000FFFF;
1171 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
1172
1173 static constexpr uint64_t Operand0Mask8 = 0x00000000000000FFull;
1174 static constexpr uint64_t Operand0Mask16 = 0x00000000FFFFFFFFull;
1175 static constexpr uint64_t Operand0Mask32 = 0xFFFFFFFFFFFFFFFFull;
1176
1177 using Operand0Type_int8 = int16_t;
1178 using Operand0Type_uint8 = uint16_t;
1179 using Operand0Type_int16 = int32_t;
1180 using Operand0Type_uint16 = uint32_t;
1181 using Operand0Type_int32 = int64_t;
1182 using Operand0Type_uint32 = uint64_t;
1183
1184 #define TestImplReg(Inst, Value0, Src, Value1, Type, Size) \
1185 do { \
1186 static_assert(GPRRegister::Encoded_Reg_eax != \
1187 GPRRegister::Encoded_Reg_##Src, \
1188 "eax can not be src1."); \
1189 static_assert(GPRRegister::Encoded_Reg_edx != \
1190 GPRRegister::Encoded_Reg_##Src, \
1191 "edx can not be src1."); \
1192 \
1193 static constexpr char TestString[] = \
1194 "(" #Inst ", " #Value0 ", " #Src ", " #Value1 ", " #Type ", " #Size \
1195 ")"; \
1196 static constexpr Operand0Type_##Type##Size Operand0 = \
1197 static_cast<Type##64_t>(Value0) & Operand0Mask##Size; \
1198 static constexpr Type##Size##_t Operand0Lo = Operand0 & Mask##Size; \
1199 static constexpr Type##Size##_t Operand0Hi = \
1200 (Operand0 >> Size) & Mask##Size; \
1201 static constexpr Type##Size##_t Operand1 = \
1202 static_cast<Type##Size##_t>(Value1) & Mask##Size; \
1203 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_eax, \
1204 Immediate(Operand0Lo)); \
1205 if (Size == 8) { \
1206 /* mov Operand0Hi, %ah */ \
1207 __ mov(IceType_i8, GPRRegister::Encoded_Reg_esp, Immediate(Operand0Hi)); \
1208 } else { \
1209 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
1210 Immediate(Operand0Hi)); \
1211 } \
1212 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
1213 Immediate(Operand1)); \
1214 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Src); \
1215 if (Size == 8) { \
1216 /* mov %ah, %dl */ \
1217 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
1218 GPRRegister::Encoded_Reg_esp); \
1219 __ And(IceType_i16, GPRRegister::Encoded_Reg_eax, Immediate(0x00FF)); \
1220 if (GPRRegister::Encoded_Reg_##Src == GPRRegister::Encoded_Reg_esi) { \
1221 __ And(IceType_i16, GPRRegister::Encoded_Reg_edx, Immediate(0x00FF)); \
1222 } \
1223 } \
1224 \
1225 AssembledTest test = assemble(); \
1226 test.run(); \
1227 \
1228 static constexpr uint32_t Quocient = (Operand0 / Operand1) & Mask##Size; \
1229 static constexpr uint32_t Reminder = (Operand0 % Operand1) & Mask##Size; \
1230 EXPECT_EQ(Quocient, test.eax()) << TestString; \
1231 EXPECT_EQ(Reminder, test.edx()) << TestString; \
1232 reset(); \
1233 } while (0)
1234
1235 #define TestImplAddr(Inst, Value0, Value1, Type, Size) \
1236 do { \
1237 static constexpr char TestString[] = \
1238 "(" #Inst ", " #Value0 ", Addr, " #Value1 ", " #Type ", " #Size ")"; \
1239 static constexpr Operand0Type_##Type##Size Operand0 = \
1240 static_cast<Type##64_t>(Value0) & Operand0Mask##Size; \
1241 static constexpr Type##Size##_t Operand0Lo = Operand0 & Mask##Size; \
1242 static constexpr Type##Size##_t Operand0Hi = \
1243 (Operand0 >> Size) & Mask##Size; \
1244 const uint32_t T0 = allocateDword(); \
1245 static constexpr Type##Size##_t V0 = \
1246 static_cast<Type##Size##_t>(Value1) & Mask##Size; \
1247 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_eax, \
1248 Immediate(Operand0Lo)); \
1249 if (Size == 8) { \
1250 /* mov Operand0Hi, %ah */ \
1251 __ mov(IceType_i8, GPRRegister::Encoded_Reg_esp, Immediate(Operand0Hi)); \
1252 } else { \
1253 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
1254 Immediate(Operand0Hi)); \
1255 } \
1256 __ Inst(IceType_i##Size, dwordAddress(T0)); \
1257 if (Size == 8) { \
1258 /* mov %ah, %dl */ \
1259 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
1260 GPRRegister::Encoded_Reg_esp); \
1261 __ And(IceType_i16, GPRRegister::Encoded_Reg_eax, Immediate(0x00FF)); \
1262 } \
1263 \
1264 AssembledTest test = assemble(); \
1265 test.setDwordTo(T0, static_cast<uint32_t>(V0)); \
1266 test.run(); \
1267 \
1268 static constexpr uint32_t Quocient = (Operand0 / V0) & Mask##Size; \
1269 static constexpr uint32_t Reminder = (Operand0 % V0) & Mask##Size; \
1270 EXPECT_EQ(Quocient, test.eax()) << TestString; \
1271 EXPECT_EQ(Reminder, test.edx()) << TestString; \
1272 reset(); \
1273 } while (0)
1274
1275 #define TestImplOp(Inst, Value0, Src, Value1, Type, Size) \
1276 do { \
1277 TestImplReg(Inst, Value0, Src, Value1, Type, Size); \
1278 TestImplAddr(Inst, Value0, Value1, Type, Size); \
1279 } while (0)
1280
1281 #define TestImplValue(Value0, Src, Value1, Size) \
1282 do { \
1283 TestImplOp(div, Value0, Src, Value1, uint, Size); \
1284 TestImplOp(idiv, Value0, Src, Value1, int, Size); \
1285 } while (0)
1286
1287 #define TestImplSize(Src, Size) \
1288 do { \
1289 TestImplValue(10, Src, 1, Size); \
1290 TestImplValue(10, Src, -1, Size); \
1291 } while (0)
1292
1293 #define TestImpl(Src) \
1294 do { \
1295 TestImplSize(Src, 8); \
1296 TestImplSize(Src, 16); \
1297 TestImplSize(Src, 32); \
1298 } while (0)
1299
1300 TestImpl(ebx);
1301 TestImpl(ecx);
1302 TestImpl(esi);
1303 TestImpl(edi);
1304
1305 #undef TestImpl
1306 #undef TestImplSize
1307 #undef TestImplValue
1308 #undef TestImplOp
1309 #undef TestImplAddr
1310 #undef TestImplReg
1311 }
1312
1313 // This is not executable in x86-64 because the one byte inc/dec instructions
1314 // became the REX prefixes. Therefore, these are tested with the low-level test
1315 // infrastructure.
TEST_F(AssemblerX8632LowLevelTest,Incl_Decl_Reg)1316 TEST_F(AssemblerX8632LowLevelTest, Incl_Decl_Reg) {
1317 #define TestImpl(Inst, Dst, BaseOpcode) \
1318 do { \
1319 __ Inst(GPRRegister::Encoded_Reg_##Dst); \
1320 static constexpr uint8_t ByteCount = 1; \
1321 ASSERT_EQ(ByteCount, codeBytesSize()); \
1322 verifyBytes<ByteCount>(codeBytes(), \
1323 BaseOpcode | GPRRegister::Encoded_Reg_##Dst); \
1324 reset(); \
1325 } while (0)
1326
1327 #define TestInc(Dst) \
1328 do { \
1329 constexpr uint8_t InclOpcode = 0x40; \
1330 TestImpl(incl, Dst, InclOpcode); \
1331 } while (0)
1332
1333 #define TestDec(Dst) \
1334 do { \
1335 constexpr uint8_t DeclOpcode = 0x48; \
1336 TestImpl(decl, Dst, DeclOpcode); \
1337 } while (0)
1338
1339 TestInc(eax);
1340 TestInc(ecx);
1341 TestInc(edx);
1342 TestInc(ebx);
1343 TestInc(esp);
1344 TestInc(ebp);
1345 TestInc(esi);
1346 TestInc(esi);
1347
1348 TestDec(eax);
1349 TestDec(ecx);
1350 TestDec(edx);
1351 TestDec(ebx);
1352 TestDec(esp);
1353 TestDec(ebp);
1354 TestDec(esi);
1355 TestDec(esi);
1356
1357 #undef TestInc
1358 #undef TestDec
1359 #undef TestImpl
1360 }
1361
TEST_F(AssemblerX8632Test,Incl_Decl_Addr)1362 TEST_F(AssemblerX8632Test, Incl_Decl_Addr) {
1363 #define TestImpl(Inst, Value0) \
1364 do { \
1365 const bool IsInc = std::string(#Inst).find("incl") != std::string::npos; \
1366 const uint32_t T0 = allocateDword(); \
1367 const uint32_t V0 = Value0; \
1368 \
1369 __ Inst(dwordAddress(T0)); \
1370 \
1371 AssembledTest test = assemble(); \
1372 test.setDwordTo(T0, V0); \
1373 test.run(); \
1374 \
1375 ASSERT_EQ(static_cast<uint32_t>(Value0 + (IsInc ? 1 : -1)), \
1376 test.contentsOfDword(T0)); \
1377 reset(); \
1378 } while (0)
1379
1380 #define TestInc(Value0) \
1381 do { \
1382 TestImpl(incl, Value0); \
1383 } while (0)
1384
1385 #define TestDec(Value0) \
1386 do { \
1387 TestImpl(decl, Value0); \
1388 } while (0)
1389
1390 TestInc(230);
1391
1392 TestDec(30);
1393
1394 #undef TestInc
1395 #undef TestDec
1396 #undef TestImpl
1397 }
1398
TEST_F(AssemblerX8632Test,Shifts)1399 TEST_F(AssemblerX8632Test, Shifts) {
1400 static constexpr uint32_t Mask8 = 0x000000FF;
1401 static constexpr uint32_t Mask16 = 0x0000FFFF;
1402 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
1403
1404 #define TestImplRegImm(Inst, Dst, Value0, Imm, Op, Type, Size) \
1405 do { \
1406 static constexpr char TestString[] = \
1407 "(" #Inst ", " #Dst ", " #Value0 ", Imm(" #Imm "), " #Op ", " #Type \
1408 ", " #Size ")"; \
1409 const bool IsRol = std::string(#Inst).find("rol") != std::string::npos; \
1410 const uint##Size##_t Expected = \
1411 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op(Imm) | \
1412 (!IsRol ? 0 : (Value0) >> (Size - Imm))); \
1413 \
1414 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1415 Immediate((Value0)&Mask##Size)); \
1416 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1417 Immediate((Imm)&Mask##Size)); \
1418 \
1419 AssembledTest test = assemble(); \
1420 test.run(); \
1421 \
1422 ASSERT_EQ(static_cast<uint32_t>(Expected), test.Dst()) << TestString; \
1423 reset(); \
1424 } while (0)
1425
1426 #define TestImplRegRegImm(Inst, Dst, Value0, Src, Value1, Count, Op0, Op1, \
1427 Type, Size) \
1428 do { \
1429 static constexpr char TestString[] = \
1430 "(" #Inst ", " #Dst ", " #Value0 ", " #Src ", " #Value1 \
1431 ", Imm(" #Count "), " #Op0 ", " #Op1 ", " #Type ", " #Size ")"; \
1432 const uint##Size##_t Expected = \
1433 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op0(Count) | \
1434 (static_cast<Type##64_t>(Value1) Op1(Size - Count))); \
1435 \
1436 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1437 Immediate((Value0)&Mask##Size)); \
1438 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
1439 Immediate((Value1)&Mask##Size)); \
1440 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1441 GPRRegister::Encoded_Reg_##Src, Immediate(Count)); \
1442 \
1443 AssembledTest test = assemble(); \
1444 test.run(); \
1445 \
1446 ASSERT_EQ(static_cast<uint32_t>(Expected), test.Dst()) << TestString; \
1447 reset(); \
1448 } while (0)
1449
1450 #define TestImplRegCl(Inst, Dst, Value0, Count, Op, Type, Size) \
1451 do { \
1452 static constexpr char TestString[] = \
1453 "(" #Inst ", " #Dst ", " #Value0 ", " #Count ", " #Op ", " #Type \
1454 ", " #Size ")"; \
1455 const bool IsRol = std::string(#Inst).find("rol") != std::string::npos; \
1456 const uint##Size##_t Expected = \
1457 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op(Count) | \
1458 (!IsRol ? 0 : Value0 >> (Size - Count))); \
1459 \
1460 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1461 Immediate((Value0)&Mask##Size)); \
1462 __ mov(IceType_i8, GPRRegister::Encoded_Reg_ecx, \
1463 Immediate((Count)&Mask##Size)); \
1464 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1465 GPRRegister::Encoded_Reg_ecx); \
1466 \
1467 AssembledTest test = assemble(); \
1468 test.run(); \
1469 \
1470 ASSERT_EQ(static_cast<uint32_t>(Expected), test.Dst()) << TestString; \
1471 reset(); \
1472 } while (0)
1473
1474 #define TestImplRegRegCl(Inst, Dst, Value0, Src, Value1, Count, Op0, Op1, \
1475 Type, Size) \
1476 do { \
1477 static constexpr char TestString[] = \
1478 "(" #Inst ", " #Dst ", " #Value0 ", " #Src ", " #Value1 ", " #Count \
1479 ", " #Op0 ", " #Op1 ", " #Type ", " #Size ")"; \
1480 const uint##Size##_t Expected = \
1481 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op0(Count) | \
1482 (static_cast<Type##64_t>(Value1) Op1(Size - Count))); \
1483 \
1484 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1485 Immediate((Value0)&Mask##Size)); \
1486 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
1487 Immediate((Value1)&Mask##Size)); \
1488 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_ecx, \
1489 Immediate((Count)&0x7F)); \
1490 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1491 GPRRegister::Encoded_Reg_##Src); \
1492 \
1493 AssembledTest test = assemble(); \
1494 test.run(); \
1495 \
1496 ASSERT_EQ(static_cast<uint32_t>(Expected), test.Dst()) << TestString; \
1497 reset(); \
1498 } while (0)
1499
1500 #define TestImplAddrCl(Inst, Value0, Count, Op, Type, Size) \
1501 do { \
1502 static constexpr char TestString[] = \
1503 "(" #Inst ", Addr, " #Value0 ", " #Count ", " #Op ", " #Type \
1504 ", " #Size ")"; \
1505 const bool IsRol = std::string(#Inst).find("rol") != std::string::npos; \
1506 const uint##Size##_t Expected = \
1507 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op(Count) | \
1508 (!IsRol ? 0 : Value0 >> (Size - Count))); \
1509 const uint32_t T0 = allocateDword(); \
1510 const uint32_t V0 = Value0; \
1511 \
1512 __ mov(IceType_i8, GPRRegister::Encoded_Reg_ecx, \
1513 Immediate((Count)&Mask##Size)); \
1514 __ Inst(IceType_i##Size, dwordAddress(T0), GPRRegister::Encoded_Reg_ecx); \
1515 \
1516 AssembledTest test = assemble(); \
1517 test.setDwordTo(T0, V0); \
1518 test.run(); \
1519 \
1520 ASSERT_EQ(static_cast<uint32_t>(Expected), \
1521 Mask##Size &test.contentsOfDword(T0)) \
1522 << TestString; \
1523 reset(); \
1524 } while (0)
1525
1526 #define TestImplAddrRegCl(Inst, Value0, Src, Value1, Count, Op0, Op1, Type, \
1527 Size) \
1528 do { \
1529 static constexpr char TestString[] = \
1530 "(" #Inst ", Addr, " #Value0 ", " #Src ", " #Value1 ", " #Count \
1531 ", " #Op0 ", " #Op1 ", " #Type ", " #Size ")"; \
1532 const uint##Size##_t Expected = \
1533 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op0(Count) | \
1534 (static_cast<Type##64_t>(Value1) Op1(Size - Count))); \
1535 const uint32_t T0 = allocateDword(); \
1536 \
1537 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
1538 Immediate((Value1)&Mask##Size)); \
1539 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_ecx, \
1540 Immediate((Count)&0x7F)); \
1541 __ Inst(IceType_i##Size, dwordAddress(T0), \
1542 GPRRegister::Encoded_Reg_##Src); \
1543 \
1544 AssembledTest test = assemble(); \
1545 test.setDwordTo(T0, static_cast<uint32_t>(Value0)); \
1546 test.run(); \
1547 \
1548 ASSERT_EQ(static_cast<uint32_t>(Expected), test.contentsOfDword(T0)) \
1549 << TestString; \
1550 reset(); \
1551 } while (0)
1552
1553 #define TestImplOp(Inst, Dst, Value0, Count, Op, Type, Size) \
1554 do { \
1555 static_assert(GPRRegister::Encoded_Reg_##Dst != \
1556 GPRRegister::Encoded_Reg_ecx, \
1557 "ecx should not be specified as Dst"); \
1558 TestImplRegImm(Inst, Dst, Value0, Count, Op, Type, Size); \
1559 TestImplRegImm(Inst, ecx, Value0, Count, Op, Type, Size); \
1560 TestImplRegCl(Inst, Dst, Value0, Count, Op, Type, Size); \
1561 TestImplAddrCl(Inst, Value0, Count, Op, Type, Size); \
1562 } while (0)
1563
1564 #define TestImplThreeOperandOp(Inst, Dst, Value0, Src, Value1, Count, Op0, \
1565 Op1, Type, Size) \
1566 do { \
1567 static_assert(GPRRegister::Encoded_Reg_##Dst != \
1568 GPRRegister::Encoded_Reg_ecx, \
1569 "ecx should not be specified as Dst"); \
1570 static_assert(GPRRegister::Encoded_Reg_##Src != \
1571 GPRRegister::Encoded_Reg_ecx, \
1572 "ecx should not be specified as Src"); \
1573 TestImplRegRegImm(Inst, Dst, Value0, Src, Value1, Count, Op0, Op1, Type, \
1574 Size); \
1575 TestImplRegRegCl(Inst, Dst, Value0, Src, Value1, Count, Op0, Op1, Type, \
1576 Size); \
1577 TestImplAddrRegCl(Inst, Value0, Src, Value1, Count, Op0, Op1, Type, Size); \
1578 } while (0)
1579
1580 #define TestImplValue(Dst, Value0, Count, Size) \
1581 do { \
1582 TestImplOp(rol, Dst, Value0, Count, <<, uint, Size); \
1583 TestImplOp(shl, Dst, Value0, Count, <<, uint, Size); \
1584 TestImplOp(shr, Dst, Value0, Count, >>, uint, Size); \
1585 TestImplOp(sar, Dst, Value0, Count, >>, int, Size); \
1586 } while (0)
1587
1588 #define TestImplThreeOperandValue(Dst, Value0, Src, Value1, Count, Size) \
1589 do { \
1590 TestImplThreeOperandOp(shld, Dst, Value0, Src, Value1, Count, <<, >>, \
1591 uint, Size); \
1592 TestImplThreeOperandOp(shrd, Dst, Value0, Src, Value1, Count, >>, <<, \
1593 uint, Size); \
1594 } while (0)
1595
1596 #define TestImplSize(Dst, Size) \
1597 do { \
1598 TestImplValue(Dst, 0x8F, 3, Size); \
1599 TestImplValue(Dst, 0x8FFF, 7, Size); \
1600 TestImplValue(Dst, 0x8FFFF, 7, Size); \
1601 } while (0)
1602
1603 #define TestImplThreeOperandSize(Dst, Src, Size) \
1604 do { \
1605 TestImplThreeOperandValue(Dst, 0xFFF3, Src, 0xA000, 8, Size); \
1606 } while (0)
1607
1608 #define TestImpl(Dst, Src) \
1609 do { \
1610 if (GPRRegister::Encoded_Reg_##Dst < 4) { \
1611 TestImplSize(Dst, 8); \
1612 } \
1613 TestImplSize(Dst, 16); \
1614 TestImplThreeOperandSize(Dst, Src, 16); \
1615 TestImplSize(Dst, 32); \
1616 TestImplThreeOperandSize(Dst, Src, 32); \
1617 } while (0)
1618
1619 TestImpl(eax, ebx);
1620 TestImpl(ebx, edx);
1621 TestImpl(edx, esi);
1622 TestImpl(esi, edi);
1623 TestImpl(edi, eax);
1624
1625 #undef TestImpl
1626 #undef TestImplThreeOperandSize
1627 #undef TestImplSize
1628 #undef TestImplValue
1629 #undef TestImplThreeOperandValue
1630 #undef TestImplOp
1631 #undef TestImplThreeOperandOp
1632 #undef TestImplAddrCl
1633 #undef TestImplRegRegCl
1634 #undef TestImplRegCl
1635 #undef TestImplRegRegImm
1636 #undef TestImplRegImm
1637 }
1638
TEST_F(AssemblerX8632Test,Neg)1639 TEST_F(AssemblerX8632Test, Neg) {
1640 static constexpr uint32_t Mask8 = 0x000000ff;
1641 static constexpr uint32_t Mask16 = 0x0000ffff;
1642 static constexpr uint32_t Mask32 = 0xffffffff;
1643
1644 #define TestImplReg(Dst, Size) \
1645 do { \
1646 static constexpr int32_t Value = 0xFF00A543; \
1647 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1648 Immediate(static_cast<int##Size##_t>(Value) & Mask##Size)); \
1649 __ neg(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst); \
1650 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_eax, \
1651 GPRRegister::Encoded_Reg_##Dst); \
1652 __ And(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(Mask##Size)); \
1653 \
1654 AssembledTest test = assemble(); \
1655 test.run(); \
1656 \
1657 ASSERT_EQ(1 + (~static_cast<int##Size##_t>(Value) & Mask##Size), \
1658 test.eax()) \
1659 << "(" #Dst ", " #Size ")"; \
1660 reset(); \
1661 } while (0)
1662
1663 #define TestImplAddr(Size) \
1664 do { \
1665 static constexpr int32_t Value = 0xFF00A543; \
1666 const uint32_t T0 = allocateDword(); \
1667 __ neg(IceType_i##Size, dwordAddress(T0)); \
1668 \
1669 AssembledTest test = assemble(); \
1670 test.setDwordTo(T0, Value &Mask##Size); \
1671 test.run(); \
1672 \
1673 ASSERT_EQ(1 + (~static_cast<int##Size##_t>(Value) & Mask##Size), \
1674 test.contentsOfDword(T0)) \
1675 << "(Addr, " #Size ")"; \
1676 reset(); \
1677 } while (0)
1678
1679 #define TestImpl(Size) \
1680 do { \
1681 TestImplAddr(Size); \
1682 TestImplReg(eax, Size); \
1683 TestImplReg(ebx, Size); \
1684 TestImplReg(ecx, Size); \
1685 TestImplReg(edx, Size); \
1686 TestImplReg(esi, Size); \
1687 TestImplReg(edi, Size); \
1688 } while (0)
1689
1690 TestImpl(8);
1691 TestImpl(16);
1692 TestImpl(32);
1693
1694 #undef TestImpl
1695 #undef TestImplAddr
1696 #undef TestImplReg
1697 }
1698
TEST_F(AssemblerX8632Test,Not)1699 TEST_F(AssemblerX8632Test, Not) {
1700 #define TestImpl(Dst) \
1701 do { \
1702 static constexpr uint32_t Value = 0xFF00A543; \
1703 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dst, Immediate(Value)); \
1704 __ notl(GPRRegister::Encoded_Reg_##Dst); \
1705 \
1706 AssembledTest test = assemble(); \
1707 test.run(); \
1708 \
1709 ASSERT_EQ(~Value, test.Dst()) << "(" #Dst ")"; \
1710 reset(); \
1711 } while (0)
1712
1713 TestImpl(eax);
1714 TestImpl(ebx);
1715 TestImpl(ecx);
1716 TestImpl(edx);
1717 TestImpl(esi);
1718 TestImpl(edi);
1719
1720 #undef TestImpl
1721 }
1722
TEST_F(AssemblerX8632Test,Bswap)1723 TEST_F(AssemblerX8632Test, Bswap) {
1724 #define TestImpl(Dst) \
1725 do { \
1726 static constexpr uint32_t Value = 0xFF00A543; \
1727 static constexpr uint32_t Expected = 0x43A500FF; \
1728 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dst, Immediate(Value)); \
1729 __ bswap(IceType_i32, GPRRegister::Encoded_Reg_##Dst); \
1730 \
1731 AssembledTest test = assemble(); \
1732 test.run(); \
1733 \
1734 ASSERT_EQ(Expected, test.Dst()) << "(" #Dst ")"; \
1735 reset(); \
1736 } while (0)
1737
1738 TestImpl(eax);
1739 TestImpl(ebx);
1740 TestImpl(ecx);
1741 TestImpl(edx);
1742 TestImpl(esi);
1743 TestImpl(edi);
1744
1745 #undef TestImpl
1746 }
1747
TEST_F(AssemblerX8632Test,Bt)1748 TEST_F(AssemblerX8632Test, Bt) {
1749 #define TestImpl(Dst, Value0, Src, Value1) \
1750 do { \
1751 static constexpr char TestString[] = \
1752 "(" #Dst ", " #Value0 ", " #Src ", " #Value1 ")"; \
1753 static constexpr uint32_t Expected = ((Value0) & (1u << (Value1))) != 0; \
1754 \
1755 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dst, Immediate(Value0)); \
1756 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Src, Immediate(Value1)); \
1757 __ bt(GPRRegister::Encoded_Reg_##Dst, GPRRegister::Encoded_Reg_##Src); \
1758 __ setcc(Cond::Br_b, ByteRegister::Encoded_8_Reg_al); \
1759 __ And(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(0xFFu)); \
1760 \
1761 AssembledTest test = assemble(); \
1762 test.run(); \
1763 \
1764 ASSERT_EQ(Expected, test.eax()) << TestString; \
1765 reset(); \
1766 } while (0)
1767
1768 TestImpl(eax, 0x08000000, ebx, 27u);
1769 TestImpl(ebx, 0x08000000, ecx, 23u);
1770 TestImpl(ecx, 0x00000000, edx, 1u);
1771 TestImpl(edx, 0x08000300, esi, 9u);
1772 TestImpl(esi, 0x08000300, edi, 10u);
1773 TestImpl(edi, 0x7FFFEFFF, eax, 13u);
1774
1775 #undef TestImpl
1776 }
1777
1778 template <uint32_t Value, uint32_t Bits> class BitScanHelper {
1779 BitScanHelper() = delete;
1780
1781 public:
1782 static_assert(Bits == 16 || Bits == 32, "Bits must be 16 or 32");
1783 using ValueType =
1784 typename std::conditional<Bits == 16, uint16_t, uint32_t>::type;
1785
1786 private:
BitIndex(bool Forward,ValueType Index)1787 static constexpr ValueType BitIndex(bool Forward, ValueType Index) {
1788 return (Value == 0)
1789 ? BitScanHelper<Value, Bits>::NoBitSet
1790 : (Value & (1u << Index)
1791 ? Index
1792 : BitIndex(Forward, (Forward ? Index + 1 : Index - 1)));
1793 }
1794
1795 public:
1796 static constexpr ValueType NoBitSet = static_cast<ValueType>(-1);
1797 static constexpr ValueType bsf = BitIndex(/*Forward*/ true, /*Index=*/0);
1798 static constexpr ValueType bsr =
1799 BitIndex(/*Forward*/ false, /*Index=*/Bits - 1);
1800 };
1801
TEST_F(AssemblerX8632Test,BitScanOperations)1802 TEST_F(AssemblerX8632Test, BitScanOperations) {
1803 #define TestImplRegReg(Inst, Dst, Src, Value1, Size) \
1804 do { \
1805 static constexpr char TestString[] = \
1806 "(" #Inst ", " #Dst ", " #Src ", " #Value1 ", " #Size ")"; \
1807 static constexpr uint32_t Expected = BitScanHelper<Value1, Size>::Inst; \
1808 const uint32_t ZeroFlag = allocateDword(); \
1809 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
1810 Immediate(Value1)); \
1811 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1812 GPRRegister::Encoded_Reg_##Src); \
1813 __ setcc(Cond::Br_e, dwordAddress(ZeroFlag)); \
1814 \
1815 AssembledTest test = assemble(); \
1816 test.setDwordTo(ZeroFlag, 0u); \
1817 test.run(); \
1818 \
1819 ASSERT_EQ((Expected == BitScanHelper<Value1, Size>::NoBitSet), \
1820 test.contentsOfDword(ZeroFlag)) \
1821 << TestString; \
1822 if ((Expected != BitScanHelper<Value1, Size>::NoBitSet)) { \
1823 ASSERT_EQ(Expected, test.Dst()) << TestString; \
1824 } \
1825 reset(); \
1826 } while (0)
1827
1828 #define TestImplRegAddr(Inst, Dst, Value1, Size) \
1829 do { \
1830 static constexpr char TestString[] = \
1831 "(" #Inst ", " #Dst ", Addr, " #Value1 ", " #Size ")"; \
1832 static constexpr uint32_t Expected = BitScanHelper<Value1, Size>::Inst; \
1833 const uint32_t T0 = allocateDword(); \
1834 const uint32_t ZeroFlag = allocateDword(); \
1835 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
1836 dwordAddress(T0)); \
1837 __ setcc(Cond::Br_e, dwordAddress(ZeroFlag)); \
1838 \
1839 AssembledTest test = assemble(); \
1840 test.setDwordTo(T0, Value1); \
1841 test.setDwordTo(ZeroFlag, 0u); \
1842 test.run(); \
1843 \
1844 ASSERT_EQ((Expected == BitScanHelper<Value1, Size>::NoBitSet), \
1845 test.contentsOfDword(ZeroFlag)) \
1846 << TestString; \
1847 if (Expected != BitScanHelper<Value1, Size>::NoBitSet) { \
1848 ASSERT_EQ(Expected, test.Dst()) << TestString; \
1849 } \
1850 reset(); \
1851 } while (0)
1852
1853 #define TestImplSize(Dst, Src, Value1, Size) \
1854 do { \
1855 TestImplRegReg(bsf, Dst, Src, Value1, Size); \
1856 TestImplRegAddr(bsf, Dst, Value1, Size); \
1857 TestImplRegReg(bsr, Dst, Src, Value1, Size); \
1858 TestImplRegAddr(bsf, Dst, Value1, Size); \
1859 } while (0)
1860
1861 #define TestImplValue(Dst, Src, Value1) \
1862 do { \
1863 TestImplSize(Dst, Src, Value1, 16); \
1864 TestImplSize(Dst, Src, Value1, 32); \
1865 } while (0)
1866
1867 #define TestImpl(Dst, Src) \
1868 do { \
1869 TestImplValue(Dst, Src, 0x80000001); \
1870 TestImplValue(Dst, Src, 0x00000000); \
1871 TestImplValue(Dst, Src, 0x80001000); \
1872 TestImplValue(Dst, Src, 0x00FFFF00); \
1873 } while (0)
1874
1875 TestImpl(eax, ebx);
1876 TestImpl(ebx, ecx);
1877 TestImpl(ecx, edx);
1878 TestImpl(edx, esi);
1879 TestImpl(esi, edi);
1880 TestImpl(edi, eax);
1881
1882 #undef TestImpl
1883 #undef TestImplValue
1884 #undef TestImplSize
1885 #undef TestImplRegAddr
1886 #undef TestImplRegReg
1887 }
1888
1889 } // end of anonymous namespace
1890 } // end of namespace Test
1891 } // end of namespace X8632
1892 } // end of namespace Ice
1893