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, 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. |

