[llvm] Add executed MC/DC TestVectors to `llvm-cov export` (PR #159119)

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 23 03:50:29 PDT 2025


https://github.com/kuzmich321 updated https://github.com/llvm/llvm-project/pull/159119

>From 21f94135a5138516f4daa48b499bcf8c040e37b4 Mon Sep 17 00:00:00 2001
From: Arpad Borsos <swatinem at swatinem.de>
Date: Wed, 21 Aug 2024 14:29:47 +0200
Subject: [PATCH 1/3] Add executed MC/DC TestVectors to `llvm-cov export`

---
 .../Inputs/binary-formats.canonical.json      |  2 +-
 llvm/tools/llvm-cov/CoverageExporterJson.cpp  | 54 +++++++++++++------
 2 files changed, 40 insertions(+), 16 deletions(-)

diff --git a/llvm/test/tools/llvm-cov/Inputs/binary-formats.canonical.json b/llvm/test/tools/llvm-cov/Inputs/binary-formats.canonical.json
index 5f9122d01da9a..f219ca6c7e179 100644
--- a/llvm/test/tools/llvm-cov/Inputs/binary-formats.canonical.json
+++ b/llvm/test/tools/llvm-cov/Inputs/binary-formats.canonical.json
@@ -33,4 +33,4 @@ CHECK-SAME:     "mcdc":{"count":0,"covered":0,"notcovered":0,"percent":0},
 CHECK-SAME:     "regions":{"count":1,"covered":1,"notcovered":0,"percent":100}}}
 CHECK-SAME: ],
 CHECK-SAME: "type":"llvm.coverage.json.export"
-CHECK-SAME: "version":"3.0.1"
+CHECK-SAME: "version":"3.1.0"
diff --git a/llvm/tools/llvm-cov/CoverageExporterJson.cpp b/llvm/tools/llvm-cov/CoverageExporterJson.cpp
index 06de33dc070e0..5319286addf54 100644
--- a/llvm/tools/llvm-cov/CoverageExporterJson.cpp
+++ b/llvm/tools/llvm-cov/CoverageExporterJson.cpp
@@ -62,7 +62,7 @@
 #include <utility>
 
 /// The semantic version combined as a string.
-#define LLVM_COVERAGE_EXPORT_JSON_STR "3.0.1"
+#define LLVM_COVERAGE_EXPORT_JSON_STR "3.1.0"
 
 /// Unique type identifier for JSON coverage export.
 #define LLVM_COVERAGE_EXPORT_JSON_TYPE_STR "llvm.coverage.json.export"
@@ -108,13 +108,42 @@ json::Array gatherConditions(const coverage::MCDCRecord &Record) {
   return Conditions;
 }
 
