[objc-arc] Make sure that multiple owners is propogated correctly through the pass...
authorMichael Gottesman <mgottesman@apple.com>
Fri, 24 May 2013 20:44:02 +0000 (20:44 +0000)
committerMichael Gottesman <mgottesman@apple.com>
Fri, 24 May 2013 20:44:02 +0000 (20:44 +0000)
rdar://13750319

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182669 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/ObjCARC/ObjCARCOpts.cpp
test/Transforms/ObjCARC/allocas.ll

index aa2134152d8393765bb92b69df41f077ac710230..91490d1b2d06f0d7418a70fff6c710eb89664f1c 100644 (file)
@@ -30,6 +30,7 @@
 #include "ObjCARCAliasAnalysis.h"
 #include "ProvenanceAnalysis.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/Statistic.h"
@@ -454,18 +455,8 @@ namespace {
     /// sequence.
     SmallPtrSet<Instruction *, 2> ReverseInsertPts;
 
-    /// Does this pointer have multiple owners?
-    ///
-    /// In the presence of multiple owners with the same provenance caused by
-    /// allocas, we can not assume that the frontend will emit balanced code
-    /// since it could put the release on the pointer loaded from the
-    /// alloca. This confuses the optimizer so we must be more conservative in
-    /// that case.
-    bool MultipleOwners;
-
     RRInfo() :
-      KnownSafe(false), IsTailCallRelease(false), ReleaseMetadata(0),
-      MultipleOwners(false) {}
+      KnownSafe(false), IsTailCallRelease(false), ReleaseMetadata(0) {}
 
     void clear();
 
@@ -478,7 +469,6 @@ namespace {
 void RRInfo::clear() {
   KnownSafe = false;
   IsTailCallRelease = false;
-  MultipleOwners = false;
   ReleaseMetadata = 0;
   Calls.clear();
   ReverseInsertPts.clear();
@@ -569,7 +559,6 @@ PtrState::Merge(const PtrState &Other, bool TopDown) {
     RRI.IsTailCallRelease = RRI.IsTailCallRelease &&
                             Other.RRI.IsTailCallRelease;
     RRI.Calls.insert(Other.RRI.Calls.begin(), Other.RRI.Calls.end());
-    RRI.MultipleOwners |= Other.RRI.MultipleOwners;
 
     // Merge the insert point sets. If there are any differences,
     // that makes this a partial merge.
@@ -1058,6 +1047,9 @@ namespace {
     bool Changed;
     ProvenanceAnalysis PA;
 
+    // This is used to track if a pointer is stored into an alloca.
+    DenseSet<const Value *> MultiOwnersSet;
+
     /// A flag indicating whether this optimization pass should run.
     bool Run;
 
@@ -1943,7 +1935,7 @@ ObjCARCOpt::VisitInstructionBottomUp(Instruction *Inst,
         BBState::ptr_iterator I = MyStates.findPtrBottomUpState(
           StripPointerCastsAndObjCCalls(SI->getValueOperand()));
         if (I != MyStates.bottom_up_ptr_end())
-          I->second.RRI.MultipleOwners = true;
+          MultiOwnersSet.insert(I->first);
       }
     }
     break;
@@ -2515,7 +2507,8 @@ ObjCARCOpt::ConnectTDBUTraversals(DenseMap<const BasicBlock *, BBState>
       assert(It != Retains.end());
       const RRInfo &NewRetainRRI = It->second;
       KnownSafeTD &= NewRetainRRI.KnownSafe;
-      MultipleOwners |= NewRetainRRI.MultipleOwners;
+      MultipleOwners =
+        MultipleOwners || MultiOwnersSet.count(GetObjCArg(NewRetain));
       for (SmallPtrSet<Instruction *, 2>::const_iterator
              LI = NewRetainRRI.Calls.begin(),
              LE = NewRetainRRI.Calls.end(); LI != LE; ++LI) {
@@ -2903,8 +2896,14 @@ bool ObjCARCOpt::OptimizeSequences(Function &F) {
   bool NestingDetected = Visit(F, BBStates, Retains, Releases);
 
   // Transform.
-  return PerformCodePlacement(BBStates, Retains, Releases, F.getParent()) &&
-         NestingDetected;
+  bool AnyPairsCompletelyEliminated = PerformCodePlacement(BBStates, Retains,
+                                                           Releases,
+                                                           F.getParent());
+
+  // Cleanup.
+  MultiOwnersSet.clear();
+
+  return AnyPairsCompletelyEliminated && NestingDetected;
 }
 
 /// Check if there is a dependent call earlier that does not have anything in
index eabd54deb7cfcb52de10f0d676f7e2a370d6f695..58740d2d802fbd83951eb93cd67c7327088511e4 100644 (file)
@@ -197,6 +197,103 @@ entry:
   ret void
 }
 
+; Make sure that if a store is in a different basic block we handle known safe
+; conservatively.
+
+
+; CHECK: define void @test2a(i8* %x)
+; CHECK: @objc_retain(i8* %x)
+; CHECK: @objc_retain(i8* %x)
+; CHECK: @objc_release(i8* %y)
+; CHECK: @objc_release(i8* %x)
+; CHECK: ret void
+; CHECK: }
+define void @test2a(i8* %x) {
+entry:
+  %A = alloca i8*
+  store i8* %x, i8** %A, align 8
+  %y = load i8** %A
+  br label %bb1
+
+bb1:
+  br label %bb2
+
+bb2:
+  br label %bb3
+
+bb3:
+  tail call i8* @objc_retain(i8* %x)
+  tail call i8* @objc_retain(i8* %x)
+  call void @use_alloca(i8** %A)
+  call void @objc_release(i8* %y), !clang.imprecise_release !0
+  call void @use_pointer(i8* %x)
+  call void @objc_release(i8* %x), !clang.imprecise_release !0
+  ret void
+}
+
+; CHECK: define void @test2b(i8* %x)
+; CHECK: @objc_retain(i8* %x)
+; CHECK: @objc_retain(i8* %x)
+; CHECK: @objc_release(i8* %y)
+; CHECK: @objc_release(i8* %x)
+; CHECK: ret void
+; CHECK: }
+define void @test2b(i8* %x) {
+entry:
+  %A = alloca i8*
+  %gep1 = getelementptr i8** %A, i32 0
+  store i8* %x, i8** %gep1, align 8
+  %gep2 = getelementptr i8** %A, i32 0
+  %y = load i8** %gep2
+  br label %bb1
+
+bb1:
+  br label %bb2
+
+bb2:
+  br label %bb3
+
+bb3:
+  tail call i8* @objc_retain(i8* %x)
+  tail call i8* @objc_retain(i8* %x)
+  call void @use_alloca(i8** %A)
+  call void @objc_release(i8* %y), !clang.imprecise_release !0
+  call void @use_pointer(i8* %x)
+  call void @objc_release(i8* %x), !clang.imprecise_release !0
+  ret void
+}
+
+; CHECK: define void @test2c(i8* %x)
+; CHECK: @objc_retain(i8* %x)
+; CHECK: @objc_retain(i8* %x)
+; CHECK: @objc_release(i8* %y)
+; CHECK: @objc_release(i8* %x)
+; CHECK: ret void
+; CHECK: }
+define void @test2c(i8* %x) {
+entry:
+  %A = alloca i8*, i32 3
+  %gep1 = getelementptr i8** %A, i32 2
+  store i8* %x, i8** %gep1, align 8
+  %gep2 = getelementptr i8** %A, i32 2
+  %y = load i8** %gep2
+  tail call i8* @objc_retain(i8* %x)
+  br label %bb1
+
+bb1:
+  br label %bb2
+
+bb2:
+  br label %bb3
+
+bb3:
+  tail call i8* @objc_retain(i8* %x)
+  call void @use_alloca(i8** %A)
+  call void @objc_release(i8* %y), !clang.imprecise_release !0
+  call void @use_pointer(i8* %x)
+  call void @objc_release(i8* %x), !clang.imprecise_release !0
+  ret void
+}
 
 !0 = metadata !{}