The ARC language-specific optimizer. Credit to Dan Gohman.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@133108 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
John McCall 2011-06-15 23:37:01 +00:00
parent 5f36bb1759
commit 9fbd318d36
28 changed files with 6947 additions and 0 deletions

View File

@ -86,6 +86,13 @@ namespace llvm {
//
ImmutablePass *createTypeBasedAliasAnalysisPass();
//===--------------------------------------------------------------------===//
//
// createObjCARCAliasAnalysisPass - This pass implements ObjC-ARC-based
// alias analysis.
//
ImmutablePass *createObjCARCAliasAnalysisPass();
//===--------------------------------------------------------------------===//
//
// createProfileLoaderPass - This pass loads information from a profile dump

View File

@ -160,6 +160,10 @@ void initializeModuleDebugInfoPrinterPass(PassRegistry&);
void initializeNoAAPass(PassRegistry&);
void initializeNoProfileInfoPass(PassRegistry&);
void initializeNoPathProfileInfoPass(PassRegistry&);
void initializeObjCARCAliasAnalysisPass(PassRegistry&);
void initializeObjCARCExpandPass(PassRegistry&);
void initializeObjCARCContractPass(PassRegistry&);
void initializeObjCARCOptPass(PassRegistry&);
void initializeOptimalEdgeProfilerPass(PassRegistry&);
void initializeOptimizePHIsPass(PassRegistry&);
void initializePEIPass(PassRegistry&);

View File

@ -97,6 +97,10 @@ namespace {
(void) llvm::createLowerSwitchPass();
(void) llvm::createNoAAPass();
(void) llvm::createNoProfileInfoPass();
(void) llvm::createObjCARCAliasAnalysisPass();
(void) llvm::createObjCARCExpandPass();
(void) llvm::createObjCARCContractPass();
(void) llvm::createObjCARCOptPass();
(void) llvm::createProfileEstimatorPass();
(void) llvm::createProfileVerifierPass();
(void) llvm::createPathProfileVerifierPass();

View File

@ -188,6 +188,7 @@ public:
MPM.add(createArgumentPromotionPass()); // Scalarize uninlined fn args
// Start of function pass.
MPM.add(createObjCARCExpandPass()); // Canonicalize ObjC ARC code.
// Break up aggregate allocas, using SSAUpdater.
MPM.add(createScalarReplAggregatesPass(-1, false));
MPM.add(createEarlyCSEPass()); // Catch trivial redundancies
@ -223,6 +224,7 @@ public:
MPM.add(createJumpThreadingPass()); // Thread jumps
MPM.add(createCorrelatedValuePropagationPass());
MPM.add(createDeadStoreEliminationPass()); // Delete dead stores
MPM.add(createObjCARCOptPass()); // Objective-C ARC optimizations.
MPM.add(createAggressiveDCEPass()); // Delete dead instructions
MPM.add(createCFGSimplificationPass()); // Merge & remove BBs
MPM.add(createInstructionCombiningPass()); // Clean up after everything.

View File

@ -336,6 +336,24 @@ Pass *createLowerAtomicPass();
//
Pass *createCorrelatedValuePropagationPass();
//===----------------------------------------------------------------------===//
//
// ObjCARCExpand - ObjC ARC preliminary simplifications.
//
Pass *createObjCARCExpandPass();
//===----------------------------------------------------------------------===//
//
// ObjCARCContract - Late ObjC ARC cleanups.
//
Pass *createObjCARCContractPass();
//===----------------------------------------------------------------------===//
//
// ObjCARCOpt - ObjC ARC optimization.
//
Pass *createObjCARCOptPass();
//===----------------------------------------------------------------------===//
//
// InstructionSimplifier - Remove redundant instructions.

View File

@ -303,6 +303,10 @@ bool LLVMTargetMachine::addCommonCodeGenPasses(PassManagerBase &PM,
if (!DisableVerify)
PM.add(createVerifierPass());
// Simplify ObjC ARC code. This is done late because it makes re-optimization
// difficult.
PM.add(createObjCARCContractPass());
// Run loop strength reduction before anything else.
if (OptLevel != CodeGenOpt::None && !DisableLSR) {
PM.add(createLoopStrengthReducePass(getTargetLowering()));

View File

@ -20,6 +20,7 @@ add_llvm_library(LLVMScalarOpts
LoopUnswitch.cpp
LowerAtomic.cpp
MemCpyOptimizer.cpp
ObjCARC.cpp
Reassociate.cpp
Reg2Mem.cpp
SCCP.cpp

File diff suppressed because it is too large Load Diff

View File

@ -49,6 +49,10 @@ void llvm::initializeScalarOpts(PassRegistry &Registry) {
initializeLoopIdiomRecognizePass(Registry);
initializeLowerAtomicPass(Registry);
initializeMemCpyOptPass(Registry);
initializeObjCARCAliasAnalysisPass(Registry);
initializeObjCARCExpandPass(Registry);
initializeObjCARCContractPass(Registry);
initializeObjCARCOptPass(Registry);
initializeReassociatePass(Registry);
initializeRegToMemPass(Registry);
initializeSCCPPass(Registry);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
; RUN: opt -S -objc-arc < %s | FileCheck %s
; rdar://9503416
; Detect loop boundaries and don't move retains and releases
; across them.
declare void @use_pointer(i8*)
declare i8* @objc_retain(i8*)
declare void @objc_release(i8*)
; CHECK: define void @test0(
; CHECK: call i8* @objc_retain(
; CHECK: for.body:
; CHECK-NOT: @objc
; CHECK: for.end:
; CHECK: call void @objc_release(
; CHECK: }
define void @test0(i8* %digits) {
entry:
%tmp1 = call i8* @objc_retain(i8* %digits) nounwind
call void @use_pointer(i8* %tmp1)
br label %for.body
for.body: ; preds = %for.body, %entry
%upcDigitIndex.01 = phi i64 [ 2, %entry ], [ %inc, %for.body ]
call void @use_pointer(i8* %tmp1)
%inc = add i64 %upcDigitIndex.01, 1
%cmp = icmp ult i64 %inc, 12
br i1 %cmp, label %for.body, label %for.end
for.end: ; preds = %for.body
call void @objc_release(i8* %tmp1) nounwind, !clang.imprecise_release !0
ret void
}
; CHECK: define void @test1(
; CHECK: call i8* @objc_retain(
; CHECK: for.body:
; CHECK-NOT: @objc
; CHECK: for.end:
; CHECK: void @objc_release(
; CHECK: }
define void @test1(i8* %digits) {
entry:
%tmp1 = call i8* @objc_retain(i8* %digits) nounwind
br label %for.body
for.body: ; preds = %for.body, %entry
%upcDigitIndex.01 = phi i64 [ 2, %entry ], [ %inc, %for.body ]
call void @use_pointer(i8* %tmp1)
call void @use_pointer(i8* %tmp1)
%inc = add i64 %upcDigitIndex.01, 1
%cmp = icmp ult i64 %inc, 12
br i1 %cmp, label %for.body, label %for.end
for.end: ; preds = %for.body
call void @objc_release(i8* %tmp1) nounwind, !clang.imprecise_release !0
ret void
}
; CHECK: define void @test2(
; CHECK: call i8* @objc_retain(
; CHECK: for.body:
; CHECK-NOT: @objc
; CHECK: for.end:
; CHECK: void @objc_release(
; CHECK: }
define void @test2(i8* %digits) {
entry:
%tmp1 = call i8* @objc_retain(i8* %digits) nounwind
br label %for.body
for.body: ; preds = %for.body, %entry
%upcDigitIndex.01 = phi i64 [ 2, %entry ], [ %inc, %for.body ]
call void @use_pointer(i8* %tmp1)
%inc = add i64 %upcDigitIndex.01, 1
%cmp = icmp ult i64 %inc, 12
br i1 %cmp, label %for.body, label %for.end
for.end: ; preds = %for.body
call void @use_pointer(i8* %tmp1)
call void @objc_release(i8* %tmp1) nounwind, !clang.imprecise_release !0
ret void
}
!0 = metadata !{}

View File

@ -0,0 +1,23 @@
; RUN: opt -S -objc-arc-contract < %s | FileCheck %s
; CHECK: %call = tail call i32* @qux()
; CHECK-NEXT: %tcall = bitcast i32* %call to i8*
; CHECK-NEXT: call void asm sideeffect "mov\09r7, r7\09\09@ marker for objc_retainAutoreleaseReturnValue", ""()
; CHECK-NEXT: %0 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %tcall) nounwind
define void @foo() {
entry:
%call = tail call i32* @qux()
%tcall = bitcast i32* %call to i8*
%0 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %tcall) nounwind
tail call void @bar(i8* %0)
ret void
}
declare i32* @qux()
declare i8* @objc_retainAutoreleasedReturnValue(i8*)
declare void @bar(i8*)
!clang.arc.retainAutoreleasedReturnValueMarker = !{!0}
!0 = metadata !{metadata !"mov\09r7, r7\09\09@ marker for objc_retainAutoreleaseReturnValue"}

View File

@ -0,0 +1,31 @@
; RUN: opt -objc-arc-contract -S < %s | FileCheck %s
; CHECK: call void @objc_storeStrong(i8**
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-apple-darwin11.0.0"
%0 = type opaque
%1 = type opaque
@"OBJC_IVAR_$_Controller.preferencesController" = external global i64, section "__DATA, __objc_const", align 8
declare i8* @objc_retain(i8*)
declare void @objc_release(i8*)
define hidden void @y(%0* nocapture %self, %1* %preferencesController) nounwind {
entry:
%ivar = load i64* @"OBJC_IVAR_$_Controller.preferencesController", align 8
%tmp = bitcast %0* %self to i8*
%add.ptr = getelementptr inbounds i8* %tmp, i64 %ivar
%tmp1 = bitcast i8* %add.ptr to %1**
%tmp2 = load %1** %tmp1, align 8
%tmp3 = bitcast %1* %preferencesController to i8*
%tmp4 = tail call i8* @objc_retain(i8* %tmp3) nounwind
%tmp5 = bitcast %1* %tmp2 to i8*
tail call void @objc_release(i8* %tmp5) nounwind
%tmp6 = bitcast i8* %tmp4 to %1*
store %1* %tmp6, %1** %tmp1, align 8
ret void
}

View File

@ -0,0 +1,59 @@
; RUN: opt -objc-arc-contract -S < %s | FileCheck %s
target datalayout = "e-p:64:64:64"
declare i8* @objc_retain(i8*)
declare void @objc_release(i8*)
@x = external global i8*
; CHECK: define void @test0(
; CHECK: entry:
; CHECK-NEXT: call void @objc_storeStrong(i8** @x, i8* %p) nounwind
; CHECK-NEXT: ret void
define void @test0(i8* %p) {
entry:
%0 = tail call i8* @objc_retain(i8* %p) nounwind
%tmp = load i8** @x, align 8
store i8* %0, i8** @x, align 8
tail call void @objc_release(i8* %tmp) nounwind
ret void
}
; Don't do this if the load is volatile.
; CHECK: define void @test1(i8* %p) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %0 = tail call i8* @objc_retain(i8* %p) nounwind
; CHECK-NEXT: %tmp = volatile load i8** @x, align 8
; CHECK-NEXT: store i8* %0, i8** @x, align 8
; CHECK-NEXT: tail call void @objc_release(i8* %tmp) nounwind
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test1(i8* %p) {
entry:
%0 = tail call i8* @objc_retain(i8* %p) nounwind
%tmp = volatile load i8** @x, align 8
store i8* %0, i8** @x, align 8
tail call void @objc_release(i8* %tmp) nounwind
ret void
}
; Don't do this if the store is volatile.
; CHECK: define void @test2(i8* %p) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %0 = tail call i8* @objc_retain(i8* %p) nounwind
; CHECK-NEXT: %tmp = load i8** @x, align 8
; CHECK-NEXT: volatile store i8* %0, i8** @x, align 8
; CHECK-NEXT: tail call void @objc_release(i8* %tmp) nounwind
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test2(i8* %p) {
entry:
%0 = tail call i8* @objc_retain(i8* %p) nounwind
%tmp = load i8** @x, align 8
volatile store i8* %0, i8** @x, align 8
tail call void @objc_release(i8* %tmp) nounwind
ret void
}

View File

@ -0,0 +1,63 @@
; RUN: opt -objc-arc-contract -S < %s | FileCheck %s
; rdar://9511608
%0 = type opaque
%1 = type opaque
%2 = type { i64, i64 }
%3 = type { i8*, i8* }
%4 = type opaque
declare %0* @"\01-[NSAttributedString(Terminal) pathAtIndex:effectiveRange:]"(%1*, i8* nocapture, i64, %2*) optsize
declare i8* @objc_retainAutoreleasedReturnValue(i8*)
declare i8* @objc_msgSend_fixup(i8*, %3*, ...)
declare void @objc_release(i8*)
declare %2 @NSUnionRange(i64, i64, i64, i64) optsize
declare i8* @objc_autoreleaseReturnValue(i8*)
declare i8* @objc_autorelease(i8*)
declare i8* @objc_msgSend() nonlazybind
; Don't get in trouble on bugpointed code.
; CHECK: define void @test0(
define void @test0() {
bb:
%tmp = bitcast %4* undef to i8*
%tmp1 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %tmp) nounwind
br label %bb3
bb3: ; preds = %bb2
br i1 undef, label %bb6, label %bb4
bb4: ; preds = %bb3
switch i64 undef, label %bb5 [
i64 9223372036854775807, label %bb6
i64 0, label %bb6
]
bb5: ; preds = %bb4
br label %bb6
bb6: ; preds = %bb5, %bb4, %bb4, %bb3
%tmp7 = phi %4* [ undef, %bb5 ], [ undef, %bb4 ], [ undef, %bb3 ], [ undef, %bb4 ]
unreachable
}
; When rewriting operands for a phi which has multiple operands
; for the same block, use the exactly same value in each block.
; CHECK: define void @test1(
; CHECK: %0 = bitcast i8* %tmp3 to %0*
; CHECK: br i1 undef, label %bb7, label %bb7
; CHECK: bb7:
; CHECK: %tmp8 = phi %0* [ %0, %bb ], [ %0, %bb ]
define void @test1() {
bb:
%tmp = tail call %0* bitcast (i8* ()* @objc_msgSend to %0* ()*)()
%tmp2 = bitcast %0* %tmp to i8*
%tmp3 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %tmp2) nounwind
br i1 undef, label %bb7, label %bb7
bb7: ; preds = %bb6, %bb6, %bb5
%tmp8 = phi %0* [ %tmp, %bb ], [ %tmp, %bb ]
unreachable
}

View File

@ -0,0 +1,145 @@
; RUN: opt -objc-arc-contract -S < %s | FileCheck %s
target datalayout = "e-p:64:64:64"
declare i8* @objc_retain(i8*)
declare void @objc_release(i8*)
declare i8* @objc_autorelease(i8*)
declare i8* @objc_autoreleaseReturnValue(i8*)
declare i8* @objc_retainAutoreleasedReturnValue(i8*)
declare void @use_pointer(i8*)
declare i8* @returner()
; CHECK: define void @test0
; CHECK: call void @use_pointer(i8* %0)
; CHECK: }
define void @test0(i8* %x) nounwind {
entry:
%0 = call i8* @objc_retain(i8* %x) nounwind
call void @use_pointer(i8* %x)
ret void
}
; CHECK: define void @test1
; CHECK: call void @use_pointer(i8* %0)
; CHECK: }
define void @test1(i8* %x) nounwind {
entry:
%0 = call i8* @objc_autorelease(i8* %x) nounwind
call void @use_pointer(i8* %x)
ret void
}
; Merge objc_retain and objc_autorelease into objc_retainAutorelease.
; CHECK: define void @test2(
; CHECK: tail call i8* @objc_retainAutorelease(i8* %x) nounwind
; CHECK: }
define void @test2(i8* %x) nounwind {
entry:
%0 = tail call i8* @objc_retain(i8* %x) nounwind
tail call i8* @objc_autorelease(i8* %0) nounwind
call void @use_pointer(i8* %x)
ret void
}
; Same as test2 but the value is returned. Do an RV optimization.
; CHECK: define i8* @test2b(
; CHECK: tail call i8* @objc_retainAutoreleaseReturnValue(i8* %x) nounwind
; CHECK: }
define i8* @test2b(i8* %x) nounwind {
entry:
%0 = tail call i8* @objc_retain(i8* %x) nounwind
tail call i8* @objc_autoreleaseReturnValue(i8* %0) nounwind
ret i8* %x
}
; Merge a retain,autorelease pair around a call.
; CHECK: define void @test3(
; CHECK: tail call i8* @objc_retainAutorelease(i8* %x) nounwind
; CHECK: @use_pointer(i8* %0)
; CHECK: }
define void @test3(i8* %x, i64 %n) {
entry:
tail call i8* @objc_retain(i8* %x) nounwind
call void @use_pointer(i8* %x)
tail call i8* @objc_autorelease(i8* %x) nounwind
ret void
}
; Trivial retain,autorelease pair with intervening call, but it's post-dominated
; by another release. The retain and autorelease can be merged.
; CHECK: define void @test4(
; CHECK-NEXT: entry:
; CHECK-NEXT: @objc_retainAutorelease(i8* %x) nounwind
; CHECK-NEXT: @use_pointer
; CHECK-NEXT: @objc_release
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test4(i8* %x, i64 %n) {
entry:
tail call i8* @objc_retain(i8* %x) nounwind
call void @use_pointer(i8* %x)
tail call i8* @objc_autorelease(i8* %x) nounwind
tail call void @objc_release(i8* %x) nounwind
ret void
}
; Don't merge retain and autorelease if they're not control-equivalent.
; CHECK: define void @test5(
; CHECK: tail call i8* @objc_retain(i8* %p) nounwind
; CHECK: true:
; CHECK: tail call i8* @objc_autorelease(i8* %0) nounwind
; CHECK: }
define void @test5(i8* %p, i1 %a) {
entry:
tail call i8* @objc_retain(i8* %p) nounwind
br i1 %a, label %true, label %false
true:
tail call i8* @objc_autorelease(i8* %p) nounwind
call void @use_pointer(i8* %p)
ret void
false:
ret void
}
; Don't eliminate objc_retainAutoreleasedReturnValue by merging it into
; an objc_autorelease.
; TODO? Merge objc_retainAutoreleasedReturnValue and objc_autorelease into
; objc_retainAutoreleasedReturnValueAutorelease and merge
; objc_retainAutoreleasedReturnValue and objc_autoreleaseReturnValue
; into objc_retainAutoreleasedReturnValueAutoreleaseReturnValue?
; Those entrypoints don't exist yet though.
; CHECK: define i8* @test6(
; CHECK: call i8* @objc_retainAutoreleasedReturnValue(i8* %p) nounwind
; CHECK: %t = tail call i8* @objc_autoreleaseReturnValue(i8* %1) nounwind
; CHECK: }
define i8* @test6() {
%p = call i8* @returner()
tail call i8* @objc_retainAutoreleasedReturnValue(i8* %p) nounwind
%t = tail call i8* @objc_autoreleaseReturnValue(i8* %p) nounwind
call void @use_pointer(i8* %t)
ret i8* %t
}
; Don't spoil the RV optimization.
; CHECK: define i8* @test7(i8* %p)
; CHECK: tail call i8* @objc_retain(i8* %p)
; CHECK: call void @use_pointer(i8* %1)
; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %1)
; CHECK: ret i8* %2
define i8* @test7(i8* %p) {
%1 = tail call i8* @objc_retain(i8* %p)
call void @use_pointer(i8* %p)
%2 = tail call i8* @objc_autoreleaseReturnValue(i8* %p)
ret i8* %p
}

View File

@ -0,0 +1,3 @@
load_lib llvm.exp
RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,c,cpp}]]

View File

@ -0,0 +1,28 @@
; RUN: opt -objc-arc-expand -S < %s | FileCheck %s
target datalayout = "e-p:64:64:64"
declare i8* @objc_retain(i8*)
declare i8* @objc_autorelease(i8*)
declare void @use_pointer(i8*)
; CHECK: define void @test0
; CHECK: call void @use_pointer(i8* %x)
; CHECK: }
define void @test0(i8* %x) nounwind {
entry:
%0 = call i8* @objc_retain(i8* %x) nounwind
call void @use_pointer(i8* %0)
ret void
}
; CHECK: define void @test1
; CHECK: call void @use_pointer(i8* %x)
; CHECK: }
define void @test1(i8* %x) nounwind {
entry:
%0 = call i8* @objc_autorelease(i8* %x) nounwind
call void @use_pointer(i8* %x)
ret void
}

View File

@ -0,0 +1,21 @@
; RUN: opt -S -basicaa -objc-arc -gvn < %s | FileCheck %s
@x = common global i8* null, align 8
declare i8* @objc_retain(i8*)
; GVN should be able to eliminate this redundant load, with ARC-specific
; alias analysis.
; CHECK: @foo
; CHECK-NEXT: entry:
; CHECK-NEXT: %s = load i8** @x
; CHECK-NOT: load
; CHECK: ret i8* %s
define i8* @foo(i32 %n) nounwind {
entry:
%s = load i8** @x
%0 = tail call i8* @objc_retain(i8* %s) nounwind
%t = load i8** @x
ret i8* %s
}

View File

@ -0,0 +1,221 @@
; RUN: opt -S -objc-arc-contract < %s | FileCheck %s
; The optimizer should be able to move the autorelease past a control triangle
; and various scary looking things and fold it into an objc_retainAutorelease.
; CHECK: bb57:
; CHECK: tail call i8* @objc_retainAutorelease(i8* %tmp71x) nounwind
; CHECK: bb99:
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-apple-darwin11.0.0"
%0 = type { i8* (i8*, %1*, ...)*, i8* }
%1 = type { i8*, i8* }
%2 = type { %2*, %2*, %3*, i8* (i8*, i8*)**, %4* }
%3 = type opaque
%4 = type { i32, i32, i32, i8*, i8*, %5*, %7*, %10*, i8*, %9* }
%5 = type { i32, i32, [0 x %6] }
%6 = type { i8*, i8*, i8* }
%7 = type { i64, [0 x %8*] }
%8 = type { i8*, i8*, %7*, %5*, %5*, %5*, %5*, %9*, i32, i32 }
%9 = type { i32, i32, [0 x %1] }
%10 = type { i32, i32, [0 x %11] }
%11 = type { i64*, i8*, i8*, i32, i32 }
%12 = type { i32*, i32, i8*, i64 }
%13 = type opaque
%14 = type opaque
%15 = type opaque
%16 = type opaque
%17 = type opaque
%18 = type opaque
%19 = type opaque
%20 = type opaque
%21 = type opaque
%22 = type opaque
%23 = type opaque
%24 = type opaque
%25 = type opaque
@"\01l_objc_msgSend_fixup_alloc" = external hidden global %0, section "__DATA, __objc_msgrefs, coalesced", align 16
@"\01L_OBJC_SELECTOR_REFERENCES_8" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_3725" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_CLASSLIST_REFERENCES_$_40" = external hidden global %2*, section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8
@"\01L_OBJC_SELECTOR_REFERENCES_4227" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_4631" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_CLASSLIST_REFERENCES_$_70" = external hidden global %2*, section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8
@"\01L_OBJC_SELECTOR_REFERENCES_148" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_159" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_188" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_328" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01l_objc_msgSend_fixup_objectAtIndex_" = external hidden global %0, section "__DATA, __objc_msgrefs, coalesced", align 16
@_unnamed_cfstring_386 = external hidden constant %12, section "__DATA,__cfstring"
@"\01l_objc_msgSend_fixup_count" = external hidden global %0, section "__DATA, __objc_msgrefs, coalesced", align 16
@"\01L_OBJC_SELECTOR_REFERENCES_389" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_391" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_393" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@NSPrintHeaderAndFooter = external constant %13*
@"\01L_OBJC_SELECTOR_REFERENCES_395" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_CLASSLIST_REFERENCES_$_396" = external hidden global %2*, section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8
@"\01L_OBJC_SELECTOR_REFERENCES_398" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_400" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_402" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_404" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_406" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_408" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_CLASSLIST_REFERENCES_$_409" = external hidden global %2*, section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8
@"\01L_OBJC_SELECTOR_REFERENCES_411" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_413" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_415" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
declare i8* @objc_msgSend(i8*, i8*, ...)
declare i8* @objc_retain(i8*)
declare void @objc_release(i8*)
declare i8* @objc_autorelease(i8*)
declare i8* @objc_explicit_autorelease(i8*)
define hidden %14* @foo(%15* %arg, %16* %arg2) {
bb:
%tmp = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_3725", align 8
%tmp4 = bitcast %15* %arg to i8*
%tmp5 = tail call %18* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %18* (i8*, i8*)*)(i8* %tmp4, i8* %tmp)
%tmp6 = bitcast %18* %tmp5 to i8*
%tmp7 = tail call i8* @objc_retain(i8* %tmp6) nounwind
%tmp8 = load %2** @"\01L_OBJC_CLASSLIST_REFERENCES_$_40", align 8
%tmp9 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_4227", align 8
%tmp10 = bitcast %2* %tmp8 to i8*
%tmp11 = tail call %19* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %19* (i8*, i8*)*)(i8* %tmp10, i8* %tmp9)
%tmp12 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_4631", align 8
%tmp13 = bitcast %19* %tmp11 to i8*
%tmp14 = tail call signext i8 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8 (i8*, i8*, %13*)*)(i8* %tmp13, i8* %tmp12, %13* bitcast (%12* @_unnamed_cfstring_386 to %13*))
%tmp15 = bitcast %16* %arg2 to i8*
%tmp16 = load i8** bitcast (%0* @"\01l_objc_msgSend_fixup_count" to i8**), align 16
%tmp17 = bitcast i8* %tmp16 to i64 (i8*, %1*)*
%tmp18 = tail call i64 %tmp17(i8* %tmp15, %1* bitcast (%0* @"\01l_objc_msgSend_fixup_count" to %1*))
%tmp19 = icmp eq i64 %tmp18, 0
br i1 %tmp19, label %bb22, label %bb20
bb20: ; preds = %bb
%tmp21 = icmp eq i8 %tmp14, 0
br label %bb25
bb22: ; preds = %bb
%tmp23 = bitcast i8* %tmp7 to %18*
%tmp24 = icmp eq i8 %tmp14, 0
br i1 %tmp24, label %bb46, label %bb25
bb25: ; preds = %bb22, %bb20
%tmp26 = phi i1 [ %tmp21, %bb20 ], [ false, %bb22 ]
%tmp27 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_188", align 8
%tmp28 = tail call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* %tmp7, i8* %tmp27)
%tmp29 = tail call i8* @objc_explicit_autorelease(i8* %tmp28) nounwind
%tmp30 = bitcast i8* %tmp29 to %18*
tail call void @objc_release(i8* %tmp7) nounwind
%tmp31 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_389", align 8
%tmp32 = tail call %20* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %20* (i8*, i8*)*)(i8* %tmp29, i8* %tmp31)
%tmp33 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_391", align 8
%tmp34 = bitcast %20* %tmp32 to i8*
tail call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, %16*)*)(i8* %tmp34, i8* %tmp33, %16* %arg2)
br i1 %tmp26, label %bb46, label %bb35
bb35: ; preds = %bb25
%tmp36 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_389", align 8
%tmp37 = tail call %20* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %20* (i8*, i8*)*)(i8* %tmp29, i8* %tmp36)
%tmp38 = load %2** @"\01L_OBJC_CLASSLIST_REFERENCES_$_70", align 8
%tmp39 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_393", align 8
%tmp40 = bitcast %2* %tmp38 to i8*
%tmp41 = tail call %21* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %21* (i8*, i8*, i8)*)(i8* %tmp40, i8* %tmp39, i8 signext 1)
%tmp42 = bitcast %21* %tmp41 to i8*
%tmp43 = load %13** @NSPrintHeaderAndFooter, align 8
%tmp44 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_159", align 8
%tmp45 = bitcast %20* %tmp37 to i8*
tail call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*, %13*)*)(i8* %tmp45, i8* %tmp44, i8* %tmp42, %13* %tmp43)
br label %bb46
bb46: ; preds = %bb35, %bb25, %bb22
%tmp47 = phi %18* [ %tmp30, %bb35 ], [ %tmp30, %bb25 ], [ %tmp23, %bb22 ]
%tmp48 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_328", align 8
%tmp49 = tail call %22* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %22* (i8*, i8*)*)(i8* %tmp4, i8* %tmp48)
%tmp50 = bitcast %22* %tmp49 to i8*
%tmp51 = load i8** bitcast (%0* @"\01l_objc_msgSend_fixup_count" to i8**), align 16
%tmp52 = bitcast i8* %tmp51 to i64 (i8*, %1*)*
%tmp53 = tail call i64 %tmp52(i8* %tmp50, %1* bitcast (%0* @"\01l_objc_msgSend_fixup_count" to %1*))
%tmp54 = icmp eq i64 %tmp53, 0
br i1 %tmp54, label %bb55, label %bb57
bb55: ; preds = %bb46
%tmp56 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_395", align 8
tail call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*)*)(i8* %tmp4, i8* %tmp56)
br label %bb57
bb57: ; preds = %bb55, %bb46
%tmp58 = load %2** @"\01L_OBJC_CLASSLIST_REFERENCES_$_396", align 8
%tmp59 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_328", align 8
%tmp60 = tail call %22* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %22* (i8*, i8*)*)(i8* %tmp4, i8* %tmp59)
%tmp61 = bitcast %22* %tmp60 to i8*
%tmp62 = load i8** bitcast (%0* @"\01l_objc_msgSend_fixup_objectAtIndex_" to i8**), align 16
%tmp63 = bitcast i8* %tmp62 to i8* (i8*, %1*, i64)*
%tmp64 = tail call i8* %tmp63(i8* %tmp61, %1* bitcast (%0* @"\01l_objc_msgSend_fixup_objectAtIndex_" to %1*), i64 0)
%tmp65 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_398", align 8
%tmp66 = tail call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* %tmp64, i8* %tmp65)
%tmp67 = bitcast i8* %tmp66 to %23*
%tmp68 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_400", align 8
%tmp69 = bitcast %2* %tmp58 to i8*
%tmp70 = tail call %14* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %14* (i8*, i8*, %23*, %18*)*)(i8* %tmp69, i8* %tmp68, %23* %tmp67, %18* %tmp47)
%tmp71 = bitcast %14* %tmp70 to i8*
; hack to prevent the optimize from using objc_retainAutoreleasedReturnValue.
%tmp71x = getelementptr i8* %tmp71, i64 1
%tmp72 = tail call i8* @objc_retain(i8* %tmp71x) nounwind
%tmp73 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_402", align 8
tail call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8)*)(i8* %tmp72, i8* %tmp73, i8 signext 1)
%tmp74 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_404", align 8
tail call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8)*)(i8* %tmp72, i8* %tmp74, i8 signext 1)
%tmp75 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_328", align 8
%tmp76 = tail call %22* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %22* (i8*, i8*)*)(i8* %tmp4, i8* %tmp75)
%tmp77 = bitcast %22* %tmp76 to i8*
%tmp78 = load i8** bitcast (%0* @"\01l_objc_msgSend_fixup_objectAtIndex_" to i8**), align 16
%tmp79 = bitcast i8* %tmp78 to i8* (i8*, %1*, i64)*
%tmp80 = tail call i8* %tmp79(i8* %tmp77, %1* bitcast (%0* @"\01l_objc_msgSend_fixup_objectAtIndex_" to %1*), i64 0)
%tmp81 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_406", align 8
tail call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i64)*)(i8* %tmp80, i8* %tmp81, i64 9223372036854775807)
%tmp82 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_408", align 8
%tmp83 = tail call %24* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %24* (i8*, i8*)*)(i8* %tmp72, i8* %tmp82)
%tmp84 = bitcast %24* %tmp83 to i8*
%tmp85 = tail call i8* @objc_retain(i8* %tmp84) nounwind
%tmp86 = load %2** @"\01L_OBJC_CLASSLIST_REFERENCES_$_409", align 8
%tmp87 = bitcast %2* %tmp86 to i8*
%tmp88 = load i8** bitcast (%0* @"\01l_objc_msgSend_fixup_alloc" to i8**), align 16
%tmp89 = bitcast i8* %tmp88 to i8* (i8*, %1*)*
%tmp90 = tail call i8* %tmp89(i8* %tmp87, %1* bitcast (%0* @"\01l_objc_msgSend_fixup_alloc" to %1*))
%tmp91 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_8", align 8
%tmp92 = tail call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* %tmp90, i8* %tmp91)
%tmp93 = tail call i8* @objc_explicit_autorelease(i8* %tmp92) nounwind
%tmp94 = bitcast i8* %tmp93 to %25*
%tmp95 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_411", align 8
tail call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, %25*)*)(i8* %tmp85, i8* %tmp95, %25* %tmp94)
tail call void @objc_release(i8* %tmp93) nounwind
%tmp96 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_148", align 8
%tmp97 = tail call signext i8 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8 (i8*, i8*)*)(i8* %tmp4, i8* %tmp96)
%tmp98 = icmp eq i8 %tmp97, 0
br i1 %tmp98, label %bb99, label %bb104
bb99: ; preds = %bb57
%tmp100 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_413", align 8
%tmp101 = tail call i64 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i64 (i8*, i8*)*)(i8* %tmp85, i8* %tmp100)
%tmp102 = or i64 %tmp101, 12
%tmp103 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_415", align 8
tail call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i64)*)(i8* %tmp85, i8* %tmp103, i64 %tmp102)
br label %bb104
bb104: ; preds = %bb99, %bb57
%tmp105 = tail call i8* @objc_autorelease(i8* %tmp72) nounwind
%tmp106 = bitcast i8* %tmp105 to %14*
tail call void @objc_release(i8* %tmp85) nounwind
%tmp107 = bitcast %18* %tmp47 to i8*
tail call void @objc_release(i8* %tmp107) nounwind
ret %14* %tmp106
}

