[llvm] [ObjCARC] Delete adjacent retain+release pairs (PR #218263)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Aug 23 10:13:25 PDT 2026
https://github.com/AZero13 updated https://github.com/llvm/llvm-project/pull/218263
>From 5bf7f507ee3000239cfa301b54313511a1beda62 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Sat, 22 Aug 2026 20:32:18 -0400
Subject: [PATCH 1/2] [ObjCARC] Precommit test for adjacent retain+release
peephole
---
.../test/Transforms/ObjCARC/release-retain.ll | 31 +++++++++++++++++++
1 file changed, 31 insertions(+)
create mode 100644 llvm/test/Transforms/ObjCARC/release-retain.ll
diff --git a/llvm/test/Transforms/ObjCARC/release-retain.ll b/llvm/test/Transforms/ObjCARC/release-retain.ll
new file mode 100644
index 0000000000000..0a6d1ed96000f
--- /dev/null
+++ b/llvm/test/Transforms/ObjCARC/release-retain.ll
@@ -0,0 +1,31 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -passes=objc-arc < %s | FileCheck %s
+
+declare ptr @llvm.objc.retain(ptr)
+declare void @llvm.objc.release(ptr)
+
+define void @test_retain_release(ptr %x) {
+; CHECK-LABEL: define void @test_retain_release(
+; CHECK-SAME: ptr [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: ret void
+;
+entry:
+ %0 = call ptr @llvm.objc.retain(ptr %x)
+ call void @llvm.objc.release(ptr %x)
+ ret void
+}
+
+define void @test_retain_release_different_pointers(ptr %x, ptr %y) {
+; CHECK-LABEL: define void @test_retain_release_different_pointers(
+; CHECK-SAME: ptr [[X:%.*]], ptr [[Y:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0:[0-9]+]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[Y]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
+entry:
+ %0 = call ptr @llvm.objc.retain(ptr %x)
+ call void @llvm.objc.release(ptr %y)
+ ret void
+}
>From 5398ef6eb2aa4c0125c6f2a8be1a17e13f20f1c2 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Sun, 23 Aug 2026 12:51:05 -0400
Subject: [PATCH 2/2] [ObjCARC] Delete adjacent retain+release pairs
Adds a peephole optimization to ObjCARCOpt::OptimizeIndividualCalls that catches trivial retain followed by release pairs on the same RC identity root and deletes them.
Since these balance each other perfectly and are adjacent, we can eliminate both the retain and the release without invoking the more expensive OptimizeSequences dataflow pass, removing redundant reference counting operations immediately.
This unblocks further optimizations, such as removing inner autoreleasePoolPush/Pop pairs that were previously shadowed by the redundant operations, as evidenced by updates required to existing tests.
---
llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp | 20 +
llvm/test/Transforms/ObjCARC/basic.ll | 2246 +++++++++++------
.../ObjCARC/test_autorelease_pool.ll | 4 +-
3 files changed, 1557 insertions(+), 713 deletions(-)
diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
index f92e5bbdf0111..4fb0a0b4f3078 100644
--- a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
+++ b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
@@ -848,6 +848,26 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
break;
}
+ if (Class == ARCInstKind::Release) {
+ Instruction *PrevInst = Inst->getPrevNode();
+ while (PrevInst && PrevInst->isDebugOrPseudoInst())
+ PrevInst = PrevInst->getPrevNode();
+
+ if (PrevInst && GetBasicARCInstKind(PrevInst) == ARCInstKind::Retain &&
+ GetArgRCIdentityRoot(Inst) == GetArgRCIdentityRoot(PrevInst)) {
+ LLVM_DEBUG(dbgs() << "Deleting adjacent retain and release: "
+ << *PrevInst << " and " << *Inst << "\n");
+ if (!PrevInst->use_empty())
+ PrevInst->replaceAllUsesWith(
+ cast<CallInst>(PrevInst)->getArgOperand(0));
+ EraseInstruction(Inst);
+ EraseInstruction(PrevInst);
+ Changed = true;
+ ++NumNoops;
+ continue;
+ }
+ }
+
OptimizeIndividualCallImpl(F, Inst, Class, Arg);
}
diff --git a/llvm/test/Transforms/ObjCARC/basic.ll b/llvm/test/Transforms/ObjCARC/basic.ll
index 24f2862ffe5c7..38e7d44ad9a8e 100644
--- a/llvm/test/Transforms/ObjCARC/basic.ll
+++ b/llvm/test/Transforms/ObjCARC/basic.ll
@@ -1,3 +1,4 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt -aa-pipeline=basic-aa -passes=objc-arc -S < %s | FileCheck %s
target datalayout = "e-p:64:64:64"
@@ -31,11 +32,23 @@ declare ptr @objc_msgSend(ptr, ptr, ...)
; Simple retain+release pair deletion, with some intervening control
; flow and harmless instructions.
-; CHECK: define void @test0_precise(ptr %x, i1 %p) [[NUW:#[0-9]+]] {
-; CHECK: @llvm.objc.retain
-; CHECK: @llvm.objc.release
-; CHECK: {{^}}}
define void @test0_precise(ptr %x, i1 %p) nounwind {
+; CHECK-LABEL: define void @test0_precise(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[P:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[P]], label %[[T:.*]], label %[[F:.*]]
+; CHECK: [[T]]:
+; CHECK-NEXT: store i8 3, ptr [[X]], align 1
+; CHECK-NEXT: store float 2.000000e+00, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[RETURN:.*]]
+; CHECK: [[F]]:
+; CHECK-NEXT: store i32 7, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
br i1 %p, label %t, label %f
@@ -54,10 +67,21 @@ return:
ret void
}
-; CHECK: define void @test0_imprecise(ptr %x, i1 %p) [[NUW]] {
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test0_imprecise(ptr %x, i1 %p) nounwind {
+; CHECK-LABEL: define void @test0_imprecise(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[P:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[P]], label %[[T:.*]], label %[[F:.*]]
+; CHECK: [[T]]:
+; CHECK-NEXT: store i8 3, ptr [[X]], align 1
+; CHECK-NEXT: store float 2.000000e+00, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[RETURN:.*]]
+; CHECK: [[F]]:
+; CHECK-NEXT: store i32 7, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
br i1 %p, label %t, label %f
@@ -81,11 +105,26 @@ return:
; TODO: Make the llvm.objc.release's argument be %0.
-; CHECK: define void @test1_precise(ptr %x, i1 %p, i1 %q) [[NUW]] {
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.release(ptr %x)
-; CHECK: {{^}}}
define void @test1_precise(ptr %x, i1 %p, i1 %q) nounwind {
+; CHECK-LABEL: define void @test1_precise(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[P:%.*]], i1 [[Q:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[P]], label %[[T:.*]], label %[[F:.*]]
+; CHECK: [[T]]:
+; CHECK-NEXT: store i8 3, ptr [[X]], align 1
+; CHECK-NEXT: store float 2.000000e+00, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[RETURN:.*]]
+; CHECK: [[F]]:
+; CHECK-NEXT: store i32 7, ptr [[X]], align 4
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: br i1 [[Q]], label %[[RETURN]], label %[[ALT_RETURN:.*]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+; CHECK: [[ALT_RETURN]]:
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
br i1 %p, label %t, label %f
@@ -108,11 +147,26 @@ alt_return:
ret void
}
-; CHECK: define void @test1_imprecise(ptr %x, i1 %p, i1 %q) [[NUW]] {
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.release
-; CHECK: {{^}}}
define void @test1_imprecise(ptr %x, i1 %p, i1 %q) nounwind {
+; CHECK-LABEL: define void @test1_imprecise(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[P:%.*]], i1 [[Q:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[P]], label %[[T:.*]], label %[[F:.*]]
+; CHECK: [[T]]:
+; CHECK-NEXT: store i8 3, ptr [[X]], align 1
+; CHECK-NEXT: store float 2.000000e+00, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[RETURN:.*]]
+; CHECK: [[F]]:
+; CHECK-NEXT: store i32 7, ptr [[X]], align 4
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: br i1 [[Q]], label %[[RETURN]], label %[[ALT_RETURN:.*]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META3:![0-9]+]]
+; CHECK-NEXT: ret void
+; CHECK: [[ALT_RETURN]]:
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
br i1 %p, label %t, label %f
@@ -138,15 +192,24 @@ alt_return:
; Don't do partial elimination into two different CFG diamonds.
-; CHECK: define void @test1b_precise(ptr %x, i1 %p, i1 %q) {
-; CHECK: entry:
-; CHECK: tail call ptr @llvm.objc.retain(ptr %x) [[NUW]]
-; CHECK-NOT: @llvm.objc.
-; CHECK: if.end5:
-; CHECK: tail call void @llvm.objc.release(ptr %x) [[NUW]]
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test1b_precise(ptr %x, i1 %p, i1 %q) {
+; CHECK-LABEL: define void @test1b_precise(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[P:%.*]], i1 [[Q:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[P]], label %[[IF_THEN:.*]], label %[[IF_END:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: tail call void @callee()
+; CHECK-NEXT: br label %[[IF_END]]
+; CHECK: [[IF_END]]:
+; CHECK-NEXT: br i1 [[Q]], label %[[IF_THEN3:.*]], label %[[IF_END5:.*]]
+; CHECK: [[IF_THEN3]]:
+; CHECK-NEXT: tail call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: br label %[[IF_END5]]
+; CHECK: [[IF_END5]]:
+; CHECK-NEXT: tail call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
tail call ptr @llvm.objc.retain(ptr %x) nounwind
br i1 %p, label %if.then, label %if.end
@@ -167,15 +230,24 @@ if.end5: ; preds = %if.then3, %if.end
ret void
}
-; CHECK-LABEL: define void @test1b_imprecise(
-; CHECK: entry:
-; CHECK: tail call ptr @llvm.objc.retain(ptr %x) [[NUW:#[0-9]+]]
-; CHECK-NOT: @llvm.objc.
-; CHECK: if.end5:
-; CHECK: tail call void @llvm.objc.release(ptr %x) [[NUW]], !clang.imprecise_release ![[RELEASE:[0-9]+]]
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test1b_imprecise(ptr %x, i1 %p, i1 %q) {
+; CHECK-LABEL: define void @test1b_imprecise(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[P:%.*]], i1 [[Q:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[P]], label %[[IF_THEN:.*]], label %[[IF_END:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: tail call void @callee()
+; CHECK-NEXT: br label %[[IF_END]]
+; CHECK: [[IF_END]]:
+; CHECK-NEXT: br i1 [[Q]], label %[[IF_THEN3:.*]], label %[[IF_END5:.*]]
+; CHECK: [[IF_THEN3]]:
+; CHECK-NEXT: tail call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: br label %[[IF_END5]]
+; CHECK: [[IF_END5]]:
+; CHECK-NEXT: tail call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: ret void
+;
entry:
tail call ptr @llvm.objc.retain(ptr %x) nounwind
br i1 %p, label %if.then, label %if.end
@@ -200,11 +272,25 @@ if.end5: ; preds = %if.then3, %if.end
; Like test0 but the pointer is passed to an intervening call,
; so the optimization is not safe.
-; CHECK-LABEL: define void @test2_precise(
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.release
-; CHECK: {{^}}}
define void @test2_precise(ptr %x, i1 %p) nounwind {
+; CHECK-LABEL: define void @test2_precise(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[P:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[P]], label %[[T:.*]], label %[[F:.*]]
+; CHECK: [[T]]:
+; CHECK-NEXT: store i8 3, ptr [[X]], align 1
+; CHECK-NEXT: store float 2.000000e+00, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[RETURN:.*]]
+; CHECK: [[F]]:
+; CHECK-NEXT: store i32 7, ptr [[X]], align 4
+; CHECK-NEXT: call void @use_pointer(ptr [[TMP0]])
+; CHECK-NEXT: store float 3.000000e+00, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
br i1 %p, label %t, label %f
@@ -225,11 +311,25 @@ return:
ret void
}
-; CHECK-LABEL: define void @test2_imprecise(
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.release
-; CHECK: {{^}}}
define void @test2_imprecise(ptr %x, i1 %p) nounwind {
+; CHECK-LABEL: define void @test2_imprecise(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[P:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[P]], label %[[T:.*]], label %[[F:.*]]
+; CHECK: [[T]]:
+; CHECK-NEXT: store i8 3, ptr [[X]], align 1
+; CHECK-NEXT: store float 2.000000e+00, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[RETURN:.*]]
+; CHECK: [[F]]:
+; CHECK-NEXT: store i32 7, ptr [[X]], align 4
+; CHECK-NEXT: call void @use_pointer(ptr [[TMP0]])
+; CHECK-NEXT: store float 3.000000e+00, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
br i1 %p, label %t, label %f
@@ -255,11 +355,20 @@ return:
; TODO: For now, assume this can't happen.
-; CHECK-LABEL: define void @test3_precise(
; TODO: @llvm.objc.retain(ptr %a)
; TODO: @llvm.objc.release
; CHECK: {{^}}}
define void @test3_precise(ptr %x, ptr %q) nounwind {
+; CHECK-LABEL: define void @test3_precise(
+; CHECK-SAME: ptr [[X:%.*]], ptr [[Q:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: [[J:%.*]] = load volatile i1, ptr [[Q]], align 1
+; CHECK-NEXT: br i1 [[J]], label %[[LOOP]], label %[[RETURN:.*]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
br label %loop
@@ -273,11 +382,20 @@ return:
ret void
}
-; CHECK-LABEL: define void @test3_imprecise(
; TODO: @llvm.objc.retain(ptr %a)
; TODO: @llvm.objc.release
; CHECK: {{^}}}
define void @test3_imprecise(ptr %x, ptr %q) nounwind {
+; CHECK-LABEL: define void @test3_imprecise(
+; CHECK-SAME: ptr [[X:%.*]], ptr [[Q:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: [[J:%.*]] = load volatile i1, ptr [[Q]], align 1
+; CHECK-NEXT: br i1 [[J]], label %[[LOOP]], label %[[RETURN:.*]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
br label %loop
@@ -297,11 +415,22 @@ return:
; Like test0 but the retain is in a loop,
; so the optimization is not safe.
-; CHECK-LABEL: define void @test4_precise(
; TODO: @llvm.objc.retain(ptr %a)
; TODO: @llvm.objc.release
; CHECK: {{^}}}
define void @test4_precise(ptr %x, ptr %q) nounwind {
+; CHECK-LABEL: define void @test4_precise(
+; CHECK-SAME: ptr [[X:%.*]], ptr [[Q:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: [[J:%.*]] = load volatile i1, ptr [[Q]], align 1
+; CHECK-NEXT: br i1 [[J]], label %[[LOOP]], label %[[RETURN:.*]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
br label %loop
@@ -315,11 +444,22 @@ return:
ret void
}
-; CHECK-LABEL: define void @test4_imprecise(
; TODO: @llvm.objc.retain(ptr %a)
; TODO: @llvm.objc.release
; CHECK: {{^}}}
define void @test4_imprecise(ptr %x, ptr %q) nounwind {
+; CHECK-LABEL: define void @test4_imprecise(
+; CHECK-SAME: ptr [[X:%.*]], ptr [[Q:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: [[J:%.*]] = load volatile i1, ptr [[Q]], align 1
+; CHECK-NEXT: br i1 [[J]], label %[[LOOP]], label %[[RETURN:.*]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: ret void
+;
entry:
br label %loop
@@ -337,11 +477,17 @@ return:
; Like test0 but the pointer is conditionally passed to an intervening call,
; so the optimization is not safe.
-; CHECK-LABEL: define void @test5a(
-; CHECK: @llvm.objc.retain(ptr
-; CHECK: @llvm.objc.release
-; CHECK: {{^}}}
define void @test5a(ptr %x, i1 %q, ptr %y) nounwind {
+; CHECK-LABEL: define void @test5a(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[Q:%.*]], ptr [[Y:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[S:%.*]] = select i1 [[Q]], ptr [[Y]], ptr [[X]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[S]])
+; CHECK-NEXT: store i32 7, ptr [[X]], align 4
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
%s = select i1 %q, ptr %y, ptr %0
@@ -351,11 +497,17 @@ entry:
ret void
}
-; CHECK-LABEL: define void @test5b(
-; CHECK: @llvm.objc.retain(ptr
-; CHECK: @llvm.objc.release
-; CHECK: {{^}}}
define void @test5b(ptr %x, i1 %q, ptr %y) nounwind {
+; CHECK-LABEL: define void @test5b(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[Q:%.*]], ptr [[Y:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[S:%.*]] = select i1 [[Q]], ptr [[Y]], ptr [[X]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[S]])
+; CHECK-NEXT: store i32 7, ptr [[X]], align 4
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
%s = select i1 %q, ptr %y, ptr %0
@@ -369,16 +521,25 @@ entry:
; retain+release pair deletion, where the release happens on two different
; flow paths.
-; CHECK-LABEL: define void @test6a(
-; CHECK: entry:
-; CHECK: tail call ptr @llvm.objc.retain
-; CHECK: t:
-; CHECK: call void @llvm.objc.release
-; CHECK: f:
-; CHECK: call void @llvm.objc.release
-; CHECK: return:
-; CHECK: {{^}}}
define void @test6a(ptr %x, i1 %p) nounwind {
+; CHECK-LABEL: define void @test6a(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[P:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[P]], label %[[T:.*]], label %[[F:.*]]
+; CHECK: [[T]]:
+; CHECK-NEXT: store i8 3, ptr [[X]], align 1
+; CHECK-NEXT: store float 2.000000e+00, ptr [[X]], align 4
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br label %[[RETURN:.*]]
+; CHECK: [[F]]:
+; CHECK-NEXT: store i32 7, ptr [[X]], align 4
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
br i1 %p, label %t, label %f
@@ -399,10 +560,22 @@ return:
ret void
}
-; CHECK-LABEL: define void @test6b(
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test6b(ptr %x, i1 %p) nounwind {
+; CHECK-LABEL: define void @test6b(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[P:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[P]], label %[[T:.*]], label %[[F:.*]]
+; CHECK: [[T]]:
+; CHECK-NEXT: store i8 3, ptr [[X]], align 1
+; CHECK-NEXT: store float 2.000000e+00, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[RETURN:.*]]
+; CHECK: [[F]]:
+; CHECK-NEXT: store i32 7, ptr [[X]], align 4
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
br i1 %p, label %t, label %f
@@ -423,16 +596,25 @@ return:
ret void
}
-; CHECK-LABEL: define void @test6c(
-; CHECK: entry:
-; CHECK: tail call ptr @llvm.objc.retain
-; CHECK: t:
-; CHECK: call void @llvm.objc.release
-; CHECK: f:
-; CHECK: call void @llvm.objc.release
-; CHECK: return:
-; CHECK: {{^}}}
define void @test6c(ptr %x, i1 %p) nounwind {
+; CHECK-LABEL: define void @test6c(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[P:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[P]], label %[[T:.*]], label %[[F:.*]]
+; CHECK: [[T]]:
+; CHECK-NEXT: store i8 3, ptr [[X]], align 1
+; CHECK-NEXT: store float 2.000000e+00, ptr [[X]], align 4
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br label %[[RETURN:.*]]
+; CHECK: [[F]]:
+; CHECK-NEXT: store i32 7, ptr [[X]], align 4
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
br i1 %p, label %t, label %f
@@ -453,16 +635,25 @@ return:
ret void
}
-; CHECK-LABEL: define void @test6d(
-; CHECK: entry:
-; CHECK: tail call ptr @llvm.objc.retain
-; CHECK: t:
-; CHECK: call void @llvm.objc.release
-; CHECK: f:
-; CHECK: call void @llvm.objc.release
-; CHECK: return:
-; CHECK: {{^}}}
define void @test6d(ptr %x, i1 %p) nounwind {
+; CHECK-LABEL: define void @test6d(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[P:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[P]], label %[[T:.*]], label %[[F:.*]]
+; CHECK: [[T]]:
+; CHECK-NEXT: store i8 3, ptr [[X]], align 1
+; CHECK-NEXT: store float 2.000000e+00, ptr [[X]], align 4
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: br label %[[RETURN:.*]]
+; CHECK: [[F]]:
+; CHECK-NEXT: store i32 7, ptr [[X]], align 4
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
br i1 %p, label %t, label %f
@@ -487,17 +678,25 @@ return:
; retain+release pair deletion, where the retain happens on two different
; flow paths.
-; CHECK-LABEL: define void @test7(
-; CHECK: entry:
-; CHECK-NOT: llvm.objc.
-; CHECK: t:
-; CHECK: call ptr @llvm.objc.retain
-; CHECK: f:
-; CHECK: call ptr @llvm.objc.retain
-; CHECK: return:
-; CHECK: call void @llvm.objc.release
-; CHECK: {{^}}}
define void @test7(ptr %x, i1 %p) nounwind {
+; CHECK-LABEL: define void @test7(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[P:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[P]], label %[[T:.*]], label %[[F:.*]]
+; CHECK: [[T]]:
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: store i8 3, ptr [[X]], align 1
+; CHECK-NEXT: store float 2.000000e+00, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[RETURN:.*]]
+; CHECK: [[F]]:
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: store i32 7, ptr [[X]], align 4
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
br i1 %p, label %t, label %f
@@ -518,10 +717,22 @@ return:
ret void
}
-; CHECK-LABEL: define void @test7b(
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test7b(ptr %x, i1 %p) nounwind {
+; CHECK-LABEL: define void @test7b(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[P:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[P]], label %[[T:.*]], label %[[F:.*]]
+; CHECK: [[T]]:
+; CHECK-NEXT: store i8 3, ptr [[X]], align 1
+; CHECK-NEXT: store float 2.000000e+00, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[RETURN:.*]]
+; CHECK: [[F]]:
+; CHECK-NEXT: store i32 7, ptr [[X]], align 4
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: ret void
+;
entry:
br i1 %p, label %t, label %f
@@ -544,15 +755,25 @@ return:
; Like test7, but there's a retain/retainBlock mismatch. Don't delete!
-; CHECK-LABEL: define void @test7c(
-; CHECK: t:
-; CHECK: call ptr @llvm.objc.retainBlock
-; CHECK: f:
-; CHECK: call ptr @llvm.objc.retain
-; CHECK: return:
-; CHECK: call void @llvm.objc.release
-; CHECK: {{^}}}
define void @test7c(ptr %x, i1 %p) nounwind {
+; CHECK-LABEL: define void @test7c(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[P:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[P]], label %[[T:.*]], label %[[F:.*]]
+; CHECK: [[T]]:
+; CHECK-NEXT: [[TMP0:%.*]] = call ptr @llvm.objc.retainBlock(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: store i8 3, ptr [[X]], align 1
+; CHECK-NEXT: store float 2.000000e+00, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[RETURN:.*]]
+; CHECK: [[F]]:
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: store i32 7, ptr [[X]], align 4
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
br i1 %p, label %t, label %f
@@ -576,20 +797,32 @@ return:
; retain+release pair deletion, where the retain and release both happen on
; different flow paths. Wild!
-; CHECK-LABEL: define void @test8a(
-; CHECK: entry:
-; CHECK: t:
-; CHECK: @llvm.objc.retain
-; CHECK: f:
-; CHECK: @llvm.objc.retain
-; CHECK: mid:
-; CHECK: u:
-; CHECK: @llvm.objc.release
-; CHECK: g:
-; CHECK: @llvm.objc.release
-; CHECK: return:
-; CHECK: {{^}}}
define void @test8a(ptr %x, i1 %p, i1 %q) nounwind {
+; CHECK-LABEL: define void @test8a(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[P:%.*]], i1 [[Q:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[P]], label %[[T:.*]], label %[[F:.*]]
+; CHECK: [[T]]:
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: store i8 3, ptr [[X]], align 1
+; CHECK-NEXT: store float 2.000000e+00, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[MID:.*]]
+; CHECK: [[F]]:
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: store i32 7, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[MID]]
+; CHECK: [[MID]]:
+; CHECK-NEXT: br i1 [[Q]], label %[[U:.*]], label %[[G:.*]]
+; CHECK: [[U]]:
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br label %[[RETURN:.*]]
+; CHECK: [[G]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: ret void
+;
entry:
br i1 %p, label %t, label %f
@@ -620,10 +853,28 @@ return:
ret void
}
-; CHECK-LABEL: define void @test8b(
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test8b(ptr %x, i1 %p, i1 %q) nounwind {
+; CHECK-LABEL: define void @test8b(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[P:%.*]], i1 [[Q:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[P]], label %[[T:.*]], label %[[F:.*]]
+; CHECK: [[T]]:
+; CHECK-NEXT: store i8 3, ptr [[X]], align 1
+; CHECK-NEXT: store float 2.000000e+00, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[MID:.*]]
+; CHECK: [[F]]:
+; CHECK-NEXT: store i32 7, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[MID]]
+; CHECK: [[MID]]:
+; CHECK-NEXT: br i1 [[Q]], label %[[U:.*]], label %[[G:.*]]
+; CHECK: [[U]]:
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: br label %[[RETURN:.*]]
+; CHECK: [[G]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: ret void
+;
entry:
br i1 %p, label %t, label %f
@@ -654,21 +905,30 @@ return:
ret void
}
-; CHECK-LABEL: define void @test8c(
-; CHECK: entry:
-; CHECK: t:
-; CHECK-NOT: @llvm.objc.
-; CHECK: f:
-; CHECK-NOT: @llvm.objc.
-; CHECK: mid:
-; CHECK: u:
-; CHECK: @llvm.objc.retain
-; CHECK: @llvm.objc.release
-; CHECK: g:
-; CHECK-NOT: @llvm.objc.
-; CHECK: return:
-; CHECK: {{^}}}
define void @test8c(ptr %x, i1 %p, i1 %q) nounwind {
+; CHECK-LABEL: define void @test8c(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[P:%.*]], i1 [[Q:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[P]], label %[[T:.*]], label %[[F:.*]]
+; CHECK: [[T]]:
+; CHECK-NEXT: store i8 3, ptr [[X]], align 1
+; CHECK-NEXT: store float 2.000000e+00, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[MID:.*]]
+; CHECK: [[F]]:
+; CHECK-NEXT: store i32 7, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[MID]]
+; CHECK: [[MID]]:
+; CHECK-NEXT: br i1 [[Q]], label %[[U:.*]], label %[[G:.*]]
+; CHECK: [[U]]:
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br label %[[RETURN:.*]]
+; CHECK: [[G]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: ret void
+;
entry:
br i1 %p, label %t, label %f
@@ -699,20 +959,32 @@ return:
ret void
}
-; CHECK-LABEL: define void @test8d(
-; CHECK: entry:
-; CHECK: t:
-; CHECK: @llvm.objc.retain
-; CHECK: f:
-; CHECK: @llvm.objc.retain
-; CHECK: mid:
-; CHECK: u:
-; CHECK: @llvm.objc.release
-; CHECK: g:
-; CHECK: @llvm.objc.release
-; CHECK: return:
-; CHECK: {{^}}}
define void @test8d(ptr %x, i1 %p, i1 %q) nounwind {
+; CHECK-LABEL: define void @test8d(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[P:%.*]], i1 [[Q:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[P]], label %[[T:.*]], label %[[F:.*]]
+; CHECK: [[T]]:
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: store i8 3, ptr [[X]], align 1
+; CHECK-NEXT: store float 2.000000e+00, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[MID:.*]]
+; CHECK: [[F]]:
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: store i32 7, ptr [[X]], align 4
+; CHECK-NEXT: br label %[[MID]]
+; CHECK: [[MID]]:
+; CHECK-NEXT: br i1 [[Q]], label %[[U:.*]], label %[[G:.*]]
+; CHECK: [[U]]:
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: br label %[[RETURN:.*]]
+; CHECK: [[G]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: ret void
+;
entry:
br i1 %p, label %t, label %f
@@ -745,10 +1017,12 @@ return:
; Trivial retain+release pair deletion.
-; CHECK-LABEL: define void @test9(
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test9(ptr %x) nounwind {
+; CHECK-LABEL: define void @test9(
+; CHECK-SAME: ptr [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
call void @llvm.objc.release(ptr %0) nounwind
@@ -757,11 +1031,15 @@ entry:
; Retain+release pair, but on an unknown pointer relationship. Don't delete!
-; CHECK-LABEL: define void @test9b(
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.release(ptr %s)
-; CHECK: {{^}}}
define void @test9b(ptr %x, i1 %j, ptr %p) nounwind {
+; CHECK-LABEL: define void @test9b(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[J:%.*]], ptr [[P:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: [[S:%.*]] = select i1 [[J]], ptr [[X]], ptr [[P]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[S]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
%s = select i1 %j, ptr %x, ptr %p
@@ -771,13 +1049,16 @@ entry:
; Trivial retain+release pair with intervening calls - don't delete!
-; CHECK-LABEL: define void @test10(
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @callee
-; CHECK: @use_pointer
-; CHECK: @llvm.objc.release
-; CHECK: {{^}}}
define void @test10(ptr %x) nounwind {
+; CHECK-LABEL: define void @test10(
+; CHECK-SAME: ptr [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
call void @callee()
@@ -790,11 +1071,15 @@ entry:
; Also, add a tail keyword, since llvm.objc.retain can never be passed
; a stack argument.
-; CHECK-LABEL: define void @test11(
-; CHECK: tail call ptr @llvm.objc.retain(ptr %x) [[NUW]]
-; CHECK: call ptr @llvm.objc.autorelease(ptr %0) [[NUW]]
-; CHECK: {{^}}}
define void @test11(ptr %x) nounwind {
+; CHECK-LABEL: define void @test11(
+; CHECK-SAME: ptr [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.objc.autorelease(ptr [[TMP0]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
call ptr @llvm.objc.autorelease(ptr %0) nounwind
@@ -804,11 +1089,12 @@ entry:
; Same as test11 but with no use_pointer call. Delete the pair!
-; CHECK-LABEL: define void @test11a(
-; CHECK: entry:
-; CHECK-NEXT: ret void
-; CHECK: {{^}}}
define void @test11a(ptr %x) nounwind {
+; CHECK-LABEL: define void @test11a(
+; CHECK-SAME: ptr [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
call ptr @llvm.objc.autorelease(ptr %0) nounwind
@@ -819,11 +1105,14 @@ entry:
; since if the frontend emitted code for an __autoreleasing variable, we may
; want it to be in the autorelease pool.
-; CHECK-LABEL: define ptr @test11b(
-; CHECK: tail call ptr @llvm.objc.retain(ptr %x) [[NUW]]
-; CHECK: call ptr @llvm.objc.autorelease(ptr %0) [[NUW]]
-; CHECK: {{^}}}
define ptr @test11b(ptr %x) nounwind {
+; CHECK-LABEL: define ptr @test11b(
+; CHECK-SAME: ptr [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.objc.autorelease(ptr [[TMP0]]) #[[ATTR0]]
+; CHECK-NEXT: ret ptr [[X]]
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
call ptr @llvm.objc.autorelease(ptr %0) nounwind
@@ -833,13 +1122,17 @@ entry:
; We can not delete this retain, release since we do not have a post-dominating
; use of the release.
-; CHECK-LABEL: define void @test12(
-; CHECK-NEXT: entry:
-; CHECK-NEXT: @llvm.objc.retain(ptr %x)
-; CHECK-NEXT: @llvm.objc.retain
-; CHECK: @llvm.objc.release
-; CHECK: {{^}}}
define void @test12(ptr %x, i64 %n) {
+; CHECK-LABEL: define void @test12(
+; CHECK-SAME: ptr [[X:%.*]], i64 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %x) nounwind
call ptr @llvm.objc.retain(ptr %x) nounwind
@@ -851,13 +1144,16 @@ entry:
; Trivial retain,autorelease pair. Don't delete!
-; CHECK-LABEL: define void @test13(
-; CHECK: tail call ptr @llvm.objc.retain(ptr %x) [[NUW]]
-; CHECK: tail call ptr @llvm.objc.retain(ptr %x) [[NUW]]
-; CHECK: @use_pointer(ptr %x)
-; CHECK: call ptr @llvm.objc.autorelease(ptr %x) [[NUW]]
-; CHECK: {{^}}}
define void @test13(ptr %x, i64 %n) {
+; CHECK-LABEL: define void @test13(
+; CHECK-SAME: ptr [[X:%.*]], i64 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: [[TMP2:%.*]] = call ptr @llvm.objc.autorelease(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %x) nounwind
call ptr @llvm.objc.retain(ptr %x) nounwind
@@ -868,16 +1164,17 @@ entry:
; Delete the retain+release pair.
-; CHECK-LABEL: define void @test13b(
-; CHECK-NEXT: entry:
-; CHECK-NEXT: @llvm.objc.retain(ptr %x)
-; CHECK-NEXT: @use_pointer
-; CHECK-NEXT: @use_pointer
-; CHECK-NEXT: @use_pointer
-; CHECK-NEXT: @llvm.objc.release
-; CHECK-NEXT: ret void
-; CHECK-NEXT: }
define void @test13b(ptr %x, i64 %n) {
+; CHECK-LABEL: define void @test13b(
+; CHECK-SAME: ptr [[X:%.*]], i64 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %x) nounwind
call ptr @llvm.objc.retain(ptr %x) nounwind
@@ -892,17 +1189,21 @@ entry:
; Don't delete the retain+release pair because there's an
; autoreleasePoolPop in the way.
-; CHECK-LABEL: define void @test13c(
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.autoreleasePoolPop
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @use_pointer
-; CHECK: @llvm.objc.release
-; CHECK: {{^}}}
define void @test13c(ptr %x, i64 %n) {
+; CHECK-LABEL: define void @test13c(
+; CHECK-SAME: ptr [[X:%.*]], i64 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.objc.autoreleasePoolPop(ptr poison) #[[ATTR0]]
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %x) nounwind
- call void @llvm.objc.autoreleasePoolPop(ptr undef)
+ call void @llvm.objc.autoreleasePoolPop(ptr poison)
call ptr @llvm.objc.retain(ptr %x) nounwind
call void @use_pointer(ptr %x)
call void @use_pointer(ptr %x)
@@ -913,17 +1214,18 @@ entry:
; Like test13c, but there's an autoreleasePoolPush in the way, but that
; doesn't matter.
-; CHECK-LABEL: define void @test13d(
-; CHECK-NEXT: entry:
-; CHECK-NEXT: @llvm.objc.retain(ptr %x)
-; CHECK-NEXT: @llvm.objc.autoreleasePoolPush
-; CHECK-NEXT: @use_pointer
-; CHECK-NEXT: @use_pointer
-; CHECK-NEXT: @use_pointer
-; CHECK-NEXT: @llvm.objc.release
-; CHECK-NEXT: ret void
-; CHECK-NEXT: }
define void @test13d(ptr %x, i64 %n) {
+; CHECK-LABEL: define void @test13d(
+; CHECK-SAME: ptr [[X:%.*]], i64 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.objc.autoreleasePoolPush() #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %x) nounwind
call ptr @llvm.objc.autoreleasePoolPush()
@@ -940,16 +1242,17 @@ entry:
; another release. But it is not known safe in the top down direction. We can
; not eliminate it.
-; CHECK-LABEL: define void @test14(
-; CHECK-NEXT: entry:
-; CHECK-NEXT: @llvm.objc.retain
-; CHECK-NEXT: @use_pointer
-; CHECK-NEXT: @use_pointer
-; CHECK-NEXT: @llvm.objc.release
-; CHECK-NEXT: @llvm.objc.release
-; CHECK-NEXT: ret void
-; CHECK-NEXT: }
define void @test14(ptr %x, i64 %n) {
+; CHECK-LABEL: define void @test14(
+; CHECK-SAME: ptr [[X:%.*]], i64 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %x) nounwind
call void @use_pointer(ptr %x)
@@ -962,15 +1265,16 @@ entry:
; Trivial retain,autorelease pair with intervening call, but it's post-dominated
; by another release. Don't delete anything.
-; CHECK-LABEL: define void @test15(
-; CHECK-NEXT: entry:
-; CHECK-NEXT: @llvm.objc.retain(ptr %x)
-; CHECK-NEXT: @use_pointer
-; CHECK-NEXT: @llvm.objc.autorelease(ptr %x)
-; CHECK-NEXT: @llvm.objc.release
-; CHECK-NEXT: ret void
-; CHECK-NEXT: }
define void @test15(ptr %x, i64 %n) {
+; CHECK-LABEL: define void @test15(
+; CHECK-SAME: ptr [[X:%.*]], i64 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.objc.autorelease(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %x) nounwind
call void @use_pointer(ptr %x)
@@ -982,14 +1286,15 @@ entry:
; Trivial retain,autorelease pair, post-dominated
; by another release. Delete the retain and release.
-; CHECK-LABEL: define void @test15b(
-; CHECK-NEXT: entry:
-; CHECK-NEXT: @llvm.objc.retain
-; CHECK-NEXT: @llvm.objc.autorelease
-; CHECK-NEXT: @llvm.objc.release
-; CHECK-NEXT: ret void
-; CHECK-NEXT: }
define void @test15b(ptr %x, i64 %n) {
+; CHECK-LABEL: define void @test15b(
+; CHECK-SAME: ptr [[X:%.*]], i64 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.objc.autorelease(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %x) nounwind
call ptr @llvm.objc.autorelease(ptr %x) nounwind
@@ -997,12 +1302,13 @@ entry:
ret void
}
-; CHECK-LABEL: define void @test15c(
-; CHECK-NEXT: entry:
-; CHECK-NEXT: @llvm.objc.autorelease
-; CHECK-NEXT: ret void
-; CHECK-NEXT: }
define void @test15c(ptr %x, i64 %n) {
+; CHECK-LABEL: define void @test15c(
+; CHECK-SAME: ptr [[X:%.*]], i64 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = call ptr @llvm.objc.autorelease(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %x) nounwind
call ptr @llvm.objc.autorelease(ptr %x) nounwind
@@ -1012,14 +1318,29 @@ entry:
; Retain+release pairs in diamonds, all dominated by a retain.
-; CHECK-LABEL: define void @test16a(
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK-NOT: @objc
-; CHECK: purple:
-; CHECK: @use_pointer
-; CHECK: @llvm.objc.release
-; CHECK: {{^}}}
define void @test16a(i1 %a, i1 %b, ptr %x) {
+; CHECK-LABEL: define void @test16a(
+; CHECK-SAME: i1 [[A:%.*]], i1 [[B:%.*]], ptr [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[A]], label %[[RED:.*]], label %[[ORANGE:.*]]
+; CHECK: [[RED]]:
+; CHECK-NEXT: br label %[[YELLOW:.*]]
+; CHECK: [[ORANGE]]:
+; CHECK-NEXT: br label %[[YELLOW]]
+; CHECK: [[YELLOW]]:
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: br i1 [[B]], label %[[GREEN:.*]], label %[[BLUE:.*]]
+; CHECK: [[GREEN]]:
+; CHECK-NEXT: br label %[[PURPLE:.*]]
+; CHECK: [[BLUE]]:
+; CHECK-NEXT: br label %[[PURPLE]]
+; CHECK: [[PURPLE]]:
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %x) nounwind
br i1 %a, label %red, label %orange
@@ -1051,15 +1372,30 @@ purple:
ret void
}
-; CHECK-LABEL: define void @test16b(
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK-NOT: @objc
-; CHECK: purple:
-; CHECK-NEXT: @use_pointer
-; CHECK-NEXT: @use_pointer
-; CHECK-NEXT: @llvm.objc.release
-; CHECK: {{^}}}
define void @test16b(i1 %a, i1 %b, ptr %x) {
+; CHECK-LABEL: define void @test16b(
+; CHECK-SAME: i1 [[A:%.*]], i1 [[B:%.*]], ptr [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[A]], label %[[RED:.*]], label %[[ORANGE:.*]]
+; CHECK: [[RED]]:
+; CHECK-NEXT: br label %[[YELLOW:.*]]
+; CHECK: [[ORANGE]]:
+; CHECK-NEXT: br label %[[YELLOW]]
+; CHECK: [[YELLOW]]:
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: br i1 [[B]], label %[[GREEN:.*]], label %[[BLUE:.*]]
+; CHECK: [[GREEN]]:
+; CHECK-NEXT: br label %[[PURPLE:.*]]
+; CHECK: [[BLUE]]:
+; CHECK-NEXT: br label %[[PURPLE]]
+; CHECK: [[PURPLE]]:
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %x) nounwind
br i1 %a, label %red, label %orange
@@ -1092,14 +1428,29 @@ purple:
ret void
}
-; CHECK-LABEL: define void @test16c(
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK-NOT: @objc
-; CHECK: purple:
-; CHECK: @use_pointer
-; CHECK: @llvm.objc.release
-; CHECK: {{^}}}
define void @test16c(i1 %a, i1 %b, ptr %x) {
+; CHECK-LABEL: define void @test16c(
+; CHECK-SAME: i1 [[A:%.*]], i1 [[B:%.*]], ptr [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[A]], label %[[RED:.*]], label %[[ORANGE:.*]]
+; CHECK: [[RED]]:
+; CHECK-NEXT: br label %[[YELLOW:.*]]
+; CHECK: [[ORANGE]]:
+; CHECK-NEXT: br label %[[YELLOW]]
+; CHECK: [[YELLOW]]:
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: br i1 [[B]], label %[[GREEN:.*]], label %[[BLUE:.*]]
+; CHECK: [[GREEN]]:
+; CHECK-NEXT: br label %[[PURPLE:.*]]
+; CHECK: [[BLUE]]:
+; CHECK-NEXT: br label %[[PURPLE]]
+; CHECK: [[PURPLE]]:
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %x) nounwind
br i1 %a, label %red, label %orange
@@ -1131,11 +1482,31 @@ purple:
ret void
}
-; CHECK-LABEL: define void @test16d(
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc
-; CHECK: {{^}}}
define void @test16d(i1 %a, i1 %b, ptr %x) {
+; CHECK-LABEL: define void @test16d(
+; CHECK-SAME: i1 [[A:%.*]], i1 [[B:%.*]], ptr [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[A]], label %[[RED:.*]], label %[[ORANGE:.*]]
+; CHECK: [[RED]]:
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br label %[[YELLOW:.*]]
+; CHECK: [[ORANGE]]:
+; CHECK-NEXT: [[TMP2:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br label %[[YELLOW]]
+; CHECK: [[YELLOW]]:
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: br i1 [[B]], label %[[GREEN:.*]], label %[[BLUE:.*]]
+; CHECK: [[GREEN]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br label %[[PURPLE:.*]]
+; CHECK: [[BLUE]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: br label %[[PURPLE]]
+; CHECK: [[PURPLE]]:
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %x) nounwind
br i1 %a, label %red, label %orange
@@ -1167,10 +1538,10 @@ purple:
; Delete no-ops.
-; CHECK-LABEL: define void @test18(
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test18() {
+; CHECK-LABEL: define void @test18() {
+; CHECK-NEXT: ret void
+;
call ptr @llvm.objc.retain(ptr null)
call void @llvm.objc.release(ptr null)
call ptr @llvm.objc.autorelease(ptr null)
@@ -1179,27 +1550,29 @@ define void @test18() {
; Delete no-ops where undef can be assumed to be null.
-; CHECK-LABEL: define void @test18b(
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test18b() {
- call ptr @llvm.objc.retain(ptr undef)
- call void @llvm.objc.release(ptr undef)
- call ptr @llvm.objc.autorelease(ptr undef)
+; CHECK-LABEL: define void @test18b() {
+; CHECK-NEXT: ret void
+;
+ call ptr @llvm.objc.retain(ptr poison)
+ call void @llvm.objc.release(ptr poison)
+ call ptr @llvm.objc.autorelease(ptr poison)
ret void
}
; Replace uses of arguments with uses of return values, to reduce
; register pressure.
-; CHECK: define void @test19(ptr %y) {
-; CHECK: %0 = tail call ptr @llvm.objc.retain(ptr %y)
-; CHECK: call void @use_pointer(ptr %y)
-; CHECK: call void @use_pointer(ptr %y)
-; CHECK: call void @llvm.objc.release(ptr %y)
-; CHECK: ret void
-; CHECK: {{^}}}
define void @test19(ptr %y) {
+; CHECK-LABEL: define void @test19(
+; CHECK-SAME: ptr [[Y:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[Y]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[Y]])
+; CHECK-NEXT: call void @use_pointer(ptr [[Y]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[Y]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %y) nounwind
call void @use_pointer(ptr %y)
@@ -1210,24 +1583,37 @@ entry:
; Bitcast insertion
-; CHECK-LABEL: define void @test20(
-; CHECK: %tmp1 = tail call ptr @llvm.objc.retain(ptr %self) [[NUW]]
-; CHECK-NEXT: invoke
-; CHECK: {{^}}}
define void @test20(ptr %self) personality ptr @__gxx_personality_v0 {
+; CHECK-LABEL: define void @test20(
+; CHECK-SAME: ptr [[SELF:%.*]]) personality ptr @__gxx_personality_v0 {
+; CHECK-NEXT: [[IF_THEN12:.*]]:
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[SELF]]) #[[ATTR0]]
+; CHECK-NEXT: invoke void @invokee()
+; CHECK-NEXT: to label %[[INVOKE_CONT23:.*]] unwind label %[[LPAD20:.*]]
+; CHECK: [[INVOKE_CONT23]]:
+; CHECK-NEXT: invoke void @invokee()
+; CHECK-NEXT: to label %[[IF_END:.*]] unwind label %[[LPAD20]]
+; CHECK: [[LPAD20]]:
+; CHECK-NEXT: [[TMP502:%.*]] = phi ptr [ undef, %[[INVOKE_CONT23]] ], [ [[SELF]], %[[IF_THEN12]] ]
+; CHECK-NEXT: [[EXN:%.*]] = landingpad { ptr, i32 }
+; CHECK-NEXT: cleanup
+; CHECK-NEXT: unreachable
+; CHECK: [[IF_END]]:
+; CHECK-NEXT: ret void
+;
if.then12:
%tmp1 = call ptr @llvm.objc.retain(ptr %self) nounwind
invoke void @invokee()
- to label %invoke.cont23 unwind label %lpad20
+ to label %invoke.cont23 unwind label %lpad20
invoke.cont23: ; preds = %if.then12
invoke void @invokee()
- to label %if.end unwind label %lpad20
+ to label %if.end unwind label %lpad20
lpad20: ; preds = %invoke.cont23, %if.then12
%tmp502 = phi ptr [ undef, %invoke.cont23 ], [ %self, %if.then12 ]
%exn = landingpad {ptr, i32}
- cleanup
+ cleanup
unreachable
if.end: ; preds = %invoke.cont23
@@ -1237,11 +1623,12 @@ if.end: ; preds = %invoke.cont23
; Delete a redundant retain,autorelease when forwaring a call result
; directly to a return value.
-; CHECK-LABEL: define ptr @test21(
-; CHECK: call ptr @returner()
-; CHECK-NEXT: ret ptr %call
-; CHECK-NEXT: }
define ptr @test21() {
+; CHECK-LABEL: define ptr @test21() {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[CALL:%.*]] = call ptr @returner()
+; CHECK-NEXT: ret ptr [[CALL]]
+;
entry:
%call = call ptr @returner()
%0 = call ptr @llvm.objc.retain(ptr %call) nounwind
@@ -1251,14 +1638,18 @@ entry:
; Move an objc call up through a phi that has null operands.
-; CHECK-LABEL: define void @test22(
-; CHECK: B:
-; CHECK: call void @llvm.objc.release(ptr %p)
-; CHECK: br label %C
-; CHECK: C: ; preds = %B, %A
-; CHECK-NOT: @llvm.objc.release
-; CHECK: {{^}}}
define void @test22(ptr %p, i1 %a) {
+; CHECK-LABEL: define void @test22(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[A:%.*]]) {
+; CHECK-NEXT: br i1 [[A]], label %[[A:.*]], label %[[B:.*]]
+; CHECK: [[A]]:
+; CHECK-NEXT: br label %[[C:.*]]
+; CHECK: [[B]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: br label %[[C]]
+; CHECK: [[C]]:
+; CHECK-NEXT: ret void
+;
br i1 %a, label %A, label %B
A:
br label %C
@@ -1272,11 +1663,19 @@ C:
; Do not move an llvm.objc.release that doesn't have the clang.imprecise_release tag.
-; CHECK-LABEL: define void @test22_precise(
-; CHECK: %[[P0:.*]] = phi ptr
-; CHECK: call void @llvm.objc.release(ptr %[[P0]])
-; CHECK: ret void
define void @test22_precise(ptr %p, i1 %a) {
+; CHECK-LABEL: define void @test22_precise(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[A:%.*]]) {
+; CHECK-NEXT: br i1 [[A]], label %[[A:.*]], label %[[B:.*]]
+; CHECK: [[A]]:
+; CHECK-NEXT: br label %[[C:.*]]
+; CHECK: [[B]]:
+; CHECK-NEXT: br label %[[C]]
+; CHECK: [[C]]:
+; CHECK-NEXT: [[H:%.*]] = phi ptr [ null, %[[A]] ], [ [[P]], %[[B]] ]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[H]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
br i1 %a, label %A, label %B
A:
br label %C
@@ -1290,11 +1689,15 @@ C:
; Any call can decrement a retain count.
-; CHECK-LABEL: define void @test24(
-; CHECK: @llvm.objc.retain(ptr %a)
-; CHECK: @llvm.objc.release
-; CHECK: {{^}}}
define void @test24(ptr %r, ptr %a) {
+; CHECK-LABEL: define void @test24(
+; CHECK-SAME: ptr [[R:%.*]], ptr [[A:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[A]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[R]])
+; CHECK-NEXT: [[Q:%.*]] = load i8, ptr [[A]], align 1
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[A]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
call ptr @llvm.objc.retain(ptr %a)
call void @use_pointer(ptr %r)
%q = load i8, ptr %a
@@ -1305,14 +1708,20 @@ define void @test24(ptr %r, ptr %a) {
; Don't move a retain/release pair if the release can be moved
; but the retain can't be moved to balance it.
-; CHECK-LABEL: define void @test25(
-; CHECK: entry:
-; CHECK: call ptr @llvm.objc.retain(ptr %p)
-; CHECK: true:
-; CHECK: done:
-; CHECK: call void @llvm.objc.release(ptr %p)
-; CHECK: {{^}}}
define void @test25(ptr %p, i1 %x) {
+; CHECK-LABEL: define void @test25(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: br i1 [[X]], label %[[TRUE:.*]], label %[[DONE:.*]]
+; CHECK: [[TRUE]]:
+; CHECK-NEXT: store i8 0, ptr [[P]], align 1
+; CHECK-NEXT: br label %[[DONE]]
+; CHECK: [[DONE]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%f0 = call ptr @llvm.objc.retain(ptr %p)
call void @callee()
@@ -1330,14 +1739,20 @@ done:
; Don't move a retain/release pair if the retain can be moved
; but the release can't be moved to balance it.
-; CHECK-LABEL: define void @test26(
-; CHECK: entry:
-; CHECK: call ptr @llvm.objc.retain(ptr %p)
-; CHECK: true:
-; CHECK: done:
-; CHECK: call void @llvm.objc.release(ptr %p)
-; CHECK: {{^}}}
define void @test26(ptr %p, i1 %x) {
+; CHECK-LABEL: define void @test26(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[F0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[X]], label %[[TRUE:.*]], label %[[DONE:.*]]
+; CHECK: [[TRUE]]:
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: br label %[[DONE]]
+; CHECK: [[DONE]]:
+; CHECK-NEXT: store i8 0, ptr [[P]], align 1
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%f0 = call ptr @llvm.objc.retain(ptr %p)
br i1 %x, label %true, label %done
@@ -1354,15 +1769,20 @@ done:
; Don't sink the retain,release into the loop.
-; CHECK-LABEL: define void @test27(
-; CHECK: entry:
-; CHECK: call ptr @llvm.objc.retain(ptr %p)
-; CHECK: loop:
-; CHECK-NOT: @llvm.objc.
-; CHECK: done:
-; CHECK: call void @llvm.objc.release
-; CHECK: {{^}}}
define void @test27(ptr %p, i1 %x, i1 %y) {
+; CHECK-LABEL: define void @test27(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[X:%.*]], i1 [[Y:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[F0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[X]], label %[[LOOP:.*]], label %[[DONE:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: store i8 0, ptr [[P]], align 1
+; CHECK-NEXT: br i1 [[Y]], label %[[DONE]], label %[[LOOP]]
+; CHECK: [[DONE]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%f0 = call ptr @llvm.objc.retain(ptr %p)
br i1 %x, label %loop, label %done
@@ -1379,17 +1799,20 @@ done:
; Trivial code motion case: Triangle.
-; CHECK-LABEL: define void @test28(
-; CHECK-NOT: @llvm.objc.
-; CHECK: true:
-; CHECK: call ptr @llvm.objc.retain
-; CHECK: call void @callee()
-; CHECK: store
-; CHECK: call void @llvm.objc.release
-; CHECK: done:
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test28(ptr %p, i1 %x) {
+; CHECK-LABEL: define void @test28(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[X]], label %[[TRUE:.*]], label %[[DONE:.*]]
+; CHECK: [[TRUE]]:
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: store i8 0, ptr [[P]], align 1
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: br label %[[DONE]]
+; CHECK: [[DONE]]:
+; CHECK-NEXT: ret void
+;
entry:
%f0 = call ptr @llvm.objc.retain(ptr %p)
br i1 %x, label %true, label %done
@@ -1407,18 +1830,21 @@ done:
; Trivial code motion case: Triangle, but no metadata. Don't move past
; unrelated memory references!
-; CHECK-LABEL: define void @test28b(
-; CHECK: call ptr @llvm.objc.retain
-; CHECK: true:
-; CHECK-NOT: @llvm.objc.
-; CHECK: call void @callee()
-; CHECK-NOT: @llvm.objc.
-; CHECK: store
-; CHECK-NOT: @llvm.objc.
-; CHECK: done:
-; CHECK: @llvm.objc.release
-; CHECK: {{^}}}
define void @test28b(ptr %p, i1 %x, ptr noalias %t) {
+; CHECK-LABEL: define void @test28b(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[X:%.*]], ptr noalias [[T:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[F0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[X]], label %[[TRUE:.*]], label %[[DONE:.*]]
+; CHECK: [[TRUE]]:
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: store i8 0, ptr [[P]], align 1
+; CHECK-NEXT: br label %[[DONE]]
+; CHECK: [[DONE]]:
+; CHECK-NEXT: store i8 0, ptr [[T]], align 1
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%f0 = call ptr @llvm.objc.retain(ptr %p)
br i1 %x, label %true, label %done
@@ -1437,17 +1863,21 @@ done:
; Trivial code motion case: Triangle, with metadata. Do move past
; unrelated memory references! And preserve the metadata.
-; CHECK-LABEL: define void @test28c(
-; CHECK-NOT: @llvm.objc.
-; CHECK: true:
-; CHECK: call ptr @llvm.objc.retain
-; CHECK: call void @callee()
-; CHECK: store
-; CHECK: call void @llvm.objc.release(ptr %p) [[NUW]], !clang.imprecise_release
-; CHECK: done:
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test28c(ptr %p, i1 %x, ptr noalias %t) {
+; CHECK-LABEL: define void @test28c(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[X:%.*]], ptr noalias [[T:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[X]], label %[[TRUE:.*]], label %[[DONE:.*]]
+; CHECK: [[TRUE]]:
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: store i8 0, ptr [[P]], align 1
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: br label %[[DONE]]
+; CHECK: [[DONE]]:
+; CHECK-NEXT: store i8 0, ptr [[T]], align 1
+; CHECK-NEXT: ret void
+;
entry:
%f0 = call ptr @llvm.objc.retain(ptr %p)
br i1 %x, label %true, label %done
@@ -1465,17 +1895,23 @@ done:
; Like test28. but with two releases.
-; CHECK-LABEL: define void @test29(
-; CHECK: call ptr @llvm.objc.retain
-; CHECK: true:
-; CHECK: call void @callee()
-; CHECK: store
-; CHECK: done:
-; CHECK: call void @llvm.objc.release
-; CHECK: ohno:
-; CHECK: call void @llvm.objc.release
-; CHECK: {{^}}}
define void @test29(ptr %p, i1 %x, i1 %y) {
+; CHECK-LABEL: define void @test29(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[X:%.*]], i1 [[Y:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[F0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[X]], label %[[TRUE:.*]], label %[[DONE:.*]]
+; CHECK: [[TRUE]]:
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: store i8 0, ptr [[P]], align 1
+; CHECK-NEXT: br i1 [[Y]], label %[[DONE]], label %[[OHNO:.*]]
+; CHECK: [[DONE]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+; CHECK: [[OHNO]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%f0 = call ptr @llvm.objc.retain(ptr %p)
br i1 %x, label %true, label %done
@@ -1497,18 +1933,25 @@ ohno:
; Basic case with the use and call in a diamond
; with an extra release.
-; CHECK-LABEL: define void @test30(
-; CHECK: call ptr @llvm.objc.retain
-; CHECK: true:
-; CHECK: call void @callee()
-; CHECK: store
-; CHECK: false:
-; CHECK: done:
-; CHECK: call void @llvm.objc.release
-; CHECK: ohno:
-; CHECK: call void @llvm.objc.release
-; CHECK: {{^}}}
define void @test30(ptr %p, i1 %x, i1 %y, i1 %z) {
+; CHECK-LABEL: define void @test30(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[X:%.*]], i1 [[Y:%.*]], i1 [[Z:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[F0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[X]], label %[[TRUE:.*]], label %[[FALSE:.*]]
+; CHECK: [[TRUE]]:
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: store i8 0, ptr [[P]], align 1
+; CHECK-NEXT: br i1 [[Y]], label %[[DONE:.*]], label %[[OHNO:.*]]
+; CHECK: [[FALSE]]:
+; CHECK-NEXT: br i1 [[Z]], label %[[DONE]], label %[[OHNO]]
+; CHECK: [[DONE]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+; CHECK: [[OHNO]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%f0 = call ptr @llvm.objc.retain(ptr %p)
br i1 %x, label %true, label %false
@@ -1532,17 +1975,21 @@ ohno:
; Basic case with a mergeable release.
-; CHECK-LABEL: define void @test31(
-; CHECK: call ptr @llvm.objc.retain(ptr %p)
-; CHECK: call void @callee()
-; CHECK: store
-; CHECK: true:
-; CHECK: call void @llvm.objc.release
-; CHECK: false:
-; CHECK: call void @llvm.objc.release
-; CHECK: ret void
-; CHECK: {{^}}}
define void @test31(ptr %p, i1 %x) {
+; CHECK-LABEL: define void @test31(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: store i8 0, ptr [[P]], align 1
+; CHECK-NEXT: br i1 [[X]], label %[[TRUE:.*]], label %[[FALSE:.*]]
+; CHECK: [[TRUE]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+; CHECK: [[FALSE]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%f0 = call ptr @llvm.objc.retain(ptr %p)
call void @callee()
@@ -1558,15 +2005,20 @@ false:
; Don't consider bitcasts or getelementptrs direct uses.
-; CHECK-LABEL: define void @test32(
-; CHECK: call ptr @llvm.objc.retain
-; CHECK: true:
-; CHECK: call void @callee()
-; CHECK: store
-; CHECK: done:
-; CHECK: call void @llvm.objc.release
-; CHECK: {{^}}}
define void @test32(ptr %p, i1 %x) {
+; CHECK-LABEL: define void @test32(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[F0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[X]], label %[[TRUE:.*]], label %[[DONE:.*]]
+; CHECK: [[TRUE]]:
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: store i8 0, ptr [[P]], align 1
+; CHECK-NEXT: br label %[[DONE]]
+; CHECK: [[DONE]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%f0 = call ptr @llvm.objc.retain(ptr %p)
br i1 %x, label %true, label %done
@@ -1583,15 +2035,20 @@ done:
; Do consider icmps to be direct uses.
-; CHECK-LABEL: define void @test33(
-; CHECK: call ptr @llvm.objc.retain
-; CHECK: true:
-; CHECK: call void @callee()
-; CHECK: icmp
-; CHECK: done:
-; CHECK: call void @llvm.objc.release
-; CHECK: {{^}}}
define void @test33(ptr %p, i1 %x, ptr %y) {
+; CHECK-LABEL: define void @test33(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[X:%.*]], ptr [[Y:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[F0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[X]], label %[[TRUE:.*]], label %[[DONE:.*]]
+; CHECK: [[TRUE]]:
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: [[V:%.*]] = icmp eq ptr [[P]], [[Y]]
+; CHECK-NEXT: br label %[[DONE]]
+; CHECK: [[DONE]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%f0 = call ptr @llvm.objc.retain(ptr %p)
br i1 %x, label %true, label %done
@@ -1609,13 +2066,19 @@ done:
; Delete retain,release if there's just a possible dec and we have imprecise
; releases.
-; CHECK-LABEL: define void @test34a(
-; CHECK: call ptr @llvm.objc.retain
-; CHECK: true:
-; CHECK: done:
-; CHECK: call void @llvm.objc.release
-; CHECK: {{^}}}
define void @test34a(ptr %p, i1 %x, ptr %y) {
+; CHECK-LABEL: define void @test34a(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[X:%.*]], ptr [[Y:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[F0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[X]], label %[[TRUE:.*]], label %[[DONE:.*]]
+; CHECK: [[TRUE]]:
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: br label %[[DONE]]
+; CHECK: [[DONE]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%f0 = call ptr @llvm.objc.retain(ptr %p)
br i1 %x, label %true, label %done
@@ -1629,10 +2092,17 @@ done:
ret void
}
-; CHECK-LABEL: define void @test34b(
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test34b(ptr %p, i1 %x, ptr %y) {
+; CHECK-LABEL: define void @test34b(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[X:%.*]], ptr [[Y:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[X]], label %[[TRUE:.*]], label %[[DONE:.*]]
+; CHECK: [[TRUE]]:
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: br label %[[DONE]]
+; CHECK: [[DONE]]:
+; CHECK-NEXT: ret void
+;
entry:
%f0 = call ptr @llvm.objc.retain(ptr %p)
br i1 %x, label %true, label %done
@@ -1651,14 +2121,19 @@ done:
; release.
; Precise.
-; CHECK-LABEL: define void @test35a(
-; CHECK: entry:
-; CHECK: call ptr @llvm.objc.retain
-; CHECK: true:
-; CHECK: done:
-; CHECK: call void @llvm.objc.release
-; CHECK: {{^}}}
define void @test35a(ptr %p, i1 %x, ptr %y) {
+; CHECK-LABEL: define void @test35a(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[X:%.*]], ptr [[Y:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[F0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[X]], label %[[TRUE:.*]], label %[[DONE:.*]]
+; CHECK: [[TRUE]]:
+; CHECK-NEXT: [[V:%.*]] = icmp eq ptr [[P]], [[Y]]
+; CHECK-NEXT: br label %[[DONE]]
+; CHECK: [[DONE]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%f0 = call ptr @llvm.objc.retain(ptr %p)
br i1 %x, label %true, label %done
@@ -1673,10 +2148,17 @@ done:
}
; Imprecise.
-; CHECK-LABEL: define void @test35b(
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test35b(ptr %p, i1 %x, ptr %y) {
+; CHECK-LABEL: define void @test35b(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[X:%.*]], ptr [[Y:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[X]], label %[[TRUE:.*]], label %[[DONE:.*]]
+; CHECK: [[TRUE]]:
+; CHECK-NEXT: [[V:%.*]] = icmp eq ptr [[P]], [[Y]]
+; CHECK-NEXT: br label %[[DONE]]
+; CHECK: [[DONE]]:
+; CHECK-NEXT: ret void
+;
entry:
%f0 = call ptr @llvm.objc.retain(ptr %p)
br i1 %x, label %true, label %done
@@ -1692,14 +2174,16 @@ done:
; Delete a retain,release if there's no actual use and we have precise release.
-; CHECK-LABEL: define void @test36a(
-; CHECK: @llvm.objc.retain
-; CHECK: call void @callee()
-; CHECK-NOT: @llvm.objc.
-; CHECK: call void @callee()
-; CHECK: @llvm.objc.release
-; CHECK: {{^}}}
define void @test36a(ptr %p) {
+; CHECK-LABEL: define void @test36a(
+; CHECK-SAME: ptr [[P:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %p)
call void @callee()
@@ -1710,10 +2194,14 @@ entry:
; Like test36, but with metadata.
-; CHECK-LABEL: define void @test36b(
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test36b(ptr %p) {
+; CHECK-LABEL: define void @test36b(
+; CHECK-SAME: ptr [[P:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %p)
call void @callee()
@@ -1724,10 +2212,34 @@ entry:
; Be aggressive about analyzing phis to eliminate possible uses.
-; CHECK-LABEL: define void @test38(
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test38(ptr %p, i1 %u, i1 %m, ptr %z, ptr %y, ptr %x, ptr %w) {
+; CHECK-LABEL: define void @test38(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[U:%.*]], i1 [[M:%.*]], ptr [[Z:%.*]], ptr [[Y:%.*]], ptr [[X:%.*]], ptr [[W:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[U]], label %[[TRUE:.*]], label %[[FALSE:.*]]
+; CHECK: [[TRUE]]:
+; CHECK-NEXT: br i1 [[M]], label %[[A:.*]], label %[[B:.*]]
+; CHECK: [[FALSE]]:
+; CHECK-NEXT: br i1 [[M]], label %[[C:.*]], label %[[D:.*]]
+; CHECK: [[A]]:
+; CHECK-NEXT: br label %[[E:.*]]
+; CHECK: [[B]]:
+; CHECK-NEXT: br label %[[E]]
+; CHECK: [[C]]:
+; CHECK-NEXT: br label %[[F:.*]]
+; CHECK: [[D]]:
+; CHECK-NEXT: br label %[[F]]
+; CHECK: [[E]]:
+; CHECK-NEXT: [[J:%.*]] = phi ptr [ [[Z]], %[[A]] ], [ [[Y]], %[[B]] ]
+; CHECK-NEXT: br label %[[G:.*]]
+; CHECK: [[F]]:
+; CHECK-NEXT: [[K:%.*]] = phi ptr [ [[W]], %[[C]] ], [ [[X]], %[[D]] ]
+; CHECK-NEXT: br label %[[G]]
+; CHECK: [[G]]:
+; CHECK-NEXT: [[H:%.*]] = phi ptr [ [[J]], %[[E]] ], [ [[K]], %[[F]] ]
+; CHECK-NEXT: call void @use_pointer(ptr [[H]])
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %p)
br i1 %u, label %true, label %false
@@ -1758,10 +2270,16 @@ g:
; Delete retain,release pairs around loops.
-; CHECK-LABEL: define void @test39(
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test39(ptr %p, i1 %arg) {
+; CHECK-LABEL: define void @test39(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[ARG:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: br i1 [[ARG]], label %[[LOOP]], label %[[EXIT:.*]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %p)
br label %loop
@@ -1776,10 +2294,17 @@ exit: ; preds = %loop
; Delete retain,release pairs around loops containing uses.
-; CHECK-LABEL: define void @test39b(
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test39b(ptr %p, i1 %arg) {
+; CHECK-LABEL: define void @test39b(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[ARG:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: store i8 0, ptr [[P]], align 1
+; CHECK-NEXT: br i1 [[ARG]], label %[[LOOP]], label %[[EXIT:.*]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %p)
br label %loop
@@ -1795,10 +2320,17 @@ exit: ; preds = %loop
; Delete retain,release pairs around loops containing potential decrements.
-; CHECK-LABEL: define void @test39c(
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test39c(ptr %p, i1 %arg) {
+; CHECK-LABEL: define void @test39c(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[ARG:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: call void @use_pointer(ptr [[P]])
+; CHECK-NEXT: br i1 [[ARG]], label %[[LOOP]], label %[[EXIT:.*]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %p)
br label %loop
@@ -1815,10 +2347,17 @@ exit: ; preds = %loop
; Delete retain,release pairs around loops even if
; the successors are in a different order.
-; CHECK-LABEL: define void @test40(
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test40(ptr %p, i1 %arg) {
+; CHECK-LABEL: define void @test40(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[ARG:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: call void @use_pointer(ptr [[P]])
+; CHECK-NEXT: br i1 [[ARG]], label %[[EXIT:.*]], label %[[LOOP]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %p)
br label %loop
@@ -1835,18 +2374,19 @@ exit: ; preds = %loop
; Do the known-incremented retain+release elimination even if the pointer
; is also autoreleased.
-; CHECK-LABEL: define void @test42(
-; CHECK-NEXT: entry:
-; CHECK-NEXT: call ptr @llvm.objc.retain(ptr %p)
-; CHECK-NEXT: call ptr @llvm.objc.autorelease(ptr %p)
-; CHECK-NEXT: call void @use_pointer(ptr %p)
-; CHECK-NEXT: call void @use_pointer(ptr %p)
-; CHECK-NEXT: call void @use_pointer(ptr %p)
-; CHECK-NEXT: call void @use_pointer(ptr %p)
-; CHECK-NEXT: call void @llvm.objc.release(ptr %p)
-; CHECK-NEXT: ret void
-; CHECK-NEXT: }
define void @test42(ptr %p) {
+; CHECK-LABEL: define void @test42(
+; CHECK-SAME: ptr [[P:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.objc.autorelease(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[P]])
+; CHECK-NEXT: call void @use_pointer(ptr [[P]])
+; CHECK-NEXT: call void @use_pointer(ptr [[P]])
+; CHECK-NEXT: call void @use_pointer(ptr [[P]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %p)
call ptr @llvm.objc.autorelease(ptr %p)
@@ -1863,25 +2403,26 @@ entry:
; Don't the known-incremented retain+release elimination if the pointer is
; autoreleased and there's an autoreleasePoolPop.
-; CHECK-LABEL: define void @test43(
-; CHECK-NEXT: entry:
-; CHECK-NEXT: call ptr @llvm.objc.retain(ptr %p)
-; CHECK-NEXT: call ptr @llvm.objc.autorelease(ptr %p)
-; CHECK-NEXT: call ptr @llvm.objc.retain
-; CHECK-NEXT: call void @use_pointer(ptr %p)
-; CHECK-NEXT: call void @use_pointer(ptr %p)
-; CHECK-NEXT: call void @llvm.objc.autoreleasePoolPop(ptr undef)
-; CHECK-NEXT: call void @llvm.objc.release
-; CHECK-NEXT: ret void
-; CHECK-NEXT: }
define void @test43(ptr %p) {
+; CHECK-LABEL: define void @test43(
+; CHECK-SAME: ptr [[P:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.objc.autorelease(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP2:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[P]])
+; CHECK-NEXT: call void @use_pointer(ptr [[P]])
+; CHECK-NEXT: call void @llvm.objc.autoreleasePoolPop(ptr poison) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %p)
call ptr @llvm.objc.autorelease(ptr %p)
call ptr @llvm.objc.retain(ptr %p)
call void @use_pointer(ptr %p)
call void @use_pointer(ptr %p)
- call void @llvm.objc.autoreleasePoolPop(ptr undef)
+ call void @llvm.objc.autoreleasePoolPop(ptr poison)
call void @llvm.objc.release(ptr %p)
ret void
}
@@ -1889,18 +2430,19 @@ entry:
; Do the known-incremented retain+release elimination if the pointer is
; autoreleased and there's an autoreleasePoolPush.
-; CHECK-LABEL: define void @test43b(
-; CHECK-NEXT: entry:
-; CHECK-NEXT: call ptr @llvm.objc.retain(ptr %p)
-; CHECK-NEXT: call ptr @llvm.objc.autorelease(ptr %p)
-; CHECK-NEXT: call void @use_pointer(ptr %p)
-; CHECK-NEXT: call void @use_pointer(ptr %p)
-; CHECK-NEXT: call ptr @llvm.objc.autoreleasePoolPush()
-; CHECK-NEXT: call void @use_pointer(ptr %p)
-; CHECK-NEXT: call void @llvm.objc.release
-; CHECK-NEXT: ret void
-; CHECK-NEXT: }
define void @test43b(ptr %p) {
+; CHECK-LABEL: define void @test43b(
+; CHECK-SAME: ptr [[P:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.objc.autorelease(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[P]])
+; CHECK-NEXT: call void @use_pointer(ptr [[P]])
+; CHECK-NEXT: [[TMP2:%.*]] = call ptr @llvm.objc.autoreleasePoolPush() #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[P]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %p)
call ptr @llvm.objc.autorelease(ptr %p)
@@ -1916,10 +2458,11 @@ entry:
; Do retain+release elimination for non-provenance pointers.
-; CHECK-LABEL: define void @test44(
-; CHECK-NOT: llvm.objc.
-; CHECK: {{^}}}
define void @test44(ptr %pp) {
+; CHECK-LABEL: define void @test44(
+; CHECK-SAME: ptr [[PP:%.*]]) {
+; CHECK-NEXT: ret void
+;
%p = load ptr, ptr %pp
%q = call ptr @llvm.objc.retain(ptr %p)
call void @llvm.objc.release(ptr %q)
@@ -1929,13 +2472,17 @@ define void @test44(ptr %pp) {
; Don't delete retain+release with an unknown-provenance
; may-alias llvm.objc.release between them.
-; CHECK-LABEL: define void @test45(
-; CHECK: call ptr @llvm.objc.retain(ptr %p)
-; CHECK: call void @llvm.objc.release(ptr %q)
-; CHECK: call void @use_pointer(ptr %p)
-; CHECK: call void @llvm.objc.release(ptr %p)
-; CHECK: {{^}}}
define void @test45(ptr %pp, ptr %qq) {
+; CHECK-LABEL: define void @test45(
+; CHECK-SAME: ptr [[PP:%.*]], ptr [[QQ:%.*]]) {
+; CHECK-NEXT: [[P:%.*]] = load ptr, ptr [[PP]], align 8
+; CHECK-NEXT: [[Q:%.*]] = load ptr, ptr [[QQ]], align 8
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[Q]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[P]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
%p = load ptr, ptr %pp
%q = load ptr, ptr %qq
call ptr @llvm.objc.retain(ptr %p)
@@ -1947,12 +2494,19 @@ define void @test45(ptr %pp, ptr %qq) {
; Don't delete retain and autorelease here.
-; CHECK-LABEL: define void @test46(
-; CHECK: tail call ptr @llvm.objc.retain(ptr %p) [[NUW]]
-; CHECK: true:
-; CHECK: call ptr @llvm.objc.autorelease(ptr %p) [[NUW]]
-; CHECK: {{^}}}
define void @test46(ptr %p, i1 %a) {
+; CHECK-LABEL: define void @test46(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[A:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[A]], label %[[TRUE:.*]], label %[[FALSE:.*]]
+; CHECK: [[TRUE]]:
+; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.objc.autorelease(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[P]])
+; CHECK-NEXT: ret void
+; CHECK: [[FALSE]]:
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %p)
br i1 %a, label %true, label %false
@@ -1968,33 +2522,33 @@ false:
; Delete no-op cast calls.
-; CHECK-LABEL: define ptr @test47(
-; CHECK-NOT: call
-; CHECK: ret ptr %p
-; CHECK: {{^}}}
define ptr @test47(ptr %p) nounwind {
+; CHECK-LABEL: define ptr @test47(
+; CHECK-SAME: ptr [[P:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret ptr [[P]]
+;
%x = call ptr @llvm.objc.retainedObject(ptr %p)
ret ptr %x
}
; Delete no-op cast calls.
-; CHECK-LABEL: define ptr @test48(
-; CHECK-NOT: call
-; CHECK: ret ptr %p
-; CHECK: {{^}}}
define ptr @test48(ptr %p) nounwind {
+; CHECK-LABEL: define ptr @test48(
+; CHECK-SAME: ptr [[P:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret ptr [[P]]
+;
%x = call ptr @llvm.objc.unretainedObject(ptr %p)
ret ptr %x
}
; Delete no-op cast calls.
-; CHECK-LABEL: define ptr @test49(
-; CHECK-NOT: call
-; CHECK: ret ptr %p
-; CHECK: {{^}}}
define ptr @test49(ptr %p) nounwind {
+; CHECK-LABEL: define ptr @test49(
+; CHECK-SAME: ptr [[P:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret ptr [[P]]
+;
%x = call ptr @llvm.objc.unretainedPointer(ptr %p)
ret ptr %x
}
@@ -2002,14 +2556,15 @@ define ptr @test49(ptr %p) nounwind {
; Do delete retain+release with intervening stores of the address value if we
; have imprecise release attached to llvm.objc.release.
-; CHECK-LABEL: define void @test50a(
-; CHECK-NEXT: call ptr @llvm.objc.retain
-; CHECK-NEXT: call void @callee
-; CHECK-NEXT: store
-; CHECK-NEXT: call void @llvm.objc.release
-; CHECK-NEXT: ret void
-; CHECK-NEXT: }
define void @test50a(ptr %p, ptr %pp) {
+; CHECK-LABEL: define void @test50a(
+; CHECK-SAME: ptr [[P:%.*]], ptr [[PP:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: store ptr [[P]], ptr [[PP]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
call ptr @llvm.objc.retain(ptr %p)
call void @callee()
store ptr %p, ptr %pp
@@ -2017,10 +2572,13 @@ define void @test50a(ptr %p, ptr %pp) {
ret void
}
-; CHECK-LABEL: define void @test50b(
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test50b(ptr %p, ptr %pp) {
+; CHECK-LABEL: define void @test50b(
+; CHECK-SAME: ptr [[P:%.*]], ptr [[PP:%.*]]) {
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: store ptr [[P]], ptr [[PP]], align 8
+; CHECK-NEXT: ret void
+;
call ptr @llvm.objc.retain(ptr %p)
call void @callee()
store ptr %p, ptr %pp
@@ -2032,12 +2590,15 @@ define void @test50b(ptr %p, ptr %pp) {
; Don't delete retain+release with intervening stores through the
; address value.
-; CHECK-LABEL: define void @test51a(
-; CHECK: call ptr @llvm.objc.retain(ptr %p)
-; CHECK: call void @llvm.objc.release(ptr %p)
-; CHECK: ret void
-; CHECK: {{^}}}
define void @test51a(ptr %p) {
+; CHECK-LABEL: define void @test51a(
+; CHECK-SAME: ptr [[P:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: store i8 0, ptr [[P]], align 1
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
call ptr @llvm.objc.retain(ptr %p)
call void @callee()
store i8 0, ptr %p
@@ -2045,12 +2606,15 @@ define void @test51a(ptr %p) {
ret void
}
-; CHECK-LABEL: define void @test51b(
-; CHECK: call ptr @llvm.objc.retain(ptr %p)
-; CHECK: call void @llvm.objc.release(ptr %p)
-; CHECK: ret void
-; CHECK: {{^}}}
define void @test51b(ptr %p) {
+; CHECK-LABEL: define void @test51b(
+; CHECK-SAME: ptr [[P:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: store i8 0, ptr [[P]], align 1
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: ret void
+;
call ptr @llvm.objc.retain(ptr %p)
call void @callee()
store i8 0, ptr %p
@@ -2061,14 +2625,17 @@ define void @test51b(ptr %p) {
; Don't delete retain+release with intervening use of a pointer of
; unknown provenance.
-; CHECK-LABEL: define void @test52a(
-; CHECK: call ptr @llvm.objc.retain
-; CHECK: call void @callee()
-; CHECK: call void @use_pointer(ptr %z)
-; CHECK: call void @llvm.objc.release
-; CHECK: ret void
-; CHECK: {{^}}}
define void @test52a(ptr %zz, ptr %pp) {
+; CHECK-LABEL: define void @test52a(
+; CHECK-SAME: ptr [[ZZ:%.*]], ptr [[PP:%.*]]) {
+; CHECK-NEXT: [[P:%.*]] = load ptr, ptr [[PP]], align 8
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: [[Z:%.*]] = load ptr, ptr [[ZZ]], align 8
+; CHECK-NEXT: call void @use_pointer(ptr [[Z]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
%p = load ptr, ptr %pp
%1 = call ptr @llvm.objc.retain(ptr %p)
call void @callee()
@@ -2078,14 +2645,17 @@ define void @test52a(ptr %zz, ptr %pp) {
ret void
}
-; CHECK-LABEL: define void @test52b(
-; CHECK: call ptr @llvm.objc.retain
-; CHECK: call void @callee()
-; CHECK: call void @use_pointer(ptr %z)
-; CHECK: call void @llvm.objc.release
-; CHECK: ret void
-; CHECK: {{^}}}
define void @test52b(ptr %zz, ptr %pp) {
+; CHECK-LABEL: define void @test52b(
+; CHECK-SAME: ptr [[ZZ:%.*]], ptr [[PP:%.*]]) {
+; CHECK-NEXT: [[P:%.*]] = load ptr, ptr [[PP]], align 8
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: [[Z:%.*]] = load ptr, ptr [[ZZ]], align 8
+; CHECK-NEXT: call void @use_pointer(ptr [[Z]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: ret void
+;
%p = load ptr, ptr %pp
%1 = call ptr @llvm.objc.retain(ptr %p)
call void @callee()
@@ -2100,10 +2670,17 @@ define void @test52b(ptr %zz, ptr %pp) {
; Oops. That's wrong. Clang sometimes uses function types gratuitously.
; See rdar://10551239.
-; CHECK-LABEL: define void @test53(
-; CHECK: @llvm.objc.
-; CHECK: {{^}}}
define void @test53(ptr %zz, ptr %pp) {
+; CHECK-LABEL: define void @test53(
+; CHECK-SAME: ptr [[ZZ:%.*]], ptr [[PP:%.*]]) {
+; CHECK-NEXT: [[P:%.*]] = load ptr, ptr [[PP]], align 8
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: [[Z:%.*]] = load ptr, ptr [[ZZ]], align 8
+; CHECK-NEXT: call void @callee_fnptr(ptr [[Z]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
%p = load ptr, ptr %pp
%1 = call ptr @llvm.objc.retain(ptr %p)
call void @callee()
@@ -2115,12 +2692,12 @@ define void @test53(ptr %zz, ptr %pp) {
; Convert autorelease to release if the value is unused.
-; CHECK-LABEL: define void @test54(
-; CHECK: call ptr @returner()
-; CHECK-NEXT: call void @llvm.objc.release(ptr %t) [[NUW]], !clang.imprecise_release ![[RELEASE]]
-; CHECK-NEXT: ret void
-; CHECK: {{^}}}
define void @test54() {
+; CHECK-LABEL: define void @test54() {
+; CHECK-NEXT: [[T:%.*]] = call ptr @returner()
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[T]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: ret void
+;
%t = call ptr @returner()
call ptr @llvm.objc.autorelease(ptr %t)
ret void
@@ -2128,10 +2705,12 @@ define void @test54() {
; Nested retain+release pairs. Delete them both.
-; CHECK-LABEL: define void @test55(
-; CHECK-NOT: @objc
-; CHECK: {{^}}}
define void @test55(ptr %x) {
+; CHECK-LABEL: define void @test55(
+; CHECK-SAME: ptr [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
%1 = call ptr @llvm.objc.retain(ptr %x) nounwind
@@ -2145,17 +2724,21 @@ entry:
; can be partially eliminated. Plus an extra outer pair to
; eliminate, for fun.
-; CHECK-LABEL: define void @test56(
-; CHECK-NOT: @objc
-; CHECK: if.then:
-; CHECK-NEXT: %0 = tail call ptr @llvm.objc.retain(ptr %x) [[NUW]]
-; CHECK-NEXT: tail call void @use_pointer(ptr %x)
-; CHECK-NEXT: tail call void @use_pointer(ptr %x)
-; CHECK-NEXT: tail call void @llvm.objc.release(ptr %x) [[NUW]], !clang.imprecise_release ![[RELEASE]]
-; CHECK-NEXT: br label %if.end
-; CHECK-NOT: @objc
-; CHECK: {{^}}}
define void @test56(ptr %x, i32 %n) {
+; CHECK-LABEL: define void @test56(
+; CHECK-SAME: ptr [[X:%.*]], i32 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[N]], 0
+; CHECK-NEXT: br i1 [[TOBOOL]], label %[[IF_END:.*]], label %[[IF_THEN:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: tail call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: tail call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: tail call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: br label %[[IF_END]]
+; CHECK: [[IF_END]]:
+; CHECK-NEXT: ret void
+;
entry:
%0 = tail call ptr @llvm.objc.retain(ptr %x) nounwind
%1 = tail call ptr @llvm.objc.retain(ptr %0) nounwind
@@ -2179,18 +2762,19 @@ if.end: ; preds = %entry, %if.then
; unnecessary because the presence of the second one means that the first one
; won't be deleting the object.
-; CHECK-LABEL: define void @test57(
-; CHECK-NEXT: entry:
-; CHECK-NEXT: tail call ptr @llvm.objc.retain(ptr %x) [[NUW]]
-; CHECK-NEXT: call void @use_pointer(ptr %x)
-; CHECK-NEXT: call void @use_pointer(ptr %x)
-; CHECK-NEXT: tail call ptr @llvm.objc.retain(ptr %x) [[NUW]]
-; CHECK-NEXT: call void @use_pointer(ptr %x)
-; CHECK-NEXT: call void @use_pointer(ptr %x)
-; CHECK-NEXT: call void @llvm.objc.release(ptr %x) [[NUW]]
-; CHECK-NEXT: ret void
-; CHECK-NEXT: }
define void @test57(ptr %x) nounwind {
+; CHECK-LABEL: define void @test57(
+; CHECK-SAME: ptr [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %x) nounwind
call ptr @llvm.objc.retain(ptr %x) nounwind
@@ -2207,14 +2791,17 @@ entry:
; An adjacent retain+release pair is sufficient even if it will be
; removed itself.
-; CHECK-LABEL: define void @test58(
-; CHECK-NEXT: entry:
-; CHECK-NEXT: @llvm.objc.retain
-; CHECK-NEXT: call void @use_pointer(ptr %x)
-; CHECK-NEXT: call void @use_pointer(ptr %x)
-; CHECK-NEXT: ret void
-; CHECK-NEXT: }
define void @test58(ptr %x) nounwind {
+; CHECK-LABEL: define void @test58(
+; CHECK-SAME: ptr [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %x) nounwind
call ptr @llvm.objc.retain(ptr %x) nounwind
@@ -2228,15 +2815,16 @@ entry:
; Don't delete the second retain+release pair in an adjacent set.
-; CHECK-LABEL: define void @test59(
-; CHECK-NEXT: entry:
-; CHECK-NEXT: %0 = tail call ptr @llvm.objc.retain(ptr %x) [[NUW]]
-; CHECK-NEXT: call void @use_pointer(ptr %x)
-; CHECK-NEXT: call void @use_pointer(ptr %x)
-; CHECK-NEXT: call void @llvm.objc.release(ptr %x) [[NUW]]
-; CHECK-NEXT: ret void
-; CHECK-NEXT: }
define void @test59(ptr %x) nounwind {
+; CHECK-LABEL: define void @test59(
+; CHECK-SAME: ptr [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%a = call ptr @llvm.objc.retain(ptr %x) nounwind
call void @llvm.objc.release(ptr %x) nounwind
@@ -2255,11 +2843,16 @@ entry:
; We have a precise lifetime retain/release here. We can not remove them since
; @something is not constant.
-; CHECK-LABEL: define void @test60a(
-; CHECK: call ptr @llvm.objc.retain
-; CHECK: call void @llvm.objc.release
-; CHECK: {{^}}}
define void @test60a() {
+; CHECK-LABEL: define void @test60a() {
+; CHECK-NEXT: [[T:%.*]] = load ptr, ptr @constptr, align 8
+; CHECK-NEXT: [[S:%.*]] = load ptr, ptr @something, align 8
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[S]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: call void @use_pointer(ptr [[T]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[S]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
%t = load ptr, ptr @constptr
%s = load ptr, ptr @something
call ptr @llvm.objc.retain(ptr %s)
@@ -2269,12 +2862,15 @@ define void @test60a() {
ret void
}
-; CHECK-LABEL: define void @test60b(
-; CHECK: call ptr @llvm.objc.retain
-; CHECK-NOT: call ptr @llvm.objc.retain
-; CHECK-NOT: call ptr @llvm.objc.release
-; CHECK: {{^}}}
define void @test60b() {
+; CHECK-LABEL: define void @test60b() {
+; CHECK-NEXT: [[T:%.*]] = load ptr, ptr @constptr, align 8
+; CHECK-NEXT: [[S:%.*]] = load ptr, ptr @something, align 8
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[T]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: call void @use_pointer(ptr [[S]])
+; CHECK-NEXT: ret void
+;
%t = load ptr, ptr @constptr
%s = load ptr, ptr @something
call ptr @llvm.objc.retain(ptr %t)
@@ -2285,10 +2881,13 @@ define void @test60b() {
ret void
}
-; CHECK-LABEL: define void @test60c(
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test60c() {
+; CHECK-LABEL: define void @test60c() {
+; CHECK-NEXT: [[S:%.*]] = load ptr, ptr @something, align 8
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: call void @use_pointer(ptr [[S]])
+; CHECK-NEXT: ret void
+;
%t = load ptr, ptr @constptr
%s = load ptr, ptr @something
call ptr @llvm.objc.retain(ptr %t)
@@ -2298,10 +2897,13 @@ define void @test60c() {
ret void
}
-; CHECK-LABEL: define void @test60d(
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test60d() {
+; CHECK-LABEL: define void @test60d() {
+; CHECK-NEXT: [[S:%.*]] = load ptr, ptr @something, align 8
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: call void @use_pointer(ptr [[S]])
+; CHECK-NEXT: ret void
+;
%t = load ptr, ptr @constptr
%s = load ptr, ptr @something
call ptr @llvm.objc.retain(ptr %t)
@@ -2311,10 +2913,13 @@ define void @test60d() {
ret void
}
-; CHECK-LABEL: define void @test60e(
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test60e() {
+; CHECK-LABEL: define void @test60e() {
+; CHECK-NEXT: [[S:%.*]] = load ptr, ptr @something, align 8
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: call void @use_pointer(ptr [[S]])
+; CHECK-NEXT: ret void
+;
%t = load ptr, ptr @constptr
%s = load ptr, ptr @something
call ptr @llvm.objc.retain(ptr %t)
@@ -2327,10 +2932,13 @@ define void @test60e() {
; Constant pointers to objects don't need to be considered related to other
; pointers.
-; CHECK-LABEL: define void @test61(
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test61() {
+; CHECK-LABEL: define void @test61() {
+; CHECK-NEXT: [[T:%.*]] = load ptr, ptr @constptr, align 8
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: call void @use_pointer(ptr [[T]])
+; CHECK-NEXT: ret void
+;
%t = load ptr, ptr @constptr
call ptr @llvm.objc.retain(ptr %t)
call void @callee()
@@ -2342,10 +2950,19 @@ define void @test61() {
; Delete a retain matched by releases when one is inside the loop and the
; other is outside the loop.
-; CHECK-LABEL: define void @test62(
-; CHECK-NOT: @llvm.objc.
-; CHECK: {{^}}}
define void @test62(ptr %x, ptr %p) nounwind {
+; CHECK-LABEL: define void @test62(
+; CHECK-SAME: ptr [[X:%.*]], ptr [[P:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: [[Q:%.*]] = load i1, ptr [[P]], align 1
+; CHECK-NEXT: br i1 [[Q]], label %[[LOOP_MORE:.*]], label %[[EXIT:.*]]
+; CHECK: [[LOOP_MORE]]:
+; CHECK-NEXT: br label %[[LOOP]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
entry:
br label %loop
@@ -2366,13 +2983,21 @@ exit:
; Like test62 but with no release in exit.
; Don't delete anything!
-; CHECK-LABEL: define void @test63(
-; CHECK: loop:
-; CHECK: tail call ptr @llvm.objc.retain(ptr %x)
-; CHECK: loop.more:
-; CHECK: call void @llvm.objc.release(ptr %x)
-; CHECK: {{^}}}
define void @test63(ptr %x, ptr %p) nounwind {
+; CHECK-LABEL: define void @test63(
+; CHECK-SAME: ptr [[X:%.*]], ptr [[P:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: [[Q:%.*]] = load i1, ptr [[P]], align 1
+; CHECK-NEXT: br i1 [[Q]], label %[[LOOP_MORE:.*]], label %[[EXIT:.*]]
+; CHECK: [[LOOP_MORE]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br label %[[LOOP]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
entry:
br label %loop
@@ -2392,13 +3017,21 @@ exit:
; Like test62 but with no release in loop.more.
; Don't delete anything!
-; CHECK-LABEL: define void @test64(
-; CHECK: loop:
-; CHECK: tail call ptr @llvm.objc.retain(ptr %x)
-; CHECK: exit:
-; CHECK: call void @llvm.objc.release(ptr %x)
-; CHECK: {{^}}}
define void @test64(ptr %x, ptr %p) nounwind {
+; CHECK-LABEL: define void @test64(
+; CHECK-SAME: ptr [[X:%.*]], ptr [[P:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: [[Q:%.*]] = load i1, ptr [[P]], align 1
+; CHECK-NEXT: br i1 [[Q]], label %[[LOOP_MORE:.*]], label %[[EXIT:.*]]
+; CHECK: [[LOOP_MORE]]:
+; CHECK-NEXT: br label %[[LOOP]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
br label %loop
@@ -2417,13 +3050,20 @@ exit:
; Move an autorelease past a phi with a null.
-; CHECK-LABEL: define ptr @test65(
-; CHECK: if.then:
-; CHECK: call ptr @llvm.objc.autorelease(
-; CHECK: return:
-; CHECK-NOT: @llvm.objc.autorelease
-; CHECK: {{^}}}
define ptr @test65(i1 %x) {
+; CHECK-LABEL: define ptr @test65(
+; CHECK-SAME: i1 [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: br i1 [[X]], label %[[RETURN:.*]], label %[[IF_THEN:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: [[C:%.*]] = call ptr @returner()
+; CHECK-NEXT: [[S:%.*]] = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[C]]) #[[ATTR0]]
+; CHECK-NEXT: [[Q1:%.*]] = call ptr @llvm.objc.autorelease(ptr [[S]]) #[[ATTR0]]
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: [[RETVAL:%.*]] = phi ptr [ [[S]], %[[IF_THEN]] ], [ null, %[[ENTRY]] ]
+; CHECK-NEXT: ret ptr [[RETVAL]]
+;
entry:
br i1 %x, label %return, label %if.then
@@ -2440,13 +3080,22 @@ return: ; preds = %if.then, %entry
; Don't move an autorelease past an autorelease pool boundary.
-; CHECK-LABEL: define ptr @test65b(
-; CHECK: if.then:
-; CHECK-NOT: @llvm.objc.autorelease
-; CHECK: return:
-; CHECK: call ptr @llvm.objc.autorelease(
-; CHECK: {{^}}}
define ptr @test65b(i1 %x) {
+; CHECK-LABEL: define ptr @test65b(
+; CHECK-SAME: i1 [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[T:%.*]] = call ptr @llvm.objc.autoreleasePoolPush() #[[ATTR0]]
+; CHECK-NEXT: br i1 [[X]], label %[[RETURN:.*]], label %[[IF_THEN:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: [[C:%.*]] = call ptr @returner()
+; CHECK-NEXT: [[S:%.*]] = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[C]]) #[[ATTR0]]
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: [[RETVAL:%.*]] = phi ptr [ [[S]], %[[IF_THEN]] ], [ null, %[[ENTRY]] ]
+; CHECK-NEXT: call void @llvm.objc.autoreleasePoolPop(ptr [[T]]) #[[ATTR0]]
+; CHECK-NEXT: [[Q:%.*]] = call ptr @llvm.objc.autorelease(ptr [[RETVAL]]) #[[ATTR0]]
+; CHECK-NEXT: ret ptr [[RETVAL]]
+;
entry:
%t = call ptr @llvm.objc.autoreleasePoolPush()
br i1 %x, label %return, label %if.then
@@ -2466,13 +3115,20 @@ return: ; preds = %if.then, %entry
; Don't move an autoreleaseReuturnValue, which would break
; the RV optimization.
-; CHECK-LABEL: define ptr @test65c(
-; CHECK: if.then:
-; CHECK-NOT: @llvm.objc.autorelease
-; CHECK: return:
-; CHECK: call ptr @llvm.objc.autoreleaseReturnValue(
-; CHECK: {{^}}}
define ptr @test65c(i1 %x) {
+; CHECK-LABEL: define ptr @test65c(
+; CHECK-SAME: i1 [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: br i1 [[X]], label %[[RETURN:.*]], label %[[IF_THEN:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: [[C:%.*]] = call ptr @returner()
+; CHECK-NEXT: [[S:%.*]] = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[C]]) #[[ATTR0]]
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: [[RETVAL:%.*]] = phi ptr [ [[S]], %[[IF_THEN]] ], [ null, %[[ENTRY]] ]
+; CHECK-NEXT: [[Q:%.*]] = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr [[RETVAL]]) #[[ATTR0]]
+; CHECK-NEXT: ret ptr [[RETVAL]]
+;
entry:
br i1 %x, label %return, label %if.then
@@ -2487,13 +3143,20 @@ return: ; preds = %if.then, %entry
ret ptr %retval
}
-; CHECK-LABEL: define ptr @test65d(
-; CHECK: if.then:
-; CHECK-NOT: @llvm.objc.autorelease
-; CHECK: return:
-; CHECK: call ptr @llvm.objc.autoreleaseReturnValue(
-; CHECK: {{^}}}
define ptr @test65d(i1 %x) {
+; CHECK-LABEL: define ptr @test65d(
+; CHECK-SAME: i1 [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: br i1 [[X]], label %[[RETURN:.*]], label %[[IF_THEN:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: [[C:%.*]] = call ptr @returner()
+; CHECK-NEXT: [[S:%.*]] = tail call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr [[C]]) #[[ATTR0]]
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: [[RETVAL:%.*]] = phi ptr [ [[S]], %[[IF_THEN]] ], [ null, %[[ENTRY]] ]
+; CHECK-NEXT: [[Q:%.*]] = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr [[RETVAL]]) #[[ATTR0]]
+; CHECK-NEXT: ret ptr [[RETVAL]]
+;
entry:
br i1 %x, label %return, label %if.then
@@ -2511,13 +3174,22 @@ return: ; preds = %if.then, %entry
; An llvm.objc.retain can serve as a may-use for a different pointer.
; rdar://11931823
-; CHECK-LABEL: define void @test66a(
-; CHECK: tail call ptr @llvm.objc.retain(ptr %cond) [[NUW]]
-; CHECK: tail call void @llvm.objc.release(ptr %call) [[NUW]]
-; CHECK: tail call ptr @llvm.objc.retain(ptr %tmp8) [[NUW]]
-; CHECK: tail call void @llvm.objc.release(ptr %cond) [[NUW]]
-; CHECK: {{^}}}
define void @test66a(ptr %tmp5, ptr %bar, i1 %tobool, i1 %tobool1, ptr %call) {
+; CHECK-LABEL: define void @test66a(
+; CHECK-SAME: ptr [[TMP5:%.*]], ptr [[BAR:%.*]], i1 [[TOBOOL:%.*]], i1 [[TOBOOL1:%.*]], ptr [[CALL:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: br i1 [[TOBOOL]], label %[[COND_TRUE:.*]], label %[[COND_END:.*]]
+; CHECK: [[COND_TRUE]]:
+; CHECK-NEXT: br label %[[COND_END]]
+; CHECK: [[COND_END]]:
+; CHECK-NEXT: [[COND:%.*]] = phi ptr [ [[TMP5]], %[[COND_TRUE]] ], [ [[CALL]], %[[ENTRY]] ]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[COND]]) #[[ATTR0]]
+; CHECK-NEXT: tail call void @llvm.objc.release(ptr [[CALL]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP8:%.*]] = select i1 [[TOBOOL1]], ptr [[COND]], ptr [[BAR]]
+; CHECK-NEXT: [[TMP9:%.*]] = tail call ptr @llvm.objc.retain(ptr [[TMP8]]) #[[ATTR0]]
+; CHECK-NEXT: tail call void @llvm.objc.release(ptr [[COND]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
br i1 %tobool, label %cond.true, label %cond.end
@@ -2534,13 +3206,22 @@ cond.end: ; preds = %cond.true, %entry
ret void
}
-; CHECK-LABEL: define void @test66b(
-; CHECK: tail call ptr @llvm.objc.retain(ptr %cond) [[NUW]]
-; CHECK: tail call void @llvm.objc.release(ptr %call) [[NUW]]
-; CHECK: tail call ptr @llvm.objc.retain(ptr %tmp8) [[NUW]]
-; CHECK: tail call void @llvm.objc.release(ptr %cond) [[NUW]]
-; CHECK: {{^}}}
define void @test66b(ptr %tmp5, ptr %bar, i1 %tobool, i1 %tobool1, ptr %call) {
+; CHECK-LABEL: define void @test66b(
+; CHECK-SAME: ptr [[TMP5:%.*]], ptr [[BAR:%.*]], i1 [[TOBOOL:%.*]], i1 [[TOBOOL1:%.*]], ptr [[CALL:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: br i1 [[TOBOOL]], label %[[COND_TRUE:.*]], label %[[COND_END:.*]]
+; CHECK: [[COND_TRUE]]:
+; CHECK-NEXT: br label %[[COND_END]]
+; CHECK: [[COND_END]]:
+; CHECK-NEXT: [[COND:%.*]] = phi ptr [ [[TMP5]], %[[COND_TRUE]] ], [ [[CALL]], %[[ENTRY]] ]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[COND]]) #[[ATTR0]]
+; CHECK-NEXT: tail call void @llvm.objc.release(ptr [[CALL]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: [[TMP8:%.*]] = select i1 [[TOBOOL1]], ptr [[COND]], ptr [[BAR]]
+; CHECK-NEXT: [[TMP9:%.*]] = tail call ptr @llvm.objc.retain(ptr [[TMP8]]) #[[ATTR0]]
+; CHECK-NEXT: tail call void @llvm.objc.release(ptr [[COND]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
br i1 %tobool, label %cond.true, label %cond.end
@@ -2557,13 +3238,22 @@ cond.end: ; preds = %cond.true, %entry
ret void
}
-; CHECK-LABEL: define void @test66c(
-; CHECK: tail call ptr @llvm.objc.retain(ptr %cond) [[NUW]]
-; CHECK: tail call void @llvm.objc.release(ptr %call) [[NUW]]
-; CHECK: tail call ptr @llvm.objc.retain(ptr %tmp8) [[NUW]]
-; CHECK: tail call void @llvm.objc.release(ptr %cond) [[NUW]]
-; CHECK: {{^}}}
define void @test66c(ptr %tmp5, ptr %bar, i1 %tobool, i1 %tobool1, ptr %call) {
+; CHECK-LABEL: define void @test66c(
+; CHECK-SAME: ptr [[TMP5:%.*]], ptr [[BAR:%.*]], i1 [[TOBOOL:%.*]], i1 [[TOBOOL1:%.*]], ptr [[CALL:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: br i1 [[TOBOOL]], label %[[COND_TRUE:.*]], label %[[COND_END:.*]]
+; CHECK: [[COND_TRUE]]:
+; CHECK-NEXT: br label %[[COND_END]]
+; CHECK: [[COND_END]]:
+; CHECK-NEXT: [[COND:%.*]] = phi ptr [ [[TMP5]], %[[COND_TRUE]] ], [ [[CALL]], %[[ENTRY]] ]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[COND]]) #[[ATTR0]]
+; CHECK-NEXT: tail call void @llvm.objc.release(ptr [[CALL]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP8:%.*]] = select i1 [[TOBOOL1]], ptr [[COND]], ptr [[BAR]]
+; CHECK-NEXT: [[TMP9:%.*]] = tail call ptr @llvm.objc.retain(ptr [[TMP8]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: tail call void @llvm.objc.release(ptr [[COND]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
br i1 %tobool, label %cond.true, label %cond.end
@@ -2580,13 +3270,22 @@ cond.end: ; preds = %cond.true, %entry
ret void
}
-; CHECK-LABEL: define void @test66d(
-; CHECK: tail call ptr @llvm.objc.retain(ptr %cond) [[NUW]]
-; CHECK: tail call void @llvm.objc.release(ptr %call) [[NUW]]
-; CHECK: tail call ptr @llvm.objc.retain(ptr %tmp8) [[NUW]]
-; CHECK: tail call void @llvm.objc.release(ptr %cond) [[NUW]]
-; CHECK: {{^}}}
define void @test66d(ptr %tmp5, ptr %bar, i1 %tobool, i1 %tobool1, ptr %call) {
+; CHECK-LABEL: define void @test66d(
+; CHECK-SAME: ptr [[TMP5:%.*]], ptr [[BAR:%.*]], i1 [[TOBOOL:%.*]], i1 [[TOBOOL1:%.*]], ptr [[CALL:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: br i1 [[TOBOOL]], label %[[COND_TRUE:.*]], label %[[COND_END:.*]]
+; CHECK: [[COND_TRUE]]:
+; CHECK-NEXT: br label %[[COND_END]]
+; CHECK: [[COND_END]]:
+; CHECK-NEXT: [[COND:%.*]] = phi ptr [ [[TMP5]], %[[COND_TRUE]] ], [ [[CALL]], %[[ENTRY]] ]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[COND]]) #[[ATTR0]]
+; CHECK-NEXT: tail call void @llvm.objc.release(ptr [[CALL]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: [[TMP8:%.*]] = select i1 [[TOBOOL1]], ptr [[COND]], ptr [[BAR]]
+; CHECK-NEXT: [[TMP9:%.*]] = tail call ptr @llvm.objc.retain(ptr [[TMP8]]) #[[ATTR0]]
+; CHECK-NEXT: tail call void @llvm.objc.release(ptr [[COND]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: ret void
+;
entry:
br i1 %tobool, label %cond.true, label %cond.end
@@ -2612,11 +3311,6 @@ declare i32 @puts(ptr captures(none)) nounwind
@str = internal constant [16 x i8] c"-[ Top0 _getX ]\00"
; FIXME: Should be able to eliminate the retain and release
-; CHECK-LABEL: define { <2 x float>, <2 x float> } @"\01-[A z]"(ptr %self, ptr captures(none) %_cmd)
-; CHECK: tail call ptr @llvm.objc.retain(ptr %self)
-; CHECK-NEXT: %call = tail call i32 (ptr, ...) @printf(
-; CHECK: tail call void @llvm.objc.release(ptr %self)
-; CHECK: {{^}}}
define { <2 x float>, <2 x float> } @"\01-[A z]"(ptr %self, ptr captures(none) %_cmd) nounwind {
invoke.cont:
%i1 = tail call ptr @llvm.objc.retain(ptr %self) nounwind
@@ -2645,7 +3339,7 @@ invoke.cont:
tail call void @llvm.objc.release(ptr %self) nounwind
%tmp29 = trunc i128 %srcval to i64
%tmp30 = bitcast i64 %tmp29 to <2 x float>
- %tmp31 = insertvalue { <2 x float>, <2 x float> } undef, <2 x float> %tmp30, 0
+ %tmp31 = insertvalue { <2 x float>, <2 x float> } poison, <2 x float> %tmp30, 0
%tmp32 = lshr i128 %srcval, 64
%tmp33 = trunc i128 %tmp32 to i64
%tmp34 = bitcast i64 %tmp33 to <2 x float>
@@ -2654,10 +3348,6 @@ invoke.cont:
}
; FIXME: Should be able to eliminate the retain and release
-; CHECK-LABEL: @"\01-[Top0 _getX]"(ptr %self, ptr captures(none) %_cmd)
-; CHECK: tail call ptr @llvm.objc.retain(ptr %self)
-; CHECK: %puts = tail call i32 @puts
-; CHECK: tail call void @llvm.objc.release(ptr %self)
define i32 @"\01-[Top0 _getX]"(ptr %self, ptr captures(none) %_cmd) nounwind {
invoke.cont:
%i1 = tail call ptr @llvm.objc.retain(ptr %self) nounwind
@@ -2672,14 +3362,24 @@ invoke.cont:
; A simple loop. Eliminate the retain and release inside of it!
-; CHECK: define void @loop(ptr %x, i64 %n) {
-; CHECK: for.body:
-; CHECK-NOT: @llvm.objc.
-; CHECK: @objc_msgSend
-; CHECK-NOT: @llvm.objc.
-; CHECK: for.end:
-; CHECK: {{^}}}
define void @loop(ptr %x, i64 %n) {
+; CHECK-LABEL: define void @loop(
+; CHECK-SAME: ptr [[X:%.*]], i64 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: [[CMP9:%.*]] = icmp sgt i64 [[N]], 0
+; CHECK-NEXT: br i1 [[CMP9]], label %[[FOR_BODY:.*]], label %[[FOR_END:.*]]
+; CHECK: [[FOR_BODY]]:
+; CHECK-NEXT: [[I_010:%.*]] = phi i64 [ [[INC:%.*]], %[[FOR_BODY]] ], [ 0, %[[ENTRY]] ]
+; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL:%.*]] = tail call ptr (ptr, ptr, ...) @objc_msgSend(ptr [[X]], ptr [[TMP5]])
+; CHECK-NEXT: [[INC]] = add nsw i64 [[I_010]], 1
+; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[INC]], [[N]]
+; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_END]], label %[[FOR_BODY]]
+; CHECK: [[FOR_END]]:
+; CHECK-NEXT: tail call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: ret void
+;
entry:
%0 = tail call ptr @llvm.objc.retain(ptr %x) nounwind
%cmp9 = icmp sgt i64 %n, 0
@@ -2702,9 +3402,6 @@ for.end: ; preds = %for.body, %entry
; ObjCARCOpt can delete the retain,release on self.
-; CHECK: define void @TextEditTest(ptr %self, ptr %pboard) {
-; CHECK-NOT: call ptr @llvm.objc.retain(ptr %tmp7)
-; CHECK: {{^}}}
%0 = type { ptr, ptr }
%1 = type opaque
@@ -2759,6 +3456,133 @@ for.end: ; preds = %for.body, %entry
declare ptr @truncatedString(ptr, i64)
define void @TextEditTest(ptr %self, ptr %pboard) {
+; CHECK-LABEL: define void @TextEditTest(
+; CHECK-SAME: ptr [[SELF:%.*]], ptr [[PBOARD:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[ERR:%.*]] = alloca ptr, align 8
+; CHECK-NEXT: store ptr null, ptr [[ERR]], align 8
+; CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_17", align 8
+; CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr @kUTTypePlainText, align 8
+; CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_19", align 8
+; CHECK-NEXT: [[CALL5:%.*]] = call ptr (ptr, ptr, ...) @objc_msgSend(ptr [[TMP1]], ptr [[TMP3]], ptr [[TMP2]])
+; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_21", align 8
+; CHECK-NEXT: [[CALL76:%.*]] = call ptr (ptr, ptr, ...) @objc_msgSend(ptr [[PBOARD]], ptr [[TMP5]], ptr [[CALL5]])
+; CHECK-NEXT: [[TMP9:%.*]] = tail call ptr @llvm.objc.retain(ptr [[CALL76]]) #[[ATTR0]]
+; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq ptr [[TMP9]], null
+; CHECK-NEXT: br i1 [[TOBOOL]], label %[[END:.*]], label %[[LAND_LHS_TRUE:.*]]
+; CHECK: [[LAND_LHS_TRUE]]:
+; CHECK-NEXT: [[TMP11:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_23", align 8
+; CHECK-NEXT: [[CALL137:%.*]] = call ptr (ptr, ptr, ...) @objc_msgSend(ptr [[PBOARD]], ptr [[TMP11]], ptr [[TMP9]])
+; CHECK-NEXT: [[TMP10:%.*]] = tail call ptr @llvm.objc.retain(ptr [[CALL137]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP12:%.*]] = tail call ptr @llvm.objc.retain(ptr [[CALL137]]) #[[ATTR0]]
+; CHECK-NEXT: [[TOBOOL16:%.*]] = icmp eq ptr [[CALL137]], null
+; CHECK-NEXT: br i1 [[TOBOOL16]], label %[[END]], label %[[IF_THEN:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: [[TMP19:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_25", align 8
+; CHECK-NEXT: [[CALL21:%.*]] = call signext i8 @objc_msgSend(ptr [[CALL137]], ptr [[TMP19]])
+; CHECK-NEXT: [[TOBOOL22:%.*]] = icmp eq i8 [[CALL21]], 0
+; CHECK-NEXT: br i1 [[TOBOOL22]], label %[[IF_THEN44:.*]], label %[[LAND_LHS_TRUE23:.*]]
+; CHECK: [[LAND_LHS_TRUE23]]:
+; CHECK-NEXT: [[TMP24:%.*]] = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_26", align 8
+; CHECK-NEXT: [[TMP26:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_28", align 8
+; CHECK-NEXT: [[CALL2822:%.*]] = call ptr (ptr, ptr, ...) @objc_msgSend(ptr [[TMP24]], ptr [[TMP26]], ptr [[CALL137]])
+; CHECK-NEXT: [[TMP14:%.*]] = tail call ptr @llvm.objc.retain(ptr [[CALL2822]]) #[[ATTR0]]
+; CHECK-NEXT: [[TOBOOL30:%.*]] = icmp eq ptr [[CALL2822]], null
+; CHECK-NEXT: br i1 [[TOBOOL30]], label %[[IF_THEN44]], label %[[IF_END:.*]]
+; CHECK: [[IF_END]]:
+; CHECK-NEXT: [[TMP32:%.*]] = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_29", align 8
+; CHECK-NEXT: [[TMP33:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_31", align 8
+; CHECK-NEXT: [[CALL35:%.*]] = call ptr (ptr, ptr, ...) @objc_msgSend(ptr [[TMP32]], ptr [[TMP33]])
+; CHECK-NEXT: [[TMP37:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_33", align 8
+; CHECK-NEXT: [[CALL3923:%.*]] = call ptr (ptr, ptr, ...) @objc_msgSend(ptr [[CALL35]], ptr [[TMP37]], ptr [[CALL2822]], i32 signext 1, ptr [[ERR]])
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[CALL3923]], null
+; CHECK-NEXT: br i1 [[CMP]], label %[[IF_THEN44]], label %[[END]]
+; CHECK: [[IF_THEN44]]:
+; CHECK-NEXT: [[URL_025:%.*]] = phi ptr [ [[CALL2822]], %[[IF_END]] ], [ [[CALL2822]], %[[LAND_LHS_TRUE23]] ], [ null, %[[IF_THEN]] ]
+; CHECK-NEXT: [[TMP49:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_35", align 8
+; CHECK-NEXT: [[CALL51:%.*]] = call [[STRUCT__NSRANGE:%.*]] @[[OBJC_MSGSEND:[a-zA-Z0-9_$\"\\.-]*[a-zA-Z_$\"\\.-][a-zA-Z0-9_$\"\\.-]*]](ptr [[CALL137]], ptr [[TMP49]], i64 0, i64 0)
+; CHECK-NEXT: [[CALL513:%.*]] = extractvalue [[STRUCT__NSRANGE]] [[CALL51]], 0
+; CHECK-NEXT: [[CALL514:%.*]] = extractvalue [[STRUCT__NSRANGE]] [[CALL51]], 1
+; CHECK-NEXT: [[TMP52:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_37", align 8
+; CHECK-NEXT: [[CALL548:%.*]] = call ptr (ptr, ptr, ...) @objc_msgSend(ptr [[CALL137]], ptr [[TMP52]], i64 [[CALL513]], i64 [[CALL514]])
+; CHECK-NEXT: [[TMP55:%.*]] = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_38", align 8
+; CHECK-NEXT: [[TMP56:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_40", align 8
+; CHECK-NEXT: [[CALL58:%.*]] = call ptr (ptr, ptr, ...) @objc_msgSend(ptr [[TMP55]], ptr [[TMP56]])
+; CHECK-NEXT: [[TMP59:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_42", align 8
+; CHECK-NEXT: [[CALL6110:%.*]] = call ptr (ptr, ptr, ...) @objc_msgSend(ptr [[CALL548]], ptr [[TMP59]], ptr [[CALL58]])
+; CHECK-NEXT: [[TMP15:%.*]] = tail call ptr @llvm.objc.retain(ptr [[CALL6110]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[CALL137]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP64:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_46", align 8
+; CHECK-NEXT: [[CALL66:%.*]] = call signext i8 @objc_msgSend(ptr [[CALL6110]], ptr [[TMP64]], ptr @_unnamed_cfstring_44)
+; CHECK-NEXT: [[TOBOOL67:%.*]] = icmp eq i8 [[CALL66]], 0
+; CHECK-NEXT: br i1 [[TOBOOL67]], label %[[IF_END74:.*]], label %[[IF_THEN68:.*]]
+; CHECK: [[IF_THEN68]]:
+; CHECK-NEXT: [[TMP70:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_48", align 8
+; CHECK-NEXT: [[CALL7220:%.*]] = call ptr (ptr, ptr, ...) @objc_msgSend(ptr [[CALL6110]], ptr [[TMP70]])
+; CHECK-NEXT: [[TMP16:%.*]] = tail call ptr @llvm.objc.retain(ptr [[CALL7220]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[CALL6110]]) #[[ATTR0]]
+; CHECK-NEXT: br label %[[IF_END74]]
+; CHECK: [[IF_END74]]:
+; CHECK-NEXT: [[FILENAME_0_IN:%.*]] = phi ptr [ [[CALL7220]], %[[IF_THEN68]] ], [ [[CALL6110]], %[[IF_THEN44]] ]
+; CHECK-NEXT: [[TMP17:%.*]] = load ptr, ptr @"\01l_objc_msgSend_fixup_isEqual_", align 16
+; CHECK-NEXT: [[CALL78:%.*]] = call signext i8 (ptr, ptr, ptr, ...) [[TMP17]](ptr [[CALL137]], ptr @"\01l_objc_msgSend_fixup_isEqual_", ptr [[FILENAME_0_IN]])
+; CHECK-NEXT: [[TOBOOL79:%.*]] = icmp eq i8 [[CALL78]], 0
+; CHECK-NEXT: br i1 [[TOBOOL79]], label %[[LAND_LHS_TRUE80:.*]], label %[[IF_THEN109:.*]]
+; CHECK: [[LAND_LHS_TRUE80]]:
+; CHECK-NEXT: [[TMP82:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_25", align 8
+; CHECK-NEXT: [[CALL84:%.*]] = call signext i8 @objc_msgSend(ptr [[FILENAME_0_IN]], ptr [[TMP82]])
+; CHECK-NEXT: [[TOBOOL86:%.*]] = icmp eq i8 [[CALL84]], 0
+; CHECK-NEXT: br i1 [[TOBOOL86]], label %[[IF_THEN109]], label %[[IF_END106:.*]]
+; CHECK: [[IF_END106]]:
+; CHECK-NEXT: [[TMP88:%.*]] = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_26", align 8
+; CHECK-NEXT: [[TMP90:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_28", align 8
+; CHECK-NEXT: [[CALL9218:%.*]] = call ptr (ptr, ptr, ...) @objc_msgSend(ptr [[TMP88]], ptr [[TMP90]], ptr [[FILENAME_0_IN]])
+; CHECK-NEXT: [[TMP21:%.*]] = tail call ptr @llvm.objc.retain(ptr [[CALL9218]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[URL_025]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP94:%.*]] = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_29", align 8
+; CHECK-NEXT: [[TMP95:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_31", align 8
+; CHECK-NEXT: [[CALL97:%.*]] = call ptr (ptr, ptr, ...) @objc_msgSend(ptr [[TMP94]], ptr [[TMP95]])
+; CHECK-NEXT: [[TMP99:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_33", align 8
+; CHECK-NEXT: [[CALL10119:%.*]] = call ptr (ptr, ptr, ...) @objc_msgSend(ptr [[CALL97]], ptr [[TMP99]], ptr [[CALL9218]], i32 signext 1, ptr [[ERR]])
+; CHECK-NEXT: [[PHITMP:%.*]] = icmp eq ptr [[CALL10119]], null
+; CHECK-NEXT: br i1 [[PHITMP]], label %[[IF_THEN109]], label %[[END]]
+; CHECK: [[IF_THEN109]]:
+; CHECK-NEXT: [[URL_129:%.*]] = phi ptr [ [[CALL9218]], %[[IF_END106]] ], [ [[URL_025]], %[[IF_END74]] ], [ [[URL_025]], %[[LAND_LHS_TRUE80]] ]
+; CHECK-NEXT: [[TMP110:%.*]] = load ptr, ptr [[ERR]], align 8
+; CHECK-NEXT: [[TOBOOL111:%.*]] = icmp eq ptr [[TMP110]], null
+; CHECK-NEXT: br i1 [[TOBOOL111]], label %[[IF_THEN112:.*]], label %[[IF_END125:.*]]
+; CHECK: [[IF_THEN112]]:
+; CHECK-NEXT: [[TMP113:%.*]] = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_50", align 8
+; CHECK-NEXT: [[TMP114:%.*]] = load ptr, ptr @NSCocoaErrorDomain, align 8
+; CHECK-NEXT: [[TMP115:%.*]] = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_51", align 8
+; CHECK-NEXT: [[CALL117:%.*]] = call ptr @truncatedString(ptr [[FILENAME_0_IN]], i64 1034)
+; CHECK-NEXT: [[TMP118:%.*]] = load ptr, ptr @NSFilePathErrorKey, align 8
+; CHECK-NEXT: [[TMP119:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_53", align 8
+; CHECK-NEXT: [[CALL12113:%.*]] = call ptr (ptr, ptr, ...) @objc_msgSend(ptr [[TMP115]], ptr [[TMP119]], ptr [[CALL117]], ptr [[TMP118]], ptr null)
+; CHECK-NEXT: [[TMP122:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_55", align 8
+; CHECK-NEXT: [[CALL12414:%.*]] = call ptr (ptr, ptr, ...) @objc_msgSend(ptr [[TMP113]], ptr [[TMP122]], ptr [[TMP114]], i64 258, ptr [[CALL12113]])
+; CHECK-NEXT: [[TMP23:%.*]] = tail call ptr @llvm.objc.retain(ptr [[CALL12414]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP25:%.*]] = call ptr @llvm.objc.autorelease(ptr [[TMP23]]) #[[ATTR0]]
+; CHECK-NEXT: store ptr [[TMP25]], ptr [[ERR]], align 8
+; CHECK-NEXT: br label %[[IF_END125]]
+; CHECK: [[IF_END125]]:
+; CHECK-NEXT: [[TMP127:%.*]] = phi ptr [ [[TMP110]], %[[IF_THEN109]] ], [ [[TMP25]], %[[IF_THEN112]] ]
+; CHECK-NEXT: [[TMP126:%.*]] = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_56", align 8
+; CHECK-NEXT: [[TMP128:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_58", align 8
+; CHECK-NEXT: [[CALL13015:%.*]] = call ptr (ptr, ptr, ...) @objc_msgSend(ptr [[TMP126]], ptr [[TMP128]], ptr [[TMP127]])
+; CHECK-NEXT: [[TMP131:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_60", align 8
+; CHECK-NEXT: [[CALL13317:%.*]] = call ptr (ptr, ptr, ...) @objc_msgSend(ptr [[CALL13015]], ptr [[TMP131]])
+; CHECK-NEXT: br label %[[END]]
+; CHECK: [[END]]:
+; CHECK-NEXT: [[FILENAME_2:%.*]] = phi ptr [ [[FILENAME_0_IN]], %[[IF_END106]] ], [ [[FILENAME_0_IN]], %[[IF_END125]] ], [ [[CALL137]], %[[LAND_LHS_TRUE]] ], [ null, %[[ENTRY]] ], [ [[CALL137]], %[[IF_END]] ]
+; CHECK-NEXT: [[ORIGFILENAME_0:%.*]] = phi ptr [ [[CALL137]], %[[IF_END106]] ], [ [[CALL137]], %[[IF_END125]] ], [ [[CALL137]], %[[LAND_LHS_TRUE]] ], [ null, %[[ENTRY]] ], [ [[CALL137]], %[[IF_END]] ]
+; CHECK-NEXT: [[URL_2:%.*]] = phi ptr [ [[CALL9218]], %[[IF_END106]] ], [ [[URL_129]], %[[IF_END125]] ], [ null, %[[LAND_LHS_TRUE]] ], [ null, %[[ENTRY]] ], [ [[CALL2822]], %[[IF_END]] ]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP9]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[URL_2]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[ORIGFILENAME_0]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[FILENAME_2]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: ret void
+;
entry:
%err = alloca ptr, align 8
%tmp8 = call ptr @llvm.objc.retain(ptr %self) nounwind
@@ -2911,12 +3735,13 @@ declare i32 @llvm.objc.sync.exit(ptr)
; Make sure that we understand that objc_sync_{enter,exit} are IC_User not
; IC_Call/IC_CallOrUser.
-; CHECK-LABEL: define void @test67(
-; CHECK-NEXT: call i32 @llvm.objc.sync.enter(ptr %x)
-; CHECK-NEXT: call i32 @llvm.objc.sync.exit(ptr %x)
-; CHECK-NEXT: ret void
-; CHECK-NEXT: }
define void @test67(ptr %x) {
+; CHECK-LABEL: define void @test67(
+; CHECK-SAME: ptr [[X:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.objc.sync.enter(ptr [[X]])
+; CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.objc.sync.exit(ptr [[X]])
+; CHECK-NEXT: ret void
+;
call ptr @llvm.objc.retain(ptr %x)
call i32 @llvm.objc.sync.enter(ptr %x)
call i32 @llvm.objc.sync.exit(ptr %x)
@@ -2924,13 +3749,13 @@ define void @test67(ptr %x) {
ret void
}
-; CHECK-LABEL: define void @test68(
-; CHECK-NOT: call
-; CHECK: call void @callee2(
-; CHECK-NOT: call
-; CHECK: ret void
define void @test68(ptr %a, ptr %b) {
+; CHECK-LABEL: define void @test68(
+; CHECK-SAME: ptr [[A:%.*]], ptr [[B:%.*]]) {
+; CHECK-NEXT: call void @callee2(ptr [[A]], ptr [[B]])
+; CHECK-NEXT: ret void
+;
call ptr @llvm.objc.retain(ptr %a)
call ptr @llvm.objc.retain(ptr %b)
call void @callee2(ptr %a, ptr %b)
@@ -2946,13 +3771,14 @@ define void @test68(ptr %a, ptr %b) {
!1 = !{i32 1, !"Debug Info Version", i32 3}
!2 = distinct !DISubprogram(unit: !3, type: !7)
!3 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang",
- file: !4,
- isOptimized: true, flags: "-O2",
- splitDebugFilename: "abc.debug", emissionKind: 2)
+ file: !4,
+ isOptimized: true, flags: "-O2",
+ splitDebugFilename: "abc.debug", emissionKind: 2)
!4 = !DIFile(filename: "path/to/file", directory: "/path/to/dir")
!5 = !{i32 2, !"Debug Info Version", i32 3}
-; CHECK: attributes [[NUW]] = { nounwind }
-; CHECK: ![[RELEASE]] = !{}
!6 = !{null}
!7 = !DISubroutineType(types: !6)
+;.
+; CHECK: [[META3]] = !{}
+;.
diff --git a/llvm/test/Transforms/ObjCARC/test_autorelease_pool.ll b/llvm/test/Transforms/ObjCARC/test_autorelease_pool.ll
index a25d85a76d1b0..495e68e412699 100644
--- a/llvm/test/Transforms/ObjCARC/test_autorelease_pool.ll
+++ b/llvm/test/Transforms/ObjCARC/test_autorelease_pool.ll
@@ -211,9 +211,7 @@ define void @test_complex_shadowing() {
; CHECK-NEXT: [[OBJ3:%.*]] = call ptr @create_object()
; CHECK-NEXT: call void @llvm.objc.release(ptr [[OBJ1]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
; CHECK-NEXT: call void @llvm.objc.release(ptr [[OBJ2]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
-; CHECK-NEXT: [[INNER2_POOL:%.*]] = call ptr @llvm.objc.autoreleasePoolPush() #[[ATTR0]]
-; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.objc.autorelease(ptr [[OBJ3]]) #[[ATTR0]]
-; CHECK-NEXT: call void @llvm.objc.autoreleasePoolPop(ptr [[INNER2_POOL]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[OBJ3]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
; CHECK-NEXT: ret void
;
%obj1 = call ptr @create_object()
More information about the llvm-commits
mailing list