Move the complex address expression out of DIVariable and into an extra
[oota-llvm.git] / test / Transforms / ObjCARC / allocas.ll
index 58740d2d802fbd83951eb93cd67c7327088511e4..d2e78417046dddcae6035db919843688683a6eca 100644 (file)
@@ -18,15 +18,17 @@ 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**)
 
-declare void @llvm.dbg.value(metadata, i64, metadata)
+declare void @llvm.dbg.value(metadata, i64, metadata, metadata)
 
 declare i8* @objc_msgSend(i8*, i8*, ...)
 
 
-; In the presense of allocas, unconditionally remove retain/release pairs only
+; In the presence of allocas, unconditionally remove retain/release pairs only
 ; if they are known safe in both directions. This prevents matching up an inner
 ; retain with the boundary guarding release in the following situation:
 ; 
@@ -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 presence 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(...)