xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/X86/X86PadShortFunction.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
10b57cec5SDimitry Andric //===-------- X86PadShortFunction.cpp - pad short functions -----------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines the pass which will pad short functions to prevent
100b57cec5SDimitry Andric // a stall if a function returns before the return address is ready. This
110b57cec5SDimitry Andric // is needed for some Intel Atom processors.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "X86.h"
170b57cec5SDimitry Andric #include "X86InstrInfo.h"
180b57cec5SDimitry Andric #include "X86Subtarget.h"
190b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
20480093f4SDimitry Andric #include "llvm/Analysis/ProfileSummaryInfo.h"
21480093f4SDimitry Andric #include "llvm/CodeGen/LazyMachineBlockFrequencyInfo.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
230b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
24480093f4SDimitry Andric #include "llvm/CodeGen/MachineSizeOpts.h"
250b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h"
260b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSchedule.h"
270b57cec5SDimitry Andric #include "llvm/IR/Function.h"
280b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
290b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric using namespace llvm;
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric #define DEBUG_TYPE "x86-pad-short-functions"
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric STATISTIC(NumBBsPadded, "Number of basic blocks padded");
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric namespace {
380b57cec5SDimitry Andric   struct VisitedBBInfo {
390b57cec5SDimitry Andric     // HasReturn - Whether the BB contains a return instruction
40*81ad6265SDimitry Andric     bool HasReturn = false;
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric     // Cycles - Number of cycles until return if HasReturn is true, otherwise
430b57cec5SDimitry Andric     // number of cycles until end of the BB
44*81ad6265SDimitry Andric     unsigned int Cycles = 0;
450b57cec5SDimitry Andric 
46*81ad6265SDimitry Andric     VisitedBBInfo() = default;
VisitedBBInfo__anonf6824cbe0111::VisitedBBInfo470b57cec5SDimitry Andric     VisitedBBInfo(bool HasReturn, unsigned int Cycles)
480b57cec5SDimitry Andric       : HasReturn(HasReturn), Cycles(Cycles) {}
490b57cec5SDimitry Andric   };
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric   struct PadShortFunc : public MachineFunctionPass {
520b57cec5SDimitry Andric     static char ID;
PadShortFunc__anonf6824cbe0111::PadShortFunc53*81ad6265SDimitry Andric     PadShortFunc() : MachineFunctionPass(ID) {}
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric     bool runOnMachineFunction(MachineFunction &MF) override;
560b57cec5SDimitry Andric 
getAnalysisUsage__anonf6824cbe0111::PadShortFunc57480093f4SDimitry Andric     void getAnalysisUsage(AnalysisUsage &AU) const override {
58480093f4SDimitry Andric       AU.addRequired<ProfileSummaryInfoWrapperPass>();
59480093f4SDimitry Andric       AU.addRequired<LazyMachineBlockFrequencyInfoPass>();
605ffd83dbSDimitry Andric       AU.addPreserved<LazyMachineBlockFrequencyInfoPass>();
61480093f4SDimitry Andric       MachineFunctionPass::getAnalysisUsage(AU);
62480093f4SDimitry Andric     }
63480093f4SDimitry Andric 
getRequiredProperties__anonf6824cbe0111::PadShortFunc640b57cec5SDimitry Andric     MachineFunctionProperties getRequiredProperties() const override {
650b57cec5SDimitry Andric       return MachineFunctionProperties().set(
660b57cec5SDimitry Andric           MachineFunctionProperties::Property::NoVRegs);
670b57cec5SDimitry Andric     }
680b57cec5SDimitry Andric 
getPassName__anonf6824cbe0111::PadShortFunc690b57cec5SDimitry Andric     StringRef getPassName() const override {
700b57cec5SDimitry Andric       return "X86 Atom pad short functions";
710b57cec5SDimitry Andric     }
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   private:
740b57cec5SDimitry Andric     void findReturns(MachineBasicBlock *MBB,
750b57cec5SDimitry Andric                      unsigned int Cycles = 0);
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric     bool cyclesUntilReturn(MachineBasicBlock *MBB,
780b57cec5SDimitry Andric                            unsigned int &Cycles);
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric     void addPadding(MachineBasicBlock *MBB,
810b57cec5SDimitry Andric                     MachineBasicBlock::iterator &MBBI,
820b57cec5SDimitry Andric                     unsigned int NOOPsToAdd);
830b57cec5SDimitry Andric 
84*81ad6265SDimitry Andric     const unsigned int Threshold = 4;
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric     // ReturnBBs - Maps basic blocks that return to the minimum number of
870b57cec5SDimitry Andric     // cycles until the return, starting from the entry block.
880b57cec5SDimitry Andric     DenseMap<MachineBasicBlock*, unsigned int> ReturnBBs;
890b57cec5SDimitry Andric 
900b57cec5SDimitry Andric     // VisitedBBs - Cache of previously visited BBs.
910b57cec5SDimitry Andric     DenseMap<MachineBasicBlock*, VisitedBBInfo> VisitedBBs;
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric     TargetSchedModel TSM;
940b57cec5SDimitry Andric   };
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric   char PadShortFunc::ID = 0;
970b57cec5SDimitry Andric }
980b57cec5SDimitry Andric 
createX86PadShortFunctions()990b57cec5SDimitry Andric FunctionPass *llvm::createX86PadShortFunctions() {
1000b57cec5SDimitry Andric   return new PadShortFunc();
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric /// runOnMachineFunction - Loop over all of the basic blocks, inserting
1040b57cec5SDimitry Andric /// NOOP instructions before early exits.
runOnMachineFunction(MachineFunction & MF)1050b57cec5SDimitry Andric bool PadShortFunc::runOnMachineFunction(MachineFunction &MF) {
1060b57cec5SDimitry Andric   if (skipFunction(MF.getFunction()))
1070b57cec5SDimitry Andric     return false;
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric   if (MF.getFunction().hasOptSize())
1100b57cec5SDimitry Andric     return false;
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   if (!MF.getSubtarget<X86Subtarget>().padShortFunctions())
1130b57cec5SDimitry Andric     return false;
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric   TSM.init(&MF.getSubtarget());
1160b57cec5SDimitry Andric 
117480093f4SDimitry Andric   auto *PSI =
118480093f4SDimitry Andric       &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI();
119480093f4SDimitry Andric   auto *MBFI = (PSI && PSI->hasProfileSummary()) ?
120480093f4SDimitry Andric                &getAnalysis<LazyMachineBlockFrequencyInfoPass>().getBFI() :
121480093f4SDimitry Andric                nullptr;
122480093f4SDimitry Andric 
1230b57cec5SDimitry Andric   // Search through basic blocks and mark the ones that have early returns
1240b57cec5SDimitry Andric   ReturnBBs.clear();
1250b57cec5SDimitry Andric   VisitedBBs.clear();
1260b57cec5SDimitry Andric   findReturns(&MF.front());
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric   bool MadeChange = false;
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric   // Pad the identified basic blocks with NOOPs
13104eeddc0SDimitry Andric   for (const auto &ReturnBB : ReturnBBs) {
13204eeddc0SDimitry Andric     MachineBasicBlock *MBB = ReturnBB.first;
13304eeddc0SDimitry Andric     unsigned Cycles = ReturnBB.second;
1340b57cec5SDimitry Andric 
135480093f4SDimitry Andric     // Function::hasOptSize is already checked above.
136480093f4SDimitry Andric     bool OptForSize = llvm::shouldOptimizeForSize(MBB, PSI, MBFI);
137480093f4SDimitry Andric     if (OptForSize)
138480093f4SDimitry Andric       continue;
139480093f4SDimitry Andric 
1400b57cec5SDimitry Andric     if (Cycles < Threshold) {
1410b57cec5SDimitry Andric       // BB ends in a return. Skip over any DBG_VALUE instructions
1420b57cec5SDimitry Andric       // trailing the terminator.
1430b57cec5SDimitry Andric       assert(MBB->size() > 0 &&
1440b57cec5SDimitry Andric              "Basic block should contain at least a RET but is empty");
1450b57cec5SDimitry Andric       MachineBasicBlock::iterator ReturnLoc = --MBB->end();
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric       while (ReturnLoc->isDebugInstr())
1480b57cec5SDimitry Andric         --ReturnLoc;
1490b57cec5SDimitry Andric       assert(ReturnLoc->isReturn() && !ReturnLoc->isCall() &&
1500b57cec5SDimitry Andric              "Basic block does not end with RET");
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric       addPadding(MBB, ReturnLoc, Threshold - Cycles);
1530b57cec5SDimitry Andric       NumBBsPadded++;
1540b57cec5SDimitry Andric       MadeChange = true;
1550b57cec5SDimitry Andric     }
1560b57cec5SDimitry Andric   }
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric   return MadeChange;
1590b57cec5SDimitry Andric }
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric /// findReturn - Starting at MBB, follow control flow and add all
1620b57cec5SDimitry Andric /// basic blocks that contain a return to ReturnBBs.
findReturns(MachineBasicBlock * MBB,unsigned int Cycles)1630b57cec5SDimitry Andric void PadShortFunc::findReturns(MachineBasicBlock *MBB, unsigned int Cycles) {
1640b57cec5SDimitry Andric   // If this BB has a return, note how many cycles it takes to get there.
1650b57cec5SDimitry Andric   bool hasReturn = cyclesUntilReturn(MBB, Cycles);
1660b57cec5SDimitry Andric   if (Cycles >= Threshold)
1670b57cec5SDimitry Andric     return;
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric   if (hasReturn) {
1700b57cec5SDimitry Andric     ReturnBBs[MBB] = std::max(ReturnBBs[MBB], Cycles);
1710b57cec5SDimitry Andric     return;
1720b57cec5SDimitry Andric   }
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric   // Follow branches in BB and look for returns
175349cc55cSDimitry Andric   for (MachineBasicBlock *Succ : MBB->successors())
176349cc55cSDimitry Andric     if (Succ != MBB)
177349cc55cSDimitry Andric       findReturns(Succ, Cycles);
1780b57cec5SDimitry Andric }
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric /// cyclesUntilReturn - return true if the MBB has a return instruction,
1810b57cec5SDimitry Andric /// and return false otherwise.
1820b57cec5SDimitry Andric /// Cycles will be incremented by the number of cycles taken to reach the
1830b57cec5SDimitry Andric /// return or the end of the BB, whichever occurs first.
cyclesUntilReturn(MachineBasicBlock * MBB,unsigned int & Cycles)1840b57cec5SDimitry Andric bool PadShortFunc::cyclesUntilReturn(MachineBasicBlock *MBB,
1850b57cec5SDimitry Andric                                      unsigned int &Cycles) {
1860b57cec5SDimitry Andric   // Return cached result if BB was previously visited
1870b57cec5SDimitry Andric   DenseMap<MachineBasicBlock*, VisitedBBInfo>::iterator it
1880b57cec5SDimitry Andric     = VisitedBBs.find(MBB);
1890b57cec5SDimitry Andric   if (it != VisitedBBs.end()) {
1900b57cec5SDimitry Andric     VisitedBBInfo BBInfo = it->second;
1910b57cec5SDimitry Andric     Cycles += BBInfo.Cycles;
1920b57cec5SDimitry Andric     return BBInfo.HasReturn;
1930b57cec5SDimitry Andric   }
1940b57cec5SDimitry Andric 
1950b57cec5SDimitry Andric   unsigned int CyclesToEnd = 0;
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric   for (MachineInstr &MI : *MBB) {
1980b57cec5SDimitry Andric     // Mark basic blocks with a return instruction. Calls to other
1990b57cec5SDimitry Andric     // functions do not count because the called function will be padded,
2000b57cec5SDimitry Andric     // if necessary.
2010b57cec5SDimitry Andric     if (MI.isReturn() && !MI.isCall()) {
2020b57cec5SDimitry Andric       VisitedBBs[MBB] = VisitedBBInfo(true, CyclesToEnd);
2030b57cec5SDimitry Andric       Cycles += CyclesToEnd;
2040b57cec5SDimitry Andric       return true;
2050b57cec5SDimitry Andric     }
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric     CyclesToEnd += TSM.computeInstrLatency(&MI);
2080b57cec5SDimitry Andric   }
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric   VisitedBBs[MBB] = VisitedBBInfo(false, CyclesToEnd);
2110b57cec5SDimitry Andric   Cycles += CyclesToEnd;
2120b57cec5SDimitry Andric   return false;
2130b57cec5SDimitry Andric }
2140b57cec5SDimitry Andric 
2150b57cec5SDimitry Andric /// addPadding - Add the given number of NOOP instructions to the function
2160b57cec5SDimitry Andric /// just prior to the return at MBBI
addPadding(MachineBasicBlock * MBB,MachineBasicBlock::iterator & MBBI,unsigned int NOOPsToAdd)2170b57cec5SDimitry Andric void PadShortFunc::addPadding(MachineBasicBlock *MBB,
2180b57cec5SDimitry Andric                               MachineBasicBlock::iterator &MBBI,
2190b57cec5SDimitry Andric                               unsigned int NOOPsToAdd) {
220fe6060f1SDimitry Andric   const DebugLoc &DL = MBBI->getDebugLoc();
2210b57cec5SDimitry Andric   unsigned IssueWidth = TSM.getIssueWidth();
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric   for (unsigned i = 0, e = IssueWidth * NOOPsToAdd; i != e; ++i)
2240b57cec5SDimitry Andric     BuildMI(*MBB, MBBI, DL, TSM.getInstrInfo()->get(X86::NOOP));
2250b57cec5SDimitry Andric }
226