+json::Value renderCondState(const coverage::MCDCRecord::CondState CondState) {
+  switch (CondState) {
+  case coverage::MCDCRecord::MCDC_DontCare:
+    return json::Value(nullptr);
+  case coverage::MCDCRecord::MCDC_True:
+    return json::Value(true);
+  case coverage::MCDCRecord::MCDC_False:
+    return json::Value(false);
+  }
+}
+
+json::Array gatherTestVectors(coverage::MCDCRecord &Record) {
+  json::Array TestVectors;
+  unsigned NumConditions = Record.getNumConditions();
+  for (unsigned tv = 0; tv < Record.getNumTestVectors(); tv++) {
+
+    json::Array TVConditions;
+    for (unsigned c = 0; c < NumConditions; c++)
+      TVConditions.push_back(renderCondState(Record.getTVCondition(tv, c)));
+
+    TestVectors.push_back(
+        json::Object({{"executed", json::Value(true)},
+                      {"result", renderCondState(Record.getTVResult(tv))},
+                      {"conditions", std::move(TVConditions)}}));
+  }
+  return TestVectors;
+}
+
 json::Array renderMCDCRecord(const coverage::MCDCRecord &Record) {
   const llvm::coverage::CounterMappingRegion &CMR = Record.getDecisionRegion();
   const auto [TrueDecisions, FalseDecisions] = Record.getDecisions();
   return json::Array({CMR.LineStart, CMR.ColumnStart, CMR.LineEnd,
                       CMR.ColumnEnd, TrueDecisions, FalseDecisions,
                       CMR.FileID, CMR.ExpandedFileID, int64_t(CMR.Kind),
-                      gatherConditions(Record)});
+                      gatherConditions(Record),
+                      gatherTestVectors(const_cast<coverage::MCDCRecord &>(Record))});
 }
 
 json::Array renderRegions(ArrayRef<coverage::CountedRegion> Regions) {
@@ -216,32 +245,28 @@ json::Object renderSummary(const FileCoverageSummary &Summary) {
 }
 
 json::Array renderFileExpansions(const coverage::CoverageMapping &Coverage,
-                                 const coverage::CoverageData &FileCoverage,
-                                 const FileCoverageSummary &FileReport) {
+                                 const coverage::CoverageData &FileCoverage) {
   json::Array ExpansionArray;
   for (const auto &Expansion : FileCoverage.getExpansions())
     ExpansionArray.push_back(renderExpansion(Coverage, Expansion));
   return ExpansionArray;
 }
 
-json::Array renderFileSegments(const coverage::CoverageData &FileCoverage,
-                               const FileCoverageSummary &FileReport) {
+json::Array renderFileSegments(const coverage::CoverageData &FileCoverage) {
   json::Array SegmentArray;
   for (const auto &Segment : FileCoverage)
     SegmentArray.push_back(renderSegment(Segment));
   return SegmentArray;
 }
 
-json::Array renderFileBranches(const coverage::CoverageData &FileCoverage,
-                               const FileCoverageSummary &FileReport) {
+json::Array renderFileBranches(const coverage::CoverageData &FileCoverage) {
   json::Array BranchArray;
   for (const auto &Branch : FileCoverage.getBranches())
     BranchArray.push_back(renderBranch(Branch));
   return BranchArray;
 }
 
-json::Array renderFileMCDC(const coverage::CoverageData &FileCoverage,
-                           const FileCoverageSummary &FileReport) {
+json::Array renderFileMCDC(const coverage::CoverageData &FileCoverage) {
   json::Array MCDCRecordArray;
   for (const auto &Record : FileCoverage.getMCDCRecords())
     MCDCRecordArray.push_back(renderMCDCRecord(Record));
@@ -256,12 +281,11 @@ json::Object renderFile(const coverage::CoverageMapping &Coverage,
   if (!Options.ExportSummaryOnly) {
     // Calculate and render detailed coverage information for given file.
     auto FileCoverage = Coverage.getCoverageForFile(Filename);
-    File["segments"] = renderFileSegments(FileCoverage, FileReport);
-    File["branches"] = renderFileBranches(FileCoverage, FileReport);
-    File["mcdc_records"] = renderFileMCDC(FileCoverage, FileReport);
+    File["segments"] = renderFileSegments(FileCoverage);
+    File["branches"] = renderFileBranches(FileCoverage);
+    File["mcdc_records"] = renderFileMCDC(FileCoverage);
     if (!Options.SkipExpansions) {
-      File["expansions"] =
-          renderFileExpansions(Coverage, FileCoverage, FileReport);
+      File["expansions"] = renderFileExpansions(Coverage, FileCoverage);
     }
   }
   File["summary"] = renderSummary(FileReport);

>From a9e1ad2ffdc820a8cd99adb1e958ad90f208ed47 Mon Sep 17 00:00:00 2001
From: Andrew Ignatov <dota2drot at gmail.com>
Date: Tue, 16 Sep 2025 17:58:18 +0200
Subject: [PATCH 2/3] add doc and tests for executed test vectors in llvm-cov
 export

---
 llvm/test/tools/llvm-cov/mcdc-export-json.test | 8 ++++----
 llvm/tools/llvm-cov/CoverageExporterJson.cpp   | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/llvm/test/tools/llvm-cov/mcdc-export-json.test b/llvm/test/tools/llvm-cov/mcdc-export-json.test
index e6dbd17bee5b2..30055bef415b8 100644
--- a/llvm/test/tools/llvm-cov/mcdc-export-json.test
+++ b/llvm/test/tools/llvm-cov/mcdc-export-json.test
@@ -1,10 +1,10 @@
 // RUN: llvm-profdata merge %S/Inputs/mcdc-general.proftext -o %t.profdata
 // RUN: llvm-cov export --format=text %S/Inputs/mcdc-general.o -instr-profile %t.profdata | FileCheck %s
 
-// CHECK: 12,7,12,27,2,4,0,0,5,[true,true,true,true]
-// CHECK: 15,7,15,13,1,2,0,0,5,[true,true]
-// CHECK: 15,19,15,25,1,1,0,0,5,[true,false]
-// CHECK: 18,7,19,15,1,3,0,0,5,[true,true,false,true]
+// CHECK: 12,7,12,27,2,4,0,0,5,[true,true,true,true],[{"conditions":[false,null,false,null],"executed":true,"result":false},{"conditions":[false,null,true,false],"executed":true,"result":false},{"conditions":[true,false,false,null],"executed":true,"result":false},{"conditions":[true,false,true,false],"executed":true,"result":false},{"conditions":[true,false,true,true],"executed":true,"result":true},{"conditions":[true,true,null,null],"executed":true,"result":true}]],[15,7,15,13,1,2,0,0,5,[true,true],[{"conditions":[false,null],"executed":true,"result":false},{"conditions":[true,false],"executed":true,"result":false},{"conditions":[true,true],"executed":true,"result":true}]],[15,19,15,25,1,1,0,0,5,[true,false],[{"conditions":[false,null],"executed":true,"result":false},{"conditions":[true,true],"executed":true,"result":true}]],[18,7,19,15,1,3,0,0,5,[true,true,false,true],[{"conditions":[false,null,null,null],"executed":true,"result":false},{"conditions":[true,false,null,null],"executed":true,"result":false},{"conditions":[true,true,true,false],"executed":true,"result":false},{"conditions":[true,true,true,true],"executed":true,"result":true}]]
+// CHECK: 15,7,15,13,1,2,0,0,5,[true,true],[{"conditions":[false,null],"executed":true,"result":false},{"conditions":[true,false],"executed":true,"result":false},{"conditions":[true,true],"executed":true,"result":true}]
+// CHECK: 15,19,15,25,1,1,0,0,5,[true,false],[{"conditions":[false,null],"executed":true,"result":false},{"conditions":[true,true],"executed":true,"result":true}]
+// CHECK: 18,7,19,15,1,3,0,0,5,[true,true,false,true],[{"conditions":[false,null,null,null],"executed":true,"result":false},{"conditions":[true,false,null,null],"executed":true,"result":false},{"conditions":[true,true,true,false],"executed":true,"result":false},{"conditions":[true,true,true,true],"executed":true,"result":true}]
 // CHECK: "mcdc":{"count":12,"covered":10,"notcovered":2,"percent":83.333333333333343}
 
 Instructions for regenerating the test:
diff --git a/llvm/tools/llvm-cov/CoverageExporterJson.cpp b/llvm/tools/llvm-cov/CoverageExporterJson.cpp
index 5319286addf54..2abaaaf8d2012 100644
--- a/llvm/tools/llvm-cov/CoverageExporterJson.cpp
+++ b/llvm/tools/llvm-cov/CoverageExporterJson.cpp
@@ -21,7 +21,7 @@
 //         -- Branches: array => List of Branches in the file
 //           -- Branch: dict => Describes a branch of the file with counters
 //         -- MCDC Records: array => List of MCDC records in the file
-//           -- MCDC Values: array => List of T/F covered condition values
+//           -- MCDC Values: array => List of T/F covered condition values and list of executed test vectors
 //         -- Segments: array => List of Segments contained in the file
 //           -- Segment: dict => Describes a segment of the file with a counter
 //         -- Expansions: array => List of expansion records

>From 67ccd34564b715e7203823a571cbef8ac232510d Mon Sep 17 00:00:00 2001
From: Andrew Ignatov <dota2drot at gmail.com>
Date: Tue, 16 Sep 2025 20:30:31 +0200
Subject: [PATCH 3/3] cleanup

---
 llvm/test/tools/llvm-cov/mcdc-export-json.test | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/test/tools/llvm-cov/mcdc-export-json.test b/llvm/test/tools/llvm-cov/mcdc-export-json.test
index 30055bef415b8..4b6f3b011451a 100644
--- a/llvm/test/tools/llvm-cov/mcdc-export-json.test
+++ b/llvm/test/tools/llvm-cov/mcdc-export-json.test
@@ -1,7 +1,7 @@
 // RUN: llvm-profdata merge %S/Inputs/mcdc-general.proftext -o %t.profdata
 // RUN: llvm-cov export --format=text %S/Inputs/mcdc-general.o -instr-profile %t.profdata | FileCheck %s
 
-// CHECK: 12,7,12,27,2,4,0,0,5,[true,true,true,true],[{"conditions":[false,null,false,null],"executed":true,"result":false},{"conditions":[false,null,true,false],"executed":true,"result":false},{"conditions":[true,false,false,null],"executed":true,"result":false},{"conditions":[true,false,true,false],"executed":true,"result":false},{"conditions":[true,false,true,true],"executed":true,"result":true},{"conditions":[true,true,null,null],"executed":true,"result":true}]],[15,7,15,13,1,2,0,0,5,[true,true],[{"conditions":[false,null],"executed":true,"result":false},{"conditions":[true,false],"executed":true,"result":false},{"conditions":[true,true],"executed":true,"result":true}]],[15,19,15,25,1,1,0,0,5,[true,false],[{"conditions":[false,null],"executed":true,"result":false},{"conditions":[true,true],"executed":true,"result":true}]],[18,7,19,15,1,3,0,0,5,[true,true,false,true],[{"conditions":[false,null,null,null],"executed":true,"result":false},{"conditions":[true,false,null,null],"executed":true,"result":false},{"conditions":[true,true,true,false],"executed":true,"result":false},{"conditions":[true,true,true,true],"executed":true,"result":true}]]
+// CHECK: 12,7,12,27,2,4,0,0,5,[true,true,true,true],[{"conditions":[false,null,false,null],"executed":true,"result":false},{"conditions":[false,null,true,false],"executed":true,"result":false},{"conditions":[true,false,false,null],"executed":true,"result":false},{"conditions":[true,false,true,false],"executed":true,"result":false},{"conditions":[true,false,true,true],"executed":true,"result":true},{"conditions":[true,true,null,null],"executed":true,"result":true}]
 // CHECK: 15,7,15,13,1,2,0,0,5,[true,true],[{"conditions":[false,null],"executed":true,"result":false},{"conditions":[true,false],"executed":true,"result":false},{"conditions":[true,true],"executed":true,"result":true}]
 // CHECK: 15,19,15,25,1,1,0,0,5,[true,false],[{"conditions":[false,null],"executed":true,"result":false},{"conditions":[true,true],"executed":true,"result":true}]
 // CHECK: 18,7,19,15,1,3,0,0,5,[true,true,false,true],[{"conditions":[false,null,null,null],"executed":true,"result":false},{"conditions":[true,false,null,null],"executed":true,"result":false},{"conditions":[true,true,true,false],"executed":true,"result":false},{"conditions":[true,true,true,true],"executed":true,"result":true}]



More information about the llvm-commits mailing list