xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonLoopAlign.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===----- HexagonLoopAlign.cpp - Generate loop alignment directives  -----===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric // Inspect a basic block and if its single basic block loop with a small
9*0fca6ea1SDimitry Andric // number of instructions, set the prefLoopAlignment to 32 bytes (5).
10*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
11*0fca6ea1SDimitry Andric 
12*0fca6ea1SDimitry Andric #define DEBUG_TYPE "hexagon-loop-align"
13*0fca6ea1SDimitry Andric 
14*0fca6ea1SDimitry Andric #include "HexagonTargetMachine.h"
15*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
16*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
17*0fca6ea1SDimitry Andric #include "llvm/CodeGen/SchedulerRegistry.h"
18*0fca6ea1SDimitry Andric #include "llvm/Support/Debug.h"
19*0fca6ea1SDimitry Andric 
20*0fca6ea1SDimitry Andric using namespace llvm;
21*0fca6ea1SDimitry Andric 
22*0fca6ea1SDimitry Andric static cl::opt<bool>
23*0fca6ea1SDimitry Andric     DisableLoopAlign("disable-hexagon-loop-align", cl::Hidden,
24*0fca6ea1SDimitry Andric                      cl::desc("Disable Hexagon loop alignment pass"));
25*0fca6ea1SDimitry Andric 
26*0fca6ea1SDimitry Andric static cl::opt<uint32_t> HVXLoopAlignLimitUB(
27*0fca6ea1SDimitry Andric     "hexagon-hvx-loop-align-limit-ub", cl::Hidden, cl::init(16),
28*0fca6ea1SDimitry Andric     cl::desc("Set hexagon hvx loop upper bound align limit"));
29*0fca6ea1SDimitry Andric 
30*0fca6ea1SDimitry Andric static cl::opt<uint32_t> TinyLoopAlignLimitUB(
31*0fca6ea1SDimitry Andric     "hexagon-tiny-loop-align-limit-ub", cl::Hidden, cl::init(16),
32*0fca6ea1SDimitry Andric     cl::desc("Set hexagon tiny-core loop upper bound align limit"));
33*0fca6ea1SDimitry Andric 
34*0fca6ea1SDimitry Andric static cl::opt<uint32_t>
35*0fca6ea1SDimitry Andric     LoopAlignLimitUB("hexagon-loop-align-limit-ub", cl::Hidden, cl::init(8),
36*0fca6ea1SDimitry Andric                      cl::desc("Set hexagon loop upper bound align limit"));
37*0fca6ea1SDimitry Andric 
38*0fca6ea1SDimitry Andric static cl::opt<uint32_t>
39*0fca6ea1SDimitry Andric     LoopAlignLimitLB("hexagon-loop-align-limit-lb", cl::Hidden, cl::init(4),
40*0fca6ea1SDimitry Andric                      cl::desc("Set hexagon loop lower bound align limit"));
41*0fca6ea1SDimitry Andric 
42*0fca6ea1SDimitry Andric static cl::opt<uint32_t>
43*0fca6ea1SDimitry Andric     LoopBndlAlignLimit("hexagon-loop-bundle-align-limit", cl::Hidden,
44*0fca6ea1SDimitry Andric                        cl::init(4),
45*0fca6ea1SDimitry Andric                        cl::desc("Set hexagon loop align bundle limit"));
46*0fca6ea1SDimitry Andric 
47*0fca6ea1SDimitry Andric static cl::opt<uint32_t> TinyLoopBndlAlignLimit(
48*0fca6ea1SDimitry Andric     "hexagon-tiny-loop-bundle-align-limit", cl::Hidden, cl::init(8),
49*0fca6ea1SDimitry Andric     cl::desc("Set hexagon tiny-core loop align bundle limit"));
50*0fca6ea1SDimitry Andric 
51*0fca6ea1SDimitry Andric static cl::opt<uint32_t>
52*0fca6ea1SDimitry Andric     LoopEdgeThreshold("hexagon-loop-edge-threshold", cl::Hidden, cl::init(7500),
53*0fca6ea1SDimitry Andric                       cl::desc("Set hexagon loop align edge theshold"));
54*0fca6ea1SDimitry Andric 
55*0fca6ea1SDimitry Andric namespace llvm {
56*0fca6ea1SDimitry Andric FunctionPass *createHexagonLoopAlign();
57*0fca6ea1SDimitry Andric void initializeHexagonLoopAlignPass(PassRegistry &);
58*0fca6ea1SDimitry Andric } // namespace llvm
59*0fca6ea1SDimitry Andric 
60*0fca6ea1SDimitry Andric namespace {
61*0fca6ea1SDimitry Andric 
62*0fca6ea1SDimitry Andric class HexagonLoopAlign : public MachineFunctionPass {
63*0fca6ea1SDimitry Andric   const HexagonSubtarget *HST = nullptr;
64*0fca6ea1SDimitry Andric   const TargetMachine *HTM = nullptr;
65*0fca6ea1SDimitry Andric   const HexagonInstrInfo *HII = nullptr;
66*0fca6ea1SDimitry Andric 
67*0fca6ea1SDimitry Andric public:
68*0fca6ea1SDimitry Andric   static char ID;
69*0fca6ea1SDimitry Andric   HexagonLoopAlign() : MachineFunctionPass(ID) {
70*0fca6ea1SDimitry Andric     initializeHexagonLoopAlignPass(*PassRegistry::getPassRegistry());
71*0fca6ea1SDimitry Andric   }
72*0fca6ea1SDimitry Andric   bool shouldBalignLoop(MachineBasicBlock &BB, bool AboveThres);
73*0fca6ea1SDimitry Andric   bool isSingleLoop(MachineBasicBlock &MBB);
74*0fca6ea1SDimitry Andric   bool attemptToBalignSmallLoop(MachineFunction &MF, MachineBasicBlock &MBB);
75*0fca6ea1SDimitry Andric 
76*0fca6ea1SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
77*0fca6ea1SDimitry Andric     AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
78*0fca6ea1SDimitry Andric     AU.addRequired<MachineBlockFrequencyInfoWrapperPass>();
79*0fca6ea1SDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
80*0fca6ea1SDimitry Andric   }
81*0fca6ea1SDimitry Andric 
82*0fca6ea1SDimitry Andric   StringRef getPassName() const override { return "Hexagon LoopAlign pass"; }
83*0fca6ea1SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
84*0fca6ea1SDimitry Andric };
85*0fca6ea1SDimitry Andric 
86*0fca6ea1SDimitry Andric char HexagonLoopAlign::ID = 0;
87*0fca6ea1SDimitry Andric 
88*0fca6ea1SDimitry Andric bool HexagonLoopAlign::shouldBalignLoop(MachineBasicBlock &BB,
89*0fca6ea1SDimitry Andric                                         bool AboveThres) {
90*0fca6ea1SDimitry Andric   bool isVec = false;
91*0fca6ea1SDimitry Andric   unsigned InstCnt = 0;
92*0fca6ea1SDimitry Andric   unsigned BndlCnt = 0;
93*0fca6ea1SDimitry Andric 
94*0fca6ea1SDimitry Andric   for (MachineBasicBlock::instr_iterator II = BB.instr_begin(),
95*0fca6ea1SDimitry Andric                                          IE = BB.instr_end();
96*0fca6ea1SDimitry Andric        II != IE; ++II) {
97*0fca6ea1SDimitry Andric 
98*0fca6ea1SDimitry Andric     // End if the instruction is endloop.
99*0fca6ea1SDimitry Andric     if (HII->isEndLoopN(II->getOpcode()))
100*0fca6ea1SDimitry Andric       break;
101*0fca6ea1SDimitry Andric     // Count the number of bundles.
102*0fca6ea1SDimitry Andric     if (II->isBundle()) {
103*0fca6ea1SDimitry Andric       BndlCnt++;
104*0fca6ea1SDimitry Andric       continue;
105*0fca6ea1SDimitry Andric     }
106*0fca6ea1SDimitry Andric     // Skip over debug instructions.
107*0fca6ea1SDimitry Andric     if (II->isDebugInstr())
108*0fca6ea1SDimitry Andric       continue;
109*0fca6ea1SDimitry Andric     // Check if there are any HVX instructions in loop.
110*0fca6ea1SDimitry Andric     isVec |= HII->isHVXVec(*II);
111*0fca6ea1SDimitry Andric     // Count the number of instructions.
112*0fca6ea1SDimitry Andric     InstCnt++;
113*0fca6ea1SDimitry Andric   }
114*0fca6ea1SDimitry Andric 
115*0fca6ea1SDimitry Andric   LLVM_DEBUG({
116*0fca6ea1SDimitry Andric     dbgs() << "Bundle Count : " << BndlCnt << "\n";
117*0fca6ea1SDimitry Andric     dbgs() << "Instruction Count : " << InstCnt << "\n";
118*0fca6ea1SDimitry Andric   });
119*0fca6ea1SDimitry Andric 
120*0fca6ea1SDimitry Andric   unsigned LimitUB = 0;
121*0fca6ea1SDimitry Andric   unsigned LimitBndl = LoopBndlAlignLimit;
122*0fca6ea1SDimitry Andric   // The conditions in the order of priority.
123*0fca6ea1SDimitry Andric   if (HST->isTinyCore()) {
124*0fca6ea1SDimitry Andric     LimitUB = TinyLoopAlignLimitUB;
125*0fca6ea1SDimitry Andric     LimitBndl = TinyLoopBndlAlignLimit;
126*0fca6ea1SDimitry Andric   } else if (isVec)
127*0fca6ea1SDimitry Andric     LimitUB = HVXLoopAlignLimitUB;
128*0fca6ea1SDimitry Andric   else if (AboveThres)
129*0fca6ea1SDimitry Andric     LimitUB = LoopAlignLimitUB;
130*0fca6ea1SDimitry Andric 
131*0fca6ea1SDimitry Andric   // if the upper bound is not set to a value, implies we didn't meet
132*0fca6ea1SDimitry Andric   // the criteria.
133*0fca6ea1SDimitry Andric   if (LimitUB == 0)
134*0fca6ea1SDimitry Andric     return false;
135*0fca6ea1SDimitry Andric 
136*0fca6ea1SDimitry Andric   return InstCnt >= LoopAlignLimitLB && InstCnt <= LimitUB &&
137*0fca6ea1SDimitry Andric          BndlCnt <= LimitBndl;
138*0fca6ea1SDimitry Andric }
139*0fca6ea1SDimitry Andric 
140*0fca6ea1SDimitry Andric bool HexagonLoopAlign::isSingleLoop(MachineBasicBlock &MBB) {
141*0fca6ea1SDimitry Andric   int Succs = MBB.succ_size();
142*0fca6ea1SDimitry Andric   return (MBB.isSuccessor(&MBB) && (Succs == 2));
143*0fca6ea1SDimitry Andric }
144*0fca6ea1SDimitry Andric 
145*0fca6ea1SDimitry Andric bool HexagonLoopAlign::attemptToBalignSmallLoop(MachineFunction &MF,
146*0fca6ea1SDimitry Andric                                                 MachineBasicBlock &MBB) {
147*0fca6ea1SDimitry Andric   if (!isSingleLoop(MBB))
148*0fca6ea1SDimitry Andric     return false;
149*0fca6ea1SDimitry Andric 
150*0fca6ea1SDimitry Andric   const MachineBranchProbabilityInfo *MBPI =
151*0fca6ea1SDimitry Andric       &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
152*0fca6ea1SDimitry Andric   const MachineBlockFrequencyInfo *MBFI =
153*0fca6ea1SDimitry Andric       &getAnalysis<MachineBlockFrequencyInfoWrapperPass>().getMBFI();
154*0fca6ea1SDimitry Andric 
155*0fca6ea1SDimitry Andric   // Compute frequency of back edge,
156*0fca6ea1SDimitry Andric   BlockFrequency BlockFreq = MBFI->getBlockFreq(&MBB);
157*0fca6ea1SDimitry Andric   BranchProbability BrProb = MBPI->getEdgeProbability(&MBB, &MBB);
158*0fca6ea1SDimitry Andric   BlockFrequency EdgeFreq = BlockFreq * BrProb;
159*0fca6ea1SDimitry Andric   LLVM_DEBUG({
160*0fca6ea1SDimitry Andric     dbgs() << "Loop Align Pass:\n";
161*0fca6ea1SDimitry Andric     dbgs() << "\tedge with freq(" << EdgeFreq.getFrequency() << ")\n";
162*0fca6ea1SDimitry Andric   });
163*0fca6ea1SDimitry Andric 
164*0fca6ea1SDimitry Andric   bool AboveThres = EdgeFreq.getFrequency() > LoopEdgeThreshold;
165*0fca6ea1SDimitry Andric   if (shouldBalignLoop(MBB, AboveThres)) {
166*0fca6ea1SDimitry Andric     // We found a loop, change its alignment to be 32 (5).
167*0fca6ea1SDimitry Andric     MBB.setAlignment(llvm::Align(1 << 5));
168*0fca6ea1SDimitry Andric     return true;
169*0fca6ea1SDimitry Andric   }
170*0fca6ea1SDimitry Andric   return false;
171*0fca6ea1SDimitry Andric }
172*0fca6ea1SDimitry Andric 
173*0fca6ea1SDimitry Andric // Inspect each basic block, and if its a single BB loop, see if it
174*0fca6ea1SDimitry Andric // meets the criteria for increasing alignment to 32.
175*0fca6ea1SDimitry Andric 
176*0fca6ea1SDimitry Andric bool HexagonLoopAlign::runOnMachineFunction(MachineFunction &MF) {
177*0fca6ea1SDimitry Andric 
178*0fca6ea1SDimitry Andric   HST = &MF.getSubtarget<HexagonSubtarget>();
179*0fca6ea1SDimitry Andric   HII = HST->getInstrInfo();
180*0fca6ea1SDimitry Andric   HTM = &MF.getTarget();
181*0fca6ea1SDimitry Andric 
182*0fca6ea1SDimitry Andric   if (skipFunction(MF.getFunction()))
183*0fca6ea1SDimitry Andric     return false;
184*0fca6ea1SDimitry Andric   if (DisableLoopAlign)
185*0fca6ea1SDimitry Andric     return false;
186*0fca6ea1SDimitry Andric 
187*0fca6ea1SDimitry Andric   // This optimization is performed at
188*0fca6ea1SDimitry Andric   // i) -O2 and above, and  when the loop has a HVX instruction.
189*0fca6ea1SDimitry Andric   // ii) -O3
190*0fca6ea1SDimitry Andric   if (HST->useHVXOps()) {
191*0fca6ea1SDimitry Andric     if (HTM->getOptLevel() < CodeGenOptLevel::Default)
192*0fca6ea1SDimitry Andric       return false;
193*0fca6ea1SDimitry Andric   } else {
194*0fca6ea1SDimitry Andric     if (HTM->getOptLevel() < CodeGenOptLevel::Aggressive)
195*0fca6ea1SDimitry Andric       return false;
196*0fca6ea1SDimitry Andric   }
197*0fca6ea1SDimitry Andric 
198*0fca6ea1SDimitry Andric   bool Changed = false;
199*0fca6ea1SDimitry Andric   for (MachineFunction::iterator MBBi = MF.begin(), MBBe = MF.end();
200*0fca6ea1SDimitry Andric        MBBi != MBBe; ++MBBi) {
201*0fca6ea1SDimitry Andric     MachineBasicBlock &MBB = *MBBi;
202*0fca6ea1SDimitry Andric     Changed |= attemptToBalignSmallLoop(MF, MBB);
203*0fca6ea1SDimitry Andric   }
204*0fca6ea1SDimitry Andric   return Changed;
205*0fca6ea1SDimitry Andric }
206*0fca6ea1SDimitry Andric 
207*0fca6ea1SDimitry Andric } // namespace
208*0fca6ea1SDimitry Andric 
209*0fca6ea1SDimitry Andric INITIALIZE_PASS(HexagonLoopAlign, "hexagon-loop-align",
210*0fca6ea1SDimitry Andric                 "Hexagon LoopAlign pass", false, false)
211*0fca6ea1SDimitry Andric 
212*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
213*0fca6ea1SDimitry Andric //                         Public Constructor Functions
214*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
215*0fca6ea1SDimitry Andric 
216*0fca6ea1SDimitry Andric FunctionPass *llvm::createHexagonLoopAlign() { return new HexagonLoopAlign(); }
217