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