From d5cab5435371b8cc74a9e05ebd40b5995ebad149 Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Thu, 12 Feb 2009 17:55:02 +0000 Subject: [PATCH] Add a very basic implemenation of global blocks. This needs to be cleaned up. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64387 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Expr.h | 1 + lib/CodeGen/CGBlocks.cpp | 140 ++++++++++++++++++++++++++++++--- lib/CodeGen/CGExprConstant.cpp | 4 + lib/CodeGen/CodeGenFunction.h | 12 +++ lib/CodeGen/CodeGenModule.cpp | 3 +- lib/CodeGen/CodeGenModule.h | 7 ++ 6 files changed, 154 insertions(+), 13 deletions(-) diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 408c660a48..05d088b759 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -2098,6 +2098,7 @@ public: BlockExpr(BlockDecl *BD, QualType ty) : Expr(BlockExprClass, ty), TheBlock(BD) {} + const BlockDecl *getBlockDecl() const { return TheBlock; } BlockDecl *getBlockDecl() { return TheBlock; } // Convenience functions for probing the underlying BlockDecl. diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 38aab2d3ac..9aa5207a44 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -14,18 +14,24 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "llvm/Module.h" +#include "llvm/Target/TargetData.h" #include using namespace clang; using namespace CodeGen; -static const llvm::Type *getBlockDescriptorType(CodeGenFunction &CGF) { +// Block flags +enum { + IsGlobal = 1 << 28 +}; + +static const llvm::Type *getBlockDescriptorType(CodeGenModule &CGM) { static const llvm::Type *Ty = 0; if (!Ty) { const llvm::Type *UnsignedLongTy = - CGF.ConvertType(CGF.getContext().UnsignedLongTy); + CGM.getTypes().ConvertType(CGM.getContext().UnsignedLongTy); // struct __block_descriptor { // unsigned long reserved; @@ -35,13 +41,13 @@ static const llvm::Type *getBlockDescriptorType(CodeGenFunction &CGF) { UnsignedLongTy, NULL); - CGF.CGM.getModule().addTypeName("struct.__block_descriptor", Ty); + CGM.getModule().addTypeName("struct.__block_descriptor", Ty); } return Ty; } -static const llvm::Type *getGenericBlockLiteralType(CodeGenFunction &CGF) { +static const llvm::Type *getGenericBlockLiteralType(CodeGenModule &CGM) { static const llvm::Type *Ty = 0; if (!Ty) { @@ -49,7 +55,7 @@ static const llvm::Type *getGenericBlockLiteralType(CodeGenFunction &CGF) { llvm::PointerType::getUnqual(llvm::Type::Int8Ty); const llvm::Type *BlockDescPtrTy = - llvm::PointerType::getUnqual(getBlockDescriptorType(CGF)); + llvm::PointerType::getUnqual(getBlockDescriptorType(CGM)); // struct __block_literal_generic { // void *isa; @@ -65,7 +71,7 @@ static const llvm::Type *getGenericBlockLiteralType(CodeGenFunction &CGF) { BlockDescPtrTy, NULL); - CGF.CGM.getModule().addTypeName("struct.__block_literal_generic", Ty); + CGM.getModule().addTypeName("struct.__block_literal_generic", Ty); } return Ty; @@ -74,8 +80,7 @@ static const llvm::Type *getGenericBlockLiteralType(CodeGenFunction &CGF) { /// getBlockFunctionType - Given a BlockPointerType, will return the /// function type for the block, including the first block literal argument. static QualType getBlockFunctionType(ASTContext &Ctx, - const BlockPointerType *BPT) -{ + const BlockPointerType *BPT) { const FunctionTypeProto *FTy = cast(BPT->getPointeeType()); llvm::SmallVector Types; @@ -90,8 +95,7 @@ static QualType getBlockFunctionType(ASTContext &Ctx, FTy->isVariadic(), 0); } -RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) -{ +RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) { const BlockPointerType *BPT = E->getCallee()->getType()->getAsBlockPointerType(); @@ -99,7 +103,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) // Get a pointer to the generic block literal. const llvm::Type *BlockLiteralTy = - llvm::PointerType::getUnqual(getGenericBlockLiteralType(*this)); + llvm::PointerType::getUnqual(getGenericBlockLiteralType(CGM)); // Bitcast the callee to a block literal. llvm::Value *BlockLiteral = @@ -135,3 +139,117 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) return EmitCall(CGM.getTypes().getFunctionInfo(E->getType(), Args), Func, Args); } + +llvm::Constant *CodeGenModule::GetAddrOfGlobalBlock(const BlockExpr *BE) { + if (!NSConcreteGlobalBlock) { + const llvm::Type *Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + + // FIXME: Wee should have a CodeGenModule::AddRuntimeVariable that does the + // same thing as CreateRuntimeFunction if there's already a variable with + // the same name. + NSConcreteGlobalBlock = + new llvm::GlobalVariable(Ty, false, + llvm::GlobalVariable::ExternalLinkage, 0, + "_NSConcreteGlobalBlock", &getModule()); + } + + // Generate the block descriptor. + const llvm::Type *UnsignedLongTy = Types.ConvertType(Context.UnsignedLongTy); + + llvm::Constant *DescriptorFields[2]; + + // Reserved + DescriptorFields[0] = llvm::Constant::getNullValue(UnsignedLongTy); + + // Block literal size. For global blocks we just use the size of the generic + // block literal struct. + uint64_t BlockLiteralSize = + TheTargetData.getTypeStoreSizeInBits(getGenericBlockLiteralType(*this)) / 8; + DescriptorFields[1] = llvm::ConstantInt::get(UnsignedLongTy,BlockLiteralSize); + + llvm::Constant *DescriptorStruct = + llvm::ConstantStruct::get(&DescriptorFields[0], 2); + + llvm::GlobalVariable *Descriptor = + new llvm::GlobalVariable(DescriptorStruct->getType(), true, + llvm::GlobalVariable::InternalLinkage, + DescriptorStruct, "__block_descriptor_global", + &getModule()); + + // Generate the constants for the block literal. + llvm::Constant *LiteralFields[5]; + + CodeGenFunction::BlockInfo Info(0, "global"); + llvm::Function *Fn = CodeGenFunction(*this).GenerateBlockFunction(BE, Info); + + // isa + LiteralFields[0] = NSConcreteGlobalBlock; + + // Flags + LiteralFields[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, IsGlobal); + + // Reserved + LiteralFields[2] = llvm::Constant::getNullValue(llvm::Type::Int32Ty); + + // Function + LiteralFields[3] = Fn; + + // Descriptor + LiteralFields[4] = Descriptor; + + llvm::Constant *BlockLiteralStruct = + llvm::ConstantStruct::get(&LiteralFields[0], 5); + + llvm::GlobalVariable *BlockLiteral = + new llvm::GlobalVariable(BlockLiteralStruct->getType(), true, + llvm::GlobalVariable::InternalLinkage, + BlockLiteralStruct, "__block_literal_global", + &getModule()); + + return BlockLiteral; +} + +llvm::Function *CodeGenFunction::GenerateBlockFunction(const BlockExpr *Expr, + const BlockInfo& Info) +{ + const FunctionTypeProto *FTy = + cast(Expr->getFunctionType()); + + FunctionArgList Args; + + const BlockDecl *BD = Expr->getBlockDecl(); + + // FIXME: This leaks + ImplicitParamDecl *SelfDecl = + ImplicitParamDecl::Create(getContext(), 0, + SourceLocation(), 0, + getContext().getPointerType(getContext().VoidTy)); + + Args.push_back(std::make_pair(SelfDecl, SelfDecl->getType())); + + for (BlockDecl::param_iterator i = BD->param_begin(), + e = BD->param_end(); i != e; ++i) + Args.push_back(std::make_pair(*e, (*e)->getType())); + + const CGFunctionInfo &FI = + CGM.getTypes().getFunctionInfo(FTy->getResultType(), Args); + + std::string Name = std::string("__block_function_") + Info.NameSuffix; + + CodeGenTypes &Types = CGM.getTypes(); + const llvm::FunctionType *LTy = Types.GetFunctionType(FI, FTy->isVariadic()); + + llvm::Function *Fn = + llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, + Name, + &CGM.getModule()); + + StartFunction(BD, FTy->getResultType(), Fn, Args, + Expr->getBody()->getLocEnd()); + EmitStmt(Expr->getBody()); + FinishFunction(cast(Expr->getBody())->getRBracLoc()); + + return Fn; +} + + diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 1f6da8a414..91153f796b 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -371,6 +371,10 @@ public: return Visit(E->getSubExpr()); } + llvm::Constant *VisitBlockExpr(const BlockExpr *E) { + return CGM.GetAddrOfGlobalBlock(E); + } + // Utility methods const llvm::Type *ConvertType(QualType T) { return CGM.getTypes().ConvertType(T); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index f6196fe64f..ce4a424c33 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -243,6 +243,18 @@ public: void GenerateObjCSetter(ObjCImplementationDecl *IMP, const ObjCPropertyImplDecl *PID); + struct BlockInfo { + const llvm::Type *BlockLiteralTy; + + const char *NameSuffix; + + BlockInfo(const llvm::Type *blt, const char *ns) + : BlockLiteralTy(blt), NameSuffix(ns) {} + }; + + llvm::Function *GenerateBlockFunction(const BlockExpr *Expr, + const BlockInfo& Info); + void GenerateCode(const FunctionDecl *FD, llvm::Function *Fn); void StartFunction(const Decl *D, QualType RetTy, diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 7192e9db2f..a3b79562d1 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -35,7 +35,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const LangOptions &LO, Diagnostic &diags, bool GenerateDebugInfo) : Context(C), Features(LO), TheModule(M), TheTargetData(TD), Diags(diags), Types(C, M, TD), Runtime(0), MemCpyFn(0), MemMoveFn(0), MemSetFn(0), - CFConstantStringClassRef(0) { + CFConstantStringClassRef(0), NSConcreteGlobalBlock(0) { if (Features.ObjC1) { if (Features.NeXTRuntime) { @@ -1125,4 +1125,3 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { assert(isa(D) && "Unsupported decl kind"); } } - diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index bedefcaa3f..0c3964fd5f 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -40,6 +40,7 @@ namespace clang { class ObjCImplementationDecl; class ObjCCategoryImplDecl; class ObjCProtocolDecl; + class BlockExpr; class Decl; class Expr; class Stmt; @@ -121,6 +122,10 @@ class CodeGenModule { /// Obj-C class pointer. llvm::Constant *CFConstantStringClassRef; + /// NSConcreteGlobalBlock - Cached reference to the clas pointer for + /// global blocks. + llvm::Constant *NSConcreteGlobalBlock; + std::vector BuiltinFunctions; public: CodeGenModule(ASTContext &C, const LangOptions &Features, llvm::Module &M, @@ -196,6 +201,8 @@ public: llvm::Constant *GetAddrOfConstantCString(const std::string &str, const char *GlobalName=0); + llvm::Constant *GetAddrOfGlobalBlock(const BlockExpr *BE); + /// getBuiltinLibFunction - Given a builtin id for a function like /// "__builtin_fabsf", return a Function* for "fabsf". llvm::Function *getBuiltinLibFunction(unsigned BuiltinID); -- 2.40.0