//===--- CGBlocks.cpp - Emit LLVM Code for declarations -------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This contains code to emit blocks. // //===----------------------------------------------------------------------===// #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "llvm/Module.h" #include "llvm/Target/TargetData.h" #include using namespace clang; using namespace CodeGen; 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 *CodeGenFunction::BuildDescriptorBlockDecl(uint64_t Size) { const llvm::PointerType *PtrToInt8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); const llvm::Type *UnsignedLongTy = CGM.getTypes().ConvertType(getContext().UnsignedLongTy); llvm::Constant *C; std::vector Elts; // reserved C = llvm::ConstantInt::get(UnsignedLongTy, 0); Elts.push_back(C); // Size // FIXME: What is the right way to say this doesn't fit? We should give // a user diagnostic in that case. Better fix would be to change the // API to size_t. C = llvm::ConstantInt::get(UnsignedLongTy, Size); Elts.push_back(C); if (BlockHasCopyDispose) { // copy_func_helper_decl // FIXME: implement C = llvm::ConstantInt::get(UnsignedLongTy, 0); C = llvm::ConstantExpr::getBitCast(C, PtrToInt8Ty); Elts.push_back(C); // destroy_func_decl // FIXME: implement C = llvm::ConstantInt::get(UnsignedLongTy, 0); C = llvm::ConstantExpr::getBitCast(C, PtrToInt8Ty); Elts.push_back(C); } C = llvm::ConstantStruct::get(Elts); C = new llvm::GlobalVariable(C->getType(), true, llvm::GlobalValue::InternalLinkage, C, "__block_descriptor_tmp", &CGM.getModule()); return C; } llvm::Constant *CodeGenModule::getNSConcreteGlobalBlock() { if (NSConcreteGlobalBlock) return NSConcreteGlobalBlock; const llvm::PointerType *PtrToInt8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); // FIXME: We 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(PtrToInt8Ty, false, llvm::GlobalValue::ExternalLinkage, 0, "_NSConcreteGlobalBlock", &getModule()); return NSConcreteGlobalBlock; } llvm::Constant *CodeGenModule::getNSConcreteStackBlock() { if (NSConcreteStackBlock) return NSConcreteStackBlock; const llvm::PointerType *PtrToInt8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); // FIXME: We should have a CodeGenModule::AddRuntimeVariable that does the // same thing as CreateRuntimeFunction if there's already a variable with // the same name. NSConcreteStackBlock = new llvm::GlobalVariable(PtrToInt8Ty, false, llvm::GlobalValue::ExternalLinkage, 0, "_NSConcreteStackBlock", &getModule()); return NSConcreteStackBlock; } // FIXME: Push most into CGM, passing down a few bits, like current // function name. llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { bool insideFunction = false; bool BlockRefDeclList = false; bool BlockByrefDeclList = false; std::vector Elts; llvm::Constant *C; llvm::Value *V; { // C = BuildBlockStructInitlist(); unsigned int flags = BLOCK_HAS_DESCRIPTOR; if (BlockHasCopyDispose) flags |= BLOCK_HAS_COPY_DISPOSE; // __isa C = CGM.getNSConcreteStackBlock(); if (!insideFunction || (!BlockRefDeclList && !BlockByrefDeclList)) { C = CGM.getNSConcreteGlobalBlock(); flags |= BLOCK_IS_GLOBAL; } const llvm::PointerType *PtrToInt8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); C = llvm::ConstantExpr::getBitCast(C, PtrToInt8Ty); Elts.push_back(C); // __flags const llvm::IntegerType *IntTy = cast( CGM.getTypes().ConvertType(CGM.getContext().IntTy)); C = llvm::ConstantInt::get(IntTy, flags); Elts.push_back(C); // __reserved C = llvm::ConstantInt::get(IntTy, 0); Elts.push_back(C); // __invoke const char *Name = ""; if (const NamedDecl *ND = dyn_cast(CurFuncDecl)) if (ND->getIdentifier()) Name = ND->getNameAsCString(); BlockInfo Info(0, Name); uint64_t subBlockSize, subBlockAlign; llvm::SmallVector subBlockDeclRefDecls; llvm::Function *Fn = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, subBlockSize, subBlockAlign, subBlockDeclRefDecls); Elts.push_back(Fn); // __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); char Name[32]; sprintf(Name, "__block_holder_tmp_%d", CGM.getGlobalUniqueCount()); C = new llvm::GlobalVariable(C->getType(), true, llvm::GlobalValue::InternalLinkage, C, Name, &CGM.getModule()); QualType BPT = BE->getType(); C = llvm::ConstantExpr::getBitCast(C, ConvertType(BPT)); return C; } std::vector Types(5+subBlockDeclRefDecls.size()); 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()); llvm::Type *Ty = llvm::StructType::get(Types, true); llvm::AllocaInst *A = CreateTempAlloca(Ty); A->setAlignment(subBlockAlign); V = A; for (unsigned i=0; i<5; ++i) Builder.CreateStore(Elts[i], Builder.CreateStructGEP(V, i, "block.tmp")); for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i) { ValueDecl *VD = subBlockDeclRefDecls[i]; 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); if (r.isScalar()) Builder.CreateStore(r.getScalarVal(), 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. } // FIXME: Add block_byref_decl_list. } QualType BPT = BE->getType(); return Builder.CreateBitCast(V, ConvertType(BPT)); } const llvm::Type *CodeGenModule::getBlockDescriptorType() { if (BlockDescriptorType) return BlockDescriptorType; const llvm::Type *UnsignedLongTy = getTypes().ConvertType(getContext().UnsignedLongTy); // struct __block_descriptor { // unsigned long reserved; // unsigned long block_size; // }; BlockDescriptorType = llvm::StructType::get(UnsignedLongTy, UnsignedLongTy, NULL); getModule().addTypeName("struct.__block_descriptor", BlockDescriptorType); return BlockDescriptorType; } const llvm::Type * CodeGenModule::getGenericBlockLiteralType() { if (GenericBlockLiteralType) return GenericBlockLiteralType; const llvm::Type *Int8PtrTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); const llvm::Type *BlockDescPtrTy = llvm::PointerType::getUnqual(getBlockDescriptorType()); const llvm::IntegerType *IntTy = cast( getTypes().ConvertType(getContext().IntTy)); // struct __block_literal_generic { // void *__isa; // int __flags; // int __reserved; // void (*__invoke)(void *); // struct __block_descriptor *__descriptor; // }; GenericBlockLiteralType = llvm::StructType::get(Int8PtrTy, IntTy, IntTy, Int8PtrTy, BlockDescPtrTy, NULL); getModule().addTypeName("struct.__block_literal_generic", GenericBlockLiteralType); return GenericBlockLiteralType; } const llvm::Type * CodeGenModule::getGenericExtendedBlockLiteralType() { if (GenericExtendedBlockLiteralType) return GenericExtendedBlockLiteralType; const llvm::Type *Int8PtrTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); const llvm::Type *BlockDescPtrTy = llvm::PointerType::getUnqual(getBlockDescriptorType()); const llvm::IntegerType *IntTy = cast( getTypes().ConvertType(getContext().IntTy)); // struct __block_literal_generic { // void *__isa; // int __flags; // int __reserved; // void (*__invoke)(void *); // struct __block_descriptor *__descriptor; // void *__copy_func_helper_decl; // void *__destroy_func_decl; // }; GenericExtendedBlockLiteralType = llvm::StructType::get(Int8PtrTy, IntTy, IntTy, Int8PtrTy, BlockDescPtrTy, Int8PtrTy, Int8PtrTy, NULL); getModule().addTypeName("struct.__block_literal_extended_generic", GenericExtendedBlockLiteralType); return GenericExtendedBlockLiteralType; } /// 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 FunctionTypeProto *FTy = cast(BPT->getPointeeType()); llvm::SmallVector Types; Types.push_back(Ctx.getPointerType(Ctx.VoidTy)); for (FunctionTypeProto::arg_type_iterator i = FTy->arg_type_begin(), e = FTy->arg_type_end(); i != e; ++i) Types.push_back(*i); return Ctx.getFunctionType(FTy->getResultType(), &Types[0], Types.size(), FTy->isVariadic(), 0); } RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) { const BlockPointerType *BPT = E->getCallee()->getType()->getAsBlockPointerType(); llvm::Value *Callee = EmitScalarExpr(E->getCallee()); // Get a pointer to the generic block literal. const llvm::Type *BlockLiteralTy = llvm::PointerType::getUnqual(CGM.getGenericBlockLiteralType()); // Bitcast the callee to a block literal. llvm::Value *BlockLiteral = Builder.CreateBitCast(Callee, BlockLiteralTy, "block.literal"); // Get the function pointer from the literal. llvm::Value *FuncPtr = Builder.CreateStructGEP(BlockLiteral, 3, "tmp"); llvm::Value *Func = Builder.CreateLoad(FuncPtr, false, "tmp"); // Cast the function pointer to the right type. const llvm::Type *BlockFTy = ConvertType(getBlockFunctionType(getContext(), BPT)); const llvm::Type *BlockFTyPtr = llvm::PointerType::getUnqual(BlockFTy); Func = Builder.CreateBitCast(Func, BlockFTyPtr); BlockLiteral = Builder.CreateBitCast(BlockLiteral, llvm::PointerType::getUnqual(llvm::Type::Int8Ty), "tmp"); // Add the block literal. QualType VoidPtrTy = getContext().getPointerType(getContext().VoidTy); CallArgList Args; Args.push_back(std::make_pair(RValue::get(BlockLiteral), VoidPtrTy)); // And the rest of the arguments. for (CallExpr::const_arg_iterator i = E->arg_begin(), e = E->arg_end(); i != e; ++i) Args.push_back(std::make_pair(EmitAnyExprToTemp(*i), i->getType())); // And call the block. return EmitCall(CGM.getTypes().getFunctionInfo(E->getType(), Args), Func, Args); } llvm::Constant * CodeGenModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { // Generate the block descriptor. const llvm::Type *UnsignedLongTy = Types.ConvertType(Context.UnsignedLongTy); const llvm::IntegerType *IntTy = cast( getTypes().ConvertType(getContext().IntTy)); 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()) / 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, n); uint64_t subBlockSize, subBlockAlign; llvm::SmallVector subBlockDeclRefDecls; llvm::Function *Fn = CodeGenFunction(*this).GenerateBlockFunction(BE, Info, subBlockSize, subBlockAlign, subBlockDeclRefDecls); assert(subBlockSize == BlockLiteralSize && "no imports allowed for global block"); // isa LiteralFields[0] = getNSConcreteGlobalBlock(); // Flags LiteralFields[1] = llvm::ConstantInt::get(IntTy, BLOCK_IS_GLOBAL); // Reserved LiteralFields[2] = llvm::Constant::getNullValue(IntTy); // 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::Value *CodeGenFunction::LoadBlockStruct() { return Builder.CreateLoad(LocalDeclMap[getBlockStructDecl()], "self"); } llvm::Function *CodeGenFunction::GenerateBlockFunction(const BlockExpr *Expr, const BlockInfo& Info, uint64_t &Size, uint64_t &Align, llvm::SmallVector &subBlockDeclRefDecls) { 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())); BlockStructDecl = SelfDecl; for (BlockDecl::param_iterator i = BD->param_begin(), e = BD->param_end(); i != e; ++i) Args.push_back(std::make_pair(*i, (*i)->getType())); const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(FTy->getResultType(), Args); std::string Name = std::string("__") + Info.Name + "_block_invoke_"; 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()); // The runtime needs a minimum alignment of a void *. uint64_t MinAlign = getContext().getTypeAlign(getContext().VoidPtrTy) / 8; BlockOffset = llvm::RoundUpToAlignment(BlockOffset, MinAlign); Size = BlockOffset; Align = BlockAlign; subBlockDeclRefDecls = BlockDeclRefDecls; return Fn; }