[PATCH] D49303: [CodeGen][ObjC] Treat non-escaping blocks as global blocks to make copy/dispose a no-op

2022-07-25 Thread John McCall via Phabricator via cfe-commits
rjmccall added a comment.

Blocks that don't capture anything have always been allocated globally.  This 
optimization is using the global ISA for blocks that do capture locals but 
which are known statically (on penalty of UB) to not escape the original scope 
of the block literal.  Using the global ISA causes attempts to copy these 
blocks to have no effect, in case the program attempts to do unnecessary copies 
despite the block being declared non-escaping.


Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D49303/new/

https://reviews.llvm.org/D49303

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49303: [CodeGen][ObjC] Treat non-escaping blocks as global blocks to make copy/dispose a no-op

2022-07-25 Thread Jake Li via Phabricator via cfe-commits
jajadude added a comment.
Herald added a project: All.

@ahatanak @rjmccall  What if a block is marked with `noescape` and captures 
some variables at the same time?  Wouldn't that cause problem If the compiler 
continues to optimize it to `NSConcreteGlobal` type anyway?


Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D49303/new/

https://reviews.llvm.org/D49303

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49303: [CodeGen][ObjC] Treat non-escaping blocks as global blocks to make copy/dispose a no-op

2018-07-20 Thread Akira Hatanaka via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
ahatanak marked an inline comment as done.
Closed by commit rL337580: [CodeGen][ObjC] Make copying and disposing of a 
non-escaping block (authored by ahatanak, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D49303?vs=156404&id=156530#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D49303

Files:
  cfe/trunk/docs/Block-ABI-Apple.rst
  cfe/trunk/lib/CodeGen/CGBlocks.cpp
  cfe/trunk/lib/CodeGen/CGBlocks.h
  cfe/trunk/test/CodeGenObjC/noescape.m

Index: cfe/trunk/test/CodeGenObjC/noescape.m
===
--- cfe/trunk/test/CodeGenObjC/noescape.m
+++ cfe/trunk/test/CodeGenObjC/noescape.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -o - %s | FileCheck -check-prefix CHECK -check-prefix CHECK-NOARC %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -fobjc-arc -o - %s | FileCheck -check-prefix CHECK -check-prefix CHECK-ARC %s
 
 typedef void (^BlockTy)(void);
 
@@ -12,6 +13,12 @@
 void noescapeFunc2(__attribute__((noescape)) id);
 void noescapeFunc3(__attribute__((noescape)) union U);
 
+// Block descriptors of non-escaping blocks don't need pointers to copy/dispose
+// helper functions.
+
+// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
+// CHECK: @[[BLOCK_DESCIPTOR_TMP_2:.*]] = internal constant { i64, i64, i8*, i64 } { i64 0, i64 40, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
+
 // CHECK-LABEL: define void @test0(
 // CHECK: call void @noescapeFunc0({{.*}}, {{.*}} nocapture {{.*}})
 // CHECK: declare void @noescapeFunc0(i8*, {{.*}} nocapture)
@@ -69,3 +76,41 @@
   ^(int *__attribute__((noescape)) p0){}(p);
   b(p);
 }
