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