[llvm] r301289 - [ObjCARC] Do not sink an objc_retain past a clang.arc.use.

Akira Hatanaka via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 24 21:06:36 PDT 2017


Author: ahatanak
Date: Mon Apr 24 23:06:35 2017
New Revision: 301289

URL: http://llvm.org/viewvc/llvm-project?rev=301289&view=rev
Log:
[ObjCARC] Do not sink an objc_retain past a clang.arc.use.

We need to do this to prevent a miscompile which sinks an objc_retain
past an objc_release that releases the object objc_retain retains. This
happens because the top-down and bottom-up traversals each determines
the insert point for retain or release individually without knowing
where the other instruction is moved.

For example, when the following IR is fed to the ARC optimizer, the
top-down traversal decides to insert objc_retain right before
objc_release and the bottom-up traversal decides to insert objc_release
right after clang.arc.use.

(IR before ARC optimizer)
%11 = call i8* @objc_retain(i8* %10)
call void (...) @clang.arc.use(%0* %5)
call void @llvm.dbg.value(...)
call void @objc_release(i8* %6)

This reverses the order of objc_release and objc_retain, which causes
the object to be destructed prematurely.

(IR after ARC optimizer)
call void (...) @clang.arc.use(%0* %5)
call void @objc_release(i8* %6)
call void @llvm.dbg.value(...)
%11 = call i8* @objc_retain(i8* %10)

rdar://problem/30530580

Added:
    llvm/trunk/test/Transforms/ObjCARC/clang-arc-use-barrier.ll
Modified:
    llvm/trunk/lib/Transforms/ObjCARC/PtrState.cpp
    llvm/trunk/test/Transforms/ObjCARC/intrinsic-use.ll

