xref: /freebsd/contrib/llvm-project/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp (revision 1ac55f4cb0001fed92329746c730aa9a947c09a5)
10b57cec5SDimitry Andric //===- CoverageMapping.cpp - Code coverage mapping support ----------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file contains support for clang's and llvm's instrumentation based
100b57cec5SDimitry Andric // code coverage.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/ProfileData/Coverage/CoverageMapping.h"
150b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
160b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
170b57cec5SDimitry Andric #include "llvm/ADT/SmallBitVector.h"
180b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
190b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
20*1ac55f4cSDimitry Andric #include "llvm/Object/BuildID.h"
210b57cec5SDimitry Andric #include "llvm/ProfileData/Coverage/CoverageMappingReader.h"
220b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfReader.h"
230b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
240b57cec5SDimitry Andric #include "llvm/Support/Errc.h"
250b57cec5SDimitry Andric #include "llvm/Support/Error.h"
260b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
270b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
280b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
290b57cec5SDimitry Andric #include <algorithm>
300b57cec5SDimitry Andric #include <cassert>
310b57cec5SDimitry Andric #include <cstdint>
320b57cec5SDimitry Andric #include <iterator>
330b57cec5SDimitry Andric #include <map>
340b57cec5SDimitry Andric #include <memory>
35bdd1243dSDimitry Andric #include <optional>
360b57cec5SDimitry Andric #include <string>
370b57cec5SDimitry Andric #include <system_error>
380b57cec5SDimitry Andric #include <utility>
390b57cec5SDimitry Andric #include <vector>
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric using namespace llvm;
420b57cec5SDimitry Andric using namespace coverage;
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric #define DEBUG_TYPE "coverage-mapping"
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric Counter CounterExpressionBuilder::get(const CounterExpression &E) {
470b57cec5SDimitry Andric   auto It = ExpressionIndices.find(E);
480b57cec5SDimitry Andric   if (It != ExpressionIndices.end())
490b57cec5SDimitry Andric     return Counter::getExpression(It->second);
500b57cec5SDimitry Andric   unsigned I = Expressions.size();
510b57cec5SDimitry Andric   Expressions.push_back(E);
520b57cec5SDimitry Andric   ExpressionIndices[E] = I;
530b57cec5SDimitry Andric   return Counter::getExpression(I);
540b57cec5SDimitry Andric }
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric void CounterExpressionBuilder::extractTerms(Counter C, int Factor,
570b57cec5SDimitry Andric                                             SmallVectorImpl<Term> &Terms) {
580b57cec5SDimitry Andric   switch (C.getKind()) {
590b57cec5SDimitry Andric   case Counter::Zero:
600b57cec5SDimitry Andric     break;
610b57cec5SDimitry Andric   case Counter::CounterValueReference:
620b57cec5SDimitry Andric     Terms.emplace_back(C.getCounterID(), Factor);
630b57cec5SDimitry Andric     break;
640b57cec5SDimitry Andric   case Counter::Expression:
650b57cec5SDimitry Andric     const auto &E = Expressions[C.getExpressionID()];
660b57cec5SDimitry Andric     extractTerms(E.LHS, Factor, Terms);
670b57cec5SDimitry Andric     extractTerms(
680b57cec5SDimitry Andric         E.RHS, E.Kind == CounterExpression::Subtract ? -Factor : Factor, Terms);
690b57cec5SDimitry Andric     break;
700b57cec5SDimitry Andric   }
710b57cec5SDimitry Andric }
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric Counter CounterExpressionBuilder::simplify(Counter ExpressionTree) {
740b57cec5SDimitry Andric   // Gather constant terms.
750b57cec5SDimitry Andric   SmallVector<Term, 32> Terms;
760b57cec5SDimitry Andric   extractTerms(ExpressionTree, +1, Terms);
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric   // If there are no terms, this is just a zero. The algorithm below assumes at
790b57cec5SDimitry Andric   // least one term.
800b57cec5SDimitry Andric   if (Terms.size() == 0)
810b57cec5SDimitry Andric     return Counter::getZero();
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric   // Group the terms by counter ID.
840b57cec5SDimitry Andric   llvm::sort(Terms, [](const Term &LHS, const Term &RHS) {
850b57cec5SDimitry Andric     return LHS.CounterID < RHS.CounterID;
860b57cec5SDimitry Andric   });
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric   // Combine terms by counter ID to eliminate counters that sum to zero.
890b57cec5SDimitry Andric   auto Prev = Terms.begin();
900b57cec5SDimitry Andric   for (auto I = Prev + 1, E = Terms.end(); I != E; ++I) {
910b57cec5SDimitry Andric     if (I->CounterID == Prev->CounterID) {
920b57cec5SDimitry Andric       Prev->Factor += I->Factor;
930b57cec5SDimitry Andric       continue;
940b57cec5SDimitry Andric     }
950b57cec5SDimitry Andric     ++Prev;
960b57cec5SDimitry Andric     *Prev = *I;
970b57cec5SDimitry Andric   }
980b57cec5SDimitry Andric   Terms.erase(++Prev, Terms.end());
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric   Counter C;
1010b57cec5SDimitry Andric   // Create additions. We do this before subtractions to avoid constructs like
1020b57cec5SDimitry Andric   // ((0 - X) + Y), as opposed to (Y - X).
1030b57cec5SDimitry Andric   for (auto T : Terms) {
1040b57cec5SDimitry Andric     if (T.Factor <= 0)
1050b57cec5SDimitry Andric       continue;
1060b57cec5SDimitry Andric     for (int I = 0; I < T.Factor; ++I)
1070b57cec5SDimitry Andric       if (C.isZero())
1080b57cec5SDimitry Andric         C = Counter::getCounter(T.CounterID);
1090b57cec5SDimitry Andric       else
1100b57cec5SDimitry Andric         C = get(CounterExpression(CounterExpression::Add, C,
1110b57cec5SDimitry Andric                                   Counter::getCounter(T.CounterID)));
1120b57cec5SDimitry Andric   }
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric   // Create subtractions.
1150b57cec5SDimitry Andric   for (auto T : Terms) {
1160b57cec5SDimitry Andric     if (T.Factor >= 0)
1170b57cec5SDimitry Andric       continue;
1180b57cec5SDimitry Andric     for (int I = 0; I < -T.Factor; ++I)
1190b57cec5SDimitry Andric       C = get(CounterExpression(CounterExpression::Subtract, C,
1200b57cec5SDimitry Andric                                 Counter::getCounter(T.CounterID)));
1210b57cec5SDimitry Andric   }
1220b57cec5SDimitry Andric   return C;
1230b57cec5SDimitry Andric }
1240b57cec5SDimitry Andric 
12581ad6265SDimitry Andric Counter CounterExpressionBuilder::add(Counter LHS, Counter RHS, bool Simplify) {
12681ad6265SDimitry Andric   auto Cnt = get(CounterExpression(CounterExpression::Add, LHS, RHS));
12781ad6265SDimitry Andric   return Simplify ? simplify(Cnt) : Cnt;
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric 
13081ad6265SDimitry Andric Counter CounterExpressionBuilder::subtract(Counter LHS, Counter RHS,
13181ad6265SDimitry Andric                                            bool Simplify) {
13281ad6265SDimitry Andric   auto Cnt = get(CounterExpression(CounterExpression::Subtract, LHS, RHS));
13381ad6265SDimitry Andric   return Simplify ? simplify(Cnt) : Cnt;
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric void CounterMappingContext::dump(const Counter &C, raw_ostream &OS) const {
1370b57cec5SDimitry Andric   switch (C.getKind()) {
1380b57cec5SDimitry Andric   case Counter::Zero:
1390b57cec5SDimitry Andric     OS << '0';
1400b57cec5SDimitry Andric     return;
1410b57cec5SDimitry Andric   case Counter::CounterValueReference:
1420b57cec5SDimitry Andric     OS << '#' << C.getCounterID();
1430b57cec5SDimitry Andric     break;
1440b57cec5SDimitry Andric   case Counter::Expression: {
1450b57cec5SDimitry Andric     if (C.getExpressionID() >= Expressions.size())
1460b57cec5SDimitry Andric       return;
1470b57cec5SDimitry Andric     const auto &E = Expressions[C.getExpressionID()];
1480b57cec5SDimitry Andric     OS << '(';
1490b57cec5SDimitry Andric     dump(E.LHS, OS);
1500b57cec5SDimitry Andric     OS << (E.Kind == CounterExpression::Subtract ? " - " : " + ");
1510b57cec5SDimitry Andric     dump(E.RHS, OS);
1520b57cec5SDimitry Andric     OS << ')';
1530b57cec5SDimitry Andric     break;
1540b57cec5SDimitry Andric   }
1550b57cec5SDimitry Andric   }
1560b57cec5SDimitry Andric   if (CounterValues.empty())
1570b57cec5SDimitry Andric     return;
1580b57cec5SDimitry Andric   Expected<int64_t> Value = evaluate(C);
1590b57cec5SDimitry Andric   if (auto E = Value.takeError()) {
1600b57cec5SDimitry Andric     consumeError(std::move(E));
1610b57cec5SDimitry Andric     return;
1620b57cec5SDimitry Andric   }
1630b57cec5SDimitry Andric   OS << '[' << *Value << ']';
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric Expected<int64_t> CounterMappingContext::evaluate(const Counter &C) const {
1670b57cec5SDimitry Andric   switch (C.getKind()) {
1680b57cec5SDimitry Andric   case Counter::Zero:
1690b57cec5SDimitry Andric     return 0;
1700b57cec5SDimitry Andric   case Counter::CounterValueReference:
1710b57cec5SDimitry Andric     if (C.getCounterID() >= CounterValues.size())
1720b57cec5SDimitry Andric       return errorCodeToError(errc::argument_out_of_domain);
1730b57cec5SDimitry Andric     return CounterValues[C.getCounterID()];
1740b57cec5SDimitry Andric   case Counter::Expression: {
1750b57cec5SDimitry Andric     if (C.getExpressionID() >= Expressions.size())
1760b57cec5SDimitry Andric       return errorCodeToError(errc::argument_out_of_domain);
1770b57cec5SDimitry Andric     const auto &E = Expressions[C.getExpressionID()];
1780b57cec5SDimitry Andric     Expected<int64_t> LHS = evaluate(E.LHS);
1790b57cec5SDimitry Andric     if (!LHS)
1800b57cec5SDimitry Andric       return LHS;
1810b57cec5SDimitry Andric     Expected<int64_t> RHS = evaluate(E.RHS);
1820b57cec5SDimitry Andric     if (!RHS)
1830b57cec5SDimitry Andric       return RHS;
1840b57cec5SDimitry Andric     return E.Kind == CounterExpression::Subtract ? *LHS - *RHS : *LHS + *RHS;
1850b57cec5SDimitry Andric   }
1860b57cec5SDimitry Andric   }
1870b57cec5SDimitry Andric   llvm_unreachable("Unhandled CounterKind");
1880b57cec5SDimitry Andric }
1890b57cec5SDimitry Andric 
190fe6060f1SDimitry Andric unsigned CounterMappingContext::getMaxCounterID(const Counter &C) const {
191fe6060f1SDimitry Andric   switch (C.getKind()) {
192fe6060f1SDimitry Andric   case Counter::Zero:
193fe6060f1SDimitry Andric     return 0;
194fe6060f1SDimitry Andric   case Counter::CounterValueReference:
195fe6060f1SDimitry Andric     return C.getCounterID();
196fe6060f1SDimitry Andric   case Counter::Expression: {
197fe6060f1SDimitry Andric     if (C.getExpressionID() >= Expressions.size())
198fe6060f1SDimitry Andric       return 0;
199fe6060f1SDimitry Andric     const auto &E = Expressions[C.getExpressionID()];
200fe6060f1SDimitry Andric     return std::max(getMaxCounterID(E.LHS), getMaxCounterID(E.RHS));
201fe6060f1SDimitry Andric   }
202fe6060f1SDimitry Andric   }
203fe6060f1SDimitry Andric   llvm_unreachable("Unhandled CounterKind");
204fe6060f1SDimitry Andric }
205fe6060f1SDimitry Andric 
2060b57cec5SDimitry Andric void FunctionRecordIterator::skipOtherFiles() {
2070b57cec5SDimitry Andric   while (Current != Records.end() && !Filename.empty() &&
2080b57cec5SDimitry Andric          Filename != Current->Filenames[0])
2090b57cec5SDimitry Andric     ++Current;
2100b57cec5SDimitry Andric   if (Current == Records.end())
2110b57cec5SDimitry Andric     *this = FunctionRecordIterator();
2120b57cec5SDimitry Andric }
2130b57cec5SDimitry Andric 
2148bcb0991SDimitry Andric ArrayRef<unsigned> CoverageMapping::getImpreciseRecordIndicesForFilename(
2158bcb0991SDimitry Andric     StringRef Filename) const {
2168bcb0991SDimitry Andric   size_t FilenameHash = hash_value(Filename);
2178bcb0991SDimitry Andric   auto RecordIt = FilenameHash2RecordIndices.find(FilenameHash);
2188bcb0991SDimitry Andric   if (RecordIt == FilenameHash2RecordIndices.end())
2198bcb0991SDimitry Andric     return {};
2208bcb0991SDimitry Andric   return RecordIt->second;
2218bcb0991SDimitry Andric }
2228bcb0991SDimitry Andric 
223fe6060f1SDimitry Andric static unsigned getMaxCounterID(const CounterMappingContext &Ctx,
224fe6060f1SDimitry Andric                                 const CoverageMappingRecord &Record) {
225fe6060f1SDimitry Andric   unsigned MaxCounterID = 0;
226fe6060f1SDimitry Andric   for (const auto &Region : Record.MappingRegions) {
227fe6060f1SDimitry Andric     MaxCounterID = std::max(MaxCounterID, Ctx.getMaxCounterID(Region.Count));
228fe6060f1SDimitry Andric   }
229fe6060f1SDimitry Andric   return MaxCounterID;
230fe6060f1SDimitry Andric }
231fe6060f1SDimitry Andric 
2320b57cec5SDimitry Andric Error CoverageMapping::loadFunctionRecord(
2330b57cec5SDimitry Andric     const CoverageMappingRecord &Record,
2340b57cec5SDimitry Andric     IndexedInstrProfReader &ProfileReader) {
2350b57cec5SDimitry Andric   StringRef OrigFuncName = Record.FunctionName;
2360b57cec5SDimitry Andric   if (OrigFuncName.empty())
2370b57cec5SDimitry Andric     return make_error<CoverageMapError>(coveragemap_error::malformed);
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric   if (Record.Filenames.empty())
2400b57cec5SDimitry Andric     OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName);
2410b57cec5SDimitry Andric   else
2420b57cec5SDimitry Andric     OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]);
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric   CounterMappingContext Ctx(Record.Expressions);
2450b57cec5SDimitry Andric 
2460b57cec5SDimitry Andric   std::vector<uint64_t> Counts;
2470b57cec5SDimitry Andric   if (Error E = ProfileReader.getFunctionCounts(Record.FunctionName,
2480b57cec5SDimitry Andric                                                 Record.FunctionHash, Counts)) {
2490b57cec5SDimitry Andric     instrprof_error IPE = InstrProfError::take(std::move(E));
2500b57cec5SDimitry Andric     if (IPE == instrprof_error::hash_mismatch) {
2515ffd83dbSDimitry Andric       FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
2525ffd83dbSDimitry Andric                                       Record.FunctionHash);
2530b57cec5SDimitry Andric       return Error::success();
2540b57cec5SDimitry Andric     } else if (IPE != instrprof_error::unknown_function)
2550b57cec5SDimitry Andric       return make_error<InstrProfError>(IPE);
256fe6060f1SDimitry Andric     Counts.assign(getMaxCounterID(Ctx, Record) + 1, 0);
2570b57cec5SDimitry Andric   }
2580b57cec5SDimitry Andric   Ctx.setCounts(Counts);
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric   assert(!Record.MappingRegions.empty() && "Function has no regions");
2610b57cec5SDimitry Andric 
2620b57cec5SDimitry Andric   // This coverage record is a zero region for a function that's unused in
2630b57cec5SDimitry Andric   // some TU, but used in a different TU. Ignore it. The coverage maps from the
2640b57cec5SDimitry Andric   // the other TU will either be loaded (providing full region counts) or they
2650b57cec5SDimitry Andric   // won't (in which case we don't unintuitively report functions as uncovered
2660b57cec5SDimitry Andric   // when they have non-zero counts in the profile).
2670b57cec5SDimitry Andric   if (Record.MappingRegions.size() == 1 &&
2680b57cec5SDimitry Andric       Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
2690b57cec5SDimitry Andric     return Error::success();
2700b57cec5SDimitry Andric 
2710b57cec5SDimitry Andric   FunctionRecord Function(OrigFuncName, Record.Filenames);
2720b57cec5SDimitry Andric   for (const auto &Region : Record.MappingRegions) {
2730b57cec5SDimitry Andric     Expected<int64_t> ExecutionCount = Ctx.evaluate(Region.Count);
2740b57cec5SDimitry Andric     if (auto E = ExecutionCount.takeError()) {
2750b57cec5SDimitry Andric       consumeError(std::move(E));
2760b57cec5SDimitry Andric       return Error::success();
2770b57cec5SDimitry Andric     }
278e8d8bef9SDimitry Andric     Expected<int64_t> AltExecutionCount = Ctx.evaluate(Region.FalseCount);
279e8d8bef9SDimitry Andric     if (auto E = AltExecutionCount.takeError()) {
280e8d8bef9SDimitry Andric       consumeError(std::move(E));
281e8d8bef9SDimitry Andric       return Error::success();
282e8d8bef9SDimitry Andric     }
283e8d8bef9SDimitry Andric     Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount);
2840b57cec5SDimitry Andric   }
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric   // Don't create records for (filenames, function) pairs we've already seen.
2870b57cec5SDimitry Andric   auto FilenamesHash = hash_combine_range(Record.Filenames.begin(),
2880b57cec5SDimitry Andric                                           Record.Filenames.end());
2890b57cec5SDimitry Andric   if (!RecordProvenance[FilenamesHash].insert(hash_value(OrigFuncName)).second)
2900b57cec5SDimitry Andric     return Error::success();
2910b57cec5SDimitry Andric 
2920b57cec5SDimitry Andric   Functions.push_back(std::move(Function));
2938bcb0991SDimitry Andric 
2948bcb0991SDimitry Andric   // Performance optimization: keep track of the indices of the function records
2958bcb0991SDimitry Andric   // which correspond to each filename. This can be used to substantially speed
2968bcb0991SDimitry Andric   // up queries for coverage info in a file.
2978bcb0991SDimitry Andric   unsigned RecordIndex = Functions.size() - 1;
2988bcb0991SDimitry Andric   for (StringRef Filename : Record.Filenames) {
2998bcb0991SDimitry Andric     auto &RecordIndices = FilenameHash2RecordIndices[hash_value(Filename)];
3008bcb0991SDimitry Andric     // Note that there may be duplicates in the filename set for a function
3018bcb0991SDimitry Andric     // record, because of e.g. macro expansions in the function in which both
3028bcb0991SDimitry Andric     // the macro and the function are defined in the same file.
3038bcb0991SDimitry Andric     if (RecordIndices.empty() || RecordIndices.back() != RecordIndex)
3048bcb0991SDimitry Andric       RecordIndices.push_back(RecordIndex);
3058bcb0991SDimitry Andric   }
3068bcb0991SDimitry Andric 
3070b57cec5SDimitry Andric   return Error::success();
3080b57cec5SDimitry Andric }
3090b57cec5SDimitry Andric 
310fe6060f1SDimitry Andric // This function is for memory optimization by shortening the lifetimes
311fe6060f1SDimitry Andric // of CoverageMappingReader instances.
312fe6060f1SDimitry Andric Error CoverageMapping::loadFromReaders(
313fe6060f1SDimitry Andric     ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
314fe6060f1SDimitry Andric     IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage) {
315fe6060f1SDimitry Andric   for (const auto &CoverageReader : CoverageReaders) {
316fe6060f1SDimitry Andric     for (auto RecordOrErr : *CoverageReader) {
317fe6060f1SDimitry Andric       if (Error E = RecordOrErr.takeError())
318fe6060f1SDimitry Andric         return E;
319fe6060f1SDimitry Andric       const auto &Record = *RecordOrErr;
320fe6060f1SDimitry Andric       if (Error E = Coverage.loadFunctionRecord(Record, ProfileReader))
321fe6060f1SDimitry Andric         return E;
322fe6060f1SDimitry Andric     }
323fe6060f1SDimitry Andric   }
324fe6060f1SDimitry Andric   return Error::success();
325fe6060f1SDimitry Andric }
326fe6060f1SDimitry Andric 
3270b57cec5SDimitry Andric Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
3280b57cec5SDimitry Andric     ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
3290b57cec5SDimitry Andric     IndexedInstrProfReader &ProfileReader) {
3300b57cec5SDimitry Andric   auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
331fe6060f1SDimitry Andric   if (Error E = loadFromReaders(CoverageReaders, ProfileReader, *Coverage))
3320b57cec5SDimitry Andric     return std::move(E);
3330b57cec5SDimitry Andric   return std::move(Coverage);
3340b57cec5SDimitry Andric }
3350b57cec5SDimitry Andric 
3368bcb0991SDimitry Andric // If E is a no_data_found error, returns success. Otherwise returns E.
3378bcb0991SDimitry Andric static Error handleMaybeNoDataFoundError(Error E) {
3388bcb0991SDimitry Andric   return handleErrors(
3398bcb0991SDimitry Andric       std::move(E), [](const CoverageMapError &CME) {
3408bcb0991SDimitry Andric         if (CME.get() == coveragemap_error::no_data_found)
3418bcb0991SDimitry Andric           return static_cast<Error>(Error::success());
3428bcb0991SDimitry Andric         return make_error<CoverageMapError>(CME.get());
3438bcb0991SDimitry Andric       });
3448bcb0991SDimitry Andric }
3458bcb0991SDimitry Andric 
346*1ac55f4cSDimitry Andric Error CoverageMapping::loadFromFile(
347*1ac55f4cSDimitry Andric     StringRef Filename, StringRef Arch, StringRef CompilationDir,
348*1ac55f4cSDimitry Andric     IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage,
349*1ac55f4cSDimitry Andric     bool &DataFound, SmallVectorImpl<object::BuildID> *FoundBinaryIDs) {
350*1ac55f4cSDimitry Andric   auto CovMappingBufOrErr = MemoryBuffer::getFileOrSTDIN(
351*1ac55f4cSDimitry Andric       Filename, /*IsText=*/false, /*RequiresNullTerminator=*/false);
352*1ac55f4cSDimitry Andric   if (std::error_code EC = CovMappingBufOrErr.getError())
353*1ac55f4cSDimitry Andric     return createFileError(Filename, errorCodeToError(EC));
354*1ac55f4cSDimitry Andric   MemoryBufferRef CovMappingBufRef =
355*1ac55f4cSDimitry Andric       CovMappingBufOrErr.get()->getMemBufferRef();
356*1ac55f4cSDimitry Andric   SmallVector<std::unique_ptr<MemoryBuffer>, 4> Buffers;
357*1ac55f4cSDimitry Andric 
358*1ac55f4cSDimitry Andric   SmallVector<object::BuildIDRef> BinaryIDs;
359*1ac55f4cSDimitry Andric   auto CoverageReadersOrErr = BinaryCoverageReader::create(
360*1ac55f4cSDimitry Andric       CovMappingBufRef, Arch, Buffers, CompilationDir,
361*1ac55f4cSDimitry Andric       FoundBinaryIDs ? &BinaryIDs : nullptr);
362*1ac55f4cSDimitry Andric   if (Error E = CoverageReadersOrErr.takeError()) {
363*1ac55f4cSDimitry Andric     E = handleMaybeNoDataFoundError(std::move(E));
364*1ac55f4cSDimitry Andric     if (E)
365*1ac55f4cSDimitry Andric       return createFileError(Filename, std::move(E));
366*1ac55f4cSDimitry Andric     return E;
367*1ac55f4cSDimitry Andric   }
368*1ac55f4cSDimitry Andric 
369*1ac55f4cSDimitry Andric   SmallVector<std::unique_ptr<CoverageMappingReader>, 4> Readers;
370*1ac55f4cSDimitry Andric   for (auto &Reader : CoverageReadersOrErr.get())
371*1ac55f4cSDimitry Andric     Readers.push_back(std::move(Reader));
372*1ac55f4cSDimitry Andric   if (FoundBinaryIDs && !Readers.empty()) {
373*1ac55f4cSDimitry Andric     llvm::append_range(*FoundBinaryIDs,
374*1ac55f4cSDimitry Andric                        llvm::map_range(BinaryIDs, [](object::BuildIDRef BID) {
375*1ac55f4cSDimitry Andric                          return object::BuildID(BID);
376*1ac55f4cSDimitry Andric                        }));
377*1ac55f4cSDimitry Andric   }
378*1ac55f4cSDimitry Andric   DataFound |= !Readers.empty();
379*1ac55f4cSDimitry Andric   if (Error E = loadFromReaders(Readers, ProfileReader, Coverage))
380*1ac55f4cSDimitry Andric     return createFileError(Filename, std::move(E));
381*1ac55f4cSDimitry Andric   return Error::success();
382*1ac55f4cSDimitry Andric }
383*1ac55f4cSDimitry Andric 
3840b57cec5SDimitry Andric Expected<std::unique_ptr<CoverageMapping>>
3850b57cec5SDimitry Andric CoverageMapping::load(ArrayRef<StringRef> ObjectFilenames,
386fe6060f1SDimitry Andric                       StringRef ProfileFilename, ArrayRef<StringRef> Arches,
387*1ac55f4cSDimitry Andric                       StringRef CompilationDir,
388*1ac55f4cSDimitry Andric                       const object::BuildIDFetcher *BIDFetcher) {
3890b57cec5SDimitry Andric   auto ProfileReaderOrErr = IndexedInstrProfReader::create(ProfileFilename);
3900b57cec5SDimitry Andric   if (Error E = ProfileReaderOrErr.takeError())
391fcaf7f86SDimitry Andric     return createFileError(ProfileFilename, std::move(E));
3920b57cec5SDimitry Andric   auto ProfileReader = std::move(ProfileReaderOrErr.get());
393fe6060f1SDimitry Andric   auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
394fe6060f1SDimitry Andric   bool DataFound = false;
3950b57cec5SDimitry Andric 
396*1ac55f4cSDimitry Andric   auto GetArch = [&](size_t Idx) {
397*1ac55f4cSDimitry Andric     if (Arches.empty())
398*1ac55f4cSDimitry Andric       return StringRef();
399*1ac55f4cSDimitry Andric     if (Arches.size() == 1)
400*1ac55f4cSDimitry Andric       return Arches.front();
401*1ac55f4cSDimitry Andric     return Arches[Idx];
402*1ac55f4cSDimitry Andric   };
403*1ac55f4cSDimitry Andric 
404*1ac55f4cSDimitry Andric   SmallVector<object::BuildID> FoundBinaryIDs;
4050b57cec5SDimitry Andric   for (const auto &File : llvm::enumerate(ObjectFilenames)) {
406*1ac55f4cSDimitry Andric     if (Error E =
407*1ac55f4cSDimitry Andric             loadFromFile(File.value(), GetArch(File.index()), CompilationDir,
408*1ac55f4cSDimitry Andric                          *ProfileReader, *Coverage, DataFound, &FoundBinaryIDs))
409*1ac55f4cSDimitry Andric       return std::move(E);
4108bcb0991SDimitry Andric   }
411fe6060f1SDimitry Andric 
412*1ac55f4cSDimitry Andric   if (BIDFetcher) {
413*1ac55f4cSDimitry Andric     std::vector<object::BuildID> ProfileBinaryIDs;
414*1ac55f4cSDimitry Andric     if (Error E = ProfileReader->readBinaryIds(ProfileBinaryIDs))
415*1ac55f4cSDimitry Andric       return createFileError(ProfileFilename, std::move(E));
416*1ac55f4cSDimitry Andric 
417*1ac55f4cSDimitry Andric     SmallVector<object::BuildIDRef> BinaryIDsToFetch;
418*1ac55f4cSDimitry Andric     if (!ProfileBinaryIDs.empty()) {
419*1ac55f4cSDimitry Andric       const auto &Compare = [](object::BuildIDRef A, object::BuildIDRef B) {
420*1ac55f4cSDimitry Andric         return std::lexicographical_compare(A.begin(), A.end(), B.begin(),
421*1ac55f4cSDimitry Andric                                             B.end());
422*1ac55f4cSDimitry Andric       };
423*1ac55f4cSDimitry Andric       llvm::sort(FoundBinaryIDs, Compare);
424*1ac55f4cSDimitry Andric       std::set_difference(
425*1ac55f4cSDimitry Andric           ProfileBinaryIDs.begin(), ProfileBinaryIDs.end(),
426*1ac55f4cSDimitry Andric           FoundBinaryIDs.begin(), FoundBinaryIDs.end(),
427*1ac55f4cSDimitry Andric           std::inserter(BinaryIDsToFetch, BinaryIDsToFetch.end()), Compare);
4280b57cec5SDimitry Andric     }
429*1ac55f4cSDimitry Andric 
430*1ac55f4cSDimitry Andric     for (object::BuildIDRef BinaryID : BinaryIDsToFetch) {
431*1ac55f4cSDimitry Andric       std::optional<std::string> PathOpt = BIDFetcher->fetch(BinaryID);
432*1ac55f4cSDimitry Andric       if (!PathOpt)
433*1ac55f4cSDimitry Andric         continue;
434*1ac55f4cSDimitry Andric       std::string Path = std::move(*PathOpt);
435*1ac55f4cSDimitry Andric       StringRef Arch = Arches.size() == 1 ? Arches.front() : StringRef();
436*1ac55f4cSDimitry Andric       if (Error E = loadFromFile(Path, Arch, CompilationDir, *ProfileReader,
437*1ac55f4cSDimitry Andric                                  *Coverage, DataFound))
438*1ac55f4cSDimitry Andric         return std::move(E);
439*1ac55f4cSDimitry Andric     }
440*1ac55f4cSDimitry Andric   }
441*1ac55f4cSDimitry Andric 
442*1ac55f4cSDimitry Andric   if (!DataFound)
443fcaf7f86SDimitry Andric     return createFileError(
444fcaf7f86SDimitry Andric         join(ObjectFilenames.begin(), ObjectFilenames.end(), ", "),
445fcaf7f86SDimitry Andric         make_error<CoverageMapError>(coveragemap_error::no_data_found));
446fe6060f1SDimitry Andric   return std::move(Coverage);
4470b57cec5SDimitry Andric }
4480b57cec5SDimitry Andric 
4490b57cec5SDimitry Andric namespace {
4500b57cec5SDimitry Andric 
4510b57cec5SDimitry Andric /// Distributes functions into instantiation sets.
4520b57cec5SDimitry Andric ///
4530b57cec5SDimitry Andric /// An instantiation set is a collection of functions that have the same source
4540b57cec5SDimitry Andric /// code, ie, template functions specializations.
4550b57cec5SDimitry Andric class FunctionInstantiationSetCollector {
4560b57cec5SDimitry Andric   using MapT = std::map<LineColPair, std::vector<const FunctionRecord *>>;
4570b57cec5SDimitry Andric   MapT InstantiatedFunctions;
4580b57cec5SDimitry Andric 
4590b57cec5SDimitry Andric public:
4600b57cec5SDimitry Andric   void insert(const FunctionRecord &Function, unsigned FileID) {
4610b57cec5SDimitry Andric     auto I = Function.CountedRegions.begin(), E = Function.CountedRegions.end();
4620b57cec5SDimitry Andric     while (I != E && I->FileID != FileID)
4630b57cec5SDimitry Andric       ++I;
4640b57cec5SDimitry Andric     assert(I != E && "function does not cover the given file");
4650b57cec5SDimitry Andric     auto &Functions = InstantiatedFunctions[I->startLoc()];
4660b57cec5SDimitry Andric     Functions.push_back(&Function);
4670b57cec5SDimitry Andric   }
4680b57cec5SDimitry Andric 
4690b57cec5SDimitry Andric   MapT::iterator begin() { return InstantiatedFunctions.begin(); }
4700b57cec5SDimitry Andric   MapT::iterator end() { return InstantiatedFunctions.end(); }
4710b57cec5SDimitry Andric };
4720b57cec5SDimitry Andric 
4730b57cec5SDimitry Andric class SegmentBuilder {
4740b57cec5SDimitry Andric   std::vector<CoverageSegment> &Segments;
4750b57cec5SDimitry Andric   SmallVector<const CountedRegion *, 8> ActiveRegions;
4760b57cec5SDimitry Andric 
4770b57cec5SDimitry Andric   SegmentBuilder(std::vector<CoverageSegment> &Segments) : Segments(Segments) {}
4780b57cec5SDimitry Andric 
4790b57cec5SDimitry Andric   /// Emit a segment with the count from \p Region starting at \p StartLoc.
4800b57cec5SDimitry Andric   //
4810b57cec5SDimitry Andric   /// \p IsRegionEntry: The segment is at the start of a new non-gap region.
4820b57cec5SDimitry Andric   /// \p EmitSkippedRegion: The segment must be emitted as a skipped region.
4830b57cec5SDimitry Andric   void startSegment(const CountedRegion &Region, LineColPair StartLoc,
4840b57cec5SDimitry Andric                     bool IsRegionEntry, bool EmitSkippedRegion = false) {
4850b57cec5SDimitry Andric     bool HasCount = !EmitSkippedRegion &&
4860b57cec5SDimitry Andric                     (Region.Kind != CounterMappingRegion::SkippedRegion);
4870b57cec5SDimitry Andric 
4880b57cec5SDimitry Andric     // If the new segment wouldn't affect coverage rendering, skip it.
4890b57cec5SDimitry Andric     if (!Segments.empty() && !IsRegionEntry && !EmitSkippedRegion) {
4900b57cec5SDimitry Andric       const auto &Last = Segments.back();
4910b57cec5SDimitry Andric       if (Last.HasCount == HasCount && Last.Count == Region.ExecutionCount &&
4920b57cec5SDimitry Andric           !Last.IsRegionEntry)
4930b57cec5SDimitry Andric         return;
4940b57cec5SDimitry Andric     }
4950b57cec5SDimitry Andric 
4960b57cec5SDimitry Andric     if (HasCount)
4970b57cec5SDimitry Andric       Segments.emplace_back(StartLoc.first, StartLoc.second,
4980b57cec5SDimitry Andric                             Region.ExecutionCount, IsRegionEntry,
4990b57cec5SDimitry Andric                             Region.Kind == CounterMappingRegion::GapRegion);
5000b57cec5SDimitry Andric     else
5010b57cec5SDimitry Andric       Segments.emplace_back(StartLoc.first, StartLoc.second, IsRegionEntry);
5020b57cec5SDimitry Andric 
5030b57cec5SDimitry Andric     LLVM_DEBUG({
5040b57cec5SDimitry Andric       const auto &Last = Segments.back();
5050b57cec5SDimitry Andric       dbgs() << "Segment at " << Last.Line << ":" << Last.Col
5060b57cec5SDimitry Andric              << " (count = " << Last.Count << ")"
5070b57cec5SDimitry Andric              << (Last.IsRegionEntry ? ", RegionEntry" : "")
5080b57cec5SDimitry Andric              << (!Last.HasCount ? ", Skipped" : "")
5090b57cec5SDimitry Andric              << (Last.IsGapRegion ? ", Gap" : "") << "\n";
5100b57cec5SDimitry Andric     });
5110b57cec5SDimitry Andric   }
5120b57cec5SDimitry Andric 
5130b57cec5SDimitry Andric   /// Emit segments for active regions which end before \p Loc.
5140b57cec5SDimitry Andric   ///
515bdd1243dSDimitry Andric   /// \p Loc: The start location of the next region. If std::nullopt, all active
5160b57cec5SDimitry Andric   /// regions are completed.
5170b57cec5SDimitry Andric   /// \p FirstCompletedRegion: Index of the first completed region.
518bdd1243dSDimitry Andric   void completeRegionsUntil(std::optional<LineColPair> Loc,
5190b57cec5SDimitry Andric                             unsigned FirstCompletedRegion) {
5200b57cec5SDimitry Andric     // Sort the completed regions by end location. This makes it simple to
5210b57cec5SDimitry Andric     // emit closing segments in sorted order.
5220b57cec5SDimitry Andric     auto CompletedRegionsIt = ActiveRegions.begin() + FirstCompletedRegion;
5230b57cec5SDimitry Andric     std::stable_sort(CompletedRegionsIt, ActiveRegions.end(),
5240b57cec5SDimitry Andric                       [](const CountedRegion *L, const CountedRegion *R) {
5250b57cec5SDimitry Andric                         return L->endLoc() < R->endLoc();
5260b57cec5SDimitry Andric                       });
5270b57cec5SDimitry Andric 
5280b57cec5SDimitry Andric     // Emit segments for all completed regions.
5290b57cec5SDimitry Andric     for (unsigned I = FirstCompletedRegion + 1, E = ActiveRegions.size(); I < E;
5300b57cec5SDimitry Andric          ++I) {
5310b57cec5SDimitry Andric       const auto *CompletedRegion = ActiveRegions[I];
5320b57cec5SDimitry Andric       assert((!Loc || CompletedRegion->endLoc() <= *Loc) &&
5330b57cec5SDimitry Andric              "Completed region ends after start of new region");
5340b57cec5SDimitry Andric 
5350b57cec5SDimitry Andric       const auto *PrevCompletedRegion = ActiveRegions[I - 1];
5360b57cec5SDimitry Andric       auto CompletedSegmentLoc = PrevCompletedRegion->endLoc();
5370b57cec5SDimitry Andric 
5380b57cec5SDimitry Andric       // Don't emit any more segments if they start where the new region begins.
5390b57cec5SDimitry Andric       if (Loc && CompletedSegmentLoc == *Loc)
5400b57cec5SDimitry Andric         break;
5410b57cec5SDimitry Andric 
5420b57cec5SDimitry Andric       // Don't emit a segment if the next completed region ends at the same
5430b57cec5SDimitry Andric       // location as this one.
5440b57cec5SDimitry Andric       if (CompletedSegmentLoc == CompletedRegion->endLoc())
5450b57cec5SDimitry Andric         continue;
5460b57cec5SDimitry Andric 
5470b57cec5SDimitry Andric       // Use the count from the last completed region which ends at this loc.
5480b57cec5SDimitry Andric       for (unsigned J = I + 1; J < E; ++J)
5490b57cec5SDimitry Andric         if (CompletedRegion->endLoc() == ActiveRegions[J]->endLoc())
5500b57cec5SDimitry Andric           CompletedRegion = ActiveRegions[J];
5510b57cec5SDimitry Andric 
5520b57cec5SDimitry Andric       startSegment(*CompletedRegion, CompletedSegmentLoc, false);
5530b57cec5SDimitry Andric     }
5540b57cec5SDimitry Andric 
5550b57cec5SDimitry Andric     auto Last = ActiveRegions.back();
5560b57cec5SDimitry Andric     if (FirstCompletedRegion && Last->endLoc() != *Loc) {
5570b57cec5SDimitry Andric       // If there's a gap after the end of the last completed region and the
5580b57cec5SDimitry Andric       // start of the new region, use the last active region to fill the gap.
5590b57cec5SDimitry Andric       startSegment(*ActiveRegions[FirstCompletedRegion - 1], Last->endLoc(),
5600b57cec5SDimitry Andric                    false);
5610b57cec5SDimitry Andric     } else if (!FirstCompletedRegion && (!Loc || *Loc != Last->endLoc())) {
5620b57cec5SDimitry Andric       // Emit a skipped segment if there are no more active regions. This
5630b57cec5SDimitry Andric       // ensures that gaps between functions are marked correctly.
5640b57cec5SDimitry Andric       startSegment(*Last, Last->endLoc(), false, true);
5650b57cec5SDimitry Andric     }
5660b57cec5SDimitry Andric 
5670b57cec5SDimitry Andric     // Pop the completed regions.
5680b57cec5SDimitry Andric     ActiveRegions.erase(CompletedRegionsIt, ActiveRegions.end());
5690b57cec5SDimitry Andric   }
5700b57cec5SDimitry Andric 
5710b57cec5SDimitry Andric   void buildSegmentsImpl(ArrayRef<CountedRegion> Regions) {
5720b57cec5SDimitry Andric     for (const auto &CR : enumerate(Regions)) {
5730b57cec5SDimitry Andric       auto CurStartLoc = CR.value().startLoc();
5740b57cec5SDimitry Andric 
5750b57cec5SDimitry Andric       // Active regions which end before the current region need to be popped.
5760b57cec5SDimitry Andric       auto CompletedRegions =
5770b57cec5SDimitry Andric           std::stable_partition(ActiveRegions.begin(), ActiveRegions.end(),
5780b57cec5SDimitry Andric                                 [&](const CountedRegion *Region) {
5790b57cec5SDimitry Andric                                   return !(Region->endLoc() <= CurStartLoc);
5800b57cec5SDimitry Andric                                 });
5810b57cec5SDimitry Andric       if (CompletedRegions != ActiveRegions.end()) {
5820b57cec5SDimitry Andric         unsigned FirstCompletedRegion =
5830b57cec5SDimitry Andric             std::distance(ActiveRegions.begin(), CompletedRegions);
5840b57cec5SDimitry Andric         completeRegionsUntil(CurStartLoc, FirstCompletedRegion);
5850b57cec5SDimitry Andric       }
5860b57cec5SDimitry Andric 
5870b57cec5SDimitry Andric       bool GapRegion = CR.value().Kind == CounterMappingRegion::GapRegion;
5880b57cec5SDimitry Andric 
5890b57cec5SDimitry Andric       // Try to emit a segment for the current region.
5900b57cec5SDimitry Andric       if (CurStartLoc == CR.value().endLoc()) {
5910b57cec5SDimitry Andric         // Avoid making zero-length regions active. If it's the last region,
5920b57cec5SDimitry Andric         // emit a skipped segment. Otherwise use its predecessor's count.
593e8d8bef9SDimitry Andric         const bool Skipped =
594e8d8bef9SDimitry Andric             (CR.index() + 1) == Regions.size() ||
595e8d8bef9SDimitry Andric             CR.value().Kind == CounterMappingRegion::SkippedRegion;
5960b57cec5SDimitry Andric         startSegment(ActiveRegions.empty() ? CR.value() : *ActiveRegions.back(),
5970b57cec5SDimitry Andric                      CurStartLoc, !GapRegion, Skipped);
598e8d8bef9SDimitry Andric         // If it is skipped segment, create a segment with last pushed
599e8d8bef9SDimitry Andric         // regions's count at CurStartLoc.
600e8d8bef9SDimitry Andric         if (Skipped && !ActiveRegions.empty())
601e8d8bef9SDimitry Andric           startSegment(*ActiveRegions.back(), CurStartLoc, false);
6020b57cec5SDimitry Andric         continue;
6030b57cec5SDimitry Andric       }
6040b57cec5SDimitry Andric       if (CR.index() + 1 == Regions.size() ||
6050b57cec5SDimitry Andric           CurStartLoc != Regions[CR.index() + 1].startLoc()) {
6060b57cec5SDimitry Andric         // Emit a segment if the next region doesn't start at the same location
6070b57cec5SDimitry Andric         // as this one.
6080b57cec5SDimitry Andric         startSegment(CR.value(), CurStartLoc, !GapRegion);
6090b57cec5SDimitry Andric       }
6100b57cec5SDimitry Andric 
6110b57cec5SDimitry Andric       // This region is active (i.e not completed).
6120b57cec5SDimitry Andric       ActiveRegions.push_back(&CR.value());
6130b57cec5SDimitry Andric     }
6140b57cec5SDimitry Andric 
6150b57cec5SDimitry Andric     // Complete any remaining active regions.
6160b57cec5SDimitry Andric     if (!ActiveRegions.empty())
617bdd1243dSDimitry Andric       completeRegionsUntil(std::nullopt, 0);
6180b57cec5SDimitry Andric   }
6190b57cec5SDimitry Andric 
6200b57cec5SDimitry Andric   /// Sort a nested sequence of regions from a single file.
6210b57cec5SDimitry Andric   static void sortNestedRegions(MutableArrayRef<CountedRegion> Regions) {
6220b57cec5SDimitry Andric     llvm::sort(Regions, [](const CountedRegion &LHS, const CountedRegion &RHS) {
6230b57cec5SDimitry Andric       if (LHS.startLoc() != RHS.startLoc())
6240b57cec5SDimitry Andric         return LHS.startLoc() < RHS.startLoc();
6250b57cec5SDimitry Andric       if (LHS.endLoc() != RHS.endLoc())
6260b57cec5SDimitry Andric         // When LHS completely contains RHS, we sort LHS first.
6270b57cec5SDimitry Andric         return RHS.endLoc() < LHS.endLoc();
6280b57cec5SDimitry Andric       // If LHS and RHS cover the same area, we need to sort them according
6290b57cec5SDimitry Andric       // to their kinds so that the most suitable region will become "active"
6300b57cec5SDimitry Andric       // in combineRegions(). Because we accumulate counter values only from
6310b57cec5SDimitry Andric       // regions of the same kind as the first region of the area, prefer
6320b57cec5SDimitry Andric       // CodeRegion to ExpansionRegion and ExpansionRegion to SkippedRegion.
6330b57cec5SDimitry Andric       static_assert(CounterMappingRegion::CodeRegion <
6340b57cec5SDimitry Andric                             CounterMappingRegion::ExpansionRegion &&
6350b57cec5SDimitry Andric                         CounterMappingRegion::ExpansionRegion <
6360b57cec5SDimitry Andric                             CounterMappingRegion::SkippedRegion,
6370b57cec5SDimitry Andric                     "Unexpected order of region kind values");
6380b57cec5SDimitry Andric       return LHS.Kind < RHS.Kind;
6390b57cec5SDimitry Andric     });
6400b57cec5SDimitry Andric   }
6410b57cec5SDimitry Andric 
6420b57cec5SDimitry Andric   /// Combine counts of regions which cover the same area.
6430b57cec5SDimitry Andric   static ArrayRef<CountedRegion>
6440b57cec5SDimitry Andric   combineRegions(MutableArrayRef<CountedRegion> Regions) {
6450b57cec5SDimitry Andric     if (Regions.empty())
6460b57cec5SDimitry Andric       return Regions;
6470b57cec5SDimitry Andric     auto Active = Regions.begin();
6480b57cec5SDimitry Andric     auto End = Regions.end();
6490b57cec5SDimitry Andric     for (auto I = Regions.begin() + 1; I != End; ++I) {
6500b57cec5SDimitry Andric       if (Active->startLoc() != I->startLoc() ||
6510b57cec5SDimitry Andric           Active->endLoc() != I->endLoc()) {
6520b57cec5SDimitry Andric         // Shift to the next region.
6530b57cec5SDimitry Andric         ++Active;
6540b57cec5SDimitry Andric         if (Active != I)
6550b57cec5SDimitry Andric           *Active = *I;
6560b57cec5SDimitry Andric         continue;
6570b57cec5SDimitry Andric       }
6580b57cec5SDimitry Andric       // Merge duplicate region.
6590b57cec5SDimitry Andric       // If CodeRegions and ExpansionRegions cover the same area, it's probably
6600b57cec5SDimitry Andric       // a macro which is fully expanded to another macro. In that case, we need
6610b57cec5SDimitry Andric       // to accumulate counts only from CodeRegions, or else the area will be
6620b57cec5SDimitry Andric       // counted twice.
6630b57cec5SDimitry Andric       // On the other hand, a macro may have a nested macro in its body. If the
6640b57cec5SDimitry Andric       // outer macro is used several times, the ExpansionRegion for the nested
6650b57cec5SDimitry Andric       // macro will also be added several times. These ExpansionRegions cover
6660b57cec5SDimitry Andric       // the same source locations and have to be combined to reach the correct
6670b57cec5SDimitry Andric       // value for that area.
6680b57cec5SDimitry Andric       // We add counts of the regions of the same kind as the active region
6690b57cec5SDimitry Andric       // to handle the both situations.
6700b57cec5SDimitry Andric       if (I->Kind == Active->Kind)
6710b57cec5SDimitry Andric         Active->ExecutionCount += I->ExecutionCount;
6720b57cec5SDimitry Andric     }
6730b57cec5SDimitry Andric     return Regions.drop_back(std::distance(++Active, End));
6740b57cec5SDimitry Andric   }
6750b57cec5SDimitry Andric 
6760b57cec5SDimitry Andric public:
6770b57cec5SDimitry Andric   /// Build a sorted list of CoverageSegments from a list of Regions.
6780b57cec5SDimitry Andric   static std::vector<CoverageSegment>
6790b57cec5SDimitry Andric   buildSegments(MutableArrayRef<CountedRegion> Regions) {
6800b57cec5SDimitry Andric     std::vector<CoverageSegment> Segments;
6810b57cec5SDimitry Andric     SegmentBuilder Builder(Segments);
6820b57cec5SDimitry Andric 
6830b57cec5SDimitry Andric     sortNestedRegions(Regions);
6840b57cec5SDimitry Andric     ArrayRef<CountedRegion> CombinedRegions = combineRegions(Regions);
6850b57cec5SDimitry Andric 
6860b57cec5SDimitry Andric     LLVM_DEBUG({
6870b57cec5SDimitry Andric       dbgs() << "Combined regions:\n";
6880b57cec5SDimitry Andric       for (const auto &CR : CombinedRegions)
6890b57cec5SDimitry Andric         dbgs() << "  " << CR.LineStart << ":" << CR.ColumnStart << " -> "
6900b57cec5SDimitry Andric                << CR.LineEnd << ":" << CR.ColumnEnd
6910b57cec5SDimitry Andric                << " (count=" << CR.ExecutionCount << ")\n";
6920b57cec5SDimitry Andric     });
6930b57cec5SDimitry Andric 
6940b57cec5SDimitry Andric     Builder.buildSegmentsImpl(CombinedRegions);
6950b57cec5SDimitry Andric 
6960b57cec5SDimitry Andric #ifndef NDEBUG
6970b57cec5SDimitry Andric     for (unsigned I = 1, E = Segments.size(); I < E; ++I) {
6980b57cec5SDimitry Andric       const auto &L = Segments[I - 1];
6990b57cec5SDimitry Andric       const auto &R = Segments[I];
7000b57cec5SDimitry Andric       if (!(L.Line < R.Line) && !(L.Line == R.Line && L.Col < R.Col)) {
701e8d8bef9SDimitry Andric         if (L.Line == R.Line && L.Col == R.Col && !L.HasCount)
702e8d8bef9SDimitry Andric           continue;
7030b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << " ! Segment " << L.Line << ":" << L.Col
7040b57cec5SDimitry Andric                           << " followed by " << R.Line << ":" << R.Col << "\n");
7050b57cec5SDimitry Andric         assert(false && "Coverage segments not unique or sorted");
7060b57cec5SDimitry Andric       }
7070b57cec5SDimitry Andric     }
7080b57cec5SDimitry Andric #endif
7090b57cec5SDimitry Andric 
7100b57cec5SDimitry Andric     return Segments;
7110b57cec5SDimitry Andric   }
7120b57cec5SDimitry Andric };
7130b57cec5SDimitry Andric 
7140b57cec5SDimitry Andric } // end anonymous namespace
7150b57cec5SDimitry Andric 
7160b57cec5SDimitry Andric std::vector<StringRef> CoverageMapping::getUniqueSourceFiles() const {
7170b57cec5SDimitry Andric   std::vector<StringRef> Filenames;
7180b57cec5SDimitry Andric   for (const auto &Function : getCoveredFunctions())
719e8d8bef9SDimitry Andric     llvm::append_range(Filenames, Function.Filenames);
7200b57cec5SDimitry Andric   llvm::sort(Filenames);
7210b57cec5SDimitry Andric   auto Last = std::unique(Filenames.begin(), Filenames.end());
7220b57cec5SDimitry Andric   Filenames.erase(Last, Filenames.end());
7230b57cec5SDimitry Andric   return Filenames;
7240b57cec5SDimitry Andric }
7250b57cec5SDimitry Andric 
7260b57cec5SDimitry Andric static SmallBitVector gatherFileIDs(StringRef SourceFile,
7270b57cec5SDimitry Andric                                     const FunctionRecord &Function) {
7280b57cec5SDimitry Andric   SmallBitVector FilenameEquivalence(Function.Filenames.size(), false);
7290b57cec5SDimitry Andric   for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I)
7300b57cec5SDimitry Andric     if (SourceFile == Function.Filenames[I])
7310b57cec5SDimitry Andric       FilenameEquivalence[I] = true;
7320b57cec5SDimitry Andric   return FilenameEquivalence;
7330b57cec5SDimitry Andric }
7340b57cec5SDimitry Andric 
7350b57cec5SDimitry Andric /// Return the ID of the file where the definition of the function is located.
736bdd1243dSDimitry Andric static std::optional<unsigned>
737bdd1243dSDimitry Andric findMainViewFileID(const FunctionRecord &Function) {
7380b57cec5SDimitry Andric   SmallBitVector IsNotExpandedFile(Function.Filenames.size(), true);
7390b57cec5SDimitry Andric   for (const auto &CR : Function.CountedRegions)
7400b57cec5SDimitry Andric     if (CR.Kind == CounterMappingRegion::ExpansionRegion)
7410b57cec5SDimitry Andric       IsNotExpandedFile[CR.ExpandedFileID] = false;
7420b57cec5SDimitry Andric   int I = IsNotExpandedFile.find_first();
7430b57cec5SDimitry Andric   if (I == -1)
744bdd1243dSDimitry Andric     return std::nullopt;
7450b57cec5SDimitry Andric   return I;
7460b57cec5SDimitry Andric }
7470b57cec5SDimitry Andric 
7480b57cec5SDimitry Andric /// Check if SourceFile is the file that contains the definition of
749bdd1243dSDimitry Andric /// the Function. Return the ID of the file in that case or std::nullopt
750bdd1243dSDimitry Andric /// otherwise.
751bdd1243dSDimitry Andric static std::optional<unsigned>
752bdd1243dSDimitry Andric findMainViewFileID(StringRef SourceFile, const FunctionRecord &Function) {
753bdd1243dSDimitry Andric   std::optional<unsigned> I = findMainViewFileID(Function);
7540b57cec5SDimitry Andric   if (I && SourceFile == Function.Filenames[*I])
7550b57cec5SDimitry Andric     return I;
756bdd1243dSDimitry Andric   return std::nullopt;
7570b57cec5SDimitry Andric }
7580b57cec5SDimitry Andric 
7590b57cec5SDimitry Andric static bool isExpansion(const CountedRegion &R, unsigned FileID) {
7600b57cec5SDimitry Andric   return R.Kind == CounterMappingRegion::ExpansionRegion && R.FileID == FileID;
7610b57cec5SDimitry Andric }
7620b57cec5SDimitry Andric 
7630b57cec5SDimitry Andric CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
7640b57cec5SDimitry Andric   CoverageData FileCoverage(Filename);
7650b57cec5SDimitry Andric   std::vector<CountedRegion> Regions;
7660b57cec5SDimitry Andric 
7678bcb0991SDimitry Andric   // Look up the function records in the given file. Due to hash collisions on
7688bcb0991SDimitry Andric   // the filename, we may get back some records that are not in the file.
7698bcb0991SDimitry Andric   ArrayRef<unsigned> RecordIndices =
7708bcb0991SDimitry Andric       getImpreciseRecordIndicesForFilename(Filename);
7718bcb0991SDimitry Andric   for (unsigned RecordIndex : RecordIndices) {
7728bcb0991SDimitry Andric     const FunctionRecord &Function = Functions[RecordIndex];
7730b57cec5SDimitry Andric     auto MainFileID = findMainViewFileID(Filename, Function);
7740b57cec5SDimitry Andric     auto FileIDs = gatherFileIDs(Filename, Function);
7750b57cec5SDimitry Andric     for (const auto &CR : Function.CountedRegions)
7760b57cec5SDimitry Andric       if (FileIDs.test(CR.FileID)) {
7770b57cec5SDimitry Andric         Regions.push_back(CR);
7780b57cec5SDimitry Andric         if (MainFileID && isExpansion(CR, *MainFileID))
7790b57cec5SDimitry Andric           FileCoverage.Expansions.emplace_back(CR, Function);
7800b57cec5SDimitry Andric       }
781e8d8bef9SDimitry Andric     // Capture branch regions specific to the function (excluding expansions).
782e8d8bef9SDimitry Andric     for (const auto &CR : Function.CountedBranchRegions)
783e8d8bef9SDimitry Andric       if (FileIDs.test(CR.FileID) && (CR.FileID == CR.ExpandedFileID))
784e8d8bef9SDimitry Andric         FileCoverage.BranchRegions.push_back(CR);
7850b57cec5SDimitry Andric   }
7860b57cec5SDimitry Andric 
7870b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Emitting segments for file: " << Filename << "\n");
7880b57cec5SDimitry Andric   FileCoverage.Segments = SegmentBuilder::buildSegments(Regions);
7890b57cec5SDimitry Andric 
7900b57cec5SDimitry Andric   return FileCoverage;
7910b57cec5SDimitry Andric }
7920b57cec5SDimitry Andric 
7930b57cec5SDimitry Andric std::vector<InstantiationGroup>
7940b57cec5SDimitry Andric CoverageMapping::getInstantiationGroups(StringRef Filename) const {
7950b57cec5SDimitry Andric   FunctionInstantiationSetCollector InstantiationSetCollector;
7968bcb0991SDimitry Andric   // Look up the function records in the given file. Due to hash collisions on
7978bcb0991SDimitry Andric   // the filename, we may get back some records that are not in the file.
7988bcb0991SDimitry Andric   ArrayRef<unsigned> RecordIndices =
7998bcb0991SDimitry Andric       getImpreciseRecordIndicesForFilename(Filename);
8008bcb0991SDimitry Andric   for (unsigned RecordIndex : RecordIndices) {
8018bcb0991SDimitry Andric     const FunctionRecord &Function = Functions[RecordIndex];
8020b57cec5SDimitry Andric     auto MainFileID = findMainViewFileID(Filename, Function);
8030b57cec5SDimitry Andric     if (!MainFileID)
8040b57cec5SDimitry Andric       continue;
8050b57cec5SDimitry Andric     InstantiationSetCollector.insert(Function, *MainFileID);
8060b57cec5SDimitry Andric   }
8070b57cec5SDimitry Andric 
8080b57cec5SDimitry Andric   std::vector<InstantiationGroup> Result;
8090b57cec5SDimitry Andric   for (auto &InstantiationSet : InstantiationSetCollector) {
8100b57cec5SDimitry Andric     InstantiationGroup IG{InstantiationSet.first.first,
8110b57cec5SDimitry Andric                           InstantiationSet.first.second,
8120b57cec5SDimitry Andric                           std::move(InstantiationSet.second)};
8130b57cec5SDimitry Andric     Result.emplace_back(std::move(IG));
8140b57cec5SDimitry Andric   }
8150b57cec5SDimitry Andric   return Result;
8160b57cec5SDimitry Andric }
8170b57cec5SDimitry Andric 
8180b57cec5SDimitry Andric CoverageData
8190b57cec5SDimitry Andric CoverageMapping::getCoverageForFunction(const FunctionRecord &Function) const {
8200b57cec5SDimitry Andric   auto MainFileID = findMainViewFileID(Function);
8210b57cec5SDimitry Andric   if (!MainFileID)
8220b57cec5SDimitry Andric     return CoverageData();
8230b57cec5SDimitry Andric 
8240b57cec5SDimitry Andric   CoverageData FunctionCoverage(Function.Filenames[*MainFileID]);
8250b57cec5SDimitry Andric   std::vector<CountedRegion> Regions;
8260b57cec5SDimitry Andric   for (const auto &CR : Function.CountedRegions)
8270b57cec5SDimitry Andric     if (CR.FileID == *MainFileID) {
8280b57cec5SDimitry Andric       Regions.push_back(CR);
8290b57cec5SDimitry Andric       if (isExpansion(CR, *MainFileID))
8300b57cec5SDimitry Andric         FunctionCoverage.Expansions.emplace_back(CR, Function);
8310b57cec5SDimitry Andric     }
832e8d8bef9SDimitry Andric   // Capture branch regions specific to the function (excluding expansions).
833e8d8bef9SDimitry Andric   for (const auto &CR : Function.CountedBranchRegions)
834e8d8bef9SDimitry Andric     if (CR.FileID == *MainFileID)
835e8d8bef9SDimitry Andric       FunctionCoverage.BranchRegions.push_back(CR);
8360b57cec5SDimitry Andric 
8370b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Emitting segments for function: " << Function.Name
8380b57cec5SDimitry Andric                     << "\n");
8390b57cec5SDimitry Andric   FunctionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
8400b57cec5SDimitry Andric 
8410b57cec5SDimitry Andric   return FunctionCoverage;
8420b57cec5SDimitry Andric }
8430b57cec5SDimitry Andric 
8440b57cec5SDimitry Andric CoverageData CoverageMapping::getCoverageForExpansion(
8450b57cec5SDimitry Andric     const ExpansionRecord &Expansion) const {
8460b57cec5SDimitry Andric   CoverageData ExpansionCoverage(
8470b57cec5SDimitry Andric       Expansion.Function.Filenames[Expansion.FileID]);
8480b57cec5SDimitry Andric   std::vector<CountedRegion> Regions;
8490b57cec5SDimitry Andric   for (const auto &CR : Expansion.Function.CountedRegions)
8500b57cec5SDimitry Andric     if (CR.FileID == Expansion.FileID) {
8510b57cec5SDimitry Andric       Regions.push_back(CR);
8520b57cec5SDimitry Andric       if (isExpansion(CR, Expansion.FileID))
8530b57cec5SDimitry Andric         ExpansionCoverage.Expansions.emplace_back(CR, Expansion.Function);
8540b57cec5SDimitry Andric     }
855e8d8bef9SDimitry Andric   for (const auto &CR : Expansion.Function.CountedBranchRegions)
856e8d8bef9SDimitry Andric     // Capture branch regions that only pertain to the corresponding expansion.
857e8d8bef9SDimitry Andric     if (CR.FileID == Expansion.FileID)
858e8d8bef9SDimitry Andric       ExpansionCoverage.BranchRegions.push_back(CR);
8590b57cec5SDimitry Andric 
8600b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Emitting segments for expansion of file "
8610b57cec5SDimitry Andric                     << Expansion.FileID << "\n");
8620b57cec5SDimitry Andric   ExpansionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
8630b57cec5SDimitry Andric 
8640b57cec5SDimitry Andric   return ExpansionCoverage;
8650b57cec5SDimitry Andric }
8660b57cec5SDimitry Andric 
8670b57cec5SDimitry Andric LineCoverageStats::LineCoverageStats(
8680b57cec5SDimitry Andric     ArrayRef<const CoverageSegment *> LineSegments,
8690b57cec5SDimitry Andric     const CoverageSegment *WrappedSegment, unsigned Line)
8700b57cec5SDimitry Andric     : ExecutionCount(0), HasMultipleRegions(false), Mapped(false), Line(Line),
8710b57cec5SDimitry Andric       LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
8720b57cec5SDimitry Andric   // Find the minimum number of regions which start in this line.
8730b57cec5SDimitry Andric   unsigned MinRegionCount = 0;
8740b57cec5SDimitry Andric   auto isStartOfRegion = [](const CoverageSegment *S) {
8750b57cec5SDimitry Andric     return !S->IsGapRegion && S->HasCount && S->IsRegionEntry;
8760b57cec5SDimitry Andric   };
8770b57cec5SDimitry Andric   for (unsigned I = 0; I < LineSegments.size() && MinRegionCount < 2; ++I)
8780b57cec5SDimitry Andric     if (isStartOfRegion(LineSegments[I]))
8790b57cec5SDimitry Andric       ++MinRegionCount;
8800b57cec5SDimitry Andric 
8810b57cec5SDimitry Andric   bool StartOfSkippedRegion = !LineSegments.empty() &&
8820b57cec5SDimitry Andric                               !LineSegments.front()->HasCount &&
8830b57cec5SDimitry Andric                               LineSegments.front()->IsRegionEntry;
8840b57cec5SDimitry Andric 
8850b57cec5SDimitry Andric   HasMultipleRegions = MinRegionCount > 1;
8860b57cec5SDimitry Andric   Mapped =
8870b57cec5SDimitry Andric       !StartOfSkippedRegion &&
8880b57cec5SDimitry Andric       ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0));
8890b57cec5SDimitry Andric 
8900b57cec5SDimitry Andric   if (!Mapped)
8910b57cec5SDimitry Andric     return;
8920b57cec5SDimitry Andric 
8930b57cec5SDimitry Andric   // Pick the max count from the non-gap, region entry segments and the
8940b57cec5SDimitry Andric   // wrapped count.
8950b57cec5SDimitry Andric   if (WrappedSegment)
8960b57cec5SDimitry Andric     ExecutionCount = WrappedSegment->Count;
8970b57cec5SDimitry Andric   if (!MinRegionCount)
8980b57cec5SDimitry Andric     return;
8990b57cec5SDimitry Andric   for (const auto *LS : LineSegments)
9000b57cec5SDimitry Andric     if (isStartOfRegion(LS))
9010b57cec5SDimitry Andric       ExecutionCount = std::max(ExecutionCount, LS->Count);
9020b57cec5SDimitry Andric }
9030b57cec5SDimitry Andric 
9040b57cec5SDimitry Andric LineCoverageIterator &LineCoverageIterator::operator++() {
9050b57cec5SDimitry Andric   if (Next == CD.end()) {
9060b57cec5SDimitry Andric     Stats = LineCoverageStats();
9070b57cec5SDimitry Andric     Ended = true;
9080b57cec5SDimitry Andric     return *this;
9090b57cec5SDimitry Andric   }
9100b57cec5SDimitry Andric   if (Segments.size())
9110b57cec5SDimitry Andric     WrappedSegment = Segments.back();
9120b57cec5SDimitry Andric   Segments.clear();
9130b57cec5SDimitry Andric   while (Next != CD.end() && Next->Line == Line)
9140b57cec5SDimitry Andric     Segments.push_back(&*Next++);
9150b57cec5SDimitry Andric   Stats = LineCoverageStats(Segments, WrappedSegment, Line);
9160b57cec5SDimitry Andric   ++Line;
9170b57cec5SDimitry Andric   return *this;
9180b57cec5SDimitry Andric }
9190b57cec5SDimitry Andric 
9200b57cec5SDimitry Andric static std::string getCoverageMapErrString(coveragemap_error Err) {
9210b57cec5SDimitry Andric   switch (Err) {
9220b57cec5SDimitry Andric   case coveragemap_error::success:
9230b57cec5SDimitry Andric     return "Success";
9240b57cec5SDimitry Andric   case coveragemap_error::eof:
9250b57cec5SDimitry Andric     return "End of File";
9260b57cec5SDimitry Andric   case coveragemap_error::no_data_found:
9270b57cec5SDimitry Andric     return "No coverage data found";
9280b57cec5SDimitry Andric   case coveragemap_error::unsupported_version:
9290b57cec5SDimitry Andric     return "Unsupported coverage format version";
9300b57cec5SDimitry Andric   case coveragemap_error::truncated:
9310b57cec5SDimitry Andric     return "Truncated coverage data";
9320b57cec5SDimitry Andric   case coveragemap_error::malformed:
9330b57cec5SDimitry Andric     return "Malformed coverage data";
9345ffd83dbSDimitry Andric   case coveragemap_error::decompression_failed:
9355ffd83dbSDimitry Andric     return "Failed to decompress coverage data (zlib)";
936e8d8bef9SDimitry Andric   case coveragemap_error::invalid_or_missing_arch_specifier:
937e8d8bef9SDimitry Andric     return "`-arch` specifier is invalid or missing for universal binary";
9380b57cec5SDimitry Andric   }
9390b57cec5SDimitry Andric   llvm_unreachable("A value of coveragemap_error has no message.");
9400b57cec5SDimitry Andric }
9410b57cec5SDimitry Andric 
9420b57cec5SDimitry Andric namespace {
9430b57cec5SDimitry Andric 
9440b57cec5SDimitry Andric // FIXME: This class is only here to support the transition to llvm::Error. It
9450b57cec5SDimitry Andric // will be removed once this transition is complete. Clients should prefer to
9460b57cec5SDimitry Andric // deal with the Error value directly, rather than converting to error_code.
9470b57cec5SDimitry Andric class CoverageMappingErrorCategoryType : public std::error_category {
9480b57cec5SDimitry Andric   const char *name() const noexcept override { return "llvm.coveragemap"; }
9490b57cec5SDimitry Andric   std::string message(int IE) const override {
9500b57cec5SDimitry Andric     return getCoverageMapErrString(static_cast<coveragemap_error>(IE));
9510b57cec5SDimitry Andric   }
9520b57cec5SDimitry Andric };
9530b57cec5SDimitry Andric 
9540b57cec5SDimitry Andric } // end anonymous namespace
9550b57cec5SDimitry Andric 
9560b57cec5SDimitry Andric std::string CoverageMapError::message() const {
9570b57cec5SDimitry Andric   return getCoverageMapErrString(Err);
9580b57cec5SDimitry Andric }
9590b57cec5SDimitry Andric 
9600b57cec5SDimitry Andric const std::error_category &llvm::coverage::coveragemap_category() {
961753f127fSDimitry Andric   static CoverageMappingErrorCategoryType ErrorCategory;
962753f127fSDimitry Andric   return ErrorCategory;
9630b57cec5SDimitry Andric }
9640b57cec5SDimitry Andric 
9650b57cec5SDimitry Andric char CoverageMapError::ID = 0;
966