diff options
-rw-r--r-- | lib/CodeGen/CGBlocks.cpp | 184 | ||||
-rw-r--r-- | lib/CodeGen/CGBlocks.h | 38 | ||||
-rw-r--r-- | lib/CodeGen/CGDecl.cpp | 6 | ||||
-rw-r--r-- | lib/CodeGen/CGExpr.cpp | 15 | ||||
-rw-r--r-- | lib/CodeGen/CGExprAgg.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/CGExprComplex.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/CGExprScalar.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/CGObjC.cpp | 7 | ||||
-rw-r--r-- | lib/CodeGen/CGTemporaries.cpp | 12 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.cpp | 10 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 15 | ||||
-rw-r--r-- | test/CodeGenObjC/arc-blocks.m | 14 | ||||
-rw-r--r-- | test/CodeGenObjC/arc-foreach.m | 13 |
13 files changed, 243 insertions, 83 deletions
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index ce9e30ceba..9825c1ea69 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -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); diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h index 6e71c1fdc0..69f3355084 100644 --- a/lib/CodeGen/CGBlocks.h +++ b/lib/CodeGen/CGBlocks.h @@ -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 diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 384d92a9bf..d685847155 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -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 diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 4d14d18e59..0b6195dc79 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -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: diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 0fda665963..f3e86fbb44 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -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) { diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index e62f9a620e..d58db67917 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -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!"); diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index dfdf7b8640..3fc5c7b015 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -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); diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 88d19a3b6c..686f0e6833 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -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); } diff --git a/lib/CodeGen/CGTemporaries.cpp b/lib/CodeGen/CGTemporaries.cpp index 0387daeb65..7e9ff91a92 100644 --- a/lib/CodeGen/CGTemporaries.cpp +++ b/lib/CodeGen/CGTemporaries.cpp @@ -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()); -} diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 0346936146..0a5efe03be 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -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); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 383eb587ca..c3aca51555 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -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); diff --git a/test/CodeGenObjC/arc-blocks.m b/test/CodeGenObjC/arc-blocks.m index 38675a4393..6ca5c3c352 100644 --- a/test/CodeGenObjC/arc-blocks.m +++ b/test/CodeGenObjC/arc-blocks.m @@ -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 diff --git a/test/CodeGenObjC/arc-foreach.m b/test/CodeGenObjC/arc-foreach.m index 9449b3d2d6..de550328f0 100644 --- a/test/CodeGenObjC/arc-foreach.m +++ b/test/CodeGenObjC/arc-foreach.m @@ -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 |