https://github.com/chapuni updated https://github.com/llvm/llvm-project/pull/125406
>From a6d4be0e4b05b411c7160385485cfed0f173965c Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi <geek4ci...@gmail.com> Date: Sun, 2 Feb 2025 21:55:43 +0900 Subject: [PATCH 1/4] [MC/DC] Update CoverageMapping tests To resolve the error, rename mcdc-error-nests.cpp -> mcdc-nested-expr.cpp at first. - `func_condop` A corner case that contains close decisions. - `func_expect` Uses `__builtin_expect`. (#124565) - `func_lnot` Contains logical not(s) `!` among MC/DC binary operators. (#124563) mcdc-single-cond.cpp is for #95336. --- .../test/CoverageMapping/mcdc-error-nests.cpp | 10 -- .../test/CoverageMapping/mcdc-nested-expr.cpp | 34 +++++++ .../test/CoverageMapping/mcdc-single-cond.cpp | 97 +++++++++++++++++++ 3 files changed, 131 insertions(+), 10 deletions(-) delete mode 100644 clang/test/CoverageMapping/mcdc-error-nests.cpp create mode 100644 clang/test/CoverageMapping/mcdc-nested-expr.cpp create mode 100644 clang/test/CoverageMapping/mcdc-single-cond.cpp diff --git a/clang/test/CoverageMapping/mcdc-error-nests.cpp b/clang/test/CoverageMapping/mcdc-error-nests.cpp deleted file mode 100644 index 3add2b9ccd3fb..0000000000000 --- a/clang/test/CoverageMapping/mcdc-error-nests.cpp +++ /dev/null @@ -1,10 +0,0 @@ -// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++11 -fcoverage-mcdc -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only %s 2>&1| FileCheck %s - -// "Split-nest" -- boolean expressions within boolean expressions. -extern bool bar(bool); -bool func_split_nest(bool a, bool b, bool c, bool d, bool e, bool f, bool g) { - bool res = a && b && c && bar(d && e) && f && g; - return bar(res); -} - -// CHECK: warning: unsupported MC/DC boolean expression; contains an operation with a nested boolean expression. diff --git a/clang/test/CoverageMapping/mcdc-nested-expr.cpp b/clang/test/CoverageMapping/mcdc-nested-expr.cpp new file mode 100644 index 0000000000000..bb82873e3b600 --- /dev/null +++ b/clang/test/CoverageMapping/mcdc-nested-expr.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++11 -fcoverage-mcdc -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only %s 2> %t.stderr.txt | FileCheck %s +// RUN: FileCheck %s --check-prefix=WARN < %t.stderr.txt + +// "Split-nest" -- boolean expressions within boolean expressions. +extern bool bar(bool); +// CHECK: func_split_nest{{.*}}: +bool func_split_nest(bool a, bool b, bool c, bool d, bool e, bool f, bool g) { + // WARN: :[[@LINE+1]]:14: warning: unsupported MC/DC boolean expression; contains an operation with a nested boolean expression. + bool res = a && b && c && bar(d && e) && f && g; + return bar(res); +} + +// The inner expr begins with the same Loc as the outer expr +// CHECK: func_condop{{.*}}: +bool func_condop(bool a, bool b, bool c) { + // WARN: :[[@LINE+1]]:10: warning: unsupported MC/DC boolean expression; contains an operation with a nested boolean expression. + return (a && b ? true : false) && c; +} + +// __builtin_expect +// Treated as parentheses. +// CHECK: func_expect{{.*}}: +bool func_expect(bool a, bool b, bool c) { + // WARN: :[[@LINE+1]]:10: warning: unsupported MC/DC boolean expression; contains an operation with a nested boolean expression. + return a || __builtin_expect(b && c, true); +} + +// LNot among BinOp(s) +// Doesn't split exprs. +// CHECK: func_lnot{{.*}}: +bool func_lnot(bool a, bool b, bool c, bool d) { + // WARN: :[[@LINE+1]]:10: warning: unsupported MC/DC boolean expression; contains an operation with a nested boolean expression. + return !(a || b) && !(c && d); +} diff --git a/clang/test/CoverageMapping/mcdc-single-cond.cpp b/clang/test/CoverageMapping/mcdc-single-cond.cpp new file mode 100644 index 0000000000000..b1eeea879e521 --- /dev/null +++ b/clang/test/CoverageMapping/mcdc-single-cond.cpp @@ -0,0 +1,97 @@ +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++11 -fcoverage-mcdc -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -disable-llvm-passes -emit-llvm -o %t2.ll %s | FileCheck %s --check-prefixes=MM,MM2 +// RUN: FileCheck %s --check-prefixes=LL,LL2 < %t2.ll + +// LL: define{{.+}}func_cond{{.+}}( +// MM: func_cond{{.*}}: +int func_cond(bool a, bool b) { + // %mcdc.addr* are emitted by static order. + // LL: %[[MA:mcdc.addr.*]] = alloca i32, align 4 + // LL: call void @llvm.instrprof.mcdc.parameters(ptr @[[PROFN:.+]], i64 [[#H:]], i32 [[#BS:]]) + int count = 0; + if (a) + // NB=2 Single cond + // MM2-NOT: Decision + ++count; + if (a ? true : false) + // NB=2,2 Wider decision comes first. + // MA2 has C:2 + // MA3 has C:1 + ++count; + if (a && b ? true : false) + // NB=2,3 Wider decision comes first. + // MM2: Decision,File 0, [[@LINE-2]]:7 -> [[#L:@LINE-2]]:13 = M:[[#I:3]], C:2 + // MM: Branch,File 0, [[#L]]:7 -> [[#L]]:8 = #6, (#0 - #6) [1,2,0] + // MM: Branch,File 0, [[#L]]:12 -> [[#L]]:13 = #7, (#6 - #7) [2,0,0] + // LL: store i32 0, ptr %[[MA]], align 4 + // LL: = load i32, ptr %[[MA]], align 4 + // LL: store i32 %{{.+}}, ptr %[[MA]], align 4 + // LL: = load i32, ptr %[[MA]], align 4 + // LL: store i32 %{{.+}}, ptr %[[MA]], align 4 + // LL2: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:0]], ptr %[[MA]]) + ++count; + while (a || true) { + // NB=3 BinOp only + // MM: Decision,File 0, [[@LINE-2]]:10 -> [[#L:@LINE-2]]:19 = M:[[#I:I+3]], C:2 + // MM: Branch,File 0, [[#L]]:10 -> [[#L]]:11 = (#0 - #9), #9 [1,0,2] + // MM: Branch,File 0, [[#L]]:15 -> [[#L]]:19 = (#9 - #10), 0 [2,0,0] + // LL: store i32 0, ptr %[[MA]], align 4 + // LL: = load i32, ptr %[[MA]], align 4 + // LL: store i32 %{{.+}}, ptr %[[MA]], align 4 + // LL: = load i32, ptr %[[MA]], align 4 + // LL: store i32 %{{.+}}, ptr %[[MA]], align 4 + // LL2: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA]]) + ++count; + break; + } + while (a || true ? false : true) { + // Wider decision comes first. + // MM2: Decision,File 0, [[@LINE-2]]:10 -> [[#L:@LINE-2]]:19 = M:[[#I:I+3]], C:2 + // MM: Branch,File 0, [[#L]]:10 -> [[#L]]:11 = ((#0 + #11) - #13), #13 [1,0,2] + // MM: Branch,File 0, [[#L]]:15 -> [[#L]]:19 = (#13 - #14), 0 [2,0,0] + // LL: store i32 0, ptr %[[MA]], align 4 + // LL: = load i32, ptr %[[MA]], align 4 + // LL: store i32 %{{.+}}, ptr %[[MA]], align 4 + // LL: = load i32, ptr %[[MA]], align 4 + // LL: store i32 %{{.+}}, ptr %[[MA]], align 4 + // LL: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA]]) + ++count; + } + do { + ++count; + } while (a && false); + // BinOp only + // MM: Decision,File 0, [[@LINE-2]]:12 -> [[#L:@LINE-2]]:22 = M:[[#I:I+3]], C:2 + // MM: Branch,File 0, [[#L]]:12 -> [[#L]]:13 = #16, ((#0 + #15) - #16) [1,2,0] + // MM: Branch,File 0, [[#L]]:17 -> [[#L]]:22 = 0, (#16 - #17) [2,0,0] + // LL: store i32 0, ptr %[[MA]], align 4 + // LL: = load i32, ptr %[[MA]], align 4 + // LL: store i32 %{{.+}}, ptr %[[MA]], align 4 + // LL: = load i32, ptr %[[MA]], align 4 + // LL: store i32 %{{.+}}, ptr %[[MA]], align 4 + // LL2: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA]]) + do { + ++count; + } while (a && false ? true : false); + // Wider decision comes first. + // MM2: Decision,File 0, [[@LINE-2]]:12 -> [[#L:@LINE-2]]:22 = M:15, C:2 + // MM: Branch,File 0, [[#L]]:12 -> [[#L]]:13 = #20, ((#0 + #18) - #20) [1,2,0] + // MM: Branch,File 0, [[#L]]:17 -> [[#L]]:22 = 0, (#20 - #21) [2,0,0] + // LL: store i32 0, ptr %[[MA]], align 4 + // LL: = load i32, ptr %[[MA]], align 4 + // LL: store i32 %{{.+}}, ptr %[[MA]], align 4 + // LL: = load i32, ptr %[[MA]], align 4 + // LL: store i32 %{{.+}}, ptr %[[MA]], align 4 + // LL: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA]]) + // FIXME: Confirm (B+3==BS) + for (int i = 0; i < (a ? 2 : 1); ++i) { + // Simple nested decision (different column) + // MM2-NOT: Decision + // LL2-NOT: call void @llvm.instrprof.mcdc.tvbitmap.update + ++count; + } + for (int i = 0; i >= 4 ? false : true; ++i) { + // Wider decision comes first. + ++count; + } + return count; +} >From f2cf50e10b59d7d461967baef4d589c9282d0f6d Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi <geek4ci...@gmail.com> Date: Sun, 2 Feb 2025 22:11:51 +0900 Subject: [PATCH 2/4] [MC/DC] Enable usage of `!` among `&&` and `||` In the current implementation, `!(a || b) && c` was not treated as one Decision with three terms. Fixes #124563 --- clang/include/clang/AST/IgnoreExpr.h | 8 ++ clang/lib/CodeGen/CodeGenFunction.cpp | 12 ++- clang/lib/CodeGen/CodeGenPGO.cpp | 8 +- clang/lib/CodeGen/CoverageMappingGen.cpp | 12 +++ .../test/CoverageMapping/mcdc-nested-expr.cpp | 6 +- clang/test/Profile/c-mcdc-not.c | 95 +++++++++++++++++++ 6 files changed, 132 insertions(+), 9 deletions(-) diff --git a/clang/include/clang/AST/IgnoreExpr.h b/clang/include/clang/AST/IgnoreExpr.h index 917bada61fa6f..c48c0c0daf815 100644 --- a/clang/include/clang/AST/IgnoreExpr.h +++ b/clang/include/clang/AST/IgnoreExpr.h @@ -134,6 +134,14 @@ inline Expr *IgnoreElidableImplicitConstructorSingleStep(Expr *E) { return E; } +inline Expr *IgnoreUOpLNotSingleStep(Expr *E) { + if (auto *UO = dyn_cast<UnaryOperator>(E)) { + if (UO->getOpcode() == UO_LNot) + return UO->getSubExpr(); + } + return E; +} + inline Expr *IgnoreImplicitAsWrittenSingleStep(Expr *E) { if (auto *ICE = dyn_cast<ImplicitCastExpr>(E)) return ICE->getSubExprAsWritten(); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index bbef277a52448..2c380ac926b1e 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -27,6 +27,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" +#include "clang/AST/IgnoreExpr.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/Basic/Builtins.h" @@ -1748,12 +1749,13 @@ bool CodeGenFunction::ConstantFoldsToSimpleInteger(const Expr *Cond, /// Strip parentheses and simplistic logical-NOT operators. const Expr *CodeGenFunction::stripCond(const Expr *C) { - while (const UnaryOperator *Op = dyn_cast<UnaryOperator>(C->IgnoreParens())) { - if (Op->getOpcode() != UO_LNot) - break; - C = Op->getSubExpr(); + while (true) { + const Expr *SC = + IgnoreExprNodes(C, IgnoreParensSingleStep, IgnoreUOpLNotSingleStep); + if (C == SC) + return SC; + C = SC; } - return C->IgnoreParens(); } /// Determine whether the given condition is an instrumentable condition diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp index 792373839107f..0fd49b880bba3 100644 --- a/clang/lib/CodeGen/CodeGenPGO.cpp +++ b/clang/lib/CodeGen/CodeGenPGO.cpp @@ -247,8 +247,9 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> { } if (const Expr *E = dyn_cast<Expr>(S)) { - const BinaryOperator *BinOp = dyn_cast<BinaryOperator>(E->IgnoreParens()); - if (BinOp && BinOp->isLogicalOp()) { + if (const auto *BinOp = + dyn_cast<BinaryOperator>(CodeGenFunction::stripCond(E)); + BinOp && BinOp->isLogicalOp()) { /// Check for "split-nested" logical operators. This happens when a new /// boolean expression logical-op nest is encountered within an existing /// boolean expression, separated by a non-logical operator. For @@ -280,7 +281,8 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> { return true; if (const Expr *E = dyn_cast<Expr>(S)) { - const BinaryOperator *BinOp = dyn_cast<BinaryOperator>(E->IgnoreParens()); + const BinaryOperator *BinOp = + dyn_cast<BinaryOperator>(CodeGenFunction::stripCond(E)); if (BinOp && BinOp->isLogicalOp()) { assert(LogOpStack.back() == BinOp); LogOpStack.pop_back(); diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index f09157771d2b5..9bf73cf27a5fa 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -799,6 +799,12 @@ struct MCDCCoverageBuilder { /// Return the LHS Decision ([0,0] if not set). const mcdc::ConditionIDs &back() const { return DecisionStack.back(); } + void swapConds() { + if (DecisionStack.empty()) + return; + + std::swap(DecisionStack.back()[false], DecisionStack.back()[true]); + } /// Push the binary operator statement to track the nest level and assign IDs /// to the operator's LHS and RHS. The RHS may be a larger subtree that is /// broken up on successive levels. @@ -2241,6 +2247,12 @@ struct CounterCoverageMappingBuilder SM.isInSystemHeader(SM.getSpellingLoc(E->getEndLoc()))); } + void VisitUnaryLNot(const UnaryOperator *E) { + MCDCBuilder.swapConds(); + Visit(E->getSubExpr()); + MCDCBuilder.swapConds(); + } + void VisitBinLAnd(const BinaryOperator *E) { if (isExprInSystemHeader(E)) { LeafExprSet.insert(E); diff --git a/clang/test/CoverageMapping/mcdc-nested-expr.cpp b/clang/test/CoverageMapping/mcdc-nested-expr.cpp index bb82873e3b600..a49dad0b33612 100644 --- a/clang/test/CoverageMapping/mcdc-nested-expr.cpp +++ b/clang/test/CoverageMapping/mcdc-nested-expr.cpp @@ -29,6 +29,10 @@ bool func_expect(bool a, bool b, bool c) { // Doesn't split exprs. // CHECK: func_lnot{{.*}}: bool func_lnot(bool a, bool b, bool c, bool d) { - // WARN: :[[@LINE+1]]:10: warning: unsupported MC/DC boolean expression; contains an operation with a nested boolean expression. return !(a || b) && !(c && d); + // CHECK: Decision,File 0, [[@LINE-1]]:10 -> [[#L:@LINE-1]]:32 = M:5, C:4 + // CHECK: Branch,File 0, [[#L]]:12 -> [[#L]]:13 = (#0 - #2), #2 [1,0,3] + // CHECK: Branch,File 0, [[#L]]:17 -> [[#L]]:18 = (#2 - #3), #3 [3,0,2] + // CHECK: Branch,File 0, [[#L]]:25 -> [[#L]]:26 = #4, (#1 - #4) [2,4,0] + // CHECK: Branch,File 0, [[#L]]:30 -> [[#L]]:31 = #5, (#4 - #5) [4,0,0] } diff --git a/clang/test/Profile/c-mcdc-not.c b/clang/test/Profile/c-mcdc-not.c index 7083aa226fb95..d6d79bf15cb08 100644 --- a/clang/test/Profile/c-mcdc-not.c +++ b/clang/test/Profile/c-mcdc-not.c @@ -85,3 +85,98 @@ int test(int a, int b, int c, int d, int e, int f) { // MCDC: %[[BITS:.+]] = load i8, ptr %[[LAB4]], align 1 // MCDC: %[[LAB8:[0-9]+]] = or i8 %[[BITS]], %[[LAB7]] // MCDC: store i8 %[[LAB8]], ptr %[[LAB4]], align 1 + +int internot(int a, int b, int c, int d, int e, int f) { + return !(!(!a && b) || !(!!(!c && d) || !(e && !f))); +} + +// MCDC-LABEL: @internot( +// MCDC-DAG: store i32 0, ptr %mcdc.addr, align 4 + +// Branch #2, (#0 - #2) [1,3,0] +// !a [+0 => b][+6 => END] +// MCDC-DAG: %[[A:.+]] = load i32, ptr %a.addr, align 4 +// MCDC-DAG: %[[AB:.+]] = icmp ne i32 %[[A]], 0 +// MCDC-DAG: %[[AN:.+]] = xor i1 %[[AB]], true +// MCDC-DAG: %[[M1:.+]] = load i32, ptr %mcdc.addr, align 4 +// MCDC-DAG: %[[M1T:.+]] = add i32 %[[M1]], 0 +// MCDC-DAG: %[[M1F:.+]] = add i32 %[[M1]], 6 +// MCDC-DAG: %[[M1S:.+]] = select i1 %[[AN]], i32 %[[M1T]], i32 %[[M1F]] +// MCDC-DAG: store i32 %[[M1S]], ptr %mcdc.addr, align 4 + +// Branch #3, (#2 - #3) [3,2,0] +// b [+0 => c][+7 => END] +// MCDC-DAG: %[[B:.+]] = load i32, ptr %b.addr, align 4 +// MCDC-DAG: %[[BB:.+]] = icmp ne i32 %[[B]], 0 +// MCDC-DAG: %[[M3:.+]] = load i32, ptr %mcdc.addr, align 4 +// MCDC-DAG: %[[M3T:.+]] = add i32 %[[M3]], 0 +// MCDC-DAG: %[[M3F:.+]] = add i32 %[[M3]], 7 +// MCDC-DAG: %[[M3S:.+]] = select i1 %[[BB]], i32 %[[M3T]], i32 %[[M3F]] +// MCDC-DAG: store i32 %[[M3S]], ptr %mcdc.addr, align 4 + +// Branch #5, (#1 - #5) [2,5,4] +// !c [+0 => d][+0 => e] +// MCDC-DAG: %[[C:.+]] = load i32, ptr %c.addr, align 4 +// MCDC-DAG: %[[CB:.+]] = icmp ne i32 %[[C]], 0 +// MCDC-DAG: %[[CN:.+]] = xor i1 %[[CB]], true +// MCDC-DAG: %[[M2:.+]] = load i32, ptr %mcdc.addr, align 4 +// MCDC-DAG: %[[M2T:.+]] = add i32 %[[M2]], 0 +// MCDC-DAG: %[[M2F:.+]] = add i32 %[[M2]], 0 +// MCDC-DAG: %[[M2S:.+]] = select i1 %[[CN]], i32 %[[M2T]], i32 %[[M2F]] +// MCDC-DAG: store i32 %[[M2S]], ptr %mcdc.addr, align 4 + +// Branch #6, (#5 - #6) [5,0,4] +// d [+8 => END][+1 => e]] +// MCDC-DAG: %[[D:.+]] = load i32, ptr %d.addr, align 4 +// MCDC-DAG: %[[DB:.+]] = icmp ne i32 %[[D]], 0 +// MCDC-DAG: %[[M5:.+]] = load i32, ptr %mcdc.addr, align 4 +// MCDC-DAG: %[[M5T:.+]] = add i32 %[[M5]], 8 +// MCDC-DAG: %[[M5F:.+]] = add i32 %[[M5]], 1 +// MCDC-DAG: %[[M5S:.+]] = select i1 %[[DB]], i32 %[[M5T]], i32 %[[M5F]] +// MCDC-DAG: store i32 %[[M5S]], ptr %mcdc.addr, align 4 + +// Branch #7, (#4 - #7) [4,6,0] +// e [+0 => f][+0 => END] +// from: +// [c => +0] +// [d => +1] +// MCDC-DAG: %[[E:.+]] = load i32, ptr %e.addr, align 4 +// MCDC-DAG: %[[EB:.+]] = icmp ne i32 %[[E]], 0 +// MCDC-DAG: %[[M4:.+]] = load i32, ptr %mcdc.addr, align 4 +// MCDC-DAG: %[[M4T:.+]] = add i32 %[[M4]], 0 +// MCDC-DAG: %[[M4F:.+]] = add i32 %[[M4]], 0 +// MCDC-DAG: %[[M4S:.+]] = select i1 %[[EB]], i32 %[[M4T]], i32 %[[M4F]] +// MCDC-DAG: store i32 %[[M4S]], ptr %mcdc.addr, align 4 + +// Branch #8, (#7 - #8) [6,0,0] +// !f [+4 => END][+2 => END] +// MCDC-DAG: %[[F:.+]] = load i32, ptr %f.addr, align 4 +// MCDC-DAG: %[[FB:.+]] = icmp ne i32 %[[F]], 0 +// MCDC-DAG: %[[FN:.+]] = xor i1 %[[FB]], true +// MCDC-DAG: %[[M6:.+]] = load i32, ptr %mcdc.addr, align 4 +// MCDC-DAG: %[[M6T:.+]] = add i32 %[[M6]], 4 +// MCDC-DAG: %[[M6F:.+]] = add i32 %[[M6]], 2 +// MCDC-DAG: %[[M6S:.+]] = select i1 %[[FN]], i32 %[[M6T]], i32 %[[M6F]] +// MCDC-DAG: store i32 %[[M6S]], ptr %mcdc.addr, align 4 + +// from: +// [e => +0] +// [f => +2] +// [c => +0] +// [d => +1] +// [f => +4] +// [c => +0] +// [d => +1] +// [a => +6] +// [b => +7] +// [d => +8] +// MCDC-DAG: %[[T0:.+]] = load i32, ptr %mcdc.addr, align 4 +// MCDC-DAG: %[[T:.+]] = add i32 %[[T0]], 0 +// MCDC-DAG: %[[TA:.+]] = lshr i32 %[[T]], 3 +// MCDC-DAG: %[[BA:.+]] = getelementptr inbounds i8, ptr @__profbm_internot, i32 %[[TA]] +// MCDC-DAG: %[[BI:.+]] = and i32 %[[T]], 7 +// MCDC-DAG: %[[BI1:.+]] = trunc i32 %[[BI]] to i8 +// MCDC-DAG: %[[BM:.+]] = shl i8 1, %[[BI1]] +// MCDC-DAG: %mcdc.bits = load i8, ptr %[[BA]], align 1 +// MCDC-DAG: %[[BN:.+]] = or i8 %mcdc.bits, %[[BM]] +// MCDC-DAG: store i8 %[[BN]], ptr %[[BA]], align 1 >From 7c71ae3369b1df23c8a3e65a2950885b6162e06b Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi <geek4ci...@gmail.com> Date: Mon, 3 Feb 2025 20:30:27 +0900 Subject: [PATCH 3/4] Update ReleaseNotes --- clang/docs/ReleaseNotes.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index b8b47103d9517..22f52b388fd40 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -116,6 +116,9 @@ Improvements to Clang's time-trace Improvements to Coverage Mapping -------------------------------- +- [MC/DC] Unary logical not `!` among binary operators is recognized + as a part of the expression. (#GH124563) + Bug Fixes in This Version ------------------------- >From 8b35e76018417c301dc757ea5446292dd3a3996c Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi <geek4ci...@gmail.com> Date: Sat, 1 Mar 2025 15:52:53 +0900 Subject: [PATCH 4/4] Remove mcdc-single-cond.cpp --- .../test/CoverageMapping/mcdc-single-cond.cpp | 97 ------------------- 1 file changed, 97 deletions(-) delete mode 100644 clang/test/CoverageMapping/mcdc-single-cond.cpp diff --git a/clang/test/CoverageMapping/mcdc-single-cond.cpp b/clang/test/CoverageMapping/mcdc-single-cond.cpp deleted file mode 100644 index b1eeea879e521..0000000000000 --- a/clang/test/CoverageMapping/mcdc-single-cond.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++11 -fcoverage-mcdc -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -disable-llvm-passes -emit-llvm -o %t2.ll %s | FileCheck %s --check-prefixes=MM,MM2 -// RUN: FileCheck %s --check-prefixes=LL,LL2 < %t2.ll - -// LL: define{{.+}}func_cond{{.+}}( -// MM: func_cond{{.*}}: -int func_cond(bool a, bool b) { - // %mcdc.addr* are emitted by static order. - // LL: %[[MA:mcdc.addr.*]] = alloca i32, align 4 - // LL: call void @llvm.instrprof.mcdc.parameters(ptr @[[PROFN:.+]], i64 [[#H:]], i32 [[#BS:]]) - int count = 0; - if (a) - // NB=2 Single cond - // MM2-NOT: Decision - ++count; - if (a ? true : false) - // NB=2,2 Wider decision comes first. - // MA2 has C:2 - // MA3 has C:1 - ++count; - if (a && b ? true : false) - // NB=2,3 Wider decision comes first. - // MM2: Decision,File 0, [[@LINE-2]]:7 -> [[#L:@LINE-2]]:13 = M:[[#I:3]], C:2 - // MM: Branch,File 0, [[#L]]:7 -> [[#L]]:8 = #6, (#0 - #6) [1,2,0] - // MM: Branch,File 0, [[#L]]:12 -> [[#L]]:13 = #7, (#6 - #7) [2,0,0] - // LL: store i32 0, ptr %[[MA]], align 4 - // LL: = load i32, ptr %[[MA]], align 4 - // LL: store i32 %{{.+}}, ptr %[[MA]], align 4 - // LL: = load i32, ptr %[[MA]], align 4 - // LL: store i32 %{{.+}}, ptr %[[MA]], align 4 - // LL2: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:0]], ptr %[[MA]]) - ++count; - while (a || true) { - // NB=3 BinOp only - // MM: Decision,File 0, [[@LINE-2]]:10 -> [[#L:@LINE-2]]:19 = M:[[#I:I+3]], C:2 - // MM: Branch,File 0, [[#L]]:10 -> [[#L]]:11 = (#0 - #9), #9 [1,0,2] - // MM: Branch,File 0, [[#L]]:15 -> [[#L]]:19 = (#9 - #10), 0 [2,0,0] - // LL: store i32 0, ptr %[[MA]], align 4 - // LL: = load i32, ptr %[[MA]], align 4 - // LL: store i32 %{{.+}}, ptr %[[MA]], align 4 - // LL: = load i32, ptr %[[MA]], align 4 - // LL: store i32 %{{.+}}, ptr %[[MA]], align 4 - // LL2: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA]]) - ++count; - break; - } - while (a || true ? false : true) { - // Wider decision comes first. - // MM2: Decision,File 0, [[@LINE-2]]:10 -> [[#L:@LINE-2]]:19 = M:[[#I:I+3]], C:2 - // MM: Branch,File 0, [[#L]]:10 -> [[#L]]:11 = ((#0 + #11) - #13), #13 [1,0,2] - // MM: Branch,File 0, [[#L]]:15 -> [[#L]]:19 = (#13 - #14), 0 [2,0,0] - // LL: store i32 0, ptr %[[MA]], align 4 - // LL: = load i32, ptr %[[MA]], align 4 - // LL: store i32 %{{.+}}, ptr %[[MA]], align 4 - // LL: = load i32, ptr %[[MA]], align 4 - // LL: store i32 %{{.+}}, ptr %[[MA]], align 4 - // LL: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA]]) - ++count; - } - do { - ++count; - } while (a && false); - // BinOp only - // MM: Decision,File 0, [[@LINE-2]]:12 -> [[#L:@LINE-2]]:22 = M:[[#I:I+3]], C:2 - // MM: Branch,File 0, [[#L]]:12 -> [[#L]]:13 = #16, ((#0 + #15) - #16) [1,2,0] - // MM: Branch,File 0, [[#L]]:17 -> [[#L]]:22 = 0, (#16 - #17) [2,0,0] - // LL: store i32 0, ptr %[[MA]], align 4 - // LL: = load i32, ptr %[[MA]], align 4 - // LL: store i32 %{{.+}}, ptr %[[MA]], align 4 - // LL: = load i32, ptr %[[MA]], align 4 - // LL: store i32 %{{.+}}, ptr %[[MA]], align 4 - // LL2: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA]]) - do { - ++count; - } while (a && false ? true : false); - // Wider decision comes first. - // MM2: Decision,File 0, [[@LINE-2]]:12 -> [[#L:@LINE-2]]:22 = M:15, C:2 - // MM: Branch,File 0, [[#L]]:12 -> [[#L]]:13 = #20, ((#0 + #18) - #20) [1,2,0] - // MM: Branch,File 0, [[#L]]:17 -> [[#L]]:22 = 0, (#20 - #21) [2,0,0] - // LL: store i32 0, ptr %[[MA]], align 4 - // LL: = load i32, ptr %[[MA]], align 4 - // LL: store i32 %{{.+}}, ptr %[[MA]], align 4 - // LL: = load i32, ptr %[[MA]], align 4 - // LL: store i32 %{{.+}}, ptr %[[MA]], align 4 - // LL: call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA]]) - // FIXME: Confirm (B+3==BS) - for (int i = 0; i < (a ? 2 : 1); ++i) { - // Simple nested decision (different column) - // MM2-NOT: Decision - // LL2-NOT: call void @llvm.instrprof.mcdc.tvbitmap.update - ++count; - } - for (int i = 0; i >= 4 ? false : true; ++i) { - // Wider decision comes first. - ++count; - } - return count; -} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits