[PATCH] Initial code coverage mapping data structures, and reader and writers + C interface for ProfileData library
Bob Wilson
bob.wilson at apple.com
Mon Jun 30 10:27:43 PDT 2014
> 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.
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.
* 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?
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.
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
More information about the llvm-commits
mailing list