HelpText<"Display exploded graph using 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: 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_stack_depth_EQ : Joined<"-analyzer-inline-max-stack-depth=">,
+ Alias<analyzer_inline_max_stack_depth>;
+
def analyzer_inline_max_function_size : Separate<"-analyzer-inline-max-function-size">,
HelpText<"Bound on the number of basic blocks in an inlined function (200 by default)">;
+def analyzer_inline_max_function_size_EQ : Joined<"-analyzer-inline-max-function-size=">,
+ Alias<analyzer_inline_max_function_size>;
+
+def analyzer_ipa : Separate<"-analyzer-ipa">,
+ HelpText<"Specify the inter-procedural analysis mode">;
+def analyzer_ipa_EQ : Joined<"-analyzer-ipa=">, Alias<analyzer_ipa>;
+
+def analyzer_inlining_mode : Separate<"-analyzer-inlining-mode">,
+ HelpText<"Specify the function selection heuristic used during inlining">;
+def analyzer_inlining_mode_EQ : Joined<"-analyzer-inlining-mode=">, Alias<analyzer_inlining_mode>;
+
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">,
ANALYSIS_PURGE(PurgeBlock, "block", "Purge symbols, bindings, and constraints before every basic block")
ANALYSIS_PURGE(PurgeNone, "none", "Do not purge symbols, bindings, or constraints")
+#ifndef ANALYSIS_IPA
+#define ANALYSIS_IPA(NAME, CMDFLAG, DESC)
+#endif
+
+ANALYSIS_IPA(None, "none", "Perform only intra-procedural analysis")
+ANALYSIS_IPA(Inlining, "inlining", "Experimental: Inline callees when their definitions are available")
+
+#ifndef ANALYSIS_INLINING_MODE
+#define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC)
+#endif
+
+ANALYSIS_INLINING_MODE(All, "all", "Analyze all functions in the order defined in the TU")
+ANALYSIS_INLINING_MODE(NoRedundancy, "noredundancy", "Do not analyze a function which has been previously inlined, use call graph to order")
+
#undef ANALYSIS_STORE
#undef ANALYSIS_CONSTRAINTS
#undef ANALYSIS_DIAGNOSTICS
#undef ANALYSIS_PURGE
+#undef ANALYSIS_INLINING_MODE
+#undef ANALYSIS_IPA
NumPurgeModes
};
+/// AnalysisIPAMode - Set of inter-procedural modes.
+enum AnalysisIPAMode {
+#define ANALYSIS_IPA(NAME, CMDFLAG, DESC) NAME,
+#include "clang/Frontend/Analyses.def"
+NumIPAModes
+};
+
+/// AnalysisInlineFunctionSelection - Set of inlining function selection heuristics.
+enum AnalysisInliningMode {
+#define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) NAME,
+#include "clang/Frontend/Analyses.def"
+NumInliningModes
+};
+
class AnalyzerOptions {
public:
/// \brief Pair of checker name and enable/disable.
AnalysisConstraints AnalysisConstraintsOpt;
AnalysisDiagClients AnalysisDiagOpt;
AnalysisPurgeMode AnalysisPurgeOpt;
+ AnalysisIPAMode IPAMode;
std::string AnalyzeSpecificFunction;
unsigned MaxNodes;
unsigned MaxLoop;
unsigned TrimGraph : 1;
unsigned VisualizeEGDot : 1;
unsigned VisualizeEGUbi : 1;
- unsigned InlineCall : 1;
unsigned UnoptimizedCFG : 1;
unsigned CFGAddImplicitDtors : 1;
unsigned CFGAddInitializers : 1;
unsigned PrintStats : 1;
unsigned InlineMaxStackDepth;
unsigned InlineMaxFunctionSize;
+ AnalysisInliningMode InliningMode;
public:
AnalyzerOptions() {
AnalysisConstraintsOpt = RangeConstraintsModel;
AnalysisDiagOpt = PD_HTML;
AnalysisPurgeOpt = PurgeStmt;
+ IPAMode = Inlining;
ShowCheckerHelp = 0;
AnalyzeAll = 0;
AnalyzerDisplayProgress = 0;
TrimGraph = 0;
VisualizeEGDot = 0;
VisualizeEGUbi = 0;
- InlineCall = 1;
UnoptimizedCFG = 0;
CFGAddImplicitDtors = 0;
CFGAddInitializers = 0;
// Cap the stack depth at 4 calls (5 stack frames, base + 4 calls).
InlineMaxStackDepth = 5;
InlineMaxFunctionSize = 200;
+ InliningMode = All;
}
};
/// bifurcates paths.
bool EagerlyAssume;
bool TrimGraph;
- bool InlineCall;
bool EagerlyTrimEGraph;
public:
- // Settings for inlining tuning.
+ // \brief inter-procedural analysis mode.
+ AnalysisIPAMode IPAMode;
+ // 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;
+ /// \brief The mode of function selection used during inlining.
+ AnalysisInliningMode InliningMode;
public:
AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
unsigned maxnodes, unsigned maxvisit,
bool vizdot, bool vizubi, AnalysisPurgeMode purge,
bool eager, bool trim,
- bool inlinecall, bool useUnoptimizedCFG,
+ bool useUnoptimizedCFG,
bool addImplicitDtors, bool addInitializers,
bool eagerlyTrimEGraph,
+ AnalysisIPAMode ipa,
unsigned inlineMaxStack,
- unsigned inlineMaxFunctionSize);
+ unsigned inlineMaxFunctionSize,
+ AnalysisInliningMode inliningMode);
/// Construct a clone of the given AnalysisManager with the given ASTContext
/// and DiagnosticsEngine.
bool shouldEagerlyAssume() const { return EagerlyAssume; }
- bool shouldInlineCall() const { return InlineCall; }
+ bool shouldInlineCall() const { return (IPAMode == Inlining); }
bool hasIndexer() const { return Idxer != 0; }
CmdArgs.push_back("-analyzer-eagerly-assume");
- CmdArgs.push_back("-analyzer-inline-call");
+ CmdArgs.push_back("-analyzer-ipa=inlining");
// Add default argument set.
if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) {
static const char *getAnalysisPurgeModeName(AnalysisPurgeMode Kind) {
switch (Kind) {
default:
- llvm_unreachable("Unknown analysis client!");
+ llvm_unreachable("Unknown analysis purge mode!");
#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \
case NAME: return CMDFLAG;
#include "clang/Frontend/Analyses.def"
}
}
+static const char *getAnalysisIPAModeName(AnalysisIPAMode Kind) {
+ switch (Kind) {
+ default:
+ llvm_unreachable("Unknown analysis ipa mode!");
+#define ANALYSIS_IPA(NAME, CMDFLAG, DESC) \
+ case NAME: return CMDFLAG;
+#include "clang/Frontend/Analyses.def"
+ }
+}
+
+static const char *
+ getAnalysisInliningModeName(AnalysisInliningMode Kind) {
+ switch (Kind) {
+ default:
+ llvm_unreachable("Unknown analysis inlining mode!");
+#define ANALYSIS_INLINE_SELECTION(NAME, CMDFLAG, DESC) \
+ case NAME: return CMDFLAG;
+#include "clang/Frontend/Analyses.def"
+ }
+}
+
//===----------------------------------------------------------------------===//
// Serialization (to args)
//===----------------------------------------------------------------------===//
Res.push_back("-analyze-function");
Res.push_back(Opts.AnalyzeSpecificFunction);
}
+ if (Opts.IPAMode != Inlining) {
+ Res.push_back("-analyzer-ipa");
+ Res.push_back(getAnalysisIPAModeName(Opts.IPAMode));
+ }
+ if (Opts.InliningMode != All) {
+ Res.push_back("-analyzer-inlining-mode");
+ Res.push_back(getAnalysisInliningModeName(Opts.InliningMode));
+ }
+
if (Opts.AnalyzeAll)
Res.push_back("-analyzer-opt-analyze-headers");
if (Opts.AnalyzerDisplayProgress)
}
}
+ if (Arg *A = Args.getLastArg(OPT_analyzer_ipa)) {
+ StringRef Name = A->getValue(Args);
+ AnalysisIPAMode Value = llvm::StringSwitch<AnalysisIPAMode>(Name)
+#define ANALYSIS_IPA(NAME, CMDFLAG, DESC) \
+ .Case(CMDFLAG, NAME)
+#include "clang/Frontend/Analyses.def"
+ .Default(NumIPAModes);
+ if (Value == NumIPAModes) {
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << Name;
+ Success = false;
+ } else {
+ Opts.IPAMode = Value;
+ }
+ }
+
+ if (Arg *A = Args.getLastArg(OPT_analyzer_inlining_mode)) {
+ StringRef Name = A->getValue(Args);
+ AnalysisInliningMode Value = llvm::StringSwitch<AnalysisInliningMode>(Name)
+#define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) \
+ .Case(CMDFLAG, NAME)
+#include "clang/Frontend/Analyses.def"
+ .Default(NumInliningModes);
+ if (Value == NumInliningModes) {
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << Name;
+ Success = false;
+ } else {
+ Opts.InliningMode = Value;
+ }
+ }
+
Opts.ShowCheckerHelp = Args.hasArg(OPT_analyzer_checker_help);
Opts.VisualizeEGDot = Args.hasArg(OPT_analyzer_viz_egraph_graphviz);
Opts.VisualizeEGUbi = Args.hasArg(OPT_analyzer_viz_egraph_ubigraph);
Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags);
Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 4, Diags);
Opts.EagerlyTrimEGraph = !Args.hasArg(OPT_analyzer_no_eagerly_trim_egraph);
- 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,
bool vizdot, bool vizubi,
AnalysisPurgeMode purge,
bool eager, bool trim,
- bool inlinecall, bool useUnoptimizedCFG,
+ bool useUnoptimizedCFG,
bool addImplicitDtors, bool addInitializers,
bool eagerlyTrimEGraph,
+ AnalysisIPAMode ipa,
unsigned inlineMaxStack,
- unsigned inlineMaxFunctionSize)
+ unsigned inlineMaxFunctionSize,
+ AnalysisInliningMode IMode)
: AnaCtxMgr(useUnoptimizedCFG, addImplicitDtors, addInitializers),
Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd),
CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr),
CheckerMgr(checkerMgr), Idxer(idxer),
AScope(ScopeDecl), MaxNodes(maxnodes), MaxVisit(maxvisit),
VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge),
- EagerlyAssume(eager), TrimGraph(trim), InlineCall(inlinecall),
+ EagerlyAssume(eager), TrimGraph(trim),
EagerlyTrimEGraph(eagerlyTrimEGraph),
+ IPAMode(ipa),
InlineMaxStackDepth(inlineMaxStack),
- InlineMaxFunctionSize(inlineMaxFunctionSize)
+ InlineMaxFunctionSize(inlineMaxFunctionSize),
+ InliningMode(IMode)
{
AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd();
}
PurgeDead(ParentAM.PurgeDead),
EagerlyAssume(ParentAM.EagerlyAssume),
TrimGraph(ParentAM.TrimGraph),
- InlineCall(ParentAM.InlineCall),
EagerlyTrimEGraph(ParentAM.EagerlyTrimEGraph),
+ IPAMode(ParentAM.IPAMode),
InlineMaxStackDepth(ParentAM.InlineMaxStackDepth),
- InlineMaxFunctionSize(ParentAM.InlineMaxFunctionSize)
+ InlineMaxFunctionSize(ParentAM.InlineMaxFunctionSize),
+ InliningMode(ParentAM.InliningMode)
{
AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd();
}
Opts.MaxNodes, Opts.MaxLoop,
Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
Opts.AnalysisPurgeOpt, Opts.EagerlyAssume,
- Opts.TrimGraph, Opts.InlineCall,
+ Opts.TrimGraph,
Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors,
Opts.CFGAddInitializers,
Opts.EagerlyTrimEGraph,
+ Opts.IPAMode,
Opts.InlineMaxStackDepth,
- Opts.InlineMaxFunctionSize));
+ Opts.InlineMaxFunctionSize,
+ Opts.InliningMode));
}
virtual void HandleTranslationUnit(ASTContext &C);
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -analyzer-inline-call -cfg-add-implicit-dtors -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -analyzer-ipa=inlining -cfg-add-implicit-dtors -verify %s
class A {
public:
-// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=core -analyzer-inline-call -analyzer-store region -verify %s
+// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-store region -verify %s
// For now, don't inline varargs.
void foo(int *x, ...) {
-// RUN: %clang --analyze %s -Xclang -analyzer-inline-call -o %t
+// RUN: %clang --analyze %s -Xclang -analyzer-ipa=inlining -o %t
// RUN: FileCheck -input-file %t %s
// <rdar://problem/10967815>
-// RUN: %clang --analyze %s -Xclang -analyzer-inline-call -o %t > /dev/null 2>&1
+// RUN: %clang --analyze %s -Xclang -analyzer-ipa=inlining -o %t > /dev/null 2>&1
// RUN: FileCheck -input-file %t %s
static inline bug(int *p) {
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-inline-call -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-store region -verify %s
int test1_f1() {
int y = 1;
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-inline-call -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-store region -verify %s
// Test parameter 'a' is registered to LiveVariables analysis data although it
// is not referenced in the function body.
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-inline-call -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-store region -verify %s
// Test when entering f1(), we set the right AnalysisDeclContext to Environment.
// Otherwise, block-level expr '1 && a' would not be block-level.
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-inline-call -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-store region -verify %s
int g(int a) {
return a;
-// RUN: %clang_cc1 -analyze -analyzer-checker=osx.SecKeychainAPI %s -analyzer-inline-call -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=osx.SecKeychainAPI %s -analyzer-ipa=inlining -verify
// Fake typedefs.
typedef unsigned int OSStatus;
-// 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
+// RUN: %clang_cc1 -analyze -analyzer-checker=unix.Malloc -analyzer-ipa=inlining -analyzer-inline-max-stack-depth=5 -analyzer-inline-max-function-size=6 -analyzer-store=region -verify %s
#include "system-header-simulator.h"
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -analyzer-inline-call -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -analyzer-ipa=inlining -verify %s
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from Mac OS X headers: