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