diff options
author | Artem Dergachev <artem.dergachev@gmail.com> | 2019-04-30 03:01:02 +0000 |
---|---|---|
committer | Artem Dergachev <artem.dergachev@gmail.com> | 2019-04-30 03:01:02 +0000 |
commit | ab7747b727d79c9cc67b0ffb75528bf9bb67d9e8 (patch) | |
tree | f4ed5911b20fd7c3744ceb50de080ec81aebf951 /clang/lib/Analysis/CFG.cpp | |
parent | eb71c0c961d4e0f9138164eb5c7ab22758385fdc (diff) | |
download | bcm5719-llvm-ab7747b727d79c9cc67b0ffb75528bf9bb67d9e8.tar.gz bcm5719-llvm-ab7747b727d79c9cc67b0ffb75528bf9bb67d9e8.zip |
[analyzer] Treat functions without run-time branches as "small".
Currently we always inline functions that have no branches, i.e. have exactly
three CFG blocks: ENTRY, some code, EXIT. This makes sense because when there
are no branches, it means that there's no exponential complexity introduced
by inlining such function. Such functions also don't trigger various fundamental
problems with our inlining mechanism, such as the problem of inlined
defensive checks.
Sometimes the CFG may contain more blocks, but in practice it still has
linear structure because all directions (except, at most, one) of all branches
turned out to be unreachable. When this happens, still treat the function
as "small". This is useful, in particular, for dealing with C++17 if constexpr.
Differential Revision: https://reviews.llvm.org/D61051
llvm-svn: 359531
Diffstat (limited to 'clang/lib/Analysis/CFG.cpp')
-rw-r--r-- | clang/lib/Analysis/CFG.cpp | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index 6ff72540afe..fdd845e9802 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -4677,6 +4677,51 @@ std::unique_ptr<CFG> CFG::buildCFG(const Decl *D, Stmt *Statement, return Builder.buildCFG(D, Statement); } +bool CFG::isLinear() const { + // Quick path: if we only have the ENTRY block, the EXIT block, and some code + // in between, then we have no room for control flow. + if (size() <= 3) + return true; + + // Traverse the CFG until we find a branch. + // TODO: While this should still be very fast, + // maybe we should cache the answer. + llvm::SmallPtrSet<const CFGBlock *, 4> Visited; + const CFGBlock *B = Entry; + while (B != Exit) { + auto IteratorAndFlag = Visited.insert(B); + if (!IteratorAndFlag.second) { + // We looped back to a block that we've already visited. Not linear. + return false; + } + + // Iterate over reachable successors. + const CFGBlock *FirstReachableB = nullptr; + for (const CFGBlock::AdjacentBlock &AB : B->succs()) { + if (!AB.isReachable()) + continue; + + if (FirstReachableB == nullptr) { + FirstReachableB = &*AB; + } else { + // We've encountered a branch. It's not a linear CFG. + return false; + } + } + + if (!FirstReachableB) { + // We reached a dead end. EXIT is unreachable. This is linear enough. + return true; + } + + // There's only one way to move forward. Proceed. + B = FirstReachableB; + } + + // We reached EXIT and found no branches. + return true; +} + const CXXDestructorDecl * CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const { switch (getKind()) { |