+
+// If the block is non-escaping, set the BLOCK_IS_NOESCAPE and BLOCK_IS_GLOBAL
+// bits of field 'flags' and set the 'isa' field to 'NSConcreteGlobalBlock'.
+
+// CHECK: define void @test6(i8* %{{.*}}, i8* %[[B:.*]])
+// CHECK: %{{.*}} = alloca i8*, align 8
+// CHECK: %[[B_ADDR:.*]] = alloca i8*, align 8
+// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, align 8
+// CHECK-NOARC: store i8* %[[B]], i8** %[[B_ADDR]], align 8
+// CHECK-ARC: store i8* null, i8** %[[B_ADDR]], align 8
+// CHECK-ARC: call void @objc_storeStrong(i8** %[[B_ADDR]], i8* %[[B]])
+// CHECK-ARC: %[[V0:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 5
+// CHECK: %[[BLOCK_ISA:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 0
+// CHECK: store i8* bitcast (i8** @_NSConcreteGlobalBlock to i8*), i8** %[[BLOCK_ISA]], align 8
+// CHECK: %[[BLOCK_FLAGS:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 1
+// CHECK: store i32 -796917760, i32* %[[BLOCK_FLAGS]], align 8
+// CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 4
+// CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i64 }* @[[BLOCK_DESCIPTOR_TMP_2]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
+// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 5
+// CHECK-NOARC: %[[V1:.*]] = load i8*, i8** %[[B_ADDR]], align 8
+// CHECK-NOARC: store i8* %[[V1]], i8** %[[BLOCK_CAPTURED]], align 8
+// CHECK-ARC: %[[V2:.*]] = load i8*, i8** %[[B_ADDR]], align 8
+// CHECK-ARC: %[[V3:.*]] = call i8* @objc_retain(i8* %[[V2]]) #3
+// CHECK-ARC: store i8* %[[V3]], i8** %[[BLOCK_CAPTURED]], align 8
+// CHECK: call void @noescapeFunc0(
+// CHECK-ARC: call void @objc_storeStrong(i8** %[[V0]], i8* null)
+// CHECK-ARC: call void @objc_storeStrong(i8** %[[B_ADDR]], i8* null)
+
+// Non-escaping blocks don't need copy/dispose helper functions.
+
+// CHECK-NOT: define internal void @__copy_helper_block_
+// CHECK-NOT: define internal void @__destroy_helper_block_
+
+void func(id);
+
+void test6(id a, id b) {
+  noescapeFunc0(a, ^{ func(b); });
+}
Index: cfe/trunk/lib/CodeGen/CGBlocks.h
===
--- cfe/trunk/lib/CodeGen/CGBlocks.h
+++ cfe/trunk/lib/CodeGen/CGBlocks.h
@@ -54,6 +54,7 @@
 };
 
 enum BlockLiteralFlags {
+  BLOCK_IS_NOESCAPE  =  (1 << 23),
 

[PATCH] D49303: [CodeGen][ObjC] Treat non-escaping blocks as global blocks to make copy/dispose a no-op

2018-07-19 Thread John McCall via Phabricator via cfe-commits
rjmccall accepted this revision.
rjmccall added a comment.
This revision is now accepted and ready to land.

Thanks.  A couple tiny things and then LGTM.




Comment at: docs/Block-ABI-Apple.rst:69
+// block is a no-op, which is exactly how global blocks are handled.
+
+BLOCK_IS_NOESCAPE  =  (1 << 23),

Thanks, that looks good.  I think it's important to emphasize that setting 
`BLOCK_IS_GLOBAL` is necessary *for backward compatibility*, though.

You have a newline between the comment and BLOCK_IS_NOESCAPE that feels 
out-of-place.


Repository:
  rC Clang

https://reviews.llvm.org/D49303



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49303: [CodeGen][ObjC] Treat non-escaping blocks as global blocks to make copy/dispose a no-op

2018-07-19 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 156404.
ahatanak marked 2 inline comments as done.
ahatanak added a comment.

Add a comment that explains the meaning of BLOCK_IS_NOESCAPE to the docs. 
Rename function needsCopyDispose to needsCopyDisposeHelpers.


Repository:
  rC Clang

https://reviews.llvm.org/D49303

Files:
  docs/Block-ABI-Apple.rst
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGBlocks.h
  test/CodeGenObjC/noescape.m

Index: test/CodeGenObjC/noescape.m
===
--- test/CodeGenObjC/noescape.m
+++ test/CodeGenObjC/noescape.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -o - %s | FileCheck -check-prefix CHECK -check-prefix CHECK-NOARC %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -fobjc-arc -o - %s | FileCheck -check-prefix CHECK -check-prefix CHECK-ARC %s
 
 typedef void (^BlockTy)(void);
 
@@ -12,6 +13,12 @@
 void noescapeFunc2(__attribute__((noescape)) id);
 void noescapeFunc3(__attribute__((noescape)) union U);
 
+// Block descriptors of non-escaping blocks don't need pointers to copy/dispose
+// helper functions.
+
+// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
+// CHECK: @[[BLOCK_DESCIPTOR_TMP_2:.*]] = internal constant { i64, i64, i8*, i64 } { i64 0, i64 40, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
+
 // CHECK-LABEL: define void @test0(
 // CHECK: call void @noescapeFunc0({{.*}}, {{.*}} nocapture {{.*}})
 // CHECK: declare void @noescapeFunc0(i8*, {{.*}} nocapture)
@@ -69,3 +76,41 @@
   ^(int *__attribute__((noescape)) p0){}(p);
   b(p);
 }
