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