ahatanak created this revision.
ahatanak added reviewers: rjmccall, arphaman.
Herald added a subscriber: dexonsmith.

Currently, clang generates a new block descriptor global variable for each 
block literal. This patch merges block descriptors that are identical inside 
and across translation units using the same approach taken in r339438.

To enable merging identical block descriptors, the information of each member 
of a block descriptor is encoded into the block descriptor name. Also, the 
linkage of the block descriptor is `linkonce_odr` unless the copy or dispose 
helper is internal.


Repository:
  rC Clang

https://reviews.llvm.org/D50783

Files:
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGObjCGNU.cpp
  lib/CodeGen/CGObjCMac.cpp
  lib/CodeGen/CGObjCRuntime.h
  test/CodeGenCXX/blocks.cpp
  test/CodeGenObjC/arc-blocks.m
  test/CodeGenObjC/fragile-arc.m
  test/CodeGenObjC/noescape.m

Index: test/CodeGenObjC/noescape.m
===================================================================
--- test/CodeGenObjC/noescape.m
+++ test/CodeGenObjC/noescape.m
@@ -17,7 +17,7 @@
 // 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: @[[BLOCK_DESCIPTOR_TMP_2:.*]] = linkonce_odr hidden 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 {{.*}})
Index: test/CodeGenObjC/fragile-arc.m
===================================================================
--- test/CodeGenObjC/fragile-arc.m
+++ test/CodeGenObjC/fragile-arc.m
@@ -126,13 +126,13 @@
 extern void useBlock(void (^block)(void));
 
 //  256 == 0x100 == starts with 1 strong
-// GLOBALS: @__block_descriptor_tmp{{.*}} = internal constant {{.*}}, i32 256 }
+// GLOBALS: @"__block_descriptor{{.*}} = linkonce_odr hidden {{.*}}, i32 256 }
 void testBlockLayoutStrong(id x) {
   useBlock(^{ (void) x; });
 }
 
 //  1   == 0x001 == starts with 1 weak
-// GLOBALS: @__block_descriptor_tmp{{.*}} = internal constant {{.*}}, i32 1 }
+// GLOBALS: @"__block_descriptor{{.*}} = linkonce_odr hidden {{.*}}, i32 1 }
 void testBlockLayoutWeak(__weak id x) {
   useBlock(^{ (void) x; });
 }
Index: test/CodeGenObjC/arc-blocks.m
===================================================================
--- test/CodeGenObjC/arc-blocks.m
+++ test/CodeGenObjC/arc-blocks.m
@@ -2,15 +2,10 @@
 // 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 }
