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"
@@ -583,6 +584,160 @@ static unsigned getMaxBitmapSize(const CounterMappingContext &Ctx,
583
584
return MaxBitmapID + (SizeInBits / CHAR_BIT);
584
585
}
585
586
587
+ namespace {
588
+
589
+ // / Collect Decisions, Branchs, and Expansions and associate them.
590
+ class MCDCDecisionRecorder {
591
+ private:
592
+ // / This holds the DecisionRegion and MCDCBranches under it.
593
+ // / Also traverses Expansion(s).
594
+ // / The Decision has the number of MCDCBranches and will complete
595
+ // / when it is filled with unique ConditionID of MCDCBranches.
596
+ struct DecisionRecord {
597
+ const CounterMappingRegion *DecisionRegion;
598
+
599
+ // / They are reflected from DecisionRegion for convenience.
600
+ LineColPair DecisionStartLoc;
601
+ LineColPair DecisionEndLoc;
602
+
603
+ // / This is passed to `MCDCRecordProcessor`, so this should be compatible
604
+ // / to`ArrayRef<const CounterMappingRegion *>`.
605
+ SmallVector<const CounterMappingRegion *> MCDCBranches;
606
+
607
+ // / IDs that are stored in MCDCBranches
608
+ // / Complete when all IDs (1 to NumConditions) are met.
609
+ DenseSet<CounterMappingRegion::MCDCConditionID> ConditionIDs;
610
+
611
+ // / Set of IDs of Expansion(s) that are relevant to DecisionRegion
612
+ // / and its children (via expansions).
613
+ // / FileID pointed by ExpandedFileID is dedicated to the expansion, so
614
+ // / the location in the expansion doesn't matter.
615
+ DenseSet<unsigned > ExpandedFileIDs;
616
+
617
+ DecisionRecord (const CounterMappingRegion &Decision)
618
+ : DecisionRegion(&Decision), DecisionStartLoc(Decision.startLoc()),
619
+ DecisionEndLoc (Decision.endLoc()) {
620
+ assert (Decision.Kind == CounterMappingRegion::MCDCDecisionRegion);
621
+ }
622
+
623
+ // / Determine whether DecisionRecord dominates `R`.
624
+ bool dominates (const CounterMappingRegion &R) const {
625
+ // Determine whether `R` is included in `DecisionRegion`.
626
+ if (R.FileID == DecisionRegion->FileID &&
627
+ R.startLoc () >= DecisionStartLoc && R.endLoc () <= DecisionEndLoc)
628
+ return true ;
629
+
630
+ // Determine whether `R` is pointed by any of Expansions.
631
+ return ExpandedFileIDs.contains (R.FileID );
632
+ }
633
+
634
+ enum Result {
635
+ NotProcessed = 0 , // / Irrelevant to this Decision
636
+ Processed, // / Added to this Decision
637
+ Completed, // / Added and filled this Decision
638
+ };
639
+
640
+ // / Add Branch into the Decision
641
+ // / \param Branch expects MCDCBranchRegion
642
+ // / \returns NotProcessed/Processed/Completed
643
+ Result addBranch (const CounterMappingRegion &Branch) {
644
+ assert (Branch.Kind == CounterMappingRegion::MCDCBranchRegion);
645
+
646
+ auto ConditionID = Branch.MCDCParams .ID ;
647
+ assert (ConditionID > 0 && " ConditionID should begin with 1" );
648
+
649
+ if (ConditionIDs.contains (ConditionID) ||
650
+ ConditionID > DecisionRegion->MCDCParams .NumConditions )
651
+ return NotProcessed;
652
+
653
+ if (!this ->dominates (Branch))
654
+ return NotProcessed;
655
+
656
+ assert (MCDCBranches.size () < DecisionRegion->MCDCParams .NumConditions );
657
+
658
+ // Put `ID=1` in front of `MCDCBranches` for convenience
659
+ // even if `MCDCBranches` is not topological.
660
+ if (ConditionID == 1 )
661
+ MCDCBranches.insert (MCDCBranches.begin (), &Branch);
662
+ else
663
+ MCDCBranches.push_back (&Branch);
664
+
665
+ // Mark `ID` as `assigned`.
666
+ ConditionIDs.insert (ConditionID);
667
+
668
+ // `Completed` when `MCDCBranches` is full
669
+ return (MCDCBranches.size () == DecisionRegion->MCDCParams .NumConditions
670
+ ? Completed
671
+ : Processed);
672
+ }
673
+
674
+ // / Record Expansion if it is relevant to this Decision.
675
+ // / Each `Expansion` may nest.
676
+ // / \returns true if recorded.
677
+ bool recordExpansion (const CounterMappingRegion &Expansion) {
678
+ if (!this ->dominates (Expansion))
679
+ return false ;
680
+
681
+ ExpandedFileIDs.insert (Expansion.ExpandedFileID );
682
+ return true ;
683
+ }
684
+ };
685
+
686
+ private:
687
+ // / Decisions in progress
688
+ // / DecisionRecord is added for each MCDCDecisionRegion.
689
+ // / DecisionRecord is removed when Decision is completed.
690
+ SmallVector<DecisionRecord> Decisions;
691
+
692
+ public:
693
+ ~MCDCDecisionRecorder () {
694
+ assert (Decisions.empty () && " All Decisions have not been resolved" );
695
+ }
696
+
697
+ // / Register Region and start recording.
698
+ void registerDecision (const CounterMappingRegion &Decision) {
699
+ Decisions.emplace_back (Decision);
700
+ }
701
+
702
+ void recordExpansion (const CounterMappingRegion &Expansion) {
703
+ any_of (Decisions, [&Expansion](auto &Decision) {
704
+ return Decision.recordExpansion (Expansion);
705
+ });
706
+ }
707
+
708
+ using DecisionAndBranches =
709
+ std::pair<const CounterMappingRegion *, // / Decision
710
+ SmallVector<const CounterMappingRegion *> // / Branches
711
+ >;
712
+
713
+ // / Add MCDCBranchRegion to DecisionRecord.
714
+ // / \param Branch to be processed
715
+ // / \returns DecisionsAndBranches if DecisionRecord completed.
716
+ // / Or returns nullopt.
717
+ std::optional<DecisionAndBranches>
718
+ processBranch (const CounterMappingRegion &Branch) {
719
+ // Seek each Decision and apply Region to it.
720
+ for (auto DecisionIter = Decisions.begin (), DecisionEnd = Decisions.end ();
721
+ DecisionIter != DecisionEnd; ++DecisionIter)
722
+ switch (DecisionIter->addBranch (Branch)) {
723
+ case DecisionRecord::NotProcessed:
724
+ continue ;
725
+ case DecisionRecord::Processed:
726
+ return std::nullopt;
727
+ case DecisionRecord::Completed:
728
+ DecisionAndBranches Result =
729
+ std::make_pair (DecisionIter->DecisionRegion ,
730
+ std::move (DecisionIter->MCDCBranches ));
731
+ Decisions.erase (DecisionIter); // No longer used.
732
+ return Result;
733
+ }
734
+
735
+ llvm_unreachable (" Branch not found in Decisions" );
736
+ }
737
+ };
738
+
739
+ } // namespace
740
+
586
741
Error CoverageMapping::loadFunctionRecord (
587
742
const CoverageMappingRecord &Record,
588
743
IndexedInstrProfReader &ProfileReader) {
@@ -639,18 +794,13 @@ Error CoverageMapping::loadFunctionRecord(
639
794
Record.MappingRegions [0 ].Count .isZero () && Counts[0 ] > 0 )
640
795
return Error::success ();
641
796
642
- unsigned NumConds = 0 ;
643
- const CounterMappingRegion *MCDCDecision;
644
- std::vector<const CounterMappingRegion *> MCDCBranches;
645
-
797
+ MCDCDecisionRecorder MCDCDecisions;
646
798
FunctionRecord Function (OrigFuncName, Record.Filenames );
647
799
for (const auto &Region : Record.MappingRegions ) {
648
- // If an MCDCDecisionRegion is seen, track the BranchRegions that follow
649
- // it according to Region.NumConditions .
800
+ // MCDCDecisionRegion should be handled first since it overlaps with
801
+ // others inside .
650
802
if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion) {
651
- assert (NumConds == 0 );
652
- MCDCDecision = &Region;
653
- NumConds = Region.MCDCParams .NumConditions ;
803
+ MCDCDecisions.registerDecision (Region);
654
804
continue ;
655
805
}
656
806
Expected<int64_t > ExecutionCount = Ctx.evaluate (Region.Count );
@@ -665,43 +815,47 @@ Error CoverageMapping::loadFunctionRecord(
665
815
}
666
816
Function.pushRegion (Region, *ExecutionCount, *AltExecutionCount);
667
817
668
- // If a MCDCDecisionRegion was seen, store the BranchRegions that
669
- // correspond to it in a vector, according to the number of conditions
670
- // recorded for the region (tracked by NumConds).
671
- if (NumConds > 0 && Region.Kind == CounterMappingRegion::MCDCBranchRegion) {
672
- MCDCBranches.push_back (&Region);
673
-
674
- // As we move through all of the MCDCBranchRegions that follow the
675
- // MCDCDecisionRegion, decrement NumConds to make sure we account for
676
- // them all before we calculate the bitmap of executed test vectors.
677
- if (--NumConds == 0 ) {
678
- // Evaluating the test vector bitmap for the decision region entails
679
- // calculating precisely what bits are pertinent to this region alone.
680
- // This is calculated based on the recorded offset into the global
681
- // profile bitmap; the length is calculated based on the recorded
682
- // number of conditions.
683
- Expected<BitVector> ExecutedTestVectorBitmap =
684
- Ctx.evaluateBitmap (MCDCDecision);
685
- if (auto E = ExecutedTestVectorBitmap.takeError ()) {
686
- consumeError (std::move (E));
687
- return Error::success ();
688
- }
818
+ // Record ExpansionRegion.
819
+ if (Region.Kind == CounterMappingRegion::ExpansionRegion) {
820
+ MCDCDecisions.recordExpansion (Region);
821
+ continue ;
822
+ }
689
823
690
- // Since the bitmap identifies the executed test vectors for an MC/DC
691
- // DecisionRegion, all of the information is now available to process.
692
- // This is where the bulk of the MC/DC progressing takes place.
693
- Expected<MCDCRecord> Record = Ctx.evaluateMCDCRegion (
694
- *MCDCDecision, *ExecutedTestVectorBitmap, MCDCBranches);
695
- if (auto E = Record.takeError ()) {
696
- consumeError (std::move (E));
697
- return Error::success ();
698
- }
824
+ // Do nothing unless MCDCBranchRegion.
825
+ if (Region.Kind != CounterMappingRegion::MCDCBranchRegion)
826
+ continue ;
699
827
700
- // Save the MC/DC Record so that it can be visualized later.
701
- Function.pushMCDCRecord (*Record);
702
- MCDCBranches.clear ();
703
- }
828
+ auto Result = MCDCDecisions.processBranch (Region);
829
+ if (!Result) // Any Decision doesn't complete.
830
+ continue ;
831
+
832
+ auto MCDCDecision = Result->first ;
833
+ auto &MCDCBranches = Result->second ;
834
+
835
+ // Evaluating the test vector bitmap for the decision region entails
836
+ // calculating precisely what bits are pertinent to this region alone.
837
+ // This is calculated based on the recorded offset into the global
838
+ // profile bitmap; the length is calculated based on the recorded
839
+ // number of conditions.
840
+ Expected<BitVector> ExecutedTestVectorBitmap =
841
+ Ctx.evaluateBitmap (MCDCDecision);
842
+ if (auto E = ExecutedTestVectorBitmap.takeError ()) {
843
+ consumeError (std::move (E));
844
+ return Error::success ();
704
845
}
846
+
847
+ // Since the bitmap identifies the executed test vectors for an MC/DC
848
+ // DecisionRegion, all of the information is now available to process.
849
+ // This is where the bulk of the MC/DC progressing takes place.
850
+ Expected<MCDCRecord> Record = Ctx.evaluateMCDCRegion (
851
+ *MCDCDecision, *ExecutedTestVectorBitmap, MCDCBranches);
852
+ if (auto E = Record.takeError ()) {
853
+ consumeError (std::move (E));
854
+ return Error::success ();
855
+ }
856
+
857
+ // Save the MC/DC Record so that it can be visualized later.
858
+ Function.pushMCDCRecord (*Record);
705
859
}
706
860
707
861
// Don't create records for (filenames, function) pairs we've already seen.
0 commit comments