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) 108 : ExegesisTarget_(ExegesisTarget::lookup(llvm::Triple(kTriple))) { 109 EXPECT_THAT(ExegesisTarget_, NotNull()); 110 std::string error; 111 Target_ = llvm::TargetRegistry::lookupTarget(kTriple, error); 112 EXPECT_THAT(Target_, NotNull()); 113 STI_.reset(Target_->createMCSubtargetInfo(kTriple, "core2", Features)); 114 } 115 116 static void SetUpTestCase() { 117 LLVMInitializeX86TargetInfo(); 118 LLVMInitializeX86Target(); 119 LLVMInitializeX86TargetMC(); 120 InitializeX86ExegesisTarget(); 121 } 122 123 std::vector<MCInst> setRegTo(unsigned Reg, const APInt &Value) { 124 return ExegesisTarget_->setRegTo(*STI_, Reg, Value); 125 } 126 127 const llvm::Target *Target_; 128 const ExegesisTarget *const ExegesisTarget_; 129 std::unique_ptr<llvm::MCSubtargetInfo> STI_; 130 }; 131 132 class Core2TargetTest : public X86TargetTest { 133 public: 134 Core2TargetTest() : X86TargetTest("") {} 135 }; 136 137 class Core2AvxTargetTest : public X86TargetTest { 138 public: 139 Core2AvxTargetTest() : X86TargetTest("+avx") {} 140 }; 141 142 class Core2Avx512TargetTest : public X86TargetTest { 143 public: 144 Core2Avx512TargetTest() : X86TargetTest("+avx512vl") {} 145 }; 146 147 TEST_F(Core2TargetTest, SetFlags) { 148 const unsigned Reg = llvm::X86::EFLAGS; 149 EXPECT_THAT( 150 setRegTo(Reg, APInt(64, 0x1111222233334444ULL)), 151 ElementsAre(IsStackAllocate(8), 152 IsMovValueToStack(llvm::X86::MOV32mi, 0x33334444UL, 0), 153 IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 4), 154 OpcodeIs(llvm::X86::POPF64))); 155 } 156 157 TEST_F(Core2TargetTest, SetRegToGR8Value) { 158 const uint8_t Value = 0xFFU; 159 const unsigned Reg = llvm::X86::AL; 160 EXPECT_THAT(setRegTo(Reg, APInt(8, Value)), 161 ElementsAre(IsMovImmediate(llvm::X86::MOV8ri, Reg, Value))); 162 } 163 164 TEST_F(Core2TargetTest, SetRegToGR16Value) { 165 const uint16_t Value = 0xFFFFU; 166 const unsigned Reg = llvm::X86::BX; 167 EXPECT_THAT(setRegTo(Reg, APInt(16, Value)), 168 ElementsAre(IsMovImmediate(llvm::X86::MOV16ri, Reg, Value))); 169 } 170 171 TEST_F(Core2TargetTest, SetRegToGR32Value) { 172 const uint32_t Value = 0x7FFFFU; 173 const unsigned Reg = llvm::X86::ECX; 174 EXPECT_THAT(setRegTo(Reg, APInt(32, Value)), 175 ElementsAre(IsMovImmediate(llvm::X86::MOV32ri, Reg, Value))); 176 } 177 178 TEST_F(Core2TargetTest, SetRegToGR64Value) { 179 const uint64_t Value = 0x7FFFFFFFFFFFFFFFULL; 180 const unsigned Reg = llvm::X86::RDX; 181 EXPECT_THAT(setRegTo(Reg, APInt(64, Value)), 182 ElementsAre(IsMovImmediate(llvm::X86::MOV64ri, Reg, Value))); 183 } 184 185 TEST_F(Core2TargetTest, SetRegToVR64Value) { 186 EXPECT_THAT( 187 setRegTo(llvm::X86::MM0, APInt(64, 0x1111222233334444ULL)), 188 ElementsAre(IsStackAllocate(8), 189 IsMovValueToStack(llvm::X86::MOV32mi, 0x33334444UL, 0), 190 IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 4), 191 IsMovValueFromStack(llvm::X86::MMX_MOVQ64rm, llvm::X86::MM0), 192 IsStackDeallocate(8))); 193 } 194 195 TEST_F(Core2TargetTest, SetRegToVR128Value_Use_MOVDQUrm) { 196 EXPECT_THAT( 197 setRegTo(llvm::X86::XMM0, 198 APInt(128, "11112222333344445555666677778888", 16)), 199 ElementsAre(IsStackAllocate(16), 200 IsMovValueToStack(llvm::X86::MOV32mi, 0x77778888UL, 0), 201 IsMovValueToStack(llvm::X86::MOV32mi, 0x55556666UL, 4), 202 IsMovValueToStack(llvm::X86::MOV32mi, 0x33334444UL, 8), 203 IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 12), 204 IsMovValueFromStack(llvm::X86::MOVDQUrm, llvm::X86::XMM0), 205 IsStackDeallocate(16))); 206 } 207 208 TEST_F(Core2AvxTargetTest, SetRegToVR128Value_Use_VMOVDQUrm) { 209 EXPECT_THAT( 210 setRegTo(llvm::X86::XMM0, 211 APInt(128, "11112222333344445555666677778888", 16)), 212 ElementsAre(IsStackAllocate(16), 213 IsMovValueToStack(llvm::X86::MOV32mi, 0x77778888UL, 0), 214 IsMovValueToStack(llvm::X86::MOV32mi, 0x55556666UL, 4), 215 IsMovValueToStack(llvm::X86::MOV32mi, 0x33334444UL, 8), 216 IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 12), 217 IsMovValueFromStack(llvm::X86::VMOVDQUrm, llvm::X86::XMM0), 218 IsStackDeallocate(16))); 219 } 220 221 TEST_F(Core2Avx512TargetTest, SetRegToVR128Value_Use_VMOVDQU32Z128rm) { 222 EXPECT_THAT( 223 setRegTo(llvm::X86::XMM0, 224 APInt(128, "11112222333344445555666677778888", 16)), 225 ElementsAre( 226 IsStackAllocate(16), 227 IsMovValueToStack(llvm::X86::MOV32mi, 0x77778888UL, 0), 228 IsMovValueToStack(llvm::X86::MOV32mi, 0x55556666UL, 4), 229 IsMovValueToStack(llvm::X86::MOV32mi, 0x33334444UL, 8), 230 IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 12), 231 IsMovValueFromStack(llvm::X86::VMOVDQU32Z128rm, llvm::X86::XMM0), 232 IsStackDeallocate(16))); 233 } 234 235 TEST_F(Core2AvxTargetTest, SetRegToVR256Value_Use_VMOVDQUYrm) { 236 const char ValueStr[] = 237 "1111111122222222333333334444444455555555666666667777777788888888"; 238 EXPECT_THAT(setRegTo(llvm::X86::YMM0, APInt(256, ValueStr, 16)), 239 ElementsAreArray( 240 {IsStackAllocate(32), 241 IsMovValueToStack(llvm::X86::MOV32mi, 0x88888888UL, 0), 242 IsMovValueToStack(llvm::X86::MOV32mi, 0x77777777UL, 4), 243 IsMovValueToStack(llvm::X86::MOV32mi, 0x66666666UL, 8), 244 IsMovValueToStack(llvm::X86::MOV32mi, 0x55555555UL, 12), 245 IsMovValueToStack(llvm::X86::MOV32mi, 0x44444444UL, 16), 246 IsMovValueToStack(llvm::X86::MOV32mi, 0x33333333UL, 20), 247 IsMovValueToStack(llvm::X86::MOV32mi, 0x22222222UL, 24), 248 IsMovValueToStack(llvm::X86::MOV32mi, 0x11111111UL, 28), 249 IsMovValueFromStack(llvm::X86::VMOVDQUYrm, llvm::X86::YMM0), 250 IsStackDeallocate(32)})); 251 } 252 253 TEST_F(Core2Avx512TargetTest, SetRegToVR256Value_Use_VMOVDQU32Z256rm) { 254 const char ValueStr[] = 255 "1111111122222222333333334444444455555555666666667777777788888888"; 256 EXPECT_THAT( 257 setRegTo(llvm::X86::YMM0, APInt(256, ValueStr, 16)), 258 ElementsAreArray( 259 {IsStackAllocate(32), 260 IsMovValueToStack(llvm::X86::MOV32mi, 0x88888888UL, 0), 261 IsMovValueToStack(llvm::X86::MOV32mi, 0x77777777UL, 4), 262 IsMovValueToStack(llvm::X86::MOV32mi, 0x66666666UL, 8), 263 IsMovValueToStack(llvm::X86::MOV32mi, 0x55555555UL, 12), 264 IsMovValueToStack(llvm::X86::MOV32mi, 0x44444444UL, 16), 265 IsMovValueToStack(llvm::X86::MOV32mi, 0x33333333UL, 20), 266 IsMovValueToStack(llvm::X86::MOV32mi, 0x22222222UL, 24), 267 IsMovValueToStack(llvm::X86::MOV32mi, 0x11111111UL, 28), 268 IsMovValueFromStack(llvm::X86::VMOVDQU32Z256rm, llvm::X86::YMM0), 269 IsStackDeallocate(32)})); 270 } 271 272 TEST_F(Core2Avx512TargetTest, SetRegToVR512Value) { 273 const char ValueStr[] = 274 "1111111122222222333333334444444455555555666666667777777788888888" 275 "99999999AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDDEEEEEEEEFFFFFFFF00000000"; 276 EXPECT_THAT( 277 setRegTo(llvm::X86::ZMM0, APInt(512, ValueStr, 16)), 278 ElementsAreArray( 279 {IsStackAllocate(64), 280 IsMovValueToStack(llvm::X86::MOV32mi, 0x00000000UL, 0), 281 IsMovValueToStack(llvm::X86::MOV32mi, 0xFFFFFFFFUL, 4), 282 IsMovValueToStack(llvm::X86::MOV32mi, 0xEEEEEEEEUL, 8), 283 IsMovValueToStack(llvm::X86::MOV32mi, 0xDDDDDDDDUL, 12), 284 IsMovValueToStack(llvm::X86::MOV32mi, 0xCCCCCCCCUL, 16), 285 IsMovValueToStack(llvm::X86::MOV32mi, 0xBBBBBBBBUL, 20), 286 IsMovValueToStack(llvm::X86::MOV32mi, 0xAAAAAAAAUL, 24), 287 IsMovValueToStack(llvm::X86::MOV32mi, 0x99999999UL, 28), 288 IsMovValueToStack(llvm::X86::MOV32mi, 0x88888888UL, 32), 289 IsMovValueToStack(llvm::X86::MOV32mi, 0x77777777UL, 36), 290 IsMovValueToStack(llvm::X86::MOV32mi, 0x66666666UL, 40), 291 IsMovValueToStack(llvm::X86::MOV32mi, 0x55555555UL, 44), 292 IsMovValueToStack(llvm::X86::MOV32mi, 0x44444444UL, 48), 293 IsMovValueToStack(llvm::X86::MOV32mi, 0x33333333UL, 52), 294 IsMovValueToStack(llvm::X86::MOV32mi, 0x22222222UL, 56), 295 IsMovValueToStack(llvm::X86::MOV32mi, 0x11111111UL, 60), 296 IsMovValueFromStack(llvm::X86::VMOVDQU32Zrm, llvm::X86::ZMM0), 297 IsStackDeallocate(64)})); 298 } 299 300 // Note: We always put 80 bits on the stack independently of the size of the 301 // value. This uses a bit more space but makes the code simpler. 302 303 TEST_F(Core2TargetTest, SetRegToST0_32Bits) { 304 EXPECT_THAT( 305 setRegTo(llvm::X86::ST0, APInt(32, 0x11112222ULL)), 306 ElementsAre(IsStackAllocate(10), 307 IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 0), 308 IsMovValueToStack(llvm::X86::MOV32mi, 0x00000000UL, 4), 309 IsMovValueToStack(llvm::X86::MOV16mi, 0x0000UL, 8), 310 OpcodeIs(llvm::X86::LD_F80m), IsStackDeallocate(10))); 311 } 312 313 TEST_F(Core2TargetTest, SetRegToST1_32Bits) { 314 const MCInst CopySt0ToSt1 = 315 llvm::MCInstBuilder(llvm::X86::ST_Frr).addReg(llvm::X86::ST1); 316 EXPECT_THAT( 317 setRegTo(llvm::X86::ST1, APInt(32, 0x11112222ULL)), 318 ElementsAre(IsStackAllocate(10), 319 IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 0), 320 IsMovValueToStack(llvm::X86::MOV32mi, 0x00000000UL, 4), 321 IsMovValueToStack(llvm::X86::MOV16mi, 0x0000UL, 8), 322 OpcodeIs(llvm::X86::LD_F80m), CopySt0ToSt1, 323 IsStackDeallocate(10))); 324 } 325 326 TEST_F(Core2TargetTest, SetRegToST0_64Bits) { 327 EXPECT_THAT( 328 setRegTo(llvm::X86::ST0, APInt(64, 0x1111222233334444ULL)), 329 ElementsAre(IsStackAllocate(10), 330 IsMovValueToStack(llvm::X86::MOV32mi, 0x33334444UL, 0), 331 IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 4), 332 IsMovValueToStack(llvm::X86::MOV16mi, 0x0000UL, 8), 333 OpcodeIs(llvm::X86::LD_F80m), IsStackDeallocate(10))); 334 } 335 336 TEST_F(Core2TargetTest, SetRegToST0_80Bits) { 337 EXPECT_THAT( 338 setRegTo(llvm::X86::ST0, APInt(80, "11112222333344445555", 16)), 339 ElementsAre(IsStackAllocate(10), 340 IsMovValueToStack(llvm::X86::MOV32mi, 0x44445555UL, 0), 341 IsMovValueToStack(llvm::X86::MOV32mi, 0x22223333UL, 4), 342 IsMovValueToStack(llvm::X86::MOV16mi, 0x1111UL, 8), 343 OpcodeIs(llvm::X86::LD_F80m), IsStackDeallocate(10))); 344 } 345 346 TEST_F(Core2TargetTest, SetRegToFP0_80Bits) { 347 EXPECT_THAT( 348 setRegTo(llvm::X86::FP0, APInt(80, "11112222333344445555", 16)), 349 ElementsAre(IsStackAllocate(10), 350 IsMovValueToStack(llvm::X86::MOV32mi, 0x44445555UL, 0), 351 IsMovValueToStack(llvm::X86::MOV32mi, 0x22223333UL, 4), 352 IsMovValueToStack(llvm::X86::MOV16mi, 0x1111UL, 8), 353 OpcodeIs(llvm::X86::LD_Fp80m), IsStackDeallocate(10))); 354 } 355 356 TEST_F(Core2TargetTest, SetRegToFP1_32Bits) { 357 EXPECT_THAT( 358 setRegTo(llvm::X86::FP1, APInt(32, 0x11112222ULL)), 359 ElementsAre(IsStackAllocate(10), 360 IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 0), 361 IsMovValueToStack(llvm::X86::MOV32mi, 0x00000000UL, 4), 362 IsMovValueToStack(llvm::X86::MOV16mi, 0x0000UL, 8), 363 OpcodeIs(llvm::X86::LD_Fp80m), 364 IsStackDeallocate(10))); 365 } 366 367 TEST_F(Core2TargetTest, SetRegToFP1_4Bits) { 368 EXPECT_THAT( 369 setRegTo(llvm::X86::FP1, APInt(4, 0x1ULL)), 370 ElementsAre(IsStackAllocate(10), 371 IsMovValueToStack(llvm::X86::MOV32mi, 0x00000001UL, 0), 372 IsMovValueToStack(llvm::X86::MOV32mi, 0x00000000UL, 4), 373 IsMovValueToStack(llvm::X86::MOV16mi, 0x0000UL, 8), 374 OpcodeIs(llvm::X86::LD_Fp80m), 375 IsStackDeallocate(10))); 376 } 377 378 } // namespace 379 } // namespace exegesis 380 } // namespace llvm 381