1 //===- subzero/unittest/AssemblerX8632/Locked.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,Mfence)16 TEST_F(AssemblerX8632LowLevelTest, Mfence) {
17 __ mfence();
18
19 static constexpr uint8_t ByteCount = 3;
20 ASSERT_EQ(ByteCount, codeBytesSize());
21 verifyBytes<ByteCount>(codeBytes(), 0x0F, 0xAE, 0xF0);
22 }
23
TEST_F(AssemblerX8632LowLevelTest,Lock)24 TEST_F(AssemblerX8632LowLevelTest, Lock) {
25 __ lock();
26
27 static constexpr uint8_t ByteCount = 1;
28 ASSERT_EQ(ByteCount, codeBytesSize());
29 verifyBytes<ByteCount>(codeBytes(), 0xF0);
30 }
31
TEST_F(AssemblerX8632Test,Xchg)32 TEST_F(AssemblerX8632Test, Xchg) {
33 static constexpr uint32_t Mask8 = 0x000000FF;
34 static constexpr uint32_t Mask16 = 0x0000FFFF;
35 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
36
37 #define TestImplAddrReg(Value0, Dst1, Value1, Size) \
38 do { \
39 static constexpr char TestString[] = \
40 "(" #Value0 ", " #Dst1 ", " #Value1 ", " #Size ")"; \
41 const uint32_t T0 = allocateDword(); \
42 const uint32_t V0 = (Value0)&Mask##Size; \
43 const uint32_t V1 = (Value1)&Mask##Size; \
44 \
45 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst1, \
46 Immediate(Value1)); \
47 __ xchg(IceType_i##Size, dwordAddress(T0), \
48 GPRRegister::Encoded_Reg_##Dst1); \
49 __ And(IceType_i32, GPRRegister::Encoded_Reg_##Dst1, \
50 Immediate(Mask##Size)); \
51 \
52 AssembledTest test = assemble(); \
53 test.setDwordTo(T0, V0); \
54 test.run(); \
55 \
56 ASSERT_EQ(V0, test.Dst1()) << TestString; \
57 ASSERT_EQ(V1, test.contentsOfDword(T0)) << TestString; \
58 reset(); \
59 } while (0)
60
61 #define TestImplSize(Dst1, Size) \
62 do { \
63 TestImplAddrReg(0xa2b34567, Dst1, 0x0507ddee, Size); \
64 } while (0)
65
66 #define TestImpl(Dst1) \
67 do { \
68 if (GPRRegister::Encoded_Reg_##Dst1 < 4) { \
69 TestImplSize(Dst1, 8); \
70 } \
71 TestImplSize(Dst1, 16); \
72 TestImplSize(Dst1, 32); \
73 } while (0)
74
75 TestImpl(eax);
76 TestImpl(ebx);
77 TestImpl(ecx);
78 TestImpl(edx);
79 TestImpl(esi);
80 TestImpl(edi);
81
82 #undef TestImpl
83 #undef TestImplSize
84 #undef TestImplAddrReg
85
86 #define TestImplRegReg(Reg0, Value0, Reg1, Value1, Size) \
87 do { \
88 static constexpr char TestString[] = \
89 "(" #Reg0 "," #Value0 ", " #Reg1 ", " #Value1 ", " #Size ")"; \
90 const uint32_t V0 = (Value0)&Mask##Size; \
91 const uint32_t V1 = (Value1)&Mask##Size; \
92 \
93 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Reg0, \
94 Immediate(Value0)); \
95 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Reg1, \
96 Immediate(Value1)); \
97 __ xchg(IceType_i##Size, GPRRegister::Encoded_Reg_##Reg0, \
98 GPRRegister::Encoded_Reg_##Reg1); \
99 __ And(IceType_i32, GPRRegister::Encoded_Reg_##Reg0, \
100 Immediate(Mask##Size)); \
101 __ And(IceType_i32, GPRRegister::Encoded_Reg_##Reg1, \
102 Immediate(Mask##Size)); \
103 \
104 AssembledTest test = assemble(); \
105 test.run(); \
106 \
107 ASSERT_EQ(V0, test.Reg1()) << TestString; \
108 ASSERT_EQ(V1, test.Reg0()) << TestString; \
109 reset(); \
110 } while (0)
111
112 #define TestImplSize(Reg0, Reg1, Size) \
113 do { \
114 TestImplRegReg(Reg0, 0xa2b34567, Reg1, 0x0507ddee, Size); \
115 } while (0)
116
117 #define TestImpl(Reg0, Reg1) \
118 do { \
119 if (GPRRegister::Encoded_Reg_##Reg0 < 4 && \
120 GPRRegister::Encoded_Reg_##Reg1 < 4) { \
121 TestImplSize(Reg0, Reg1, 8); \
122 } \
123 TestImplSize(Reg0, Reg1, 16); \
124 TestImplSize(Reg0, Reg1, 32); \
125 } while (0)
126
127 TestImpl(eax, ebx);
128 TestImpl(edx, eax);
129 TestImpl(ecx, edx);
130 TestImpl(esi, eax);
131 TestImpl(edx, edi);
132
133 #undef TestImpl
134 #undef TestImplSize
135 #undef TestImplRegReg
136 }
137
TEST_F(AssemblerX8632Test,Xadd)138 TEST_F(AssemblerX8632Test, Xadd) {
139 static constexpr bool NotLocked = false;
140 static constexpr bool Locked = true;
141
142 static constexpr uint32_t Mask8 = 0x000000FF;
143 static constexpr uint32_t Mask16 = 0x0000FFFF;
144 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
145
146 #define TestImplAddrReg(Value0, Dst1, Value1, LockedOrNot, Size) \
147 do { \
148 static constexpr char TestString[] = \
149 "(" #Value0 ", " #Dst1 ", " #Value1 ", " #Size ")"; \
150 const uint32_t T0 = allocateDword(); \
151 const uint32_t V0 = (Value0)&Mask##Size; \
152 const uint32_t V1 = (Value1)&Mask##Size; \
153 \
154 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst1, \
155 Immediate(Value1)); \
156 __ xadd(IceType_i##Size, dwordAddress(T0), \
157 GPRRegister::Encoded_Reg_##Dst1, LockedOrNot); \
158 __ And(IceType_i32, GPRRegister::Encoded_Reg_##Dst1, \
159 Immediate(Mask##Size)); \
160 \
161 AssembledTest test = assemble(); \
162 test.setDwordTo(T0, V0); \
163 test.run(); \
164 \
165 ASSERT_EQ(V0, test.Dst1()) << TestString; \
166 ASSERT_EQ(Mask##Size &(V1 + V0), test.contentsOfDword(T0)) << TestString; \
167 reset(); \
168 } while (0)
169
170 #define TestImplSize(Dst1, Size) \
171 do { \
172 TestImplAddrReg(0xa2b34567, Dst1, 0x0507ddee, NotLocked, Size); \
173 TestImplAddrReg(0xa2b34567, Dst1, 0x0507ddee, Locked, Size); \
174 } while (0)
175
176 #define TestImpl(Dst1) \
177 do { \
178 if (GPRRegister::Encoded_Reg_##Dst1 < 4) { \
179 TestImplSize(Dst1, 8); \
180 } \
181 TestImplSize(Dst1, 16); \
182 TestImplSize(Dst1, 32); \
183 } while (0)
184
185 TestImpl(eax);
186 TestImpl(ebx);
187 TestImpl(ecx);
188 TestImpl(edx);
189 TestImpl(esi);
190 TestImpl(edi);
191
192 #undef TestImpl
193 #undef TestImplSize
194 #undef TestImplAddrReg
195 }
196
TEST_F(AssemblerX8632LowLevelTest,Xadd)197 TEST_F(AssemblerX8632LowLevelTest, Xadd) {
198 static constexpr bool NotLocked = false;
199 static constexpr bool Locked = true;
200
201 // Ensures that xadd emits a lock prefix accordingly.
202 {
203 __ xadd(IceType_i8, Address(0x1FF00, AssemblerFixup::NoFixup),
204 GPRRegister::Encoded_Reg_esi, NotLocked);
205 static constexpr uint8_t ByteCountNotLocked8 = 7;
206 ASSERT_EQ(ByteCountNotLocked8, codeBytesSize());
207 verifyBytes<ByteCountNotLocked8>(codeBytes(), 0x0F, 0xC0, 0x35, 0x00, 0xFF,
208 0x01, 0x00);
209 reset();
210
211 __ xadd(IceType_i8, Address(0x1FF00, AssemblerFixup::NoFixup),
212 GPRRegister::Encoded_Reg_esi, Locked);
213 static constexpr uint8_t ByteCountLocked8 = 1 + ByteCountNotLocked8;
214 ASSERT_EQ(ByteCountLocked8, codeBytesSize());
215 verifyBytes<ByteCountLocked8>(codeBytes(), 0xF0, 0x0F, 0xC0, 0x35, 0x00,
216 0xFF, 0x01, 0x00);
217 reset();
218 }
219
220 {
221 __ xadd(IceType_i16, Address(0x1FF00, AssemblerFixup::NoFixup),
222 GPRRegister::Encoded_Reg_esi, NotLocked);
223 static constexpr uint8_t ByteCountNotLocked16 = 8;
224 ASSERT_EQ(ByteCountNotLocked16, codeBytesSize());
225 verifyBytes<ByteCountNotLocked16>(codeBytes(), 0x66, 0x0F, 0xC1, 0x35, 0x00,
226 0xFF, 0x01, 0x00);
227 reset();
228
229 __ xadd(IceType_i16, Address(0x1FF00, AssemblerFixup::NoFixup),
230 GPRRegister::Encoded_Reg_esi, Locked);
231 static constexpr uint8_t ByteCountLocked16 = 1 + ByteCountNotLocked16;
232 ASSERT_EQ(ByteCountLocked16, codeBytesSize());
233 verifyBytes<ByteCountLocked16>(codeBytes(), 0x66, 0xF0, 0x0F, 0xC1, 0x35,
234 0x00, 0xFF, 0x01, 0x00);
235 reset();
236 }
237
238 {
239 __ xadd(IceType_i32, Address(0x1FF00, AssemblerFixup::NoFixup),
240 GPRRegister::Encoded_Reg_esi, NotLocked);
241 static constexpr uint8_t ByteCountNotLocked32 = 7;
242 ASSERT_EQ(ByteCountNotLocked32, codeBytesSize());
243 verifyBytes<ByteCountNotLocked32>(codeBytes(), 0x0F, 0xC1, 0x35, 0x00, 0xFF,
244 0x01, 0x00);
245 reset();
246
247 __ xadd(IceType_i32, Address(0x1FF00, AssemblerFixup::NoFixup),
248 GPRRegister::Encoded_Reg_esi, Locked);
249 static constexpr uint8_t ByteCountLocked32 = 1 + ByteCountNotLocked32;
250 ASSERT_EQ(ByteCountLocked32, codeBytesSize());
251 verifyBytes<ByteCountLocked32>(codeBytes(), 0xF0, 0x0F, 0xC1, 0x35, 0x00,
252 0xFF, 0x01, 0x00);
253 reset();
254 }
255 }
256
TEST_F(AssemblerX8632Test,Cmpxchg8b)257 TEST_F(AssemblerX8632Test, Cmpxchg8b) {
258 static constexpr bool NotLocked = false;
259 static constexpr bool Locked = true;
260
261 #define TestImpl(Value0, Value1, ValueMem, LockedOrNot) \
262 do { \
263 static constexpr char TestString[] = \
264 "(" #Value0 ", " #Value1 ", " #ValueMem ", " #LockedOrNot ")"; \
265 const uint32_t T0 = allocateQword(); \
266 static constexpr uint64_t V0 = ValueMem; \
267 const uint32_t ZeroFlag = allocateDword(); \
268 \
269 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, \
270 Immediate(uint64_t(Value0) & 0xFFFFFFFF)); \
271 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edx, \
272 Immediate(uint64_t(Value0) >> 32)); \
273 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ebx, \
274 Immediate(uint64_t(Value1) & 0xFFFFFFFF)); \
275 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ecx, \
276 Immediate(uint64_t(Value1) >> 32)); \
277 __ cmpxchg8b(dwordAddress(T0), LockedOrNot); \
278 __ setcc(Cond::Br_e, dwordAddress(ZeroFlag)); \
279 \
280 AssembledTest test = assemble(); \
281 test.setQwordTo(T0, V0); \
282 test.setDwordTo(ZeroFlag, uint32_t(0xFF)); \
283 test.run(); \
284 \
285 if (V0 == (Value0)) { \
286 ASSERT_EQ(uint64_t(Value1), test.contentsOfQword(T0)) << TestString; \
287 ASSERT_EQ(1u, test.contentsOfDword(ZeroFlag)) << TestString; \
288 } else { \
289 ASSERT_EQ(uint64_t(ValueMem) & 0xFFFFFFFF, test.eax()) << TestString; \
290 ASSERT_EQ((uint64_t(ValueMem) >> 32) & 0xFFFFFFFF, test.edx()) \
291 << TestString; \
292 ASSERT_EQ(0u, test.contentsOfDword(ZeroFlag)) << TestString; \
293 } \
294 reset(); \
295 } while (0)
296
297 TestImpl(0x98987676543210ull, 0x1, 0x98987676543210ull, NotLocked);
298 TestImpl(0x98987676543210ull, 0x1, 0x98987676543210ull, Locked);
299 TestImpl(0x98987676543210ull, 0x1, 0x98987676543211ull, NotLocked);
300 TestImpl(0x98987676543210ull, 0x1, 0x98987676543211ull, Locked);
301
302 #undef TestImpl
303 }
304
TEST_F(AssemblerX8632LowLevelTest,Cmpxchg8b)305 TEST_F(AssemblerX8632LowLevelTest, Cmpxchg8b) {
306 static constexpr bool NotLocked = false;
307 static constexpr bool Locked = true;
308
309 // Ensures that cmpxchg8b emits a lock prefix accordingly.
310 __ cmpxchg8b(Address(0x1FF00, AssemblerFixup::NoFixup), NotLocked);
311 static constexpr uint8_t ByteCountNotLocked = 7;
312 ASSERT_EQ(ByteCountNotLocked, codeBytesSize());
313 verifyBytes<ByteCountNotLocked>(codeBytes(), 0x0F, 0xC7, 0x0D, 0x00, 0xFF,
314 0x01, 0x00);
315 reset();
316
317 __ cmpxchg8b(Address(0x1FF00, AssemblerFixup::NoFixup), Locked);
318 static constexpr uint8_t ByteCountLocked = 1 + ByteCountNotLocked;
319 ASSERT_EQ(ByteCountLocked, codeBytesSize());
320 verifyBytes<ByteCountLocked>(codeBytes(), 0xF0, 0x0F, 0xC7, 0x0D, 0x00, 0xFF,
321 0x01, 0x00);
322 reset();
323 }
324
TEST_F(AssemblerX8632Test,Cmpxchg)325 TEST_F(AssemblerX8632Test, Cmpxchg) {
326 static constexpr bool NotLocked = false;
327 static constexpr bool Locked = true;
328
329 static constexpr uint32_t Mask8 = 0x000000FF;
330 static constexpr uint32_t Mask16 = 0x0000FFFF;
331 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
332
333 #define TestImplAddrReg(Value0, Src, Value1, ValueMem, LockedOrNot, Size) \
334 do { \
335 static constexpr char TestString[] = \
336 "(" #Value0 ", " #Src ", " #Value1 ", " #ValueMem ", " #LockedOrNot \
337 ", " #Size ")"; \
338 const uint32_t T0 = allocateDword(); \
339 static constexpr uint32_t V0 = (ValueMem)&Mask##Size; \
340 const uint32_t ZeroFlag = allocateDword(); \
341 \
342 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_eax, \
343 Immediate((Value0)&Mask##Size)); \
344 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
345 Immediate((Value1)&Mask##Size)); \
346 __ cmpxchg(IceType_i##Size, dwordAddress(T0), \
347 GPRRegister::Encoded_Reg_##Src, LockedOrNot); \
348 __ setcc(Cond::Br_e, dwordAddress(ZeroFlag)); \
349 \
350 AssembledTest test = assemble(); \
351 test.setDwordTo(T0, V0); \
352 test.setDwordTo(ZeroFlag, uint32_t(0xFF)); \
353 test.run(); \
354 \
355 if (V0 == (Mask##Size & (Value0))) { \
356 ASSERT_EQ(uint32_t((Value1)&Mask##Size), test.contentsOfDword(T0)) \
357 << TestString; \
358 ASSERT_EQ(1u, test.contentsOfDword(ZeroFlag)) << TestString; \
359 } else { \
360 ASSERT_EQ(uint32_t((ValueMem)&Mask##Size), test.eax()) << TestString; \
361 ASSERT_EQ(0u, test.contentsOfDword(ZeroFlag)) << TestString; \
362 } \
363 reset(); \
364 } while (0)
365
366 #define TestImplValue(Value0, Src, Value1, ValueMem, LockedOrNot) \
367 do { \
368 if (GPRRegister::Encoded_Reg_##Src < 4) { \
369 TestImplAddrReg(Value0, Src, Value1, ValueMem, LockedOrNot, 8); \
370 } \
371 TestImplAddrReg(Value0, Src, Value1, ValueMem, LockedOrNot, 16); \
372 TestImplAddrReg(Value0, Src, Value1, ValueMem, LockedOrNot, 32); \
373 } while (0)
374
375 #define TestImpl(Src, LockedOrNot) \
376 do { \
377 TestImplValue(0xFFFFFFFF, Src, 0x1, 0xFFFFFFFF, LockedOrNot); \
378 TestImplValue(0x0FFF0F0F, Src, 0x1, 0xFFFFFFFF, LockedOrNot); \
379 } while (0)
380
381 TestImpl(ebx, Locked);
382 TestImpl(edx, NotLocked);
383 TestImpl(ecx, Locked);
384 TestImpl(ecx, NotLocked);
385 TestImpl(edx, Locked);
386 TestImpl(edx, NotLocked);
387 TestImpl(esi, Locked);
388 TestImpl(esi, NotLocked);
389 TestImpl(edi, Locked);
390 TestImpl(edi, NotLocked);
391
392 #undef TestImpl
393 #undef TestImplValue
394 #undef TestImplAddrReg
395 }
396
TEST_F(AssemblerX8632LowLevelTest,Cmpxchg)397 TEST_F(AssemblerX8632LowLevelTest, Cmpxchg) {
398 static constexpr bool NotLocked = false;
399 static constexpr bool Locked = true;
400
401 // Ensures that cmpxchg emits a lock prefix accordingly.
402 {
403 __ cmpxchg(IceType_i8, Address(0x1FF00, AssemblerFixup::NoFixup),
404 GPRRegister::Encoded_Reg_esi, NotLocked);
405 static constexpr uint8_t ByteCountNotLocked8 = 7;
406 ASSERT_EQ(ByteCountNotLocked8, codeBytesSize());
407 verifyBytes<ByteCountNotLocked8>(codeBytes(), 0x0F, 0xB0, 0x35, 0x00, 0xFF,
408 0x01, 0x00);
409 reset();
410
411 __ cmpxchg(IceType_i8, Address(0x1FF00, AssemblerFixup::NoFixup),
412 GPRRegister::Encoded_Reg_esi, Locked);
413 static constexpr uint8_t ByteCountLocked8 = 1 + ByteCountNotLocked8;
414 ASSERT_EQ(ByteCountLocked8, codeBytesSize());
415 verifyBytes<ByteCountLocked8>(codeBytes(), 0xF0, 0x0F, 0xB0, 0x35, 0x00,
416 0xFF, 0x01, 0x00);
417 reset();
418 }
419
420 {
421 __ cmpxchg(IceType_i16, Address(0x1FF00, AssemblerFixup::NoFixup),
422 GPRRegister::Encoded_Reg_esi, NotLocked);
423 static constexpr uint8_t ByteCountNotLocked16 = 8;
424 ASSERT_EQ(ByteCountNotLocked16, codeBytesSize());
425 verifyBytes<ByteCountNotLocked16>(codeBytes(), 0x66, 0x0F, 0xB1, 0x35, 0x00,
426 0xFF, 0x01, 0x00);
427 reset();
428
429 __ cmpxchg(IceType_i16, Address(0x1FF00, AssemblerFixup::NoFixup),
430 GPRRegister::Encoded_Reg_esi, Locked);
431 static constexpr uint8_t ByteCountLocked16 = 1 + ByteCountNotLocked16;
432 ASSERT_EQ(ByteCountLocked16, codeBytesSize());
433 verifyBytes<ByteCountLocked16>(codeBytes(), 0x66, 0xF0, 0x0F, 0xB1, 0x35,
434 0x00, 0xFF, 0x01, 0x00);
435 reset();
436 }
437
438 {
439 __ cmpxchg(IceType_i32, Address(0x1FF00, AssemblerFixup::NoFixup),
440 GPRRegister::Encoded_Reg_esi, NotLocked);
441 static constexpr uint8_t ByteCountNotLocked32 = 7;
442 ASSERT_EQ(ByteCountNotLocked32, codeBytesSize());
443 verifyBytes<ByteCountNotLocked32>(codeBytes(), 0x0F, 0xB1, 0x35, 0x00, 0xFF,
444 0x01, 0x00);
445 reset();
446
447 __ cmpxchg(IceType_i32, Address(0x1FF00, AssemblerFixup::NoFixup),
448 GPRRegister::Encoded_Reg_esi, Locked);
449 static constexpr uint8_t ByteCountLocked32 = 1 + ByteCountNotLocked32;
450 ASSERT_EQ(ByteCountLocked32, codeBytesSize());
451 verifyBytes<ByteCountLocked32>(codeBytes(), 0xF0, 0x0F, 0xB1, 0x35, 0x00,
452 0xFF, 0x01, 0x00);
453 reset();
454 }
455 }
456
457 } // end of anonymous namespace
458 } // end of namespace Test
459 } // end of namespace X8632
460 } // end of namespace Ice
461