From 0cdece438972f4c670973d99d2c7743ab822de1a Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 19 Jan 2012 19:14:36 +0000 Subject: [PATCH] Set the "tail" flag on pattern-matched objc_storeStrong calls. rdar://10531041. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@148490 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/Scalar/ObjCARC.cpp | 32 +++++++++++++++++++ .../ObjCARC/contract-storestrong-ivar.ll | 2 +- .../ObjCARC/contract-storestrong.ll | 2 +- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/lib/Transforms/Scalar/ObjCARC.cpp b/lib/Transforms/Scalar/ObjCARC.cpp index 410f6bcd42f..08bb67eb1a2 100644 --- a/lib/Transforms/Scalar/ObjCARC.cpp +++ b/lib/Transforms/Scalar/ObjCARC.cpp @@ -3600,6 +3600,11 @@ namespace { /// RetainRV calls to make the optimization work on targets which need it. const MDString *RetainRVMarker; + /// StoreStrongCalls - The set of inserted objc_storeStrong calls. If + /// at the end of walking the function we have found no alloca + /// instructions, these calls can be marked "tail". + DenseSet StoreStrongCalls; + Constant *getStoreStrongCallee(Module *M); Constant *getRetainAutoreleaseCallee(Module *M); Constant *getRetainAutoreleaseRVCallee(Module *M); @@ -3803,6 +3808,11 @@ void ObjCARCContract::ContractRelease(Instruction *Release, StoreStrong->setDoesNotThrow(); StoreStrong->setDebugLoc(Store->getDebugLoc()); + // We can't set the tail flag yet, because we haven't yet determined + // whether there are any escaping allocas. Remember this call, so that + // we can set the tail flag once we know it's safe. + StoreStrongCalls.insert(StoreStrong); + if (&*Iter == Store) ++Iter; Store->eraseFromParent(); Release->eraseFromParent(); @@ -3849,6 +3859,13 @@ bool ObjCARCContract::runOnFunction(Function &F) { PA.setAA(&getAnalysis()); + // Track whether it's ok to mark objc_storeStrong calls with the "tail" + // keyword. Be conservative if the function has variadic arguments. + // It seems that functions which "return twice" are also unsafe for the + // "tail" argument, because they are setjmp, which could need to + // return to an earlier stack state. + bool TailOkForStoreStrongs = !F.isVarArg() && !F.callsFunctionThatReturnsTwice(); + // For ObjC library calls which return their argument, replace uses of the // argument with uses of the call return value, if it dominates the use. This // reduces register pressure. @@ -3905,6 +3922,13 @@ bool ObjCARCContract::runOnFunction(Function &F) { case IC_Release: ContractRelease(Inst, I); continue; + case IC_User: + // Be conservative if the function has any alloca instructions. + // Technically we only care about escaping alloca instructions, + // but this is sufficient to handle some interesting cases. + if (isa(Inst)) + TailOkForStoreStrongs = false; + continue; default: continue; } @@ -3969,5 +3993,13 @@ bool ObjCARCContract::runOnFunction(Function &F) { } } + // If this function has no escaping allocas or suspicious vararg usage, + // objc_storeStrong calls can be marked with the "tail" keyword. + if (TailOkForStoreStrongs) + for (DenseSet::iterator I = StoreStrongCalls.begin(), + E = StoreStrongCalls.end(); I != E; ++I) + (*I)->setTailCall(); + StoreStrongCalls.clear(); + return Changed; } diff --git a/test/Transforms/ObjCARC/contract-storestrong-ivar.ll b/test/Transforms/ObjCARC/contract-storestrong-ivar.ll index 4ad78e75347..4a9b3140f10 100644 --- a/test/Transforms/ObjCARC/contract-storestrong-ivar.ll +++ b/test/Transforms/ObjCARC/contract-storestrong-ivar.ll @@ -1,6 +1,6 @@ ; RUN: opt -objc-arc-contract -S < %s | FileCheck %s -; CHECK: call void @objc_storeStrong(i8** +; CHECK: tail call void @objc_storeStrong(i8** target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" target triple = "x86_64-apple-darwin11.0.0" diff --git a/test/Transforms/ObjCARC/contract-storestrong.ll b/test/Transforms/ObjCARC/contract-storestrong.ll index fda2ff4cbfc..4ff0596fbbc 100644 --- a/test/Transforms/ObjCARC/contract-storestrong.ll +++ b/test/Transforms/ObjCARC/contract-storestrong.ll @@ -9,7 +9,7 @@ declare void @objc_release(i8*) ; CHECK: define void @test0( ; CHECK: entry: -; CHECK-NEXT: call void @objc_storeStrong(i8** @x, i8* %p) nounwind +; CHECK-NEXT: tail call void @objc_storeStrong(i8** @x, i8* %p) nounwind ; CHECK-NEXT: ret void define void @test0(i8* %p) { entry: