[clang] 66c6bbe - Put code that avoids heapifying local blocks behind a flag

Walter Lee via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 14 11:06:28 PDT 2021


Author: Walter Lee
Date: 2021-09-14T14:06:05-04:00
New Revision: 66c6bbe7ff56441706d6cbb349fde9a02e248c9a

URL: https://github.com/llvm/llvm-project/commit/66c6bbe7ff56441706d6cbb349fde9a02e248c9a
DIFF: https://github.com/llvm/llvm-project/commit/66c6bbe7ff56441706d6cbb349fde9a02e248c9a.diff

LOG: Put code that avoids heapifying local blocks behind a flag

This change puts the functionality in commit
c5792aa90fa45a1842f190c146f19e2c71ea6fbd behind a flag that is off by
default.  The original commit is not in Apple's Clang fork (and blocks
are an Apple extension in the first place), and there is one known
issue that needs to be addressed before it can be enabled safely.

Differential Revision: https://reviews.llvm.org/D108243

Added: 
    

Modified: 
    clang/include/clang/Basic/CodeGenOptions.def
    clang/include/clang/Driver/Options.td
    clang/lib/CodeGen/CGObjC.cpp
    clang/test/CodeGenObjC/arc-block-copy-escape.m
    clang/test/CodeGenObjC/arc-blocks.m
    clang/test/CodeGenObjCXX/arc-blocks.mm
    clang/test/PCH/arc-blocks.mm

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index 73edae63bfc91..737d2d70bf466 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -188,6 +188,7 @@ CODEGENOPT(NoZeroInitializedInBSS , 1, 0) ///< -fno-zero-initialized-in-bss.
 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
index 6d0dba2bc5adc..6e8fe785ae04c 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2369,6 +2369,11 @@ def fobjc_disable_direct_methods_for_testing :
   Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Ignore attribute objc_direct so that direct methods can be tested">,
   MarshallingInfoFlag<LangOpts<"ObjCDisableDirectMethodsForTesting">>;
+defm objc_avoid_heapify_local_blocks : BoolFOption<"objc-avoid-heapify-local-blocks",
+  CodeGenOpts<"ObjCAvoidHeapifyLocalBlocks">, DefaultFalse,
+  PosFlag<SetTrue, [], "Try">,
+  NegFlag<SetFalse, [], "Don't try">,
+  BothFlags<[CC1Option, NoDriverOption], " to avoid heapifying local blocks">>;
 
 def fomit_frame_pointer : Flag<["-"], "fomit-frame-pointer">, Group<f_Group>;
 def fopenmp : Flag<["-"], "fopenmp">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused, FlangOption, FC1Option]>,

diff  --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp
index 0aaec9af2f41e..4eced4ec046fb 100644
--- a/clang/lib/CodeGen/CGObjC.cpp
+++ b/clang/lib/CodeGen/CGObjC.cpp
@@ -3332,7 +3332,8 @@ struct ARCRetainExprEmitter :
     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
index 9e409ce72e247..300405f852987 100644
--- 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
index ab0ee3789cba8..6fa25a0aa0857 100644
--- 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 @@ id test9(void) {
 // 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 @@ id test9(void) {
 // 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 @@ void test10b(void) {
   __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
index 2b06bf0fffebe..2f07f99df02c5 100644
--- 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 @@ void foo1() {
 
 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 @@ void initialization(id a) {
     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 @@ void initialization2(id a) {
     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 @@ void assignment(id a) {
     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 @@ void assignmentConditional(id a, bool c) {
     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 @@ void assignment2(id a) {
 
 // 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
index 28c2dde2919d6..a26b03d3a6d00 100644
--- 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


        


More information about the cfe-commits mailing list