From: Mike Stump Date: Thu, 12 Feb 2009 18:29:15 +0000 (+0000) Subject: Initial codegen for block literals. This is a work in progress. I've X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=df6b68c9487aed2042c7fc23db10a79f89083a11;p=clang 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 --- 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 //===----------------------------------------------------------------------===//