-// CHECK-COMMON: @{{.*}} = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32r to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32r to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 16 }, align 8
-// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP9:.*]] = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32r to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32r to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 16 }, align 8
-// CHECK-COMMON: @{{.*}} = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32s to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
-// CHECK-COMMON: @{{.*}} = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32s to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
-// CHECK-COMMON: @{{.*}} = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32s to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
-// CHECK-COMMON: @{{.*}} = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32s to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
-// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP44:.*]] = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32s to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
-// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP46:.*]] = internal constant { i64, i64, i8*, i8*, i8*, i8* } { i64 0, i64 48, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32s to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @{{.*}}, i32 0, i32 0) }, align 8
-// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP48:.*]] = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32b to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.47, i32 0, i32 0), i64 256 }, align 8
+// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP44:.*]] = linkonce_odr hidden constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32s to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
+// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP9:.*]] = linkonce_odr hidden constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32r to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32r to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 16 }, align 8
+// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP46:.*]] = linkonce_odr hidden constant { i64, i64, i8*, i8*, i8*, i8* } { i64 0, i64 48, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32s to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @{{.*}}, i32 0, i32 0) }, align 8
+// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP48:.*]] = linkonce_odr hidden constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32b to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([9 x i8], [9 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
 
 // This shouldn't crash.
 void test0(id (^maker)(void)) {
Index: test/CodeGenCXX/blocks.cpp
===================================================================
--- test/CodeGenCXX/blocks.cpp
+++ test/CodeGenCXX/blocks.cpp
@@ -1,5 +1,8 @@
 // RUN: %clang_cc1 %s -fblocks -triple x86_64-apple-darwin -emit-llvm -o - | FileCheck %s
 
+// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
+// CHECK: @[[BLOCK_DESCRIPTOR22:.*]] = internal constant { i64, i64, i8*, i8*, i8*, i8* } { i64 0, i64 36, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32c22_ZTSN12_GLOBAL__N_11BE to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32c22_ZTSN12_GLOBAL__N_11BE to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i8* null }, align 8
+
 namespace test0 {
   // CHECK-LABEL: define void @_ZN5test04testEi(
   // CHECK: define internal void @___ZN5test04testEi_block_invoke{{.*}}(
@@ -122,7 +125,7 @@
   // CHECK-LABEL: define internal void @___ZN5test44testEv_block_invoke
   // CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align 1
   // CHECK-NEXT: store i8* [[BLOCKDESC:%.*]], i8** {{.*}}, align 8
-  // CHECK-NEXT: bitcast i8* [[BLOCKDESC]] to <{ i8*, i32, i32, i8*, %struct.__block_descriptor* }>*
+  // CHECK-NEXT: bitcast i8* [[BLOCKDESC]] to <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]* }>*
   // CHECK:      call void @_ZN5test41AC1Ev([[A]]* [[TMP]])
   // CHECK-NEXT: call void @_ZN5test43fooENS_1AE([[A]]* [[TMP]])
   // CHECK-NEXT: call void @_ZN5test41AD1Ev([[A]]* [[TMP]])
@@ -277,8 +280,11 @@
   }
 }
 
-// Copy/dispose helper functions that capture objects of non-external types
-// should have internal linkage.
+// Copy/dispose helper functions and block descriptors of blocks that capture
+// objects that are non-external and non-trivial have internal linkage.
+
+// CHECK-LABEL: define internal void @_ZN12_GLOBAL__N_14testEv(
+// CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i8*, i8*, i8* }* @[[BLOCK_DESCRIPTOR22]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %{{.*}}, align 8
 
 // CHECK-LABEL: define internal void @__copy_helper_block_8_32c22_ZTSN12_GLOBAL__N_11BE(
 // CHECK-LABEL: define internal void @__destroy_helper_block_8_32c22_ZTSN12_GLOBAL__N_11BE(
Index: lib/CodeGen/CGObjCRuntime.h
===================================================================
--- lib/CodeGen/CGObjCRuntime.h
+++ lib/CodeGen/CGObjCRuntime.h
@@ -277,7 +277,8 @@
   virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM,
                                   const CodeGen::CGBlockInfo &blockInfo) = 0;
   virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM,
-                                  const CodeGen::CGBlockInfo &blockInfo) = 0;
+                                  const CodeGen::CGBlockInfo &blockInfo,
+                                  std::string &layoutStr) = 0;
 
   /// Returns an i8* which points to the byref layout information.
   virtual llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM,
Index: lib/CodeGen/CGObjCMac.cpp
===================================================================
--- lib/CodeGen/CGObjCMac.cpp
+++ lib/CodeGen/CGObjCMac.cpp
@@ -37,6 +37,7 @@
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Module.h"
+#include "llvm/Support/ScopedPrinter.h"
 #include "llvm/Support/raw_ostream.h"
 #include <cstdio>
 
@@ -1084,7 +1085,8 @@
   llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM,
                                      const CGBlockInfo &blockInfo) override;
   llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM,
-                                     const CGBlockInfo &blockInfo) override;
+                                     const CGBlockInfo &blockInfo,
+                                     std::string &layoutStr) override;
 
   llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM,
                                    QualType T) override;
@@ -2795,8 +2797,37 @@
   return getConstantGEP(VMContext, Entry, 0, 0);
 }
 
