1f8d79198SJustin Bogner //=-- InstrProfReader.cpp - Instrumented profiling reader -------------------=//
2f8d79198SJustin Bogner //
3f8d79198SJustin Bogner //                     The LLVM Compiler Infrastructure
4f8d79198SJustin Bogner //
5f8d79198SJustin Bogner // This file is distributed under the University of Illinois Open Source
6f8d79198SJustin Bogner // License. See LICENSE.TXT for details.
7f8d79198SJustin Bogner //
8f8d79198SJustin Bogner //===----------------------------------------------------------------------===//
9f8d79198SJustin Bogner //
10f8d79198SJustin Bogner // This file contains support for reading profiling data for clang's
11f8d79198SJustin Bogner // instrumentation based PGO and coverage.
12f8d79198SJustin Bogner //
13f8d79198SJustin Bogner //===----------------------------------------------------------------------===//
14f8d79198SJustin Bogner 
15f8d79198SJustin Bogner #include "llvm/ProfileData/InstrProfReader.h"
16f8d79198SJustin Bogner #include "llvm/ProfileData/InstrProf.h"
17f8d79198SJustin Bogner 
18b7aa2630SJustin Bogner #include "InstrProfIndexed.h"
19b7aa2630SJustin Bogner 
20f8d79198SJustin Bogner #include <cassert>
21f8d79198SJustin Bogner 
22f8d79198SJustin Bogner using namespace llvm;
23f8d79198SJustin Bogner 
24db4ed0bdSRafael Espindola static std::error_code
25db4ed0bdSRafael Espindola setupMemoryBuffer(std::string Path, std::unique_ptr<MemoryBuffer> &Buffer) {
26adf21f2aSRafael Espindola   ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
27adf21f2aSRafael Espindola       MemoryBuffer::getFileOrSTDIN(Path);
28adf21f2aSRafael Espindola   if (std::error_code EC = BufferOrErr.getError())
29f8d79198SJustin Bogner     return EC;
30adf21f2aSRafael Espindola   Buffer = std::move(BufferOrErr.get());
31f8d79198SJustin Bogner 
32f8d79198SJustin Bogner   // Sanity check the file.
33f8d79198SJustin Bogner   if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max())
34f8d79198SJustin Bogner     return instrprof_error::too_large;
35b7aa2630SJustin Bogner   return instrprof_error::success;
36b7aa2630SJustin Bogner }
37b7aa2630SJustin Bogner 
38db4ed0bdSRafael Espindola static std::error_code initializeReader(InstrProfReader &Reader) {
39b7aa2630SJustin Bogner   return Reader.readHeader();
40b7aa2630SJustin Bogner }
41b7aa2630SJustin Bogner 
42db4ed0bdSRafael Espindola std::error_code
43db4ed0bdSRafael Espindola InstrProfReader::create(std::string Path,
44b7aa2630SJustin Bogner                         std::unique_ptr<InstrProfReader> &Result) {
45b7aa2630SJustin Bogner   // Set up the buffer to read.
46b7aa2630SJustin Bogner   std::unique_ptr<MemoryBuffer> Buffer;
47db4ed0bdSRafael Espindola   if (std::error_code EC = setupMemoryBuffer(Path, Buffer))
48b7aa2630SJustin Bogner     return EC;
49f8d79198SJustin Bogner 
5009a67f45SDuncan P. N. Exon Smith   // Create the reader.
51b7aa2630SJustin Bogner   if (IndexedInstrProfReader::hasFormat(*Buffer))
52b7aa2630SJustin Bogner     Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
53b7aa2630SJustin Bogner   else if (RawInstrProfReader64::hasFormat(*Buffer))
544680361dSDuncan P. N. Exon Smith     Result.reset(new RawInstrProfReader64(std::move(Buffer)));
554680361dSDuncan P. N. Exon Smith   else if (RawInstrProfReader32::hasFormat(*Buffer))
564680361dSDuncan P. N. Exon Smith     Result.reset(new RawInstrProfReader32(std::move(Buffer)));
5724b4b653SDuncan P. N. Exon Smith   else
584c5b7cb1SDuncan P. N. Exon Smith     Result.reset(new TextInstrProfReader(std::move(Buffer)));
5909a67f45SDuncan P. N. Exon Smith 
60b7aa2630SJustin Bogner   // Initialize the reader and return the result.
61b7aa2630SJustin Bogner   return initializeReader(*Result);
62b7aa2630SJustin Bogner }
63b7aa2630SJustin Bogner 
64db4ed0bdSRafael Espindola std::error_code IndexedInstrProfReader::create(
65b7aa2630SJustin Bogner     std::string Path, std::unique_ptr<IndexedInstrProfReader> &Result) {
66b7aa2630SJustin Bogner   // Set up the buffer to read.
67b7aa2630SJustin Bogner   std::unique_ptr<MemoryBuffer> Buffer;
68db4ed0bdSRafael Espindola   if (std::error_code EC = setupMemoryBuffer(Path, Buffer))
69b7aa2630SJustin Bogner     return EC;
70b7aa2630SJustin Bogner 
71b7aa2630SJustin Bogner   // Create the reader.
72b7aa2630SJustin Bogner   if (!IndexedInstrProfReader::hasFormat(*Buffer))
73b7aa2630SJustin Bogner     return instrprof_error::bad_magic;
74b7aa2630SJustin Bogner   Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
75b7aa2630SJustin Bogner 
76b7aa2630SJustin Bogner   // Initialize the reader and return the result.
77b7aa2630SJustin Bogner   return initializeReader(*Result);
78f8d79198SJustin Bogner }
79f8d79198SJustin Bogner 
80f8d79198SJustin Bogner void InstrProfIterator::Increment() {
81f8d79198SJustin Bogner   if (Reader->readNextRecord(Record))
82f8d79198SJustin Bogner     *this = InstrProfIterator();
83f8d79198SJustin Bogner }
84f8d79198SJustin Bogner 
85db4ed0bdSRafael Espindola std::error_code TextInstrProfReader::readNextRecord(InstrProfRecord &Record) {
86*cf36a366SJustin Bogner   // Skip empty lines and comments.
87*cf36a366SJustin Bogner   while (!Line.is_at_end() && (Line->empty() || Line->startswith("#")))
88f8d79198SJustin Bogner     ++Line;
89f8d79198SJustin Bogner   // If we hit EOF while looking for a name, we're done.
90f8d79198SJustin Bogner   if (Line.is_at_end())
91f8d79198SJustin Bogner     return error(instrprof_error::eof);
92f8d79198SJustin Bogner 
93f8d79198SJustin Bogner   // Read the function name.
94f8d79198SJustin Bogner   Record.Name = *Line++;
95f8d79198SJustin Bogner 
96f8d79198SJustin Bogner   // Read the function hash.
97f8d79198SJustin Bogner   if (Line.is_at_end())
98f8d79198SJustin Bogner     return error(instrprof_error::truncated);
99f8d79198SJustin Bogner   if ((Line++)->getAsInteger(10, Record.Hash))
100f8d79198SJustin Bogner     return error(instrprof_error::malformed);
101f8d79198SJustin Bogner 
102f8d79198SJustin Bogner   // Read the number of counters.
103f8d79198SJustin Bogner   uint64_t NumCounters;
104f8d79198SJustin Bogner   if (Line.is_at_end())
105f8d79198SJustin Bogner     return error(instrprof_error::truncated);
106f8d79198SJustin Bogner   if ((Line++)->getAsInteger(10, NumCounters))
107f8d79198SJustin Bogner     return error(instrprof_error::malformed);
108b59d7c73SJustin Bogner   if (NumCounters == 0)
109b59d7c73SJustin Bogner     return error(instrprof_error::malformed);
110f8d79198SJustin Bogner 
111f8d79198SJustin Bogner   // Read each counter and fill our internal storage with the values.
112f8d79198SJustin Bogner   Counts.clear();
113f8d79198SJustin Bogner   Counts.reserve(NumCounters);
114f8d79198SJustin Bogner   for (uint64_t I = 0; I < NumCounters; ++I) {
115f8d79198SJustin Bogner     if (Line.is_at_end())
116f8d79198SJustin Bogner       return error(instrprof_error::truncated);
117f8d79198SJustin Bogner     uint64_t Count;
118f8d79198SJustin Bogner     if ((Line++)->getAsInteger(10, Count))
119f8d79198SJustin Bogner       return error(instrprof_error::malformed);
120f8d79198SJustin Bogner     Counts.push_back(Count);
121f8d79198SJustin Bogner   }
122f8d79198SJustin Bogner   // Give the record a reference to our internal counter storage.
123f8d79198SJustin Bogner   Record.Counts = Counts;
124f8d79198SJustin Bogner 
125f8d79198SJustin Bogner   return success();
126f8d79198SJustin Bogner }
12724b4b653SDuncan P. N. Exon Smith 
1284680361dSDuncan P. N. Exon Smith template <class IntPtrT>
1294680361dSDuncan P. N. Exon Smith static uint64_t getRawMagic();
1304680361dSDuncan P. N. Exon Smith 
1314680361dSDuncan P. N. Exon Smith template <>
1324680361dSDuncan P. N. Exon Smith uint64_t getRawMagic<uint64_t>() {
13309a67f45SDuncan P. N. Exon Smith   return
134745a2bf0SDuncan P. N. Exon Smith     uint64_t(255) << 56 |
135745a2bf0SDuncan P. N. Exon Smith     uint64_t('l') << 48 |
136745a2bf0SDuncan P. N. Exon Smith     uint64_t('p') << 40 |
137745a2bf0SDuncan P. N. Exon Smith     uint64_t('r') << 32 |
138745a2bf0SDuncan P. N. Exon Smith     uint64_t('o') << 24 |
139745a2bf0SDuncan P. N. Exon Smith     uint64_t('f') << 16 |
140745a2bf0SDuncan P. N. Exon Smith     uint64_t('r') <<  8 |
141745a2bf0SDuncan P. N. Exon Smith     uint64_t(129);
14209a67f45SDuncan P. N. Exon Smith }
14309a67f45SDuncan P. N. Exon Smith 
1444680361dSDuncan P. N. Exon Smith template <>
1454680361dSDuncan P. N. Exon Smith uint64_t getRawMagic<uint32_t>() {
1464680361dSDuncan P. N. Exon Smith   return
1474680361dSDuncan P. N. Exon Smith     uint64_t(255) << 56 |
1484680361dSDuncan P. N. Exon Smith     uint64_t('l') << 48 |
1494680361dSDuncan P. N. Exon Smith     uint64_t('p') << 40 |
1504680361dSDuncan P. N. Exon Smith     uint64_t('r') << 32 |
1514680361dSDuncan P. N. Exon Smith     uint64_t('o') << 24 |
1524680361dSDuncan P. N. Exon Smith     uint64_t('f') << 16 |
1534680361dSDuncan P. N. Exon Smith     uint64_t('R') <<  8 |
1544680361dSDuncan P. N. Exon Smith     uint64_t(129);
15509a67f45SDuncan P. N. Exon Smith }
15609a67f45SDuncan P. N. Exon Smith 
1574680361dSDuncan P. N. Exon Smith template <class IntPtrT>
1584680361dSDuncan P. N. Exon Smith bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) {
159d7d83477SDuncan P. N. Exon Smith   if (DataBuffer.getBufferSize() < sizeof(uint64_t))
1604680361dSDuncan P. N. Exon Smith     return false;
161d7d83477SDuncan P. N. Exon Smith   uint64_t Magic =
162d7d83477SDuncan P. N. Exon Smith     *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart());
163d7d83477SDuncan P. N. Exon Smith   return getRawMagic<IntPtrT>() == Magic ||
164ef5e867fSArtyom Skrobov     sys::getSwappedBytes(getRawMagic<IntPtrT>()) == Magic;
1654680361dSDuncan P. N. Exon Smith }
1664680361dSDuncan P. N. Exon Smith 
1674680361dSDuncan P. N. Exon Smith template <class IntPtrT>
168db4ed0bdSRafael Espindola std::error_code RawInstrProfReader<IntPtrT>::readHeader() {
16909a67f45SDuncan P. N. Exon Smith   if (!hasFormat(*DataBuffer))
17009a67f45SDuncan P. N. Exon Smith     return error(instrprof_error::bad_magic);
17124b4b653SDuncan P. N. Exon Smith   if (DataBuffer->getBufferSize() < sizeof(RawHeader))
172531bb481SDuncan P. N. Exon Smith     return error(instrprof_error::bad_header);
173d7d83477SDuncan P. N. Exon Smith   auto *Header =
174d7d83477SDuncan P. N. Exon Smith     reinterpret_cast<const RawHeader *>(DataBuffer->getBufferStart());
1754680361dSDuncan P. N. Exon Smith   ShouldSwapBytes = Header->Magic != getRawMagic<IntPtrT>();
17624b4b653SDuncan P. N. Exon Smith   return readHeader(*Header);
17724b4b653SDuncan P. N. Exon Smith }
17824b4b653SDuncan P. N. Exon Smith 
179a119f323SJustin Bogner template <class IntPtrT>
180db4ed0bdSRafael Espindola std::error_code
181db4ed0bdSRafael Espindola RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
182a119f323SJustin Bogner   const char *End = DataBuffer->getBufferEnd();
183a119f323SJustin Bogner   // Skip zero padding between profiles.
184a119f323SJustin Bogner   while (CurrentPos != End && *CurrentPos == 0)
185a119f323SJustin Bogner     ++CurrentPos;
186a119f323SJustin Bogner   // If there's nothing left, we're done.
187a119f323SJustin Bogner   if (CurrentPos == End)
188a119f323SJustin Bogner     return instrprof_error::eof;
189a119f323SJustin Bogner   // If there isn't enough space for another header, this is probably just
190a119f323SJustin Bogner   // garbage at the end of the file.
191a119f323SJustin Bogner   if (CurrentPos + sizeof(RawHeader) > End)
192a119f323SJustin Bogner     return instrprof_error::malformed;
193a119f323SJustin Bogner   // The magic should have the same byte order as in the previous header.
194a119f323SJustin Bogner   uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos);
195a119f323SJustin Bogner   if (Magic != swap(getRawMagic<IntPtrT>()))
196a119f323SJustin Bogner     return instrprof_error::bad_magic;
197a119f323SJustin Bogner 
198a119f323SJustin Bogner   // There's another profile to read, so we need to process the header.
199a119f323SJustin Bogner   auto *Header = reinterpret_cast<const RawHeader *>(CurrentPos);
200a119f323SJustin Bogner   return readHeader(*Header);
201a119f323SJustin Bogner }
202a119f323SJustin Bogner 
20309a67f45SDuncan P. N. Exon Smith static uint64_t getRawVersion() {
20409a67f45SDuncan P. N. Exon Smith   return 1;
20509a67f45SDuncan P. N. Exon Smith }
20609a67f45SDuncan P. N. Exon Smith 
2074680361dSDuncan P. N. Exon Smith template <class IntPtrT>
208db4ed0bdSRafael Espindola std::error_code
209db4ed0bdSRafael Espindola RawInstrProfReader<IntPtrT>::readHeader(const RawHeader &Header) {
21024b4b653SDuncan P. N. Exon Smith   if (swap(Header.Version) != getRawVersion())
21124b4b653SDuncan P. N. Exon Smith     return error(instrprof_error::unsupported_version);
21224b4b653SDuncan P. N. Exon Smith 
21324b4b653SDuncan P. N. Exon Smith   CountersDelta = swap(Header.CountersDelta);
21424b4b653SDuncan P. N. Exon Smith   NamesDelta = swap(Header.NamesDelta);
21524b4b653SDuncan P. N. Exon Smith   auto DataSize = swap(Header.DataSize);
21624b4b653SDuncan P. N. Exon Smith   auto CountersSize = swap(Header.CountersSize);
21724b4b653SDuncan P. N. Exon Smith   auto NamesSize = swap(Header.NamesSize);
21824b4b653SDuncan P. N. Exon Smith 
21924b4b653SDuncan P. N. Exon Smith   ptrdiff_t DataOffset = sizeof(RawHeader);
22024b4b653SDuncan P. N. Exon Smith   ptrdiff_t CountersOffset = DataOffset + sizeof(ProfileData) * DataSize;
22124b4b653SDuncan P. N. Exon Smith   ptrdiff_t NamesOffset = CountersOffset + sizeof(uint64_t) * CountersSize;
222a119f323SJustin Bogner   size_t ProfileSize = NamesOffset + sizeof(char) * NamesSize;
22324b4b653SDuncan P. N. Exon Smith 
224a119f323SJustin Bogner   auto *Start = reinterpret_cast<const char *>(&Header);
225a119f323SJustin Bogner   if (Start + ProfileSize > DataBuffer->getBufferEnd())
226531bb481SDuncan P. N. Exon Smith     return error(instrprof_error::bad_header);
22724b4b653SDuncan P. N. Exon Smith 
228d7d83477SDuncan P. N. Exon Smith   Data = reinterpret_cast<const ProfileData *>(Start + DataOffset);
22924b4b653SDuncan P. N. Exon Smith   DataEnd = Data + DataSize;
230d7d83477SDuncan P. N. Exon Smith   CountersStart = reinterpret_cast<const uint64_t *>(Start + CountersOffset);
231d7d83477SDuncan P. N. Exon Smith   NamesStart = Start + NamesOffset;
232a119f323SJustin Bogner   ProfileEnd = Start + ProfileSize;
23324b4b653SDuncan P. N. Exon Smith 
23424b4b653SDuncan P. N. Exon Smith   return success();
23524b4b653SDuncan P. N. Exon Smith }
23624b4b653SDuncan P. N. Exon Smith 
2374680361dSDuncan P. N. Exon Smith template <class IntPtrT>
238db4ed0bdSRafael Espindola std::error_code
2394680361dSDuncan P. N. Exon Smith RawInstrProfReader<IntPtrT>::readNextRecord(InstrProfRecord &Record) {
24024b4b653SDuncan P. N. Exon Smith   if (Data == DataEnd)
241db4ed0bdSRafael Espindola     if (std::error_code EC = readNextHeader(ProfileEnd))
242a119f323SJustin Bogner       return EC;
24324b4b653SDuncan P. N. Exon Smith 
24424b4b653SDuncan P. N. Exon Smith   // Get the raw data.
24524b4b653SDuncan P. N. Exon Smith   StringRef RawName(getName(Data->NamePtr), swap(Data->NameSize));
246b59d7c73SJustin Bogner   uint32_t NumCounters = swap(Data->NumCounters);
247b59d7c73SJustin Bogner   if (NumCounters == 0)
248b59d7c73SJustin Bogner     return error(instrprof_error::malformed);
249b59d7c73SJustin Bogner   auto RawCounts = makeArrayRef(getCounter(Data->CounterPtr), NumCounters);
25024b4b653SDuncan P. N. Exon Smith 
25124b4b653SDuncan P. N. Exon Smith   // Check bounds.
252d7d83477SDuncan P. N. Exon Smith   auto *NamesStartAsCounter = reinterpret_cast<const uint64_t *>(NamesStart);
25324b4b653SDuncan P. N. Exon Smith   if (RawName.data() < NamesStart ||
25424b4b653SDuncan P. N. Exon Smith       RawName.data() + RawName.size() > DataBuffer->getBufferEnd() ||
25524b4b653SDuncan P. N. Exon Smith       RawCounts.data() < CountersStart ||
256d7d83477SDuncan P. N. Exon Smith       RawCounts.data() + RawCounts.size() > NamesStartAsCounter)
25724b4b653SDuncan P. N. Exon Smith     return error(instrprof_error::malformed);
25824b4b653SDuncan P. N. Exon Smith 
25924b4b653SDuncan P. N. Exon Smith   // Store the data in Record, byte-swapping as necessary.
26024b4b653SDuncan P. N. Exon Smith   Record.Hash = swap(Data->FuncHash);
26124b4b653SDuncan P. N. Exon Smith   Record.Name = RawName;
26224b4b653SDuncan P. N. Exon Smith   if (ShouldSwapBytes) {
26324b4b653SDuncan P. N. Exon Smith     Counts.clear();
26424b4b653SDuncan P. N. Exon Smith     Counts.reserve(RawCounts.size());
26524b4b653SDuncan P. N. Exon Smith     for (uint64_t Count : RawCounts)
26624b4b653SDuncan P. N. Exon Smith       Counts.push_back(swap(Count));
26724b4b653SDuncan P. N. Exon Smith     Record.Counts = Counts;
26824b4b653SDuncan P. N. Exon Smith   } else
26924b4b653SDuncan P. N. Exon Smith     Record.Counts = RawCounts;
27024b4b653SDuncan P. N. Exon Smith 
27124b4b653SDuncan P. N. Exon Smith   // Iterate.
27224b4b653SDuncan P. N. Exon Smith   ++Data;
27324b4b653SDuncan P. N. Exon Smith   return success();
27424b4b653SDuncan P. N. Exon Smith }
2754680361dSDuncan P. N. Exon Smith 
2764680361dSDuncan P. N. Exon Smith namespace llvm {
2774680361dSDuncan P. N. Exon Smith template class RawInstrProfReader<uint32_t>;
2784680361dSDuncan P. N. Exon Smith template class RawInstrProfReader<uint64_t>;
2794680361dSDuncan P. N. Exon Smith }
280b7aa2630SJustin Bogner 
281b5d368e8SJustin Bogner InstrProfLookupTrait::hash_value_type
282b5d368e8SJustin Bogner InstrProfLookupTrait::ComputeHash(StringRef K) {
283b5d368e8SJustin Bogner   return IndexedInstrProf::ComputeHash(HashType, K);
284b5d368e8SJustin Bogner }
285b5d368e8SJustin Bogner 
286b7aa2630SJustin Bogner bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) {
287b7aa2630SJustin Bogner   if (DataBuffer.getBufferSize() < 8)
288b7aa2630SJustin Bogner     return false;
289b7aa2630SJustin Bogner   using namespace support;
290b7aa2630SJustin Bogner   uint64_t Magic =
291b7aa2630SJustin Bogner       endian::read<uint64_t, little, aligned>(DataBuffer.getBufferStart());
292b7aa2630SJustin Bogner   return Magic == IndexedInstrProf::Magic;
293b7aa2630SJustin Bogner }
294b7aa2630SJustin Bogner 
295db4ed0bdSRafael Espindola std::error_code IndexedInstrProfReader::readHeader() {
296a7c9ed57SAaron Ballman   const unsigned char *Start =
297a7c9ed57SAaron Ballman       (const unsigned char *)DataBuffer->getBufferStart();
298b7aa2630SJustin Bogner   const unsigned char *Cur = Start;
299a7c9ed57SAaron Ballman   if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24)
300b7aa2630SJustin Bogner     return error(instrprof_error::truncated);
301b7aa2630SJustin Bogner 
302b7aa2630SJustin Bogner   using namespace support;
303b7aa2630SJustin Bogner 
304b7aa2630SJustin Bogner   // Check the magic number.
305b7aa2630SJustin Bogner   uint64_t Magic = endian::readNext<uint64_t, little, unaligned>(Cur);
306b7aa2630SJustin Bogner   if (Magic != IndexedInstrProf::Magic)
307b7aa2630SJustin Bogner     return error(instrprof_error::bad_magic);
308b7aa2630SJustin Bogner 
309b7aa2630SJustin Bogner   // Read the version.
310b7aa2630SJustin Bogner   uint64_t Version = endian::readNext<uint64_t, little, unaligned>(Cur);
311b7aa2630SJustin Bogner   if (Version != IndexedInstrProf::Version)
312b7aa2630SJustin Bogner     return error(instrprof_error::unsupported_version);
313b7aa2630SJustin Bogner 
314b7aa2630SJustin Bogner   // Read the maximal function count.
315b7aa2630SJustin Bogner   MaxFunctionCount = endian::readNext<uint64_t, little, unaligned>(Cur);
316b7aa2630SJustin Bogner 
317b7aa2630SJustin Bogner   // Read the hash type and start offset.
318b7aa2630SJustin Bogner   IndexedInstrProf::HashT HashType = static_cast<IndexedInstrProf::HashT>(
319b7aa2630SJustin Bogner       endian::readNext<uint64_t, little, unaligned>(Cur));
320b7aa2630SJustin Bogner   if (HashType > IndexedInstrProf::HashT::Last)
321b7aa2630SJustin Bogner     return error(instrprof_error::unsupported_hash_type);
322b7aa2630SJustin Bogner   uint64_t HashOffset = endian::readNext<uint64_t, little, unaligned>(Cur);
323b7aa2630SJustin Bogner 
324b7aa2630SJustin Bogner   // The rest of the file is an on disk hash table.
325b7aa2630SJustin Bogner   Index.reset(InstrProfReaderIndex::Create(Start + HashOffset, Cur, Start,
326b7aa2630SJustin Bogner                                            InstrProfLookupTrait(HashType)));
327b7aa2630SJustin Bogner   // Set up our iterator for readNextRecord.
328b7aa2630SJustin Bogner   RecordIterator = Index->data_begin();
329b7aa2630SJustin Bogner 
330b7aa2630SJustin Bogner   return success();
331b7aa2630SJustin Bogner }
332b7aa2630SJustin Bogner 
333db4ed0bdSRafael Espindola std::error_code IndexedInstrProfReader::getFunctionCounts(
334b7aa2630SJustin Bogner     StringRef FuncName, uint64_t &FuncHash, std::vector<uint64_t> &Counts) {
335b7aa2630SJustin Bogner   const auto &Iter = Index->find(FuncName);
336b7aa2630SJustin Bogner   if (Iter == Index->end())
337b7aa2630SJustin Bogner     return error(instrprof_error::unknown_function);
338b7aa2630SJustin Bogner 
339b7aa2630SJustin Bogner   // Found it. Make sure it's valid before giving back a result.
340b7aa2630SJustin Bogner   const InstrProfRecord &Record = *Iter;
341b7aa2630SJustin Bogner   if (Record.Name.empty())
342b7aa2630SJustin Bogner     return error(instrprof_error::malformed);
343b7aa2630SJustin Bogner   FuncHash = Record.Hash;
344b7aa2630SJustin Bogner   Counts = Record.Counts;
345b7aa2630SJustin Bogner   return success();
346b7aa2630SJustin Bogner }
347b7aa2630SJustin Bogner 
348db4ed0bdSRafael Espindola std::error_code
349db4ed0bdSRafael Espindola IndexedInstrProfReader::readNextRecord(InstrProfRecord &Record) {
350b7aa2630SJustin Bogner   // Are we out of records?
351b7aa2630SJustin Bogner   if (RecordIterator == Index->data_end())
352b7aa2630SJustin Bogner     return error(instrprof_error::eof);
353b7aa2630SJustin Bogner 
354b7aa2630SJustin Bogner   // Read the next one.
355b7aa2630SJustin Bogner   Record = *RecordIterator;
356b7aa2630SJustin Bogner   ++RecordIterator;
357b7aa2630SJustin Bogner   if (Record.Name.empty())
358b7aa2630SJustin Bogner     return error(instrprof_error::malformed);
359b7aa2630SJustin Bogner   return success();
360b7aa2630SJustin Bogner }
361