Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 1 | //===-- BBSectionsPrepare.cpp ---=========---------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // BBSectionsPrepare implementation. |
| 10 | // |
| 11 | // The purpose of this pass is to assign sections to basic blocks when |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 12 | // -fbasicblock-sections= option is used. Exception landing pad blocks are |
| 13 | // specially handled by grouping them in a single section. Further, with |
| 14 | // profile information only the subset of basic blocks with profiles are placed |
| 15 | // in a separate section and the rest are grouped in a cold section. |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 16 | // |
| 17 | // Basic Block Sections |
| 18 | // ==================== |
| 19 | // |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 20 | // With option, -fbasicblock-sections=, each basic block could be placed in a |
| 21 | // unique ELF text section in the object file along with a symbol labelling the |
| 22 | // basic block. The linker can then order the basic block sections in any |
| 23 | // arbitrary sequence which when done correctly can encapsulate block layout, |
| 24 | // function layout and function splitting optimizations. However, there are a |
| 25 | // couple of challenges to be addressed for this to be feasible: |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 26 | // |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 27 | // 1. The compiler must not allow any implicit fall-through between any two |
| 28 | // adjacent basic blocks as they could be reordered at link time to be |
| 29 | // non-adjacent. In other words, the compiler must make a fall-through |
| 30 | // between adjacent basic blocks explicit by retaining the direct jump |
| 31 | // instruction that jumps to the next basic block. |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 32 | // |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 33 | // 2. All inter-basic block branch targets would now need to be resolved by the |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 34 | // linker as they cannot be calculated during compile time. This is done |
| 35 | // using static relocations. Further, the compiler tries to use short branch |
| 36 | // instructions on some ISAs for small branch offsets. This is not possible |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 37 | // with basic block sections as the offset is not determined at compile time, |
| 38 | // and long branch instructions have to be used everywhere. |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 39 | // |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 40 | // 3. Each additional section bloats object file sizes by tens of bytes. The |
| 41 | // number of basic blocks can be potentially very large compared to the size |
| 42 | // of functions and can bloat object sizes significantly. Option |
| 43 | // fbasicblock-sections= also takes a file path which can be used to specify |
| 44 | // a subset of basic blocks that needs unique sections to keep the bloats |
| 45 | // small. |
| 46 | // |
| 47 | // 4. Debug Information (DebugInfo) and Call Frame Information (CFI) emission |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 48 | // needs special handling with basic block sections. DebugInfo needs to be |
| 49 | // emitted with more relocations as basic block sections can break a |
| 50 | // function into potentially several disjoint pieces, and CFI needs to be |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 51 | // emitted per basic block. This also bloats the object file and binary |
| 52 | // sizes. |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 53 | // |
| 54 | // Basic Block Labels |
| 55 | // ================== |
| 56 | // |
| 57 | // With -fbasicblock-sections=labels, or when a basic block is placed in a |
| 58 | // unique section, it is labelled with a symbol. This allows easy mapping of |
| 59 | // virtual addresses from PMU profiles back to the corresponding basic blocks. |
| 60 | // Since the number of basic blocks is large, the labeling bloats the symbol |
| 61 | // table sizes and the string table sizes significantly. While the binary size |
| 62 | // does increase, it does not affect performance as the symbol table is not |
| 63 | // loaded in memory during run-time. The string table size bloat is kept very |
| 64 | // minimal using a unary naming scheme that uses string suffix compression. The |
| 65 | // basic blocks for function foo are named "a.BB.foo", "aa.BB.foo", ... This |
| 66 | // turns out to be very good for string table sizes and the bloat in the string |
| 67 | // table size for a very large binary is ~8 %. The naming also allows using |
| 68 | // the --symbol-ordering-file option in LLD to arbitrarily reorder the |
| 69 | // sections. |
| 70 | // |
| 71 | //===----------------------------------------------------------------------===// |
| 72 | |
| 73 | #include "llvm/ADT/SmallSet.h" |
| 74 | #include "llvm/ADT/StringMap.h" |
| 75 | #include "llvm/ADT/StringRef.h" |
| 76 | #include "llvm/CodeGen/MachineFunction.h" |
| 77 | #include "llvm/CodeGen/MachineFunctionPass.h" |
| 78 | #include "llvm/CodeGen/MachineModuleInfo.h" |
| 79 | #include "llvm/CodeGen/Passes.h" |
| 80 | #include "llvm/CodeGen/TargetInstrInfo.h" |
| 81 | #include "llvm/InitializePasses.h" |
| 82 | #include "llvm/Support/LineIterator.h" |
| 83 | #include "llvm/Support/MemoryBuffer.h" |
| 84 | #include "llvm/Target/TargetMachine.h" |
| 85 | |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 86 | #include <string> |
| 87 | |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 88 | using llvm::SmallSet; |
| 89 | using llvm::StringMap; |
| 90 | using llvm::StringRef; |
| 91 | using namespace llvm; |
| 92 | |
| 93 | namespace { |
| 94 | |
| 95 | class BBSectionsPrepare : public MachineFunctionPass { |
| 96 | public: |
| 97 | static char ID; |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 98 | StringMap<SmallSet<unsigned, 4>> BBSectionsList; |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 99 | const MemoryBuffer *MBuf = nullptr; |
| 100 | |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 101 | BBSectionsPrepare() : MachineFunctionPass(ID) { |
| 102 | initializeBBSectionsPreparePass(*PassRegistry::getPassRegistry()); |
| 103 | } |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 104 | |
| 105 | BBSectionsPrepare(const MemoryBuffer *Buf) |
| 106 | : MachineFunctionPass(ID), MBuf(Buf) { |
| 107 | initializeBBSectionsPreparePass(*PassRegistry::getPassRegistry()); |
| 108 | }; |
| 109 | |
| 110 | StringRef getPassName() const override { |
| 111 | return "Basic Block Sections Analysis"; |
| 112 | } |
| 113 | |
| 114 | void getAnalysisUsage(AnalysisUsage &AU) const override; |
| 115 | |
| 116 | /// Read profiles of basic blocks if available here. |
| 117 | bool doInitialization(Module &M) override; |
| 118 | |
| 119 | /// Identify basic blocks that need separate sections and prepare to emit them |
| 120 | /// accordingly. |
| 121 | bool runOnMachineFunction(MachineFunction &MF) override; |
| 122 | }; |
| 123 | |
| 124 | } // end anonymous namespace |
| 125 | |
| 126 | char BBSectionsPrepare::ID = 0; |
| 127 | INITIALIZE_PASS(BBSectionsPrepare, "bbsections-prepare", |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 128 | "Determine if a basic block needs a special section", false, |
| 129 | false) |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 130 | |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 131 | // This inserts an unconditional branch at the end of MBB to the next basic |
| 132 | // block S if and only if the control-flow implicitly falls through from MBB to |
| 133 | // S and S and MBB belong to different sections. This is necessary with basic |
| 134 | // block sections as MBB and S could be potentially reordered. |
| 135 | static void insertUnconditionalFallthroughBranch(MachineBasicBlock &MBB) { |
| 136 | MachineBasicBlock *Fallthrough = MBB.getFallThrough(); |
| 137 | |
| 138 | if (Fallthrough == nullptr) |
| 139 | return; |
| 140 | |
| 141 | // If this basic block and the Fallthrough basic block are in the same |
| 142 | // section then do not insert the jump. |
| 143 | if (MBB.sameSection(Fallthrough)) |
| 144 | return; |
| 145 | |
| 146 | const TargetInstrInfo *TII = MBB.getParent()->getSubtarget().getInstrInfo(); |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 147 | SmallVector<MachineOperand, 4> Cond; |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 148 | MachineBasicBlock *TBB = nullptr, *FBB = nullptr; |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 149 | |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 150 | // If a branch to the fall through block already exists, return. |
| 151 | if (!TII->analyzeBranch(MBB, TBB, FBB, Cond) && |
| 152 | (TBB == Fallthrough || FBB == Fallthrough)) { |
| 153 | return; |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 154 | } |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 155 | |
| 156 | Cond.clear(); |
| 157 | DebugLoc DL = MBB.findBranchDebugLoc(); |
| 158 | TII->insertBranch(MBB, Fallthrough, nullptr, Cond, DL); |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 159 | } |
| 160 | |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 161 | /// This function sorts basic blocks according to the sections in which they are |
| 162 | /// emitted. Basic block sections automatically turn on function sections so |
| 163 | /// the entry block is in the function section. The other sections that are |
| 164 | /// created are: |
| 165 | /// 1) Exception section - basic blocks that are landing pads |
| 166 | /// 2) Cold section - basic blocks that will not have unique sections. |
| 167 | /// 3) Unique section - one per basic block that is emitted in a unique section. |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 168 | static bool assignSectionsAndSortBasicBlocks( |
| 169 | MachineFunction &MF, |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 170 | const StringMap<SmallSet<unsigned, 4>> &BBSectionsList) { |
| 171 | SmallSet<unsigned, 4> S = BBSectionsList.lookup(MF.getName()); |
| 172 | |
| 173 | bool HasHotEHPads = false; |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 174 | |
| 175 | for (auto &MBB : MF) { |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 176 | // Entry basic block cannot start another section because the function |
| 177 | // starts one already. |
| 178 | if (MBB.getNumber() == MF.front().getNumber()) { |
| 179 | MBB.setSectionType(MachineBasicBlockSection::MBBS_Entry); |
| 180 | continue; |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 181 | } |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 182 | // Check if this BB is a cold basic block. With the list option, all cold |
| 183 | // basic blocks can be clustered in a single cold section. |
| 184 | // All Exception landing pads must be in a single section. If all the |
| 185 | // landing pads are cold, it can be kept in the cold section. Otherwise, we |
| 186 | // create a separate exception section. |
| 187 | bool isColdBB = ((MF.getTarget().getBBSectionsType() == |
| 188 | llvm::BasicBlockSection::List) && |
| 189 | !S.empty() && !S.count(MBB.getNumber())); |
| 190 | if (isColdBB) { |
| 191 | MBB.setSectionType(MachineBasicBlockSection::MBBS_Cold); |
| 192 | } else if (MBB.isEHPad()) { |
| 193 | // We handle non-cold basic eh blocks later. |
| 194 | HasHotEHPads = true; |
| 195 | } else { |
| 196 | // Place this MBB in a unique section. A unique section begins and ends |
| 197 | // that section by definition. |
| 198 | MBB.setSectionType(MachineBasicBlockSection::MBBS_Unique); |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 199 | } |
| 200 | } |
| 201 | |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 202 | // If some EH Pads are not cold then we move all EH Pads to the exception |
| 203 | // section as we require that all EH Pads be in a single section. |
| 204 | if (HasHotEHPads) { |
| 205 | std::for_each(MF.begin(), MF.end(), [&](MachineBasicBlock &MBB) { |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 206 | if (MBB.isEHPad()) |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 207 | MBB.setSectionType(MachineBasicBlockSection::MBBS_Exception); |
| 208 | }); |
| 209 | } |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 210 | |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 211 | for (auto &MBB : MF) { |
| 212 | // With -fbasicblock-sections, fall through blocks must be made |
| 213 | // explicitly reachable. Do this after sections is set as |
| 214 | // unnecessary fallthroughs can be avoided. |
| 215 | insertUnconditionalFallthroughBranch(MBB); |
| 216 | } |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 217 | |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 218 | MF.sort(([&](MachineBasicBlock &X, MachineBasicBlock &Y) { |
| 219 | unsigned TypeX = X.getSectionType(); |
| 220 | unsigned TypeY = Y.getSectionType(); |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 221 | |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 222 | return (TypeX != TypeY) ? TypeX < TypeY : X.getNumber() < Y.getNumber(); |
| 223 | })); |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 224 | |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 225 | MF.setSectionRange(); |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 226 | return true; |
| 227 | } |
| 228 | |
| 229 | bool BBSectionsPrepare::runOnMachineFunction(MachineFunction &MF) { |
| 230 | auto BBSectionsType = MF.getTarget().getBBSectionsType(); |
| 231 | assert(BBSectionsType != BasicBlockSection::None && |
| 232 | "BB Sections not enabled!"); |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 233 | |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 234 | // Renumber blocks before sorting them for basic block sections. This is |
| 235 | // useful during sorting, basic blocks in the same section will retain the |
| 236 | // default order. This renumbering should also be done for basic block |
| 237 | // labels to match the profiles with the correct blocks. |
| 238 | MF.RenumberBlocks(); |
| 239 | |
| 240 | if (BBSectionsType == BasicBlockSection::Labels) { |
| 241 | MF.setBBSectionsType(BBSectionsType); |
| 242 | MF.createBBLabels(); |
| 243 | return true; |
| 244 | } |
| 245 | |
| 246 | if (BBSectionsType == BasicBlockSection::List && |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 247 | BBSectionsList.find(MF.getName()) == BBSectionsList.end()) |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 248 | return true; |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 249 | |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 250 | MF.setBBSectionsType(BBSectionsType); |
| 251 | MF.createBBLabels(); |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 252 | assignSectionsAndSortBasicBlocks(MF, BBSectionsList); |
| 253 | |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 254 | return true; |
| 255 | } |
| 256 | |
| 257 | // Basic Block Sections can be enabled for a subset of machine basic blocks. |
| 258 | // This is done by passing a file containing names of functions for which basic |
| 259 | // block sections are desired. Additionally, machine basic block ids of the |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 260 | // functions can also be specified for a finer granularity. |
| 261 | // A file with basic block sections for all of function main and two blocks for |
| 262 | // function foo looks like this: |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 263 | // ---------------------------- |
| 264 | // list.txt: |
| 265 | // !main |
| 266 | // !foo |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 267 | // !!2 |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 268 | // !!4 |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 269 | static bool getBBSectionsList(const MemoryBuffer *MBuf, |
| 270 | StringMap<SmallSet<unsigned, 4>> &bbMap) { |
| 271 | if (!MBuf) |
| 272 | return false; |
| 273 | |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 274 | line_iterator LineIt(*MBuf, /*SkipBlanks=*/true, /*CommentMarker=*/'#'); |
| 275 | |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 276 | StringMap<SmallSet<unsigned, 4>>::iterator fi = bbMap.end(); |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 277 | |
| 278 | for (; !LineIt.is_at_eof(); ++LineIt) { |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 279 | StringRef s(*LineIt); |
| 280 | if (s[0] == '@') |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 281 | continue; |
| 282 | // Check for the leading "!" |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 283 | if (!s.consume_front("!") || s.empty()) |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 284 | break; |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 285 | // Check for second "!" which encodes basic block ids. |
| 286 | if (s.consume_front("!")) { |
| 287 | if (fi != bbMap.end()) |
| 288 | fi->second.insert(std::stoi(s.str())); |
| 289 | else |
| 290 | return false; |
| 291 | } else { |
| 292 | // Start a new function. |
| 293 | auto R = bbMap.try_emplace(s.split('/').first); |
| 294 | fi = R.first; |
| 295 | assert(R.second); |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 296 | } |
| 297 | } |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 298 | return true; |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 299 | } |
| 300 | |
| 301 | bool BBSectionsPrepare::doInitialization(Module &M) { |
Rahman Lavaee | 4ddf7ab | 2020-04-13 12:12:34 -0700 | [diff] [blame^] | 302 | if (MBuf) |
| 303 | getBBSectionsList(MBuf, BBSectionsList); |
| 304 | return true; |
Sriraman Tallam | df082ac | 2020-03-16 15:56:02 -0700 | [diff] [blame] | 305 | } |
| 306 | |
| 307 | void BBSectionsPrepare::getAnalysisUsage(AnalysisUsage &AU) const { |
| 308 | AU.setPreservesAll(); |
| 309 | AU.addRequired<MachineModuleInfoWrapperPass>(); |
| 310 | } |
| 311 | |
| 312 | MachineFunctionPass * |
| 313 | llvm::createBBSectionsPreparePass(const MemoryBuffer *Buf) { |
| 314 | return new BBSectionsPrepare(Buf); |
| 315 | } |