[cfe-commits] r128618 - in /cfe/trunk: lib/CodeGen/CGBlocks.cpp lib/CodeGen/CodeGenFunction.h lib/CodeGen/CodeGenModule.h test/CodeGenCXX/blocks.cpp

John McCall rjmccall at apple.com
Thu Mar 31 01:03:29 PDT 2011


Author: rjmccall
Date: Thu Mar 31 03:03:29 2011
New Revision: 128618

URL: http://llvm.org/viewvc/llvm-project?rev=128618&view=rev
Log:
After much contemplation, I've decided that we probably shouldn't "unique"
__block object copy/dispose helpers for C++ objects with those for
different variables with completely different semantics simply because
they happen to both be no more aligned than a pointer.

Found by inspection.

Also, internalize most of the helper generation logic within CGBlocks.cpp,
and refactor it to fit my peculiar aesthetic sense.


Modified:
    cfe/trunk/lib/CodeGen/CGBlocks.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/lib/CodeGen/CodeGenModule.h
    cfe/trunk/test/CodeGenCXX/blocks.cpp

Modified: cfe/trunk/lib/CodeGen/CGBlocks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBlocks.cpp?rev=128618&r1=128617&r2=128618&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGBlocks.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGBlocks.cpp Thu Mar 31 03:03:29 2011
@@ -34,6 +34,9 @@
     ++Name;
 }
 
+// Anchor the vtable to this translation unit.
+CodeGenModule::ByrefHelpers::~ByrefHelpers() {}
+
 /// Build the given block as a global block.
 static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
                                         const CGBlockInfo &blockInfo,
@@ -1218,87 +1221,158 @@
   return llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy);
 }
 
