[analyzer] Change inlining policy to inline small functions when reanalyzing ObjC methods as top level.

This allows us to better reason about(inline) small wrapper functions.

llvm-svn: 178063
This commit is contained in:
Anna Zaks 2013-03-26 18:57:58 +00:00
parent ea47959c2f
commit b13d21b6e1
4 changed files with 51 additions and 21 deletions

View File

@ -48,13 +48,13 @@ class CXXConstructorCall;
class ExprEngine : public SubEngine { class ExprEngine : public SubEngine {
public: public:
/// The modes of inlining. /// The modes of inlining, which override the default analysis-wide settings.
enum InliningModes { enum InliningModes {
/// Do not inline any of the callees. /// Follow the default settings for inlining callees.
Inline_None = 0, Inline_Regular = 0,
/// Inline all callees. /// Do minimal inlining of callees.
Inline_All = 0x1 Inline_Minimal = 0x1
} ; };
private: private:
AnalysisManager &AMgr; AnalysisManager &AMgr;

View File

@ -683,7 +683,7 @@ bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D,
if (CalleeADC->isBodyAutosynthesized()) if (CalleeADC->isBodyAutosynthesized())
return true; return true;
if (HowToInline == Inline_None) if (!AMgr.shouldInlineCall())
return false; return false;
// Check if we should inline a call based on its kind. // Check if we should inline a call based on its kind.
@ -745,6 +745,12 @@ bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D,
NumReachedInlineCountMax++; NumReachedInlineCountMax++;
return false; return false;
} }
if (HowToInline == Inline_Minimal &&
(CalleeCFG->getNumBlockIDs() > Opts.getAlwaysInlineSize()
|| IsRecursive))
return false;
Engine.FunctionSummaries->bumpNumTimesInlined(D); Engine.FunctionSummaries->bumpNumTimesInlined(D);
return true; return true;

View File

@ -234,11 +234,11 @@ public:
else if (Mode == AM_Path) { else if (Mode == AM_Path) {
llvm::errs() << " (Path, "; llvm::errs() << " (Path, ";
switch (IMode) { switch (IMode) {
case ExprEngine::Inline_None: case ExprEngine::Inline_Minimal:
llvm::errs() << " Inline_None"; llvm::errs() << " Inline_Minimal";
break; break;
case ExprEngine::Inline_All: case ExprEngine::Inline_Regular:
llvm::errs() << " Inline_All"; llvm::errs() << " Inline_Regular";
break; break;
} }
llvm::errs() << ")"; llvm::errs() << ")";
@ -284,7 +284,8 @@ public:
virtual void HandleTranslationUnit(ASTContext &C); virtual void HandleTranslationUnit(ASTContext &C);
/// \brief Determine which inlining mode should be used when this function is /// \brief Determine which inlining mode should be used when this function is
/// analyzed. For example, determines if the callees should be inlined. /// analyzed. This allows to redefine the default inlining policies when
/// analyzing a given function.
ExprEngine::InliningModes ExprEngine::InliningModes
getInliningModeForFunction(const Decl *D, SetOfConstDecls Visited); getInliningModeForFunction(const Decl *D, SetOfConstDecls Visited);
@ -299,7 +300,7 @@ public:
/// set of functions which should be considered analyzed after analyzing the /// set of functions which should be considered analyzed after analyzing the
/// given root function. /// given root function.
void HandleCode(Decl *D, AnalysisMode Mode, void HandleCode(Decl *D, AnalysisMode Mode,
ExprEngine::InliningModes IMode = ExprEngine::Inline_None, ExprEngine::InliningModes IMode = ExprEngine::Inline_Minimal,
SetOfConstDecls *VisitedCallees = 0); SetOfConstDecls *VisitedCallees = 0);
void RunPathSensitiveChecks(Decl *D, void RunPathSensitiveChecks(Decl *D,
@ -410,22 +411,18 @@ static bool shouldSkipFunction(const Decl *D,
ExprEngine::InliningModes ExprEngine::InliningModes
AnalysisConsumer::getInliningModeForFunction(const Decl *D, AnalysisConsumer::getInliningModeForFunction(const Decl *D,
SetOfConstDecls Visited) { SetOfConstDecls Visited) {
ExprEngine::InliningModes HowToInline =
(Mgr->shouldInlineCall()) ? ExprEngine::Inline_All :
ExprEngine::Inline_None;
// We want to reanalyze all ObjC methods as top level to report Retain // We want to reanalyze all ObjC methods as top level to report Retain
// Count naming convention errors more aggressively. But we can turn off // Count naming convention errors more aggressively. But we should tune down
// inlining when reanalyzing an already inlined function. // inlining when reanalyzing an already inlined function.
if (Visited.count(D)) { if (Visited.count(D)) {
assert(isa<ObjCMethodDecl>(D) && assert(isa<ObjCMethodDecl>(D) &&
"We are only reanalyzing ObjCMethods."); "We are only reanalyzing ObjCMethods.");
const ObjCMethodDecl *ObjCM = cast<ObjCMethodDecl>(D); const ObjCMethodDecl *ObjCM = cast<ObjCMethodDecl>(D);
if (ObjCM->getMethodFamily() != OMF_init) if (ObjCM->getMethodFamily() != OMF_init)
HowToInline = ExprEngine::Inline_None; return ExprEngine::Inline_Minimal;
} }
return HowToInline; return ExprEngine::Inline_Regular;
} }
void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) { void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) {
@ -595,7 +592,7 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
checkerMgr->runCheckersOnASTBody(D, *Mgr, BR); checkerMgr->runCheckersOnASTBody(D, *Mgr, BR);
if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) { if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
RunPathSensitiveChecks(D, IMode, VisitedCallees); RunPathSensitiveChecks(D, IMode, VisitedCallees);
if (IMode != ExprEngine::Inline_None) if (IMode != ExprEngine::Inline_Minimal)
NumFunctionsAnalyzed++; NumFunctionsAnalyzed++;
} }
} }

View File

@ -361,3 +361,30 @@ CFStringRef testCovariantReturnType() {
} }
return Str; return Str;
} }
// Test that we reanalyze ObjC methods which have been inlined. When reanalyzing
// them, make sure we inline very small functions.
@interface MyClass : NSObject
- (id)test_return_retained_NS;
- (void)test_return_retained;
@end
id returnInputParam(id x) {
return x;
}
@implementation MyClass
- (id)test_return_retained_NS {
// This method does not follow naming conventions, so a warning will be
// reported when it is reanalyzed at top level.
return returnInputParam([[NSString alloc] init]); // expected-warning {{leak}}
}
- (void)test_return_retained {
id x = test_return_retained_NS(); // expected-warning {{leak}}
[x retain];
[x release];
}
@end