Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(255)

Side by Side Diff: unittest/AssemblerX8632/GPRArith.cpp

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

Powered by Google App Engine
This is Rietveld 408576698