Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[Coverage] Add gap region between binary operator '&& and ||' and RHS#149085

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
int-zjt wants to merge3 commits intollvm:main
base:main
Choose a base branch
Loading
fromint-zjt:add_gap_region_after_and_or

Conversation

int-zjt
Copy link
Contributor

Issue Summary

We identified an inaccuracy in line coverage reporting when short-circuit evaluation occurs in multi-line conditional expressions. Specifically:

  1. Un-executed conditions following line breaks may be incorrectly marked as covered
    (e.g., conditionB in a non-executed && chain shows coverage)
    1|       |#include <iostream>    2|       |    3|      1|int main() {    4|      1|    bool conditionA = false;    5|      1|    bool conditionB = true;    6|      1|    if (conditionA &&    7|      1|        conditionB) {    8|      0|        std::cout << "IF-THEN" << std::endl;    9|      0|    }   10|      1|    return 0;   11|      1|}
  1. Inconsistent coverage reporting across un-executed conditions
    (adjacent un-executed conditions may show 1 vs 0 line coverage)
    1|       |#include <iostream>    2|       |    3|      1|int main() {    4|      1|    bool conditionA = false;    5|      1|    bool conditionB = true;    6|      1|    bool conditionC = true;    7|      1|    if (conditionA &&    8|      1|        (conditionB ||    9|      0|        conditionC)) {   10|      0|        std::cout << "IF-THEN" << std::endl;   11|      0|    }   12|      1|    return 0;   13|      1|}

Root Cause Analysis

The currentWrappedSegment mechanism may propagates coverage data from the last segment of the LHS line to subsequent RHS lines. Because the LHS line's coverage data depends on count of its segments andWrappedSegment's count, it may causes false positive coverage for un-executed RHS conditions.

Proposed Solution

The current implementation correctly handles single-statement if bodies through GapRegion insertion:

if (cond)       // Line 1    statement;  // Line 2

Processing workflow:

  1. A GapRegion is created spanning from the end of the condition (Line 1) to the start of the body statement (Line 2)
  2. This GapRegion inherits the execution counter from Line 2
  3. During coverage calculation:
  • Line 2 uses this GapRegion as its WrappedSegment
  • Prevents propagation of Line 1's coverage data to Line 2

Generalize the GapRegion insertion strategy from if-statements to logical operators, placing RHS-synchronized segments at LHS-line-end to isolate coverage contexts during short-circuit evaluation.

@llvmbotllvmbot added clangClang issues not falling into any other category compiler-rt clang:codegenIR generation bugs: mangling, exceptions, etc. PGOProfile Guided Optimizations labelsJul 16, 2025
@llvmbot
Copy link
Member

llvmbot commentedJul 16, 2025
edited
Loading

@llvm/pr-subscribers-pgo
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-codegen

Author: None (int-zjt)

Changes

Issue Summary

We identified an inaccuracy in line coverage reporting when short-circuit evaluation occurs in multi-line conditional expressions. Specifically:

  1. Un-executed conditions following line breaks may be incorrectly marked as covered
    (e.g., conditionB in a non-executed && chain shows coverage)
    1|       |#include &lt;iostream&gt;    2|       |    3|      1|int main() {    4|      1|    bool conditionA = false;    5|      1|    bool conditionB = true;    6|      1|    if (conditionA &amp;&amp;    7|      1|        conditionB) {    8|      0|        std::cout &lt;&lt; "IF-THEN" &lt;&lt; std::endl;    9|      0|    }   10|      1|    return 0;   11|      1|}
  1. Inconsistent coverage reporting across un-executed conditions
    (adjacent un-executed conditions may show 1 vs 0 line coverage)
    1|       |#include &lt;iostream&gt;    2|       |    3|      1|int main() {    4|      1|    bool conditionA = false;    5|      1|    bool conditionB = true;    6|      1|    bool conditionC = true;    7|      1|    if (conditionA &amp;&amp;    8|      1|        (conditionB ||    9|      0|        conditionC)) {   10|      0|        std::cout &lt;&lt; "IF-THEN" &lt;&lt; std::endl;   11|      0|    }   12|      1|    return 0;   13|      1|}

Root Cause Analysis

The currentWrappedSegment mechanism may propagates coverage data from the last segment of the LHS line to subsequent RHS lines. Because the LHS line's coverage data depends on count of its segments andWrappedSegment's count, it may causes false positive coverage for un-executed RHS conditions.

Proposed Solution

The current implementation correctly handles single-statement if bodies through GapRegion insertion:

if (cond)       // Line 1    statement;  // Line 2

Processing workflow:

  1. A GapRegion is created spanning from the end of the condition (Line 1) to the start of the body statement (Line 2)
  2. This GapRegion inherits the execution counter from Line 2
  3. During coverage calculation:
  • Line 2 uses this GapRegion as its WrappedSegment
  • Prevents propagation of Line 1's coverage data to Line 2

Generalize the GapRegion insertion strategy from if-statements to logical operators, placing RHS-synchronized segments at LHS-line-end to isolate coverage contexts during short-circuit evaluation.


Full diff:https://github.com/llvm/llvm-project/pull/149085.diff

2 Files Affected:

  • (modified) clang/lib/CodeGen/CoverageMappingGen.cpp (+10)
  • (added) compiler-rt/test/profile/Linux/coverage_short_circuit.cpp (+36)
diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cppindex 4aafac349e3e9..f55290a5feee6 100644--- a/clang/lib/CodeGen/CoverageMappingGen.cpp+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp@@ -2269,6 +2269,11 @@ struct CounterCoverageMappingBuilder     // Track LHS True/False Decision.     const auto DecisionLHS = MCDCBuilder.pop();+    if (auto Gap =+            findGapAreaBetween(getEnd(E->getLHS()), getStart(E->getRHS()))) {+      fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), getRegionCounter(E));+    }+     // Counter tracks the right hand side of a logical and operator.     extendRegion(E->getRHS());     propagateCounts(getRegionCounter(E), E->getRHS());@@ -2330,6 +2335,11 @@ struct CounterCoverageMappingBuilder     // Track LHS True/False Decision.     const auto DecisionLHS = MCDCBuilder.pop();+    if (auto Gap =+            findGapAreaBetween(getEnd(E->getLHS()), getStart(E->getRHS()))) {+      fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), getRegionCounter(E));+    }+     // Counter tracks the right hand side of a logical or operator.     extendRegion(E->getRHS());     propagateCounts(getRegionCounter(E), E->getRHS());diff --git a/compiler-rt/test/profile/Linux/coverage_short_circuit.cpp b/compiler-rt/test/profile/Linux/coverage_short_circuit.cppnew file mode 100644index 0000000000000..cc4022bc3c286--- /dev/null+++ b/compiler-rt/test/profile/Linux/coverage_short_circuit.cpp@@ -0,0 +1,36 @@+// RUN: %clangxx_profgen -std=c++17 -fuse-ld=lld -fcoverage-mapping -o %t %s+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t+// RUN: llvm-profdata merge -o %t.profdata %t.profraw+// RUN: llvm-cov show %t -instr-profile=%t.profdata 2>&1 | FileCheck %s++void foo() {          // CHECK:       [[@LINE]]| 1|void foo() {+  bool cond1 = false; // CHECK-NEXT:  [[@LINE]]| 1|  bool cond1 = false;+  bool cond2 = true;  // CHECK-NEXT:  [[@LINE]]| 1|  bool cond2 = true;+  if (cond1 &&        // CHECK-NEXT:  [[@LINE]]| 1|  if (cond1 &&+      cond2) {        // CHECK-NEXT:  [[@LINE]]| 0|      cond2) {+  }                   // CHECK-NEXT:  [[@LINE]]| 0|  }+} // CHECK-NEXT:  [[@LINE]]| 1|}++void bar() {          // CHECK:       [[@LINE]]| 1|void bar() {+  bool cond1 = true;  // CHECK-NEXT:  [[@LINE]]| 1|  bool cond1 = true;+  bool cond2 = false; // CHECK-NEXT:  [[@LINE]]| 1|  bool cond2 = false;+  if (cond1 &&        // CHECK-NEXT:  [[@LINE]]| 1|  if (cond1 &&+      cond2) {        // CHECK-NEXT:  [[@LINE]]| 1|      cond2) {+  }                   // CHECK-NEXT:  [[@LINE]]| 0|  }+} // CHECK-NEXT:  [[@LINE]]| 1|}++void baz() {          // CHECK:       [[@LINE]]| 1|void baz() {+  bool cond1 = false; // CHECK-NEXT:  [[@LINE]]| 1|  bool cond1 = false;+  bool cond2 = true;  // CHECK-NEXT:  [[@LINE]]| 1|  bool cond2 = true;+  if (cond1           // CHECK-NEXT:  [[@LINE]]| 1|  if (cond1+      &&              // CHECK-NEXT:  [[@LINE]]| 0|      &&+      cond2) {        // CHECK-NEXT:  [[@LINE]]| 0|      cond2) {+  }                   // CHECK-NEXT:  [[@LINE]]| 0|  }+} // CHECK-NEXT:  [[@LINE]]| 1|}++int main() {+  foo();+  bar();+  baz();+  return 0;+}

@github-actionsGitHub Actions
Copy link

github-actionsbot commentedJul 16, 2025
edited
Loading

✅ With the latest revision this PR passed the C/C++ code formatter.

@evodius96
Copy link
Contributor

Thank you! I assume this is only a problem with line coverage? In other words, region coverage is still correct when visualized.

@int-zjt
Copy link
ContributorAuthor

Thank you! I assume this is only a problem with line coverage? In other words, region coverage is still correct when visualized.

Yeah, region coverage is still correct, just line coverage is wrong.

@Enna1
Copy link
Contributor

Clang :: CoverageMapping/logical.cpp test failed

@int-zjtint-zjt changed the title[llvm-cov] Add gap region between binary operator '&& and ||' and RHS[Coverage] Add gap region between binary operator '&& and ||' and RHSJul 17, 2025
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@chapunichapuniAwaiting requested review from chapuni

@MaskRayMaskRayAwaiting requested review from MaskRay

@ZequanWuZequanWuAwaiting requested review from ZequanWu

@evodius96evodius96Awaiting requested review from evodius96

Assignees
No one assigned
Labels
clang:codegenIR generation bugs: mangling, exceptions, etc.clangClang issues not falling into any other categorycompiler-rtPGOProfile Guided Optimizations
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

4 participants
@int-zjt@llvmbot@evodius96@Enna1

[8]ページ先頭

©2009-2025 Movatter.jp