"git@repo.hca.bsc.es:rferrer/llvm-epi-0.8.git" did not exist on "bc3b4e3f123403fb91d33293d1a5984d9585e4a7"
Newer
Older
//===--- 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"
Anders Carlsson
committed
#include "llvm/Target/TargetData.h"
#include <algorithm>
using namespace clang;
using namespace CodeGen;
Anders Carlsson
committed
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)
Anders Carlsson
committed
};
llvm::Constant *CodeGenFunction::BuildDescriptorBlockDecl() {
// FIXME: Push up.
bool BlockHasCopyDispose = false;
const llvm::PointerType *PtrToInt8Ty
= llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
const llvm::Type *UnsignedLongTy
= CGM.getTypes().ConvertType(getContext().UnsignedLongTy);
llvm::Constant *C;
std::vector<llvm::Constant*> Elts;
// reserved
Elts.push_back(C);
// Size
int sz;
if (!BlockHasCopyDispose)
sz = CGM.getTargetData()
.getTypeStoreSizeInBits(CGM.getGenericBlockLiteralType()) / 8;
else
sz = CGM.getTargetData()
.getTypeStoreSizeInBits(CGM.getGenericExtendedBlockLiteralType()) / 8;
Elts.push_back(C);
if (BlockHasCopyDispose) {
// copy_func_helper_decl
C = llvm::ConstantExpr::getBitCast(C, PtrToInt8Ty);
Elts.push_back(C);
// destroy_func_decl
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());
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::Constant *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
// FIXME: Push up
bool BlockHasCopyDispose = false;
bool insideFunction = false;
bool BlockRefDeclList = false;
bool BlockByrefDeclList = false;
std::vector<llvm::Constant*> Elts;
llvm::Constant *C;
{
// C = BuildBlockStructInitlist();
unsigned int flags = BLOCK_HAS_DESCRIPTOR;
if (BlockHasCopyDispose)
flags |= BLOCK_HAS_COPY_DISPOSE;
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<llvm::IntegerType>(
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
if (const NamedDecl *ND = dyn_cast<NamedDecl>(CurFuncDecl))
if (ND->getIdentifier())
Name = ND->getNameAsCString();
BlockInfo Info(0, Name);
llvm::Function *Fn = CodeGenFunction(*this).GenerateBlockFunction(BE, Info);
Elts.push_back(Fn);
// __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];
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;
}
const llvm::Type *CodeGenModule::getBlockDescriptorType() {
if (BlockDescriptorType)
return BlockDescriptorType;
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;
llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
llvm::PointerType::getUnqual(getBlockDescriptorType());
const llvm::IntegerType *IntTy = cast<llvm::IntegerType>(
getTypes().ConvertType(getContext().IntTy));
// void *__isa;
// int __flags;
// int __reserved;
// void (*__invoke)(void *);
// struct __block_descriptor *__descriptor;
// };
GenericBlockLiteralType = llvm::StructType::get(Int8PtrTy,
Int8PtrTy,
BlockDescPtrTy,
NULL);
getModule().addTypeName("struct.__block_literal_generic",
GenericBlockLiteralType);
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
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<llvm::IntegerType>(
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,
Anders Carlsson
committed
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(),
FTy->isVariadic(), 0);
}
Anders Carlsson
committed
RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) {
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.
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.
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();
// And call the block.
return EmitCall(CGM.getTypes().getFunctionInfo(E->getType(), Args),
Anders Carlsson
committed
llvm::Constant *
CodeGenModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
Anders Carlsson
committed
// Generate the block descriptor.
const llvm::Type *UnsignedLongTy = Types.ConvertType(Context.UnsignedLongTy);
const llvm::IntegerType *IntTy = cast<llvm::IntegerType>(
getTypes().ConvertType(getContext().IntTy));
Anders Carlsson
committed
llvm::Constant *DescriptorFields[2];
Anders Carlsson
committed
// Reserved
DescriptorFields[0] = llvm::Constant::getNullValue(UnsignedLongTy);
Anders Carlsson
committed
// Block literal size. For global blocks we just use the size of the generic
// block literal struct.
TheTargetData.getTypeStoreSizeInBits(getGenericBlockLiteralType()) / 8;
Anders Carlsson
committed
DescriptorFields[1] = llvm::ConstantInt::get(UnsignedLongTy,BlockLiteralSize);
Anders Carlsson
committed
llvm::ConstantStruct::get(&DescriptorFields[0], 2);
Anders Carlsson
committed
llvm::GlobalVariable *Descriptor =
new llvm::GlobalVariable(DescriptorStruct->getType(), true,
llvm::GlobalVariable::InternalLinkage,
DescriptorStruct, "__block_descriptor_global",
Anders Carlsson
committed
&getModule());
Anders Carlsson
committed
// Generate the constants for the block literal.
llvm::Constant *LiteralFields[5];
CodeGenFunction::BlockInfo Info(0, n);
Anders Carlsson
committed
llvm::Function *Fn = CodeGenFunction(*this).GenerateBlockFunction(BE, Info);
Anders Carlsson
committed
// isa
LiteralFields[0] = getNSConcreteGlobalBlock();
Anders Carlsson
committed
// Flags
LiteralFields[1] = llvm::ConstantInt::get(IntTy, BLOCK_IS_GLOBAL);
Anders Carlsson
committed
// Reserved
LiteralFields[2] = llvm::Constant::getNullValue(IntTy);
Anders Carlsson
committed
// Function
LiteralFields[3] = Fn;
Anders Carlsson
committed
// Descriptor
LiteralFields[4] = Descriptor;
Anders Carlsson
committed
llvm::ConstantStruct::get(&LiteralFields[0], 5);
Anders Carlsson
committed
new llvm::GlobalVariable(BlockLiteralStruct->getType(), true,
llvm::GlobalVariable::InternalLinkage,
BlockLiteralStruct, "__block_literal_global",
Anders Carlsson
committed
&getModule());
Anders Carlsson
committed
return BlockLiteral;
}
llvm::Function *CodeGenFunction::GenerateBlockFunction(const BlockExpr *Expr,
const BlockInfo& Info)
{
Anders Carlsson
committed
cast<FunctionTypeProto>(Expr->getFunctionType());
Anders Carlsson
committed
FunctionArgList Args;
Anders Carlsson
committed
const BlockDecl *BD = Expr->getBlockDecl();
// FIXME: This leaks
Anders Carlsson
committed
ImplicitParamDecl::Create(getContext(), 0,
SourceLocation(), 0,
getContext().getPointerType(getContext().VoidTy));
Anders Carlsson
committed
Args.push_back(std::make_pair(SelfDecl, SelfDecl->getType()));
for (BlockDecl::param_iterator i = BD->param_begin(),
Anders Carlsson
committed
e = BD->param_end(); i != e; ++i)
Args.push_back(std::make_pair(*i, (*i)->getType()));
Anders Carlsson
committed
CGM.getTypes().getFunctionInfo(FTy->getResultType(), Args);
std::string Name = std::string("__") + Info.Name + "_block_invoke_";
Anders Carlsson
committed
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, FTy->isVariadic());
Anders Carlsson
committed
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
Name,
&CGM.getModule());
Anders Carlsson
committed
Expr->getBody()->getLocEnd());
EmitStmt(Expr->getBody());
FinishFunction(cast<CompoundStmt>(Expr->getBody())->getRBracLoc());
return Fn;
}