From 1db7d04b710565d36e7b6659531799b9d3df0c35 Mon Sep 17 00:00:00 2001 From: Mike Stump Date: Sat, 28 Feb 2009 09:07:16 +0000 Subject: [PATCH] First cut CodeGen support for __block variables. llvm-svn: 65688 --- clang/lib/CodeGen/CGBlocks.cpp | 88 ++++++++++++++++++++++++----- clang/lib/CodeGen/CGDecl.cpp | 4 ++ clang/lib/CodeGen/CGExpr.cpp | 37 +++++++++++- clang/lib/CodeGen/CGExprScalar.cpp | 35 +----------- clang/lib/CodeGen/CodeGenFunction.h | 41 ++++---------- 5 files changed, 129 insertions(+), 76 deletions(-) diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp index 276c46fdb5a6..2833b7ecb0bc 100644 --- a/clang/lib/CodeGen/CGBlocks.cpp +++ b/clang/lib/CodeGen/CGBlocks.cpp @@ -154,7 +154,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { Name = ND->getNameAsCString(); BlockInfo Info(0, Name); uint64_t subBlockSize, subBlockAlign; - llvm::SmallVector subBlockDeclRefDecls; + llvm::SmallVector subBlockDeclRefDecls; llvm::Function *Fn = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, subBlockSize, subBlockAlign, subBlockDeclRefDecls); @@ -163,7 +163,6 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { // __descriptor Elts.push_back(BuildDescriptorBlockDecl(subBlockSize)); - // FIXME: Also check to make sure there are no byref variables if (subBlockDeclRefDecls.size() == 0) { C = llvm::ConstantStruct::get(Elts); @@ -181,8 +180,14 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { for (int i=0; i<5; ++i) Types[i] = Elts[i]->getType(); - for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i) - Types[i+5] = ConvertType(subBlockDeclRefDecls[i]->getType()); + for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i) { + const Expr *E = subBlockDeclRefDecls[i]; + const BlockDeclRefExpr *BDRE = dyn_cast(E); + QualType Ty = E->getType(); + if (BDRE && BDRE->isByRef()) + Ty = getContext().getPointerType(Ty); + Types[i+5] = ConvertType(Ty); + } llvm::Type *Ty = llvm::StructType::get(Types, true); @@ -195,14 +200,32 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i) { - ValueDecl *VD = subBlockDeclRefDecls[i]; + // FIXME: Push const down. + Expr *E = const_cast(subBlockDeclRefDecls[i]); + DeclRefExpr *DR; + ValueDecl *VD; + + DR = dyn_cast(E); + // Skip padding. + if (DR) continue; + + BlockDeclRefExpr *BDRE = dyn_cast(E); + VD = BDRE->getDecl(); + + // FIXME: I want a better way to do this. + if (LocalDeclMap[VD]) { + E = new (getContext()) DeclRefExpr (cast(VD), + VD->getType(), SourceLocation(), + false, false); + } + if (BDRE->isByRef()) + E = new (getContext()) + UnaryOperator(E, UnaryOperator::AddrOf, + getContext().getPointerType(E->getType()), + SourceLocation()); - if (VD->getIdentifier() == 0) - continue; - SourceLocation Loc = VD->getLocation(); - DeclRefExpr D(VD, VD->getType(), Loc); llvm::Value* Addr = Builder.CreateStructGEP(V, i+5, "tmp"); - RValue r = EmitAnyExpr(&D, Addr, false); + RValue r = EmitAnyExpr(E, Addr, false); if (r.isScalar()) Builder.CreateStore(r.getScalarVal(), Addr); else if (r.isComplex()) @@ -215,8 +238,6 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { // FIXME: Ensure that the offset created by the backend for // the struct matches the previously computed offset in BlockDecls. } - - // FIXME: Add block_byref_decl_list. } QualType BPT = BE->getType(); @@ -412,7 +433,7 @@ CodeGenModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { CodeGenFunction::BlockInfo Info(0, n); uint64_t subBlockSize, subBlockAlign; - llvm::SmallVector subBlockDeclRefDecls; + llvm::SmallVector subBlockDeclRefDecls; llvm::Function *Fn = CodeGenFunction(*this).GenerateBlockFunction(BE, Info, subBlockSize, subBlockAlign, @@ -455,7 +476,7 @@ llvm::Function *CodeGenFunction::GenerateBlockFunction(const BlockExpr *Expr, const BlockInfo& Info, uint64_t &Size, uint64_t &Align, - llvm::SmallVector &subBlockDeclRefDecls) { + llvm::SmallVector &subBlockDeclRefDecls) { const FunctionProtoType *FTy = cast(Expr->getFunctionType()); @@ -503,3 +524,42 @@ llvm::Function *CodeGenFunction::GenerateBlockFunction(const BlockExpr *Expr, return Fn; } + +uint64_t CodeGenFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) { + const ValueDecl *D = dyn_cast(BDRE->getDecl()); + + uint64_t Size = getContext().getTypeSize(D->getType()) / 8; + uint64_t Align = getContext().getDeclAlignInBytes(D); + + if (BDRE->isByRef()) { + Size = getContext().getTypeSize(getContext().VoidPtrTy) / 8; + Align = getContext().getTypeAlign(getContext().VoidPtrTy) / 8; + } + + assert ((Align > 0) && "alignment must be 1 byte or more"); + + uint64_t OldOffset = BlockOffset; + + // 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); + QualType PadTy = getContext().getConstantArrayType(getContext().CharTy, + llvm::APInt(32, Pad), + ArrayType::Normal, 0); + ValueDecl *PadDecl = VarDecl::Create(getContext(), 0, SourceLocation(), + 0, QualType(PadTy), VarDecl::None, + SourceLocation()); + Expr *E; + E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(), + SourceLocation(), false, false); + BlockDeclRefDecls.push_back(E); + } + BlockDeclRefDecls.push_back(BDRE); + + BlockOffset += Size; + return BlockOffset-Size; +} diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index ee2516a85085..d8123c8ec136 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -88,6 +88,10 @@ CodeGenFunction::CreateStaticBlockVarDecl(const VarDecl &D, else if (isa(CurFuncDecl)) ContextName = std::string(CurFn->getNameStart(), CurFn->getNameStart() + CurFn->getNameLen()); + else if (isa(CurFuncDecl)) + // FIXME: We want to traverse up and pick a name based upon where we came + // from. + ContextName = "block"; else assert(0 && "Unknown context for block var decl"); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index e353ab49c303..7e8eff3847d3 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -151,6 +151,9 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { case Expr::ObjCEncodeExprClass: return EmitObjCEncodeExprLValue(cast(E)); + case Expr::BlockDeclRefExprClass: + return EmitBlockDeclRefLValue(cast(E)); + case Expr::CXXConditionDeclExprClass: return EmitCXXConditionDeclLValue(cast(E)); @@ -627,7 +630,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { } else { llvm::Value *V = LocalDeclMap[VD]; - assert(V && "BlockVarDecl not entered in LocalDeclMap?"); + assert(V && "DeclRefExpr not entered in LocalDeclMap?"); // local variables do not get their gc attribute set. QualType::GCAttrTypes attr = QualType::GCNone; // local static? @@ -660,6 +663,38 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { return LValue(); } +LValue CodeGenFunction::EmitBlockDeclRefLValue(const BlockDeclRefExpr *E) { + return LValue::MakeAddr(GetAddrOfBlockDecl(E), 0); +} + +llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) { + // FIXME: ensure we don't need copy/dispose. + uint64_t &offset = BlockDecls[E->getDecl()]; + + const llvm::Type *Ty; + Ty = CGM.getTypes().ConvertType(E->getDecl()->getType()); + + // See if we have already allocated an offset for this variable. + if (offset == 0) { + // if not, allocate one now. + offset = getBlockOffset(E); + } + + llvm::Value *BlockLiteral = LoadBlockStruct(); + llvm::Value *V = Builder.CreateGEP(BlockLiteral, + llvm::ConstantInt::get(llvm::Type::Int64Ty, + offset), + "tmp"); + Ty = llvm::PointerType::get(Ty, 0); + if (E->isByRef()) + Ty = llvm::PointerType::get(Ty, 0); + V = Builder.CreateBitCast(V, Ty); + if (E->isByRef()) + V = Builder.CreateLoad(V, false, "tmp"); + + return V; +} + LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { // __extension__ doesn't affect lvalue-ness. if (E->getOpcode() == UnaryOperator::Extension) diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index c65c0816e2bd..0b8cc535bf02 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -224,7 +224,7 @@ public: Value *VisitStmtExpr(const StmtExpr *E); - Value *VisitBlockDeclRefExpr(BlockDeclRefExpr *E); + Value *VisitBlockDeclRefExpr(const BlockDeclRefExpr *E); // Unary Operators. Value *VisitPrePostIncDec(const UnaryOperator *E, bool isInc, bool isPre); @@ -601,37 +601,8 @@ Value *ScalarExprEmitter::VisitStmtExpr(const StmtExpr *E) { !E->getType()->isVoidType()).getScalarVal(); } -Value *ScalarExprEmitter::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { - if (E->isByRef()) { - // FIXME: Add codegen for __block variables. - return VisitExpr(E); - } - - // FIXME: ensure we don't need copy/dispose. - uint64_t &offset = CGF.BlockDecls[E->getDecl()]; - - const llvm::Type *Ty; - Ty = CGF.CGM.getTypes().ConvertType(E->getDecl()->getType()); - - // See if we have already allocated an offset for this variable. - if (offset == 0) { - // if not, allocate one now. - offset = CGF.getBlockOffset(E->getDecl()); - } - - llvm::Value *BlockLiteral = CGF.LoadBlockStruct(); - llvm::Value *V = Builder.CreateGEP(BlockLiteral, - llvm::ConstantInt::get(llvm::Type::Int64Ty, - offset), - "tmp"); - Ty = llvm::PointerType::get(Ty, 0); - if (E->isByRef()) - Ty = llvm::PointerType::get(Ty, 0); - V = Builder.CreateBitCast(V, Ty); - V = Builder.CreateLoad(V, false, "tmp"); - if (E->isByRef()) - V = Builder.CreateLoad(V, false, "tmp"); - return V; +Value *ScalarExprEmitter::VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) { + return Builder.CreateLoad(CGF.GetAddrOfBlockDecl(E), false, "tmp"); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 057f554ac692..f2a08b1c5c02 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -282,7 +282,7 @@ public: llvm::Function *GenerateBlockFunction(const BlockExpr *Expr, const BlockInfo& Info, uint64_t &Size, uint64_t &Align, - llvm::SmallVector &subBlockDeclRefDecls); + llvm::SmallVector &subBlockDeclRefDecls); ImplicitParamDecl *BlockStructDecl; @@ -295,40 +295,21 @@ public: /// BlockDeclRefDecls - Decls from BlockDeclRefExprs in apperance order /// in a block literal. Decls without names are used for padding. - llvm::SmallVector BlockDeclRefDecls; + llvm::SmallVector BlockDeclRefDecls; /// BlockOffset - The offset in bytes for the next allocation of an /// imported block variable. uint64_t BlockOffset; /// BlockAlign - Maximal alignment needed for the Block expressed in bytes. uint64_t BlockAlign; - /// getBlockOffset - Offset for next allocated variable used in a BlockExpr. - uint64_t getBlockOffset(ValueDecl *D) { - uint64_t Size = getContext().getTypeSize(D->getType()) / 8; - uint64_t Align = getContext().getDeclAlignInBytes(D); - - assert ((Align > 0) && "alignment must be 1 byte or more"); - - uint64_t OldOffset = BlockOffset; - - // 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; - llvm::ArrayType::get(llvm::Type::Int8Ty, Pad); - QualType PadTy = getContext().getConstantArrayType(getContext().CharTy, - llvm::APInt(32, Pad), - ArrayType::Normal, 0); - ValueDecl *PadDecl = VarDecl::Create(getContext(), 0, SourceLocation(), - 0, QualType(PadTy), VarDecl::None, SourceLocation()); - BlockDeclRefDecls.push_back(PadDecl); - BlockDeclRefDecls.push_back(D); - - BlockOffset += Size; - return BlockOffset-Size; - } - std::map BlockDecls; + /// getBlockOffset - Allocate an offset for the ValueDecl from a + /// BlockDeclRefExpr in a block literal (BlockExpr). + uint64_t getBlockOffset(const BlockDeclRefExpr *E); + + /// BlockDecls - Offsets for all Decls in BlockDeclRefExprs. + std::map BlockDecls; + + llvm::Value *GetAddrOfBlockDecl(const BlockDeclRefExpr *E); void GenerateCode(const FunctionDecl *FD, llvm::Function *Fn); @@ -665,6 +646,8 @@ public: LValue EmitLValueForBitfield(llvm::Value* Base, FieldDecl* Field, unsigned CVRQualifiers); + LValue EmitBlockDeclRefLValue(const BlockDeclRefExpr *E); + LValue EmitCXXConditionDeclLValue(const CXXConditionDeclExpr *E); LValue EmitObjCMessageExprLValue(const ObjCMessageExpr *E); -- GitLab