+static std::string getBlockLayoutInfoString(
+    const SmallVectorImpl<CGObjCCommonMac::RUN_SKIP> &RunSkipBlockVars) {
+  std::string Str;
+
+  for (const CGObjCCommonMac::RUN_SKIP &R : RunSkipBlockVars) {
+    Str += llvm::to_string(R.block_var_bytepos.getQuantity());
+    Str += "s" + llvm::to_string(R.block_var_size.getQuantity());
+    switch (R.opcode) {
+    case CGObjCCommonMac::BLOCK_LAYOUT_STRONG:
+      Str += "s";
+      break;
+    case CGObjCCommonMac::BLOCK_LAYOUT_BYREF:
+      Str += "r";
+      break;
+    case CGObjCCommonMac::BLOCK_LAYOUT_WEAK:
+      Str += "w";
+      break;
+    case CGObjCCommonMac::BLOCK_LAYOUT_UNRETAINED:
+      Str += "u";
+      break;
+    default:
+      break;
+    }
+  }
+
+  return Str;
+}
+
 llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
-                                                    const CGBlockInfo &blockInfo) {
+                                                    const CGBlockInfo &blockInfo,
+                                                    std::string &layoutStr) {
   assert(CGM.getLangOpts().getGC() == LangOptions::NonGC);
 
   RunSkipBlockVars.clear();
@@ -2845,6 +2876,8 @@
     UpdateRunSkipBlockVars(CI.isByRef(), getBlockCaptureLifetime(type, false),
                            fieldOffset, fieldSize);
   }
+
+  layoutStr = getBlockLayoutInfoString(RunSkipBlockVars);
   return getBitmapBlockLayout(false);
 }
 
Index: lib/CodeGen/CGObjCGNU.cpp
===================================================================
--- lib/CodeGen/CGObjCGNU.cpp
+++ lib/CodeGen/CGObjCGNU.cpp
@@ -655,7 +655,8 @@
     return NULLPtr;
   }
   llvm::Constant *BuildRCBlockLayout(CodeGenModule &CGM,
-                                     const CGBlockInfo &blockInfo) override {
+                                     const CGBlockInfo &blockInfo,
+                                     std::string &layoutStr) override {
     return NULLPtr;
   }
 
Index: lib/CodeGen/CGBlocks.cpp
===================================================================
--- lib/CodeGen/CGBlocks.cpp
+++ lib/CodeGen/CGBlocks.cpp
@@ -65,6 +65,59 @@
   return CodeGenFunction(CGM).GenerateDestroyHelperFunction(blockInfo);
 }
 
+namespace {
+
+// A struct containing the information needed to generate a block descriptor
+// global variable and its name.
+struct BlockDescriptorInfo {
+  // Size of the block.
+  unsigned Size;
+
+  // Block copy and dispose helper functions.
+  llvm::Constant *CopyHelper = nullptr, *DisposeHelper = nullptr;
+
+  // Type-encoding string.
+  std::string TypeAtEncoding;
+
+  // Block layout string. Note that we cannot use the block layout's C literal
+  // string since it may contain a null byte, which is not allowed in function
+  // names.
+  std::string BlockLayoutStr;
+
+  // The global variable that has the block layout information.
+  llvm::Constant *LayoutInfo;
+};
+
+const char CopyHelperPrefix[] = "__copy_helper_block_";
+const char DisposeHelperPrefix[] = "__destroy_helper_block_";
+
+}
+
+static std::string getBlockDescriptorName(const BlockDescriptorInfo &DescInfo) {
+  std::string Name = "__block_descriptor";
+  Name += llvm::to_string(DescInfo.Size);
+
+  if (DescInfo.CopyHelper) {
+    // The name of the copy helper with the prefix removed.
+    StringRef CopyHelperStr =
+        DescInfo.CopyHelper->getOperand(0)->getName().substr(
+            StringRef(CopyHelperPrefix).size());
+    Name +=
+        "c" + llvm::to_string(CopyHelperStr.size()) + "_" + CopyHelperStr.str();
+    // The name of the dispose helper with the prefix removed.
+    StringRef DisposeHelperStr =
+        DescInfo.DisposeHelper->getOperand(0)->getName().substr(
+            StringRef(DisposeHelperPrefix).size());
+    Name += "d" + llvm::to_string(DisposeHelperStr.size()) + "_" +
+            DisposeHelperStr.str();
+  }
+
+  Name += "e" + llvm::to_string(DescInfo.TypeAtEncoding.size()) + "_" +
+          DescInfo.TypeAtEncoding;
+  Name += "l" + DescInfo.BlockLayoutStr;
+  return Name;
+}
+
 /// buildBlockDescriptor - Build the block descriptor meta-data for a block.
 /// buildBlockDescriptor is accessed from 5th field of the Block_literal
 /// meta-data and contains stationary information about the block literal.
