xref: /llvm-project/bolt/lib/Profile/DataReader.cpp (revision 2f09f445b2d6b3ef197aecd8d1e06d08140380f3)
1*2f09f445SMaksim Panchenko //===- bolt/Profile/DataReader.cpp - Perf data reader ---------------------===//
2a34c753fSRafael Auler //
3a34c753fSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a34c753fSRafael Auler // See https://llvm.org/LICENSE.txt for license information.
5a34c753fSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a34c753fSRafael Auler //
7a34c753fSRafael Auler //===----------------------------------------------------------------------===//
8a34c753fSRafael Auler //
9a34c753fSRafael Auler // This family of functions reads profile data written by the perf2bolt
10a34c753fSRafael Auler // utility and stores it in memory for llvm-bolt consumption.
11a34c753fSRafael Auler //
12a34c753fSRafael Auler //===----------------------------------------------------------------------===//
13a34c753fSRafael Auler 
14a34c753fSRafael Auler #include "bolt/Profile/DataReader.h"
15a34c753fSRafael Auler #include "bolt/Core/BinaryFunction.h"
16a34c753fSRafael Auler #include "bolt/Passes/MCF.h"
17a34c753fSRafael Auler #include "bolt/Utils/Utils.h"
18a34c753fSRafael Auler #include "llvm/Support/CommandLine.h"
19a34c753fSRafael Auler #include "llvm/Support/Debug.h"
20a34c753fSRafael Auler #include <map>
21a34c753fSRafael Auler 
22a34c753fSRafael Auler #undef  DEBUG_TYPE
23a34c753fSRafael Auler #define DEBUG_TYPE "bolt-prof"
24a34c753fSRafael Auler 
25a34c753fSRafael Auler using namespace llvm;
26a34c753fSRafael Auler 
27a34c753fSRafael Auler namespace opts {
28a34c753fSRafael Auler 
29a34c753fSRafael Auler extern cl::OptionCategory BoltCategory;
30a34c753fSRafael Auler extern llvm::cl::opt<unsigned> Verbosity;
31a34c753fSRafael Auler 
32a34c753fSRafael Auler static cl::opt<bool>
33a34c753fSRafael Auler DumpData("dump-data",
34a34c753fSRafael Auler   cl::desc("dump parsed bolt data for debugging"),
35a34c753fSRafael Auler   cl::Hidden,
36a34c753fSRafael Auler   cl::cat(BoltCategory));
37a34c753fSRafael Auler 
38a34c753fSRafael Auler } // namespace opts
39a34c753fSRafael Auler 
40a34c753fSRafael Auler namespace llvm {
41a34c753fSRafael Auler namespace bolt {
42a34c753fSRafael Auler 
43a34c753fSRafael Auler Optional<StringRef> getLTOCommonName(const StringRef Name) {
44a34c753fSRafael Auler   size_t LTOSuffixPos = Name.find(".lto_priv.");
45a34c753fSRafael Auler   if (LTOSuffixPos != StringRef::npos) {
46a34c753fSRafael Auler     return Name.substr(0, LTOSuffixPos + 10);
47a34c753fSRafael Auler   } else if ((LTOSuffixPos = Name.find(".constprop.")) != StringRef::npos) {
48a34c753fSRafael Auler     return Name.substr(0, LTOSuffixPos + 11);
49a34c753fSRafael Auler   } else {
50a34c753fSRafael Auler     return NoneType();
51a34c753fSRafael Auler   }
52a34c753fSRafael Auler }
53a34c753fSRafael Auler 
54a34c753fSRafael Auler namespace {
55a34c753fSRafael Auler 
56a34c753fSRafael Auler /// Return true if the function name can change across compilations.
57a34c753fSRafael Auler bool hasVolatileName(const BinaryFunction &BF) {
58a34c753fSRafael Auler   for (const StringRef Name : BF.getNames()) {
59a34c753fSRafael Auler     if (getLTOCommonName(Name))
60a34c753fSRafael Auler       return true;
61a34c753fSRafael Auler   }
62a34c753fSRafael Auler   return false;
63a34c753fSRafael Auler }
64a34c753fSRafael Auler 
65a34c753fSRafael Auler /// Return standard escaped name of the function possibly renamed by BOLT.
66a34c753fSRafael Auler std::string normalizeName(StringRef NameRef) {
67a34c753fSRafael Auler   // Strip "PG." prefix used for globalized locals.
68a34c753fSRafael Auler   NameRef = NameRef.startswith("PG.") ? NameRef.substr(2) : NameRef;
69a34c753fSRafael Auler   return getEscapedName(NameRef);
70a34c753fSRafael Auler }
71a34c753fSRafael Auler 
72a34c753fSRafael Auler } // anonymous namespace
73a34c753fSRafael Auler 
74a34c753fSRafael Auler raw_ostream &operator<<(raw_ostream &OS, const Location &Loc) {
75a34c753fSRafael Auler   if (Loc.IsSymbol) {
76a34c753fSRafael Auler     OS << Loc.Name;
77a34c753fSRafael Auler     if (Loc.Offset)
78a34c753fSRafael Auler       OS << "+" << Twine::utohexstr(Loc.Offset);
79a34c753fSRafael Auler   } else {
80a34c753fSRafael Auler     OS << Twine::utohexstr(Loc.Offset);
81a34c753fSRafael Auler   }
82a34c753fSRafael Auler   return OS;
83a34c753fSRafael Auler }
84a34c753fSRafael Auler 
85a34c753fSRafael Auler void FuncBranchData::appendFrom(const FuncBranchData &FBD, uint64_t Offset) {
86a34c753fSRafael Auler   Data.insert(Data.end(), FBD.Data.begin(), FBD.Data.end());
87a34c753fSRafael Auler   for (auto I = Data.begin(), E = Data.end(); I != E; ++I) {
88a34c753fSRafael Auler     if (I->From.Name == FBD.Name) {
89a34c753fSRafael Auler       I->From.Name = this->Name;
90a34c753fSRafael Auler       I->From.Offset += Offset;
91a34c753fSRafael Auler     }
92a34c753fSRafael Auler     if (I->To.Name == FBD.Name) {
93a34c753fSRafael Auler       I->To.Name = this->Name;
94a34c753fSRafael Auler       I->To.Offset += Offset;
95a34c753fSRafael Auler     }
96a34c753fSRafael Auler   }
97a34c753fSRafael Auler   std::stable_sort(Data.begin(), Data.end());
98a34c753fSRafael Auler   ExecutionCount += FBD.ExecutionCount;
99a34c753fSRafael Auler   for (auto I = FBD.EntryData.begin(), E = FBD.EntryData.end(); I != E; ++I) {
100a34c753fSRafael Auler     assert(I->To.Name == FBD.Name);
101a34c753fSRafael Auler     auto NewElmt = EntryData.insert(EntryData.end(), *I);
102a34c753fSRafael Auler     NewElmt->To.Name = this->Name;
103a34c753fSRafael Auler     NewElmt->To.Offset += Offset;
104a34c753fSRafael Auler   }
105a34c753fSRafael Auler }
106a34c753fSRafael Auler 
107a34c753fSRafael Auler uint64_t FuncBranchData::getNumExecutedBranches() const {
108a34c753fSRafael Auler   uint64_t ExecutedBranches = 0;
109a34c753fSRafael Auler   for (const BranchInfo &BI : Data) {
110a34c753fSRafael Auler     int64_t BranchCount = BI.Branches;
111a34c753fSRafael Auler     assert(BranchCount >= 0 && "branch execution count should not be negative");
112a34c753fSRafael Auler     ExecutedBranches += BranchCount;
113a34c753fSRafael Auler   }
114a34c753fSRafael Auler   return ExecutedBranches;
115a34c753fSRafael Auler }
116a34c753fSRafael Auler 
11740c2e0faSMaksim Panchenko void SampleInfo::mergeWith(const SampleInfo &SI) { Hits += SI.Hits; }
118a34c753fSRafael Auler 
119a34c753fSRafael Auler void SampleInfo::print(raw_ostream &OS) const {
120a34c753fSRafael Auler   OS << Loc.IsSymbol << " " << Loc.Name << " " << Twine::utohexstr(Loc.Offset)
121a34c753fSRafael Auler      << " " << Hits << "\n";
122a34c753fSRafael Auler }
123a34c753fSRafael Auler 
12440c2e0faSMaksim Panchenko uint64_t FuncSampleData::getSamples(uint64_t Start, uint64_t End) const {
125a34c753fSRafael Auler   assert(std::is_sorted(Data.begin(), Data.end()));
126a34c753fSRafael Auler   struct Compare {
127a34c753fSRafael Auler     bool operator()(const SampleInfo &SI, const uint64_t Val) const {
128a34c753fSRafael Auler       return SI.Loc.Offset < Val;
129a34c753fSRafael Auler     }
130a34c753fSRafael Auler     bool operator()(const uint64_t Val, const SampleInfo &SI) const {
131a34c753fSRafael Auler       return Val < SI.Loc.Offset;
132a34c753fSRafael Auler     }
133a34c753fSRafael Auler   };
134a34c753fSRafael Auler   uint64_t Result = 0;
135a34c753fSRafael Auler   for (auto I = std::lower_bound(Data.begin(), Data.end(), Start, Compare()),
136a34c753fSRafael Auler             E = std::lower_bound(Data.begin(), Data.end(), End, Compare());
137a34c753fSRafael Auler        I != E; ++I) {
138a34c753fSRafael Auler     Result += I->Hits;
139a34c753fSRafael Auler   }
140a34c753fSRafael Auler   return Result;
141a34c753fSRafael Auler }
142a34c753fSRafael Auler 
143a34c753fSRafael Auler void FuncSampleData::bumpCount(uint64_t Offset, uint64_t Count) {
144a34c753fSRafael Auler   auto Iter = Index.find(Offset);
145a34c753fSRafael Auler   if (Iter == Index.end()) {
146a34c753fSRafael Auler     Data.emplace_back(Location(true, Name, Offset), Count);
147a34c753fSRafael Auler     Index[Offset] = Data.size() - 1;
148a34c753fSRafael Auler     return;
149a34c753fSRafael Auler   }
150a34c753fSRafael Auler   SampleInfo &SI = Data[Iter->second];
151a34c753fSRafael Auler   SI.Hits += Count;
152a34c753fSRafael Auler }
153a34c753fSRafael Auler 
154a34c753fSRafael Auler void FuncBranchData::bumpBranchCount(uint64_t OffsetFrom, uint64_t OffsetTo,
155a34c753fSRafael Auler                                      uint64_t Count, uint64_t Mispreds) {
156a34c753fSRafael Auler   auto Iter = IntraIndex[OffsetFrom].find(OffsetTo);
157a34c753fSRafael Auler   if (Iter == IntraIndex[OffsetFrom].end()) {
158a34c753fSRafael Auler     Data.emplace_back(Location(true, Name, OffsetFrom),
159a34c753fSRafael Auler                       Location(true, Name, OffsetTo), Mispreds, Count);
160a34c753fSRafael Auler     IntraIndex[OffsetFrom][OffsetTo] = Data.size() - 1;
161a34c753fSRafael Auler     return;
162a34c753fSRafael Auler   }
163a34c753fSRafael Auler   BranchInfo &BI = Data[Iter->second];
164a34c753fSRafael Auler   BI.Branches += Count;
165a34c753fSRafael Auler   BI.Mispreds += Mispreds;
166a34c753fSRafael Auler }
167a34c753fSRafael Auler 
168a34c753fSRafael Auler void FuncBranchData::bumpCallCount(uint64_t OffsetFrom, const Location &To,
169a34c753fSRafael Auler                                    uint64_t Count, uint64_t Mispreds) {
170a34c753fSRafael Auler   auto Iter = InterIndex[OffsetFrom].find(To);
171a34c753fSRafael Auler   if (Iter == InterIndex[OffsetFrom].end()) {
172a34c753fSRafael Auler     Data.emplace_back(Location(true, Name, OffsetFrom), To, Mispreds, Count);
173a34c753fSRafael Auler     InterIndex[OffsetFrom][To] = Data.size() - 1;
174a34c753fSRafael Auler     return;
175a34c753fSRafael Auler   }
176a34c753fSRafael Auler   BranchInfo &BI = Data[Iter->second];
177a34c753fSRafael Auler   BI.Branches += Count;
178a34c753fSRafael Auler   BI.Mispreds += Mispreds;
179a34c753fSRafael Auler }
180a34c753fSRafael Auler 
181a34c753fSRafael Auler void FuncBranchData::bumpEntryCount(const Location &From, uint64_t OffsetTo,
182a34c753fSRafael Auler                                     uint64_t Count, uint64_t Mispreds) {
183a34c753fSRafael Auler   auto Iter = EntryIndex[OffsetTo].find(From);
184a34c753fSRafael Auler   if (Iter == EntryIndex[OffsetTo].end()) {
185a34c753fSRafael Auler     EntryData.emplace_back(From, Location(true, Name, OffsetTo), Mispreds,
186a34c753fSRafael Auler                            Count);
187a34c753fSRafael Auler     EntryIndex[OffsetTo][From] = EntryData.size() - 1;
188a34c753fSRafael Auler     return;
189a34c753fSRafael Auler   }
190a34c753fSRafael Auler   BranchInfo &BI = EntryData[Iter->second];
191a34c753fSRafael Auler   BI.Branches += Count;
192a34c753fSRafael Auler   BI.Mispreds += Mispreds;
193a34c753fSRafael Auler }
194a34c753fSRafael Auler 
195a34c753fSRafael Auler void BranchInfo::mergeWith(const BranchInfo &BI) {
196a34c753fSRafael Auler   Branches += BI.Branches;
197a34c753fSRafael Auler   Mispreds += BI.Mispreds;
198a34c753fSRafael Auler }
199a34c753fSRafael Auler 
200a34c753fSRafael Auler void BranchInfo::print(raw_ostream &OS) const {
201a34c753fSRafael Auler   OS << From.IsSymbol << " " << From.Name << " "
20240c2e0faSMaksim Panchenko      << Twine::utohexstr(From.Offset) << " " << To.IsSymbol << " " << To.Name
20340c2e0faSMaksim Panchenko      << " " << Twine::utohexstr(To.Offset) << " " << Mispreds << " " << Branches
20440c2e0faSMaksim Panchenko      << '\n';
205a34c753fSRafael Auler }
206a34c753fSRafael Auler 
207a34c753fSRafael Auler ErrorOr<const BranchInfo &> FuncBranchData::getBranch(uint64_t From,
208a34c753fSRafael Auler                                                       uint64_t To) const {
209a34c753fSRafael Auler   for (const BranchInfo &I : Data) {
21040c2e0faSMaksim Panchenko     if (I.From.Offset == From && I.To.Offset == To && I.From.Name == I.To.Name)
211a34c753fSRafael Auler       return I;
212a34c753fSRafael Auler   }
213a34c753fSRafael Auler   return make_error_code(llvm::errc::invalid_argument);
214a34c753fSRafael Auler }
215a34c753fSRafael Auler 
216a34c753fSRafael Auler ErrorOr<const BranchInfo &>
217a34c753fSRafael Auler FuncBranchData::getDirectCallBranch(uint64_t From) const {
218a34c753fSRafael Auler   // Commented out because it can be expensive.
219a34c753fSRafael Auler   // assert(std::is_sorted(Data.begin(), Data.end()));
220a34c753fSRafael Auler   struct Compare {
221a34c753fSRafael Auler     bool operator()(const BranchInfo &BI, const uint64_t Val) const {
222a34c753fSRafael Auler       return BI.From.Offset < Val;
223a34c753fSRafael Auler     }
224a34c753fSRafael Auler     bool operator()(const uint64_t Val, const BranchInfo &BI) const {
225a34c753fSRafael Auler       return Val < BI.From.Offset;
226a34c753fSRafael Auler     }
227a34c753fSRafael Auler   };
228a34c753fSRafael Auler   auto Range = std::equal_range(Data.begin(), Data.end(), From, Compare());
229a34c753fSRafael Auler   for (auto I = Range.first; I != Range.second; ++I) {
230a34c753fSRafael Auler     if (I->From.Name != I->To.Name)
231a34c753fSRafael Auler       return *I;
232a34c753fSRafael Auler   }
233a34c753fSRafael Auler   return make_error_code(llvm::errc::invalid_argument);
234a34c753fSRafael Auler }
235a34c753fSRafael Auler 
236a34c753fSRafael Auler void MemInfo::print(raw_ostream &OS) const {
237a34c753fSRafael Auler   OS << (Offset.IsSymbol + 3) << " " << Offset.Name << " "
23840c2e0faSMaksim Panchenko      << Twine::utohexstr(Offset.Offset) << " " << (Addr.IsSymbol + 3) << " "
23940c2e0faSMaksim Panchenko      << Addr.Name << " " << Twine::utohexstr(Addr.Offset) << " " << Count
24040c2e0faSMaksim Panchenko      << "\n";
241a34c753fSRafael Auler }
242a34c753fSRafael Auler 
243a34c753fSRafael Auler void MemInfo::prettyPrint(raw_ostream &OS) const {
244a34c753fSRafael Auler   OS << "(PC: " << Offset << ", M: " << Addr << ", C: " << Count << ")";
245a34c753fSRafael Auler }
246a34c753fSRafael Auler 
247a34c753fSRafael Auler void FuncMemData::update(const Location &Offset, const Location &Addr) {
248a34c753fSRafael Auler   auto Iter = EventIndex[Offset.Offset].find(Addr);
249a34c753fSRafael Auler   if (Iter == EventIndex[Offset.Offset].end()) {
250a34c753fSRafael Auler     Data.emplace_back(MemInfo(Offset, Addr, 1));
251a34c753fSRafael Auler     EventIndex[Offset.Offset][Addr] = Data.size() - 1;
252a34c753fSRafael Auler     return;
253a34c753fSRafael Auler   }
254a34c753fSRafael Auler   ++Data[Iter->second].Count;
255a34c753fSRafael Auler }
256a34c753fSRafael Auler 
257a34c753fSRafael Auler Error DataReader::preprocessProfile(BinaryContext &BC) {
258a34c753fSRafael Auler   if (std::error_code EC = parseInput()) {
259a34c753fSRafael Auler     return errorCodeToError(EC);
260a34c753fSRafael Auler   }
261a34c753fSRafael Auler 
262a34c753fSRafael Auler   if (opts::DumpData) {
263a34c753fSRafael Auler     dump();
264a34c753fSRafael Auler   }
265a34c753fSRafael Auler 
266a34c753fSRafael Auler   if (collectedInBoltedBinary()) {
267a34c753fSRafael Auler     outs() << "BOLT-INFO: profile collection done on a binary already "
268a34c753fSRafael Auler               "processed by BOLT\n";
269a34c753fSRafael Auler   }
270a34c753fSRafael Auler 
271a34c753fSRafael Auler   for (auto &BFI : BC.getBinaryFunctions()) {
272a34c753fSRafael Auler     BinaryFunction &Function = BFI.second;
273a34c753fSRafael Auler     if (FuncMemData *MemData = getMemDataForNames(Function.getNames())) {
274a34c753fSRafael Auler       setMemData(Function, MemData);
275a34c753fSRafael Auler       MemData->Used = true;
276a34c753fSRafael Auler     }
277a34c753fSRafael Auler     if (FuncBranchData *FuncData = getBranchDataForNames(Function.getNames())) {
278a34c753fSRafael Auler       setBranchData(Function, FuncData);
279a34c753fSRafael Auler       Function.ExecutionCount = FuncData->ExecutionCount;
280a34c753fSRafael Auler       FuncData->Used = true;
281a34c753fSRafael Auler     }
282a34c753fSRafael Auler   }
283a34c753fSRafael Auler 
284a34c753fSRafael Auler   for (auto &BFI : BC.getBinaryFunctions()) {
285a34c753fSRafael Auler     BinaryFunction &Function = BFI.second;
286a34c753fSRafael Auler     matchProfileMemData(Function);
287a34c753fSRafael Auler   }
288a34c753fSRafael Auler 
289a34c753fSRafael Auler   return Error::success();
290a34c753fSRafael Auler }
291a34c753fSRafael Auler 
292a34c753fSRafael Auler Error DataReader::readProfilePreCFG(BinaryContext &BC) {
293a34c753fSRafael Auler   for (auto &BFI : BC.getBinaryFunctions()) {
294a34c753fSRafael Auler     BinaryFunction &Function = BFI.second;
295a34c753fSRafael Auler     FuncMemData *MemoryData = getMemData(Function);
296a34c753fSRafael Auler     if (!MemoryData)
297a34c753fSRafael Auler       continue;
298a34c753fSRafael Auler 
299a34c753fSRafael Auler     for (MemInfo &MI : MemoryData->Data) {
300a34c753fSRafael Auler       const uint64_t Offset = MI.Offset.Offset;
301a34c753fSRafael Auler       auto II = Function.Instructions.find(Offset);
302a34c753fSRafael Auler       if (II == Function.Instructions.end()) {
303a34c753fSRafael Auler         // Ignore bad instruction address.
304a34c753fSRafael Auler         continue;
305a34c753fSRafael Auler       }
306a34c753fSRafael Auler 
307a34c753fSRafael Auler       auto &MemAccessProfile =
308a34c753fSRafael Auler           BC.MIB->getOrCreateAnnotationAs<MemoryAccessProfile>(
309a34c753fSRafael Auler               II->second, "MemoryAccessProfile");
310a34c753fSRafael Auler       BinaryData *BD = nullptr;
311a34c753fSRafael Auler       if (MI.Addr.IsSymbol) {
312a34c753fSRafael Auler         BD = BC.getBinaryDataByName(MI.Addr.Name);
313a34c753fSRafael Auler       }
31440c2e0faSMaksim Panchenko       MemAccessProfile.AddressAccessInfo.push_back(
31540c2e0faSMaksim Panchenko           {BD, MI.Addr.Offset, MI.Count});
316a34c753fSRafael Auler       auto NextII = std::next(II);
317a34c753fSRafael Auler       if (NextII == Function.Instructions.end()) {
318a34c753fSRafael Auler         MemAccessProfile.NextInstrOffset = Function.getSize();
319a34c753fSRafael Auler       } else {
320a34c753fSRafael Auler         MemAccessProfile.NextInstrOffset = II->first;
321a34c753fSRafael Auler       }
322a34c753fSRafael Auler     }
323a34c753fSRafael Auler     Function.HasMemoryProfile = true;
324a34c753fSRafael Auler   }
325a34c753fSRafael Auler 
326a34c753fSRafael Auler   return Error::success();
327a34c753fSRafael Auler }
328a34c753fSRafael Auler 
329a34c753fSRafael Auler Error DataReader::readProfile(BinaryContext &BC) {
330a34c753fSRafael Auler   for (auto &BFI : BC.getBinaryFunctions()) {
331a34c753fSRafael Auler     BinaryFunction &Function = BFI.second;
332a34c753fSRafael Auler     readProfile(Function);
333a34c753fSRafael Auler   }
334a34c753fSRafael Auler 
335a34c753fSRafael Auler   uint64_t NumUnused = 0;
336a34c753fSRafael Auler   for (const StringMapEntry<FuncBranchData> &FuncData : NamesToBranches)
337a34c753fSRafael Auler     if (!FuncData.getValue().Used)
338a34c753fSRafael Auler       ++NumUnused;
339a34c753fSRafael Auler   BC.setNumUnusedProfiledObjects(NumUnused);
340a34c753fSRafael Auler 
341a34c753fSRafael Auler   return Error::success();
342a34c753fSRafael Auler }
343a34c753fSRafael Auler 
344a34c753fSRafael Auler std::error_code DataReader::parseInput() {
345a34c753fSRafael Auler   ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
346a34c753fSRafael Auler       MemoryBuffer::getFileOrSTDIN(Filename);
347a34c753fSRafael Auler   if (std::error_code EC = MB.getError()) {
348a34c753fSRafael Auler     Diag << "cannot open " << Filename << ": " << EC.message() << "\n";
349a34c753fSRafael Auler     return EC;
350a34c753fSRafael Auler   }
351a34c753fSRafael Auler   FileBuf = std::move(MB.get());
352a34c753fSRafael Auler   ParsingBuf = FileBuf->getBuffer();
353a34c753fSRafael Auler   if (std::error_code EC = parse()) {
354a34c753fSRafael Auler     return EC;
355a34c753fSRafael Auler   }
356a34c753fSRafael Auler   if (!ParsingBuf.empty()) {
357a34c753fSRafael Auler     Diag << "WARNING: invalid profile data detected at line " << Line
358a34c753fSRafael Auler          << ". Possibly corrupted profile.\n";
359a34c753fSRafael Auler   }
360a34c753fSRafael Auler 
361a34c753fSRafael Auler   buildLTONameMaps();
362a34c753fSRafael Auler 
363a34c753fSRafael Auler   return std::error_code();
364a34c753fSRafael Auler }
365a34c753fSRafael Auler 
366a34c753fSRafael Auler void DataReader::readProfile(BinaryFunction &BF) {
367a34c753fSRafael Auler   if (BF.empty())
368a34c753fSRafael Auler     return;
369a34c753fSRafael Auler 
370a34c753fSRafael Auler   if (!hasLBR()) {
371a34c753fSRafael Auler     BF.ProfileFlags = BinaryFunction::PF_SAMPLE;
372a34c753fSRafael Auler     readSampleData(BF);
373a34c753fSRafael Auler     return;
374a34c753fSRafael Auler   }
375a34c753fSRafael Auler 
376a34c753fSRafael Auler   BF.ProfileFlags = BinaryFunction::PF_LBR;
377a34c753fSRafael Auler 
378a34c753fSRafael Auler   // Possibly assign/re-assign branch profile data.
379a34c753fSRafael Auler   matchProfileData(BF);
380a34c753fSRafael Auler 
381a34c753fSRafael Auler   FuncBranchData *FBD = getBranchData(BF);
382a34c753fSRafael Auler   if (!FBD)
383a34c753fSRafael Auler     return;
384a34c753fSRafael Auler 
385a34c753fSRafael Auler   // Assign basic block counts to function entry points. These only include
386a34c753fSRafael Auler   // counts for outside entries.
387a34c753fSRafael Auler   //
388a34c753fSRafael Auler   // There is a slight skew introduced here as branches originated from RETs
389a34c753fSRafael Auler   // may be accounted for in the execution count of an entry block if the last
390a34c753fSRafael Auler   // instruction in a predecessor fall-through block is a call. This situation
391a34c753fSRafael Auler   // should rarely happen because there are few multiple-entry functions.
392a34c753fSRafael Auler   for (const BranchInfo &BI : FBD->EntryData) {
393a34c753fSRafael Auler     BinaryBasicBlock *BB = BF.getBasicBlockAtOffset(BI.To.Offset);
394a34c753fSRafael Auler     if (BB && (BB->isEntryPoint() || BB->isLandingPad())) {
395a34c753fSRafael Auler       uint64_t Count = BB->getExecutionCount();
396a34c753fSRafael Auler       if (Count == BinaryBasicBlock::COUNT_NO_PROFILE)
397a34c753fSRafael Auler         Count = 0;
398a34c753fSRafael Auler       BB->setExecutionCount(Count + BI.Branches);
399a34c753fSRafael Auler     }
400a34c753fSRafael Auler   }
401a34c753fSRafael Auler 
402a34c753fSRafael Auler   uint64_t MismatchedBranches = 0;
403a34c753fSRafael Auler   for (const BranchInfo &BI : FBD->Data) {
404a34c753fSRafael Auler     if (BI.From.Name != BI.To.Name) {
405a34c753fSRafael Auler       continue;
406a34c753fSRafael Auler     }
407a34c753fSRafael Auler 
40840c2e0faSMaksim Panchenko     if (!recordBranch(BF, BI.From.Offset, BI.To.Offset, BI.Branches,
40940c2e0faSMaksim Panchenko                       BI.Mispreds)) {
410a34c753fSRafael Auler       LLVM_DEBUG(dbgs() << "bad branch : " << BI.From.Offset << " -> "
411a34c753fSRafael Auler                         << BI.To.Offset << '\n');
412a34c753fSRafael Auler       ++MismatchedBranches;
413a34c753fSRafael Auler     }
414a34c753fSRafael Auler   }
415a34c753fSRafael Auler 
416a34c753fSRafael Auler   // Convert branch data into annotations.
417a34c753fSRafael Auler   convertBranchData(BF);
418a34c753fSRafael Auler }
419a34c753fSRafael Auler 
420a34c753fSRafael Auler void DataReader::matchProfileData(BinaryFunction &BF) {
421a34c753fSRafael Auler   // This functionality is available for LBR-mode only
422a34c753fSRafael Auler   // TODO: Implement evaluateProfileData() for samples, checking whether
423a34c753fSRafael Auler   // sample addresses match instruction addresses in the function
424a34c753fSRafael Auler   if (!hasLBR())
425a34c753fSRafael Auler     return;
426a34c753fSRafael Auler 
427a34c753fSRafael Auler   FuncBranchData *FBD = getBranchData(BF);
428a34c753fSRafael Auler   if (FBD) {
429a34c753fSRafael Auler     BF.ProfileMatchRatio = evaluateProfileData(BF, *FBD);
430a34c753fSRafael Auler     BF.RawBranchCount = FBD->getNumExecutedBranches();
431a34c753fSRafael Auler     if (BF.ProfileMatchRatio == 1.0f) {
432a34c753fSRafael Auler       if (fetchProfileForOtherEntryPoints(BF)) {
433a34c753fSRafael Auler         BF.ProfileMatchRatio = evaluateProfileData(BF, *FBD);
434a34c753fSRafael Auler         BF.ExecutionCount = FBD->ExecutionCount;
435a34c753fSRafael Auler         BF.RawBranchCount = FBD->getNumExecutedBranches();
436a34c753fSRafael Auler       }
437a34c753fSRafael Auler       return;
438a34c753fSRafael Auler     }
439a34c753fSRafael Auler   }
440a34c753fSRafael Auler 
441a34c753fSRafael Auler   // Check if the function name can fluctuate between several compilations
442a34c753fSRafael Auler   // possibly triggered by minor unrelated code changes in the source code
443a34c753fSRafael Auler   // of the input binary.
444a34c753fSRafael Auler   if (!hasVolatileName(BF))
445a34c753fSRafael Auler     return;
446a34c753fSRafael Auler 
447a34c753fSRafael Auler   // Check for a profile that matches with 100% confidence.
448a34c753fSRafael Auler   const std::vector<FuncBranchData *> AllBranchData =
449a34c753fSRafael Auler       getBranchDataForNamesRegex(BF.getNames());
450a34c753fSRafael Auler   for (FuncBranchData *NewBranchData : AllBranchData) {
451a34c753fSRafael Auler     // Prevent functions from sharing the same profile.
452a34c753fSRafael Auler     if (NewBranchData->Used)
453a34c753fSRafael Auler       continue;
454a34c753fSRafael Auler 
455a34c753fSRafael Auler     if (evaluateProfileData(BF, *NewBranchData) != 1.0f)
456a34c753fSRafael Auler       continue;
457a34c753fSRafael Auler 
458a34c753fSRafael Auler     if (FBD)
459a34c753fSRafael Auler       FBD->Used = false;
460a34c753fSRafael Auler 
461a34c753fSRafael Auler     // Update function profile data with the new set.
462a34c753fSRafael Auler     setBranchData(BF, NewBranchData);
463a34c753fSRafael Auler     NewBranchData->Used = true;
464a34c753fSRafael Auler     BF.ExecutionCount = NewBranchData->ExecutionCount;
465a34c753fSRafael Auler     BF.ProfileMatchRatio = 1.0f;
466a34c753fSRafael Auler     break;
467a34c753fSRafael Auler   }
468a34c753fSRafael Auler }
469a34c753fSRafael Auler 
470a34c753fSRafael Auler void DataReader::matchProfileMemData(BinaryFunction &BF) {
471a34c753fSRafael Auler   const std::vector<FuncMemData *> AllMemData =
472a34c753fSRafael Auler       getMemDataForNamesRegex(BF.getNames());
473a34c753fSRafael Auler   for (FuncMemData *NewMemData : AllMemData) {
474a34c753fSRafael Auler     // Prevent functions from sharing the same profile.
475a34c753fSRafael Auler     if (NewMemData->Used)
476a34c753fSRafael Auler       continue;
477a34c753fSRafael Auler 
478a34c753fSRafael Auler     if (FuncMemData *MD = getMemData(BF))
479a34c753fSRafael Auler       MD->Used = false;
480a34c753fSRafael Auler 
481a34c753fSRafael Auler     // Update function profile data with the new set.
482a34c753fSRafael Auler     setMemData(BF, NewMemData);
483a34c753fSRafael Auler     NewMemData->Used = true;
484a34c753fSRafael Auler     break;
485a34c753fSRafael Auler   }
486a34c753fSRafael Auler }
487a34c753fSRafael Auler 
488a34c753fSRafael Auler bool DataReader::fetchProfileForOtherEntryPoints(BinaryFunction &BF) {
489a34c753fSRafael Auler   BinaryContext &BC = BF.getBinaryContext();
490a34c753fSRafael Auler 
491a34c753fSRafael Auler   FuncBranchData *FBD = getBranchData(BF);
492a34c753fSRafael Auler   if (!FBD)
493a34c753fSRafael Auler     return false;
494a34c753fSRafael Auler 
495a34c753fSRafael Auler   // Check if we are missing profiling data for secondary entry points
496a34c753fSRafael Auler   bool First = true;
497a34c753fSRafael Auler   bool Updated = false;
498a34c753fSRafael Auler   for (BinaryBasicBlock *BB : BF.BasicBlocks) {
499a34c753fSRafael Auler     if (First) {
500a34c753fSRafael Auler       First = false;
501a34c753fSRafael Auler       continue;
502a34c753fSRafael Auler     }
503a34c753fSRafael Auler     if (BB->isEntryPoint()) {
504a34c753fSRafael Auler       uint64_t EntryAddress = BB->getOffset() + BF.getAddress();
505a34c753fSRafael Auler       // Look for branch data associated with this entry point
506a34c753fSRafael Auler       if (BinaryData *BD = BC.getBinaryDataAtAddress(EntryAddress)) {
507a34c753fSRafael Auler         if (FuncBranchData *Data = getBranchDataForSymbols(BD->getSymbols())) {
508a34c753fSRafael Auler           FBD->appendFrom(*Data, BB->getOffset());
509a34c753fSRafael Auler           Data->Used = true;
510a34c753fSRafael Auler           Updated = true;
511a34c753fSRafael Auler         }
512a34c753fSRafael Auler       }
513a34c753fSRafael Auler     }
514a34c753fSRafael Auler   }
515a34c753fSRafael Auler 
516a34c753fSRafael Auler   return Updated;
517a34c753fSRafael Auler }
518a34c753fSRafael Auler 
519a34c753fSRafael Auler float DataReader::evaluateProfileData(BinaryFunction &BF,
520a34c753fSRafael Auler                                       const FuncBranchData &BranchData) const {
521a34c753fSRafael Auler   BinaryContext &BC = BF.getBinaryContext();
522a34c753fSRafael Auler 
523a34c753fSRafael Auler   // Until we define a minimal profile, we consider an empty branch data to be
524a34c753fSRafael Auler   // a valid profile. It could happen to a function without branches when we
525a34c753fSRafael Auler   // still have an EntryData for the execution count.
526a34c753fSRafael Auler   if (BranchData.Data.empty()) {
527a34c753fSRafael Auler     return 1.0f;
528a34c753fSRafael Auler   }
529a34c753fSRafael Auler 
530a34c753fSRafael Auler   uint64_t NumMatchedBranches = 0;
531a34c753fSRafael Auler   for (const BranchInfo &BI : BranchData.Data) {
532a34c753fSRafael Auler     bool IsValid = false;
533a34c753fSRafael Auler     if (BI.From.Name == BI.To.Name) {
534a34c753fSRafael Auler       // Try to record information with 0 count.
535a34c753fSRafael Auler       IsValid = recordBranch(BF, BI.From.Offset, BI.To.Offset, 0);
536a34c753fSRafael Auler     } else if (collectedInBoltedBinary()) {
537a34c753fSRafael Auler       // We can't check branch source for collections in bolted binaries because
538a34c753fSRafael Auler       // the source of the branch may be mapped to the first instruction in a BB
539a34c753fSRafael Auler       // instead of the original branch (which may not exist in the source bin).
540a34c753fSRafael Auler       IsValid = true;
541a34c753fSRafael Auler     } else {
542a34c753fSRafael Auler       // The branch has to originate from this function.
543a34c753fSRafael Auler       // Check for calls, tail calls, rets and indirect branches.
544a34c753fSRafael Auler       // When matching profiling info, we did not reach the stage
545a34c753fSRafael Auler       // when we identify tail calls, so they are still represented
546a34c753fSRafael Auler       // by regular branch instructions and we need isBranch() here.
547a34c753fSRafael Auler       MCInst *Instr = BF.getInstructionAtOffset(BI.From.Offset);
548a34c753fSRafael Auler       // If it's a prefix - skip it.
549a34c753fSRafael Auler       if (Instr && BC.MIB->isPrefix(*Instr))
550a34c753fSRafael Auler         Instr = BF.getInstructionAtOffset(BI.From.Offset + 1);
55140c2e0faSMaksim Panchenko       if (Instr && (BC.MIB->isCall(*Instr) || BC.MIB->isBranch(*Instr) ||
552a34c753fSRafael Auler                     BC.MIB->isReturn(*Instr))) {
553a34c753fSRafael Auler         IsValid = true;
554a34c753fSRafael Auler       }
555a34c753fSRafael Auler     }
556a34c753fSRafael Auler 
557a34c753fSRafael Auler     if (IsValid) {
558a34c753fSRafael Auler       ++NumMatchedBranches;
559a34c753fSRafael Auler       continue;
560a34c753fSRafael Auler     }
561a34c753fSRafael Auler 
562a34c753fSRafael Auler     LLVM_DEBUG(dbgs() << "\tinvalid branch in " << BF << " : 0x"
563a34c753fSRafael Auler                       << Twine::utohexstr(BI.From.Offset) << " -> ";
564a34c753fSRafael Auler                if (BI.From.Name == BI.To.Name) dbgs()
565a34c753fSRafael Auler                << "0x" << Twine::utohexstr(BI.To.Offset) << '\n';
566a34c753fSRafael Auler                else dbgs() << "<outbounds>\n";);
567a34c753fSRafael Auler   }
568a34c753fSRafael Auler 
569a34c753fSRafael Auler   const float MatchRatio = (float)NumMatchedBranches / BranchData.Data.size();
570a34c753fSRafael Auler   if (opts::Verbosity >= 2 && NumMatchedBranches < BranchData.Data.size()) {
571a34c753fSRafael Auler     errs() << "BOLT-WARNING: profile branches match only "
572a34c753fSRafael Auler            << format("%.1f%%", MatchRatio * 100.0f) << " ("
573a34c753fSRafael Auler            << NumMatchedBranches << '/' << BranchData.Data.size()
574a34c753fSRafael Auler            << ") for function " << BF << '\n';
575a34c753fSRafael Auler   }
576a34c753fSRafael Auler 
577a34c753fSRafael Auler   return MatchRatio;
578a34c753fSRafael Auler }
579a34c753fSRafael Auler 
580a34c753fSRafael Auler void DataReader::readSampleData(BinaryFunction &BF) {
581a34c753fSRafael Auler   FuncSampleData *SampleDataOrErr = getFuncSampleData(BF.getNames());
582a34c753fSRafael Auler   if (!SampleDataOrErr)
583a34c753fSRafael Auler     return;
584a34c753fSRafael Auler 
585a34c753fSRafael Auler   // Basic samples mode territory (without LBR info)
586a34c753fSRafael Auler   // First step is to assign BB execution count based on samples from perf
587a34c753fSRafael Auler   BF.ProfileMatchRatio = 1.0f;
588a34c753fSRafael Auler   BF.removeTagsFromProfile();
589a34c753fSRafael Auler   bool NormalizeByInsnCount = usesEvent("cycles") || usesEvent("instructions");
590a34c753fSRafael Auler   bool NormalizeByCalls = usesEvent("branches");
591a34c753fSRafael Auler   static bool NagUser = true;
592a34c753fSRafael Auler   if (NagUser) {
593a34c753fSRafael Auler     outs()
594a34c753fSRafael Auler         << "BOLT-INFO: operating with basic samples profiling data (no LBR).\n";
595a34c753fSRafael Auler     if (NormalizeByInsnCount) {
596a34c753fSRafael Auler       outs() << "BOLT-INFO: normalizing samples by instruction count.\n";
597a34c753fSRafael Auler     } else if (NormalizeByCalls) {
598a34c753fSRafael Auler       outs() << "BOLT-INFO: normalizing samples by branches.\n";
599a34c753fSRafael Auler     }
600a34c753fSRafael Auler     NagUser = false;
601a34c753fSRafael Auler   }
602a34c753fSRafael Auler   uint64_t LastOffset = BF.getSize();
603a34c753fSRafael Auler   uint64_t TotalEntryCount = 0;
604a34c753fSRafael Auler   for (auto I = BF.BasicBlockOffsets.rbegin(), E = BF.BasicBlockOffsets.rend();
605a34c753fSRafael Auler        I != E; ++I) {
606a34c753fSRafael Auler     uint64_t CurOffset = I->first;
607a34c753fSRafael Auler     // Always work with samples multiplied by 1000 to avoid losing them if we
608a34c753fSRafael Auler     // later need to normalize numbers
609a34c753fSRafael Auler     uint64_t NumSamples =
610a34c753fSRafael Auler         SampleDataOrErr->getSamples(CurOffset, LastOffset) * 1000;
611a34c753fSRafael Auler     if (NormalizeByInsnCount && I->second->getNumNonPseudos())
612a34c753fSRafael Auler       NumSamples /= I->second->getNumNonPseudos();
613a34c753fSRafael Auler     else if (NormalizeByCalls) {
614a34c753fSRafael Auler       uint32_t NumCalls = I->second->getNumCalls();
615a34c753fSRafael Auler       NumSamples /= NumCalls + 1;
616a34c753fSRafael Auler     }
617a34c753fSRafael Auler     I->second->setExecutionCount(NumSamples);
618a34c753fSRafael Auler     if (I->second->isEntryPoint())
619a34c753fSRafael Auler       TotalEntryCount += NumSamples;
620a34c753fSRafael Auler     LastOffset = CurOffset;
621a34c753fSRafael Auler   }
622a34c753fSRafael Auler 
623a34c753fSRafael Auler   BF.ExecutionCount = TotalEntryCount;
624a34c753fSRafael Auler 
625a34c753fSRafael Auler   estimateEdgeCounts(BF);
626a34c753fSRafael Auler }
627a34c753fSRafael Auler 
628a34c753fSRafael Auler void DataReader::convertBranchData(BinaryFunction &BF) const {
629a34c753fSRafael Auler   BinaryContext &BC = BF.getBinaryContext();
630a34c753fSRafael Auler 
631a34c753fSRafael Auler   if (BF.empty())
632a34c753fSRafael Auler     return;
633a34c753fSRafael Auler 
634a34c753fSRafael Auler   FuncBranchData *FBD = getBranchData(BF);
635a34c753fSRafael Auler   if (!FBD)
636a34c753fSRafael Auler     return;
637a34c753fSRafael Auler 
638a34c753fSRafael Auler   // Profile information for calls.
639a34c753fSRafael Auler   //
640a34c753fSRafael Auler   // There are 3 cases that we annotate differently:
641a34c753fSRafael Auler   //   1) Conditional tail calls that could be mispredicted.
642a34c753fSRafael Auler   //   2) Indirect calls to multiple destinations with mispredictions.
643a34c753fSRafael Auler   //      Before we validate CFG we have to handle indirect branches here too.
644a34c753fSRafael Auler   //   3) Regular direct calls. The count could be different from containing
645a34c753fSRafael Auler   //      basic block count. Keep this data in case we find it useful.
646a34c753fSRafael Auler   //
647a34c753fSRafael Auler   for (BranchInfo &BI : FBD->Data) {
648a34c753fSRafael Auler     // Ignore internal branches.
649a34c753fSRafael Auler     if (BI.To.IsSymbol && BI.To.Name == BI.From.Name && BI.To.Offset != 0)
650a34c753fSRafael Auler       continue;
651a34c753fSRafael Auler 
652a34c753fSRafael Auler     MCInst *Instr = BF.getInstructionAtOffset(BI.From.Offset);
653a34c753fSRafael Auler     if (!Instr ||
654a34c753fSRafael Auler         (!BC.MIB->isCall(*Instr) && !BC.MIB->isIndirectBranch(*Instr)))
655a34c753fSRafael Auler       continue;
656a34c753fSRafael Auler 
657a34c753fSRafael Auler     auto setOrUpdateAnnotation = [&](StringRef Name, uint64_t Count) {
658a34c753fSRafael Auler       if (opts::Verbosity >= 1 && BC.MIB->hasAnnotation(*Instr, Name)) {
659a34c753fSRafael Auler         errs() << "BOLT-WARNING: duplicate " << Name << " info for offset 0x"
66040c2e0faSMaksim Panchenko                << Twine::utohexstr(BI.From.Offset) << " in function " << BF
66140c2e0faSMaksim Panchenko                << '\n';
662a34c753fSRafael Auler       }
663a34c753fSRafael Auler       auto &Value = BC.MIB->getOrCreateAnnotationAs<uint64_t>(*Instr, Name);
664a34c753fSRafael Auler       Value += Count;
665a34c753fSRafael Auler     };
666a34c753fSRafael Auler 
667a34c753fSRafael Auler     if (BC.MIB->isIndirectCall(*Instr) || BC.MIB->isIndirectBranch(*Instr)) {
668a34c753fSRafael Auler       IndirectCallSiteProfile &CSP =
669a34c753fSRafael Auler           BC.MIB->getOrCreateAnnotationAs<IndirectCallSiteProfile>(
670a34c753fSRafael Auler               *Instr, "CallProfile");
671a34c753fSRafael Auler       MCSymbol *CalleeSymbol = nullptr;
672a34c753fSRafael Auler       if (BI.To.IsSymbol) {
673a34c753fSRafael Auler         if (BinaryData *BD = BC.getBinaryDataByName(BI.To.Name)) {
674a34c753fSRafael Auler           CalleeSymbol = BD->getSymbol();
675a34c753fSRafael Auler         }
676a34c753fSRafael Auler       }
677a34c753fSRafael Auler       CSP.emplace_back(CalleeSymbol, BI.Branches, BI.Mispreds);
678a34c753fSRafael Auler     } else if (BC.MIB->getConditionalTailCall(*Instr)) {
679a34c753fSRafael Auler       setOrUpdateAnnotation("CTCTakenCount", BI.Branches);
680a34c753fSRafael Auler       setOrUpdateAnnotation("CTCMispredCount", BI.Mispreds);
681a34c753fSRafael Auler     } else {
682a34c753fSRafael Auler       setOrUpdateAnnotation("Count", BI.Branches);
683a34c753fSRafael Auler     }
684a34c753fSRafael Auler   }
685a34c753fSRafael Auler }
686a34c753fSRafael Auler 
68740c2e0faSMaksim Panchenko bool DataReader::recordBranch(BinaryFunction &BF, uint64_t From, uint64_t To,
688a34c753fSRafael Auler                               uint64_t Count, uint64_t Mispreds) const {
689a34c753fSRafael Auler   BinaryContext &BC = BF.getBinaryContext();
690a34c753fSRafael Auler 
691a34c753fSRafael Auler   BinaryBasicBlock *FromBB = BF.getBasicBlockContainingOffset(From);
692a34c753fSRafael Auler   BinaryBasicBlock *ToBB = BF.getBasicBlockContainingOffset(To);
693a34c753fSRafael Auler 
694a34c753fSRafael Auler   if (!FromBB || !ToBB) {
695a34c753fSRafael Auler     LLVM_DEBUG(dbgs() << "failed to get block for recorded branch\n");
696a34c753fSRafael Auler     return false;
697a34c753fSRafael Auler   }
698a34c753fSRafael Auler 
699a34c753fSRafael Auler   // Could be bad LBR data; ignore the branch. In the case of data collected
700a34c753fSRafael Auler   // in binaries optimized by BOLT, a source BB may be mapped to two output
701a34c753fSRafael Auler   // BBs as a result of optimizations. In that case, a branch between these
702a34c753fSRafael Auler   // two will be recorded as a branch from A going to A in the source address
703a34c753fSRafael Auler   // space. Keep processing.
704a34c753fSRafael Auler   if (From == To) {
705a34c753fSRafael Auler     return true;
706a34c753fSRafael Auler   }
707a34c753fSRafael Auler 
708a34c753fSRafael Auler   // Return from a tail call.
709ccb99dd1SMaksim Panchenko   if (FromBB->succ_size() == 0)
710a34c753fSRafael Auler     return true;
711a34c753fSRafael Auler 
712a34c753fSRafael Auler   // Very rarely we will see ignored branches. Do a linear check.
713a34c753fSRafael Auler   for (std::pair<uint32_t, uint32_t> &Branch : BF.IgnoredBranches) {
71440c2e0faSMaksim Panchenko     if (Branch ==
71540c2e0faSMaksim Panchenko         std::make_pair(static_cast<uint32_t>(From), static_cast<uint32_t>(To)))
716a34c753fSRafael Auler       return true;
717a34c753fSRafael Auler   }
718a34c753fSRafael Auler 
71908f56926SVladislav Khmelevsky   bool OffsetMatches = !!(To == ToBB->getOffset());
72008f56926SVladislav Khmelevsky   if (!OffsetMatches) {
72108f56926SVladislav Khmelevsky     // Skip the nops to support old .fdata
72208f56926SVladislav Khmelevsky     uint64_t Offset = ToBB->getOffset();
72308f56926SVladislav Khmelevsky     for (MCInst &Instr : *ToBB) {
72408f56926SVladislav Khmelevsky       if (!BC.MIB->isNoop(Instr))
72508f56926SVladislav Khmelevsky         break;
72608f56926SVladislav Khmelevsky 
72708f56926SVladislav Khmelevsky       Offset += BC.MIB->getAnnotationWithDefault<uint32_t>(Instr, "Size");
72808f56926SVladislav Khmelevsky     }
72908f56926SVladislav Khmelevsky 
73008f56926SVladislav Khmelevsky     if (To == Offset)
73108f56926SVladislav Khmelevsky       OffsetMatches = true;
73208f56926SVladislav Khmelevsky   }
73308f56926SVladislav Khmelevsky 
73408f56926SVladislav Khmelevsky   if (!OffsetMatches) {
735a34c753fSRafael Auler     // "To" could be referring to nop instructions in between 2 basic blocks.
736a34c753fSRafael Auler     // While building the CFG we make sure these nops are attributed to the
737a34c753fSRafael Auler     // previous basic block, thus we check if the destination belongs to the
738a34c753fSRafael Auler     // gap past the last instruction.
739a34c753fSRafael Auler     const MCInst *LastInstr = ToBB->getLastNonPseudoInstr();
740a34c753fSRafael Auler     if (LastInstr) {
741a34c753fSRafael Auler       const uint32_t LastInstrOffset =
742a34c753fSRafael Auler           BC.MIB->getAnnotationWithDefault<uint32_t>(*LastInstr, "Offset");
743a34c753fSRafael Auler 
744a34c753fSRafael Auler       // With old .fdata we are getting FT branches for "jcc,jmp" sequences.
745a34c753fSRafael Auler       if (To == LastInstrOffset && BC.MIB->isUnconditionalBranch(*LastInstr)) {
746a34c753fSRafael Auler         return true;
747a34c753fSRafael Auler       }
748a34c753fSRafael Auler 
749a34c753fSRafael Auler       if (To <= LastInstrOffset) {
750a34c753fSRafael Auler         LLVM_DEBUG(dbgs() << "branch recorded into the middle of the block"
751a34c753fSRafael Auler                           << " in " << BF << " : " << From << " -> " << To
752a34c753fSRafael Auler                           << '\n');
753a34c753fSRafael Auler         return false;
754a34c753fSRafael Auler       }
755a34c753fSRafael Auler     }
756a34c753fSRafael Auler 
757a34c753fSRafael Auler     // The real destination is the layout successor of the detected ToBB.
758a34c753fSRafael Auler     if (ToBB == BF.BasicBlocksLayout.back())
759a34c753fSRafael Auler       return false;
760a34c753fSRafael Auler     BinaryBasicBlock *NextBB = BF.BasicBlocksLayout[ToBB->getIndex() + 1];
761a34c753fSRafael Auler     assert((NextBB && NextBB->getOffset() > ToBB->getOffset()) && "bad layout");
762a34c753fSRafael Auler     ToBB = NextBB;
763a34c753fSRafael Auler   }
764a34c753fSRafael Auler 
765a34c753fSRafael Auler   // If there's no corresponding instruction for 'From', we have probably
766a34c753fSRafael Auler   // discarded it as a FT from __builtin_unreachable.
767a34c753fSRafael Auler   MCInst *FromInstruction = BF.getInstructionAtOffset(From);
768a34c753fSRafael Auler   if (!FromInstruction) {
769a34c753fSRafael Auler     // If the data was collected in a bolted binary, the From addresses may be
770a34c753fSRafael Auler     // translated to the first instruction of the source BB if BOLT inserted
771a34c753fSRafael Auler     // a new branch that did not exist in the source (we can't map it to the
772a34c753fSRafael Auler     // source instruction, so we map it to the first instr of source BB).
773a34c753fSRafael Auler     // We do not keep offsets for random instructions. So the check above will
774a34c753fSRafael Auler     // evaluate to true if the first instr is not a branch (call/jmp/ret/etc)
775a34c753fSRafael Auler     if (collectedInBoltedBinary()) {
776a34c753fSRafael Auler       if (FromBB->getInputOffset() != From) {
777a34c753fSRafael Auler         LLVM_DEBUG(dbgs() << "offset " << From << " does not match a BB in "
778a34c753fSRafael Auler                           << BF << '\n');
779a34c753fSRafael Auler         return false;
780a34c753fSRafael Auler       }
781a34c753fSRafael Auler       FromInstruction = nullptr;
782a34c753fSRafael Auler     } else {
783a34c753fSRafael Auler       LLVM_DEBUG(dbgs() << "no instruction for offset " << From << " in " << BF
784a34c753fSRafael Auler                         << '\n');
785a34c753fSRafael Auler       return false;
786a34c753fSRafael Auler     }
787a34c753fSRafael Auler   }
788a34c753fSRafael Auler 
789a34c753fSRafael Auler   if (!FromBB->getSuccessor(ToBB->getLabel())) {
790a34c753fSRafael Auler     // Check if this is a recursive call or a return from a recursive call.
791a34c753fSRafael Auler     if (FromInstruction && ToBB->isEntryPoint() &&
792a34c753fSRafael Auler         (BC.MIB->isCall(*FromInstruction) ||
793a34c753fSRafael Auler          BC.MIB->isIndirectBranch(*FromInstruction))) {
794a34c753fSRafael Auler       // Execution count is already accounted for.
795a34c753fSRafael Auler       return true;
796a34c753fSRafael Auler     }
797a34c753fSRafael Auler     // For data collected in a bolted binary, we may have created two output BBs
798a34c753fSRafael Auler     // that map to one original block. Branches between these two blocks will
79940c2e0faSMaksim Panchenko     // appear here as one BB jumping to itself, even though it has no loop
80040c2e0faSMaksim Panchenko     // edges. Ignore these.
801a34c753fSRafael Auler     if (collectedInBoltedBinary() && FromBB == ToBB)
802a34c753fSRafael Auler       return true;
803a34c753fSRafael Auler 
804ccb99dd1SMaksim Panchenko     BinaryBasicBlock *FTSuccessor = FromBB->getConditionalSuccessor(false);
805ccb99dd1SMaksim Panchenko     if (FTSuccessor && FTSuccessor->succ_size() == 1 &&
806ccb99dd1SMaksim Panchenko         FTSuccessor->getSuccessor(ToBB->getLabel())) {
807ccb99dd1SMaksim Panchenko       BinaryBasicBlock::BinaryBranchInfo &FTBI =
808ccb99dd1SMaksim Panchenko           FTSuccessor->getBranchInfo(*ToBB);
809ccb99dd1SMaksim Panchenko       FTBI.Count += Count;
810ccb99dd1SMaksim Panchenko       if (Count)
811ccb99dd1SMaksim Panchenko         FTBI.MispredictedCount += Mispreds;
812ccb99dd1SMaksim Panchenko       ToBB = FTSuccessor;
813ccb99dd1SMaksim Panchenko     } else {
814a34c753fSRafael Auler       LLVM_DEBUG(dbgs() << "invalid branch in " << BF << '\n'
815a34c753fSRafael Auler                         << Twine::utohexstr(From) << " -> "
816a34c753fSRafael Auler                         << Twine::utohexstr(To) << '\n');
817a34c753fSRafael Auler       return false;
818a34c753fSRafael Auler     }
819ccb99dd1SMaksim Panchenko   }
820a34c753fSRafael Auler 
821a34c753fSRafael Auler   BinaryBasicBlock::BinaryBranchInfo &BI = FromBB->getBranchInfo(*ToBB);
822a34c753fSRafael Auler   BI.Count += Count;
823a34c753fSRafael Auler   // Only update mispredicted count if it the count was real.
824a34c753fSRafael Auler   if (Count) {
825a34c753fSRafael Auler     BI.MispredictedCount += Mispreds;
826a34c753fSRafael Auler   }
827a34c753fSRafael Auler 
828a34c753fSRafael Auler   return true;
829a34c753fSRafael Auler }
830a34c753fSRafael Auler 
831a34c753fSRafael Auler void DataReader::reportError(StringRef ErrorMsg) {
832a34c753fSRafael Auler   Diag << "Error reading BOLT data input file: line " << Line << ", column "
833a34c753fSRafael Auler        << Col << ": " << ErrorMsg << '\n';
834a34c753fSRafael Auler }
835a34c753fSRafael Auler 
836a34c753fSRafael Auler bool DataReader::expectAndConsumeFS() {
837a34c753fSRafael Auler   if (ParsingBuf[0] != FieldSeparator) {
838a34c753fSRafael Auler     reportError("expected field separator");
839a34c753fSRafael Auler     return false;
840a34c753fSRafael Auler   }
841a34c753fSRafael Auler   ParsingBuf = ParsingBuf.drop_front(1);
842a34c753fSRafael Auler   Col += 1;
843a34c753fSRafael Auler   return true;
844a34c753fSRafael Auler }
845a34c753fSRafael Auler 
846a34c753fSRafael Auler void DataReader::consumeAllRemainingFS() {
847a34c753fSRafael Auler   while (ParsingBuf[0] == FieldSeparator) {
848a34c753fSRafael Auler     ParsingBuf = ParsingBuf.drop_front(1);
849a34c753fSRafael Auler     Col += 1;
850a34c753fSRafael Auler   }
851a34c753fSRafael Auler }
852a34c753fSRafael Auler 
853a34c753fSRafael Auler bool DataReader::checkAndConsumeNewLine() {
854a34c753fSRafael Auler   if (ParsingBuf[0] != '\n')
855a34c753fSRafael Auler     return false;
856a34c753fSRafael Auler 
857a34c753fSRafael Auler   ParsingBuf = ParsingBuf.drop_front(1);
858a34c753fSRafael Auler   Col = 0;
859a34c753fSRafael Auler   Line += 1;
860a34c753fSRafael Auler   return true;
861a34c753fSRafael Auler }
862a34c753fSRafael Auler 
863a34c753fSRafael Auler ErrorOr<StringRef> DataReader::parseString(char EndChar, bool EndNl) {
864a34c753fSRafael Auler   if (EndChar == '\\') {
865a34c753fSRafael Auler     reportError("EndChar could not be backslash");
866a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
867a34c753fSRafael Auler   }
868a34c753fSRafael Auler 
869a34c753fSRafael Auler   std::string EndChars(1, EndChar);
870a34c753fSRafael Auler   EndChars.push_back('\\');
871a34c753fSRafael Auler   if (EndNl)
872a34c753fSRafael Auler     EndChars.push_back('\n');
873a34c753fSRafael Auler 
874a34c753fSRafael Auler   size_t StringEnd = 0;
875a34c753fSRafael Auler   do {
876a34c753fSRafael Auler     StringEnd = ParsingBuf.find_first_of(EndChars, StringEnd);
877a34c753fSRafael Auler     if (StringEnd == StringRef::npos ||
878a34c753fSRafael Auler         (StringEnd == 0 && ParsingBuf[StringEnd] != '\\')) {
879a34c753fSRafael Auler       reportError("malformed field");
880a34c753fSRafael Auler       return make_error_code(llvm::errc::io_error);
881a34c753fSRafael Auler     }
882a34c753fSRafael Auler 
883a34c753fSRafael Auler     if (ParsingBuf[StringEnd] != '\\')
884a34c753fSRafael Auler       break;
885a34c753fSRafael Auler 
886a34c753fSRafael Auler     StringEnd += 2;
887a34c753fSRafael Auler   } while (1);
888a34c753fSRafael Auler 
889a34c753fSRafael Auler   StringRef Str = ParsingBuf.substr(0, StringEnd);
890a34c753fSRafael Auler 
891a34c753fSRafael Auler   // If EndNl was set and nl was found instead of EndChar, do not consume the
892a34c753fSRafael Auler   // new line.
89340c2e0faSMaksim Panchenko   bool EndNlInsteadOfEndChar = ParsingBuf[StringEnd] == '\n' && EndChar != '\n';
894a34c753fSRafael Auler   unsigned End = EndNlInsteadOfEndChar ? StringEnd : StringEnd + 1;
895a34c753fSRafael Auler 
896a34c753fSRafael Auler   ParsingBuf = ParsingBuf.drop_front(End);
897a34c753fSRafael Auler   if (EndChar == '\n') {
898a34c753fSRafael Auler     Col = 0;
899a34c753fSRafael Auler     Line += 1;
900a34c753fSRafael Auler   } else {
901a34c753fSRafael Auler     Col += End;
902a34c753fSRafael Auler   }
903a34c753fSRafael Auler   return Str;
904a34c753fSRafael Auler }
905a34c753fSRafael Auler 
906a34c753fSRafael Auler ErrorOr<int64_t> DataReader::parseNumberField(char EndChar, bool EndNl) {
907a34c753fSRafael Auler   ErrorOr<StringRef> NumStrRes = parseString(EndChar, EndNl);
908a34c753fSRafael Auler   if (std::error_code EC = NumStrRes.getError())
909a34c753fSRafael Auler     return EC;
910a34c753fSRafael Auler   StringRef NumStr = NumStrRes.get();
911a34c753fSRafael Auler   int64_t Num;
912a34c753fSRafael Auler   if (NumStr.getAsInteger(10, Num)) {
913a34c753fSRafael Auler     reportError("expected decimal number");
914a34c753fSRafael Auler     Diag << "Found: " << NumStr << "\n";
915a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
916a34c753fSRafael Auler   }
917a34c753fSRafael Auler   return Num;
918a34c753fSRafael Auler }
919a34c753fSRafael Auler 
920a34c753fSRafael Auler ErrorOr<uint64_t> DataReader::parseHexField(char EndChar, bool EndNl) {
921a34c753fSRafael Auler   ErrorOr<StringRef> NumStrRes = parseString(EndChar, EndNl);
922a34c753fSRafael Auler   if (std::error_code EC = NumStrRes.getError())
923a34c753fSRafael Auler     return EC;
924a34c753fSRafael Auler   StringRef NumStr = NumStrRes.get();
925a34c753fSRafael Auler   uint64_t Num;
926a34c753fSRafael Auler   if (NumStr.getAsInteger(16, Num)) {
927a34c753fSRafael Auler     reportError("expected hexidecimal number");
928a34c753fSRafael Auler     Diag << "Found: " << NumStr << "\n";
929a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
930a34c753fSRafael Auler   }
931a34c753fSRafael Auler   return Num;
932a34c753fSRafael Auler }
933a34c753fSRafael Auler 
93440c2e0faSMaksim Panchenko ErrorOr<Location> DataReader::parseLocation(char EndChar, bool EndNl,
935a34c753fSRafael Auler                                             bool ExpectMemLoc) {
936a34c753fSRafael Auler   // Read whether the location of the branch should be DSO or a symbol
937a34c753fSRafael Auler   // 0 means it is a DSO. 1 means it is a global symbol. 2 means it is a local
938a34c753fSRafael Auler   // symbol.
939a34c753fSRafael Auler   // The symbol flag is also used to tag memory load events by adding 3 to the
940a34c753fSRafael Auler   // base values, i.e. 3 not a symbol, 4 global symbol and 5 local symbol.
94140c2e0faSMaksim Panchenko   if (!ExpectMemLoc && ParsingBuf[0] != '0' && ParsingBuf[0] != '1' &&
94240c2e0faSMaksim Panchenko       ParsingBuf[0] != '2') {
943a34c753fSRafael Auler     reportError("expected 0, 1 or 2");
944a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
945a34c753fSRafael Auler   }
946a34c753fSRafael Auler 
94740c2e0faSMaksim Panchenko   if (ExpectMemLoc && ParsingBuf[0] != '3' && ParsingBuf[0] != '4' &&
94840c2e0faSMaksim Panchenko       ParsingBuf[0] != '5') {
949a34c753fSRafael Auler     reportError("expected 3, 4 or 5");
950a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
951a34c753fSRafael Auler   }
952a34c753fSRafael Auler 
953a34c753fSRafael Auler   bool IsSymbol =
954a34c753fSRafael Auler       (!ExpectMemLoc && (ParsingBuf[0] == '1' || ParsingBuf[0] == '2')) ||
955a34c753fSRafael Auler       (ExpectMemLoc && (ParsingBuf[0] == '4' || ParsingBuf[0] == '5'));
956a34c753fSRafael Auler   ParsingBuf = ParsingBuf.drop_front(1);
957a34c753fSRafael Auler   Col += 1;
958a34c753fSRafael Auler 
959a34c753fSRafael Auler   if (!expectAndConsumeFS())
960a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
961a34c753fSRafael Auler   consumeAllRemainingFS();
962a34c753fSRafael Auler 
963a34c753fSRafael Auler   // Read the string containing the symbol or the DSO name
964a34c753fSRafael Auler   ErrorOr<StringRef> NameRes = parseString(FieldSeparator);
965a34c753fSRafael Auler   if (std::error_code EC = NameRes.getError())
966a34c753fSRafael Auler     return EC;
967a34c753fSRafael Auler   StringRef Name = NameRes.get();
968a34c753fSRafael Auler   consumeAllRemainingFS();
969a34c753fSRafael Auler 
970a34c753fSRafael Auler   // Read the offset
971a34c753fSRafael Auler   ErrorOr<uint64_t> Offset = parseHexField(EndChar, EndNl);
972a34c753fSRafael Auler   if (std::error_code EC = Offset.getError())
973a34c753fSRafael Auler     return EC;
974a34c753fSRafael Auler 
975a34c753fSRafael Auler   return Location(IsSymbol, Name, Offset.get());
976a34c753fSRafael Auler }
977a34c753fSRafael Auler 
978a34c753fSRafael Auler ErrorOr<BranchInfo> DataReader::parseBranchInfo() {
979a34c753fSRafael Auler   ErrorOr<Location> Res = parseLocation(FieldSeparator);
980a34c753fSRafael Auler   if (std::error_code EC = Res.getError())
981a34c753fSRafael Auler     return EC;
982a34c753fSRafael Auler   Location From = Res.get();
983a34c753fSRafael Auler 
984a34c753fSRafael Auler   consumeAllRemainingFS();
985a34c753fSRafael Auler   Res = parseLocation(FieldSeparator);
986a34c753fSRafael Auler   if (std::error_code EC = Res.getError())
987a34c753fSRafael Auler     return EC;
988a34c753fSRafael Auler   Location To = Res.get();
989a34c753fSRafael Auler 
990a34c753fSRafael Auler   consumeAllRemainingFS();
991a34c753fSRafael Auler   ErrorOr<int64_t> MRes = parseNumberField(FieldSeparator);
992a34c753fSRafael Auler   if (std::error_code EC = MRes.getError())
993a34c753fSRafael Auler     return EC;
994a34c753fSRafael Auler   int64_t NumMispreds = MRes.get();
995a34c753fSRafael Auler 
996a34c753fSRafael Auler   consumeAllRemainingFS();
997a34c753fSRafael Auler   ErrorOr<int64_t> BRes = parseNumberField(FieldSeparator, /* EndNl = */ true);
998a34c753fSRafael Auler   if (std::error_code EC = BRes.getError())
999a34c753fSRafael Auler     return EC;
1000a34c753fSRafael Auler   int64_t NumBranches = BRes.get();
1001a34c753fSRafael Auler 
1002a34c753fSRafael Auler   consumeAllRemainingFS();
1003a34c753fSRafael Auler   if (!checkAndConsumeNewLine()) {
1004a34c753fSRafael Auler     reportError("expected end of line");
1005a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
1006a34c753fSRafael Auler   }
1007a34c753fSRafael Auler 
1008a34c753fSRafael Auler   return BranchInfo(std::move(From), std::move(To), NumMispreds, NumBranches);
1009a34c753fSRafael Auler }
1010a34c753fSRafael Auler 
1011a34c753fSRafael Auler ErrorOr<MemInfo> DataReader::parseMemInfo() {
1012a34c753fSRafael Auler   ErrorOr<Location> Res = parseMemLocation(FieldSeparator);
1013a34c753fSRafael Auler   if (std::error_code EC = Res.getError())
1014a34c753fSRafael Auler     return EC;
1015a34c753fSRafael Auler   Location Offset = Res.get();
1016a34c753fSRafael Auler 
1017a34c753fSRafael Auler   consumeAllRemainingFS();
1018a34c753fSRafael Auler   Res = parseMemLocation(FieldSeparator);
1019a34c753fSRafael Auler   if (std::error_code EC = Res.getError())
1020a34c753fSRafael Auler     return EC;
1021a34c753fSRafael Auler   Location Addr = Res.get();
1022a34c753fSRafael Auler 
1023a34c753fSRafael Auler   consumeAllRemainingFS();
1024a34c753fSRafael Auler   ErrorOr<int64_t> CountRes = parseNumberField(FieldSeparator, true);
1025a34c753fSRafael Auler   if (std::error_code EC = CountRes.getError())
1026a34c753fSRafael Auler     return EC;
1027a34c753fSRafael Auler 
1028a34c753fSRafael Auler   consumeAllRemainingFS();
1029a34c753fSRafael Auler   if (!checkAndConsumeNewLine()) {
1030a34c753fSRafael Auler     reportError("expected end of line");
1031a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
1032a34c753fSRafael Auler   }
1033a34c753fSRafael Auler 
1034a34c753fSRafael Auler   return MemInfo(Offset, Addr, CountRes.get());
1035a34c753fSRafael Auler }
1036a34c753fSRafael Auler 
1037a34c753fSRafael Auler ErrorOr<SampleInfo> DataReader::parseSampleInfo() {
1038a34c753fSRafael Auler   ErrorOr<Location> Res = parseLocation(FieldSeparator);
1039a34c753fSRafael Auler   if (std::error_code EC = Res.getError())
1040a34c753fSRafael Auler     return EC;
1041a34c753fSRafael Auler   Location Address = Res.get();
1042a34c753fSRafael Auler 
1043a34c753fSRafael Auler   consumeAllRemainingFS();
1044a34c753fSRafael Auler   ErrorOr<int64_t> BRes = parseNumberField(FieldSeparator, /* EndNl = */ true);
1045a34c753fSRafael Auler   if (std::error_code EC = BRes.getError())
1046a34c753fSRafael Auler     return EC;
1047a34c753fSRafael Auler   int64_t Occurrences = BRes.get();
1048a34c753fSRafael Auler 
1049a34c753fSRafael Auler   consumeAllRemainingFS();
1050a34c753fSRafael Auler   if (!checkAndConsumeNewLine()) {
1051a34c753fSRafael Auler     reportError("expected end of line");
1052a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
1053a34c753fSRafael Auler   }
1054a34c753fSRafael Auler 
1055a34c753fSRafael Auler   return SampleInfo(std::move(Address), Occurrences);
1056a34c753fSRafael Auler }
1057a34c753fSRafael Auler 
1058a34c753fSRafael Auler ErrorOr<bool> DataReader::maybeParseNoLBRFlag() {
1059a34c753fSRafael Auler   if (ParsingBuf.size() < 6 || ParsingBuf.substr(0, 6) != "no_lbr")
1060a34c753fSRafael Auler     return false;
1061a34c753fSRafael Auler   ParsingBuf = ParsingBuf.drop_front(6);
1062a34c753fSRafael Auler   Col += 6;
1063a34c753fSRafael Auler 
1064a34c753fSRafael Auler   if (ParsingBuf.size() > 0 && ParsingBuf[0] == ' ')
1065a34c753fSRafael Auler     ParsingBuf = ParsingBuf.drop_front(1);
1066a34c753fSRafael Auler 
1067a34c753fSRafael Auler   while (ParsingBuf.size() > 0 && ParsingBuf[0] != '\n') {
1068a34c753fSRafael Auler     ErrorOr<StringRef> EventName = parseString(' ', true);
1069a34c753fSRafael Auler     if (!EventName)
1070a34c753fSRafael Auler       return make_error_code(llvm::errc::io_error);
1071a34c753fSRafael Auler     EventNames.insert(EventName.get());
1072a34c753fSRafael Auler   }
1073a34c753fSRafael Auler 
1074a34c753fSRafael Auler   if (!checkAndConsumeNewLine()) {
1075a34c753fSRafael Auler     reportError("malformed no_lbr line");
1076a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
1077a34c753fSRafael Auler   }
1078a34c753fSRafael Auler   return true;
1079a34c753fSRafael Auler }
1080a34c753fSRafael Auler 
1081a34c753fSRafael Auler ErrorOr<bool> DataReader::maybeParseBATFlag() {
1082a34c753fSRafael Auler   if (ParsingBuf.size() < 16 || ParsingBuf.substr(0, 16) != "boltedcollection")
1083a34c753fSRafael Auler     return false;
1084a34c753fSRafael Auler   ParsingBuf = ParsingBuf.drop_front(16);
1085a34c753fSRafael Auler   Col += 16;
1086a34c753fSRafael Auler 
1087a34c753fSRafael Auler   if (!checkAndConsumeNewLine()) {
1088a34c753fSRafael Auler     reportError("malformed boltedcollection line");
1089a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
1090a34c753fSRafael Auler   }
1091a34c753fSRafael Auler   return true;
1092a34c753fSRafael Auler }
1093a34c753fSRafael Auler 
1094a34c753fSRafael Auler bool DataReader::hasBranchData() {
1095a34c753fSRafael Auler   if (ParsingBuf.size() == 0)
1096a34c753fSRafael Auler     return false;
1097a34c753fSRafael Auler 
1098a34c753fSRafael Auler   if (ParsingBuf[0] == '0' || ParsingBuf[0] == '1' || ParsingBuf[0] == '2')
1099a34c753fSRafael Auler     return true;
1100a34c753fSRafael Auler   return false;
1101a34c753fSRafael Auler }
1102a34c753fSRafael Auler 
1103a34c753fSRafael Auler bool DataReader::hasMemData() {
1104a34c753fSRafael Auler   if (ParsingBuf.size() == 0)
1105a34c753fSRafael Auler     return false;
1106a34c753fSRafael Auler 
1107a34c753fSRafael Auler   if (ParsingBuf[0] == '3' || ParsingBuf[0] == '4' || ParsingBuf[0] == '5')
1108a34c753fSRafael Auler     return true;
1109a34c753fSRafael Auler   return false;
1110a34c753fSRafael Auler }
1111a34c753fSRafael Auler 
1112a34c753fSRafael Auler std::error_code DataReader::parseInNoLBRMode() {
1113a34c753fSRafael Auler   auto GetOrCreateFuncEntry = [&](StringRef Name) {
1114a34c753fSRafael Auler     auto I = NamesToSamples.find(Name);
1115a34c753fSRafael Auler     if (I == NamesToSamples.end()) {
1116a34c753fSRafael Auler       bool Success;
1117a34c753fSRafael Auler       std::tie(I, Success) = NamesToSamples.insert(std::make_pair(
1118a34c753fSRafael Auler           Name, FuncSampleData(Name, FuncSampleData::ContainerTy())));
1119a34c753fSRafael Auler 
1120a34c753fSRafael Auler       assert(Success && "unexpected result of insert");
1121a34c753fSRafael Auler     }
1122a34c753fSRafael Auler     return I;
1123a34c753fSRafael Auler   };
1124a34c753fSRafael Auler 
1125a34c753fSRafael Auler   auto GetOrCreateFuncMemEntry = [&](StringRef Name) {
1126a34c753fSRafael Auler     auto I = NamesToMemEvents.find(Name);
1127a34c753fSRafael Auler     if (I == NamesToMemEvents.end()) {
1128a34c753fSRafael Auler       bool Success;
1129a34c753fSRafael Auler       std::tie(I, Success) = NamesToMemEvents.insert(
1130a34c753fSRafael Auler           std::make_pair(Name, FuncMemData(Name, FuncMemData::ContainerTy())));
1131a34c753fSRafael Auler       assert(Success && "unexpected result of insert");
1132a34c753fSRafael Auler     }
1133a34c753fSRafael Auler     return I;
1134a34c753fSRafael Auler   };
1135a34c753fSRafael Auler 
1136a34c753fSRafael Auler   while (hasBranchData()) {
1137a34c753fSRafael Auler     ErrorOr<SampleInfo> Res = parseSampleInfo();
1138a34c753fSRafael Auler     if (std::error_code EC = Res.getError())
1139a34c753fSRafael Auler       return EC;
1140a34c753fSRafael Auler 
1141a34c753fSRafael Auler     SampleInfo SI = Res.get();
1142a34c753fSRafael Auler 
1143a34c753fSRafael Auler     // Ignore samples not involving known locations
1144a34c753fSRafael Auler     if (!SI.Loc.IsSymbol)
1145a34c753fSRafael Auler       continue;
1146a34c753fSRafael Auler 
1147a34c753fSRafael Auler     StringMapIterator<FuncSampleData> I = GetOrCreateFuncEntry(SI.Loc.Name);
1148a34c753fSRafael Auler     I->getValue().Data.emplace_back(std::move(SI));
1149a34c753fSRafael Auler   }
1150a34c753fSRafael Auler 
1151a34c753fSRafael Auler   while (hasMemData()) {
1152a34c753fSRafael Auler     ErrorOr<MemInfo> Res = parseMemInfo();
1153a34c753fSRafael Auler     if (std::error_code EC = Res.getError())
1154a34c753fSRafael Auler       return EC;
1155a34c753fSRafael Auler 
1156a34c753fSRafael Auler     MemInfo MI = Res.get();
1157a34c753fSRafael Auler 
1158a34c753fSRafael Auler     // Ignore memory events not involving known pc.
1159a34c753fSRafael Auler     if (!MI.Offset.IsSymbol)
1160a34c753fSRafael Auler       continue;
1161a34c753fSRafael Auler 
1162a34c753fSRafael Auler     StringMapIterator<FuncMemData> I = GetOrCreateFuncMemEntry(MI.Offset.Name);
1163a34c753fSRafael Auler     I->getValue().Data.emplace_back(std::move(MI));
1164a34c753fSRafael Auler   }
1165a34c753fSRafael Auler 
1166a34c753fSRafael Auler   for (StringMapEntry<FuncSampleData> &FuncSamples : NamesToSamples) {
1167a34c753fSRafael Auler     std::stable_sort(FuncSamples.second.Data.begin(),
1168a34c753fSRafael Auler                      FuncSamples.second.Data.end());
1169a34c753fSRafael Auler   }
1170a34c753fSRafael Auler 
1171a34c753fSRafael Auler   for (StringMapEntry<FuncMemData> &MemEvents : NamesToMemEvents) {
1172a34c753fSRafael Auler     std::stable_sort(MemEvents.second.Data.begin(),
1173a34c753fSRafael Auler                      MemEvents.second.Data.end());
1174a34c753fSRafael Auler   }
1175a34c753fSRafael Auler 
1176a34c753fSRafael Auler   return std::error_code();
1177a34c753fSRafael Auler }
1178a34c753fSRafael Auler 
1179a34c753fSRafael Auler std::error_code DataReader::parse() {
1180a34c753fSRafael Auler   auto GetOrCreateFuncEntry = [&](StringRef Name) {
1181a34c753fSRafael Auler     auto I = NamesToBranches.find(Name);
1182a34c753fSRafael Auler     if (I == NamesToBranches.end()) {
1183a34c753fSRafael Auler       bool Success;
1184a34c753fSRafael Auler       std::tie(I, Success) = NamesToBranches.insert(std::make_pair(
1185a34c753fSRafael Auler           Name, FuncBranchData(Name, FuncBranchData::ContainerTy(),
1186a34c753fSRafael Auler                                FuncBranchData::ContainerTy())));
1187a34c753fSRafael Auler       assert(Success && "unexpected result of insert");
1188a34c753fSRafael Auler     }
1189a34c753fSRafael Auler     return I;
1190a34c753fSRafael Auler   };
1191a34c753fSRafael Auler 
1192a34c753fSRafael Auler   auto GetOrCreateFuncMemEntry = [&](StringRef Name) {
1193a34c753fSRafael Auler     auto I = NamesToMemEvents.find(Name);
1194a34c753fSRafael Auler     if (I == NamesToMemEvents.end()) {
1195a34c753fSRafael Auler       bool Success;
1196a34c753fSRafael Auler       std::tie(I, Success) = NamesToMemEvents.insert(
1197a34c753fSRafael Auler           std::make_pair(Name, FuncMemData(Name, FuncMemData::ContainerTy())));
1198a34c753fSRafael Auler       assert(Success && "unexpected result of insert");
1199a34c753fSRafael Auler     }
1200a34c753fSRafael Auler     return I;
1201a34c753fSRafael Auler   };
1202a34c753fSRafael Auler 
1203a34c753fSRafael Auler   Col = 0;
1204a34c753fSRafael Auler   Line = 1;
1205a34c753fSRafael Auler   ErrorOr<bool> FlagOrErr = maybeParseNoLBRFlag();
1206a34c753fSRafael Auler   if (!FlagOrErr)
1207a34c753fSRafael Auler     return FlagOrErr.getError();
1208a34c753fSRafael Auler   NoLBRMode = *FlagOrErr;
1209a34c753fSRafael Auler 
1210a34c753fSRafael Auler   ErrorOr<bool> BATFlagOrErr = maybeParseBATFlag();
1211a34c753fSRafael Auler   if (!BATFlagOrErr)
1212a34c753fSRafael Auler     return BATFlagOrErr.getError();
1213a34c753fSRafael Auler   BATMode = *BATFlagOrErr;
1214a34c753fSRafael Auler 
1215a34c753fSRafael Auler   if (!hasBranchData() && !hasMemData()) {
1216a34c753fSRafael Auler     Diag << "ERROR: no valid profile data found\n";
1217a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
1218a34c753fSRafael Auler   }
1219a34c753fSRafael Auler 
1220a34c753fSRafael Auler   if (NoLBRMode)
1221a34c753fSRafael Auler     return parseInNoLBRMode();
1222a34c753fSRafael Auler 
1223a34c753fSRafael Auler   while (hasBranchData()) {
1224a34c753fSRafael Auler     ErrorOr<BranchInfo> Res = parseBranchInfo();
1225a34c753fSRafael Auler     if (std::error_code EC = Res.getError())
1226a34c753fSRafael Auler       return EC;
1227a34c753fSRafael Auler 
1228a34c753fSRafael Auler     BranchInfo BI = Res.get();
1229a34c753fSRafael Auler 
1230a34c753fSRafael Auler     // Ignore branches not involving known location.
1231a34c753fSRafael Auler     if (!BI.From.IsSymbol && !BI.To.IsSymbol)
1232a34c753fSRafael Auler       continue;
1233a34c753fSRafael Auler 
1234a34c753fSRafael Auler     StringMapIterator<FuncBranchData> I = GetOrCreateFuncEntry(BI.From.Name);
1235a34c753fSRafael Auler     I->getValue().Data.emplace_back(std::move(BI));
1236a34c753fSRafael Auler 
1237a34c753fSRafael Auler     // Add entry data for branches to another function or branches
1238a34c753fSRafael Auler     // to entry points (including recursive calls)
1239a34c753fSRafael Auler     if (BI.To.IsSymbol &&
1240a34c753fSRafael Auler         (!BI.From.Name.equals(BI.To.Name) || BI.To.Offset == 0)) {
1241a34c753fSRafael Auler       I = GetOrCreateFuncEntry(BI.To.Name);
1242a34c753fSRafael Auler       I->getValue().EntryData.emplace_back(std::move(BI));
1243a34c753fSRafael Auler     }
1244a34c753fSRafael Auler 
1245a34c753fSRafael Auler     // If destination is the function start - update execution count.
1246a34c753fSRafael Auler     // NB: the data is skewed since we cannot tell tail recursion from
1247a34c753fSRafael Auler     //     branches to the function start.
1248a34c753fSRafael Auler     if (BI.To.IsSymbol && BI.To.Offset == 0) {
1249a34c753fSRafael Auler       I = GetOrCreateFuncEntry(BI.To.Name);
1250a34c753fSRafael Auler       I->getValue().ExecutionCount += BI.Branches;
1251a34c753fSRafael Auler     }
1252a34c753fSRafael Auler   }
1253a34c753fSRafael Auler 
1254a34c753fSRafael Auler   while (hasMemData()) {
1255a34c753fSRafael Auler     ErrorOr<MemInfo> Res = parseMemInfo();
1256a34c753fSRafael Auler     if (std::error_code EC = Res.getError())
1257a34c753fSRafael Auler       return EC;
1258a34c753fSRafael Auler 
1259a34c753fSRafael Auler     MemInfo MI = Res.get();
1260a34c753fSRafael Auler 
1261a34c753fSRafael Auler     // Ignore memory events not involving known pc.
1262a34c753fSRafael Auler     if (!MI.Offset.IsSymbol)
1263a34c753fSRafael Auler       continue;
1264a34c753fSRafael Auler 
1265a34c753fSRafael Auler     StringMapIterator<FuncMemData> I = GetOrCreateFuncMemEntry(MI.Offset.Name);
1266a34c753fSRafael Auler     I->getValue().Data.emplace_back(std::move(MI));
1267a34c753fSRafael Auler   }
1268a34c753fSRafael Auler 
1269a34c753fSRafael Auler   for (StringMapEntry<FuncBranchData> &FuncBranches : NamesToBranches) {
1270a34c753fSRafael Auler     std::stable_sort(FuncBranches.second.Data.begin(),
1271a34c753fSRafael Auler                      FuncBranches.second.Data.end());
1272a34c753fSRafael Auler   }
1273a34c753fSRafael Auler 
1274a34c753fSRafael Auler   for (StringMapEntry<FuncMemData> &MemEvents : NamesToMemEvents) {
1275a34c753fSRafael Auler     std::stable_sort(MemEvents.second.Data.begin(),
1276a34c753fSRafael Auler                      MemEvents.second.Data.end());
1277a34c753fSRafael Auler   }
1278a34c753fSRafael Auler 
1279a34c753fSRafael Auler   return std::error_code();
1280a34c753fSRafael Auler }
1281a34c753fSRafael Auler 
1282a34c753fSRafael Auler void DataReader::buildLTONameMaps() {
1283a34c753fSRafael Auler   for (StringMapEntry<FuncBranchData> &FuncData : NamesToBranches) {
1284a34c753fSRafael Auler     const StringRef FuncName = FuncData.getKey();
1285a34c753fSRafael Auler     const Optional<StringRef> CommonName = getLTOCommonName(FuncName);
1286a34c753fSRafael Auler     if (CommonName)
1287a34c753fSRafael Auler       LTOCommonNameMap[*CommonName].push_back(&FuncData.getValue());
1288a34c753fSRafael Auler   }
1289a34c753fSRafael Auler 
1290a34c753fSRafael Auler   for (StringMapEntry<FuncMemData> &FuncData : NamesToMemEvents) {
1291a34c753fSRafael Auler     const StringRef FuncName = FuncData.getKey();
1292a34c753fSRafael Auler     const Optional<StringRef> CommonName = getLTOCommonName(FuncName);
1293a34c753fSRafael Auler     if (CommonName)
1294a34c753fSRafael Auler       LTOCommonNameMemMap[*CommonName].push_back(&FuncData.getValue());
1295a34c753fSRafael Auler   }
1296a34c753fSRafael Auler }
1297a34c753fSRafael Auler 
1298a34c753fSRafael Auler namespace {
1299a34c753fSRafael Auler template <typename MapTy>
1300a34c753fSRafael Auler decltype(MapTy::MapEntryTy::second) *
1301a34c753fSRafael Auler fetchMapEntry(MapTy &Map, const std::vector<MCSymbol *> &Symbols) {
1302a34c753fSRafael Auler   // Do a reverse order iteration since the name in profile has a higher chance
1303a34c753fSRafael Auler   // of matching a name at the end of the list.
1304a34c753fSRafael Auler   for (auto SI = Symbols.rbegin(), SE = Symbols.rend(); SI != SE; ++SI) {
1305a34c753fSRafael Auler     auto I = Map.find(normalizeName((*SI)->getName()));
1306a34c753fSRafael Auler     if (I != Map.end())
1307a34c753fSRafael Auler       return &I->getValue();
1308a34c753fSRafael Auler   }
1309a34c753fSRafael Auler   return nullptr;
1310a34c753fSRafael Auler }
1311a34c753fSRafael Auler 
1312a34c753fSRafael Auler template <typename MapTy>
1313a34c753fSRafael Auler decltype(MapTy::MapEntryTy::second) *
1314a34c753fSRafael Auler fetchMapEntry(MapTy &Map, const std::vector<StringRef> &FuncNames) {
1315a34c753fSRafael Auler   // Do a reverse order iteration since the name in profile has a higher chance
1316a34c753fSRafael Auler   // of matching a name at the end of the list.
1317a34c753fSRafael Auler   for (auto FI = FuncNames.rbegin(), FE = FuncNames.rend(); FI != FE; ++FI) {
1318a34c753fSRafael Auler     auto I = Map.find(normalizeName(*FI));
1319a34c753fSRafael Auler     if (I != Map.end())
1320a34c753fSRafael Auler       return &I->getValue();
1321a34c753fSRafael Auler   }
1322a34c753fSRafael Auler   return nullptr;
1323a34c753fSRafael Auler }
1324a34c753fSRafael Auler 
1325a34c753fSRafael Auler template <typename MapTy>
132640c2e0faSMaksim Panchenko std::vector<decltype(MapTy::MapEntryTy::second) *> fetchMapEntriesRegex(
1327a34c753fSRafael Auler     MapTy &Map,
132840c2e0faSMaksim Panchenko     const StringMap<std::vector<decltype(MapTy::MapEntryTy::second) *>>
132940c2e0faSMaksim Panchenko         &LTOCommonNameMap,
1330a34c753fSRafael Auler     const std::vector<StringRef> &FuncNames) {
1331a34c753fSRafael Auler   std::vector<decltype(MapTy::MapEntryTy::second) *> AllData;
1332a34c753fSRafael Auler   // Do a reverse order iteration since the name in profile has a higher chance
1333a34c753fSRafael Auler   // of matching a name at the end of the list.
1334a34c753fSRafael Auler   for (auto FI = FuncNames.rbegin(), FE = FuncNames.rend(); FI != FE; ++FI) {
1335a34c753fSRafael Auler     std::string Name = normalizeName(*FI);
1336a34c753fSRafael Auler     const Optional<StringRef> LTOCommonName = getLTOCommonName(Name);
1337a34c753fSRafael Auler     if (LTOCommonName) {
1338a34c753fSRafael Auler       auto I = LTOCommonNameMap.find(*LTOCommonName);
1339a34c753fSRafael Auler       if (I != LTOCommonNameMap.end()) {
1340a34c753fSRafael Auler         const std::vector<decltype(MapTy::MapEntryTy::second) *> &CommonData =
1341a34c753fSRafael Auler             I->getValue();
1342a34c753fSRafael Auler         AllData.insert(AllData.end(), CommonData.begin(), CommonData.end());
1343a34c753fSRafael Auler       }
1344a34c753fSRafael Auler     } else {
1345a34c753fSRafael Auler       auto I = Map.find(Name);
1346a34c753fSRafael Auler       if (I != Map.end()) {
1347a34c753fSRafael Auler         return {&I->getValue()};
1348a34c753fSRafael Auler       }
1349a34c753fSRafael Auler     }
1350a34c753fSRafael Auler   }
1351a34c753fSRafael Auler   return AllData;
1352a34c753fSRafael Auler }
1353a34c753fSRafael Auler 
1354a34c753fSRafael Auler }
1355a34c753fSRafael Auler 
1356a34c753fSRafael Auler bool DataReader::mayHaveProfileData(const BinaryFunction &Function) {
1357a34c753fSRafael Auler   if (getBranchData(Function) || getMemData(Function))
1358a34c753fSRafael Auler     return true;
1359a34c753fSRafael Auler 
1360a34c753fSRafael Auler   if (getBranchDataForNames(Function.getNames()) ||
1361a34c753fSRafael Auler       getMemDataForNames(Function.getNames()))
1362a34c753fSRafael Auler     return true;
1363a34c753fSRafael Auler 
1364a34c753fSRafael Auler   if (!hasVolatileName(Function))
1365a34c753fSRafael Auler     return false;
1366a34c753fSRafael Auler 
1367a34c753fSRafael Auler   const std::vector<FuncBranchData *> AllBranchData =
1368a34c753fSRafael Auler       getBranchDataForNamesRegex(Function.getNames());
1369a34c753fSRafael Auler   if (!AllBranchData.empty())
1370a34c753fSRafael Auler     return true;
1371a34c753fSRafael Auler 
1372a34c753fSRafael Auler   const std::vector<FuncMemData *> AllMemData =
1373a34c753fSRafael Auler       getMemDataForNamesRegex(Function.getNames());
1374a34c753fSRafael Auler   if (!AllMemData.empty())
1375a34c753fSRafael Auler     return true;
1376a34c753fSRafael Auler 
1377a34c753fSRafael Auler   return false;
1378a34c753fSRafael Auler }
1379a34c753fSRafael Auler 
1380a34c753fSRafael Auler FuncBranchData *
1381a34c753fSRafael Auler DataReader::getBranchDataForNames(const std::vector<StringRef> &FuncNames) {
1382a34c753fSRafael Auler   return fetchMapEntry<NamesToBranchesMapTy>(NamesToBranches, FuncNames);
1383a34c753fSRafael Auler }
1384a34c753fSRafael Auler 
1385a34c753fSRafael Auler FuncBranchData *
1386a34c753fSRafael Auler DataReader::getBranchDataForSymbols(const std::vector<MCSymbol *> &Symbols) {
1387a34c753fSRafael Auler   return fetchMapEntry<NamesToBranchesMapTy>(NamesToBranches, Symbols);
1388a34c753fSRafael Auler }
1389a34c753fSRafael Auler 
1390a34c753fSRafael Auler FuncMemData *
1391a34c753fSRafael Auler DataReader::getMemDataForNames(const std::vector<StringRef> &FuncNames) {
1392a34c753fSRafael Auler   return fetchMapEntry<NamesToMemEventsMapTy>(NamesToMemEvents, FuncNames);
1393a34c753fSRafael Auler }
1394a34c753fSRafael Auler 
1395a34c753fSRafael Auler FuncSampleData *
1396a34c753fSRafael Auler DataReader::getFuncSampleData(const std::vector<StringRef> &FuncNames) {
1397a34c753fSRafael Auler   return fetchMapEntry<NamesToSamplesMapTy>(NamesToSamples, FuncNames);
1398a34c753fSRafael Auler }
1399a34c753fSRafael Auler 
140040c2e0faSMaksim Panchenko std::vector<FuncBranchData *> DataReader::getBranchDataForNamesRegex(
1401a34c753fSRafael Auler     const std::vector<StringRef> &FuncNames) {
1402a34c753fSRafael Auler   return fetchMapEntriesRegex(NamesToBranches, LTOCommonNameMap, FuncNames);
1403a34c753fSRafael Auler }
1404a34c753fSRafael Auler 
1405a34c753fSRafael Auler std::vector<FuncMemData *>
1406a34c753fSRafael Auler DataReader::getMemDataForNamesRegex(const std::vector<StringRef> &FuncNames) {
1407a34c753fSRafael Auler   return fetchMapEntriesRegex(NamesToMemEvents, LTOCommonNameMemMap, FuncNames);
1408a34c753fSRafael Auler }
1409a34c753fSRafael Auler 
1410a34c753fSRafael Auler bool DataReader::hasLocalsWithFileName() const {
1411a34c753fSRafael Auler   for (const StringMapEntry<FuncBranchData> &Func : NamesToBranches) {
1412a34c753fSRafael Auler     const StringRef &FuncName = Func.getKey();
1413a34c753fSRafael Auler     if (FuncName.count('/') == 2 && FuncName[0] != '/')
1414a34c753fSRafael Auler       return true;
1415a34c753fSRafael Auler   }
1416a34c753fSRafael Auler   return false;
1417a34c753fSRafael Auler }
1418a34c753fSRafael Auler 
1419a34c753fSRafael Auler void DataReader::dump() const {
1420a34c753fSRafael Auler   for (const StringMapEntry<FuncBranchData> &Func : NamesToBranches) {
1421a34c753fSRafael Auler     Diag << Func.getKey() << " branches:\n";
1422a34c753fSRafael Auler     for (const BranchInfo &BI : Func.getValue().Data) {
1423a34c753fSRafael Auler       Diag << BI.From.Name << " " << BI.From.Offset << " " << BI.To.Name << " "
1424a34c753fSRafael Auler            << BI.To.Offset << " " << BI.Mispreds << " " << BI.Branches << "\n";
1425a34c753fSRafael Auler     }
1426a34c753fSRafael Auler     Diag << Func.getKey() << " entry points:\n";
1427a34c753fSRafael Auler     for (const BranchInfo &BI : Func.getValue().EntryData) {
1428a34c753fSRafael Auler       Diag << BI.From.Name << " " << BI.From.Offset << " " << BI.To.Name << " "
1429a34c753fSRafael Auler            << BI.To.Offset << " " << BI.Mispreds << " " << BI.Branches << "\n";
1430a34c753fSRafael Auler     }
1431a34c753fSRafael Auler   }
1432a34c753fSRafael Auler 
1433a34c753fSRafael Auler   for (auto I = EventNames.begin(), E = EventNames.end(); I != E; ++I) {
1434a34c753fSRafael Auler     StringRef Event = I->getKey();
1435a34c753fSRafael Auler     Diag << "Data was collected with event: " << Event << "\n";
1436a34c753fSRafael Auler   }
1437a34c753fSRafael Auler   for (const StringMapEntry<FuncSampleData> &Func : NamesToSamples) {
1438a34c753fSRafael Auler     Diag << Func.getKey() << " samples:\n";
1439a34c753fSRafael Auler     for (const SampleInfo &SI : Func.getValue().Data) {
144040c2e0faSMaksim Panchenko       Diag << SI.Loc.Name << " " << SI.Loc.Offset << " " << SI.Hits << "\n";
1441a34c753fSRafael Auler     }
1442a34c753fSRafael Auler   }
1443a34c753fSRafael Auler 
1444a34c753fSRafael Auler   for (const StringMapEntry<FuncMemData> &Func : NamesToMemEvents) {
1445a34c753fSRafael Auler     Diag << "Memory events for " << Func.getValue().Name;
1446a34c753fSRafael Auler     Location LastOffset(0);
1447a34c753fSRafael Auler     for (const MemInfo &MI : Func.getValue().Data) {
1448a34c753fSRafael Auler       if (MI.Offset == LastOffset) {
1449a34c753fSRafael Auler         Diag << ", " << MI.Addr << "/" << MI.Count;
1450a34c753fSRafael Auler       } else {
1451a34c753fSRafael Auler         Diag << "\n" << MI.Offset << ": " << MI.Addr << "/" << MI.Count;
1452a34c753fSRafael Auler       }
1453a34c753fSRafael Auler       LastOffset = MI.Offset;
1454a34c753fSRafael Auler     }
1455a34c753fSRafael Auler     Diag << "\n";
1456a34c753fSRafael Auler   }
1457a34c753fSRafael Auler }
1458a34c753fSRafael Auler 
1459a34c753fSRafael Auler } // namespace bolt
1460a34c753fSRafael Auler } // namespace llvm
1461