1 //===-------- X86PadShortFunction.cpp - pad short functions -----------===// 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 // This file defines the pass which will pad short functions to prevent 10 // a stall if a function returns before the return address is ready. This 11 // is needed for some Intel Atom processors. 12 // 13 //===----------------------------------------------------------------------===// 14 15 16 #include "X86.h" 17 #include "X86InstrInfo.h" 18 #include "X86Subtarget.h" 19 #include "llvm/ADT/Statistic.h" 20 #include "llvm/CodeGen/MachineFunctionPass.h" 21 #include "llvm/CodeGen/MachineInstrBuilder.h" 22 #include "llvm/CodeGen/Passes.h" 23 #include "llvm/CodeGen/TargetSchedule.h" 24 #include "llvm/IR/Function.h" 25 #include "llvm/Support/Debug.h" 26 #include "llvm/Support/raw_ostream.h" 27 28 using namespace llvm; 29 30 #define DEBUG_TYPE "x86-pad-short-functions" 31 32 STATISTIC(NumBBsPadded, "Number of basic blocks padded"); 33 34 namespace { 35 struct VisitedBBInfo { 36 // HasReturn - Whether the BB contains a return instruction 37 bool HasReturn; 38 39 // Cycles - Number of cycles until return if HasReturn is true, otherwise 40 // number of cycles until end of the BB 41 unsigned int Cycles; 42 43 VisitedBBInfo() : HasReturn(false), Cycles(0) {} 44 VisitedBBInfo(bool HasReturn, unsigned int Cycles) 45 : HasReturn(HasReturn), Cycles(Cycles) {} 46 }; 47 48 struct PadShortFunc : public MachineFunctionPass { 49 static char ID; 50 PadShortFunc() : MachineFunctionPass(ID) 51 , Threshold(4) {} 52 53 bool runOnMachineFunction(MachineFunction &MF) override; 54 55 MachineFunctionProperties getRequiredProperties() const override { 56 return MachineFunctionProperties().set( 57 MachineFunctionProperties::Property::NoVRegs); 58 } 59 60 StringRef getPassName() const override { 61 return "X86 Atom pad short functions"; 62 } 63 64 private: 65 void findReturns(MachineBasicBlock *MBB, 66 unsigned int Cycles = 0); 67 68 bool cyclesUntilReturn(MachineBasicBlock *MBB, 69 unsigned int &Cycles); 70 71 void addPadding(MachineBasicBlock *MBB, 72 MachineBasicBlock::iterator &MBBI, 73 unsigned int NOOPsToAdd); 74 75 const unsigned int Threshold; 76 77 // ReturnBBs - Maps basic blocks that return to the minimum number of 78 // cycles until the return, starting from the entry block. 79 DenseMap<MachineBasicBlock*, unsigned int> ReturnBBs; 80 81 // VisitedBBs - Cache of previously visited BBs. 82 DenseMap<MachineBasicBlock*, VisitedBBInfo> VisitedBBs; 83 84 TargetSchedModel TSM; 85 }; 86 87 char PadShortFunc::ID = 0; 88 } 89 90 FunctionPass *llvm::createX86PadShortFunctions() { 91 return new PadShortFunc(); 92 } 93 94 /// runOnMachineFunction - Loop over all of the basic blocks, inserting 95 /// NOOP instructions before early exits. 96 bool PadShortFunc::runOnMachineFunction(MachineFunction &MF) { 97 if (skipFunction(MF.getFunction())) 98 return false; 99 100 if (MF.getFunction().optForSize()) 101 return false; 102 103 if (!MF.getSubtarget<X86Subtarget>().padShortFunctions()) 104 return false; 105 106 TSM.init(&MF.getSubtarget()); 107 108 // Search through basic blocks and mark the ones that have early returns 109 ReturnBBs.clear(); 110 VisitedBBs.clear(); 111 findReturns(&MF.front()); 112 113 bool MadeChange = false; 114 115 MachineBasicBlock *MBB; 116 unsigned int Cycles = 0; 117 118 // Pad the identified basic blocks with NOOPs 119 for (DenseMap<MachineBasicBlock*, unsigned int>::iterator I = ReturnBBs.begin(); 120 I != ReturnBBs.end(); ++I) { 121 MBB = I->first; 122 Cycles = I->second; 123 124 if (Cycles < Threshold) { 125 // BB ends in a return. Skip over any DBG_VALUE instructions 126 // trailing the terminator. 127 assert(MBB->size() > 0 && 128 "Basic block should contain at least a RET but is empty"); 129 MachineBasicBlock::iterator ReturnLoc = --MBB->end(); 130 131 while (ReturnLoc->isDebugInstr()) 132 --ReturnLoc; 133 assert(ReturnLoc->isReturn() && !ReturnLoc->isCall() && 134 "Basic block does not end with RET"); 135 136 addPadding(MBB, ReturnLoc, Threshold - Cycles); 137 NumBBsPadded++; 138 MadeChange = true; 139 } 140 } 141 142 return MadeChange; 143 } 144 145 /// findReturn - Starting at MBB, follow control flow and add all 146 /// basic blocks that contain a return to ReturnBBs. 147 void PadShortFunc::findReturns(MachineBasicBlock *MBB, unsigned int Cycles) { 148 // If this BB has a return, note how many cycles it takes to get there. 149 bool hasReturn = cyclesUntilReturn(MBB, Cycles); 150 if (Cycles >= Threshold) 151 return; 152 153 if (hasReturn) { 154 ReturnBBs[MBB] = std::max(ReturnBBs[MBB], Cycles); 155 return; 156 } 157 158 // Follow branches in BB and look for returns 159 for (MachineBasicBlock::succ_iterator I = MBB->succ_begin(); 160 I != MBB->succ_end(); ++I) { 161 if (*I == MBB) 162 continue; 163 findReturns(*I, Cycles); 164 } 165 } 166 167 /// cyclesUntilReturn - return true if the MBB has a return instruction, 168 /// and return false otherwise. 169 /// Cycles will be incremented by the number of cycles taken to reach the 170 /// return or the end of the BB, whichever occurs first. 171 bool PadShortFunc::cyclesUntilReturn(MachineBasicBlock *MBB, 172 unsigned int &Cycles) { 173 // Return cached result if BB was previously visited 174 DenseMap<MachineBasicBlock*, VisitedBBInfo>::iterator it 175 = VisitedBBs.find(MBB); 176 if (it != VisitedBBs.end()) { 177 VisitedBBInfo BBInfo = it->second; 178 Cycles += BBInfo.Cycles; 179 return BBInfo.HasReturn; 180 } 181 182 unsigned int CyclesToEnd = 0; 183 184 for (MachineInstr &MI : *MBB) { 185 // Mark basic blocks with a return instruction. Calls to other 186 // functions do not count because the called function will be padded, 187 // if necessary. 188 if (MI.isReturn() && !MI.isCall()) { 189 VisitedBBs[MBB] = VisitedBBInfo(true, CyclesToEnd); 190 Cycles += CyclesToEnd; 191 return true; 192 } 193 194 CyclesToEnd += TSM.computeInstrLatency(&MI); 195 } 196 197 VisitedBBs[MBB] = VisitedBBInfo(false, CyclesToEnd); 198 Cycles += CyclesToEnd; 199 return false; 200 } 201 202 /// addPadding - Add the given number of NOOP instructions to the function 203 /// just prior to the return at MBBI 204 void PadShortFunc::addPadding(MachineBasicBlock *MBB, 205 MachineBasicBlock::iterator &MBBI, 206 unsigned int NOOPsToAdd) { 207 DebugLoc DL = MBBI->getDebugLoc(); 208 unsigned IssueWidth = TSM.getIssueWidth(); 209 210 for (unsigned i = 0, e = IssueWidth * NOOPsToAdd; i != e; ++i) 211 BuildMI(*MBB, MBBI, DL, TSM.getInstrInfo()->get(X86::NOOP)); 212 } 213