[ObjC][ARC] In HandlePotentialAlterRefCount, check whether an
authorAkira Hatanaka <ahatanaka@apple.com>
Sat, 29 Aug 2020 00:44:56 +0000 (17:44 -0700)
committerAkira Hatanaka <ahatanaka@apple.com>
Sat, 29 Aug 2020 00:45:14 +0000 (17:45 -0700)
instruction can decrement the reference count, not whether it can alter
it

This prevents the state transition from S_Use to S_CanRelease when doing
a bottom-up traversal and the transition from S_Retain to S_CanRelease
when doing a top-down traversal when the visited instruction can
increment the ref count but cannot decrement it. This allows the ARC
optimizer to remove retain/release pairs which were previously not
removed.

rdar://problem/21793154

llvm/lib/Transforms/ObjCARC/PtrState.cpp
llvm/test/Transforms/ObjCARC/basic.ll
llvm/test/Transforms/ObjCARC/opt-catchswitch.ll

index 26dd416..6071ec3 100644 (file)
@@ -232,7 +232,7 @@ bool BottomUpPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
   Sequence S = GetSeq();
 
   // Check for possible releases.
-  if (!CanAlterRefCount(Inst, Ptr, PA, Class))
+  if (!CanDecrementRefCount(Inst, Ptr, PA, Class))
     return false;
 
   LLVM_DEBUG(dbgs() << "            CanAlterRefCount: Seq: " << S << "; "
@@ -383,7 +383,7 @@ bool TopDownPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
                                                    ARCInstKind Class) {
   // Check for possible releases. Treat clang.arc.use as a releasing instruction
   // to prevent sinking a retain past it.
-  if (!CanAlterRefCount(Inst, Ptr, PA, Class) &&
+  if (!CanDecrementRefCount(Inst, Ptr, PA, Class) &&
       Class != ARCInstKind::IntrinsicUser)
     return false;
 
index b25049c..ca27ca5 100644 (file)
@@ -19,6 +19,7 @@ declare i8* @llvm.objc.unretainedPointer(i8*)
 
 declare void @use_pointer(i8*)
 declare void @callee()
+declare void @callee2(i8*, i8*)
 declare void @callee_fnptr(void ()*)
 declare void @invokee()
 declare i8* @returner()
@@ -3057,6 +3058,21 @@ define void @test67(i8* %x) {
   ret void
 }
 
+; CHECK-LABEL: define void @test68(
+; CHECK-NOT:     call
+; CHECK:         call void @callee2(
+; CHECK-NOT:     call
+; CHECK:         ret void
+
+define void @test68(i8* %a, i8* %b) {
+  call i8* @llvm.objc.retain(i8* %a)
+  call i8* @llvm.objc.retain(i8* %b)
+  call void @callee2(i8* %a, i8* %b)
+  call void @llvm.objc.release(i8* %b), !clang.imprecise_release !0
+  call void @llvm.objc.release(i8* %a), !clang.imprecise_release !0
+  ret void
+}
+
 !llvm.module.flags = !{!1}
 !llvm.dbg.cu = !{!3}
 
index b627c11..2cce994 100644 (file)
@@ -15,6 +15,9 @@ declare dllimport void @llvm.objc.release(i8*)
 define i8* @g(i8* %p, i8* %q) local_unnamed_addr personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
 entry:
   %0 = tail call i8* @llvm.objc.retain(i8* %p) #0
+  ; the following call prevents ARC optimizer from removing the retain/release
+  ; pair on %p
+  %v1 = call i8* @f(i8* null, i8* null)
   %1 = tail call i8* @llvm.objc.retain(i8* %q) #0
   %call = invoke i8* @f(i8* %p, i8* %q)
           to label %invoke.cont unwind label %catch.dispatch, !clang.arc.no_objc_arc_exceptions !0
@@ -40,6 +43,7 @@ cleanup:
 
 ; CHECK-LABEL: entry:
 ; CHECK-NEXT:    %0 = tail call i8* @llvm.objc.retain(i8* %p) #0
+; CHECK-NEXT:    call i8* @f(i8* null, i8* null)
 ; CHECK-NEXT:    %call = invoke i8* @f(i8* %p, i8* %q)
 ; CHECK-NEXT:            to label %invoke.cont unwind label %catch.dispatch