-llvm::Constant *CodeGenFunction::
-GeneratebyrefCopyHelperFunction(const llvm::Type *T, BlockFieldFlags flags,
-                                const VarDecl *variable) {
-  QualType R = getContext().VoidTy;
+namespace {
+
+/// Emits the copy/dispose helper functions for a __block object of id type.
+class ObjectByrefHelpers : public CodeGenModule::ByrefHelpers {
+  BlockFieldFlags Flags;
+
+public:
+  ObjectByrefHelpers(CharUnits alignment, BlockFieldFlags flags)
+    : ByrefHelpers(alignment), Flags(flags) {}
+
+  void emitCopy(CodeGenFunction &CGF, llvm::Value *srcField,
+                llvm::Value *destField) {
+    destField = CGF.Builder.CreateBitCast(destField, CGF.VoidPtrTy);
+
+    srcField = CGF.Builder.CreateBitCast(srcField, CGF.VoidPtrPtrTy);
+    llvm::Value *srcValue = CGF.Builder.CreateLoad(srcField);
+
+    unsigned flags = (Flags | BLOCK_BYREF_CALLER).getBitMask();
+
+    llvm::Value *flagsVal = llvm::ConstantInt::get(CGF.Int32Ty, flags);
+    llvm::Value *fn = CGF.CGM.getBlockObjectAssign();
+    CGF.Builder.CreateCall3(fn, destField, srcValue, flagsVal);
+  }
+
+  void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
+    field = CGF.Builder.CreateBitCast(field, CGF.Int8PtrTy->getPointerTo(0));
+    llvm::Value *value = CGF.Builder.CreateLoad(field);
+
+    CGF.BuildBlockRelease(value, Flags | BLOCK_BYREF_CALLER);
+  }
+
+  void profileImpl(llvm::FoldingSetNodeID &id) const {
+    id.AddInteger(Flags.getBitMask());
+  }
+};
+
+/// Emits the copy/dispose helpers for a __block variable with a
+/// nontrivial copy constructor or destructor.
+class CXXByrefHelpers : public CodeGenModule::ByrefHelpers {
+  QualType VarType;
+  const Expr *CopyExpr;
+
+public:
+  CXXByrefHelpers(CharUnits alignment, QualType type,
+                  const Expr *copyExpr)
+    : ByrefHelpers(alignment), VarType(type), CopyExpr(copyExpr) {}
+
+  bool needsCopy() const { return CopyExpr != 0; }
+  void emitCopy(CodeGenFunction &CGF, llvm::Value *destField,
+                llvm::Value *srcField) {
+    if (!CopyExpr) return;
+    CGF.EmitSynthesizedCXXCopyCtor(destField, srcField, CopyExpr);
+  }
+
+  void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
+    EHScopeStack::stable_iterator cleanupDepth = CGF.EHStack.stable_begin();
+    CGF.PushDestructorCleanup(VarType, field);
+    CGF.PopCleanupBlocks(cleanupDepth);
+  }
+
+  void profileImpl(llvm::FoldingSetNodeID &id) const {
+    id.AddPointer(VarType.getCanonicalType().getAsOpaquePtr());
+  }
+};
+} // end anonymous namespace
+
+static llvm::Constant *
+generateByrefCopyHelper(CodeGenFunction &CGF,
+                        const llvm::StructType &byrefType,
+                        CodeGenModule::ByrefHelpers &byrefInfo) {
+  ASTContext &Context = CGF.getContext();
+
+  QualType R = Context.VoidTy;
 
   FunctionArgList args;
-  ImplicitParamDecl dst(0, SourceLocation(), 0, getContext().VoidPtrTy);
+  ImplicitParamDecl dst(0, SourceLocation(), 0, Context.VoidPtrTy);
   args.push_back(&dst);
 
-  ImplicitParamDecl src(0, SourceLocation(), 0, getContext().VoidPtrTy);
+  ImplicitParamDecl src(0, SourceLocation(), 0, Context.VoidPtrTy);
   args.push_back(&src);
 
   const CGFunctionInfo &FI =
-      CGM.getTypes().getFunctionInfo(R, args, FunctionType::ExtInfo());
+    CGF.CGM.getTypes().getFunctionInfo(R, args, FunctionType::ExtInfo());
 
-  CodeGenTypes &Types = CGM.getTypes();
+  CodeGenTypes &Types = CGF.CGM.getTypes();
   const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
 
   // FIXME: We'd like to put these into a mergable by content, with
   // internal linkage.
   llvm::Function *Fn =
     llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
-                           "__Block_byref_object_copy_", &CGM.getModule());
+                           "__Block_byref_object_copy_", &CGF.CGM.getModule());
 
   IdentifierInfo *II
-    = &CGM.getContext().Idents.get("__Block_byref_object_copy_");
+    = &Context.Idents.get("__Block_byref_object_copy_");
 
