xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
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