diff options
Diffstat (limited to 'llvm/tools/llvm-exegesis/lib/Latency.cpp')
-rw-r--r-- | llvm/tools/llvm-exegesis/lib/Latency.cpp | 118 |
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. |