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

Alex L arphaman at gmail.com
Tue Jul 8 10:43:42 PDT 2014


Hi,
I've attached the updated version of this patch.
I've also sent out the patches for the new code coverage tool and clang's
coverage mapping generation in separate threads.
Cheers,
Alex


2014-06-30 10:37 GMT-07:00 Alex L <arphaman at gmail.com>:

>
> 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/20140708/4545585f/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: coverageMapping.patch
Type: application/octet-stream
Size: 57225 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20140708/4545585f/attachment.obj>


More information about the llvm-commits mailing list