xref: /freebsd-src/contrib/llvm-project/llvm/lib/ProfileData/InstrProfReader.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- InstrProfReader.cpp - Instrumented profiling reader ----------------===//
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 contains support for reading profiling data for clang's
100b57cec5SDimitry Andric // instrumentation based PGO and coverage.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfReader.h"
150b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
160b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
175ffd83dbSDimitry Andric #include "llvm/ADT/StringExtras.h"
180b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
190b57cec5SDimitry Andric #include "llvm/IR/ProfileSummary.h"
200b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProf.h"
2181ad6265SDimitry Andric #include "llvm/ProfileData/MemProf.h"
220b57cec5SDimitry Andric #include "llvm/ProfileData/ProfileCommon.h"
2306c3fb27SDimitry Andric #include "llvm/ProfileData/SymbolRemappingReader.h"
240b57cec5SDimitry Andric #include "llvm/Support/Endian.h"
250b57cec5SDimitry Andric #include "llvm/Support/Error.h"
260b57cec5SDimitry Andric #include "llvm/Support/ErrorOr.h"
27*0fca6ea1SDimitry Andric #include "llvm/Support/FormatVariadic.h"
280b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
290b57cec5SDimitry Andric #include "llvm/Support/SwapByteOrder.h"
3006c3fb27SDimitry Andric #include "llvm/Support/VirtualFileSystem.h"
310b57cec5SDimitry Andric #include <algorithm>
320b57cec5SDimitry Andric #include <cstddef>
330b57cec5SDimitry Andric #include <cstdint>
340b57cec5SDimitry Andric #include <limits>
350b57cec5SDimitry Andric #include <memory>
36*0fca6ea1SDimitry Andric #include <optional>
370b57cec5SDimitry Andric #include <system_error>
380b57cec5SDimitry Andric #include <utility>
390b57cec5SDimitry Andric #include <vector>
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric using namespace llvm;
420b57cec5SDimitry Andric 
435f757f3fSDimitry Andric // Extracts the variant information from the top 32 bits in the version and
441fd87a68SDimitry Andric // returns an enum specifying the variants present.
451fd87a68SDimitry Andric static InstrProfKind getProfileKindFromVersion(uint64_t Version) {
461fd87a68SDimitry Andric   InstrProfKind ProfileKind = InstrProfKind::Unknown;
471fd87a68SDimitry Andric   if (Version & VARIANT_MASK_IR_PROF) {
4881ad6265SDimitry Andric     ProfileKind |= InstrProfKind::IRInstrumentation;
491fd87a68SDimitry Andric   }
501fd87a68SDimitry Andric   if (Version & VARIANT_MASK_CSIR_PROF) {
5181ad6265SDimitry Andric     ProfileKind |= InstrProfKind::ContextSensitive;
521fd87a68SDimitry Andric   }
531fd87a68SDimitry Andric   if (Version & VARIANT_MASK_INSTR_ENTRY) {
5481ad6265SDimitry Andric     ProfileKind |= InstrProfKind::FunctionEntryInstrumentation;
551fd87a68SDimitry Andric   }
561fd87a68SDimitry Andric   if (Version & VARIANT_MASK_BYTE_COVERAGE) {
571fd87a68SDimitry Andric     ProfileKind |= InstrProfKind::SingleByteCoverage;
581fd87a68SDimitry Andric   }
591fd87a68SDimitry Andric   if (Version & VARIANT_MASK_FUNCTION_ENTRY_ONLY) {
601fd87a68SDimitry Andric     ProfileKind |= InstrProfKind::FunctionEntryOnly;
611fd87a68SDimitry Andric   }
6281ad6265SDimitry Andric   if (Version & VARIANT_MASK_MEMPROF) {
6381ad6265SDimitry Andric     ProfileKind |= InstrProfKind::MemProf;
6481ad6265SDimitry Andric   }
6506c3fb27SDimitry Andric   if (Version & VARIANT_MASK_TEMPORAL_PROF) {
6606c3fb27SDimitry Andric     ProfileKind |= InstrProfKind::TemporalProfile;
6706c3fb27SDimitry Andric   }
681fd87a68SDimitry Andric   return ProfileKind;
691fd87a68SDimitry Andric }
701fd87a68SDimitry Andric 
710b57cec5SDimitry Andric static Expected<std::unique_ptr<MemoryBuffer>>
7206c3fb27SDimitry Andric setupMemoryBuffer(const Twine &Filename, vfs::FileSystem &FS) {
7306c3fb27SDimitry Andric   auto BufferOrErr = Filename.str() == "-" ? MemoryBuffer::getSTDIN()
7406c3fb27SDimitry Andric                                            : FS.getBufferForFile(Filename);
750b57cec5SDimitry Andric   if (std::error_code EC = BufferOrErr.getError())
760b57cec5SDimitry Andric     return errorCodeToError(EC);
770b57cec5SDimitry Andric   return std::move(BufferOrErr.get());
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric static Error initializeReader(InstrProfReader &Reader) {
810b57cec5SDimitry Andric   return Reader.readHeader();
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric 
84bdd1243dSDimitry Andric /// Read a list of binary ids from a profile that consist of
85bdd1243dSDimitry Andric /// a. uint64_t binary id length
86bdd1243dSDimitry Andric /// b. uint8_t  binary id data
87bdd1243dSDimitry Andric /// c. uint8_t  padding (if necessary)
88bdd1243dSDimitry Andric /// This function is shared between raw and indexed profiles.
89bdd1243dSDimitry Andric /// Raw profiles are in host-endian format, and indexed profiles are in
90bdd1243dSDimitry Andric /// little-endian format. So, this function takes an argument indicating the
91bdd1243dSDimitry Andric /// associated endian format to read the binary ids correctly.
92bdd1243dSDimitry Andric static Error
93bdd1243dSDimitry Andric readBinaryIdsInternal(const MemoryBuffer &DataBuffer,
94*0fca6ea1SDimitry Andric                       ArrayRef<uint8_t> BinaryIdsBuffer,
95bdd1243dSDimitry Andric                       std::vector<llvm::object::BuildID> &BinaryIds,
965f757f3fSDimitry Andric                       const llvm::endianness Endian) {
97bdd1243dSDimitry Andric   using namespace support;
98bdd1243dSDimitry Andric 
99*0fca6ea1SDimitry Andric   const uint64_t BinaryIdsSize = BinaryIdsBuffer.size();
100*0fca6ea1SDimitry Andric   const uint8_t *BinaryIdsStart = BinaryIdsBuffer.data();
101*0fca6ea1SDimitry Andric 
102bdd1243dSDimitry Andric   if (BinaryIdsSize == 0)
103bdd1243dSDimitry Andric     return Error::success();
104bdd1243dSDimitry Andric 
105bdd1243dSDimitry Andric   const uint8_t *BI = BinaryIdsStart;
106bdd1243dSDimitry Andric   const uint8_t *BIEnd = BinaryIdsStart + BinaryIdsSize;
107bdd1243dSDimitry Andric   const uint8_t *End =
108bdd1243dSDimitry Andric       reinterpret_cast<const uint8_t *>(DataBuffer.getBufferEnd());
109bdd1243dSDimitry Andric 
110bdd1243dSDimitry Andric   while (BI < BIEnd) {
111bdd1243dSDimitry Andric     size_t Remaining = BIEnd - BI;
112bdd1243dSDimitry Andric     // There should be enough left to read the binary id length.
113bdd1243dSDimitry Andric     if (Remaining < sizeof(uint64_t))
114bdd1243dSDimitry Andric       return make_error<InstrProfError>(
115bdd1243dSDimitry Andric           instrprof_error::malformed,
116bdd1243dSDimitry Andric           "not enough data to read binary id length");
117bdd1243dSDimitry Andric 
118*0fca6ea1SDimitry Andric     uint64_t BILen = endian::readNext<uint64_t>(BI, Endian);
119bdd1243dSDimitry Andric     if (BILen == 0)
120bdd1243dSDimitry Andric       return make_error<InstrProfError>(instrprof_error::malformed,
121bdd1243dSDimitry Andric                                         "binary id length is 0");
122bdd1243dSDimitry Andric 
123bdd1243dSDimitry Andric     Remaining = BIEnd - BI;
124bdd1243dSDimitry Andric     // There should be enough left to read the binary id data.
125bdd1243dSDimitry Andric     if (Remaining < alignToPowerOf2(BILen, sizeof(uint64_t)))
126bdd1243dSDimitry Andric       return make_error<InstrProfError>(
127bdd1243dSDimitry Andric           instrprof_error::malformed, "not enough data to read binary id data");
128bdd1243dSDimitry Andric 
129bdd1243dSDimitry Andric     // Add binary id to the binary ids list.
130bdd1243dSDimitry Andric     BinaryIds.push_back(object::BuildID(BI, BI + BILen));
131bdd1243dSDimitry Andric 
132bdd1243dSDimitry Andric     // Increment by binary id data length, which aligned to the size of uint64.
133bdd1243dSDimitry Andric     BI += alignToPowerOf2(BILen, sizeof(uint64_t));
134bdd1243dSDimitry Andric     if (BI > End)
135bdd1243dSDimitry Andric       return make_error<InstrProfError>(
136bdd1243dSDimitry Andric           instrprof_error::malformed,
137bdd1243dSDimitry Andric           "binary id section is greater than buffer size");
138bdd1243dSDimitry Andric   }
139bdd1243dSDimitry Andric 
140bdd1243dSDimitry Andric   return Error::success();
141bdd1243dSDimitry Andric }
142bdd1243dSDimitry Andric 
143*0fca6ea1SDimitry Andric static void printBinaryIdsInternal(raw_ostream &OS,
144*0fca6ea1SDimitry Andric                                    ArrayRef<llvm::object::BuildID> BinaryIds) {
145bdd1243dSDimitry Andric   OS << "Binary IDs: \n";
146*0fca6ea1SDimitry Andric   for (const auto &BI : BinaryIds) {
147*0fca6ea1SDimitry Andric     for (auto I : BI)
148*0fca6ea1SDimitry Andric       OS << format("%02x", I);
149bdd1243dSDimitry Andric     OS << "\n";
150bdd1243dSDimitry Andric   }
151bdd1243dSDimitry Andric }
152bdd1243dSDimitry Andric 
1530b57cec5SDimitry Andric Expected<std::unique_ptr<InstrProfReader>>
15406c3fb27SDimitry Andric InstrProfReader::create(const Twine &Path, vfs::FileSystem &FS,
1555f757f3fSDimitry Andric                         const InstrProfCorrelator *Correlator,
1565f757f3fSDimitry Andric                         std::function<void(Error)> Warn) {
1570b57cec5SDimitry Andric   // Set up the buffer to read.
15806c3fb27SDimitry Andric   auto BufferOrError = setupMemoryBuffer(Path, FS);
1590b57cec5SDimitry Andric   if (Error E = BufferOrError.takeError())
1600b57cec5SDimitry Andric     return std::move(E);
1615f757f3fSDimitry Andric   return InstrProfReader::create(std::move(BufferOrError.get()), Correlator,
1625f757f3fSDimitry Andric                                  Warn);
1630b57cec5SDimitry Andric }
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric Expected<std::unique_ptr<InstrProfReader>>
1660eae32dcSDimitry Andric InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
1675f757f3fSDimitry Andric                         const InstrProfCorrelator *Correlator,
1685f757f3fSDimitry Andric                         std::function<void(Error)> Warn) {
1690b57cec5SDimitry Andric   if (Buffer->getBufferSize() == 0)
1700b57cec5SDimitry Andric     return make_error<InstrProfError>(instrprof_error::empty_raw_profile);
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric   std::unique_ptr<InstrProfReader> Result;
1730b57cec5SDimitry Andric   // Create the reader.
1740b57cec5SDimitry Andric   if (IndexedInstrProfReader::hasFormat(*Buffer))
1750b57cec5SDimitry Andric     Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
1760b57cec5SDimitry Andric   else if (RawInstrProfReader64::hasFormat(*Buffer))
1775f757f3fSDimitry Andric     Result.reset(new RawInstrProfReader64(std::move(Buffer), Correlator, Warn));
1780b57cec5SDimitry Andric   else if (RawInstrProfReader32::hasFormat(*Buffer))
1795f757f3fSDimitry Andric     Result.reset(new RawInstrProfReader32(std::move(Buffer), Correlator, Warn));
1800b57cec5SDimitry Andric   else if (TextInstrProfReader::hasFormat(*Buffer))
1810b57cec5SDimitry Andric     Result.reset(new TextInstrProfReader(std::move(Buffer)));
1820b57cec5SDimitry Andric   else
1830b57cec5SDimitry Andric     return make_error<InstrProfError>(instrprof_error::unrecognized_format);
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric   // Initialize the reader and return the result.
1860b57cec5SDimitry Andric   if (Error E = initializeReader(*Result))
1870b57cec5SDimitry Andric     return std::move(E);
1880b57cec5SDimitry Andric 
1890b57cec5SDimitry Andric   return std::move(Result);
1900b57cec5SDimitry Andric }
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric Expected<std::unique_ptr<IndexedInstrProfReader>>
19306c3fb27SDimitry Andric IndexedInstrProfReader::create(const Twine &Path, vfs::FileSystem &FS,
19406c3fb27SDimitry Andric                                const Twine &RemappingPath) {
1950b57cec5SDimitry Andric   // Set up the buffer to read.
19606c3fb27SDimitry Andric   auto BufferOrError = setupMemoryBuffer(Path, FS);
1970b57cec5SDimitry Andric   if (Error E = BufferOrError.takeError())
1980b57cec5SDimitry Andric     return std::move(E);
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric   // Set up the remapping buffer if requested.
2010b57cec5SDimitry Andric   std::unique_ptr<MemoryBuffer> RemappingBuffer;
2020b57cec5SDimitry Andric   std::string RemappingPathStr = RemappingPath.str();
2030b57cec5SDimitry Andric   if (!RemappingPathStr.empty()) {
20406c3fb27SDimitry Andric     auto RemappingBufferOrError = setupMemoryBuffer(RemappingPathStr, FS);
2050b57cec5SDimitry Andric     if (Error E = RemappingBufferOrError.takeError())
2060b57cec5SDimitry Andric       return std::move(E);
2070b57cec5SDimitry Andric     RemappingBuffer = std::move(RemappingBufferOrError.get());
2080b57cec5SDimitry Andric   }
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric   return IndexedInstrProfReader::create(std::move(BufferOrError.get()),
2110b57cec5SDimitry Andric                                         std::move(RemappingBuffer));
2120b57cec5SDimitry Andric }
2130b57cec5SDimitry Andric 
2140b57cec5SDimitry Andric Expected<std::unique_ptr<IndexedInstrProfReader>>
2150b57cec5SDimitry Andric IndexedInstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
2160b57cec5SDimitry Andric                                std::unique_ptr<MemoryBuffer> RemappingBuffer) {
2170b57cec5SDimitry Andric   // Create the reader.
2180b57cec5SDimitry Andric   if (!IndexedInstrProfReader::hasFormat(*Buffer))
2190b57cec5SDimitry Andric     return make_error<InstrProfError>(instrprof_error::bad_magic);
2208bcb0991SDimitry Andric   auto Result = std::make_unique<IndexedInstrProfReader>(
2210b57cec5SDimitry Andric       std::move(Buffer), std::move(RemappingBuffer));
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric   // Initialize the reader and return the result.
2240b57cec5SDimitry Andric   if (Error E = initializeReader(*Result))
2250b57cec5SDimitry Andric     return std::move(E);
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric   return std::move(Result);
2280b57cec5SDimitry Andric }
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric bool TextInstrProfReader::hasFormat(const MemoryBuffer &Buffer) {
2310b57cec5SDimitry Andric   // Verify that this really looks like plain ASCII text by checking a
2320b57cec5SDimitry Andric   // 'reasonable' number of characters (up to profile magic size).
2330b57cec5SDimitry Andric   size_t count = std::min(Buffer.getBufferSize(), sizeof(uint64_t));
2340b57cec5SDimitry Andric   StringRef buffer = Buffer.getBufferStart();
2350b57cec5SDimitry Andric   return count == 0 ||
2360b57cec5SDimitry Andric          std::all_of(buffer.begin(), buffer.begin() + count,
2375ffd83dbSDimitry Andric                      [](char c) { return isPrint(c) || isSpace(c); });
2380b57cec5SDimitry Andric }
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric // Read the profile variant flag from the header: ":FE" means this is a FE
2410b57cec5SDimitry Andric // generated profile. ":IR" means this is an IR level profile. Other strings
2420b57cec5SDimitry Andric // with a leading ':' will be reported an error format.
2430b57cec5SDimitry Andric Error TextInstrProfReader::readHeader() {
2440b57cec5SDimitry Andric   Symtab.reset(new InstrProfSymtab());
245e8d8bef9SDimitry Andric 
2465f757f3fSDimitry Andric   while (Line->starts_with(":")) {
247e8d8bef9SDimitry Andric     StringRef Str = Line->substr(1);
248fe6060f1SDimitry Andric     if (Str.equals_insensitive("ir"))
24981ad6265SDimitry Andric       ProfileKind |= InstrProfKind::IRInstrumentation;
250fe6060f1SDimitry Andric     else if (Str.equals_insensitive("fe"))
25181ad6265SDimitry Andric       ProfileKind |= InstrProfKind::FrontendInstrumentation;
252fe6060f1SDimitry Andric     else if (Str.equals_insensitive("csir")) {
25381ad6265SDimitry Andric       ProfileKind |= InstrProfKind::IRInstrumentation;
25481ad6265SDimitry Andric       ProfileKind |= InstrProfKind::ContextSensitive;
255fe6060f1SDimitry Andric     } else if (Str.equals_insensitive("entry_first"))
25681ad6265SDimitry Andric       ProfileKind |= InstrProfKind::FunctionEntryInstrumentation;
257fe6060f1SDimitry Andric     else if (Str.equals_insensitive("not_entry_first"))
25881ad6265SDimitry Andric       ProfileKind &= ~InstrProfKind::FunctionEntryInstrumentation;
2595f757f3fSDimitry Andric     else if (Str.equals_insensitive("single_byte_coverage"))
2605f757f3fSDimitry Andric       ProfileKind |= InstrProfKind::SingleByteCoverage;
26106c3fb27SDimitry Andric     else if (Str.equals_insensitive("temporal_prof_traces")) {
26206c3fb27SDimitry Andric       ProfileKind |= InstrProfKind::TemporalProfile;
26306c3fb27SDimitry Andric       if (auto Err = readTemporalProfTraceData())
26406c3fb27SDimitry Andric         return error(std::move(Err));
26506c3fb27SDimitry Andric     } else
2660b57cec5SDimitry Andric       return error(instrprof_error::bad_header);
2670b57cec5SDimitry Andric     ++Line;
268e8d8bef9SDimitry Andric   }
2690b57cec5SDimitry Andric   return success();
2700b57cec5SDimitry Andric }
2710b57cec5SDimitry Andric 
27206c3fb27SDimitry Andric /// Temporal profile trace data is stored in the header immediately after
27306c3fb27SDimitry Andric /// ":temporal_prof_traces". The first integer is the number of traces, the
27406c3fb27SDimitry Andric /// second integer is the stream size, then the following lines are the actual
27506c3fb27SDimitry Andric /// traces which consist of a weight and a comma separated list of function
27606c3fb27SDimitry Andric /// names.
27706c3fb27SDimitry Andric Error TextInstrProfReader::readTemporalProfTraceData() {
27806c3fb27SDimitry Andric   if ((++Line).is_at_end())
27906c3fb27SDimitry Andric     return error(instrprof_error::eof);
28006c3fb27SDimitry Andric 
28106c3fb27SDimitry Andric   uint32_t NumTraces;
28206c3fb27SDimitry Andric   if (Line->getAsInteger(0, NumTraces))
28306c3fb27SDimitry Andric     return error(instrprof_error::malformed);
28406c3fb27SDimitry Andric 
28506c3fb27SDimitry Andric   if ((++Line).is_at_end())
28606c3fb27SDimitry Andric     return error(instrprof_error::eof);
28706c3fb27SDimitry Andric 
28806c3fb27SDimitry Andric   if (Line->getAsInteger(0, TemporalProfTraceStreamSize))
28906c3fb27SDimitry Andric     return error(instrprof_error::malformed);
29006c3fb27SDimitry Andric 
29106c3fb27SDimitry Andric   for (uint32_t i = 0; i < NumTraces; i++) {
29206c3fb27SDimitry Andric     if ((++Line).is_at_end())
29306c3fb27SDimitry Andric       return error(instrprof_error::eof);
29406c3fb27SDimitry Andric 
29506c3fb27SDimitry Andric     TemporalProfTraceTy Trace;
29606c3fb27SDimitry Andric     if (Line->getAsInteger(0, Trace.Weight))
29706c3fb27SDimitry Andric       return error(instrprof_error::malformed);
29806c3fb27SDimitry Andric 
29906c3fb27SDimitry Andric     if ((++Line).is_at_end())
30006c3fb27SDimitry Andric       return error(instrprof_error::eof);
30106c3fb27SDimitry Andric 
30206c3fb27SDimitry Andric     SmallVector<StringRef> FuncNames;
30306c3fb27SDimitry Andric     Line->split(FuncNames, ",", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
30406c3fb27SDimitry Andric     for (auto &FuncName : FuncNames)
30506c3fb27SDimitry Andric       Trace.FunctionNameRefs.push_back(
30606c3fb27SDimitry Andric           IndexedInstrProf::ComputeHash(FuncName.trim()));
30706c3fb27SDimitry Andric     TemporalProfTraces.push_back(std::move(Trace));
30806c3fb27SDimitry Andric   }
30906c3fb27SDimitry Andric   return success();
31006c3fb27SDimitry Andric }
31106c3fb27SDimitry Andric 
3120b57cec5SDimitry Andric Error
3130b57cec5SDimitry Andric TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) {
3140b57cec5SDimitry Andric 
3150b57cec5SDimitry Andric #define CHECK_LINE_END(Line)                                                   \
3160b57cec5SDimitry Andric   if (Line.is_at_end())                                                        \
3170b57cec5SDimitry Andric     return error(instrprof_error::truncated);
3180b57cec5SDimitry Andric #define READ_NUM(Str, Dst)                                                     \
3190b57cec5SDimitry Andric   if ((Str).getAsInteger(10, (Dst)))                                           \
3200b57cec5SDimitry Andric     return error(instrprof_error::malformed);
3210b57cec5SDimitry Andric #define VP_READ_ADVANCE(Val)                                                   \
3220b57cec5SDimitry Andric   CHECK_LINE_END(Line);                                                        \
3230b57cec5SDimitry Andric   uint32_t Val;                                                                \
3240b57cec5SDimitry Andric   READ_NUM((*Line), (Val));                                                    \
3250b57cec5SDimitry Andric   Line++;
3260b57cec5SDimitry Andric 
3270b57cec5SDimitry Andric   if (Line.is_at_end())
3280b57cec5SDimitry Andric     return success();
3290b57cec5SDimitry Andric 
3300b57cec5SDimitry Andric   uint32_t NumValueKinds;
3310b57cec5SDimitry Andric   if (Line->getAsInteger(10, NumValueKinds)) {
3320b57cec5SDimitry Andric     // No value profile data
3330b57cec5SDimitry Andric     return success();
3340b57cec5SDimitry Andric   }
3350b57cec5SDimitry Andric   if (NumValueKinds == 0 || NumValueKinds > IPVK_Last + 1)
336349cc55cSDimitry Andric     return error(instrprof_error::malformed,
337349cc55cSDimitry Andric                  "number of value kinds is invalid");
3380b57cec5SDimitry Andric   Line++;
3390b57cec5SDimitry Andric 
3400b57cec5SDimitry Andric   for (uint32_t VK = 0; VK < NumValueKinds; VK++) {
3410b57cec5SDimitry Andric     VP_READ_ADVANCE(ValueKind);
3420b57cec5SDimitry Andric     if (ValueKind > IPVK_Last)
343349cc55cSDimitry Andric       return error(instrprof_error::malformed, "value kind is invalid");
344349cc55cSDimitry Andric     ;
3450b57cec5SDimitry Andric     VP_READ_ADVANCE(NumValueSites);
3460b57cec5SDimitry Andric     if (!NumValueSites)
3470b57cec5SDimitry Andric       continue;
3480b57cec5SDimitry Andric 
3490b57cec5SDimitry Andric     Record.reserveSites(VK, NumValueSites);
3500b57cec5SDimitry Andric     for (uint32_t S = 0; S < NumValueSites; S++) {
3510b57cec5SDimitry Andric       VP_READ_ADVANCE(NumValueData);
3520b57cec5SDimitry Andric 
3530b57cec5SDimitry Andric       std::vector<InstrProfValueData> CurrentValues;
3540b57cec5SDimitry Andric       for (uint32_t V = 0; V < NumValueData; V++) {
3550b57cec5SDimitry Andric         CHECK_LINE_END(Line);
3560b57cec5SDimitry Andric         std::pair<StringRef, StringRef> VD = Line->rsplit(':');
3570b57cec5SDimitry Andric         uint64_t TakenCount, Value;
3580b57cec5SDimitry Andric         if (ValueKind == IPVK_IndirectCallTarget) {
3590b57cec5SDimitry Andric           if (InstrProfSymtab::isExternalSymbol(VD.first)) {
3600b57cec5SDimitry Andric             Value = 0;
3610b57cec5SDimitry Andric           } else {
3620b57cec5SDimitry Andric             if (Error E = Symtab->addFuncName(VD.first))
3630b57cec5SDimitry Andric               return E;
3640b57cec5SDimitry Andric             Value = IndexedInstrProf::ComputeHash(VD.first);
3650b57cec5SDimitry Andric           }
366*0fca6ea1SDimitry Andric         } else if (ValueKind == IPVK_VTableTarget) {
367*0fca6ea1SDimitry Andric           if (InstrProfSymtab::isExternalSymbol(VD.first))
368*0fca6ea1SDimitry Andric             Value = 0;
369*0fca6ea1SDimitry Andric           else {
370*0fca6ea1SDimitry Andric             if (Error E = Symtab->addVTableName(VD.first))
371*0fca6ea1SDimitry Andric               return E;
372*0fca6ea1SDimitry Andric             Value = IndexedInstrProf::ComputeHash(VD.first);
373*0fca6ea1SDimitry Andric           }
3740b57cec5SDimitry Andric         } else {
3750b57cec5SDimitry Andric           READ_NUM(VD.first, Value);
3760b57cec5SDimitry Andric         }
3770b57cec5SDimitry Andric         READ_NUM(VD.second, TakenCount);
3780b57cec5SDimitry Andric         CurrentValues.push_back({Value, TakenCount});
3790b57cec5SDimitry Andric         Line++;
3800b57cec5SDimitry Andric       }
381*0fca6ea1SDimitry Andric       assert(CurrentValues.size() == NumValueData);
382*0fca6ea1SDimitry Andric       Record.addValueData(ValueKind, S, CurrentValues, nullptr);
3830b57cec5SDimitry Andric     }
3840b57cec5SDimitry Andric   }
3850b57cec5SDimitry Andric   return success();
3860b57cec5SDimitry Andric 
3870b57cec5SDimitry Andric #undef CHECK_LINE_END
3880b57cec5SDimitry Andric #undef READ_NUM
3890b57cec5SDimitry Andric #undef VP_READ_ADVANCE
3900b57cec5SDimitry Andric }
3910b57cec5SDimitry Andric 
3920b57cec5SDimitry Andric Error TextInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
3930b57cec5SDimitry Andric   // Skip empty lines and comments.
3945f757f3fSDimitry Andric   while (!Line.is_at_end() && (Line->empty() || Line->starts_with("#")))
3950b57cec5SDimitry Andric     ++Line;
3960b57cec5SDimitry Andric   // If we hit EOF while looking for a name, we're done.
3970b57cec5SDimitry Andric   if (Line.is_at_end()) {
3980b57cec5SDimitry Andric     return error(instrprof_error::eof);
3990b57cec5SDimitry Andric   }
4000b57cec5SDimitry Andric 
4010b57cec5SDimitry Andric   // Read the function name.
4020b57cec5SDimitry Andric   Record.Name = *Line++;
4030b57cec5SDimitry Andric   if (Error E = Symtab->addFuncName(Record.Name))
4040b57cec5SDimitry Andric     return error(std::move(E));
4050b57cec5SDimitry Andric 
4060b57cec5SDimitry Andric   // Read the function hash.
4070b57cec5SDimitry Andric   if (Line.is_at_end())
4080b57cec5SDimitry Andric     return error(instrprof_error::truncated);
4090b57cec5SDimitry Andric   if ((Line++)->getAsInteger(0, Record.Hash))
410349cc55cSDimitry Andric     return error(instrprof_error::malformed,
411349cc55cSDimitry Andric                  "function hash is not a valid integer");
4120b57cec5SDimitry Andric 
4130b57cec5SDimitry Andric   // Read the number of counters.
4140b57cec5SDimitry Andric   uint64_t NumCounters;
4150b57cec5SDimitry Andric   if (Line.is_at_end())
4160b57cec5SDimitry Andric     return error(instrprof_error::truncated);
4170b57cec5SDimitry Andric   if ((Line++)->getAsInteger(10, NumCounters))
418349cc55cSDimitry Andric     return error(instrprof_error::malformed,
419349cc55cSDimitry Andric                  "number of counters is not a valid integer");
4200b57cec5SDimitry Andric   if (NumCounters == 0)
421349cc55cSDimitry Andric     return error(instrprof_error::malformed, "number of counters is zero");
4220b57cec5SDimitry Andric 
4230b57cec5SDimitry Andric   // Read each counter and fill our internal storage with the values.
4240b57cec5SDimitry Andric   Record.Clear();
4250b57cec5SDimitry Andric   Record.Counts.reserve(NumCounters);
4260b57cec5SDimitry Andric   for (uint64_t I = 0; I < NumCounters; ++I) {
4270b57cec5SDimitry Andric     if (Line.is_at_end())
4280b57cec5SDimitry Andric       return error(instrprof_error::truncated);
4290b57cec5SDimitry Andric     uint64_t Count;
4300b57cec5SDimitry Andric     if ((Line++)->getAsInteger(10, Count))
431349cc55cSDimitry Andric       return error(instrprof_error::malformed, "count is invalid");
4320b57cec5SDimitry Andric     Record.Counts.push_back(Count);
4330b57cec5SDimitry Andric   }
4340b57cec5SDimitry Andric 
4355f757f3fSDimitry Andric   // Bitmap byte information is indicated with special character.
4365f757f3fSDimitry Andric   if (Line->starts_with("$")) {
4375f757f3fSDimitry Andric     Record.BitmapBytes.clear();
4385f757f3fSDimitry Andric     // Read the number of bitmap bytes.
4395f757f3fSDimitry Andric     uint64_t NumBitmapBytes;
4405f757f3fSDimitry Andric     if ((Line++)->drop_front(1).trim().getAsInteger(0, NumBitmapBytes))
4415f757f3fSDimitry Andric       return error(instrprof_error::malformed,
4425f757f3fSDimitry Andric                    "number of bitmap bytes is not a valid integer");
4435f757f3fSDimitry Andric     if (NumBitmapBytes != 0) {
4445f757f3fSDimitry Andric       // Read each bitmap and fill our internal storage with the values.
4455f757f3fSDimitry Andric       Record.BitmapBytes.reserve(NumBitmapBytes);
4465f757f3fSDimitry Andric       for (uint8_t I = 0; I < NumBitmapBytes; ++I) {
4475f757f3fSDimitry Andric         if (Line.is_at_end())
4485f757f3fSDimitry Andric           return error(instrprof_error::truncated);
4495f757f3fSDimitry Andric         uint8_t BitmapByte;
4505f757f3fSDimitry Andric         if ((Line++)->getAsInteger(0, BitmapByte))
4515f757f3fSDimitry Andric           return error(instrprof_error::malformed,
4525f757f3fSDimitry Andric                        "bitmap byte is not a valid integer");
4535f757f3fSDimitry Andric         Record.BitmapBytes.push_back(BitmapByte);
4545f757f3fSDimitry Andric       }
4555f757f3fSDimitry Andric     }
4565f757f3fSDimitry Andric   }
4575f757f3fSDimitry Andric 
4580b57cec5SDimitry Andric   // Check if value profile data exists and read it if so.
4590b57cec5SDimitry Andric   if (Error E = readValueProfileData(Record))
4600b57cec5SDimitry Andric     return error(std::move(E));
4610b57cec5SDimitry Andric 
4620b57cec5SDimitry Andric   return success();
4630b57cec5SDimitry Andric }
4640b57cec5SDimitry Andric 
4650b57cec5SDimitry Andric template <class IntPtrT>
4661fd87a68SDimitry Andric InstrProfKind RawInstrProfReader<IntPtrT>::getProfileKind() const {
4671fd87a68SDimitry Andric   return getProfileKindFromVersion(Version);
4681fd87a68SDimitry Andric }
4691fd87a68SDimitry Andric 
4701fd87a68SDimitry Andric template <class IntPtrT>
47106c3fb27SDimitry Andric SmallVector<TemporalProfTraceTy> &
47206c3fb27SDimitry Andric RawInstrProfReader<IntPtrT>::getTemporalProfTraces(
47306c3fb27SDimitry Andric     std::optional<uint64_t> Weight) {
47406c3fb27SDimitry Andric   if (TemporalProfTimestamps.empty()) {
47506c3fb27SDimitry Andric     assert(TemporalProfTraces.empty());
47606c3fb27SDimitry Andric     return TemporalProfTraces;
47706c3fb27SDimitry Andric   }
47806c3fb27SDimitry Andric   // Sort functions by their timestamps to build the trace.
47906c3fb27SDimitry Andric   std::sort(TemporalProfTimestamps.begin(), TemporalProfTimestamps.end());
48006c3fb27SDimitry Andric   TemporalProfTraceTy Trace;
48106c3fb27SDimitry Andric   if (Weight)
48206c3fb27SDimitry Andric     Trace.Weight = *Weight;
48306c3fb27SDimitry Andric   for (auto &[TimestampValue, NameRef] : TemporalProfTimestamps)
48406c3fb27SDimitry Andric     Trace.FunctionNameRefs.push_back(NameRef);
48506c3fb27SDimitry Andric   TemporalProfTraces = {std::move(Trace)};
48606c3fb27SDimitry Andric   return TemporalProfTraces;
48706c3fb27SDimitry Andric }
48806c3fb27SDimitry Andric 
48906c3fb27SDimitry Andric template <class IntPtrT>
4900b57cec5SDimitry Andric bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) {
4910b57cec5SDimitry Andric   if (DataBuffer.getBufferSize() < sizeof(uint64_t))
4920b57cec5SDimitry Andric     return false;
4930b57cec5SDimitry Andric   uint64_t Magic =
4940b57cec5SDimitry Andric     *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart());
4950b57cec5SDimitry Andric   return RawInstrProf::getMagic<IntPtrT>() == Magic ||
4965f757f3fSDimitry Andric          llvm::byteswap(RawInstrProf::getMagic<IntPtrT>()) == Magic;
4970b57cec5SDimitry Andric }
4980b57cec5SDimitry Andric 
4990b57cec5SDimitry Andric template <class IntPtrT>
5000b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readHeader() {
5010b57cec5SDimitry Andric   if (!hasFormat(*DataBuffer))
5020b57cec5SDimitry Andric     return error(instrprof_error::bad_magic);
5030b57cec5SDimitry Andric   if (DataBuffer->getBufferSize() < sizeof(RawInstrProf::Header))
5040b57cec5SDimitry Andric     return error(instrprof_error::bad_header);
5050b57cec5SDimitry Andric   auto *Header = reinterpret_cast<const RawInstrProf::Header *>(
5060b57cec5SDimitry Andric       DataBuffer->getBufferStart());
5070b57cec5SDimitry Andric   ShouldSwapBytes = Header->Magic != RawInstrProf::getMagic<IntPtrT>();
5080b57cec5SDimitry Andric   return readHeader(*Header);
5090b57cec5SDimitry Andric }
5100b57cec5SDimitry Andric 
5110b57cec5SDimitry Andric template <class IntPtrT>
5120b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
5130b57cec5SDimitry Andric   const char *End = DataBuffer->getBufferEnd();
5140b57cec5SDimitry Andric   // Skip zero padding between profiles.
5150b57cec5SDimitry Andric   while (CurrentPos != End && *CurrentPos == 0)
5160b57cec5SDimitry Andric     ++CurrentPos;
5170b57cec5SDimitry Andric   // If there's nothing left, we're done.
5180b57cec5SDimitry Andric   if (CurrentPos == End)
5190b57cec5SDimitry Andric     return make_error<InstrProfError>(instrprof_error::eof);
5200b57cec5SDimitry Andric   // If there isn't enough space for another header, this is probably just
5210b57cec5SDimitry Andric   // garbage at the end of the file.
5220b57cec5SDimitry Andric   if (CurrentPos + sizeof(RawInstrProf::Header) > End)
523349cc55cSDimitry Andric     return make_error<InstrProfError>(instrprof_error::malformed,
524349cc55cSDimitry Andric                                       "not enough space for another header");
5250b57cec5SDimitry Andric   // The writer ensures each profile is padded to start at an aligned address.
5260b57cec5SDimitry Andric   if (reinterpret_cast<size_t>(CurrentPos) % alignof(uint64_t))
527349cc55cSDimitry Andric     return make_error<InstrProfError>(instrprof_error::malformed,
528349cc55cSDimitry Andric                                       "insufficient padding");
5290b57cec5SDimitry Andric   // The magic should have the same byte order as in the previous header.
5300b57cec5SDimitry Andric   uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos);
5310b57cec5SDimitry Andric   if (Magic != swap(RawInstrProf::getMagic<IntPtrT>()))
5320b57cec5SDimitry Andric     return make_error<InstrProfError>(instrprof_error::bad_magic);
5330b57cec5SDimitry Andric 
5340b57cec5SDimitry Andric   // There's another profile to read, so we need to process the header.
5350b57cec5SDimitry Andric   auto *Header = reinterpret_cast<const RawInstrProf::Header *>(CurrentPos);
5360b57cec5SDimitry Andric   return readHeader(*Header);
5370b57cec5SDimitry Andric }
5380b57cec5SDimitry Andric 
5390b57cec5SDimitry Andric template <class IntPtrT>
5400b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) {
541*0fca6ea1SDimitry Andric   if (Error E = Symtab.create(StringRef(NamesStart, NamesEnd - NamesStart),
542*0fca6ea1SDimitry Andric                               StringRef(VNamesStart, VNamesEnd - VNamesStart)))
5430b57cec5SDimitry Andric     return error(std::move(E));
5440b57cec5SDimitry Andric   for (const RawInstrProf::ProfileData<IntPtrT> *I = Data; I != DataEnd; ++I) {
5450b57cec5SDimitry Andric     const IntPtrT FPtr = swap(I->FunctionPointer);
5460b57cec5SDimitry Andric     if (!FPtr)
5470b57cec5SDimitry Andric       continue;
548647cbc5dSDimitry Andric     Symtab.mapAddress(FPtr, swap(I->NameRef));
5490b57cec5SDimitry Andric   }
550*0fca6ea1SDimitry Andric 
551*0fca6ea1SDimitry Andric   if (VTableBegin != nullptr && VTableEnd != nullptr) {
552*0fca6ea1SDimitry Andric     for (const RawInstrProf::VTableProfileData<IntPtrT> *I = VTableBegin;
553*0fca6ea1SDimitry Andric          I != VTableEnd; ++I) {
554*0fca6ea1SDimitry Andric       const IntPtrT VPtr = swap(I->VTablePointer);
555*0fca6ea1SDimitry Andric       if (!VPtr)
556*0fca6ea1SDimitry Andric         continue;
557*0fca6ea1SDimitry Andric       // Map both begin and end address to the name hash, since the instrumented
558*0fca6ea1SDimitry Andric       // address could be somewhere in the middle.
559*0fca6ea1SDimitry Andric       // VPtr is of type uint32_t or uint64_t so 'VPtr + I->VTableSize' marks
560*0fca6ea1SDimitry Andric       // the end of vtable address.
561*0fca6ea1SDimitry Andric       Symtab.mapVTableAddress(VPtr, VPtr + swap(I->VTableSize),
562*0fca6ea1SDimitry Andric                               swap(I->VTableNameHash));
563*0fca6ea1SDimitry Andric     }
564*0fca6ea1SDimitry Andric   }
5650b57cec5SDimitry Andric   return success();
5660b57cec5SDimitry Andric }
5670b57cec5SDimitry Andric 
5680b57cec5SDimitry Andric template <class IntPtrT>
5690b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readHeader(
5700b57cec5SDimitry Andric     const RawInstrProf::Header &Header) {
5710b57cec5SDimitry Andric   Version = swap(Header.Version);
5720b57cec5SDimitry Andric   if (GET_VERSION(Version) != RawInstrProf::Version)
57306c3fb27SDimitry Andric     return error(instrprof_error::raw_profile_version_mismatch,
57406c3fb27SDimitry Andric                  ("Profile uses raw profile format version = " +
57506c3fb27SDimitry Andric                   Twine(GET_VERSION(Version)) +
57606c3fb27SDimitry Andric                   "; expected version = " + Twine(RawInstrProf::Version) +
57706c3fb27SDimitry Andric                   "\nPLEASE update this tool to version in the raw profile, or "
57806c3fb27SDimitry Andric                   "regenerate raw profile with expected version.")
57906c3fb27SDimitry Andric                      .str());
5800b57cec5SDimitry Andric 
5815f757f3fSDimitry Andric   uint64_t BinaryIdSize = swap(Header.BinaryIdsSize);
5825f757f3fSDimitry Andric   // Binary id start just after the header if exists.
5835f757f3fSDimitry Andric   const uint8_t *BinaryIdStart =
5845f757f3fSDimitry Andric       reinterpret_cast<const uint8_t *>(&Header) + sizeof(RawInstrProf::Header);
5855f757f3fSDimitry Andric   const uint8_t *BinaryIdEnd = BinaryIdStart + BinaryIdSize;
5865f757f3fSDimitry Andric   const uint8_t *BufferEnd = (const uint8_t *)DataBuffer->getBufferEnd();
5875f757f3fSDimitry Andric   if (BinaryIdSize % sizeof(uint64_t) || BinaryIdEnd > BufferEnd)
588349cc55cSDimitry Andric     return error(instrprof_error::bad_header);
589*0fca6ea1SDimitry Andric   ArrayRef<uint8_t> BinaryIdsBuffer(BinaryIdStart, BinaryIdSize);
590*0fca6ea1SDimitry Andric   if (!BinaryIdsBuffer.empty()) {
591*0fca6ea1SDimitry Andric     if (Error Err = readBinaryIdsInternal(*DataBuffer, BinaryIdsBuffer,
5925f757f3fSDimitry Andric                                           BinaryIds, getDataEndianness()))
5935f757f3fSDimitry Andric       return Err;
5945f757f3fSDimitry Andric   }
595349cc55cSDimitry Andric 
5960b57cec5SDimitry Andric   CountersDelta = swap(Header.CountersDelta);
5975f757f3fSDimitry Andric   BitmapDelta = swap(Header.BitmapDelta);
5980b57cec5SDimitry Andric   NamesDelta = swap(Header.NamesDelta);
5995f757f3fSDimitry Andric   auto NumData = swap(Header.NumData);
600480093f4SDimitry Andric   auto PaddingBytesBeforeCounters = swap(Header.PaddingBytesBeforeCounters);
6015f757f3fSDimitry Andric   auto CountersSize = swap(Header.NumCounters) * getCounterTypeSize();
602480093f4SDimitry Andric   auto PaddingBytesAfterCounters = swap(Header.PaddingBytesAfterCounters);
6035f757f3fSDimitry Andric   auto NumBitmapBytes = swap(Header.NumBitmapBytes);
6045f757f3fSDimitry Andric   auto PaddingBytesAfterBitmapBytes = swap(Header.PaddingBytesAfterBitmapBytes);
6050eae32dcSDimitry Andric   auto NamesSize = swap(Header.NamesSize);
606*0fca6ea1SDimitry Andric   auto VTableNameSize = swap(Header.VNamesSize);
607*0fca6ea1SDimitry Andric   auto NumVTables = swap(Header.NumVTables);
6080b57cec5SDimitry Andric   ValueKindLast = swap(Header.ValueKindLast);
6090b57cec5SDimitry Andric 
61004eeddc0SDimitry Andric   auto DataSize = NumData * sizeof(RawInstrProf::ProfileData<IntPtrT>);
611*0fca6ea1SDimitry Andric   auto PaddingBytesAfterNames = getNumPaddingBytes(NamesSize);
612*0fca6ea1SDimitry Andric   auto PaddingBytesAfterVTableNames = getNumPaddingBytes(VTableNameSize);
613*0fca6ea1SDimitry Andric 
614*0fca6ea1SDimitry Andric   auto VTableSectionSize =
615*0fca6ea1SDimitry Andric       NumVTables * sizeof(RawInstrProf::VTableProfileData<IntPtrT>);
616*0fca6ea1SDimitry Andric   auto PaddingBytesAfterVTableProfData = getNumPaddingBytes(VTableSectionSize);
6170b57cec5SDimitry Andric 
618fe6060f1SDimitry Andric   // Profile data starts after profile header and binary ids if exist.
6195f757f3fSDimitry Andric   ptrdiff_t DataOffset = sizeof(RawInstrProf::Header) + BinaryIdSize;
62004eeddc0SDimitry Andric   ptrdiff_t CountersOffset = DataOffset + DataSize + PaddingBytesBeforeCounters;
6215f757f3fSDimitry Andric   ptrdiff_t BitmapOffset =
62204eeddc0SDimitry Andric       CountersOffset + CountersSize + PaddingBytesAfterCounters;
6235f757f3fSDimitry Andric   ptrdiff_t NamesOffset =
6245f757f3fSDimitry Andric       BitmapOffset + NumBitmapBytes + PaddingBytesAfterBitmapBytes;
625*0fca6ea1SDimitry Andric   ptrdiff_t VTableProfDataOffset =
626*0fca6ea1SDimitry Andric       NamesOffset + NamesSize + PaddingBytesAfterNames;
627*0fca6ea1SDimitry Andric   ptrdiff_t VTableNameOffset = VTableProfDataOffset + VTableSectionSize +
628*0fca6ea1SDimitry Andric                                PaddingBytesAfterVTableProfData;
629*0fca6ea1SDimitry Andric   ptrdiff_t ValueDataOffset =
630*0fca6ea1SDimitry Andric       VTableNameOffset + VTableNameSize + PaddingBytesAfterVTableNames;
6310b57cec5SDimitry Andric 
6320b57cec5SDimitry Andric   auto *Start = reinterpret_cast<const char *>(&Header);
6330b57cec5SDimitry Andric   if (Start + ValueDataOffset > DataBuffer->getBufferEnd())
6340b57cec5SDimitry Andric     return error(instrprof_error::bad_header);
6350b57cec5SDimitry Andric 
6360eae32dcSDimitry Andric   if (Correlator) {
6370eae32dcSDimitry Andric     // These sizes in the raw file are zero because we constructed them in the
6380eae32dcSDimitry Andric     // Correlator.
6395f757f3fSDimitry Andric     if (!(DataSize == 0 && NamesSize == 0 && CountersDelta == 0 &&
6405f757f3fSDimitry Andric           NamesDelta == 0))
6415f757f3fSDimitry Andric       return error(instrprof_error::unexpected_correlation_info);
6420eae32dcSDimitry Andric     Data = Correlator->getDataPointer();
6430eae32dcSDimitry Andric     DataEnd = Data + Correlator->getDataSize();
64404eeddc0SDimitry Andric     NamesStart = Correlator->getNamesPointer();
64504eeddc0SDimitry Andric     NamesEnd = NamesStart + Correlator->getNamesSize();
6460eae32dcSDimitry Andric   } else {
6470b57cec5SDimitry Andric     Data = reinterpret_cast<const RawInstrProf::ProfileData<IntPtrT> *>(
6480b57cec5SDimitry Andric         Start + DataOffset);
64904eeddc0SDimitry Andric     DataEnd = Data + NumData;
650*0fca6ea1SDimitry Andric     VTableBegin =
651*0fca6ea1SDimitry Andric         reinterpret_cast<const RawInstrProf::VTableProfileData<IntPtrT> *>(
652*0fca6ea1SDimitry Andric             Start + VTableProfDataOffset);
653*0fca6ea1SDimitry Andric     VTableEnd = VTableBegin + NumVTables;
6540eae32dcSDimitry Andric     NamesStart = Start + NamesOffset;
6550eae32dcSDimitry Andric     NamesEnd = NamesStart + NamesSize;
656*0fca6ea1SDimitry Andric     VNamesStart = Start + VTableNameOffset;
657*0fca6ea1SDimitry Andric     VNamesEnd = VNamesStart + VTableNameSize;
6580eae32dcSDimitry Andric   }
659fe6060f1SDimitry Andric 
66004eeddc0SDimitry Andric   CountersStart = Start + CountersOffset;
66104eeddc0SDimitry Andric   CountersEnd = CountersStart + CountersSize;
6625f757f3fSDimitry Andric   BitmapStart = Start + BitmapOffset;
6635f757f3fSDimitry Andric   BitmapEnd = BitmapStart + NumBitmapBytes;
6640b57cec5SDimitry Andric   ValueDataStart = reinterpret_cast<const uint8_t *>(Start + ValueDataOffset);
6650b57cec5SDimitry Andric 
6668bcb0991SDimitry Andric   std::unique_ptr<InstrProfSymtab> NewSymtab = std::make_unique<InstrProfSymtab>();
66781ad6265SDimitry Andric   if (Error E = createSymtab(*NewSymtab))
6680b57cec5SDimitry Andric     return E;
6690b57cec5SDimitry Andric 
6700b57cec5SDimitry Andric   Symtab = std::move(NewSymtab);
6710b57cec5SDimitry Andric   return success();
6720b57cec5SDimitry Andric }
6730b57cec5SDimitry Andric 
6740b57cec5SDimitry Andric template <class IntPtrT>
6750b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readName(NamedInstrProfRecord &Record) {
6760b57cec5SDimitry Andric   Record.Name = getName(Data->NameRef);
6770b57cec5SDimitry Andric   return success();
6780b57cec5SDimitry Andric }
6790b57cec5SDimitry Andric 
6800b57cec5SDimitry Andric template <class IntPtrT>
6810b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readFuncHash(NamedInstrProfRecord &Record) {
6820b57cec5SDimitry Andric   Record.Hash = swap(Data->FuncHash);
6830b57cec5SDimitry Andric   return success();
6840b57cec5SDimitry Andric }
6850b57cec5SDimitry Andric 
6860b57cec5SDimitry Andric template <class IntPtrT>
6870b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readRawCounts(
6880b57cec5SDimitry Andric     InstrProfRecord &Record) {
6890b57cec5SDimitry Andric   uint32_t NumCounters = swap(Data->NumCounters);
6900b57cec5SDimitry Andric   if (NumCounters == 0)
691349cc55cSDimitry Andric     return error(instrprof_error::malformed, "number of counters is zero");
6920b57cec5SDimitry Andric 
69304eeddc0SDimitry Andric   ptrdiff_t CounterBaseOffset = swap(Data->CounterPtr) - CountersDelta;
69404eeddc0SDimitry Andric   if (CounterBaseOffset < 0)
695349cc55cSDimitry Andric     return error(
696349cc55cSDimitry Andric         instrprof_error::malformed,
69704eeddc0SDimitry Andric         ("counter offset " + Twine(CounterBaseOffset) + " is negative").str());
698349cc55cSDimitry Andric 
69904eeddc0SDimitry Andric   if (CounterBaseOffset >= CountersEnd - CountersStart)
7000eae32dcSDimitry Andric     return error(instrprof_error::malformed,
70104eeddc0SDimitry Andric                  ("counter offset " + Twine(CounterBaseOffset) +
70204eeddc0SDimitry Andric                   " is greater than the maximum counter offset " +
70304eeddc0SDimitry Andric                   Twine(CountersEnd - CountersStart - 1))
704349cc55cSDimitry Andric                      .str());
705349cc55cSDimitry Andric 
70604eeddc0SDimitry Andric   uint64_t MaxNumCounters =
70704eeddc0SDimitry Andric       (CountersEnd - (CountersStart + CounterBaseOffset)) /
70804eeddc0SDimitry Andric       getCounterTypeSize();
70904eeddc0SDimitry Andric   if (NumCounters > MaxNumCounters)
710349cc55cSDimitry Andric     return error(instrprof_error::malformed,
71104eeddc0SDimitry Andric                  ("number of counters " + Twine(NumCounters) +
712349cc55cSDimitry Andric                   " is greater than the maximum number of counters " +
71304eeddc0SDimitry Andric                   Twine(MaxNumCounters))
714349cc55cSDimitry Andric                      .str());
7158bcb0991SDimitry Andric 
7160b57cec5SDimitry Andric   Record.Counts.clear();
71704eeddc0SDimitry Andric   Record.Counts.reserve(NumCounters);
71804eeddc0SDimitry Andric   for (uint32_t I = 0; I < NumCounters; I++) {
7191fd87a68SDimitry Andric     const char *Ptr =
7201fd87a68SDimitry Andric         CountersStart + CounterBaseOffset + I * getCounterTypeSize();
72106c3fb27SDimitry Andric     if (I == 0 && hasTemporalProfile()) {
72206c3fb27SDimitry Andric       uint64_t TimestampValue = swap(*reinterpret_cast<const uint64_t *>(Ptr));
72306c3fb27SDimitry Andric       if (TimestampValue != 0 &&
72406c3fb27SDimitry Andric           TimestampValue != std::numeric_limits<uint64_t>::max()) {
72506c3fb27SDimitry Andric         TemporalProfTimestamps.emplace_back(TimestampValue,
72606c3fb27SDimitry Andric                                             swap(Data->NameRef));
72706c3fb27SDimitry Andric         TemporalProfTraceStreamSize = 1;
72806c3fb27SDimitry Andric       }
72906c3fb27SDimitry Andric       if (hasSingleByteCoverage()) {
73006c3fb27SDimitry Andric         // In coverage mode, getCounterTypeSize() returns 1 byte but our
73106c3fb27SDimitry Andric         // timestamp field has size uint64_t. Increment I so that the next
73206c3fb27SDimitry Andric         // iteration of this for loop points to the byte after the timestamp
73306c3fb27SDimitry Andric         // field, i.e., I += 8.
73406c3fb27SDimitry Andric         I += 7;
73506c3fb27SDimitry Andric       }
73606c3fb27SDimitry Andric       continue;
73706c3fb27SDimitry Andric     }
7381fd87a68SDimitry Andric     if (hasSingleByteCoverage()) {
7391fd87a68SDimitry Andric       // A value of zero signifies the block is covered.
7401fd87a68SDimitry Andric       Record.Counts.push_back(*Ptr == 0 ? 1 : 0);
7411fd87a68SDimitry Andric     } else {
7425f757f3fSDimitry Andric       uint64_t CounterValue = swap(*reinterpret_cast<const uint64_t *>(Ptr));
7435f757f3fSDimitry Andric       if (CounterValue > MaxCounterValue && Warn)
7445f757f3fSDimitry Andric         Warn(make_error<InstrProfError>(
7455f757f3fSDimitry Andric             instrprof_error::counter_value_too_large, Twine(CounterValue)));
7465f757f3fSDimitry Andric 
7475f757f3fSDimitry Andric       Record.Counts.push_back(CounterValue);
74804eeddc0SDimitry Andric     }
7491fd87a68SDimitry Andric   }
7500b57cec5SDimitry Andric 
7510b57cec5SDimitry Andric   return success();
7520b57cec5SDimitry Andric }
7530b57cec5SDimitry Andric 
7540b57cec5SDimitry Andric template <class IntPtrT>
7555f757f3fSDimitry Andric Error RawInstrProfReader<IntPtrT>::readRawBitmapBytes(InstrProfRecord &Record) {
7565f757f3fSDimitry Andric   uint32_t NumBitmapBytes = swap(Data->NumBitmapBytes);
7575f757f3fSDimitry Andric 
7585f757f3fSDimitry Andric   Record.BitmapBytes.clear();
7595f757f3fSDimitry Andric   Record.BitmapBytes.reserve(NumBitmapBytes);
7605f757f3fSDimitry Andric 
7615f757f3fSDimitry Andric   // It's possible MCDC is either not enabled or only used for some functions
7625f757f3fSDimitry Andric   // and not others. So if we record 0 bytes, just move on.
7635f757f3fSDimitry Andric   if (NumBitmapBytes == 0)
7645f757f3fSDimitry Andric     return success();
7655f757f3fSDimitry Andric 
7665f757f3fSDimitry Andric   // BitmapDelta decreases as we advance to the next data record.
7675f757f3fSDimitry Andric   ptrdiff_t BitmapOffset = swap(Data->BitmapPtr) - BitmapDelta;
7685f757f3fSDimitry Andric   if (BitmapOffset < 0)
7695f757f3fSDimitry Andric     return error(
7705f757f3fSDimitry Andric         instrprof_error::malformed,
7715f757f3fSDimitry Andric         ("bitmap offset " + Twine(BitmapOffset) + " is negative").str());
7725f757f3fSDimitry Andric 
7735f757f3fSDimitry Andric   if (BitmapOffset >= BitmapEnd - BitmapStart)
7745f757f3fSDimitry Andric     return error(instrprof_error::malformed,
7755f757f3fSDimitry Andric                  ("bitmap offset " + Twine(BitmapOffset) +
7765f757f3fSDimitry Andric                   " is greater than the maximum bitmap offset " +
7775f757f3fSDimitry Andric                   Twine(BitmapEnd - BitmapStart - 1))
7785f757f3fSDimitry Andric                      .str());
7795f757f3fSDimitry Andric 
7805f757f3fSDimitry Andric   uint64_t MaxNumBitmapBytes =
7815f757f3fSDimitry Andric       (BitmapEnd - (BitmapStart + BitmapOffset)) / sizeof(uint8_t);
7825f757f3fSDimitry Andric   if (NumBitmapBytes > MaxNumBitmapBytes)
7835f757f3fSDimitry Andric     return error(instrprof_error::malformed,
7845f757f3fSDimitry Andric                  ("number of bitmap bytes " + Twine(NumBitmapBytes) +
7855f757f3fSDimitry Andric                   " is greater than the maximum number of bitmap bytes " +
7865f757f3fSDimitry Andric                   Twine(MaxNumBitmapBytes))
7875f757f3fSDimitry Andric                      .str());
7885f757f3fSDimitry Andric 
7895f757f3fSDimitry Andric   for (uint32_t I = 0; I < NumBitmapBytes; I++) {
7905f757f3fSDimitry Andric     const char *Ptr = BitmapStart + BitmapOffset + I;
7915f757f3fSDimitry Andric     Record.BitmapBytes.push_back(swap(*Ptr));
7925f757f3fSDimitry Andric   }
7935f757f3fSDimitry Andric 
7945f757f3fSDimitry Andric   return success();
7955f757f3fSDimitry Andric }
7965f757f3fSDimitry Andric 
7975f757f3fSDimitry Andric template <class IntPtrT>
7980b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readValueProfilingData(
7990b57cec5SDimitry Andric     InstrProfRecord &Record) {
8000b57cec5SDimitry Andric   Record.clearValueData();
8010b57cec5SDimitry Andric   CurValueDataSize = 0;
8020b57cec5SDimitry Andric   // Need to match the logic in value profile dumper code in compiler-rt:
8030b57cec5SDimitry Andric   uint32_t NumValueKinds = 0;
8040b57cec5SDimitry Andric   for (uint32_t I = 0; I < IPVK_Last + 1; I++)
8050b57cec5SDimitry Andric     NumValueKinds += (Data->NumValueSites[I] != 0);
8060b57cec5SDimitry Andric 
8070b57cec5SDimitry Andric   if (!NumValueKinds)
8080b57cec5SDimitry Andric     return success();
8090b57cec5SDimitry Andric 
8100b57cec5SDimitry Andric   Expected<std::unique_ptr<ValueProfData>> VDataPtrOrErr =
8110b57cec5SDimitry Andric       ValueProfData::getValueProfData(
8120b57cec5SDimitry Andric           ValueDataStart, (const unsigned char *)DataBuffer->getBufferEnd(),
8130b57cec5SDimitry Andric           getDataEndianness());
8140b57cec5SDimitry Andric 
8150b57cec5SDimitry Andric   if (Error E = VDataPtrOrErr.takeError())
8160b57cec5SDimitry Andric     return E;
8170b57cec5SDimitry Andric 
8180b57cec5SDimitry Andric   // Note that besides deserialization, this also performs the conversion for
8190b57cec5SDimitry Andric   // indirect call targets.  The function pointers from the raw profile are
8200b57cec5SDimitry Andric   // remapped into function name hashes.
8210b57cec5SDimitry Andric   VDataPtrOrErr.get()->deserializeTo(Record, Symtab.get());
8220b57cec5SDimitry Andric   CurValueDataSize = VDataPtrOrErr.get()->getSize();
8230b57cec5SDimitry Andric   return success();
8240b57cec5SDimitry Andric }
8250b57cec5SDimitry Andric 
8260b57cec5SDimitry Andric template <class IntPtrT>
8270b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readNextRecord(NamedInstrProfRecord &Record) {
828bdd1243dSDimitry Andric   // Keep reading profiles that consist of only headers and no profile data and
829bdd1243dSDimitry Andric   // counters.
830bdd1243dSDimitry Andric   while (atEnd())
8310b57cec5SDimitry Andric     // At this point, ValueDataStart field points to the next header.
8320b57cec5SDimitry Andric     if (Error E = readNextHeader(getNextHeaderPos()))
8330b57cec5SDimitry Andric       return error(std::move(E));
8340b57cec5SDimitry Andric 
83506c3fb27SDimitry Andric   // Read name and set it in Record.
8360b57cec5SDimitry Andric   if (Error E = readName(Record))
8370b57cec5SDimitry Andric     return error(std::move(E));
8380b57cec5SDimitry Andric 
8390b57cec5SDimitry Andric   // Read FuncHash and set it in Record.
8400b57cec5SDimitry Andric   if (Error E = readFuncHash(Record))
8410b57cec5SDimitry Andric     return error(std::move(E));
8420b57cec5SDimitry Andric 
8430b57cec5SDimitry Andric   // Read raw counts and set Record.
8440b57cec5SDimitry Andric   if (Error E = readRawCounts(Record))
8450b57cec5SDimitry Andric     return error(std::move(E));
8460b57cec5SDimitry Andric 
8475f757f3fSDimitry Andric   // Read raw bitmap bytes and set Record.
8485f757f3fSDimitry Andric   if (Error E = readRawBitmapBytes(Record))
8495f757f3fSDimitry Andric     return error(std::move(E));
8505f757f3fSDimitry Andric 
8510b57cec5SDimitry Andric   // Read value data and set Record.
8520b57cec5SDimitry Andric   if (Error E = readValueProfilingData(Record))
8530b57cec5SDimitry Andric     return error(std::move(E));
8540b57cec5SDimitry Andric 
8550b57cec5SDimitry Andric   // Iterate.
8560b57cec5SDimitry Andric   advanceData();
8570b57cec5SDimitry Andric   return success();
8580b57cec5SDimitry Andric }
8590b57cec5SDimitry Andric 
860bdd1243dSDimitry Andric template <class IntPtrT>
861bdd1243dSDimitry Andric Error RawInstrProfReader<IntPtrT>::readBinaryIds(
862bdd1243dSDimitry Andric     std::vector<llvm::object::BuildID> &BinaryIds) {
8635f757f3fSDimitry Andric   BinaryIds.insert(BinaryIds.begin(), this->BinaryIds.begin(),
8645f757f3fSDimitry Andric                    this->BinaryIds.end());
8655f757f3fSDimitry Andric   return Error::success();
866349cc55cSDimitry Andric }
867349cc55cSDimitry Andric 
868fe6060f1SDimitry Andric template <class IntPtrT>
869fe6060f1SDimitry Andric Error RawInstrProfReader<IntPtrT>::printBinaryIds(raw_ostream &OS) {
8705f757f3fSDimitry Andric   if (!BinaryIds.empty())
8715f757f3fSDimitry Andric     printBinaryIdsInternal(OS, BinaryIds);
8725f757f3fSDimitry Andric   return Error::success();
873fe6060f1SDimitry Andric }
874fe6060f1SDimitry Andric 
8750b57cec5SDimitry Andric namespace llvm {
8760b57cec5SDimitry Andric 
8770b57cec5SDimitry Andric template class RawInstrProfReader<uint32_t>;
8780b57cec5SDimitry Andric template class RawInstrProfReader<uint64_t>;
8790b57cec5SDimitry Andric 
8800b57cec5SDimitry Andric } // end namespace llvm
8810b57cec5SDimitry Andric 
8820b57cec5SDimitry Andric InstrProfLookupTrait::hash_value_type
8830b57cec5SDimitry Andric InstrProfLookupTrait::ComputeHash(StringRef K) {
8840b57cec5SDimitry Andric   return IndexedInstrProf::ComputeHash(HashType, K);
8850b57cec5SDimitry Andric }
8860b57cec5SDimitry Andric 
8870b57cec5SDimitry Andric using data_type = InstrProfLookupTrait::data_type;
8880b57cec5SDimitry Andric using offset_type = InstrProfLookupTrait::offset_type;
8890b57cec5SDimitry Andric 
8900b57cec5SDimitry Andric bool InstrProfLookupTrait::readValueProfilingData(
8910b57cec5SDimitry Andric     const unsigned char *&D, const unsigned char *const End) {
8920b57cec5SDimitry Andric   Expected<std::unique_ptr<ValueProfData>> VDataPtrOrErr =
8930b57cec5SDimitry Andric       ValueProfData::getValueProfData(D, End, ValueProfDataEndianness);
8940b57cec5SDimitry Andric 
8950b57cec5SDimitry Andric   if (VDataPtrOrErr.takeError())
8960b57cec5SDimitry Andric     return false;
8970b57cec5SDimitry Andric 
8980b57cec5SDimitry Andric   VDataPtrOrErr.get()->deserializeTo(DataBuffer.back(), nullptr);
8990b57cec5SDimitry Andric   D += VDataPtrOrErr.get()->TotalSize;
9000b57cec5SDimitry Andric 
9010b57cec5SDimitry Andric   return true;
9020b57cec5SDimitry Andric }
9030b57cec5SDimitry Andric 
9040b57cec5SDimitry Andric data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D,
9050b57cec5SDimitry Andric                                          offset_type N) {
9060b57cec5SDimitry Andric   using namespace support;
9070b57cec5SDimitry Andric 
9080b57cec5SDimitry Andric   // Check if the data is corrupt. If so, don't try to read it.
9090b57cec5SDimitry Andric   if (N % sizeof(uint64_t))
9100b57cec5SDimitry Andric     return data_type();
9110b57cec5SDimitry Andric 
9120b57cec5SDimitry Andric   DataBuffer.clear();
9130b57cec5SDimitry Andric   std::vector<uint64_t> CounterBuffer;
9145f757f3fSDimitry Andric   std::vector<uint8_t> BitmapByteBuffer;
9150b57cec5SDimitry Andric 
9160b57cec5SDimitry Andric   const unsigned char *End = D + N;
9170b57cec5SDimitry Andric   while (D < End) {
9180b57cec5SDimitry Andric     // Read hash.
9190b57cec5SDimitry Andric     if (D + sizeof(uint64_t) >= End)
9200b57cec5SDimitry Andric       return data_type();
921*0fca6ea1SDimitry Andric     uint64_t Hash = endian::readNext<uint64_t, llvm::endianness::little>(D);
9220b57cec5SDimitry Andric 
9230b57cec5SDimitry Andric     // Initialize number of counters for GET_VERSION(FormatVersion) == 1.
9240b57cec5SDimitry Andric     uint64_t CountsSize = N / sizeof(uint64_t) - 1;
9250b57cec5SDimitry Andric     // If format version is different then read the number of counters.
9260b57cec5SDimitry Andric     if (GET_VERSION(FormatVersion) != IndexedInstrProf::ProfVersion::Version1) {
9270b57cec5SDimitry Andric       if (D + sizeof(uint64_t) > End)
9280b57cec5SDimitry Andric         return data_type();
929*0fca6ea1SDimitry Andric       CountsSize = endian::readNext<uint64_t, llvm::endianness::little>(D);
9300b57cec5SDimitry Andric     }
9310b57cec5SDimitry Andric     // Read counter values.
9320b57cec5SDimitry Andric     if (D + CountsSize * sizeof(uint64_t) > End)
9330b57cec5SDimitry Andric       return data_type();
9340b57cec5SDimitry Andric 
9350b57cec5SDimitry Andric     CounterBuffer.clear();
9360b57cec5SDimitry Andric     CounterBuffer.reserve(CountsSize);
9370b57cec5SDimitry Andric     for (uint64_t J = 0; J < CountsSize; ++J)
9385f757f3fSDimitry Andric       CounterBuffer.push_back(
939*0fca6ea1SDimitry Andric           endian::readNext<uint64_t, llvm::endianness::little>(D));
9400b57cec5SDimitry Andric 
9415f757f3fSDimitry Andric     // Read bitmap bytes for GET_VERSION(FormatVersion) > 10.
9425f757f3fSDimitry Andric     if (GET_VERSION(FormatVersion) > IndexedInstrProf::ProfVersion::Version10) {
9435f757f3fSDimitry Andric       uint64_t BitmapBytes = 0;
9445f757f3fSDimitry Andric       if (D + sizeof(uint64_t) > End)
9455f757f3fSDimitry Andric         return data_type();
946*0fca6ea1SDimitry Andric       BitmapBytes = endian::readNext<uint64_t, llvm::endianness::little>(D);
9475f757f3fSDimitry Andric       // Read bitmap byte values.
9485f757f3fSDimitry Andric       if (D + BitmapBytes * sizeof(uint8_t) > End)
9495f757f3fSDimitry Andric         return data_type();
9505f757f3fSDimitry Andric       BitmapByteBuffer.clear();
9515f757f3fSDimitry Andric       BitmapByteBuffer.reserve(BitmapBytes);
9525f757f3fSDimitry Andric       for (uint64_t J = 0; J < BitmapBytes; ++J)
9535f757f3fSDimitry Andric         BitmapByteBuffer.push_back(static_cast<uint8_t>(
954*0fca6ea1SDimitry Andric             endian::readNext<uint64_t, llvm::endianness::little>(D)));
9555f757f3fSDimitry Andric     }
9565f757f3fSDimitry Andric 
9575f757f3fSDimitry Andric     DataBuffer.emplace_back(K, Hash, std::move(CounterBuffer),
9585f757f3fSDimitry Andric                             std::move(BitmapByteBuffer));
9590b57cec5SDimitry Andric 
9600b57cec5SDimitry Andric     // Read value profiling data.
9610b57cec5SDimitry Andric     if (GET_VERSION(FormatVersion) > IndexedInstrProf::ProfVersion::Version2 &&
9620b57cec5SDimitry Andric         !readValueProfilingData(D, End)) {
9630b57cec5SDimitry Andric       DataBuffer.clear();
9640b57cec5SDimitry Andric       return data_type();
9650b57cec5SDimitry Andric     }
9660b57cec5SDimitry Andric   }
9670b57cec5SDimitry Andric   return DataBuffer;
9680b57cec5SDimitry Andric }
9690b57cec5SDimitry Andric 
9700b57cec5SDimitry Andric template <typename HashTableImpl>
9710b57cec5SDimitry Andric Error InstrProfReaderIndex<HashTableImpl>::getRecords(
9720b57cec5SDimitry Andric     StringRef FuncName, ArrayRef<NamedInstrProfRecord> &Data) {
9730b57cec5SDimitry Andric   auto Iter = HashTable->find(FuncName);
9740b57cec5SDimitry Andric   if (Iter == HashTable->end())
9750b57cec5SDimitry Andric     return make_error<InstrProfError>(instrprof_error::unknown_function);
9760b57cec5SDimitry Andric 
9770b57cec5SDimitry Andric   Data = (*Iter);
9780b57cec5SDimitry Andric   if (Data.empty())
979349cc55cSDimitry Andric     return make_error<InstrProfError>(instrprof_error::malformed,
980349cc55cSDimitry Andric                                       "profile data is empty");
9810b57cec5SDimitry Andric 
9820b57cec5SDimitry Andric   return Error::success();
9830b57cec5SDimitry Andric }
9840b57cec5SDimitry Andric 
9850b57cec5SDimitry Andric template <typename HashTableImpl>
9860b57cec5SDimitry Andric Error InstrProfReaderIndex<HashTableImpl>::getRecords(
9870b57cec5SDimitry Andric     ArrayRef<NamedInstrProfRecord> &Data) {
9880b57cec5SDimitry Andric   if (atEnd())
9890b57cec5SDimitry Andric     return make_error<InstrProfError>(instrprof_error::eof);
9900b57cec5SDimitry Andric 
9910b57cec5SDimitry Andric   Data = *RecordIterator;
9920b57cec5SDimitry Andric 
9930b57cec5SDimitry Andric   if (Data.empty())
994349cc55cSDimitry Andric     return make_error<InstrProfError>(instrprof_error::malformed,
995349cc55cSDimitry Andric                                       "profile data is empty");
9960b57cec5SDimitry Andric 
9970b57cec5SDimitry Andric   return Error::success();
9980b57cec5SDimitry Andric }
9990b57cec5SDimitry Andric 
10000b57cec5SDimitry Andric template <typename HashTableImpl>
10010b57cec5SDimitry Andric InstrProfReaderIndex<HashTableImpl>::InstrProfReaderIndex(
10020b57cec5SDimitry Andric     const unsigned char *Buckets, const unsigned char *const Payload,
10030b57cec5SDimitry Andric     const unsigned char *const Base, IndexedInstrProf::HashT HashType,
10040b57cec5SDimitry Andric     uint64_t Version) {
10050b57cec5SDimitry Andric   FormatVersion = Version;
10060b57cec5SDimitry Andric   HashTable.reset(HashTableImpl::Create(
10070b57cec5SDimitry Andric       Buckets, Payload, Base,
10080b57cec5SDimitry Andric       typename HashTableImpl::InfoType(HashType, Version)));
10090b57cec5SDimitry Andric   RecordIterator = HashTable->data_begin();
10100b57cec5SDimitry Andric }
10110b57cec5SDimitry Andric 
10121fd87a68SDimitry Andric template <typename HashTableImpl>
10131fd87a68SDimitry Andric InstrProfKind InstrProfReaderIndex<HashTableImpl>::getProfileKind() const {
10141fd87a68SDimitry Andric   return getProfileKindFromVersion(FormatVersion);
10151fd87a68SDimitry Andric }
10161fd87a68SDimitry Andric 
10170b57cec5SDimitry Andric namespace {
10180b57cec5SDimitry Andric /// A remapper that does not apply any remappings.
10190b57cec5SDimitry Andric class InstrProfReaderNullRemapper : public InstrProfReaderRemapper {
10200b57cec5SDimitry Andric   InstrProfReaderIndexBase &Underlying;
10210b57cec5SDimitry Andric 
10220b57cec5SDimitry Andric public:
10230b57cec5SDimitry Andric   InstrProfReaderNullRemapper(InstrProfReaderIndexBase &Underlying)
10240b57cec5SDimitry Andric       : Underlying(Underlying) {}
10250b57cec5SDimitry Andric 
10260b57cec5SDimitry Andric   Error getRecords(StringRef FuncName,
10270b57cec5SDimitry Andric                    ArrayRef<NamedInstrProfRecord> &Data) override {
10280b57cec5SDimitry Andric     return Underlying.getRecords(FuncName, Data);
10290b57cec5SDimitry Andric   }
10300b57cec5SDimitry Andric };
1031349cc55cSDimitry Andric } // namespace
10320b57cec5SDimitry Andric 
10330b57cec5SDimitry Andric /// A remapper that applies remappings based on a symbol remapping file.
10340b57cec5SDimitry Andric template <typename HashTableImpl>
10350b57cec5SDimitry Andric class llvm::InstrProfReaderItaniumRemapper
10360b57cec5SDimitry Andric     : public InstrProfReaderRemapper {
10370b57cec5SDimitry Andric public:
10380b57cec5SDimitry Andric   InstrProfReaderItaniumRemapper(
10390b57cec5SDimitry Andric       std::unique_ptr<MemoryBuffer> RemapBuffer,
10400b57cec5SDimitry Andric       InstrProfReaderIndex<HashTableImpl> &Underlying)
10410b57cec5SDimitry Andric       : RemapBuffer(std::move(RemapBuffer)), Underlying(Underlying) {
10420b57cec5SDimitry Andric   }
10430b57cec5SDimitry Andric 
10440b57cec5SDimitry Andric   /// Extract the original function name from a PGO function name.
10450b57cec5SDimitry Andric   static StringRef extractName(StringRef Name) {
1046cb14a3feSDimitry Andric     // We can have multiple pieces separated by kGlobalIdentifierDelimiter (
1047cb14a3feSDimitry Andric     // semicolon now and colon in older profiles); there can be pieces both
1048cb14a3feSDimitry Andric     // before and after the mangled name. Find the first part that starts with
1049cb14a3feSDimitry Andric     // '_Z'; we'll assume that's the mangled name we want.
10500b57cec5SDimitry Andric     std::pair<StringRef, StringRef> Parts = {StringRef(), Name};
10510b57cec5SDimitry Andric     while (true) {
1052*0fca6ea1SDimitry Andric       Parts = Parts.second.split(GlobalIdentifierDelimiter);
10535f757f3fSDimitry Andric       if (Parts.first.starts_with("_Z"))
10540b57cec5SDimitry Andric         return Parts.first;
10550b57cec5SDimitry Andric       if (Parts.second.empty())
10560b57cec5SDimitry Andric         return Name;
10570b57cec5SDimitry Andric     }
10580b57cec5SDimitry Andric   }
10590b57cec5SDimitry Andric 
10600b57cec5SDimitry Andric   /// Given a mangled name extracted from a PGO function name, and a new
10610b57cec5SDimitry Andric   /// form for that mangled name, reconstitute the name.
10620b57cec5SDimitry Andric   static void reconstituteName(StringRef OrigName, StringRef ExtractedName,
10630b57cec5SDimitry Andric                                StringRef Replacement,
10640b57cec5SDimitry Andric                                SmallVectorImpl<char> &Out) {
10650b57cec5SDimitry Andric     Out.reserve(OrigName.size() + Replacement.size() - ExtractedName.size());
10660b57cec5SDimitry Andric     Out.insert(Out.end(), OrigName.begin(), ExtractedName.begin());
10670b57cec5SDimitry Andric     Out.insert(Out.end(), Replacement.begin(), Replacement.end());
10680b57cec5SDimitry Andric     Out.insert(Out.end(), ExtractedName.end(), OrigName.end());
10690b57cec5SDimitry Andric   }
10700b57cec5SDimitry Andric 
10710b57cec5SDimitry Andric   Error populateRemappings() override {
10720b57cec5SDimitry Andric     if (Error E = Remappings.read(*RemapBuffer))
10730b57cec5SDimitry Andric       return E;
10740b57cec5SDimitry Andric     for (StringRef Name : Underlying.HashTable->keys()) {
10750b57cec5SDimitry Andric       StringRef RealName = extractName(Name);
10760b57cec5SDimitry Andric       if (auto Key = Remappings.insert(RealName)) {
10770b57cec5SDimitry Andric         // FIXME: We could theoretically map the same equivalence class to
10780b57cec5SDimitry Andric         // multiple names in the profile data. If that happens, we should
10790b57cec5SDimitry Andric         // return NamedInstrProfRecords from all of them.
10800b57cec5SDimitry Andric         MappedNames.insert({Key, RealName});
10810b57cec5SDimitry Andric       }
10820b57cec5SDimitry Andric     }
10830b57cec5SDimitry Andric     return Error::success();
10840b57cec5SDimitry Andric   }
10850b57cec5SDimitry Andric 
10860b57cec5SDimitry Andric   Error getRecords(StringRef FuncName,
10870b57cec5SDimitry Andric                    ArrayRef<NamedInstrProfRecord> &Data) override {
10880b57cec5SDimitry Andric     StringRef RealName = extractName(FuncName);
10890b57cec5SDimitry Andric     if (auto Key = Remappings.lookup(RealName)) {
10900b57cec5SDimitry Andric       StringRef Remapped = MappedNames.lookup(Key);
10910b57cec5SDimitry Andric       if (!Remapped.empty()) {
10920b57cec5SDimitry Andric         if (RealName.begin() == FuncName.begin() &&
10930b57cec5SDimitry Andric             RealName.end() == FuncName.end())
10940b57cec5SDimitry Andric           FuncName = Remapped;
10950b57cec5SDimitry Andric         else {
10960b57cec5SDimitry Andric           // Try rebuilding the name from the given remapping.
10970b57cec5SDimitry Andric           SmallString<256> Reconstituted;
10980b57cec5SDimitry Andric           reconstituteName(FuncName, RealName, Remapped, Reconstituted);
10990b57cec5SDimitry Andric           Error E = Underlying.getRecords(Reconstituted, Data);
11000b57cec5SDimitry Andric           if (!E)
11010b57cec5SDimitry Andric             return E;
11020b57cec5SDimitry Andric 
11030b57cec5SDimitry Andric           // If we failed because the name doesn't exist, fall back to asking
11040b57cec5SDimitry Andric           // about the original name.
11050b57cec5SDimitry Andric           if (Error Unhandled = handleErrors(
11060b57cec5SDimitry Andric                   std::move(E), [](std::unique_ptr<InstrProfError> Err) {
11070b57cec5SDimitry Andric                     return Err->get() == instrprof_error::unknown_function
11080b57cec5SDimitry Andric                                ? Error::success()
11090b57cec5SDimitry Andric                                : Error(std::move(Err));
11100b57cec5SDimitry Andric                   }))
11110b57cec5SDimitry Andric             return Unhandled;
11120b57cec5SDimitry Andric         }
11130b57cec5SDimitry Andric       }
11140b57cec5SDimitry Andric     }
11150b57cec5SDimitry Andric     return Underlying.getRecords(FuncName, Data);
11160b57cec5SDimitry Andric   }
11170b57cec5SDimitry Andric 
11180b57cec5SDimitry Andric private:
11190b57cec5SDimitry Andric   /// The memory buffer containing the remapping configuration. Remappings
11200b57cec5SDimitry Andric   /// holds pointers into this buffer.
11210b57cec5SDimitry Andric   std::unique_ptr<MemoryBuffer> RemapBuffer;
11220b57cec5SDimitry Andric 
11230b57cec5SDimitry Andric   /// The mangling remapper.
11240b57cec5SDimitry Andric   SymbolRemappingReader Remappings;
11250b57cec5SDimitry Andric 
11260b57cec5SDimitry Andric   /// Mapping from mangled name keys to the name used for the key in the
11270b57cec5SDimitry Andric   /// profile data.
11280b57cec5SDimitry Andric   /// FIXME: Can we store a location within the on-disk hash table instead of
11290b57cec5SDimitry Andric   /// redoing lookup?
11300b57cec5SDimitry Andric   DenseMap<SymbolRemappingReader::Key, StringRef> MappedNames;
11310b57cec5SDimitry Andric 
11320b57cec5SDimitry Andric   /// The real profile data reader.
11330b57cec5SDimitry Andric   InstrProfReaderIndex<HashTableImpl> &Underlying;
11340b57cec5SDimitry Andric };
11350b57cec5SDimitry Andric 
11360b57cec5SDimitry Andric bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) {
11370b57cec5SDimitry Andric   using namespace support;
11380b57cec5SDimitry Andric 
11390b57cec5SDimitry Andric   if (DataBuffer.getBufferSize() < 8)
11400b57cec5SDimitry Andric     return false;
11415f757f3fSDimitry Andric   uint64_t Magic = endian::read<uint64_t, llvm::endianness::little, aligned>(
11425f757f3fSDimitry Andric       DataBuffer.getBufferStart());
11430b57cec5SDimitry Andric   // Verify that it's magical.
11440b57cec5SDimitry Andric   return Magic == IndexedInstrProf::Magic;
11450b57cec5SDimitry Andric }
11460b57cec5SDimitry Andric 
11470b57cec5SDimitry Andric const unsigned char *
11480b57cec5SDimitry Andric IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version,
11490b57cec5SDimitry Andric                                     const unsigned char *Cur, bool UseCS) {
11500b57cec5SDimitry Andric   using namespace IndexedInstrProf;
11510b57cec5SDimitry Andric   using namespace support;
11520b57cec5SDimitry Andric 
11530b57cec5SDimitry Andric   if (Version >= IndexedInstrProf::Version4) {
11540b57cec5SDimitry Andric     const IndexedInstrProf::Summary *SummaryInLE =
11550b57cec5SDimitry Andric         reinterpret_cast<const IndexedInstrProf::Summary *>(Cur);
11565f757f3fSDimitry Andric     uint64_t NFields = endian::byte_swap<uint64_t, llvm::endianness::little>(
11575f757f3fSDimitry Andric         SummaryInLE->NumSummaryFields);
11585f757f3fSDimitry Andric     uint64_t NEntries = endian::byte_swap<uint64_t, llvm::endianness::little>(
11595f757f3fSDimitry Andric         SummaryInLE->NumCutoffEntries);
11600b57cec5SDimitry Andric     uint32_t SummarySize =
11610b57cec5SDimitry Andric         IndexedInstrProf::Summary::getSize(NFields, NEntries);
11620b57cec5SDimitry Andric     std::unique_ptr<IndexedInstrProf::Summary> SummaryData =
11630b57cec5SDimitry Andric         IndexedInstrProf::allocSummary(SummarySize);
11640b57cec5SDimitry Andric 
11650b57cec5SDimitry Andric     const uint64_t *Src = reinterpret_cast<const uint64_t *>(SummaryInLE);
11660b57cec5SDimitry Andric     uint64_t *Dst = reinterpret_cast<uint64_t *>(SummaryData.get());
11670b57cec5SDimitry Andric     for (unsigned I = 0; I < SummarySize / sizeof(uint64_t); I++)
11685f757f3fSDimitry Andric       Dst[I] = endian::byte_swap<uint64_t, llvm::endianness::little>(Src[I]);
11690b57cec5SDimitry Andric 
11700b57cec5SDimitry Andric     SummaryEntryVector DetailedSummary;
11710b57cec5SDimitry Andric     for (unsigned I = 0; I < SummaryData->NumCutoffEntries; I++) {
11720b57cec5SDimitry Andric       const IndexedInstrProf::Summary::Entry &Ent = SummaryData->getEntry(I);
11730b57cec5SDimitry Andric       DetailedSummary.emplace_back((uint32_t)Ent.Cutoff, Ent.MinBlockCount,
11740b57cec5SDimitry Andric                                    Ent.NumBlocks);
11750b57cec5SDimitry Andric     }
11760b57cec5SDimitry Andric     std::unique_ptr<llvm::ProfileSummary> &Summary =
11770b57cec5SDimitry Andric         UseCS ? this->CS_Summary : this->Summary;
11780b57cec5SDimitry Andric 
11790b57cec5SDimitry Andric     // initialize InstrProfSummary using the SummaryData from disk.
11808bcb0991SDimitry Andric     Summary = std::make_unique<ProfileSummary>(
11810b57cec5SDimitry Andric         UseCS ? ProfileSummary::PSK_CSInstr : ProfileSummary::PSK_Instr,
11820b57cec5SDimitry Andric         DetailedSummary, SummaryData->get(Summary::TotalBlockCount),
11830b57cec5SDimitry Andric         SummaryData->get(Summary::MaxBlockCount),
11840b57cec5SDimitry Andric         SummaryData->get(Summary::MaxInternalBlockCount),
11850b57cec5SDimitry Andric         SummaryData->get(Summary::MaxFunctionCount),
11860b57cec5SDimitry Andric         SummaryData->get(Summary::TotalNumBlocks),
11870b57cec5SDimitry Andric         SummaryData->get(Summary::TotalNumFunctions));
11880b57cec5SDimitry Andric     return Cur + SummarySize;
11890b57cec5SDimitry Andric   } else {
11908bcb0991SDimitry Andric     // The older versions do not support a profile summary. This just computes
11918bcb0991SDimitry Andric     // an empty summary, which will not result in accurate hot/cold detection.
11928bcb0991SDimitry Andric     // We would need to call addRecord for all NamedInstrProfRecords to get the
11938bcb0991SDimitry Andric     // correct summary. However, this version is old (prior to early 2016) and
11948bcb0991SDimitry Andric     // has not been supporting an accurate summary for several years.
11950b57cec5SDimitry Andric     InstrProfSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
11968bcb0991SDimitry Andric     Summary = Builder.getSummary();
11970b57cec5SDimitry Andric     return Cur;
11980b57cec5SDimitry Andric   }
11990b57cec5SDimitry Andric }
12000b57cec5SDimitry Andric 
1201*0fca6ea1SDimitry Andric Error IndexedMemProfReader::deserializeV012(const unsigned char *Start,
1202*0fca6ea1SDimitry Andric                                             const unsigned char *Ptr,
1203*0fca6ea1SDimitry Andric                                             uint64_t FirstWord) {
1204*0fca6ea1SDimitry Andric   // The value returned from RecordTableGenerator.Emit.
1205*0fca6ea1SDimitry Andric   const uint64_t RecordTableOffset =
1206*0fca6ea1SDimitry Andric       Version == memprof::Version0
1207*0fca6ea1SDimitry Andric           ? FirstWord
1208*0fca6ea1SDimitry Andric           : support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1209*0fca6ea1SDimitry Andric   // The offset in the stream right before invoking
1210*0fca6ea1SDimitry Andric   // FrameTableGenerator.Emit.
1211*0fca6ea1SDimitry Andric   const uint64_t FramePayloadOffset =
1212*0fca6ea1SDimitry Andric       support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1213*0fca6ea1SDimitry Andric   // The value returned from FrameTableGenerator.Emit.
1214*0fca6ea1SDimitry Andric   const uint64_t FrameTableOffset =
1215*0fca6ea1SDimitry Andric       support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1216*0fca6ea1SDimitry Andric 
1217*0fca6ea1SDimitry Andric   // The offset in the stream right before invoking
1218*0fca6ea1SDimitry Andric   // CallStackTableGenerator.Emit.
1219*0fca6ea1SDimitry Andric   uint64_t CallStackPayloadOffset = 0;
1220*0fca6ea1SDimitry Andric   // The value returned from CallStackTableGenerator.Emit.
1221*0fca6ea1SDimitry Andric   uint64_t CallStackTableOffset = 0;
1222*0fca6ea1SDimitry Andric   if (Version >= memprof::Version2) {
1223*0fca6ea1SDimitry Andric     CallStackPayloadOffset =
1224*0fca6ea1SDimitry Andric         support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1225*0fca6ea1SDimitry Andric     CallStackTableOffset =
1226*0fca6ea1SDimitry Andric         support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1227*0fca6ea1SDimitry Andric   }
1228*0fca6ea1SDimitry Andric 
1229*0fca6ea1SDimitry Andric   // Read the schema.
1230*0fca6ea1SDimitry Andric   auto SchemaOr = memprof::readMemProfSchema(Ptr);
1231*0fca6ea1SDimitry Andric   if (!SchemaOr)
1232*0fca6ea1SDimitry Andric     return SchemaOr.takeError();
1233*0fca6ea1SDimitry Andric   Schema = SchemaOr.get();
1234*0fca6ea1SDimitry Andric 
1235*0fca6ea1SDimitry Andric   // Now initialize the table reader with a pointer into data buffer.
1236*0fca6ea1SDimitry Andric   MemProfRecordTable.reset(MemProfRecordHashTable::Create(
1237*0fca6ea1SDimitry Andric       /*Buckets=*/Start + RecordTableOffset,
1238*0fca6ea1SDimitry Andric       /*Payload=*/Ptr,
1239*0fca6ea1SDimitry Andric       /*Base=*/Start, memprof::RecordLookupTrait(Version, Schema)));
1240*0fca6ea1SDimitry Andric 
1241*0fca6ea1SDimitry Andric   // Initialize the frame table reader with the payload and bucket offsets.
1242*0fca6ea1SDimitry Andric   MemProfFrameTable.reset(MemProfFrameHashTable::Create(
1243*0fca6ea1SDimitry Andric       /*Buckets=*/Start + FrameTableOffset,
1244*0fca6ea1SDimitry Andric       /*Payload=*/Start + FramePayloadOffset,
1245*0fca6ea1SDimitry Andric       /*Base=*/Start));
1246*0fca6ea1SDimitry Andric 
1247*0fca6ea1SDimitry Andric   if (Version >= memprof::Version2)
1248*0fca6ea1SDimitry Andric     MemProfCallStackTable.reset(MemProfCallStackHashTable::Create(
1249*0fca6ea1SDimitry Andric         /*Buckets=*/Start + CallStackTableOffset,
1250*0fca6ea1SDimitry Andric         /*Payload=*/Start + CallStackPayloadOffset,
1251*0fca6ea1SDimitry Andric         /*Base=*/Start));
1252*0fca6ea1SDimitry Andric 
1253*0fca6ea1SDimitry Andric   return Error::success();
1254*0fca6ea1SDimitry Andric }
1255*0fca6ea1SDimitry Andric 
1256*0fca6ea1SDimitry Andric Error IndexedMemProfReader::deserializeV3(const unsigned char *Start,
1257*0fca6ea1SDimitry Andric                                           const unsigned char *Ptr) {
1258*0fca6ea1SDimitry Andric   // The offset in the stream right before invoking
1259*0fca6ea1SDimitry Andric   // CallStackTableGenerator.Emit.
1260*0fca6ea1SDimitry Andric   const uint64_t CallStackPayloadOffset =
1261*0fca6ea1SDimitry Andric       support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1262*0fca6ea1SDimitry Andric   // The offset in the stream right before invoking RecordTableGenerator.Emit.
1263*0fca6ea1SDimitry Andric   const uint64_t RecordPayloadOffset =
1264*0fca6ea1SDimitry Andric       support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1265*0fca6ea1SDimitry Andric   // The value returned from RecordTableGenerator.Emit.
1266*0fca6ea1SDimitry Andric   const uint64_t RecordTableOffset =
1267*0fca6ea1SDimitry Andric       support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1268*0fca6ea1SDimitry Andric 
1269*0fca6ea1SDimitry Andric   // Read the schema.
1270*0fca6ea1SDimitry Andric   auto SchemaOr = memprof::readMemProfSchema(Ptr);
1271*0fca6ea1SDimitry Andric   if (!SchemaOr)
1272*0fca6ea1SDimitry Andric     return SchemaOr.takeError();
1273*0fca6ea1SDimitry Andric   Schema = SchemaOr.get();
1274*0fca6ea1SDimitry Andric 
1275*0fca6ea1SDimitry Andric   FrameBase = Ptr;
1276*0fca6ea1SDimitry Andric   CallStackBase = Start + CallStackPayloadOffset;
1277*0fca6ea1SDimitry Andric 
1278*0fca6ea1SDimitry Andric   // Now initialize the table reader with a pointer into data buffer.
1279*0fca6ea1SDimitry Andric   MemProfRecordTable.reset(MemProfRecordHashTable::Create(
1280*0fca6ea1SDimitry Andric       /*Buckets=*/Start + RecordTableOffset,
1281*0fca6ea1SDimitry Andric       /*Payload=*/Start + RecordPayloadOffset,
1282*0fca6ea1SDimitry Andric       /*Base=*/Start, memprof::RecordLookupTrait(memprof::Version3, Schema)));
1283*0fca6ea1SDimitry Andric 
1284*0fca6ea1SDimitry Andric   return Error::success();
1285*0fca6ea1SDimitry Andric }
1286*0fca6ea1SDimitry Andric 
1287*0fca6ea1SDimitry Andric Error IndexedMemProfReader::deserialize(const unsigned char *Start,
1288*0fca6ea1SDimitry Andric                                         uint64_t MemProfOffset) {
1289*0fca6ea1SDimitry Andric   const unsigned char *Ptr = Start + MemProfOffset;
1290*0fca6ea1SDimitry Andric 
1291*0fca6ea1SDimitry Andric   // Read the first 64-bit word, which may be RecordTableOffset in
1292*0fca6ea1SDimitry Andric   // memprof::MemProfVersion0 or the MemProf version number in
1293*0fca6ea1SDimitry Andric   // memprof::MemProfVersion1 and above.
1294*0fca6ea1SDimitry Andric   const uint64_t FirstWord =
1295*0fca6ea1SDimitry Andric       support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1296*0fca6ea1SDimitry Andric 
1297*0fca6ea1SDimitry Andric   if (FirstWord == memprof::Version1 || FirstWord == memprof::Version2 ||
1298*0fca6ea1SDimitry Andric       FirstWord == memprof::Version3) {
1299*0fca6ea1SDimitry Andric     // Everything is good.  We can proceed to deserialize the rest.
1300*0fca6ea1SDimitry Andric     Version = static_cast<memprof::IndexedVersion>(FirstWord);
1301*0fca6ea1SDimitry Andric   } else if (FirstWord >= 24) {
1302*0fca6ea1SDimitry Andric     // This is a heuristic/hack to detect memprof::MemProfVersion0,
1303*0fca6ea1SDimitry Andric     // which does not have a version field in the header.
1304*0fca6ea1SDimitry Andric     // In memprof::MemProfVersion0, FirstWord will be RecordTableOffset,
1305*0fca6ea1SDimitry Andric     // which should be at least 24 because of the MemProf header size.
1306*0fca6ea1SDimitry Andric     Version = memprof::Version0;
1307*0fca6ea1SDimitry Andric   } else {
1308*0fca6ea1SDimitry Andric     return make_error<InstrProfError>(
1309*0fca6ea1SDimitry Andric         instrprof_error::unsupported_version,
1310*0fca6ea1SDimitry Andric         formatv("MemProf version {} not supported; "
1311*0fca6ea1SDimitry Andric                 "requires version between {} and {}, inclusive",
1312*0fca6ea1SDimitry Andric                 FirstWord, memprof::MinimumSupportedVersion,
1313*0fca6ea1SDimitry Andric                 memprof::MaximumSupportedVersion));
1314*0fca6ea1SDimitry Andric   }
1315*0fca6ea1SDimitry Andric 
1316*0fca6ea1SDimitry Andric   switch (Version) {
1317*0fca6ea1SDimitry Andric   case memprof::Version0:
1318*0fca6ea1SDimitry Andric   case memprof::Version1:
1319*0fca6ea1SDimitry Andric   case memprof::Version2:
1320*0fca6ea1SDimitry Andric     if (Error E = deserializeV012(Start, Ptr, FirstWord))
1321*0fca6ea1SDimitry Andric       return E;
1322*0fca6ea1SDimitry Andric     break;
1323*0fca6ea1SDimitry Andric   case memprof::Version3:
1324*0fca6ea1SDimitry Andric     if (Error E = deserializeV3(Start, Ptr))
1325*0fca6ea1SDimitry Andric       return E;
1326*0fca6ea1SDimitry Andric     break;
1327*0fca6ea1SDimitry Andric   }
1328*0fca6ea1SDimitry Andric 
1329*0fca6ea1SDimitry Andric #ifdef EXPENSIVE_CHECKS
1330*0fca6ea1SDimitry Andric   // Go through all the records and verify that CSId has been correctly
1331*0fca6ea1SDimitry Andric   // populated.  Do this only under EXPENSIVE_CHECKS.  Otherwise, we
1332*0fca6ea1SDimitry Andric   // would defeat the purpose of OnDiskIterableChainedHashTable.
1333*0fca6ea1SDimitry Andric   // Note that we can compare CSId against actual call stacks only for
1334*0fca6ea1SDimitry Andric   // Version0 and Version1 because IndexedAllocationInfo::CallStack and
1335*0fca6ea1SDimitry Andric   // IndexedMemProfRecord::CallSites are not populated in Version2.
1336*0fca6ea1SDimitry Andric   if (Version <= memprof::Version1)
1337*0fca6ea1SDimitry Andric     for (const auto &Record : MemProfRecordTable->data())
1338*0fca6ea1SDimitry Andric       verifyIndexedMemProfRecord(Record);
1339*0fca6ea1SDimitry Andric #endif
1340*0fca6ea1SDimitry Andric 
1341*0fca6ea1SDimitry Andric   return Error::success();
1342*0fca6ea1SDimitry Andric }
1343*0fca6ea1SDimitry Andric 
13440b57cec5SDimitry Andric Error IndexedInstrProfReader::readHeader() {
13450b57cec5SDimitry Andric   using namespace support;
13460b57cec5SDimitry Andric 
13470b57cec5SDimitry Andric   const unsigned char *Start =
13480b57cec5SDimitry Andric       (const unsigned char *)DataBuffer->getBufferStart();
13490b57cec5SDimitry Andric   const unsigned char *Cur = Start;
13500b57cec5SDimitry Andric   if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24)
13510b57cec5SDimitry Andric     return error(instrprof_error::truncated);
13520b57cec5SDimitry Andric 
135381ad6265SDimitry Andric   auto HeaderOr = IndexedInstrProf::Header::readFromBuffer(Start);
135481ad6265SDimitry Andric   if (!HeaderOr)
135581ad6265SDimitry Andric     return HeaderOr.takeError();
13560b57cec5SDimitry Andric 
135781ad6265SDimitry Andric   const IndexedInstrProf::Header *Header = &HeaderOr.get();
135881ad6265SDimitry Andric   Cur += Header->size();
13590b57cec5SDimitry Andric 
1360*0fca6ea1SDimitry Andric   Cur = readSummary((IndexedInstrProf::ProfVersion)Header->Version, Cur,
13610b57cec5SDimitry Andric                     /* UseCS */ false);
1362*0fca6ea1SDimitry Andric   if (Header->Version & VARIANT_MASK_CSIR_PROF)
1363*0fca6ea1SDimitry Andric     Cur = readSummary((IndexedInstrProf::ProfVersion)Header->Version, Cur,
13640b57cec5SDimitry Andric                       /* UseCS */ true);
13650b57cec5SDimitry Andric   // Read the hash type and start offset.
1366*0fca6ea1SDimitry Andric   IndexedInstrProf::HashT HashType =
1367*0fca6ea1SDimitry Andric       static_cast<IndexedInstrProf::HashT>(Header->HashType);
13680b57cec5SDimitry Andric   if (HashType > IndexedInstrProf::HashT::Last)
13690b57cec5SDimitry Andric     return error(instrprof_error::unsupported_hash_type);
13700b57cec5SDimitry Andric 
137181ad6265SDimitry Andric   // The hash table with profile counts comes next.
137281ad6265SDimitry Andric   auto IndexPtr = std::make_unique<InstrProfReaderIndex<OnDiskHashTableImplV3>>(
1373*0fca6ea1SDimitry Andric       Start + Header->HashOffset, Cur, Start, HashType, Header->Version);
137481ad6265SDimitry Andric 
1375bdd1243dSDimitry Andric   // The MemProfOffset field in the header is only valid when the format
1376bdd1243dSDimitry Andric   // version is higher than 8 (when it was introduced).
1377*0fca6ea1SDimitry Andric   if (Header->getIndexedProfileVersion() >= 8 &&
1378*0fca6ea1SDimitry Andric       Header->Version & VARIANT_MASK_MEMPROF) {
1379*0fca6ea1SDimitry Andric     if (Error E = MemProfReader.deserialize(Start, Header->MemProfOffset))
1380*0fca6ea1SDimitry Andric       return E;
138181ad6265SDimitry Andric   }
13820b57cec5SDimitry Andric 
1383bdd1243dSDimitry Andric   // BinaryIdOffset field in the header is only valid when the format version
1384bdd1243dSDimitry Andric   // is higher than 9 (when it was introduced).
1385*0fca6ea1SDimitry Andric   if (Header->getIndexedProfileVersion() >= 9) {
1386*0fca6ea1SDimitry Andric     const unsigned char *Ptr = Start + Header->BinaryIdOffset;
1387bdd1243dSDimitry Andric     // Read binary ids size.
1388*0fca6ea1SDimitry Andric     uint64_t BinaryIdsSize =
1389*0fca6ea1SDimitry Andric         support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1390bdd1243dSDimitry Andric     if (BinaryIdsSize % sizeof(uint64_t))
1391bdd1243dSDimitry Andric       return error(instrprof_error::bad_header);
1392bdd1243dSDimitry Andric     // Set the binary ids start.
1393*0fca6ea1SDimitry Andric     BinaryIdsBuffer = ArrayRef<uint8_t>(Ptr, BinaryIdsSize);
1394*0fca6ea1SDimitry Andric     if (Ptr > (const unsigned char *)DataBuffer->getBufferEnd())
1395bdd1243dSDimitry Andric       return make_error<InstrProfError>(instrprof_error::malformed,
1396bdd1243dSDimitry Andric                                         "corrupted binary ids");
1397bdd1243dSDimitry Andric   }
1398bdd1243dSDimitry Andric 
1399*0fca6ea1SDimitry Andric   if (Header->getIndexedProfileVersion() >= 12) {
1400*0fca6ea1SDimitry Andric     const unsigned char *Ptr = Start + Header->VTableNamesOffset;
1401*0fca6ea1SDimitry Andric 
1402*0fca6ea1SDimitry Andric     uint64_t CompressedVTableNamesLen =
1403*0fca6ea1SDimitry Andric         support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
1404*0fca6ea1SDimitry Andric 
1405*0fca6ea1SDimitry Andric     // Writer first writes the length of compressed string, and then the actual
1406*0fca6ea1SDimitry Andric     // content.
1407*0fca6ea1SDimitry Andric     const char *VTableNamePtr = (const char *)Ptr;
1408*0fca6ea1SDimitry Andric     if (VTableNamePtr > (const char *)DataBuffer->getBufferEnd())
1409*0fca6ea1SDimitry Andric       return make_error<InstrProfError>(instrprof_error::truncated);
1410*0fca6ea1SDimitry Andric 
1411*0fca6ea1SDimitry Andric     VTableName = StringRef(VTableNamePtr, CompressedVTableNamesLen);
1412*0fca6ea1SDimitry Andric   }
1413*0fca6ea1SDimitry Andric 
1414*0fca6ea1SDimitry Andric   if (Header->getIndexedProfileVersion() >= 10 &&
1415*0fca6ea1SDimitry Andric       Header->Version & VARIANT_MASK_TEMPORAL_PROF) {
1416*0fca6ea1SDimitry Andric     const unsigned char *Ptr = Start + Header->TemporalProfTracesOffset;
141706c3fb27SDimitry Andric     const auto *PtrEnd = (const unsigned char *)DataBuffer->getBufferEnd();
141806c3fb27SDimitry Andric     // Expect at least two 64 bit fields: NumTraces, and TraceStreamSize
141906c3fb27SDimitry Andric     if (Ptr + 2 * sizeof(uint64_t) > PtrEnd)
142006c3fb27SDimitry Andric       return error(instrprof_error::truncated);
142106c3fb27SDimitry Andric     const uint64_t NumTraces =
1422*0fca6ea1SDimitry Andric         support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
142306c3fb27SDimitry Andric     TemporalProfTraceStreamSize =
1424*0fca6ea1SDimitry Andric         support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
142506c3fb27SDimitry Andric     for (unsigned i = 0; i < NumTraces; i++) {
142606c3fb27SDimitry Andric       // Expect at least two 64 bit fields: Weight and NumFunctions
142706c3fb27SDimitry Andric       if (Ptr + 2 * sizeof(uint64_t) > PtrEnd)
142806c3fb27SDimitry Andric         return error(instrprof_error::truncated);
142906c3fb27SDimitry Andric       TemporalProfTraceTy Trace;
143006c3fb27SDimitry Andric       Trace.Weight =
1431*0fca6ea1SDimitry Andric           support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
143206c3fb27SDimitry Andric       const uint64_t NumFunctions =
1433*0fca6ea1SDimitry Andric           support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
143406c3fb27SDimitry Andric       // Expect at least NumFunctions 64 bit fields
143506c3fb27SDimitry Andric       if (Ptr + NumFunctions * sizeof(uint64_t) > PtrEnd)
143606c3fb27SDimitry Andric         return error(instrprof_error::truncated);
143706c3fb27SDimitry Andric       for (unsigned j = 0; j < NumFunctions; j++) {
143806c3fb27SDimitry Andric         const uint64_t NameRef =
1439*0fca6ea1SDimitry Andric             support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
144006c3fb27SDimitry Andric         Trace.FunctionNameRefs.push_back(NameRef);
144106c3fb27SDimitry Andric       }
144206c3fb27SDimitry Andric       TemporalProfTraces.push_back(std::move(Trace));
144306c3fb27SDimitry Andric     }
144406c3fb27SDimitry Andric   }
144506c3fb27SDimitry Andric 
14460b57cec5SDimitry Andric   // Load the remapping table now if requested.
14470b57cec5SDimitry Andric   if (RemappingBuffer) {
1448bdd1243dSDimitry Andric     Remapper =
1449bdd1243dSDimitry Andric         std::make_unique<InstrProfReaderItaniumRemapper<OnDiskHashTableImplV3>>(
14500b57cec5SDimitry Andric             std::move(RemappingBuffer), *IndexPtr);
14510b57cec5SDimitry Andric     if (Error E = Remapper->populateRemappings())
14520b57cec5SDimitry Andric       return E;
14530b57cec5SDimitry Andric   } else {
14548bcb0991SDimitry Andric     Remapper = std::make_unique<InstrProfReaderNullRemapper>(*IndexPtr);
14550b57cec5SDimitry Andric   }
14560b57cec5SDimitry Andric   Index = std::move(IndexPtr);
14570b57cec5SDimitry Andric 
14580b57cec5SDimitry Andric   return success();
14590b57cec5SDimitry Andric }
14600b57cec5SDimitry Andric 
14610b57cec5SDimitry Andric InstrProfSymtab &IndexedInstrProfReader::getSymtab() {
146281ad6265SDimitry Andric   if (Symtab)
146381ad6265SDimitry Andric     return *Symtab;
14640b57cec5SDimitry Andric 
1465*0fca6ea1SDimitry Andric   auto NewSymtab = std::make_unique<InstrProfSymtab>();
1466*0fca6ea1SDimitry Andric 
1467*0fca6ea1SDimitry Andric   if (Error E = NewSymtab->initVTableNamesFromCompressedStrings(VTableName)) {
1468*0fca6ea1SDimitry Andric     auto [ErrCode, Msg] = InstrProfError::take(std::move(E));
1469*0fca6ea1SDimitry Andric     consumeError(error(ErrCode, Msg));
1470*0fca6ea1SDimitry Andric   }
1471*0fca6ea1SDimitry Andric 
1472*0fca6ea1SDimitry Andric   // finalizeSymtab is called inside populateSymtab.
147381ad6265SDimitry Andric   if (Error E = Index->populateSymtab(*NewSymtab)) {
147406c3fb27SDimitry Andric     auto [ErrCode, Msg] = InstrProfError::take(std::move(E));
147506c3fb27SDimitry Andric     consumeError(error(ErrCode, Msg));
14760b57cec5SDimitry Andric   }
14770b57cec5SDimitry Andric 
14780b57cec5SDimitry Andric   Symtab = std::move(NewSymtab);
147981ad6265SDimitry Andric   return *Symtab;
14800b57cec5SDimitry Andric }
14810b57cec5SDimitry Andric 
1482fcaf7f86SDimitry Andric Expected<InstrProfRecord> IndexedInstrProfReader::getInstrProfRecord(
14835f757f3fSDimitry Andric     StringRef FuncName, uint64_t FuncHash, StringRef DeprecatedFuncName,
14845f757f3fSDimitry Andric     uint64_t *MismatchedFuncSum) {
14850b57cec5SDimitry Andric   ArrayRef<NamedInstrProfRecord> Data;
1486fcaf7f86SDimitry Andric   uint64_t FuncSum = 0;
14875f757f3fSDimitry Andric   auto Err = Remapper->getRecords(FuncName, Data);
14885f757f3fSDimitry Andric   if (Err) {
14895f757f3fSDimitry Andric     // If we don't find FuncName, try DeprecatedFuncName to handle profiles
14905f757f3fSDimitry Andric     // built by older compilers.
14915f757f3fSDimitry Andric     auto Err2 =
14925f757f3fSDimitry Andric         handleErrors(std::move(Err), [&](const InstrProfError &IE) -> Error {
14935f757f3fSDimitry Andric           if (IE.get() != instrprof_error::unknown_function)
14945f757f3fSDimitry Andric             return make_error<InstrProfError>(IE);
14955f757f3fSDimitry Andric           if (auto Err = Remapper->getRecords(DeprecatedFuncName, Data))
14965f757f3fSDimitry Andric             return Err;
14975f757f3fSDimitry Andric           return Error::success();
14985f757f3fSDimitry Andric         });
14995f757f3fSDimitry Andric     if (Err2)
15005f757f3fSDimitry Andric       return std::move(Err2);
15015f757f3fSDimitry Andric   }
15020b57cec5SDimitry Andric   // Found it. Look for counters with the right hash.
1503fcaf7f86SDimitry Andric 
1504fcaf7f86SDimitry Andric   // A flag to indicate if the records are from the same type
1505fcaf7f86SDimitry Andric   // of profile (i.e cs vs nocs).
1506fcaf7f86SDimitry Andric   bool CSBitMatch = false;
1507*0fca6ea1SDimitry Andric   auto getFuncSum = [](ArrayRef<uint64_t> Counts) {
1508fcaf7f86SDimitry Andric     uint64_t ValueSum = 0;
1509bdd1243dSDimitry Andric     for (uint64_t CountValue : Counts) {
1510fcaf7f86SDimitry Andric       if (CountValue == (uint64_t)-1)
1511fcaf7f86SDimitry Andric         continue;
1512fcaf7f86SDimitry Andric       // Handle overflow -- if that happens, return max.
1513fcaf7f86SDimitry Andric       if (std::numeric_limits<uint64_t>::max() - CountValue <= ValueSum)
1514fcaf7f86SDimitry Andric         return std::numeric_limits<uint64_t>::max();
1515fcaf7f86SDimitry Andric       ValueSum += CountValue;
1516fcaf7f86SDimitry Andric     }
1517fcaf7f86SDimitry Andric     return ValueSum;
1518fcaf7f86SDimitry Andric   };
1519fcaf7f86SDimitry Andric 
15200eae32dcSDimitry Andric   for (const NamedInstrProfRecord &I : Data) {
15210b57cec5SDimitry Andric     // Check for a match and fill the vector if there is one.
15220eae32dcSDimitry Andric     if (I.Hash == FuncHash)
15230eae32dcSDimitry Andric       return std::move(I);
1524fcaf7f86SDimitry Andric     if (NamedInstrProfRecord::hasCSFlagInHash(I.Hash) ==
1525fcaf7f86SDimitry Andric         NamedInstrProfRecord::hasCSFlagInHash(FuncHash)) {
1526fcaf7f86SDimitry Andric       CSBitMatch = true;
1527fcaf7f86SDimitry Andric       if (MismatchedFuncSum == nullptr)
1528fcaf7f86SDimitry Andric         continue;
1529fcaf7f86SDimitry Andric       FuncSum = std::max(FuncSum, getFuncSum(I.Counts));
15300b57cec5SDimitry Andric     }
1531fcaf7f86SDimitry Andric   }
1532fcaf7f86SDimitry Andric   if (CSBitMatch) {
1533fcaf7f86SDimitry Andric     if (MismatchedFuncSum != nullptr)
1534fcaf7f86SDimitry Andric       *MismatchedFuncSum = FuncSum;
15350b57cec5SDimitry Andric     return error(instrprof_error::hash_mismatch);
15360b57cec5SDimitry Andric   }
1537fcaf7f86SDimitry Andric   return error(instrprof_error::unknown_function);
1538fcaf7f86SDimitry Andric }
15390b57cec5SDimitry Andric 
1540*0fca6ea1SDimitry Andric static Expected<memprof::MemProfRecord>
1541*0fca6ea1SDimitry Andric getMemProfRecordV0(const memprof::IndexedMemProfRecord &IndexedRecord,
1542*0fca6ea1SDimitry Andric                    MemProfFrameHashTable &MemProfFrameTable) {
1543*0fca6ea1SDimitry Andric   memprof::FrameIdConverter<MemProfFrameHashTable> FrameIdConv(
1544*0fca6ea1SDimitry Andric       MemProfFrameTable);
1545*0fca6ea1SDimitry Andric 
1546*0fca6ea1SDimitry Andric   memprof::MemProfRecord Record =
1547*0fca6ea1SDimitry Andric       memprof::MemProfRecord(IndexedRecord, FrameIdConv);
1548*0fca6ea1SDimitry Andric 
1549*0fca6ea1SDimitry Andric   // Check that all frame ids were successfully converted to frames.
1550*0fca6ea1SDimitry Andric   if (FrameIdConv.LastUnmappedId) {
1551*0fca6ea1SDimitry Andric     return make_error<InstrProfError>(instrprof_error::hash_mismatch,
1552*0fca6ea1SDimitry Andric                                       "memprof frame not found for frame id " +
1553*0fca6ea1SDimitry Andric                                           Twine(*FrameIdConv.LastUnmappedId));
1554*0fca6ea1SDimitry Andric   }
1555*0fca6ea1SDimitry Andric 
1556*0fca6ea1SDimitry Andric   return Record;
1557*0fca6ea1SDimitry Andric }
1558*0fca6ea1SDimitry Andric 
1559*0fca6ea1SDimitry Andric static Expected<memprof::MemProfRecord>
1560*0fca6ea1SDimitry Andric getMemProfRecordV2(const memprof::IndexedMemProfRecord &IndexedRecord,
1561*0fca6ea1SDimitry Andric                    MemProfFrameHashTable &MemProfFrameTable,
1562*0fca6ea1SDimitry Andric                    MemProfCallStackHashTable &MemProfCallStackTable) {
1563*0fca6ea1SDimitry Andric   memprof::FrameIdConverter<MemProfFrameHashTable> FrameIdConv(
1564*0fca6ea1SDimitry Andric       MemProfFrameTable);
1565*0fca6ea1SDimitry Andric 
1566*0fca6ea1SDimitry Andric   memprof::CallStackIdConverter<MemProfCallStackHashTable> CSIdConv(
1567*0fca6ea1SDimitry Andric       MemProfCallStackTable, FrameIdConv);
1568*0fca6ea1SDimitry Andric 
1569*0fca6ea1SDimitry Andric   memprof::MemProfRecord Record = IndexedRecord.toMemProfRecord(CSIdConv);
1570*0fca6ea1SDimitry Andric 
1571*0fca6ea1SDimitry Andric   // Check that all call stack ids were successfully converted to call stacks.
1572*0fca6ea1SDimitry Andric   if (CSIdConv.LastUnmappedId) {
1573*0fca6ea1SDimitry Andric     return make_error<InstrProfError>(
1574*0fca6ea1SDimitry Andric         instrprof_error::hash_mismatch,
1575*0fca6ea1SDimitry Andric         "memprof call stack not found for call stack id " +
1576*0fca6ea1SDimitry Andric             Twine(*CSIdConv.LastUnmappedId));
1577*0fca6ea1SDimitry Andric   }
1578*0fca6ea1SDimitry Andric 
1579*0fca6ea1SDimitry Andric   // Check that all frame ids were successfully converted to frames.
1580*0fca6ea1SDimitry Andric   if (FrameIdConv.LastUnmappedId) {
1581*0fca6ea1SDimitry Andric     return make_error<InstrProfError>(instrprof_error::hash_mismatch,
1582*0fca6ea1SDimitry Andric                                       "memprof frame not found for frame id " +
1583*0fca6ea1SDimitry Andric                                           Twine(*FrameIdConv.LastUnmappedId));
1584*0fca6ea1SDimitry Andric   }
1585*0fca6ea1SDimitry Andric 
1586*0fca6ea1SDimitry Andric   return Record;
1587*0fca6ea1SDimitry Andric }
1588*0fca6ea1SDimitry Andric 
1589*0fca6ea1SDimitry Andric static Expected<memprof::MemProfRecord>
1590*0fca6ea1SDimitry Andric getMemProfRecordV3(const memprof::IndexedMemProfRecord &IndexedRecord,
1591*0fca6ea1SDimitry Andric                    const unsigned char *FrameBase,
1592*0fca6ea1SDimitry Andric                    const unsigned char *CallStackBase) {
1593*0fca6ea1SDimitry Andric   memprof::LinearFrameIdConverter FrameIdConv(FrameBase);
1594*0fca6ea1SDimitry Andric   memprof::LinearCallStackIdConverter CSIdConv(CallStackBase, FrameIdConv);
1595*0fca6ea1SDimitry Andric   memprof::MemProfRecord Record = IndexedRecord.toMemProfRecord(CSIdConv);
1596*0fca6ea1SDimitry Andric   return Record;
1597*0fca6ea1SDimitry Andric }
1598*0fca6ea1SDimitry Andric 
159981ad6265SDimitry Andric Expected<memprof::MemProfRecord>
1600*0fca6ea1SDimitry Andric IndexedMemProfReader::getMemProfRecord(const uint64_t FuncNameHash) const {
160181ad6265SDimitry Andric   // TODO: Add memprof specific errors.
160281ad6265SDimitry Andric   if (MemProfRecordTable == nullptr)
160381ad6265SDimitry Andric     return make_error<InstrProfError>(instrprof_error::invalid_prof,
160481ad6265SDimitry Andric                                       "no memprof data available in profile");
160581ad6265SDimitry Andric   auto Iter = MemProfRecordTable->find(FuncNameHash);
160681ad6265SDimitry Andric   if (Iter == MemProfRecordTable->end())
160781ad6265SDimitry Andric     return make_error<InstrProfError>(
160881ad6265SDimitry Andric         instrprof_error::unknown_function,
160981ad6265SDimitry Andric         "memprof record not found for function hash " + Twine(FuncNameHash));
161081ad6265SDimitry Andric 
1611*0fca6ea1SDimitry Andric   const memprof::IndexedMemProfRecord &IndexedRecord = *Iter;
1612*0fca6ea1SDimitry Andric   switch (Version) {
1613*0fca6ea1SDimitry Andric   case memprof::Version0:
1614*0fca6ea1SDimitry Andric   case memprof::Version1:
1615*0fca6ea1SDimitry Andric     assert(MemProfFrameTable && "MemProfFrameTable must be available");
1616*0fca6ea1SDimitry Andric     assert(!MemProfCallStackTable &&
1617*0fca6ea1SDimitry Andric            "MemProfCallStackTable must not be available");
1618*0fca6ea1SDimitry Andric     return getMemProfRecordV0(IndexedRecord, *MemProfFrameTable);
1619*0fca6ea1SDimitry Andric   case memprof::Version2:
1620*0fca6ea1SDimitry Andric     assert(MemProfFrameTable && "MemProfFrameTable must be available");
1621*0fca6ea1SDimitry Andric     assert(MemProfCallStackTable && "MemProfCallStackTable must be available");
1622*0fca6ea1SDimitry Andric     return getMemProfRecordV2(IndexedRecord, *MemProfFrameTable,
1623*0fca6ea1SDimitry Andric                               *MemProfCallStackTable);
1624*0fca6ea1SDimitry Andric   case memprof::Version3:
1625*0fca6ea1SDimitry Andric     assert(!MemProfFrameTable && "MemProfFrameTable must not be available");
1626*0fca6ea1SDimitry Andric     assert(!MemProfCallStackTable &&
1627*0fca6ea1SDimitry Andric            "MemProfCallStackTable must not be available");
1628*0fca6ea1SDimitry Andric     assert(FrameBase && "FrameBase must be available");
1629*0fca6ea1SDimitry Andric     assert(CallStackBase && "CallStackBase must be available");
1630*0fca6ea1SDimitry Andric     return getMemProfRecordV3(IndexedRecord, FrameBase, CallStackBase);
163181ad6265SDimitry Andric   }
163281ad6265SDimitry Andric 
1633*0fca6ea1SDimitry Andric   return make_error<InstrProfError>(
1634*0fca6ea1SDimitry Andric       instrprof_error::unsupported_version,
1635*0fca6ea1SDimitry Andric       formatv("MemProf version {} not supported; "
1636*0fca6ea1SDimitry Andric               "requires version between {} and {}, inclusive",
1637*0fca6ea1SDimitry Andric               Version, memprof::MinimumSupportedVersion,
1638*0fca6ea1SDimitry Andric               memprof::MaximumSupportedVersion));
163981ad6265SDimitry Andric }
164081ad6265SDimitry Andric 
16410b57cec5SDimitry Andric Error IndexedInstrProfReader::getFunctionCounts(StringRef FuncName,
16420b57cec5SDimitry Andric                                                 uint64_t FuncHash,
16430b57cec5SDimitry Andric                                                 std::vector<uint64_t> &Counts) {
16440b57cec5SDimitry Andric   Expected<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash);
16450b57cec5SDimitry Andric   if (Error E = Record.takeError())
16460b57cec5SDimitry Andric     return error(std::move(E));
16470b57cec5SDimitry Andric 
16480b57cec5SDimitry Andric   Counts = Record.get().Counts;
16490b57cec5SDimitry Andric   return success();
16500b57cec5SDimitry Andric }
16510b57cec5SDimitry Andric 
1652*0fca6ea1SDimitry Andric Error IndexedInstrProfReader::getFunctionBitmap(StringRef FuncName,
1653*0fca6ea1SDimitry Andric                                                 uint64_t FuncHash,
1654*0fca6ea1SDimitry Andric                                                 BitVector &Bitmap) {
16555f757f3fSDimitry Andric   Expected<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash);
16565f757f3fSDimitry Andric   if (Error E = Record.takeError())
16575f757f3fSDimitry Andric     return error(std::move(E));
16585f757f3fSDimitry Andric 
1659*0fca6ea1SDimitry Andric   const auto &BitmapBytes = Record.get().BitmapBytes;
1660*0fca6ea1SDimitry Andric   size_t I = 0, E = BitmapBytes.size();
1661*0fca6ea1SDimitry Andric   Bitmap.resize(E * CHAR_BIT);
1662*0fca6ea1SDimitry Andric   BitVector::apply(
1663*0fca6ea1SDimitry Andric       [&](auto X) {
1664*0fca6ea1SDimitry Andric         using XTy = decltype(X);
1665*0fca6ea1SDimitry Andric         alignas(XTy) uint8_t W[sizeof(X)];
1666*0fca6ea1SDimitry Andric         size_t N = std::min(E - I, sizeof(W));
1667*0fca6ea1SDimitry Andric         std::memset(W, 0, sizeof(W));
1668*0fca6ea1SDimitry Andric         std::memcpy(W, &BitmapBytes[I], N);
1669*0fca6ea1SDimitry Andric         I += N;
1670*0fca6ea1SDimitry Andric         return support::endian::read<XTy, llvm::endianness::little,
1671*0fca6ea1SDimitry Andric                                      support::aligned>(W);
1672*0fca6ea1SDimitry Andric       },
1673*0fca6ea1SDimitry Andric       Bitmap, Bitmap);
1674*0fca6ea1SDimitry Andric   assert(I == E);
1675*0fca6ea1SDimitry Andric 
16765f757f3fSDimitry Andric   return success();
16775f757f3fSDimitry Andric }
16785f757f3fSDimitry Andric 
16790b57cec5SDimitry Andric Error IndexedInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
16800b57cec5SDimitry Andric   ArrayRef<NamedInstrProfRecord> Data;
16810b57cec5SDimitry Andric 
16820b57cec5SDimitry Andric   Error E = Index->getRecords(Data);
16830b57cec5SDimitry Andric   if (E)
16840b57cec5SDimitry Andric     return error(std::move(E));
16850b57cec5SDimitry Andric 
16860b57cec5SDimitry Andric   Record = Data[RecordIndex++];
16870b57cec5SDimitry Andric   if (RecordIndex >= Data.size()) {
16880b57cec5SDimitry Andric     Index->advanceToNextKey();
16890b57cec5SDimitry Andric     RecordIndex = 0;
16900b57cec5SDimitry Andric   }
16910b57cec5SDimitry Andric   return success();
16920b57cec5SDimitry Andric }
16930b57cec5SDimitry Andric 
1694bdd1243dSDimitry Andric Error IndexedInstrProfReader::readBinaryIds(
1695bdd1243dSDimitry Andric     std::vector<llvm::object::BuildID> &BinaryIds) {
1696*0fca6ea1SDimitry Andric   return readBinaryIdsInternal(*DataBuffer, BinaryIdsBuffer, BinaryIds,
1697*0fca6ea1SDimitry Andric                                llvm::endianness::little);
1698bdd1243dSDimitry Andric }
1699bdd1243dSDimitry Andric 
1700bdd1243dSDimitry Andric Error IndexedInstrProfReader::printBinaryIds(raw_ostream &OS) {
17015f757f3fSDimitry Andric   std::vector<llvm::object::BuildID> BinaryIds;
17025f757f3fSDimitry Andric   if (Error E = readBinaryIds(BinaryIds))
17035f757f3fSDimitry Andric     return E;
17045f757f3fSDimitry Andric   printBinaryIdsInternal(OS, BinaryIds);
17055f757f3fSDimitry Andric   return Error::success();
1706bdd1243dSDimitry Andric }
1707bdd1243dSDimitry Andric 
17088bcb0991SDimitry Andric void InstrProfReader::accumulateCounts(CountSumOrPercent &Sum, bool IsCS) {
17090b57cec5SDimitry Andric   uint64_t NumFuncs = 0;
17100b57cec5SDimitry Andric   for (const auto &Func : *this) {
17110b57cec5SDimitry Andric     if (isIRLevelProfile()) {
17120b57cec5SDimitry Andric       bool FuncIsCS = NamedInstrProfRecord::hasCSFlagInHash(Func.Hash);
17130b57cec5SDimitry Andric       if (FuncIsCS != IsCS)
17140b57cec5SDimitry Andric         continue;
17150b57cec5SDimitry Andric     }
17168bcb0991SDimitry Andric     Func.accumulateCounts(Sum);
17170b57cec5SDimitry Andric     ++NumFuncs;
17180b57cec5SDimitry Andric   }
17190b57cec5SDimitry Andric   Sum.NumEntries = NumFuncs;
17200b57cec5SDimitry Andric }
1721