//===-- 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 using llvm::SmallSet; using llvm::StringMap; using llvm::StringRef; using namespace llvm; namespace { class BBSectionsPrepare : public MachineFunctionPass { public: static char ID; StringMap> 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 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> &BBSectionsList) { SmallSet 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> &bbMap) { if (!MBuf) return false; line_iterator LineIt(*MBuf, /*SkipBlanks=*/true, /*CommentMarker=*/'#'); StringMap>::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(); } MachineFunctionPass * llvm::createBBSectionsPreparePass(const MemoryBuffer *Buf) { return new BBSectionsPrepare(Buf); }