xref: /freebsd/contrib/llvm-project/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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"
16*5f757f3fSDimitry Andric #include "llvm/ADT/DenseSet.h"
1781ad6265SDimitry Andric #include "llvm/ADT/SmallSet.h"
1806c3fb27SDimitry Andric #include "llvm/ADT/SmallString.h"
1981ad6265SDimitry Andric #include "llvm/ADT/SmallVector.h"
2081ad6265SDimitry Andric #include "llvm/ADT/StringMap.h"
2181ad6265SDimitry Andric #include "llvm/ADT/StringRef.h"
2206c3fb27SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h"
23*5f757f3fSDimitry Andric #include "llvm/Pass.h"
2481ad6265SDimitry Andric #include "llvm/Support/Error.h"
25*5f757f3fSDimitry Andric #include "llvm/Support/ErrorHandling.h"
2681ad6265SDimitry Andric #include "llvm/Support/LineIterator.h"
2781ad6265SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
2806c3fb27SDimitry Andric #include "llvm/Support/Path.h"
2906c3fb27SDimitry Andric #include <llvm/ADT/STLExtras.h>
3081ad6265SDimitry Andric 
3181ad6265SDimitry Andric using namespace llvm;
3281ad6265SDimitry Andric 
3381ad6265SDimitry Andric char BasicBlockSectionsProfileReader::ID = 0;
3481ad6265SDimitry Andric INITIALIZE_PASS(BasicBlockSectionsProfileReader, "bbsections-profile-reader",
3581ad6265SDimitry Andric                 "Reads and parses a basic block sections profile.", false,
3681ad6265SDimitry Andric                 false)
3781ad6265SDimitry Andric 
38*5f757f3fSDimitry Andric Expected<UniqueBBID>
39*5f757f3fSDimitry Andric BasicBlockSectionsProfileReader::parseUniqueBBID(StringRef S) const {
40*5f757f3fSDimitry Andric   SmallVector<StringRef, 2> Parts;
41*5f757f3fSDimitry Andric   S.split(Parts, '.');
42*5f757f3fSDimitry Andric   if (Parts.size() > 2)
43*5f757f3fSDimitry Andric     return createProfileParseError(Twine("unable to parse basic block id: '") +
44*5f757f3fSDimitry Andric                                    S + "'");
45*5f757f3fSDimitry Andric   unsigned long long BaseBBID;
46*5f757f3fSDimitry Andric   if (getAsUnsignedInteger(Parts[0], 10, BaseBBID))
47*5f757f3fSDimitry Andric     return createProfileParseError(
48*5f757f3fSDimitry Andric         Twine("unable to parse BB id: '" + Parts[0]) +
49*5f757f3fSDimitry Andric         "': unsigned integer expected");
50*5f757f3fSDimitry Andric   unsigned long long CloneID = 0;
51*5f757f3fSDimitry Andric   if (Parts.size() > 1 && getAsUnsignedInteger(Parts[1], 10, CloneID))
52*5f757f3fSDimitry Andric     return createProfileParseError(Twine("unable to parse clone id: '") +
53*5f757f3fSDimitry Andric                                    Parts[1] + "': unsigned integer expected");
54*5f757f3fSDimitry Andric   return UniqueBBID{static_cast<unsigned>(BaseBBID),
55*5f757f3fSDimitry Andric                     static_cast<unsigned>(CloneID)};
56*5f757f3fSDimitry Andric }
57*5f757f3fSDimitry Andric 
5881ad6265SDimitry Andric bool BasicBlockSectionsProfileReader::isFunctionHot(StringRef FuncName) const {
59*5f757f3fSDimitry Andric   return getClusterInfoForFunction(FuncName).first;
6081ad6265SDimitry Andric }
6181ad6265SDimitry Andric 
6281ad6265SDimitry Andric std::pair<bool, SmallVector<BBClusterInfo>>
63*5f757f3fSDimitry Andric BasicBlockSectionsProfileReader::getClusterInfoForFunction(
6481ad6265SDimitry Andric     StringRef FuncName) const {
65*5f757f3fSDimitry Andric   auto R = ProgramPathAndClusterInfo.find(getAliasName(FuncName));
66*5f757f3fSDimitry Andric   return R != ProgramPathAndClusterInfo.end()
67*5f757f3fSDimitry Andric              ? std::pair(true, R->second.ClusterInfo)
68*5f757f3fSDimitry Andric              : std::pair(false, SmallVector<BBClusterInfo>());
69*5f757f3fSDimitry Andric }
70*5f757f3fSDimitry Andric 
71*5f757f3fSDimitry Andric SmallVector<SmallVector<unsigned>>
72*5f757f3fSDimitry Andric BasicBlockSectionsProfileReader::getClonePathsForFunction(
73*5f757f3fSDimitry Andric     StringRef FuncName) const {
74*5f757f3fSDimitry Andric   return ProgramPathAndClusterInfo.lookup(getAliasName(FuncName)).ClonePaths;
75*5f757f3fSDimitry Andric }
76*5f757f3fSDimitry Andric 
77*5f757f3fSDimitry Andric // Reads the version 1 basic block sections profile. Profile for each function
78*5f757f3fSDimitry Andric // is encoded as follows:
79*5f757f3fSDimitry Andric //   m <module_name>
80*5f757f3fSDimitry Andric //   f <function_name_1> <function_name_2> ...
81*5f757f3fSDimitry Andric //   c <bb_id_1> <bb_id_2> <bb_id_3>
82*5f757f3fSDimitry Andric //   c <bb_id_4> <bb_id_5>
83*5f757f3fSDimitry Andric //   ...
84*5f757f3fSDimitry Andric // Module name specifier (starting with 'm') is optional and allows
85*5f757f3fSDimitry Andric // distinguishing profile for internal-linkage functions with the same name. If
86*5f757f3fSDimitry Andric // not specified, it will apply to any function with the same name. Function
87*5f757f3fSDimitry Andric // name specifier (starting with 'f') can specify multiple function name
88*5f757f3fSDimitry Andric // aliases. Basic block clusters are specified by 'c' and specify the cluster of
89*5f757f3fSDimitry Andric // basic blocks, and the internal order in which they must be placed in the same
90*5f757f3fSDimitry Andric // section.
91*5f757f3fSDimitry Andric // This profile can also specify cloning paths which instruct the compiler to
92*5f757f3fSDimitry Andric // clone basic blocks along a path. The cloned blocks are then specified in the
93*5f757f3fSDimitry Andric // cluster information.
94*5f757f3fSDimitry Andric // The following profile lists two cloning paths (starting with 'p') for
95*5f757f3fSDimitry Andric // function bar and places the total 9 blocks within two clusters. The first two
96*5f757f3fSDimitry Andric // blocks of a cloning path specify the edge along which the path is cloned. For
97*5f757f3fSDimitry Andric // instance, path 1 (1 -> 3 -> 4) instructs that 3 and 4 must be cloned along
98*5f757f3fSDimitry Andric // the edge 1->3. Within the given clusters, each cloned block is identified by
99*5f757f3fSDimitry Andric // "<original block id>.<clone id>". For instance, 3.1 represents the first
100*5f757f3fSDimitry Andric // clone of block 3. Original blocks are specified just with their block ids. A
101*5f757f3fSDimitry Andric // block cloned multiple times appears with distinct clone ids. The CFG for bar
102*5f757f3fSDimitry Andric // is shown below before and after cloning with its final clusters labeled.
103*5f757f3fSDimitry Andric //
104*5f757f3fSDimitry Andric // f main
105*5f757f3fSDimitry Andric // f bar
106*5f757f3fSDimitry Andric // p 1 3 4           # cloning path 1
107*5f757f3fSDimitry Andric // p 4 2             # cloning path 2
108*5f757f3fSDimitry Andric // c 1 3.1 4.1 6     # basic block cluster 1
109*5f757f3fSDimitry Andric // c 0 2 3 4 2.1 5   # basic block cluster 2
110*5f757f3fSDimitry Andric // ****************************************************************************
111*5f757f3fSDimitry Andric // function bar before and after cloning with basic block clusters shown.
112*5f757f3fSDimitry Andric // ****************************************************************************
113*5f757f3fSDimitry Andric //                                ....      ..............
114*5f757f3fSDimitry Andric //      0 -------+                : 0 :---->: 1 ---> 3.1 :
115*5f757f3fSDimitry Andric //      |        |                : | :     :........ |  :
116*5f757f3fSDimitry Andric //      v        v                : v :             : v  :
117*5f757f3fSDimitry Andric // +--> 2 --> 5  1   ~~~~~~>  +---: 2 :             : 4.1: clsuter 1
118*5f757f3fSDimitry Andric // |    |        |            |   : | :             : |  :
119*5f757f3fSDimitry Andric // |    v        |            |   : v .......       : v  :
120*5f757f3fSDimitry Andric // |    3 <------+            |   : 3 <--+  :       : 6  :
121*5f757f3fSDimitry Andric // |    |                     |   : |    |  :       :....:
122*5f757f3fSDimitry Andric // |    v                     |   : v    |  :
123*5f757f3fSDimitry Andric // +--- 4 ---> 6              |   : 4    |  :
124*5f757f3fSDimitry Andric //                            |   : |    |  :
125*5f757f3fSDimitry Andric //                            |   : v    |  :
126*5f757f3fSDimitry Andric //                            |   :2.1---+  : cluster 2
127*5f757f3fSDimitry Andric //                            |   : | ......:
128*5f757f3fSDimitry Andric //                            |   : v :
129*5f757f3fSDimitry Andric //                            +-->: 5 :
130*5f757f3fSDimitry Andric //                                ....
131*5f757f3fSDimitry Andric // ****************************************************************************
132*5f757f3fSDimitry Andric Error BasicBlockSectionsProfileReader::ReadV1Profile() {
133*5f757f3fSDimitry Andric   auto FI = ProgramPathAndClusterInfo.end();
134*5f757f3fSDimitry Andric 
135*5f757f3fSDimitry Andric   // Current cluster ID corresponding to this function.
136*5f757f3fSDimitry Andric   unsigned CurrentCluster = 0;
137*5f757f3fSDimitry Andric   // Current position in the current cluster.
138*5f757f3fSDimitry Andric   unsigned CurrentPosition = 0;
139*5f757f3fSDimitry Andric 
140*5f757f3fSDimitry Andric   // Temporary set to ensure every basic block ID appears once in the clusters
141*5f757f3fSDimitry Andric   // of a function.
142*5f757f3fSDimitry Andric   DenseSet<UniqueBBID> FuncBBIDs;
143*5f757f3fSDimitry Andric 
144*5f757f3fSDimitry Andric   // Debug-info-based module filename for the current function. Empty string
145*5f757f3fSDimitry Andric   // means no filename.
146*5f757f3fSDimitry Andric   StringRef DIFilename;
147*5f757f3fSDimitry Andric 
148*5f757f3fSDimitry Andric   for (; !LineIt.is_at_eof(); ++LineIt) {
149*5f757f3fSDimitry Andric     StringRef S(*LineIt);
150*5f757f3fSDimitry Andric     char Specifier = S[0];
151*5f757f3fSDimitry Andric     S = S.drop_front().trim();
152*5f757f3fSDimitry Andric     SmallVector<StringRef, 4> Values;
153*5f757f3fSDimitry Andric     S.split(Values, ' ');
154*5f757f3fSDimitry Andric     switch (Specifier) {
155*5f757f3fSDimitry Andric     case '@':
156*5f757f3fSDimitry Andric       continue;
157*5f757f3fSDimitry Andric     case 'm': // Module name speicifer.
158*5f757f3fSDimitry Andric       if (Values.size() != 1) {
159*5f757f3fSDimitry Andric         return createProfileParseError(Twine("invalid module name value: '") +
160*5f757f3fSDimitry Andric                                        S + "'");
161*5f757f3fSDimitry Andric       }
162*5f757f3fSDimitry Andric       DIFilename = sys::path::remove_leading_dotslash(Values[0]);
163*5f757f3fSDimitry Andric       continue;
164*5f757f3fSDimitry Andric     case 'f': { // Function names specifier.
165*5f757f3fSDimitry Andric       bool FunctionFound = any_of(Values, [&](StringRef Alias) {
166*5f757f3fSDimitry Andric         auto It = FunctionNameToDIFilename.find(Alias);
167*5f757f3fSDimitry Andric         // No match if this function name is not found in this module.
168*5f757f3fSDimitry Andric         if (It == FunctionNameToDIFilename.end())
169*5f757f3fSDimitry Andric           return false;
170*5f757f3fSDimitry Andric         // Return a match if debug-info-filename is not specified. Otherwise,
171*5f757f3fSDimitry Andric         // check for equality.
172*5f757f3fSDimitry Andric         return DIFilename.empty() || It->second.equals(DIFilename);
173*5f757f3fSDimitry Andric       });
174*5f757f3fSDimitry Andric       if (!FunctionFound) {
175*5f757f3fSDimitry Andric         // Skip the following profile by setting the profile iterator (FI) to
176*5f757f3fSDimitry Andric         // the past-the-end element.
177*5f757f3fSDimitry Andric         FI = ProgramPathAndClusterInfo.end();
178*5f757f3fSDimitry Andric         DIFilename = "";
179*5f757f3fSDimitry Andric         continue;
180*5f757f3fSDimitry Andric       }
181*5f757f3fSDimitry Andric       for (size_t i = 1; i < Values.size(); ++i)
182*5f757f3fSDimitry Andric         FuncAliasMap.try_emplace(Values[i], Values.front());
183*5f757f3fSDimitry Andric 
184*5f757f3fSDimitry Andric       // Prepare for parsing clusters of this function name.
185*5f757f3fSDimitry Andric       // Start a new cluster map for this function name.
186*5f757f3fSDimitry Andric       auto R = ProgramPathAndClusterInfo.try_emplace(Values.front());
187*5f757f3fSDimitry Andric       // Report error when multiple profiles have been specified for the same
188*5f757f3fSDimitry Andric       // function.
189*5f757f3fSDimitry Andric       if (!R.second)
190*5f757f3fSDimitry Andric         return createProfileParseError("duplicate profile for function '" +
191*5f757f3fSDimitry Andric                                        Values.front() + "'");
192*5f757f3fSDimitry Andric       FI = R.first;
193*5f757f3fSDimitry Andric       CurrentCluster = 0;
194*5f757f3fSDimitry Andric       FuncBBIDs.clear();
195*5f757f3fSDimitry Andric       // We won't need DIFilename anymore. Clean it up to avoid its application
196*5f757f3fSDimitry Andric       // on the next function.
197*5f757f3fSDimitry Andric       DIFilename = "";
198*5f757f3fSDimitry Andric       continue;
199*5f757f3fSDimitry Andric     }
200*5f757f3fSDimitry Andric     case 'c': // Basic block cluster specifier.
201*5f757f3fSDimitry Andric       // Skip the profile when we the profile iterator (FI) refers to the
202*5f757f3fSDimitry Andric       // past-the-end element.
203*5f757f3fSDimitry Andric       if (FI == ProgramPathAndClusterInfo.end())
204*5f757f3fSDimitry Andric         continue;
205*5f757f3fSDimitry Andric       // Reset current cluster position.
206*5f757f3fSDimitry Andric       CurrentPosition = 0;
207*5f757f3fSDimitry Andric       for (auto BasicBlockIDStr : Values) {
208*5f757f3fSDimitry Andric         auto BasicBlockID = parseUniqueBBID(BasicBlockIDStr);
209*5f757f3fSDimitry Andric         if (!BasicBlockID)
210*5f757f3fSDimitry Andric           return BasicBlockID.takeError();
211*5f757f3fSDimitry Andric         if (!FuncBBIDs.insert(*BasicBlockID).second)
212*5f757f3fSDimitry Andric           return createProfileParseError(
213*5f757f3fSDimitry Andric               Twine("duplicate basic block id found '") + BasicBlockIDStr +
214*5f757f3fSDimitry Andric               "'");
215*5f757f3fSDimitry Andric 
216*5f757f3fSDimitry Andric         if (!BasicBlockID->BaseID && CurrentPosition)
217*5f757f3fSDimitry Andric           return createProfileParseError(
218*5f757f3fSDimitry Andric               "entry BB (0) does not begin a cluster.");
219*5f757f3fSDimitry Andric 
220*5f757f3fSDimitry Andric         FI->second.ClusterInfo.emplace_back(BBClusterInfo{
221*5f757f3fSDimitry Andric             *std::move(BasicBlockID), CurrentCluster, CurrentPosition++});
222*5f757f3fSDimitry Andric       }
223*5f757f3fSDimitry Andric       CurrentCluster++;
224*5f757f3fSDimitry Andric       continue;
225*5f757f3fSDimitry Andric     case 'p': { // Basic block cloning path specifier.
226*5f757f3fSDimitry Andric       // Skip the profile when we the profile iterator (FI) refers to the
227*5f757f3fSDimitry Andric       // past-the-end element.
228*5f757f3fSDimitry Andric       if (FI == ProgramPathAndClusterInfo.end())
229*5f757f3fSDimitry Andric         continue;
230*5f757f3fSDimitry Andric       SmallSet<unsigned, 5> BBsInPath;
231*5f757f3fSDimitry Andric       FI->second.ClonePaths.push_back({});
232*5f757f3fSDimitry Andric       for (size_t I = 0; I < Values.size(); ++I) {
233*5f757f3fSDimitry Andric         auto BaseBBIDStr = Values[I];
234*5f757f3fSDimitry Andric         unsigned long long BaseBBID = 0;
235*5f757f3fSDimitry Andric         if (getAsUnsignedInteger(BaseBBIDStr, 10, BaseBBID))
236*5f757f3fSDimitry Andric           return createProfileParseError(Twine("unsigned integer expected: '") +
237*5f757f3fSDimitry Andric                                          BaseBBIDStr + "'");
238*5f757f3fSDimitry Andric         if (I != 0 && !BBsInPath.insert(BaseBBID).second)
239*5f757f3fSDimitry Andric           return createProfileParseError(
240*5f757f3fSDimitry Andric               Twine("duplicate cloned block in path: '") + BaseBBIDStr + "'");
241*5f757f3fSDimitry Andric         FI->second.ClonePaths.back().push_back(BaseBBID);
242*5f757f3fSDimitry Andric       }
243*5f757f3fSDimitry Andric       continue;
244*5f757f3fSDimitry Andric     }
245*5f757f3fSDimitry Andric     default:
246*5f757f3fSDimitry Andric       return createProfileParseError(Twine("invalid specifier: '") +
247*5f757f3fSDimitry Andric                                      Twine(Specifier) + "'");
248*5f757f3fSDimitry Andric     }
249*5f757f3fSDimitry Andric     llvm_unreachable("should not break from this switch statement");
250*5f757f3fSDimitry Andric   }
251*5f757f3fSDimitry Andric   return Error::success();
252*5f757f3fSDimitry Andric }
253*5f757f3fSDimitry Andric 
254*5f757f3fSDimitry Andric Error BasicBlockSectionsProfileReader::ReadV0Profile() {
255*5f757f3fSDimitry Andric   auto FI = ProgramPathAndClusterInfo.end();
256*5f757f3fSDimitry Andric   // Current cluster ID corresponding to this function.
257*5f757f3fSDimitry Andric   unsigned CurrentCluster = 0;
258*5f757f3fSDimitry Andric   // Current position in the current cluster.
259*5f757f3fSDimitry Andric   unsigned CurrentPosition = 0;
260*5f757f3fSDimitry Andric 
261*5f757f3fSDimitry Andric   // Temporary set to ensure every basic block ID appears once in the clusters
262*5f757f3fSDimitry Andric   // of a function.
263*5f757f3fSDimitry Andric   SmallSet<unsigned, 4> FuncBBIDs;
264*5f757f3fSDimitry Andric 
265*5f757f3fSDimitry Andric   for (; !LineIt.is_at_eof(); ++LineIt) {
266*5f757f3fSDimitry Andric     StringRef S(*LineIt);
267*5f757f3fSDimitry Andric     if (S[0] == '@')
268*5f757f3fSDimitry Andric       continue;
269*5f757f3fSDimitry Andric     // Check for the leading "!"
270*5f757f3fSDimitry Andric     if (!S.consume_front("!") || S.empty())
271*5f757f3fSDimitry Andric       break;
272*5f757f3fSDimitry Andric     // Check for second "!" which indicates a cluster of basic blocks.
273*5f757f3fSDimitry Andric     if (S.consume_front("!")) {
274*5f757f3fSDimitry Andric       // Skip the profile when we the profile iterator (FI) refers to the
275*5f757f3fSDimitry Andric       // past-the-end element.
276*5f757f3fSDimitry Andric       if (FI == ProgramPathAndClusterInfo.end())
277*5f757f3fSDimitry Andric         continue;
278*5f757f3fSDimitry Andric       SmallVector<StringRef, 4> BBIDs;
279*5f757f3fSDimitry Andric       S.split(BBIDs, ' ');
280*5f757f3fSDimitry Andric       // Reset current cluster position.
281*5f757f3fSDimitry Andric       CurrentPosition = 0;
282*5f757f3fSDimitry Andric       for (auto BBIDStr : BBIDs) {
283*5f757f3fSDimitry Andric         unsigned long long BBID;
284*5f757f3fSDimitry Andric         if (getAsUnsignedInteger(BBIDStr, 10, BBID))
285*5f757f3fSDimitry Andric           return createProfileParseError(Twine("unsigned integer expected: '") +
286*5f757f3fSDimitry Andric                                          BBIDStr + "'");
287*5f757f3fSDimitry Andric         if (!FuncBBIDs.insert(BBID).second)
288*5f757f3fSDimitry Andric           return createProfileParseError(
289*5f757f3fSDimitry Andric               Twine("duplicate basic block id found '") + BBIDStr + "'");
290*5f757f3fSDimitry Andric         if (BBID == 0 && CurrentPosition)
291*5f757f3fSDimitry Andric           return createProfileParseError(
292*5f757f3fSDimitry Andric               "entry BB (0) does not begin a cluster");
293*5f757f3fSDimitry Andric 
294*5f757f3fSDimitry Andric         FI->second.ClusterInfo.emplace_back(
295*5f757f3fSDimitry Andric             BBClusterInfo({{static_cast<unsigned>(BBID), 0},
296*5f757f3fSDimitry Andric                            CurrentCluster,
297*5f757f3fSDimitry Andric                            CurrentPosition++}));
298*5f757f3fSDimitry Andric       }
299*5f757f3fSDimitry Andric       CurrentCluster++;
300*5f757f3fSDimitry Andric     } else {
301*5f757f3fSDimitry Andric       // This is a function name specifier. It may include a debug info filename
302*5f757f3fSDimitry Andric       // specifier starting with `M=`.
303*5f757f3fSDimitry Andric       auto [AliasesStr, DIFilenameStr] = S.split(' ');
304*5f757f3fSDimitry Andric       SmallString<128> DIFilename;
305*5f757f3fSDimitry Andric       if (DIFilenameStr.starts_with("M=")) {
306*5f757f3fSDimitry Andric         DIFilename =
307*5f757f3fSDimitry Andric             sys::path::remove_leading_dotslash(DIFilenameStr.substr(2));
308*5f757f3fSDimitry Andric         if (DIFilename.empty())
309*5f757f3fSDimitry Andric           return createProfileParseError("empty module name specifier");
310*5f757f3fSDimitry Andric       } else if (!DIFilenameStr.empty()) {
311*5f757f3fSDimitry Andric         return createProfileParseError("unknown string found: '" +
312*5f757f3fSDimitry Andric                                        DIFilenameStr + "'");
313*5f757f3fSDimitry Andric       }
314*5f757f3fSDimitry Andric       // Function aliases are separated using '/'. We use the first function
315*5f757f3fSDimitry Andric       // name for the cluster info mapping and delegate all other aliases to
316*5f757f3fSDimitry Andric       // this one.
317*5f757f3fSDimitry Andric       SmallVector<StringRef, 4> Aliases;
318*5f757f3fSDimitry Andric       AliasesStr.split(Aliases, '/');
319*5f757f3fSDimitry Andric       bool FunctionFound = any_of(Aliases, [&](StringRef Alias) {
320*5f757f3fSDimitry Andric         auto It = FunctionNameToDIFilename.find(Alias);
321*5f757f3fSDimitry Andric         // No match if this function name is not found in this module.
322*5f757f3fSDimitry Andric         if (It == FunctionNameToDIFilename.end())
323*5f757f3fSDimitry Andric           return false;
324*5f757f3fSDimitry Andric         // Return a match if debug-info-filename is not specified. Otherwise,
325*5f757f3fSDimitry Andric         // check for equality.
326*5f757f3fSDimitry Andric         return DIFilename.empty() || It->second.equals(DIFilename);
327*5f757f3fSDimitry Andric       });
328*5f757f3fSDimitry Andric       if (!FunctionFound) {
329*5f757f3fSDimitry Andric         // Skip the following profile by setting the profile iterator (FI) to
330*5f757f3fSDimitry Andric         // the past-the-end element.
331*5f757f3fSDimitry Andric         FI = ProgramPathAndClusterInfo.end();
332*5f757f3fSDimitry Andric         continue;
333*5f757f3fSDimitry Andric       }
334*5f757f3fSDimitry Andric       for (size_t i = 1; i < Aliases.size(); ++i)
335*5f757f3fSDimitry Andric         FuncAliasMap.try_emplace(Aliases[i], Aliases.front());
336*5f757f3fSDimitry Andric 
337*5f757f3fSDimitry Andric       // Prepare for parsing clusters of this function name.
338*5f757f3fSDimitry Andric       // Start a new cluster map for this function name.
339*5f757f3fSDimitry Andric       auto R = ProgramPathAndClusterInfo.try_emplace(Aliases.front());
340*5f757f3fSDimitry Andric       // Report error when multiple profiles have been specified for the same
341*5f757f3fSDimitry Andric       // function.
342*5f757f3fSDimitry Andric       if (!R.second)
343*5f757f3fSDimitry Andric         return createProfileParseError("duplicate profile for function '" +
344*5f757f3fSDimitry Andric                                        Aliases.front() + "'");
345*5f757f3fSDimitry Andric       FI = R.first;
346*5f757f3fSDimitry Andric       CurrentCluster = 0;
347*5f757f3fSDimitry Andric       FuncBBIDs.clear();
348*5f757f3fSDimitry Andric     }
349*5f757f3fSDimitry Andric   }
350*5f757f3fSDimitry Andric   return Error::success();
35181ad6265SDimitry Andric }
35281ad6265SDimitry Andric 
35381ad6265SDimitry Andric // Basic Block Sections can be enabled for a subset of machine basic blocks.
35481ad6265SDimitry Andric // This is done by passing a file containing names of functions for which basic
35581ad6265SDimitry Andric // block sections are desired. Additionally, machine basic block ids of the
35681ad6265SDimitry Andric // functions can also be specified for a finer granularity. Moreover, a cluster
35781ad6265SDimitry Andric // of basic blocks could be assigned to the same section.
35806c3fb27SDimitry Andric // Optionally, a debug-info filename can be specified for each function to allow
35906c3fb27SDimitry Andric // distinguishing internal-linkage functions of the same name.
36081ad6265SDimitry Andric // A file with basic block sections for all of function main and three blocks
36181ad6265SDimitry Andric // for function foo (of which 1 and 2 are placed in a cluster) looks like this:
36206c3fb27SDimitry Andric // (Profile for function foo is only loaded when its debug-info filename
36306c3fb27SDimitry Andric // matches 'path/to/foo_file.cc').
36481ad6265SDimitry Andric // ----------------------------
36581ad6265SDimitry Andric // list.txt:
36681ad6265SDimitry Andric // !main
36706c3fb27SDimitry Andric // !foo M=path/to/foo_file.cc
36881ad6265SDimitry Andric // !!1 2
36981ad6265SDimitry Andric // !!4
37006c3fb27SDimitry Andric Error BasicBlockSectionsProfileReader::ReadProfile() {
37181ad6265SDimitry Andric   assert(MBuf);
37281ad6265SDimitry Andric 
373*5f757f3fSDimitry Andric   unsigned long long Version = 0;
374*5f757f3fSDimitry Andric   StringRef FirstLine(*LineIt);
375*5f757f3fSDimitry Andric   if (FirstLine.consume_front("v")) {
376*5f757f3fSDimitry Andric     if (getAsUnsignedInteger(FirstLine, 10, Version)) {
377*5f757f3fSDimitry Andric       return createProfileParseError(Twine("version number expected: '") +
378*5f757f3fSDimitry Andric                                      FirstLine + "'");
37981ad6265SDimitry Andric     }
380*5f757f3fSDimitry Andric     if (Version > 1) {
381*5f757f3fSDimitry Andric       return createProfileParseError(Twine("invalid profile version: ") +
382*5f757f3fSDimitry Andric                                      Twine(Version));
38306c3fb27SDimitry Andric     }
384*5f757f3fSDimitry Andric     ++LineIt;
38506c3fb27SDimitry Andric   }
38681ad6265SDimitry Andric 
387*5f757f3fSDimitry Andric   switch (Version) {
388*5f757f3fSDimitry Andric   case 0:
389*5f757f3fSDimitry Andric     // TODO: Deprecate V0 once V1 is fully integrated downstream.
390*5f757f3fSDimitry Andric     return ReadV0Profile();
391*5f757f3fSDimitry Andric   case 1:
392*5f757f3fSDimitry Andric     return ReadV1Profile();
393*5f757f3fSDimitry Andric   default:
394*5f757f3fSDimitry Andric     llvm_unreachable("Invalid profile version.");
39581ad6265SDimitry Andric   }
39681ad6265SDimitry Andric }
39781ad6265SDimitry Andric 
39806c3fb27SDimitry Andric bool BasicBlockSectionsProfileReader::doInitialization(Module &M) {
39981ad6265SDimitry Andric   if (!MBuf)
40006c3fb27SDimitry Andric     return false;
40106c3fb27SDimitry Andric   // Get the function name to debug info filename mapping.
40206c3fb27SDimitry Andric   FunctionNameToDIFilename.clear();
40306c3fb27SDimitry Andric   for (const Function &F : M) {
40406c3fb27SDimitry Andric     SmallString<128> DIFilename;
40506c3fb27SDimitry Andric     if (F.isDeclaration())
40606c3fb27SDimitry Andric       continue;
40706c3fb27SDimitry Andric     DISubprogram *Subprogram = F.getSubprogram();
40806c3fb27SDimitry Andric     if (Subprogram) {
40906c3fb27SDimitry Andric       llvm::DICompileUnit *CU = Subprogram->getUnit();
41006c3fb27SDimitry Andric       if (CU)
41106c3fb27SDimitry Andric         DIFilename = sys::path::remove_leading_dotslash(CU->getFilename());
41206c3fb27SDimitry Andric     }
41306c3fb27SDimitry Andric     [[maybe_unused]] bool inserted =
41406c3fb27SDimitry Andric         FunctionNameToDIFilename.try_emplace(F.getName(), DIFilename).second;
41506c3fb27SDimitry Andric     assert(inserted);
41606c3fb27SDimitry Andric   }
41706c3fb27SDimitry Andric   if (auto Err = ReadProfile())
41881ad6265SDimitry Andric     report_fatal_error(std::move(Err));
41906c3fb27SDimitry Andric   return false;
42081ad6265SDimitry Andric }
42181ad6265SDimitry Andric 
42281ad6265SDimitry Andric ImmutablePass *
42381ad6265SDimitry Andric llvm::createBasicBlockSectionsProfileReaderPass(const MemoryBuffer *Buf) {
42481ad6265SDimitry Andric   return new BasicBlockSectionsProfileReader(Buf);
42581ad6265SDimitry Andric }
426