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