diff options
author | dim <dim@FreeBSD.org> | 2011-07-17 15:40:56 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2011-07-17 15:40:56 +0000 |
commit | 611ba3ea3300b71eb95dc4e45f20eee5dddd32e1 (patch) | |
tree | 2097d084eb235c0b12c0bff3445f4ec7bbaa8a12 /lib/CodeGen/CGBlocks.cpp | |
parent | c49018d9cce52d8c9f34b44865ec3ba8e89a1488 (diff) | |
download | FreeBSD-src-611ba3ea3300b71eb95dc4e45f20eee5dddd32e1.zip FreeBSD-src-611ba3ea3300b71eb95dc4e45f20eee5dddd32e1.tar.gz |
Vendor import of clang trunk r135360:
http://llvm.org/svn/llvm-project/cfe/trunk@135360
Diffstat (limited to 'lib/CodeGen/CGBlocks.cpp')
-rw-r--r-- | lib/CodeGen/CGBlocks.cpp | 316 |
1 files changed, 239 insertions, 77 deletions
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index e5da703..9815d1d 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -95,9 +95,7 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM, else elements.push_back(llvm::Constant::getNullValue(i8p)); - llvm::Constant *init = - llvm::ConstantStruct::get(CGM.getLLVMContext(), elements.data(), - elements.size(), false); + llvm::Constant *init = llvm::ConstantStruct::getAnon(elements); llvm::GlobalVariable *global = new llvm::GlobalVariable(CGM.getModule(), init->getType(), true, @@ -166,11 +164,11 @@ namespace { CharUnits Alignment; CharUnits Size; const BlockDecl::Capture *Capture; // null for 'this' - const llvm::Type *Type; + llvm::Type *Type; BlockLayoutChunk(CharUnits align, CharUnits size, const BlockDecl::Capture *capture, - const llvm::Type *type) + llvm::Type *type) : Alignment(align), Size(size), Capture(capture), Type(type) {} /// Tell the block info that this chunk has the given field index. @@ -245,7 +243,7 @@ static CharUnits getLowBit(CharUnits v) { } static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info, - llvm::SmallVectorImpl<const llvm::Type*> &elementTypes) { + llvm::SmallVectorImpl<llvm::Type*> &elementTypes) { ASTContext &C = CGM.getContext(); // The header is basically a 'struct { void *; int; int; void *; void *; }'. @@ -265,8 +263,8 @@ static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info, info.BlockSize = headerSize; assert(elementTypes.empty()); - const llvm::Type *i8p = CGM.getTypes().ConvertType(C.VoidPtrTy); - const llvm::Type *intTy = CGM.getTypes().ConvertType(C.IntTy); + llvm::Type *i8p = CGM.getTypes().ConvertType(C.VoidPtrTy); + llvm::Type *intTy = CGM.getTypes().ConvertType(C.IntTy); elementTypes.push_back(i8p); elementTypes.push_back(intTy); elementTypes.push_back(intTy); @@ -282,7 +280,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) { ASTContext &C = CGM.getContext(); const BlockDecl *block = info.getBlockDecl(); - llvm::SmallVector<const llvm::Type*, 8> elementTypes; + llvm::SmallVector<llvm::Type*, 8> elementTypes; initializeForBlockHeader(CGM, info, elementTypes); if (!block->hasCaptures()) { @@ -310,7 +308,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) { else thisType = cast<CXXMethodDecl>(DC)->getThisType(C); - const llvm::Type *llvmType = CGM.getTypes().ConvertType(thisType); + llvm::Type *llvmType = CGM.getTypes().ConvertType(thisType); std::pair<CharUnits,CharUnits> tinfo = CGM.getContext().getTypeInfoInChars(thisType); maxFieldAlign = std::max(maxFieldAlign, tinfo.second); @@ -330,7 +328,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) { // Just use void* instead of a pointer to the byref type. QualType byRefPtrTy = C.VoidPtrTy; - const llvm::Type *llvmType = CGM.getTypes().ConvertType(byRefPtrTy); + llvm::Type *llvmType = CGM.getTypes().ConvertType(byRefPtrTy); std::pair<CharUnits,CharUnits> tinfo = CGM.getContext().getTypeInfoInChars(byRefPtrTy); maxFieldAlign = std::max(maxFieldAlign, tinfo.second); @@ -347,13 +345,23 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) { continue; } - // Block pointers require copy/dispose. - if (variable->getType()->isBlockPointerType()) { - info.NeedsCopyDispose = true; + // If we have a lifetime qualifier, honor it for capture purposes. + // That includes *not* copying it if it's __unsafe_unretained. + if (Qualifiers::ObjCLifetime lifetime + = variable->getType().getObjCLifetime()) { + switch (lifetime) { + case Qualifiers::OCL_None: llvm_unreachable("impossible"); + case Qualifiers::OCL_ExplicitNone: + case Qualifiers::OCL_Autoreleasing: + break; + + case Qualifiers::OCL_Strong: + case Qualifiers::OCL_Weak: + info.NeedsCopyDispose = true; + } - // So do Objective-C pointers. - } else if (variable->getType()->isObjCObjectPointerType() || - C.isObjCNSObjectType(variable->getType())) { + // Block pointers require copy/dispose. So do Objective-C pointers. + } else if (variable->getType()->isObjCRetainableType()) { info.NeedsCopyDispose = true; // So do types that require non-trivial copy construction. @@ -376,7 +384,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) { CharUnits align = C.getDeclAlign(variable); maxFieldAlign = std::max(maxFieldAlign, align); - const llvm::Type *llvmType = + llvm::Type *llvmType = CGM.getTypes().ConvertTypeForMem(variable->getType()); layout.push_back(BlockLayoutChunk(align, size, &*ci, llvmType)); @@ -591,6 +599,11 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) { // Otherwise, fake up a POD copy into the block field. } else { + // Fake up a new variable so that EmitScalarInit doesn't think + // we're referring to the variable in its own initializer. + ImplicitParamDecl blockFieldPseudoVar(/*DC*/ 0, SourceLocation(), + /*name*/ 0, type); + // We use one of these or the other depending on whether the // reference is nested. DeclRefExpr notNested(const_cast<VarDecl*>(variable), type, VK_LValue, @@ -603,15 +616,37 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) { ImplicitCastExpr l2r(ImplicitCastExpr::OnStack, type, CK_LValueToRValue, declRef, VK_RValue); - EmitExprAsInit(&l2r, variable, blockField, - getContext().getDeclAlign(variable), + EmitExprAsInit(&l2r, &blockFieldPseudoVar, + LValue::MakeAddr(blockField, type, + getContext().getDeclAlign(variable) + .getQuantity(), + getContext()), /*captured by init*/ false); } // Push a destructor if necessary. The semantics for when this // actually gets run are really obscure. - if (!ci->isByRef() && CGM.getLangOptions().CPlusPlus) - PushDestructorCleanup(type, blockField); + if (!ci->isByRef()) { + switch (QualType::DestructionKind dtorKind = type.isDestructedType()) { + case QualType::DK_none: + break; + + // Block captures count as local values and have imprecise semantics. + // They also can't be arrays, so need to worry about that. + case QualType::DK_objc_strong_lifetime: { + // This local is a GCC and MSVC compiler workaround. + Destroyer *destroyer = &destroyARCStrongImprecise; + pushDestroy(getCleanupKind(dtorKind), blockField, type, + *destroyer, /*useEHCleanupForArray*/ false); + break; + } + + case QualType::DK_objc_weak_lifetime: + case QualType::DK_cxx_destructor: + pushDestroy(dtorKind, blockField, type); + break; + } + } } // Cast to the converted block-pointer type, which happens (somewhat @@ -624,11 +659,11 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) { } -const llvm::Type *CodeGenModule::getBlockDescriptorType() { +llvm::Type *CodeGenModule::getBlockDescriptorType() { if (BlockDescriptorType) return BlockDescriptorType; - const llvm::Type *UnsignedLongTy = + llvm::Type *UnsignedLongTy = getTypes().ConvertType(getContext().UnsignedLongTy); // struct __block_descriptor { @@ -645,24 +680,20 @@ const llvm::Type *CodeGenModule::getBlockDescriptorType() { // const char *signature; // the block signature // const char *layout; // reserved // }; - BlockDescriptorType = llvm::StructType::get(UnsignedLongTy->getContext(), - UnsignedLongTy, - UnsignedLongTy, - NULL); - - getModule().addTypeName("struct.__block_descriptor", - BlockDescriptorType); + BlockDescriptorType = + llvm::StructType::createNamed("struct.__block_descriptor", + UnsignedLongTy, UnsignedLongTy, NULL); // Now form a pointer to that. BlockDescriptorType = llvm::PointerType::getUnqual(BlockDescriptorType); return BlockDescriptorType; } -const llvm::Type *CodeGenModule::getGenericBlockLiteralType() { +llvm::Type *CodeGenModule::getGenericBlockLiteralType() { if (GenericBlockLiteralType) return GenericBlockLiteralType; - const llvm::Type *BlockDescPtrTy = getBlockDescriptorType(); + llvm::Type *BlockDescPtrTy = getBlockDescriptorType(); // struct __block_literal_generic { // void *__isa; @@ -671,16 +702,14 @@ const llvm::Type *CodeGenModule::getGenericBlockLiteralType() { // void (*__invoke)(void *); // struct __block_descriptor *__descriptor; // }; - GenericBlockLiteralType = llvm::StructType::get(getLLVMContext(), - VoidPtrTy, - IntTy, - IntTy, - VoidPtrTy, - BlockDescPtrTy, - NULL); - - getModule().addTypeName("struct.__block_literal_generic", - GenericBlockLiteralType); + GenericBlockLiteralType = + llvm::StructType::createNamed("struct.__block_literal_generic", + VoidPtrTy, + IntTy, + IntTy, + VoidPtrTy, + BlockDescPtrTy, + NULL); return GenericBlockLiteralType; } @@ -822,9 +851,7 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM, // Descriptor fields[4] = buildBlockDescriptor(CGM, blockInfo); - llvm::Constant *init = - llvm::ConstantStruct::get(CGM.getLLVMContext(), fields, BlockHeaderSize, - /*packed*/ false); + llvm::Constant *init = llvm::ConstantStruct::getAnon(fields); llvm::GlobalVariable *literal = new llvm::GlobalVariable(CGM.getModule(), @@ -1023,8 +1050,6 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, - - llvm::Constant * CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { ASTContext &C = getContext(); @@ -1084,21 +1109,40 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { if (capture.isConstant()) continue; const Expr *copyExpr = ci->getCopyExpr(); - unsigned flags = 0; + BlockFieldFlags flags; + + bool isARCWeakCapture = 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->isBlockPointerType()) { - flags = BLOCK_FIELD_IS_BLOCK; - } else if (type->isObjCObjectPointerType() || C.isObjCNSObjectType(type)) { + if (type.isObjCGCWeak()) + flags |= BLOCK_FIELD_IS_WEAK; + + } else if (type->isObjCRetainableType()) { flags = BLOCK_FIELD_IS_OBJECT; - } + if (type->isBlockPointerType()) + flags = BLOCK_FIELD_IS_BLOCK; + + // Special rules for ARC captures: + if (getLangOptions().ObjCAutoRefCount) { + Qualifiers qs = type.getQualifiers(); - if (!copyExpr && !flags) continue; + // Don't generate special copy logic for a captured object + // unless it's __strong or __weak. + if (!qs.hasStrongOrWeakObjCLifetime()) + continue; + + // Support __weak direct captures. + if (qs.getObjCLifetime() == Qualifiers::OCL_Weak) + isARCWeakCapture = true; + } + } else { + continue; + } unsigned index = capture.getIndex(); llvm::Value *srcField = Builder.CreateStructGEP(src, index); @@ -1107,12 +1151,14 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { // If there's an explicit copy expression, we do that. if (copyExpr) { EmitSynthesizedCXXCopyCtor(dstField, srcField, copyExpr); + } else if (isARCWeakCapture) { + EmitARCCopyWeak(dstField, srcField); } else { llvm::Value *srcValue = Builder.CreateLoad(srcField, "blockcopy.src"); srcValue = Builder.CreateBitCast(srcValue, VoidPtrTy); llvm::Value *dstAddr = Builder.CreateBitCast(dstField, VoidPtrTy); Builder.CreateCall3(CGM.getBlockObjectAssign(), dstAddr, srcValue, - llvm::ConstantInt::get(Int32Ty, flags)); + llvm::ConstantInt::get(Int32Ty, flags.getBitMask())); } } @@ -1176,20 +1222,37 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { BlockFieldFlags flags; const CXXDestructorDecl *dtor = 0; + bool isARCWeakCapture = false; + if (ci->isByRef()) { flags = BLOCK_FIELD_IS_BYREF; - if (type.isObjCGCWeak()) flags |= BLOCK_FIELD_IS_WEAK; - } else if (type->isBlockPointerType()) { - flags = BLOCK_FIELD_IS_BLOCK; - } else if (type->isObjCObjectPointerType() || C.isObjCNSObjectType(type)) { + 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; - } else if (C.getLangOptions().CPlusPlus) { - if (const CXXRecordDecl *record = type->getAsCXXRecordDecl()) - if (!record->hasTrivialDestructor()) - dtor = record->getDestructor(); - } + if (type->isBlockPointerType()) + flags = BLOCK_FIELD_IS_BLOCK; - if (!dtor && flags.empty()) continue; + // Special rules for ARC captures. + if (getLangOptions().ObjCAutoRefCount) { + Qualifiers qs = type.getQualifiers(); + + // Don't generate special dispose logic for a captured object + // unless it's __strong or __weak. + if (!qs.hasStrongOrWeakObjCLifetime()) + continue; + + // Support __weak direct captures. + if (qs.getObjCLifetime() == Qualifiers::OCL_Weak) + isARCWeakCapture = true; + } + } else { + continue; + } unsigned index = capture.getIndex(); llvm::Value *srcField = Builder.CreateStructGEP(src, index); @@ -1198,6 +1261,10 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { if (dtor) { PushDestructorCleanup(dtor, srcField); + // If this is a __weak capture, emit the release directly. + } else if (isARCWeakCapture) { + EmitARCDestroyWeak(srcField); + // 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. @@ -1251,6 +1318,55 @@ public: } }; +/// Emits the copy/dispose helpers for an ARC __block __weak variable. +class ARCWeakByrefHelpers : public CodeGenModule::ByrefHelpers { +public: + ARCWeakByrefHelpers(CharUnits alignment) : ByrefHelpers(alignment) {} + + void emitCopy(CodeGenFunction &CGF, llvm::Value *destField, + llvm::Value *srcField) { + CGF.EmitARCMoveWeak(destField, srcField); + } + + void emitDispose(CodeGenFunction &CGF, llvm::Value *field) { + CGF.EmitARCDestroyWeak(field); + } + + void profileImpl(llvm::FoldingSetNodeID &id) const { + // 0 is distinguishable from all pointers and byref flags + id.AddInteger(0); + } +}; + +/// Emits the copy/dispose helpers for an ARC __block __strong variable +/// that's not of block-pointer type. +class ARCStrongByrefHelpers : public CodeGenModule::ByrefHelpers { +public: + ARCStrongByrefHelpers(CharUnits alignment) : ByrefHelpers(alignment) {} + + void emitCopy(CodeGenFunction &CGF, llvm::Value *destField, + llvm::Value *srcField) { + // Do a "move" by copying the value and then zeroing out the old + // variable. + + llvm::Value *value = CGF.Builder.CreateLoad(srcField); + llvm::Value *null = + llvm::ConstantPointerNull::get(cast<llvm::PointerType>(value->getType())); + CGF.Builder.CreateStore(value, destField); + CGF.Builder.CreateStore(null, srcField); + } + + void emitDispose(CodeGenFunction &CGF, llvm::Value *field) { + llvm::Value *value = CGF.Builder.CreateLoad(field); + CGF.EmitARCRelease(value, /*precise*/ false); + } + + void profileImpl(llvm::FoldingSetNodeID &id) const { + // 1 is distinguishable from all pointers and byref flags + id.AddInteger(1); + } +}; + /// Emits the copy/dispose helpers for a __block variable with a /// nontrivial copy constructor or destructor. class CXXByrefHelpers : public CodeGenModule::ByrefHelpers { @@ -1318,6 +1434,7 @@ generateByrefCopyHelper(CodeGenFunction &CGF, SC_Static, SC_None, false, true); + CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation()); if (byrefInfo.needsCopy()) { @@ -1449,6 +1566,52 @@ CodeGenFunction::buildByrefHelpers(const llvm::StructType &byrefType, return ::buildByrefHelpers(CGM, byrefType, byrefInfo); } + // Otherwise, if we don't have a retainable type, there's nothing to do. + // that the runtime does extra copies. + if (!type->isObjCRetainableType()) return 0; + + Qualifiers qs = type.getQualifiers(); + + // If we have lifetime, that dominates. + if (Qualifiers::ObjCLifetime lifetime = qs.getObjCLifetime()) { + assert(getLangOptions().ObjCAutoRefCount); + + switch (lifetime) { + case Qualifiers::OCL_None: llvm_unreachable("impossible"); + + // These are just bits as far as the runtime is concerned. + case Qualifiers::OCL_ExplicitNone: + case Qualifiers::OCL_Autoreleasing: + return 0; + + // Tell the runtime that this is ARC __weak, called by the + // byref routines. + case Qualifiers::OCL_Weak: { + ARCWeakByrefHelpers byrefInfo(emission.Alignment); + return ::buildByrefHelpers(CGM, byrefType, byrefInfo); + } + + // ARC __strong __block variables need to be retained. + case Qualifiers::OCL_Strong: + // Block-pointers need to be _Block_copy'ed, so we let the + // runtime be in charge. But we can't use the code below + // because we don't want to set BYREF_CALLER, which will + // just make the runtime ignore us. + if (type->isBlockPointerType()) { + BlockFieldFlags flags = BLOCK_FIELD_IS_BLOCK; + ObjectByrefHelpers byrefInfo(emission.Alignment, flags); + return ::buildByrefHelpers(CGM, byrefType, byrefInfo); + + // Otherwise, we transfer ownership of the retain from the stack + // to the heap. + } else { + ARCStrongByrefHelpers byrefInfo(emission.Alignment); + return ::buildByrefHelpers(CGM, byrefType, byrefInfo); + } + } + llvm_unreachable("fell out of lifetime switch!"); + } + BlockFieldFlags flags; if (type->isBlockPointerType()) { flags |= BLOCK_FIELD_IS_BLOCK; @@ -1502,15 +1665,17 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) { QualType Ty = D->getType(); - llvm::SmallVector<const llvm::Type *, 8> types; + llvm::SmallVector<llvm::Type *, 8> types; - llvm::PATypeHolder ByRefTypeHolder = llvm::OpaqueType::get(getLLVMContext()); + llvm::StructType *ByRefType = + llvm::StructType::createNamed(getLLVMContext(), + "struct.__block_byref_" + D->getNameAsString()); // void *__isa; types.push_back(Int8PtrTy); // void *__forwarding; - types.push_back(llvm::PointerType::getUnqual(ByRefTypeHolder)); + types.push_back(llvm::PointerType::getUnqual(ByRefType)); // int32_t __flags; types.push_back(Int32Ty); @@ -1545,7 +1710,7 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) { unsigned NumPaddingBytes = AlignedOffsetInBytes - CurrentOffsetInBytes; if (NumPaddingBytes > 0) { - const llvm::Type *Ty = llvm::Type::getInt8Ty(getLLVMContext()); + llvm::Type *Ty = llvm::Type::getInt8Ty(getLLVMContext()); // FIXME: We need a sema error for alignment larger than the minimum of // the maximal stack alignment and the alignment of malloc on the system. if (NumPaddingBytes > 1) @@ -1561,13 +1726,9 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) { // T x; types.push_back(ConvertTypeForMem(Ty)); - const llvm::Type *T = llvm::StructType::get(getLLVMContext(), types, Packed); - - cast<llvm::OpaqueType>(ByRefTypeHolder.get())->refineAbstractTypeTo(T); - CGM.getModule().addTypeName("struct.__block_byref_" + D->getNameAsString(), - ByRefTypeHolder.get()); + ByRefType->setBody(types, Packed); - Info.first = ByRefTypeHolder.get(); + Info.first = ByRefType; Info.second = types.size() - 1; @@ -1638,7 +1799,8 @@ namespace { llvm::Value *Addr; CallBlockRelease(llvm::Value *Addr) : Addr(Addr) {} - void Emit(CodeGenFunction &CGF, bool IsForEH) { + void Emit(CodeGenFunction &CGF, Flags flags) { + // Should we be passing FIELD_IS_WEAK here? CGF.BuildBlockRelease(Addr, BLOCK_FIELD_IS_BYREF); } }; |