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
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
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)
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
// 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
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,
#include "BenchmarkResult.h"
#include "BenchmarkRunner.h"
+#include "Error.h"
#include "LlvmState.h"
#include "SnippetGenerator.h"
#include "llvm/ADT/Triple.h"
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.
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;
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,
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)