From: Anna Zaks Date: Fri, 2 Mar 2012 19:05:03 +0000 (+0000) Subject: [analyzer] Bound the size of the functions being inlined + provide X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8235f9c9c8b3d1737d1c6bd57f7ba3f616b92392;p=clang [analyzer] Bound the size of the functions being inlined + provide command line options for inlining tuning. This adds the option for stack depth bound as well as function size bound. + minor doxygenification git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151930 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index 9d44280874..e7a0ad38f9 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -81,7 +81,11 @@ def analyzer_viz_egraph_graphviz : Flag<"-analyzer-viz-egraph-graphviz">, def analyzer_viz_egraph_ubigraph : Flag<"-analyzer-viz-egraph-ubigraph">, HelpText<"Display exploded graph using Ubigraph">; def analyzer_inline_call : Flag<"-analyzer-inline-call">, - HelpText<"Experimental transfer function inlining callees when its definition is available.">; + HelpText<"Experimental: Inline callees when their definitions are available">; +def analyzer_inline_max_stack_depth : Separate<"-analyzer-inline-max-stack-depth">, + HelpText<"Bound on stack depth while inlining (4 by default)">; +def analyzer_inline_max_function_size : Separate<"-analyzer-inline-max-function-size">, + HelpText<"Bound on the number of basic blocks in an inlined function (10 by default)">; def analyzer_max_nodes : Separate<"-analyzer-max-nodes">, HelpText<"The maximum number of nodes the analyzer can generate (150000 default, 0 = no limit)">; def analyzer_max_loop : Separate<"-analyzer-max-loop">, diff --git a/include/clang/Frontend/AnalyzerOptions.h b/include/clang/Frontend/AnalyzerOptions.h index 8a1f4f0227..a39dc25c04 100644 --- a/include/clang/Frontend/AnalyzerOptions.h +++ b/include/clang/Frontend/AnalyzerOptions.h @@ -85,6 +85,8 @@ public: unsigned CFGAddInitializers : 1; unsigned EagerlyTrimEGraph : 1; unsigned PrintStats : 1; + unsigned InlineMaxStackDepth; + unsigned InlineMaxFunctionSize; public: AnalyzerOptions() { @@ -106,6 +108,9 @@ public: CFGAddInitializers = 0; EagerlyTrimEGraph = 0; PrintStats = 0; + // Cap the stack depth at 4 calls (5 stack frames, base + 4 calls). + InlineMaxStackDepth = 5; + InlineMaxFunctionSize = 10; } }; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h index 3a9a1254ba..39020c1cbb 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h @@ -53,28 +53,39 @@ class AnalysisManager : public BugReporterData { enum AnalysisScope { ScopeTU, ScopeDecl } AScope; - // The maximum number of exploded nodes the analyzer will generate. + /// \brief The maximum number of exploded nodes the analyzer will generate. unsigned MaxNodes; - // The maximum number of times the analyzer visit a block. + /// \brief The maximum number of times the analyzer visits a block. unsigned MaxVisit; bool VisualizeEGDot; bool VisualizeEGUbi; AnalysisPurgeMode PurgeDead; - /// EargerlyAssume - A flag indicating how the engine should handle - // expressions such as: 'x = (y != 0)'. When this flag is true then - // the subexpression 'y != 0' will be eagerly assumed to be true or false, - // thus evaluating it to the integers 0 or 1 respectively. The upside - // is that this can increase analysis precision until we have a better way - // to lazily evaluate such logic. The downside is that it eagerly - // bifurcates paths. + /// \brief The flag regulates if we should eagerly assume evaluations of + /// conditionals, thus, bifurcating the path. + /// + /// EagerlyAssume - A flag indicating how the engine should handle + /// expressions such as: 'x = (y != 0)'. When this flag is true then + /// the subexpression 'y != 0' will be eagerly assumed to be true or false, + /// thus evaluating it to the integers 0 or 1 respectively. The upside + /// is that this can increase analysis precision until we have a better way + /// to lazily evaluate such logic. The downside is that it eagerly + /// bifurcates paths. bool EagerlyAssume; bool TrimGraph; bool InlineCall; bool EagerlyTrimEGraph; +public: + // Settings for inlining tuning. + + /// \brief The inlining stack depth limit. + unsigned InlineMaxStackDepth; + /// \brief The max number of basic blocks in a function being inlined. + unsigned InlineMaxFunctionSize; + public: AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, const LangOptions &lang, PathDiagnosticConsumer *pd, @@ -87,7 +98,9 @@ public: bool eager, bool trim, bool inlinecall, bool useUnoptimizedCFG, bool addImplicitDtors, bool addInitializers, - bool eagerlyTrimEGraph); + bool eagerlyTrimEGraph, + unsigned inlineMaxStack, + unsigned inlineMaxFunctionSize); /// Construct a clone of the given AnalysisManager with the given ASTContext /// and DiagnosticsEngine. diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index b0c03024ac..14cdefb9af 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1047,6 +1047,12 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, if (Args.hasArg(OPT_analyzer_inline_call)) Opts.InlineCall = 1; Opts.PrintStats = Args.hasArg(OPT_analyzer_stats); + Opts.InlineMaxStackDepth = + Args.getLastArgIntValue(OPT_analyzer_inline_max_stack_depth, + Opts.InlineMaxStackDepth, Diags); + Opts.InlineMaxFunctionSize = + Args.getLastArgIntValue(OPT_analyzer_inline_max_function_size, + Opts.InlineMaxFunctionSize, Diags); Opts.CheckersControlList.clear(); for (arg_iterator it = Args.filtered_begin(OPT_analyzer_checker, diff --git a/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/lib/StaticAnalyzer/Core/AnalysisManager.cpp index af18eff899..00701c9a05 100644 --- a/lib/StaticAnalyzer/Core/AnalysisManager.cpp +++ b/lib/StaticAnalyzer/Core/AnalysisManager.cpp @@ -29,7 +29,9 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, bool eager, bool trim, bool inlinecall, bool useUnoptimizedCFG, bool addImplicitDtors, bool addInitializers, - bool eagerlyTrimEGraph) + bool eagerlyTrimEGraph, + unsigned inlineMaxStack, + unsigned inlineMaxFunctionSize) : AnaCtxMgr(useUnoptimizedCFG, addImplicitDtors, addInitializers), Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd), CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr), @@ -37,7 +39,9 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, AScope(ScopeDecl), MaxNodes(maxnodes), MaxVisit(maxvisit), VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge), EagerlyAssume(eager), TrimGraph(trim), InlineCall(inlinecall), - EagerlyTrimEGraph(eagerlyTrimEGraph) + EagerlyTrimEGraph(eagerlyTrimEGraph), + InlineMaxStackDepth(inlineMaxStack), + InlineMaxFunctionSize(inlineMaxFunctionSize) { AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd(); } @@ -62,7 +66,9 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, EagerlyAssume(ParentAM.EagerlyAssume), TrimGraph(ParentAM.TrimGraph), InlineCall(ParentAM.InlineCall), - EagerlyTrimEGraph(ParentAM.EagerlyTrimEGraph) + EagerlyTrimEGraph(ParentAM.EagerlyTrimEGraph), + InlineMaxStackDepth(ParentAM.InlineMaxStackDepth), + InlineMaxFunctionSize(ParentAM.InlineMaxFunctionSize) { AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd(); } diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index c570d1bf59..bb4ea99b16 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -142,13 +142,16 @@ bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, // FIXME: Handle C++. break; case Stmt::CallExprClass: { - // Cap the stack depth at 4 calls (5 stack frames, base + 4 calls). - // These heuristics are a WIP. - if (getNumberStackFrames(Pred->getLocationContext()) == 5) + if (getNumberStackFrames(Pred->getLocationContext()) + == AMgr.InlineMaxStackDepth) return false; - - // Construct a new stack frame for the callee. + AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(FD); + const CFG *CalleeCFG = CalleeADC->getCFG(); + if (CalleeCFG->getNumBlockIDs() > AMgr.InlineMaxFunctionSize) + return false; + + // Construct a new stack frame for the callee. const StackFrameContext *CallerSFC = Pred->getLocationContext()->getCurrentStackFrame(); const StackFrameContext *CalleeSFC = diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 074ad23ce4..f8b6832f72 100644 --- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -157,7 +157,9 @@ public: Opts.TrimGraph, Opts.InlineCall, Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors, Opts.CFGAddInitializers, - Opts.EagerlyTrimEGraph)); + Opts.EagerlyTrimEGraph, + Opts.InlineMaxStackDepth, + Opts.InlineMaxFunctionSize)); if (Opts.PrintStats) llvm::EnableStatistics(); } diff --git a/test/Analysis/malloc-interprocedural.c b/test/Analysis/malloc-interprocedural.c index 374c4a310d..8a42f393ba 100644 --- a/test/Analysis/malloc-interprocedural.c +++ b/test/Analysis/malloc-interprocedural.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=unix.Malloc -analyzer-inline-call -analyzer-store=region -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=unix.Malloc -analyzer-inline-call -analyzer-inline-max-stack-depth 5 -analyzer-inline-max-function-size 6 -analyzer-store=region -verify %s #include "system-header-simulator.h"