108bbd35aSDimitry Andric //===- CoverageMapping.cpp - Code coverage mapping support ----------------===//
201095a5dSDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
601095a5dSDimitry Andric //
701095a5dSDimitry Andric //===----------------------------------------------------------------------===//
801095a5dSDimitry Andric //
901095a5dSDimitry Andric // This file contains support for clang's and llvm's instrumentation based
1001095a5dSDimitry Andric // code coverage.
1101095a5dSDimitry Andric //
1201095a5dSDimitry Andric //===----------------------------------------------------------------------===//
1301095a5dSDimitry Andric
147ab83427SDimitry Andric #include "llvm/ProfileData/Coverage/CoverageMapping.h"
1571d5a254SDimitry Andric #include "llvm/ADT/ArrayRef.h"
1601095a5dSDimitry Andric #include "llvm/ADT/DenseMap.h"
17ac9a064cSDimitry Andric #include "llvm/ADT/STLExtras.h"
1801095a5dSDimitry Andric #include "llvm/ADT/SmallBitVector.h"
1971d5a254SDimitry Andric #include "llvm/ADT/SmallVector.h"
207fa27ce4SDimitry Andric #include "llvm/ADT/StringExtras.h"
2171d5a254SDimitry Andric #include "llvm/ADT/StringRef.h"
227fa27ce4SDimitry Andric #include "llvm/Object/BuildID.h"
2301095a5dSDimitry Andric #include "llvm/ProfileData/Coverage/CoverageMappingReader.h"
2401095a5dSDimitry Andric #include "llvm/ProfileData/InstrProfReader.h"
2501095a5dSDimitry Andric #include "llvm/Support/Debug.h"
2601095a5dSDimitry Andric #include "llvm/Support/Errc.h"
2771d5a254SDimitry Andric #include "llvm/Support/Error.h"
2801095a5dSDimitry Andric #include "llvm/Support/ErrorHandling.h"
2971d5a254SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
307fa27ce4SDimitry Andric #include "llvm/Support/VirtualFileSystem.h"
3101095a5dSDimitry Andric #include "llvm/Support/raw_ostream.h"
3271d5a254SDimitry Andric #include <algorithm>
3371d5a254SDimitry Andric #include <cassert>
34312c0ed1SDimitry Andric #include <cmath>
3571d5a254SDimitry Andric #include <cstdint>
3671d5a254SDimitry Andric #include <iterator>
37044eb2f6SDimitry Andric #include <map>
3871d5a254SDimitry Andric #include <memory>
39e3b55780SDimitry Andric #include <optional>
40ac9a064cSDimitry Andric #include <stack>
4171d5a254SDimitry Andric #include <string>
4271d5a254SDimitry Andric #include <system_error>
4371d5a254SDimitry Andric #include <utility>
4471d5a254SDimitry Andric #include <vector>
4501095a5dSDimitry Andric
4601095a5dSDimitry Andric using namespace llvm;
4701095a5dSDimitry Andric using namespace coverage;
4801095a5dSDimitry Andric
4901095a5dSDimitry Andric #define DEBUG_TYPE "coverage-mapping"
5001095a5dSDimitry Andric
get(const CounterExpression & E)5101095a5dSDimitry Andric Counter CounterExpressionBuilder::get(const CounterExpression &E) {
5201095a5dSDimitry Andric auto It = ExpressionIndices.find(E);
5301095a5dSDimitry Andric if (It != ExpressionIndices.end())
5401095a5dSDimitry Andric return Counter::getExpression(It->second);
5501095a5dSDimitry Andric unsigned I = Expressions.size();
5601095a5dSDimitry Andric Expressions.push_back(E);
5701095a5dSDimitry Andric ExpressionIndices[E] = I;
5801095a5dSDimitry Andric return Counter::getExpression(I);
5901095a5dSDimitry Andric }
6001095a5dSDimitry Andric
extractTerms(Counter C,int Factor,SmallVectorImpl<Term> & Terms)619df3605dSDimitry Andric void CounterExpressionBuilder::extractTerms(Counter C, int Factor,
629df3605dSDimitry Andric SmallVectorImpl<Term> &Terms) {
6301095a5dSDimitry Andric switch (C.getKind()) {
6401095a5dSDimitry Andric case Counter::Zero:
6501095a5dSDimitry Andric break;
6601095a5dSDimitry Andric case Counter::CounterValueReference:
679df3605dSDimitry Andric Terms.emplace_back(C.getCounterID(), Factor);
6801095a5dSDimitry Andric break;
6901095a5dSDimitry Andric case Counter::Expression:
7001095a5dSDimitry Andric const auto &E = Expressions[C.getExpressionID()];
719df3605dSDimitry Andric extractTerms(E.LHS, Factor, Terms);
729df3605dSDimitry Andric extractTerms(
739df3605dSDimitry Andric E.RHS, E.Kind == CounterExpression::Subtract ? -Factor : Factor, Terms);
7401095a5dSDimitry Andric break;
7501095a5dSDimitry Andric }
7601095a5dSDimitry Andric }
7701095a5dSDimitry Andric
simplify(Counter ExpressionTree)7801095a5dSDimitry Andric Counter CounterExpressionBuilder::simplify(Counter ExpressionTree) {
7901095a5dSDimitry Andric // Gather constant terms.
809df3605dSDimitry Andric SmallVector<Term, 32> Terms;
8101095a5dSDimitry Andric extractTerms(ExpressionTree, +1, Terms);
8201095a5dSDimitry Andric
8301095a5dSDimitry Andric // If there are no terms, this is just a zero. The algorithm below assumes at
8401095a5dSDimitry Andric // least one term.
8501095a5dSDimitry Andric if (Terms.size() == 0)
8601095a5dSDimitry Andric return Counter::getZero();
8701095a5dSDimitry Andric
8801095a5dSDimitry Andric // Group the terms by counter ID.
89d8e91e46SDimitry Andric llvm::sort(Terms, [](const Term &LHS, const Term &RHS) {
909df3605dSDimitry Andric return LHS.CounterID < RHS.CounterID;
9101095a5dSDimitry Andric });
9201095a5dSDimitry Andric
9301095a5dSDimitry Andric // Combine terms by counter ID to eliminate counters that sum to zero.
9401095a5dSDimitry Andric auto Prev = Terms.begin();
9501095a5dSDimitry Andric for (auto I = Prev + 1, E = Terms.end(); I != E; ++I) {
969df3605dSDimitry Andric if (I->CounterID == Prev->CounterID) {
979df3605dSDimitry Andric Prev->Factor += I->Factor;
9801095a5dSDimitry Andric continue;
9901095a5dSDimitry Andric }
10001095a5dSDimitry Andric ++Prev;
10101095a5dSDimitry Andric *Prev = *I;
10201095a5dSDimitry Andric }
10301095a5dSDimitry Andric Terms.erase(++Prev, Terms.end());
10401095a5dSDimitry Andric
10501095a5dSDimitry Andric Counter C;
10601095a5dSDimitry Andric // Create additions. We do this before subtractions to avoid constructs like
10701095a5dSDimitry Andric // ((0 - X) + Y), as opposed to (Y - X).
1089df3605dSDimitry Andric for (auto T : Terms) {
1099df3605dSDimitry Andric if (T.Factor <= 0)
11001095a5dSDimitry Andric continue;
1119df3605dSDimitry Andric for (int I = 0; I < T.Factor; ++I)
11201095a5dSDimitry Andric if (C.isZero())
1139df3605dSDimitry Andric C = Counter::getCounter(T.CounterID);
11401095a5dSDimitry Andric else
11501095a5dSDimitry Andric C = get(CounterExpression(CounterExpression::Add, C,
1169df3605dSDimitry Andric Counter::getCounter(T.CounterID)));
11701095a5dSDimitry Andric }
11801095a5dSDimitry Andric
11901095a5dSDimitry Andric // Create subtractions.
1209df3605dSDimitry Andric for (auto T : Terms) {
1219df3605dSDimitry Andric if (T.Factor >= 0)
12201095a5dSDimitry Andric continue;
1239df3605dSDimitry Andric for (int I = 0; I < -T.Factor; ++I)
12401095a5dSDimitry Andric C = get(CounterExpression(CounterExpression::Subtract, C,
1259df3605dSDimitry Andric Counter::getCounter(T.CounterID)));
12601095a5dSDimitry Andric }
12701095a5dSDimitry Andric return C;
12801095a5dSDimitry Andric }
12901095a5dSDimitry Andric
add(Counter LHS,Counter RHS,bool Simplify)130145449b1SDimitry Andric Counter CounterExpressionBuilder::add(Counter LHS, Counter RHS, bool Simplify) {
131145449b1SDimitry Andric auto Cnt = get(CounterExpression(CounterExpression::Add, LHS, RHS));
132145449b1SDimitry Andric return Simplify ? simplify(Cnt) : Cnt;
13301095a5dSDimitry Andric }
13401095a5dSDimitry Andric
subtract(Counter LHS,Counter RHS,bool Simplify)135145449b1SDimitry Andric Counter CounterExpressionBuilder::subtract(Counter LHS, Counter RHS,
136145449b1SDimitry Andric bool Simplify) {
137145449b1SDimitry Andric auto Cnt = get(CounterExpression(CounterExpression::Subtract, LHS, RHS));
138145449b1SDimitry Andric return Simplify ? simplify(Cnt) : Cnt;
13901095a5dSDimitry Andric }
14001095a5dSDimitry Andric
dump(const Counter & C,raw_ostream & OS) const14171d5a254SDimitry Andric void CounterMappingContext::dump(const Counter &C, raw_ostream &OS) const {
14201095a5dSDimitry Andric switch (C.getKind()) {
14301095a5dSDimitry Andric case Counter::Zero:
14401095a5dSDimitry Andric OS << '0';
14501095a5dSDimitry Andric return;
14601095a5dSDimitry Andric case Counter::CounterValueReference:
14701095a5dSDimitry Andric OS << '#' << C.getCounterID();
14801095a5dSDimitry Andric break;
14901095a5dSDimitry Andric case Counter::Expression: {
15001095a5dSDimitry Andric if (C.getExpressionID() >= Expressions.size())
15101095a5dSDimitry Andric return;
15201095a5dSDimitry Andric const auto &E = Expressions[C.getExpressionID()];
15301095a5dSDimitry Andric OS << '(';
15401095a5dSDimitry Andric dump(E.LHS, OS);
15501095a5dSDimitry Andric OS << (E.Kind == CounterExpression::Subtract ? " - " : " + ");
15601095a5dSDimitry Andric dump(E.RHS, OS);
15701095a5dSDimitry Andric OS << ')';
15801095a5dSDimitry Andric break;
15901095a5dSDimitry Andric }
16001095a5dSDimitry Andric }
16101095a5dSDimitry Andric if (CounterValues.empty())
16201095a5dSDimitry Andric return;
16301095a5dSDimitry Andric Expected<int64_t> Value = evaluate(C);
16401095a5dSDimitry Andric if (auto E = Value.takeError()) {
16571d5a254SDimitry Andric consumeError(std::move(E));
16601095a5dSDimitry Andric return;
16701095a5dSDimitry Andric }
16801095a5dSDimitry Andric OS << '[' << *Value << ']';
16901095a5dSDimitry Andric }
17001095a5dSDimitry Andric
evaluate(const Counter & C) const17101095a5dSDimitry Andric Expected<int64_t> CounterMappingContext::evaluate(const Counter &C) const {
172b1c73532SDimitry Andric struct StackElem {
173b1c73532SDimitry Andric Counter ICounter;
174b1c73532SDimitry Andric int64_t LHS = 0;
175b1c73532SDimitry Andric enum {
176b1c73532SDimitry Andric KNeverVisited = 0,
177b1c73532SDimitry Andric KVisitedOnce = 1,
178b1c73532SDimitry Andric KVisitedTwice = 2,
179b1c73532SDimitry Andric } VisitCount = KNeverVisited;
180b1c73532SDimitry Andric };
181b1c73532SDimitry Andric
182b1c73532SDimitry Andric std::stack<StackElem> CounterStack;
183b1c73532SDimitry Andric CounterStack.push({C});
184b1c73532SDimitry Andric
185b1c73532SDimitry Andric int64_t LastPoppedValue;
186b1c73532SDimitry Andric
187b1c73532SDimitry Andric while (!CounterStack.empty()) {
188b1c73532SDimitry Andric StackElem &Current = CounterStack.top();
189b1c73532SDimitry Andric
190b1c73532SDimitry Andric switch (Current.ICounter.getKind()) {
19101095a5dSDimitry Andric case Counter::Zero:
192b1c73532SDimitry Andric LastPoppedValue = 0;
193b1c73532SDimitry Andric CounterStack.pop();
194b1c73532SDimitry Andric break;
19501095a5dSDimitry Andric case Counter::CounterValueReference:
196b1c73532SDimitry Andric if (Current.ICounter.getCounterID() >= CounterValues.size())
19701095a5dSDimitry Andric return errorCodeToError(errc::argument_out_of_domain);
198b1c73532SDimitry Andric LastPoppedValue = CounterValues[Current.ICounter.getCounterID()];
199b1c73532SDimitry Andric CounterStack.pop();
200b1c73532SDimitry Andric break;
20101095a5dSDimitry Andric case Counter::Expression: {
202b1c73532SDimitry Andric if (Current.ICounter.getExpressionID() >= Expressions.size())
20301095a5dSDimitry Andric return errorCodeToError(errc::argument_out_of_domain);
204b1c73532SDimitry Andric const auto &E = Expressions[Current.ICounter.getExpressionID()];
205b1c73532SDimitry Andric if (Current.VisitCount == StackElem::KNeverVisited) {
206b1c73532SDimitry Andric CounterStack.push(StackElem{E.LHS});
207b1c73532SDimitry Andric Current.VisitCount = StackElem::KVisitedOnce;
208b1c73532SDimitry Andric } else if (Current.VisitCount == StackElem::KVisitedOnce) {
209b1c73532SDimitry Andric Current.LHS = LastPoppedValue;
210b1c73532SDimitry Andric CounterStack.push(StackElem{E.RHS});
211b1c73532SDimitry Andric Current.VisitCount = StackElem::KVisitedTwice;
212b1c73532SDimitry Andric } else {
213b1c73532SDimitry Andric int64_t LHS = Current.LHS;
214b1c73532SDimitry Andric int64_t RHS = LastPoppedValue;
215b1c73532SDimitry Andric LastPoppedValue =
216b1c73532SDimitry Andric E.Kind == CounterExpression::Subtract ? LHS - RHS : LHS + RHS;
217b1c73532SDimitry Andric CounterStack.pop();
218b1c73532SDimitry Andric }
219b1c73532SDimitry Andric break;
22001095a5dSDimitry Andric }
22101095a5dSDimitry Andric }
222b1c73532SDimitry Andric }
223b1c73532SDimitry Andric
224b1c73532SDimitry Andric return LastPoppedValue;
22501095a5dSDimitry Andric }
22601095a5dSDimitry Andric
TVIdxBuilder(const SmallVectorImpl<ConditionIDs> & NextIDs,int Offset)227ac9a064cSDimitry Andric mcdc::TVIdxBuilder::TVIdxBuilder(const SmallVectorImpl<ConditionIDs> &NextIDs,
228ac9a064cSDimitry Andric int Offset)
229ac9a064cSDimitry Andric : Indices(NextIDs.size()) {
230ac9a064cSDimitry Andric // Construct Nodes and set up each InCount
231ac9a064cSDimitry Andric auto N = NextIDs.size();
232ac9a064cSDimitry Andric SmallVector<MCDCNode> Nodes(N);
233ac9a064cSDimitry Andric for (unsigned ID = 0; ID < N; ++ID) {
234ac9a064cSDimitry Andric for (unsigned C = 0; C < 2; ++C) {
235ac9a064cSDimitry Andric #ifndef NDEBUG
236ac9a064cSDimitry Andric Indices[ID][C] = INT_MIN;
237ac9a064cSDimitry Andric #endif
238ac9a064cSDimitry Andric auto NextID = NextIDs[ID][C];
239ac9a064cSDimitry Andric Nodes[ID].NextIDs[C] = NextID;
240ac9a064cSDimitry Andric if (NextID >= 0)
241ac9a064cSDimitry Andric ++Nodes[NextID].InCount;
242312c0ed1SDimitry Andric }
243312c0ed1SDimitry Andric }
244312c0ed1SDimitry Andric
245ac9a064cSDimitry Andric // Sort key ordered by <-Width, Ord>
246ac9a064cSDimitry Andric SmallVector<std::tuple<int, /// -Width
247ac9a064cSDimitry Andric unsigned, /// Ord
248ac9a064cSDimitry Andric int, /// ID
249ac9a064cSDimitry Andric unsigned /// Cond (0 or 1)
250ac9a064cSDimitry Andric >>
251ac9a064cSDimitry Andric Decisions;
252ac9a064cSDimitry Andric
253ac9a064cSDimitry Andric // Traverse Nodes to assign Idx
254ac9a064cSDimitry Andric SmallVector<int> Q;
255ac9a064cSDimitry Andric assert(Nodes[0].InCount == 0);
256ac9a064cSDimitry Andric Nodes[0].Width = 1;
257ac9a064cSDimitry Andric Q.push_back(0);
258ac9a064cSDimitry Andric
259ac9a064cSDimitry Andric unsigned Ord = 0;
260ac9a064cSDimitry Andric while (!Q.empty()) {
261ac9a064cSDimitry Andric auto IID = Q.begin();
262ac9a064cSDimitry Andric int ID = *IID;
263ac9a064cSDimitry Andric Q.erase(IID);
264ac9a064cSDimitry Andric auto &Node = Nodes[ID];
265ac9a064cSDimitry Andric assert(Node.Width > 0);
266ac9a064cSDimitry Andric
267ac9a064cSDimitry Andric for (unsigned I = 0; I < 2; ++I) {
268ac9a064cSDimitry Andric auto NextID = Node.NextIDs[I];
269ac9a064cSDimitry Andric assert(NextID != 0 && "NextID should not point to the top");
270ac9a064cSDimitry Andric if (NextID < 0) {
271ac9a064cSDimitry Andric // Decision
272ac9a064cSDimitry Andric Decisions.emplace_back(-Node.Width, Ord++, ID, I);
273ac9a064cSDimitry Andric assert(Ord == Decisions.size());
274ac9a064cSDimitry Andric continue;
275ac9a064cSDimitry Andric }
276ac9a064cSDimitry Andric
277ac9a064cSDimitry Andric // Inter Node
278ac9a064cSDimitry Andric auto &NextNode = Nodes[NextID];
279ac9a064cSDimitry Andric assert(NextNode.InCount > 0);
280ac9a064cSDimitry Andric
281ac9a064cSDimitry Andric // Assign Idx
282ac9a064cSDimitry Andric assert(Indices[ID][I] == INT_MIN);
283ac9a064cSDimitry Andric Indices[ID][I] = NextNode.Width;
284ac9a064cSDimitry Andric auto NextWidth = int64_t(NextNode.Width) + Node.Width;
285ac9a064cSDimitry Andric if (NextWidth > HardMaxTVs) {
286ac9a064cSDimitry Andric NumTestVectors = HardMaxTVs; // Overflow
287ac9a064cSDimitry Andric return;
288ac9a064cSDimitry Andric }
289ac9a064cSDimitry Andric NextNode.Width = NextWidth;
290ac9a064cSDimitry Andric
291ac9a064cSDimitry Andric // Ready if all incomings are processed.
292ac9a064cSDimitry Andric // Or NextNode.Width hasn't been confirmed yet.
293ac9a064cSDimitry Andric if (--NextNode.InCount == 0)
294ac9a064cSDimitry Andric Q.push_back(NextID);
295ac9a064cSDimitry Andric }
296ac9a064cSDimitry Andric }
297ac9a064cSDimitry Andric
298ac9a064cSDimitry Andric llvm::sort(Decisions);
299ac9a064cSDimitry Andric
300ac9a064cSDimitry Andric // Assign TestVector Indices in Decision Nodes
301ac9a064cSDimitry Andric int64_t CurIdx = 0;
302ac9a064cSDimitry Andric for (auto [NegWidth, Ord, ID, C] : Decisions) {
303ac9a064cSDimitry Andric int Width = -NegWidth;
304ac9a064cSDimitry Andric assert(Nodes[ID].Width == Width);
305ac9a064cSDimitry Andric assert(Nodes[ID].NextIDs[C] < 0);
306ac9a064cSDimitry Andric assert(Indices[ID][C] == INT_MIN);
307ac9a064cSDimitry Andric Indices[ID][C] = Offset + CurIdx;
308ac9a064cSDimitry Andric CurIdx += Width;
309ac9a064cSDimitry Andric if (CurIdx > HardMaxTVs) {
310ac9a064cSDimitry Andric NumTestVectors = HardMaxTVs; // Overflow
311ac9a064cSDimitry Andric return;
312ac9a064cSDimitry Andric }
313ac9a064cSDimitry Andric }
314ac9a064cSDimitry Andric
315ac9a064cSDimitry Andric assert(CurIdx < HardMaxTVs);
316ac9a064cSDimitry Andric NumTestVectors = CurIdx;
317ac9a064cSDimitry Andric
318ac9a064cSDimitry Andric #ifndef NDEBUG
319ac9a064cSDimitry Andric for (const auto &Idxs : Indices)
320ac9a064cSDimitry Andric for (auto Idx : Idxs)
321ac9a064cSDimitry Andric assert(Idx != INT_MIN);
322ac9a064cSDimitry Andric SavedNodes = std::move(Nodes);
323ac9a064cSDimitry Andric #endif
324ac9a064cSDimitry Andric }
325ac9a064cSDimitry Andric
326ac9a064cSDimitry Andric namespace {
327ac9a064cSDimitry Andric
328ac9a064cSDimitry Andric /// Construct this->NextIDs with Branches for TVIdxBuilder to use it
329ac9a064cSDimitry Andric /// before MCDCRecordProcessor().
330ac9a064cSDimitry Andric class NextIDsBuilder {
331ac9a064cSDimitry Andric protected:
332ac9a064cSDimitry Andric SmallVector<mcdc::ConditionIDs> NextIDs;
333ac9a064cSDimitry Andric
334ac9a064cSDimitry Andric public:
NextIDsBuilder(const ArrayRef<const CounterMappingRegion * > Branches)335ac9a064cSDimitry Andric NextIDsBuilder(const ArrayRef<const CounterMappingRegion *> Branches)
336ac9a064cSDimitry Andric : NextIDs(Branches.size()) {
337ac9a064cSDimitry Andric #ifndef NDEBUG
338ac9a064cSDimitry Andric DenseSet<mcdc::ConditionID> SeenIDs;
339ac9a064cSDimitry Andric #endif
340ac9a064cSDimitry Andric for (const auto *Branch : Branches) {
341ac9a064cSDimitry Andric const auto &BranchParams = Branch->getBranchParams();
342ac9a064cSDimitry Andric assert(SeenIDs.insert(BranchParams.ID).second && "Duplicate CondID");
343ac9a064cSDimitry Andric NextIDs[BranchParams.ID] = BranchParams.Conds;
344ac9a064cSDimitry Andric }
345ac9a064cSDimitry Andric assert(SeenIDs.size() == Branches.size());
346ac9a064cSDimitry Andric }
347ac9a064cSDimitry Andric };
348ac9a064cSDimitry Andric
349ac9a064cSDimitry Andric class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
350312c0ed1SDimitry Andric /// A bitmap representing the executed test vectors for a boolean expression.
351312c0ed1SDimitry Andric /// Each index of the bitmap corresponds to a possible test vector. An index
352312c0ed1SDimitry Andric /// with a bit value of '1' indicates that the corresponding Test Vector
353312c0ed1SDimitry Andric /// identified by that index was executed.
354ac9a064cSDimitry Andric const BitVector &Bitmap;
355312c0ed1SDimitry Andric
356312c0ed1SDimitry Andric /// Decision Region to which the ExecutedTestVectorBitmap applies.
3574df029ccSDimitry Andric const CounterMappingRegion &Region;
358ac9a064cSDimitry Andric const mcdc::DecisionParameters &DecisionParams;
359312c0ed1SDimitry Andric
360312c0ed1SDimitry Andric /// Array of branch regions corresponding each conditions in the boolean
361312c0ed1SDimitry Andric /// expression.
3624df029ccSDimitry Andric ArrayRef<const CounterMappingRegion *> Branches;
363312c0ed1SDimitry Andric
364312c0ed1SDimitry Andric /// Total number of conditions in the boolean expression.
365312c0ed1SDimitry Andric unsigned NumConditions;
366312c0ed1SDimitry Andric
367312c0ed1SDimitry Andric /// Vector used to track whether a condition is constant folded.
368312c0ed1SDimitry Andric MCDCRecord::BoolVector Folded;
369312c0ed1SDimitry Andric
370312c0ed1SDimitry Andric /// Mapping of calculated MC/DC Independence Pairs for each condition.
371312c0ed1SDimitry Andric MCDCRecord::TVPairMap IndependencePairs;
372312c0ed1SDimitry Andric
373ac9a064cSDimitry Andric /// Storage for ExecVectors
374ac9a064cSDimitry Andric /// ExecVectors is the alias of its 0th element.
375ac9a064cSDimitry Andric std::array<MCDCRecord::TestVectors, 2> ExecVectorsByCond;
376312c0ed1SDimitry Andric
377312c0ed1SDimitry Andric /// Actual executed Test Vectors for the boolean expression, based on
378312c0ed1SDimitry Andric /// ExecutedTestVectorBitmap.
379ac9a064cSDimitry Andric MCDCRecord::TestVectors &ExecVectors;
380ac9a064cSDimitry Andric
381ac9a064cSDimitry Andric /// Number of False items in ExecVectors
382ac9a064cSDimitry Andric unsigned NumExecVectorsF;
383ac9a064cSDimitry Andric
384ac9a064cSDimitry Andric #ifndef NDEBUG
385ac9a064cSDimitry Andric DenseSet<unsigned> TVIdxs;
386ac9a064cSDimitry Andric #endif
387ac9a064cSDimitry Andric
388ac9a064cSDimitry Andric bool IsVersion11;
389312c0ed1SDimitry Andric
390312c0ed1SDimitry Andric public:
MCDCRecordProcessor(const BitVector & Bitmap,const CounterMappingRegion & Region,ArrayRef<const CounterMappingRegion * > Branches,bool IsVersion11)3914df029ccSDimitry Andric MCDCRecordProcessor(const BitVector &Bitmap,
3924df029ccSDimitry Andric const CounterMappingRegion &Region,
393ac9a064cSDimitry Andric ArrayRef<const CounterMappingRegion *> Branches,
394ac9a064cSDimitry Andric bool IsVersion11)
395ac9a064cSDimitry Andric : NextIDsBuilder(Branches), TVIdxBuilder(this->NextIDs), Bitmap(Bitmap),
396ac9a064cSDimitry Andric Region(Region), DecisionParams(Region.getDecisionParams()),
397ac9a064cSDimitry Andric Branches(Branches), NumConditions(DecisionParams.NumConditions),
398312c0ed1SDimitry Andric Folded(NumConditions, false), IndependencePairs(NumConditions),
399ac9a064cSDimitry Andric ExecVectors(ExecVectorsByCond[false]), IsVersion11(IsVersion11) {}
400312c0ed1SDimitry Andric
401312c0ed1SDimitry Andric private:
402ac9a064cSDimitry Andric // Walk the binary decision diagram and try assigning both false and true to
403ac9a064cSDimitry Andric // each node. When a terminal node (ID == 0) is reached, fill in the value in
404ac9a064cSDimitry Andric // the truth table.
buildTestVector(MCDCRecord::TestVector & TV,mcdc::ConditionID ID,int TVIdx)405ac9a064cSDimitry Andric void buildTestVector(MCDCRecord::TestVector &TV, mcdc::ConditionID ID,
406ac9a064cSDimitry Andric int TVIdx) {
407ac9a064cSDimitry Andric for (auto MCDCCond : {MCDCRecord::MCDC_False, MCDCRecord::MCDC_True}) {
408ac9a064cSDimitry Andric static_assert(MCDCRecord::MCDC_False == 0);
409ac9a064cSDimitry Andric static_assert(MCDCRecord::MCDC_True == 1);
410ac9a064cSDimitry Andric TV.set(ID, MCDCCond);
411ac9a064cSDimitry Andric auto NextID = NextIDs[ID][MCDCCond];
412ac9a064cSDimitry Andric auto NextTVIdx = TVIdx + Indices[ID][MCDCCond];
413ac9a064cSDimitry Andric assert(NextID == SavedNodes[ID].NextIDs[MCDCCond]);
414ac9a064cSDimitry Andric if (NextID >= 0) {
415ac9a064cSDimitry Andric buildTestVector(TV, NextID, NextTVIdx);
416ac9a064cSDimitry Andric continue;
417312c0ed1SDimitry Andric }
418312c0ed1SDimitry Andric
419ac9a064cSDimitry Andric assert(TVIdx < SavedNodes[ID].Width);
420ac9a064cSDimitry Andric assert(TVIdxs.insert(NextTVIdx).second && "Duplicate TVIdx");
421ac9a064cSDimitry Andric
422ac9a064cSDimitry Andric if (!Bitmap[IsVersion11
423ac9a064cSDimitry Andric ? DecisionParams.BitmapIdx * CHAR_BIT + TV.getIndex()
424ac9a064cSDimitry Andric : DecisionParams.BitmapIdx - NumTestVectors + NextTVIdx])
425ac9a064cSDimitry Andric continue;
426ac9a064cSDimitry Andric
427312c0ed1SDimitry Andric // Copy the completed test vector to the vector of testvectors.
428312c0ed1SDimitry Andric // The final value (T,F) is equal to the last non-dontcare state on the
429312c0ed1SDimitry Andric // path (in a short-circuiting system).
430ac9a064cSDimitry Andric ExecVectorsByCond[MCDCCond].push_back({TV, MCDCCond});
431312c0ed1SDimitry Andric }
432312c0ed1SDimitry Andric
433312c0ed1SDimitry Andric // Reset back to DontCare.
434ac9a064cSDimitry Andric TV.set(ID, MCDCRecord::MCDC_DontCare);
435312c0ed1SDimitry Andric }
436312c0ed1SDimitry Andric
437312c0ed1SDimitry Andric /// Walk the bits in the bitmap. A bit set to '1' indicates that the test
438312c0ed1SDimitry Andric /// vector at the corresponding index was executed during a test run.
findExecutedTestVectors()439ac9a064cSDimitry Andric void findExecutedTestVectors() {
440ac9a064cSDimitry Andric // Walk the binary decision diagram to enumerate all possible test vectors.
441ac9a064cSDimitry Andric // We start at the root node (ID == 0) with all values being DontCare.
442ac9a064cSDimitry Andric // `TVIdx` starts with 0 and is in the traversal.
443ac9a064cSDimitry Andric // `Index` encodes the bitmask of true values and is initially 0.
444ac9a064cSDimitry Andric MCDCRecord::TestVector TV(NumConditions);
445ac9a064cSDimitry Andric buildTestVector(TV, 0, 0);
446ac9a064cSDimitry Andric assert(TVIdxs.size() == unsigned(NumTestVectors) &&
447ac9a064cSDimitry Andric "TVIdxs wasn't fulfilled");
448ac9a064cSDimitry Andric
449ac9a064cSDimitry Andric // Fill ExecVectors order by False items and True items.
450ac9a064cSDimitry Andric // ExecVectors is the alias of ExecVectorsByCond[false], so
451ac9a064cSDimitry Andric // Append ExecVectorsByCond[true] on it.
452ac9a064cSDimitry Andric NumExecVectorsF = ExecVectors.size();
453ac9a064cSDimitry Andric auto &ExecVectorsT = ExecVectorsByCond[true];
454ac9a064cSDimitry Andric ExecVectors.append(std::make_move_iterator(ExecVectorsT.begin()),
455ac9a064cSDimitry Andric std::make_move_iterator(ExecVectorsT.end()));
456312c0ed1SDimitry Andric }
457312c0ed1SDimitry Andric
458ac9a064cSDimitry Andric // Find an independence pair for each condition:
459ac9a064cSDimitry Andric // - The condition is true in one test and false in the other.
460ac9a064cSDimitry Andric // - The decision outcome is true one test and false in the other.
461ac9a064cSDimitry Andric // - All other conditions' values must be equal or marked as "don't care".
findIndependencePairs()462312c0ed1SDimitry Andric void findIndependencePairs() {
463312c0ed1SDimitry Andric unsigned NumTVs = ExecVectors.size();
464ac9a064cSDimitry Andric for (unsigned I = NumExecVectorsF; I < NumTVs; ++I) {
465ac9a064cSDimitry Andric const auto &[A, ACond] = ExecVectors[I];
466ac9a064cSDimitry Andric assert(ACond == MCDCRecord::MCDC_True);
467ac9a064cSDimitry Andric for (unsigned J = 0; J < NumExecVectorsF; ++J) {
468ac9a064cSDimitry Andric const auto &[B, BCond] = ExecVectors[J];
469ac9a064cSDimitry Andric assert(BCond == MCDCRecord::MCDC_False);
470ac9a064cSDimitry Andric // If the two vectors differ in exactly one condition, ignoring DontCare
471ac9a064cSDimitry Andric // conditions, we have found an independence pair.
472ac9a064cSDimitry Andric auto AB = A.getDifferences(B);
473ac9a064cSDimitry Andric if (AB.count() == 1)
474ac9a064cSDimitry Andric IndependencePairs.insert(
475ac9a064cSDimitry Andric {AB.find_first(), std::make_pair(J + 1, I + 1)});
476312c0ed1SDimitry Andric }
477312c0ed1SDimitry Andric }
478312c0ed1SDimitry Andric }
479312c0ed1SDimitry Andric
480312c0ed1SDimitry Andric public:
481312c0ed1SDimitry Andric /// Process the MC/DC Record in order to produce a result for a boolean
482312c0ed1SDimitry Andric /// expression. This process includes tracking the conditions that comprise
483312c0ed1SDimitry Andric /// the decision region, calculating the list of all possible test vectors,
484312c0ed1SDimitry Andric /// marking the executed test vectors, and then finding an Independence Pair
485312c0ed1SDimitry Andric /// out of the executed test vectors for each condition in the boolean
486312c0ed1SDimitry Andric /// expression. A condition is tracked to ensure that its ID can be mapped to
487312c0ed1SDimitry Andric /// its ordinal position in the boolean expression. The condition's source
488312c0ed1SDimitry Andric /// location is also tracked, as well as whether it is constant folded (in
489312c0ed1SDimitry Andric /// which case it is excuded from the metric).
processMCDCRecord()490312c0ed1SDimitry Andric MCDCRecord processMCDCRecord() {
491312c0ed1SDimitry Andric unsigned I = 0;
492312c0ed1SDimitry Andric MCDCRecord::CondIDMap PosToID;
493312c0ed1SDimitry Andric MCDCRecord::LineColPairMap CondLoc;
494312c0ed1SDimitry Andric
495312c0ed1SDimitry Andric // Walk the Record's BranchRegions (representing Conditions) in order to:
496312c0ed1SDimitry Andric // - Hash the condition based on its corresponding ID. This will be used to
497312c0ed1SDimitry Andric // calculate the test vectors.
498312c0ed1SDimitry Andric // - Keep a map of the condition's ordinal position (1, 2, 3, 4) to its
499312c0ed1SDimitry Andric // actual ID. This will be used to visualize the conditions in the
500312c0ed1SDimitry Andric // correct order.
501312c0ed1SDimitry Andric // - Keep track of the condition source location. This will be used to
502312c0ed1SDimitry Andric // visualize where the condition is.
503312c0ed1SDimitry Andric // - Record whether the condition is constant folded so that we exclude it
504312c0ed1SDimitry Andric // from being measured.
5054df029ccSDimitry Andric for (const auto *B : Branches) {
506ac9a064cSDimitry Andric const auto &BranchParams = B->getBranchParams();
507ac9a064cSDimitry Andric PosToID[I] = BranchParams.ID;
5084df029ccSDimitry Andric CondLoc[I] = B->startLoc();
5094df029ccSDimitry Andric Folded[I++] = (B->Count.isZero() && B->FalseCount.isZero());
510312c0ed1SDimitry Andric }
511312c0ed1SDimitry Andric
512312c0ed1SDimitry Andric // Using Profile Bitmap from runtime, mark the executed test vectors.
513ac9a064cSDimitry Andric findExecutedTestVectors();
514312c0ed1SDimitry Andric
515312c0ed1SDimitry Andric // Compare executed test vectors against each other to find an independence
516312c0ed1SDimitry Andric // pairs for each condition. This processing takes the most time.
517312c0ed1SDimitry Andric findIndependencePairs();
518312c0ed1SDimitry Andric
519312c0ed1SDimitry Andric // Record Test vectors, executed vectors, and independence pairs.
520ac9a064cSDimitry Andric return MCDCRecord(Region, std::move(ExecVectors),
521ac9a064cSDimitry Andric std::move(IndependencePairs), std::move(Folded),
522ac9a064cSDimitry Andric std::move(PosToID), std::move(CondLoc));
523312c0ed1SDimitry Andric }
524312c0ed1SDimitry Andric };
525312c0ed1SDimitry Andric
526ac9a064cSDimitry Andric } // namespace
527ac9a064cSDimitry Andric
evaluateMCDCRegion(const CounterMappingRegion & Region,ArrayRef<const CounterMappingRegion * > Branches,bool IsVersion11)528312c0ed1SDimitry Andric Expected<MCDCRecord> CounterMappingContext::evaluateMCDCRegion(
5294df029ccSDimitry Andric const CounterMappingRegion &Region,
530ac9a064cSDimitry Andric ArrayRef<const CounterMappingRegion *> Branches, bool IsVersion11) {
531312c0ed1SDimitry Andric
532ac9a064cSDimitry Andric MCDCRecordProcessor MCDCProcessor(Bitmap, Region, Branches, IsVersion11);
533312c0ed1SDimitry Andric return MCDCProcessor.processMCDCRecord();
534312c0ed1SDimitry Andric }
535312c0ed1SDimitry Andric
getMaxCounterID(const Counter & C) const536344a3780SDimitry Andric unsigned CounterMappingContext::getMaxCounterID(const Counter &C) const {
537b1c73532SDimitry Andric struct StackElem {
538b1c73532SDimitry Andric Counter ICounter;
539b1c73532SDimitry Andric int64_t LHS = 0;
540b1c73532SDimitry Andric enum {
541b1c73532SDimitry Andric KNeverVisited = 0,
542b1c73532SDimitry Andric KVisitedOnce = 1,
543b1c73532SDimitry Andric KVisitedTwice = 2,
544b1c73532SDimitry Andric } VisitCount = KNeverVisited;
545b1c73532SDimitry Andric };
546b1c73532SDimitry Andric
547b1c73532SDimitry Andric std::stack<StackElem> CounterStack;
548b1c73532SDimitry Andric CounterStack.push({C});
549b1c73532SDimitry Andric
550b1c73532SDimitry Andric int64_t LastPoppedValue;
551b1c73532SDimitry Andric
552b1c73532SDimitry Andric while (!CounterStack.empty()) {
553b1c73532SDimitry Andric StackElem &Current = CounterStack.top();
554b1c73532SDimitry Andric
555b1c73532SDimitry Andric switch (Current.ICounter.getKind()) {
556344a3780SDimitry Andric case Counter::Zero:
557b1c73532SDimitry Andric LastPoppedValue = 0;
558b1c73532SDimitry Andric CounterStack.pop();
559b1c73532SDimitry Andric break;
560344a3780SDimitry Andric case Counter::CounterValueReference:
561b1c73532SDimitry Andric LastPoppedValue = Current.ICounter.getCounterID();
562b1c73532SDimitry Andric CounterStack.pop();
563b1c73532SDimitry Andric break;
564344a3780SDimitry Andric case Counter::Expression: {
565b1c73532SDimitry Andric if (Current.ICounter.getExpressionID() >= Expressions.size()) {
566b1c73532SDimitry Andric LastPoppedValue = 0;
567b1c73532SDimitry Andric CounterStack.pop();
568b1c73532SDimitry Andric } else {
569b1c73532SDimitry Andric const auto &E = Expressions[Current.ICounter.getExpressionID()];
570b1c73532SDimitry Andric if (Current.VisitCount == StackElem::KNeverVisited) {
571b1c73532SDimitry Andric CounterStack.push(StackElem{E.LHS});
572b1c73532SDimitry Andric Current.VisitCount = StackElem::KVisitedOnce;
573b1c73532SDimitry Andric } else if (Current.VisitCount == StackElem::KVisitedOnce) {
574b1c73532SDimitry Andric Current.LHS = LastPoppedValue;
575b1c73532SDimitry Andric CounterStack.push(StackElem{E.RHS});
576b1c73532SDimitry Andric Current.VisitCount = StackElem::KVisitedTwice;
577b1c73532SDimitry Andric } else {
578b1c73532SDimitry Andric int64_t LHS = Current.LHS;
579b1c73532SDimitry Andric int64_t RHS = LastPoppedValue;
580b1c73532SDimitry Andric LastPoppedValue = std::max(LHS, RHS);
581b1c73532SDimitry Andric CounterStack.pop();
582344a3780SDimitry Andric }
583344a3780SDimitry Andric }
584b1c73532SDimitry Andric break;
585b1c73532SDimitry Andric }
586b1c73532SDimitry Andric }
587b1c73532SDimitry Andric }
588b1c73532SDimitry Andric
589b1c73532SDimitry Andric return LastPoppedValue;
590344a3780SDimitry Andric }
591344a3780SDimitry Andric
skipOtherFiles()59201095a5dSDimitry Andric void FunctionRecordIterator::skipOtherFiles() {
59301095a5dSDimitry Andric while (Current != Records.end() && !Filename.empty() &&
59401095a5dSDimitry Andric Filename != Current->Filenames[0])
59501095a5dSDimitry Andric ++Current;
59601095a5dSDimitry Andric if (Current == Records.end())
59701095a5dSDimitry Andric *this = FunctionRecordIterator();
59801095a5dSDimitry Andric }
59901095a5dSDimitry Andric
getImpreciseRecordIndicesForFilename(StringRef Filename) const6001d5ae102SDimitry Andric ArrayRef<unsigned> CoverageMapping::getImpreciseRecordIndicesForFilename(
6011d5ae102SDimitry Andric StringRef Filename) const {
6021d5ae102SDimitry Andric size_t FilenameHash = hash_value(Filename);
6031d5ae102SDimitry Andric auto RecordIt = FilenameHash2RecordIndices.find(FilenameHash);
6041d5ae102SDimitry Andric if (RecordIt == FilenameHash2RecordIndices.end())
6051d5ae102SDimitry Andric return {};
6061d5ae102SDimitry Andric return RecordIt->second;
6071d5ae102SDimitry Andric }
6081d5ae102SDimitry Andric
getMaxCounterID(const CounterMappingContext & Ctx,const CoverageMappingRecord & Record)609344a3780SDimitry Andric static unsigned getMaxCounterID(const CounterMappingContext &Ctx,
610344a3780SDimitry Andric const CoverageMappingRecord &Record) {
611344a3780SDimitry Andric unsigned MaxCounterID = 0;
612344a3780SDimitry Andric for (const auto &Region : Record.MappingRegions) {
613344a3780SDimitry Andric MaxCounterID = std::max(MaxCounterID, Ctx.getMaxCounterID(Region.Count));
614344a3780SDimitry Andric }
615344a3780SDimitry Andric return MaxCounterID;
616344a3780SDimitry Andric }
617344a3780SDimitry Andric
618ac9a064cSDimitry Andric /// Returns the bit count
getMaxBitmapSize(const CoverageMappingRecord & Record,bool IsVersion11)619ac9a064cSDimitry Andric static unsigned getMaxBitmapSize(const CoverageMappingRecord &Record,
620ac9a064cSDimitry Andric bool IsVersion11) {
621ac9a064cSDimitry Andric unsigned MaxBitmapIdx = 0;
622312c0ed1SDimitry Andric unsigned NumConditions = 0;
6234df029ccSDimitry Andric // Scan max(BitmapIdx).
6244df029ccSDimitry Andric // Note that `<=` is used insted of `<`, because `BitmapIdx == 0` is valid
625ac9a064cSDimitry Andric // and `MaxBitmapIdx is `unsigned`. `BitmapIdx` is unique in the record.
626312c0ed1SDimitry Andric for (const auto &Region : reverse(Record.MappingRegions)) {
627ac9a064cSDimitry Andric if (Region.Kind != CounterMappingRegion::MCDCDecisionRegion)
628ac9a064cSDimitry Andric continue;
629ac9a064cSDimitry Andric const auto &DecisionParams = Region.getDecisionParams();
630ac9a064cSDimitry Andric if (MaxBitmapIdx <= DecisionParams.BitmapIdx) {
631ac9a064cSDimitry Andric MaxBitmapIdx = DecisionParams.BitmapIdx;
632ac9a064cSDimitry Andric NumConditions = DecisionParams.NumConditions;
633312c0ed1SDimitry Andric }
634312c0ed1SDimitry Andric }
635ac9a064cSDimitry Andric
636ac9a064cSDimitry Andric if (IsVersion11)
637ac9a064cSDimitry Andric MaxBitmapIdx = MaxBitmapIdx * CHAR_BIT +
638ac9a064cSDimitry Andric llvm::alignTo(uint64_t(1) << NumConditions, CHAR_BIT);
639ac9a064cSDimitry Andric
640ac9a064cSDimitry Andric return MaxBitmapIdx;
641312c0ed1SDimitry Andric }
642312c0ed1SDimitry Andric
643ac9a064cSDimitry Andric namespace {
644ac9a064cSDimitry Andric
645ac9a064cSDimitry Andric /// Collect Decisions, Branchs, and Expansions and associate them.
646ac9a064cSDimitry Andric class MCDCDecisionRecorder {
647ac9a064cSDimitry Andric private:
648ac9a064cSDimitry Andric /// This holds the DecisionRegion and MCDCBranches under it.
649ac9a064cSDimitry Andric /// Also traverses Expansion(s).
650ac9a064cSDimitry Andric /// The Decision has the number of MCDCBranches and will complete
651ac9a064cSDimitry Andric /// when it is filled with unique ConditionID of MCDCBranches.
652ac9a064cSDimitry Andric struct DecisionRecord {
653ac9a064cSDimitry Andric const CounterMappingRegion *DecisionRegion;
654ac9a064cSDimitry Andric
655ac9a064cSDimitry Andric /// They are reflected from DecisionRegion for convenience.
656ac9a064cSDimitry Andric mcdc::DecisionParameters DecisionParams;
657ac9a064cSDimitry Andric LineColPair DecisionStartLoc;
658ac9a064cSDimitry Andric LineColPair DecisionEndLoc;
659ac9a064cSDimitry Andric
660ac9a064cSDimitry Andric /// This is passed to `MCDCRecordProcessor`, so this should be compatible
661ac9a064cSDimitry Andric /// to`ArrayRef<const CounterMappingRegion *>`.
662ac9a064cSDimitry Andric SmallVector<const CounterMappingRegion *> MCDCBranches;
663ac9a064cSDimitry Andric
664ac9a064cSDimitry Andric /// IDs that are stored in MCDCBranches
665ac9a064cSDimitry Andric /// Complete when all IDs (1 to NumConditions) are met.
666ac9a064cSDimitry Andric DenseSet<mcdc::ConditionID> ConditionIDs;
667ac9a064cSDimitry Andric
668ac9a064cSDimitry Andric /// Set of IDs of Expansion(s) that are relevant to DecisionRegion
669ac9a064cSDimitry Andric /// and its children (via expansions).
670ac9a064cSDimitry Andric /// FileID pointed by ExpandedFileID is dedicated to the expansion, so
671ac9a064cSDimitry Andric /// the location in the expansion doesn't matter.
672ac9a064cSDimitry Andric DenseSet<unsigned> ExpandedFileIDs;
673ac9a064cSDimitry Andric
DecisionRecord__anon140606b20511::MCDCDecisionRecorder::DecisionRecord674ac9a064cSDimitry Andric DecisionRecord(const CounterMappingRegion &Decision)
675ac9a064cSDimitry Andric : DecisionRegion(&Decision),
676ac9a064cSDimitry Andric DecisionParams(Decision.getDecisionParams()),
677ac9a064cSDimitry Andric DecisionStartLoc(Decision.startLoc()),
678ac9a064cSDimitry Andric DecisionEndLoc(Decision.endLoc()) {
679ac9a064cSDimitry Andric assert(Decision.Kind == CounterMappingRegion::MCDCDecisionRegion);
680ac9a064cSDimitry Andric }
681ac9a064cSDimitry Andric
682ac9a064cSDimitry Andric /// Determine whether DecisionRecord dominates `R`.
dominates__anon140606b20511::MCDCDecisionRecorder::DecisionRecord683ac9a064cSDimitry Andric bool dominates(const CounterMappingRegion &R) const {
684ac9a064cSDimitry Andric // Determine whether `R` is included in `DecisionRegion`.
685ac9a064cSDimitry Andric if (R.FileID == DecisionRegion->FileID &&
686ac9a064cSDimitry Andric R.startLoc() >= DecisionStartLoc && R.endLoc() <= DecisionEndLoc)
687ac9a064cSDimitry Andric return true;
688ac9a064cSDimitry Andric
689ac9a064cSDimitry Andric // Determine whether `R` is pointed by any of Expansions.
690ac9a064cSDimitry Andric return ExpandedFileIDs.contains(R.FileID);
691ac9a064cSDimitry Andric }
692ac9a064cSDimitry Andric
693ac9a064cSDimitry Andric enum Result {
694ac9a064cSDimitry Andric NotProcessed = 0, /// Irrelevant to this Decision
695ac9a064cSDimitry Andric Processed, /// Added to this Decision
696ac9a064cSDimitry Andric Completed, /// Added and filled this Decision
697ac9a064cSDimitry Andric };
698ac9a064cSDimitry Andric
699ac9a064cSDimitry Andric /// Add Branch into the Decision
700ac9a064cSDimitry Andric /// \param Branch expects MCDCBranchRegion
701ac9a064cSDimitry Andric /// \returns NotProcessed/Processed/Completed
addBranch__anon140606b20511::MCDCDecisionRecorder::DecisionRecord702ac9a064cSDimitry Andric Result addBranch(const CounterMappingRegion &Branch) {
703ac9a064cSDimitry Andric assert(Branch.Kind == CounterMappingRegion::MCDCBranchRegion);
704ac9a064cSDimitry Andric
705ac9a064cSDimitry Andric auto ConditionID = Branch.getBranchParams().ID;
706ac9a064cSDimitry Andric
707ac9a064cSDimitry Andric if (ConditionIDs.contains(ConditionID) ||
708ac9a064cSDimitry Andric ConditionID >= DecisionParams.NumConditions)
709ac9a064cSDimitry Andric return NotProcessed;
710ac9a064cSDimitry Andric
711ac9a064cSDimitry Andric if (!this->dominates(Branch))
712ac9a064cSDimitry Andric return NotProcessed;
713ac9a064cSDimitry Andric
714ac9a064cSDimitry Andric assert(MCDCBranches.size() < DecisionParams.NumConditions);
715ac9a064cSDimitry Andric
716ac9a064cSDimitry Andric // Put `ID=0` in front of `MCDCBranches` for convenience
717ac9a064cSDimitry Andric // even if `MCDCBranches` is not topological.
718ac9a064cSDimitry Andric if (ConditionID == 0)
719ac9a064cSDimitry Andric MCDCBranches.insert(MCDCBranches.begin(), &Branch);
720ac9a064cSDimitry Andric else
721ac9a064cSDimitry Andric MCDCBranches.push_back(&Branch);
722ac9a064cSDimitry Andric
723ac9a064cSDimitry Andric // Mark `ID` as `assigned`.
724ac9a064cSDimitry Andric ConditionIDs.insert(ConditionID);
725ac9a064cSDimitry Andric
726ac9a064cSDimitry Andric // `Completed` when `MCDCBranches` is full
727ac9a064cSDimitry Andric return (MCDCBranches.size() == DecisionParams.NumConditions ? Completed
728ac9a064cSDimitry Andric : Processed);
729ac9a064cSDimitry Andric }
730ac9a064cSDimitry Andric
731ac9a064cSDimitry Andric /// Record Expansion if it is relevant to this Decision.
732ac9a064cSDimitry Andric /// Each `Expansion` may nest.
733ac9a064cSDimitry Andric /// \returns true if recorded.
recordExpansion__anon140606b20511::MCDCDecisionRecorder::DecisionRecord734ac9a064cSDimitry Andric bool recordExpansion(const CounterMappingRegion &Expansion) {
735ac9a064cSDimitry Andric if (!this->dominates(Expansion))
736ac9a064cSDimitry Andric return false;
737ac9a064cSDimitry Andric
738ac9a064cSDimitry Andric ExpandedFileIDs.insert(Expansion.ExpandedFileID);
739ac9a064cSDimitry Andric return true;
740ac9a064cSDimitry Andric }
741ac9a064cSDimitry Andric };
742ac9a064cSDimitry Andric
743ac9a064cSDimitry Andric private:
744ac9a064cSDimitry Andric /// Decisions in progress
745ac9a064cSDimitry Andric /// DecisionRecord is added for each MCDCDecisionRegion.
746ac9a064cSDimitry Andric /// DecisionRecord is removed when Decision is completed.
747ac9a064cSDimitry Andric SmallVector<DecisionRecord> Decisions;
748ac9a064cSDimitry Andric
749ac9a064cSDimitry Andric public:
~MCDCDecisionRecorder()750ac9a064cSDimitry Andric ~MCDCDecisionRecorder() {
751ac9a064cSDimitry Andric assert(Decisions.empty() && "All Decisions have not been resolved");
752ac9a064cSDimitry Andric }
753ac9a064cSDimitry Andric
754ac9a064cSDimitry Andric /// Register Region and start recording.
registerDecision(const CounterMappingRegion & Decision)755ac9a064cSDimitry Andric void registerDecision(const CounterMappingRegion &Decision) {
756ac9a064cSDimitry Andric Decisions.emplace_back(Decision);
757ac9a064cSDimitry Andric }
758ac9a064cSDimitry Andric
recordExpansion(const CounterMappingRegion & Expansion)759ac9a064cSDimitry Andric void recordExpansion(const CounterMappingRegion &Expansion) {
760ac9a064cSDimitry Andric any_of(Decisions, [&Expansion](auto &Decision) {
761ac9a064cSDimitry Andric return Decision.recordExpansion(Expansion);
762ac9a064cSDimitry Andric });
763ac9a064cSDimitry Andric }
764ac9a064cSDimitry Andric
765ac9a064cSDimitry Andric using DecisionAndBranches =
766ac9a064cSDimitry Andric std::pair<const CounterMappingRegion *, /// Decision
767ac9a064cSDimitry Andric SmallVector<const CounterMappingRegion *> /// Branches
768ac9a064cSDimitry Andric >;
769ac9a064cSDimitry Andric
770ac9a064cSDimitry Andric /// Add MCDCBranchRegion to DecisionRecord.
771ac9a064cSDimitry Andric /// \param Branch to be processed
772ac9a064cSDimitry Andric /// \returns DecisionsAndBranches if DecisionRecord completed.
773ac9a064cSDimitry Andric /// Or returns nullopt.
774ac9a064cSDimitry Andric std::optional<DecisionAndBranches>
processBranch(const CounterMappingRegion & Branch)775ac9a064cSDimitry Andric processBranch(const CounterMappingRegion &Branch) {
776ac9a064cSDimitry Andric // Seek each Decision and apply Region to it.
777ac9a064cSDimitry Andric for (auto DecisionIter = Decisions.begin(), DecisionEnd = Decisions.end();
778ac9a064cSDimitry Andric DecisionIter != DecisionEnd; ++DecisionIter)
779ac9a064cSDimitry Andric switch (DecisionIter->addBranch(Branch)) {
780ac9a064cSDimitry Andric case DecisionRecord::NotProcessed:
781ac9a064cSDimitry Andric continue;
782ac9a064cSDimitry Andric case DecisionRecord::Processed:
783ac9a064cSDimitry Andric return std::nullopt;
784ac9a064cSDimitry Andric case DecisionRecord::Completed:
785ac9a064cSDimitry Andric DecisionAndBranches Result =
786ac9a064cSDimitry Andric std::make_pair(DecisionIter->DecisionRegion,
787ac9a064cSDimitry Andric std::move(DecisionIter->MCDCBranches));
788ac9a064cSDimitry Andric Decisions.erase(DecisionIter); // No longer used.
789ac9a064cSDimitry Andric return Result;
790ac9a064cSDimitry Andric }
791ac9a064cSDimitry Andric
792ac9a064cSDimitry Andric llvm_unreachable("Branch not found in Decisions");
793ac9a064cSDimitry Andric }
794ac9a064cSDimitry Andric };
795ac9a064cSDimitry Andric
796ac9a064cSDimitry Andric } // namespace
797ac9a064cSDimitry Andric
loadFunctionRecord(const CoverageMappingRecord & Record,IndexedInstrProfReader & ProfileReader)798b915e9e0SDimitry Andric Error CoverageMapping::loadFunctionRecord(
799b915e9e0SDimitry Andric const CoverageMappingRecord &Record,
80001095a5dSDimitry Andric IndexedInstrProfReader &ProfileReader) {
801b915e9e0SDimitry Andric StringRef OrigFuncName = Record.FunctionName;
80208bbd35aSDimitry Andric if (OrigFuncName.empty())
803b1c73532SDimitry Andric return make_error<CoverageMapError>(coveragemap_error::malformed,
804b1c73532SDimitry Andric "record function name is empty");
80508bbd35aSDimitry Andric
806b915e9e0SDimitry Andric if (Record.Filenames.empty())
807b915e9e0SDimitry Andric OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName);
808b915e9e0SDimitry Andric else
809b915e9e0SDimitry Andric OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]);
81001095a5dSDimitry Andric
81101095a5dSDimitry Andric CounterMappingContext Ctx(Record.Expressions);
81201095a5dSDimitry Andric
813b915e9e0SDimitry Andric std::vector<uint64_t> Counts;
814b915e9e0SDimitry Andric if (Error E = ProfileReader.getFunctionCounts(Record.FunctionName,
815b915e9e0SDimitry Andric Record.FunctionHash, Counts)) {
8167fa27ce4SDimitry Andric instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
81701095a5dSDimitry Andric if (IPE == instrprof_error::hash_mismatch) {
818cfca06d7SDimitry Andric FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
819cfca06d7SDimitry Andric Record.FunctionHash);
820b915e9e0SDimitry Andric return Error::success();
821312c0ed1SDimitry Andric }
822312c0ed1SDimitry Andric if (IPE != instrprof_error::unknown_function)
82301095a5dSDimitry Andric return make_error<InstrProfError>(IPE);
824344a3780SDimitry Andric Counts.assign(getMaxCounterID(Ctx, Record) + 1, 0);
82501095a5dSDimitry Andric }
82601095a5dSDimitry Andric Ctx.setCounts(Counts);
82701095a5dSDimitry Andric
828ac9a064cSDimitry Andric bool IsVersion11 =
829ac9a064cSDimitry Andric ProfileReader.getVersion() < IndexedInstrProf::ProfVersion::Version12;
830ac9a064cSDimitry Andric
831ac9a064cSDimitry Andric BitVector Bitmap;
832ac9a064cSDimitry Andric if (Error E = ProfileReader.getFunctionBitmap(Record.FunctionName,
833ac9a064cSDimitry Andric Record.FunctionHash, Bitmap)) {
834312c0ed1SDimitry Andric instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
835312c0ed1SDimitry Andric if (IPE == instrprof_error::hash_mismatch) {
836312c0ed1SDimitry Andric FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
837312c0ed1SDimitry Andric Record.FunctionHash);
838312c0ed1SDimitry Andric return Error::success();
839312c0ed1SDimitry Andric }
840312c0ed1SDimitry Andric if (IPE != instrprof_error::unknown_function)
841312c0ed1SDimitry Andric return make_error<InstrProfError>(IPE);
842ac9a064cSDimitry Andric Bitmap = BitVector(getMaxBitmapSize(Record, IsVersion11));
843312c0ed1SDimitry Andric }
844ac9a064cSDimitry Andric Ctx.setBitmap(std::move(Bitmap));
845312c0ed1SDimitry Andric
84601095a5dSDimitry Andric assert(!Record.MappingRegions.empty() && "Function has no regions");
84701095a5dSDimitry Andric
848d8e91e46SDimitry Andric // This coverage record is a zero region for a function that's unused in
849d8e91e46SDimitry Andric // some TU, but used in a different TU. Ignore it. The coverage maps from the
850d8e91e46SDimitry Andric // the other TU will either be loaded (providing full region counts) or they
851d8e91e46SDimitry Andric // won't (in which case we don't unintuitively report functions as uncovered
852d8e91e46SDimitry Andric // when they have non-zero counts in the profile).
853d8e91e46SDimitry Andric if (Record.MappingRegions.size() == 1 &&
854d8e91e46SDimitry Andric Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
855d8e91e46SDimitry Andric return Error::success();
856d8e91e46SDimitry Andric
857ac9a064cSDimitry Andric MCDCDecisionRecorder MCDCDecisions;
85801095a5dSDimitry Andric FunctionRecord Function(OrigFuncName, Record.Filenames);
85901095a5dSDimitry Andric for (const auto &Region : Record.MappingRegions) {
860ac9a064cSDimitry Andric // MCDCDecisionRegion should be handled first since it overlaps with
861ac9a064cSDimitry Andric // others inside.
862312c0ed1SDimitry Andric if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion) {
863ac9a064cSDimitry Andric MCDCDecisions.registerDecision(Region);
864312c0ed1SDimitry Andric continue;
865312c0ed1SDimitry Andric }
86601095a5dSDimitry Andric Expected<int64_t> ExecutionCount = Ctx.evaluate(Region.Count);
86701095a5dSDimitry Andric if (auto E = ExecutionCount.takeError()) {
86871d5a254SDimitry Andric consumeError(std::move(E));
869b915e9e0SDimitry Andric return Error::success();
87001095a5dSDimitry Andric }
871b60736ecSDimitry Andric Expected<int64_t> AltExecutionCount = Ctx.evaluate(Region.FalseCount);
872b60736ecSDimitry Andric if (auto E = AltExecutionCount.takeError()) {
873b60736ecSDimitry Andric consumeError(std::move(E));
874b60736ecSDimitry Andric return Error::success();
875b60736ecSDimitry Andric }
876ac9a064cSDimitry Andric Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount,
877ac9a064cSDimitry Andric ProfileReader.hasSingleByteCoverage());
878312c0ed1SDimitry Andric
879ac9a064cSDimitry Andric // Record ExpansionRegion.
880ac9a064cSDimitry Andric if (Region.Kind == CounterMappingRegion::ExpansionRegion) {
881ac9a064cSDimitry Andric MCDCDecisions.recordExpansion(Region);
882ac9a064cSDimitry Andric continue;
883312c0ed1SDimitry Andric }
884312c0ed1SDimitry Andric
885ac9a064cSDimitry Andric // Do nothing unless MCDCBranchRegion.
886ac9a064cSDimitry Andric if (Region.Kind != CounterMappingRegion::MCDCBranchRegion)
887ac9a064cSDimitry Andric continue;
888ac9a064cSDimitry Andric
889ac9a064cSDimitry Andric auto Result = MCDCDecisions.processBranch(Region);
890ac9a064cSDimitry Andric if (!Result) // Any Decision doesn't complete.
891ac9a064cSDimitry Andric continue;
892ac9a064cSDimitry Andric
893ac9a064cSDimitry Andric auto MCDCDecision = Result->first;
894ac9a064cSDimitry Andric auto &MCDCBranches = Result->second;
895ac9a064cSDimitry Andric
896312c0ed1SDimitry Andric // Since the bitmap identifies the executed test vectors for an MC/DC
897312c0ed1SDimitry Andric // DecisionRegion, all of the information is now available to process.
898312c0ed1SDimitry Andric // This is where the bulk of the MC/DC progressing takes place.
899ac9a064cSDimitry Andric Expected<MCDCRecord> Record =
900ac9a064cSDimitry Andric Ctx.evaluateMCDCRegion(*MCDCDecision, MCDCBranches, IsVersion11);
901312c0ed1SDimitry Andric if (auto E = Record.takeError()) {
902312c0ed1SDimitry Andric consumeError(std::move(E));
903312c0ed1SDimitry Andric return Error::success();
904312c0ed1SDimitry Andric }
905312c0ed1SDimitry Andric
906312c0ed1SDimitry Andric // Save the MC/DC Record so that it can be visualized later.
907ac9a064cSDimitry Andric Function.pushMCDCRecord(std::move(*Record));
90801095a5dSDimitry Andric }
909d8e91e46SDimitry Andric
910d8e91e46SDimitry Andric // Don't create records for (filenames, function) pairs we've already seen.
911d8e91e46SDimitry Andric auto FilenamesHash = hash_combine_range(Record.Filenames.begin(),
912d8e91e46SDimitry Andric Record.Filenames.end());
913d8e91e46SDimitry Andric if (!RecordProvenance[FilenamesHash].insert(hash_value(OrigFuncName)).second)
914b915e9e0SDimitry Andric return Error::success();
91501095a5dSDimitry Andric
916b915e9e0SDimitry Andric Functions.push_back(std::move(Function));
9171d5ae102SDimitry Andric
9181d5ae102SDimitry Andric // Performance optimization: keep track of the indices of the function records
9191d5ae102SDimitry Andric // which correspond to each filename. This can be used to substantially speed
9201d5ae102SDimitry Andric // up queries for coverage info in a file.
9211d5ae102SDimitry Andric unsigned RecordIndex = Functions.size() - 1;
9221d5ae102SDimitry Andric for (StringRef Filename : Record.Filenames) {
9231d5ae102SDimitry Andric auto &RecordIndices = FilenameHash2RecordIndices[hash_value(Filename)];
9241d5ae102SDimitry Andric // Note that there may be duplicates in the filename set for a function
9251d5ae102SDimitry Andric // record, because of e.g. macro expansions in the function in which both
9261d5ae102SDimitry Andric // the macro and the function are defined in the same file.
9271d5ae102SDimitry Andric if (RecordIndices.empty() || RecordIndices.back() != RecordIndex)
9281d5ae102SDimitry Andric RecordIndices.push_back(RecordIndex);
9291d5ae102SDimitry Andric }
9301d5ae102SDimitry Andric
931b915e9e0SDimitry Andric return Error::success();
93201095a5dSDimitry Andric }
93301095a5dSDimitry Andric
934344a3780SDimitry Andric // This function is for memory optimization by shortening the lifetimes
935344a3780SDimitry Andric // of CoverageMappingReader instances.
loadFromReaders(ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,IndexedInstrProfReader & ProfileReader,CoverageMapping & Coverage)936344a3780SDimitry Andric Error CoverageMapping::loadFromReaders(
937344a3780SDimitry Andric ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
938344a3780SDimitry Andric IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage) {
939344a3780SDimitry Andric for (const auto &CoverageReader : CoverageReaders) {
940344a3780SDimitry Andric for (auto RecordOrErr : *CoverageReader) {
941344a3780SDimitry Andric if (Error E = RecordOrErr.takeError())
942344a3780SDimitry Andric return E;
943344a3780SDimitry Andric const auto &Record = *RecordOrErr;
944344a3780SDimitry Andric if (Error E = Coverage.loadFunctionRecord(Record, ProfileReader))
945344a3780SDimitry Andric return E;
946344a3780SDimitry Andric }
947344a3780SDimitry Andric }
948344a3780SDimitry Andric return Error::success();
949344a3780SDimitry Andric }
950344a3780SDimitry Andric
load(ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,IndexedInstrProfReader & ProfileReader)951b915e9e0SDimitry Andric Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
952b915e9e0SDimitry Andric ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
953b915e9e0SDimitry Andric IndexedInstrProfReader &ProfileReader) {
954b915e9e0SDimitry Andric auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
955344a3780SDimitry Andric if (Error E = loadFromReaders(CoverageReaders, ProfileReader, *Coverage))
956044eb2f6SDimitry Andric return std::move(E);
95701095a5dSDimitry Andric return std::move(Coverage);
95801095a5dSDimitry Andric }
95901095a5dSDimitry Andric
9601d5ae102SDimitry Andric // If E is a no_data_found error, returns success. Otherwise returns E.
handleMaybeNoDataFoundError(Error E)9611d5ae102SDimitry Andric static Error handleMaybeNoDataFoundError(Error E) {
9621d5ae102SDimitry Andric return handleErrors(
9631d5ae102SDimitry Andric std::move(E), [](const CoverageMapError &CME) {
9641d5ae102SDimitry Andric if (CME.get() == coveragemap_error::no_data_found)
9651d5ae102SDimitry Andric return static_cast<Error>(Error::success());
966b1c73532SDimitry Andric return make_error<CoverageMapError>(CME.get(), CME.getMessage());
9671d5ae102SDimitry Andric });
9681d5ae102SDimitry Andric }
9691d5ae102SDimitry Andric
loadFromFile(StringRef Filename,StringRef Arch,StringRef CompilationDir,IndexedInstrProfReader & ProfileReader,CoverageMapping & Coverage,bool & DataFound,SmallVectorImpl<object::BuildID> * FoundBinaryIDs)9707fa27ce4SDimitry Andric Error CoverageMapping::loadFromFile(
9717fa27ce4SDimitry Andric StringRef Filename, StringRef Arch, StringRef CompilationDir,
9727fa27ce4SDimitry Andric IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage,
9737fa27ce4SDimitry Andric bool &DataFound, SmallVectorImpl<object::BuildID> *FoundBinaryIDs) {
9747fa27ce4SDimitry Andric auto CovMappingBufOrErr = MemoryBuffer::getFileOrSTDIN(
9757fa27ce4SDimitry Andric Filename, /*IsText=*/false, /*RequiresNullTerminator=*/false);
9767fa27ce4SDimitry Andric if (std::error_code EC = CovMappingBufOrErr.getError())
9777fa27ce4SDimitry Andric return createFileError(Filename, errorCodeToError(EC));
9787fa27ce4SDimitry Andric MemoryBufferRef CovMappingBufRef =
9797fa27ce4SDimitry Andric CovMappingBufOrErr.get()->getMemBufferRef();
9807fa27ce4SDimitry Andric SmallVector<std::unique_ptr<MemoryBuffer>, 4> Buffers;
9817fa27ce4SDimitry Andric
9827fa27ce4SDimitry Andric SmallVector<object::BuildIDRef> BinaryIDs;
9837fa27ce4SDimitry Andric auto CoverageReadersOrErr = BinaryCoverageReader::create(
9847fa27ce4SDimitry Andric CovMappingBufRef, Arch, Buffers, CompilationDir,
9857fa27ce4SDimitry Andric FoundBinaryIDs ? &BinaryIDs : nullptr);
9867fa27ce4SDimitry Andric if (Error E = CoverageReadersOrErr.takeError()) {
9877fa27ce4SDimitry Andric E = handleMaybeNoDataFoundError(std::move(E));
9887fa27ce4SDimitry Andric if (E)
9897fa27ce4SDimitry Andric return createFileError(Filename, std::move(E));
9907fa27ce4SDimitry Andric return E;
9917fa27ce4SDimitry Andric }
9927fa27ce4SDimitry Andric
9937fa27ce4SDimitry Andric SmallVector<std::unique_ptr<CoverageMappingReader>, 4> Readers;
9947fa27ce4SDimitry Andric for (auto &Reader : CoverageReadersOrErr.get())
9957fa27ce4SDimitry Andric Readers.push_back(std::move(Reader));
9967fa27ce4SDimitry Andric if (FoundBinaryIDs && !Readers.empty()) {
9977fa27ce4SDimitry Andric llvm::append_range(*FoundBinaryIDs,
9987fa27ce4SDimitry Andric llvm::map_range(BinaryIDs, [](object::BuildIDRef BID) {
9997fa27ce4SDimitry Andric return object::BuildID(BID);
10007fa27ce4SDimitry Andric }));
10017fa27ce4SDimitry Andric }
10027fa27ce4SDimitry Andric DataFound |= !Readers.empty();
10037fa27ce4SDimitry Andric if (Error E = loadFromReaders(Readers, ProfileReader, Coverage))
10047fa27ce4SDimitry Andric return createFileError(Filename, std::move(E));
10057fa27ce4SDimitry Andric return Error::success();
10067fa27ce4SDimitry Andric }
10077fa27ce4SDimitry Andric
load(ArrayRef<StringRef> ObjectFilenames,StringRef ProfileFilename,vfs::FileSystem & FS,ArrayRef<StringRef> Arches,StringRef CompilationDir,const object::BuildIDFetcher * BIDFetcher,bool CheckBinaryIDs)10087fa27ce4SDimitry Andric Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
10097fa27ce4SDimitry Andric ArrayRef<StringRef> ObjectFilenames, StringRef ProfileFilename,
10107fa27ce4SDimitry Andric vfs::FileSystem &FS, ArrayRef<StringRef> Arches, StringRef CompilationDir,
10117fa27ce4SDimitry Andric const object::BuildIDFetcher *BIDFetcher, bool CheckBinaryIDs) {
10127fa27ce4SDimitry Andric auto ProfileReaderOrErr = IndexedInstrProfReader::create(ProfileFilename, FS);
101301095a5dSDimitry Andric if (Error E = ProfileReaderOrErr.takeError())
10144b4fe385SDimitry Andric return createFileError(ProfileFilename, std::move(E));
101501095a5dSDimitry Andric auto ProfileReader = std::move(ProfileReaderOrErr.get());
1016344a3780SDimitry Andric auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
1017344a3780SDimitry Andric bool DataFound = false;
1018b915e9e0SDimitry Andric
10197fa27ce4SDimitry Andric auto GetArch = [&](size_t Idx) {
10207fa27ce4SDimitry Andric if (Arches.empty())
10217fa27ce4SDimitry Andric return StringRef();
10227fa27ce4SDimitry Andric if (Arches.size() == 1)
10237fa27ce4SDimitry Andric return Arches.front();
10247fa27ce4SDimitry Andric return Arches[Idx];
10257fa27ce4SDimitry Andric };
10267fa27ce4SDimitry Andric
10277fa27ce4SDimitry Andric SmallVector<object::BuildID> FoundBinaryIDs;
1028044eb2f6SDimitry Andric for (const auto &File : llvm::enumerate(ObjectFilenames)) {
10297fa27ce4SDimitry Andric if (Error E =
10307fa27ce4SDimitry Andric loadFromFile(File.value(), GetArch(File.index()), CompilationDir,
10317fa27ce4SDimitry Andric *ProfileReader, *Coverage, DataFound, &FoundBinaryIDs))
10327fa27ce4SDimitry Andric return std::move(E);
10331d5ae102SDimitry Andric }
1034344a3780SDimitry Andric
10357fa27ce4SDimitry Andric if (BIDFetcher) {
10367fa27ce4SDimitry Andric std::vector<object::BuildID> ProfileBinaryIDs;
10377fa27ce4SDimitry Andric if (Error E = ProfileReader->readBinaryIds(ProfileBinaryIDs))
10387fa27ce4SDimitry Andric return createFileError(ProfileFilename, std::move(E));
10397fa27ce4SDimitry Andric
10407fa27ce4SDimitry Andric SmallVector<object::BuildIDRef> BinaryIDsToFetch;
10417fa27ce4SDimitry Andric if (!ProfileBinaryIDs.empty()) {
10427fa27ce4SDimitry Andric const auto &Compare = [](object::BuildIDRef A, object::BuildIDRef B) {
10437fa27ce4SDimitry Andric return std::lexicographical_compare(A.begin(), A.end(), B.begin(),
10447fa27ce4SDimitry Andric B.end());
10457fa27ce4SDimitry Andric };
10467fa27ce4SDimitry Andric llvm::sort(FoundBinaryIDs, Compare);
10477fa27ce4SDimitry Andric std::set_difference(
10487fa27ce4SDimitry Andric ProfileBinaryIDs.begin(), ProfileBinaryIDs.end(),
10497fa27ce4SDimitry Andric FoundBinaryIDs.begin(), FoundBinaryIDs.end(),
10507fa27ce4SDimitry Andric std::inserter(BinaryIDsToFetch, BinaryIDsToFetch.end()), Compare);
1051b915e9e0SDimitry Andric }
10527fa27ce4SDimitry Andric
10537fa27ce4SDimitry Andric for (object::BuildIDRef BinaryID : BinaryIDsToFetch) {
10547fa27ce4SDimitry Andric std::optional<std::string> PathOpt = BIDFetcher->fetch(BinaryID);
10557fa27ce4SDimitry Andric if (PathOpt) {
10567fa27ce4SDimitry Andric std::string Path = std::move(*PathOpt);
10577fa27ce4SDimitry Andric StringRef Arch = Arches.size() == 1 ? Arches.front() : StringRef();
10587fa27ce4SDimitry Andric if (Error E = loadFromFile(Path, Arch, CompilationDir, *ProfileReader,
10597fa27ce4SDimitry Andric *Coverage, DataFound))
10607fa27ce4SDimitry Andric return std::move(E);
10617fa27ce4SDimitry Andric } else if (CheckBinaryIDs) {
10627fa27ce4SDimitry Andric return createFileError(
10637fa27ce4SDimitry Andric ProfileFilename,
10647fa27ce4SDimitry Andric createStringError(errc::no_such_file_or_directory,
10657fa27ce4SDimitry Andric "Missing binary ID: " +
10667fa27ce4SDimitry Andric llvm::toHex(BinaryID, /*LowerCase=*/true)));
10677fa27ce4SDimitry Andric }
10687fa27ce4SDimitry Andric }
10697fa27ce4SDimitry Andric }
10707fa27ce4SDimitry Andric
10717fa27ce4SDimitry Andric if (!DataFound)
10724b4fe385SDimitry Andric return createFileError(
10734b4fe385SDimitry Andric join(ObjectFilenames.begin(), ObjectFilenames.end(), ", "),
10744b4fe385SDimitry Andric make_error<CoverageMapError>(coveragemap_error::no_data_found));
1075344a3780SDimitry Andric return std::move(Coverage);
107601095a5dSDimitry Andric }
107701095a5dSDimitry Andric
107801095a5dSDimitry Andric namespace {
107971d5a254SDimitry Andric
1080eb11fae6SDimitry Andric /// Distributes functions into instantiation sets.
108101095a5dSDimitry Andric ///
108201095a5dSDimitry Andric /// An instantiation set is a collection of functions that have the same source
108301095a5dSDimitry Andric /// code, ie, template functions specializations.
108401095a5dSDimitry Andric class FunctionInstantiationSetCollector {
1085044eb2f6SDimitry Andric using MapT = std::map<LineColPair, std::vector<const FunctionRecord *>>;
108601095a5dSDimitry Andric MapT InstantiatedFunctions;
108701095a5dSDimitry Andric
108801095a5dSDimitry Andric public:
insert(const FunctionRecord & Function,unsigned FileID)108901095a5dSDimitry Andric void insert(const FunctionRecord &Function, unsigned FileID) {
109001095a5dSDimitry Andric auto I = Function.CountedRegions.begin(), E = Function.CountedRegions.end();
109101095a5dSDimitry Andric while (I != E && I->FileID != FileID)
109201095a5dSDimitry Andric ++I;
109301095a5dSDimitry Andric assert(I != E && "function does not cover the given file");
109401095a5dSDimitry Andric auto &Functions = InstantiatedFunctions[I->startLoc()];
109501095a5dSDimitry Andric Functions.push_back(&Function);
109601095a5dSDimitry Andric }
109701095a5dSDimitry Andric
begin()109801095a5dSDimitry Andric MapT::iterator begin() { return InstantiatedFunctions.begin(); }
end()109901095a5dSDimitry Andric MapT::iterator end() { return InstantiatedFunctions.end(); }
110001095a5dSDimitry Andric };
110101095a5dSDimitry Andric
110201095a5dSDimitry Andric class SegmentBuilder {
110301095a5dSDimitry Andric std::vector<CoverageSegment> &Segments;
110401095a5dSDimitry Andric SmallVector<const CountedRegion *, 8> ActiveRegions;
110501095a5dSDimitry Andric
SegmentBuilder(std::vector<CoverageSegment> & Segments)110601095a5dSDimitry Andric SegmentBuilder(std::vector<CoverageSegment> &Segments) : Segments(Segments) {}
110701095a5dSDimitry Andric
1108044eb2f6SDimitry Andric /// Emit a segment with the count from \p Region starting at \p StartLoc.
1109044eb2f6SDimitry Andric //
1110044eb2f6SDimitry Andric /// \p IsRegionEntry: The segment is at the start of a new non-gap region.
1111044eb2f6SDimitry Andric /// \p EmitSkippedRegion: The segment must be emitted as a skipped region.
startSegment(const CountedRegion & Region,LineColPair StartLoc,bool IsRegionEntry,bool EmitSkippedRegion=false)1112044eb2f6SDimitry Andric void startSegment(const CountedRegion &Region, LineColPair StartLoc,
1113044eb2f6SDimitry Andric bool IsRegionEntry, bool EmitSkippedRegion = false) {
1114044eb2f6SDimitry Andric bool HasCount = !EmitSkippedRegion &&
1115044eb2f6SDimitry Andric (Region.Kind != CounterMappingRegion::SkippedRegion);
1116044eb2f6SDimitry Andric
1117044eb2f6SDimitry Andric // If the new segment wouldn't affect coverage rendering, skip it.
1118044eb2f6SDimitry Andric if (!Segments.empty() && !IsRegionEntry && !EmitSkippedRegion) {
1119044eb2f6SDimitry Andric const auto &Last = Segments.back();
1120044eb2f6SDimitry Andric if (Last.HasCount == HasCount && Last.Count == Region.ExecutionCount &&
1121044eb2f6SDimitry Andric !Last.IsRegionEntry)
1122044eb2f6SDimitry Andric return;
112301095a5dSDimitry Andric }
112401095a5dSDimitry Andric
1125044eb2f6SDimitry Andric if (HasCount)
1126044eb2f6SDimitry Andric Segments.emplace_back(StartLoc.first, StartLoc.second,
1127044eb2f6SDimitry Andric Region.ExecutionCount, IsRegionEntry,
1128044eb2f6SDimitry Andric Region.Kind == CounterMappingRegion::GapRegion);
112901095a5dSDimitry Andric else
1130044eb2f6SDimitry Andric Segments.emplace_back(StartLoc.first, StartLoc.second, IsRegionEntry);
1131044eb2f6SDimitry Andric
1132eb11fae6SDimitry Andric LLVM_DEBUG({
1133044eb2f6SDimitry Andric const auto &Last = Segments.back();
1134044eb2f6SDimitry Andric dbgs() << "Segment at " << Last.Line << ":" << Last.Col
1135044eb2f6SDimitry Andric << " (count = " << Last.Count << ")"
1136044eb2f6SDimitry Andric << (Last.IsRegionEntry ? ", RegionEntry" : "")
1137044eb2f6SDimitry Andric << (!Last.HasCount ? ", Skipped" : "")
1138044eb2f6SDimitry Andric << (Last.IsGapRegion ? ", Gap" : "") << "\n";
1139044eb2f6SDimitry Andric });
1140044eb2f6SDimitry Andric }
1141044eb2f6SDimitry Andric
1142044eb2f6SDimitry Andric /// Emit segments for active regions which end before \p Loc.
1143044eb2f6SDimitry Andric ///
1144e3b55780SDimitry Andric /// \p Loc: The start location of the next region. If std::nullopt, all active
1145044eb2f6SDimitry Andric /// regions are completed.
1146044eb2f6SDimitry Andric /// \p FirstCompletedRegion: Index of the first completed region.
completeRegionsUntil(std::optional<LineColPair> Loc,unsigned FirstCompletedRegion)1147e3b55780SDimitry Andric void completeRegionsUntil(std::optional<LineColPair> Loc,
1148044eb2f6SDimitry Andric unsigned FirstCompletedRegion) {
1149044eb2f6SDimitry Andric // Sort the completed regions by end location. This makes it simple to
1150044eb2f6SDimitry Andric // emit closing segments in sorted order.
1151044eb2f6SDimitry Andric auto CompletedRegionsIt = ActiveRegions.begin() + FirstCompletedRegion;
1152044eb2f6SDimitry Andric std::stable_sort(CompletedRegionsIt, ActiveRegions.end(),
1153044eb2f6SDimitry Andric [](const CountedRegion *L, const CountedRegion *R) {
1154044eb2f6SDimitry Andric return L->endLoc() < R->endLoc();
1155044eb2f6SDimitry Andric });
1156044eb2f6SDimitry Andric
1157044eb2f6SDimitry Andric // Emit segments for all completed regions.
1158044eb2f6SDimitry Andric for (unsigned I = FirstCompletedRegion + 1, E = ActiveRegions.size(); I < E;
1159044eb2f6SDimitry Andric ++I) {
1160044eb2f6SDimitry Andric const auto *CompletedRegion = ActiveRegions[I];
1161044eb2f6SDimitry Andric assert((!Loc || CompletedRegion->endLoc() <= *Loc) &&
1162044eb2f6SDimitry Andric "Completed region ends after start of new region");
1163044eb2f6SDimitry Andric
1164044eb2f6SDimitry Andric const auto *PrevCompletedRegion = ActiveRegions[I - 1];
1165044eb2f6SDimitry Andric auto CompletedSegmentLoc = PrevCompletedRegion->endLoc();
1166044eb2f6SDimitry Andric
1167044eb2f6SDimitry Andric // Don't emit any more segments if they start where the new region begins.
1168044eb2f6SDimitry Andric if (Loc && CompletedSegmentLoc == *Loc)
1169044eb2f6SDimitry Andric break;
1170044eb2f6SDimitry Andric
1171044eb2f6SDimitry Andric // Don't emit a segment if the next completed region ends at the same
1172044eb2f6SDimitry Andric // location as this one.
1173044eb2f6SDimitry Andric if (CompletedSegmentLoc == CompletedRegion->endLoc())
1174044eb2f6SDimitry Andric continue;
1175044eb2f6SDimitry Andric
1176044eb2f6SDimitry Andric // Use the count from the last completed region which ends at this loc.
1177044eb2f6SDimitry Andric for (unsigned J = I + 1; J < E; ++J)
1178044eb2f6SDimitry Andric if (CompletedRegion->endLoc() == ActiveRegions[J]->endLoc())
1179044eb2f6SDimitry Andric CompletedRegion = ActiveRegions[J];
1180044eb2f6SDimitry Andric
1181044eb2f6SDimitry Andric startSegment(*CompletedRegion, CompletedSegmentLoc, false);
1182044eb2f6SDimitry Andric }
1183044eb2f6SDimitry Andric
1184044eb2f6SDimitry Andric auto Last = ActiveRegions.back();
1185044eb2f6SDimitry Andric if (FirstCompletedRegion && Last->endLoc() != *Loc) {
1186044eb2f6SDimitry Andric // If there's a gap after the end of the last completed region and the
1187044eb2f6SDimitry Andric // start of the new region, use the last active region to fill the gap.
1188044eb2f6SDimitry Andric startSegment(*ActiveRegions[FirstCompletedRegion - 1], Last->endLoc(),
1189044eb2f6SDimitry Andric false);
1190044eb2f6SDimitry Andric } else if (!FirstCompletedRegion && (!Loc || *Loc != Last->endLoc())) {
1191044eb2f6SDimitry Andric // Emit a skipped segment if there are no more active regions. This
1192044eb2f6SDimitry Andric // ensures that gaps between functions are marked correctly.
1193044eb2f6SDimitry Andric startSegment(*Last, Last->endLoc(), false, true);
1194044eb2f6SDimitry Andric }
1195044eb2f6SDimitry Andric
1196044eb2f6SDimitry Andric // Pop the completed regions.
1197044eb2f6SDimitry Andric ActiveRegions.erase(CompletedRegionsIt, ActiveRegions.end());
119801095a5dSDimitry Andric }
119901095a5dSDimitry Andric
buildSegmentsImpl(ArrayRef<CountedRegion> Regions)120001095a5dSDimitry Andric void buildSegmentsImpl(ArrayRef<CountedRegion> Regions) {
1201044eb2f6SDimitry Andric for (const auto &CR : enumerate(Regions)) {
1202044eb2f6SDimitry Andric auto CurStartLoc = CR.value().startLoc();
1203044eb2f6SDimitry Andric
1204044eb2f6SDimitry Andric // Active regions which end before the current region need to be popped.
1205044eb2f6SDimitry Andric auto CompletedRegions =
1206044eb2f6SDimitry Andric std::stable_partition(ActiveRegions.begin(), ActiveRegions.end(),
1207044eb2f6SDimitry Andric [&](const CountedRegion *Region) {
1208044eb2f6SDimitry Andric return !(Region->endLoc() <= CurStartLoc);
1209044eb2f6SDimitry Andric });
1210044eb2f6SDimitry Andric if (CompletedRegions != ActiveRegions.end()) {
1211044eb2f6SDimitry Andric unsigned FirstCompletedRegion =
1212044eb2f6SDimitry Andric std::distance(ActiveRegions.begin(), CompletedRegions);
1213044eb2f6SDimitry Andric completeRegionsUntil(CurStartLoc, FirstCompletedRegion);
121401095a5dSDimitry Andric }
1215044eb2f6SDimitry Andric
1216044eb2f6SDimitry Andric bool GapRegion = CR.value().Kind == CounterMappingRegion::GapRegion;
1217044eb2f6SDimitry Andric
1218044eb2f6SDimitry Andric // Try to emit a segment for the current region.
1219044eb2f6SDimitry Andric if (CurStartLoc == CR.value().endLoc()) {
1220044eb2f6SDimitry Andric // Avoid making zero-length regions active. If it's the last region,
1221044eb2f6SDimitry Andric // emit a skipped segment. Otherwise use its predecessor's count.
1222b60736ecSDimitry Andric const bool Skipped =
1223b60736ecSDimitry Andric (CR.index() + 1) == Regions.size() ||
1224b60736ecSDimitry Andric CR.value().Kind == CounterMappingRegion::SkippedRegion;
1225044eb2f6SDimitry Andric startSegment(ActiveRegions.empty() ? CR.value() : *ActiveRegions.back(),
1226044eb2f6SDimitry Andric CurStartLoc, !GapRegion, Skipped);
1227b60736ecSDimitry Andric // If it is skipped segment, create a segment with last pushed
1228b60736ecSDimitry Andric // regions's count at CurStartLoc.
1229b60736ecSDimitry Andric if (Skipped && !ActiveRegions.empty())
1230b60736ecSDimitry Andric startSegment(*ActiveRegions.back(), CurStartLoc, false);
1231044eb2f6SDimitry Andric continue;
1232044eb2f6SDimitry Andric }
1233044eb2f6SDimitry Andric if (CR.index() + 1 == Regions.size() ||
1234044eb2f6SDimitry Andric CurStartLoc != Regions[CR.index() + 1].startLoc()) {
1235044eb2f6SDimitry Andric // Emit a segment if the next region doesn't start at the same location
1236044eb2f6SDimitry Andric // as this one.
1237044eb2f6SDimitry Andric startSegment(CR.value(), CurStartLoc, !GapRegion);
1238044eb2f6SDimitry Andric }
1239044eb2f6SDimitry Andric
1240044eb2f6SDimitry Andric // This region is active (i.e not completed).
1241044eb2f6SDimitry Andric ActiveRegions.push_back(&CR.value());
1242044eb2f6SDimitry Andric }
1243044eb2f6SDimitry Andric
1244044eb2f6SDimitry Andric // Complete any remaining active regions.
1245044eb2f6SDimitry Andric if (!ActiveRegions.empty())
1246e3b55780SDimitry Andric completeRegionsUntil(std::nullopt, 0);
124701095a5dSDimitry Andric }
124801095a5dSDimitry Andric
124901095a5dSDimitry Andric /// Sort a nested sequence of regions from a single file.
sortNestedRegions(MutableArrayRef<CountedRegion> Regions)125001095a5dSDimitry Andric static void sortNestedRegions(MutableArrayRef<CountedRegion> Regions) {
1251d8e91e46SDimitry Andric llvm::sort(Regions, [](const CountedRegion &LHS, const CountedRegion &RHS) {
125201095a5dSDimitry Andric if (LHS.startLoc() != RHS.startLoc())
125301095a5dSDimitry Andric return LHS.startLoc() < RHS.startLoc();
125401095a5dSDimitry Andric if (LHS.endLoc() != RHS.endLoc())
125501095a5dSDimitry Andric // When LHS completely contains RHS, we sort LHS first.
125601095a5dSDimitry Andric return RHS.endLoc() < LHS.endLoc();
125701095a5dSDimitry Andric // If LHS and RHS cover the same area, we need to sort them according
125801095a5dSDimitry Andric // to their kinds so that the most suitable region will become "active"
125901095a5dSDimitry Andric // in combineRegions(). Because we accumulate counter values only from
126001095a5dSDimitry Andric // regions of the same kind as the first region of the area, prefer
126101095a5dSDimitry Andric // CodeRegion to ExpansionRegion and ExpansionRegion to SkippedRegion.
126271d5a254SDimitry Andric static_assert(CounterMappingRegion::CodeRegion <
126371d5a254SDimitry Andric CounterMappingRegion::ExpansionRegion &&
126471d5a254SDimitry Andric CounterMappingRegion::ExpansionRegion <
126571d5a254SDimitry Andric CounterMappingRegion::SkippedRegion,
126601095a5dSDimitry Andric "Unexpected order of region kind values");
126701095a5dSDimitry Andric return LHS.Kind < RHS.Kind;
126801095a5dSDimitry Andric });
126901095a5dSDimitry Andric }
127001095a5dSDimitry Andric
127101095a5dSDimitry Andric /// Combine counts of regions which cover the same area.
127201095a5dSDimitry Andric static ArrayRef<CountedRegion>
combineRegions(MutableArrayRef<CountedRegion> Regions)127301095a5dSDimitry Andric combineRegions(MutableArrayRef<CountedRegion> Regions) {
127401095a5dSDimitry Andric if (Regions.empty())
127501095a5dSDimitry Andric return Regions;
127601095a5dSDimitry Andric auto Active = Regions.begin();
127701095a5dSDimitry Andric auto End = Regions.end();
127801095a5dSDimitry Andric for (auto I = Regions.begin() + 1; I != End; ++I) {
127901095a5dSDimitry Andric if (Active->startLoc() != I->startLoc() ||
128001095a5dSDimitry Andric Active->endLoc() != I->endLoc()) {
128101095a5dSDimitry Andric // Shift to the next region.
128201095a5dSDimitry Andric ++Active;
128301095a5dSDimitry Andric if (Active != I)
128401095a5dSDimitry Andric *Active = *I;
128501095a5dSDimitry Andric continue;
128601095a5dSDimitry Andric }
128701095a5dSDimitry Andric // Merge duplicate region.
128801095a5dSDimitry Andric // If CodeRegions and ExpansionRegions cover the same area, it's probably
128901095a5dSDimitry Andric // a macro which is fully expanded to another macro. In that case, we need
129001095a5dSDimitry Andric // to accumulate counts only from CodeRegions, or else the area will be
129101095a5dSDimitry Andric // counted twice.
129201095a5dSDimitry Andric // On the other hand, a macro may have a nested macro in its body. If the
129301095a5dSDimitry Andric // outer macro is used several times, the ExpansionRegion for the nested
129401095a5dSDimitry Andric // macro will also be added several times. These ExpansionRegions cover
129501095a5dSDimitry Andric // the same source locations and have to be combined to reach the correct
129601095a5dSDimitry Andric // value for that area.
129701095a5dSDimitry Andric // We add counts of the regions of the same kind as the active region
129801095a5dSDimitry Andric // to handle the both situations.
1299ac9a064cSDimitry Andric if (I->Kind == Active->Kind) {
1300ac9a064cSDimitry Andric assert(I->HasSingleByteCoverage == Active->HasSingleByteCoverage &&
1301ac9a064cSDimitry Andric "Regions are generated in different coverage modes");
1302ac9a064cSDimitry Andric if (I->HasSingleByteCoverage)
1303ac9a064cSDimitry Andric Active->ExecutionCount = Active->ExecutionCount || I->ExecutionCount;
1304ac9a064cSDimitry Andric else
130501095a5dSDimitry Andric Active->ExecutionCount += I->ExecutionCount;
130601095a5dSDimitry Andric }
1307ac9a064cSDimitry Andric }
130801095a5dSDimitry Andric return Regions.drop_back(std::distance(++Active, End));
130901095a5dSDimitry Andric }
131001095a5dSDimitry Andric
131101095a5dSDimitry Andric public:
1312044eb2f6SDimitry Andric /// Build a sorted list of CoverageSegments from a list of Regions.
131301095a5dSDimitry Andric static std::vector<CoverageSegment>
buildSegments(MutableArrayRef<CountedRegion> Regions)131401095a5dSDimitry Andric buildSegments(MutableArrayRef<CountedRegion> Regions) {
131501095a5dSDimitry Andric std::vector<CoverageSegment> Segments;
131601095a5dSDimitry Andric SegmentBuilder Builder(Segments);
131701095a5dSDimitry Andric
131801095a5dSDimitry Andric sortNestedRegions(Regions);
131901095a5dSDimitry Andric ArrayRef<CountedRegion> CombinedRegions = combineRegions(Regions);
132001095a5dSDimitry Andric
1321eb11fae6SDimitry Andric LLVM_DEBUG({
1322044eb2f6SDimitry Andric dbgs() << "Combined regions:\n";
1323044eb2f6SDimitry Andric for (const auto &CR : CombinedRegions)
1324044eb2f6SDimitry Andric dbgs() << " " << CR.LineStart << ":" << CR.ColumnStart << " -> "
1325044eb2f6SDimitry Andric << CR.LineEnd << ":" << CR.ColumnEnd
1326044eb2f6SDimitry Andric << " (count=" << CR.ExecutionCount << ")\n";
1327044eb2f6SDimitry Andric });
1328044eb2f6SDimitry Andric
132901095a5dSDimitry Andric Builder.buildSegmentsImpl(CombinedRegions);
1330044eb2f6SDimitry Andric
1331044eb2f6SDimitry Andric #ifndef NDEBUG
1332044eb2f6SDimitry Andric for (unsigned I = 1, E = Segments.size(); I < E; ++I) {
1333044eb2f6SDimitry Andric const auto &L = Segments[I - 1];
1334044eb2f6SDimitry Andric const auto &R = Segments[I];
1335044eb2f6SDimitry Andric if (!(L.Line < R.Line) && !(L.Line == R.Line && L.Col < R.Col)) {
1336b60736ecSDimitry Andric if (L.Line == R.Line && L.Col == R.Col && !L.HasCount)
1337b60736ecSDimitry Andric continue;
1338eb11fae6SDimitry Andric LLVM_DEBUG(dbgs() << " ! Segment " << L.Line << ":" << L.Col
1339044eb2f6SDimitry Andric << " followed by " << R.Line << ":" << R.Col << "\n");
1340044eb2f6SDimitry Andric assert(false && "Coverage segments not unique or sorted");
1341044eb2f6SDimitry Andric }
1342044eb2f6SDimitry Andric }
1343044eb2f6SDimitry Andric #endif
1344044eb2f6SDimitry Andric
134501095a5dSDimitry Andric return Segments;
134601095a5dSDimitry Andric }
134701095a5dSDimitry Andric };
134871d5a254SDimitry Andric
134971d5a254SDimitry Andric } // end anonymous namespace
135001095a5dSDimitry Andric
getUniqueSourceFiles() const135101095a5dSDimitry Andric std::vector<StringRef> CoverageMapping::getUniqueSourceFiles() const {
135201095a5dSDimitry Andric std::vector<StringRef> Filenames;
135301095a5dSDimitry Andric for (const auto &Function : getCoveredFunctions())
1354b60736ecSDimitry Andric llvm::append_range(Filenames, Function.Filenames);
1355d8e91e46SDimitry Andric llvm::sort(Filenames);
1356ac9a064cSDimitry Andric auto Last = llvm::unique(Filenames);
135701095a5dSDimitry Andric Filenames.erase(Last, Filenames.end());
135801095a5dSDimitry Andric return Filenames;
135901095a5dSDimitry Andric }
136001095a5dSDimitry Andric
gatherFileIDs(StringRef SourceFile,const FunctionRecord & Function)136101095a5dSDimitry Andric static SmallBitVector gatherFileIDs(StringRef SourceFile,
136201095a5dSDimitry Andric const FunctionRecord &Function) {
136301095a5dSDimitry Andric SmallBitVector FilenameEquivalence(Function.Filenames.size(), false);
136401095a5dSDimitry Andric for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I)
136501095a5dSDimitry Andric if (SourceFile == Function.Filenames[I])
136601095a5dSDimitry Andric FilenameEquivalence[I] = true;
136701095a5dSDimitry Andric return FilenameEquivalence;
136801095a5dSDimitry Andric }
136901095a5dSDimitry Andric
137001095a5dSDimitry Andric /// Return the ID of the file where the definition of the function is located.
1371e3b55780SDimitry Andric static std::optional<unsigned>
findMainViewFileID(const FunctionRecord & Function)1372e3b55780SDimitry Andric findMainViewFileID(const FunctionRecord &Function) {
137301095a5dSDimitry Andric SmallBitVector IsNotExpandedFile(Function.Filenames.size(), true);
137401095a5dSDimitry Andric for (const auto &CR : Function.CountedRegions)
137501095a5dSDimitry Andric if (CR.Kind == CounterMappingRegion::ExpansionRegion)
137601095a5dSDimitry Andric IsNotExpandedFile[CR.ExpandedFileID] = false;
137701095a5dSDimitry Andric int I = IsNotExpandedFile.find_first();
137801095a5dSDimitry Andric if (I == -1)
1379e3b55780SDimitry Andric return std::nullopt;
138001095a5dSDimitry Andric return I;
138101095a5dSDimitry Andric }
138201095a5dSDimitry Andric
138301095a5dSDimitry Andric /// Check if SourceFile is the file that contains the definition of
1384e3b55780SDimitry Andric /// the Function. Return the ID of the file in that case or std::nullopt
1385e3b55780SDimitry Andric /// otherwise.
1386e3b55780SDimitry Andric static std::optional<unsigned>
findMainViewFileID(StringRef SourceFile,const FunctionRecord & Function)1387e3b55780SDimitry Andric findMainViewFileID(StringRef SourceFile, const FunctionRecord &Function) {
1388e3b55780SDimitry Andric std::optional<unsigned> I = findMainViewFileID(Function);
138901095a5dSDimitry Andric if (I && SourceFile == Function.Filenames[*I])
139001095a5dSDimitry Andric return I;
1391e3b55780SDimitry Andric return std::nullopt;
139201095a5dSDimitry Andric }
139301095a5dSDimitry Andric
isExpansion(const CountedRegion & R,unsigned FileID)139401095a5dSDimitry Andric static bool isExpansion(const CountedRegion &R, unsigned FileID) {
139501095a5dSDimitry Andric return R.Kind == CounterMappingRegion::ExpansionRegion && R.FileID == FileID;
139601095a5dSDimitry Andric }
139701095a5dSDimitry Andric
getCoverageForFile(StringRef Filename) const139801095a5dSDimitry Andric CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
139901095a5dSDimitry Andric CoverageData FileCoverage(Filename);
140071d5a254SDimitry Andric std::vector<CountedRegion> Regions;
140101095a5dSDimitry Andric
14021d5ae102SDimitry Andric // Look up the function records in the given file. Due to hash collisions on
14031d5ae102SDimitry Andric // the filename, we may get back some records that are not in the file.
14041d5ae102SDimitry Andric ArrayRef<unsigned> RecordIndices =
14051d5ae102SDimitry Andric getImpreciseRecordIndicesForFilename(Filename);
14061d5ae102SDimitry Andric for (unsigned RecordIndex : RecordIndices) {
14071d5ae102SDimitry Andric const FunctionRecord &Function = Functions[RecordIndex];
140801095a5dSDimitry Andric auto MainFileID = findMainViewFileID(Filename, Function);
140901095a5dSDimitry Andric auto FileIDs = gatherFileIDs(Filename, Function);
141001095a5dSDimitry Andric for (const auto &CR : Function.CountedRegions)
141101095a5dSDimitry Andric if (FileIDs.test(CR.FileID)) {
141201095a5dSDimitry Andric Regions.push_back(CR);
141301095a5dSDimitry Andric if (MainFileID && isExpansion(CR, *MainFileID))
141401095a5dSDimitry Andric FileCoverage.Expansions.emplace_back(CR, Function);
141501095a5dSDimitry Andric }
1416b60736ecSDimitry Andric // Capture branch regions specific to the function (excluding expansions).
1417b60736ecSDimitry Andric for (const auto &CR : Function.CountedBranchRegions)
1418b60736ecSDimitry Andric if (FileIDs.test(CR.FileID) && (CR.FileID == CR.ExpandedFileID))
1419b60736ecSDimitry Andric FileCoverage.BranchRegions.push_back(CR);
1420312c0ed1SDimitry Andric // Capture MCDC records specific to the function.
1421312c0ed1SDimitry Andric for (const auto &MR : Function.MCDCRecords)
1422312c0ed1SDimitry Andric if (FileIDs.test(MR.getDecisionRegion().FileID))
1423312c0ed1SDimitry Andric FileCoverage.MCDCRecords.push_back(MR);
142401095a5dSDimitry Andric }
142501095a5dSDimitry Andric
1426eb11fae6SDimitry Andric LLVM_DEBUG(dbgs() << "Emitting segments for file: " << Filename << "\n");
142701095a5dSDimitry Andric FileCoverage.Segments = SegmentBuilder::buildSegments(Regions);
142801095a5dSDimitry Andric
142901095a5dSDimitry Andric return FileCoverage;
143001095a5dSDimitry Andric }
143101095a5dSDimitry Andric
1432044eb2f6SDimitry Andric std::vector<InstantiationGroup>
getInstantiationGroups(StringRef Filename) const1433044eb2f6SDimitry Andric CoverageMapping::getInstantiationGroups(StringRef Filename) const {
143401095a5dSDimitry Andric FunctionInstantiationSetCollector InstantiationSetCollector;
14351d5ae102SDimitry Andric // Look up the function records in the given file. Due to hash collisions on
14361d5ae102SDimitry Andric // the filename, we may get back some records that are not in the file.
14371d5ae102SDimitry Andric ArrayRef<unsigned> RecordIndices =
14381d5ae102SDimitry Andric getImpreciseRecordIndicesForFilename(Filename);
14391d5ae102SDimitry Andric for (unsigned RecordIndex : RecordIndices) {
14401d5ae102SDimitry Andric const FunctionRecord &Function = Functions[RecordIndex];
144101095a5dSDimitry Andric auto MainFileID = findMainViewFileID(Filename, Function);
144201095a5dSDimitry Andric if (!MainFileID)
144301095a5dSDimitry Andric continue;
144401095a5dSDimitry Andric InstantiationSetCollector.insert(Function, *MainFileID);
144501095a5dSDimitry Andric }
144601095a5dSDimitry Andric
1447044eb2f6SDimitry Andric std::vector<InstantiationGroup> Result;
1448b2b7c066SDimitry Andric for (auto &InstantiationSet : InstantiationSetCollector) {
1449044eb2f6SDimitry Andric InstantiationGroup IG{InstantiationSet.first.first,
1450044eb2f6SDimitry Andric InstantiationSet.first.second,
1451044eb2f6SDimitry Andric std::move(InstantiationSet.second)};
1452044eb2f6SDimitry Andric Result.emplace_back(std::move(IG));
145301095a5dSDimitry Andric }
145401095a5dSDimitry Andric return Result;
145501095a5dSDimitry Andric }
145601095a5dSDimitry Andric
145701095a5dSDimitry Andric CoverageData
getCoverageForFunction(const FunctionRecord & Function) const145801095a5dSDimitry Andric CoverageMapping::getCoverageForFunction(const FunctionRecord &Function) const {
145901095a5dSDimitry Andric auto MainFileID = findMainViewFileID(Function);
146001095a5dSDimitry Andric if (!MainFileID)
146101095a5dSDimitry Andric return CoverageData();
146201095a5dSDimitry Andric
146301095a5dSDimitry Andric CoverageData FunctionCoverage(Function.Filenames[*MainFileID]);
146471d5a254SDimitry Andric std::vector<CountedRegion> Regions;
146501095a5dSDimitry Andric for (const auto &CR : Function.CountedRegions)
146601095a5dSDimitry Andric if (CR.FileID == *MainFileID) {
146701095a5dSDimitry Andric Regions.push_back(CR);
146801095a5dSDimitry Andric if (isExpansion(CR, *MainFileID))
146901095a5dSDimitry Andric FunctionCoverage.Expansions.emplace_back(CR, Function);
147001095a5dSDimitry Andric }
1471b60736ecSDimitry Andric // Capture branch regions specific to the function (excluding expansions).
1472b60736ecSDimitry Andric for (const auto &CR : Function.CountedBranchRegions)
1473b60736ecSDimitry Andric if (CR.FileID == *MainFileID)
1474b60736ecSDimitry Andric FunctionCoverage.BranchRegions.push_back(CR);
147501095a5dSDimitry Andric
1476312c0ed1SDimitry Andric // Capture MCDC records specific to the function.
1477312c0ed1SDimitry Andric for (const auto &MR : Function.MCDCRecords)
1478312c0ed1SDimitry Andric if (MR.getDecisionRegion().FileID == *MainFileID)
1479312c0ed1SDimitry Andric FunctionCoverage.MCDCRecords.push_back(MR);
1480312c0ed1SDimitry Andric
1481eb11fae6SDimitry Andric LLVM_DEBUG(dbgs() << "Emitting segments for function: " << Function.Name
1482eb11fae6SDimitry Andric << "\n");
148301095a5dSDimitry Andric FunctionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
148401095a5dSDimitry Andric
148501095a5dSDimitry Andric return FunctionCoverage;
148601095a5dSDimitry Andric }
148701095a5dSDimitry Andric
getCoverageForExpansion(const ExpansionRecord & Expansion) const148801095a5dSDimitry Andric CoverageData CoverageMapping::getCoverageForExpansion(
148901095a5dSDimitry Andric const ExpansionRecord &Expansion) const {
149001095a5dSDimitry Andric CoverageData ExpansionCoverage(
149101095a5dSDimitry Andric Expansion.Function.Filenames[Expansion.FileID]);
149271d5a254SDimitry Andric std::vector<CountedRegion> Regions;
149301095a5dSDimitry Andric for (const auto &CR : Expansion.Function.CountedRegions)
149401095a5dSDimitry Andric if (CR.FileID == Expansion.FileID) {
149501095a5dSDimitry Andric Regions.push_back(CR);
149601095a5dSDimitry Andric if (isExpansion(CR, Expansion.FileID))
149701095a5dSDimitry Andric ExpansionCoverage.Expansions.emplace_back(CR, Expansion.Function);
149801095a5dSDimitry Andric }
1499b60736ecSDimitry Andric for (const auto &CR : Expansion.Function.CountedBranchRegions)
1500b60736ecSDimitry Andric // Capture branch regions that only pertain to the corresponding expansion.
1501b60736ecSDimitry Andric if (CR.FileID == Expansion.FileID)
1502b60736ecSDimitry Andric ExpansionCoverage.BranchRegions.push_back(CR);
150301095a5dSDimitry Andric
1504eb11fae6SDimitry Andric LLVM_DEBUG(dbgs() << "Emitting segments for expansion of file "
1505eb11fae6SDimitry Andric << Expansion.FileID << "\n");
150601095a5dSDimitry Andric ExpansionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
150701095a5dSDimitry Andric
150801095a5dSDimitry Andric return ExpansionCoverage;
150901095a5dSDimitry Andric }
151001095a5dSDimitry Andric
LineCoverageStats(ArrayRef<const CoverageSegment * > LineSegments,const CoverageSegment * WrappedSegment,unsigned Line)1511044eb2f6SDimitry Andric LineCoverageStats::LineCoverageStats(
1512044eb2f6SDimitry Andric ArrayRef<const CoverageSegment *> LineSegments,
1513044eb2f6SDimitry Andric const CoverageSegment *WrappedSegment, unsigned Line)
1514044eb2f6SDimitry Andric : ExecutionCount(0), HasMultipleRegions(false), Mapped(false), Line(Line),
1515044eb2f6SDimitry Andric LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
1516044eb2f6SDimitry Andric // Find the minimum number of regions which start in this line.
1517044eb2f6SDimitry Andric unsigned MinRegionCount = 0;
1518044eb2f6SDimitry Andric auto isStartOfRegion = [](const CoverageSegment *S) {
1519044eb2f6SDimitry Andric return !S->IsGapRegion && S->HasCount && S->IsRegionEntry;
1520044eb2f6SDimitry Andric };
1521044eb2f6SDimitry Andric for (unsigned I = 0; I < LineSegments.size() && MinRegionCount < 2; ++I)
1522044eb2f6SDimitry Andric if (isStartOfRegion(LineSegments[I]))
1523044eb2f6SDimitry Andric ++MinRegionCount;
1524044eb2f6SDimitry Andric
1525044eb2f6SDimitry Andric bool StartOfSkippedRegion = !LineSegments.empty() &&
1526044eb2f6SDimitry Andric !LineSegments.front()->HasCount &&
1527044eb2f6SDimitry Andric LineSegments.front()->IsRegionEntry;
1528044eb2f6SDimitry Andric
1529044eb2f6SDimitry Andric HasMultipleRegions = MinRegionCount > 1;
1530044eb2f6SDimitry Andric Mapped =
1531044eb2f6SDimitry Andric !StartOfSkippedRegion &&
1532044eb2f6SDimitry Andric ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0));
1533044eb2f6SDimitry Andric
15344df029ccSDimitry Andric // if there is any starting segment at this line with a counter, it must be
15354df029ccSDimitry Andric // mapped
15364df029ccSDimitry Andric Mapped |= std::any_of(
15374df029ccSDimitry Andric LineSegments.begin(), LineSegments.end(),
15384df029ccSDimitry Andric [](const auto *Seq) { return Seq->IsRegionEntry && Seq->HasCount; });
15394df029ccSDimitry Andric
15404df029ccSDimitry Andric if (!Mapped) {
1541044eb2f6SDimitry Andric return;
15424df029ccSDimitry Andric }
1543044eb2f6SDimitry Andric
1544044eb2f6SDimitry Andric // Pick the max count from the non-gap, region entry segments and the
1545044eb2f6SDimitry Andric // wrapped count.
1546044eb2f6SDimitry Andric if (WrappedSegment)
1547044eb2f6SDimitry Andric ExecutionCount = WrappedSegment->Count;
1548044eb2f6SDimitry Andric if (!MinRegionCount)
1549044eb2f6SDimitry Andric return;
1550044eb2f6SDimitry Andric for (const auto *LS : LineSegments)
1551044eb2f6SDimitry Andric if (isStartOfRegion(LS))
1552044eb2f6SDimitry Andric ExecutionCount = std::max(ExecutionCount, LS->Count);
1553044eb2f6SDimitry Andric }
1554044eb2f6SDimitry Andric
operator ++()1555044eb2f6SDimitry Andric LineCoverageIterator &LineCoverageIterator::operator++() {
1556044eb2f6SDimitry Andric if (Next == CD.end()) {
1557044eb2f6SDimitry Andric Stats = LineCoverageStats();
1558044eb2f6SDimitry Andric Ended = true;
1559044eb2f6SDimitry Andric return *this;
1560044eb2f6SDimitry Andric }
1561044eb2f6SDimitry Andric if (Segments.size())
1562044eb2f6SDimitry Andric WrappedSegment = Segments.back();
1563044eb2f6SDimitry Andric Segments.clear();
1564044eb2f6SDimitry Andric while (Next != CD.end() && Next->Line == Line)
1565044eb2f6SDimitry Andric Segments.push_back(&*Next++);
1566044eb2f6SDimitry Andric Stats = LineCoverageStats(Segments, WrappedSegment, Line);
1567044eb2f6SDimitry Andric ++Line;
1568044eb2f6SDimitry Andric return *this;
1569044eb2f6SDimitry Andric }
1570044eb2f6SDimitry Andric
getCoverageMapErrString(coveragemap_error Err,const std::string & ErrMsg="")1571b1c73532SDimitry Andric static std::string getCoverageMapErrString(coveragemap_error Err,
1572b1c73532SDimitry Andric const std::string &ErrMsg = "") {
1573b1c73532SDimitry Andric std::string Msg;
1574b1c73532SDimitry Andric raw_string_ostream OS(Msg);
1575b1c73532SDimitry Andric
157601095a5dSDimitry Andric switch (Err) {
157701095a5dSDimitry Andric case coveragemap_error::success:
1578b1c73532SDimitry Andric OS << "success";
1579b1c73532SDimitry Andric break;
158001095a5dSDimitry Andric case coveragemap_error::eof:
1581b1c73532SDimitry Andric OS << "end of File";
1582b1c73532SDimitry Andric break;
158301095a5dSDimitry Andric case coveragemap_error::no_data_found:
1584b1c73532SDimitry Andric OS << "no coverage data found";
1585b1c73532SDimitry Andric break;
158601095a5dSDimitry Andric case coveragemap_error::unsupported_version:
1587b1c73532SDimitry Andric OS << "unsupported coverage format version";
1588b1c73532SDimitry Andric break;
158901095a5dSDimitry Andric case coveragemap_error::truncated:
1590b1c73532SDimitry Andric OS << "truncated coverage data";
1591b1c73532SDimitry Andric break;
159201095a5dSDimitry Andric case coveragemap_error::malformed:
1593b1c73532SDimitry Andric OS << "malformed coverage data";
1594b1c73532SDimitry Andric break;
1595cfca06d7SDimitry Andric case coveragemap_error::decompression_failed:
1596b1c73532SDimitry Andric OS << "failed to decompress coverage data (zlib)";
1597b1c73532SDimitry Andric break;
1598b60736ecSDimitry Andric case coveragemap_error::invalid_or_missing_arch_specifier:
1599b1c73532SDimitry Andric OS << "`-arch` specifier is invalid or missing for universal binary";
1600b1c73532SDimitry Andric break;
160101095a5dSDimitry Andric }
1602b1c73532SDimitry Andric
1603b1c73532SDimitry Andric // If optional error message is not empty, append it to the message.
1604b1c73532SDimitry Andric if (!ErrMsg.empty())
1605b1c73532SDimitry Andric OS << ": " << ErrMsg;
1606b1c73532SDimitry Andric
1607b1c73532SDimitry Andric return Msg;
160801095a5dSDimitry Andric }
160901095a5dSDimitry Andric
161071d5a254SDimitry Andric namespace {
161171d5a254SDimitry Andric
161201095a5dSDimitry Andric // FIXME: This class is only here to support the transition to llvm::Error. It
161301095a5dSDimitry Andric // will be removed once this transition is complete. Clients should prefer to
161401095a5dSDimitry Andric // deal with the Error value directly, rather than converting to error_code.
161501095a5dSDimitry Andric class CoverageMappingErrorCategoryType : public std::error_category {
name() const1616b915e9e0SDimitry Andric const char *name() const noexcept override { return "llvm.coveragemap"; }
message(int IE) const161701095a5dSDimitry Andric std::string message(int IE) const override {
161801095a5dSDimitry Andric return getCoverageMapErrString(static_cast<coveragemap_error>(IE));
161901095a5dSDimitry Andric }
162001095a5dSDimitry Andric };
162171d5a254SDimitry Andric
162201095a5dSDimitry Andric } // end anonymous namespace
162301095a5dSDimitry Andric
message() const162401095a5dSDimitry Andric std::string CoverageMapError::message() const {
1625b1c73532SDimitry Andric return getCoverageMapErrString(Err, Msg);
162601095a5dSDimitry Andric }
162701095a5dSDimitry Andric
coveragemap_category()162801095a5dSDimitry Andric const std::error_category &llvm::coverage::coveragemap_category() {
16291f917f69SDimitry Andric static CoverageMappingErrorCategoryType ErrorCategory;
16301f917f69SDimitry Andric return ErrorCategory;
163101095a5dSDimitry Andric }
163201095a5dSDimitry Andric
163301095a5dSDimitry Andric char CoverageMapError::ID = 0;
1634