-  FunctionDecl *FD = FunctionDecl::Create(getContext(),
-                                          getContext().getTranslationUnitDecl(),
+  FunctionDecl *FD = FunctionDecl::Create(Context,
+                                          Context.getTranslationUnitDecl(),
                                           SourceLocation(),
                                           SourceLocation(), II, R, 0,
                                           SC_Static,
                                           SC_None,
                                           false, true);
-  StartFunction(FD, R, Fn, FI, args, SourceLocation());
+  CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
 
-  // dst->x
-  llvm::Value *V = GetAddrOfLocalVar(&dst);
-  V = Builder.CreateBitCast(V, llvm::PointerType::get(T, 0));
-  V = Builder.CreateLoad(V);
-  V = Builder.CreateStructGEP(V, 6, "x");
-  llvm::Value *DstObj = V;
-
-  // src->x
-  V = GetAddrOfLocalVar(&src);
-  V = Builder.CreateLoad(V);
-  V = Builder.CreateBitCast(V, T);
-  V = Builder.CreateStructGEP(V, 6, "x");
-  
-  if (Expr *copyExpr = getContext().getBlockVarCopyInits(variable)) {
-    llvm::Value *SrcObj = V;
-    EmitSynthesizedCXXCopyCtor(DstObj, SrcObj, copyExpr);
-  } else {
-    DstObj = Builder.CreateBitCast(DstObj, VoidPtrTy);
-    V = Builder.CreateBitCast(V, VoidPtrPtrTy);
-    llvm::Value *SrcObj = Builder.CreateLoad(V);
-    flags |= BLOCK_BYREF_CALLER;
-    llvm::Value *N = llvm::ConstantInt::get(Int32Ty, flags.getBitMask());
-    llvm::Value *F = CGM.getBlockObjectAssign();
-    Builder.CreateCall3(F, DstObj, SrcObj, N);
-  }
-  
-  FinishFunction();
-
-  return llvm::ConstantExpr::getBitCast(Fn, Int8PtrTy);
-}
+  if (byrefInfo.needsCopy()) {
+    const llvm::Type *byrefPtrType = byrefType.getPointerTo(0);
 
-llvm::Constant *
-CodeGenFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T,
-                                                    BlockFieldFlags flags,
-                                                    const VarDecl *variable) {
-  QualType R = getContext().VoidTy;
+    // dst->x
+    llvm::Value *destField = CGF.GetAddrOfLocalVar(&dst);
+    destField = CGF.Builder.CreateLoad(destField);
+    destField = CGF.Builder.CreateBitCast(destField, byrefPtrType);
+    destField = CGF.Builder.CreateStructGEP(destField, 6, "x");
+
+    // src->x
+    llvm::Value *srcField = CGF.GetAddrOfLocalVar(&src);
+    srcField = CGF.Builder.CreateLoad(srcField);
+    srcField = CGF.Builder.CreateBitCast(srcField, byrefPtrType);
+    srcField = CGF.Builder.CreateStructGEP(srcField, 6, "x");
+
+    byrefInfo.emitCopy(CGF, destField, srcField);
+  }  
+
+  CGF.FinishFunction();
+
+  return llvm::ConstantExpr::getBitCast(Fn, CGF.Int8PtrTy);
+}
+
+/// Build the copy helper for a __block variable.
+static llvm::Constant *buildByrefCopyHelper(CodeGenModule &CGM,
+                                            const llvm::StructType &byrefType,
+                                            CodeGenModule::ByrefHelpers &info) {
+  CodeGenFunction CGF(CGM);
+  return generateByrefCopyHelper(CGF, byrefType, info);
+}
+
+/// Generate code for a __block variable's dispose helper.
+static llvm::Constant *
+generateByrefDisposeHelper(CodeGenFunction &CGF,
+                           const llvm::StructType &byrefType,
+                           CodeGenModule::ByrefHelpers &byrefInfo) {
+  ASTContext &Context = CGF.getContext();
+  QualType R = Context.VoidTy;
 
   FunctionArgList args;
-  ImplicitParamDecl src(0, SourceLocation(), 0, getContext().VoidPtrTy);
+  ImplicitParamDecl src(0, SourceLocation(), 0, Context.VoidPtrTy);
   args.push_back(&src);
 
   const CGFunctionInfo &FI =
-      CGM.getTypes().getFunctionInfo(R, args, FunctionType::ExtInfo());
+    CGF.CGM.getTypes().getFunctionInfo(R, args, FunctionType::ExtInfo());
 
-  CodeGenTypes &Types = CGM.getTypes();
+  CodeGenTypes &Types = CGF.CGM.getTypes();
   const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
 
   // FIXME: We'd like to put these into a mergable by content, with
@@ -1306,82 +1380,96 @@
   llvm::Function *Fn =
     llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
                            "__Block_byref_object_dispose_",
-                           &CGM.getModule());
+                           &CGF.CGM.getModule());
 
   IdentifierInfo *II
-    = &CGM.getContext().Idents.get("__Block_byref_object_dispose_");
+    = &Context.Idents.get("__Block_byref_object_dispose_");
 
