mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-30 17:33:24 +00:00
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:
parent
5f36bb1759
commit
9fbd318d36
@ -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
|
||||
|
@ -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&);
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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()));
|
||||
|
@ -20,6 +20,7 @@ add_llvm_library(LLVMScalarOpts
|
||||
LoopUnswitch.cpp
|
||||
LowerAtomic.cpp
|
||||
MemCpyOptimizer.cpp
|
||||
ObjCARC.cpp
|
||||
Reassociate.cpp
|
||||
Reg2Mem.cpp
|
||||
SCCP.cpp
|
||||
|
3520
lib/Transforms/Scalar/ObjCARC.cpp
Normal file
3520
lib/Transforms/Scalar/ObjCARC.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
|
1898
test/Transforms/ObjCARC/basic.ll
Normal file
1898
test/Transforms/ObjCARC/basic.ll
Normal file
File diff suppressed because it is too large
Load Diff
86
test/Transforms/ObjCARC/cfg-hazards.ll
Normal file
86
test/Transforms/ObjCARC/cfg-hazards.ll
Normal 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 !{}
|
23
test/Transforms/ObjCARC/contract-marker.ll
Normal file
23
test/Transforms/ObjCARC/contract-marker.ll
Normal 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"}
|
31
test/Transforms/ObjCARC/contract-storestrong-ivar.ll
Normal file
31
test/Transforms/ObjCARC/contract-storestrong-ivar.ll
Normal 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
|
||||
}
|
59
test/Transforms/ObjCARC/contract-storestrong.ll
Normal file
59
test/Transforms/ObjCARC/contract-storestrong.ll
Normal 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
|
||||
}
|
63
test/Transforms/ObjCARC/contract-testcases.ll
Normal file
63
test/Transforms/ObjCARC/contract-testcases.ll
Normal 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
|
||||
}
|
145
test/Transforms/ObjCARC/contract.ll
Normal file
145
test/Transforms/ObjCARC/contract.ll
Normal 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
|
||||
}
|
3
test/Transforms/ObjCARC/dg.exp
Normal file
3
test/Transforms/ObjCARC/dg.exp
Normal file
@ -0,0 +1,3 @@
|
||||
load_lib llvm.exp
|
||||
|
||||
RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,c,cpp}]]
|
28
test/Transforms/ObjCARC/expand.ll
Normal file
28
test/Transforms/ObjCARC/expand.ll
Normal 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
|
||||
}
|
21
test/Transforms/ObjCARC/gvn.ll
Normal file
21
test/Transforms/ObjCARC/gvn.ll
Normal 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
|
||||
}
|
221
test/Transforms/ObjCARC/move-and-form-retain-autorelease.ll
Normal file
221
test/Transforms/ObjCARC/move-and-form-retain-autorelease.ll
Normal 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
|
||||
}
|
108
test/Transforms/ObjCARC/move-and-merge-autorelease.ll
Normal file
108
test/Transforms/ObjCARC/move-and-merge-autorelease.ll
Normal 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
|
||||
}
|
48
test/Transforms/ObjCARC/post-inlining.ll
Normal file
48
test/Transforms/ObjCARC/post-inlining.ll
Normal 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
|
||||
}
|
25
test/Transforms/ObjCARC/retain-not-declared.ll
Normal file
25
test/Transforms/ObjCARC/retain-not-declared.ll
Normal 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
|
||||
}
|
||||
|
135
test/Transforms/ObjCARC/rle-s2l.ll
Normal file
135
test/Transforms/ObjCARC/rle-s2l.ll
Normal 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
|
||||
}
|
331
test/Transforms/ObjCARC/rv.ll
Normal file
331
test/Transforms/ObjCARC/rv.ll
Normal 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
|
||||
}
|
14
test/Transforms/ObjCARC/weak-contract.ll
Normal file
14
test/Transforms/ObjCARC/weak-contract.ll
Normal 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
|
||||
}
|
87
test/Transforms/ObjCARC/weak-copies.ll
Normal file
87
test/Transforms/ObjCARC/weak-copies.ll
Normal 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 !{}
|
57
test/Transforms/ObjCARC/weak.ll
Normal file
57
test/Transforms/ObjCARC/weak.ll
Normal 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user