diff options
-rw-r--r-- | clang.xcodeproj/project.pbxproj | 4 | ||||
-rw-r--r-- | lib/CodeGen/CGBlocks.cpp | 137 | ||||
-rw-r--r-- | lib/CodeGen/CGExpr.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 2 |
4 files changed, 144 insertions, 1 deletions
diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index d95aa2b342..566002413e 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -12,6 +12,7 @@ 1A30A9E90B93A4C800201A91 /* ExprCXX.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1A30A9E80B93A4C800201A91 /* ExprCXX.h */; }; 1A32C17F0E1C87AD00A6B483 /* ExprConstant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A32C17E0E1C87AD00A6B483 /* ExprConstant.cpp */; }; 1A376A2D0D4AED9B002A1C52 /* CGExprConstant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A376A2C0D4AED9B002A1C52 /* CGExprConstant.cpp */; }; + 1A471AB50F437BC500753CE8 /* CGBlocks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A471AB40F437BC500753CE8 /* CGBlocks.cpp */; }; 1A5D5E580E5E81010023C059 /* CGCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A5D5E570E5E81010023C059 /* CGCXX.cpp */; }; 1A7342480C7B57D500122F56 /* CGObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A7342470C7B57D500122F56 /* CGObjC.cpp */; }; 1A869A700BA2164C008DA07A /* LiteralSupport.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */; }; @@ -291,6 +292,7 @@ 1A30A9E80B93A4C800201A91 /* ExprCXX.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ExprCXX.h; path = clang/AST/ExprCXX.h; sourceTree = "<group>"; tabWidth = 2; }; 1A32C17E0E1C87AD00A6B483 /* ExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ExprConstant.cpp; path = lib/AST/ExprConstant.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1A376A2C0D4AED9B002A1C52 /* CGExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprConstant.cpp; path = lib/CodeGen/CGExprConstant.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1A471AB40F437BC500753CE8 /* CGBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGBlocks.cpp; path = lib/CodeGen/CGBlocks.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1A5D5E570E5E81010023C059 /* CGCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXX.cpp; path = lib/CodeGen/CGCXX.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1A68BC110D0CADDD001A28C8 /* PPCBuiltins.def */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = text; name = PPCBuiltins.def; path = clang/AST/PPCBuiltins.def; sourceTree = "<group>"; tabWidth = 2; }; 1A68BC120D0CADDD001A28C8 /* TargetBuiltins.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TargetBuiltins.h; path = clang/AST/TargetBuiltins.h; sourceTree = "<group>"; tabWidth = 2; }; @@ -919,6 +921,7 @@ DE927FCC0C0557CD00231DA4 /* CodeGen */ = { isa = PBXGroup; children = ( + 1A471AB40F437BC500753CE8 /* CGBlocks.cpp */, DE8822350EC80C0A00CBC30A /* CGBuilder.h */, 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */, 35475B220E7997680000BFE4 /* CGCall.h */, @@ -1391,6 +1394,7 @@ 3591853F0EFB1088000039AF /* SemaTemplate.cpp in Sources */, 357EA27D0F2526F300439B60 /* SemaLookup.cpp in Sources */, DEB076CF0F3A222200F5A2BE /* DeclTemplate.cpp in Sources */, + 1A471AB50F437BC500753CE8 /* CGBlocks.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 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); +} diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 4d6c3f1c28..7ef6fdf2af 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -968,7 +968,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) { return EmitBuiltinExpr(builtinID, E); if (E->getCallee()->getType()->isBlockPointerType()) - return EmitUnsupportedRValue(E, "block pointer reference"); + return EmitBlockCallExpr(E); llvm::Value *Callee = EmitScalarExpr(E->getCallee()); return EmitCallExpr(Callee, E->getCallee()->getType(), diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 39f1c1d6ca..f6196fe64f 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -611,6 +611,8 @@ public: RValue EmitBuiltinExpr(unsigned BuiltinID, const CallExpr *E); + RValue EmitBlockCallExpr(const CallExpr *E); + /// EmitTargetBuiltinExpr - Emit the given builtin call. Returns 0 if the call /// is unhandled by the current target. llvm::Value *EmitTargetBuiltinExpr(unsigned BuiltinID, const CallExpr *E); |