1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-18 18:42:46 +02:00

[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:
Clement Courbet 2020-01-22 15:49:10 +01:00
parent 035d9f209d
commit b60c7a5360
8 changed files with 90 additions and 47 deletions

View File

@ -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

View File

@ -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

View File

@ -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,
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

View File

@ -97,7 +97,7 @@ 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,
Error randomizeUnsetVariables(const LLVMState &State,
const BitVector &ForbiddenRegs,
InstructionTemplate &IT);

View File

@ -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,

View File

@ -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,
// 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;
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.

View File

@ -566,7 +566,7 @@ private:
unsigned getMaxMemoryAccessSize() const override { return 64; }
void randomizeMCOperand(const Instruction &Instr, const Variable &Var,
Error randomizeTargetMCOperand(const Instruction &Instr, const Variable &Var,
MCOperand &AssignedValue,
const BitVector &ForbiddenRegs) 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,

View File

@ -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)