@@ -82,17 +135,55 @@
 static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM,
                                             const CGBlockInfo &blockInfo) {
   ASTContext &C = CGM.getContext();
+  BlockDescriptorInfo descInfo;
 
   llvm::IntegerType *ulong =
-    cast<llvm::IntegerType>(CGM.getTypes().ConvertType(C.UnsignedLongTy));
+      cast<llvm::IntegerType>(CGM.getTypes().ConvertType(C.UnsignedLongTy));
   llvm::PointerType *i8p = nullptr;
   if (CGM.getLangOpts().OpenCL)
-    i8p =
-      llvm::Type::getInt8PtrTy(
-           CGM.getLLVMContext(), C.getTargetAddressSpace(LangAS::opencl_constant));
+    i8p = llvm::Type::getInt8PtrTy(
+        CGM.getLLVMContext(), C.getTargetAddressSpace(LangAS::opencl_constant));
   else
     i8p = CGM.VoidPtrTy;
 
+  descInfo.Size = blockInfo.BlockSize.getQuantity();
+
+  // Optional copy/dispose helpers.
+  if (blockInfo.needsCopyDisposeHelpers()) {
+    // copy_func_helper_decl
+    descInfo.CopyHelper = buildCopyHelper(CGM, blockInfo);
+
+    // destroy_func_decl
+    descInfo.DisposeHelper = buildDisposeHelper(CGM, blockInfo);
+  }
+
+  descInfo.TypeAtEncoding =
+      CGM.getContext().getObjCEncodingForBlock(blockInfo.getBlockExpr());
+
+  std::string descName;
+
+  // GC layout.
+  if (C.getLangOpts().ObjC1) {
+    if (CGM.getLangOpts().getGC() != LangOptions::NonGC)
+      descInfo.LayoutInfo =
+          CGM.getObjCRuntime().BuildGCBlockLayout(CGM, blockInfo);
+    else {
+      descInfo.LayoutInfo =
+          CGM.getObjCRuntime().BuildRCBlockLayout(CGM, blockInfo,
+                                                  descInfo.BlockLayoutStr);
+
+      // Get the encoded block descriptor name.
+      descName = getBlockDescriptorName(descInfo);
+
+      // If the block descriptor already exists, return it.
+      if (llvm::GlobalValue *desc = CGM.getModule().getNamedValue(descName))
+        return llvm::ConstantExpr::getBitCast(desc,
+                                              CGM.getBlockDescriptorType());
+    }
+  } else
+    descInfo.LayoutInfo = llvm::ConstantPointerNull::get(i8p);
+
+  // Create a new block descriptor global variable.
   ConstantInitBuilder builder(CGM);
   auto elements = builder.beginStruct();
 
@@ -103,43 +194,54 @@
   // FIXME: What is the right way to say this doesn't fit?  We should give
   // a user diagnostic in that case.  Better fix would be to change the
   // API to size_t.
-  elements.addInt(ulong, blockInfo.BlockSize.getQuantity());
+  elements.addInt(ulong, descInfo.Size);
 
   // Optional copy/dispose helpers.
+  assert(((descInfo.CopyHelper && descInfo.DisposeHelper) ||
+          (!descInfo.CopyHelper && !descInfo.DisposeHelper)) &&
+         "both helpers exist or neither helpers exist");
   if (blockInfo.needsCopyDisposeHelpers()) {
-    // copy_func_helper_decl
-    elements.add(buildCopyHelper(CGM, blockInfo));
-
-    // destroy_func_decl
-    elements.add(buildDisposeHelper(CGM, blockInfo));
+    assert(descInfo.CopyHelper && "no copy helper");
+    elements.add(descInfo.CopyHelper);
+    elements.add(descInfo.DisposeHelper);
   }
 
   // Signature.  Mandatory ObjC-style method descriptor @encode sequence.
-  std::string typeAtEncoding =
-    CGM.getContext().getObjCEncodingForBlock(blockInfo.getBlockExpr());
   elements.add(llvm::ConstantExpr::getBitCast(
-    CGM.GetAddrOfConstantCString(typeAtEncoding).getPointer(), i8p));
+      CGM.GetAddrOfConstantCString(descInfo.TypeAtEncoding).getPointer(), i8p));
 
