Movatterモバイル変換


[0]ホーム

URL:


LLVM 20.0.0git
CoverageMapping.cpp
Go to the documentation of this file.
1//===- CoverageMapping.cpp - Code coverage mapping support ----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains support for clang's and llvm's instrumentation based
10// code coverage.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/ProfileData/Coverage/CoverageMapping.h"
15#include "llvm/ADT/ArrayRef.h"
16#include "llvm/ADT/DenseMap.h"
17#include "llvm/ADT/STLExtras.h"
18#include "llvm/ADT/SmallBitVector.h"
19#include "llvm/ADT/SmallVector.h"
20#include "llvm/ADT/StringExtras.h"
21#include "llvm/ADT/StringRef.h"
22#include "llvm/Object/BuildID.h"
23#include "llvm/ProfileData/Coverage/CoverageMappingReader.h"
24#include "llvm/ProfileData/InstrProfReader.h"
25#include "llvm/Support/Debug.h"
26#include "llvm/Support/Errc.h"
27#include "llvm/Support/Error.h"
28#include "llvm/Support/ErrorHandling.h"
29#include "llvm/Support/MemoryBuffer.h"
30#include "llvm/Support/VirtualFileSystem.h"
31#include "llvm/Support/raw_ostream.h"
32#include <algorithm>
33#include <cassert>
34#include <cmath>
35#include <cstdint>
36#include <iterator>
37#include <map>
38#include <memory>
39#include <optional>
40#include <stack>
41#include <string>
42#include <system_error>
43#include <utility>
44#include <vector>
45
46using namespacellvm;
47using namespacecoverage;
48
49#define DEBUG_TYPE "coverage-mapping"
50
51Counter CounterExpressionBuilder::get(constCounterExpression &E) {
52auto [It, Inserted] = ExpressionIndices.try_emplace(E, Expressions.size());
53if (Inserted)
54 Expressions.push_back(E);
55returnCounter::getExpression(It->second);
56}
57
58void CounterExpressionBuilder::extractTerms(CounterC,int Factor,
59SmallVectorImpl<Term> &Terms) {
60switch (C.getKind()) {
61caseCounter::Zero:
62break;
63caseCounter::CounterValueReference:
64 Terms.emplace_back(C.getCounterID(), Factor);
65break;
66caseCounter::Expression:
67constauto &E = Expressions[C.getExpressionID()];
68 extractTerms(E.LHS, Factor, Terms);
69 extractTerms(
70 E.RHS, E.Kind ==CounterExpression::Subtract ? -Factor : Factor, Terms);
71break;
72 }
73}
74
75Counter CounterExpressionBuilder::simplify(Counter ExpressionTree) {
76// Gather constant terms.
77SmallVector<Term, 32> Terms;
78 extractTerms(ExpressionTree, +1, Terms);
79
80// If there are no terms, this is just a zero. The algorithm below assumes at
81// least one term.
82if (Terms.size() == 0)
83returnCounter::getZero();
84
85// Group the terms by counter ID.
86llvm::sort(Terms, [](const Term &LHS,const Term &RHS) {
87returnLHS.CounterID <RHS.CounterID;
88 });
89
90// Combine terms by counter ID to eliminate counters that sum to zero.
91auto Prev = Terms.begin();
92for (autoI = Prev + 1, E = Terms.end();I != E; ++I) {
93if (I->CounterID == Prev->CounterID) {
94 Prev->Factor +=I->Factor;
95continue;
96 }
97 ++Prev;
98 *Prev = *I;
99 }
100 Terms.erase(++Prev, Terms.end());
101
102CounterC;
103// Create additions. We do this before subtractions to avoid constructs like
104// ((0 - X) + Y), as opposed to (Y - X).
105for (autoT : Terms) {
106if (T.Factor <= 0)
107continue;
108for (intI = 0;I <T.Factor; ++I)
109if (C.isZero())
110C =Counter::getCounter(T.CounterID);
111else
112C = get(CounterExpression(CounterExpression::Add,C,
113Counter::getCounter(T.CounterID)));
114 }
115
116// Create subtractions.
117for (autoT : Terms) {
118if (T.Factor >= 0)
119continue;
120for (intI = 0;I < -T.Factor; ++I)
121C = get(CounterExpression(CounterExpression::Subtract,C,
122Counter::getCounter(T.CounterID)));
123 }
124returnC;
125}
126
127CounterCounterExpressionBuilder::add(Counter LHS,Counter RHS,bool Simplify) {
128auto Cnt = get(CounterExpression(CounterExpression::Add,LHS,RHS));
129return Simplify ?simplify(Cnt) : Cnt;
130}
131
132CounterCounterExpressionBuilder::subtract(Counter LHS,Counter RHS,
133bool Simplify) {
134auto Cnt = get(CounterExpression(CounterExpression::Subtract,LHS,RHS));
135return Simplify ?simplify(Cnt) : Cnt;
136}
137
138CounterCounterExpressionBuilder::subst(CounterC,constSubstMap &Map) {
139// Replace C with the value found in Map even if C is Expression.
140if (autoI = Map.find(C);I != Map.end())
141returnI->second;
142
143if (!C.isExpression())
144returnC;
145
146auto CE = Expressions[C.getExpressionID()];
147auto NewLHS =subst(CE.LHS, Map);
148auto NewRHS =subst(CE.RHS, Map);
149
150// Reconstruct Expression with induced subexpressions.
151switch (CE.Kind) {
152caseCounterExpression::Add:
153C =add(NewLHS, NewRHS);
154break;
155caseCounterExpression::Subtract:
156C =subtract(NewLHS, NewRHS);
157break;
158 }
159
160returnC;
161}
162
163voidCounterMappingContext::dump(constCounter &C,raw_ostream &OS) const{
164switch (C.getKind()) {
165caseCounter::Zero:
166OS <<'0';
167return;
168caseCounter::CounterValueReference:
169OS <<'#' <<C.getCounterID();
170break;
171caseCounter::Expression: {
172if (C.getExpressionID() >= Expressions.size())
173return;
174constauto &E = Expressions[C.getExpressionID()];
175OS <<'(';
176dump(E.LHS,OS);
177OS << (E.Kind ==CounterExpression::Subtract ?" - " :" + ");
178dump(E.RHS,OS);
179OS <<')';
180break;
181 }
182 }
183if (CounterValues.empty())
184return;
185Expected<int64_t>Value =evaluate(C);
186if (auto E =Value.takeError()) {
187consumeError(std::move(E));
188return;
189 }
190OS <<'[' << *Value <<']';
191}
192
193Expected<int64_t>CounterMappingContext::evaluate(constCounter &C) const{
194structStackElem {
195Counter ICounter;
196 int64_tLHS = 0;
197enum {
198 KNeverVisited = 0,
199 KVisitedOnce = 1,
200 KVisitedTwice = 2,
201 } VisitCount = KNeverVisited;
202 };
203
204 std::stack<StackElem> CounterStack;
205 CounterStack.push({C});
206
207 int64_t LastPoppedValue;
208
209while (!CounterStack.empty()) {
210 StackElem &Current = CounterStack.top();
211
212switch (Current.ICounter.getKind()) {
213caseCounter::Zero:
214 LastPoppedValue = 0;
215 CounterStack.pop();
216break;
217caseCounter::CounterValueReference:
218if (Current.ICounter.getCounterID() >= CounterValues.size())
219returnerrorCodeToError(errc::argument_out_of_domain);
220 LastPoppedValue = CounterValues[Current.ICounter.getCounterID()];
221 CounterStack.pop();
222break;
223caseCounter::Expression: {
224if (Current.ICounter.getExpressionID() >= Expressions.size())
225returnerrorCodeToError(errc::argument_out_of_domain);
226constauto &E = Expressions[Current.ICounter.getExpressionID()];
227if (Current.VisitCount == StackElem::KNeverVisited) {
228 CounterStack.push(StackElem{E.LHS});
229 Current.VisitCount = StackElem::KVisitedOnce;
230 }elseif (Current.VisitCount == StackElem::KVisitedOnce) {
231 Current.LHS = LastPoppedValue;
232 CounterStack.push(StackElem{E.RHS});
233 Current.VisitCount = StackElem::KVisitedTwice;
234 }else {
235 int64_tLHS = Current.LHS;
236 int64_tRHS = LastPoppedValue;
237 LastPoppedValue =
238 E.Kind ==CounterExpression::Subtract ?LHS -RHS :LHS +RHS;
239 CounterStack.pop();
240 }
241break;
242 }
243 }
244 }
245
246return LastPoppedValue;
247}
248
249// Find an independence pair for each condition:
250// - The condition is true in one test and false in the other.
251// - The decision outcome is true one test and false in the other.
252// - All other conditions' values must be equal or marked as "don't care".
253voidMCDCRecord::findIndependencePairs() {
254if (IndependencePairs)
255return;
256
257 IndependencePairs.emplace();
258
259unsigned NumTVs = TV.size();
260// Will be replaced to shorter expr.
261unsigned TVTrueIdx = std::distance(
262 TV.begin(),
263 std::find_if(TV.begin(), TV.end(),
264 [&](autoI) { return (I.second == MCDCRecord::MCDC_True); })
265
266 );
267for (unsignedI = TVTrueIdx;I < NumTVs; ++I) {
268constauto &[A, ACond] = TV[I];
269assert(ACond ==MCDCRecord::MCDC_True);
270for (unsigned J = 0; J < TVTrueIdx; ++J) {
271constauto &[B, BCond] = TV[J];
272assert(BCond ==MCDCRecord::MCDC_False);
273// If the two vectors differ in exactly one condition, ignoring DontCare
274// conditions, we have found an independence pair.
275auto AB =A.getDifferences(B);
276if (AB.count() == 1)
277 IndependencePairs->insert(
278 {AB.find_first(), std::make_pair(J + 1,I + 1)});
279 }
280 }
281}
282
283mcdc::TVIdxBuilder::TVIdxBuilder(constSmallVectorImpl<ConditionIDs> &NextIDs,
284intOffset)
285 : Indices(NextIDs.size()) {
286// Construct Nodes and set up each InCount
287autoN = NextIDs.size();
288SmallVector<MCDCNode> Nodes(N);
289for (unsignedID = 0;ID <N; ++ID) {
290for (unsignedC = 0;C < 2; ++C) {
291#ifndef NDEBUG
292Indices[ID][C] = INT_MIN;
293#endif
294auto NextID = NextIDs[ID][C];
295 Nodes[ID].NextIDs[C] = NextID;
296if (NextID >= 0)
297 ++Nodes[NextID].InCount;
298 }
299 }
300
301// Sort key ordered by <-Width, Ord>
302SmallVector<std::tuple<int,/// -Width
303unsigned,/// Ord
304 int,/// ID
305unsigned/// Cond (0 or 1)
306 >>
307 Decisions;
308
309// Traverse Nodes to assign Idx
310SmallVector<int> Q;
311assert(Nodes[0].InCount == 0);
312 Nodes[0].Width = 1;
313 Q.push_back(0);
314
315unsigned Ord = 0;
316while (!Q.empty()) {
317auto IID = Q.begin();
318intID = *IID;
319 Q.erase(IID);
320auto &Node = Nodes[ID];
321assert(Node.Width > 0);
322
323for (unsignedI = 0;I < 2; ++I) {
324auto NextID = Node.NextIDs[I];
325assert(NextID != 0 &&"NextID should not point to the top");
326if (NextID < 0) {
327// Decision
328 Decisions.emplace_back(-Node.Width, Ord++,ID,I);
329assert(Ord == Decisions.size());
330continue;
331 }
332
333// Inter Node
334auto &NextNode = Nodes[NextID];
335assert(NextNode.InCount > 0);
336
337// Assign Idx
338assert(Indices[ID][I] == INT_MIN);
339Indices[ID][I] = NextNode.Width;
340auto NextWidth = int64_t(NextNode.Width) + Node.Width;
341if (NextWidth >HardMaxTVs) {
342NumTestVectors =HardMaxTVs;// Overflow
343return;
344 }
345 NextNode.Width = NextWidth;
346
347// Ready if all incomings are processed.
348// Or NextNode.Width hasn't been confirmed yet.
349if (--NextNode.InCount == 0)
350 Q.push_back(NextID);
351 }
352 }
353
354llvm::sort(Decisions);
355
356// Assign TestVector Indices in Decision Nodes
357 int64_t CurIdx = 0;
358for (auto [NegWidth, Ord,ID,C] : Decisions) {
359int Width = -NegWidth;
360assert(Nodes[ID].Width == Width);
361assert(Nodes[ID].NextIDs[C] < 0);
362assert(Indices[ID][C] == INT_MIN);
363Indices[ID][C] =Offset + CurIdx;
364 CurIdx += Width;
365if (CurIdx >HardMaxTVs) {
366NumTestVectors =HardMaxTVs;// Overflow
367return;
368 }
369 }
370
371assert(CurIdx <HardMaxTVs);
372NumTestVectors = CurIdx;
373
374#ifndef NDEBUG
375for (constauto &Idxs :Indices)
376for (autoIdx : Idxs)
377assert(Idx != INT_MIN);
378SavedNodes = std::move(Nodes);
379#endif
380}
381
382namespace{
383
384/// Construct this->NextIDs with Branches for TVIdxBuilder to use it
385/// before MCDCRecordProcessor().
386classNextIDsBuilder {
387protected:
388SmallVector<mcdc::ConditionIDs> NextIDs;
389
390public:
391 NextIDsBuilder(constArrayRef<const CounterMappingRegion *> Branches)
392 : NextIDs(Branches.size()) {
393#ifndef NDEBUG
394DenseSet<mcdc::ConditionID> SeenIDs;
395#endif
396for (constauto *Branch : Branches) {
397constauto &BranchParams = Branch->getBranchParams();
398assert(SeenIDs.insert(BranchParams.ID).second &&"Duplicate CondID");
399 NextIDs[BranchParams.ID] = BranchParams.Conds;
400 }
401assert(SeenIDs.size() == Branches.size());
402 }
403};
404
405classMCDCRecordProcessor : NextIDsBuilder,mcdc::TVIdxBuilder {
406 /// A bitmap representing the executed test vectors for a boolean expression.
407 /// Each index of the bitmap corresponds to a possible test vector. An index
408 /// with a bit value of '1' indicates that the corresponding Test Vector
409 /// identified by that index was executed.
410constBitVector &Bitmap;
411
412 /// Decision Region to which the ExecutedTestVectorBitmap applies.
413constCounterMappingRegion &Region;
414constmcdc::DecisionParameters &DecisionParams;
415
416 /// Array of branch regions corresponding each conditions in the boolean
417 /// expression.
418ArrayRef<const CounterMappingRegion *> Branches;
419
420 /// Total number of conditions in the boolean expression.
421unsigned NumConditions;
422
423 /// Vector used to track whether a condition is constant folded.
424MCDCRecord::BoolVector Folded;
425
426 /// Mapping of calculated MC/DC Independence Pairs for each condition.
427MCDCRecord::TVPairMap IndependencePairs;
428
429 /// Storage for ExecVectors
430 /// ExecVectors is the alias of its 0th element.
431 std::array<MCDCRecord::TestVectors, 2> ExecVectorsByCond;
432
433 /// Actual executed Test Vectors for the boolean expression, based on
434 /// ExecutedTestVectorBitmap.
435MCDCRecord::TestVectors &ExecVectors;
436
437#ifndef NDEBUG
438DenseSet<unsigned> TVIdxs;
439#endif
440
441bool IsVersion11;
442
443public:
444 MCDCRecordProcessor(constBitVector &Bitmap,
445constCounterMappingRegion &Region,
446ArrayRef<const CounterMappingRegion *> Branches,
447bool IsVersion11)
448 : NextIDsBuilder(Branches), TVIdxBuilder(this->NextIDs), Bitmap(Bitmap),
449Region(Region), DecisionParams(Region.getDecisionParams()),
450 Branches(Branches), NumConditions(DecisionParams.NumConditions),
451 Folded{{BitVector(NumConditions),BitVector(NumConditions)}},
452 IndependencePairs(NumConditions), ExecVectors(ExecVectorsByCond[false]),
453 IsVersion11(IsVersion11) {}
454
455private:
456// Walk the binary decision diagram and try assigning both false and true to
457// each node. When a terminal node (ID == 0) is reached, fill in the value in
458// the truth table.
459void buildTestVector(MCDCRecord::TestVector &TV,mcdc::ConditionIDID,
460int TVIdx) {
461for (auto MCDCCond : {MCDCRecord::MCDC_False,MCDCRecord::MCDC_True}) {
462static_assert(MCDCRecord::MCDC_False == 0);
463static_assert(MCDCRecord::MCDC_True == 1);
464 TV.set(ID, MCDCCond);
465auto NextID = NextIDs[ID][MCDCCond];
466auto NextTVIdx = TVIdx + Indices[ID][MCDCCond];
467assert(NextID == SavedNodes[ID].NextIDs[MCDCCond]);
468if (NextID >= 0) {
469 buildTestVector(TV, NextID, NextTVIdx);
470continue;
471 }
472
473assert(TVIdx < SavedNodes[ID].Width);
474assert(TVIdxs.insert(NextTVIdx).second &&"Duplicate TVIdx");
475
476if (!Bitmap[IsVersion11
477 ? DecisionParams.BitmapIdx * CHAR_BIT + TV.getIndex()
478 : DecisionParams.BitmapIdx - NumTestVectors + NextTVIdx])
479continue;
480
481// Copy the completed test vector to the vector of testvectors.
482// The final value (T,F) is equal to the last non-dontcare state on the
483// path (in a short-circuiting system).
484 ExecVectorsByCond[MCDCCond].push_back({TV, MCDCCond});
485 }
486
487// Reset back to DontCare.
488 TV.set(ID,MCDCRecord::MCDC_DontCare);
489 }
490
491 /// Walk the bits in the bitmap. A bit set to '1' indicates that the test
492 /// vector at the corresponding index was executed during a test run.
493void findExecutedTestVectors() {
494// Walk the binary decision diagram to enumerate all possible test vectors.
495// We start at the root node (ID == 0) with all values being DontCare.
496// `TVIdx` starts with 0 and is in the traversal.
497// `Index` encodes the bitmask of true values and is initially 0.
498MCDCRecord::TestVector TV(NumConditions);
499 buildTestVector(TV, 0, 0);
500assert(TVIdxs.size() ==unsigned(NumTestVectors) &&
501"TVIdxs wasn't fulfilled");
502
503// Fill ExecVectors order by False items and True items.
504// ExecVectors is the alias of ExecVectorsByCond[false], so
505// Append ExecVectorsByCond[true] on it.
506auto &ExecVectorsT = ExecVectorsByCond[true];
507 ExecVectors.append(std::make_move_iterator(ExecVectorsT.begin()),
508 std::make_move_iterator(ExecVectorsT.end()));
509 }
510
511public:
512 /// Process the MC/DC Record in order to produce a result for a boolean
513 /// expression. This process includes tracking the conditions that comprise
514 /// the decision region, calculating the list of all possible test vectors,
515 /// marking the executed test vectors, and then finding an Independence Pair
516 /// out of the executed test vectors for each condition in the boolean
517 /// expression. A condition is tracked to ensure that its ID can be mapped to
518 /// its ordinal position in the boolean expression. The condition's source
519 /// location is also tracked, as well as whether it is constant folded (in
520 /// which case it is excuded from the metric).
521MCDCRecord processMCDCRecord() {
522MCDCRecord::CondIDMap PosToID;
523MCDCRecord::LineColPairMap CondLoc;
524
525// Walk the Record's BranchRegions (representing Conditions) in order to:
526// - Hash the condition based on its corresponding ID. This will be used to
527// calculate the test vectors.
528// - Keep a map of the condition's ordinal position (1, 2, 3, 4) to its
529// actual ID. This will be used to visualize the conditions in the
530// correct order.
531// - Keep track of the condition source location. This will be used to
532// visualize where the condition is.
533// - Record whether the condition is constant folded so that we exclude it
534// from being measured.
535for (auto [I,B] :enumerate(Branches)) {
536constauto &BranchParams =B->getBranchParams();
537 PosToID[I] = BranchParams.ID;
538 CondLoc[I] =B->startLoc();
539 Folded[false][I] =B->FalseCount.isZero();
540 Folded[true][I] =B->Count.isZero();
541 }
542
543// Using Profile Bitmap from runtime, mark the executed test vectors.
544 findExecutedTestVectors();
545
546// Record Test vectors, executed vectors, and independence pairs.
547returnMCDCRecord(Region, std::move(ExecVectors), std::move(Folded),
548 std::move(PosToID), std::move(CondLoc));
549 }
550};
551
552}// namespace
553
554Expected<MCDCRecord>CounterMappingContext::evaluateMCDCRegion(
555constCounterMappingRegion &Region,
556ArrayRef<const CounterMappingRegion *> Branches,bool IsVersion11) {
557
558 MCDCRecordProcessor MCDCProcessor(Bitmap,Region, Branches, IsVersion11);
559return MCDCProcessor.processMCDCRecord();
560}
561
562unsignedCounterMappingContext::getMaxCounterID(constCounter &C) const{
563structStackElem {
564Counter ICounter;
565 int64_tLHS = 0;
566enum {
567 KNeverVisited = 0,
568 KVisitedOnce = 1,
569 KVisitedTwice = 2,
570 } VisitCount = KNeverVisited;
571 };
572
573 std::stack<StackElem> CounterStack;
574 CounterStack.push({C});
575
576 int64_t LastPoppedValue;
577
578while (!CounterStack.empty()) {
579 StackElem &Current = CounterStack.top();
580
581switch (Current.ICounter.getKind()) {
582caseCounter::Zero:
583 LastPoppedValue = 0;
584 CounterStack.pop();
585break;
586caseCounter::CounterValueReference:
587 LastPoppedValue = Current.ICounter.getCounterID();
588 CounterStack.pop();
589break;
590caseCounter::Expression: {
591if (Current.ICounter.getExpressionID() >= Expressions.size()) {
592 LastPoppedValue = 0;
593 CounterStack.pop();
594 }else {
595constauto &E = Expressions[Current.ICounter.getExpressionID()];
596if (Current.VisitCount == StackElem::KNeverVisited) {
597 CounterStack.push(StackElem{E.LHS});
598 Current.VisitCount = StackElem::KVisitedOnce;
599 }elseif (Current.VisitCount == StackElem::KVisitedOnce) {
600 Current.LHS = LastPoppedValue;
601 CounterStack.push(StackElem{E.RHS});
602 Current.VisitCount = StackElem::KVisitedTwice;
603 }else {
604 int64_tLHS = Current.LHS;
605 int64_tRHS = LastPoppedValue;
606 LastPoppedValue = std::max(LHS,RHS);
607 CounterStack.pop();
608 }
609 }
610break;
611 }
612 }
613 }
614
615return LastPoppedValue;
616}
617
618void FunctionRecordIterator::skipOtherFiles() {
619while (Current != Records.end() && !Filename.empty() &&
620 Filename != Current->Filenames[0])
621 advanceOne();
622if (Current == Records.end())
623 *this =FunctionRecordIterator();
624}
625
626ArrayRef<unsigned> CoverageMapping::getImpreciseRecordIndicesForFilename(
627StringRef Filename) const{
628size_t FilenameHash =hash_value(Filename);
629auto RecordIt = FilenameHash2RecordIndices.find(FilenameHash);
630if (RecordIt == FilenameHash2RecordIndices.end())
631return {};
632return RecordIt->second;
633}
634
635staticunsignedgetMaxCounterID(constCounterMappingContext &Ctx,
636constCoverageMappingRecord &Record) {
637unsigned MaxCounterID = 0;
638for (constauto &Region :Record.MappingRegions) {
639 MaxCounterID = std::max(MaxCounterID, Ctx.getMaxCounterID(Region.Count));
640 }
641return MaxCounterID;
642}
643
644/// Returns the bit count
645staticunsignedgetMaxBitmapSize(constCoverageMappingRecord &Record,
646bool IsVersion11) {
647unsigned MaxBitmapIdx = 0;
648unsigned NumConditions = 0;
649// Scan max(BitmapIdx).
650// Note that `<=` is used insted of `<`, because `BitmapIdx == 0` is valid
651// and `MaxBitmapIdx is `unsigned`. `BitmapIdx` is unique in the record.
652for (constauto &Region :reverse(Record.MappingRegions)) {
653if (Region.Kind !=CounterMappingRegion::MCDCDecisionRegion)
654continue;
655constauto &DecisionParams =Region.getDecisionParams();
656if (MaxBitmapIdx <= DecisionParams.BitmapIdx) {
657 MaxBitmapIdx = DecisionParams.BitmapIdx;
658 NumConditions = DecisionParams.NumConditions;
659 }
660 }
661
662if (IsVersion11)
663 MaxBitmapIdx = MaxBitmapIdx * CHAR_BIT +
664llvm::alignTo(uint64_t(1) << NumConditions, CHAR_BIT);
665
666return MaxBitmapIdx;
667}
668
669namespace{
670
671/// Collect Decisions, Branchs, and Expansions and associate them.
672classMCDCDecisionRecorder {
673private:
674 /// This holds the DecisionRegion and MCDCBranches under it.
675 /// Also traverses Expansion(s).
676 /// The Decision has the number of MCDCBranches and will complete
677 /// when it is filled with unique ConditionID of MCDCBranches.
678structDecisionRecord {
679constCounterMappingRegion *DecisionRegion;
680
681 /// They are reflected from DecisionRegion for convenience.
682mcdc::DecisionParameters DecisionParams;
683LineColPair DecisionStartLoc;
684LineColPair DecisionEndLoc;
685
686 /// This is passed to `MCDCRecordProcessor`, so this should be compatible
687 /// to`ArrayRef<const CounterMappingRegion *>`.
688SmallVector<const CounterMappingRegion *> MCDCBranches;
689
690 /// IDs that are stored in MCDCBranches
691 /// Complete when all IDs (1 to NumConditions) are met.
692DenseSet<mcdc::ConditionID>ConditionIDs;
693
694 /// Set of IDs of Expansion(s) that are relevant to DecisionRegion
695 /// and its children (via expansions).
696 /// FileID pointed by ExpandedFileID is dedicated to the expansion, so
697 /// the location in the expansion doesn't matter.
698DenseSet<unsigned> ExpandedFileIDs;
699
700 DecisionRecord(constCounterMappingRegion &Decision)
701 : DecisionRegion(&Decision),
702 DecisionParams(Decision.getDecisionParams()),
703 DecisionStartLoc(Decision.startLoc()),
704 DecisionEndLoc(Decision.endLoc()) {
705assert(Decision.Kind ==CounterMappingRegion::MCDCDecisionRegion);
706 }
707
708 /// Determine whether DecisionRecord dominates `R`.
709booldominates(constCounterMappingRegion &R) const{
710// Determine whether `R` is included in `DecisionRegion`.
711if (R.FileID == DecisionRegion->FileID &&
712R.startLoc() >= DecisionStartLoc &&R.endLoc() <= DecisionEndLoc)
713returntrue;
714
715// Determine whether `R` is pointed by any of Expansions.
716return ExpandedFileIDs.contains(R.FileID);
717 }
718
719enumResult {
720 NotProcessed = 0,/// Irrelevant to this Decision
721 Processed,/// Added to this Decision
722 Completed,/// Added and filled this Decision
723 };
724
725 /// Add Branch into the Decision
726 /// \param Branch expects MCDCBranchRegion
727 /// \returns NotProcessed/Processed/Completed
728Result addBranch(constCounterMappingRegion &Branch) {
729assert(Branch.Kind ==CounterMappingRegion::MCDCBranchRegion);
730
731autoConditionID =Branch.getBranchParams().ID;
732
733if (ConditionIDs.contains(ConditionID) ||
734 ConditionID >= DecisionParams.NumConditions)
735return NotProcessed;
736
737if (!this->dominates(Branch))
738return NotProcessed;
739
740assert(MCDCBranches.size() < DecisionParams.NumConditions);
741
742// Put `ID=0` in front of `MCDCBranches` for convenience
743// even if `MCDCBranches` is not topological.
744if (ConditionID == 0)
745 MCDCBranches.insert(MCDCBranches.begin(), &Branch);
746else
747 MCDCBranches.push_back(&Branch);
748
749// Mark `ID` as `assigned`.
750ConditionIDs.insert(ConditionID);
751
752// `Completed` when `MCDCBranches` is full
753return (MCDCBranches.size() == DecisionParams.NumConditions ? Completed
754 : Processed);
755 }
756
757 /// Record Expansion if it is relevant to this Decision.
758 /// Each `Expansion` may nest.
759 /// \returns true if recorded.
760bool recordExpansion(constCounterMappingRegion &Expansion) {
761if (!this->dominates(Expansion))
762returnfalse;
763
764 ExpandedFileIDs.insert(Expansion.ExpandedFileID);
765returntrue;
766 }
767 };
768
769private:
770 /// Decisions in progress
771 /// DecisionRecord is added for each MCDCDecisionRegion.
772 /// DecisionRecord is removed when Decision is completed.
773SmallVector<DecisionRecord> Decisions;
774
775public:
776 ~MCDCDecisionRecorder() {
777assert(Decisions.empty() &&"All Decisions have not been resolved");
778 }
779
780 /// Register Region and start recording.
781void registerDecision(constCounterMappingRegion &Decision) {
782 Decisions.emplace_back(Decision);
783 }
784
785void recordExpansion(constCounterMappingRegion &Expansion) {
786any_of(Decisions, [&Expansion](auto &Decision) {
787return Decision.recordExpansion(Expansion);
788 });
789 }
790
791usingDecisionAndBranches =
792 std::pair<constCounterMappingRegion *,/// Decision
793SmallVector<const CounterMappingRegion *>/// Branches
794 >;
795
796 /// Add MCDCBranchRegion to DecisionRecord.
797 /// \param Branch to be processed
798 /// \returns DecisionsAndBranches if DecisionRecord completed.
799 /// Or returns nullopt.
800 std::optional<DecisionAndBranches>
801 processBranch(constCounterMappingRegion &Branch) {
802// Seek each Decision and apply Region to it.
803for (auto DecisionIter = Decisions.begin(), DecisionEnd = Decisions.end();
804 DecisionIter != DecisionEnd; ++DecisionIter)
805switch (DecisionIter->addBranch(Branch)) {
806case DecisionRecord::NotProcessed:
807continue;
808case DecisionRecord::Processed:
809return std::nullopt;
810case DecisionRecord::Completed:
811 DecisionAndBranchesResult =
812 std::make_pair(DecisionIter->DecisionRegion,
813 std::move(DecisionIter->MCDCBranches));
814 Decisions.erase(DecisionIter);// No longer used.
815returnResult;
816 }
817
818llvm_unreachable("Branch not found in Decisions");
819 }
820};
821
822}// namespace
823
824Error CoverageMapping::loadFunctionRecord(
825constCoverageMappingRecord &Record,
826IndexedInstrProfReader &ProfileReader) {
827StringRef OrigFuncName =Record.FunctionName;
828if (OrigFuncName.empty())
829return make_error<CoverageMapError>(coveragemap_error::malformed,
830"record function name is empty");
831
832if (Record.Filenames.empty())
833 OrigFuncName =getFuncNameWithoutPrefix(OrigFuncName);
834else
835 OrigFuncName =getFuncNameWithoutPrefix(OrigFuncName,Record.Filenames[0]);
836
837CounterMappingContext Ctx(Record.Expressions);
838
839 std::vector<uint64_t> Counts;
840if (Error E = ProfileReader.getFunctionCounts(Record.FunctionName,
841Record.FunctionHash, Counts)) {
842instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
843if (IPE ==instrprof_error::hash_mismatch) {
844 FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
845Record.FunctionHash);
846returnError::success();
847 }
848if (IPE !=instrprof_error::unknown_function)
849return make_error<InstrProfError>(IPE);
850 Counts.assign(getMaxCounterID(Ctx,Record) + 1, 0);
851 }
852 Ctx.setCounts(Counts);
853
854bool IsVersion11 =
855 ProfileReader.getVersion() <IndexedInstrProf::ProfVersion::Version12;
856
857BitVector Bitmap;
858if (Error E = ProfileReader.getFunctionBitmap(Record.FunctionName,
859Record.FunctionHash, Bitmap)) {
860instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
861if (IPE ==instrprof_error::hash_mismatch) {
862 FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
863Record.FunctionHash);
864returnError::success();
865 }
866if (IPE !=instrprof_error::unknown_function)
867return make_error<InstrProfError>(IPE);
868 Bitmap =BitVector(getMaxBitmapSize(Record, IsVersion11));
869 }
870 Ctx.setBitmap(std::move(Bitmap));
871
872assert(!Record.MappingRegions.empty() &&"Function has no regions");
873
874// This coverage record is a zero region for a function that's unused in
875// some TU, but used in a different TU. Ignore it. The coverage maps from the
876// the other TU will either be loaded (providing full region counts) or they
877// won't (in which case we don't unintuitively report functions as uncovered
878// when they have non-zero counts in the profile).
879if (Record.MappingRegions.size() == 1 &&
880Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
881returnError::success();
882
883 MCDCDecisionRecorder MCDCDecisions;
884FunctionRecordFunction(OrigFuncName,Record.Filenames);
885for (constauto &Region :Record.MappingRegions) {
886// MCDCDecisionRegion should be handled first since it overlaps with
887// others inside.
888if (Region.Kind ==CounterMappingRegion::MCDCDecisionRegion) {
889 MCDCDecisions.registerDecision(Region);
890continue;
891 }
892Expected<int64_t> ExecutionCount = Ctx.evaluate(Region.Count);
893if (auto E = ExecutionCount.takeError()) {
894consumeError(std::move(E));
895returnError::success();
896 }
897Expected<int64_t> AltExecutionCount = Ctx.evaluate(Region.FalseCount);
898if (auto E = AltExecutionCount.takeError()) {
899consumeError(std::move(E));
900returnError::success();
901 }
902Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount);
903
904// Record ExpansionRegion.
905if (Region.Kind ==CounterMappingRegion::ExpansionRegion) {
906 MCDCDecisions.recordExpansion(Region);
907continue;
908 }
909
910// Do nothing unless MCDCBranchRegion.
911if (Region.Kind !=CounterMappingRegion::MCDCBranchRegion)
912continue;
913
914autoResult = MCDCDecisions.processBranch(Region);
915if (!Result)// Any Decision doesn't complete.
916continue;
917
918auto MCDCDecision =Result->first;
919auto &MCDCBranches =Result->second;
920
921// Since the bitmap identifies the executed test vectors for an MC/DC
922// DecisionRegion, all of the information is now available to process.
923// This is where the bulk of the MC/DC progressing takes place.
924Expected<MCDCRecord>Record =
925 Ctx.evaluateMCDCRegion(*MCDCDecision, MCDCBranches, IsVersion11);
926if (auto E =Record.takeError()) {
927consumeError(std::move(E));
928returnError::success();
929 }
930
931// Save the MC/DC Record so that it can be visualized later.
932Function.pushMCDCRecord(std::move(*Record));
933 }
934
935// Don't create records for (filenames, function) pairs we've already seen.
936auto FilenamesHash =hash_combine_range(Record.Filenames.begin(),
937Record.Filenames.end());
938if (!RecordProvenance[FilenamesHash].insert(hash_value(OrigFuncName)).second)
939returnError::success();
940
941 Functions.push_back(std::move(Function));
942
943// Performance optimization: keep track of the indices of the function records
944// which correspond to each filename. This can be used to substantially speed
945// up queries for coverage info in a file.
946unsigned RecordIndex = Functions.size() - 1;
947for (StringRef Filename :Record.Filenames) {
948auto &RecordIndices = FilenameHash2RecordIndices[hash_value(Filename)];
949// Note that there may be duplicates in the filename set for a function
950// record, because of e.g. macro expansions in the function in which both
951// the macro and the function are defined in the same file.
952if (RecordIndices.empty() || RecordIndices.back() != RecordIndex)
953 RecordIndices.push_back(RecordIndex);
954 }
955
956returnError::success();
957}
958
959// This function is for memory optimization by shortening the lifetimes
960// of CoverageMappingReader instances.
961Error CoverageMapping::loadFromReaders(
962ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
963IndexedInstrProfReader &ProfileReader,CoverageMapping &Coverage) {
964assert(!Coverage.SingleByteCoverage ||
965 *Coverage.SingleByteCoverage == ProfileReader.hasSingleByteCoverage());
966Coverage.SingleByteCoverage = ProfileReader.hasSingleByteCoverage();
967for (constauto &CoverageReader : CoverageReaders) {
968for (auto RecordOrErr : *CoverageReader) {
969if (Error E = RecordOrErr.takeError())
970return E;
971constauto &Record = *RecordOrErr;
972if (Error E =Coverage.loadFunctionRecord(Record, ProfileReader))
973return E;
974 }
975 }
976returnError::success();
977}
978
979Expected<std::unique_ptr<CoverageMapping>>CoverageMapping::load(
980ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
981IndexedInstrProfReader &ProfileReader) {
982auto Coverage = std::unique_ptr<CoverageMapping>(newCoverageMapping());
983if (Error E = loadFromReaders(CoverageReaders, ProfileReader, *Coverage))
984return std::move(E);
985return std::move(Coverage);
986}
987
988// If E is a no_data_found error, returns success. Otherwise returns E.
989staticErrorhandleMaybeNoDataFoundError(Error E) {
990returnhandleErrors(
991 std::move(E), [](constCoverageMapError &CME) {
992if (CME.get() ==coveragemap_error::no_data_found)
993returnstatic_cast<Error>(Error::success());
994return make_error<CoverageMapError>(CME.get(), CME.getMessage());
995 });
996}
997
998Error CoverageMapping::loadFromFile(
999StringRef Filename,StringRef Arch,StringRef CompilationDir,
1000IndexedInstrProfReader &ProfileReader,CoverageMapping &Coverage,
1001bool &DataFound,SmallVectorImpl<object::BuildID> *FoundBinaryIDs) {
1002auto CovMappingBufOrErr =MemoryBuffer::getFileOrSTDIN(
1003 Filename,/*IsText=*/false,/*RequiresNullTerminator=*/false);
1004if (std::error_code EC = CovMappingBufOrErr.getError())
1005returncreateFileError(Filename,errorCodeToError(EC));
1006MemoryBufferRef CovMappingBufRef =
1007 CovMappingBufOrErr.get()->getMemBufferRef();
1008SmallVector<std::unique_ptr<MemoryBuffer>, 4> Buffers;
1009
1010SmallVector<object::BuildIDRef> BinaryIDs;
1011auto CoverageReadersOrErr =BinaryCoverageReader::create(
1012 CovMappingBufRef, Arch, Buffers, CompilationDir,
1013 FoundBinaryIDs ? &BinaryIDs :nullptr);
1014if (Error E = CoverageReadersOrErr.takeError()) {
1015 E =handleMaybeNoDataFoundError(std::move(E));
1016if (E)
1017returncreateFileError(Filename, std::move(E));
1018return E;
1019 }
1020
1021SmallVector<std::unique_ptr<CoverageMappingReader>, 4> Readers;
1022for (auto &Reader : CoverageReadersOrErr.get())
1023 Readers.push_back(std::move(Reader));
1024if (FoundBinaryIDs && !Readers.empty()) {
1025llvm::append_range(*FoundBinaryIDs,
1026llvm::map_range(BinaryIDs, [](object::BuildIDRef BID) {
1027returnobject::BuildID(BID);
1028 }));
1029 }
1030 DataFound |= !Readers.empty();
1031if (Error E = loadFromReaders(Readers, ProfileReader, Coverage))
1032returncreateFileError(Filename, std::move(E));
1033returnError::success();
1034}
1035
1036Expected<std::unique_ptr<CoverageMapping>>CoverageMapping::load(
1037ArrayRef<StringRef> ObjectFilenames,StringRef ProfileFilename,
1038vfs::FileSystem &FS,ArrayRef<StringRef> Arches,StringRef CompilationDir,
1039constobject::BuildIDFetcher *BIDFetcher,bool CheckBinaryIDs) {
1040auto ProfileReaderOrErr =IndexedInstrProfReader::create(ProfileFilename, FS);
1041if (Error E = ProfileReaderOrErr.takeError())
1042returncreateFileError(ProfileFilename, std::move(E));
1043auto ProfileReader = std::move(ProfileReaderOrErr.get());
1044auto Coverage = std::unique_ptr<CoverageMapping>(newCoverageMapping());
1045bool DataFound =false;
1046
1047auto GetArch = [&](size_tIdx) {
1048if (Arches.empty())
1049returnStringRef();
1050if (Arches.size() == 1)
1051return Arches.front();
1052return Arches[Idx];
1053 };
1054
1055SmallVector<object::BuildID> FoundBinaryIDs;
1056for (constauto &File :llvm::enumerate(ObjectFilenames)) {
1057if (Error E =
1058 loadFromFile(File.value(), GetArch(File.index()), CompilationDir,
1059 *ProfileReader, *Coverage, DataFound, &FoundBinaryIDs))
1060return std::move(E);
1061 }
1062
1063if (BIDFetcher) {
1064 std::vector<object::BuildID> ProfileBinaryIDs;
1065if (Error E = ProfileReader->readBinaryIds(ProfileBinaryIDs))
1066returncreateFileError(ProfileFilename, std::move(E));
1067
1068SmallVector<object::BuildIDRef> BinaryIDsToFetch;
1069if (!ProfileBinaryIDs.empty()) {
1070constauto &Compare = [](object::BuildIDRefA,object::BuildIDRefB) {
1071return std::lexicographical_compare(A.begin(),A.end(),B.begin(),
1072B.end());
1073 };
1074llvm::sort(FoundBinaryIDs, Compare);
1075 std::set_difference(
1076 ProfileBinaryIDs.begin(), ProfileBinaryIDs.end(),
1077 FoundBinaryIDs.begin(), FoundBinaryIDs.end(),
1078 std::inserter(BinaryIDsToFetch, BinaryIDsToFetch.end()), Compare);
1079 }
1080
1081for (object::BuildIDRef BinaryID : BinaryIDsToFetch) {
1082 std::optional<std::string> PathOpt = BIDFetcher->fetch(BinaryID);
1083if (PathOpt) {
1084 std::string Path = std::move(*PathOpt);
1085StringRef Arch = Arches.size() == 1 ? Arches.front() :StringRef();
1086if (Error E = loadFromFile(Path, Arch, CompilationDir, *ProfileReader,
1087 *Coverage, DataFound))
1088return std::move(E);
1089 }elseif (CheckBinaryIDs) {
1090returncreateFileError(
1091 ProfileFilename,
1092createStringError(errc::no_such_file_or_directory,
1093"Missing binary ID: " +
1094 llvm::toHex(BinaryID,/*LowerCase=*/true)));
1095 }
1096 }
1097 }
1098
1099if (!DataFound)
1100returncreateFileError(
1101 join(ObjectFilenames.begin(), ObjectFilenames.end(),", "),
1102 make_error<CoverageMapError>(coveragemap_error::no_data_found));
1103return std::move(Coverage);
1104}
1105
1106namespace{
1107
1108/// Distributes functions into instantiation sets.
1109///
1110/// An instantiation set is a collection of functions that have the same source
1111/// code, ie, template functions specializations.
1112classFunctionInstantiationSetCollector {
1113usingMapT = std::map<LineColPair, std::vector<const FunctionRecord *>>;
1114MapT InstantiatedFunctions;
1115
1116public:
1117void insert(constFunctionRecord &Function,unsigned FileID) {
1118autoI =Function.CountedRegions.begin(),E =Function.CountedRegions.end();
1119while (I !=E &&I->FileID != FileID)
1120 ++I;
1121assert(I !=E &&"function does not cover the given file");
1122auto &Functions = InstantiatedFunctions[I->startLoc()];
1123 Functions.push_back(&Function);
1124 }
1125
1126 MapT::iterator begin() {return InstantiatedFunctions.begin(); }
1127 MapT::iterator end() {return InstantiatedFunctions.end(); }
1128};
1129
1130classSegmentBuilder {
1131 std::vector<CoverageSegment> &Segments;
1132SmallVector<const CountedRegion *, 8> ActiveRegions;
1133
1134 SegmentBuilder(std::vector<CoverageSegment> &Segments) :Segments(Segments) {}
1135
1136 /// Emit a segment with the count from \p Region starting at \p StartLoc.
1137//
1138 /// \p IsRegionEntry: The segment is at the start of a new non-gap region.
1139 /// \p EmitSkippedRegion: The segment must be emitted as a skipped region.
1140void startSegment(constCountedRegion &Region,LineColPair StartLoc,
1141bool IsRegionEntry,bool EmitSkippedRegion =false) {
1142bool HasCount = !EmitSkippedRegion &&
1143 (Region.Kind !=CounterMappingRegion::SkippedRegion);
1144
1145// If the new segment wouldn't affect coverage rendering, skip it.
1146if (!Segments.empty() && !IsRegionEntry && !EmitSkippedRegion) {
1147constauto &Last =Segments.back();
1148if (Last.HasCount == HasCount &&Last.Count ==Region.ExecutionCount &&
1149 !Last.IsRegionEntry)
1150return;
1151 }
1152
1153if (HasCount)
1154Segments.emplace_back(StartLoc.first, StartLoc.second,
1155Region.ExecutionCount, IsRegionEntry,
1156Region.Kind ==CounterMappingRegion::GapRegion);
1157else
1158Segments.emplace_back(StartLoc.first, StartLoc.second, IsRegionEntry);
1159
1160LLVM_DEBUG({
1161constauto &Last =Segments.back();
1162dbgs() <<"Segment at " <<Last.Line <<":" <<Last.Col
1163 <<" (count = " <<Last.Count <<")"
1164 << (Last.IsRegionEntry ?", RegionEntry" :"")
1165 << (!Last.HasCount ?", Skipped" :"")
1166 << (Last.IsGapRegion ?", Gap" :"") <<"\n";
1167 });
1168 }
1169
1170 /// Emit segments for active regions which end before \p Loc.
1171 ///
1172 /// \p Loc: The start location of the next region. If std::nullopt, all active
1173 /// regions are completed.
1174 /// \p FirstCompletedRegion: Index of the first completed region.
1175void completeRegionsUntil(std::optional<LineColPair> Loc,
1176unsigned FirstCompletedRegion) {
1177// Sort the completed regions by end location. This makes it simple to
1178// emit closing segments in sorted order.
1179auto CompletedRegionsIt = ActiveRegions.begin() + FirstCompletedRegion;
1180 std::stable_sort(CompletedRegionsIt, ActiveRegions.end(),
1181 [](constCountedRegion *L,constCountedRegion *R) {
1182 return L->endLoc() < R->endLoc();
1183 });
1184
1185// Emit segments for all completed regions.
1186for (unsignedI = FirstCompletedRegion + 1,E = ActiveRegions.size();I <E;
1187 ++I) {
1188constauto *CompletedRegion = ActiveRegions[I];
1189assert((!Loc || CompletedRegion->endLoc() <= *Loc) &&
1190"Completed region ends after start of new region");
1191
1192constauto *PrevCompletedRegion = ActiveRegions[I - 1];
1193auto CompletedSegmentLoc = PrevCompletedRegion->endLoc();
1194
1195// Don't emit any more segments if they start where the new region begins.
1196if (Loc && CompletedSegmentLoc == *Loc)
1197break;
1198
1199// Don't emit a segment if the next completed region ends at the same
1200// location as this one.
1201if (CompletedSegmentLoc == CompletedRegion->endLoc())
1202continue;
1203
1204// Use the count from the last completed region which ends at this loc.
1205for (unsigned J =I + 1; J <E; ++J)
1206if (CompletedRegion->endLoc() == ActiveRegions[J]->endLoc())
1207 CompletedRegion = ActiveRegions[J];
1208
1209 startSegment(*CompletedRegion, CompletedSegmentLoc,false);
1210 }
1211
1212autoLast = ActiveRegions.back();
1213if (FirstCompletedRegion &&Last->endLoc() != *Loc) {
1214// If there's a gap after the end of the last completed region and the
1215// start of the new region, use the last active region to fill the gap.
1216 startSegment(*ActiveRegions[FirstCompletedRegion - 1],Last->endLoc(),
1217false);
1218 }elseif (!FirstCompletedRegion && (!Loc || *Loc !=Last->endLoc())) {
1219// Emit a skipped segment if there are no more active regions. This
1220// ensures that gaps between functions are marked correctly.
1221 startSegment(*Last,Last->endLoc(),false,true);
1222 }
1223
1224// Pop the completed regions.
1225 ActiveRegions.erase(CompletedRegionsIt, ActiveRegions.end());
1226 }
1227
1228void buildSegmentsImpl(ArrayRef<CountedRegion> Regions) {
1229for (constauto &CR :enumerate(Regions)) {
1230auto CurStartLoc = CR.value().startLoc();
1231
1232// Active regions which end before the current region need to be popped.
1233auto CompletedRegions =
1234 std::stable_partition(ActiveRegions.begin(), ActiveRegions.end(),
1235 [&](constCountedRegion *Region) {
1236 return !(Region->endLoc() <= CurStartLoc);
1237 });
1238if (CompletedRegions != ActiveRegions.end()) {
1239unsigned FirstCompletedRegion =
1240 std::distance(ActiveRegions.begin(), CompletedRegions);
1241 completeRegionsUntil(CurStartLoc, FirstCompletedRegion);
1242 }
1243
1244bool GapRegion = CR.value().Kind ==CounterMappingRegion::GapRegion;
1245
1246// Try to emit a segment for the current region.
1247if (CurStartLoc == CR.value().endLoc()) {
1248// Avoid making zero-length regions active. If it's the last region,
1249// emit a skipped segment. Otherwise use its predecessor's count.
1250constbool Skipped =
1251 (CR.index() + 1) == Regions.size() ||
1252 CR.value().Kind ==CounterMappingRegion::SkippedRegion;
1253 startSegment(ActiveRegions.empty() ? CR.value() : *ActiveRegions.back(),
1254 CurStartLoc, !GapRegion, Skipped);
1255// If it is skipped segment, create a segment with last pushed
1256// regions's count at CurStartLoc.
1257if (Skipped && !ActiveRegions.empty())
1258 startSegment(*ActiveRegions.back(), CurStartLoc,false);
1259continue;
1260 }
1261if (CR.index() + 1 == Regions.size() ||
1262 CurStartLoc != Regions[CR.index() + 1].startLoc()) {
1263// Emit a segment if the next region doesn't start at the same location
1264// as this one.
1265 startSegment(CR.value(), CurStartLoc, !GapRegion);
1266 }
1267
1268// This region is active (i.e not completed).
1269 ActiveRegions.push_back(&CR.value());
1270 }
1271
1272// Complete any remaining active regions.
1273if (!ActiveRegions.empty())
1274 completeRegionsUntil(std::nullopt, 0);
1275 }
1276
1277 /// Sort a nested sequence of regions from a single file.
1278staticvoid sortNestedRegions(MutableArrayRef<CountedRegion> Regions) {
1279llvm::sort(Regions, [](constCountedRegion &LHS,constCountedRegion &RHS) {
1280if (LHS.startLoc() !=RHS.startLoc())
1281returnLHS.startLoc() <RHS.startLoc();
1282if (LHS.endLoc() !=RHS.endLoc())
1283// When LHS completely contains RHS, we sort LHS first.
1284returnRHS.endLoc() <LHS.endLoc();
1285// If LHS and RHS cover the same area, we need to sort them according
1286// to their kinds so that the most suitable region will become "active"
1287// in combineRegions(). Because we accumulate counter values only from
1288// regions of the same kind as the first region of the area, prefer
1289// CodeRegion to ExpansionRegion and ExpansionRegion to SkippedRegion.
1290static_assert(CounterMappingRegion::CodeRegion <
1291CounterMappingRegion::ExpansionRegion &&
1292CounterMappingRegion::ExpansionRegion <
1293CounterMappingRegion::SkippedRegion,
1294"Unexpected order of region kind values");
1295returnLHS.Kind <RHS.Kind;
1296 });
1297 }
1298
1299 /// Combine counts of regions which cover the same area.
1300staticArrayRef<CountedRegion>
1301 combineRegions(MutableArrayRef<CountedRegion> Regions) {
1302if (Regions.empty())
1303return Regions;
1304autoActive = Regions.begin();
1305autoEnd = Regions.end();
1306for (autoI = Regions.begin() + 1;I !=End; ++I) {
1307if (Active->startLoc() !=I->startLoc() ||
1308Active->endLoc() !=I->endLoc()) {
1309// Shift to the next region.
1310 ++Active;
1311if (Active !=I)
1312 *Active = *I;
1313continue;
1314 }
1315// Merge duplicate region.
1316// If CodeRegions and ExpansionRegions cover the same area, it's probably
1317// a macro which is fully expanded to another macro. In that case, we need
1318// to accumulate counts only from CodeRegions, or else the area will be
1319// counted twice.
1320// On the other hand, a macro may have a nested macro in its body. If the
1321// outer macro is used several times, the ExpansionRegion for the nested
1322// macro will also be added several times. These ExpansionRegions cover
1323// the same source locations and have to be combined to reach the correct
1324// value for that area.
1325// We add counts of the regions of the same kind as the active region
1326// to handle the both situations.
1327if (I->Kind ==Active->Kind)
1328Active->ExecutionCount +=I->ExecutionCount;
1329 }
1330return Regions.drop_back(std::distance(++Active,End));
1331 }
1332
1333public:
1334 /// Build a sorted list of CoverageSegments from a list of Regions.
1335static std::vector<CoverageSegment>
1336 buildSegments(MutableArrayRef<CountedRegion> Regions) {
1337 std::vector<CoverageSegment>Segments;
1338 SegmentBuilder Builder(Segments);
1339
1340 sortNestedRegions(Regions);
1341ArrayRef<CountedRegion> CombinedRegions = combineRegions(Regions);
1342
1343LLVM_DEBUG({
1344dbgs() <<"Combined regions:\n";
1345for (constauto &CR : CombinedRegions)
1346dbgs() <<" " << CR.LineStart <<":" << CR.ColumnStart <<" -> "
1347 << CR.LineEnd <<":" << CR.ColumnEnd
1348 <<" (count=" << CR.ExecutionCount <<")\n";
1349 });
1350
1351 Builder.buildSegmentsImpl(CombinedRegions);
1352
1353#ifndef NDEBUG
1354for (unsignedI = 1,E =Segments.size();I <E; ++I) {
1355constauto &L =Segments[I - 1];
1356constauto &R =Segments[I];
1357if (!(L.Line <R.Line) && !(L.Line ==R.Line &&L.Col <R.Col)) {
1358if (L.Line ==R.Line &&L.Col ==R.Col && !L.HasCount)
1359continue;
1360LLVM_DEBUG(dbgs() <<" ! Segment " <<L.Line <<":" <<L.Col
1361 <<" followed by " <<R.Line <<":" <<R.Col <<"\n");
1362assert(false &&"Coverage segments not unique or sorted");
1363 }
1364 }
1365#endif
1366
1367returnSegments;
1368 }
1369};
1370
1371}// end anonymous namespace
1372
1373std::vector<StringRef>CoverageMapping::getUniqueSourceFiles() const{
1374 std::vector<StringRef> Filenames;
1375for (constauto &Function : getCoveredFunctions())
1376llvm::append_range(Filenames,Function.Filenames);
1377llvm::sort(Filenames);
1378autoLast =llvm::unique(Filenames);
1379 Filenames.erase(Last, Filenames.end());
1380return Filenames;
1381}
1382
1383staticSmallBitVectorgatherFileIDs(StringRef SourceFile,
1384constFunctionRecord &Function) {
1385SmallBitVector FilenameEquivalence(Function.Filenames.size(),false);
1386for (unsignedI = 0, E =Function.Filenames.size();I < E; ++I)
1387if (SourceFile ==Function.Filenames[I])
1388 FilenameEquivalence[I] =true;
1389return FilenameEquivalence;
1390}
1391
1392/// Return the ID of the file where the definition of the function is located.
1393static std::optional<unsigned>
1394findMainViewFileID(constFunctionRecord &Function) {
1395SmallBitVector IsNotExpandedFile(Function.Filenames.size(),true);
1396for (constauto &CR :Function.CountedRegions)
1397if (CR.Kind ==CounterMappingRegion::ExpansionRegion)
1398 IsNotExpandedFile[CR.ExpandedFileID] =false;
1399intI = IsNotExpandedFile.find_first();
1400if (I == -1)
1401return std::nullopt;
1402returnI;
1403}
1404
1405/// Check if SourceFile is the file that contains the definition of
1406/// the Function. Return the ID of the file in that case or std::nullopt
1407/// otherwise.
1408static std::optional<unsigned>
1409findMainViewFileID(StringRef SourceFile,constFunctionRecord &Function) {
1410 std::optional<unsigned>I =findMainViewFileID(Function);
1411if (I && SourceFile ==Function.Filenames[*I])
1412returnI;
1413return std::nullopt;
1414}
1415
1416staticboolisExpansion(constCountedRegion &R,unsigned FileID) {
1417return R.Kind ==CounterMappingRegion::ExpansionRegion && R.FileID == FileID;
1418}
1419
1420CoverageDataCoverageMapping::getCoverageForFile(StringRef Filename) const{
1421assert(SingleByteCoverage);
1422CoverageData FileCoverage(*SingleByteCoverage, Filename);
1423 std::vector<CountedRegion> Regions;
1424
1425// Look up the function records in the given file. Due to hash collisions on
1426// the filename, we may get back some records that are not in the file.
1427ArrayRef<unsigned> RecordIndices =
1428 getImpreciseRecordIndicesForFilename(Filename);
1429for (unsigned RecordIndex : RecordIndices) {
1430constFunctionRecord &Function = Functions[RecordIndex];
1431auto MainFileID =findMainViewFileID(Filename,Function);
1432auto FileIDs =gatherFileIDs(Filename,Function);
1433for (constauto &CR :Function.CountedRegions)
1434if (FileIDs.test(CR.FileID)) {
1435 Regions.push_back(CR);
1436if (MainFileID &&isExpansion(CR, *MainFileID))
1437 FileCoverage.Expansions.emplace_back(CR,Function);
1438 }
1439// Capture branch regions specific to the function (excluding expansions).
1440for (constauto &CR :Function.CountedBranchRegions)
1441if (FileIDs.test(CR.FileID))
1442 FileCoverage.BranchRegions.push_back(CR);
1443// Capture MCDC records specific to the function.
1444for (constauto &MR :Function.MCDCRecords)
1445if (FileIDs.test(MR.getDecisionRegion().FileID))
1446 FileCoverage.MCDCRecords.push_back(MR);
1447 }
1448
1449LLVM_DEBUG(dbgs() <<"Emitting segments for file: " << Filename <<"\n");
1450 FileCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1451
1452return FileCoverage;
1453}
1454
1455std::vector<InstantiationGroup>
1456CoverageMapping::getInstantiationGroups(StringRef Filename) const{
1457 FunctionInstantiationSetCollector InstantiationSetCollector;
1458// Look up the function records in the given file. Due to hash collisions on
1459// the filename, we may get back some records that are not in the file.
1460ArrayRef<unsigned> RecordIndices =
1461 getImpreciseRecordIndicesForFilename(Filename);
1462for (unsigned RecordIndex : RecordIndices) {
1463constFunctionRecord &Function = Functions[RecordIndex];
1464auto MainFileID =findMainViewFileID(Filename,Function);
1465if (!MainFileID)
1466continue;
1467 InstantiationSetCollector.insert(Function, *MainFileID);
1468 }
1469
1470 std::vector<InstantiationGroup> Result;
1471for (auto &InstantiationSet : InstantiationSetCollector) {
1472InstantiationGroup IG{InstantiationSet.first.first,
1473 InstantiationSet.first.second,
1474 std::move(InstantiationSet.second)};
1475 Result.emplace_back(std::move(IG));
1476 }
1477return Result;
1478}
1479
1480CoverageData
1481CoverageMapping::getCoverageForFunction(constFunctionRecord &Function) const{
1482auto MainFileID =findMainViewFileID(Function);
1483if (!MainFileID)
1484returnCoverageData();
1485
1486assert(SingleByteCoverage);
1487CoverageData FunctionCoverage(*SingleByteCoverage,
1488Function.Filenames[*MainFileID]);
1489 std::vector<CountedRegion> Regions;
1490for (constauto &CR :Function.CountedRegions)
1491if (CR.FileID == *MainFileID) {
1492 Regions.push_back(CR);
1493if (isExpansion(CR, *MainFileID))
1494 FunctionCoverage.Expansions.emplace_back(CR,Function);
1495 }
1496// Capture branch regions specific to the function (excluding expansions).
1497for (constauto &CR :Function.CountedBranchRegions)
1498if (CR.FileID == *MainFileID)
1499 FunctionCoverage.BranchRegions.push_back(CR);
1500
1501// Capture MCDC records specific to the function.
1502for (constauto &MR :Function.MCDCRecords)
1503if (MR.getDecisionRegion().FileID == *MainFileID)
1504 FunctionCoverage.MCDCRecords.push_back(MR);
1505
1506LLVM_DEBUG(dbgs() <<"Emitting segments for function: " <<Function.Name
1507 <<"\n");
1508 FunctionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1509
1510return FunctionCoverage;
1511}
1512
1513CoverageDataCoverageMapping::getCoverageForExpansion(
1514constExpansionRecord &Expansion) const{
1515assert(SingleByteCoverage);
1516CoverageData ExpansionCoverage(
1517 *SingleByteCoverage,Expansion.Function.Filenames[Expansion.FileID]);
1518 std::vector<CountedRegion> Regions;
1519for (constauto &CR :Expansion.Function.CountedRegions)
1520if (CR.FileID ==Expansion.FileID) {
1521 Regions.push_back(CR);
1522if (isExpansion(CR,Expansion.FileID))
1523 ExpansionCoverage.Expansions.emplace_back(CR,Expansion.Function);
1524 }
1525for (constauto &CR :Expansion.Function.CountedBranchRegions)
1526// Capture branch regions that only pertain to the corresponding expansion.
1527if (CR.FileID ==Expansion.FileID)
1528 ExpansionCoverage.BranchRegions.push_back(CR);
1529
1530LLVM_DEBUG(dbgs() <<"Emitting segments for expansion of file "
1531 <<Expansion.FileID <<"\n");
1532 ExpansionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1533
1534return ExpansionCoverage;
1535}
1536
1537LineCoverageStats::LineCoverageStats(
1538ArrayRef<const CoverageSegment *> LineSegments,
1539constCoverageSegment *WrappedSegment,unsigned Line)
1540 : ExecutionCount(0), HasMultipleRegions(false), Mapped(false), Line(Line),
1541 LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
1542// Find the minimum number of regions which start in this line.
1543unsigned MinRegionCount = 0;
1544auto isStartOfRegion = [](constCoverageSegment *S) {
1545return !S->IsGapRegion && S->HasCount && S->IsRegionEntry;
1546 };
1547for (unsignedI = 0;I < LineSegments.size() && MinRegionCount < 2; ++I)
1548if (isStartOfRegion(LineSegments[I]))
1549 ++MinRegionCount;
1550
1551bool StartOfSkippedRegion = !LineSegments.empty() &&
1552 !LineSegments.front()->HasCount &&
1553 LineSegments.front()->IsRegionEntry;
1554
1555 HasMultipleRegions = MinRegionCount > 1;
1556 Mapped =
1557 !StartOfSkippedRegion &&
1558 ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0));
1559
1560// if there is any starting segment at this line with a counter, it must be
1561// mapped
1562 Mapped |=any_of(LineSegments, [](constauto *Seq) {
1563return Seq->IsRegionEntry && Seq->HasCount;
1564 });
1565
1566if (!Mapped) {
1567return;
1568 }
1569
1570// Pick the max count from the non-gap, region entry segments and the
1571// wrapped count.
1572if (WrappedSegment)
1573 ExecutionCount = WrappedSegment->Count;
1574if (!MinRegionCount)
1575return;
1576for (constauto *LS : LineSegments)
1577if (isStartOfRegion(LS))
1578 ExecutionCount = std::max(ExecutionCount, LS->Count);
1579}
1580
1581LineCoverageIterator &LineCoverageIterator::operator++() {
1582if (Next == CD.end()) {
1583 Stats =LineCoverageStats();
1584 Ended =true;
1585return *this;
1586 }
1587if (Segments.size())
1588 WrappedSegment = Segments.back();
1589 Segments.clear();
1590while (Next != CD.end() && Next->Line == Line)
1591 Segments.push_back(&*Next++);
1592 Stats =LineCoverageStats(Segments, WrappedSegment, Line);
1593 ++Line;
1594return *this;
1595}
1596
1597static std::stringgetCoverageMapErrString(coveragemap_error Err,
1598const std::string &ErrMsg ="") {
1599 std::string Msg;
1600raw_string_ostreamOS(Msg);
1601
1602switch (Err) {
1603casecoveragemap_error::success:
1604OS <<"success";
1605break;
1606casecoveragemap_error::eof:
1607OS <<"end of File";
1608break;
1609casecoveragemap_error::no_data_found:
1610OS <<"no coverage data found";
1611break;
1612casecoveragemap_error::unsupported_version:
1613OS <<"unsupported coverage format version";
1614break;
1615casecoveragemap_error::truncated:
1616OS <<"truncated coverage data";
1617break;
1618casecoveragemap_error::malformed:
1619OS <<"malformed coverage data";
1620break;
1621casecoveragemap_error::decompression_failed:
1622OS <<"failed to decompress coverage data (zlib)";
1623break;
1624casecoveragemap_error::invalid_or_missing_arch_specifier:
1625OS <<"`-arch` specifier is invalid or missing for universal binary";
1626break;
1627 }
1628
1629// If optional error message is not empty, append it to the message.
1630if (!ErrMsg.empty())
1631OS <<": " << ErrMsg;
1632
1633return Msg;
1634}
1635
1636namespace{
1637
1638// FIXME: This class is only here to support the transition to llvm::Error. It
1639// will be removed once this transition is complete. Clients should prefer to
1640// deal with the Error value directly, rather than converting to error_code.
1641classCoverageMappingErrorCategoryType :public std::error_category {
1642constchar *name()const noexcept override{return"llvm.coveragemap"; }
1643 std::string message(int IE) const override{
1644returngetCoverageMapErrString(static_cast<coveragemap_error>(IE));
1645 }
1646};
1647
1648}// end anonymous namespace
1649
1650std::stringCoverageMapError::message() const{
1651returngetCoverageMapErrString(Err, Msg);
1652}
1653
1654const std::error_category &llvm::coverage::coveragemap_category() {
1655static CoverageMappingErrorCategoryType ErrorCategory;
1656return ErrorCategory;
1657}
1658
1659charCoverageMapError::ID = 0;
const
aarch64 promote const
Definition:AArch64PromoteConstant.cpp:230
ArrayRef.h
BuildID.h
This file declares a library for handling Build IDs and using them to find debug info.
B
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
A
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
E
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
CoverageMappingReader.h
gatherFileIDs
static SmallBitVector gatherFileIDs(StringRef SourceFile, const FunctionRecord &Function)
Definition:CoverageMapping.cpp:1383
findMainViewFileID
static std::optional< unsigned > findMainViewFileID(const FunctionRecord &Function)
Return the ID of the file where the definition of the function is located.
Definition:CoverageMapping.cpp:1394
isExpansion
static bool isExpansion(const CountedRegion &R, unsigned FileID)
Definition:CoverageMapping.cpp:1416
handleMaybeNoDataFoundError
static Error handleMaybeNoDataFoundError(Error E)
Definition:CoverageMapping.cpp:989
getMaxBitmapSize
static unsigned getMaxBitmapSize(const CoverageMappingRecord &Record, bool IsVersion11)
Returns the bit count.
Definition:CoverageMapping.cpp:645
getCoverageMapErrString
static std::string getCoverageMapErrString(coveragemap_error Err, const std::string &ErrMsg="")
Definition:CoverageMapping.cpp:1597
getMaxCounterID
static unsigned getMaxCounterID(const CounterMappingContext &Ctx, const CoverageMappingRecord &Record)
Definition:CoverageMapping.cpp:635
CoverageMapping.h
Expansion
DXIL Intrinsic Expansion
Definition:DXILIntrinsicExpansion.cpp:630
Idx
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
Definition:DeadArgumentElimination.cpp:353
Debug.h
LLVM_DEBUG
#define LLVM_DEBUG(...)
Definition:Debug.h:106
DenseMap.h
This file defines the DenseMap class.
End
bool End
Definition:ELF_riscv.cpp:480
Errc.h
simplify
hexagon bit simplify
Definition:HexagonBitSimplify.cpp:289
InstrProfReader.h
I
#define I(x, y, z)
Definition:MD5.cpp:58
MemoryBuffer.h
if
if(PassOpts->AAPipeline)
Definition:PassBuilderBindings.cpp:64
dominates
static bool dominates(InstrPosIndexes &PosIndexes, const MachineInstr &A, const MachineInstr &B)
Definition:RegAllocFast.cpp:485
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
name
static const char * name
Definition:SMEABIPass.cpp:46
STLExtras.h
This file contains some templates that are useful if you are working with the STL at all.
OS
raw_pwrite_stream & OS
Definition:SampleProfWriter.cpp:51
SmallBitVector.h
This file implements the SmallBitVector class.
SmallVector.h
This file defines the SmallVector class.
StringExtras.h
This file contains some functions that are useful when dealing with strings.
StringRef.h
VirtualFileSystem.h
Defines the virtual file system interface vfs::FileSystem.
RHS
Value * RHS
Definition:X86PartialReduction.cpp:74
LHS
Value * LHS
Definition:X86PartialReduction.cpp:73
MapT
T
llvm::ArrayRef
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition:ArrayRef.h:41
llvm::ArrayRef::front
const T & front() const
front - Get the first element.
Definition:ArrayRef.h:171
llvm::ArrayRef::end
iterator end() const
Definition:ArrayRef.h:157
llvm::ArrayRef::size
size_t size() const
size - Get the array size.
Definition:ArrayRef.h:168
llvm::ArrayRef::begin
iterator begin() const
Definition:ArrayRef.h:156
llvm::ArrayRef::empty
bool empty() const
empty - Check if the array is empty.
Definition:ArrayRef.h:163
llvm::BitVector
Definition:BitVector.h:82
llvm::DenseMap
Definition:DenseMap.h:727
llvm::DenseSet
Implements a dense probed hash-table based set.
Definition:DenseSet.h:278
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition:Error.h:160
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition:Error.h:337
llvm::Expected
Tagged union holding either a T or a Error.
Definition:Error.h:481
llvm::Expected::takeError
Error takeError()
Take ownership of the stored error.
Definition:Error.h:608
llvm::Function
Definition:Function.h:63
llvm::Function::begin
iterator begin()
Definition:Function.h:853
llvm::Function::size
size_t size() const
Definition:Function.h:858
llvm::Function::end
iterator end()
Definition:Function.h:855
llvm::IndexedInstrProfReader
Reader for the indexed binary instrprof format.
Definition:InstrProfReader.h:726
llvm::IndexedInstrProfReader::getVersion
uint64_t getVersion() const override
Return the profile version.
Definition:InstrProfReader.h:767
llvm::IndexedInstrProfReader::create
static Expected< std::unique_ptr< IndexedInstrProfReader > > create(const Twine &Path, vfs::FileSystem &FS, const Twine &RemappingPath="")
Factory method to create an indexed reader.
Definition:InstrProfReader.cpp:202
llvm::IndexedInstrProfReader::getFunctionBitmap
Error getFunctionBitmap(StringRef FuncName, uint64_t FuncHash, BitVector &Bitmap)
Fill Bitmap with the profile data for the given function name.
Definition:InstrProfReader.cpp:1694
llvm::IndexedInstrProfReader::hasSingleByteCoverage
bool hasSingleByteCoverage() const override
Return true if the profile has single byte counters representing coverage.
Definition:InstrProfReader.h:781
llvm::IndexedInstrProfReader::getFunctionCounts
Error getFunctionCounts(StringRef FuncName, uint64_t FuncHash, std::vector< uint64_t > &Counts)
Fill Counts with the profile data for the given function name.
Definition:InstrProfReader.cpp:1683
llvm::IndexedInstrProfReader::readBinaryIds
Error readBinaryIds(std::vector< llvm::object::BuildID > &BinaryIds) override
Read a list of binary ids.
Definition:InstrProfReader.cpp:1736
llvm::InstrProfError::take
static std::pair< instrprof_error, std::string > take(Error E)
Consume an Error and return the raw enum value contained within it, and the optional error message.
Definition:InstrProf.h:425
llvm::MemoryBufferRef
Definition:MemoryBufferRef.h:22
llvm::MemoryBuffer::getFileOrSTDIN
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFileOrSTDIN(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, or open stdin if the Filename is "-".
Definition:MemoryBuffer.cpp:163
llvm::MutableArrayRef
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
Definition:ArrayRef.h:310
llvm::MutableArrayRef::end
iterator end() const
Definition:ArrayRef.h:360
llvm::MutableArrayRef::begin
iterator begin() const
Definition:ArrayRef.h:359
llvm::MutableArrayRef::drop_back
MutableArrayRef< T > drop_back(size_t N=1) const
Definition:ArrayRef.h:395
llvm::Record
Definition:Record.h:1596
llvm::Region
Definition:RegionInfo.h:887
llvm::SmallBitVector
This is a 'bitvector' (really, a variable-sized bit array), optimized for the case when the array is ...
Definition:SmallBitVector.h:35
llvm::SmallBitVector::find_first
int find_first() const
Returns the index of the first set bit, -1 if none of the bits are set.
Definition:SmallBitVector.h:230
llvm::SmallVectorBase::empty
bool empty() const
Definition:SmallVector.h:81
llvm::SmallVectorBase::size
size_t size() const
Definition:SmallVector.h:78
llvm::SmallVectorImpl
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition:SmallVector.h:573
llvm::SmallVectorImpl::emplace_back
reference emplace_back(ArgTypes &&... Args)
Definition:SmallVector.h:937
llvm::SmallVectorImpl::erase
iterator erase(const_iterator CI)
Definition:SmallVector.h:737
llvm::SmallVectorImpl::insert
iterator insert(iterator I, T &&Elt)
Definition:SmallVector.h:805
llvm::SmallVectorTemplateBase::push_back
void push_back(const T &Elt)
Definition:SmallVector.h:413
llvm::SmallVectorTemplateCommon::end
iterator end()
Definition:SmallVector.h:269
llvm::SmallVectorTemplateCommon::begin
iterator begin()
Definition:SmallVector.h:267
llvm::SmallVectorTemplateCommon::back
reference back()
Definition:SmallVector.h:308
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition:SmallVector.h:1196
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition:StringRef.h:51
llvm::StringRef::empty
constexpr bool empty() const
empty - Check if the string is empty.
Definition:StringRef.h:147
llvm::Value
LLVM Value Representation.
Definition:Value.h:74
llvm::coverage::BinaryCoverageReader::create
static Expected< std::vector< std::unique_ptr< BinaryCoverageReader > > > create(MemoryBufferRef ObjectBuffer, StringRef Arch, SmallVectorImpl< std::unique_ptr< MemoryBuffer > > &ObjectFileBuffers, StringRef CompilationDir="", SmallVectorImpl< object::BuildIDRef > *BinaryIDs=nullptr)
Definition:CoverageMappingReader.cpp:1270
llvm::coverage::CounterExpressionBuilder::subtract
Counter subtract(Counter LHS, Counter RHS, bool Simplify=true)
Return a counter that represents the expression that subtracts RHS from LHS.
Definition:CoverageMapping.cpp:132
llvm::coverage::CounterExpressionBuilder::add
Counter add(Counter LHS, Counter RHS, bool Simplify=true)
Return a counter that represents the expression that adds LHS and RHS.
Definition:CoverageMapping.cpp:127
llvm::coverage::CounterExpressionBuilder::subst
Counter subst(Counter C, const SubstMap &Map)
Definition:CoverageMapping.cpp:138
llvm::coverage::CounterExpressionBuilder::SubstMap
std::map< Counter, Counter > SubstMap
K to V map.
Definition:CoverageMapping.h:221
llvm::coverage::CounterMappingContext
A Counter mapping context is used to connect the counters, expressions and the obtained counter value...
Definition:CoverageMapping.h:674
llvm::coverage::CounterMappingContext::evaluateMCDCRegion
Expected< MCDCRecord > evaluateMCDCRegion(const CounterMappingRegion &Region, ArrayRef< const CounterMappingRegion * > Branches, bool IsVersion11)
Return an MCDC record that indicates executed test vectors and condition pairs.
Definition:CoverageMapping.cpp:554
llvm::coverage::CounterMappingContext::evaluate
Expected< int64_t > evaluate(const Counter &C) const
Return the number of times that a region of code associated with this counter was executed.
Definition:CoverageMapping.cpp:193
llvm::coverage::CounterMappingContext::getMaxCounterID
unsigned getMaxCounterID(const Counter &C) const
Definition:CoverageMapping.cpp:562
llvm::coverage::CounterMappingContext::dump
void dump(const Counter &C, raw_ostream &OS) const
Definition:CoverageMapping.cpp:163
llvm::coverage::CoverageData
Coverage information to be processed or displayed.
Definition:CoverageMapping.h:932
llvm::coverage::CoverageData::end
std::vector< CoverageSegment >::const_iterator end() const
Definition:CoverageMapping.h:960
llvm::coverage::CoverageMapError
Definition:CoverageMapping.h:80
llvm::coverage::CoverageMapError::message
std::string message() const override
Return the error message as a string.
Definition:CoverageMapping.cpp:1650
llvm::coverage::CoverageMapError::ID
static char ID
Definition:CoverageMapping.h:98
llvm::coverage::CoverageMapError::get
coveragemap_error get() const
Definition:CoverageMapping.h:95
llvm::coverage::CoverageMapError::getMessage
const std::string & getMessage() const
Definition:CoverageMapping.h:96
llvm::coverage::CoverageMapping
The mapping of profile information to coverage data.
Definition:CoverageMapping.h:980
llvm::coverage::CoverageMapping::getUniqueSourceFiles
std::vector< StringRef > getUniqueSourceFiles() const
Returns a lexicographically sorted, unique list of files that are covered.
Definition:CoverageMapping.cpp:1373
llvm::coverage::CoverageMapping::getCoverageForExpansion
CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion) const
Get the coverage for an expansion within a coverage set.
Definition:CoverageMapping.cpp:1513
llvm::coverage::CoverageMapping::getCoverageForFunction
CoverageData getCoverageForFunction(const FunctionRecord &Function) const
Get the coverage for a particular function.
Definition:CoverageMapping.cpp:1481
llvm::coverage::CoverageMapping::getInstantiationGroups
std::vector< InstantiationGroup > getInstantiationGroups(StringRef Filename) const
Get the list of function instantiation groups in a particular file.
Definition:CoverageMapping.cpp:1456
llvm::coverage::CoverageMapping::getCoverageForFile
CoverageData getCoverageForFile(StringRef Filename) const
Get the coverage for a particular file.
Definition:CoverageMapping.cpp:1420
llvm::coverage::CoverageMapping::load
static Expected< std::unique_ptr< CoverageMapping > > load(ArrayRef< std::unique_ptr< CoverageMappingReader > > CoverageReaders, IndexedInstrProfReader &ProfileReader)
Load the coverage mapping using the given readers.
Definition:CoverageMapping.cpp:979
llvm::coverage::FunctionRecordIterator
Iterator over Functions, optionally filtered to a single file.
Definition:CoverageMapping.h:756
llvm::coverage::InstantiationGroup
An instantiation group contains a FunctionRecord list, such that each record corresponds to a distinc...
Definition:CoverageMapping.h:875
llvm::coverage::LineCoverageIterator
An iterator over the LineCoverageStats objects for lines described by a CoverageData instance.
Definition:CoverageMapping.h:1122
llvm::coverage::LineCoverageIterator::operator++
LineCoverageIterator & operator++()
Definition:CoverageMapping.cpp:1581
llvm::coverage::LineCoverageStats
Coverage statistics for a single line.
Definition:CoverageMapping.h:1087
llvm::coverage::MCDCRecord::TestVector
Emulate SmallVector<CondState> with a pair of BitVector.
Definition:CoverageMapping.h:404
llvm::coverage::MCDCRecord::TestVector::getIndex
auto getIndex() const
Equivalent to buildTestVector's Index.
Definition:CoverageMapping.h:419
llvm::coverage::MCDCRecord::TestVector::set
void set(int I, CondState Val)
Set the condition Val at position I.
Definition:CoverageMapping.h:423
llvm::coverage::mcdc::TVIdxBuilder
Compute TestVector Indices "TVIdx" from the Conds graph.
Definition:CoverageMapping.h:638
llvm::coverage::mcdc::TVIdxBuilder::HardMaxTVs
static constexpr auto HardMaxTVs
Hard limit of test vectors.
Definition:CoverageMapping.h:660
llvm::coverage::mcdc::TVIdxBuilder::TVIdxBuilder
TVIdxBuilder(const SmallVectorImpl< ConditionIDs > &NextIDs, int Offset=0)
Calculate and assign Indices.
Definition:CoverageMapping.cpp:283
llvm::coverage::mcdc::TVIdxBuilder::Indices
SmallVector< std::array< int, 2 > > Indices
Output: Index for TestVectors bitmap (These are not CondIDs)
Definition:CoverageMapping.h:653
llvm::coverage::mcdc::TVIdxBuilder::NumTestVectors
int NumTestVectors
Output: The number of test vectors.
Definition:CoverageMapping.h:657
llvm::coverage::mcdc::TVIdxBuilder::SavedNodes
SmallVector< MCDCNode > SavedNodes
This is no longer needed after the assignment.
Definition:CoverageMapping.h:649
llvm::detail::DenseSetImpl::insert
std::pair< iterator, bool > insert(const ValueT &V)
Definition:DenseSet.h:213
llvm::detail::DenseSetImpl::size
size_type size() const
Definition:DenseSet.h:81
llvm::detail::DenseSetImpl::contains
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
Definition:DenseSet.h:193
llvm::object::BuildIDFetcher
BuildIDFetcher searches local cache directories for debug info.
Definition:BuildID.h:39
llvm::object::BuildIDFetcher::fetch
virtual std::optional< std::string > fetch(BuildIDRef BuildID) const
Returns the path to the debug file with the given build ID.
Definition:BuildID.cpp:68
llvm::raw_ostream
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition:raw_ostream.h:52
llvm::raw_string_ostream
A raw_ostream that writes to an std::string.
Definition:raw_ostream.h:661
llvm::vfs::FileSystem
The virtual file system interface.
Definition:VirtualFileSystem.h:266
uint64_t
unsigned
ErrorHandling.h
llvm_unreachable
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition:ErrorHandling.h:143
Error.h
false
Definition:StackSlotColoring.cpp:193
llvm::CallingConv::C
@ C
The default llvm calling convention, compatible with C.
Definition:CallingConv.h:34
llvm::CallingConv::ID
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition:CallingConv.h:24
llvm::IndexedInstrProf::Version12
@ Version12
Definition:InstrProf.h:1116
llvm::M68k::MemAddrModeKind::L
@ L
llvm::MCID::Branch
@ Branch
Definition:MCInstrDesc.h:159
llvm::RISCVFenceField::R
@ R
Definition:RISCVBaseInfo.h:373
llvm::coverage::mcdc::ConditionID
int16_t ConditionID
The ID for MCDCBranch.
Definition:MCDCTypes.h:24
llvm::coverage::mcdc::ConditionIDs
std::array< ConditionID, 2 > ConditionIDs
Definition:MCDCTypes.h:25
llvm::coverage::coveragemap_category
const std::error_category & coveragemap_category()
Definition:CoverageMapping.cpp:1654
llvm::coverage::coveragemap_error
coveragemap_error
Definition:CoverageMapping.h:63
llvm::coverage::coveragemap_error::success
@ success
llvm::coverage::coveragemap_error::unsupported_version
@ unsupported_version
llvm::coverage::coveragemap_error::eof
@ eof
llvm::coverage::coveragemap_error::decompression_failed
@ decompression_failed
llvm::coverage::coveragemap_error::malformed
@ malformed
llvm::coverage::coveragemap_error::invalid_or_missing_arch_specifier
@ invalid_or_missing_arch_specifier
llvm::coverage::coveragemap_error::truncated
@ truncated
llvm::coverage::coveragemap_error::no_data_found
@ no_data_found
llvm::coverage::LineColPair
std::pair< unsigned, unsigned > LineColPair
Definition:CoverageMapping.h:228
llvm::logicalview::LVAttributeKind::Coverage
@ Coverage
llvm::ms_demangle::QualifierMangleMode::Result
@ Result
llvm::object::BuildID
SmallVector< uint8_t, 10 > BuildID
A build ID in binary form.
Definition:BuildID.h:25
llvm::pdb::PDB_TableType::Segments
@ Segments
llvm::wasm::ElemSegmentMode::Active
@ Active
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition:AddressRanges.h:18
llvm::Offset
@ Offset
Definition:DWP.cpp:480
llvm::hash_value
hash_code hash_value(const FixedPointSemantics &Val)
Definition:APFixedPoint.h:136
llvm::createFileError
Error createFileError(const Twine &F, Error E)
Concatenate a source file path and/or name with an Error.
Definition:Error.h:1385
llvm::size
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition:STLExtras.h:1697
llvm::enumerate
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition:STLExtras.h:2448
llvm::getFuncNameWithoutPrefix
StringRef getFuncNameWithoutPrefix(StringRef PGOFuncName, StringRef FileName="<unknown>")
Given a PGO function name, remove the filename prefix and return the original (static) function name.
Definition:InstrProf.cpp:410
llvm::handleErrors
Error handleErrors(Error E, HandlerTs &&... Hs)
Pass the ErrorInfo(s) contained in E to their respective handlers.
Definition:Error.h:954
llvm::append_range
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition:STLExtras.h:2115
llvm::unique
auto unique(Range &&R, Predicate P)
Definition:STLExtras.h:2055
llvm::createStringError
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition:Error.h:1291
llvm::map_range
auto map_range(ContainerTy &&C, FuncTy F)
Definition:STLExtras.h:377
llvm::errc::no_such_file_or_directory
@ no_such_file_or_directory
llvm::errc::argument_out_of_domain
@ argument_out_of_domain
llvm::any_of
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition:STLExtras.h:1746
llvm::reverse
auto reverse(ContainerTy &&C)
Definition:STLExtras.h:420
llvm::sort
void sort(IteratorTy Start, IteratorTy End)
Definition:STLExtras.h:1664
llvm::dbgs
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition:Debug.cpp:163
llvm::instrprof_error
instrprof_error
Definition:InstrProf.h:354
llvm::instrprof_error::unknown_function
@ unknown_function
llvm::instrprof_error::hash_mismatch
@ hash_mismatch
llvm::alignTo
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition:Alignment.h:155
llvm::PseudoProbeReservedId::Last
@ Last
llvm::errorCodeToError
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition:Error.cpp:111
llvm::consumeError
void consumeError(Error Err)
Consume a Error without doing anything.
Definition:Error.h:1069
llvm::hash_combine_range
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last)
Compute a hash_code for a sequence of values.
Definition:Hashing.h:468
llvm::InstrProfKind::SingleByteCoverage
@ SingleByteCoverage
raw_ostream.h
N
#define N
llvm::coverage::CountedRegion
Associates a source range with an execution count.
Definition:CoverageMapping.h:372
llvm::coverage::CounterExpression
A Counter expression is a value that represents an arithmetic operation with two counters.
Definition:CoverageMapping.h:164
llvm::coverage::CounterExpression::Add
@ Add
Definition:CoverageMapping.h:165
llvm::coverage::CounterExpression::Subtract
@ Subtract
Definition:CoverageMapping.h:165
llvm::coverage::CounterMappingRegion
A Counter mapping region associates a source range with a specific counter.
Definition:CoverageMapping.h:231
llvm::coverage::CounterMappingRegion::FileID
unsigned FileID
Definition:CoverageMapping.h:279
llvm::coverage::CounterMappingRegion::Kind
RegionKind Kind
Definition:CoverageMapping.h:283
llvm::coverage::CounterMappingRegion::ExpansionRegion
@ ExpansionRegion
An ExpansionRegion represents a file expansion region that associates a source range with the expansi...
Definition:CoverageMapping.h:239
llvm::coverage::CounterMappingRegion::MCDCDecisionRegion
@ MCDCDecisionRegion
A DecisionRegion represents a top-level boolean expression and is associated with a variable length b...
Definition:CoverageMapping.h:256
llvm::coverage::CounterMappingRegion::MCDCBranchRegion
@ MCDCBranchRegion
A Branch Region can be extended to include IDs to facilitate MC/DC.
Definition:CoverageMapping.h:259
llvm::coverage::CounterMappingRegion::SkippedRegion
@ SkippedRegion
A SkippedRegion represents a source range with code that was skipped by a preprocessor or similar mea...
Definition:CoverageMapping.h:243
llvm::coverage::CounterMappingRegion::GapRegion
@ GapRegion
A GapRegion is like a CodeRegion, but its count is only set as the line execution count when its the ...
Definition:CoverageMapping.h:247
llvm::coverage::CounterMappingRegion::CodeRegion
@ CodeRegion
A CodeRegion associates some code with a counter.
Definition:CoverageMapping.h:234
llvm::coverage::Counter
A Counter is an abstract value that describes how to compute the execution count for a region of code...
Definition:CoverageMapping.h:107
llvm::coverage::Counter::getZero
static Counter getZero()
Return the counter that represents the number zero.
Definition:CoverageMapping.h:148
llvm::coverage::Counter::getCounter
static Counter getCounter(unsigned CounterId)
Return the counter that corresponds to a specific profile counter.
Definition:CoverageMapping.h:151
llvm::coverage::Counter::Expression
@ Expression
Definition:CoverageMapping.h:110
llvm::coverage::Counter::CounterValueReference
@ CounterValueReference
Definition:CoverageMapping.h:110
llvm::coverage::Counter::Zero
@ Zero
Definition:CoverageMapping.h:110
llvm::coverage::Counter::getExpression
static Counter getExpression(unsigned ExpressionId)
Return the counter that corresponds to a specific addition counter expression.
Definition:CoverageMapping.h:157
llvm::coverage::CoverageMappingRecord
Coverage mapping information for a single function.
Definition:CoverageMappingReader.h:35
llvm::coverage::CoverageSegment
The execution count information starting at a point in a file.
Definition:CoverageMapping.h:838
llvm::coverage::CoverageSegment::HasCount
bool HasCount
When false, the segment was uninstrumented or skipped.
Definition:CoverageMapping.h:846
llvm::coverage::CoverageSegment::Count
uint64_t Count
The execution count, or zero if no count was recorded.
Definition:CoverageMapping.h:844
llvm::coverage::CoverageSegment::IsGapRegion
bool IsGapRegion
Whether this enters a gap region.
Definition:CoverageMapping.h:850
llvm::coverage::ExpansionRecord
Coverage information for a macro expansion or #included file.
Definition:CoverageMapping.h:821
llvm::coverage::FunctionRecord
Code coverage information for a single function.
Definition:CoverageMapping.h:705
llvm::coverage::MCDCRecord
MCDC Record grouping all information together.
Definition:CoverageMapping.h:390
llvm::coverage::MCDCRecord::findIndependencePairs
void findIndependencePairs()
Definition:CoverageMapping.cpp:253
llvm::coverage::MCDCRecord::MCDC_DontCare
@ MCDC_DontCare
Definition:CoverageMapping.h:397
llvm::coverage::MCDCRecord::MCDC_True
@ MCDC_True
Definition:CoverageMapping.h:397
llvm::coverage::MCDCRecord::MCDC_False
@ MCDC_False
Definition:CoverageMapping.h:397
llvm::coverage::MCDCRecord::BoolVector
std::array< BitVector, 2 > BoolVector
Definition:CoverageMapping.h:452
llvm::coverage::mcdc::DecisionParameters
Definition:MCDCTypes.h:27
llvm::coverage::mcdc::DecisionParameters::NumConditions
uint16_t NumConditions
Number of Conditions used for a Decision Region.
Definition:MCDCTypes.h:32

Generated on Fri Jul 18 2025 11:47:20 for LLVM by doxygen 1.9.6
[8]ページ先頭

©2009-2025 Movatter.jp