-  FunctionDecl *FD = FunctionDecl::Create(getContext(),
-                                          getContext().getTranslationUnitDecl(),
+  FunctionDecl *FD = FunctionDecl::Create(Context,
+                                          Context.getTranslationUnitDecl(),
                                           SourceLocation(),
                                           SourceLocation(), II, R, 0,
                                           SC_Static,
                                           SC_None,
                                           false, true);
-  StartFunction(FD, R, Fn, FI, args, SourceLocation());
-
-  llvm::Value *V = GetAddrOfLocalVar(&src);
-  V = Builder.CreateBitCast(V, llvm::PointerType::get(T, 0));
-  V = Builder.CreateLoad(V);
-  V = Builder.CreateStructGEP(V, 6, "x");
-
-  // If it's not any kind of special object, it must have a destructor
-  // or something.
-  if (!flags.isSpecialPointer()) {
-    EHScopeStack::stable_iterator CleanupDepth = EHStack.stable_begin();
-    PushDestructorCleanup(variable->getType(), V);
-    PopCleanupBlocks(CleanupDepth);
+  CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
 
-  // Otherwise, call _Block_object_dispose.
-  } else {
-    V = Builder.CreateBitCast(V, llvm::PointerType::get(Int8PtrTy, 0));
-    V = Builder.CreateLoad(V);
+  if (byrefInfo.needsDispose()) {
+    llvm::Value *V = CGF.GetAddrOfLocalVar(&src);
+    V = CGF.Builder.CreateLoad(V);
+    V = CGF.Builder.CreateBitCast(V, byrefType.getPointerTo(0));
+    V = CGF.Builder.CreateStructGEP(V, 6, "x");
 
-    flags |= BLOCK_BYREF_CALLER;
-    BuildBlockRelease(V, flags);
+    byrefInfo.emitDispose(CGF, V);
   }
 
-  FinishFunction();
+  CGF.FinishFunction();
 
-  return llvm::ConstantExpr::getBitCast(Fn, Int8PtrTy);
+  return llvm::ConstantExpr::getBitCast(Fn, CGF.Int8PtrTy);
 }
 
-llvm::Constant *CodeGenModule::BuildbyrefCopyHelper(const llvm::Type *T,
-                                                    BlockFieldFlags flags,
-                                                    unsigned align,
-                                                    const VarDecl *var) {
-  // All alignments below pointer alignment are bumped up, as we
-  // always have at least that much alignment to begin with.
-  if (align < PointerAlignInBytes) align = PointerAlignInBytes;
-  
-  // As an optimization, we only generate a single function of each kind we
-  // might need.  We need a different one for each alignment and for each
-  // setting of flags.  We mix Align and flag to get the kind.
-  uint64_t Kind = (uint64_t)align*BLOCK_BYREF_CURRENT_MAX + flags.getBitMask();
-  llvm::Constant *&Entry = AssignCache[Kind];
-  if (!Entry)
-    Entry = CodeGenFunction(*this).
-                GeneratebyrefCopyHelperFunction(T, flags, var);
-  return Entry;
-}
-
-llvm::Constant *CodeGenModule::BuildbyrefDestroyHelper(const llvm::Type *T,
-                                                       BlockFieldFlags flags,
-                                                       unsigned align,
-                                                       const VarDecl *var) {
-  // All alignments below pointer alignment are bumped up, as we
-  // always have at least that much alignment to begin with.
-  if (align < PointerAlignInBytes) align = PointerAlignInBytes;
-  
-  // As an optimization, we only generate a single function of each kind we
-  // might need.  We need a different one for each alignment and for each
-  // setting of flags.  We mix Align and flag to get the kind.
-  uint64_t Kind = (uint64_t)align*BLOCK_BYREF_CURRENT_MAX + flags.getBitMask();
-  llvm::Constant *&Entry = DestroyCache[Kind];
-  if (!Entry)
-    Entry = CodeGenFunction(*this).
-                GeneratebyrefDestroyHelperFunction(T, flags, var);
-  return Entry;
+/// Build the dispose helper for a __block variable.
+static llvm::Constant *buildByrefDisposeHelper(CodeGenModule &CGM,
+                                              const llvm::StructType &byrefType,
+                                            CodeGenModule::ByrefHelpers &info) {
+  CodeGenFunction CGF(CGM);
+  return generateByrefDisposeHelper(CGF, byrefType, info);
+}
+
+/// 
+template <class T> static T *buildByrefHelpers(CodeGenModule &CGM,
+                                               const llvm::StructType &byrefTy,
+                                               T &byrefInfo) {
+  // Increase the field's alignment to be at least pointer alignment,
+  // since the layout of the byref struct will guarantee at least that.
+  byrefInfo.Alignment = std::max(byrefInfo.Alignment,
+                              CharUnits::fromQuantity(CGM.PointerAlignInBytes));
+
+  llvm::FoldingSetNodeID id;
+  byrefInfo.Profile(id);
+
+  void *insertPos;
+  CodeGenModule::ByrefHelpers *node
+    = CGM.ByrefHelpersCache.FindNodeOrInsertPos(id, insertPos);
+  if (node) return static_cast<T*>(node);
+
+  byrefInfo.CopyHelper = buildByrefCopyHelper(CGM, byrefTy, byrefInfo);
+  byrefInfo.DisposeHelper = buildByrefDisposeHelper(CGM, byrefTy, byrefInfo);
+
+  T *copy = new (CGM.getContext()) T(byrefInfo);
+  CGM.ByrefHelpersCache.InsertNode(copy, insertPos);
+  return copy;
+}
+
+CodeGenModule::ByrefHelpers *
+CodeGenFunction::buildByrefHelpers(const llvm::StructType &byrefType,
+                                   const AutoVarEmission &emission) {
+  const VarDecl &var = *emission.Variable;
+  QualType type = var.getType();
+
+  if (const CXXRecordDecl *record = type->getAsCXXRecordDecl()) {
+    const Expr *copyExpr = CGM.getContext().getBlockVarCopyInits(&var);
+    if (!copyExpr && record->hasTrivialDestructor()) return 0;
+
+    CXXByrefHelpers byrefInfo(emission.Alignment, type, copyExpr);
+    return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
+  }
+
+  BlockFieldFlags flags;
+  if (type->isBlockPointerType()) {
+    flags |= BLOCK_FIELD_IS_BLOCK;
+  } else if (CGM.getContext().isObjCNSObjectType(type) || 
+             type->isObjCObjectPointerType()) {
+    flags |= BLOCK_FIELD_IS_OBJECT;
+  } else {
+    return 0;
+  }
+
+  if (type.isObjCGCWeak())
+    flags |= BLOCK_FIELD_IS_WEAK;
+
+  ObjectByrefHelpers byrefInfo(emission.Alignment, flags);
+  return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
 }
 
 unsigned CodeGenFunction::getByRefValueLLVMField(const ValueDecl *VD) const {
@@ -1495,37 +1583,25 @@
 /// Initialize the structural components of a __block variable, i.e.
 /// everything but the actual object.
 void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) {
-  llvm::Value *V;
+  // Find the address of the local.
+  llvm::Value *addr = emission.Address;
 
-  BlockFieldFlags fieldFlags;
-  bool fieldNeedsCopyDispose = false;
+  // That's an alloca of the byref structure type.
+  const llvm::StructType *byrefType = cast<llvm::StructType>(
+                 cast<llvm::PointerType>(addr->getType())->getElementType());
+
+  // Build the byref helpers if necessary.  This is null if we don't need any.
+  CodeGenModule::ByrefHelpers *helpers =
+    buildByrefHelpers(*byrefType, emission);
 
   const VarDecl &D = *emission.Variable;
   QualType type = D.getType();
 
-  if (type->isBlockPointerType()) {
-    fieldFlags |= BLOCK_FIELD_IS_BLOCK;
-    fieldNeedsCopyDispose = true;
-  } else if (getContext().isObjCNSObjectType(type) || 
-             type->isObjCObjectPointerType()) {
-    fieldFlags |= BLOCK_FIELD_IS_OBJECT;
-    fieldNeedsCopyDispose = true;
-  } else if (getLangOptions().CPlusPlus) {
-    if (getContext().getBlockVarCopyInits(&D))
-      fieldNeedsCopyDispose = true;
-    else if (const CXXRecordDecl *record = type->getAsCXXRecordDecl())
-      fieldNeedsCopyDispose = !record->hasTrivialDestructor();
-  }
-
-  llvm::Value *addr = emission.Address;
-
-  // FIXME: Someone double check this.
-  if (type.isObjCGCWeak())
-    fieldFlags |= BLOCK_FIELD_IS_WEAK;
+  llvm::Value *V;
 
   // Initialize the 'isa', which is just 0 or 1.
   int isa = 0;
-  if (fieldFlags & BLOCK_FIELD_IS_WEAK)
+  if (type.isObjCGCWeak())
     isa = 1;
   V = Builder.CreateIntToPtr(Builder.getInt32(isa), Int8PtrTy, "isa");
   Builder.CreateStore(V, Builder.CreateStructGEP(addr, 0, "byref.isa"));
@@ -1538,29 +1614,20 @@
   //   c) the flags field is set to either 0 if no helper functions are
   //      needed or BLOCK_HAS_COPY_DISPOSE if they are,
   BlockFlags flags;
-  if (fieldNeedsCopyDispose) flags |= BLOCK_HAS_COPY_DISPOSE;
+  if (helpers) flags |= BLOCK_HAS_COPY_DISPOSE;
   Builder.CreateStore(llvm::ConstantInt::get(IntTy, flags.getBitMask()),
                       Builder.CreateStructGEP(addr, 2, "byref.flags"));
 
-  const llvm::Type *V1;
-  V1 = cast<llvm::PointerType>(addr->getType())->getElementType();
-  V = llvm::ConstantInt::get(IntTy, CGM.GetTargetTypeStoreSize(V1).getQuantity());
+  CharUnits byrefSize = CGM.GetTargetTypeStoreSize(byrefType);
+  V = llvm::ConstantInt::get(IntTy, byrefSize.getQuantity());
   Builder.CreateStore(V, Builder.CreateStructGEP(addr, 3, "byref.size"));
 
-  if (fieldNeedsCopyDispose) {
-    CharUnits alignment = emission.Alignment;
-
+  if (helpers) {
     llvm::Value *copy_helper = Builder.CreateStructGEP(addr, 4);
-    Builder.CreateStore(CGM.BuildbyrefCopyHelper(addr->getType(), fieldFlags,
-                                                 alignment.getQuantity(), &D),
-                        copy_helper);
+    Builder.CreateStore(helpers->CopyHelper, copy_helper);
 
     llvm::Value *destroy_helper = Builder.CreateStructGEP(addr, 5);
-    Builder.CreateStore(CGM.BuildbyrefDestroyHelper(addr->getType(),
-                                                    fieldFlags,
-                                                    alignment.getQuantity(),
-                                                    &D),
-                        destroy_helper);
+    Builder.CreateStore(helpers->DisposeHelper, destroy_helper);
   }
 }
 

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=128618&r1=128617&r2=128618&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Thu Mar 31 03:03:29 2011
@@ -1107,13 +1107,6 @@
   llvm::Constant *GenerateCopyHelperFunction(const CGBlockInfo &blockInfo);
   llvm::Constant *GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo);
 
-  llvm::Constant *GeneratebyrefCopyHelperFunction(const llvm::Type *,
-                                                  BlockFieldFlags flags,
-                                                  const VarDecl *BD);
-  llvm::Constant *GeneratebyrefDestroyHelperFunction(const llvm::Type *T, 
-                                                     BlockFieldFlags flags, 
-                                                     const VarDecl *BD);
-
   void BuildBlockRelease(llvm::Value *DeclPtr, BlockFieldFlags flags);
 
   class AutoVarEmission;
@@ -2182,6 +2175,10 @@
   }
 
   void EmitDeclMetadata();
+
+  CodeGenModule::ByrefHelpers *
+  buildByrefHelpers(const llvm::StructType &byrefType,
+                    const AutoVarEmission &emission);
 };
 
 /// Helper class with most of the code for saving a value for a

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=128618&r1=128617&r2=128618&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.h Thu Mar 31 03:03:29 2011
@@ -247,9 +247,6 @@
     int GlobalUniqueCount;
   } Block;
 