View File

@ -0,0 +1,108 @@
; RUN: opt -S -objc-arc < %s | FileCheck %s
; The optimizer should be able to move the autorelease past two phi nodes
; and fold it with the release in bb65.
; CHECK: bb65:
; CHECK: call i8* @objc_retainAutorelease
; CHECK: br label %bb76
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-apple-darwin11.0.0"
%0 = type opaque
%1 = type opaque
%2 = type opaque
%3 = type opaque
%4 = type opaque
%5 = type opaque
@"\01L_OBJC_SELECTOR_REFERENCES_11" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_421455" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_598" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_620" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_622" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_624" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_626" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
declare i8* @objc_msgSend(i8*, i8*, ...)
declare i8* @objc_retain(i8*)
declare void @objc_release(i8*)
declare i8* @objc_autorelease(i8*)
define hidden %0* @foo(%1* %arg, %3* %arg3) {
bb:
%tmp16 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_620", align 8
%tmp17 = bitcast %3* %arg3 to i8*
%tmp18 = call %4* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %4* (i8*, i8*)*)(i8* %tmp17, i8* %tmp16)
%tmp19 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_622", align 8
%tmp20 = bitcast %4* %tmp18 to i8*
%tmp21 = call %5* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %5* (i8*, i8*)*)(i8* %tmp20, i8* %tmp19)
%tmp22 = bitcast %5* %tmp21 to i8*
%tmp23 = call i8* @objc_retain(i8* %tmp22) nounwind
%tmp24 = bitcast i8* %tmp23 to %5*
%tmp26 = icmp eq i8* %tmp23, null
br i1 %tmp26, label %bb81, label %bb27
bb27: ; preds = %bb
%tmp29 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_11", align 8
%tmp30 = bitcast %1* %arg to i8*
%tmp31 = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* %tmp30, i8* %tmp29)
%tmp34 = call i8* @objc_retain(i8* %tmp31) nounwind
%tmp37 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_421455", align 8
%tmp39 = call %0* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %0* (i8*, i8*)*)(i8* %tmp34, i8* %tmp37)
%tmp40 = bitcast %0* %tmp39 to i8*
%tmp41 = call i8* @objc_retain(i8* %tmp40) nounwind
%tmp42 = bitcast i8* %tmp41 to %0*
%tmp44 = icmp eq i8* %tmp41, null
br i1 %tmp44, label %bb45, label %bb55
bb45: ; preds = %bb27
%tmp47 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_624", align 8
%tmp49 = call %0* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %0* (i8*, i8*)*)(i8* %tmp34, i8* %tmp47)
%tmp51 = bitcast %0* %tmp49 to i8*
%tmp52 = call i8* @objc_retain(i8* %tmp51) nounwind
call void @objc_release(i8* %tmp41) nounwind
br label %bb55
bb55: ; preds = %bb27, %bb45
%tmp13.0 = phi %0* [ %tmp42, %bb27 ], [ %tmp49, %bb45 ]
%tmp57 = icmp eq %0* %tmp13.0, null
br i1 %tmp57, label %bb76, label %bb58
bb58: ; preds = %bb55
%tmp60 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_598", align 8
%tmp61 = bitcast %0* %tmp13.0 to i8*
%tmp62 = call signext i8 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8 (i8*, i8*)*)(i8* %tmp61, i8* %tmp60)
%tmp64 = icmp eq i8 %tmp62, 0
br i1 %tmp64, label %bb76, label %bb65
bb65: ; preds = %bb58
%tmp68 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_626", align 8
%tmp69 = bitcast %0* %tmp13.0 to i8*
%tmp70 = call %0* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %0* (i8*, i8*, %5*)*)(i8* %tmp69, i8* %tmp68, %5* %tmp24)
%tmp72 = bitcast %0* %tmp70 to i8*
%tmp73 = call i8* @objc_retain(i8* %tmp72) nounwind
br label %bb76
bb76: ; preds = %bb58, %bb55, %bb65
%tmp10.0 = phi %0* [ %tmp70, %bb65 ], [ null, %bb58 ], [ null, %bb55 ]
%tmp78 = bitcast %0* %tmp13.0 to i8*
call void @objc_release(i8* %tmp78) nounwind
call void @objc_release(i8* %tmp34) nounwind
br label %bb81
bb81: ; preds = %bb, %bb76
%tmp10.1 = phi %0* [ %tmp10.0, %bb76 ], [ null, %bb ]
%tmp83 = bitcast %0* %tmp10.1 to i8*
%tmp84 = call i8* @objc_retain(i8* %tmp83) nounwind
%tmp88 = bitcast i8* %tmp87 to %0*
call void @objc_release(i8* %tmp23) nounwind
%tmp87 = call i8* @objc_autorelease(i8* %tmp84) nounwind
%tmp92 = bitcast %0* %tmp10.1 to i8*
call void @objc_release(i8* %tmp92) nounwind
ret %0* %tmp88
}

