forked from OSchip/llvm-project
[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
This commit is contained in:
parent
5c02fe1faa
commit
04fd204156
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -72,7 +72,8 @@ Expected<std::vector<BenchmarkCode>> 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<Failure>(
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -99,30 +99,6 @@ ExegesisTarget::createUopsBenchmarkRunner(const LLVMState &State) const {
|
|||
return std::make_unique<UopsBenchmarkRunner>(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<PfmCountersInfo>::value,
|
||||
"We shouldn't have dynamic initialization here");
|
||||
const PfmCountersInfo PfmCountersInfo::Default = {nullptr, nullptr, nullptr,
|
||||
|
|
|
@ -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<Failure>(
|
||||
"targets with target-specific operands should implement this");
|
||||
}
|
||||
|
||||
// Returns true if this instruction is supported as a back-to-back
|
||||
// instructions.
|
||||
|
|
|
@ -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<Failure>(
|
||||
Twine("unimplemented operand type ")
|
||||
.concat(Twine(Op.getExplicitOperandInfo().OperandType)));
|
||||
}
|
||||
|
||||
void ExegesisX86Target::fillMemoryOperands(InstructionTemplate &IT,
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue