зеркало из https://github.com/microsoft/clang-1.git
Enter the cleanups for a block outside the enclosing
full-expression. Naturally they're inactive before we enter the block literal expression. This restores the intended behavior that blocks belong to their enclosing scope. There's a useful -O0 / compile-time optimization that we're missing here with activating cleanups following straight-line code from their inactive beginnings. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@144268 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
180f47959a
Коммит
1a343ebbf4
|
@ -25,13 +25,14 @@
|
|||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
|
||||
CGBlockInfo::CGBlockInfo(const BlockExpr *blockExpr, const char *N)
|
||||
: Name(N), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false),
|
||||
HasCXXObject(false), UsesStret(false), StructureType(0), Block(blockExpr) {
|
||||
CGBlockInfo::CGBlockInfo(const BlockDecl *block, StringRef name)
|
||||
: Name(name), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false),
|
||||
HasCXXObject(false), UsesStret(false), StructureType(0), Block(block) {
|
||||
|
||||
// Skip asm prefix, if any.
|
||||
if (Name && Name[0] == '\01')
|
||||
++Name;
|
||||
// Skip asm prefix, if any. 'name' is usually taken directly from
|
||||
// the mangled name of the enclosing function.
|
||||
if (!name.empty() && name[0] == '\01')
|
||||
name = name.substr(1);
|
||||
}
|
||||
|
||||
// Anchor the vtable to this translation unit.
|
||||
|
@ -483,15 +484,137 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
|
|||
llvm::StructType::get(CGM.getLLVMContext(), elementTypes, true);
|
||||
}
|
||||
|
||||
/// Enter the scope of a block. This should be run at the entrance to
|
||||
/// a full-expression so that the block's cleanups are pushed at the
|
||||
/// right place in the stack.
|
||||
static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) {
|
||||
// Allocate the block info and place it at the head of the list.
|
||||
CGBlockInfo &blockInfo =
|
||||
*new CGBlockInfo(block, CGF.CurFn->getName());
|
||||
blockInfo.NextBlockInfo = CGF.FirstBlockInfo;
|
||||
CGF.FirstBlockInfo = &blockInfo;
|
||||
|
||||
// Compute information about the layout, etc., of this block,
|
||||
// pushing cleanups as necessary.
|
||||
computeBlockInfo(CGF.CGM, blockInfo);
|
||||
|
||||
// Nothing else to do if it can be global.
|
||||
if (blockInfo.CanBeGlobal) return;
|
||||
|
||||
// Make the allocation for the block.
|
||||
blockInfo.Address =
|
||||
CGF.CreateTempAlloca(blockInfo.StructureType, "block");
|
||||
blockInfo.Address->setAlignment(blockInfo.BlockAlign.getQuantity());
|
||||
|
||||
// If there are cleanups to emit, enter them (but inactive).
|
||||
if (!blockInfo.NeedsCopyDispose) return;
|
||||
|
||||
// Walk through the captures (in order) and find the ones not
|
||||
// captured by constant.
|
||||
for (BlockDecl::capture_const_iterator ci = block->capture_begin(),
|
||||
ce = block->capture_end(); ci != ce; ++ci) {
|
||||
// Ignore __block captures; there's nothing special in the
|
||||
// on-stack block that we need to do for them.
|
||||
if (ci->isByRef()) continue;
|
||||
|
||||
// Ignore variables that are constant-captured.
|
||||
const VarDecl *variable = ci->getVariable();
|
||||
CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
|
||||
if (capture.isConstant()) continue;
|
||||
|
||||
// Ignore objects that aren't destructed.
|
||||
QualType::DestructionKind dtorKind =
|
||||
variable->getType().isDestructedType();
|
||||
if (dtorKind == QualType::DK_none) continue;
|
||||
|
||||
CodeGenFunction::Destroyer *destroyer;
|
||||
|
||||
// Block captures count as local values and have imprecise semantics.
|
||||
// They also can't be arrays, so need to worry about that.
|
||||
if (dtorKind == QualType::DK_objc_strong_lifetime) {
|
||||
destroyer = &CodeGenFunction::destroyARCStrongImprecise;
|
||||
} else {
|
||||
destroyer = &CGF.getDestroyer(dtorKind);
|
||||
}
|
||||
|
||||
// GEP down to the address.
|
||||
llvm::Value *addr = CGF.Builder.CreateStructGEP(blockInfo.Address,
|
||||
capture.getIndex());
|
||||
|
||||
CleanupKind cleanupKind = InactiveNormalCleanup;
|
||||
bool useArrayEHCleanup = CGF.needsEHCleanup(dtorKind);
|
||||
if (useArrayEHCleanup)
|
||||
cleanupKind = InactiveNormalAndEHCleanup;
|
||||
|
||||
CGF.pushDestroy(cleanupKind, addr, variable->getType(),
|
||||
*destroyer, useArrayEHCleanup);
|
||||
|
||||
// Remember where that cleanup was.
|
||||
capture.setCleanup(CGF.EHStack.stable_begin());
|
||||
}
|
||||
}
|
||||
|
||||
/// Enter a full-expression with a non-trivial number of objects to
|
||||
/// clean up. This is in this file because, at the moment, the only
|
||||
/// kind of cleanup object is a BlockDecl*.
|
||||
void CodeGenFunction::enterNonTrivialFullExpression(const ExprWithCleanups *E) {
|
||||
assert(E->getNumObjects() != 0);
|
||||
ArrayRef<ExprWithCleanups::CleanupObject> cleanups = E->getObjects();
|
||||
for (ArrayRef<ExprWithCleanups::CleanupObject>::iterator
|
||||
i = cleanups.begin(), e = cleanups.end(); i != e; ++i) {
|
||||
enterBlockScope(*this, *i);
|
||||
}
|
||||
}
|
||||
|
||||
/// Find the layout for the given block in a linked list and remove it.
|
||||
static CGBlockInfo *findAndRemoveBlockInfo(CGBlockInfo **head,
|
||||
const BlockDecl *block) {
|
||||
while (true) {
|
||||
assert(head && *head);
|
||||
CGBlockInfo *cur = *head;
|
||||
|
||||
// If this is the block we're looking for, splice it out of the list.
|
||||
if (cur->getBlockDecl() == block) {
|
||||
*head = cur->NextBlockInfo;
|
||||
return cur;
|
||||
}
|
||||
|
||||
head = &cur->NextBlockInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/// Destroy a chain of block layouts.
|
||||
void CodeGenFunction::destroyBlockInfos(CGBlockInfo *head) {
|
||||
assert(head && "destroying an empty chain");
|
||||
do {
|
||||
CGBlockInfo *cur = head;
|
||||
head = cur->NextBlockInfo;
|
||||
delete cur;
|
||||
} while (head != 0);
|
||||
}
|
||||
|
||||
/// Emit a block literal expression in the current function.
|
||||
llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
|
||||
std::string Name = CurFn->getName();
|
||||
CGBlockInfo blockInfo(blockExpr, Name.c_str());
|
||||
// If the block has no captures, we won't have a pre-computed
|
||||
// layout for it.
|
||||
if (!blockExpr->getBlockDecl()->hasCaptures()) {
|
||||
CGBlockInfo blockInfo(blockExpr->getBlockDecl(), CurFn->getName());
|
||||
computeBlockInfo(CGM, blockInfo);
|
||||
blockInfo.BlockExpression = blockExpr;
|
||||
return EmitBlockLiteral(blockInfo);
|
||||
}
|
||||
|
||||
// Compute information about the layout, etc., of this block.
|
||||
computeBlockInfo(CGM, blockInfo);
|
||||
// Find the block info for this block and take ownership of it.
|
||||
llvm::OwningPtr<CGBlockInfo> blockInfo;
|
||||
blockInfo.reset(findAndRemoveBlockInfo(&FirstBlockInfo,
|
||||
blockExpr->getBlockDecl()));
|
||||
|
||||
// Using that metadata, generate the actual block function.
|
||||
blockInfo->BlockExpression = blockExpr;
|
||||
return EmitBlockLiteral(*blockInfo);
|
||||
}
|
||||
|
||||
llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
|
||||
// Using the computed layout, generate the actual block function.
|
||||
llvm::Constant *blockFn
|
||||
= CodeGenFunction(CGM).GenerateBlockFunction(CurGD, blockInfo,
|
||||
CurFuncDecl, LocalDeclMap);
|
||||
|
@ -509,11 +632,8 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
|
|||
// Build the block descriptor.
|
||||
llvm::Constant *descriptor = buildBlockDescriptor(CGM, blockInfo);
|
||||
|
||||
llvm::Type *intTy = ConvertType(getContext().IntTy);
|
||||
|
||||
llvm::AllocaInst *blockAddr =
|
||||
CreateTempAlloca(blockInfo.StructureType, "block");
|
||||
blockAddr->setAlignment(blockInfo.BlockAlign.getQuantity());
|
||||
llvm::AllocaInst *blockAddr = blockInfo.Address;
|
||||
assert(blockAddr && "block has no address!");
|
||||
|
||||
// Compute the initial on-stack block flags.
|
||||
BlockFlags flags = BLOCK_HAS_SIGNATURE;
|
||||
|
@ -523,9 +643,9 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
|
|||
|
||||
// Initialize the block literal.
|
||||
Builder.CreateStore(isa, Builder.CreateStructGEP(blockAddr, 0, "block.isa"));
|
||||
Builder.CreateStore(llvm::ConstantInt::get(intTy, flags.getBitMask()),
|
||||
Builder.CreateStore(llvm::ConstantInt::get(IntTy, flags.getBitMask()),
|
||||
Builder.CreateStructGEP(blockAddr, 1, "block.flags"));
|
||||
Builder.CreateStore(llvm::ConstantInt::get(intTy, 0),
|
||||
Builder.CreateStore(llvm::ConstantInt::get(IntTy, 0),
|
||||
Builder.CreateStructGEP(blockAddr, 2, "block.reserved"));
|
||||
Builder.CreateStore(blockFn, Builder.CreateStructGEP(blockAddr, 3,
|
||||
"block.invoke"));
|
||||
|
@ -625,28 +745,11 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
|
|||
/*captured by init*/ false);
|
||||
}
|
||||
|
||||
// Push a destructor if necessary. The semantics for when this
|
||||
// actually gets run are really obscure.
|
||||
// Activate the cleanup if layout pushed one.
|
||||
if (!ci->isByRef()) {
|
||||
switch (QualType::DestructionKind dtorKind = type.isDestructedType()) {
|
||||
case QualType::DK_none:
|
||||
break;
|
||||
|
||||
// Block captures count as local values and have imprecise semantics.
|
||||
// They also can't be arrays, so need to worry about that.
|
||||
case QualType::DK_objc_strong_lifetime: {
|
||||
// This local is a GCC and MSVC compiler workaround.
|
||||
Destroyer *destroyer = &destroyARCStrongImprecise;
|
||||
pushDestroy(getCleanupKind(dtorKind), blockField, type,
|
||||
*destroyer, /*useEHCleanupForArray*/ false);
|
||||
break;
|
||||
}
|
||||
|
||||
case QualType::DK_objc_weak_lifetime:
|
||||
case QualType::DK_cxx_destructor:
|
||||
pushDestroy(dtorKind, blockField, type);
|
||||
break;
|
||||
}
|
||||
EHScopeStack::stable_iterator cleanup = capture.getCleanup();
|
||||
if (cleanup.isValid())
|
||||
ActivateCleanupBlock(cleanup);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -800,7 +903,8 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const VarDecl *variable,
|
|||
llvm::Constant *
|
||||
CodeGenModule::GetAddrOfGlobalBlock(const BlockExpr *blockExpr,
|
||||
const char *name) {
|
||||
CGBlockInfo blockInfo(blockExpr, name);
|
||||
CGBlockInfo blockInfo(blockExpr->getBlockDecl(), name);
|
||||
blockInfo.BlockExpression = blockExpr;
|
||||
|
||||
// Compute information about the layout, etc., of this block.
|
||||
computeBlockInfo(*this, blockInfo);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/ExprObjC.h"
|
||||
|
||||
#include "CodeGenFunction.h"
|
||||
#include "CGBuilder.h"
|
||||
#include "CGCall.h"
|
||||
#include "CGValue.h"
|
||||
|
@ -128,13 +129,14 @@ inline BlockFieldFlags operator|(BlockFieldFlag_t l, BlockFieldFlag_t r) {
|
|||
class CGBlockInfo {
|
||||
public:
|
||||
/// Name - The name of the block, kindof.
|
||||
const char *Name;
|
||||
llvm::StringRef Name;
|
||||
|
||||
/// The field index of 'this' within the block, if there is one.
|
||||
unsigned CXXThisIndex;
|
||||
|
||||
class Capture {
|
||||
uintptr_t Data;
|
||||
EHScopeStack::stable_iterator Cleanup;
|
||||
|
||||
public:
|
||||
bool isIndex() const { return (Data & 1) != 0; }
|
||||
|
@ -144,6 +146,14 @@ public:
|
|||
assert(isConstant());
|
||||
return reinterpret_cast<llvm::Value*>(Data);
|
||||
}
|
||||
EHScopeStack::stable_iterator getCleanup() const {
|
||||
assert(isIndex());
|
||||
return Cleanup;
|
||||
}
|
||||
void setCleanup(EHScopeStack::stable_iterator cleanup) {
|
||||
assert(isIndex());
|
||||
Cleanup = cleanup;
|
||||
}
|
||||
|
||||
static Capture makeIndex(unsigned index) {
|
||||
Capture v;
|
||||
|
@ -158,9 +168,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// The mapping of allocated indexes within the block.
|
||||
llvm::DenseMap<const VarDecl*, Capture> Captures;
|
||||
|
||||
/// CanBeGlobal - True if the block can be global, i.e. it has
|
||||
/// no non-constant captures.
|
||||
bool CanBeGlobal : 1;
|
||||
|
@ -176,22 +183,35 @@ public:
|
|||
/// because it gets set later in the block-creation process.
|
||||
mutable bool UsesStret : 1;
|
||||
|
||||
/// The mapping of allocated indexes within the block.
|
||||
llvm::DenseMap<const VarDecl*, Capture> Captures;
|
||||
|
||||
llvm::AllocaInst *Address;
|
||||
llvm::StructType *StructureType;
|
||||
const BlockExpr *Block;
|
||||
const BlockDecl *Block;
|
||||
const BlockExpr *BlockExpression;
|
||||
CharUnits BlockSize;
|
||||
CharUnits BlockAlign;
|
||||
CGBlockInfo *NextBlockInfo;
|
||||
|
||||
const Capture &getCapture(const VarDecl *var) const {
|
||||
llvm::DenseMap<const VarDecl*, Capture>::const_iterator
|
||||
return const_cast<CGBlockInfo*>(this)->getCapture(var);
|
||||
}
|
||||
Capture &getCapture(const VarDecl *var) {
|
||||
llvm::DenseMap<const VarDecl*, Capture>::iterator
|
||||
it = Captures.find(var);
|
||||
assert(it != Captures.end() && "no entry for variable!");
|
||||
return it->second;
|
||||
}
|
||||
|
||||
const BlockDecl *getBlockDecl() const { return Block->getBlockDecl(); }
|
||||
const BlockExpr *getBlockExpr() const { return Block; }
|
||||
const BlockDecl *getBlockDecl() const { return Block; }
|
||||
const BlockExpr *getBlockExpr() const {
|
||||
assert(BlockExpression);
|
||||
assert(BlockExpression->getBlockDecl() == Block);
|
||||
return BlockExpression;
|
||||
}
|
||||
|
||||
CGBlockInfo(const BlockExpr *blockExpr, const char *Name);
|
||||
CGBlockInfo(const BlockDecl *blockDecl, llvm::StringRef Name);
|
||||
};
|
||||
|
||||
} // end namespace CodeGen
|
||||
|
|
|
@ -496,9 +496,11 @@ void CodeGenFunction::EmitScalarInit(const Expr *init,
|
|||
|
||||
// If we're emitting a value with lifetime, we have to do the
|
||||
// initialization *before* we leave the cleanup scopes.
|
||||
CodeGenFunction::RunCleanupsScope Scope(*this);
|
||||
if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(init))
|
||||
if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(init)) {
|
||||
enterFullExpression(ewc);
|
||||
init = ewc->getSubExpr();
|
||||
}
|
||||
CodeGenFunction::RunCleanupsScope Scope(*this);
|
||||
|
||||
// We have to maintain the illusion that the variable is
|
||||
// zero-initialized. If the variable might be accessed in its
|
||||
|
|
|
@ -229,10 +229,11 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
|
|||
if (const CXXDefaultArgExpr *DAE = dyn_cast<CXXDefaultArgExpr>(E))
|
||||
E = DAE->getExpr();
|
||||
|
||||
if (const ExprWithCleanups *TE = dyn_cast<ExprWithCleanups>(E)) {
|
||||
if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(E)) {
|
||||
CGF.enterFullExpression(EWC);
|
||||
CodeGenFunction::RunCleanupsScope Scope(CGF);
|
||||
|
||||
return EmitExprForReferenceBinding(CGF, TE->getSubExpr(),
|
||||
return EmitExprForReferenceBinding(CGF, EWC->getSubExpr(),
|
||||
ReferenceTemporary,
|
||||
ReferenceTemporaryDtor,
|
||||
ObjCARCReferenceLifetimeType,
|
||||
|
@ -677,8 +678,14 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
|
|||
return EmitCXXConstructLValue(cast<CXXConstructExpr>(E));
|
||||
case Expr::CXXBindTemporaryExprClass:
|
||||
return EmitCXXBindTemporaryLValue(cast<CXXBindTemporaryExpr>(E));
|
||||
case Expr::ExprWithCleanupsClass:
|
||||
return EmitExprWithCleanupsLValue(cast<ExprWithCleanups>(E));
|
||||
|
||||
case Expr::ExprWithCleanupsClass: {
|
||||
const ExprWithCleanups *cleanups = cast<ExprWithCleanups>(E);
|
||||
enterFullExpression(cleanups);
|
||||
RunCleanupsScope Scope(*this);
|
||||
return EmitLValue(cleanups->getSubExpr());
|
||||
}
|
||||
|
||||
case Expr::CXXScalarValueInitExprClass:
|
||||
return EmitNullInitializationLValue(cast<CXXScalarValueInitExpr>(E));
|
||||
case Expr::CXXDefaultArgExprClass:
|
||||
|
|
|
@ -536,7 +536,9 @@ AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) {
|
|||
}
|
||||
|
||||
void AggExprEmitter::VisitExprWithCleanups(ExprWithCleanups *E) {
|
||||
CGF.EmitExprWithCleanups(E, Dest);
|
||||
CGF.enterFullExpression(E);
|
||||
CodeGenFunction::RunCleanupsScope cleanups(CGF);
|
||||
Visit(E->getSubExpr());
|
||||
}
|
||||
|
||||
void AggExprEmitter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
|
||||
|
|
|
@ -179,7 +179,9 @@ public:
|
|||
return Visit(DAE->getExpr());
|
||||
}
|
||||
ComplexPairTy VisitExprWithCleanups(ExprWithCleanups *E) {
|
||||
return CGF.EmitExprWithCleanups(E).getComplexVal();
|
||||
CGF.enterFullExpression(E);
|
||||
CodeGenFunction::RunCleanupsScope Scope(CGF);
|
||||
return Visit(E->getSubExpr());
|
||||
}
|
||||
ComplexPairTy VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
|
||||
assert(E->getType()->isAnyComplexType() && "Expected complex type!");
|
||||
|
|
|
@ -353,7 +353,9 @@ public:
|
|||
}
|
||||
|
||||
Value *VisitExprWithCleanups(ExprWithCleanups *E) {
|
||||
return CGF.EmitExprWithCleanups(E).getScalarVal();
|
||||
CGF.enterFullExpression(E);
|
||||
CodeGenFunction::RunCleanupsScope Scope(CGF);
|
||||
return Visit(E->getSubExpr());
|
||||
}
|
||||
Value *VisitCXXNewExpr(const CXXNewExpr *E) {
|
||||
return CGF.EmitCXXNewExpr(E);
|
||||
|
|
|
@ -2177,6 +2177,7 @@ static TryEmitResult
|
|||
tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
|
||||
// Look through cleanups.
|
||||
if (const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(e)) {
|
||||
CGF.enterFullExpression(cleanups);
|
||||
CodeGenFunction::RunCleanupsScope scope(CGF);
|
||||
return tryEmitARCRetainScalarExpr(CGF, cleanups->getSubExpr());
|
||||
}
|
||||
|
@ -2376,10 +2377,12 @@ llvm::Value *CodeGenFunction::EmitObjCThrowOperand(const Expr *expr) {
|
|||
// @throw A().foo;
|
||||
// where a full retain+autorelease is required and would
|
||||
// otherwise happen after the destructor for the temporary.
|
||||
CodeGenFunction::RunCleanupsScope cleanups(*this);
|
||||
if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(expr))
|
||||
if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(expr)) {
|
||||
enterFullExpression(ewc);
|
||||
expr = ewc->getSubExpr();
|
||||
}
|
||||
|
||||
CodeGenFunction::RunCleanupsScope cleanups(*this);
|
||||
return EmitARCRetainAutoreleaseScalarExpr(expr);
|
||||
}
|
||||
|
||||
|
|
|
@ -35,15 +35,3 @@ void CodeGenFunction::EmitCXXTemporary(const CXXTemporary *Temporary,
|
|||
Temporary->getDestructor(),
|
||||
Ptr);
|
||||
}
|
||||
|
||||
RValue
|
||||
CodeGenFunction::EmitExprWithCleanups(const ExprWithCleanups *E,
|
||||
AggValueSlot Slot) {
|
||||
RunCleanupsScope Scope(*this);
|
||||
return EmitAnyExpr(E->getSubExpr(), Slot);
|
||||
}
|
||||
|
||||
LValue CodeGenFunction::EmitExprWithCleanupsLValue(const ExprWithCleanups *E) {
|
||||
RunCleanupsScope Scope(*this);
|
||||
return EmitLValue(E->getSubExpr());
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
|
|||
: CodeGenTypeCache(cgm), CGM(cgm),
|
||||
Target(CGM.getContext().getTargetInfo()), Builder(cgm.getModule().getContext()),
|
||||
AutoreleaseResult(false), BlockInfo(0), BlockPointer(0),
|
||||
NormalCleanupDest(0), NextCleanupDestIndex(1),
|
||||
NormalCleanupDest(0), NextCleanupDestIndex(1), FirstBlockInfo(0),
|
||||
EHResumeBlock(0), ExceptionSlot(0), EHSelectorSlot(0),
|
||||
DebugInfo(0), DisableDebugInfo(false), DidCallStackSave(false),
|
||||
IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0),
|
||||
|
@ -45,6 +45,14 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
|
|||
CGM.getCXXABI().getMangleContext().startNewFunction();
|
||||
}
|
||||
|
||||
CodeGenFunction::~CodeGenFunction() {
|
||||
// If there are any unclaimed block infos, go ahead and destroy them
|
||||
// now. This can happen if IR-gen gets clever and skips evaluating
|
||||
// something.
|
||||
if (FirstBlockInfo)
|
||||
destroyBlockInfos(FirstBlockInfo);
|
||||
}
|
||||
|
||||
|
||||
llvm::Type *CodeGenFunction::ConvertTypeForMem(QualType T) {
|
||||
return CGM.getTypes().ConvertTypeForMem(T);
|
||||
|
|
|
@ -45,6 +45,7 @@ namespace llvm {
|
|||
namespace clang {
|
||||
class APValue;
|
||||
class ASTContext;
|
||||
class BlockDecl;
|
||||
class CXXDestructorDecl;
|
||||
class CXXForRangeStmt;
|
||||
class CXXTryStmt;
|
||||
|
@ -610,6 +611,9 @@ public:
|
|||
|
||||
unsigned NextCleanupDestIndex;
|
||||
|
||||
/// FirstBlockInfo - The head of a singly-linked-list of block layouts.
|
||||
CGBlockInfo *FirstBlockInfo;
|
||||
|
||||
/// EHResumeBlock - Unified block containing a call to llvm.eh.resume.
|
||||
llvm::BasicBlock *EHResumeBlock;
|
||||
|
||||
|
@ -1169,6 +1173,7 @@ private:
|
|||
|
||||
public:
|
||||
CodeGenFunction(CodeGenModule &cgm);
|
||||
~CodeGenFunction();
|
||||
|
||||
CodeGenTypes &getTypes() const { return CGM.getTypes(); }
|
||||
ASTContext &getContext() const { return CGM.getContext(); }
|
||||
|
@ -1297,6 +1302,8 @@ public:
|
|||
//===--------------------------------------------------------------------===//
|
||||
|
||||
llvm::Value *EmitBlockLiteral(const BlockExpr *);
|
||||
llvm::Value *EmitBlockLiteral(const CGBlockInfo &Info);
|
||||
static void destroyBlockInfos(CGBlockInfo *info);
|
||||
llvm::Constant *BuildDescriptorBlockDecl(const BlockExpr *,
|
||||
const CGBlockInfo &Info,
|
||||
llvm::StructType *,
|
||||
|
@ -2074,7 +2081,6 @@ public:
|
|||
|
||||
LValue EmitCXXConstructLValue(const CXXConstructExpr *E);
|
||||
LValue EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E);
|
||||
LValue EmitExprWithCleanupsLValue(const ExprWithCleanups *E);
|
||||
LValue EmitCXXTypeidLValue(const CXXTypeidExpr *E);
|
||||
|
||||
LValue EmitObjCMessageExprLValue(const ObjCMessageExpr *E);
|
||||
|
@ -2348,8 +2354,11 @@ public:
|
|||
void EmitSynthesizedCXXCopyCtor(llvm::Value *Dest, llvm::Value *Src,
|
||||
const Expr *Exp);
|
||||
|
||||
RValue EmitExprWithCleanups(const ExprWithCleanups *E,
|
||||
AggValueSlot Slot =AggValueSlot::ignored());
|
||||
void enterFullExpression(const ExprWithCleanups *E) {
|
||||
if (E->getNumObjects() == 0) return;
|
||||
enterNonTrivialFullExpression(E);
|
||||
}
|
||||
void enterNonTrivialFullExpression(const ExprWithCleanups *E);
|
||||
|
||||
void EmitCXXThrowExpr(const CXXThrowExpr *E);
|
||||
|
||||
|
|
|
@ -25,15 +25,19 @@ void test2(id x) {
|
|||
// CHECK: define void @test2(
|
||||
// CHECK: [[X:%.*]] = alloca i8*,
|
||||
// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
|
||||
// CHECK-NEXT: alloca i1
|
||||
// CHECK-NEXT: store i1 false
|
||||
// CHECK-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{%.*}})
|
||||
// CHECK-NEXT: store i8* [[PARM]], i8** [[X]]
|
||||
// CHECK-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
|
||||
// CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
|
||||
// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]],
|
||||
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
|
||||
// CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]],
|
||||
// CHECK-NEXT: store i1 true
|
||||
// CHECK-NEXT: bitcast
|
||||
// CHECK-NEXT: call void @test2_helper(
|
||||
// CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]]
|
||||
// CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOTREL]]
|
||||
// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
|
||||
// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]]
|
||||
// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
|
||||
|
@ -233,8 +237,8 @@ void test7(void) {
|
|||
// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[VAR]])
|
||||
// CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T0]])
|
||||
// CHECK: call void @test7_helper(
|
||||
// CHECK-NEXT: call void @objc_destroyWeak(i8** [[SLOT]])
|
||||
// CHECK-NEXT: call void @objc_destroyWeak(i8** [[VAR]])
|
||||
// CHECK-NEXT: call void @objc_destroyWeak(i8** {{%.*}})
|
||||
// CHECK: call void @objc_destroyWeak(i8** [[VAR]])
|
||||
// CHECK-NEXT: ret void
|
||||
|
||||
// CHECK: define internal void @__test7_block_invoke_
|
||||
|
@ -262,15 +266,17 @@ void test7(void) {
|
|||
// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
|
||||
// CHECK: store
|
||||
// CHECK-NEXT: store
|
||||
// CHECK: [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
|
||||
// CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
|
||||
// CHECK-NEXT: [[T1:%.*]] = load [[TEST8]]** [[SELF]],
|
||||
// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST8]]* [[T1]] to i8*
|
||||
// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]])
|
||||
// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[TEST8]]*
|
||||
// CHECK-NEXT: store [[TEST8]]* [[T4]], [[TEST8]]** [[T0]]
|
||||
// CHECK-NEXT: store i1 true,
|
||||
// CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to
|
||||
// CHECK: call void @test8_helper(
|
||||
// CHECK-NEXT: [[T1:%.*]] = load [[TEST8]]** [[T0]]
|
||||
// CHECK-NEXT: [[T1:%.*]] = load [[TEST8]]** [[D0]]
|
||||
// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST8]]* [[T1]] to i8*
|
||||
// CHECK-NEXT: call void @objc_release(i8* [[T2]])
|
||||
// CHECK-NEXT: ret void
|
||||
|
|
|
@ -29,6 +29,9 @@ void test0(NSArray *array) {
|
|||
// CHECK-LP64-NEXT: [[BUFFER:%.*]] = alloca [16 x i8*], align 8
|
||||
// CHECK-LP64-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
|
||||
|
||||
// CHECK-LP64-NEXT: [[CAP_ACTIVE:%.*]] = alloca i1
|
||||
// CHECK-LP64-NEXT: store i1 false, i1* [[CAP_ACTIVE]]
|
||||
|
||||
// Initialize 'array'.
|
||||
// CHECK-LP64-NEXT: [[T0:%.*]] = bitcast [[ARRAY_T:%.*]]* {{%.*}} to i8*
|
||||
// CHECK-LP64-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
|
||||
|
@ -60,13 +63,15 @@ void test0(NSArray *array) {
|
|||
// CHECK-LP64-NEXT: [[T3:%.*]] = load i8** [[T2]]
|
||||
// CHECK-LP64-NEXT: store i8* [[T3]], i8** [[X]]
|
||||
|
||||
// CHECK-LP64: [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
|
||||
// CHECK-LP64: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
|
||||
// CHECK-LP64-NEXT: [[T1:%.*]] = load i8** [[X]]
|
||||
// CHECK-LP64-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
|
||||
// CHECK-LP64-NEXT: store i8* [[T2]], i8** [[T0]]
|
||||
// CHECK-LP64-NEXT: store i1 true, i1* [[CAP_ACTIVE]]
|
||||
// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]]
|
||||
// CHECK-LP64: call void @use_block(
|
||||
// CHECK-LP64-NEXT: [[T1:%.*]] = load i8** [[T0]]
|
||||
// CHECK-LP64-NEXT: [[T1:%.*]] = load i8** [[D0]]
|
||||
// CHECK-LP64-NEXT: call void @objc_release(i8* [[T1]])
|
||||
|
||||
// CHECK-LP64: [[T0:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
|
||||
|
@ -108,13 +113,15 @@ void test1(NSArray *array) {
|
|||
// CHECK-LP64-NEXT: [[T3:%.*]] = load i8** [[T2]]
|
||||
// CHECK-LP64-NEXT: call i8* @objc_initWeak(i8** [[X]], i8* [[T3]])
|
||||
|
||||
// CHECK-LP64: [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
|
||||
// CHECK-LP64: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
|
||||
// CHECK-LP64-NEXT: [[T1:%.*]] = call i8* @objc_loadWeak(i8** [[X]])
|
||||
// CHECK-LP64-NEXT: call i8* @objc_initWeak(i8** [[T0]], i8* [[T1]])
|
||||
// CHECK-LP64-NEXT: store i1 true,
|
||||
// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to
|
||||
// CHECK-LP64: call void @use_block
|
||||
// CHECK-LP64-NEXT: call void @objc_destroyWeak(i8** [[T0]])
|
||||
// CHECK-LP64-NEXT: call void @objc_destroyWeak(i8** [[X]])
|
||||
// CHECK-LP64: call void @objc_destroyWeak(i8** [[D0]])
|
||||
// CHECK-LP64: call void @objc_destroyWeak(i8** [[X]])
|
||||
|
||||
// rdar://problem/9817306
|
||||
@interface Test2
|
||||
|
|
Загрузка…
Ссылка в новой задаче