-  // GC layout.
-  if (C.getLangOpts().ObjC1) {
-    if (CGM.getLangOpts().getGC() != LangOptions::NonGC)
-      elements.add(CGM.getObjCRuntime().BuildGCBlockLayout(CGM, blockInfo));
-    else
-      elements.add(CGM.getObjCRuntime().BuildRCBlockLayout(CGM, blockInfo));
-  }
-  else
-    elements.addNullPointer(i8p);
+  elements.add(descInfo.LayoutInfo);
 
   unsigned AddrSpace = 0;
   if (C.getLangOpts().OpenCL)
     AddrSpace = C.getTargetAddressSpace(LangAS::opencl_constant);
 
+  llvm::GlobalValue::LinkageTypes linkage;
+  if (descName.empty()) {
+    linkage = llvm::GlobalValue::InternalLinkage;
+    descName = "__block_descriptor_tmp";
+  } else if (descInfo.CopyHelper) {
+    const auto *CopyHelper =
+        cast<llvm::Function>(descInfo.CopyHelper->getOperand(0));
+    const auto *DisposeHelper =
+        cast<llvm::Function>(descInfo.DisposeHelper->getOperand(0));
+    // If either the copy helper or the dispose helper has internal linkage,
+    // the block descriptor must have internal linkage too.
+    if (CopyHelper->getLinkage() == llvm::GlobalValue::InternalLinkage ||
+        DisposeHelper->getLinkage() == llvm::GlobalValue::InternalLinkage)
+      linkage = llvm::GlobalValue::InternalLinkage;
+    else
+      linkage = llvm::GlobalValue::LinkOnceODRLinkage;
+  } else {
+    linkage = llvm::GlobalValue::LinkOnceODRLinkage;
+  }
+
   llvm::GlobalVariable *global =
-    elements.finishAndCreateGlobal("__block_descriptor_tmp",
-                                   CGM.getPointerAlign(),
-                                   /*constant*/ true,
-                                   llvm::GlobalValue::InternalLinkage,
-                                   AddrSpace);
+      elements.finishAndCreateGlobal(descName, CGM.getPointerAlign(),
+                                     /*constant*/ true, linkage, AddrSpace);
+
+  if (linkage == llvm::GlobalValue::LinkOnceODRLinkage)
+    global->setVisibility(llvm::GlobalValue::HiddenVisibility);
 
   return llvm::ConstantExpr::getBitCast(global, CGM.getBlockDescriptorType());
 }
@@ -1664,7 +1766,7 @@
       ItaniumMangleContext::create(Ctx, Ctx.getDiagnostics()));
 
   std::string Name =
-      IsCopyHelper ? "__copy_helper_block_" : "__destroy_helper_block_";
+      IsCopyHelper ? CopyHelperPrefix : DisposeHelperPrefix;
   if (CGM.getLangOpts().Exceptions)
     Name += "e";
   if (CGM.getCodeGenOpts().ObjCAutoRefCountExceptions)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to