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, 78 insertions, 40 deletions
diff --git a/llvm/tools/llvm-exegesis/lib/Latency.cpp b/llvm/tools/llvm-exegesis/lib/Latency.cpp
index 4a2632c7b5c..4233345aba0 100644
--- a/llvm/tools/llvm-exegesis/lib/Latency.cpp
+++ b/llvm/tools/llvm-exegesis/lib/Latency.cpp
@@ -8,25 +8,41 @@
//===----------------------------------------------------------------------===//
#include "Latency.h"
-#include "BenchmarkResult.h"
-#include "InstructionSnippetGenerator.h"
+
+#include "Assembler.h"
+#include "BenchmarkRunner.h"
+#include "MCInstrDescView.h"
#include "PerfHelper.h"
-#include "llvm/MC/MCInstrDesc.h"
-#include "llvm/Support/Error.h"
-#include <algorithm>
-#include <random>
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstBuilder.h"
namespace exegesis {
+static bool HasUnknownOperand(const llvm::MCOperandInfo &OpInfo) {
+ return OpInfo.OperandType == llvm::MCOI::OPERAND_UNKNOWN;
+}
+
// FIXME: Handle memory, see PR36905.
-static bool isInvalidOperand(const llvm::MCOperandInfo &OpInfo) {
- switch (OpInfo.OperandType) {
- default:
+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;
- 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) {
@@ -38,39 +54,61 @@ LatencyBenchmarkRunner::~LatencyBenchmarkRunner() = default;
const char *LatencyBenchmarkRunner::getDisplayName() const { return "latency"; }
-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");
+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;
}
- 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);
+ return makeError(
+ "Infeasible : Didn't find any scheme to make the instruction serial\n");
}
std::vector<BenchmarkMeasure>
-LatencyBenchmarkRunner::runMeasurements(const LLVMState &State,
- const JitFunction &Function,
+LatencyBenchmarkRunner::runMeasurements(const ExecutableFunction &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