[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