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