aboutsummaryrefslogtreecommitdiff
path: root/test/Transforms/ObjCARC/retain-block-escape-analysis.ll
diff options
context:
space:
mode:
Diffstat (limited to 'test/Transforms/ObjCARC/retain-block-escape-analysis.ll')
-rw-r--r--test/Transforms/ObjCARC/retain-block-escape-analysis.ll127
1 files changed, 127 insertions, 0 deletions
diff --git a/test/Transforms/ObjCARC/retain-block-escape-analysis.ll b/test/Transforms/ObjCARC/retain-block-escape-analysis.ll
new file mode 100644
index 0000000000..2c1ddce328
--- /dev/null
+++ b/test/Transforms/ObjCARC/retain-block-escape-analysis.ll
@@ -0,0 +1,127 @@
+; 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
+}
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; This test makes sure that we do not hang clang when visiting a use ;
+; cycle caused by phi nodes during objc-arc analysis. *NOTE* This ;
+; test case looks a little convoluted since it was produced by ;
+; bugpoint. ;
+; ;
+; bugzilla://14551 ;
+; rdar://12851911 ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+define void @phinode_use_cycle(i8* %block) uwtable optsize ssp {
+; CHECK: define void @phinode_use_cycle(i8* %block)
+entry:
+ br label %for.body
+
+for.body: ; preds = %if.then, %for.body, %entry
+ %block.05 = phi void (...)* [ null, %entry ], [ %1, %if.then ], [ %block.05, %for.body ]
+ br i1 undef, label %for.body, label %if.then
+
+if.then: ; preds = %for.body
+ %0 = call i8* @objc_retainBlock(i8* %block), !clang.arc.copy_on_escape !0
+ %1 = bitcast i8* %0 to void (...)*
+ %2 = bitcast void (...)* %block.05 to i8*
+ call void @objc_release(i8* %2) nounwind, !clang.imprecise_release !0
+ br label %for.body
+}
+
+!0 = metadata !{}