[llvm-exegesis] Cleaner design without mutable data.
Summary: Previous design was relying on the 'mutate' keyword and was quite confusing. This version separate mutable from immutable data and makes it clearer what changes and what doesn't.
Reviewers: courbet
Subscribers: tschuett, llvm-commits
Differential Revision: https://reviews.llvm.org/D48020
llvm-svn: 334596
diff --git a/llvm/tools/llvm-exegesis/lib/Latency.cpp b/llvm/tools/llvm-exegesis/lib/Latency.cpp
index 896b543..6545660 100644
--- a/llvm/tools/llvm-exegesis/lib/Latency.cpp
+++ b/llvm/tools/llvm-exegesis/lib/Latency.cpp
@@ -19,93 +19,113 @@
namespace exegesis {
-static bool HasUnknownOperand(const llvm::MCOperandInfo &OpInfo) {
+static bool hasUnknownOperand(const llvm::MCOperandInfo &OpInfo) {
return OpInfo.OperandType == llvm::MCOI::OPERAND_UNKNOWN;
}
// FIXME: Handle memory, see PR36905.
-static bool HasMemoryOperand(const llvm::MCOperandInfo &OpInfo) {
+static bool hasMemoryOperand(const llvm::MCOperandInfo &OpInfo) {
return OpInfo.OperandType == llvm::MCOI::OPERAND_MEMORY;
}
-static bool IsInfeasible(const Instruction &Instruction, std::string &Error) {
- const auto &MCInstrDesc = Instruction.Description;
- if (MCInstrDesc.isPseudo()) {
- Error = "is pseudo";
- return true;
- }
- if (llvm::any_of(MCInstrDesc.operands(), HasUnknownOperand)) {
- Error = "has unknown operands";
- return true;
- }
- if (llvm::any_of(MCInstrDesc.operands(), HasMemoryOperand)) {
- Error = "has memory operands";
- return true;
- }
- return false;
-}
-
LatencyBenchmarkRunner::~LatencyBenchmarkRunner() = default;
InstructionBenchmark::ModeE LatencyBenchmarkRunner::getMode() const {
return InstructionBenchmark::Latency;
}
-llvm::Expected<std::vector<BenchmarkConfiguration>>
-LatencyBenchmarkRunner::createConfigurations(RegisterAliasingTrackerCache &RATC,
- unsigned Opcode) const {
- const llvm::MCInstrDesc &MCInstrDesc = MCInstrInfo.get(Opcode);
- const Instruction ThisInstruction(MCInstrDesc, RATC);
+llvm::Error LatencyBenchmarkRunner::isInfeasible(
+ const llvm::MCInstrDesc &MCInstrDesc) const {
+ if (MCInstrDesc.isPseudo())
+ return llvm::make_error<BenchmarkFailure>("Infeasible : is pseudo");
+ if (llvm::any_of(MCInstrDesc.operands(), hasUnknownOperand))
+ return llvm::make_error<BenchmarkFailure>(
+ "Infeasible : has unknown operands");
+ if (llvm::any_of(MCInstrDesc.operands(), hasMemoryOperand))
+ return llvm::make_error<BenchmarkFailure>(
+ "Infeasible : has memory operands");
+ return llvm::Error::success();
+}
- std::string Error;
- if (IsInfeasible(ThisInstruction, Error))
- return llvm::make_error<llvm::StringError>(
- llvm::Twine("Infeasible : ").concat(Error),
- llvm::inconvertibleErrorCode());
-
+llvm::Expected<BenchmarkConfiguration>
+LatencyBenchmarkRunner::generateSelfAliasingConfiguration(
+ const Instruction &Instr,
+ const AliasingConfigurations &SelfAliasing) const {
BenchmarkConfiguration Conf;
- const AliasingConfigurations SelfAliasing(ThisInstruction, ThisInstruction);
- if (!SelfAliasing.empty()) {
- if (!SelfAliasing.hasImplicitAliasing()) {
- Conf.Info = "explicit self cycles, selecting one aliasing Conf.";
- setRandomAliasing(SelfAliasing);
- } else {
- Conf.Info = "implicit Self cycles, picking random values.";
- }
- Conf.Snippet = {randomizeUnsetVariablesAndBuild(ThisInstruction)};
- return std::vector<BenchmarkConfiguration>{Conf};
+ InstructionInstance II(Instr);
+ if (SelfAliasing.hasImplicitAliasing()) {
+ Conf.Info = "implicit Self cycles, picking random values.";
+ } else {
+ Conf.Info = "explicit self cycles, selecting one aliasing Conf.";
+ // This is a self aliasing instruction so defs and uses are from the same
+ // instance, hence twice II in the following call.
+ setRandomAliasing(SelfAliasing, II, II);
}
+ Conf.Snippet = {II.randomizeUnsetVariablesAndBuild()};
+ return Conf;
+}
- // Let's try to create a dependency through another opcode.
+llvm::Expected<BenchmarkConfiguration>
+LatencyBenchmarkRunner::generateTwoInstructionConfiguration(
+ const Instruction &Instr,
+ const AliasingConfigurations &SelfAliasing) const {
std::vector<unsigned> Opcodes;
Opcodes.resize(MCInstrInfo.getNumOpcodes());
std::iota(Opcodes.begin(), Opcodes.end(), 0U);
std::shuffle(Opcodes.begin(), Opcodes.end(), randomGenerator());
for (const unsigned OtherOpcode : Opcodes) {
- clearVariableAssignments(ThisInstruction);
- if (OtherOpcode == Opcode)
+ if (OtherOpcode == Instr.Description.Opcode)
continue;
- const Instruction OtherInstruction(MCInstrInfo.get(OtherOpcode), RATC);
- if (IsInfeasible(OtherInstruction, Error))
+ const auto &OtherInstrDesc = MCInstrInfo.get(OtherOpcode);
+ if (auto E = isInfeasible(OtherInstrDesc)) {
+ llvm::consumeError(std::move(E));
continue;
- const AliasingConfigurations Forward(ThisInstruction, OtherInstruction);
- const AliasingConfigurations Back(OtherInstruction, ThisInstruction);
+ }
+ const Instruction OtherInstr(OtherInstrDesc, RATC);
+ const AliasingConfigurations Forward(Instr, OtherInstr);
+ const AliasingConfigurations Back(OtherInstr, Instr);
if (Forward.empty() || Back.empty())
continue;
- setRandomAliasing(Forward);
- setRandomAliasing(Back);
+ InstructionInstance ThisII(Instr);
+ InstructionInstance OtherII(OtherInstr);
+ if (!Forward.hasImplicitAliasing())
+ setRandomAliasing(Forward, ThisII, OtherII);
+ if (!Back.hasImplicitAliasing())
+ setRandomAliasing(Back, OtherII, ThisII);
+ BenchmarkConfiguration Conf;
Conf.Info = llvm::Twine("creating cycle through ")
.concat(MCInstrInfo.getName(OtherOpcode))
.concat(".")
.str();
- Conf.Snippet.push_back(randomizeUnsetVariablesAndBuild(ThisInstruction));
- Conf.Snippet.push_back(randomizeUnsetVariablesAndBuild(OtherInstruction));
- return std::vector<BenchmarkConfiguration>{Conf};
+ Conf.Snippet.push_back(ThisII.randomizeUnsetVariablesAndBuild());
+ Conf.Snippet.push_back(OtherII.randomizeUnsetVariablesAndBuild());
+ return Conf;
}
+ return llvm::make_error<BenchmarkFailure>(
+ "Infeasible : Didn't find any scheme to make the instruction serial");
+}
- return llvm::make_error<llvm::StringError>(
- "Infeasible : Didn't find any scheme to make the instruction serial",
- llvm::inconvertibleErrorCode());
+llvm::Expected<BenchmarkConfiguration>
+LatencyBenchmarkRunner::generateConfiguration(unsigned Opcode) const {
+ const auto &InstrDesc = MCInstrInfo.get(Opcode);
+ if (auto E = isInfeasible(InstrDesc))
+ return std::move(E);
+ const Instruction Instr(InstrDesc, RATC);
+ const AliasingConfigurations SelfAliasing(Instr, Instr);
+ if (SelfAliasing.empty()) {
+ // No self aliasing, trying to create a dependency through another opcode.
+ return generateTwoInstructionConfiguration(Instr, SelfAliasing);
+ } else {
+ return generateSelfAliasingConfiguration(Instr, SelfAliasing);
+ }
+}
+
+llvm::Expected<std::vector<BenchmarkConfiguration>>
+LatencyBenchmarkRunner::createConfigurations(unsigned Opcode) const {
+ if (auto E = generateConfiguration(Opcode))
+ return std::vector<BenchmarkConfiguration>{E.get()};
+ else
+ return E.takeError();
}
std::vector<BenchmarkMeasure>