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"
16c9157d92SDimitry Andric #include "llvm/ADT/DenseSet.h"
1781ad6265SDimitry Andric #include "llvm/ADT/SmallSet.h"
18fe013be4SDimitry 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"
22fe013be4SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h"
23c9157d92SDimitry Andric #include "llvm/Pass.h"
2481ad6265SDimitry Andric #include "llvm/Support/Error.h"
25c9157d92SDimitry Andric #include "llvm/Support/ErrorHandling.h"
2681ad6265SDimitry Andric #include "llvm/Support/LineIterator.h"
2781ad6265SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
28fe013be4SDimitry Andric #include "llvm/Support/Path.h"
29fe013be4SDimitry Andric #include <llvm/ADT/STLExtras.h>
3081ad6265SDimitry Andric 
3181ad6265SDimitry Andric using namespace llvm;
3281ad6265SDimitry Andric 
33*cdc20ff6SDimitry Andric char BasicBlockSectionsProfileReaderWrapperPass::ID = 0;
34*cdc20ff6SDimitry Andric INITIALIZE_PASS(BasicBlockSectionsProfileReaderWrapperPass,
35*cdc20ff6SDimitry Andric                 "bbsections-profile-reader",
3681ad6265SDimitry Andric                 "Reads and parses a basic block sections profile.", false,
3781ad6265SDimitry Andric                 false)
3881ad6265SDimitry Andric 
39c9157d92SDimitry Andric Expected<UniqueBBID>
parseUniqueBBID(StringRef S) const40c9157d92SDimitry Andric BasicBlockSectionsProfileReader::parseUniqueBBID(StringRef S) const {
41c9157d92SDimitry Andric   SmallVector<StringRef, 2> Parts;
42c9157d92SDimitry Andric   S.split(Parts, '.');
43c9157d92SDimitry Andric   if (Parts.size() > 2)
44c9157d92SDimitry Andric     return createProfileParseError(Twine("unable to parse basic block id: '") +
45c9157d92SDimitry Andric                                    S + "'");
46c9157d92SDimitry Andric   unsigned long long BaseBBID;
47c9157d92SDimitry Andric   if (getAsUnsignedInteger(Parts[0], 10, BaseBBID))
48c9157d92SDimitry Andric     return createProfileParseError(
49c9157d92SDimitry Andric         Twine("unable to parse BB id: '" + Parts[0]) +
50c9157d92SDimitry Andric         "': unsigned integer expected");
51c9157d92SDimitry Andric   unsigned long long CloneID = 0;
52c9157d92SDimitry Andric   if (Parts.size() > 1 && getAsUnsignedInteger(Parts[1], 10, CloneID))
53c9157d92SDimitry Andric     return createProfileParseError(Twine("unable to parse clone id: '") +
54c9157d92SDimitry Andric                                    Parts[1] + "': unsigned integer expected");
55c9157d92SDimitry Andric   return UniqueBBID{static_cast<unsigned>(BaseBBID),
56c9157d92SDimitry Andric                     static_cast<unsigned>(CloneID)};
57c9157d92SDimitry Andric }
58c9157d92SDimitry Andric 
isFunctionHot(StringRef FuncName) const5981ad6265SDimitry Andric bool BasicBlockSectionsProfileReader::isFunctionHot(StringRef FuncName) const {
60c9157d92SDimitry Andric   return getClusterInfoForFunction(FuncName).first;
6181ad6265SDimitry Andric }
6281ad6265SDimitry Andric 
6381ad6265SDimitry Andric std::pair<bool, SmallVector<BBClusterInfo>>
getClusterInfoForFunction(StringRef FuncName) const64c9157d92SDimitry Andric BasicBlockSectionsProfileReader::getClusterInfoForFunction(
6581ad6265SDimitry Andric     StringRef FuncName) const {
66c9157d92SDimitry Andric   auto R = ProgramPathAndClusterInfo.find(getAliasName(FuncName));
67c9157d92SDimitry Andric   return R != ProgramPathAndClusterInfo.end()
68c9157d92SDimitry Andric              ? std::pair(true, R->second.ClusterInfo)
69c9157d92SDimitry Andric              : std::pair(false, SmallVector<BBClusterInfo>());
70c9157d92SDimitry Andric }
71c9157d92SDimitry Andric 
72c9157d92SDimitry Andric SmallVector<SmallVector<unsigned>>
getClonePathsForFunction(StringRef FuncName) const73c9157d92SDimitry Andric BasicBlockSectionsProfileReader::getClonePathsForFunction(
74c9157d92SDimitry Andric     StringRef FuncName) const {
75c9157d92SDimitry Andric   return ProgramPathAndClusterInfo.lookup(getAliasName(FuncName)).ClonePaths;
76c9157d92SDimitry Andric }
77c9157d92SDimitry Andric 
78c9157d92SDimitry Andric // Reads the version 1 basic block sections profile. Profile for each function
79c9157d92SDimitry Andric // is encoded as follows:
80c9157d92SDimitry Andric //   m <module_name>
81c9157d92SDimitry Andric //   f <function_name_1> <function_name_2> ...
82c9157d92SDimitry Andric //   c <bb_id_1> <bb_id_2> <bb_id_3>
83c9157d92SDimitry Andric //   c <bb_id_4> <bb_id_5>
84c9157d92SDimitry Andric //   ...
85c9157d92SDimitry Andric // Module name specifier (starting with 'm') is optional and allows
86c9157d92SDimitry Andric // distinguishing profile for internal-linkage functions with the same name. If
87c9157d92SDimitry Andric // not specified, it will apply to any function with the same name. Function
88c9157d92SDimitry Andric // name specifier (starting with 'f') can specify multiple function name
89c9157d92SDimitry Andric // aliases. Basic block clusters are specified by 'c' and specify the cluster of
90c9157d92SDimitry Andric // basic blocks, and the internal order in which they must be placed in the same
91c9157d92SDimitry Andric // section.
92c9157d92SDimitry Andric // This profile can also specify cloning paths which instruct the compiler to
93c9157d92SDimitry Andric // clone basic blocks along a path. The cloned blocks are then specified in the
94c9157d92SDimitry Andric // cluster information.
95c9157d92SDimitry Andric // The following profile lists two cloning paths (starting with 'p') for
96c9157d92SDimitry Andric // function bar and places the total 9 blocks within two clusters. The first two
97c9157d92SDimitry Andric // blocks of a cloning path specify the edge along which the path is cloned. For
98c9157d92SDimitry Andric // instance, path 1 (1 -> 3 -> 4) instructs that 3 and 4 must be cloned along
99c9157d92SDimitry Andric // the edge 1->3. Within the given clusters, each cloned block is identified by
100c9157d92SDimitry Andric // "<original block id>.<clone id>". For instance, 3.1 represents the first
101c9157d92SDimitry Andric // clone of block 3. Original blocks are specified just with their block ids. A
102c9157d92SDimitry Andric // block cloned multiple times appears with distinct clone ids. The CFG for bar
103c9157d92SDimitry Andric // is shown below before and after cloning with its final clusters labeled.
104c9157d92SDimitry Andric //
105c9157d92SDimitry Andric // f main
106c9157d92SDimitry Andric // f bar
107c9157d92SDimitry Andric // p 1 3 4           # cloning path 1
108c9157d92SDimitry Andric // p 4 2             # cloning path 2
109c9157d92SDimitry Andric // c 1 3.1 4.1 6     # basic block cluster 1
110c9157d92SDimitry Andric // c 0 2 3 4 2.1 5   # basic block cluster 2
111c9157d92SDimitry Andric // ****************************************************************************
112c9157d92SDimitry Andric // function bar before and after cloning with basic block clusters shown.
113c9157d92SDimitry Andric // ****************************************************************************
114c9157d92SDimitry Andric //                                ....      ..............
115c9157d92SDimitry Andric //      0 -------+                : 0 :---->: 1 ---> 3.1 :
116c9157d92SDimitry Andric //      |        |                : | :     :........ |  :
117c9157d92SDimitry Andric //      v        v                : v :             : v  :
118c9157d92SDimitry Andric // +--> 2 --> 5  1   ~~~~~~>  +---: 2 :             : 4.1: clsuter 1
119c9157d92SDimitry Andric // |    |        |            |   : | :             : |  :
120c9157d92SDimitry Andric // |    v        |            |   : v .......       : v  :
121c9157d92SDimitry Andric // |    3 <------+            |   : 3 <--+  :       : 6  :
122c9157d92SDimitry Andric // |    |                     |   : |    |  :       :....:
123c9157d92SDimitry Andric // |    v                     |   : v    |  :
124c9157d92SDimitry Andric // +--- 4 ---> 6              |   : 4    |  :
125c9157d92SDimitry Andric //                            |   : |    |  :
126c9157d92SDimitry Andric //                            |   : v    |  :
127c9157d92SDimitry Andric //                            |   :2.1---+  : cluster 2
128c9157d92SDimitry Andric //                            |   : | ......:
129c9157d92SDimitry Andric //                            |   : v :
130c9157d92SDimitry Andric //                            +-->: 5 :
131c9157d92SDimitry Andric //                                ....
132c9157d92SDimitry Andric // ****************************************************************************
ReadV1Profile()133c9157d92SDimitry Andric Error BasicBlockSectionsProfileReader::ReadV1Profile() {
134c9157d92SDimitry Andric   auto FI = ProgramPathAndClusterInfo.end();
135c9157d92SDimitry Andric 
136c9157d92SDimitry Andric   // Current cluster ID corresponding to this function.
137c9157d92SDimitry Andric   unsigned CurrentCluster = 0;
138c9157d92SDimitry Andric   // Current position in the current cluster.
139c9157d92SDimitry Andric   unsigned CurrentPosition = 0;
140c9157d92SDimitry Andric 
141c9157d92SDimitry Andric   // Temporary set to ensure every basic block ID appears once in the clusters
142c9157d92SDimitry Andric   // of a function.
143c9157d92SDimitry Andric   DenseSet<UniqueBBID> FuncBBIDs;
144c9157d92SDimitry Andric 
145c9157d92SDimitry Andric   // Debug-info-based module filename for the current function. Empty string
146c9157d92SDimitry Andric   // means no filename.
147c9157d92SDimitry Andric   StringRef DIFilename;
148c9157d92SDimitry Andric 
149c9157d92SDimitry Andric   for (; !LineIt.is_at_eof(); ++LineIt) {
150c9157d92SDimitry Andric     StringRef S(*LineIt);
151c9157d92SDimitry Andric     char Specifier = S[0];
152c9157d92SDimitry Andric     S = S.drop_front().trim();
153c9157d92SDimitry Andric     SmallVector<StringRef, 4> Values;
154c9157d92SDimitry Andric     S.split(Values, ' ');
155c9157d92SDimitry Andric     switch (Specifier) {
156c9157d92SDimitry Andric     case '@':
157c9157d92SDimitry Andric       continue;
158c9157d92SDimitry Andric     case 'm': // Module name speicifer.
159c9157d92SDimitry Andric       if (Values.size() != 1) {
160c9157d92SDimitry Andric         return createProfileParseError(Twine("invalid module name value: '") +
161c9157d92SDimitry Andric                                        S + "'");
162c9157d92SDimitry Andric       }
163c9157d92SDimitry Andric       DIFilename = sys::path::remove_leading_dotslash(Values[0]);
164c9157d92SDimitry Andric       continue;
165c9157d92SDimitry Andric     case 'f': { // Function names specifier.
166c9157d92SDimitry Andric       bool FunctionFound = any_of(Values, [&](StringRef Alias) {
167c9157d92SDimitry Andric         auto It = FunctionNameToDIFilename.find(Alias);
168c9157d92SDimitry Andric         // No match if this function name is not found in this module.
169c9157d92SDimitry Andric         if (It == FunctionNameToDIFilename.end())
170c9157d92SDimitry Andric           return false;
171c9157d92SDimitry Andric         // Return a match if debug-info-filename is not specified. Otherwise,
172c9157d92SDimitry Andric         // check for equality.
173c9157d92SDimitry Andric         return DIFilename.empty() || It->second.equals(DIFilename);
174c9157d92SDimitry Andric       });
175c9157d92SDimitry Andric       if (!FunctionFound) {
176c9157d92SDimitry Andric         // Skip the following profile by setting the profile iterator (FI) to
177c9157d92SDimitry Andric         // the past-the-end element.
178c9157d92SDimitry Andric         FI = ProgramPathAndClusterInfo.end();
179c9157d92SDimitry Andric         DIFilename = "";
180c9157d92SDimitry Andric         continue;
181c9157d92SDimitry Andric       }
182c9157d92SDimitry Andric       for (size_t i = 1; i < Values.size(); ++i)
183c9157d92SDimitry Andric         FuncAliasMap.try_emplace(Values[i], Values.front());
184c9157d92SDimitry Andric 
185c9157d92SDimitry Andric       // Prepare for parsing clusters of this function name.
186c9157d92SDimitry Andric       // Start a new cluster map for this function name.
187c9157d92SDimitry Andric       auto R = ProgramPathAndClusterInfo.try_emplace(Values.front());
188c9157d92SDimitry Andric       // Report error when multiple profiles have been specified for the same
189c9157d92SDimitry Andric       // function.
190c9157d92SDimitry Andric       if (!R.second)
191c9157d92SDimitry Andric         return createProfileParseError("duplicate profile for function '" +
192c9157d92SDimitry Andric                                        Values.front() + "'");
193c9157d92SDimitry Andric       FI = R.first;
194c9157d92SDimitry Andric       CurrentCluster = 0;
195c9157d92SDimitry Andric       FuncBBIDs.clear();
196c9157d92SDimitry Andric       // We won't need DIFilename anymore. Clean it up to avoid its application
197c9157d92SDimitry Andric       // on the next function.
198c9157d92SDimitry Andric       DIFilename = "";
199c9157d92SDimitry Andric       continue;
200c9157d92SDimitry Andric     }
201c9157d92SDimitry Andric     case 'c': // Basic block cluster specifier.
202c9157d92SDimitry Andric       // Skip the profile when we the profile iterator (FI) refers to the
203c9157d92SDimitry Andric       // past-the-end element.
204c9157d92SDimitry Andric       if (FI == ProgramPathAndClusterInfo.end())
205c9157d92SDimitry Andric         continue;
206c9157d92SDimitry Andric       // Reset current cluster position.
207c9157d92SDimitry Andric       CurrentPosition = 0;
208c9157d92SDimitry Andric       for (auto BasicBlockIDStr : Values) {
209c9157d92SDimitry Andric         auto BasicBlockID = parseUniqueBBID(BasicBlockIDStr);
210c9157d92SDimitry Andric         if (!BasicBlockID)
211c9157d92SDimitry Andric           return BasicBlockID.takeError();
212c9157d92SDimitry Andric         if (!FuncBBIDs.insert(*BasicBlockID).second)
213c9157d92SDimitry Andric           return createProfileParseError(
214c9157d92SDimitry Andric               Twine("duplicate basic block id found '") + BasicBlockIDStr +
215c9157d92SDimitry Andric               "'");
216c9157d92SDimitry Andric 
217c9157d92SDimitry Andric         FI->second.ClusterInfo.emplace_back(BBClusterInfo{
218c9157d92SDimitry Andric             *std::move(BasicBlockID), CurrentCluster, CurrentPosition++});
219c9157d92SDimitry Andric       }
220c9157d92SDimitry Andric       CurrentCluster++;
221c9157d92SDimitry Andric       continue;
222c9157d92SDimitry Andric     case 'p': { // Basic block cloning path specifier.
223c9157d92SDimitry Andric       // Skip the profile when we the profile iterator (FI) refers to the
224c9157d92SDimitry Andric       // past-the-end element.
225c9157d92SDimitry Andric       if (FI == ProgramPathAndClusterInfo.end())
226c9157d92SDimitry Andric         continue;
227c9157d92SDimitry Andric       SmallSet<unsigned, 5> BBsInPath;
228c9157d92SDimitry Andric       FI->second.ClonePaths.push_back({});
229c9157d92SDimitry Andric       for (size_t I = 0; I < Values.size(); ++I) {
230c9157d92SDimitry Andric         auto BaseBBIDStr = Values[I];
231c9157d92SDimitry Andric         unsigned long long BaseBBID = 0;
232c9157d92SDimitry Andric         if (getAsUnsignedInteger(BaseBBIDStr, 10, BaseBBID))
233c9157d92SDimitry Andric           return createProfileParseError(Twine("unsigned integer expected: '") +
234c9157d92SDimitry Andric                                          BaseBBIDStr + "'");
235c9157d92SDimitry Andric         if (I != 0 && !BBsInPath.insert(BaseBBID).second)
236c9157d92SDimitry Andric           return createProfileParseError(
237c9157d92SDimitry Andric               Twine("duplicate cloned block in path: '") + BaseBBIDStr + "'");
238c9157d92SDimitry Andric         FI->second.ClonePaths.back().push_back(BaseBBID);
239c9157d92SDimitry Andric       }
240c9157d92SDimitry Andric       continue;
241c9157d92SDimitry Andric     }
242c9157d92SDimitry Andric     default:
243c9157d92SDimitry Andric       return createProfileParseError(Twine("invalid specifier: '") +
244c9157d92SDimitry Andric                                      Twine(Specifier) + "'");
245c9157d92SDimitry Andric     }
246c9157d92SDimitry Andric     llvm_unreachable("should not break from this switch statement");
247c9157d92SDimitry Andric   }
248c9157d92SDimitry Andric   return Error::success();
249c9157d92SDimitry Andric }
250c9157d92SDimitry Andric 
ReadV0Profile()251c9157d92SDimitry Andric Error BasicBlockSectionsProfileReader::ReadV0Profile() {
252c9157d92SDimitry Andric   auto FI = ProgramPathAndClusterInfo.end();
253c9157d92SDimitry Andric   // Current cluster ID corresponding to this function.
254c9157d92SDimitry Andric   unsigned CurrentCluster = 0;
255c9157d92SDimitry Andric   // Current position in the current cluster.
256c9157d92SDimitry Andric   unsigned CurrentPosition = 0;
257c9157d92SDimitry Andric 
258c9157d92SDimitry Andric   // Temporary set to ensure every basic block ID appears once in the clusters
259c9157d92SDimitry Andric   // of a function.
260c9157d92SDimitry Andric   SmallSet<unsigned, 4> FuncBBIDs;
261c9157d92SDimitry Andric 
262c9157d92SDimitry Andric   for (; !LineIt.is_at_eof(); ++LineIt) {
263c9157d92SDimitry Andric     StringRef S(*LineIt);
264c9157d92SDimitry Andric     if (S[0] == '@')
265c9157d92SDimitry Andric       continue;
266c9157d92SDimitry Andric     // Check for the leading "!"
267c9157d92SDimitry Andric     if (!S.consume_front("!") || S.empty())
268c9157d92SDimitry Andric       break;
269c9157d92SDimitry Andric     // Check for second "!" which indicates a cluster of basic blocks.
270c9157d92SDimitry Andric     if (S.consume_front("!")) {
271c9157d92SDimitry Andric       // Skip the profile when we the profile iterator (FI) refers to the
272c9157d92SDimitry Andric       // past-the-end element.
273c9157d92SDimitry Andric       if (FI == ProgramPathAndClusterInfo.end())
274c9157d92SDimitry Andric         continue;
275c9157d92SDimitry Andric       SmallVector<StringRef, 4> BBIDs;
276c9157d92SDimitry Andric       S.split(BBIDs, ' ');
277c9157d92SDimitry Andric       // Reset current cluster position.
278c9157d92SDimitry Andric       CurrentPosition = 0;
279c9157d92SDimitry Andric       for (auto BBIDStr : BBIDs) {
280c9157d92SDimitry Andric         unsigned long long BBID;
281c9157d92SDimitry Andric         if (getAsUnsignedInteger(BBIDStr, 10, BBID))
282c9157d92SDimitry Andric           return createProfileParseError(Twine("unsigned integer expected: '") +
283c9157d92SDimitry Andric                                          BBIDStr + "'");
284c9157d92SDimitry Andric         if (!FuncBBIDs.insert(BBID).second)
285c9157d92SDimitry Andric           return createProfileParseError(
286c9157d92SDimitry Andric               Twine("duplicate basic block id found '") + BBIDStr + "'");
287c9157d92SDimitry Andric 
288c9157d92SDimitry Andric         FI->second.ClusterInfo.emplace_back(
289c9157d92SDimitry Andric             BBClusterInfo({{static_cast<unsigned>(BBID), 0},
290c9157d92SDimitry Andric                            CurrentCluster,
291c9157d92SDimitry Andric                            CurrentPosition++}));
292c9157d92SDimitry Andric       }
293c9157d92SDimitry Andric       CurrentCluster++;
294c9157d92SDimitry Andric     } else {
295c9157d92SDimitry Andric       // This is a function name specifier. It may include a debug info filename
296c9157d92SDimitry Andric       // specifier starting with `M=`.
297c9157d92SDimitry Andric       auto [AliasesStr, DIFilenameStr] = S.split(' ');
298c9157d92SDimitry Andric       SmallString<128> DIFilename;
299c9157d92SDimitry Andric       if (DIFilenameStr.starts_with("M=")) {
300c9157d92SDimitry Andric         DIFilename =
301c9157d92SDimitry Andric             sys::path::remove_leading_dotslash(DIFilenameStr.substr(2));
302c9157d92SDimitry Andric         if (DIFilename.empty())
303c9157d92SDimitry Andric           return createProfileParseError("empty module name specifier");
304c9157d92SDimitry Andric       } else if (!DIFilenameStr.empty()) {
305c9157d92SDimitry Andric         return createProfileParseError("unknown string found: '" +
306c9157d92SDimitry Andric                                        DIFilenameStr + "'");
307c9157d92SDimitry Andric       }
308c9157d92SDimitry Andric       // Function aliases are separated using '/'. We use the first function
309c9157d92SDimitry Andric       // name for the cluster info mapping and delegate all other aliases to
310c9157d92SDimitry Andric       // this one.
311c9157d92SDimitry Andric       SmallVector<StringRef, 4> Aliases;
312c9157d92SDimitry Andric       AliasesStr.split(Aliases, '/');
313c9157d92SDimitry Andric       bool FunctionFound = any_of(Aliases, [&](StringRef Alias) {
314c9157d92SDimitry Andric         auto It = FunctionNameToDIFilename.find(Alias);
315c9157d92SDimitry Andric         // No match if this function name is not found in this module.
316c9157d92SDimitry Andric         if (It == FunctionNameToDIFilename.end())
317c9157d92SDimitry Andric           return false;
318c9157d92SDimitry Andric         // Return a match if debug-info-filename is not specified. Otherwise,
319c9157d92SDimitry Andric         // check for equality.
320c9157d92SDimitry Andric         return DIFilename.empty() || It->second.equals(DIFilename);
321c9157d92SDimitry Andric       });
322c9157d92SDimitry Andric       if (!FunctionFound) {
323c9157d92SDimitry Andric         // Skip the following profile by setting the profile iterator (FI) to
324c9157d92SDimitry Andric         // the past-the-end element.
325c9157d92SDimitry Andric         FI = ProgramPathAndClusterInfo.end();
326c9157d92SDimitry Andric         continue;
327c9157d92SDimitry Andric       }
328c9157d92SDimitry Andric       for (size_t i = 1; i < Aliases.size(); ++i)
329c9157d92SDimitry Andric         FuncAliasMap.try_emplace(Aliases[i], Aliases.front());
330c9157d92SDimitry Andric 
331c9157d92SDimitry Andric       // Prepare for parsing clusters of this function name.
332c9157d92SDimitry Andric       // Start a new cluster map for this function name.
333c9157d92SDimitry Andric       auto R = ProgramPathAndClusterInfo.try_emplace(Aliases.front());
334c9157d92SDimitry Andric       // Report error when multiple profiles have been specified for the same
335c9157d92SDimitry Andric       // function.
336c9157d92SDimitry Andric       if (!R.second)
337c9157d92SDimitry Andric         return createProfileParseError("duplicate profile for function '" +
338c9157d92SDimitry Andric                                        Aliases.front() + "'");
339c9157d92SDimitry Andric       FI = R.first;
340c9157d92SDimitry Andric       CurrentCluster = 0;
341c9157d92SDimitry Andric       FuncBBIDs.clear();
342c9157d92SDimitry Andric     }
343c9157d92SDimitry Andric   }
344c9157d92SDimitry Andric   return Error::success();
34581ad6265SDimitry Andric }
34681ad6265SDimitry Andric 
34781ad6265SDimitry Andric // Basic Block Sections can be enabled for a subset of machine basic blocks.
34881ad6265SDimitry Andric // This is done by passing a file containing names of functions for which basic
34981ad6265SDimitry Andric // block sections are desired. Additionally, machine basic block ids of the
35081ad6265SDimitry Andric // functions can also be specified for a finer granularity. Moreover, a cluster
35181ad6265SDimitry Andric // of basic blocks could be assigned to the same section.
352fe013be4SDimitry Andric // Optionally, a debug-info filename can be specified for each function to allow
353fe013be4SDimitry Andric // distinguishing internal-linkage functions of the same name.
35481ad6265SDimitry Andric // A file with basic block sections for all of function main and three blocks
35581ad6265SDimitry Andric // for function foo (of which 1 and 2 are placed in a cluster) looks like this:
356fe013be4SDimitry Andric // (Profile for function foo is only loaded when its debug-info filename
357fe013be4SDimitry Andric // matches 'path/to/foo_file.cc').
35881ad6265SDimitry Andric // ----------------------------
35981ad6265SDimitry Andric // list.txt:
36081ad6265SDimitry Andric // !main
361fe013be4SDimitry Andric // !foo M=path/to/foo_file.cc
36281ad6265SDimitry Andric // !!1 2
36381ad6265SDimitry Andric // !!4
ReadProfile()364fe013be4SDimitry Andric Error BasicBlockSectionsProfileReader::ReadProfile() {
36581ad6265SDimitry Andric   assert(MBuf);
36681ad6265SDimitry Andric 
367c9157d92SDimitry Andric   unsigned long long Version = 0;
368c9157d92SDimitry Andric   StringRef FirstLine(*LineIt);
369c9157d92SDimitry Andric   if (FirstLine.consume_front("v")) {
370c9157d92SDimitry Andric     if (getAsUnsignedInteger(FirstLine, 10, Version)) {
371c9157d92SDimitry Andric       return createProfileParseError(Twine("version number expected: '") +
372c9157d92SDimitry Andric                                      FirstLine + "'");
37381ad6265SDimitry Andric     }
374c9157d92SDimitry Andric     if (Version > 1) {
375c9157d92SDimitry Andric       return createProfileParseError(Twine("invalid profile version: ") +
376c9157d92SDimitry Andric                                      Twine(Version));
377fe013be4SDimitry Andric     }
378c9157d92SDimitry Andric     ++LineIt;
379fe013be4SDimitry Andric   }
38081ad6265SDimitry Andric 
381c9157d92SDimitry Andric   switch (Version) {
382c9157d92SDimitry Andric   case 0:
383c9157d92SDimitry Andric     // TODO: Deprecate V0 once V1 is fully integrated downstream.
384c9157d92SDimitry Andric     return ReadV0Profile();
385c9157d92SDimitry Andric   case 1:
386c9157d92SDimitry Andric     return ReadV1Profile();
387c9157d92SDimitry Andric   default:
388c9157d92SDimitry Andric     llvm_unreachable("Invalid profile version.");
38981ad6265SDimitry Andric   }
39081ad6265SDimitry Andric }
39181ad6265SDimitry Andric 
doInitialization(Module & M)392*cdc20ff6SDimitry Andric bool BasicBlockSectionsProfileReaderWrapperPass::doInitialization(Module &M) {
393*cdc20ff6SDimitry Andric   if (!BBSPR.MBuf)
394fe013be4SDimitry Andric     return false;
395fe013be4SDimitry Andric   // Get the function name to debug info filename mapping.
396*cdc20ff6SDimitry Andric   BBSPR.FunctionNameToDIFilename.clear();
397fe013be4SDimitry Andric   for (const Function &F : M) {
398fe013be4SDimitry Andric     SmallString<128> DIFilename;
399fe013be4SDimitry Andric     if (F.isDeclaration())
400fe013be4SDimitry Andric       continue;
401fe013be4SDimitry Andric     DISubprogram *Subprogram = F.getSubprogram();
402fe013be4SDimitry Andric     if (Subprogram) {
403fe013be4SDimitry Andric       llvm::DICompileUnit *CU = Subprogram->getUnit();
404fe013be4SDimitry Andric       if (CU)
405fe013be4SDimitry Andric         DIFilename = sys::path::remove_leading_dotslash(CU->getFilename());
406fe013be4SDimitry Andric     }
407fe013be4SDimitry Andric     [[maybe_unused]] bool inserted =
408*cdc20ff6SDimitry Andric         BBSPR.FunctionNameToDIFilename.try_emplace(F.getName(), DIFilename)
409*cdc20ff6SDimitry Andric             .second;
410fe013be4SDimitry Andric     assert(inserted);
411fe013be4SDimitry Andric   }
412*cdc20ff6SDimitry Andric   if (auto Err = BBSPR.ReadProfile())
41381ad6265SDimitry Andric     report_fatal_error(std::move(Err));
414fe013be4SDimitry Andric   return false;
41581ad6265SDimitry Andric }
41681ad6265SDimitry Andric 
417*cdc20ff6SDimitry Andric AnalysisKey BasicBlockSectionsProfileReaderAnalysis::Key;
418*cdc20ff6SDimitry Andric 
419*cdc20ff6SDimitry Andric BasicBlockSectionsProfileReader
run(Function & F,FunctionAnalysisManager & AM)420*cdc20ff6SDimitry Andric BasicBlockSectionsProfileReaderAnalysis::run(Function &F,
421*cdc20ff6SDimitry Andric                                              FunctionAnalysisManager &AM) {
422*cdc20ff6SDimitry Andric   return BasicBlockSectionsProfileReader(TM->getBBSectionsFuncListBuf());
423*cdc20ff6SDimitry Andric }
424*cdc20ff6SDimitry Andric 
isFunctionHot(StringRef FuncName) const425*cdc20ff6SDimitry Andric bool BasicBlockSectionsProfileReaderWrapperPass::isFunctionHot(
426*cdc20ff6SDimitry Andric     StringRef FuncName) const {
427*cdc20ff6SDimitry Andric   return BBSPR.isFunctionHot(FuncName);
428*cdc20ff6SDimitry Andric }
429*cdc20ff6SDimitry Andric 
430*cdc20ff6SDimitry Andric std::pair<bool, SmallVector<BBClusterInfo>>
getClusterInfoForFunction(StringRef FuncName) const431*cdc20ff6SDimitry Andric BasicBlockSectionsProfileReaderWrapperPass::getClusterInfoForFunction(
432*cdc20ff6SDimitry Andric     StringRef FuncName) const {
433*cdc20ff6SDimitry Andric   return BBSPR.getClusterInfoForFunction(FuncName);
434*cdc20ff6SDimitry Andric }
435*cdc20ff6SDimitry Andric 
436*cdc20ff6SDimitry Andric SmallVector<SmallVector<unsigned>>
getClonePathsForFunction(StringRef FuncName) const437*cdc20ff6SDimitry Andric BasicBlockSectionsProfileReaderWrapperPass::getClonePathsForFunction(
438*cdc20ff6SDimitry Andric     StringRef FuncName) const {
439*cdc20ff6SDimitry Andric   return BBSPR.getClonePathsForFunction(FuncName);
440*cdc20ff6SDimitry Andric }
441*cdc20ff6SDimitry Andric 
442*cdc20ff6SDimitry Andric BasicBlockSectionsProfileReader &
getBBSPR()443*cdc20ff6SDimitry Andric BasicBlockSectionsProfileReaderWrapperPass::getBBSPR() {
444*cdc20ff6SDimitry Andric   return BBSPR;
445*cdc20ff6SDimitry Andric }
446*cdc20ff6SDimitry Andric 
createBasicBlockSectionsProfileReaderWrapperPass(const MemoryBuffer * Buf)447*cdc20ff6SDimitry Andric ImmutablePass *llvm::createBasicBlockSectionsProfileReaderWrapperPass(
448*cdc20ff6SDimitry Andric     const MemoryBuffer *Buf) {
449*cdc20ff6SDimitry Andric   return new BasicBlockSectionsProfileReaderWrapperPass(Buf);
45081ad6265SDimitry Andric }
451