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