From: Mike Stump Date: Thu, 5 Mar 2009 08:32:30 +0000 (+0000) Subject: prep work for copy/destroy helpers for block literals. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=00470a1c4c44c5ed26bad9a38b4d3904b02d7a28;p=clang prep work for copy/destroy helpers for block literals. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66159 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 89b2b5ff13..82ac86aaa3 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -30,8 +30,8 @@ Enable__block("f__block", llvm::cl::desc("temporary option to turn on __block precessing " "even though the code isn't done yet"), llvm::cl::ValueDisallowed, llvm::cl::AllowInverse, - llvm::cl::ZeroOrMore); - + llvm::cl::ZeroOrMore, + llvm::cl::init(false)); llvm::Constant *CodeGenFunction::BuildDescriptorBlockDecl(uint64_t Size) { const llvm::Type *UnsignedLongTy @@ -53,13 +53,13 @@ llvm::Constant *CodeGenFunction::BuildDescriptorBlockDecl(uint64_t Size) { if (BlockHasCopyDispose) { // copy_func_helper_decl // FIXME: implement - C = llvm::ConstantInt::get(UnsignedLongTy, 0); + C = llvm::Constant::getNullValue(PtrToInt8Ty); C = llvm::ConstantExpr::getBitCast(C, PtrToInt8Ty); Elts.push_back(C); // destroy_func_decl // FIXME: implement - C = llvm::ConstantInt::get(UnsignedLongTy, 0); + C = llvm::Constant::getNullValue(PtrToInt8Ty); C = llvm::ConstantExpr::getBitCast(C, PtrToInt8Ty); Elts.push_back(C); } @@ -80,7 +80,7 @@ llvm::Constant *BlockModule::getNSConcreteGlobalBlock() { // same thing as CreateRuntimeFunction if there's already a variable with the // same name. NSConcreteGlobalBlock - = new llvm::GlobalVariable(PtrToInt8Ty, false, + = new llvm::GlobalVariable(PtrToInt8Ty, false, llvm::GlobalValue::ExternalLinkage, 0, "_NSConcreteGlobalBlock", &getModule()); @@ -96,7 +96,7 @@ llvm::Constant *BlockModule::getNSConcreteStackBlock() { // same thing as CreateRuntimeFunction if there's already a variable with the // same name. NSConcreteStackBlock - = new llvm::GlobalVariable(PtrToInt8Ty, false, + = new llvm::GlobalVariable(PtrToInt8Ty, false, llvm::GlobalValue::ExternalLinkage, 0, "_NSConcreteStackBlock", &getModule()); @@ -104,18 +104,18 @@ llvm::Constant *BlockModule::getNSConcreteStackBlock() { return NSConcreteStackBlock; } -static void CollectBlockDeclRefInfo(const Stmt *S, +static void CollectBlockDeclRefInfo(const Stmt *S, CodeGenFunction::BlockInfo &Info) { for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); I != E; ++I) if (*I) CollectBlockDeclRefInfo(*I, Info); - + if (const BlockDeclRefExpr *DE = dyn_cast(S)) { // FIXME: Handle enums. if (isa(DE->getDecl())) return; - + if (DE->isByRef()) Info.ByRefDeclRefs.push_back(DE); else @@ -144,8 +144,8 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { // CGF, then we can just check to see if CGF is 0. if (0 && CanBlockBeGlobal(Info)) return CGM.GetAddrOfGlobalBlock(BE, Name.c_str()); - - std::vector Elts; + + std::vector Elts(5); llvm::Constant *C; llvm::Value *V; @@ -153,34 +153,41 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { // C = BuildBlockStructInitlist(); unsigned int flags = BLOCK_HAS_DESCRIPTOR; + // We run this first so that we set BlockHasCopyDispose from the entire + // block literal. + // __invoke + uint64_t subBlockSize, subBlockAlign; + llvm::SmallVector subBlockDeclRefDecls; + llvm::Function *Fn + = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, subBlockSize, + subBlockAlign, + subBlockDeclRefDecls, + BlockHasCopyDispose); + Elts[3] = Fn; + + if (!Enable__block && BlockHasCopyDispose) + ErrorUnsupported(BE, "block literal that requires copy/dispose"); + if (BlockHasCopyDispose) flags |= BLOCK_HAS_COPY_DISPOSE; // __isa C = CGM.getNSConcreteStackBlock(); C = llvm::ConstantExpr::getBitCast(C, PtrToInt8Ty); - Elts.push_back(C); + Elts[0] = C; // __flags const llvm::IntegerType *IntTy = cast( CGM.getTypes().ConvertType(CGM.getContext().IntTy)); C = llvm::ConstantInt::get(IntTy, flags); - Elts.push_back(C); + Elts[1] = C; // __reserved C = llvm::ConstantInt::get(IntTy, 0); - Elts.push_back(C); - - // __invoke - uint64_t subBlockSize, subBlockAlign; - llvm::SmallVector subBlockDeclRefDecls; - llvm::Function *Fn - = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, subBlockSize, - subBlockAlign, subBlockDeclRefDecls); - Elts.push_back(Fn); + Elts[2] = C; // __descriptor - Elts.push_back(BuildDescriptorBlockDecl(subBlockSize)); + Elts[4] = BuildDescriptorBlockDecl(subBlockSize); if (subBlockDeclRefDecls.size() == 0) { // Optimize to being a global block. @@ -198,7 +205,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { C = llvm::ConstantExpr::getBitCast(C, ConvertType(BPT)); return C; } - + std::vector Types(5+subBlockDeclRefDecls.size()); for (int i=0; i<5; ++i) Types[i] = Elts[i]->getType(); @@ -222,7 +229,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { for (unsigned i=0; i<5; ++i) Builder.CreateStore(Elts[i], Builder.CreateStructGEP(V, i, "block.tmp")); - + for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i) { // FIXME: Push const down. @@ -254,7 +261,6 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { false, false); } if (BDRE->isByRef()) { - // FIXME: __block in nested literals E = new (getContext()) UnaryOperator(E, UnaryOperator::AddrOf, getContext().getPointerType(E->getType()), @@ -272,9 +278,9 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { // be done during Block_copy for us, and we can postpone the work // until then. uint64_t offset = BlockDecls[BDRE->getDecl()]; - + llvm::Value *BlockLiteral = LoadBlockStruct(); - + Loc = Builder.CreateGEP(BlockLiteral, llvm::ConstantInt::get(llvm::Type::Int64Ty, offset), @@ -296,7 +302,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { // the struct matches the previously computed offset in BlockDecls. } } - + QualType BPT = BE->getType(); return Builder.CreateBitCast(V, ConvertType(BPT)); } @@ -461,7 +467,7 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) { ErrorUnsupported(E, "__block variable in block literal"); else if (E->getType()->isBlockPointerType()) ErrorUnsupported(E, "block pointer in block literal"); - else if (E->getDecl()->getAttr() || + else if (E->getDecl()->getAttr() || getContext().isObjCNSObjectType(E->getType())) ErrorUnsupported(E, "__attribute__((NSObject)) variable in block " "literal"); @@ -470,6 +476,9 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) { // See if we have already allocated an offset for this variable. if (offset == 0) { + // Don't run the expensive check, unless we have to. + if (!BlockHasCopyDispose && BlockRequiresCopying(E->getType())) + BlockHasCopyDispose = true; // if not, allocate one now. offset = getBlockOffset(E); } @@ -532,18 +541,21 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { CodeGenFunction::BlockInfo Info(0, n); uint64_t subBlockSize, subBlockAlign; llvm::SmallVector subBlockDeclRefDecls; + bool subBlockHasCopyDispose; llvm::Function *Fn = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, subBlockSize, subBlockAlign, - subBlockDeclRefDecls); + subBlockDeclRefDecls, + subBlockHasCopyDispose); assert(subBlockSize == BlockLiteralSize && "no imports allowed for global block"); + assert(!subBlockHasCopyDispose && "no imports allowed for global block"); // isa LiteralFields[0] = getNSConcreteGlobalBlock(); // Flags - LiteralFields[1] = + LiteralFields[1] = llvm::ConstantInt::get(IntTy, BLOCK_IS_GLOBAL | BLOCK_HAS_DESCRIPTOR); // Reserved @@ -571,11 +583,13 @@ llvm::Value *CodeGenFunction::LoadBlockStruct() { return Builder.CreateLoad(LocalDeclMap[getBlockStructDecl()], "self"); } -llvm::Function *CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, - const BlockInfo& Info, - uint64_t &Size, - uint64_t &Align, - llvm::SmallVector &subBlockDeclRefDecls) { +llvm::Function * +CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, + const BlockInfo& Info, + uint64_t &Size, + uint64_t &Align, + llvm::SmallVector &subBlockDeclRefDecls, + bool &subBlockHasCopyDispose) { const FunctionProtoType *FTy = cast(BExpr->getFunctionType()); @@ -620,7 +634,7 @@ llvm::Function *CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, Size = BlockOffset; Align = BlockAlign; subBlockDeclRefDecls = BlockDeclRefDecls; - + subBlockHasCopyDispose |= BlockHasCopyDispose; return Fn; } @@ -642,7 +656,7 @@ uint64_t CodeGenFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) { // Ensure proper alignment, even if it means we have to have a gap BlockOffset = llvm::RoundUpToAlignment(BlockOffset, Align); BlockAlign = std::max(Align, BlockAlign); - + uint64_t Pad = BlockOffset - OldOffset; if (Pad) { llvm::ArrayType::get(llvm::Type::Int8Ty, Pad); @@ -687,7 +701,7 @@ llvm::Value *BlockFunction::getBlockObjectDispose() { ArgTys.push_back(PtrToInt8Ty); ArgTys.push_back(llvm::Type::Int32Ty); FTy = llvm::FunctionType::get(ResultType, ArgTys, false); - CGM.BlockObjectDispose + CGM.BlockObjectDispose = CGM.CreateRuntimeFunction(FTy, "_Block_object_dispose"); } return CGM.BlockObjectDispose; @@ -702,3 +716,5 @@ void BlockFunction::BuildBlockRelease(const VarDecl &D, llvm::Value *DeclPtr) { N = llvm::ConstantInt::get(llvm::Type::Int32Ty, BLOCK_FIELD_IS_BYREF); Builder.CreateCall2(F, V, N); } + +ASTContext &BlockFunction::getContext() const { return CGM.getContext(); } diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h index 3b9cc5053b..24b0cc9e5b 100644 --- a/lib/CodeGen/CGBlocks.h +++ b/lib/CodeGen/CGBlocks.h @@ -110,6 +110,7 @@ public: class BlockFunction : public BlockBase { CodeGenModule &CGM; + ASTContext &getContext() const; public: const llvm::Type *PtrToInt8Ty; @@ -160,6 +161,14 @@ public: llvm::Value *getBlockObjectDispose(); void BuildBlockRelease(const VarDecl &D, llvm::Value *DeclPtr); + + bool BlockRequiresCopying(QualType Ty) { + if (Ty->isBlockPointerType()) + return true; + if (getContext().isObjCNSObjectType(Ty)) + return true; + return false; + } }; } // end namespace CodeGen diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index f31a05a9a6..3dfb1821cc 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -338,6 +338,9 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { int flag = 0; int flags = 0; + // The block literal will need a copy/destroy helper. + BlockHasCopyDispose = true; + if (Ty->isBlockPointerType()) { flag |= BLOCK_FIELD_IS_BLOCK; flags |= BLOCK_HAS_COPY_DISPOSE; @@ -360,11 +363,15 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { V = llvm::ConstantInt::get(llvm::Type::Int32Ty, flags); Builder.CreateStore(V, flags_field); - const llvm::Type *V1 = cast(DeclPtr->getType())->getElementType(); - V = llvm::ConstantInt::get(llvm::Type::Int32Ty, CGM.getTargetData().getTypeStoreSizeInBits(V1) / 8); + const llvm::Type *V1; + V1 = cast(DeclPtr->getType())->getElementType(); + V = llvm::ConstantInt::get(llvm::Type::Int32Ty, + (CGM.getTargetData().getTypeStoreSizeInBits(V1) + / 8)); Builder.CreateStore(V, size_field); if (flags & BLOCK_HAS_COPY_DISPOSE) { + BlockHasCopyDispose = true; llvm::Value *copy_helper = Builder.CreateStructGEP(DeclPtr, 4); llvm::Value *destroy_helper = Builder.CreateStructGEP(DeclPtr, 5); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index dec265aaf9..26fde8423c 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -271,8 +271,8 @@ public: llvm::Function *GenerateBlockFunction(const BlockExpr *BExpr, const BlockInfo& Info, uint64_t &Size, uint64_t &Align, - llvm::SmallVector &subBlockDeclRefDecls); - + llvm::SmallVector &subBlockDeclRefDecls, + bool &subBlockHasCopyDispose); llvm::Value *LoadBlockStruct(); @@ -288,6 +288,7 @@ public: uint64_t BlockOffset; /// BlockAlign - Maximal alignment needed for the Block expressed in bytes. uint64_t BlockAlign; + /// getBlockOffset - Allocate an offset for the ValueDecl from a /// BlockDeclRefExpr in a block literal (BlockExpr). uint64_t getBlockOffset(const BlockDeclRefExpr *E); @@ -298,13 +299,6 @@ public: llvm::Value *GetAddrOfBlockDecl(const BlockDeclRefExpr *E); const llvm::Type *BuildByRefType(QualType Ty, uint64_t Align); - bool BlockRequiresCopying(QualType Ty) { - if (Ty->isBlockPointerType()) - return true; - if (getContext().isObjCNSObjectType(Ty)) - return true; - return false; - } void GenerateCode(const FunctionDecl *FD, llvm::Function *Fn); diff --git a/test/CodeGenObjC/blocks-unsupported.m b/test/CodeGenObjC/blocks-unsupported.m index 8e43d707ed..c9d8295601 100644 --- a/test/CodeGenObjC/blocks-unsupported.m +++ b/test/CodeGenObjC/blocks-unsupported.m @@ -5,30 +5,28 @@ void t1() { - __block int a; - ^{ a = 10; }(); // expected-error {{cannot compile this __block variable in block literal yet}} - - void (^block)(void); - ^{ (void)block; }(); // expected-error {{}} - - struct Foo *__attribute__ ((NSObject)) foo; - ^{ (void)foo; }(); // expected-error {{cannot compile this __attribute__((NSObject)) variable in block literal yet}} - - typedef struct CGColor * __attribute__ ((NSObject)) CGColorRef; - CGColorRef color; - ^{ (void)color; }(); // expected-error {{cannot compile this __attribute__((NSObject)) variable in block literal yet}} - - id a1; - ^{ (void)a1; }(); // expected-error {{cannot compile this Objective-C variable in block literal yet}} - - Foo *a2; - ^{ (void)a2; }(); // expected-error {{cannot compile this Objective-C variable in block literal yet}} - - id

a3; - ^{ (void)a3; }(); // expected-error {{cannot compile this Objective-C variable in block literal yet}} - - Foo

*a4; - ^{ (void)a4; }(); // expected-error {{cannot compile this Objective-C variable in block literal yet}} - - + __block int a; + ^{ a = 10; }(); // expected-error {{cannot compile this __block variable in block literal yet}} expected-error {{cannot compile this block literal that requires copy/dispose yet}} + + void (^block)(void); + ^{ (void)block; }(); // expected-error {{cannot compile this block pointer in block literal yet}} expected-error {{cannot compile this block literal that requires copy/dispose yet}} + + struct Foo *__attribute__ ((NSObject)) foo; + ^{ (void)foo; }(); // expected-error {{cannot compile this __attribute__((NSObject)) variable in block literal yet}} expected-error {{cannot compile this block literal that requires copy/dispose yet}} + + typedef struct CGColor * __attribute__ ((NSObject)) CGColorRef; + CGColorRef color; + ^{ (void)color; }(); // expected-error {{cannot compile this __attribute__((NSObject)) variable in block literal yet}} expected-error {{cannot compile this block literal that requires copy/dispose yet}} + + id a1; + ^{ (void)a1; }(); // expected-error {{cannot compile this Objective-C variable in block literal yet}} expected-error {{cannot compile this block literal that requires copy/dispose yet}} + + Foo *a2; + ^{ (void)a2; }(); // expected-error {{cannot compile this Objective-C variable in block literal yet}} expected-error {{cannot compile this block literal that requires copy/dispose yet}} + + id

a3; + ^{ (void)a3; }(); // expected-error {{cannot compile this Objective-C variable in block literal yet}} expected-error {{cannot compile this block literal that requires copy/dispose yet}} + + Foo

*a4; + ^{ (void)a4; }(); // expected-error {{cannot compile this Objective-C variable in block literal yet}} expected-error {{cannot compile this block literal that requires copy/dispose yet}} }