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 
24*fcd55607SDiego Novillo static ErrorOr<std::unique_ptr<MemoryBuffer>>
25*fcd55607SDiego Novillo setupMemoryBuffer(std::string Path) {
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;
30*fcd55607SDiego Novillo   auto 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;
35*fcd55607SDiego Novillo   return std::move(Buffer);
36b7aa2630SJustin Bogner }
37b7aa2630SJustin Bogner 
38db4ed0bdSRafael Espindola static std::error_code initializeReader(InstrProfReader &Reader) {
39b7aa2630SJustin Bogner   return Reader.readHeader();
40b7aa2630SJustin Bogner }
41b7aa2630SJustin Bogner 
42*fcd55607SDiego Novillo ErrorOr<std::unique_ptr<InstrProfReader>>
43*fcd55607SDiego Novillo InstrProfReader::create(std::string Path) {
44b7aa2630SJustin Bogner   // Set up the buffer to read.
45*fcd55607SDiego Novillo   auto BufferOrError = setupMemoryBuffer(Path);
46*fcd55607SDiego Novillo   if (std::error_code EC = BufferOrError.getError())
47b7aa2630SJustin Bogner     return EC;
48f8d79198SJustin Bogner 
49*fcd55607SDiego Novillo   auto Buffer = std::move(BufferOrError.get());
50*fcd55607SDiego Novillo   std::unique_ptr<InstrProfReader> Result;
51*fcd55607SDiego Novillo 
5209a67f45SDuncan P. N. Exon Smith   // Create the reader.
53b7aa2630SJustin Bogner   if (IndexedInstrProfReader::hasFormat(*Buffer))
54b7aa2630SJustin Bogner     Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
55b7aa2630SJustin Bogner   else if (RawInstrProfReader64::hasFormat(*Buffer))
564680361dSDuncan P. N. Exon Smith     Result.reset(new RawInstrProfReader64(std::move(Buffer)));
574680361dSDuncan P. N. Exon Smith   else if (RawInstrProfReader32::hasFormat(*Buffer))
584680361dSDuncan P. N. Exon Smith     Result.reset(new RawInstrProfReader32(std::move(Buffer)));
5924b4b653SDuncan P. N. Exon Smith   else
604c5b7cb1SDuncan P. N. Exon Smith     Result.reset(new TextInstrProfReader(std::move(Buffer)));
6109a67f45SDuncan P. N. Exon Smith 
62b7aa2630SJustin Bogner   // Initialize the reader and return the result.
63*fcd55607SDiego Novillo   if (std::error_code EC = initializeReader(*Result))
64*fcd55607SDiego Novillo     return EC;
65*fcd55607SDiego Novillo 
66*fcd55607SDiego Novillo   return std::move(Result);
67b7aa2630SJustin Bogner }
68b7aa2630SJustin Bogner 
69db4ed0bdSRafael Espindola std::error_code IndexedInstrProfReader::create(
70b7aa2630SJustin Bogner     std::string Path, std::unique_ptr<IndexedInstrProfReader> &Result) {
71b7aa2630SJustin Bogner   // Set up the buffer to read.
72*fcd55607SDiego Novillo   auto BufferOrError = setupMemoryBuffer(Path);
73*fcd55607SDiego Novillo   if (std::error_code EC = BufferOrError.getError())
74b7aa2630SJustin Bogner     return EC;
75b7aa2630SJustin Bogner 
76*fcd55607SDiego Novillo   auto Buffer = std::move(BufferOrError.get());
77b7aa2630SJustin Bogner   // Create the reader.
78b7aa2630SJustin Bogner   if (!IndexedInstrProfReader::hasFormat(*Buffer))
79b7aa2630SJustin Bogner     return instrprof_error::bad_magic;
80b7aa2630SJustin Bogner   Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
81b7aa2630SJustin Bogner 
82b7aa2630SJustin Bogner   // Initialize the reader and return the result.
83b7aa2630SJustin Bogner   return initializeReader(*Result);
84f8d79198SJustin Bogner }
85f8d79198SJustin Bogner 
86f8d79198SJustin Bogner void InstrProfIterator::Increment() {
87f8d79198SJustin Bogner   if (Reader->readNextRecord(Record))
88f8d79198SJustin Bogner     *this = InstrProfIterator();
89f8d79198SJustin Bogner }
90f8d79198SJustin Bogner 
91db4ed0bdSRafael Espindola std::error_code TextInstrProfReader::readNextRecord(InstrProfRecord &Record) {
92cf36a366SJustin Bogner   // Skip empty lines and comments.
93cf36a366SJustin Bogner   while (!Line.is_at_end() && (Line->empty() || Line->startswith("#")))
94f8d79198SJustin Bogner     ++Line;
95f8d79198SJustin Bogner   // If we hit EOF while looking for a name, we're done.
96f8d79198SJustin Bogner   if (Line.is_at_end())
97f8d79198SJustin Bogner     return error(instrprof_error::eof);
98f8d79198SJustin Bogner 
99f8d79198SJustin Bogner   // Read the function name.
100f8d79198SJustin Bogner   Record.Name = *Line++;
101f8d79198SJustin Bogner 
102f8d79198SJustin Bogner   // Read the function hash.
103f8d79198SJustin Bogner   if (Line.is_at_end())
104f8d79198SJustin Bogner     return error(instrprof_error::truncated);
105f8d79198SJustin Bogner   if ((Line++)->getAsInteger(10, Record.Hash))
106f8d79198SJustin Bogner     return error(instrprof_error::malformed);
107f8d79198SJustin Bogner 
108f8d79198SJustin Bogner   // Read the number of counters.
109f8d79198SJustin Bogner   uint64_t NumCounters;
110f8d79198SJustin Bogner   if (Line.is_at_end())
111f8d79198SJustin Bogner     return error(instrprof_error::truncated);
112f8d79198SJustin Bogner   if ((Line++)->getAsInteger(10, NumCounters))
113f8d79198SJustin Bogner     return error(instrprof_error::malformed);
114b59d7c73SJustin Bogner   if (NumCounters == 0)
115b59d7c73SJustin Bogner     return error(instrprof_error::malformed);
116f8d79198SJustin Bogner 
117f8d79198SJustin Bogner   // Read each counter and fill our internal storage with the values.
118f8d79198SJustin Bogner   Counts.clear();
119f8d79198SJustin Bogner   Counts.reserve(NumCounters);
120f8d79198SJustin Bogner   for (uint64_t I = 0; I < NumCounters; ++I) {
121f8d79198SJustin Bogner     if (Line.is_at_end())
122f8d79198SJustin Bogner       return error(instrprof_error::truncated);
123f8d79198SJustin Bogner     uint64_t Count;
124f8d79198SJustin Bogner     if ((Line++)->getAsInteger(10, Count))
125f8d79198SJustin Bogner       return error(instrprof_error::malformed);
126f8d79198SJustin Bogner     Counts.push_back(Count);
127f8d79198SJustin Bogner   }
128f8d79198SJustin Bogner   // Give the record a reference to our internal counter storage.
129f8d79198SJustin Bogner   Record.Counts = Counts;
130f8d79198SJustin Bogner 
131f8d79198SJustin Bogner   return success();
132f8d79198SJustin Bogner }
13324b4b653SDuncan P. N. Exon Smith 
1344680361dSDuncan P. N. Exon Smith template <class IntPtrT>
1354680361dSDuncan P. N. Exon Smith static uint64_t getRawMagic();
1364680361dSDuncan P. N. Exon Smith 
1374680361dSDuncan P. N. Exon Smith template <>
1384680361dSDuncan P. N. Exon Smith uint64_t getRawMagic<uint64_t>() {
13909a67f45SDuncan P. N. Exon Smith   return
140745a2bf0SDuncan P. N. Exon Smith     uint64_t(255) << 56 |
141745a2bf0SDuncan P. N. Exon Smith     uint64_t('l') << 48 |
142745a2bf0SDuncan P. N. Exon Smith     uint64_t('p') << 40 |
143745a2bf0SDuncan P. N. Exon Smith     uint64_t('r') << 32 |
144745a2bf0SDuncan P. N. Exon Smith     uint64_t('o') << 24 |
145745a2bf0SDuncan P. N. Exon Smith     uint64_t('f') << 16 |
146745a2bf0SDuncan P. N. Exon Smith     uint64_t('r') <<  8 |
147745a2bf0SDuncan P. N. Exon Smith     uint64_t(129);
14809a67f45SDuncan P. N. Exon Smith }
14909a67f45SDuncan P. N. Exon Smith 
1504680361dSDuncan P. N. Exon Smith template <>
1514680361dSDuncan P. N. Exon Smith uint64_t getRawMagic<uint32_t>() {
1524680361dSDuncan P. N. Exon Smith   return
1534680361dSDuncan P. N. Exon Smith     uint64_t(255) << 56 |
1544680361dSDuncan P. N. Exon Smith     uint64_t('l') << 48 |
1554680361dSDuncan P. N. Exon Smith     uint64_t('p') << 40 |
1564680361dSDuncan P. N. Exon Smith     uint64_t('r') << 32 |
1574680361dSDuncan P. N. Exon Smith     uint64_t('o') << 24 |
1584680361dSDuncan P. N. Exon Smith     uint64_t('f') << 16 |
1594680361dSDuncan P. N. Exon Smith     uint64_t('R') <<  8 |
1604680361dSDuncan P. N. Exon Smith     uint64_t(129);
16109a67f45SDuncan P. N. Exon Smith }
16209a67f45SDuncan P. N. Exon Smith 
1634680361dSDuncan P. N. Exon Smith template <class IntPtrT>
1644680361dSDuncan P. N. Exon Smith bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) {
165d7d83477SDuncan P. N. Exon Smith   if (DataBuffer.getBufferSize() < sizeof(uint64_t))
1664680361dSDuncan P. N. Exon Smith     return false;
167d7d83477SDuncan P. N. Exon Smith   uint64_t Magic =
168d7d83477SDuncan P. N. Exon Smith     *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart());
169d7d83477SDuncan P. N. Exon Smith   return getRawMagic<IntPtrT>() == Magic ||
170ef5e867fSArtyom Skrobov     sys::getSwappedBytes(getRawMagic<IntPtrT>()) == Magic;
1714680361dSDuncan P. N. Exon Smith }
1724680361dSDuncan P. N. Exon Smith 
1734680361dSDuncan P. N. Exon Smith template <class IntPtrT>
174db4ed0bdSRafael Espindola std::error_code RawInstrProfReader<IntPtrT>::readHeader() {
17509a67f45SDuncan P. N. Exon Smith   if (!hasFormat(*DataBuffer))
17609a67f45SDuncan P. N. Exon Smith     return error(instrprof_error::bad_magic);
17724b4b653SDuncan P. N. Exon Smith   if (DataBuffer->getBufferSize() < sizeof(RawHeader))
178531bb481SDuncan P. N. Exon Smith     return error(instrprof_error::bad_header);
179d7d83477SDuncan P. N. Exon Smith   auto *Header =
180d7d83477SDuncan P. N. Exon Smith     reinterpret_cast<const RawHeader *>(DataBuffer->getBufferStart());
1814680361dSDuncan P. N. Exon Smith   ShouldSwapBytes = Header->Magic != getRawMagic<IntPtrT>();
18224b4b653SDuncan P. N. Exon Smith   return readHeader(*Header);
18324b4b653SDuncan P. N. Exon Smith }
18424b4b653SDuncan P. N. Exon Smith 
185a119f323SJustin Bogner template <class IntPtrT>
186db4ed0bdSRafael Espindola std::error_code
187db4ed0bdSRafael Espindola RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
188a119f323SJustin Bogner   const char *End = DataBuffer->getBufferEnd();
189a119f323SJustin Bogner   // Skip zero padding between profiles.
190a119f323SJustin Bogner   while (CurrentPos != End && *CurrentPos == 0)
191a119f323SJustin Bogner     ++CurrentPos;
192a119f323SJustin Bogner   // If there's nothing left, we're done.
193a119f323SJustin Bogner   if (CurrentPos == End)
194a119f323SJustin Bogner     return instrprof_error::eof;
195a119f323SJustin Bogner   // If there isn't enough space for another header, this is probably just
196a119f323SJustin Bogner   // garbage at the end of the file.
197a119f323SJustin Bogner   if (CurrentPos + sizeof(RawHeader) > End)
198a119f323SJustin Bogner     return instrprof_error::malformed;
19954b11282SJustin Bogner   // The writer ensures each profile is padded to start at an aligned address.
20054b11282SJustin Bogner   if (reinterpret_cast<size_t>(CurrentPos) % alignOf<uint64_t>())
20154b11282SJustin Bogner     return instrprof_error::malformed;
202a119f323SJustin Bogner   // The magic should have the same byte order as in the previous header.
203a119f323SJustin Bogner   uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos);
204a119f323SJustin Bogner   if (Magic != swap(getRawMagic<IntPtrT>()))
205a119f323SJustin Bogner     return instrprof_error::bad_magic;
206a119f323SJustin Bogner 
207a119f323SJustin Bogner   // There's another profile to read, so we need to process the header.
208a119f323SJustin Bogner   auto *Header = reinterpret_cast<const RawHeader *>(CurrentPos);
209a119f323SJustin Bogner   return readHeader(*Header);
210a119f323SJustin Bogner }
211a119f323SJustin Bogner 
21209a67f45SDuncan P. N. Exon Smith static uint64_t getRawVersion() {
21309a67f45SDuncan P. N. Exon Smith   return 1;
21409a67f45SDuncan P. N. Exon Smith }
21509a67f45SDuncan P. N. Exon Smith 
2164680361dSDuncan P. N. Exon Smith template <class IntPtrT>
217db4ed0bdSRafael Espindola std::error_code
218db4ed0bdSRafael Espindola RawInstrProfReader<IntPtrT>::readHeader(const RawHeader &Header) {
21924b4b653SDuncan P. N. Exon Smith   if (swap(Header.Version) != getRawVersion())
22024b4b653SDuncan P. N. Exon Smith     return error(instrprof_error::unsupported_version);
22124b4b653SDuncan P. N. Exon Smith 
22224b4b653SDuncan P. N. Exon Smith   CountersDelta = swap(Header.CountersDelta);
22324b4b653SDuncan P. N. Exon Smith   NamesDelta = swap(Header.NamesDelta);
22424b4b653SDuncan P. N. Exon Smith   auto DataSize = swap(Header.DataSize);
22524b4b653SDuncan P. N. Exon Smith   auto CountersSize = swap(Header.CountersSize);
22624b4b653SDuncan P. N. Exon Smith   auto NamesSize = swap(Header.NamesSize);
22724b4b653SDuncan P. N. Exon Smith 
22824b4b653SDuncan P. N. Exon Smith   ptrdiff_t DataOffset = sizeof(RawHeader);
22924b4b653SDuncan P. N. Exon Smith   ptrdiff_t CountersOffset = DataOffset + sizeof(ProfileData) * DataSize;
23024b4b653SDuncan P. N. Exon Smith   ptrdiff_t NamesOffset = CountersOffset + sizeof(uint64_t) * CountersSize;
231a119f323SJustin Bogner   size_t ProfileSize = NamesOffset + sizeof(char) * NamesSize;
23224b4b653SDuncan P. N. Exon Smith 
233a119f323SJustin Bogner   auto *Start = reinterpret_cast<const char *>(&Header);
234a119f323SJustin Bogner   if (Start + ProfileSize > DataBuffer->getBufferEnd())
235531bb481SDuncan P. N. Exon Smith     return error(instrprof_error::bad_header);
23624b4b653SDuncan P. N. Exon Smith 
237d7d83477SDuncan P. N. Exon Smith   Data = reinterpret_cast<const ProfileData *>(Start + DataOffset);
23824b4b653SDuncan P. N. Exon Smith   DataEnd = Data + DataSize;
239d7d83477SDuncan P. N. Exon Smith   CountersStart = reinterpret_cast<const uint64_t *>(Start + CountersOffset);
240d7d83477SDuncan P. N. Exon Smith   NamesStart = Start + NamesOffset;
241a119f323SJustin Bogner   ProfileEnd = Start + ProfileSize;
24224b4b653SDuncan P. N. Exon Smith 
24324b4b653SDuncan P. N. Exon Smith   return success();
24424b4b653SDuncan P. N. Exon Smith }
24524b4b653SDuncan P. N. Exon Smith 
2464680361dSDuncan P. N. Exon Smith template <class IntPtrT>
247db4ed0bdSRafael Espindola std::error_code
2484680361dSDuncan P. N. Exon Smith RawInstrProfReader<IntPtrT>::readNextRecord(InstrProfRecord &Record) {
24924b4b653SDuncan P. N. Exon Smith   if (Data == DataEnd)
250db4ed0bdSRafael Espindola     if (std::error_code EC = readNextHeader(ProfileEnd))
251a119f323SJustin Bogner       return EC;
25224b4b653SDuncan P. N. Exon Smith 
25324b4b653SDuncan P. N. Exon Smith   // Get the raw data.
25424b4b653SDuncan P. N. Exon Smith   StringRef RawName(getName(Data->NamePtr), swap(Data->NameSize));
255b59d7c73SJustin Bogner   uint32_t NumCounters = swap(Data->NumCounters);
256b59d7c73SJustin Bogner   if (NumCounters == 0)
257b59d7c73SJustin Bogner     return error(instrprof_error::malformed);
258b59d7c73SJustin Bogner   auto RawCounts = makeArrayRef(getCounter(Data->CounterPtr), NumCounters);
25924b4b653SDuncan P. N. Exon Smith 
26024b4b653SDuncan P. N. Exon Smith   // Check bounds.
261d7d83477SDuncan P. N. Exon Smith   auto *NamesStartAsCounter = reinterpret_cast<const uint64_t *>(NamesStart);
26224b4b653SDuncan P. N. Exon Smith   if (RawName.data() < NamesStart ||
26324b4b653SDuncan P. N. Exon Smith       RawName.data() + RawName.size() > DataBuffer->getBufferEnd() ||
26424b4b653SDuncan P. N. Exon Smith       RawCounts.data() < CountersStart ||
265d7d83477SDuncan P. N. Exon Smith       RawCounts.data() + RawCounts.size() > NamesStartAsCounter)
26624b4b653SDuncan P. N. Exon Smith     return error(instrprof_error::malformed);
26724b4b653SDuncan P. N. Exon Smith 
26824b4b653SDuncan P. N. Exon Smith   // Store the data in Record, byte-swapping as necessary.
26924b4b653SDuncan P. N. Exon Smith   Record.Hash = swap(Data->FuncHash);
27024b4b653SDuncan P. N. Exon Smith   Record.Name = RawName;
27124b4b653SDuncan P. N. Exon Smith   if (ShouldSwapBytes) {
27224b4b653SDuncan P. N. Exon Smith     Counts.clear();
27324b4b653SDuncan P. N. Exon Smith     Counts.reserve(RawCounts.size());
27424b4b653SDuncan P. N. Exon Smith     for (uint64_t Count : RawCounts)
27524b4b653SDuncan P. N. Exon Smith       Counts.push_back(swap(Count));
27624b4b653SDuncan P. N. Exon Smith     Record.Counts = Counts;
27724b4b653SDuncan P. N. Exon Smith   } else
27824b4b653SDuncan P. N. Exon Smith     Record.Counts = RawCounts;
27924b4b653SDuncan P. N. Exon Smith 
28024b4b653SDuncan P. N. Exon Smith   // Iterate.
28124b4b653SDuncan P. N. Exon Smith   ++Data;
28224b4b653SDuncan P. N. Exon Smith   return success();
28324b4b653SDuncan P. N. Exon Smith }
2844680361dSDuncan P. N. Exon Smith 
2854680361dSDuncan P. N. Exon Smith namespace llvm {
2864680361dSDuncan P. N. Exon Smith template class RawInstrProfReader<uint32_t>;
2874680361dSDuncan P. N. Exon Smith template class RawInstrProfReader<uint64_t>;
2884680361dSDuncan P. N. Exon Smith }
289b7aa2630SJustin Bogner 
290b5d368e8SJustin Bogner InstrProfLookupTrait::hash_value_type
291b5d368e8SJustin Bogner InstrProfLookupTrait::ComputeHash(StringRef K) {
292b5d368e8SJustin Bogner   return IndexedInstrProf::ComputeHash(HashType, K);
293b5d368e8SJustin Bogner }
294b5d368e8SJustin Bogner 
295b7aa2630SJustin Bogner bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) {
296b7aa2630SJustin Bogner   if (DataBuffer.getBufferSize() < 8)
297b7aa2630SJustin Bogner     return false;
298b7aa2630SJustin Bogner   using namespace support;
299b7aa2630SJustin Bogner   uint64_t Magic =
300b7aa2630SJustin Bogner       endian::read<uint64_t, little, aligned>(DataBuffer.getBufferStart());
301b7aa2630SJustin Bogner   return Magic == IndexedInstrProf::Magic;
302b7aa2630SJustin Bogner }
303b7aa2630SJustin Bogner 
304db4ed0bdSRafael Espindola std::error_code IndexedInstrProfReader::readHeader() {
305a7c9ed57SAaron Ballman   const unsigned char *Start =
306a7c9ed57SAaron Ballman       (const unsigned char *)DataBuffer->getBufferStart();
307b7aa2630SJustin Bogner   const unsigned char *Cur = Start;
308a7c9ed57SAaron Ballman   if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24)
309b7aa2630SJustin Bogner     return error(instrprof_error::truncated);
310b7aa2630SJustin Bogner 
311b7aa2630SJustin Bogner   using namespace support;
312b7aa2630SJustin Bogner 
313b7aa2630SJustin Bogner   // Check the magic number.
314b7aa2630SJustin Bogner   uint64_t Magic = endian::readNext<uint64_t, little, unaligned>(Cur);
315b7aa2630SJustin Bogner   if (Magic != IndexedInstrProf::Magic)
316b7aa2630SJustin Bogner     return error(instrprof_error::bad_magic);
317b7aa2630SJustin Bogner 
318b7aa2630SJustin Bogner   // Read the version.
319821d7471SJustin Bogner   FormatVersion = endian::readNext<uint64_t, little, unaligned>(Cur);
320821d7471SJustin Bogner   if (FormatVersion > IndexedInstrProf::Version)
321b7aa2630SJustin Bogner     return error(instrprof_error::unsupported_version);
322b7aa2630SJustin Bogner 
323b7aa2630SJustin Bogner   // Read the maximal function count.
324b7aa2630SJustin Bogner   MaxFunctionCount = endian::readNext<uint64_t, little, unaligned>(Cur);
325b7aa2630SJustin Bogner 
326b7aa2630SJustin Bogner   // Read the hash type and start offset.
327b7aa2630SJustin Bogner   IndexedInstrProf::HashT HashType = static_cast<IndexedInstrProf::HashT>(
328b7aa2630SJustin Bogner       endian::readNext<uint64_t, little, unaligned>(Cur));
329b7aa2630SJustin Bogner   if (HashType > IndexedInstrProf::HashT::Last)
330b7aa2630SJustin Bogner     return error(instrprof_error::unsupported_hash_type);
331b7aa2630SJustin Bogner   uint64_t HashOffset = endian::readNext<uint64_t, little, unaligned>(Cur);
332b7aa2630SJustin Bogner 
333b7aa2630SJustin Bogner   // The rest of the file is an on disk hash table.
334b7aa2630SJustin Bogner   Index.reset(InstrProfReaderIndex::Create(Start + HashOffset, Cur, Start,
335b7aa2630SJustin Bogner                                            InstrProfLookupTrait(HashType)));
336b7aa2630SJustin Bogner   // Set up our iterator for readNextRecord.
337b7aa2630SJustin Bogner   RecordIterator = Index->data_begin();
338b7aa2630SJustin Bogner 
339b7aa2630SJustin Bogner   return success();
340b7aa2630SJustin Bogner }
341b7aa2630SJustin Bogner 
342db4ed0bdSRafael Espindola std::error_code IndexedInstrProfReader::getFunctionCounts(
343821d7471SJustin Bogner     StringRef FuncName, uint64_t FuncHash, std::vector<uint64_t> &Counts) {
344821d7471SJustin Bogner   auto Iter = Index->find(FuncName);
345b7aa2630SJustin Bogner   if (Iter == Index->end())
346b7aa2630SJustin Bogner     return error(instrprof_error::unknown_function);
347b7aa2630SJustin Bogner 
348821d7471SJustin Bogner   // Found it. Look for counters with the right hash.
349821d7471SJustin Bogner   ArrayRef<uint64_t> Data = (*Iter).Data;
350821d7471SJustin Bogner   uint64_t NumCounts;
351821d7471SJustin Bogner   for (uint64_t I = 0, E = Data.size(); I != E; I += NumCounts) {
352821d7471SJustin Bogner     // The function hash comes first.
353821d7471SJustin Bogner     uint64_t FoundHash = Data[I++];
354821d7471SJustin Bogner     // In v1, we have at least one count. Later, we have the number of counts.
355821d7471SJustin Bogner     if (I == E)
356b7aa2630SJustin Bogner       return error(instrprof_error::malformed);
357821d7471SJustin Bogner     NumCounts = FormatVersion == 1 ? E - I : Data[I++];
358821d7471SJustin Bogner     // If we have more counts than data, this is bogus.
359821d7471SJustin Bogner     if (I + NumCounts > E)
360821d7471SJustin Bogner       return error(instrprof_error::malformed);
361821d7471SJustin Bogner     // Check for a match and fill the vector if there is one.
362821d7471SJustin Bogner     if (FoundHash == FuncHash) {
363821d7471SJustin Bogner       Counts = Data.slice(I, NumCounts);
364b7aa2630SJustin Bogner       return success();
365b7aa2630SJustin Bogner     }
366821d7471SJustin Bogner   }
367821d7471SJustin Bogner   return error(instrprof_error::hash_mismatch);
368821d7471SJustin Bogner }
369b7aa2630SJustin Bogner 
370db4ed0bdSRafael Espindola std::error_code
371db4ed0bdSRafael Espindola IndexedInstrProfReader::readNextRecord(InstrProfRecord &Record) {
372b7aa2630SJustin Bogner   // Are we out of records?
373b7aa2630SJustin Bogner   if (RecordIterator == Index->data_end())
374b7aa2630SJustin Bogner     return error(instrprof_error::eof);
375b7aa2630SJustin Bogner 
376821d7471SJustin Bogner   // Record the current function name.
377821d7471SJustin Bogner   Record.Name = (*RecordIterator).Name;
378821d7471SJustin Bogner 
379821d7471SJustin Bogner   ArrayRef<uint64_t> Data = (*RecordIterator).Data;
380821d7471SJustin Bogner   // Valid data starts with a hash and either a count or the number of counts.
381821d7471SJustin Bogner   if (CurrentOffset + 1 > Data.size())
382b7aa2630SJustin Bogner     return error(instrprof_error::malformed);
383821d7471SJustin Bogner   // First we have a function hash.
384821d7471SJustin Bogner   Record.Hash = Data[CurrentOffset++];
385821d7471SJustin Bogner   // In version 1 we knew the number of counters implicitly, but in newer
386821d7471SJustin Bogner   // versions we store the number of counters next.
387821d7471SJustin Bogner   uint64_t NumCounts =
388821d7471SJustin Bogner       FormatVersion == 1 ? Data.size() - CurrentOffset : Data[CurrentOffset++];
389821d7471SJustin Bogner   if (CurrentOffset + NumCounts > Data.size())
390821d7471SJustin Bogner     return error(instrprof_error::malformed);
391821d7471SJustin Bogner   // And finally the counts themselves.
392821d7471SJustin Bogner   Record.Counts = Data.slice(CurrentOffset, NumCounts);
393821d7471SJustin Bogner 
394821d7471SJustin Bogner   // If we've exhausted this function's data, increment the record.
395821d7471SJustin Bogner   CurrentOffset += NumCounts;
396821d7471SJustin Bogner   if (CurrentOffset == Data.size()) {
397821d7471SJustin Bogner     ++RecordIterator;
398821d7471SJustin Bogner     CurrentOffset = 0;
399821d7471SJustin Bogner   }
400821d7471SJustin Bogner 
401b7aa2630SJustin Bogner   return success();
402b7aa2630SJustin Bogner }
403