llvm-project
551 строка · 20.8 Кб
1//===-- SnippetGeneratorTest.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 "../Common/AssemblerUtils.h"
10#include "LlvmState.h"
11#include "MCInstrDescView.h"
12#include "ParallelSnippetGenerator.h"
13#include "RegisterAliasing.h"
14#include "SerialSnippetGenerator.h"
15#include "TestBase.h"
16#include "X86InstrInfo.h"
17#include "llvm/ADT/SetOperations.h"
18
19#include <unordered_set>
20
21namespace llvm {
22namespace exegesis {
23
24void InitializeX86ExegesisTarget();
25
26namespace {
27
28using testing::AnyOf;
29using testing::ElementsAre;
30using testing::Gt;
31using testing::HasSubstr;
32using testing::IsEmpty;
33using testing::Not;
34using testing::SizeIs;
35
36MATCHER(IsInvalid, "") { return !arg.isValid(); }
37MATCHER(IsReg, "") { return arg.isReg(); }
38
39template <typename SnippetGeneratorT>
40class X86SnippetGeneratorTest : public X86TestBase {
41protected:
42X86SnippetGeneratorTest() : Generator(State, SnippetGenerator::Options()),
43InstrInfo(State.getInstrInfo()) {}
44
45std::vector<CodeTemplate> checkAndGetCodeTemplates(unsigned Opcode) {
46randomGenerator().seed(0); // Initialize seed.
47const Instruction &Instr = State.getIC().getInstr(Opcode);
48auto CodeTemplateOrError = Generator.generateCodeTemplates(
49&Instr, State.getRATC().emptyRegisters());
50EXPECT_FALSE(CodeTemplateOrError.takeError()); // Valid configuration.
51return std::move(CodeTemplateOrError.get());
52}
53
54SnippetGeneratorT Generator;
55const MCInstrInfo &InstrInfo;
56};
57
58using X86SerialSnippetGeneratorTest = X86SnippetGeneratorTest<SerialSnippetGenerator>;
59
60using X86ParallelSnippetGeneratorTest =
61X86SnippetGeneratorTest<ParallelSnippetGenerator>;
62
63TEST_F(X86SerialSnippetGeneratorTest, ImplicitSelfDependencyThroughImplicitReg) {
64// - ADC16i16
65// - Op0 Explicit Use Immediate
66// - Op1 Implicit Def Reg(AX)
67// - Op2 Implicit Def Reg(EFLAGS)
68// - Op3 Implicit Use Reg(AX)
69// - Op4 Implicit Use Reg(EFLAGS)
70// - Var0 [Op0]
71// - hasAliasingImplicitRegisters (execution is always serial)
72// - hasAliasingRegisters
73const unsigned Opcode = X86::ADC16i16;
74EXPECT_THAT(InstrInfo.get(Opcode).implicit_defs()[0], X86::AX);
75EXPECT_THAT(InstrInfo.get(Opcode).implicit_defs()[1], X86::EFLAGS);
76EXPECT_THAT(InstrInfo.get(Opcode).implicit_uses()[0], X86::AX);
77EXPECT_THAT(InstrInfo.get(Opcode).implicit_uses()[1], X86::EFLAGS);
78const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
79ASSERT_THAT(CodeTemplates, SizeIs(1));
80const auto &CT = CodeTemplates[0];
81EXPECT_THAT(CT.Execution, ExecutionMode::ALWAYS_SERIAL_IMPLICIT_REGS_ALIAS);
82ASSERT_THAT(CT.Instructions, SizeIs(1));
83const InstructionTemplate &IT = CT.Instructions[0];
84EXPECT_THAT(IT.getOpcode(), Opcode);
85ASSERT_THAT(IT.getVariableValues(), SizeIs(1)); // Imm.
86EXPECT_THAT(IT.getVariableValues()[0], IsInvalid()) << "Immediate is not set";
87}
88
89TEST_F(X86SerialSnippetGeneratorTest, ImplicitSelfDependencyThroughTiedRegs) {
90// - ADD16ri
91// - Op0 Explicit Def RegClass(GR16)
92// - Op1 Explicit Use RegClass(GR16) TiedToOp0
93// - Op2 Explicit Use Immediate
94// - Op3 Implicit Def Reg(EFLAGS)
95// - Var0 [Op0,Op1]
96// - Var1 [Op2]
97// - hasTiedRegisters (execution is always serial)
98// - hasAliasingRegisters
99const unsigned Opcode = X86::ADD16ri;
100EXPECT_THAT(InstrInfo.get(Opcode).implicit_defs()[0], X86::EFLAGS);
101const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
102ASSERT_THAT(CodeTemplates, SizeIs(1));
103const auto &CT = CodeTemplates[0];
104EXPECT_THAT(CT.Execution, ExecutionMode::ALWAYS_SERIAL_TIED_REGS_ALIAS);
105ASSERT_THAT(CT.Instructions, SizeIs(1));
106const InstructionTemplate &IT = CT.Instructions[0];
107EXPECT_THAT(IT.getOpcode(), Opcode);
108ASSERT_THAT(IT.getVariableValues(), SizeIs(2));
109EXPECT_THAT(IT.getVariableValues()[0], IsInvalid()) << "Operand 1 is not set";
110EXPECT_THAT(IT.getVariableValues()[1], IsInvalid()) << "Operand 2 is not set";
111}
112
113TEST_F(X86SerialSnippetGeneratorTest, ImplicitSelfDependencyThroughExplicitRegs) {
114// - VXORPSrr
115// - Op0 Explicit Def RegClass(VR128)
116// - Op1 Explicit Use RegClass(VR128)
117// - Op2 Explicit Use RegClass(VR128)
118// - Var0 [Op0]
119// - Var1 [Op1]
120// - Var2 [Op2]
121// - hasAliasingRegisters
122const unsigned Opcode = X86::VXORPSrr;
123const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
124ASSERT_THAT(CodeTemplates, SizeIs(1));
125const auto &CT = CodeTemplates[0];
126EXPECT_THAT(CT.Execution, ExecutionMode::SERIAL_VIA_EXPLICIT_REGS);
127ASSERT_THAT(CT.Instructions, SizeIs(1));
128const InstructionTemplate &IT = CT.Instructions[0];
129EXPECT_THAT(IT.getOpcode(), Opcode);
130ASSERT_THAT(IT.getVariableValues(), SizeIs(3));
131EXPECT_THAT(IT.getVariableValues(),
132AnyOf(ElementsAre(IsReg(), IsInvalid(), IsReg()),
133ElementsAre(IsReg(), IsReg(), IsInvalid())))
134<< "Op0 is either set to Op1 or to Op2";
135}
136
137TEST_F(X86SerialSnippetGeneratorTest,
138ImplicitSelfDependencyThroughExplicitRegsForbidAll) {
139// - VXORPSrr
140// - Op0 Explicit Def RegClass(VR128)
141// - Op1 Explicit Use RegClass(VR128)
142// - Op2 Explicit Use RegClass(VR128)
143// - Var0 [Op0]
144// - Var1 [Op1]
145// - Var2 [Op2]
146// - hasAliasingRegisters
147const unsigned Opcode = X86::VXORPSrr;
148randomGenerator().seed(0); // Initialize seed.
149const Instruction &Instr = State.getIC().getInstr(Opcode);
150auto AllRegisters = State.getRATC().emptyRegisters();
151AllRegisters.flip();
152auto Error =
153Generator.generateCodeTemplates(&Instr, AllRegisters).takeError();
154EXPECT_TRUE((bool)Error);
155consumeError(std::move(Error));
156}
157
158TEST_F(X86SerialSnippetGeneratorTest,
159ImplicitSelfDependencyThroughExplicitRegsForbidAlmostAll) {
160// - VXORPSrr
161// - Op0 Explicit Def RegClass(VR128)
162// - Op1 Explicit Use RegClass(VR128)
163// - Op2 Explicit Use RegClass(VR128)
164// - Var0 [Op0]
165// - Var1 [Op1]
166// - Var2 [Op2]
167// - hasAliasingRegisters
168const unsigned Opcode = X86::VXORPSrr;
169randomGenerator().seed(0); // Initialize seed.
170const Instruction &Instr = State.getIC().getInstr(Opcode);
171auto ForbiddenRegisters = State.getRATC().emptyRegisters();
172ForbiddenRegisters.flip();
173ForbiddenRegisters.reset(X86::XMM0);
174auto Error = Generator.generateCodeTemplates(&Instr, ForbiddenRegisters);
175EXPECT_FALSE((bool)Error.takeError());
176auto CodeTemplates = std::move(Error.get());
177ASSERT_THAT(CodeTemplates, SizeIs(Gt(0U))) << "Templates are available";
178for (const auto &CT : CodeTemplates) {
179EXPECT_THAT(CT.Execution, ExecutionMode::SERIAL_VIA_EXPLICIT_REGS);
180ASSERT_THAT(CT.Instructions, SizeIs(1));
181const InstructionTemplate &IT = CT.Instructions[0];
182EXPECT_THAT(IT.getOpcode(), Opcode);
183ASSERT_THAT(IT.getVariableValues(), SizeIs(3));
184for (const auto &Var : IT.getVariableValues()) {
185if (Var.isReg()) {
186EXPECT_FALSE(ForbiddenRegisters[Var.getReg()]);
187}
188}
189}
190}
191
192TEST_F(X86SerialSnippetGeneratorTest, DependencyThroughOtherOpcode) {
193// - CMP64rr
194// - Op0 Explicit Use RegClass(GR64)
195// - Op1 Explicit Use RegClass(GR64)
196// - Op2 Implicit Def Reg(EFLAGS)
197// - Var0 [Op0]
198// - Var1 [Op1]
199const unsigned Opcode = X86::CMP64rr;
200const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
201ASSERT_THAT(CodeTemplates, SizeIs(Gt(1U))) << "Many templates are available";
202for (const auto &CT : CodeTemplates) {
203EXPECT_THAT(CT.Execution, ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR);
204ASSERT_THAT(CT.Instructions, SizeIs(2));
205const InstructionTemplate &IT = CT.Instructions[0];
206EXPECT_THAT(IT.getOpcode(), Opcode);
207ASSERT_THAT(IT.getVariableValues(), SizeIs(2));
208EXPECT_THAT(IT.getVariableValues(),
209AnyOf(ElementsAre(IsReg(), IsInvalid()),
210ElementsAre(IsInvalid(), IsReg())));
211EXPECT_THAT(CT.Instructions[1].getOpcode(), Not(Opcode));
212// TODO: check that the two instructions alias each other.
213}
214}
215
216TEST_F(X86SerialSnippetGeneratorTest, LAHF) {
217// - LAHF
218// - Op0 Implicit Def Reg(AH)
219// - Op1 Implicit Use Reg(EFLAGS)
220const unsigned Opcode = X86::LAHF;
221const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
222ASSERT_THAT(CodeTemplates, SizeIs(Gt(1U))) << "Many templates are available";
223for (const auto &CT : CodeTemplates) {
224EXPECT_THAT(CT.Execution, ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR);
225ASSERT_THAT(CT.Instructions, SizeIs(2));
226const InstructionTemplate &IT = CT.Instructions[0];
227EXPECT_THAT(IT.getOpcode(), Opcode);
228ASSERT_THAT(IT.getVariableValues(), SizeIs(0));
229}
230}
231
232TEST_F(X86SerialSnippetGeneratorTest, VCVTUSI642SDZrrb_Int) {
233// - VCVTUSI642SDZrrb_Int
234// - Op0 Explicit Def RegClass(VR128X)
235// - Op1 Explicit Use RegClass(VR128X)
236// - Op2 Explicit Use STATIC_ROUNDING
237// - Op2 Explicit Use RegClass(GR64)
238// - Op4 Implicit Use Reg(MXSCR)
239const unsigned Opcode = X86::VCVTUSI642SDZrrb_Int;
240const Instruction &Instr = State.getIC().getInstr(Opcode);
241std::vector<BenchmarkCode> Configs;
242auto Error = Generator.generateConfigurations(
243&Instr, Configs, State.getRATC().emptyRegisters());
244ASSERT_FALSE(Error);
245ASSERT_THAT(Configs, SizeIs(1));
246const BenchmarkCode &BC = Configs[0];
247ASSERT_THAT(BC.Key.Instructions, SizeIs(1));
248ASSERT_TRUE(BC.Key.Instructions[0].getOperand(3).isImm());
249}
250
251TEST_F(X86ParallelSnippetGeneratorTest, SerialInstruction) {
252// - CDQ
253// - Op0 Implicit Def Reg(EAX)
254// - Op1 Implicit Def Reg(EDX)
255// - Op2 Implicit Use Reg(EAX)
256// - hasAliasingImplicitRegisters (execution is always serial)
257// - hasAliasingRegisters
258const unsigned Opcode = X86::CDQ;
259const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
260ASSERT_THAT(CodeTemplates, SizeIs(1));
261const auto &CT = CodeTemplates[0];
262EXPECT_THAT(CT.Info, HasSubstr("serial"));
263EXPECT_THAT(CT.Execution, ExecutionMode::UNKNOWN);
264ASSERT_THAT(CT.Instructions, SizeIs(1));
265const InstructionTemplate &IT = CT.Instructions[0];
266EXPECT_THAT(IT.getOpcode(), Opcode);
267ASSERT_THAT(IT.getVariableValues(), SizeIs(0));
268}
269
270TEST_F(X86ParallelSnippetGeneratorTest, ReadAfterWrite_CMOV32rr) {
271// CMOV32rr has tied variables, we enumerate the possible values to execute
272// as many in parallel as possible.
273
274// - CMOV32rr
275// - Op0 Explicit Def RegClass(GR32)
276// - Op1 Explicit Use RegClass(GR32) TiedToOp0
277// - Op2 Explicit Use RegClass(GR32)
278// - Op3 Explicit Use Immediate
279// - Op3 Implicit Use Reg(EFLAGS)
280// - Var0 [Op0,Op1]
281// - Var1 [Op2]
282// - hasTiedRegisters (execution is always serial)
283// - hasAliasingRegisters
284const unsigned Opcode = X86::CMOV32rr;
285const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
286ASSERT_THAT(CodeTemplates, SizeIs(2));
287for (const auto &CT : CodeTemplates) {
288EXPECT_THAT(CT.Info, HasSubstr("avoiding Read-After-Write issue"));
289EXPECT_THAT(CT.Execution, ExecutionMode::UNKNOWN);
290ASSERT_GT(CT.Instructions.size(), 1U);
291std::unordered_set<unsigned> AllDefRegisters;
292std::unordered_set<unsigned> AllUseRegisters;
293for (const auto &IT : CT.Instructions) {
294ASSERT_THAT(IT.getVariableValues(), SizeIs(3));
295AllDefRegisters.insert(IT.getVariableValues()[0].getReg());
296AllUseRegisters.insert(IT.getVariableValues()[1].getReg());
297}
298EXPECT_THAT(AllDefRegisters, SizeIs(CT.Instructions.size()))
299<< "Each instruction writes to a different register";
300EXPECT_THAT(AllUseRegisters, Not(IsEmpty()))
301<< "In total, some other registers are used";
302auto AllDefAndUseRegs = AllUseRegisters;
303llvm::set_intersect(AllDefAndUseRegs, AllDefRegisters); // A := A ^ B
304EXPECT_THAT(AllDefAndUseRegs, IsEmpty())
305<< "No instruction uses any register defined by any of the "
306"instructions";
307}
308}
309
310TEST_F(X86ParallelSnippetGeneratorTest, ReadAfterWrite_VFMADD132PDr) {
311// VFMADD132PDr has tied variables, we enumerate the possible values
312// to execute as many in parallel as possible.
313
314// - VFMADD132PDr
315// - Op0 Explicit Def RegClass(XMM)
316// - Op1 Explicit Use RegClass(XMM) TiedToOp0
317// - Op2 Explicit Use RegClass(XMM)
318// - Op3 Explicit Use RegClass(XMM)
319// - Var0 [Op0,Op1]
320// - Var1 [Op2]
321// - Var2 [Op3]
322// - hasTiedRegisters (execution is always serial)
323// - hasAliasingRegisters
324const unsigned Opcode = X86::VFMADD132PDr;
325const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
326ASSERT_THAT(CodeTemplates, SizeIs(3));
327for (const auto &CT : CodeTemplates) {
328EXPECT_THAT(CT.Info, HasSubstr("avoiding Read-After-Write issue"));
329EXPECT_THAT(CT.Execution, ExecutionMode::UNKNOWN);
330ASSERT_GT(CT.Instructions.size(), 1U);
331std::unordered_set<unsigned> AllDefRegisters;
332std::unordered_set<unsigned> AllUseRegisters;
333for (const auto &IT : CT.Instructions) {
334ASSERT_THAT(IT.getVariableValues(), SizeIs(3));
335AllDefRegisters.insert(IT.getVariableValues()[0].getReg());
336AllUseRegisters.insert(IT.getVariableValues()[1].getReg());
337AllUseRegisters.insert(IT.getVariableValues()[2].getReg());
338}
339EXPECT_THAT(AllDefRegisters, SizeIs(CT.Instructions.size()))
340<< "Each instruction writes to a different register";
341EXPECT_THAT(AllUseRegisters, Not(IsEmpty()))
342<< "In total, some other registers are used";
343auto AllDefAndUseRegs = AllUseRegisters;
344llvm::set_intersect(AllDefAndUseRegs, AllDefRegisters); // A := A ^ B
345EXPECT_THAT(AllDefAndUseRegs, IsEmpty())
346<< "No instruction uses any register defined by any of the "
347"instructions";
348}
349}
350
351TEST_F(X86ParallelSnippetGeneratorTest, NoTiedVariables) {
352// CMOV_GR32 has no tied variables, we make sure def and use are different
353// from each other.
354
355// - CMOV_GR32
356// - Op0 Explicit Def RegClass(GR32)
357// - Op1 Explicit Use RegClass(GR32)
358// - Op2 Explicit Use RegClass(GR32)
359// - Op3 Explicit Use Immediate
360// - Op4 Implicit Use Reg(EFLAGS)
361// - Var0 [Op0]
362// - Var1 [Op1]
363// - Var2 [Op2]
364// - Var3 [Op3]
365// - hasAliasingRegisters
366const unsigned Opcode = X86::CMOV_GR32;
367const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
368ASSERT_THAT(CodeTemplates, SizeIs(2));
369for (const auto &CT : CodeTemplates) {
370EXPECT_THAT(CT.Info, HasSubstr("no tied variables"));
371EXPECT_THAT(CT.Execution, ExecutionMode::UNKNOWN);
372ASSERT_THAT(CT.Instructions, SizeIs(1));
373const InstructionTemplate &IT = CT.Instructions[0];
374EXPECT_THAT(IT.getOpcode(), Opcode);
375ASSERT_THAT(IT.getVariableValues(), SizeIs(4));
376EXPECT_THAT(IT.getVariableValues()[0].getReg(),
377Not(IT.getVariableValues()[1].getReg()))
378<< "Def is different from first Use";
379EXPECT_THAT(IT.getVariableValues()[0].getReg(),
380Not(IT.getVariableValues()[2].getReg()))
381<< "Def is different from second Use";
382EXPECT_THAT(IT.getVariableValues()[3], IsInvalid());
383}
384}
385
386TEST_F(X86ParallelSnippetGeneratorTest, MemoryUse) {
387// Mov32rm reads from memory.
388// - MOV32rm
389// - Op0 Explicit Def RegClass(GR32)
390// - Op1 Explicit Use Memory RegClass(GR8)
391// - Op2 Explicit Use Memory
392// - Op3 Explicit Use Memory RegClass(GRH8)
393// - Op4 Explicit Use Memory
394// - Op5 Explicit Use Memory RegClass(SEGMENT_REG)
395// - Var0 [Op0]
396// - Var1 [Op1]
397// - Var2 [Op2]
398// - Var3 [Op3]
399// - Var4 [Op4]
400// - Var5 [Op5]
401// - hasMemoryOperands
402// - hasAliasingRegisters
403const unsigned Opcode = X86::MOV32rm;
404const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
405ASSERT_THAT(CodeTemplates, SizeIs(1));
406for (const auto &CT : CodeTemplates) {
407EXPECT_THAT(CT.Info, HasSubstr("no tied variables"));
408EXPECT_THAT(CT.Execution, ExecutionMode::UNKNOWN);
409ASSERT_THAT(CT.Instructions,
410SizeIs(ParallelSnippetGenerator::kMinNumDifferentAddresses));
411const InstructionTemplate &IT = CT.Instructions[0];
412EXPECT_THAT(IT.getOpcode(), Opcode);
413ASSERT_THAT(IT.getVariableValues(), SizeIs(6));
414EXPECT_EQ(IT.getVariableValues()[2].getImm(), 1);
415EXPECT_EQ(IT.getVariableValues()[3].getReg(), 0u);
416EXPECT_EQ(IT.getVariableValues()[4].getImm(), 0);
417EXPECT_EQ(IT.getVariableValues()[5].getReg(), 0u);
418}
419}
420
421TEST_F(X86ParallelSnippetGeneratorTest, MOV16ms) {
422const unsigned Opcode = X86::MOV16ms;
423const Instruction &Instr = State.getIC().getInstr(Opcode);
424std::vector<BenchmarkCode> Benchmarks;
425auto Err = Generator.generateConfigurations(&Instr, Benchmarks,
426State.getRATC().emptyRegisters());
427EXPECT_TRUE((bool)Err);
428EXPECT_THAT(toString(std::move(Err)),
429testing::HasSubstr("no available registers"));
430}
431
432TEST_F(X86ParallelSnippetGeneratorTest,
433AvoidSerializingThroughImplicitRegisters) {
434// MULX32rr implicitly uses EDX. We should not select that register to avoid
435// serialization.
436const unsigned Opcode = X86::MULX32rr;
437randomGenerator().seed(0); // Initialize seed.
438const Instruction &Instr = State.getIC().getInstr(Opcode);
439// Forbid all registers but RDX/EDX/DX/DH/DL. The only option would be to
440// choose that register, but that would serialize the instruction, so we
441// should be returning an error.
442auto AllRegisters = State.getRATC().emptyRegisters();
443AllRegisters.flip();
444AllRegisters.reset(X86::RDX);
445AllRegisters.reset(X86::EDX);
446AllRegisters.reset(X86::DX);
447AllRegisters.reset(X86::DH);
448AllRegisters.reset(X86::DL);
449auto Err = Generator.generateCodeTemplates(&Instr, AllRegisters);
450EXPECT_FALSE((bool)Err);
451EXPECT_THAT(toString(Err.takeError()),
452testing::HasSubstr("Failed to produce any snippet"));
453}
454
455class X86FakeSnippetGenerator : public SnippetGenerator {
456public:
457X86FakeSnippetGenerator(const LLVMState &State, const Options &Opts)
458: SnippetGenerator(State, Opts) {}
459
460const Instruction &getInstr(unsigned Opcode) {
461return State.getIC().getInstr(Opcode);
462}
463
464InstructionTemplate getInstructionTemplate(unsigned Opcode) {
465return {&getInstr(Opcode)};
466}
467
468private:
469Expected<std::vector<CodeTemplate>>
470generateCodeTemplates(InstructionTemplate, const BitVector &) const override {
471return make_error<StringError>("not implemented", inconvertibleErrorCode());
472}
473};
474
475using X86FakeSnippetGeneratorTest = X86SnippetGeneratorTest<X86FakeSnippetGenerator>;
476
477testing::Matcher<const RegisterValue &> IsRegisterValue(unsigned Reg,
478APInt Value) {
479return testing::AllOf(testing::Field(&RegisterValue::Register, Reg),
480testing::Field(&RegisterValue::Value, Value));
481}
482
483TEST_F(X86FakeSnippetGeneratorTest, MemoryUse_Movsb) {
484// MOVSB writes to scratch memory register.
485// - MOVSB
486// - Op0 Explicit Use Memory RegClass(GR8)
487// - Op1 Explicit Use Memory RegClass(GR8)
488// - Op2 Explicit Use Memory RegClass(SEGMENT_REG)
489// - Op3 Implicit Def Reg(EDI)
490// - Op4 Implicit Def Reg(ESI)
491// - Op5 Implicit Use Reg(EDI)
492// - Op6 Implicit Use Reg(ESI)
493// - Op7 Implicit Use Reg(DF)
494// - Var0 [Op0]
495// - Var1 [Op1]
496// - Var2 [Op2]
497// - hasMemoryOperands
498// - hasAliasingImplicitRegisters (execution is always serial)
499// - hasAliasingRegisters
500const unsigned Opcode = X86::MOVSB;
501const Instruction &Instr = State.getIC().getInstr(Opcode);
502std::vector<BenchmarkCode> Benchmarks;
503auto Error = Generator.generateConfigurations(
504&Instr, Benchmarks, State.getRATC().emptyRegisters());
505EXPECT_TRUE((bool)Error);
506consumeError(std::move(Error));
507}
508
509TEST_F(X86FakeSnippetGeneratorTest, ComputeRegisterInitialValuesAdd16ri) {
510// ADD16ri:
511// explicit def 0 : reg RegClass=GR16
512// explicit use 1 : reg RegClass=GR16 | TIED_TO:0
513// explicit use 2 : imm
514// implicit def : EFLAGS
515InstructionTemplate IT = Generator.getInstructionTemplate(X86::ADD16ri);
516IT.getValueFor(IT.getInstr().Variables[0]) = MCOperand::createReg(X86::AX);
517std::vector<InstructionTemplate> Snippet;
518Snippet.push_back(std::move(IT));
519const auto RIV = Generator.computeRegisterInitialValues(Snippet);
520EXPECT_THAT(RIV, ElementsAre(IsRegisterValue(X86::AX, APInt())));
521}
522
523TEST_F(X86FakeSnippetGeneratorTest, ComputeRegisterInitialValuesAdd64rr) {
524// ADD64rr:
525// mov64ri rax, 42
526// add64rr rax, rax, rbx
527// -> only rbx needs defining.
528std::vector<InstructionTemplate> Snippet;
529{
530InstructionTemplate Mov = Generator.getInstructionTemplate(X86::MOV64ri);
531Mov.getValueFor(Mov.getInstr().Variables[0]) =
532MCOperand::createReg(X86::RAX);
533Mov.getValueFor(Mov.getInstr().Variables[1]) = MCOperand::createImm(42);
534Snippet.push_back(std::move(Mov));
535}
536{
537InstructionTemplate Add = Generator.getInstructionTemplate(X86::ADD64rr);
538Add.getValueFor(Add.getInstr().Variables[0]) =
539MCOperand::createReg(X86::RAX);
540Add.getValueFor(Add.getInstr().Variables[1]) =
541MCOperand::createReg(X86::RBX);
542Snippet.push_back(std::move(Add));
543}
544
545const auto RIV = Generator.computeRegisterInitialValues(Snippet);
546EXPECT_THAT(RIV, ElementsAre(IsRegisterValue(X86::RBX, APInt())));
547}
548
549} // namespace
550} // namespace exegesis
551} // namespace llvm
552