forked from OSchip/llvm-project
Improved ABI compliance for __block variables. No testcases yet as we
still give an unsupported error for them due to the fact this is a work in progress. llvm-svn: 66007
This commit is contained in:
parent
e08f4cb9a1
commit
97d01d50d9
|
@ -21,15 +21,6 @@
|
|||
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);
|
||||
|
@ -142,7 +133,11 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
|
|||
CollectBlockDeclRefInfo(BE->getBody(), Info);
|
||||
|
||||
// Check if the block can be global.
|
||||
if (CanBlockBeGlobal(Info))
|
||||
// FIXME: This test doesn't work for nested blocks yet. Longer
|
||||
// term, I'd like to just have one code path. We should move
|
||||
// this function into CGM and pass CGF, then we can just check to
|
||||
// see if CGF is 0.
|
||||
if (0 && CanBlockBeGlobal(Info))
|
||||
return CGM.GetAddrOfGlobalBlock(BE, Name.c_str());
|
||||
|
||||
std::vector<llvm::Constant*> Elts;
|
||||
|
@ -209,9 +204,11 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
|
|||
const Expr *E = subBlockDeclRefDecls[i];
|
||||
const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
|
||||
QualType Ty = E->getType();
|
||||
if (BDRE && BDRE->isByRef())
|
||||
Ty = getContext().getPointerType(Ty);
|
||||
Types[i+5] = ConvertType(Ty);
|
||||
if (BDRE && BDRE->isByRef()) {
|
||||
uint64_t Align = getContext().getDeclAlignInBytes(BDRE->getDecl());
|
||||
Types[i+5] = llvm::PointerType::get(BuildByRefType(Ty, Align), 0);
|
||||
} else
|
||||
Types[i+5] = ConvertType(Ty);
|
||||
}
|
||||
|
||||
llvm::Type *Ty = llvm::StructType::get(Types, true);
|
||||
|
@ -237,23 +234,41 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
|
|||
BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
|
||||
VD = BDRE->getDecl();
|
||||
|
||||
llvm::Value* Addr = Builder.CreateStructGEP(V, i+5, "tmp");
|
||||
// FIXME: I want a better way to do this.
|
||||
if (LocalDeclMap[VD]) {
|
||||
E = new (getContext()) DeclRefExpr (cast<NamedDecl>(VD),
|
||||
VD->getType(), SourceLocation(),
|
||||
false, false);
|
||||
if (BDRE->isByRef()) {
|
||||
const llvm::Type *Ty = Types[i+5];
|
||||
llvm::Value *Loc = LocalDeclMap[VD];
|
||||
Loc = Builder.CreateStructGEP(Loc, 1, "forwarding");
|
||||
Loc = Builder.CreateLoad(Loc, false);
|
||||
Loc = Builder.CreateBitCast(Loc, Ty);
|
||||
Builder.CreateStore(Loc, Addr);
|
||||
continue;
|
||||
} else
|
||||
E = new (getContext()) DeclRefExpr (cast<NamedDecl>(VD),
|
||||
VD->getType(), SourceLocation(),
|
||||
false, false);
|
||||
}
|
||||
if (BDRE->isByRef())
|
||||
if (BDRE->isByRef()) {
|
||||
// FIXME: __block in nested literals
|
||||
E = new (getContext())
|
||||
UnaryOperator(E, UnaryOperator::AddrOf,
|
||||
getContext().getPointerType(E->getType()),
|
||||
SourceLocation());
|
||||
}
|
||||
|
||||
llvm::Value* Addr = Builder.CreateStructGEP(V, i+5, "tmp");
|
||||
RValue r = EmitAnyExpr(E, Addr, false);
|
||||
if (r.isScalar())
|
||||
Builder.CreateStore(r.getScalarVal(), Addr);
|
||||
else if (r.isComplex())
|
||||
if (r.isScalar()) {
|
||||
llvm::Value *Loc = r.getScalarVal();
|
||||
const llvm::Type *Ty = Types[i+5];
|
||||
if (BDRE->isByRef()) {
|
||||
Loc = Builder.CreateBitCast(Loc, Ty);
|
||||
Loc = Builder.CreateStructGEP(Loc, 1, "forwarding");
|
||||
Loc = Builder.CreateBitCast(Loc, Ty);
|
||||
}
|
||||
Builder.CreateStore(Loc, Addr);
|
||||
} else if (r.isComplex())
|
||||
// FIXME: implement
|
||||
ErrorUnsupported(BE, "complex in block literal");
|
||||
else if (r.isAggregate())
|
||||
|
@ -426,6 +441,55 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) {
|
|||
Func, Args);
|
||||
}
|
||||
|
||||
llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
|
||||
uint64_t &offset = BlockDecls[E->getDecl()];
|
||||
|
||||
const llvm::Type *Ty;
|
||||
Ty = CGM.getTypes().ConvertType(E->getDecl()->getType());
|
||||
|
||||
// FIXME: add support for copy/dispose helpers.
|
||||
if (1 && E->isByRef())
|
||||
ErrorUnsupported(E, "__block variable in block literal");
|
||||
else if (E->getType()->isBlockPointerType())
|
||||
ErrorUnsupported(E, "block pointer in block literal");
|
||||
else if (E->getDecl()->getAttr<ObjCNSObjectAttr>() ||
|
||||
getContext().isObjCNSObjectType(E->getType()))
|
||||
ErrorUnsupported(E, "__attribute__((NSObject)) variable in block "
|
||||
"literal");
|
||||
else if (getContext().isObjCObjectPointerType(E->getType()))
|
||||
ErrorUnsupported(E, "Objective-C variable in block literal");
|
||||
|
||||
// See if we have already allocated an offset for this variable.
|
||||
if (offset == 0) {
|
||||
// if not, allocate one now.
|
||||
offset = getBlockOffset(E);
|
||||
}
|
||||
|
||||
llvm::Value *BlockLiteral = LoadBlockStruct();
|
||||
llvm::Value *V = Builder.CreateGEP(BlockLiteral,
|
||||
llvm::ConstantInt::get(llvm::Type::Int64Ty,
|
||||
offset),
|
||||
"tmp");
|
||||
if (E->isByRef()) {
|
||||
bool needsCopyDispose = BlockRequiresCopying(E->getType());
|
||||
uint64_t Align = getContext().getDeclAlignInBytes(E->getDecl());
|
||||
const llvm::Type *PtrStructTy
|
||||
= llvm::PointerType::get(BuildByRefType(E->getType(), Align), 0);
|
||||
Ty = PtrStructTy;
|
||||
Ty = llvm::PointerType::get(Ty, 0);
|
||||
V = Builder.CreateBitCast(V, Ty);
|
||||
V = Builder.CreateLoad(V, false);
|
||||
V = Builder.CreateStructGEP(V, 1, "forwarding");
|
||||
V = Builder.CreateLoad(V, false);
|
||||
V = Builder.CreateBitCast(V, PtrStructTy);
|
||||
V = Builder.CreateStructGEP(V, needsCopyDispose*2 + 4, "x");
|
||||
} else {
|
||||
Ty = llvm::PointerType::get(Ty, 0);
|
||||
V = Builder.CreateBitCast(V, Ty);
|
||||
}
|
||||
return V;
|
||||
}
|
||||
|
||||
llvm::Constant *
|
||||
CodeGenModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
|
||||
// Generate the block descriptor.
|
||||
|
@ -589,3 +653,23 @@ uint64_t CodeGenFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) {
|
|||
BlockOffset += Size;
|
||||
return BlockOffset-Size;
|
||||
}
|
||||
|
||||
llvm::Value *CodeGenFunction::BuildCopyHelper(int flag) {
|
||||
const llvm::PointerType *PtrToInt8Ty
|
||||
= llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
|
||||
// FIXME: implement
|
||||
llvm::Value *V = llvm::ConstantInt::get(llvm::Type::Int32Ty, 43);
|
||||
V = Builder.CreateIntToPtr(V, PtrToInt8Ty, "tmp");
|
||||
V = Builder.CreateBitCast(V, PtrToInt8Ty, "tmp");
|
||||
return V;
|
||||
}
|
||||
|
||||
llvm::Value *CodeGenFunction::BuildDestroyHelper(int flag) {
|
||||
const llvm::PointerType *PtrToInt8Ty
|
||||
= llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
|
||||
// FIXME: implement
|
||||
llvm::Value *V = llvm::ConstantInt::get(llvm::Type::Int32Ty, 44);
|
||||
V = Builder.CreateIntToPtr(V, PtrToInt8Ty, "tmp");
|
||||
V = Builder.CreateBitCast(V, PtrToInt8Ty, "tmp");
|
||||
return V;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "llvm/GlobalVariable.h"
|
||||
#include "llvm/Intrinsics.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#include "llvm/Type.h"
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
|
@ -188,20 +189,61 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) {
|
|||
}
|
||||
}
|
||||
|
||||
/// BuildByRefType - This routine changes a __block variable declared as T x
|
||||
/// into:
|
||||
///
|
||||
/// struct {
|
||||
/// void *__isa;
|
||||
/// void *__forwarding;
|
||||
/// int32_t __flags;
|
||||
/// int32_t __size;
|
||||
/// void *__copy_helper;
|
||||
/// void *__destroy_helper;
|
||||
/// T x;
|
||||
/// } x
|
||||
///
|
||||
/// Align is the alignment needed in bytes for x.
|
||||
const llvm::Type *CodeGenFunction::BuildByRefType(QualType Ty,
|
||||
uint64_t Align) {
|
||||
const llvm::Type *LTy = ConvertType(Ty);
|
||||
bool needsCopyDispose = BlockRequiresCopying(Ty);
|
||||
std::vector<const llvm::Type *> Types(needsCopyDispose*2+5);
|
||||
const llvm::PointerType *PtrToInt8Ty
|
||||
= llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
|
||||
Types[0] = PtrToInt8Ty;
|
||||
Types[1] = PtrToInt8Ty;
|
||||
Types[2] = llvm::Type::Int32Ty;
|
||||
Types[3] = llvm::Type::Int32Ty;
|
||||
if (needsCopyDispose) {
|
||||
Types[4] = PtrToInt8Ty;
|
||||
Types[5] = PtrToInt8Ty;
|
||||
}
|
||||
// FIXME: Align this on at least an Align boundary.
|
||||
Types[needsCopyDispose*2 + 4] = LTy;
|
||||
return llvm::StructType::get(Types, false);
|
||||
}
|
||||
|
||||
/// EmitLocalBlockVarDecl - Emit code and set up an entry in LocalDeclMap for a
|
||||
/// variable declaration with auto, register, or no storage class specifier.
|
||||
/// These turn into simple stack objects, or GlobalValues depending on target.
|
||||
void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
|
||||
QualType Ty = D.getType();
|
||||
bool isByRef = D.getAttr<BlocksAttr>();
|
||||
|
||||
llvm::Value *DeclPtr;
|
||||
if (Ty->isConstantSizeType()) {
|
||||
if (!Target.useGlobalsForAutomaticVariables()) {
|
||||
// A normal fixed sized variable becomes an alloca in the entry block.
|
||||
const llvm::Type *LTy = ConvertType(Ty);
|
||||
if (isByRef)
|
||||
LTy = BuildByRefType(Ty, getContext().getDeclAlignInBytes(&D));
|
||||
llvm::AllocaInst *Alloc =
|
||||
CreateTempAlloca(LTy, CGM.getMangledName(&D));
|
||||
Alloc->setAlignment(getContext().getDeclAlignInBytes(&D));
|
||||
if (isByRef)
|
||||
Alloc->setAlignment(std::max(getContext().getDeclAlignInBytes(&D),
|
||||
getContext().getTypeAlign(getContext().VoidPtrTy) / 8));
|
||||
else
|
||||
Alloc->setAlignment(getContext().getDeclAlignInBytes(&D));
|
||||
DeclPtr = Alloc;
|
||||
} else {
|
||||
// Targets that don't support recursion emit locals as globals.
|
||||
|
@ -259,18 +301,77 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
|
|||
// Emit debug info for local var declaration.
|
||||
if (CGDebugInfo *DI = getDebugInfo()) {
|
||||
DI->setLocation(D.getLocation());
|
||||
DI->EmitDeclareOfAutoVariable(&D, DeclPtr, Builder);
|
||||
if (isByRef) {
|
||||
llvm::Value *Loc;
|
||||
bool needsCopyDispose = BlockRequiresCopying(Ty);
|
||||
// FIXME: I think we need to indirect through the forwarding pointer first
|
||||
Loc = Builder.CreateStructGEP(DeclPtr, needsCopyDispose*2+4, "x");
|
||||
DI->EmitDeclareOfAutoVariable(&D, Loc, Builder);
|
||||
} else
|
||||
DI->EmitDeclareOfAutoVariable(&D, DeclPtr, Builder);
|
||||
}
|
||||
|
||||
// If this local has an initializer, emit it now.
|
||||
if (const Expr *Init = D.getInit()) {
|
||||
llvm::Value *Loc = DeclPtr;
|
||||
if (isByRef) {
|
||||
bool needsCopyDispose = BlockRequiresCopying(Ty);
|
||||
Loc = Builder.CreateStructGEP(DeclPtr, needsCopyDispose*2+4, "x");
|
||||
}
|
||||
if (!hasAggregateLLVMType(Init->getType())) {
|
||||
llvm::Value *V = EmitScalarExpr(Init);
|
||||
Builder.CreateStore(V, DeclPtr, D.getType().isVolatileQualified());
|
||||
Builder.CreateStore(V, Loc, D.getType().isVolatileQualified());
|
||||
} else if (Init->getType()->isAnyComplexType()) {
|
||||
EmitComplexExprIntoAddr(Init, DeclPtr, D.getType().isVolatileQualified());
|
||||
EmitComplexExprIntoAddr(Init, Loc, D.getType().isVolatileQualified());
|
||||
} else {
|
||||
EmitAggExpr(Init, DeclPtr, D.getType().isVolatileQualified());
|
||||
EmitAggExpr(Init, Loc, D.getType().isVolatileQualified());
|
||||
}
|
||||
}
|
||||
if (isByRef) {
|
||||
const llvm::PointerType *PtrToInt8Ty
|
||||
= llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
|
||||
|
||||
llvm::Value *isa_field = Builder.CreateStructGEP(DeclPtr, 0);
|
||||
llvm::Value *forwarding_field = Builder.CreateStructGEP(DeclPtr, 1);
|
||||
llvm::Value *flags_field = Builder.CreateStructGEP(DeclPtr, 2);
|
||||
llvm::Value *size_field = Builder.CreateStructGEP(DeclPtr, 3);
|
||||
llvm::Value *V;
|
||||
int flag = 0;
|
||||
int flags = 0;
|
||||
|
||||
if (Ty->isBlockPointerType()) {
|
||||
flag |= BLOCK_FIELD_IS_BLOCK;
|
||||
flags |= BLOCK_HAS_COPY_DISPOSE;
|
||||
} else if (BlockRequiresCopying(Ty)) {
|
||||
flags |= BLOCK_HAS_COPY_DISPOSE;
|
||||
flag |= BLOCK_FIELD_IS_OBJECT;
|
||||
}
|
||||
// FIXME: Need to set BLOCK_FIELD_IS_WEAK as appropriate.
|
||||
|
||||
int isa = 0;
|
||||
if (flag&BLOCK_FIELD_IS_WEAK)
|
||||
isa = 1;
|
||||
V = llvm::ConstantInt::get(llvm::Type::Int32Ty, isa);
|
||||
V = Builder.CreateIntToPtr(V, PtrToInt8Ty, "tmp");
|
||||
Builder.CreateStore(V, isa_field);
|
||||
|
||||
V = Builder.CreateBitCast(DeclPtr, PtrToInt8Ty, "tmp");
|
||||
Builder.CreateStore(V, forwarding_field);
|
||||
|
||||
V = llvm::ConstantInt::get(llvm::Type::Int32Ty, flags);
|
||||
Builder.CreateStore(V, flags_field);
|
||||
|
||||
const llvm::Type *V1 = cast<llvm::PointerType>(DeclPtr->getType())->getElementType();
|
||||
V = llvm::ConstantInt::get(llvm::Type::Int32Ty, CGM.getTargetData().getTypeStoreSizeInBits(V1) / 8);
|
||||
Builder.CreateStore(V, size_field);
|
||||
|
||||
if (flags & BLOCK_HAS_COPY_DISPOSE) {
|
||||
llvm::Value *copy_helper = Builder.CreateStructGEP(DeclPtr, 4);
|
||||
llvm::Value *destroy_helper = Builder.CreateStructGEP(DeclPtr, 5);
|
||||
|
||||
Builder.CreateStore(BuildCopyHelper(flag), copy_helper);
|
||||
|
||||
Builder.CreateStore(BuildDestroyHelper(flag), destroy_helper);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -636,6 +636,17 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
|
|||
// local static?
|
||||
if (!VD->hasLocalStorage())
|
||||
attr = getContext().getObjCGCAttrKind(E->getType());
|
||||
if (VD->getAttr<BlocksAttr>()) {
|
||||
bool needsCopyDispose = BlockRequiresCopying(VD->getType());
|
||||
const llvm::Type *PtrStructTy = V->getType();
|
||||
const llvm::Type *Ty = PtrStructTy;
|
||||
Ty = llvm::PointerType::get(Ty, 0);
|
||||
V = Builder.CreateStructGEP(V, 1, "forwarding");
|
||||
V = Builder.CreateBitCast(V, Ty);
|
||||
V = Builder.CreateLoad(V, false);
|
||||
V = Builder.CreateBitCast(V, PtrStructTy);
|
||||
V = Builder.CreateStructGEP(V, needsCopyDispose*2 + 4, "x");
|
||||
}
|
||||
LV = LValue::MakeAddr(V, E->getType().getCVRQualifiers(), attr);
|
||||
}
|
||||
LValue::SetObjCNonGC(LV, VD->hasLocalStorage());
|
||||
|
@ -667,45 +678,6 @@ LValue CodeGenFunction::EmitBlockDeclRefLValue(const BlockDeclRefExpr *E) {
|
|||
return LValue::MakeAddr(GetAddrOfBlockDecl(E), 0);
|
||||
}
|
||||
|
||||
llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
|
||||
// FIXME: ensure we don't need copy/dispose.
|
||||
uint64_t &offset = BlockDecls[E->getDecl()];
|
||||
|
||||
const llvm::Type *Ty;
|
||||
Ty = CGM.getTypes().ConvertType(E->getDecl()->getType());
|
||||
|
||||
if (E->isByRef())
|
||||
ErrorUnsupported(E, "__block variable in block literal");
|
||||
else if (E->getType()->isBlockPointerType())
|
||||
ErrorUnsupported(E, "block pointer in block literal");
|
||||
else if (E->getDecl()->getAttr<ObjCNSObjectAttr>() ||
|
||||
getContext().isObjCNSObjectType(E->getType()))
|
||||
ErrorUnsupported(E, "__attribute__((NSObject)) variable in block "
|
||||
"literal");
|
||||
else if (getContext().isObjCObjectPointerType(E->getType()))
|
||||
ErrorUnsupported(E, "Objective-C variable in block literal");
|
||||
|
||||
// See if we have already allocated an offset for this variable.
|
||||
if (offset == 0) {
|
||||
// if not, allocate one now.
|
||||
offset = getBlockOffset(E);
|
||||
}
|
||||
|
||||
llvm::Value *BlockLiteral = LoadBlockStruct();
|
||||
llvm::Value *V = Builder.CreateGEP(BlockLiteral,
|
||||
llvm::ConstantInt::get(llvm::Type::Int64Ty,
|
||||
offset),
|
||||
"tmp");
|
||||
Ty = llvm::PointerType::get(Ty, 0);
|
||||
if (E->isByRef())
|
||||
Ty = llvm::PointerType::get(Ty, 0);
|
||||
V = Builder.CreateBitCast(V, Ty);
|
||||
if (E->isByRef())
|
||||
V = Builder.CreateLoad(V, false, "tmp");
|
||||
|
||||
return V;
|
||||
}
|
||||
|
||||
LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
|
||||
// __extension__ doesn't affect lvalue-ness.
|
||||
if (E->getOpcode() == UnaryOperator::Extension)
|
||||
|
|
|
@ -264,6 +264,30 @@ public:
|
|||
// Block Bits
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
enum {
|
||||
BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)),
|
||||
block, ... */
|
||||
BLOCK_FIELD_IS_BLOCK = 7, /* a block variable */
|
||||
BLOCK_FIELD_IS_BYREF = 8, /* the on stack structure holding the __block
|
||||
variable */
|
||||
BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy
|
||||
helpers */
|
||||
BLOCK_BYREF_CALLER = 128 /* called from __block (byref) copy/dispose
|
||||
support routines */
|
||||
};
|
||||
|
||||
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::Value *BuildCopyHelper(int flag);
|
||||
llvm::Value *BuildDestroyHelper(int flag);
|
||||
|
||||
llvm::Value *BuildBlockLiteralTmp(const BlockExpr *);
|
||||
llvm::Constant *BuildDescriptorBlockDecl(uint64_t Size);
|
||||
|
||||
|
@ -319,6 +343,15 @@ public:
|
|||
|
||||
llvm::Value *GetAddrOfBlockDecl(const BlockDeclRefExpr *E);
|
||||
|
||||
const llvm::Type *BuildByRefType(QualType Ty, uint64_t Align);
|
||||
bool BlockRequiresCopying(QualType Ty) {
|
||||
if (Ty->isBlockPointerType())
|
||||
return true;
|
||||
if (getContext().isObjCNSObjectType(Ty))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void GenerateCode(const FunctionDecl *FD,
|
||||
llvm::Function *Fn);
|
||||
void StartFunction(const Decl *D, QualType RetTy,
|
||||
|
|
|
@ -139,6 +139,15 @@ class CodeGenModule {
|
|||
/// strings. This value has type int * but is actually an Obj-C class pointer.
|
||||
llvm::Constant *CFConstantStringClassRef;
|
||||
|
||||
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)
|
||||
};
|
||||
|
||||
/// NSConcreteGlobalBlock - Cached reference to the class pointer for global
|
||||
/// blocks.
|
||||
llvm::Constant *NSConcreteGlobalBlock;
|
||||
|
|
Loading…
Reference in New Issue