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().hasOptSize()) 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 // Pad the identified basic blocks with NOOPs 116 for (DenseMap<MachineBasicBlock*, unsigned int>::iterator I = ReturnBBs.begin(); 117 I != ReturnBBs.end(); ++I) { 118 MachineBasicBlock *MBB = I->first; 119 unsigned Cycles = I->second; 120 121 if (Cycles < Threshold) { 122 // BB ends in a return. Skip over any DBG_VALUE instructions 123 // trailing the terminator. 124 assert(MBB->size() > 0 && 125 "Basic block should contain at least a RET but is empty"); 126 MachineBasicBlock::iterator ReturnLoc = --MBB->end(); 127 128 while (ReturnLoc->isDebugInstr()) 129 --ReturnLoc; 130 assert(ReturnLoc->isReturn() && !ReturnLoc->isCall() && 131 "Basic block does not end with RET"); 132 133 addPadding(MBB, ReturnLoc, Threshold - Cycles); 134 NumBBsPadded++; 135 MadeChange = true; 136 } 137 } 138 139 return MadeChange; 140 } 141 142 /// findReturn - Starting at MBB, follow control flow and add all 143 /// basic blocks that contain a return to ReturnBBs. 144 void PadShortFunc::findReturns(MachineBasicBlock *MBB, unsigned int Cycles) { 145 // If this BB has a return, note how many cycles it takes to get there. 146 bool hasReturn = cyclesUntilReturn(MBB, Cycles); 147 if (Cycles >= Threshold) 148 return; 149 150 if (hasReturn) { 151 ReturnBBs[MBB] = std::max(ReturnBBs[MBB], Cycles); 152 return; 153 } 154 155 // Follow branches in BB and look for returns 156 for (MachineBasicBlock::succ_iterator I = MBB->succ_begin(); 157 I != MBB->succ_end(); ++I) { 158 if (*I == MBB) 159 continue; 160 findReturns(*I, Cycles); 161 } 162 } 163 164 /// cyclesUntilReturn - return true if the MBB has a return instruction, 165 /// and return false otherwise. 166 /// Cycles will be incremented by the number of cycles taken to reach the 167 /// return or the end of the BB, whichever occurs first. 168 bool PadShortFunc::cyclesUntilReturn(MachineBasicBlock *MBB, 169 unsigned int &Cycles) { 170 // Return cached result if BB was previously visited 171 DenseMap<MachineBasicBlock*, VisitedBBInfo>::iterator it 172 = VisitedBBs.find(MBB); 173 if (it != VisitedBBs.end()) { 174 VisitedBBInfo BBInfo = it->second; 175 Cycles += BBInfo.Cycles; 176 return BBInfo.HasReturn; 177 } 178 179 unsigned int CyclesToEnd = 0; 180 181 for (MachineInstr &MI : *MBB) { 182 // Mark basic blocks with a return instruction. Calls to other 183 // functions do not count because the called function will be padded, 184 // if necessary. 185 if (MI.isReturn() && !MI.isCall()) { 186 VisitedBBs[MBB] = VisitedBBInfo(true, CyclesToEnd); 187 Cycles += CyclesToEnd; 188 return true; 189 } 190 191 CyclesToEnd += TSM.computeInstrLatency(&MI); 192 } 193 194 VisitedBBs[MBB] = VisitedBBInfo(false, CyclesToEnd); 195 Cycles += CyclesToEnd; 196 return false; 197 } 198 199 /// addPadding - Add the given number of NOOP instructions to the function 200 /// just prior to the return at MBBI 201 void PadShortFunc::addPadding(MachineBasicBlock *MBB, 202 MachineBasicBlock::iterator &MBBI, 203 unsigned int NOOPsToAdd) { 204 DebugLoc DL = MBBI->getDebugLoc(); 205 unsigned IssueWidth = TSM.getIssueWidth(); 206 207 for (unsigned i = 0, e = IssueWidth * NOOPsToAdd; i != e; ++i) 208 BuildMI(*MBB, MBBI, DL, TSM.getInstrInfo()->get(X86::NOOP)); 209 } 210