diff options
Diffstat (limited to 'clang/test')
| -rw-r--r-- | clang/test/CodeGenObjC/arc-block-copy-escape.m | 4 | ||||
| -rw-r--r-- | clang/test/CodeGenObjC/arc-blocks.m | 14 | ||||
| -rw-r--r-- | clang/test/CodeGenObjCXX/arc-blocks.mm | 120 | ||||
| -rw-r--r-- | clang/test/PCH/arc-blocks.mm | 49 |
4 files changed, 177 insertions, 10 deletions
diff --git a/clang/test/CodeGenObjC/arc-block-copy-escape.m b/clang/test/CodeGenObjC/arc-block-copy-escape.m index 3823a95d6a8..9e409ce72e2 100644 --- a/clang/test/CodeGenObjC/arc-block-copy-escape.m +++ b/clang/test/CodeGenObjC/arc-block-copy-escape.m @@ -9,14 +9,14 @@ void use_int(int); void test0(int i) { block_t block = ^{ use_int(i); }; // CHECK-LABEL: define {{.*}}void @test0( - // CHECK: call {{.*}}i8* @llvm.objc.retainBlock(i8* {{%.*}}) [[NUW:#[0-9]+]], !clang.arc.copy_on_escape + // CHECK-NOT: @llvm.objc.retainBlock( // CHECK: ret void } void test1(int i) { id block = ^{ use_int(i); }; // CHECK-LABEL: define {{.*}}void @test1( - // CHECK: call {{.*}}i8* @llvm.objc.retainBlock(i8* {{%.*}}) [[NUW]] + // CHECK: call {{.*}}i8* @llvm.objc.retainBlock(i8* {{%.*}}) [[NUW:#[0-9]+]] // CHECK-NOT: !clang.arc.copy_on_escape // CHECK: ret void } diff --git a/clang/test/CodeGenObjC/arc-blocks.m b/clang/test/CodeGenObjC/arc-blocks.m index 49da992f95f..47e2723b511 100644 --- a/clang/test/CodeGenObjC/arc-blocks.m +++ b/clang/test/CodeGenObjC/arc-blocks.m @@ -338,20 +338,19 @@ void test10a(void) { __block void (^block)(void) = ^{ block(); }; // CHECK-LABEL: define void @test10a() // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]], + // CHECK: [[BLOCK1:%.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, align 8 // Zero-initialization before running the initializer. // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[BYREF]], i32 0, i32 6 // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8 // Run the initializer as an assignment. - // CHECK: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8* - // CHECK-NEXT: [[T1:%.*]] = call i8* @llvm.objc.retainBlock(i8* [[T0]]) - // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()* + // CHECK: [[T2:%.*]] = bitcast <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* [[BLOCK1]] to void ()* // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[BYREF]], i32 0, i32 1 // CHECK-NEXT: [[T4:%.*]] = load [[BYREF_T]]*, [[BYREF_T]]** [[T3]] // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[T4]], i32 0, i32 6 // CHECK-NEXT: [[T6:%.*]] = load void ()*, void ()** [[T5]], align 8 - // CHECK-NEXT: store void ()* {{%.*}}, void ()** [[T5]], align 8 + // CHECK-NEXT: store void ()* [[T2]], void ()** [[T5]], align 8 // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8* // CHECK-NEXT: call void @llvm.objc.release(i8* [[T7]]) @@ -401,6 +400,7 @@ void test10b(void) { // CHECK-LABEL: define void @test10b() // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]], + // CHECK: [[BLOCK3:%.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, align 8 // Zero-initialize. // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[BYREF]], i32 0, i32 6 @@ -409,14 +409,12 @@ void test10b(void) { // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[BYREF]], i32 0, i32 6 // The assignment. - // CHECK: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8* - // CHECK-NEXT: [[T1:%.*]] = call i8* @llvm.objc.retainBlock(i8* [[T0]]) - // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()* + // CHECK: [[T2:%.*]] = bitcast <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* [[BLOCK3]] to void ()* // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[BYREF]], i32 0, i32 1 // CHECK-NEXT: [[T4:%.*]] = load [[BYREF_T]]*, [[BYREF_T]]** [[T3]] // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[T4]], i32 0, i32 6 // CHECK-NEXT: [[T6:%.*]] = load void ()*, void ()** [[T5]], align 8 - // CHECK-NEXT: store void ()* {{%.*}}, void ()** [[T5]], align 8 + // CHECK-NEXT: store void ()* [[T2]], void ()** [[T5]], align 8 // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8* // CHECK-NEXT: call void @llvm.objc.release(i8* [[T7]]) diff --git a/clang/test/CodeGenObjCXX/arc-blocks.mm b/clang/test/CodeGenObjCXX/arc-blocks.mm index ec0c12456aa..24697cf1bd3 100644 --- a/clang/test/CodeGenObjCXX/arc-blocks.mm +++ b/clang/test/CodeGenObjCXX/arc-blocks.mm @@ -201,3 +201,123 @@ void foo1() { ^{ (void)t0; (void)t1; (void)t2; (void)t3; (void)t4; (void)t5; }; } } + +// Test that calls to @llvm.objc.retainBlock aren't emitted in some cases. + +namespace test_block_retain { + typedef void (^BlockTy)(); + + void foo1(id); + +// CHECK-LABEL: define void @_ZN17test_block_retain14initializationEP11objc_object( +// CHECK-NOT: @llvm.objc.retainBlock( + void initialization(id a) { + BlockTy b0 = ^{ foo1(a); }; + BlockTy b1 = (^{ foo1(a); }); + b0(); + b1(); + } + +// CHECK-LABEL: define void @_ZN17test_block_retain20initializationStaticEP11objc_object( +// CHECK: @llvm.objc.retainBlock( + void initializationStatic(id a) { + static BlockTy b0 = ^{ foo1(a); }; + b0(); + } + +// CHECK-LABEL: define void @_ZN17test_block_retain15initialization2EP11objc_object +// CHECK: %[[B0:.*]] = alloca void ()*, align 8 +// CHECK: %[[B1:.*]] = alloca void ()*, align 8 +// CHECK: load void ()*, void ()** %[[B0]], align 8 +// CHECK-NOT: @llvm.objc.retainBlock +// CHECK: %[[V9:.*]] = load void ()*, void ()** %[[B0]], align 8 +// CHECK: %[[V10:.*]] = bitcast void ()* %[[V9]] to i8* +// CHECK: %[[V11:.*]] = call i8* @llvm.objc.retainBlock(i8* %[[V10]]) +// CHECK: %[[V12:.*]] = bitcast i8* %[[V11]] to void ()* +// CHECK: store void ()* %[[V12]], void ()** %[[B1]], align 8 + void initialization2(id a) { + BlockTy b0 = ^{ foo1(a); }; + b0(); + BlockTy b1 = b0; // can't optimize this yet. + b1(); + } + +// CHECK-LABEL: define void @_ZN17test_block_retain10assignmentEP11objc_object( +// CHECK-NOT: @llvm.objc.retainBlock( + void assignment(id a) { + BlockTy b0; + (b0) = ^{ foo1(a); }; + b0(); + b0 = (^{ foo1(a); }); + b0(); + } + +// CHECK-LABEL: define void @_ZN17test_block_retain16assignmentStaticEP11objc_object( +// CHECK: @llvm.objc.retainBlock( + void assignmentStatic(id a) { + static BlockTy b0; + b0 = ^{ foo1(a); }; + b0(); + } + +// CHECK-LABEL: define void @_ZN17test_block_retain21assignmentConditionalEP11objc_objectb( +// CHECK: @llvm.objc.retainBlock( + void assignmentConditional(id a, bool c) { + BlockTy b0; + if (c) + // can't optimize this since 'b0' is declared in the outer scope. + b0 = ^{ foo1(a); }; + b0(); + } + +// CHECK-LABEL: define void @_ZN17test_block_retain11assignment2EP11objc_object( +// CHECK: %[[B0:.*]] = alloca void ()*, align 8 +// CHECK: %[[B1:.*]] = alloca void ()*, align 8 +// CHECK-NOT: @llvm.objc.retainBlock +// CHECK: store void ()* null, void ()** %[[B1]], align 8 +// CHECK: %[[V9:.*]] = load void ()*, void ()** %[[B0]], align 8 +// CHECK: %[[V10:.*]] = bitcast void ()* %[[V9]] to i8* +// CHECK: %[[V11:.*]] = call i8* @llvm.objc.retainBlock(i8* %[[V10]] +// CHECK: %[[V12:.*]] = bitcast i8* %[[V11]] to void ()* +// CHECK: store void ()* %[[V12]], void ()** %[[B1]], align 8 + void assignment2(id a) { + BlockTy b0 = ^{ foo1(a); }; + b0(); + BlockTy b1; + b1 = b0; // can't optimize this yet. + b1(); + } + +// We cannot remove the call to @llvm.objc.retainBlock if the variable is of type id. + +// CHECK: define void @_ZN17test_block_retain21initializationObjCPtrEP11objc_object( +// CHECK: alloca i8*, align 8 +// CHECK: %[[B0:.*]] = alloca i8*, align 8 +// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, align 8 +// CHECK: %[[V3:.*]] = bitcast <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]] to void ()* +// CHECK: %[[V4:.*]] = bitcast void ()* %[[V3]] to i8* +// CHECK: %[[V5:.*]] = call i8* @llvm.objc.retainBlock(i8* %[[V4]]) +// CHECK: %[[V6:.*]] = bitcast i8* %[[V5]] to void ()* +// CHECK: %[[V7:.*]] = bitcast void ()* %[[V6]] to i8* +// CHECK: store i8* %[[V7]], i8** %[[B0]], align 8 + void initializationObjCPtr(id a) { + id b0 = ^{ foo1(a); }; + ((BlockTy)b0)(); + } + +// CHECK: define void @_ZN17test_block_retain17assignmentObjCPtrEP11objc_object( +// CHECK: %[[B0:.*]] = alloca void ()*, align 8 +// CHECK: %[[B1:.*]] = alloca i8*, align 8 +// CHECK: %[[V4:.*]] = load void ()*, void ()** %[[B0]], align 8 +// CHECK: %[[V5:.*]] = bitcast void ()* %[[V4]] to i8* +// CHECK: %[[V6:.*]] = call i8* @llvm.objc.retainBlock(i8* %[[V5]]) +// CHECK: %[[V7:.*]] = bitcast i8* %[[V6]] to void ()* +// CHECK: %[[V8:.*]] = bitcast void ()* %[[V7]] to i8* +// CHECK: store i8* %[[V8]], i8** %[[B1]], align 8 + void assignmentObjCPtr(id a) { + BlockTy b0 = ^{ foo1(a); }; + id b1; + b1 = b0; + ((BlockTy)b1)(); + } +} diff --git a/clang/test/PCH/arc-blocks.mm b/clang/test/PCH/arc-blocks.mm new file mode 100644 index 00000000000..74b7e470ea5 --- /dev/null +++ b/clang/test/PCH/arc-blocks.mm @@ -0,0 +1,49 @@ +// RUN: %clang_cc1 -fobjc-arc -fblocks -std=c++1y -emit-pch %s -o %t +// RUN: %clang_cc1 -fobjc-arc -fblocks -std=c++1y -include-pch %t -emit-llvm -o - %s | FileCheck %s + +#ifndef HEADER_INCLUDED +#define HEADER_INCLUDED + +namespace test_block_retain { + typedef void (^BlockTy)(); + void foo1(id); + + inline void initialization(id a) { + // Call to @llvm.objc.retainBlock isn't needed. + BlockTy b0 = ^{ foo1(a); }; + b0(); + } + + inline void assignmentConditional(id a, bool c) { + BlockTy b0; + if (c) + // @llvm.objc.retainBlock is called since 'b0' is declared in the outer scope. + b0 = ^{ foo1(a); }; + b0(); + } +} + +#else + +// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 } + +namespace test_block_retain { +// CHECK-LABEL: define linkonce_odr void @_ZN17test_block_retain14initializationEP11objc_object( +// CHECK-NOT: call i8* @llvm.objc.retainBlock( + + void test_initialization(id a) { + initialization(a); + } + +// CHECK-LABEL: define void @_ZN17test_block_retain26test_assignmentConditionalEP11objc_objectb( +// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, align 8 +// CHECK: %[[V4:.*]] = bitcast <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]] to void ()* +// CHECK: %[[V5:.*]] = bitcast void ()* %[[V4]] to i8* +// CHECK: call i8* @llvm.objc.retainBlock(i8* %[[V5]]) + + void test_assignmentConditional(id a, bool c) { + assignmentConditional(a, c); + } +} + +#endif |

