//===-- SnippetRepetitor.cpp ------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include #include #include "SnippetRepetitor.h" #include "Target.h" #include "llvm/ADT/Sequence.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" namespace llvm { namespace exegesis { namespace { class DuplicateSnippetRepetitor : public SnippetRepetitor { public: using SnippetRepetitor::SnippetRepetitor; // Repeats the snippet until there are at least MinInstructions in the // resulting code. FillFunction Repeat(ArrayRef Instructions, unsigned MinInstructions, unsigned LoopBodySize) const override { return [Instructions, MinInstructions](FunctionFiller &Filler) { auto Entry = Filler.getEntry(); if (!Instructions.empty()) { // Add the whole snippet at least once. Entry.addInstructions(Instructions); for (unsigned I = Instructions.size(); I < MinInstructions; ++I) { Entry.addInstruction(Instructions[I % Instructions.size()]); } } Entry.addReturn(); }; } BitVector getReservedRegs() const override { // We're using no additional registers. return State.getRATC().emptyRegisters(); } }; class LoopSnippetRepetitor : public SnippetRepetitor { public: explicit LoopSnippetRepetitor(const LLVMState &State) : SnippetRepetitor(State), LoopCounter(State.getExegesisTarget().getLoopCounterRegister( State.getTargetMachine().getTargetTriple())) {} // Loop over the snippet ceil(MinInstructions / Instructions.Size()) times. FillFunction Repeat(ArrayRef Instructions, unsigned MinInstructions, unsigned LoopBodySize) const override { return [this, Instructions, MinInstructions, LoopBodySize](FunctionFiller &Filler) { const auto &ET = State.getExegesisTarget(); auto Entry = Filler.getEntry(); auto Loop = Filler.addBasicBlock(); auto Exit = Filler.addBasicBlock(); const unsigned LoopUnrollFactor = LoopBodySize <= Instructions.size() ? 1 : divideCeil(LoopBodySize, Instructions.size()); assert(LoopUnrollFactor >= 1 && "Should end up with at least 1 snippet."); // Set loop counter to the right value: const APInt LoopCount( 32, divideCeil(MinInstructions, LoopUnrollFactor * Instructions.size())); assert(LoopCount.uge(1) && "Trip count should be at least 1."); for (const MCInst &Inst : ET.setRegTo(State.getSubtargetInfo(), LoopCounter, LoopCount)) Entry.addInstruction(Inst); // Set up the loop basic block. Entry.MBB->addSuccessor(Loop.MBB, BranchProbability::getOne()); Loop.MBB->addSuccessor(Loop.MBB, BranchProbability::getOne()); // The live ins are: the loop counter, the registers that were setup by // the entry block, and entry block live ins. Loop.MBB->addLiveIn(LoopCounter); for (unsigned Reg : Filler.getRegistersSetUp()) Loop.MBB->addLiveIn(Reg); for (const auto &LiveIn : Entry.MBB->liveins()) Loop.MBB->addLiveIn(LiveIn); for (auto _ : seq(0U, LoopUnrollFactor)) { (void)_; Loop.addInstructions(Instructions); } ET.decrementLoopCounterAndJump(*Loop.MBB, *Loop.MBB, State.getInstrInfo()); // Set up the exit basic block. Loop.MBB->addSuccessor(Exit.MBB, BranchProbability::getZero()); Exit.addReturn(); }; } BitVector getReservedRegs() const override { // We're using a single loop counter, but we have to reserve all aliasing // registers. return State.getRATC().getRegister(LoopCounter).aliasedBits(); } private: const unsigned LoopCounter; }; } // namespace SnippetRepetitor::~SnippetRepetitor() {} std::unique_ptr SnippetRepetitor::Create(InstructionBenchmark::RepetitionModeE Mode, const LLVMState &State) { switch (Mode) { case InstructionBenchmark::Duplicate: return std::make_unique(State); case InstructionBenchmark::Loop: return std::make_unique(State); case InstructionBenchmark::AggregateMin: break; } llvm_unreachable("Unknown RepetitionModeE enum"); } } // namespace exegesis } // namespace llvm