<div dir="ltr"><br><div class="gmail_extra">Thanks!<br></div><div class="gmail_extra"><br><div class="gmail_quote">2014-06-30 10:27 GMT-07:00 Bob Wilson <span dir="ltr"><<a href="mailto:bob.wilson@apple.com" target="_blank">bob.wilson@apple.com</a>></span>:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class=""><br>
> On Jun 25, 2014, at 4:32 PM, Alex L <<a href="mailto:arphaman@gmail.com">arphaman@gmail.com</a>> wrote:<br>
><br>
> Hi everyone,<br>
> 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.<br>
<br>
</div>Review, part 3…. the reader/writer code:<br>
<br>
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.<br>
<br></blockquote><div><br></div><div>Sure, I will write the description of the format in the new document in the llvm docs.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Some general comments on the format:<br>
<br>
* 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.<br></blockquote><div><br></div><div>I think that this is a good idea, I will add version information.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
* 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?<br></blockquote><div><br></div><div>Yes, this should be possible. <br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Other comments inline below….<br>
<br>
> diff --git a/include/llvm/ProfileData/CoverageMappingReader.h b/include/llvm/ProfileData/CoverageMappingReader.h<br>
> new file mode 100644<br>
> index 0000000..d8d2261<br>
> --- /dev/null<br>
> +++ b/include/llvm/ProfileData/CoverageMappingReader.h<br>
> @@ -0,0 +1,178 @@<br>
> +//=-- CoverageMappingReader.h - Code coverage mapping reader ------*- C++ -*-=//<br>
<div class="">> +//<br>
> +// The LLVM Compiler Infrastructure<br>
> +//<br>
> +// This file is distributed under the University of Illinois Open Source<br>
> +// License. See LICENSE.TXT for details.<br>
> +//<br>
> +//===----------------------------------------------------------------------===//<br>
> +//<br>
</div>> +// This file contains support for reading coverage mapping data for<br>
> +// instrumentation based coverage.<br>
> +//<br>
> +//===----------------------------------------------------------------------===//<br>
> +<br>
> +#ifndef LLVM_PROFILEDATA_COVERAGEMAPPING_READER_H_<br>
> +#define LLVM_PROFILEDATA_COVERAGEMAPPING_READER_H_<br>
> +<br>
> +#include "llvm/ProfileData/InstrProf.h"<br>
> +#include "llvm/ProfileData/CoverageMapping.h"<br>
> +#include "llvm/Object/ObjectFile.h"<br>
> +#include "llvm/ADT/ArrayRef.h"<br>
> +#include "llvm/ADT/StringRef.h"<br>
> +#include "llvm/Support/MemoryBuffer.h"<br>
> +#include "llvm/Support/FileSystem.h"<br>
> +<br>
> +#include <iterator><br>
> +<br>
> +namespace llvm {<br>
> +<br>
> +class CoverageMappingReader;<br>
> +<br>
> +/// Coverage mapping information for a single function.<br>
> +struct CoverageMappingRecord {<br>
> + StringRef FunctionName;<br>
> + ArrayRef<StringRef> Filenames;<br>
> + ArrayRef<CounterExpression> Expressions;<br>
> + ArrayRef<CounterMappingRegion> MappingRegions;<br>
> +};<br>
> +<br>
> +/// A file format agnostic iterator over coverage mapping data.<br>
> +class CoverageMappingIterator<br>
> + : public std::iterator<std::input_iterator_tag, CoverageMappingRecord> {<br>
> + CoverageMappingReader *Reader;<br>
> + CoverageMappingRecord Record;<br>
> +<br>
> + void Increment();<br>
> +<br>
> +public:<br>
> + CoverageMappingIterator() : Reader(nullptr) {}<br>
> + CoverageMappingIterator(CoverageMappingReader *Reader) : Reader(Reader) {<br>
> + Increment();<br>
> + }<br>
> +<br>
> + CoverageMappingIterator &operator++() {<br>
> + Increment();<br>
> + return *this;<br>
> + }<br>
> + bool operator==(const CoverageMappingIterator &RHS) {<br>
> + return Reader == RHS.Reader;<br>
> + }<br>
> + bool operator!=(const CoverageMappingIterator &RHS) {<br>
> + return Reader != RHS.Reader;<br>
> + }<br>
> + CoverageMappingRecord &operator*() { return Record; }<br>
> + CoverageMappingRecord *operator->() { return &Record; }<br>
> +};<br>
> +<br>
> +/// Base class and interface for reading coverage mapping data of any known<br>
> +/// format. Provides an iterator over CoverageMappingRecords.<br>
> +class CoverageMappingReader {<br>
> + std::error_code LastError;<br>
> +<br>
> +public:<br>
> + CoverageMappingReader() : LastError(instrprof_error::success) {}<br>
> + virtual ~CoverageMappingReader() {}<br>
> +<br>
> + /// Read the header. Required before reading first record.<br>
> + virtual std::error_code readHeader() = 0;<br>
> + /// Read a single record.<br>
> + virtual std::error_code readNextRecord(CoverageMappingRecord &Record) = 0;<br>
> + /// Iterator over profile data.<br>
> + CoverageMappingIterator begin() { return CoverageMappingIterator(this); }<br>
> + CoverageMappingIterator end() { return CoverageMappingIterator(); }<br>
> +<br>
> +protected:<br>
> + /// Set the current error_code and return same.<br>
> + std::error_code error(std::error_code EC) {<br>
> + LastError = EC;<br>
> + return EC;<br>
> + }<br>
> +<br>
> + /// Clear the current error code and return a successful one.<br>
> + std::error_code success() { return error(instrprof_error::success); }<br>
> +<br>
> +public:<br>
> + /// Return true if the reader has finished reading the profile data.<br>
> + bool isEOF() { return LastError == instrprof_error::eof; }<br>
> + /// Return true if the reader encountered an error reading profiling data.<br>
> + bool hasError() { return LastError && !isEOF(); }<br>
> + /// Get the current error code.<br>
> + std::error_code getError() { return LastError; }<br>
> +};<br>
> +<br>
> +/// Reader for the raw coverage mapping binary format from<br>
> +/// CoverageMappingWriter.<br>
<br>
Did you mean CoverageMappingReader?<br>
<br>
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.<br>
</blockquote><div><br></div><div>Yes, this makes sense. I will do that.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
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.<br>
<br>
> +class RawCoverageMappingReader : public CoverageMappingReader {<br>
> + StringRef FunctionName;<br>
> + StringRef MappingData;<br>
> + std::vector<StringRef> &Filenames;<br>
> + std::vector<CounterExpression> &Expressions;<br>
> + std::vector<CounterMappingRegion> &MappingRegions;<br>
> +<br>
> + RawCoverageMappingReader(const RawCoverageMappingReader &)<br>
> + LLVM_DELETED_FUNCTION;<br>
> + RawCoverageMappingReader &<br>
> + operator=(const RawCoverageMappingReader &) LLVM_DELETED_FUNCTION;<br>
> +<br>
> +public:<br>
> + RawCoverageMappingReader(StringRef FunctionName, StringRef MappingData,<br>
> + std::vector<StringRef> &Filenames,<br>
> + std::vector<CounterExpression> &Expressions,<br>
> + std::vector<CounterMappingRegion> &MappingRegions)<br>
> + : FunctionName(FunctionName), MappingData(MappingData),<br>
> + Filenames(Filenames), Expressions(Expressions),<br>
> + MappingRegions(MappingRegions) {}<br>
> +<br>
> + std::error_code readHeader() override;<br>
> + std::error_code readNextRecord(CoverageMappingRecord &Record) override;<br>
> +<br>
> +private:<br>
> + std::error_code readULEB128(uint64_t &Result);<br>
> + std::error_code readIntMax(uint64_t &Result, uint64_t MaxPlus1);<br>
> + std::error_code readSize(uint64_t &Result);<br>
> + std::error_code readString(StringRef &Result);<br>
> + std::error_code readCounter(Counter &C);<br>
> + std::error_code<br>
> + readMappingRegionsSubArray(std::vector<CounterMappingRegion> &MappingRegions,<br>
> + unsigned &InferredFileID, size_t VFMsize);<br>
> +};<br>
> +<br>
> +/// Reader for the coverage mapping data that is emitted by the<br>
> +/// frontend and stored in an object file.<br>
> +class ObjectFileCoverageMappingReader : public CoverageMappingReader {<br>
> +public:<br>
> + struct ProfileMappingRecord {<br>
> + StringRef FunctionName;<br>
> + StringRef CoverageMapping;<br>
> +<br>
> + ProfileMappingRecord(StringRef FunctionName, StringRef CoverageMapping)<br>
> + : FunctionName(FunctionName), CoverageMapping(CoverageMapping) {}<br>
> + };<br>
> +<br>
> +private:<br>
> + std::unique_ptr<llvm::object::ObjectFile> Object;<br>
> + std::vector<ProfileMappingRecord> MappingRecords;<br>
> + size_t CurrentRecord;<br>
> + std::vector<StringRef> Filenames;<br>
> + std::vector<CounterExpression> Expressions;<br>
> + std::vector<CounterMappingRegion> MappingRegions;<br>
> +<br>
> + ObjectFileCoverageMappingReader(const ObjectFileCoverageMappingReader &)<br>
> + LLVM_DELETED_FUNCTION;<br>
> + ObjectFileCoverageMappingReader &<br>
> + operator=(const ObjectFileCoverageMappingReader &) LLVM_DELETED_FUNCTION;<br>
> +<br>
> +public:<br>
> + ObjectFileCoverageMappingReader(StringRef FileName);<br>
> + ObjectFileCoverageMappingReader(<br>
> + std::unique_ptr<MemoryBuffer> &ObjectBuffer,<br>
> + sys::fs::file_magic Type = sys::fs::file_magic::unknown);<br>
> +<br>
> + std::error_code readHeader() override;<br>
> + std::error_code readNextRecord(CoverageMappingRecord &Record) override;<br>
> +};<br>
<div class="">> +<br>
> +} // end namespace llvm<br>
> +<br>
</div>> +#endif // LLVM_PROFILEDATA_COVERAGEMAPPING_READER_H_<br>
> diff --git a/include/llvm/ProfileData/CoverageMappingWriter.h b/include/llvm/ProfileData/CoverageMappingWriter.h<br>
> new file mode 100644<br>
> index 0000000..a358299<br>
> --- /dev/null<br>
> +++ b/include/llvm/ProfileData/CoverageMappingWriter.h<br>
> @@ -0,0 +1,53 @@<br>
> +//=-- CoverageMappingWriter.h - Code coverage mapping writer ------*- C++ -*-=//<br>
<div class="">> +//<br>
> +// The LLVM Compiler Infrastructure<br>
> +//<br>
> +// This file is distributed under the University of Illinois Open Source<br>
> +// License. See LICENSE.TXT for details.<br>
> +//<br>
> +//===----------------------------------------------------------------------===//<br>
> +//<br>
</div>> +// This file contains support for writing coverage mapping data for<br>
> +// instrumentation based coverage.<br>
> +//<br>
> +//===----------------------------------------------------------------------===//<br>
> +<br>
> +#ifndef LLVM_PROFILEDATA_COVERAGEMAPPING_WRITER_H_<br>
> +#define LLVM_PROFILEDATA_COVERAGEMAPPING_WRITER_H_<br>
> +<br>
> +#include "llvm/ProfileData/CoverageMapping.h"<br>
> +#include "llvm/ADT/ArrayRef.h"<br>
> +#include "llvm/ADT/StringMap.h"<br>
> +#include "llvm/Support/raw_ostream.h"<br>
> +<br>
> +namespace llvm {<br>
> +<br>
> +/// Writer for instrumentation based coverage mapping data.<br>
> +class CoverageMappingWriter {<br>
> + ArrayRef<StringRef> Filenames;<br>
> + ArrayRef<unsigned> VirtualFileMapping;<br>
> + ArrayRef<CounterExpression> Expressions;<br>
> + MutableArrayRef<CounterMappingRegion> MappingRegions;<br>
> +<br>
> +public:<br>
> + CoverageMappingWriter(ArrayRef<StringRef> Filenames,<br>
> + ArrayRef<unsigned> VirtualFileMapping,<br>
> + ArrayRef<CounterExpression> Expressions,<br>
> + MutableArrayRef<CounterMappingRegion> MappingRegions)<br>
> + : Filenames(Filenames), VirtualFileMapping(VirtualFileMapping),<br>
> + Expressions(Expressions), MappingRegions(MappingRegions) {}<br>
> +<br>
> + CoverageMappingWriter(ArrayRef<StringRef> Filenames,<br>
> + ArrayRef<CounterExpression> Expressions,<br>
> + MutableArrayRef<CounterMappingRegion> MappingRegions)<br>
> + : Filenames(Filenames), Expressions(Expressions),<br>
> + MappingRegions(MappingRegions) {}<br>
> +<br>
> + /// Write encoded coverage mapping data to the given<br>
> + /// output stream.<br>
> + void write(raw_ostream &OS);<br>
> +};<br>
<div class="">> +<br>
> +} // end namespace llvm<br>
> +<br>
</div>> +#endif // LLVM_PROFILE_COVERAGEMAPPING_WRITER_H_<br>
> diff --git a/lib/ProfileData/CMakeLists.txt b/lib/ProfileData/CMakeLists.txt<br>
> index aefb16c..aad558f 100644<br>
> --- a/lib/ProfileData/CMakeLists.txt<br>
> +++ b/lib/ProfileData/CMakeLists.txt<br>
> @@ -2,4 +2,8 @@ add_llvm_library(LLVMProfileData<br>
> InstrProf.cpp<br>
> InstrProfReader.cpp<br>
> InstrProfWriter.cpp<br>
> + CoverageMapping.cpp<br>
> + CoverageMappingWriter.cpp<br>
> + CoverageMappingReader.cpp<br>
> + ProfileData.cpp<br>
> )<br>
><br>
<br>
> diff --git a/lib/ProfileData/CoverageMappingReader.cpp b/lib/ProfileData/CoverageMappingReader.cpp<br>
> new file mode 100644<br>
> index 0000000..4c90bf8<br>
> --- /dev/null<br>
> +++ b/lib/ProfileData/CoverageMappingReader.cpp<br>
> @@ -0,0 +1,394 @@<br>
> +//=-- CoverageMappingReader.cpp - Code coverage mapping reader ----*- C++ -*-=//<br>
<div class="">> +//<br>
> +// The LLVM Compiler Infrastructure<br>
> +//<br>
> +// This file is distributed under the University of Illinois Open Source<br>
> +// License. See LICENSE.TXT for details.<br>
> +//<br>
> +//===----------------------------------------------------------------------===//<br>
> +//<br>
</div>> +// This file contains support for reading coverage mapping data for<br>
> +// instrumentation based coverage.<br>
> +//<br>
> +//===----------------------------------------------------------------------===//<br>
> +<br>
> +#include "llvm/ProfileData/CoverageMappingReader.h"<br>
> +#include "llvm/Object/ObjectFile.h"<br>
> +#include "llvm/Support/LEB128.h"<br>
> +<br>
> +using namespace llvm;<br>
> +using namespace llvm::object;<br>
> +<br>
> +void CoverageMappingIterator::Increment() {<br>
> + if (Reader->readNextRecord(Record))<br>
> + *this = CoverageMappingIterator();<br>
> +}<br>
> +<br>
> +std::error_code RawCoverageMappingReader::readULEB128(uint64_t &Result) {<br>
> + if (MappingData.size() < 1)<br>
> + return error(instrprof_error::truncated);<br>
> + unsigned N = 0;<br>
> + Result =<br>
> + decodeULEB128(reinterpret_cast<const uint8_t *>(MappingData.data()), &N);<br>
> + if (N > MappingData.size())<br>
> + return error(instrprof_error::malformed);<br>
> + MappingData = MappingData.substr(N);<br>
> + return success();<br>
> +}<br>
> +<br>
> +std::error_code RawCoverageMappingReader::readIntMax(uint64_t &Result,<br>
> + uint64_t MaxPlus1) {<br>
> + auto Err = readULEB128(Result);<br>
> + if (Err)<br>
> + return Err;<br>
> + if (Result >= MaxPlus1)<br>
> + return error(instrprof_error::malformed);<br>
> + return success();<br>
> +}<br>
> +<br>
> +std::error_code RawCoverageMappingReader::readSize(uint64_t &Result) {<br>
> + auto Err = readULEB128(Result);<br>
> + if (Err)<br>
> + return Err;<br>
> + // Sanity check the number<br>
> + if (Result > MappingData.size())<br>
> + return error(instrprof_error::malformed);<br>
> + return success();<br>
> +}<br>
> +<br>
> +std::error_code RawCoverageMappingReader::readString(StringRef &Result) {<br>
> + uint64_t Length;<br>
> + auto Err = readSize(Length);<br>
> + if (Err)<br>
> + return Err;<br>
> + Result = MappingData.substr(0, Length);<br>
> + MappingData = MappingData.substr(Length);<br>
> + return success();<br>
> +}<br>
> +<br>
> +std::error_code RawCoverageMappingReader::readCounter(Counter &C) {<br>
> + uint64_t IntValue;<br>
> + auto Err = readIntMax(IntValue, std::numeric_limits<unsigned>::max());<br>
> + if (Err)<br>
> + return Err;<br>
> + if (C.Decode(IntValue))<br>
> + return error(instrprof_error::malformed);<br>
> + return success();<br>
> +}<br>
> +<br>
> +std::error_code RawCoverageMappingReader::readHeader() { return success(); }<br>
> +<br>
> +static unsigned const EncodingCounterTagAndExpansionRegionTagBits =<br>
> + Counter::EncodingTagBits + 1;<br>
> +<br>
> +std::error_code RawCoverageMappingReader::readMappingRegionsSubArray(<br>
> + std::vector<CounterMappingRegion> &MappingRegions, unsigned &InferredFileID,<br>
> + size_t VFMsize) {<br>
> + uint64_t IntValue;<br>
> + auto Err = readSize(IntValue);<br>
> + if (Err)<br>
> + return Err;<br>
> + unsigned PrevLineStart = 0;<br>
> + for (size_t I = 0, S = IntValue; I < S; ++I) {<br>
> + Counter C;<br>
> + CounterMappingRegion::RegionKind Kind = CounterMappingRegion::CodeRegion;<br>
> +<br>
> + // Read the combined counter + region kind<br>
> + uint64_t IntValue;<br>
> + auto Err = readIntMax(IntValue, std::numeric_limits<unsigned>::max());<br>
> + if (Err)<br>
> + return Err;<br>
> + unsigned Tag = IntValue & Counter::EncodingTagMask;<br>
> + uint64_t ExpandedFileID = 0;<br>
> + if (Tag != Counter::Zero) {<br>
> + if (C.Decode(IntValue))<br>
> + return error(instrprof_error::malformed);<br>
> + } else {<br>
> + // Is it an expansion region?<br>
> + if ((IntValue >> Counter::EncodingTagBits) & 1) {<br>
> + Kind = CounterMappingRegion::ExpansionRegion;<br>
> + ExpandedFileID =<br>
> + IntValue >> EncodingCounterTagAndExpansionRegionTagBits;<br>
> + } else {<br>
> + switch (IntValue >> EncodingCounterTagAndExpansionRegionTagBits) {<br>
> + case CounterMappingRegion::CodeRegion:<br>
> + break;<br>
> + case CounterMappingRegion::EmptyRegion:<br>
> + Kind = CounterMappingRegion::EmptyRegion;<br>
> + break;<br>
> + case CounterMappingRegion::SkippedRegion:<br>
> + Kind = CounterMappingRegion::SkippedRegion;<br>
> + break;<br>
> + default:<br>
> + return error(instrprof_error::malformed);<br>
> + }<br>
> + }<br>
> + }<br>
> +<br>
> + // Read the source range<br>
> + uint64_t LocationInfo[4];<br>
> + for (unsigned J = 0; J < 4; ++J) {<br>
> + Err = readIntMax(LocationInfo[J], std::numeric_limits<unsigned>::max());<br>
> + if (Err)<br>
> + return Err;<br>
> + }<br>
> + PrevLineStart += LocationInfo[0];<br>
> + // Adjust the column locations for the empty regions that<br>
> + // are supposed to cover whole lines.<br>
> + if (LocationInfo[1] == 0 && LocationInfo[3] == 0) {<br>
> + LocationInfo[1] = 1;<br>
> + LocationInfo[3] = std::numeric_limits<unsigned>::max();<br>
> + }<br>
> + MappingRegions.push_back(CounterMappingRegion(<br>
> + C, InferredFileID, PrevLineStart, LocationInfo[1],<br>
> + PrevLineStart + LocationInfo[2], LocationInfo[3], Kind));<br>
> + MappingRegions.back().ExpandedFileID = ExpandedFileID;<br>
> + }<br>
> + return success();<br>
> +}<br>
> +<br>
> +std::error_code<br>
> +RawCoverageMappingReader::readNextRecord(CoverageMappingRecord &Record) {<br>
> + uint64_t IntValue;<br>
> +<br>
> + // Read the filenames<br>
> + llvm::SmallVector<StringRef, 8> UniqueFilenames;<br>
> + auto Err = readSize(IntValue);<br>
> + if (Err)<br>
> + return Err;<br>
> + for (size_t I = 0, S = IntValue; I < S; ++I) {<br>
> + StringRef Filename;<br>
> + auto Err = readString(Filename);<br>
> + if (Err)<br>
> + return Err;<br>
> + UniqueFilenames.push_back(Filename);<br>
> + }<br>
> +<br>
> + // Read the virtual file mapping<br>
> + llvm::SmallVector<unsigned, 8> VirtualFileMapping;<br>
> + Err = readSize(IntValue);<br>
> + if (Err)<br>
> + return Err;<br>
> + if (IntValue == 0) {<br>
> + // Construct the identity virtual file mapping<br>
> + for (unsigned I = 0, S = UniqueFilenames.size(); I < S; ++I)<br>
> + VirtualFileMapping.push_back(I);<br>
> + } else {<br>
> + for (size_t I = 0, S = IntValue; I < S; ++I) {<br>
> + auto Err = readIntMax(IntValue, UniqueFilenames.size());<br>
> + if (Err)<br>
> + return Err;<br>
> + VirtualFileMapping.push_back(IntValue);<br>
> + }<br>
> + }<br>
> +<br>
> + // Construct the files using unique filenames<br>
> + // and virtual file mapping<br>
> + for (auto I : VirtualFileMapping) {<br>
> + Filenames.push_back(UniqueFilenames[I]);<br>
> + }<br>
> +<br>
> + // Read the expressions<br>
> + Err = readSize(IntValue);<br>
> + if (Err)<br>
> + return Err;<br>
> + Expressions.reserve(IntValue);<br>
> + for (size_t I = 0, S = IntValue; I < S; ++I) {<br>
> + Counter LHS, RHS;<br>
> + Err = readCounter(LHS);<br>
> + if (Err)<br>
> + return Err;<br>
> + Err = readCounter(RHS);<br>
> + if (Err)<br>
> + return Err;<br>
> + Expressions.push_back(<br>
> + CounterExpression(CounterExpression::Unknown, LHS, RHS));<br>
> + }<br>
> +<br>
> + // Read the mapping regions sub-arrays<br>
> + for (unsigned InferredFileID = 0, S = VirtualFileMapping.size();<br>
> + InferredFileID < S; ++InferredFileID) {<br>
> + Err = readMappingRegionsSubArray(MappingRegions, InferredFileID,<br>
> + VirtualFileMapping.size());<br>
> + if (Err)<br>
> + return Err;<br>
> + }<br>
> +<br>
> + // Set the counters for the expansion regions<br>
> + // i.e. Counter of expansion region = counter of the first region<br>
> + // from the expanded file.<br>
> + for (auto &I : MappingRegions) {<br>
> + if (I.Kind == CounterMappingRegion::ExpansionRegion) {<br>
> + for (const auto &J : MappingRegions) {<br>
> + if (J.FileID == I.ExpandedFileID) {<br>
> + I.Count = J.Count;<br>
<div class="">> + break;<br>
> + }<br>
> + }<br>
> + }<br>
> + }<br>
</div>> +<br>
> + Record.FunctionName = FunctionName;<br>
> + Record.Filenames = Filenames;<br>
> + Record.Expressions = Expressions;<br>
> + Record.MappingRegions = MappingRegions;<br>
> + return success();<br>
> +}<br>
> +<br>
> +ObjectFileCoverageMappingReader::ObjectFileCoverageMappingReader(<br>
> + StringRef FileName)<br>
> + : CurrentRecord(0) {<br>
> + auto File = llvm::object::ObjectFile::createObjectFile(FileName);<br>
> + if (!File)<br>
> + error(File.getError());<br>
> + else<br>
> + Object.reset(File.get());<br>
> +}<br>
> +<br>
> +ObjectFileCoverageMappingReader::ObjectFileCoverageMappingReader(<br>
> + std::unique_ptr<MemoryBuffer> &ObjectBuffer, sys::fs::file_magic Type)<br>
> + : CurrentRecord(0) {<br>
> + auto File = llvm::object::ObjectFile::createObjectFile(ObjectBuffer, Type);<br>
> + if (!File)<br>
> + error(File.getError());<br>
> + else<br>
> + Object.reset(File.get());<br>
> +}<br>
> +<br>
> +/// A structure which represents<br>
> +/// the CoverageMappingRecord<br>
> +/// which points to both the<br>
> +/// mapping data and the function's name<br>
> +template <typename IntPtrT> struct CoverageMappingRecord {<br>
> + IntPtrT CoverageMappingPtr;<br>
> + IntPtrT FunctionNamePtr;<br>
> + uint32_t CoverageMappingSize;<br>
> + uint32_t FunctionNameSize;<br>
> +};<br>
> +<br>
> +/// A helper structure to access the data<br>
> +/// from the sections in an object file.<br>
> +struct SectionData {<br>
> + StringRef Data;<br>
> + uint64_t Address;<br>
> +<br>
> + std::error_code load(SectionRef &Section) {<br>
> + auto Err = Section.getContents(Data);<br>
> + if (Err)<br>
> + return Err;<br>
> + return Section.getAddress(Address);<br>
> + }<br>
> +<br>
> + std::error_code get(uint64_t Pointer, size_t Size, StringRef &Result) {<br>
> + if (Pointer < Address)<br>
> + return instrprof_error::malformed;<br>
> + auto Offset = Pointer - Address;<br>
> + if (Offset + Size > Data.size())<br>
> + return instrprof_error::malformed;<br>
> + Result = Data.substr(Pointer - Address, Size);<br>
> + return instrprof_error::success;<br>
> + }<br>
> +};<br>
> +<br>
> +template <typename T><br>
> +std::error_code readCoverageMappingData(<br>
> + SectionRef &ProfileNames, SectionRef &CoverageMapping,<br>
> + SectionRef &CoverageData,<br>
> + std::vector<ObjectFileCoverageMappingReader::ProfileMappingRecord> &<br>
> + Records) {<br>
> + // Get the contents of the given sections<br>
> + StringRef Data;<br>
> + auto Err = CoverageData.getContents(Data);<br>
> + if (Err)<br>
> + return Err;<br>
> + SectionData CoverageMappingData, ProfileNamesData;<br>
> + Err = CoverageMappingData.load(CoverageMapping);<br>
> + if (Err)<br>
> + return Err;<br>
> + Err = ProfileNamesData.load(ProfileNames);<br>
> + if (Err)<br>
> + return Err;<br>
> +<br>
> + // Read the records in the coverage data section<br>
> + while (!Data.empty()) {<br>
> + if (Data.size() < sizeof(CoverageMappingRecord<T>))<br>
> + return instrprof_error::malformed;<br>
> + auto MappingRecord =<br>
> + reinterpret_cast<const CoverageMappingRecord<T> *>(Data.data());<br>
> + StringRef Mapping;<br>
> + Err = CoverageMappingData.get(MappingRecord->CoverageMappingPtr,<br>
> + MappingRecord->CoverageMappingSize, Mapping);<br>
> + if (Err)<br>
> + return Err;<br>
> + StringRef FunctionName;<br>
> + Err = ProfileNamesData.get(MappingRecord->FunctionNamePtr,<br>
> + MappingRecord->FunctionNameSize, FunctionName);<br>
> + if (Err)<br>
> + return Err;<br>
> + Records.push_back(ObjectFileCoverageMappingReader::ProfileMappingRecord(<br>
> + FunctionName, Mapping));<br>
> + Data = Data.substr(sizeof(CoverageMappingRecord<T>));<br>
> + }<br>
> +<br>
> + return instrprof_error::success;<br>
> +}<br>
> +<br>
> +std::error_code ObjectFileCoverageMappingReader::readHeader() {<br>
> + if (!Object)<br>
> + return getError();<br>
> + auto BytesInAddress = Object->getBytesInAddress();<br>
> + if (BytesInAddress != 4 && BytesInAddress != 8)<br>
> + return error(instrprof_error::malformed);<br>
> +<br>
> + // Look for the sections that we are interested in<br>
> + int FoundSectionCount = 0;<br>
> + SectionRef ProfileNames, CoverageMapping, CoverageData;<br>
> + for (const auto &Section : Object->sections()) {<br>
> + StringRef Name;<br>
> + auto Err = Section.getName(Name);<br>
> + if (Err)<br>
> + return Err;<br>
> + if (Name == "__llvm_prf_names") {<br>
> + ProfileNames = Section;<br>
> + } else if (Name == "__llvm_prf_cvmap") {<br>
> + CoverageMapping = Section;<br>
> + } else if (Name == "__llvm_prf_cvdat") {<br>
> + CoverageData = Section;<br>
> + } else<br>
> + continue;<br>
> + ++FoundSectionCount;<br>
> + }<br>
> + if (FoundSectionCount != 3)<br>
> + return error(instrprof_error::malformed);<br>
> +<br>
> + // Load the data from the found sections<br>
> + std::error_code Err;<br>
> + if (BytesInAddress == 4)<br>
> + Err = readCoverageMappingData<uint32_t>(ProfileNames, CoverageMapping,<br>
> + CoverageData, MappingRecords);<br>
> + else<br>
> + Err = readCoverageMappingData<uint64_t>(ProfileNames, CoverageMapping,<br>
> + CoverageData, MappingRecords);<br>
> + if (Err)<br>
> + return error(Err);<br>
> +<br>
> + return success();<br>
> +}<br>
> +<br>
> +std::error_code<br>
> +ObjectFileCoverageMappingReader::readNextRecord(CoverageMappingRecord &Record) {<br>
> + if (CurrentRecord >= MappingRecords.size())<br>
> + return error(instrprof_error::eof);<br>
> +<br>
> + Filenames.clear();<br>
> + Expressions.clear();<br>
> + MappingRegions.clear();<br>
> + auto Err = RawCoverageMappingReader(<br>
> + MappingRecords[CurrentRecord].FunctionName,<br>
> + MappingRecords[CurrentRecord].CoverageMapping, Filenames,<br>
> + Expressions, MappingRegions).readNextRecord(Record);<br>
> + if (Err)<br>
> + return Err;<br>
> + ++CurrentRecord;<br>
> + return success();<br>
> +}<br>
> diff --git a/lib/ProfileData/CoverageMappingWriter.cpp b/lib/ProfileData/CoverageMappingWriter.cpp<br>
> new file mode 100644<br>
> index 0000000..f24726d<br>
> --- /dev/null<br>
> +++ b/lib/ProfileData/CoverageMappingWriter.cpp<br>
> @@ -0,0 +1,193 @@<br>
> +//=-- CoverageMappingWriter.cpp - Code coverage mapping writer -------------=//<br>
<div class="">> +//<br>
> +// The LLVM Compiler Infrastructure<br>
> +//<br>
> +// This file is distributed under the University of Illinois Open Source<br>
> +// License. See LICENSE.TXT for details.<br>
> +//<br>
> +//===----------------------------------------------------------------------===//<br>
> +//<br>
</div>> +// This file contains support for writing coverage mapping data for<br>
> +// instrumentation based coverage.<br>
> +//<br>
> +//===----------------------------------------------------------------------===//<br>
> +<br>
> +#include "llvm/ProfileData/CoverageMappingWriter.h"<br>
> +#include "llvm/Support/LEB128.h"<br>
<div class="">> +<br>
> +using namespace llvm;<br>
> +<br>
</div>> +/// Determine if the virtual file mapping has a one to one<br>
> +/// consecutive mapping with the filenames<br>
> +static bool<br>
> +isIdentityVirtualFileMapping(ArrayRef<StringRef> Filenames,<br>
> + ArrayRef<unsigned> VirtualFileMapping) {<br>
> + if (VirtualFileMapping.empty())<br>
> + return true;<br>
> + if (Filenames.size() != VirtualFileMapping.size())<br>
> + return false;<br>
> + unsigned I = 0;<br>
> + for (auto J : VirtualFileMapping) {<br>
> + if (J != I)<br>
> + return false;<br>
> + ++I;<br>
> + }<br>
> + return true;<br>
> +}<br>
> +<br>
> +namespace {<br>
> +/// Gather only the expressions that are used by the mapping<br>
> +/// regions in this function.<br>
> +class CounterExpressionsMinimizer {<br>
> + ArrayRef<CounterExpression> Expressions;<br>
> + llvm::SmallVector<CounterExpression, 16> UsedExpressions;<br>
> + std::vector<unsigned> AdjustedExpressionIDs;<br>
> +<br>
> +public:<br>
> + void mark(Counter C) {<br>
> + if (!C.isExpression())<br>
> + return;<br>
> + unsigned ID = C.getExpressionID();<br>
> + AdjustedExpressionIDs[ID] = 1;<br>
> + mark(Expressions[ID].LHS);<br>
> + mark(Expressions[ID].RHS);<br>
> + }<br>
> +<br>
> + void gatherUsed(Counter C) {<br>
> + if (!C.isExpression() || !AdjustedExpressionIDs[C.getExpressionID()])<br>
> + return;<br>
> + AdjustedExpressionIDs[C.getExpressionID()] = UsedExpressions.size();<br>
<div class="">> + const auto &E = Expressions[C.getExpressionID()];<br>
</div>> + UsedExpressions.push_back(E);<br>
> + gatherUsed(E.LHS);<br>
> + gatherUsed(E.RHS);<br>
> + }<br>
> +<br>
> + CounterExpressionsMinimizer(ArrayRef<CounterExpression> Expressions,<br>
> + ArrayRef<CounterMappingRegion> MappingRegions)<br>
> + : Expressions(Expressions) {<br>
> + AdjustedExpressionIDs.resize(Expressions.size(), 0);<br>
> + for (const auto &I : MappingRegions)<br>
> + mark(I.Count);<br>
> + for (const auto &I : MappingRegions)<br>
> + gatherUsed(I.Count);<br>
> + }<br>
> +<br>
> + ArrayRef<CounterExpression> getExpressions() const { return UsedExpressions; }<br>
> +<br>
> + /// Adjust the given counter to<br>
> + /// correctly transition from the old<br>
> + /// expression ids to the new expression ids.<br>
> + Counter adjust(Counter C) const {<br>
> + if (C.isExpression())<br>
> + C = Counter::getExpression(C.getKind(),<br>
> + AdjustedExpressionIDs[C.getExpressionID()]);<br>
> + return C;<br>
> + }<br>
> +};<br>
> +}<br>
> +<br>
> +static void writeCounter(Counter C, raw_ostream &OS) {<br>
> + encodeULEB128(C.Encode(), OS);<br>
> +}<br>
> +<br>
> +static unsigned const EncodingCounterTagAndExpansionRegionTagBits =<br>
> + Counter::EncodingTagBits + 1;<br>
> +<br>
> +/// Return the number of regions that have the given FileID<br>
> +static unsigned countFileIDs(ArrayRef<CounterMappingRegion> Regions,<br>
> + unsigned FileID) {<br>
> + unsigned Result = 0;<br>
> + for (const auto &I : Regions) {<br>
> + if (I.FileID == FileID)<br>
> + ++Result;<br>
> + if (I.FileID > FileID)<br>
> + break;<br>
> + }<br>
> + return Result;<br>
> +}<br>
> +<br>
> +void CoverageMappingWriter::write(raw_ostream &OS) {<br>
> + // Sort the regions in an ascending order by the file id and the starting<br>
> + // location<br>
> + std::sort(MappingRegions.begin(), MappingRegions.end());<br>
> +<br>
> + // Write out the file names<br>
> + encodeULEB128(Filenames.size(), OS);<br>
> + for (const auto &Filename : Filenames) {<br>
> + encodeULEB128(Filename.size(), OS);<br>
> + OS << Filename;<br>
> + }<br>
> +<br>
> + // Write out the virtual file mapping (if necessary)<br>
> + if (!isIdentityVirtualFileMapping(Filenames, VirtualFileMapping)) {<br>
> + encodeULEB128(VirtualFileMapping.size(), OS);<br>
> + for (const auto &FileID : VirtualFileMapping)<br>
> + encodeULEB128(FileID, OS);<br>
> + } else<br>
> + encodeULEB128(0, OS);<br>
> +<br>
> + // Write out the expressions.<br>
> + CounterExpressionsMinimizer Minimizer(Expressions, MappingRegions);<br>
> + encodeULEB128(Minimizer.getExpressions().size(), OS);<br>
> + for (const auto &E : Minimizer.getExpressions()) {<br>
> + writeCounter(Minimizer.adjust(E.LHS), OS);<br>
> + writeCounter(Minimizer.adjust(E.RHS), OS);<br>
> + }<br>
> +<br>
> + // Write out the mapping regions<br>
> + // Split the regions into subarrays where each region in a<br>
> + // subarray has a fileID which is the index of that subarray.<br>
> + unsigned PrevLineStart = 0;<br>
> + unsigned CurrentFileID = MappingRegions.front().FileID;<br>
> + assert(CurrentFileID == 0);<br>
> + encodeULEB128(countFileIDs(MappingRegions, CurrentFileID), OS);<br>
> + for (const auto &I : MappingRegions) {<br>
> + if (I.FileID != CurrentFileID) {<br>
> + // Ensure that all file ids have at least one mapping region<br>
> + assert(I.FileID == (CurrentFileID + 1));<br>
> + // Start a new region sub-array<br>
> + CurrentFileID = I.FileID;<br>
> + encodeULEB128(countFileIDs(MappingRegions, CurrentFileID), OS);<br>
> + PrevLineStart = 0;<br>
> + }<br>
> + Counter Count = Minimizer.adjust(I.Count);<br>
> + switch (I.Kind) {<br>
> + case CounterMappingRegion::CodeRegion:<br>
> + writeCounter(Count, OS);<br>
> + break;<br>
> + case CounterMappingRegion::ExpansionRegion: {<br>
> + assert(Count.isZero());<br>
> + assert(I.ExpandedFileID <= (std::numeric_limits<unsigned>::max() >><br>
> + EncodingCounterTagAndExpansionRegionTagBits));<br>
> + // Mark an expansion region with a set bit that follows the counter tag,<br>
> + // and pack the expanded file id into the remaining bits.<br>
> + unsigned EncodedTagExpandedFileID =<br>
> + (1 << Counter::EncodingTagBits) |<br>
> + (I.ExpandedFileID << EncodingCounterTagAndExpansionRegionTagBits);<br>
> + encodeULEB128(EncodedTagExpandedFileID, OS);<br>
> + break;<br>
> + }<br>
> + case CounterMappingRegion::EmptyRegion:<br>
> + assert(Count.isZero());<br>
> + encodeULEB128(<br>
> + unsigned(I.Kind) << EncodingCounterTagAndExpansionRegionTagBits, OS);<br>
> + break;<br>
> + case CounterMappingRegion::SkippedRegion:<br>
> + assert(Count.isZero());<br>
> + assert(Count.Encode() == Counter::Zero);<br>
> + encodeULEB128(<br>
> + unsigned(I.Kind) << EncodingCounterTagAndExpansionRegionTagBits, OS);<br>
> + break;<br>
> + }<br>
> + assert(I.LineStart >= PrevLineStart);<br>
> + encodeULEB128(I.LineStart - PrevLineStart, OS);<br>
> + encodeULEB128(I.ColumnStart, OS);<br>
> + assert(I.LineEnd >= I.LineStart);<br>
> + encodeULEB128(I.LineEnd - I.LineStart, OS);<br>
> + encodeULEB128(I.ColumnEnd, OS);<br>
> + PrevLineStart = I.LineStart;<br>
> + }<br>
> + // Ensure that all file ids have at least one mapping region<br>
> + assert(CurrentFileID == (VirtualFileMapping.size() - 1));<br>
> +}<br>
> diff --git a/lib/ProfileData/LLVMBuild.txt b/lib/ProfileData/LLVMBuild.txt<br>
> index 0a8cbe3..2990ee8 100644<br>
> --- a/lib/ProfileData/LLVMBuild.txt<br>
> +++ b/lib/ProfileData/LLVMBuild.txt<br>
> @@ -19,4 +19,4 @@<br>
> type = Library<br>
> name = ProfileData<br>
> parent = Libraries<br>
> -required_libraries = Support<br>
> +required_libraries = Support Object<br>
<br>
</blockquote></div><br></div></div>