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" 17b3edf446SDimitry Andric #include "llvm/ADT/STLExtras.h" 180b57cec5SDimitry Andric #include "llvm/ADT/SmallBitVector.h" 190b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 2006c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h" 210b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 221ac55f4cSDimitry Andric #include "llvm/Object/BuildID.h" 230b57cec5SDimitry Andric #include "llvm/ProfileData/Coverage/CoverageMappingReader.h" 240b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfReader.h" 250b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 260b57cec5SDimitry Andric #include "llvm/Support/Errc.h" 270b57cec5SDimitry Andric #include "llvm/Support/Error.h" 280b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 290b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h" 3006c3fb27SDimitry Andric #include "llvm/Support/VirtualFileSystem.h" 310b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 320b57cec5SDimitry Andric #include <algorithm> 330b57cec5SDimitry Andric #include <cassert> 345f757f3fSDimitry Andric #include <cmath> 350b57cec5SDimitry Andric #include <cstdint> 360b57cec5SDimitry Andric #include <iterator> 370b57cec5SDimitry Andric #include <map> 380b57cec5SDimitry Andric #include <memory> 39bdd1243dSDimitry Andric #include <optional> 40*0fca6ea1SDimitry Andric #include <stack> 410b57cec5SDimitry Andric #include <string> 420b57cec5SDimitry Andric #include <system_error> 430b57cec5SDimitry Andric #include <utility> 440b57cec5SDimitry Andric #include <vector> 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric using namespace llvm; 470b57cec5SDimitry Andric using namespace coverage; 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric #define DEBUG_TYPE "coverage-mapping" 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric Counter CounterExpressionBuilder::get(const CounterExpression &E) { 520b57cec5SDimitry Andric auto It = ExpressionIndices.find(E); 530b57cec5SDimitry Andric if (It != ExpressionIndices.end()) 540b57cec5SDimitry Andric return Counter::getExpression(It->second); 550b57cec5SDimitry Andric unsigned I = Expressions.size(); 560b57cec5SDimitry Andric Expressions.push_back(E); 570b57cec5SDimitry Andric ExpressionIndices[E] = I; 580b57cec5SDimitry Andric return Counter::getExpression(I); 590b57cec5SDimitry Andric } 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric void CounterExpressionBuilder::extractTerms(Counter C, int Factor, 620b57cec5SDimitry Andric SmallVectorImpl<Term> &Terms) { 630b57cec5SDimitry Andric switch (C.getKind()) { 640b57cec5SDimitry Andric case Counter::Zero: 650b57cec5SDimitry Andric break; 660b57cec5SDimitry Andric case Counter::CounterValueReference: 670b57cec5SDimitry Andric Terms.emplace_back(C.getCounterID(), Factor); 680b57cec5SDimitry Andric break; 690b57cec5SDimitry Andric case Counter::Expression: 700b57cec5SDimitry Andric const auto &E = Expressions[C.getExpressionID()]; 710b57cec5SDimitry Andric extractTerms(E.LHS, Factor, Terms); 720b57cec5SDimitry Andric extractTerms( 730b57cec5SDimitry Andric E.RHS, E.Kind == CounterExpression::Subtract ? -Factor : Factor, Terms); 740b57cec5SDimitry Andric break; 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric } 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric Counter CounterExpressionBuilder::simplify(Counter ExpressionTree) { 790b57cec5SDimitry Andric // Gather constant terms. 800b57cec5SDimitry Andric SmallVector<Term, 32> Terms; 810b57cec5SDimitry Andric extractTerms(ExpressionTree, +1, Terms); 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric // If there are no terms, this is just a zero. The algorithm below assumes at 840b57cec5SDimitry Andric // least one term. 850b57cec5SDimitry Andric if (Terms.size() == 0) 860b57cec5SDimitry Andric return Counter::getZero(); 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric // Group the terms by counter ID. 890b57cec5SDimitry Andric llvm::sort(Terms, [](const Term &LHS, const Term &RHS) { 900b57cec5SDimitry Andric return LHS.CounterID < RHS.CounterID; 910b57cec5SDimitry Andric }); 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric // Combine terms by counter ID to eliminate counters that sum to zero. 940b57cec5SDimitry Andric auto Prev = Terms.begin(); 950b57cec5SDimitry Andric for (auto I = Prev + 1, E = Terms.end(); I != E; ++I) { 960b57cec5SDimitry Andric if (I->CounterID == Prev->CounterID) { 970b57cec5SDimitry Andric Prev->Factor += I->Factor; 980b57cec5SDimitry Andric continue; 990b57cec5SDimitry Andric } 1000b57cec5SDimitry Andric ++Prev; 1010b57cec5SDimitry Andric *Prev = *I; 1020b57cec5SDimitry Andric } 1030b57cec5SDimitry Andric Terms.erase(++Prev, Terms.end()); 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric Counter C; 1060b57cec5SDimitry Andric // Create additions. We do this before subtractions to avoid constructs like 1070b57cec5SDimitry Andric // ((0 - X) + Y), as opposed to (Y - X). 1080b57cec5SDimitry Andric for (auto T : Terms) { 1090b57cec5SDimitry Andric if (T.Factor <= 0) 1100b57cec5SDimitry Andric continue; 1110b57cec5SDimitry Andric for (int I = 0; I < T.Factor; ++I) 1120b57cec5SDimitry Andric if (C.isZero()) 1130b57cec5SDimitry Andric C = Counter::getCounter(T.CounterID); 1140b57cec5SDimitry Andric else 1150b57cec5SDimitry Andric C = get(CounterExpression(CounterExpression::Add, C, 1160b57cec5SDimitry Andric Counter::getCounter(T.CounterID))); 1170b57cec5SDimitry Andric } 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric // Create subtractions. 1200b57cec5SDimitry Andric for (auto T : Terms) { 1210b57cec5SDimitry Andric if (T.Factor >= 0) 1220b57cec5SDimitry Andric continue; 1230b57cec5SDimitry Andric for (int I = 0; I < -T.Factor; ++I) 1240b57cec5SDimitry Andric C = get(CounterExpression(CounterExpression::Subtract, C, 1250b57cec5SDimitry Andric Counter::getCounter(T.CounterID))); 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric return C; 1280b57cec5SDimitry Andric } 1290b57cec5SDimitry Andric 13081ad6265SDimitry Andric Counter CounterExpressionBuilder::add(Counter LHS, Counter RHS, bool Simplify) { 13181ad6265SDimitry Andric auto Cnt = get(CounterExpression(CounterExpression::Add, LHS, RHS)); 13281ad6265SDimitry Andric return Simplify ? simplify(Cnt) : Cnt; 1330b57cec5SDimitry Andric } 1340b57cec5SDimitry Andric 13581ad6265SDimitry Andric Counter CounterExpressionBuilder::subtract(Counter LHS, Counter RHS, 13681ad6265SDimitry Andric bool Simplify) { 13781ad6265SDimitry Andric auto Cnt = get(CounterExpression(CounterExpression::Subtract, LHS, RHS)); 13881ad6265SDimitry Andric return Simplify ? simplify(Cnt) : Cnt; 1390b57cec5SDimitry Andric } 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric void CounterMappingContext::dump(const Counter &C, raw_ostream &OS) const { 1420b57cec5SDimitry Andric switch (C.getKind()) { 1430b57cec5SDimitry Andric case Counter::Zero: 1440b57cec5SDimitry Andric OS << '0'; 1450b57cec5SDimitry Andric return; 1460b57cec5SDimitry Andric case Counter::CounterValueReference: 1470b57cec5SDimitry Andric OS << '#' << C.getCounterID(); 1480b57cec5SDimitry Andric break; 1490b57cec5SDimitry Andric case Counter::Expression: { 1500b57cec5SDimitry Andric if (C.getExpressionID() >= Expressions.size()) 1510b57cec5SDimitry Andric return; 1520b57cec5SDimitry Andric const auto &E = Expressions[C.getExpressionID()]; 1530b57cec5SDimitry Andric OS << '('; 1540b57cec5SDimitry Andric dump(E.LHS, OS); 1550b57cec5SDimitry Andric OS << (E.Kind == CounterExpression::Subtract ? " - " : " + "); 1560b57cec5SDimitry Andric dump(E.RHS, OS); 1570b57cec5SDimitry Andric OS << ')'; 1580b57cec5SDimitry Andric break; 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric if (CounterValues.empty()) 1620b57cec5SDimitry Andric return; 1630b57cec5SDimitry Andric Expected<int64_t> Value = evaluate(C); 1640b57cec5SDimitry Andric if (auto E = Value.takeError()) { 1650b57cec5SDimitry Andric consumeError(std::move(E)); 1660b57cec5SDimitry Andric return; 1670b57cec5SDimitry Andric } 1680b57cec5SDimitry Andric OS << '[' << *Value << ']'; 1690b57cec5SDimitry Andric } 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric Expected<int64_t> CounterMappingContext::evaluate(const Counter &C) const { 1725f757f3fSDimitry Andric struct StackElem { 1735f757f3fSDimitry Andric Counter ICounter; 1745f757f3fSDimitry Andric int64_t LHS = 0; 1755f757f3fSDimitry Andric enum { 1765f757f3fSDimitry Andric KNeverVisited = 0, 1775f757f3fSDimitry Andric KVisitedOnce = 1, 1785f757f3fSDimitry Andric KVisitedTwice = 2, 1795f757f3fSDimitry Andric } VisitCount = KNeverVisited; 1805f757f3fSDimitry Andric }; 1815f757f3fSDimitry Andric 1825f757f3fSDimitry Andric std::stack<StackElem> CounterStack; 1835f757f3fSDimitry Andric CounterStack.push({C}); 1845f757f3fSDimitry Andric 1855f757f3fSDimitry Andric int64_t LastPoppedValue; 1865f757f3fSDimitry Andric 1875f757f3fSDimitry Andric while (!CounterStack.empty()) { 1885f757f3fSDimitry Andric StackElem &Current = CounterStack.top(); 1895f757f3fSDimitry Andric 1905f757f3fSDimitry Andric switch (Current.ICounter.getKind()) { 1910b57cec5SDimitry Andric case Counter::Zero: 1925f757f3fSDimitry Andric LastPoppedValue = 0; 1935f757f3fSDimitry Andric CounterStack.pop(); 1945f757f3fSDimitry Andric break; 1950b57cec5SDimitry Andric case Counter::CounterValueReference: 1965f757f3fSDimitry Andric if (Current.ICounter.getCounterID() >= CounterValues.size()) 1970b57cec5SDimitry Andric return errorCodeToError(errc::argument_out_of_domain); 1985f757f3fSDimitry Andric LastPoppedValue = CounterValues[Current.ICounter.getCounterID()]; 1995f757f3fSDimitry Andric CounterStack.pop(); 2005f757f3fSDimitry Andric break; 2010b57cec5SDimitry Andric case Counter::Expression: { 2025f757f3fSDimitry Andric if (Current.ICounter.getExpressionID() >= Expressions.size()) 2030b57cec5SDimitry Andric return errorCodeToError(errc::argument_out_of_domain); 2045f757f3fSDimitry Andric const auto &E = Expressions[Current.ICounter.getExpressionID()]; 2055f757f3fSDimitry Andric if (Current.VisitCount == StackElem::KNeverVisited) { 2065f757f3fSDimitry Andric CounterStack.push(StackElem{E.LHS}); 2075f757f3fSDimitry Andric Current.VisitCount = StackElem::KVisitedOnce; 2085f757f3fSDimitry Andric } else if (Current.VisitCount == StackElem::KVisitedOnce) { 2095f757f3fSDimitry Andric Current.LHS = LastPoppedValue; 2105f757f3fSDimitry Andric CounterStack.push(StackElem{E.RHS}); 2115f757f3fSDimitry Andric Current.VisitCount = StackElem::KVisitedTwice; 2125f757f3fSDimitry Andric } else { 2135f757f3fSDimitry Andric int64_t LHS = Current.LHS; 2145f757f3fSDimitry Andric int64_t RHS = LastPoppedValue; 2155f757f3fSDimitry Andric LastPoppedValue = 2165f757f3fSDimitry Andric E.Kind == CounterExpression::Subtract ? LHS - RHS : LHS + RHS; 2175f757f3fSDimitry Andric CounterStack.pop(); 2185f757f3fSDimitry Andric } 2195f757f3fSDimitry Andric break; 2200b57cec5SDimitry Andric } 2210b57cec5SDimitry Andric } 2225f757f3fSDimitry Andric } 2235f757f3fSDimitry Andric 2245f757f3fSDimitry Andric return LastPoppedValue; 2255f757f3fSDimitry Andric } 2265f757f3fSDimitry Andric 227*0fca6ea1SDimitry Andric mcdc::TVIdxBuilder::TVIdxBuilder(const SmallVectorImpl<ConditionIDs> &NextIDs, 228*0fca6ea1SDimitry Andric int Offset) 229*0fca6ea1SDimitry Andric : Indices(NextIDs.size()) { 230*0fca6ea1SDimitry Andric // Construct Nodes and set up each InCount 231*0fca6ea1SDimitry Andric auto N = NextIDs.size(); 232*0fca6ea1SDimitry Andric SmallVector<MCDCNode> Nodes(N); 233*0fca6ea1SDimitry Andric for (unsigned ID = 0; ID < N; ++ID) { 234*0fca6ea1SDimitry Andric for (unsigned C = 0; C < 2; ++C) { 235*0fca6ea1SDimitry Andric #ifndef NDEBUG 236*0fca6ea1SDimitry Andric Indices[ID][C] = INT_MIN; 237*0fca6ea1SDimitry Andric #endif 238*0fca6ea1SDimitry Andric auto NextID = NextIDs[ID][C]; 239*0fca6ea1SDimitry Andric Nodes[ID].NextIDs[C] = NextID; 240*0fca6ea1SDimitry Andric if (NextID >= 0) 241*0fca6ea1SDimitry Andric ++Nodes[NextID].InCount; 2425f757f3fSDimitry Andric } 2435f757f3fSDimitry Andric } 2445f757f3fSDimitry Andric 245*0fca6ea1SDimitry Andric // Sort key ordered by <-Width, Ord> 246*0fca6ea1SDimitry Andric SmallVector<std::tuple<int, /// -Width 247*0fca6ea1SDimitry Andric unsigned, /// Ord 248*0fca6ea1SDimitry Andric int, /// ID 249*0fca6ea1SDimitry Andric unsigned /// Cond (0 or 1) 250*0fca6ea1SDimitry Andric >> 251*0fca6ea1SDimitry Andric Decisions; 252*0fca6ea1SDimitry Andric 253*0fca6ea1SDimitry Andric // Traverse Nodes to assign Idx 254*0fca6ea1SDimitry Andric SmallVector<int> Q; 255*0fca6ea1SDimitry Andric assert(Nodes[0].InCount == 0); 256*0fca6ea1SDimitry Andric Nodes[0].Width = 1; 257*0fca6ea1SDimitry Andric Q.push_back(0); 258*0fca6ea1SDimitry Andric 259*0fca6ea1SDimitry Andric unsigned Ord = 0; 260*0fca6ea1SDimitry Andric while (!Q.empty()) { 261*0fca6ea1SDimitry Andric auto IID = Q.begin(); 262*0fca6ea1SDimitry Andric int ID = *IID; 263*0fca6ea1SDimitry Andric Q.erase(IID); 264*0fca6ea1SDimitry Andric auto &Node = Nodes[ID]; 265*0fca6ea1SDimitry Andric assert(Node.Width > 0); 266*0fca6ea1SDimitry Andric 267*0fca6ea1SDimitry Andric for (unsigned I = 0; I < 2; ++I) { 268*0fca6ea1SDimitry Andric auto NextID = Node.NextIDs[I]; 269*0fca6ea1SDimitry Andric assert(NextID != 0 && "NextID should not point to the top"); 270*0fca6ea1SDimitry Andric if (NextID < 0) { 271*0fca6ea1SDimitry Andric // Decision 272*0fca6ea1SDimitry Andric Decisions.emplace_back(-Node.Width, Ord++, ID, I); 273*0fca6ea1SDimitry Andric assert(Ord == Decisions.size()); 274*0fca6ea1SDimitry Andric continue; 275*0fca6ea1SDimitry Andric } 276*0fca6ea1SDimitry Andric 277*0fca6ea1SDimitry Andric // Inter Node 278*0fca6ea1SDimitry Andric auto &NextNode = Nodes[NextID]; 279*0fca6ea1SDimitry Andric assert(NextNode.InCount > 0); 280*0fca6ea1SDimitry Andric 281*0fca6ea1SDimitry Andric // Assign Idx 282*0fca6ea1SDimitry Andric assert(Indices[ID][I] == INT_MIN); 283*0fca6ea1SDimitry Andric Indices[ID][I] = NextNode.Width; 284*0fca6ea1SDimitry Andric auto NextWidth = int64_t(NextNode.Width) + Node.Width; 285*0fca6ea1SDimitry Andric if (NextWidth > HardMaxTVs) { 286*0fca6ea1SDimitry Andric NumTestVectors = HardMaxTVs; // Overflow 287*0fca6ea1SDimitry Andric return; 288*0fca6ea1SDimitry Andric } 289*0fca6ea1SDimitry Andric NextNode.Width = NextWidth; 290*0fca6ea1SDimitry Andric 291*0fca6ea1SDimitry Andric // Ready if all incomings are processed. 292*0fca6ea1SDimitry Andric // Or NextNode.Width hasn't been confirmed yet. 293*0fca6ea1SDimitry Andric if (--NextNode.InCount == 0) 294*0fca6ea1SDimitry Andric Q.push_back(NextID); 295*0fca6ea1SDimitry Andric } 296*0fca6ea1SDimitry Andric } 297*0fca6ea1SDimitry Andric 298*0fca6ea1SDimitry Andric llvm::sort(Decisions); 299*0fca6ea1SDimitry Andric 300*0fca6ea1SDimitry Andric // Assign TestVector Indices in Decision Nodes 301*0fca6ea1SDimitry Andric int64_t CurIdx = 0; 302*0fca6ea1SDimitry Andric for (auto [NegWidth, Ord, ID, C] : Decisions) { 303*0fca6ea1SDimitry Andric int Width = -NegWidth; 304*0fca6ea1SDimitry Andric assert(Nodes[ID].Width == Width); 305*0fca6ea1SDimitry Andric assert(Nodes[ID].NextIDs[C] < 0); 306*0fca6ea1SDimitry Andric assert(Indices[ID][C] == INT_MIN); 307*0fca6ea1SDimitry Andric Indices[ID][C] = Offset + CurIdx; 308*0fca6ea1SDimitry Andric CurIdx += Width; 309*0fca6ea1SDimitry Andric if (CurIdx > HardMaxTVs) { 310*0fca6ea1SDimitry Andric NumTestVectors = HardMaxTVs; // Overflow 311*0fca6ea1SDimitry Andric return; 312*0fca6ea1SDimitry Andric } 313*0fca6ea1SDimitry Andric } 314*0fca6ea1SDimitry Andric 315*0fca6ea1SDimitry Andric assert(CurIdx < HardMaxTVs); 316*0fca6ea1SDimitry Andric NumTestVectors = CurIdx; 317*0fca6ea1SDimitry Andric 318*0fca6ea1SDimitry Andric #ifndef NDEBUG 319*0fca6ea1SDimitry Andric for (const auto &Idxs : Indices) 320*0fca6ea1SDimitry Andric for (auto Idx : Idxs) 321*0fca6ea1SDimitry Andric assert(Idx != INT_MIN); 322*0fca6ea1SDimitry Andric SavedNodes = std::move(Nodes); 323*0fca6ea1SDimitry Andric #endif 324*0fca6ea1SDimitry Andric } 325*0fca6ea1SDimitry Andric 326*0fca6ea1SDimitry Andric namespace { 327*0fca6ea1SDimitry Andric 328*0fca6ea1SDimitry Andric /// Construct this->NextIDs with Branches for TVIdxBuilder to use it 329*0fca6ea1SDimitry Andric /// before MCDCRecordProcessor(). 330*0fca6ea1SDimitry Andric class NextIDsBuilder { 331*0fca6ea1SDimitry Andric protected: 332*0fca6ea1SDimitry Andric SmallVector<mcdc::ConditionIDs> NextIDs; 333*0fca6ea1SDimitry Andric 334*0fca6ea1SDimitry Andric public: 335*0fca6ea1SDimitry Andric NextIDsBuilder(const ArrayRef<const CounterMappingRegion *> Branches) 336*0fca6ea1SDimitry Andric : NextIDs(Branches.size()) { 337*0fca6ea1SDimitry Andric #ifndef NDEBUG 338*0fca6ea1SDimitry Andric DenseSet<mcdc::ConditionID> SeenIDs; 339*0fca6ea1SDimitry Andric #endif 340*0fca6ea1SDimitry Andric for (const auto *Branch : Branches) { 341*0fca6ea1SDimitry Andric const auto &BranchParams = Branch->getBranchParams(); 342*0fca6ea1SDimitry Andric assert(SeenIDs.insert(BranchParams.ID).second && "Duplicate CondID"); 343*0fca6ea1SDimitry Andric NextIDs[BranchParams.ID] = BranchParams.Conds; 344*0fca6ea1SDimitry Andric } 345*0fca6ea1SDimitry Andric assert(SeenIDs.size() == Branches.size()); 346*0fca6ea1SDimitry Andric } 347*0fca6ea1SDimitry Andric }; 348*0fca6ea1SDimitry Andric 349*0fca6ea1SDimitry Andric class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder { 3505f757f3fSDimitry Andric /// A bitmap representing the executed test vectors for a boolean expression. 3515f757f3fSDimitry Andric /// Each index of the bitmap corresponds to a possible test vector. An index 3525f757f3fSDimitry Andric /// with a bit value of '1' indicates that the corresponding Test Vector 3535f757f3fSDimitry Andric /// identified by that index was executed. 354*0fca6ea1SDimitry Andric const BitVector &Bitmap; 3555f757f3fSDimitry Andric 3565f757f3fSDimitry Andric /// Decision Region to which the ExecutedTestVectorBitmap applies. 3577a6dacacSDimitry Andric const CounterMappingRegion &Region; 358*0fca6ea1SDimitry Andric const mcdc::DecisionParameters &DecisionParams; 3595f757f3fSDimitry Andric 3605f757f3fSDimitry Andric /// Array of branch regions corresponding each conditions in the boolean 3615f757f3fSDimitry Andric /// expression. 3627a6dacacSDimitry Andric ArrayRef<const CounterMappingRegion *> Branches; 3635f757f3fSDimitry Andric 3645f757f3fSDimitry Andric /// Total number of conditions in the boolean expression. 3655f757f3fSDimitry Andric unsigned NumConditions; 3665f757f3fSDimitry Andric 3675f757f3fSDimitry Andric /// Vector used to track whether a condition is constant folded. 3685f757f3fSDimitry Andric MCDCRecord::BoolVector Folded; 3695f757f3fSDimitry Andric 3705f757f3fSDimitry Andric /// Mapping of calculated MC/DC Independence Pairs for each condition. 3715f757f3fSDimitry Andric MCDCRecord::TVPairMap IndependencePairs; 3725f757f3fSDimitry Andric 373*0fca6ea1SDimitry Andric /// Storage for ExecVectors 374*0fca6ea1SDimitry Andric /// ExecVectors is the alias of its 0th element. 375*0fca6ea1SDimitry Andric std::array<MCDCRecord::TestVectors, 2> ExecVectorsByCond; 3765f757f3fSDimitry Andric 3775f757f3fSDimitry Andric /// Actual executed Test Vectors for the boolean expression, based on 3785f757f3fSDimitry Andric /// ExecutedTestVectorBitmap. 379*0fca6ea1SDimitry Andric MCDCRecord::TestVectors &ExecVectors; 380*0fca6ea1SDimitry Andric 381*0fca6ea1SDimitry Andric /// Number of False items in ExecVectors 382*0fca6ea1SDimitry Andric unsigned NumExecVectorsF; 383*0fca6ea1SDimitry Andric 384*0fca6ea1SDimitry Andric #ifndef NDEBUG 385*0fca6ea1SDimitry Andric DenseSet<unsigned> TVIdxs; 386*0fca6ea1SDimitry Andric #endif 387*0fca6ea1SDimitry Andric 388*0fca6ea1SDimitry Andric bool IsVersion11; 3895f757f3fSDimitry Andric 3905f757f3fSDimitry Andric public: 3917a6dacacSDimitry Andric MCDCRecordProcessor(const BitVector &Bitmap, 3927a6dacacSDimitry Andric const CounterMappingRegion &Region, 393*0fca6ea1SDimitry Andric ArrayRef<const CounterMappingRegion *> Branches, 394*0fca6ea1SDimitry Andric bool IsVersion11) 395*0fca6ea1SDimitry Andric : NextIDsBuilder(Branches), TVIdxBuilder(this->NextIDs), Bitmap(Bitmap), 396*0fca6ea1SDimitry Andric Region(Region), DecisionParams(Region.getDecisionParams()), 397*0fca6ea1SDimitry Andric Branches(Branches), NumConditions(DecisionParams.NumConditions), 3985f757f3fSDimitry Andric Folded(NumConditions, false), IndependencePairs(NumConditions), 399*0fca6ea1SDimitry Andric ExecVectors(ExecVectorsByCond[false]), IsVersion11(IsVersion11) {} 4005f757f3fSDimitry Andric 4015f757f3fSDimitry Andric private: 402*0fca6ea1SDimitry Andric // Walk the binary decision diagram and try assigning both false and true to 403*0fca6ea1SDimitry Andric // each node. When a terminal node (ID == 0) is reached, fill in the value in 404*0fca6ea1SDimitry Andric // the truth table. 405*0fca6ea1SDimitry Andric void buildTestVector(MCDCRecord::TestVector &TV, mcdc::ConditionID ID, 406*0fca6ea1SDimitry Andric int TVIdx) { 407*0fca6ea1SDimitry Andric for (auto MCDCCond : {MCDCRecord::MCDC_False, MCDCRecord::MCDC_True}) { 408*0fca6ea1SDimitry Andric static_assert(MCDCRecord::MCDC_False == 0); 409*0fca6ea1SDimitry Andric static_assert(MCDCRecord::MCDC_True == 1); 410*0fca6ea1SDimitry Andric TV.set(ID, MCDCCond); 411*0fca6ea1SDimitry Andric auto NextID = NextIDs[ID][MCDCCond]; 412*0fca6ea1SDimitry Andric auto NextTVIdx = TVIdx + Indices[ID][MCDCCond]; 413*0fca6ea1SDimitry Andric assert(NextID == SavedNodes[ID].NextIDs[MCDCCond]); 414*0fca6ea1SDimitry Andric if (NextID >= 0) { 415*0fca6ea1SDimitry Andric buildTestVector(TV, NextID, NextTVIdx); 416*0fca6ea1SDimitry Andric continue; 4175f757f3fSDimitry Andric } 4185f757f3fSDimitry Andric 419*0fca6ea1SDimitry Andric assert(TVIdx < SavedNodes[ID].Width); 420*0fca6ea1SDimitry Andric assert(TVIdxs.insert(NextTVIdx).second && "Duplicate TVIdx"); 421*0fca6ea1SDimitry Andric 422*0fca6ea1SDimitry Andric if (!Bitmap[IsVersion11 423*0fca6ea1SDimitry Andric ? DecisionParams.BitmapIdx * CHAR_BIT + TV.getIndex() 424*0fca6ea1SDimitry Andric : DecisionParams.BitmapIdx - NumTestVectors + NextTVIdx]) 425*0fca6ea1SDimitry Andric continue; 426*0fca6ea1SDimitry Andric 4275f757f3fSDimitry Andric // Copy the completed test vector to the vector of testvectors. 4285f757f3fSDimitry Andric // The final value (T,F) is equal to the last non-dontcare state on the 4295f757f3fSDimitry Andric // path (in a short-circuiting system). 430*0fca6ea1SDimitry Andric ExecVectorsByCond[MCDCCond].push_back({TV, MCDCCond}); 4315f757f3fSDimitry Andric } 4325f757f3fSDimitry Andric 4335f757f3fSDimitry Andric // Reset back to DontCare. 434*0fca6ea1SDimitry Andric TV.set(ID, MCDCRecord::MCDC_DontCare); 4355f757f3fSDimitry Andric } 4365f757f3fSDimitry Andric 4375f757f3fSDimitry Andric /// Walk the bits in the bitmap. A bit set to '1' indicates that the test 4385f757f3fSDimitry Andric /// vector at the corresponding index was executed during a test run. 439*0fca6ea1SDimitry Andric void findExecutedTestVectors() { 440*0fca6ea1SDimitry Andric // Walk the binary decision diagram to enumerate all possible test vectors. 441*0fca6ea1SDimitry Andric // We start at the root node (ID == 0) with all values being DontCare. 442*0fca6ea1SDimitry Andric // `TVIdx` starts with 0 and is in the traversal. 443*0fca6ea1SDimitry Andric // `Index` encodes the bitmask of true values and is initially 0. 444*0fca6ea1SDimitry Andric MCDCRecord::TestVector TV(NumConditions); 445*0fca6ea1SDimitry Andric buildTestVector(TV, 0, 0); 446*0fca6ea1SDimitry Andric assert(TVIdxs.size() == unsigned(NumTestVectors) && 447*0fca6ea1SDimitry Andric "TVIdxs wasn't fulfilled"); 448*0fca6ea1SDimitry Andric 449*0fca6ea1SDimitry Andric // Fill ExecVectors order by False items and True items. 450*0fca6ea1SDimitry Andric // ExecVectors is the alias of ExecVectorsByCond[false], so 451*0fca6ea1SDimitry Andric // Append ExecVectorsByCond[true] on it. 452*0fca6ea1SDimitry Andric NumExecVectorsF = ExecVectors.size(); 453*0fca6ea1SDimitry Andric auto &ExecVectorsT = ExecVectorsByCond[true]; 454*0fca6ea1SDimitry Andric ExecVectors.append(std::make_move_iterator(ExecVectorsT.begin()), 455*0fca6ea1SDimitry Andric std::make_move_iterator(ExecVectorsT.end())); 4565f757f3fSDimitry Andric } 4575f757f3fSDimitry Andric 458*0fca6ea1SDimitry Andric // Find an independence pair for each condition: 459*0fca6ea1SDimitry Andric // - The condition is true in one test and false in the other. 460*0fca6ea1SDimitry Andric // - The decision outcome is true one test and false in the other. 461*0fca6ea1SDimitry Andric // - All other conditions' values must be equal or marked as "don't care". 4625f757f3fSDimitry Andric void findIndependencePairs() { 4635f757f3fSDimitry Andric unsigned NumTVs = ExecVectors.size(); 464*0fca6ea1SDimitry Andric for (unsigned I = NumExecVectorsF; I < NumTVs; ++I) { 465*0fca6ea1SDimitry Andric const auto &[A, ACond] = ExecVectors[I]; 466*0fca6ea1SDimitry Andric assert(ACond == MCDCRecord::MCDC_True); 467*0fca6ea1SDimitry Andric for (unsigned J = 0; J < NumExecVectorsF; ++J) { 468*0fca6ea1SDimitry Andric const auto &[B, BCond] = ExecVectors[J]; 469*0fca6ea1SDimitry Andric assert(BCond == MCDCRecord::MCDC_False); 470*0fca6ea1SDimitry Andric // If the two vectors differ in exactly one condition, ignoring DontCare 471*0fca6ea1SDimitry Andric // conditions, we have found an independence pair. 472*0fca6ea1SDimitry Andric auto AB = A.getDifferences(B); 473*0fca6ea1SDimitry Andric if (AB.count() == 1) 474*0fca6ea1SDimitry Andric IndependencePairs.insert( 475*0fca6ea1SDimitry Andric {AB.find_first(), std::make_pair(J + 1, I + 1)}); 4765f757f3fSDimitry Andric } 4775f757f3fSDimitry Andric } 4785f757f3fSDimitry Andric } 4795f757f3fSDimitry Andric 4805f757f3fSDimitry Andric public: 4815f757f3fSDimitry Andric /// Process the MC/DC Record in order to produce a result for a boolean 4825f757f3fSDimitry Andric /// expression. This process includes tracking the conditions that comprise 4835f757f3fSDimitry Andric /// the decision region, calculating the list of all possible test vectors, 4845f757f3fSDimitry Andric /// marking the executed test vectors, and then finding an Independence Pair 4855f757f3fSDimitry Andric /// out of the executed test vectors for each condition in the boolean 4865f757f3fSDimitry Andric /// expression. A condition is tracked to ensure that its ID can be mapped to 4875f757f3fSDimitry Andric /// its ordinal position in the boolean expression. The condition's source 4885f757f3fSDimitry Andric /// location is also tracked, as well as whether it is constant folded (in 4895f757f3fSDimitry Andric /// which case it is excuded from the metric). 4905f757f3fSDimitry Andric MCDCRecord processMCDCRecord() { 4915f757f3fSDimitry Andric unsigned I = 0; 4925f757f3fSDimitry Andric MCDCRecord::CondIDMap PosToID; 4935f757f3fSDimitry Andric MCDCRecord::LineColPairMap CondLoc; 4945f757f3fSDimitry Andric 4955f757f3fSDimitry Andric // Walk the Record's BranchRegions (representing Conditions) in order to: 4965f757f3fSDimitry Andric // - Hash the condition based on its corresponding ID. This will be used to 4975f757f3fSDimitry Andric // calculate the test vectors. 4985f757f3fSDimitry Andric // - Keep a map of the condition's ordinal position (1, 2, 3, 4) to its 4995f757f3fSDimitry Andric // actual ID. This will be used to visualize the conditions in the 5005f757f3fSDimitry Andric // correct order. 5015f757f3fSDimitry Andric // - Keep track of the condition source location. This will be used to 5025f757f3fSDimitry Andric // visualize where the condition is. 5035f757f3fSDimitry Andric // - Record whether the condition is constant folded so that we exclude it 5045f757f3fSDimitry Andric // from being measured. 5057a6dacacSDimitry Andric for (const auto *B : Branches) { 506*0fca6ea1SDimitry Andric const auto &BranchParams = B->getBranchParams(); 507*0fca6ea1SDimitry Andric PosToID[I] = BranchParams.ID; 5087a6dacacSDimitry Andric CondLoc[I] = B->startLoc(); 5097a6dacacSDimitry Andric Folded[I++] = (B->Count.isZero() && B->FalseCount.isZero()); 5105f757f3fSDimitry Andric } 5115f757f3fSDimitry Andric 5125f757f3fSDimitry Andric // Using Profile Bitmap from runtime, mark the executed test vectors. 513*0fca6ea1SDimitry Andric findExecutedTestVectors(); 5145f757f3fSDimitry Andric 5155f757f3fSDimitry Andric // Compare executed test vectors against each other to find an independence 5165f757f3fSDimitry Andric // pairs for each condition. This processing takes the most time. 5175f757f3fSDimitry Andric findIndependencePairs(); 5185f757f3fSDimitry Andric 5195f757f3fSDimitry Andric // Record Test vectors, executed vectors, and independence pairs. 520*0fca6ea1SDimitry Andric return MCDCRecord(Region, std::move(ExecVectors), 521*0fca6ea1SDimitry Andric std::move(IndependencePairs), std::move(Folded), 522*0fca6ea1SDimitry Andric std::move(PosToID), std::move(CondLoc)); 5235f757f3fSDimitry Andric } 5245f757f3fSDimitry Andric }; 5255f757f3fSDimitry Andric 526*0fca6ea1SDimitry Andric } // namespace 527*0fca6ea1SDimitry Andric 5285f757f3fSDimitry Andric Expected<MCDCRecord> CounterMappingContext::evaluateMCDCRegion( 5297a6dacacSDimitry Andric const CounterMappingRegion &Region, 530*0fca6ea1SDimitry Andric ArrayRef<const CounterMappingRegion *> Branches, bool IsVersion11) { 5315f757f3fSDimitry Andric 532*0fca6ea1SDimitry Andric MCDCRecordProcessor MCDCProcessor(Bitmap, Region, Branches, IsVersion11); 5335f757f3fSDimitry Andric return MCDCProcessor.processMCDCRecord(); 5340b57cec5SDimitry Andric } 5350b57cec5SDimitry Andric 536fe6060f1SDimitry Andric unsigned CounterMappingContext::getMaxCounterID(const Counter &C) const { 5375f757f3fSDimitry Andric struct StackElem { 5385f757f3fSDimitry Andric Counter ICounter; 5395f757f3fSDimitry Andric int64_t LHS = 0; 5405f757f3fSDimitry Andric enum { 5415f757f3fSDimitry Andric KNeverVisited = 0, 5425f757f3fSDimitry Andric KVisitedOnce = 1, 5435f757f3fSDimitry Andric KVisitedTwice = 2, 5445f757f3fSDimitry Andric } VisitCount = KNeverVisited; 5455f757f3fSDimitry Andric }; 5465f757f3fSDimitry Andric 5475f757f3fSDimitry Andric std::stack<StackElem> CounterStack; 5485f757f3fSDimitry Andric CounterStack.push({C}); 5495f757f3fSDimitry Andric 5505f757f3fSDimitry Andric int64_t LastPoppedValue; 5515f757f3fSDimitry Andric 5525f757f3fSDimitry Andric while (!CounterStack.empty()) { 5535f757f3fSDimitry Andric StackElem &Current = CounterStack.top(); 5545f757f3fSDimitry Andric 5555f757f3fSDimitry Andric switch (Current.ICounter.getKind()) { 556fe6060f1SDimitry Andric case Counter::Zero: 5575f757f3fSDimitry Andric LastPoppedValue = 0; 5585f757f3fSDimitry Andric CounterStack.pop(); 5595f757f3fSDimitry Andric break; 560fe6060f1SDimitry Andric case Counter::CounterValueReference: 5615f757f3fSDimitry Andric LastPoppedValue = Current.ICounter.getCounterID(); 5625f757f3fSDimitry Andric CounterStack.pop(); 5635f757f3fSDimitry Andric break; 564fe6060f1SDimitry Andric case Counter::Expression: { 5655f757f3fSDimitry Andric if (Current.ICounter.getExpressionID() >= Expressions.size()) { 5665f757f3fSDimitry Andric LastPoppedValue = 0; 5675f757f3fSDimitry Andric CounterStack.pop(); 5685f757f3fSDimitry Andric } else { 5695f757f3fSDimitry Andric const auto &E = Expressions[Current.ICounter.getExpressionID()]; 5705f757f3fSDimitry Andric if (Current.VisitCount == StackElem::KNeverVisited) { 5715f757f3fSDimitry Andric CounterStack.push(StackElem{E.LHS}); 5725f757f3fSDimitry Andric Current.VisitCount = StackElem::KVisitedOnce; 5735f757f3fSDimitry Andric } else if (Current.VisitCount == StackElem::KVisitedOnce) { 5745f757f3fSDimitry Andric Current.LHS = LastPoppedValue; 5755f757f3fSDimitry Andric CounterStack.push(StackElem{E.RHS}); 5765f757f3fSDimitry Andric Current.VisitCount = StackElem::KVisitedTwice; 5775f757f3fSDimitry Andric } else { 5785f757f3fSDimitry Andric int64_t LHS = Current.LHS; 5795f757f3fSDimitry Andric int64_t RHS = LastPoppedValue; 5805f757f3fSDimitry Andric LastPoppedValue = std::max(LHS, RHS); 5815f757f3fSDimitry Andric CounterStack.pop(); 582fe6060f1SDimitry Andric } 583fe6060f1SDimitry Andric } 5845f757f3fSDimitry Andric break; 5855f757f3fSDimitry Andric } 5865f757f3fSDimitry Andric } 5875f757f3fSDimitry Andric } 5885f757f3fSDimitry Andric 5895f757f3fSDimitry Andric return LastPoppedValue; 590fe6060f1SDimitry Andric } 591fe6060f1SDimitry Andric 5920b57cec5SDimitry Andric void FunctionRecordIterator::skipOtherFiles() { 5930b57cec5SDimitry Andric while (Current != Records.end() && !Filename.empty() && 5940b57cec5SDimitry Andric Filename != Current->Filenames[0]) 5950b57cec5SDimitry Andric ++Current; 5960b57cec5SDimitry Andric if (Current == Records.end()) 5970b57cec5SDimitry Andric *this = FunctionRecordIterator(); 5980b57cec5SDimitry Andric } 5990b57cec5SDimitry Andric 6008bcb0991SDimitry Andric ArrayRef<unsigned> CoverageMapping::getImpreciseRecordIndicesForFilename( 6018bcb0991SDimitry Andric StringRef Filename) const { 6028bcb0991SDimitry Andric size_t FilenameHash = hash_value(Filename); 6038bcb0991SDimitry Andric auto RecordIt = FilenameHash2RecordIndices.find(FilenameHash); 6048bcb0991SDimitry Andric if (RecordIt == FilenameHash2RecordIndices.end()) 6058bcb0991SDimitry Andric return {}; 6068bcb0991SDimitry Andric return RecordIt->second; 6078bcb0991SDimitry Andric } 6088bcb0991SDimitry Andric 609fe6060f1SDimitry Andric static unsigned getMaxCounterID(const CounterMappingContext &Ctx, 610fe6060f1SDimitry Andric const CoverageMappingRecord &Record) { 611fe6060f1SDimitry Andric unsigned MaxCounterID = 0; 612fe6060f1SDimitry Andric for (const auto &Region : Record.MappingRegions) { 613fe6060f1SDimitry Andric MaxCounterID = std::max(MaxCounterID, Ctx.getMaxCounterID(Region.Count)); 614fe6060f1SDimitry Andric } 615fe6060f1SDimitry Andric return MaxCounterID; 616fe6060f1SDimitry Andric } 617fe6060f1SDimitry Andric 618*0fca6ea1SDimitry Andric /// Returns the bit count 619*0fca6ea1SDimitry Andric static unsigned getMaxBitmapSize(const CoverageMappingRecord &Record, 620*0fca6ea1SDimitry Andric bool IsVersion11) { 621*0fca6ea1SDimitry Andric unsigned MaxBitmapIdx = 0; 6225f757f3fSDimitry Andric unsigned NumConditions = 0; 6237a6dacacSDimitry Andric // Scan max(BitmapIdx). 6247a6dacacSDimitry Andric // Note that `<=` is used insted of `<`, because `BitmapIdx == 0` is valid 625*0fca6ea1SDimitry Andric // and `MaxBitmapIdx is `unsigned`. `BitmapIdx` is unique in the record. 6265f757f3fSDimitry Andric for (const auto &Region : reverse(Record.MappingRegions)) { 627*0fca6ea1SDimitry Andric if (Region.Kind != CounterMappingRegion::MCDCDecisionRegion) 628*0fca6ea1SDimitry Andric continue; 629*0fca6ea1SDimitry Andric const auto &DecisionParams = Region.getDecisionParams(); 630*0fca6ea1SDimitry Andric if (MaxBitmapIdx <= DecisionParams.BitmapIdx) { 631*0fca6ea1SDimitry Andric MaxBitmapIdx = DecisionParams.BitmapIdx; 632*0fca6ea1SDimitry Andric NumConditions = DecisionParams.NumConditions; 6335f757f3fSDimitry Andric } 6345f757f3fSDimitry Andric } 635*0fca6ea1SDimitry Andric 636*0fca6ea1SDimitry Andric if (IsVersion11) 637*0fca6ea1SDimitry Andric MaxBitmapIdx = MaxBitmapIdx * CHAR_BIT + 638*0fca6ea1SDimitry Andric llvm::alignTo(uint64_t(1) << NumConditions, CHAR_BIT); 639*0fca6ea1SDimitry Andric 640*0fca6ea1SDimitry Andric return MaxBitmapIdx; 6415f757f3fSDimitry Andric } 6425f757f3fSDimitry Andric 643b3edf446SDimitry Andric namespace { 644b3edf446SDimitry Andric 645b3edf446SDimitry Andric /// Collect Decisions, Branchs, and Expansions and associate them. 646b3edf446SDimitry Andric class MCDCDecisionRecorder { 647b3edf446SDimitry Andric private: 648b3edf446SDimitry Andric /// This holds the DecisionRegion and MCDCBranches under it. 649b3edf446SDimitry Andric /// Also traverses Expansion(s). 650b3edf446SDimitry Andric /// The Decision has the number of MCDCBranches and will complete 651b3edf446SDimitry Andric /// when it is filled with unique ConditionID of MCDCBranches. 652b3edf446SDimitry Andric struct DecisionRecord { 653b3edf446SDimitry Andric const CounterMappingRegion *DecisionRegion; 654b3edf446SDimitry Andric 655b3edf446SDimitry Andric /// They are reflected from DecisionRegion for convenience. 656*0fca6ea1SDimitry Andric mcdc::DecisionParameters DecisionParams; 657b3edf446SDimitry Andric LineColPair DecisionStartLoc; 658b3edf446SDimitry Andric LineColPair DecisionEndLoc; 659b3edf446SDimitry Andric 660b3edf446SDimitry Andric /// This is passed to `MCDCRecordProcessor`, so this should be compatible 661b3edf446SDimitry Andric /// to`ArrayRef<const CounterMappingRegion *>`. 662b3edf446SDimitry Andric SmallVector<const CounterMappingRegion *> MCDCBranches; 663b3edf446SDimitry Andric 664b3edf446SDimitry Andric /// IDs that are stored in MCDCBranches 665b3edf446SDimitry Andric /// Complete when all IDs (1 to NumConditions) are met. 666*0fca6ea1SDimitry Andric DenseSet<mcdc::ConditionID> ConditionIDs; 667b3edf446SDimitry Andric 668b3edf446SDimitry Andric /// Set of IDs of Expansion(s) that are relevant to DecisionRegion 669b3edf446SDimitry Andric /// and its children (via expansions). 670b3edf446SDimitry Andric /// FileID pointed by ExpandedFileID is dedicated to the expansion, so 671b3edf446SDimitry Andric /// the location in the expansion doesn't matter. 672b3edf446SDimitry Andric DenseSet<unsigned> ExpandedFileIDs; 673b3edf446SDimitry Andric 674b3edf446SDimitry Andric DecisionRecord(const CounterMappingRegion &Decision) 675*0fca6ea1SDimitry Andric : DecisionRegion(&Decision), 676*0fca6ea1SDimitry Andric DecisionParams(Decision.getDecisionParams()), 677*0fca6ea1SDimitry Andric DecisionStartLoc(Decision.startLoc()), 678b3edf446SDimitry Andric DecisionEndLoc(Decision.endLoc()) { 679b3edf446SDimitry Andric assert(Decision.Kind == CounterMappingRegion::MCDCDecisionRegion); 680b3edf446SDimitry Andric } 681b3edf446SDimitry Andric 682b3edf446SDimitry Andric /// Determine whether DecisionRecord dominates `R`. 683b3edf446SDimitry Andric bool dominates(const CounterMappingRegion &R) const { 684b3edf446SDimitry Andric // Determine whether `R` is included in `DecisionRegion`. 685b3edf446SDimitry Andric if (R.FileID == DecisionRegion->FileID && 686b3edf446SDimitry Andric R.startLoc() >= DecisionStartLoc && R.endLoc() <= DecisionEndLoc) 687b3edf446SDimitry Andric return true; 688b3edf446SDimitry Andric 689b3edf446SDimitry Andric // Determine whether `R` is pointed by any of Expansions. 690b3edf446SDimitry Andric return ExpandedFileIDs.contains(R.FileID); 691b3edf446SDimitry Andric } 692b3edf446SDimitry Andric 693b3edf446SDimitry Andric enum Result { 694b3edf446SDimitry Andric NotProcessed = 0, /// Irrelevant to this Decision 695b3edf446SDimitry Andric Processed, /// Added to this Decision 696b3edf446SDimitry Andric Completed, /// Added and filled this Decision 697b3edf446SDimitry Andric }; 698b3edf446SDimitry Andric 699b3edf446SDimitry Andric /// Add Branch into the Decision 700b3edf446SDimitry Andric /// \param Branch expects MCDCBranchRegion 701b3edf446SDimitry Andric /// \returns NotProcessed/Processed/Completed 702b3edf446SDimitry Andric Result addBranch(const CounterMappingRegion &Branch) { 703b3edf446SDimitry Andric assert(Branch.Kind == CounterMappingRegion::MCDCBranchRegion); 704b3edf446SDimitry Andric 705*0fca6ea1SDimitry Andric auto ConditionID = Branch.getBranchParams().ID; 706b3edf446SDimitry Andric 707b3edf446SDimitry Andric if (ConditionIDs.contains(ConditionID) || 708*0fca6ea1SDimitry Andric ConditionID >= DecisionParams.NumConditions) 709b3edf446SDimitry Andric return NotProcessed; 710b3edf446SDimitry Andric 711b3edf446SDimitry Andric if (!this->dominates(Branch)) 712b3edf446SDimitry Andric return NotProcessed; 713b3edf446SDimitry Andric 714*0fca6ea1SDimitry Andric assert(MCDCBranches.size() < DecisionParams.NumConditions); 715b3edf446SDimitry Andric 716*0fca6ea1SDimitry Andric // Put `ID=0` in front of `MCDCBranches` for convenience 717b3edf446SDimitry Andric // even if `MCDCBranches` is not topological. 718*0fca6ea1SDimitry Andric if (ConditionID == 0) 719b3edf446SDimitry Andric MCDCBranches.insert(MCDCBranches.begin(), &Branch); 720b3edf446SDimitry Andric else 721b3edf446SDimitry Andric MCDCBranches.push_back(&Branch); 722b3edf446SDimitry Andric 723b3edf446SDimitry Andric // Mark `ID` as `assigned`. 724b3edf446SDimitry Andric ConditionIDs.insert(ConditionID); 725b3edf446SDimitry Andric 726b3edf446SDimitry Andric // `Completed` when `MCDCBranches` is full 727*0fca6ea1SDimitry Andric return (MCDCBranches.size() == DecisionParams.NumConditions ? Completed 728b3edf446SDimitry Andric : Processed); 729b3edf446SDimitry Andric } 730b3edf446SDimitry Andric 731b3edf446SDimitry Andric /// Record Expansion if it is relevant to this Decision. 732b3edf446SDimitry Andric /// Each `Expansion` may nest. 733b3edf446SDimitry Andric /// \returns true if recorded. 734b3edf446SDimitry Andric bool recordExpansion(const CounterMappingRegion &Expansion) { 735b3edf446SDimitry Andric if (!this->dominates(Expansion)) 736b3edf446SDimitry Andric return false; 737b3edf446SDimitry Andric 738b3edf446SDimitry Andric ExpandedFileIDs.insert(Expansion.ExpandedFileID); 739b3edf446SDimitry Andric return true; 740b3edf446SDimitry Andric } 741b3edf446SDimitry Andric }; 742b3edf446SDimitry Andric 743b3edf446SDimitry Andric private: 744b3edf446SDimitry Andric /// Decisions in progress 745b3edf446SDimitry Andric /// DecisionRecord is added for each MCDCDecisionRegion. 746b3edf446SDimitry Andric /// DecisionRecord is removed when Decision is completed. 747b3edf446SDimitry Andric SmallVector<DecisionRecord> Decisions; 748b3edf446SDimitry Andric 749b3edf446SDimitry Andric public: 750b3edf446SDimitry Andric ~MCDCDecisionRecorder() { 751b3edf446SDimitry Andric assert(Decisions.empty() && "All Decisions have not been resolved"); 752b3edf446SDimitry Andric } 753b3edf446SDimitry Andric 754b3edf446SDimitry Andric /// Register Region and start recording. 755b3edf446SDimitry Andric void registerDecision(const CounterMappingRegion &Decision) { 756b3edf446SDimitry Andric Decisions.emplace_back(Decision); 757b3edf446SDimitry Andric } 758b3edf446SDimitry Andric 759b3edf446SDimitry Andric void recordExpansion(const CounterMappingRegion &Expansion) { 760b3edf446SDimitry Andric any_of(Decisions, [&Expansion](auto &Decision) { 761b3edf446SDimitry Andric return Decision.recordExpansion(Expansion); 762b3edf446SDimitry Andric }); 763b3edf446SDimitry Andric } 764b3edf446SDimitry Andric 765b3edf446SDimitry Andric using DecisionAndBranches = 766b3edf446SDimitry Andric std::pair<const CounterMappingRegion *, /// Decision 767b3edf446SDimitry Andric SmallVector<const CounterMappingRegion *> /// Branches 768b3edf446SDimitry Andric >; 769b3edf446SDimitry Andric 770b3edf446SDimitry Andric /// Add MCDCBranchRegion to DecisionRecord. 771b3edf446SDimitry Andric /// \param Branch to be processed 772b3edf446SDimitry Andric /// \returns DecisionsAndBranches if DecisionRecord completed. 773b3edf446SDimitry Andric /// Or returns nullopt. 774b3edf446SDimitry Andric std::optional<DecisionAndBranches> 775b3edf446SDimitry Andric processBranch(const CounterMappingRegion &Branch) { 776b3edf446SDimitry Andric // Seek each Decision and apply Region to it. 777b3edf446SDimitry Andric for (auto DecisionIter = Decisions.begin(), DecisionEnd = Decisions.end(); 778b3edf446SDimitry Andric DecisionIter != DecisionEnd; ++DecisionIter) 779b3edf446SDimitry Andric switch (DecisionIter->addBranch(Branch)) { 780b3edf446SDimitry Andric case DecisionRecord::NotProcessed: 781b3edf446SDimitry Andric continue; 782b3edf446SDimitry Andric case DecisionRecord::Processed: 783b3edf446SDimitry Andric return std::nullopt; 784b3edf446SDimitry Andric case DecisionRecord::Completed: 785b3edf446SDimitry Andric DecisionAndBranches Result = 786b3edf446SDimitry Andric std::make_pair(DecisionIter->DecisionRegion, 787b3edf446SDimitry Andric std::move(DecisionIter->MCDCBranches)); 788b3edf446SDimitry Andric Decisions.erase(DecisionIter); // No longer used. 789b3edf446SDimitry Andric return Result; 790b3edf446SDimitry Andric } 791b3edf446SDimitry Andric 792b3edf446SDimitry Andric llvm_unreachable("Branch not found in Decisions"); 793b3edf446SDimitry Andric } 794b3edf446SDimitry Andric }; 795b3edf446SDimitry Andric 796b3edf446SDimitry Andric } // namespace 797b3edf446SDimitry Andric 7980b57cec5SDimitry Andric Error CoverageMapping::loadFunctionRecord( 7990b57cec5SDimitry Andric const CoverageMappingRecord &Record, 8000b57cec5SDimitry Andric IndexedInstrProfReader &ProfileReader) { 8010b57cec5SDimitry Andric StringRef OrigFuncName = Record.FunctionName; 8020b57cec5SDimitry Andric if (OrigFuncName.empty()) 8035f757f3fSDimitry Andric return make_error<CoverageMapError>(coveragemap_error::malformed, 8045f757f3fSDimitry Andric "record function name is empty"); 8050b57cec5SDimitry Andric 8060b57cec5SDimitry Andric if (Record.Filenames.empty()) 8070b57cec5SDimitry Andric OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName); 8080b57cec5SDimitry Andric else 8090b57cec5SDimitry Andric OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]); 8100b57cec5SDimitry Andric 8110b57cec5SDimitry Andric CounterMappingContext Ctx(Record.Expressions); 8120b57cec5SDimitry Andric 8130b57cec5SDimitry Andric std::vector<uint64_t> Counts; 8140b57cec5SDimitry Andric if (Error E = ProfileReader.getFunctionCounts(Record.FunctionName, 8150b57cec5SDimitry Andric Record.FunctionHash, Counts)) { 81606c3fb27SDimitry Andric instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E))); 8170b57cec5SDimitry Andric if (IPE == instrprof_error::hash_mismatch) { 8185ffd83dbSDimitry Andric FuncHashMismatches.emplace_back(std::string(Record.FunctionName), 8195ffd83dbSDimitry Andric Record.FunctionHash); 8200b57cec5SDimitry Andric return Error::success(); 8215f757f3fSDimitry Andric } 8225f757f3fSDimitry Andric if (IPE != instrprof_error::unknown_function) 8230b57cec5SDimitry Andric return make_error<InstrProfError>(IPE); 824fe6060f1SDimitry Andric Counts.assign(getMaxCounterID(Ctx, Record) + 1, 0); 8250b57cec5SDimitry Andric } 8260b57cec5SDimitry Andric Ctx.setCounts(Counts); 8270b57cec5SDimitry Andric 828*0fca6ea1SDimitry Andric bool IsVersion11 = 829*0fca6ea1SDimitry Andric ProfileReader.getVersion() < IndexedInstrProf::ProfVersion::Version12; 830*0fca6ea1SDimitry Andric 831*0fca6ea1SDimitry Andric BitVector Bitmap; 832*0fca6ea1SDimitry Andric if (Error E = ProfileReader.getFunctionBitmap(Record.FunctionName, 833*0fca6ea1SDimitry Andric Record.FunctionHash, Bitmap)) { 8345f757f3fSDimitry Andric instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E))); 8355f757f3fSDimitry Andric if (IPE == instrprof_error::hash_mismatch) { 8365f757f3fSDimitry Andric FuncHashMismatches.emplace_back(std::string(Record.FunctionName), 8375f757f3fSDimitry Andric Record.FunctionHash); 8385f757f3fSDimitry Andric return Error::success(); 8395f757f3fSDimitry Andric } 8405f757f3fSDimitry Andric if (IPE != instrprof_error::unknown_function) 8415f757f3fSDimitry Andric return make_error<InstrProfError>(IPE); 842*0fca6ea1SDimitry Andric Bitmap = BitVector(getMaxBitmapSize(Record, IsVersion11)); 8435f757f3fSDimitry Andric } 844*0fca6ea1SDimitry Andric Ctx.setBitmap(std::move(Bitmap)); 8455f757f3fSDimitry Andric 8460b57cec5SDimitry Andric assert(!Record.MappingRegions.empty() && "Function has no regions"); 8470b57cec5SDimitry Andric 8480b57cec5SDimitry Andric // This coverage record is a zero region for a function that's unused in 8490b57cec5SDimitry Andric // some TU, but used in a different TU. Ignore it. The coverage maps from the 8500b57cec5SDimitry Andric // the other TU will either be loaded (providing full region counts) or they 8510b57cec5SDimitry Andric // won't (in which case we don't unintuitively report functions as uncovered 8520b57cec5SDimitry Andric // when they have non-zero counts in the profile). 8530b57cec5SDimitry Andric if (Record.MappingRegions.size() == 1 && 8540b57cec5SDimitry Andric Record.MappingRegions[0].Count.isZero() && Counts[0] > 0) 8550b57cec5SDimitry Andric return Error::success(); 8560b57cec5SDimitry Andric 857b3edf446SDimitry Andric MCDCDecisionRecorder MCDCDecisions; 8580b57cec5SDimitry Andric FunctionRecord Function(OrigFuncName, Record.Filenames); 8590b57cec5SDimitry Andric for (const auto &Region : Record.MappingRegions) { 860b3edf446SDimitry Andric // MCDCDecisionRegion should be handled first since it overlaps with 861b3edf446SDimitry Andric // others inside. 8625f757f3fSDimitry Andric if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion) { 863b3edf446SDimitry Andric MCDCDecisions.registerDecision(Region); 8645f757f3fSDimitry Andric continue; 8655f757f3fSDimitry Andric } 8660b57cec5SDimitry Andric Expected<int64_t> ExecutionCount = Ctx.evaluate(Region.Count); 8670b57cec5SDimitry Andric if (auto E = ExecutionCount.takeError()) { 8680b57cec5SDimitry Andric consumeError(std::move(E)); 8690b57cec5SDimitry Andric return Error::success(); 8700b57cec5SDimitry Andric } 871e8d8bef9SDimitry Andric Expected<int64_t> AltExecutionCount = Ctx.evaluate(Region.FalseCount); 872e8d8bef9SDimitry Andric if (auto E = AltExecutionCount.takeError()) { 873e8d8bef9SDimitry Andric consumeError(std::move(E)); 874e8d8bef9SDimitry Andric return Error::success(); 875e8d8bef9SDimitry Andric } 876*0fca6ea1SDimitry Andric Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount, 877*0fca6ea1SDimitry Andric ProfileReader.hasSingleByteCoverage()); 8785f757f3fSDimitry Andric 879b3edf446SDimitry Andric // Record ExpansionRegion. 880b3edf446SDimitry Andric if (Region.Kind == CounterMappingRegion::ExpansionRegion) { 881b3edf446SDimitry Andric MCDCDecisions.recordExpansion(Region); 882b3edf446SDimitry Andric continue; 883b3edf446SDimitry Andric } 8845f757f3fSDimitry Andric 885b3edf446SDimitry Andric // Do nothing unless MCDCBranchRegion. 886b3edf446SDimitry Andric if (Region.Kind != CounterMappingRegion::MCDCBranchRegion) 887b3edf446SDimitry Andric continue; 888b3edf446SDimitry Andric 889b3edf446SDimitry Andric auto Result = MCDCDecisions.processBranch(Region); 890b3edf446SDimitry Andric if (!Result) // Any Decision doesn't complete. 891b3edf446SDimitry Andric continue; 892b3edf446SDimitry Andric 893b3edf446SDimitry Andric auto MCDCDecision = Result->first; 894b3edf446SDimitry Andric auto &MCDCBranches = Result->second; 895b3edf446SDimitry Andric 8965f757f3fSDimitry Andric // Since the bitmap identifies the executed test vectors for an MC/DC 8975f757f3fSDimitry Andric // DecisionRegion, all of the information is now available to process. 8985f757f3fSDimitry Andric // This is where the bulk of the MC/DC progressing takes place. 899*0fca6ea1SDimitry Andric Expected<MCDCRecord> Record = 900*0fca6ea1SDimitry Andric Ctx.evaluateMCDCRegion(*MCDCDecision, MCDCBranches, IsVersion11); 9015f757f3fSDimitry Andric if (auto E = Record.takeError()) { 9025f757f3fSDimitry Andric consumeError(std::move(E)); 9035f757f3fSDimitry Andric return Error::success(); 9045f757f3fSDimitry Andric } 9055f757f3fSDimitry Andric 9065f757f3fSDimitry Andric // Save the MC/DC Record so that it can be visualized later. 907*0fca6ea1SDimitry Andric Function.pushMCDCRecord(std::move(*Record)); 9080b57cec5SDimitry Andric } 9090b57cec5SDimitry Andric 9100b57cec5SDimitry Andric // Don't create records for (filenames, function) pairs we've already seen. 9110b57cec5SDimitry Andric auto FilenamesHash = hash_combine_range(Record.Filenames.begin(), 9120b57cec5SDimitry Andric Record.Filenames.end()); 9130b57cec5SDimitry Andric if (!RecordProvenance[FilenamesHash].insert(hash_value(OrigFuncName)).second) 9140b57cec5SDimitry Andric return Error::success(); 9150b57cec5SDimitry Andric 9160b57cec5SDimitry Andric Functions.push_back(std::move(Function)); 9178bcb0991SDimitry Andric 9188bcb0991SDimitry Andric // Performance optimization: keep track of the indices of the function records 9198bcb0991SDimitry Andric // which correspond to each filename. This can be used to substantially speed 9208bcb0991SDimitry Andric // up queries for coverage info in a file. 9218bcb0991SDimitry Andric unsigned RecordIndex = Functions.size() - 1; 9228bcb0991SDimitry Andric for (StringRef Filename : Record.Filenames) { 9238bcb0991SDimitry Andric auto &RecordIndices = FilenameHash2RecordIndices[hash_value(Filename)]; 9248bcb0991SDimitry Andric // Note that there may be duplicates in the filename set for a function 9258bcb0991SDimitry Andric // record, because of e.g. macro expansions in the function in which both 9268bcb0991SDimitry Andric // the macro and the function are defined in the same file. 9278bcb0991SDimitry Andric if (RecordIndices.empty() || RecordIndices.back() != RecordIndex) 9288bcb0991SDimitry Andric RecordIndices.push_back(RecordIndex); 9298bcb0991SDimitry Andric } 9308bcb0991SDimitry Andric 9310b57cec5SDimitry Andric return Error::success(); 9320b57cec5SDimitry Andric } 9330b57cec5SDimitry Andric 934fe6060f1SDimitry Andric // This function is for memory optimization by shortening the lifetimes 935fe6060f1SDimitry Andric // of CoverageMappingReader instances. 936fe6060f1SDimitry Andric Error CoverageMapping::loadFromReaders( 937fe6060f1SDimitry Andric ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders, 938fe6060f1SDimitry Andric IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage) { 939fe6060f1SDimitry Andric for (const auto &CoverageReader : CoverageReaders) { 940fe6060f1SDimitry Andric for (auto RecordOrErr : *CoverageReader) { 941fe6060f1SDimitry Andric if (Error E = RecordOrErr.takeError()) 942fe6060f1SDimitry Andric return E; 943fe6060f1SDimitry Andric const auto &Record = *RecordOrErr; 944fe6060f1SDimitry Andric if (Error E = Coverage.loadFunctionRecord(Record, ProfileReader)) 945fe6060f1SDimitry Andric return E; 946fe6060f1SDimitry Andric } 947fe6060f1SDimitry Andric } 948fe6060f1SDimitry Andric return Error::success(); 949fe6060f1SDimitry Andric } 950fe6060f1SDimitry Andric 9510b57cec5SDimitry Andric Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load( 9520b57cec5SDimitry Andric ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders, 9530b57cec5SDimitry Andric IndexedInstrProfReader &ProfileReader) { 9540b57cec5SDimitry Andric auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping()); 955fe6060f1SDimitry Andric if (Error E = loadFromReaders(CoverageReaders, ProfileReader, *Coverage)) 9560b57cec5SDimitry Andric return std::move(E); 9570b57cec5SDimitry Andric return std::move(Coverage); 9580b57cec5SDimitry Andric } 9590b57cec5SDimitry Andric 9608bcb0991SDimitry Andric // If E is a no_data_found error, returns success. Otherwise returns E. 9618bcb0991SDimitry Andric static Error handleMaybeNoDataFoundError(Error E) { 9628bcb0991SDimitry Andric return handleErrors( 9638bcb0991SDimitry Andric std::move(E), [](const CoverageMapError &CME) { 9648bcb0991SDimitry Andric if (CME.get() == coveragemap_error::no_data_found) 9658bcb0991SDimitry Andric return static_cast<Error>(Error::success()); 9665f757f3fSDimitry Andric return make_error<CoverageMapError>(CME.get(), CME.getMessage()); 9678bcb0991SDimitry Andric }); 9688bcb0991SDimitry Andric } 9698bcb0991SDimitry Andric 9701ac55f4cSDimitry Andric Error CoverageMapping::loadFromFile( 9711ac55f4cSDimitry Andric StringRef Filename, StringRef Arch, StringRef CompilationDir, 9721ac55f4cSDimitry Andric IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage, 9731ac55f4cSDimitry Andric bool &DataFound, SmallVectorImpl<object::BuildID> *FoundBinaryIDs) { 9741ac55f4cSDimitry Andric auto CovMappingBufOrErr = MemoryBuffer::getFileOrSTDIN( 9751ac55f4cSDimitry Andric Filename, /*IsText=*/false, /*RequiresNullTerminator=*/false); 9761ac55f4cSDimitry Andric if (std::error_code EC = CovMappingBufOrErr.getError()) 9771ac55f4cSDimitry Andric return createFileError(Filename, errorCodeToError(EC)); 9781ac55f4cSDimitry Andric MemoryBufferRef CovMappingBufRef = 9791ac55f4cSDimitry Andric CovMappingBufOrErr.get()->getMemBufferRef(); 9801ac55f4cSDimitry Andric SmallVector<std::unique_ptr<MemoryBuffer>, 4> Buffers; 9811ac55f4cSDimitry Andric 9821ac55f4cSDimitry Andric SmallVector<object::BuildIDRef> BinaryIDs; 9831ac55f4cSDimitry Andric auto CoverageReadersOrErr = BinaryCoverageReader::create( 9841ac55f4cSDimitry Andric CovMappingBufRef, Arch, Buffers, CompilationDir, 9851ac55f4cSDimitry Andric FoundBinaryIDs ? &BinaryIDs : nullptr); 9861ac55f4cSDimitry Andric if (Error E = CoverageReadersOrErr.takeError()) { 9871ac55f4cSDimitry Andric E = handleMaybeNoDataFoundError(std::move(E)); 9881ac55f4cSDimitry Andric if (E) 9891ac55f4cSDimitry Andric return createFileError(Filename, std::move(E)); 9901ac55f4cSDimitry Andric return E; 9911ac55f4cSDimitry Andric } 9921ac55f4cSDimitry Andric 9931ac55f4cSDimitry Andric SmallVector<std::unique_ptr<CoverageMappingReader>, 4> Readers; 9941ac55f4cSDimitry Andric for (auto &Reader : CoverageReadersOrErr.get()) 9951ac55f4cSDimitry Andric Readers.push_back(std::move(Reader)); 9961ac55f4cSDimitry Andric if (FoundBinaryIDs && !Readers.empty()) { 9971ac55f4cSDimitry Andric llvm::append_range(*FoundBinaryIDs, 9981ac55f4cSDimitry Andric llvm::map_range(BinaryIDs, [](object::BuildIDRef BID) { 9991ac55f4cSDimitry Andric return object::BuildID(BID); 10001ac55f4cSDimitry Andric })); 10011ac55f4cSDimitry Andric } 10021ac55f4cSDimitry Andric DataFound |= !Readers.empty(); 10031ac55f4cSDimitry Andric if (Error E = loadFromReaders(Readers, ProfileReader, Coverage)) 10041ac55f4cSDimitry Andric return createFileError(Filename, std::move(E)); 10051ac55f4cSDimitry Andric return Error::success(); 10061ac55f4cSDimitry Andric } 10071ac55f4cSDimitry Andric 100806c3fb27SDimitry Andric Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load( 100906c3fb27SDimitry Andric ArrayRef<StringRef> ObjectFilenames, StringRef ProfileFilename, 101006c3fb27SDimitry Andric vfs::FileSystem &FS, ArrayRef<StringRef> Arches, StringRef CompilationDir, 101106c3fb27SDimitry Andric const object::BuildIDFetcher *BIDFetcher, bool CheckBinaryIDs) { 101206c3fb27SDimitry Andric auto ProfileReaderOrErr = IndexedInstrProfReader::create(ProfileFilename, FS); 10130b57cec5SDimitry Andric if (Error E = ProfileReaderOrErr.takeError()) 1014fcaf7f86SDimitry Andric return createFileError(ProfileFilename, std::move(E)); 10150b57cec5SDimitry Andric auto ProfileReader = std::move(ProfileReaderOrErr.get()); 1016fe6060f1SDimitry Andric auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping()); 1017fe6060f1SDimitry Andric bool DataFound = false; 10180b57cec5SDimitry Andric 10191ac55f4cSDimitry Andric auto GetArch = [&](size_t Idx) { 10201ac55f4cSDimitry Andric if (Arches.empty()) 10211ac55f4cSDimitry Andric return StringRef(); 10221ac55f4cSDimitry Andric if (Arches.size() == 1) 10231ac55f4cSDimitry Andric return Arches.front(); 10241ac55f4cSDimitry Andric return Arches[Idx]; 10251ac55f4cSDimitry Andric }; 10261ac55f4cSDimitry Andric 10271ac55f4cSDimitry Andric SmallVector<object::BuildID> FoundBinaryIDs; 10280b57cec5SDimitry Andric for (const auto &File : llvm::enumerate(ObjectFilenames)) { 10291ac55f4cSDimitry Andric if (Error E = 10301ac55f4cSDimitry Andric loadFromFile(File.value(), GetArch(File.index()), CompilationDir, 10311ac55f4cSDimitry Andric *ProfileReader, *Coverage, DataFound, &FoundBinaryIDs)) 10321ac55f4cSDimitry Andric return std::move(E); 10338bcb0991SDimitry Andric } 1034fe6060f1SDimitry Andric 10351ac55f4cSDimitry Andric if (BIDFetcher) { 10361ac55f4cSDimitry Andric std::vector<object::BuildID> ProfileBinaryIDs; 10371ac55f4cSDimitry Andric if (Error E = ProfileReader->readBinaryIds(ProfileBinaryIDs)) 10381ac55f4cSDimitry Andric return createFileError(ProfileFilename, std::move(E)); 10391ac55f4cSDimitry Andric 10401ac55f4cSDimitry Andric SmallVector<object::BuildIDRef> BinaryIDsToFetch; 10411ac55f4cSDimitry Andric if (!ProfileBinaryIDs.empty()) { 10421ac55f4cSDimitry Andric const auto &Compare = [](object::BuildIDRef A, object::BuildIDRef B) { 10431ac55f4cSDimitry Andric return std::lexicographical_compare(A.begin(), A.end(), B.begin(), 10441ac55f4cSDimitry Andric B.end()); 10451ac55f4cSDimitry Andric }; 10461ac55f4cSDimitry Andric llvm::sort(FoundBinaryIDs, Compare); 10471ac55f4cSDimitry Andric std::set_difference( 10481ac55f4cSDimitry Andric ProfileBinaryIDs.begin(), ProfileBinaryIDs.end(), 10491ac55f4cSDimitry Andric FoundBinaryIDs.begin(), FoundBinaryIDs.end(), 10501ac55f4cSDimitry Andric std::inserter(BinaryIDsToFetch, BinaryIDsToFetch.end()), Compare); 10510b57cec5SDimitry Andric } 10521ac55f4cSDimitry Andric 10531ac55f4cSDimitry Andric for (object::BuildIDRef BinaryID : BinaryIDsToFetch) { 10541ac55f4cSDimitry Andric std::optional<std::string> PathOpt = BIDFetcher->fetch(BinaryID); 105506c3fb27SDimitry Andric if (PathOpt) { 10561ac55f4cSDimitry Andric std::string Path = std::move(*PathOpt); 10571ac55f4cSDimitry Andric StringRef Arch = Arches.size() == 1 ? Arches.front() : StringRef(); 10581ac55f4cSDimitry Andric if (Error E = loadFromFile(Path, Arch, CompilationDir, *ProfileReader, 10591ac55f4cSDimitry Andric *Coverage, DataFound)) 10601ac55f4cSDimitry Andric return std::move(E); 106106c3fb27SDimitry Andric } else if (CheckBinaryIDs) { 106206c3fb27SDimitry Andric return createFileError( 106306c3fb27SDimitry Andric ProfileFilename, 106406c3fb27SDimitry Andric createStringError(errc::no_such_file_or_directory, 106506c3fb27SDimitry Andric "Missing binary ID: " + 106606c3fb27SDimitry Andric llvm::toHex(BinaryID, /*LowerCase=*/true))); 106706c3fb27SDimitry Andric } 10681ac55f4cSDimitry Andric } 10691ac55f4cSDimitry Andric } 10701ac55f4cSDimitry Andric 10711ac55f4cSDimitry Andric if (!DataFound) 1072fcaf7f86SDimitry Andric return createFileError( 1073fcaf7f86SDimitry Andric join(ObjectFilenames.begin(), ObjectFilenames.end(), ", "), 1074fcaf7f86SDimitry Andric make_error<CoverageMapError>(coveragemap_error::no_data_found)); 1075fe6060f1SDimitry Andric return std::move(Coverage); 10760b57cec5SDimitry Andric } 10770b57cec5SDimitry Andric 10780b57cec5SDimitry Andric namespace { 10790b57cec5SDimitry Andric 10800b57cec5SDimitry Andric /// Distributes functions into instantiation sets. 10810b57cec5SDimitry Andric /// 10820b57cec5SDimitry Andric /// An instantiation set is a collection of functions that have the same source 10830b57cec5SDimitry Andric /// code, ie, template functions specializations. 10840b57cec5SDimitry Andric class FunctionInstantiationSetCollector { 10850b57cec5SDimitry Andric using MapT = std::map<LineColPair, std::vector<const FunctionRecord *>>; 10860b57cec5SDimitry Andric MapT InstantiatedFunctions; 10870b57cec5SDimitry Andric 10880b57cec5SDimitry Andric public: 10890b57cec5SDimitry Andric void insert(const FunctionRecord &Function, unsigned FileID) { 10900b57cec5SDimitry Andric auto I = Function.CountedRegions.begin(), E = Function.CountedRegions.end(); 10910b57cec5SDimitry Andric while (I != E && I->FileID != FileID) 10920b57cec5SDimitry Andric ++I; 10930b57cec5SDimitry Andric assert(I != E && "function does not cover the given file"); 10940b57cec5SDimitry Andric auto &Functions = InstantiatedFunctions[I->startLoc()]; 10950b57cec5SDimitry Andric Functions.push_back(&Function); 10960b57cec5SDimitry Andric } 10970b57cec5SDimitry Andric 10980b57cec5SDimitry Andric MapT::iterator begin() { return InstantiatedFunctions.begin(); } 10990b57cec5SDimitry Andric MapT::iterator end() { return InstantiatedFunctions.end(); } 11000b57cec5SDimitry Andric }; 11010b57cec5SDimitry Andric 11020b57cec5SDimitry Andric class SegmentBuilder { 11030b57cec5SDimitry Andric std::vector<CoverageSegment> &Segments; 11040b57cec5SDimitry Andric SmallVector<const CountedRegion *, 8> ActiveRegions; 11050b57cec5SDimitry Andric 11060b57cec5SDimitry Andric SegmentBuilder(std::vector<CoverageSegment> &Segments) : Segments(Segments) {} 11070b57cec5SDimitry Andric 11080b57cec5SDimitry Andric /// Emit a segment with the count from \p Region starting at \p StartLoc. 11090b57cec5SDimitry Andric // 11100b57cec5SDimitry Andric /// \p IsRegionEntry: The segment is at the start of a new non-gap region. 11110b57cec5SDimitry Andric /// \p EmitSkippedRegion: The segment must be emitted as a skipped region. 11120b57cec5SDimitry Andric void startSegment(const CountedRegion &Region, LineColPair StartLoc, 11130b57cec5SDimitry Andric bool IsRegionEntry, bool EmitSkippedRegion = false) { 11140b57cec5SDimitry Andric bool HasCount = !EmitSkippedRegion && 11150b57cec5SDimitry Andric (Region.Kind != CounterMappingRegion::SkippedRegion); 11160b57cec5SDimitry Andric 11170b57cec5SDimitry Andric // If the new segment wouldn't affect coverage rendering, skip it. 11180b57cec5SDimitry Andric if (!Segments.empty() && !IsRegionEntry && !EmitSkippedRegion) { 11190b57cec5SDimitry Andric const auto &Last = Segments.back(); 11200b57cec5SDimitry Andric if (Last.HasCount == HasCount && Last.Count == Region.ExecutionCount && 11210b57cec5SDimitry Andric !Last.IsRegionEntry) 11220b57cec5SDimitry Andric return; 11230b57cec5SDimitry Andric } 11240b57cec5SDimitry Andric 11250b57cec5SDimitry Andric if (HasCount) 11260b57cec5SDimitry Andric Segments.emplace_back(StartLoc.first, StartLoc.second, 11270b57cec5SDimitry Andric Region.ExecutionCount, IsRegionEntry, 11280b57cec5SDimitry Andric Region.Kind == CounterMappingRegion::GapRegion); 11290b57cec5SDimitry Andric else 11300b57cec5SDimitry Andric Segments.emplace_back(StartLoc.first, StartLoc.second, IsRegionEntry); 11310b57cec5SDimitry Andric 11320b57cec5SDimitry Andric LLVM_DEBUG({ 11330b57cec5SDimitry Andric const auto &Last = Segments.back(); 11340b57cec5SDimitry Andric dbgs() << "Segment at " << Last.Line << ":" << Last.Col 11350b57cec5SDimitry Andric << " (count = " << Last.Count << ")" 11360b57cec5SDimitry Andric << (Last.IsRegionEntry ? ", RegionEntry" : "") 11370b57cec5SDimitry Andric << (!Last.HasCount ? ", Skipped" : "") 11380b57cec5SDimitry Andric << (Last.IsGapRegion ? ", Gap" : "") << "\n"; 11390b57cec5SDimitry Andric }); 11400b57cec5SDimitry Andric } 11410b57cec5SDimitry Andric 11420b57cec5SDimitry Andric /// Emit segments for active regions which end before \p Loc. 11430b57cec5SDimitry Andric /// 1144bdd1243dSDimitry Andric /// \p Loc: The start location of the next region. If std::nullopt, all active 11450b57cec5SDimitry Andric /// regions are completed. 11460b57cec5SDimitry Andric /// \p FirstCompletedRegion: Index of the first completed region. 1147bdd1243dSDimitry Andric void completeRegionsUntil(std::optional<LineColPair> Loc, 11480b57cec5SDimitry Andric unsigned FirstCompletedRegion) { 11490b57cec5SDimitry Andric // Sort the completed regions by end location. This makes it simple to 11500b57cec5SDimitry Andric // emit closing segments in sorted order. 11510b57cec5SDimitry Andric auto CompletedRegionsIt = ActiveRegions.begin() + FirstCompletedRegion; 11520b57cec5SDimitry Andric std::stable_sort(CompletedRegionsIt, ActiveRegions.end(), 11530b57cec5SDimitry Andric [](const CountedRegion *L, const CountedRegion *R) { 11540b57cec5SDimitry Andric return L->endLoc() < R->endLoc(); 11550b57cec5SDimitry Andric }); 11560b57cec5SDimitry Andric 11570b57cec5SDimitry Andric // Emit segments for all completed regions. 11580b57cec5SDimitry Andric for (unsigned I = FirstCompletedRegion + 1, E = ActiveRegions.size(); I < E; 11590b57cec5SDimitry Andric ++I) { 11600b57cec5SDimitry Andric const auto *CompletedRegion = ActiveRegions[I]; 11610b57cec5SDimitry Andric assert((!Loc || CompletedRegion->endLoc() <= *Loc) && 11620b57cec5SDimitry Andric "Completed region ends after start of new region"); 11630b57cec5SDimitry Andric 11640b57cec5SDimitry Andric const auto *PrevCompletedRegion = ActiveRegions[I - 1]; 11650b57cec5SDimitry Andric auto CompletedSegmentLoc = PrevCompletedRegion->endLoc(); 11660b57cec5SDimitry Andric 11670b57cec5SDimitry Andric // Don't emit any more segments if they start where the new region begins. 11680b57cec5SDimitry Andric if (Loc && CompletedSegmentLoc == *Loc) 11690b57cec5SDimitry Andric break; 11700b57cec5SDimitry Andric 11710b57cec5SDimitry Andric // Don't emit a segment if the next completed region ends at the same 11720b57cec5SDimitry Andric // location as this one. 11730b57cec5SDimitry Andric if (CompletedSegmentLoc == CompletedRegion->endLoc()) 11740b57cec5SDimitry Andric continue; 11750b57cec5SDimitry Andric 11760b57cec5SDimitry Andric // Use the count from the last completed region which ends at this loc. 11770b57cec5SDimitry Andric for (unsigned J = I + 1; J < E; ++J) 11780b57cec5SDimitry Andric if (CompletedRegion->endLoc() == ActiveRegions[J]->endLoc()) 11790b57cec5SDimitry Andric CompletedRegion = ActiveRegions[J]; 11800b57cec5SDimitry Andric 11810b57cec5SDimitry Andric startSegment(*CompletedRegion, CompletedSegmentLoc, false); 11820b57cec5SDimitry Andric } 11830b57cec5SDimitry Andric 11840b57cec5SDimitry Andric auto Last = ActiveRegions.back(); 11850b57cec5SDimitry Andric if (FirstCompletedRegion && Last->endLoc() != *Loc) { 11860b57cec5SDimitry Andric // If there's a gap after the end of the last completed region and the 11870b57cec5SDimitry Andric // start of the new region, use the last active region to fill the gap. 11880b57cec5SDimitry Andric startSegment(*ActiveRegions[FirstCompletedRegion - 1], Last->endLoc(), 11890b57cec5SDimitry Andric false); 11900b57cec5SDimitry Andric } else if (!FirstCompletedRegion && (!Loc || *Loc != Last->endLoc())) { 11910b57cec5SDimitry Andric // Emit a skipped segment if there are no more active regions. This 11920b57cec5SDimitry Andric // ensures that gaps between functions are marked correctly. 11930b57cec5SDimitry Andric startSegment(*Last, Last->endLoc(), false, true); 11940b57cec5SDimitry Andric } 11950b57cec5SDimitry Andric 11960b57cec5SDimitry Andric // Pop the completed regions. 11970b57cec5SDimitry Andric ActiveRegions.erase(CompletedRegionsIt, ActiveRegions.end()); 11980b57cec5SDimitry Andric } 11990b57cec5SDimitry Andric 12000b57cec5SDimitry Andric void buildSegmentsImpl(ArrayRef<CountedRegion> Regions) { 12010b57cec5SDimitry Andric for (const auto &CR : enumerate(Regions)) { 12020b57cec5SDimitry Andric auto CurStartLoc = CR.value().startLoc(); 12030b57cec5SDimitry Andric 12040b57cec5SDimitry Andric // Active regions which end before the current region need to be popped. 12050b57cec5SDimitry Andric auto CompletedRegions = 12060b57cec5SDimitry Andric std::stable_partition(ActiveRegions.begin(), ActiveRegions.end(), 12070b57cec5SDimitry Andric [&](const CountedRegion *Region) { 12080b57cec5SDimitry Andric return !(Region->endLoc() <= CurStartLoc); 12090b57cec5SDimitry Andric }); 12100b57cec5SDimitry Andric if (CompletedRegions != ActiveRegions.end()) { 12110b57cec5SDimitry Andric unsigned FirstCompletedRegion = 12120b57cec5SDimitry Andric std::distance(ActiveRegions.begin(), CompletedRegions); 12130b57cec5SDimitry Andric completeRegionsUntil(CurStartLoc, FirstCompletedRegion); 12140b57cec5SDimitry Andric } 12150b57cec5SDimitry Andric 12160b57cec5SDimitry Andric bool GapRegion = CR.value().Kind == CounterMappingRegion::GapRegion; 12170b57cec5SDimitry Andric 12180b57cec5SDimitry Andric // Try to emit a segment for the current region. 12190b57cec5SDimitry Andric if (CurStartLoc == CR.value().endLoc()) { 12200b57cec5SDimitry Andric // Avoid making zero-length regions active. If it's the last region, 12210b57cec5SDimitry Andric // emit a skipped segment. Otherwise use its predecessor's count. 1222e8d8bef9SDimitry Andric const bool Skipped = 1223e8d8bef9SDimitry Andric (CR.index() + 1) == Regions.size() || 1224e8d8bef9SDimitry Andric CR.value().Kind == CounterMappingRegion::SkippedRegion; 12250b57cec5SDimitry Andric startSegment(ActiveRegions.empty() ? CR.value() : *ActiveRegions.back(), 12260b57cec5SDimitry Andric CurStartLoc, !GapRegion, Skipped); 1227e8d8bef9SDimitry Andric // If it is skipped segment, create a segment with last pushed 1228e8d8bef9SDimitry Andric // regions's count at CurStartLoc. 1229e8d8bef9SDimitry Andric if (Skipped && !ActiveRegions.empty()) 1230e8d8bef9SDimitry Andric startSegment(*ActiveRegions.back(), CurStartLoc, false); 12310b57cec5SDimitry Andric continue; 12320b57cec5SDimitry Andric } 12330b57cec5SDimitry Andric if (CR.index() + 1 == Regions.size() || 12340b57cec5SDimitry Andric CurStartLoc != Regions[CR.index() + 1].startLoc()) { 12350b57cec5SDimitry Andric // Emit a segment if the next region doesn't start at the same location 12360b57cec5SDimitry Andric // as this one. 12370b57cec5SDimitry Andric startSegment(CR.value(), CurStartLoc, !GapRegion); 12380b57cec5SDimitry Andric } 12390b57cec5SDimitry Andric 12400b57cec5SDimitry Andric // This region is active (i.e not completed). 12410b57cec5SDimitry Andric ActiveRegions.push_back(&CR.value()); 12420b57cec5SDimitry Andric } 12430b57cec5SDimitry Andric 12440b57cec5SDimitry Andric // Complete any remaining active regions. 12450b57cec5SDimitry Andric if (!ActiveRegions.empty()) 1246bdd1243dSDimitry Andric completeRegionsUntil(std::nullopt, 0); 12470b57cec5SDimitry Andric } 12480b57cec5SDimitry Andric 12490b57cec5SDimitry Andric /// Sort a nested sequence of regions from a single file. 12500b57cec5SDimitry Andric static void sortNestedRegions(MutableArrayRef<CountedRegion> Regions) { 12510b57cec5SDimitry Andric llvm::sort(Regions, [](const CountedRegion &LHS, const CountedRegion &RHS) { 12520b57cec5SDimitry Andric if (LHS.startLoc() != RHS.startLoc()) 12530b57cec5SDimitry Andric return LHS.startLoc() < RHS.startLoc(); 12540b57cec5SDimitry Andric if (LHS.endLoc() != RHS.endLoc()) 12550b57cec5SDimitry Andric // When LHS completely contains RHS, we sort LHS first. 12560b57cec5SDimitry Andric return RHS.endLoc() < LHS.endLoc(); 12570b57cec5SDimitry Andric // If LHS and RHS cover the same area, we need to sort them according 12580b57cec5SDimitry Andric // to their kinds so that the most suitable region will become "active" 12590b57cec5SDimitry Andric // in combineRegions(). Because we accumulate counter values only from 12600b57cec5SDimitry Andric // regions of the same kind as the first region of the area, prefer 12610b57cec5SDimitry Andric // CodeRegion to ExpansionRegion and ExpansionRegion to SkippedRegion. 12620b57cec5SDimitry Andric static_assert(CounterMappingRegion::CodeRegion < 12630b57cec5SDimitry Andric CounterMappingRegion::ExpansionRegion && 12640b57cec5SDimitry Andric CounterMappingRegion::ExpansionRegion < 12650b57cec5SDimitry Andric CounterMappingRegion::SkippedRegion, 12660b57cec5SDimitry Andric "Unexpected order of region kind values"); 12670b57cec5SDimitry Andric return LHS.Kind < RHS.Kind; 12680b57cec5SDimitry Andric }); 12690b57cec5SDimitry Andric } 12700b57cec5SDimitry Andric 12710b57cec5SDimitry Andric /// Combine counts of regions which cover the same area. 12720b57cec5SDimitry Andric static ArrayRef<CountedRegion> 12730b57cec5SDimitry Andric combineRegions(MutableArrayRef<CountedRegion> Regions) { 12740b57cec5SDimitry Andric if (Regions.empty()) 12750b57cec5SDimitry Andric return Regions; 12760b57cec5SDimitry Andric auto Active = Regions.begin(); 12770b57cec5SDimitry Andric auto End = Regions.end(); 12780b57cec5SDimitry Andric for (auto I = Regions.begin() + 1; I != End; ++I) { 12790b57cec5SDimitry Andric if (Active->startLoc() != I->startLoc() || 12800b57cec5SDimitry Andric Active->endLoc() != I->endLoc()) { 12810b57cec5SDimitry Andric // Shift to the next region. 12820b57cec5SDimitry Andric ++Active; 12830b57cec5SDimitry Andric if (Active != I) 12840b57cec5SDimitry Andric *Active = *I; 12850b57cec5SDimitry Andric continue; 12860b57cec5SDimitry Andric } 12870b57cec5SDimitry Andric // Merge duplicate region. 12880b57cec5SDimitry Andric // If CodeRegions and ExpansionRegions cover the same area, it's probably 12890b57cec5SDimitry Andric // a macro which is fully expanded to another macro. In that case, we need 12900b57cec5SDimitry Andric // to accumulate counts only from CodeRegions, or else the area will be 12910b57cec5SDimitry Andric // counted twice. 12920b57cec5SDimitry Andric // On the other hand, a macro may have a nested macro in its body. If the 12930b57cec5SDimitry Andric // outer macro is used several times, the ExpansionRegion for the nested 12940b57cec5SDimitry Andric // macro will also be added several times. These ExpansionRegions cover 12950b57cec5SDimitry Andric // the same source locations and have to be combined to reach the correct 12960b57cec5SDimitry Andric // value for that area. 12970b57cec5SDimitry Andric // We add counts of the regions of the same kind as the active region 12980b57cec5SDimitry Andric // to handle the both situations. 1299*0fca6ea1SDimitry Andric if (I->Kind == Active->Kind) { 1300*0fca6ea1SDimitry Andric assert(I->HasSingleByteCoverage == Active->HasSingleByteCoverage && 1301*0fca6ea1SDimitry Andric "Regions are generated in different coverage modes"); 1302*0fca6ea1SDimitry Andric if (I->HasSingleByteCoverage) 1303*0fca6ea1SDimitry Andric Active->ExecutionCount = Active->ExecutionCount || I->ExecutionCount; 1304*0fca6ea1SDimitry Andric else 13050b57cec5SDimitry Andric Active->ExecutionCount += I->ExecutionCount; 13060b57cec5SDimitry Andric } 1307*0fca6ea1SDimitry Andric } 13080b57cec5SDimitry Andric return Regions.drop_back(std::distance(++Active, End)); 13090b57cec5SDimitry Andric } 13100b57cec5SDimitry Andric 13110b57cec5SDimitry Andric public: 13120b57cec5SDimitry Andric /// Build a sorted list of CoverageSegments from a list of Regions. 13130b57cec5SDimitry Andric static std::vector<CoverageSegment> 13140b57cec5SDimitry Andric buildSegments(MutableArrayRef<CountedRegion> Regions) { 13150b57cec5SDimitry Andric std::vector<CoverageSegment> Segments; 13160b57cec5SDimitry Andric SegmentBuilder Builder(Segments); 13170b57cec5SDimitry Andric 13180b57cec5SDimitry Andric sortNestedRegions(Regions); 13190b57cec5SDimitry Andric ArrayRef<CountedRegion> CombinedRegions = combineRegions(Regions); 13200b57cec5SDimitry Andric 13210b57cec5SDimitry Andric LLVM_DEBUG({ 13220b57cec5SDimitry Andric dbgs() << "Combined regions:\n"; 13230b57cec5SDimitry Andric for (const auto &CR : CombinedRegions) 13240b57cec5SDimitry Andric dbgs() << " " << CR.LineStart << ":" << CR.ColumnStart << " -> " 13250b57cec5SDimitry Andric << CR.LineEnd << ":" << CR.ColumnEnd 13260b57cec5SDimitry Andric << " (count=" << CR.ExecutionCount << ")\n"; 13270b57cec5SDimitry Andric }); 13280b57cec5SDimitry Andric 13290b57cec5SDimitry Andric Builder.buildSegmentsImpl(CombinedRegions); 13300b57cec5SDimitry Andric 13310b57cec5SDimitry Andric #ifndef NDEBUG 13320b57cec5SDimitry Andric for (unsigned I = 1, E = Segments.size(); I < E; ++I) { 13330b57cec5SDimitry Andric const auto &L = Segments[I - 1]; 13340b57cec5SDimitry Andric const auto &R = Segments[I]; 13350b57cec5SDimitry Andric if (!(L.Line < R.Line) && !(L.Line == R.Line && L.Col < R.Col)) { 1336e8d8bef9SDimitry Andric if (L.Line == R.Line && L.Col == R.Col && !L.HasCount) 1337e8d8bef9SDimitry Andric continue; 13380b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " ! Segment " << L.Line << ":" << L.Col 13390b57cec5SDimitry Andric << " followed by " << R.Line << ":" << R.Col << "\n"); 13400b57cec5SDimitry Andric assert(false && "Coverage segments not unique or sorted"); 13410b57cec5SDimitry Andric } 13420b57cec5SDimitry Andric } 13430b57cec5SDimitry Andric #endif 13440b57cec5SDimitry Andric 13450b57cec5SDimitry Andric return Segments; 13460b57cec5SDimitry Andric } 13470b57cec5SDimitry Andric }; 13480b57cec5SDimitry Andric 13490b57cec5SDimitry Andric } // end anonymous namespace 13500b57cec5SDimitry Andric 13510b57cec5SDimitry Andric std::vector<StringRef> CoverageMapping::getUniqueSourceFiles() const { 13520b57cec5SDimitry Andric std::vector<StringRef> Filenames; 13530b57cec5SDimitry Andric for (const auto &Function : getCoveredFunctions()) 1354e8d8bef9SDimitry Andric llvm::append_range(Filenames, Function.Filenames); 13550b57cec5SDimitry Andric llvm::sort(Filenames); 1356*0fca6ea1SDimitry Andric auto Last = llvm::unique(Filenames); 13570b57cec5SDimitry Andric Filenames.erase(Last, Filenames.end()); 13580b57cec5SDimitry Andric return Filenames; 13590b57cec5SDimitry Andric } 13600b57cec5SDimitry Andric 13610b57cec5SDimitry Andric static SmallBitVector gatherFileIDs(StringRef SourceFile, 13620b57cec5SDimitry Andric const FunctionRecord &Function) { 13630b57cec5SDimitry Andric SmallBitVector FilenameEquivalence(Function.Filenames.size(), false); 13640b57cec5SDimitry Andric for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) 13650b57cec5SDimitry Andric if (SourceFile == Function.Filenames[I]) 13660b57cec5SDimitry Andric FilenameEquivalence[I] = true; 13670b57cec5SDimitry Andric return FilenameEquivalence; 13680b57cec5SDimitry Andric } 13690b57cec5SDimitry Andric 13700b57cec5SDimitry Andric /// Return the ID of the file where the definition of the function is located. 1371bdd1243dSDimitry Andric static std::optional<unsigned> 1372bdd1243dSDimitry Andric findMainViewFileID(const FunctionRecord &Function) { 13730b57cec5SDimitry Andric SmallBitVector IsNotExpandedFile(Function.Filenames.size(), true); 13740b57cec5SDimitry Andric for (const auto &CR : Function.CountedRegions) 13750b57cec5SDimitry Andric if (CR.Kind == CounterMappingRegion::ExpansionRegion) 13760b57cec5SDimitry Andric IsNotExpandedFile[CR.ExpandedFileID] = false; 13770b57cec5SDimitry Andric int I = IsNotExpandedFile.find_first(); 13780b57cec5SDimitry Andric if (I == -1) 1379bdd1243dSDimitry Andric return std::nullopt; 13800b57cec5SDimitry Andric return I; 13810b57cec5SDimitry Andric } 13820b57cec5SDimitry Andric 13830b57cec5SDimitry Andric /// Check if SourceFile is the file that contains the definition of 1384bdd1243dSDimitry Andric /// the Function. Return the ID of the file in that case or std::nullopt 1385bdd1243dSDimitry Andric /// otherwise. 1386bdd1243dSDimitry Andric static std::optional<unsigned> 1387bdd1243dSDimitry Andric findMainViewFileID(StringRef SourceFile, const FunctionRecord &Function) { 1388bdd1243dSDimitry Andric std::optional<unsigned> I = findMainViewFileID(Function); 13890b57cec5SDimitry Andric if (I && SourceFile == Function.Filenames[*I]) 13900b57cec5SDimitry Andric return I; 1391bdd1243dSDimitry Andric return std::nullopt; 13920b57cec5SDimitry Andric } 13930b57cec5SDimitry Andric 13940b57cec5SDimitry Andric static bool isExpansion(const CountedRegion &R, unsigned FileID) { 13950b57cec5SDimitry Andric return R.Kind == CounterMappingRegion::ExpansionRegion && R.FileID == FileID; 13960b57cec5SDimitry Andric } 13970b57cec5SDimitry Andric 13980b57cec5SDimitry Andric CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const { 13990b57cec5SDimitry Andric CoverageData FileCoverage(Filename); 14000b57cec5SDimitry Andric std::vector<CountedRegion> Regions; 14010b57cec5SDimitry Andric 14028bcb0991SDimitry Andric // Look up the function records in the given file. Due to hash collisions on 14038bcb0991SDimitry Andric // the filename, we may get back some records that are not in the file. 14048bcb0991SDimitry Andric ArrayRef<unsigned> RecordIndices = 14058bcb0991SDimitry Andric getImpreciseRecordIndicesForFilename(Filename); 14068bcb0991SDimitry Andric for (unsigned RecordIndex : RecordIndices) { 14078bcb0991SDimitry Andric const FunctionRecord &Function = Functions[RecordIndex]; 14080b57cec5SDimitry Andric auto MainFileID = findMainViewFileID(Filename, Function); 14090b57cec5SDimitry Andric auto FileIDs = gatherFileIDs(Filename, Function); 14100b57cec5SDimitry Andric for (const auto &CR : Function.CountedRegions) 14110b57cec5SDimitry Andric if (FileIDs.test(CR.FileID)) { 14120b57cec5SDimitry Andric Regions.push_back(CR); 14130b57cec5SDimitry Andric if (MainFileID && isExpansion(CR, *MainFileID)) 14140b57cec5SDimitry Andric FileCoverage.Expansions.emplace_back(CR, Function); 14150b57cec5SDimitry Andric } 1416e8d8bef9SDimitry Andric // Capture branch regions specific to the function (excluding expansions). 1417e8d8bef9SDimitry Andric for (const auto &CR : Function.CountedBranchRegions) 1418e8d8bef9SDimitry Andric if (FileIDs.test(CR.FileID) && (CR.FileID == CR.ExpandedFileID)) 1419e8d8bef9SDimitry Andric FileCoverage.BranchRegions.push_back(CR); 14205f757f3fSDimitry Andric // Capture MCDC records specific to the function. 14215f757f3fSDimitry Andric for (const auto &MR : Function.MCDCRecords) 14225f757f3fSDimitry Andric if (FileIDs.test(MR.getDecisionRegion().FileID)) 14235f757f3fSDimitry Andric FileCoverage.MCDCRecords.push_back(MR); 14240b57cec5SDimitry Andric } 14250b57cec5SDimitry Andric 14260b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Emitting segments for file: " << Filename << "\n"); 14270b57cec5SDimitry Andric FileCoverage.Segments = SegmentBuilder::buildSegments(Regions); 14280b57cec5SDimitry Andric 14290b57cec5SDimitry Andric return FileCoverage; 14300b57cec5SDimitry Andric } 14310b57cec5SDimitry Andric 14320b57cec5SDimitry Andric std::vector<InstantiationGroup> 14330b57cec5SDimitry Andric CoverageMapping::getInstantiationGroups(StringRef Filename) const { 14340b57cec5SDimitry Andric FunctionInstantiationSetCollector InstantiationSetCollector; 14358bcb0991SDimitry Andric // Look up the function records in the given file. Due to hash collisions on 14368bcb0991SDimitry Andric // the filename, we may get back some records that are not in the file. 14378bcb0991SDimitry Andric ArrayRef<unsigned> RecordIndices = 14388bcb0991SDimitry Andric getImpreciseRecordIndicesForFilename(Filename); 14398bcb0991SDimitry Andric for (unsigned RecordIndex : RecordIndices) { 14408bcb0991SDimitry Andric const FunctionRecord &Function = Functions[RecordIndex]; 14410b57cec5SDimitry Andric auto MainFileID = findMainViewFileID(Filename, Function); 14420b57cec5SDimitry Andric if (!MainFileID) 14430b57cec5SDimitry Andric continue; 14440b57cec5SDimitry Andric InstantiationSetCollector.insert(Function, *MainFileID); 14450b57cec5SDimitry Andric } 14460b57cec5SDimitry Andric 14470b57cec5SDimitry Andric std::vector<InstantiationGroup> Result; 14480b57cec5SDimitry Andric for (auto &InstantiationSet : InstantiationSetCollector) { 14490b57cec5SDimitry Andric InstantiationGroup IG{InstantiationSet.first.first, 14500b57cec5SDimitry Andric InstantiationSet.first.second, 14510b57cec5SDimitry Andric std::move(InstantiationSet.second)}; 14520b57cec5SDimitry Andric Result.emplace_back(std::move(IG)); 14530b57cec5SDimitry Andric } 14540b57cec5SDimitry Andric return Result; 14550b57cec5SDimitry Andric } 14560b57cec5SDimitry Andric 14570b57cec5SDimitry Andric CoverageData 14580b57cec5SDimitry Andric CoverageMapping::getCoverageForFunction(const FunctionRecord &Function) const { 14590b57cec5SDimitry Andric auto MainFileID = findMainViewFileID(Function); 14600b57cec5SDimitry Andric if (!MainFileID) 14610b57cec5SDimitry Andric return CoverageData(); 14620b57cec5SDimitry Andric 14630b57cec5SDimitry Andric CoverageData FunctionCoverage(Function.Filenames[*MainFileID]); 14640b57cec5SDimitry Andric std::vector<CountedRegion> Regions; 14650b57cec5SDimitry Andric for (const auto &CR : Function.CountedRegions) 14660b57cec5SDimitry Andric if (CR.FileID == *MainFileID) { 14670b57cec5SDimitry Andric Regions.push_back(CR); 14680b57cec5SDimitry Andric if (isExpansion(CR, *MainFileID)) 14690b57cec5SDimitry Andric FunctionCoverage.Expansions.emplace_back(CR, Function); 14700b57cec5SDimitry Andric } 1471e8d8bef9SDimitry Andric // Capture branch regions specific to the function (excluding expansions). 1472e8d8bef9SDimitry Andric for (const auto &CR : Function.CountedBranchRegions) 1473e8d8bef9SDimitry Andric if (CR.FileID == *MainFileID) 1474e8d8bef9SDimitry Andric FunctionCoverage.BranchRegions.push_back(CR); 14750b57cec5SDimitry Andric 14765f757f3fSDimitry Andric // Capture MCDC records specific to the function. 14775f757f3fSDimitry Andric for (const auto &MR : Function.MCDCRecords) 14785f757f3fSDimitry Andric if (MR.getDecisionRegion().FileID == *MainFileID) 14795f757f3fSDimitry Andric FunctionCoverage.MCDCRecords.push_back(MR); 14805f757f3fSDimitry Andric 14810b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Emitting segments for function: " << Function.Name 14820b57cec5SDimitry Andric << "\n"); 14830b57cec5SDimitry Andric FunctionCoverage.Segments = SegmentBuilder::buildSegments(Regions); 14840b57cec5SDimitry Andric 14850b57cec5SDimitry Andric return FunctionCoverage; 14860b57cec5SDimitry Andric } 14870b57cec5SDimitry Andric 14880b57cec5SDimitry Andric CoverageData CoverageMapping::getCoverageForExpansion( 14890b57cec5SDimitry Andric const ExpansionRecord &Expansion) const { 14900b57cec5SDimitry Andric CoverageData ExpansionCoverage( 14910b57cec5SDimitry Andric Expansion.Function.Filenames[Expansion.FileID]); 14920b57cec5SDimitry Andric std::vector<CountedRegion> Regions; 14930b57cec5SDimitry Andric for (const auto &CR : Expansion.Function.CountedRegions) 14940b57cec5SDimitry Andric if (CR.FileID == Expansion.FileID) { 14950b57cec5SDimitry Andric Regions.push_back(CR); 14960b57cec5SDimitry Andric if (isExpansion(CR, Expansion.FileID)) 14970b57cec5SDimitry Andric ExpansionCoverage.Expansions.emplace_back(CR, Expansion.Function); 14980b57cec5SDimitry Andric } 1499e8d8bef9SDimitry Andric for (const auto &CR : Expansion.Function.CountedBranchRegions) 1500e8d8bef9SDimitry Andric // Capture branch regions that only pertain to the corresponding expansion. 1501e8d8bef9SDimitry Andric if (CR.FileID == Expansion.FileID) 1502e8d8bef9SDimitry Andric ExpansionCoverage.BranchRegions.push_back(CR); 15030b57cec5SDimitry Andric 15040b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Emitting segments for expansion of file " 15050b57cec5SDimitry Andric << Expansion.FileID << "\n"); 15060b57cec5SDimitry Andric ExpansionCoverage.Segments = SegmentBuilder::buildSegments(Regions); 15070b57cec5SDimitry Andric 15080b57cec5SDimitry Andric return ExpansionCoverage; 15090b57cec5SDimitry Andric } 15100b57cec5SDimitry Andric 15110b57cec5SDimitry Andric LineCoverageStats::LineCoverageStats( 15120b57cec5SDimitry Andric ArrayRef<const CoverageSegment *> LineSegments, 15130b57cec5SDimitry Andric const CoverageSegment *WrappedSegment, unsigned Line) 15140b57cec5SDimitry Andric : ExecutionCount(0), HasMultipleRegions(false), Mapped(false), Line(Line), 15150b57cec5SDimitry Andric LineSegments(LineSegments), WrappedSegment(WrappedSegment) { 15160b57cec5SDimitry Andric // Find the minimum number of regions which start in this line. 15170b57cec5SDimitry Andric unsigned MinRegionCount = 0; 15180b57cec5SDimitry Andric auto isStartOfRegion = [](const CoverageSegment *S) { 15190b57cec5SDimitry Andric return !S->IsGapRegion && S->HasCount && S->IsRegionEntry; 15200b57cec5SDimitry Andric }; 15210b57cec5SDimitry Andric for (unsigned I = 0; I < LineSegments.size() && MinRegionCount < 2; ++I) 15220b57cec5SDimitry Andric if (isStartOfRegion(LineSegments[I])) 15230b57cec5SDimitry Andric ++MinRegionCount; 15240b57cec5SDimitry Andric 15250b57cec5SDimitry Andric bool StartOfSkippedRegion = !LineSegments.empty() && 15260b57cec5SDimitry Andric !LineSegments.front()->HasCount && 15270b57cec5SDimitry Andric LineSegments.front()->IsRegionEntry; 15280b57cec5SDimitry Andric 15290b57cec5SDimitry Andric HasMultipleRegions = MinRegionCount > 1; 15300b57cec5SDimitry Andric Mapped = 15310b57cec5SDimitry Andric !StartOfSkippedRegion && 15320b57cec5SDimitry Andric ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0)); 15330b57cec5SDimitry Andric 15347a6dacacSDimitry Andric // if there is any starting segment at this line with a counter, it must be 15357a6dacacSDimitry Andric // mapped 15367a6dacacSDimitry Andric Mapped |= std::any_of( 15377a6dacacSDimitry Andric LineSegments.begin(), LineSegments.end(), 15387a6dacacSDimitry Andric [](const auto *Seq) { return Seq->IsRegionEntry && Seq->HasCount; }); 15397a6dacacSDimitry Andric 15407a6dacacSDimitry Andric if (!Mapped) { 15410b57cec5SDimitry Andric return; 15427a6dacacSDimitry Andric } 15430b57cec5SDimitry Andric 15440b57cec5SDimitry Andric // Pick the max count from the non-gap, region entry segments and the 15450b57cec5SDimitry Andric // wrapped count. 15460b57cec5SDimitry Andric if (WrappedSegment) 15470b57cec5SDimitry Andric ExecutionCount = WrappedSegment->Count; 15480b57cec5SDimitry Andric if (!MinRegionCount) 15490b57cec5SDimitry Andric return; 15500b57cec5SDimitry Andric for (const auto *LS : LineSegments) 15510b57cec5SDimitry Andric if (isStartOfRegion(LS)) 15520b57cec5SDimitry Andric ExecutionCount = std::max(ExecutionCount, LS->Count); 15530b57cec5SDimitry Andric } 15540b57cec5SDimitry Andric 15550b57cec5SDimitry Andric LineCoverageIterator &LineCoverageIterator::operator++() { 15560b57cec5SDimitry Andric if (Next == CD.end()) { 15570b57cec5SDimitry Andric Stats = LineCoverageStats(); 15580b57cec5SDimitry Andric Ended = true; 15590b57cec5SDimitry Andric return *this; 15600b57cec5SDimitry Andric } 15610b57cec5SDimitry Andric if (Segments.size()) 15620b57cec5SDimitry Andric WrappedSegment = Segments.back(); 15630b57cec5SDimitry Andric Segments.clear(); 15640b57cec5SDimitry Andric while (Next != CD.end() && Next->Line == Line) 15650b57cec5SDimitry Andric Segments.push_back(&*Next++); 15660b57cec5SDimitry Andric Stats = LineCoverageStats(Segments, WrappedSegment, Line); 15670b57cec5SDimitry Andric ++Line; 15680b57cec5SDimitry Andric return *this; 15690b57cec5SDimitry Andric } 15700b57cec5SDimitry Andric 15715f757f3fSDimitry Andric static std::string getCoverageMapErrString(coveragemap_error Err, 15725f757f3fSDimitry Andric const std::string &ErrMsg = "") { 15735f757f3fSDimitry Andric std::string Msg; 15745f757f3fSDimitry Andric raw_string_ostream OS(Msg); 15755f757f3fSDimitry Andric 15760b57cec5SDimitry Andric switch (Err) { 15770b57cec5SDimitry Andric case coveragemap_error::success: 15785f757f3fSDimitry Andric OS << "success"; 15795f757f3fSDimitry Andric break; 15800b57cec5SDimitry Andric case coveragemap_error::eof: 15815f757f3fSDimitry Andric OS << "end of File"; 15825f757f3fSDimitry Andric break; 15830b57cec5SDimitry Andric case coveragemap_error::no_data_found: 15845f757f3fSDimitry Andric OS << "no coverage data found"; 15855f757f3fSDimitry Andric break; 15860b57cec5SDimitry Andric case coveragemap_error::unsupported_version: 15875f757f3fSDimitry Andric OS << "unsupported coverage format version"; 15885f757f3fSDimitry Andric break; 15890b57cec5SDimitry Andric case coveragemap_error::truncated: 15905f757f3fSDimitry Andric OS << "truncated coverage data"; 15915f757f3fSDimitry Andric break; 15920b57cec5SDimitry Andric case coveragemap_error::malformed: 15935f757f3fSDimitry Andric OS << "malformed coverage data"; 15945f757f3fSDimitry Andric break; 15955ffd83dbSDimitry Andric case coveragemap_error::decompression_failed: 15965f757f3fSDimitry Andric OS << "failed to decompress coverage data (zlib)"; 15975f757f3fSDimitry Andric break; 1598e8d8bef9SDimitry Andric case coveragemap_error::invalid_or_missing_arch_specifier: 15995f757f3fSDimitry Andric OS << "`-arch` specifier is invalid or missing for universal binary"; 16005f757f3fSDimitry Andric break; 16010b57cec5SDimitry Andric } 16025f757f3fSDimitry Andric 16035f757f3fSDimitry Andric // If optional error message is not empty, append it to the message. 16045f757f3fSDimitry Andric if (!ErrMsg.empty()) 16055f757f3fSDimitry Andric OS << ": " << ErrMsg; 16065f757f3fSDimitry Andric 16075f757f3fSDimitry Andric return Msg; 16080b57cec5SDimitry Andric } 16090b57cec5SDimitry Andric 16100b57cec5SDimitry Andric namespace { 16110b57cec5SDimitry Andric 16120b57cec5SDimitry Andric // FIXME: This class is only here to support the transition to llvm::Error. It 16130b57cec5SDimitry Andric // will be removed once this transition is complete. Clients should prefer to 16140b57cec5SDimitry Andric // deal with the Error value directly, rather than converting to error_code. 16150b57cec5SDimitry Andric class CoverageMappingErrorCategoryType : public std::error_category { 16160b57cec5SDimitry Andric const char *name() const noexcept override { return "llvm.coveragemap"; } 16170b57cec5SDimitry Andric std::string message(int IE) const override { 16180b57cec5SDimitry Andric return getCoverageMapErrString(static_cast<coveragemap_error>(IE)); 16190b57cec5SDimitry Andric } 16200b57cec5SDimitry Andric }; 16210b57cec5SDimitry Andric 16220b57cec5SDimitry Andric } // end anonymous namespace 16230b57cec5SDimitry Andric 16240b57cec5SDimitry Andric std::string CoverageMapError::message() const { 16255f757f3fSDimitry Andric return getCoverageMapErrString(Err, Msg); 16260b57cec5SDimitry Andric } 16270b57cec5SDimitry Andric 16280b57cec5SDimitry Andric const std::error_category &llvm::coverage::coveragemap_category() { 1629753f127fSDimitry Andric static CoverageMappingErrorCategoryType ErrorCategory; 1630753f127fSDimitry Andric return ErrorCategory; 16310b57cec5SDimitry Andric } 16320b57cec5SDimitry Andric 16330b57cec5SDimitry Andric char CoverageMapError::ID = 0; 1634