[cfe-commits] r66007 - in /cfe/trunk/lib/CodeGen: CGBlocks.cpp CGDecl.cpp CGExpr.cpp CodeGenFunction.h CodeGenModule.h
Mike Stump
mrs at apple.com
Tue Mar 3 19:23:47 PST 2009
Author: mrs
Date: Tue Mar 3 21:23:46 2009
New Revision: 66007
URL: http://llvm.org/viewvc/llvm-project?rev=66007&view=rev
Log:
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.
Modified:
cfe/trunk/lib/CodeGen/CGBlocks.cpp
cfe/trunk/lib/CodeGen/CGDecl.cpp
cfe/trunk/lib/CodeGen/CGExpr.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.h
cfe/trunk/lib/CodeGen/CodeGenModule.h
Modified: cfe/trunk/lib/CodeGen/CGBlocks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBlocks.cpp?rev=66007&r1=66006&r2=66007&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGBlocks.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGBlocks.cpp Tue Mar 3 21:23:46 2009
@@ -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 @@
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 @@
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 @@
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 @@
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 @@
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;
+}
Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=66007&r1=66006&r2=66007&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Tue Mar 3 21:23:46 2009
@@ -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 @@
}
}
+/// 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 @@
// 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);
}
}
Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=66007&r1=66006&r2=66007&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Tue Mar 3 21:23:46 2009
@@ -636,6 +636,17 @@
// 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 @@
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)
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=66007&r1=66006&r2=66007&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Tue Mar 3 21:23:46 2009
@@ -264,6 +264,30 @@
// 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 @@
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,
Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=66007&r1=66006&r2=66007&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.h Tue Mar 3 21:23:46 2009
@@ -139,6 +139,15 @@
/// 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;
More information about the cfe-commits
mailing list