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 namespace { 22 /// \brief Gather only the expressions that are used by the mapping 23 /// regions in this function. 24 class CounterExpressionsMinimizer { 25 ArrayRef<CounterExpression> Expressions; 26 llvm::SmallVector<CounterExpression, 16> UsedExpressions; 27 std::vector<unsigned> AdjustedExpressionIDs; 28 29 public: 30 void mark(Counter C) { 31 if (!C.isExpression()) 32 return; 33 unsigned ID = C.getExpressionID(); 34 AdjustedExpressionIDs[ID] = 1; 35 mark(Expressions[ID].LHS); 36 mark(Expressions[ID].RHS); 37 } 38 39 void gatherUsed(Counter C) { 40 if (!C.isExpression() || !AdjustedExpressionIDs[C.getExpressionID()]) 41 return; 42 AdjustedExpressionIDs[C.getExpressionID()] = UsedExpressions.size(); 43 const auto &E = Expressions[C.getExpressionID()]; 44 UsedExpressions.push_back(E); 45 gatherUsed(E.LHS); 46 gatherUsed(E.RHS); 47 } 48 49 CounterExpressionsMinimizer(ArrayRef<CounterExpression> Expressions, 50 ArrayRef<CounterMappingRegion> MappingRegions) 51 : Expressions(Expressions) { 52 AdjustedExpressionIDs.resize(Expressions.size(), 0); 53 for (const auto &I : MappingRegions) 54 mark(I.Count); 55 for (const auto &I : MappingRegions) 56 gatherUsed(I.Count); 57 } 58 59 ArrayRef<CounterExpression> getExpressions() const { return UsedExpressions; } 60 61 /// \brief Adjust the given counter to correctly transition from the old 62 /// expression ids to the new expression ids. 63 Counter adjust(Counter C) const { 64 if (C.isExpression()) 65 C = Counter::getExpression(AdjustedExpressionIDs[C.getExpressionID()]); 66 return C; 67 } 68 }; 69 } 70 71 /// \brief Encode the counter. 72 /// 73 /// The encoding uses the following format: 74 /// Low 2 bits - Tag: 75 /// Counter::Zero(0) - A Counter with kind Counter::Zero 76 /// Counter::CounterValueReference(1) - A counter with kind 77 /// Counter::CounterValueReference 78 /// Counter::Expression(2) + CounterExpression::Subtract(0) - 79 /// A counter with kind Counter::Expression and an expression 80 /// with kind CounterExpression::Subtract 81 /// Counter::Expression(2) + CounterExpression::Add(1) - 82 /// A counter with kind Counter::Expression and an expression 83 /// with kind CounterExpression::Add 84 /// Remaining bits - Counter/Expression ID. 85 static unsigned encodeCounter(ArrayRef<CounterExpression> Expressions, 86 Counter C) { 87 unsigned Tag = unsigned(C.getKind()); 88 if (C.isExpression()) 89 Tag += Expressions[C.getExpressionID()].Kind; 90 unsigned ID = C.getCounterID(); 91 assert(ID <= 92 (std::numeric_limits<unsigned>::max() >> Counter::EncodingTagBits)); 93 return Tag | (ID << Counter::EncodingTagBits); 94 } 95 96 static void writeCounter(ArrayRef<CounterExpression> Expressions, Counter C, 97 raw_ostream &OS) { 98 encodeULEB128(encodeCounter(Expressions, C), OS); 99 } 100 101 void CoverageMappingWriter::write(raw_ostream &OS) { 102 // Sort the regions in an ascending order by the file id and the starting 103 // location. 104 std::stable_sort(MappingRegions.begin(), MappingRegions.end()); 105 106 // Write out the fileid -> filename mapping. 107 encodeULEB128(VirtualFileMapping.size(), OS); 108 for (const auto &FileID : VirtualFileMapping) 109 encodeULEB128(FileID, OS); 110 111 // Write out the expressions. 112 CounterExpressionsMinimizer Minimizer(Expressions, MappingRegions); 113 auto MinExpressions = Minimizer.getExpressions(); 114 encodeULEB128(MinExpressions.size(), OS); 115 for (const auto &E : MinExpressions) { 116 writeCounter(MinExpressions, Minimizer.adjust(E.LHS), OS); 117 writeCounter(MinExpressions, Minimizer.adjust(E.RHS), OS); 118 } 119 120 // Write out the mapping regions. 121 // Split the regions into subarrays where each region in a 122 // subarray has a fileID which is the index of that subarray. 123 unsigned PrevLineStart = 0; 124 unsigned CurrentFileID = ~0U; 125 for (auto I = MappingRegions.begin(), E = MappingRegions.end(); I != E; ++I) { 126 if (I->FileID != CurrentFileID) { 127 // Ensure that all file ids have at least one mapping region. 128 assert(I->FileID == (CurrentFileID + 1)); 129 // Find the number of regions with this file id. 130 unsigned RegionCount = 1; 131 for (auto J = I + 1; J != E && I->FileID == J->FileID; ++J) 132 ++RegionCount; 133 // Start a new region sub-array. 134 encodeULEB128(RegionCount, OS); 135 136 CurrentFileID = I->FileID; 137 PrevLineStart = 0; 138 } 139 Counter Count = Minimizer.adjust(I->Count); 140 switch (I->Kind) { 141 case CounterMappingRegion::CodeRegion: 142 writeCounter(MinExpressions, Count, OS); 143 break; 144 case CounterMappingRegion::ExpansionRegion: { 145 assert(Count.isZero()); 146 assert(I->ExpandedFileID <= 147 (std::numeric_limits<unsigned>::max() >> 148 Counter::EncodingCounterTagAndExpansionRegionTagBits)); 149 // Mark an expansion region with a set bit that follows the counter tag, 150 // and pack the expanded file id into the remaining bits. 151 unsigned EncodedTagExpandedFileID = 152 (1 << Counter::EncodingTagBits) | 153 (I->ExpandedFileID 154 << Counter::EncodingCounterTagAndExpansionRegionTagBits); 155 encodeULEB128(EncodedTagExpandedFileID, OS); 156 break; 157 } 158 case CounterMappingRegion::SkippedRegion: 159 assert(Count.isZero()); 160 encodeULEB128(unsigned(I->Kind) 161 << Counter::EncodingCounterTagAndExpansionRegionTagBits, 162 OS); 163 break; 164 } 165 assert(I->LineStart >= PrevLineStart); 166 encodeULEB128(I->LineStart - PrevLineStart, OS); 167 encodeULEB128(I->ColumnStart, OS); 168 assert(I->LineEnd >= I->LineStart); 169 encodeULEB128(I->LineEnd - I->LineStart, OS); 170 encodeULEB128(I->ColumnEnd, OS); 171 PrevLineStart = I->LineStart; 172 } 173 // Ensure that all file ids have at least one mapping region. 174 assert(CurrentFileID == (VirtualFileMapping.size() - 1)); 175 } 176 177 /// \brief Encode coverage data into \p OS. 178 static void encodeCoverageData(ArrayRef<std::string> Filenames, 179 ArrayRef<std::string> CoverageMappings, 180 size_t &FilenamesSize, 181 size_t &CoverageMappingsSize, raw_ostream &OS) { 182 size_t OSOffset = OS.GetNumBytesInBuffer(); 183 184 // Encode the filenames. 185 encodeULEB128(Filenames.size(), OS); 186 for (const auto &Filename : Filenames) { 187 encodeULEB128(Filename.size(), OS); 188 OS << Filename; 189 } 190 191 FilenamesSize = OS.GetNumBytesInBuffer() - OSOffset; 192 193 // Encode the coverage mappings. 194 for (const auto &RawMapping : CoverageMappings) 195 OS << RawMapping; 196 197 // Pad the output stream to an 8-byte boundary. Account for the padding bytes 198 // in \p CoverageMappingsSize. 199 if (size_t Rem = OS.GetNumBytesInBuffer() % 8) { 200 CoverageMappingsSize += 8 - Rem; 201 for (size_t I = 0, S = 8 - Rem; I < S; ++I) 202 OS << '\0'; 203 } 204 205 CoverageMappingsSize = OS.GetNumBytesInBuffer() - FilenamesSize - OSOffset; 206 } 207 208 namespace llvm { 209 namespace coverage { 210 211 Expected<std::string> encodeFilenamesAndRawMappings( 212 ArrayRef<std::string> Filenames, ArrayRef<std::string> CoverageMappings, 213 size_t &FilenamesSize, size_t &CoverageMappingsSize) { 214 std::string CoverageData; 215 { 216 raw_string_ostream OS{CoverageData}; 217 encodeCoverageData(Filenames, CoverageMappings, FilenamesSize, 218 CoverageMappingsSize, OS); 219 } 220 return std::move(CoverageData); 221 } 222 223 } // end namespace coverage 224 } // end namespace llvm 225