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
64 // We can not use loop snippet repetitor for terminator instructions.
65 for (const MCInst &Inst : Instructions) {
66 const unsigned Opcode = Inst.getOpcode();
67 const MCInstrDesc &MCID = Filler.MCII->get(Opcode);
68 if (!MCID.isTerminator())
69 continue;
70 Entry.addReturn();
71 return;
72 }
73
74 auto Loop = Filler.addBasicBlock();
75 auto Exit = Filler.addBasicBlock();
76
77 const unsigned LoopUnrollFactor =
78 LoopBodySize <= Instructions.size()
79 ? 1
80 : divideCeil(LoopBodySize, Instructions.size());
81 assert(LoopUnrollFactor >= 1 && "Should end up with at least 1 snippet.");
82
83 // Set loop counter to the right value:
84 const APInt LoopCount(
85 32,
86 divideCeil(MinInstructions, LoopUnrollFactor * Instructions.size()));
87 assert(LoopCount.uge(1) && "Trip count should be at least 1.");
88 for (const MCInst &Inst :
89 ET.setRegTo(State.getSubtargetInfo(), LoopCounter, LoopCount))
90 Entry.addInstruction(Inst);
91
92 // Set up the loop basic block.
93 Entry.MBB->addSuccessor(Loop.MBB, BranchProbability::getOne());
94 Loop.MBB->addSuccessor(Loop.MBB, BranchProbability::getOne());
95 // If the snippet setup completed, then we can track liveness.
96 if (Loop.MF.getProperties().hasProperty(
97 MachineFunctionProperties::Property::TracksLiveness)) {
98 // The live ins are: the loop counter, the registers that were setup by
99 // the entry block, and entry block live ins.
100 Loop.MBB->addLiveIn(LoopCounter);
101 for (unsigned Reg : Filler.getRegistersSetUp())
102 Loop.MBB->addLiveIn(Reg);
103 for (const auto &LiveIn : Entry.MBB->liveins())
104 Loop.MBB->addLiveIn(LiveIn);
105 }
106 for (auto _ : seq(0U, LoopUnrollFactor)) {
107 (void)_;
108 Loop.addInstructions(Instructions);
109 }
110 ET.decrementLoopCounterAndJump(*Loop.MBB, *Loop.MBB,
111 State.getInstrInfo());
112
113 // Set up the exit basic block.
114 Loop.MBB->addSuccessor(Exit.MBB, BranchProbability::getZero());
115 Exit.addReturn();
116 };
117 }
118
getReservedRegs() const119 BitVector getReservedRegs() const override {
120 // We're using a single loop counter, but we have to reserve all aliasing
121 // registers.
122 return State.getRATC().getRegister(LoopCounter).aliasedBits();
123 }
124
125 private:
126 const unsigned LoopCounter;
127 };
128
129 } // namespace
130
~SnippetRepetitor()131 SnippetRepetitor::~SnippetRepetitor() {}
132
133 std::unique_ptr<const SnippetRepetitor>
Create(InstructionBenchmark::RepetitionModeE Mode,const LLVMState & State)134 SnippetRepetitor::Create(InstructionBenchmark::RepetitionModeE Mode,
135 const LLVMState &State) {
136 switch (Mode) {
137 case InstructionBenchmark::Duplicate:
138 return std::make_unique<DuplicateSnippetRepetitor>(State);
139 case InstructionBenchmark::Loop:
140 return std::make_unique<LoopSnippetRepetitor>(State);
141 case InstructionBenchmark::AggregateMin:
142 break;
143 }
144 llvm_unreachable("Unknown RepetitionModeE enum");
145 }
146
147 } // namespace exegesis
148 } // namespace llvm
149