arphaman created this revision.

This patch refactors the code figures out which block captures need to be 
copied/destroyed using special copy/destroy code.
This is a preparation patch for work on merging block copy/destroy routines.

Thanks for taking a look!


Repository:
  rL LLVM

https://reviews.llvm.org/D30345

Files:
  lib/CodeGen/CGBlocks.cpp

Index: lib/CodeGen/CGBlocks.cpp
===================================================================
--- lib/CodeGen/CGBlocks.cpp
+++ lib/CodeGen/CGBlocks.cpp
@@ -1373,6 +1373,110 @@
   return fn;
 }
 
+namespace {
+
+/// Represents a type of copy operation that should be performed for an entity
+/// that's captured by a block.
+enum class BlockCaptureCopyType {
+  CXXCopyCtor,
+  ARCWeak,
+  ARCStrong,
+  BlockObjectAssign
+};
+
+/// Represents a type of destroy operation that should be performed on an
+/// entity that's captured by a block.
+enum class BlockCaptureDestroyType {
+  CXXDtor,
+  ARCWeak,
+  ARCStrong,
+  BlockRelease
+};
+
+template <typename T> struct BlockCaptureCopyDestroyGenericInfo {
+  T Type;
+  BlockFieldFlags Flags;
+  const BlockDecl::Capture &CI;
+  const CGBlockInfo::Capture &Capture;
+
+  BlockCaptureCopyDestroyGenericInfo(T Type, BlockFieldFlags Flags,
+                                     const BlockDecl::Capture &CI,
+                                     const CGBlockInfo::Capture &Capture)
+      : Type(Type), Flags(Flags), CI(CI), Capture(Capture) {}
+};
+
+using BlockCaptureCopyInfo =
+    BlockCaptureCopyDestroyGenericInfo<BlockCaptureCopyType>;
+
+using BlockCaptureDestroyInfo =
+    BlockCaptureCopyDestroyGenericInfo<BlockCaptureDestroyType>;
+
+} // end anonymous namespace
+
+/// Find the set of block captures that need to be explicitly copied.
+static void
+computeBlockCopyEntries(const CGBlockInfo &BlockInfo,
+                        const LangOptions &LangOpts,
+                        SmallVectorImpl<BlockCaptureCopyInfo> &CopiedCaptures) {
+  for (const auto &CI : BlockInfo.getBlockDecl()->captures()) {
+    const VarDecl *Variable = CI.getVariable();
+    QualType Type = Variable->getType();
+    const CGBlockInfo::Capture &Capture = BlockInfo.getCapture(Variable);
+    if (Capture.isConstant())
+      continue;
+
+    if (CI.getCopyExpr()) {
+      assert(!CI.isByRef());
+      // don't bother computing flags
+      CopiedCaptures.emplace_back(BlockCaptureCopyType::CXXCopyCtor,
+                                  BlockFieldFlags(), CI, Capture);
+      continue;
+    }
+    BlockFieldFlags Flags;
+    BlockCaptureCopyType CopyType = BlockCaptureCopyType::BlockObjectAssign;
+    if (CI.isByRef()) {
+      Flags = BLOCK_FIELD_IS_BYREF;
+      if (Type.isObjCGCWeak())
+        Flags |= BLOCK_FIELD_IS_WEAK;
+    } else if (Type->isObjCRetainableType()) {
+      Flags = BLOCK_FIELD_IS_OBJECT;
+      bool isBlockPointer = Type->isBlockPointerType();
+      if (isBlockPointer)
+        Flags = BLOCK_FIELD_IS_BLOCK;
+
+      // Special rules for ARC captures:
+      Qualifiers QS = Type.getQualifiers();
+
+      // We need to register __weak direct captures with the runtime.
+      if (QS.getObjCLifetime() == Qualifiers::OCL_Weak) {
+        CopyType = BlockCaptureCopyType::ARCWeak;
+
+        // We need to retain the copied value for __strong direct captures.
+      } else if (QS.getObjCLifetime() == Qualifiers::OCL_Strong) {
+        // If it's a block pointer, we have to copy the block and
+        // assign that to the destination pointer, so we might as
+        // well use _Block_object_assign.  Otherwise we can avoid that.
+        if (!isBlockPointer)
+          CopyType = BlockCaptureCopyType::ARCStrong;
+
+        // Non-ARC captures of retainable pointers are strong and
+        // therefore require a call to _Block_object_assign.
+      } else if (!QS.getObjCLifetime() && !LangOpts.ObjCAutoRefCount) {
+        // fall through
+
+        // Otherwise the memcpy is fine.
+      } else {
+        continue;
+      }
+
+      // For all other types, the memcpy is fine.
+    } else {
+      continue;
+    }
+    CopiedCaptures.emplace_back(CopyType, Flags, CI, Capture);
+  }
+}
+
 /// Generate the copy-helper function for a block closure object:
 ///   static void block_copy_helper(block_t *dst, block_t *src);
 /// The runtime will have previously initialized 'dst' by doing a
