xref: /src/contrib/llvm-project/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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