summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAkira Hatanaka <ahatanaka@apple.com>2017-04-25 04:06:35 +0000
committerAkira Hatanaka <ahatanaka@apple.com>2017-04-25 04:06:35 +0000
commit490397fc08f1e4f24cc80354c6ea39f7db11d4ad (patch)
tree66997fea5eecc21736fee31e7466038d29039541
parent5b65f12bfa5bbcc657110edb6cffd8f5282edd88 (diff)
downloadbcm5719-llvm-490397fc08f1e4f24cc80354c6ea39f7db11d4ad.tar.gz
bcm5719-llvm-490397fc08f1e4f24cc80354c6ea39f7db11d4ad.zip
[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 llvm-svn: 301289
-rw-r--r--llvm/lib/Transforms/ObjCARC/PtrState.cpp6
-rw-r--r--llvm/test/Transforms/ObjCARC/clang-arc-use-barrier.ll45
-rw-r--r--llvm/test/Transforms/ObjCARC/intrinsic-use.ll11
3 files changed, 53 insertions, 9 deletions
diff --git a/llvm/lib/Transforms/ObjCARC/PtrState.cpp b/llvm/lib/Transforms/ObjCARC/PtrState.cpp
index a5afc8ad977..c1bbc4e96b1 100644
--- a/llvm/lib/Transforms/ObjCARC/PtrState.cpp
+++ b/llvm/lib/Transforms/ObjCARC/PtrState.cpp
@@ -351,8 +351,10 @@ bool TopDownPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
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
diff --git a/llvm/test/Transforms/ObjCARC/clang-arc-use-barrier.ll b/llvm/test/Transforms/ObjCARC/clang-arc-use-barrier.ll
new file mode 100644
index 00000000000..98d49ec512e
--- /dev/null
+++ b/llvm/test/Transforms/ObjCARC/clang-arc-use-barrier.ll
@@ -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
diff --git a/llvm/test/Transforms/ObjCARC/intrinsic-use.ll b/llvm/test/Transforms/ObjCARC/intrinsic-use.ll
index f75b1872b17..f5956201454 100644
--- a/llvm/test/Transforms/ObjCARC/intrinsic-use.ll
+++ b/llvm/test/Transforms/ObjCARC/intrinsic-use.ll
@@ -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]])
OpenPOWER on IntegriCloud