1 //===-- TargetTest.cpp -----------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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"
20 #include "llvm/MC/MCInstPrinter.h"
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();
32 bool operator==(const MCInst
&a
, const MCInst
&b
) {
33 if (a
.getOpcode() != b
.getOpcode())
35 if (a
.getNumOperands() != b
.getNumOperands())
37 for (unsigned I
= 0; I
< a
.getNumOperands(); ++I
) {
38 if (!(a
.getOperand(I
) == b
.getOperand(I
)))
49 void InitializeX86ExegesisTarget();
54 using testing::ElementsAre
;
55 using testing::ElementsAreArray
;
58 using testing::Matcher
;
59 using testing::NotNull
;
60 using testing::Property
;
61 using testing::SizeIs
;
65 using llvm::MCInstBuilder
;
66 using llvm::MCOperand
;
68 Matcher
<MCOperand
> IsImm(int64_t Value
) {
69 return AllOf(Property(&MCOperand::isImm
, Eq(true)),
70 Property(&MCOperand::getImm
, Eq(Value
)));
73 Matcher
<MCOperand
> IsReg(unsigned Reg
) {
74 return AllOf(Property(&MCOperand::isReg
, Eq(true)),
75 Property(&MCOperand::getReg
, Eq(Reg
)));
78 Matcher
<MCInst
> OpcodeIs(unsigned Opcode
) {
79 return Property(&MCInst::getOpcode
, Eq(Opcode
));
82 Matcher
<MCInst
> IsMovImmediate(unsigned Opcode
, int64_t Reg
, int64_t Value
) {
83 return AllOf(OpcodeIs(Opcode
), ElementsAre(IsReg(Reg
), IsImm(Value
)));
86 Matcher
<MCInst
> IsMovValueToStack(unsigned Opcode
, int64_t Value
,
88 return AllOf(OpcodeIs(Opcode
),
89 ElementsAre(IsReg(llvm::X86::RSP
), IsImm(1), IsReg(0),
90 IsImm(Offset
), IsReg(0), IsImm(Value
)));
93 Matcher
<MCInst
> IsMovValueFromStack(unsigned Opcode
, unsigned Reg
) {
94 return AllOf(OpcodeIs(Opcode
),
95 ElementsAre(IsReg(Reg
), IsReg(llvm::X86::RSP
), IsImm(1),
96 IsReg(0), IsImm(0), IsReg(0)));
99 Matcher
<MCInst
> IsStackAllocate(unsigned Size
) {
101 OpcodeIs(llvm::X86::SUB64ri8
),
102 ElementsAre(IsReg(llvm::X86::RSP
), IsReg(llvm::X86::RSP
), IsImm(Size
)));
105 Matcher
<MCInst
> IsStackDeallocate(unsigned Size
) {
107 OpcodeIs(llvm::X86::ADD64ri8
),
108 ElementsAre(IsReg(llvm::X86::RSP
), IsReg(llvm::X86::RSP
), IsImm(Size
)));
111 constexpr const char kTriple
[] = "x86_64-unknown-linux";
113 class X86TargetTest
: public ::testing::Test
{
115 X86TargetTest(const char *Features
) : State(kTriple
, "core2", Features
) {}
117 static void SetUpTestCase() {
118 LLVMInitializeX86TargetInfo();
119 LLVMInitializeX86Target();
120 LLVMInitializeX86TargetMC();
121 InitializeX86ExegesisTarget();
124 std::vector
<MCInst
> setRegTo(unsigned Reg
, const APInt
&Value
) {
125 return State
.getExegesisTarget().setRegTo(State
.getSubtargetInfo(), Reg
,
132 class Core2TargetTest
: public X86TargetTest
{
134 Core2TargetTest() : X86TargetTest("") {}
137 class Core2AvxTargetTest
: public X86TargetTest
{
139 Core2AvxTargetTest() : X86TargetTest("+avx") {}
142 class Core2Avx512TargetTest
: public X86TargetTest
{
144 Core2Avx512TargetTest() : X86TargetTest("+avx512vl") {}
147 TEST_F(Core2TargetTest
, NoHighByteRegs
) {
148 EXPECT_TRUE(State
.getRATC().reservedRegisters().test(X86::AH
));
151 TEST_F(Core2TargetTest
, SetFlags
) {
152 const unsigned Reg
= llvm::X86::EFLAGS
;
154 setRegTo(Reg
, APInt(64, 0x1111222233334444ULL
)),
155 ElementsAre(IsStackAllocate(8),
156 IsMovValueToStack(llvm::X86::MOV32mi
, 0x33334444UL
, 0),
157 IsMovValueToStack(llvm::X86::MOV32mi
, 0x11112222UL
, 4),
158 OpcodeIs(llvm::X86::POPF64
)));
161 TEST_F(Core2TargetTest
, SetRegToGR8Value
) {
162 const uint8_t Value
= 0xFFU
;
163 const unsigned Reg
= llvm::X86::AL
;
164 EXPECT_THAT(setRegTo(Reg
, APInt(8, Value
)),
165 ElementsAre(IsMovImmediate(llvm::X86::MOV8ri
, Reg
, Value
)));
168 TEST_F(Core2TargetTest
, SetRegToGR16Value
) {
169 const uint16_t Value
= 0xFFFFU
;
170 const unsigned Reg
= llvm::X86::BX
;
171 EXPECT_THAT(setRegTo(Reg
, APInt(16, Value
)),
172 ElementsAre(IsMovImmediate(llvm::X86::MOV16ri
, Reg
, Value
)));
175 TEST_F(Core2TargetTest
, SetRegToGR32Value
) {
176 const uint32_t Value
= 0x7FFFFU
;
177 const unsigned Reg
= llvm::X86::ECX
;
178 EXPECT_THAT(setRegTo(Reg
, APInt(32, Value
)),
179 ElementsAre(IsMovImmediate(llvm::X86::MOV32ri
, Reg
, Value
)));
182 TEST_F(Core2TargetTest
, SetRegToGR64Value
) {
183 const uint64_t Value
= 0x7FFFFFFFFFFFFFFFULL
;
184 const unsigned Reg
= llvm::X86::RDX
;
185 EXPECT_THAT(setRegTo(Reg
, APInt(64, Value
)),
186 ElementsAre(IsMovImmediate(llvm::X86::MOV64ri
, Reg
, Value
)));
189 TEST_F(Core2TargetTest
, SetRegToVR64Value
) {
191 setRegTo(llvm::X86::MM0
, APInt(64, 0x1111222233334444ULL
)),
192 ElementsAre(IsStackAllocate(8),
193 IsMovValueToStack(llvm::X86::MOV32mi
, 0x33334444UL
, 0),
194 IsMovValueToStack(llvm::X86::MOV32mi
, 0x11112222UL
, 4),
195 IsMovValueFromStack(llvm::X86::MMX_MOVQ64rm
, llvm::X86::MM0
),
196 IsStackDeallocate(8)));
199 TEST_F(Core2TargetTest
, SetRegToVR128Value_Use_MOVDQUrm
) {
201 setRegTo(llvm::X86::XMM0
,
202 APInt(128, "11112222333344445555666677778888", 16)),
203 ElementsAre(IsStackAllocate(16),
204 IsMovValueToStack(llvm::X86::MOV32mi
, 0x77778888UL
, 0),
205 IsMovValueToStack(llvm::X86::MOV32mi
, 0x55556666UL
, 4),
206 IsMovValueToStack(llvm::X86::MOV32mi
, 0x33334444UL
, 8),
207 IsMovValueToStack(llvm::X86::MOV32mi
, 0x11112222UL
, 12),
208 IsMovValueFromStack(llvm::X86::MOVDQUrm
, llvm::X86::XMM0
),
209 IsStackDeallocate(16)));
212 TEST_F(Core2AvxTargetTest
, SetRegToVR128Value_Use_VMOVDQUrm
) {
214 setRegTo(llvm::X86::XMM0
,
215 APInt(128, "11112222333344445555666677778888", 16)),
216 ElementsAre(IsStackAllocate(16),
217 IsMovValueToStack(llvm::X86::MOV32mi
, 0x77778888UL
, 0),
218 IsMovValueToStack(llvm::X86::MOV32mi
, 0x55556666UL
, 4),
219 IsMovValueToStack(llvm::X86::MOV32mi
, 0x33334444UL
, 8),
220 IsMovValueToStack(llvm::X86::MOV32mi
, 0x11112222UL
, 12),
221 IsMovValueFromStack(llvm::X86::VMOVDQUrm
, llvm::X86::XMM0
),
222 IsStackDeallocate(16)));
225 TEST_F(Core2Avx512TargetTest
, SetRegToVR128Value_Use_VMOVDQU32Z128rm
) {
227 setRegTo(llvm::X86::XMM0
,
228 APInt(128, "11112222333344445555666677778888", 16)),
231 IsMovValueToStack(llvm::X86::MOV32mi
, 0x77778888UL
, 0),
232 IsMovValueToStack(llvm::X86::MOV32mi
, 0x55556666UL
, 4),
233 IsMovValueToStack(llvm::X86::MOV32mi
, 0x33334444UL
, 8),
234 IsMovValueToStack(llvm::X86::MOV32mi
, 0x11112222UL
, 12),
235 IsMovValueFromStack(llvm::X86::VMOVDQU32Z128rm
, llvm::X86::XMM0
),
236 IsStackDeallocate(16)));
239 TEST_F(Core2AvxTargetTest
, SetRegToVR256Value_Use_VMOVDQUYrm
) {
240 const char ValueStr
[] =
241 "1111111122222222333333334444444455555555666666667777777788888888";
242 EXPECT_THAT(setRegTo(llvm::X86::YMM0
, APInt(256, ValueStr
, 16)),
244 {IsStackAllocate(32),
245 IsMovValueToStack(llvm::X86::MOV32mi
, 0x88888888UL
, 0),
246 IsMovValueToStack(llvm::X86::MOV32mi
, 0x77777777UL
, 4),
247 IsMovValueToStack(llvm::X86::MOV32mi
, 0x66666666UL
, 8),
248 IsMovValueToStack(llvm::X86::MOV32mi
, 0x55555555UL
, 12),
249 IsMovValueToStack(llvm::X86::MOV32mi
, 0x44444444UL
, 16),
250 IsMovValueToStack(llvm::X86::MOV32mi
, 0x33333333UL
, 20),
251 IsMovValueToStack(llvm::X86::MOV32mi
, 0x22222222UL
, 24),
252 IsMovValueToStack(llvm::X86::MOV32mi
, 0x11111111UL
, 28),
253 IsMovValueFromStack(llvm::X86::VMOVDQUYrm
, llvm::X86::YMM0
),
254 IsStackDeallocate(32)}));
257 TEST_F(Core2Avx512TargetTest
, SetRegToVR256Value_Use_VMOVDQU32Z256rm
) {
258 const char ValueStr
[] =
259 "1111111122222222333333334444444455555555666666667777777788888888";
261 setRegTo(llvm::X86::YMM0
, APInt(256, ValueStr
, 16)),
263 {IsStackAllocate(32),
264 IsMovValueToStack(llvm::X86::MOV32mi
, 0x88888888UL
, 0),
265 IsMovValueToStack(llvm::X86::MOV32mi
, 0x77777777UL
, 4),
266 IsMovValueToStack(llvm::X86::MOV32mi
, 0x66666666UL
, 8),
267 IsMovValueToStack(llvm::X86::MOV32mi
, 0x55555555UL
, 12),
268 IsMovValueToStack(llvm::X86::MOV32mi
, 0x44444444UL
, 16),
269 IsMovValueToStack(llvm::X86::MOV32mi
, 0x33333333UL
, 20),
270 IsMovValueToStack(llvm::X86::MOV32mi
, 0x22222222UL
, 24),
271 IsMovValueToStack(llvm::X86::MOV32mi
, 0x11111111UL
, 28),
272 IsMovValueFromStack(llvm::X86::VMOVDQU32Z256rm
, llvm::X86::YMM0
),
273 IsStackDeallocate(32)}));
276 TEST_F(Core2Avx512TargetTest
, SetRegToVR512Value
) {
277 const char ValueStr
[] =
278 "1111111122222222333333334444444455555555666666667777777788888888"
279 "99999999AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDDEEEEEEEEFFFFFFFF00000000";
281 setRegTo(llvm::X86::ZMM0
, APInt(512, ValueStr
, 16)),
283 {IsStackAllocate(64),
284 IsMovValueToStack(llvm::X86::MOV32mi
, 0x00000000UL
, 0),
285 IsMovValueToStack(llvm::X86::MOV32mi
, 0xFFFFFFFFUL
, 4),
286 IsMovValueToStack(llvm::X86::MOV32mi
, 0xEEEEEEEEUL
, 8),
287 IsMovValueToStack(llvm::X86::MOV32mi
, 0xDDDDDDDDUL
, 12),
288 IsMovValueToStack(llvm::X86::MOV32mi
, 0xCCCCCCCCUL
, 16),
289 IsMovValueToStack(llvm::X86::MOV32mi
, 0xBBBBBBBBUL
, 20),
290 IsMovValueToStack(llvm::X86::MOV32mi
, 0xAAAAAAAAUL
, 24),
291 IsMovValueToStack(llvm::X86::MOV32mi
, 0x99999999UL
, 28),
292 IsMovValueToStack(llvm::X86::MOV32mi
, 0x88888888UL
, 32),
293 IsMovValueToStack(llvm::X86::MOV32mi
, 0x77777777UL
, 36),
294 IsMovValueToStack(llvm::X86::MOV32mi
, 0x66666666UL
, 40),
295 IsMovValueToStack(llvm::X86::MOV32mi
, 0x55555555UL
, 44),
296 IsMovValueToStack(llvm::X86::MOV32mi
, 0x44444444UL
, 48),
297 IsMovValueToStack(llvm::X86::MOV32mi
, 0x33333333UL
, 52),
298 IsMovValueToStack(llvm::X86::MOV32mi
, 0x22222222UL
, 56),
299 IsMovValueToStack(llvm::X86::MOV32mi
, 0x11111111UL
, 60),
300 IsMovValueFromStack(llvm::X86::VMOVDQU32Zrm
, llvm::X86::ZMM0
),
301 IsStackDeallocate(64)}));
304 // Note: We always put 80 bits on the stack independently of the size of the
305 // value. This uses a bit more space but makes the code simpler.
307 TEST_F(Core2TargetTest
, SetRegToST0_32Bits
) {
309 setRegTo(llvm::X86::ST0
, 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
), IsStackDeallocate(10)));
317 TEST_F(Core2TargetTest
, SetRegToST1_32Bits
) {
318 const MCInst CopySt0ToSt1
=
319 llvm::MCInstBuilder(llvm::X86::ST_Frr
).addReg(llvm::X86::ST1
);
321 setRegTo(llvm::X86::ST1
, APInt(32, 0x11112222ULL
)),
322 ElementsAre(IsStackAllocate(10),
323 IsMovValueToStack(llvm::X86::MOV32mi
, 0x11112222UL
, 0),
324 IsMovValueToStack(llvm::X86::MOV32mi
, 0x00000000UL
, 4),
325 IsMovValueToStack(llvm::X86::MOV16mi
, 0x0000UL
, 8),
326 OpcodeIs(llvm::X86::LD_F80m
), CopySt0ToSt1
,
327 IsStackDeallocate(10)));
330 TEST_F(Core2TargetTest
, SetRegToST0_64Bits
) {
332 setRegTo(llvm::X86::ST0
, APInt(64, 0x1111222233334444ULL
)),
333 ElementsAre(IsStackAllocate(10),
334 IsMovValueToStack(llvm::X86::MOV32mi
, 0x33334444UL
, 0),
335 IsMovValueToStack(llvm::X86::MOV32mi
, 0x11112222UL
, 4),
336 IsMovValueToStack(llvm::X86::MOV16mi
, 0x0000UL
, 8),
337 OpcodeIs(llvm::X86::LD_F80m
), IsStackDeallocate(10)));
340 TEST_F(Core2TargetTest
, SetRegToST0_80Bits
) {
342 setRegTo(llvm::X86::ST0
, APInt(80, "11112222333344445555", 16)),
343 ElementsAre(IsStackAllocate(10),
344 IsMovValueToStack(llvm::X86::MOV32mi
, 0x44445555UL
, 0),
345 IsMovValueToStack(llvm::X86::MOV32mi
, 0x22223333UL
, 4),
346 IsMovValueToStack(llvm::X86::MOV16mi
, 0x1111UL
, 8),
347 OpcodeIs(llvm::X86::LD_F80m
), IsStackDeallocate(10)));
350 TEST_F(Core2TargetTest
, SetRegToFP0_80Bits
) {
352 setRegTo(llvm::X86::FP0
, APInt(80, "11112222333344445555", 16)),
353 ElementsAre(IsStackAllocate(10),
354 IsMovValueToStack(llvm::X86::MOV32mi
, 0x44445555UL
, 0),
355 IsMovValueToStack(llvm::X86::MOV32mi
, 0x22223333UL
, 4),
356 IsMovValueToStack(llvm::X86::MOV16mi
, 0x1111UL
, 8),
357 OpcodeIs(llvm::X86::LD_Fp80m
), IsStackDeallocate(10)));
360 TEST_F(Core2TargetTest
, SetRegToFP1_32Bits
) {
362 setRegTo(llvm::X86::FP1
, APInt(32, 0x11112222ULL
)),
363 ElementsAre(IsStackAllocate(10),
364 IsMovValueToStack(llvm::X86::MOV32mi
, 0x11112222UL
, 0),
365 IsMovValueToStack(llvm::X86::MOV32mi
, 0x00000000UL
, 4),
366 IsMovValueToStack(llvm::X86::MOV16mi
, 0x0000UL
, 8),
367 OpcodeIs(llvm::X86::LD_Fp80m
), IsStackDeallocate(10)));
370 TEST_F(Core2TargetTest
, SetRegToFP1_4Bits
) {
372 setRegTo(llvm::X86::FP1
, APInt(4, 0x1ULL
)),
373 ElementsAre(IsStackAllocate(10),
374 IsMovValueToStack(llvm::X86::MOV32mi
, 0x00000001UL
, 0),
375 IsMovValueToStack(llvm::X86::MOV32mi
, 0x00000000UL
, 4),
376 IsMovValueToStack(llvm::X86::MOV16mi
, 0x0000UL
, 8),
377 OpcodeIs(llvm::X86::LD_Fp80m
), IsStackDeallocate(10)));
380 TEST_F(Core2Avx512TargetTest
, FillMemoryOperands_ADD64rm
) {
381 Instruction
I(State
.getInstrInfo(), State
.getRATC(), X86::ADD64rm
);
382 InstructionTemplate
IT(I
);
383 constexpr const int kOffset
= 42;
384 State
.getExegesisTarget().fillMemoryOperands(IT
, X86::RDI
, kOffset
);
385 // Memory is operands 2-6.
386 EXPECT_THAT(IT
.getValueFor(I
.Operands
[2]), IsReg(X86::RDI
));
387 EXPECT_THAT(IT
.getValueFor(I
.Operands
[3]), IsImm(1));
388 EXPECT_THAT(IT
.getValueFor(I
.Operands
[4]), IsReg(0));
389 EXPECT_THAT(IT
.getValueFor(I
.Operands
[5]), IsImm(kOffset
));
390 EXPECT_THAT(IT
.getValueFor(I
.Operands
[6]), IsReg(0));
393 TEST_F(Core2Avx512TargetTest
, FillMemoryOperands_VGATHERDPSZ128rm
) {
394 Instruction
I(State
.getInstrInfo(), State
.getRATC(), X86::VGATHERDPSZ128rm
);
395 InstructionTemplate
IT(I
);
396 constexpr const int kOffset
= 42;
397 State
.getExegesisTarget().fillMemoryOperands(IT
, X86::RDI
, kOffset
);
398 // Memory is operands 4-8.
399 EXPECT_THAT(IT
.getValueFor(I
.Operands
[4]), IsReg(X86::RDI
));
400 EXPECT_THAT(IT
.getValueFor(I
.Operands
[5]), IsImm(1));
401 EXPECT_THAT(IT
.getValueFor(I
.Operands
[6]), IsReg(0));
402 EXPECT_THAT(IT
.getValueFor(I
.Operands
[7]), IsImm(kOffset
));
403 EXPECT_THAT(IT
.getValueFor(I
.Operands
[8]), IsReg(0));
407 } // namespace exegesis