ProfileData: Introduce the InstrProfReader interface and a text reader
[oota-llvm.git] / lib / ProfileData / InstrProfReader.cpp
1 //=-- InstrProfReader.cpp - Instrumented profiling reader -------------------=//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file contains support for reading profiling data for clang's
11 // instrumentation based PGO and coverage.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "llvm/ProfileData/InstrProfReader.h"
16 #include "llvm/ProfileData/InstrProf.h"
17 #include "llvm/Support/Endian.h"
18
19 #include <cassert>
20
21 using namespace llvm;
22
23 error_code InstrProfReader::create(std::string Path,
24                                    std::unique_ptr<InstrProfReader> &Result) {
25   std::unique_ptr<MemoryBuffer> Buffer;
26   if (error_code EC = MemoryBuffer::getFileOrSTDIN(Path, Buffer))
27     return EC;
28
29   // Sanity check the file.
30   if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max())
31     return instrprof_error::too_large;
32
33   // FIXME: This needs to determine which format the file is and construct the
34   // correct subclass.
35   Result.reset(new TextInstrProfReader(Buffer));
36
37   return instrprof_error::success;
38 }
39
40 void InstrProfIterator::Increment() {
41   if (Reader->readNextRecord(Record))
42     *this = InstrProfIterator();
43 }
44
45 error_code TextInstrProfReader::readNextRecord(InstrProfRecord &Record) {
46   // Skip empty lines.
47   while (!Line.is_at_end() && Line->empty())
48     ++Line;
49   // If we hit EOF while looking for a name, we're done.
50   if (Line.is_at_end())
51     return error(instrprof_error::eof);
52
53   // Read the function name.
54   Record.Name = *Line++;
55
56   // Read the function hash.
57   if (Line.is_at_end())
58     return error(instrprof_error::truncated);
59   if ((Line++)->getAsInteger(10, Record.Hash))
60     return error(instrprof_error::malformed);
61
62   // Read the number of counters.
63   uint64_t NumCounters;
64   if (Line.is_at_end())
65     return error(instrprof_error::truncated);
66   if ((Line++)->getAsInteger(10, NumCounters))
67     return error(instrprof_error::malformed);
68
69   // Read each counter and fill our internal storage with the values.
70   Counts.clear();
71   Counts.reserve(NumCounters);
72   for (uint64_t I = 0; I < NumCounters; ++I) {
73     if (Line.is_at_end())
74       return error(instrprof_error::truncated);
75     uint64_t Count;
76     if ((Line++)->getAsInteger(10, Count))
77       return error(instrprof_error::malformed);
78     Counts.push_back(Count);
79   }
80   // Give the record a reference to our internal counter storage.
81   Record.Counts = Counts;
82
83   return success();
84 }