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