[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.

llvm-svn: 163558
This commit is contained in:
Anna Zaks 2012-09-10 22:37:19 +00:00
parent 41ff85d754
commit 14ce52492f
4 changed files with 83 additions and 8 deletions

View File

@ -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;

View File

@ -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();
}

View File

@ -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))

View File

@ -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();
}