Modified: llvm/trunk/lib/Transforms/ObjCARC/PtrState.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/ObjCARC/PtrState.cpp?rev=301289&r1=301288&r2=301289&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/ObjCARC/PtrState.cpp (original)
+++ llvm/trunk/lib/Transforms/ObjCARC/PtrState.cpp Mon Apr 24 23:06:35 2017
@@ -351,8 +351,10 @@ bool TopDownPtrState::HandlePotentialAlt
                                                    const Value *Ptr,
                                                    ProvenanceAnalysis &PA,
                                                    ARCInstKind Class) {
-  // Check for possible releases.
-  if (!CanAlterRefCount(Inst, Ptr, PA, 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) &&
+      Class != ARCInstKind::IntrinsicUser)
     return false;
 
   DEBUG(dbgs() << "            CanAlterRefCount: Seq: " << GetSeq() << "; " << *Ptr

Added: llvm/trunk/test/Transforms/ObjCARC/clang-arc-use-barrier.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/ObjCARC/clang-arc-use-barrier.ll?rev=301289&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/ObjCARC/clang-arc-use-barrier.ll (added)
+++ llvm/trunk/test/Transforms/ObjCARC/clang-arc-use-barrier.ll Mon Apr 24 23:06:35 2017
@@ -0,0 +1,45 @@
+; RUN: opt -objc-arc -S %s | FileCheck %s
+
+%0 = type opaque
+
+; Make sure ARC optimizer doesn't sink @obj_retain past @clang.arc.use.
+
+; CHECK: call i8* @objc_retain(
+; CHECK: call void (...) @clang.arc.use(
+; CHECK: call i8* @objc_retain(
+; CHECK: call void (...) @clang.arc.use(
+
+define void @runTest() local_unnamed_addr {
+  %1 = alloca %0*, align 8
+  %2 = alloca %0*, align 8
+  %3 = tail call %0* @foo0()
+  %4 = bitcast %0* %3 to i8*
+  %5 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %4)
+  store %0* %3, %0** %1, align 8
+  call void @foo1(%0** nonnull %1)
+  %6 = load %0*, %0** %1, align 8
+  %7 = bitcast %0* %6 to i8*
+  %8 = call i8* @objc_retain(i8* %7)
+  call void (...) @clang.arc.use(%0* %3)
+  call void @objc_release(i8* %4)
+  store %0* %6, %0** %2, align 8
+  call void @foo1(%0** nonnull %2)
+  %9 = load %0*, %0** %2, align 8
+  %10 = bitcast %0* %9 to i8*
+  %11 = call i8* @objc_retain(i8* %10)
+  call void (...) @clang.arc.use(%0* %6)
+  %tmp1 = load %0*, %0** %2, align 8
+  call void @objc_release(i8* %7)
+  call void @foo2(%0* %9)
+  call void @objc_release(i8* %10)
+  ret void
+}
+
+declare %0* @foo0() local_unnamed_addr
+declare void @foo1(%0**) local_unnamed_addr
+declare void @foo2(%0*) local_unnamed_addr
+
+declare i8* @objc_retainAutoreleasedReturnValue(i8*) local_unnamed_addr
+declare i8* @objc_retain(i8*) local_unnamed_addr
+declare void @clang.arc.use(...) local_unnamed_addr
+declare void @objc_release(i8*) local_unnamed_addr

Modified: llvm/trunk/test/Transforms/ObjCARC/intrinsic-use.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/ObjCARC/intrinsic-use.ll?rev=301289&r1=301288&r2=301289&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/ObjCARC/intrinsic-use.ll (original)
+++ llvm/trunk/test/Transforms/ObjCARC/intrinsic-use.ll Mon Apr 24 23:06:35 2017
@@ -14,23 +14,20 @@ declare void @test0_helper(i8*, i8**)
 ; Ensure that we honor clang.arc.use as a use and don't miscompile
 ; the reduced test case from <rdar://13195034>.
 ;
-; FIXME: the fact that we re-order retains w.r.t. @clang.arc.use could
-; be problematic if we get run twice, e.g. under LTO.
-;
 ; CHECK-LABEL:      define void @test0(
 ; CHECK:        @objc_retain(i8* %x)
 ; CHECK-NEXT:   store i8* %y, i8** %temp0
 ; CHECK-NEXT:   @objc_retain(i8* %y)
 ; CHECK-NEXT:   call void @test0_helper
 ; CHECK-NEXT:   [[VAL1:%.*]] = load i8*, i8** %temp0
-; CHECK-NEXT:   call void (...) @clang.arc.use(i8* %y)
 ; CHECK-NEXT:   @objc_retain(i8* [[VAL1]])
+; CHECK-NEXT:   call void (...) @clang.arc.use(i8* %y)
 ; CHECK-NEXT:   @objc_release(i8* %y)
 ; CHECK-NEXT:   store i8* [[VAL1]], i8** %temp1
 ; CHECK-NEXT:   call void @test0_helper
 ; CHECK-NEXT:   [[VAL2:%.*]] = load i8*, i8** %temp1
-; CHECK-NEXT:   call void (...) @clang.arc.use(i8* [[VAL1]])
 ; CHECK-NEXT:   @objc_retain(i8* [[VAL2]])
+; CHECK-NEXT:   call void (...) @clang.arc.use(i8* [[VAL1]])
 ; CHECK-NEXT:   @objc_release(i8* [[VAL1]])
 ; CHECK-NEXT:   @objc_autorelease(i8* %x)
 ; CHECK-NEXT:   store i8* %x, i8** %out
@@ -71,14 +68,14 @@ entry:
 ; CHECK-NEXT:   @objc_retain(i8* %y)
 ; CHECK-NEXT:   call void @test0_helper
 ; CHECK-NEXT:   [[VAL1:%.*]] = load i8*, i8** %temp0
-; CHECK-NEXT:   call void (...) @clang.arc.use(i8* %y)
 ; CHECK-NEXT:   @objc_retain(i8* [[VAL1]])
+; CHECK-NEXT:   call void (...) @clang.arc.use(i8* %y)
 ; CHECK-NEXT:   @objc_release(i8* %y)
 ; CHECK-NEXT:   store i8* [[VAL1]], i8** %temp1
 ; CHECK-NEXT:   call void @test0_helper
 ; CHECK-NEXT:   [[VAL2:%.*]] = load i8*, i8** %temp1
-; CHECK-NEXT:   call void (...) @clang.arc.use(i8* [[VAL1]])
 ; CHECK-NEXT:   @objc_retain(i8* [[VAL2]])
+; CHECK-NEXT:   call void (...) @clang.arc.use(i8* [[VAL1]])
 ; CHECK-NEXT:   @objc_release(i8* [[VAL1]])
 ; CHECK-NEXT:   @objc_autorelease(i8* %x)
 ; CHECK-NEXT:   @objc_release(i8* [[VAL2]])




More information about the llvm-commits mailing list