summaryrefslogtreecommitdiffstats
path: root/lib/CodeGen/CGBlocks.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen/CGBlocks.cpp')
-rw-r--r--lib/CodeGen/CGBlocks.cpp483
1 files changed, 284 insertions, 199 deletions
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 8082b33..de58597 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -24,6 +24,45 @@
using namespace clang;
using namespace CodeGen;
+/// CGBlockInfo - Information to generate a block literal.
+class clang::CodeGen::CGBlockInfo {
+public:
+ /// Name - The name of the block, kindof.
+ const char *Name;
+
+ /// DeclRefs - Variables from parent scopes that have been
+ /// imported into this block.
+ llvm::SmallVector<const BlockDeclRefExpr *, 8> DeclRefs;
+
+ /// InnerBlocks - This block and the blocks it encloses.
+ llvm::SmallPtrSet<const DeclContext *, 4> InnerBlocks;
+
+ /// CXXThisRef - Non-null if 'this' was required somewhere, in
+ /// which case this is that expression.
+ const CXXThisExpr *CXXThisRef;
+
+ /// NeedsObjCSelf - True if something in this block has an implicit
+ /// reference to 'self'.
+ bool NeedsObjCSelf;
+
+ /// These are initialized by GenerateBlockFunction.
+ bool BlockHasCopyDispose;
+ CharUnits BlockSize;
+ CharUnits BlockAlign;
+ llvm::SmallVector<const Expr*, 8> BlockLayout;
+
+ CGBlockInfo(const char *Name);
+};
+
+CGBlockInfo::CGBlockInfo(const char *N)
+ : Name(N), CXXThisRef(0), NeedsObjCSelf(false) {
+
+ // Skip asm prefix, if any.
+ if (Name && Name[0] == '\01')
+ ++Name;
+}
+
+
llvm::Constant *CodeGenFunction::
BuildDescriptorBlockDecl(const BlockExpr *BE, bool BlockHasCopyDispose, CharUnits Size,
const llvm::StructType* Ty,
@@ -86,58 +125,86 @@ llvm::Constant *BlockModule::getNSConcreteStackBlock() {
return NSConcreteStackBlock;
}
-static void CollectBlockDeclRefInfo(
- const Stmt *S, CodeGenFunction::BlockInfo &Info,
- llvm::SmallSet<const DeclContext *, 16> &InnerContexts) {
+static void CollectBlockDeclRefInfo(const Stmt *S, CGBlockInfo &Info) {
for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end();
I != E; ++I)
if (*I)
- CollectBlockDeclRefInfo(*I, Info, InnerContexts);
+ CollectBlockDeclRefInfo(*I, Info);
// We want to ensure we walk down into block literals so we can find
// all nested BlockDeclRefExprs.
if (const BlockExpr *BE = dyn_cast<BlockExpr>(S)) {
- InnerContexts.insert(cast<DeclContext>(BE->getBlockDecl()));
- CollectBlockDeclRefInfo(BE->getBody(), Info, InnerContexts);
+ Info.InnerBlocks.insert(BE->getBlockDecl());
+ CollectBlockDeclRefInfo(BE->getBody(), Info);
}
- if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) {
+ else if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) {
+ const ValueDecl *D = BDRE->getDecl();
// FIXME: Handle enums.
- if (isa<FunctionDecl>(BDRE->getDecl()))
+ if (isa<FunctionDecl>(D))
return;
+ if (isa<ImplicitParamDecl>(D) &&
+ isa<ObjCMethodDecl>(D->getDeclContext()) &&
+ cast<ObjCMethodDecl>(D->getDeclContext())->getSelfDecl() == D) {
+ Info.NeedsObjCSelf = true;
+ return;
+ }
+
// Only Decls that escape are added.
- if (!InnerContexts.count(BDRE->getDecl()->getDeclContext()))
+ if (!Info.InnerBlocks.count(D->getDeclContext()))
Info.DeclRefs.push_back(BDRE);
}
+
+ // Make sure to capture implicit 'self' references due to super calls.
+ else if (const ObjCMessageExpr *E = dyn_cast<ObjCMessageExpr>(S)) {
+ if (E->getReceiverKind() == ObjCMessageExpr::SuperClass ||
+ E->getReceiverKind() == ObjCMessageExpr::SuperInstance)
+ Info.NeedsObjCSelf = true;
+ }
+
+ // Getter/setter uses may also cause implicit super references,
+ // which we can check for with:
+ else if (isa<ObjCSuperExpr>(S))
+ Info.NeedsObjCSelf = true;
+
+ else if (isa<CXXThisExpr>(S))
+ Info.CXXThisRef = cast<CXXThisExpr>(S);
}
-/// CanBlockBeGlobal - Given a BlockInfo struct, determines if a block can be
+/// CanBlockBeGlobal - Given a CGBlockInfo struct, determines if a block can be
/// declared as a global variable instead of on the stack.
-static bool CanBlockBeGlobal(const CodeGenFunction::BlockInfo &Info) {
+static bool CanBlockBeGlobal(const CGBlockInfo &Info) {
return Info.DeclRefs.empty();
}
/// AllocateAllBlockDeclRefs - Preallocate all nested BlockDeclRefExprs to
/// ensure we can generate the debug information for the parameter for the block
/// invoke function.
-static void AllocateAllBlockDeclRefs(const CodeGenFunction::BlockInfo &Info,
- CodeGenFunction *CGF) {
- // FIXME: Also always forward the this pointer in C++ as well.
+static void AllocateAllBlockDeclRefs(CodeGenFunction &CGF, CGBlockInfo &Info) {
+ if (Info.CXXThisRef)
+ CGF.AllocateBlockCXXThisPointer(Info.CXXThisRef);
for (size_t i = 0; i < Info.DeclRefs.size(); ++i)
- CGF->AllocateBlockDecl(Info.DeclRefs[i]);
+ CGF.AllocateBlockDecl(Info.DeclRefs[i]);
+
+ if (Info.NeedsObjCSelf) {
+ ValueDecl *Self = cast<ObjCMethodDecl>(CGF.CurFuncDecl)->getSelfDecl();
+ BlockDeclRefExpr *BDRE =
+ new (CGF.getContext()) BlockDeclRefExpr(Self, Self->getType(),
+ SourceLocation(), false);
+ Info.DeclRefs.push_back(BDRE);
+ CGF.AllocateBlockDecl(BDRE);
+ }
}
// FIXME: Push most into CGM, passing down a few bits, like current function
// name.
llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
-
std::string Name = CurFn->getName();
- CodeGenFunction::BlockInfo Info(0, Name.c_str());
- llvm::SmallSet<const DeclContext *, 16> InnerContexts;
- InnerContexts.insert(BE->getBlockDecl());
- CollectBlockDeclRefInfo(BE->getBody(), Info, InnerContexts);
+ CGBlockInfo Info(Name.c_str());
+ Info.InnerBlocks.insert(BE->getBlockDecl());
+ CollectBlockDeclRefInfo(BE->getBody(), Info);
// Check if the block can be global.
// FIXME: This test doesn't work for nested blocks yet. Longer term, I'd like
@@ -160,23 +227,15 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
// We run this first so that we set BlockHasCopyDispose from the entire
// block literal.
// __invoke
- CharUnits subBlockSize;
- CharUnits subBlockAlign;
- llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls;
- bool subBlockHasCopyDispose = false;
llvm::Function *Fn
= CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, CurFuncDecl,
- LocalDeclMap,
- subBlockSize,
- subBlockAlign,
- subBlockDeclRefDecls,
- subBlockHasCopyDispose);
- BlockHasCopyDispose |= subBlockHasCopyDispose;
+ LocalDeclMap);
+ BlockHasCopyDispose |= Info.BlockHasCopyDispose;
Elts[3] = Fn;
// FIXME: Don't use BlockHasCopyDispose, it is set more often then
// necessary, for example: { ^{ __block int i; ^{ i = 1; }(); }(); }
- if (subBlockHasCopyDispose)
+ if (Info.BlockHasCopyDispose)
flags |= BLOCK_HAS_COPY_DISPOSE;
// __isa
@@ -206,10 +265,10 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
C = llvm::ConstantInt::get(IntTy, 0);
Elts[2] = C;
- if (subBlockDeclRefDecls.size() == 0) {
+ if (Info.BlockLayout.empty()) {
// __descriptor
- Elts[4] = BuildDescriptorBlockDecl(BE, subBlockHasCopyDispose, subBlockSize,
- 0, 0);
+ Elts[4] = BuildDescriptorBlockDecl(BE, Info.BlockHasCopyDispose,
+ Info.BlockSize, 0, 0);
// Optimize to being a global block.
Elts[0] = CGM.getNSConcreteGlobalBlock();
@@ -227,13 +286,13 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
return C;
}
- std::vector<const llvm::Type *> Types(BlockFields+subBlockDeclRefDecls.size());
+ std::vector<const llvm::Type *> Types(BlockFields+Info.BlockLayout.size());
for (int i=0; i<4; ++i)
Types[i] = Elts[i]->getType();
Types[4] = PtrToInt8Ty;
- for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i) {
- const Expr *E = subBlockDeclRefDecls[i];
+ for (unsigned i = 0, n = Info.BlockLayout.size(); i != n; ++i) {
+ const Expr *E = Info.BlockLayout[i];
const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
QualType Ty = E->getType();
if (BDRE && BDRE->isByRef()) {
@@ -245,105 +304,113 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
llvm::StructType *Ty = llvm::StructType::get(VMContext, Types, true);
llvm::AllocaInst *A = CreateTempAlloca(Ty);
- A->setAlignment(subBlockAlign.getQuantity());
+ A->setAlignment(Info.BlockAlign.getQuantity());
V = A;
- std::vector<HelperInfo> NoteForHelper(subBlockDeclRefDecls.size());
- int helpersize = 0;
+ // Build layout / cleanup information for all the data entries in the
+ // layout, and write the enclosing fields into the type.
+ std::vector<HelperInfo> NoteForHelper(Info.BlockLayout.size());
+ unsigned NumHelpers = 0;
for (unsigned i=0; i<4; ++i)
Builder.CreateStore(Elts[i], Builder.CreateStructGEP(V, i, "block.tmp"));
- for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i)
- {
- // FIXME: Push const down.
- Expr *E = const_cast<Expr*>(subBlockDeclRefDecls[i]);
- DeclRefExpr *DR;
- ValueDecl *VD;
-
- DR = dyn_cast<DeclRefExpr>(E);
- // Skip padding.
- if (DR) continue;
-
- BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
- VD = BDRE->getDecl();
-
- llvm::Value* Addr = Builder.CreateStructGEP(V, i+BlockFields, "tmp");
- NoteForHelper[helpersize].index = i+5;
- NoteForHelper[helpersize].RequiresCopying
- = BlockRequiresCopying(VD->getType());
- NoteForHelper[helpersize].flag
- = (VD->getType()->isBlockPointerType()
- ? BLOCK_FIELD_IS_BLOCK
- : BLOCK_FIELD_IS_OBJECT);
-
- if (LocalDeclMap[VD]) {
- if (BDRE->isByRef()) {
- NoteForHelper[helpersize].flag = BLOCK_FIELD_IS_BYREF |
- // FIXME: Someone double check this.
- (VD->getType().isObjCGCWeak() ? BLOCK_FIELD_IS_WEAK : 0);
- llvm::Value *Loc = LocalDeclMap[VD];
- Loc = Builder.CreateStructGEP(Loc, 1, "forwarding");
- Loc = Builder.CreateLoad(Loc);
- Builder.CreateStore(Loc, Addr);
- ++helpersize;
- continue;
- } else
- E = new (getContext()) DeclRefExpr (VD,
- VD->getType(),
- SourceLocation());
- }
+ for (unsigned i=0; i < Info.BlockLayout.size(); ++i) {
+ const Expr *E = Info.BlockLayout[i];
+
+ // Skip padding.
+ if (isa<DeclRefExpr>(E)) continue;
+
+ llvm::Value* Addr = Builder.CreateStructGEP(V, i+BlockFields, "tmp");
+ HelperInfo &Note = NoteForHelper[NumHelpers++];
+
+ Note.index = i+5;
+
+ if (isa<CXXThisExpr>(E)) {
+ Note.RequiresCopying = false;
+ Note.flag = BLOCK_FIELD_IS_OBJECT;
+
+ Builder.CreateStore(LoadCXXThis(), Addr);
+ continue;
+ }
+
+ const BlockDeclRefExpr *BDRE = cast<BlockDeclRefExpr>(E);
+ const ValueDecl *VD = BDRE->getDecl();
+ QualType T = VD->getType();
+
+ Note.RequiresCopying = BlockRequiresCopying(T);
+
+ if (BDRE->isByRef()) {
+ Note.flag = BLOCK_FIELD_IS_BYREF;
+ if (T.isObjCGCWeak())
+ Note.flag |= BLOCK_FIELD_IS_WEAK;
+ } else if (T->isBlockPointerType()) {
+ Note.flag = BLOCK_FIELD_IS_BLOCK;
+ } else {
+ Note.flag = BLOCK_FIELD_IS_OBJECT;
+ }
+
+ if (LocalDeclMap[VD]) {
if (BDRE->isByRef()) {
- NoteForHelper[helpersize].flag = BLOCK_FIELD_IS_BYREF |
- // FIXME: Someone double check this.
- (VD->getType().isObjCGCWeak() ? BLOCK_FIELD_IS_WEAK : 0);
- E = new (getContext())
- UnaryOperator(E, UnaryOperator::AddrOf,
- getContext().getPointerType(E->getType()),
- SourceLocation());
- }
- ++helpersize;
-
- RValue r = EmitAnyExpr(E, Addr, false);
- if (r.isScalar()) {
- llvm::Value *Loc = r.getScalarVal();
- const llvm::Type *Ty = Types[i+BlockFields];
- if (BDRE->isByRef()) {
- // E is now the address of the value field, instead, we want the
- // address of the actual ByRef struct. We optimize this slightly
- // compared to gcc by not grabbing the forwarding slot as this must
- // be done during Block_copy for us, and we can postpone the work
- // until then.
- CharUnits offset = BlockDecls[BDRE->getDecl()];
-
- llvm::Value *BlockLiteral = LoadBlockStruct();
-
- Loc = Builder.CreateGEP(BlockLiteral,
- llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- offset.getQuantity()),
- "block.literal");
- Ty = llvm::PointerType::get(Ty, 0);
- Loc = Builder.CreateBitCast(Loc, Ty);
- Loc = Builder.CreateLoad(Loc);
- // Loc = Builder.CreateBitCast(Loc, Ty);
- }
+ llvm::Value *Loc = LocalDeclMap[VD];
+ Loc = Builder.CreateStructGEP(Loc, 1, "forwarding");
+ Loc = Builder.CreateLoad(Loc);
Builder.CreateStore(Loc, Addr);
- } else if (r.isComplex())
- // FIXME: implement
- ErrorUnsupported(BE, "complex in block literal");
- else if (r.isAggregate())
- ; // Already created into the destination
- else
- assert (0 && "bad block variable");
- // FIXME: Ensure that the offset created by the backend for
- // the struct matches the previously computed offset in BlockDecls.
+ continue;
+ } else {
+ E = new (getContext()) DeclRefExpr(const_cast<ValueDecl*>(VD),
+ VD->getType(),
+ SourceLocation());
+ }
}
- NoteForHelper.resize(helpersize);
+
+ if (BDRE->isByRef()) {
+ E = new (getContext())
+ UnaryOperator(const_cast<Expr*>(E), UnaryOperator::AddrOf,
+ getContext().getPointerType(E->getType()),
+ SourceLocation());
+ }
+
+ RValue r = EmitAnyExpr(E, Addr, false);
+ if (r.isScalar()) {
+ llvm::Value *Loc = r.getScalarVal();
+ const llvm::Type *Ty = Types[i+BlockFields];
+ if (BDRE->isByRef()) {
+ // E is now the address of the value field, instead, we want the
+ // address of the actual ByRef struct. We optimize this slightly
+ // compared to gcc by not grabbing the forwarding slot as this must
+ // be done during Block_copy for us, and we can postpone the work
+ // until then.
+ CharUnits offset = BlockDecls[BDRE->getDecl()];
+
+ llvm::Value *BlockLiteral = LoadBlockStruct();
+
+ Loc = Builder.CreateGEP(BlockLiteral,
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
+ offset.getQuantity()),
+ "block.literal");
+ Ty = llvm::PointerType::get(Ty, 0);
+ Loc = Builder.CreateBitCast(Loc, Ty);
+ Loc = Builder.CreateLoad(Loc);
+ // 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())
+ ; // Already created into the destination
+ else
+ assert (0 && "bad block variable");
+ // FIXME: Ensure that the offset created by the backend for
+ // the struct matches the previously computed offset in BlockDecls.
+ }
+ NoteForHelper.resize(NumHelpers);
// __descriptor
llvm::Value *Descriptor = BuildDescriptorBlockDecl(BE,
- subBlockHasCopyDispose,
- subBlockSize, Ty,
+ Info.BlockHasCopyDispose,
+ Info.BlockSize, Ty,
&NoteForHelper);
Descriptor = Builder.CreateBitCast(Descriptor, PtrToInt8Ty);
Builder.CreateStore(Descriptor, Builder.CreateStructGEP(V, 4, "block.tmp"));
@@ -487,13 +554,25 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
return EmitCall(FnInfo, Func, ReturnValue, Args);
}
-CharUnits CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) {
+void CodeGenFunction::AllocateBlockCXXThisPointer(const CXXThisExpr *E) {
+ assert(BlockCXXThisOffset.isZero() && "already computed 'this' pointer");
+
+ // Figure out what the offset is.
+ QualType T = E->getType();
+ std::pair<CharUnits,CharUnits> TypeInfo = getContext().getTypeInfoInChars(T);
+ CharUnits Offset = getBlockOffset(TypeInfo.first, TypeInfo.second);
+
+ BlockCXXThisOffset = Offset;
+ BlockLayout.push_back(E);
+}
+
+void CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) {
const ValueDecl *VD = E->getDecl();
- CharUnits &offset = BlockDecls[VD];
+ CharUnits &Offset = BlockDecls[VD];
// See if we have already allocated an offset for this variable.
- if (offset.isPositive())
- return offset;
+ if (!Offset.isZero())
+ return;
// Don't run the expensive check, unless we have to.
if (!BlockHasCopyDispose)
@@ -501,23 +580,34 @@ CharUnits CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) {
|| BlockRequiresCopying(E->getType()))
BlockHasCopyDispose = true;
- // if not, allocate one now.
- offset = getBlockOffset(E);
+ const ValueDecl *D = cast<ValueDecl>(E->getDecl());
- return offset;
+ CharUnits Size;
+ CharUnits Align;
+
+ if (E->isByRef()) {
+ llvm::tie(Size,Align) =
+ getContext().getTypeInfoInChars(getContext().VoidPtrTy);
+ } else {
+ Size = getContext().getTypeSizeInChars(D->getType());
+ Align = getContext().getDeclAlign(D);
+ }
+
+ Offset = getBlockOffset(Size, Align);
+ BlockLayout.push_back(E);
}
-llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
- const ValueDecl *VD = E->getDecl();
- CharUnits offset = AllocateBlockDecl(E);
-
+llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const ValueDecl *VD,
+ bool IsByRef) {
+ CharUnits offset = BlockDecls[VD];
+ assert(!offset.isZero() && "getting address of unallocated decl");
llvm::Value *BlockLiteral = LoadBlockStruct();
llvm::Value *V = Builder.CreateGEP(BlockLiteral,
llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
offset.getQuantity()),
"block.literal");
- if (E->isByRef()) {
+ if (IsByRef) {
const llvm::Type *PtrStructTy
= llvm::PointerType::get(BuildByRefType(VD), 0);
// The block literal will need a copy/destroy helper.
@@ -543,19 +633,6 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
return V;
}
-void CodeGenFunction::BlockForwardSelf() {
- const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
- ImplicitParamDecl *SelfDecl = OMD->getSelfDecl();
- llvm::Value *&DMEntry = LocalDeclMap[SelfDecl];
- if (DMEntry)
- return;
- // FIXME - Eliminate BlockDeclRefExprs, clients don't need/want to care
- BlockDeclRefExpr *BDRE = new (getContext())
- BlockDeclRefExpr(SelfDecl,
- SelfDecl->getType(), SourceLocation(), false);
- DMEntry = GetAddrOfBlockDecl(BDRE);
-}
-
llvm::Constant *
BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
// Generate the block descriptor.
@@ -600,19 +677,11 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
std::vector<llvm::Constant*> LiteralFields(FieldCount);
- CodeGenFunction::BlockInfo Info(0, n);
- CharUnits subBlockSize;
- CharUnits subBlockAlign;
- llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls;
- bool subBlockHasCopyDispose = false;
+ CGBlockInfo Info(n);
llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap;
llvm::Function *Fn
- = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, 0, LocalDeclMap,
- subBlockSize,
- subBlockAlign,
- subBlockDeclRefDecls,
- subBlockHasCopyDispose);
- assert(subBlockSize == BlockLiteralSize
+ = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, 0, LocalDeclMap);
+ assert(Info.BlockSize == BlockLiteralSize
&& "no imports allowed for global block");
// isa
@@ -651,13 +720,9 @@ llvm::Value *CodeGenFunction::LoadBlockStruct() {
llvm::Function *
CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
- const BlockInfo& Info,
+ CGBlockInfo &Info,
const Decl *OuterFuncDecl,
- llvm::DenseMap<const Decl*, llvm::Value*> ldm,
- CharUnits &Size,
- CharUnits &Align,
- llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls,
- bool &subBlockHasCopyDispose) {
+ llvm::DenseMap<const Decl*, llvm::Value*> ldm) {
// Check if we should generate debug info for this block.
if (CGM.getDebugInfo())
@@ -701,11 +766,12 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor");
- // Allocate all BlockDeclRefDecls, so we can calculate the right ParmTy below.
- AllocateAllBlockDeclRefs(Info, this);
+ // Build the block struct now.
+ AllocateAllBlockDeclRefs(*this, Info);
QualType ParmTy = getContext().getBlockParmType(BlockHasCopyDispose,
- BlockDeclRefDecls);
+ BlockLayout);
+
// FIXME: This leaks
ImplicitParamDecl *SelfDecl =
ImplicitParamDecl::Create(getContext(), const_cast<BlockDecl*>(BD),
@@ -725,10 +791,11 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, IsVariadic);
+ MangleBuffer Name;
+ CGM.getMangledName(Name, BD);
llvm::Function *Fn =
- llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
- llvm::Twine("__") + Info.Name + "_block_invoke_",
- &CGM.getModule());
+ llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
+ Name.getString(), &CGM.getModule());
CGM.SetInternalFunctionAttributes(BD, Fn, FI);
@@ -738,6 +805,34 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
CurFuncDecl = OuterFuncDecl;
CurCodeDecl = BD;
+ // If we have a C++ 'this' reference, go ahead and force it into
+ // existence now.
+ if (Info.CXXThisRef) {
+ assert(!BlockCXXThisOffset.isZero() &&
+ "haven't yet allocated 'this' reference");
+
+ // TODO: I have a dream that one day this will be typed.
+ llvm::Value *BlockLiteral = LoadBlockStruct();
+ llvm::Value *ThisPtrRaw =
+ Builder.CreateConstInBoundsGEP1_64(BlockLiteral,
+ BlockCXXThisOffset.getQuantity(),
+ "this.ptr.raw");
+
+ const llvm::Type *Ty =
+ CGM.getTypes().ConvertType(Info.CXXThisRef->getType());
+ Ty = llvm::PointerType::get(Ty, 0);
+ llvm::Value *ThisPtr = Builder.CreateBitCast(ThisPtrRaw, Ty, "this.ptr");
+
+ CXXThisValue = Builder.CreateLoad(ThisPtr, "this");
+ }
+
+ // If we have an Objective C 'self' reference, go ahead and force it
+ // into existence now.
+ if (Info.NeedsObjCSelf) {
+ ValueDecl *Self = cast<ObjCMethodDecl>(CurFuncDecl)->getSelfDecl();
+ LocalDeclMap[Self] = GetAddrOfBlockDecl(Self, false);
+ }
+
// Save a spot to insert the debug information for all the BlockDeclRefDecls.
llvm::BasicBlock *entry = Builder.GetInsertBlock();
llvm::BasicBlock::iterator entry_ptr = Builder.GetInsertPoint();
@@ -754,9 +849,10 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
if (CGDebugInfo *DI = getDebugInfo()) {
// Emit debug information for all the BlockDeclRefDecls.
- for (unsigned i = 0, e = BlockDeclRefDecls.size(); i != e; ++i) {
- if (const BlockDeclRefExpr *BDRE =
- dyn_cast<BlockDeclRefExpr>(BlockDeclRefDecls[i])) {
+ // FIXME: also for 'this'
+ for (unsigned i = 0, e = BlockLayout.size(); i != e; ++i) {
+ if (const BlockDeclRefExpr *BDRE =
+ dyn_cast<BlockDeclRefExpr>(BlockLayout[i])) {
const ValueDecl *D = BDRE->getDecl();
DI->setLocation(D->getLocation());
DI->EmitDeclareOfBlockDeclRefVariable(BDRE,
@@ -779,25 +875,15 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
llvm::RoundUpToAlignment(BlockOffset.getQuantity(),
MinAlign.getQuantity()));
- Size = BlockOffset;
- Align = BlockAlign;
- subBlockDeclRefDecls = BlockDeclRefDecls;
- subBlockHasCopyDispose |= BlockHasCopyDispose;
+ Info.BlockSize = BlockOffset;
+ Info.BlockAlign = BlockAlign;
+ Info.BlockLayout = BlockLayout;
+ Info.BlockHasCopyDispose = BlockHasCopyDispose;
return Fn;
}
-CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) {
- const ValueDecl *D = dyn_cast<ValueDecl>(BDRE->getDecl());
-
- CharUnits Size = getContext().getTypeSizeInChars(D->getType());
- CharUnits Align = getContext().getDeclAlign(D);
-
- if (BDRE->isByRef()) {
- Size = getContext().getTypeSizeInChars(getContext().VoidPtrTy);
- Align = getContext().getTypeAlignInChars(getContext().VoidPtrTy);
- }
-
- assert ((Align.isPositive()) && "alignment must be 1 byte or more");
+CharUnits BlockFunction::getBlockOffset(CharUnits Size, CharUnits Align) {
+ assert((Align.isPositive()) && "alignment must be 1 byte or more");
CharUnits OldOffset = BlockOffset;
@@ -808,23 +894,22 @@ CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) {
CharUnits Pad = BlockOffset - OldOffset;
if (Pad.isPositive()) {
- llvm::ArrayType::get(llvm::Type::getInt8Ty(VMContext), Pad.getQuantity());
QualType PadTy = getContext().getConstantArrayType(getContext().CharTy,
llvm::APInt(32,
Pad.getQuantity()),
ArrayType::Normal, 0);
- ValueDecl *PadDecl = VarDecl::Create(getContext(), 0, SourceLocation(),
+ ValueDecl *PadDecl = VarDecl::Create(getContext(),
+ getContext().getTranslationUnitDecl(),
+ SourceLocation(),
0, QualType(PadTy), 0,
VarDecl::None, VarDecl::None);
- Expr *E;
- E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(),
- SourceLocation());
- BlockDeclRefDecls.push_back(E);
+ Expr *E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(),
+ SourceLocation());
+ BlockLayout.push_back(E);
}
- BlockDeclRefDecls.push_back(BDRE);
BlockOffset += Size;
- return BlockOffset-Size;
+ return BlockOffset - Size;
}
llvm::Constant *BlockFunction::
OpenPOWER on IntegriCloud