aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2012-09-10 22:37:19 +0000
committerAnna Zaks <ganna@apple.com>2012-09-10 22:37:19 +0000
commit7229d0011766c174beffe6a846d78f448f845b39 (patch)
treec6c004f9d5ac847f1fda118d9b38301aef304d16
parent654f1d508cbc9553f4931b340dfa19b453f72ebd (diff)
[analyzer] Add ipa-always-inline-size option (with 3 as the default).
The option allows to always inline very small functions, whose size (in number of basic blocks) is set using -analyzer-config ipa-always-inline-size option. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163558 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/StaticAnalyzer/Core/AnalyzerOptions.h15
-rw-r--r--lib/StaticAnalyzer/Core/AnalyzerOptions.cpp24
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp22
-rw-r--r--test/Analysis/inlining/test-always-inline-size-option.c30
4 files changed, 83 insertions, 8 deletions
diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
index eb3f8e4271..72e614d3e7 100644
--- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
+++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -18,9 +18,9 @@
#include <string>
#include <vector>
#include "clang/Basic/LLVM.h"
-#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/StringMap.h"
namespace clang {
class ASTConsumer;
@@ -177,6 +177,10 @@ private:
/// \sa mayInlineTemplateFunctions
llvm::Optional<bool> InlineTemplateFunctions;
+
+ // Cache of the "ipa-always-inline-size" setting.
+ // \sa getAlwaysInlineSize
+ llvm::Optional<unsigned> AlwaysInlineSize;
/// Interprets an option's string value as a boolean.
///
@@ -184,6 +188,9 @@ private:
/// If an option value is not provided, returns the given \p DefaultVal.
bool getBooleanOption(StringRef Name, bool DefaultVal) const;
+ /// Interprets an option's string value as an integer value.
+ int getOptionAsInteger(llvm::StringRef Name, int DefaultVal) const;
+
public:
/// Returns the option controlling which C++ member functions will be
/// considered for inlining.
@@ -213,6 +220,12 @@ public:
/// accepts the values "true" and "false".
bool mayInlineTemplateFunctions() const;
+ // Returns the size of the functions (in basic blocks), which should be
+ // considered to be small enough to always inline.
+ //
+ // This is controlled by "ipa-always-inline-size" analyzer-config option.
+ unsigned getAlwaysInlineSize() const;
+
public:
AnalyzerOptions() : CXXMemberInliningMode() {
AnalysisStoreOpt = RegionStoreModel;
diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index 29e2783476..5cbbb8d462 100644
--- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -16,6 +16,7 @@
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
+using namespace llvm;
bool
AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind K) const {
@@ -80,3 +81,26 @@ bool AnalyzerOptions::mayInlineTemplateFunctions() const {
return *InlineTemplateFunctions;
}
+
+int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) const {
+ std::string OptStr = Config.lookup(Name);
+ if (OptStr.empty())
+ return DefaultVal;
+
+ int Res = DefaultVal;
+ assert(StringRef(OptStr).getAsInteger(10, Res) == false &&
+ "analyzer-config option should be numeric.");
+
+ return Res;
+}
+
+unsigned AnalyzerOptions::getAlwaysInlineSize() const {
+ if (!AlwaysInlineSize.hasValue()) {
+ unsigned DefaultSize = 3;
+ Optional<unsigned> &MutableOption =
+ const_cast<Optional<unsigned> &>(AlwaysInlineSize);
+ MutableOption = getOptionAsInteger("ipa-always-inline-size", DefaultSize);
+ }
+
+ return AlwaysInlineSize.getValue();
+}
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 9bf63c5b96..a4e1eb2f4c 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -247,14 +247,18 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
}
}
-static unsigned getNumberStackFrames(const LocationContext *LCtx) {
- unsigned count = 0;
+static void examineStackFrames(const Decl *D, const LocationContext *LCtx,
+ bool &IsRecursive, unsigned &StackDepth) {
+ IsRecursive = false;
+ StackDepth = 0;
while (LCtx) {
- if (isa<StackFrameContext>(LCtx))
- ++count;
+ if (const StackFrameContext *SFC = dyn_cast<StackFrameContext>(LCtx)) {
+ ++StackDepth;
+ if (SFC->getDecl() == D)
+ IsRecursive = true;
+ }
LCtx = LCtx->getParent();
}
- return count;
}
static bool IsInStdNamespace(const FunctionDecl *FD) {
@@ -282,8 +286,12 @@ bool ExprEngine::shouldInlineDecl(const Decl *D, ExplodedNode *Pred) {
if (!CalleeCFG)
return false;
- if (getNumberStackFrames(Pred->getLocationContext())
- == AMgr.options.InlineMaxStackDepth)
+ bool IsRecursive = false;
+ unsigned StackDepth = 0;
+ examineStackFrames(D, Pred->getLocationContext(), IsRecursive, StackDepth);
+ if ((StackDepth >= AMgr.options.InlineMaxStackDepth) &&
+ ((CalleeCFG->getNumBlockIDs() > AMgr.options.getAlwaysInlineSize())
+ || IsRecursive))
return false;
if (Engine.FunctionSummaries->hasReachedMaxBlockCount(D))
diff --git a/test/Analysis/inlining/test-always-inline-size-option.c b/test/Analysis/inlining/test-always-inline-size-option.c
new file mode 100644
index 0000000000..ef604c2128
--- /dev/null
+++ b/test/Analysis/inlining/test-always-inline-size-option.c
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-inline-max-stack-depth=3 -analyzer-config ipa-always-inline-size=3 -verify %s
+
+void clang_analyzer_eval(int);
+int nested5() {
+ return 0;
+}
+int nested4() {
+ return nested5();
+}
+int nested3() {
+ return nested4();
+}
+int nested2() {
+ return nested3();
+}
+int nested1() {
+ return nested2();
+}
+
+void testNested() {
+ clang_analyzer_eval(nested1() == 0); // expected-warning{{TRUE}}
+}
+
+// Make sure we terminate a recursive path.
+int recursive() {
+ return recursive();
+}
+int callRecursive() {
+ return recursive();
+}