llvm-project/llvm/lib/CodeGen/BBSectionsPrepare.cpp

316 lines
12 KiB
C++

//===-- BBSectionsPrepare.cpp ---=========---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// BBSectionsPrepare implementation.
//
// The purpose of this pass is to assign sections to basic blocks when
// -fbasicblock-sections= option is used. Exception landing pad blocks are
// specially handled by grouping them in a single section. Further, with
// profile information only the subset of basic blocks with profiles are placed
// in a separate section and the rest are grouped in a cold section.
//
// Basic Block Sections
// ====================
//
// With option, -fbasicblock-sections=, each basic block could be placed in a
// unique ELF text section in the object file along with a symbol labelling the
// basic block. The linker can then order the basic block sections in any
// arbitrary sequence which when done correctly can encapsulate block layout,
// function layout and function splitting optimizations. However, there are a
// couple of challenges to be addressed for this to be feasible:
//
// 1. The compiler must not allow any implicit fall-through between any two
// adjacent basic blocks as they could be reordered at link time to be
// non-adjacent. In other words, the compiler must make a fall-through
// between adjacent basic blocks explicit by retaining the direct jump
// instruction that jumps to the next basic block.
//
// 2. All inter-basic block branch targets would now need to be resolved by the
// linker as they cannot be calculated during compile time. This is done
// using static relocations. Further, the compiler tries to use short branch
// instructions on some ISAs for small branch offsets. This is not possible
// with basic block sections as the offset is not determined at compile time,
// and long branch instructions have to be used everywhere.
//
// 3. Each additional section bloats object file sizes by tens of bytes. The
// number of basic blocks can be potentially very large compared to the size
// of functions and can bloat object sizes significantly. Option
// fbasicblock-sections= also takes a file path which can be used to specify
// a subset of basic blocks that needs unique sections to keep the bloats
// small.
//
// 4. Debug Information (DebugInfo) and Call Frame Information (CFI) emission
// needs special handling with basic block sections. DebugInfo needs to be
// emitted with more relocations as basic block sections can break a
// function into potentially several disjoint pieces, and CFI needs to be
// emitted per basic block. This also bloats the object file and binary
// sizes.
//
// Basic Block Labels
// ==================
//
// With -fbasicblock-sections=labels, or when a basic block is placed in a
// unique section, it is labelled with a symbol. This allows easy mapping of
// virtual addresses from PMU profiles back to the corresponding basic blocks.
// Since the number of basic blocks is large, the labeling bloats the symbol
// table sizes and the string table sizes significantly. While the binary size
// does increase, it does not affect performance as the symbol table is not
// loaded in memory during run-time. The string table size bloat is kept very
// minimal using a unary naming scheme that uses string suffix compression. The
// basic blocks for function foo are named "a.BB.foo", "aa.BB.foo", ... This
// turns out to be very good for string table sizes and the bloat in the string
// table size for a very large binary is ~8 %. The naming also allows using
// the --symbol-ordering-file option in LLD to arbitrarily reorder the
// sections.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/InitializePasses.h"
#include "llvm/Support/LineIterator.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Target/TargetMachine.h"
#include <string>
using llvm::SmallSet;
using llvm::StringMap;
using llvm::StringRef;
using namespace llvm;
namespace {
class BBSectionsPrepare : public MachineFunctionPass {
public:
static char ID;
StringMap<SmallSet<unsigned, 4>> BBSectionsList;
const MemoryBuffer *MBuf = nullptr;
BBSectionsPrepare() : MachineFunctionPass(ID) {
initializeBBSectionsPreparePass(*PassRegistry::getPassRegistry());
}
BBSectionsPrepare(const MemoryBuffer *Buf)
: MachineFunctionPass(ID), MBuf(Buf) {
initializeBBSectionsPreparePass(*PassRegistry::getPassRegistry());
};
StringRef getPassName() const override {
return "Basic Block Sections Analysis";
}
void getAnalysisUsage(AnalysisUsage &AU) const override;
/// Read profiles of basic blocks if available here.
bool doInitialization(Module &M) override;
/// Identify basic blocks that need separate sections and prepare to emit them
/// accordingly.
bool runOnMachineFunction(MachineFunction &MF) override;
};
} // end anonymous namespace
char BBSectionsPrepare::ID = 0;
INITIALIZE_PASS(BBSectionsPrepare, "bbsections-prepare",
"Determine if a basic block needs a special section", false,
false)
// This inserts an unconditional branch at the end of MBB to the next basic
// block S if and only if the control-flow implicitly falls through from MBB to
// S and S and MBB belong to different sections. This is necessary with basic
// block sections as MBB and S could be potentially reordered.
static void insertUnconditionalFallthroughBranch(MachineBasicBlock &MBB) {
MachineBasicBlock *Fallthrough = MBB.getFallThrough();
if (Fallthrough == nullptr)
return;
// If this basic block and the Fallthrough basic block are in the same
// section then do not insert the jump.
if (MBB.sameSection(Fallthrough))
return;
const TargetInstrInfo *TII = MBB.getParent()->getSubtarget().getInstrInfo();
SmallVector<MachineOperand, 4> Cond;
MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
// If a branch to the fall through block already exists, return.
if (!TII->analyzeBranch(MBB, TBB, FBB, Cond) &&
(TBB == Fallthrough || FBB == Fallthrough)) {
return;
}
Cond.clear();
DebugLoc DL = MBB.findBranchDebugLoc();
TII->insertBranch(MBB, Fallthrough, nullptr, Cond, DL);
}
/// This function sorts basic blocks according to the sections in which they are
/// emitted. Basic block sections automatically turn on function sections so
/// the entry block is in the function section. The other sections that are
/// created are:
/// 1) Exception section - basic blocks that are landing pads
/// 2) Cold section - basic blocks that will not have unique sections.
/// 3) Unique section - one per basic block that is emitted in a unique section.
static bool assignSectionsAndSortBasicBlocks(
MachineFunction &MF,
const StringMap<SmallSet<unsigned, 4>> &BBSectionsList) {
SmallSet<unsigned, 4> S = BBSectionsList.lookup(MF.getName());
bool HasHotEHPads = false;
for (auto &MBB : MF) {
// Entry basic block cannot start another section because the function
// starts one already.
if (MBB.getNumber() == MF.front().getNumber()) {
MBB.setSectionType(MachineBasicBlockSection::MBBS_Entry);
continue;
}
// Check if this BB is a cold basic block. With the list option, all cold
// basic blocks can be clustered in a single cold section.
// All Exception landing pads must be in a single section. If all the
// landing pads are cold, it can be kept in the cold section. Otherwise, we
// create a separate exception section.
bool isColdBB = ((MF.getTarget().getBBSectionsType() ==
llvm::BasicBlockSection::List) &&
!S.empty() && !S.count(MBB.getNumber()));
if (isColdBB) {
MBB.setSectionType(MachineBasicBlockSection::MBBS_Cold);
} else if (MBB.isEHPad()) {
// We handle non-cold basic eh blocks later.
HasHotEHPads = true;
} else {
// Place this MBB in a unique section. A unique section begins and ends
// that section by definition.
MBB.setSectionType(MachineBasicBlockSection::MBBS_Unique);
}
}
// If some EH Pads are not cold then we move all EH Pads to the exception
// section as we require that all EH Pads be in a single section.
if (HasHotEHPads) {
std::for_each(MF.begin(), MF.end(), [&](MachineBasicBlock &MBB) {
if (MBB.isEHPad())
MBB.setSectionType(MachineBasicBlockSection::MBBS_Exception);
});
}
for (auto &MBB : MF) {
// With -fbasicblock-sections, fall through blocks must be made
// explicitly reachable. Do this after sections is set as
// unnecessary fallthroughs can be avoided.
insertUnconditionalFallthroughBranch(MBB);
}
MF.sort(([&](MachineBasicBlock &X, MachineBasicBlock &Y) {
unsigned TypeX = X.getSectionType();
unsigned TypeY = Y.getSectionType();
return (TypeX != TypeY) ? TypeX < TypeY : X.getNumber() < Y.getNumber();
}));
MF.setSectionRange();
return true;
}
bool BBSectionsPrepare::runOnMachineFunction(MachineFunction &MF) {
auto BBSectionsType = MF.getTarget().getBBSectionsType();
assert(BBSectionsType != BasicBlockSection::None &&
"BB Sections not enabled!");
// Renumber blocks before sorting them for basic block sections. This is
// useful during sorting, basic blocks in the same section will retain the
// default order. This renumbering should also be done for basic block
// labels to match the profiles with the correct blocks.
MF.RenumberBlocks();
if (BBSectionsType == BasicBlockSection::Labels) {
MF.setBBSectionsType(BBSectionsType);
MF.createBBLabels();
return true;
}
if (BBSectionsType == BasicBlockSection::List &&
BBSectionsList.find(MF.getName()) == BBSectionsList.end())
return true;
MF.setBBSectionsType(BBSectionsType);
MF.createBBLabels();
assignSectionsAndSortBasicBlocks(MF, BBSectionsList);
return true;
}
// Basic Block Sections can be enabled for a subset of machine basic blocks.
// This is done by passing a file containing names of functions for which basic
// block sections are desired. Additionally, machine basic block ids of the
// functions can also be specified for a finer granularity.
// A file with basic block sections for all of function main and two blocks for
// function foo looks like this:
// ----------------------------
// list.txt:
// !main
// !foo
// !!2
// !!4
static bool getBBSectionsList(const MemoryBuffer *MBuf,
StringMap<SmallSet<unsigned, 4>> &bbMap) {
if (!MBuf)
return false;
line_iterator LineIt(*MBuf, /*SkipBlanks=*/true, /*CommentMarker=*/'#');
StringMap<SmallSet<unsigned, 4>>::iterator fi = bbMap.end();
for (; !LineIt.is_at_eof(); ++LineIt) {
StringRef s(*LineIt);
if (s[0] == '@')
continue;
// Check for the leading "!"
if (!s.consume_front("!") || s.empty())
break;
// Check for second "!" which encodes basic block ids.
if (s.consume_front("!")) {
if (fi != bbMap.end())
fi->second.insert(std::stoi(s.str()));
else
return false;
} else {
// Start a new function.
auto R = bbMap.try_emplace(s.split('/').first);
fi = R.first;
assert(R.second);
}
}
return true;
}
bool BBSectionsPrepare::doInitialization(Module &M) {
if (MBuf)
getBBSectionsList(MBuf, BBSectionsList);
return true;
}
void BBSectionsPrepare::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
AU.addRequired<MachineModuleInfoWrapperPass>();
}
MachineFunctionPass *
llvm::createBBSectionsPreparePass(const MemoryBuffer *Buf) {
return new BBSectionsPrepare(Buf);
}