From b60c7a53606266a6886948c5fa0c6012f043824b Mon Sep 17 00:00:00 2001 From: Clement Courbet Date: Wed, 22 Jan 2020 15:49:10 +0100 Subject: [PATCH] [llvm-exegesis] Allow the randomizer to fail nicely... Summary: ... instead of crashing. On typical exmaple is when there are no available registers. Reviewers: gchatelet Subscribers: tschuett, mstojanovic, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D73196 --- tools/llvm-exegesis/lib/RegisterAliasing.cpp | 9 ++++ tools/llvm-exegesis/lib/RegisterAliasing.h | 3 ++ tools/llvm-exegesis/lib/SnippetGenerator.cpp | 51 ++++++++++++++++--- tools/llvm-exegesis/lib/SnippetGenerator.h | 6 +-- tools/llvm-exegesis/lib/Target.cpp | 24 --------- tools/llvm-exegesis/lib/Target.h | 16 +++--- tools/llvm-exegesis/lib/X86/Target.cpp | 17 ++++--- .../X86/SnippetGeneratorTest.cpp | 11 ++++ 8 files changed, 90 insertions(+), 47 deletions(-) diff --git a/tools/llvm-exegesis/lib/RegisterAliasing.cpp b/tools/llvm-exegesis/lib/RegisterAliasing.cpp index 1db19524015..ee612fb0dd6 100644 --- a/tools/llvm-exegesis/lib/RegisterAliasing.cpp +++ b/tools/llvm-exegesis/lib/RegisterAliasing.cpp @@ -79,5 +79,14 @@ RegisterAliasingTrackerCache::getRegisterClass(unsigned RegClassIndex) const { return *Found; } +std::string debugString(const MCRegisterInfo &RegInfo, const BitVector &Regs) { + std::string Result; + for (const unsigned Reg : Regs.set_bits()) { + Result.append(RegInfo.getName(Reg)); + Result.push_back(' '); + } + return Result; +} + } // namespace exegesis } // namespace llvm diff --git a/tools/llvm-exegesis/lib/RegisterAliasing.h b/tools/llvm-exegesis/lib/RegisterAliasing.h index f269c89a3f9..b2980854ba2 100644 --- a/tools/llvm-exegesis/lib/RegisterAliasing.h +++ b/tools/llvm-exegesis/lib/RegisterAliasing.h @@ -110,6 +110,9 @@ inline void remove(BitVector &A, const BitVector &B) { A.reset(I); } +// Returns a debug string for the list of registers. +std::string debugString(const MCRegisterInfo &RegInfo, const BitVector &Regs); + } // namespace exegesis } // namespace llvm diff --git a/tools/llvm-exegesis/lib/SnippetGenerator.cpp b/tools/llvm-exegesis/lib/SnippetGenerator.cpp index d1f168fe43b..af3709486ec 100644 --- a/tools/llvm-exegesis/lib/SnippetGenerator.cpp +++ b/tools/llvm-exegesis/lib/SnippetGenerator.cpp @@ -72,7 +72,8 @@ Expected> SnippetGenerator::generateConfigurations( BenchmarkCode BC; BC.Info = CT.Info; for (InstructionTemplate &IT : CT.Instructions) { - randomizeUnsetVariables(State.getExegesisTarget(), ForbiddenRegs, IT); + if (auto error = randomizeUnsetVariables(State, ForbiddenRegs, IT)) + return std::move(error); BC.Key.Instructions.push_back(IT.build()); } if (CT.ScratchSpacePointerInReg) @@ -215,15 +216,53 @@ void setRandomAliasing(const AliasingConfigurations &AliasingConfigurations, setRegisterOperandValue(randomElement(RandomConf.Uses), UseIB); } -void randomizeUnsetVariables(const ExegesisTarget &Target, - const BitVector &ForbiddenRegs, - InstructionTemplate &IT) { +static Error randomizeMCOperand(const LLVMState &State, + const Instruction &Instr, const Variable &Var, + MCOperand &AssignedValue, + const BitVector &ForbiddenRegs) { + const Operand &Op = Instr.getPrimaryOperand(Var); + if (Op.getExplicitOperandInfo().OperandType >= + MCOI::OperandType::OPERAND_FIRST_TARGET) + return State.getExegesisTarget().randomizeTargetMCOperand( + Instr, Var, AssignedValue, ForbiddenRegs); + switch (Op.getExplicitOperandInfo().OperandType) { + case MCOI::OperandType::OPERAND_IMMEDIATE: + // FIXME: explore immediate values too. + AssignedValue = MCOperand::createImm(1); + break; + case MCOI::OperandType::OPERAND_REGISTER: { + assert(Op.isReg()); + auto AllowedRegs = Op.getRegisterAliasing().sourceBits(); + assert(AllowedRegs.size() == ForbiddenRegs.size()); + for (auto I : ForbiddenRegs.set_bits()) + AllowedRegs.reset(I); + if (!AllowedRegs.any()) + return make_error( + Twine("no available registers:\ncandidates:\n") + .concat(debugString(State.getRegInfo(), + Op.getRegisterAliasing().sourceBits())) + .concat("\nforbidden:\n") + .concat(debugString(State.getRegInfo(), ForbiddenRegs))); + AssignedValue = MCOperand::createReg(randomBit(AllowedRegs)); + break; + } + default: + break; + } + return Error::success(); +} + +Error randomizeUnsetVariables(const LLVMState &State, + const BitVector &ForbiddenRegs, + InstructionTemplate &IT) { for (const Variable &Var : IT.getInstr().Variables) { MCOperand &AssignedValue = IT.getValueFor(Var); if (!AssignedValue.isValid()) - Target.randomizeMCOperand(IT.getInstr(), Var, AssignedValue, - ForbiddenRegs); + if (auto Err = randomizeMCOperand(State, IT.getInstr(), Var, + AssignedValue, ForbiddenRegs)) + return Err; } + return Error::success(); } } // namespace exegesis diff --git a/tools/llvm-exegesis/lib/SnippetGenerator.h b/tools/llvm-exegesis/lib/SnippetGenerator.h index 70f81f942be..7e7f6e487e1 100644 --- a/tools/llvm-exegesis/lib/SnippetGenerator.h +++ b/tools/llvm-exegesis/lib/SnippetGenerator.h @@ -97,9 +97,9 @@ void setRandomAliasing(const AliasingConfigurations &AliasingConfigurations, // Assigns a Random Value to all Variables in IT that are still Invalid. // Do not use any of the registers in `ForbiddenRegs`. -void randomizeUnsetVariables(const ExegesisTarget &Target, - const BitVector &ForbiddenRegs, - InstructionTemplate &IT); +Error randomizeUnsetVariables(const LLVMState &State, + const BitVector &ForbiddenRegs, + InstructionTemplate &IT); } // namespace exegesis } // namespace llvm diff --git a/tools/llvm-exegesis/lib/Target.cpp b/tools/llvm-exegesis/lib/Target.cpp index 40021e2931c..701ff14be20 100644 --- a/tools/llvm-exegesis/lib/Target.cpp +++ b/tools/llvm-exegesis/lib/Target.cpp @@ -99,30 +99,6 @@ ExegesisTarget::createUopsBenchmarkRunner(const LLVMState &State) const { return std::make_unique(State); } -void ExegesisTarget::randomizeMCOperand(const Instruction &Instr, - const Variable &Var, - MCOperand &AssignedValue, - const BitVector &ForbiddenRegs) const { - const Operand &Op = Instr.getPrimaryOperand(Var); - switch (Op.getExplicitOperandInfo().OperandType) { - case MCOI::OperandType::OPERAND_IMMEDIATE: - // FIXME: explore immediate values too. - AssignedValue = MCOperand::createImm(1); - break; - case MCOI::OperandType::OPERAND_REGISTER: { - assert(Op.isReg()); - auto AllowedRegs = Op.getRegisterAliasing().sourceBits(); - assert(AllowedRegs.size() == ForbiddenRegs.size()); - for (auto I : ForbiddenRegs.set_bits()) - AllowedRegs.reset(I); - AssignedValue = MCOperand::createReg(randomBit(AllowedRegs)); - break; - } - default: - break; - } -} - static_assert(std::is_pod::value, "We shouldn't have dynamic initialization here"); const PfmCountersInfo PfmCountersInfo::Default = {nullptr, nullptr, nullptr, diff --git a/tools/llvm-exegesis/lib/Target.h b/tools/llvm-exegesis/lib/Target.h index bd430090410..d9bddc56e82 100644 --- a/tools/llvm-exegesis/lib/Target.h +++ b/tools/llvm-exegesis/lib/Target.h @@ -18,6 +18,7 @@ #include "BenchmarkResult.h" #include "BenchmarkRunner.h" +#include "Error.h" #include "LlvmState.h" #include "SnippetGenerator.h" #include "llvm/ADT/Triple.h" @@ -108,12 +109,15 @@ public: virtual unsigned getMaxMemoryAccessSize() const { return 0; } // Assigns a random operand of the right type to variable Var. - // The default implementation only handles generic operand types. - // The target is responsible for handling any operand - // starting from OPERAND_FIRST_TARGET. - virtual void randomizeMCOperand(const Instruction &Instr, const Variable &Var, - MCOperand &AssignedValue, - const BitVector &ForbiddenRegs) const; + // The target is responsible for handling any operand starting from + // OPERAND_FIRST_TARGET. + virtual Error randomizeTargetMCOperand(const Instruction &Instr, + const Variable &Var, + MCOperand &AssignedValue, + const BitVector &ForbiddenRegs) const { + return make_error( + "targets with target-specific operands should implement this"); + } // Returns true if this instruction is supported as a back-to-back // instructions. diff --git a/tools/llvm-exegesis/lib/X86/Target.cpp b/tools/llvm-exegesis/lib/X86/Target.cpp index cea8af0cf69..a76e590cfa2 100644 --- a/tools/llvm-exegesis/lib/X86/Target.cpp +++ b/tools/llvm-exegesis/lib/X86/Target.cpp @@ -566,9 +566,9 @@ private: unsigned getMaxMemoryAccessSize() const override { return 64; } - void randomizeMCOperand(const Instruction &Instr, const Variable &Var, - MCOperand &AssignedValue, - const BitVector &ForbiddenRegs) const override; + Error randomizeTargetMCOperand(const Instruction &Instr, const Variable &Var, + MCOperand &AssignedValue, + const BitVector &ForbiddenRegs) const override; void fillMemoryOperands(InstructionTemplate &IT, unsigned Reg, unsigned Offset) const override; @@ -644,24 +644,25 @@ unsigned ExegesisX86Target::getLoopCounterRegister(const Triple &TT) const { return kLoopCounterReg; } -void ExegesisX86Target::randomizeMCOperand( +Error ExegesisX86Target::randomizeTargetMCOperand( const Instruction &Instr, const Variable &Var, MCOperand &AssignedValue, const BitVector &ForbiddenRegs) const { - ExegesisTarget::randomizeMCOperand(Instr, Var, AssignedValue, ForbiddenRegs); - const Operand &Op = Instr.getPrimaryOperand(Var); switch (Op.getExplicitOperandInfo().OperandType) { case X86::OperandType::OPERAND_ROUNDING_CONTROL: AssignedValue = MCOperand::createImm(randomIndex(X86::STATIC_ROUNDING::NO_EXC)); - break; + return Error::success(); case X86::OperandType::OPERAND_COND_CODE: AssignedValue = MCOperand::createImm(randomIndex(X86::CondCode::LAST_VALID_COND)); - break; + return Error::success(); default: break; } + return make_error( + Twine("unimplemented operand type ") + .concat(Twine(Op.getExplicitOperandInfo().OperandType))); } void ExegesisX86Target::fillMemoryOperands(InstructionTemplate &IT, diff --git a/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp b/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp index 808ea34e743..a833e1e2279 100644 --- a/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp +++ b/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp @@ -354,6 +354,17 @@ TEST_F(ParallelSnippetGeneratorTest, MemoryUse) { EXPECT_EQ(IT.getVariableValues()[5].getReg(), 0u); } +TEST_F(ParallelSnippetGeneratorTest, MOV16ms) { + const unsigned Opcode = X86::MOV16ms; + const Instruction &Instr = State.getIC().getInstr(Opcode); + auto Err = + Generator.generateConfigurations(Instr, State.getRATC().emptyRegisters()) + .takeError(); + EXPECT_TRUE((bool)Err); + EXPECT_THAT(toString(std::move(Err)), + testing::HasSubstr("no available registers")); +} + class FakeSnippetGenerator : public SnippetGenerator { public: FakeSnippetGenerator(const LLVMState &State, const Options &Opts)