[PATCH] Initial code coverage mapping data structures, and reader and writers + C interface for ProfileData library

Alex L arphaman at gmail.com
Mon Jun 30 10:37:53 PDT 2014


Thanks!

2014-06-30 10:27 GMT-07:00 Bob Wilson <bob.wilson at apple.com>:

>
> > On Jun 25, 2014, at 4:32 PM, Alex L <arphaman at gmail.com> wrote:
> >
> > Hi everyone,
> > This is a first patch that implements the data structures, readers and
> writers used by the new code coverage system. I added the new code to the
> ProfileData library. I also added a very minimal C api for the ProfileData
> library.
>
> Review, part 3…. the reader/writer code:
>
> Before going into the details, it would help a lot if you would write up a
> description of the data format. It would make it a lot easier to figure out
> what this code is doing if there was a good description of the format
> somewhere.
>
>
Sure, I will write the description of the format in the new document in the
llvm docs.


> Some general comments on the format:
>
> * I think we’ll need a version number. Hopefully this format won’t need to
> change often, but when it does, we’ll still want the tools to be able to
> read old versions.
>

I think that this is a good idea, I will add version information.


>
> * From what I can tell, you’ve got a separate table of filenames for each
> function. Can you find a way to share those and have one file table per
> translation unit?
>

Yes, this should be possible.


