1edd7eaddSDimitry Andric //===- CoverageMapping.cpp - Code coverage mapping support ----------------===//
23ca95b02SDimitry Andric //
33ca95b02SDimitry Andric // The LLVM Compiler Infrastructure
43ca95b02SDimitry Andric //
53ca95b02SDimitry Andric // This file is distributed under the University of Illinois Open Source
63ca95b02SDimitry Andric // License. See LICENSE.TXT for details.
73ca95b02SDimitry Andric //
83ca95b02SDimitry Andric //===----------------------------------------------------------------------===//
93ca95b02SDimitry Andric //
103ca95b02SDimitry Andric // This file contains support for clang's and llvm's instrumentation based
113ca95b02SDimitry Andric // code coverage.
123ca95b02SDimitry Andric //
133ca95b02SDimitry Andric //===----------------------------------------------------------------------===//
143ca95b02SDimitry Andric
15db17bf38SDimitry Andric #include "llvm/ProfileData/Coverage/CoverageMapping.h"
167a7e6055SDimitry Andric #include "llvm/ADT/ArrayRef.h"
173ca95b02SDimitry Andric #include "llvm/ADT/DenseMap.h"
187a7e6055SDimitry Andric #include "llvm/ADT/None.h"
193ca95b02SDimitry Andric #include "llvm/ADT/Optional.h"
203ca95b02SDimitry Andric #include "llvm/ADT/SmallBitVector.h"
217a7e6055SDimitry Andric #include "llvm/ADT/SmallVector.h"
227a7e6055SDimitry Andric #include "llvm/ADT/StringRef.h"
233ca95b02SDimitry Andric #include "llvm/ProfileData/Coverage/CoverageMappingReader.h"
243ca95b02SDimitry Andric #include "llvm/ProfileData/InstrProfReader.h"
253ca95b02SDimitry Andric #include "llvm/Support/Debug.h"
263ca95b02SDimitry Andric #include "llvm/Support/Errc.h"
277a7e6055SDimitry Andric #include "llvm/Support/Error.h"
283ca95b02SDimitry Andric #include "llvm/Support/ErrorHandling.h"
293ca95b02SDimitry Andric #include "llvm/Support/ManagedStatic.h"
307a7e6055SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
313ca95b02SDimitry Andric #include "llvm/Support/raw_ostream.h"
327a7e6055SDimitry Andric #include <algorithm>
337a7e6055SDimitry Andric #include <cassert>
347a7e6055SDimitry Andric #include <cstdint>
357a7e6055SDimitry Andric #include <iterator>
362cab237bSDimitry Andric #include <map>
377a7e6055SDimitry Andric #include <memory>
387a7e6055SDimitry Andric #include <string>
397a7e6055SDimitry Andric #include <system_error>
407a7e6055SDimitry Andric #include <utility>
417a7e6055SDimitry Andric #include <vector>
423ca95b02SDimitry Andric
433ca95b02SDimitry Andric using namespace llvm;
443ca95b02SDimitry Andric using namespace coverage;
453ca95b02SDimitry Andric
463ca95b02SDimitry Andric #define DEBUG_TYPE "coverage-mapping"
473ca95b02SDimitry Andric
get(const CounterExpression & E)483ca95b02SDimitry Andric Counter CounterExpressionBuilder::get(const CounterExpression &E) {
493ca95b02SDimitry Andric auto It = ExpressionIndices.find(E);
503ca95b02SDimitry Andric if (It != ExpressionIndices.end())
513ca95b02SDimitry Andric return Counter::getExpression(It->second);
523ca95b02SDimitry Andric unsigned I = Expressions.size();
533ca95b02SDimitry Andric Expressions.push_back(E);
543ca95b02SDimitry Andric ExpressionIndices[E] = I;
553ca95b02SDimitry Andric return Counter::getExpression(I);
563ca95b02SDimitry Andric }
573ca95b02SDimitry Andric
extractTerms(Counter C,int Factor,SmallVectorImpl<Term> & Terms)58a580b014SDimitry Andric void CounterExpressionBuilder::extractTerms(Counter C, int Factor,
59a580b014SDimitry Andric SmallVectorImpl<Term> &Terms) {
603ca95b02SDimitry Andric switch (C.getKind()) {
613ca95b02SDimitry Andric case Counter::Zero:
623ca95b02SDimitry Andric break;
633ca95b02SDimitry Andric case Counter::CounterValueReference:
64a580b014SDimitry Andric Terms.emplace_back(C.getCounterID(), Factor);
653ca95b02SDimitry Andric break;
663ca95b02SDimitry Andric case Counter::Expression:
673ca95b02SDimitry Andric const auto &E = Expressions[C.getExpressionID()];
68a580b014SDimitry Andric extractTerms(E.LHS, Factor, Terms);
69a580b014SDimitry Andric extractTerms(
70a580b014SDimitry Andric E.RHS, E.Kind == CounterExpression::Subtract ? -Factor : Factor, Terms);
713ca95b02SDimitry Andric break;
723ca95b02SDimitry Andric }
733ca95b02SDimitry Andric }
743ca95b02SDimitry Andric
simplify(Counter ExpressionTree)753ca95b02SDimitry Andric Counter CounterExpressionBuilder::simplify(Counter ExpressionTree) {
763ca95b02SDimitry Andric // Gather constant terms.
77a580b014SDimitry Andric SmallVector<Term, 32> Terms;
783ca95b02SDimitry Andric extractTerms(ExpressionTree, +1, Terms);
793ca95b02SDimitry Andric
803ca95b02SDimitry Andric // If there are no terms, this is just a zero. The algorithm below assumes at
813ca95b02SDimitry Andric // least one term.
823ca95b02SDimitry Andric if (Terms.size() == 0)
833ca95b02SDimitry Andric return Counter::getZero();
843ca95b02SDimitry Andric
853ca95b02SDimitry Andric // Group the terms by counter ID.
86*b5893f02SDimitry Andric llvm::sort(Terms, [](const Term &LHS, const Term &RHS) {
87a580b014SDimitry Andric return LHS.CounterID < RHS.CounterID;
883ca95b02SDimitry Andric });
893ca95b02SDimitry Andric
903ca95b02SDimitry Andric // Combine terms by counter ID to eliminate counters that sum to zero.
913ca95b02SDimitry Andric auto Prev = Terms.begin();
923ca95b02SDimitry Andric for (auto I = Prev + 1, E = Terms.end(); I != E; ++I) {
93a580b014SDimitry Andric if (I->CounterID == Prev->CounterID) {
94a580b014SDimitry Andric Prev->Factor += I->Factor;
953ca95b02SDimitry Andric continue;
963ca95b02SDimitry Andric }
973ca95b02SDimitry Andric ++Prev;
983ca95b02SDimitry Andric *Prev = *I;
993ca95b02SDimitry Andric }
1003ca95b02SDimitry Andric Terms.erase(++Prev, Terms.end());
1013ca95b02SDimitry Andric
1023ca95b02SDimitry Andric Counter C;
1033ca95b02SDimitry Andric // Create additions. We do this before subtractions to avoid constructs like
1043ca95b02SDimitry Andric // ((0 - X) + Y), as opposed to (Y - X).
105a580b014SDimitry Andric for (auto T : Terms) {
106a580b014SDimitry Andric if (T.Factor <= 0)
1073ca95b02SDimitry Andric continue;
108a580b014SDimitry Andric for (int I = 0; I < T.Factor; ++I)
1093ca95b02SDimitry Andric if (C.isZero())
110a580b014SDimitry Andric C = Counter::getCounter(T.CounterID);
1113ca95b02SDimitry Andric else
1123ca95b02SDimitry Andric C = get(CounterExpression(CounterExpression::Add, C,
113a580b014SDimitry Andric Counter::getCounter(T.CounterID)));
1143ca95b02SDimitry Andric }
1153ca95b02SDimitry Andric
1163ca95b02SDimitry Andric // Create subtractions.
117a580b014SDimitry Andric for (auto T : Terms) {
118a580b014SDimitry Andric if (T.Factor >= 0)
1193ca95b02SDimitry Andric continue;
120a580b014SDimitry Andric for (int I = 0; I < -T.Factor; ++I)
1213ca95b02SDimitry Andric C = get(CounterExpression(CounterExpression::Subtract, C,
122a580b014SDimitry Andric Counter::getCounter(T.CounterID)));
1233ca95b02SDimitry Andric }
1243ca95b02SDimitry Andric return C;
1253ca95b02SDimitry Andric }
1263ca95b02SDimitry Andric
add(Counter LHS,Counter RHS)1273ca95b02SDimitry Andric Counter CounterExpressionBuilder::add(Counter LHS, Counter RHS) {
1283ca95b02SDimitry Andric return simplify(get(CounterExpression(CounterExpression::Add, LHS, RHS)));
1293ca95b02SDimitry Andric }
1303ca95b02SDimitry Andric
subtract(Counter LHS,Counter RHS)1313ca95b02SDimitry Andric Counter CounterExpressionBuilder::subtract(Counter LHS, Counter RHS) {
1323ca95b02SDimitry Andric return simplify(
1333ca95b02SDimitry Andric get(CounterExpression(CounterExpression::Subtract, LHS, RHS)));
1343ca95b02SDimitry Andric }
1353ca95b02SDimitry Andric
dump(const Counter & C,raw_ostream & OS) const1367a7e6055SDimitry Andric void CounterMappingContext::dump(const Counter &C, raw_ostream &OS) const {
1373ca95b02SDimitry Andric switch (C.getKind()) {
1383ca95b02SDimitry Andric case Counter::Zero:
1393ca95b02SDimitry Andric OS << '0';
1403ca95b02SDimitry Andric return;
1413ca95b02SDimitry Andric case Counter::CounterValueReference:
1423ca95b02SDimitry Andric OS << '#' << C.getCounterID();
1433ca95b02SDimitry Andric break;
1443ca95b02SDimitry Andric case Counter::Expression: {
1453ca95b02SDimitry Andric if (C.getExpressionID() >= Expressions.size())
1463ca95b02SDimitry Andric return;
1473ca95b02SDimitry Andric const auto &E = Expressions[C.getExpressionID()];
1483ca95b02SDimitry Andric OS << '(';
1493ca95b02SDimitry Andric dump(E.LHS, OS);
1503ca95b02SDimitry Andric OS << (E.Kind == CounterExpression::Subtract ? " - " : " + ");
1513ca95b02SDimitry Andric dump(E.RHS, OS);
1523ca95b02SDimitry Andric OS << ')';
1533ca95b02SDimitry Andric break;
1543ca95b02SDimitry Andric }
1553ca95b02SDimitry Andric }
1563ca95b02SDimitry Andric if (CounterValues.empty())
1573ca95b02SDimitry Andric return;
1583ca95b02SDimitry Andric Expected<int64_t> Value = evaluate(C);
1593ca95b02SDimitry Andric if (auto E = Value.takeError()) {
1607a7e6055SDimitry Andric consumeError(std::move(E));
1613ca95b02SDimitry Andric return;
1623ca95b02SDimitry Andric }
1633ca95b02SDimitry Andric OS << '[' << *Value << ']';
1643ca95b02SDimitry Andric }
1653ca95b02SDimitry Andric
evaluate(const Counter & C) const1663ca95b02SDimitry Andric Expected<int64_t> CounterMappingContext::evaluate(const Counter &C) const {
1673ca95b02SDimitry Andric switch (C.getKind()) {
1683ca95b02SDimitry Andric case Counter::Zero:
1693ca95b02SDimitry Andric return 0;
1703ca95b02SDimitry Andric case Counter::CounterValueReference:
1713ca95b02SDimitry Andric if (C.getCounterID() >= CounterValues.size())
1723ca95b02SDimitry Andric return errorCodeToError(errc::argument_out_of_domain);
1733ca95b02SDimitry Andric return CounterValues[C.getCounterID()];
1743ca95b02SDimitry Andric case Counter::Expression: {
1753ca95b02SDimitry Andric if (C.getExpressionID() >= Expressions.size())
1763ca95b02SDimitry Andric return errorCodeToError(errc::argument_out_of_domain);
1773ca95b02SDimitry Andric const auto &E = Expressions[C.getExpressionID()];
1783ca95b02SDimitry Andric Expected<int64_t> LHS = evaluate(E.LHS);
1793ca95b02SDimitry Andric if (!LHS)
1803ca95b02SDimitry Andric return LHS;
1813ca95b02SDimitry Andric Expected<int64_t> RHS = evaluate(E.RHS);
1823ca95b02SDimitry Andric if (!RHS)
1833ca95b02SDimitry Andric return RHS;
1843ca95b02SDimitry Andric return E.Kind == CounterExpression::Subtract ? *LHS - *RHS : *LHS + *RHS;
1853ca95b02SDimitry Andric }
1863ca95b02SDimitry Andric }
1873ca95b02SDimitry Andric llvm_unreachable("Unhandled CounterKind");
1883ca95b02SDimitry Andric }
1893ca95b02SDimitry Andric
skipOtherFiles()1903ca95b02SDimitry Andric void FunctionRecordIterator::skipOtherFiles() {
1913ca95b02SDimitry Andric while (Current != Records.end() && !Filename.empty() &&
1923ca95b02SDimitry Andric Filename != Current->Filenames[0])
1933ca95b02SDimitry Andric ++Current;
1943ca95b02SDimitry Andric if (Current == Records.end())
1953ca95b02SDimitry Andric *this = FunctionRecordIterator();
1963ca95b02SDimitry Andric }
1973ca95b02SDimitry Andric
loadFunctionRecord(const CoverageMappingRecord & Record,IndexedInstrProfReader & ProfileReader)198d88c1a5aSDimitry Andric Error CoverageMapping::loadFunctionRecord(
199d88c1a5aSDimitry Andric const CoverageMappingRecord &Record,
2003ca95b02SDimitry Andric IndexedInstrProfReader &ProfileReader) {
201d88c1a5aSDimitry Andric StringRef OrigFuncName = Record.FunctionName;
202edd7eaddSDimitry Andric if (OrigFuncName.empty())
203edd7eaddSDimitry Andric return make_error<CoverageMapError>(coveragemap_error::malformed);
204edd7eaddSDimitry Andric
205d88c1a5aSDimitry Andric if (Record.Filenames.empty())
206d88c1a5aSDimitry Andric OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName);
207d88c1a5aSDimitry Andric else
208d88c1a5aSDimitry Andric OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]);
2093ca95b02SDimitry Andric
2103ca95b02SDimitry Andric CounterMappingContext Ctx(Record.Expressions);
2113ca95b02SDimitry Andric
212d88c1a5aSDimitry Andric std::vector<uint64_t> Counts;
213d88c1a5aSDimitry Andric if (Error E = ProfileReader.getFunctionCounts(Record.FunctionName,
214d88c1a5aSDimitry Andric Record.FunctionHash, Counts)) {
2153ca95b02SDimitry Andric instrprof_error IPE = InstrProfError::take(std::move(E));
2163ca95b02SDimitry Andric if (IPE == instrprof_error::hash_mismatch) {
2172cab237bSDimitry Andric FuncHashMismatches.emplace_back(Record.FunctionName, Record.FunctionHash);
218d88c1a5aSDimitry Andric return Error::success();
2193ca95b02SDimitry Andric } else if (IPE != instrprof_error::unknown_function)
2203ca95b02SDimitry Andric return make_error<InstrProfError>(IPE);
2213ca95b02SDimitry Andric Counts.assign(Record.MappingRegions.size(), 0);
2223ca95b02SDimitry Andric }
2233ca95b02SDimitry Andric Ctx.setCounts(Counts);
2243ca95b02SDimitry Andric
2253ca95b02SDimitry Andric assert(!Record.MappingRegions.empty() && "Function has no regions");
2263ca95b02SDimitry Andric
227*b5893f02SDimitry Andric // This coverage record is a zero region for a function that's unused in
228*b5893f02SDimitry Andric // some TU, but used in a different TU. Ignore it. The coverage maps from the
229*b5893f02SDimitry Andric // the other TU will either be loaded (providing full region counts) or they
230*b5893f02SDimitry Andric // won't (in which case we don't unintuitively report functions as uncovered
231*b5893f02SDimitry Andric // when they have non-zero counts in the profile).
232*b5893f02SDimitry Andric if (Record.MappingRegions.size() == 1 &&
233*b5893f02SDimitry Andric Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
234*b5893f02SDimitry Andric return Error::success();
235*b5893f02SDimitry Andric
2363ca95b02SDimitry Andric FunctionRecord Function(OrigFuncName, Record.Filenames);
2373ca95b02SDimitry Andric for (const auto &Region : Record.MappingRegions) {
2383ca95b02SDimitry Andric Expected<int64_t> ExecutionCount = Ctx.evaluate(Region.Count);
2393ca95b02SDimitry Andric if (auto E = ExecutionCount.takeError()) {
2407a7e6055SDimitry Andric consumeError(std::move(E));
241d88c1a5aSDimitry Andric return Error::success();
2423ca95b02SDimitry Andric }
2433ca95b02SDimitry Andric Function.pushRegion(Region, *ExecutionCount);
2443ca95b02SDimitry Andric }
245*b5893f02SDimitry Andric
246*b5893f02SDimitry Andric // Don't create records for (filenames, function) pairs we've already seen.
247*b5893f02SDimitry Andric auto FilenamesHash = hash_combine_range(Record.Filenames.begin(),
248*b5893f02SDimitry Andric Record.Filenames.end());
249*b5893f02SDimitry Andric if (!RecordProvenance[FilenamesHash].insert(hash_value(OrigFuncName)).second)
250d88c1a5aSDimitry Andric return Error::success();
2513ca95b02SDimitry Andric
252d88c1a5aSDimitry Andric Functions.push_back(std::move(Function));
253d88c1a5aSDimitry Andric return Error::success();
2543ca95b02SDimitry Andric }
2553ca95b02SDimitry Andric
load(ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,IndexedInstrProfReader & ProfileReader)256d88c1a5aSDimitry Andric Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
257d88c1a5aSDimitry Andric ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
258d88c1a5aSDimitry Andric IndexedInstrProfReader &ProfileReader) {
259d88c1a5aSDimitry Andric auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
260d88c1a5aSDimitry Andric
2612cab237bSDimitry Andric for (const auto &CoverageReader : CoverageReaders) {
2622cab237bSDimitry Andric for (auto RecordOrErr : *CoverageReader) {
2632cab237bSDimitry Andric if (Error E = RecordOrErr.takeError())
2642cab237bSDimitry Andric return std::move(E);
2652cab237bSDimitry Andric const auto &Record = *RecordOrErr;
266d88c1a5aSDimitry Andric if (Error E = Coverage->loadFunctionRecord(Record, ProfileReader))
267d88c1a5aSDimitry Andric return std::move(E);
2682cab237bSDimitry Andric }
2692cab237bSDimitry Andric }
270d88c1a5aSDimitry Andric
2713ca95b02SDimitry Andric return std::move(Coverage);
2723ca95b02SDimitry Andric }
2733ca95b02SDimitry Andric
2743ca95b02SDimitry Andric Expected<std::unique_ptr<CoverageMapping>>
load(ArrayRef<StringRef> ObjectFilenames,StringRef ProfileFilename,ArrayRef<StringRef> Arches)275d88c1a5aSDimitry Andric CoverageMapping::load(ArrayRef<StringRef> ObjectFilenames,
2762cab237bSDimitry Andric StringRef ProfileFilename, ArrayRef<StringRef> Arches) {
2773ca95b02SDimitry Andric auto ProfileReaderOrErr = IndexedInstrProfReader::create(ProfileFilename);
2783ca95b02SDimitry Andric if (Error E = ProfileReaderOrErr.takeError())
2793ca95b02SDimitry Andric return std::move(E);
2803ca95b02SDimitry Andric auto ProfileReader = std::move(ProfileReaderOrErr.get());
281d88c1a5aSDimitry Andric
282d88c1a5aSDimitry Andric SmallVector<std::unique_ptr<CoverageMappingReader>, 4> Readers;
283d88c1a5aSDimitry Andric SmallVector<std::unique_ptr<MemoryBuffer>, 4> Buffers;
2842cab237bSDimitry Andric for (const auto &File : llvm::enumerate(ObjectFilenames)) {
2852cab237bSDimitry Andric auto CovMappingBufOrErr = MemoryBuffer::getFileOrSTDIN(File.value());
286d88c1a5aSDimitry Andric if (std::error_code EC = CovMappingBufOrErr.getError())
287d88c1a5aSDimitry Andric return errorCodeToError(EC);
2882cab237bSDimitry Andric StringRef Arch = Arches.empty() ? StringRef() : Arches[File.index()];
289d88c1a5aSDimitry Andric auto CoverageReaderOrErr =
290d88c1a5aSDimitry Andric BinaryCoverageReader::create(CovMappingBufOrErr.get(), Arch);
291d88c1a5aSDimitry Andric if (Error E = CoverageReaderOrErr.takeError())
292d88c1a5aSDimitry Andric return std::move(E);
293d88c1a5aSDimitry Andric Readers.push_back(std::move(CoverageReaderOrErr.get()));
294d88c1a5aSDimitry Andric Buffers.push_back(std::move(CovMappingBufOrErr.get()));
295d88c1a5aSDimitry Andric }
296d88c1a5aSDimitry Andric return load(Readers, *ProfileReader);
2973ca95b02SDimitry Andric }
2983ca95b02SDimitry Andric
2993ca95b02SDimitry Andric namespace {
3007a7e6055SDimitry Andric
3014ba319b5SDimitry Andric /// Distributes functions into instantiation sets.
3023ca95b02SDimitry Andric ///
3033ca95b02SDimitry Andric /// An instantiation set is a collection of functions that have the same source
3043ca95b02SDimitry Andric /// code, ie, template functions specializations.
3053ca95b02SDimitry Andric class FunctionInstantiationSetCollector {
3062cab237bSDimitry Andric using MapT = std::map<LineColPair, std::vector<const FunctionRecord *>>;
3073ca95b02SDimitry Andric MapT InstantiatedFunctions;
3083ca95b02SDimitry Andric
3093ca95b02SDimitry Andric public:
insert(const FunctionRecord & Function,unsigned FileID)3103ca95b02SDimitry Andric void insert(const FunctionRecord &Function, unsigned FileID) {
3113ca95b02SDimitry Andric auto I = Function.CountedRegions.begin(), E = Function.CountedRegions.end();
3123ca95b02SDimitry Andric while (I != E && I->FileID != FileID)
3133ca95b02SDimitry Andric ++I;
3143ca95b02SDimitry Andric assert(I != E && "function does not cover the given file");
3153ca95b02SDimitry Andric auto &Functions = InstantiatedFunctions[I->startLoc()];
3163ca95b02SDimitry Andric Functions.push_back(&Function);
3173ca95b02SDimitry Andric }
3183ca95b02SDimitry Andric
begin()3193ca95b02SDimitry Andric MapT::iterator begin() { return InstantiatedFunctions.begin(); }
end()3203ca95b02SDimitry Andric MapT::iterator end() { return InstantiatedFunctions.end(); }
3213ca95b02SDimitry Andric };
3223ca95b02SDimitry Andric
3233ca95b02SDimitry Andric class SegmentBuilder {
3243ca95b02SDimitry Andric std::vector<CoverageSegment> &Segments;
3253ca95b02SDimitry Andric SmallVector<const CountedRegion *, 8> ActiveRegions;
3263ca95b02SDimitry Andric
SegmentBuilder(std::vector<CoverageSegment> & Segments)3273ca95b02SDimitry Andric SegmentBuilder(std::vector<CoverageSegment> &Segments) : Segments(Segments) {}
3283ca95b02SDimitry Andric
3292cab237bSDimitry Andric /// Emit a segment with the count from \p Region starting at \p StartLoc.
3302cab237bSDimitry Andric //
3312cab237bSDimitry Andric /// \p IsRegionEntry: The segment is at the start of a new non-gap region.
3322cab237bSDimitry Andric /// \p EmitSkippedRegion: The segment must be emitted as a skipped region.
startSegment(const CountedRegion & Region,LineColPair StartLoc,bool IsRegionEntry,bool EmitSkippedRegion=false)3332cab237bSDimitry Andric void startSegment(const CountedRegion &Region, LineColPair StartLoc,
3342cab237bSDimitry Andric bool IsRegionEntry, bool EmitSkippedRegion = false) {
3352cab237bSDimitry Andric bool HasCount = !EmitSkippedRegion &&
3362cab237bSDimitry Andric (Region.Kind != CounterMappingRegion::SkippedRegion);
3372cab237bSDimitry Andric
3382cab237bSDimitry Andric // If the new segment wouldn't affect coverage rendering, skip it.
3392cab237bSDimitry Andric if (!Segments.empty() && !IsRegionEntry && !EmitSkippedRegion) {
3402cab237bSDimitry Andric const auto &Last = Segments.back();
3412cab237bSDimitry Andric if (Last.HasCount == HasCount && Last.Count == Region.ExecutionCount &&
3422cab237bSDimitry Andric !Last.IsRegionEntry)
3432cab237bSDimitry Andric return;
3443ca95b02SDimitry Andric }
3453ca95b02SDimitry Andric
3462cab237bSDimitry Andric if (HasCount)
3472cab237bSDimitry Andric Segments.emplace_back(StartLoc.first, StartLoc.second,
3482cab237bSDimitry Andric Region.ExecutionCount, IsRegionEntry,
3492cab237bSDimitry Andric Region.Kind == CounterMappingRegion::GapRegion);
3503ca95b02SDimitry Andric else
3512cab237bSDimitry Andric Segments.emplace_back(StartLoc.first, StartLoc.second, IsRegionEntry);
3522cab237bSDimitry Andric
3534ba319b5SDimitry Andric LLVM_DEBUG({
3542cab237bSDimitry Andric const auto &Last = Segments.back();
3552cab237bSDimitry Andric dbgs() << "Segment at " << Last.Line << ":" << Last.Col
3562cab237bSDimitry Andric << " (count = " << Last.Count << ")"
3572cab237bSDimitry Andric << (Last.IsRegionEntry ? ", RegionEntry" : "")
3582cab237bSDimitry Andric << (!Last.HasCount ? ", Skipped" : "")
3592cab237bSDimitry Andric << (Last.IsGapRegion ? ", Gap" : "") << "\n";
3602cab237bSDimitry Andric });
3612cab237bSDimitry Andric }
3622cab237bSDimitry Andric
3632cab237bSDimitry Andric /// Emit segments for active regions which end before \p Loc.
3642cab237bSDimitry Andric ///
3652cab237bSDimitry Andric /// \p Loc: The start location of the next region. If None, all active
3662cab237bSDimitry Andric /// regions are completed.
3672cab237bSDimitry Andric /// \p FirstCompletedRegion: Index of the first completed region.
completeRegionsUntil(Optional<LineColPair> Loc,unsigned FirstCompletedRegion)3682cab237bSDimitry Andric void completeRegionsUntil(Optional<LineColPair> Loc,
3692cab237bSDimitry Andric unsigned FirstCompletedRegion) {
3702cab237bSDimitry Andric // Sort the completed regions by end location. This makes it simple to
3712cab237bSDimitry Andric // emit closing segments in sorted order.
3722cab237bSDimitry Andric auto CompletedRegionsIt = ActiveRegions.begin() + FirstCompletedRegion;
3732cab237bSDimitry Andric std::stable_sort(CompletedRegionsIt, ActiveRegions.end(),
3742cab237bSDimitry Andric [](const CountedRegion *L, const CountedRegion *R) {
3752cab237bSDimitry Andric return L->endLoc() < R->endLoc();
3762cab237bSDimitry Andric });
3772cab237bSDimitry Andric
3782cab237bSDimitry Andric // Emit segments for all completed regions.
3792cab237bSDimitry Andric for (unsigned I = FirstCompletedRegion + 1, E = ActiveRegions.size(); I < E;
3802cab237bSDimitry Andric ++I) {
3812cab237bSDimitry Andric const auto *CompletedRegion = ActiveRegions[I];
3822cab237bSDimitry Andric assert((!Loc || CompletedRegion->endLoc() <= *Loc) &&
3832cab237bSDimitry Andric "Completed region ends after start of new region");
3842cab237bSDimitry Andric
3852cab237bSDimitry Andric const auto *PrevCompletedRegion = ActiveRegions[I - 1];
3862cab237bSDimitry Andric auto CompletedSegmentLoc = PrevCompletedRegion->endLoc();
3872cab237bSDimitry Andric
3882cab237bSDimitry Andric // Don't emit any more segments if they start where the new region begins.
3892cab237bSDimitry Andric if (Loc && CompletedSegmentLoc == *Loc)
3902cab237bSDimitry Andric break;
3912cab237bSDimitry Andric
3922cab237bSDimitry Andric // Don't emit a segment if the next completed region ends at the same
3932cab237bSDimitry Andric // location as this one.
3942cab237bSDimitry Andric if (CompletedSegmentLoc == CompletedRegion->endLoc())
3952cab237bSDimitry Andric continue;
3962cab237bSDimitry Andric
3972cab237bSDimitry Andric // Use the count from the last completed region which ends at this loc.
3982cab237bSDimitry Andric for (unsigned J = I + 1; J < E; ++J)
3992cab237bSDimitry Andric if (CompletedRegion->endLoc() == ActiveRegions[J]->endLoc())
4002cab237bSDimitry Andric CompletedRegion = ActiveRegions[J];
4012cab237bSDimitry Andric
4022cab237bSDimitry Andric startSegment(*CompletedRegion, CompletedSegmentLoc, false);
4032cab237bSDimitry Andric }
4042cab237bSDimitry Andric
4052cab237bSDimitry Andric auto Last = ActiveRegions.back();
4062cab237bSDimitry Andric if (FirstCompletedRegion && Last->endLoc() != *Loc) {
4072cab237bSDimitry Andric // If there's a gap after the end of the last completed region and the
4082cab237bSDimitry Andric // start of the new region, use the last active region to fill the gap.
4092cab237bSDimitry Andric startSegment(*ActiveRegions[FirstCompletedRegion - 1], Last->endLoc(),
4102cab237bSDimitry Andric false);
4112cab237bSDimitry Andric } else if (!FirstCompletedRegion && (!Loc || *Loc != Last->endLoc())) {
4122cab237bSDimitry Andric // Emit a skipped segment if there are no more active regions. This
4132cab237bSDimitry Andric // ensures that gaps between functions are marked correctly.
4142cab237bSDimitry Andric startSegment(*Last, Last->endLoc(), false, true);
4152cab237bSDimitry Andric }
4162cab237bSDimitry Andric
4172cab237bSDimitry Andric // Pop the completed regions.
4182cab237bSDimitry Andric ActiveRegions.erase(CompletedRegionsIt, ActiveRegions.end());
4193ca95b02SDimitry Andric }
4203ca95b02SDimitry Andric
buildSegmentsImpl(ArrayRef<CountedRegion> Regions)4213ca95b02SDimitry Andric void buildSegmentsImpl(ArrayRef<CountedRegion> Regions) {
4222cab237bSDimitry Andric for (const auto &CR : enumerate(Regions)) {
4232cab237bSDimitry Andric auto CurStartLoc = CR.value().startLoc();
4242cab237bSDimitry Andric
4252cab237bSDimitry Andric // Active regions which end before the current region need to be popped.
4262cab237bSDimitry Andric auto CompletedRegions =
4272cab237bSDimitry Andric std::stable_partition(ActiveRegions.begin(), ActiveRegions.end(),
4282cab237bSDimitry Andric [&](const CountedRegion *Region) {
4292cab237bSDimitry Andric return !(Region->endLoc() <= CurStartLoc);
4302cab237bSDimitry Andric });
4312cab237bSDimitry Andric if (CompletedRegions != ActiveRegions.end()) {
4322cab237bSDimitry Andric unsigned FirstCompletedRegion =
4332cab237bSDimitry Andric std::distance(ActiveRegions.begin(), CompletedRegions);
4342cab237bSDimitry Andric completeRegionsUntil(CurStartLoc, FirstCompletedRegion);
4353ca95b02SDimitry Andric }
4362cab237bSDimitry Andric
4372cab237bSDimitry Andric bool GapRegion = CR.value().Kind == CounterMappingRegion::GapRegion;
4382cab237bSDimitry Andric
4392cab237bSDimitry Andric // Try to emit a segment for the current region.
4402cab237bSDimitry Andric if (CurStartLoc == CR.value().endLoc()) {
4412cab237bSDimitry Andric // Avoid making zero-length regions active. If it's the last region,
4422cab237bSDimitry Andric // emit a skipped segment. Otherwise use its predecessor's count.
4432cab237bSDimitry Andric const bool Skipped = (CR.index() + 1) == Regions.size();
4442cab237bSDimitry Andric startSegment(ActiveRegions.empty() ? CR.value() : *ActiveRegions.back(),
4452cab237bSDimitry Andric CurStartLoc, !GapRegion, Skipped);
4462cab237bSDimitry Andric continue;
4472cab237bSDimitry Andric }
4482cab237bSDimitry Andric if (CR.index() + 1 == Regions.size() ||
4492cab237bSDimitry Andric CurStartLoc != Regions[CR.index() + 1].startLoc()) {
4502cab237bSDimitry Andric // Emit a segment if the next region doesn't start at the same location
4512cab237bSDimitry Andric // as this one.
4522cab237bSDimitry Andric startSegment(CR.value(), CurStartLoc, !GapRegion);
4532cab237bSDimitry Andric }
4542cab237bSDimitry Andric
4552cab237bSDimitry Andric // This region is active (i.e not completed).
4562cab237bSDimitry Andric ActiveRegions.push_back(&CR.value());
4572cab237bSDimitry Andric }
4582cab237bSDimitry Andric
4592cab237bSDimitry Andric // Complete any remaining active regions.
4602cab237bSDimitry Andric if (!ActiveRegions.empty())
4612cab237bSDimitry Andric completeRegionsUntil(None, 0);
4623ca95b02SDimitry Andric }
4633ca95b02SDimitry Andric
4643ca95b02SDimitry Andric /// Sort a nested sequence of regions from a single file.
sortNestedRegions(MutableArrayRef<CountedRegion> Regions)4653ca95b02SDimitry Andric static void sortNestedRegions(MutableArrayRef<CountedRegion> Regions) {
466*b5893f02SDimitry Andric llvm::sort(Regions, [](const CountedRegion &LHS, const CountedRegion &RHS) {
4673ca95b02SDimitry Andric if (LHS.startLoc() != RHS.startLoc())
4683ca95b02SDimitry Andric return LHS.startLoc() < RHS.startLoc();
4693ca95b02SDimitry Andric if (LHS.endLoc() != RHS.endLoc())
4703ca95b02SDimitry Andric // When LHS completely contains RHS, we sort LHS first.
4713ca95b02SDimitry Andric return RHS.endLoc() < LHS.endLoc();
4723ca95b02SDimitry Andric // If LHS and RHS cover the same area, we need to sort them according
4733ca95b02SDimitry Andric // to their kinds so that the most suitable region will become "active"
4743ca95b02SDimitry Andric // in combineRegions(). Because we accumulate counter values only from
4753ca95b02SDimitry Andric // regions of the same kind as the first region of the area, prefer
4763ca95b02SDimitry Andric // CodeRegion to ExpansionRegion and ExpansionRegion to SkippedRegion.
4777a7e6055SDimitry Andric static_assert(CounterMappingRegion::CodeRegion <
4787a7e6055SDimitry Andric CounterMappingRegion::ExpansionRegion &&
4797a7e6055SDimitry Andric CounterMappingRegion::ExpansionRegion <
4807a7e6055SDimitry Andric CounterMappingRegion::SkippedRegion,
4813ca95b02SDimitry Andric "Unexpected order of region kind values");
4823ca95b02SDimitry Andric return LHS.Kind < RHS.Kind;
4833ca95b02SDimitry Andric });
4843ca95b02SDimitry Andric }
4853ca95b02SDimitry Andric
4863ca95b02SDimitry Andric /// Combine counts of regions which cover the same area.
4873ca95b02SDimitry Andric static ArrayRef<CountedRegion>
combineRegions(MutableArrayRef<CountedRegion> Regions)4883ca95b02SDimitry Andric combineRegions(MutableArrayRef<CountedRegion> Regions) {
4893ca95b02SDimitry Andric if (Regions.empty())
4903ca95b02SDimitry Andric return Regions;
4913ca95b02SDimitry Andric auto Active = Regions.begin();
4923ca95b02SDimitry Andric auto End = Regions.end();
4933ca95b02SDimitry Andric for (auto I = Regions.begin() + 1; I != End; ++I) {
4943ca95b02SDimitry Andric if (Active->startLoc() != I->startLoc() ||
4953ca95b02SDimitry Andric Active->endLoc() != I->endLoc()) {
4963ca95b02SDimitry Andric // Shift to the next region.
4973ca95b02SDimitry Andric ++Active;
4983ca95b02SDimitry Andric if (Active != I)
4993ca95b02SDimitry Andric *Active = *I;
5003ca95b02SDimitry Andric continue;
5013ca95b02SDimitry Andric }
5023ca95b02SDimitry Andric // Merge duplicate region.
5033ca95b02SDimitry Andric // If CodeRegions and ExpansionRegions cover the same area, it's probably
5043ca95b02SDimitry Andric // a macro which is fully expanded to another macro. In that case, we need
5053ca95b02SDimitry Andric // to accumulate counts only from CodeRegions, or else the area will be
5063ca95b02SDimitry Andric // counted twice.
5073ca95b02SDimitry Andric // On the other hand, a macro may have a nested macro in its body. If the
5083ca95b02SDimitry Andric // outer macro is used several times, the ExpansionRegion for the nested
5093ca95b02SDimitry Andric // macro will also be added several times. These ExpansionRegions cover
5103ca95b02SDimitry Andric // the same source locations and have to be combined to reach the correct
5113ca95b02SDimitry Andric // value for that area.
5123ca95b02SDimitry Andric // We add counts of the regions of the same kind as the active region
5133ca95b02SDimitry Andric // to handle the both situations.
5143ca95b02SDimitry Andric if (I->Kind == Active->Kind)
5153ca95b02SDimitry Andric Active->ExecutionCount += I->ExecutionCount;
5163ca95b02SDimitry Andric }
5173ca95b02SDimitry Andric return Regions.drop_back(std::distance(++Active, End));
5183ca95b02SDimitry Andric }
5193ca95b02SDimitry Andric
5203ca95b02SDimitry Andric public:
5212cab237bSDimitry Andric /// Build a sorted list of CoverageSegments from a list of Regions.
5223ca95b02SDimitry Andric static std::vector<CoverageSegment>
buildSegments(MutableArrayRef<CountedRegion> Regions)5233ca95b02SDimitry Andric buildSegments(MutableArrayRef<CountedRegion> Regions) {
5243ca95b02SDimitry Andric std::vector<CoverageSegment> Segments;
5253ca95b02SDimitry Andric SegmentBuilder Builder(Segments);
5263ca95b02SDimitry Andric
5273ca95b02SDimitry Andric sortNestedRegions(Regions);
5283ca95b02SDimitry Andric ArrayRef<CountedRegion> CombinedRegions = combineRegions(Regions);
5293ca95b02SDimitry Andric
5304ba319b5SDimitry Andric LLVM_DEBUG({
5312cab237bSDimitry Andric dbgs() << "Combined regions:\n";
5322cab237bSDimitry Andric for (const auto &CR : CombinedRegions)
5332cab237bSDimitry Andric dbgs() << " " << CR.LineStart << ":" << CR.ColumnStart << " -> "
5342cab237bSDimitry Andric << CR.LineEnd << ":" << CR.ColumnEnd
5352cab237bSDimitry Andric << " (count=" << CR.ExecutionCount << ")\n";
5362cab237bSDimitry Andric });
5372cab237bSDimitry Andric
5383ca95b02SDimitry Andric Builder.buildSegmentsImpl(CombinedRegions);
5392cab237bSDimitry Andric
5402cab237bSDimitry Andric #ifndef NDEBUG
5412cab237bSDimitry Andric for (unsigned I = 1, E = Segments.size(); I < E; ++I) {
5422cab237bSDimitry Andric const auto &L = Segments[I - 1];
5432cab237bSDimitry Andric const auto &R = Segments[I];
5442cab237bSDimitry Andric if (!(L.Line < R.Line) && !(L.Line == R.Line && L.Col < R.Col)) {
5454ba319b5SDimitry Andric LLVM_DEBUG(dbgs() << " ! Segment " << L.Line << ":" << L.Col
5462cab237bSDimitry Andric << " followed by " << R.Line << ":" << R.Col << "\n");
5472cab237bSDimitry Andric assert(false && "Coverage segments not unique or sorted");
5482cab237bSDimitry Andric }
5492cab237bSDimitry Andric }
5502cab237bSDimitry Andric #endif
5512cab237bSDimitry Andric
5523ca95b02SDimitry Andric return Segments;
5533ca95b02SDimitry Andric }
5543ca95b02SDimitry Andric };
5557a7e6055SDimitry Andric
5567a7e6055SDimitry Andric } // end anonymous namespace
5573ca95b02SDimitry Andric
getUniqueSourceFiles() const5583ca95b02SDimitry Andric std::vector<StringRef> CoverageMapping::getUniqueSourceFiles() const {
5593ca95b02SDimitry Andric std::vector<StringRef> Filenames;
5603ca95b02SDimitry Andric for (const auto &Function : getCoveredFunctions())
5613ca95b02SDimitry Andric Filenames.insert(Filenames.end(), Function.Filenames.begin(),
5623ca95b02SDimitry Andric Function.Filenames.end());
563*b5893f02SDimitry Andric llvm::sort(Filenames);
5643ca95b02SDimitry Andric auto Last = std::unique(Filenames.begin(), Filenames.end());
5653ca95b02SDimitry Andric Filenames.erase(Last, Filenames.end());
5663ca95b02SDimitry Andric return Filenames;
5673ca95b02SDimitry Andric }
5683ca95b02SDimitry Andric
gatherFileIDs(StringRef SourceFile,const FunctionRecord & Function)5693ca95b02SDimitry Andric static SmallBitVector gatherFileIDs(StringRef SourceFile,
5703ca95b02SDimitry Andric const FunctionRecord &Function) {
5713ca95b02SDimitry Andric SmallBitVector FilenameEquivalence(Function.Filenames.size(), false);
5723ca95b02SDimitry Andric for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I)
5733ca95b02SDimitry Andric if (SourceFile == Function.Filenames[I])
5743ca95b02SDimitry Andric FilenameEquivalence[I] = true;
5753ca95b02SDimitry Andric return FilenameEquivalence;
5763ca95b02SDimitry Andric }
5773ca95b02SDimitry Andric
5783ca95b02SDimitry Andric /// Return the ID of the file where the definition of the function is located.
findMainViewFileID(const FunctionRecord & Function)5793ca95b02SDimitry Andric static Optional<unsigned> findMainViewFileID(const FunctionRecord &Function) {
5803ca95b02SDimitry Andric SmallBitVector IsNotExpandedFile(Function.Filenames.size(), true);
5813ca95b02SDimitry Andric for (const auto &CR : Function.CountedRegions)
5823ca95b02SDimitry Andric if (CR.Kind == CounterMappingRegion::ExpansionRegion)
5833ca95b02SDimitry Andric IsNotExpandedFile[CR.ExpandedFileID] = false;
5843ca95b02SDimitry Andric int I = IsNotExpandedFile.find_first();
5853ca95b02SDimitry Andric if (I == -1)
5863ca95b02SDimitry Andric return None;
5873ca95b02SDimitry Andric return I;
5883ca95b02SDimitry Andric }
5893ca95b02SDimitry Andric
5903ca95b02SDimitry Andric /// Check if SourceFile is the file that contains the definition of
5913ca95b02SDimitry Andric /// the Function. Return the ID of the file in that case or None otherwise.
findMainViewFileID(StringRef SourceFile,const FunctionRecord & Function)5923ca95b02SDimitry Andric static Optional<unsigned> findMainViewFileID(StringRef SourceFile,
5933ca95b02SDimitry Andric const FunctionRecord &Function) {
5943ca95b02SDimitry Andric Optional<unsigned> I = findMainViewFileID(Function);
5953ca95b02SDimitry Andric if (I && SourceFile == Function.Filenames[*I])
5963ca95b02SDimitry Andric return I;
5973ca95b02SDimitry Andric return None;
5983ca95b02SDimitry Andric }
5993ca95b02SDimitry Andric
isExpansion(const CountedRegion & R,unsigned FileID)6003ca95b02SDimitry Andric static bool isExpansion(const CountedRegion &R, unsigned FileID) {
6013ca95b02SDimitry Andric return R.Kind == CounterMappingRegion::ExpansionRegion && R.FileID == FileID;
6023ca95b02SDimitry Andric }
6033ca95b02SDimitry Andric
getCoverageForFile(StringRef Filename) const6043ca95b02SDimitry Andric CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
6053ca95b02SDimitry Andric CoverageData FileCoverage(Filename);
6067a7e6055SDimitry Andric std::vector<CountedRegion> Regions;
6073ca95b02SDimitry Andric
6083ca95b02SDimitry Andric for (const auto &Function : Functions) {
6093ca95b02SDimitry Andric auto MainFileID = findMainViewFileID(Filename, Function);
6103ca95b02SDimitry Andric auto FileIDs = gatherFileIDs(Filename, Function);
6113ca95b02SDimitry Andric for (const auto &CR : Function.CountedRegions)
6123ca95b02SDimitry Andric if (FileIDs.test(CR.FileID)) {
6133ca95b02SDimitry Andric Regions.push_back(CR);
6143ca95b02SDimitry Andric if (MainFileID && isExpansion(CR, *MainFileID))
6153ca95b02SDimitry Andric FileCoverage.Expansions.emplace_back(CR, Function);
6163ca95b02SDimitry Andric }
6173ca95b02SDimitry Andric }
6183ca95b02SDimitry Andric
6194ba319b5SDimitry Andric LLVM_DEBUG(dbgs() << "Emitting segments for file: " << Filename << "\n");
6203ca95b02SDimitry Andric FileCoverage.Segments = SegmentBuilder::buildSegments(Regions);
6213ca95b02SDimitry Andric
6223ca95b02SDimitry Andric return FileCoverage;
6233ca95b02SDimitry Andric }
6243ca95b02SDimitry Andric
6252cab237bSDimitry Andric std::vector<InstantiationGroup>
getInstantiationGroups(StringRef Filename) const6262cab237bSDimitry Andric CoverageMapping::getInstantiationGroups(StringRef Filename) const {
6273ca95b02SDimitry Andric FunctionInstantiationSetCollector InstantiationSetCollector;
6283ca95b02SDimitry Andric for (const auto &Function : Functions) {
6293ca95b02SDimitry Andric auto MainFileID = findMainViewFileID(Filename, Function);
6303ca95b02SDimitry Andric if (!MainFileID)
6313ca95b02SDimitry Andric continue;
6323ca95b02SDimitry Andric InstantiationSetCollector.insert(Function, *MainFileID);
6333ca95b02SDimitry Andric }
6343ca95b02SDimitry Andric
6352cab237bSDimitry Andric std::vector<InstantiationGroup> Result;
636fe4fed2eSDimitry Andric for (auto &InstantiationSet : InstantiationSetCollector) {
6372cab237bSDimitry Andric InstantiationGroup IG{InstantiationSet.first.first,
6382cab237bSDimitry Andric InstantiationSet.first.second,
6392cab237bSDimitry Andric std::move(InstantiationSet.second)};
6402cab237bSDimitry Andric Result.emplace_back(std::move(IG));
6413ca95b02SDimitry Andric }
6423ca95b02SDimitry Andric return Result;
6433ca95b02SDimitry Andric }
6443ca95b02SDimitry Andric
6453ca95b02SDimitry Andric CoverageData
getCoverageForFunction(const FunctionRecord & Function) const6463ca95b02SDimitry Andric CoverageMapping::getCoverageForFunction(const FunctionRecord &Function) const {
6473ca95b02SDimitry Andric auto MainFileID = findMainViewFileID(Function);
6483ca95b02SDimitry Andric if (!MainFileID)
6493ca95b02SDimitry Andric return CoverageData();
6503ca95b02SDimitry Andric
6513ca95b02SDimitry Andric CoverageData FunctionCoverage(Function.Filenames[*MainFileID]);
6527a7e6055SDimitry Andric std::vector<CountedRegion> Regions;
6533ca95b02SDimitry Andric for (const auto &CR : Function.CountedRegions)
6543ca95b02SDimitry Andric if (CR.FileID == *MainFileID) {
6553ca95b02SDimitry Andric Regions.push_back(CR);
6563ca95b02SDimitry Andric if (isExpansion(CR, *MainFileID))
6573ca95b02SDimitry Andric FunctionCoverage.Expansions.emplace_back(CR, Function);
6583ca95b02SDimitry Andric }
6593ca95b02SDimitry Andric
6604ba319b5SDimitry Andric LLVM_DEBUG(dbgs() << "Emitting segments for function: " << Function.Name
6614ba319b5SDimitry Andric << "\n");
6623ca95b02SDimitry Andric FunctionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
6633ca95b02SDimitry Andric
6643ca95b02SDimitry Andric return FunctionCoverage;
6653ca95b02SDimitry Andric }
6663ca95b02SDimitry Andric
getCoverageForExpansion(const ExpansionRecord & Expansion) const6673ca95b02SDimitry Andric CoverageData CoverageMapping::getCoverageForExpansion(
6683ca95b02SDimitry Andric const ExpansionRecord &Expansion) const {
6693ca95b02SDimitry Andric CoverageData ExpansionCoverage(
6703ca95b02SDimitry Andric Expansion.Function.Filenames[Expansion.FileID]);
6717a7e6055SDimitry Andric std::vector<CountedRegion> Regions;
6723ca95b02SDimitry Andric for (const auto &CR : Expansion.Function.CountedRegions)
6733ca95b02SDimitry Andric if (CR.FileID == Expansion.FileID) {
6743ca95b02SDimitry Andric Regions.push_back(CR);
6753ca95b02SDimitry Andric if (isExpansion(CR, Expansion.FileID))
6763ca95b02SDimitry Andric ExpansionCoverage.Expansions.emplace_back(CR, Expansion.Function);
6773ca95b02SDimitry Andric }
6783ca95b02SDimitry Andric
6794ba319b5SDimitry Andric LLVM_DEBUG(dbgs() << "Emitting segments for expansion of file "
6804ba319b5SDimitry Andric << Expansion.FileID << "\n");
6813ca95b02SDimitry Andric ExpansionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
6823ca95b02SDimitry Andric
6833ca95b02SDimitry Andric return ExpansionCoverage;
6843ca95b02SDimitry Andric }
6853ca95b02SDimitry Andric
LineCoverageStats(ArrayRef<const CoverageSegment * > LineSegments,const CoverageSegment * WrappedSegment,unsigned Line)6862cab237bSDimitry Andric LineCoverageStats::LineCoverageStats(
6872cab237bSDimitry Andric ArrayRef<const CoverageSegment *> LineSegments,
6882cab237bSDimitry Andric const CoverageSegment *WrappedSegment, unsigned Line)
6892cab237bSDimitry Andric : ExecutionCount(0), HasMultipleRegions(false), Mapped(false), Line(Line),
6902cab237bSDimitry Andric LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
6912cab237bSDimitry Andric // Find the minimum number of regions which start in this line.
6922cab237bSDimitry Andric unsigned MinRegionCount = 0;
6932cab237bSDimitry Andric auto isStartOfRegion = [](const CoverageSegment *S) {
6942cab237bSDimitry Andric return !S->IsGapRegion && S->HasCount && S->IsRegionEntry;
6952cab237bSDimitry Andric };
6962cab237bSDimitry Andric for (unsigned I = 0; I < LineSegments.size() && MinRegionCount < 2; ++I)
6972cab237bSDimitry Andric if (isStartOfRegion(LineSegments[I]))
6982cab237bSDimitry Andric ++MinRegionCount;
6992cab237bSDimitry Andric
7002cab237bSDimitry Andric bool StartOfSkippedRegion = !LineSegments.empty() &&
7012cab237bSDimitry Andric !LineSegments.front()->HasCount &&
7022cab237bSDimitry Andric LineSegments.front()->IsRegionEntry;
7032cab237bSDimitry Andric
7042cab237bSDimitry Andric HasMultipleRegions = MinRegionCount > 1;
7052cab237bSDimitry Andric Mapped =
7062cab237bSDimitry Andric !StartOfSkippedRegion &&
7072cab237bSDimitry Andric ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0));
7082cab237bSDimitry Andric
7092cab237bSDimitry Andric if (!Mapped)
7102cab237bSDimitry Andric return;
7112cab237bSDimitry Andric
7122cab237bSDimitry Andric // Pick the max count from the non-gap, region entry segments and the
7132cab237bSDimitry Andric // wrapped count.
7142cab237bSDimitry Andric if (WrappedSegment)
7152cab237bSDimitry Andric ExecutionCount = WrappedSegment->Count;
7162cab237bSDimitry Andric if (!MinRegionCount)
7172cab237bSDimitry Andric return;
7182cab237bSDimitry Andric for (const auto *LS : LineSegments)
7192cab237bSDimitry Andric if (isStartOfRegion(LS))
7202cab237bSDimitry Andric ExecutionCount = std::max(ExecutionCount, LS->Count);
7212cab237bSDimitry Andric }
7222cab237bSDimitry Andric
operator ++()7232cab237bSDimitry Andric LineCoverageIterator &LineCoverageIterator::operator++() {
7242cab237bSDimitry Andric if (Next == CD.end()) {
7252cab237bSDimitry Andric Stats = LineCoverageStats();
7262cab237bSDimitry Andric Ended = true;
7272cab237bSDimitry Andric return *this;
7282cab237bSDimitry Andric }
7292cab237bSDimitry Andric if (Segments.size())
7302cab237bSDimitry Andric WrappedSegment = Segments.back();
7312cab237bSDimitry Andric Segments.clear();
7322cab237bSDimitry Andric while (Next != CD.end() && Next->Line == Line)
7332cab237bSDimitry Andric Segments.push_back(&*Next++);
7342cab237bSDimitry Andric Stats = LineCoverageStats(Segments, WrappedSegment, Line);
7352cab237bSDimitry Andric ++Line;
7362cab237bSDimitry Andric return *this;
7372cab237bSDimitry Andric }
7382cab237bSDimitry Andric
getCoverageMapErrString(coveragemap_error Err)7397a7e6055SDimitry Andric static std::string getCoverageMapErrString(coveragemap_error Err) {
7403ca95b02SDimitry Andric switch (Err) {
7413ca95b02SDimitry Andric case coveragemap_error::success:
7423ca95b02SDimitry Andric return "Success";
7433ca95b02SDimitry Andric case coveragemap_error::eof:
7443ca95b02SDimitry Andric return "End of File";
7453ca95b02SDimitry Andric case coveragemap_error::no_data_found:
7463ca95b02SDimitry Andric return "No coverage data found";
7473ca95b02SDimitry Andric case coveragemap_error::unsupported_version:
7483ca95b02SDimitry Andric return "Unsupported coverage format version";
7493ca95b02SDimitry Andric case coveragemap_error::truncated:
7503ca95b02SDimitry Andric return "Truncated coverage data";
7513ca95b02SDimitry Andric case coveragemap_error::malformed:
7523ca95b02SDimitry Andric return "Malformed coverage data";
7533ca95b02SDimitry Andric }
7543ca95b02SDimitry Andric llvm_unreachable("A value of coveragemap_error has no message.");
7553ca95b02SDimitry Andric }
7563ca95b02SDimitry Andric
7577a7e6055SDimitry Andric namespace {
7587a7e6055SDimitry Andric
7593ca95b02SDimitry Andric // FIXME: This class is only here to support the transition to llvm::Error. It
7603ca95b02SDimitry Andric // will be removed once this transition is complete. Clients should prefer to
7613ca95b02SDimitry Andric // deal with the Error value directly, rather than converting to error_code.
7623ca95b02SDimitry Andric class CoverageMappingErrorCategoryType : public std::error_category {
name() const763d88c1a5aSDimitry Andric const char *name() const noexcept override { return "llvm.coveragemap"; }
message(int IE) const7643ca95b02SDimitry Andric std::string message(int IE) const override {
7653ca95b02SDimitry Andric return getCoverageMapErrString(static_cast<coveragemap_error>(IE));
7663ca95b02SDimitry Andric }
7673ca95b02SDimitry Andric };
7687a7e6055SDimitry Andric
7693ca95b02SDimitry Andric } // end anonymous namespace
7703ca95b02SDimitry Andric
message() const7713ca95b02SDimitry Andric std::string CoverageMapError::message() const {
7723ca95b02SDimitry Andric return getCoverageMapErrString(Err);
7733ca95b02SDimitry Andric }
7743ca95b02SDimitry Andric
7753ca95b02SDimitry Andric static ManagedStatic<CoverageMappingErrorCategoryType> ErrorCategory;
7763ca95b02SDimitry Andric
coveragemap_category()7773ca95b02SDimitry Andric const std::error_category &llvm::coverage::coveragemap_category() {
7783ca95b02SDimitry Andric return *ErrorCategory;
7793ca95b02SDimitry Andric }
7803ca95b02SDimitry Andric
7813ca95b02SDimitry Andric char CoverageMapError::ID = 0;
782