-  llvm::DenseMap<uint64_t, llvm::Constant *> AssignCache;
-  llvm::DenseMap<uint64_t, llvm::Constant *> DestroyCache;
-
   /// @}
 public:
   CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts,
@@ -385,14 +382,35 @@
                                CastExpr::path_const_iterator PathBegin,
                                CastExpr::path_const_iterator PathEnd);
 
-  llvm::Constant *BuildbyrefCopyHelper(const llvm::Type *T,
-                                       BlockFieldFlags flags,
-                                       unsigned Align,
-                                       const VarDecl *variable);
-  llvm::Constant *BuildbyrefDestroyHelper(const llvm::Type *T,
-                                          BlockFieldFlags flags,
-                                          unsigned Align,
-                                          const VarDecl *variable);
+  /// A pair of helper functions for a __block variable.
+  class ByrefHelpers : public llvm::FoldingSetNode {
+  public:
+    llvm::Constant *CopyHelper;
+    llvm::Constant *DisposeHelper;
+
+    /// The alignment of the field.  This is important because
+    /// different offsets to the field within the byref struct need to
+    /// have different helper functions.
+    CharUnits Alignment;
+
+    ByrefHelpers(CharUnits alignment) : Alignment(alignment) {}
+    virtual ~ByrefHelpers();
+
+    void Profile(llvm::FoldingSetNodeID &id) const {
+      id.AddInteger(Alignment.getQuantity());
+      profileImpl(id);
+    }
+    virtual void profileImpl(llvm::FoldingSetNodeID &id) const = 0;
+
+    virtual bool needsCopy() const { return true; }
+    virtual void emitCopy(CodeGenFunction &CGF,
+                          llvm::Value *dest, llvm::Value *src) = 0;
+
+    virtual bool needsDispose() const { return true; }
+    virtual void emitDispose(CodeGenFunction &CGF, llvm::Value *field) = 0;
+  };
+
+  llvm::FoldingSet<ByrefHelpers> ByrefHelpersCache;
 
   /// getUniqueBlockCount - Fetches the global unique block count.
   int getUniqueBlockCount() { return ++Block.GlobalUniqueCount; }

