[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:
parent
41ff85d754
commit
14ce52492f
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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();
|
||||
}
|
Loading…
Reference in New Issue