[clang] [clang][dataflow] Check for backedges directly (instead of loop statements). (PR #68923)
https://github.com/martinboehme edited https://github.com/llvm/llvm-project/pull/68923 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Check for backedges directly (instead of loop statements). (PR #68923)
@@ -53,19 +52,8 @@ static int blockIndexInPredecessor(const CFGBlock , return BlockPos - Pred.succ_begin(); } -static bool isLoopHead(const CFGBlock ) { - if (const auto *T = B.getTerminatorStmt()) -switch (T->getStmtClass()) { - case Stmt::WhileStmtClass: - case Stmt::DoStmtClass: - case Stmt::ForStmtClass: - case Stmt::CXXForRangeStmtClass: -return true; - default: -return false; -} - - return false; +static bool isBackedgeNode(const CFGBlock ) { martinboehme wrote: Yes, but * It still requires work (not everyone has an IDE with great cross-linking, so this could be multiple clicks), and * * We're introducing a new term here ("backedge node"), and it's not clear without an explanation whether a) we intend for this to be a synonym for "has loop target" (but then why aren't we reusing that term -- is it because we think "backedge node" is clearer?), or b) `getLoopTarget() != nullptr` happens to be the right implementation today, but we think it might change in the future, so we're wrapping this check in a function? https://github.com/llvm/llvm-project/pull/68923 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Check for backedges directly (instead of loop statements). (PR #68923)
https://github.com/ymand closed https://github.com/llvm/llvm-project/pull/68923 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Check for backedges directly (instead of loop statements). (PR #68923)
@@ -53,19 +52,8 @@ static int blockIndexInPredecessor(const CFGBlock , return BlockPos - Pred.succ_begin(); } -static bool isLoopHead(const CFGBlock ) { - if (const auto *T = B.getTerminatorStmt()) -switch (T->getStmtClass()) { - case Stmt::WhileStmtClass: - case Stmt::DoStmtClass: - case Stmt::ForStmtClass: - case Stmt::CXXForRangeStmtClass: -return true; - default: -return false; -} - - return false; +static bool isBackedgeNode(const CFGBlock ) { ymand wrote: https://github.com/llvm/llvm-project/blob/eb14f47bf1ccfda500ba3c3092d70e269f6f0b56/clang/include/clang/Analysis/CFG.h#L805 Fwiw, I think this comment is better than the one in the CFG, so I don't know that linking is worth much, especially since it can be found pretty easily just by looking at `getLoopTarget`. https://github.com/llvm/llvm-project/pull/68923 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Check for backedges directly (instead of loop statements). (PR #68923)
https://github.com/ymand updated https://github.com/llvm/llvm-project/pull/68923 >From 83486a35e6d0e754dd99369fc546d04afedbe923 Mon Sep 17 00:00:00 2001 From: Yitzhak Mandelbaum Date: Thu, 12 Oct 2023 19:35:54 + Subject: [PATCH 1/3] [clang][dataflow] Check for backedges directly (instead of loop statements). Widen on backedge nodes, instead of nodes with a loop statement as terminator. This fixes #67834 and a precision loss from assignment in a loop condition. The commit contains tests for both of these issues. --- .../TypeErasedDataflowAnalysis.cpp| 29 ++- .../Analysis/FlowSensitive/TransferTest.cpp | 14 + .../TypeErasedDataflowAnalysisTest.cpp| 28 ++ 3 files changed, 51 insertions(+), 20 deletions(-) diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp index 6b167891c1a3ac8..5da3a5b1ccf8a2c 100644 --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -12,7 +12,6 @@ //===--===// #include -#include #include #include #include @@ -33,8 +32,8 @@ #include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h" #include "clang/Analysis/FlowSensitive/Value.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallBitVector.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Error.h" @@ -53,19 +52,8 @@ static int blockIndexInPredecessor(const CFGBlock , return BlockPos - Pred.succ_begin(); } -static bool isLoopHead(const CFGBlock ) { - if (const auto *T = B.getTerminatorStmt()) -switch (T->getStmtClass()) { - case Stmt::WhileStmtClass: - case Stmt::DoStmtClass: - case Stmt::ForStmtClass: - case Stmt::CXXForRangeStmtClass: -return true; - default: -return false; -} - - return false; +static bool isBackedgeNode(const CFGBlock ) { + return B.getLoopTarget() != nullptr; } namespace { @@ -502,14 +490,15 @@ runTypeErasedDataflowAnalysis( PostVisitCFG) { PrettyStackTraceAnalysis CrashInfo(CFCtx, "runTypeErasedDataflowAnalysis"); - PostOrderCFGView POV(()); - ForwardDataflowWorklist Worklist(CFCtx.getCFG(), ); + const clang::CFG = CFCtx.getCFG(); + PostOrderCFGView POV(); + ForwardDataflowWorklist Worklist(CFG, ); std::vector> BlockStates( - CFCtx.getCFG().size()); + CFG.size()); // The entry basic block doesn't contain statements so it can be skipped. - const CFGBlock = CFCtx.getCFG().getEntry(); + const CFGBlock = CFG.getEntry(); BlockStates[Entry.getBlockID()] = {Analysis.typeErasedInitialElement(), InitEnv.fork()}; Worklist.enqueueSuccessors(); @@ -553,7 +542,7 @@ runTypeErasedDataflowAnalysis( llvm::errs() << "Old Env:\n"; OldBlockState->Env.dump(); }); - if (isLoopHead(*Block)) { + if (isBackedgeNode(*Block)) { LatticeJoinEffect Effect1 = Analysis.widenTypeErased( NewBlockState.Lattice, OldBlockState->Lattice); LatticeJoinEffect Effect2 = diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 632632a1b30e78b..7c697fa5f87d941 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -4099,6 +4099,20 @@ TEST(TransferTest, LoopDereferencingChangingRecordPointerConverges) { ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); } +TEST(TransferTest, LoopWithDisjunctiveConditionConverges) { + std::string Code = R"cc( +bool foo(); + +void target() { + bool c = false; + while (foo() || foo()) { +c = true; + } +} + )cc"; + ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); +} + TEST(TransferTest, DoesNotCrashOnUnionThisExpr) { std::string Code = R"( union Union { diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp index 2425bb8711bdbaf..6800d736afd9b08 100644 --- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -913,6 +913,34 @@ TEST_F(FlowConditionTest, WhileStmt) { }); } +TEST_F(FlowConditionTest, WhileStmtWithAssignmentInCondition) { + std::string Code = R"( +void target(bool Foo) { + // This test checks whether the analysis preserves the connection between + // the value of `Foo` and the assignment expression, despite widening. + // The equality operator generates a fresh boolean variable on each +
[clang] [clang][dataflow] Check for backedges directly (instead of loop statements). (PR #68923)
@@ -502,14 +490,15 @@ runTypeErasedDataflowAnalysis( PostVisitCFG) { PrettyStackTraceAnalysis CrashInfo(CFCtx, "runTypeErasedDataflowAnalysis"); - PostOrderCFGView POV(()); - ForwardDataflowWorklist Worklist(CFCtx.getCFG(), ); + const clang::CFG = CFCtx.getCFG(); + PostOrderCFGView POV(); + ForwardDataflowWorklist Worklist(CFG, ); std::vector> BlockStates( - CFCtx.getCFG().size()); + CFG.size()); // The entry basic block doesn't contain statements so it can be skipped. - const CFGBlock = CFCtx.getCFG().getEntry(); + const CFGBlock = CFG.getEntry(); ymand wrote: it was originally part of this patch, but I ended up undoing some of the new changes. I considered separating this out, but I think for such small NFC changes you run the real risk that you simply won't follow up. That is, it's a great idea, but if we try to make this the norm, I think the result will be many lost small cleanup opportunities. Maybe that's worth it, for review clarity. I don't really know where to draw the line. https://github.com/llvm/llvm-project/pull/68923 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Check for backedges directly (instead of loop statements). (PR #68923)
@@ -913,6 +913,34 @@ TEST_F(FlowConditionTest, WhileStmt) { }); } +TEST_F(FlowConditionTest, WhileStmtWithAssignmentInCondition) { + std::string Code = R"( +void target(bool Foo) { + // This test checks whether the analysis preserves the connection between + // the value of `Foo` and the assignment expression, despite widening. + // The equality operator generates a fresh boolean variable on each + // interpretation, which forces use of widening. + while ((Foo = (3 == 4))) { +(void)0; +/*[[p]]*/ + } +} + )"; + runDataflow( + Code, + [](const llvm::StringMap> , + ASTContext ) { +const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); +ASSERT_THAT(FooDecl, NotNull()); + +ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); martinboehme wrote: Suggest deleting this assertion. `getEnvironmentAtAnnotation()` already asserts that an annotation "p" exists. (I know we assert this in a lot of existing tests, but it just seems like clutter.) https://github.com/llvm/llvm-project/pull/68923 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Check for backedges directly (instead of loop statements). (PR #68923)
@@ -913,6 +913,34 @@ TEST_F(FlowConditionTest, WhileStmt) { }); } +TEST_F(FlowConditionTest, WhileStmtWithAssignmentInCondition) { + std::string Code = R"( +void target(bool Foo) { + // This test checks whether the analysis preserves the connection between + // the value of `Foo` and the assignment expression, despite widening. + // The equality operator generates a fresh boolean variable on each + // interpretation, which forces use of widening. + while ((Foo = (3 == 4))) { +(void)0; +/*[[p]]*/ + } +} + )"; + runDataflow( + Code, + [](const llvm::StringMap> , + ASTContext ) { +const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); +ASSERT_THAT(FooDecl, NotNull()); martinboehme wrote: This assertion is unnecessary -- findValueDecl() already asserts internally that its return value is non-null. (But see also suggested edit below.) https://github.com/llvm/llvm-project/pull/68923 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Check for backedges directly (instead of loop statements). (PR #68923)
@@ -4099,6 +4099,20 @@ TEST(TransferTest, LoopDereferencingChangingRecordPointerConverges) { ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); } +TEST(TransferTest, LoopWithDisjunctiveConditionConverges) { martinboehme wrote: Test naming: I think the key aspect is not that the condition is a disjunction but that it's a short-circuited binary operator -- so maybe `LoopWithShortCircuitedConditionConverges`? https://github.com/llvm/llvm-project/pull/68923 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Check for backedges directly (instead of loop statements). (PR #68923)
@@ -53,19 +52,8 @@ static int blockIndexInPredecessor(const CFGBlock , return BlockPos - Pred.succ_begin(); } -static bool isLoopHead(const CFGBlock ) { - if (const auto *T = B.getTerminatorStmt()) -switch (T->getStmtClass()) { - case Stmt::WhileStmtClass: - case Stmt::DoStmtClass: - case Stmt::ForStmtClass: - case Stmt::CXXForRangeStmtClass: -return true; - default: -return false; -} - - return false; +static bool isBackedgeNode(const CFGBlock ) { martinboehme wrote: Can you add a short comment explaining what a "backedge node" is? (I think the term "backedge node" isn't otherwise defined in Clang or the framework -- or if it is, it would be useful to add a link.) https://github.com/llvm/llvm-project/pull/68923 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Check for backedges directly (instead of loop statements). (PR #68923)
@@ -913,6 +913,34 @@ TEST_F(FlowConditionTest, WhileStmt) { }); } +TEST_F(FlowConditionTest, WhileStmtWithAssignmentInCondition) { + std::string Code = R"( +void target(bool Foo) { + // This test checks whether the analysis preserves the connection between + // the value of `Foo` and the assignment expression, despite widening. + // The equality operator generates a fresh boolean variable on each + // interpretation, which forces use of widening. + while ((Foo = (3 == 4))) { +(void)0; +/*[[p]]*/ + } +} + )"; + runDataflow( + Code, + [](const llvm::StringMap> , + ASTContext ) { +const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); +ASSERT_THAT(FooDecl, NotNull()); + +ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); +const Environment = getEnvironmentAtAnnotation(Results, "p"); + +auto = cast(Env.getValue(*FooDecl))->formula(); martinboehme wrote: ```suggestion const Environment = getEnvironmentAtAnnotation(Results, "p"); auto = getValueForDecl(ASTCtx, Env, "Foo"); ``` You may need to include "TestingSupport.h". https://github.com/llvm/llvm-project/pull/68923 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Check for backedges directly (instead of loop statements). (PR #68923)
@@ -502,14 +490,15 @@ runTypeErasedDataflowAnalysis( PostVisitCFG) { PrettyStackTraceAnalysis CrashInfo(CFCtx, "runTypeErasedDataflowAnalysis"); - PostOrderCFGView POV(()); - ForwardDataflowWorklist Worklist(CFCtx.getCFG(), ); + const clang::CFG = CFCtx.getCFG(); + PostOrderCFGView POV(); + ForwardDataflowWorklist Worklist(CFG, ); std::vector> BlockStates( - CFCtx.getCFG().size()); + CFG.size()); // The entry basic block doesn't contain statements so it can be skipped. - const CFGBlock = CFCtx.getCFG().getEntry(); + const CFGBlock = CFG.getEntry(); martinboehme wrote: Nit: This refactoring is entirely independent of the rest of this PR. Suggest submitting changes like this as a separate "NFC" PR to minimize the size of PRs and ease review. https://github.com/llvm/llvm-project/pull/68923 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Check for backedges directly (instead of loop statements). (PR #68923)
https://github.com/martinboehme edited https://github.com/llvm/llvm-project/pull/68923 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Check for backedges directly (instead of loop statements). (PR #68923)
https://github.com/martinboehme approved this pull request. LGTM with comments https://github.com/llvm/llvm-project/pull/68923 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Check for backedges directly (instead of loop statements). (PR #68923)
ymand wrote: > Nice fix! So, it looks like our definition of "loop head" was wrong. Indeed. We didn't think of the way control-flow constructs *inside* the condition expression would be represented. Ironically (?), this is actually simpler and fixes another issue besides, which is nice. ;) https://github.com/llvm/llvm-project/pull/68923 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Check for backedges directly (instead of loop statements). (PR #68923)
https://github.com/ymand updated https://github.com/llvm/llvm-project/pull/68923 >From 83486a35e6d0e754dd99369fc546d04afedbe923 Mon Sep 17 00:00:00 2001 From: Yitzhak Mandelbaum Date: Thu, 12 Oct 2023 19:35:54 + Subject: [PATCH 1/2] [clang][dataflow] Check for backedges directly (instead of loop statements). Widen on backedge nodes, instead of nodes with a loop statement as terminator. This fixes #67834 and a precision loss from assignment in a loop condition. The commit contains tests for both of these issues. --- .../TypeErasedDataflowAnalysis.cpp| 29 ++- .../Analysis/FlowSensitive/TransferTest.cpp | 14 + .../TypeErasedDataflowAnalysisTest.cpp| 28 ++ 3 files changed, 51 insertions(+), 20 deletions(-) diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp index 6b167891c1a3ac8..5da3a5b1ccf8a2c 100644 --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -12,7 +12,6 @@ //===--===// #include -#include #include #include #include @@ -33,8 +32,8 @@ #include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h" #include "clang/Analysis/FlowSensitive/Value.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallBitVector.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Error.h" @@ -53,19 +52,8 @@ static int blockIndexInPredecessor(const CFGBlock , return BlockPos - Pred.succ_begin(); } -static bool isLoopHead(const CFGBlock ) { - if (const auto *T = B.getTerminatorStmt()) -switch (T->getStmtClass()) { - case Stmt::WhileStmtClass: - case Stmt::DoStmtClass: - case Stmt::ForStmtClass: - case Stmt::CXXForRangeStmtClass: -return true; - default: -return false; -} - - return false; +static bool isBackedgeNode(const CFGBlock ) { + return B.getLoopTarget() != nullptr; } namespace { @@ -502,14 +490,15 @@ runTypeErasedDataflowAnalysis( PostVisitCFG) { PrettyStackTraceAnalysis CrashInfo(CFCtx, "runTypeErasedDataflowAnalysis"); - PostOrderCFGView POV(()); - ForwardDataflowWorklist Worklist(CFCtx.getCFG(), ); + const clang::CFG = CFCtx.getCFG(); + PostOrderCFGView POV(); + ForwardDataflowWorklist Worklist(CFG, ); std::vector> BlockStates( - CFCtx.getCFG().size()); + CFG.size()); // The entry basic block doesn't contain statements so it can be skipped. - const CFGBlock = CFCtx.getCFG().getEntry(); + const CFGBlock = CFG.getEntry(); BlockStates[Entry.getBlockID()] = {Analysis.typeErasedInitialElement(), InitEnv.fork()}; Worklist.enqueueSuccessors(); @@ -553,7 +542,7 @@ runTypeErasedDataflowAnalysis( llvm::errs() << "Old Env:\n"; OldBlockState->Env.dump(); }); - if (isLoopHead(*Block)) { + if (isBackedgeNode(*Block)) { LatticeJoinEffect Effect1 = Analysis.widenTypeErased( NewBlockState.Lattice, OldBlockState->Lattice); LatticeJoinEffect Effect2 = diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 632632a1b30e78b..7c697fa5f87d941 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -4099,6 +4099,20 @@ TEST(TransferTest, LoopDereferencingChangingRecordPointerConverges) { ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); } +TEST(TransferTest, LoopWithDisjunctiveConditionConverges) { + std::string Code = R"cc( +bool foo(); + +void target() { + bool c = false; + while (foo() || foo()) { +c = true; + } +} + )cc"; + ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); +} + TEST(TransferTest, DoesNotCrashOnUnionThisExpr) { std::string Code = R"( union Union { diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp index 2425bb8711bdbaf..6800d736afd9b08 100644 --- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -913,6 +913,34 @@ TEST_F(FlowConditionTest, WhileStmt) { }); } +TEST_F(FlowConditionTest, WhileStmtWithAssignmentInCondition) { + std::string Code = R"( +void target(bool Foo) { + // This test checks whether the analysis preserves the connection between + // the value of `Foo` and the assignment expression, despite widening. + // The equality operator generates a fresh boolean variable on each +
[clang] [clang][dataflow] Check for backedges directly (instead of loop statements). (PR #68923)
https://github.com/Xazax-hun approved this pull request. Nice fix! So, it looks like our definition of "loop head" was wrong. https://github.com/llvm/llvm-project/pull/68923 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Check for backedges directly (instead of loop statements). (PR #68923)
github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning: You can test this locally with the following command: ``bash git-clang-format --diff 50ece4cba949787241b5fbfc94be6cfdc66e90ee da8cacb47b8f80f7ecb1e86f98683be6c54b4e57 -- clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp `` View the diff from clang-format here. ``diff diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp index c635edd12219..d96ad66dd674 100644 --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -53,7 +53,7 @@ static int blockIndexInPredecessor(const CFGBlock , } static bool isBackedgeNode(const CFGBlock ) { - return B.getLoopTarget() != nullptr; + return B.getLoopTarget() != nullptr; } namespace { @@ -494,7 +494,6 @@ runTypeErasedDataflowAnalysis( PostOrderCFGView POV(); ForwardDataflowWorklist Worklist(CFG, ); - std::vector> BlockStates( CFG.size()); `` https://github.com/llvm/llvm-project/pull/68923 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Check for backedges directly (instead of loop statements). (PR #68923)
https://github.com/ymand updated https://github.com/llvm/llvm-project/pull/68923 >From 83486a35e6d0e754dd99369fc546d04afedbe923 Mon Sep 17 00:00:00 2001 From: Yitzhak Mandelbaum Date: Thu, 12 Oct 2023 19:35:54 + Subject: [PATCH] [clang][dataflow] Check for backedges directly (instead of loop statements). Widen on backedge nodes, instead of nodes with a loop statement as terminator. This fixes #67834 and a precision loss from assignment in a loop condition. The commit contains tests for both of these issues. --- .../TypeErasedDataflowAnalysis.cpp| 29 ++- .../Analysis/FlowSensitive/TransferTest.cpp | 14 + .../TypeErasedDataflowAnalysisTest.cpp| 28 ++ 3 files changed, 51 insertions(+), 20 deletions(-) diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp index 6b167891c1a3ac8..5da3a5b1ccf8a2c 100644 --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -12,7 +12,6 @@ //===--===// #include -#include #include #include #include @@ -33,8 +32,8 @@ #include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h" #include "clang/Analysis/FlowSensitive/Value.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallBitVector.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Error.h" @@ -53,19 +52,8 @@ static int blockIndexInPredecessor(const CFGBlock , return BlockPos - Pred.succ_begin(); } -static bool isLoopHead(const CFGBlock ) { - if (const auto *T = B.getTerminatorStmt()) -switch (T->getStmtClass()) { - case Stmt::WhileStmtClass: - case Stmt::DoStmtClass: - case Stmt::ForStmtClass: - case Stmt::CXXForRangeStmtClass: -return true; - default: -return false; -} - - return false; +static bool isBackedgeNode(const CFGBlock ) { + return B.getLoopTarget() != nullptr; } namespace { @@ -502,14 +490,15 @@ runTypeErasedDataflowAnalysis( PostVisitCFG) { PrettyStackTraceAnalysis CrashInfo(CFCtx, "runTypeErasedDataflowAnalysis"); - PostOrderCFGView POV(()); - ForwardDataflowWorklist Worklist(CFCtx.getCFG(), ); + const clang::CFG = CFCtx.getCFG(); + PostOrderCFGView POV(); + ForwardDataflowWorklist Worklist(CFG, ); std::vector> BlockStates( - CFCtx.getCFG().size()); + CFG.size()); // The entry basic block doesn't contain statements so it can be skipped. - const CFGBlock = CFCtx.getCFG().getEntry(); + const CFGBlock = CFG.getEntry(); BlockStates[Entry.getBlockID()] = {Analysis.typeErasedInitialElement(), InitEnv.fork()}; Worklist.enqueueSuccessors(); @@ -553,7 +542,7 @@ runTypeErasedDataflowAnalysis( llvm::errs() << "Old Env:\n"; OldBlockState->Env.dump(); }); - if (isLoopHead(*Block)) { + if (isBackedgeNode(*Block)) { LatticeJoinEffect Effect1 = Analysis.widenTypeErased( NewBlockState.Lattice, OldBlockState->Lattice); LatticeJoinEffect Effect2 = diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 632632a1b30e78b..7c697fa5f87d941 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -4099,6 +4099,20 @@ TEST(TransferTest, LoopDereferencingChangingRecordPointerConverges) { ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); } +TEST(TransferTest, LoopWithDisjunctiveConditionConverges) { + std::string Code = R"cc( +bool foo(); + +void target() { + bool c = false; + while (foo() || foo()) { +c = true; + } +} + )cc"; + ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); +} + TEST(TransferTest, DoesNotCrashOnUnionThisExpr) { std::string Code = R"( union Union { diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp index 2425bb8711bdbaf..6800d736afd9b08 100644 --- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -913,6 +913,34 @@ TEST_F(FlowConditionTest, WhileStmt) { }); } +TEST_F(FlowConditionTest, WhileStmtWithAssignmentInCondition) { + std::string Code = R"( +void target(bool Foo) { + // This test checks whether the analysis preserves the connection between + // the value of `Foo` and the assignment expression, despite widening. + // The equality operator generates a fresh boolean variable on each +
[clang] [clang][dataflow] Check for backedges directly (instead of loop statements). (PR #68923)
llvmbot wrote: @llvm/pr-subscribers-clang Author: Yitzhak Mandelbaum (ymand) Changes Widen on backedge nodes, instead of nodes with a loop statement as terminator. This fixes #67834 and a precision loss from assignment in a loop condition. The commit contains tests for both of these issues. --- Full diff: https://github.com/llvm/llvm-project/pull/68923.diff 3 Files Affected: - (modified) clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp (+10-20) - (modified) clang/unittests/Analysis/FlowSensitive/TransferTest.cpp (+14) - (modified) clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp (+28) ``diff diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp index 6b167891c1a3ac8..c635edd12219f0e 100644 --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -12,7 +12,6 @@ //===--===// #include -#include #include #include #include @@ -33,8 +32,8 @@ #include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h" #include "clang/Analysis/FlowSensitive/Value.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallBitVector.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Error.h" @@ -53,19 +52,8 @@ static int blockIndexInPredecessor(const CFGBlock , return BlockPos - Pred.succ_begin(); } -static bool isLoopHead(const CFGBlock ) { - if (const auto *T = B.getTerminatorStmt()) -switch (T->getStmtClass()) { - case Stmt::WhileStmtClass: - case Stmt::DoStmtClass: - case Stmt::ForStmtClass: - case Stmt::CXXForRangeStmtClass: -return true; - default: -return false; -} - - return false; +static bool isBackedgeNode(const CFGBlock ) { + return B.getLoopTarget() != nullptr; } namespace { @@ -502,14 +490,16 @@ runTypeErasedDataflowAnalysis( PostVisitCFG) { PrettyStackTraceAnalysis CrashInfo(CFCtx, "runTypeErasedDataflowAnalysis"); - PostOrderCFGView POV(()); - ForwardDataflowWorklist Worklist(CFCtx.getCFG(), ); + const clang::CFG = CFCtx.getCFG(); + PostOrderCFGView POV(); + ForwardDataflowWorklist Worklist(CFG, ); + std::vector> BlockStates( - CFCtx.getCFG().size()); + CFG.size()); // The entry basic block doesn't contain statements so it can be skipped. - const CFGBlock = CFCtx.getCFG().getEntry(); + const CFGBlock = CFG.getEntry(); BlockStates[Entry.getBlockID()] = {Analysis.typeErasedInitialElement(), InitEnv.fork()}; Worklist.enqueueSuccessors(); @@ -553,7 +543,7 @@ runTypeErasedDataflowAnalysis( llvm::errs() << "Old Env:\n"; OldBlockState->Env.dump(); }); - if (isLoopHead(*Block)) { + if (isBackedgeNode(*Block)) { LatticeJoinEffect Effect1 = Analysis.widenTypeErased( NewBlockState.Lattice, OldBlockState->Lattice); LatticeJoinEffect Effect2 = diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 632632a1b30e78b..7c697fa5f87d941 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -4099,6 +4099,20 @@ TEST(TransferTest, LoopDereferencingChangingRecordPointerConverges) { ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); } +TEST(TransferTest, LoopWithDisjunctiveConditionConverges) { + std::string Code = R"cc( +bool foo(); + +void target() { + bool c = false; + while (foo() || foo()) { +c = true; + } +} + )cc"; + ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); +} + TEST(TransferTest, DoesNotCrashOnUnionThisExpr) { std::string Code = R"( union Union { diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp index 2425bb8711bdbaf..6800d736afd9b08 100644 --- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -913,6 +913,34 @@ TEST_F(FlowConditionTest, WhileStmt) { }); } +TEST_F(FlowConditionTest, WhileStmtWithAssignmentInCondition) { + std::string Code = R"( +void target(bool Foo) { + // This test checks whether the analysis preserves the connection between + // the value of `Foo` and the assignment expression, despite widening. + // The equality operator generates a fresh boolean variable on each + // interpretation, which forces use of widening. + while ((Foo = (3 == 4))) { +(void)0; +
[clang] [clang][dataflow] Check for backedges directly (instead of loop statements). (PR #68923)
https://github.com/ymand created https://github.com/llvm/llvm-project/pull/68923 Widen on backedge nodes, instead of nodes with a loop statement as terminator. This fixes #67834 and a precision loss from assignment in a loop condition. The commit contains tests for both of these issues. >From da8cacb47b8f80f7ecb1e86f98683be6c54b4e57 Mon Sep 17 00:00:00 2001 From: Yitzhak Mandelbaum Date: Thu, 12 Oct 2023 19:35:54 + Subject: [PATCH] [clang][dataflow] Check for backedges directly (instead of loop statements). Widen on backedge nodes, instead of nodes with a loop statement as terminator. This fixes #67834 and a precision loss from assignment in a loop condition. The commit contains tests for both of these issues. --- .../TypeErasedDataflowAnalysis.cpp| 30 +++ .../Analysis/FlowSensitive/TransferTest.cpp | 14 + .../TypeErasedDataflowAnalysisTest.cpp| 28 + 3 files changed, 52 insertions(+), 20 deletions(-) diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp index 6b167891c1a3ac8..c635edd12219f0e 100644 --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -12,7 +12,6 @@ //===--===// #include -#include #include #include #include @@ -33,8 +32,8 @@ #include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h" #include "clang/Analysis/FlowSensitive/Value.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallBitVector.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Error.h" @@ -53,19 +52,8 @@ static int blockIndexInPredecessor(const CFGBlock , return BlockPos - Pred.succ_begin(); } -static bool isLoopHead(const CFGBlock ) { - if (const auto *T = B.getTerminatorStmt()) -switch (T->getStmtClass()) { - case Stmt::WhileStmtClass: - case Stmt::DoStmtClass: - case Stmt::ForStmtClass: - case Stmt::CXXForRangeStmtClass: -return true; - default: -return false; -} - - return false; +static bool isBackedgeNode(const CFGBlock ) { + return B.getLoopTarget() != nullptr; } namespace { @@ -502,14 +490,16 @@ runTypeErasedDataflowAnalysis( PostVisitCFG) { PrettyStackTraceAnalysis CrashInfo(CFCtx, "runTypeErasedDataflowAnalysis"); - PostOrderCFGView POV(()); - ForwardDataflowWorklist Worklist(CFCtx.getCFG(), ); + const clang::CFG = CFCtx.getCFG(); + PostOrderCFGView POV(); + ForwardDataflowWorklist Worklist(CFG, ); + std::vector> BlockStates( - CFCtx.getCFG().size()); + CFG.size()); // The entry basic block doesn't contain statements so it can be skipped. - const CFGBlock = CFCtx.getCFG().getEntry(); + const CFGBlock = CFG.getEntry(); BlockStates[Entry.getBlockID()] = {Analysis.typeErasedInitialElement(), InitEnv.fork()}; Worklist.enqueueSuccessors(); @@ -553,7 +543,7 @@ runTypeErasedDataflowAnalysis( llvm::errs() << "Old Env:\n"; OldBlockState->Env.dump(); }); - if (isLoopHead(*Block)) { + if (isBackedgeNode(*Block)) { LatticeJoinEffect Effect1 = Analysis.widenTypeErased( NewBlockState.Lattice, OldBlockState->Lattice); LatticeJoinEffect Effect2 = diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 632632a1b30e78b..7c697fa5f87d941 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -4099,6 +4099,20 @@ TEST(TransferTest, LoopDereferencingChangingRecordPointerConverges) { ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); } +TEST(TransferTest, LoopWithDisjunctiveConditionConverges) { + std::string Code = R"cc( +bool foo(); + +void target() { + bool c = false; + while (foo() || foo()) { +c = true; + } +} + )cc"; + ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); +} + TEST(TransferTest, DoesNotCrashOnUnionThisExpr) { std::string Code = R"( union Union { diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp index 2425bb8711bdbaf..6800d736afd9b08 100644 --- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -913,6 +913,34 @@ TEST_F(FlowConditionTest, WhileStmt) { }); } +TEST_F(FlowConditionTest, WhileStmtWithAssignmentInCondition) { + std::string Code = R"( +void target(bool Foo) { + // This test checks