1 //===-- BasicBlockSectionsProfileReader.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 // Implementation of the basic block sections profile reader pass. It parses 10 // and stores the basic block sections profile file (which is specified via the 11 // `-basic-block-sections` flag). 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "llvm/CodeGen/BasicBlockSectionsProfileReader.h" 16 #include "llvm/ADT/SmallSet.h" 17 #include "llvm/ADT/SmallVector.h" 18 #include "llvm/ADT/StringMap.h" 19 #include "llvm/ADT/StringRef.h" 20 #include "llvm/Support/Error.h" 21 #include "llvm/Support/LineIterator.h" 22 #include "llvm/Support/MemoryBuffer.h" 23 24 using namespace llvm; 25 26 char BasicBlockSectionsProfileReader::ID = 0; 27 INITIALIZE_PASS(BasicBlockSectionsProfileReader, "bbsections-profile-reader", 28 "Reads and parses a basic block sections profile.", false, 29 false) 30 31 bool BasicBlockSectionsProfileReader::isFunctionHot(StringRef FuncName) const { 32 return getBBClusterInfoForFunction(FuncName).first; 33 } 34 35 std::pair<bool, SmallVector<BBClusterInfo>> 36 BasicBlockSectionsProfileReader::getBBClusterInfoForFunction( 37 StringRef FuncName) const { 38 std::pair<bool, SmallVector<BBClusterInfo>> cluster_info(false, {}); 39 auto R = ProgramBBClusterInfo.find(getAliasName(FuncName)); 40 if (R != ProgramBBClusterInfo.end()) { 41 cluster_info.second = R->second; 42 cluster_info.first = true; 43 } 44 return cluster_info; 45 } 46 47 // Basic Block Sections can be enabled for a subset of machine basic blocks. 48 // This is done by passing a file containing names of functions for which basic 49 // block sections are desired. Additionally, machine basic block ids of the 50 // functions can also be specified for a finer granularity. Moreover, a cluster 51 // of basic blocks could be assigned to the same section. 52 // A file with basic block sections for all of function main and three blocks 53 // for function foo (of which 1 and 2 are placed in a cluster) looks like this: 54 // ---------------------------- 55 // list.txt: 56 // !main 57 // !foo 58 // !!1 2 59 // !!4 60 static Error getBBClusterInfo(const MemoryBuffer *MBuf, 61 ProgramBBClusterInfoMapTy &ProgramBBClusterInfo, 62 StringMap<StringRef> &FuncAliasMap) { 63 assert(MBuf); 64 line_iterator LineIt(*MBuf, /*SkipBlanks=*/true, /*CommentMarker=*/'#'); 65 66 auto invalidProfileError = [&](auto Message) { 67 return make_error<StringError>( 68 Twine("Invalid profile " + MBuf->getBufferIdentifier() + " at line " + 69 Twine(LineIt.line_number()) + ": " + Message), 70 inconvertibleErrorCode()); 71 }; 72 73 auto FI = ProgramBBClusterInfo.end(); 74 75 // Current cluster ID corresponding to this function. 76 unsigned CurrentCluster = 0; 77 // Current position in the current cluster. 78 unsigned CurrentPosition = 0; 79 80 // Temporary set to ensure every basic block ID appears once in the clusters 81 // of a function. 82 SmallSet<unsigned, 4> FuncBBIDs; 83 84 for (; !LineIt.is_at_eof(); ++LineIt) { 85 StringRef S(*LineIt); 86 if (S[0] == '@') 87 continue; 88 // Check for the leading "!" 89 if (!S.consume_front("!") || S.empty()) 90 break; 91 // Check for second "!" which indicates a cluster of basic blocks. 92 if (S.consume_front("!")) { 93 if (FI == ProgramBBClusterInfo.end()) 94 return invalidProfileError( 95 "Cluster list does not follow a function name specifier."); 96 SmallVector<StringRef, 4> BBIDs; 97 S.split(BBIDs, ' '); 98 // Reset current cluster position. 99 CurrentPosition = 0; 100 for (auto BBIDStr : BBIDs) { 101 unsigned long long BBID; 102 if (getAsUnsignedInteger(BBIDStr, 10, BBID)) 103 return invalidProfileError(Twine("Unsigned integer expected: '") + 104 BBIDStr + "'."); 105 if (!FuncBBIDs.insert(BBID).second) 106 return invalidProfileError(Twine("Duplicate basic block id found '") + 107 BBIDStr + "'."); 108 if (BBID == 0 && CurrentPosition) 109 return invalidProfileError("Entry BB (0) does not begin a cluster."); 110 111 FI->second.emplace_back( 112 BBClusterInfo{((unsigned)BBID), CurrentCluster, CurrentPosition++}); 113 } 114 CurrentCluster++; 115 } else { // This is a function name specifier. 116 // Function aliases are separated using '/'. We use the first function 117 // name for the cluster info mapping and delegate all other aliases to 118 // this one. 119 SmallVector<StringRef, 4> Aliases; 120 S.split(Aliases, '/'); 121 for (size_t i = 1; i < Aliases.size(); ++i) 122 FuncAliasMap.try_emplace(Aliases[i], Aliases.front()); 123 124 // Prepare for parsing clusters of this function name. 125 // Start a new cluster map for this function name. 126 FI = ProgramBBClusterInfo.try_emplace(Aliases.front()).first; 127 CurrentCluster = 0; 128 FuncBBIDs.clear(); 129 } 130 } 131 return Error::success(); 132 } 133 134 void BasicBlockSectionsProfileReader::initializePass() { 135 if (!MBuf) 136 return; 137 if (auto Err = getBBClusterInfo(MBuf, ProgramBBClusterInfo, FuncAliasMap)) 138 report_fatal_error(std::move(Err)); 139 } 140 141 ImmutablePass * 142 llvm::createBasicBlockSectionsProfileReaderPass(const MemoryBuffer *Buf) { 143 return new BasicBlockSectionsProfileReader(Buf); 144 } 145