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 <array>
10 #include <string>
11 
12 #include "SnippetRepetitor.h"
13 #include "Target.h"
14 #include "llvm/ADT/Sequence.h"
15 #include "llvm/CodeGen/TargetInstrInfo.h"
16 #include "llvm/CodeGen/TargetSubtargetInfo.h"
17 
18 namespace llvm {
19 namespace exegesis {
20 namespace {
21 
22 class DuplicateSnippetRepetitor : public SnippetRepetitor {
23 public:
24   using SnippetRepetitor::SnippetRepetitor;
25 
26   // Repeats the snippet until there are at least MinInstructions in the
27   // resulting code.
Repeat(ArrayRef<MCInst> Instructions,unsigned MinInstructions,unsigned LoopBodySize) const28   FillFunction Repeat(ArrayRef<MCInst> Instructions, unsigned MinInstructions,
29                       unsigned LoopBodySize) const override {
30     return [Instructions, MinInstructions](FunctionFiller &Filler) {
31       auto Entry = Filler.getEntry();
32       if (!Instructions.empty()) {
33         // Add the whole snippet at least once.
34         Entry.addInstructions(Instructions);
35         for (unsigned I = Instructions.size(); I < MinInstructions; ++I) {
36           Entry.addInstruction(Instructions[I % Instructions.size()]);
37         }
38       }
39       Entry.addReturn();
40     };
41   }
42 
getReservedRegs() const43   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:
LoopSnippetRepetitor(const LLVMState & State)51   explicit LoopSnippetRepetitor(const LLVMState &State)
52       : SnippetRepetitor(State),
53         LoopCounter(State.getExegesisTarget().getLoopCounterRegister(
54             State.getTargetMachine().getTargetTriple())) {}
55 
56   // Loop over the snippet ceil(MinInstructions / Instructions.Size()) times.
Repeat(ArrayRef<MCInst> Instructions,unsigned MinInstructions,unsigned LoopBodySize) const57   FillFunction Repeat(ArrayRef<MCInst> Instructions, unsigned MinInstructions,
58                       unsigned LoopBodySize) const override {
59     return [this, Instructions, MinInstructions,
60             LoopBodySize](FunctionFiller &Filler) {
61       const auto &ET = State.getExegesisTarget();
62       auto Entry = Filler.getEntry();
63       auto Loop = Filler.addBasicBlock();
64       auto Exit = Filler.addBasicBlock();
65 
66       const unsigned LoopUnrollFactor =
67           LoopBodySize <= Instructions.size()
68               ? 1
69               : divideCeil(LoopBodySize, Instructions.size());
70       assert(LoopUnrollFactor >= 1 && "Should end up with at least 1 snippet.");
71 
72       // Set loop counter to the right value:
73       const APInt LoopCount(
74           32,
75           divideCeil(MinInstructions, LoopUnrollFactor * Instructions.size()));
76       assert(LoopCount.uge(1) && "Trip count should be at least 1.");
77       for (const MCInst &Inst :
78            ET.setRegTo(State.getSubtargetInfo(), LoopCounter, LoopCount))
79         Entry.addInstruction(Inst);
80 
81       // Set up the loop basic block.
82       Entry.MBB->addSuccessor(Loop.MBB, BranchProbability::getOne());
83       Loop.MBB->addSuccessor(Loop.MBB, BranchProbability::getOne());
84       // The live ins are: the loop counter, the registers that were setup by
85       // the entry block, and entry block live ins.
86       Loop.MBB->addLiveIn(LoopCounter);
87       for (unsigned Reg : Filler.getRegistersSetUp())
88         Loop.MBB->addLiveIn(Reg);
89       for (const auto &LiveIn : Entry.MBB->liveins())
90         Loop.MBB->addLiveIn(LiveIn);
91       for (auto _ : seq(0U, LoopUnrollFactor)) {
92         (void)_;
93         Loop.addInstructions(Instructions);
94       }
95       ET.decrementLoopCounterAndJump(*Loop.MBB, *Loop.MBB,
96                                      State.getInstrInfo());
97 
98       // Set up the exit basic block.
99       Loop.MBB->addSuccessor(Exit.MBB, BranchProbability::getZero());
100       Exit.addReturn();
101     };
102   }
103 
getReservedRegs() const104   BitVector getReservedRegs() const override {
105     // We're using a single loop counter, but we have to reserve all aliasing
106     // registers.
107     return State.getRATC().getRegister(LoopCounter).aliasedBits();
108   }
109 
110 private:
111   const unsigned LoopCounter;
112 };
113 
114 } // namespace
115 
~SnippetRepetitor()116 SnippetRepetitor::~SnippetRepetitor() {}
117 
118 std::unique_ptr<const SnippetRepetitor>
Create(InstructionBenchmark::RepetitionModeE Mode,const LLVMState & State)119 SnippetRepetitor::Create(InstructionBenchmark::RepetitionModeE Mode,
120                          const LLVMState &State) {
121   switch (Mode) {
122   case InstructionBenchmark::Duplicate:
123     return std::make_unique<DuplicateSnippetRepetitor>(State);
124   case InstructionBenchmark::Loop:
125     return std::make_unique<LoopSnippetRepetitor>(State);
126   case InstructionBenchmark::AggregateMin:
127     break;
128   }
129   llvm_unreachable("Unknown RepetitionModeE enum");
130 }
131 
132 } // namespace exegesis
133 } // namespace llvm
134