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