10b57cec5SDimitry Andric //===- SampleProfReader.cpp - Read LLVM sample profile data ---------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements the class that reads LLVM sample profiles. It
100b57cec5SDimitry Andric // supports three file formats: text, binary and gcov.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric // The textual representation is useful for debugging and testing purposes. The
130b57cec5SDimitry Andric // binary representation is more compact, resulting in smaller file sizes.
140b57cec5SDimitry Andric //
150b57cec5SDimitry Andric // The gcov encoding is the one generated by GCC's AutoFDO profile creation
160b57cec5SDimitry Andric // tool (https://github.com/google/autofdo)
170b57cec5SDimitry Andric //
180b57cec5SDimitry Andric // All three encodings can be used interchangeably as an input sample profile.
190b57cec5SDimitry Andric //
200b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric #include "llvm/ProfileData/SampleProfReader.h"
230b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
240b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
250b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
260b57cec5SDimitry Andric #include "llvm/IR/ProfileSummary.h"
270b57cec5SDimitry Andric #include "llvm/ProfileData/ProfileCommon.h"
280b57cec5SDimitry Andric #include "llvm/ProfileData/SampleProf.h"
29*5f7ddb14SDimitry Andric #include "llvm/Support/CommandLine.h"
308bcb0991SDimitry Andric #include "llvm/Support/Compression.h"
310b57cec5SDimitry Andric #include "llvm/Support/ErrorOr.h"
320b57cec5SDimitry Andric #include "llvm/Support/LEB128.h"
330b57cec5SDimitry Andric #include "llvm/Support/LineIterator.h"
340b57cec5SDimitry Andric #include "llvm/Support/MD5.h"
350b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
360b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
370b57cec5SDimitry Andric #include <algorithm>
380b57cec5SDimitry Andric #include <cstddef>
390b57cec5SDimitry Andric #include <cstdint>
400b57cec5SDimitry Andric #include <limits>
410b57cec5SDimitry Andric #include <memory>
42*5f7ddb14SDimitry Andric #include <set>
430b57cec5SDimitry Andric #include <system_error>
440b57cec5SDimitry Andric #include <vector>
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric using namespace llvm;
470b57cec5SDimitry Andric using namespace sampleprof;
480b57cec5SDimitry Andric 
49*5f7ddb14SDimitry Andric #define DEBUG_TYPE "samplepgo-reader"
50*5f7ddb14SDimitry Andric 
51*5f7ddb14SDimitry Andric // This internal option specifies if the profile uses FS discriminators.
52*5f7ddb14SDimitry Andric // It only applies to text, binary and compact binary format profiles.
53*5f7ddb14SDimitry Andric // For ext-binary format profiles, the flag is set in the summary.
54*5f7ddb14SDimitry Andric static cl::opt<bool> ProfileIsFSDisciminator(
55*5f7ddb14SDimitry Andric     "profile-isfs", cl::Hidden, cl::init(false),
56*5f7ddb14SDimitry Andric     cl::desc("Profile uses flow senstive discriminators"));
57*5f7ddb14SDimitry Andric 
580b57cec5SDimitry Andric /// Dump the function profile for \p FName.
590b57cec5SDimitry Andric ///
600b57cec5SDimitry Andric /// \param FName Name of the function to print.
610b57cec5SDimitry Andric /// \param OS Stream to emit the output to.
dumpFunctionProfile(StringRef FName,raw_ostream & OS)620b57cec5SDimitry Andric void SampleProfileReader::dumpFunctionProfile(StringRef FName,
630b57cec5SDimitry Andric                                               raw_ostream &OS) {
640b57cec5SDimitry Andric   OS << "Function: " << FName << ": " << Profiles[FName];
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric /// Dump all the function profiles found on stream \p OS.
dump(raw_ostream & OS)680b57cec5SDimitry Andric void SampleProfileReader::dump(raw_ostream &OS) {
690b57cec5SDimitry Andric   for (const auto &I : Profiles)
700b57cec5SDimitry Andric     dumpFunctionProfile(I.getKey(), OS);
710b57cec5SDimitry Andric }
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric /// Parse \p Input as function head.
740b57cec5SDimitry Andric ///
750b57cec5SDimitry Andric /// Parse one line of \p Input, and update function name in \p FName,
760b57cec5SDimitry Andric /// function's total sample count in \p NumSamples, function's entry
770b57cec5SDimitry Andric /// count in \p NumHeadSamples.
780b57cec5SDimitry Andric ///
790b57cec5SDimitry Andric /// \returns true if parsing is successful.
ParseHead(const StringRef & Input,StringRef & FName,uint64_t & NumSamples,uint64_t & NumHeadSamples)800b57cec5SDimitry Andric static bool ParseHead(const StringRef &Input, StringRef &FName,
810b57cec5SDimitry Andric                       uint64_t &NumSamples, uint64_t &NumHeadSamples) {
820b57cec5SDimitry Andric   if (Input[0] == ' ')
830b57cec5SDimitry Andric     return false;
840b57cec5SDimitry Andric   size_t n2 = Input.rfind(':');
850b57cec5SDimitry Andric   size_t n1 = Input.rfind(':', n2 - 1);
860b57cec5SDimitry Andric   FName = Input.substr(0, n1);
870b57cec5SDimitry Andric   if (Input.substr(n1 + 1, n2 - n1 - 1).getAsInteger(10, NumSamples))
880b57cec5SDimitry Andric     return false;
890b57cec5SDimitry Andric   if (Input.substr(n2 + 1).getAsInteger(10, NumHeadSamples))
900b57cec5SDimitry Andric     return false;
910b57cec5SDimitry Andric   return true;
920b57cec5SDimitry Andric }
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric /// Returns true if line offset \p L is legal (only has 16 bits).
isOffsetLegal(unsigned L)950b57cec5SDimitry Andric static bool isOffsetLegal(unsigned L) { return (L & 0xffff) == L; }
960b57cec5SDimitry Andric 
97af732203SDimitry Andric /// Parse \p Input that contains metadata.
98af732203SDimitry Andric /// Possible metadata:
99af732203SDimitry Andric /// - CFG Checksum information:
100af732203SDimitry Andric ///     !CFGChecksum: 12345
101*5f7ddb14SDimitry Andric /// - CFG Checksum information:
102*5f7ddb14SDimitry Andric ///     !Attributes: 1
103af732203SDimitry Andric /// Stores the FunctionHash (a.k.a. CFG Checksum) into \p FunctionHash.
parseMetadata(const StringRef & Input,uint64_t & FunctionHash,uint32_t & Attributes)104*5f7ddb14SDimitry Andric static bool parseMetadata(const StringRef &Input, uint64_t &FunctionHash,
105*5f7ddb14SDimitry Andric                           uint32_t &Attributes) {
106*5f7ddb14SDimitry Andric   if (Input.startswith("!CFGChecksum:")) {
107af732203SDimitry Andric     StringRef CFGInfo = Input.substr(strlen("!CFGChecksum:")).trim();
108af732203SDimitry Andric     return !CFGInfo.getAsInteger(10, FunctionHash);
109af732203SDimitry Andric   }
110af732203SDimitry Andric 
111*5f7ddb14SDimitry Andric   if (Input.startswith("!Attributes:")) {
112*5f7ddb14SDimitry Andric     StringRef Attrib = Input.substr(strlen("!Attributes:")).trim();
113*5f7ddb14SDimitry Andric     return !Attrib.getAsInteger(10, Attributes);
114*5f7ddb14SDimitry Andric   }
115*5f7ddb14SDimitry Andric 
116*5f7ddb14SDimitry Andric   return false;
117*5f7ddb14SDimitry Andric }
118*5f7ddb14SDimitry Andric 
119af732203SDimitry Andric enum class LineType {
120af732203SDimitry Andric   CallSiteProfile,
121af732203SDimitry Andric   BodyProfile,
122af732203SDimitry Andric   Metadata,
123af732203SDimitry Andric };
124af732203SDimitry Andric 
1250b57cec5SDimitry Andric /// Parse \p Input as line sample.
1260b57cec5SDimitry Andric ///
1270b57cec5SDimitry Andric /// \param Input input line.
128af732203SDimitry Andric /// \param LineTy Type of this line.
1290b57cec5SDimitry Andric /// \param Depth the depth of the inline stack.
1300b57cec5SDimitry Andric /// \param NumSamples total samples of the line/inlined callsite.
1310b57cec5SDimitry Andric /// \param LineOffset line offset to the start of the function.
1320b57cec5SDimitry Andric /// \param Discriminator discriminator of the line.
1330b57cec5SDimitry Andric /// \param TargetCountMap map from indirect call target to count.
134af732203SDimitry Andric /// \param FunctionHash the function's CFG hash, used by pseudo probe.
1350b57cec5SDimitry Andric ///
1360b57cec5SDimitry Andric /// returns true if parsing is successful.
ParseLine(const StringRef & Input,LineType & LineTy,uint32_t & Depth,uint64_t & NumSamples,uint32_t & LineOffset,uint32_t & Discriminator,StringRef & CalleeName,DenseMap<StringRef,uint64_t> & TargetCountMap,uint64_t & FunctionHash,uint32_t & Attributes)137af732203SDimitry Andric static bool ParseLine(const StringRef &Input, LineType &LineTy, uint32_t &Depth,
1380b57cec5SDimitry Andric                       uint64_t &NumSamples, uint32_t &LineOffset,
1390b57cec5SDimitry Andric                       uint32_t &Discriminator, StringRef &CalleeName,
140af732203SDimitry Andric                       DenseMap<StringRef, uint64_t> &TargetCountMap,
141*5f7ddb14SDimitry Andric                       uint64_t &FunctionHash, uint32_t &Attributes) {
1420b57cec5SDimitry Andric   for (Depth = 0; Input[Depth] == ' '; Depth++)
1430b57cec5SDimitry Andric     ;
1440b57cec5SDimitry Andric   if (Depth == 0)
1450b57cec5SDimitry Andric     return false;
1460b57cec5SDimitry Andric 
147af732203SDimitry Andric   if (Depth == 1 && Input[Depth] == '!') {
148af732203SDimitry Andric     LineTy = LineType::Metadata;
149*5f7ddb14SDimitry Andric     return parseMetadata(Input.substr(Depth), FunctionHash, Attributes);
150af732203SDimitry Andric   }
151af732203SDimitry Andric 
1520b57cec5SDimitry Andric   size_t n1 = Input.find(':');
1530b57cec5SDimitry Andric   StringRef Loc = Input.substr(Depth, n1 - Depth);
1540b57cec5SDimitry Andric   size_t n2 = Loc.find('.');
1550b57cec5SDimitry Andric   if (n2 == StringRef::npos) {
1560b57cec5SDimitry Andric     if (Loc.getAsInteger(10, LineOffset) || !isOffsetLegal(LineOffset))
1570b57cec5SDimitry Andric       return false;
1580b57cec5SDimitry Andric     Discriminator = 0;
1590b57cec5SDimitry Andric   } else {
1600b57cec5SDimitry Andric     if (Loc.substr(0, n2).getAsInteger(10, LineOffset))
1610b57cec5SDimitry Andric       return false;
1620b57cec5SDimitry Andric     if (Loc.substr(n2 + 1).getAsInteger(10, Discriminator))
1630b57cec5SDimitry Andric       return false;
1640b57cec5SDimitry Andric   }
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric   StringRef Rest = Input.substr(n1 + 2);
167af732203SDimitry Andric   if (isDigit(Rest[0])) {
168af732203SDimitry Andric     LineTy = LineType::BodyProfile;
1690b57cec5SDimitry Andric     size_t n3 = Rest.find(' ');
1700b57cec5SDimitry Andric     if (n3 == StringRef::npos) {
1710b57cec5SDimitry Andric       if (Rest.getAsInteger(10, NumSamples))
1720b57cec5SDimitry Andric         return false;
1730b57cec5SDimitry Andric     } else {
1740b57cec5SDimitry Andric       if (Rest.substr(0, n3).getAsInteger(10, NumSamples))
1750b57cec5SDimitry Andric         return false;
1760b57cec5SDimitry Andric     }
1770b57cec5SDimitry Andric     // Find call targets and their sample counts.
1780b57cec5SDimitry Andric     // Note: In some cases, there are symbols in the profile which are not
1790b57cec5SDimitry Andric     // mangled. To accommodate such cases, use colon + integer pairs as the
1800b57cec5SDimitry Andric     // anchor points.
1810b57cec5SDimitry Andric     // An example:
1820b57cec5SDimitry Andric     // _M_construct<char *>:1000 string_view<std::allocator<char> >:437
1830b57cec5SDimitry Andric     // ":1000" and ":437" are used as anchor points so the string above will
1840b57cec5SDimitry Andric     // be interpreted as
1850b57cec5SDimitry Andric     // target: _M_construct<char *>
1860b57cec5SDimitry Andric     // count: 1000
1870b57cec5SDimitry Andric     // target: string_view<std::allocator<char> >
1880b57cec5SDimitry Andric     // count: 437
1890b57cec5SDimitry Andric     while (n3 != StringRef::npos) {
1900b57cec5SDimitry Andric       n3 += Rest.substr(n3).find_first_not_of(' ');
1910b57cec5SDimitry Andric       Rest = Rest.substr(n3);
1920b57cec5SDimitry Andric       n3 = Rest.find_first_of(':');
1930b57cec5SDimitry Andric       if (n3 == StringRef::npos || n3 == 0)
1940b57cec5SDimitry Andric         return false;
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric       StringRef Target;
1970b57cec5SDimitry Andric       uint64_t count, n4;
1980b57cec5SDimitry Andric       while (true) {
1990b57cec5SDimitry Andric         // Get the segment after the current colon.
2000b57cec5SDimitry Andric         StringRef AfterColon = Rest.substr(n3 + 1);
2010b57cec5SDimitry Andric         // Get the target symbol before the current colon.
2020b57cec5SDimitry Andric         Target = Rest.substr(0, n3);
2030b57cec5SDimitry Andric         // Check if the word after the current colon is an integer.
2040b57cec5SDimitry Andric         n4 = AfterColon.find_first_of(' ');
2050b57cec5SDimitry Andric         n4 = (n4 != StringRef::npos) ? n3 + n4 + 1 : Rest.size();
2060b57cec5SDimitry Andric         StringRef WordAfterColon = Rest.substr(n3 + 1, n4 - n3 - 1);
2070b57cec5SDimitry Andric         if (!WordAfterColon.getAsInteger(10, count))
2080b57cec5SDimitry Andric           break;
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric         // Try to find the next colon.
2110b57cec5SDimitry Andric         uint64_t n5 = AfterColon.find_first_of(':');
2120b57cec5SDimitry Andric         if (n5 == StringRef::npos)
2130b57cec5SDimitry Andric           return false;
2140b57cec5SDimitry Andric         n3 += n5 + 1;
2150b57cec5SDimitry Andric       }
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric       // An anchor point is found. Save the {target, count} pair
2180b57cec5SDimitry Andric       TargetCountMap[Target] = count;
2190b57cec5SDimitry Andric       if (n4 == Rest.size())
2200b57cec5SDimitry Andric         break;
2210b57cec5SDimitry Andric       // Change n3 to the next blank space after colon + integer pair.
2220b57cec5SDimitry Andric       n3 = n4;
2230b57cec5SDimitry Andric     }
2240b57cec5SDimitry Andric   } else {
225af732203SDimitry Andric     LineTy = LineType::CallSiteProfile;
2260b57cec5SDimitry Andric     size_t n3 = Rest.find_last_of(':');
2270b57cec5SDimitry Andric     CalleeName = Rest.substr(0, n3);
2280b57cec5SDimitry Andric     if (Rest.substr(n3 + 1).getAsInteger(10, NumSamples))
2290b57cec5SDimitry Andric       return false;
2300b57cec5SDimitry Andric   }
2310b57cec5SDimitry Andric   return true;
2320b57cec5SDimitry Andric }
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric /// Load samples from a text file.
2350b57cec5SDimitry Andric ///
2360b57cec5SDimitry Andric /// See the documentation at the top of the file for an explanation of
2370b57cec5SDimitry Andric /// the expected format.
2380b57cec5SDimitry Andric ///
2390b57cec5SDimitry Andric /// \returns true if the file was loaded successfully, false otherwise.
readImpl()2408bcb0991SDimitry Andric std::error_code SampleProfileReaderText::readImpl() {
2410b57cec5SDimitry Andric   line_iterator LineIt(*Buffer, /*SkipBlanks=*/true, '#');
2420b57cec5SDimitry Andric   sampleprof_error Result = sampleprof_error::success;
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric   InlineCallStack InlineStack;
245af732203SDimitry Andric   uint32_t ProbeProfileCount = 0;
246af732203SDimitry Andric 
247af732203SDimitry Andric   // SeenMetadata tracks whether we have processed metadata for the current
248af732203SDimitry Andric   // top-level function profile.
249af732203SDimitry Andric   bool SeenMetadata = false;
2500b57cec5SDimitry Andric 
251*5f7ddb14SDimitry Andric   ProfileIsFS = ProfileIsFSDisciminator;
2520b57cec5SDimitry Andric   for (; !LineIt.is_at_eof(); ++LineIt) {
2530b57cec5SDimitry Andric     if ((*LineIt)[(*LineIt).find_first_not_of(' ')] == '#')
2540b57cec5SDimitry Andric       continue;
2550b57cec5SDimitry Andric     // Read the header of each function.
2560b57cec5SDimitry Andric     //
2570b57cec5SDimitry Andric     // Note that for function identifiers we are actually expecting
2580b57cec5SDimitry Andric     // mangled names, but we may not always get them. This happens when
2590b57cec5SDimitry Andric     // the compiler decides not to emit the function (e.g., it was inlined
2600b57cec5SDimitry Andric     // and removed). In this case, the binary will not have the linkage
2610b57cec5SDimitry Andric     // name for the function, so the profiler will emit the function's
2620b57cec5SDimitry Andric     // unmangled name, which may contain characters like ':' and '>' in its
2630b57cec5SDimitry Andric     // name (member functions, templates, etc).
2640b57cec5SDimitry Andric     //
2650b57cec5SDimitry Andric     // The only requirement we place on the identifier, then, is that it
2660b57cec5SDimitry Andric     // should not begin with a number.
2670b57cec5SDimitry Andric     if ((*LineIt)[0] != ' ') {
2680b57cec5SDimitry Andric       uint64_t NumSamples, NumHeadSamples;
2690b57cec5SDimitry Andric       StringRef FName;
2700b57cec5SDimitry Andric       if (!ParseHead(*LineIt, FName, NumSamples, NumHeadSamples)) {
2710b57cec5SDimitry Andric         reportError(LineIt.line_number(),
2720b57cec5SDimitry Andric                     "Expected 'mangled_name:NUM:NUM', found " + *LineIt);
2730b57cec5SDimitry Andric         return sampleprof_error::malformed;
2740b57cec5SDimitry Andric       }
275af732203SDimitry Andric       SeenMetadata = false;
276af732203SDimitry Andric       SampleContext FContext(FName);
277af732203SDimitry Andric       if (FContext.hasContext())
278af732203SDimitry Andric         ++CSProfileCount;
279af732203SDimitry Andric       Profiles[FContext] = FunctionSamples();
280af732203SDimitry Andric       FunctionSamples &FProfile = Profiles[FContext];
281af732203SDimitry Andric       FProfile.setName(FContext.getNameWithoutContext());
282af732203SDimitry Andric       FProfile.setContext(FContext);
2830b57cec5SDimitry Andric       MergeResult(Result, FProfile.addTotalSamples(NumSamples));
2840b57cec5SDimitry Andric       MergeResult(Result, FProfile.addHeadSamples(NumHeadSamples));
2850b57cec5SDimitry Andric       InlineStack.clear();
2860b57cec5SDimitry Andric       InlineStack.push_back(&FProfile);
2870b57cec5SDimitry Andric     } else {
2880b57cec5SDimitry Andric       uint64_t NumSamples;
2890b57cec5SDimitry Andric       StringRef FName;
2900b57cec5SDimitry Andric       DenseMap<StringRef, uint64_t> TargetCountMap;
2910b57cec5SDimitry Andric       uint32_t Depth, LineOffset, Discriminator;
292af732203SDimitry Andric       LineType LineTy;
293*5f7ddb14SDimitry Andric       uint64_t FunctionHash = 0;
294*5f7ddb14SDimitry Andric       uint32_t Attributes = 0;
295af732203SDimitry Andric       if (!ParseLine(*LineIt, LineTy, Depth, NumSamples, LineOffset,
296*5f7ddb14SDimitry Andric                      Discriminator, FName, TargetCountMap, FunctionHash,
297*5f7ddb14SDimitry Andric                      Attributes)) {
2980b57cec5SDimitry Andric         reportError(LineIt.line_number(),
2990b57cec5SDimitry Andric                     "Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found " +
3000b57cec5SDimitry Andric                         *LineIt);
3010b57cec5SDimitry Andric         return sampleprof_error::malformed;
3020b57cec5SDimitry Andric       }
303af732203SDimitry Andric       if (SeenMetadata && LineTy != LineType::Metadata) {
304af732203SDimitry Andric         // Metadata must be put at the end of a function profile.
305af732203SDimitry Andric         reportError(LineIt.line_number(),
306af732203SDimitry Andric                     "Found non-metadata after metadata: " + *LineIt);
307af732203SDimitry Andric         return sampleprof_error::malformed;
308af732203SDimitry Andric       }
309*5f7ddb14SDimitry Andric 
310*5f7ddb14SDimitry Andric       // Here we handle FS discriminators.
311*5f7ddb14SDimitry Andric       Discriminator &= getDiscriminatorMask();
312*5f7ddb14SDimitry Andric 
3130b57cec5SDimitry Andric       while (InlineStack.size() > Depth) {
3140b57cec5SDimitry Andric         InlineStack.pop_back();
3150b57cec5SDimitry Andric       }
316af732203SDimitry Andric       switch (LineTy) {
317af732203SDimitry Andric       case LineType::CallSiteProfile: {
3180b57cec5SDimitry Andric         FunctionSamples &FSamples = InlineStack.back()->functionSamplesAt(
3195ffd83dbSDimitry Andric             LineLocation(LineOffset, Discriminator))[std::string(FName)];
3200b57cec5SDimitry Andric         FSamples.setName(FName);
3210b57cec5SDimitry Andric         MergeResult(Result, FSamples.addTotalSamples(NumSamples));
3220b57cec5SDimitry Andric         InlineStack.push_back(&FSamples);
323af732203SDimitry Andric         break;
324af732203SDimitry Andric       }
325af732203SDimitry Andric       case LineType::BodyProfile: {
3260b57cec5SDimitry Andric         while (InlineStack.size() > Depth) {
3270b57cec5SDimitry Andric           InlineStack.pop_back();
3280b57cec5SDimitry Andric         }
3290b57cec5SDimitry Andric         FunctionSamples &FProfile = *InlineStack.back();
3300b57cec5SDimitry Andric         for (const auto &name_count : TargetCountMap) {
3310b57cec5SDimitry Andric           MergeResult(Result, FProfile.addCalledTargetSamples(
3320b57cec5SDimitry Andric                                   LineOffset, Discriminator, name_count.first,
3330b57cec5SDimitry Andric                                   name_count.second));
3340b57cec5SDimitry Andric         }
3350b57cec5SDimitry Andric         MergeResult(Result, FProfile.addBodySamples(LineOffset, Discriminator,
3360b57cec5SDimitry Andric                                                     NumSamples));
337af732203SDimitry Andric         break;
338af732203SDimitry Andric       }
339af732203SDimitry Andric       case LineType::Metadata: {
340af732203SDimitry Andric         FunctionSamples &FProfile = *InlineStack.back();
341*5f7ddb14SDimitry Andric         if (FunctionHash) {
342af732203SDimitry Andric           FProfile.setFunctionHash(FunctionHash);
343af732203SDimitry Andric           ++ProbeProfileCount;
344*5f7ddb14SDimitry Andric         }
345*5f7ddb14SDimitry Andric         if (Attributes)
346*5f7ddb14SDimitry Andric           FProfile.getContext().setAllAttributes(Attributes);
347af732203SDimitry Andric         SeenMetadata = true;
348af732203SDimitry Andric         break;
3490b57cec5SDimitry Andric       }
3500b57cec5SDimitry Andric       }
3510b57cec5SDimitry Andric     }
352af732203SDimitry Andric   }
353af732203SDimitry Andric 
354af732203SDimitry Andric   assert((CSProfileCount == 0 || CSProfileCount == Profiles.size()) &&
355af732203SDimitry Andric          "Cannot have both context-sensitive and regular profile");
356af732203SDimitry Andric   ProfileIsCS = (CSProfileCount > 0);
357af732203SDimitry Andric   assert((ProbeProfileCount == 0 || ProbeProfileCount == Profiles.size()) &&
358af732203SDimitry Andric          "Cannot have both probe-based profiles and regular profiles");
359af732203SDimitry Andric   ProfileIsProbeBased = (ProbeProfileCount > 0);
360af732203SDimitry Andric   FunctionSamples::ProfileIsProbeBased = ProfileIsProbeBased;
361af732203SDimitry Andric   FunctionSamples::ProfileIsCS = ProfileIsCS;
362af732203SDimitry Andric 
3630b57cec5SDimitry Andric   if (Result == sampleprof_error::success)
3640b57cec5SDimitry Andric     computeSummary();
3650b57cec5SDimitry Andric 
3660b57cec5SDimitry Andric   return Result;
3670b57cec5SDimitry Andric }
3680b57cec5SDimitry Andric 
hasFormat(const MemoryBuffer & Buffer)3690b57cec5SDimitry Andric bool SampleProfileReaderText::hasFormat(const MemoryBuffer &Buffer) {
3700b57cec5SDimitry Andric   bool result = false;
3710b57cec5SDimitry Andric 
3720b57cec5SDimitry Andric   // Check that the first non-comment line is a valid function header.
3730b57cec5SDimitry Andric   line_iterator LineIt(Buffer, /*SkipBlanks=*/true, '#');
3740b57cec5SDimitry Andric   if (!LineIt.is_at_eof()) {
3750b57cec5SDimitry Andric     if ((*LineIt)[0] != ' ') {
3760b57cec5SDimitry Andric       uint64_t NumSamples, NumHeadSamples;
3770b57cec5SDimitry Andric       StringRef FName;
3780b57cec5SDimitry Andric       result = ParseHead(*LineIt, FName, NumSamples, NumHeadSamples);
3790b57cec5SDimitry Andric     }
3800b57cec5SDimitry Andric   }
3810b57cec5SDimitry Andric 
3820b57cec5SDimitry Andric   return result;
3830b57cec5SDimitry Andric }
3840b57cec5SDimitry Andric 
readNumber()3850b57cec5SDimitry Andric template <typename T> ErrorOr<T> SampleProfileReaderBinary::readNumber() {
3860b57cec5SDimitry Andric   unsigned NumBytesRead = 0;
3870b57cec5SDimitry Andric   std::error_code EC;
3880b57cec5SDimitry Andric   uint64_t Val = decodeULEB128(Data, &NumBytesRead);
3890b57cec5SDimitry Andric 
3900b57cec5SDimitry Andric   if (Val > std::numeric_limits<T>::max())
3910b57cec5SDimitry Andric     EC = sampleprof_error::malformed;
3920b57cec5SDimitry Andric   else if (Data + NumBytesRead > End)
3930b57cec5SDimitry Andric     EC = sampleprof_error::truncated;
3940b57cec5SDimitry Andric   else
3950b57cec5SDimitry Andric     EC = sampleprof_error::success;
3960b57cec5SDimitry Andric 
3970b57cec5SDimitry Andric   if (EC) {
3980b57cec5SDimitry Andric     reportError(0, EC.message());
3990b57cec5SDimitry Andric     return EC;
4000b57cec5SDimitry Andric   }
4010b57cec5SDimitry Andric 
4020b57cec5SDimitry Andric   Data += NumBytesRead;
4030b57cec5SDimitry Andric   return static_cast<T>(Val);
4040b57cec5SDimitry Andric }
4050b57cec5SDimitry Andric 
readString()4060b57cec5SDimitry Andric ErrorOr<StringRef> SampleProfileReaderBinary::readString() {
4070b57cec5SDimitry Andric   std::error_code EC;
4080b57cec5SDimitry Andric   StringRef Str(reinterpret_cast<const char *>(Data));
4090b57cec5SDimitry Andric   if (Data + Str.size() + 1 > End) {
4100b57cec5SDimitry Andric     EC = sampleprof_error::truncated;
4110b57cec5SDimitry Andric     reportError(0, EC.message());
4120b57cec5SDimitry Andric     return EC;
4130b57cec5SDimitry Andric   }
4140b57cec5SDimitry Andric 
4150b57cec5SDimitry Andric   Data += Str.size() + 1;
4160b57cec5SDimitry Andric   return Str;
4170b57cec5SDimitry Andric }
4180b57cec5SDimitry Andric 
4190b57cec5SDimitry Andric template <typename T>
readUnencodedNumber()4200b57cec5SDimitry Andric ErrorOr<T> SampleProfileReaderBinary::readUnencodedNumber() {
4210b57cec5SDimitry Andric   std::error_code EC;
4220b57cec5SDimitry Andric 
4230b57cec5SDimitry Andric   if (Data + sizeof(T) > End) {
4240b57cec5SDimitry Andric     EC = sampleprof_error::truncated;
4250b57cec5SDimitry Andric     reportError(0, EC.message());
4260b57cec5SDimitry Andric     return EC;
4270b57cec5SDimitry Andric   }
4280b57cec5SDimitry Andric 
4290b57cec5SDimitry Andric   using namespace support;
4300b57cec5SDimitry Andric   T Val = endian::readNext<T, little, unaligned>(Data);
4310b57cec5SDimitry Andric   return Val;
4320b57cec5SDimitry Andric }
4330b57cec5SDimitry Andric 
4340b57cec5SDimitry Andric template <typename T>
readStringIndex(T & Table)4350b57cec5SDimitry Andric inline ErrorOr<uint32_t> SampleProfileReaderBinary::readStringIndex(T &Table) {
4360b57cec5SDimitry Andric   std::error_code EC;
4370b57cec5SDimitry Andric   auto Idx = readNumber<uint32_t>();
4380b57cec5SDimitry Andric   if (std::error_code EC = Idx.getError())
4390b57cec5SDimitry Andric     return EC;
4400b57cec5SDimitry Andric   if (*Idx >= Table.size())
4410b57cec5SDimitry Andric     return sampleprof_error::truncated_name_table;
4420b57cec5SDimitry Andric   return *Idx;
4430b57cec5SDimitry Andric }
4440b57cec5SDimitry Andric 
readStringFromTable()4458bcb0991SDimitry Andric ErrorOr<StringRef> SampleProfileReaderBinary::readStringFromTable() {
4460b57cec5SDimitry Andric   auto Idx = readStringIndex(NameTable);
4470b57cec5SDimitry Andric   if (std::error_code EC = Idx.getError())
4480b57cec5SDimitry Andric     return EC;
4490b57cec5SDimitry Andric 
4500b57cec5SDimitry Andric   return NameTable[*Idx];
4510b57cec5SDimitry Andric }
4520b57cec5SDimitry Andric 
readStringFromTable()453af732203SDimitry Andric ErrorOr<StringRef> SampleProfileReaderExtBinaryBase::readStringFromTable() {
454af732203SDimitry Andric   if (!FixedLengthMD5)
455af732203SDimitry Andric     return SampleProfileReaderBinary::readStringFromTable();
456af732203SDimitry Andric 
457af732203SDimitry Andric   // read NameTable index.
458af732203SDimitry Andric   auto Idx = readStringIndex(NameTable);
459af732203SDimitry Andric   if (std::error_code EC = Idx.getError())
460af732203SDimitry Andric     return EC;
461af732203SDimitry Andric 
462af732203SDimitry Andric   // Check whether the name to be accessed has been accessed before,
463af732203SDimitry Andric   // if not, read it from memory directly.
464af732203SDimitry Andric   StringRef &SR = NameTable[*Idx];
465af732203SDimitry Andric   if (SR.empty()) {
466af732203SDimitry Andric     const uint8_t *SavedData = Data;
467af732203SDimitry Andric     Data = MD5NameMemStart + ((*Idx) * sizeof(uint64_t));
468af732203SDimitry Andric     auto FID = readUnencodedNumber<uint64_t>();
469af732203SDimitry Andric     if (std::error_code EC = FID.getError())
470af732203SDimitry Andric       return EC;
471af732203SDimitry Andric     // Save the string converted from uint64_t in MD5StringBuf. All the
472af732203SDimitry Andric     // references to the name are all StringRefs refering to the string
473af732203SDimitry Andric     // in MD5StringBuf.
474af732203SDimitry Andric     MD5StringBuf->push_back(std::to_string(*FID));
475af732203SDimitry Andric     SR = MD5StringBuf->back();
476af732203SDimitry Andric     Data = SavedData;
477af732203SDimitry Andric   }
478af732203SDimitry Andric   return SR;
479af732203SDimitry Andric }
480af732203SDimitry Andric 
readStringFromTable()4810b57cec5SDimitry Andric ErrorOr<StringRef> SampleProfileReaderCompactBinary::readStringFromTable() {
4820b57cec5SDimitry Andric   auto Idx = readStringIndex(NameTable);
4830b57cec5SDimitry Andric   if (std::error_code EC = Idx.getError())
4840b57cec5SDimitry Andric     return EC;
4850b57cec5SDimitry Andric 
4860b57cec5SDimitry Andric   return StringRef(NameTable[*Idx]);
4870b57cec5SDimitry Andric }
4880b57cec5SDimitry Andric 
4890b57cec5SDimitry Andric std::error_code
readProfile(FunctionSamples & FProfile)4900b57cec5SDimitry Andric SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) {
4910b57cec5SDimitry Andric   auto NumSamples = readNumber<uint64_t>();
4920b57cec5SDimitry Andric   if (std::error_code EC = NumSamples.getError())
4930b57cec5SDimitry Andric     return EC;
4940b57cec5SDimitry Andric   FProfile.addTotalSamples(*NumSamples);
4950b57cec5SDimitry Andric 
4960b57cec5SDimitry Andric   // Read the samples in the body.
4970b57cec5SDimitry Andric   auto NumRecords = readNumber<uint32_t>();
4980b57cec5SDimitry Andric   if (std::error_code EC = NumRecords.getError())
4990b57cec5SDimitry Andric     return EC;
5000b57cec5SDimitry Andric 
5010b57cec5SDimitry Andric   for (uint32_t I = 0; I < *NumRecords; ++I) {
5020b57cec5SDimitry Andric     auto LineOffset = readNumber<uint64_t>();
5030b57cec5SDimitry Andric     if (std::error_code EC = LineOffset.getError())
5040b57cec5SDimitry Andric       return EC;
5050b57cec5SDimitry Andric 
5060b57cec5SDimitry Andric     if (!isOffsetLegal(*LineOffset)) {
5070b57cec5SDimitry Andric       return std::error_code();
5080b57cec5SDimitry Andric     }
5090b57cec5SDimitry Andric 
5100b57cec5SDimitry Andric     auto Discriminator = readNumber<uint64_t>();
5110b57cec5SDimitry Andric     if (std::error_code EC = Discriminator.getError())
5120b57cec5SDimitry Andric       return EC;
5130b57cec5SDimitry Andric 
5140b57cec5SDimitry Andric     auto NumSamples = readNumber<uint64_t>();
5150b57cec5SDimitry Andric     if (std::error_code EC = NumSamples.getError())
5160b57cec5SDimitry Andric       return EC;
5170b57cec5SDimitry Andric 
5180b57cec5SDimitry Andric     auto NumCalls = readNumber<uint32_t>();
5190b57cec5SDimitry Andric     if (std::error_code EC = NumCalls.getError())
5200b57cec5SDimitry Andric       return EC;
5210b57cec5SDimitry Andric 
522*5f7ddb14SDimitry Andric     // Here we handle FS discriminators:
523*5f7ddb14SDimitry Andric     uint32_t DiscriminatorVal = (*Discriminator) & getDiscriminatorMask();
524*5f7ddb14SDimitry Andric 
5250b57cec5SDimitry Andric     for (uint32_t J = 0; J < *NumCalls; ++J) {
5260b57cec5SDimitry Andric       auto CalledFunction(readStringFromTable());
5270b57cec5SDimitry Andric       if (std::error_code EC = CalledFunction.getError())
5280b57cec5SDimitry Andric         return EC;
5290b57cec5SDimitry Andric 
5300b57cec5SDimitry Andric       auto CalledFunctionSamples = readNumber<uint64_t>();
5310b57cec5SDimitry Andric       if (std::error_code EC = CalledFunctionSamples.getError())
5320b57cec5SDimitry Andric         return EC;
5330b57cec5SDimitry Andric 
534*5f7ddb14SDimitry Andric       FProfile.addCalledTargetSamples(*LineOffset, DiscriminatorVal,
5350b57cec5SDimitry Andric                                       *CalledFunction, *CalledFunctionSamples);
5360b57cec5SDimitry Andric     }
5370b57cec5SDimitry Andric 
538*5f7ddb14SDimitry Andric     FProfile.addBodySamples(*LineOffset, DiscriminatorVal, *NumSamples);
5390b57cec5SDimitry Andric   }
5400b57cec5SDimitry Andric 
5410b57cec5SDimitry Andric   // Read all the samples for inlined function calls.
5420b57cec5SDimitry Andric   auto NumCallsites = readNumber<uint32_t>();
5430b57cec5SDimitry Andric   if (std::error_code EC = NumCallsites.getError())
5440b57cec5SDimitry Andric     return EC;
5450b57cec5SDimitry Andric 
5460b57cec5SDimitry Andric   for (uint32_t J = 0; J < *NumCallsites; ++J) {
5470b57cec5SDimitry Andric     auto LineOffset = readNumber<uint64_t>();
5480b57cec5SDimitry Andric     if (std::error_code EC = LineOffset.getError())
5490b57cec5SDimitry Andric       return EC;
5500b57cec5SDimitry Andric 
5510b57cec5SDimitry Andric     auto Discriminator = readNumber<uint64_t>();
5520b57cec5SDimitry Andric     if (std::error_code EC = Discriminator.getError())
5530b57cec5SDimitry Andric       return EC;
5540b57cec5SDimitry Andric 
5550b57cec5SDimitry Andric     auto FName(readStringFromTable());
5560b57cec5SDimitry Andric     if (std::error_code EC = FName.getError())
5570b57cec5SDimitry Andric       return EC;
5580b57cec5SDimitry Andric 
559*5f7ddb14SDimitry Andric     // Here we handle FS discriminators:
560*5f7ddb14SDimitry Andric     uint32_t DiscriminatorVal = (*Discriminator) & getDiscriminatorMask();
561*5f7ddb14SDimitry Andric 
5620b57cec5SDimitry Andric     FunctionSamples &CalleeProfile = FProfile.functionSamplesAt(
563*5f7ddb14SDimitry Andric         LineLocation(*LineOffset, DiscriminatorVal))[std::string(*FName)];
5640b57cec5SDimitry Andric     CalleeProfile.setName(*FName);
5650b57cec5SDimitry Andric     if (std::error_code EC = readProfile(CalleeProfile))
5660b57cec5SDimitry Andric       return EC;
5670b57cec5SDimitry Andric   }
5680b57cec5SDimitry Andric 
5690b57cec5SDimitry Andric   return sampleprof_error::success;
5700b57cec5SDimitry Andric }
5710b57cec5SDimitry Andric 
5728bcb0991SDimitry Andric std::error_code
readFuncProfile(const uint8_t * Start)5738bcb0991SDimitry Andric SampleProfileReaderBinary::readFuncProfile(const uint8_t *Start) {
5748bcb0991SDimitry Andric   Data = Start;
5750b57cec5SDimitry Andric   auto NumHeadSamples = readNumber<uint64_t>();
5760b57cec5SDimitry Andric   if (std::error_code EC = NumHeadSamples.getError())
5770b57cec5SDimitry Andric     return EC;
5780b57cec5SDimitry Andric 
5790b57cec5SDimitry Andric   auto FName(readStringFromTable());
5800b57cec5SDimitry Andric   if (std::error_code EC = FName.getError())
5810b57cec5SDimitry Andric     return EC;
5820b57cec5SDimitry Andric 
583af732203SDimitry Andric   SampleContext FContext(*FName);
584af732203SDimitry Andric   Profiles[FContext] = FunctionSamples();
585af732203SDimitry Andric   FunctionSamples &FProfile = Profiles[FContext];
586af732203SDimitry Andric   FProfile.setName(FContext.getNameWithoutContext());
587af732203SDimitry Andric   FProfile.setContext(FContext);
5880b57cec5SDimitry Andric   FProfile.addHeadSamples(*NumHeadSamples);
5890b57cec5SDimitry Andric 
590af732203SDimitry Andric   if (FContext.hasContext())
591af732203SDimitry Andric     CSProfileCount++;
592af732203SDimitry Andric 
5930b57cec5SDimitry Andric   if (std::error_code EC = readProfile(FProfile))
5940b57cec5SDimitry Andric     return EC;
5950b57cec5SDimitry Andric   return sampleprof_error::success;
5960b57cec5SDimitry Andric }
5970b57cec5SDimitry Andric 
readImpl()5988bcb0991SDimitry Andric std::error_code SampleProfileReaderBinary::readImpl() {
599*5f7ddb14SDimitry Andric   ProfileIsFS = ProfileIsFSDisciminator;
6000b57cec5SDimitry Andric   while (!at_eof()) {
6018bcb0991SDimitry Andric     if (std::error_code EC = readFuncProfile(Data))
6020b57cec5SDimitry Andric       return EC;
6030b57cec5SDimitry Andric   }
6040b57cec5SDimitry Andric 
6050b57cec5SDimitry Andric   return sampleprof_error::success;
6060b57cec5SDimitry Andric }
6070b57cec5SDimitry Andric 
readOneSection(const uint8_t * Start,uint64_t Size,const SecHdrTableEntry & Entry)608af732203SDimitry Andric std::error_code SampleProfileReaderExtBinaryBase::readOneSection(
6095ffd83dbSDimitry Andric     const uint8_t *Start, uint64_t Size, const SecHdrTableEntry &Entry) {
6108bcb0991SDimitry Andric   Data = Start;
6118bcb0991SDimitry Andric   End = Start + Size;
6125ffd83dbSDimitry Andric   switch (Entry.Type) {
6138bcb0991SDimitry Andric   case SecProfSummary:
6148bcb0991SDimitry Andric     if (std::error_code EC = readSummary())
6158bcb0991SDimitry Andric       return EC;
6165ffd83dbSDimitry Andric     if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagPartial))
6175ffd83dbSDimitry Andric       Summary->setPartialProfile(true);
618*5f7ddb14SDimitry Andric     if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagFullContext))
619*5f7ddb14SDimitry Andric       FunctionSamples::ProfileIsCS = ProfileIsCS = true;
620*5f7ddb14SDimitry Andric     if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagFSDiscriminator))
621*5f7ddb14SDimitry Andric       FunctionSamples::ProfileIsFS = ProfileIsFS = true;
6228bcb0991SDimitry Andric     break;
623af732203SDimitry Andric   case SecNameTable: {
624af732203SDimitry Andric     FixedLengthMD5 =
625af732203SDimitry Andric         hasSecFlag(Entry, SecNameTableFlags::SecFlagFixedLengthMD5);
626af732203SDimitry Andric     bool UseMD5 = hasSecFlag(Entry, SecNameTableFlags::SecFlagMD5Name);
627af732203SDimitry Andric     assert((!FixedLengthMD5 || UseMD5) &&
628af732203SDimitry Andric            "If FixedLengthMD5 is true, UseMD5 has to be true");
629*5f7ddb14SDimitry Andric     FunctionSamples::HasUniqSuffix =
630*5f7ddb14SDimitry Andric         hasSecFlag(Entry, SecNameTableFlags::SecFlagUniqSuffix);
631af732203SDimitry Andric     if (std::error_code EC = readNameTableSec(UseMD5))
6328bcb0991SDimitry Andric       return EC;
6338bcb0991SDimitry Andric     break;
634af732203SDimitry Andric   }
6358bcb0991SDimitry Andric   case SecLBRProfile:
6368bcb0991SDimitry Andric     if (std::error_code EC = readFuncProfiles())
6378bcb0991SDimitry Andric       return EC;
6388bcb0991SDimitry Andric     break;
6398bcb0991SDimitry Andric   case SecFuncOffsetTable:
6408bcb0991SDimitry Andric     if (std::error_code EC = readFuncOffsetTable())
6418bcb0991SDimitry Andric       return EC;
6428bcb0991SDimitry Andric     break;
643*5f7ddb14SDimitry Andric   case SecFuncMetadata: {
644af732203SDimitry Andric     ProfileIsProbeBased =
645af732203SDimitry Andric         hasSecFlag(Entry, SecFuncMetadataFlags::SecFlagIsProbeBased);
646af732203SDimitry Andric     FunctionSamples::ProfileIsProbeBased = ProfileIsProbeBased;
647*5f7ddb14SDimitry Andric     bool HasAttribute =
648*5f7ddb14SDimitry Andric         hasSecFlag(Entry, SecFuncMetadataFlags::SecFlagHasAttribute);
649*5f7ddb14SDimitry Andric     if (std::error_code EC = readFuncMetadata(HasAttribute))
650af732203SDimitry Andric       return EC;
651af732203SDimitry Andric     break;
652*5f7ddb14SDimitry Andric   }
653af732203SDimitry Andric   case SecProfileSymbolList:
654af732203SDimitry Andric     if (std::error_code EC = readProfileSymbolList())
655af732203SDimitry Andric       return EC;
656af732203SDimitry Andric     break;
6578bcb0991SDimitry Andric   default:
658af732203SDimitry Andric     if (std::error_code EC = readCustomSection(Entry))
659af732203SDimitry Andric       return EC;
6608bcb0991SDimitry Andric     break;
6618bcb0991SDimitry Andric   }
6628bcb0991SDimitry Andric   return sampleprof_error::success;
6638bcb0991SDimitry Andric }
6648bcb0991SDimitry Andric 
collectFuncsFromModule()665*5f7ddb14SDimitry Andric bool SampleProfileReaderExtBinaryBase::collectFuncsFromModule() {
666*5f7ddb14SDimitry Andric   if (!M)
667*5f7ddb14SDimitry Andric     return false;
6688bcb0991SDimitry Andric   FuncsToUse.clear();
669*5f7ddb14SDimitry Andric   for (auto &F : *M)
6708bcb0991SDimitry Andric     FuncsToUse.insert(FunctionSamples::getCanonicalFnName(F));
671*5f7ddb14SDimitry Andric   return true;
6728bcb0991SDimitry Andric }
6738bcb0991SDimitry Andric 
readFuncOffsetTable()674af732203SDimitry Andric std::error_code SampleProfileReaderExtBinaryBase::readFuncOffsetTable() {
675af732203SDimitry Andric   // If there are more than one FuncOffsetTable, the profile read associated
676af732203SDimitry Andric   // with previous FuncOffsetTable has to be done before next FuncOffsetTable
677af732203SDimitry Andric   // is read.
678af732203SDimitry Andric   FuncOffsetTable.clear();
679af732203SDimitry Andric 
6808bcb0991SDimitry Andric   auto Size = readNumber<uint64_t>();
6818bcb0991SDimitry Andric   if (std::error_code EC = Size.getError())
6828bcb0991SDimitry Andric     return EC;
6838bcb0991SDimitry Andric 
6848bcb0991SDimitry Andric   FuncOffsetTable.reserve(*Size);
6858bcb0991SDimitry Andric   for (uint32_t I = 0; I < *Size; ++I) {
6868bcb0991SDimitry Andric     auto FName(readStringFromTable());
6878bcb0991SDimitry Andric     if (std::error_code EC = FName.getError())
6888bcb0991SDimitry Andric       return EC;
6898bcb0991SDimitry Andric 
6908bcb0991SDimitry Andric     auto Offset = readNumber<uint64_t>();
6918bcb0991SDimitry Andric     if (std::error_code EC = Offset.getError())
6928bcb0991SDimitry Andric       return EC;
6938bcb0991SDimitry Andric 
6948bcb0991SDimitry Andric     FuncOffsetTable[*FName] = *Offset;
6958bcb0991SDimitry Andric   }
6968bcb0991SDimitry Andric   return sampleprof_error::success;
6978bcb0991SDimitry Andric }
6988bcb0991SDimitry Andric 
readFuncProfiles()699af732203SDimitry Andric std::error_code SampleProfileReaderExtBinaryBase::readFuncProfiles() {
700*5f7ddb14SDimitry Andric   // Collect functions used by current module if the Reader has been
701*5f7ddb14SDimitry Andric   // given a module.
702*5f7ddb14SDimitry Andric   // collectFuncsFromModule uses FunctionSamples::getCanonicalFnName
703*5f7ddb14SDimitry Andric   // which will query FunctionSamples::HasUniqSuffix, so it has to be
704*5f7ddb14SDimitry Andric   // called after FunctionSamples::HasUniqSuffix is set, i.e. after
705*5f7ddb14SDimitry Andric   // NameTable section is read.
706*5f7ddb14SDimitry Andric   bool LoadFuncsToBeUsed = collectFuncsFromModule();
707*5f7ddb14SDimitry Andric 
708*5f7ddb14SDimitry Andric   // When LoadFuncsToBeUsed is false, load all the function profiles.
7098bcb0991SDimitry Andric   const uint8_t *Start = Data;
710*5f7ddb14SDimitry Andric   if (!LoadFuncsToBeUsed) {
7118bcb0991SDimitry Andric     while (Data < End) {
7128bcb0991SDimitry Andric       if (std::error_code EC = readFuncProfile(Data))
7138bcb0991SDimitry Andric         return EC;
7148bcb0991SDimitry Andric     }
7158bcb0991SDimitry Andric     assert(Data == End && "More data is read than expected");
716af732203SDimitry Andric   } else {
717*5f7ddb14SDimitry Andric     // Load function profiles on demand.
7188bcb0991SDimitry Andric     if (Remapper) {
7198bcb0991SDimitry Andric       for (auto Name : FuncsToUse) {
7208bcb0991SDimitry Andric         Remapper->insert(Name);
7218bcb0991SDimitry Andric       }
7228bcb0991SDimitry Andric     }
7238bcb0991SDimitry Andric 
7245ffd83dbSDimitry Andric     if (useMD5()) {
7255ffd83dbSDimitry Andric       for (auto Name : FuncsToUse) {
7265ffd83dbSDimitry Andric         auto GUID = std::to_string(MD5Hash(Name));
7275ffd83dbSDimitry Andric         auto iter = FuncOffsetTable.find(StringRef(GUID));
7285ffd83dbSDimitry Andric         if (iter == FuncOffsetTable.end())
7295ffd83dbSDimitry Andric           continue;
7305ffd83dbSDimitry Andric         const uint8_t *FuncProfileAddr = Start + iter->second;
7315ffd83dbSDimitry Andric         assert(FuncProfileAddr < End && "out of LBRProfile section");
7325ffd83dbSDimitry Andric         if (std::error_code EC = readFuncProfile(FuncProfileAddr))
7335ffd83dbSDimitry Andric           return EC;
7345ffd83dbSDimitry Andric       }
735*5f7ddb14SDimitry Andric     } else if (FunctionSamples::ProfileIsCS) {
736*5f7ddb14SDimitry Andric       // Compute the ordered set of names, so we can
737*5f7ddb14SDimitry Andric       // get all context profiles under a subtree by
738*5f7ddb14SDimitry Andric       // iterating through the ordered names.
739*5f7ddb14SDimitry Andric       struct Comparer {
740*5f7ddb14SDimitry Andric         // Ignore the closing ']' when ordering context
741*5f7ddb14SDimitry Andric         bool operator()(const StringRef &L, const StringRef &R) const {
742*5f7ddb14SDimitry Andric           return L.substr(0, L.size() - 1) < R.substr(0, R.size() - 1);
743*5f7ddb14SDimitry Andric         }
744*5f7ddb14SDimitry Andric       };
745*5f7ddb14SDimitry Andric       std::set<StringRef, Comparer> OrderedNames;
746*5f7ddb14SDimitry Andric       for (auto Name : FuncOffsetTable) {
747*5f7ddb14SDimitry Andric         OrderedNames.insert(Name.first);
748*5f7ddb14SDimitry Andric       }
749*5f7ddb14SDimitry Andric 
750*5f7ddb14SDimitry Andric       // For each function in current module, load all
751*5f7ddb14SDimitry Andric       // context profiles for the function.
752*5f7ddb14SDimitry Andric       for (auto NameOffset : FuncOffsetTable) {
753*5f7ddb14SDimitry Andric         StringRef ContextName = NameOffset.first;
754*5f7ddb14SDimitry Andric         SampleContext FContext(ContextName);
755*5f7ddb14SDimitry Andric         auto FuncName = FContext.getNameWithoutContext();
756*5f7ddb14SDimitry Andric         if (!FuncsToUse.count(FuncName) &&
757*5f7ddb14SDimitry Andric             (!Remapper || !Remapper->exist(FuncName)))
758*5f7ddb14SDimitry Andric           continue;
759*5f7ddb14SDimitry Andric 
760*5f7ddb14SDimitry Andric         // For each context profile we need, try to load
761*5f7ddb14SDimitry Andric         // all context profile in the subtree. This can
762*5f7ddb14SDimitry Andric         // help profile guided importing for ThinLTO.
763*5f7ddb14SDimitry Andric         auto It = OrderedNames.find(ContextName);
764*5f7ddb14SDimitry Andric         while (It != OrderedNames.end() &&
765*5f7ddb14SDimitry Andric                It->startswith(ContextName.substr(0, ContextName.size() - 1))) {
766*5f7ddb14SDimitry Andric           const uint8_t *FuncProfileAddr = Start + FuncOffsetTable[*It];
767*5f7ddb14SDimitry Andric           assert(FuncProfileAddr < End && "out of LBRProfile section");
768*5f7ddb14SDimitry Andric           if (std::error_code EC = readFuncProfile(FuncProfileAddr))
769*5f7ddb14SDimitry Andric             return EC;
770*5f7ddb14SDimitry Andric           // Remove loaded context profile so we won't
771*5f7ddb14SDimitry Andric           // load it repeatedly.
772*5f7ddb14SDimitry Andric           It = OrderedNames.erase(It);
773*5f7ddb14SDimitry Andric         }
774*5f7ddb14SDimitry Andric       }
7755ffd83dbSDimitry Andric     } else {
7768bcb0991SDimitry Andric       for (auto NameOffset : FuncOffsetTable) {
777af732203SDimitry Andric         SampleContext FContext(NameOffset.first);
778af732203SDimitry Andric         auto FuncName = FContext.getNameWithoutContext();
7798bcb0991SDimitry Andric         if (!FuncsToUse.count(FuncName) &&
7808bcb0991SDimitry Andric             (!Remapper || !Remapper->exist(FuncName)))
7818bcb0991SDimitry Andric           continue;
7828bcb0991SDimitry Andric         const uint8_t *FuncProfileAddr = Start + NameOffset.second;
7838bcb0991SDimitry Andric         assert(FuncProfileAddr < End && "out of LBRProfile section");
7848bcb0991SDimitry Andric         if (std::error_code EC = readFuncProfile(FuncProfileAddr))
7858bcb0991SDimitry Andric           return EC;
7868bcb0991SDimitry Andric       }
7875ffd83dbSDimitry Andric     }
7888bcb0991SDimitry Andric     Data = End;
789af732203SDimitry Andric   }
790af732203SDimitry Andric   assert((CSProfileCount == 0 || CSProfileCount == Profiles.size()) &&
791af732203SDimitry Andric          "Cannot have both context-sensitive and regular profile");
792*5f7ddb14SDimitry Andric   assert(ProfileIsCS == (CSProfileCount > 0) &&
793*5f7ddb14SDimitry Andric          "Section flag should be consistent with actual profile");
7948bcb0991SDimitry Andric   return sampleprof_error::success;
7958bcb0991SDimitry Andric }
7968bcb0991SDimitry Andric 
readProfileSymbolList()797af732203SDimitry Andric std::error_code SampleProfileReaderExtBinaryBase::readProfileSymbolList() {
7988bcb0991SDimitry Andric   if (!ProfSymList)
7998bcb0991SDimitry Andric     ProfSymList = std::make_unique<ProfileSymbolList>();
8008bcb0991SDimitry Andric 
8018bcb0991SDimitry Andric   if (std::error_code EC = ProfSymList->read(Data, End - Data))
8028bcb0991SDimitry Andric     return EC;
8038bcb0991SDimitry Andric 
8048bcb0991SDimitry Andric   Data = End;
8058bcb0991SDimitry Andric   return sampleprof_error::success;
8068bcb0991SDimitry Andric }
8078bcb0991SDimitry Andric 
decompressSection(const uint8_t * SecStart,const uint64_t SecSize,const uint8_t * & DecompressBuf,uint64_t & DecompressBufSize)8088bcb0991SDimitry Andric std::error_code SampleProfileReaderExtBinaryBase::decompressSection(
8098bcb0991SDimitry Andric     const uint8_t *SecStart, const uint64_t SecSize,
8108bcb0991SDimitry Andric     const uint8_t *&DecompressBuf, uint64_t &DecompressBufSize) {
8118bcb0991SDimitry Andric   Data = SecStart;
8128bcb0991SDimitry Andric   End = SecStart + SecSize;
8138bcb0991SDimitry Andric   auto DecompressSize = readNumber<uint64_t>();
8148bcb0991SDimitry Andric   if (std::error_code EC = DecompressSize.getError())
8158bcb0991SDimitry Andric     return EC;
8168bcb0991SDimitry Andric   DecompressBufSize = *DecompressSize;
8178bcb0991SDimitry Andric 
8188bcb0991SDimitry Andric   auto CompressSize = readNumber<uint64_t>();
8198bcb0991SDimitry Andric   if (std::error_code EC = CompressSize.getError())
8208bcb0991SDimitry Andric     return EC;
8218bcb0991SDimitry Andric 
8228bcb0991SDimitry Andric   if (!llvm::zlib::isAvailable())
8238bcb0991SDimitry Andric     return sampleprof_error::zlib_unavailable;
8248bcb0991SDimitry Andric 
8258bcb0991SDimitry Andric   StringRef CompressedStrings(reinterpret_cast<const char *>(Data),
8268bcb0991SDimitry Andric                               *CompressSize);
8278bcb0991SDimitry Andric   char *Buffer = Allocator.Allocate<char>(DecompressBufSize);
8288bcb0991SDimitry Andric   size_t UCSize = DecompressBufSize;
8298bcb0991SDimitry Andric   llvm::Error E =
8308bcb0991SDimitry Andric       zlib::uncompress(CompressedStrings, Buffer, UCSize);
8318bcb0991SDimitry Andric   if (E)
8328bcb0991SDimitry Andric     return sampleprof_error::uncompress_failed;
8338bcb0991SDimitry Andric   DecompressBuf = reinterpret_cast<const uint8_t *>(Buffer);
8348bcb0991SDimitry Andric   return sampleprof_error::success;
8358bcb0991SDimitry Andric }
8368bcb0991SDimitry Andric 
readImpl()8378bcb0991SDimitry Andric std::error_code SampleProfileReaderExtBinaryBase::readImpl() {
8388bcb0991SDimitry Andric   const uint8_t *BufStart =
8398bcb0991SDimitry Andric       reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
8408bcb0991SDimitry Andric 
8418bcb0991SDimitry Andric   for (auto &Entry : SecHdrTable) {
8428bcb0991SDimitry Andric     // Skip empty section.
8438bcb0991SDimitry Andric     if (!Entry.Size)
8448bcb0991SDimitry Andric       continue;
8458bcb0991SDimitry Andric 
846af732203SDimitry Andric     // Skip sections without context when SkipFlatProf is true.
847af732203SDimitry Andric     if (SkipFlatProf && hasSecFlag(Entry, SecCommonFlags::SecFlagFlat))
848af732203SDimitry Andric       continue;
849af732203SDimitry Andric 
8508bcb0991SDimitry Andric     const uint8_t *SecStart = BufStart + Entry.Offset;
8518bcb0991SDimitry Andric     uint64_t SecSize = Entry.Size;
8528bcb0991SDimitry Andric 
8538bcb0991SDimitry Andric     // If the section is compressed, decompress it into a buffer
8548bcb0991SDimitry Andric     // DecompressBuf before reading the actual data. The pointee of
8558bcb0991SDimitry Andric     // 'Data' will be changed to buffer hold by DecompressBuf
8568bcb0991SDimitry Andric     // temporarily when reading the actual data.
8575ffd83dbSDimitry Andric     bool isCompressed = hasSecFlag(Entry, SecCommonFlags::SecFlagCompress);
8588bcb0991SDimitry Andric     if (isCompressed) {
8598bcb0991SDimitry Andric       const uint8_t *DecompressBuf;
8608bcb0991SDimitry Andric       uint64_t DecompressBufSize;
8618bcb0991SDimitry Andric       if (std::error_code EC = decompressSection(
8628bcb0991SDimitry Andric               SecStart, SecSize, DecompressBuf, DecompressBufSize))
8638bcb0991SDimitry Andric         return EC;
8648bcb0991SDimitry Andric       SecStart = DecompressBuf;
8658bcb0991SDimitry Andric       SecSize = DecompressBufSize;
8668bcb0991SDimitry Andric     }
8678bcb0991SDimitry Andric 
8685ffd83dbSDimitry Andric     if (std::error_code EC = readOneSection(SecStart, SecSize, Entry))
8698bcb0991SDimitry Andric       return EC;
8708bcb0991SDimitry Andric     if (Data != SecStart + SecSize)
8718bcb0991SDimitry Andric       return sampleprof_error::malformed;
8728bcb0991SDimitry Andric 
8738bcb0991SDimitry Andric     // Change the pointee of 'Data' from DecompressBuf to original Buffer.
8748bcb0991SDimitry Andric     if (isCompressed) {
8758bcb0991SDimitry Andric       Data = BufStart + Entry.Offset;
8768bcb0991SDimitry Andric       End = BufStart + Buffer->getBufferSize();
8778bcb0991SDimitry Andric     }
8788bcb0991SDimitry Andric   }
8798bcb0991SDimitry Andric 
8808bcb0991SDimitry Andric   return sampleprof_error::success;
8818bcb0991SDimitry Andric }
8828bcb0991SDimitry Andric 
readImpl()8838bcb0991SDimitry Andric std::error_code SampleProfileReaderCompactBinary::readImpl() {
884*5f7ddb14SDimitry Andric   // Collect functions used by current module if the Reader has been
885*5f7ddb14SDimitry Andric   // given a module.
886*5f7ddb14SDimitry Andric   bool LoadFuncsToBeUsed = collectFuncsFromModule();
887*5f7ddb14SDimitry Andric   ProfileIsFS = ProfileIsFSDisciminator;
8888bcb0991SDimitry Andric   std::vector<uint64_t> OffsetsToUse;
889*5f7ddb14SDimitry Andric   if (!LoadFuncsToBeUsed) {
890*5f7ddb14SDimitry Andric     // load all the function profiles.
8918bcb0991SDimitry Andric     for (auto FuncEntry : FuncOffsetTable) {
8928bcb0991SDimitry Andric       OffsetsToUse.push_back(FuncEntry.second);
8938bcb0991SDimitry Andric     }
894*5f7ddb14SDimitry Andric   } else {
895*5f7ddb14SDimitry Andric     // load function profiles on demand.
8960b57cec5SDimitry Andric     for (auto Name : FuncsToUse) {
8970b57cec5SDimitry Andric       auto GUID = std::to_string(MD5Hash(Name));
8980b57cec5SDimitry Andric       auto iter = FuncOffsetTable.find(StringRef(GUID));
8990b57cec5SDimitry Andric       if (iter == FuncOffsetTable.end())
9000b57cec5SDimitry Andric         continue;
9018bcb0991SDimitry Andric       OffsetsToUse.push_back(iter->second);
9028bcb0991SDimitry Andric     }
9038bcb0991SDimitry Andric   }
9048bcb0991SDimitry Andric 
9058bcb0991SDimitry Andric   for (auto Offset : OffsetsToUse) {
9060b57cec5SDimitry Andric     const uint8_t *SavedData = Data;
9078bcb0991SDimitry Andric     if (std::error_code EC = readFuncProfile(
9088bcb0991SDimitry Andric             reinterpret_cast<const uint8_t *>(Buffer->getBufferStart()) +
9098bcb0991SDimitry Andric             Offset))
9100b57cec5SDimitry Andric       return EC;
9110b57cec5SDimitry Andric     Data = SavedData;
9120b57cec5SDimitry Andric   }
9130b57cec5SDimitry Andric   return sampleprof_error::success;
9140b57cec5SDimitry Andric }
9150b57cec5SDimitry Andric 
verifySPMagic(uint64_t Magic)9160b57cec5SDimitry Andric std::error_code SampleProfileReaderRawBinary::verifySPMagic(uint64_t Magic) {
9170b57cec5SDimitry Andric   if (Magic == SPMagic())
9180b57cec5SDimitry Andric     return sampleprof_error::success;
9190b57cec5SDimitry Andric   return sampleprof_error::bad_magic;
9200b57cec5SDimitry Andric }
9210b57cec5SDimitry Andric 
verifySPMagic(uint64_t Magic)9228bcb0991SDimitry Andric std::error_code SampleProfileReaderExtBinary::verifySPMagic(uint64_t Magic) {
9238bcb0991SDimitry Andric   if (Magic == SPMagic(SPF_Ext_Binary))
9248bcb0991SDimitry Andric     return sampleprof_error::success;
9258bcb0991SDimitry Andric   return sampleprof_error::bad_magic;
9268bcb0991SDimitry Andric }
9278bcb0991SDimitry Andric 
9280b57cec5SDimitry Andric std::error_code
verifySPMagic(uint64_t Magic)9290b57cec5SDimitry Andric SampleProfileReaderCompactBinary::verifySPMagic(uint64_t Magic) {
9300b57cec5SDimitry Andric   if (Magic == SPMagic(SPF_Compact_Binary))
9310b57cec5SDimitry Andric     return sampleprof_error::success;
9320b57cec5SDimitry Andric   return sampleprof_error::bad_magic;
9330b57cec5SDimitry Andric }
9340b57cec5SDimitry Andric 
readNameTable()9358bcb0991SDimitry Andric std::error_code SampleProfileReaderBinary::readNameTable() {
9360b57cec5SDimitry Andric   auto Size = readNumber<uint32_t>();
9370b57cec5SDimitry Andric   if (std::error_code EC = Size.getError())
9380b57cec5SDimitry Andric     return EC;
939af732203SDimitry Andric   NameTable.reserve(*Size + NameTable.size());
9400b57cec5SDimitry Andric   for (uint32_t I = 0; I < *Size; ++I) {
9410b57cec5SDimitry Andric     auto Name(readString());
9420b57cec5SDimitry Andric     if (std::error_code EC = Name.getError())
9430b57cec5SDimitry Andric       return EC;
9440b57cec5SDimitry Andric     NameTable.push_back(*Name);
9450b57cec5SDimitry Andric   }
9460b57cec5SDimitry Andric 
9470b57cec5SDimitry Andric   return sampleprof_error::success;
9480b57cec5SDimitry Andric }
9490b57cec5SDimitry Andric 
readMD5NameTable()950af732203SDimitry Andric std::error_code SampleProfileReaderExtBinaryBase::readMD5NameTable() {
9515ffd83dbSDimitry Andric   auto Size = readNumber<uint64_t>();
9525ffd83dbSDimitry Andric   if (std::error_code EC = Size.getError())
9535ffd83dbSDimitry Andric     return EC;
9545ffd83dbSDimitry Andric   MD5StringBuf = std::make_unique<std::vector<std::string>>();
9555ffd83dbSDimitry Andric   MD5StringBuf->reserve(*Size);
956af732203SDimitry Andric   if (FixedLengthMD5) {
957af732203SDimitry Andric     // Preallocate and initialize NameTable so we can check whether a name
958af732203SDimitry Andric     // index has been read before by checking whether the element in the
959af732203SDimitry Andric     // NameTable is empty, meanwhile readStringIndex can do the boundary
960af732203SDimitry Andric     // check using the size of NameTable.
961af732203SDimitry Andric     NameTable.resize(*Size + NameTable.size());
962af732203SDimitry Andric 
963af732203SDimitry Andric     MD5NameMemStart = Data;
964af732203SDimitry Andric     Data = Data + (*Size) * sizeof(uint64_t);
965af732203SDimitry Andric     return sampleprof_error::success;
966af732203SDimitry Andric   }
967af732203SDimitry Andric   NameTable.reserve(*Size);
9685ffd83dbSDimitry Andric   for (uint32_t I = 0; I < *Size; ++I) {
9695ffd83dbSDimitry Andric     auto FID = readNumber<uint64_t>();
9705ffd83dbSDimitry Andric     if (std::error_code EC = FID.getError())
9715ffd83dbSDimitry Andric       return EC;
9725ffd83dbSDimitry Andric     MD5StringBuf->push_back(std::to_string(*FID));
9735ffd83dbSDimitry Andric     // NameTable is a vector of StringRef. Here it is pushing back a
9745ffd83dbSDimitry Andric     // StringRef initialized with the last string in MD5stringBuf.
9755ffd83dbSDimitry Andric     NameTable.push_back(MD5StringBuf->back());
9765ffd83dbSDimitry Andric   }
9775ffd83dbSDimitry Andric   return sampleprof_error::success;
9785ffd83dbSDimitry Andric }
9795ffd83dbSDimitry Andric 
readNameTableSec(bool IsMD5)980af732203SDimitry Andric std::error_code SampleProfileReaderExtBinaryBase::readNameTableSec(bool IsMD5) {
9815ffd83dbSDimitry Andric   if (IsMD5)
9825ffd83dbSDimitry Andric     return readMD5NameTable();
9835ffd83dbSDimitry Andric   return SampleProfileReaderBinary::readNameTable();
9845ffd83dbSDimitry Andric }
9855ffd83dbSDimitry Andric 
986*5f7ddb14SDimitry Andric std::error_code
readFuncMetadata(bool ProfileHasAttribute)987*5f7ddb14SDimitry Andric SampleProfileReaderExtBinaryBase::readFuncMetadata(bool ProfileHasAttribute) {
988af732203SDimitry Andric   while (Data < End) {
989af732203SDimitry Andric     auto FName(readStringFromTable());
990af732203SDimitry Andric     if (std::error_code EC = FName.getError())
991af732203SDimitry Andric       return EC;
992af732203SDimitry Andric 
993*5f7ddb14SDimitry Andric     SampleContext FContext(*FName);
994*5f7ddb14SDimitry Andric     bool ProfileInMap = Profiles.count(FContext);
995*5f7ddb14SDimitry Andric 
996*5f7ddb14SDimitry Andric     if (ProfileIsProbeBased) {
997af732203SDimitry Andric       auto Checksum = readNumber<uint64_t>();
998af732203SDimitry Andric       if (std::error_code EC = Checksum.getError())
999af732203SDimitry Andric         return EC;
1000*5f7ddb14SDimitry Andric       if (ProfileInMap)
1001af732203SDimitry Andric         Profiles[FContext].setFunctionHash(*Checksum);
1002af732203SDimitry Andric     }
1003af732203SDimitry Andric 
1004*5f7ddb14SDimitry Andric     if (ProfileHasAttribute) {
1005*5f7ddb14SDimitry Andric       auto Attributes = readNumber<uint32_t>();
1006*5f7ddb14SDimitry Andric       if (std::error_code EC = Attributes.getError())
1007*5f7ddb14SDimitry Andric         return EC;
1008*5f7ddb14SDimitry Andric       if (ProfileInMap)
1009*5f7ddb14SDimitry Andric         Profiles[FContext].getContext().setAllAttributes(*Attributes);
1010*5f7ddb14SDimitry Andric     }
1011*5f7ddb14SDimitry Andric   }
1012*5f7ddb14SDimitry Andric 
1013af732203SDimitry Andric   assert(Data == End && "More data is read than expected");
1014af732203SDimitry Andric   return sampleprof_error::success;
1015af732203SDimitry Andric }
1016af732203SDimitry Andric 
readNameTable()10170b57cec5SDimitry Andric std::error_code SampleProfileReaderCompactBinary::readNameTable() {
10180b57cec5SDimitry Andric   auto Size = readNumber<uint64_t>();
10190b57cec5SDimitry Andric   if (std::error_code EC = Size.getError())
10200b57cec5SDimitry Andric     return EC;
10210b57cec5SDimitry Andric   NameTable.reserve(*Size);
10220b57cec5SDimitry Andric   for (uint32_t I = 0; I < *Size; ++I) {
10230b57cec5SDimitry Andric     auto FID = readNumber<uint64_t>();
10240b57cec5SDimitry Andric     if (std::error_code EC = FID.getError())
10250b57cec5SDimitry Andric       return EC;
10260b57cec5SDimitry Andric     NameTable.push_back(std::to_string(*FID));
10270b57cec5SDimitry Andric   }
10280b57cec5SDimitry Andric   return sampleprof_error::success;
10290b57cec5SDimitry Andric }
10300b57cec5SDimitry Andric 
1031af732203SDimitry Andric std::error_code
readSecHdrTableEntry(uint32_t Idx)1032af732203SDimitry Andric SampleProfileReaderExtBinaryBase::readSecHdrTableEntry(uint32_t Idx) {
10338bcb0991SDimitry Andric   SecHdrTableEntry Entry;
10348bcb0991SDimitry Andric   auto Type = readUnencodedNumber<uint64_t>();
10358bcb0991SDimitry Andric   if (std::error_code EC = Type.getError())
10368bcb0991SDimitry Andric     return EC;
10378bcb0991SDimitry Andric   Entry.Type = static_cast<SecType>(*Type);
10380b57cec5SDimitry Andric 
10398bcb0991SDimitry Andric   auto Flags = readUnencodedNumber<uint64_t>();
10408bcb0991SDimitry Andric   if (std::error_code EC = Flags.getError())
10418bcb0991SDimitry Andric     return EC;
10428bcb0991SDimitry Andric   Entry.Flags = *Flags;
10438bcb0991SDimitry Andric 
10448bcb0991SDimitry Andric   auto Offset = readUnencodedNumber<uint64_t>();
10458bcb0991SDimitry Andric   if (std::error_code EC = Offset.getError())
10468bcb0991SDimitry Andric     return EC;
10478bcb0991SDimitry Andric   Entry.Offset = *Offset;
10488bcb0991SDimitry Andric 
10498bcb0991SDimitry Andric   auto Size = readUnencodedNumber<uint64_t>();
10508bcb0991SDimitry Andric   if (std::error_code EC = Size.getError())
10518bcb0991SDimitry Andric     return EC;
10528bcb0991SDimitry Andric   Entry.Size = *Size;
10538bcb0991SDimitry Andric 
1054af732203SDimitry Andric   Entry.LayoutIndex = Idx;
10558bcb0991SDimitry Andric   SecHdrTable.push_back(std::move(Entry));
10568bcb0991SDimitry Andric   return sampleprof_error::success;
10578bcb0991SDimitry Andric }
10588bcb0991SDimitry Andric 
readSecHdrTable()10598bcb0991SDimitry Andric std::error_code SampleProfileReaderExtBinaryBase::readSecHdrTable() {
10608bcb0991SDimitry Andric   auto EntryNum = readUnencodedNumber<uint64_t>();
10618bcb0991SDimitry Andric   if (std::error_code EC = EntryNum.getError())
10628bcb0991SDimitry Andric     return EC;
10638bcb0991SDimitry Andric 
10648bcb0991SDimitry Andric   for (uint32_t i = 0; i < (*EntryNum); i++)
1065af732203SDimitry Andric     if (std::error_code EC = readSecHdrTableEntry(i))
10668bcb0991SDimitry Andric       return EC;
10678bcb0991SDimitry Andric 
10688bcb0991SDimitry Andric   return sampleprof_error::success;
10698bcb0991SDimitry Andric }
10708bcb0991SDimitry Andric 
readHeader()10718bcb0991SDimitry Andric std::error_code SampleProfileReaderExtBinaryBase::readHeader() {
10728bcb0991SDimitry Andric   const uint8_t *BufStart =
10738bcb0991SDimitry Andric       reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
10748bcb0991SDimitry Andric   Data = BufStart;
10758bcb0991SDimitry Andric   End = BufStart + Buffer->getBufferSize();
10768bcb0991SDimitry Andric 
10778bcb0991SDimitry Andric   if (std::error_code EC = readMagicIdent())
10788bcb0991SDimitry Andric     return EC;
10798bcb0991SDimitry Andric 
10808bcb0991SDimitry Andric   if (std::error_code EC = readSecHdrTable())
10818bcb0991SDimitry Andric     return EC;
10828bcb0991SDimitry Andric 
10838bcb0991SDimitry Andric   return sampleprof_error::success;
10848bcb0991SDimitry Andric }
10858bcb0991SDimitry Andric 
getSectionSize(SecType Type)10868bcb0991SDimitry Andric uint64_t SampleProfileReaderExtBinaryBase::getSectionSize(SecType Type) {
1087af732203SDimitry Andric   uint64_t Size = 0;
10888bcb0991SDimitry Andric   for (auto &Entry : SecHdrTable) {
10898bcb0991SDimitry Andric     if (Entry.Type == Type)
1090af732203SDimitry Andric       Size += Entry.Size;
10918bcb0991SDimitry Andric   }
1092af732203SDimitry Andric   return Size;
10938bcb0991SDimitry Andric }
10948bcb0991SDimitry Andric 
getFileSize()10958bcb0991SDimitry Andric uint64_t SampleProfileReaderExtBinaryBase::getFileSize() {
10968bcb0991SDimitry Andric   // Sections in SecHdrTable is not necessarily in the same order as
10978bcb0991SDimitry Andric   // sections in the profile because section like FuncOffsetTable needs
10988bcb0991SDimitry Andric   // to be written after section LBRProfile but needs to be read before
10998bcb0991SDimitry Andric   // section LBRProfile, so we cannot simply use the last entry in
11008bcb0991SDimitry Andric   // SecHdrTable to calculate the file size.
11018bcb0991SDimitry Andric   uint64_t FileSize = 0;
11028bcb0991SDimitry Andric   for (auto &Entry : SecHdrTable) {
11038bcb0991SDimitry Andric     FileSize = std::max(Entry.Offset + Entry.Size, FileSize);
11048bcb0991SDimitry Andric   }
11058bcb0991SDimitry Andric   return FileSize;
11068bcb0991SDimitry Andric }
11078bcb0991SDimitry Andric 
getSecFlagsStr(const SecHdrTableEntry & Entry)11085ffd83dbSDimitry Andric static std::string getSecFlagsStr(const SecHdrTableEntry &Entry) {
11095ffd83dbSDimitry Andric   std::string Flags;
11105ffd83dbSDimitry Andric   if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress))
11115ffd83dbSDimitry Andric     Flags.append("{compressed,");
11125ffd83dbSDimitry Andric   else
11135ffd83dbSDimitry Andric     Flags.append("{");
11145ffd83dbSDimitry Andric 
1115af732203SDimitry Andric   if (hasSecFlag(Entry, SecCommonFlags::SecFlagFlat))
1116af732203SDimitry Andric     Flags.append("flat,");
1117af732203SDimitry Andric 
11185ffd83dbSDimitry Andric   switch (Entry.Type) {
11195ffd83dbSDimitry Andric   case SecNameTable:
1120af732203SDimitry Andric     if (hasSecFlag(Entry, SecNameTableFlags::SecFlagFixedLengthMD5))
1121af732203SDimitry Andric       Flags.append("fixlenmd5,");
1122af732203SDimitry Andric     else if (hasSecFlag(Entry, SecNameTableFlags::SecFlagMD5Name))
11235ffd83dbSDimitry Andric       Flags.append("md5,");
1124*5f7ddb14SDimitry Andric     if (hasSecFlag(Entry, SecNameTableFlags::SecFlagUniqSuffix))
1125*5f7ddb14SDimitry Andric       Flags.append("uniq,");
11265ffd83dbSDimitry Andric     break;
11275ffd83dbSDimitry Andric   case SecProfSummary:
11285ffd83dbSDimitry Andric     if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagPartial))
11295ffd83dbSDimitry Andric       Flags.append("partial,");
1130*5f7ddb14SDimitry Andric     if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagFullContext))
1131*5f7ddb14SDimitry Andric       Flags.append("context,");
1132*5f7ddb14SDimitry Andric     if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagFSDiscriminator))
1133*5f7ddb14SDimitry Andric       Flags.append("fs-discriminator,");
11345ffd83dbSDimitry Andric     break;
11355ffd83dbSDimitry Andric   default:
11365ffd83dbSDimitry Andric     break;
11375ffd83dbSDimitry Andric   }
11385ffd83dbSDimitry Andric   char &last = Flags.back();
11395ffd83dbSDimitry Andric   if (last == ',')
11405ffd83dbSDimitry Andric     last = '}';
11415ffd83dbSDimitry Andric   else
11425ffd83dbSDimitry Andric     Flags.append("}");
11435ffd83dbSDimitry Andric   return Flags;
11445ffd83dbSDimitry Andric }
11455ffd83dbSDimitry Andric 
dumpSectionInfo(raw_ostream & OS)11468bcb0991SDimitry Andric bool SampleProfileReaderExtBinaryBase::dumpSectionInfo(raw_ostream &OS) {
11478bcb0991SDimitry Andric   uint64_t TotalSecsSize = 0;
11488bcb0991SDimitry Andric   for (auto &Entry : SecHdrTable) {
11498bcb0991SDimitry Andric     OS << getSecName(Entry.Type) << " - Offset: " << Entry.Offset
11505ffd83dbSDimitry Andric        << ", Size: " << Entry.Size << ", Flags: " << getSecFlagsStr(Entry)
11515ffd83dbSDimitry Andric        << "\n";
11525ffd83dbSDimitry Andric     ;
1153af732203SDimitry Andric     TotalSecsSize += Entry.Size;
11548bcb0991SDimitry Andric   }
11558bcb0991SDimitry Andric   uint64_t HeaderSize = SecHdrTable.front().Offset;
11568bcb0991SDimitry Andric   assert(HeaderSize + TotalSecsSize == getFileSize() &&
11578bcb0991SDimitry Andric          "Size of 'header + sections' doesn't match the total size of profile");
11588bcb0991SDimitry Andric 
11598bcb0991SDimitry Andric   OS << "Header Size: " << HeaderSize << "\n";
11608bcb0991SDimitry Andric   OS << "Total Sections Size: " << TotalSecsSize << "\n";
11618bcb0991SDimitry Andric   OS << "File Size: " << getFileSize() << "\n";
11628bcb0991SDimitry Andric   return true;
11638bcb0991SDimitry Andric }
11648bcb0991SDimitry Andric 
readMagicIdent()11658bcb0991SDimitry Andric std::error_code SampleProfileReaderBinary::readMagicIdent() {
11660b57cec5SDimitry Andric   // Read and check the magic identifier.
11670b57cec5SDimitry Andric   auto Magic = readNumber<uint64_t>();
11680b57cec5SDimitry Andric   if (std::error_code EC = Magic.getError())
11690b57cec5SDimitry Andric     return EC;
11700b57cec5SDimitry Andric   else if (std::error_code EC = verifySPMagic(*Magic))
11710b57cec5SDimitry Andric     return EC;
11720b57cec5SDimitry Andric 
11730b57cec5SDimitry Andric   // Read the version number.
11740b57cec5SDimitry Andric   auto Version = readNumber<uint64_t>();
11750b57cec5SDimitry Andric   if (std::error_code EC = Version.getError())
11760b57cec5SDimitry Andric     return EC;
11770b57cec5SDimitry Andric   else if (*Version != SPVersion())
11780b57cec5SDimitry Andric     return sampleprof_error::unsupported_version;
11790b57cec5SDimitry Andric 
11808bcb0991SDimitry Andric   return sampleprof_error::success;
11818bcb0991SDimitry Andric }
11828bcb0991SDimitry Andric 
readHeader()11838bcb0991SDimitry Andric std::error_code SampleProfileReaderBinary::readHeader() {
11848bcb0991SDimitry Andric   Data = reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
11858bcb0991SDimitry Andric   End = Data + Buffer->getBufferSize();
11868bcb0991SDimitry Andric 
11878bcb0991SDimitry Andric   if (std::error_code EC = readMagicIdent())
11888bcb0991SDimitry Andric     return EC;
11898bcb0991SDimitry Andric 
11900b57cec5SDimitry Andric   if (std::error_code EC = readSummary())
11910b57cec5SDimitry Andric     return EC;
11920b57cec5SDimitry Andric 
11930b57cec5SDimitry Andric   if (std::error_code EC = readNameTable())
11940b57cec5SDimitry Andric     return EC;
11950b57cec5SDimitry Andric   return sampleprof_error::success;
11960b57cec5SDimitry Andric }
11970b57cec5SDimitry Andric 
readHeader()11980b57cec5SDimitry Andric std::error_code SampleProfileReaderCompactBinary::readHeader() {
11990b57cec5SDimitry Andric   SampleProfileReaderBinary::readHeader();
12000b57cec5SDimitry Andric   if (std::error_code EC = readFuncOffsetTable())
12010b57cec5SDimitry Andric     return EC;
12020b57cec5SDimitry Andric   return sampleprof_error::success;
12030b57cec5SDimitry Andric }
12040b57cec5SDimitry Andric 
readFuncOffsetTable()12050b57cec5SDimitry Andric std::error_code SampleProfileReaderCompactBinary::readFuncOffsetTable() {
12060b57cec5SDimitry Andric   auto TableOffset = readUnencodedNumber<uint64_t>();
12070b57cec5SDimitry Andric   if (std::error_code EC = TableOffset.getError())
12080b57cec5SDimitry Andric     return EC;
12090b57cec5SDimitry Andric 
12100b57cec5SDimitry Andric   const uint8_t *SavedData = Data;
12110b57cec5SDimitry Andric   const uint8_t *TableStart =
12120b57cec5SDimitry Andric       reinterpret_cast<const uint8_t *>(Buffer->getBufferStart()) +
12130b57cec5SDimitry Andric       *TableOffset;
12140b57cec5SDimitry Andric   Data = TableStart;
12150b57cec5SDimitry Andric 
12160b57cec5SDimitry Andric   auto Size = readNumber<uint64_t>();
12170b57cec5SDimitry Andric   if (std::error_code EC = Size.getError())
12180b57cec5SDimitry Andric     return EC;
12190b57cec5SDimitry Andric 
12200b57cec5SDimitry Andric   FuncOffsetTable.reserve(*Size);
12210b57cec5SDimitry Andric   for (uint32_t I = 0; I < *Size; ++I) {
12220b57cec5SDimitry Andric     auto FName(readStringFromTable());
12230b57cec5SDimitry Andric     if (std::error_code EC = FName.getError())
12240b57cec5SDimitry Andric       return EC;
12250b57cec5SDimitry Andric 
12260b57cec5SDimitry Andric     auto Offset = readNumber<uint64_t>();
12270b57cec5SDimitry Andric     if (std::error_code EC = Offset.getError())
12280b57cec5SDimitry Andric       return EC;
12290b57cec5SDimitry Andric 
12300b57cec5SDimitry Andric     FuncOffsetTable[*FName] = *Offset;
12310b57cec5SDimitry Andric   }
12320b57cec5SDimitry Andric   End = TableStart;
12330b57cec5SDimitry Andric   Data = SavedData;
12340b57cec5SDimitry Andric   return sampleprof_error::success;
12350b57cec5SDimitry Andric }
12360b57cec5SDimitry Andric 
collectFuncsFromModule()1237*5f7ddb14SDimitry Andric bool SampleProfileReaderCompactBinary::collectFuncsFromModule() {
1238*5f7ddb14SDimitry Andric   if (!M)
1239*5f7ddb14SDimitry Andric     return false;
12400b57cec5SDimitry Andric   FuncsToUse.clear();
1241*5f7ddb14SDimitry Andric   for (auto &F : *M)
12428bcb0991SDimitry Andric     FuncsToUse.insert(FunctionSamples::getCanonicalFnName(F));
1243*5f7ddb14SDimitry Andric   return true;
12440b57cec5SDimitry Andric }
12450b57cec5SDimitry Andric 
readSummaryEntry(std::vector<ProfileSummaryEntry> & Entries)12460b57cec5SDimitry Andric std::error_code SampleProfileReaderBinary::readSummaryEntry(
12470b57cec5SDimitry Andric     std::vector<ProfileSummaryEntry> &Entries) {
12480b57cec5SDimitry Andric   auto Cutoff = readNumber<uint64_t>();
12490b57cec5SDimitry Andric   if (std::error_code EC = Cutoff.getError())
12500b57cec5SDimitry Andric     return EC;
12510b57cec5SDimitry Andric 
12520b57cec5SDimitry Andric   auto MinBlockCount = readNumber<uint64_t>();
12530b57cec5SDimitry Andric   if (std::error_code EC = MinBlockCount.getError())
12540b57cec5SDimitry Andric     return EC;
12550b57cec5SDimitry Andric 
12560b57cec5SDimitry Andric   auto NumBlocks = readNumber<uint64_t>();
12570b57cec5SDimitry Andric   if (std::error_code EC = NumBlocks.getError())
12580b57cec5SDimitry Andric     return EC;
12590b57cec5SDimitry Andric 
12600b57cec5SDimitry Andric   Entries.emplace_back(*Cutoff, *MinBlockCount, *NumBlocks);
12610b57cec5SDimitry Andric   return sampleprof_error::success;
12620b57cec5SDimitry Andric }
12630b57cec5SDimitry Andric 
readSummary()12640b57cec5SDimitry Andric std::error_code SampleProfileReaderBinary::readSummary() {
12650b57cec5SDimitry Andric   auto TotalCount = readNumber<uint64_t>();
12660b57cec5SDimitry Andric   if (std::error_code EC = TotalCount.getError())
12670b57cec5SDimitry Andric     return EC;
12680b57cec5SDimitry Andric 
12690b57cec5SDimitry Andric   auto MaxBlockCount = readNumber<uint64_t>();
12700b57cec5SDimitry Andric   if (std::error_code EC = MaxBlockCount.getError())
12710b57cec5SDimitry Andric     return EC;
12720b57cec5SDimitry Andric 
12730b57cec5SDimitry Andric   auto MaxFunctionCount = readNumber<uint64_t>();
12740b57cec5SDimitry Andric   if (std::error_code EC = MaxFunctionCount.getError())
12750b57cec5SDimitry Andric     return EC;
12760b57cec5SDimitry Andric 
12770b57cec5SDimitry Andric   auto NumBlocks = readNumber<uint64_t>();
12780b57cec5SDimitry Andric   if (std::error_code EC = NumBlocks.getError())
12790b57cec5SDimitry Andric     return EC;
12800b57cec5SDimitry Andric 
12810b57cec5SDimitry Andric   auto NumFunctions = readNumber<uint64_t>();
12820b57cec5SDimitry Andric   if (std::error_code EC = NumFunctions.getError())
12830b57cec5SDimitry Andric     return EC;
12840b57cec5SDimitry Andric 
12850b57cec5SDimitry Andric   auto NumSummaryEntries = readNumber<uint64_t>();
12860b57cec5SDimitry Andric   if (std::error_code EC = NumSummaryEntries.getError())
12870b57cec5SDimitry Andric     return EC;
12880b57cec5SDimitry Andric 
12890b57cec5SDimitry Andric   std::vector<ProfileSummaryEntry> Entries;
12900b57cec5SDimitry Andric   for (unsigned i = 0; i < *NumSummaryEntries; i++) {
12910b57cec5SDimitry Andric     std::error_code EC = readSummaryEntry(Entries);
12920b57cec5SDimitry Andric     if (EC != sampleprof_error::success)
12930b57cec5SDimitry Andric       return EC;
12940b57cec5SDimitry Andric   }
12958bcb0991SDimitry Andric   Summary = std::make_unique<ProfileSummary>(
12960b57cec5SDimitry Andric       ProfileSummary::PSK_Sample, Entries, *TotalCount, *MaxBlockCount, 0,
12970b57cec5SDimitry Andric       *MaxFunctionCount, *NumBlocks, *NumFunctions);
12980b57cec5SDimitry Andric 
12990b57cec5SDimitry Andric   return sampleprof_error::success;
13000b57cec5SDimitry Andric }
13010b57cec5SDimitry Andric 
hasFormat(const MemoryBuffer & Buffer)13020b57cec5SDimitry Andric bool SampleProfileReaderRawBinary::hasFormat(const MemoryBuffer &Buffer) {
13030b57cec5SDimitry Andric   const uint8_t *Data =
13040b57cec5SDimitry Andric       reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
13050b57cec5SDimitry Andric   uint64_t Magic = decodeULEB128(Data);
13060b57cec5SDimitry Andric   return Magic == SPMagic();
13070b57cec5SDimitry Andric }
13080b57cec5SDimitry Andric 
hasFormat(const MemoryBuffer & Buffer)13098bcb0991SDimitry Andric bool SampleProfileReaderExtBinary::hasFormat(const MemoryBuffer &Buffer) {
13108bcb0991SDimitry Andric   const uint8_t *Data =
13118bcb0991SDimitry Andric       reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
13128bcb0991SDimitry Andric   uint64_t Magic = decodeULEB128(Data);
13138bcb0991SDimitry Andric   return Magic == SPMagic(SPF_Ext_Binary);
13148bcb0991SDimitry Andric }
13158bcb0991SDimitry Andric 
hasFormat(const MemoryBuffer & Buffer)13160b57cec5SDimitry Andric bool SampleProfileReaderCompactBinary::hasFormat(const MemoryBuffer &Buffer) {
13170b57cec5SDimitry Andric   const uint8_t *Data =
13180b57cec5SDimitry Andric       reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
13190b57cec5SDimitry Andric   uint64_t Magic = decodeULEB128(Data);
13200b57cec5SDimitry Andric   return Magic == SPMagic(SPF_Compact_Binary);
13210b57cec5SDimitry Andric }
13220b57cec5SDimitry Andric 
skipNextWord()13230b57cec5SDimitry Andric std::error_code SampleProfileReaderGCC::skipNextWord() {
13240b57cec5SDimitry Andric   uint32_t dummy;
13250b57cec5SDimitry Andric   if (!GcovBuffer.readInt(dummy))
13260b57cec5SDimitry Andric     return sampleprof_error::truncated;
13270b57cec5SDimitry Andric   return sampleprof_error::success;
13280b57cec5SDimitry Andric }
13290b57cec5SDimitry Andric 
readNumber()13300b57cec5SDimitry Andric template <typename T> ErrorOr<T> SampleProfileReaderGCC::readNumber() {
13310b57cec5SDimitry Andric   if (sizeof(T) <= sizeof(uint32_t)) {
13320b57cec5SDimitry Andric     uint32_t Val;
13330b57cec5SDimitry Andric     if (GcovBuffer.readInt(Val) && Val <= std::numeric_limits<T>::max())
13340b57cec5SDimitry Andric       return static_cast<T>(Val);
13350b57cec5SDimitry Andric   } else if (sizeof(T) <= sizeof(uint64_t)) {
13360b57cec5SDimitry Andric     uint64_t Val;
13370b57cec5SDimitry Andric     if (GcovBuffer.readInt64(Val) && Val <= std::numeric_limits<T>::max())
13380b57cec5SDimitry Andric       return static_cast<T>(Val);
13390b57cec5SDimitry Andric   }
13400b57cec5SDimitry Andric 
13410b57cec5SDimitry Andric   std::error_code EC = sampleprof_error::malformed;
13420b57cec5SDimitry Andric   reportError(0, EC.message());
13430b57cec5SDimitry Andric   return EC;
13440b57cec5SDimitry Andric }
13450b57cec5SDimitry Andric 
readString()13460b57cec5SDimitry Andric ErrorOr<StringRef> SampleProfileReaderGCC::readString() {
13470b57cec5SDimitry Andric   StringRef Str;
13480b57cec5SDimitry Andric   if (!GcovBuffer.readString(Str))
13490b57cec5SDimitry Andric     return sampleprof_error::truncated;
13500b57cec5SDimitry Andric   return Str;
13510b57cec5SDimitry Andric }
13520b57cec5SDimitry Andric 
readHeader()13530b57cec5SDimitry Andric std::error_code SampleProfileReaderGCC::readHeader() {
13540b57cec5SDimitry Andric   // Read the magic identifier.
13550b57cec5SDimitry Andric   if (!GcovBuffer.readGCDAFormat())
13560b57cec5SDimitry Andric     return sampleprof_error::unrecognized_format;
13570b57cec5SDimitry Andric 
13580b57cec5SDimitry Andric   // Read the version number. Note - the GCC reader does not validate this
13590b57cec5SDimitry Andric   // version, but the profile creator generates v704.
13600b57cec5SDimitry Andric   GCOV::GCOVVersion version;
13610b57cec5SDimitry Andric   if (!GcovBuffer.readGCOVVersion(version))
13620b57cec5SDimitry Andric     return sampleprof_error::unrecognized_format;
13630b57cec5SDimitry Andric 
13645ffd83dbSDimitry Andric   if (version != GCOV::V407)
13650b57cec5SDimitry Andric     return sampleprof_error::unsupported_version;
13660b57cec5SDimitry Andric 
13670b57cec5SDimitry Andric   // Skip the empty integer.
13680b57cec5SDimitry Andric   if (std::error_code EC = skipNextWord())
13690b57cec5SDimitry Andric     return EC;
13700b57cec5SDimitry Andric 
13710b57cec5SDimitry Andric   return sampleprof_error::success;
13720b57cec5SDimitry Andric }
13730b57cec5SDimitry Andric 
readSectionTag(uint32_t Expected)13740b57cec5SDimitry Andric std::error_code SampleProfileReaderGCC::readSectionTag(uint32_t Expected) {
13750b57cec5SDimitry Andric   uint32_t Tag;
13760b57cec5SDimitry Andric   if (!GcovBuffer.readInt(Tag))
13770b57cec5SDimitry Andric     return sampleprof_error::truncated;
13780b57cec5SDimitry Andric 
13790b57cec5SDimitry Andric   if (Tag != Expected)
13800b57cec5SDimitry Andric     return sampleprof_error::malformed;
13810b57cec5SDimitry Andric 
13820b57cec5SDimitry Andric   if (std::error_code EC = skipNextWord())
13830b57cec5SDimitry Andric     return EC;
13840b57cec5SDimitry Andric 
13850b57cec5SDimitry Andric   return sampleprof_error::success;
13860b57cec5SDimitry Andric }
13870b57cec5SDimitry Andric 
readNameTable()13880b57cec5SDimitry Andric std::error_code SampleProfileReaderGCC::readNameTable() {
13890b57cec5SDimitry Andric   if (std::error_code EC = readSectionTag(GCOVTagAFDOFileNames))
13900b57cec5SDimitry Andric     return EC;
13910b57cec5SDimitry Andric 
13920b57cec5SDimitry Andric   uint32_t Size;
13930b57cec5SDimitry Andric   if (!GcovBuffer.readInt(Size))
13940b57cec5SDimitry Andric     return sampleprof_error::truncated;
13950b57cec5SDimitry Andric 
13960b57cec5SDimitry Andric   for (uint32_t I = 0; I < Size; ++I) {
13970b57cec5SDimitry Andric     StringRef Str;
13980b57cec5SDimitry Andric     if (!GcovBuffer.readString(Str))
13990b57cec5SDimitry Andric       return sampleprof_error::truncated;
14005ffd83dbSDimitry Andric     Names.push_back(std::string(Str));
14010b57cec5SDimitry Andric   }
14020b57cec5SDimitry Andric 
14030b57cec5SDimitry Andric   return sampleprof_error::success;
14040b57cec5SDimitry Andric }
14050b57cec5SDimitry Andric 
readFunctionProfiles()14060b57cec5SDimitry Andric std::error_code SampleProfileReaderGCC::readFunctionProfiles() {
14070b57cec5SDimitry Andric   if (std::error_code EC = readSectionTag(GCOVTagAFDOFunction))
14080b57cec5SDimitry Andric     return EC;
14090b57cec5SDimitry Andric 
14100b57cec5SDimitry Andric   uint32_t NumFunctions;
14110b57cec5SDimitry Andric   if (!GcovBuffer.readInt(NumFunctions))
14120b57cec5SDimitry Andric     return sampleprof_error::truncated;
14130b57cec5SDimitry Andric 
14140b57cec5SDimitry Andric   InlineCallStack Stack;
14150b57cec5SDimitry Andric   for (uint32_t I = 0; I < NumFunctions; ++I)
14160b57cec5SDimitry Andric     if (std::error_code EC = readOneFunctionProfile(Stack, true, 0))
14170b57cec5SDimitry Andric       return EC;
14180b57cec5SDimitry Andric 
14190b57cec5SDimitry Andric   computeSummary();
14200b57cec5SDimitry Andric   return sampleprof_error::success;
14210b57cec5SDimitry Andric }
14220b57cec5SDimitry Andric 
readOneFunctionProfile(const InlineCallStack & InlineStack,bool Update,uint32_t Offset)14230b57cec5SDimitry Andric std::error_code SampleProfileReaderGCC::readOneFunctionProfile(
14240b57cec5SDimitry Andric     const InlineCallStack &InlineStack, bool Update, uint32_t Offset) {
14250b57cec5SDimitry Andric   uint64_t HeadCount = 0;
14260b57cec5SDimitry Andric   if (InlineStack.size() == 0)
14270b57cec5SDimitry Andric     if (!GcovBuffer.readInt64(HeadCount))
14280b57cec5SDimitry Andric       return sampleprof_error::truncated;
14290b57cec5SDimitry Andric 
14300b57cec5SDimitry Andric   uint32_t NameIdx;
14310b57cec5SDimitry Andric   if (!GcovBuffer.readInt(NameIdx))
14320b57cec5SDimitry Andric     return sampleprof_error::truncated;
14330b57cec5SDimitry Andric 
14340b57cec5SDimitry Andric   StringRef Name(Names[NameIdx]);
14350b57cec5SDimitry Andric 
14360b57cec5SDimitry Andric   uint32_t NumPosCounts;
14370b57cec5SDimitry Andric   if (!GcovBuffer.readInt(NumPosCounts))
14380b57cec5SDimitry Andric     return sampleprof_error::truncated;
14390b57cec5SDimitry Andric 
14400b57cec5SDimitry Andric   uint32_t NumCallsites;
14410b57cec5SDimitry Andric   if (!GcovBuffer.readInt(NumCallsites))
14420b57cec5SDimitry Andric     return sampleprof_error::truncated;
14430b57cec5SDimitry Andric 
14440b57cec5SDimitry Andric   FunctionSamples *FProfile = nullptr;
14450b57cec5SDimitry Andric   if (InlineStack.size() == 0) {
14460b57cec5SDimitry Andric     // If this is a top function that we have already processed, do not
14470b57cec5SDimitry Andric     // update its profile again.  This happens in the presence of
14480b57cec5SDimitry Andric     // function aliases.  Since these aliases share the same function
14490b57cec5SDimitry Andric     // body, there will be identical replicated profiles for the
14500b57cec5SDimitry Andric     // original function.  In this case, we simply not bother updating
14510b57cec5SDimitry Andric     // the profile of the original function.
14520b57cec5SDimitry Andric     FProfile = &Profiles[Name];
14530b57cec5SDimitry Andric     FProfile->addHeadSamples(HeadCount);
14540b57cec5SDimitry Andric     if (FProfile->getTotalSamples() > 0)
14550b57cec5SDimitry Andric       Update = false;
14560b57cec5SDimitry Andric   } else {
14570b57cec5SDimitry Andric     // Otherwise, we are reading an inlined instance. The top of the
14580b57cec5SDimitry Andric     // inline stack contains the profile of the caller. Insert this
14590b57cec5SDimitry Andric     // callee in the caller's CallsiteMap.
14600b57cec5SDimitry Andric     FunctionSamples *CallerProfile = InlineStack.front();
14610b57cec5SDimitry Andric     uint32_t LineOffset = Offset >> 16;
14620b57cec5SDimitry Andric     uint32_t Discriminator = Offset & 0xffff;
14630b57cec5SDimitry Andric     FProfile = &CallerProfile->functionSamplesAt(
14645ffd83dbSDimitry Andric         LineLocation(LineOffset, Discriminator))[std::string(Name)];
14650b57cec5SDimitry Andric   }
14660b57cec5SDimitry Andric   FProfile->setName(Name);
14670b57cec5SDimitry Andric 
14680b57cec5SDimitry Andric   for (uint32_t I = 0; I < NumPosCounts; ++I) {
14690b57cec5SDimitry Andric     uint32_t Offset;
14700b57cec5SDimitry Andric     if (!GcovBuffer.readInt(Offset))
14710b57cec5SDimitry Andric       return sampleprof_error::truncated;
14720b57cec5SDimitry Andric 
14730b57cec5SDimitry Andric     uint32_t NumTargets;
14740b57cec5SDimitry Andric     if (!GcovBuffer.readInt(NumTargets))
14750b57cec5SDimitry Andric       return sampleprof_error::truncated;
14760b57cec5SDimitry Andric 
14770b57cec5SDimitry Andric     uint64_t Count;
14780b57cec5SDimitry Andric     if (!GcovBuffer.readInt64(Count))
14790b57cec5SDimitry Andric       return sampleprof_error::truncated;
14800b57cec5SDimitry Andric 
14810b57cec5SDimitry Andric     // The line location is encoded in the offset as:
14820b57cec5SDimitry Andric     //   high 16 bits: line offset to the start of the function.
14830b57cec5SDimitry Andric     //   low 16 bits: discriminator.
14840b57cec5SDimitry Andric     uint32_t LineOffset = Offset >> 16;
14850b57cec5SDimitry Andric     uint32_t Discriminator = Offset & 0xffff;
14860b57cec5SDimitry Andric 
14870b57cec5SDimitry Andric     InlineCallStack NewStack;
14880b57cec5SDimitry Andric     NewStack.push_back(FProfile);
1489af732203SDimitry Andric     llvm::append_range(NewStack, InlineStack);
14900b57cec5SDimitry Andric     if (Update) {
14910b57cec5SDimitry Andric       // Walk up the inline stack, adding the samples on this line to
14920b57cec5SDimitry Andric       // the total sample count of the callers in the chain.
14930b57cec5SDimitry Andric       for (auto CallerProfile : NewStack)
14940b57cec5SDimitry Andric         CallerProfile->addTotalSamples(Count);
14950b57cec5SDimitry Andric 
14960b57cec5SDimitry Andric       // Update the body samples for the current profile.
14970b57cec5SDimitry Andric       FProfile->addBodySamples(LineOffset, Discriminator, Count);
14980b57cec5SDimitry Andric     }
14990b57cec5SDimitry Andric 
15000b57cec5SDimitry Andric     // Process the list of functions called at an indirect call site.
15010b57cec5SDimitry Andric     // These are all the targets that a function pointer (or virtual
15020b57cec5SDimitry Andric     // function) resolved at runtime.
15030b57cec5SDimitry Andric     for (uint32_t J = 0; J < NumTargets; J++) {
15040b57cec5SDimitry Andric       uint32_t HistVal;
15050b57cec5SDimitry Andric       if (!GcovBuffer.readInt(HistVal))
15060b57cec5SDimitry Andric         return sampleprof_error::truncated;
15070b57cec5SDimitry Andric 
15080b57cec5SDimitry Andric       if (HistVal != HIST_TYPE_INDIR_CALL_TOPN)
15090b57cec5SDimitry Andric         return sampleprof_error::malformed;
15100b57cec5SDimitry Andric 
15110b57cec5SDimitry Andric       uint64_t TargetIdx;
15120b57cec5SDimitry Andric       if (!GcovBuffer.readInt64(TargetIdx))
15130b57cec5SDimitry Andric         return sampleprof_error::truncated;
15140b57cec5SDimitry Andric       StringRef TargetName(Names[TargetIdx]);
15150b57cec5SDimitry Andric 
15160b57cec5SDimitry Andric       uint64_t TargetCount;
15170b57cec5SDimitry Andric       if (!GcovBuffer.readInt64(TargetCount))
15180b57cec5SDimitry Andric         return sampleprof_error::truncated;
15190b57cec5SDimitry Andric 
15200b57cec5SDimitry Andric       if (Update)
15210b57cec5SDimitry Andric         FProfile->addCalledTargetSamples(LineOffset, Discriminator,
15220b57cec5SDimitry Andric                                          TargetName, TargetCount);
15230b57cec5SDimitry Andric     }
15240b57cec5SDimitry Andric   }
15250b57cec5SDimitry Andric 
15260b57cec5SDimitry Andric   // Process all the inlined callers into the current function. These
15270b57cec5SDimitry Andric   // are all the callsites that were inlined into this function.
15280b57cec5SDimitry Andric   for (uint32_t I = 0; I < NumCallsites; I++) {
15290b57cec5SDimitry Andric     // The offset is encoded as:
15300b57cec5SDimitry Andric     //   high 16 bits: line offset to the start of the function.
15310b57cec5SDimitry Andric     //   low 16 bits: discriminator.
15320b57cec5SDimitry Andric     uint32_t Offset;
15330b57cec5SDimitry Andric     if (!GcovBuffer.readInt(Offset))
15340b57cec5SDimitry Andric       return sampleprof_error::truncated;
15350b57cec5SDimitry Andric     InlineCallStack NewStack;
15360b57cec5SDimitry Andric     NewStack.push_back(FProfile);
1537af732203SDimitry Andric     llvm::append_range(NewStack, InlineStack);
15380b57cec5SDimitry Andric     if (std::error_code EC = readOneFunctionProfile(NewStack, Update, Offset))
15390b57cec5SDimitry Andric       return EC;
15400b57cec5SDimitry Andric   }
15410b57cec5SDimitry Andric 
15420b57cec5SDimitry Andric   return sampleprof_error::success;
15430b57cec5SDimitry Andric }
15440b57cec5SDimitry Andric 
15450b57cec5SDimitry Andric /// Read a GCC AutoFDO profile.
15460b57cec5SDimitry Andric ///
15470b57cec5SDimitry Andric /// This format is generated by the Linux Perf conversion tool at
15480b57cec5SDimitry Andric /// https://github.com/google/autofdo.
readImpl()15498bcb0991SDimitry Andric std::error_code SampleProfileReaderGCC::readImpl() {
1550*5f7ddb14SDimitry Andric   assert(!ProfileIsFSDisciminator && "Gcc profiles not support FSDisciminator");
15510b57cec5SDimitry Andric   // Read the string table.
15520b57cec5SDimitry Andric   if (std::error_code EC = readNameTable())
15530b57cec5SDimitry Andric     return EC;
15540b57cec5SDimitry Andric 
15550b57cec5SDimitry Andric   // Read the source profile.
15560b57cec5SDimitry Andric   if (std::error_code EC = readFunctionProfiles())
15570b57cec5SDimitry Andric     return EC;
15580b57cec5SDimitry Andric 
15590b57cec5SDimitry Andric   return sampleprof_error::success;
15600b57cec5SDimitry Andric }
15610b57cec5SDimitry Andric 
hasFormat(const MemoryBuffer & Buffer)15620b57cec5SDimitry Andric bool SampleProfileReaderGCC::hasFormat(const MemoryBuffer &Buffer) {
15630b57cec5SDimitry Andric   StringRef Magic(reinterpret_cast<const char *>(Buffer.getBufferStart()));
15640b57cec5SDimitry Andric   return Magic == "adcg*704";
15650b57cec5SDimitry Andric }
15660b57cec5SDimitry Andric 
applyRemapping(LLVMContext & Ctx)15678bcb0991SDimitry Andric void SampleProfileReaderItaniumRemapper::applyRemapping(LLVMContext &Ctx) {
15685ffd83dbSDimitry Andric   // If the reader uses MD5 to represent string, we can't remap it because
15690b57cec5SDimitry Andric   // we don't know what the original function names were.
15705ffd83dbSDimitry Andric   if (Reader.useMD5()) {
15710b57cec5SDimitry Andric     Ctx.diagnose(DiagnosticInfoSampleProfile(
15728bcb0991SDimitry Andric         Reader.getBuffer()->getBufferIdentifier(),
15730b57cec5SDimitry Andric         "Profile data remapping cannot be applied to profile data "
15740b57cec5SDimitry Andric         "in compact format (original mangled names are not available).",
15750b57cec5SDimitry Andric         DS_Warning));
15768bcb0991SDimitry Andric     return;
15770b57cec5SDimitry Andric   }
15780b57cec5SDimitry Andric 
1579af732203SDimitry Andric   // CSSPGO-TODO: Remapper is not yet supported.
1580af732203SDimitry Andric   // We will need to remap the entire context string.
15818bcb0991SDimitry Andric   assert(Remappings && "should be initialized while creating remapper");
1582af732203SDimitry Andric   for (auto &Sample : Reader.getProfiles()) {
1583af732203SDimitry Andric     DenseSet<StringRef> NamesInSample;
1584af732203SDimitry Andric     Sample.second.findAllNames(NamesInSample);
1585af732203SDimitry Andric     for (auto &Name : NamesInSample)
1586af732203SDimitry Andric       if (auto Key = Remappings->insert(Name))
1587af732203SDimitry Andric         NameMap.insert({Key, Name});
1588af732203SDimitry Andric   }
15890b57cec5SDimitry Andric 
15908bcb0991SDimitry Andric   RemappingApplied = true;
15910b57cec5SDimitry Andric }
15920b57cec5SDimitry Andric 
1593af732203SDimitry Andric Optional<StringRef>
lookUpNameInProfile(StringRef Fname)1594af732203SDimitry Andric SampleProfileReaderItaniumRemapper::lookUpNameInProfile(StringRef Fname) {
15958bcb0991SDimitry Andric   if (auto Key = Remappings->lookup(Fname))
1596af732203SDimitry Andric     return NameMap.lookup(Key);
1597af732203SDimitry Andric   return None;
15980b57cec5SDimitry Andric }
15990b57cec5SDimitry Andric 
16000b57cec5SDimitry Andric /// Prepare a memory buffer for the contents of \p Filename.
16010b57cec5SDimitry Andric ///
16020b57cec5SDimitry Andric /// \returns an error code indicating the status of the buffer.
16030b57cec5SDimitry Andric static ErrorOr<std::unique_ptr<MemoryBuffer>>
setupMemoryBuffer(const Twine & Filename)16040b57cec5SDimitry Andric setupMemoryBuffer(const Twine &Filename) {
1605*5f7ddb14SDimitry Andric   auto BufferOrErr = MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/true);
16060b57cec5SDimitry Andric   if (std::error_code EC = BufferOrErr.getError())
16070b57cec5SDimitry Andric     return EC;
16080b57cec5SDimitry Andric   auto Buffer = std::move(BufferOrErr.get());
16090b57cec5SDimitry Andric 
16100b57cec5SDimitry Andric   // Sanity check the file.
16110b57cec5SDimitry Andric   if (uint64_t(Buffer->getBufferSize()) > std::numeric_limits<uint32_t>::max())
16120b57cec5SDimitry Andric     return sampleprof_error::too_large;
16130b57cec5SDimitry Andric 
16140b57cec5SDimitry Andric   return std::move(Buffer);
16150b57cec5SDimitry Andric }
16160b57cec5SDimitry Andric 
16170b57cec5SDimitry Andric /// Create a sample profile reader based on the format of the input file.
16180b57cec5SDimitry Andric ///
16190b57cec5SDimitry Andric /// \param Filename The file to open.
16200b57cec5SDimitry Andric ///
16210b57cec5SDimitry Andric /// \param C The LLVM context to use to emit diagnostics.
16220b57cec5SDimitry Andric ///
1623*5f7ddb14SDimitry Andric /// \param P The FSDiscriminatorPass.
1624*5f7ddb14SDimitry Andric ///
16258bcb0991SDimitry Andric /// \param RemapFilename The file used for profile remapping.
16268bcb0991SDimitry Andric ///
16270b57cec5SDimitry Andric /// \returns an error code indicating the status of the created reader.
16280b57cec5SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileReader>>
create(const std::string Filename,LLVMContext & C,FSDiscriminatorPass P,const std::string RemapFilename)16298bcb0991SDimitry Andric SampleProfileReader::create(const std::string Filename, LLVMContext &C,
1630*5f7ddb14SDimitry Andric                             FSDiscriminatorPass P,
16318bcb0991SDimitry Andric                             const std::string RemapFilename) {
16320b57cec5SDimitry Andric   auto BufferOrError = setupMemoryBuffer(Filename);
16330b57cec5SDimitry Andric   if (std::error_code EC = BufferOrError.getError())
16340b57cec5SDimitry Andric     return EC;
1635*5f7ddb14SDimitry Andric   return create(BufferOrError.get(), C, P, RemapFilename);
16360b57cec5SDimitry Andric }
16370b57cec5SDimitry Andric 
16380b57cec5SDimitry Andric /// Create a sample profile remapper from the given input, to remap the
16390b57cec5SDimitry Andric /// function names in the given profile data.
16400b57cec5SDimitry Andric ///
16410b57cec5SDimitry Andric /// \param Filename The file to open.
16420b57cec5SDimitry Andric ///
16438bcb0991SDimitry Andric /// \param Reader The profile reader the remapper is going to be applied to.
16448bcb0991SDimitry Andric ///
16450b57cec5SDimitry Andric /// \param C The LLVM context to use to emit diagnostics.
16460b57cec5SDimitry Andric ///
16470b57cec5SDimitry Andric /// \returns an error code indicating the status of the created reader.
16488bcb0991SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileReaderItaniumRemapper>>
create(const std::string Filename,SampleProfileReader & Reader,LLVMContext & C)16498bcb0991SDimitry Andric SampleProfileReaderItaniumRemapper::create(const std::string Filename,
16508bcb0991SDimitry Andric                                            SampleProfileReader &Reader,
16518bcb0991SDimitry Andric                                            LLVMContext &C) {
16520b57cec5SDimitry Andric   auto BufferOrError = setupMemoryBuffer(Filename);
16530b57cec5SDimitry Andric   if (std::error_code EC = BufferOrError.getError())
16540b57cec5SDimitry Andric     return EC;
16558bcb0991SDimitry Andric   return create(BufferOrError.get(), Reader, C);
16568bcb0991SDimitry Andric }
16578bcb0991SDimitry Andric 
16588bcb0991SDimitry Andric /// Create a sample profile remapper from the given input, to remap the
16598bcb0991SDimitry Andric /// function names in the given profile data.
16608bcb0991SDimitry Andric ///
16618bcb0991SDimitry Andric /// \param B The memory buffer to create the reader from (assumes ownership).
16628bcb0991SDimitry Andric ///
16638bcb0991SDimitry Andric /// \param C The LLVM context to use to emit diagnostics.
16648bcb0991SDimitry Andric ///
16658bcb0991SDimitry Andric /// \param Reader The profile reader the remapper is going to be applied to.
16668bcb0991SDimitry Andric ///
16678bcb0991SDimitry Andric /// \returns an error code indicating the status of the created reader.
16688bcb0991SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileReaderItaniumRemapper>>
create(std::unique_ptr<MemoryBuffer> & B,SampleProfileReader & Reader,LLVMContext & C)16698bcb0991SDimitry Andric SampleProfileReaderItaniumRemapper::create(std::unique_ptr<MemoryBuffer> &B,
16708bcb0991SDimitry Andric                                            SampleProfileReader &Reader,
16718bcb0991SDimitry Andric                                            LLVMContext &C) {
16728bcb0991SDimitry Andric   auto Remappings = std::make_unique<SymbolRemappingReader>();
16738bcb0991SDimitry Andric   if (Error E = Remappings->read(*B.get())) {
16748bcb0991SDimitry Andric     handleAllErrors(
16758bcb0991SDimitry Andric         std::move(E), [&](const SymbolRemappingParseError &ParseError) {
16768bcb0991SDimitry Andric           C.diagnose(DiagnosticInfoSampleProfile(B->getBufferIdentifier(),
16778bcb0991SDimitry Andric                                                  ParseError.getLineNum(),
16788bcb0991SDimitry Andric                                                  ParseError.getMessage()));
16798bcb0991SDimitry Andric         });
16808bcb0991SDimitry Andric     return sampleprof_error::malformed;
16818bcb0991SDimitry Andric   }
16828bcb0991SDimitry Andric 
16838bcb0991SDimitry Andric   return std::make_unique<SampleProfileReaderItaniumRemapper>(
16848bcb0991SDimitry Andric       std::move(B), std::move(Remappings), Reader);
16850b57cec5SDimitry Andric }
16860b57cec5SDimitry Andric 
16870b57cec5SDimitry Andric /// Create a sample profile reader based on the format of the input data.
16880b57cec5SDimitry Andric ///
16890b57cec5SDimitry Andric /// \param B The memory buffer to create the reader from (assumes ownership).
16900b57cec5SDimitry Andric ///
16910b57cec5SDimitry Andric /// \param C The LLVM context to use to emit diagnostics.
16920b57cec5SDimitry Andric ///
1693*5f7ddb14SDimitry Andric /// \param P The FSDiscriminatorPass.
1694*5f7ddb14SDimitry Andric ///
16958bcb0991SDimitry Andric /// \param RemapFilename The file used for profile remapping.
16968bcb0991SDimitry Andric ///
16970b57cec5SDimitry Andric /// \returns an error code indicating the status of the created reader.
16980b57cec5SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileReader>>
create(std::unique_ptr<MemoryBuffer> & B,LLVMContext & C,FSDiscriminatorPass P,const std::string RemapFilename)16998bcb0991SDimitry Andric SampleProfileReader::create(std::unique_ptr<MemoryBuffer> &B, LLVMContext &C,
1700*5f7ddb14SDimitry Andric                             FSDiscriminatorPass P,
17018bcb0991SDimitry Andric                             const std::string RemapFilename) {
17020b57cec5SDimitry Andric   std::unique_ptr<SampleProfileReader> Reader;
17030b57cec5SDimitry Andric   if (SampleProfileReaderRawBinary::hasFormat(*B))
17040b57cec5SDimitry Andric     Reader.reset(new SampleProfileReaderRawBinary(std::move(B), C));
17058bcb0991SDimitry Andric   else if (SampleProfileReaderExtBinary::hasFormat(*B))
17068bcb0991SDimitry Andric     Reader.reset(new SampleProfileReaderExtBinary(std::move(B), C));
17070b57cec5SDimitry Andric   else if (SampleProfileReaderCompactBinary::hasFormat(*B))
17080b57cec5SDimitry Andric     Reader.reset(new SampleProfileReaderCompactBinary(std::move(B), C));
17090b57cec5SDimitry Andric   else if (SampleProfileReaderGCC::hasFormat(*B))
17100b57cec5SDimitry Andric     Reader.reset(new SampleProfileReaderGCC(std::move(B), C));
17110b57cec5SDimitry Andric   else if (SampleProfileReaderText::hasFormat(*B))
17120b57cec5SDimitry Andric     Reader.reset(new SampleProfileReaderText(std::move(B), C));
17130b57cec5SDimitry Andric   else
17140b57cec5SDimitry Andric     return sampleprof_error::unrecognized_format;
17150b57cec5SDimitry Andric 
17168bcb0991SDimitry Andric   if (!RemapFilename.empty()) {
17178bcb0991SDimitry Andric     auto ReaderOrErr =
17188bcb0991SDimitry Andric         SampleProfileReaderItaniumRemapper::create(RemapFilename, *Reader, C);
17198bcb0991SDimitry Andric     if (std::error_code EC = ReaderOrErr.getError()) {
17208bcb0991SDimitry Andric       std::string Msg = "Could not create remapper: " + EC.message();
17218bcb0991SDimitry Andric       C.diagnose(DiagnosticInfoSampleProfile(RemapFilename, Msg));
17220b57cec5SDimitry Andric       return EC;
17238bcb0991SDimitry Andric     }
17248bcb0991SDimitry Andric     Reader->Remapper = std::move(ReaderOrErr.get());
17258bcb0991SDimitry Andric   }
17268bcb0991SDimitry Andric 
17278bcb0991SDimitry Andric   FunctionSamples::Format = Reader->getFormat();
17288bcb0991SDimitry Andric   if (std::error_code EC = Reader->readHeader()) {
17298bcb0991SDimitry Andric     return EC;
17308bcb0991SDimitry Andric   }
17310b57cec5SDimitry Andric 
1732*5f7ddb14SDimitry Andric   Reader->setDiscriminatorMaskedBitFrom(P);
1733*5f7ddb14SDimitry Andric 
17340b57cec5SDimitry Andric   return std::move(Reader);
17350b57cec5SDimitry Andric }
17360b57cec5SDimitry Andric 
17370b57cec5SDimitry Andric // For text and GCC file formats, we compute the summary after reading the
17380b57cec5SDimitry Andric // profile. Binary format has the profile summary in its header.
computeSummary()17390b57cec5SDimitry Andric void SampleProfileReader::computeSummary() {
17400b57cec5SDimitry Andric   SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
1741af732203SDimitry Andric   Summary = Builder.computeSummaryForProfiles(Profiles);
17420b57cec5SDimitry Andric }
1743