[llvm] Think in terms of blocks for ARC (PR #130860)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Mar 14 06:33:34 PDT 2025
https://github.com/AZero13 updated https://github.com/llvm/llvm-project/pull/130860
>From fe3610f44aa72c79447c4e2c6164d0f3aeaf98d3 Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Mon, 10 Mar 2025 14:24:09 -0400
Subject: [PATCH] Think in terms of blocks
Handle critical edges for ObjCARC
---
llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp | 102 +-
llvm/test/Transforms/ObjCARC/allocas.ll | 403 ++-
llvm/test/Transforms/ObjCARC/basic.ll | 2234 +++++++++++------
.../ObjCARC/clang-arc-use-barrier.ll | 27 +-
llvm/test/Transforms/ObjCARC/code-motion.ll | 106 +-
.../Transforms/ObjCARC/funclet-catchpad.ll | 29 +-
llvm/test/Transforms/ObjCARC/intrinsic-use.ll | 106 +-
llvm/test/Transforms/ObjCARC/invoke.ll | 211 +-
llvm/test/Transforms/ObjCARC/nested.ll | 658 ++++-
.../test/Transforms/ObjCARC/split-backedge.ll | 42 +-
10 files changed, 2854 insertions(+), 1064 deletions(-)
diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
index 9d7f5e64f9868..60bd238476f03 100644
--- a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
+++ b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
@@ -138,12 +138,6 @@ static const Value *FindSingleUseIdentifiedObject(const Value *Arg) {
// calls followed by objc_autoreleasePoolPop calls (perhaps in ObjC++ code
// after inlining) can be turned into plain release calls.
-// TODO: Critical-edge splitting. If the optimial insertion point is
-// a critical edge, the current algorithm has to fail, because it doesn't
-// know how to split edges. It should be possible to make the optimizer
-// think in terms of edges, rather than blocks, and then split critical
-// edges on demand.
-
// TODO: OptimizeSequences could generalized to be Interprocedural.
// TODO: Recognize that a bunch of other objc runtime calls have
@@ -599,6 +593,7 @@ class ObjCARCOpt {
void init(Function &F);
bool run(Function &F, AAResults &AA);
bool hasCFGChanged() const { return CFGChanged; }
+ BasicBlock *SplitCriticalEdge(BasicBlock *Pred, BasicBlock *Succ);
};
} // end anonymous namespace
@@ -1765,8 +1760,50 @@ void ObjCARCOpt::MoveCalls(Value *Arg, RRInfo &RetainsToMove,
Module *M) {
LLVM_DEBUG(dbgs() << "== ObjCARCOpt::MoveCalls ==\n");
- // Insert the new retain and release calls.
+ // First, handle critical edges for retain insertion points
+ SmallVector<Instruction *, 4> NewRetainInsertPts;
+ for (Instruction *InsertPt : RetainsToMove.ReverseInsertPts) {
+ BasicBlock *BB = InsertPt->getParent();
+ BasicBlock *Pred = BB->getUniquePredecessor();
+
+ // If this is a critical edge, split it
+ if (!Pred && BB->hasNPredecessors(1)) {
+ for (BasicBlock *PredBB : predecessors(BB)) {
+ if (PredBB->getTerminator()->getNumSuccessors() > 1) {
+ if (BasicBlock *NewBB = SplitCriticalEdge(PredBB, BB)) {
+ // Add the new block as an insertion point
+ NewRetainInsertPts.push_back(NewBB->getTerminator());
+ }
+ }
+ }
+ } else {
+ NewRetainInsertPts.push_back(InsertPt);
+ }
+ }
+
+ // Then handle critical edges for release insertion points
+ SmallVector<Instruction *, 4> NewReleaseInsertPts;
for (Instruction *InsertPt : ReleasesToMove.ReverseInsertPts) {
+ BasicBlock *BB = InsertPt->getParent();
+ BasicBlock *Pred = BB->getUniquePredecessor();
+
+ // If this is a critical edge, split it
+ if (!Pred && BB->hasNPredecessors(1)) {
+ for (BasicBlock *PredBB : predecessors(BB)) {
+ if (PredBB->getTerminator()->getNumSuccessors() > 1) {
+ if (BasicBlock *NewBB = SplitCriticalEdge(PredBB, BB)) {
+ // Add the new block as an insertion point
+ NewReleaseInsertPts.push_back(NewBB->getTerminator());
+ }
+ }
+ }
+ } else {
+ NewReleaseInsertPts.push_back(InsertPt);
+ }
+ }
+
+ // Now insert the new retain calls at the split points
+ for (Instruction *InsertPt : NewRetainInsertPts) {
Function *Decl = EP.get(ARCRuntimeEntryPointKind::Retain);
SmallVector<OperandBundleDef, 1> BundleList;
addOpBundleForFunclet(InsertPt->getParent(), BundleList);
@@ -1780,7 +1817,9 @@ void ObjCARCOpt::MoveCalls(Value *Arg, RRInfo &RetainsToMove,
"At insertion point: "
<< *InsertPt << "\n");
}
- for (Instruction *InsertPt : RetainsToMove.ReverseInsertPts) {
+
+ // And insert the new release calls at the split points
+ for (Instruction *InsertPt : NewReleaseInsertPts) {
Function *Decl = EP.get(ARCRuntimeEntryPointKind::Release);
SmallVector<OperandBundleDef, 1> BundleList;
addOpBundleForFunclet(InsertPt->getParent(), BundleList);
@@ -2488,6 +2527,53 @@ bool ObjCARCOpt::run(Function &F, AAResults &AA) {
return Changed;
}
+/// Split critical edges where we need to insert retain/release calls
+BasicBlock *ObjCARCOpt::SplitCriticalEdge(BasicBlock *Pred, BasicBlock *Succ) {
+ // Don't split if either block is a landing pad - we want to maintain
+ // the property that landing pads have exactly one predecessor
+ if (Succ->isLandingPad() || isa<InvokeInst>(Pred->getTerminator()))
+ return nullptr;
+
+ // We need both multiple successors in predecessor and
+ // multiple predecessors in successor
+ if (Pred->getTerminator()->getNumSuccessors() <= 1 ||
+ Succ->getUniquePredecessor())
+ return nullptr;
+
+ // Create a new basic block for the split edge
+ BasicBlock *NewBB = BasicBlock::Create(
+ Pred->getContext(), Pred->getName() + "." + Succ->getName() + ".arc",
+ Pred->getParent());
+
+ // Update the terminator of Pred to branch to NewBB instead of Succ
+ BranchInst *Term = cast<BranchInst>(Pred->getTerminator());
+ for (unsigned i = 0, e = Term->getNumSuccessors(); i != e; ++i) {
+ if (Term->getSuccessor(i) == Succ) {
+ Term->setSuccessor(i, NewBB);
+ break;
+ }
+ }
+
+ // Create an unconditional branch from NewBB to Succ
+ BranchInst::Create(Succ, NewBB);
+
+ // Update PHI nodes in Succ
+ for (PHINode &PHI : Succ->phis()) {
+ Value *V = PHI.getIncomingValueForBlock(Pred);
+ PHI.setIncomingBlock(PHI.getBasicBlockIndex(Pred), NewBB);
+ PHI.addIncoming(V, Pred);
+ }
+
+ // Update any funclet bundles
+ if (!BlockEHColors.empty()) {
+ const ColorVector &CV = BlockEHColors.find(Pred)->second;
+ BlockEHColors[NewBB] = CV;
+ }
+
+ CFGChanged = true;
+ return NewBB;
+}
+
/// @}
///
diff --git a/llvm/test/Transforms/ObjCARC/allocas.ll b/llvm/test/Transforms/ObjCARC/allocas.ll
index 6fe2edf3e2dd4..03f428e96683e 100644
--- a/llvm/test/Transforms/ObjCARC/allocas.ll
+++ b/llvm/test/Transforms/ObjCARC/allocas.ll
@@ -1,3 +1,4 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -passes=objc-arc -S < %s | FileCheck %s
declare ptr @llvm.objc.retain(ptr)
@@ -31,7 +32,7 @@ declare ptr @objc_msgSend(ptr, ptr, ...)
; In the presence of allocas, unconditionally remove retain/release pairs only
; if they are known safe in both directions. This prevents matching up an inner
; retain with the boundary guarding release in the following situation:
-;
+;
; %A = alloca
; retain(%x)
; retain(%x) <--- Inner Retain
@@ -43,14 +44,21 @@ declare ptr @objc_msgSend(ptr, ptr, ...)
;
; rdar://13750319
-; CHECK: define void @test1a(ptr %x)
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.release(ptr %y)
-; CHECK: @llvm.objc.release(ptr %x)
-; CHECK: ret void
-; CHECK: }
define void @test1a(ptr %x) {
+; CHECK-LABEL: define void @test1a(
+; CHECK-SAME: ptr [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[A:%.*]] = alloca ptr, align 8
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0:[0-9]+]]
+; CHECK-NEXT: store ptr [[X]], ptr [[A]], align 8
+; CHECK-NEXT: [[Y:%.*]] = load ptr, ptr [[A]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META0:![0-9]+]]
+; CHECK-NEXT: call void @use_alloca(ptr [[A]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[Y]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%A = alloca ptr
tail call ptr @llvm.objc.retain(ptr %x)
@@ -64,14 +72,21 @@ entry:
ret void
}
-; CHECK: define void @test1b(ptr %x)
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.release(ptr %y)
-; CHECK: @llvm.objc.release(ptr %x)
-; CHECK: ret void
-; CHECK: }
define void @test1b(ptr %x) {
+; CHECK-LABEL: define void @test1b(
+; CHECK-SAME: ptr [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[A:%.*]] = alloca ptr, align 8
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: store ptr [[X]], ptr [[A]], align 8
+; CHECK-NEXT: [[Y:%.*]] = load ptr, ptr [[A]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @use_alloca(ptr [[A]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[Y]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%A = alloca ptr
tail call ptr @llvm.objc.retain(ptr %x)
@@ -86,14 +101,22 @@ entry:
}
-; CHECK: define void @test1c(ptr %x)
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.release(ptr %y)
-; CHECK: @llvm.objc.release(ptr %x)
-; CHECK: ret void
-; CHECK: }
define void @test1c(ptr %x) {
+; CHECK-LABEL: define void @test1c(
+; CHECK-SAME: ptr [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[A:%.*]] = alloca ptr, i32 3, align 8
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr ptr, ptr [[A]], i32 2
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: store ptr [[X]], ptr [[GEP]], align 8
+; CHECK-NEXT: [[Y:%.*]] = load ptr, ptr [[GEP]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @use_alloca(ptr [[A]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[Y]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%A = alloca ptr, i32 3
%gep = getelementptr ptr, ptr %A, i32 2
@@ -109,14 +132,29 @@ entry:
}
-; CHECK: define void @test1d(ptr %x, i1 %arg)
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.release(ptr %y)
-; CHECK: @llvm.objc.release(ptr %x)
-; CHECK: ret void
-; CHECK: }
define void @test1d(ptr %x, i1 %arg) {
+; CHECK-LABEL: define void @test1d(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[ARG:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[ARG]], label %[[USE_ALLOCAA:.*]], label %[[USE_ALLOCAB:.*]]
+; CHECK: [[USE_ALLOCAA]]:
+; CHECK-NEXT: [[ALLOCAA:%.*]] = alloca ptr, align 8
+; CHECK-NEXT: br label %[[EXIT:.*]]
+; CHECK: [[USE_ALLOCAB]]:
+; CHECK-NEXT: [[ALLOCAB:%.*]] = alloca ptr, align 8
+; CHECK-NEXT: br label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: [[A:%.*]] = phi ptr [ [[ALLOCAA]], %[[USE_ALLOCAA]] ], [ [[ALLOCAB]], %[[USE_ALLOCAB]] ]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: store ptr [[X]], ptr [[A]], align 8
+; CHECK-NEXT: [[Y:%.*]] = load ptr, ptr [[A]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @use_alloca(ptr [[A]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[Y]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
br i1 %arg, label %use_allocaA, label %use_allocaB
@@ -141,14 +179,30 @@ exit:
ret void
}
-; CHECK: define void @test1e(ptr %x, i1 %arg)
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.release(ptr %y)
-; CHECK: @llvm.objc.release(ptr %x)
-; CHECK: ret void
-; CHECK: }
define void @test1e(ptr %x, i1 %arg) {
+; CHECK-LABEL: define void @test1e(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[ARG:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[ARG]], label %[[USE_ALLOCAA:.*]], label %[[USE_ALLOCAB:.*]]
+; CHECK: [[USE_ALLOCAA]]:
+; CHECK-NEXT: [[ALLOCAA:%.*]] = alloca ptr, i32 4, align 8
+; CHECK-NEXT: br label %[[EXIT:.*]]
+; CHECK: [[USE_ALLOCAB]]:
+; CHECK-NEXT: [[ALLOCAB:%.*]] = alloca ptr, i32 4, align 8
+; CHECK-NEXT: br label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: [[A:%.*]] = phi ptr [ [[ALLOCAA]], %[[USE_ALLOCAA]] ], [ [[ALLOCAB]], %[[USE_ALLOCAB]] ]
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr ptr, ptr [[A]], i32 2
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: store ptr [[X]], ptr [[GEP]], align 8
+; CHECK-NEXT: [[Y:%.*]] = load ptr, ptr [[GEP]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @use_alloca(ptr [[A]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[Y]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
br i1 %arg, label %use_allocaA, label %use_allocaB
@@ -174,14 +228,23 @@ exit:
ret void
}
-; CHECK: define void @test1f(ptr %x)
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.release(ptr %y)
-; CHECK: @llvm.objc.release(ptr %x)
-; CHECK: ret void
-; CHECK: }
define void @test1f(ptr %x) {
+; CHECK-LABEL: define void @test1f(
+; CHECK-SAME: ptr [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[ALLOCAONE:%.*]] = alloca ptr, align 8
+; CHECK-NEXT: [[ALLOCATWO:%.*]] = alloca ptr, align 8
+; CHECK-NEXT: [[A:%.*]] = select i1 undef, ptr [[ALLOCAONE]], ptr [[ALLOCATWO]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: store ptr [[X]], ptr [[A]], align 8
+; CHECK-NEXT: [[Y:%.*]] = load ptr, ptr [[A]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @use_alloca(ptr [[A]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[Y]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%allocaOne = alloca ptr
%allocaTwo = alloca ptr
@@ -201,14 +264,27 @@ entry:
; conservatively.
-; CHECK: define void @test2a(ptr %x)
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.release(ptr %y)
-; CHECK: @llvm.objc.release(ptr %x)
-; CHECK: ret void
-; CHECK: }
define void @test2a(ptr %x) {
+; CHECK-LABEL: define void @test2a(
+; CHECK-SAME: ptr [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[A:%.*]] = alloca ptr, align 8
+; CHECK-NEXT: store ptr [[X]], ptr [[A]], align 8
+; CHECK-NEXT: [[Y:%.*]] = load ptr, ptr [[A]], align 8
+; CHECK-NEXT: br label %[[BB1:.*]]
+; CHECK: [[BB1]]:
+; CHECK-NEXT: br label %[[BB2:.*]]
+; CHECK: [[BB2]]:
+; CHECK-NEXT: br label %[[BB3:.*]]
+; CHECK: [[BB3]]:
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @use_alloca(ptr [[A]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[Y]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%A = alloca ptr
store ptr %x, ptr %A, align 8
@@ -231,14 +307,27 @@ bb3:
ret void
}
-; CHECK: define void @test2b(ptr %x)
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.release(ptr %y)
-; CHECK: @llvm.objc.release(ptr %x)
-; CHECK: ret void
-; CHECK: }
define void @test2b(ptr %x) {
+; CHECK-LABEL: define void @test2b(
+; CHECK-SAME: ptr [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[A:%.*]] = alloca ptr, align 8
+; CHECK-NEXT: store ptr [[X]], ptr [[A]], align 8
+; CHECK-NEXT: [[Y:%.*]] = load ptr, ptr [[A]], align 8
+; CHECK-NEXT: br label %[[BB1:.*]]
+; CHECK: [[BB1]]:
+; CHECK-NEXT: br label %[[BB2:.*]]
+; CHECK: [[BB2]]:
+; CHECK-NEXT: br label %[[BB3:.*]]
+; CHECK: [[BB3]]:
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @use_alloca(ptr [[A]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[Y]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%A = alloca ptr
store ptr %x, ptr %A, align 8
@@ -261,14 +350,29 @@ bb3:
ret void
}
-; CHECK: define void @test2c(ptr %x)
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.release(ptr %y)
-; CHECK: @llvm.objc.release(ptr %x)
-; CHECK: ret void
-; CHECK: }
define void @test2c(ptr %x) {
+; CHECK-LABEL: define void @test2c(
+; CHECK-SAME: ptr [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[A:%.*]] = alloca ptr, i32 3, align 8
+; CHECK-NEXT: [[GEP1:%.*]] = getelementptr ptr, ptr [[A]], i32 2
+; CHECK-NEXT: store ptr [[X]], ptr [[GEP1]], align 8
+; CHECK-NEXT: [[GEP2:%.*]] = getelementptr ptr, ptr [[A]], i32 2
+; CHECK-NEXT: [[Y:%.*]] = load ptr, ptr [[GEP2]], align 8
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br label %[[BB1:.*]]
+; CHECK: [[BB1]]:
+; CHECK-NEXT: br label %[[BB2:.*]]
+; CHECK: [[BB2]]:
+; CHECK-NEXT: br label %[[BB3:.*]]
+; CHECK: [[BB3]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @use_alloca(ptr [[A]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[Y]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%A = alloca ptr, i32 3
%gep1 = getelementptr ptr, ptr %A, i32 2
@@ -293,14 +397,36 @@ bb3:
ret void
}
-; CHECK: define void @test2d(ptr %x)
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK: @llvm.objc.release(ptr %y)
-; CHECK: @llvm.objc.release(ptr %x)
-; CHECK: ret void
-; CHECK: }
define void @test2d(ptr %x) {
+; CHECK-LABEL: define void @test2d(
+; CHECK-SAME: ptr [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br label %[[BB1:.*]]
+; CHECK: [[BB1]]:
+; CHECK-NEXT: [[ABB1:%.*]] = alloca ptr, i32 3, align 8
+; CHECK-NEXT: [[GEPBB11:%.*]] = getelementptr ptr, ptr [[ABB1]], i32 2
+; CHECK-NEXT: store ptr [[X]], ptr [[GEPBB11]], align 8
+; CHECK-NEXT: [[GEPBB12:%.*]] = getelementptr ptr, ptr [[ABB1]], i32 2
+; CHECK-NEXT: [[YBB1:%.*]] = load ptr, ptr [[GEPBB12]], align 8
+; CHECK-NEXT: br label %[[BB3:.*]]
+; CHECK: [[BB2:.*]]:
+; CHECK-NEXT: [[ABB2:%.*]] = alloca ptr, i32 4, align 8
+; CHECK-NEXT: [[GEPBB21:%.*]] = getelementptr ptr, ptr [[ABB2]], i32 2
+; CHECK-NEXT: store ptr [[X]], ptr [[GEPBB21]], align 8
+; CHECK-NEXT: [[GEPBB22:%.*]] = getelementptr ptr, ptr [[ABB2]], i32 2
+; CHECK-NEXT: [[YBB2:%.*]] = load ptr, ptr [[GEPBB22]], align 8
+; CHECK-NEXT: br label %[[BB3]]
+; CHECK: [[BB3]]:
+; CHECK-NEXT: [[A:%.*]] = phi ptr [ [[ABB1]], %[[BB1]] ], [ [[ABB2]], %[[BB2]] ]
+; CHECK-NEXT: [[Y:%.*]] = phi ptr [ [[YBB1]], %[[BB1]] ], [ [[YBB2]], %[[BB2]] ]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @use_alloca(ptr [[A]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[Y]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
tail call ptr @llvm.objc.retain(ptr %x)
br label %bb1
@@ -338,30 +464,52 @@ bb3:
;
; rdar://13949644
-; CHECK: define void @test3a() {
-; CHECK: entry:
-; CHECK: @llvm.objc.retainAutoreleasedReturnValue
-; CHECK: @llvm.objc.retain
-; CHECK: @llvm.objc.retain
-; CHECK: @llvm.objc.retain
-; CHECK: @llvm.objc.retain
-; CHECK: arraydestroy.body:
-; CHECK: @llvm.objc.release
-; CHECK-NOT: @llvm.objc.release
-; CHECK: arraydestroy.done:
-; CHECK-NOT: @llvm.objc.release
-; CHECK: arraydestroy.body1:
-; CHECK: @llvm.objc.release
-; CHECK-NOT: @llvm.objc.release
-; CHECK: arraydestroy.done1:
-; CHECK: @llvm.objc.release
-; CHECK: ret void
-; CHECK: }
define void @test3a() {
+; CHECK-LABEL: define void @test3a() {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[KEYS:%.*]] = alloca [2 x ptr], align 16
+; CHECK-NEXT: [[OBJS:%.*]] = alloca [2 x ptr], align 16
+; CHECK-NEXT: [[CALL1:%.*]] = call ptr @returner()
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[CALL1]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[CALL1]]) #[[ATTR0]]
+; CHECK-NEXT: store ptr [[CALL1]], ptr [[OBJS]], align 8
+; CHECK-NEXT: [[OBJS_ELT:%.*]] = getelementptr inbounds [2 x ptr], ptr [[OBJS]], i64 0, i64 1
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[CALL1]]) #[[ATTR0]]
+; CHECK-NEXT: store ptr [[CALL1]], ptr [[OBJS_ELT]], align 8
+; CHECK-NEXT: [[CALL2:%.*]] = call ptr @returner1()
+; CHECK-NEXT: [[CALL3:%.*]] = call ptr @returner2()
+; CHECK-NEXT: [[TMP2:%.*]] = tail call ptr @llvm.objc.retain(ptr [[CALL2]]) #[[ATTR0]]
+; CHECK-NEXT: store ptr [[CALL2]], ptr [[KEYS]], align 8
+; CHECK-NEXT: [[KEYS_ELT:%.*]] = getelementptr inbounds [2 x ptr], ptr [[KEYS]], i64 0, i64 1
+; CHECK-NEXT: [[TMP3:%.*]] = tail call ptr @llvm.objc.retain(ptr [[CALL3]]) #[[ATTR0]]
+; CHECK-NEXT: store ptr [[CALL3]], ptr [[KEYS_ELT]], align 8
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [2 x ptr], ptr [[OBJS]], i64 0, i64 2
+; CHECK-NEXT: br label %[[ARRAYDESTROY_BODY:.*]]
+; CHECK: [[ARRAYDESTROY_BODY]]:
+; CHECK-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[GEP]], %[[ENTRY]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], %[[ARRAYDESTROY_BODY]] ]
+; CHECK-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds ptr, ptr [[ARRAYDESTROY_ELEMENTPAST]], i64 -1
+; CHECK-NEXT: [[DESTROY_TMP:%.*]] = load ptr, ptr [[ARRAYDESTROY_ELEMENT]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[DESTROY_TMP]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: [[ARRAYDESTROY_CMP:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[OBJS]]
+; CHECK-NEXT: br i1 [[ARRAYDESTROY_CMP]], label %[[ARRAYDESTROY_DONE:.*]], label %[[ARRAYDESTROY_BODY]]
+; CHECK: [[ARRAYDESTROY_DONE]]:
+; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds [2 x ptr], ptr [[KEYS]], i64 0, i64 2
+; CHECK-NEXT: br label %[[ARRAYDESTROY_BODY1:.*]]
+; CHECK: [[ARRAYDESTROY_BODY1]]:
+; CHECK-NEXT: [[ARRAYDESTROY_ELEMENTPAST1:%.*]] = phi ptr [ [[GEP1]], %[[ARRAYDESTROY_DONE]] ], [ [[ARRAYDESTROY_ELEMENT1:%.*]], %[[ARRAYDESTROY_BODY1]] ]
+; CHECK-NEXT: [[ARRAYDESTROY_ELEMENT1]] = getelementptr inbounds ptr, ptr [[ARRAYDESTROY_ELEMENTPAST1]], i64 -1
+; CHECK-NEXT: [[DESTROY_TMP1:%.*]] = load ptr, ptr [[ARRAYDESTROY_ELEMENT1]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[DESTROY_TMP1]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: [[ARRAYDESTROY_CMP1:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT1]], [[KEYS]]
+; CHECK-NEXT: br i1 [[ARRAYDESTROY_CMP1]], label %[[ARRAYDESTROY_DONE1:.*]], label %[[ARRAYDESTROY_BODY1]]
+; CHECK: [[ARRAYDESTROY_DONE1]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[CALL1]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: ret void
+;
entry:
%keys = alloca [2 x ptr], align 16
%objs = alloca [2 x ptr], align 16
-
+
%call1 = call ptr @returner()
%tmp0 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call1)
@@ -377,8 +525,8 @@ entry:
store ptr %call2, ptr %keys, align 8
%keys.elt = getelementptr inbounds [2 x ptr], ptr %keys, i64 0, i64 1
tail call ptr @llvm.objc.retain(ptr %call3)
- store ptr %call3, ptr %keys.elt
-
+ store ptr %call3, ptr %keys.elt
+
%gep = getelementptr inbounds [2 x ptr], ptr %objs, i64 0, i64 2
br label %arraydestroy.body
@@ -412,30 +560,52 @@ arraydestroy.done1:
;
; rdar://13949644
-; CHECK: define void @test3b() {
-; CHECK: entry:
-; CHECK: @llvm.objc.retainAutoreleasedReturnValue
-; CHECK: @llvm.objc.retain
-; CHECK: @llvm.objc.retain
-; CHECK: @llvm.objc.retain
-; CHECK: @llvm.objc.retain
-; CHECK: arraydestroy.body:
-; CHECK: @llvm.objc.release
-; CHECK-NOT: @llvm.objc.release
-; CHECK: arraydestroy.done:
-; CHECK-NOT: @llvm.objc.release
-; CHECK: arraydestroy.body1:
-; CHECK: @llvm.objc.release
-; CHECK-NOT: @llvm.objc.release
-; CHECK: arraydestroy.done1:
-; CHECK: @llvm.objc.release
-; CHECK: ret void
-; CHECK: }
define void @test3b() {
+; CHECK-LABEL: define void @test3b() {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[KEYS:%.*]] = alloca [2 x ptr], align 16
+; CHECK-NEXT: [[OBJS:%.*]] = alloca [2 x ptr], align 16
+; CHECK-NEXT: [[CALL1:%.*]] = call ptr @returner()
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[CALL1]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[CALL1]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[CALL1]]) #[[ATTR0]]
+; CHECK-NEXT: store ptr [[CALL1]], ptr [[OBJS]], align 8
+; CHECK-NEXT: [[OBJS_ELT:%.*]] = getelementptr inbounds [2 x ptr], ptr [[OBJS]], i64 0, i64 1
+; CHECK-NEXT: store ptr [[CALL1]], ptr [[OBJS_ELT]], align 8
+; CHECK-NEXT: [[CALL2:%.*]] = call ptr @returner1()
+; CHECK-NEXT: [[CALL3:%.*]] = call ptr @returner2()
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[CALL2]]) #[[ATTR0]]
+; CHECK-NEXT: store ptr [[CALL2]], ptr [[KEYS]], align 8
+; CHECK-NEXT: [[KEYS_ELT:%.*]] = getelementptr inbounds [2 x ptr], ptr [[KEYS]], i64 0, i64 1
+; CHECK-NEXT: [[TMP2:%.*]] = tail call ptr @llvm.objc.retain(ptr [[CALL3]]) #[[ATTR0]]
+; CHECK-NEXT: store ptr [[CALL3]], ptr [[KEYS_ELT]], align 8
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [2 x ptr], ptr [[OBJS]], i64 0, i64 2
+; CHECK-NEXT: br label %[[ARRAYDESTROY_BODY:.*]]
+; CHECK: [[ARRAYDESTROY_BODY]]:
+; CHECK-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[GEP]], %[[ENTRY]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], %[[ARRAYDESTROY_BODY]] ]
+; CHECK-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds ptr, ptr [[ARRAYDESTROY_ELEMENTPAST]], i64 -1
+; CHECK-NEXT: [[DESTROY_TMP:%.*]] = load ptr, ptr [[ARRAYDESTROY_ELEMENT]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[DESTROY_TMP]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: [[ARRAYDESTROY_CMP:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[OBJS]]
+; CHECK-NEXT: br i1 [[ARRAYDESTROY_CMP]], label %[[ARRAYDESTROY_DONE:.*]], label %[[ARRAYDESTROY_BODY]]
+; CHECK: [[ARRAYDESTROY_DONE]]:
+; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds [2 x ptr], ptr [[KEYS]], i64 0, i64 2
+; CHECK-NEXT: br label %[[ARRAYDESTROY_BODY1:.*]]
+; CHECK: [[ARRAYDESTROY_BODY1]]:
+; CHECK-NEXT: [[ARRAYDESTROY_ELEMENTPAST1:%.*]] = phi ptr [ [[GEP1]], %[[ARRAYDESTROY_DONE]] ], [ [[ARRAYDESTROY_ELEMENT1:%.*]], %[[ARRAYDESTROY_BODY1]] ]
+; CHECK-NEXT: [[ARRAYDESTROY_ELEMENT1]] = getelementptr inbounds ptr, ptr [[ARRAYDESTROY_ELEMENTPAST1]], i64 -1
+; CHECK-NEXT: [[DESTROY_TMP1:%.*]] = load ptr, ptr [[ARRAYDESTROY_ELEMENT1]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[DESTROY_TMP1]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: [[ARRAYDESTROY_CMP1:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT1]], [[KEYS]]
+; CHECK-NEXT: br i1 [[ARRAYDESTROY_CMP1]], label %[[ARRAYDESTROY_DONE1:.*]], label %[[ARRAYDESTROY_BODY1]]
+; CHECK: [[ARRAYDESTROY_DONE1]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[CALL1]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: ret void
+;
entry:
%keys = alloca [2 x ptr], align 16
%objs = alloca [2 x ptr], align 16
-
+
%call1 = call ptr @returner()
%tmp0 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call1)
%tmp1 = tail call ptr @llvm.objc.retain(ptr %call1)
@@ -452,8 +622,8 @@ entry:
store ptr %call2, ptr %keys, align 8
%keys.elt = getelementptr inbounds [2 x ptr], ptr %keys, i64 0, i64 1
tail call ptr @llvm.objc.retain(ptr %call3)
- store ptr %call3, ptr %keys.elt
-
+ store ptr %call3, ptr %keys.elt
+
%gep = getelementptr inbounds [2 x ptr], ptr %objs, i64 0, i64 2
br label %arraydestroy.body
@@ -486,3 +656,6 @@ arraydestroy.done1:
!0 = !{}
declare i32 @__gxx_personality_v0(...)
+;.
+; CHECK: [[META0]] = !{}
+;.
diff --git a/llvm/test/Transforms/ObjCARC/basic.ll b/llvm/test/Transforms/ObjCARC/basic.ll
index aa0c53b4f4851..e92ac86cce77f 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 5
; 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: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[S]])
+; CHECK-NEXT: store i32 7, ptr [[X]], align 4
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(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: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: call void @use_pointer(ptr [[S]])
+; CHECK-NEXT: store i32 7, ptr [[X]], align 4
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(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
@@ -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: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(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: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(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: call void @llvm.objc.release(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: 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,14 +1189,18 @@ 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 undef) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.objc.release(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: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %x) nounwind
call void @llvm.objc.autoreleasePoolPop(ptr undef)
@@ -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: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(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: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: [[TMP0:%.*]] = call ptr @llvm.objc.autorelease(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(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,10 +1550,10 @@ 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() {
+; CHECK-LABEL: define void @test18b() {
+; CHECK-NEXT: ret void
+;
call ptr @llvm.objc.retain(ptr undef)
call void @llvm.objc.release(ptr undef)
call ptr @llvm.objc.autorelease(ptr undef)
@@ -1192,14 +1563,16 @@ define void @test18b() {
; 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: call void @llvm.objc.release(ptr [[Y]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[Y]])
+; CHECK-NEXT: call void @use_pointer(ptr [[Y]])
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(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: call void @llvm.objc.release(ptr [[A]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[R]])
+; CHECK-NEXT: [[Q:%.*]] = load i8, ptr [[A]], align 1
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(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: call void @llvm.objc.release(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: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(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: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: store i8 0, ptr [[P]], align 1
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; 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: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: store i8 0, ptr [[P]], align 1
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; 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: call void @llvm.objc.release(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: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+; CHECK: [[FALSE]]:
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(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,18 +2403,19 @@ 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 undef) #[[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)
@@ -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: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[Q]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[P]])
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(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: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: store i8 0, ptr [[P]], align 1
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(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: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: store i8 0, ptr [[P]], align 1
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; 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: call void @llvm.objc.release(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: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(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: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: [[Z:%.*]] = load ptr, ptr [[ZZ]], align 8
+; CHECK-NEXT: call void @use_pointer(ptr [[Z]])
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; 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: call void @llvm.objc.release(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: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(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,14 @@ 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: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; 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 +2726,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: tail call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; CHECK-NEXT: tail call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: tail call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; 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 +2764,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: call void @llvm.objc.release(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: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %x) nounwind
call ptr @llvm.objc.retain(ptr %x) nounwind
@@ -2207,14 +2793,15 @@ 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: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; 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: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(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: tail call void @llvm.objc.release(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: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(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: tail call void @llvm.objc.release(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: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(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: tail call void @llvm.objc.release(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: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(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: tail call void @llvm.objc.release(ptr [[COND]]) #[[ATTR0]], !clang.imprecise_release [[META3]]
+; 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: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[COND]]) #[[ATTR0]]
+; 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
@@ -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,11 +3771,12 @@ define void @test68(ptr %a, ptr %b) {
!1 = !{i32 1, !"Debug Info Version", i32 3}
!2 = distinct !DISubprogram(unit: !3)
!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]] = !{}
+;.
+; CHECK: [[META3]] = !{}
+;.
diff --git a/llvm/test/Transforms/ObjCARC/clang-arc-use-barrier.ll b/llvm/test/Transforms/ObjCARC/clang-arc-use-barrier.ll
index 2581917a3896b..2bfdd49e35157 100644
--- a/llvm/test/Transforms/ObjCARC/clang-arc-use-barrier.ll
+++ b/llvm/test/Transforms/ObjCARC/clang-arc-use-barrier.ll
@@ -1,15 +1,34 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -passes=objc-arc -S %s | FileCheck %s
%0 = type opaque
; Make sure ARC optimizer doesn't sink @obj_retain past @llvm.objc.clang.arc.use.
-; CHECK: call ptr @llvm.objc.retain
-; CHECK: call void (...) @llvm.objc.clang.arc.use(
-; CHECK: call ptr @llvm.objc.retain
-; CHECK: call void (...) @llvm.objc.clang.arc.use(
define void @runTest() local_unnamed_addr {
+; CHECK-LABEL: define void @runTest() local_unnamed_addr {
+; CHECK-NEXT: [[TMP1:%.*]] = alloca ptr, align 8
+; CHECK-NEXT: [[TMP2:%.*]] = alloca ptr, align 8
+; CHECK-NEXT: [[TMP3:%.*]] = tail call ptr @foo0()
+; CHECK-NEXT: [[TMP4:%.*]] = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[TMP3]]) #[[ATTR0:[0-9]+]]
+; CHECK-NEXT: store ptr [[TMP3]], ptr [[TMP1]], align 8
+; CHECK-NEXT: call void @foo1(ptr nonnull [[TMP1]])
+; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP1]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP5]]) #[[ATTR0]]
+; CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(ptr [[TMP3]])
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP3]]) #[[ATTR0]]
+; CHECK-NEXT: store ptr [[TMP5]], ptr [[TMP2]], align 8
+; CHECK-NEXT: call void @foo1(ptr nonnull [[TMP2]])
+; CHECK-NEXT: [[TMP6:%.*]] = load ptr, ptr [[TMP2]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP6]]) #[[ATTR0]]
+; CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(ptr [[TMP5]])
+; CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[TMP2]], align 8
+; CHECK-NEXT: [[TMP7:%.*]] = tail call ptr @llvm.objc.retain(ptr [[TMP5]]) #[[ATTR0]]
+; CHECK-NEXT: call void @foo2(ptr [[TMP6]])
+; CHECK-NEXT: [[TMP8:%.*]] = tail call ptr @llvm.objc.retain(ptr [[TMP6]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
%1 = alloca ptr, align 8
%2 = alloca ptr, align 8
%3 = tail call ptr @foo0()
diff --git a/llvm/test/Transforms/ObjCARC/code-motion.ll b/llvm/test/Transforms/ObjCARC/code-motion.ll
index 499ee77bc6541..849d4ca163771 100644
--- a/llvm/test/Transforms/ObjCARC/code-motion.ll
+++ b/llvm/test/Transforms/ObjCARC/code-motion.ll
@@ -1,3 +1,4 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -passes=objc-arc -S < %s | FileCheck %s
declare void @alterRefCount()
@@ -9,10 +10,18 @@ declare void @readOnlyFunc(ptr, ptr)
; Check that ARC optimizer doesn't reverse the order of the retain call and the
; release call when there are debug instructions.
-; CHECK: call ptr @llvm.objc.retain(ptr %x)
-; CHECK: call void @llvm.objc.release(ptr %x)
define i32 @test(ptr %x, ptr %y, i8 %z, i32 %i) {
+; CHECK-LABEL: define i32 @test(
+; CHECK-SAME: ptr [[X:%.*]], ptr [[Y:%.*]], i8 [[Z:%.*]], i32 [[I:%.*]]) {
+; CHECK-NEXT: [[I_ADDR:%.*]] = alloca i32, align 4
+; CHECK-NEXT: store i32 [[I]], ptr [[I_ADDR]], align 4
+; CHECK-NEXT: store i8 [[Z]], ptr [[X]], align 1
+; CHECK-NEXT: tail call void @llvm.objc.release(ptr [[X]]) #[[ATTR0:[0-9]+]]
+; CHECK-NEXT: call void @alterRefCount()
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret i32 [[I]]
+;
%i.addr = alloca i32, align 4
store i32 %i, ptr %i.addr, align 4
%v1 = tail call ptr @llvm.objc.retain(ptr %x)
@@ -26,11 +35,16 @@ define i32 @test(ptr %x, ptr %y, i8 %z, i32 %i) {
; ARC optimizer shouldn't move the release call, which is a precise release call
; past the call to @alterRefCount.
-; CHECK-LABEL: define void @test2(
-; CHECK: call void @alterRefCount(
-; CHECK: call void @llvm.objc.release(
define void @test2() {
+; CHECK-LABEL: define void @test2() {
+; CHECK-NEXT: [[V0:%.*]] = load ptr, ptr @g0, align 8
+; CHECK-NEXT: tail call void @llvm.objc.release(ptr [[V0]]) #[[ATTR0]]
+; CHECK-NEXT: tail call void @use(ptr [[V0]])
+; CHECK-NEXT: tail call void @alterRefCount()
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[V0]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
%v0 = load ptr, ptr @g0, align 8
%v1 = tail call ptr @llvm.objc.retain(ptr %v0)
tail call void @use(ptr %v0)
@@ -51,20 +65,21 @@ define void @test2() {
; Ideally, the retain/release pairs in BB if.then should be removed.
define void @test3(ptr %obj, i1 %cond) {
-; CHECK-LABEL: @test3(
-; CHECK-NEXT: [[TMP2:%.*]] = tail call ptr @llvm.objc.retain(ptr [[OBJ:%.*]])
-; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
-; CHECK: if.then:
-; CHECK-NEXT: call void @readOnlyFunc(ptr [[OBJ]], ptr null)
+; CHECK-LABEL: define void @test3(
+; CHECK-SAME: ptr [[OBJ:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[V0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[OBJ]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: call void @readOnlyFunc(ptr [[OBJ]], ptr null) #[[ATTR1:[0-9]+]]
; CHECK-NEXT: [[TMP1:%.*]] = add i32 1, 2
; CHECK-NEXT: call void @alterRefCount()
-; CHECK-NEXT: br label [[JOIN:%.*]]
-; CHECK: if.else:
+; CHECK-NEXT: br label %[[JOIN:.*]]
+; CHECK: [[IF_ELSE]]:
; CHECK-NEXT: call void @alterRefCount()
; CHECK-NEXT: call void @use(ptr [[OBJ]])
-; CHECK-NEXT: br label [[JOIN]]
-; CHECK: join:
-; CHECK-NEXT: call void @llvm.objc.release(ptr [[OBJ]]) {{.*}}, !clang.imprecise_release !2
+; CHECK-NEXT: br label %[[JOIN]]
+; CHECK: [[JOIN]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[OBJ]]) #[[ATTR0]], !clang.imprecise_release [[META2:![0-9]+]]
; CHECK-NEXT: ret void
;
%v0 = call ptr @llvm.objc.retain(ptr %obj)
@@ -87,23 +102,24 @@ join:
}
define void @test4(ptr %obj0, ptr %obj1, i1 %cond) {
-; CHECK-LABEL: @test4(
-; CHECK-NEXT: [[TMP3:%.*]] = tail call ptr @llvm.objc.retain(ptr [[OBJ0:%.*]])
-; CHECK-NEXT: [[TMP2:%.*]] = tail call ptr @llvm.objc.retain(ptr [[OBJ1:%.*]])
-; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
-; CHECK: if.then:
-; CHECK-NEXT: call void @readOnlyFunc(ptr [[OBJ0]], ptr [[OBJ1]])
+; CHECK-LABEL: define void @test4(
+; CHECK-SAME: ptr [[OBJ0:%.*]], ptr [[OBJ1:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[V0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[OBJ0]]) #[[ATTR0]]
+; CHECK-NEXT: [[V1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[OBJ1]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: call void @readOnlyFunc(ptr [[OBJ0]], ptr [[OBJ1]]) #[[ATTR1]]
; CHECK-NEXT: [[TMP1:%.*]] = add i32 1, 2
; CHECK-NEXT: call void @alterRefCount()
-; CHECK-NEXT: br label [[JOIN:%.*]]
-; CHECK: if.else:
+; CHECK-NEXT: br label %[[JOIN:.*]]
+; CHECK: [[IF_ELSE]]:
; CHECK-NEXT: call void @alterRefCount()
; CHECK-NEXT: call void @use(ptr [[OBJ0]])
; CHECK-NEXT: call void @use(ptr [[OBJ1]])
-; CHECK-NEXT: br label [[JOIN]]
-; CHECK: join:
-; CHECK-NEXT: call void @llvm.objc.release(ptr [[OBJ0]]) {{.*}}, !clang.imprecise_release !2
-; CHECK-NEXT: call void @llvm.objc.release(ptr [[OBJ1]]) {{.*}}, !clang.imprecise_release !2
+; CHECK-NEXT: br label %[[JOIN]]
+; CHECK: [[JOIN]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[OBJ0]]) #[[ATTR0]], !clang.imprecise_release [[META2]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[OBJ1]]) #[[ATTR0]], !clang.imprecise_release [[META2]]
; CHECK-NEXT: ret void
;
%v0 = call ptr @llvm.objc.retain(ptr %obj0)
@@ -132,26 +148,27 @@ join:
; eliminated are in different blocks (bb1 and if.then).
define void @test5(ptr %obj, i1 %cond0, i1 %cond1) {
-; CHECK-LABEL: @test5(
-; CHECK-NEXT: [[V0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[OBJ:%.*]])
-; CHECK-NEXT: br i1 [[COND0:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
-; CHECK: if.then:
-; CHECK-NEXT: call void @readOnlyFunc(ptr [[OBJ]], ptr null)
-; CHECK-NEXT: br i1 [[COND1:%.*]], label [[IF_THEN2:%.*]], label [[IF_ELSE2:%.*]]
-; CHECK: if.then2:
-; CHECK-NEXT: br label [[BB1:%.*]]
-; CHECK: if.else2:
-; CHECK-NEXT: br label [[BB1]]
-; CHECK: bb1:
+; CHECK-LABEL: define void @test5(
+; CHECK-SAME: ptr [[OBJ:%.*]], i1 [[COND0:%.*]], i1 [[COND1:%.*]]) {
+; CHECK-NEXT: [[V0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[OBJ]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[COND0]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: call void @readOnlyFunc(ptr [[OBJ]], ptr null) #[[ATTR1]]
+; CHECK-NEXT: br i1 [[COND1]], label %[[IF_THEN2:.*]], label %[[IF_ELSE2:.*]]
+; CHECK: [[IF_THEN2]]:
+; CHECK-NEXT: br label %[[BB1:.*]]
+; CHECK: [[IF_ELSE2]]:
+; CHECK-NEXT: br label %[[BB1]]
+; CHECK: [[BB1]]:
; CHECK-NEXT: [[TMP1:%.*]] = add i32 1, 2
; CHECK-NEXT: call void @alterRefCount()
-; CHECK-NEXT: br label [[JOIN:%.*]]
-; CHECK: if.else:
+; CHECK-NEXT: br label %[[JOIN:.*]]
+; CHECK: [[IF_ELSE]]:
; CHECK-NEXT: call void @alterRefCount()
; CHECK-NEXT: call void @use(ptr [[OBJ]])
-; CHECK-NEXT: br label [[JOIN]]
-; CHECK: join:
-; CHECK-NEXT: call void @llvm.objc.release(ptr [[OBJ]])
+; CHECK-NEXT: br label %[[JOIN]]
+; CHECK: [[JOIN]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[OBJ]]) #[[ATTR0]], !clang.imprecise_release [[META2]]
; CHECK-NEXT: ret void
;
%v0 = call ptr @llvm.objc.retain(ptr %obj)
@@ -201,3 +218,6 @@ attributes #0 = { readonly }
!8 = distinct !DICompileUnit(language: DW_LANG_ObjC, file: !4, isOptimized: false, runtimeVersion: 2, emissionKind: FullDebug, enums: !9, nameTableKind: None)
!9 = !{}
!10 = !DILocation(line: 1, column: 14, scope: !3)
+;.
+; CHECK: [[META2]] = !{}
+;.
diff --git a/llvm/test/Transforms/ObjCARC/funclet-catchpad.ll b/llvm/test/Transforms/ObjCARC/funclet-catchpad.ll
index 9f047c29bc159..78e75da5837b2 100644
--- a/llvm/test/Transforms/ObjCARC/funclet-catchpad.ll
+++ b/llvm/test/Transforms/ObjCARC/funclet-catchpad.ll
@@ -1,14 +1,29 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -mtriple=x86_64-windows-msvc -passes=objc-arc -S < %s | FileCheck %s
-; Check that funclet tokens are preserved
-;
-; CHECK-LABEL: catch:
-; CHECK: %1 = catchpad within %0
-; CHECK: %2 = tail call ptr @llvm.objc.retain(ptr %exn) #0 [ "funclet"(token %1) ]
-; CHECK: call void @llvm.objc.release(ptr %exn) #0 [ "funclet"(token %1) ]
-; CHECK: catchret from %1 to label %eh.cont
+; Check that funclet tokens are preserved, and that the optimization correctly
+; reorders retain and release calls while preserving the funclet operand.
define void @try_catch_with_objc_intrinsic() personality ptr @__CxxFrameHandler3 {
+; CHECK-LABEL: @try_catch_with_objc_intrinsic(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 8
+; CHECK-NEXT: invoke void @may_throw(ptr null)
+; CHECK-NEXT: to label %eh.cont unwind label %catch.dispatch
+; CHECK: catch.dispatch:
+; CHECK-NEXT: [[TMP0:%.*]] = catchswitch within none [label %catch] unwind to caller
+; CHECK: eh.cont:
+; CHECK-NEXT: ret void
+; CHECK: catch:
+; CHECK-NEXT: [[TMP1:%.*]] = catchpad within [[TMP0]] [ptr null, i32 0, ptr [[EXN_SLOT]]]
+; CHECK-NEXT: br label %if.then
+; CHECK: if.then:
+; CHECK-NEXT: [[EXN:%.*]] = load ptr, ptr null, align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[EXN]]) #[[ATTR0:[0-9]+]] [ "funclet"(token [[TMP1]]) ]
+; CHECK-NEXT: call void @may_throw(ptr [[EXN]])
+; CHECK-NEXT: [[TMP2:%.*]] = tail call ptr @llvm.objc.retain(ptr [[EXN]]) #[[ATTR0]] [ "funclet"(token [[TMP1]]) ]
+; CHECK-NEXT: catchret from [[TMP1]] to label %eh.cont
+;
entry:
%exn.slot = alloca ptr, align 8
invoke void @may_throw(ptr null) to label %eh.cont unwind label %catch.dispatch
diff --git a/llvm/test/Transforms/ObjCARC/intrinsic-use.ll b/llvm/test/Transforms/ObjCARC/intrinsic-use.ll
index 884e2ebea7350..404a7877d0896 100644
--- a/llvm/test/Transforms/ObjCARC/intrinsic-use.ll
+++ b/llvm/test/Transforms/ObjCARC/intrinsic-use.ll
@@ -1,3 +1,4 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -passes=objc-arc -S < %s | FileCheck %s
target datalayout = "e-p:64:64:64"
@@ -16,29 +17,33 @@ declare void @can_release(ptr)
; Ensure that we honor clang.arc.use as a use and don't miscompile
; the reduced test case from <rdar://13195034>.
;
-; CHECK-LABEL: define void @test0(
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK-NEXT: store ptr %y, ptr %temp0
-; CHECK-NEXT: @llvm.objc.retain(ptr %y)
-; CHECK-NEXT: call void @test0_helper
-; CHECK-NEXT: [[VAL1:%.*]] = load ptr, ptr %temp0
-; CHECK-NEXT: @llvm.objc.retain(ptr [[VAL1]])
-; CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(ptr %y)
-; CHECK-NEXT: @llvm.objc.release(ptr %y)
-; CHECK-NEXT: store ptr [[VAL1]], ptr %temp1
-; CHECK-NEXT: call void @test0_helper
-; CHECK-NEXT: [[VAL2:%.*]] = load ptr, ptr %temp1
-; CHECK-NEXT: @llvm.objc.retain(ptr [[VAL2]])
-; CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(ptr [[VAL1]])
-; CHECK-NEXT: @llvm.objc.release(ptr [[VAL1]])
-; CHECK-NEXT: @llvm.objc.autorelease(ptr %x)
-; CHECK-NEXT: store ptr %x, ptr %out
-; CHECK-NEXT: @llvm.objc.retain(ptr %x)
-; CHECK-NEXT: @llvm.objc.release(ptr [[VAL2]])
-; CHECK-NEXT: @llvm.objc.release(ptr %x)
-; CHECK-NEXT: ret void
-; CHECK-NEXT: }
define void @test0(ptr %out, ptr %x, ptr %y) {
+; CHECK-LABEL: define void @test0(
+; CHECK-SAME: ptr [[OUT:%.*]], ptr [[X:%.*]], ptr [[Y:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TEMP0:%.*]] = alloca ptr, align 8
+; CHECK-NEXT: [[TEMP1:%.*]] = alloca ptr, align 8
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0:[0-9]+]]
+; CHECK-NEXT: store ptr [[Y]], ptr [[TEMP0]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[Y]]) #[[ATTR0]]
+; CHECK-NEXT: call void @test0_helper(ptr [[X]], ptr [[TEMP0]])
+; CHECK-NEXT: [[VAL1:%.*]] = load ptr, ptr [[TEMP0]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[VAL1]]) #[[ATTR0]]
+; CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(ptr [[Y]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[Y]]) #[[ATTR0]]
+; CHECK-NEXT: store ptr [[VAL1]], ptr [[TEMP1]], align 8
+; CHECK-NEXT: call void @test0_helper(ptr [[X]], ptr [[TEMP1]])
+; CHECK-NEXT: [[VAL2:%.*]] = load ptr, ptr [[TEMP1]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[VAL2]]) #[[ATTR0]]
+; CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(ptr [[VAL1]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP2:%.*]] = tail call ptr @llvm.objc.retain(ptr [[VAL1]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP3:%.*]] = call ptr @llvm.objc.autorelease(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: store ptr [[X]], ptr [[OUT]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP4:%.*]] = tail call ptr @llvm.objc.retain(ptr [[VAL2]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP5:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%temp0 = alloca ptr, align 8
%temp1 = alloca ptr, align 8
@@ -64,27 +69,31 @@ entry:
ret void
}
-; CHECK-LABEL: define void @test0a(
-; CHECK: @llvm.objc.retain(ptr %x)
-; CHECK-NEXT: store ptr %y, ptr %temp0
-; CHECK-NEXT: @llvm.objc.retain(ptr %y)
-; CHECK-NEXT: call void @test0_helper
-; CHECK-NEXT: [[VAL1:%.*]] = load ptr, ptr %temp0
-; CHECK-NEXT: @llvm.objc.retain(ptr [[VAL1]])
-; CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(ptr %y)
-; CHECK-NEXT: @llvm.objc.release(ptr %y)
-; CHECK-NEXT: store ptr [[VAL1]], ptr %temp1
-; CHECK-NEXT: call void @test0_helper
-; CHECK-NEXT: [[VAL2:%.*]] = load ptr, ptr %temp1
-; CHECK-NEXT: @llvm.objc.retain(ptr [[VAL2]])
-; CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(ptr [[VAL1]])
-; CHECK-NEXT: @llvm.objc.release(ptr [[VAL1]])
-; CHECK-NEXT: @llvm.objc.autorelease(ptr %x)
-; CHECK-NEXT: @llvm.objc.release(ptr [[VAL2]])
-; CHECK-NEXT: store ptr %x, ptr %out
-; CHECK-NEXT: ret void
-; CHECK-NEXT: }
define void @test0a(ptr %out, ptr %x, ptr %y) {
+; CHECK-LABEL: define void @test0a(
+; CHECK-SAME: ptr [[OUT:%.*]], ptr [[X:%.*]], ptr [[Y:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TEMP0:%.*]] = alloca ptr, align 8
+; CHECK-NEXT: [[TEMP1:%.*]] = alloca ptr, align 8
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: store ptr [[Y]], ptr [[TEMP0]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[Y]]) #[[ATTR0]], !clang.imprecise_release [[META0:![0-9]+]]
+; CHECK-NEXT: call void @test0_helper(ptr [[X]], ptr [[TEMP0]])
+; CHECK-NEXT: [[VAL1:%.*]] = load ptr, ptr [[TEMP0]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[VAL1]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(ptr [[Y]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[Y]]) #[[ATTR0]]
+; CHECK-NEXT: store ptr [[VAL1]], ptr [[TEMP1]], align 8
+; CHECK-NEXT: call void @test0_helper(ptr [[X]], ptr [[TEMP1]])
+; CHECK-NEXT: [[VAL2:%.*]] = load ptr, ptr [[TEMP1]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[VAL2]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(ptr [[VAL1]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP2:%.*]] = tail call ptr @llvm.objc.retain(ptr [[VAL1]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP3:%.*]] = call ptr @llvm.objc.autorelease(ptr [[X]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP4:%.*]] = tail call ptr @llvm.objc.retain(ptr [[VAL2]]) #[[ATTR0]]
+; CHECK-NEXT: store ptr [[X]], ptr [[OUT]], align 8
+; CHECK-NEXT: ret void
+;
entry:
%temp0 = alloca ptr, align 8
%temp1 = alloca ptr, align 8
@@ -113,12 +122,14 @@ entry:
; ARC optimizer should be able to safely remove the retain/release pair as the
; call to @llvm.objc.clang.arc.noop.use is a no-op.
-; CHECK-LABEL: define void @test_arc_noop_use(
-; CHECK-NEXT: call void @can_release(ptr %x)
-; CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(
-; CHECK-NEXT: ret void
define void @test_arc_noop_use(ptr %out, ptr %x) {
+; CHECK-LABEL: define void @test_arc_noop_use(
+; CHECK-SAME: ptr [[OUT:%.*]], ptr [[X:%.*]]) {
+; CHECK-NEXT: call void @can_release(ptr [[X]])
+; CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[X]])
+; CHECK-NEXT: ret void
+;
call ptr @llvm.objc.retain(ptr %x)
call void @can_release(ptr %x)
call void (...) @llvm.objc.clang.arc.noop.use(ptr %x)
@@ -128,3 +139,6 @@ define void @test_arc_noop_use(ptr %out, ptr %x) {
!0 = !{}
+;.
+; CHECK: [[META0]] = !{}
+;.
diff --git a/llvm/test/Transforms/ObjCARC/invoke.ll b/llvm/test/Transforms/ObjCARC/invoke.ll
index a792b8e868366..7c1a454daab2c 100644
--- a/llvm/test/Transforms/ObjCARC/invoke.ll
+++ b/llvm/test/Transforms/ObjCARC/invoke.ll
@@ -1,3 +1,4 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -S -passes=objc-arc < %s | FileCheck %s
declare ptr @llvm.objc.retain(ptr)
@@ -10,20 +11,28 @@ declare ptr @returner()
; ARCOpt shouldn't try to move the releases to the block containing the invoke.
-; CHECK-LABEL: define void @test0(
-; CHECK: invoke.cont:
-; CHECK: call void @llvm.objc.release(ptr %zipFile) [[NUW:#[0-9]+]], !clang.imprecise_release !0
-; CHECK: ret void
-; CHECK: lpad:
-; CHECK: call void @llvm.objc.release(ptr %zipFile) [[NUW]], !clang.imprecise_release !0
-; CHECK: ret void
-; CHECK-NEXT: }
define void @test0(ptr %zipFile) personality ptr @__gxx_personality_v0 {
+; CHECK-LABEL: define void @test0(
+; CHECK-SAME: ptr [[ZIPFILE:%.*]]) personality ptr @__gxx_personality_v0 {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[ZIPFILE]]) #[[ATTR0:[0-9]+]], !clang.imprecise_release [[META0:![0-9]+]]
+; CHECK-NEXT: call void @use_pointer(ptr [[ZIPFILE]])
+; CHECK-NEXT: invoke void @objc_msgSend(ptr [[ZIPFILE]])
+; CHECK-NEXT: to label %[[INVOKE_CONT:.*]] unwind label %[[LPAD:.*]]
+; CHECK: [[INVOKE_CONT]]:
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[ZIPFILE]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+; CHECK: [[LPAD]]:
+; CHECK-NEXT: [[EXN:%.*]] = landingpad { ptr, i32 }
+; CHECK-NEXT: cleanup
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[ZIPFILE]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %zipFile) nounwind
call void @use_pointer(ptr %zipFile)
- invoke void @objc_msgSend(ptr %zipFile)
- to label %invoke.cont unwind label %lpad
+ invoke void @objc_msgSend(ptr %zipFile)
+ to label %invoke.cont unwind label %lpad
invoke.cont: ; preds = %entry
call void @llvm.objc.release(ptr %zipFile) nounwind, !clang.imprecise_release !0
@@ -31,31 +40,39 @@ invoke.cont: ; preds = %entry
lpad: ; preds = %entry
%exn = landingpad {ptr, i32}
- cleanup
+ cleanup
call void @llvm.objc.release(ptr %zipFile) nounwind, !clang.imprecise_release !0
ret void
}
; ARCOpt should move the release before the callee calls.
-; CHECK-LABEL: define void @test1(
-; CHECK: invoke.cont:
-; CHECK: call void @llvm.objc.release(ptr %zipFile) [[NUW]], !clang.imprecise_release !0
-; CHECK: call void @callee()
-; CHECK: br label %done
-; CHECK: lpad:
-; CHECK: call void @llvm.objc.release(ptr %zipFile) [[NUW]], !clang.imprecise_release !0
-; CHECK: call void @callee()
-; CHECK: br label %done
-; CHECK: done:
-; CHECK-NEXT: ret void
-; CHECK-NEXT: }
define void @test1(ptr %zipFile) personality ptr @__gxx_personality_v0 {
+; CHECK-LABEL: define void @test1(
+; CHECK-SAME: ptr [[ZIPFILE:%.*]]) personality ptr @__gxx_personality_v0 {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[ZIPFILE]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[ZIPFILE]])
+; CHECK-NEXT: invoke void @objc_msgSend(ptr [[ZIPFILE]])
+; CHECK-NEXT: to label %[[INVOKE_CONT:.*]] unwind label %[[LPAD:.*]]
+; CHECK: [[INVOKE_CONT]]:
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[ZIPFILE]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: br label %[[DONE:.*]]
+; CHECK: [[LPAD]]:
+; CHECK-NEXT: [[EXN:%.*]] = landingpad { ptr, i32 }
+; CHECK-NEXT: cleanup
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[ZIPFILE]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: br label %[[DONE]]
+; CHECK: [[DONE]]:
+; CHECK-NEXT: ret void
+;
entry:
call ptr @llvm.objc.retain(ptr %zipFile) nounwind
call void @use_pointer(ptr %zipFile)
invoke void @objc_msgSend(ptr %zipFile)
- to label %invoke.cont unwind label %lpad
+ to label %invoke.cont unwind label %lpad
invoke.cont: ; preds = %entry
call void @callee()
@@ -63,7 +80,7 @@ invoke.cont: ; preds = %entry
lpad: ; preds = %entry
%exn = landingpad {ptr, i32}
- cleanup
+ cleanup
call void @callee()
br label %done
@@ -75,26 +92,33 @@ done:
; The optimizer should ignore invoke unwind paths consistently.
; PR12265
-; CHECK: define void @test2() personality ptr @__objc_personality_v0 {
-; CHECK: invoke.cont:
-; CHECK-NEXT: call ptr @llvm.objc.retain
-; CHECK-NOT: @llvm.objc.r
-; CHECK: finally.cont:
-; CHECK-NEXT: call void @llvm.objc.release
-; CHECK-NOT: @objc
-; CHECK: finally.rethrow:
-; CHECK-NOT: @objc
-; CHECK: }
define void @test2() personality ptr @__objc_personality_v0 {
+; CHECK-LABEL: define void @test2() personality ptr @__objc_personality_v0 {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[CALL:%.*]] = invoke ptr @objc_msgSend()
+; CHECK-NEXT: to label %[[INVOKE_CONT:.*]] unwind label %[[FINALLY_RETHROW:.*]], !clang.arc.no_objc_arc_exceptions [[META0]]
+; CHECK: [[INVOKE_CONT]]:
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[CALL]]) #[[ATTR0]]
+; CHECK-NEXT: call void @objc_msgSend(), !clang.arc.no_objc_arc_exceptions [[META0]]
+; CHECK-NEXT: invoke void @use_pointer(ptr [[CALL]])
+; CHECK-NEXT: to label %[[FINALLY_CONT:.*]] unwind label %[[FINALLY_RETHROW]], !clang.arc.no_objc_arc_exceptions [[META0]]
+; CHECK: [[FINALLY_CONT]]:
+; CHECK-NEXT: tail call void @llvm.objc.release(ptr [[CALL]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: ret void
+; CHECK: [[FINALLY_RETHROW]]:
+; CHECK-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 }
+; CHECK-NEXT: catch ptr null
+; CHECK-NEXT: unreachable
+;
entry:
%call = invoke ptr @objc_msgSend()
- to label %invoke.cont unwind label %finally.rethrow, !clang.arc.no_objc_arc_exceptions !0
+ to label %invoke.cont unwind label %finally.rethrow, !clang.arc.no_objc_arc_exceptions !0
invoke.cont: ; preds = %entry
%tmp1 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind
call void @objc_msgSend(), !clang.arc.no_objc_arc_exceptions !0
invoke void @use_pointer(ptr %call)
- to label %finally.cont unwind label %finally.rethrow, !clang.arc.no_objc_arc_exceptions !0
+ to label %finally.cont unwind label %finally.rethrow, !clang.arc.no_objc_arc_exceptions !0
finally.cont: ; preds = %invoke.cont
tail call void @llvm.objc.release(ptr %call) nounwind, !clang.imprecise_release !0
@@ -102,18 +126,33 @@ finally.cont: ; preds = %invoke.cont
finally.rethrow: ; preds = %invoke.cont, %entry
%tmp2 = landingpad { ptr, i32 }
- catch ptr null
+ catch ptr null
unreachable
}
; Don't try to place code on invoke critical edges.
-; CHECK-LABEL: define void @test3(
-; CHECK: if.end:
-; CHECK-NEXT: call void @llvm.objc.release(ptr %p) [[NUW]]
-; CHECK-NEXT: ret void
-; CHECK-NEXT: }
define void @test3(ptr %p, i1 %b) personality ptr @__objc_personality_v0 {
+; CHECK-LABEL: define void @test3(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[B:%.*]]) personality ptr @__objc_personality_v0 {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: br i1 [[B]], label %[[IF_ELSE:.*]], label %[[IF_THEN:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: invoke void @use_pointer(ptr [[P]])
+; CHECK-NEXT: to label %[[IF_END:.*]] unwind label %[[LPAD:.*]], !clang.arc.no_objc_arc_exceptions [[META0]]
+; CHECK: [[IF_ELSE]]:
+; CHECK-NEXT: invoke void @use_pointer(ptr [[P]])
+; CHECK-NEXT: to label %[[IF_END]] unwind label %[[LPAD]], !clang.arc.no_objc_arc_exceptions [[META0]]
+; CHECK: [[LPAD]]:
+; CHECK-NEXT: [[R:%.*]] = landingpad { ptr, i32 }
+; CHECK-NEXT: cleanup
+; CHECK-NEXT: ret void
+; CHECK: [[IF_END]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %p)
call void @callee()
@@ -121,15 +160,15 @@ entry:
if.then:
invoke void @use_pointer(ptr %p)
- to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
+ to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
if.else:
invoke void @use_pointer(ptr %p)
- to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
+ to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
lpad:
%r = landingpad { ptr, i32 }
- cleanup
+ cleanup
ret void
if.end:
@@ -139,17 +178,28 @@ if.end:
; Like test3, but with ARC-relevant exception handling.
-; CHECK-LABEL: define void @test4(
-; CHECK: lpad:
-; CHECK-NEXT: %r = landingpad { ptr, i32 }
-; CHECK-NEXT: cleanup
-; CHECK-NEXT: call void @llvm.objc.release(ptr %p) [[NUW]]
-; CHECK-NEXT: ret void
-; CHECK: if.end:
-; CHECK-NEXT: call void @llvm.objc.release(ptr %p) [[NUW]]
-; CHECK-NEXT: ret void
-; CHECK-NEXT: }
define void @test4(ptr %p, i1 %b) personality ptr @__objc_personality_v0 {
+; CHECK-LABEL: define void @test4(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[B:%.*]]) personality ptr @__objc_personality_v0 {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: br i1 [[B]], label %[[IF_ELSE:.*]], label %[[IF_THEN:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: invoke void @use_pointer(ptr [[P]])
+; CHECK-NEXT: to label %[[IF_END:.*]] unwind label %[[LPAD:.*]]
+; CHECK: [[IF_ELSE]]:
+; CHECK-NEXT: invoke void @use_pointer(ptr [[P]])
+; CHECK-NEXT: to label %[[IF_END]] unwind label %[[LPAD]]
+; CHECK: [[LPAD]]:
+; CHECK-NEXT: [[R:%.*]] = landingpad { ptr, i32 }
+; CHECK-NEXT: cleanup
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+; CHECK: [[IF_END]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%0 = call ptr @llvm.objc.retain(ptr %p)
call void @callee()
@@ -157,15 +207,15 @@ entry:
if.then:
invoke void @use_pointer(ptr %p)
- to label %if.end unwind label %lpad
+ to label %if.end unwind label %lpad
if.else:
invoke void @use_pointer(ptr %p)
- to label %if.end unwind label %lpad
+ to label %if.end unwind label %lpad
lpad:
%r = landingpad { ptr, i32 }
- cleanup
+ cleanup
call void @llvm.objc.release(ptr %p)
ret void
@@ -177,17 +227,26 @@ if.end:
; Don't turn the retainAutoreleaseReturnValue into retain, because it's
; for an invoke which we can assume codegen will put immediately prior.
-; CHECK-LABEL: define void @test5(
-; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %z)
-; CHECK: }
define void @test5() personality ptr @__objc_personality_v0 {
+; CHECK-LABEL: define void @test5() personality ptr @__objc_personality_v0 {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[Z:%.*]] = invoke ptr @returner()
+; CHECK-NEXT: to label %[[IF_END:.*]] unwind label %[[LPAD:.*]], !clang.arc.no_objc_arc_exceptions [[META0]]
+; CHECK: [[LPAD]]:
+; CHECK-NEXT: [[R13:%.*]] = landingpad { ptr, i32 }
+; CHECK-NEXT: cleanup
+; CHECK-NEXT: ret void
+; CHECK: [[IF_END]]:
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[Z]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%z = invoke ptr @returner()
- to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
+ to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
lpad:
%r13 = landingpad { ptr, i32 }
- cleanup
+ cleanup
ret void
if.end:
@@ -197,17 +256,27 @@ if.end:
; Like test5, but there's intervening code.
-; CHECK-LABEL: define void @test6(
-; CHECK: call ptr @llvm.objc.retain(ptr %z)
-; CHECK: }
define void @test6() personality ptr @__objc_personality_v0 {
+; CHECK-LABEL: define void @test6() personality ptr @__objc_personality_v0 {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[Z:%.*]] = invoke ptr @returner()
+; CHECK-NEXT: to label %[[IF_END:.*]] unwind label %[[LPAD:.*]], !clang.arc.no_objc_arc_exceptions [[META0]]
+; CHECK: [[LPAD]]:
+; CHECK-NEXT: [[R13:%.*]] = landingpad { ptr, i32 }
+; CHECK-NEXT: cleanup
+; CHECK-NEXT: ret void
+; CHECK: [[IF_END]]:
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[Z]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%z = invoke ptr @returner()
- to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
+ to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
lpad:
%r13 = landingpad { ptr, i32 }
- cleanup
+ cleanup
ret void
if.end:
@@ -219,6 +288,8 @@ if.end:
declare i32 @__gxx_personality_v0(...)
declare i32 @__objc_personality_v0(...)
-; CHECK: attributes [[NUW]] = { nounwind }
!0 = !{}
+;.
+; CHECK: [[META0]] = !{}
+;.
diff --git a/llvm/test/Transforms/ObjCARC/nested.ll b/llvm/test/Transforms/ObjCARC/nested.ll
index d03cbd5f54e71..5ad1f450fa8ab 100644
--- a/llvm/test/Transforms/ObjCARC/nested.ll
+++ b/llvm/test/Transforms/ObjCARC/nested.ll
@@ -1,3 +1,4 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -passes=objc-arc -S < %s | FileCheck %s
%struct.__objcFastEnumerationState = type { i64, ptr, ptr, [5 x i64] }
@@ -25,11 +26,55 @@ declare void @__crasher_block_invoke1(ptr nocapture)
; Delete a nested retain+release pair.
-; CHECK-LABEL: define void @test0(
-; CHECK: call ptr @llvm.objc.retain
-; CHECK-NOT: @llvm.objc.retain
-; CHECK: }
define void @test0(ptr %a) nounwind {
+; CHECK-LABEL: define void @test0(
+; CHECK-SAME: ptr [[A:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[STATE_PTR:%.*]] = alloca [[STRUCT___OBJCFASTENUMERATIONSTATE:%.*]], align 8
+; CHECK-NEXT: [[ITEMS_PTR:%.*]] = alloca [16 x ptr], align 8
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[A]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[STATE_PTR]], i8 0, i64 64, i1 false)
+; CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL:%.*]] = call i64 @objc_msgSend(ptr [[TMP0]], ptr [[TMP2]], ptr [[STATE_PTR]], ptr [[ITEMS_PTR]], i64 16)
+; CHECK-NEXT: [[ISZERO:%.*]] = icmp eq i64 [[CALL]], 0
+; CHECK-NEXT: br i1 [[ISZERO]], label %[[FORCOLL_EMPTY:.*]], label %[[FORCOLL_LOOPINIT:.*]]
+; CHECK: [[FORCOLL_LOOPINIT]]:
+; CHECK-NEXT: [[MUTATIONSPTR_PTR:%.*]] = getelementptr inbounds [[STRUCT___OBJCFASTENUMERATIONSTATE]], ptr [[STATE_PTR]], i64 0, i32 2
+; CHECK-NEXT: [[MUTATIONSPTR:%.*]] = load ptr, ptr [[MUTATIONSPTR_PTR]], align 8
+; CHECK-NEXT: [[FORCOLL_INITIAL_MUTATIONS:%.*]] = load i64, ptr [[MUTATIONSPTR]], align 8
+; CHECK-NEXT: [[STATEITEMS_PTR:%.*]] = getelementptr inbounds [[STRUCT___OBJCFASTENUMERATIONSTATE]], ptr [[STATE_PTR]], i64 0, i32 1
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY_OUTER:.*]]
+; CHECK: [[FORCOLL_LOOPBODY_OUTER]]:
+; CHECK-NEXT: [[FORCOLL_COUNT_PH:%.*]] = phi i64 [ [[CALL]], %[[FORCOLL_LOOPINIT]] ], [ [[CALL6:%.*]], %[[FORCOLL_REFETCH:.*]] ]
+; CHECK-NEXT: [[TMP7:%.*]] = icmp ugt i64 [[FORCOLL_COUNT_PH]], 1
+; CHECK-NEXT: [[UMAX:%.*]] = select i1 [[TMP7]], i64 [[FORCOLL_COUNT_PH]], i64 1
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY:.*]]
+; CHECK: [[FORCOLL_LOOPBODY]]:
+; CHECK-NEXT: [[FORCOLL_INDEX:%.*]] = phi i64 [ 0, %[[FORCOLL_LOOPBODY_OUTER]] ], [ [[TMP3:%.*]], %[[FORCOLL_NOTMUTATED:.*]] ]
+; CHECK-NEXT: [[MUTATIONSPTR3:%.*]] = load ptr, ptr [[MUTATIONSPTR_PTR]], align 8
+; CHECK-NEXT: [[STATEMUTATIONS:%.*]] = load i64, ptr [[MUTATIONSPTR3]], align 8
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[STATEMUTATIONS]], [[FORCOLL_INITIAL_MUTATIONS]]
+; CHECK-NEXT: br i1 [[TMP1]], label %[[FORCOLL_NOTMUTATED]], label %[[FORCOLL_MUTATED:.*]]
+; CHECK: [[FORCOLL_MUTATED]]:
+; CHECK-NEXT: call void @llvm.objc.enumerationMutation(ptr [[TMP0]])
+; CHECK-NEXT: br label %[[FORCOLL_NOTMUTATED]]
+; CHECK: [[FORCOLL_NOTMUTATED]]:
+; CHECK-NEXT: [[STATEITEMS:%.*]] = load ptr, ptr [[STATEITEMS_PTR]], align 8
+; CHECK-NEXT: [[CURRENTITEM_PTR:%.*]] = getelementptr ptr, ptr [[STATEITEMS]], i64 [[FORCOLL_INDEX]]
+; CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[CURRENTITEM_PTR]], align 8
+; CHECK-NEXT: call void @use(ptr [[TMP2]])
+; CHECK-NEXT: [[TMP3]] = add i64 [[FORCOLL_INDEX]], 1
+; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[TMP3]], [[UMAX]]
+; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FORCOLL_REFETCH]], label %[[FORCOLL_LOOPBODY]]
+; CHECK: [[FORCOLL_REFETCH]]:
+; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL6]] = call i64 @objc_msgSend(ptr [[TMP0]], ptr [[TMP5]], ptr [[STATE_PTR]], ptr [[ITEMS_PTR]], i64 16)
+; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i64 [[CALL6]], 0
+; CHECK-NEXT: br i1 [[TMP4]], label %[[FORCOLL_EMPTY]], label %[[FORCOLL_LOOPBODY_OUTER]]
+; CHECK: [[FORCOLL_EMPTY]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP0]]) #[[ATTR0]], !clang.imprecise_release [[META0:![0-9]+]]
+; CHECK-NEXT: ret void
+;
entry:
%state.ptr = alloca %struct.__objcFastEnumerationState, align 8
%items.ptr = alloca [16 x ptr], align 8
@@ -88,11 +133,56 @@ forcoll.empty:
; Delete a nested retain+release pair.
-; CHECK-LABEL: define void @test2(
-; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
-; CHECK-NOT: @llvm.objc.retain
-; CHECK: }
define void @test2() nounwind {
+; CHECK-LABEL: define void @test2(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[STATE_PTR:%.*]] = alloca [[STRUCT___OBJCFASTENUMERATIONSTATE:%.*]], align 8
+; CHECK-NEXT: [[ITEMS_PTR:%.*]] = alloca [16 x ptr], align 8
+; CHECK-NEXT: [[CALL:%.*]] = call ptr @returner()
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[CALL]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[STATE_PTR]], i8 0, i64 64, i1 false)
+; CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL3:%.*]] = call i64 @objc_msgSend(ptr [[TMP0]], ptr [[TMP2]], ptr [[STATE_PTR]], ptr [[ITEMS_PTR]], i64 16)
+; CHECK-NEXT: [[ISZERO:%.*]] = icmp eq i64 [[CALL3]], 0
+; CHECK-NEXT: br i1 [[ISZERO]], label %[[FORCOLL_EMPTY:.*]], label %[[FORCOLL_LOOPINIT:.*]]
+; CHECK: [[FORCOLL_LOOPINIT]]:
+; CHECK-NEXT: [[MUTATIONSPTR_PTR:%.*]] = getelementptr inbounds [[STRUCT___OBJCFASTENUMERATIONSTATE]], ptr [[STATE_PTR]], i64 0, i32 2
+; CHECK-NEXT: [[MUTATIONSPTR:%.*]] = load ptr, ptr [[MUTATIONSPTR_PTR]], align 8
+; CHECK-NEXT: [[FORCOLL_INITIAL_MUTATIONS:%.*]] = load i64, ptr [[MUTATIONSPTR]], align 8
+; CHECK-NEXT: [[STATEITEMS_PTR:%.*]] = getelementptr inbounds [[STRUCT___OBJCFASTENUMERATIONSTATE]], ptr [[STATE_PTR]], i64 0, i32 1
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY_OUTER:.*]]
+; CHECK: [[FORCOLL_LOOPBODY_OUTER]]:
+; CHECK-NEXT: [[FORCOLL_COUNT_PH:%.*]] = phi i64 [ [[CALL3]], %[[FORCOLL_LOOPINIT]] ], [ [[CALL7:%.*]], %[[FORCOLL_REFETCH:.*]] ]
+; CHECK-NEXT: [[TMP8:%.*]] = icmp ugt i64 [[FORCOLL_COUNT_PH]], 1
+; CHECK-NEXT: [[UMAX:%.*]] = select i1 [[TMP8]], i64 [[FORCOLL_COUNT_PH]], i64 1
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY:.*]]
+; CHECK: [[FORCOLL_LOOPBODY]]:
+; CHECK-NEXT: [[FORCOLL_INDEX:%.*]] = phi i64 [ 0, %[[FORCOLL_LOOPBODY_OUTER]] ], [ [[TMP3:%.*]], %[[FORCOLL_NOTMUTATED:.*]] ]
+; CHECK-NEXT: [[MUTATIONSPTR4:%.*]] = load ptr, ptr [[MUTATIONSPTR_PTR]], align 8
+; CHECK-NEXT: [[STATEMUTATIONS:%.*]] = load i64, ptr [[MUTATIONSPTR4]], align 8
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[STATEMUTATIONS]], [[FORCOLL_INITIAL_MUTATIONS]]
+; CHECK-NEXT: br i1 [[TMP1]], label %[[FORCOLL_NOTMUTATED]], label %[[FORCOLL_MUTATED:.*]]
+; CHECK: [[FORCOLL_MUTATED]]:
+; CHECK-NEXT: call void @llvm.objc.enumerationMutation(ptr [[TMP0]])
+; CHECK-NEXT: br label %[[FORCOLL_NOTMUTATED]]
+; CHECK: [[FORCOLL_NOTMUTATED]]:
+; CHECK-NEXT: [[STATEITEMS:%.*]] = load ptr, ptr [[STATEITEMS_PTR]], align 8
+; CHECK-NEXT: [[CURRENTITEM_PTR:%.*]] = getelementptr ptr, ptr [[STATEITEMS]], i64 [[FORCOLL_INDEX]]
+; CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[CURRENTITEM_PTR]], align 8
+; CHECK-NEXT: call void @use(ptr [[TMP2]])
+; CHECK-NEXT: [[TMP3]] = add i64 [[FORCOLL_INDEX]], 1
+; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[TMP3]], [[UMAX]]
+; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FORCOLL_REFETCH]], label %[[FORCOLL_LOOPBODY]]
+; CHECK: [[FORCOLL_REFETCH]]:
+; CHECK-NEXT: [[TMP6:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL7]] = call i64 @objc_msgSend(ptr [[TMP0]], ptr [[TMP6]], ptr [[STATE_PTR]], ptr [[ITEMS_PTR]], i64 16)
+; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i64 [[CALL7]], 0
+; CHECK-NEXT: br i1 [[TMP4]], label %[[FORCOLL_EMPTY]], label %[[FORCOLL_LOOPBODY_OUTER]]
+; CHECK: [[FORCOLL_EMPTY]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP0]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: ret void
+;
entry:
%state.ptr = alloca %struct.__objcFastEnumerationState, align 8
%items.ptr = alloca [16 x ptr], align 8
@@ -152,11 +242,56 @@ forcoll.empty:
; Delete a nested retain+release pair.
-; CHECK-LABEL: define void @test4(
-; CHECK: call ptr @llvm.objc.retain
-; CHECK-NOT: @llvm.objc.retain
-; CHECK: }
define void @test4() nounwind {
+; CHECK-LABEL: define void @test4(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[STATE_PTR:%.*]] = alloca [[STRUCT___OBJCFASTENUMERATIONSTATE:%.*]], align 8
+; CHECK-NEXT: [[ITEMS_PTR:%.*]] = alloca [16 x ptr], align 8
+; CHECK-NEXT: [[TMP:%.*]] = load ptr, ptr @g, align 8
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[TMP]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[STATE_PTR]], i8 0, i64 64, i1 false)
+; CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL:%.*]] = call i64 @objc_msgSend(ptr [[TMP0]], ptr [[TMP4]], ptr [[STATE_PTR]], ptr [[ITEMS_PTR]], i64 16)
+; CHECK-NEXT: [[ISZERO:%.*]] = icmp eq i64 [[CALL]], 0
+; CHECK-NEXT: br i1 [[ISZERO]], label %[[FORCOLL_EMPTY:.*]], label %[[FORCOLL_LOOPINIT:.*]]
+; CHECK: [[FORCOLL_LOOPINIT]]:
+; CHECK-NEXT: [[MUTATIONSPTR_PTR:%.*]] = getelementptr inbounds [[STRUCT___OBJCFASTENUMERATIONSTATE]], ptr [[STATE_PTR]], i64 0, i32 2
+; CHECK-NEXT: [[MUTATIONSPTR:%.*]] = load ptr, ptr [[MUTATIONSPTR_PTR]], align 8
+; CHECK-NEXT: [[FORCOLL_INITIAL_MUTATIONS:%.*]] = load i64, ptr [[MUTATIONSPTR]], align 8
+; CHECK-NEXT: [[STATEITEMS_PTR:%.*]] = getelementptr inbounds [[STRUCT___OBJCFASTENUMERATIONSTATE]], ptr [[STATE_PTR]], i64 0, i32 1
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY_OUTER:.*]]
+; CHECK: [[FORCOLL_LOOPBODY_OUTER]]:
+; CHECK-NEXT: [[FORCOLL_COUNT_PH:%.*]] = phi i64 [ [[CALL]], %[[FORCOLL_LOOPINIT]] ], [ [[CALL8:%.*]], %[[FORCOLL_REFETCH:.*]] ]
+; CHECK-NEXT: [[TMP9:%.*]] = icmp ugt i64 [[FORCOLL_COUNT_PH]], 1
+; CHECK-NEXT: [[UMAX:%.*]] = select i1 [[TMP9]], i64 [[FORCOLL_COUNT_PH]], i64 1
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY:.*]]
+; CHECK: [[FORCOLL_LOOPBODY]]:
+; CHECK-NEXT: [[FORCOLL_INDEX:%.*]] = phi i64 [ 0, %[[FORCOLL_LOOPBODY_OUTER]] ], [ [[TMP3:%.*]], %[[FORCOLL_NOTMUTATED:.*]] ]
+; CHECK-NEXT: [[MUTATIONSPTR5:%.*]] = load ptr, ptr [[MUTATIONSPTR_PTR]], align 8
+; CHECK-NEXT: [[STATEMUTATIONS:%.*]] = load i64, ptr [[MUTATIONSPTR5]], align 8
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[STATEMUTATIONS]], [[FORCOLL_INITIAL_MUTATIONS]]
+; CHECK-NEXT: br i1 [[TMP1]], label %[[FORCOLL_NOTMUTATED]], label %[[FORCOLL_MUTATED:.*]]
+; CHECK: [[FORCOLL_MUTATED]]:
+; CHECK-NEXT: call void @llvm.objc.enumerationMutation(ptr [[TMP0]])
+; CHECK-NEXT: br label %[[FORCOLL_NOTMUTATED]]
+; CHECK: [[FORCOLL_NOTMUTATED]]:
+; CHECK-NEXT: [[STATEITEMS:%.*]] = load ptr, ptr [[STATEITEMS_PTR]], align 8
+; CHECK-NEXT: [[CURRENTITEM_PTR:%.*]] = getelementptr ptr, ptr [[STATEITEMS]], i64 [[FORCOLL_INDEX]]
+; CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[CURRENTITEM_PTR]], align 8
+; CHECK-NEXT: call void @use(ptr [[TMP2]])
+; CHECK-NEXT: [[TMP3]] = add i64 [[FORCOLL_INDEX]], 1
+; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[TMP3]], [[UMAX]]
+; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FORCOLL_REFETCH]], label %[[FORCOLL_LOOPBODY]]
+; CHECK: [[FORCOLL_REFETCH]]:
+; CHECK-NEXT: [[TMP7:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL8]] = call i64 @objc_msgSend(ptr [[TMP0]], ptr [[TMP7]], ptr [[STATE_PTR]], ptr [[ITEMS_PTR]], i64 16)
+; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i64 [[CALL8]], 0
+; CHECK-NEXT: br i1 [[TMP4]], label %[[FORCOLL_EMPTY]], label %[[FORCOLL_LOOPBODY_OUTER]]
+; CHECK: [[FORCOLL_EMPTY]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP0]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: ret void
+;
entry:
%state.ptr = alloca %struct.__objcFastEnumerationState, align 8
%items.ptr = alloca [16 x ptr], align 8
@@ -216,11 +351,56 @@ forcoll.empty:
; Delete a nested retain+release pair.
-; CHECK-LABEL: define void @test5(
-; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
-; CHECK-NOT: @llvm.objc.retain
-; CHECK: }
define void @test5() nounwind {
+; CHECK-LABEL: define void @test5(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[STATE_PTR:%.*]] = alloca [[STRUCT___OBJCFASTENUMERATIONSTATE:%.*]], align 8
+; CHECK-NEXT: [[ITEMS_PTR:%.*]] = alloca [16 x ptr], align 8
+; CHECK-NEXT: [[CALL:%.*]] = call ptr @returner()
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[CALL]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[STATE_PTR]], i8 0, i64 64, i1 false)
+; CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL3:%.*]] = call i64 @objc_msgSend(ptr [[TMP0]], ptr [[TMP2]], ptr [[STATE_PTR]], ptr [[ITEMS_PTR]], i64 16)
+; CHECK-NEXT: [[ISZERO:%.*]] = icmp eq i64 [[CALL3]], 0
+; CHECK-NEXT: br i1 [[ISZERO]], label %[[FORCOLL_EMPTY:.*]], label %[[FORCOLL_LOOPINIT:.*]]
+; CHECK: [[FORCOLL_LOOPINIT]]:
+; CHECK-NEXT: [[MUTATIONSPTR_PTR:%.*]] = getelementptr inbounds [[STRUCT___OBJCFASTENUMERATIONSTATE]], ptr [[STATE_PTR]], i64 0, i32 2
+; CHECK-NEXT: [[MUTATIONSPTR:%.*]] = load ptr, ptr [[MUTATIONSPTR_PTR]], align 8
+; CHECK-NEXT: [[FORCOLL_INITIAL_MUTATIONS:%.*]] = load i64, ptr [[MUTATIONSPTR]], align 8
+; CHECK-NEXT: [[STATEITEMS_PTR:%.*]] = getelementptr inbounds [[STRUCT___OBJCFASTENUMERATIONSTATE]], ptr [[STATE_PTR]], i64 0, i32 1
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY_OUTER:.*]]
+; CHECK: [[FORCOLL_LOOPBODY_OUTER]]:
+; CHECK-NEXT: [[FORCOLL_COUNT_PH:%.*]] = phi i64 [ [[CALL3]], %[[FORCOLL_LOOPINIT]] ], [ [[CALL7:%.*]], %[[FORCOLL_REFETCH:.*]] ]
+; CHECK-NEXT: [[TMP8:%.*]] = icmp ugt i64 [[FORCOLL_COUNT_PH]], 1
+; CHECK-NEXT: [[UMAX:%.*]] = select i1 [[TMP8]], i64 [[FORCOLL_COUNT_PH]], i64 1
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY:.*]]
+; CHECK: [[FORCOLL_LOOPBODY]]:
+; CHECK-NEXT: [[FORCOLL_INDEX:%.*]] = phi i64 [ 0, %[[FORCOLL_LOOPBODY_OUTER]] ], [ [[TMP3:%.*]], %[[FORCOLL_NOTMUTATED:.*]] ]
+; CHECK-NEXT: [[MUTATIONSPTR4:%.*]] = load ptr, ptr [[MUTATIONSPTR_PTR]], align 8
+; CHECK-NEXT: [[STATEMUTATIONS:%.*]] = load i64, ptr [[MUTATIONSPTR4]], align 8
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[STATEMUTATIONS]], [[FORCOLL_INITIAL_MUTATIONS]]
+; CHECK-NEXT: br i1 [[TMP1]], label %[[FORCOLL_NOTMUTATED]], label %[[FORCOLL_MUTATED:.*]]
+; CHECK: [[FORCOLL_MUTATED]]:
+; CHECK-NEXT: call void @llvm.objc.enumerationMutation(ptr [[TMP0]])
+; CHECK-NEXT: br label %[[FORCOLL_NOTMUTATED]]
+; CHECK: [[FORCOLL_NOTMUTATED]]:
+; CHECK-NEXT: [[STATEITEMS:%.*]] = load ptr, ptr [[STATEITEMS_PTR]], align 8
+; CHECK-NEXT: [[CURRENTITEM_PTR:%.*]] = getelementptr ptr, ptr [[STATEITEMS]], i64 [[FORCOLL_INDEX]]
+; CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[CURRENTITEM_PTR]], align 8
+; CHECK-NEXT: call void @use(ptr [[TMP2]])
+; CHECK-NEXT: [[TMP3]] = add i64 [[FORCOLL_INDEX]], 1
+; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[TMP3]], [[UMAX]]
+; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FORCOLL_REFETCH]], label %[[FORCOLL_LOOPBODY]]
+; CHECK: [[FORCOLL_REFETCH]]:
+; CHECK-NEXT: [[TMP6:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL7]] = call i64 @objc_msgSend(ptr [[TMP0]], ptr [[TMP6]], ptr [[STATE_PTR]], ptr [[ITEMS_PTR]], i64 16)
+; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i64 [[CALL7]], 0
+; CHECK-NEXT: br i1 [[TMP4]], label %[[FORCOLL_EMPTY]], label %[[FORCOLL_LOOPBODY_OUTER]]
+; CHECK: [[FORCOLL_EMPTY]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP0]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: ret void
+;
entry:
%state.ptr = alloca %struct.__objcFastEnumerationState, align 8
%items.ptr = alloca [16 x ptr], align 8
@@ -281,11 +461,57 @@ forcoll.empty:
; We handle this now due to the fact that a release just needs a post dominating
; use.
;
-; CHECK-LABEL: define void @test6(
-; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
-; CHECK-NOT: @llvm.objc.retain
-; CHECK: }
define void @test6() nounwind {
+; CHECK-LABEL: define void @test6(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[STATE_PTR:%.*]] = alloca [[STRUCT___OBJCFASTENUMERATIONSTATE:%.*]], align 8
+; CHECK-NEXT: [[ITEMS_PTR:%.*]] = alloca [16 x ptr], align 8
+; CHECK-NEXT: [[CALL:%.*]] = call ptr @returner()
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[CALL]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[STATE_PTR]], i8 0, i64 64, i1 false)
+; CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL3:%.*]] = call i64 @objc_msgSend(ptr [[TMP0]], ptr [[TMP2]], ptr [[STATE_PTR]], ptr [[ITEMS_PTR]], i64 16)
+; CHECK-NEXT: [[ISZERO:%.*]] = icmp eq i64 [[CALL3]], 0
+; CHECK-NEXT: br i1 [[ISZERO]], label %[[FORCOLL_EMPTY:.*]], label %[[FORCOLL_LOOPINIT:.*]]
+; CHECK: [[FORCOLL_LOOPINIT]]:
+; CHECK-NEXT: [[MUTATIONSPTR_PTR:%.*]] = getelementptr inbounds [[STRUCT___OBJCFASTENUMERATIONSTATE]], ptr [[STATE_PTR]], i64 0, i32 2
+; CHECK-NEXT: [[MUTATIONSPTR:%.*]] = load ptr, ptr [[MUTATIONSPTR_PTR]], align 8
+; CHECK-NEXT: [[FORCOLL_INITIAL_MUTATIONS:%.*]] = load i64, ptr [[MUTATIONSPTR]], align 8
+; CHECK-NEXT: [[STATEITEMS_PTR:%.*]] = getelementptr inbounds [[STRUCT___OBJCFASTENUMERATIONSTATE]], ptr [[STATE_PTR]], i64 0, i32 1
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY_OUTER:.*]]
+; CHECK: [[FORCOLL_LOOPBODY_OUTER]]:
+; CHECK-NEXT: [[FORCOLL_COUNT_PH:%.*]] = phi i64 [ [[CALL3]], %[[FORCOLL_LOOPINIT]] ], [ [[CALL7:%.*]], %[[FORCOLL_REFETCH:.*]] ]
+; CHECK-NEXT: [[TMP8:%.*]] = icmp ugt i64 [[FORCOLL_COUNT_PH]], 1
+; CHECK-NEXT: [[UMAX:%.*]] = select i1 [[TMP8]], i64 [[FORCOLL_COUNT_PH]], i64 1
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY:.*]]
+; CHECK: [[FORCOLL_LOOPBODY]]:
+; CHECK-NEXT: [[FORCOLL_INDEX:%.*]] = phi i64 [ 0, %[[FORCOLL_LOOPBODY_OUTER]] ], [ [[TMP3:%.*]], %[[FORCOLL_NOTMUTATED:.*]] ]
+; CHECK-NEXT: [[MUTATIONSPTR4:%.*]] = load ptr, ptr [[MUTATIONSPTR_PTR]], align 8
+; CHECK-NEXT: [[STATEMUTATIONS:%.*]] = load i64, ptr [[MUTATIONSPTR4]], align 8
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[STATEMUTATIONS]], [[FORCOLL_INITIAL_MUTATIONS]]
+; CHECK-NEXT: br i1 [[TMP1]], label %[[FORCOLL_NOTMUTATED]], label %[[FORCOLL_MUTATED:.*]]
+; CHECK: [[FORCOLL_MUTATED]]:
+; CHECK-NEXT: call void @llvm.objc.enumerationMutation(ptr [[TMP0]])
+; CHECK-NEXT: br label %[[FORCOLL_NOTMUTATED]]
+; CHECK: [[FORCOLL_NOTMUTATED]]:
+; CHECK-NEXT: [[STATEITEMS:%.*]] = load ptr, ptr [[STATEITEMS_PTR]], align 8
+; CHECK-NEXT: [[CURRENTITEM_PTR:%.*]] = getelementptr ptr, ptr [[STATEITEMS]], i64 [[FORCOLL_INDEX]]
+; CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[CURRENTITEM_PTR]], align 8
+; CHECK-NEXT: call void @use(ptr [[TMP2]])
+; CHECK-NEXT: [[TMP3]] = add i64 [[FORCOLL_INDEX]], 1
+; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[TMP3]], [[UMAX]]
+; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FORCOLL_REFETCH]], label %[[FORCOLL_LOOPBODY]]
+; CHECK: [[FORCOLL_REFETCH]]:
+; CHECK-NEXT: [[TMP6:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL7]] = call i64 @objc_msgSend(ptr [[TMP0]], ptr [[TMP6]], ptr [[STATE_PTR]], ptr [[ITEMS_PTR]], i64 16)
+; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i64 [[CALL7]], 0
+; CHECK-NEXT: br i1 [[TMP4]], label %[[FORCOLL_EMPTY]], label %[[FORCOLL_LOOPBODY_OUTER]]
+; CHECK: [[FORCOLL_EMPTY]]:
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP0]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: ret void
+;
entry:
%state.ptr = alloca %struct.__objcFastEnumerationState, align 8
%items.ptr = alloca [16 x ptr], align 8
@@ -348,11 +574,60 @@ forcoll.empty:
; The optimizer currently can't do this, because isn't isn't sophisticated enough in
; reasnoning about nesting.
-; CHECK-LABEL: define void @test7(
-; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
-; CHECK: @llvm.objc.retain
-; CHECK: }
define void @test7() nounwind {
+; CHECK-LABEL: define void @test7(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[STATE_PTR:%.*]] = alloca [[STRUCT___OBJCFASTENUMERATIONSTATE:%.*]], align 8
+; CHECK-NEXT: [[ITEMS_PTR:%.*]] = alloca [16 x ptr], align 8
+; CHECK-NEXT: [[CALL:%.*]] = call ptr @returner()
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[CALL]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[STATE_PTR]], i8 0, i64 64, i1 false)
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[TMP0]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL3:%.*]] = call i64 @objc_msgSend(ptr [[TMP1]], ptr [[TMP2]], ptr [[STATE_PTR]], ptr [[ITEMS_PTR]], i64 16)
+; CHECK-NEXT: [[ISZERO:%.*]] = icmp eq i64 [[CALL3]], 0
+; CHECK-NEXT: br i1 [[ISZERO]], label %[[FORCOLL_EMPTY:.*]], label %[[FORCOLL_LOOPINIT:.*]]
+; CHECK: [[FORCOLL_LOOPINIT]]:
+; CHECK-NEXT: [[MUTATIONSPTR_PTR:%.*]] = getelementptr inbounds [[STRUCT___OBJCFASTENUMERATIONSTATE]], ptr [[STATE_PTR]], i64 0, i32 2
+; CHECK-NEXT: [[MUTATIONSPTR:%.*]] = load ptr, ptr [[MUTATIONSPTR_PTR]], align 8
+; CHECK-NEXT: [[FORCOLL_INITIAL_MUTATIONS:%.*]] = load i64, ptr [[MUTATIONSPTR]], align 8
+; CHECK-NEXT: [[STATEITEMS_PTR:%.*]] = getelementptr inbounds [[STRUCT___OBJCFASTENUMERATIONSTATE]], ptr [[STATE_PTR]], i64 0, i32 1
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY_OUTER:.*]]
+; CHECK: [[FORCOLL_LOOPBODY_OUTER]]:
+; CHECK-NEXT: [[FORCOLL_COUNT_PH:%.*]] = phi i64 [ [[CALL3]], %[[FORCOLL_LOOPINIT]] ], [ [[CALL7:%.*]], %[[FORCOLL_REFETCH:.*]] ]
+; CHECK-NEXT: [[TMP8:%.*]] = icmp ugt i64 [[FORCOLL_COUNT_PH]], 1
+; CHECK-NEXT: [[UMAX:%.*]] = select i1 [[TMP8]], i64 [[FORCOLL_COUNT_PH]], i64 1
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY:.*]]
+; CHECK: [[FORCOLL_LOOPBODY]]:
+; CHECK-NEXT: [[FORCOLL_INDEX:%.*]] = phi i64 [ 0, %[[FORCOLL_LOOPBODY_OUTER]] ], [ [[TMP4:%.*]], %[[FORCOLL_NOTMUTATED:.*]] ]
+; CHECK-NEXT: [[MUTATIONSPTR4:%.*]] = load ptr, ptr [[MUTATIONSPTR_PTR]], align 8
+; CHECK-NEXT: [[STATEMUTATIONS:%.*]] = load i64, ptr [[MUTATIONSPTR4]], align 8
+; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[STATEMUTATIONS]], [[FORCOLL_INITIAL_MUTATIONS]]
+; CHECK-NEXT: br i1 [[TMP2]], label %[[FORCOLL_NOTMUTATED]], label %[[FORCOLL_MUTATED:.*]]
+; CHECK: [[FORCOLL_MUTATED]]:
+; CHECK-NEXT: call void @llvm.objc.enumerationMutation(ptr [[TMP1]])
+; CHECK-NEXT: br label %[[FORCOLL_NOTMUTATED]]
+; CHECK: [[FORCOLL_NOTMUTATED]]:
+; CHECK-NEXT: [[STATEITEMS:%.*]] = load ptr, ptr [[STATEITEMS_PTR]], align 8
+; CHECK-NEXT: [[CURRENTITEM_PTR:%.*]] = getelementptr ptr, ptr [[STATEITEMS]], i64 [[FORCOLL_INDEX]]
+; CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[CURRENTITEM_PTR]], align 8
+; CHECK-NEXT: call void @use(ptr [[TMP3]])
+; CHECK-NEXT: [[TMP4]] = add i64 [[FORCOLL_INDEX]], 1
+; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[TMP4]], [[UMAX]]
+; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FORCOLL_REFETCH]], label %[[FORCOLL_LOOPBODY]]
+; CHECK: [[FORCOLL_REFETCH]]:
+; CHECK-NEXT: [[TMP6:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL7]] = call i64 @objc_msgSend(ptr [[TMP1]], ptr [[TMP6]], ptr [[STATE_PTR]], ptr [[ITEMS_PTR]], i64 16)
+; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i64 [[CALL7]], 0
+; CHECK-NEXT: br i1 [[TMP5]], label %[[FORCOLL_EMPTY]], label %[[FORCOLL_LOOPBODY_OUTER]]
+; CHECK: [[FORCOLL_EMPTY]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP1]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP0]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: ret void
+;
entry:
%state.ptr = alloca %struct.__objcFastEnumerationState, align 8
%items.ptr = alloca [16 x ptr], align 8
@@ -414,11 +689,61 @@ forcoll.empty:
; Delete a nested retain+release pair.
-; CHECK-LABEL: define void @test8(
-; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
-; CHECK-NOT: @llvm.objc.retain
-; CHECK: }
define void @test8() nounwind {
+; CHECK-LABEL: define void @test8(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[STATE_PTR:%.*]] = alloca [[STRUCT___OBJCFASTENUMERATIONSTATE:%.*]], align 8
+; CHECK-NEXT: [[ITEMS_PTR:%.*]] = alloca [16 x ptr], align 8
+; CHECK-NEXT: [[CALL:%.*]] = call ptr @returner()
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[CALL]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[STATE_PTR]], i8 0, i64 64, i1 false)
+; CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL3:%.*]] = call i64 @objc_msgSend(ptr [[TMP0]], ptr [[TMP2]], ptr [[STATE_PTR]], ptr [[ITEMS_PTR]], i64 16)
+; CHECK-NEXT: [[ISZERO:%.*]] = icmp eq i64 [[CALL3]], 0
+; CHECK-NEXT: br i1 [[ISZERO]], label %[[FORCOLL_EMPTY:.*]], label %[[FORCOLL_LOOPINIT:.*]]
+; CHECK: [[FORCOLL_LOOPINIT]]:
+; CHECK-NEXT: [[MUTATIONSPTR_PTR:%.*]] = getelementptr inbounds [[STRUCT___OBJCFASTENUMERATIONSTATE]], ptr [[STATE_PTR]], i64 0, i32 2
+; CHECK-NEXT: [[MUTATIONSPTR:%.*]] = load ptr, ptr [[MUTATIONSPTR_PTR]], align 8
+; CHECK-NEXT: [[FORCOLL_INITIAL_MUTATIONS:%.*]] = load i64, ptr [[MUTATIONSPTR]], align 8
+; CHECK-NEXT: [[STATEITEMS_PTR:%.*]] = getelementptr inbounds [[STRUCT___OBJCFASTENUMERATIONSTATE]], ptr [[STATE_PTR]], i64 0, i32 1
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY_OUTER:.*]]
+; CHECK: [[FORCOLL_LOOPBODY_OUTER]]:
+; CHECK-NEXT: [[FORCOLL_COUNT_PH:%.*]] = phi i64 [ [[CALL3]], %[[FORCOLL_LOOPINIT]] ], [ [[CALL7:%.*]], %[[FORCOLL_REFETCH:.*]] ]
+; CHECK-NEXT: [[TMP8:%.*]] = icmp ugt i64 [[FORCOLL_COUNT_PH]], 1
+; CHECK-NEXT: [[UMAX:%.*]] = select i1 [[TMP8]], i64 [[FORCOLL_COUNT_PH]], i64 1
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY:.*]]
+; CHECK: [[FORCOLL_LOOPBODY]]:
+; CHECK-NEXT: [[FORCOLL_INDEX:%.*]] = phi i64 [ 0, %[[FORCOLL_LOOPBODY_OUTER]] ], [ [[TMP3:%.*]], %[[FORCOLL_NEXT:.*]] ]
+; CHECK-NEXT: [[MUTATIONSPTR4:%.*]] = load ptr, ptr [[MUTATIONSPTR_PTR]], align 8
+; CHECK-NEXT: [[STATEMUTATIONS:%.*]] = load i64, ptr [[MUTATIONSPTR4]], align 8
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[STATEMUTATIONS]], [[FORCOLL_INITIAL_MUTATIONS]]
+; CHECK-NEXT: br i1 [[TMP1]], label %[[FORCOLL_NOTMUTATED:.*]], label %[[FORCOLL_MUTATED:.*]]
+; CHECK: [[FORCOLL_MUTATED]]:
+; CHECK-NEXT: call void @llvm.objc.enumerationMutation(ptr [[TMP0]])
+; CHECK-NEXT: br label %[[FORCOLL_NOTMUTATED]]
+; CHECK: [[FORCOLL_NOTMUTATED]]:
+; CHECK-NEXT: [[STATEITEMS:%.*]] = load ptr, ptr [[STATEITEMS_PTR]], align 8
+; CHECK-NEXT: [[CURRENTITEM_PTR:%.*]] = getelementptr ptr, ptr [[STATEITEMS]], i64 [[FORCOLL_INDEX]]
+; CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[CURRENTITEM_PTR]], align 8
+; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq ptr [[TMP2]], null
+; CHECK-NEXT: br i1 [[TOBOOL]], label %[[FORCOLL_NEXT]], label %[[IF_THEN:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: br label %[[FORCOLL_NEXT]]
+; CHECK: [[FORCOLL_NEXT]]:
+; CHECK-NEXT: [[TMP3]] = add i64 [[FORCOLL_INDEX]], 1
+; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[TMP3]], [[UMAX]]
+; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FORCOLL_REFETCH]], label %[[FORCOLL_LOOPBODY]]
+; CHECK: [[FORCOLL_REFETCH]]:
+; CHECK-NEXT: [[TMP6:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL7]] = call i64 @objc_msgSend(ptr [[TMP0]], ptr [[TMP6]], ptr [[STATE_PTR]], ptr [[ITEMS_PTR]], i64 16)
+; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i64 [[CALL7]], 0
+; CHECK-NEXT: br i1 [[TMP4]], label %[[FORCOLL_EMPTY]], label %[[FORCOLL_LOOPBODY_OUTER]]
+; CHECK: [[FORCOLL_EMPTY]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP0]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: ret void
+;
entry:
%state.ptr = alloca %struct.__objcFastEnumerationState, align 8
%items.ptr = alloca [16 x ptr], align 8
@@ -487,12 +812,58 @@ forcoll.empty:
; The optimizer currently can't do this, because of a split loop backedge.
; See test9b for the same testcase without a split backedge.
-; CHECK-LABEL: define void @test9(
-; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
-; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
-; CHECK: call ptr @llvm.objc.retain
-; CHECK: }
define void @test9() nounwind {
+; CHECK-LABEL: define void @test9(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[STATE_PTR:%.*]] = alloca [[STRUCT___OBJCFASTENUMERATIONSTATE:%.*]], align 8
+; CHECK-NEXT: [[ITEMS_PTR:%.*]] = alloca [16 x ptr], align 8
+; CHECK-NEXT: [[CALL:%.*]] = call ptr @returner()
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[CALL]]) #[[ATTR0]]
+; CHECK-NEXT: [[CALL1:%.*]] = call ptr @returner()
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[CALL1]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[STATE_PTR]], i8 0, i64 64, i1 false)
+; CHECK-NEXT: [[TMP2:%.*]] = tail call ptr @llvm.objc.retain(ptr [[TMP0]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL4:%.*]] = call i64 @objc_msgSend(ptr [[TMP2]], ptr [[TMP3]], ptr [[STATE_PTR]], ptr [[ITEMS_PTR]], i64 16)
+; CHECK-NEXT: [[ISZERO:%.*]] = icmp eq i64 [[CALL4]], 0
+; CHECK-NEXT: br i1 [[ISZERO]], label %[[FORCOLL_EMPTY:.*]], label %[[FORCOLL_LOOPINIT:.*]]
+; CHECK: [[FORCOLL_LOOPINIT]]:
+; CHECK-NEXT: [[MUTATIONSPTR_PTR:%.*]] = getelementptr inbounds [[STRUCT___OBJCFASTENUMERATIONSTATE]], ptr [[STATE_PTR]], i64 0, i32 2
+; CHECK-NEXT: [[MUTATIONSPTR:%.*]] = load ptr, ptr [[MUTATIONSPTR_PTR]], align 8
+; CHECK-NEXT: [[FORCOLL_INITIAL_MUTATIONS:%.*]] = load i64, ptr [[MUTATIONSPTR]], align 8
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY_OUTER:.*]]
+; CHECK: [[FORCOLL_LOOPBODY_OUTER]]:
+; CHECK-NEXT: [[FORCOLL_COUNT_PH:%.*]] = phi i64 [ [[CALL4]], %[[FORCOLL_LOOPINIT]] ], [ [[CALL7:%.*]], %[[FORCOLL_REFETCH:.*]] ]
+; CHECK-NEXT: [[TMP9:%.*]] = icmp ugt i64 [[FORCOLL_COUNT_PH]], 1
+; CHECK-NEXT: [[UMAX:%.*]] = select i1 [[TMP9]], i64 [[FORCOLL_COUNT_PH]], i64 1
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY:.*]]
+; CHECK: [[FORCOLL_LOOPBODY]]:
+; CHECK-NEXT: [[FORCOLL_INDEX:%.*]] = phi i64 [ [[PHITMP:%.*]], %[[FORCOLL_NOTMUTATED_FORCOLL_LOOPBODY_CRIT_EDGE:.*]] ], [ 1, %[[FORCOLL_LOOPBODY_OUTER]] ]
+; CHECK-NEXT: [[MUTATIONSPTR5:%.*]] = load ptr, ptr [[MUTATIONSPTR_PTR]], align 8
+; CHECK-NEXT: [[STATEMUTATIONS:%.*]] = load i64, ptr [[MUTATIONSPTR5]], align 8
+; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i64 [[STATEMUTATIONS]], [[FORCOLL_INITIAL_MUTATIONS]]
+; CHECK-NEXT: br i1 [[TMP3]], label %[[FORCOLL_NOTMUTATED:.*]], label %[[FORCOLL_MUTATED:.*]]
+; CHECK: [[FORCOLL_MUTATED]]:
+; CHECK-NEXT: call void @llvm.objc.enumerationMutation(ptr [[TMP2]])
+; CHECK-NEXT: br label %[[FORCOLL_NOTMUTATED]]
+; CHECK: [[FORCOLL_NOTMUTATED]]:
+; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[FORCOLL_INDEX]], [[UMAX]]
+; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FORCOLL_REFETCH]], label %[[FORCOLL_NOTMUTATED_FORCOLL_LOOPBODY_CRIT_EDGE]]
+; CHECK: [[FORCOLL_NOTMUTATED_FORCOLL_LOOPBODY_CRIT_EDGE]]:
+; CHECK-NEXT: [[PHITMP]] = add i64 [[FORCOLL_INDEX]], 1
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY]]
+; CHECK: [[FORCOLL_REFETCH]]:
+; CHECK-NEXT: [[TMP6:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL7]] = call i64 @objc_msgSend(ptr [[TMP2]], ptr [[TMP6]], ptr [[STATE_PTR]], ptr [[ITEMS_PTR]], i64 16)
+; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i64 [[CALL7]], 0
+; CHECK-NEXT: br i1 [[TMP4]], label %[[FORCOLL_EMPTY]], label %[[FORCOLL_LOOPBODY_OUTER]]
+; CHECK: [[FORCOLL_EMPTY]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP2]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP1]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP0]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: ret void
+;
entry:
%state.ptr = alloca %struct.__objcFastEnumerationState, align 8
%items.ptr = alloca [16 x ptr], align 8
@@ -553,12 +924,56 @@ forcoll.empty:
; Like test9, but without a split backedge. TODO: optimize this.
-; CHECK-LABEL: define void @test9b(
-; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
-; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
-; CHECK: @llvm.objc.retain
-; CHECK: }
define void @test9b() nounwind {
+; CHECK-LABEL: define void @test9b(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[STATE_PTR:%.*]] = alloca [[STRUCT___OBJCFASTENUMERATIONSTATE:%.*]], align 8
+; CHECK-NEXT: [[ITEMS_PTR:%.*]] = alloca [16 x ptr], align 8
+; CHECK-NEXT: [[CALL:%.*]] = call ptr @returner()
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[CALL]]) #[[ATTR0]]
+; CHECK-NEXT: [[CALL1:%.*]] = call ptr @returner()
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[CALL1]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[STATE_PTR]], i8 0, i64 64, i1 false)
+; CHECK-NEXT: [[TMP2:%.*]] = tail call ptr @llvm.objc.retain(ptr [[TMP0]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL4:%.*]] = call i64 @objc_msgSend(ptr [[TMP2]], ptr [[TMP3]], ptr [[STATE_PTR]], ptr [[ITEMS_PTR]], i64 16)
+; CHECK-NEXT: [[ISZERO:%.*]] = icmp eq i64 [[CALL4]], 0
+; CHECK-NEXT: br i1 [[ISZERO]], label %[[FORCOLL_EMPTY:.*]], label %[[FORCOLL_LOOPINIT:.*]]
+; CHECK: [[FORCOLL_LOOPINIT]]:
+; CHECK-NEXT: [[MUTATIONSPTR_PTR:%.*]] = getelementptr inbounds [[STRUCT___OBJCFASTENUMERATIONSTATE]], ptr [[STATE_PTR]], i64 0, i32 2
+; CHECK-NEXT: [[MUTATIONSPTR:%.*]] = load ptr, ptr [[MUTATIONSPTR_PTR]], align 8
+; CHECK-NEXT: [[FORCOLL_INITIAL_MUTATIONS:%.*]] = load i64, ptr [[MUTATIONSPTR]], align 8
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY_OUTER:.*]]
+; CHECK: [[FORCOLL_LOOPBODY_OUTER]]:
+; CHECK-NEXT: [[FORCOLL_COUNT_PH:%.*]] = phi i64 [ [[CALL4]], %[[FORCOLL_LOOPINIT]] ], [ [[CALL7:%.*]], %[[FORCOLL_REFETCH:.*]] ]
+; CHECK-NEXT: [[TMP9:%.*]] = icmp ugt i64 [[FORCOLL_COUNT_PH]], 1
+; CHECK-NEXT: [[UMAX:%.*]] = select i1 [[TMP9]], i64 [[FORCOLL_COUNT_PH]], i64 1
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY:.*]]
+; CHECK: [[FORCOLL_LOOPBODY]]:
+; CHECK-NEXT: [[FORCOLL_INDEX:%.*]] = phi i64 [ [[PHITMP:%.*]], %[[FORCOLL_NOTMUTATED:.*]] ], [ 0, %[[FORCOLL_LOOPBODY_OUTER]] ]
+; CHECK-NEXT: [[MUTATIONSPTR5:%.*]] = load ptr, ptr [[MUTATIONSPTR_PTR]], align 8
+; CHECK-NEXT: [[STATEMUTATIONS:%.*]] = load i64, ptr [[MUTATIONSPTR5]], align 8
+; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i64 [[STATEMUTATIONS]], [[FORCOLL_INITIAL_MUTATIONS]]
+; CHECK-NEXT: br i1 [[TMP3]], label %[[FORCOLL_NOTMUTATED]], label %[[FORCOLL_MUTATED:.*]]
+; CHECK: [[FORCOLL_MUTATED]]:
+; CHECK-NEXT: call void @llvm.objc.enumerationMutation(ptr [[TMP2]])
+; CHECK-NEXT: br label %[[FORCOLL_NOTMUTATED]]
+; CHECK: [[FORCOLL_NOTMUTATED]]:
+; CHECK-NEXT: [[PHITMP]] = add i64 [[FORCOLL_INDEX]], 1
+; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[PHITMP]], [[UMAX]]
+; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FORCOLL_REFETCH]], label %[[FORCOLL_LOOPBODY]]
+; CHECK: [[FORCOLL_REFETCH]]:
+; CHECK-NEXT: [[TMP6:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL7]] = call i64 @objc_msgSend(ptr [[TMP2]], ptr [[TMP6]], ptr [[STATE_PTR]], ptr [[ITEMS_PTR]], i64 16)
+; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i64 [[CALL7]], 0
+; CHECK-NEXT: br i1 [[TMP4]], label %[[FORCOLL_EMPTY]], label %[[FORCOLL_LOOPBODY_OUTER]]
+; CHECK: [[FORCOLL_EMPTY]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP2]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP1]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP0]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: ret void
+;
entry:
%state.ptr = alloca %struct.__objcFastEnumerationState, align 8
%items.ptr = alloca [16 x ptr], align 8
@@ -618,12 +1033,59 @@ forcoll.empty:
; The optimizer currently can't do this, because of a split loop backedge.
; See test10b for the same testcase without a split backedge.
-; CHECK-LABEL: define void @test10(
-; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
-; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
-; CHECK: call ptr @llvm.objc.retain
-; CHECK: }
define void @test10() nounwind {
+; CHECK-LABEL: define void @test10(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[STATE_PTR:%.*]] = alloca [[STRUCT___OBJCFASTENUMERATIONSTATE:%.*]], align 8
+; CHECK-NEXT: [[ITEMS_PTR:%.*]] = alloca [16 x ptr], align 8
+; CHECK-NEXT: [[CALL:%.*]] = call ptr @returner()
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[CALL]]) #[[ATTR0]]
+; CHECK-NEXT: [[CALL1:%.*]] = call ptr @returner()
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[CALL1]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[STATE_PTR]], i8 0, i64 64, i1 false)
+; CHECK-NEXT: [[TMP2:%.*]] = tail call ptr @llvm.objc.retain(ptr [[TMP0]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL4:%.*]] = call i64 @objc_msgSend(ptr [[TMP2]], ptr [[TMP3]], ptr [[STATE_PTR]], ptr [[ITEMS_PTR]], i64 16)
+; CHECK-NEXT: [[ISZERO:%.*]] = icmp eq i64 [[CALL4]], 0
+; CHECK-NEXT: br i1 [[ISZERO]], label %[[FORCOLL_EMPTY:.*]], label %[[FORCOLL_LOOPINIT:.*]]
+; CHECK: [[FORCOLL_LOOPINIT]]:
+; CHECK-NEXT: [[MUTATIONSPTR_PTR:%.*]] = getelementptr inbounds [[STRUCT___OBJCFASTENUMERATIONSTATE]], ptr [[STATE_PTR]], i64 0, i32 2
+; CHECK-NEXT: [[MUTATIONSPTR:%.*]] = load ptr, ptr [[MUTATIONSPTR_PTR]], align 8
+; CHECK-NEXT: [[FORCOLL_INITIAL_MUTATIONS:%.*]] = load i64, ptr [[MUTATIONSPTR]], align 8
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY_OUTER:.*]]
+; CHECK: [[FORCOLL_LOOPBODY_OUTER]]:
+; CHECK-NEXT: [[FORCOLL_COUNT_PH:%.*]] = phi i64 [ [[CALL4]], %[[FORCOLL_LOOPINIT]] ], [ [[CALL7:%.*]], %[[FORCOLL_REFETCH:.*]] ]
+; CHECK-NEXT: [[TMP9:%.*]] = icmp ugt i64 [[FORCOLL_COUNT_PH]], 1
+; CHECK-NEXT: [[UMAX:%.*]] = select i1 [[TMP9]], i64 [[FORCOLL_COUNT_PH]], i64 1
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY:.*]]
+; CHECK: [[FORCOLL_LOOPBODY]]:
+; CHECK-NEXT: [[FORCOLL_INDEX:%.*]] = phi i64 [ [[PHITMP:%.*]], %[[FORCOLL_NOTMUTATED_FORCOLL_LOOPBODY_CRIT_EDGE:.*]] ], [ 1, %[[FORCOLL_LOOPBODY_OUTER]] ]
+; CHECK-NEXT: [[MUTATIONSPTR5:%.*]] = load ptr, ptr [[MUTATIONSPTR_PTR]], align 8
+; CHECK-NEXT: [[STATEMUTATIONS:%.*]] = load i64, ptr [[MUTATIONSPTR5]], align 8
+; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i64 [[STATEMUTATIONS]], [[FORCOLL_INITIAL_MUTATIONS]]
+; CHECK-NEXT: br i1 [[TMP3]], label %[[FORCOLL_NOTMUTATED:.*]], label %[[FORCOLL_MUTATED:.*]]
+; CHECK: [[FORCOLL_MUTATED]]:
+; CHECK-NEXT: call void @llvm.objc.enumerationMutation(ptr [[TMP2]])
+; CHECK-NEXT: br label %[[FORCOLL_NOTMUTATED]]
+; CHECK: [[FORCOLL_NOTMUTATED]]:
+; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[FORCOLL_INDEX]], [[UMAX]]
+; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FORCOLL_REFETCH]], label %[[FORCOLL_NOTMUTATED_FORCOLL_LOOPBODY_CRIT_EDGE]]
+; CHECK: [[FORCOLL_NOTMUTATED_FORCOLL_LOOPBODY_CRIT_EDGE]]:
+; CHECK-NEXT: [[PHITMP]] = add i64 [[FORCOLL_INDEX]], 1
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY]]
+; CHECK: [[FORCOLL_REFETCH]]:
+; CHECK-NEXT: [[TMP6:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL7]] = call i64 @objc_msgSend(ptr [[TMP2]], ptr [[TMP6]], ptr [[STATE_PTR]], ptr [[ITEMS_PTR]], i64 16)
+; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i64 [[CALL7]], 0
+; CHECK-NEXT: br i1 [[TMP4]], label %[[FORCOLL_EMPTY]], label %[[FORCOLL_LOOPBODY_OUTER]]
+; CHECK: [[FORCOLL_EMPTY]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP2]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP1]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP0]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: ret void
+;
entry:
%state.ptr = alloca %struct.__objcFastEnumerationState, align 8
%items.ptr = alloca [16 x ptr], align 8
@@ -685,12 +1147,57 @@ forcoll.empty:
; Like test10, but without a split backedge. TODO: optimize this.
-; CHECK-LABEL: define void @test10b(
-; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
-; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue
-; CHECK: @llvm.objc.retain
-; CHECK: }
define void @test10b() nounwind {
+; CHECK-LABEL: define void @test10b(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[STATE_PTR:%.*]] = alloca [[STRUCT___OBJCFASTENUMERATIONSTATE:%.*]], align 8
+; CHECK-NEXT: [[ITEMS_PTR:%.*]] = alloca [16 x ptr], align 8
+; CHECK-NEXT: [[CALL:%.*]] = call ptr @returner()
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[CALL]]) #[[ATTR0]]
+; CHECK-NEXT: [[CALL1:%.*]] = call ptr @returner()
+; CHECK-NEXT: [[TMP1:%.*]] = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[CALL1]]) #[[ATTR0]]
+; CHECK-NEXT: call void @callee()
+; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[STATE_PTR]], i8 0, i64 64, i1 false)
+; CHECK-NEXT: [[TMP2:%.*]] = tail call ptr @llvm.objc.retain(ptr [[TMP0]]) #[[ATTR0]]
+; CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL4:%.*]] = call i64 @objc_msgSend(ptr [[TMP2]], ptr [[TMP3]], ptr [[STATE_PTR]], ptr [[ITEMS_PTR]], i64 16)
+; CHECK-NEXT: [[ISZERO:%.*]] = icmp eq i64 [[CALL4]], 0
+; CHECK-NEXT: br i1 [[ISZERO]], label %[[FORCOLL_EMPTY:.*]], label %[[FORCOLL_LOOPINIT:.*]]
+; CHECK: [[FORCOLL_LOOPINIT]]:
+; CHECK-NEXT: [[MUTATIONSPTR_PTR:%.*]] = getelementptr inbounds [[STRUCT___OBJCFASTENUMERATIONSTATE]], ptr [[STATE_PTR]], i64 0, i32 2
+; CHECK-NEXT: [[MUTATIONSPTR:%.*]] = load ptr, ptr [[MUTATIONSPTR_PTR]], align 8
+; CHECK-NEXT: [[FORCOLL_INITIAL_MUTATIONS:%.*]] = load i64, ptr [[MUTATIONSPTR]], align 8
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY_OUTER:.*]]
+; CHECK: [[FORCOLL_LOOPBODY_OUTER]]:
+; CHECK-NEXT: [[FORCOLL_COUNT_PH:%.*]] = phi i64 [ [[CALL4]], %[[FORCOLL_LOOPINIT]] ], [ [[CALL7:%.*]], %[[FORCOLL_REFETCH:.*]] ]
+; CHECK-NEXT: [[TMP9:%.*]] = icmp ugt i64 [[FORCOLL_COUNT_PH]], 1
+; CHECK-NEXT: [[UMAX:%.*]] = select i1 [[TMP9]], i64 [[FORCOLL_COUNT_PH]], i64 1
+; CHECK-NEXT: br label %[[FORCOLL_LOOPBODY:.*]]
+; CHECK: [[FORCOLL_LOOPBODY]]:
+; CHECK-NEXT: [[FORCOLL_INDEX:%.*]] = phi i64 [ [[PHITMP:%.*]], %[[FORCOLL_NOTMUTATED:.*]] ], [ 0, %[[FORCOLL_LOOPBODY_OUTER]] ]
+; CHECK-NEXT: [[MUTATIONSPTR5:%.*]] = load ptr, ptr [[MUTATIONSPTR_PTR]], align 8
+; CHECK-NEXT: [[STATEMUTATIONS:%.*]] = load i64, ptr [[MUTATIONSPTR5]], align 8
+; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i64 [[STATEMUTATIONS]], [[FORCOLL_INITIAL_MUTATIONS]]
+; CHECK-NEXT: br i1 [[TMP3]], label %[[FORCOLL_NOTMUTATED]], label %[[FORCOLL_MUTATED:.*]]
+; CHECK: [[FORCOLL_MUTATED]]:
+; CHECK-NEXT: call void @llvm.objc.enumerationMutation(ptr [[TMP2]])
+; CHECK-NEXT: br label %[[FORCOLL_NOTMUTATED]]
+; CHECK: [[FORCOLL_NOTMUTATED]]:
+; CHECK-NEXT: [[PHITMP]] = add i64 [[FORCOLL_INDEX]], 1
+; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[PHITMP]], [[UMAX]]
+; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FORCOLL_REFETCH]], label %[[FORCOLL_LOOPBODY]]
+; CHECK: [[FORCOLL_REFETCH]]:
+; CHECK-NEXT: [[TMP6:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
+; CHECK-NEXT: [[CALL7]] = call i64 @objc_msgSend(ptr [[TMP2]], ptr [[TMP6]], ptr [[STATE_PTR]], ptr [[ITEMS_PTR]], i64 16)
+; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i64 [[CALL7]], 0
+; CHECK-NEXT: br i1 [[TMP4]], label %[[FORCOLL_EMPTY]], label %[[FORCOLL_LOOPBODY_OUTER]]
+; CHECK: [[FORCOLL_EMPTY]]:
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP2]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP1]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[TMP0]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: ret void
+;
entry:
%state.ptr = alloca %struct.__objcFastEnumerationState, align 8
%items.ptr = alloca [16 x ptr], align 8
@@ -756,12 +1263,51 @@ forcoll.empty:
@__block_d_tmp = external hidden constant { i64, i64, ptr, ptr, ptr, ptr }
@__block_d_tmp5 = external hidden constant { i64, i64, ptr, ptr, ptr, ptr }
-; CHECK-LABEL: define void @test11(
-; CHECK: tail call ptr @llvm.objc.retain(ptr %call) [[NUW:#[0-9]+]]
-; CHECK: tail call ptr @llvm.objc.retain(ptr %call) [[NUW]]
-; CHECK: call void @llvm.objc.release(ptr %call) [[NUW]], !clang.imprecise_release !0
-; CHECK: }
define void @test11() {
+; CHECK-LABEL: define void @test11() {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[BLOCK:%.*]] = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8
+; CHECK-NEXT: [[BLOCK9:%.*]] = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8
+; CHECK-NEXT: [[CALL:%.*]] = call ptr @def(), !clang.arc.no_objc_arc_exceptions [[META0]]
+; CHECK-NEXT: [[FOO:%.*]] = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr [[BLOCK]], i64 0, i32 5
+; CHECK-NEXT: [[BLOCK_ISA:%.*]] = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr [[BLOCK]], i64 0, i32 0
+; CHECK-NEXT: store ptr @_NSConcreteStackBlock, ptr [[BLOCK_ISA]], align 8
+; CHECK-NEXT: [[BLOCK_FLAGS:%.*]] = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr [[BLOCK]], i64 0, i32 1
+; CHECK-NEXT: store i32 1107296256, ptr [[BLOCK_FLAGS]], align 8
+; CHECK-NEXT: [[BLOCK_RESERVED:%.*]] = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr [[BLOCK]], i64 0, i32 2
+; CHECK-NEXT: store i32 0, ptr [[BLOCK_RESERVED]], align 4
+; CHECK-NEXT: [[BLOCK_INVOKE:%.*]] = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr [[BLOCK]], i64 0, i32 3
+; CHECK-NEXT: store ptr @__crasher_block_invoke, ptr [[BLOCK_INVOKE]], align 8
+; CHECK-NEXT: [[BLOCK_D:%.*]] = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr [[BLOCK]], i64 0, i32 4
+; CHECK-NEXT: store ptr @__block_d_tmp, ptr [[BLOCK_D]], align 8
+; CHECK-NEXT: [[FOO2:%.*]] = tail call ptr @llvm.objc.retain(ptr [[CALL]]) #[[ATTR0]]
+; CHECK-NEXT: store ptr [[FOO2]], ptr [[FOO]], align 8
+; CHECK-NEXT: [[FOO5:%.*]] = call ptr @llvm.objc.retainBlock(ptr [[BLOCK]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use(ptr [[FOO5]]), !clang.arc.no_objc_arc_exceptions [[META0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[FOO5]]) #[[ATTR0]]
+; CHECK-NEXT: [[STRONGDESTROY:%.*]] = load ptr, ptr [[FOO]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[STRONGDESTROY]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: [[FOO10:%.*]] = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr [[BLOCK9]], i64 0, i32 5
+; CHECK-NEXT: [[BLOCK_ISA11:%.*]] = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr [[BLOCK9]], i64 0, i32 0
+; CHECK-NEXT: store ptr @_NSConcreteStackBlock, ptr [[BLOCK_ISA11]], align 8
+; CHECK-NEXT: [[BLOCK_FLAGS12:%.*]] = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr [[BLOCK9]], i64 0, i32 1
+; CHECK-NEXT: store i32 1107296256, ptr [[BLOCK_FLAGS12]], align 8
+; CHECK-NEXT: [[BLOCK_RESERVED13:%.*]] = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr [[BLOCK9]], i64 0, i32 2
+; CHECK-NEXT: store i32 0, ptr [[BLOCK_RESERVED13]], align 4
+; CHECK-NEXT: [[BLOCK_INVOKE14:%.*]] = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr [[BLOCK9]], i64 0, i32 3
+; CHECK-NEXT: store ptr @__crasher_block_invoke1, ptr [[BLOCK_INVOKE14]], align 8
+; CHECK-NEXT: [[BLOCK_D15:%.*]] = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr }>, ptr [[BLOCK9]], i64 0, i32 4
+; CHECK-NEXT: store ptr @__block_d_tmp5, ptr [[BLOCK_D15]], align 8
+; CHECK-NEXT: store ptr [[CALL]], ptr [[FOO10]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[CALL]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: [[FOO21:%.*]] = call ptr @llvm.objc.retainBlock(ptr [[BLOCK9]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use(ptr [[FOO21]]), !clang.arc.no_objc_arc_exceptions [[META0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[FOO21]]) #[[ATTR0]]
+; CHECK-NEXT: [[STRONGDESTROY25:%.*]] = load ptr, ptr [[FOO10]], align 8
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[STRONGDESTROY25]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[CALL]]) #[[ATTR0]]
+; CHECK-NEXT: ret void
+;
entry:
%block = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8
%block9 = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8
@@ -807,6 +1353,6 @@ entry:
}
-; CHECK: attributes [[NUW]] = { nounwind }
-; CHECK: attributes #1 = { nocallback nofree nounwind willreturn memory(argmem: write) }
-; CHECK: attributes #2 = { nonlazybind }
+;.
+; CHECK: [[META0]] = !{}
+;.
diff --git a/llvm/test/Transforms/ObjCARC/split-backedge.ll b/llvm/test/Transforms/ObjCARC/split-backedge.ll
index ed855541cfb54..c28071f5908f5 100644
--- a/llvm/test/Transforms/ObjCARC/split-backedge.ll
+++ b/llvm/test/Transforms/ObjCARC/split-backedge.ll
@@ -1,28 +1,46 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -S -passes=objc-arc < %s | FileCheck %s
; Handle a retain+release pair entirely contained within a split loop backedge.
; rdar://11256239
-; CHECK-LABEL: define void @test0(
-; CHECK: call ptr @llvm.objc.retain(ptr %call) [[NUW:#[0-9]+]]
-; CHECK: call ptr @llvm.objc.retain(ptr %call) [[NUW]]
-; CHECK: call ptr @llvm.objc.retain(ptr %cond) [[NUW]]
-; CHECK: call void @llvm.objc.release(ptr %call) [[NUW]]
-; CHECK: call void @llvm.objc.release(ptr %call) [[NUW]]
-; CHECK: call void @llvm.objc.release(ptr %cond) [[NUW]]
define void @test0() personality ptr @__objc_personality_v0 {
+; CHECK-LABEL: define void @test0() personality ptr @__objc_personality_v0 {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br label %[[WHILE_BODY:.*]]
+; CHECK: [[WHILE_BODY]]:
+; CHECK-NEXT: [[CALL:%.*]] = invoke ptr @returner()
+; CHECK-NEXT: to label %[[INVOKE_CONT:.*]] unwind label %[[LPAD:.*]], !clang.arc.no_objc_arc_exceptions [[META0:![0-9]+]]
+; CHECK: [[INVOKE_CONT]]:
+; CHECK-NEXT: [[T0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[CALL]]) #[[ATTR0:[0-9]+]]
+; CHECK-NEXT: [[T1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[CALL]]) #[[ATTR0]]
+; CHECK-NEXT: [[CALL_I1:%.*]] = invoke ptr @returner()
+; CHECK-NEXT: to label %[[INVOKE_CONT1:.*]] unwind label %[[LPAD]]
+; CHECK: [[INVOKE_CONT1]]:
+; CHECK-NEXT: [[COND:%.*]] = select i1 undef, ptr null, ptr [[CALL]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[COND]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[CALL]]) #[[ATTR0]]
+; CHECK-NEXT: call void @llvm.objc.release(ptr [[CALL]]) #[[ATTR0]]
+; CHECK-NEXT: call void @use_pointer(ptr [[COND]])
+; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[COND]]) #[[ATTR0]]
+; CHECK-NEXT: br label %[[WHILE_BODY]]
+; CHECK: [[LPAD]]:
+; CHECK-NEXT: [[T4:%.*]] = landingpad { ptr, i32 }
+; CHECK-NEXT: catch ptr null
+; CHECK-NEXT: ret void
+;
entry:
br label %while.body
while.body: ; preds = %while.cond
%call = invoke ptr @returner()
- to label %invoke.cont unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
+ to label %invoke.cont unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
invoke.cont: ; preds = %while.body
%t0 = call ptr @llvm.objc.retain(ptr %call) nounwind
%t1 = call ptr @llvm.objc.retain(ptr %call) nounwind
%call.i1 = invoke ptr @returner()
- to label %invoke.cont1 unwind label %lpad
+ to label %invoke.cont1 unwind label %lpad
invoke.cont1: ; preds = %invoke.cont
%cond = select i1 undef, ptr null, ptr %call
@@ -35,7 +53,7 @@ invoke.cont1: ; preds = %invoke.cont
lpad: ; preds = %invoke.cont, %while.body
%t4 = landingpad { ptr, i32 }
- catch ptr null
+ catch ptr null
ret void
}
@@ -47,4 +65,6 @@ declare void @use_pointer(ptr)
!0 = !{}
-; CHECK: attributes [[NUW]] = { nounwind }
+;.
+; CHECK: [[META0]] = !{}
+;.
More information about the llvm-commits
mailing list