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"
170a446fd5SBenjamin Kramer #include "llvm/ADT/STLExtras.h"
18e78d131aSEugene Zelenko #include "llvm/ADT/StringRef.h"
19e78d131aSEugene Zelenko #include "llvm/IR/ProfileSummary.h"
20e78d131aSEugene Zelenko #include "llvm/ProfileData/InstrProf.h"
21e78d131aSEugene Zelenko #include "llvm/ProfileData/ProfileCommon.h"
22e78d131aSEugene Zelenko #include "llvm/Support/Endian.h"
23e78d131aSEugene Zelenko #include "llvm/Support/Error.h"
24e78d131aSEugene Zelenko #include "llvm/Support/ErrorOr.h"
25e78d131aSEugene Zelenko #include "llvm/Support/MemoryBuffer.h"
26ceed4eb1SRichard Smith #include "llvm/Support/SymbolRemappingReader.h"
27e78d131aSEugene Zelenko #include "llvm/Support/SwapByteOrder.h"
28e78d131aSEugene Zelenko #include <algorithm>
29e78d131aSEugene Zelenko #include <cctype>
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 
409152fd17SVedant Kumar static Expected<std::unique_ptr<MemoryBuffer>>
410da23a27SBenjamin Kramer setupMemoryBuffer(const Twine &Path) {
42adf21f2aSRafael Espindola   ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
43adf21f2aSRafael Espindola       MemoryBuffer::getFileOrSTDIN(Path);
44adf21f2aSRafael Espindola   if (std::error_code EC = BufferOrErr.getError())
459152fd17SVedant Kumar     return errorCodeToError(EC);
462b6c537bSJustin Bogner   return std::move(BufferOrErr.get());
47b7aa2630SJustin Bogner }
48b7aa2630SJustin Bogner 
499152fd17SVedant Kumar static Error initializeReader(InstrProfReader &Reader) {
50b7aa2630SJustin Bogner   return Reader.readHeader();
51b7aa2630SJustin Bogner }
52b7aa2630SJustin Bogner 
539152fd17SVedant Kumar Expected<std::unique_ptr<InstrProfReader>>
540da23a27SBenjamin Kramer InstrProfReader::create(const Twine &Path) {
55b7aa2630SJustin Bogner   // Set up the buffer to read.
56fcd55607SDiego Novillo   auto BufferOrError = setupMemoryBuffer(Path);
579152fd17SVedant Kumar   if (Error E = BufferOrError.takeError())
589152fd17SVedant Kumar     return std::move(E);
592b6c537bSJustin Bogner   return InstrProfReader::create(std::move(BufferOrError.get()));
602b6c537bSJustin Bogner }
61f8d79198SJustin Bogner 
629152fd17SVedant Kumar Expected<std::unique_ptr<InstrProfReader>>
632b6c537bSJustin Bogner InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer) {
642b6c537bSJustin Bogner   // Sanity check the buffer.
65d6c15b66SVedant Kumar   if (uint64_t(Buffer->getBufferSize()) > std::numeric_limits<uint64_t>::max())
669152fd17SVedant Kumar     return make_error<InstrProfError>(instrprof_error::too_large);
672b6c537bSJustin Bogner 
682c684cfdSRong Xu   if (Buffer->getBufferSize() == 0)
692c684cfdSRong Xu     return make_error<InstrProfError>(instrprof_error::empty_raw_profile);
702c684cfdSRong Xu 
71fcd55607SDiego Novillo   std::unique_ptr<InstrProfReader> Result;
7209a67f45SDuncan P. N. Exon Smith   // Create the reader.
73b7aa2630SJustin Bogner   if (IndexedInstrProfReader::hasFormat(*Buffer))
74b7aa2630SJustin Bogner     Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
75b7aa2630SJustin Bogner   else if (RawInstrProfReader64::hasFormat(*Buffer))
764680361dSDuncan P. N. Exon Smith     Result.reset(new RawInstrProfReader64(std::move(Buffer)));
774680361dSDuncan P. N. Exon Smith   else if (RawInstrProfReader32::hasFormat(*Buffer))
784680361dSDuncan P. N. Exon Smith     Result.reset(new RawInstrProfReader32(std::move(Buffer)));
794f823667SNathan Slingerland   else if (TextInstrProfReader::hasFormat(*Buffer))
80911ced6bSNathan Slingerland     Result.reset(new TextInstrProfReader(std::move(Buffer)));
814f823667SNathan Slingerland   else
829152fd17SVedant Kumar     return make_error<InstrProfError>(instrprof_error::unrecognized_format);
8309a67f45SDuncan P. N. Exon Smith 
84b7aa2630SJustin Bogner   // Initialize the reader and return the result.
859152fd17SVedant Kumar   if (Error E = initializeReader(*Result))
869152fd17SVedant Kumar     return std::move(E);
87fcd55607SDiego Novillo 
88fcd55607SDiego Novillo   return std::move(Result);
89b7aa2630SJustin Bogner }
90b7aa2630SJustin Bogner 
919152fd17SVedant Kumar Expected<std::unique_ptr<IndexedInstrProfReader>>
92ceed4eb1SRichard Smith IndexedInstrProfReader::create(const Twine &Path, const Twine &RemappingPath) {
93b7aa2630SJustin Bogner   // Set up the buffer to read.
94fcd55607SDiego Novillo   auto BufferOrError = setupMemoryBuffer(Path);
959152fd17SVedant Kumar   if (Error E = BufferOrError.takeError())
969152fd17SVedant Kumar     return std::move(E);
97ceed4eb1SRichard Smith 
98ceed4eb1SRichard Smith   // Set up the remapping buffer if requested.
99ceed4eb1SRichard Smith   std::unique_ptr<MemoryBuffer> RemappingBuffer;
100ceed4eb1SRichard Smith   std::string RemappingPathStr = RemappingPath.str();
101ceed4eb1SRichard Smith   if (!RemappingPathStr.empty()) {
102ceed4eb1SRichard Smith     auto RemappingBufferOrError = setupMemoryBuffer(RemappingPathStr);
103ceed4eb1SRichard Smith     if (Error E = RemappingBufferOrError.takeError())
104ceed4eb1SRichard Smith       return std::move(E);
105ceed4eb1SRichard Smith     RemappingBuffer = std::move(RemappingBufferOrError.get());
106ceed4eb1SRichard Smith   }
107ceed4eb1SRichard Smith 
108ceed4eb1SRichard Smith   return IndexedInstrProfReader::create(std::move(BufferOrError.get()),
109ceed4eb1SRichard Smith                                         std::move(RemappingBuffer));
1102b6c537bSJustin Bogner }
111b7aa2630SJustin Bogner 
1129152fd17SVedant Kumar Expected<std::unique_ptr<IndexedInstrProfReader>>
113ceed4eb1SRichard Smith IndexedInstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
114ceed4eb1SRichard Smith                                std::unique_ptr<MemoryBuffer> RemappingBuffer) {
1152b6c537bSJustin Bogner   // Sanity check the buffer.
116d6c15b66SVedant Kumar   if (uint64_t(Buffer->getBufferSize()) > std::numeric_limits<uint64_t>::max())
1179152fd17SVedant Kumar     return make_error<InstrProfError>(instrprof_error::too_large);
118ab89ed7dSJustin Bogner 
119b7aa2630SJustin Bogner   // Create the reader.
120b7aa2630SJustin Bogner   if (!IndexedInstrProfReader::hasFormat(*Buffer))
1219152fd17SVedant Kumar     return make_error<InstrProfError>(instrprof_error::bad_magic);
122*0eaee545SJonas Devlieghere   auto Result = std::make_unique<IndexedInstrProfReader>(
123ceed4eb1SRichard Smith       std::move(Buffer), std::move(RemappingBuffer));
124b7aa2630SJustin Bogner 
125b7aa2630SJustin Bogner   // Initialize the reader and return the result.
1269152fd17SVedant Kumar   if (Error E = initializeReader(*Result))
1279152fd17SVedant Kumar     return std::move(E);
128ab89ed7dSJustin Bogner 
129ab89ed7dSJustin Bogner   return std::move(Result);
130f8d79198SJustin Bogner }
131f8d79198SJustin Bogner 
132f8d79198SJustin Bogner void InstrProfIterator::Increment() {
1339152fd17SVedant Kumar   if (auto E = Reader->readNextRecord(Record)) {
1349152fd17SVedant Kumar     // Handle errors in the reader.
1359152fd17SVedant Kumar     InstrProfError::take(std::move(E));
136f8d79198SJustin Bogner     *this = InstrProfIterator();
137f8d79198SJustin Bogner   }
1389152fd17SVedant Kumar }
139f8d79198SJustin Bogner 
1404f823667SNathan Slingerland bool TextInstrProfReader::hasFormat(const MemoryBuffer &Buffer) {
1414f823667SNathan Slingerland   // Verify that this really looks like plain ASCII text by checking a
1424f823667SNathan Slingerland   // 'reasonable' number of characters (up to profile magic size).
1434f823667SNathan Slingerland   size_t count = std::min(Buffer.getBufferSize(), sizeof(uint64_t));
1444f823667SNathan Slingerland   StringRef buffer = Buffer.getBufferStart();
1452491dd11SVedant Kumar   return count == 0 ||
1462491dd11SVedant Kumar          std::all_of(buffer.begin(), buffer.begin() + count,
1476f1da6e3SMichael Kruse                      [](char c) { return isPrint(c) || ::isspace(c); });
1484f823667SNathan Slingerland }
1494f823667SNathan Slingerland 
15033c76c0cSRong Xu // Read the profile variant flag from the header: ":FE" means this is a FE
15133c76c0cSRong Xu // generated profile. ":IR" means this is an IR level profile. Other strings
15233c76c0cSRong Xu // with a leading ':' will be reported an error format.
1539152fd17SVedant Kumar Error TextInstrProfReader::readHeader() {
154a716cc5cSXinliang David Li   Symtab.reset(new InstrProfSymtab());
15533c76c0cSRong Xu   bool IsIRInstr = false;
15633c76c0cSRong Xu   if (!Line->startswith(":")) {
15733c76c0cSRong Xu     IsIRLevelProfile = false;
15833c76c0cSRong Xu     return success();
15933c76c0cSRong Xu   }
16033c76c0cSRong Xu   StringRef Str = (Line)->substr(1);
16133c76c0cSRong Xu   if (Str.equals_lower("ir"))
16233c76c0cSRong Xu     IsIRInstr = true;
16333c76c0cSRong Xu   else if (Str.equals_lower("fe"))
16433c76c0cSRong Xu     IsIRInstr = false;
165a6ff69f6SRong Xu   else if (Str.equals_lower("csir")) {
166a6ff69f6SRong Xu     IsIRInstr = true;
167a6ff69f6SRong Xu     HasCSIRLevelProfile = true;
168a6ff69f6SRong Xu   } else
1699152fd17SVedant Kumar     return error(instrprof_error::bad_header);
17033c76c0cSRong Xu 
17133c76c0cSRong Xu   ++Line;
17233c76c0cSRong Xu   IsIRLevelProfile = IsIRInstr;
173a716cc5cSXinliang David Li   return success();
174a716cc5cSXinliang David Li }
175a716cc5cSXinliang David Li 
1769152fd17SVedant Kumar Error
177e3bf4fd3SXinliang David Li TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) {
178e3bf4fd3SXinliang David Li 
179e3bf4fd3SXinliang David Li #define CHECK_LINE_END(Line)                                                   \
180e3bf4fd3SXinliang David Li   if (Line.is_at_end())                                                        \
181e3bf4fd3SXinliang David Li     return error(instrprof_error::truncated);
182e3bf4fd3SXinliang David Li #define READ_NUM(Str, Dst)                                                     \
183e3bf4fd3SXinliang David Li   if ((Str).getAsInteger(10, (Dst)))                                           \
184e3bf4fd3SXinliang David Li     return error(instrprof_error::malformed);
185e3bf4fd3SXinliang David Li #define VP_READ_ADVANCE(Val)                                                   \
186e3bf4fd3SXinliang David Li   CHECK_LINE_END(Line);                                                        \
187e3bf4fd3SXinliang David Li   uint32_t Val;                                                                \
188e3bf4fd3SXinliang David Li   READ_NUM((*Line), (Val));                                                    \
189e3bf4fd3SXinliang David Li   Line++;
190e3bf4fd3SXinliang David Li 
191e3bf4fd3SXinliang David Li   if (Line.is_at_end())
192e3bf4fd3SXinliang David Li     return success();
193a716cc5cSXinliang David Li 
194e3bf4fd3SXinliang David Li   uint32_t NumValueKinds;
195e3bf4fd3SXinliang David Li   if (Line->getAsInteger(10, NumValueKinds)) {
196e3bf4fd3SXinliang David Li     // No value profile data
197e3bf4fd3SXinliang David Li     return success();
198e3bf4fd3SXinliang David Li   }
199e3bf4fd3SXinliang David Li   if (NumValueKinds == 0 || NumValueKinds > IPVK_Last + 1)
200e3bf4fd3SXinliang David Li     return error(instrprof_error::malformed);
201e3bf4fd3SXinliang David Li   Line++;
202e3bf4fd3SXinliang David Li 
203e3bf4fd3SXinliang David Li   for (uint32_t VK = 0; VK < NumValueKinds; VK++) {
204e3bf4fd3SXinliang David Li     VP_READ_ADVANCE(ValueKind);
205e3bf4fd3SXinliang David Li     if (ValueKind > IPVK_Last)
206e3bf4fd3SXinliang David Li       return error(instrprof_error::malformed);
207e3bf4fd3SXinliang David Li     VP_READ_ADVANCE(NumValueSites);
208e3bf4fd3SXinliang David Li     if (!NumValueSites)
209e3bf4fd3SXinliang David Li       continue;
210e3bf4fd3SXinliang David Li 
211e3bf4fd3SXinliang David Li     Record.reserveSites(VK, NumValueSites);
212e3bf4fd3SXinliang David Li     for (uint32_t S = 0; S < NumValueSites; S++) {
213e3bf4fd3SXinliang David Li       VP_READ_ADVANCE(NumValueData);
214e3bf4fd3SXinliang David Li 
215e3bf4fd3SXinliang David Li       std::vector<InstrProfValueData> CurrentValues;
216e3bf4fd3SXinliang David Li       for (uint32_t V = 0; V < NumValueData; V++) {
217e3bf4fd3SXinliang David Li         CHECK_LINE_END(Line);
21835723644SRong Xu         std::pair<StringRef, StringRef> VD = Line->rsplit(':');
219e3bf4fd3SXinliang David Li         uint64_t TakenCount, Value;
220cbb11407SRong Xu         if (ValueKind == IPVK_IndirectCallTarget) {
22129a21babSMircea Trofin           if (InstrProfSymtab::isExternalSymbol(VD.first)) {
22229a21babSMircea Trofin             Value = 0;
22329a21babSMircea Trofin           } else {
224b5794ca9SVedant Kumar             if (Error E = Symtab->addFuncName(VD.first))
225b5794ca9SVedant Kumar               return E;
226a716cc5cSXinliang David Li             Value = IndexedInstrProf::ComputeHash(VD.first);
22729a21babSMircea Trofin           }
228a716cc5cSXinliang David Li         } else {
229e3bf4fd3SXinliang David Li           READ_NUM(VD.first, Value);
230e3bf4fd3SXinliang David Li         }
231a716cc5cSXinliang David Li         READ_NUM(VD.second, TakenCount);
232e3bf4fd3SXinliang David Li         CurrentValues.push_back({Value, TakenCount});
233e3bf4fd3SXinliang David Li         Line++;
234e3bf4fd3SXinliang David Li       }
235cbb11407SRong Xu       Record.addValueData(ValueKind, S, CurrentValues.data(), NumValueData,
236cbb11407SRong Xu                           nullptr);
237e3bf4fd3SXinliang David Li     }
238e3bf4fd3SXinliang David Li   }
239e3bf4fd3SXinliang David Li   return success();
240e3bf4fd3SXinliang David Li 
241e3bf4fd3SXinliang David Li #undef CHECK_LINE_END
242e3bf4fd3SXinliang David Li #undef READ_NUM
243e3bf4fd3SXinliang David Li #undef VP_READ_ADVANCE
244e3bf4fd3SXinliang David Li }
245e3bf4fd3SXinliang David Li 
246cf9d52c6SDavid Blaikie Error TextInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
247cf36a366SJustin Bogner   // Skip empty lines and comments.
248cf36a366SJustin Bogner   while (!Line.is_at_end() && (Line->empty() || Line->startswith("#")))
249f8d79198SJustin Bogner     ++Line;
250f8d79198SJustin Bogner   // If we hit EOF while looking for a name, we're done.
251a716cc5cSXinliang David Li   if (Line.is_at_end()) {
252f8d79198SJustin Bogner     return error(instrprof_error::eof);
253a716cc5cSXinliang David Li   }
254f8d79198SJustin Bogner 
255f8d79198SJustin Bogner   // Read the function name.
256f8d79198SJustin Bogner   Record.Name = *Line++;
257b5794ca9SVedant Kumar   if (Error E = Symtab->addFuncName(Record.Name))
25829a21babSMircea Trofin     return error(std::move(E));
259f8d79198SJustin Bogner 
260f8d79198SJustin Bogner   // Read the function hash.
261f8d79198SJustin Bogner   if (Line.is_at_end())
262f8d79198SJustin Bogner     return error(instrprof_error::truncated);
263f95ca075SJustin Bogner   if ((Line++)->getAsInteger(0, Record.Hash))
264f8d79198SJustin Bogner     return error(instrprof_error::malformed);
265f8d79198SJustin Bogner 
266f8d79198SJustin Bogner   // Read the number of counters.
267f8d79198SJustin Bogner   uint64_t NumCounters;
268f8d79198SJustin Bogner   if (Line.is_at_end())
269f8d79198SJustin Bogner     return error(instrprof_error::truncated);
270f8d79198SJustin Bogner   if ((Line++)->getAsInteger(10, NumCounters))
271f8d79198SJustin Bogner     return error(instrprof_error::malformed);
272b59d7c73SJustin Bogner   if (NumCounters == 0)
273b59d7c73SJustin Bogner     return error(instrprof_error::malformed);
274f8d79198SJustin Bogner 
275f8d79198SJustin Bogner   // Read each counter and fill our internal storage with the values.
2766241c2a6SRong Xu   Record.Clear();
2773a7d44cbSJustin Bogner   Record.Counts.reserve(NumCounters);
278f8d79198SJustin Bogner   for (uint64_t I = 0; I < NumCounters; ++I) {
279f8d79198SJustin Bogner     if (Line.is_at_end())
280f8d79198SJustin Bogner       return error(instrprof_error::truncated);
281f8d79198SJustin Bogner     uint64_t Count;
282f8d79198SJustin Bogner     if ((Line++)->getAsInteger(10, Count))
283f8d79198SJustin Bogner       return error(instrprof_error::malformed);
2843a7d44cbSJustin Bogner     Record.Counts.push_back(Count);
285f8d79198SJustin Bogner   }
286f8d79198SJustin Bogner 
287e3bf4fd3SXinliang David Li   // Check if value profile data exists and read it if so.
2889152fd17SVedant Kumar   if (Error E = readValueProfileData(Record))
28929a21babSMircea Trofin     return error(std::move(E));
290e3bf4fd3SXinliang David Li 
291f8d79198SJustin Bogner   return success();
292f8d79198SJustin Bogner }
29324b4b653SDuncan P. N. Exon Smith 
2944680361dSDuncan P. N. Exon Smith template <class IntPtrT>
2954680361dSDuncan P. N. Exon Smith bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) {
296d7d83477SDuncan P. N. Exon Smith   if (DataBuffer.getBufferSize() < sizeof(uint64_t))
2974680361dSDuncan P. N. Exon Smith     return false;
298d7d83477SDuncan P. N. Exon Smith   uint64_t Magic =
299d7d83477SDuncan P. N. Exon Smith     *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart());
300dab183edSXinliang David Li   return RawInstrProf::getMagic<IntPtrT>() == Magic ||
301dab183edSXinliang David Li          sys::getSwappedBytes(RawInstrProf::getMagic<IntPtrT>()) == Magic;
3024680361dSDuncan P. N. Exon Smith }
3034680361dSDuncan P. N. Exon Smith 
3044680361dSDuncan P. N. Exon Smith template <class IntPtrT>
3059152fd17SVedant Kumar Error RawInstrProfReader<IntPtrT>::readHeader() {
30609a67f45SDuncan P. N. Exon Smith   if (!hasFormat(*DataBuffer))
30709a67f45SDuncan P. N. Exon Smith     return error(instrprof_error::bad_magic);
308dab183edSXinliang David Li   if (DataBuffer->getBufferSize() < sizeof(RawInstrProf::Header))
309531bb481SDuncan P. N. Exon Smith     return error(instrprof_error::bad_header);
310dab183edSXinliang David Li   auto *Header = reinterpret_cast<const RawInstrProf::Header *>(
311dab183edSXinliang David Li       DataBuffer->getBufferStart());
312dab183edSXinliang David Li   ShouldSwapBytes = Header->Magic != RawInstrProf::getMagic<IntPtrT>();
31324b4b653SDuncan P. N. Exon Smith   return readHeader(*Header);
31424b4b653SDuncan P. N. Exon Smith }
31524b4b653SDuncan P. N. Exon Smith 
316a119f323SJustin Bogner template <class IntPtrT>
3179152fd17SVedant Kumar Error RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
318a119f323SJustin Bogner   const char *End = DataBuffer->getBufferEnd();
319a119f323SJustin Bogner   // Skip zero padding between profiles.
320a119f323SJustin Bogner   while (CurrentPos != End && *CurrentPos == 0)
321a119f323SJustin Bogner     ++CurrentPos;
322a119f323SJustin Bogner   // If there's nothing left, we're done.
323a119f323SJustin Bogner   if (CurrentPos == End)
3249152fd17SVedant Kumar     return make_error<InstrProfError>(instrprof_error::eof);
325a119f323SJustin Bogner   // If there isn't enough space for another header, this is probably just
326a119f323SJustin Bogner   // garbage at the end of the file.
327dab183edSXinliang David Li   if (CurrentPos + sizeof(RawInstrProf::Header) > End)
3289152fd17SVedant Kumar     return make_error<InstrProfError>(instrprof_error::malformed);
32954b11282SJustin Bogner   // The writer ensures each profile is padded to start at an aligned address.
330b2505005SBenjamin Kramer   if (reinterpret_cast<size_t>(CurrentPos) % alignof(uint64_t))
3319152fd17SVedant Kumar     return make_error<InstrProfError>(instrprof_error::malformed);
332a119f323SJustin Bogner   // The magic should have the same byte order as in the previous header.
333a119f323SJustin Bogner   uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos);
334dab183edSXinliang David Li   if (Magic != swap(RawInstrProf::getMagic<IntPtrT>()))
3359152fd17SVedant Kumar     return make_error<InstrProfError>(instrprof_error::bad_magic);
336a119f323SJustin Bogner 
337a119f323SJustin Bogner   // There's another profile to read, so we need to process the header.
338dab183edSXinliang David Li   auto *Header = reinterpret_cast<const RawInstrProf::Header *>(CurrentPos);
339a119f323SJustin Bogner   return readHeader(*Header);
340a119f323SJustin Bogner }
341a119f323SJustin Bogner 
3424680361dSDuncan P. N. Exon Smith template <class IntPtrT>
3439152fd17SVedant Kumar Error RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) {
3449152fd17SVedant Kumar   if (Error E = Symtab.create(StringRef(NamesStart, NamesSize)))
3459152fd17SVedant Kumar     return error(std::move(E));
346a716cc5cSXinliang David Li   for (const RawInstrProf::ProfileData<IntPtrT> *I = Data; I != DataEnd; ++I) {
347a716cc5cSXinliang David Li     const IntPtrT FPtr = swap(I->FunctionPointer);
348a716cc5cSXinliang David Li     if (!FPtr)
349a716cc5cSXinliang David Li       continue;
350a82d6c0aSXinliang David Li     Symtab.mapAddress(FPtr, I->NameRef);
351a716cc5cSXinliang David Li   }
352e44482feSVedant Kumar   return success();
353a716cc5cSXinliang David Li }
354a716cc5cSXinliang David Li 
355a716cc5cSXinliang David Li template <class IntPtrT>
3569152fd17SVedant Kumar Error RawInstrProfReader<IntPtrT>::readHeader(
3579152fd17SVedant Kumar     const RawInstrProf::Header &Header) {
35833c76c0cSRong Xu   Version = swap(Header.Version);
35933c76c0cSRong Xu   if (GET_VERSION(Version) != RawInstrProf::Version)
36024b4b653SDuncan P. N. Exon Smith     return error(instrprof_error::unsupported_version);
36124b4b653SDuncan P. N. Exon Smith 
36224b4b653SDuncan P. N. Exon Smith   CountersDelta = swap(Header.CountersDelta);
36324b4b653SDuncan P. N. Exon Smith   NamesDelta = swap(Header.NamesDelta);
36424b4b653SDuncan P. N. Exon Smith   auto DataSize = swap(Header.DataSize);
36524b4b653SDuncan P. N. Exon Smith   auto CountersSize = swap(Header.CountersSize);
366a82d6c0aSXinliang David Li   NamesSize = swap(Header.NamesSize);
3676fac1741SBetul Buyukkurt   ValueKindLast = swap(Header.ValueKindLast);
3686fac1741SBetul Buyukkurt 
3696fac1741SBetul Buyukkurt   auto DataSizeInBytes = DataSize * sizeof(RawInstrProf::ProfileData<IntPtrT>);
3706fac1741SBetul Buyukkurt   auto PaddingSize = getNumPaddingBytes(NamesSize);
37124b4b653SDuncan P. N. Exon Smith 
372dab183edSXinliang David Li   ptrdiff_t DataOffset = sizeof(RawInstrProf::Header);
3736fac1741SBetul Buyukkurt   ptrdiff_t CountersOffset = DataOffset + DataSizeInBytes;
37424b4b653SDuncan P. N. Exon Smith   ptrdiff_t NamesOffset = CountersOffset + sizeof(uint64_t) * CountersSize;
3756fac1741SBetul Buyukkurt   ptrdiff_t ValueDataOffset = NamesOffset + NamesSize + PaddingSize;
37624b4b653SDuncan P. N. Exon Smith 
377a119f323SJustin Bogner   auto *Start = reinterpret_cast<const char *>(&Header);
378188a7c5fSXinliang David Li   if (Start + ValueDataOffset > DataBuffer->getBufferEnd())
379531bb481SDuncan P. N. Exon Smith     return error(instrprof_error::bad_header);
38024b4b653SDuncan P. N. Exon Smith 
381dab183edSXinliang David Li   Data = reinterpret_cast<const RawInstrProf::ProfileData<IntPtrT> *>(
382dab183edSXinliang David Li       Start + DataOffset);
38324b4b653SDuncan P. N. Exon Smith   DataEnd = Data + DataSize;
384d7d83477SDuncan P. N. Exon Smith   CountersStart = reinterpret_cast<const uint64_t *>(Start + CountersOffset);
385d7d83477SDuncan P. N. Exon Smith   NamesStart = Start + NamesOffset;
3866fac1741SBetul Buyukkurt   ValueDataStart = reinterpret_cast<const uint8_t *>(Start + ValueDataOffset);
38724b4b653SDuncan P. N. Exon Smith 
388*0eaee545SJonas Devlieghere   std::unique_ptr<InstrProfSymtab> NewSymtab = std::make_unique<InstrProfSymtab>();
3899152fd17SVedant Kumar   if (Error E = createSymtab(*NewSymtab.get()))
3909152fd17SVedant Kumar     return E;
391e44482feSVedant Kumar 
392a716cc5cSXinliang David Li   Symtab = std::move(NewSymtab);
39324b4b653SDuncan P. N. Exon Smith   return success();
39424b4b653SDuncan P. N. Exon Smith }
39524b4b653SDuncan P. N. Exon Smith 
3964680361dSDuncan P. N. Exon Smith template <class IntPtrT>
397cf9d52c6SDavid Blaikie Error RawInstrProfReader<IntPtrT>::readName(NamedInstrProfRecord &Record) {
398a82d6c0aSXinliang David Li   Record.Name = getName(Data->NameRef);
399cf4a128cSXinliang David Li   return success();
400cf4a128cSXinliang David Li }
401cf4a128cSXinliang David Li 
402cf4a128cSXinliang David Li template <class IntPtrT>
403cf9d52c6SDavid Blaikie Error RawInstrProfReader<IntPtrT>::readFuncHash(NamedInstrProfRecord &Record) {
404cf4a128cSXinliang David Li   Record.Hash = swap(Data->FuncHash);
405cf4a128cSXinliang David Li   return success();
406cf4a128cSXinliang David Li }
407cf4a128cSXinliang David Li 
408cf4a128cSXinliang David Li template <class IntPtrT>
4099152fd17SVedant Kumar Error RawInstrProfReader<IntPtrT>::readRawCounts(
410cf4a128cSXinliang David Li     InstrProfRecord &Record) {
411b59d7c73SJustin Bogner   uint32_t NumCounters = swap(Data->NumCounters);
412cf4a128cSXinliang David Li   IntPtrT CounterPtr = Data->CounterPtr;
413b59d7c73SJustin Bogner   if (NumCounters == 0)
414b59d7c73SJustin Bogner     return error(instrprof_error::malformed);
415cf4a128cSXinliang David Li 
416cf4a128cSXinliang David Li   auto RawCounts = makeArrayRef(getCounter(CounterPtr), NumCounters);
417cf4a128cSXinliang David Li   auto *NamesStartAsCounter = reinterpret_cast<const uint64_t *>(NamesStart);
41824b4b653SDuncan P. N. Exon Smith 
41924b4b653SDuncan P. N. Exon Smith   // Check bounds.
420cf4a128cSXinliang David Li   if (RawCounts.data() < CountersStart ||
421d7d83477SDuncan P. N. Exon Smith       RawCounts.data() + RawCounts.size() > NamesStartAsCounter)
42224b4b653SDuncan P. N. Exon Smith     return error(instrprof_error::malformed);
42324b4b653SDuncan P. N. Exon Smith 
42424b4b653SDuncan P. N. Exon Smith   if (ShouldSwapBytes) {
4253a7d44cbSJustin Bogner     Record.Counts.clear();
4263a7d44cbSJustin Bogner     Record.Counts.reserve(RawCounts.size());
42724b4b653SDuncan P. N. Exon Smith     for (uint64_t Count : RawCounts)
4283a7d44cbSJustin Bogner       Record.Counts.push_back(swap(Count));
42924b4b653SDuncan P. N. Exon Smith   } else
43024b4b653SDuncan P. N. Exon Smith     Record.Counts = RawCounts;
43124b4b653SDuncan P. N. Exon Smith 
432cf4a128cSXinliang David Li   return success();
433cf4a128cSXinliang David Li }
434cf4a128cSXinliang David Li 
435cf4a128cSXinliang David Li template <class IntPtrT>
4369152fd17SVedant Kumar Error RawInstrProfReader<IntPtrT>::readValueProfilingData(
4379152fd17SVedant Kumar     InstrProfRecord &Record) {
4386fac1741SBetul Buyukkurt   Record.clearValueData();
439d922c26cSXinliang David Li   CurValueDataSize = 0;
440d922c26cSXinliang David Li   // Need to match the logic in value profile dumper code in compiler-rt:
441d922c26cSXinliang David Li   uint32_t NumValueKinds = 0;
442d922c26cSXinliang David Li   for (uint32_t I = 0; I < IPVK_Last + 1; I++)
443d922c26cSXinliang David Li     NumValueKinds += (Data->NumValueSites[I] != 0);
444d922c26cSXinliang David Li 
445d922c26cSXinliang David Li   if (!NumValueKinds)
4466fac1741SBetul Buyukkurt     return success();
4476fac1741SBetul Buyukkurt 
4489152fd17SVedant Kumar   Expected<std::unique_ptr<ValueProfData>> VDataPtrOrErr =
449188a7c5fSXinliang David Li       ValueProfData::getValueProfData(
450188a7c5fSXinliang David Li           ValueDataStart, (const unsigned char *)DataBuffer->getBufferEnd(),
45101cb9bd7SXinliang David Li           getDataEndianness());
4526fac1741SBetul Buyukkurt 
4539152fd17SVedant Kumar   if (Error E = VDataPtrOrErr.takeError())
4549152fd17SVedant Kumar     return E;
4556fac1741SBetul Buyukkurt 
4562f36f059SAdam Nemet   // Note that besides deserialization, this also performs the conversion for
4572f36f059SAdam Nemet   // indirect call targets.  The function pointers from the raw profile are
4582f36f059SAdam Nemet   // remapped into function name hashes.
459556f8f6aSMircea Trofin   VDataPtrOrErr.get()->deserializeTo(Record, Symtab.get());
460d922c26cSXinliang David Li   CurValueDataSize = VDataPtrOrErr.get()->getSize();
4616fac1741SBetul Buyukkurt   return success();
4626fac1741SBetul Buyukkurt }
4636fac1741SBetul Buyukkurt 
4646fac1741SBetul Buyukkurt template <class IntPtrT>
465cf9d52c6SDavid Blaikie Error RawInstrProfReader<IntPtrT>::readNextRecord(NamedInstrProfRecord &Record) {
466cf4a128cSXinliang David Li   if (atEnd())
467188a7c5fSXinliang David Li     // At this point, ValueDataStart field points to the next header.
4689152fd17SVedant Kumar     if (Error E = readNextHeader(getNextHeaderPos()))
4695b63803dSMircea Trofin       return error(std::move(E));
470cf4a128cSXinliang David Li 
471cf4a128cSXinliang David Li   // Read name ad set it in Record.
4729152fd17SVedant Kumar   if (Error E = readName(Record))
4735b63803dSMircea Trofin     return error(std::move(E));
474cf4a128cSXinliang David Li 
475cf4a128cSXinliang David Li   // Read FuncHash and set it in Record.
4769152fd17SVedant Kumar   if (Error E = readFuncHash(Record))
4775b63803dSMircea Trofin     return error(std::move(E));
478cf4a128cSXinliang David Li 
479cf4a128cSXinliang David Li   // Read raw counts and set Record.
4809152fd17SVedant Kumar   if (Error E = readRawCounts(Record))
4815b63803dSMircea Trofin     return error(std::move(E));
482cf4a128cSXinliang David Li 
4836fac1741SBetul Buyukkurt   // Read value data and set Record.
4849152fd17SVedant Kumar   if (Error E = readValueProfilingData(Record))
4855b63803dSMircea Trofin     return error(std::move(E));
4866fac1741SBetul Buyukkurt 
48724b4b653SDuncan P. N. Exon Smith   // Iterate.
488cf4a128cSXinliang David Li   advanceData();
48924b4b653SDuncan P. N. Exon Smith   return success();
49024b4b653SDuncan P. N. Exon Smith }
4914680361dSDuncan P. N. Exon Smith 
4924680361dSDuncan P. N. Exon Smith namespace llvm {
493e78d131aSEugene Zelenko 
4944680361dSDuncan P. N. Exon Smith template class RawInstrProfReader<uint32_t>;
4954680361dSDuncan P. N. Exon Smith template class RawInstrProfReader<uint64_t>;
496e78d131aSEugene Zelenko 
497e78d131aSEugene Zelenko } // end namespace llvm
498b7aa2630SJustin Bogner 
499b5d368e8SJustin Bogner InstrProfLookupTrait::hash_value_type
500b5d368e8SJustin Bogner InstrProfLookupTrait::ComputeHash(StringRef K) {
501b5d368e8SJustin Bogner   return IndexedInstrProf::ComputeHash(HashType, K);
502b5d368e8SJustin Bogner }
503b5d368e8SJustin Bogner 
50472208a82SEugene Zelenko using data_type = InstrProfLookupTrait::data_type;
50572208a82SEugene Zelenko using offset_type = InstrProfLookupTrait::offset_type;
5063a7d44cbSJustin Bogner 
507be969c29SXinliang David Li bool InstrProfLookupTrait::readValueProfilingData(
5089e9a057aSJustin Bogner     const unsigned char *&D, const unsigned char *const End) {
5099152fd17SVedant Kumar   Expected<std::unique_ptr<ValueProfData>> VDataPtrOrErr =
51099556877SXinliang David Li       ValueProfData::getValueProfData(D, End, ValueProfDataEndianness);
5119e9a057aSJustin Bogner 
5129152fd17SVedant Kumar   if (VDataPtrOrErr.takeError())
5139e9a057aSJustin Bogner     return false;
5142004f003SXinliang David Li 
515a716cc5cSXinliang David Li   VDataPtrOrErr.get()->deserializeTo(DataBuffer.back(), nullptr);
516ee415895SXinliang David Li   D += VDataPtrOrErr.get()->TotalSize;
5179e9a057aSJustin Bogner 
5189e9a057aSJustin Bogner   return true;
5199e9a057aSJustin Bogner }
5209e9a057aSJustin Bogner 
5213a7d44cbSJustin Bogner data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D,
5223a7d44cbSJustin Bogner                                          offset_type N) {
523e78d131aSEugene Zelenko   using namespace support;
524e78d131aSEugene Zelenko 
5253a7d44cbSJustin Bogner   // Check if the data is corrupt. If so, don't try to read it.
5263a7d44cbSJustin Bogner   if (N % sizeof(uint64_t))
5273a7d44cbSJustin Bogner     return data_type();
5283a7d44cbSJustin Bogner 
5293a7d44cbSJustin Bogner   DataBuffer.clear();
5303a7d44cbSJustin Bogner   std::vector<uint64_t> CounterBuffer;
5319e9a057aSJustin Bogner 
5329e9a057aSJustin Bogner   const unsigned char *End = D + N;
5339e9a057aSJustin Bogner   while (D < End) {
534c758387eSXinliang David Li     // Read hash.
5359e9a057aSJustin Bogner     if (D + sizeof(uint64_t) >= End)
5369e9a057aSJustin Bogner       return data_type();
5373a7d44cbSJustin Bogner     uint64_t Hash = endian::readNext<uint64_t, little, unaligned>(D);
5383a7d44cbSJustin Bogner 
53933c76c0cSRong Xu     // Initialize number of counters for GET_VERSION(FormatVersion) == 1.
5409e9a057aSJustin Bogner     uint64_t CountsSize = N / sizeof(uint64_t) - 1;
541c758387eSXinliang David Li     // If format version is different then read the number of counters.
54233c76c0cSRong Xu     if (GET_VERSION(FormatVersion) != IndexedInstrProf::ProfVersion::Version1) {
5439e9a057aSJustin Bogner       if (D + sizeof(uint64_t) > End)
5443a7d44cbSJustin Bogner         return data_type();
5459e9a057aSJustin Bogner       CountsSize = endian::readNext<uint64_t, little, unaligned>(D);
5469e9a057aSJustin Bogner     }
547c758387eSXinliang David Li     // Read counter values.
5489e9a057aSJustin Bogner     if (D + CountsSize * sizeof(uint64_t) > End)
5493a7d44cbSJustin Bogner       return data_type();
5503a7d44cbSJustin Bogner 
5513a7d44cbSJustin Bogner     CounterBuffer.clear();
5529e9a057aSJustin Bogner     CounterBuffer.reserve(CountsSize);
5539e9a057aSJustin Bogner     for (uint64_t J = 0; J < CountsSize; ++J)
5543a7d44cbSJustin Bogner       CounterBuffer.push_back(endian::readNext<uint64_t, little, unaligned>(D));
5553a7d44cbSJustin Bogner 
5562004f003SXinliang David Li     DataBuffer.emplace_back(K, Hash, std::move(CounterBuffer));
5579e9a057aSJustin Bogner 
558c758387eSXinliang David Li     // Read value profiling data.
55933c76c0cSRong Xu     if (GET_VERSION(FormatVersion) > IndexedInstrProf::ProfVersion::Version2 &&
560a6b2c4f7SXinliang David Li         !readValueProfilingData(D, End)) {
5619e9a057aSJustin Bogner       DataBuffer.clear();
5629e9a057aSJustin Bogner       return data_type();
5639e9a057aSJustin Bogner     }
5643a7d44cbSJustin Bogner   }
5653a7d44cbSJustin Bogner   return DataBuffer;
5663a7d44cbSJustin Bogner }
5673a7d44cbSJustin Bogner 
568a28306dbSXinliang David Li template <typename HashTableImpl>
5699152fd17SVedant Kumar Error InstrProfReaderIndex<HashTableImpl>::getRecords(
570cf9d52c6SDavid Blaikie     StringRef FuncName, ArrayRef<NamedInstrProfRecord> &Data) {
571a28306dbSXinliang David Li   auto Iter = HashTable->find(FuncName);
572a28306dbSXinliang David Li   if (Iter == HashTable->end())
5739152fd17SVedant Kumar     return make_error<InstrProfError>(instrprof_error::unknown_function);
574140f4c4fSXinliang David Li 
575140f4c4fSXinliang David Li   Data = (*Iter);
5764c3ab815SXinliang David Li   if (Data.empty())
5779152fd17SVedant Kumar     return make_error<InstrProfError>(instrprof_error::malformed);
578140f4c4fSXinliang David Li 
5799152fd17SVedant Kumar   return Error::success();
580140f4c4fSXinliang David Li }
581140f4c4fSXinliang David Li 
582a28306dbSXinliang David Li template <typename HashTableImpl>
5839152fd17SVedant Kumar Error InstrProfReaderIndex<HashTableImpl>::getRecords(
584cf9d52c6SDavid Blaikie     ArrayRef<NamedInstrProfRecord> &Data) {
585a28306dbSXinliang David Li   if (atEnd())
5869152fd17SVedant Kumar     return make_error<InstrProfError>(instrprof_error::eof);
587140f4c4fSXinliang David Li 
588140f4c4fSXinliang David Li   Data = *RecordIterator;
589140f4c4fSXinliang David Li 
5902d4803e8SXinliang David Li   if (Data.empty())
5919152fd17SVedant Kumar     return make_error<InstrProfError>(instrprof_error::malformed);
592140f4c4fSXinliang David Li 
5939152fd17SVedant Kumar   return Error::success();
594140f4c4fSXinliang David Li }
595140f4c4fSXinliang David Li 
596a28306dbSXinliang David Li template <typename HashTableImpl>
597a28306dbSXinliang David Li InstrProfReaderIndex<HashTableImpl>::InstrProfReaderIndex(
598a28306dbSXinliang David Li     const unsigned char *Buckets, const unsigned char *const Payload,
599a28306dbSXinliang David Li     const unsigned char *const Base, IndexedInstrProf::HashT HashType,
600140f4c4fSXinliang David Li     uint64_t Version) {
601140f4c4fSXinliang David Li   FormatVersion = Version;
602a28306dbSXinliang David Li   HashTable.reset(HashTableImpl::Create(
603a28306dbSXinliang David Li       Buckets, Payload, Base,
604a28306dbSXinliang David Li       typename HashTableImpl::InfoType(HashType, Version)));
605a28306dbSXinliang David Li   RecordIterator = HashTable->data_begin();
606140f4c4fSXinliang David Li }
607140f4c4fSXinliang David Li 
608ceed4eb1SRichard Smith namespace {
609ceed4eb1SRichard Smith /// A remapper that does not apply any remappings.
610ceed4eb1SRichard Smith class InstrProfReaderNullRemapper : public InstrProfReaderRemapper {
611ceed4eb1SRichard Smith   InstrProfReaderIndexBase &Underlying;
612ceed4eb1SRichard Smith 
613ceed4eb1SRichard Smith public:
614ceed4eb1SRichard Smith   InstrProfReaderNullRemapper(InstrProfReaderIndexBase &Underlying)
615ceed4eb1SRichard Smith       : Underlying(Underlying) {}
616ceed4eb1SRichard Smith 
617ceed4eb1SRichard Smith   Error getRecords(StringRef FuncName,
618ceed4eb1SRichard Smith                    ArrayRef<NamedInstrProfRecord> &Data) override {
619ceed4eb1SRichard Smith     return Underlying.getRecords(FuncName, Data);
620ceed4eb1SRichard Smith   }
621ceed4eb1SRichard Smith };
622ceed4eb1SRichard Smith }
623ceed4eb1SRichard Smith 
624ceed4eb1SRichard Smith /// A remapper that applies remappings based on a symbol remapping file.
625ceed4eb1SRichard Smith template <typename HashTableImpl>
626ceed4eb1SRichard Smith class llvm::InstrProfReaderItaniumRemapper
627ceed4eb1SRichard Smith     : public InstrProfReaderRemapper {
628ceed4eb1SRichard Smith public:
629ceed4eb1SRichard Smith   InstrProfReaderItaniumRemapper(
630ceed4eb1SRichard Smith       std::unique_ptr<MemoryBuffer> RemapBuffer,
631ceed4eb1SRichard Smith       InstrProfReaderIndex<HashTableImpl> &Underlying)
632ceed4eb1SRichard Smith       : RemapBuffer(std::move(RemapBuffer)), Underlying(Underlying) {
633ceed4eb1SRichard Smith   }
634ceed4eb1SRichard Smith 
635ceed4eb1SRichard Smith   /// Extract the original function name from a PGO function name.
636ceed4eb1SRichard Smith   static StringRef extractName(StringRef Name) {
637ceed4eb1SRichard Smith     // We can have multiple :-separated pieces; there can be pieces both
638ceed4eb1SRichard Smith     // before and after the mangled name. Find the first part that starts
639ceed4eb1SRichard Smith     // with '_Z'; we'll assume that's the mangled name we want.
640ceed4eb1SRichard Smith     std::pair<StringRef, StringRef> Parts = {StringRef(), Name};
641ceed4eb1SRichard Smith     while (true) {
642ceed4eb1SRichard Smith       Parts = Parts.second.split(':');
643ceed4eb1SRichard Smith       if (Parts.first.startswith("_Z"))
644ceed4eb1SRichard Smith         return Parts.first;
645ceed4eb1SRichard Smith       if (Parts.second.empty())
646ceed4eb1SRichard Smith         return Name;
647ceed4eb1SRichard Smith     }
648ceed4eb1SRichard Smith   }
649ceed4eb1SRichard Smith 
650ceed4eb1SRichard Smith   /// Given a mangled name extracted from a PGO function name, and a new
651ceed4eb1SRichard Smith   /// form for that mangled name, reconstitute the name.
652ceed4eb1SRichard Smith   static void reconstituteName(StringRef OrigName, StringRef ExtractedName,
653ceed4eb1SRichard Smith                                StringRef Replacement,
654ceed4eb1SRichard Smith                                SmallVectorImpl<char> &Out) {
655ceed4eb1SRichard Smith     Out.reserve(OrigName.size() + Replacement.size() - ExtractedName.size());
656ceed4eb1SRichard Smith     Out.insert(Out.end(), OrigName.begin(), ExtractedName.begin());
657ceed4eb1SRichard Smith     Out.insert(Out.end(), Replacement.begin(), Replacement.end());
658ceed4eb1SRichard Smith     Out.insert(Out.end(), ExtractedName.end(), OrigName.end());
659ceed4eb1SRichard Smith   }
660ceed4eb1SRichard Smith 
661ceed4eb1SRichard Smith   Error populateRemappings() override {
662ceed4eb1SRichard Smith     if (Error E = Remappings.read(*RemapBuffer))
663ceed4eb1SRichard Smith       return E;
664ceed4eb1SRichard Smith     for (StringRef Name : Underlying.HashTable->keys()) {
665ceed4eb1SRichard Smith       StringRef RealName = extractName(Name);
666ceed4eb1SRichard Smith       if (auto Key = Remappings.insert(RealName)) {
667ceed4eb1SRichard Smith         // FIXME: We could theoretically map the same equivalence class to
668ceed4eb1SRichard Smith         // multiple names in the profile data. If that happens, we should
669ceed4eb1SRichard Smith         // return NamedInstrProfRecords from all of them.
670ceed4eb1SRichard Smith         MappedNames.insert({Key, RealName});
671ceed4eb1SRichard Smith       }
672ceed4eb1SRichard Smith     }
673ceed4eb1SRichard Smith     return Error::success();
674ceed4eb1SRichard Smith   }
675ceed4eb1SRichard Smith 
676ceed4eb1SRichard Smith   Error getRecords(StringRef FuncName,
677ceed4eb1SRichard Smith                    ArrayRef<NamedInstrProfRecord> &Data) override {
678ceed4eb1SRichard Smith     StringRef RealName = extractName(FuncName);
679ceed4eb1SRichard Smith     if (auto Key = Remappings.lookup(RealName)) {
680ceed4eb1SRichard Smith       StringRef Remapped = MappedNames.lookup(Key);
681ceed4eb1SRichard Smith       if (!Remapped.empty()) {
682ceed4eb1SRichard Smith         if (RealName.begin() == FuncName.begin() &&
683ceed4eb1SRichard Smith             RealName.end() == FuncName.end())
684ceed4eb1SRichard Smith           FuncName = Remapped;
685ceed4eb1SRichard Smith         else {
686ceed4eb1SRichard Smith           // Try rebuilding the name from the given remapping.
687ceed4eb1SRichard Smith           SmallString<256> Reconstituted;
688ceed4eb1SRichard Smith           reconstituteName(FuncName, RealName, Remapped, Reconstituted);
689ceed4eb1SRichard Smith           Error E = Underlying.getRecords(Reconstituted, Data);
690ceed4eb1SRichard Smith           if (!E)
691ceed4eb1SRichard Smith             return E;
692ceed4eb1SRichard Smith 
693ceed4eb1SRichard Smith           // If we failed because the name doesn't exist, fall back to asking
694ceed4eb1SRichard Smith           // about the original name.
695ceed4eb1SRichard Smith           if (Error Unhandled = handleErrors(
696ceed4eb1SRichard Smith                   std::move(E), [](std::unique_ptr<InstrProfError> Err) {
697ceed4eb1SRichard Smith                     return Err->get() == instrprof_error::unknown_function
698ceed4eb1SRichard Smith                                ? Error::success()
699ceed4eb1SRichard Smith                                : Error(std::move(Err));
700ceed4eb1SRichard Smith                   }))
701ceed4eb1SRichard Smith             return Unhandled;
702ceed4eb1SRichard Smith         }
703ceed4eb1SRichard Smith       }
704ceed4eb1SRichard Smith     }
705ceed4eb1SRichard Smith     return Underlying.getRecords(FuncName, Data);
706ceed4eb1SRichard Smith   }
707ceed4eb1SRichard Smith 
708ceed4eb1SRichard Smith private:
709ceed4eb1SRichard Smith   /// The memory buffer containing the remapping configuration. Remappings
710ceed4eb1SRichard Smith   /// holds pointers into this buffer.
711ceed4eb1SRichard Smith   std::unique_ptr<MemoryBuffer> RemapBuffer;
712ceed4eb1SRichard Smith 
713ceed4eb1SRichard Smith   /// The mangling remapper.
714ceed4eb1SRichard Smith   SymbolRemappingReader Remappings;
715ceed4eb1SRichard Smith 
716ceed4eb1SRichard Smith   /// Mapping from mangled name keys to the name used for the key in the
717ceed4eb1SRichard Smith   /// profile data.
718ceed4eb1SRichard Smith   /// FIXME: Can we store a location within the on-disk hash table instead of
719ceed4eb1SRichard Smith   /// redoing lookup?
720ceed4eb1SRichard Smith   DenseMap<SymbolRemappingReader::Key, StringRef> MappedNames;
721ceed4eb1SRichard Smith 
722ceed4eb1SRichard Smith   /// The real profile data reader.
723ceed4eb1SRichard Smith   InstrProfReaderIndex<HashTableImpl> &Underlying;
724ceed4eb1SRichard Smith };
725ceed4eb1SRichard Smith 
726b7aa2630SJustin Bogner bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) {
727e78d131aSEugene Zelenko   using namespace support;
728e78d131aSEugene Zelenko 
7294c3ab815SXinliang David Li   if (DataBuffer.getBufferSize() < 8)
7304c3ab815SXinliang David Li     return false;
731b7aa2630SJustin Bogner   uint64_t Magic =
732b7aa2630SJustin Bogner       endian::read<uint64_t, little, aligned>(DataBuffer.getBufferStart());
733c758387eSXinliang David Li   // Verify that it's magical.
734b7aa2630SJustin Bogner   return Magic == IndexedInstrProf::Magic;
735b7aa2630SJustin Bogner }
736b7aa2630SJustin Bogner 
7376c93ee8dSXinliang David Li const unsigned char *
7386c93ee8dSXinliang David Li IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version,
739a6ff69f6SRong Xu                                     const unsigned char *Cur, bool UseCS) {
740e5a17e3fSEaswaran Raman   using namespace IndexedInstrProf;
7416c93ee8dSXinliang David Li   using namespace support;
742e78d131aSEugene Zelenko 
7436c93ee8dSXinliang David Li   if (Version >= IndexedInstrProf::Version4) {
7446c93ee8dSXinliang David Li     const IndexedInstrProf::Summary *SummaryInLE =
7456c93ee8dSXinliang David Li         reinterpret_cast<const IndexedInstrProf::Summary *>(Cur);
7466c93ee8dSXinliang David Li     uint64_t NFields =
7476c93ee8dSXinliang David Li         endian::byte_swap<uint64_t, little>(SummaryInLE->NumSummaryFields);
7486c93ee8dSXinliang David Li     uint64_t NEntries =
7496c93ee8dSXinliang David Li         endian::byte_swap<uint64_t, little>(SummaryInLE->NumCutoffEntries);
7506c93ee8dSXinliang David Li     uint32_t SummarySize =
7516c93ee8dSXinliang David Li         IndexedInstrProf::Summary::getSize(NFields, NEntries);
7526c93ee8dSXinliang David Li     std::unique_ptr<IndexedInstrProf::Summary> SummaryData =
7536c93ee8dSXinliang David Li         IndexedInstrProf::allocSummary(SummarySize);
7546c93ee8dSXinliang David Li 
7556c93ee8dSXinliang David Li     const uint64_t *Src = reinterpret_cast<const uint64_t *>(SummaryInLE);
7566c93ee8dSXinliang David Li     uint64_t *Dst = reinterpret_cast<uint64_t *>(SummaryData.get());
7576c93ee8dSXinliang David Li     for (unsigned I = 0; I < SummarySize / sizeof(uint64_t); I++)
7586c93ee8dSXinliang David Li       Dst[I] = endian::byte_swap<uint64_t, little>(Src[I]);
7596c93ee8dSXinliang David Li 
76072208a82SEugene Zelenko     SummaryEntryVector DetailedSummary;
761e5a17e3fSEaswaran Raman     for (unsigned I = 0; I < SummaryData->NumCutoffEntries; I++) {
762e5a17e3fSEaswaran Raman       const IndexedInstrProf::Summary::Entry &Ent = SummaryData->getEntry(I);
763e5a17e3fSEaswaran Raman       DetailedSummary.emplace_back((uint32_t)Ent.Cutoff, Ent.MinBlockCount,
764e5a17e3fSEaswaran Raman                                    Ent.NumBlocks);
765e5a17e3fSEaswaran Raman     }
766a6ff69f6SRong Xu     std::unique_ptr<llvm::ProfileSummary> &Summary =
767a6ff69f6SRong Xu         UseCS ? this->CS_Summary : this->Summary;
768a6ff69f6SRong Xu 
7694309570dSEaswaran Raman     // initialize InstrProfSummary using the SummaryData from disk.
770*0eaee545SJonas Devlieghere     Summary = std::make_unique<ProfileSummary>(
771a6ff69f6SRong Xu         UseCS ? ProfileSummary::PSK_CSInstr : ProfileSummary::PSK_Instr,
772a6ff69f6SRong Xu         DetailedSummary, SummaryData->get(Summary::TotalBlockCount),
773e5a17e3fSEaswaran Raman         SummaryData->get(Summary::MaxBlockCount),
774e5a17e3fSEaswaran Raman         SummaryData->get(Summary::MaxInternalBlockCount),
775e5a17e3fSEaswaran Raman         SummaryData->get(Summary::MaxFunctionCount),
776e5a17e3fSEaswaran Raman         SummaryData->get(Summary::TotalNumBlocks),
7777cefdb81SEaswaran Raman         SummaryData->get(Summary::TotalNumFunctions));
7786c93ee8dSXinliang David Li     return Cur + SummarySize;
7796c93ee8dSXinliang David Li   } else {
7806c93ee8dSXinliang David Li     // For older version of profile data, we need to compute on the fly:
7816c93ee8dSXinliang David Li     using namespace IndexedInstrProf;
782e78d131aSEugene Zelenko 
783e5a17e3fSEaswaran Raman     InstrProfSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
784e5a17e3fSEaswaran Raman     // FIXME: This only computes an empty summary. Need to call addRecord for
785cf9d52c6SDavid Blaikie     // all NamedInstrProfRecords to get the correct summary.
78638de59e4SBenjamin Kramer     this->Summary = Builder.getSummary();
7876c93ee8dSXinliang David Li     return Cur;
7886c93ee8dSXinliang David Li   }
7896c93ee8dSXinliang David Li }
7906c93ee8dSXinliang David Li 
7919152fd17SVedant Kumar Error IndexedInstrProfReader::readHeader() {
792e78d131aSEugene Zelenko   using namespace support;
793e78d131aSEugene Zelenko 
794a7c9ed57SAaron Ballman   const unsigned char *Start =
795a7c9ed57SAaron Ballman       (const unsigned char *)DataBuffer->getBufferStart();
796b7aa2630SJustin Bogner   const unsigned char *Cur = Start;
797a7c9ed57SAaron Ballman   if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24)
798b7aa2630SJustin Bogner     return error(instrprof_error::truncated);
799b7aa2630SJustin Bogner 
800dab183edSXinliang David Li   auto *Header = reinterpret_cast<const IndexedInstrProf::Header *>(Cur);
801dab183edSXinliang David Li   Cur += sizeof(IndexedInstrProf::Header);
802dab183edSXinliang David Li 
803b7aa2630SJustin Bogner   // Check the magic number.
804dab183edSXinliang David Li   uint64_t Magic = endian::byte_swap<uint64_t, little>(Header->Magic);
805b7aa2630SJustin Bogner   if (Magic != IndexedInstrProf::Magic)
806b7aa2630SJustin Bogner     return error(instrprof_error::bad_magic);
807b7aa2630SJustin Bogner 
808b7aa2630SJustin Bogner   // Read the version.
809140f4c4fSXinliang David Li   uint64_t FormatVersion = endian::byte_swap<uint64_t, little>(Header->Version);
81033c76c0cSRong Xu   if (GET_VERSION(FormatVersion) >
81133c76c0cSRong Xu       IndexedInstrProf::ProfVersion::CurrentVersion)
812b7aa2630SJustin Bogner     return error(instrprof_error::unsupported_version);
813b7aa2630SJustin Bogner 
814a6ff69f6SRong Xu   Cur = readSummary((IndexedInstrProf::ProfVersion)FormatVersion, Cur,
815a6ff69f6SRong Xu                     /* UseCS */ false);
81605c0afe8SRong Xu   if (FormatVersion & VARIANT_MASK_CSIR_PROF)
817a6ff69f6SRong Xu     Cur = readSummary((IndexedInstrProf::ProfVersion)FormatVersion, Cur,
818a6ff69f6SRong Xu                       /* UseCS */ true);
819b7aa2630SJustin Bogner 
820b7aa2630SJustin Bogner   // Read the hash type and start offset.
821b7aa2630SJustin Bogner   IndexedInstrProf::HashT HashType = static_cast<IndexedInstrProf::HashT>(
822dab183edSXinliang David Li       endian::byte_swap<uint64_t, little>(Header->HashType));
823b7aa2630SJustin Bogner   if (HashType > IndexedInstrProf::HashT::Last)
824b7aa2630SJustin Bogner     return error(instrprof_error::unsupported_hash_type);
825dab183edSXinliang David Li 
826dab183edSXinliang David Li   uint64_t HashOffset = endian::byte_swap<uint64_t, little>(Header->HashOffset);
827b7aa2630SJustin Bogner 
828b7aa2630SJustin Bogner   // The rest of the file is an on disk hash table.
829ceed4eb1SRichard Smith   auto IndexPtr =
830*0eaee545SJonas Devlieghere       std::make_unique<InstrProfReaderIndex<OnDiskHashTableImplV3>>(
831a28306dbSXinliang David Li           Start + HashOffset, Cur, Start, HashType, FormatVersion);
832ceed4eb1SRichard Smith 
833ceed4eb1SRichard Smith   // Load the remapping table now if requested.
834ceed4eb1SRichard Smith   if (RemappingBuffer) {
835*0eaee545SJonas Devlieghere     Remapper = std::make_unique<
836ceed4eb1SRichard Smith         InstrProfReaderItaniumRemapper<OnDiskHashTableImplV3>>(
837ceed4eb1SRichard Smith         std::move(RemappingBuffer), *IndexPtr);
838ceed4eb1SRichard Smith     if (Error E = Remapper->populateRemappings())
839ceed4eb1SRichard Smith       return E;
840ceed4eb1SRichard Smith   } else {
841*0eaee545SJonas Devlieghere     Remapper = std::make_unique<InstrProfReaderNullRemapper>(*IndexPtr);
842ceed4eb1SRichard Smith   }
843ceed4eb1SRichard Smith   Index = std::move(IndexPtr);
844ceed4eb1SRichard Smith 
845b7aa2630SJustin Bogner   return success();
846b7aa2630SJustin Bogner }
847b7aa2630SJustin Bogner 
848a716cc5cSXinliang David Li InstrProfSymtab &IndexedInstrProfReader::getSymtab() {
849a716cc5cSXinliang David Li   if (Symtab.get())
850a716cc5cSXinliang David Li     return *Symtab.get();
851a716cc5cSXinliang David Li 
852*0eaee545SJonas Devlieghere   std::unique_ptr<InstrProfSymtab> NewSymtab = std::make_unique<InstrProfSymtab>();
853b5794ca9SVedant Kumar   if (Error E = Index->populateSymtab(*NewSymtab.get())) {
854b5794ca9SVedant Kumar     consumeError(error(InstrProfError::take(std::move(E))));
855b5794ca9SVedant Kumar   }
856a716cc5cSXinliang David Li 
857a716cc5cSXinliang David Li   Symtab = std::move(NewSymtab);
858a716cc5cSXinliang David Li   return *Symtab.get();
859a716cc5cSXinliang David Li }
860a716cc5cSXinliang David Li 
8619152fd17SVedant Kumar Expected<InstrProfRecord>
8626aa216c2SXinliang David Li IndexedInstrProfReader::getInstrProfRecord(StringRef FuncName,
8636aa216c2SXinliang David Li                                            uint64_t FuncHash) {
864cf9d52c6SDavid Blaikie   ArrayRef<NamedInstrProfRecord> Data;
865ceed4eb1SRichard Smith   Error Err = Remapper->getRecords(FuncName, Data);
8669152fd17SVedant Kumar   if (Err)
8679152fd17SVedant Kumar     return std::move(Err);
868821d7471SJustin Bogner   // Found it. Look for counters with the right hash.
8693a7d44cbSJustin Bogner   for (unsigned I = 0, E = Data.size(); I < E; ++I) {
870821d7471SJustin Bogner     // Check for a match and fill the vector if there is one.
8713a7d44cbSJustin Bogner     if (Data[I].Hash == FuncHash) {
8722004f003SXinliang David Li       return std::move(Data[I]);
873b7aa2630SJustin Bogner     }
874821d7471SJustin Bogner   }
875821d7471SJustin Bogner   return error(instrprof_error::hash_mismatch);
876821d7471SJustin Bogner }
877b7aa2630SJustin Bogner 
8789152fd17SVedant Kumar Error IndexedInstrProfReader::getFunctionCounts(StringRef FuncName,
8799152fd17SVedant Kumar                                                 uint64_t FuncHash,
8806aa216c2SXinliang David Li                                                 std::vector<uint64_t> &Counts) {
8819152fd17SVedant Kumar   Expected<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash);
8829152fd17SVedant Kumar   if (Error E = Record.takeError())
8839152fd17SVedant Kumar     return error(std::move(E));
8842004f003SXinliang David Li 
8852004f003SXinliang David Li   Counts = Record.get().Counts;
8862004f003SXinliang David Li   return success();
8872004f003SXinliang David Li }
8882004f003SXinliang David Li 
889cf9d52c6SDavid Blaikie Error IndexedInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
890cf9d52c6SDavid Blaikie   ArrayRef<NamedInstrProfRecord> Data;
891140f4c4fSXinliang David Li 
8929152fd17SVedant Kumar   Error E = Index->getRecords(Data);
8939152fd17SVedant Kumar   if (E)
8949152fd17SVedant Kumar     return error(std::move(E));
895140f4c4fSXinliang David Li 
8963a7d44cbSJustin Bogner   Record = Data[RecordIndex++];
8973a7d44cbSJustin Bogner   if (RecordIndex >= Data.size()) {
898a28306dbSXinliang David Li     Index->advanceToNextKey();
8993a7d44cbSJustin Bogner     RecordIndex = 0;
900821d7471SJustin Bogner   }
901b7aa2630SJustin Bogner   return success();
902b7aa2630SJustin Bogner }
903998b97f6SRong Xu 
904998b97f6SRong Xu void InstrProfReader::accumuateCounts(CountSumOrPercent &Sum, bool IsCS) {
905998b97f6SRong Xu   uint64_t NumFuncs = 0;
906998b97f6SRong Xu   for (const auto &Func : *this) {
907998b97f6SRong Xu     if (isIRLevelProfile()) {
908998b97f6SRong Xu       bool FuncIsCS = NamedInstrProfRecord::hasCSFlagInHash(Func.Hash);
909998b97f6SRong Xu       if (FuncIsCS != IsCS)
910998b97f6SRong Xu         continue;
911998b97f6SRong Xu     }
912998b97f6SRong Xu     Func.accumuateCounts(Sum);
913998b97f6SRong Xu     ++NumFuncs;
914998b97f6SRong Xu   }
915998b97f6SRong Xu   Sum.NumEntries = NumFuncs;
916998b97f6SRong Xu }
917