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.cpp118
1 files changed, 40 insertions, 78 deletions
diff --git a/llvm/tools/llvm-exegesis/lib/Latency.cpp b/llvm/tools/llvm-exegesis/lib/Latency.cpp
index 4233345aba0..4a2632c7b5c 100644
--- a/llvm/tools/llvm-exegesis/lib/Latency.cpp
+++ b/llvm/tools/llvm-exegesis/lib/Latency.cpp
@@ -8,41 +8,25 @@
//===----------------------------------------------------------------------===//
#include "Latency.h"
-
-#include "Assembler.h"
-#include "BenchmarkRunner.h"
-#include "MCInstrDescView.h"
+#include "BenchmarkResult.h"
+#include "InstructionSnippetGenerator.h"
#include "PerfHelper.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/MC/MCInst.h"
-#include "llvm/MC/MCInstBuilder.h"
+#include "llvm/MC/MCInstrDesc.h"
+#include "llvm/Support/Error.h"
+#include <algorithm>
+#include <random>
namespace exegesis {
-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) {
- 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";
+static bool isInvalidOperand(const llvm::MCOperandInfo &OpInfo) {
+ switch (OpInfo.OperandType) {
+ default:
return true;
+ case llvm::MCOI::OPERAND_IMMEDIATE:
+ case llvm::MCOI::OPERAND_REGISTER:
+ return false;
}
- if (llvm::any_of(MCInstrDesc.operands(), HasMemoryOperand)) {
- Error = "has memory operands";
- return true;
- }
- return false;
}
static llvm::Error makeError(llvm::Twine Msg) {
@@ -54,61 +38,39 @@ LatencyBenchmarkRunner::~LatencyBenchmarkRunner() = default;
const char *LatencyBenchmarkRunner::getDisplayName() const { return "latency"; }
-llvm::Expected<std::vector<llvm::MCInst>>
-LatencyBenchmarkRunner::createSnippet(RegisterAliasingTrackerCache &RATC,
- unsigned Opcode,
- llvm::raw_ostream &Info) const {
- std::vector<llvm::MCInst> Snippet;
- const llvm::MCInstrDesc &MCInstrDesc = MCInstrInfo.get(Opcode);
- const Instruction ThisInstruction(MCInstrDesc, RATC);
-
- std::string Error;
- if (IsInfeasible(ThisInstruction, Error))
- return makeError(llvm::Twine("Infeasible : ").concat(Error));
-
- const AliasingConfigurations SelfAliasing(ThisInstruction, ThisInstruction);
- if (!SelfAliasing.empty()) {
- if (!SelfAliasing.hasImplicitAliasing()) {
- Info << "explicit self cycles, selecting one aliasing configuration.\n";
- setRandomAliasing(SelfAliasing);
- } else {
- Info << "implicit Self cycles, picking random values.\n";
- }
- Snippet.push_back(randomizeUnsetVariablesAndBuild(ThisInstruction));
- return Snippet;
- }
-
- // Let's try to create a dependency through another opcode.
- 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)
- continue;
- const Instruction OtherInstruction(MCInstrInfo.get(OtherOpcode), RATC);
- if (IsInfeasible(OtherInstruction, Error))
- continue;
- const AliasingConfigurations Forward(ThisInstruction, OtherInstruction);
- const AliasingConfigurations Back(OtherInstruction, ThisInstruction);
- if (Forward.empty() || Back.empty())
- continue;
- setRandomAliasing(Forward);
- setRandomAliasing(Back);
- Info << "creating cycle through " << MCInstrInfo.getName(OtherOpcode)
- << ".\n";
- Snippet.push_back(randomizeUnsetVariablesAndBuild(ThisInstruction));
- Snippet.push_back(randomizeUnsetVariablesAndBuild(OtherInstruction));
- return Snippet;
+llvm::Expected<std::vector<llvm::MCInst>> LatencyBenchmarkRunner::createCode(
+ const LLVMState &State, const unsigned OpcodeIndex,
+ const unsigned NumRepetitions, const JitFunctionContext &Context) const {
+ std::default_random_engine RandomEngine;
+ const auto GetRandomIndex = [&RandomEngine](size_t Size) {
+ assert(Size > 0 && "trying to get select a random element of an empty set");
+ return std::uniform_int_distribution<>(0, Size - 1)(RandomEngine);
+ };
+
+ const auto &InstrInfo = State.getInstrInfo();
+ const auto &RegInfo = State.getRegInfo();
+ const llvm::MCInstrDesc &InstrDesc = InstrInfo.get(OpcodeIndex);
+ for (const llvm::MCOperandInfo &OpInfo : InstrDesc.operands()) {
+ if (isInvalidOperand(OpInfo))
+ return makeError("Only registers and immediates are supported");
}
- return makeError(
- "Infeasible : Didn't find any scheme to make the instruction serial\n");
+ const auto Vars = getVariables(RegInfo, InstrDesc, Context.getReservedRegs());
+ const std::vector<AssignmentChain> AssignmentChains =
+ computeSequentialAssignmentChains(RegInfo, Vars);
+ if (AssignmentChains.empty())
+ return makeError("Unable to find a dependency chain.");
+ const std::vector<llvm::MCPhysReg> Regs =
+ getRandomAssignment(Vars, AssignmentChains, GetRandomIndex);
+ const llvm::MCInst Inst = generateMCInst(InstrDesc, Vars, Regs);
+ if (!State.canAssemble(Inst))
+ return makeError("MCInst does not assemble.");
+ return std::vector<llvm::MCInst>(NumRepetitions, Inst);
}
std::vector<BenchmarkMeasure>
-LatencyBenchmarkRunner::runMeasurements(const ExecutableFunction &Function,
+LatencyBenchmarkRunner::runMeasurements(const LLVMState &State,
+ const JitFunction &Function,
const unsigned NumRepetitions) const {
// Cycle measurements include some overhead from the kernel. Repeat the
// measure several times and take the minimum value.
OpenPOWER on IntegriCloud