1 #include "Target.h" 2 3 #include <cassert> 4 #include <memory> 5 6 #include "MCTargetDesc/X86MCTargetDesc.h" 7 #include "llvm/Support/TargetRegistry.h" 8 #include "llvm/Support/TargetSelect.h" 9 #include "gmock/gmock.h" 10 #include "gtest/gtest.h" 11 12 #include "llvm/MC/MCInstPrinter.h" 13 14 namespace llvm { 15 16 bool operator==(const MCOperand &a, const MCOperand &b) { 17 if (a.isImm() && b.isImm()) 18 return a.getImm() == b.getImm(); 19 if (a.isReg() && b.isReg()) 20 return a.getReg() == b.getReg(); 21 return false; 22 } 23 24 bool operator==(const MCInst &a, const MCInst &b) { 25 if (a.getOpcode() != b.getOpcode()) 26 return false; 27 if (a.getNumOperands() != b.getNumOperands()) 28 return false; 29 for (unsigned I = 0; I < a.getNumOperands(); ++I) { 30 if (!(a.getOperand(I) == b.getOperand(I))) 31 return false; 32 } 33 return true; 34 } 35 36 } // namespace llvm 37 38 namespace llvm { 39 namespace exegesis { 40 41 void InitializeX86ExegesisTarget(); 42 43 namespace { 44 45 using testing::AllOf; 46 using testing::ElementsAre; 47 using testing::ElementsAreArray; 48 using testing::Eq; 49 using testing::Gt; 50 using testing::Matcher; 51 using testing::NotNull; 52 using testing::Property; 53 using testing::SizeIs; 54 55 using llvm::APInt; 56 using llvm::MCInst; 57 using llvm::MCInstBuilder; 58 using llvm::MCOperand; 59 60 Matcher<MCOperand> IsImm(int64_t Value) { 61 return AllOf(Property(&MCOperand::isImm, Eq(true)), 62 Property(&MCOperand::getImm, Eq(Value))); 63 } 64 65 Matcher<MCOperand> IsReg(unsigned Reg) { 66 return AllOf(Property(&MCOperand::isReg, Eq(true)), 67 Property(&MCOperand::getReg, Eq(Reg))); 68 } 69 70 Matcher<MCInst> OpcodeIs(unsigned Opcode) { 71 return Property(&MCInst::getOpcode, Eq(Opcode)); 72 } 73 74 Matcher<MCInst> IsMovImmediate(unsigned Opcode, int64_t Reg, int64_t Value) { 75 return AllOf(OpcodeIs(Opcode), ElementsAre(IsReg(Reg), IsImm(Value))); 76 } 77 78 Matcher<MCInst> IsMovValueToStack(unsigned Opcode, int64_t Value, 79 size_t Offset) { 80 return AllOf(OpcodeIs(Opcode), 81 ElementsAre(IsReg(llvm::X86::RSP), IsImm(1), IsReg(0), 82 IsImm(Offset), IsReg(0), IsImm(Value))); 83 } 84 85 Matcher<MCInst> IsMovValueFromStack(unsigned Opcode, unsigned Reg) { 86 return AllOf(OpcodeIs(Opcode), 87 ElementsAre(IsReg(Reg), IsReg(llvm::X86::RSP), IsImm(1), 88 IsReg(0), IsImm(0), IsReg(0))); 89 } 90 91 Matcher<MCInst> IsStackAllocate(unsigned Size) { 92 return AllOf( 93 OpcodeIs(llvm::X86::SUB64ri8), 94 ElementsAre(IsReg(llvm::X86::RSP), IsReg(llvm::X86::RSP), IsImm(Size))); 95 } 96 97 Matcher<MCInst> IsStackDeallocate(unsigned Size) { 98 return AllOf( 99 OpcodeIs(llvm::X86::ADD64ri8), 100 ElementsAre(IsReg(llvm::X86::RSP), IsReg(llvm::X86::RSP), IsImm(Size))); 101 } 102 103 constexpr const char kTriple[] = "x86_64-unknown-linux"; 104 105 class X86TargetTest : public ::testing::Test { 106 protected: 107 X86TargetTest(const char *Features) : State(kTriple, "core2", Features) {} 108 109 static void SetUpTestCase() { 110 LLVMInitializeX86TargetInfo(); 111 LLVMInitializeX86Target(); 112 LLVMInitializeX86TargetMC(); 113 InitializeX86ExegesisTarget(); 114 } 115 116 std::vector<MCInst> setRegTo(unsigned Reg, const APInt &Value) { 117 return State.getExegesisTarget().setRegTo(State.getSubtargetInfo(), Reg, 118 Value); 119 } 120 121 LLVMState State; 122 }; 123 124 class Core2TargetTest : public X86TargetTest { 125 public: 126 Core2TargetTest() : X86TargetTest("") {} 127 }; 128 129 class Core2AvxTargetTest : public X86TargetTest { 130 public: 131 Core2AvxTargetTest() : X86TargetTest("+avx") {} 132 }; 133 134 class Core2Avx512TargetTest : public X86TargetTest { 135 public: 136 Core2Avx512TargetTest() : X86TargetTest("+avx512vl") {} 137 }; 138 139 TEST_F(Core2TargetTest, SetFlags) { 140 const unsigned Reg = llvm::X86::EFLAGS; 141 EXPECT_THAT( 142 setRegTo(Reg, APInt(64, 0x1111222233334444ULL)), 143 ElementsAre(IsStackAllocate(8), 144 IsMovValueToStack(llvm::X86::MOV32mi, 0x33334444UL, 0), 145 IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 4), 146 OpcodeIs(llvm::X86::POPF64))); 147 } 148 149 TEST_F(Core2TargetTest, SetRegToGR8Value) { 150 const uint8_t Value = 0xFFU; 151 const unsigned Reg = llvm::X86::AL; 152 EXPECT_THAT(setRegTo(Reg, APInt(8, Value)), 153 ElementsAre(IsMovImmediate(llvm::X86::MOV8ri, Reg, Value))); 154 } 155 156 TEST_F(Core2TargetTest, SetRegToGR16Value) { 157 const uint16_t Value = 0xFFFFU; 158 const unsigned Reg = llvm::X86::BX; 159 EXPECT_THAT(setRegTo(Reg, APInt(16, Value)), 160 ElementsAre(IsMovImmediate(llvm::X86::MOV16ri, Reg, Value))); 161 } 162 163 TEST_F(Core2TargetTest, SetRegToGR32Value) { 164 const uint32_t Value = 0x7FFFFU; 165 const unsigned Reg = llvm::X86::ECX; 166 EXPECT_THAT(setRegTo(Reg, APInt(32, Value)), 167 ElementsAre(IsMovImmediate(llvm::X86::MOV32ri, Reg, Value))); 168 } 169 170 TEST_F(Core2TargetTest, SetRegToGR64Value) { 171 const uint64_t Value = 0x7FFFFFFFFFFFFFFFULL; 172 const unsigned Reg = llvm::X86::RDX; 173 EXPECT_THAT(setRegTo(Reg, APInt(64, Value)), 174 ElementsAre(IsMovImmediate(llvm::X86::MOV64ri, Reg, Value))); 175 } 176 177 TEST_F(Core2TargetTest, SetRegToVR64Value) { 178 EXPECT_THAT( 179 setRegTo(llvm::X86::MM0, APInt(64, 0x1111222233334444ULL)), 180 ElementsAre(IsStackAllocate(8), 181 IsMovValueToStack(llvm::X86::MOV32mi, 0x33334444UL, 0), 182 IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 4), 183 IsMovValueFromStack(llvm::X86::MMX_MOVQ64rm, llvm::X86::MM0), 184 IsStackDeallocate(8))); 185 } 186 187 TEST_F(Core2TargetTest, SetRegToVR128Value_Use_MOVDQUrm) { 188 EXPECT_THAT( 189 setRegTo(llvm::X86::XMM0, 190 APInt(128, "11112222333344445555666677778888", 16)), 191 ElementsAre(IsStackAllocate(16), 192 IsMovValueToStack(llvm::X86::MOV32mi, 0x77778888UL, 0), 193 IsMovValueToStack(llvm::X86::MOV32mi, 0x55556666UL, 4), 194 IsMovValueToStack(llvm::X86::MOV32mi, 0x33334444UL, 8), 195 IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 12), 196 IsMovValueFromStack(llvm::X86::MOVDQUrm, llvm::X86::XMM0), 197 IsStackDeallocate(16))); 198 } 199 200 TEST_F(Core2AvxTargetTest, SetRegToVR128Value_Use_VMOVDQUrm) { 201 EXPECT_THAT( 202 setRegTo(llvm::X86::XMM0, 203 APInt(128, "11112222333344445555666677778888", 16)), 204 ElementsAre(IsStackAllocate(16), 205 IsMovValueToStack(llvm::X86::MOV32mi, 0x77778888UL, 0), 206 IsMovValueToStack(llvm::X86::MOV32mi, 0x55556666UL, 4), 207 IsMovValueToStack(llvm::X86::MOV32mi, 0x33334444UL, 8), 208 IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 12), 209 IsMovValueFromStack(llvm::X86::VMOVDQUrm, llvm::X86::XMM0), 210 IsStackDeallocate(16))); 211 } 212 213 TEST_F(Core2Avx512TargetTest, SetRegToVR128Value_Use_VMOVDQU32Z128rm) { 214 EXPECT_THAT( 215 setRegTo(llvm::X86::XMM0, 216 APInt(128, "11112222333344445555666677778888", 16)), 217 ElementsAre( 218 IsStackAllocate(16), 219 IsMovValueToStack(llvm::X86::MOV32mi, 0x77778888UL, 0), 220 IsMovValueToStack(llvm::X86::MOV32mi, 0x55556666UL, 4), 221 IsMovValueToStack(llvm::X86::MOV32mi, 0x33334444UL, 8), 222 IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 12), 223 IsMovValueFromStack(llvm::X86::VMOVDQU32Z128rm, llvm::X86::XMM0), 224 IsStackDeallocate(16))); 225 } 226 227 TEST_F(Core2AvxTargetTest, SetRegToVR256Value_Use_VMOVDQUYrm) { 228 const char ValueStr[] = 229 "1111111122222222333333334444444455555555666666667777777788888888"; 230 EXPECT_THAT(setRegTo(llvm::X86::YMM0, APInt(256, ValueStr, 16)), 231 ElementsAreArray( 232 {IsStackAllocate(32), 233 IsMovValueToStack(llvm::X86::MOV32mi, 0x88888888UL, 0), 234 IsMovValueToStack(llvm::X86::MOV32mi, 0x77777777UL, 4), 235 IsMovValueToStack(llvm::X86::MOV32mi, 0x66666666UL, 8), 236 IsMovValueToStack(llvm::X86::MOV32mi, 0x55555555UL, 12), 237 IsMovValueToStack(llvm::X86::MOV32mi, 0x44444444UL, 16), 238 IsMovValueToStack(llvm::X86::MOV32mi, 0x33333333UL, 20), 239 IsMovValueToStack(llvm::X86::MOV32mi, 0x22222222UL, 24), 240 IsMovValueToStack(llvm::X86::MOV32mi, 0x11111111UL, 28), 241 IsMovValueFromStack(llvm::X86::VMOVDQUYrm, llvm::X86::YMM0), 242 IsStackDeallocate(32)})); 243 } 244 245 TEST_F(Core2Avx512TargetTest, SetRegToVR256Value_Use_VMOVDQU32Z256rm) { 246 const char ValueStr[] = 247 "1111111122222222333333334444444455555555666666667777777788888888"; 248 EXPECT_THAT( 249 setRegTo(llvm::X86::YMM0, APInt(256, ValueStr, 16)), 250 ElementsAreArray( 251 {IsStackAllocate(32), 252 IsMovValueToStack(llvm::X86::MOV32mi, 0x88888888UL, 0), 253 IsMovValueToStack(llvm::X86::MOV32mi, 0x77777777UL, 4), 254 IsMovValueToStack(llvm::X86::MOV32mi, 0x66666666UL, 8), 255 IsMovValueToStack(llvm::X86::MOV32mi, 0x55555555UL, 12), 256 IsMovValueToStack(llvm::X86::MOV32mi, 0x44444444UL, 16), 257 IsMovValueToStack(llvm::X86::MOV32mi, 0x33333333UL, 20), 258 IsMovValueToStack(llvm::X86::MOV32mi, 0x22222222UL, 24), 259 IsMovValueToStack(llvm::X86::MOV32mi, 0x11111111UL, 28), 260 IsMovValueFromStack(llvm::X86::VMOVDQU32Z256rm, llvm::X86::YMM0), 261 IsStackDeallocate(32)})); 262 } 263 264 TEST_F(Core2Avx512TargetTest, SetRegToVR512Value) { 265 const char ValueStr[] = 266 "1111111122222222333333334444444455555555666666667777777788888888" 267 "99999999AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDDEEEEEEEEFFFFFFFF00000000"; 268 EXPECT_THAT( 269 setRegTo(llvm::X86::ZMM0, APInt(512, ValueStr, 16)), 270 ElementsAreArray( 271 {IsStackAllocate(64), 272 IsMovValueToStack(llvm::X86::MOV32mi, 0x00000000UL, 0), 273 IsMovValueToStack(llvm::X86::MOV32mi, 0xFFFFFFFFUL, 4), 274 IsMovValueToStack(llvm::X86::MOV32mi, 0xEEEEEEEEUL, 8), 275 IsMovValueToStack(llvm::X86::MOV32mi, 0xDDDDDDDDUL, 12), 276 IsMovValueToStack(llvm::X86::MOV32mi, 0xCCCCCCCCUL, 16), 277 IsMovValueToStack(llvm::X86::MOV32mi, 0xBBBBBBBBUL, 20), 278 IsMovValueToStack(llvm::X86::MOV32mi, 0xAAAAAAAAUL, 24), 279 IsMovValueToStack(llvm::X86::MOV32mi, 0x99999999UL, 28), 280 IsMovValueToStack(llvm::X86::MOV32mi, 0x88888888UL, 32), 281 IsMovValueToStack(llvm::X86::MOV32mi, 0x77777777UL, 36), 282 IsMovValueToStack(llvm::X86::MOV32mi, 0x66666666UL, 40), 283 IsMovValueToStack(llvm::X86::MOV32mi, 0x55555555UL, 44), 284 IsMovValueToStack(llvm::X86::MOV32mi, 0x44444444UL, 48), 285 IsMovValueToStack(llvm::X86::MOV32mi, 0x33333333UL, 52), 286 IsMovValueToStack(llvm::X86::MOV32mi, 0x22222222UL, 56), 287 IsMovValueToStack(llvm::X86::MOV32mi, 0x11111111UL, 60), 288 IsMovValueFromStack(llvm::X86::VMOVDQU32Zrm, llvm::X86::ZMM0), 289 IsStackDeallocate(64)})); 290 } 291 292 // Note: We always put 80 bits on the stack independently of the size of the 293 // value. This uses a bit more space but makes the code simpler. 294 295 TEST_F(Core2TargetTest, SetRegToST0_32Bits) { 296 EXPECT_THAT( 297 setRegTo(llvm::X86::ST0, APInt(32, 0x11112222ULL)), 298 ElementsAre(IsStackAllocate(10), 299 IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 0), 300 IsMovValueToStack(llvm::X86::MOV32mi, 0x00000000UL, 4), 301 IsMovValueToStack(llvm::X86::MOV16mi, 0x0000UL, 8), 302 OpcodeIs(llvm::X86::LD_F80m), IsStackDeallocate(10))); 303 } 304 305 TEST_F(Core2TargetTest, SetRegToST1_32Bits) { 306 const MCInst CopySt0ToSt1 = 307 llvm::MCInstBuilder(llvm::X86::ST_Frr).addReg(llvm::X86::ST1); 308 EXPECT_THAT( 309 setRegTo(llvm::X86::ST1, APInt(32, 0x11112222ULL)), 310 ElementsAre(IsStackAllocate(10), 311 IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 0), 312 IsMovValueToStack(llvm::X86::MOV32mi, 0x00000000UL, 4), 313 IsMovValueToStack(llvm::X86::MOV16mi, 0x0000UL, 8), 314 OpcodeIs(llvm::X86::LD_F80m), CopySt0ToSt1, 315 IsStackDeallocate(10))); 316 } 317 318 TEST_F(Core2TargetTest, SetRegToST0_64Bits) { 319 EXPECT_THAT( 320 setRegTo(llvm::X86::ST0, APInt(64, 0x1111222233334444ULL)), 321 ElementsAre(IsStackAllocate(10), 322 IsMovValueToStack(llvm::X86::MOV32mi, 0x33334444UL, 0), 323 IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 4), 324 IsMovValueToStack(llvm::X86::MOV16mi, 0x0000UL, 8), 325 OpcodeIs(llvm::X86::LD_F80m), IsStackDeallocate(10))); 326 } 327 328 TEST_F(Core2TargetTest, SetRegToST0_80Bits) { 329 EXPECT_THAT( 330 setRegTo(llvm::X86::ST0, APInt(80, "11112222333344445555", 16)), 331 ElementsAre(IsStackAllocate(10), 332 IsMovValueToStack(llvm::X86::MOV32mi, 0x44445555UL, 0), 333 IsMovValueToStack(llvm::X86::MOV32mi, 0x22223333UL, 4), 334 IsMovValueToStack(llvm::X86::MOV16mi, 0x1111UL, 8), 335 OpcodeIs(llvm::X86::LD_F80m), IsStackDeallocate(10))); 336 } 337 338 TEST_F(Core2TargetTest, SetRegToFP0_80Bits) { 339 EXPECT_THAT( 340 setRegTo(llvm::X86::FP0, APInt(80, "11112222333344445555", 16)), 341 ElementsAre(IsStackAllocate(10), 342 IsMovValueToStack(llvm::X86::MOV32mi, 0x44445555UL, 0), 343 IsMovValueToStack(llvm::X86::MOV32mi, 0x22223333UL, 4), 344 IsMovValueToStack(llvm::X86::MOV16mi, 0x1111UL, 8), 345 OpcodeIs(llvm::X86::LD_Fp80m), IsStackDeallocate(10))); 346 } 347 348 TEST_F(Core2TargetTest, SetRegToFP1_32Bits) { 349 EXPECT_THAT( 350 setRegTo(llvm::X86::FP1, APInt(32, 0x11112222ULL)), 351 ElementsAre(IsStackAllocate(10), 352 IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 0), 353 IsMovValueToStack(llvm::X86::MOV32mi, 0x00000000UL, 4), 354 IsMovValueToStack(llvm::X86::MOV16mi, 0x0000UL, 8), 355 OpcodeIs(llvm::X86::LD_Fp80m), IsStackDeallocate(10))); 356 } 357 358 TEST_F(Core2TargetTest, SetRegToFP1_4Bits) { 359 EXPECT_THAT( 360 setRegTo(llvm::X86::FP1, APInt(4, 0x1ULL)), 361 ElementsAre(IsStackAllocate(10), 362 IsMovValueToStack(llvm::X86::MOV32mi, 0x00000001UL, 0), 363 IsMovValueToStack(llvm::X86::MOV32mi, 0x00000000UL, 4), 364 IsMovValueToStack(llvm::X86::MOV16mi, 0x0000UL, 8), 365 OpcodeIs(llvm::X86::LD_Fp80m), IsStackDeallocate(10))); 366 } 367 368 TEST_F(Core2Avx512TargetTest, FillMemoryOperands_ADD64rm) { 369 Instruction I(State.getInstrInfo(), State.getRATC(), X86::ADD64rm); 370 InstructionTemplate IT(I); 371 constexpr const int kOffset = 42; 372 State.getExegesisTarget().fillMemoryOperands(IT, X86::RDI, kOffset); 373 // Memory is operands 2-6. 374 EXPECT_THAT(IT.getValueFor(I.Operands[2]), IsReg(X86::RDI)); 375 EXPECT_THAT(IT.getValueFor(I.Operands[3]), IsImm(1)); 376 EXPECT_THAT(IT.getValueFor(I.Operands[4]), IsReg(0)); 377 EXPECT_THAT(IT.getValueFor(I.Operands[5]), IsImm(kOffset)); 378 EXPECT_THAT(IT.getValueFor(I.Operands[6]), IsReg(0)); 379 } 380 381 TEST_F(Core2Avx512TargetTest, FillMemoryOperands_VGATHERDPSZ128rm) { 382 Instruction I(State.getInstrInfo(), State.getRATC(), X86::VGATHERDPSZ128rm); 383 InstructionTemplate IT(I); 384 constexpr const int kOffset = 42; 385 State.getExegesisTarget().fillMemoryOperands(IT, X86::RDI, kOffset); 386 // Memory is operands 4-8. 387 EXPECT_THAT(IT.getValueFor(I.Operands[4]), IsReg(X86::RDI)); 388 EXPECT_THAT(IT.getValueFor(I.Operands[5]), IsImm(1)); 389 EXPECT_THAT(IT.getValueFor(I.Operands[6]), IsReg(0)); 390 EXPECT_THAT(IT.getValueFor(I.Operands[7]), IsImm(kOffset)); 391 EXPECT_THAT(IT.getValueFor(I.Operands[8]), IsReg(0)); 392 } 393 394 } // namespace 395 } // namespace exegesis 396 } // namespace llvm 397