1e78d131aSEugene Zelenko //===- InstrProfReader.cpp - Instrumented profiling reader ----------------===//
2f8d79198SJustin Bogner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f8d79198SJustin Bogner //
7f8d79198SJustin Bogner //===----------------------------------------------------------------------===//
8f8d79198SJustin Bogner //
9f8d79198SJustin Bogner // This file contains support for reading profiling data for clang's
10f8d79198SJustin Bogner // instrumentation based PGO and coverage.
11f8d79198SJustin Bogner //
12f8d79198SJustin Bogner //===----------------------------------------------------------------------===//
13f8d79198SJustin Bogner 
146bda14b3SChandler Carruth #include "llvm/ProfileData/InstrProfReader.h"
15e78d131aSEugene Zelenko #include "llvm/ADT/ArrayRef.h"
16ceed4eb1SRichard Smith #include "llvm/ADT/DenseMap.h"
17d10c995bSSam McCall #include "llvm/ADT/StringExtras.h"
18e78d131aSEugene Zelenko #include "llvm/ADT/StringRef.h"
19e78d131aSEugene Zelenko #include "llvm/IR/ProfileSummary.h"
20e78d131aSEugene Zelenko #include "llvm/ProfileData/InstrProf.h"
210a418490SSnehasish Kumar #include "llvm/ProfileData/MemProf.h"
22e78d131aSEugene Zelenko #include "llvm/ProfileData/ProfileCommon.h"
23e78d131aSEugene Zelenko #include "llvm/Support/Endian.h"
24e78d131aSEugene Zelenko #include "llvm/Support/Error.h"
25e78d131aSEugene Zelenko #include "llvm/Support/ErrorOr.h"
26e78d131aSEugene Zelenko #include "llvm/Support/MemoryBuffer.h"
27fd895bc8SGulfem Savrun Yeniceri #include "llvm/Support/SwapByteOrder.h"
28e50a3884SGulfem Savrun Yeniceri #include "llvm/Support/SymbolRemappingReader.h"
29e78d131aSEugene Zelenko #include <algorithm>
30e78d131aSEugene Zelenko #include <cstddef>
31e78d131aSEugene Zelenko #include <cstdint>
32e78d131aSEugene Zelenko #include <limits>
33e78d131aSEugene Zelenko #include <memory>
34e78d131aSEugene Zelenko #include <system_error>
35e78d131aSEugene Zelenko #include <utility>
36e78d131aSEugene Zelenko #include <vector>
37f8d79198SJustin Bogner 
38f8d79198SJustin Bogner using namespace llvm;
39f8d79198SJustin Bogner 
40186dcd4aSSnehasish Kumar // Extracts the variant information from the top 8 bits in the version and
41186dcd4aSSnehasish Kumar // returns an enum specifying the variants present.
getProfileKindFromVersion(uint64_t Version)42186dcd4aSSnehasish Kumar static InstrProfKind getProfileKindFromVersion(uint64_t Version) {
43186dcd4aSSnehasish Kumar   InstrProfKind ProfileKind = InstrProfKind::Unknown;
44186dcd4aSSnehasish Kumar   if (Version & VARIANT_MASK_IR_PROF) {
45b6817999SSnehasish Kumar     ProfileKind |= InstrProfKind::IRInstrumentation;
46186dcd4aSSnehasish Kumar   }
47186dcd4aSSnehasish Kumar   if (Version & VARIANT_MASK_CSIR_PROF) {
48b6817999SSnehasish Kumar     ProfileKind |= InstrProfKind::ContextSensitive;
49186dcd4aSSnehasish Kumar   }
50186dcd4aSSnehasish Kumar   if (Version & VARIANT_MASK_INSTR_ENTRY) {
51b6817999SSnehasish Kumar     ProfileKind |= InstrProfKind::FunctionEntryInstrumentation;
52186dcd4aSSnehasish Kumar   }
53186dcd4aSSnehasish Kumar   if (Version & VARIANT_MASK_BYTE_COVERAGE) {
54186dcd4aSSnehasish Kumar     ProfileKind |= InstrProfKind::SingleByteCoverage;
55186dcd4aSSnehasish Kumar   }
56186dcd4aSSnehasish Kumar   if (Version & VARIANT_MASK_FUNCTION_ENTRY_ONLY) {
57186dcd4aSSnehasish Kumar     ProfileKind |= InstrProfKind::FunctionEntryOnly;
58186dcd4aSSnehasish Kumar   }
590a418490SSnehasish Kumar   if (Version & VARIANT_MASK_MEMPROF) {
600a418490SSnehasish Kumar     ProfileKind |= InstrProfKind::MemProf;
610a418490SSnehasish Kumar   }
62186dcd4aSSnehasish Kumar   return ProfileKind;
63186dcd4aSSnehasish Kumar }
64186dcd4aSSnehasish Kumar 
659152fd17SVedant Kumar static Expected<std::unique_ptr<MemoryBuffer>>
setupMemoryBuffer(const Twine & Path)660da23a27SBenjamin Kramer setupMemoryBuffer(const Twine &Path) {
67adf21f2aSRafael Espindola   ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
68e71994a2SJonathan Crowther       MemoryBuffer::getFileOrSTDIN(Path, /*IsText=*/true);
69adf21f2aSRafael Espindola   if (std::error_code EC = BufferOrErr.getError())
709152fd17SVedant Kumar     return errorCodeToError(EC);
712b6c537bSJustin Bogner   return std::move(BufferOrErr.get());
72b7aa2630SJustin Bogner }
73b7aa2630SJustin Bogner 
initializeReader(InstrProfReader & Reader)749152fd17SVedant Kumar static Error initializeReader(InstrProfReader &Reader) {
75b7aa2630SJustin Bogner   return Reader.readHeader();
76b7aa2630SJustin Bogner }
77b7aa2630SJustin Bogner 
789152fd17SVedant Kumar Expected<std::unique_ptr<InstrProfReader>>
create(const Twine & Path,const InstrProfCorrelator * Correlator)7965d7fd02SEllis Hoag InstrProfReader::create(const Twine &Path,
8065d7fd02SEllis Hoag                         const InstrProfCorrelator *Correlator) {
81b7aa2630SJustin Bogner   // Set up the buffer to read.
82fcd55607SDiego Novillo   auto BufferOrError = setupMemoryBuffer(Path);
839152fd17SVedant Kumar   if (Error E = BufferOrError.takeError())
84c55cf4afSBill Wendling     return std::move(E);
8565d7fd02SEllis Hoag   return InstrProfReader::create(std::move(BufferOrError.get()), Correlator);
862b6c537bSJustin Bogner }
87f8d79198SJustin Bogner 
889152fd17SVedant Kumar Expected<std::unique_ptr<InstrProfReader>>
create(std::unique_ptr<MemoryBuffer> Buffer,const InstrProfCorrelator * Correlator)8965d7fd02SEllis Hoag InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
9065d7fd02SEllis Hoag                         const InstrProfCorrelator *Correlator) {
9165d7fd02SEllis Hoag   // Sanity check the buffer.
92d6c15b66SVedant Kumar   if (uint64_t(Buffer->getBufferSize()) > std::numeric_limits<uint64_t>::max())
939152fd17SVedant Kumar     return make_error<InstrProfError>(instrprof_error::too_large);
942b6c537bSJustin Bogner 
952c684cfdSRong Xu   if (Buffer->getBufferSize() == 0)
962c684cfdSRong Xu     return make_error<InstrProfError>(instrprof_error::empty_raw_profile);
972c684cfdSRong Xu 
98fcd55607SDiego Novillo   std::unique_ptr<InstrProfReader> Result;
9909a67f45SDuncan P. N. Exon Smith   // Create the reader.
100b7aa2630SJustin Bogner   if (IndexedInstrProfReader::hasFormat(*Buffer))
101b7aa2630SJustin Bogner     Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
102b7aa2630SJustin Bogner   else if (RawInstrProfReader64::hasFormat(*Buffer))
10365d7fd02SEllis Hoag     Result.reset(new RawInstrProfReader64(std::move(Buffer), Correlator));
1044680361dSDuncan P. N. Exon Smith   else if (RawInstrProfReader32::hasFormat(*Buffer))
10565d7fd02SEllis Hoag     Result.reset(new RawInstrProfReader32(std::move(Buffer), Correlator));
1064f823667SNathan Slingerland   else if (TextInstrProfReader::hasFormat(*Buffer))
107911ced6bSNathan Slingerland     Result.reset(new TextInstrProfReader(std::move(Buffer)));
1084f823667SNathan Slingerland   else
1099152fd17SVedant Kumar     return make_error<InstrProfError>(instrprof_error::unrecognized_format);
11009a67f45SDuncan P. N. Exon Smith 
111b7aa2630SJustin Bogner   // Initialize the reader and return the result.
1129152fd17SVedant Kumar   if (Error E = initializeReader(*Result))
113c55cf4afSBill Wendling     return std::move(E);
114fcd55607SDiego Novillo 
115c55cf4afSBill Wendling   return std::move(Result);
116b7aa2630SJustin Bogner }
117b7aa2630SJustin Bogner 
1189152fd17SVedant Kumar Expected<std::unique_ptr<IndexedInstrProfReader>>
create(const Twine & Path,const Twine & RemappingPath)119ceed4eb1SRichard Smith IndexedInstrProfReader::create(const Twine &Path, const Twine &RemappingPath) {
120b7aa2630SJustin Bogner   // Set up the buffer to read.
121fcd55607SDiego Novillo   auto BufferOrError = setupMemoryBuffer(Path);
1229152fd17SVedant Kumar   if (Error E = BufferOrError.takeError())
123c55cf4afSBill Wendling     return std::move(E);
124ceed4eb1SRichard Smith 
125ceed4eb1SRichard Smith   // Set up the remapping buffer if requested.
126ceed4eb1SRichard Smith   std::unique_ptr<MemoryBuffer> RemappingBuffer;
127ceed4eb1SRichard Smith   std::string RemappingPathStr = RemappingPath.str();
128ceed4eb1SRichard Smith   if (!RemappingPathStr.empty()) {
129ceed4eb1SRichard Smith     auto RemappingBufferOrError = setupMemoryBuffer(RemappingPathStr);
130ceed4eb1SRichard Smith     if (Error E = RemappingBufferOrError.takeError())
131c55cf4afSBill Wendling       return std::move(E);
132ceed4eb1SRichard Smith     RemappingBuffer = std::move(RemappingBufferOrError.get());
133ceed4eb1SRichard Smith   }
134ceed4eb1SRichard Smith 
135ceed4eb1SRichard Smith   return IndexedInstrProfReader::create(std::move(BufferOrError.get()),
136ceed4eb1SRichard Smith                                         std::move(RemappingBuffer));
1372b6c537bSJustin Bogner }
138b7aa2630SJustin Bogner 
1399152fd17SVedant Kumar Expected<std::unique_ptr<IndexedInstrProfReader>>
create(std::unique_ptr<MemoryBuffer> Buffer,std::unique_ptr<MemoryBuffer> RemappingBuffer)140ceed4eb1SRichard Smith IndexedInstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
141ceed4eb1SRichard Smith                                std::unique_ptr<MemoryBuffer> RemappingBuffer) {
142d6c15b66SVedant Kumar   if (uint64_t(Buffer->getBufferSize()) > std::numeric_limits<uint64_t>::max())
1439152fd17SVedant Kumar     return make_error<InstrProfError>(instrprof_error::too_large);
144ab89ed7dSJustin Bogner 
145b7aa2630SJustin Bogner   // Create the reader.
146b7aa2630SJustin Bogner   if (!IndexedInstrProfReader::hasFormat(*Buffer))
1479152fd17SVedant Kumar     return make_error<InstrProfError>(instrprof_error::bad_magic);
1480eaee545SJonas Devlieghere   auto Result = std::make_unique<IndexedInstrProfReader>(
149ceed4eb1SRichard Smith       std::move(Buffer), std::move(RemappingBuffer));
150b7aa2630SJustin Bogner 
151b7aa2630SJustin Bogner   // Initialize the reader and return the result.
1529152fd17SVedant Kumar   if (Error E = initializeReader(*Result))
153c55cf4afSBill Wendling     return std::move(E);
154ab89ed7dSJustin Bogner 
155c55cf4afSBill Wendling   return std::move(Result);
156f8d79198SJustin Bogner }
157f8d79198SJustin Bogner 
hasFormat(const MemoryBuffer & Buffer)1584f823667SNathan Slingerland bool TextInstrProfReader::hasFormat(const MemoryBuffer &Buffer) {
1594f823667SNathan Slingerland   // Verify that this really looks like plain ASCII text by checking a
1604f823667SNathan Slingerland   // 'reasonable' number of characters (up to profile magic size).
1614f823667SNathan Slingerland   size_t count = std::min(Buffer.getBufferSize(), sizeof(uint64_t));
1624f823667SNathan Slingerland   StringRef buffer = Buffer.getBufferStart();
1632491dd11SVedant Kumar   return count == 0 ||
1642491dd11SVedant Kumar          std::all_of(buffer.begin(), buffer.begin() + count,
165d10c995bSSam McCall                      [](char c) { return isPrint(c) || isSpace(c); });
1664f823667SNathan Slingerland }
1674f823667SNathan Slingerland 
16833c76c0cSRong Xu // Read the profile variant flag from the header: ":FE" means this is a FE
16933c76c0cSRong Xu // generated profile. ":IR" means this is an IR level profile. Other strings
17033c76c0cSRong Xu // with a leading ':' will be reported an error format.
readHeader()1719152fd17SVedant Kumar Error TextInstrProfReader::readHeader() {
172a716cc5cSXinliang David Li   Symtab.reset(new InstrProfSymtab());
17350da55a5SRong Xu 
17450da55a5SRong Xu   while (Line->startswith(":")) {
17550da55a5SRong Xu     StringRef Str = Line->substr(1);
17642f74e82SMartin Storsjö     if (Str.equals_insensitive("ir"))
177b6817999SSnehasish Kumar       ProfileKind |= InstrProfKind::IRInstrumentation;
17842f74e82SMartin Storsjö     else if (Str.equals_insensitive("fe"))
179b6817999SSnehasish Kumar       ProfileKind |= InstrProfKind::FrontendInstrumentation;
18042f74e82SMartin Storsjö     else if (Str.equals_insensitive("csir")) {
181b6817999SSnehasish Kumar       ProfileKind |= InstrProfKind::IRInstrumentation;
182b6817999SSnehasish Kumar       ProfileKind |= InstrProfKind::ContextSensitive;
18342f74e82SMartin Storsjö     } else if (Str.equals_insensitive("entry_first"))
184b6817999SSnehasish Kumar       ProfileKind |= InstrProfKind::FunctionEntryInstrumentation;
18542f74e82SMartin Storsjö     else if (Str.equals_insensitive("not_entry_first"))
186b6817999SSnehasish Kumar       ProfileKind &= ~InstrProfKind::FunctionEntryInstrumentation;
18750da55a5SRong Xu     else
1889152fd17SVedant Kumar       return error(instrprof_error::bad_header);
18933c76c0cSRong Xu     ++Line;
19050da55a5SRong Xu   }
191a716cc5cSXinliang David Li   return success();
192a716cc5cSXinliang David Li }
193a716cc5cSXinliang David Li 
1949152fd17SVedant Kumar Error
readValueProfileData(InstrProfRecord & Record)195e3bf4fd3SXinliang David Li TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) {
196e3bf4fd3SXinliang David Li 
197e3bf4fd3SXinliang David Li #define CHECK_LINE_END(Line)                                                   \
198e3bf4fd3SXinliang David Li   if (Line.is_at_end())                                                        \
199e3bf4fd3SXinliang David Li     return error(instrprof_error::truncated);
200e3bf4fd3SXinliang David Li #define READ_NUM(Str, Dst)                                                     \
201e3bf4fd3SXinliang David Li   if ((Str).getAsInteger(10, (Dst)))                                           \
202e3bf4fd3SXinliang David Li     return error(instrprof_error::malformed);
203e3bf4fd3SXinliang David Li #define VP_READ_ADVANCE(Val)                                                   \
204e3bf4fd3SXinliang David Li   CHECK_LINE_END(Line);                                                        \
205e3bf4fd3SXinliang David Li   uint32_t Val;                                                                \
206e3bf4fd3SXinliang David Li   READ_NUM((*Line), (Val));                                                    \
207e3bf4fd3SXinliang David Li   Line++;
208e3bf4fd3SXinliang David Li 
209e3bf4fd3SXinliang David Li   if (Line.is_at_end())
210e3bf4fd3SXinliang David Li     return success();
211a716cc5cSXinliang David Li 
212e3bf4fd3SXinliang David Li   uint32_t NumValueKinds;
213e3bf4fd3SXinliang David Li   if (Line->getAsInteger(10, NumValueKinds)) {
214e3bf4fd3SXinliang David Li     // No value profile data
215e3bf4fd3SXinliang David Li     return success();
216e3bf4fd3SXinliang David Li   }
217e3bf4fd3SXinliang David Li   if (NumValueKinds == 0 || NumValueKinds > IPVK_Last + 1)
218ee88b8d6SGulfem Savrun Yeniceri     return error(instrprof_error::malformed,
219ee88b8d6SGulfem Savrun Yeniceri                  "number of value kinds is invalid");
220e3bf4fd3SXinliang David Li   Line++;
221e3bf4fd3SXinliang David Li 
222e3bf4fd3SXinliang David Li   for (uint32_t VK = 0; VK < NumValueKinds; VK++) {
223e3bf4fd3SXinliang David Li     VP_READ_ADVANCE(ValueKind);
224e3bf4fd3SXinliang David Li     if (ValueKind > IPVK_Last)
225ee88b8d6SGulfem Savrun Yeniceri       return error(instrprof_error::malformed, "value kind is invalid");
226ee88b8d6SGulfem Savrun Yeniceri     ;
227e3bf4fd3SXinliang David Li     VP_READ_ADVANCE(NumValueSites);
228e3bf4fd3SXinliang David Li     if (!NumValueSites)
229e3bf4fd3SXinliang David Li       continue;
230e3bf4fd3SXinliang David Li 
231e3bf4fd3SXinliang David Li     Record.reserveSites(VK, NumValueSites);
232e3bf4fd3SXinliang David Li     for (uint32_t S = 0; S < NumValueSites; S++) {
233e3bf4fd3SXinliang David Li       VP_READ_ADVANCE(NumValueData);
234e3bf4fd3SXinliang David Li 
235e3bf4fd3SXinliang David Li       std::vector<InstrProfValueData> CurrentValues;
236e3bf4fd3SXinliang David Li       for (uint32_t V = 0; V < NumValueData; V++) {
237e3bf4fd3SXinliang David Li         CHECK_LINE_END(Line);
23835723644SRong Xu         std::pair<StringRef, StringRef> VD = Line->rsplit(':');
239e3bf4fd3SXinliang David Li         uint64_t TakenCount, Value;
240cbb11407SRong Xu         if (ValueKind == IPVK_IndirectCallTarget) {
24129a21babSMircea Trofin           if (InstrProfSymtab::isExternalSymbol(VD.first)) {
24229a21babSMircea Trofin             Value = 0;
24329a21babSMircea Trofin           } else {
244b5794ca9SVedant Kumar             if (Error E = Symtab->addFuncName(VD.first))
245b5794ca9SVedant Kumar               return E;
246a716cc5cSXinliang David Li             Value = IndexedInstrProf::ComputeHash(VD.first);
24729a21babSMircea Trofin           }
248a716cc5cSXinliang David Li         } else {
249e3bf4fd3SXinliang David Li           READ_NUM(VD.first, Value);
250e3bf4fd3SXinliang David Li         }
251a716cc5cSXinliang David Li         READ_NUM(VD.second, TakenCount);
252e3bf4fd3SXinliang David Li         CurrentValues.push_back({Value, TakenCount});
253e3bf4fd3SXinliang David Li         Line++;
254e3bf4fd3SXinliang David Li       }
255cbb11407SRong Xu       Record.addValueData(ValueKind, S, CurrentValues.data(), NumValueData,
256cbb11407SRong Xu                           nullptr);
257e3bf4fd3SXinliang David Li     }
258e3bf4fd3SXinliang David Li   }
259e3bf4fd3SXinliang David Li   return success();
260e3bf4fd3SXinliang David Li 
261e3bf4fd3SXinliang David Li #undef CHECK_LINE_END
262e3bf4fd3SXinliang David Li #undef READ_NUM
263e3bf4fd3SXinliang David Li #undef VP_READ_ADVANCE
264e3bf4fd3SXinliang David Li }
265e3bf4fd3SXinliang David Li 
readNextRecord(NamedInstrProfRecord & Record)266cf9d52c6SDavid Blaikie Error TextInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
267cf36a366SJustin Bogner   // Skip empty lines and comments.
268cf36a366SJustin Bogner   while (!Line.is_at_end() && (Line->empty() || Line->startswith("#")))
269f8d79198SJustin Bogner     ++Line;
270f8d79198SJustin Bogner   // If we hit EOF while looking for a name, we're done.
271a716cc5cSXinliang David Li   if (Line.is_at_end()) {
272f8d79198SJustin Bogner     return error(instrprof_error::eof);
273a716cc5cSXinliang David Li   }
274f8d79198SJustin Bogner 
275f8d79198SJustin Bogner   // Read the function name.
276f8d79198SJustin Bogner   Record.Name = *Line++;
277b5794ca9SVedant Kumar   if (Error E = Symtab->addFuncName(Record.Name))
27829a21babSMircea Trofin     return error(std::move(E));
279f8d79198SJustin Bogner 
280f8d79198SJustin Bogner   // Read the function hash.
281f8d79198SJustin Bogner   if (Line.is_at_end())
282f8d79198SJustin Bogner     return error(instrprof_error::truncated);
283f95ca075SJustin Bogner   if ((Line++)->getAsInteger(0, Record.Hash))
284ee88b8d6SGulfem Savrun Yeniceri     return error(instrprof_error::malformed,
285ee88b8d6SGulfem Savrun Yeniceri                  "function hash is not a valid integer");
286f8d79198SJustin Bogner 
287f8d79198SJustin Bogner   // Read the number of counters.
288f8d79198SJustin Bogner   uint64_t NumCounters;
289f8d79198SJustin Bogner   if (Line.is_at_end())
290f8d79198SJustin Bogner     return error(instrprof_error::truncated);
291f8d79198SJustin Bogner   if ((Line++)->getAsInteger(10, NumCounters))
292ee88b8d6SGulfem Savrun Yeniceri     return error(instrprof_error::malformed,
293ee88b8d6SGulfem Savrun Yeniceri                  "number of counters is not a valid integer");
294b59d7c73SJustin Bogner   if (NumCounters == 0)
295ee88b8d6SGulfem Savrun Yeniceri     return error(instrprof_error::malformed, "number of counters is zero");
296f8d79198SJustin Bogner 
297f8d79198SJustin Bogner   // Read each counter and fill our internal storage with the values.
2986241c2a6SRong Xu   Record.Clear();
2993a7d44cbSJustin Bogner   Record.Counts.reserve(NumCounters);
300f8d79198SJustin Bogner   for (uint64_t I = 0; I < NumCounters; ++I) {
301f8d79198SJustin Bogner     if (Line.is_at_end())
302f8d79198SJustin Bogner       return error(instrprof_error::truncated);
303f8d79198SJustin Bogner     uint64_t Count;
304f8d79198SJustin Bogner     if ((Line++)->getAsInteger(10, Count))
305ee88b8d6SGulfem Savrun Yeniceri       return error(instrprof_error::malformed, "count is invalid");
3063a7d44cbSJustin Bogner     Record.Counts.push_back(Count);
307f8d79198SJustin Bogner   }
308f8d79198SJustin Bogner 
309e3bf4fd3SXinliang David Li   // Check if value profile data exists and read it if so.
3109152fd17SVedant Kumar   if (Error E = readValueProfileData(Record))
31129a21babSMircea Trofin     return error(std::move(E));
312e3bf4fd3SXinliang David Li 
313f8d79198SJustin Bogner   return success();
314f8d79198SJustin Bogner }
31524b4b653SDuncan P. N. Exon Smith 
3164680361dSDuncan P. N. Exon Smith template <class IntPtrT>
getProfileKind() const317186dcd4aSSnehasish Kumar InstrProfKind RawInstrProfReader<IntPtrT>::getProfileKind() const {
318186dcd4aSSnehasish Kumar   return getProfileKindFromVersion(Version);
319186dcd4aSSnehasish Kumar }
320186dcd4aSSnehasish Kumar 
321186dcd4aSSnehasish Kumar template <class IntPtrT>
hasFormat(const MemoryBuffer & DataBuffer)3224680361dSDuncan P. N. Exon Smith bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) {
323d7d83477SDuncan P. N. Exon Smith   if (DataBuffer.getBufferSize() < sizeof(uint64_t))
3244680361dSDuncan P. N. Exon Smith     return false;
325d7d83477SDuncan P. N. Exon Smith   uint64_t Magic =
326d7d83477SDuncan P. N. Exon Smith     *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart());
327dab183edSXinliang David Li   return RawInstrProf::getMagic<IntPtrT>() == Magic ||
328dab183edSXinliang David Li          sys::getSwappedBytes(RawInstrProf::getMagic<IntPtrT>()) == Magic;
3294680361dSDuncan P. N. Exon Smith }
3304680361dSDuncan P. N. Exon Smith 
3314680361dSDuncan P. N. Exon Smith template <class IntPtrT>
readHeader()3329152fd17SVedant Kumar Error RawInstrProfReader<IntPtrT>::readHeader() {
33309a67f45SDuncan P. N. Exon Smith   if (!hasFormat(*DataBuffer))
33409a67f45SDuncan P. N. Exon Smith     return error(instrprof_error::bad_magic);
335dab183edSXinliang David Li   if (DataBuffer->getBufferSize() < sizeof(RawInstrProf::Header))
336531bb481SDuncan P. N. Exon Smith     return error(instrprof_error::bad_header);
337dab183edSXinliang David Li   auto *Header = reinterpret_cast<const RawInstrProf::Header *>(
338dab183edSXinliang David Li       DataBuffer->getBufferStart());
339dab183edSXinliang David Li   ShouldSwapBytes = Header->Magic != RawInstrProf::getMagic<IntPtrT>();
34024b4b653SDuncan P. N. Exon Smith   return readHeader(*Header);
34124b4b653SDuncan P. N. Exon Smith }
34224b4b653SDuncan P. N. Exon Smith 
343a119f323SJustin Bogner template <class IntPtrT>
readNextHeader(const char * CurrentPos)3449152fd17SVedant Kumar Error RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
345a119f323SJustin Bogner   const char *End = DataBuffer->getBufferEnd();
346a119f323SJustin Bogner   // Skip zero padding between profiles.
347a119f323SJustin Bogner   while (CurrentPos != End && *CurrentPos == 0)
348a119f323SJustin Bogner     ++CurrentPos;
349a119f323SJustin Bogner   // If there's nothing left, we're done.
350a119f323SJustin Bogner   if (CurrentPos == End)
3519152fd17SVedant Kumar     return make_error<InstrProfError>(instrprof_error::eof);
352a119f323SJustin Bogner   // If there isn't enough space for another header, this is probably just
353a119f323SJustin Bogner   // garbage at the end of the file.
354dab183edSXinliang David Li   if (CurrentPos + sizeof(RawInstrProf::Header) > End)
355ee88b8d6SGulfem Savrun Yeniceri     return make_error<InstrProfError>(instrprof_error::malformed,
356ee88b8d6SGulfem Savrun Yeniceri                                       "not enough space for another header");
35754b11282SJustin Bogner   // The writer ensures each profile is padded to start at an aligned address.
358b2505005SBenjamin Kramer   if (reinterpret_cast<size_t>(CurrentPos) % alignof(uint64_t))
359ee88b8d6SGulfem Savrun Yeniceri     return make_error<InstrProfError>(instrprof_error::malformed,
360ee88b8d6SGulfem Savrun Yeniceri                                       "insufficient padding");
361a119f323SJustin Bogner   // The magic should have the same byte order as in the previous header.
362a119f323SJustin Bogner   uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos);
363dab183edSXinliang David Li   if (Magic != swap(RawInstrProf::getMagic<IntPtrT>()))
3649152fd17SVedant Kumar     return make_error<InstrProfError>(instrprof_error::bad_magic);
365a119f323SJustin Bogner 
366a119f323SJustin Bogner   // There's another profile to read, so we need to process the header.
367dab183edSXinliang David Li   auto *Header = reinterpret_cast<const RawInstrProf::Header *>(CurrentPos);
368a119f323SJustin Bogner   return readHeader(*Header);
369a119f323SJustin Bogner }
370a119f323SJustin Bogner 
3714680361dSDuncan P. N. Exon Smith template <class IntPtrT>
createSymtab(InstrProfSymtab & Symtab)3729152fd17SVedant Kumar Error RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) {
37365d7fd02SEllis Hoag   if (Error E = Symtab.create(StringRef(NamesStart, NamesEnd - NamesStart)))
3749152fd17SVedant Kumar     return error(std::move(E));
375a716cc5cSXinliang David Li   for (const RawInstrProf::ProfileData<IntPtrT> *I = Data; I != DataEnd; ++I) {
376a716cc5cSXinliang David Li     const IntPtrT FPtr = swap(I->FunctionPointer);
377a716cc5cSXinliang David Li     if (!FPtr)
378a716cc5cSXinliang David Li       continue;
379a82d6c0aSXinliang David Li     Symtab.mapAddress(FPtr, I->NameRef);
380a716cc5cSXinliang David Li   }
381e44482feSVedant Kumar   return success();
382a716cc5cSXinliang David Li }
383a716cc5cSXinliang David Li 
384a716cc5cSXinliang David Li template <class IntPtrT>
readHeader(const RawInstrProf::Header & Header)3859152fd17SVedant Kumar Error RawInstrProfReader<IntPtrT>::readHeader(
3869152fd17SVedant Kumar     const RawInstrProf::Header &Header) {
38733c76c0cSRong Xu   Version = swap(Header.Version);
38833c76c0cSRong Xu   if (GET_VERSION(Version) != RawInstrProf::Version)
38924b4b653SDuncan P. N. Exon Smith     return error(instrprof_error::unsupported_version);
39065d7fd02SEllis Hoag   if (useDebugInfoCorrelate() && !Correlator)
39165d7fd02SEllis Hoag     return error(instrprof_error::missing_debug_info_for_correlation);
39265d7fd02SEllis Hoag   if (!useDebugInfoCorrelate() && Correlator)
39365d7fd02SEllis Hoag     return error(instrprof_error::unexpected_debug_info_for_correlation);
39424b4b653SDuncan P. N. Exon Smith 
39583302c84SPetr Hosek   BinaryIdsSize = swap(Header.BinaryIdsSize);
396b9f547e8SLeonard Chan   if (BinaryIdsSize % sizeof(uint64_t))
397b9f547e8SLeonard Chan     return error(instrprof_error::bad_header);
398b9f547e8SLeonard Chan 
39924b4b653SDuncan P. N. Exon Smith   CountersDelta = swap(Header.CountersDelta);
40024b4b653SDuncan P. N. Exon Smith   NamesDelta = swap(Header.NamesDelta);
40188d81770SEllis Hoag   auto NumData = swap(Header.DataSize);
402d889d1efSVedant Kumar   auto PaddingBytesBeforeCounters = swap(Header.PaddingBytesBeforeCounters);
40388d81770SEllis Hoag   auto CountersSize = swap(Header.CountersSize) * getCounterTypeSize();
404d889d1efSVedant Kumar   auto PaddingBytesAfterCounters = swap(Header.PaddingBytesAfterCounters);
40565d7fd02SEllis Hoag   auto NamesSize = swap(Header.NamesSize);
4066fac1741SBetul Buyukkurt   ValueKindLast = swap(Header.ValueKindLast);
4076fac1741SBetul Buyukkurt 
408f2147375SEllis Hoag   auto DataSize = NumData * sizeof(RawInstrProf::ProfileData<IntPtrT>);
4096fac1741SBetul Buyukkurt   auto PaddingSize = getNumPaddingBytes(NamesSize);
41024b4b653SDuncan P. N. Exon Smith 
411e50a3884SGulfem Savrun Yeniceri   // Profile data starts after profile header and binary ids if exist.
412e50a3884SGulfem Savrun Yeniceri   ptrdiff_t DataOffset = sizeof(RawInstrProf::Header) + BinaryIdsSize;
413f2147375SEllis Hoag   ptrdiff_t CountersOffset = DataOffset + DataSize + PaddingBytesBeforeCounters;
414f2147375SEllis Hoag   ptrdiff_t NamesOffset =
415f2147375SEllis Hoag       CountersOffset + CountersSize + PaddingBytesAfterCounters;
4166fac1741SBetul Buyukkurt   ptrdiff_t ValueDataOffset = NamesOffset + NamesSize + PaddingSize;
41724b4b653SDuncan P. N. Exon Smith 
418a119f323SJustin Bogner   auto *Start = reinterpret_cast<const char *>(&Header);
419188a7c5fSXinliang David Li   if (Start + ValueDataOffset > DataBuffer->getBufferEnd())
420531bb481SDuncan P. N. Exon Smith     return error(instrprof_error::bad_header);
42124b4b653SDuncan P. N. Exon Smith 
42265d7fd02SEllis Hoag   if (Correlator) {
42365d7fd02SEllis Hoag     // These sizes in the raw file are zero because we constructed them in the
42465d7fd02SEllis Hoag     // Correlator.
42565d7fd02SEllis Hoag     assert(DataSize == 0 && NamesSize == 0);
42665d7fd02SEllis Hoag     assert(CountersDelta == 0 && NamesDelta == 0);
42765d7fd02SEllis Hoag     Data = Correlator->getDataPointer();
42865d7fd02SEllis Hoag     DataEnd = Data + Correlator->getDataSize();
429f1705952SEllis Hoag     NamesStart = Correlator->getNamesPointer();
430f1705952SEllis Hoag     NamesEnd = NamesStart + Correlator->getNamesSize();
43165d7fd02SEllis Hoag   } else {
432dab183edSXinliang David Li     Data = reinterpret_cast<const RawInstrProf::ProfileData<IntPtrT> *>(
433dab183edSXinliang David Li         Start + DataOffset);
434f2147375SEllis Hoag     DataEnd = Data + NumData;
43565d7fd02SEllis Hoag     NamesStart = Start + NamesOffset;
43665d7fd02SEllis Hoag     NamesEnd = NamesStart + NamesSize;
43765d7fd02SEllis Hoag   }
438e50a3884SGulfem Savrun Yeniceri 
439e50a3884SGulfem Savrun Yeniceri   // Binary ids start just after the header.
440e50a3884SGulfem Savrun Yeniceri   BinaryIdsStart =
441e50a3884SGulfem Savrun Yeniceri       reinterpret_cast<const uint8_t *>(&Header) + sizeof(RawInstrProf::Header);
442f2147375SEllis Hoag   CountersStart = Start + CountersOffset;
443f2147375SEllis Hoag   CountersEnd = CountersStart + CountersSize;
4446fac1741SBetul Buyukkurt   ValueDataStart = reinterpret_cast<const uint8_t *>(Start + ValueDataOffset);
44524b4b653SDuncan P. N. Exon Smith 
446b9f547e8SLeonard Chan   const uint8_t *BufferEnd = (const uint8_t *)DataBuffer->getBufferEnd();
447b9f547e8SLeonard Chan   if (BinaryIdsStart + BinaryIdsSize > BufferEnd)
448b9f547e8SLeonard Chan     return error(instrprof_error::bad_header);
449b9f547e8SLeonard Chan 
4500eaee545SJonas Devlieghere   std::unique_ptr<InstrProfSymtab> NewSymtab = std::make_unique<InstrProfSymtab>();
45114415a3aSKazu Hirata   if (Error E = createSymtab(*NewSymtab))
4529152fd17SVedant Kumar     return E;
453e44482feSVedant Kumar 
454a716cc5cSXinliang David Li   Symtab = std::move(NewSymtab);
45524b4b653SDuncan P. N. Exon Smith   return success();
45624b4b653SDuncan P. N. Exon Smith }
45724b4b653SDuncan P. N. Exon Smith 
4584680361dSDuncan P. N. Exon Smith template <class IntPtrT>
readName(NamedInstrProfRecord & Record)459cf9d52c6SDavid Blaikie Error RawInstrProfReader<IntPtrT>::readName(NamedInstrProfRecord &Record) {
460a82d6c0aSXinliang David Li   Record.Name = getName(Data->NameRef);
461cf4a128cSXinliang David Li   return success();
462cf4a128cSXinliang David Li }
463cf4a128cSXinliang David Li 
464cf4a128cSXinliang David Li template <class IntPtrT>
readFuncHash(NamedInstrProfRecord & Record)465cf9d52c6SDavid Blaikie Error RawInstrProfReader<IntPtrT>::readFuncHash(NamedInstrProfRecord &Record) {
466cf4a128cSXinliang David Li   Record.Hash = swap(Data->FuncHash);
467cf4a128cSXinliang David Li   return success();
468cf4a128cSXinliang David Li }
469cf4a128cSXinliang David Li 
470cf4a128cSXinliang David Li template <class IntPtrT>
readRawCounts(InstrProfRecord & Record)4719152fd17SVedant Kumar Error RawInstrProfReader<IntPtrT>::readRawCounts(
472cf4a128cSXinliang David Li     InstrProfRecord &Record) {
473b59d7c73SJustin Bogner   uint32_t NumCounters = swap(Data->NumCounters);
474b59d7c73SJustin Bogner   if (NumCounters == 0)
475ee88b8d6SGulfem Savrun Yeniceri     return error(instrprof_error::malformed, "number of counters is zero");
476cf4a128cSXinliang David Li 
477f2147375SEllis Hoag   ptrdiff_t CounterBaseOffset = swap(Data->CounterPtr) - CountersDelta;
478f2147375SEllis Hoag   if (CounterBaseOffset < 0)
479ee88b8d6SGulfem Savrun Yeniceri     return error(
480ee88b8d6SGulfem Savrun Yeniceri         instrprof_error::malformed,
481f2147375SEllis Hoag         ("counter offset " + Twine(CounterBaseOffset) + " is negative").str());
482ee88b8d6SGulfem Savrun Yeniceri 
483f2147375SEllis Hoag   if (CounterBaseOffset >= CountersEnd - CountersStart)
48465d7fd02SEllis Hoag     return error(instrprof_error::malformed,
485f2147375SEllis Hoag                  ("counter offset " + Twine(CounterBaseOffset) +
486f2147375SEllis Hoag                   " is greater than the maximum counter offset " +
487f2147375SEllis Hoag                   Twine(CountersEnd - CountersStart - 1))
488ee88b8d6SGulfem Savrun Yeniceri                      .str());
489ee88b8d6SGulfem Savrun Yeniceri 
490f2147375SEllis Hoag   uint64_t MaxNumCounters =
491f2147375SEllis Hoag       (CountersEnd - (CountersStart + CounterBaseOffset)) /
492f2147375SEllis Hoag       getCounterTypeSize();
493f2147375SEllis Hoag   if (NumCounters > MaxNumCounters)
494ee88b8d6SGulfem Savrun Yeniceri     return error(instrprof_error::malformed,
495f2147375SEllis Hoag                  ("number of counters " + Twine(NumCounters) +
496126e7611SGulfem Savrun Yeniceri                   " is greater than the maximum number of counters " +
497f2147375SEllis Hoag                   Twine(MaxNumCounters))
498ee88b8d6SGulfem Savrun Yeniceri                      .str());
49995fb23abSVedant Kumar 
5003a7d44cbSJustin Bogner   Record.Counts.clear();
501f2147375SEllis Hoag   Record.Counts.reserve(NumCounters);
502f2147375SEllis Hoag   for (uint32_t I = 0; I < NumCounters; I++) {
50311d30742SEllis Hoag     const char *Ptr =
50411d30742SEllis Hoag         CountersStart + CounterBaseOffset + I * getCounterTypeSize();
50511d30742SEllis Hoag     if (hasSingleByteCoverage()) {
50611d30742SEllis Hoag       // A value of zero signifies the block is covered.
50711d30742SEllis Hoag       Record.Counts.push_back(*Ptr == 0 ? 1 : 0);
50811d30742SEllis Hoag     } else {
50911d30742SEllis Hoag       const auto *CounterValue = reinterpret_cast<const uint64_t *>(Ptr);
510f2147375SEllis Hoag       Record.Counts.push_back(swap(*CounterValue));
511f2147375SEllis Hoag     }
51211d30742SEllis Hoag   }
51324b4b653SDuncan P. N. Exon Smith 
514cf4a128cSXinliang David Li   return success();
515cf4a128cSXinliang David Li }
516cf4a128cSXinliang David Li 
517cf4a128cSXinliang David Li template <class IntPtrT>
readValueProfilingData(InstrProfRecord & Record)5189152fd17SVedant Kumar Error RawInstrProfReader<IntPtrT>::readValueProfilingData(
5199152fd17SVedant Kumar     InstrProfRecord &Record) {
5206fac1741SBetul Buyukkurt   Record.clearValueData();
521d922c26cSXinliang David Li   CurValueDataSize = 0;
522d922c26cSXinliang David Li   // Need to match the logic in value profile dumper code in compiler-rt:
523d922c26cSXinliang David Li   uint32_t NumValueKinds = 0;
524d922c26cSXinliang David Li   for (uint32_t I = 0; I < IPVK_Last + 1; I++)
525d922c26cSXinliang David Li     NumValueKinds += (Data->NumValueSites[I] != 0);
526d922c26cSXinliang David Li 
527d922c26cSXinliang David Li   if (!NumValueKinds)
5286fac1741SBetul Buyukkurt     return success();
5296fac1741SBetul Buyukkurt 
5309152fd17SVedant Kumar   Expected<std::unique_ptr<ValueProfData>> VDataPtrOrErr =
531188a7c5fSXinliang David Li       ValueProfData::getValueProfData(
532188a7c5fSXinliang David Li           ValueDataStart, (const unsigned char *)DataBuffer->getBufferEnd(),
53301cb9bd7SXinliang David Li           getDataEndianness());
5346fac1741SBetul Buyukkurt 
5359152fd17SVedant Kumar   if (Error E = VDataPtrOrErr.takeError())
5369152fd17SVedant Kumar     return E;
5376fac1741SBetul Buyukkurt 
5382f36f059SAdam Nemet   // Note that besides deserialization, this also performs the conversion for
5392f36f059SAdam Nemet   // indirect call targets.  The function pointers from the raw profile are
5402f36f059SAdam Nemet   // remapped into function name hashes.
541556f8f6aSMircea Trofin   VDataPtrOrErr.get()->deserializeTo(Record, Symtab.get());
542d922c26cSXinliang David Li   CurValueDataSize = VDataPtrOrErr.get()->getSize();
5436fac1741SBetul Buyukkurt   return success();
5446fac1741SBetul Buyukkurt }
5456fac1741SBetul Buyukkurt 
5466fac1741SBetul Buyukkurt template <class IntPtrT>
readNextRecord(NamedInstrProfRecord & Record)547cf9d52c6SDavid Blaikie Error RawInstrProfReader<IntPtrT>::readNextRecord(NamedInstrProfRecord &Record) {
548cf4a128cSXinliang David Li   if (atEnd())
549188a7c5fSXinliang David Li     // At this point, ValueDataStart field points to the next header.
5509152fd17SVedant Kumar     if (Error E = readNextHeader(getNextHeaderPos()))
5515b63803dSMircea Trofin       return error(std::move(E));
552cf4a128cSXinliang David Li 
553cf4a128cSXinliang David Li   // Read name ad set it in Record.
5549152fd17SVedant Kumar   if (Error E = readName(Record))
5555b63803dSMircea Trofin     return error(std::move(E));
556cf4a128cSXinliang David Li 
557cf4a128cSXinliang David Li   // Read FuncHash and set it in Record.
5589152fd17SVedant Kumar   if (Error E = readFuncHash(Record))
5595b63803dSMircea Trofin     return error(std::move(E));
560cf4a128cSXinliang David Li 
561cf4a128cSXinliang David Li   // Read raw counts and set Record.
5629152fd17SVedant Kumar   if (Error E = readRawCounts(Record))
5635b63803dSMircea Trofin     return error(std::move(E));
564cf4a128cSXinliang David Li 
5656fac1741SBetul Buyukkurt   // Read value data and set Record.
5669152fd17SVedant Kumar   if (Error E = readValueProfilingData(Record))
5675b63803dSMircea Trofin     return error(std::move(E));
5686fac1741SBetul Buyukkurt 
56924b4b653SDuncan P. N. Exon Smith   // Iterate.
570cf4a128cSXinliang David Li   advanceData();
57124b4b653SDuncan P. N. Exon Smith   return success();
57224b4b653SDuncan P. N. Exon Smith }
5734680361dSDuncan P. N. Exon Smith 
RoundUp(size_t size,size_t align)574b9f547e8SLeonard Chan static size_t RoundUp(size_t size, size_t align) {
575b9f547e8SLeonard Chan   return (size + align - 1) & ~(align - 1);
576b9f547e8SLeonard Chan }
577b9f547e8SLeonard Chan 
578e50a3884SGulfem Savrun Yeniceri template <class IntPtrT>
printBinaryIds(raw_ostream & OS)579e50a3884SGulfem Savrun Yeniceri Error RawInstrProfReader<IntPtrT>::printBinaryIds(raw_ostream &OS) {
580e50a3884SGulfem Savrun Yeniceri   if (BinaryIdsSize == 0)
581e50a3884SGulfem Savrun Yeniceri     return success();
582e50a3884SGulfem Savrun Yeniceri 
583e50a3884SGulfem Savrun Yeniceri   OS << "Binary IDs: \n";
584e50a3884SGulfem Savrun Yeniceri   const uint8_t *BI = BinaryIdsStart;
585b9f547e8SLeonard Chan   const uint8_t *BIEnd = BinaryIdsStart + BinaryIdsSize;
586b9f547e8SLeonard Chan   while (BI < BIEnd) {
587b9f547e8SLeonard Chan     size_t Remaining = BIEnd - BI;
588b9f547e8SLeonard Chan 
589b9f547e8SLeonard Chan     // There should be enough left to read the binary ID size field.
590b9f547e8SLeonard Chan     if (Remaining < sizeof(uint64_t))
591ee88b8d6SGulfem Savrun Yeniceri       return make_error<InstrProfError>(
592ee88b8d6SGulfem Savrun Yeniceri           instrprof_error::malformed,
593ee88b8d6SGulfem Savrun Yeniceri           "not enough data to read binary id length");
594b9f547e8SLeonard Chan 
595e50a3884SGulfem Savrun Yeniceri     uint64_t BinaryIdLen = swap(*reinterpret_cast<const uint64_t *>(BI));
596b9f547e8SLeonard Chan 
597b9f547e8SLeonard Chan     // There should be enough left to read the binary ID size field, and the
598b9f547e8SLeonard Chan     // binary ID.
599b9f547e8SLeonard Chan     if (Remaining < sizeof(BinaryIdLen) + BinaryIdLen)
600ee88b8d6SGulfem Savrun Yeniceri       return make_error<InstrProfError>(
601ee88b8d6SGulfem Savrun Yeniceri           instrprof_error::malformed, "not enough data to read binary id data");
602b9f547e8SLeonard Chan 
603e50a3884SGulfem Savrun Yeniceri     // Increment by binary id length data type size.
604e50a3884SGulfem Savrun Yeniceri     BI += sizeof(BinaryIdLen);
605e50a3884SGulfem Savrun Yeniceri     if (BI > (const uint8_t *)DataBuffer->getBufferEnd())
606ee88b8d6SGulfem Savrun Yeniceri       return make_error<InstrProfError>(
607ee88b8d6SGulfem Savrun Yeniceri           instrprof_error::malformed,
608ee88b8d6SGulfem Savrun Yeniceri           "binary id that is read is bigger than buffer size");
609e50a3884SGulfem Savrun Yeniceri 
610e50a3884SGulfem Savrun Yeniceri     for (uint64_t I = 0; I < BinaryIdLen; I++)
611e50a3884SGulfem Savrun Yeniceri       OS << format("%02x", BI[I]);
612e50a3884SGulfem Savrun Yeniceri     OS << "\n";
613e50a3884SGulfem Savrun Yeniceri 
614b9f547e8SLeonard Chan     // Increment by binary id data length, rounded to the next 8 bytes. This
615b9f547e8SLeonard Chan     // accounts for the zero-padding after each build ID.
616b9f547e8SLeonard Chan     BI += RoundUp(BinaryIdLen, sizeof(uint64_t));
617e50a3884SGulfem Savrun Yeniceri     if (BI > (const uint8_t *)DataBuffer->getBufferEnd())
618e50a3884SGulfem Savrun Yeniceri       return make_error<InstrProfError>(instrprof_error::malformed);
619e50a3884SGulfem Savrun Yeniceri   }
620e50a3884SGulfem Savrun Yeniceri 
621e50a3884SGulfem Savrun Yeniceri   return success();
622e50a3884SGulfem Savrun Yeniceri }
623e50a3884SGulfem Savrun Yeniceri 
6244680361dSDuncan P. N. Exon Smith namespace llvm {
625e78d131aSEugene Zelenko 
6264680361dSDuncan P. N. Exon Smith template class RawInstrProfReader<uint32_t>;
6274680361dSDuncan P. N. Exon Smith template class RawInstrProfReader<uint64_t>;
628e78d131aSEugene Zelenko 
629e78d131aSEugene Zelenko } // end namespace llvm
630b7aa2630SJustin Bogner 
631b5d368e8SJustin Bogner InstrProfLookupTrait::hash_value_type
ComputeHash(StringRef K)632b5d368e8SJustin Bogner InstrProfLookupTrait::ComputeHash(StringRef K) {
633b5d368e8SJustin Bogner   return IndexedInstrProf::ComputeHash(HashType, K);
634b5d368e8SJustin Bogner }
635b5d368e8SJustin Bogner 
63672208a82SEugene Zelenko using data_type = InstrProfLookupTrait::data_type;
63772208a82SEugene Zelenko using offset_type = InstrProfLookupTrait::offset_type;
6383a7d44cbSJustin Bogner 
readValueProfilingData(const unsigned char * & D,const unsigned char * const End)639be969c29SXinliang David Li bool InstrProfLookupTrait::readValueProfilingData(
6409e9a057aSJustin Bogner     const unsigned char *&D, const unsigned char *const End) {
6419152fd17SVedant Kumar   Expected<std::unique_ptr<ValueProfData>> VDataPtrOrErr =
64299556877SXinliang David Li       ValueProfData::getValueProfData(D, End, ValueProfDataEndianness);
6439e9a057aSJustin Bogner 
6449152fd17SVedant Kumar   if (VDataPtrOrErr.takeError())
6459e9a057aSJustin Bogner     return false;
6462004f003SXinliang David Li 
647a716cc5cSXinliang David Li   VDataPtrOrErr.get()->deserializeTo(DataBuffer.back(), nullptr);
648ee415895SXinliang David Li   D += VDataPtrOrErr.get()->TotalSize;
6499e9a057aSJustin Bogner 
6509e9a057aSJustin Bogner   return true;
6519e9a057aSJustin Bogner }
6529e9a057aSJustin Bogner 
ReadData(StringRef K,const unsigned char * D,offset_type N)6533a7d44cbSJustin Bogner data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D,
6543a7d44cbSJustin Bogner                                          offset_type N) {
655e78d131aSEugene Zelenko   using namespace support;
656e78d131aSEugene Zelenko 
6573a7d44cbSJustin Bogner   // Check if the data is corrupt. If so, don't try to read it.
6583a7d44cbSJustin Bogner   if (N % sizeof(uint64_t))
6593a7d44cbSJustin Bogner     return data_type();
6603a7d44cbSJustin Bogner 
6613a7d44cbSJustin Bogner   DataBuffer.clear();
6623a7d44cbSJustin Bogner   std::vector<uint64_t> CounterBuffer;
6639e9a057aSJustin Bogner 
6649e9a057aSJustin Bogner   const unsigned char *End = D + N;
6659e9a057aSJustin Bogner   while (D < End) {
666c758387eSXinliang David Li     // Read hash.
6679e9a057aSJustin Bogner     if (D + sizeof(uint64_t) >= End)
6689e9a057aSJustin Bogner       return data_type();
6693a7d44cbSJustin Bogner     uint64_t Hash = endian::readNext<uint64_t, little, unaligned>(D);
6703a7d44cbSJustin Bogner 
67133c76c0cSRong Xu     // Initialize number of counters for GET_VERSION(FormatVersion) == 1.
6729e9a057aSJustin Bogner     uint64_t CountsSize = N / sizeof(uint64_t) - 1;
673c758387eSXinliang David Li     // If format version is different then read the number of counters.
67433c76c0cSRong Xu     if (GET_VERSION(FormatVersion) != IndexedInstrProf::ProfVersion::Version1) {
6759e9a057aSJustin Bogner       if (D + sizeof(uint64_t) > End)
6763a7d44cbSJustin Bogner         return data_type();
6779e9a057aSJustin Bogner       CountsSize = endian::readNext<uint64_t, little, unaligned>(D);
6789e9a057aSJustin Bogner     }
679c758387eSXinliang David Li     // Read counter values.
6809e9a057aSJustin Bogner     if (D + CountsSize * sizeof(uint64_t) > End)
6813a7d44cbSJustin Bogner       return data_type();
6823a7d44cbSJustin Bogner 
6833a7d44cbSJustin Bogner     CounterBuffer.clear();
6849e9a057aSJustin Bogner     CounterBuffer.reserve(CountsSize);
6859e9a057aSJustin Bogner     for (uint64_t J = 0; J < CountsSize; ++J)
6863a7d44cbSJustin Bogner       CounterBuffer.push_back(endian::readNext<uint64_t, little, unaligned>(D));
6873a7d44cbSJustin Bogner 
6882004f003SXinliang David Li     DataBuffer.emplace_back(K, Hash, std::move(CounterBuffer));
6899e9a057aSJustin Bogner 
690c758387eSXinliang David Li     // Read value profiling data.
69133c76c0cSRong Xu     if (GET_VERSION(FormatVersion) > IndexedInstrProf::ProfVersion::Version2 &&
692a6b2c4f7SXinliang David Li         !readValueProfilingData(D, End)) {
6939e9a057aSJustin Bogner       DataBuffer.clear();
6949e9a057aSJustin Bogner       return data_type();
6959e9a057aSJustin Bogner     }
6963a7d44cbSJustin Bogner   }
6973a7d44cbSJustin Bogner   return DataBuffer;
6983a7d44cbSJustin Bogner }
6993a7d44cbSJustin Bogner 
700a28306dbSXinliang David Li template <typename HashTableImpl>
getRecords(StringRef FuncName,ArrayRef<NamedInstrProfRecord> & Data)7019152fd17SVedant Kumar Error InstrProfReaderIndex<HashTableImpl>::getRecords(
702cf9d52c6SDavid Blaikie     StringRef FuncName, ArrayRef<NamedInstrProfRecord> &Data) {
703a28306dbSXinliang David Li   auto Iter = HashTable->find(FuncName);
704a28306dbSXinliang David Li   if (Iter == HashTable->end())
7059152fd17SVedant Kumar     return make_error<InstrProfError>(instrprof_error::unknown_function);
706140f4c4fSXinliang David Li 
707140f4c4fSXinliang David Li   Data = (*Iter);
7084c3ab815SXinliang David Li   if (Data.empty())
709ee88b8d6SGulfem Savrun Yeniceri     return make_error<InstrProfError>(instrprof_error::malformed,
710ee88b8d6SGulfem Savrun Yeniceri                                       "profile data is empty");
711140f4c4fSXinliang David Li 
7129152fd17SVedant Kumar   return Error::success();
713140f4c4fSXinliang David Li }
714140f4c4fSXinliang David Li 
715a28306dbSXinliang David Li template <typename HashTableImpl>
getRecords(ArrayRef<NamedInstrProfRecord> & Data)7169152fd17SVedant Kumar Error InstrProfReaderIndex<HashTableImpl>::getRecords(
717cf9d52c6SDavid Blaikie     ArrayRef<NamedInstrProfRecord> &Data) {
718a28306dbSXinliang David Li   if (atEnd())
7199152fd17SVedant Kumar     return make_error<InstrProfError>(instrprof_error::eof);
720140f4c4fSXinliang David Li 
721140f4c4fSXinliang David Li   Data = *RecordIterator;
722140f4c4fSXinliang David Li 
7232d4803e8SXinliang David Li   if (Data.empty())
724ee88b8d6SGulfem Savrun Yeniceri     return make_error<InstrProfError>(instrprof_error::malformed,
725ee88b8d6SGulfem Savrun Yeniceri                                       "profile data is empty");
726140f4c4fSXinliang David Li 
7279152fd17SVedant Kumar   return Error::success();
728140f4c4fSXinliang David Li }
729140f4c4fSXinliang David Li 
730a28306dbSXinliang David Li template <typename HashTableImpl>
InstrProfReaderIndex(const unsigned char * Buckets,const unsigned char * const Payload,const unsigned char * const Base,IndexedInstrProf::HashT HashType,uint64_t Version)731a28306dbSXinliang David Li InstrProfReaderIndex<HashTableImpl>::InstrProfReaderIndex(
732a28306dbSXinliang David Li     const unsigned char *Buckets, const unsigned char *const Payload,
733a28306dbSXinliang David Li     const unsigned char *const Base, IndexedInstrProf::HashT HashType,
734140f4c4fSXinliang David Li     uint64_t Version) {
735140f4c4fSXinliang David Li   FormatVersion = Version;
736a28306dbSXinliang David Li   HashTable.reset(HashTableImpl::Create(
737a28306dbSXinliang David Li       Buckets, Payload, Base,
738a28306dbSXinliang David Li       typename HashTableImpl::InfoType(HashType, Version)));
739a28306dbSXinliang David Li   RecordIterator = HashTable->data_begin();
740140f4c4fSXinliang David Li }
741140f4c4fSXinliang David Li 
742186dcd4aSSnehasish Kumar template <typename HashTableImpl>
getProfileKind() const743186dcd4aSSnehasish Kumar InstrProfKind InstrProfReaderIndex<HashTableImpl>::getProfileKind() const {
744186dcd4aSSnehasish Kumar   return getProfileKindFromVersion(FormatVersion);
745186dcd4aSSnehasish Kumar }
746186dcd4aSSnehasish Kumar 
747ceed4eb1SRichard Smith namespace {
748ceed4eb1SRichard Smith /// A remapper that does not apply any remappings.
749ceed4eb1SRichard Smith class InstrProfReaderNullRemapper : public InstrProfReaderRemapper {
750ceed4eb1SRichard Smith   InstrProfReaderIndexBase &Underlying;
751ceed4eb1SRichard Smith 
752ceed4eb1SRichard Smith public:
InstrProfReaderNullRemapper(InstrProfReaderIndexBase & Underlying)753ceed4eb1SRichard Smith   InstrProfReaderNullRemapper(InstrProfReaderIndexBase &Underlying)
754ceed4eb1SRichard Smith       : Underlying(Underlying) {}
755ceed4eb1SRichard Smith 
getRecords(StringRef FuncName,ArrayRef<NamedInstrProfRecord> & Data)756ceed4eb1SRichard Smith   Error getRecords(StringRef FuncName,
757ceed4eb1SRichard Smith                    ArrayRef<NamedInstrProfRecord> &Data) override {
758ceed4eb1SRichard Smith     return Underlying.getRecords(FuncName, Data);
759ceed4eb1SRichard Smith   }
760ceed4eb1SRichard Smith };
761ee88b8d6SGulfem Savrun Yeniceri } // namespace
762ceed4eb1SRichard Smith 
763ceed4eb1SRichard Smith /// A remapper that applies remappings based on a symbol remapping file.
764ceed4eb1SRichard Smith template <typename HashTableImpl>
765ceed4eb1SRichard Smith class llvm::InstrProfReaderItaniumRemapper
766ceed4eb1SRichard Smith     : public InstrProfReaderRemapper {
767ceed4eb1SRichard Smith public:
InstrProfReaderItaniumRemapper(std::unique_ptr<MemoryBuffer> RemapBuffer,InstrProfReaderIndex<HashTableImpl> & Underlying)768ceed4eb1SRichard Smith   InstrProfReaderItaniumRemapper(
769ceed4eb1SRichard Smith       std::unique_ptr<MemoryBuffer> RemapBuffer,
770ceed4eb1SRichard Smith       InstrProfReaderIndex<HashTableImpl> &Underlying)
771ceed4eb1SRichard Smith       : RemapBuffer(std::move(RemapBuffer)), Underlying(Underlying) {
772ceed4eb1SRichard Smith   }
773ceed4eb1SRichard Smith 
774ceed4eb1SRichard Smith   /// Extract the original function name from a PGO function name.
extractName(StringRef Name)775ceed4eb1SRichard Smith   static StringRef extractName(StringRef Name) {
776ceed4eb1SRichard Smith     // We can have multiple :-separated pieces; there can be pieces both
777ceed4eb1SRichard Smith     // before and after the mangled name. Find the first part that starts
778ceed4eb1SRichard Smith     // with '_Z'; we'll assume that's the mangled name we want.
779ceed4eb1SRichard Smith     std::pair<StringRef, StringRef> Parts = {StringRef(), Name};
780ceed4eb1SRichard Smith     while (true) {
781ceed4eb1SRichard Smith       Parts = Parts.second.split(':');
782ceed4eb1SRichard Smith       if (Parts.first.startswith("_Z"))
783ceed4eb1SRichard Smith         return Parts.first;
784ceed4eb1SRichard Smith       if (Parts.second.empty())
785ceed4eb1SRichard Smith         return Name;
786ceed4eb1SRichard Smith     }
787ceed4eb1SRichard Smith   }
788ceed4eb1SRichard Smith 
789ceed4eb1SRichard Smith   /// Given a mangled name extracted from a PGO function name, and a new
790ceed4eb1SRichard Smith   /// form for that mangled name, reconstitute the name.
reconstituteName(StringRef OrigName,StringRef ExtractedName,StringRef Replacement,SmallVectorImpl<char> & Out)791ceed4eb1SRichard Smith   static void reconstituteName(StringRef OrigName, StringRef ExtractedName,
792ceed4eb1SRichard Smith                                StringRef Replacement,
793ceed4eb1SRichard Smith                                SmallVectorImpl<char> &Out) {
794ceed4eb1SRichard Smith     Out.reserve(OrigName.size() + Replacement.size() - ExtractedName.size());
795ceed4eb1SRichard Smith     Out.insert(Out.end(), OrigName.begin(), ExtractedName.begin());
796ceed4eb1SRichard Smith     Out.insert(Out.end(), Replacement.begin(), Replacement.end());
797ceed4eb1SRichard Smith     Out.insert(Out.end(), ExtractedName.end(), OrigName.end());
798ceed4eb1SRichard Smith   }
799ceed4eb1SRichard Smith 
populateRemappings()800ceed4eb1SRichard Smith   Error populateRemappings() override {
801ceed4eb1SRichard Smith     if (Error E = Remappings.read(*RemapBuffer))
802ceed4eb1SRichard Smith       return E;
803ceed4eb1SRichard Smith     for (StringRef Name : Underlying.HashTable->keys()) {
804ceed4eb1SRichard Smith       StringRef RealName = extractName(Name);
805ceed4eb1SRichard Smith       if (auto Key = Remappings.insert(RealName)) {
806ceed4eb1SRichard Smith         // FIXME: We could theoretically map the same equivalence class to
807ceed4eb1SRichard Smith         // multiple names in the profile data. If that happens, we should
808ceed4eb1SRichard Smith         // return NamedInstrProfRecords from all of them.
809ceed4eb1SRichard Smith         MappedNames.insert({Key, RealName});
810ceed4eb1SRichard Smith       }
811ceed4eb1SRichard Smith     }
812ceed4eb1SRichard Smith     return Error::success();
813ceed4eb1SRichard Smith   }
814ceed4eb1SRichard Smith 
getRecords(StringRef FuncName,ArrayRef<NamedInstrProfRecord> & Data)815ceed4eb1SRichard Smith   Error getRecords(StringRef FuncName,
816ceed4eb1SRichard Smith                    ArrayRef<NamedInstrProfRecord> &Data) override {
817ceed4eb1SRichard Smith     StringRef RealName = extractName(FuncName);
818ceed4eb1SRichard Smith     if (auto Key = Remappings.lookup(RealName)) {
819ceed4eb1SRichard Smith       StringRef Remapped = MappedNames.lookup(Key);
820ceed4eb1SRichard Smith       if (!Remapped.empty()) {
821ceed4eb1SRichard Smith         if (RealName.begin() == FuncName.begin() &&
822ceed4eb1SRichard Smith             RealName.end() == FuncName.end())
823ceed4eb1SRichard Smith           FuncName = Remapped;
824ceed4eb1SRichard Smith         else {
825ceed4eb1SRichard Smith           // Try rebuilding the name from the given remapping.
826ceed4eb1SRichard Smith           SmallString<256> Reconstituted;
827ceed4eb1SRichard Smith           reconstituteName(FuncName, RealName, Remapped, Reconstituted);
828ceed4eb1SRichard Smith           Error E = Underlying.getRecords(Reconstituted, Data);
829ceed4eb1SRichard Smith           if (!E)
830ceed4eb1SRichard Smith             return E;
831ceed4eb1SRichard Smith 
832ceed4eb1SRichard Smith           // If we failed because the name doesn't exist, fall back to asking
833ceed4eb1SRichard Smith           // about the original name.
834ceed4eb1SRichard Smith           if (Error Unhandled = handleErrors(
835ceed4eb1SRichard Smith                   std::move(E), [](std::unique_ptr<InstrProfError> Err) {
836ceed4eb1SRichard Smith                     return Err->get() == instrprof_error::unknown_function
837ceed4eb1SRichard Smith                                ? Error::success()
838ceed4eb1SRichard Smith                                : Error(std::move(Err));
839ceed4eb1SRichard Smith                   }))
840ceed4eb1SRichard Smith             return Unhandled;
841ceed4eb1SRichard Smith         }
842ceed4eb1SRichard Smith       }
843ceed4eb1SRichard Smith     }
844ceed4eb1SRichard Smith     return Underlying.getRecords(FuncName, Data);
845ceed4eb1SRichard Smith   }
846ceed4eb1SRichard Smith 
847ceed4eb1SRichard Smith private:
848ceed4eb1SRichard Smith   /// The memory buffer containing the remapping configuration. Remappings
849ceed4eb1SRichard Smith   /// holds pointers into this buffer.
850ceed4eb1SRichard Smith   std::unique_ptr<MemoryBuffer> RemapBuffer;
851ceed4eb1SRichard Smith 
852ceed4eb1SRichard Smith   /// The mangling remapper.
853ceed4eb1SRichard Smith   SymbolRemappingReader Remappings;
854ceed4eb1SRichard Smith 
855ceed4eb1SRichard Smith   /// Mapping from mangled name keys to the name used for the key in the
856ceed4eb1SRichard Smith   /// profile data.
857ceed4eb1SRichard Smith   /// FIXME: Can we store a location within the on-disk hash table instead of
858ceed4eb1SRichard Smith   /// redoing lookup?
859ceed4eb1SRichard Smith   DenseMap<SymbolRemappingReader::Key, StringRef> MappedNames;
860ceed4eb1SRichard Smith 
861ceed4eb1SRichard Smith   /// The real profile data reader.
862ceed4eb1SRichard Smith   InstrProfReaderIndex<HashTableImpl> &Underlying;
863ceed4eb1SRichard Smith };
864ceed4eb1SRichard Smith 
hasFormat(const MemoryBuffer & DataBuffer)865b7aa2630SJustin Bogner bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) {
866e78d131aSEugene Zelenko   using namespace support;
867e78d131aSEugene Zelenko 
8684c3ab815SXinliang David Li   if (DataBuffer.getBufferSize() < 8)
8694c3ab815SXinliang David Li     return false;
870b7aa2630SJustin Bogner   uint64_t Magic =
871b7aa2630SJustin Bogner       endian::read<uint64_t, little, aligned>(DataBuffer.getBufferStart());
872c758387eSXinliang David Li   // Verify that it's magical.
873b7aa2630SJustin Bogner   return Magic == IndexedInstrProf::Magic;
874b7aa2630SJustin Bogner }
875b7aa2630SJustin Bogner 
8766c93ee8dSXinliang David Li const unsigned char *
readSummary(IndexedInstrProf::ProfVersion Version,const unsigned char * Cur,bool UseCS)8776c93ee8dSXinliang David Li IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version,
878a6ff69f6SRong Xu                                     const unsigned char *Cur, bool UseCS) {
879e5a17e3fSEaswaran Raman   using namespace IndexedInstrProf;
8806c93ee8dSXinliang David Li   using namespace support;
881e78d131aSEugene Zelenko 
8826c93ee8dSXinliang David Li   if (Version >= IndexedInstrProf::Version4) {
8836c93ee8dSXinliang David Li     const IndexedInstrProf::Summary *SummaryInLE =
8846c93ee8dSXinliang David Li         reinterpret_cast<const IndexedInstrProf::Summary *>(Cur);
8856c93ee8dSXinliang David Li     uint64_t NFields =
8866c93ee8dSXinliang David Li         endian::byte_swap<uint64_t, little>(SummaryInLE->NumSummaryFields);
8876c93ee8dSXinliang David Li     uint64_t NEntries =
8886c93ee8dSXinliang David Li         endian::byte_swap<uint64_t, little>(SummaryInLE->NumCutoffEntries);
8896c93ee8dSXinliang David Li     uint32_t SummarySize =
8906c93ee8dSXinliang David Li         IndexedInstrProf::Summary::getSize(NFields, NEntries);
8916c93ee8dSXinliang David Li     std::unique_ptr<IndexedInstrProf::Summary> SummaryData =
8926c93ee8dSXinliang David Li         IndexedInstrProf::allocSummary(SummarySize);
8936c93ee8dSXinliang David Li 
8946c93ee8dSXinliang David Li     const uint64_t *Src = reinterpret_cast<const uint64_t *>(SummaryInLE);
8956c93ee8dSXinliang David Li     uint64_t *Dst = reinterpret_cast<uint64_t *>(SummaryData.get());
8966c93ee8dSXinliang David Li     for (unsigned I = 0; I < SummarySize / sizeof(uint64_t); I++)
8976c93ee8dSXinliang David Li       Dst[I] = endian::byte_swap<uint64_t, little>(Src[I]);
8986c93ee8dSXinliang David Li 
89972208a82SEugene Zelenko     SummaryEntryVector DetailedSummary;
900e5a17e3fSEaswaran Raman     for (unsigned I = 0; I < SummaryData->NumCutoffEntries; I++) {
901e5a17e3fSEaswaran Raman       const IndexedInstrProf::Summary::Entry &Ent = SummaryData->getEntry(I);
902e5a17e3fSEaswaran Raman       DetailedSummary.emplace_back((uint32_t)Ent.Cutoff, Ent.MinBlockCount,
903e5a17e3fSEaswaran Raman                                    Ent.NumBlocks);
904e5a17e3fSEaswaran Raman     }
905a6ff69f6SRong Xu     std::unique_ptr<llvm::ProfileSummary> &Summary =
906a6ff69f6SRong Xu         UseCS ? this->CS_Summary : this->Summary;
907a6ff69f6SRong Xu 
9084309570dSEaswaran Raman     // initialize InstrProfSummary using the SummaryData from disk.
9090eaee545SJonas Devlieghere     Summary = std::make_unique<ProfileSummary>(
910a6ff69f6SRong Xu         UseCS ? ProfileSummary::PSK_CSInstr : ProfileSummary::PSK_Instr,
911a6ff69f6SRong Xu         DetailedSummary, SummaryData->get(Summary::TotalBlockCount),
912e5a17e3fSEaswaran Raman         SummaryData->get(Summary::MaxBlockCount),
913e5a17e3fSEaswaran Raman         SummaryData->get(Summary::MaxInternalBlockCount),
914e5a17e3fSEaswaran Raman         SummaryData->get(Summary::MaxFunctionCount),
915e5a17e3fSEaswaran Raman         SummaryData->get(Summary::TotalNumBlocks),
9167cefdb81SEaswaran Raman         SummaryData->get(Summary::TotalNumFunctions));
9176c93ee8dSXinliang David Li     return Cur + SummarySize;
9186c93ee8dSXinliang David Li   } else {
919fd2044f2STeresa Johnson     // The older versions do not support a profile summary. This just computes
920fd2044f2STeresa Johnson     // an empty summary, which will not result in accurate hot/cold detection.
921fd2044f2STeresa Johnson     // We would need to call addRecord for all NamedInstrProfRecords to get the
922fd2044f2STeresa Johnson     // correct summary. However, this version is old (prior to early 2016) and
923fd2044f2STeresa Johnson     // has not been supporting an accurate summary for several years.
924e5a17e3fSEaswaran Raman     InstrProfSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
925fd2044f2STeresa Johnson     Summary = Builder.getSummary();
9266c93ee8dSXinliang David Li     return Cur;
9276c93ee8dSXinliang David Li   }
9286c93ee8dSXinliang David Li }
9296c93ee8dSXinliang David Li 
readHeader()9309152fd17SVedant Kumar Error IndexedInstrProfReader::readHeader() {
931e78d131aSEugene Zelenko   using namespace support;
932e78d131aSEugene Zelenko 
933a7c9ed57SAaron Ballman   const unsigned char *Start =
934a7c9ed57SAaron Ballman       (const unsigned char *)DataBuffer->getBufferStart();
935b7aa2630SJustin Bogner   const unsigned char *Cur = Start;
936a7c9ed57SAaron Ballman   if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24)
937b7aa2630SJustin Bogner     return error(instrprof_error::truncated);
938b7aa2630SJustin Bogner 
939a3beb340SSnehasish Kumar   auto HeaderOr = IndexedInstrProf::Header::readFromBuffer(Start);
940a3beb340SSnehasish Kumar   if (!HeaderOr)
941a3beb340SSnehasish Kumar     return HeaderOr.takeError();
942dab183edSXinliang David Li 
943a3beb340SSnehasish Kumar   const IndexedInstrProf::Header *Header = &HeaderOr.get();
944a3beb340SSnehasish Kumar   Cur += Header->size();
945b7aa2630SJustin Bogner 
946a3beb340SSnehasish Kumar   Cur = readSummary((IndexedInstrProf::ProfVersion)Header->formatVersion(), Cur,
947a6ff69f6SRong Xu                     /* UseCS */ false);
948a3beb340SSnehasish Kumar   if (Header->formatVersion() & VARIANT_MASK_CSIR_PROF)
949a3beb340SSnehasish Kumar     Cur = readSummary((IndexedInstrProf::ProfVersion)Header->formatVersion(), Cur,
950a6ff69f6SRong Xu                       /* UseCS */ true);
951b7aa2630SJustin Bogner 
952b7aa2630SJustin Bogner   // Read the hash type and start offset.
953b7aa2630SJustin Bogner   IndexedInstrProf::HashT HashType = static_cast<IndexedInstrProf::HashT>(
954dab183edSXinliang David Li       endian::byte_swap<uint64_t, little>(Header->HashType));
955b7aa2630SJustin Bogner   if (HashType > IndexedInstrProf::HashT::Last)
956b7aa2630SJustin Bogner     return error(instrprof_error::unsupported_hash_type);
957dab183edSXinliang David Li 
958dab183edSXinliang David Li   uint64_t HashOffset = endian::byte_swap<uint64_t, little>(Header->HashOffset);
959b7aa2630SJustin Bogner 
9600a418490SSnehasish Kumar   // The hash table with profile counts comes next.
961a3beb340SSnehasish Kumar   auto IndexPtr = std::make_unique<InstrProfReaderIndex<OnDiskHashTableImplV3>>(
962a3beb340SSnehasish Kumar       Start + HashOffset, Cur, Start, HashType, Header->formatVersion());
963ceed4eb1SRichard Smith 
9640a418490SSnehasish Kumar   // The MemProfOffset field in the header is only valid when the format version
9650a418490SSnehasish Kumar   // is higher than 8 (when it was introduced).
9660a418490SSnehasish Kumar   if (GET_VERSION(Header->formatVersion()) >= 8 &&
9670a418490SSnehasish Kumar       Header->formatVersion() & VARIANT_MASK_MEMPROF) {
9680a418490SSnehasish Kumar     uint64_t MemProfOffset =
9690a418490SSnehasish Kumar         endian::byte_swap<uint64_t, little>(Header->MemProfOffset);
9700a418490SSnehasish Kumar 
9710a418490SSnehasish Kumar     const unsigned char *Ptr = Start + MemProfOffset;
9726dd6a616SSnehasish Kumar     // The value returned from RecordTableGenerator.Emit.
9736dd6a616SSnehasish Kumar     const uint64_t RecordTableOffset =
9746dd6a616SSnehasish Kumar         support::endian::readNext<uint64_t, little, unaligned>(Ptr);
9756dd6a616SSnehasish Kumar     // The offset in the stream right before invoking FrameTableGenerator.Emit.
9766dd6a616SSnehasish Kumar     const uint64_t FramePayloadOffset =
9776dd6a616SSnehasish Kumar         support::endian::readNext<uint64_t, little, unaligned>(Ptr);
9786dd6a616SSnehasish Kumar     // The value returned from FrameTableGenerator.Emit.
9796dd6a616SSnehasish Kumar     const uint64_t FrameTableOffset =
9800a418490SSnehasish Kumar         support::endian::readNext<uint64_t, little, unaligned>(Ptr);
9810a418490SSnehasish Kumar 
9820a418490SSnehasish Kumar     // Read the schema.
9830a418490SSnehasish Kumar     auto SchemaOr = memprof::readMemProfSchema(Ptr);
9840a418490SSnehasish Kumar     if (!SchemaOr)
9850a418490SSnehasish Kumar       return SchemaOr.takeError();
9860a418490SSnehasish Kumar     Schema = SchemaOr.get();
9870a418490SSnehasish Kumar 
9880a418490SSnehasish Kumar     // Now initialize the table reader with a pointer into data buffer.
9896dd6a616SSnehasish Kumar     MemProfRecordTable.reset(MemProfRecordHashTable::Create(
9906dd6a616SSnehasish Kumar         /*Buckets=*/Start + RecordTableOffset,
9910a418490SSnehasish Kumar         /*Payload=*/Ptr,
9926dd6a616SSnehasish Kumar         /*Base=*/Start, memprof::RecordLookupTrait(Schema)));
9936dd6a616SSnehasish Kumar 
9946dd6a616SSnehasish Kumar     // Initialize the frame table reader with the payload and bucket offsets.
9956dd6a616SSnehasish Kumar     MemProfFrameTable.reset(MemProfFrameHashTable::Create(
9966dd6a616SSnehasish Kumar         /*Buckets=*/Start + FrameTableOffset,
9976dd6a616SSnehasish Kumar         /*Payload=*/Start + FramePayloadOffset,
9986dd6a616SSnehasish Kumar         /*Base=*/Start, memprof::FrameLookupTrait()));
9990a418490SSnehasish Kumar   }
10000a418490SSnehasish Kumar 
1001ceed4eb1SRichard Smith   // Load the remapping table now if requested.
1002ceed4eb1SRichard Smith   if (RemappingBuffer) {
10030eaee545SJonas Devlieghere     Remapper = std::make_unique<
1004ceed4eb1SRichard Smith         InstrProfReaderItaniumRemapper<OnDiskHashTableImplV3>>(
1005ceed4eb1SRichard Smith         std::move(RemappingBuffer), *IndexPtr);
1006ceed4eb1SRichard Smith     if (Error E = Remapper->populateRemappings())
1007ceed4eb1SRichard Smith       return E;
1008ceed4eb1SRichard Smith   } else {
10090eaee545SJonas Devlieghere     Remapper = std::make_unique<InstrProfReaderNullRemapper>(*IndexPtr);
1010ceed4eb1SRichard Smith   }
1011ceed4eb1SRichard Smith   Index = std::move(IndexPtr);
1012ceed4eb1SRichard Smith 
1013b7aa2630SJustin Bogner   return success();
1014b7aa2630SJustin Bogner }
1015b7aa2630SJustin Bogner 
getSymtab()1016a716cc5cSXinliang David Li InstrProfSymtab &IndexedInstrProfReader::getSymtab() {
101714415a3aSKazu Hirata   if (Symtab)
101814415a3aSKazu Hirata     return *Symtab;
1019a716cc5cSXinliang David Li 
10200eaee545SJonas Devlieghere   std::unique_ptr<InstrProfSymtab> NewSymtab = std::make_unique<InstrProfSymtab>();
102114415a3aSKazu Hirata   if (Error E = Index->populateSymtab(*NewSymtab)) {
1022b5794ca9SVedant Kumar     consumeError(error(InstrProfError::take(std::move(E))));
1023b5794ca9SVedant Kumar   }
1024a716cc5cSXinliang David Li 
1025a716cc5cSXinliang David Li   Symtab = std::move(NewSymtab);
102614415a3aSKazu Hirata   return *Symtab;
1027a716cc5cSXinliang David Li }
1028a716cc5cSXinliang David Li 
getInstrProfRecord(StringRef FuncName,uint64_t FuncHash,uint64_t * MismatchedFuncSum)1029*5e044329SRong Xu Expected<InstrProfRecord> IndexedInstrProfReader::getInstrProfRecord(
1030*5e044329SRong Xu     StringRef FuncName, uint64_t FuncHash, uint64_t *MismatchedFuncSum) {
1031cf9d52c6SDavid Blaikie   ArrayRef<NamedInstrProfRecord> Data;
1032*5e044329SRong Xu   uint64_t FuncSum = 0;
1033ceed4eb1SRichard Smith   Error Err = Remapper->getRecords(FuncName, Data);
10349152fd17SVedant Kumar   if (Err)
1035c55cf4afSBill Wendling     return std::move(Err);
1036821d7471SJustin Bogner   // Found it. Look for counters with the right hash.
10374a40fa82SRong Xu 
10384a40fa82SRong Xu   // A flag to indicate if the records are from the same type
10394a40fa82SRong Xu   // of profile (i.e cs vs nocs).
10404a40fa82SRong Xu   bool CSBitMatch = false;
1041*5e044329SRong Xu   auto getFuncSum = [](const std::vector<uint64_t> &Counts) {
1042*5e044329SRong Xu     uint64_t ValueSum = 0;
1043*5e044329SRong Xu     for (unsigned I = 0, S = Counts.size(); I < S; I++) {
1044*5e044329SRong Xu       uint64_t CountValue = Counts[I];
1045*5e044329SRong Xu       if (CountValue == (uint64_t)-1)
1046*5e044329SRong Xu         continue;
1047*5e044329SRong Xu       // Handle overflow -- if that happens, return max.
1048*5e044329SRong Xu       if (std::numeric_limits<uint64_t>::max() - CountValue <= ValueSum)
1049*5e044329SRong Xu         return std::numeric_limits<uint64_t>::max();
1050*5e044329SRong Xu       ValueSum += CountValue;
1051*5e044329SRong Xu     }
1052*5e044329SRong Xu     return ValueSum;
1053*5e044329SRong Xu   };
10544a40fa82SRong Xu 
1055ccdd5bb2SKazu Hirata   for (const NamedInstrProfRecord &I : Data) {
1056821d7471SJustin Bogner     // Check for a match and fill the vector if there is one.
1057ccdd5bb2SKazu Hirata     if (I.Hash == FuncHash)
1058ccdd5bb2SKazu Hirata       return std::move(I);
10594a40fa82SRong Xu     if (NamedInstrProfRecord::hasCSFlagInHash(I.Hash) ==
10604a40fa82SRong Xu         NamedInstrProfRecord::hasCSFlagInHash(FuncHash)) {
10614a40fa82SRong Xu       CSBitMatch = true;
1062*5e044329SRong Xu       if (MismatchedFuncSum == nullptr)
1063*5e044329SRong Xu         continue;
1064*5e044329SRong Xu       FuncSum = std::max(FuncSum, getFuncSum(I.Counts));
1065821d7471SJustin Bogner     }
10664a40fa82SRong Xu   }
10674a40fa82SRong Xu   if (CSBitMatch) {
1068*5e044329SRong Xu     if (MismatchedFuncSum != nullptr)
1069*5e044329SRong Xu       *MismatchedFuncSum = FuncSum;
1070821d7471SJustin Bogner     return error(instrprof_error::hash_mismatch);
1071821d7471SJustin Bogner   }
10724a40fa82SRong Xu   return error(instrprof_error::unknown_function);
10734a40fa82SRong Xu }
1074b7aa2630SJustin Bogner 
10756dd6a616SSnehasish Kumar Expected<memprof::MemProfRecord>
getMemProfRecord(const uint64_t FuncNameHash)10760a418490SSnehasish Kumar IndexedInstrProfReader::getMemProfRecord(const uint64_t FuncNameHash) {
10770a418490SSnehasish Kumar   // TODO: Add memprof specific errors.
10786dd6a616SSnehasish Kumar   if (MemProfRecordTable == nullptr)
10790a418490SSnehasish Kumar     return make_error<InstrProfError>(instrprof_error::invalid_prof,
10800a418490SSnehasish Kumar                                       "no memprof data available in profile");
10816dd6a616SSnehasish Kumar   auto Iter = MemProfRecordTable->find(FuncNameHash);
10826dd6a616SSnehasish Kumar   if (Iter == MemProfRecordTable->end())
108365529486STeresa Johnson     return make_error<InstrProfError>(
108465529486STeresa Johnson         instrprof_error::unknown_function,
108565529486STeresa Johnson         "memprof record not found for function hash " + Twine(FuncNameHash));
10866dd6a616SSnehasish Kumar 
10876dd6a616SSnehasish Kumar   // Setup a callback to convert from frame ids to frame using the on-disk
10886dd6a616SSnehasish Kumar   // FrameData hash table.
10896dd6a616SSnehasish Kumar   memprof::FrameId LastUnmappedFrameId = 0;
10906dd6a616SSnehasish Kumar   bool HasFrameMappingError = false;
10916dd6a616SSnehasish Kumar   auto IdToFrameCallback = [&](const memprof::FrameId Id) {
10926dd6a616SSnehasish Kumar     auto FrIter = MemProfFrameTable->find(Id);
10936dd6a616SSnehasish Kumar     if (FrIter == MemProfFrameTable->end()) {
10946dd6a616SSnehasish Kumar       LastUnmappedFrameId = Id;
10956dd6a616SSnehasish Kumar       HasFrameMappingError = true;
10966dd6a616SSnehasish Kumar       return memprof::Frame(0, 0, 0, false);
10976dd6a616SSnehasish Kumar     }
10986dd6a616SSnehasish Kumar     return *FrIter;
10996dd6a616SSnehasish Kumar   };
11006dd6a616SSnehasish Kumar 
11016dd6a616SSnehasish Kumar   memprof::MemProfRecord Record(*Iter, IdToFrameCallback);
11026dd6a616SSnehasish Kumar 
11036dd6a616SSnehasish Kumar   // Check that all frame ids were successfully converted to frames.
11046dd6a616SSnehasish Kumar   if (HasFrameMappingError) {
11056dd6a616SSnehasish Kumar     return make_error<InstrProfError>(instrprof_error::hash_mismatch,
11066dd6a616SSnehasish Kumar                                       "memprof frame not found for frame id " +
11076dd6a616SSnehasish Kumar                                           Twine(LastUnmappedFrameId));
11086dd6a616SSnehasish Kumar   }
11096dd6a616SSnehasish Kumar   return Record;
11100a418490SSnehasish Kumar }
11110a418490SSnehasish Kumar 
getFunctionCounts(StringRef FuncName,uint64_t FuncHash,std::vector<uint64_t> & Counts)11129152fd17SVedant Kumar Error IndexedInstrProfReader::getFunctionCounts(StringRef FuncName,
11139152fd17SVedant Kumar                                                 uint64_t FuncHash,
11146aa216c2SXinliang David Li                                                 std::vector<uint64_t> &Counts) {
11159152fd17SVedant Kumar   Expected<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash);
11169152fd17SVedant Kumar   if (Error E = Record.takeError())
11179152fd17SVedant Kumar     return error(std::move(E));
11182004f003SXinliang David Li 
11192004f003SXinliang David Li   Counts = Record.get().Counts;
11202004f003SXinliang David Li   return success();
11212004f003SXinliang David Li }
11222004f003SXinliang David Li 
readNextRecord(NamedInstrProfRecord & Record)1123cf9d52c6SDavid Blaikie Error IndexedInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
1124cf9d52c6SDavid Blaikie   ArrayRef<NamedInstrProfRecord> Data;
1125140f4c4fSXinliang David Li 
11269152fd17SVedant Kumar   Error E = Index->getRecords(Data);
11279152fd17SVedant Kumar   if (E)
11289152fd17SVedant Kumar     return error(std::move(E));
1129140f4c4fSXinliang David Li 
11303a7d44cbSJustin Bogner   Record = Data[RecordIndex++];
11313a7d44cbSJustin Bogner   if (RecordIndex >= Data.size()) {
1132a28306dbSXinliang David Li     Index->advanceToNextKey();
11333a7d44cbSJustin Bogner     RecordIndex = 0;
1134821d7471SJustin Bogner   }
1135b7aa2630SJustin Bogner   return success();
1136b7aa2630SJustin Bogner }
1137998b97f6SRong Xu 
accumulateCounts(CountSumOrPercent & Sum,bool IsCS)1138e0fa2689SRong Xu void InstrProfReader::accumulateCounts(CountSumOrPercent &Sum, bool IsCS) {
1139998b97f6SRong Xu   uint64_t NumFuncs = 0;
1140998b97f6SRong Xu   for (const auto &Func : *this) {
1141998b97f6SRong Xu     if (isIRLevelProfile()) {
1142998b97f6SRong Xu       bool FuncIsCS = NamedInstrProfRecord::hasCSFlagInHash(Func.Hash);
1143998b97f6SRong Xu       if (FuncIsCS != IsCS)
1144998b97f6SRong Xu         continue;
1145998b97f6SRong Xu     }
1146e0fa2689SRong Xu     Func.accumulateCounts(Sum);
1147998b97f6SRong Xu     ++NumFuncs;
1148998b97f6SRong Xu   }
1149998b97f6SRong Xu   Sum.NumEntries = NumFuncs;
1150998b97f6SRong Xu }
1151