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