@@ -365,11 +365,15 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
365365 unsigned NumConditions;
366366
367367 // / Vector used to track whether a condition is constant folded.
368- MCDCRecord::BoolVector Folded ;
368+ MCDCRecord::ResultVector CondResults ;
369369
370370 // / Mapping of calculated MC/DC Independence Pairs for each condition.
371371 MCDCRecord::TVPairMap IndependencePairs;
372372
373+ // / All possible Test Vectors for the boolean expression derived from
374+ // / binary decision diagran of the expression.
375+ MCDCRecord::TestVectors TestVectors;
376+
373377 // / Storage for ExecVectors
374378 // / ExecVectors is the alias of its 0th element.
375379 std::array<MCDCRecord::TestVectors, 2 > ExecVectorsByCond;
@@ -395,8 +399,9 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
395399 : NextIDsBuilder(Branches), TVIdxBuilder(this ->NextIDs), Bitmap(Bitmap),
396400 Region (Region), DecisionParams(Region.getDecisionParams()),
397401 Branches(Branches), NumConditions(DecisionParams.NumConditions),
398- Folded(NumConditions, false ), IndependencePairs(NumConditions),
399- ExecVectors(ExecVectorsByCond[false ]), IsVersion11(IsVersion11) {}
402+ CondResults(NumConditions, MCDCRecord::CondResult::MCDC_Normal),
403+ IndependencePairs(NumConditions), ExecVectors(ExecVectorsByCond[false ]),
404+ IsVersion11(IsVersion11) {}
400405
401406private:
402407 // Walk the binary decision diagram and try assigning both false and true to
@@ -418,6 +423,7 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
418423
419424 assert (TVIdx < SavedNodes[ID].Width );
420425 assert (TVIdxs.insert (NextTVIdx).second && " Duplicate TVIdx" );
426+ TestVectors.push_back ({TV, MCDCCond});
421427
422428 if (!Bitmap[IsVersion11
423429 ? DecisionParams.BitmapIdx * CHAR_BIT + TV.getIndex ()
@@ -445,7 +451,6 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
445451 buildTestVector (TV, 0 , 0 );
446452 assert (TVIdxs.size () == unsigned (NumTestVectors) &&
447453 " TVIdxs wasn't fulfilled" );
448-
449454 // Fill ExecVectors order by False items and True items.
450455 // ExecVectors is the alias of ExecVectorsByCond[false], so
451456 // Append ExecVectorsByCond[true] on it.
@@ -477,48 +482,130 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
477482 }
478483 }
479484
485+ void findCoverablePairs (const MCDCRecord::CondIDMap &PosToID) {
486+ llvm::SmallVector<unsigned > FoldedCondPos;
487+ for (unsigned I = 0 ; I < CondResults.size (); ++I) {
488+ if (CondResults[I] == MCDCRecord::MCDC_Constant ||
489+ CondResults[I] == MCDCRecord::MCDC_Unreachable) {
490+ FoldedCondPos.push_back (I);
491+ }
492+ }
493+ if (FoldedCondPos.empty ()) {
494+ return ;
495+ }
496+ std::array<MCDCRecord::TestVectors, 2 > PracticalTestVectorsByCond;
497+ for (const auto &TVWithCond : TestVectors) {
498+ const bool Practical =
499+ llvm::all_of (FoldedCondPos, [&](const unsigned &Pos) {
500+ const auto &[TV, Cond] = TVWithCond;
501+ const auto ID = PosToID.at (Pos);
502+ if (TV[ID] == MCDCRecord::MCDC_DontCare) {
503+ return true ;
504+ }
505+ if (CondResults[Pos] == MCDCRecord::MCDC_Constant) {
506+ const auto ConstantValue = Branches[Pos]->Count .isZero ()
507+ ? MCDCRecord::MCDC_False
508+ : MCDCRecord::MCDC_True;
509+ if (TV[ID] == ConstantValue) {
510+ return true ;
511+ }
512+ }
513+ return false ;
514+ });
515+
516+ if (Practical) {
517+ PracticalTestVectorsByCond[TVWithCond.second ].push_back (TVWithCond);
518+ }
519+ }
520+
521+ // If a condition:
522+ // - is uncoverable, all test vectors in exact one element of
523+ // `PracticalTestVectorsByCond` show it is `DontCare`;
524+ // - is unreachable, all test vectors in both elements of
525+ // `PracticalTestVectorsByCond` show it is `DontCare`;
526+ //
527+ // Otherwise, the condition is coverable as long as it has not been marked
528+ // as constant or unreachable before.
529+ for (unsigned Pos = 0 ; Pos < Branches.size (); ++Pos) {
530+ if (CondResults[Pos] != MCDCRecord::MCDC_Normal) {
531+ continue ;
532+ }
533+ const auto ID = PosToID.at (Pos);
534+ unsigned InaccessibleCondCount =
535+ llvm::count_if (PracticalTestVectorsByCond,
536+ [=](const MCDCRecord::TestVectors &TestVectors) {
537+ for (const auto &[TV, Cond] : TestVectors) {
538+ if (TV[ID] != MCDCRecord::MCDC_DontCare) {
539+ return false ;
540+ }
541+ }
542+ return true ;
543+ });
544+ switch (InaccessibleCondCount) {
545+ case 1 :
546+ CondResults[Pos] = MCDCRecord::CondResult::MCDC_Uncoverable;
547+ break ;
548+ case 2 :
549+ CondResults[Pos] = MCDCRecord::CondResult::MCDC_Unreachable;
550+ break ;
551+ default :
552+ break ;
553+ }
554+ }
555+ }
556+
480557public:
481558 // / Process the MC/DC Record in order to produce a result for a boolean
482559 // / expression. This process includes tracking the conditions that comprise
483560 // / the decision region, calculating the list of all possible test vectors,
484561 // / marking the executed test vectors, and then finding an Independence Pair
485562 // / out of the executed test vectors for each condition in the boolean
486- // / expression. A condition is tracked to ensure that its ID can be mapped to
487- // / its ordinal position in the boolean expression. The condition's source
488- // / location is also tracked, as well as whether it is constant folded (in
489- // / which case it is excuded from the metric).
563+ // / expression. A condition is tracked to ensure that its ID can be mapped
564+ // / to its ordinal position in the boolean expression. The condition's
565+ // / source location is also tracked, as well as whether it is constant
566+ // / folded (in which case it is excuded from the metric).
490567 MCDCRecord processMCDCRecord () {
491568 unsigned I = 0 ;
492569 MCDCRecord::CondIDMap PosToID;
493570 MCDCRecord::LineColPairMap CondLoc;
494571
495572 // Walk the Record's BranchRegions (representing Conditions) in order to:
496- // - Hash the condition based on its corresponding ID. This will be used to
573+ // - Hash the condition based on its corresponding ID. This will be used
574+ // to
497575 // calculate the test vectors.
498576 // - Keep a map of the condition's ordinal position (1, 2, 3, 4) to its
499577 // actual ID. This will be used to visualize the conditions in the
500578 // correct order.
501579 // - Keep track of the condition source location. This will be used to
502580 // visualize where the condition is.
503- // - Record whether the condition is constant folded so that we exclude it
581+ // - Record whether the condition is folded so that we exclude it
504582 // from being measured.
505583 for (const auto *B : Branches) {
506584 const auto &BranchParams = B->getBranchParams ();
507585 PosToID[I] = BranchParams.ID ;
508586 CondLoc[I] = B->startLoc ();
509- Folded[I++] = (B->Count .isZero () || B->FalseCount .isZero ());
587+ if (B->Count .isZero () && B->FalseCount .isZero ()) {
588+ CondResults[I] = MCDCRecord::CondResult::MCDC_Unreachable;
589+ } else if (B->Count .isZero () || B->FalseCount .isZero ()) {
590+ CondResults[I] = MCDCRecord::CondResult::MCDC_Constant;
591+ }
592+ ++I;
510593 }
511594
512595 // Using Profile Bitmap from runtime, mark the executed test vectors.
513596 findExecutedTestVectors ();
514597
515- // Compare executed test vectors against each other to find an independence
516- // pairs for each condition. This processing takes the most time.
598+ // Compare executed test vectors against each other to find an
599+ // independence pairs for each condition. This processing takes the most
600+ // time.
517601 findIndependencePairs ();
518602
603+ // Identify all conditions making no difference on outcome of the decision.
604+ findCoverablePairs (PosToID);
605+
519606 // Record Test vectors, executed vectors, and independence pairs.
520607 return MCDCRecord (Region, std::move (ExecVectors),
521- std::move (IndependencePairs), std::move (Folded ),
608+ std::move (IndependencePairs), std::move (CondResults ),
522609 std::move (PosToID), std::move (CondLoc));
523610 }
524611};
@@ -910,8 +997,8 @@ Error CoverageMapping::loadFunctionRecord(
910997 }
911998
912999 // Don't create records for (filenames, function) pairs we've already seen.
913- auto FilenamesHash = hash_combine_range (Record. Filenames . begin (),
914- Record.Filenames .end ());
1000+ auto FilenamesHash =
1001+ hash_combine_range (Record. Filenames . begin (), Record.Filenames .end ());
9151002 if (!RecordProvenance[FilenamesHash].insert (hash_value (OrigFuncName)).second )
9161003 return Error::success ();
9171004
@@ -961,12 +1048,11 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
9611048
9621049// If E is a no_data_found error, returns success. Otherwise returns E.
9631050static Error handleMaybeNoDataFoundError (Error E) {
964- return handleErrors (
965- std::move (E), [](const CoverageMapError &CME) {
966- if (CME.get () == coveragemap_error::no_data_found)
967- return static_cast <Error>(Error::success ());
968- return make_error<CoverageMapError>(CME.get (), CME.getMessage ());
969- });
1051+ return handleErrors (std::move (E), [](const CoverageMapError &CME) {
1052+ if (CME.get () == coveragemap_error::no_data_found)
1053+ return static_cast <Error>(Error::success ());
1054+ return make_error<CoverageMapError>(CME.get (), CME.getMessage ());
1055+ });
9701056}
9711057
9721058Error CoverageMapping::loadFromFile (
@@ -1058,7 +1144,7 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
10581144 std::string Path = std::move (*PathOpt);
10591145 StringRef Arch = Arches.size () == 1 ? Arches.front () : StringRef ();
10601146 if (Error E = loadFromFile (Path, Arch, CompilationDir, *ProfileReader,
1061- *Coverage, DataFound))
1147+ *Coverage, DataFound))
10621148 return std::move (E);
10631149 } else if (CheckBinaryIDs) {
10641150 return createFileError (
@@ -1152,9 +1238,9 @@ class SegmentBuilder {
11521238 // emit closing segments in sorted order.
11531239 auto CompletedRegionsIt = ActiveRegions.begin () + FirstCompletedRegion;
11541240 std::stable_sort (CompletedRegionsIt, ActiveRegions.end (),
1155- [](const CountedRegion *L, const CountedRegion *R) {
1156- return L->endLoc () < R->endLoc ();
1157- });
1241+ [](const CountedRegion *L, const CountedRegion *R) {
1242+ return L->endLoc () < R->endLoc ();
1243+ });
11581244
11591245 // Emit segments for all completed regions.
11601246 for (unsigned I = FirstCompletedRegion + 1 , E = ActiveRegions.size (); I < E;
0 commit comments