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 
operator ==(const MCOperand & a,const MCOperand & b)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 
operator ==(const MCInst & a,const MCInst & b)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 
IsImm(int64_t Value)63 Matcher<MCOperand> IsImm(int64_t Value) {
64   return AllOf(Property(&MCOperand::isImm, Eq(true)),
65                Property(&MCOperand::getImm, Eq(Value)));
66 }
67 
IsReg(unsigned Reg)68 Matcher<MCOperand> IsReg(unsigned Reg) {
69   return AllOf(Property(&MCOperand::isReg, Eq(true)),
70                Property(&MCOperand::getReg, Eq(Reg)));
71 }
72 
OpcodeIs(unsigned Opcode)73 Matcher<MCInst> OpcodeIs(unsigned Opcode) {
74   return Property(&MCInst::getOpcode, Eq(Opcode));
75 }
76 
IsMovImmediate(unsigned Opcode,int64_t Reg,int64_t Value)77 Matcher<MCInst> IsMovImmediate(unsigned Opcode, int64_t Reg, int64_t Value) {
78   return AllOf(OpcodeIs(Opcode), ElementsAre(IsReg(Reg), IsImm(Value)));
79 }
80 
IsMovValueToStack(unsigned Opcode,int64_t Value,size_t Offset)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 
IsMovValueFromStack(unsigned Opcode,unsigned Reg)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 
IsStackAllocate(unsigned Size)94 Matcher<MCInst> IsStackAllocate(unsigned Size) {
95   return AllOf(OpcodeIs(X86::SUB64ri8),
96                ElementsAre(IsReg(X86::RSP), IsReg(X86::RSP), IsImm(Size)));
97 }
98 
IsStackDeallocate(unsigned Size)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:
X86TargetTest(const char * Features)108   X86TargetTest(const char *Features) : State(kTriple, "core2", Features) {}
109 
SetUpTestCase()110   static void SetUpTestCase() {
111     LLVMInitializeX86TargetInfo();
112     LLVMInitializeX86Target();
113     LLVMInitializeX86TargetMC();
114     InitializeX86ExegesisTarget();
115   }
116 
setRegTo(unsigned Reg,const APInt & Value)117   std::vector<MCInst> setRegTo(unsigned Reg, const APInt &Value) {
118     return State.getExegesisTarget().setRegTo(State.getSubtargetInfo(), Reg,
119                                               Value);
120   }
121 
getInstr(unsigned OpCode)122   const Instruction &getInstr(unsigned OpCode) {
123     return State.getIC().getInstr(OpCode);
124   }
125 
126   LLVMState State;
127 };
128 
129 class Core2TargetTest : public X86TargetTest {
130 public:
Core2TargetTest()131   Core2TargetTest() : X86TargetTest("") {}
132 };
133 
134 class Core2AvxTargetTest : public X86TargetTest {
135 public:
Core2AvxTargetTest()136   Core2AvxTargetTest() : X86TargetTest("+avx") {}
137 };
138 
139 class Core2Avx512TargetTest : public X86TargetTest {
140 public:
Core2Avx512TargetTest()141   Core2Avx512TargetTest() : X86TargetTest("+avx512vl") {}
142 };
143 
TEST_F(Core2TargetTest,NoHighByteRegs)144 TEST_F(Core2TargetTest, NoHighByteRegs) {
145   EXPECT_TRUE(State.getRATC().reservedRegisters().test(X86::AH));
146 }
147 
TEST_F(Core2TargetTest,SetFlags)148 TEST_F(Core2TargetTest, 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 
TEST_F(Core2TargetTest,SetRegToGR8Value)157 TEST_F(Core2TargetTest, 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 
TEST_F(Core2TargetTest,SetRegToGR16Value)164 TEST_F(Core2TargetTest, 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 
TEST_F(Core2TargetTest,SetRegToGR32Value)171 TEST_F(Core2TargetTest, 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 
TEST_F(Core2TargetTest,SetRegToGR64Value)178 TEST_F(Core2TargetTest, 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 
TEST_F(Core2TargetTest,SetRegToVR64Value)185 TEST_F(Core2TargetTest, 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 
TEST_F(Core2TargetTest,SetRegToVR128Value_Use_MOVDQUrm)194 TEST_F(Core2TargetTest, 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 
TEST_F(Core2AvxTargetTest,SetRegToVR128Value_Use_VMOVDQUrm)206 TEST_F(Core2AvxTargetTest, 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 
TEST_F(Core2Avx512TargetTest,SetRegToVR128Value_Use_VMOVDQU32Z128rm)218 TEST_F(Core2Avx512TargetTest, 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 
TEST_F(Core2AvxTargetTest,SetRegToVR256Value_Use_VMOVDQUYrm)230 TEST_F(Core2AvxTargetTest, 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 
TEST_F(Core2Avx512TargetTest,SetRegToVR256Value_Use_VMOVDQU32Z256rm)248 TEST_F(Core2Avx512TargetTest, 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 
TEST_F(Core2Avx512TargetTest,SetRegToVR512Value)266 TEST_F(Core2Avx512TargetTest, 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 
TEST_F(Core2TargetTest,SetRegToST0_32Bits)296 TEST_F(Core2TargetTest, 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 
TEST_F(Core2TargetTest,SetRegToST1_32Bits)305 TEST_F(Core2TargetTest, 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 
TEST_F(Core2TargetTest,SetRegToST0_64Bits)316 TEST_F(Core2TargetTest, 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 
TEST_F(Core2TargetTest,SetRegToST0_80Bits)325 TEST_F(Core2TargetTest, 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 
TEST_F(Core2TargetTest,SetRegToFP0_80Bits)334 TEST_F(Core2TargetTest, 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 
TEST_F(Core2TargetTest,SetRegToFP1_32Bits)343 TEST_F(Core2TargetTest, 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 
TEST_F(Core2TargetTest,SetRegToFP1_4Bits)352 TEST_F(Core2TargetTest, 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 
TEST_F(Core2Avx512TargetTest,FillMemoryOperands_ADD64rm)361 TEST_F(Core2Avx512TargetTest, 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 
TEST_F(Core2Avx512TargetTest,FillMemoryOperands_VGATHERDPSZ128rm)374 TEST_F(Core2Avx512TargetTest, 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 } // namespace
388 } // namespace exegesis
389 } // namespace llvm
390