1 //===- subzero/unittest/AssemblerX8664/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 "AssemblerX8664/TestUtil.h"
10
11 namespace Ice {
12 namespace X8664 {
13 namespace Test {
14 namespace {
15
TEST_F(AssemblerX8664LowLevelTest,Mfence)16 TEST_F(AssemblerX8664LowLevelTest, 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(AssemblerX8664LowLevelTest,Lock)24 TEST_F(AssemblerX8664LowLevelTest, 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(AssemblerX8664Test,Xchg)32 TEST_F(AssemblerX8664Test, 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, Encoded_GPR_##Dst1(), Immediate(Value1)); \
46 __ xchg(IceType_i##Size, dwordAddress(T0), Encoded_GPR_##Dst1()); \
47 __ And(IceType_i32, Encoded_GPR_##Dst1(), Immediate(Mask##Size)); \
48 \
49 AssembledTest test = assemble(); \
50 test.setDwordTo(T0, V0); \
51 test.run(); \
52 \
53 ASSERT_EQ(V0, test.Dst1()) << TestString; \
54 ASSERT_EQ(V1, test.contentsOfDword(T0)) << TestString; \
55 reset(); \
56 } while (0)
57
58 #define TestImplSize(Dst1, Size) \
59 do { \
60 TestImplAddrReg(0xa2b34567, Dst1, 0x0507ddee, Size); \
61 } while (0)
62
63 #define TestImpl(Dst1) \
64 do { \
65 TestImplSize(Dst1, 8); \
66 TestImplSize(Dst1, 16); \
67 TestImplSize(Dst1, 32); \
68 } while (0)
69
70 TestImpl(r1);
71 TestImpl(r2);
72 TestImpl(r3);
73 TestImpl(r4);
74 TestImpl(r5);
75 TestImpl(r6);
76 TestImpl(r7);
77 TestImpl(r8);
78 TestImpl(r10);
79 TestImpl(r11);
80 TestImpl(r12);
81 TestImpl(r13);
82 TestImpl(r14);
83 TestImpl(r15);
84
85 #undef TestImpl
86 #undef TestImplSize
87 #undef TestImplAddrReg
88
89 #define TestImplRegReg(Reg0, Value0, Reg1, Value1, Size) \
90 do { \
91 static constexpr char TestString[] = \
92 "(" #Reg0 "," #Value0 ", " #Reg1 ", " #Value1 ", " #Size ")"; \
93 const uint32_t V0 = (Value0)&Mask##Size; \
94 const uint32_t V1 = (Value1)&Mask##Size; \
95 \
96 __ mov(IceType_i##Size, Encoded_GPR_##Reg0(), Immediate(Value0)); \
97 __ mov(IceType_i##Size, Encoded_GPR_##Reg1(), Immediate(Value1)); \
98 __ xchg(IceType_i##Size, Encoded_GPR_##Reg0(), Encoded_GPR_##Reg1()); \
99 __ And(IceType_i32, Encoded_GPR_##Reg0(), Immediate(Mask##Size)); \
100 __ And(IceType_i32, Encoded_GPR_##Reg1(), Immediate(Mask##Size)); \
101 \
102 AssembledTest test = assemble(); \
103 test.run(); \
104 \
105 ASSERT_EQ(V0, test.Reg1()) << TestString; \
106 ASSERT_EQ(V1, test.Reg0()) << TestString; \
107 reset(); \
108 } while (0)
109
110 #define TestImplSize(Reg0, Reg1, Size) \
111 do { \
112 TestImplRegReg(Reg0, 0xa2b34567, Reg1, 0x0507ddee, Size); \
113 } while (0)
114
115 #define TestImpl(Reg0, Reg1) \
116 do { \
117 TestImplSize(Reg0, Reg1, 8); \
118 TestImplSize(Reg0, Reg1, 16); \
119 TestImplSize(Reg0, Reg1, 32); \
120 } while (0)
121
122 // r1 == rax so has a short encoding
123 TestImpl(r6, r1);
124 TestImpl(r1, r8);
125
126 TestImpl(r2, r10);
127 TestImpl(r3, r11);
128 TestImpl(r4, r12);
129 TestImpl(r5, r13);
130 TestImpl(r6, r14);
131 TestImpl(r7, r15);
132
133 #undef TestImpl
134 #undef TestImplSize
135 #undef TestImplRegReg
136 }
137
TEST_F(AssemblerX8664Test,Xadd)138 TEST_F(AssemblerX8664Test, 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, Encoded_GPR_##Dst1(), Immediate(Value1)); \
155 __ xadd(IceType_i##Size, dwordAddress(T0), Encoded_GPR_##Dst1(), \
156 LockedOrNot); \
157 __ And(IceType_i32, Encoded_GPR_##Dst1(), Immediate(Mask##Size)); \
158 \
159 AssembledTest test = assemble(); \
160 test.setDwordTo(T0, V0); \
161 test.run(); \
162 \
163 ASSERT_EQ(V0, test.Dst1()) << TestString; \
164 ASSERT_EQ(Mask##Size &(V1 + V0), test.contentsOfDword(T0)) << TestString; \
165 reset(); \
166 } while (0)
167
168 #define TestImplSize(Dst1, Size) \
169 do { \
170 TestImplAddrReg(0xa2b34567, Dst1, 0x0507ddee, NotLocked, Size); \
171 TestImplAddrReg(0xa2b34567, Dst1, 0x0507ddee, Locked, Size); \
172 } while (0)
173
174 #define TestImpl(Dst1) \
175 do { \
176 TestImplSize(Dst1, 8); \
177 TestImplSize(Dst1, 16); \
178 TestImplSize(Dst1, 32); \
179 } while (0)
180
181 TestImpl(r1);
182 TestImpl(r2);
183 TestImpl(r3);
184 TestImpl(r4);
185 TestImpl(r5);
186 TestImpl(r6);
187 TestImpl(r7);
188 TestImpl(r8);
189 TestImpl(r10);
190 TestImpl(r11);
191 TestImpl(r12);
192 TestImpl(r13);
193 TestImpl(r14);
194 TestImpl(r15);
195
196 #undef TestImpl
197 #undef TestImplSize
198 #undef TestImplAddrReg
199 }
200
TEST_F(AssemblerX8664LowLevelTest,Xadd)201 TEST_F(AssemblerX8664LowLevelTest, Xadd) {
202 static constexpr bool NotLocked = false;
203 static constexpr bool Locked = true;
204
205 // Ensures that xadd emits a lock prefix accordingly.
206 {
207 __ xadd(IceType_i8, Address::Absolute(0x1FF00), Encoded_GPR_r14(),
208 NotLocked);
209 static constexpr uint8_t ByteCountNotLocked8 = 10;
210 ASSERT_EQ(ByteCountNotLocked8, codeBytesSize());
211 ASSERT_TRUE(verifyBytes<ByteCountNotLocked8>(codeBytes(), 0x67, 0x44, 0x0F,
212 0xC0, 0x34, 0x25, 0x00, 0xFF,
213 0x01, 0x00));
214 reset();
215
216 __ xadd(IceType_i8, Address::Absolute(0x1FF00), Encoded_GPR_r14(), Locked);
217 static constexpr uint8_t ByteCountLocked8 = 1 + ByteCountNotLocked8;
218 ASSERT_EQ(ByteCountLocked8, codeBytesSize());
219 ASSERT_TRUE(verifyBytes<ByteCountLocked8>(codeBytes(), 0xF0, 0x67, 0x44,
220 0x0F, 0xC0, 0x34, 0x25, 0x00,
221 0xFF, 0x01, 0x00));
222 reset();
223 }
224
225 {
226 __ xadd(IceType_i16, Address::Absolute(0x1FF00), Encoded_GPR_r14(),
227 NotLocked);
228 static constexpr uint8_t ByteCountNotLocked16 = 11;
229 ASSERT_EQ(ByteCountNotLocked16, codeBytesSize());
230 ASSERT_TRUE(verifyBytes<ByteCountNotLocked16>(codeBytes(), 0x66, 0x67, 0x44,
231 0x0F, 0xC1, 0x34, 0x25, 0x00,
232 0xFF, 0x01, 0x00));
233 reset();
234
235 __ xadd(IceType_i16, Address::Absolute(0x1FF00), Encoded_GPR_r14(), Locked);
236 static constexpr uint8_t ByteCountLocked16 = 1 + ByteCountNotLocked16;
237 ASSERT_EQ(ByteCountLocked16, codeBytesSize());
238 ASSERT_TRUE(verifyBytes<ByteCountLocked16>(codeBytes(), 0x66, 0xF0, 0x67,
239 0x44, 0x0F, 0xC1, 0x34, 0x25,
240 0x00, 0xFF, 0x01, 0x00));
241 reset();
242 }
243
244 {
245 __ xadd(IceType_i32, Address::Absolute(0x1FF00), Encoded_GPR_r14(),
246 NotLocked);
247 static constexpr uint8_t ByteCountNotLocked32 = 10;
248 ASSERT_EQ(ByteCountNotLocked32, codeBytesSize());
249 ASSERT_TRUE(verifyBytes<ByteCountNotLocked32>(codeBytes(), 0x67, 0x44, 0x0F,
250 0xC1, 0x34, 0x25, 0x00, 0xFF,
251 0x01, 0x00));
252 reset();
253
254 __ xadd(IceType_i32, Address::Absolute(0x1FF00), Encoded_GPR_r14(), Locked);
255 static constexpr uint8_t ByteCountLocked32 = 1 + ByteCountNotLocked32;
256 ASSERT_EQ(ByteCountLocked32, codeBytesSize());
257 ASSERT_TRUE(verifyBytes<ByteCountLocked32>(codeBytes(), 0xF0, 0x67, 0x44,
258 0x0F, 0xC1, 0x34, 0x25, 0x00,
259 0xFF, 0x01, 0x00));
260 reset();
261 }
262 }
263
TEST_F(AssemblerX8664LowLevelTest,EmitSegmentOverride)264 TEST_F(AssemblerX8664LowLevelTest, EmitSegmentOverride) {
265 #define TestImpl(Prefix) \
266 do { \
267 static constexpr uint8_t ByteCount = 1; \
268 __ emitSegmentOverride(Prefix); \
269 ASSERT_EQ(ByteCount, codeBytesSize()) << Prefix; \
270 ASSERT_TRUE(verifyBytes<ByteCount>(codeBytes(), Prefix)); \
271 reset(); \
272 } while (0)
273
274 TestImpl(0x26);
275 TestImpl(0x2E);
276 TestImpl(0x36);
277 TestImpl(0x3E);
278 TestImpl(0x64);
279 TestImpl(0x65);
280 TestImpl(0x66);
281 TestImpl(0x67);
282
283 #undef TestImpl
284 }
285
TEST_F(AssemblerX8664Test,Cmpxchg8b)286 TEST_F(AssemblerX8664Test, Cmpxchg8b) {
287 static constexpr bool NotLocked = false;
288 static constexpr bool Locked = true;
289
290 #define TestImpl(Value0, Value1, ValueMem, LockedOrNot) \
291 do { \
292 static constexpr char TestString[] = \
293 "(" #Value0 ", " #Value1 ", " #ValueMem ", " #LockedOrNot ")"; \
294 const uint32_t T0 = allocateQword(); \
295 static constexpr uint64_t V0 = ValueMem; \
296 const uint32_t ZeroFlag = allocateDword(); \
297 \
298 __ mov(IceType_i32, Encoded_GPR_eax(), \
299 Immediate(uint64_t(Value0) & 0xFFFFFFFF)); \
300 __ mov(IceType_i32, Encoded_GPR_edx(), Immediate(uint64_t(Value0) >> 32)); \
301 __ mov(IceType_i32, Encoded_GPR_ebx(), \
302 Immediate(uint64_t(Value1) & 0xFFFFFFFF)); \
303 __ mov(IceType_i32, Encoded_GPR_ecx(), Immediate(uint64_t(Value1) >> 32)); \
304 __ cmpxchg8b(dwordAddress(T0), LockedOrNot); \
305 __ setcc(Cond::Br_e, dwordAddress(ZeroFlag)); \
306 \
307 AssembledTest test = assemble(); \
308 test.setQwordTo(T0, V0); \
309 test.setDwordTo(ZeroFlag, uint32_t(0xFF)); \
310 test.run(); \
311 \
312 if (V0 == (Value0)) { \
313 ASSERT_EQ(uint64_t(Value1), test.contentsOfQword(T0)) << TestString; \
314 ASSERT_EQ(1u, test.contentsOfDword(ZeroFlag)) << TestString; \
315 } else { \
316 ASSERT_EQ(uint64_t(ValueMem) & 0xFFFFFFFF, test.eax()) << TestString; \
317 ASSERT_EQ((uint64_t(ValueMem) >> 32) & 0xFFFFFFFF, test.edx()) \
318 << TestString; \
319 ASSERT_EQ(0u, test.contentsOfDword(ZeroFlag)) << TestString; \
320 } \
321 reset(); \
322 } while (0)
323
324 TestImpl(0x98987676543210ull, 0x1, 0x98987676543210ull, NotLocked);
325 TestImpl(0x98987676543210ull, 0x1, 0x98987676543210ull, Locked);
326 TestImpl(0x98987676543210ull, 0x1, 0x98987676543211ull, NotLocked);
327 TestImpl(0x98987676543210ull, 0x1, 0x98987676543211ull, Locked);
328
329 #undef TestImpl
330 }
331
TEST_F(AssemblerX8664LowLevelTest,Cmpxchg8b)332 TEST_F(AssemblerX8664LowLevelTest, Cmpxchg8b) {
333 static constexpr bool NotLocked = false;
334 static constexpr bool Locked = true;
335
336 // Ensures that cmpxchg8b emits a lock prefix accordingly.
337 __ cmpxchg8b(Address::Absolute(0x1FF00), NotLocked);
338 static constexpr uint8_t ByteCountNotLocked = 9;
339 ASSERT_EQ(ByteCountNotLocked, codeBytesSize());
340 ASSERT_TRUE(verifyBytes<ByteCountNotLocked>(
341 codeBytes(), 0x67, 0x0F, 0xC7, 0x0C, 0x25, 0x00, 0xFF, 0x01, 0x00));
342 reset();
343
344 __ cmpxchg8b(Address::Absolute(0x1FF00), Locked);
345 static constexpr uint8_t ByteCountLocked = 1 + ByteCountNotLocked;
346 ASSERT_EQ(ByteCountLocked, codeBytesSize());
347 ASSERT_TRUE(verifyBytes<ByteCountLocked>(codeBytes(), 0xF0, 0x67, 0x0F, 0xC7,
348 0x0C, 0x25, 0x00, 0xFF, 0x01, 0x00));
349 reset();
350 }
351
TEST_F(AssemblerX8664Test,Cmpxchg)352 TEST_F(AssemblerX8664Test, Cmpxchg) {
353 static constexpr bool NotLocked = false;
354 static constexpr bool Locked = true;
355
356 static constexpr uint32_t Mask8 = 0x000000FF;
357 static constexpr uint32_t Mask16 = 0x0000FFFF;
358 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
359
360 #define TestImplAddrReg(Value0, Src, Value1, ValueMem, LockedOrNot, Size) \
361 do { \
362 static constexpr char TestString[] = \
363 "(" #Value0 ", " #Src ", " #Value1 ", " #ValueMem ", " #LockedOrNot \
364 ", " #Size ")"; \
365 const uint32_t T0 = allocateDword(); \
366 static constexpr uint32_t V0 = (ValueMem)&Mask##Size; \
367 const uint32_t ZeroFlag = allocateDword(); \
368 \
369 __ mov(IceType_i##Size, Encoded_GPR_eax(), \
370 Immediate((Value0)&Mask##Size)); \
371 __ mov(IceType_i##Size, Encoded_GPR_##Src(), \
372 Immediate((Value1)&Mask##Size)); \
373 __ cmpxchg(IceType_i##Size, dwordAddress(T0), Encoded_GPR_##Src(), \
374 LockedOrNot); \
375 __ setcc(Cond::Br_e, dwordAddress(ZeroFlag)); \
376 \
377 AssembledTest test = assemble(); \
378 test.setDwordTo(T0, V0); \
379 test.setDwordTo(ZeroFlag, uint32_t(0xFF)); \
380 test.run(); \
381 \
382 if (V0 == (Mask##Size & (Value0))) { \
383 ASSERT_EQ(uint32_t((Value1)&Mask##Size), test.contentsOfDword(T0)) \
384 << TestString; \
385 ASSERT_EQ(1u, test.contentsOfDword(ZeroFlag)) << TestString; \
386 } else { \
387 ASSERT_EQ(uint32_t((ValueMem)&Mask##Size), test.eax()) << TestString; \
388 ASSERT_EQ(0u, test.contentsOfDword(ZeroFlag)) << TestString; \
389 } \
390 reset(); \
391 } while (0)
392
393 #define TestImplValue(Value0, Src, Value1, ValueMem, LockedOrNot) \
394 do { \
395 TestImplAddrReg(Value0, Src, Value1, ValueMem, LockedOrNot, 8); \
396 TestImplAddrReg(Value0, Src, Value1, ValueMem, LockedOrNot, 16); \
397 TestImplAddrReg(Value0, Src, Value1, ValueMem, LockedOrNot, 32); \
398 } while (0)
399
400 #define TestImpl(Src, LockedOrNot) \
401 do { \
402 TestImplValue(0xFFFFFFFF, Src, 0x1, 0xFFFFFFFF, LockedOrNot); \
403 TestImplValue(0x0FFF0F0F, Src, 0x1, 0xFFFFFFFF, LockedOrNot); \
404 } while (0)
405
406 TestImpl(r2, Locked);
407 TestImpl(r2, NotLocked);
408 TestImpl(r3, Locked);
409 TestImpl(r3, NotLocked);
410 TestImpl(r4, Locked);
411 TestImpl(r4, NotLocked);
412 TestImpl(r5, Locked);
413 TestImpl(r5, NotLocked);
414 TestImpl(r6, Locked);
415 TestImpl(r6, NotLocked);
416 TestImpl(r7, Locked);
417 TestImpl(r7, NotLocked);
418 TestImpl(r8, Locked);
419 TestImpl(r8, NotLocked);
420 TestImpl(r10, Locked);
421 TestImpl(r10, NotLocked);
422 TestImpl(r11, Locked);
423 TestImpl(r11, NotLocked);
424 TestImpl(r12, Locked);
425 TestImpl(r12, NotLocked);
426 TestImpl(r13, Locked);
427 TestImpl(r13, NotLocked);
428 TestImpl(r14, Locked);
429 TestImpl(r14, NotLocked);
430 TestImpl(r15, Locked);
431 TestImpl(r15, NotLocked);
432
433 #undef TestImpl
434 #undef TestImplValue
435 #undef TestImplAddrReg
436 }
437
TEST_F(AssemblerX8664LowLevelTest,Cmpxchg)438 TEST_F(AssemblerX8664LowLevelTest, Cmpxchg) {
439 static constexpr bool NotLocked = false;
440 static constexpr bool Locked = true;
441
442 // Ensures that cmpxchg emits a lock prefix accordingly.
443 {
444 __ cmpxchg(IceType_i8, Address::Absolute(0x1FF00), Encoded_GPR_r14(),
445 NotLocked);
446 static constexpr uint8_t ByteCountNotLocked8 = 10;
447 ASSERT_EQ(ByteCountNotLocked8, codeBytesSize());
448 ASSERT_TRUE(verifyBytes<ByteCountNotLocked8>(codeBytes(), 0x67, 0x44, 0x0F,
449 0xB0, 0x34, 0x25, 0x00, 0xFF,
450 0x01, 0x00));
451 reset();
452
453 __ cmpxchg(IceType_i8, Address::Absolute(0x1FF00), Encoded_GPR_r14(),
454 Locked);
455 static constexpr uint8_t ByteCountLocked8 = 1 + ByteCountNotLocked8;
456 ASSERT_EQ(ByteCountLocked8, codeBytesSize());
457 ASSERT_TRUE(verifyBytes<ByteCountLocked8>(codeBytes(), 0xF0, 0x67, 0x44,
458 0x0F, 0xB0, 0x34, 0x25, 0x00,
459 0xFF, 0x01, 0x00));
460 reset();
461 }
462
463 {
464 __ cmpxchg(IceType_i16, Address::Absolute(0x1FF00), Encoded_GPR_r14(),
465 NotLocked);
466 static constexpr uint8_t ByteCountNotLocked16 = 11;
467 ASSERT_EQ(ByteCountNotLocked16, codeBytesSize());
468 ASSERT_TRUE(verifyBytes<ByteCountNotLocked16>(codeBytes(), 0x66, 0x67, 0x44,
469 0x0F, 0xB1, 0x34, 0x25, 0x00,
470 0xFF, 0x01, 0x00));
471 reset();
472
473 __ cmpxchg(IceType_i16, Address::Absolute(0x1FF00), Encoded_GPR_r14(),
474 Locked);
475 static constexpr uint8_t ByteCountLocked16 = 1 + ByteCountNotLocked16;
476 ASSERT_EQ(ByteCountLocked16, codeBytesSize());
477 ASSERT_TRUE(verifyBytes<ByteCountLocked16>(codeBytes(), 0x66, 0xF0, 0x67,
478 0x44, 0x0F, 0xB1, 0x34, 0x25,
479 0x00, 0xFF, 0x01, 0x00));
480 reset();
481 }
482
483 {
484 __ cmpxchg(IceType_i32, Address::Absolute(0x1FF00), Encoded_GPR_r14(),
485 NotLocked);
486 static constexpr uint8_t ByteCountNotLocked32 = 10;
487 ASSERT_EQ(ByteCountNotLocked32, codeBytesSize());
488 ASSERT_TRUE(verifyBytes<ByteCountNotLocked32>(codeBytes(), 0x67, 0x44, 0x0F,
489 0xB1, 0x34, 0x25, 0x00, 0xFF,
490 0x01, 0x00));
491 reset();
492
493 __ cmpxchg(IceType_i32, Address::Absolute(0x1FF00), Encoded_GPR_r14(),
494 Locked);
495 static constexpr uint8_t ByteCountLocked32 = 1 + ByteCountNotLocked32;
496 ASSERT_EQ(ByteCountLocked32, codeBytesSize());
497 ASSERT_TRUE(verifyBytes<ByteCountLocked32>(codeBytes(), 0xF0, 0x67, 0x44,
498 0x0F, 0xB1, 0x34, 0x25, 0x00,
499 0xFF, 0x01, 0x00));
500 reset();
501 }
502 }
503
504 } // end of anonymous namespace
505 } // end of namespace Test
506 } // end of namespace X8664
507 } // end of namespace Ice
508