1*0b57cec5SDimitry Andric //===- CoverageMapping.cpp - Code coverage mapping support ----------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This file contains support for clang's and llvm's instrumentation based 10*0b57cec5SDimitry Andric // code coverage. 11*0b57cec5SDimitry Andric // 12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 13*0b57cec5SDimitry Andric 14*0b57cec5SDimitry Andric #include "llvm/ProfileData/Coverage/CoverageMapping.h" 15*0b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h" 16*0b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 17*0b57cec5SDimitry Andric #include "llvm/ADT/None.h" 18*0b57cec5SDimitry Andric #include "llvm/ADT/Optional.h" 19*0b57cec5SDimitry Andric #include "llvm/ADT/SmallBitVector.h" 20*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 21*0b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 22*0b57cec5SDimitry Andric #include "llvm/ProfileData/Coverage/CoverageMappingReader.h" 23*0b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfReader.h" 24*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 25*0b57cec5SDimitry Andric #include "llvm/Support/Errc.h" 26*0b57cec5SDimitry Andric #include "llvm/Support/Error.h" 27*0b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 28*0b57cec5SDimitry Andric #include "llvm/Support/ManagedStatic.h" 29*0b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h" 30*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 31*0b57cec5SDimitry Andric #include <algorithm> 32*0b57cec5SDimitry Andric #include <cassert> 33*0b57cec5SDimitry Andric #include <cstdint> 34*0b57cec5SDimitry Andric #include <iterator> 35*0b57cec5SDimitry Andric #include <map> 36*0b57cec5SDimitry Andric #include <memory> 37*0b57cec5SDimitry Andric #include <string> 38*0b57cec5SDimitry Andric #include <system_error> 39*0b57cec5SDimitry Andric #include <utility> 40*0b57cec5SDimitry Andric #include <vector> 41*0b57cec5SDimitry Andric 42*0b57cec5SDimitry Andric using namespace llvm; 43*0b57cec5SDimitry Andric using namespace coverage; 44*0b57cec5SDimitry Andric 45*0b57cec5SDimitry Andric #define DEBUG_TYPE "coverage-mapping" 46*0b57cec5SDimitry Andric 47*0b57cec5SDimitry Andric Counter CounterExpressionBuilder::get(const CounterExpression &E) { 48*0b57cec5SDimitry Andric auto It = ExpressionIndices.find(E); 49*0b57cec5SDimitry Andric if (It != ExpressionIndices.end()) 50*0b57cec5SDimitry Andric return Counter::getExpression(It->second); 51*0b57cec5SDimitry Andric unsigned I = Expressions.size(); 52*0b57cec5SDimitry Andric Expressions.push_back(E); 53*0b57cec5SDimitry Andric ExpressionIndices[E] = I; 54*0b57cec5SDimitry Andric return Counter::getExpression(I); 55*0b57cec5SDimitry Andric } 56*0b57cec5SDimitry Andric 57*0b57cec5SDimitry Andric void CounterExpressionBuilder::extractTerms(Counter C, int Factor, 58*0b57cec5SDimitry Andric SmallVectorImpl<Term> &Terms) { 59*0b57cec5SDimitry Andric switch (C.getKind()) { 60*0b57cec5SDimitry Andric case Counter::Zero: 61*0b57cec5SDimitry Andric break; 62*0b57cec5SDimitry Andric case Counter::CounterValueReference: 63*0b57cec5SDimitry Andric Terms.emplace_back(C.getCounterID(), Factor); 64*0b57cec5SDimitry Andric break; 65*0b57cec5SDimitry Andric case Counter::Expression: 66*0b57cec5SDimitry Andric const auto &E = Expressions[C.getExpressionID()]; 67*0b57cec5SDimitry Andric extractTerms(E.LHS, Factor, Terms); 68*0b57cec5SDimitry Andric extractTerms( 69*0b57cec5SDimitry Andric E.RHS, E.Kind == CounterExpression::Subtract ? -Factor : Factor, Terms); 70*0b57cec5SDimitry Andric break; 71*0b57cec5SDimitry Andric } 72*0b57cec5SDimitry Andric } 73*0b57cec5SDimitry Andric 74*0b57cec5SDimitry Andric Counter CounterExpressionBuilder::simplify(Counter ExpressionTree) { 75*0b57cec5SDimitry Andric // Gather constant terms. 76*0b57cec5SDimitry Andric SmallVector<Term, 32> Terms; 77*0b57cec5SDimitry Andric extractTerms(ExpressionTree, +1, Terms); 78*0b57cec5SDimitry Andric 79*0b57cec5SDimitry Andric // If there are no terms, this is just a zero. The algorithm below assumes at 80*0b57cec5SDimitry Andric // least one term. 81*0b57cec5SDimitry Andric if (Terms.size() == 0) 82*0b57cec5SDimitry Andric return Counter::getZero(); 83*0b57cec5SDimitry Andric 84*0b57cec5SDimitry Andric // Group the terms by counter ID. 85*0b57cec5SDimitry Andric llvm::sort(Terms, [](const Term &LHS, const Term &RHS) { 86*0b57cec5SDimitry Andric return LHS.CounterID < RHS.CounterID; 87*0b57cec5SDimitry Andric }); 88*0b57cec5SDimitry Andric 89*0b57cec5SDimitry Andric // Combine terms by counter ID to eliminate counters that sum to zero. 90*0b57cec5SDimitry Andric auto Prev = Terms.begin(); 91*0b57cec5SDimitry Andric for (auto I = Prev + 1, E = Terms.end(); I != E; ++I) { 92*0b57cec5SDimitry Andric if (I->CounterID == Prev->CounterID) { 93*0b57cec5SDimitry Andric Prev->Factor += I->Factor; 94*0b57cec5SDimitry Andric continue; 95*0b57cec5SDimitry Andric } 96*0b57cec5SDimitry Andric ++Prev; 97*0b57cec5SDimitry Andric *Prev = *I; 98*0b57cec5SDimitry Andric } 99*0b57cec5SDimitry Andric Terms.erase(++Prev, Terms.end()); 100*0b57cec5SDimitry Andric 101*0b57cec5SDimitry Andric Counter C; 102*0b57cec5SDimitry Andric // Create additions. We do this before subtractions to avoid constructs like 103*0b57cec5SDimitry Andric // ((0 - X) + Y), as opposed to (Y - X). 104*0b57cec5SDimitry Andric for (auto T : Terms) { 105*0b57cec5SDimitry Andric if (T.Factor <= 0) 106*0b57cec5SDimitry Andric continue; 107*0b57cec5SDimitry Andric for (int I = 0; I < T.Factor; ++I) 108*0b57cec5SDimitry Andric if (C.isZero()) 109*0b57cec5SDimitry Andric C = Counter::getCounter(T.CounterID); 110*0b57cec5SDimitry Andric else 111*0b57cec5SDimitry Andric C = get(CounterExpression(CounterExpression::Add, C, 112*0b57cec5SDimitry Andric Counter::getCounter(T.CounterID))); 113*0b57cec5SDimitry Andric } 114*0b57cec5SDimitry Andric 115*0b57cec5SDimitry Andric // Create subtractions. 116*0b57cec5SDimitry Andric for (auto T : Terms) { 117*0b57cec5SDimitry Andric if (T.Factor >= 0) 118*0b57cec5SDimitry Andric continue; 119*0b57cec5SDimitry Andric for (int I = 0; I < -T.Factor; ++I) 120*0b57cec5SDimitry Andric C = get(CounterExpression(CounterExpression::Subtract, C, 121*0b57cec5SDimitry Andric Counter::getCounter(T.CounterID))); 122*0b57cec5SDimitry Andric } 123*0b57cec5SDimitry Andric return C; 124*0b57cec5SDimitry Andric } 125*0b57cec5SDimitry Andric 126*0b57cec5SDimitry Andric Counter CounterExpressionBuilder::add(Counter LHS, Counter RHS) { 127*0b57cec5SDimitry Andric return simplify(get(CounterExpression(CounterExpression::Add, LHS, RHS))); 128*0b57cec5SDimitry Andric } 129*0b57cec5SDimitry Andric 130*0b57cec5SDimitry Andric Counter CounterExpressionBuilder::subtract(Counter LHS, Counter RHS) { 131*0b57cec5SDimitry Andric return simplify( 132*0b57cec5SDimitry Andric get(CounterExpression(CounterExpression::Subtract, LHS, RHS))); 133*0b57cec5SDimitry Andric } 134*0b57cec5SDimitry Andric 135*0b57cec5SDimitry Andric void CounterMappingContext::dump(const Counter &C, raw_ostream &OS) const { 136*0b57cec5SDimitry Andric switch (C.getKind()) { 137*0b57cec5SDimitry Andric case Counter::Zero: 138*0b57cec5SDimitry Andric OS << '0'; 139*0b57cec5SDimitry Andric return; 140*0b57cec5SDimitry Andric case Counter::CounterValueReference: 141*0b57cec5SDimitry Andric OS << '#' << C.getCounterID(); 142*0b57cec5SDimitry Andric break; 143*0b57cec5SDimitry Andric case Counter::Expression: { 144*0b57cec5SDimitry Andric if (C.getExpressionID() >= Expressions.size()) 145*0b57cec5SDimitry Andric return; 146*0b57cec5SDimitry Andric const auto &E = Expressions[C.getExpressionID()]; 147*0b57cec5SDimitry Andric OS << '('; 148*0b57cec5SDimitry Andric dump(E.LHS, OS); 149*0b57cec5SDimitry Andric OS << (E.Kind == CounterExpression::Subtract ? " - " : " + "); 150*0b57cec5SDimitry Andric dump(E.RHS, OS); 151*0b57cec5SDimitry Andric OS << ')'; 152*0b57cec5SDimitry Andric break; 153*0b57cec5SDimitry Andric } 154*0b57cec5SDimitry Andric } 155*0b57cec5SDimitry Andric if (CounterValues.empty()) 156*0b57cec5SDimitry Andric return; 157*0b57cec5SDimitry Andric Expected<int64_t> Value = evaluate(C); 158*0b57cec5SDimitry Andric if (auto E = Value.takeError()) { 159*0b57cec5SDimitry Andric consumeError(std::move(E)); 160*0b57cec5SDimitry Andric return; 161*0b57cec5SDimitry Andric } 162*0b57cec5SDimitry Andric OS << '[' << *Value << ']'; 163*0b57cec5SDimitry Andric } 164*0b57cec5SDimitry Andric 165*0b57cec5SDimitry Andric Expected<int64_t> CounterMappingContext::evaluate(const Counter &C) const { 166*0b57cec5SDimitry Andric switch (C.getKind()) { 167*0b57cec5SDimitry Andric case Counter::Zero: 168*0b57cec5SDimitry Andric return 0; 169*0b57cec5SDimitry Andric case Counter::CounterValueReference: 170*0b57cec5SDimitry Andric if (C.getCounterID() >= CounterValues.size()) 171*0b57cec5SDimitry Andric return errorCodeToError(errc::argument_out_of_domain); 172*0b57cec5SDimitry Andric return CounterValues[C.getCounterID()]; 173*0b57cec5SDimitry Andric case Counter::Expression: { 174*0b57cec5SDimitry Andric if (C.getExpressionID() >= Expressions.size()) 175*0b57cec5SDimitry Andric return errorCodeToError(errc::argument_out_of_domain); 176*0b57cec5SDimitry Andric const auto &E = Expressions[C.getExpressionID()]; 177*0b57cec5SDimitry Andric Expected<int64_t> LHS = evaluate(E.LHS); 178*0b57cec5SDimitry Andric if (!LHS) 179*0b57cec5SDimitry Andric return LHS; 180*0b57cec5SDimitry Andric Expected<int64_t> RHS = evaluate(E.RHS); 181*0b57cec5SDimitry Andric if (!RHS) 182*0b57cec5SDimitry Andric return RHS; 183*0b57cec5SDimitry Andric return E.Kind == CounterExpression::Subtract ? *LHS - *RHS : *LHS + *RHS; 184*0b57cec5SDimitry Andric } 185*0b57cec5SDimitry Andric } 186*0b57cec5SDimitry Andric llvm_unreachable("Unhandled CounterKind"); 187*0b57cec5SDimitry Andric } 188*0b57cec5SDimitry Andric 189*0b57cec5SDimitry Andric void FunctionRecordIterator::skipOtherFiles() { 190*0b57cec5SDimitry Andric while (Current != Records.end() && !Filename.empty() && 191*0b57cec5SDimitry Andric Filename != Current->Filenames[0]) 192*0b57cec5SDimitry Andric ++Current; 193*0b57cec5SDimitry Andric if (Current == Records.end()) 194*0b57cec5SDimitry Andric *this = FunctionRecordIterator(); 195*0b57cec5SDimitry Andric } 196*0b57cec5SDimitry Andric 197*0b57cec5SDimitry Andric Error CoverageMapping::loadFunctionRecord( 198*0b57cec5SDimitry Andric const CoverageMappingRecord &Record, 199*0b57cec5SDimitry Andric IndexedInstrProfReader &ProfileReader) { 200*0b57cec5SDimitry Andric StringRef OrigFuncName = Record.FunctionName; 201*0b57cec5SDimitry Andric if (OrigFuncName.empty()) 202*0b57cec5SDimitry Andric return make_error<CoverageMapError>(coveragemap_error::malformed); 203*0b57cec5SDimitry Andric 204*0b57cec5SDimitry Andric if (Record.Filenames.empty()) 205*0b57cec5SDimitry Andric OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName); 206*0b57cec5SDimitry Andric else 207*0b57cec5SDimitry Andric OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]); 208*0b57cec5SDimitry Andric 209*0b57cec5SDimitry Andric CounterMappingContext Ctx(Record.Expressions); 210*0b57cec5SDimitry Andric 211*0b57cec5SDimitry Andric std::vector<uint64_t> Counts; 212*0b57cec5SDimitry Andric if (Error E = ProfileReader.getFunctionCounts(Record.FunctionName, 213*0b57cec5SDimitry Andric Record.FunctionHash, Counts)) { 214*0b57cec5SDimitry Andric instrprof_error IPE = InstrProfError::take(std::move(E)); 215*0b57cec5SDimitry Andric if (IPE == instrprof_error::hash_mismatch) { 216*0b57cec5SDimitry Andric FuncHashMismatches.emplace_back(Record.FunctionName, Record.FunctionHash); 217*0b57cec5SDimitry Andric return Error::success(); 218*0b57cec5SDimitry Andric } else if (IPE != instrprof_error::unknown_function) 219*0b57cec5SDimitry Andric return make_error<InstrProfError>(IPE); 220*0b57cec5SDimitry Andric Counts.assign(Record.MappingRegions.size(), 0); 221*0b57cec5SDimitry Andric } 222*0b57cec5SDimitry Andric Ctx.setCounts(Counts); 223*0b57cec5SDimitry Andric 224*0b57cec5SDimitry Andric assert(!Record.MappingRegions.empty() && "Function has no regions"); 225*0b57cec5SDimitry Andric 226*0b57cec5SDimitry Andric // This coverage record is a zero region for a function that's unused in 227*0b57cec5SDimitry Andric // some TU, but used in a different TU. Ignore it. The coverage maps from the 228*0b57cec5SDimitry Andric // the other TU will either be loaded (providing full region counts) or they 229*0b57cec5SDimitry Andric // won't (in which case we don't unintuitively report functions as uncovered 230*0b57cec5SDimitry Andric // when they have non-zero counts in the profile). 231*0b57cec5SDimitry Andric if (Record.MappingRegions.size() == 1 && 232*0b57cec5SDimitry Andric Record.MappingRegions[0].Count.isZero() && Counts[0] > 0) 233*0b57cec5SDimitry Andric return Error::success(); 234*0b57cec5SDimitry Andric 235*0b57cec5SDimitry Andric FunctionRecord Function(OrigFuncName, Record.Filenames); 236*0b57cec5SDimitry Andric for (const auto &Region : Record.MappingRegions) { 237*0b57cec5SDimitry Andric Expected<int64_t> ExecutionCount = Ctx.evaluate(Region.Count); 238*0b57cec5SDimitry Andric if (auto E = ExecutionCount.takeError()) { 239*0b57cec5SDimitry Andric consumeError(std::move(E)); 240*0b57cec5SDimitry Andric return Error::success(); 241*0b57cec5SDimitry Andric } 242*0b57cec5SDimitry Andric Function.pushRegion(Region, *ExecutionCount); 243*0b57cec5SDimitry Andric } 244*0b57cec5SDimitry Andric 245*0b57cec5SDimitry Andric // Don't create records for (filenames, function) pairs we've already seen. 246*0b57cec5SDimitry Andric auto FilenamesHash = hash_combine_range(Record.Filenames.begin(), 247*0b57cec5SDimitry Andric Record.Filenames.end()); 248*0b57cec5SDimitry Andric if (!RecordProvenance[FilenamesHash].insert(hash_value(OrigFuncName)).second) 249*0b57cec5SDimitry Andric return Error::success(); 250*0b57cec5SDimitry Andric 251*0b57cec5SDimitry Andric Functions.push_back(std::move(Function)); 252*0b57cec5SDimitry Andric return Error::success(); 253*0b57cec5SDimitry Andric } 254*0b57cec5SDimitry Andric 255*0b57cec5SDimitry Andric Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load( 256*0b57cec5SDimitry Andric ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders, 257*0b57cec5SDimitry Andric IndexedInstrProfReader &ProfileReader) { 258*0b57cec5SDimitry Andric auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping()); 259*0b57cec5SDimitry Andric 260*0b57cec5SDimitry Andric for (const auto &CoverageReader : CoverageReaders) { 261*0b57cec5SDimitry Andric for (auto RecordOrErr : *CoverageReader) { 262*0b57cec5SDimitry Andric if (Error E = RecordOrErr.takeError()) 263*0b57cec5SDimitry Andric return std::move(E); 264*0b57cec5SDimitry Andric const auto &Record = *RecordOrErr; 265*0b57cec5SDimitry Andric if (Error E = Coverage->loadFunctionRecord(Record, ProfileReader)) 266*0b57cec5SDimitry Andric return std::move(E); 267*0b57cec5SDimitry Andric } 268*0b57cec5SDimitry Andric } 269*0b57cec5SDimitry Andric 270*0b57cec5SDimitry Andric return std::move(Coverage); 271*0b57cec5SDimitry Andric } 272*0b57cec5SDimitry Andric 273*0b57cec5SDimitry Andric Expected<std::unique_ptr<CoverageMapping>> 274*0b57cec5SDimitry Andric CoverageMapping::load(ArrayRef<StringRef> ObjectFilenames, 275*0b57cec5SDimitry Andric StringRef ProfileFilename, ArrayRef<StringRef> Arches) { 276*0b57cec5SDimitry Andric auto ProfileReaderOrErr = IndexedInstrProfReader::create(ProfileFilename); 277*0b57cec5SDimitry Andric if (Error E = ProfileReaderOrErr.takeError()) 278*0b57cec5SDimitry Andric return std::move(E); 279*0b57cec5SDimitry Andric auto ProfileReader = std::move(ProfileReaderOrErr.get()); 280*0b57cec5SDimitry Andric 281*0b57cec5SDimitry Andric SmallVector<std::unique_ptr<CoverageMappingReader>, 4> Readers; 282*0b57cec5SDimitry Andric SmallVector<std::unique_ptr<MemoryBuffer>, 4> Buffers; 283*0b57cec5SDimitry Andric for (const auto &File : llvm::enumerate(ObjectFilenames)) { 284*0b57cec5SDimitry Andric auto CovMappingBufOrErr = MemoryBuffer::getFileOrSTDIN(File.value()); 285*0b57cec5SDimitry Andric if (std::error_code EC = CovMappingBufOrErr.getError()) 286*0b57cec5SDimitry Andric return errorCodeToError(EC); 287*0b57cec5SDimitry Andric StringRef Arch = Arches.empty() ? StringRef() : Arches[File.index()]; 288*0b57cec5SDimitry Andric MemoryBufferRef CovMappingBufRef = 289*0b57cec5SDimitry Andric CovMappingBufOrErr.get()->getMemBufferRef(); 290*0b57cec5SDimitry Andric auto CoverageReadersOrErr = 291*0b57cec5SDimitry Andric BinaryCoverageReader::create(CovMappingBufRef, Arch, Buffers); 292*0b57cec5SDimitry Andric if (Error E = CoverageReadersOrErr.takeError()) 293*0b57cec5SDimitry Andric return std::move(E); 294*0b57cec5SDimitry Andric for (auto &Reader : CoverageReadersOrErr.get()) 295*0b57cec5SDimitry Andric Readers.push_back(std::move(Reader)); 296*0b57cec5SDimitry Andric Buffers.push_back(std::move(CovMappingBufOrErr.get())); 297*0b57cec5SDimitry Andric } 298*0b57cec5SDimitry Andric return load(Readers, *ProfileReader); 299*0b57cec5SDimitry Andric } 300*0b57cec5SDimitry Andric 301*0b57cec5SDimitry Andric namespace { 302*0b57cec5SDimitry Andric 303*0b57cec5SDimitry Andric /// Distributes functions into instantiation sets. 304*0b57cec5SDimitry Andric /// 305*0b57cec5SDimitry Andric /// An instantiation set is a collection of functions that have the same source 306*0b57cec5SDimitry Andric /// code, ie, template functions specializations. 307*0b57cec5SDimitry Andric class FunctionInstantiationSetCollector { 308*0b57cec5SDimitry Andric using MapT = std::map<LineColPair, std::vector<const FunctionRecord *>>; 309*0b57cec5SDimitry Andric MapT InstantiatedFunctions; 310*0b57cec5SDimitry Andric 311*0b57cec5SDimitry Andric public: 312*0b57cec5SDimitry Andric void insert(const FunctionRecord &Function, unsigned FileID) { 313*0b57cec5SDimitry Andric auto I = Function.CountedRegions.begin(), E = Function.CountedRegions.end(); 314*0b57cec5SDimitry Andric while (I != E && I->FileID != FileID) 315*0b57cec5SDimitry Andric ++I; 316*0b57cec5SDimitry Andric assert(I != E && "function does not cover the given file"); 317*0b57cec5SDimitry Andric auto &Functions = InstantiatedFunctions[I->startLoc()]; 318*0b57cec5SDimitry Andric Functions.push_back(&Function); 319*0b57cec5SDimitry Andric } 320*0b57cec5SDimitry Andric 321*0b57cec5SDimitry Andric MapT::iterator begin() { return InstantiatedFunctions.begin(); } 322*0b57cec5SDimitry Andric MapT::iterator end() { return InstantiatedFunctions.end(); } 323*0b57cec5SDimitry Andric }; 324*0b57cec5SDimitry Andric 325*0b57cec5SDimitry Andric class SegmentBuilder { 326*0b57cec5SDimitry Andric std::vector<CoverageSegment> &Segments; 327*0b57cec5SDimitry Andric SmallVector<const CountedRegion *, 8> ActiveRegions; 328*0b57cec5SDimitry Andric 329*0b57cec5SDimitry Andric SegmentBuilder(std::vector<CoverageSegment> &Segments) : Segments(Segments) {} 330*0b57cec5SDimitry Andric 331*0b57cec5SDimitry Andric /// Emit a segment with the count from \p Region starting at \p StartLoc. 332*0b57cec5SDimitry Andric // 333*0b57cec5SDimitry Andric /// \p IsRegionEntry: The segment is at the start of a new non-gap region. 334*0b57cec5SDimitry Andric /// \p EmitSkippedRegion: The segment must be emitted as a skipped region. 335*0b57cec5SDimitry Andric void startSegment(const CountedRegion &Region, LineColPair StartLoc, 336*0b57cec5SDimitry Andric bool IsRegionEntry, bool EmitSkippedRegion = false) { 337*0b57cec5SDimitry Andric bool HasCount = !EmitSkippedRegion && 338*0b57cec5SDimitry Andric (Region.Kind != CounterMappingRegion::SkippedRegion); 339*0b57cec5SDimitry Andric 340*0b57cec5SDimitry Andric // If the new segment wouldn't affect coverage rendering, skip it. 341*0b57cec5SDimitry Andric if (!Segments.empty() && !IsRegionEntry && !EmitSkippedRegion) { 342*0b57cec5SDimitry Andric const auto &Last = Segments.back(); 343*0b57cec5SDimitry Andric if (Last.HasCount == HasCount && Last.Count == Region.ExecutionCount && 344*0b57cec5SDimitry Andric !Last.IsRegionEntry) 345*0b57cec5SDimitry Andric return; 346*0b57cec5SDimitry Andric } 347*0b57cec5SDimitry Andric 348*0b57cec5SDimitry Andric if (HasCount) 349*0b57cec5SDimitry Andric Segments.emplace_back(StartLoc.first, StartLoc.second, 350*0b57cec5SDimitry Andric Region.ExecutionCount, IsRegionEntry, 351*0b57cec5SDimitry Andric Region.Kind == CounterMappingRegion::GapRegion); 352*0b57cec5SDimitry Andric else 353*0b57cec5SDimitry Andric Segments.emplace_back(StartLoc.first, StartLoc.second, IsRegionEntry); 354*0b57cec5SDimitry Andric 355*0b57cec5SDimitry Andric LLVM_DEBUG({ 356*0b57cec5SDimitry Andric const auto &Last = Segments.back(); 357*0b57cec5SDimitry Andric dbgs() << "Segment at " << Last.Line << ":" << Last.Col 358*0b57cec5SDimitry Andric << " (count = " << Last.Count << ")" 359*0b57cec5SDimitry Andric << (Last.IsRegionEntry ? ", RegionEntry" : "") 360*0b57cec5SDimitry Andric << (!Last.HasCount ? ", Skipped" : "") 361*0b57cec5SDimitry Andric << (Last.IsGapRegion ? ", Gap" : "") << "\n"; 362*0b57cec5SDimitry Andric }); 363*0b57cec5SDimitry Andric } 364*0b57cec5SDimitry Andric 365*0b57cec5SDimitry Andric /// Emit segments for active regions which end before \p Loc. 366*0b57cec5SDimitry Andric /// 367*0b57cec5SDimitry Andric /// \p Loc: The start location of the next region. If None, all active 368*0b57cec5SDimitry Andric /// regions are completed. 369*0b57cec5SDimitry Andric /// \p FirstCompletedRegion: Index of the first completed region. 370*0b57cec5SDimitry Andric void completeRegionsUntil(Optional<LineColPair> Loc, 371*0b57cec5SDimitry Andric unsigned FirstCompletedRegion) { 372*0b57cec5SDimitry Andric // Sort the completed regions by end location. This makes it simple to 373*0b57cec5SDimitry Andric // emit closing segments in sorted order. 374*0b57cec5SDimitry Andric auto CompletedRegionsIt = ActiveRegions.begin() + FirstCompletedRegion; 375*0b57cec5SDimitry Andric std::stable_sort(CompletedRegionsIt, ActiveRegions.end(), 376*0b57cec5SDimitry Andric [](const CountedRegion *L, const CountedRegion *R) { 377*0b57cec5SDimitry Andric return L->endLoc() < R->endLoc(); 378*0b57cec5SDimitry Andric }); 379*0b57cec5SDimitry Andric 380*0b57cec5SDimitry Andric // Emit segments for all completed regions. 381*0b57cec5SDimitry Andric for (unsigned I = FirstCompletedRegion + 1, E = ActiveRegions.size(); I < E; 382*0b57cec5SDimitry Andric ++I) { 383*0b57cec5SDimitry Andric const auto *CompletedRegion = ActiveRegions[I]; 384*0b57cec5SDimitry Andric assert((!Loc || CompletedRegion->endLoc() <= *Loc) && 385*0b57cec5SDimitry Andric "Completed region ends after start of new region"); 386*0b57cec5SDimitry Andric 387*0b57cec5SDimitry Andric const auto *PrevCompletedRegion = ActiveRegions[I - 1]; 388*0b57cec5SDimitry Andric auto CompletedSegmentLoc = PrevCompletedRegion->endLoc(); 389*0b57cec5SDimitry Andric 390*0b57cec5SDimitry Andric // Don't emit any more segments if they start where the new region begins. 391*0b57cec5SDimitry Andric if (Loc && CompletedSegmentLoc == *Loc) 392*0b57cec5SDimitry Andric break; 393*0b57cec5SDimitry Andric 394*0b57cec5SDimitry Andric // Don't emit a segment if the next completed region ends at the same 395*0b57cec5SDimitry Andric // location as this one. 396*0b57cec5SDimitry Andric if (CompletedSegmentLoc == CompletedRegion->endLoc()) 397*0b57cec5SDimitry Andric continue; 398*0b57cec5SDimitry Andric 399*0b57cec5SDimitry Andric // Use the count from the last completed region which ends at this loc. 400*0b57cec5SDimitry Andric for (unsigned J = I + 1; J < E; ++J) 401*0b57cec5SDimitry Andric if (CompletedRegion->endLoc() == ActiveRegions[J]->endLoc()) 402*0b57cec5SDimitry Andric CompletedRegion = ActiveRegions[J]; 403*0b57cec5SDimitry Andric 404*0b57cec5SDimitry Andric startSegment(*CompletedRegion, CompletedSegmentLoc, false); 405*0b57cec5SDimitry Andric } 406*0b57cec5SDimitry Andric 407*0b57cec5SDimitry Andric auto Last = ActiveRegions.back(); 408*0b57cec5SDimitry Andric if (FirstCompletedRegion && Last->endLoc() != *Loc) { 409*0b57cec5SDimitry Andric // If there's a gap after the end of the last completed region and the 410*0b57cec5SDimitry Andric // start of the new region, use the last active region to fill the gap. 411*0b57cec5SDimitry Andric startSegment(*ActiveRegions[FirstCompletedRegion - 1], Last->endLoc(), 412*0b57cec5SDimitry Andric false); 413*0b57cec5SDimitry Andric } else if (!FirstCompletedRegion && (!Loc || *Loc != Last->endLoc())) { 414*0b57cec5SDimitry Andric // Emit a skipped segment if there are no more active regions. This 415*0b57cec5SDimitry Andric // ensures that gaps between functions are marked correctly. 416*0b57cec5SDimitry Andric startSegment(*Last, Last->endLoc(), false, true); 417*0b57cec5SDimitry Andric } 418*0b57cec5SDimitry Andric 419*0b57cec5SDimitry Andric // Pop the completed regions. 420*0b57cec5SDimitry Andric ActiveRegions.erase(CompletedRegionsIt, ActiveRegions.end()); 421*0b57cec5SDimitry Andric } 422*0b57cec5SDimitry Andric 423*0b57cec5SDimitry Andric void buildSegmentsImpl(ArrayRef<CountedRegion> Regions) { 424*0b57cec5SDimitry Andric for (const auto &CR : enumerate(Regions)) { 425*0b57cec5SDimitry Andric auto CurStartLoc = CR.value().startLoc(); 426*0b57cec5SDimitry Andric 427*0b57cec5SDimitry Andric // Active regions which end before the current region need to be popped. 428*0b57cec5SDimitry Andric auto CompletedRegions = 429*0b57cec5SDimitry Andric std::stable_partition(ActiveRegions.begin(), ActiveRegions.end(), 430*0b57cec5SDimitry Andric [&](const CountedRegion *Region) { 431*0b57cec5SDimitry Andric return !(Region->endLoc() <= CurStartLoc); 432*0b57cec5SDimitry Andric }); 433*0b57cec5SDimitry Andric if (CompletedRegions != ActiveRegions.end()) { 434*0b57cec5SDimitry Andric unsigned FirstCompletedRegion = 435*0b57cec5SDimitry Andric std::distance(ActiveRegions.begin(), CompletedRegions); 436*0b57cec5SDimitry Andric completeRegionsUntil(CurStartLoc, FirstCompletedRegion); 437*0b57cec5SDimitry Andric } 438*0b57cec5SDimitry Andric 439*0b57cec5SDimitry Andric bool GapRegion = CR.value().Kind == CounterMappingRegion::GapRegion; 440*0b57cec5SDimitry Andric 441*0b57cec5SDimitry Andric // Try to emit a segment for the current region. 442*0b57cec5SDimitry Andric if (CurStartLoc == CR.value().endLoc()) { 443*0b57cec5SDimitry Andric // Avoid making zero-length regions active. If it's the last region, 444*0b57cec5SDimitry Andric // emit a skipped segment. Otherwise use its predecessor's count. 445*0b57cec5SDimitry Andric const bool Skipped = (CR.index() + 1) == Regions.size(); 446*0b57cec5SDimitry Andric startSegment(ActiveRegions.empty() ? CR.value() : *ActiveRegions.back(), 447*0b57cec5SDimitry Andric CurStartLoc, !GapRegion, Skipped); 448*0b57cec5SDimitry Andric continue; 449*0b57cec5SDimitry Andric } 450*0b57cec5SDimitry Andric if (CR.index() + 1 == Regions.size() || 451*0b57cec5SDimitry Andric CurStartLoc != Regions[CR.index() + 1].startLoc()) { 452*0b57cec5SDimitry Andric // Emit a segment if the next region doesn't start at the same location 453*0b57cec5SDimitry Andric // as this one. 454*0b57cec5SDimitry Andric startSegment(CR.value(), CurStartLoc, !GapRegion); 455*0b57cec5SDimitry Andric } 456*0b57cec5SDimitry Andric 457*0b57cec5SDimitry Andric // This region is active (i.e not completed). 458*0b57cec5SDimitry Andric ActiveRegions.push_back(&CR.value()); 459*0b57cec5SDimitry Andric } 460*0b57cec5SDimitry Andric 461*0b57cec5SDimitry Andric // Complete any remaining active regions. 462*0b57cec5SDimitry Andric if (!ActiveRegions.empty()) 463*0b57cec5SDimitry Andric completeRegionsUntil(None, 0); 464*0b57cec5SDimitry Andric } 465*0b57cec5SDimitry Andric 466*0b57cec5SDimitry Andric /// Sort a nested sequence of regions from a single file. 467*0b57cec5SDimitry Andric static void sortNestedRegions(MutableArrayRef<CountedRegion> Regions) { 468*0b57cec5SDimitry Andric llvm::sort(Regions, [](const CountedRegion &LHS, const CountedRegion &RHS) { 469*0b57cec5SDimitry Andric if (LHS.startLoc() != RHS.startLoc()) 470*0b57cec5SDimitry Andric return LHS.startLoc() < RHS.startLoc(); 471*0b57cec5SDimitry Andric if (LHS.endLoc() != RHS.endLoc()) 472*0b57cec5SDimitry Andric // When LHS completely contains RHS, we sort LHS first. 473*0b57cec5SDimitry Andric return RHS.endLoc() < LHS.endLoc(); 474*0b57cec5SDimitry Andric // If LHS and RHS cover the same area, we need to sort them according 475*0b57cec5SDimitry Andric // to their kinds so that the most suitable region will become "active" 476*0b57cec5SDimitry Andric // in combineRegions(). Because we accumulate counter values only from 477*0b57cec5SDimitry Andric // regions of the same kind as the first region of the area, prefer 478*0b57cec5SDimitry Andric // CodeRegion to ExpansionRegion and ExpansionRegion to SkippedRegion. 479*0b57cec5SDimitry Andric static_assert(CounterMappingRegion::CodeRegion < 480*0b57cec5SDimitry Andric CounterMappingRegion::ExpansionRegion && 481*0b57cec5SDimitry Andric CounterMappingRegion::ExpansionRegion < 482*0b57cec5SDimitry Andric CounterMappingRegion::SkippedRegion, 483*0b57cec5SDimitry Andric "Unexpected order of region kind values"); 484*0b57cec5SDimitry Andric return LHS.Kind < RHS.Kind; 485*0b57cec5SDimitry Andric }); 486*0b57cec5SDimitry Andric } 487*0b57cec5SDimitry Andric 488*0b57cec5SDimitry Andric /// Combine counts of regions which cover the same area. 489*0b57cec5SDimitry Andric static ArrayRef<CountedRegion> 490*0b57cec5SDimitry Andric combineRegions(MutableArrayRef<CountedRegion> Regions) { 491*0b57cec5SDimitry Andric if (Regions.empty()) 492*0b57cec5SDimitry Andric return Regions; 493*0b57cec5SDimitry Andric auto Active = Regions.begin(); 494*0b57cec5SDimitry Andric auto End = Regions.end(); 495*0b57cec5SDimitry Andric for (auto I = Regions.begin() + 1; I != End; ++I) { 496*0b57cec5SDimitry Andric if (Active->startLoc() != I->startLoc() || 497*0b57cec5SDimitry Andric Active->endLoc() != I->endLoc()) { 498*0b57cec5SDimitry Andric // Shift to the next region. 499*0b57cec5SDimitry Andric ++Active; 500*0b57cec5SDimitry Andric if (Active != I) 501*0b57cec5SDimitry Andric *Active = *I; 502*0b57cec5SDimitry Andric continue; 503*0b57cec5SDimitry Andric } 504*0b57cec5SDimitry Andric // Merge duplicate region. 505*0b57cec5SDimitry Andric // If CodeRegions and ExpansionRegions cover the same area, it's probably 506*0b57cec5SDimitry Andric // a macro which is fully expanded to another macro. In that case, we need 507*0b57cec5SDimitry Andric // to accumulate counts only from CodeRegions, or else the area will be 508*0b57cec5SDimitry Andric // counted twice. 509*0b57cec5SDimitry Andric // On the other hand, a macro may have a nested macro in its body. If the 510*0b57cec5SDimitry Andric // outer macro is used several times, the ExpansionRegion for the nested 511*0b57cec5SDimitry Andric // macro will also be added several times. These ExpansionRegions cover 512*0b57cec5SDimitry Andric // the same source locations and have to be combined to reach the correct 513*0b57cec5SDimitry Andric // value for that area. 514*0b57cec5SDimitry Andric // We add counts of the regions of the same kind as the active region 515*0b57cec5SDimitry Andric // to handle the both situations. 516*0b57cec5SDimitry Andric if (I->Kind == Active->Kind) 517*0b57cec5SDimitry Andric Active->ExecutionCount += I->ExecutionCount; 518*0b57cec5SDimitry Andric } 519*0b57cec5SDimitry Andric return Regions.drop_back(std::distance(++Active, End)); 520*0b57cec5SDimitry Andric } 521*0b57cec5SDimitry Andric 522*0b57cec5SDimitry Andric public: 523*0b57cec5SDimitry Andric /// Build a sorted list of CoverageSegments from a list of Regions. 524*0b57cec5SDimitry Andric static std::vector<CoverageSegment> 525*0b57cec5SDimitry Andric buildSegments(MutableArrayRef<CountedRegion> Regions) { 526*0b57cec5SDimitry Andric std::vector<CoverageSegment> Segments; 527*0b57cec5SDimitry Andric SegmentBuilder Builder(Segments); 528*0b57cec5SDimitry Andric 529*0b57cec5SDimitry Andric sortNestedRegions(Regions); 530*0b57cec5SDimitry Andric ArrayRef<CountedRegion> CombinedRegions = combineRegions(Regions); 531*0b57cec5SDimitry Andric 532*0b57cec5SDimitry Andric LLVM_DEBUG({ 533*0b57cec5SDimitry Andric dbgs() << "Combined regions:\n"; 534*0b57cec5SDimitry Andric for (const auto &CR : CombinedRegions) 535*0b57cec5SDimitry Andric dbgs() << " " << CR.LineStart << ":" << CR.ColumnStart << " -> " 536*0b57cec5SDimitry Andric << CR.LineEnd << ":" << CR.ColumnEnd 537*0b57cec5SDimitry Andric << " (count=" << CR.ExecutionCount << ")\n"; 538*0b57cec5SDimitry Andric }); 539*0b57cec5SDimitry Andric 540*0b57cec5SDimitry Andric Builder.buildSegmentsImpl(CombinedRegions); 541*0b57cec5SDimitry Andric 542*0b57cec5SDimitry Andric #ifndef NDEBUG 543*0b57cec5SDimitry Andric for (unsigned I = 1, E = Segments.size(); I < E; ++I) { 544*0b57cec5SDimitry Andric const auto &L = Segments[I - 1]; 545*0b57cec5SDimitry Andric const auto &R = Segments[I]; 546*0b57cec5SDimitry Andric if (!(L.Line < R.Line) && !(L.Line == R.Line && L.Col < R.Col)) { 547*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " ! Segment " << L.Line << ":" << L.Col 548*0b57cec5SDimitry Andric << " followed by " << R.Line << ":" << R.Col << "\n"); 549*0b57cec5SDimitry Andric assert(false && "Coverage segments not unique or sorted"); 550*0b57cec5SDimitry Andric } 551*0b57cec5SDimitry Andric } 552*0b57cec5SDimitry Andric #endif 553*0b57cec5SDimitry Andric 554*0b57cec5SDimitry Andric return Segments; 555*0b57cec5SDimitry Andric } 556*0b57cec5SDimitry Andric }; 557*0b57cec5SDimitry Andric 558*0b57cec5SDimitry Andric } // end anonymous namespace 559*0b57cec5SDimitry Andric 560*0b57cec5SDimitry Andric std::vector<StringRef> CoverageMapping::getUniqueSourceFiles() const { 561*0b57cec5SDimitry Andric std::vector<StringRef> Filenames; 562*0b57cec5SDimitry Andric for (const auto &Function : getCoveredFunctions()) 563*0b57cec5SDimitry Andric Filenames.insert(Filenames.end(), Function.Filenames.begin(), 564*0b57cec5SDimitry Andric Function.Filenames.end()); 565*0b57cec5SDimitry Andric llvm::sort(Filenames); 566*0b57cec5SDimitry Andric auto Last = std::unique(Filenames.begin(), Filenames.end()); 567*0b57cec5SDimitry Andric Filenames.erase(Last, Filenames.end()); 568*0b57cec5SDimitry Andric return Filenames; 569*0b57cec5SDimitry Andric } 570*0b57cec5SDimitry Andric 571*0b57cec5SDimitry Andric static SmallBitVector gatherFileIDs(StringRef SourceFile, 572*0b57cec5SDimitry Andric const FunctionRecord &Function) { 573*0b57cec5SDimitry Andric SmallBitVector FilenameEquivalence(Function.Filenames.size(), false); 574*0b57cec5SDimitry Andric for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) 575*0b57cec5SDimitry Andric if (SourceFile == Function.Filenames[I]) 576*0b57cec5SDimitry Andric FilenameEquivalence[I] = true; 577*0b57cec5SDimitry Andric return FilenameEquivalence; 578*0b57cec5SDimitry Andric } 579*0b57cec5SDimitry Andric 580*0b57cec5SDimitry Andric /// Return the ID of the file where the definition of the function is located. 581*0b57cec5SDimitry Andric static Optional<unsigned> findMainViewFileID(const FunctionRecord &Function) { 582*0b57cec5SDimitry Andric SmallBitVector IsNotExpandedFile(Function.Filenames.size(), true); 583*0b57cec5SDimitry Andric for (const auto &CR : Function.CountedRegions) 584*0b57cec5SDimitry Andric if (CR.Kind == CounterMappingRegion::ExpansionRegion) 585*0b57cec5SDimitry Andric IsNotExpandedFile[CR.ExpandedFileID] = false; 586*0b57cec5SDimitry Andric int I = IsNotExpandedFile.find_first(); 587*0b57cec5SDimitry Andric if (I == -1) 588*0b57cec5SDimitry Andric return None; 589*0b57cec5SDimitry Andric return I; 590*0b57cec5SDimitry Andric } 591*0b57cec5SDimitry Andric 592*0b57cec5SDimitry Andric /// Check if SourceFile is the file that contains the definition of 593*0b57cec5SDimitry Andric /// the Function. Return the ID of the file in that case or None otherwise. 594*0b57cec5SDimitry Andric static Optional<unsigned> findMainViewFileID(StringRef SourceFile, 595*0b57cec5SDimitry Andric const FunctionRecord &Function) { 596*0b57cec5SDimitry Andric Optional<unsigned> I = findMainViewFileID(Function); 597*0b57cec5SDimitry Andric if (I && SourceFile == Function.Filenames[*I]) 598*0b57cec5SDimitry Andric return I; 599*0b57cec5SDimitry Andric return None; 600*0b57cec5SDimitry Andric } 601*0b57cec5SDimitry Andric 602*0b57cec5SDimitry Andric static bool isExpansion(const CountedRegion &R, unsigned FileID) { 603*0b57cec5SDimitry Andric return R.Kind == CounterMappingRegion::ExpansionRegion && R.FileID == FileID; 604*0b57cec5SDimitry Andric } 605*0b57cec5SDimitry Andric 606*0b57cec5SDimitry Andric CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const { 607*0b57cec5SDimitry Andric CoverageData FileCoverage(Filename); 608*0b57cec5SDimitry Andric std::vector<CountedRegion> Regions; 609*0b57cec5SDimitry Andric 610*0b57cec5SDimitry Andric for (const auto &Function : Functions) { 611*0b57cec5SDimitry Andric auto MainFileID = findMainViewFileID(Filename, Function); 612*0b57cec5SDimitry Andric auto FileIDs = gatherFileIDs(Filename, Function); 613*0b57cec5SDimitry Andric for (const auto &CR : Function.CountedRegions) 614*0b57cec5SDimitry Andric if (FileIDs.test(CR.FileID)) { 615*0b57cec5SDimitry Andric Regions.push_back(CR); 616*0b57cec5SDimitry Andric if (MainFileID && isExpansion(CR, *MainFileID)) 617*0b57cec5SDimitry Andric FileCoverage.Expansions.emplace_back(CR, Function); 618*0b57cec5SDimitry Andric } 619*0b57cec5SDimitry Andric } 620*0b57cec5SDimitry Andric 621*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Emitting segments for file: " << Filename << "\n"); 622*0b57cec5SDimitry Andric FileCoverage.Segments = SegmentBuilder::buildSegments(Regions); 623*0b57cec5SDimitry Andric 624*0b57cec5SDimitry Andric return FileCoverage; 625*0b57cec5SDimitry Andric } 626*0b57cec5SDimitry Andric 627*0b57cec5SDimitry Andric std::vector<InstantiationGroup> 628*0b57cec5SDimitry Andric CoverageMapping::getInstantiationGroups(StringRef Filename) const { 629*0b57cec5SDimitry Andric FunctionInstantiationSetCollector InstantiationSetCollector; 630*0b57cec5SDimitry Andric for (const auto &Function : Functions) { 631*0b57cec5SDimitry Andric auto MainFileID = findMainViewFileID(Filename, Function); 632*0b57cec5SDimitry Andric if (!MainFileID) 633*0b57cec5SDimitry Andric continue; 634*0b57cec5SDimitry Andric InstantiationSetCollector.insert(Function, *MainFileID); 635*0b57cec5SDimitry Andric } 636*0b57cec5SDimitry Andric 637*0b57cec5SDimitry Andric std::vector<InstantiationGroup> Result; 638*0b57cec5SDimitry Andric for (auto &InstantiationSet : InstantiationSetCollector) { 639*0b57cec5SDimitry Andric InstantiationGroup IG{InstantiationSet.first.first, 640*0b57cec5SDimitry Andric InstantiationSet.first.second, 641*0b57cec5SDimitry Andric std::move(InstantiationSet.second)}; 642*0b57cec5SDimitry Andric Result.emplace_back(std::move(IG)); 643*0b57cec5SDimitry Andric } 644*0b57cec5SDimitry Andric return Result; 645*0b57cec5SDimitry Andric } 646*0b57cec5SDimitry Andric 647*0b57cec5SDimitry Andric CoverageData 648*0b57cec5SDimitry Andric CoverageMapping::getCoverageForFunction(const FunctionRecord &Function) const { 649*0b57cec5SDimitry Andric auto MainFileID = findMainViewFileID(Function); 650*0b57cec5SDimitry Andric if (!MainFileID) 651*0b57cec5SDimitry Andric return CoverageData(); 652*0b57cec5SDimitry Andric 653*0b57cec5SDimitry Andric CoverageData FunctionCoverage(Function.Filenames[*MainFileID]); 654*0b57cec5SDimitry Andric std::vector<CountedRegion> Regions; 655*0b57cec5SDimitry Andric for (const auto &CR : Function.CountedRegions) 656*0b57cec5SDimitry Andric if (CR.FileID == *MainFileID) { 657*0b57cec5SDimitry Andric Regions.push_back(CR); 658*0b57cec5SDimitry Andric if (isExpansion(CR, *MainFileID)) 659*0b57cec5SDimitry Andric FunctionCoverage.Expansions.emplace_back(CR, Function); 660*0b57cec5SDimitry Andric } 661*0b57cec5SDimitry Andric 662*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Emitting segments for function: " << Function.Name 663*0b57cec5SDimitry Andric << "\n"); 664*0b57cec5SDimitry Andric FunctionCoverage.Segments = SegmentBuilder::buildSegments(Regions); 665*0b57cec5SDimitry Andric 666*0b57cec5SDimitry Andric return FunctionCoverage; 667*0b57cec5SDimitry Andric } 668*0b57cec5SDimitry Andric 669*0b57cec5SDimitry Andric CoverageData CoverageMapping::getCoverageForExpansion( 670*0b57cec5SDimitry Andric const ExpansionRecord &Expansion) const { 671*0b57cec5SDimitry Andric CoverageData ExpansionCoverage( 672*0b57cec5SDimitry Andric Expansion.Function.Filenames[Expansion.FileID]); 673*0b57cec5SDimitry Andric std::vector<CountedRegion> Regions; 674*0b57cec5SDimitry Andric for (const auto &CR : Expansion.Function.CountedRegions) 675*0b57cec5SDimitry Andric if (CR.FileID == Expansion.FileID) { 676*0b57cec5SDimitry Andric Regions.push_back(CR); 677*0b57cec5SDimitry Andric if (isExpansion(CR, Expansion.FileID)) 678*0b57cec5SDimitry Andric ExpansionCoverage.Expansions.emplace_back(CR, Expansion.Function); 679*0b57cec5SDimitry Andric } 680*0b57cec5SDimitry Andric 681*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Emitting segments for expansion of file " 682*0b57cec5SDimitry Andric << Expansion.FileID << "\n"); 683*0b57cec5SDimitry Andric ExpansionCoverage.Segments = SegmentBuilder::buildSegments(Regions); 684*0b57cec5SDimitry Andric 685*0b57cec5SDimitry Andric return ExpansionCoverage; 686*0b57cec5SDimitry Andric } 687*0b57cec5SDimitry Andric 688*0b57cec5SDimitry Andric LineCoverageStats::LineCoverageStats( 689*0b57cec5SDimitry Andric ArrayRef<const CoverageSegment *> LineSegments, 690*0b57cec5SDimitry Andric const CoverageSegment *WrappedSegment, unsigned Line) 691*0b57cec5SDimitry Andric : ExecutionCount(0), HasMultipleRegions(false), Mapped(false), Line(Line), 692*0b57cec5SDimitry Andric LineSegments(LineSegments), WrappedSegment(WrappedSegment) { 693*0b57cec5SDimitry Andric // Find the minimum number of regions which start in this line. 694*0b57cec5SDimitry Andric unsigned MinRegionCount = 0; 695*0b57cec5SDimitry Andric auto isStartOfRegion = [](const CoverageSegment *S) { 696*0b57cec5SDimitry Andric return !S->IsGapRegion && S->HasCount && S->IsRegionEntry; 697*0b57cec5SDimitry Andric }; 698*0b57cec5SDimitry Andric for (unsigned I = 0; I < LineSegments.size() && MinRegionCount < 2; ++I) 699*0b57cec5SDimitry Andric if (isStartOfRegion(LineSegments[I])) 700*0b57cec5SDimitry Andric ++MinRegionCount; 701*0b57cec5SDimitry Andric 702*0b57cec5SDimitry Andric bool StartOfSkippedRegion = !LineSegments.empty() && 703*0b57cec5SDimitry Andric !LineSegments.front()->HasCount && 704*0b57cec5SDimitry Andric LineSegments.front()->IsRegionEntry; 705*0b57cec5SDimitry Andric 706*0b57cec5SDimitry Andric HasMultipleRegions = MinRegionCount > 1; 707*0b57cec5SDimitry Andric Mapped = 708*0b57cec5SDimitry Andric !StartOfSkippedRegion && 709*0b57cec5SDimitry Andric ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0)); 710*0b57cec5SDimitry Andric 711*0b57cec5SDimitry Andric if (!Mapped) 712*0b57cec5SDimitry Andric return; 713*0b57cec5SDimitry Andric 714*0b57cec5SDimitry Andric // Pick the max count from the non-gap, region entry segments and the 715*0b57cec5SDimitry Andric // wrapped count. 716*0b57cec5SDimitry Andric if (WrappedSegment) 717*0b57cec5SDimitry Andric ExecutionCount = WrappedSegment->Count; 718*0b57cec5SDimitry Andric if (!MinRegionCount) 719*0b57cec5SDimitry Andric return; 720*0b57cec5SDimitry Andric for (const auto *LS : LineSegments) 721*0b57cec5SDimitry Andric if (isStartOfRegion(LS)) 722*0b57cec5SDimitry Andric ExecutionCount = std::max(ExecutionCount, LS->Count); 723*0b57cec5SDimitry Andric } 724*0b57cec5SDimitry Andric 725*0b57cec5SDimitry Andric LineCoverageIterator &LineCoverageIterator::operator++() { 726*0b57cec5SDimitry Andric if (Next == CD.end()) { 727*0b57cec5SDimitry Andric Stats = LineCoverageStats(); 728*0b57cec5SDimitry Andric Ended = true; 729*0b57cec5SDimitry Andric return *this; 730*0b57cec5SDimitry Andric } 731*0b57cec5SDimitry Andric if (Segments.size()) 732*0b57cec5SDimitry Andric WrappedSegment = Segments.back(); 733*0b57cec5SDimitry Andric Segments.clear(); 734*0b57cec5SDimitry Andric while (Next != CD.end() && Next->Line == Line) 735*0b57cec5SDimitry Andric Segments.push_back(&*Next++); 736*0b57cec5SDimitry Andric Stats = LineCoverageStats(Segments, WrappedSegment, Line); 737*0b57cec5SDimitry Andric ++Line; 738*0b57cec5SDimitry Andric return *this; 739*0b57cec5SDimitry Andric } 740*0b57cec5SDimitry Andric 741*0b57cec5SDimitry Andric static std::string getCoverageMapErrString(coveragemap_error Err) { 742*0b57cec5SDimitry Andric switch (Err) { 743*0b57cec5SDimitry Andric case coveragemap_error::success: 744*0b57cec5SDimitry Andric return "Success"; 745*0b57cec5SDimitry Andric case coveragemap_error::eof: 746*0b57cec5SDimitry Andric return "End of File"; 747*0b57cec5SDimitry Andric case coveragemap_error::no_data_found: 748*0b57cec5SDimitry Andric return "No coverage data found"; 749*0b57cec5SDimitry Andric case coveragemap_error::unsupported_version: 750*0b57cec5SDimitry Andric return "Unsupported coverage format version"; 751*0b57cec5SDimitry Andric case coveragemap_error::truncated: 752*0b57cec5SDimitry Andric return "Truncated coverage data"; 753*0b57cec5SDimitry Andric case coveragemap_error::malformed: 754*0b57cec5SDimitry Andric return "Malformed coverage data"; 755*0b57cec5SDimitry Andric } 756*0b57cec5SDimitry Andric llvm_unreachable("A value of coveragemap_error has no message."); 757*0b57cec5SDimitry Andric } 758*0b57cec5SDimitry Andric 759*0b57cec5SDimitry Andric namespace { 760*0b57cec5SDimitry Andric 761*0b57cec5SDimitry Andric // FIXME: This class is only here to support the transition to llvm::Error. It 762*0b57cec5SDimitry Andric // will be removed once this transition is complete. Clients should prefer to 763*0b57cec5SDimitry Andric // deal with the Error value directly, rather than converting to error_code. 764*0b57cec5SDimitry Andric class CoverageMappingErrorCategoryType : public std::error_category { 765*0b57cec5SDimitry Andric const char *name() const noexcept override { return "llvm.coveragemap"; } 766*0b57cec5SDimitry Andric std::string message(int IE) const override { 767*0b57cec5SDimitry Andric return getCoverageMapErrString(static_cast<coveragemap_error>(IE)); 768*0b57cec5SDimitry Andric } 769*0b57cec5SDimitry Andric }; 770*0b57cec5SDimitry Andric 771*0b57cec5SDimitry Andric } // end anonymous namespace 772*0b57cec5SDimitry Andric 773*0b57cec5SDimitry Andric std::string CoverageMapError::message() const { 774*0b57cec5SDimitry Andric return getCoverageMapErrString(Err); 775*0b57cec5SDimitry Andric } 776*0b57cec5SDimitry Andric 777*0b57cec5SDimitry Andric static ManagedStatic<CoverageMappingErrorCategoryType> ErrorCategory; 778*0b57cec5SDimitry Andric 779*0b57cec5SDimitry Andric const std::error_category &llvm::coverage::coveragemap_category() { 780*0b57cec5SDimitry Andric return *ErrorCategory; 781*0b57cec5SDimitry Andric } 782*0b57cec5SDimitry Andric 783*0b57cec5SDimitry Andric char CoverageMapError::ID = 0; 784