diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -188,6 +188,7 @@ ENUM_CODEGENOPT(ObjCDispatchMethod, ObjCDispatchMethodKind, 2, Legacy) /// Replace certain message sends with calls to ObjC runtime entrypoints CODEGENOPT(ObjCConvertMessagesToRuntimeCalls , 1, 1) +CODEGENOPT(ObjCAvoidHeapifyLocalBlocks, 1, 0) VALUE_CODEGENOPT(OptimizationLevel, 2, 0) ///< The -O[0-3] option specified. VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified. diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2373,6 +2373,11 @@ Group, Flags<[CC1Option]>, HelpText<"Ignore attribute objc_direct so that direct methods can be tested">, MarshallingInfoFlag>; +defm objc_avoid_heapify_local_blocks : BoolFOption<"objc-avoid-heapify-local-blocks", + CodeGenOpts<"ObjCAvoidHeapifyLocalBlocks">, DefaultFalse, + PosFlag, + NegFlag, + BothFlags<[CC1Option], " to avoid heapifying local blocks">>; def fomit_frame_pointer : Flag<["-"], "fomit-frame-pointer">, Group; def fopenmp : Flag<["-"], "fopenmp">, Group, Flags<[CC1Option, NoArgumentUnused, FlangOption, FC1Option]>, diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -3344,7 +3344,8 @@ TryEmitResult result = visitExpr(e); // Avoid the block-retain if this is a block literal that doesn't need to be // copied to the heap. - if (e->getBlockDecl()->canAvoidCopyToHeap()) + if (CGF.CGM.getCodeGenOpts().ObjCAvoidHeapifyLocalBlocks && + e->getBlockDecl()->canAvoidCopyToHeap()) result.setInt(true); return result; } diff --git a/clang/test/CodeGenObjC/arc-block-copy-escape.m b/clang/test/CodeGenObjC/arc-block-copy-escape.m --- a/clang/test/CodeGenObjC/arc-block-copy-escape.m +++ b/clang/test/CodeGenObjC/arc-block-copy-escape.m @@ -1,4 +1,6 @@ -// RUN: %clang_cc1 -fobjc-arc -fblocks -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -fobjc-arc -fblocks -emit-llvm %s -o - | FileCheck -check-prefix=CHECK -check-prefix=CHECK-HEAP %s +// RUN: %clang_cc1 -fobjc-arc -fblocks -fobjc-avoid-heapify-local-blocks -emit-llvm %s -o - | FileCheck -check-prefix=CHECK -check-prefix=CHECK-NOHEAP %s + typedef void (^block_t)(void); void use_block(block_t); @@ -8,17 +10,19 @@ void test0(int i) { block_t block = ^{ use_int(i); }; - // CHECK-LABEL: define {{.*}}void @test0( - // CHECK-NOT: @llvm.objc.retainBlock( - // CHECK: ret void + // CHECK-LABEL: define {{.*}}void @test0( + // CHECK-HEAP: call {{.*}}i8* @llvm.objc.retainBlock(i8* {{%.*}}) [[NUW:#[0-9]+]], !clang.arc.copy_on_escape + // CHECK-NOHEAP-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:#[0-9]+]] - // CHECK-NOT: !clang.arc.copy_on_escape - // CHECK: ret void + // CHECK-HEAP: call {{.*}}i8* @llvm.objc.retainBlock(i8* {{%.*}}) [[NUW]] + // CHECK-NOHEAP: call {{.*}}i8* @llvm.objc.retainBlock(i8* {{%.*}}) [[NUW:#[0-9]+]] + // CHECK-NOT: !clang.arc.copy_on_escape + // CHECK: ret void } // CHECK: attributes [[NUW]] = { nounwind } diff --git a/clang/test/CodeGenObjC/arc-blocks.m b/clang/test/CodeGenObjC/arc-blocks.m --- a/clang/test/CodeGenObjC/arc-blocks.m +++ b/clang/test/CodeGenObjC/arc-blocks.m @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-passes -o - %s | FileCheck -check-prefix=CHECK -check-prefix=CHECK-COMMON %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-passes -o - %s | FileCheck -check-prefix=CHECK -check-prefix=CHECK-HEAP -check-prefix=CHECK-COMMON %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-passes -fobjc-avoid-heapify-local-blocks -o - %s | FileCheck -check-prefix=CHECK -check-prefix=CHECK-NOHEAP -check-prefix=CHECK-COMMON %s // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-UNOPT -check-prefix=CHECK-COMMON %s // CHECK-COMMON: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 } @@ -320,7 +321,7 @@ // CHECK-LABEL: define{{.*}} i8* @test9( // CHECK: load i8*, i8** getelementptr // CHECK-NEXT: bitcast i8* -// CHECK-NEXT: call i8* +// CHECK-NEXT: call i8* // CHECK-NEXT: tail call i8* @llvm.objc.autoreleaseReturnValue // CHECK-NEXT: ret i8* @@ -334,31 +335,35 @@ // when the initialization captures the variable. 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 + // CHECK-LABEL: define{{.*}} void @test10a() + // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]], + // CHECK-NOHEAP: [[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 + // 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: [[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 ()* [[T2]], void ()** [[T5]], align 8 - // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8* - // CHECK-NEXT: call void @llvm.objc.release(i8* [[T7]]) + // CHECK-HEAP: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8* + // CHECK-HEAP-NEXT: [[T1:%.*]] = call i8* @llvm.objc.retainBlock(i8* [[T0]]) + // CHECK-HEAP-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()* + // CHECK-NOHEAP: [[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-HEAP-NEXT: store void ()* {{%.*}}, void ()** [[T5]], align 8 + // CHECK-NOHEAP-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]]) // Destroy at end of function. - // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[BYREF]], i32 0, i32 6 - // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8* - // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8) - // CHECK-NEXT: [[T1:%.*]] = load void ()*, void ()** [[SLOT]] - // CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8* - // CHECK-NEXT: call void @llvm.objc.release(i8* [[T2]]) + // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[BYREF]], i32 0, i32 6 + // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8* + // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8) + // CHECK-NEXT: [[T1:%.*]] = load void ()*, void ()** [[SLOT]] + // CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8* + // CHECK-NEXT: call void @llvm.objc.release(i8* [[T2]]) // CHECK: ret void } @@ -396,32 +401,36 @@ __block void (^block)(void); block = ^{ block(); }; - // CHECK-LABEL: define{{.*}} void @test10b() - // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]], - // CHECK: [[BLOCK3:%.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, align 8 + // CHECK-LABEL: define{{.*}} void @test10b() + // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]], + // CHECK-NOHEAP: [[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 - // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8 + // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[BYREF]], i32 0, i32 6 + // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8 - // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[BYREF]], i32 0, i32 6 + // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[BYREF]], i32 0, i32 6 // The assignment. - // 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 ()* [[T2]], void ()** [[T5]], align 8 - // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8* - // CHECK-NEXT: call void @llvm.objc.release(i8* [[T7]]) + // CHECK-HEAP: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8* + // CHECK-HEAP-NEXT: [[T1:%.*]] = call i8* @llvm.objc.retainBlock(i8* [[T0]]) + // CHECK-HEAP-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()* + // CHECK-NOHEAP: [[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-HEAP-NEXT: store void ()* {{%.*}}, void ()** [[T5]], align 8 + // CHECK-NOHEAP-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]]) // Destroy at end of function. - // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8* - // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8) - // CHECK-NEXT: [[T1:%.*]] = load void ()*, void ()** [[SLOT]] - // CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8* - // CHECK-NEXT: call void @llvm.objc.release(i8* [[T2]]) + // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8* + // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8) + // CHECK-NEXT: [[T1:%.*]] = load void ()*, void ()** [[SLOT]] + // CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8* + // CHECK-NEXT: call void @llvm.objc.release(i8* [[T2]]) // CHECK: ret void } diff --git a/clang/test/CodeGenObjCXX/arc-blocks.mm b/clang/test/CodeGenObjCXX/arc-blocks.mm --- a/clang/test/CodeGenObjCXX/arc-blocks.mm +++ b/clang/test/CodeGenObjCXX/arc-blocks.mm @@ -1,9 +1,11 @@ // RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -fexceptions -fobjc-arc-exceptions -o - %s | FileCheck -check-prefix CHECK %s // RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -fexceptions -fobjc-arc-exceptions -O1 -o - %s | FileCheck -check-prefix CHECK-O1 %s // RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -o - %s | FileCheck -check-prefix CHECK-NOEXCP %s +// RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -fexceptions -fobjc-arc-exceptions -fobjc-avoid-heapify-local-blocks -o - %s | FileCheck -check-prefix CHECK-NOHEAP %s // CHECK: [[A:.*]] = type { i64, [10 x i8*] } // CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 } +// CHECK-NOHEAP: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 } // CHECK: %[[STRUCT_TEST1_S0:.*]] = type { i32 } // CHECK: %[[STRUCT_TRIVIAL_INTERNAL:.*]] = type { i32 } @@ -209,8 +211,8 @@ namespace test_block_retain { -// CHECK-LABEL: define{{.*}} void @_ZN17test_block_retain14initializationEP11objc_object( -// CHECK-NOT: @llvm.objc.retainBlock( +// CHECK-NOHEAP-LABEL: define{{.*}} void @_ZN17test_block_retain14initializationEP11objc_object( +// CHECK-NOHEAP-NOT: @llvm.objc.retainBlock( void initialization(id a) { BlockTy b0 = ^{ foo1(a); }; BlockTy b1 = (^{ foo1(a); }); @@ -218,23 +220,23 @@ b1(); } -// CHECK-LABEL: define{{.*}} void @_ZN17test_block_retain20initializationStaticEP11objc_object( -// CHECK: @llvm.objc.retainBlock( +// CHECK-NOHEAP-LABEL: define{{.*}} void @_ZN17test_block_retain20initializationStaticEP11objc_object( +// CHECK-NOHEAP: @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 +// CHECK-NOHEAP-LABEL: define{{.*}} void @_ZN17test_block_retain15initialization2EP11objc_object +// CHECK-NOHEAP: %[[B0:.*]] = alloca void ()*, align 8 +// CHECK-NOHEAP: %[[B1:.*]] = alloca void ()*, align 8 +// CHECK-NOHEAP: load void ()*, void ()** %[[B0]], align 8 +// CHECK-NOHEAP-NOT: @llvm.objc.retainBlock +// CHECK-NOHEAP: %[[V9:.*]] = load void ()*, void ()** %[[B0]], align 8 +// CHECK-NOHEAP: %[[V10:.*]] = bitcast void ()* %[[V9]] to i8* +// CHECK-NOHEAP: %[[V11:.*]] = call i8* @llvm.objc.retainBlock(i8* %[[V10]]) +// CHECK-NOHEAP: %[[V12:.*]] = bitcast i8* %[[V11]] to void ()* +// CHECK-NOHEAP: store void ()* %[[V12]], void ()** %[[B1]], align 8 void initialization2(id a) { BlockTy b0 = ^{ foo1(a); }; b0(); @@ -242,8 +244,8 @@ b1(); } -// CHECK-LABEL: define{{.*}} void @_ZN17test_block_retain10assignmentEP11objc_object( -// CHECK-NOT: @llvm.objc.retainBlock( +// CHECK-NOHEAP-LABEL: define{{.*}} void @_ZN17test_block_retain10assignmentEP11objc_object( +// CHECK-NOHEAP-NOT: @llvm.objc.retainBlock( void assignment(id a) { BlockTy b0; (b0) = ^{ foo1(a); }; @@ -252,16 +254,16 @@ b0(); } -// CHECK-LABEL: define{{.*}} void @_ZN17test_block_retain16assignmentStaticEP11objc_object( -// CHECK: @llvm.objc.retainBlock( +// CHECK-NOHEAP-LABEL: define{{.*}} void @_ZN17test_block_retain16assignmentStaticEP11objc_object( +// CHECK-NOHEAP: @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( +// CHECK-NOHEAP-LABEL: define{{.*}} void @_ZN17test_block_retain21assignmentConditionalEP11objc_objectb( +// CHECK-NOHEAP: @llvm.objc.retainBlock( void assignmentConditional(id a, bool c) { BlockTy b0; if (c) @@ -270,16 +272,16 @@ 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 +// CHECK-NOHEAP-LABEL: define{{.*}} void @_ZN17test_block_retain11assignment2EP11objc_object( +// CHECK-NOHEAP: %[[B0:.*]] = alloca void ()*, align 8 +// CHECK-NOHEAP: %[[B1:.*]] = alloca void ()*, align 8 +// CHECK-NOHEAP-NOT: @llvm.objc.retainBlock +// CHECK-NOHEAP: store void ()* null, void ()** %[[B1]], align 8 +// CHECK-NOHEAP: %[[V9:.*]] = load void ()*, void ()** %[[B0]], align 8 +// CHECK-NOHEAP: %[[V10:.*]] = bitcast void ()* %[[V9]] to i8* +// CHECK-NOHEAP: %[[V11:.*]] = call i8* @llvm.objc.retainBlock(i8* %[[V10]] +// CHECK-NOHEAP: %[[V12:.*]] = bitcast i8* %[[V11]] to void ()* +// CHECK-NOHEAP: store void ()* %[[V12]], void ()** %[[B1]], align 8 void assignment2(id a) { BlockTy b0 = ^{ foo1(a); }; b0(); @@ -290,30 +292,30 @@ // 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 +// CHECK-NOHEAP: define{{.*}} void @_ZN17test_block_retain21initializationObjCPtrEP11objc_object( +// CHECK-NOHEAP: alloca i8*, align 8 +// CHECK-NOHEAP: %[[B0:.*]] = alloca i8*, align 8 +// CHECK-NOHEAP: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, align 8 +// CHECK-NOHEAP: %[[V3:.*]] = bitcast <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]] to void ()* +// CHECK-NOHEAP: %[[V4:.*]] = bitcast void ()* %[[V3]] to i8* +// CHECK-NOHEAP: %[[V5:.*]] = call i8* @llvm.objc.retainBlock(i8* %[[V4]]) +// CHECK-NOHEAP: %[[V6:.*]] = bitcast i8* %[[V5]] to void ()* +// CHECK-NOHEAP: %[[V7:.*]] = bitcast void ()* %[[V6]] to i8* +// CHECK-NOHEAP: 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 +// CHECK-NOHEAP: define{{.*}} void @_ZN17test_block_retain17assignmentObjCPtrEP11objc_object( +// CHECK-NOHEAP: %[[B0:.*]] = alloca void ()*, align 8 +// CHECK-NOHEAP: %[[B1:.*]] = alloca i8*, align 8 +// CHECK-NOHEAP: %[[V4:.*]] = load void ()*, void ()** %[[B0]], align 8 +// CHECK-NOHEAP: %[[V5:.*]] = bitcast void ()* %[[V4]] to i8* +// CHECK-NOHEAP: %[[V6:.*]] = call i8* @llvm.objc.retainBlock(i8* %[[V5]]) +// CHECK-NOHEAP: %[[V7:.*]] = bitcast i8* %[[V6]] to void ()* +// CHECK-NOHEAP: %[[V8:.*]] = bitcast void ()* %[[V7]] to i8* +// CHECK-NOHEAP: store i8* %[[V8]], i8** %[[B1]], align 8 void assignmentObjCPtr(id a) { BlockTy b0 = ^{ foo1(a); }; id b1; diff --git a/clang/test/PCH/arc-blocks.mm b/clang/test/PCH/arc-blocks.mm --- a/clang/test/PCH/arc-blocks.mm +++ b/clang/test/PCH/arc-blocks.mm @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-arc -fblocks -std=c++1y -emit-pch %s -o %t -// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-arc -fblocks -std=c++1y -include-pch %t -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-arc -fblocks -std=c++1y -include-pch %t -fobjc-avoid-heapify-local-blocks -emit-llvm -o - %s | FileCheck %s #ifndef HEADER_INCLUDED #define HEADER_INCLUDED