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