aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/StaticAnalyzer/Core/AnalyzerOptions.h8
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h22
-rw-r--r--lib/StaticAnalyzer/Core/AnalyzerOptions.cpp6
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp15
-rw-r--r--test/Analysis/analyzer-config.c3
-rw-r--r--test/Analysis/analyzer-config.cpp3
6 files changed, 50 insertions, 7 deletions
diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
index 9cbce17ca8..02bb036a0a 100644
--- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
+++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -193,6 +193,9 @@ private:
/// \sa getGraphTrimInterval
llvm::Optional<unsigned> GraphTrimInterval;
+ /// \sa getMaxTimesInlineLarge
+ llvm::Optional<unsigned> MaxTimesInlineLarge;
+
/// Interprets an option's string value as a boolean.
///
/// Accepts the strings "true" and "false".
@@ -276,6 +279,11 @@ public:
/// node reclamation, set the option to "0".
unsigned getGraphTrimInterval();
+ /// Returns the maximum times a large function could be inlined.
+ ///
+ /// This is controlled by the 'max-times-inline-large' config option.
+ unsigned getMaxTimesInlineLarge();
+
public:
AnalyzerOptions() : CXXMemberInliningMode() {
AnalysisStoreOpt = RegionStoreModel;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
index 9e2505fe60..546cec568f 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
@@ -37,10 +37,14 @@ class FunctionSummariesTy {
/// Marks the IDs of the basic blocks visited during the analyzes.
llvm::BitVector VisitedBasicBlocks;
+ /// The number of times the function has been inlined.
+ unsigned TimesInlined;
+
FunctionSummary() :
MayReachMaxBlockCount(false),
TotalBasicBlocks(0),
- VisitedBasicBlocks(0) {}
+ VisitedBasicBlocks(0),
+ TimesInlined(0) {}
};
typedef llvm::DenseMap<const Decl*, FunctionSummary*> MapTy;
@@ -84,11 +88,23 @@ public:
unsigned getNumVisitedBasicBlocks(const Decl* D) {
MapTy::const_iterator I = Map.find(D);
- if (I != Map.end())
- return I->second->VisitedBasicBlocks.count();
+ if (I != Map.end())
+ return I->second->VisitedBasicBlocks.count();
return 0;
}
+ unsigned getNumTimesInlined(const Decl* D) {
+ MapTy::const_iterator I = Map.find(D);
+ if (I != Map.end())
+ return I->second->TimesInlined;
+ return 0;
+ }
+
+ void bumpNumTimesInlined(const Decl* D) {
+ MapTy::iterator I = findOrInsertSummary(D);
+ I->second->TimesInlined++;
+ }
+
/// Get the percentage of the reachable blocks.
unsigned getPercentBlocksReachable(const Decl *D) {
MapTy::const_iterator I = Map.find(D);
diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index 8ecbac009d..b993804afe 100644
--- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -133,6 +133,12 @@ unsigned AnalyzerOptions::getGraphTrimInterval() {
return GraphTrimInterval.getValue();
}
+unsigned AnalyzerOptions::getMaxTimesInlineLarge() {
+ if (!MaxTimesInlineLarge.hasValue())
+ MaxTimesInlineLarge = getOptionAsInteger("max-times-inline-large", 32);
+ return MaxTimesInlineLarge.getValue();
+}
+
bool AnalyzerOptions::shouldSynthesizeBodies() {
return getBooleanOption("faux-bodies", true);
}
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index d654bb5f70..7c1c26e8f7 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -33,6 +33,9 @@ STATISTIC(NumOfDynamicDispatchPathSplits,
STATISTIC(NumInlinedCalls,
"The # of times we inlined a call");
+STATISTIC(NumReachedInlineCountMax,
+ "The # of times we reached inline count maximum");
+
void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
// Get the entry block in the CFG of the callee.
const StackFrameContext *calleeCtx = CE.getCalleeContext();
@@ -415,12 +418,12 @@ bool ExprEngine::shouldInlineDecl(const Decl *D, ExplodedNode *Pred) {
if (getContext().getLangOpts().CPlusPlus) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// Conditionally allow the inlining of template functions.
- if (!getAnalysisManager().options.mayInlineTemplateFunctions())
+ if (!AMgr.options.mayInlineTemplateFunctions())
if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate)
return false;
// Conditionally allow the inlining of C++ standard library functions.
- if (!getAnalysisManager().options.mayInlineCXXStandardLibrary())
+ if (!AMgr.options.mayInlineCXXStandardLibrary())
if (getContext().getSourceManager().isInSystemHeader(FD->getLocation()))
if (IsInStdNamespace(FD))
return false;
@@ -432,6 +435,14 @@ bool ExprEngine::shouldInlineDecl(const Decl *D, ExplodedNode *Pred) {
if (!CalleeADC->getAnalysis<RelaxedLiveVariables>())
return false;
+ if (Engine.FunctionSummaries->getNumTimesInlined(D) >
+ AMgr.options.getMaxTimesInlineLarge() &&
+ CalleeCFG->getNumBlockIDs() > 13) {
+ NumReachedInlineCountMax++;
+ return false;
+ }
+ Engine.FunctionSummaries->bumpNumTimesInlined(D);
+
return true;
}
diff --git a/test/Analysis/analyzer-config.c b/test/Analysis/analyzer-config.c
index 990f5784b4..d156a6ec3b 100644
--- a/test/Analysis/analyzer-config.c
+++ b/test/Analysis/analyzer-config.c
@@ -9,5 +9,6 @@ void foo() { bar(); }
// CHECK-NEXT: faux-bodies = true
// CHECK-NEXT: graph-trim-interval = 1000
// CHECK-NEXT: ipa-always-inline-size = 3
+// CHECK-NEXT: max-times-inline-large = 32
// CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 4
+// CHECK-NEXT: num-entries = 5
diff --git a/test/Analysis/analyzer-config.cpp b/test/Analysis/analyzer-config.cpp
index fb142669b4..b3a8b34d49 100644
--- a/test/Analysis/analyzer-config.cpp
+++ b/test/Analysis/analyzer-config.cpp
@@ -18,5 +18,6 @@ public:
// CHECK-NEXT: faux-bodies = true
// CHECK-NEXT: graph-trim-interval = 1000
// CHECK-NEXT: ipa-always-inline-size = 3
+// CHECK-NEXT: max-times-inline-large = 32
// CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 7
+// CHECK-NEXT: num-entries = 8