summaryrefslogtreecommitdiff
path: root/test/Transforms/ObjCARC
diff options
context:
space:
mode:
authorMichael Gottesman <mgottesman@apple.com>2013-05-24 20:44:05 +0000
committerMichael Gottesman <mgottesman@apple.com>2013-05-24 20:44:05 +0000
commit7932798384725834bd77f934e3408e5cca29c131 (patch)
tree10fea11bdb6a9c1ec35d1ab099d29168cd398423 /test/Transforms/ObjCARC
parent35e88e57eacdb8edff3b5890e8271a805f250606 (diff)
downloadllvm-7932798384725834bd77f934e3408e5cca29c131.tar.gz
llvm-7932798384725834bd77f934e3408e5cca29c131.tar.bz2
llvm-7932798384725834bd77f934e3408e5cca29c131.tar.xz
[objc-arc] KnownSafe does not imply that it is safe to perform code motion across CFG edges since even if it is safe to remove RR pairs, we may still be able to move a retain/release into a loop.
rdar://13949644 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182670 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/Transforms/ObjCARC')
-rw-r--r--test/Transforms/ObjCARC/allocas.ll200
1 files changed, 200 insertions, 0 deletions
diff --git a/test/Transforms/ObjCARC/allocas.ll b/test/Transforms/ObjCARC/allocas.ll
index 58740d2d80..50656739ae 100644
--- a/test/Transforms/ObjCARC/allocas.ll
+++ b/test/Transforms/ObjCARC/allocas.ll
@@ -18,6 +18,8 @@ declare void @callee()
declare void @callee_fnptr(void ()*)
declare void @invokee()
declare i8* @returner()
+declare i8* @returner1()
+declare i8* @returner2()
declare void @bar(i32 ()*)
declare void @use_alloca(i8**)
@@ -295,6 +297,204 @@ bb3:
ret void
}
+; CHECK: define void @test2d(i8* %x)
+; CHECK: @objc_retain(i8* %x)
+; CHECK: @objc_retain(i8* %x)
+; CHECK: @objc_release(i8* %y)
+; CHECK: @objc_release(i8* %x)
+; CHECK: ret void
+; CHECK: }
+define void @test2d(i8* %x) {
+entry:
+ tail call i8* @objc_retain(i8* %x)
+ br label %bb1
+
+bb1:
+ %Abb1 = alloca i8*, i32 3
+ %gepbb11 = getelementptr i8** %Abb1, i32 2
+ store i8* %x, i8** %gepbb11, align 8
+ %gepbb12 = getelementptr i8** %Abb1, i32 2
+ %ybb1 = load i8** %gepbb12
+ br label %bb3
+
+bb2:
+ %Abb2 = alloca i8*, i32 4
+ %gepbb21 = getelementptr i8** %Abb2, i32 2
+ store i8* %x, i8** %gepbb21, align 8
+ %gepbb22 = getelementptr i8** %Abb2, i32 2
+ %ybb2 = load i8** %gepbb22
+ br label %bb3
+
+bb3:
+ %A = phi i8** [ %Abb1, %bb1 ], [ %Abb2, %bb2 ]
+ %y = phi i8* [ %ybb1, %bb1 ], [ %ybb2, %bb2 ]
+ tail call i8* @objc_retain(i8* %x)
+ call void @use_alloca(i8** %A)
+ call void @objc_release(i8* %y), !clang.imprecise_release !0
+ call void @use_pointer(i8* %x)
+ call void @objc_release(i8* %x), !clang.imprecise_release !0
+ ret void
+}
+
+; Make sure in the presense of allocas, if we find a cfghazard we do not perform
+; code motion even if we are known safe. These two concepts are separate and
+; should be treated as such.
+;
+; rdar://13949644
+
+; CHECK: define void @test3a() {
+; CHECK: entry:
+; CHECK: @objc_retainAutoreleasedReturnValue
+; CHECK: @objc_retain
+; CHECK: @objc_retain
+; CHECK: @objc_retain
+; CHECK: @objc_retain
+; CHECK: arraydestroy.body:
+; CHECK: @objc_release
+; CHECK-NOT: @objc_release
+; CHECK: arraydestroy.done:
+; CHECK-NOT: @objc_release
+; CHECK: arraydestroy.body1:
+; CHECK: @objc_release
+; CHECK-NOT: @objc_release
+; CHECK: arraydestroy.done1:
+; CHECK: @objc_release
+; CHECK: ret void
+; CHECK: }
+define void @test3a() {
+entry:
+ %keys = alloca [2 x i8*], align 16
+ %objs = alloca [2 x i8*], align 16
+
+ %call1 = call i8* @returner()
+ %tmp0 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %call1)
+
+ %objs.begin = getelementptr inbounds [2 x i8*]* %objs, i64 0, i64 0
+ tail call i8* @objc_retain(i8* %call1)
+ store i8* %call1, i8** %objs.begin, align 8
+ %objs.elt = getelementptr inbounds [2 x i8*]* %objs, i64 0, i64 1
+ tail call i8* @objc_retain(i8* %call1)
+ store i8* %call1, i8** %objs.elt
+
+ %call2 = call i8* @returner1()
+ %call3 = call i8* @returner2()
+ %keys.begin = getelementptr inbounds [2 x i8*]* %keys, i64 0, i64 0
+ tail call i8* @objc_retain(i8* %call2)
+ store i8* %call2, i8** %keys.begin, align 8
+ %keys.elt = getelementptr inbounds [2 x i8*]* %keys, i64 0, i64 1
+ tail call i8* @objc_retain(i8* %call3)
+ store i8* %call3, i8** %keys.elt
+
+ %gep = getelementptr inbounds [2 x i8*]* %objs, i64 0, i64 2
+ br label %arraydestroy.body
+
+arraydestroy.body:
+ %arraydestroy.elementPast = phi i8** [ %gep, %entry ], [ %arraydestroy.element, %arraydestroy.body ]
+ %arraydestroy.element = getelementptr inbounds i8** %arraydestroy.elementPast, i64 -1
+ %destroy_tmp = load i8** %arraydestroy.element, align 8
+ call void @objc_release(i8* %destroy_tmp), !clang.imprecise_release !0
+ %objs_ptr = getelementptr inbounds [2 x i8*]* %objs, i64 0, i64 0
+ %arraydestroy.cmp = icmp eq i8** %arraydestroy.element, %objs_ptr
+ br i1 %arraydestroy.cmp, label %arraydestroy.done, label %arraydestroy.body
+
+arraydestroy.done:
+ %gep1 = getelementptr inbounds [2 x i8*]* %keys, i64 0, i64 2
+ br label %arraydestroy.body1
+
+arraydestroy.body1:
+ %arraydestroy.elementPast1 = phi i8** [ %gep1, %arraydestroy.done ], [ %arraydestroy.element1, %arraydestroy.body1 ]
+ %arraydestroy.element1 = getelementptr inbounds i8** %arraydestroy.elementPast1, i64 -1
+ %destroy_tmp1 = load i8** %arraydestroy.element1, align 8
+ call void @objc_release(i8* %destroy_tmp1), !clang.imprecise_release !0
+ %keys_ptr = getelementptr inbounds [2 x i8*]* %keys, i64 0, i64 0
+ %arraydestroy.cmp1 = icmp eq i8** %arraydestroy.element1, %keys_ptr
+ br i1 %arraydestroy.cmp1, label %arraydestroy.done1, label %arraydestroy.body1
+
+arraydestroy.done1:
+ call void @objc_release(i8* %call1), !clang.imprecise_release !0
+ ret void
+}
+
+; Make sure that even though we stop said code motion we still allow for
+; pointers to be removed if we are known safe in both directions.
+;
+; rdar://13949644
+
+; CHECK: define void @test3b() {
+; CHECK: entry:
+; CHECK: @objc_retainAutoreleasedReturnValue
+; CHECK: @objc_retain
+; CHECK: @objc_retain
+; CHECK: @objc_retain
+; CHECK: @objc_retain
+; CHECK: arraydestroy.body:
+; CHECK: @objc_release
+; CHECK-NOT: @objc_release
+; CHECK: arraydestroy.done:
+; CHECK-NOT: @objc_release
+; CHECK: arraydestroy.body1:
+; CHECK: @objc_release
+; CHECK-NOT: @objc_release
+; CHECK: arraydestroy.done1:
+; CHECK: @objc_release
+; CHECK: ret void
+; CHECK: }
+define void @test3b() {
+entry:
+ %keys = alloca [2 x i8*], align 16
+ %objs = alloca [2 x i8*], align 16
+
+ %call1 = call i8* @returner()
+ %tmp0 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %call1)
+ %tmp1 = tail call i8* @objc_retain(i8* %call1)
+
+ %objs.begin = getelementptr inbounds [2 x i8*]* %objs, i64 0, i64 0
+ tail call i8* @objc_retain(i8* %call1)
+ store i8* %call1, i8** %objs.begin, align 8
+ %objs.elt = getelementptr inbounds [2 x i8*]* %objs, i64 0, i64 1
+ tail call i8* @objc_retain(i8* %call1)
+ store i8* %call1, i8** %objs.elt
+
+ %call2 = call i8* @returner1()
+ %call3 = call i8* @returner2()
+ %keys.begin = getelementptr inbounds [2 x i8*]* %keys, i64 0, i64 0
+ tail call i8* @objc_retain(i8* %call2)
+ store i8* %call2, i8** %keys.begin, align 8
+ %keys.elt = getelementptr inbounds [2 x i8*]* %keys, i64 0, i64 1
+ tail call i8* @objc_retain(i8* %call3)
+ store i8* %call3, i8** %keys.elt
+
+ %gep = getelementptr inbounds [2 x i8*]* %objs, i64 0, i64 2
+ br label %arraydestroy.body
+
+arraydestroy.body:
+ %arraydestroy.elementPast = phi i8** [ %gep, %entry ], [ %arraydestroy.element, %arraydestroy.body ]
+ %arraydestroy.element = getelementptr inbounds i8** %arraydestroy.elementPast, i64 -1
+ %destroy_tmp = load i8** %arraydestroy.element, align 8
+ call void @objc_release(i8* %destroy_tmp), !clang.imprecise_release !0
+ %objs_ptr = getelementptr inbounds [2 x i8*]* %objs, i64 0, i64 0
+ %arraydestroy.cmp = icmp eq i8** %arraydestroy.element, %objs_ptr
+ br i1 %arraydestroy.cmp, label %arraydestroy.done, label %arraydestroy.body
+
+arraydestroy.done:
+ %gep1 = getelementptr inbounds [2 x i8*]* %keys, i64 0, i64 2
+ br label %arraydestroy.body1
+
+arraydestroy.body1:
+ %arraydestroy.elementPast1 = phi i8** [ %gep1, %arraydestroy.done ], [ %arraydestroy.element1, %arraydestroy.body1 ]
+ %arraydestroy.element1 = getelementptr inbounds i8** %arraydestroy.elementPast1, i64 -1
+ %destroy_tmp1 = load i8** %arraydestroy.element1, align 8
+ call void @objc_release(i8* %destroy_tmp1), !clang.imprecise_release !0
+ %keys_ptr = getelementptr inbounds [2 x i8*]* %keys, i64 0, i64 0
+ %arraydestroy.cmp1 = icmp eq i8** %arraydestroy.element1, %keys_ptr
+ br i1 %arraydestroy.cmp1, label %arraydestroy.done1, label %arraydestroy.body1
+
+arraydestroy.done1:
+ call void @objc_release(i8* %call1), !clang.imprecise_release !0
+ call void @objc_release(i8* %call1), !clang.imprecise_release !0
+ ret void
+}
+
!0 = metadata !{}
declare i32 @__gxx_personality_v0(...)