summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2013-02-02 00:30:04 +0000
committerAnna Zaks <ganna@apple.com>2013-02-02 00:30:04 +0000
commit00c69a597cd9ca62c392f8e09c2698e2740d7241 (patch)
tree37f66222837410d0e4d507404a79b21f049891ed
parente9eb13aba3f684947962af9fc2ae0bc1e59a9f85 (diff)
downloadbcm5719-llvm-00c69a597cd9ca62c392f8e09c2698e2740d7241.tar.gz
bcm5719-llvm-00c69a597cd9ca62c392f8e09c2698e2740d7241.zip
[analyzer] Always inline functions with bodies generated by BodyFarm.
Inlining these functions is essential for correctness. We often have cases where we do not inline calls. For example, the shallow mode and when reanalyzing previously inlined ObjC methods as top level. llvm-svn: 174245
-rw-r--r--clang/include/clang/Analysis/AnalysisContext.h14
-rw-r--r--clang/lib/Analysis/AnalysisDeclContext.cpp17
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp16
-rw-r--r--clang/test/Analysis/NSString.m24
4 files changed, 68 insertions, 3 deletions
diff --git a/clang/include/clang/Analysis/AnalysisContext.h b/clang/include/clang/Analysis/AnalysisContext.h
index 168fc003dc3..062af1bad13 100644
--- a/clang/include/clang/Analysis/AnalysisContext.h
+++ b/clang/include/clang/Analysis/AnalysisContext.h
@@ -133,7 +133,21 @@ public:
void registerForcedBlockExpression(const Stmt *stmt);
const CFGBlock *getBlockForRegisteredExpression(const Stmt *stmt);
+ /// \brief Get the body of the Declaration.
Stmt *getBody() const;
+
+ /// \brief Get the body of the Declaration.
+ /// \param IsAutosynthesized Output parameter that specifies if the body is
+ /// auto-generated by the BodyFarm.
+ Stmt *getBody(bool &IsAutosynthesized) const;
+
+ /// \brief Checks if the body of the Decl is generated by the BodyFarm.
+ ///
+ /// Note, the lookup is not free. We are going to call getBody behind
+ /// the sceines.
+ /// \sa getBody
+ bool isBodyAutosynthesized() const;
+
CFG *getCFG();
CFGStmtMap *getCFGStmtMap();
diff --git a/clang/lib/Analysis/AnalysisDeclContext.cpp b/clang/lib/Analysis/AnalysisDeclContext.cpp
index bcaad9b0db5..20cc3d55f3e 100644
--- a/clang/lib/Analysis/AnalysisDeclContext.cpp
+++ b/clang/lib/Analysis/AnalysisDeclContext.cpp
@@ -86,11 +86,13 @@ static BodyFarm &getBodyFarm(ASTContext &C) {
return *BF;
}
-Stmt *AnalysisDeclContext::getBody() const {
+Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Stmt *Body = FD->getBody();
- if (!Body && Manager && Manager->synthesizeBodies())
+ if (!Body && Manager && Manager->synthesizeBodies()) {
+ IsAutosynthesized = true;
return getBodyFarm(getASTContext()).getBody(FD);
+ }
return Body;
}
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
@@ -104,6 +106,17 @@ Stmt *AnalysisDeclContext::getBody() const {
llvm_unreachable("unknown code decl");
}
+Stmt *AnalysisDeclContext::getBody() const {
+ bool Tmp;
+ return getBody(Tmp);
+}
+
+bool AnalysisDeclContext::isBodyAutosynthesized() const {
+ bool Tmp;
+ getBody(Tmp);
+ return Tmp;
+}
+
const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const {
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
return MD->getSelfDecl();
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 2c1f6c1d8f9..1d006b09ccb 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -733,13 +733,27 @@ void ExprEngine::conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr,
Bldr.generateNode(Call.getProgramPoint(), State, Pred);
}
+static bool isEssentialToInline(const CallEvent &Call) {
+ const Decl *D = Call.getDecl();
+ if (D) {
+ AnalysisDeclContext *AD =
+ Call.getLocationContext()->getAnalysisDeclContext()->
+ getManager()->getContext(D);
+
+ // The auto-synthesized bodies are essential to inline as they are
+ // usually small and commonly used.
+ return AD->isBodyAutosynthesized();
+ }
+ return false;
+}
+
void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred,
const CallEvent &CallTemplate) {
// Make sure we have the most recent state attached to the call.
ProgramStateRef State = Pred->getState();
CallEventRef<> Call = CallTemplate.cloneWithState(State);
- if (HowToInline == Inline_None) {
+ if (HowToInline == Inline_None && !isEssentialToInline(CallTemplate)) {
conservativeEvalCall(*Call, Bldr, Pred, State);
return;
}
diff --git a/clang/test/Analysis/NSString.m b/clang/test/Analysis/NSString.m
index 9339069f4c4..e7ac730c72e 100644
--- a/clang/test/Analysis/NSString.m
+++ b/clang/test/Analysis/NSString.m
@@ -404,3 +404,27 @@ void testOSCompareAndSwapXXBarrier_parameter_no_direct_release(NSString **old) {
else
return;
}
+
+@interface AlwaysInlineBodyFarmBodies : NSObject {
+ NSString *_value;
+}
+ - (NSString *)_value;
+ - (void)callValue;
+@end
+
+@implementation AlwaysInlineBodyFarmBodies
+
+- (NSString *)_value {
+ if (!_value) {
+ NSString *s = [[NSString alloc] init];
+ if (!OSAtomicCompareAndSwapPtr(0, s, (void**)&_value)) {
+ [s release];
+ }
+ }
+ return _value;
+}
+
+- (void)callValue {
+ [self _value];
+}
+@end \ No newline at end of file
OpenPOWER on IntegriCloud