ymandel created this revision. ymandel added reviewers: xazax.hun, samestep, sgatev, gribozavr. Herald added subscribers: martong, tschuett, rnkovacs. Herald added a reviewer: NoQ. Herald added a project: All. ymandel requested review of this revision. Herald added a project: clang.
This patch modifies context-sensitive analysis of functions to use a cache, rather than recreate the `ControlFlowContext` from a function decl on each encounter. However, this is just step 1 (of N) in adding support for a configurable map of "modeled" function decls. The map will go from the actual function decl to the `ControlFlowContext` used to model it. Only functions pre-configured in the map will be modeled in a context-sensitive way. We start with a cache because it introduces the desired map, while retaining the current behavior. Here, functions are mapped to their actual implementations (when available). Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D131039 Files: clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp
Index: clang/lib/Analysis/FlowSensitive/Transfer.cpp =================================================================== --- clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -507,28 +507,27 @@ return; Env.setStorageLocation(*S, *ArgLoc); } else if (const FunctionDecl *F = S->getDirectCallee()) { - // This case is for context-sensitive analysis, which we only do if we - // have the callee body available in the translation unit. - if (!Options.ContextSensitive || F->getBody() == nullptr) + // This case is for context-sensitive analysis. + if (!Options.ContextSensitive) + return; + + const ControlFlowContext *CFCtx = Env.getControlFlowContext(F); + if (!CFCtx) return; // FIXME: We don't support context-sensitive analysis of recursion, so // we should return early here if `F` is the same as the `FunctionDecl` // holding `S` itself. - auto &ASTCtx = F->getASTContext(); - - // FIXME: Cache these CFGs. - auto CFCtx = ControlFlowContext::build(F, F->getBody(), &ASTCtx); - // FIXME: Handle errors here and below. - assert(CFCtx); auto ExitBlock = CFCtx->getCFG().getExit().getBlockID(); auto CalleeEnv = Env.pushCall(S); - // FIXME: Use the same analysis as the caller for the callee. - DataflowAnalysisOptions Options; - auto Analysis = NoopAnalysis(ASTCtx, Options); + // FIXME: Use the same analysis as the caller for the callee. Note, + // though, that doing so would require support for changing the analysis's + // ASTContext. + auto Analysis = NoopAnalysis(CFCtx->getDecl().getASTContext(), + DataflowAnalysisOptions()); auto BlockToOutputState = dataflow::runDataflowAnalysis(*CFCtx, Analysis, CalleeEnv); Index: clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp =================================================================== --- clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp +++ clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp @@ -16,6 +16,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/Analysis/FlowSensitive/DebugSupport.h" #include "clang/Analysis/FlowSensitive/Value.h" +#include "clang/Basic/IdentifierTable.h" #include "llvm/Support/Debug.h" #include <cassert> #include <memory> @@ -335,6 +336,30 @@ llvm::dbgs() << debugString(Constraints, AtomNames); } +const ControlFlowContext * +DataflowAnalysisContext::getControlFlowContext(const FunctionDecl *F) { + // FIXME: This is an expensive approach since we *always* print the fully + // qualified name. Instead, we should prefilter by some means (e.g. checking + // the identifier against a set). + std::string QualName; + llvm::raw_string_ostream OS(QualName); + F->printQualifiedName(OS); + auto It = FunctionModels.find(QualName); + if (It != FunctionModels.end()) + return &It->second; + + if (F->getBody() != nullptr) { + auto CFCtx = + ControlFlowContext::build(F, F->getBody(), &F->getASTContext()); + // FIXME: Handle errors. + assert(CFCtx); + auto Result = FunctionModels.insert({QualName, std::move(*CFCtx)}); + return &Result.first->second; + } + + return nullptr; +} + } // namespace dataflow } // namespace clang Index: clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp =================================================================== --- clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp +++ clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp @@ -64,7 +64,7 @@ llvm::DenseMap<const Stmt *, const CFGBlock *> StmtToBlock = buildStmtToBasicBlockMap(*Cfg); - return ControlFlowContext(std::move(Cfg), std::move(StmtToBlock)); + return ControlFlowContext(D, std::move(Cfg), std::move(StmtToBlock)); } } // namespace dataflow Index: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h =================================================================== --- clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -19,6 +19,7 @@ #include "clang/AST/DeclBase.h" #include "clang/AST/Expr.h" #include "clang/AST/Type.h" +#include "clang/Analysis/FlowSensitive/ControlFlowContext.h" #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" #include "clang/Analysis/FlowSensitive/DataflowLattice.h" #include "clang/Analysis/FlowSensitive/StorageLocation.h" @@ -343,6 +344,12 @@ /// imply that `Val` is true. bool flowConditionImplies(BoolValue &Val) const; + /// Returns the `ControlFlowContext` registered for `F`, if any. Otherwise, + /// returns null. + const ControlFlowContext *getControlFlowContext(const FunctionDecl *F) { + return DACtx->getControlFlowContext(F); + } + LLVM_DUMP_METHOD void dump() const; private: Index: clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h =================================================================== --- clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h +++ clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h @@ -18,6 +18,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" #include "clang/AST/TypeOrdering.h" +#include "clang/Analysis/FlowSensitive/ControlFlowContext.h" #include "clang/Analysis/FlowSensitive/Solver.h" #include "clang/Analysis/FlowSensitive/StorageLocation.h" #include "clang/Analysis/FlowSensitive/Value.h" @@ -254,6 +255,10 @@ LLVM_DUMP_METHOD void dumpFlowCondition(AtomicBoolValue &Token); + /// Returns the `ControlFlowContext` registered for `F`, if any. Otherwise, + /// returns null. + const ControlFlowContext *getControlFlowContext(const FunctionDecl *F); + private: struct NullableQualTypeDenseMapInfo : private llvm::DenseMapInfo<QualType> { static QualType getEmptyKey() { @@ -360,6 +365,9 @@ llvm::DenseMap<AtomicBoolValue *, llvm::DenseSet<AtomicBoolValue *>> FlowConditionDeps; llvm::DenseMap<AtomicBoolValue *, BoolValue *> FlowConditionConstraints; + + // Keyed on the function's fully qualified name. No leading "::". + llvm::StringMap<ControlFlowContext> FunctionModels; }; } // namespace dataflow Index: clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h =================================================================== --- clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h +++ clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h @@ -20,7 +20,6 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Stmt.h" -#include "clang/Analysis/CFG.h" #include "clang/Analysis/FlowSensitive/ControlFlowContext.h" #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" #include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h" Index: clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h =================================================================== --- clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h +++ clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h @@ -30,10 +30,14 @@ /// analysis. class ControlFlowContext { public: - /// Builds a ControlFlowContext from an AST node. + /// Builds a ControlFlowContext from an AST node. `D` is the function in which + /// `S` resides. All arguments must be non-null. static llvm::Expected<ControlFlowContext> build(const Decl *D, Stmt *S, ASTContext *C); + /// Returns the `Decl` containing the statement used to construct the CFG. + const Decl &getDecl() const { return *ContainingDecl; } + /// Returns the CFG that is stored in this context. const CFG &getCFG() const { return *Cfg; } @@ -43,10 +47,17 @@ } private: - ControlFlowContext(std::unique_ptr<CFG> Cfg, + // `D` must not be null. + ControlFlowContext(const Decl *D, std::unique_ptr<CFG> Cfg, llvm::DenseMap<const Stmt *, const CFGBlock *> StmtToBlock) - : Cfg(std::move(Cfg)), StmtToBlock(std::move(StmtToBlock)) {} + : ContainingDecl(D), Cfg(std::move(Cfg)), + StmtToBlock(std::move(StmtToBlock)) { + assert(D != nullptr); + assert(Cfg != nullptr); + } + /// The `Decl` containing the statement used to construct the CFG. + const Decl *ContainingDecl; std::unique_ptr<CFG> Cfg; llvm::DenseMap<const Stmt *, const CFGBlock *> StmtToBlock; };
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits