diff options
Diffstat (limited to 'test/Transforms/ObjCARC/basic.ll')
-rw-r--r-- | test/Transforms/ObjCARC/basic.ll | 141 |
1 files changed, 139 insertions, 2 deletions
diff --git a/test/Transforms/ObjCARC/basic.ll b/test/Transforms/ObjCARC/basic.ll index a6bbf8674b..861173b9c9 100644 --- a/test/Transforms/ObjCARC/basic.ll +++ b/test/Transforms/ObjCARC/basic.ll @@ -86,6 +86,37 @@ alt_return: ret void } +; Don't do partial elimination into two different CFG diamonds. + +; CHECK: define void @test1b( +; CHECK: entry: +; CHECK: tail call i8* @objc_retain(i8* %x) nounwind +; CHECK-NOT: @objc_ +; CHECK: if.end5: +; CHECK: tail call void @objc_release(i8* %x) nounwind, !clang.imprecise_release !0 +; CHECK-NOT: @objc_ +; CHECK: } +define void @test1b(i8* %x, i1 %p, i1 %q) { +entry: + tail call i8* @objc_retain(i8* %x) nounwind + br i1 %p, label %if.then, label %if.end + +if.then: ; preds = %entry + tail call void @callee() + br label %if.end + +if.end: ; preds = %if.then, %entry + br i1 %q, label %if.then3, label %if.end5 + +if.then3: ; preds = %if.end + tail call void @use_pointer(i8* %x) + br label %if.end5 + +if.end5: ; preds = %if.then3, %if.end + tail call void @objc_release(i8* %x) nounwind, !clang.imprecise_release !0 + ret void +} + ; Like test0 but the pointer is passed to an intervening call, ; so the optimization is not safe. @@ -353,13 +384,14 @@ entry: ; CHECK: define void @test10( ; CHECK: @objc_retain(i8* %x) +; CHECK: @callee ; CHECK: @use_pointer ; CHECK: @objc_release ; CHECK: } define void @test10(i8* %x) nounwind { entry: %0 = call i8* @objc_retain(i8* %x) nounwind - call void @use_pointer(i8* %x) + call void @callee() call void @use_pointer(i8* %x) call void @objc_release(i8* %0) nounwind ret void @@ -697,6 +729,8 @@ invoke.cont23: ; preds = %if.then12 lpad20: ; preds = %invoke.cont23, %if.then12 %tmp502 = phi double* [ undef, %invoke.cont23 ], [ %self, %if.then12 ] + %exn = landingpad {i8*, i32} personality i32 (...)* @__gxx_personality_v0 + cleanup unreachable if.end: ; preds = %invoke.cont23 @@ -768,7 +802,7 @@ entry: define void @test23b(i8* %p) { entry: %0 = call i8* @objc_retainBlock(i8* %p) nounwind - call void @use_pointer(i8* %p) + call void @callee() call void @use_pointer(i8* %p) call void @objc_release(i8* %p) nounwind ret void @@ -1569,6 +1603,107 @@ if.end: ; preds = %entry, %if.then ret void } +; When there are adjacent retain+release pairs, the first one is +; known unnecessary because the presence of the second one means that +; the first one won't be deleting the object. + +; CHECK: define void @test57( +; CHECK-NEXT: entry: +; CHECK-NEXT: call void @use_pointer(i8* %x) +; CHECK-NEXT: call void @use_pointer(i8* %x) +; CHECK-NEXT: %0 = tail call i8* @objc_retain(i8* %x) nounwind +; CHECK-NEXT: call void @use_pointer(i8* %x) +; CHECK-NEXT: call void @use_pointer(i8* %x) +; CHECK-NEXT: call void @objc_release(i8* %x) nounwind +; CHECK-NEXT: ret void +; CHECK-NEXT: } +define void @test57(i8* %x) nounwind { +entry: + call i8* @objc_retain(i8* %x) nounwind + call void @use_pointer(i8* %x) + call void @use_pointer(i8* %x) + call void @objc_release(i8* %x) nounwind + call i8* @objc_retain(i8* %x) nounwind + call void @use_pointer(i8* %x) + call void @use_pointer(i8* %x) + call void @objc_release(i8* %x) nounwind + ret void +} + +; An adjacent retain+release pair is sufficient even if it will be +; removed itself. + +; CHECK: define void @test58( +; CHECK-NEXT: entry: +; CHECK-NEXT: call void @use_pointer(i8* %x) +; CHECK-NEXT: call void @use_pointer(i8* %x) +; CHECK-NEXT: ret void +; CHECK-NEXT: } +define void @test58(i8* %x) nounwind { +entry: + call i8* @objc_retain(i8* %x) nounwind + call void @use_pointer(i8* %x) + call void @use_pointer(i8* %x) + call void @objc_release(i8* %x) nounwind + call i8* @objc_retain(i8* %x) nounwind + call void @objc_release(i8* %x) nounwind + ret void +} + +; Don't delete the second retain+release pair in an adjacent set. + +; CHECK: define void @test59( +; CHECK-NEXT: entry: +; CHECK-NEXT: %0 = tail call i8* @objc_retain(i8* %x) nounwind +; CHECK-NEXT: call void @use_pointer(i8* %x) +; CHECK-NEXT: call void @use_pointer(i8* %x) +; CHECK-NEXT: call void @objc_release(i8* %x) nounwind +; CHECK-NEXT: ret void +; CHECK-NEXT: } +define void @test59(i8* %x) nounwind { +entry: + %a = call i8* @objc_retain(i8* %x) nounwind + call void @objc_release(i8* %x) nounwind + %b = call i8* @objc_retain(i8* %x) nounwind + call void @use_pointer(i8* %x) + call void @use_pointer(i8* %x) + call void @objc_release(i8* %x) nounwind + ret void +} + +; Constant pointers to objects don't need reference counting. + +@constptr = external constant i8* +@something = external global i8* + +; CHECK: define void @test60( +; CHECK-NOT: @objc_ +; CHECK: } +define void @test60() { + %t = load i8** @constptr + %s = load i8** @something + call i8* @objc_retain(i8* %s) + call void @callee() + call void @use_pointer(i8* %t) + call void @objc_release(i8* %s) + ret void +} + +; Constant pointers to objects don't need to be considered related to other +; pointers. + +; CHECK: define void @test61( +; CHECK-NOT: @objc_ +; CHECK: } +define void @test61() { + %t = load i8** @constptr + call i8* @objc_retain(i8* %t) + call void @callee() + call void @use_pointer(i8* %t) + call void @objc_release(i8* %t) + ret void +} + declare void @bar(i32 ()*) ; A few real-world testcases. @@ -1896,3 +2031,5 @@ end: ; preds = %if.end125, %if.end1 } !0 = metadata !{} + +declare i32 @__gxx_personality_v0(...) |