aboutsummaryrefslogtreecommitdiff
path: root/test/Transforms/ObjCARC/contract.ll
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2011-06-15 23:37:01 +0000
committerJohn McCall <rjmccall@apple.com>2011-06-15 23:37:01 +0000
commit9fbd318d36e618fb08fb53bb48b7c848e617a8a7 (patch)
tree734b59edd4958b31e22b6cbd005df15fdd8ab78b /test/Transforms/ObjCARC/contract.ll
parent5f36bb1759e35bd3aef4b6ce226e091849f6b816 (diff)
The ARC language-specific optimizer. Credit to Dan Gohman.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@133108 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/Transforms/ObjCARC/contract.ll')
-rw-r--r--test/Transforms/ObjCARC/contract.ll145
1 files changed, 145 insertions, 0 deletions
diff --git a/test/Transforms/ObjCARC/contract.ll b/test/Transforms/ObjCARC/contract.ll
new file mode 100644
index 0000000000..04ae3ca505
--- /dev/null
+++ b/test/Transforms/ObjCARC/contract.ll
@@ -0,0 +1,145 @@
+; RUN: opt -objc-arc-contract -S < %s | FileCheck %s
+
+target datalayout = "e-p:64:64:64"
+
+declare i8* @objc_retain(i8*)
+declare void @objc_release(i8*)
+declare i8* @objc_autorelease(i8*)
+declare i8* @objc_autoreleaseReturnValue(i8*)
+declare i8* @objc_retainAutoreleasedReturnValue(i8*)
+
+declare void @use_pointer(i8*)
+declare i8* @returner()
+
+; CHECK: define void @test0
+; CHECK: call void @use_pointer(i8* %0)
+; CHECK: }
+define void @test0(i8* %x) nounwind {
+entry:
+ %0 = call i8* @objc_retain(i8* %x) nounwind
+ call void @use_pointer(i8* %x)
+ ret void
+}
+
+; CHECK: define void @test1
+; CHECK: call void @use_pointer(i8* %0)
+; CHECK: }
+define void @test1(i8* %x) nounwind {
+entry:
+ %0 = call i8* @objc_autorelease(i8* %x) nounwind
+ call void @use_pointer(i8* %x)
+ ret void
+}
+
+; Merge objc_retain and objc_autorelease into objc_retainAutorelease.
+
+; CHECK: define void @test2(
+; CHECK: tail call i8* @objc_retainAutorelease(i8* %x) nounwind
+; CHECK: }
+define void @test2(i8* %x) nounwind {
+entry:
+ %0 = tail call i8* @objc_retain(i8* %x) nounwind
+ tail call i8* @objc_autorelease(i8* %0) nounwind
+ call void @use_pointer(i8* %x)
+ ret void
+}
+
+; Same as test2 but the value is returned. Do an RV optimization.
+
+; CHECK: define i8* @test2b(
+; CHECK: tail call i8* @objc_retainAutoreleaseReturnValue(i8* %x) nounwind
+; CHECK: }
+define i8* @test2b(i8* %x) nounwind {
+entry:
+ %0 = tail call i8* @objc_retain(i8* %x) nounwind
+ tail call i8* @objc_autoreleaseReturnValue(i8* %0) nounwind
+ ret i8* %x
+}
+
+; Merge a retain,autorelease pair around a call.
+
+; CHECK: define void @test3(
+; CHECK: tail call i8* @objc_retainAutorelease(i8* %x) nounwind
+; CHECK: @use_pointer(i8* %0)
+; CHECK: }
+define void @test3(i8* %x, i64 %n) {
+entry:
+ tail call i8* @objc_retain(i8* %x) nounwind
+ call void @use_pointer(i8* %x)
+ tail call i8* @objc_autorelease(i8* %x) nounwind
+ ret void
+}
+
+; Trivial retain,autorelease pair with intervening call, but it's post-dominated
+; by another release. The retain and autorelease can be merged.
+
+; CHECK: define void @test4(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: @objc_retainAutorelease(i8* %x) nounwind
+; CHECK-NEXT: @use_pointer
+; CHECK-NEXT: @objc_release
+; CHECK-NEXT: ret void
+; CHECK-NEXT: }
+define void @test4(i8* %x, i64 %n) {
+entry:
+ tail call i8* @objc_retain(i8* %x) nounwind
+ call void @use_pointer(i8* %x)
+ tail call i8* @objc_autorelease(i8* %x) nounwind
+ tail call void @objc_release(i8* %x) nounwind
+ ret void
+}
+
+; Don't merge retain and autorelease if they're not control-equivalent.
+
+; CHECK: define void @test5(
+; CHECK: tail call i8* @objc_retain(i8* %p) nounwind
+; CHECK: true:
+; CHECK: tail call i8* @objc_autorelease(i8* %0) nounwind
+; CHECK: }
+define void @test5(i8* %p, i1 %a) {
+entry:
+ tail call i8* @objc_retain(i8* %p) nounwind
+ br i1 %a, label %true, label %false
+
+true:
+ tail call i8* @objc_autorelease(i8* %p) nounwind
+ call void @use_pointer(i8* %p)
+ ret void
+
+false:
+ ret void
+}
+
+; Don't eliminate objc_retainAutoreleasedReturnValue by merging it into
+; an objc_autorelease.
+; TODO? Merge objc_retainAutoreleasedReturnValue and objc_autorelease into
+; objc_retainAutoreleasedReturnValueAutorelease and merge
+; objc_retainAutoreleasedReturnValue and objc_autoreleaseReturnValue
+; into objc_retainAutoreleasedReturnValueAutoreleaseReturnValue?
+; Those entrypoints don't exist yet though.
+
+; CHECK: define i8* @test6(
+; CHECK: call i8* @objc_retainAutoreleasedReturnValue(i8* %p) nounwind
+; CHECK: %t = tail call i8* @objc_autoreleaseReturnValue(i8* %1) nounwind
+; CHECK: }
+define i8* @test6() {
+ %p = call i8* @returner()
+ tail call i8* @objc_retainAutoreleasedReturnValue(i8* %p) nounwind
+ %t = tail call i8* @objc_autoreleaseReturnValue(i8* %p) nounwind
+ call void @use_pointer(i8* %t)
+ ret i8* %t
+}
+
+; Don't spoil the RV optimization.
+
+; CHECK: define i8* @test7(i8* %p)
+; CHECK: tail call i8* @objc_retain(i8* %p)
+; CHECK: call void @use_pointer(i8* %1)
+; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %1)
+; CHECK: ret i8* %2
+define i8* @test7(i8* %p) {
+ %1 = tail call i8* @objc_retain(i8* %p)
+ call void @use_pointer(i8* %p)
+ %2 = tail call i8* @objc_autoreleaseReturnValue(i8* %p)
+ ret i8* %p
+}