@@ -1431,78 +1535,27 @@
   dst = Address(Builder.CreateLoad(dst), blockInfo.BlockAlign);
   dst = Builder.CreateBitCast(dst, structPtrTy, "block.dest");
 
-  const BlockDecl *blockDecl = blockInfo.getBlockDecl();
-
-  for (const auto &CI : blockDecl->captures()) {
-    const VarDecl *variable = CI.getVariable();
-    QualType type = variable->getType();
-
-    const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
-    if (capture.isConstant()) continue;
-
-    const Expr *copyExpr = CI.getCopyExpr();
-    BlockFieldFlags flags;
-
-    bool useARCWeakCopy = false;
-    bool useARCStrongCopy = false;
-
-    if (copyExpr) {
-      assert(!CI.isByRef());
-      // don't bother computing flags
-
-    } else if (CI.isByRef()) {
-      flags = BLOCK_FIELD_IS_BYREF;
-      if (type.isObjCGCWeak())
-        flags |= BLOCK_FIELD_IS_WEAK;
-
-    } else if (type->isObjCRetainableType()) {
-      flags = BLOCK_FIELD_IS_OBJECT;
-      bool isBlockPointer = type->isBlockPointerType();
-      if (isBlockPointer)
-        flags = BLOCK_FIELD_IS_BLOCK;
-
-      // Special rules for ARC captures:
-      Qualifiers qs = type.getQualifiers();
+  SmallVector<BlockCaptureCopyInfo, 4> CopiedCaptures;
+  computeBlockCopyEntries(blockInfo, getLangOpts(), CopiedCaptures);
 
-      // We need to register __weak direct captures with the runtime.
-      if (qs.getObjCLifetime() == Qualifiers::OCL_Weak) {
-        useARCWeakCopy = true;
-
-      // We need to retain the copied value for __strong direct captures.
-      } else if (qs.getObjCLifetime() == Qualifiers::OCL_Strong) {
-        // If it's a block pointer, we have to copy the block and
-        // assign that to the destination pointer, so we might as
-        // well use _Block_object_assign.  Otherwise we can avoid that.
-        if (!isBlockPointer)
-          useARCStrongCopy = true;
-
-      // Non-ARC captures of retainable pointers are strong and
-      // therefore require a call to _Block_object_assign.
-      } else if (!qs.getObjCLifetime() && !getLangOpts().ObjCAutoRefCount) {
-        // fall through
-
-      // Otherwise the memcpy is fine.
-      } else {
-        continue;
-      }
-
-    // For all other types, the memcpy is fine.
-    } else {
-      continue;
-    }
+  for (const auto &CopiedCapture : CopiedCaptures) {
+    const BlockDecl::Capture &CI = CopiedCapture.CI;
+    const CGBlockInfo::Capture &capture = CopiedCapture.Capture;
+    BlockFieldFlags flags = CopiedCapture.Flags;
 
     unsigned index = capture.getIndex();
     Address srcField = Builder.CreateStructGEP(src, index, capture.getOffset());
     Address dstField = Builder.CreateStructGEP(dst, index, capture.getOffset());
 
     // If there's an explicit copy expression, we do that.
-    if (copyExpr) {
-      EmitSynthesizedCXXCopyCtor(dstField, srcField, copyExpr);
-    } else if (useARCWeakCopy) {
+    if (CI.getCopyExpr()) {
+      assert(CopiedCapture.Type == BlockCaptureCopyType::CXXCopyCtor);
+      EmitSynthesizedCXXCopyCtor(dstField, srcField, CI.getCopyExpr());
+    } else if (CopiedCapture.Type == BlockCaptureCopyType::ARCWeak) {
       EmitARCCopyWeak(dstField, srcField);
     } else {
       llvm::Value *srcValue = Builder.CreateLoad(srcField, "blockcopy.src");
-      if (useARCStrongCopy) {
+      if (CopiedCapture.Type == BlockCaptureCopyType::ARCStrong) {
         // At -O0, store null into the destination field (so that the
         // storeStrong doesn't over-release) and then call storeStrong.
         // This is a workaround to not having an initStrong call.
@@ -1523,13 +1576,15 @@
           cast<llvm::Instruction>(dstField.getPointer())->eraseFromParent();
         }
       } else {
+        assert(CopiedCapture.Type == BlockCaptureCopyType::BlockObjectAssign);
         srcValue = Builder.CreateBitCast(srcValue, VoidPtrTy);
         llvm::Value *dstAddr =
           Builder.CreateBitCast(dstField.getPointer(), VoidPtrTy);
         llvm::Value *args[] = {
           dstAddr, srcValue, llvm::ConstantInt::get(Int32Ty, flags.getBitMask())
         };
 
+        const VarDecl *variable = CI.getVariable();
         bool copyCanThrow = false;
         if (CI.isByRef() && variable->getType()->getAsCXXRecordDecl()) {
           const Expr *copyExpr =
@@ -1553,6 +1608,63 @@
   return llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy);
 }
 
+/// Find the set of block captures that need to be explicitly destroyed.
+static void computeBlockDestroyEntries(
+    const CGBlockInfo &BlockInfo, const LangOptions &LangOpts,
+    SmallVectorImpl<BlockCaptureDestroyInfo> &DestroyedCaptures) {
+  for (const auto &CI : BlockInfo.getBlockDecl()->captures()) {
+    const VarDecl *Variable = CI.getVariable();
+    QualType Type = Variable->getType();
+
+    const CGBlockInfo::Capture &Capture = BlockInfo.getCapture(Variable);
+    if (Capture.isConstant())
+      continue;
+
+    BlockFieldFlags Flags;
+    BlockCaptureDestroyType DestroyType = BlockCaptureDestroyType::BlockRelease;
+
+    if (CI.isByRef()) {
+      Flags = BLOCK_FIELD_IS_BYREF;
+      if (Type.isObjCGCWeak())
+        Flags |= BLOCK_FIELD_IS_WEAK;
+    } else if (const CXXRecordDecl *Record = Type->getAsCXXRecordDecl()) {
+      if (!Record->hasTrivialDestructor())
+        DestroyedCaptures.emplace_back(BlockCaptureDestroyType::CXXDtor,
+                                       BlockFieldFlags(), CI, Capture);
+      continue;
+    } else if (Type->isObjCRetainableType()) {
+      Flags = BLOCK_FIELD_IS_OBJECT;
+      if (Type->isBlockPointerType())
+        Flags = BLOCK_FIELD_IS_BLOCK;
+
+      // Special rules for ARC captures.
+      Qualifiers QS = Type.getQualifiers();
+
+      // Use objc_storeStrong for __strong direct captures; the
+      // dynamic tools really like it when we do this.
+      if (QS.getObjCLifetime() == Qualifiers::OCL_Strong) {
+        DestroyType = BlockCaptureDestroyType::ARCStrong;
+
+        // Support __weak direct captures.
+      } else if (QS.getObjCLifetime() == Qualifiers::OCL_Weak) {
+        DestroyType = BlockCaptureDestroyType::ARCWeak;
+
+        // Non-ARC captures are strong, and we need to use
+        // _Block_object_dispose.
+      } else if (!QS.hasObjCLifetime() && !LangOpts.ObjCAutoRefCount) {
+        // fall through
+
+        // Otherwise, we have nothing to do.
+      } else {
+        continue;
+      }
+    } else {
+      continue;
+    }
+    DestroyedCaptures.emplace_back(DestroyType, Flags, CI, Capture);
+  }
+}
+
 /// Generate the destroy-helper function for a block closure object:
 ///   static void block_destroy_helper(block_t *theBlock);
 ///
@@ -1602,79 +1714,38 @@
   src = Address(Builder.CreateLoad(src), blockInfo.BlockAlign);
   src = Builder.CreateBitCast(src, structPtrTy, "block");
 
-  const BlockDecl *blockDecl = blockInfo.getBlockDecl();
-
   CodeGenFunction::RunCleanupsScope cleanups(*this);
 
-  for (const auto &CI : blockDecl->captures()) {
-    const VarDecl *variable = CI.getVariable();
-    QualType type = variable->getType();
-
-    const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
-    if (capture.isConstant()) continue;
-
-    BlockFieldFlags flags;
-    const CXXDestructorDecl *dtor = nullptr;
-
-    bool useARCWeakDestroy = false;
-    bool useARCStrongDestroy = false;
-
-    if (CI.isByRef()) {
-      flags = BLOCK_FIELD_IS_BYREF;
-      if (type.isObjCGCWeak())
-        flags |= BLOCK_FIELD_IS_WEAK;
-    } else if (const CXXRecordDecl *record = type->getAsCXXRecordDecl()) {
-      if (record->hasTrivialDestructor())
-        continue;
-      dtor = record->getDestructor();
-    } else if (type->isObjCRetainableType()) {
-      flags = BLOCK_FIELD_IS_OBJECT;
-      if (type->isBlockPointerType())
-        flags = BLOCK_FIELD_IS_BLOCK;
-
-      // Special rules for ARC captures.
-      Qualifiers qs = type.getQualifiers();
-
-      // Use objc_storeStrong for __strong direct captures; the
-      // dynamic tools really like it when we do this.
-      if (qs.getObjCLifetime() == Qualifiers::OCL_Strong) {
-        useARCStrongDestroy = true;
-
-      // Support __weak direct captures.
-      } else if (qs.getObjCLifetime() == Qualifiers::OCL_Weak) {
-        useARCWeakDestroy = true;
-
-      // Non-ARC captures are strong, and we need to use _Block_object_dispose.
-      } else if (!qs.hasObjCLifetime() && !getLangOpts().ObjCAutoRefCount) {
-        // fall through
+  SmallVector<BlockCaptureDestroyInfo, 4> DestroyedCaptures;
+  computeBlockDestroyEntries(blockInfo, getLangOpts(), DestroyedCaptures);
 
-      // Otherwise, we have nothing to do.
-      } else {
-        continue;
-      }
-    } else {
-      continue;
-    }
+  for (const auto &DestroyedCapture : DestroyedCaptures) {
+    const BlockDecl::Capture &CI = DestroyedCapture.CI;
+    const CGBlockInfo::Capture &capture = DestroyedCapture.Capture;
+    BlockFieldFlags flags = DestroyedCapture.Flags;
 
     Address srcField =
       Builder.CreateStructGEP(src, capture.getIndex(), capture.getOffset());
 
-    // If there's an explicit copy expression, we do that.
-    if (dtor) {
-      PushDestructorCleanup(dtor, srcField);
+    // If the captured record has a destructor then call it.
+    if (DestroyedCapture.Type == BlockCaptureDestroyType::CXXDtor) {
+      const auto *Dtor =
+          CI.getVariable()->getType()->getAsCXXRecordDecl()->getDestructor();
+      PushDestructorCleanup(Dtor, srcField);
 
-    // If this is a __weak capture, emit the release directly.
-    } else if (useARCWeakDestroy) {
+      // If this is a __weak capture, emit the release directly.
+    } else if (DestroyedCapture.Type == BlockCaptureDestroyType::ARCWeak) {
       EmitARCDestroyWeak(srcField);
 
     // Destroy strong objects with a call if requested.
-    } else if (useARCStrongDestroy) {
+    } else if (DestroyedCapture.Type == BlockCaptureDestroyType::ARCStrong) {
       EmitARCDestroyStrong(srcField, ARCImpreciseLifetime);
 
     // Otherwise we call _Block_object_dispose.  It wouldn't be too
     // hard to just emit this as a cleanup if we wanted to make sure
     // that things were done in reverse.
     } else {
+      assert(DestroyedCapture.Type == BlockCaptureDestroyType::BlockRelease);
       llvm::Value *value = Builder.CreateLoad(srcField);
       value = Builder.CreateBitCast(value, VoidPtrTy);
       BuildBlockRelease(value, flags);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to