10b57cec5SDimitry Andric //===- CoverageMappingWriter.cpp - Code coverage mapping writer -----------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file contains support for writing coverage mapping data for 100b57cec5SDimitry Andric // instrumentation based coverage. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" 150b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h" 160b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 1706c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h" 1806c3fb27SDimitry Andric #include "llvm/ProfileData/InstrProf.h" 195ffd83dbSDimitry Andric #include "llvm/Support/Compression.h" 200b57cec5SDimitry Andric #include "llvm/Support/LEB128.h" 210b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 220b57cec5SDimitry Andric #include <algorithm> 230b57cec5SDimitry Andric #include <cassert> 240b57cec5SDimitry Andric #include <limits> 250b57cec5SDimitry Andric #include <vector> 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric using namespace llvm; 280b57cec5SDimitry Andric using namespace coverage; 290b57cec5SDimitry Andric 308bcb0991SDimitry Andric CoverageFilenamesSectionWriter::CoverageFilenamesSectionWriter( 31fe6060f1SDimitry Andric ArrayRef<std::string> Filenames) 328bcb0991SDimitry Andric : Filenames(Filenames) { 338bcb0991SDimitry Andric #ifndef NDEBUG 348bcb0991SDimitry Andric StringSet<> NameSet; 358bcb0991SDimitry Andric for (StringRef Name : Filenames) 368bcb0991SDimitry Andric assert(NameSet.insert(Name).second && "Duplicate filename"); 378bcb0991SDimitry Andric #endif 388bcb0991SDimitry Andric } 398bcb0991SDimitry Andric 405ffd83dbSDimitry Andric void CoverageFilenamesSectionWriter::write(raw_ostream &OS, bool Compress) { 415ffd83dbSDimitry Andric std::string FilenamesStr; 425ffd83dbSDimitry Andric { 435ffd83dbSDimitry Andric raw_string_ostream FilenamesOS{FilenamesStr}; 440b57cec5SDimitry Andric for (const auto &Filename : Filenames) { 455ffd83dbSDimitry Andric encodeULEB128(Filename.size(), FilenamesOS); 465ffd83dbSDimitry Andric FilenamesOS << Filename; 470b57cec5SDimitry Andric } 480b57cec5SDimitry Andric } 490b57cec5SDimitry Andric 50753f127fSDimitry Andric SmallVector<uint8_t, 128> CompressedStr; 51753f127fSDimitry Andric bool doCompression = Compress && compression::zlib::isAvailable() && 52753f127fSDimitry Andric DoInstrProfNameCompression; 5381ad6265SDimitry Andric if (doCompression) 54753f127fSDimitry Andric compression::zlib::compress(arrayRefFromStringRef(FilenamesStr), 55753f127fSDimitry Andric CompressedStr, 56753f127fSDimitry Andric compression::zlib::BestSizeCompression); 575ffd83dbSDimitry Andric 585ffd83dbSDimitry Andric // ::= <num-filenames> 595ffd83dbSDimitry Andric // <uncompressed-len> 605ffd83dbSDimitry Andric // <compressed-len-or-zero> 615ffd83dbSDimitry Andric // (<compressed-filenames> | <uncompressed-filenames>) 625ffd83dbSDimitry Andric encodeULEB128(Filenames.size(), OS); 635ffd83dbSDimitry Andric encodeULEB128(FilenamesStr.size(), OS); 645ffd83dbSDimitry Andric encodeULEB128(doCompression ? CompressedStr.size() : 0U, OS); 65753f127fSDimitry Andric OS << (doCompression ? toStringRef(CompressedStr) : StringRef(FilenamesStr)); 665ffd83dbSDimitry Andric } 675ffd83dbSDimitry Andric 680b57cec5SDimitry Andric namespace { 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric /// Gather only the expressions that are used by the mapping 710b57cec5SDimitry Andric /// regions in this function. 720b57cec5SDimitry Andric class CounterExpressionsMinimizer { 730b57cec5SDimitry Andric ArrayRef<CounterExpression> Expressions; 740b57cec5SDimitry Andric SmallVector<CounterExpression, 16> UsedExpressions; 750b57cec5SDimitry Andric std::vector<unsigned> AdjustedExpressionIDs; 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric public: 780b57cec5SDimitry Andric CounterExpressionsMinimizer(ArrayRef<CounterExpression> Expressions, 790b57cec5SDimitry Andric ArrayRef<CounterMappingRegion> MappingRegions) 800b57cec5SDimitry Andric : Expressions(Expressions) { 810b57cec5SDimitry Andric AdjustedExpressionIDs.resize(Expressions.size(), 0); 82e8d8bef9SDimitry Andric for (const auto &I : MappingRegions) { 830b57cec5SDimitry Andric mark(I.Count); 84e8d8bef9SDimitry Andric mark(I.FalseCount); 85e8d8bef9SDimitry Andric } 86e8d8bef9SDimitry Andric for (const auto &I : MappingRegions) { 870b57cec5SDimitry Andric gatherUsed(I.Count); 88e8d8bef9SDimitry Andric gatherUsed(I.FalseCount); 89e8d8bef9SDimitry Andric } 900b57cec5SDimitry Andric } 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric void mark(Counter C) { 930b57cec5SDimitry Andric if (!C.isExpression()) 940b57cec5SDimitry Andric return; 950b57cec5SDimitry Andric unsigned ID = C.getExpressionID(); 960b57cec5SDimitry Andric AdjustedExpressionIDs[ID] = 1; 970b57cec5SDimitry Andric mark(Expressions[ID].LHS); 980b57cec5SDimitry Andric mark(Expressions[ID].RHS); 990b57cec5SDimitry Andric } 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric void gatherUsed(Counter C) { 1020b57cec5SDimitry Andric if (!C.isExpression() || !AdjustedExpressionIDs[C.getExpressionID()]) 1030b57cec5SDimitry Andric return; 1040b57cec5SDimitry Andric AdjustedExpressionIDs[C.getExpressionID()] = UsedExpressions.size(); 1050b57cec5SDimitry Andric const auto &E = Expressions[C.getExpressionID()]; 1060b57cec5SDimitry Andric UsedExpressions.push_back(E); 1070b57cec5SDimitry Andric gatherUsed(E.LHS); 1080b57cec5SDimitry Andric gatherUsed(E.RHS); 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric ArrayRef<CounterExpression> getExpressions() const { return UsedExpressions; } 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric /// Adjust the given counter to correctly transition from the old 1140b57cec5SDimitry Andric /// expression ids to the new expression ids. 1150b57cec5SDimitry Andric Counter adjust(Counter C) const { 1160b57cec5SDimitry Andric if (C.isExpression()) 1170b57cec5SDimitry Andric C = Counter::getExpression(AdjustedExpressionIDs[C.getExpressionID()]); 1180b57cec5SDimitry Andric return C; 1190b57cec5SDimitry Andric } 1200b57cec5SDimitry Andric }; 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric } // end anonymous namespace 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric /// Encode the counter. 1250b57cec5SDimitry Andric /// 1260b57cec5SDimitry Andric /// The encoding uses the following format: 1270b57cec5SDimitry Andric /// Low 2 bits - Tag: 1280b57cec5SDimitry Andric /// Counter::Zero(0) - A Counter with kind Counter::Zero 1290b57cec5SDimitry Andric /// Counter::CounterValueReference(1) - A counter with kind 1300b57cec5SDimitry Andric /// Counter::CounterValueReference 1310b57cec5SDimitry Andric /// Counter::Expression(2) + CounterExpression::Subtract(0) - 1320b57cec5SDimitry Andric /// A counter with kind Counter::Expression and an expression 1330b57cec5SDimitry Andric /// with kind CounterExpression::Subtract 1340b57cec5SDimitry Andric /// Counter::Expression(2) + CounterExpression::Add(1) - 1350b57cec5SDimitry Andric /// A counter with kind Counter::Expression and an expression 1360b57cec5SDimitry Andric /// with kind CounterExpression::Add 1370b57cec5SDimitry Andric /// Remaining bits - Counter/Expression ID. 1380b57cec5SDimitry Andric static unsigned encodeCounter(ArrayRef<CounterExpression> Expressions, 1390b57cec5SDimitry Andric Counter C) { 1400b57cec5SDimitry Andric unsigned Tag = unsigned(C.getKind()); 1410b57cec5SDimitry Andric if (C.isExpression()) 1420b57cec5SDimitry Andric Tag += Expressions[C.getExpressionID()].Kind; 1430b57cec5SDimitry Andric unsigned ID = C.getCounterID(); 1440b57cec5SDimitry Andric assert(ID <= 1450b57cec5SDimitry Andric (std::numeric_limits<unsigned>::max() >> Counter::EncodingTagBits)); 1460b57cec5SDimitry Andric return Tag | (ID << Counter::EncodingTagBits); 1470b57cec5SDimitry Andric } 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric static void writeCounter(ArrayRef<CounterExpression> Expressions, Counter C, 1500b57cec5SDimitry Andric raw_ostream &OS) { 1510b57cec5SDimitry Andric encodeULEB128(encodeCounter(Expressions, C), OS); 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric void CoverageMappingWriter::write(raw_ostream &OS) { 1550b57cec5SDimitry Andric // Check that we don't have any bogus regions. 1560b57cec5SDimitry Andric assert(all_of(MappingRegions, 1570b57cec5SDimitry Andric [](const CounterMappingRegion &CMR) { 1580b57cec5SDimitry Andric return CMR.startLoc() <= CMR.endLoc(); 1590b57cec5SDimitry Andric }) && 1600b57cec5SDimitry Andric "Source region does not begin before it ends"); 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric // Sort the regions in an ascending order by the file id and the starting 1630b57cec5SDimitry Andric // location. Sort by region kinds to ensure stable order for tests. 1640b57cec5SDimitry Andric llvm::stable_sort(MappingRegions, [](const CounterMappingRegion &LHS, 1650b57cec5SDimitry Andric const CounterMappingRegion &RHS) { 1660b57cec5SDimitry Andric if (LHS.FileID != RHS.FileID) 1670b57cec5SDimitry Andric return LHS.FileID < RHS.FileID; 1680b57cec5SDimitry Andric if (LHS.startLoc() != RHS.startLoc()) 1690b57cec5SDimitry Andric return LHS.startLoc() < RHS.startLoc(); 170b3edf446SDimitry Andric 171b3edf446SDimitry Andric // Put `Decision` before `Expansion`. 172b3edf446SDimitry Andric auto getKindKey = [](CounterMappingRegion::RegionKind Kind) { 173b3edf446SDimitry Andric return (Kind == CounterMappingRegion::MCDCDecisionRegion 174b3edf446SDimitry Andric ? 2 * CounterMappingRegion::ExpansionRegion - 1 175b3edf446SDimitry Andric : 2 * Kind); 176b3edf446SDimitry Andric }; 177b3edf446SDimitry Andric 178b3edf446SDimitry Andric return getKindKey(LHS.Kind) < getKindKey(RHS.Kind); 1790b57cec5SDimitry Andric }); 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric // Write out the fileid -> filename mapping. 1820b57cec5SDimitry Andric encodeULEB128(VirtualFileMapping.size(), OS); 1830b57cec5SDimitry Andric for (const auto &FileID : VirtualFileMapping) 1840b57cec5SDimitry Andric encodeULEB128(FileID, OS); 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric // Write out the expressions. 1870b57cec5SDimitry Andric CounterExpressionsMinimizer Minimizer(Expressions, MappingRegions); 1880b57cec5SDimitry Andric auto MinExpressions = Minimizer.getExpressions(); 1890b57cec5SDimitry Andric encodeULEB128(MinExpressions.size(), OS); 1900b57cec5SDimitry Andric for (const auto &E : MinExpressions) { 1910b57cec5SDimitry Andric writeCounter(MinExpressions, Minimizer.adjust(E.LHS), OS); 1920b57cec5SDimitry Andric writeCounter(MinExpressions, Minimizer.adjust(E.RHS), OS); 1930b57cec5SDimitry Andric } 1940b57cec5SDimitry Andric 1950b57cec5SDimitry Andric // Write out the mapping regions. 1960b57cec5SDimitry Andric // Split the regions into subarrays where each region in a 1970b57cec5SDimitry Andric // subarray has a fileID which is the index of that subarray. 1980b57cec5SDimitry Andric unsigned PrevLineStart = 0; 1990b57cec5SDimitry Andric unsigned CurrentFileID = ~0U; 2000b57cec5SDimitry Andric for (auto I = MappingRegions.begin(), E = MappingRegions.end(); I != E; ++I) { 2010b57cec5SDimitry Andric if (I->FileID != CurrentFileID) { 2020b57cec5SDimitry Andric // Ensure that all file ids have at least one mapping region. 2030b57cec5SDimitry Andric assert(I->FileID == (CurrentFileID + 1)); 2040b57cec5SDimitry Andric // Find the number of regions with this file id. 2050b57cec5SDimitry Andric unsigned RegionCount = 1; 2060b57cec5SDimitry Andric for (auto J = I + 1; J != E && I->FileID == J->FileID; ++J) 2070b57cec5SDimitry Andric ++RegionCount; 2080b57cec5SDimitry Andric // Start a new region sub-array. 2090b57cec5SDimitry Andric encodeULEB128(RegionCount, OS); 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric CurrentFileID = I->FileID; 2120b57cec5SDimitry Andric PrevLineStart = 0; 2130b57cec5SDimitry Andric } 2140b57cec5SDimitry Andric Counter Count = Minimizer.adjust(I->Count); 215e8d8bef9SDimitry Andric Counter FalseCount = Minimizer.adjust(I->FalseCount); 216*0fca6ea1SDimitry Andric bool ParamsShouldBeNull = true; 2170b57cec5SDimitry Andric switch (I->Kind) { 2180b57cec5SDimitry Andric case CounterMappingRegion::CodeRegion: 2190b57cec5SDimitry Andric case CounterMappingRegion::GapRegion: 2200b57cec5SDimitry Andric writeCounter(MinExpressions, Count, OS); 2210b57cec5SDimitry Andric break; 2220b57cec5SDimitry Andric case CounterMappingRegion::ExpansionRegion: { 2230b57cec5SDimitry Andric assert(Count.isZero()); 2240b57cec5SDimitry Andric assert(I->ExpandedFileID <= 2250b57cec5SDimitry Andric (std::numeric_limits<unsigned>::max() >> 2260b57cec5SDimitry Andric Counter::EncodingCounterTagAndExpansionRegionTagBits)); 2270b57cec5SDimitry Andric // Mark an expansion region with a set bit that follows the counter tag, 2280b57cec5SDimitry Andric // and pack the expanded file id into the remaining bits. 2290b57cec5SDimitry Andric unsigned EncodedTagExpandedFileID = 2300b57cec5SDimitry Andric (1 << Counter::EncodingTagBits) | 2310b57cec5SDimitry Andric (I->ExpandedFileID 2320b57cec5SDimitry Andric << Counter::EncodingCounterTagAndExpansionRegionTagBits); 2330b57cec5SDimitry Andric encodeULEB128(EncodedTagExpandedFileID, OS); 2340b57cec5SDimitry Andric break; 2350b57cec5SDimitry Andric } 2360b57cec5SDimitry Andric case CounterMappingRegion::SkippedRegion: 2370b57cec5SDimitry Andric assert(Count.isZero()); 2380b57cec5SDimitry Andric encodeULEB128(unsigned(I->Kind) 2390b57cec5SDimitry Andric << Counter::EncodingCounterTagAndExpansionRegionTagBits, 2400b57cec5SDimitry Andric OS); 2410b57cec5SDimitry Andric break; 242e8d8bef9SDimitry Andric case CounterMappingRegion::BranchRegion: 243e8d8bef9SDimitry Andric encodeULEB128(unsigned(I->Kind) 244e8d8bef9SDimitry Andric << Counter::EncodingCounterTagAndExpansionRegionTagBits, 245e8d8bef9SDimitry Andric OS); 246e8d8bef9SDimitry Andric writeCounter(MinExpressions, Count, OS); 247e8d8bef9SDimitry Andric writeCounter(MinExpressions, FalseCount, OS); 248e8d8bef9SDimitry Andric break; 2495f757f3fSDimitry Andric case CounterMappingRegion::MCDCBranchRegion: 2505f757f3fSDimitry Andric encodeULEB128(unsigned(I->Kind) 2515f757f3fSDimitry Andric << Counter::EncodingCounterTagAndExpansionRegionTagBits, 2525f757f3fSDimitry Andric OS); 2535f757f3fSDimitry Andric writeCounter(MinExpressions, Count, OS); 2545f757f3fSDimitry Andric writeCounter(MinExpressions, FalseCount, OS); 255*0fca6ea1SDimitry Andric { 256*0fca6ea1SDimitry Andric // They are written as internal values plus 1. 257*0fca6ea1SDimitry Andric const auto &BranchParams = I->getBranchParams(); 258*0fca6ea1SDimitry Andric ParamsShouldBeNull = false; 259*0fca6ea1SDimitry Andric unsigned ID1 = BranchParams.ID + 1; 260*0fca6ea1SDimitry Andric unsigned TID1 = BranchParams.Conds[true] + 1; 261*0fca6ea1SDimitry Andric unsigned FID1 = BranchParams.Conds[false] + 1; 262*0fca6ea1SDimitry Andric encodeULEB128(ID1, OS); 263*0fca6ea1SDimitry Andric encodeULEB128(TID1, OS); 264*0fca6ea1SDimitry Andric encodeULEB128(FID1, OS); 265*0fca6ea1SDimitry Andric } 2665f757f3fSDimitry Andric break; 2675f757f3fSDimitry Andric case CounterMappingRegion::MCDCDecisionRegion: 2685f757f3fSDimitry Andric encodeULEB128(unsigned(I->Kind) 2695f757f3fSDimitry Andric << Counter::EncodingCounterTagAndExpansionRegionTagBits, 2705f757f3fSDimitry Andric OS); 271*0fca6ea1SDimitry Andric { 272*0fca6ea1SDimitry Andric const auto &DecisionParams = I->getDecisionParams(); 273*0fca6ea1SDimitry Andric ParamsShouldBeNull = false; 274*0fca6ea1SDimitry Andric encodeULEB128(static_cast<unsigned>(DecisionParams.BitmapIdx), OS); 275*0fca6ea1SDimitry Andric encodeULEB128(static_cast<unsigned>(DecisionParams.NumConditions), OS); 276*0fca6ea1SDimitry Andric } 2775f757f3fSDimitry Andric break; 2780b57cec5SDimitry Andric } 2790b57cec5SDimitry Andric assert(I->LineStart >= PrevLineStart); 2800b57cec5SDimitry Andric encodeULEB128(I->LineStart - PrevLineStart, OS); 2810b57cec5SDimitry Andric encodeULEB128(I->ColumnStart, OS); 2820b57cec5SDimitry Andric assert(I->LineEnd >= I->LineStart); 2830b57cec5SDimitry Andric encodeULEB128(I->LineEnd - I->LineStart, OS); 2840b57cec5SDimitry Andric encodeULEB128(I->ColumnEnd, OS); 2850b57cec5SDimitry Andric PrevLineStart = I->LineStart; 286*0fca6ea1SDimitry Andric assert((!ParamsShouldBeNull || std::get_if<0>(&I->MCDCParams)) && 287*0fca6ea1SDimitry Andric "MCDCParams should be empty"); 288*0fca6ea1SDimitry Andric (void)ParamsShouldBeNull; 2890b57cec5SDimitry Andric } 2900b57cec5SDimitry Andric // Ensure that all file ids have at least one mapping region. 2910b57cec5SDimitry Andric assert(CurrentFileID == (VirtualFileMapping.size() - 1)); 2920b57cec5SDimitry Andric } 2935f757f3fSDimitry Andric 2945f757f3fSDimitry Andric void TestingFormatWriter::write(raw_ostream &OS, TestingFormatVersion Version) { 2955f757f3fSDimitry Andric auto ByteSwap = [](uint64_t N) { 2965f757f3fSDimitry Andric return support::endian::byte_swap<uint64_t, llvm::endianness::little>(N); 2975f757f3fSDimitry Andric }; 2985f757f3fSDimitry Andric 2995f757f3fSDimitry Andric // Output a 64bit magic number. 3005f757f3fSDimitry Andric auto Magic = ByteSwap(TestingFormatMagic); 3015f757f3fSDimitry Andric OS.write(reinterpret_cast<char *>(&Magic), sizeof(Magic)); 3025f757f3fSDimitry Andric 3035f757f3fSDimitry Andric // Output a 64bit version field. 3045f757f3fSDimitry Andric auto VersionLittle = ByteSwap(uint64_t(Version)); 3055f757f3fSDimitry Andric OS.write(reinterpret_cast<char *>(&VersionLittle), sizeof(VersionLittle)); 3065f757f3fSDimitry Andric 3075f757f3fSDimitry Andric // Output the ProfileNames data. 3085f757f3fSDimitry Andric encodeULEB128(ProfileNamesData.size(), OS); 3095f757f3fSDimitry Andric encodeULEB128(ProfileNamesAddr, OS); 3105f757f3fSDimitry Andric OS << ProfileNamesData; 3115f757f3fSDimitry Andric 3125f757f3fSDimitry Andric // Version2 adds an extra field to indicate the size of the 3135f757f3fSDimitry Andric // CoverageMappingData. 3145f757f3fSDimitry Andric if (Version == TestingFormatVersion::Version2) 3155f757f3fSDimitry Andric encodeULEB128(CoverageMappingData.size(), OS); 3165f757f3fSDimitry Andric 3175f757f3fSDimitry Andric // Coverage mapping data is expected to have an alignment of 8. 3185f757f3fSDimitry Andric for (unsigned Pad = offsetToAlignment(OS.tell(), Align(8)); Pad; --Pad) 3195f757f3fSDimitry Andric OS.write(uint8_t(0)); 3205f757f3fSDimitry Andric OS << CoverageMappingData; 3215f757f3fSDimitry Andric 3225f757f3fSDimitry Andric // Coverage records data is expected to have an alignment of 8. 3235f757f3fSDimitry Andric for (unsigned Pad = offsetToAlignment(OS.tell(), Align(8)); Pad; --Pad) 3245f757f3fSDimitry Andric OS.write(uint8_t(0)); 3255f757f3fSDimitry Andric OS << CoverageRecordsData; 3265f757f3fSDimitry Andric } 327