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 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 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 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 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 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 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 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 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 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 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