diff options
-rw-r--r-- | docs/analyzer/IPA.txt | 7 | ||||
-rw-r--r-- | include/clang/Frontend/Analyses.def | 1 | ||||
-rw-r--r-- | include/clang/Frontend/AnalyzerOptions.h | 2 | ||||
-rw-r--r-- | lib/Frontend/CompilerInvocation.cpp | 2 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp | 24 |
5 files changed, 25 insertions, 11 deletions
diff --git a/docs/analyzer/IPA.txt b/docs/analyzer/IPA.txt index 5691977128..c52b17a502 100644 --- a/docs/analyzer/IPA.txt +++ b/docs/analyzer/IPA.txt @@ -3,12 +3,13 @@ Inlining Inlining Modes ----------------------- --analyzer-ipa=none - All inlining is disabled. +-analyzer-ipa=none - All inlining is disabled. This is the only mode available in LLVM 3.1 and earlier and in Xcode 4.3 and earlier. +-analyzer-ipa=basic-inlining - Turns on inlining for C functions, C++ static member functions, and blocks -- essentially, the calls that behave like simple C function calls. This is essentially the mode used in Xcode 4.4. -analyzer-ipa=inlining - Turns on inlining when we can confidently find the function/method body corresponding to the call. (C functions, static functions, devirtualized C++ methods, ObjC class methods, ObjC instance methods when we are confident about the dynamic type of the instance). -analyzer-ipa=dynamic - Inline instance methods for which the type is determined at runtime and we are not 100% sure that our type info is correct. For virtual calls, inline the most plausible definition. -analyzer-ipa=dynamic-bifurcate - Same as -analyzer-ipa=dynamic, but the path is split. We inline on one branch and do not inline on the other. This mode does not drop the coverage in cases when the parent class has code that is only exercised when some of its methods are overriden. -Currently, -analyzer-ipa=inlining is the default mode. +Currently, -analyzer-ipa=basic-inlining is the default mode. Basics of Implementation ----------------------- @@ -50,7 +51,7 @@ Type information is tracked as DynamicTypeInfo, stored within the program state. When asked to provide a definition, the CallEvents for dynamic calls will use the type info in their state to provide the best definition of the method to be called. In some cases this devirtualization can be perfect or near-perfect, and we can inline the definition as usual. In others we can make a guess, but report that our guess may not be the method actually called at runtime. -The -analyzer-ipa option has four different modes: none, inlining, dynamic, and dynamic-bifurcate. Under -analyzer-ipa=dynamic, all dynamic calls are inlined, whether we are certain or not that this will actually be the definition used at runtime. Under -analyzer-ipa=inlining, only "near-perfect" devirtualized calls are inlined*, and other dynamic calls are evaluated conservatively (as if no definition were available). +The -analyzer-ipa option has five different modes: none, basic-inlining, inlining, dynamic, and dynamic-bifurcate. Under -analyzer-ipa=dynamic, all dynamic calls are inlined, whether we are certain or not that this will actually be the definition used at runtime. Under -analyzer-ipa=inlining, only "near-perfect" devirtualized calls are inlined*, and other dynamic calls are evaluated conservatively (as if no definition were available). Under -analyzer-ipa=basic-inlining, only simple calls (C functions and a few others) are inlined, and no devirtualization is performed. * Currently, no Objective-C messages are not inlined under -analyzer-ipa=inlining, even if we are reasonably confident of the type of the receiver. We plan to enable this once we have tested our heuristics more thoroughly. diff --git a/include/clang/Frontend/Analyses.def b/include/clang/Frontend/Analyses.def index 29ddc9e176..829ad71380 100644 --- a/include/clang/Frontend/Analyses.def +++ b/include/clang/Frontend/Analyses.def @@ -47,6 +47,7 @@ ANALYSIS_PURGE(PurgeNone, "none", "Do not purge symbols, bindings, or constrain #endif ANALYSIS_IPA(None, "none", "Perform only intra-procedural analysis") +ANALYSIS_IPA(BasicInlining, "basic-inlining", "Inline C functions and blocks when their definitions are available") ANALYSIS_IPA(Inlining, "inlining", "Inline callees when their definitions are available") ANALYSIS_IPA(DynamicDispatch, "dynamic", "Experimental: Enable inlining of dynamically dispatched methods") ANALYSIS_IPA(DynamicDispatchBifurcate, "dynamic-bifurcate", "Experimental: Enable inlining of dynamically dispatched methods, bifurcate paths when exact type info is unavailable") diff --git a/include/clang/Frontend/AnalyzerOptions.h b/include/clang/Frontend/AnalyzerOptions.h index 4e489fea74..4e5d7cba7c 100644 --- a/include/clang/Frontend/AnalyzerOptions.h +++ b/include/clang/Frontend/AnalyzerOptions.h @@ -109,7 +109,7 @@ public: AnalysisConstraintsOpt = RangeConstraintsModel; AnalysisDiagOpt = PD_HTML; AnalysisPurgeOpt = PurgeStmt; - IPAMode = Inlining; + IPAMode = BasicInlining; ShowCheckerHelp = 0; AnalyzeAll = 0; AnalyzerDisplayProgress = 0; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 09e95ce693..95f9c38828 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -147,7 +147,7 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, ToArgsList &Res) { getAnalysisPurgeModeName(Opts.AnalysisPurgeOpt)); if (!Opts.AnalyzeSpecificFunction.empty()) Res.push_back("-analyze-function", Opts.AnalyzeSpecificFunction); - if (Opts.IPAMode != Inlining) + if (Opts.IPAMode != BasicInlining) Res.push_back("-analyzer-ipa", getAnalysisIPAModeName(Opts.IPAMode)); if (Opts.InliningMode != NoRedundancy) Res.push_back("-analyzer-inlining-mode", diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index 3b2e4ec824..62e93b132e 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -22,8 +22,6 @@ #include "llvm/ADT/Statistic.h" #include "llvm/Support/SaveAndRestore.h" -#define CXX_INLINING_ENABLED 1 - using namespace clang; using namespace ento; @@ -305,6 +303,20 @@ template<> struct ProgramStateTrait<DynamicDispatchBifurcationMap> }} +static bool shouldInlineCXX(AnalysisManager &AMgr) { + switch (AMgr.IPAMode) { + case None: + case BasicInlining: + return false; + case Inlining: + case DynamicDispatch: + case DynamicDispatchBifurcate: + return true; + case NumIPAModes: + llvm_unreachable("not actually a valid option"); + } +} + bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D, NodeBuilder &Bldr, ExplodedNode *Pred, ProgramStateRef State) { @@ -320,11 +332,11 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D, break; case CE_CXXMember: case CE_CXXMemberOperator: - if (!CXX_INLINING_ENABLED) + if (!shouldInlineCXX(getAnalysisManager())) return false; break; case CE_CXXConstructor: { - if (!CXX_INLINING_ENABLED) + if (!shouldInlineCXX(getAnalysisManager())) return false; // Only inline constructors and destructors if we built the CFGs for them @@ -351,7 +363,7 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D, break; } case CE_CXXDestructor: { - if (!CXX_INLINING_ENABLED) + if (!shouldInlineCXX(getAnalysisManager())) return false; // Only inline constructors and destructors if we built the CFGs for them @@ -371,7 +383,7 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D, break; } case CE_CXXAllocator: - if (!CXX_INLINING_ENABLED) + if (!shouldInlineCXX(getAnalysisManager())) return false; // Do not inline allocators until we model deallocators. |