-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang][dataflow] Check for backedges directly (instead of loop statements). #68923
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,7 +12,6 @@ | |
//===----------------------------------------------------------------------===// | ||
|
||
#include <algorithm> | ||
#include <memory> | ||
#include <optional> | ||
#include <system_error> | ||
#include <utility> | ||
|
@@ -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,14 @@ static int blockIndexInPredecessor(const CFGBlock &Pred, | |
return BlockPos - Pred.succ_begin(); | ||
} | ||
|
||
static bool isLoopHead(const CFGBlock &B) { | ||
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; | ||
// A "backedge" node is a block introduced in the CFG exclusively to indicate a | ||
// loop backedge. They are exactly identified by the presence of a non-null | ||
// pointer to the entry block of the loop condition. Note that this is not | ||
// necessarily the block with the loop statement as terminator, because | ||
// short-circuit operators will result in multiple blocks encoding the loop | ||
// condition, only one of which will contain the loop statement as terminator. | ||
static bool isBackedgeNode(const CFGBlock &B) { | ||
return B.getLoopTarget() != nullptr; | ||
} | ||
|
||
namespace { | ||
|
@@ -502,14 +496,15 @@ runTypeErasedDataflowAnalysis( | |
PostVisitCFG) { | ||
PrettyStackTraceAnalysis CrashInfo(CFCtx, "runTypeErasedDataflowAnalysis"); | ||
|
||
PostOrderCFGView POV(&CFCtx.getCFG()); | ||
ForwardDataflowWorklist Worklist(CFCtx.getCFG(), &POV); | ||
const clang::CFG &CFG = CFCtx.getCFG(); | ||
PostOrderCFGView POV(&CFG); | ||
ForwardDataflowWorklist Worklist(CFG, &POV); | ||
|
||
std::vector<std::optional<TypeErasedDataflowAnalysisState>> BlockStates( | ||
CFCtx.getCFG().size()); | ||
CFG.size()); | ||
|
||
// The entry basic block doesn't contain statements so it can be skipped. | ||
const CFGBlock &Entry = CFCtx.getCFG().getEntry(); | ||
const CFGBlock &Entry = CFG.getEntry(); | ||
Comment on lines
-505
to
+507
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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. |
||
BlockStates[Entry.getBlockID()] = {Analysis.typeErasedInitialElement(), | ||
InitEnv.fork()}; | ||
Worklist.enqueueSuccessors(&Entry); | ||
|
@@ -553,7 +548,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 = | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
llvm-project/clang/include/clang/Analysis/CFG.h
Line 805 in eb14f47
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
.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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?