1515#define LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPING_H
1616
1717#include " llvm/ADT/ArrayRef.h"
18+ #include " llvm/ADT/BitVector.h"
1819#include " llvm/ADT/DenseMap.h"
1920#include " llvm/ADT/DenseSet.h"
2021#include " llvm/ADT/Hashing.h"
3334#include < cstdint>
3435#include < iterator>
3536#include < memory>
37+ #include < sstream>
3638#include < string>
3739#include < system_error>
3840#include < tuple>
@@ -237,7 +239,28 @@ struct CounterMappingRegion {
237239 // / A BranchRegion represents leaf-level boolean expressions and is
238240 // / associated with two counters, each representing the number of times the
239241 // / expression evaluates to true or false.
240- BranchRegion
242+ BranchRegion,
243+
244+ // / A DecisionRegion represents a top-level boolean expression and is
245+ // / associated with a variable length bitmap index and condition number.
246+ MCDCDecisionRegion,
247+
248+ // / A Branch Region can be extended to include IDs to facilitate MC/DC.
249+ MCDCBranchRegion
250+ };
251+
252+ using MCDCConditionID = unsigned int ;
253+ struct MCDCParameters {
254+ // / Byte Index of Bitmap Coverage Object for a Decision Region (MC/DC
255+ // / only).
256+ unsigned BitmapIdx = 0 ;
257+
258+ // / Number of Conditions used for a Decision Region (MC/DC only).
259+ unsigned NumConditions = 0 ;
260+
261+ // / IDs used to represent a branch region and other branch regions
262+ // / evaluated based on True and False branches (MC/DC only).
263+ MCDCConditionID ID = 0 , TrueID = 0 , FalseID = 0 ;
241264 };
242265
243266 // / Primary Counter that is also used for Branch Regions (TrueCount).
@@ -246,8 +269,13 @@ struct CounterMappingRegion {
246269 // / Secondary Counter used for Branch Regions (FalseCount).
247270 Counter FalseCount;
248271
249- unsigned FileID, ExpandedFileID;
272+ // / Parameters used for Modified Condition/Decision Coverage
273+ MCDCParameters MCDCParams;
274+
275+ unsigned FileID = 0 ;
276+ unsigned ExpandedFileID = 0 ;
250277 unsigned LineStart, ColumnStart, LineEnd, ColumnEnd;
278+
251279 RegionKind Kind;
252280
253281 CounterMappingRegion (Counter Count, unsigned FileID, unsigned ExpandedFileID,
@@ -257,15 +285,24 @@ struct CounterMappingRegion {
257285 LineStart (LineStart), ColumnStart(ColumnStart), LineEnd(LineEnd),
258286 ColumnEnd(ColumnEnd), Kind(Kind) {}
259287
260- CounterMappingRegion (Counter Count, Counter FalseCount, unsigned FileID,
288+ CounterMappingRegion (Counter Count, Counter FalseCount,
289+ MCDCParameters MCDCParams, unsigned FileID,
261290 unsigned ExpandedFileID, unsigned LineStart,
262291 unsigned ColumnStart, unsigned LineEnd,
263292 unsigned ColumnEnd, RegionKind Kind)
264- : Count(Count), FalseCount(FalseCount), FileID(FileID ),
265- ExpandedFileID(ExpandedFileID), LineStart(LineStart),
293+ : Count(Count), FalseCount(FalseCount), MCDCParams(MCDCParams ),
294+ FileID(FileID), ExpandedFileID(ExpandedFileID), LineStart(LineStart),
266295 ColumnStart(ColumnStart), LineEnd(LineEnd), ColumnEnd(ColumnEnd),
267296 Kind(Kind) {}
268297
298+ CounterMappingRegion (MCDCParameters MCDCParams, unsigned FileID,
299+ unsigned ExpandedFileID, unsigned LineStart,
300+ unsigned ColumnStart, unsigned LineEnd,
301+ unsigned ColumnEnd, RegionKind Kind)
302+ : MCDCParams(MCDCParams), ExpandedFileID(ExpandedFileID),
303+ LineStart(LineStart), ColumnStart(ColumnStart), LineEnd(LineEnd),
304+ ColumnEnd(ColumnEnd), Kind(Kind) {}
305+
269306 static CounterMappingRegion
270307 makeRegion (Counter Count, unsigned FileID, unsigned LineStart,
271308 unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) {
@@ -299,8 +336,27 @@ struct CounterMappingRegion {
299336 makeBranchRegion (Counter Count, Counter FalseCount, unsigned FileID,
300337 unsigned LineStart, unsigned ColumnStart, unsigned LineEnd,
301338 unsigned ColumnEnd) {
302- return CounterMappingRegion (Count, FalseCount, FileID, 0 , LineStart,
303- ColumnStart, LineEnd, ColumnEnd, BranchRegion);
339+ return CounterMappingRegion (Count, FalseCount, MCDCParameters (), FileID, 0 ,
340+ LineStart, ColumnStart, LineEnd, ColumnEnd,
341+ BranchRegion);
342+ }
343+
344+ static CounterMappingRegion
345+ makeBranchRegion (Counter Count, Counter FalseCount, MCDCParameters MCDCParams,
346+ unsigned FileID, unsigned LineStart, unsigned ColumnStart,
347+ unsigned LineEnd, unsigned ColumnEnd) {
348+ return CounterMappingRegion (Count, FalseCount, MCDCParams, FileID, 0 ,
349+ LineStart, ColumnStart, LineEnd, ColumnEnd,
350+ MCDCParams.ID == 0 ? BranchRegion
351+ : MCDCBranchRegion);
352+ }
353+
354+ static CounterMappingRegion
355+ makeDecisionRegion (MCDCParameters MCDCParams, unsigned FileID,
356+ unsigned LineStart, unsigned ColumnStart, unsigned LineEnd,
357+ unsigned ColumnEnd) {
358+ return CounterMappingRegion (MCDCParams, FileID, 0 , LineStart, ColumnStart,
359+ LineEnd, ColumnEnd, MCDCDecisionRegion);
304360 }
305361
306362 inline LineColPair startLoc () const {
@@ -326,18 +382,177 @@ struct CountedRegion : public CounterMappingRegion {
326382 FalseExecutionCount(FalseExecutionCount), Folded(false ) {}
327383};
328384
385+ // / MCDC Record grouping all information together.
386+ struct MCDCRecord {
387+ enum CondState { MCDC_DontCare = -1 , MCDC_False = 0 , MCDC_True = 1 };
388+
389+ using TestVector = llvm::SmallVector<CondState>;
390+ using TestVectors = llvm::SmallVector<TestVector>;
391+ using BoolVector = llvm::SmallVector<bool >;
392+ using TVRowPair = std::pair<unsigned , unsigned >;
393+ using TVPairMap = llvm::DenseMap<unsigned , TVRowPair>;
394+ using CondIDMap = llvm::DenseMap<unsigned , unsigned >;
395+ using LineColPairMap = llvm::DenseMap<unsigned , LineColPair>;
396+
397+ private:
398+ CounterMappingRegion Region;
399+ TestVectors TV;
400+ TVPairMap IndependencePairs;
401+ BoolVector Folded;
402+ CondIDMap PosToID;
403+ LineColPairMap CondLoc;
404+
405+ public:
406+ MCDCRecord (CounterMappingRegion Region, TestVectors TV,
407+ TVPairMap IndependencePairs, BoolVector Folded, CondIDMap PosToID,
408+ LineColPairMap CondLoc)
409+ : Region(Region), TV(TV), IndependencePairs(IndependencePairs),
410+ Folded (Folded), PosToID(PosToID), CondLoc(CondLoc){};
411+
412+ CounterMappingRegion getDecisionRegion () const { return Region; }
413+ unsigned getNumConditions () const { return Region.MCDCParams .NumConditions ; }
414+ unsigned getNumTestVectors () const { return TV.size (); }
415+ bool isCondFolded (unsigned Condition) const { return Folded[Condition]; }
416+
417+ CondState getTVCondition (unsigned TestVectorIndex, unsigned Condition) {
418+ // Accessing conditions in the TestVectors requires a translation from a
419+ // ordinal position to actual condition ID. This is done via PosToID[].
420+ return TV[TestVectorIndex][PosToID[Condition]];
421+ }
422+
423+ CondState getTVResult (unsigned TestVectorIndex) {
424+ // The last value for a Test Vector, after its constituent conditions, is
425+ // always the Result. See MCDCRecordProcessor::RecordTestVector().
426+ return TV[TestVectorIndex][getNumConditions ()];
427+ }
428+
429+ bool isConditionIndependencePairCovered (unsigned Condition) const {
430+ // Accessing conditions in the TestVector Row Pairs requires a translation
431+ // from a ordinal position to actual condition ID. This is done via
432+ // PosToID[].
433+ auto It = PosToID.find (Condition);
434+ if (It != PosToID.end ())
435+ return (IndependencePairs.find (It->second ) != IndependencePairs.end ());
436+ llvm_unreachable (" Condition ID without an Ordinal mapping" );
437+ }
438+
439+ TVRowPair getConditionIndependencePair (unsigned Condition) {
440+ // Accessing conditions in the TestVector Row Pairs requires a translation
441+ // from a ordinal position to actual condition ID. This is done via
442+ // PosToID[].
443+ assert (isConditionIndependencePairCovered (Condition));
444+ return IndependencePairs[PosToID[Condition]];
445+ }
446+
447+ float getPercentCovered () const {
448+ unsigned Folded = 0 ;
449+ unsigned Covered = 0 ;
450+ for (unsigned C = 0 ; C < getNumConditions (); C++) {
451+ if (isCondFolded (C))
452+ Folded++;
453+ else if (isConditionIndependencePairCovered (C))
454+ Covered++;
455+ }
456+
457+ unsigned Total = getNumConditions () - Folded;
458+ if (Total == 0 )
459+ return 0.0 ;
460+ return (static_cast <double >(Covered) / static_cast <double >(Total)) * 100.0 ;
461+ }
462+
463+ std::string getConditionHeaderString (unsigned Condition) {
464+ std::ostringstream OS;
465+ OS << " Condition C" << Condition + 1 << " --> (" ;
466+ OS << CondLoc[Condition].first << " :" << CondLoc[Condition].second ;
467+ OS << " )\n " ;
468+ return OS.str ();
469+ }
470+
471+ std::string getTestVectorHeaderString () {
472+ std::ostringstream OS;
473+ if (getNumTestVectors () == 0 ) {
474+ OS << " None.\n " ;
475+ return OS.str ();
476+ }
477+ for (unsigned I = 0 ; I < getNumConditions (); I++) {
478+ OS << " C" << I + 1 ;
479+ if (I != getNumConditions () - 1 )
480+ OS << " , " ;
481+ }
482+ OS << " Result\n " ;
483+ return OS.str ();
484+ }
485+
486+ std::string getTestVectorString (unsigned TestVectorIndex) {
487+ assert (TestVectorIndex < getNumTestVectors () &&
488+ " TestVector index out of bounds!" );
489+ std::ostringstream OS;
490+ // Add individual condition values to the string.
491+ OS << " " << TestVectorIndex + 1 << " { " ;
492+ for (unsigned Condition = 0 ; Condition < getNumConditions (); Condition++) {
493+ if (isCondFolded (Condition))
494+ OS << " C" ;
495+ else {
496+ switch (getTVCondition (TestVectorIndex, Condition)) {
497+ case MCDCRecord::MCDC_DontCare:
498+ OS << " -" ;
499+ break ;
500+ case MCDCRecord::MCDC_True:
501+ OS << " T" ;
502+ break ;
503+ case MCDCRecord::MCDC_False:
504+ OS << " F" ;
505+ break ;
506+ }
507+ }
508+ if (Condition != getNumConditions () - 1 )
509+ OS << " , " ;
510+ }
511+
512+ // Add result value to the string.
513+ OS << " = " ;
514+ if (getTVResult (TestVectorIndex) == MCDC_True)
515+ OS << " T" ;
516+ else
517+ OS << " F" ;
518+ OS << " }\n " ;
519+
520+ return OS.str ();
521+ }
522+
523+ std::string getConditionCoverageString (unsigned Condition) {
524+ assert (Condition < getNumConditions () &&
525+ " Condition index is out of bounds!" );
526+ std::ostringstream OS;
527+
528+ OS << " C" << Condition + 1 << " -Pair: " ;
529+ if (isCondFolded (Condition)) {
530+ OS << " constant folded\n " ;
531+ } else if (isConditionIndependencePairCovered (Condition)) {
532+ TVRowPair rows = getConditionIndependencePair (Condition);
533+ OS << " covered: (" << rows.first << " ," ;
534+ OS << rows.second << " )\n " ;
535+ } else
536+ OS << " not covered\n " ;
537+
538+ return OS.str ();
539+ }
540+ };
541+
329542// / A Counter mapping context is used to connect the counters, expressions
330543// / and the obtained counter values.
331544class CounterMappingContext {
332545 ArrayRef<CounterExpression> Expressions;
333546 ArrayRef<uint64_t > CounterValues;
547+ ArrayRef<uint8_t > BitmapBytes;
334548
335549public:
336550 CounterMappingContext (ArrayRef<CounterExpression> Expressions,
337551 ArrayRef<uint64_t > CounterValues = std::nullopt )
338552 : Expressions(Expressions), CounterValues(CounterValues) {}
339553
340554 void setCounts (ArrayRef<uint64_t > Counts) { CounterValues = Counts; }
555+ void setBitmapBytes (ArrayRef<uint8_t > Bytes) { BitmapBytes = Bytes; }
341556
342557 void dump (const Counter &C, raw_ostream &OS) const ;
343558 void dump (const Counter &C) const { dump (C, dbgs ()); }
@@ -346,6 +561,17 @@ class CounterMappingContext {
346561 // / counter was executed.
347562 Expected<int64_t > evaluate (const Counter &C) const ;
348563
564+ // / Return the number of times that a region of code associated with this
565+ // / counter was executed.
566+ Expected<BitVector>
567+ evaluateBitmap (const CounterMappingRegion *MCDCDecision) const ;
568+
569+ // / Return an MCDC record that indicates executed test vectors and condition
570+ // / pairs.
571+ Expected<MCDCRecord>
572+ evaluateMCDCRegion (CounterMappingRegion Region, BitVector Bitmap,
573+ ArrayRef<CounterMappingRegion> Branches);
574+
349575 unsigned getMaxCounterID (const Counter &C) const ;
350576};
351577
@@ -364,6 +590,8 @@ struct FunctionRecord {
364590 std::vector<CountedRegion> CountedRegions;
365591 // / Branch Regions in the function along with their counts.
366592 std::vector<CountedRegion> CountedBranchRegions;
593+ // / MCDC Records record a DecisionRegion and associated BranchRegions.
594+ std::vector<MCDCRecord> MCDCRecords;
367595 // / The number of times this function was executed.
368596 uint64_t ExecutionCount = 0 ;
369597
@@ -373,9 +601,12 @@ struct FunctionRecord {
373601 FunctionRecord (FunctionRecord &&FR) = default ;
374602 FunctionRecord &operator =(FunctionRecord &&) = default ;
375603
604+ void pushMCDCRecord (MCDCRecord Record) { MCDCRecords.push_back (Record); }
605+
376606 void pushRegion (CounterMappingRegion Region, uint64_t Count,
377607 uint64_t FalseCount) {
378- if (Region.Kind == CounterMappingRegion::BranchRegion) {
608+ if (Region.Kind == CounterMappingRegion::BranchRegion ||
609+ Region.Kind == CounterMappingRegion::MCDCBranchRegion) {
379610 CountedBranchRegions.emplace_back (Region, Count, FalseCount);
380611 // If both counters are hard-coded to zero, then this region represents a
381612 // constant-folded branch.
@@ -546,6 +777,7 @@ class CoverageData {
546777 std::vector<CoverageSegment> Segments;
547778 std::vector<ExpansionRecord> Expansions;
548779 std::vector<CountedRegion> BranchRegions;
780+ std::vector<MCDCRecord> MCDCRecords;
549781
550782public:
551783 CoverageData () = default ;
@@ -572,6 +804,9 @@ class CoverageData {
572804
573805 // / Branches that can be further processed.
574806 ArrayRef<CountedRegion> getBranches () const { return BranchRegions; }
807+
808+ // / MCDC Records that can be further processed.
809+ ArrayRef<MCDCRecord> getMCDCRecords () const { return MCDCRecords; }
575810};
576811
577812// / The mapping of profile information to coverage data.
0 commit comments