Modified: cfe/trunk/test/CodeGenCXX/blocks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/blocks.cpp?rev=128618&r1=128617&r2=128618&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/blocks.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/blocks.cpp Thu Mar 31 03:03:29 2011
@@ -55,3 +55,35 @@
   // ...or non-trivial copy constructors, but it's not clear how to do
   // that and still have a constant initializer in '03.
 }
+
+namespace test2 {
+  struct A {
+    A();
+    A(const A &);
+    ~A();
+  };
+
+  struct B {
+    B();
+    B(const B &);
+    ~B();
+  };
+
+  // CHECK: define void @_ZN5test24testEv()
+  void test() {
+    __block A a;
+    __block B b;
+  }
+
+  // CHECK: define internal void @__Block_byref_object_copy
+  // CHECK: call void @_ZN5test21AC1ERKS0_(
+
+  // CHECK: define internal void @__Block_byref_object_dispose
+  // CHECK: call void @_ZN5test21AD1Ev(
+
+  // CHECK: define internal void @__Block_byref_object_copy
+  // CHECK: call void @_ZN5test21BC1ERKS0_(
+
+  // CHECK: define internal void @__Block_byref_object_dispose
+  // CHECK: call void @_ZN5test21BD1Ev(
+}





More information about the cfe-commits mailing list