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"
17fe013be4SDimitry Andric #include "llvm/ADT/StringExtras.h"
18fe013be4SDimitry 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
CoverageFilenamesSectionWriter(ArrayRef<std::string> Filenames)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
write(raw_ostream & OS,bool Compress)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:
CounterExpressionsMinimizer(ArrayRef<CounterExpression> Expressions,ArrayRef<CounterMappingRegion> MappingRegions)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
mark(Counter C)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
gatherUsed(Counter C)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
getExpressions() const1110b57cec5SDimitry 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.
adjust(Counter C) const1150b57cec5SDimitry 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.
encodeCounter(ArrayRef<CounterExpression> Expressions,Counter C)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
writeCounter(ArrayRef<CounterExpression> Expressions,Counter C,raw_ostream & OS)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
write(raw_ostream & OS)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();
170*b9d9368bSDimitry Andric
171*b9d9368bSDimitry Andric // Put `Decision` before `Expansion`.
172*b9d9368bSDimitry Andric auto getKindKey = [](CounterMappingRegion::RegionKind Kind) {
173*b9d9368bSDimitry Andric return (Kind == CounterMappingRegion::MCDCDecisionRegion
174*b9d9368bSDimitry Andric ? 2 * CounterMappingRegion::ExpansionRegion - 1
175*b9d9368bSDimitry Andric : 2 * Kind);
176*b9d9368bSDimitry Andric };
177*b9d9368bSDimitry Andric
178*b9d9368bSDimitry 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);
2160b57cec5SDimitry Andric switch (I->Kind) {
2170b57cec5SDimitry Andric case CounterMappingRegion::CodeRegion:
2180b57cec5SDimitry Andric case CounterMappingRegion::GapRegion:
2190b57cec5SDimitry Andric writeCounter(MinExpressions, Count, OS);
2200b57cec5SDimitry Andric break;
2210b57cec5SDimitry Andric case CounterMappingRegion::ExpansionRegion: {
2220b57cec5SDimitry Andric assert(Count.isZero());
2230b57cec5SDimitry Andric assert(I->ExpandedFileID <=
2240b57cec5SDimitry Andric (std::numeric_limits<unsigned>::max() >>
2250b57cec5SDimitry Andric Counter::EncodingCounterTagAndExpansionRegionTagBits));
2260b57cec5SDimitry Andric // Mark an expansion region with a set bit that follows the counter tag,
2270b57cec5SDimitry Andric // and pack the expanded file id into the remaining bits.
2280b57cec5SDimitry Andric unsigned EncodedTagExpandedFileID =
2290b57cec5SDimitry Andric (1 << Counter::EncodingTagBits) |
2300b57cec5SDimitry Andric (I->ExpandedFileID
2310b57cec5SDimitry Andric << Counter::EncodingCounterTagAndExpansionRegionTagBits);
2320b57cec5SDimitry Andric encodeULEB128(EncodedTagExpandedFileID, OS);
2330b57cec5SDimitry Andric break;
2340b57cec5SDimitry Andric }
2350b57cec5SDimitry Andric case CounterMappingRegion::SkippedRegion:
2360b57cec5SDimitry Andric assert(Count.isZero());
2370b57cec5SDimitry Andric encodeULEB128(unsigned(I->Kind)
2380b57cec5SDimitry Andric << Counter::EncodingCounterTagAndExpansionRegionTagBits,
2390b57cec5SDimitry Andric OS);
2400b57cec5SDimitry Andric break;
241e8d8bef9SDimitry Andric case CounterMappingRegion::BranchRegion:
242e8d8bef9SDimitry Andric encodeULEB128(unsigned(I->Kind)
243e8d8bef9SDimitry Andric << Counter::EncodingCounterTagAndExpansionRegionTagBits,
244e8d8bef9SDimitry Andric OS);
245e8d8bef9SDimitry Andric writeCounter(MinExpressions, Count, OS);
246e8d8bef9SDimitry Andric writeCounter(MinExpressions, FalseCount, OS);
247e8d8bef9SDimitry Andric break;
248c9157d92SDimitry Andric case CounterMappingRegion::MCDCBranchRegion:
249c9157d92SDimitry Andric encodeULEB128(unsigned(I->Kind)
250c9157d92SDimitry Andric << Counter::EncodingCounterTagAndExpansionRegionTagBits,
251c9157d92SDimitry Andric OS);
252c9157d92SDimitry Andric writeCounter(MinExpressions, Count, OS);
253c9157d92SDimitry Andric writeCounter(MinExpressions, FalseCount, OS);
254c9157d92SDimitry Andric encodeULEB128(unsigned(I->MCDCParams.ID), OS);
255c9157d92SDimitry Andric encodeULEB128(unsigned(I->MCDCParams.TrueID), OS);
256c9157d92SDimitry Andric encodeULEB128(unsigned(I->MCDCParams.FalseID), OS);
257c9157d92SDimitry Andric break;
258c9157d92SDimitry Andric case CounterMappingRegion::MCDCDecisionRegion:
259c9157d92SDimitry Andric encodeULEB128(unsigned(I->Kind)
260c9157d92SDimitry Andric << Counter::EncodingCounterTagAndExpansionRegionTagBits,
261c9157d92SDimitry Andric OS);
262c9157d92SDimitry Andric encodeULEB128(unsigned(I->MCDCParams.BitmapIdx), OS);
263c9157d92SDimitry Andric encodeULEB128(unsigned(I->MCDCParams.NumConditions), OS);
264c9157d92SDimitry Andric break;
2650b57cec5SDimitry Andric }
2660b57cec5SDimitry Andric assert(I->LineStart >= PrevLineStart);
2670b57cec5SDimitry Andric encodeULEB128(I->LineStart - PrevLineStart, OS);
2680b57cec5SDimitry Andric encodeULEB128(I->ColumnStart, OS);
2690b57cec5SDimitry Andric assert(I->LineEnd >= I->LineStart);
2700b57cec5SDimitry Andric encodeULEB128(I->LineEnd - I->LineStart, OS);
2710b57cec5SDimitry Andric encodeULEB128(I->ColumnEnd, OS);
2720b57cec5SDimitry Andric PrevLineStart = I->LineStart;
2730b57cec5SDimitry Andric }
2740b57cec5SDimitry Andric // Ensure that all file ids have at least one mapping region.
2750b57cec5SDimitry Andric assert(CurrentFileID == (VirtualFileMapping.size() - 1));
2760b57cec5SDimitry Andric }
277c9157d92SDimitry Andric
write(raw_ostream & OS,TestingFormatVersion Version)278c9157d92SDimitry Andric void TestingFormatWriter::write(raw_ostream &OS, TestingFormatVersion Version) {
279c9157d92SDimitry Andric auto ByteSwap = [](uint64_t N) {
280c9157d92SDimitry Andric return support::endian::byte_swap<uint64_t, llvm::endianness::little>(N);
281c9157d92SDimitry Andric };
282c9157d92SDimitry Andric
283c9157d92SDimitry Andric // Output a 64bit magic number.
284c9157d92SDimitry Andric auto Magic = ByteSwap(TestingFormatMagic);
285c9157d92SDimitry Andric OS.write(reinterpret_cast<char *>(&Magic), sizeof(Magic));
286c9157d92SDimitry Andric
287c9157d92SDimitry Andric // Output a 64bit version field.
288c9157d92SDimitry Andric auto VersionLittle = ByteSwap(uint64_t(Version));
289c9157d92SDimitry Andric OS.write(reinterpret_cast<char *>(&VersionLittle), sizeof(VersionLittle));
290c9157d92SDimitry Andric
291c9157d92SDimitry Andric // Output the ProfileNames data.
292c9157d92SDimitry Andric encodeULEB128(ProfileNamesData.size(), OS);
293c9157d92SDimitry Andric encodeULEB128(ProfileNamesAddr, OS);
294c9157d92SDimitry Andric OS << ProfileNamesData;
295c9157d92SDimitry Andric
296c9157d92SDimitry Andric // Version2 adds an extra field to indicate the size of the
297c9157d92SDimitry Andric // CoverageMappingData.
298c9157d92SDimitry Andric if (Version == TestingFormatVersion::Version2)
299c9157d92SDimitry Andric encodeULEB128(CoverageMappingData.size(), OS);
300c9157d92SDimitry Andric
301c9157d92SDimitry Andric // Coverage mapping data is expected to have an alignment of 8.
302c9157d92SDimitry Andric for (unsigned Pad = offsetToAlignment(OS.tell(), Align(8)); Pad; --Pad)
303c9157d92SDimitry Andric OS.write(uint8_t(0));
304c9157d92SDimitry Andric OS << CoverageMappingData;
305c9157d92SDimitry Andric
306c9157d92SDimitry Andric // Coverage records data is expected to have an alignment of 8.
307c9157d92SDimitry Andric for (unsigned Pad = offsetToAlignment(OS.tell(), Align(8)); Pad; --Pad)
308c9157d92SDimitry Andric OS.write(uint8_t(0));
309c9157d92SDimitry Andric OS << CoverageRecordsData;
310c9157d92SDimitry Andric }
311