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;
HexagonLoopAlign()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
getAnalysisUsage(AnalysisUsage & AU) const76*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
getPassName() const82*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
shouldBalignLoop(MachineBasicBlock & BB,bool AboveThres)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
isSingleLoop(MachineBasicBlock & MBB)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
attemptToBalignSmallLoop(MachineFunction & MF,MachineBasicBlock & MBB)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
runOnMachineFunction(MachineFunction & MF)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
createHexagonLoopAlign()216*0fca6ea1SDimitry Andric FunctionPass *llvm::createHexagonLoopAlign() { return new HexagonLoopAlign(); }
217