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"
23fe013be4SDimitry 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"
270b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
280b57cec5SDimitry Andric #include "llvm/Support/SwapByteOrder.h"
29fe013be4SDimitry Andric #include "llvm/Support/VirtualFileSystem.h"
300b57cec5SDimitry Andric #include <algorithm>
310b57cec5SDimitry Andric #include <cstddef>
320b57cec5SDimitry Andric #include <cstdint>
330b57cec5SDimitry Andric #include <limits>
340b57cec5SDimitry Andric #include <memory>
350b57cec5SDimitry Andric #include <system_error>
360b57cec5SDimitry Andric #include <utility>
370b57cec5SDimitry Andric #include <vector>
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric using namespace llvm;
400b57cec5SDimitry Andric 
41c9157d92SDimitry Andric // Extracts the variant information from the top 32 bits in the version and
421fd87a68SDimitry Andric // returns an enum specifying the variants present.
getProfileKindFromVersion(uint64_t Version)431fd87a68SDimitry Andric static InstrProfKind getProfileKindFromVersion(uint64_t Version) {
441fd87a68SDimitry Andric   InstrProfKind ProfileKind = InstrProfKind::Unknown;
451fd87a68SDimitry Andric   if (Version & VARIANT_MASK_IR_PROF) {
4681ad6265SDimitry Andric     ProfileKind |= InstrProfKind::IRInstrumentation;
471fd87a68SDimitry Andric   }
481fd87a68SDimitry Andric   if (Version & VARIANT_MASK_CSIR_PROF) {
4981ad6265SDimitry Andric     ProfileKind |= InstrProfKind::ContextSensitive;
501fd87a68SDimitry Andric   }
511fd87a68SDimitry Andric   if (Version & VARIANT_MASK_INSTR_ENTRY) {
5281ad6265SDimitry Andric     ProfileKind |= InstrProfKind::FunctionEntryInstrumentation;
531fd87a68SDimitry Andric   }
541fd87a68SDimitry Andric   if (Version & VARIANT_MASK_BYTE_COVERAGE) {
551fd87a68SDimitry Andric     ProfileKind |= InstrProfKind::SingleByteCoverage;
561fd87a68SDimitry Andric   }
571fd87a68SDimitry Andric   if (Version & VARIANT_MASK_FUNCTION_ENTRY_ONLY) {
581fd87a68SDimitry Andric     ProfileKind |= InstrProfKind::FunctionEntryOnly;
591fd87a68SDimitry Andric   }
6081ad6265SDimitry Andric   if (Version & VARIANT_MASK_MEMPROF) {
6181ad6265SDimitry Andric     ProfileKind |= InstrProfKind::MemProf;
6281ad6265SDimitry Andric   }
63fe013be4SDimitry Andric   if (Version & VARIANT_MASK_TEMPORAL_PROF) {
64fe013be4SDimitry Andric     ProfileKind |= InstrProfKind::TemporalProfile;
65fe013be4SDimitry Andric   }
661fd87a68SDimitry Andric   return ProfileKind;
671fd87a68SDimitry Andric }
681fd87a68SDimitry Andric 
690b57cec5SDimitry Andric static Expected<std::unique_ptr<MemoryBuffer>>
setupMemoryBuffer(const Twine & Filename,vfs::FileSystem & FS)70fe013be4SDimitry Andric setupMemoryBuffer(const Twine &Filename, vfs::FileSystem &FS) {
71fe013be4SDimitry Andric   auto BufferOrErr = Filename.str() == "-" ? MemoryBuffer::getSTDIN()
72fe013be4SDimitry Andric                                            : FS.getBufferForFile(Filename);
730b57cec5SDimitry Andric   if (std::error_code EC = BufferOrErr.getError())
740b57cec5SDimitry Andric     return errorCodeToError(EC);
750b57cec5SDimitry Andric   return std::move(BufferOrErr.get());
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric 
initializeReader(InstrProfReader & Reader)780b57cec5SDimitry Andric static Error initializeReader(InstrProfReader &Reader) {
790b57cec5SDimitry Andric   return Reader.readHeader();
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric 
82bdd1243dSDimitry Andric /// Read a list of binary ids from a profile that consist of
83bdd1243dSDimitry Andric /// a. uint64_t binary id length
84bdd1243dSDimitry Andric /// b. uint8_t  binary id data
85bdd1243dSDimitry Andric /// c. uint8_t  padding (if necessary)
86bdd1243dSDimitry Andric /// This function is shared between raw and indexed profiles.
87bdd1243dSDimitry Andric /// Raw profiles are in host-endian format, and indexed profiles are in
88bdd1243dSDimitry Andric /// little-endian format. So, this function takes an argument indicating the
89bdd1243dSDimitry Andric /// associated endian format to read the binary ids correctly.
90bdd1243dSDimitry Andric static Error
readBinaryIdsInternal(const MemoryBuffer & DataBuffer,const uint64_t BinaryIdsSize,const uint8_t * BinaryIdsStart,std::vector<llvm::object::BuildID> & BinaryIds,const llvm::endianness Endian)91bdd1243dSDimitry Andric readBinaryIdsInternal(const MemoryBuffer &DataBuffer,
92bdd1243dSDimitry Andric                       const uint64_t BinaryIdsSize,
93bdd1243dSDimitry Andric                       const uint8_t *BinaryIdsStart,
94bdd1243dSDimitry Andric                       std::vector<llvm::object::BuildID> &BinaryIds,
95c9157d92SDimitry Andric                       const llvm::endianness Endian) {
96bdd1243dSDimitry Andric   using namespace support;
97bdd1243dSDimitry Andric 
98bdd1243dSDimitry Andric   if (BinaryIdsSize == 0)
99bdd1243dSDimitry Andric     return Error::success();
100bdd1243dSDimitry Andric 
101bdd1243dSDimitry Andric   const uint8_t *BI = BinaryIdsStart;
102bdd1243dSDimitry Andric   const uint8_t *BIEnd = BinaryIdsStart + BinaryIdsSize;
103bdd1243dSDimitry Andric   const uint8_t *End =
104bdd1243dSDimitry Andric       reinterpret_cast<const uint8_t *>(DataBuffer.getBufferEnd());
105bdd1243dSDimitry Andric 
106bdd1243dSDimitry Andric   while (BI < BIEnd) {
107bdd1243dSDimitry Andric     size_t Remaining = BIEnd - BI;
108bdd1243dSDimitry Andric     // There should be enough left to read the binary id length.
109bdd1243dSDimitry Andric     if (Remaining < sizeof(uint64_t))
110bdd1243dSDimitry Andric       return make_error<InstrProfError>(
111bdd1243dSDimitry Andric           instrprof_error::malformed,
112bdd1243dSDimitry Andric           "not enough data to read binary id length");
113bdd1243dSDimitry Andric 
114bdd1243dSDimitry Andric     uint64_t BILen = 0;
115c9157d92SDimitry Andric     if (Endian == llvm::endianness::little)
116c9157d92SDimitry Andric       BILen =
117c9157d92SDimitry Andric           endian::readNext<uint64_t, llvm::endianness::little, unaligned>(BI);
118bdd1243dSDimitry Andric     else
119c9157d92SDimitry Andric       BILen = endian::readNext<uint64_t, llvm::endianness::big, unaligned>(BI);
120bdd1243dSDimitry Andric 
121bdd1243dSDimitry Andric     if (BILen == 0)
122bdd1243dSDimitry Andric       return make_error<InstrProfError>(instrprof_error::malformed,
123bdd1243dSDimitry Andric                                         "binary id length is 0");
124bdd1243dSDimitry Andric 
125bdd1243dSDimitry Andric     Remaining = BIEnd - BI;
126bdd1243dSDimitry Andric     // There should be enough left to read the binary id data.
127bdd1243dSDimitry Andric     if (Remaining < alignToPowerOf2(BILen, sizeof(uint64_t)))
128bdd1243dSDimitry Andric       return make_error<InstrProfError>(
129bdd1243dSDimitry Andric           instrprof_error::malformed, "not enough data to read binary id data");
130bdd1243dSDimitry Andric 
131bdd1243dSDimitry Andric     // Add binary id to the binary ids list.
132bdd1243dSDimitry Andric     BinaryIds.push_back(object::BuildID(BI, BI + BILen));
133bdd1243dSDimitry Andric 
134bdd1243dSDimitry Andric     // Increment by binary id data length, which aligned to the size of uint64.
135bdd1243dSDimitry Andric     BI += alignToPowerOf2(BILen, sizeof(uint64_t));
136bdd1243dSDimitry Andric     if (BI > End)
137bdd1243dSDimitry Andric       return make_error<InstrProfError>(
138bdd1243dSDimitry Andric           instrprof_error::malformed,
139bdd1243dSDimitry Andric           "binary id section is greater than buffer size");
140bdd1243dSDimitry Andric   }
141bdd1243dSDimitry Andric 
142bdd1243dSDimitry Andric   return Error::success();
143bdd1243dSDimitry Andric }
144bdd1243dSDimitry Andric 
145c9157d92SDimitry Andric static void
printBinaryIdsInternal(raw_ostream & OS,std::vector<llvm::object::BuildID> & BinaryIds)146c9157d92SDimitry Andric printBinaryIdsInternal(raw_ostream &OS,
147c9157d92SDimitry Andric                        std::vector<llvm::object::BuildID> &BinaryIds) {
148bdd1243dSDimitry Andric   OS << "Binary IDs: \n";
149bdd1243dSDimitry Andric   for (auto BI : BinaryIds) {
150bdd1243dSDimitry Andric     for (uint64_t I = 0; I < BI.size(); I++)
151bdd1243dSDimitry Andric       OS << format("%02x", BI[I]);
152bdd1243dSDimitry Andric     OS << "\n";
153bdd1243dSDimitry Andric   }
154bdd1243dSDimitry Andric }
155bdd1243dSDimitry Andric 
1560b57cec5SDimitry Andric Expected<std::unique_ptr<InstrProfReader>>
create(const Twine & Path,vfs::FileSystem & FS,const InstrProfCorrelator * Correlator,std::function<void (Error)> Warn)157fe013be4SDimitry Andric InstrProfReader::create(const Twine &Path, vfs::FileSystem &FS,
158c9157d92SDimitry Andric                         const InstrProfCorrelator *Correlator,
159c9157d92SDimitry Andric                         std::function<void(Error)> Warn) {
1600b57cec5SDimitry Andric   // Set up the buffer to read.
161fe013be4SDimitry Andric   auto BufferOrError = setupMemoryBuffer(Path, FS);
1620b57cec5SDimitry Andric   if (Error E = BufferOrError.takeError())
1630b57cec5SDimitry Andric     return std::move(E);
164c9157d92SDimitry Andric   return InstrProfReader::create(std::move(BufferOrError.get()), Correlator,
165c9157d92SDimitry Andric                                  Warn);
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric Expected<std::unique_ptr<InstrProfReader>>
create(std::unique_ptr<MemoryBuffer> Buffer,const InstrProfCorrelator * Correlator,std::function<void (Error)> Warn)1690eae32dcSDimitry Andric InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
170c9157d92SDimitry Andric                         const InstrProfCorrelator *Correlator,
171c9157d92SDimitry Andric                         std::function<void(Error)> Warn) {
1720b57cec5SDimitry Andric   if (Buffer->getBufferSize() == 0)
1730b57cec5SDimitry Andric     return make_error<InstrProfError>(instrprof_error::empty_raw_profile);
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric   std::unique_ptr<InstrProfReader> Result;
1760b57cec5SDimitry Andric   // Create the reader.
1770b57cec5SDimitry Andric   if (IndexedInstrProfReader::hasFormat(*Buffer))
1780b57cec5SDimitry Andric     Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
1790b57cec5SDimitry Andric   else if (RawInstrProfReader64::hasFormat(*Buffer))
180c9157d92SDimitry Andric     Result.reset(new RawInstrProfReader64(std::move(Buffer), Correlator, Warn));
1810b57cec5SDimitry Andric   else if (RawInstrProfReader32::hasFormat(*Buffer))
182c9157d92SDimitry Andric     Result.reset(new RawInstrProfReader32(std::move(Buffer), Correlator, Warn));
1830b57cec5SDimitry Andric   else if (TextInstrProfReader::hasFormat(*Buffer))
1840b57cec5SDimitry Andric     Result.reset(new TextInstrProfReader(std::move(Buffer)));
1850b57cec5SDimitry Andric   else
1860b57cec5SDimitry Andric     return make_error<InstrProfError>(instrprof_error::unrecognized_format);
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric   // Initialize the reader and return the result.
1890b57cec5SDimitry Andric   if (Error E = initializeReader(*Result))
1900b57cec5SDimitry Andric     return std::move(E);
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric   return std::move(Result);
1930b57cec5SDimitry Andric }
1940b57cec5SDimitry Andric 
1950b57cec5SDimitry Andric Expected<std::unique_ptr<IndexedInstrProfReader>>
create(const Twine & Path,vfs::FileSystem & FS,const Twine & RemappingPath)196fe013be4SDimitry Andric IndexedInstrProfReader::create(const Twine &Path, vfs::FileSystem &FS,
197fe013be4SDimitry Andric                                const Twine &RemappingPath) {
1980b57cec5SDimitry Andric   // Set up the buffer to read.
199fe013be4SDimitry Andric   auto BufferOrError = setupMemoryBuffer(Path, FS);
2000b57cec5SDimitry Andric   if (Error E = BufferOrError.takeError())
2010b57cec5SDimitry Andric     return std::move(E);
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric   // Set up the remapping buffer if requested.
2040b57cec5SDimitry Andric   std::unique_ptr<MemoryBuffer> RemappingBuffer;
2050b57cec5SDimitry Andric   std::string RemappingPathStr = RemappingPath.str();
2060b57cec5SDimitry Andric   if (!RemappingPathStr.empty()) {
207fe013be4SDimitry Andric     auto RemappingBufferOrError = setupMemoryBuffer(RemappingPathStr, FS);
2080b57cec5SDimitry Andric     if (Error E = RemappingBufferOrError.takeError())
2090b57cec5SDimitry Andric       return std::move(E);
2100b57cec5SDimitry Andric     RemappingBuffer = std::move(RemappingBufferOrError.get());
2110b57cec5SDimitry Andric   }
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric   return IndexedInstrProfReader::create(std::move(BufferOrError.get()),
2140b57cec5SDimitry Andric                                         std::move(RemappingBuffer));
2150b57cec5SDimitry Andric }
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric Expected<std::unique_ptr<IndexedInstrProfReader>>
create(std::unique_ptr<MemoryBuffer> Buffer,std::unique_ptr<MemoryBuffer> RemappingBuffer)2180b57cec5SDimitry Andric IndexedInstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
2190b57cec5SDimitry Andric                                std::unique_ptr<MemoryBuffer> RemappingBuffer) {
2200b57cec5SDimitry Andric   // Create the reader.
2210b57cec5SDimitry Andric   if (!IndexedInstrProfReader::hasFormat(*Buffer))
2220b57cec5SDimitry Andric     return make_error<InstrProfError>(instrprof_error::bad_magic);
2238bcb0991SDimitry Andric   auto Result = std::make_unique<IndexedInstrProfReader>(
2240b57cec5SDimitry Andric       std::move(Buffer), std::move(RemappingBuffer));
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric   // Initialize the reader and return the result.
2270b57cec5SDimitry Andric   if (Error E = initializeReader(*Result))
2280b57cec5SDimitry Andric     return std::move(E);
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric   return std::move(Result);
2310b57cec5SDimitry Andric }
2320b57cec5SDimitry Andric 
hasFormat(const MemoryBuffer & Buffer)2330b57cec5SDimitry Andric bool TextInstrProfReader::hasFormat(const MemoryBuffer &Buffer) {
2340b57cec5SDimitry Andric   // Verify that this really looks like plain ASCII text by checking a
2350b57cec5SDimitry Andric   // 'reasonable' number of characters (up to profile magic size).
2360b57cec5SDimitry Andric   size_t count = std::min(Buffer.getBufferSize(), sizeof(uint64_t));
2370b57cec5SDimitry Andric   StringRef buffer = Buffer.getBufferStart();
2380b57cec5SDimitry Andric   return count == 0 ||
2390b57cec5SDimitry Andric          std::all_of(buffer.begin(), buffer.begin() + count,
2405ffd83dbSDimitry Andric                      [](char c) { return isPrint(c) || isSpace(c); });
2410b57cec5SDimitry Andric }
2420b57cec5SDimitry Andric 
2430b57cec5SDimitry Andric // Read the profile variant flag from the header: ":FE" means this is a FE
2440b57cec5SDimitry Andric // generated profile. ":IR" means this is an IR level profile. Other strings
2450b57cec5SDimitry Andric // with a leading ':' will be reported an error format.
readHeader()2460b57cec5SDimitry Andric Error TextInstrProfReader::readHeader() {
2470b57cec5SDimitry Andric   Symtab.reset(new InstrProfSymtab());
248e8d8bef9SDimitry Andric 
249c9157d92SDimitry Andric   while (Line->starts_with(":")) {
250e8d8bef9SDimitry Andric     StringRef Str = Line->substr(1);
251fe6060f1SDimitry Andric     if (Str.equals_insensitive("ir"))
25281ad6265SDimitry Andric       ProfileKind |= InstrProfKind::IRInstrumentation;
253fe6060f1SDimitry Andric     else if (Str.equals_insensitive("fe"))
25481ad6265SDimitry Andric       ProfileKind |= InstrProfKind::FrontendInstrumentation;
255fe6060f1SDimitry Andric     else if (Str.equals_insensitive("csir")) {
25681ad6265SDimitry Andric       ProfileKind |= InstrProfKind::IRInstrumentation;
25781ad6265SDimitry Andric       ProfileKind |= InstrProfKind::ContextSensitive;
258fe6060f1SDimitry Andric     } else if (Str.equals_insensitive("entry_first"))
25981ad6265SDimitry Andric       ProfileKind |= InstrProfKind::FunctionEntryInstrumentation;
260fe6060f1SDimitry Andric     else if (Str.equals_insensitive("not_entry_first"))
26181ad6265SDimitry Andric       ProfileKind &= ~InstrProfKind::FunctionEntryInstrumentation;
262c9157d92SDimitry Andric     else if (Str.equals_insensitive("single_byte_coverage"))
263c9157d92SDimitry Andric       ProfileKind |= InstrProfKind::SingleByteCoverage;
264fe013be4SDimitry Andric     else if (Str.equals_insensitive("temporal_prof_traces")) {
265fe013be4SDimitry Andric       ProfileKind |= InstrProfKind::TemporalProfile;
266fe013be4SDimitry Andric       if (auto Err = readTemporalProfTraceData())
267fe013be4SDimitry Andric         return error(std::move(Err));
268fe013be4SDimitry Andric     } else
2690b57cec5SDimitry Andric       return error(instrprof_error::bad_header);
2700b57cec5SDimitry Andric     ++Line;
271e8d8bef9SDimitry Andric   }
2720b57cec5SDimitry Andric   return success();
2730b57cec5SDimitry Andric }
2740b57cec5SDimitry Andric 
275fe013be4SDimitry Andric /// Temporal profile trace data is stored in the header immediately after
276fe013be4SDimitry Andric /// ":temporal_prof_traces". The first integer is the number of traces, the
277fe013be4SDimitry Andric /// second integer is the stream size, then the following lines are the actual
278fe013be4SDimitry Andric /// traces which consist of a weight and a comma separated list of function
279fe013be4SDimitry Andric /// names.
readTemporalProfTraceData()280fe013be4SDimitry Andric Error TextInstrProfReader::readTemporalProfTraceData() {
281fe013be4SDimitry Andric   if ((++Line).is_at_end())
282fe013be4SDimitry Andric     return error(instrprof_error::eof);
283fe013be4SDimitry Andric 
284fe013be4SDimitry Andric   uint32_t NumTraces;
285fe013be4SDimitry Andric   if (Line->getAsInteger(0, NumTraces))
286fe013be4SDimitry Andric     return error(instrprof_error::malformed);
287fe013be4SDimitry Andric 
288fe013be4SDimitry Andric   if ((++Line).is_at_end())
289fe013be4SDimitry Andric     return error(instrprof_error::eof);
290fe013be4SDimitry Andric 
291fe013be4SDimitry Andric   if (Line->getAsInteger(0, TemporalProfTraceStreamSize))
292fe013be4SDimitry Andric     return error(instrprof_error::malformed);
293fe013be4SDimitry Andric 
294fe013be4SDimitry Andric   for (uint32_t i = 0; i < NumTraces; i++) {
295fe013be4SDimitry Andric     if ((++Line).is_at_end())
296fe013be4SDimitry Andric       return error(instrprof_error::eof);
297fe013be4SDimitry Andric 
298fe013be4SDimitry Andric     TemporalProfTraceTy Trace;
299fe013be4SDimitry Andric     if (Line->getAsInteger(0, Trace.Weight))
300fe013be4SDimitry Andric       return error(instrprof_error::malformed);
301fe013be4SDimitry Andric 
302fe013be4SDimitry Andric     if ((++Line).is_at_end())
303fe013be4SDimitry Andric       return error(instrprof_error::eof);
304fe013be4SDimitry Andric 
305fe013be4SDimitry Andric     SmallVector<StringRef> FuncNames;
306fe013be4SDimitry Andric     Line->split(FuncNames, ",", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
307fe013be4SDimitry Andric     for (auto &FuncName : FuncNames)
308fe013be4SDimitry Andric       Trace.FunctionNameRefs.push_back(
309fe013be4SDimitry Andric           IndexedInstrProf::ComputeHash(FuncName.trim()));
310fe013be4SDimitry Andric     TemporalProfTraces.push_back(std::move(Trace));
311fe013be4SDimitry Andric   }
312fe013be4SDimitry Andric   return success();
313fe013be4SDimitry Andric }
314fe013be4SDimitry Andric 
3150b57cec5SDimitry Andric Error
readValueProfileData(InstrProfRecord & Record)3160b57cec5SDimitry Andric TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) {
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric #define CHECK_LINE_END(Line)                                                   \
3190b57cec5SDimitry Andric   if (Line.is_at_end())                                                        \
3200b57cec5SDimitry Andric     return error(instrprof_error::truncated);
3210b57cec5SDimitry Andric #define READ_NUM(Str, Dst)                                                     \
3220b57cec5SDimitry Andric   if ((Str).getAsInteger(10, (Dst)))                                           \
3230b57cec5SDimitry Andric     return error(instrprof_error::malformed);
3240b57cec5SDimitry Andric #define VP_READ_ADVANCE(Val)                                                   \
3250b57cec5SDimitry Andric   CHECK_LINE_END(Line);                                                        \
3260b57cec5SDimitry Andric   uint32_t Val;                                                                \
3270b57cec5SDimitry Andric   READ_NUM((*Line), (Val));                                                    \
3280b57cec5SDimitry Andric   Line++;
3290b57cec5SDimitry Andric 
3300b57cec5SDimitry Andric   if (Line.is_at_end())
3310b57cec5SDimitry Andric     return success();
3320b57cec5SDimitry Andric 
3330b57cec5SDimitry Andric   uint32_t NumValueKinds;
3340b57cec5SDimitry Andric   if (Line->getAsInteger(10, NumValueKinds)) {
3350b57cec5SDimitry Andric     // No value profile data
3360b57cec5SDimitry Andric     return success();
3370b57cec5SDimitry Andric   }
3380b57cec5SDimitry Andric   if (NumValueKinds == 0 || NumValueKinds > IPVK_Last + 1)
339349cc55cSDimitry Andric     return error(instrprof_error::malformed,
340349cc55cSDimitry Andric                  "number of value kinds is invalid");
3410b57cec5SDimitry Andric   Line++;
3420b57cec5SDimitry Andric 
3430b57cec5SDimitry Andric   for (uint32_t VK = 0; VK < NumValueKinds; VK++) {
3440b57cec5SDimitry Andric     VP_READ_ADVANCE(ValueKind);
3450b57cec5SDimitry Andric     if (ValueKind > IPVK_Last)
346349cc55cSDimitry Andric       return error(instrprof_error::malformed, "value kind is invalid");
347349cc55cSDimitry Andric     ;
3480b57cec5SDimitry Andric     VP_READ_ADVANCE(NumValueSites);
3490b57cec5SDimitry Andric     if (!NumValueSites)
3500b57cec5SDimitry Andric       continue;
3510b57cec5SDimitry Andric 
3520b57cec5SDimitry Andric     Record.reserveSites(VK, NumValueSites);
3530b57cec5SDimitry Andric     for (uint32_t S = 0; S < NumValueSites; S++) {
3540b57cec5SDimitry Andric       VP_READ_ADVANCE(NumValueData);
3550b57cec5SDimitry Andric 
3560b57cec5SDimitry Andric       std::vector<InstrProfValueData> CurrentValues;
3570b57cec5SDimitry Andric       for (uint32_t V = 0; V < NumValueData; V++) {
3580b57cec5SDimitry Andric         CHECK_LINE_END(Line);
3590b57cec5SDimitry Andric         std::pair<StringRef, StringRef> VD = Line->rsplit(':');
3600b57cec5SDimitry Andric         uint64_t TakenCount, Value;
3610b57cec5SDimitry Andric         if (ValueKind == IPVK_IndirectCallTarget) {
3620b57cec5SDimitry Andric           if (InstrProfSymtab::isExternalSymbol(VD.first)) {
3630b57cec5SDimitry Andric             Value = 0;
3640b57cec5SDimitry Andric           } else {
3650b57cec5SDimitry Andric             if (Error E = Symtab->addFuncName(VD.first))
3660b57cec5SDimitry Andric               return E;
3670b57cec5SDimitry Andric             Value = IndexedInstrProf::ComputeHash(VD.first);
3680b57cec5SDimitry Andric           }
3690b57cec5SDimitry Andric         } else {
3700b57cec5SDimitry Andric           READ_NUM(VD.first, Value);
3710b57cec5SDimitry Andric         }
3720b57cec5SDimitry Andric         READ_NUM(VD.second, TakenCount);
3730b57cec5SDimitry Andric         CurrentValues.push_back({Value, TakenCount});
3740b57cec5SDimitry Andric         Line++;
3750b57cec5SDimitry Andric       }
3760b57cec5SDimitry Andric       Record.addValueData(ValueKind, S, CurrentValues.data(), NumValueData,
3770b57cec5SDimitry Andric                           nullptr);
3780b57cec5SDimitry Andric     }
3790b57cec5SDimitry Andric   }
3800b57cec5SDimitry Andric   return success();
3810b57cec5SDimitry Andric 
3820b57cec5SDimitry Andric #undef CHECK_LINE_END
3830b57cec5SDimitry Andric #undef READ_NUM
3840b57cec5SDimitry Andric #undef VP_READ_ADVANCE
3850b57cec5SDimitry Andric }
3860b57cec5SDimitry Andric 
readNextRecord(NamedInstrProfRecord & Record)3870b57cec5SDimitry Andric Error TextInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
3880b57cec5SDimitry Andric   // Skip empty lines and comments.
389c9157d92SDimitry Andric   while (!Line.is_at_end() && (Line->empty() || Line->starts_with("#")))
3900b57cec5SDimitry Andric     ++Line;
3910b57cec5SDimitry Andric   // If we hit EOF while looking for a name, we're done.
3920b57cec5SDimitry Andric   if (Line.is_at_end()) {
3930b57cec5SDimitry Andric     return error(instrprof_error::eof);
3940b57cec5SDimitry Andric   }
3950b57cec5SDimitry Andric 
3960b57cec5SDimitry Andric   // Read the function name.
3970b57cec5SDimitry Andric   Record.Name = *Line++;
3980b57cec5SDimitry Andric   if (Error E = Symtab->addFuncName(Record.Name))
3990b57cec5SDimitry Andric     return error(std::move(E));
4000b57cec5SDimitry Andric 
4010b57cec5SDimitry Andric   // Read the function hash.
4020b57cec5SDimitry Andric   if (Line.is_at_end())
4030b57cec5SDimitry Andric     return error(instrprof_error::truncated);
4040b57cec5SDimitry Andric   if ((Line++)->getAsInteger(0, Record.Hash))
405349cc55cSDimitry Andric     return error(instrprof_error::malformed,
406349cc55cSDimitry Andric                  "function hash is not a valid integer");
4070b57cec5SDimitry Andric 
4080b57cec5SDimitry Andric   // Read the number of counters.
4090b57cec5SDimitry Andric   uint64_t NumCounters;
4100b57cec5SDimitry Andric   if (Line.is_at_end())
4110b57cec5SDimitry Andric     return error(instrprof_error::truncated);
4120b57cec5SDimitry Andric   if ((Line++)->getAsInteger(10, NumCounters))
413349cc55cSDimitry Andric     return error(instrprof_error::malformed,
414349cc55cSDimitry Andric                  "number of counters is not a valid integer");
4150b57cec5SDimitry Andric   if (NumCounters == 0)
416349cc55cSDimitry Andric     return error(instrprof_error::malformed, "number of counters is zero");
4170b57cec5SDimitry Andric 
4180b57cec5SDimitry Andric   // Read each counter and fill our internal storage with the values.
4190b57cec5SDimitry Andric   Record.Clear();
4200b57cec5SDimitry Andric   Record.Counts.reserve(NumCounters);
4210b57cec5SDimitry Andric   for (uint64_t I = 0; I < NumCounters; ++I) {
4220b57cec5SDimitry Andric     if (Line.is_at_end())
4230b57cec5SDimitry Andric       return error(instrprof_error::truncated);
4240b57cec5SDimitry Andric     uint64_t Count;
4250b57cec5SDimitry Andric     if ((Line++)->getAsInteger(10, Count))
426349cc55cSDimitry Andric       return error(instrprof_error::malformed, "count is invalid");
4270b57cec5SDimitry Andric     Record.Counts.push_back(Count);
4280b57cec5SDimitry Andric   }
4290b57cec5SDimitry Andric 
430c9157d92SDimitry Andric   // Bitmap byte information is indicated with special character.
431c9157d92SDimitry Andric   if (Line->starts_with("$")) {
432c9157d92SDimitry Andric     Record.BitmapBytes.clear();
433c9157d92SDimitry Andric     // Read the number of bitmap bytes.
434c9157d92SDimitry Andric     uint64_t NumBitmapBytes;
435c9157d92SDimitry Andric     if ((Line++)->drop_front(1).trim().getAsInteger(0, NumBitmapBytes))
436c9157d92SDimitry Andric       return error(instrprof_error::malformed,
437c9157d92SDimitry Andric                    "number of bitmap bytes is not a valid integer");
438c9157d92SDimitry Andric     if (NumBitmapBytes != 0) {
439c9157d92SDimitry Andric       // Read each bitmap and fill our internal storage with the values.
440c9157d92SDimitry Andric       Record.BitmapBytes.reserve(NumBitmapBytes);
441c9157d92SDimitry Andric       for (uint8_t I = 0; I < NumBitmapBytes; ++I) {
442c9157d92SDimitry Andric         if (Line.is_at_end())
443c9157d92SDimitry Andric           return error(instrprof_error::truncated);
444c9157d92SDimitry Andric         uint8_t BitmapByte;
445c9157d92SDimitry Andric         if ((Line++)->getAsInteger(0, BitmapByte))
446c9157d92SDimitry Andric           return error(instrprof_error::malformed,
447c9157d92SDimitry Andric                        "bitmap byte is not a valid integer");
448c9157d92SDimitry Andric         Record.BitmapBytes.push_back(BitmapByte);
449c9157d92SDimitry Andric       }
450c9157d92SDimitry Andric     }
451c9157d92SDimitry Andric   }
452c9157d92SDimitry Andric 
4530b57cec5SDimitry Andric   // Check if value profile data exists and read it if so.
4540b57cec5SDimitry Andric   if (Error E = readValueProfileData(Record))
4550b57cec5SDimitry Andric     return error(std::move(E));
4560b57cec5SDimitry Andric 
4570b57cec5SDimitry Andric   return success();
4580b57cec5SDimitry Andric }
4590b57cec5SDimitry Andric 
4600b57cec5SDimitry Andric template <class IntPtrT>
getProfileKind() const4611fd87a68SDimitry Andric InstrProfKind RawInstrProfReader<IntPtrT>::getProfileKind() const {
4621fd87a68SDimitry Andric   return getProfileKindFromVersion(Version);
4631fd87a68SDimitry Andric }
4641fd87a68SDimitry Andric 
4651fd87a68SDimitry Andric template <class IntPtrT>
466fe013be4SDimitry Andric SmallVector<TemporalProfTraceTy> &
getTemporalProfTraces(std::optional<uint64_t> Weight)467fe013be4SDimitry Andric RawInstrProfReader<IntPtrT>::getTemporalProfTraces(
468fe013be4SDimitry Andric     std::optional<uint64_t> Weight) {
469fe013be4SDimitry Andric   if (TemporalProfTimestamps.empty()) {
470fe013be4SDimitry Andric     assert(TemporalProfTraces.empty());
471fe013be4SDimitry Andric     return TemporalProfTraces;
472fe013be4SDimitry Andric   }
473fe013be4SDimitry Andric   // Sort functions by their timestamps to build the trace.
474fe013be4SDimitry Andric   std::sort(TemporalProfTimestamps.begin(), TemporalProfTimestamps.end());
475fe013be4SDimitry Andric   TemporalProfTraceTy Trace;
476fe013be4SDimitry Andric   if (Weight)
477fe013be4SDimitry Andric     Trace.Weight = *Weight;
478fe013be4SDimitry Andric   for (auto &[TimestampValue, NameRef] : TemporalProfTimestamps)
479fe013be4SDimitry Andric     Trace.FunctionNameRefs.push_back(NameRef);
480fe013be4SDimitry Andric   TemporalProfTraces = {std::move(Trace)};
481fe013be4SDimitry Andric   return TemporalProfTraces;
482fe013be4SDimitry Andric }
483fe013be4SDimitry Andric 
484fe013be4SDimitry Andric template <class IntPtrT>
hasFormat(const MemoryBuffer & DataBuffer)4850b57cec5SDimitry Andric bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) {
4860b57cec5SDimitry Andric   if (DataBuffer.getBufferSize() < sizeof(uint64_t))
4870b57cec5SDimitry Andric     return false;
4880b57cec5SDimitry Andric   uint64_t Magic =
4890b57cec5SDimitry Andric     *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart());
4900b57cec5SDimitry Andric   return RawInstrProf::getMagic<IntPtrT>() == Magic ||
491c9157d92SDimitry Andric          llvm::byteswap(RawInstrProf::getMagic<IntPtrT>()) == Magic;
4920b57cec5SDimitry Andric }
4930b57cec5SDimitry Andric 
4940b57cec5SDimitry Andric template <class IntPtrT>
readHeader()4950b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readHeader() {
4960b57cec5SDimitry Andric   if (!hasFormat(*DataBuffer))
4970b57cec5SDimitry Andric     return error(instrprof_error::bad_magic);
4980b57cec5SDimitry Andric   if (DataBuffer->getBufferSize() < sizeof(RawInstrProf::Header))
4990b57cec5SDimitry Andric     return error(instrprof_error::bad_header);
5000b57cec5SDimitry Andric   auto *Header = reinterpret_cast<const RawInstrProf::Header *>(
5010b57cec5SDimitry Andric       DataBuffer->getBufferStart());
5020b57cec5SDimitry Andric   ShouldSwapBytes = Header->Magic != RawInstrProf::getMagic<IntPtrT>();
5030b57cec5SDimitry Andric   return readHeader(*Header);
5040b57cec5SDimitry Andric }
5050b57cec5SDimitry Andric 
5060b57cec5SDimitry Andric template <class IntPtrT>
readNextHeader(const char * CurrentPos)5070b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
5080b57cec5SDimitry Andric   const char *End = DataBuffer->getBufferEnd();
5090b57cec5SDimitry Andric   // Skip zero padding between profiles.
5100b57cec5SDimitry Andric   while (CurrentPos != End && *CurrentPos == 0)
5110b57cec5SDimitry Andric     ++CurrentPos;
5120b57cec5SDimitry Andric   // If there's nothing left, we're done.
5130b57cec5SDimitry Andric   if (CurrentPos == End)
5140b57cec5SDimitry Andric     return make_error<InstrProfError>(instrprof_error::eof);
5150b57cec5SDimitry Andric   // If there isn't enough space for another header, this is probably just
5160b57cec5SDimitry Andric   // garbage at the end of the file.
5170b57cec5SDimitry Andric   if (CurrentPos + sizeof(RawInstrProf::Header) > End)
518349cc55cSDimitry Andric     return make_error<InstrProfError>(instrprof_error::malformed,
519349cc55cSDimitry Andric                                       "not enough space for another header");
5200b57cec5SDimitry Andric   // The writer ensures each profile is padded to start at an aligned address.
5210b57cec5SDimitry Andric   if (reinterpret_cast<size_t>(CurrentPos) % alignof(uint64_t))
522349cc55cSDimitry Andric     return make_error<InstrProfError>(instrprof_error::malformed,
523349cc55cSDimitry Andric                                       "insufficient padding");
5240b57cec5SDimitry Andric   // The magic should have the same byte order as in the previous header.
5250b57cec5SDimitry Andric   uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos);
5260b57cec5SDimitry Andric   if (Magic != swap(RawInstrProf::getMagic<IntPtrT>()))
5270b57cec5SDimitry Andric     return make_error<InstrProfError>(instrprof_error::bad_magic);
5280b57cec5SDimitry Andric 
5290b57cec5SDimitry Andric   // There's another profile to read, so we need to process the header.
5300b57cec5SDimitry Andric   auto *Header = reinterpret_cast<const RawInstrProf::Header *>(CurrentPos);
5310b57cec5SDimitry Andric   return readHeader(*Header);
5320b57cec5SDimitry Andric }
5330b57cec5SDimitry Andric 
5340b57cec5SDimitry Andric template <class IntPtrT>
createSymtab(InstrProfSymtab & Symtab)5350b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) {
5360eae32dcSDimitry Andric   if (Error E = Symtab.create(StringRef(NamesStart, NamesEnd - NamesStart)))
5370b57cec5SDimitry Andric     return error(std::move(E));
5380b57cec5SDimitry Andric   for (const RawInstrProf::ProfileData<IntPtrT> *I = Data; I != DataEnd; ++I) {
5390b57cec5SDimitry Andric     const IntPtrT FPtr = swap(I->FunctionPointer);
5400b57cec5SDimitry Andric     if (!FPtr)
5410b57cec5SDimitry Andric       continue;
542*de8261c4SDimitry Andric     Symtab.mapAddress(FPtr, swap(I->NameRef));
5430b57cec5SDimitry Andric   }
5440b57cec5SDimitry Andric   return success();
5450b57cec5SDimitry Andric }
5460b57cec5SDimitry Andric 
5470b57cec5SDimitry Andric template <class IntPtrT>
readHeader(const RawInstrProf::Header & Header)5480b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readHeader(
5490b57cec5SDimitry Andric     const RawInstrProf::Header &Header) {
5500b57cec5SDimitry Andric   Version = swap(Header.Version);
5510b57cec5SDimitry Andric   if (GET_VERSION(Version) != RawInstrProf::Version)
552fe013be4SDimitry Andric     return error(instrprof_error::raw_profile_version_mismatch,
553fe013be4SDimitry Andric                  ("Profile uses raw profile format version = " +
554fe013be4SDimitry Andric                   Twine(GET_VERSION(Version)) +
555fe013be4SDimitry Andric                   "; expected version = " + Twine(RawInstrProf::Version) +
556fe013be4SDimitry Andric                   "\nPLEASE update this tool to version in the raw profile, or "
557fe013be4SDimitry Andric                   "regenerate raw profile with expected version.")
558fe013be4SDimitry Andric                      .str());
5590b57cec5SDimitry Andric 
560c9157d92SDimitry Andric   uint64_t BinaryIdSize = swap(Header.BinaryIdsSize);
561c9157d92SDimitry Andric   // Binary id start just after the header if exists.
562c9157d92SDimitry Andric   const uint8_t *BinaryIdStart =
563c9157d92SDimitry Andric       reinterpret_cast<const uint8_t *>(&Header) + sizeof(RawInstrProf::Header);
564c9157d92SDimitry Andric   const uint8_t *BinaryIdEnd = BinaryIdStart + BinaryIdSize;
565c9157d92SDimitry Andric   const uint8_t *BufferEnd = (const uint8_t *)DataBuffer->getBufferEnd();
566c9157d92SDimitry Andric   if (BinaryIdSize % sizeof(uint64_t) || BinaryIdEnd > BufferEnd)
567349cc55cSDimitry Andric     return error(instrprof_error::bad_header);
568c9157d92SDimitry Andric   if (BinaryIdSize != 0) {
569c9157d92SDimitry Andric     if (Error Err =
570c9157d92SDimitry Andric             readBinaryIdsInternal(*DataBuffer, BinaryIdSize, BinaryIdStart,
571c9157d92SDimitry Andric                                   BinaryIds, getDataEndianness()))
572c9157d92SDimitry Andric       return Err;
573c9157d92SDimitry Andric   }
574349cc55cSDimitry Andric 
5750b57cec5SDimitry Andric   CountersDelta = swap(Header.CountersDelta);
576c9157d92SDimitry Andric   BitmapDelta = swap(Header.BitmapDelta);
5770b57cec5SDimitry Andric   NamesDelta = swap(Header.NamesDelta);
578c9157d92SDimitry Andric   auto NumData = swap(Header.NumData);
579480093f4SDimitry Andric   auto PaddingBytesBeforeCounters = swap(Header.PaddingBytesBeforeCounters);
580c9157d92SDimitry Andric   auto CountersSize = swap(Header.NumCounters) * getCounterTypeSize();
581480093f4SDimitry Andric   auto PaddingBytesAfterCounters = swap(Header.PaddingBytesAfterCounters);
582c9157d92SDimitry Andric   auto NumBitmapBytes = swap(Header.NumBitmapBytes);
583c9157d92SDimitry Andric   auto PaddingBytesAfterBitmapBytes = swap(Header.PaddingBytesAfterBitmapBytes);
5840eae32dcSDimitry Andric   auto NamesSize = swap(Header.NamesSize);
5850b57cec5SDimitry Andric   ValueKindLast = swap(Header.ValueKindLast);
5860b57cec5SDimitry Andric 
58704eeddc0SDimitry Andric   auto DataSize = NumData * sizeof(RawInstrProf::ProfileData<IntPtrT>);
5880b57cec5SDimitry Andric   auto PaddingSize = getNumPaddingBytes(NamesSize);
5890b57cec5SDimitry Andric 
590fe6060f1SDimitry Andric   // Profile data starts after profile header and binary ids if exist.
591c9157d92SDimitry Andric   ptrdiff_t DataOffset = sizeof(RawInstrProf::Header) + BinaryIdSize;
59204eeddc0SDimitry Andric   ptrdiff_t CountersOffset = DataOffset + DataSize + PaddingBytesBeforeCounters;
593c9157d92SDimitry Andric   ptrdiff_t BitmapOffset =
59404eeddc0SDimitry Andric       CountersOffset + CountersSize + PaddingBytesAfterCounters;
595c9157d92SDimitry Andric   ptrdiff_t NamesOffset =
596c9157d92SDimitry Andric       BitmapOffset + NumBitmapBytes + PaddingBytesAfterBitmapBytes;
5970b57cec5SDimitry Andric   ptrdiff_t ValueDataOffset = NamesOffset + NamesSize + PaddingSize;
5980b57cec5SDimitry Andric 
5990b57cec5SDimitry Andric   auto *Start = reinterpret_cast<const char *>(&Header);
6000b57cec5SDimitry Andric   if (Start + ValueDataOffset > DataBuffer->getBufferEnd())
6010b57cec5SDimitry Andric     return error(instrprof_error::bad_header);
6020b57cec5SDimitry Andric 
6030eae32dcSDimitry Andric   if (Correlator) {
6040eae32dcSDimitry Andric     // These sizes in the raw file are zero because we constructed them in the
6050eae32dcSDimitry Andric     // Correlator.
606c9157d92SDimitry Andric     if (!(DataSize == 0 && NamesSize == 0 && CountersDelta == 0 &&
607c9157d92SDimitry Andric           NamesDelta == 0))
608c9157d92SDimitry Andric       return error(instrprof_error::unexpected_correlation_info);
6090eae32dcSDimitry Andric     Data = Correlator->getDataPointer();
6100eae32dcSDimitry Andric     DataEnd = Data + Correlator->getDataSize();
61104eeddc0SDimitry Andric     NamesStart = Correlator->getNamesPointer();
61204eeddc0SDimitry Andric     NamesEnd = NamesStart + Correlator->getNamesSize();
6130eae32dcSDimitry Andric   } else {
6140b57cec5SDimitry Andric     Data = reinterpret_cast<const RawInstrProf::ProfileData<IntPtrT> *>(
6150b57cec5SDimitry Andric         Start + DataOffset);
61604eeddc0SDimitry Andric     DataEnd = Data + NumData;
6170eae32dcSDimitry Andric     NamesStart = Start + NamesOffset;
6180eae32dcSDimitry Andric     NamesEnd = NamesStart + NamesSize;
6190eae32dcSDimitry Andric   }
620fe6060f1SDimitry Andric 
62104eeddc0SDimitry Andric   CountersStart = Start + CountersOffset;
62204eeddc0SDimitry Andric   CountersEnd = CountersStart + CountersSize;
623c9157d92SDimitry Andric   BitmapStart = Start + BitmapOffset;
624c9157d92SDimitry Andric   BitmapEnd = BitmapStart + NumBitmapBytes;
6250b57cec5SDimitry Andric   ValueDataStart = reinterpret_cast<const uint8_t *>(Start + ValueDataOffset);
6260b57cec5SDimitry Andric 
6278bcb0991SDimitry Andric   std::unique_ptr<InstrProfSymtab> NewSymtab = std::make_unique<InstrProfSymtab>();
62881ad6265SDimitry Andric   if (Error E = createSymtab(*NewSymtab))
6290b57cec5SDimitry Andric     return E;
6300b57cec5SDimitry Andric 
6310b57cec5SDimitry Andric   Symtab = std::move(NewSymtab);
6320b57cec5SDimitry Andric   return success();
6330b57cec5SDimitry Andric }
6340b57cec5SDimitry Andric 
6350b57cec5SDimitry Andric template <class IntPtrT>
readName(NamedInstrProfRecord & Record)6360b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readName(NamedInstrProfRecord &Record) {
6370b57cec5SDimitry Andric   Record.Name = getName(Data->NameRef);
6380b57cec5SDimitry Andric   return success();
6390b57cec5SDimitry Andric }
6400b57cec5SDimitry Andric 
6410b57cec5SDimitry Andric template <class IntPtrT>
readFuncHash(NamedInstrProfRecord & Record)6420b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readFuncHash(NamedInstrProfRecord &Record) {
6430b57cec5SDimitry Andric   Record.Hash = swap(Data->FuncHash);
6440b57cec5SDimitry Andric   return success();
6450b57cec5SDimitry Andric }
6460b57cec5SDimitry Andric 
6470b57cec5SDimitry Andric template <class IntPtrT>
readRawCounts(InstrProfRecord & Record)6480b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readRawCounts(
6490b57cec5SDimitry Andric     InstrProfRecord &Record) {
6500b57cec5SDimitry Andric   uint32_t NumCounters = swap(Data->NumCounters);
6510b57cec5SDimitry Andric   if (NumCounters == 0)
652349cc55cSDimitry Andric     return error(instrprof_error::malformed, "number of counters is zero");
6530b57cec5SDimitry Andric 
65404eeddc0SDimitry Andric   ptrdiff_t CounterBaseOffset = swap(Data->CounterPtr) - CountersDelta;
65504eeddc0SDimitry Andric   if (CounterBaseOffset < 0)
656349cc55cSDimitry Andric     return error(
657349cc55cSDimitry Andric         instrprof_error::malformed,
65804eeddc0SDimitry Andric         ("counter offset " + Twine(CounterBaseOffset) + " is negative").str());
659349cc55cSDimitry Andric 
66004eeddc0SDimitry Andric   if (CounterBaseOffset >= CountersEnd - CountersStart)
6610eae32dcSDimitry Andric     return error(instrprof_error::malformed,
66204eeddc0SDimitry Andric                  ("counter offset " + Twine(CounterBaseOffset) +
66304eeddc0SDimitry Andric                   " is greater than the maximum counter offset " +
66404eeddc0SDimitry Andric                   Twine(CountersEnd - CountersStart - 1))
665349cc55cSDimitry Andric                      .str());
666349cc55cSDimitry Andric 
66704eeddc0SDimitry Andric   uint64_t MaxNumCounters =
66804eeddc0SDimitry Andric       (CountersEnd - (CountersStart + CounterBaseOffset)) /
66904eeddc0SDimitry Andric       getCounterTypeSize();
67004eeddc0SDimitry Andric   if (NumCounters > MaxNumCounters)
671349cc55cSDimitry Andric     return error(instrprof_error::malformed,
67204eeddc0SDimitry Andric                  ("number of counters " + Twine(NumCounters) +
673349cc55cSDimitry Andric                   " is greater than the maximum number of counters " +
67404eeddc0SDimitry Andric                   Twine(MaxNumCounters))
675349cc55cSDimitry Andric                      .str());
6768bcb0991SDimitry Andric 
6770b57cec5SDimitry Andric   Record.Counts.clear();
67804eeddc0SDimitry Andric   Record.Counts.reserve(NumCounters);
67904eeddc0SDimitry Andric   for (uint32_t I = 0; I < NumCounters; I++) {
6801fd87a68SDimitry Andric     const char *Ptr =
6811fd87a68SDimitry Andric         CountersStart + CounterBaseOffset + I * getCounterTypeSize();
682fe013be4SDimitry Andric     if (I == 0 && hasTemporalProfile()) {
683fe013be4SDimitry Andric       uint64_t TimestampValue = swap(*reinterpret_cast<const uint64_t *>(Ptr));
684fe013be4SDimitry Andric       if (TimestampValue != 0 &&
685fe013be4SDimitry Andric           TimestampValue != std::numeric_limits<uint64_t>::max()) {
686fe013be4SDimitry Andric         TemporalProfTimestamps.emplace_back(TimestampValue,
687fe013be4SDimitry Andric                                             swap(Data->NameRef));
688fe013be4SDimitry Andric         TemporalProfTraceStreamSize = 1;
689fe013be4SDimitry Andric       }
690fe013be4SDimitry Andric       if (hasSingleByteCoverage()) {
691fe013be4SDimitry Andric         // In coverage mode, getCounterTypeSize() returns 1 byte but our
692fe013be4SDimitry Andric         // timestamp field has size uint64_t. Increment I so that the next
693fe013be4SDimitry Andric         // iteration of this for loop points to the byte after the timestamp
694fe013be4SDimitry Andric         // field, i.e., I += 8.
695fe013be4SDimitry Andric         I += 7;
696fe013be4SDimitry Andric       }
697fe013be4SDimitry Andric       continue;
698fe013be4SDimitry Andric     }
6991fd87a68SDimitry Andric     if (hasSingleByteCoverage()) {
7001fd87a68SDimitry Andric       // A value of zero signifies the block is covered.
7011fd87a68SDimitry Andric       Record.Counts.push_back(*Ptr == 0 ? 1 : 0);
7021fd87a68SDimitry Andric     } else {
703c9157d92SDimitry Andric       uint64_t CounterValue = swap(*reinterpret_cast<const uint64_t *>(Ptr));
704c9157d92SDimitry Andric       if (CounterValue > MaxCounterValue && Warn)
705c9157d92SDimitry Andric         Warn(make_error<InstrProfError>(
706c9157d92SDimitry Andric             instrprof_error::counter_value_too_large, Twine(CounterValue)));
707c9157d92SDimitry Andric 
708c9157d92SDimitry Andric       Record.Counts.push_back(CounterValue);
70904eeddc0SDimitry Andric     }
7101fd87a68SDimitry Andric   }
7110b57cec5SDimitry Andric 
7120b57cec5SDimitry Andric   return success();
7130b57cec5SDimitry Andric }
7140b57cec5SDimitry Andric 
7150b57cec5SDimitry Andric template <class IntPtrT>
readRawBitmapBytes(InstrProfRecord & Record)716c9157d92SDimitry Andric Error RawInstrProfReader<IntPtrT>::readRawBitmapBytes(InstrProfRecord &Record) {
717c9157d92SDimitry Andric   uint32_t NumBitmapBytes = swap(Data->NumBitmapBytes);
718c9157d92SDimitry Andric 
719c9157d92SDimitry Andric   Record.BitmapBytes.clear();
720c9157d92SDimitry Andric   Record.BitmapBytes.reserve(NumBitmapBytes);
721c9157d92SDimitry Andric 
722c9157d92SDimitry Andric   // It's possible MCDC is either not enabled or only used for some functions
723c9157d92SDimitry Andric   // and not others. So if we record 0 bytes, just move on.
724c9157d92SDimitry Andric   if (NumBitmapBytes == 0)
725c9157d92SDimitry Andric     return success();
726c9157d92SDimitry Andric 
727c9157d92SDimitry Andric   // BitmapDelta decreases as we advance to the next data record.
728c9157d92SDimitry Andric   ptrdiff_t BitmapOffset = swap(Data->BitmapPtr) - BitmapDelta;
729c9157d92SDimitry Andric   if (BitmapOffset < 0)
730c9157d92SDimitry Andric     return error(
731c9157d92SDimitry Andric         instrprof_error::malformed,
732c9157d92SDimitry Andric         ("bitmap offset " + Twine(BitmapOffset) + " is negative").str());
733c9157d92SDimitry Andric 
734c9157d92SDimitry Andric   if (BitmapOffset >= BitmapEnd - BitmapStart)
735c9157d92SDimitry Andric     return error(instrprof_error::malformed,
736c9157d92SDimitry Andric                  ("bitmap offset " + Twine(BitmapOffset) +
737c9157d92SDimitry Andric                   " is greater than the maximum bitmap offset " +
738c9157d92SDimitry Andric                   Twine(BitmapEnd - BitmapStart - 1))
739c9157d92SDimitry Andric                      .str());
740c9157d92SDimitry Andric 
741c9157d92SDimitry Andric   uint64_t MaxNumBitmapBytes =
742c9157d92SDimitry Andric       (BitmapEnd - (BitmapStart + BitmapOffset)) / sizeof(uint8_t);
743c9157d92SDimitry Andric   if (NumBitmapBytes > MaxNumBitmapBytes)
744c9157d92SDimitry Andric     return error(instrprof_error::malformed,
745c9157d92SDimitry Andric                  ("number of bitmap bytes " + Twine(NumBitmapBytes) +
746c9157d92SDimitry Andric                   " is greater than the maximum number of bitmap bytes " +
747c9157d92SDimitry Andric                   Twine(MaxNumBitmapBytes))
748c9157d92SDimitry Andric                      .str());
749c9157d92SDimitry Andric 
750c9157d92SDimitry Andric   for (uint32_t I = 0; I < NumBitmapBytes; I++) {
751c9157d92SDimitry Andric     const char *Ptr = BitmapStart + BitmapOffset + I;
752c9157d92SDimitry Andric     Record.BitmapBytes.push_back(swap(*Ptr));
753c9157d92SDimitry Andric   }
754c9157d92SDimitry Andric 
755c9157d92SDimitry Andric   return success();
756c9157d92SDimitry Andric }
757c9157d92SDimitry Andric 
758c9157d92SDimitry Andric template <class IntPtrT>
readValueProfilingData(InstrProfRecord & Record)7590b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readValueProfilingData(
7600b57cec5SDimitry Andric     InstrProfRecord &Record) {
7610b57cec5SDimitry Andric   Record.clearValueData();
7620b57cec5SDimitry Andric   CurValueDataSize = 0;
7630b57cec5SDimitry Andric   // Need to match the logic in value profile dumper code in compiler-rt:
7640b57cec5SDimitry Andric   uint32_t NumValueKinds = 0;
7650b57cec5SDimitry Andric   for (uint32_t I = 0; I < IPVK_Last + 1; I++)
7660b57cec5SDimitry Andric     NumValueKinds += (Data->NumValueSites[I] != 0);
7670b57cec5SDimitry Andric 
7680b57cec5SDimitry Andric   if (!NumValueKinds)
7690b57cec5SDimitry Andric     return success();
7700b57cec5SDimitry Andric 
7710b57cec5SDimitry Andric   Expected<std::unique_ptr<ValueProfData>> VDataPtrOrErr =
7720b57cec5SDimitry Andric       ValueProfData::getValueProfData(
7730b57cec5SDimitry Andric           ValueDataStart, (const unsigned char *)DataBuffer->getBufferEnd(),
7740b57cec5SDimitry Andric           getDataEndianness());
7750b57cec5SDimitry Andric 
7760b57cec5SDimitry Andric   if (Error E = VDataPtrOrErr.takeError())
7770b57cec5SDimitry Andric     return E;
7780b57cec5SDimitry Andric 
7790b57cec5SDimitry Andric   // Note that besides deserialization, this also performs the conversion for
7800b57cec5SDimitry Andric   // indirect call targets.  The function pointers from the raw profile are
7810b57cec5SDimitry Andric   // remapped into function name hashes.
7820b57cec5SDimitry Andric   VDataPtrOrErr.get()->deserializeTo(Record, Symtab.get());
7830b57cec5SDimitry Andric   CurValueDataSize = VDataPtrOrErr.get()->getSize();
7840b57cec5SDimitry Andric   return success();
7850b57cec5SDimitry Andric }
7860b57cec5SDimitry Andric 
7870b57cec5SDimitry Andric template <class IntPtrT>
readNextRecord(NamedInstrProfRecord & Record)7880b57cec5SDimitry Andric Error RawInstrProfReader<IntPtrT>::readNextRecord(NamedInstrProfRecord &Record) {
789bdd1243dSDimitry Andric   // Keep reading profiles that consist of only headers and no profile data and
790bdd1243dSDimitry Andric   // counters.
791bdd1243dSDimitry Andric   while (atEnd())
7920b57cec5SDimitry Andric     // At this point, ValueDataStart field points to the next header.
7930b57cec5SDimitry Andric     if (Error E = readNextHeader(getNextHeaderPos()))
7940b57cec5SDimitry Andric       return error(std::move(E));
7950b57cec5SDimitry Andric 
796fe013be4SDimitry Andric   // Read name and set it in Record.
7970b57cec5SDimitry Andric   if (Error E = readName(Record))
7980b57cec5SDimitry Andric     return error(std::move(E));
7990b57cec5SDimitry Andric 
8000b57cec5SDimitry Andric   // Read FuncHash and set it in Record.
8010b57cec5SDimitry Andric   if (Error E = readFuncHash(Record))
8020b57cec5SDimitry Andric     return error(std::move(E));
8030b57cec5SDimitry Andric 
8040b57cec5SDimitry Andric   // Read raw counts and set Record.
8050b57cec5SDimitry Andric   if (Error E = readRawCounts(Record))
8060b57cec5SDimitry Andric     return error(std::move(E));
8070b57cec5SDimitry Andric 
808c9157d92SDimitry Andric   // Read raw bitmap bytes and set Record.
809c9157d92SDimitry Andric   if (Error E = readRawBitmapBytes(Record))
810c9157d92SDimitry Andric     return error(std::move(E));
811c9157d92SDimitry Andric 
8120b57cec5SDimitry Andric   // Read value data and set Record.
8130b57cec5SDimitry Andric   if (Error E = readValueProfilingData(Record))
8140b57cec5SDimitry Andric     return error(std::move(E));
8150b57cec5SDimitry Andric 
8160b57cec5SDimitry Andric   // Iterate.
8170b57cec5SDimitry Andric   advanceData();
8180b57cec5SDimitry Andric   return success();
8190b57cec5SDimitry Andric }
8200b57cec5SDimitry Andric 
821bdd1243dSDimitry Andric template <class IntPtrT>
readBinaryIds(std::vector<llvm::object::BuildID> & BinaryIds)822bdd1243dSDimitry Andric Error RawInstrProfReader<IntPtrT>::readBinaryIds(
823bdd1243dSDimitry Andric     std::vector<llvm::object::BuildID> &BinaryIds) {
824c9157d92SDimitry Andric   BinaryIds.insert(BinaryIds.begin(), this->BinaryIds.begin(),
825c9157d92SDimitry Andric                    this->BinaryIds.end());
826c9157d92SDimitry Andric   return Error::success();
827349cc55cSDimitry Andric }
828349cc55cSDimitry Andric 
829fe6060f1SDimitry Andric template <class IntPtrT>
printBinaryIds(raw_ostream & OS)830fe6060f1SDimitry Andric Error RawInstrProfReader<IntPtrT>::printBinaryIds(raw_ostream &OS) {
831c9157d92SDimitry Andric   if (!BinaryIds.empty())
832c9157d92SDimitry Andric     printBinaryIdsInternal(OS, BinaryIds);
833c9157d92SDimitry Andric   return Error::success();
834fe6060f1SDimitry Andric }
835fe6060f1SDimitry Andric 
8360b57cec5SDimitry Andric namespace llvm {
8370b57cec5SDimitry Andric 
8380b57cec5SDimitry Andric template class RawInstrProfReader<uint32_t>;
8390b57cec5SDimitry Andric template class RawInstrProfReader<uint64_t>;
8400b57cec5SDimitry Andric 
8410b57cec5SDimitry Andric } // end namespace llvm
8420b57cec5SDimitry Andric 
8430b57cec5SDimitry Andric InstrProfLookupTrait::hash_value_type
ComputeHash(StringRef K)8440b57cec5SDimitry Andric InstrProfLookupTrait::ComputeHash(StringRef K) {
8450b57cec5SDimitry Andric   return IndexedInstrProf::ComputeHash(HashType, K);
8460b57cec5SDimitry Andric }
8470b57cec5SDimitry Andric 
8480b57cec5SDimitry Andric using data_type = InstrProfLookupTrait::data_type;
8490b57cec5SDimitry Andric using offset_type = InstrProfLookupTrait::offset_type;
8500b57cec5SDimitry Andric 
readValueProfilingData(const unsigned char * & D,const unsigned char * const End)8510b57cec5SDimitry Andric bool InstrProfLookupTrait::readValueProfilingData(
8520b57cec5SDimitry Andric     const unsigned char *&D, const unsigned char *const End) {
8530b57cec5SDimitry Andric   Expected<std::unique_ptr<ValueProfData>> VDataPtrOrErr =
8540b57cec5SDimitry Andric       ValueProfData::getValueProfData(D, End, ValueProfDataEndianness);
8550b57cec5SDimitry Andric 
8560b57cec5SDimitry Andric   if (VDataPtrOrErr.takeError())
8570b57cec5SDimitry Andric     return false;
8580b57cec5SDimitry Andric 
8590b57cec5SDimitry Andric   VDataPtrOrErr.get()->deserializeTo(DataBuffer.back(), nullptr);
8600b57cec5SDimitry Andric   D += VDataPtrOrErr.get()->TotalSize;
8610b57cec5SDimitry Andric 
8620b57cec5SDimitry Andric   return true;
8630b57cec5SDimitry Andric }
8640b57cec5SDimitry Andric 
ReadData(StringRef K,const unsigned char * D,offset_type N)8650b57cec5SDimitry Andric data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D,
8660b57cec5SDimitry Andric                                          offset_type N) {
8670b57cec5SDimitry Andric   using namespace support;
8680b57cec5SDimitry Andric 
8690b57cec5SDimitry Andric   // Check if the data is corrupt. If so, don't try to read it.
8700b57cec5SDimitry Andric   if (N % sizeof(uint64_t))
8710b57cec5SDimitry Andric     return data_type();
8720b57cec5SDimitry Andric 
8730b57cec5SDimitry Andric   DataBuffer.clear();
8740b57cec5SDimitry Andric   std::vector<uint64_t> CounterBuffer;
875c9157d92SDimitry Andric   std::vector<uint8_t> BitmapByteBuffer;
8760b57cec5SDimitry Andric 
8770b57cec5SDimitry Andric   const unsigned char *End = D + N;
8780b57cec5SDimitry Andric   while (D < End) {
8790b57cec5SDimitry Andric     // Read hash.
8800b57cec5SDimitry Andric     if (D + sizeof(uint64_t) >= End)
8810b57cec5SDimitry Andric       return data_type();
882c9157d92SDimitry Andric     uint64_t Hash =
883c9157d92SDimitry Andric         endian::readNext<uint64_t, llvm::endianness::little, unaligned>(D);
8840b57cec5SDimitry Andric 
8850b57cec5SDimitry Andric     // Initialize number of counters for GET_VERSION(FormatVersion) == 1.
8860b57cec5SDimitry Andric     uint64_t CountsSize = N / sizeof(uint64_t) - 1;
8870b57cec5SDimitry Andric     // If format version is different then read the number of counters.
8880b57cec5SDimitry Andric     if (GET_VERSION(FormatVersion) != IndexedInstrProf::ProfVersion::Version1) {
8890b57cec5SDimitry Andric       if (D + sizeof(uint64_t) > End)
8900b57cec5SDimitry Andric         return data_type();
891c9157d92SDimitry Andric       CountsSize =
892c9157d92SDimitry Andric           endian::readNext<uint64_t, llvm::endianness::little, unaligned>(D);
8930b57cec5SDimitry Andric     }
8940b57cec5SDimitry Andric     // Read counter values.
8950b57cec5SDimitry Andric     if (D + CountsSize * sizeof(uint64_t) > End)
8960b57cec5SDimitry Andric       return data_type();
8970b57cec5SDimitry Andric 
8980b57cec5SDimitry Andric     CounterBuffer.clear();
8990b57cec5SDimitry Andric     CounterBuffer.reserve(CountsSize);
9000b57cec5SDimitry Andric     for (uint64_t J = 0; J < CountsSize; ++J)
901c9157d92SDimitry Andric       CounterBuffer.push_back(
902c9157d92SDimitry Andric           endian::readNext<uint64_t, llvm::endianness::little, unaligned>(D));
9030b57cec5SDimitry Andric 
904c9157d92SDimitry Andric     // Read bitmap bytes for GET_VERSION(FormatVersion) > 10.
905c9157d92SDimitry Andric     if (GET_VERSION(FormatVersion) > IndexedInstrProf::ProfVersion::Version10) {
906c9157d92SDimitry Andric       uint64_t BitmapBytes = 0;
907c9157d92SDimitry Andric       if (D + sizeof(uint64_t) > End)
908c9157d92SDimitry Andric         return data_type();
909c9157d92SDimitry Andric       BitmapBytes =
910c9157d92SDimitry Andric           endian::readNext<uint64_t, llvm::endianness::little, unaligned>(D);
911c9157d92SDimitry Andric       // Read bitmap byte values.
912c9157d92SDimitry Andric       if (D + BitmapBytes * sizeof(uint8_t) > End)
913c9157d92SDimitry Andric         return data_type();
914c9157d92SDimitry Andric       BitmapByteBuffer.clear();
915c9157d92SDimitry Andric       BitmapByteBuffer.reserve(BitmapBytes);
916c9157d92SDimitry Andric       for (uint64_t J = 0; J < BitmapBytes; ++J)
917c9157d92SDimitry Andric         BitmapByteBuffer.push_back(static_cast<uint8_t>(
918c9157d92SDimitry Andric             endian::readNext<uint64_t, llvm::endianness::little, unaligned>(
919c9157d92SDimitry Andric                 D)));
920c9157d92SDimitry Andric     }
921c9157d92SDimitry Andric 
922c9157d92SDimitry Andric     DataBuffer.emplace_back(K, Hash, std::move(CounterBuffer),
923c9157d92SDimitry Andric                             std::move(BitmapByteBuffer));
9240b57cec5SDimitry Andric 
9250b57cec5SDimitry Andric     // Read value profiling data.
9260b57cec5SDimitry Andric     if (GET_VERSION(FormatVersion) > IndexedInstrProf::ProfVersion::Version2 &&
9270b57cec5SDimitry Andric         !readValueProfilingData(D, End)) {
9280b57cec5SDimitry Andric       DataBuffer.clear();
9290b57cec5SDimitry Andric       return data_type();
9300b57cec5SDimitry Andric     }
9310b57cec5SDimitry Andric   }
9320b57cec5SDimitry Andric   return DataBuffer;
9330b57cec5SDimitry Andric }
9340b57cec5SDimitry Andric 
9350b57cec5SDimitry Andric template <typename HashTableImpl>
getRecords(StringRef FuncName,ArrayRef<NamedInstrProfRecord> & Data)9360b57cec5SDimitry Andric Error InstrProfReaderIndex<HashTableImpl>::getRecords(
9370b57cec5SDimitry Andric     StringRef FuncName, ArrayRef<NamedInstrProfRecord> &Data) {
9380b57cec5SDimitry Andric   auto Iter = HashTable->find(FuncName);
9390b57cec5SDimitry Andric   if (Iter == HashTable->end())
9400b57cec5SDimitry Andric     return make_error<InstrProfError>(instrprof_error::unknown_function);
9410b57cec5SDimitry Andric 
9420b57cec5SDimitry Andric   Data = (*Iter);
9430b57cec5SDimitry Andric   if (Data.empty())
944349cc55cSDimitry Andric     return make_error<InstrProfError>(instrprof_error::malformed,
945349cc55cSDimitry Andric                                       "profile data is empty");
9460b57cec5SDimitry Andric 
9470b57cec5SDimitry Andric   return Error::success();
9480b57cec5SDimitry Andric }
9490b57cec5SDimitry Andric 
9500b57cec5SDimitry Andric template <typename HashTableImpl>
getRecords(ArrayRef<NamedInstrProfRecord> & Data)9510b57cec5SDimitry Andric Error InstrProfReaderIndex<HashTableImpl>::getRecords(
9520b57cec5SDimitry Andric     ArrayRef<NamedInstrProfRecord> &Data) {
9530b57cec5SDimitry Andric   if (atEnd())
9540b57cec5SDimitry Andric     return make_error<InstrProfError>(instrprof_error::eof);
9550b57cec5SDimitry Andric 
9560b57cec5SDimitry Andric   Data = *RecordIterator;
9570b57cec5SDimitry Andric 
9580b57cec5SDimitry Andric   if (Data.empty())
959349cc55cSDimitry Andric     return make_error<InstrProfError>(instrprof_error::malformed,
960349cc55cSDimitry Andric                                       "profile data is empty");
9610b57cec5SDimitry Andric 
9620b57cec5SDimitry Andric   return Error::success();
9630b57cec5SDimitry Andric }
9640b57cec5SDimitry Andric 
9650b57cec5SDimitry Andric template <typename HashTableImpl>
InstrProfReaderIndex(const unsigned char * Buckets,const unsigned char * const Payload,const unsigned char * const Base,IndexedInstrProf::HashT HashType,uint64_t Version)9660b57cec5SDimitry Andric InstrProfReaderIndex<HashTableImpl>::InstrProfReaderIndex(
9670b57cec5SDimitry Andric     const unsigned char *Buckets, const unsigned char *const Payload,
9680b57cec5SDimitry Andric     const unsigned char *const Base, IndexedInstrProf::HashT HashType,
9690b57cec5SDimitry Andric     uint64_t Version) {
9700b57cec5SDimitry Andric   FormatVersion = Version;
9710b57cec5SDimitry Andric   HashTable.reset(HashTableImpl::Create(
9720b57cec5SDimitry Andric       Buckets, Payload, Base,
9730b57cec5SDimitry Andric       typename HashTableImpl::InfoType(HashType, Version)));
9740b57cec5SDimitry Andric   RecordIterator = HashTable->data_begin();
9750b57cec5SDimitry Andric }
9760b57cec5SDimitry Andric 
9771fd87a68SDimitry Andric template <typename HashTableImpl>
getProfileKind() const9781fd87a68SDimitry Andric InstrProfKind InstrProfReaderIndex<HashTableImpl>::getProfileKind() const {
9791fd87a68SDimitry Andric   return getProfileKindFromVersion(FormatVersion);
9801fd87a68SDimitry Andric }
9811fd87a68SDimitry Andric 
9820b57cec5SDimitry Andric namespace {
9830b57cec5SDimitry Andric /// A remapper that does not apply any remappings.
9840b57cec5SDimitry Andric class InstrProfReaderNullRemapper : public InstrProfReaderRemapper {
9850b57cec5SDimitry Andric   InstrProfReaderIndexBase &Underlying;
9860b57cec5SDimitry Andric 
9870b57cec5SDimitry Andric public:
InstrProfReaderNullRemapper(InstrProfReaderIndexBase & Underlying)9880b57cec5SDimitry Andric   InstrProfReaderNullRemapper(InstrProfReaderIndexBase &Underlying)
9890b57cec5SDimitry Andric       : Underlying(Underlying) {}
9900b57cec5SDimitry Andric 
getRecords(StringRef FuncName,ArrayRef<NamedInstrProfRecord> & Data)9910b57cec5SDimitry Andric   Error getRecords(StringRef FuncName,
9920b57cec5SDimitry Andric                    ArrayRef<NamedInstrProfRecord> &Data) override {
9930b57cec5SDimitry Andric     return Underlying.getRecords(FuncName, Data);
9940b57cec5SDimitry Andric   }
9950b57cec5SDimitry Andric };
996349cc55cSDimitry Andric } // namespace
9970b57cec5SDimitry Andric 
9980b57cec5SDimitry Andric /// A remapper that applies remappings based on a symbol remapping file.
9990b57cec5SDimitry Andric template <typename HashTableImpl>
10000b57cec5SDimitry Andric class llvm::InstrProfReaderItaniumRemapper
10010b57cec5SDimitry Andric     : public InstrProfReaderRemapper {
10020b57cec5SDimitry Andric public:
InstrProfReaderItaniumRemapper(std::unique_ptr<MemoryBuffer> RemapBuffer,InstrProfReaderIndex<HashTableImpl> & Underlying)10030b57cec5SDimitry Andric   InstrProfReaderItaniumRemapper(
10040b57cec5SDimitry Andric       std::unique_ptr<MemoryBuffer> RemapBuffer,
10050b57cec5SDimitry Andric       InstrProfReaderIndex<HashTableImpl> &Underlying)
10060b57cec5SDimitry Andric       : RemapBuffer(std::move(RemapBuffer)), Underlying(Underlying) {
10070b57cec5SDimitry Andric   }
10080b57cec5SDimitry Andric 
10090b57cec5SDimitry Andric   /// Extract the original function name from a PGO function name.
extractName(StringRef Name)10100b57cec5SDimitry Andric   static StringRef extractName(StringRef Name) {
1011e710425bSDimitry Andric     // We can have multiple pieces separated by kGlobalIdentifierDelimiter (
1012e710425bSDimitry Andric     // semicolon now and colon in older profiles); there can be pieces both
1013e710425bSDimitry Andric     // before and after the mangled name. Find the first part that starts with
1014e710425bSDimitry Andric     // '_Z'; we'll assume that's the mangled name we want.
10150b57cec5SDimitry Andric     std::pair<StringRef, StringRef> Parts = {StringRef(), Name};
10160b57cec5SDimitry Andric     while (true) {
1017e710425bSDimitry Andric       Parts = Parts.second.split(kGlobalIdentifierDelimiter);
1018c9157d92SDimitry Andric       if (Parts.first.starts_with("_Z"))
10190b57cec5SDimitry Andric         return Parts.first;
10200b57cec5SDimitry Andric       if (Parts.second.empty())
10210b57cec5SDimitry Andric         return Name;
10220b57cec5SDimitry Andric     }
10230b57cec5SDimitry Andric   }
10240b57cec5SDimitry Andric 
10250b57cec5SDimitry Andric   /// Given a mangled name extracted from a PGO function name, and a new
10260b57cec5SDimitry Andric   /// form for that mangled name, reconstitute the name.
reconstituteName(StringRef OrigName,StringRef ExtractedName,StringRef Replacement,SmallVectorImpl<char> & Out)10270b57cec5SDimitry Andric   static void reconstituteName(StringRef OrigName, StringRef ExtractedName,
10280b57cec5SDimitry Andric                                StringRef Replacement,
10290b57cec5SDimitry Andric                                SmallVectorImpl<char> &Out) {
10300b57cec5SDimitry Andric     Out.reserve(OrigName.size() + Replacement.size() - ExtractedName.size());
10310b57cec5SDimitry Andric     Out.insert(Out.end(), OrigName.begin(), ExtractedName.begin());
10320b57cec5SDimitry Andric     Out.insert(Out.end(), Replacement.begin(), Replacement.end());
10330b57cec5SDimitry Andric     Out.insert(Out.end(), ExtractedName.end(), OrigName.end());
10340b57cec5SDimitry Andric   }
10350b57cec5SDimitry Andric 
populateRemappings()10360b57cec5SDimitry Andric   Error populateRemappings() override {
10370b57cec5SDimitry Andric     if (Error E = Remappings.read(*RemapBuffer))
10380b57cec5SDimitry Andric       return E;
10390b57cec5SDimitry Andric     for (StringRef Name : Underlying.HashTable->keys()) {
10400b57cec5SDimitry Andric       StringRef RealName = extractName(Name);
10410b57cec5SDimitry Andric       if (auto Key = Remappings.insert(RealName)) {
10420b57cec5SDimitry Andric         // FIXME: We could theoretically map the same equivalence class to
10430b57cec5SDimitry Andric         // multiple names in the profile data. If that happens, we should
10440b57cec5SDimitry Andric         // return NamedInstrProfRecords from all of them.
10450b57cec5SDimitry Andric         MappedNames.insert({Key, RealName});
10460b57cec5SDimitry Andric       }
10470b57cec5SDimitry Andric     }
10480b57cec5SDimitry Andric     return Error::success();
10490b57cec5SDimitry Andric   }
10500b57cec5SDimitry Andric 
getRecords(StringRef FuncName,ArrayRef<NamedInstrProfRecord> & Data)10510b57cec5SDimitry Andric   Error getRecords(StringRef FuncName,
10520b57cec5SDimitry Andric                    ArrayRef<NamedInstrProfRecord> &Data) override {
10530b57cec5SDimitry Andric     StringRef RealName = extractName(FuncName);
10540b57cec5SDimitry Andric     if (auto Key = Remappings.lookup(RealName)) {
10550b57cec5SDimitry Andric       StringRef Remapped = MappedNames.lookup(Key);
10560b57cec5SDimitry Andric       if (!Remapped.empty()) {
10570b57cec5SDimitry Andric         if (RealName.begin() == FuncName.begin() &&
10580b57cec5SDimitry Andric             RealName.end() == FuncName.end())
10590b57cec5SDimitry Andric           FuncName = Remapped;
10600b57cec5SDimitry Andric         else {
10610b57cec5SDimitry Andric           // Try rebuilding the name from the given remapping.
10620b57cec5SDimitry Andric           SmallString<256> Reconstituted;
10630b57cec5SDimitry Andric           reconstituteName(FuncName, RealName, Remapped, Reconstituted);
10640b57cec5SDimitry Andric           Error E = Underlying.getRecords(Reconstituted, Data);
10650b57cec5SDimitry Andric           if (!E)
10660b57cec5SDimitry Andric             return E;
10670b57cec5SDimitry Andric 
10680b57cec5SDimitry Andric           // If we failed because the name doesn't exist, fall back to asking
10690b57cec5SDimitry Andric           // about the original name.
10700b57cec5SDimitry Andric           if (Error Unhandled = handleErrors(
10710b57cec5SDimitry Andric                   std::move(E), [](std::unique_ptr<InstrProfError> Err) {
10720b57cec5SDimitry Andric                     return Err->get() == instrprof_error::unknown_function
10730b57cec5SDimitry Andric                                ? Error::success()
10740b57cec5SDimitry Andric                                : Error(std::move(Err));
10750b57cec5SDimitry Andric                   }))
10760b57cec5SDimitry Andric             return Unhandled;
10770b57cec5SDimitry Andric         }
10780b57cec5SDimitry Andric       }
10790b57cec5SDimitry Andric     }
10800b57cec5SDimitry Andric     return Underlying.getRecords(FuncName, Data);
10810b57cec5SDimitry Andric   }
10820b57cec5SDimitry Andric 
10830b57cec5SDimitry Andric private:
10840b57cec5SDimitry Andric   /// The memory buffer containing the remapping configuration. Remappings
10850b57cec5SDimitry Andric   /// holds pointers into this buffer.
10860b57cec5SDimitry Andric   std::unique_ptr<MemoryBuffer> RemapBuffer;
10870b57cec5SDimitry Andric 
10880b57cec5SDimitry Andric   /// The mangling remapper.
10890b57cec5SDimitry Andric   SymbolRemappingReader Remappings;
10900b57cec5SDimitry Andric 
10910b57cec5SDimitry Andric   /// Mapping from mangled name keys to the name used for the key in the
10920b57cec5SDimitry Andric   /// profile data.
10930b57cec5SDimitry Andric   /// FIXME: Can we store a location within the on-disk hash table instead of
10940b57cec5SDimitry Andric   /// redoing lookup?
10950b57cec5SDimitry Andric   DenseMap<SymbolRemappingReader::Key, StringRef> MappedNames;
10960b57cec5SDimitry Andric 
10970b57cec5SDimitry Andric   /// The real profile data reader.
10980b57cec5SDimitry Andric   InstrProfReaderIndex<HashTableImpl> &Underlying;
10990b57cec5SDimitry Andric };
11000b57cec5SDimitry Andric 
hasFormat(const MemoryBuffer & DataBuffer)11010b57cec5SDimitry Andric bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) {
11020b57cec5SDimitry Andric   using namespace support;
11030b57cec5SDimitry Andric 
11040b57cec5SDimitry Andric   if (DataBuffer.getBufferSize() < 8)
11050b57cec5SDimitry Andric     return false;
1106c9157d92SDimitry Andric   uint64_t Magic = endian::read<uint64_t, llvm::endianness::little, aligned>(
1107c9157d92SDimitry Andric       DataBuffer.getBufferStart());
11080b57cec5SDimitry Andric   // Verify that it's magical.
11090b57cec5SDimitry Andric   return Magic == IndexedInstrProf::Magic;
11100b57cec5SDimitry Andric }
11110b57cec5SDimitry Andric 
11120b57cec5SDimitry Andric const unsigned char *
readSummary(IndexedInstrProf::ProfVersion Version,const unsigned char * Cur,bool UseCS)11130b57cec5SDimitry Andric IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version,
11140b57cec5SDimitry Andric                                     const unsigned char *Cur, bool UseCS) {
11150b57cec5SDimitry Andric   using namespace IndexedInstrProf;
11160b57cec5SDimitry Andric   using namespace support;
11170b57cec5SDimitry Andric 
11180b57cec5SDimitry Andric   if (Version >= IndexedInstrProf::Version4) {
11190b57cec5SDimitry Andric     const IndexedInstrProf::Summary *SummaryInLE =
11200b57cec5SDimitry Andric         reinterpret_cast<const IndexedInstrProf::Summary *>(Cur);
1121c9157d92SDimitry Andric     uint64_t NFields = endian::byte_swap<uint64_t, llvm::endianness::little>(
1122c9157d92SDimitry Andric         SummaryInLE->NumSummaryFields);
1123c9157d92SDimitry Andric     uint64_t NEntries = endian::byte_swap<uint64_t, llvm::endianness::little>(
1124c9157d92SDimitry Andric         SummaryInLE->NumCutoffEntries);
11250b57cec5SDimitry Andric     uint32_t SummarySize =
11260b57cec5SDimitry Andric         IndexedInstrProf::Summary::getSize(NFields, NEntries);
11270b57cec5SDimitry Andric     std::unique_ptr<IndexedInstrProf::Summary> SummaryData =
11280b57cec5SDimitry Andric         IndexedInstrProf::allocSummary(SummarySize);
11290b57cec5SDimitry Andric 
11300b57cec5SDimitry Andric     const uint64_t *Src = reinterpret_cast<const uint64_t *>(SummaryInLE);
11310b57cec5SDimitry Andric     uint64_t *Dst = reinterpret_cast<uint64_t *>(SummaryData.get());
11320b57cec5SDimitry Andric     for (unsigned I = 0; I < SummarySize / sizeof(uint64_t); I++)
1133c9157d92SDimitry Andric       Dst[I] = endian::byte_swap<uint64_t, llvm::endianness::little>(Src[I]);
11340b57cec5SDimitry Andric 
11350b57cec5SDimitry Andric     SummaryEntryVector DetailedSummary;
11360b57cec5SDimitry Andric     for (unsigned I = 0; I < SummaryData->NumCutoffEntries; I++) {
11370b57cec5SDimitry Andric       const IndexedInstrProf::Summary::Entry &Ent = SummaryData->getEntry(I);
11380b57cec5SDimitry Andric       DetailedSummary.emplace_back((uint32_t)Ent.Cutoff, Ent.MinBlockCount,
11390b57cec5SDimitry Andric                                    Ent.NumBlocks);
11400b57cec5SDimitry Andric     }
11410b57cec5SDimitry Andric     std::unique_ptr<llvm::ProfileSummary> &Summary =
11420b57cec5SDimitry Andric         UseCS ? this->CS_Summary : this->Summary;
11430b57cec5SDimitry Andric 
11440b57cec5SDimitry Andric     // initialize InstrProfSummary using the SummaryData from disk.
11458bcb0991SDimitry Andric     Summary = std::make_unique<ProfileSummary>(
11460b57cec5SDimitry Andric         UseCS ? ProfileSummary::PSK_CSInstr : ProfileSummary::PSK_Instr,
11470b57cec5SDimitry Andric         DetailedSummary, SummaryData->get(Summary::TotalBlockCount),
11480b57cec5SDimitry Andric         SummaryData->get(Summary::MaxBlockCount),
11490b57cec5SDimitry Andric         SummaryData->get(Summary::MaxInternalBlockCount),
11500b57cec5SDimitry Andric         SummaryData->get(Summary::MaxFunctionCount),
11510b57cec5SDimitry Andric         SummaryData->get(Summary::TotalNumBlocks),
11520b57cec5SDimitry Andric         SummaryData->get(Summary::TotalNumFunctions));
11530b57cec5SDimitry Andric     return Cur + SummarySize;
11540b57cec5SDimitry Andric   } else {
11558bcb0991SDimitry Andric     // The older versions do not support a profile summary. This just computes
11568bcb0991SDimitry Andric     // an empty summary, which will not result in accurate hot/cold detection.
11578bcb0991SDimitry Andric     // We would need to call addRecord for all NamedInstrProfRecords to get the
11588bcb0991SDimitry Andric     // correct summary. However, this version is old (prior to early 2016) and
11598bcb0991SDimitry Andric     // has not been supporting an accurate summary for several years.
11600b57cec5SDimitry Andric     InstrProfSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
11618bcb0991SDimitry Andric     Summary = Builder.getSummary();
11620b57cec5SDimitry Andric     return Cur;
11630b57cec5SDimitry Andric   }
11640b57cec5SDimitry Andric }
11650b57cec5SDimitry Andric 
readHeader()11660b57cec5SDimitry Andric Error IndexedInstrProfReader::readHeader() {
11670b57cec5SDimitry Andric   using namespace support;
11680b57cec5SDimitry Andric 
11690b57cec5SDimitry Andric   const unsigned char *Start =
11700b57cec5SDimitry Andric       (const unsigned char *)DataBuffer->getBufferStart();
11710b57cec5SDimitry Andric   const unsigned char *Cur = Start;
11720b57cec5SDimitry Andric   if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24)
11730b57cec5SDimitry Andric     return error(instrprof_error::truncated);
11740b57cec5SDimitry Andric 
117581ad6265SDimitry Andric   auto HeaderOr = IndexedInstrProf::Header::readFromBuffer(Start);
117681ad6265SDimitry Andric   if (!HeaderOr)
117781ad6265SDimitry Andric     return HeaderOr.takeError();
11780b57cec5SDimitry Andric 
117981ad6265SDimitry Andric   const IndexedInstrProf::Header *Header = &HeaderOr.get();
118081ad6265SDimitry Andric   Cur += Header->size();
11810b57cec5SDimitry Andric 
118281ad6265SDimitry Andric   Cur = readSummary((IndexedInstrProf::ProfVersion)Header->formatVersion(), Cur,
11830b57cec5SDimitry Andric                     /* UseCS */ false);
118481ad6265SDimitry Andric   if (Header->formatVersion() & VARIANT_MASK_CSIR_PROF)
1185bdd1243dSDimitry Andric     Cur =
1186bdd1243dSDimitry Andric         readSummary((IndexedInstrProf::ProfVersion)Header->formatVersion(), Cur,
11870b57cec5SDimitry Andric                     /* UseCS */ true);
11880b57cec5SDimitry Andric   // Read the hash type and start offset.
11890b57cec5SDimitry Andric   IndexedInstrProf::HashT HashType = static_cast<IndexedInstrProf::HashT>(
1190c9157d92SDimitry Andric       endian::byte_swap<uint64_t, llvm::endianness::little>(Header->HashType));
11910b57cec5SDimitry Andric   if (HashType > IndexedInstrProf::HashT::Last)
11920b57cec5SDimitry Andric     return error(instrprof_error::unsupported_hash_type);
11930b57cec5SDimitry Andric 
1194c9157d92SDimitry Andric   uint64_t HashOffset =
1195c9157d92SDimitry Andric       endian::byte_swap<uint64_t, llvm::endianness::little>(Header->HashOffset);
11960b57cec5SDimitry Andric 
119781ad6265SDimitry Andric   // The hash table with profile counts comes next.
119881ad6265SDimitry Andric   auto IndexPtr = std::make_unique<InstrProfReaderIndex<OnDiskHashTableImplV3>>(
119981ad6265SDimitry Andric       Start + HashOffset, Cur, Start, HashType, Header->formatVersion());
120081ad6265SDimitry Andric 
1201bdd1243dSDimitry Andric   // The MemProfOffset field in the header is only valid when the format
1202bdd1243dSDimitry Andric   // version is higher than 8 (when it was introduced).
120381ad6265SDimitry Andric   if (GET_VERSION(Header->formatVersion()) >= 8 &&
120481ad6265SDimitry Andric       Header->formatVersion() & VARIANT_MASK_MEMPROF) {
120581ad6265SDimitry Andric     uint64_t MemProfOffset =
1206c9157d92SDimitry Andric         endian::byte_swap<uint64_t, llvm::endianness::little>(
1207c9157d92SDimitry Andric             Header->MemProfOffset);
120881ad6265SDimitry Andric 
120981ad6265SDimitry Andric     const unsigned char *Ptr = Start + MemProfOffset;
121081ad6265SDimitry Andric     // The value returned from RecordTableGenerator.Emit.
121181ad6265SDimitry Andric     const uint64_t RecordTableOffset =
1212c9157d92SDimitry Andric         support::endian::readNext<uint64_t, llvm::endianness::little,
1213c9157d92SDimitry Andric                                   unaligned>(Ptr);
1214bdd1243dSDimitry Andric     // The offset in the stream right before invoking
1215bdd1243dSDimitry Andric     // FrameTableGenerator.Emit.
121681ad6265SDimitry Andric     const uint64_t FramePayloadOffset =
1217c9157d92SDimitry Andric         support::endian::readNext<uint64_t, llvm::endianness::little,
1218c9157d92SDimitry Andric                                   unaligned>(Ptr);
121981ad6265SDimitry Andric     // The value returned from FrameTableGenerator.Emit.
122081ad6265SDimitry Andric     const uint64_t FrameTableOffset =
1221c9157d92SDimitry Andric         support::endian::readNext<uint64_t, llvm::endianness::little,
1222c9157d92SDimitry Andric                                   unaligned>(Ptr);
122381ad6265SDimitry Andric 
122481ad6265SDimitry Andric     // Read the schema.
122581ad6265SDimitry Andric     auto SchemaOr = memprof::readMemProfSchema(Ptr);
122681ad6265SDimitry Andric     if (!SchemaOr)
122781ad6265SDimitry Andric       return SchemaOr.takeError();
122881ad6265SDimitry Andric     Schema = SchemaOr.get();
122981ad6265SDimitry Andric 
123081ad6265SDimitry Andric     // Now initialize the table reader with a pointer into data buffer.
123181ad6265SDimitry Andric     MemProfRecordTable.reset(MemProfRecordHashTable::Create(
123281ad6265SDimitry Andric         /*Buckets=*/Start + RecordTableOffset,
123381ad6265SDimitry Andric         /*Payload=*/Ptr,
123481ad6265SDimitry Andric         /*Base=*/Start, memprof::RecordLookupTrait(Schema)));
123581ad6265SDimitry Andric 
123681ad6265SDimitry Andric     // Initialize the frame table reader with the payload and bucket offsets.
123781ad6265SDimitry Andric     MemProfFrameTable.reset(MemProfFrameHashTable::Create(
123881ad6265SDimitry Andric         /*Buckets=*/Start + FrameTableOffset,
123981ad6265SDimitry Andric         /*Payload=*/Start + FramePayloadOffset,
124081ad6265SDimitry Andric         /*Base=*/Start, memprof::FrameLookupTrait()));
124181ad6265SDimitry Andric   }
12420b57cec5SDimitry Andric 
1243bdd1243dSDimitry Andric   // BinaryIdOffset field in the header is only valid when the format version
1244bdd1243dSDimitry Andric   // is higher than 9 (when it was introduced).
1245bdd1243dSDimitry Andric   if (GET_VERSION(Header->formatVersion()) >= 9) {
1246bdd1243dSDimitry Andric     uint64_t BinaryIdOffset =
1247c9157d92SDimitry Andric         endian::byte_swap<uint64_t, llvm::endianness::little>(
1248c9157d92SDimitry Andric             Header->BinaryIdOffset);
1249bdd1243dSDimitry Andric     const unsigned char *Ptr = Start + BinaryIdOffset;
1250bdd1243dSDimitry Andric     // Read binary ids size.
1251c9157d92SDimitry Andric     BinaryIdsSize =
1252c9157d92SDimitry Andric         support::endian::readNext<uint64_t, llvm::endianness::little,
1253c9157d92SDimitry Andric                                   unaligned>(Ptr);
1254bdd1243dSDimitry Andric     if (BinaryIdsSize % sizeof(uint64_t))
1255bdd1243dSDimitry Andric       return error(instrprof_error::bad_header);
1256bdd1243dSDimitry Andric     // Set the binary ids start.
1257bdd1243dSDimitry Andric     BinaryIdsStart = Ptr;
1258bdd1243dSDimitry Andric     if (BinaryIdsStart > (const unsigned char *)DataBuffer->getBufferEnd())
1259bdd1243dSDimitry Andric       return make_error<InstrProfError>(instrprof_error::malformed,
1260bdd1243dSDimitry Andric                                         "corrupted binary ids");
1261bdd1243dSDimitry Andric   }
1262bdd1243dSDimitry Andric 
1263fe013be4SDimitry Andric   if (GET_VERSION(Header->formatVersion()) >= 10 &&
1264fe013be4SDimitry Andric       Header->formatVersion() & VARIANT_MASK_TEMPORAL_PROF) {
1265fe013be4SDimitry Andric     uint64_t TemporalProfTracesOffset =
1266c9157d92SDimitry Andric         endian::byte_swap<uint64_t, llvm::endianness::little>(
1267c9157d92SDimitry Andric             Header->TemporalProfTracesOffset);
1268fe013be4SDimitry Andric     const unsigned char *Ptr = Start + TemporalProfTracesOffset;
1269fe013be4SDimitry Andric     const auto *PtrEnd = (const unsigned char *)DataBuffer->getBufferEnd();
1270fe013be4SDimitry Andric     // Expect at least two 64 bit fields: NumTraces, and TraceStreamSize
1271fe013be4SDimitry Andric     if (Ptr + 2 * sizeof(uint64_t) > PtrEnd)
1272fe013be4SDimitry Andric       return error(instrprof_error::truncated);
1273fe013be4SDimitry Andric     const uint64_t NumTraces =
1274c9157d92SDimitry Andric         support::endian::readNext<uint64_t, llvm::endianness::little,
1275c9157d92SDimitry Andric                                   unaligned>(Ptr);
1276fe013be4SDimitry Andric     TemporalProfTraceStreamSize =
1277c9157d92SDimitry Andric         support::endian::readNext<uint64_t, llvm::endianness::little,
1278c9157d92SDimitry Andric                                   unaligned>(Ptr);
1279fe013be4SDimitry Andric     for (unsigned i = 0; i < NumTraces; i++) {
1280fe013be4SDimitry Andric       // Expect at least two 64 bit fields: Weight and NumFunctions
1281fe013be4SDimitry Andric       if (Ptr + 2 * sizeof(uint64_t) > PtrEnd)
1282fe013be4SDimitry Andric         return error(instrprof_error::truncated);
1283fe013be4SDimitry Andric       TemporalProfTraceTy Trace;
1284fe013be4SDimitry Andric       Trace.Weight =
1285c9157d92SDimitry Andric           support::endian::readNext<uint64_t, llvm::endianness::little,
1286c9157d92SDimitry Andric                                     unaligned>(Ptr);
1287fe013be4SDimitry Andric       const uint64_t NumFunctions =
1288c9157d92SDimitry Andric           support::endian::readNext<uint64_t, llvm::endianness::little,
1289c9157d92SDimitry Andric                                     unaligned>(Ptr);
1290fe013be4SDimitry Andric       // Expect at least NumFunctions 64 bit fields
1291fe013be4SDimitry Andric       if (Ptr + NumFunctions * sizeof(uint64_t) > PtrEnd)
1292fe013be4SDimitry Andric         return error(instrprof_error::truncated);
1293fe013be4SDimitry Andric       for (unsigned j = 0; j < NumFunctions; j++) {
1294fe013be4SDimitry Andric         const uint64_t NameRef =
1295c9157d92SDimitry Andric             support::endian::readNext<uint64_t, llvm::endianness::little,
1296c9157d92SDimitry Andric                                       unaligned>(Ptr);
1297fe013be4SDimitry Andric         Trace.FunctionNameRefs.push_back(NameRef);
1298fe013be4SDimitry Andric       }
1299fe013be4SDimitry Andric       TemporalProfTraces.push_back(std::move(Trace));
1300fe013be4SDimitry Andric     }
1301fe013be4SDimitry Andric   }
1302fe013be4SDimitry Andric 
13030b57cec5SDimitry Andric   // Load the remapping table now if requested.
13040b57cec5SDimitry Andric   if (RemappingBuffer) {
1305bdd1243dSDimitry Andric     Remapper =
1306bdd1243dSDimitry Andric         std::make_unique<InstrProfReaderItaniumRemapper<OnDiskHashTableImplV3>>(
13070b57cec5SDimitry Andric             std::move(RemappingBuffer), *IndexPtr);
13080b57cec5SDimitry Andric     if (Error E = Remapper->populateRemappings())
13090b57cec5SDimitry Andric       return E;
13100b57cec5SDimitry Andric   } else {
13118bcb0991SDimitry Andric     Remapper = std::make_unique<InstrProfReaderNullRemapper>(*IndexPtr);
13120b57cec5SDimitry Andric   }
13130b57cec5SDimitry Andric   Index = std::move(IndexPtr);
13140b57cec5SDimitry Andric 
13150b57cec5SDimitry Andric   return success();
13160b57cec5SDimitry Andric }
13170b57cec5SDimitry Andric 
getSymtab()13180b57cec5SDimitry Andric InstrProfSymtab &IndexedInstrProfReader::getSymtab() {
131981ad6265SDimitry Andric   if (Symtab)
132081ad6265SDimitry Andric     return *Symtab;
13210b57cec5SDimitry Andric 
13228bcb0991SDimitry Andric   std::unique_ptr<InstrProfSymtab> NewSymtab = std::make_unique<InstrProfSymtab>();
132381ad6265SDimitry Andric   if (Error E = Index->populateSymtab(*NewSymtab)) {
1324fe013be4SDimitry Andric     auto [ErrCode, Msg] = InstrProfError::take(std::move(E));
1325fe013be4SDimitry Andric     consumeError(error(ErrCode, Msg));
13260b57cec5SDimitry Andric   }
13270b57cec5SDimitry Andric 
13280b57cec5SDimitry Andric   Symtab = std::move(NewSymtab);
132981ad6265SDimitry Andric   return *Symtab;
13300b57cec5SDimitry Andric }
13310b57cec5SDimitry Andric 
getInstrProfRecord(StringRef FuncName,uint64_t FuncHash,StringRef DeprecatedFuncName,uint64_t * MismatchedFuncSum)1332fcaf7f86SDimitry Andric Expected<InstrProfRecord> IndexedInstrProfReader::getInstrProfRecord(
1333c9157d92SDimitry Andric     StringRef FuncName, uint64_t FuncHash, StringRef DeprecatedFuncName,
1334c9157d92SDimitry Andric     uint64_t *MismatchedFuncSum) {
13350b57cec5SDimitry Andric   ArrayRef<NamedInstrProfRecord> Data;
1336fcaf7f86SDimitry Andric   uint64_t FuncSum = 0;
1337c9157d92SDimitry Andric   auto Err = Remapper->getRecords(FuncName, Data);
1338c9157d92SDimitry Andric   if (Err) {
1339c9157d92SDimitry Andric     // If we don't find FuncName, try DeprecatedFuncName to handle profiles
1340c9157d92SDimitry Andric     // built by older compilers.
1341c9157d92SDimitry Andric     auto Err2 =
1342c9157d92SDimitry Andric         handleErrors(std::move(Err), [&](const InstrProfError &IE) -> Error {
1343c9157d92SDimitry Andric           if (IE.get() != instrprof_error::unknown_function)
1344c9157d92SDimitry Andric             return make_error<InstrProfError>(IE);
1345c9157d92SDimitry Andric           if (auto Err = Remapper->getRecords(DeprecatedFuncName, Data))
1346c9157d92SDimitry Andric             return Err;
1347c9157d92SDimitry Andric           return Error::success();
1348c9157d92SDimitry Andric         });
1349c9157d92SDimitry Andric     if (Err2)
1350c9157d92SDimitry Andric       return std::move(Err2);
1351c9157d92SDimitry Andric   }
13520b57cec5SDimitry Andric   // Found it. Look for counters with the right hash.
1353fcaf7f86SDimitry Andric 
1354fcaf7f86SDimitry Andric   // A flag to indicate if the records are from the same type
1355fcaf7f86SDimitry Andric   // of profile (i.e cs vs nocs).
1356fcaf7f86SDimitry Andric   bool CSBitMatch = false;
1357fcaf7f86SDimitry Andric   auto getFuncSum = [](const std::vector<uint64_t> &Counts) {
1358fcaf7f86SDimitry Andric     uint64_t ValueSum = 0;
1359bdd1243dSDimitry Andric     for (uint64_t CountValue : Counts) {
1360fcaf7f86SDimitry Andric       if (CountValue == (uint64_t)-1)
1361fcaf7f86SDimitry Andric         continue;
1362fcaf7f86SDimitry Andric       // Handle overflow -- if that happens, return max.
1363fcaf7f86SDimitry Andric       if (std::numeric_limits<uint64_t>::max() - CountValue <= ValueSum)
1364fcaf7f86SDimitry Andric         return std::numeric_limits<uint64_t>::max();
1365fcaf7f86SDimitry Andric       ValueSum += CountValue;
1366fcaf7f86SDimitry Andric     }
1367fcaf7f86SDimitry Andric     return ValueSum;
1368fcaf7f86SDimitry Andric   };
1369fcaf7f86SDimitry Andric 
13700eae32dcSDimitry Andric   for (const NamedInstrProfRecord &I : Data) {
13710b57cec5SDimitry Andric     // Check for a match and fill the vector if there is one.
13720eae32dcSDimitry Andric     if (I.Hash == FuncHash)
13730eae32dcSDimitry Andric       return std::move(I);
1374fcaf7f86SDimitry Andric     if (NamedInstrProfRecord::hasCSFlagInHash(I.Hash) ==
1375fcaf7f86SDimitry Andric         NamedInstrProfRecord::hasCSFlagInHash(FuncHash)) {
1376fcaf7f86SDimitry Andric       CSBitMatch = true;
1377fcaf7f86SDimitry Andric       if (MismatchedFuncSum == nullptr)
1378fcaf7f86SDimitry Andric         continue;
1379fcaf7f86SDimitry Andric       FuncSum = std::max(FuncSum, getFuncSum(I.Counts));
13800b57cec5SDimitry Andric     }
1381fcaf7f86SDimitry Andric   }
1382fcaf7f86SDimitry Andric   if (CSBitMatch) {
1383fcaf7f86SDimitry Andric     if (MismatchedFuncSum != nullptr)
1384fcaf7f86SDimitry Andric       *MismatchedFuncSum = FuncSum;
13850b57cec5SDimitry Andric     return error(instrprof_error::hash_mismatch);
13860b57cec5SDimitry Andric   }
1387fcaf7f86SDimitry Andric   return error(instrprof_error::unknown_function);
1388fcaf7f86SDimitry Andric }
13890b57cec5SDimitry Andric 
139081ad6265SDimitry Andric Expected<memprof::MemProfRecord>
getMemProfRecord(const uint64_t FuncNameHash)139181ad6265SDimitry Andric IndexedInstrProfReader::getMemProfRecord(const uint64_t FuncNameHash) {
139281ad6265SDimitry Andric   // TODO: Add memprof specific errors.
139381ad6265SDimitry Andric   if (MemProfRecordTable == nullptr)
139481ad6265SDimitry Andric     return make_error<InstrProfError>(instrprof_error::invalid_prof,
139581ad6265SDimitry Andric                                       "no memprof data available in profile");
139681ad6265SDimitry Andric   auto Iter = MemProfRecordTable->find(FuncNameHash);
139781ad6265SDimitry Andric   if (Iter == MemProfRecordTable->end())
139881ad6265SDimitry Andric     return make_error<InstrProfError>(
139981ad6265SDimitry Andric         instrprof_error::unknown_function,
140081ad6265SDimitry Andric         "memprof record not found for function hash " + Twine(FuncNameHash));
140181ad6265SDimitry Andric 
140281ad6265SDimitry Andric   // Setup a callback to convert from frame ids to frame using the on-disk
140381ad6265SDimitry Andric   // FrameData hash table.
140481ad6265SDimitry Andric   memprof::FrameId LastUnmappedFrameId = 0;
140581ad6265SDimitry Andric   bool HasFrameMappingError = false;
140681ad6265SDimitry Andric   auto IdToFrameCallback = [&](const memprof::FrameId Id) {
140781ad6265SDimitry Andric     auto FrIter = MemProfFrameTable->find(Id);
140881ad6265SDimitry Andric     if (FrIter == MemProfFrameTable->end()) {
140981ad6265SDimitry Andric       LastUnmappedFrameId = Id;
141081ad6265SDimitry Andric       HasFrameMappingError = true;
141181ad6265SDimitry Andric       return memprof::Frame(0, 0, 0, false);
141281ad6265SDimitry Andric     }
141381ad6265SDimitry Andric     return *FrIter;
141481ad6265SDimitry Andric   };
141581ad6265SDimitry Andric 
141681ad6265SDimitry Andric   memprof::MemProfRecord Record(*Iter, IdToFrameCallback);
141781ad6265SDimitry Andric 
141881ad6265SDimitry Andric   // Check that all frame ids were successfully converted to frames.
141981ad6265SDimitry Andric   if (HasFrameMappingError) {
142081ad6265SDimitry Andric     return make_error<InstrProfError>(instrprof_error::hash_mismatch,
142181ad6265SDimitry Andric                                       "memprof frame not found for frame id " +
142281ad6265SDimitry Andric                                           Twine(LastUnmappedFrameId));
142381ad6265SDimitry Andric   }
142481ad6265SDimitry Andric   return Record;
142581ad6265SDimitry Andric }
142681ad6265SDimitry Andric 
getFunctionCounts(StringRef FuncName,uint64_t FuncHash,std::vector<uint64_t> & Counts)14270b57cec5SDimitry Andric Error IndexedInstrProfReader::getFunctionCounts(StringRef FuncName,
14280b57cec5SDimitry Andric                                                 uint64_t FuncHash,
14290b57cec5SDimitry Andric                                                 std::vector<uint64_t> &Counts) {
14300b57cec5SDimitry Andric   Expected<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash);
14310b57cec5SDimitry Andric   if (Error E = Record.takeError())
14320b57cec5SDimitry Andric     return error(std::move(E));
14330b57cec5SDimitry Andric 
14340b57cec5SDimitry Andric   Counts = Record.get().Counts;
14350b57cec5SDimitry Andric   return success();
14360b57cec5SDimitry Andric }
14370b57cec5SDimitry Andric 
getFunctionBitmapBytes(StringRef FuncName,uint64_t FuncHash,std::vector<uint8_t> & BitmapBytes)1438c9157d92SDimitry Andric Error IndexedInstrProfReader::getFunctionBitmapBytes(
1439c9157d92SDimitry Andric     StringRef FuncName, uint64_t FuncHash, std::vector<uint8_t> &BitmapBytes) {
1440c9157d92SDimitry Andric   Expected<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash);
1441c9157d92SDimitry Andric   if (Error E = Record.takeError())
1442c9157d92SDimitry Andric     return error(std::move(E));
1443c9157d92SDimitry Andric 
1444c9157d92SDimitry Andric   BitmapBytes = Record.get().BitmapBytes;
1445c9157d92SDimitry Andric   return success();
1446c9157d92SDimitry Andric }
1447c9157d92SDimitry Andric 
readNextRecord(NamedInstrProfRecord & Record)14480b57cec5SDimitry Andric Error IndexedInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
14490b57cec5SDimitry Andric   ArrayRef<NamedInstrProfRecord> Data;
14500b57cec5SDimitry Andric 
14510b57cec5SDimitry Andric   Error E = Index->getRecords(Data);
14520b57cec5SDimitry Andric   if (E)
14530b57cec5SDimitry Andric     return error(std::move(E));
14540b57cec5SDimitry Andric 
14550b57cec5SDimitry Andric   Record = Data[RecordIndex++];
14560b57cec5SDimitry Andric   if (RecordIndex >= Data.size()) {
14570b57cec5SDimitry Andric     Index->advanceToNextKey();
14580b57cec5SDimitry Andric     RecordIndex = 0;
14590b57cec5SDimitry Andric   }
14600b57cec5SDimitry Andric   return success();
14610b57cec5SDimitry Andric }
14620b57cec5SDimitry Andric 
readBinaryIds(std::vector<llvm::object::BuildID> & BinaryIds)1463bdd1243dSDimitry Andric Error IndexedInstrProfReader::readBinaryIds(
1464bdd1243dSDimitry Andric     std::vector<llvm::object::BuildID> &BinaryIds) {
1465bdd1243dSDimitry Andric   return readBinaryIdsInternal(*DataBuffer, BinaryIdsSize, BinaryIdsStart,
1466c9157d92SDimitry Andric                                BinaryIds, llvm::endianness::little);
1467bdd1243dSDimitry Andric }
1468bdd1243dSDimitry Andric 
printBinaryIds(raw_ostream & OS)1469bdd1243dSDimitry Andric Error IndexedInstrProfReader::printBinaryIds(raw_ostream &OS) {
1470c9157d92SDimitry Andric   std::vector<llvm::object::BuildID> BinaryIds;
1471c9157d92SDimitry Andric   if (Error E = readBinaryIds(BinaryIds))
1472c9157d92SDimitry Andric     return E;
1473c9157d92SDimitry Andric   printBinaryIdsInternal(OS, BinaryIds);
1474c9157d92SDimitry Andric   return Error::success();
1475bdd1243dSDimitry Andric }
1476bdd1243dSDimitry Andric 
accumulateCounts(CountSumOrPercent & Sum,bool IsCS)14778bcb0991SDimitry Andric void InstrProfReader::accumulateCounts(CountSumOrPercent &Sum, bool IsCS) {
14780b57cec5SDimitry Andric   uint64_t NumFuncs = 0;
14790b57cec5SDimitry Andric   for (const auto &Func : *this) {
14800b57cec5SDimitry Andric     if (isIRLevelProfile()) {
14810b57cec5SDimitry Andric       bool FuncIsCS = NamedInstrProfRecord::hasCSFlagInHash(Func.Hash);
14820b57cec5SDimitry Andric       if (FuncIsCS != IsCS)
14830b57cec5SDimitry Andric         continue;
14840b57cec5SDimitry Andric     }
14858bcb0991SDimitry Andric     Func.accumulateCounts(Sum);
14860b57cec5SDimitry Andric     ++NumFuncs;
14870b57cec5SDimitry Andric   }
14880b57cec5SDimitry Andric   Sum.NumEntries = NumFuncs;
14890b57cec5SDimitry Andric }
1490