#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/CodeGen/BasicBlockSectionsProfileReader.h"
#include "llvm/CodeGen/BasicBlockSectionUtils.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/InitializePasses.h"
#include "llvm/Target/TargetMachine.h"
using namespace llvm;
cl::opt<std::string> llvm::BBSectionsColdTextPrefix(
"bbsections-cold-text-prefix",
cl::desc("The text prefix to use for cold basic block clusters"),
cl::init(".text.split."), cl::Hidden);
cl::opt<bool> BBSectionsDetectSourceDrift(
"bbsections-detect-source-drift",
cl::desc("This checks if there is a fdo instr. profile hash "
"mismatch for this function"),
cl::init(true), cl::Hidden);
namespace {
class BasicBlockSections : public MachineFunctionPass {
public:
static char ID;
BasicBlockSectionsProfileReader *BBSectionsProfileReader = nullptr;
BasicBlockSections() : MachineFunctionPass(ID) {
initializeBasicBlockSectionsPass(*PassRegistry::getPassRegistry());
}
StringRef getPassName() const override {
return "Basic Block Sections Analysis";
}
void getAnalysisUsage(AnalysisUsage &AU) const override;
bool runOnMachineFunction(MachineFunction &MF) override;
};
}
char BasicBlockSections::ID = 0;
INITIALIZE_PASS(BasicBlockSections, "bbsections-prepare",
"Prepares for basic block sections, by splitting functions "
"into clusters of basic blocks.",
false, false)
static void updateBranches(
MachineFunction &MF,
const SmallVector<MachineBasicBlock *, 4> &PreLayoutFallThroughs) {
const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
SmallVector<MachineOperand, 4> Cond;
for (auto &MBB : MF) {
auto NextMBBI = std::next(MBB.getIterator());
auto *FTMBB = PreLayoutFallThroughs[MBB.getNumber()];
if (FTMBB && (MBB.isEndSection() || &*NextMBBI != FTMBB))
TII->insertUnconditionalBranch(MBB, FTMBB, MBB.findBranchDebugLoc());
if (MBB.isEndSection())
continue;
Cond.clear();
MachineBasicBlock *TBB = nullptr, *FBB = nullptr; if (TII->analyzeBranch(MBB, TBB, FBB, Cond))
continue;
MBB.updateTerminator(FTMBB);
}
}
bool getBBClusterInfoForFunction(
const MachineFunction &MF,
BasicBlockSectionsProfileReader *BBSectionsProfileReader,
std::vector<Optional<BBClusterInfo>> &V) {
std::pair<bool, SmallVector<BBClusterInfo, 4>> P =
BBSectionsProfileReader->getBBClusterInfoForFunction(MF.getName());
if (!P.first)
return false;
if (P.second.empty()) {
V.clear();
return true;
}
V.resize(MF.getNumBlockIDs());
for (auto bbClusterInfo : P.second) {
if (bbClusterInfo.MBBNumber >= MF.getNumBlockIDs())
return false;
V[bbClusterInfo.MBBNumber] = bbClusterInfo;
}
return true;
}
static void
assignSections(MachineFunction &MF,
const std::vector<Optional<BBClusterInfo>> &FuncBBClusterInfo) {
assert(MF.hasBBSections() && "BB Sections is not set for function.");
Optional<MBBSectionID> EHPadsSectionID;
for (auto &MBB : MF) {
if (MF.getTarget().getBBSectionsType() == llvm::BasicBlockSection::All ||
FuncBBClusterInfo.empty()) {
MBB.setSectionID({static_cast<unsigned int>(MBB.getNumber())});
} else if (FuncBBClusterInfo[MBB.getNumber()])
MBB.setSectionID(FuncBBClusterInfo[MBB.getNumber()]->ClusterID);
else {
MBB.setSectionID(MBBSectionID::ColdSectionID);
}
if (MBB.isEHPad() && EHPadsSectionID != MBB.getSectionID() &&
EHPadsSectionID != MBBSectionID::ExceptionSectionID) {
EHPadsSectionID = EHPadsSectionID ? MBBSectionID::ExceptionSectionID
: MBB.getSectionID();
}
}
if (EHPadsSectionID == MBBSectionID::ExceptionSectionID)
for (auto &MBB : MF)
if (MBB.isEHPad())
MBB.setSectionID(*EHPadsSectionID);
}
void llvm::sortBasicBlocksAndUpdateBranches(
MachineFunction &MF, MachineBasicBlockComparator MBBCmp) {
SmallVector<MachineBasicBlock *, 4> PreLayoutFallThroughs(
MF.getNumBlockIDs());
for (auto &MBB : MF)
PreLayoutFallThroughs[MBB.getNumber()] = MBB.getFallThrough();
MF.sort(MBBCmp);
MF.assignBeginEndSections();
updateBranches(MF, PreLayoutFallThroughs);
}
void llvm::avoidZeroOffsetLandingPad(MachineFunction &MF) {
for (auto &MBB : MF) {
if (MBB.isBeginSection() && MBB.isEHPad()) {
MachineBasicBlock::iterator MI = MBB.begin();
while (!MI->isEHLabel())
++MI;
MCInst Nop = MF.getSubtarget().getInstrInfo()->getNop();
BuildMI(MBB, MI, DebugLoc(),
MF.getSubtarget().getInstrInfo()->get(Nop.getOpcode()));
}
}
}
static bool hasInstrProfHashMismatch(MachineFunction &MF) {
if (!BBSectionsDetectSourceDrift)
return false;
const char MetadataName[] = "instr_prof_hash_mismatch";
auto *Existing = MF.getFunction().getMetadata(LLVMContext::MD_annotation);
if (Existing) {
MDTuple *Tuple = cast<MDTuple>(Existing);
for (const auto &N : Tuple->operands())
if (cast<MDString>(N.get())->getString() == MetadataName)
return true;
}
return false;
}
bool BasicBlockSections::runOnMachineFunction(MachineFunction &MF) {
auto BBSectionsType = MF.getTarget().getBBSectionsType();
assert(BBSectionsType != BasicBlockSection::None &&
"BB Sections not enabled!");
if (BBSectionsType == BasicBlockSection::List &&
hasInstrProfHashMismatch(MF))
return true;
MF.RenumberBlocks();
if (BBSectionsType == BasicBlockSection::Labels) {
MF.setBBSectionsType(BBSectionsType);
return true;
}
BBSectionsProfileReader = &getAnalysis<BasicBlockSectionsProfileReader>();
std::vector<Optional<BBClusterInfo>> FuncBBClusterInfo;
if (BBSectionsType == BasicBlockSection::List &&
!getBBClusterInfoForFunction(MF, BBSectionsProfileReader,
FuncBBClusterInfo))
return true;
MF.setBBSectionsType(BBSectionsType);
assignSections(MF, FuncBBClusterInfo);
auto EntryBBSectionID = MF.front().getSectionID();
auto MBBSectionOrder = [EntryBBSectionID](const MBBSectionID &LHS,
const MBBSectionID &RHS) {
if (LHS == EntryBBSectionID || RHS == EntryBBSectionID)
return LHS == EntryBBSectionID;
return LHS.Type == RHS.Type ? LHS.Number < RHS.Number : LHS.Type < RHS.Type;
};
auto Comparator = [&](const MachineBasicBlock &X,
const MachineBasicBlock &Y) {
auto XSectionID = X.getSectionID();
auto YSectionID = Y.getSectionID();
if (XSectionID != YSectionID)
return MBBSectionOrder(XSectionID, YSectionID);
if (XSectionID.Type == MBBSectionID::SectionType::Default)
return FuncBBClusterInfo[X.getNumber()]->PositionInCluster <
FuncBBClusterInfo[Y.getNumber()]->PositionInCluster;
return X.getNumber() < Y.getNumber();
};
sortBasicBlocksAndUpdateBranches(MF, Comparator);
avoidZeroOffsetLandingPad(MF);
return true;
}
void BasicBlockSections::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
AU.addRequired<BasicBlockSectionsProfileReader>();
MachineFunctionPass::getAnalysisUsage(AU);
}
MachineFunctionPass *llvm::createBasicBlockSectionsPass() {
return new BasicBlockSections();
}