15
15
#define LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPING_H
16
16
17
17
#include " llvm/ADT/ArrayRef.h"
18
+ #include " llvm/ADT/BitVector.h"
18
19
#include " llvm/ADT/DenseMap.h"
19
20
#include " llvm/ADT/DenseSet.h"
20
21
#include " llvm/ADT/Hashing.h"
33
34
#include < cstdint>
34
35
#include < iterator>
35
36
#include < memory>
37
+ #include < sstream>
36
38
#include < string>
37
39
#include < system_error>
38
40
#include < tuple>
@@ -237,7 +239,28 @@ struct CounterMappingRegion {
237
239
// / A BranchRegion represents leaf-level boolean expressions and is
238
240
// / associated with two counters, each representing the number of times the
239
241
// / 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 ;
241
264
};
242
265
243
266
// / Primary Counter that is also used for Branch Regions (TrueCount).
@@ -246,8 +269,13 @@ struct CounterMappingRegion {
246
269
// / Secondary Counter used for Branch Regions (FalseCount).
247
270
Counter FalseCount;
248
271
249
- unsigned FileID, ExpandedFileID;
272
+ // / Parameters used for Modified Condition/Decision Coverage
273
+ MCDCParameters MCDCParams;
274
+
275
+ unsigned FileID = 0 ;
276
+ unsigned ExpandedFileID = 0 ;
250
277
unsigned LineStart, ColumnStart, LineEnd, ColumnEnd;
278
+
251
279
RegionKind Kind;
252
280
253
281
CounterMappingRegion (Counter Count, unsigned FileID, unsigned ExpandedFileID,
@@ -257,15 +285,24 @@ struct CounterMappingRegion {
257
285
LineStart (LineStart), ColumnStart(ColumnStart), LineEnd(LineEnd),
258
286
ColumnEnd(ColumnEnd), Kind(Kind) {}
259
287
260
- CounterMappingRegion (Counter Count, Counter FalseCount, unsigned FileID,
288
+ CounterMappingRegion (Counter Count, Counter FalseCount,
289
+ MCDCParameters MCDCParams, unsigned FileID,
261
290
unsigned ExpandedFileID, unsigned LineStart,
262
291
unsigned ColumnStart, unsigned LineEnd,
263
292
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),
266
295
ColumnStart(ColumnStart), LineEnd(LineEnd), ColumnEnd(ColumnEnd),
267
296
Kind(Kind) {}
268
297
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
+
269
306
static CounterMappingRegion
270
307
makeRegion (Counter Count, unsigned FileID, unsigned LineStart,
271
308
unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) {
@@ -299,8 +336,27 @@ struct CounterMappingRegion {
299
336
makeBranchRegion (Counter Count, Counter FalseCount, unsigned FileID,
300
337
unsigned LineStart, unsigned ColumnStart, unsigned LineEnd,
301
338
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);
304
360
}
305
361
306
362
inline LineColPair startLoc () const {
@@ -326,18 +382,177 @@ struct CountedRegion : public CounterMappingRegion {
326
382
FalseExecutionCount(FalseExecutionCount), Folded(false ) {}
327
383
};
328
384
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
+
329
542
// / A Counter mapping context is used to connect the counters, expressions
330
543
// / and the obtained counter values.
331
544
class CounterMappingContext {
332
545
ArrayRef<CounterExpression> Expressions;
333
546
ArrayRef<uint64_t > CounterValues;
547
+ ArrayRef<uint8_t > BitmapBytes;
334
548
335
549
public:
336
550
CounterMappingContext (ArrayRef<CounterExpression> Expressions,
337
551
ArrayRef<uint64_t > CounterValues = std::nullopt)
338
552
: Expressions(Expressions), CounterValues(CounterValues) {}
339
553
340
554
void setCounts (ArrayRef<uint64_t > Counts) { CounterValues = Counts; }
555
+ void setBitmapBytes (ArrayRef<uint8_t > Bytes) { BitmapBytes = Bytes; }
341
556
342
557
void dump (const Counter &C, raw_ostream &OS) const ;
343
558
void dump (const Counter &C) const { dump (C, dbgs ()); }
@@ -346,6 +561,17 @@ class CounterMappingContext {
346
561
// / counter was executed.
347
562
Expected<int64_t > evaluate (const Counter &C) const ;
348
563
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
+
349
575
unsigned getMaxCounterID (const Counter &C) const ;
350
576
};
351
577
@@ -364,6 +590,8 @@ struct FunctionRecord {
364
590
std::vector<CountedRegion> CountedRegions;
365
591
// / Branch Regions in the function along with their counts.
366
592
std::vector<CountedRegion> CountedBranchRegions;
593
+ // / MCDC Records record a DecisionRegion and associated BranchRegions.
594
+ std::vector<MCDCRecord> MCDCRecords;
367
595
// / The number of times this function was executed.
368
596
uint64_t ExecutionCount = 0 ;
369
597
@@ -373,9 +601,12 @@ struct FunctionRecord {
373
601
FunctionRecord (FunctionRecord &&FR) = default ;
374
602
FunctionRecord &operator =(FunctionRecord &&) = default ;
375
603
604
+ void pushMCDCRecord (MCDCRecord Record) { MCDCRecords.push_back (Record); }
605
+
376
606
void pushRegion (CounterMappingRegion Region, uint64_t Count,
377
607
uint64_t FalseCount) {
378
- if (Region.Kind == CounterMappingRegion::BranchRegion) {
608
+ if (Region.Kind == CounterMappingRegion::BranchRegion ||
609
+ Region.Kind == CounterMappingRegion::MCDCBranchRegion) {
379
610
CountedBranchRegions.emplace_back (Region, Count, FalseCount);
380
611
// If both counters are hard-coded to zero, then this region represents a
381
612
// constant-folded branch.
@@ -546,6 +777,7 @@ class CoverageData {
546
777
std::vector<CoverageSegment> Segments;
547
778
std::vector<ExpansionRecord> Expansions;
548
779
std::vector<CountedRegion> BranchRegions;
780
+ std::vector<MCDCRecord> MCDCRecords;
549
781
550
782
public:
551
783
CoverageData () = default ;
@@ -572,6 +804,9 @@ class CoverageData {
572
804
573
805
// / Branches that can be further processed.
574
806
ArrayRef<CountedRegion> getBranches () const { return BranchRegions; }
807
+
808
+ // / MCDC Records that can be further processed.
809
+ ArrayRef<MCDCRecord> getMCDCRecords () const { return MCDCRecords; }
575
810
};
576
811
577
812
// / The mapping of profile information to coverage data.
0 commit comments