#include "X86.h"
#include "X86InstrInfo.h"
#include "X86Subtarget.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/CodeGen/LazyMachineBlockFrequencyInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineSizeOpts.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/TargetSchedule.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
#define DEBUG_TYPE "x86-pad-short-functions"
STATISTIC(NumBBsPadded, "Number of basic blocks padded");
namespace {
struct VisitedBBInfo {
bool HasReturn = false;
unsigned int Cycles = 0;
VisitedBBInfo() = default;
VisitedBBInfo(bool HasReturn, unsigned int Cycles)
: HasReturn(HasReturn), Cycles(Cycles) {}
};
struct PadShortFunc : public MachineFunctionPass {
static char ID;
PadShortFunc() : MachineFunctionPass(ID) {}
bool runOnMachineFunction(MachineFunction &MF) override;
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<ProfileSummaryInfoWrapperPass>();
AU.addRequired<LazyMachineBlockFrequencyInfoPass>();
AU.addPreserved<LazyMachineBlockFrequencyInfoPass>();
MachineFunctionPass::getAnalysisUsage(AU);
}
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
MachineFunctionProperties::Property::NoVRegs);
}
StringRef getPassName() const override {
return "X86 Atom pad short functions";
}
private:
void findReturns(MachineBasicBlock *MBB,
unsigned int Cycles = 0);
bool cyclesUntilReturn(MachineBasicBlock *MBB,
unsigned int &Cycles);
void addPadding(MachineBasicBlock *MBB,
MachineBasicBlock::iterator &MBBI,
unsigned int NOOPsToAdd);
const unsigned int Threshold = 4;
DenseMap<MachineBasicBlock*, unsigned int> ReturnBBs;
DenseMap<MachineBasicBlock*, VisitedBBInfo> VisitedBBs;
TargetSchedModel TSM;
};
char PadShortFunc::ID = 0;
}
FunctionPass *llvm::createX86PadShortFunctions() {
return new PadShortFunc();
}
bool PadShortFunc::runOnMachineFunction(MachineFunction &MF) {
if (skipFunction(MF.getFunction()))
return false;
if (MF.getFunction().hasOptSize())
return false;
if (!MF.getSubtarget<X86Subtarget>().padShortFunctions())
return false;
TSM.init(&MF.getSubtarget());
auto *PSI =
&getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI();
auto *MBFI = (PSI && PSI->hasProfileSummary()) ?
&getAnalysis<LazyMachineBlockFrequencyInfoPass>().getBFI() :
nullptr;
ReturnBBs.clear();
VisitedBBs.clear();
findReturns(&MF.front());
bool MadeChange = false;
for (const auto &ReturnBB : ReturnBBs) {
MachineBasicBlock *MBB = ReturnBB.first;
unsigned Cycles = ReturnBB.second;
bool OptForSize = llvm::shouldOptimizeForSize(MBB, PSI, MBFI);
if (OptForSize)
continue;
if (Cycles < Threshold) {
assert(MBB->size() > 0 &&
"Basic block should contain at least a RET but is empty");
MachineBasicBlock::iterator ReturnLoc = --MBB->end();
while (ReturnLoc->isDebugInstr())
--ReturnLoc;
assert(ReturnLoc->isReturn() && !ReturnLoc->isCall() &&
"Basic block does not end with RET");
addPadding(MBB, ReturnLoc, Threshold - Cycles);
NumBBsPadded++;
MadeChange = true;
}
}
return MadeChange;
}
void PadShortFunc::findReturns(MachineBasicBlock *MBB, unsigned int Cycles) {
bool hasReturn = cyclesUntilReturn(MBB, Cycles);
if (Cycles >= Threshold)
return;
if (hasReturn) {
ReturnBBs[MBB] = std::max(ReturnBBs[MBB], Cycles);
return;
}
for (MachineBasicBlock *Succ : MBB->successors())
if (Succ != MBB)
findReturns(Succ, Cycles);
}
bool PadShortFunc::cyclesUntilReturn(MachineBasicBlock *MBB,
unsigned int &Cycles) {
DenseMap<MachineBasicBlock*, VisitedBBInfo>::iterator it
= VisitedBBs.find(MBB);
if (it != VisitedBBs.end()) {
VisitedBBInfo BBInfo = it->second;
Cycles += BBInfo.Cycles;
return BBInfo.HasReturn;
}
unsigned int CyclesToEnd = 0;
for (MachineInstr &MI : *MBB) {
if (MI.isReturn() && !MI.isCall()) {
VisitedBBs[MBB] = VisitedBBInfo(true, CyclesToEnd);
Cycles += CyclesToEnd;
return true;
}
CyclesToEnd += TSM.computeInstrLatency(&MI);
}
VisitedBBs[MBB] = VisitedBBInfo(false, CyclesToEnd);
Cycles += CyclesToEnd;
return false;
}
void PadShortFunc::addPadding(MachineBasicBlock *MBB,
MachineBasicBlock::iterator &MBBI,
unsigned int NOOPsToAdd) {
const DebugLoc &DL = MBBI->getDebugLoc();
unsigned IssueWidth = TSM.getIssueWidth();
for (unsigned i = 0, e = IssueWidth * NOOPsToAdd; i != e; ++i)
BuildMI(*MBB, MBBI, DL, TSM.getInstrInfo()->get(X86::NOOP));
}