@@ -365,11 +365,15 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
365
365
unsigned NumConditions;
366
366
367
367
// / Vector used to track whether a condition is constant folded.
368
- MCDCRecord::BoolVector Folded ;
368
+ MCDCRecord::ResultVector CondResults ;
369
369
370
370
// / Mapping of calculated MC/DC Independence Pairs for each condition.
371
371
MCDCRecord::TVPairMap IndependencePairs;
372
372
373
+ // / All possible Test Vectors for the boolean expression derived from
374
+ // / binary decision diagran of the expression.
375
+ MCDCRecord::TestVectors TestVectors;
376
+
373
377
// / Storage for ExecVectors
374
378
// / ExecVectors is the alias of its 0th element.
375
379
std::array<MCDCRecord::TestVectors, 2 > ExecVectorsByCond;
@@ -395,8 +399,9 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
395
399
: NextIDsBuilder(Branches), TVIdxBuilder(this ->NextIDs), Bitmap(Bitmap),
396
400
Region (Region), DecisionParams(Region.getDecisionParams()),
397
401
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) {}
400
405
401
406
private:
402
407
// Walk the binary decision diagram and try assigning both false and true to
@@ -418,6 +423,7 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
418
423
419
424
assert (TVIdx < SavedNodes[ID].Width );
420
425
assert (TVIdxs.insert (NextTVIdx).second && " Duplicate TVIdx" );
426
+ TestVectors.push_back ({TV, MCDCCond});
421
427
422
428
if (!Bitmap[IsVersion11
423
429
? DecisionParams.BitmapIdx * CHAR_BIT + TV.getIndex ()
@@ -445,7 +451,6 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
445
451
buildTestVector (TV, 0 , 0 );
446
452
assert (TVIdxs.size () == unsigned (NumTestVectors) &&
447
453
" TVIdxs wasn't fulfilled" );
448
-
449
454
// Fill ExecVectors order by False items and True items.
450
455
// ExecVectors is the alias of ExecVectorsByCond[false], so
451
456
// Append ExecVectorsByCond[true] on it.
@@ -477,48 +482,130 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
477
482
}
478
483
}
479
484
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
+
480
557
public:
481
558
// / Process the MC/DC Record in order to produce a result for a boolean
482
559
// / expression. This process includes tracking the conditions that comprise
483
560
// / the decision region, calculating the list of all possible test vectors,
484
561
// / marking the executed test vectors, and then finding an Independence Pair
485
562
// / 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).
490
567
MCDCRecord processMCDCRecord () {
491
568
unsigned I = 0 ;
492
569
MCDCRecord::CondIDMap PosToID;
493
570
MCDCRecord::LineColPairMap CondLoc;
494
571
495
572
// 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
497
575
// calculate the test vectors.
498
576
// - Keep a map of the condition's ordinal position (1, 2, 3, 4) to its
499
577
// actual ID. This will be used to visualize the conditions in the
500
578
// correct order.
501
579
// - Keep track of the condition source location. This will be used to
502
580
// 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
504
582
// from being measured.
505
583
for (const auto *B : Branches) {
506
584
const auto &BranchParams = B->getBranchParams ();
507
585
PosToID[I] = BranchParams.ID ;
508
586
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;
510
593
}
511
594
512
595
// Using Profile Bitmap from runtime, mark the executed test vectors.
513
596
findExecutedTestVectors ();
514
597
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.
517
601
findIndependencePairs ();
518
602
603
+ // Identify all conditions making no difference on outcome of the decision.
604
+ findCoverablePairs (PosToID);
605
+
519
606
// Record Test vectors, executed vectors, and independence pairs.
520
607
return MCDCRecord (Region, std::move (ExecVectors),
521
- std::move (IndependencePairs), std::move (Folded ),
608
+ std::move (IndependencePairs), std::move (CondResults ),
522
609
std::move (PosToID), std::move (CondLoc));
523
610
}
524
611
};
@@ -910,8 +997,8 @@ Error CoverageMapping::loadFunctionRecord(
910
997
}
911
998
912
999
// 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 ());
915
1002
if (!RecordProvenance[FilenamesHash].insert (hash_value (OrigFuncName)).second )
916
1003
return Error::success ();
917
1004
@@ -961,12 +1048,11 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
961
1048
962
1049
// If E is a no_data_found error, returns success. Otherwise returns E.
963
1050
static 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
+ });
970
1056
}
971
1057
972
1058
Error CoverageMapping::loadFromFile (
@@ -1058,7 +1144,7 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
1058
1144
std::string Path = std::move (*PathOpt);
1059
1145
StringRef Arch = Arches.size () == 1 ? Arches.front () : StringRef ();
1060
1146
if (Error E = loadFromFile (Path, Arch, CompilationDir, *ProfileReader,
1061
- *Coverage, DataFound))
1147
+ *Coverage, DataFound))
1062
1148
return std::move (E);
1063
1149
} else if (CheckBinaryIDs) {
1064
1150
return createFileError (
@@ -1152,9 +1238,9 @@ class SegmentBuilder {
1152
1238
// emit closing segments in sorted order.
1153
1239
auto CompletedRegionsIt = ActiveRegions.begin () + FirstCompletedRegion;
1154
1240
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
+ });
1158
1244
1159
1245
// Emit segments for all completed regions.
1160
1246
for (unsigned I = FirstCompletedRegion + 1 , E = ActiveRegions.size (); I < E;
0 commit comments