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