@@ -423,9 +423,16 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
423
423
// / Vector used to track whether a condition is constant folded.
424
424
MCDCRecord::BoolVector Folded;
425
425
426
+ // / Vector used to track whether a condition is constant folded.
427
+ MCDCRecord::ResultVector CondResults;
428
+
426
429
// / Mapping of calculated MC/DC Independence Pairs for each condition.
427
430
MCDCRecord::TVPairMap IndependencePairs;
428
431
432
+ // / All possible Test Vectors for the boolean expression derived from
433
+ // / binary decision diagran of the expression.
434
+ MCDCRecord::TestVectors TestVectors;
435
+
429
436
// / Storage for ExecVectors
430
437
// / ExecVectors is the alias of its 0th element.
431
438
std::array<MCDCRecord::TestVectors, 2 > ExecVectorsByCond;
@@ -449,6 +456,7 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
449
456
Region (Region), DecisionParams(Region.getDecisionParams()),
450
457
Branches(Branches), NumConditions(DecisionParams.NumConditions),
451
458
Folded{{BitVector (NumConditions), BitVector (NumConditions)}},
459
+ CondResults (NumConditions, MCDCRecord::CondResult::MCDC_Normal),
452
460
IndependencePairs(NumConditions), ExecVectors(ExecVectorsByCond[false ]),
453
461
IsVersion11(IsVersion11) {}
454
462
@@ -472,6 +480,7 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
472
480
473
481
assert (TVIdx < SavedNodes[ID].Width );
474
482
assert (TVIdxs.insert (NextTVIdx).second && " Duplicate TVIdx" );
483
+ TestVectors.push_back ({TV, MCDCCond});
475
484
476
485
if (!Bitmap[IsVersion11
477
486
? DecisionParams.BitmapIdx * CHAR_BIT + TV.getIndex ()
@@ -499,7 +508,6 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
499
508
buildTestVector (TV, 0 , 0 );
500
509
assert (TVIdxs.size () == unsigned (NumTestVectors) &&
501
510
" TVIdxs wasn't fulfilled" );
502
-
503
511
// Fill ExecVectors order by False items and True items.
504
512
// ExecVectors is the alias of ExecVectorsByCond[false], so
505
513
// Append ExecVectorsByCond[true] on it.
@@ -508,44 +516,128 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
508
516
std::make_move_iterator (ExecVectorsT.end ()));
509
517
}
510
518
519
+ void findCoverablePairs (const MCDCRecord::CondIDMap &PosToID) {
520
+ llvm::SmallVector<unsigned > FoldedCondPos;
521
+ for (unsigned I = 0 ; I < CondResults.size (); ++I) {
522
+ if (CondResults[I] == MCDCRecord::MCDC_Constant ||
523
+ CondResults[I] == MCDCRecord::MCDC_Unreachable) {
524
+ FoldedCondPos.push_back (I);
525
+ }
526
+ }
527
+ if (FoldedCondPos.empty ()) {
528
+ return ;
529
+ }
530
+ std::array<MCDCRecord::TestVectors, 2 > PracticalTestVectorsByCond;
531
+ for (const auto &TVWithCond : TestVectors) {
532
+ const bool Practical =
533
+ llvm::all_of (FoldedCondPos, [&](const unsigned &Pos) {
534
+ const auto &[TV, Cond] = TVWithCond;
535
+ const auto ID = PosToID.at (Pos);
536
+ if (TV[ID] == MCDCRecord::MCDC_DontCare) {
537
+ return true ;
538
+ }
539
+ if (CondResults[Pos] == MCDCRecord::MCDC_Constant) {
540
+ const auto ConstantValue = Branches[Pos]->Count .isZero ()
541
+ ? MCDCRecord::MCDC_False
542
+ : MCDCRecord::MCDC_True;
543
+ if (TV[ID] == ConstantValue) {
544
+ return true ;
545
+ }
546
+ }
547
+ return false ;
548
+ });
549
+
550
+ if (Practical) {
551
+ PracticalTestVectorsByCond[TVWithCond.second ].push_back (TVWithCond);
552
+ }
553
+ }
554
+
555
+ // If a condition:
556
+ // - is uncoverable, all test vectors in exact one element of
557
+ // `PracticalTestVectorsByCond` show it is `DontCare`;
558
+ // - is unreachable, all test vectors in both elements of
559
+ // `PracticalTestVectorsByCond` show it is `DontCare`;
560
+ //
561
+ // Otherwise, the condition is coverable as long as it has not been marked
562
+ // as constant or unreachable before.
563
+ for (unsigned Pos = 0 ; Pos < Branches.size (); ++Pos) {
564
+ if (CondResults[Pos] != MCDCRecord::MCDC_Normal) {
565
+ continue ;
566
+ }
567
+ const auto ID = PosToID.at (Pos);
568
+ unsigned InaccessibleCondCount =
569
+ llvm::count_if (PracticalTestVectorsByCond,
570
+ [=](const MCDCRecord::TestVectors &TestVectors) {
571
+ for (const auto &[TV, Cond] : TestVectors) {
572
+ if (TV[ID] != MCDCRecord::MCDC_DontCare) {
573
+ return false ;
574
+ }
575
+ }
576
+ return true ;
577
+ });
578
+ switch (InaccessibleCondCount) {
579
+ case 1 :
580
+ CondResults[Pos] = MCDCRecord::CondResult::MCDC_Uncoverable;
581
+ break ;
582
+ case 2 :
583
+ CondResults[Pos] = MCDCRecord::CondResult::MCDC_Unreachable;
584
+ break ;
585
+ default :
586
+ break ;
587
+ }
588
+ }
589
+ }
590
+
511
591
public:
512
592
// / Process the MC/DC Record in order to produce a result for a boolean
513
593
// / expression. This process includes tracking the conditions that comprise
514
594
// / the decision region, calculating the list of all possible test vectors,
515
595
// / marking the executed test vectors, and then finding an Independence Pair
516
596
// / 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).
597
+ // / expression. A condition is tracked to ensure that its ID can be mapped
598
+ // / to its ordinal position in the boolean expression. The condition's
599
+ // / source location is also tracked, as well as whether it is constant
600
+ // / folded (in which case it is excuded from the metric).
521
601
MCDCRecord processMCDCRecord () {
522
602
MCDCRecord::CondIDMap PosToID;
523
603
MCDCRecord::LineColPairMap CondLoc;
524
604
525
605
// Walk the Record's BranchRegions (representing Conditions) in order to:
526
- // - Hash the condition based on its corresponding ID. This will be used to
606
+ // - Hash the condition based on its corresponding ID. This will be used
607
+ // to
527
608
// calculate the test vectors.
528
609
// - Keep a map of the condition's ordinal position (1, 2, 3, 4) to its
529
610
// actual ID. This will be used to visualize the conditions in the
530
611
// correct order.
531
612
// - Keep track of the condition source location. This will be used to
532
613
// visualize where the condition is.
533
- // - Record whether the condition is constant folded so that we exclude it
614
+ // - Record whether the condition is folded so that we exclude it
534
615
// from being measured.
535
616
for (auto [I, B] : enumerate(Branches)) {
536
617
const auto &BranchParams = B->getBranchParams ();
537
618
PosToID[I] = BranchParams.ID ;
538
619
CondLoc[I] = B->startLoc ();
539
620
Folded[false ][I] = B->FalseCount .isZero ();
540
621
Folded[true ][I] = B->Count .isZero ();
622
+ if (B->Count .isZero () && B->FalseCount .isZero ()) {
623
+ CondResults[I] = MCDCRecord::CondResult::MCDC_Unreachable;
624
+ } else if (B->Count .isZero () || B->FalseCount .isZero ()) {
625
+ CondResults[I] = MCDCRecord::CondResult::MCDC_Constant;
626
+ }
627
+ ++I;
541
628
}
542
629
543
630
// Using Profile Bitmap from runtime, mark the executed test vectors.
544
631
findExecutedTestVectors ();
545
632
633
+ // Identify all conditions making no difference on outcome of the decision.
634
+ findCoverablePairs (PosToID);
635
+
546
636
// Record Test vectors, executed vectors, and independence pairs.
547
- return MCDCRecord (Region, std::move (ExecVectors), std::move (Folded),
548
- std::move (PosToID), std::move (CondLoc));
637
+ return MCDCRecord (Region, std::move (ExecVectors),
638
+ std::move (IndependencePairs), std::move (Folded),
639
+ std::move (CondResults), std::move (PosToID),
640
+ std::move (CondLoc));
549
641
}
550
642
};
551
643
@@ -935,8 +1027,8 @@ Error CoverageMapping::loadFunctionRecord(
935
1027
}
936
1028
937
1029
// Don't create records for (filenames, function) pairs we've already seen.
938
- auto FilenamesHash = hash_combine_range (Record. Filenames . begin (),
939
- Record.Filenames .end ());
1030
+ auto FilenamesHash =
1031
+ hash_combine_range (Record. Filenames . begin (), Record.Filenames .end ());
940
1032
if (!RecordProvenance[FilenamesHash].insert (hash_value (OrigFuncName)).second )
941
1033
return Error::success ();
942
1034
@@ -989,12 +1081,11 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
989
1081
990
1082
// If E is a no_data_found error, returns success. Otherwise returns E.
991
1083
static Error handleMaybeNoDataFoundError (Error E) {
992
- return handleErrors (
993
- std::move (E), [](const CoverageMapError &CME) {
994
- if (CME.get () == coveragemap_error::no_data_found)
995
- return static_cast <Error>(Error::success ());
996
- return make_error<CoverageMapError>(CME.get (), CME.getMessage ());
997
- });
1084
+ return handleErrors (std::move (E), [](const CoverageMapError &CME) {
1085
+ if (CME.get () == coveragemap_error::no_data_found)
1086
+ return static_cast <Error>(Error::success ());
1087
+ return make_error<CoverageMapError>(CME.get (), CME.getMessage ());
1088
+ });
998
1089
}
999
1090
1000
1091
Error CoverageMapping::loadFromFile (
@@ -1086,7 +1177,7 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
1086
1177
std::string Path = std::move (*PathOpt);
1087
1178
StringRef Arch = Arches.size () == 1 ? Arches.front () : StringRef ();
1088
1179
if (Error E = loadFromFile (Path, Arch, CompilationDir, *ProfileReader,
1089
- *Coverage, DataFound))
1180
+ *Coverage, DataFound))
1090
1181
return std::move (E);
1091
1182
} else if (CheckBinaryIDs) {
1092
1183
return createFileError (
@@ -1180,9 +1271,9 @@ class SegmentBuilder {
1180
1271
// emit closing segments in sorted order.
1181
1272
auto CompletedRegionsIt = ActiveRegions.begin () + FirstCompletedRegion;
1182
1273
std::stable_sort (CompletedRegionsIt, ActiveRegions.end (),
1183
- [](const CountedRegion *L, const CountedRegion *R) {
1184
- return L->endLoc () < R->endLoc ();
1185
- });
1274
+ [](const CountedRegion *L, const CountedRegion *R) {
1275
+ return L->endLoc () < R->endLoc ();
1276
+ });
1186
1277
1187
1278
// Emit segments for all completed regions.
1188
1279
for (unsigned I = FirstCompletedRegion + 1 , E = ActiveRegions.size (); I < E;
0 commit comments