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