View File

@ -0,0 +1,48 @@
; RUN: opt -S -objc-arc < %s | FileCheck %s
declare void @use_pointer(i8*)
declare i8* @returner()
declare i8* @objc_retain(i8*)
declare i8* @objc_autoreleaseReturnValue(i8*)
declare i8* @objc_retainAutoreleasedReturnValue(i8*)
; Clean up residue left behind after inlining.
; CHECK: define void @test0(
; CHECK: entry:
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test0(i8* %call.i) {
entry:
%0 = tail call i8* @objc_retain(i8* %call.i) nounwind
%1 = tail call i8* @objc_autoreleaseReturnValue(i8* %0) nounwind
ret void
}
; Same as test0, but with slightly different use arrangements.
; CHECK: define void @test1(
; CHECK: entry:
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test1(i8* %call.i) {
entry:
%0 = tail call i8* @objc_retain(i8* %call.i) nounwind
%1 = tail call i8* @objc_autoreleaseReturnValue(i8* %call.i) nounwind
ret void
}
; Delete a retainRV+autoreleaseRV even if the pointer is used.
; CHECK: define void @test24(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @use_pointer(i8* %p)
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test24(i8* %p) {
entry:
call i8* @objc_autoreleaseReturnValue(i8* %p) nounwind
call i8* @objc_retainAutoreleasedReturnValue(i8* %p) nounwind
call void @use_pointer(i8* %p)
ret void
}

View File

@ -0,0 +1,25 @@
; RUN: opt -S -objc-arc -objc-arc-contract < %s | FileCheck %s
; Test that the optimizer can create an objc_retainAutoreleaseReturnValue
; declaration even if no objc_retain declaration exists.
; rdar://9401303
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
declare i8* @objc_unretainedObject(i8*)
declare i8* @objc_retainAutoreleasedReturnValue(i8*)
declare i8* @objc_autoreleaseReturnValue(i8*)
; CHECK: define i8* @foo(i8* %p) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %0 = tail call i8* @objc_retainAutoreleaseReturnValue(i8* %p) nounwind
; CHECK-NEXT: ret i8* %0
; CHECK-NEXT: }
define i8* @foo(i8* %p) {
entry:
%call = tail call i8* @objc_unretainedObject(i8* %p)
%0 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %call) nounwind
%1 = tail call i8* @objc_autoreleaseReturnValue(i8* %0) nounwind
ret i8* %1
}

View File

@ -0,0 +1,135 @@
; RUN: opt -S -basicaa -objc-arc < %s | FileCheck %s
declare i8* @objc_loadWeak(i8**)
declare i8* @objc_loadWeakRetained(i8**)
declare i8* @objc_storeWeak(i8**, i8*)
declare i8* @objc_initWeak(i8**, i8*)
declare void @use_pointer(i8*)
declare void @callee()
; Basic redundant @objc_loadWeak elimination.
; CHECK: define void @test0(i8** %p) {
; CHECK-NEXT: %y = call i8* @objc_loadWeak(i8** %p)
; CHECK-NEXT: call void @use_pointer(i8* %y)
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test0(i8** %p) {
%x = call i8* @objc_loadWeak(i8** %p)
%y = call i8* @objc_loadWeak(i8** %p)
call void @use_pointer(i8* %y)
ret void
}
; DCE the @objc_loadWeak.
; CHECK: define void @test1(i8** %p) {
; CHECK-NEXT: %y = call i8* @objc_loadWeakRetained(i8** %p)
; CHECK-NEXT: call void @use_pointer(i8* %y)
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test1(i8** %p) {
%x = call i8* @objc_loadWeak(i8** %p)
%y = call i8* @objc_loadWeakRetained(i8** %p)
call void @use_pointer(i8* %y)
ret void
}
; Basic redundant @objc_loadWeakRetained elimination.
; CHECK: define void @test2(i8** %p) {
; CHECK-NEXT: %x = call i8* @objc_loadWeak(i8** %p)
; CHECK-NEXT: store i8 3, i8* %x
; CHECK-NEXT: %1 = tail call i8* @objc_retain(i8* %x)
; CHECK-NEXT: call void @use_pointer(i8* %x)
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test2(i8** %p) {
%x = call i8* @objc_loadWeak(i8** %p)
store i8 3, i8* %x
%y = call i8* @objc_loadWeakRetained(i8** %p)
call void @use_pointer(i8* %y)
ret void
}
; Basic redundant @objc_loadWeakRetained elimination, this time
; with a readonly call instead of a store.
; CHECK: define void @test3(i8** %p) {
; CHECK-NEXT: %x = call i8* @objc_loadWeak(i8** %p)
; CHECK-NEXT: call void @use_pointer(i8* %x) readonly
; CHECK-NEXT: %1 = tail call i8* @objc_retain(i8* %x)
; CHECK-NEXT: call void @use_pointer(i8* %x)
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test3(i8** %p) {
%x = call i8* @objc_loadWeak(i8** %p)
call void @use_pointer(i8* %x) readonly
%y = call i8* @objc_loadWeakRetained(i8** %p)
call void @use_pointer(i8* %y)
ret void
}
; A regular call blocks redundant weak load elimination.
; CHECK: define void @test4(i8** %p) {
; CHECK-NEXT: %x = call i8* @objc_loadWeak(i8** %p)
; CHECK-NEXT: call void @use_pointer(i8* %x) readonly
; CHECK-NEXT: call void @callee()
; CHECK-NEXT: %y = call i8* @objc_loadWeak(i8** %p)
; CHECK-NEXT: call void @use_pointer(i8* %y)
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test4(i8** %p) {
%x = call i8* @objc_loadWeak(i8** %p)
call void @use_pointer(i8* %x) readonly
call void @callee()
%y = call i8* @objc_loadWeak(i8** %p)
call void @use_pointer(i8* %y)
ret void
}
; Store to load forwarding.
; CHECK: define void @test5(i8** %p, i8* %n) {
; CHECK-NEXT: %1 = call i8* @objc_storeWeak(i8** %p, i8* %n)
; CHECK-NEXT: call void @use_pointer(i8* %n)
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test5(i8** %p, i8* %n) {
call i8* @objc_storeWeak(i8** %p, i8* %n)
%y = call i8* @objc_loadWeak(i8** %p)
call void @use_pointer(i8* %y)
ret void
}
; Store to load forwarding with objc_initWeak.
; CHECK: define void @test6(i8** %p, i8* %n) {
; CHECK-NEXT: %1 = call i8* @objc_initWeak(i8** %p, i8* %n)
; CHECK-NEXT: call void @use_pointer(i8* %n)
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test6(i8** %p, i8* %n) {
call i8* @objc_initWeak(i8** %p, i8* %n)
%y = call i8* @objc_loadWeak(i8** %p)
call void @use_pointer(i8* %y)
ret void
}
; Don't forward if there's a may-alias store in the way.
; CHECK: define void @test7(i8** %p, i8* %n, i8** %q, i8* %m) {
; CHECK-NEXT: call i8* @objc_initWeak(i8** %p, i8* %n)
; CHECK-NEXT: call i8* @objc_storeWeak(i8** %q, i8* %m)
; CHECK-NEXT: %y = call i8* @objc_loadWeak(i8** %p)
; CHECK-NEXT: call void @use_pointer(i8* %y)
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test7(i8** %p, i8* %n, i8** %q, i8* %m) {
call i8* @objc_initWeak(i8** %p, i8* %n)
call i8* @objc_storeWeak(i8** %q, i8* %m)
%y = call i8* @objc_loadWeak(i8** %p)
call void @use_pointer(i8* %y)
ret void
}

View File

@ -0,0 +1,331 @@
; RUN: opt -objc-arc -S < %s | FileCheck %s
target datalayout = "e-p:64:64:64"
declare i8* @objc_retain(i8*)
declare i8* @objc_retainAutoreleasedReturnValue(i8*)
declare void @objc_release(i8*)
declare i8* @objc_autorelease(i8*)
declare i8* @objc_autoreleaseReturnValue(i8*)
declare i8* @objc_retainAutoreleaseReturnValue(i8*)
declare void @objc_autoreleasePoolPop(i8*)
declare void @objc_autoreleasePoolPush()
declare i8* @objc_retainBlock(i8*)
declare i8* @objc_retainedObject(i8*)
declare i8* @objc_unretainedObject(i8*)
declare i8* @objc_unretainedPointer(i8*)
declare void @use_pointer(i8*)
declare void @callee()
declare void @callee_fnptr(void ()*)
declare void @invokee()
declare i8* @returner()
; Test that retain+release elimination is suppressed when the
; retain is an objc_retainAutoreleasedReturnValue, since it's
; better to do the RV optimization.
; CHECK: define void @test0(
; CHECK-NEXT: entry:
; CHECK-NEXT: %x = call i8* @returner
; CHECK-NEXT: %0 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %x) nounwind
; CHECK: t:
; CHECK-NOT: @objc_
; CHECK: return:
; CHECK-NEXT: call void @objc_release(i8* %x)
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test0(i1 %p) nounwind {
entry:
%x = call i8* @returner()
%0 = call i8* @objc_retainAutoreleasedReturnValue(i8* %x)
br i1 %p, label %t, label %return
t:
call void @use_pointer(i8* %x)
store i8 0, i8* %x
br label %return
return:
call void @objc_release(i8* %x) nounwind
ret void
}
; Delete no-ops.
; CHECK: define void @test2
; CHECK-NOT: @objc_
; CHECK: }
define void @test2() {
call i8* @objc_retainAutoreleasedReturnValue(i8* null)
call i8* @objc_autoreleaseReturnValue(i8* null)
; call i8* @objc_retainAutoreleaseReturnValue(i8* null) ; TODO
ret void
}
; Delete a redundant retainRV,autoreleaseRV when forwaring a call result
; directly to a return value.
; CHECK: define i8* @test3
; CHECK: call i8* @returner()
; CHECK-NEXT: ret i8* %call
define i8* @test3() {
entry:
%call = call i8* @returner()
%0 = call i8* @objc_retainAutoreleasedReturnValue(i8* %call) nounwind
%1 = call i8* @objc_autoreleaseReturnValue(i8* %0) nounwind
ret i8* %1
}
; Delete a redundant retain,autoreleaseRV when forwaring a call result
; directly to a return value.
; CHECK: define i8* @test4
; CHECK: call i8* @returner()
; CHECK-NEXT: ret i8* %call
define i8* @test4() {
entry:
%call = call i8* @returner()
%0 = call i8* @objc_retain(i8* %call) nounwind
%1 = call i8* @objc_autoreleaseReturnValue(i8* %0) nounwind
ret i8* %1
}
; Delete a redundant fused retain+autoreleaseRV when forwaring a call result
; directly to a return value.
; TODO
; HECK: define i8* @test5
; HECK: call i8* @returner()
; HECK-NEXT: ret i8* %call
;define i8* @test5() {
;entry:
; %call = call i8* @returner()
; %0 = call i8* @objc_retainAutoreleaseReturnValue(i8* %call) nounwind
; ret i8* %0
;}
; Don't eliminate objc_retainAutoreleasedReturnValue by merging it into
; an objc_autorelease.
; TODO? Merge objc_retainAutoreleasedReturnValue and objc_autorelease into
; objc_retainAutoreleasedReturnValueAutorelease and merge
; objc_retainAutoreleasedReturnValue and objc_autoreleaseReturnValue
; into objc_retainAutoreleasedReturnValueAutoreleaseReturnValue?
; Those entrypoints don't exist yet though.
; CHECK: define i8* @test7(
; CHECK: call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
; CHECK: %t = tail call i8* @objc_autoreleaseReturnValue(i8* %p)
define i8* @test7() {
%p = call i8* @returner()
call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
%t = call i8* @objc_autoreleaseReturnValue(i8* %p)
call void @use_pointer(i8* %t)
ret i8* %t
}
; CHECK: define i8* @test7b(
; CHECK: call i8* @objc_retain(i8* %p)
; CHECK: %t = tail call i8* @objc_autoreleaseReturnValue(i8* %p)
define i8* @test7b() {
%p = call i8* @returner()
call void @use_pointer(i8* %p)
call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
%t = call i8* @objc_autoreleaseReturnValue(i8* %p)
ret i8* %t
}
; Turn objc_retain into objc_retainAutoreleasedReturnValue if its operand
; is a return value.
; CHECK: define void @test8()
; CHECK: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
define void @test8() {
%p = call i8* @returner()
call i8* @objc_retain(i8* %p)
ret void
}
; Don't apply the RV optimization to autorelease if there's no retain.
; CHECK: define i8* @test9(i8* %p)
; CHECK: tail call i8* @objc_autorelease(i8* %p)
define i8* @test9(i8* %p) {
call i8* @objc_autorelease(i8* %p)
ret i8* %p
}
; Apply the RV optimization.
; CHECK: define i8* @test10(i8* %p)
; CHECK: tail call i8* @objc_retain(i8* %p) nounwind
; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %p) nounwind
; CHECK-NEXT: ret i8* %p
define i8* @test10(i8* %p) {
%1 = call i8* @objc_retain(i8* %p)
%2 = call i8* @objc_autorelease(i8* %p)
ret i8* %p
}
; Don't do the autoreleaseRV optimization because @use_pointer
; could undo the retain.
; CHECK: define i8* @test11(i8* %p)
; CHECK: tail call i8* @objc_retain(i8* %p)
; CHECK-NEXT: call void @use_pointer(i8* %p)
; CHECK: tail call i8* @objc_autorelease(i8* %p)
; CHECK-NEXT: ret i8* %p
define i8* @test11(i8* %p) {
%1 = call i8* @objc_retain(i8* %p)
call void @use_pointer(i8* %p)
%2 = call i8* @objc_autorelease(i8* %p)
ret i8* %p
}
; Don't spoil the RV optimization.
; CHECK: define i8* @test12(i8* %p)
; CHECK: tail call i8* @objc_retain(i8* %p)
; CHECK: call void @use_pointer(i8* %p)
; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %p)
; CHECK: ret i8* %p
define i8* @test12(i8* %p) {
%1 = call i8* @objc_retain(i8* %p)
call void @use_pointer(i8* %p)
%2 = call i8* @objc_autoreleaseReturnValue(i8* %p)
ret i8* %p
}
; Don't zap the objc_retainAutoreleasedReturnValue.
; CHECK: define i8* @test13(
; CHECK: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
; CHECK: tail call i8* @objc_autorelease(i8* %p)
; CHECK: ret i8* %p
define i8* @test13() {
%p = call i8* @returner()
%1 = call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
call void @callee()
%2 = call i8* @objc_autorelease(i8* %p)
ret i8* %p
}
; Convert objc_retainAutoreleasedReturnValue to objc_retain if its
; argument is not a return value.
; CHECK: define void @test14(
; CHECK-NEXT: tail call i8* @objc_retain(i8* %p) nounwind
; CHECK-NEXT: ret void
define void @test14(i8* %p) {
call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
ret void
}
; Don't convert objc_retainAutoreleasedReturnValue to objc_retain if its
; argument is a return value.
; CHECK: define void @test15(
; CHECK-NEXT: %y = call i8* @returner()
; CHECK-NEXT: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %y) nounwind
; CHECK-NEXT: ret void
define void @test15() {
%y = call i8* @returner()
call i8* @objc_retainAutoreleasedReturnValue(i8* %y)
ret void
}
; Convert objc_retain to objc_retainAutoreleasedReturnValue if its
; argument is a return value.
; CHECK: define void @test16(
; CHECK-NEXT: %y = call i8* @returner()
; CHECK-NEXT: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %y) nounwind
; CHECK-NEXT: ret void
define void @test16() {
%y = call i8* @returner()
call i8* @objc_retain(i8* %y)
ret void
}
; Don't convert objc_retain to objc_retainAutoreleasedReturnValue if its
; argument is not a return value.
; CHECK: define void @test17(
; CHECK-NEXT: tail call i8* @objc_retain(i8* %y) nounwind
; CHECK-NEXT: ret void
define void @test17(i8* %y) {
call i8* @objc_retain(i8* %y)
ret void
}
; Don't Convert objc_retain to objc_retainAutoreleasedReturnValue if it
; isn't next to the call providing its return value.
; CHECK: define void @test18(
; CHECK-NEXT: %y = call i8* @returner()
; CHECK-NEXT: call void @callee()
; CHECK-NEXT: tail call i8* @objc_retain(i8* %y) nounwind
; CHECK-NEXT: ret void
define void @test18() {
%y = call i8* @returner()
call void @callee()
call i8* @objc_retain(i8* %y)
ret void
}
; Delete autoreleaseRV+retainRV pairs.
; CHECK: define i8* @test19(i8* %p) {
; CHECK-NEXT: ret i8* %p
define i8* @test19(i8* %p) {
call i8* @objc_autoreleaseReturnValue(i8* %p)
call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
ret i8* %p
}
; Like test19 but with plain autorelease.
; CHECK: define i8* @test20(i8* %p) {
; CHECK-NEXT: call i8* @objc_autorelease(i8* %p)
; CHECK-NEXT: call i8* @objc_retain(i8* %p)
; CHECK-NEXT: ret i8* %p
define i8* @test20(i8* %p) {
call i8* @objc_autorelease(i8* %p)
call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
ret i8* %p
}
; Like test19 but with plain retain.
; CHECK: define i8* @test21(i8* %p) {
; CHECK-NEXT: call i8* @objc_autoreleaseReturnValue(i8* %p)
; CHECK-NEXT: call i8* @objc_retain(i8* %p)
; CHECK-NEXT: ret i8* %p
define i8* @test21(i8* %p) {
call i8* @objc_autoreleaseReturnValue(i8* %p)
call i8* @objc_retain(i8* %p)
ret i8* %p
}
; Like test19 but with plain retain and autorelease.
; CHECK: define i8* @test22(i8* %p) {
; CHECK-NEXT: call i8* @objc_autorelease(i8* %p)
; CHECK-NEXT: call i8* @objc_retain(i8* %p)
; CHECK-NEXT: ret i8* %p
define i8* @test22(i8* %p) {
call i8* @objc_autorelease(i8* %p)
call i8* @objc_retain(i8* %p)
ret i8* %p
}
; Convert autoreleaseRV to autorelease.
; CHECK: define void @test23(
; CHECK: tail call i8* @objc_autorelease(i8* %p) nounwind
define void @test23(i8* %p) {
store i8 0, i8* %p
call i8* @objc_autoreleaseReturnValue(i8* %p)
ret void
}

View File

@ -0,0 +1,14 @@
; RUN: opt -objc-arc-contract -S < %s | FileCheck %s
declare i8* @objc_initWeak(i8**, i8*)
; Convert objc_initWeak(p, null) to *p = null.
; CHECK: define i8* @test0(i8** %p) {
; CHECK-NEXT: store i8* null, i8** %p
; CHECK-NEXT: ret i8* null
; CHECK-NEXT: }
define i8* @test0(i8** %p) {
%t = call i8* @objc_initWeak(i8** %p, i8* null)
ret i8* %t
}

View File

@ -0,0 +1,87 @@
; RUN: opt -S -basicaa -objc-arc < %s | FileCheck %s
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-apple-darwin11.0.0"
%0 = type { i64, i64, i8*, i8*, i8*, i8* }
%1 = type <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>
%struct.__block_descriptor = type { i64, i64 }
@_NSConcreteStackBlock = external global i8*
@.str = private unnamed_addr constant [6 x i8] c"v8@?0\00"
@"\01L_OBJC_CLASS_NAME_" = internal global [3 x i8] c"\01@\00", section "__TEXT,__objc_classname,cstring_literals", align 1
@__block_descriptor_tmp = internal constant %0 { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_ to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_ to i8*), i8* getelementptr inbounds ([6 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([3 x i8]* @"\01L_OBJC_CLASS_NAME_", i32 0, i32 0) }
@"\01L_OBJC_IMAGE_INFO" = internal constant [2 x i32] [i32 0, i32 16], section "__DATA, __objc_imageinfo, regular, no_dead_strip"
@llvm.used = appending global [2 x i8*] [i8* getelementptr inbounds ([3 x i8]* @"\01L_OBJC_CLASS_NAME_", i32 0, i32 0), i8* bitcast ([2 x i32]* @"\01L_OBJC_IMAGE_INFO" to i8*)], section "llvm.metadata"
; Eliminate unnecessary weak pointer copies.
; CHECK: define void @foo() {
; CHECK-NEXT: entry:
; CHECK-NEXT: %call = call i8* @bar()
; CHECK-NEXT: call void @use(i8* %call) nounwind
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @foo() {
entry:
%w = alloca i8*, align 8
%x = alloca i8*, align 8
%call = call i8* @bar()
%0 = call i8* @objc_initWeak(i8** %w, i8* %call) nounwind
%1 = call i8* @objc_loadWeak(i8** %w) nounwind
%2 = call i8* @objc_initWeak(i8** %x, i8* %1) nounwind
%3 = call i8* @objc_loadWeak(i8** %x) nounwind
call void @use(i8* %3) nounwind
call void @objc_destroyWeak(i8** %x) nounwind
call void @objc_destroyWeak(i8** %w) nounwind
ret void
}
; Eliminate unnecessary weak pointer copies in a block initialization.
; CHECK: define void @qux(i8* %me) nounwind {
; CHECK-NEXT: entry:
; CHECK-NEXT: %block = alloca %1, align 8
; CHECK-NOT: alloca
; CHECK: }
define void @qux(i8* %me) nounwind {
entry:
%w = alloca i8*, align 8
%block = alloca %1, align 8
%0 = call i8* @objc_retain(i8* %me) nounwind
%1 = call i8* @objc_initWeak(i8** %w, i8* %0) nounwind
%block.isa = getelementptr inbounds %1* %block, i64 0, i32 0
store i8* bitcast (i8** @_NSConcreteStackBlock to i8*), i8** %block.isa, align 8
%block.flags = getelementptr inbounds %1* %block, i64 0, i32 1
store i32 1107296256, i32* %block.flags, align 8
%block.reserved = getelementptr inbounds %1* %block, i64 0, i32 2
store i32 0, i32* %block.reserved, align 4
%block.invoke = getelementptr inbounds %1* %block, i64 0, i32 3
store i8* bitcast (void (i8*)* @__qux_block_invoke_0 to i8*), i8** %block.invoke, align 8
%block.descriptor = getelementptr inbounds %1* %block, i64 0, i32 4
store %struct.__block_descriptor* bitcast (%0* @__block_descriptor_tmp to %struct.__block_descriptor*), %struct.__block_descriptor** %block.descriptor, align 8
%block.captured = getelementptr inbounds %1* %block, i64 0, i32 5
%2 = call i8* @objc_loadWeak(i8** %w) nounwind
%3 = call i8* @objc_initWeak(i8** %block.captured, i8* %2) nounwind
%4 = bitcast %1* %block to void ()*
call void @use_block(void ()* %4) nounwind
call void @objc_destroyWeak(i8** %block.captured) nounwind
call void @objc_destroyWeak(i8** %w) nounwind
call void @objc_release(i8* %0) nounwind, !clang.imprecise_release !0
ret void
}
declare i8* @objc_retain(i8*)
declare void @use_block(void ()*) nounwind
declare void @__qux_block_invoke_0(i8* %.block_descriptor) nounwind
declare void @__copy_helper_block_(i8*, i8*) nounwind
declare void @objc_copyWeak(i8**, i8**)
declare void @__destroy_helper_block_(i8*) nounwind
declare void @objc_release(i8*)
declare i8* @bar()
declare i8* @objc_initWeak(i8**, i8*)
declare i8* @objc_loadWeak(i8**)
declare void @use(i8*) nounwind
declare void @objc_destroyWeak(i8**)
!0 = metadata !{}

View File

@ -0,0 +1,57 @@
; RUN: opt -objc-arc -S < %s | FileCheck %s
declare i8* @objc_initWeak(i8**, i8*)
declare i8* @objc_storeWeak(i8**, i8*)
declare i8* @objc_loadWeak(i8**)
declare void @objc_destroyWeak(i8**)
declare i8* @objc_loadWeakRetained(i8**)
declare void @objc_moveWeak(i8**, i8**)
declare void @objc_copyWeak(i8**, i8**)
; If the pointer-to-weak-pointer is null, it's undefined behavior.
; CHECK: define void @test0(
; CHECK: store i8* undef, i8** null
; CHECK: store i8* undef, i8** null
; CHECK: store i8* undef, i8** null
; CHECK: store i8* undef, i8** null
; CHECK: store i8* undef, i8** null
; CHECK: store i8* undef, i8** null
; CHECK: store i8* undef, i8** null
; CHECK: store i8* undef, i8** null
; CHECK: store i8* undef, i8** null
; CHECK: store i8* undef, i8** null
; CHECK: store i8* undef, i8** null
; CHECK: store i8* undef, i8** null
; CHECK: store i8* undef, i8** null
; CHECK: store i8* undef, i8** null
; CHECK: store i8* undef, i8** null
; CHECK: store i8* undef, i8** null
; CHECK: store i8* undef, i8** null
; CHECK: store i8* undef, i8** null
; CHECK: ret void
define void @test0(i8* %p, i8** %q) {
entry:
call i8* @objc_storeWeak(i8** null, i8* %p)
call i8* @objc_storeWeak(i8** undef, i8* %p)
call i8* @objc_loadWeakRetained(i8** null)
call i8* @objc_loadWeakRetained(i8** undef)
call i8* @objc_loadWeak(i8** null)
call i8* @objc_loadWeak(i8** undef)
call i8* @objc_initWeak(i8** null, i8* %p)
call i8* @objc_initWeak(i8** undef, i8* %p)
call void @objc_destroyWeak(i8** null)
call void @objc_destroyWeak(i8** undef)
call void @objc_copyWeak(i8** null, i8** %q)
call void @objc_copyWeak(i8** undef, i8** %q)
call void @objc_copyWeak(i8** %q, i8** null)
call void @objc_copyWeak(i8** %q, i8** undef)
call void @objc_moveWeak(i8** null, i8** %q)
call void @objc_moveWeak(i8** undef, i8** %q)
call void @objc_moveWeak(i8** %q, i8** null)
call void @objc_moveWeak(i8** %q, i8** undef)
ret void
}