@@ -362,11 +362,15 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
362
362
unsigned NumConditions;
363
363
364
364
// / Vector used to track whether a condition is constant folded.
365
- MCDCRecord::BoolVector Folded ;
365
+ MCDCRecord::ResultVector CondResults ;
366
366
367
367
// / Mapping of calculated MC/DC Independence Pairs for each condition.
368
368
MCDCRecord::TVPairMap IndependencePairs;
369
369
370
+ // / All possible Test Vectors for the boolean expression derived from
371
+ // / binary decision diagran of the expression.
372
+ MCDCRecord::TestVectors TestVectors;
373
+
370
374
// / Storage for ExecVectors
371
375
// / ExecVectors is the alias of its 0th element.
372
376
std::array<MCDCRecord::TestVectors, 2 > ExecVectorsByCond;
@@ -392,8 +396,9 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
392
396
: NextIDsBuilder(Branches), TVIdxBuilder(this ->NextIDs), Bitmap(Bitmap),
393
397
Region (Region), DecisionParams(Region.getDecisionParams()),
394
398
Branches(Branches), NumConditions(DecisionParams.NumConditions),
395
- Folded(NumConditions, false ), IndependencePairs(NumConditions),
396
- ExecVectors(ExecVectorsByCond[false ]), IsVersion11(IsVersion11) {}
399
+ CondResults(NumConditions, MCDCRecord::CondResult::MCDC_Normal),
400
+ IndependencePairs(NumConditions), ExecVectors(ExecVectorsByCond[false ]),
401
+ IsVersion11(IsVersion11) {}
397
402
398
403
private:
399
404
// Walk the binary decision diagram and try assigning both false and true to
@@ -415,6 +420,7 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
415
420
416
421
assert (TVIdx < SavedNodes[ID].Width );
417
422
assert (TVIdxs.insert (NextTVIdx).second && " Duplicate TVIdx" );
423
+ TestVectors.push_back ({TV, MCDCCond});
418
424
419
425
if (!Bitmap[IsVersion11
420
426
? DecisionParams.BitmapIdx * CHAR_BIT + TV.getIndex ()
@@ -442,7 +448,6 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
442
448
buildTestVector (TV, 0 , 0 );
443
449
assert (TVIdxs.size () == unsigned (NumTestVectors) &&
444
450
" TVIdxs wasn't fulfilled" );
445
-
446
451
// Fill ExecVectors order by False items and True items.
447
452
// ExecVectors is the alias of ExecVectorsByCond[false], so
448
453
// Append ExecVectorsByCond[true] on it.
@@ -474,48 +479,130 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
474
479
}
475
480
}
476
481
482
+ void findCoverablePairs (const MCDCRecord::CondIDMap &PosToID) {
483
+ llvm::SmallVector<unsigned > FoldedCondPos;
484
+ for (unsigned I = 0 ; I < CondResults.size (); ++I) {
485
+ if (CondResults[I] == MCDCRecord::MCDC_Constant ||
486
+ CondResults[I] == MCDCRecord::MCDC_Unreachable) {
487
+ FoldedCondPos.push_back (I);
488
+ }
489
+ }
490
+ if (FoldedCondPos.empty ()) {
491
+ return ;
492
+ }
493
+ std::array<MCDCRecord::TestVectors, 2 > PracticalTestVectorsByCond;
494
+ for (const auto &TVWithCond : TestVectors) {
495
+ const bool Practical =
496
+ llvm::all_of (FoldedCondPos, [&](const unsigned &Pos) {
497
+ const auto &[TV, Cond] = TVWithCond;
498
+ const auto ID = PosToID.at (Pos);
499
+ if (TV[ID] == MCDCRecord::MCDC_DontCare) {
500
+ return true ;
501
+ }
502
+ if (CondResults[Pos] == MCDCRecord::MCDC_Constant) {
503
+ const auto ConstantValue = Branches[Pos]->Count .isZero ()
504
+ ? MCDCRecord::MCDC_False
505
+ : MCDCRecord::MCDC_True;
506
+ if (TV[ID] == ConstantValue) {
507
+ return true ;
508
+ }
509
+ }
510
+ return false ;
511
+ });
512
+
513
+ if (Practical) {
514
+ PracticalTestVectorsByCond[TVWithCond.second ].push_back (TVWithCond);
515
+ }
516
+ }
517
+
518
+ // If a condition:
519
+ // - is uncoverable, all test vectors in exact one element of
520
+ // `PracticalTestVectorsByCond` show it is `DontCare`;
521
+ // - is unreachable, all test vectors in both elements of
522
+ // `PracticalTestVectorsByCond` show it is `DontCare`;
523
+ //
524
+ // Otherwise, the condition is coverable as long as it has not been marked
525
+ // as constant or unreachable before.
526
+ for (unsigned Pos = 0 ; Pos < Branches.size (); ++Pos) {
527
+ if (CondResults[Pos] != MCDCRecord::MCDC_Normal) {
528
+ continue ;
529
+ }
530
+ const auto ID = PosToID.at (Pos);
531
+ unsigned InaccessibleCondCount =
532
+ llvm::count_if (PracticalTestVectorsByCond,
533
+ [=](const MCDCRecord::TestVectors &TestVectors) {
534
+ for (const auto &[TV, Cond] : TestVectors) {
535
+ if (TV[ID] != MCDCRecord::MCDC_DontCare) {
536
+ return false ;
537
+ }
538
+ }
539
+ return true ;
540
+ });
541
+ switch (InaccessibleCondCount) {
542
+ case 1 :
543
+ CondResults[Pos] = MCDCRecord::CondResult::MCDC_Uncoverable;
544
+ break ;
545
+ case 2 :
546
+ CondResults[Pos] = MCDCRecord::CondResult::MCDC_Unreachable;
547
+ break ;
548
+ default :
549
+ break ;
550
+ }
551
+ }
552
+ }
553
+
477
554
public:
478
555
// / Process the MC/DC Record in order to produce a result for a boolean
479
556
// / expression. This process includes tracking the conditions that comprise
480
557
// / the decision region, calculating the list of all possible test vectors,
481
558
// / marking the executed test vectors, and then finding an Independence Pair
482
559
// / out of the executed test vectors for each condition in the boolean
483
- // / expression. A condition is tracked to ensure that its ID can be mapped to
484
- // / its ordinal position in the boolean expression. The condition's source
485
- // / location is also tracked, as well as whether it is constant folded (in
486
- // / which case it is excuded from the metric).
560
+ // / expression. A condition is tracked to ensure that its ID can be mapped
561
+ // / to its ordinal position in the boolean expression. The condition's
562
+ // / source location is also tracked, as well as whether it is constant
563
+ // / folded (in which case it is excuded from the metric).
487
564
MCDCRecord processMCDCRecord () {
488
565
unsigned I = 0 ;
489
566
MCDCRecord::CondIDMap PosToID;
490
567
MCDCRecord::LineColPairMap CondLoc;
491
568
492
569
// Walk the Record's BranchRegions (representing Conditions) in order to:
493
- // - Hash the condition based on its corresponding ID. This will be used to
570
+ // - Hash the condition based on its corresponding ID. This will be used
571
+ // to
494
572
// calculate the test vectors.
495
573
// - Keep a map of the condition's ordinal position (1, 2, 3, 4) to its
496
574
// actual ID. This will be used to visualize the conditions in the
497
575
// correct order.
498
576
// - Keep track of the condition source location. This will be used to
499
577
// visualize where the condition is.
500
- // - Record whether the condition is constant folded so that we exclude it
578
+ // - Record whether the condition is folded so that we exclude it
501
579
// from being measured.
502
580
for (const auto *B : Branches) {
503
581
const auto &BranchParams = B->getBranchParams ();
504
582
PosToID[I] = BranchParams.ID ;
505
583
CondLoc[I] = B->startLoc ();
506
- Folded[I++] = (B->Count .isZero () || B->FalseCount .isZero ());
584
+ if (B->Count .isZero () && B->FalseCount .isZero ()) {
585
+ CondResults[I] = MCDCRecord::CondResult::MCDC_Unreachable;
586
+ } else if (B->Count .isZero () || B->FalseCount .isZero ()) {
587
+ CondResults[I] = MCDCRecord::CondResult::MCDC_Constant;
588
+ }
589
+ ++I;
507
590
}
508
591
509
592
// Using Profile Bitmap from runtime, mark the executed test vectors.
510
593
findExecutedTestVectors ();
511
594
512
- // Compare executed test vectors against each other to find an independence
513
- // pairs for each condition. This processing takes the most time.
595
+ // Compare executed test vectors against each other to find an
596
+ // independence pairs for each condition. This processing takes the most
597
+ // time.
514
598
findIndependencePairs ();
515
599
600
+ // Identify all conditions making no difference on outcome of the decision.
601
+ findCoverablePairs (PosToID);
602
+
516
603
// Record Test vectors, executed vectors, and independence pairs.
517
604
return MCDCRecord (Region, std::move (ExecVectors),
518
- std::move (IndependencePairs), std::move (Folded ),
605
+ std::move (IndependencePairs), std::move (CondResults ),
519
606
std::move (PosToID), std::move (CondLoc));
520
607
}
521
608
};
@@ -907,8 +994,8 @@ Error CoverageMapping::loadFunctionRecord(
907
994
}
908
995
909
996
// Don't create records for (filenames, function) pairs we've already seen.
910
- auto FilenamesHash = hash_combine_range (Record. Filenames . begin (),
911
- Record.Filenames .end ());
997
+ auto FilenamesHash =
998
+ hash_combine_range (Record. Filenames . begin (), Record.Filenames .end ());
912
999
if (!RecordProvenance[FilenamesHash].insert (hash_value (OrigFuncName)).second )
913
1000
return Error::success ();
914
1001
@@ -958,12 +1045,11 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
958
1045
959
1046
// If E is a no_data_found error, returns success. Otherwise returns E.
960
1047
static Error handleMaybeNoDataFoundError (Error E) {
961
- return handleErrors (
962
- std::move (E), [](const CoverageMapError &CME) {
963
- if (CME.get () == coveragemap_error::no_data_found)
964
- return static_cast <Error>(Error::success ());
965
- return make_error<CoverageMapError>(CME.get (), CME.getMessage ());
966
- });
1048
+ return handleErrors (std::move (E), [](const CoverageMapError &CME) {
1049
+ if (CME.get () == coveragemap_error::no_data_found)
1050
+ return static_cast <Error>(Error::success ());
1051
+ return make_error<CoverageMapError>(CME.get (), CME.getMessage ());
1052
+ });
967
1053
}
968
1054
969
1055
Error CoverageMapping::loadFromFile (
@@ -1055,7 +1141,7 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
1055
1141
std::string Path = std::move (*PathOpt);
1056
1142
StringRef Arch = Arches.size () == 1 ? Arches.front () : StringRef ();
1057
1143
if (Error E = loadFromFile (Path, Arch, CompilationDir, *ProfileReader,
1058
- *Coverage, DataFound))
1144
+ *Coverage, DataFound))
1059
1145
return std::move (E);
1060
1146
} else if (CheckBinaryIDs) {
1061
1147
return createFileError (
@@ -1149,9 +1235,9 @@ class SegmentBuilder {
1149
1235
// emit closing segments in sorted order.
1150
1236
auto CompletedRegionsIt = ActiveRegions.begin () + FirstCompletedRegion;
1151
1237
std::stable_sort (CompletedRegionsIt, ActiveRegions.end (),
1152
- [](const CountedRegion *L, const CountedRegion *R) {
1153
- return L->endLoc () < R->endLoc ();
1154
- });
1238
+ [](const CountedRegion *L, const CountedRegion *R) {
1239
+ return L->endLoc () < R->endLoc ();
1240
+ });
1155
1241
1156
1242
// Emit segments for all completed regions.
1157
1243
for (unsigned I = FirstCompletedRegion + 1 , E = ActiveRegions.size (); I < E;
0 commit comments