Skip to content

Commit 424b9cf

Browse files
authored
[Coverage][clang] Ensure bitmap for ternary condition is updated before visiting children (#78814)
This is a fix for MC/DC issue #78453 in which a ConditionalOperator that evaluates a complex condition was incorrectly updating its global bitmap after visiting its LHS and RHS children. This was wrong because if the LHS or RHS also evaluate a complex condition, the MCDC temporary bitmap value will get corrupted. The fix is to ensure that the bitmap is updated prior to visiting the LHS and RHS.
1 parent 1000cef commit 424b9cf

File tree

2 files changed

+95
-4
lines changed

2 files changed

+95
-4
lines changed

clang/lib/CodeGen/CGExprScalar.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4960,6 +4960,13 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
49604960
CGF.getProfileCount(lhsExpr));
49614961

49624962
CGF.EmitBlock(LHSBlock);
4963+
4964+
// If the top of the logical operator nest, update the MCDC bitmap for the
4965+
// ConditionalOperator prior to visiting its LHS and RHS blocks, since they
4966+
// may also contain a boolean expression.
4967+
if (CGF.MCDCLogOpStack.empty())
4968+
CGF.maybeUpdateMCDCTestVectorBitmap(condExpr);
4969+
49634970
CGF.incrementProfileCounter(E);
49644971
eval.begin(CGF);
49654972
Value *LHS = Visit(lhsExpr);
@@ -4969,6 +4976,13 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
49694976
Builder.CreateBr(ContBlock);
49704977

49714978
CGF.EmitBlock(RHSBlock);
4979+
4980+
// If the top of the logical operator nest, update the MCDC bitmap for the
4981+
// ConditionalOperator prior to visiting its LHS and RHS blocks, since they
4982+
// may also contain a boolean expression.
4983+
if (CGF.MCDCLogOpStack.empty())
4984+
CGF.maybeUpdateMCDCTestVectorBitmap(condExpr);
4985+
49724986
eval.begin(CGF);
49734987
Value *RHS = Visit(rhsExpr);
49744988
eval.end(CGF);
@@ -4987,10 +5001,6 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
49875001
PN->addIncoming(LHS, LHSBlock);
49885002
PN->addIncoming(RHS, RHSBlock);
49895003