>
> Other comments inline below….
>
> > diff --git a/include/llvm/ProfileData/CoverageMappingReader.h
> b/include/llvm/ProfileData/CoverageMappingReader.h
> > new file mode 100644
> > index 0000000..d8d2261
> > --- /dev/null
> > +++ b/include/llvm/ProfileData/CoverageMappingReader.h
> > @@ -0,0 +1,178 @@
> > +//=-- CoverageMappingReader.h - Code coverage mapping reader ------*-
> C++ -*-=//
> > +//
> > +//                     The LLVM Compiler Infrastructure
> > +//
> > +// This file is distributed under the University of Illinois Open Source
> > +// License. See LICENSE.TXT for details.
> > +//
> >
> +//===----------------------------------------------------------------------===//
> > +//
> > +// This file contains support for reading coverage mapping data for
> > +// instrumentation based coverage.
> > +//
> >
> +//===----------------------------------------------------------------------===//
> > +
> > +#ifndef LLVM_PROFILEDATA_COVERAGEMAPPING_READER_H_
> > +#define LLVM_PROFILEDATA_COVERAGEMAPPING_READER_H_
> > +
> > +#include "llvm/ProfileData/InstrProf.h"
> > +#include "llvm/ProfileData/CoverageMapping.h"
> > +#include "llvm/Object/ObjectFile.h"
> > +#include "llvm/ADT/ArrayRef.h"
> > +#include "llvm/ADT/StringRef.h"
> > +#include "llvm/Support/MemoryBuffer.h"
> > +#include "llvm/Support/FileSystem.h"
> > +
> > +#include <iterator>
> > +
> > +namespace llvm {
> > +
> > +class CoverageMappingReader;
> > +
> > +/// Coverage mapping information for a single function.
> > +struct CoverageMappingRecord {
> > +  StringRef FunctionName;
> > +  ArrayRef<StringRef> Filenames;
> > +  ArrayRef<CounterExpression> Expressions;
> > +  ArrayRef<CounterMappingRegion> MappingRegions;
> > +};
> > +
> > +/// A file format agnostic iterator over coverage mapping data.
> > +class CoverageMappingIterator
> > +    : public std::iterator<std::input_iterator_tag,
> CoverageMappingRecord> {
> > +  CoverageMappingReader *Reader;
> > +  CoverageMappingRecord Record;
> > +
> > +  void Increment();
> > +
> > +public:
> > +  CoverageMappingIterator() : Reader(nullptr) {}
> > +  CoverageMappingIterator(CoverageMappingReader *Reader) :
> Reader(Reader) {
> > +    Increment();
> > +  }
> > +
> > +  CoverageMappingIterator &operator++() {
> > +    Increment();
> > +    return *this;
> > +  }
> > +  bool operator==(const CoverageMappingIterator &RHS) {
> > +    return Reader == RHS.Reader;
> > +  }
> > +  bool operator!=(const CoverageMappingIterator &RHS) {
> > +    return Reader != RHS.Reader;
> > +  }
> > +  CoverageMappingRecord &operator*() { return Record; }
> > +  CoverageMappingRecord *operator->() { return &Record; }
> > +};
> > +
> > +/// Base class and interface for reading coverage mapping data of any
> known
> > +/// format. Provides an iterator over CoverageMappingRecords.
> > +class CoverageMappingReader {
> > +  std::error_code LastError;
> > +
> > +public:
> > +  CoverageMappingReader() : LastError(instrprof_error::success) {}
> > +  virtual ~CoverageMappingReader() {}
> > +
> > +  /// Read the header.  Required before reading first record.
> > +  virtual std::error_code readHeader() = 0;
> > +  /// Read a single record.
> > +  virtual std::error_code readNextRecord(CoverageMappingRecord &Record)
> = 0;
> > +  /// Iterator over profile data.
> > +  CoverageMappingIterator begin() { return
> CoverageMappingIterator(this); }
> > +  CoverageMappingIterator end() { return CoverageMappingIterator(); }
> > +
> > +protected:
> > +  /// Set the current error_code and return same.
> > +  std::error_code error(std::error_code EC) {
> > +    LastError = EC;
> > +    return EC;
> > +  }
> > +
> > +  /// Clear the current error code and return a successful one.
> > +  std::error_code success() { return error(instrprof_error::success); }
> > +
> > +public:
> > +  /// Return true if the reader has finished reading the profile data.
> > +  bool isEOF() { return LastError == instrprof_error::eof; }
> > +  /// Return true if the reader encountered an error reading profiling
> data.
> > +  bool hasError() { return LastError && !isEOF(); }
> > +  /// Get the current error code.
> > +  std::error_code getError() { return LastError; }
> > +};
> > +
> > +/// Reader for the raw coverage mapping binary format from
> > +/// CoverageMappingWriter.
>
> Did you mean CoverageMappingReader?
>
> It really doesn’t seem to me like this ought to be derived from
> CoverageMappingReader, though. The only place that I see
> RawCoverageMappingReader being used is in
> ObjectFileCoverageMappingReader::readNextRecord, where you are creating an
> instance of it and then calling the readNextRecord function. It seems like
> RawCoverageMappingReader is not being used as a kind of
> CoverageMappingReader and should not be derived from it. And, if you fix
> that, there’s no reason to have separate classes for CoverageMappingReader
> and ObjectFileCoverageMappingReader — you can collapse those into one class.
>

Yes, this makes sense. I will do that.


>
> I think I’ll stop there for now. Most of the rest of the reader/writer
> code looks pretty straightforward, and I’ll wait until we settle these
> higher level questions before delving into the details.
>
> > +class RawCoverageMappingReader : public CoverageMappingReader {
> > +  StringRef FunctionName;
> > +  StringRef MappingData;
> > +  std::vector<StringRef> &Filenames;
> > +  std::vector<CounterExpression> &Expressions;
> > +  std::vector<CounterMappingRegion> &MappingRegions;
> > +
> > +  RawCoverageMappingReader(const RawCoverageMappingReader &)
> > +      LLVM_DELETED_FUNCTION;
> > +  RawCoverageMappingReader &
> > +  operator=(const RawCoverageMappingReader &) LLVM_DELETED_FUNCTION;
> > +
> > +public:
> > +  RawCoverageMappingReader(StringRef FunctionName, StringRef
> MappingData,
> > +                           std::vector<StringRef> &Filenames,
> > +                           std::vector<CounterExpression> &Expressions,
> > +                           std::vector<CounterMappingRegion>
> &MappingRegions)
> > +      : FunctionName(FunctionName), MappingData(MappingData),
> > +        Filenames(Filenames), Expressions(Expressions),
> > +        MappingRegions(MappingRegions) {}
> > +
> > +  std::error_code readHeader() override;
> > +  std::error_code readNextRecord(CoverageMappingRecord &Record)
> override;
> > +
> > +private:
> > +  std::error_code readULEB128(uint64_t &Result);
> > +  std::error_code readIntMax(uint64_t &Result, uint64_t MaxPlus1);
> > +  std::error_code readSize(uint64_t &Result);
> > +  std::error_code readString(StringRef &Result);
> > +  std::error_code readCounter(Counter &C);
> > +  std::error_code
> > +  readMappingRegionsSubArray(std::vector<CounterMappingRegion>
> &MappingRegions,
> > +                             unsigned &InferredFileID, size_t VFMsize);
> > +};
> > +
> > +/// Reader for the coverage mapping data that is emitted by the
> > +/// frontend and stored in an object file.
> > +class ObjectFileCoverageMappingReader : public CoverageMappingReader {
> > +public:
> > +  struct ProfileMappingRecord {
> > +    StringRef FunctionName;
> > +    StringRef CoverageMapping;
> > +
> > +    ProfileMappingRecord(StringRef FunctionName, StringRef
> CoverageMapping)
> > +        : FunctionName(FunctionName), CoverageMapping(CoverageMapping)
> {}
> > +  };
> > +
> > +private:
> > +  std::unique_ptr<llvm::object::ObjectFile> Object;
> > +  std::vector<ProfileMappingRecord> MappingRecords;
> > +  size_t CurrentRecord;
> > +  std::vector<StringRef> Filenames;
> > +  std::vector<CounterExpression> Expressions;
> > +  std::vector<CounterMappingRegion> MappingRegions;
> > +
> > +  ObjectFileCoverageMappingReader(const ObjectFileCoverageMappingReader
> &)
> > +      LLVM_DELETED_FUNCTION;
> > +  ObjectFileCoverageMappingReader &
> > +  operator=(const ObjectFileCoverageMappingReader &)
> LLVM_DELETED_FUNCTION;
> > +
> > +public:
> > +  ObjectFileCoverageMappingReader(StringRef FileName);
> > +  ObjectFileCoverageMappingReader(
> > +      std::unique_ptr<MemoryBuffer> &ObjectBuffer,
> > +      sys::fs::file_magic Type = sys::fs::file_magic::unknown);
> > +
> > +  std::error_code readHeader() override;
> > +  std::error_code readNextRecord(CoverageMappingRecord &Record)
> override;
> > +};
> > +
> > +} // end namespace llvm
> > +
> > +#endif // LLVM_PROFILEDATA_COVERAGEMAPPING_READER_H_
> > diff --git a/include/llvm/ProfileData/CoverageMappingWriter.h
> b/include/llvm/ProfileData/CoverageMappingWriter.h
> > new file mode 100644
> > index 0000000..a358299
> > --- /dev/null
> > +++ b/include/llvm/ProfileData/CoverageMappingWriter.h
> > @@ -0,0 +1,53 @@
> > +//=-- CoverageMappingWriter.h - Code coverage mapping writer ------*-
> C++ -*-=//
> > +//
> > +//                     The LLVM Compiler Infrastructure
> > +//
> > +// This file is distributed under the University of Illinois Open Source
> > +// License. See LICENSE.TXT for details.
> > +//
> >
> +//===----------------------------------------------------------------------===//
> > +//
> > +// This file contains support for writing coverage mapping data for
> > +// instrumentation based coverage.
> > +//
> >
> +//===----------------------------------------------------------------------===//
> > +
> > +#ifndef LLVM_PROFILEDATA_COVERAGEMAPPING_WRITER_H_
> > +#define LLVM_PROFILEDATA_COVERAGEMAPPING_WRITER_H_
> > +
> > +#include "llvm/ProfileData/CoverageMapping.h"
> > +#include "llvm/ADT/ArrayRef.h"
> > +#include "llvm/ADT/StringMap.h"
> > +#include "llvm/Support/raw_ostream.h"
> > +
> > +namespace llvm {
> > +
> > +/// Writer for instrumentation based coverage mapping data.
> > +class CoverageMappingWriter {
> > +  ArrayRef<StringRef> Filenames;
> > +  ArrayRef<unsigned> VirtualFileMapping;
> > +  ArrayRef<CounterExpression> Expressions;
> > +  MutableArrayRef<CounterMappingRegion> MappingRegions;
> > +
> > +public:
> > +  CoverageMappingWriter(ArrayRef<StringRef> Filenames,
> > +                        ArrayRef<unsigned> VirtualFileMapping,
> > +                        ArrayRef<CounterExpression> Expressions,
> > +                        MutableArrayRef<CounterMappingRegion>
> MappingRegions)
> > +      : Filenames(Filenames), VirtualFileMapping(VirtualFileMapping),
> > +        Expressions(Expressions), MappingRegions(MappingRegions) {}
> > +
> > +  CoverageMappingWriter(ArrayRef<StringRef> Filenames,
> > +                        ArrayRef<CounterExpression> Expressions,
> > +                        MutableArrayRef<CounterMappingRegion>
> MappingRegions)
> > +      : Filenames(Filenames), Expressions(Expressions),
> > +        MappingRegions(MappingRegions) {}
> > +
> > +  /// Write encoded coverage mapping data to the given
> > +  /// output stream.
> > +  void write(raw_ostream &OS);
> > +};
> > +
> > +} // end namespace llvm
> > +
> > +#endif // LLVM_PROFILE_COVERAGEMAPPING_WRITER_H_
> > diff --git a/lib/ProfileData/CMakeLists.txt
> b/lib/ProfileData/CMakeLists.txt
> > index aefb16c..aad558f 100644
> > --- a/lib/ProfileData/CMakeLists.txt
> > +++ b/lib/ProfileData/CMakeLists.txt
> > @@ -2,4 +2,8 @@ add_llvm_library(LLVMProfileData
> >    InstrProf.cpp
> >    InstrProfReader.cpp
> >    InstrProfWriter.cpp
> > +  CoverageMapping.cpp
> > +  CoverageMappingWriter.cpp
> > +  CoverageMappingReader.cpp
> > +  ProfileData.cpp
> >    )
> >
>
> > diff --git a/lib/ProfileData/CoverageMappingReader.cpp
> b/lib/ProfileData/CoverageMappingReader.cpp
> > new file mode 100644
> > index 0000000..4c90bf8
> > --- /dev/null
> > +++ b/lib/ProfileData/CoverageMappingReader.cpp
> > @@ -0,0 +1,394 @@
> > +//=-- CoverageMappingReader.cpp - Code coverage mapping reader ----*-
> C++ -*-=//
> > +//
> > +//                     The LLVM Compiler Infrastructure
> > +//
> > +// This file is distributed under the University of Illinois Open Source
> > +// License. See LICENSE.TXT for details.
> > +//
> >
> +//===----------------------------------------------------------------------===//
> > +//
> > +// This file contains support for reading coverage mapping data for
> > +// instrumentation based coverage.
> > +//
> >
> +//===----------------------------------------------------------------------===//
> > +
> > +#include "llvm/ProfileData/CoverageMappingReader.h"
> > +#include "llvm/Object/ObjectFile.h"
> > +#include "llvm/Support/LEB128.h"
> > +
> > +using namespace llvm;
> > +using namespace llvm::object;
> > +
> > +void CoverageMappingIterator::Increment() {
> > +  if (Reader->readNextRecord(Record))
> > +    *this = CoverageMappingIterator();
> > +}
> > +
> > +std::error_code RawCoverageMappingReader::readULEB128(uint64_t &Result)
> {
> > +  if (MappingData.size() < 1)
> > +    return error(instrprof_error::truncated);
> > +  unsigned N = 0;
> > +  Result =
> > +      decodeULEB128(reinterpret_cast<const uint8_t
> *>(MappingData.data()), &N);
> > +  if (N > MappingData.size())
> > +    return error(instrprof_error::malformed);
> > +  MappingData = MappingData.substr(N);
> > +  return success();
> > +}
> > +
> > +std::error_code RawCoverageMappingReader::readIntMax(uint64_t &Result,
> > +                                                     uint64_t MaxPlus1)
> {
> > +  auto Err = readULEB128(Result);
> > +  if (Err)
> > +    return Err;
> > +  if (Result >= MaxPlus1)
> > +    return error(instrprof_error::malformed);
> > +  return success();
> > +}
> > +
> > +std::error_code RawCoverageMappingReader::readSize(uint64_t &Result) {
> > +  auto Err = readULEB128(Result);
> > +  if (Err)
> > +    return Err;
> > +  // Sanity check the number
> > +  if (Result > MappingData.size())
> > +    return error(instrprof_error::malformed);
> > +  return success();
> > +}
> > +
> > +std::error_code RawCoverageMappingReader::readString(StringRef &Result)
> {
> > +  uint64_t Length;
> > +  auto Err = readSize(Length);
> > +  if (Err)
> > +    return Err;
> > +  Result = MappingData.substr(0, Length);
> > +  MappingData = MappingData.substr(Length);
> > +  return success();
> > +}
> > +
> > +std::error_code RawCoverageMappingReader::readCounter(Counter &C) {
> > +  uint64_t IntValue;
> > +  auto Err = readIntMax(IntValue, std::numeric_limits<unsigned>::max());
> > +  if (Err)
> > +    return Err;
> > +  if (C.Decode(IntValue))
> > +    return error(instrprof_error::malformed);
> > +  return success();
> > +}
> > +
> > +std::error_code RawCoverageMappingReader::readHeader() { return
> success(); }
> > +
> > +static unsigned const EncodingCounterTagAndExpansionRegionTagBits =
> > +    Counter::EncodingTagBits + 1;
> > +
> > +std::error_code RawCoverageMappingReader::readMappingRegionsSubArray(
> > +    std::vector<CounterMappingRegion> &MappingRegions, unsigned
> &InferredFileID,
> > +    size_t VFMsize) {
> > +  uint64_t IntValue;
> > +  auto Err = readSize(IntValue);
> > +  if (Err)
> > +    return Err;
> > +  unsigned PrevLineStart = 0;
> > +  for (size_t I = 0, S = IntValue; I < S; ++I) {
> > +    Counter C;
> > +    CounterMappingRegion::RegionKind Kind =
> CounterMappingRegion::CodeRegion;
> > +
> > +    // Read the combined counter + region kind
> > +    uint64_t IntValue;
> > +    auto Err = readIntMax(IntValue,
> std::numeric_limits<unsigned>::max());
> > +    if (Err)
> > +      return Err;
> > +    unsigned Tag = IntValue & Counter::EncodingTagMask;
> > +    uint64_t ExpandedFileID = 0;
> > +    if (Tag != Counter::Zero) {
> > +      if (C.Decode(IntValue))
> > +        return error(instrprof_error::malformed);
> > +    } else {
> > +      // Is it an expansion region?
> > +      if ((IntValue >> Counter::EncodingTagBits) & 1) {
> > +        Kind = CounterMappingRegion::ExpansionRegion;
> > +        ExpandedFileID =
> > +            IntValue >> EncodingCounterTagAndExpansionRegionTagBits;
> > +      } else {
> > +        switch (IntValue >>
> EncodingCounterTagAndExpansionRegionTagBits) {
> > +        case CounterMappingRegion::CodeRegion:
> > +          break;
> > +        case CounterMappingRegion::EmptyRegion:
> > +          Kind = CounterMappingRegion::EmptyRegion;
> > +          break;
> > +        case CounterMappingRegion::SkippedRegion:
> > +          Kind = CounterMappingRegion::SkippedRegion;
> > +          break;
> > +        default:
> > +          return error(instrprof_error::malformed);
> > +        }
> > +      }
> > +    }
> > +
> > +    // Read the source range
> > +    uint64_t LocationInfo[4];
> > +    for (unsigned J = 0; J < 4; ++J) {
> > +      Err = readIntMax(LocationInfo[J],
> std::numeric_limits<unsigned>::max());
> > +      if (Err)
> > +        return Err;
> > +    }
> > +    PrevLineStart += LocationInfo[0];
> > +    // Adjust the column locations for the empty regions that
> > +    // are supposed to cover whole lines.
> > +    if (LocationInfo[1] == 0 && LocationInfo[3] == 0) {
> > +      LocationInfo[1] = 1;
> > +      LocationInfo[3] = std::numeric_limits<unsigned>::max();
> > +    }
> > +    MappingRegions.push_back(CounterMappingRegion(
> > +        C, InferredFileID, PrevLineStart, LocationInfo[1],
> > +        PrevLineStart + LocationInfo[2], LocationInfo[3], Kind));
> > +    MappingRegions.back().ExpandedFileID = ExpandedFileID;
> > +  }
> > +  return success();
> > +}
> > +
> > +std::error_code
> > +RawCoverageMappingReader::readNextRecord(CoverageMappingRecord &Record)
> {
> > +  uint64_t IntValue;
> > +
> > +  // Read the filenames
> > +  llvm::SmallVector<StringRef, 8> UniqueFilenames;
> > +  auto Err = readSize(IntValue);
> > +  if (Err)
> > +    return Err;
> > +  for (size_t I = 0, S = IntValue; I < S; ++I) {
> > +    StringRef Filename;
> > +    auto Err = readString(Filename);
> > +    if (Err)
> > +      return Err;
> > +    UniqueFilenames.push_back(Filename);
> > +  }
> > +
> > +  // Read the virtual file mapping
> > +  llvm::SmallVector<unsigned, 8> VirtualFileMapping;
> > +  Err = readSize(IntValue);
> > +  if (Err)
> > +    return Err;
> > +  if (IntValue == 0) {
> > +    // Construct the identity virtual file mapping
> > +    for (unsigned I = 0, S = UniqueFilenames.size(); I < S; ++I)
> > +      VirtualFileMapping.push_back(I);
> > +  } else {
> > +    for (size_t I = 0, S = IntValue; I < S; ++I) {
> > +      auto Err = readIntMax(IntValue, UniqueFilenames.size());
> > +      if (Err)
> > +        return Err;
> > +      VirtualFileMapping.push_back(IntValue);
> > +    }
> > +  }
> > +
> > +  // Construct the files using unique filenames
> > +  // and virtual file mapping
> > +  for (auto I : VirtualFileMapping) {
> > +    Filenames.push_back(UniqueFilenames[I]);
> > +  }
> > +
> > +  // Read the expressions
> > +  Err = readSize(IntValue);
> > +  if (Err)
> > +    return Err;
> > +  Expressions.reserve(IntValue);
> > +  for (size_t I = 0, S = IntValue; I < S; ++I) {
> > +    Counter LHS, RHS;
> > +    Err = readCounter(LHS);
> > +    if (Err)
> > +      return Err;
> > +    Err = readCounter(RHS);
> > +    if (Err)
> > +      return Err;
> > +    Expressions.push_back(
> > +        CounterExpression(CounterExpression::Unknown, LHS, RHS));
> > +  }
> > +
> > +  // Read the mapping regions sub-arrays
> > +  for (unsigned InferredFileID = 0, S = VirtualFileMapping.size();
> > +       InferredFileID < S; ++InferredFileID) {
> > +    Err = readMappingRegionsSubArray(MappingRegions, InferredFileID,
> > +                                     VirtualFileMapping.size());
> > +    if (Err)
> > +      return Err;
> > +  }
> > +
> > +  // Set the counters for the expansion regions
> > +  // i.e. Counter of expansion region = counter of the first region
> > +  // from the expanded file.
> > +  for (auto &I : MappingRegions) {
> > +    if (I.Kind == CounterMappingRegion::ExpansionRegion) {
> > +      for (const auto &J : MappingRegions) {
> > +        if (J.FileID == I.ExpandedFileID) {
> > +          I.Count = J.Count;
> > +          break;
> > +        }
> > +      }
> > +    }
> > +  }
> > +
> > +  Record.FunctionName = FunctionName;
> > +  Record.Filenames = Filenames;
> > +  Record.Expressions = Expressions;
> > +  Record.MappingRegions = MappingRegions;
> > +  return success();
> > +}
> > +
> > +ObjectFileCoverageMappingReader::ObjectFileCoverageMappingReader(
> > +    StringRef FileName)
> > +    : CurrentRecord(0) {
> > +  auto File = llvm::object::ObjectFile::createObjectFile(FileName);
> > +  if (!File)
> > +    error(File.getError());
> > +  else
> > +    Object.reset(File.get());
> > +}
> > +
> > +ObjectFileCoverageMappingReader::ObjectFileCoverageMappingReader(
> > +    std::unique_ptr<MemoryBuffer> &ObjectBuffer, sys::fs::file_magic
> Type)
> > +    : CurrentRecord(0) {
> > +  auto File = llvm::object::ObjectFile::createObjectFile(ObjectBuffer,
> Type);
> > +  if (!File)
> > +    error(File.getError());
> > +  else
> > +    Object.reset(File.get());
> > +}
> > +
> > +/// A structure which represents
> > +/// the CoverageMappingRecord
> > +/// which points to both the
> > +/// mapping data and the function's name
> > +template <typename IntPtrT> struct CoverageMappingRecord {
> > +  IntPtrT CoverageMappingPtr;
> > +  IntPtrT FunctionNamePtr;
> > +  uint32_t CoverageMappingSize;
> > +  uint32_t FunctionNameSize;
> > +};
> > +
> > +/// A helper structure to access the data
> > +/// from the sections in an object file.
> > +struct SectionData {
> > +  StringRef Data;
> > +  uint64_t Address;
> > +
> > +  std::error_code load(SectionRef &Section) {
> > +    auto Err = Section.getContents(Data);
> > +    if (Err)
> > +      return Err;
> > +    return Section.getAddress(Address);
> > +  }
> > +
> > +  std::error_code get(uint64_t Pointer, size_t Size, StringRef &Result)
> {
> > +    if (Pointer < Address)
> > +      return instrprof_error::malformed;
> > +    auto Offset = Pointer - Address;
> > +    if (Offset + Size > Data.size())
> > +      return instrprof_error::malformed;
> > +    Result = Data.substr(Pointer - Address, Size);
> > +    return instrprof_error::success;
> > +  }
> > +};
> > +
> > +template <typename T>
> > +std::error_code readCoverageMappingData(
> > +    SectionRef &ProfileNames, SectionRef &CoverageMapping,
> > +    SectionRef &CoverageData,
> > +    std::vector<ObjectFileCoverageMappingReader::ProfileMappingRecord> &
> > +        Records) {
> > +  // Get the contents of the given sections
> > +  StringRef Data;
> > +  auto Err = CoverageData.getContents(Data);
> > +  if (Err)
> > +    return Err;
> > +  SectionData CoverageMappingData, ProfileNamesData;
> > +  Err = CoverageMappingData.load(CoverageMapping);
> > +  if (Err)
> > +    return Err;
> > +  Err = ProfileNamesData.load(ProfileNames);
> > +  if (Err)
> > +    return Err;
> > +
> > +  // Read the records in the coverage data section
> > +  while (!Data.empty()) {
> > +    if (Data.size() < sizeof(CoverageMappingRecord<T>))
> > +      return instrprof_error::malformed;
> > +    auto MappingRecord =
> > +        reinterpret_cast<const CoverageMappingRecord<T> *>(Data.data());
> > +    StringRef Mapping;
> > +    Err = CoverageMappingData.get(MappingRecord->CoverageMappingPtr,
> > +                                  MappingRecord->CoverageMappingSize,
> Mapping);
> > +    if (Err)
> > +      return Err;
> > +    StringRef FunctionName;
> > +    Err = ProfileNamesData.get(MappingRecord->FunctionNamePtr,
> > +                               MappingRecord->FunctionNameSize,
> FunctionName);
> > +    if (Err)
> > +      return Err;
> > +
>  Records.push_back(ObjectFileCoverageMappingReader::ProfileMappingRecord(
> > +        FunctionName, Mapping));
> > +    Data = Data.substr(sizeof(CoverageMappingRecord<T>));
> > +  }
> > +
> > +  return instrprof_error::success;
> > +}
> > +
> > +std::error_code ObjectFileCoverageMappingReader::readHeader() {
> > +  if (!Object)
> > +    return getError();
> > +  auto BytesInAddress = Object->getBytesInAddress();
> > +  if (BytesInAddress != 4 && BytesInAddress != 8)
> > +    return error(instrprof_error::malformed);
> > +
> > +  // Look for the sections that we are interested in
> > +  int FoundSectionCount = 0;
> > +  SectionRef ProfileNames, CoverageMapping, CoverageData;
> > +  for (const auto &Section : Object->sections()) {
> > +    StringRef Name;
> > +    auto Err = Section.getName(Name);
> > +    if (Err)
> > +      return Err;
> > +    if (Name == "__llvm_prf_names") {
> > +      ProfileNames = Section;
> > +    } else if (Name == "__llvm_prf_cvmap") {
> > +      CoverageMapping = Section;
> > +    } else if (Name == "__llvm_prf_cvdat") {
> > +      CoverageData = Section;
> > +    } else
> > +      continue;
> > +    ++FoundSectionCount;
> > +  }
> > +  if (FoundSectionCount != 3)
> > +    return error(instrprof_error::malformed);
> > +
> > +  // Load the data from the found sections
> > +  std::error_code Err;
> > +  if (BytesInAddress == 4)
> > +    Err = readCoverageMappingData<uint32_t>(ProfileNames,
> CoverageMapping,
> > +                                            CoverageData,
> MappingRecords);
> > +  else
> > +    Err = readCoverageMappingData<uint64_t>(ProfileNames,
> CoverageMapping,
> > +                                            CoverageData,
> MappingRecords);
> > +  if (Err)
> > +    return error(Err);
> > +
> > +  return success();
> > +}
> > +
> > +std::error_code
> > +ObjectFileCoverageMappingReader::readNextRecord(CoverageMappingRecord
> &Record) {
> > +  if (CurrentRecord >= MappingRecords.size())
> > +    return error(instrprof_error::eof);
> > +
> > +  Filenames.clear();
> > +  Expressions.clear();
> > +  MappingRegions.clear();
> > +  auto Err = RawCoverageMappingReader(
> > +                 MappingRecords[CurrentRecord].FunctionName,
> > +                 MappingRecords[CurrentRecord].CoverageMapping,
> Filenames,
> > +                 Expressions, MappingRegions).readNextRecord(Record);
> > +  if (Err)
> > +    return Err;
> > +  ++CurrentRecord;
> > +  return success();
> > +}
> > diff --git a/lib/ProfileData/CoverageMappingWriter.cpp
> b/lib/ProfileData/CoverageMappingWriter.cpp
> > new file mode 100644
> > index 0000000..f24726d
> > --- /dev/null
> > +++ b/lib/ProfileData/CoverageMappingWriter.cpp
> > @@ -0,0 +1,193 @@
> > +//=-- CoverageMappingWriter.cpp - Code coverage mapping writer
> -------------=//
> > +//
> > +//                     The LLVM Compiler Infrastructure
> > +//
> > +// This file is distributed under the University of Illinois Open Source
> > +// License. See LICENSE.TXT for details.
> > +//
> >
> +//===----------------------------------------------------------------------===//
> > +//
> > +// This file contains support for writing coverage mapping data for
> > +// instrumentation based coverage.
> > +//
> >
> +//===----------------------------------------------------------------------===//
> > +
> > +#include "llvm/ProfileData/CoverageMappingWriter.h"
> > +#include "llvm/Support/LEB128.h"
> > +
> > +using namespace llvm;
> > +
> > +/// Determine if the virtual file mapping has a one to one
> > +/// consecutive mapping with the filenames
> > +static bool
> > +isIdentityVirtualFileMapping(ArrayRef<StringRef> Filenames,
> > +                             ArrayRef<unsigned> VirtualFileMapping) {
> > +  if (VirtualFileMapping.empty())
> > +    return true;
> > +  if (Filenames.size() != VirtualFileMapping.size())
> > +    return false;
> > +  unsigned I = 0;
> > +  for (auto J : VirtualFileMapping) {
> > +    if (J != I)
> > +      return false;
> > +    ++I;
> > +  }
> > +  return true;
> > +}
> > +
> > +namespace {
> > +/// Gather only the expressions that are used by the mapping
> > +/// regions in this function.
> > +class CounterExpressionsMinimizer {
> > +  ArrayRef<CounterExpression> Expressions;
> > +  llvm::SmallVector<CounterExpression, 16> UsedExpressions;
> > +  std::vector<unsigned> AdjustedExpressionIDs;
> > +
> > +public:
> > +  void mark(Counter C) {
> > +    if (!C.isExpression())
> > +      return;
> > +    unsigned ID = C.getExpressionID();
> > +    AdjustedExpressionIDs[ID] = 1;
> > +    mark(Expressions[ID].LHS);
> > +    mark(Expressions[ID].RHS);
> > +  }
> > +
> > +  void gatherUsed(Counter C) {
> > +    if (!C.isExpression() ||
> !AdjustedExpressionIDs[C.getExpressionID()])
> > +      return;
> > +    AdjustedExpressionIDs[C.getExpressionID()] = UsedExpressions.size();
> > +    const auto &E = Expressions[C.getExpressionID()];
> > +    UsedExpressions.push_back(E);
> > +    gatherUsed(E.LHS);
> > +    gatherUsed(E.RHS);
> > +  }
> > +
> > +  CounterExpressionsMinimizer(ArrayRef<CounterExpression> Expressions,
> > +                              ArrayRef<CounterMappingRegion>
> MappingRegions)
> > +      : Expressions(Expressions) {
> > +    AdjustedExpressionIDs.resize(Expressions.size(), 0);
> > +    for (const auto &I : MappingRegions)
> > +      mark(I.Count);
> > +    for (const auto &I : MappingRegions)
> > +      gatherUsed(I.Count);
> > +  }
> > +
> > +  ArrayRef<CounterExpression> getExpressions() const { return
> UsedExpressions; }
> > +
> > +  /// Adjust the given counter to
> > +  /// correctly transition from the old
> > +  /// expression ids to the new expression ids.
> > +  Counter adjust(Counter C) const {
> > +    if (C.isExpression())
> > +      C = Counter::getExpression(C.getKind(),
> > +
> AdjustedExpressionIDs[C.getExpressionID()]);
> > +    return C;
> > +  }
> > +};
> > +}
> > +
> > +static void writeCounter(Counter C, raw_ostream &OS) {
> > +  encodeULEB128(C.Encode(), OS);
> > +}
> > +
> > +static unsigned const EncodingCounterTagAndExpansionRegionTagBits =
> > +    Counter::EncodingTagBits + 1;
> > +
> > +/// Return the number of regions that have the given FileID
> > +static unsigned countFileIDs(ArrayRef<CounterMappingRegion> Regions,
> > +                             unsigned FileID) {
> > +  unsigned Result = 0;
> > +  for (const auto &I : Regions) {
> > +    if (I.FileID == FileID)
> > +      ++Result;
> > +    if (I.FileID > FileID)
> > +      break;
> > +  }
> > +  return Result;
> > +}
> > +
> > +void CoverageMappingWriter::write(raw_ostream &OS) {
> > +  // Sort the regions in an ascending order by the file id and the
> starting
> > +  // location
> > +  std::sort(MappingRegions.begin(), MappingRegions.end());
> > +
> > +  // Write out the file names
> > +  encodeULEB128(Filenames.size(), OS);
> > +  for (const auto &Filename : Filenames) {
> > +    encodeULEB128(Filename.size(), OS);
> > +    OS << Filename;
> > +  }
> > +
> > +  // Write out the virtual file mapping (if necessary)
> > +  if (!isIdentityVirtualFileMapping(Filenames, VirtualFileMapping)) {
> > +    encodeULEB128(VirtualFileMapping.size(), OS);
> > +    for (const auto &FileID : VirtualFileMapping)
> > +      encodeULEB128(FileID, OS);
> > +  } else
> > +    encodeULEB128(0, OS);
> > +
> > +  // Write out the expressions.
> > +  CounterExpressionsMinimizer Minimizer(Expressions, MappingRegions);
> > +  encodeULEB128(Minimizer.getExpressions().size(), OS);
> > +  for (const auto &E : Minimizer.getExpressions()) {
> > +    writeCounter(Minimizer.adjust(E.LHS), OS);
> > +    writeCounter(Minimizer.adjust(E.RHS), OS);
> > +  }
> > +
> > +  // Write out the mapping regions
> > +  // Split the regions into subarrays where each region in a
> > +  // subarray has a fileID which is the index of that subarray.
> > +  unsigned PrevLineStart = 0;
> > +  unsigned CurrentFileID = MappingRegions.front().FileID;
> > +  assert(CurrentFileID == 0);
> > +  encodeULEB128(countFileIDs(MappingRegions, CurrentFileID), OS);
> > +  for (const auto &I : MappingRegions) {
> > +    if (I.FileID != CurrentFileID) {
> > +      // Ensure that all file ids have at least one mapping region
> > +      assert(I.FileID == (CurrentFileID + 1));
> > +      // Start a new region sub-array
> > +      CurrentFileID = I.FileID;
> > +      encodeULEB128(countFileIDs(MappingRegions, CurrentFileID), OS);
> > +      PrevLineStart = 0;
> > +    }
> > +    Counter Count = Minimizer.adjust(I.Count);
> > +    switch (I.Kind) {
> > +    case CounterMappingRegion::CodeRegion:
> > +      writeCounter(Count, OS);
> > +      break;
> > +    case CounterMappingRegion::ExpansionRegion: {
> > +      assert(Count.isZero());
> > +      assert(I.ExpandedFileID <= (std::numeric_limits<unsigned>::max()
> >>
> > +
>  EncodingCounterTagAndExpansionRegionTagBits));
> > +      // Mark an expansion region with a set bit that follows the
> counter tag,
> > +      // and pack the expanded file id into the remaining bits.
> > +      unsigned EncodedTagExpandedFileID =
> > +          (1 << Counter::EncodingTagBits) |
> > +          (I.ExpandedFileID <<
> EncodingCounterTagAndExpansionRegionTagBits);
> > +      encodeULEB128(EncodedTagExpandedFileID, OS);
> > +      break;
> > +    }
> > +    case CounterMappingRegion::EmptyRegion:
> > +      assert(Count.isZero());
> > +      encodeULEB128(
> > +          unsigned(I.Kind) <<
> EncodingCounterTagAndExpansionRegionTagBits, OS);
> > +      break;
> > +    case CounterMappingRegion::SkippedRegion:
> > +      assert(Count.isZero());
> > +      assert(Count.Encode() == Counter::Zero);
> > +      encodeULEB128(
> > +          unsigned(I.Kind) <<
> EncodingCounterTagAndExpansionRegionTagBits, OS);
> > +      break;
> > +    }
> > +    assert(I.LineStart >= PrevLineStart);
> > +    encodeULEB128(I.LineStart - PrevLineStart, OS);
> > +    encodeULEB128(I.ColumnStart, OS);
> > +    assert(I.LineEnd >= I.LineStart);
> > +    encodeULEB128(I.LineEnd - I.LineStart, OS);
> > +    encodeULEB128(I.ColumnEnd, OS);
> > +    PrevLineStart = I.LineStart;
> > +  }
> > +  // Ensure that all file ids have at least one mapping region
> > +  assert(CurrentFileID == (VirtualFileMapping.size() - 1));
> > +}
> > diff --git a/lib/ProfileData/LLVMBuild.txt
> b/lib/ProfileData/LLVMBuild.txt
> > index 0a8cbe3..2990ee8 100644
> > --- a/lib/ProfileData/LLVMBuild.txt
> > +++ b/lib/ProfileData/LLVMBuild.txt
> > @@ -19,4 +19,4 @@
> >  type = Library
> >  name = ProfileData
> >  parent = Libraries
> > -required_libraries = Support
> > +required_libraries = Support Object
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20140630/3af509b4/attachment.html>


More information about the llvm-commits mailing list