diff options
Diffstat (limited to 'lib/CodeGen/CGBlocks.cpp')
-rw-r--r-- | lib/CodeGen/CGBlocks.cpp | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp new file mode 100644 index 0000000000..38aab2d3ac --- /dev/null +++ b/lib/CodeGen/CGBlocks.cpp @@ -0,0 +1,137 @@ +//===--- 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 <algorithm> + +using namespace clang; +using namespace CodeGen; + +static const llvm::Type *getBlockDescriptorType(CodeGenFunction &CGF) { + static const llvm::Type *Ty = 0; + + if (!Ty) { + const llvm::Type *UnsignedLongTy = + CGF.ConvertType(CGF.getContext().UnsignedLongTy); + + // struct __block_descriptor { + // unsigned long reserved; + // unsigned long block_size; + // }; + Ty = llvm::StructType::get(UnsignedLongTy, + UnsignedLongTy, + NULL); + + CGF.CGM.getModule().addTypeName("struct.__block_descriptor", Ty); + } + + return Ty; +} + +static const llvm::Type *getGenericBlockLiteralType(CodeGenFunction &CGF) { + static const llvm::Type *Ty = 0; + + if (!Ty) { + const llvm::Type *Int8PtrTy = + llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + + const llvm::Type *BlockDescPtrTy = + llvm::PointerType::getUnqual(getBlockDescriptorType(CGF)); + + // struct __block_literal_generic { + // void *isa; + // int flags; + // int reserved; + // void (*invoke)(void *); + // struct __block_descriptor *descriptor; + // }; + Ty = llvm::StructType::get(Int8PtrTy, + llvm::Type::Int32Ty, + llvm::Type::Int32Ty, + Int8PtrTy, + BlockDescPtrTy, + NULL); + + CGF.CGM.getModule().addTypeName("struct.__block_literal_generic", Ty); + } + + return Ty; +} + +/// 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<FunctionTypeProto>(BPT->getPointeeType()); + + llvm::SmallVector<QualType, 8> 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(getGenericBlockLiteralType(*this)); + + // 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, FuncPtr, "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); +} |