summaryrefslogtreecommitdiff
path: root/test/Transforms/ObjCARC
diff options
context:
space:
mode:
Diffstat (limited to 'test/Transforms/ObjCARC')
-rw-r--r--test/Transforms/ObjCARC/allocas.ll203
1 files changed, 203 insertions, 0 deletions
diff --git a/test/Transforms/ObjCARC/allocas.ll b/test/Transforms/ObjCARC/allocas.ll
new file mode 100644
index 0000000000..eabd54deb7
--- /dev/null
+++ b/test/Transforms/ObjCARC/allocas.ll
@@ -0,0 +1,203 @@
+; RUN: opt -objc-arc -S < %s | FileCheck %s
+
+declare i8* @objc_retain(i8*)
+declare i8* @objc_retainAutoreleasedReturnValue(i8*)
+declare void @objc_release(i8*)
+declare i8* @objc_autorelease(i8*)
+declare i8* @objc_autoreleaseReturnValue(i8*)
+declare void @objc_autoreleasePoolPop(i8*)
+declare i8* @objc_autoreleasePoolPush()
+declare i8* @objc_retainBlock(i8*)
+
+declare i8* @objc_retainedObject(i8*)
+declare i8* @objc_unretainedObject(i8*)
+declare i8* @objc_unretainedPointer(i8*)
+
+declare void @use_pointer(i8*)
+declare void @callee()
+declare void @callee_fnptr(void ()*)
+declare void @invokee()
+declare i8* @returner()
+declare void @bar(i32 ()*)
+declare void @use_alloca(i8**)
+
+declare void @llvm.dbg.value(metadata, i64, metadata)
+
+declare i8* @objc_msgSend(i8*, i8*, ...)
+
+
+; In the presense 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:
+;
+; %A = alloca
+; retain(%x)
+; retain(%x) <--- Inner Retain
+; store %x, %A
+; %y = load %A
+; ... DO STUFF ...
+; release(%y)
+; release(%x) <--- Guarding Release
+;
+; rdar://13750319
+
+; CHECK: define void @test1a(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 @test1a(i8* %x) {
+entry:
+ %A = alloca i8*
+ tail call i8* @objc_retain(i8* %x)
+ tail call i8* @objc_retain(i8* %x)
+ store i8* %x, i8** %A, align 8
+ %y = load i8** %A
+ 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
+}
+
+; CHECK: define void @test1b(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 @test1b(i8* %x) {
+entry:
+ %A = alloca i8*
+ %gep = getelementptr i8** %A, i32 0
+ tail call i8* @objc_retain(i8* %x)
+ tail call i8* @objc_retain(i8* %x)
+ store i8* %x, i8** %gep, align 8
+ %y = load i8** %A
+ 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
+}
+
+
+; CHECK: define void @test1c(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 @test1c(i8* %x) {
+entry:
+ %A = alloca i8*, i32 3
+ %gep = getelementptr i8** %A, i32 2
+ tail call i8* @objc_retain(i8* %x)
+ tail call i8* @objc_retain(i8* %x)
+ store i8* %x, i8** %gep, align 8
+ %y = load i8** %gep
+ 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
+}
+
+
+; CHECK: define void @test1d(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 @test1d(i8* %x) {
+entry:
+ br i1 undef, label %use_allocaA, label %use_allocaB
+
+use_allocaA:
+ %allocaA = alloca i8*
+ br label %exit
+
+use_allocaB:
+ %allocaB = alloca i8*
+ br label %exit
+
+exit:
+ %A = phi i8** [ %allocaA, %use_allocaA ], [ %allocaB, %use_allocaB ]
+ %gep = getelementptr i8** %A, i32 0
+ tail call i8* @objc_retain(i8* %x)
+ tail call i8* @objc_retain(i8* %x)
+ store i8* %x, i8** %gep, align 8
+ %y = load i8** %gep
+ 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
+}
+
+; CHECK: define void @test1e(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 @test1e(i8* %x) {
+entry:
+ br i1 undef, label %use_allocaA, label %use_allocaB
+
+use_allocaA:
+ %allocaA = alloca i8*, i32 4
+ br label %exit
+
+use_allocaB:
+ %allocaB = alloca i8*, i32 4
+ br label %exit
+
+exit:
+ %A = phi i8** [ %allocaA, %use_allocaA ], [ %allocaB, %use_allocaB ]
+ %gep = getelementptr i8** %A, i32 2
+ tail call i8* @objc_retain(i8* %x)
+ tail call i8* @objc_retain(i8* %x)
+ store i8* %x, i8** %gep, align 8
+ %y = load i8** %gep
+ 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
+}
+
+; CHECK: define void @test1f(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 @test1f(i8* %x) {
+entry:
+ %allocaOne = alloca i8*
+ %allocaTwo = alloca i8*
+ %A = select i1 undef, i8** %allocaOne, i8** %allocaTwo
+ tail call i8* @objc_retain(i8* %x)
+ tail call i8* @objc_retain(i8* %x)
+ store i8* %x, i8** %A, align 8
+ %y = load i8** %A
+ 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
+}
+
+
+!0 = metadata !{}
+
+declare i32 @__gxx_personality_v0(...)