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) {
26db4ed0bdSRafael Espindola   if (std::error_code EC = MemoryBuffer::getFileOrSTDIN(Path, Buffer))
27f8d79198SJustin Bogner     return EC;
28f8d79198SJustin Bogner 
29f8d79198SJustin Bogner   // Sanity check the file.
30f8d79198SJustin Bogner   if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max())
31f8d79198SJustin Bogner     return instrprof_error::too_large;
32b7aa2630SJustin Bogner   return instrprof_error::success;
33b7aa2630SJustin Bogner }
34b7aa2630SJustin Bogner 
35db4ed0bdSRafael Espindola static std::error_code initializeReader(InstrProfReader &Reader) {
36b7aa2630SJustin Bogner   return Reader.readHeader();
37b7aa2630SJustin Bogner }
38b7aa2630SJustin Bogner 
39db4ed0bdSRafael Espindola std::error_code
40db4ed0bdSRafael Espindola InstrProfReader::create(std::string Path,
41b7aa2630SJustin Bogner                         std::unique_ptr<InstrProfReader> &Result) {
42b7aa2630SJustin Bogner   // Set up the buffer to read.
43b7aa2630SJustin Bogner   std::unique_ptr<MemoryBuffer> Buffer;
44db4ed0bdSRafael Espindola   if (std::error_code EC = setupMemoryBuffer(Path, Buffer))
45b7aa2630SJustin Bogner     return EC;
46f8d79198SJustin Bogner 
4709a67f45SDuncan P. N. Exon Smith   // Create the reader.
48b7aa2630SJustin Bogner   if (IndexedInstrProfReader::hasFormat(*Buffer))
49b7aa2630SJustin Bogner     Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
50b7aa2630SJustin Bogner   else if (RawInstrProfReader64::hasFormat(*Buffer))
514680361dSDuncan P. N. Exon Smith     Result.reset(new RawInstrProfReader64(std::move(Buffer)));
524680361dSDuncan P. N. Exon Smith   else if (RawInstrProfReader32::hasFormat(*Buffer))
534680361dSDuncan P. N. Exon Smith     Result.reset(new RawInstrProfReader32(std::move(Buffer)));
5424b4b653SDuncan P. N. Exon Smith   else
554c5b7cb1SDuncan P. N. Exon Smith     Result.reset(new TextInstrProfReader(std::move(Buffer)));
5609a67f45SDuncan P. N. Exon Smith 
57b7aa2630SJustin Bogner   // Initialize the reader and return the result.
58b7aa2630SJustin Bogner   return initializeReader(*Result);
59b7aa2630SJustin Bogner }
60b7aa2630SJustin Bogner 
61db4ed0bdSRafael Espindola std::error_code IndexedInstrProfReader::create(
62b7aa2630SJustin Bogner     std::string Path, std::unique_ptr<IndexedInstrProfReader> &Result) {
63b7aa2630SJustin Bogner   // Set up the buffer to read.
64b7aa2630SJustin Bogner   std::unique_ptr<MemoryBuffer> Buffer;
65db4ed0bdSRafael Espindola   if (std::error_code EC = setupMemoryBuffer(Path, Buffer))
66b7aa2630SJustin Bogner     return EC;
67b7aa2630SJustin Bogner 
68b7aa2630SJustin Bogner   // Create the reader.
69b7aa2630SJustin Bogner   if (!IndexedInstrProfReader::hasFormat(*Buffer))
70b7aa2630SJustin Bogner     return instrprof_error::bad_magic;
71b7aa2630SJustin Bogner   Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
72b7aa2630SJustin Bogner 
73b7aa2630SJustin Bogner   // Initialize the reader and return the result.
74b7aa2630SJustin Bogner   return initializeReader(*Result);
75f8d79198SJustin Bogner }
76f8d79198SJustin Bogner 
77f8d79198SJustin Bogner void InstrProfIterator::Increment() {
78f8d79198SJustin Bogner   if (Reader->readNextRecord(Record))
79f8d79198SJustin Bogner     *this = InstrProfIterator();
80f8d79198SJustin Bogner }
81f8d79198SJustin Bogner 
82db4ed0bdSRafael Espindola std::error_code TextInstrProfReader::readNextRecord(InstrProfRecord &Record) {
83f8d79198SJustin Bogner   // Skip empty lines.
84f8d79198SJustin Bogner   while (!Line.is_at_end() && Line->empty())
85f8d79198SJustin Bogner     ++Line;
86f8d79198SJustin Bogner   // If we hit EOF while looking for a name, we're done.
87f8d79198SJustin Bogner   if (Line.is_at_end())
88f8d79198SJustin Bogner     return error(instrprof_error::eof);
89f8d79198SJustin Bogner 
90f8d79198SJustin Bogner   // Read the function name.
91f8d79198SJustin Bogner   Record.Name = *Line++;
92f8d79198SJustin Bogner 
93f8d79198SJustin Bogner   // Read the function hash.
94f8d79198SJustin Bogner   if (Line.is_at_end())
95f8d79198SJustin Bogner     return error(instrprof_error::truncated);
96f8d79198SJustin Bogner   if ((Line++)->getAsInteger(10, Record.Hash))
97f8d79198SJustin Bogner     return error(instrprof_error::malformed);
98f8d79198SJustin Bogner 
99f8d79198SJustin Bogner   // Read the number of counters.
100f8d79198SJustin Bogner   uint64_t NumCounters;
101f8d79198SJustin Bogner   if (Line.is_at_end())
102f8d79198SJustin Bogner     return error(instrprof_error::truncated);
103f8d79198SJustin Bogner   if ((Line++)->getAsInteger(10, NumCounters))
104f8d79198SJustin Bogner     return error(instrprof_error::malformed);
105b59d7c73SJustin Bogner   if (NumCounters == 0)
106b59d7c73SJustin Bogner     return error(instrprof_error::malformed);
107f8d79198SJustin Bogner 
108f8d79198SJustin Bogner   // Read each counter and fill our internal storage with the values.
109f8d79198SJustin Bogner   Counts.clear();
110f8d79198SJustin Bogner   Counts.reserve(NumCounters);
111f8d79198SJustin Bogner   for (uint64_t I = 0; I < NumCounters; ++I) {
112f8d79198SJustin Bogner     if (Line.is_at_end())
113f8d79198SJustin Bogner       return error(instrprof_error::truncated);
114f8d79198SJustin Bogner     uint64_t Count;
115f8d79198SJustin Bogner     if ((Line++)->getAsInteger(10, Count))
116f8d79198SJustin Bogner       return error(instrprof_error::malformed);
117f8d79198SJustin Bogner     Counts.push_back(Count);
118f8d79198SJustin Bogner   }
119f8d79198SJustin Bogner   // Give the record a reference to our internal counter storage.
120f8d79198SJustin Bogner   Record.Counts = Counts;
121f8d79198SJustin Bogner 
122f8d79198SJustin Bogner   return success();
123f8d79198SJustin Bogner }
12424b4b653SDuncan P. N. Exon Smith 
1254680361dSDuncan P. N. Exon Smith template <class IntPtrT>
1264680361dSDuncan P. N. Exon Smith static uint64_t getRawMagic();
1274680361dSDuncan P. N. Exon Smith 
1284680361dSDuncan P. N. Exon Smith template <>
1294680361dSDuncan P. N. Exon Smith uint64_t getRawMagic<uint64_t>() {
13009a67f45SDuncan P. N. Exon Smith   return
131745a2bf0SDuncan P. N. Exon Smith     uint64_t(255) << 56 |
132745a2bf0SDuncan P. N. Exon Smith     uint64_t('l') << 48 |
133745a2bf0SDuncan P. N. Exon Smith     uint64_t('p') << 40 |
134745a2bf0SDuncan P. N. Exon Smith     uint64_t('r') << 32 |
135745a2bf0SDuncan P. N. Exon Smith     uint64_t('o') << 24 |
136745a2bf0SDuncan P. N. Exon Smith     uint64_t('f') << 16 |
137745a2bf0SDuncan P. N. Exon Smith     uint64_t('r') <<  8 |
138745a2bf0SDuncan P. N. Exon Smith     uint64_t(129);
13909a67f45SDuncan P. N. Exon Smith }
14009a67f45SDuncan P. N. Exon Smith 
1414680361dSDuncan P. N. Exon Smith template <>
1424680361dSDuncan P. N. Exon Smith uint64_t getRawMagic<uint32_t>() {
1434680361dSDuncan P. N. Exon Smith   return
1444680361dSDuncan P. N. Exon Smith     uint64_t(255) << 56 |
1454680361dSDuncan P. N. Exon Smith     uint64_t('l') << 48 |
1464680361dSDuncan P. N. Exon Smith     uint64_t('p') << 40 |
1474680361dSDuncan P. N. Exon Smith     uint64_t('r') << 32 |
1484680361dSDuncan P. N. Exon Smith     uint64_t('o') << 24 |
1494680361dSDuncan P. N. Exon Smith     uint64_t('f') << 16 |
1504680361dSDuncan P. N. Exon Smith     uint64_t('R') <<  8 |
1514680361dSDuncan P. N. Exon Smith     uint64_t(129);
15209a67f45SDuncan P. N. Exon Smith }
15309a67f45SDuncan P. N. Exon Smith 
1544680361dSDuncan P. N. Exon Smith template <class IntPtrT>
1554680361dSDuncan P. N. Exon Smith bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) {
156d7d83477SDuncan P. N. Exon Smith   if (DataBuffer.getBufferSize() < sizeof(uint64_t))
1574680361dSDuncan P. N. Exon Smith     return false;
158d7d83477SDuncan P. N. Exon Smith   uint64_t Magic =
159d7d83477SDuncan P. N. Exon Smith     *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart());
160d7d83477SDuncan P. N. Exon Smith   return getRawMagic<IntPtrT>() == Magic ||
161*ef5e867fSArtyom Skrobov     sys::getSwappedBytes(getRawMagic<IntPtrT>()) == Magic;
1624680361dSDuncan P. N. Exon Smith }
1634680361dSDuncan P. N. Exon Smith 
1644680361dSDuncan P. N. Exon Smith template <class IntPtrT>
165db4ed0bdSRafael Espindola std::error_code RawInstrProfReader<IntPtrT>::readHeader() {
16609a67f45SDuncan P. N. Exon Smith   if (!hasFormat(*DataBuffer))
16709a67f45SDuncan P. N. Exon Smith     return error(instrprof_error::bad_magic);
16824b4b653SDuncan P. N. Exon Smith   if (DataBuffer->getBufferSize() < sizeof(RawHeader))
169531bb481SDuncan P. N. Exon Smith     return error(instrprof_error::bad_header);
170d7d83477SDuncan P. N. Exon Smith   auto *Header =
171d7d83477SDuncan P. N. Exon Smith     reinterpret_cast<const RawHeader *>(DataBuffer->getBufferStart());
1724680361dSDuncan P. N. Exon Smith   ShouldSwapBytes = Header->Magic != getRawMagic<IntPtrT>();
17324b4b653SDuncan P. N. Exon Smith   return readHeader(*Header);
17424b4b653SDuncan P. N. Exon Smith }
17524b4b653SDuncan P. N. Exon Smith 
176a119f323SJustin Bogner template <class IntPtrT>
177db4ed0bdSRafael Espindola std::error_code
178db4ed0bdSRafael Espindola RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
179a119f323SJustin Bogner   const char *End = DataBuffer->getBufferEnd();
180a119f323SJustin Bogner   // Skip zero padding between profiles.
181a119f323SJustin Bogner   while (CurrentPos != End && *CurrentPos == 0)
182a119f323SJustin Bogner     ++CurrentPos;
183a119f323SJustin Bogner   // If there's nothing left, we're done.
184a119f323SJustin Bogner   if (CurrentPos == End)
185a119f323SJustin Bogner     return instrprof_error::eof;
186a119f323SJustin Bogner   // If there isn't enough space for another header, this is probably just
187a119f323SJustin Bogner   // garbage at the end of the file.
188a119f323SJustin Bogner   if (CurrentPos + sizeof(RawHeader) > End)
189a119f323SJustin Bogner     return instrprof_error::malformed;
190a119f323SJustin Bogner   // The magic should have the same byte order as in the previous header.
191a119f323SJustin Bogner   uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos);
192a119f323SJustin Bogner   if (Magic != swap(getRawMagic<IntPtrT>()))
193a119f323SJustin Bogner     return instrprof_error::bad_magic;
194a119f323SJustin Bogner 
195a119f323SJustin Bogner   // There's another profile to read, so we need to process the header.
196a119f323SJustin Bogner   auto *Header = reinterpret_cast<const RawHeader *>(CurrentPos);
197a119f323SJustin Bogner   return readHeader(*Header);
198a119f323SJustin Bogner }
199a119f323SJustin Bogner 
20009a67f45SDuncan P. N. Exon Smith static uint64_t getRawVersion() {
20109a67f45SDuncan P. N. Exon Smith   return 1;
20209a67f45SDuncan P. N. Exon Smith }
20309a67f45SDuncan P. N. Exon Smith 
2044680361dSDuncan P. N. Exon Smith template <class IntPtrT>
205db4ed0bdSRafael Espindola std::error_code
206db4ed0bdSRafael Espindola RawInstrProfReader<IntPtrT>::readHeader(const RawHeader &Header) {
20724b4b653SDuncan P. N. Exon Smith   if (swap(Header.Version) != getRawVersion())
20824b4b653SDuncan P. N. Exon Smith     return error(instrprof_error::unsupported_version);
20924b4b653SDuncan P. N. Exon Smith 
21024b4b653SDuncan P. N. Exon Smith   CountersDelta = swap(Header.CountersDelta);
21124b4b653SDuncan P. N. Exon Smith   NamesDelta = swap(Header.NamesDelta);
21224b4b653SDuncan P. N. Exon Smith   auto DataSize = swap(Header.DataSize);
21324b4b653SDuncan P. N. Exon Smith   auto CountersSize = swap(Header.CountersSize);
21424b4b653SDuncan P. N. Exon Smith   auto NamesSize = swap(Header.NamesSize);
21524b4b653SDuncan P. N. Exon Smith 
21624b4b653SDuncan P. N. Exon Smith   ptrdiff_t DataOffset = sizeof(RawHeader);
21724b4b653SDuncan P. N. Exon Smith   ptrdiff_t CountersOffset = DataOffset + sizeof(ProfileData) * DataSize;
21824b4b653SDuncan P. N. Exon Smith   ptrdiff_t NamesOffset = CountersOffset + sizeof(uint64_t) * CountersSize;
219a119f323SJustin Bogner   size_t ProfileSize = NamesOffset + sizeof(char) * NamesSize;
22024b4b653SDuncan P. N. Exon Smith 
221a119f323SJustin Bogner   auto *Start = reinterpret_cast<const char *>(&Header);
222a119f323SJustin Bogner   if (Start + ProfileSize > DataBuffer->getBufferEnd())
223531bb481SDuncan P. N. Exon Smith     return error(instrprof_error::bad_header);
22424b4b653SDuncan P. N. Exon Smith 
225d7d83477SDuncan P. N. Exon Smith   Data = reinterpret_cast<const ProfileData *>(Start + DataOffset);
22624b4b653SDuncan P. N. Exon Smith   DataEnd = Data + DataSize;
227d7d83477SDuncan P. N. Exon Smith   CountersStart = reinterpret_cast<const uint64_t *>(Start + CountersOffset);
228d7d83477SDuncan P. N. Exon Smith   NamesStart = Start + NamesOffset;
229a119f323SJustin Bogner   ProfileEnd = Start + ProfileSize;
23024b4b653SDuncan P. N. Exon Smith 
23124b4b653SDuncan P. N. Exon Smith   return success();
23224b4b653SDuncan P. N. Exon Smith }
23324b4b653SDuncan P. N. Exon Smith 
2344680361dSDuncan P. N. Exon Smith template <class IntPtrT>
235db4ed0bdSRafael Espindola std::error_code
2364680361dSDuncan P. N. Exon Smith RawInstrProfReader<IntPtrT>::readNextRecord(InstrProfRecord &Record) {
23724b4b653SDuncan P. N. Exon Smith   if (Data == DataEnd)
238db4ed0bdSRafael Espindola     if (std::error_code EC = readNextHeader(ProfileEnd))
239a119f323SJustin Bogner       return EC;
24024b4b653SDuncan P. N. Exon Smith 
24124b4b653SDuncan P. N. Exon Smith   // Get the raw data.
24224b4b653SDuncan P. N. Exon Smith   StringRef RawName(getName(Data->NamePtr), swap(Data->NameSize));
243b59d7c73SJustin Bogner   uint32_t NumCounters = swap(Data->NumCounters);
244b59d7c73SJustin Bogner   if (NumCounters == 0)
245b59d7c73SJustin Bogner     return error(instrprof_error::malformed);
246b59d7c73SJustin Bogner   auto RawCounts = makeArrayRef(getCounter(Data->CounterPtr), NumCounters);
24724b4b653SDuncan P. N. Exon Smith 
24824b4b653SDuncan P. N. Exon Smith   // Check bounds.
249d7d83477SDuncan P. N. Exon Smith   auto *NamesStartAsCounter = reinterpret_cast<const uint64_t *>(NamesStart);
25024b4b653SDuncan P. N. Exon Smith   if (RawName.data() < NamesStart ||
25124b4b653SDuncan P. N. Exon Smith       RawName.data() + RawName.size() > DataBuffer->getBufferEnd() ||
25224b4b653SDuncan P. N. Exon Smith       RawCounts.data() < CountersStart ||
253d7d83477SDuncan P. N. Exon Smith       RawCounts.data() + RawCounts.size() > NamesStartAsCounter)
25424b4b653SDuncan P. N. Exon Smith     return error(instrprof_error::malformed);
25524b4b653SDuncan P. N. Exon Smith 
25624b4b653SDuncan P. N. Exon Smith   // Store the data in Record, byte-swapping as necessary.
25724b4b653SDuncan P. N. Exon Smith   Record.Hash = swap(Data->FuncHash);
25824b4b653SDuncan P. N. Exon Smith   Record.Name = RawName;
25924b4b653SDuncan P. N. Exon Smith   if (ShouldSwapBytes) {
26024b4b653SDuncan P. N. Exon Smith     Counts.clear();
26124b4b653SDuncan P. N. Exon Smith     Counts.reserve(RawCounts.size());
26224b4b653SDuncan P. N. Exon Smith     for (uint64_t Count : RawCounts)
26324b4b653SDuncan P. N. Exon Smith       Counts.push_back(swap(Count));
26424b4b653SDuncan P. N. Exon Smith     Record.Counts = Counts;
26524b4b653SDuncan P. N. Exon Smith   } else
26624b4b653SDuncan P. N. Exon Smith     Record.Counts = RawCounts;
26724b4b653SDuncan P. N. Exon Smith 
26824b4b653SDuncan P. N. Exon Smith   // Iterate.
26924b4b653SDuncan P. N. Exon Smith   ++Data;
27024b4b653SDuncan P. N. Exon Smith   return success();
27124b4b653SDuncan P. N. Exon Smith }
2724680361dSDuncan P. N. Exon Smith 
2734680361dSDuncan P. N. Exon Smith namespace llvm {
2744680361dSDuncan P. N. Exon Smith template class RawInstrProfReader<uint32_t>;
2754680361dSDuncan P. N. Exon Smith template class RawInstrProfReader<uint64_t>;
2764680361dSDuncan P. N. Exon Smith }
277b7aa2630SJustin Bogner 
278b5d368e8SJustin Bogner InstrProfLookupTrait::hash_value_type
279b5d368e8SJustin Bogner InstrProfLookupTrait::ComputeHash(StringRef K) {
280b5d368e8SJustin Bogner   return IndexedInstrProf::ComputeHash(HashType, K);
281b5d368e8SJustin Bogner }
282b5d368e8SJustin Bogner 
283b7aa2630SJustin Bogner bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) {
284b7aa2630SJustin Bogner   if (DataBuffer.getBufferSize() < 8)
285b7aa2630SJustin Bogner     return false;
286b7aa2630SJustin Bogner   using namespace support;
287b7aa2630SJustin Bogner   uint64_t Magic =
288b7aa2630SJustin Bogner       endian::read<uint64_t, little, aligned>(DataBuffer.getBufferStart());
289b7aa2630SJustin Bogner   return Magic == IndexedInstrProf::Magic;
290b7aa2630SJustin Bogner }
291b7aa2630SJustin Bogner 
292db4ed0bdSRafael Espindola std::error_code IndexedInstrProfReader::readHeader() {
293a7c9ed57SAaron Ballman   const unsigned char *Start =
294a7c9ed57SAaron Ballman       (const unsigned char *)DataBuffer->getBufferStart();
295b7aa2630SJustin Bogner   const unsigned char *Cur = Start;
296a7c9ed57SAaron Ballman   if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24)
297b7aa2630SJustin Bogner     return error(instrprof_error::truncated);
298b7aa2630SJustin Bogner 
299b7aa2630SJustin Bogner   using namespace support;
300b7aa2630SJustin Bogner 
301b7aa2630SJustin Bogner   // Check the magic number.
302b7aa2630SJustin Bogner   uint64_t Magic = endian::readNext<uint64_t, little, unaligned>(Cur);
303b7aa2630SJustin Bogner   if (Magic != IndexedInstrProf::Magic)
304b7aa2630SJustin Bogner     return error(instrprof_error::bad_magic);
305b7aa2630SJustin Bogner 
306b7aa2630SJustin Bogner   // Read the version.
307b7aa2630SJustin Bogner   uint64_t Version = endian::readNext<uint64_t, little, unaligned>(Cur);
308b7aa2630SJustin Bogner   if (Version != IndexedInstrProf::Version)
309b7aa2630SJustin Bogner     return error(instrprof_error::unsupported_version);
310b7aa2630SJustin Bogner 
311b7aa2630SJustin Bogner   // Read the maximal function count.
312b7aa2630SJustin Bogner   MaxFunctionCount = endian::readNext<uint64_t, little, unaligned>(Cur);
313b7aa2630SJustin Bogner 
314b7aa2630SJustin Bogner   // Read the hash type and start offset.
315b7aa2630SJustin Bogner   IndexedInstrProf::HashT HashType = static_cast<IndexedInstrProf::HashT>(
316b7aa2630SJustin Bogner       endian::readNext<uint64_t, little, unaligned>(Cur));
317b7aa2630SJustin Bogner   if (HashType > IndexedInstrProf::HashT::Last)
318b7aa2630SJustin Bogner     return error(instrprof_error::unsupported_hash_type);
319b7aa2630SJustin Bogner   uint64_t HashOffset = endian::readNext<uint64_t, little, unaligned>(Cur);
320b7aa2630SJustin Bogner 
321b7aa2630SJustin Bogner   // The rest of the file is an on disk hash table.
322b7aa2630SJustin Bogner   Index.reset(InstrProfReaderIndex::Create(Start + HashOffset, Cur, Start,
323b7aa2630SJustin Bogner                                            InstrProfLookupTrait(HashType)));
324b7aa2630SJustin Bogner   // Set up our iterator for readNextRecord.
325b7aa2630SJustin Bogner   RecordIterator = Index->data_begin();
326b7aa2630SJustin Bogner 
327b7aa2630SJustin Bogner   return success();
328b7aa2630SJustin Bogner }
329b7aa2630SJustin Bogner 
330db4ed0bdSRafael Espindola std::error_code IndexedInstrProfReader::getFunctionCounts(
331b7aa2630SJustin Bogner     StringRef FuncName, uint64_t &FuncHash, std::vector<uint64_t> &Counts) {
332b7aa2630SJustin Bogner   const auto &Iter = Index->find(FuncName);
333b7aa2630SJustin Bogner   if (Iter == Index->end())
334b7aa2630SJustin Bogner     return error(instrprof_error::unknown_function);
335b7aa2630SJustin Bogner 
336b7aa2630SJustin Bogner   // Found it. Make sure it's valid before giving back a result.
337b7aa2630SJustin Bogner   const InstrProfRecord &Record = *Iter;
338b7aa2630SJustin Bogner   if (Record.Name.empty())
339b7aa2630SJustin Bogner     return error(instrprof_error::malformed);
340b7aa2630SJustin Bogner   FuncHash = Record.Hash;
341b7aa2630SJustin Bogner   Counts = Record.Counts;
342b7aa2630SJustin Bogner   return success();
343b7aa2630SJustin Bogner }
344b7aa2630SJustin Bogner 
345db4ed0bdSRafael Espindola std::error_code
346db4ed0bdSRafael Espindola IndexedInstrProfReader::readNextRecord(InstrProfRecord &Record) {
347b7aa2630SJustin Bogner   // Are we out of records?
348b7aa2630SJustin Bogner   if (RecordIterator == Index->data_end())
349b7aa2630SJustin Bogner     return error(instrprof_error::eof);
350b7aa2630SJustin Bogner 
351b7aa2630SJustin Bogner   // Read the next one.
352b7aa2630SJustin Bogner   Record = *RecordIterator;
353b7aa2630SJustin Bogner   ++RecordIterator;
354b7aa2630SJustin Bogner   if (Record.Name.empty())
355b7aa2630SJustin Bogner     return error(instrprof_error::malformed);
356b7aa2630SJustin Bogner   return success();
357b7aa2630SJustin Bogner }
358