xref: /llvm-project/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp (revision ef8dedc79ce02710ffba6a3005e05672702f555f)
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   auto R = ProgramBBClusterInfo.find(getAliasName(FuncName));
39   return R != ProgramBBClusterInfo.end()
40              ? std::pair(true, R->second)
41              : std::pair(false, SmallVector<BBClusterInfo>{});
42 }
43 
44 // Basic Block Sections can be enabled for a subset of machine basic blocks.
45 // This is done by passing a file containing names of functions for which basic
46 // block sections are desired.  Additionally, machine basic block ids of the
47 // functions can also be specified for a finer granularity. Moreover, a cluster
48 // of basic blocks could be assigned to the same section.
49 // A file with basic block sections for all of function main and three blocks
50 // for function foo (of which 1 and 2 are placed in a cluster) looks like this:
51 // ----------------------------
52 // list.txt:
53 // !main
54 // !foo
55 // !!1 2
56 // !!4
57 static Error getBBClusterInfo(const MemoryBuffer *MBuf,
58                               ProgramBBClusterInfoMapTy &ProgramBBClusterInfo,
59                               StringMap<StringRef> &FuncAliasMap) {
60   assert(MBuf);
61   line_iterator LineIt(*MBuf, /*SkipBlanks=*/true, /*CommentMarker=*/'#');
62 
63   auto invalidProfileError = [&](auto Message) {
64     return make_error<StringError>(
65         Twine("Invalid profile " + MBuf->getBufferIdentifier() + " at line " +
66               Twine(LineIt.line_number()) + ": " + Message),
67         inconvertibleErrorCode());
68   };
69 
70   auto FI = ProgramBBClusterInfo.end();
71 
72   // Current cluster ID corresponding to this function.
73   unsigned CurrentCluster = 0;
74   // Current position in the current cluster.
75   unsigned CurrentPosition = 0;
76 
77   // Temporary set to ensure every basic block ID appears once in the clusters
78   // of a function.
79   SmallSet<unsigned, 4> FuncBBIDs;
80 
81   for (; !LineIt.is_at_eof(); ++LineIt) {
82     StringRef S(*LineIt);
83     if (S[0] == '@')
84       continue;
85     // Check for the leading "!"
86     if (!S.consume_front("!") || S.empty())
87       break;
88     // Check for second "!" which indicates a cluster of basic blocks.
89     if (S.consume_front("!")) {
90       if (FI == ProgramBBClusterInfo.end())
91         return invalidProfileError(
92             "Cluster list does not follow a function name specifier.");
93       SmallVector<StringRef, 4> BBIDs;
94       S.split(BBIDs, ' ');
95       // Reset current cluster position.
96       CurrentPosition = 0;
97       for (auto BBIDStr : BBIDs) {
98         unsigned long long BBID;
99         if (getAsUnsignedInteger(BBIDStr, 10, BBID))
100           return invalidProfileError(Twine("Unsigned integer expected: '") +
101                                      BBIDStr + "'.");
102         if (!FuncBBIDs.insert(BBID).second)
103           return invalidProfileError(Twine("Duplicate basic block id found '") +
104                                      BBIDStr + "'.");
105         if (BBID == 0 && CurrentPosition)
106           return invalidProfileError("Entry BB (0) does not begin a cluster.");
107 
108         FI->second.emplace_back(
109             BBClusterInfo{((unsigned)BBID), CurrentCluster, CurrentPosition++});
110       }
111       CurrentCluster++;
112     } else { // This is a function name specifier.
113       // Function aliases are separated using '/'. We use the first function
114       // name for the cluster info mapping and delegate all other aliases to
115       // this one.
116       SmallVector<StringRef, 4> Aliases;
117       S.split(Aliases, '/');
118       for (size_t i = 1; i < Aliases.size(); ++i)
119         FuncAliasMap.try_emplace(Aliases[i], Aliases.front());
120 
121       // Prepare for parsing clusters of this function name.
122       // Start a new cluster map for this function name.
123       FI = ProgramBBClusterInfo.try_emplace(Aliases.front()).first;
124       CurrentCluster = 0;
125       FuncBBIDs.clear();
126     }
127   }
128   return Error::success();
129 }
130 
131 void BasicBlockSectionsProfileReader::initializePass() {
132   if (!MBuf)
133     return;
134   if (auto Err = getBBClusterInfo(MBuf, ProgramBBClusterInfo, FuncAliasMap))
135     report_fatal_error(std::move(Err));
136 }
137 
138 ImmutablePass *
139 llvm::createBasicBlockSectionsProfileReaderPass(const MemoryBuffer *Buf) {
140   return new BasicBlockSectionsProfileReader(Buf);
141 }
142