1*dc707122SEaswaran Raman //=-- CoverageMappingWriter.cpp - Code coverage mapping writer -------------=// 2*dc707122SEaswaran Raman // 3*dc707122SEaswaran Raman // The LLVM Compiler Infrastructure 4*dc707122SEaswaran Raman // 5*dc707122SEaswaran Raman // This file is distributed under the University of Illinois Open Source 6*dc707122SEaswaran Raman // License. See LICENSE.TXT for details. 7*dc707122SEaswaran Raman // 8*dc707122SEaswaran Raman //===----------------------------------------------------------------------===// 9*dc707122SEaswaran Raman // 10*dc707122SEaswaran Raman // This file contains support for writing coverage mapping data for 11*dc707122SEaswaran Raman // instrumentation based coverage. 12*dc707122SEaswaran Raman // 13*dc707122SEaswaran Raman //===----------------------------------------------------------------------===// 14*dc707122SEaswaran Raman 15*dc707122SEaswaran Raman #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" 16*dc707122SEaswaran Raman #include "llvm/Support/LEB128.h" 17*dc707122SEaswaran Raman 18*dc707122SEaswaran Raman using namespace llvm; 19*dc707122SEaswaran Raman using namespace coverage; 20*dc707122SEaswaran Raman 21*dc707122SEaswaran Raman void CoverageFilenamesSectionWriter::write(raw_ostream &OS) { 22*dc707122SEaswaran Raman encodeULEB128(Filenames.size(), OS); 23*dc707122SEaswaran Raman for (const auto &Filename : Filenames) { 24*dc707122SEaswaran Raman encodeULEB128(Filename.size(), OS); 25*dc707122SEaswaran Raman OS << Filename; 26*dc707122SEaswaran Raman } 27*dc707122SEaswaran Raman } 28*dc707122SEaswaran Raman 29*dc707122SEaswaran Raman namespace { 30*dc707122SEaswaran Raman /// \brief Gather only the expressions that are used by the mapping 31*dc707122SEaswaran Raman /// regions in this function. 32*dc707122SEaswaran Raman class CounterExpressionsMinimizer { 33*dc707122SEaswaran Raman ArrayRef<CounterExpression> Expressions; 34*dc707122SEaswaran Raman llvm::SmallVector<CounterExpression, 16> UsedExpressions; 35*dc707122SEaswaran Raman std::vector<unsigned> AdjustedExpressionIDs; 36*dc707122SEaswaran Raman 37*dc707122SEaswaran Raman public: 38*dc707122SEaswaran Raman void mark(Counter C) { 39*dc707122SEaswaran Raman if (!C.isExpression()) 40*dc707122SEaswaran Raman return; 41*dc707122SEaswaran Raman unsigned ID = C.getExpressionID(); 42*dc707122SEaswaran Raman AdjustedExpressionIDs[ID] = 1; 43*dc707122SEaswaran Raman mark(Expressions[ID].LHS); 44*dc707122SEaswaran Raman mark(Expressions[ID].RHS); 45*dc707122SEaswaran Raman } 46*dc707122SEaswaran Raman 47*dc707122SEaswaran Raman void gatherUsed(Counter C) { 48*dc707122SEaswaran Raman if (!C.isExpression() || !AdjustedExpressionIDs[C.getExpressionID()]) 49*dc707122SEaswaran Raman return; 50*dc707122SEaswaran Raman AdjustedExpressionIDs[C.getExpressionID()] = UsedExpressions.size(); 51*dc707122SEaswaran Raman const auto &E = Expressions[C.getExpressionID()]; 52*dc707122SEaswaran Raman UsedExpressions.push_back(E); 53*dc707122SEaswaran Raman gatherUsed(E.LHS); 54*dc707122SEaswaran Raman gatherUsed(E.RHS); 55*dc707122SEaswaran Raman } 56*dc707122SEaswaran Raman 57*dc707122SEaswaran Raman CounterExpressionsMinimizer(ArrayRef<CounterExpression> Expressions, 58*dc707122SEaswaran Raman ArrayRef<CounterMappingRegion> MappingRegions) 59*dc707122SEaswaran Raman : Expressions(Expressions) { 60*dc707122SEaswaran Raman AdjustedExpressionIDs.resize(Expressions.size(), 0); 61*dc707122SEaswaran Raman for (const auto &I : MappingRegions) 62*dc707122SEaswaran Raman mark(I.Count); 63*dc707122SEaswaran Raman for (const auto &I : MappingRegions) 64*dc707122SEaswaran Raman gatherUsed(I.Count); 65*dc707122SEaswaran Raman } 66*dc707122SEaswaran Raman 67*dc707122SEaswaran Raman ArrayRef<CounterExpression> getExpressions() const { return UsedExpressions; } 68*dc707122SEaswaran Raman 69*dc707122SEaswaran Raman /// \brief Adjust the given counter to correctly transition from the old 70*dc707122SEaswaran Raman /// expression ids to the new expression ids. 71*dc707122SEaswaran Raman Counter adjust(Counter C) const { 72*dc707122SEaswaran Raman if (C.isExpression()) 73*dc707122SEaswaran Raman C = Counter::getExpression(AdjustedExpressionIDs[C.getExpressionID()]); 74*dc707122SEaswaran Raman return C; 75*dc707122SEaswaran Raman } 76*dc707122SEaswaran Raman }; 77*dc707122SEaswaran Raman } 78*dc707122SEaswaran Raman 79*dc707122SEaswaran Raman /// \brief Encode the counter. 80*dc707122SEaswaran Raman /// 81*dc707122SEaswaran Raman /// The encoding uses the following format: 82*dc707122SEaswaran Raman /// Low 2 bits - Tag: 83*dc707122SEaswaran Raman /// Counter::Zero(0) - A Counter with kind Counter::Zero 84*dc707122SEaswaran Raman /// Counter::CounterValueReference(1) - A counter with kind 85*dc707122SEaswaran Raman /// Counter::CounterValueReference 86*dc707122SEaswaran Raman /// Counter::Expression(2) + CounterExpression::Subtract(0) - 87*dc707122SEaswaran Raman /// A counter with kind Counter::Expression and an expression 88*dc707122SEaswaran Raman /// with kind CounterExpression::Subtract 89*dc707122SEaswaran Raman /// Counter::Expression(2) + CounterExpression::Add(1) - 90*dc707122SEaswaran Raman /// A counter with kind Counter::Expression and an expression 91*dc707122SEaswaran Raman /// with kind CounterExpression::Add 92*dc707122SEaswaran Raman /// Remaining bits - Counter/Expression ID. 93*dc707122SEaswaran Raman static unsigned encodeCounter(ArrayRef<CounterExpression> Expressions, 94*dc707122SEaswaran Raman Counter C) { 95*dc707122SEaswaran Raman unsigned Tag = unsigned(C.getKind()); 96*dc707122SEaswaran Raman if (C.isExpression()) 97*dc707122SEaswaran Raman Tag += Expressions[C.getExpressionID()].Kind; 98*dc707122SEaswaran Raman unsigned ID = C.getCounterID(); 99*dc707122SEaswaran Raman assert(ID <= 100*dc707122SEaswaran Raman (std::numeric_limits<unsigned>::max() >> Counter::EncodingTagBits)); 101*dc707122SEaswaran Raman return Tag | (ID << Counter::EncodingTagBits); 102*dc707122SEaswaran Raman } 103*dc707122SEaswaran Raman 104*dc707122SEaswaran Raman static void writeCounter(ArrayRef<CounterExpression> Expressions, Counter C, 105*dc707122SEaswaran Raman raw_ostream &OS) { 106*dc707122SEaswaran Raman encodeULEB128(encodeCounter(Expressions, C), OS); 107*dc707122SEaswaran Raman } 108*dc707122SEaswaran Raman 109*dc707122SEaswaran Raman void CoverageMappingWriter::write(raw_ostream &OS) { 110*dc707122SEaswaran Raman // Sort the regions in an ascending order by the file id and the starting 111*dc707122SEaswaran Raman // location. 112*dc707122SEaswaran Raman std::stable_sort(MappingRegions.begin(), MappingRegions.end()); 113*dc707122SEaswaran Raman 114*dc707122SEaswaran Raman // Write out the fileid -> filename mapping. 115*dc707122SEaswaran Raman encodeULEB128(VirtualFileMapping.size(), OS); 116*dc707122SEaswaran Raman for (const auto &FileID : VirtualFileMapping) 117*dc707122SEaswaran Raman encodeULEB128(FileID, OS); 118*dc707122SEaswaran Raman 119*dc707122SEaswaran Raman // Write out the expressions. 120*dc707122SEaswaran Raman CounterExpressionsMinimizer Minimizer(Expressions, MappingRegions); 121*dc707122SEaswaran Raman auto MinExpressions = Minimizer.getExpressions(); 122*dc707122SEaswaran Raman encodeULEB128(MinExpressions.size(), OS); 123*dc707122SEaswaran Raman for (const auto &E : MinExpressions) { 124*dc707122SEaswaran Raman writeCounter(MinExpressions, Minimizer.adjust(E.LHS), OS); 125*dc707122SEaswaran Raman writeCounter(MinExpressions, Minimizer.adjust(E.RHS), OS); 126*dc707122SEaswaran Raman } 127*dc707122SEaswaran Raman 128*dc707122SEaswaran Raman // Write out the mapping regions. 129*dc707122SEaswaran Raman // Split the regions into subarrays where each region in a 130*dc707122SEaswaran Raman // subarray has a fileID which is the index of that subarray. 131*dc707122SEaswaran Raman unsigned PrevLineStart = 0; 132*dc707122SEaswaran Raman unsigned CurrentFileID = ~0U; 133*dc707122SEaswaran Raman for (auto I = MappingRegions.begin(), E = MappingRegions.end(); I != E; ++I) { 134*dc707122SEaswaran Raman if (I->FileID != CurrentFileID) { 135*dc707122SEaswaran Raman // Ensure that all file ids have at least one mapping region. 136*dc707122SEaswaran Raman assert(I->FileID == (CurrentFileID + 1)); 137*dc707122SEaswaran Raman // Find the number of regions with this file id. 138*dc707122SEaswaran Raman unsigned RegionCount = 1; 139*dc707122SEaswaran Raman for (auto J = I + 1; J != E && I->FileID == J->FileID; ++J) 140*dc707122SEaswaran Raman ++RegionCount; 141*dc707122SEaswaran Raman // Start a new region sub-array. 142*dc707122SEaswaran Raman encodeULEB128(RegionCount, OS); 143*dc707122SEaswaran Raman 144*dc707122SEaswaran Raman CurrentFileID = I->FileID; 145*dc707122SEaswaran Raman PrevLineStart = 0; 146*dc707122SEaswaran Raman } 147*dc707122SEaswaran Raman Counter Count = Minimizer.adjust(I->Count); 148*dc707122SEaswaran Raman switch (I->Kind) { 149*dc707122SEaswaran Raman case CounterMappingRegion::CodeRegion: 150*dc707122SEaswaran Raman writeCounter(MinExpressions, Count, OS); 151*dc707122SEaswaran Raman break; 152*dc707122SEaswaran Raman case CounterMappingRegion::ExpansionRegion: { 153*dc707122SEaswaran Raman assert(Count.isZero()); 154*dc707122SEaswaran Raman assert(I->ExpandedFileID <= 155*dc707122SEaswaran Raman (std::numeric_limits<unsigned>::max() >> 156*dc707122SEaswaran Raman Counter::EncodingCounterTagAndExpansionRegionTagBits)); 157*dc707122SEaswaran Raman // Mark an expansion region with a set bit that follows the counter tag, 158*dc707122SEaswaran Raman // and pack the expanded file id into the remaining bits. 159*dc707122SEaswaran Raman unsigned EncodedTagExpandedFileID = 160*dc707122SEaswaran Raman (1 << Counter::EncodingTagBits) | 161*dc707122SEaswaran Raman (I->ExpandedFileID 162*dc707122SEaswaran Raman << Counter::EncodingCounterTagAndExpansionRegionTagBits); 163*dc707122SEaswaran Raman encodeULEB128(EncodedTagExpandedFileID, OS); 164*dc707122SEaswaran Raman break; 165*dc707122SEaswaran Raman } 166*dc707122SEaswaran Raman case CounterMappingRegion::SkippedRegion: 167*dc707122SEaswaran Raman assert(Count.isZero()); 168*dc707122SEaswaran Raman encodeULEB128(unsigned(I->Kind) 169*dc707122SEaswaran Raman << Counter::EncodingCounterTagAndExpansionRegionTagBits, 170*dc707122SEaswaran Raman OS); 171*dc707122SEaswaran Raman break; 172*dc707122SEaswaran Raman } 173*dc707122SEaswaran Raman assert(I->LineStart >= PrevLineStart); 174*dc707122SEaswaran Raman encodeULEB128(I->LineStart - PrevLineStart, OS); 175*dc707122SEaswaran Raman encodeULEB128(I->ColumnStart, OS); 176*dc707122SEaswaran Raman assert(I->LineEnd >= I->LineStart); 177*dc707122SEaswaran Raman encodeULEB128(I->LineEnd - I->LineStart, OS); 178*dc707122SEaswaran Raman encodeULEB128(I->ColumnEnd, OS); 179*dc707122SEaswaran Raman PrevLineStart = I->LineStart; 180*dc707122SEaswaran Raman } 181*dc707122SEaswaran Raman // Ensure that all file ids have at least one mapping region. 182*dc707122SEaswaran Raman assert(CurrentFileID == (VirtualFileMapping.size() - 1)); 183*dc707122SEaswaran Raman } 184