17330f729Sjoerg //===- CoverageMapping.cpp - Code coverage mapping support ----------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This file contains support for clang's and llvm's instrumentation based
107330f729Sjoerg // code coverage.
117330f729Sjoerg //
127330f729Sjoerg //===----------------------------------------------------------------------===//
137330f729Sjoerg
147330f729Sjoerg #include "llvm/ProfileData/Coverage/CoverageMapping.h"
157330f729Sjoerg #include "llvm/ADT/ArrayRef.h"
167330f729Sjoerg #include "llvm/ADT/DenseMap.h"
177330f729Sjoerg #include "llvm/ADT/None.h"
187330f729Sjoerg #include "llvm/ADT/Optional.h"
197330f729Sjoerg #include "llvm/ADT/SmallBitVector.h"
207330f729Sjoerg #include "llvm/ADT/SmallVector.h"
217330f729Sjoerg #include "llvm/ADT/StringRef.h"
227330f729Sjoerg #include "llvm/ProfileData/Coverage/CoverageMappingReader.h"
237330f729Sjoerg #include "llvm/ProfileData/InstrProfReader.h"
247330f729Sjoerg #include "llvm/Support/Debug.h"
257330f729Sjoerg #include "llvm/Support/Errc.h"
267330f729Sjoerg #include "llvm/Support/Error.h"
277330f729Sjoerg #include "llvm/Support/ErrorHandling.h"
287330f729Sjoerg #include "llvm/Support/ManagedStatic.h"
297330f729Sjoerg #include "llvm/Support/MemoryBuffer.h"
307330f729Sjoerg #include "llvm/Support/raw_ostream.h"
317330f729Sjoerg #include <algorithm>
327330f729Sjoerg #include <cassert>
337330f729Sjoerg #include <cstdint>
347330f729Sjoerg #include <iterator>
357330f729Sjoerg #include <map>
367330f729Sjoerg #include <memory>
377330f729Sjoerg #include <string>
387330f729Sjoerg #include <system_error>
397330f729Sjoerg #include <utility>
407330f729Sjoerg #include <vector>
417330f729Sjoerg
427330f729Sjoerg using namespace llvm;
437330f729Sjoerg using namespace coverage;
447330f729Sjoerg
457330f729Sjoerg #define DEBUG_TYPE "coverage-mapping"
467330f729Sjoerg
get(const CounterExpression & E)477330f729Sjoerg Counter CounterExpressionBuilder::get(const CounterExpression &E) {
487330f729Sjoerg auto It = ExpressionIndices.find(E);
497330f729Sjoerg if (It != ExpressionIndices.end())
507330f729Sjoerg return Counter::getExpression(It->second);
517330f729Sjoerg unsigned I = Expressions.size();
527330f729Sjoerg Expressions.push_back(E);
537330f729Sjoerg ExpressionIndices[E] = I;
547330f729Sjoerg return Counter::getExpression(I);
557330f729Sjoerg }
567330f729Sjoerg
extractTerms(Counter C,int Factor,SmallVectorImpl<Term> & Terms)577330f729Sjoerg void CounterExpressionBuilder::extractTerms(Counter C, int Factor,
587330f729Sjoerg SmallVectorImpl<Term> &Terms) {
597330f729Sjoerg switch (C.getKind()) {
607330f729Sjoerg case Counter::Zero:
617330f729Sjoerg break;
627330f729Sjoerg case Counter::CounterValueReference:
637330f729Sjoerg Terms.emplace_back(C.getCounterID(), Factor);
647330f729Sjoerg break;
657330f729Sjoerg case Counter::Expression:
667330f729Sjoerg const auto &E = Expressions[C.getExpressionID()];
677330f729Sjoerg extractTerms(E.LHS, Factor, Terms);
687330f729Sjoerg extractTerms(
697330f729Sjoerg E.RHS, E.Kind == CounterExpression::Subtract ? -Factor : Factor, Terms);
707330f729Sjoerg break;
717330f729Sjoerg }
727330f729Sjoerg }
737330f729Sjoerg
simplify(Counter ExpressionTree)747330f729Sjoerg Counter CounterExpressionBuilder::simplify(Counter ExpressionTree) {
757330f729Sjoerg // Gather constant terms.
767330f729Sjoerg SmallVector<Term, 32> Terms;
777330f729Sjoerg extractTerms(ExpressionTree, +1, Terms);
787330f729Sjoerg
797330f729Sjoerg // If there are no terms, this is just a zero. The algorithm below assumes at
807330f729Sjoerg // least one term.
817330f729Sjoerg if (Terms.size() == 0)
827330f729Sjoerg return Counter::getZero();
837330f729Sjoerg
847330f729Sjoerg // Group the terms by counter ID.
857330f729Sjoerg llvm::sort(Terms, [](const Term &LHS, const Term &RHS) {
867330f729Sjoerg return LHS.CounterID < RHS.CounterID;
877330f729Sjoerg });
887330f729Sjoerg
897330f729Sjoerg // Combine terms by counter ID to eliminate counters that sum to zero.
907330f729Sjoerg auto Prev = Terms.begin();
917330f729Sjoerg for (auto I = Prev + 1, E = Terms.end(); I != E; ++I) {
927330f729Sjoerg if (I->CounterID == Prev->CounterID) {
937330f729Sjoerg Prev->Factor += I->Factor;
947330f729Sjoerg continue;
957330f729Sjoerg }
967330f729Sjoerg ++Prev;
977330f729Sjoerg *Prev = *I;
987330f729Sjoerg }
997330f729Sjoerg Terms.erase(++Prev, Terms.end());
1007330f729Sjoerg
1017330f729Sjoerg Counter C;
1027330f729Sjoerg // Create additions. We do this before subtractions to avoid constructs like
1037330f729Sjoerg // ((0 - X) + Y), as opposed to (Y - X).
1047330f729Sjoerg for (auto T : Terms) {
1057330f729Sjoerg if (T.Factor <= 0)
1067330f729Sjoerg continue;
1077330f729Sjoerg for (int I = 0; I < T.Factor; ++I)
1087330f729Sjoerg if (C.isZero())
1097330f729Sjoerg C = Counter::getCounter(T.CounterID);
1107330f729Sjoerg else
1117330f729Sjoerg C = get(CounterExpression(CounterExpression::Add, C,
1127330f729Sjoerg Counter::getCounter(T.CounterID)));
1137330f729Sjoerg }
1147330f729Sjoerg
1157330f729Sjoerg // Create subtractions.
1167330f729Sjoerg for (auto T : Terms) {
1177330f729Sjoerg if (T.Factor >= 0)
1187330f729Sjoerg continue;
1197330f729Sjoerg for (int I = 0; I < -T.Factor; ++I)
1207330f729Sjoerg C = get(CounterExpression(CounterExpression::Subtract, C,
1217330f729Sjoerg Counter::getCounter(T.CounterID)));
1227330f729Sjoerg }
1237330f729Sjoerg return C;
1247330f729Sjoerg }
1257330f729Sjoerg
add(Counter LHS,Counter RHS)1267330f729Sjoerg Counter CounterExpressionBuilder::add(Counter LHS, Counter RHS) {
1277330f729Sjoerg return simplify(get(CounterExpression(CounterExpression::Add, LHS, RHS)));
1287330f729Sjoerg }
1297330f729Sjoerg
subtract(Counter LHS,Counter RHS)1307330f729Sjoerg Counter CounterExpressionBuilder::subtract(Counter LHS, Counter RHS) {
1317330f729Sjoerg return simplify(
1327330f729Sjoerg get(CounterExpression(CounterExpression::Subtract, LHS, RHS)));
1337330f729Sjoerg }
1347330f729Sjoerg
dump(const Counter & C,raw_ostream & OS) const1357330f729Sjoerg void CounterMappingContext::dump(const Counter &C, raw_ostream &OS) const {
1367330f729Sjoerg switch (C.getKind()) {
1377330f729Sjoerg case Counter::Zero:
1387330f729Sjoerg OS << '0';
1397330f729Sjoerg return;
1407330f729Sjoerg case Counter::CounterValueReference:
1417330f729Sjoerg OS << '#' << C.getCounterID();
1427330f729Sjoerg break;
1437330f729Sjoerg case Counter::Expression: {
1447330f729Sjoerg if (C.getExpressionID() >= Expressions.size())
1457330f729Sjoerg return;
1467330f729Sjoerg const auto &E = Expressions[C.getExpressionID()];
1477330f729Sjoerg OS << '(';
1487330f729Sjoerg dump(E.LHS, OS);
1497330f729Sjoerg OS << (E.Kind == CounterExpression::Subtract ? " - " : " + ");
1507330f729Sjoerg dump(E.RHS, OS);
1517330f729Sjoerg OS << ')';
1527330f729Sjoerg break;
1537330f729Sjoerg }
1547330f729Sjoerg }
1557330f729Sjoerg if (CounterValues.empty())
1567330f729Sjoerg return;
1577330f729Sjoerg Expected<int64_t> Value = evaluate(C);
1587330f729Sjoerg if (auto E = Value.takeError()) {
1597330f729Sjoerg consumeError(std::move(E));
1607330f729Sjoerg return;
1617330f729Sjoerg }
1627330f729Sjoerg OS << '[' << *Value << ']';
1637330f729Sjoerg }
1647330f729Sjoerg
evaluate(const Counter & C) const1657330f729Sjoerg Expected<int64_t> CounterMappingContext::evaluate(const Counter &C) const {
1667330f729Sjoerg switch (C.getKind()) {
1677330f729Sjoerg case Counter::Zero:
1687330f729Sjoerg return 0;
1697330f729Sjoerg case Counter::CounterValueReference:
1707330f729Sjoerg if (C.getCounterID() >= CounterValues.size())
1717330f729Sjoerg return errorCodeToError(errc::argument_out_of_domain);
1727330f729Sjoerg return CounterValues[C.getCounterID()];
1737330f729Sjoerg case Counter::Expression: {
1747330f729Sjoerg if (C.getExpressionID() >= Expressions.size())
1757330f729Sjoerg return errorCodeToError(errc::argument_out_of_domain);
1767330f729Sjoerg const auto &E = Expressions[C.getExpressionID()];
1777330f729Sjoerg Expected<int64_t> LHS = evaluate(E.LHS);
1787330f729Sjoerg if (!LHS)
1797330f729Sjoerg return LHS;
1807330f729Sjoerg Expected<int64_t> RHS = evaluate(E.RHS);
1817330f729Sjoerg if (!RHS)
1827330f729Sjoerg return RHS;
1837330f729Sjoerg return E.Kind == CounterExpression::Subtract ? *LHS - *RHS : *LHS + *RHS;
1847330f729Sjoerg }
1857330f729Sjoerg }
1867330f729Sjoerg llvm_unreachable("Unhandled CounterKind");
1877330f729Sjoerg }
1887330f729Sjoerg
getMaxCounterID(const Counter & C) const189*82d56013Sjoerg unsigned CounterMappingContext::getMaxCounterID(const Counter &C) const {
190*82d56013Sjoerg switch (C.getKind()) {
191*82d56013Sjoerg case Counter::Zero:
192*82d56013Sjoerg return 0;
193*82d56013Sjoerg case Counter::CounterValueReference:
194*82d56013Sjoerg return C.getCounterID();
195*82d56013Sjoerg case Counter::Expression: {
196*82d56013Sjoerg if (C.getExpressionID() >= Expressions.size())
197*82d56013Sjoerg return 0;
198*82d56013Sjoerg const auto &E = Expressions[C.getExpressionID()];
199*82d56013Sjoerg return std::max(getMaxCounterID(E.LHS), getMaxCounterID(E.RHS));
200*82d56013Sjoerg }
201*82d56013Sjoerg }
202*82d56013Sjoerg llvm_unreachable("Unhandled CounterKind");
203*82d56013Sjoerg }
204*82d56013Sjoerg
skipOtherFiles()2057330f729Sjoerg void FunctionRecordIterator::skipOtherFiles() {
2067330f729Sjoerg while (Current != Records.end() && !Filename.empty() &&
2077330f729Sjoerg Filename != Current->Filenames[0])
2087330f729Sjoerg ++Current;
2097330f729Sjoerg if (Current == Records.end())
2107330f729Sjoerg *this = FunctionRecordIterator();
2117330f729Sjoerg }
2127330f729Sjoerg
getImpreciseRecordIndicesForFilename(StringRef Filename) const2137330f729Sjoerg ArrayRef<unsigned> CoverageMapping::getImpreciseRecordIndicesForFilename(
2147330f729Sjoerg StringRef Filename) const {
2157330f729Sjoerg size_t FilenameHash = hash_value(Filename);
2167330f729Sjoerg auto RecordIt = FilenameHash2RecordIndices.find(FilenameHash);
2177330f729Sjoerg if (RecordIt == FilenameHash2RecordIndices.end())
2187330f729Sjoerg return {};
2197330f729Sjoerg return RecordIt->second;
2207330f729Sjoerg }
2217330f729Sjoerg
getMaxCounterID(const CounterMappingContext & Ctx,const CoverageMappingRecord & Record)222*82d56013Sjoerg static unsigned getMaxCounterID(const CounterMappingContext &Ctx,
223*82d56013Sjoerg const CoverageMappingRecord &Record) {
224*82d56013Sjoerg unsigned MaxCounterID = 0;
225*82d56013Sjoerg for (const auto &Region : Record.MappingRegions) {
226*82d56013Sjoerg MaxCounterID = std::max(MaxCounterID, Ctx.getMaxCounterID(Region.Count));
227*82d56013Sjoerg }
228*82d56013Sjoerg return MaxCounterID;
229*82d56013Sjoerg }
230*82d56013Sjoerg
loadFunctionRecord(const CoverageMappingRecord & Record,IndexedInstrProfReader & ProfileReader)2317330f729Sjoerg Error CoverageMapping::loadFunctionRecord(
2327330f729Sjoerg const CoverageMappingRecord &Record,
2337330f729Sjoerg IndexedInstrProfReader &ProfileReader) {
2347330f729Sjoerg StringRef OrigFuncName = Record.FunctionName;
2357330f729Sjoerg if (OrigFuncName.empty())
2367330f729Sjoerg return make_error<CoverageMapError>(coveragemap_error::malformed);
2377330f729Sjoerg
2387330f729Sjoerg if (Record.Filenames.empty())
2397330f729Sjoerg OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName);
2407330f729Sjoerg else
2417330f729Sjoerg OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]);
2427330f729Sjoerg
2437330f729Sjoerg CounterMappingContext Ctx(Record.Expressions);
2447330f729Sjoerg
2457330f729Sjoerg std::vector<uint64_t> Counts;
2467330f729Sjoerg if (Error E = ProfileReader.getFunctionCounts(Record.FunctionName,
2477330f729Sjoerg Record.FunctionHash, Counts)) {
2487330f729Sjoerg instrprof_error IPE = InstrProfError::take(std::move(E));
2497330f729Sjoerg if (IPE == instrprof_error::hash_mismatch) {
250*82d56013Sjoerg FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
251*82d56013Sjoerg Record.FunctionHash);
2527330f729Sjoerg return Error::success();
2537330f729Sjoerg } else if (IPE != instrprof_error::unknown_function)
2547330f729Sjoerg return make_error<InstrProfError>(IPE);
255*82d56013Sjoerg Counts.assign(getMaxCounterID(Ctx, Record) + 1, 0);
2567330f729Sjoerg }
2577330f729Sjoerg Ctx.setCounts(Counts);
2587330f729Sjoerg
2597330f729Sjoerg assert(!Record.MappingRegions.empty() && "Function has no regions");
2607330f729Sjoerg
2617330f729Sjoerg // This coverage record is a zero region for a function that's unused in
2627330f729Sjoerg // some TU, but used in a different TU. Ignore it. The coverage maps from the
2637330f729Sjoerg // the other TU will either be loaded (providing full region counts) or they
2647330f729Sjoerg // won't (in which case we don't unintuitively report functions as uncovered
2657330f729Sjoerg // when they have non-zero counts in the profile).
2667330f729Sjoerg if (Record.MappingRegions.size() == 1 &&
2677330f729Sjoerg Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
2687330f729Sjoerg return Error::success();
2697330f729Sjoerg
2707330f729Sjoerg FunctionRecord Function(OrigFuncName, Record.Filenames);
2717330f729Sjoerg for (const auto &Region : Record.MappingRegions) {
2727330f729Sjoerg Expected<int64_t> ExecutionCount = Ctx.evaluate(Region.Count);
2737330f729Sjoerg if (auto E = ExecutionCount.takeError()) {
2747330f729Sjoerg consumeError(std::move(E));
2757330f729Sjoerg return Error::success();
2767330f729Sjoerg }
277*82d56013Sjoerg Expected<int64_t> AltExecutionCount = Ctx.evaluate(Region.FalseCount);
278*82d56013Sjoerg if (auto E = AltExecutionCount.takeError()) {
279*82d56013Sjoerg consumeError(std::move(E));
280*82d56013Sjoerg return Error::success();
281*82d56013Sjoerg }
282*82d56013Sjoerg Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount);
2837330f729Sjoerg }
2847330f729Sjoerg
2857330f729Sjoerg // Don't create records for (filenames, function) pairs we've already seen.
2867330f729Sjoerg auto FilenamesHash = hash_combine_range(Record.Filenames.begin(),
2877330f729Sjoerg Record.Filenames.end());
2887330f729Sjoerg if (!RecordProvenance[FilenamesHash].insert(hash_value(OrigFuncName)).second)
2897330f729Sjoerg return Error::success();
2907330f729Sjoerg
2917330f729Sjoerg Functions.push_back(std::move(Function));
2927330f729Sjoerg
2937330f729Sjoerg // Performance optimization: keep track of the indices of the function records
2947330f729Sjoerg // which correspond to each filename. This can be used to substantially speed
2957330f729Sjoerg // up queries for coverage info in a file.
2967330f729Sjoerg unsigned RecordIndex = Functions.size() - 1;
2977330f729Sjoerg for (StringRef Filename : Record.Filenames) {
2987330f729Sjoerg auto &RecordIndices = FilenameHash2RecordIndices[hash_value(Filename)];
2997330f729Sjoerg // Note that there may be duplicates in the filename set for a function
3007330f729Sjoerg // record, because of e.g. macro expansions in the function in which both
3017330f729Sjoerg // the macro and the function are defined in the same file.
3027330f729Sjoerg if (RecordIndices.empty() || RecordIndices.back() != RecordIndex)
3037330f729Sjoerg RecordIndices.push_back(RecordIndex);
3047330f729Sjoerg }
3057330f729Sjoerg
3067330f729Sjoerg return Error::success();
3077330f729Sjoerg }
3087330f729Sjoerg
309*82d56013Sjoerg // This function is for memory optimization by shortening the lifetimes
310*82d56013Sjoerg // of CoverageMappingReader instances.
loadFromReaders(ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,IndexedInstrProfReader & ProfileReader,CoverageMapping & Coverage)311*82d56013Sjoerg Error CoverageMapping::loadFromReaders(
312*82d56013Sjoerg ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
313*82d56013Sjoerg IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage) {
314*82d56013Sjoerg for (const auto &CoverageReader : CoverageReaders) {
315*82d56013Sjoerg for (auto RecordOrErr : *CoverageReader) {
316*82d56013Sjoerg if (Error E = RecordOrErr.takeError())
317*82d56013Sjoerg return E;
318*82d56013Sjoerg const auto &Record = *RecordOrErr;
319*82d56013Sjoerg if (Error E = Coverage.loadFunctionRecord(Record, ProfileReader))
320*82d56013Sjoerg return E;
321*82d56013Sjoerg }
322*82d56013Sjoerg }
323*82d56013Sjoerg return Error::success();
324*82d56013Sjoerg }
325*82d56013Sjoerg
load(ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,IndexedInstrProfReader & ProfileReader)3267330f729Sjoerg Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
3277330f729Sjoerg ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
3287330f729Sjoerg IndexedInstrProfReader &ProfileReader) {
3297330f729Sjoerg auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
330*82d56013Sjoerg if (Error E = loadFromReaders(CoverageReaders, ProfileReader, *Coverage))
3317330f729Sjoerg return std::move(E);
3327330f729Sjoerg return std::move(Coverage);
3337330f729Sjoerg }
3347330f729Sjoerg
3357330f729Sjoerg // If E is a no_data_found error, returns success. Otherwise returns E.
handleMaybeNoDataFoundError(Error E)3367330f729Sjoerg static Error handleMaybeNoDataFoundError(Error E) {
3377330f729Sjoerg return handleErrors(
3387330f729Sjoerg std::move(E), [](const CoverageMapError &CME) {
3397330f729Sjoerg if (CME.get() == coveragemap_error::no_data_found)
3407330f729Sjoerg return static_cast<Error>(Error::success());
3417330f729Sjoerg return make_error<CoverageMapError>(CME.get());
3427330f729Sjoerg });
3437330f729Sjoerg }
3447330f729Sjoerg
3457330f729Sjoerg Expected<std::unique_ptr<CoverageMapping>>
load(ArrayRef<StringRef> ObjectFilenames,StringRef ProfileFilename,ArrayRef<StringRef> Arches,StringRef CompilationDir)3467330f729Sjoerg CoverageMapping::load(ArrayRef<StringRef> ObjectFilenames,
347*82d56013Sjoerg StringRef ProfileFilename, ArrayRef<StringRef> Arches,
348*82d56013Sjoerg StringRef CompilationDir) {
3497330f729Sjoerg auto ProfileReaderOrErr = IndexedInstrProfReader::create(ProfileFilename);
3507330f729Sjoerg if (Error E = ProfileReaderOrErr.takeError())
3517330f729Sjoerg return std::move(E);
3527330f729Sjoerg auto ProfileReader = std::move(ProfileReaderOrErr.get());
353*82d56013Sjoerg auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
354*82d56013Sjoerg bool DataFound = false;
3557330f729Sjoerg
3567330f729Sjoerg for (const auto &File : llvm::enumerate(ObjectFilenames)) {
357*82d56013Sjoerg auto CovMappingBufOrErr = MemoryBuffer::getFileOrSTDIN(
358*82d56013Sjoerg File.value(), /*IsText=*/false, /*RequiresNullTerminator=*/false);
3597330f729Sjoerg if (std::error_code EC = CovMappingBufOrErr.getError())
3607330f729Sjoerg return errorCodeToError(EC);
3617330f729Sjoerg StringRef Arch = Arches.empty() ? StringRef() : Arches[File.index()];
3627330f729Sjoerg MemoryBufferRef CovMappingBufRef =
3637330f729Sjoerg CovMappingBufOrErr.get()->getMemBufferRef();
364*82d56013Sjoerg SmallVector<std::unique_ptr<MemoryBuffer>, 4> Buffers;
365*82d56013Sjoerg auto CoverageReadersOrErr = BinaryCoverageReader::create(
366*82d56013Sjoerg CovMappingBufRef, Arch, Buffers, CompilationDir);
3677330f729Sjoerg if (Error E = CoverageReadersOrErr.takeError()) {
3687330f729Sjoerg E = handleMaybeNoDataFoundError(std::move(E));
3697330f729Sjoerg if (E)
3707330f729Sjoerg return std::move(E);
3717330f729Sjoerg // E == success (originally a no_data_found error).
3727330f729Sjoerg continue;
3737330f729Sjoerg }
374*82d56013Sjoerg
375*82d56013Sjoerg SmallVector<std::unique_ptr<CoverageMappingReader>, 4> Readers;
3767330f729Sjoerg for (auto &Reader : CoverageReadersOrErr.get())
3777330f729Sjoerg Readers.push_back(std::move(Reader));
378*82d56013Sjoerg DataFound |= !Readers.empty();
379*82d56013Sjoerg if (Error E = loadFromReaders(Readers, *ProfileReader, *Coverage))
380*82d56013Sjoerg return std::move(E);
3817330f729Sjoerg }
3827330f729Sjoerg // If no readers were created, either no objects were provided or none of them
3837330f729Sjoerg // had coverage data. Return an error in the latter case.
384*82d56013Sjoerg if (!DataFound && !ObjectFilenames.empty())
3857330f729Sjoerg return make_error<CoverageMapError>(coveragemap_error::no_data_found);
386*82d56013Sjoerg return std::move(Coverage);
3877330f729Sjoerg }
3887330f729Sjoerg
3897330f729Sjoerg namespace {
3907330f729Sjoerg
3917330f729Sjoerg /// Distributes functions into instantiation sets.
3927330f729Sjoerg ///
3937330f729Sjoerg /// An instantiation set is a collection of functions that have the same source
3947330f729Sjoerg /// code, ie, template functions specializations.
3957330f729Sjoerg class FunctionInstantiationSetCollector {
3967330f729Sjoerg using MapT = std::map<LineColPair, std::vector<const FunctionRecord *>>;
3977330f729Sjoerg MapT InstantiatedFunctions;
3987330f729Sjoerg
3997330f729Sjoerg public:
insert(const FunctionRecord & Function,unsigned FileID)4007330f729Sjoerg void insert(const FunctionRecord &Function, unsigned FileID) {
4017330f729Sjoerg auto I = Function.CountedRegions.begin(), E = Function.CountedRegions.end();
4027330f729Sjoerg while (I != E && I->FileID != FileID)
4037330f729Sjoerg ++I;
4047330f729Sjoerg assert(I != E && "function does not cover the given file");
4057330f729Sjoerg auto &Functions = InstantiatedFunctions[I->startLoc()];
4067330f729Sjoerg Functions.push_back(&Function);
4077330f729Sjoerg }
4087330f729Sjoerg
begin()4097330f729Sjoerg MapT::iterator begin() { return InstantiatedFunctions.begin(); }
end()4107330f729Sjoerg MapT::iterator end() { return InstantiatedFunctions.end(); }
4117330f729Sjoerg };
4127330f729Sjoerg
4137330f729Sjoerg class SegmentBuilder {
4147330f729Sjoerg std::vector<CoverageSegment> &Segments;
4157330f729Sjoerg SmallVector<const CountedRegion *, 8> ActiveRegions;
4167330f729Sjoerg
SegmentBuilder(std::vector<CoverageSegment> & Segments)4177330f729Sjoerg SegmentBuilder(std::vector<CoverageSegment> &Segments) : Segments(Segments) {}
4187330f729Sjoerg
4197330f729Sjoerg /// Emit a segment with the count from \p Region starting at \p StartLoc.
4207330f729Sjoerg //
4217330f729Sjoerg /// \p IsRegionEntry: The segment is at the start of a new non-gap region.
4227330f729Sjoerg /// \p EmitSkippedRegion: The segment must be emitted as a skipped region.
startSegment(const CountedRegion & Region,LineColPair StartLoc,bool IsRegionEntry,bool EmitSkippedRegion=false)4237330f729Sjoerg void startSegment(const CountedRegion &Region, LineColPair StartLoc,
4247330f729Sjoerg bool IsRegionEntry, bool EmitSkippedRegion = false) {
4257330f729Sjoerg bool HasCount = !EmitSkippedRegion &&
4267330f729Sjoerg (Region.Kind != CounterMappingRegion::SkippedRegion);
4277330f729Sjoerg
4287330f729Sjoerg // If the new segment wouldn't affect coverage rendering, skip it.
4297330f729Sjoerg if (!Segments.empty() && !IsRegionEntry && !EmitSkippedRegion) {
4307330f729Sjoerg const auto &Last = Segments.back();
4317330f729Sjoerg if (Last.HasCount == HasCount && Last.Count == Region.ExecutionCount &&
4327330f729Sjoerg !Last.IsRegionEntry)
4337330f729Sjoerg return;
4347330f729Sjoerg }
4357330f729Sjoerg
4367330f729Sjoerg if (HasCount)
4377330f729Sjoerg Segments.emplace_back(StartLoc.first, StartLoc.second,
4387330f729Sjoerg Region.ExecutionCount, IsRegionEntry,
4397330f729Sjoerg Region.Kind == CounterMappingRegion::GapRegion);
4407330f729Sjoerg else
4417330f729Sjoerg Segments.emplace_back(StartLoc.first, StartLoc.second, IsRegionEntry);
4427330f729Sjoerg
4437330f729Sjoerg LLVM_DEBUG({
4447330f729Sjoerg const auto &Last = Segments.back();
4457330f729Sjoerg dbgs() << "Segment at " << Last.Line << ":" << Last.Col
4467330f729Sjoerg << " (count = " << Last.Count << ")"
4477330f729Sjoerg << (Last.IsRegionEntry ? ", RegionEntry" : "")
4487330f729Sjoerg << (!Last.HasCount ? ", Skipped" : "")
4497330f729Sjoerg << (Last.IsGapRegion ? ", Gap" : "") << "\n";
4507330f729Sjoerg });
4517330f729Sjoerg }
4527330f729Sjoerg
4537330f729Sjoerg /// Emit segments for active regions which end before \p Loc.
4547330f729Sjoerg ///
4557330f729Sjoerg /// \p Loc: The start location of the next region. If None, all active
4567330f729Sjoerg /// regions are completed.
4577330f729Sjoerg /// \p FirstCompletedRegion: Index of the first completed region.
completeRegionsUntil(Optional<LineColPair> Loc,unsigned FirstCompletedRegion)4587330f729Sjoerg void completeRegionsUntil(Optional<LineColPair> Loc,
4597330f729Sjoerg unsigned FirstCompletedRegion) {
4607330f729Sjoerg // Sort the completed regions by end location. This makes it simple to
4617330f729Sjoerg // emit closing segments in sorted order.
4627330f729Sjoerg auto CompletedRegionsIt = ActiveRegions.begin() + FirstCompletedRegion;
4637330f729Sjoerg std::stable_sort(CompletedRegionsIt, ActiveRegions.end(),
4647330f729Sjoerg [](const CountedRegion *L, const CountedRegion *R) {
4657330f729Sjoerg return L->endLoc() < R->endLoc();
4667330f729Sjoerg });
4677330f729Sjoerg
4687330f729Sjoerg // Emit segments for all completed regions.
4697330f729Sjoerg for (unsigned I = FirstCompletedRegion + 1, E = ActiveRegions.size(); I < E;
4707330f729Sjoerg ++I) {
4717330f729Sjoerg const auto *CompletedRegion = ActiveRegions[I];
4727330f729Sjoerg assert((!Loc || CompletedRegion->endLoc() <= *Loc) &&
4737330f729Sjoerg "Completed region ends after start of new region");
4747330f729Sjoerg
4757330f729Sjoerg const auto *PrevCompletedRegion = ActiveRegions[I - 1];
4767330f729Sjoerg auto CompletedSegmentLoc = PrevCompletedRegion->endLoc();
4777330f729Sjoerg
4787330f729Sjoerg // Don't emit any more segments if they start where the new region begins.
4797330f729Sjoerg if (Loc && CompletedSegmentLoc == *Loc)
4807330f729Sjoerg break;
4817330f729Sjoerg
4827330f729Sjoerg // Don't emit a segment if the next completed region ends at the same
4837330f729Sjoerg // location as this one.
4847330f729Sjoerg if (CompletedSegmentLoc == CompletedRegion->endLoc())
4857330f729Sjoerg continue;
4867330f729Sjoerg
4877330f729Sjoerg // Use the count from the last completed region which ends at this loc.
4887330f729Sjoerg for (unsigned J = I + 1; J < E; ++J)
4897330f729Sjoerg if (CompletedRegion->endLoc() == ActiveRegions[J]->endLoc())
4907330f729Sjoerg CompletedRegion = ActiveRegions[J];
4917330f729Sjoerg
4927330f729Sjoerg startSegment(*CompletedRegion, CompletedSegmentLoc, false);
4937330f729Sjoerg }
4947330f729Sjoerg
4957330f729Sjoerg auto Last = ActiveRegions.back();
4967330f729Sjoerg if (FirstCompletedRegion && Last->endLoc() != *Loc) {
4977330f729Sjoerg // If there's a gap after the end of the last completed region and the
4987330f729Sjoerg // start of the new region, use the last active region to fill the gap.
4997330f729Sjoerg startSegment(*ActiveRegions[FirstCompletedRegion - 1], Last->endLoc(),
5007330f729Sjoerg false);
5017330f729Sjoerg } else if (!FirstCompletedRegion && (!Loc || *Loc != Last->endLoc())) {
5027330f729Sjoerg // Emit a skipped segment if there are no more active regions. This
5037330f729Sjoerg // ensures that gaps between functions are marked correctly.
5047330f729Sjoerg startSegment(*Last, Last->endLoc(), false, true);
5057330f729Sjoerg }
5067330f729Sjoerg
5077330f729Sjoerg // Pop the completed regions.
5087330f729Sjoerg ActiveRegions.erase(CompletedRegionsIt, ActiveRegions.end());
5097330f729Sjoerg }
5107330f729Sjoerg
buildSegmentsImpl(ArrayRef<CountedRegion> Regions)5117330f729Sjoerg void buildSegmentsImpl(ArrayRef<CountedRegion> Regions) {
5127330f729Sjoerg for (const auto &CR : enumerate(Regions)) {
5137330f729Sjoerg auto CurStartLoc = CR.value().startLoc();
5147330f729Sjoerg
5157330f729Sjoerg // Active regions which end before the current region need to be popped.
5167330f729Sjoerg auto CompletedRegions =
5177330f729Sjoerg std::stable_partition(ActiveRegions.begin(), ActiveRegions.end(),
5187330f729Sjoerg [&](const CountedRegion *Region) {
5197330f729Sjoerg return !(Region->endLoc() <= CurStartLoc);
5207330f729Sjoerg });
5217330f729Sjoerg if (CompletedRegions != ActiveRegions.end()) {
5227330f729Sjoerg unsigned FirstCompletedRegion =
5237330f729Sjoerg std::distance(ActiveRegions.begin(), CompletedRegions);
5247330f729Sjoerg completeRegionsUntil(CurStartLoc, FirstCompletedRegion);
5257330f729Sjoerg }
5267330f729Sjoerg
5277330f729Sjoerg bool GapRegion = CR.value().Kind == CounterMappingRegion::GapRegion;
5287330f729Sjoerg
5297330f729Sjoerg // Try to emit a segment for the current region.
5307330f729Sjoerg if (CurStartLoc == CR.value().endLoc()) {
5317330f729Sjoerg // Avoid making zero-length regions active. If it's the last region,
5327330f729Sjoerg // emit a skipped segment. Otherwise use its predecessor's count.
533*82d56013Sjoerg const bool Skipped =
534*82d56013Sjoerg (CR.index() + 1) == Regions.size() ||
535*82d56013Sjoerg CR.value().Kind == CounterMappingRegion::SkippedRegion;
5367330f729Sjoerg startSegment(ActiveRegions.empty() ? CR.value() : *ActiveRegions.back(),
5377330f729Sjoerg CurStartLoc, !GapRegion, Skipped);
538*82d56013Sjoerg // If it is skipped segment, create a segment with last pushed
539*82d56013Sjoerg // regions's count at CurStartLoc.
540*82d56013Sjoerg if (Skipped && !ActiveRegions.empty())
541*82d56013Sjoerg startSegment(*ActiveRegions.back(), CurStartLoc, false);
5427330f729Sjoerg continue;
5437330f729Sjoerg }
5447330f729Sjoerg if (CR.index() + 1 == Regions.size() ||
5457330f729Sjoerg CurStartLoc != Regions[CR.index() + 1].startLoc()) {
5467330f729Sjoerg // Emit a segment if the next region doesn't start at the same location
5477330f729Sjoerg // as this one.
5487330f729Sjoerg startSegment(CR.value(), CurStartLoc, !GapRegion);
5497330f729Sjoerg }
5507330f729Sjoerg
5517330f729Sjoerg // This region is active (i.e not completed).
5527330f729Sjoerg ActiveRegions.push_back(&CR.value());
5537330f729Sjoerg }
5547330f729Sjoerg
5557330f729Sjoerg // Complete any remaining active regions.
5567330f729Sjoerg if (!ActiveRegions.empty())
5577330f729Sjoerg completeRegionsUntil(None, 0);
5587330f729Sjoerg }
5597330f729Sjoerg
5607330f729Sjoerg /// Sort a nested sequence of regions from a single file.
sortNestedRegions(MutableArrayRef<CountedRegion> Regions)5617330f729Sjoerg static void sortNestedRegions(MutableArrayRef<CountedRegion> Regions) {
5627330f729Sjoerg llvm::sort(Regions, [](const CountedRegion &LHS, const CountedRegion &RHS) {
5637330f729Sjoerg if (LHS.startLoc() != RHS.startLoc())
5647330f729Sjoerg return LHS.startLoc() < RHS.startLoc();
5657330f729Sjoerg if (LHS.endLoc() != RHS.endLoc())
5667330f729Sjoerg // When LHS completely contains RHS, we sort LHS first.
5677330f729Sjoerg return RHS.endLoc() < LHS.endLoc();
5687330f729Sjoerg // If LHS and RHS cover the same area, we need to sort them according
5697330f729Sjoerg // to their kinds so that the most suitable region will become "active"
5707330f729Sjoerg // in combineRegions(). Because we accumulate counter values only from
5717330f729Sjoerg // regions of the same kind as the first region of the area, prefer
5727330f729Sjoerg // CodeRegion to ExpansionRegion and ExpansionRegion to SkippedRegion.
5737330f729Sjoerg static_assert(CounterMappingRegion::CodeRegion <
5747330f729Sjoerg CounterMappingRegion::ExpansionRegion &&
5757330f729Sjoerg CounterMappingRegion::ExpansionRegion <
5767330f729Sjoerg CounterMappingRegion::SkippedRegion,
5777330f729Sjoerg "Unexpected order of region kind values");
5787330f729Sjoerg return LHS.Kind < RHS.Kind;
5797330f729Sjoerg });
5807330f729Sjoerg }
5817330f729Sjoerg
5827330f729Sjoerg /// Combine counts of regions which cover the same area.
5837330f729Sjoerg static ArrayRef<CountedRegion>
combineRegions(MutableArrayRef<CountedRegion> Regions)5847330f729Sjoerg combineRegions(MutableArrayRef<CountedRegion> Regions) {
5857330f729Sjoerg if (Regions.empty())
5867330f729Sjoerg return Regions;
5877330f729Sjoerg auto Active = Regions.begin();
5887330f729Sjoerg auto End = Regions.end();
5897330f729Sjoerg for (auto I = Regions.begin() + 1; I != End; ++I) {
5907330f729Sjoerg if (Active->startLoc() != I->startLoc() ||
5917330f729Sjoerg Active->endLoc() != I->endLoc()) {
5927330f729Sjoerg // Shift to the next region.
5937330f729Sjoerg ++Active;
5947330f729Sjoerg if (Active != I)
5957330f729Sjoerg *Active = *I;
5967330f729Sjoerg continue;
5977330f729Sjoerg }
5987330f729Sjoerg // Merge duplicate region.
5997330f729Sjoerg // If CodeRegions and ExpansionRegions cover the same area, it's probably
6007330f729Sjoerg // a macro which is fully expanded to another macro. In that case, we need
6017330f729Sjoerg // to accumulate counts only from CodeRegions, or else the area will be
6027330f729Sjoerg // counted twice.
6037330f729Sjoerg // On the other hand, a macro may have a nested macro in its body. If the
6047330f729Sjoerg // outer macro is used several times, the ExpansionRegion for the nested
6057330f729Sjoerg // macro will also be added several times. These ExpansionRegions cover
6067330f729Sjoerg // the same source locations and have to be combined to reach the correct
6077330f729Sjoerg // value for that area.
6087330f729Sjoerg // We add counts of the regions of the same kind as the active region
6097330f729Sjoerg // to handle the both situations.
6107330f729Sjoerg if (I->Kind == Active->Kind)
6117330f729Sjoerg Active->ExecutionCount += I->ExecutionCount;
6127330f729Sjoerg }
6137330f729Sjoerg return Regions.drop_back(std::distance(++Active, End));
6147330f729Sjoerg }
6157330f729Sjoerg
6167330f729Sjoerg public:
6177330f729Sjoerg /// Build a sorted list of CoverageSegments from a list of Regions.
6187330f729Sjoerg static std::vector<CoverageSegment>
buildSegments(MutableArrayRef<CountedRegion> Regions)6197330f729Sjoerg buildSegments(MutableArrayRef<CountedRegion> Regions) {
6207330f729Sjoerg std::vector<CoverageSegment> Segments;
6217330f729Sjoerg SegmentBuilder Builder(Segments);
6227330f729Sjoerg
6237330f729Sjoerg sortNestedRegions(Regions);
6247330f729Sjoerg ArrayRef<CountedRegion> CombinedRegions = combineRegions(Regions);
6257330f729Sjoerg
6267330f729Sjoerg LLVM_DEBUG({
6277330f729Sjoerg dbgs() << "Combined regions:\n";
6287330f729Sjoerg for (const auto &CR : CombinedRegions)
6297330f729Sjoerg dbgs() << " " << CR.LineStart << ":" << CR.ColumnStart << " -> "
6307330f729Sjoerg << CR.LineEnd << ":" << CR.ColumnEnd
6317330f729Sjoerg << " (count=" << CR.ExecutionCount << ")\n";
6327330f729Sjoerg });
6337330f729Sjoerg
6347330f729Sjoerg Builder.buildSegmentsImpl(CombinedRegions);
6357330f729Sjoerg
6367330f729Sjoerg #ifndef NDEBUG
6377330f729Sjoerg for (unsigned I = 1, E = Segments.size(); I < E; ++I) {
6387330f729Sjoerg const auto &L = Segments[I - 1];
6397330f729Sjoerg const auto &R = Segments[I];
6407330f729Sjoerg if (!(L.Line < R.Line) && !(L.Line == R.Line && L.Col < R.Col)) {
641*82d56013Sjoerg if (L.Line == R.Line && L.Col == R.Col && !L.HasCount)
642*82d56013Sjoerg continue;
6437330f729Sjoerg LLVM_DEBUG(dbgs() << " ! Segment " << L.Line << ":" << L.Col
6447330f729Sjoerg << " followed by " << R.Line << ":" << R.Col << "\n");
6457330f729Sjoerg assert(false && "Coverage segments not unique or sorted");
6467330f729Sjoerg }
6477330f729Sjoerg }
6487330f729Sjoerg #endif
6497330f729Sjoerg
6507330f729Sjoerg return Segments;
6517330f729Sjoerg }
6527330f729Sjoerg };
6537330f729Sjoerg
6547330f729Sjoerg } // end anonymous namespace
6557330f729Sjoerg
getUniqueSourceFiles() const6567330f729Sjoerg std::vector<StringRef> CoverageMapping::getUniqueSourceFiles() const {
6577330f729Sjoerg std::vector<StringRef> Filenames;
6587330f729Sjoerg for (const auto &Function : getCoveredFunctions())
659*82d56013Sjoerg llvm::append_range(Filenames, Function.Filenames);
6607330f729Sjoerg llvm::sort(Filenames);
6617330f729Sjoerg auto Last = std::unique(Filenames.begin(), Filenames.end());
6627330f729Sjoerg Filenames.erase(Last, Filenames.end());
6637330f729Sjoerg return Filenames;
6647330f729Sjoerg }
6657330f729Sjoerg
gatherFileIDs(StringRef SourceFile,const FunctionRecord & Function)6667330f729Sjoerg static SmallBitVector gatherFileIDs(StringRef SourceFile,
6677330f729Sjoerg const FunctionRecord &Function) {
6687330f729Sjoerg SmallBitVector FilenameEquivalence(Function.Filenames.size(), false);
6697330f729Sjoerg for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I)
6707330f729Sjoerg if (SourceFile == Function.Filenames[I])
6717330f729Sjoerg FilenameEquivalence[I] = true;
6727330f729Sjoerg return FilenameEquivalence;
6737330f729Sjoerg }
6747330f729Sjoerg
6757330f729Sjoerg /// Return the ID of the file where the definition of the function is located.
findMainViewFileID(const FunctionRecord & Function)6767330f729Sjoerg static Optional<unsigned> findMainViewFileID(const FunctionRecord &Function) {
6777330f729Sjoerg SmallBitVector IsNotExpandedFile(Function.Filenames.size(), true);
6787330f729Sjoerg for (const auto &CR : Function.CountedRegions)
6797330f729Sjoerg if (CR.Kind == CounterMappingRegion::ExpansionRegion)
6807330f729Sjoerg IsNotExpandedFile[CR.ExpandedFileID] = false;
6817330f729Sjoerg int I = IsNotExpandedFile.find_first();
6827330f729Sjoerg if (I == -1)
6837330f729Sjoerg return None;
6847330f729Sjoerg return I;
6857330f729Sjoerg }
6867330f729Sjoerg
6877330f729Sjoerg /// Check if SourceFile is the file that contains the definition of
6887330f729Sjoerg /// the Function. Return the ID of the file in that case or None otherwise.
findMainViewFileID(StringRef SourceFile,const FunctionRecord & Function)6897330f729Sjoerg static Optional<unsigned> findMainViewFileID(StringRef SourceFile,
6907330f729Sjoerg const FunctionRecord &Function) {
6917330f729Sjoerg Optional<unsigned> I = findMainViewFileID(Function);
6927330f729Sjoerg if (I && SourceFile == Function.Filenames[*I])
6937330f729Sjoerg return I;
6947330f729Sjoerg return None;
6957330f729Sjoerg }
6967330f729Sjoerg
isExpansion(const CountedRegion & R,unsigned FileID)6977330f729Sjoerg static bool isExpansion(const CountedRegion &R, unsigned FileID) {
6987330f729Sjoerg return R.Kind == CounterMappingRegion::ExpansionRegion && R.FileID == FileID;
6997330f729Sjoerg }
7007330f729Sjoerg
getCoverageForFile(StringRef Filename) const7017330f729Sjoerg CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
7027330f729Sjoerg CoverageData FileCoverage(Filename);
7037330f729Sjoerg std::vector<CountedRegion> Regions;
7047330f729Sjoerg
7057330f729Sjoerg // Look up the function records in the given file. Due to hash collisions on
7067330f729Sjoerg // the filename, we may get back some records that are not in the file.
7077330f729Sjoerg ArrayRef<unsigned> RecordIndices =
7087330f729Sjoerg getImpreciseRecordIndicesForFilename(Filename);
7097330f729Sjoerg for (unsigned RecordIndex : RecordIndices) {
7107330f729Sjoerg const FunctionRecord &Function = Functions[RecordIndex];
7117330f729Sjoerg auto MainFileID = findMainViewFileID(Filename, Function);
7127330f729Sjoerg auto FileIDs = gatherFileIDs(Filename, Function);
7137330f729Sjoerg for (const auto &CR : Function.CountedRegions)
7147330f729Sjoerg if (FileIDs.test(CR.FileID)) {
7157330f729Sjoerg Regions.push_back(CR);
7167330f729Sjoerg if (MainFileID && isExpansion(CR, *MainFileID))
7177330f729Sjoerg FileCoverage.Expansions.emplace_back(CR, Function);
7187330f729Sjoerg }
719*82d56013Sjoerg // Capture branch regions specific to the function (excluding expansions).
720*82d56013Sjoerg for (const auto &CR : Function.CountedBranchRegions)
721*82d56013Sjoerg if (FileIDs.test(CR.FileID) && (CR.FileID == CR.ExpandedFileID))
722*82d56013Sjoerg FileCoverage.BranchRegions.push_back(CR);
7237330f729Sjoerg }
7247330f729Sjoerg
7257330f729Sjoerg LLVM_DEBUG(dbgs() << "Emitting segments for file: " << Filename << "\n");
7267330f729Sjoerg FileCoverage.Segments = SegmentBuilder::buildSegments(Regions);
7277330f729Sjoerg
7287330f729Sjoerg return FileCoverage;
7297330f729Sjoerg }
7307330f729Sjoerg
7317330f729Sjoerg std::vector<InstantiationGroup>
getInstantiationGroups(StringRef Filename) const7327330f729Sjoerg CoverageMapping::getInstantiationGroups(StringRef Filename) const {
7337330f729Sjoerg FunctionInstantiationSetCollector InstantiationSetCollector;
7347330f729Sjoerg // Look up the function records in the given file. Due to hash collisions on
7357330f729Sjoerg // the filename, we may get back some records that are not in the file.
7367330f729Sjoerg ArrayRef<unsigned> RecordIndices =
7377330f729Sjoerg getImpreciseRecordIndicesForFilename(Filename);
7387330f729Sjoerg for (unsigned RecordIndex : RecordIndices) {
7397330f729Sjoerg const FunctionRecord &Function = Functions[RecordIndex];
7407330f729Sjoerg auto MainFileID = findMainViewFileID(Filename, Function);
7417330f729Sjoerg if (!MainFileID)
7427330f729Sjoerg continue;
7437330f729Sjoerg InstantiationSetCollector.insert(Function, *MainFileID);
7447330f729Sjoerg }
7457330f729Sjoerg
7467330f729Sjoerg std::vector<InstantiationGroup> Result;
7477330f729Sjoerg for (auto &InstantiationSet : InstantiationSetCollector) {
7487330f729Sjoerg InstantiationGroup IG{InstantiationSet.first.first,
7497330f729Sjoerg InstantiationSet.first.second,
7507330f729Sjoerg std::move(InstantiationSet.second)};
7517330f729Sjoerg Result.emplace_back(std::move(IG));
7527330f729Sjoerg }
7537330f729Sjoerg return Result;
7547330f729Sjoerg }
7557330f729Sjoerg
7567330f729Sjoerg CoverageData
getCoverageForFunction(const FunctionRecord & Function) const7577330f729Sjoerg CoverageMapping::getCoverageForFunction(const FunctionRecord &Function) const {
7587330f729Sjoerg auto MainFileID = findMainViewFileID(Function);
7597330f729Sjoerg if (!MainFileID)
7607330f729Sjoerg return CoverageData();
7617330f729Sjoerg
7627330f729Sjoerg CoverageData FunctionCoverage(Function.Filenames[*MainFileID]);
7637330f729Sjoerg std::vector<CountedRegion> Regions;
7647330f729Sjoerg for (const auto &CR : Function.CountedRegions)
7657330f729Sjoerg if (CR.FileID == *MainFileID) {
7667330f729Sjoerg Regions.push_back(CR);
7677330f729Sjoerg if (isExpansion(CR, *MainFileID))
7687330f729Sjoerg FunctionCoverage.Expansions.emplace_back(CR, Function);
7697330f729Sjoerg }
770*82d56013Sjoerg // Capture branch regions specific to the function (excluding expansions).
771*82d56013Sjoerg for (const auto &CR : Function.CountedBranchRegions)
772*82d56013Sjoerg if (CR.FileID == *MainFileID)
773*82d56013Sjoerg FunctionCoverage.BranchRegions.push_back(CR);
7747330f729Sjoerg
7757330f729Sjoerg LLVM_DEBUG(dbgs() << "Emitting segments for function: " << Function.Name
7767330f729Sjoerg << "\n");
7777330f729Sjoerg FunctionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
7787330f729Sjoerg
7797330f729Sjoerg return FunctionCoverage;
7807330f729Sjoerg }
7817330f729Sjoerg
getCoverageForExpansion(const ExpansionRecord & Expansion) const7827330f729Sjoerg CoverageData CoverageMapping::getCoverageForExpansion(
7837330f729Sjoerg const ExpansionRecord &Expansion) const {
7847330f729Sjoerg CoverageData ExpansionCoverage(
7857330f729Sjoerg Expansion.Function.Filenames[Expansion.FileID]);
7867330f729Sjoerg std::vector<CountedRegion> Regions;
7877330f729Sjoerg for (const auto &CR : Expansion.Function.CountedRegions)
7887330f729Sjoerg if (CR.FileID == Expansion.FileID) {
7897330f729Sjoerg Regions.push_back(CR);
7907330f729Sjoerg if (isExpansion(CR, Expansion.FileID))
7917330f729Sjoerg ExpansionCoverage.Expansions.emplace_back(CR, Expansion.Function);
7927330f729Sjoerg }
793*82d56013Sjoerg for (const auto &CR : Expansion.Function.CountedBranchRegions)
794*82d56013Sjoerg // Capture branch regions that only pertain to the corresponding expansion.
795*82d56013Sjoerg if (CR.FileID == Expansion.FileID)
796*82d56013Sjoerg ExpansionCoverage.BranchRegions.push_back(CR);
7977330f729Sjoerg
7987330f729Sjoerg LLVM_DEBUG(dbgs() << "Emitting segments for expansion of file "
7997330f729Sjoerg << Expansion.FileID << "\n");
8007330f729Sjoerg ExpansionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
8017330f729Sjoerg
8027330f729Sjoerg return ExpansionCoverage;
8037330f729Sjoerg }
8047330f729Sjoerg
LineCoverageStats(ArrayRef<const CoverageSegment * > LineSegments,const CoverageSegment * WrappedSegment,unsigned Line)8057330f729Sjoerg LineCoverageStats::LineCoverageStats(
8067330f729Sjoerg ArrayRef<const CoverageSegment *> LineSegments,
8077330f729Sjoerg const CoverageSegment *WrappedSegment, unsigned Line)
8087330f729Sjoerg : ExecutionCount(0), HasMultipleRegions(false), Mapped(false), Line(Line),
8097330f729Sjoerg LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
8107330f729Sjoerg // Find the minimum number of regions which start in this line.
8117330f729Sjoerg unsigned MinRegionCount = 0;
8127330f729Sjoerg auto isStartOfRegion = [](const CoverageSegment *S) {
8137330f729Sjoerg return !S->IsGapRegion && S->HasCount && S->IsRegionEntry;
8147330f729Sjoerg };
8157330f729Sjoerg for (unsigned I = 0; I < LineSegments.size() && MinRegionCount < 2; ++I)
8167330f729Sjoerg if (isStartOfRegion(LineSegments[I]))
8177330f729Sjoerg ++MinRegionCount;
8187330f729Sjoerg
8197330f729Sjoerg bool StartOfSkippedRegion = !LineSegments.empty() &&
8207330f729Sjoerg !LineSegments.front()->HasCount &&
8217330f729Sjoerg LineSegments.front()->IsRegionEntry;
8227330f729Sjoerg
8237330f729Sjoerg HasMultipleRegions = MinRegionCount > 1;
8247330f729Sjoerg Mapped =
8257330f729Sjoerg !StartOfSkippedRegion &&
8267330f729Sjoerg ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0));
8277330f729Sjoerg
8287330f729Sjoerg if (!Mapped)
8297330f729Sjoerg return;
8307330f729Sjoerg
8317330f729Sjoerg // Pick the max count from the non-gap, region entry segments and the
8327330f729Sjoerg // wrapped count.
8337330f729Sjoerg if (WrappedSegment)
8347330f729Sjoerg ExecutionCount = WrappedSegment->Count;
8357330f729Sjoerg if (!MinRegionCount)
8367330f729Sjoerg return;
8377330f729Sjoerg for (const auto *LS : LineSegments)
8387330f729Sjoerg if (isStartOfRegion(LS))
8397330f729Sjoerg ExecutionCount = std::max(ExecutionCount, LS->Count);
8407330f729Sjoerg }
8417330f729Sjoerg
operator ++()8427330f729Sjoerg LineCoverageIterator &LineCoverageIterator::operator++() {
8437330f729Sjoerg if (Next == CD.end()) {
8447330f729Sjoerg Stats = LineCoverageStats();
8457330f729Sjoerg Ended = true;
8467330f729Sjoerg return *this;
8477330f729Sjoerg }
8487330f729Sjoerg if (Segments.size())
8497330f729Sjoerg WrappedSegment = Segments.back();
8507330f729Sjoerg Segments.clear();
8517330f729Sjoerg while (Next != CD.end() && Next->Line == Line)
8527330f729Sjoerg Segments.push_back(&*Next++);
8537330f729Sjoerg Stats = LineCoverageStats(Segments, WrappedSegment, Line);
8547330f729Sjoerg ++Line;
8557330f729Sjoerg return *this;
8567330f729Sjoerg }
8577330f729Sjoerg
getCoverageMapErrString(coveragemap_error Err)8587330f729Sjoerg static std::string getCoverageMapErrString(coveragemap_error Err) {
8597330f729Sjoerg switch (Err) {
8607330f729Sjoerg case coveragemap_error::success:
8617330f729Sjoerg return "Success";
8627330f729Sjoerg case coveragemap_error::eof:
8637330f729Sjoerg return "End of File";
8647330f729Sjoerg case coveragemap_error::no_data_found:
8657330f729Sjoerg return "No coverage data found";
8667330f729Sjoerg case coveragemap_error::unsupported_version:
8677330f729Sjoerg return "Unsupported coverage format version";
8687330f729Sjoerg case coveragemap_error::truncated:
8697330f729Sjoerg return "Truncated coverage data";
8707330f729Sjoerg case coveragemap_error::malformed:
8717330f729Sjoerg return "Malformed coverage data";
872*82d56013Sjoerg case coveragemap_error::decompression_failed:
873*82d56013Sjoerg return "Failed to decompress coverage data (zlib)";
874*82d56013Sjoerg case coveragemap_error::invalid_or_missing_arch_specifier:
875*82d56013Sjoerg return "`-arch` specifier is invalid or missing for universal binary";
8767330f729Sjoerg }
8777330f729Sjoerg llvm_unreachable("A value of coveragemap_error has no message.");
8787330f729Sjoerg }
8797330f729Sjoerg
8807330f729Sjoerg namespace {
8817330f729Sjoerg
8827330f729Sjoerg // FIXME: This class is only here to support the transition to llvm::Error. It
8837330f729Sjoerg // will be removed once this transition is complete. Clients should prefer to
8847330f729Sjoerg // deal with the Error value directly, rather than converting to error_code.
8857330f729Sjoerg class CoverageMappingErrorCategoryType : public std::error_category {
name() const8867330f729Sjoerg const char *name() const noexcept override { return "llvm.coveragemap"; }
message(int IE) const8877330f729Sjoerg std::string message(int IE) const override {
8887330f729Sjoerg return getCoverageMapErrString(static_cast<coveragemap_error>(IE));
8897330f729Sjoerg }
8907330f729Sjoerg };
8917330f729Sjoerg
8927330f729Sjoerg } // end anonymous namespace
8937330f729Sjoerg
message() const8947330f729Sjoerg std::string CoverageMapError::message() const {
8957330f729Sjoerg return getCoverageMapErrString(Err);
8967330f729Sjoerg }
8977330f729Sjoerg
8987330f729Sjoerg static ManagedStatic<CoverageMappingErrorCategoryType> ErrorCategory;
8997330f729Sjoerg
coveragemap_category()9007330f729Sjoerg const std::error_category &llvm::coverage::coveragemap_category() {
9017330f729Sjoerg return *ErrorCategory;
9027330f729Sjoerg }
9037330f729Sjoerg
9047330f729Sjoerg char CoverageMapError::ID = 0;
905