From df6b68c9487aed2042c7fc23db10a79f89083a11 Mon Sep 17 00:00:00 2001 From: Mike Stump Date: Thu, 12 Feb 2009 18:29:15 +0000 Subject: [PATCH] Initial codegen for block literals. This is a work in progress. I've tried to put FIXMEs on the most important things to fix up. Lots left to do including more codegen, more documentation and cleaning code and style cleanups. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64390 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGExprScalar.cpp | 148 +++++++++++++++++++++++++++++++++-- 1 file changed, 142 insertions(+), 6 deletions(-) diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index d344cc0d1b..8afed8997b 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -85,7 +85,10 @@ public: /// type is an LLVM scalar type. Value *EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src, QualType SrcTy, QualType DstTy); - + + llvm::Constant *BuildBlockLiteralTmp (); + llvm::Constant *BuildDescriptorBlockDecl(); + //===--------------------------------------------------------------------===// // Visitor Methods //===--------------------------------------------------------------------===// @@ -319,11 +322,7 @@ public: Value *VisitBinComma (const BinaryOperator *E); // Other Operators. - Value *VisitBlockExpr(const BlockExpr *BE) { - CGF.ErrorUnsupported(BE, "block expression"); - return llvm::UndefValue::get(CGF.ConvertType(BE->getType())); - } - + Value *VisitBlockExpr(const BlockExpr *BE); Value *VisitConditionalOperator(const ConditionalOperator *CO); Value *VisitChooseExpr(ChooseExpr *CE); Value *VisitOverloadExpr(OverloadExpr *OE); @@ -1361,6 +1360,143 @@ Value *ScalarExprEmitter::VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { return C; } +enum { + BLOCK_NEEDS_FREE = (1 << 24), + BLOCK_HAS_COPY_DISPOSE = (1 << 25), + BLOCK_HAS_CXX_OBJ = (1 << 26), + BLOCK_IS_GC = (1 << 27), + BLOCK_IS_GLOBAL = (1 << 28), + BLOCK_HAS_DESCRIPTOR = (1 << 29) +}; + +llvm::Constant *ScalarExprEmitter::BuildDescriptorBlockDecl() { + // FIXME: Push up. + bool BlockHasCopyDispose = false; + + const llvm::PointerType *PtrToInt8Ty + = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + llvm::Constant *C; + std::vector Elts; + + // reserved + const llvm::IntegerType *LongTy + = cast( + CGF.CGM.getTypes().ConvertType(CGF.CGM.getContext().LongTy)); + C = llvm::ConstantInt::get(LongTy, 0); + Elts.push_back(C); + + // Size + // FIXME: This should be the size of BlockStructType + C = llvm::ConstantInt::get(LongTy, 20); + Elts.push_back(C); + + if (BlockHasCopyDispose) { + // copy_func_helper_decl + C = llvm::ConstantInt::get(LongTy, 0); + C = llvm::ConstantExpr::getBitCast(C, PtrToInt8Ty); + Elts.push_back(C); + + // destroy_func_decl + C = llvm::ConstantInt::get(LongTy, 0); + C = llvm::ConstantExpr::getBitCast(C, PtrToInt8Ty); + Elts.push_back(C); + } + + C = llvm::ConstantStruct::get(Elts); + + // FIXME: Should be in module? + static int desc_unique_count; + char Name[32]; + sprintf(Name, "__block_descriptor_tmp_%d", ++desc_unique_count); + C = new llvm::GlobalVariable(C->getType(), true, + llvm::GlobalValue::InternalLinkage, + C, Name, &CGF.CGM.getModule()); + return C; +} + +llvm::Constant *ScalarExprEmitter::BuildBlockLiteralTmp() { + // FIXME: Push up + bool BlockHasCopyDispose = false; + bool insideFunction = false; + bool BlockRefDeclList = false; + bool BlockByrefDeclList = false; + + std::vector Elts; + llvm::Constant *C; + + bool staticBlockTmp = (BlockRefDeclList == 0 + && BlockByrefDeclList == 0); + + { + // C = BuildBlockStructInitlist(); + unsigned int flags = BLOCK_HAS_DESCRIPTOR; + + if (BlockHasCopyDispose) + flags |= BLOCK_HAS_COPY_DISPOSE; + + const llvm::PointerType *PtrToInt8Ty + = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + // FIXME: static? What if we start up a new, unrelated module? + // logically we want 1 per module. + static llvm::Constant *NSConcreteGlobalBlock_decl + = new llvm::GlobalVariable(PtrToInt8Ty, false, + llvm::GlobalValue::ExternalLinkage, + 0, "_NSConcreteGlobalBlock", + &CGF.CGM.getModule()); + static llvm::Constant *NSConcreteStackBlock_decl + = new llvm::GlobalVariable(PtrToInt8Ty, false, + llvm::GlobalValue::ExternalLinkage, + 0, "_NSConcreteStackBlock", + &CGF.CGM.getModule()); + C = NSConcreteStackBlock_decl; + if (!insideFunction || + (!BlockRefDeclList && !BlockByrefDeclList)) { + C = NSConcreteGlobalBlock_decl; + flags |= BLOCK_IS_GLOBAL; + } + C = llvm::ConstantExpr::getBitCast(C, PtrToInt8Ty); + Elts.push_back(C); + + // __flags + const llvm::IntegerType *IntTy = cast( + CGF.CGM.getTypes().ConvertType(CGF.CGM.getContext().IntTy)); + C = llvm::ConstantInt::get(IntTy, flags); + Elts.push_back(C); + + // __reserved + C = llvm::ConstantInt::get(IntTy, 0); + Elts.push_back(C); + + // __FuncPtr + // FIXME: Build this up. + Elts.push_back(C); + + // __descriptor + Elts.push_back(BuildDescriptorBlockDecl()); + + // FIXME: Add block_original_ref_decl_list and block_byref_decl_list. + } + + C = llvm::ConstantStruct::get(Elts); + + char Name[32]; + // FIXME: Boost in CGM? + static int global_unique_count; + sprintf(Name, "__block_holder_tmp_%d", ++global_unique_count); + C = new llvm::GlobalVariable(C->getType(), true, + llvm::GlobalValue::InternalLinkage, + C, Name, &CGF.CGM.getModule()); + return C; +} + +Value *ScalarExprEmitter::VisitBlockExpr(const BlockExpr *BE) { + llvm::Constant *C = BuildBlockLiteralTmp(); + + const llvm::PointerType *PtrToInt8Ty + = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + return llvm::ConstantExpr::getBitCast(C, PtrToInt8Ty); +} + //===----------------------------------------------------------------------===// // Entry Point into this File //===----------------------------------------------------------------------===// -- 2.40.0