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