LLVM API Documentation

CoverageMappingWriter.cpp
Go to the documentation of this file.
00001 //=-- CoverageMappingWriter.cpp - Code coverage mapping writer -------------=//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file contains support for writing coverage mapping data for
00011 // instrumentation based coverage.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #include "llvm/ProfileData/CoverageMappingWriter.h"
00016 #include "llvm/Support/LEB128.h"
00017 
00018 using namespace llvm;
00019 using namespace coverage;
00020 
00021 void CoverageFilenamesSectionWriter::write(raw_ostream &OS) {
00022   encodeULEB128(Filenames.size(), OS);
00023   for (const auto &Filename : Filenames) {
00024     encodeULEB128(Filename.size(), OS);
00025     OS << Filename;
00026   }
00027 }
00028 
00029 namespace {
00030 /// \brief Gather only the expressions that are used by the mapping
00031 /// regions in this function.
00032 class CounterExpressionsMinimizer {
00033   ArrayRef<CounterExpression> Expressions;
00034   llvm::SmallVector<CounterExpression, 16> UsedExpressions;
00035   std::vector<unsigned> AdjustedExpressionIDs;
00036 
00037 public:
00038   void mark(Counter C) {
00039     if (!C.isExpression())
00040       return;
00041     unsigned ID = C.getExpressionID();
00042     AdjustedExpressionIDs[ID] = 1;
00043     mark(Expressions[ID].LHS);
00044     mark(Expressions[ID].RHS);
00045   }
00046 
00047   void gatherUsed(Counter C) {
00048     if (!C.isExpression() || !AdjustedExpressionIDs[C.getExpressionID()])
00049       return;
00050     AdjustedExpressionIDs[C.getExpressionID()] = UsedExpressions.size();
00051     const auto &E = Expressions[C.getExpressionID()];
00052     UsedExpressions.push_back(E);
00053     gatherUsed(E.LHS);
00054     gatherUsed(E.RHS);
00055   }
00056 
00057   CounterExpressionsMinimizer(ArrayRef<CounterExpression> Expressions,
00058                               ArrayRef<CounterMappingRegion> MappingRegions)
00059       : Expressions(Expressions) {
00060     AdjustedExpressionIDs.resize(Expressions.size(), 0);
00061     for (const auto &I : MappingRegions)
00062       mark(I.Count);
00063     for (const auto &I : MappingRegions)
00064       gatherUsed(I.Count);
00065   }
00066 
00067   ArrayRef<CounterExpression> getExpressions() const { return UsedExpressions; }
00068 
00069   /// \brief Adjust the given counter to correctly transition from the old
00070   /// expression ids to the new expression ids.
00071   Counter adjust(Counter C) const {
00072     if (C.isExpression())
00073       C = Counter::getExpression(AdjustedExpressionIDs[C.getExpressionID()]);
00074     return C;
00075   }
00076 };
00077 }
00078 
00079 /// \brief Return the number of regions that have the given FileID.
00080 static unsigned countFileIDs(ArrayRef<CounterMappingRegion> Regions,
00081                              unsigned FileID) {
00082   unsigned Result = 0;
00083   for (const auto &I : Regions) {
00084     if (I.FileID == FileID)
00085       ++Result;
00086     if (I.FileID > FileID)
00087       break;
00088   }
00089   return Result;
00090 }
00091 
00092 /// \brief Encode the counter.
00093 ///
00094 /// The encoding uses the following format:
00095 /// Low 2 bits - Tag:
00096 ///   Counter::Zero(0) - A Counter with kind Counter::Zero
00097 ///   Counter::CounterValueReference(1) - A counter with kind
00098 ///     Counter::CounterValueReference
00099 ///   Counter::Expression(2) + CounterExpression::Subtract(0) -
00100 ///     A counter with kind Counter::Expression and an expression
00101 ///     with kind CounterExpression::Subtract
00102 ///   Counter::Expression(2) + CounterExpression::Add(1) -
00103 ///     A counter with kind Counter::Expression and an expression
00104 ///     with kind CounterExpression::Add
00105 /// Remaining bits - Counter/Expression ID.
00106 static unsigned encodeCounter(ArrayRef<CounterExpression> Expressions,
00107                               Counter C) {
00108   unsigned Tag = unsigned(C.getKind());
00109   if (C.isExpression())
00110     Tag += Expressions[C.getExpressionID()].Kind;
00111   unsigned ID = C.getCounterID();
00112   assert(ID <=
00113          (std::numeric_limits<unsigned>::max() >> Counter::EncodingTagBits));
00114   return Tag | (ID << Counter::EncodingTagBits);
00115 }
00116 
00117 static void writeCounter(ArrayRef<CounterExpression> Expressions, Counter C,
00118                          raw_ostream &OS) {
00119   encodeULEB128(encodeCounter(Expressions, C), OS);
00120 }
00121 
00122 void CoverageMappingWriter::write(raw_ostream &OS) {
00123   // Sort the regions in an ascending order by the file id and the starting
00124   // location.
00125   std::sort(MappingRegions.begin(), MappingRegions.end());
00126 
00127   // Write out the fileid -> filename mapping.
00128   encodeULEB128(VirtualFileMapping.size(), OS);
00129   for (const auto &FileID : VirtualFileMapping)
00130     encodeULEB128(FileID, OS);
00131 
00132   // Write out the expressions.
00133   CounterExpressionsMinimizer Minimizer(Expressions, MappingRegions);
00134   auto MinExpressions = Minimizer.getExpressions();
00135   encodeULEB128(MinExpressions.size(), OS);
00136   for (const auto &E : MinExpressions) {
00137     writeCounter(MinExpressions, Minimizer.adjust(E.LHS), OS);
00138     writeCounter(MinExpressions, Minimizer.adjust(E.RHS), OS);
00139   }
00140 
00141   // Write out the mapping regions.
00142   // Split the regions into subarrays where each region in a
00143   // subarray has a fileID which is the index of that subarray.
00144   unsigned PrevLineStart = 0;
00145   unsigned CurrentFileID = MappingRegions.front().FileID;
00146   assert(CurrentFileID == 0);
00147   encodeULEB128(countFileIDs(MappingRegions, CurrentFileID), OS);
00148   for (const auto &I : MappingRegions) {
00149     if (I.FileID != CurrentFileID) {
00150       // Ensure that all file ids have at least one mapping region.
00151       assert(I.FileID == (CurrentFileID + 1));
00152       // Start a new region sub-array.
00153       CurrentFileID = I.FileID;
00154       encodeULEB128(countFileIDs(MappingRegions, CurrentFileID), OS);
00155       PrevLineStart = 0;
00156     }
00157     Counter Count = Minimizer.adjust(I.Count);
00158     switch (I.Kind) {
00159     case CounterMappingRegion::CodeRegion:
00160       writeCounter(MinExpressions, Count, OS);
00161       break;
00162     case CounterMappingRegion::ExpansionRegion: {
00163       assert(Count.isZero());
00164       assert(I.ExpandedFileID <=
00165              (std::numeric_limits<unsigned>::max() >>
00166               Counter::EncodingCounterTagAndExpansionRegionTagBits));
00167       // Mark an expansion region with a set bit that follows the counter tag,
00168       // and pack the expanded file id into the remaining bits.
00169       unsigned EncodedTagExpandedFileID =
00170           (1 << Counter::EncodingTagBits) |
00171           (I.ExpandedFileID
00172            << Counter::EncodingCounterTagAndExpansionRegionTagBits);
00173       encodeULEB128(EncodedTagExpandedFileID, OS);
00174       break;
00175     }
00176     case CounterMappingRegion::SkippedRegion:
00177       assert(Count.isZero());
00178       encodeULEB128(unsigned(I.Kind)
00179                         << Counter::EncodingCounterTagAndExpansionRegionTagBits,
00180                     OS);
00181       break;
00182     }
00183     assert(I.LineStart >= PrevLineStart);
00184     encodeULEB128(I.LineStart - PrevLineStart, OS);
00185     uint64_t CodeBeforeColumnStart =
00186         uint64_t(I.HasCodeBefore) |
00187         (uint64_t(I.ColumnStart)
00188          << CounterMappingRegion::EncodingHasCodeBeforeBits);
00189     encodeULEB128(CodeBeforeColumnStart, OS);
00190     assert(I.LineEnd >= I.LineStart);
00191     encodeULEB128(I.LineEnd - I.LineStart, OS);
00192     encodeULEB128(I.ColumnEnd, OS);
00193     PrevLineStart = I.LineStart;
00194   }
00195   // Ensure that all file ids have at least one mapping region.
00196   assert(CurrentFileID == (VirtualFileMapping.size() - 1));
00197 }