1 //===-- SnippetRepetitor.cpp ------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "SnippetRepetitor.h" 10 #include "Target.h" 11 #include "llvm/ADT/Sequence.h" 12 #include "llvm/CodeGen/TargetInstrInfo.h" 13 #include "llvm/CodeGen/TargetLowering.h" 14 #include "llvm/CodeGen/TargetSubtargetInfo.h" 15 16 namespace llvm { 17 namespace exegesis { 18 namespace { 19 20 class DuplicateSnippetRepetitor : public SnippetRepetitor { 21 public: 22 using SnippetRepetitor::SnippetRepetitor; 23 24 // Repeats the snippet until there are at least MinInstructions in the 25 // resulting code. 26 FillFunction Repeat(ArrayRef<MCInst> Instructions, unsigned MinInstructions, 27 unsigned LoopBodySize, 28 bool CleanupMemory) const override { 29 return [this, Instructions, MinInstructions, 30 CleanupMemory](FunctionFiller &Filler) { 31 auto Entry = Filler.getEntry(); 32 if (!Instructions.empty()) { 33 const unsigned NumRepetitions = 34 divideCeil(MinInstructions, Instructions.size()); 35 for (unsigned I = 0; I < NumRepetitions; ++I) { 36 Entry.addInstructions(Instructions); 37 } 38 } 39 Entry.addReturn(State.getExegesisTarget(), CleanupMemory); 40 }; 41 } 42 43 BitVector getReservedRegs() const override { 44 // We're using no additional registers. 45 return State.getRATC().emptyRegisters(); 46 } 47 }; 48 49 class LoopSnippetRepetitor : public SnippetRepetitor { 50 public: 51 explicit LoopSnippetRepetitor(const LLVMState &State, MCRegister LoopRegister) 52 : SnippetRepetitor(State), LoopCounter(LoopRegister) {} 53 54 // Loop over the snippet ceil(MinInstructions / Instructions.Size()) times. 55 FillFunction Repeat(ArrayRef<MCInst> Instructions, unsigned MinInstructions, 56 unsigned LoopBodySize, 57 bool CleanupMemory) const override { 58 return [this, Instructions, MinInstructions, LoopBodySize, 59 CleanupMemory](FunctionFiller &Filler) { 60 const auto &ET = State.getExegesisTarget(); 61 auto Entry = Filler.getEntry(); 62 63 // We can not use loop snippet repetitor for terminator instructions. 64 for (const MCInst &Inst : Instructions) { 65 const unsigned Opcode = Inst.getOpcode(); 66 const MCInstrDesc &MCID = Filler.MCII->get(Opcode); 67 if (!MCID.isTerminator()) 68 continue; 69 Entry.addReturn(State.getExegesisTarget(), CleanupMemory); 70 return; 71 } 72 73 auto Loop = Filler.addBasicBlock(); 74 auto Exit = Filler.addBasicBlock(); 75 76 // Align the loop machine basic block to a target-specific boundary 77 // to promote optimal instruction fetch/predecoding conditions. 78 Loop.MBB->setAlignment( 79 Filler.MF.getSubtarget().getTargetLowering()->getPrefLoopAlignment()); 80 81 const unsigned LoopUnrollFactor = 82 LoopBodySize <= Instructions.size() 83 ? 1 84 : divideCeil(LoopBodySize, Instructions.size()); 85 assert(LoopUnrollFactor >= 1 && "Should end up with at least 1 snippet."); 86 87 // Set loop counter to the right value: 88 const APInt LoopCount( 89 32, 90 divideCeil(MinInstructions, LoopUnrollFactor * Instructions.size())); 91 assert(LoopCount.uge(1) && "Trip count should be at least 1."); 92 for (const MCInst &Inst : 93 ET.setRegTo(State.getSubtargetInfo(), LoopCounter, LoopCount)) 94 Entry.addInstruction(Inst); 95 96 // Set up the loop basic block. 97 Entry.MBB->addSuccessor(Loop.MBB, BranchProbability::getOne()); 98 Loop.MBB->addSuccessor(Loop.MBB, BranchProbability::getOne()); 99 // If the snippet setup completed, then we can track liveness. 100 if (Loop.MF.getProperties().hasProperty( 101 MachineFunctionProperties::Property::TracksLiveness)) { 102 // The live ins are: the loop counter, the registers that were setup by 103 // the entry block, and entry block live ins. 104 Loop.MBB->addLiveIn(LoopCounter); 105 for (MCRegister Reg : Filler.getRegistersSetUp()) 106 Loop.MBB->addLiveIn(Reg); 107 for (const auto &LiveIn : Entry.MBB->liveins()) 108 Loop.MBB->addLiveIn(LiveIn); 109 } 110 for (auto _ : seq(LoopUnrollFactor)) { 111 (void)_; 112 Loop.addInstructions(Instructions); 113 } 114 ET.decrementLoopCounterAndJump(*Loop.MBB, *Loop.MBB, State.getInstrInfo(), 115 LoopCounter); 116 117 // Set up the exit basic block. 118 Loop.MBB->addSuccessor(Exit.MBB, BranchProbability::getZero()); 119 Exit.addReturn(State.getExegesisTarget(), CleanupMemory); 120 }; 121 } 122 123 BitVector getReservedRegs() const override { 124 // We're using a single loop counter, but we have to reserve all aliasing 125 // registers. 126 return State.getRATC().getRegister(LoopCounter).aliasedBits(); 127 } 128 129 private: 130 const MCRegister LoopCounter; 131 }; 132 133 } // namespace 134 135 SnippetRepetitor::~SnippetRepetitor() {} 136 137 std::unique_ptr<const SnippetRepetitor> 138 SnippetRepetitor::Create(Benchmark::RepetitionModeE Mode, 139 const LLVMState &State, MCRegister LoopRegister) { 140 switch (Mode) { 141 case Benchmark::Duplicate: 142 case Benchmark::MiddleHalfDuplicate: 143 return std::make_unique<DuplicateSnippetRepetitor>(State); 144 case Benchmark::Loop: 145 case Benchmark::MiddleHalfLoop: 146 return std::make_unique<LoopSnippetRepetitor>(State, LoopRegister); 147 case Benchmark::AggregateMin: 148 break; 149 } 150 llvm_unreachable("Unknown RepetitionModeE enum"); 151 } 152 153 } // namespace exegesis 154 } // namespace llvm 155