xref: /llvm-project/llvm/unittests/tools/llvm-exegesis/X86/TargetTest.cpp (revision bbab546a7195350ca58a189247d6baf6ab5fb81a)
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