The promised test case for r175939.
authorMichael Gottesman <mgottesman@apple.com>
Sun, 17 Mar 2013 08:42:58 +0000 (08:42 +0000)
committerMichael Gottesman <mgottesman@apple.com>
Sun, 17 Mar 2013 08:42:58 +0000 (08:42 +0000)
This test makes sure that the ObjCARC escape analysis looks at the uses of
instructions which copy the block pointer value by checking all four cases where
that can occur.

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

test/Transforms/ObjCARC/retain-block-escape-analysis.ll [new file with mode: 0644]

diff --git a/test/Transforms/ObjCARC/retain-block-escape-analysis.ll b/test/Transforms/ObjCARC/retain-block-escape-analysis.ll
new file mode 100644 (file)
index 0000000..05f4c36
--- /dev/null
@@ -0,0 +1,100 @@
+; RUN: opt -S -objc-arc < %s | FileCheck %s
+
+declare i8* @objc_retain(i8*) nonlazybind
+declare void @objc_release(i8*) nonlazybind
+declare i8* @objc_retainBlock(i8*)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Use by an instruction which copies the value is an escape if the             ;
+; result is an escape. The current instructions with this property are:        ;
+;                                                                              ;
+; 1. BitCast.                                                                  ;
+; 2. GEP.                                                                      ;
+; 3. PhiNode.                                                                  ;
+; 4. SelectInst.                                                               ;
+;                                                                              ;
+; Make sure that such instructions do not confuse the optimizer into removing  ;
+; an objc_retainBlock that is needed.                                          ;
+;                                                                              ;
+; rdar://13273675. (With extra test cases to handle bitcast, phi, and select.  ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+define void @bitcasttest(i8* %storage, void (...)* %block)  {
+; CHECK: define void @bitcasttest
+entry:
+  %t1 = bitcast void (...)* %block to i8*
+; CHECK-NOT: tail call i8* @objc_retain
+  %t2 = tail call i8* @objc_retain(i8* %t1)
+; CHECK: tail call i8* @objc_retainBlock
+  %t3 = tail call i8* @objc_retainBlock(i8* %t1), !clang.arc.copy_on_escape !0
+  %t4 = bitcast i8* %storage to void (...)**
+  %t5 = bitcast i8* %t3 to void (...)*
+  store void (...)* %t5, void (...)** %t4, align 8
+; CHECK-NOT: call void @objc_release
+  call void @objc_release(i8* %t1)
+  ret void
+}
+
+define void @geptest(void (...)** %storage_array, void (...)* %block)  {
+; CHECK: define void @geptest
+entry:
+  %t1 = bitcast void (...)* %block to i8*
+; CHECK-NOT: tail call i8* @objc_retain
+  %t2 = tail call i8* @objc_retain(i8* %t1)
+; CHECK: tail call i8* @objc_retainBlock
+  %t3 = tail call i8* @objc_retainBlock(i8* %t1), !clang.arc.copy_on_escape !0
+  %t4 = bitcast i8* %t3 to void (...)*
+  
+  %storage = getelementptr inbounds void (...)** %storage_array, i64 0
+  
+  store void (...)* %t4, void (...)** %storage, align 8
+; CHECK-NOT: call void @objc_release
+  call void @objc_release(i8* %t1)
+  ret void
+}
+
+define void @selecttest(void (...)** %store1, void (...)** %store2,
+                        void (...)* %block) {
+; CHECK: define void @selecttest
+entry:
+  %t1 = bitcast void (...)* %block to i8*
+; CHECK-NOT: tail call i8* @objc_retain
+  %t2 = tail call i8* @objc_retain(i8* %t1)
+; CHECK: tail call i8* @objc_retainBlock
+  %t3 = tail call i8* @objc_retainBlock(i8* %t1), !clang.arc.copy_on_escape !0
+  %t4 = bitcast i8* %t3 to void (...)*
+  %store = select i1 undef, void (...)** %store1, void (...)** %store2
+  store void (...)* %t4, void (...)** %store, align 8
+; CHECK-NOT: call void @objc_release
+  call void @objc_release(i8* %t1)
+  ret void
+}
+
+define void @phinodetest(void (...)** %storage1,
+                         void (...)** %storage2,
+                         void (...)* %block) {
+; CHECK: define void @phinodetest
+entry:
+  %t1 = bitcast void (...)* %block to i8*
+; CHECK-NOT: tail call i8* @objc_retain
+  %t2 = tail call i8* @objc_retain(i8* %t1)
+; CHECK: tail call i8* @objc_retainBlock
+  %t3 = tail call i8* @objc_retainBlock(i8* %t1), !clang.arc.copy_on_escape !0
+  %t4 = bitcast i8* %t3 to void (...)*
+  br i1 undef, label %store1_set, label %store2_set
+
+store1_set:
+  br label %end
+
+store2_set:
+  br label %end
+
+end:
+  %storage = phi void (...)** [ %storage1, %store1_set ], [ %storage2, %store2_set]
+  store void (...)* %t4, void (...)** %storage, align 8
+; CHECK-NOT: call void @objc_release
+  call void @objc_release(i8* %t1)
+  ret void
+}
+
+!0 = metadata !{}