diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2010-05-27 15:17:06 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2010-05-27 15:17:06 +0000 |
commit | 53992adde3eda3ccf9da63bc7e45673f043de18f (patch) | |
tree | 3558f327a6f9ab59c5d7a06528d84e1560445247 /lib/CodeGen/CGBlocks.cpp | |
parent | 7e411337c0ed226dace6e07f1420486768161308 (diff) | |
download | FreeBSD-src-53992adde3eda3ccf9da63bc7e45673f043de18f.zip FreeBSD-src-53992adde3eda3ccf9da63bc7e45673f043de18f.tar.gz |
Update clang to r104832.
Diffstat (limited to 'lib/CodeGen/CGBlocks.cpp')
-rw-r--r-- | lib/CodeGen/CGBlocks.cpp | 483 |
1 files changed, 284 insertions, 199 deletions
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 8082b33..de58597 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -24,6 +24,45 @@ using namespace clang; using namespace CodeGen; +/// CGBlockInfo - Information to generate a block literal. +class clang::CodeGen::CGBlockInfo { +public: + /// Name - The name of the block, kindof. + const char *Name; + + /// DeclRefs - Variables from parent scopes that have been + /// imported into this block. + llvm::SmallVector<const BlockDeclRefExpr *, 8> DeclRefs; + + /// InnerBlocks - This block and the blocks it encloses. + llvm::SmallPtrSet<const DeclContext *, 4> InnerBlocks; + + /// CXXThisRef - Non-null if 'this' was required somewhere, in + /// which case this is that expression. + const CXXThisExpr *CXXThisRef; + + /// NeedsObjCSelf - True if something in this block has an implicit + /// reference to 'self'. + bool NeedsObjCSelf; + + /// These are initialized by GenerateBlockFunction. + bool BlockHasCopyDispose; + CharUnits BlockSize; + CharUnits BlockAlign; + llvm::SmallVector<const Expr*, 8> BlockLayout; + + CGBlockInfo(const char *Name); +}; + +CGBlockInfo::CGBlockInfo(const char *N) + : Name(N), CXXThisRef(0), NeedsObjCSelf(false) { + + // Skip asm prefix, if any. + if (Name && Name[0] == '\01') + ++Name; +} + + llvm::Constant *CodeGenFunction:: BuildDescriptorBlockDecl(const BlockExpr *BE, bool BlockHasCopyDispose, CharUnits Size, const llvm::StructType* Ty, @@ -86,58 +125,86 @@ llvm::Constant *BlockModule::getNSConcreteStackBlock() { return NSConcreteStackBlock; } -static void CollectBlockDeclRefInfo( - const Stmt *S, CodeGenFunction::BlockInfo &Info, - llvm::SmallSet<const DeclContext *, 16> &InnerContexts) { +static void CollectBlockDeclRefInfo(const Stmt *S, CGBlockInfo &Info) { for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); I != E; ++I) if (*I) - CollectBlockDeclRefInfo(*I, Info, InnerContexts); + CollectBlockDeclRefInfo(*I, Info); // We want to ensure we walk down into block literals so we can find // all nested BlockDeclRefExprs. if (const BlockExpr *BE = dyn_cast<BlockExpr>(S)) { - InnerContexts.insert(cast<DeclContext>(BE->getBlockDecl())); - CollectBlockDeclRefInfo(BE->getBody(), Info, InnerContexts); + Info.InnerBlocks.insert(BE->getBlockDecl()); + CollectBlockDeclRefInfo(BE->getBody(), Info); } - if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) { + else if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) { + const ValueDecl *D = BDRE->getDecl(); // FIXME: Handle enums. - if (isa<FunctionDecl>(BDRE->getDecl())) + if (isa<FunctionDecl>(D)) return; + if (isa<ImplicitParamDecl>(D) && + isa<ObjCMethodDecl>(D->getDeclContext()) && + cast<ObjCMethodDecl>(D->getDeclContext())->getSelfDecl() == D) { + Info.NeedsObjCSelf = true; + return; + } + // Only Decls that escape are added. - if (!InnerContexts.count(BDRE->getDecl()->getDeclContext())) + if (!Info.InnerBlocks.count(D->getDeclContext())) Info.DeclRefs.push_back(BDRE); } + + // Make sure to capture implicit 'self' references due to super calls. + else if (const ObjCMessageExpr *E = dyn_cast<ObjCMessageExpr>(S)) { + if (E->getReceiverKind() == ObjCMessageExpr::SuperClass || + E->getReceiverKind() == ObjCMessageExpr::SuperInstance) + Info.NeedsObjCSelf = true; + } + + // Getter/setter uses may also cause implicit super references, + // which we can check for with: + else if (isa<ObjCSuperExpr>(S)) + Info.NeedsObjCSelf = true; + + else if (isa<CXXThisExpr>(S)) + Info.CXXThisRef = cast<CXXThisExpr>(S); } -/// CanBlockBeGlobal - Given a BlockInfo struct, determines if a block can be +/// CanBlockBeGlobal - Given a CGBlockInfo struct, determines if a block can be /// declared as a global variable instead of on the stack. -static bool CanBlockBeGlobal(const CodeGenFunction::BlockInfo &Info) { +static bool CanBlockBeGlobal(const CGBlockInfo &Info) { return Info.DeclRefs.empty(); } /// AllocateAllBlockDeclRefs - Preallocate all nested BlockDeclRefExprs to /// ensure we can generate the debug information for the parameter for the block /// invoke function. -static void AllocateAllBlockDeclRefs(const CodeGenFunction::BlockInfo &Info, - CodeGenFunction *CGF) { - // FIXME: Also always forward the this pointer in C++ as well. +static void AllocateAllBlockDeclRefs(CodeGenFunction &CGF, CGBlockInfo &Info) { + if (Info.CXXThisRef) + CGF.AllocateBlockCXXThisPointer(Info.CXXThisRef); for (size_t i = 0; i < Info.DeclRefs.size(); ++i) - CGF->AllocateBlockDecl(Info.DeclRefs[i]); + CGF.AllocateBlockDecl(Info.DeclRefs[i]); + + if (Info.NeedsObjCSelf) { + ValueDecl *Self = cast<ObjCMethodDecl>(CGF.CurFuncDecl)->getSelfDecl(); + BlockDeclRefExpr *BDRE = + new (CGF.getContext()) BlockDeclRefExpr(Self, Self->getType(), + SourceLocation(), false); + Info.DeclRefs.push_back(BDRE); + CGF.AllocateBlockDecl(BDRE); + } } // FIXME: Push most into CGM, passing down a few bits, like current function // name. llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { - std::string Name = CurFn->getName(); - CodeGenFunction::BlockInfo Info(0, Name.c_str()); - llvm::SmallSet<const DeclContext *, 16> InnerContexts; - InnerContexts.insert(BE->getBlockDecl()); - CollectBlockDeclRefInfo(BE->getBody(), Info, InnerContexts); + CGBlockInfo Info(Name.c_str()); + Info.InnerBlocks.insert(BE->getBlockDecl()); + CollectBlockDeclRefInfo(BE->getBody(), Info); // Check if the block can be global. // FIXME: This test doesn't work for nested blocks yet. Longer term, I'd like @@ -160,23 +227,15 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { // We run this first so that we set BlockHasCopyDispose from the entire // block literal. // __invoke - CharUnits subBlockSize; - CharUnits subBlockAlign; - llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls; - bool subBlockHasCopyDispose = false; llvm::Function *Fn = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, CurFuncDecl, - LocalDeclMap, - subBlockSize, - subBlockAlign, - subBlockDeclRefDecls, - subBlockHasCopyDispose); - BlockHasCopyDispose |= subBlockHasCopyDispose; + LocalDeclMap); + BlockHasCopyDispose |= Info.BlockHasCopyDispose; Elts[3] = Fn; // FIXME: Don't use BlockHasCopyDispose, it is set more often then // necessary, for example: { ^{ __block int i; ^{ i = 1; }(); }(); } - if (subBlockHasCopyDispose) + if (Info.BlockHasCopyDispose) flags |= BLOCK_HAS_COPY_DISPOSE; // __isa @@ -206,10 +265,10 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { C = llvm::ConstantInt::get(IntTy, 0); Elts[2] = C; - if (subBlockDeclRefDecls.size() == 0) { + if (Info.BlockLayout.empty()) { // __descriptor - Elts[4] = BuildDescriptorBlockDecl(BE, subBlockHasCopyDispose, subBlockSize, - 0, 0); + Elts[4] = BuildDescriptorBlockDecl(BE, Info.BlockHasCopyDispose, + Info.BlockSize, 0, 0); // Optimize to being a global block. Elts[0] = CGM.getNSConcreteGlobalBlock(); @@ -227,13 +286,13 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { return C; } - std::vector<const llvm::Type *> Types(BlockFields+subBlockDeclRefDecls.size()); + std::vector<const llvm::Type *> Types(BlockFields+Info.BlockLayout.size()); for (int i=0; i<4; ++i) Types[i] = Elts[i]->getType(); Types[4] = PtrToInt8Ty; - for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i) { - const Expr *E = subBlockDeclRefDecls[i]; + for (unsigned i = 0, n = Info.BlockLayout.size(); i != n; ++i) { + const Expr *E = Info.BlockLayout[i]; const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E); QualType Ty = E->getType(); if (BDRE && BDRE->isByRef()) { @@ -245,105 +304,113 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { llvm::StructType *Ty = llvm::StructType::get(VMContext, Types, true); llvm::AllocaInst *A = CreateTempAlloca(Ty); - A->setAlignment(subBlockAlign.getQuantity()); + A->setAlignment(Info.BlockAlign.getQuantity()); V = A; - std::vector<HelperInfo> NoteForHelper(subBlockDeclRefDecls.size()); - int helpersize = 0; + // Build layout / cleanup information for all the data entries in the + // layout, and write the enclosing fields into the type. + std::vector<HelperInfo> NoteForHelper(Info.BlockLayout.size()); + unsigned NumHelpers = 0; for (unsigned i=0; i<4; ++i) Builder.CreateStore(Elts[i], Builder.CreateStructGEP(V, i, "block.tmp")); - for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i) - { - // FIXME: Push const down. - Expr *E = const_cast<Expr*>(subBlockDeclRefDecls[i]); - DeclRefExpr *DR; - ValueDecl *VD; - - DR = dyn_cast<DeclRefExpr>(E); - // Skip padding. - if (DR) continue; - - BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E); - VD = BDRE->getDecl(); - - llvm::Value* Addr = Builder.CreateStructGEP(V, i+BlockFields, "tmp"); - NoteForHelper[helpersize].index = i+5; - NoteForHelper[helpersize].RequiresCopying - = BlockRequiresCopying(VD->getType()); - NoteForHelper[helpersize].flag - = (VD->getType()->isBlockPointerType() - ? BLOCK_FIELD_IS_BLOCK - : BLOCK_FIELD_IS_OBJECT); - - if (LocalDeclMap[VD]) { - if (BDRE->isByRef()) { - NoteForHelper[helpersize].flag = BLOCK_FIELD_IS_BYREF | - // FIXME: Someone double check this. - (VD->getType().isObjCGCWeak() ? BLOCK_FIELD_IS_WEAK : 0); - llvm::Value *Loc = LocalDeclMap[VD]; - Loc = Builder.CreateStructGEP(Loc, 1, "forwarding"); - Loc = Builder.CreateLoad(Loc); - Builder.CreateStore(Loc, Addr); - ++helpersize; - continue; - } else - E = new (getContext()) DeclRefExpr (VD, - VD->getType(), - SourceLocation()); - } + for (unsigned i=0; i < Info.BlockLayout.size(); ++i) { + const Expr *E = Info.BlockLayout[i]; + + // Skip padding. + if (isa<DeclRefExpr>(E)) continue; + + llvm::Value* Addr = Builder.CreateStructGEP(V, i+BlockFields, "tmp"); + HelperInfo &Note = NoteForHelper[NumHelpers++]; + + Note.index = i+5; + + if (isa<CXXThisExpr>(E)) { + Note.RequiresCopying = false; + Note.flag = BLOCK_FIELD_IS_OBJECT; + + Builder.CreateStore(LoadCXXThis(), Addr); + continue; + } + + const BlockDeclRefExpr *BDRE = cast<BlockDeclRefExpr>(E); + const ValueDecl *VD = BDRE->getDecl(); + QualType T = VD->getType(); + + Note.RequiresCopying = BlockRequiresCopying(T); + + if (BDRE->isByRef()) { + Note.flag = BLOCK_FIELD_IS_BYREF; + if (T.isObjCGCWeak()) + Note.flag |= BLOCK_FIELD_IS_WEAK; + } else if (T->isBlockPointerType()) { + Note.flag = BLOCK_FIELD_IS_BLOCK; + } else { + Note.flag = BLOCK_FIELD_IS_OBJECT; + } + + if (LocalDeclMap[VD]) { if (BDRE->isByRef()) { - NoteForHelper[helpersize].flag = BLOCK_FIELD_IS_BYREF | - // FIXME: Someone double check this. - (VD->getType().isObjCGCWeak() ? BLOCK_FIELD_IS_WEAK : 0); - E = new (getContext()) - UnaryOperator(E, UnaryOperator::AddrOf, - getContext().getPointerType(E->getType()), - SourceLocation()); - } - ++helpersize; - - RValue r = EmitAnyExpr(E, Addr, false); - if (r.isScalar()) { - llvm::Value *Loc = r.getScalarVal(); - const llvm::Type *Ty = Types[i+BlockFields]; - if (BDRE->isByRef()) { - // E is now the address of the value field, instead, we want the - // address of the actual ByRef struct. We optimize this slightly - // compared to gcc by not grabbing the forwarding slot as this must - // be done during Block_copy for us, and we can postpone the work - // until then. - CharUnits offset = BlockDecls[BDRE->getDecl()]; - - llvm::Value *BlockLiteral = LoadBlockStruct(); - - Loc = Builder.CreateGEP(BlockLiteral, - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - offset.getQuantity()), - "block.literal"); - Ty = llvm::PointerType::get(Ty, 0); - Loc = Builder.CreateBitCast(Loc, Ty); - Loc = Builder.CreateLoad(Loc); - // Loc = Builder.CreateBitCast(Loc, Ty); - } + llvm::Value *Loc = LocalDeclMap[VD]; + Loc = Builder.CreateStructGEP(Loc, 1, "forwarding"); + Loc = Builder.CreateLoad(Loc); Builder.CreateStore(Loc, Addr); - } else if (r.isComplex()) - // FIXME: implement - ErrorUnsupported(BE, "complex in block literal"); - else if (r.isAggregate()) - ; // Already created into the destination - else - assert (0 && "bad block variable"); - // FIXME: Ensure that the offset created by the backend for - // the struct matches the previously computed offset in BlockDecls. + continue; + } else { + E = new (getContext()) DeclRefExpr(const_cast<ValueDecl*>(VD), + VD->getType(), + SourceLocation()); + } } - NoteForHelper.resize(helpersize); + + if (BDRE->isByRef()) { + E = new (getContext()) + UnaryOperator(const_cast<Expr*>(E), UnaryOperator::AddrOf, + getContext().getPointerType(E->getType()), + SourceLocation()); + } + + RValue r = EmitAnyExpr(E, Addr, false); + if (r.isScalar()) { + llvm::Value *Loc = r.getScalarVal(); + const llvm::Type *Ty = Types[i+BlockFields]; + if (BDRE->isByRef()) { + // E is now the address of the value field, instead, we want the + // address of the actual ByRef struct. We optimize this slightly + // compared to gcc by not grabbing the forwarding slot as this must + // be done during Block_copy for us, and we can postpone the work + // until then. + CharUnits offset = BlockDecls[BDRE->getDecl()]; + + llvm::Value *BlockLiteral = LoadBlockStruct(); + + Loc = Builder.CreateGEP(BlockLiteral, + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), + offset.getQuantity()), + "block.literal"); + Ty = llvm::PointerType::get(Ty, 0); + Loc = Builder.CreateBitCast(Loc, Ty); + Loc = Builder.CreateLoad(Loc); + // Loc = Builder.CreateBitCast(Loc, Ty); + } + Builder.CreateStore(Loc, Addr); + } else if (r.isComplex()) + // FIXME: implement + ErrorUnsupported(BE, "complex in block literal"); + else if (r.isAggregate()) + ; // Already created into the destination + else + assert (0 && "bad block variable"); + // FIXME: Ensure that the offset created by the backend for + // the struct matches the previously computed offset in BlockDecls. + } + NoteForHelper.resize(NumHelpers); // __descriptor llvm::Value *Descriptor = BuildDescriptorBlockDecl(BE, - subBlockHasCopyDispose, - subBlockSize, Ty, + Info.BlockHasCopyDispose, + Info.BlockSize, Ty, &NoteForHelper); Descriptor = Builder.CreateBitCast(Descriptor, PtrToInt8Ty); Builder.CreateStore(Descriptor, Builder.CreateStructGEP(V, 4, "block.tmp")); @@ -487,13 +554,25 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E, return EmitCall(FnInfo, Func, ReturnValue, Args); } -CharUnits CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) { +void CodeGenFunction::AllocateBlockCXXThisPointer(const CXXThisExpr *E) { + assert(BlockCXXThisOffset.isZero() && "already computed 'this' pointer"); + + // Figure out what the offset is. + QualType T = E->getType(); + std::pair<CharUnits,CharUnits> TypeInfo = getContext().getTypeInfoInChars(T); + CharUnits Offset = getBlockOffset(TypeInfo.first, TypeInfo.second); + + BlockCXXThisOffset = Offset; + BlockLayout.push_back(E); +} + +void CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) { const ValueDecl *VD = E->getDecl(); - CharUnits &offset = BlockDecls[VD]; + CharUnits &Offset = BlockDecls[VD]; // See if we have already allocated an offset for this variable. - if (offset.isPositive()) - return offset; + if (!Offset.isZero()) + return; // Don't run the expensive check, unless we have to. if (!BlockHasCopyDispose) @@ -501,23 +580,34 @@ CharUnits CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) { || BlockRequiresCopying(E->getType())) BlockHasCopyDispose = true; - // if not, allocate one now. - offset = getBlockOffset(E); + const ValueDecl *D = cast<ValueDecl>(E->getDecl()); - return offset; + CharUnits Size; + CharUnits Align; + + if (E->isByRef()) { + llvm::tie(Size,Align) = + getContext().getTypeInfoInChars(getContext().VoidPtrTy); + } else { + Size = getContext().getTypeSizeInChars(D->getType()); + Align = getContext().getDeclAlign(D); + } + + Offset = getBlockOffset(Size, Align); + BlockLayout.push_back(E); } -llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) { - const ValueDecl *VD = E->getDecl(); - CharUnits offset = AllocateBlockDecl(E); - +llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const ValueDecl *VD, + bool IsByRef) { + CharUnits offset = BlockDecls[VD]; + assert(!offset.isZero() && "getting address of unallocated decl"); llvm::Value *BlockLiteral = LoadBlockStruct(); llvm::Value *V = Builder.CreateGEP(BlockLiteral, llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), offset.getQuantity()), "block.literal"); - if (E->isByRef()) { + if (IsByRef) { const llvm::Type *PtrStructTy = llvm::PointerType::get(BuildByRefType(VD), 0); // The block literal will need a copy/destroy helper. @@ -543,19 +633,6 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) { return V; } -void CodeGenFunction::BlockForwardSelf() { - const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl); - ImplicitParamDecl *SelfDecl = OMD->getSelfDecl(); - llvm::Value *&DMEntry = LocalDeclMap[SelfDecl]; - if (DMEntry) - return; - // FIXME - Eliminate BlockDeclRefExprs, clients don't need/want to care - BlockDeclRefExpr *BDRE = new (getContext()) - BlockDeclRefExpr(SelfDecl, - SelfDecl->getType(), SourceLocation(), false); - DMEntry = GetAddrOfBlockDecl(BDRE); -} - llvm::Constant * BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { // Generate the block descriptor. @@ -600,19 +677,11 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { std::vector<llvm::Constant*> LiteralFields(FieldCount); - CodeGenFunction::BlockInfo Info(0, n); - CharUnits subBlockSize; - CharUnits subBlockAlign; - llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls; - bool subBlockHasCopyDispose = false; + CGBlockInfo Info(n); llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap; llvm::Function *Fn - = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, 0, LocalDeclMap, - subBlockSize, - subBlockAlign, - subBlockDeclRefDecls, - subBlockHasCopyDispose); - assert(subBlockSize == BlockLiteralSize + = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, 0, LocalDeclMap); + assert(Info.BlockSize == BlockLiteralSize && "no imports allowed for global block"); // isa @@ -651,13 +720,9 @@ llvm::Value *CodeGenFunction::LoadBlockStruct() { llvm::Function * CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, - const BlockInfo& Info, + CGBlockInfo &Info, const Decl *OuterFuncDecl, - llvm::DenseMap<const Decl*, llvm::Value*> ldm, - CharUnits &Size, - CharUnits &Align, - llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls, - bool &subBlockHasCopyDispose) { + llvm::DenseMap<const Decl*, llvm::Value*> ldm) { // Check if we should generate debug info for this block. if (CGM.getDebugInfo()) @@ -701,11 +766,12 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor"); - // Allocate all BlockDeclRefDecls, so we can calculate the right ParmTy below. - AllocateAllBlockDeclRefs(Info, this); + // Build the block struct now. + AllocateAllBlockDeclRefs(*this, Info); QualType ParmTy = getContext().getBlockParmType(BlockHasCopyDispose, - BlockDeclRefDecls); + BlockLayout); + // FIXME: This leaks ImplicitParamDecl *SelfDecl = ImplicitParamDecl::Create(getContext(), const_cast<BlockDecl*>(BD), @@ -725,10 +791,11 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, IsVariadic); + MangleBuffer Name; + CGM.getMangledName(Name, BD); llvm::Function *Fn = - llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, - llvm::Twine("__") + Info.Name + "_block_invoke_", - &CGM.getModule()); + llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, + Name.getString(), &CGM.getModule()); CGM.SetInternalFunctionAttributes(BD, Fn, FI); @@ -738,6 +805,34 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, CurFuncDecl = OuterFuncDecl; CurCodeDecl = BD; + // If we have a C++ 'this' reference, go ahead and force it into + // existence now. + if (Info.CXXThisRef) { + assert(!BlockCXXThisOffset.isZero() && + "haven't yet allocated 'this' reference"); + + // TODO: I have a dream that one day this will be typed. + llvm::Value *BlockLiteral = LoadBlockStruct(); + llvm::Value *ThisPtrRaw = + Builder.CreateConstInBoundsGEP1_64(BlockLiteral, + BlockCXXThisOffset.getQuantity(), + "this.ptr.raw"); + + const llvm::Type *Ty = + CGM.getTypes().ConvertType(Info.CXXThisRef->getType()); + Ty = llvm::PointerType::get(Ty, 0); + llvm::Value *ThisPtr = Builder.CreateBitCast(ThisPtrRaw, Ty, "this.ptr"); + + CXXThisValue = Builder.CreateLoad(ThisPtr, "this"); + } + + // If we have an Objective C 'self' reference, go ahead and force it + // into existence now. + if (Info.NeedsObjCSelf) { + ValueDecl *Self = cast<ObjCMethodDecl>(CurFuncDecl)->getSelfDecl(); + LocalDeclMap[Self] = GetAddrOfBlockDecl(Self, false); + } + // Save a spot to insert the debug information for all the BlockDeclRefDecls. llvm::BasicBlock *entry = Builder.GetInsertBlock(); llvm::BasicBlock::iterator entry_ptr = Builder.GetInsertPoint(); @@ -754,9 +849,10 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, if (CGDebugInfo *DI = getDebugInfo()) { // Emit debug information for all the BlockDeclRefDecls. - for (unsigned i = 0, e = BlockDeclRefDecls.size(); i != e; ++i) { - if (const BlockDeclRefExpr *BDRE = - dyn_cast<BlockDeclRefExpr>(BlockDeclRefDecls[i])) { + // FIXME: also for 'this' + for (unsigned i = 0, e = BlockLayout.size(); i != e; ++i) { + if (const BlockDeclRefExpr *BDRE = + dyn_cast<BlockDeclRefExpr>(BlockLayout[i])) { const ValueDecl *D = BDRE->getDecl(); DI->setLocation(D->getLocation()); DI->EmitDeclareOfBlockDeclRefVariable(BDRE, @@ -779,25 +875,15 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, llvm::RoundUpToAlignment(BlockOffset.getQuantity(), MinAlign.getQuantity())); - Size = BlockOffset; - Align = BlockAlign; - subBlockDeclRefDecls = BlockDeclRefDecls; - subBlockHasCopyDispose |= BlockHasCopyDispose; + Info.BlockSize = BlockOffset; + Info.BlockAlign = BlockAlign; + Info.BlockLayout = BlockLayout; + Info.BlockHasCopyDispose = BlockHasCopyDispose; return Fn; } -CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) { - const ValueDecl *D = dyn_cast<ValueDecl>(BDRE->getDecl()); - - CharUnits Size = getContext().getTypeSizeInChars(D->getType()); - CharUnits Align = getContext().getDeclAlign(D); - - if (BDRE->isByRef()) { - Size = getContext().getTypeSizeInChars(getContext().VoidPtrTy); - Align = getContext().getTypeAlignInChars(getContext().VoidPtrTy); - } - - assert ((Align.isPositive()) && "alignment must be 1 byte or more"); +CharUnits BlockFunction::getBlockOffset(CharUnits Size, CharUnits Align) { + assert((Align.isPositive()) && "alignment must be 1 byte or more"); CharUnits OldOffset = BlockOffset; @@ -808,23 +894,22 @@ CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) { CharUnits Pad = BlockOffset - OldOffset; if (Pad.isPositive()) { - llvm::ArrayType::get(llvm::Type::getInt8Ty(VMContext), Pad.getQuantity()); QualType PadTy = getContext().getConstantArrayType(getContext().CharTy, llvm::APInt(32, Pad.getQuantity()), ArrayType::Normal, 0); - ValueDecl *PadDecl = VarDecl::Create(getContext(), 0, SourceLocation(), + ValueDecl *PadDecl = VarDecl::Create(getContext(), + getContext().getTranslationUnitDecl(), + SourceLocation(), 0, QualType(PadTy), 0, VarDecl::None, VarDecl::None); - Expr *E; - E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(), - SourceLocation()); - BlockDeclRefDecls.push_back(E); + Expr *E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(), + SourceLocation()); + BlockLayout.push_back(E); } - BlockDeclRefDecls.push_back(BDRE); BlockOffset += Size; - return BlockOffset-Size; + return BlockOffset - Size; } llvm::Constant *BlockFunction:: |