181ad6265SDimitry Andric //===-- BasicBlockSectionsProfileReader.cpp -------------------------------===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric // 981ad6265SDimitry Andric // Implementation of the basic block sections profile reader pass. It parses 1081ad6265SDimitry Andric // and stores the basic block sections profile file (which is specified via the 1181ad6265SDimitry Andric // `-basic-block-sections` flag). 1281ad6265SDimitry Andric // 1381ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1481ad6265SDimitry Andric 1581ad6265SDimitry Andric #include "llvm/CodeGen/BasicBlockSectionsProfileReader.h" 1681ad6265SDimitry Andric #include "llvm/ADT/SmallSet.h" 1781ad6265SDimitry Andric #include "llvm/ADT/SmallVector.h" 1881ad6265SDimitry Andric #include "llvm/ADT/StringMap.h" 1981ad6265SDimitry Andric #include "llvm/ADT/StringRef.h" 2081ad6265SDimitry Andric #include "llvm/Support/Error.h" 2181ad6265SDimitry Andric #include "llvm/Support/LineIterator.h" 2281ad6265SDimitry Andric #include "llvm/Support/MemoryBuffer.h" 2381ad6265SDimitry Andric 2481ad6265SDimitry Andric using namespace llvm; 2581ad6265SDimitry Andric 2681ad6265SDimitry Andric char BasicBlockSectionsProfileReader::ID = 0; 2781ad6265SDimitry Andric INITIALIZE_PASS(BasicBlockSectionsProfileReader, "bbsections-profile-reader", 2881ad6265SDimitry Andric "Reads and parses a basic block sections profile.", false, 2981ad6265SDimitry Andric false) 3081ad6265SDimitry Andric 3181ad6265SDimitry Andric bool BasicBlockSectionsProfileReader::isFunctionHot(StringRef FuncName) const { 3281ad6265SDimitry Andric return getBBClusterInfoForFunction(FuncName).first; 3381ad6265SDimitry Andric } 3481ad6265SDimitry Andric 3581ad6265SDimitry Andric std::pair<bool, SmallVector<BBClusterInfo>> 3681ad6265SDimitry Andric BasicBlockSectionsProfileReader::getBBClusterInfoForFunction( 3781ad6265SDimitry Andric StringRef FuncName) const { 3881ad6265SDimitry Andric std::pair<bool, SmallVector<BBClusterInfo>> cluster_info(false, {}); 3981ad6265SDimitry Andric auto R = ProgramBBClusterInfo.find(getAliasName(FuncName)); 4081ad6265SDimitry Andric if (R != ProgramBBClusterInfo.end()) { 4181ad6265SDimitry Andric cluster_info.second = R->second; 4281ad6265SDimitry Andric cluster_info.first = true; 4381ad6265SDimitry Andric } 4481ad6265SDimitry Andric return cluster_info; 4581ad6265SDimitry Andric } 4681ad6265SDimitry Andric 4781ad6265SDimitry Andric // Basic Block Sections can be enabled for a subset of machine basic blocks. 4881ad6265SDimitry Andric // This is done by passing a file containing names of functions for which basic 4981ad6265SDimitry Andric // block sections are desired. Additionally, machine basic block ids of the 5081ad6265SDimitry Andric // functions can also be specified for a finer granularity. Moreover, a cluster 5181ad6265SDimitry Andric // of basic blocks could be assigned to the same section. 5281ad6265SDimitry Andric // A file with basic block sections for all of function main and three blocks 5381ad6265SDimitry Andric // for function foo (of which 1 and 2 are placed in a cluster) looks like this: 5481ad6265SDimitry Andric // ---------------------------- 5581ad6265SDimitry Andric // list.txt: 5681ad6265SDimitry Andric // !main 5781ad6265SDimitry Andric // !foo 5881ad6265SDimitry Andric // !!1 2 5981ad6265SDimitry Andric // !!4 6081ad6265SDimitry Andric static Error getBBClusterInfo(const MemoryBuffer *MBuf, 6181ad6265SDimitry Andric ProgramBBClusterInfoMapTy &ProgramBBClusterInfo, 6281ad6265SDimitry Andric StringMap<StringRef> &FuncAliasMap) { 6381ad6265SDimitry Andric assert(MBuf); 6481ad6265SDimitry Andric line_iterator LineIt(*MBuf, /*SkipBlanks=*/true, /*CommentMarker=*/'#'); 6581ad6265SDimitry Andric 6681ad6265SDimitry Andric auto invalidProfileError = [&](auto Message) { 6781ad6265SDimitry Andric return make_error<StringError>( 6881ad6265SDimitry Andric Twine("Invalid profile " + MBuf->getBufferIdentifier() + " at line " + 6981ad6265SDimitry Andric Twine(LineIt.line_number()) + ": " + Message), 7081ad6265SDimitry Andric inconvertibleErrorCode()); 7181ad6265SDimitry Andric }; 7281ad6265SDimitry Andric 7381ad6265SDimitry Andric auto FI = ProgramBBClusterInfo.end(); 7481ad6265SDimitry Andric 7581ad6265SDimitry Andric // Current cluster ID corresponding to this function. 7681ad6265SDimitry Andric unsigned CurrentCluster = 0; 7781ad6265SDimitry Andric // Current position in the current cluster. 7881ad6265SDimitry Andric unsigned CurrentPosition = 0; 7981ad6265SDimitry Andric 8081ad6265SDimitry Andric // Temporary set to ensure every basic block ID appears once in the clusters 8181ad6265SDimitry Andric // of a function. 8281ad6265SDimitry Andric SmallSet<unsigned, 4> FuncBBIDs; 8381ad6265SDimitry Andric 8481ad6265SDimitry Andric for (; !LineIt.is_at_eof(); ++LineIt) { 8581ad6265SDimitry Andric StringRef S(*LineIt); 8681ad6265SDimitry Andric if (S[0] == '@') 8781ad6265SDimitry Andric continue; 8881ad6265SDimitry Andric // Check for the leading "!" 8981ad6265SDimitry Andric if (!S.consume_front("!") || S.empty()) 9081ad6265SDimitry Andric break; 9181ad6265SDimitry Andric // Check for second "!" which indicates a cluster of basic blocks. 9281ad6265SDimitry Andric if (S.consume_front("!")) { 9381ad6265SDimitry Andric if (FI == ProgramBBClusterInfo.end()) 9481ad6265SDimitry Andric return invalidProfileError( 9581ad6265SDimitry Andric "Cluster list does not follow a function name specifier."); 96bdd1243dSDimitry Andric SmallVector<StringRef, 4> BBIDs; 97bdd1243dSDimitry Andric S.split(BBIDs, ' '); 9881ad6265SDimitry Andric // Reset current cluster position. 9981ad6265SDimitry Andric CurrentPosition = 0; 100bdd1243dSDimitry Andric for (auto BBIDStr : BBIDs) { 101bdd1243dSDimitry Andric unsigned long long BBID; 102bdd1243dSDimitry Andric if (getAsUnsignedInteger(BBIDStr, 10, BBID)) 10381ad6265SDimitry Andric return invalidProfileError(Twine("Unsigned integer expected: '") + 104bdd1243dSDimitry Andric BBIDStr + "'."); 105bdd1243dSDimitry Andric if (!FuncBBIDs.insert(BBID).second) 10681ad6265SDimitry Andric return invalidProfileError(Twine("Duplicate basic block id found '") + 107bdd1243dSDimitry Andric BBIDStr + "'."); 108bdd1243dSDimitry Andric if (BBID == 0 && CurrentPosition) 10981ad6265SDimitry Andric return invalidProfileError("Entry BB (0) does not begin a cluster."); 11081ad6265SDimitry Andric 111bdd1243dSDimitry Andric FI->second.emplace_back( 112bdd1243dSDimitry Andric BBClusterInfo{((unsigned)BBID), CurrentCluster, CurrentPosition++}); 11381ad6265SDimitry Andric } 11481ad6265SDimitry Andric CurrentCluster++; 11581ad6265SDimitry Andric } else { // This is a function name specifier. 11681ad6265SDimitry Andric // Function aliases are separated using '/'. We use the first function 11781ad6265SDimitry Andric // name for the cluster info mapping and delegate all other aliases to 11881ad6265SDimitry Andric // this one. 11981ad6265SDimitry Andric SmallVector<StringRef, 4> Aliases; 12081ad6265SDimitry Andric S.split(Aliases, '/'); 12181ad6265SDimitry Andric for (size_t i = 1; i < Aliases.size(); ++i) 12281ad6265SDimitry Andric FuncAliasMap.try_emplace(Aliases[i], Aliases.front()); 12381ad6265SDimitry Andric 12481ad6265SDimitry Andric // Prepare for parsing clusters of this function name. 12581ad6265SDimitry Andric // Start a new cluster map for this function name. 12681ad6265SDimitry Andric FI = ProgramBBClusterInfo.try_emplace(Aliases.front()).first; 12781ad6265SDimitry Andric CurrentCluster = 0; 12881ad6265SDimitry Andric FuncBBIDs.clear(); 12981ad6265SDimitry Andric } 13081ad6265SDimitry Andric } 13181ad6265SDimitry Andric return Error::success(); 13281ad6265SDimitry Andric } 13381ad6265SDimitry Andric 13481ad6265SDimitry Andric void BasicBlockSectionsProfileReader::initializePass() { 13581ad6265SDimitry Andric if (!MBuf) 13681ad6265SDimitry Andric return; 13781ad6265SDimitry Andric if (auto Err = getBBClusterInfo(MBuf, ProgramBBClusterInfo, FuncAliasMap)) 13881ad6265SDimitry Andric report_fatal_error(std::move(Err)); 13981ad6265SDimitry Andric } 14081ad6265SDimitry Andric 14181ad6265SDimitry Andric ImmutablePass * 14281ad6265SDimitry Andric llvm::createBasicBlockSectionsProfileReaderPass(const MemoryBuffer *Buf) { 14381ad6265SDimitry Andric return new BasicBlockSectionsProfileReader(Buf); 14481ad6265SDimitry Andric } 145