+
+// If the block is non-escaping, set the BLOCK_IS_NOESCAPE and BLOCK_IS_GLOBAL
+// bits of field 'flags' and set the 'isa' field to 'NSConcreteGlobalBlock'.
+
+// CHECK: define void @test6(i8* %{{.*}}, i8* %[[B:.*]])
+// CHECK: %{{.*}} = alloca i8*, align 8
+// CHECK: %[[B_ADDR:.*]] = alloca i8*, align 8
+// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, align 8
+// CHECK-NOARC: store i8* %[[B]], i8** %[[B_ADDR]], align 8
+// CHECK-ARC: store i8* null, i8** %[[B_ADDR]], align 8
+// CHECK-ARC: call void @objc_storeStrong(i8** %[[B_ADDR]], i8* %[[B]])
+// CHECK-ARC: %[[V0:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 5
+// CHECK: %[[BLOCK_ISA:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 0
+// CHECK: store i8* bitcast (i8** @_NSConcreteGlobalBlock to i8*), i8** %[[BLOCK_ISA]], align 8
+// CHECK: %[[BLOCK_FLAGS:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 1
+// CHECK: store i32 -796917760, i32* %[[BLOCK_FLAGS]], align 8
+// CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 4
+// CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i64 }* @[[BLOCK_DESCIPTOR_TMP_2]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
+// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 5
+// CHECK-NOARC: %[[V1:.*]] = load i8*, i8** %[[B_ADDR]], align 8
+// CHECK-NOARC: store i8* %[[V1]], i8** %[[BLOCK_CAPTURED]], align 8
+// CHECK-ARC: %[[V2:.*]] = load i8*, i8** %[[B_ADDR]], align 8
+// CHECK-ARC: %[[V3:.*]] = call i8* @objc_retain(i8* %[[V2]]) #3
+// CHECK-ARC: store i8* %[[V3]], i8** %[[BLOCK_CAPTURED]], align 8
+// CHECK: call void @noescapeFunc0(
+// CHECK-ARC: call void @objc_storeStrong(i8** %[[V0]], i8* null)
+// CHECK-ARC: call void @objc_storeStrong(i8** %[[B_ADDR]], i8* null)
+
+// Non-escaping blocks don't need copy/dispose helper functions.
+
+// CHECK-NOT: define internal void @__copy_helper_block_
+// CHECK-NOT: define internal void @__destroy_helper_block_
+
+void func(id);
+
+void test6(id a, id b) {
+  noescapeFunc0(a, ^{ func(b); });
+}
Index: lib/CodeGen/CGBlocks.h
===
--- lib/CodeGen/CGBlocks.h
+++ lib/CodeGen/CGBlocks.h
@@ -54,6 +54,7 @@
 };
 
 enum BlockLiteralFlags {
+  BLOCK_IS_NOESCAPE  =  (1 << 23),
   BLOCK_HAS_COPY_DISPOSE =  (1 << 25),
   BLOCK_HAS_CXX_OBJ =   (1 << 26),
   BLOCK_IS_GLOBAL = (1 << 28),
@@ -214,7 +215,8 @@
   /// no non-constant captures.
   bool CanBeGlobal : 1;
 
-  /// True if the blo

[PATCH] D49303: [CodeGen][ObjC] Treat non-escaping blocks as global blocks to make copy/dispose a no-op

2018-07-19 Thread John McCall via Phabricator via cfe-commits
rjmccall added inline comments.



Comment at: docs/Block-ABI-Apple.rst:64
 enum {
+BLOCK_IS_NOESCAPE  =  (1 << 23),
 BLOCK_HAS_COPY_DISPOSE =  (1 << 25),

Something happened to my older comments here, but please document the meaning 
of this flag.  Specifically, it is set on blocks that do have captures (and 
thus are not true global blocks) but which are known not to escape for various 
other reasons.  Please include the fact that it implies `BLOCK_IS_GLOBAL` and 
explain why.



Comment at: lib/CodeGen/CGBlocks.h:283
+  // Indicates whether the block needs a custom copy or dispose function.
+  bool needsCopyDispose() const {
+return NeedsCopyDispose && !Block->doesNotEscape();

Please rename this to `needsCopyDisposeHelpers()` to make it clearer that it's 
specifically about the need for the functions.


Repository:
  rC Clang

https://reviews.llvm.org/D49303



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49303: [CodeGen][ObjC] Treat non-escaping blocks as global blocks to make copy/dispose a no-op

2018-07-19 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 156332.
ahatanak added a comment.

Fix a bug where the capture cleanups weren't pushed when 
BlockDecl::doesNotEscape() returns true.

Test that, when ARC is enabled, captures are retained and copied into the stack 
block object and destroyed when the stack block object goes out of scope.


Repository:
  rC Clang

https://reviews.llvm.org/D49303

Files:
  docs/Block-ABI-Apple.rst
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGBlocks.h
  test/CodeGenObjC/noescape.m

Index: test/CodeGenObjC/noescape.m
===
--- test/CodeGenObjC/noescape.m
+++ test/CodeGenObjC/noescape.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -o - %s | FileCheck -check-prefix CHECK -check-prefix CHECK-NOARC %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -fobjc-arc -o - %s | FileCheck -check-prefix CHECK -check-prefix CHECK-ARC %s
 
 typedef void (^BlockTy)(void);
 
@@ -12,6 +13,12 @@
 void noescapeFunc2(__attribute__((noescape)) id);
 void noescapeFunc3(__attribute__((noescape)) union U);
 
+// Block descriptors of non-escaping blocks don't need pointers to copy/dispose
+// helper functions.
+
+// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
+// CHECK: @[[BLOCK_DESCIPTOR_TMP_2:.*]] = internal constant { i64, i64, i8*, i64 } { i64 0, i64 40, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
+
 // CHECK-LABEL: define void @test0(
 // CHECK: call void @noescapeFunc0({{.*}}, {{.*}} nocapture {{.*}})
 // CHECK: declare void @noescapeFunc0(i8*, {{.*}} nocapture)
@@ -69,3 +76,41 @@
   ^(int *__attribute__((noescape)) p0){}(p);
   b(p);
 }
+
+// If the block is non-escaping, set the BLOCK_IS_NOESCAPE and BLOCK_IS_GLOBAL
+// bits of field 'flags' and set the 'isa' field to 'NSConcreteGlobalBlock'.
+
+// CHECK: define void @test6(i8* %{{.*}}, i8* %[[B:.*]])
+// CHECK: %{{.*}} = alloca i8*, align 8
+// CHECK: %[[B_ADDR:.*]] = alloca i8*, align 8
+// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, align 8
+// CHECK-NOARC: store i8* %[[B]], i8** %[[B_ADDR]], align 8
+// CHECK-ARC: store i8* null, i8** %[[B_ADDR]], align 8
+// CHECK-ARC: call void @objc_storeStrong(i8** %[[B_ADDR]], i8* %[[B]])
+// CHECK-ARC: %[[V0:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 5
+// CHECK: %[[BLOCK_ISA:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 0
+// CHECK: store i8* bitcast (i8** @_NSConcreteGlobalBlock to i8*), i8** %[[BLOCK_ISA]], align 8
+// CHECK: %[[BLOCK_FLAGS:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 1
+// CHECK: store i32 -796917760, i32* %[[BLOCK_FLAGS]], align 8
+// CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 4
+// CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i64 }* @[[BLOCK_DESCIPTOR_TMP_2]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
+// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 5
+// CHECK-NOARC: %[[V1:.*]] = load i8*, i8** %[[B_ADDR]], align 8
+// CHECK-NOARC: store i8* %[[V1]], i8** %[[BLOCK_CAPTURED]], align 8
+// CHECK-ARC: %[[V2:.*]] = load i8*, i8** %[[B_ADDR]], align 8
+// CHECK-ARC: %[[V3:.*]] = call i8* @objc_retain(i8* %[[V2]]) #3
+// CHECK-ARC: store i8* %[[V3]], i8** %[[BLOCK_CAPTURED]], align 8
+// CHECK: call void @noescapeFunc0(
+// CHECK-ARC: call void @objc_storeStrong(i8** %[[V0]], i8* null)
+// CHECK-ARC: call void @objc_storeStrong(i8** %[[B_ADDR]], i8* null)
+
+// Non-escaping blocks don't need copy/dispose helper functions.
+
+// CHECK-NOT: define internal void @__copy_helper_block_
+// CHECK-NOT: define internal void @__destroy_helper_block_
+
+void func(id);
+
+void test6(id a, id b) {
+  noescapeFunc0(a, ^{ func(b); });
+}
Index: lib/CodeGen/CGBlocks.h
===
--- lib/CodeGen/CGBlocks.h
+++ lib/CodeGen/CGBlocks.h
@@ -54,6 +54,7 @@
 };
 
 enum BlockLiteralFlags {
+  BLOCK_IS_NOESCAPE  =  (1 << 23),
   BLOCK_HAS_COPY_DISPOSE =  (1 << 25),
   BLOCK_HAS_CXX_OBJ =   (1 << 26),
   BLOCK_IS_GLOBAL = (1 << 28),
@@ -214,7 +215,8 @@
   ///

[PATCH] D49303: [CodeGen][ObjC] Treat non-escaping blocks as global blocks to make copy/dispose a no-op

2018-07-18 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak planned changes to this revision.
ahatanak added a comment.

In https://reviews.llvm.org/D49303#1165902, @rjmccall wrote:

> Please test that we still copy captures correctly into the block object and 
> destroy them when the block object is destroyed.


There is a bug in my patch where the capture cleanups aren't pushed when 
doesNotEscape() returns true. I'm working on a fix.


Repository:
  rC Clang

https://reviews.llvm.org/D49303



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49303: [CodeGen][ObjC] Treat non-escaping blocks as global blocks to make copy/dispose a no-op

2018-07-17 Thread John McCall via Phabricator via cfe-commits
rjmccall added a comment.

Please test that we still copy captures correctly into the block object and 
destroy them when the block object is destroyed.

For the sorts of ephemeral blocks that we currently mark non-escaping, we can 
think about optimizing that away, too, but for now please test that we still 
perform captures normally.


Repository:
  rC Clang

https://reviews.llvm.org/D49303



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49303: [CodeGen][ObjC] Treat non-escaping blocks as global blocks to make copy/dispose a no-op

2018-07-13 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak created this revision.
ahatanak added a reviewer: rjmccall.
Herald added a subscriber: dexonsmith.

Copying or disposing of a non-escaping block can be a no-op. A non-escaping 
block on the stack doesn't have to be copied to the heap as we know it won't be 
called after its lifetime ends.

rdar://problem/39352313


Repository:
  rC Clang

https://reviews.llvm.org/D49303

Files:
  docs/Block-ABI-Apple.rst
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGBlocks.h
  test/CodeGenObjC/noescape.m

Index: test/CodeGenObjC/noescape.m
===
--- test/CodeGenObjC/noescape.m
+++ test/CodeGenObjC/noescape.m
@@ -12,6 +12,12 @@
 void noescapeFunc2(__attribute__((noescape)) id);
 void noescapeFunc3(__attribute__((noescape)) union U);
 
+// Block descriptors of non-escaping blocks don't need pointers to copy/dispose
+// helper functions.
+
+// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
+// CHECK: @[[BLOCK_DESCIPTOR_TMP_2:.*]] = internal constant { i64, i64, i8*, i64 } { i64 0, i64 40, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
+
 // CHECK-LABEL: define void @test0(
 // CHECK: call void @noescapeFunc0({{.*}}, {{.*}} nocapture {{.*}})
 // CHECK: declare void @noescapeFunc0(i8*, {{.*}} nocapture)
@@ -69,3 +75,26 @@
   ^(int *__attribute__((noescape)) p0){}(p);
   b(p);
 }
+
+// If the block is non-escaping, set the BLOCK_IS_NOESCAPE and BLOCK_IS_GLOBAL
+// bits of field 'flags' and set the 'isa' field to 'NSConcreteGlobalBlock'.
+
+// CHECK-LABEL: define void @test6(
+// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, align 8
+// CHECK: %[[BLOCK_ISA:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 0
+// CHECK: store i8* bitcast (i8** @_NSConcreteGlobalBlock to i8*), i8** %[[BLOCK_ISA]], align 8
+// CHECK: %[[BLOCK_FLAGS:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 1
+// CHECK: store i32 -796917760, i32* %[[BLOCK_FLAGS]], align 8
+// CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 4
+// CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i64 }* @[[BLOCK_DESCIPTOR_TMP_2]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
+
+// Non-escaping blocks don't need copy/dispose helper functions.
+
+// CHECK-NOT: define internal void @__copy_helper_block_
+// CHECK-NOT: define internal void @__destroy_helper_block_
+
+void func(id);
+
+void test6(id a, id b) {
+  noescapeFunc0(a, ^{ func(b); });
+}
Index: lib/CodeGen/CGBlocks.h
===
--- lib/CodeGen/CGBlocks.h
+++ lib/CodeGen/CGBlocks.h
@@ -54,6 +54,7 @@
 };
 
 enum BlockLiteralFlags {
+  BLOCK_IS_NOESCAPE  =  (1 << 23),
   BLOCK_HAS_COPY_DISPOSE =  (1 << 25),
   BLOCK_HAS_CXX_OBJ =   (1 << 26),
   BLOCK_IS_GLOBAL = (1 << 28),
Index: lib/CodeGen/CGBlocks.cpp
===
--- lib/CodeGen/CGBlocks.cpp
+++ lib/CodeGen/CGBlocks.cpp
@@ -159,6 +159,7 @@
 
 /// These are the flags (with corresponding bit number) that the
 /// compiler is actually supposed to know about.
+///  23. BLOCK_IS_NOESCAPE - indicates that the block is non-escaping
 ///  25. BLOCK_HAS_COPY_DISPOSE - indicates that the block
 ///   descriptor provides copy and dispose helper functions
 ///  26. BLOCK_HAS_CXX_OBJ - indicates that there's a captured
@@ -496,6 +497,9 @@
 BlockLayoutChunk(align, size, lifetime, &CI, llvmType, VT));
   }
 
+  if (info.getBlockDecl()->doesNotEscape())
+info.NeedsCopyDispose = false;
+
   // If that was everything, we're done here.
   if (layout.empty()) {
 info.StructureType =
@@ -778,8 +782,14 @@
   llvm::Constant *descriptor;
   BlockFlags flags;
   if (!IsOpenCL) {
-isa = llvm::ConstantExpr::getBitCast(CGM.getNSConcreteStackBlock(),
- VoidPtrTy);
+// If the block is non-escaping, set field 'isa 'to NSConcreteGlobalBlock
+// and set the BLOCK_IS_GLOBAL bit of field 'flags' so that copying and
+// disposing of blocks become no-ops.
+
+llvm::Constant *blockISA = blockInfo.getBlockDecl()->doesNotEscape()
+   ? CGM.getNSConcreteGlobalBlock()
+   : CGM.getNSConcreteStackBlock();
+isa = llvm::ConstantExpr::getBitCast(blockISA, VoidPtrTy);
 
 // Build the block descriptor.
 descriptor = buildBlockDescriptor(CGM, blockInfo);
@@ -794,6 +804,8 @@
   fla