4990-
// If the top of the logical operator nest, update the MCDC bitmap.
4991-
if (CGF.MCDCLogOpStack.empty())
4992-
CGF.maybeUpdateMCDCTestVectorBitmap(condExpr);
4993-
49945004
return PN;
49955005
}
49965006

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// RUN: %clang_cc1 -triple %itanium_abi_triple %s -o - -emit-llvm -fprofile-instrument=clang -fcoverage-mapping -fcoverage-mcdc | FileCheck %s -check-prefix=MCDC
2+
// RUN: %clang_cc1 -triple %itanium_abi_triple %s -o - -emit-llvm -fprofile-instrument=clang -fcoverage-mapping | FileCheck %s -check-prefix=NOMCDC
3+
4+
int test(int a, int b, int c, int d, int e, int f) {
5+
return ((a || b) ? (c && d) : (e || f));
6+
}
7+
8+
// NOMCDC-NOT: %mcdc.addr
9+
// NOMCDC-NOT: __profbm_test
10+
11+
// MCDC BOOKKEEPING.
12+
// MCDC: @__profbm_test = private global [3 x i8] zeroinitializer
13+
14+
// ALLOCATE MCDC TEMP AND ZERO IT.
15+
// MCDC-LABEL: @test(
16+
// MCDC: %mcdc.addr = alloca i32, align 4
17+
// MCDC: store i32 0, ptr %mcdc.addr, align 4
18+
19+
// TERNARY TRUE SHOULD UPDATE THE BITMAP WITH RESULT AT ELEMENT 0.
20+
// MCDC-LABEL: cond.true:
21+
// MCDC-DAG: %[[TEMP:mcdc.temp[0-9]*]] = load i32, ptr %mcdc.addr, align 4
22+
// MCDC: %[[LAB1:[0-9]+]] = lshr i32 %[[TEMP]], 3
23+
// MCDC: %[[LAB2:[0-9]+]] = zext i32 %[[LAB1]] to i64
24+
// MCDC: %[[LAB3:[0-9]+]] = add i64 ptrtoint (ptr @__profbm_test to i64), %[[LAB2]]
25+
// MCDC: %[[LAB4:[0-9]+]] = inttoptr i64 %[[LAB3]] to ptr
26+
// MCDC: %[[LAB5:[0-9]+]] = and i32 %[[TEMP]], 7
27+
// MCDC: %[[LAB6:[0-9]+]] = trunc i32 %[[LAB5]] to i8
28+
// MCDC: %[[LAB7:[0-9]+]] = shl i8 1, %[[LAB6]]
29+
// MCDC: %[[LAB8:mcdc.bits[0-9]*]] = load i8, ptr %[[LAB4]], align 1
30+
// MCDC: %[[LAB9:[0-9]+]] = or i8 %[[LAB8]], %[[LAB7]]
31+
// MCDC: store i8 %[[LAB9]], ptr %[[LAB4]], align 1
32+
33+
// CHECK FOR ZERO OF MCDC TEMP
34+
// MCDC: store i32 0, ptr %mcdc.addr, align 4
35+
36+
// TERNARY TRUE YIELDS TERNARY LHS LOGICAL-AND.
37+
// TERNARY LHS LOGICAL-AND SHOULD UPDATE THE BITMAP WITH RESULT AT ELEMENT 1.
38+
// MCDC-LABEL: land.end:
39+
// MCDC-DAG: %[[TEMP:mcdc.temp[0-9]*]] = load i32, ptr %mcdc.addr, align 4
40+
// MCDC: %[[LAB1:[0-9]+]] = lshr i32 %[[TEMP]], 3
41+
// MCDC: %[[LAB2:[0-9]+]] = zext i32 %[[LAB1]] to i64
42+
// MCDC: %[[LAB3:[0-9]+]] = add i64 ptrtoint (ptr getelementptr inbounds ([3 x i8], ptr @__profbm_test, i32 0, i32 1) to i64), %[[LAB2]]
43+
// MCDC: %[[LAB4:[0-9]+]] = inttoptr i64 %[[LAB3]] to ptr
44+
// MCDC: %[[LAB5:[0-9]+]] = and i32 %[[TEMP]], 7
45+
// MCDC: %[[LAB6:[0-9]+]] = trunc i32 %[[LAB5]] to i8
46+
// MCDC: %[[LAB7:[0-9]+]] = shl i8 1, %[[LAB6]]
47+
// MCDC: %[[LAB8:mcdc.bits[0-9]*]] = load i8, ptr %[[LAB4]], align 1
48+
// MCDC: %[[LAB9:[0-9]+]] = or i8 %[[LAB8]], %[[LAB7]]
49+
// MCDC: store i8 %[[LAB9]], ptr %[[LAB4]], align 1
50+
51+
// TERNARY FALSE SHOULD UPDATE THE BITMAP WITH RESULT AT ELEMENT 0.
52+
// MCDC-LABEL: cond.false:
53+
// MCDC-DAG: %[[TEMP:mcdc.temp[0-9]*]] = load i32, ptr %mcdc.addr, align 4
54+
// MCDC: %[[LAB1:[0-9]+]] = lshr i32 %[[TEMP]], 3
55+
// MCDC: %[[LAB2:[0-9]+]] = zext i32 %[[LAB1]] to i64
56+
// MCDC: %[[LAB3:[0-9]+]] = add i64 ptrtoint (ptr @__profbm_test to i64), %[[LAB2]]
57+
// MCDC: %[[LAB4:[0-9]+]] = inttoptr i64 %[[LAB3]] to ptr
58+
// MCDC: %[[LAB5:[0-9]+]] = and i32 %[[TEMP]], 7
59+
// MCDC: %[[LAB6:[0-9]+]] = trunc i32 %[[LAB5]] to i8
60+
// MCDC: %[[LAB7:[0-9]+]] = shl i8 1, %[[LAB6]]
61+
// MCDC: %[[LAB8:mcdc.bits[0-9]*]] = load i8, ptr %[[LAB4]], align 1
62+
// MCDC: %[[LAB9:[0-9]+]] = or i8 %[[LAB8]], %[[LAB7]]
63+
// MCDC: store i8 %[[LAB9]], ptr %[[LAB4]], align 1
64+
65+
// CHECK FOR ZERO OF MCDC TEMP
66+
// MCDC: store i32 0, ptr %mcdc.addr, align 4
67+
68+
// TERNARY FALSE YIELDS TERNARY RHS LOGICAL-OR.
69+
// TERNARY RHS LOGICAL-OR SHOULD UPDATE THE BITMAP WITH RESULT AT ELEMENT 2.
70+
// MCDC-LABEL: lor.end:
71+
// MCDC-DAG: %[[TEMP:mcdc.temp[0-9]*]] = load i32, ptr %mcdc.addr, align 4
72+
// MCDC: %[[LAB1:[0-9]+]] = lshr i32 %[[TEMP]], 3
73+
// MCDC: %[[LAB2:[0-9]+]] = zext i32 %[[LAB1]] to i64
74+
// MCDC: %[[LAB3:[0-9]+]] = add i64 ptrtoint (ptr getelementptr inbounds ([3 x i8], ptr @__profbm_test, i32 0, i32 2) to i64), %[[LAB2]]
75+
// MCDC: %[[LAB4:[0-9]+]] = inttoptr i64 %[[LAB3]] to ptr
76+
// MCDC: %[[LAB5:[0-9]+]] = and i32 %[[TEMP]], 7
77+
// MCDC: %[[LAB6:[0-9]+]] = trunc i32 %[[LAB5]] to i8
78+
// MCDC: %[[LAB7:[0-9]+]] = shl i8 1, %[[LAB6]]
79+
// MCDC: %[[LAB8:mcdc.bits[0-9]*]] = load i8, ptr %[[LAB4]], align 1
80+
// MCDC: %[[LAB9:[0-9]+]] = or i8 %[[LAB8]], %[[LAB7]]
81+
// MCDC: store i8 %[[LAB9]], ptr %[[LAB4]], align 1

0 commit comments

Comments
 (0)