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