xref: /llvm-project/llvm/tools/llvm-exegesis/lib/SnippetRepetitor.cpp (revision ff1b01bb7897bf2401540096af775d35b12eb247)
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