Add a very basic implemenation of global blocks. This needs to be cleaned up.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64387 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 38aab2d..9aa5207 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -14,18 +14,24 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "llvm/Module.h"
+#include "llvm/Target/TargetData.h"
#include <algorithm>
using namespace clang;
using namespace CodeGen;
-static const llvm::Type *getBlockDescriptorType(CodeGenFunction &CGF) {
+// Block flags
+enum {
+ IsGlobal = 1 << 28
+};
+
+static const llvm::Type *getBlockDescriptorType(CodeGenModule &CGM) {
static const llvm::Type *Ty = 0;
if (!Ty) {
const llvm::Type *UnsignedLongTy =
- CGF.ConvertType(CGF.getContext().UnsignedLongTy);
+ CGM.getTypes().ConvertType(CGM.getContext().UnsignedLongTy);
// struct __block_descriptor {
// unsigned long reserved;
@@ -35,13 +41,13 @@
UnsignedLongTy,
NULL);
- CGF.CGM.getModule().addTypeName("struct.__block_descriptor", Ty);
+ CGM.getModule().addTypeName("struct.__block_descriptor", Ty);
}
return Ty;
}
-static const llvm::Type *getGenericBlockLiteralType(CodeGenFunction &CGF) {
+static const llvm::Type *getGenericBlockLiteralType(CodeGenModule &CGM) {
static const llvm::Type *Ty = 0;
if (!Ty) {
@@ -49,7 +55,7 @@
llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
const llvm::Type *BlockDescPtrTy =
- llvm::PointerType::getUnqual(getBlockDescriptorType(CGF));
+ llvm::PointerType::getUnqual(getBlockDescriptorType(CGM));
// struct __block_literal_generic {
// void *isa;
@@ -65,7 +71,7 @@
BlockDescPtrTy,
NULL);
- CGF.CGM.getModule().addTypeName("struct.__block_literal_generic", Ty);
+ CGM.getModule().addTypeName("struct.__block_literal_generic", Ty);
}
return Ty;
@@ -74,8 +80,7 @@
/// 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 BlockPointerType *BPT) {
const FunctionTypeProto *FTy = cast<FunctionTypeProto>(BPT->getPointeeType());
llvm::SmallVector<QualType, 8> Types;
@@ -90,8 +95,7 @@
FTy->isVariadic(), 0);
}
-RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E)
-{
+RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) {
const BlockPointerType *BPT =
E->getCallee()->getType()->getAsBlockPointerType();
@@ -99,7 +103,7 @@
// Get a pointer to the generic block literal.
const llvm::Type *BlockLiteralTy =
- llvm::PointerType::getUnqual(getGenericBlockLiteralType(*this));
+ llvm::PointerType::getUnqual(getGenericBlockLiteralType(CGM));
// Bitcast the callee to a block literal.
llvm::Value *BlockLiteral =
@@ -135,3 +139,117 @@
return EmitCall(CGM.getTypes().getFunctionInfo(E->getType(), Args),
Func, Args);
}
+
+llvm::Constant *CodeGenModule::GetAddrOfGlobalBlock(const BlockExpr *BE) {
+ if (!NSConcreteGlobalBlock) {
+ const llvm::Type *Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+
+ // FIXME: Wee 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(Ty, false,
+ llvm::GlobalVariable::ExternalLinkage, 0,
+ "_NSConcreteGlobalBlock", &getModule());
+ }
+
+ // Generate the block descriptor.
+ const llvm::Type *UnsignedLongTy = Types.ConvertType(Context.UnsignedLongTy);
+
+ 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(*this)) / 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, "global");
+ llvm::Function *Fn = CodeGenFunction(*this).GenerateBlockFunction(BE, Info);
+
+ // isa
+ LiteralFields[0] = NSConcreteGlobalBlock;
+
+ // Flags
+ LiteralFields[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, IsGlobal);
+
+ // Reserved
+ LiteralFields[2] = llvm::Constant::getNullValue(llvm::Type::Int32Ty);
+
+ // 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::Function *CodeGenFunction::GenerateBlockFunction(const BlockExpr *Expr,
+ const BlockInfo& Info)
+{
+ const FunctionTypeProto *FTy =
+ cast<FunctionTypeProto>(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()));
+
+ for (BlockDecl::param_iterator i = BD->param_begin(),
+ e = BD->param_end(); i != e; ++i)
+ Args.push_back(std::make_pair(*e, (*e)->getType()));
+
+ const CGFunctionInfo &FI =
+ CGM.getTypes().getFunctionInfo(FTy->getResultType(), Args);
+
+ std::string Name = std::string("__block_function_") + Info.NameSuffix;
+
+ 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<CompoundStmt>(Expr->getBody())->getRBracLoc());
+
+ return Fn;
+}
+
+