https://github.com/chapuni created https://github.com/llvm/llvm-project/pull/125405
Fixes #124565 >From f70a6c8686617963c55854c2d8c6fa8607ca0806 Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi <geek4ci...@gmail.com> Date: Sun, 2 Feb 2025 22:10:25 +0900 Subject: [PATCH] [MC/DC] Handle __builtin_expect as if parenthses Fixes #124565 --- clang/include/clang/AST/IgnoreExpr.h | 9 +++++++++ clang/lib/CodeGen/CodeGenFunction.cpp | 13 ++++++++----- clang/lib/CodeGen/CodeGenPGO.cpp | 8 +++++--- clang/test/CoverageMapping/mcdc-nested-expr.cpp | 5 ++++- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/clang/include/clang/AST/IgnoreExpr.h b/clang/include/clang/AST/IgnoreExpr.h index 917bada61fa6fdd..c366aa176674815 100644 --- a/clang/include/clang/AST/IgnoreExpr.h +++ b/clang/include/clang/AST/IgnoreExpr.h @@ -134,6 +134,15 @@ inline Expr *IgnoreElidableImplicitConstructorSingleStep(Expr *E) { return E; } +inline Expr *IgnoreBuiltinExpectSingleStep(Expr *E) { + if (auto *CE = dyn_cast<CallExpr>(E)) { + if (const FunctionDecl *FD = CE->getDirectCallee()) + if (FD->getBuiltinID() == Builtin::BI__builtin_expect) + return CE->getArg(0); + } + 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 bbef277a524480b..05766aa7693d2e1 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,14 @@ 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, + IgnoreBuiltinExpectSingleStep, + IgnoreImplicitCastsSingleStep); + 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 792373839107f0a..0fd49b880bba305 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/test/CoverageMapping/mcdc-nested-expr.cpp b/clang/test/CoverageMapping/mcdc-nested-expr.cpp index bb82873e3b600d0..0614a2b7ab8c101 100644 --- a/clang/test/CoverageMapping/mcdc-nested-expr.cpp +++ b/clang/test/CoverageMapping/mcdc-nested-expr.cpp @@ -21,8 +21,11 @@ bool func_condop(bool a, bool b, bool c) { // 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); + // CHECK: Decision,File 0, [[@LINE-1]]:10 -> [[#L:@LINE-1]]:45 = M:4, C:3 + // CHECK: Branch,File 0, [[#L]]:10 -> [[#L]]:11 = (#0 - #1), #1 [1,0,2] + // CHECK: Branch,File 0, [[#L]]:32 -> [[#L]]:33 = #2, (#1 - #2) [2,3,0] + // CHECK: Branch,File 0, [[#L]]:37 -> [[#L]]:38 = #3, (#2 - #3) [3,0,0] } // LNot among BinOp(s) _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits