aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2011-02-07 10:33:21 +0000
committerJohn McCall <rjmccall@apple.com>2011-02-07 10:33:21 +0000
commit6b5a61b6dc400027fd793dcadceeb9da944a37ea (patch)
tree8fd6aca5e8914908e0ee03c007988ea87219d2b8
parent683564a7a93c952f1fbe573b55c542418d29d859 (diff)
A few more tweaks to the blocks AST representation:
- BlockDeclRefExprs always store VarDecls - BDREs no longer store copy expressions - BlockDecls now store a list of captured variables, information about how they're captured, and a copy expression if necessary With that in hand, change IR generation to use the captures data in blocks instead of walking the block independently. Additionally, optimize block layout by emitting fields in descending alignment order, with a heuristic for filling in words when alignment of the end of the block header is insufficient for the most aligned field. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@125005 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/ASTContext.h4
-rw-r--r--include/clang/AST/Decl.h74
-rw-r--r--include/clang/AST/Expr.h24
-rw-r--r--include/clang/Sema/ScopeInfo.h7
-rw-r--r--lib/AST/ASTContext.cpp9
-rw-r--r--lib/AST/Decl.cpp23
-rw-r--r--lib/AST/Expr.cpp7
-rw-r--r--lib/AST/StmtDumper.cpp52
-rw-r--r--lib/AST/StmtProfile.cpp2
-rw-r--r--lib/CodeGen/CGBlocks.cpp1655
-rw-r--r--lib/CodeGen/CGBlocks.h69
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp30
-rw-r--r--lib/CodeGen/CGDebugInfo.h14
-rw-r--r--lib/CodeGen/CGDecl.cpp7
-rw-r--r--lib/CodeGen/CGExpr.cpp4
-rw-r--r--lib/CodeGen/CGExprScalar.cpp4
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp4
-rw-r--r--lib/CodeGen/CGObjCMac.cpp92
-rw-r--r--lib/CodeGen/CGObjCRuntime.h6
-rw-r--r--lib/CodeGen/CodeGenFunction.h90
-rw-r--r--lib/Rewrite/RewriteObjC.cpp3
-rw-r--r--lib/Sema/SemaExpr.cpp210
-rw-r--r--lib/Sema/SemaExprObjC.cpp13
-rw-r--r--lib/Sema/TreeTransform.h4
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp21
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp3
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp16
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp1
-rw-r--r--test/CXX/expr/expr.cast/p4.cpp8
-rw-r--r--test/CodeGen/blocks-1.c24
-rw-r--r--test/CodeGen/blocksignature.c8
-rw-r--r--test/CodeGen/blockstret.c2
-rw-r--r--test/CodeGenObjC/block-var-layout.m91
-rw-r--r--test/CodeGenObjCXX/block-var-layout.mm73
34 files changed, 1467 insertions, 1187 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 6d3a9f0619..8a05730154 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -855,9 +855,9 @@ public:
void getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string &S)
const;
- /// getObjCEncodingForBlockDecl - Return the encoded type for this block
+ /// getObjCEncodingForBlock - Return the encoded type for this block
/// declaration.
- void getObjCEncodingForBlock(const BlockExpr *Expr, std::string& S) const;
+ std::string getObjCEncodingForBlock(const BlockExpr *blockExpr) const;
/// getObjCEncodingForPropertyDecl - Return the encoded type for
/// this method declaration. If non-NULL, Container must be either
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 485883e18b..f81f9d0ca4 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -2493,6 +2493,46 @@ public:
/// ^{ statement-body } or ^(int arg1, float arg2){ statement-body }
///
class BlockDecl : public Decl, public DeclContext {
+public:
+ /// A class which contains all the information about a particular
+ /// captured value.
+ class Capture {
+ enum {
+ flag_isByRef = 0x1,
+ flag_isNested = 0x2
+ };
+
+ /// The variable being captured.
+ llvm::PointerIntPair<VarDecl*, 2> VariableAndFlags;
+
+ /// The copy expression, expressed in terms of a DeclRef (or
+ /// BlockDeclRef) to the captured variable. Only required if the
+ /// variable has a C++ class type.
+ Expr *CopyExpr;
+
+ public:
+ Capture(VarDecl *variable, bool byRef, bool nested, Expr *copy)
+ : VariableAndFlags(variable,
+ (byRef ? flag_isByRef : 0) | (nested ? flag_isNested : 0)),
+ CopyExpr(copy) {}
+
+ /// The variable being captured.
+ VarDecl *getVariable() const { return VariableAndFlags.getPointer(); }
+
+ /// Whether this is a "by ref" capture, i.e. a capture of a __block
+ /// variable.
+ bool isByRef() const { return VariableAndFlags.getInt() & flag_isByRef; }
+
+ /// Whether this is a nested capture, i.e. the variable captured
+ /// is not from outside the immediately enclosing function/block.
+ bool isNested() const { return VariableAndFlags.getInt() & flag_isNested; }
+
+ bool hasCopyExpr() const { return CopyExpr != 0; }
+ Expr *getCopyExpr() const { return CopyExpr; }
+ void setCopyExpr(Expr *e) { CopyExpr = e; }
+ };
+
+private:
// FIXME: This can be packed into the bitfields in Decl.
bool IsVariadic : 1;
bool CapturesCXXThis : 1;
@@ -2505,15 +2545,15 @@ class BlockDecl : public Decl, public DeclContext {
Stmt *Body;
TypeSourceInfo *SignatureAsWritten;
- VarDecl **CapturedDecls;
- unsigned NumCapturedDecls;
+ Capture *Captures;
+ unsigned NumCaptures;
protected:
BlockDecl(DeclContext *DC, SourceLocation CaretLoc)
: Decl(Block, DC, CaretLoc), DeclContext(Block),
IsVariadic(false), CapturesCXXThis(false),
ParamInfo(0), NumParams(0), Body(0),
- SignatureAsWritten(0), CapturedDecls(0), NumCapturedDecls(0) {}
+ SignatureAsWritten(0), Captures(0), NumCaptures(0) {}
public:
static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L);
@@ -2555,25 +2595,25 @@ public:
/// hasCaptures - True if this block (or its nested blocks) captures
/// anything of local storage from its enclosing scopes.
- bool hasCaptures() const { return NumCapturedDecls != 0 || CapturesCXXThis; }
+ bool hasCaptures() const { return NumCaptures != 0 || CapturesCXXThis; }
- unsigned getNumCapturedDecls() const { return NumCapturedDecls; }
+ /// getNumCaptures - Returns the number of captured variables.
+ /// Does not include an entry for 'this'.
+ unsigned getNumCaptures() const { return NumCaptures; }
- typedef VarDecl * const *capture_iterator;
- typedef VarDecl const * const *capture_const_iterator;
- capture_iterator capture_begin() { return CapturedDecls; }
- capture_iterator capture_end() { return CapturedDecls + NumCapturedDecls; }
- capture_const_iterator capture_begin() const { return CapturedDecls; }
- capture_const_iterator capture_end() const {
- return CapturedDecls + NumCapturedDecls;
- }
+ typedef const Capture *capture_iterator;
+ typedef const Capture *capture_const_iterator;
+ capture_iterator capture_begin() { return Captures; }
+ capture_iterator capture_end() { return Captures + NumCaptures; }
+ capture_const_iterator capture_begin() const { return Captures; }
+ capture_const_iterator capture_end() const { return Captures + NumCaptures; }
bool capturesCXXThis() const { return CapturesCXXThis; }
- void setCapturedDecls(ASTContext &Context,
- VarDecl * const *begin,
- VarDecl * const *end,
- bool capturesCXXThis);
+ void setCaptures(ASTContext &Context,
+ const Capture *begin,
+ const Capture *end,
+ bool capturesCXXThis);
virtual SourceRange getSourceRange() const;
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index cf1faf1aff..247a4d10ba 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -3565,27 +3565,25 @@ public:
virtual child_iterator child_end();
};
-/// BlockDeclRefExpr - A reference to a declared variable, function,
-/// enum, etc.
+/// BlockDeclRefExpr - A reference to a local variable declared in an
+/// enclosing scope.
class BlockDeclRefExpr : public Expr {
- ValueDecl *D;
+ VarDecl *D;
SourceLocation Loc;
bool IsByRef : 1;
bool ConstQualAdded : 1;
- Stmt *CopyConstructorVal;
public:
- BlockDeclRefExpr(ValueDecl *d, QualType t, ExprValueKind VK,
- SourceLocation l, bool ByRef, bool constAdded = false,
- Stmt *copyConstructorVal = 0);
+ BlockDeclRefExpr(VarDecl *d, QualType t, ExprValueKind VK,
+ SourceLocation l, bool ByRef, bool constAdded = false);
// \brief Build an empty reference to a declared variable in a
// block.
explicit BlockDeclRefExpr(EmptyShell Empty)
: Expr(BlockDeclRefExprClass, Empty) { }
- ValueDecl *getDecl() { return D; }
- const ValueDecl *getDecl() const { return D; }
- void setDecl(ValueDecl *VD) { D = VD; }
+ VarDecl *getDecl() { return D; }
+ const VarDecl *getDecl() const { return D; }
+ void setDecl(VarDecl *VD) { D = VD; }
SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation L) { Loc = L; }
@@ -3598,12 +3596,6 @@ public:
bool isConstQualAdded() const { return ConstQualAdded; }
void setConstQualAdded(bool C) { ConstQualAdded = C; }
- const Expr *getCopyConstructorExpr() const
- { return cast_or_null<Expr>(CopyConstructorVal); }
- Expr *getCopyConstructorExpr()
- { return cast_or_null<Expr>(CopyConstructorVal); }
- void setCopyConstructorExpr(Expr *E) { CopyConstructorVal = E; }
-
static bool classof(const Stmt *T) {
return T->getStmtClass() == BlockDeclRefExprClass;
}
diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h
index 0ba61b34eb..edd1432d8e 100644
--- a/include/clang/Sema/ScopeInfo.h
+++ b/include/clang/Sema/ScopeInfo.h
@@ -116,8 +116,11 @@ public:
/// Its return type may be BuiltinType::Dependent.
QualType FunctionType;
- /// Captures - The set of variables captured by this block.
- llvm::SmallSetVector<VarDecl*, 4> Captures;
+ /// CaptureMap - A map of captured variables to (index+1) into Captures.
+ llvm::DenseMap<VarDecl*, unsigned> CaptureMap;
+
+ /// Captures - The captured variables.
+ llvm::SmallVector<BlockDecl::Capture, 4> Captures;
/// CapturesCXXThis - Whether this block captures 'this'.
bool CapturesCXXThis;
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index d96d079908..63e84d4131 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -3693,10 +3693,11 @@ std::string charUnitsToString(const CharUnits &CU) {
return llvm::itostr(CU.getQuantity());
}
-/// getObjCEncodingForBlockDecl - Return the encoded type for this block
+/// getObjCEncodingForBlock - Return the encoded type for this block
/// declaration.
-void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr,
- std::string& S) const {
+std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const {
+ std::string S;
+
const BlockDecl *Decl = Expr->getBlockDecl();
QualType BlockTy =
Expr->getType()->getAs<BlockPointerType>()->getPointeeType();
@@ -3739,6 +3740,8 @@ void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr,
S += charUnitsToString(ParmOffset);
ParmOffset += getObjCEncodingTypeSize(PType);
}
+
+ return S;
}
void ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl,
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index db69e0878a..4fb47bfcdc 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -2104,21 +2104,26 @@ void BlockDecl::setParams(ParmVarDecl **NewParamInfo,
}
}
-void BlockDecl::setCapturedDecls(ASTContext &Context,
- VarDecl * const *begin,
- VarDecl * const *end,
- bool capturesCXXThis) {
+void BlockDecl::setCaptures(ASTContext &Context,
+ const Capture *begin,
+ const Capture *end,
+ bool capturesCXXThis) {
CapturesCXXThis = capturesCXXThis;
if (begin == end) {
- NumCapturedDecls = 0;
- CapturedDecls = 0;
+ NumCaptures = 0;
+ Captures = 0;
return;
}
- NumCapturedDecls = end - begin;
- CapturedDecls = new (Context) VarDecl*[NumCapturedDecls];
- memcpy(CapturedDecls, begin, NumCapturedDecls * sizeof(VarDecl*));
+ NumCaptures = end - begin;
+
+ // Avoid new Capture[] because we don't want to provide a default
+ // constructor.
+ size_t allocationSize = NumCaptures * sizeof(Capture);
+ void *buffer = Context.Allocate(allocationSize, /*alignment*/sizeof(void*));
+ memcpy(buffer, begin, allocationSize);
+ Captures = static_cast<Capture*>(buffer);
}
SourceRange BlockDecl::getSourceRange() const {
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 04498f7b9a..b22d9d5452 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -2961,13 +2961,12 @@ Stmt::child_iterator ObjCMessageExpr::child_end() {
}
// Blocks
-BlockDeclRefExpr::BlockDeclRefExpr(ValueDecl *d, QualType t, ExprValueKind VK,
+BlockDeclRefExpr::BlockDeclRefExpr(VarDecl *d, QualType t, ExprValueKind VK,
SourceLocation l, bool ByRef,
- bool constAdded, Stmt *copyConstructorVal)
+ bool constAdded)
: Expr(BlockDeclRefExprClass, t, VK, OK_Ordinary, false, false,
d->isParameterPack()),
- D(d), Loc(l), IsByRef(ByRef),
- ConstQualAdded(constAdded), CopyConstructorVal(copyConstructorVal)
+ D(d), Loc(l), IsByRef(ByRef), ConstQualAdded(constAdded)
{
bool TypeDependent = false;
bool ValueDependent = false;
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index 8b62dcc940..5def7d9a0b 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -100,6 +100,7 @@ namespace {
OS << ":'" << QualType::getAsString(D_split) << "'";
}
}
+ void DumpDeclRef(Decl *node);
void DumpStmt(const Stmt *Node) {
Indent();
OS << "(" << Node->getStmtClassName()
@@ -153,6 +154,7 @@ namespace {
void VisitBinaryOperator(BinaryOperator *Node);
void VisitCompoundAssignOperator(CompoundAssignOperator *Node);
void VisitAddrLabelExpr(AddrLabelExpr *Node);
+ void VisitBlockExpr(BlockExpr *Node);
// C++
void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node);
@@ -362,21 +364,21 @@ void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) {
DumpExpr(Node);
OS << " ";
- switch (Node->getDecl()->getKind()) {
- default: OS << "Decl"; break;
- case Decl::Function: OS << "FunctionDecl"; break;
- case Decl::Var: OS << "Var"; break;
- case Decl::ParmVar: OS << "ParmVar"; break;
- case Decl::EnumConstant: OS << "EnumConstant"; break;
- case Decl::Typedef: OS << "Typedef"; break;
- case Decl::Record: OS << "Record"; break;
- case Decl::Enum: OS << "Enum"; break;
- case Decl::CXXRecord: OS << "CXXRecord"; break;
- case Decl::ObjCInterface: OS << "ObjCInterface"; break;
- case Decl::ObjCClass: OS << "ObjCClass"; break;
+ DumpDeclRef(Node->getDecl());
+}
+
+void StmtDumper::DumpDeclRef(Decl *d) {
+ OS << d->getDeclKindName() << ' ' << (void*) d;
+
+ if (NamedDecl *nd = dyn_cast<NamedDecl>(d)) {
+ OS << " '";
+ nd->getDeclName().printName(OS);
+ OS << "'";
}
- OS << "='" << Node->getDecl() << "' " << (void*)Node->getDecl();
+ if (ValueDecl *vd = dyn_cast<ValueDecl>(d)) {
+ OS << ' '; DumpType(vd->getType());
+ }
}
void StmtDumper::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
@@ -474,6 +476,30 @@ void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
DumpType(Node->getComputationResultType());
}
+void StmtDumper::VisitBlockExpr(BlockExpr *Node) {
+ DumpExpr(Node);
+
+ IndentLevel++;
+ BlockDecl *block = Node->getBlockDecl();
+ if (block->capturesCXXThis()) {
+ OS << '\n'; Indent(); OS << "(capture this)";
+ }
+ for (BlockDecl::capture_iterator
+ i = block->capture_begin(), e = block->capture_end(); i != e; ++i) {
+ OS << '\n';
+ Indent();
+ OS << "(capture ";
+ if (i->isByRef()) OS << "byref ";
+ if (i->isNested()) OS << "nested ";
+ DumpDeclRef(i->getVariable());
+ if (i->hasCopyExpr()) DumpSubTree(i->getCopyExpr());
+ OS << ")";
+ }
+ IndentLevel--;
+
+ DumpSubTree(block->getBody());
+}
+
// GNU extensions.
void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) {
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index e75c274015..842a2d92d8 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -425,8 +425,6 @@ void StmtProfiler::VisitBlockDeclRefExpr(BlockDeclRefExpr *S) {
VisitDecl(S->getDecl());
ID.AddBoolean(S->isByRef());
ID.AddBoolean(S->isConstQualAdded());
- if (S->getCopyConstructorExpr())
- Visit(S->getCopyConstructorExpr());
}
static Stmt::StmtClass DecodeOperatorCall(CXXOperatorCallExpr *S,
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index a594a0bb9e..bdbc9d3b55 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -24,141 +24,84 @@
using namespace clang;
using namespace CodeGen;
-CGBlockInfo::CGBlockInfo(const char *N)
- : Name(N), CXXThisRef(0), NeedsObjCSelf(false),
- HasCXXObject(false) {
+CGBlockInfo::CGBlockInfo(const BlockExpr *blockExpr, const char *N)
+ : Name(N), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false),
+ HasCXXObject(false), HasWeakBlockVariable(false),
+ StructureType(0), Block(blockExpr) {
// Skip asm prefix, if any.
if (Name && Name[0] == '\01')
++Name;
}
+/// Build the given block as a global block.
+static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
+ const CGBlockInfo &blockInfo,
+ llvm::Constant *blockFn);
-llvm::Constant *CodeGenFunction::
-BuildDescriptorBlockDecl(const BlockExpr *BE, const CGBlockInfo &Info,
- const llvm::StructType* Ty,
- llvm::Constant *BlockVarLayout,
- std::vector<HelperInfo> *NoteForHelper) {
- CharUnits Size = Info.BlockSize;
- const llvm::Type *UnsignedLongTy
- = CGM.getTypes().ConvertType(getContext().UnsignedLongTy);
- llvm::Constant *C;
- std::vector<llvm::Constant*> Elts;
+/// Build the helper function to copy a block.
+static llvm::Constant *buildCopyHelper(CodeGenModule &CGM,
+ const CGBlockInfo &blockInfo) {
+ return CodeGenFunction(CGM).GenerateCopyHelperFunction(blockInfo);
+}
+
+/// Build the helper function to dipose of a block.
+static llvm::Constant *buildDisposeHelper(CodeGenModule &CGM,
+ const CGBlockInfo &blockInfo) {
+ return CodeGenFunction(CGM).GenerateDestroyHelperFunction(blockInfo);
+}
+
+/// Build the block descriptor constant for a block.
+static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM,
+ const CGBlockInfo &blockInfo) {
+ ASTContext &C = CGM.getContext();
+
+ const llvm::Type *ulong = CGM.getTypes().ConvertType(C.UnsignedLongTy);
+ const llvm::Type *i8p = CGM.getTypes().ConvertType(C.VoidPtrTy);
+
+ llvm::SmallVector<llvm::Constant*, 6> elements;
// reserved
- C = llvm::ConstantInt::get(UnsignedLongTy, 0);
- Elts.push_back(C);
+ elements.push_back(llvm::ConstantInt::get(ulong, 0));
// Size
// FIXME: What is the right way to say this doesn't fit? We should give
// a user diagnostic in that case. Better fix would be to change the
// API to size_t.
- C = llvm::ConstantInt::get(UnsignedLongTy, Size.getQuantity());
- Elts.push_back(C);
+ elements.push_back(llvm::ConstantInt::get(ulong,
+ blockInfo.BlockSize.getQuantity()));
- // optional copy/dispose helpers
- if (Info.BlockHasCopyDispose) {
+ // Optional copy/dispose helpers.
+ if (blockInfo.NeedsCopyDispose) {
// copy_func_helper_decl
- Elts.push_back(BuildCopyHelper(Ty, NoteForHelper));
+ elements.push_back(buildCopyHelper(CGM, blockInfo));
// destroy_func_decl
- Elts.push_back(BuildDestroyHelper(Ty, NoteForHelper));
+ elements.push_back(buildDisposeHelper(CGM, blockInfo));
}
- // Signature. non-optional ObjC-style method descriptor @encode sequence
- std::string BlockTypeEncoding;
- CGM.getContext().getObjCEncodingForBlock(BE, BlockTypeEncoding);
-
- Elts.push_back(llvm::ConstantExpr::getBitCast(
- CGM.GetAddrOfConstantCString(BlockTypeEncoding), PtrToInt8Ty));
+ // Signature. Mandatory ObjC-style method descriptor @encode sequence.
+ std::string typeAtEncoding =
+ CGM.getContext().getObjCEncodingForBlock(blockInfo.getBlockExpr());
+ elements.push_back(llvm::ConstantExpr::getBitCast(
+ CGM.GetAddrOfConstantCString(typeAtEncoding), i8p));
- // Layout.
- C = BlockVarLayout;
-
- Elts.push_back(C);
-
- C = llvm::ConstantStruct::get(VMContext, Elts, false);
-
- C = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true,
- llvm::GlobalValue::InternalLinkage,
- C, "__block_descriptor_tmp");
- return C;
-}
-
-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);
-
- // 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)) {
- Info.InnerBlocks.insert(BE->getBlockDecl());
- CollectBlockDeclRefInfo(BE->getBody(), Info);
- }
-
- else if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) {
- const ValueDecl *D = BDRE->getDecl();
- // FIXME: Handle enums.
- 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 (!Info.InnerBlocks.count(D->getDeclContext())) {
- if (BDRE->getCopyConstructorExpr())
- Info.HasCXXObject = true;
- Info.DeclRefs.push_back(BDRE);
- }
- }
+ // GC layout.
+ if (C.getLangOptions().ObjC1)
+ elements.push_back(CGM.getObjCRuntime().BuildGCBlockLayout(CGM, blockInfo));
+ else
+ elements.push_back(llvm::Constant::getNullValue(i8p));
- // 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;
- }
- else if (const ObjCPropertyRefExpr *PE = dyn_cast<ObjCPropertyRefExpr>(S)) {
- // Getter/setter uses may also cause implicit super references,
- // which we can check for with:
- if (PE->isSuperReceiver())
- Info.NeedsObjCSelf = true;
- }
- else if (isa<CXXThisExpr>(S))
- Info.CXXThisRef = cast<CXXThisExpr>(S);
-}
+ llvm::Constant *init =
+ llvm::ConstantStruct::get(CGM.getLLVMContext(), elements.data(),
+ elements.size(), false);
-/// 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 CGBlockInfo &Info) {
- return Info.DeclRefs.empty();
-}
+ llvm::GlobalVariable *global =
+ new llvm::GlobalVariable(CGM.getModule(), init->getType(), true,
+ llvm::GlobalValue::InternalLinkage,
+ init, "__block_descriptor_tmp");
-/// AllocateAllBlockDeclRefs - Preallocate all nested BlockDeclRefExprs to
-/// ensure we can generate the debug information for the parameter for the block
-/// invoke function.
-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]);
-
- if (Info.NeedsObjCSelf) {
- ValueDecl *Self = cast<ObjCMethodDecl>(CGF.CurFuncDecl)->getSelfDecl();
- BlockDeclRefExpr *BDRE =
- new (CGF.getContext()) BlockDeclRefExpr(Self, Self->getType(), VK_RValue,
- SourceLocation(), false);
- Info.DeclRefs.push_back(BDRE);
- CGF.AllocateBlockDecl(BDRE);
- }
+ return llvm::ConstantExpr::getBitCast(global, CGM.getBlockDescriptorType());
}
static unsigned computeBlockFlag(CodeGenModule &CGM,
@@ -176,256 +119,506 @@ static unsigned computeBlockFlag(CodeGenModule &CGM,
return flags;
}
-// 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();
- CGBlockInfo Info(Name.c_str());
- Info.InnerBlocks.insert(BE->getBlockDecl());
- CollectBlockDeclRefInfo(BE->getBody(), Info);
+/*
+ Purely notional variadic template describing the layout of a block.
+
+ template <class _ResultType, class... _ParamTypes, class... _CaptureTypes>
+ struct Block_literal {
+ /// Initialized to one of:
+ /// extern void *_NSConcreteStackBlock[];
+ /// extern void *_NSConcreteGlobalBlock[];
+ ///
+ /// In theory, we could start one off malloc'ed by setting
+ /// BLOCK_NEEDS_FREE, giving it a refcount of 1, and using
+ /// this isa:
+ /// extern void *_NSConcreteMallocBlock[];
+ struct objc_class *isa;
+
+ /// These are the flags (with corresponding bit number) that the
+ /// compiler is actually supposed to know about.
+ /// 25. BLOCK_HAS_COPY_DISPOSE - indicates that the block
+ /// descriptor provides copy and dispose helper functions
+ /// 26. BLOCK_HAS_CXX_OBJ - indicates that there's a captured
+ /// object with a nontrivial destructor or copy constructor
+ /// 28. BLOCK_IS_GLOBAL - indicates that the block is allocated
+ /// as global memory
+ /// 29. BLOCK_USE_STRET - indicates that the block function
+ /// uses stret, which objc_msgSend needs to know about
+ /// 30. BLOCK_HAS_SIGNATURE - indicates that the block has an
+ /// @encoded signature string
+ /// And we're not supposed to manipulate these:
+ /// 24. BLOCK_NEEDS_FREE - indicates that the block has been moved
+ /// to malloc'ed memory
+ /// 27. BLOCK_IS_GC - indicates that the block has been moved to
+ /// to GC-allocated memory
+ /// Additionally, the bottom 16 bits are a reference count which
+ /// should be zero on the stack.
+ int flags;
+
+ /// Reserved; should be zero-initialized.
+ int reserved;
+
+ /// Function pointer generated from block literal.
+ _ResultType (*invoke)(Block_literal *, _ParamTypes...);
+
+ /// Block description metadata generated from block literal.
+ struct Block_descriptor *block_descriptor;
+
+ /// Captured values follow.
+ _CapturesTypes captures...;
+ };
+ */
+
+/// The number of fields in a block header.
+const unsigned BlockHeaderSize = 5;
+
+namespace {
+ /// A chunk of data that we actually have to capture in the block.
+ struct BlockLayoutChunk {
+ CharUnits Alignment;
+ CharUnits Size;
+ const BlockDecl::Capture *Capture; // null for 'this'
+ const llvm::Type *Type;
+
+ BlockLayoutChunk(CharUnits align, CharUnits size,
+ const BlockDecl::Capture *capture,
+ const llvm::Type *type)
+ : Alignment(align), Size(size), Capture(capture), Type(type) {}
+
+ /// Tell the block info that this chunk has the given field index.
+ void setIndex(CGBlockInfo &info, unsigned index) {
+ if (!Capture)
+ info.CXXThisIndex = index;
+ else
+ info.Captures[Capture->getVariable()]
+ = CGBlockInfo::Capture::makeIndex(index);
+ }
+ };
- // Check if the block can be global.
- // 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());
+ /// Order by descending alignment.
+ bool operator<(const BlockLayoutChunk &left, const BlockLayoutChunk &right) {
+ return left.Alignment > right.Alignment;
+ }
+}
- size_t BlockFields = 5;
+/// It is illegal to modify a const object after initialization.
+/// Therefore, if a const object has a constant initializer, we don't
+/// actually need to keep storage for it in the block; we'll just
+/// rematerialize it at the start of the block function. This is
+/// acceptable because we make no promises about address stability of
+/// captured variables.
+static llvm::Constant *tryCaptureAsConstant(CodeGenModule &CGM,
+ const VarDecl *var) {
+ QualType type = var->getType();
+
+ // We can only do this if the variable is const.
+ if (!type.isConstQualified()) return 0;
+
+ // Furthermore, in C++ we can't do this for classes. TODO: we might