14
14
#include " llvm/ProfileData/Coverage/CoverageMapping.h"
15
15
#include " llvm/ADT/ArrayRef.h"
16
16
#include " llvm/ADT/DenseMap.h"
17
+ #include " llvm/ADT/STLExtras.h"
17
18
#include " llvm/ADT/SmallBitVector.h"
18
19
#include " llvm/ADT/SmallVector.h"
19
20
#include " llvm/ADT/StringExtras.h"
@@ -523,6 +524,160 @@ static unsigned getMaxBitmapSize(const CounterMappingContext &Ctx,
523
524
return MaxBitmapID + (SizeInBits / CHAR_BIT);
524
525
}
525
526
527
+ namespace {
528
+
529
+ // / Collect Decisions, Branchs, and Expansions and associate them.
530
+ class MCDCDecisionRecorder {
531
+ private:
532
+ // / This holds the DecisionRegion and MCDCBranches under it.
533
+ // / Also traverses Expansion(s).
534
+ // / The Decision has the number of MCDCBranches and will complete
535
+ // / when it is filled with unique ConditionID of MCDCBranches.
536
+ struct DecisionRecord {
537
+ const CounterMappingRegion *DecisionRegion;
538
+
539
+ // / They are reflected from DecisionRegion for convenience.
540
+ LineColPair DecisionStartLoc;
541
+ LineColPair DecisionEndLoc;
542
+
543
+ // / This is passed to `MCDCRecordProcessor`, so this should be compatible
544
+ // / to`ArrayRef<const CounterMappingRegion *>`.
545
+ SmallVector<const CounterMappingRegion *> MCDCBranches;
546
+
547
+ // / IDs that are stored in MCDCBranches
548
+ // / Complete when all IDs (1 to NumConditions) are met.
549
+ DenseSet<CounterMappingRegion::MCDCConditionID> ConditionIDs;
550
+
551
+ // / Set of IDs of Expansion(s) that are relevant to DecisionRegion
552
+ // / and its children (via expansions).
553
+ // / FileID pointed by ExpandedFileID is dedicated to the expansion, so
554
+ // / the location in the expansion doesn't matter.
555
+ DenseSet<unsigned > ExpandedFileIDs;
556
+
557
+ DecisionRecord (const CounterMappingRegion &Decision)
558
+ : DecisionRegion(&Decision), DecisionStartLoc(Decision.startLoc()),
559
+ DecisionEndLoc (Decision.endLoc()) {
560
+ assert (Decision.Kind == CounterMappingRegion::MCDCDecisionRegion);
561
+ }
562
+
563
+ // / Determine whether DecisionRecord dominates `R`.
564
+ bool dominates (const CounterMappingRegion &R) const {
565
+ // Determine whether `R` is included in `DecisionRegion`.
566
+ if (R.FileID == DecisionRegion->FileID &&
567
+ R.startLoc () >= DecisionStartLoc && R.endLoc () <= DecisionEndLoc)
568
+ return true ;
569
+
570
+ // Determine whether `R` is pointed by any of Expansions.
571
+ return ExpandedFileIDs.contains (R.FileID );
572
+ }
573
+
574
+ enum Result {
575
+ NotProcessed = 0 , // / Irrelevant to this Decision
576
+ Processed, // / Added to this Decision
577
+ Completed, // / Added and filled this Decision
578
+ };
579
+
580
+ // / Add Branch into the Decision
581
+ // / \param Branch expects MCDCBranchRegion
582
+ // / \returns NotProcessed/Processed/Completed
583
+ Result addBranch (const CounterMappingRegion &Branch) {
584
+ assert (Branch.Kind == CounterMappingRegion::MCDCBranchRegion);
585
+
586
+ auto ConditionID = Branch.MCDCParams .ID ;
587
+ assert (ConditionID > 0 && " ConditionID should begin with 1" );
588
+
589
+ if (ConditionIDs.contains (ConditionID) ||
590
+ ConditionID > DecisionRegion->MCDCParams .NumConditions )
591
+ return NotProcessed;
592
+
593
+ if (!this ->dominates (Branch))
594
+ return NotProcessed;
595
+
596
+ assert (MCDCBranches.size () < DecisionRegion->MCDCParams .NumConditions );
597
+
598
+ // Put `ID=1` in front of `MCDCBranches` for convenience
599
+ // even if `MCDCBranches` is not topological.
600
+ if (ConditionID == 1 )
601
+ MCDCBranches.insert (MCDCBranches.begin (), &Branch);
602
+ else
603
+ MCDCBranches.push_back (&Branch);
604
+
605
+ // Mark `ID` as `assigned`.
606
+ ConditionIDs.insert (ConditionID);
607
+
608
+ // `Completed` when `MCDCBranches` is full
609
+ return (MCDCBranches.size () == DecisionRegion->MCDCParams .NumConditions
610
+ ? Completed
611
+ : Processed);
612
+ }
613
+
614
+ // / Record Expansion if it is relevant to this Decision.
615
+ // / Each `Expansion` may nest.
616
+ // / \returns true if recorded.
617
+ bool recordExpansion (const CounterMappingRegion &Expansion) {
618
+ if (!this ->dominates (Expansion))
619
+ return false ;
620
+
621
+ ExpandedFileIDs.insert (Expansion.ExpandedFileID );
622
+ return true ;
623
+ }
624
+ };
625
+
626
+ private:
627
+ // / Decisions in progress
628
+ // / DecisionRecord is added for each MCDCDecisionRegion.
629
+ // / DecisionRecord is removed when Decision is completed.
630
+ SmallVector<DecisionRecord> Decisions;
631
+
632
+ public:
633
+ ~MCDCDecisionRecorder () {
634
+ assert (Decisions.empty () && " All Decisions have not been resolved" );
635
+ }
636
+
637
+ // / Register Region and start recording.
638
+ void registerDecision (const CounterMappingRegion &Decision) {
639
+ Decisions.emplace_back (Decision);
640
+ }
641
+
642
+ void recordExpansion (const CounterMappingRegion &Expansion) {
643
+ any_of (Decisions, [&Expansion](auto &Decision) {
644
+ return Decision.recordExpansion (Expansion);
645
+ });
646
+ }
647
+
648
+ using DecisionAndBranches =
649
+ std::pair<const CounterMappingRegion *, // / Decision
650
+ SmallVector<const CounterMappingRegion *> // / Branches
651
+ >;
652
+
653
+ // / Add MCDCBranchRegion to DecisionRecord.
654
+ // / \param Branch to be processed
655
+ // / \returns DecisionsAndBranches if DecisionRecord completed.
656
+ // / Or returns nullopt.
657
+ std::optional<DecisionAndBranches>
658
+ processBranch (const CounterMappingRegion &Branch) {
659
+ // Seek each Decision and apply Region to it.
660
+ for (auto DecisionIter = Decisions.begin (), DecisionEnd = Decisions.end ();
661
+ DecisionIter != DecisionEnd; ++DecisionIter)
662
+ switch (DecisionIter->addBranch (Branch)) {
663
+ case DecisionRecord::NotProcessed:
664
+ continue ;
665
+ case DecisionRecord::Processed:
666
+ return std::nullopt;
667
+ case DecisionRecord::Completed:
668
+ DecisionAndBranches Result =
669
+ std::make_pair (DecisionIter->DecisionRegion ,
670
+ std::move (DecisionIter->MCDCBranches ));
671
+ Decisions.erase (DecisionIter); // No longer used.
672
+ return Result;
673
+ }
674
+
675
+ llvm_unreachable (" Branch not found in Decisions" );
676
+ }
677
+ };
678
+
679
+ } // namespace
680
+
526
681
Error CoverageMapping::loadFunctionRecord (
527
682
const CoverageMappingRecord &Record,
528
683
IndexedInstrProfReader &ProfileReader) {
@@ -579,18 +734,13 @@ Error CoverageMapping::loadFunctionRecord(
579
734
Record.MappingRegions [0 ].Count .isZero () && Counts[0 ] > 0 )
580
735
return Error::success ();
581
736
582
- unsigned NumConds = 0 ;
583
- const CounterMappingRegion *MCDCDecision;
584
- std::vector<const CounterMappingRegion *> MCDCBranches;
585
-
737
+ MCDCDecisionRecorder MCDCDecisions;
586
738
FunctionRecord Function (OrigFuncName, Record.Filenames );
587
739
for (const auto &Region : Record.MappingRegions ) {
588
- // If an MCDCDecisionRegion is seen, track the BranchRegions that follow
589
- // it according to Region.NumConditions .
740
+ // MCDCDecisionRegion should be handled first since it overlaps with
741
+ // others inside .
590
742
if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion) {
591
- assert (NumConds == 0 );
592
- MCDCDecision = &Region;
593
- NumConds = Region.MCDCParams .NumConditions ;
743
+ MCDCDecisions.registerDecision (Region);
594
744
continue ;
595
745
}
596
746
Expected<int64_t > ExecutionCount = Ctx.evaluate (Region.Count );
@@ -605,43 +755,47 @@ Error CoverageMapping::loadFunctionRecord(
605
755
}
606
756
Function.pushRegion (Region, *ExecutionCount, *AltExecutionCount);
607
757
608
- // If a MCDCDecisionRegion was seen, store the BranchRegions that
609
- // correspond to it in a vector, according to the number of conditions
610
- // recorded for the region (tracked by NumConds).
611
- if (NumConds > 0 && Region.Kind == CounterMappingRegion::MCDCBranchRegion) {
612
- MCDCBranches.push_back (&Region);
613
-
614
- // As we move through all of the MCDCBranchRegions that follow the
615
- // MCDCDecisionRegion, decrement NumConds to make sure we account for
616
- // them all before we calculate the bitmap of executed test vectors.
617
- if (--NumConds == 0 ) {
618
- // Evaluating the test vector bitmap for the decision region entails
619
- // calculating precisely what bits are pertinent to this region alone.
620
- // This is calculated based on the recorded offset into the global
621
- // profile bitmap; the length is calculated based on the recorded
622
- // number of conditions.
623
- Expected<BitVector> ExecutedTestVectorBitmap =
624
- Ctx.evaluateBitmap (MCDCDecision);
625
- if (auto E = ExecutedTestVectorBitmap.takeError ()) {
626
- consumeError (std::move (E));
627
- return Error::success ();
628
- }
758
+ // Record ExpansionRegion.
759
+ if (Region.Kind == CounterMappingRegion::ExpansionRegion) {
760
+ MCDCDecisions.recordExpansion (Region);
761
+ continue ;
762
+ }
629
763
630
- // Since the bitmap identifies the executed test vectors for an MC/DC
631
- // DecisionRegion, all of the information is now available to process.
632
- // This is where the bulk of the MC/DC progressing takes place.
633
- Expected<MCDCRecord> Record = Ctx.evaluateMCDCRegion (
634
- *MCDCDecision, *ExecutedTestVectorBitmap, MCDCBranches);
635
- if (auto E = Record.takeError ()) {
636
- consumeError (std::move (E));
637
- return Error::success ();
638
- }
764
+ // Do nothing unless MCDCBranchRegion.
765
+ if (Region.Kind != CounterMappingRegion::MCDCBranchRegion)
766
+ continue ;
639
767
640
- // Save the MC/DC Record so that it can be visualized later.
641
- Function.pushMCDCRecord (*Record);
642
- MCDCBranches.clear ();
643
- }
768
+ auto Result = MCDCDecisions.processBranch (Region);
769
+ if (!Result) // Any Decision doesn't complete.
770
+ continue ;
771
+
772
+ auto MCDCDecision = Result->first ;
773
+ auto &MCDCBranches = Result->second ;
774
+
775
+ // Evaluating the test vector bitmap for the decision region entails
776
+ // calculating precisely what bits are pertinent to this region alone.
777
+ // This is calculated based on the recorded offset into the global
778
+ // profile bitmap; the length is calculated based on the recorded
779
+ // number of conditions.
780
+ Expected<BitVector> ExecutedTestVectorBitmap =
781
+ Ctx.evaluateBitmap (MCDCDecision);
782
+ if (auto E = ExecutedTestVectorBitmap.takeError ()) {
783
+ consumeError (std::move (E));
784
+ return Error::success ();
644
785
}
786
+
787
+ // Since the bitmap identifies the executed test vectors for an MC/DC
788
+ // DecisionRegion, all of the information is now available to process.
789
+ // This is where the bulk of the MC/DC progressing takes place.
790
+ Expected<MCDCRecord> Record = Ctx.evaluateMCDCRegion (
791
+ *MCDCDecision, *ExecutedTestVectorBitmap, MCDCBranches);
792
+ if (auto E = Record.takeError ()) {
793
+ consumeError (std::move (E));
794
+ return Error::success ();
795
+ }
796
+
797
+ // Save the MC/DC Record so that it can be visualized later.
798
+ Function.pushMCDCRecord (*Record);
645
799
}
646
800
647
801
// Don't create records for (filenames, function) pairs we've already seen.
0 commit comments