summaryrefslogtreecommitdiffstats
path: root/llvm/tools/llvm-exegesis/lib/Latency.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-exegesis/lib/Latency.cpp')
-rw-r--r--llvm/tools/llvm-exegesis/lib/Latency.cpp155
1 files changed, 125 insertions, 30 deletions
diff --git a/llvm/tools/llvm-exegesis/lib/Latency.cpp b/llvm/tools/llvm-exegesis/lib/Latency.cpp
index 040b42b53e2..7b991a452aa 100644
--- a/llvm/tools/llvm-exegesis/lib/Latency.cpp
+++ b/llvm/tools/llvm-exegesis/lib/Latency.cpp
@@ -20,53 +20,148 @@
namespace exegesis {
-LatencySnippetGenerator::~LatencySnippetGenerator() = default;
+struct ExecutionClass {
+ ExecutionMode Mask;
+ const char *Description;
+} static const kExecutionClasses[] = {
+ {ExecutionMode::ALWAYS_SERIAL_IMPLICIT_REGS_ALIAS |
+ ExecutionMode::ALWAYS_SERIAL_TIED_REGS_ALIAS,
+ "Repeating a single implicitly serial instruction"},
+ {ExecutionMode::SERIAL_VIA_EXPLICIT_REGS,
+ "Repeating a single explicitly serial instruction"},
+ {ExecutionMode::SERIAL_VIA_MEMORY_INSTR |
+ ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR,
+ "Repeating two instructions"},
+};
-llvm::Expected<std::vector<CodeTemplate>>
-generateTwoInstructionPrototypes(const LLVMState &State,
- const Instruction &Instr) {
+static constexpr size_t kMaxAliasingInstructions = 10;
+
+static std::vector<Instruction>
+computeAliasingInstructions(const LLVMState &State, const Instruction &Instr,
+ size_t MaxAliasingInstructions) {
+ // Randomly iterate the set of instructions.
std::vector<unsigned> Opcodes;
Opcodes.resize(State.getInstrInfo().getNumOpcodes());
std::iota(Opcodes.begin(), Opcodes.end(), 0U);
std::shuffle(Opcodes.begin(), Opcodes.end(), randomGenerator());
+
+ std::vector<Instruction> AliasingInstructions;
for (const unsigned OtherOpcode : Opcodes) {
- if (OtherOpcode == Instr.Description->Opcode)
+ if (OtherOpcode == Instr.Description->getOpcode())
continue;
const Instruction OtherInstr(State, OtherOpcode);
if (OtherInstr.hasMemoryOperands())
continue;
- const AliasingConfigurations Forward(Instr, OtherInstr);
- const AliasingConfigurations Back(OtherInstr, Instr);
- if (Forward.empty() || Back.empty())
- continue;
- InstructionTemplate ThisIT(Instr);
- InstructionTemplate OtherIT(OtherInstr);
- if (!Forward.hasImplicitAliasing())
- setRandomAliasing(Forward, ThisIT, OtherIT);
- if (!Back.hasImplicitAliasing())
- setRandomAliasing(Back, OtherIT, ThisIT);
+ if (Instr.hasAliasingRegistersThrough(OtherInstr))
+ AliasingInstructions.push_back(std::move(OtherInstr));
+ if (AliasingInstructions.size() >= MaxAliasingInstructions)
+ break;
+ }
+ return AliasingInstructions;
+}
+
+static ExecutionMode getExecutionModes(const Instruction &Instr) {
+ ExecutionMode EM;
+ if (Instr.hasAliasingImplicitRegisters())
+ EM |= ExecutionMode::ALWAYS_SERIAL_IMPLICIT_REGS_ALIAS;
+ if (Instr.hasTiedRegisters())
+ EM |= ExecutionMode::ALWAYS_SERIAL_TIED_REGS_ALIAS;
+ if (Instr.hasMemoryOperands())
+ EM |= ExecutionMode::SERIAL_VIA_MEMORY_INSTR;
+ else {
+ if (Instr.hasAliasingRegisters())
+ EM |= ExecutionMode::SERIAL_VIA_EXPLICIT_REGS;
+ if (Instr.hasOneUseOrOneDef())
+ EM |= ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR;
+ }
+ return EM;
+}
+
+static void appendCodeTemplates(const LLVMState &State,
+ const Instruction &Instr,
+ ExecutionMode ExecutionModeBit,
+ llvm::StringRef ExecutionClassDescription,
+ std::vector<CodeTemplate> &CodeTemplates) {
+ assert(isEnumValue(ExecutionModeBit) && "Bit must be a power of two");
+ switch (ExecutionModeBit) {
+ case ExecutionMode::ALWAYS_SERIAL_IMPLICIT_REGS_ALIAS:
+ // Nothing to do, the instruction is always serial.
+ LLVM_FALLTHROUGH;
+ case ExecutionMode::ALWAYS_SERIAL_TIED_REGS_ALIAS: {
+ // Picking whatever value for the tied variable will make the instruction
+ // serial.
CodeTemplate CT;
- CT.Info = llvm::formatv("creating cycle through {0}.",
- State.getInstrInfo().getName(OtherOpcode));
- CT.Instructions.push_back(std::move(ThisIT));
- CT.Instructions.push_back(std::move(OtherIT));
- return getSingleton(CT);
+ CT.Execution = ExecutionModeBit;
+ CT.Info = ExecutionClassDescription;
+ CT.Instructions.push_back(Instr);
+ CodeTemplates.push_back(std::move(CT));
+ return;
+ }
+ case ExecutionMode::SERIAL_VIA_MEMORY_INSTR: {
+ // Select back-to-back memory instruction.
+ // TODO: Implement me.
+ return;
+ }
+ case ExecutionMode::SERIAL_VIA_EXPLICIT_REGS: {
+ // Making the execution of this instruction serial by selecting one def
+ // register to alias with one use register.
+ const AliasingConfigurations SelfAliasing(Instr, Instr);
+ assert(!SelfAliasing.empty() && !SelfAliasing.hasImplicitAliasing() &&
+ "Instr must alias itself explicitly");
+ InstructionTemplate IT(Instr);
+ // This is a self aliasing instruction so defs and uses are from the same
+ // instance, hence twice IT in the following call.
+ setRandomAliasing(SelfAliasing, IT, IT);
+ CodeTemplate CT;
+ CT.Execution = ExecutionModeBit;
+ CT.Info = ExecutionClassDescription;
+ CT.Instructions.push_back(std::move(IT));
+ CodeTemplates.push_back(std::move(CT));
+ return;
+ }
+ case ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR: {
+ // Select back-to-back non-memory instruction.
+ for (const auto OtherInstr :
+ computeAliasingInstructions(State, Instr, kMaxAliasingInstructions)) {
+ const AliasingConfigurations Forward(Instr, OtherInstr);
+ const AliasingConfigurations Back(OtherInstr, Instr);
+ InstructionTemplate ThisIT(Instr);
+ InstructionTemplate OtherIT(OtherInstr);
+ if (!Forward.hasImplicitAliasing())
+ setRandomAliasing(Forward, ThisIT, OtherIT);
+ if (!Back.hasImplicitAliasing())
+ setRandomAliasing(Back, OtherIT, ThisIT);
+ CodeTemplate CT;
+ CT.Execution = ExecutionModeBit;
+ CT.Info = ExecutionClassDescription;
+ CT.Instructions.push_back(std::move(ThisIT));
+ CT.Instructions.push_back(std::move(OtherIT));
+ CodeTemplates.push_back(std::move(CT));
+ }
+ return;
+ }
+ default:
+ llvm_unreachable("Unhandled enum value");
}
- return llvm::make_error<BenchmarkFailure>(
- "Infeasible : Didn't find any scheme to make the instruction serial");
}
+LatencySnippetGenerator::~LatencySnippetGenerator() = default;
+
llvm::Expected<std::vector<CodeTemplate>>
LatencySnippetGenerator::generateCodeTemplates(const Instruction &Instr) const {
- if (Instr.hasMemoryOperands())
+ std::vector<CodeTemplate> Results;
+ const ExecutionMode EM = getExecutionModes(Instr);
+ for (const auto EC : kExecutionClasses) {
+ for (const auto ExecutionModeBit : getExecutionModeBits(EM & EC.Mask))
+ appendCodeTemplates(State, Instr, ExecutionModeBit, EC.Description,
+ Results);
+ if (!Results.empty())
+ break;
+ }
+ if (Results.empty())
return llvm::make_error<BenchmarkFailure>(
- "Infeasible : has memory operands");
- return llvm::handleExpected( //
- generateSelfAliasingCodeTemplates(Instr),
- [this, &Instr]() {
- return generateTwoInstructionPrototypes(State, Instr);
- },
- [](const BenchmarkFailure &) { /*Consume Error*/ });
+ "No strategy found to make the execution serial");
+ return std::move(Results);
}
const char *LatencyBenchmarkRunner::getCounterName() const {
OpenPOWER on IntegriCloud