diff options
Diffstat (limited to 'test/CodeGenObjC/arc.m')
-rw-r--r-- | test/CodeGenObjC/arc.m | 307 |
1 files changed, 96 insertions, 211 deletions
diff --git a/test/CodeGenObjC/arc.m b/test/CodeGenObjC/arc.m index 8e38019..7262dc8 100644 --- a/test/CodeGenObjC/arc.m +++ b/test/CodeGenObjC/arc.m @@ -1,6 +1,37 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-optzns -o - %s | FileCheck %s // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-GLOBALS %s +// rdar://13129783. Check both native/non-native arc platforms. Here we check +// that they treat nonlazybind differently. +// RUN: %clang_cc1 -fobjc-runtime=macosx-10.6.0 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=ARC-ALIEN %s +// RUN: %clang_cc1 -fobjc-runtime=macosx-10.7.0 -triple x86_64-apple-darwin11 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=ARC-NATIVE %s + +// ARC-ALIEN: declare extern_weak void @objc_storeStrong(i8**, i8*) +// ARC-ALIEN: declare extern_weak i8* @objc_retain(i8*) +// ARC-ALIEN: declare extern_weak i8* @objc_autoreleaseReturnValue(i8*) +// ARC-ALIEN: declare i8* @objc_msgSend(i8*, i8*, ...) [[NLB:#[0-9]+]] +// ARC-ALIEN: declare extern_weak void @objc_release(i8*) +// ARC-ALIEN: declare extern_weak i8* @objc_retainAutoreleasedReturnValue(i8*) +// ARC-ALIEN: declare extern_weak i8* @objc_initWeak(i8**, i8*) +// ARC-ALIEN: declare extern_weak i8* @objc_storeWeak(i8**, i8*) +// ARC-ALIEN: declare extern_weak i8* @objc_loadWeakRetained(i8**) +// ARC-ALIEN: declare extern_weak void @objc_destroyWeak(i8**) +// ARC-ALIEN: declare extern_weak i8* @objc_autorelease(i8*) +// ARC-ALIEN: declare extern_weak i8* @objc_retainAutorelease(i8*) + +// ARC-NATIVE: declare void @objc_storeStrong(i8**, i8*) +// ARC-NATIVE: declare i8* @objc_retain(i8*) [[NLB:#[0-9]+]] +// ARC-NATIVE: declare i8* @objc_autoreleaseReturnValue(i8*) +// ARC-NATIVE: declare i8* @objc_msgSend(i8*, i8*, ...) [[NLB]] +// ARC-NATIVE: declare void @objc_release(i8*) [[NLB]] +// ARC-NATIVE: declare i8* @objc_retainAutoreleasedReturnValue(i8*) +// ARC-NATIVE: declare i8* @objc_initWeak(i8**, i8*) +// ARC-NATIVE: declare i8* @objc_storeWeak(i8**, i8*) +// ARC-NATIVE: declare i8* @objc_loadWeakRetained(i8**) +// ARC-NATIVE: declare void @objc_destroyWeak(i8**) +// ARC-NATIVE: declare i8* @objc_autorelease(i8*) +// ARC-NATIVE: declare i8* @objc_retainAutorelease(i8*) + // CHECK: define void @test0 void test0(id x) { // CHECK: [[X:%.*]] = alloca i8* @@ -9,9 +40,6 @@ void test0(id x) { // CHECK-NEXT: [[TMP:%.*]] = load i8** [[X]] // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) // CHECK-NEXT: ret void -// rdar://12040837 - // CHECK: declare extern_weak i8* @objc_retain(i8*) nonlazybind - // CHECK: declare extern_weak void @objc_release(i8*) nonlazybind } // CHECK: define i8* @test1(i8* @@ -29,7 +57,7 @@ id test1(id x) { // CHECK-NEXT: call void @objc_release(i8* [[T0]]) // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]] // CHECK-NEXT: call void @objc_release(i8* [[T1]]) - // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[RET]]) + // CHECK-NEXT: [[T1:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[RET]]) // CHECK-NEXT: ret i8* [[T1]] id y; return y; @@ -88,12 +116,12 @@ void test3_unelided() { // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST3]]* [[T0]] to i8* // CHECK-NEXT: [[COPY:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend {{.*}})(i8* [[T1]], - // CHECK-NEXT: call void @objc_release(i8* [[COPY]]) nounwind + // CHECK-NEXT: call void @objc_release(i8* [[COPY]]) [[NUW:#[0-9]+]] [x copy]; // CHECK-NEXT: [[T0:%.*]] = load [[TEST3]]** [[X]] // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST3]]* [[T0]] to i8* - // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind + // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]] // CHECK-NEXT: ret void } @@ -127,13 +155,13 @@ void test3() { // Assignment to x. // CHECK-NEXT: [[TMP:%.*]] = load i8** [[X]] // CHECK-NEXT: store i8* [[COPY]], i8** [[X]] - // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) nounwind + // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) [[NUW]] x = [x copy]; // Cleanup for x. // CHECK-NEXT: [[TMP:%.*]] = load i8** [[X]] - // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) nounwind + // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) [[NUW]] // CHECK-NEXT: ret void } @@ -156,7 +184,7 @@ id test4() { // Retain/release elided. // CHECK-NEXT: bitcast // CHECK-NEXT: [[INIT:%.*]] = bitcast - // CHECK-NEXT: [[RET:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[INIT]]) + // CHECK-NEXT: [[RET:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[INIT]]) // CHECK-NEXT: ret i8* [[RET]] @@ -188,7 +216,7 @@ void test5(Test5 *x, id y) { // CHECK-NEXT: [[VAR:%.*]] = bitcast // CHECK-NEXT: [[TMP:%.*]] = load i8** [[VAR]] // CHECK-NEXT: store i8* null, i8** [[VAR]] - // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) nounwind + // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) [[NUW]] x->var = 0; // CHECK-NEXT: [[YVAL:%.*]] = load i8** [[Y]] @@ -197,18 +225,18 @@ void test5(Test5 *x, id y) { // CHECK-NEXT: bitcast // CHECK-NEXT: getelementptr // CHECK-NEXT: [[VAR:%.*]] = bitcast - // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* [[YVAL]]) nounwind + // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* [[YVAL]]) [[NUW]] // CHECK-NEXT: [[TMP:%.*]] = load i8** [[VAR]] // CHECK-NEXT: store i8* [[T0]], i8** [[VAR]] - // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) nounwind + // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) [[NUW]] x->var = y; // Epilogue. // CHECK-NEXT: [[TMP:%.*]] = load i8** [[Y]] - // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) nounwind + // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) [[NUW]] // CHECK-NEXT: [[T0:%.*]] = load [[TEST5]]** [[X]] // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST5]]* [[T0]] to i8* - // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind + // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]] // CHECK-NEXT: ret void } @@ -219,7 +247,7 @@ void test6() { // CHECK-NEXT: [[CALL:%.*]] = call i8* @test6_helper() // CHECK-NEXT: store i8* [[CALL]], i8** [[X]] // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]] - // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release + // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release // CHECK-NEXT: ret void id x = test6_helper(); } @@ -230,10 +258,10 @@ void test7() { // CHECK: [[X:%.*]] = alloca i8* // CHECK-NEXT: store i8* null, i8** [[X]] // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]] - // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) nounwind + // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) [[NUW]] // CHECK-NEXT: call void @test7_helper(i8* [[T1]]) // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]] - // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release + // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release // CHECK-NEXT: ret void id x; test7_helper(x); @@ -245,27 +273,7 @@ void test8() { // CHECK: [[X:%.*]] = alloca i8* // CHECK-NEXT: [[T0:%.*]] = call i8* @test8_helper() // CHECK-NEXT: store i8* [[T0]], i8** [[X]] - // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind - // CHECK-NOT: imprecise_release - // CHECK-NEXT: ret void -} - -id test9_helper(void) __attribute__((ns_returns_retained)); -void test9() { - id x __attribute__((objc_precise_lifetime)) = test9_helper(); - x = 0; - // CHECK: [[X:%.*]] = alloca i8* - // CHECK-NEXT: [[CALL:%.*]] = call i8* @test9_helper() - // CHECK-NEXT: store i8* [[CALL]], i8** [[X]] - - // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]] - // CHECK-NEXT: store i8* null, i8** [[X]] - // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release - - // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]] - // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind - // CHECK-NOT: clang.imprecise_release - + // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]], !clang.imprecise_release // CHECK-NEXT: ret void } @@ -314,7 +322,7 @@ void test11(id (*f)(void) __attribute__((ns_returns_retained))) { // CHECK-NEXT: [[T1:%.*]] = call i8* [[T0]]() // CHECK-NEXT: store i8* [[T1]], i8** [[X]], align // CHECK-NEXT: [[T3:%.*]] = load i8** [[X]] - // CHECK-NEXT: call void @objc_release(i8* [[T3]]) nounwind, !clang.imprecise_release + // CHECK-NEXT: call void @objc_release(i8* [[T3]]) [[NUW]], !clang.imprecise_release // CHECK-NEXT: ret void id x = f(); } @@ -343,9 +351,9 @@ void test12(void) { // CHECK-NEXT: store i8* [[T2]], i8** [[Y]], align // CHECK-NEXT: [[T4:%.*]] = load i8** [[Y]] - // CHECK-NEXT: call void @objc_release(i8* [[T4]]) nounwind, !clang.imprecise_release + // CHECK-NEXT: call void @objc_release(i8* [[T4]]) [[NUW]], !clang.imprecise_release // CHECK-NEXT: call void @objc_destroyWeak(i8** [[X]]) - // CHECK-NEXT: ret void + // CHECK: ret void } // Indirect consuming calls. @@ -359,7 +367,7 @@ void test13(void) { extern fnty *test13_func; // CHECK-NEXT: [[FN:%.*]] = load void (i8*)** @test13_func, align // CHECK-NEXT: [[X_VAL:%.*]] = load i8** [[X]], align - // CHECK-NEXT: [[X_TMP:%.*]] = call i8* @objc_retain(i8* [[X_VAL]]) nounwind + // CHECK-NEXT: [[X_TMP:%.*]] = call i8* @objc_retain(i8* [[X_VAL]]) [[NUW]] // CHECK-NEXT: call void [[FN]](i8* [[X_TMP]]) test13_func(x); @@ -369,14 +377,14 @@ void test13(void) { // CHECK-NEXT: [[BLOCK_FN_PTR:%.*]] = getelementptr inbounds [[BLOCKTY]]* [[BLOCK]], i32 0, i32 3 // CHECK-NEXT: [[BLOCK_OPAQUE:%.*]] = bitcast [[BLOCKTY]]* [[BLOCK]] to i8* // CHECK-NEXT: [[X_VAL:%.*]] = load i8** [[X]], align - // CHECK-NEXT: [[X_TMP:%.*]] = call i8* @objc_retain(i8* [[X_VAL]]) nounwind + // CHECK-NEXT: [[X_TMP:%.*]] = call i8* @objc_retain(i8* [[X_VAL]]) [[NUW]] // CHECK-NEXT: [[BLOCK_FN_TMP:%.*]] = load i8** [[BLOCK_FN_PTR]] // CHECK-NEXT: [[BLOCK_FN:%.*]] = bitcast i8* [[BLOCK_FN_TMP]] to void (i8*, i8*)* // CHECK-NEXT: call void [[BLOCK_FN]](i8* [[BLOCK_OPAQUE]], i8* [[X_TMP]]) test13_block(x); // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]] - // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind + // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]] // CHECK-NEXT: ret void } @@ -426,14 +434,14 @@ void test13(void) { // CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST16]]* [[BASE]] to i8* // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8* [[T0]], i64 [[Y_OFF]] // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to i8** - // CHECK-NEXT: call void @objc_storeStrong(i8** [[T2]], i8* null) nounwind + // CHECK-NEXT: call void @objc_storeStrong(i8** [[T2]], i8* null) [[NUW]] // Destroy z. // CHECK-NEXT: [[Z_OFF:%.*]] = load i64* @"OBJC_IVAR_$_Test16.z" // CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST16]]* [[BASE]] to i8* // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8* [[T0]], i64 [[Z_OFF]] // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to i8** - // CHECK-NEXT: call void @objc_storeStrong(i8** [[T2]], i8* null) nounwind + // CHECK-NEXT: call void @objc_storeStrong(i8** [[T2]], i8* null) [[NUW]] // CHECK-NEXT: ret void @@ -452,19 +460,20 @@ void test13(void) { void test19() { // CHECK: define void @test19() // CHECK: [[X:%.*]] = alloca [5 x i8*], align 16 + // CHECK: call void @llvm.lifetime.start // CHECK-NEXT: [[T0:%.*]] = bitcast [5 x i8*]* [[X]] to i8* - // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 40, i32 16, i1 false) + // CHECK: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 40, i32 16, i1 false) id x[5]; extern id test19_helper(void); x[2] = test19_helper(); // CHECK-NEXT: [[CALL:%.*]] = call i8* @test19_helper() - // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[CALL]]) nounwind + // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[CALL]]) [[NUW]] // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [5 x i8*]* [[X]], i32 0, i64 2 // CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]] // CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]] - // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind + // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]] // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [5 x i8*]* [[X]], i32 0, i32 0 // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds i8** [[BEGIN]], i64 5 @@ -473,7 +482,7 @@ void test19() { // CHECK: [[AFTER:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ] // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds i8** [[AFTER]], i64 -1 // CHECK-NEXT: [[T0:%.*]] = load i8** [[CUR]] - // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release + // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]], !clang.imprecise_release // CHECK-NEXT: [[EQ:%.*]] = icmp eq i8** [[CUR]], [[BEGIN]] // CHECK-NEXT: br i1 [[EQ]], @@ -512,7 +521,7 @@ void test20(unsigned n) { // CHECK: [[AFTER:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ] // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds i8** [[AFTER]], i64 -1 // CHECK-NEXT: [[T0:%.*]] = load i8** [[CUR]] - // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release + // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]], !clang.imprecise_release // CHECK-NEXT: [[EQ:%.*]] = icmp eq i8** [[CUR]], [[VLA]] // CHECK-NEXT: br i1 [[EQ]], @@ -558,7 +567,7 @@ void test21(unsigned n) { // CHECK: [[AFTER:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ] // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds i8** [[AFTER]], i64 -1 // CHECK-NEXT: [[T0:%.*]] = load i8** [[CUR]] - // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release + // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]], !clang.imprecise_release // CHECK-NEXT: [[EQ:%.*]] = icmp eq i8** [[CUR]], [[BEGIN]] // CHECK-NEXT: br i1 [[EQ]], @@ -567,39 +576,6 @@ void test21(unsigned n) { // CHECK-NEXT: ret void } -void test22(_Bool cond) { - id test22_helper(void) __attribute__((ns_returns_retained)); - - // CHECK: define void @test22( - // CHECK: [[COND:%.*]] = alloca i8, - // CHECK-NEXT: [[X:%.*]] = alloca i8*, - // CHECK-NEXT: [[RELVAL:%.*]] = alloca i8* - // CHECK-NEXT: [[RELCOND:%.*]] = alloca i1 - // CHECK-NEXT: zext - // CHECK-NEXT: store - // CHECK-NEXT: [[T0:%.*]] = load i8* [[COND]] - // CHECK-NEXT: [[T1:%.*]] = trunc i8 [[T0]] to i1 - // CHECK-NEXT: store i1 false, i1* [[RELCOND]] - // CHECK-NEXT: br i1 [[T1]], - // CHECK: br label - // CHECK: [[CALL:%.*]] = call i8* @test22_helper() - // CHECK-NEXT: store i8* [[CALL]], i8** [[RELVAL]] - // CHECK-NEXT: store i1 true, i1* [[RELCOND]] - // CHECK-NEXT: br label - // CHECK: [[T0:%.*]] = phi i8* [ null, {{%.*}} ], [ [[CALL]], {{%.*}} ] - // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) nounwind - // CHECK-NEXT: store i8* [[T1]], i8** [[X]], - // CHECK-NEXT: [[REL:%.*]] = load i1* [[RELCOND]] - // CHECK-NEXT: br i1 [[REL]], - // CHECK: [[T0:%.*]] = load i8** [[RELVAL]] - // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind - // CHECK-NEXT: br label - // CHECK: [[T0:%.*]] = load i8** [[X]] - // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind - // CHECK-NEXT: ret void - id x = (cond ? 0 : test22_helper()); -} - // rdar://problem/8922540 // Note that we no longer emit .release_ivars flags. // rdar://problem/12492434 @@ -646,7 +622,9 @@ void test22(_Bool cond) { // CHECK-NEXT: store i8* {{%.*}}, i8** [[CMD]] // CHECK-NEXT: [[T0:%.*]] = load [[TEST27]]** [[SELF]] // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST27]]* [[T0]] to i8* -// CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[T1]]) +// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) +// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST27]]* +// CHECK-NEXT: [[RET:%.*]] = bitcast [[TEST27]]* [[T3]] to i8* // CHECK-NEXT: store i32 {{[0-9]+}}, i32* [[DEST]] // CHECK-NEXT: [[T0:%.*]] = load [[TEST27]]** [[SELF]] // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST27]]* [[T0]] to i8* @@ -681,7 +659,7 @@ void test22(_Bool cond) { @implementation Test29 static id _test29_allocator = 0; - (id) init { -// CHECK: define internal i8* @"\01-[Test29 init]"([[TEST29:%.*]]* {{%.*}}, +// CHECK: define internal i8* @"\01-[Test29 init]"([[TEST29:%[^*]*]]* {{%.*}}, // CHECK: [[SELF:%.*]] = alloca [[TEST29]]*, align 8 // CHECK-NEXT: [[CMD:%.*]] = alloca i8*, align 8 // CHECK-NEXT: [[CLEANUP:%.*]] = alloca i32 @@ -710,13 +688,15 @@ static id _test29_allocator = 0; // Return statement. // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[CALL]] // CHECK-NEXT: [[CALL:%.*]] = bitcast -// CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[CALL]]) nounwind +// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* [[CALL]]) [[NUW]] +// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[TEST29]]* +// CHECK-NEXT: [[RET:%.*]] = bitcast [[TEST29]]* [[T1]] to i8* // CHECK-NEXT: store i32 1, i32* [[CLEANUP]] // Cleanup. // CHECK-NEXT: [[T0:%.*]] = load [[TEST29]]** [[SELF]] // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST29]]* [[T0]] to i8* -// CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release +// CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release // Return. // CHECK-NEXT: ret i8* [[RET]] @@ -754,7 +734,7 @@ static id _test29_allocator = 0; // Assignment. // CHECK-NEXT: [[T0:%.*]] = bitcast i8* [[CALL]] to [[TEST29]]* // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST29]]* [[T0]] to i8* -// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) nounwind +// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) [[NUW]] // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST29]]* // CHECK-NEXT: [[T4:%.*]] = load [[TEST29]]** [[SELF]], align // CHECK-NEXT: store [[TEST29]]* [[T3]], [[TEST29]]** [[SELF]], align @@ -764,16 +744,18 @@ static id _test29_allocator = 0; // Return statement. // CHECK-NEXT: [[T0:%.*]] = load [[TEST29]]** [[SELF]] // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST29]]* [[T0]] to i8* -// CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[T1]]) nounwind +// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* [[T1]]) [[NUW]] +// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[TEST29]]* +// CHECK-NEXT: [[RET:%.*]] = bitcast [[TEST29]]* [[T1]] to i8* // CHECK-NEXT: store i32 1, i32* [[CLEANUP]] // Cleanup. // CHECK-NEXT: [[T0:%.*]] = load i8** [[ALLOCATOR]] -// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release +// CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]], !clang.imprecise_release // CHECK-NEXT: [[T0:%.*]] = load [[TEST29]]** [[SELF]] // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST29]]* [[T0]] to i8* -// CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release +// CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release // Return. // CHECK-NEXT: ret i8* [[RET]] @@ -791,7 +773,7 @@ typedef struct Test30_helper Test30_helper; char *helper; } - (id) init { -// CHECK: define internal i8* @"\01-[Test30 init]"([[TEST30:%.*]]* {{%.*}}, +// CHECK: define internal i8* @"\01-[Test30 init]"([[TEST30:%[^*]*]]* {{%.*}}, // CHECK: [[RET:%.*]] = alloca [[TEST30]]* // CHECK-NEXT: alloca i8* // CHECK-NEXT: alloca i32 @@ -819,7 +801,9 @@ char *helper; // Return. // CHECK-NEXT: [[T0:%.*]] = load [[TEST30]]** [[SELF]] // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST30]]* [[T0]] to i8* -// CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[T1]]) +// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* [[T1]]) +// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[TEST30]]* +// CHECK-NEXT: [[RET:%.*]] = bitcast [[TEST30]]* [[T1]] to i8* // CHECK-NEXT: store i32 1 // Cleanup. @@ -882,8 +866,8 @@ void test33(Test33 *ptr) { // CHECK-NEXT: store [[A_T]]* null, [[A_T]]** [[A]] // CHECK-NEXT: load [[TEST33]]** [[PTR]] - // CHECK-NEXT: [[T0:%.*]] = load [[A_T]]** [[A]] - // CHECK-NEXT: store [[A_T]]* [[T0]], [[A_T]]** [[TEMP0]] + // CHECK-NEXT: [[W0:%.*]] = load [[A_T]]** [[A]] + // CHECK-NEXT: store [[A_T]]* [[W0]], [[A_T]]** [[TEMP0]] // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_ // CHECK-NEXT: bitcast // CHECK-NEXT: objc_msgSend{{.*}}, [[A_T]]** [[TEMP0]]) @@ -891,14 +875,15 @@ void test33(Test33 *ptr) { // CHECK-NEXT: [[T1:%.*]] = bitcast [[A_T]]* [[T0]] to i8* // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A_T]]* + // CHECK-NEXT: call void (...)* @clang.arc.use([[A_T]]* [[W0]]) [[NUW]] // CHECK-NEXT: [[T4:%.*]] = load [[A_T]]** [[A]] // CHECK-NEXT: store [[A_T]]* [[T3]], [[A_T]]** [[A]] // CHECK-NEXT: [[T5:%.*]] = bitcast [[A_T]]* [[T4]] to i8* // CHECK-NEXT: call void @objc_release(i8* [[T5]]) // CHECK-NEXT: load [[TEST33]]** [[PTR]] - // CHECK-NEXT: [[T0:%.*]] = load [[A_T]]** [[A]] - // CHECK-NEXT: store [[A_T]]* [[T0]], [[A_T]]** [[TEMP1]] + // CHECK-NEXT: [[W0:%.*]] = load [[A_T]]** [[A]] + // CHECK-NEXT: store [[A_T]]* [[W0]], [[A_T]]** [[TEMP1]] // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_ // CHECK-NEXT: bitcast // CHECK-NEXT: objc_msgSend{{.*}}, [[A_T]]** [[TEMP1]]) @@ -906,6 +891,7 @@ void test33(Test33 *ptr) { // CHECK-NEXT: [[T1:%.*]] = bitcast [[A_T]]* [[T0]] to i8* // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A_T]]* + // CHECK-NEXT: call void (...)* @clang.arc.use([[A_T]]* [[W0]]) [[NUW]] // CHECK-NEXT: [[T4:%.*]] = load [[A_T]]** [[A]] // CHECK-NEXT: store [[A_T]]* [[T3]], [[A_T]]** [[A]] // CHECK-NEXT: [[T5:%.*]] = bitcast [[A_T]]* [[T4]] to i8* @@ -945,61 +931,6 @@ void test33(Test33 *ptr) { // CHECK-NEXT: ret void } -void test34(int cond) { - __strong id strong; - __weak id weak; - extern void test34_sink(id *); - test34_sink(cond ? &strong : 0); - test34_sink(cond ? &weak : 0); - - // CHECK: define void @test34( - // CHECK: [[COND:%.*]] = alloca i32 - // CHECK-NEXT: [[STRONG:%.*]] = alloca i8* - // CHECK-NEXT: [[WEAK:%.*]] = alloca i8* - // CHECK-NEXT: [[TEMP1:%.*]] = alloca i8* - // CHECK-NEXT: [[TEMP2:%.*]] = alloca i8* - // CHECK-NEXT: store i32 - // CHECK-NEXT: store i8* null, i8** [[STRONG]] - // CHECK-NEXT: call i8* @objc_initWeak(i8** [[WEAK]], i8* null) - - // CHECK-NEXT: [[T0:%.*]] = load i32* [[COND]] - // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 0 - // CHECK: [[ARG:%.*]] = phi i8** - // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null - // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i8** null, i8** [[TEMP1]] - // CHECK-NEXT: br i1 [[T0]], - // CHECK: [[T0:%.*]] = load i8** [[ARG]] - // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP1]] - // CHECK-NEXT: br label - // CHECK: call void @test34_sink(i8** [[T1]]) - // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null - // CHECK-NEXT: br i1 [[T0]], - // CHECK: [[T0:%.*]] = load i8** [[TEMP1]] - // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) - // CHECK-NEXT: [[T2:%.*]] = load i8** [[ARG]] - // CHECK-NEXT: store i8* [[T1]], i8** [[ARG]] - // CHECK-NEXT: call void @objc_release(i8* [[T2]]) - // CHECK-NEXT: br label - - // CHECK: [[T0:%.*]] = load i32* [[COND]] - // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 0 - // CHECK: [[ARG:%.*]] = phi i8** - // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null - // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i8** null, i8** [[TEMP2]] - // CHECK-NEXT: br i1 [[T0]], - // CHECK: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[ARG]]) - // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP2]] - // CHECK-NEXT: br label - // CHECK: call void @test34_sink(i8** [[T1]]) - // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null - // CHECK-NEXT: br i1 [[T0]], - // CHECK: [[T0:%.*]] = load i8** [[TEMP2]] - // CHECK-NEXT: call i8* @objc_storeWeak(i8** [[ARG]], i8* [[T0]]) - // CHECK-NEXT: br label - - // CHECK: call void @objc_destroyWeak(i8** [[WEAK]]) - // CHECK: ret void -} // CHECK: define void @test36 void test36(id x) { @@ -1034,15 +965,16 @@ void test37(void) { // CHECK-NEXT: [[TEMP:%.*]] = alloca i8* // CHECK-NEXT: store [[TEST37]]* null, [[TEST37]]** [[VAR]] - // CHECK-NEXT: [[T0:%.*]] = load [[TEST37]]** [[VAR]] - // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST37]]* [[T0]] to i8* - // CHECK-NEXT: store i8* [[T1]], i8** [[TEMP]] + // CHECK-NEXT: [[W0:%.*]] = load [[TEST37]]** [[VAR]] + // CHECK-NEXT: [[W1:%.*]] = bitcast [[TEST37]]* [[W0]] to i8* + // CHECK-NEXT: store i8* [[W1]], i8** [[TEMP]] // CHECK-NEXT: call void @test37_helper(i8** [[TEMP]]) // CHECK-NEXT: [[T0:%.*]] = load i8** [[TEMP]] // CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[TEST37]]* // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST37]]* [[T1]] to i8* // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) // CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[TEST37]]* + // CHECK-NEXT: call void (...)* @clang.arc.use(i8* [[W1]]) [[NUW]] // CHECK-NEXT: [[T5:%.*]] = load [[TEST37]]** [[VAR]] // CHECK-NEXT: store [[TEST37]]* [[T4]], [[TEST37]]** [[VAR]] // CHECK-NEXT: [[T6:%.*]] = bitcast [[TEST37]]* [[T5]] to i8* @@ -1186,7 +1118,7 @@ id test52(void) { // CHECK-NEXT: store i32 5, i32* [[X]], // CHECK-NEXT: [[T0:%.*]] = load i32* [[X]], // CHECK-NEXT: [[T1:%.*]] = call i8* @test52_helper(i32 [[T0]]) -// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T1]]) +// CHECK-NEXT: [[T2:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[T1]]) // CHECK-NEXT: ret i8* [[T2]] } @@ -1287,7 +1219,7 @@ void test56_test(void) { // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8* [[T2]], i64 [[T1]] // CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to i8** // CHECK-NEXT: [[T5:%.*]] = call i8* @objc_loadWeakRetained(i8** [[T4]]) -// CHECK-NEXT: [[T6:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T5]]) +// CHECK-NEXT: [[T6:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[T5]]) // CHECK-NEXT: ret i8* [[T6]] // CHECK: define internal i8* @"\01-[Test57 unsafe]"( @@ -1299,57 +1231,6 @@ void test56_test(void) { // CHECK-NEXT: [[T5:%.*]] = load i8** [[T4]] // CHECK-NEXT: ret i8* [[T5]] -// rdar://problem/9821110 -@interface Test58 -- (char*) interior __attribute__((objc_returns_inner_pointer)); -// Should we allow this on properties? -@end -extern Test58 *test58_helper(void); - -// CHECK: define void @test58a() -void test58a(void) { - // CHECK: [[T0:%.*]] = call [[TEST58:%.*]]* @test58_helper() - // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST58]]* [[T0]] to i8* - // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]]) - // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST58]]* - // CHECK-NEXT: store [[TEST58]]* [[T3]] - // CHECK-NEXT: [[T0:%.*]] = load [[TEST58]]** - // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST58]]* [[T0]] to i8* - // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]]) - // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST58]]* - // CHECK-NEXT: [[T4:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_ - // CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST58]]* [[T3]] to i8* - // CHECK-NEXT: [[T6:%.*]] = call i8* bitcast - // CHECK-NEXT: store i8* [[T6]], i8** - // CHECK-NEXT: [[T0:%.*]] = load [[TEST58]]** - // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST58]]* [[T0]] to i8* - // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release - // CHECK-NEXT: ret void - Test58 *ptr = test58_helper(); - char *c = [(ptr) interior]; -} - -// CHECK: define void @test58b() -void test58b(void) { - // CHECK: [[T0:%.*]] = call [[TEST58:%.*]]* @test58_helper() - // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST58]]* [[T0]] to i8* - // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]]) - // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST58]]* - // CHECK-NEXT: store [[TEST58]]* [[T3]] - // CHECK-NEXT: [[T0:%.*]] = load [[TEST58]]** - // CHECK-NEXT: [[T1:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_ - // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST58]]* [[T0]] to i8* - // CHECK-NEXT: [[T3:%.*]] = call i8* bitcast - // CHECK-NEXT: store i8* [[T3]], i8** - // CHECK-NEXT: [[T0:%.*]] = load [[TEST58]]** - // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST58]]* [[T0]] to i8* - // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind - // CHECK-NOT: clang.imprecise_release - // CHECK-NEXT: ret void - __attribute__((objc_precise_lifetime)) Test58 *ptr = test58_helper(); - char *c = [ptr interior]; -} - // rdar://problem/9842343 void test59(void) { extern id test59_getlock(void); @@ -1491,7 +1372,7 @@ void test66(void) { // CHECK-NEXT: br i1 [[SIX]], label [[NULINIT:%.*]], label [[CALL:%.*]] // CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*)*)(i8* [[T7]], i8* [[T6]], i8* [[T5]]) // CHECK-NEXT: br label [[CONT:%.*]] -// CHECK: call void @objc_release(i8* [[T5]]) nounwind +// CHECK: call void @objc_release(i8* [[T5]]) [[NUW]] // CHECK-NEXT: br label [[CONT:%.*]] // CHECK: [[T8:%.*]] = bitcast [[TEST66]]* [[T3]] to i8* // CHECK-NEXT: call void @objc_release(i8* [[T8]]) @@ -1543,3 +1424,7 @@ void test70(id i) { [2] = i }; } + +// ARC-ALIEN: attributes [[NLB]] = { nonlazybind } +// ARC-NATIVE: attributes [[NLB]] = { nonlazybind } +// CHECK: attributes [[NUW]] = { nounwind } |