I will look into it. Thanks for the testcase.
We also have PR21220, which is about switch/case statements. Cheers, Arnaud From: Nick Lewycky [mailto:[email protected]] Sent: 10 October 2014 06:13 To: Arnaud De Grandmaison Cc: llvm cfe Subject: Re: r218865 - Emit lifetime.start / lifetime.end markers for unnamed temporary objects. Arnaud, I think this introduced a regression which is filed as PR21236. I'm going to revert this to unblock myself, but please reapply when fixed. Sorry for the trouble! On 2 October 2014 05:19, Arnaud A. de Grandmaison <[email protected]> wrote: Author: aadg Date: Thu Oct 2 07:19:51 2014 New Revision: 218865 URL: http://llvm.org/viewvc/llvm-project?rev=218865 <http://llvm.org/viewvc/llvm-project?rev=218865&view=rev> &view=rev Log: Emit lifetime.start / lifetime.end markers for unnamed temporary objects. This will give more information to the optimizers so that they can reuse stack slots and reduce stack usage. Added: cfe/trunk/test/CodeGenCXX/unnamed-object-lifetime.cpp Modified: cfe/trunk/lib/CodeGen/CGCleanup.cpp cfe/trunk/lib/CodeGen/CGDecl.cpp cfe/trunk/lib/CodeGen/CGExpr.cpp cfe/trunk/lib/CodeGen/CodeGenFunction.cpp cfe/trunk/lib/CodeGen/CodeGenFunction.h Modified: cfe/trunk/lib/CodeGen/CGCleanup.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCleanup.cpp?rev=218865 <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCleanup.cpp?rev=218865&r1=218864&r2=218865&view=diff> &r1=218864&r2=218865&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGCleanup.cpp (original) +++ cfe/trunk/lib/CodeGen/CGCleanup.cpp Thu Oct 2 07:19:51 2014 @@ -387,14 +387,9 @@ void CodeGenFunction::PopCleanupBlocks(E } } -/// Pops cleanup blocks until the given savepoint is reached, then add the -/// cleanups from the given savepoint in the lifetime-extended cleanups stack. +/// Move our deferred cleanups onto the EH stack. void -CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old, - size_t OldLifetimeExtendedSize) { - PopCleanupBlocks(Old); - - // Move our deferred cleanups onto the EH stack. +CodeGenFunction::MoveDeferedCleanups(size_t OldLifetimeExtendedSize) { for (size_t I = OldLifetimeExtendedSize, E = LifetimeExtendedCleanupStack.size(); I != E; /**/) { // Alignment should be guaranteed by the vptrs in the individual cleanups. @@ -414,6 +409,17 @@ CodeGenFunction::PopCleanupBlocks(EHScop LifetimeExtendedCleanupStack.resize(OldLifetimeExtendedSize); } +/// Pops cleanup blocks until the given savepoint is reached, then add the +/// cleanups from the given savepoint in the lifetime-extended cleanups stack. +void +CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old, + size_t OldLifetimeExtendedSize) { + PopCleanupBlocks(Old); + + // Move our deferred cleanups onto the EH stack. + MoveDeferedCleanups(OldLifetimeExtendedSize); +} + static llvm::BasicBlock *CreateNormalEntry(CodeGenFunction &CGF, EHCleanupScope &Scope) { assert(Scope.isNormalCleanup()); Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=218865 <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=218865&r1=218864&r2=218865&view=diff> &r1=218864&r2=218865&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGDecl.cpp (original) +++ cfe/trunk/lib/CodeGen/CGDecl.cpp Thu Oct 2 07:19:51 2014 @@ -476,12 +476,10 @@ namespace { : Addr(addr), Size(size) {} void Emit(CodeGenFunction &CGF, Flags flags) override { - llvm::Value *castAddr = CGF.Builder.CreateBitCast(Addr, CGF.Int8PtrTy); - CGF.Builder.CreateCall2(CGF.CGM.getLLVMLifetimeEndFn(), - Size, castAddr) - ->setDoesNotThrow(); + CGF.EmitLifetimeEnd(Size, Addr); } }; + } /// EmitAutoVarWithLifetime - Does the setup required for an automatic @@ -800,8 +798,7 @@ static bool shouldUseMemSetPlusStoresToI } /// Should we use the LLVM lifetime intrinsics for the given local variable? -static bool shouldUseLifetimeMarkers(CodeGenFunction &CGF, const VarDecl &D, - unsigned Size) { +static bool shouldUseLifetimeMarkers(CodeGenFunction &CGF, uint64_t Size) { // For now, only in optimized builds. if (CGF.CGM.getCodeGenOpts().OptimizationLevel == 0) return false; @@ -813,7 +810,6 @@ static bool shouldUseLifetimeMarkers(Cod return Size > SizeThreshold; } - /// EmitAutoVarDecl - Emit code and set up an entry in LocalDeclMap for a /// variable declaration with auto, register, or no storage class specifier. /// These turn into simple stack objects, or GlobalValues depending on target. @@ -823,6 +819,27 @@ void CodeGenFunction::EmitAutoVarDecl(co EmitAutoVarCleanups(emission); } +/// Emit a lifetime.begin marker if some criteria are satisfied. +/// \return a pointer to the temporary size Value if a marker was emitted, null +/// otherwise +llvm::Value *CodeGenFunction::EmitLifetimeStart(uint64_t Size, + llvm::Value *Addr) { + if (!shouldUseLifetimeMarkers(*this, Size)) + return nullptr; + + llvm::Value *SizeV = llvm::ConstantInt::get(Int64Ty, Size); + llvm::Value *CastAddr = Builder.CreateBitCast(Addr, Int8PtrTy); + Builder.CreateCall2(CGM.getLLVMLifetimeStartFn(), SizeV, CastAddr) + ->setDoesNotThrow(); + return SizeV; +} + +void CodeGenFunction::EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr) { + llvm::Value *CastAddr = Builder.CreateBitCast(Addr, Int8PtrTy); + Builder.CreateCall2(CGM.getLLVMLifetimeEndFn(), Size, CastAddr) + ->setDoesNotThrow(); +} + /// EmitAutoVarAlloca - Emit the alloca and debug information for a /// local variable. Does not emit initialization or destruction. CodeGenFunction::AutoVarEmission @@ -918,13 +935,8 @@ CodeGenFunction::EmitAutoVarAlloca(const // Emit a lifetime intrinsic if meaningful. There's no point // in doing this if we don't have a valid insertion point (?). uint64_t size = CGM.getDataLayout().getTypeAllocSize(LTy); - if (HaveInsertPoint() && shouldUseLifetimeMarkers(*this, D, size)) { - llvm::Value *sizeV = llvm::ConstantInt::get(Int64Ty, size); - - emission.SizeForLifetimeMarkers = sizeV; - llvm::Value *castAddr = Builder.CreateBitCast(Alloc, Int8PtrTy); - Builder.CreateCall2(CGM.getLLVMLifetimeStartFn(), sizeV, castAddr) - ->setDoesNotThrow(); + if (HaveInsertPoint() && EmitLifetimeStart(size, Alloc)) { + emission.SizeForLifetimeMarkers = llvm::ConstantInt::get(Int64Ty, size); } else { assert(!emission.useLifetimeMarkers()); } @@ -1366,6 +1378,32 @@ void CodeGenFunction::pushLifetimeExtend cleanupKind, addr, type, destroyer, useEHCleanupForArray); } +void +CodeGenFunction::pushLifetimeEndMarker(StorageDuration SD, + llvm::Value *ReferenceTemporary, + llvm::Value *SizeForLifeTimeMarkers) { + // SizeForLifeTimeMarkers is null in case no corresponding + // @llvm.lifetime.start was emitted: there is nothing to do then. + if (!SizeForLifeTimeMarkers) + return; + + switch (SD) { + case SD_FullExpression: + pushFullExprCleanup<CallLifetimeEnd>(NormalAndEHCleanup, ReferenceTemporary, + SizeForLifeTimeMarkers); + return; + case SD_Automatic: + EHStack.pushCleanup<CallLifetimeEnd>(static_cast<CleanupKind>(EHCleanup), + ReferenceTemporary, + SizeForLifeTimeMarkers); + pushCleanupAfterFullExpr<CallLifetimeEnd>( + NormalAndEHCleanup, ReferenceTemporary, SizeForLifeTimeMarkers); + return; + default: + llvm_unreachable("unexpected storage duration for Lifetime markers"); + } +} + /// emitDestroy - Immediately perform the destruction of the given /// object. /// Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=218865 <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=218865&r1=218864&r2=218865&view=diff> &r1=218864&r2=218865&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExpr.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExpr.cpp Thu Oct 2 07:19:51 2014 @@ -173,9 +173,10 @@ void CodeGenFunction::EmitAnyExprToMem(c llvm_unreachable("bad evaluation kind"); } -static void -pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M, - const Expr *E, llvm::Value *ReferenceTemporary) { +static void pushTemporaryCleanup(CodeGenFunction &CGF, + const MaterializeTemporaryExpr *M, + const Expr *E, llvm::Value *ReferenceTemporary, + llvm::Value *SizeForLifeTimeMarkers) { // Objective-C++ ARC: // If we are binding a reference to a temporary that has ownership, we // need to perform retain/release operations on the temporary. @@ -242,6 +243,10 @@ pushTemporaryCleanup(CodeGenFunction &CG } } + // Call @llvm.lifetime.end marker for the temporary. + CGF.pushLifetimeEndMarker(M->getStorageDuration(), ReferenceTemporary, + SizeForLifeTimeMarkers); + CXXDestructorDecl *ReferenceTemporaryDtor = nullptr; if (const RecordType *RT = E->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) { @@ -296,11 +301,18 @@ pushTemporaryCleanup(CodeGenFunction &CG static llvm::Value * createReferenceTemporary(CodeGenFunction &CGF, - const MaterializeTemporaryExpr *M, const Expr *Inner) { + const MaterializeTemporaryExpr *M, const Expr *Inner, + llvm::Value *&SizeForLifeTimeMarkers) { + SizeForLifeTimeMarkers = nullptr; switch (M->getStorageDuration()) { case SD_FullExpression: - case SD_Automatic: - return CGF.CreateMemTemp(Inner->getType(), "ref.tmp"); + case SD_Automatic: { + llvm::Value *RefTemp = CGF.CreateMemTemp(Inner->getType(), "ref.tmp"); + uint64_t TempSize = CGF.CGM.getDataLayout().getTypeStoreSize( + CGF.ConvertTypeForMem(Inner->getType())); + SizeForLifeTimeMarkers = CGF.EmitLifetimeStart(TempSize, RefTemp); + return RefTemp; + } case SD_Thread: case SD_Static: @@ -321,7 +333,8 @@ LValue CodeGenFunction::EmitMaterializeT M->getType().getObjCLifetime() != Qualifiers::OCL_None && M->getType().getObjCLifetime() != Qualifiers::OCL_ExplicitNone) { // FIXME: Fold this into the general case below. - llvm::Value *Object = createReferenceTemporary(*this, M, E); + llvm::Value *ObjectSize; + llvm::Value *Object = createReferenceTemporary(*this, M, E, ObjectSize); LValue RefTempDst = MakeAddrLValue(Object, M->getType()); if (auto *Var = dyn_cast<llvm::GlobalVariable>(Object)) { @@ -333,7 +346,7 @@ LValue CodeGenFunction::EmitMaterializeT EmitScalarInit(E, M->getExtendingDecl(), RefTempDst, false); - pushTemporaryCleanup(*this, M, E, Object); + pushTemporaryCleanup(*this, M, E, Object, ObjectSize); return RefTempDst; } @@ -351,8 +364,10 @@ LValue CodeGenFunction::EmitMaterializeT } } - // Create and initialize the reference temporary. - llvm::Value *Object = createReferenceTemporary(*this, M, E); + // Create and initialize the reference temporary and get the temporary size + llvm::Value *ObjectSize; + llvm::Value *Object = createReferenceTemporary(*this, M, E, ObjectSize); + if (auto *Var = dyn_cast<llvm::GlobalVariable>(Object)) { // If the temporary is a global and has a constant initializer, we may // have already initialized it. @@ -363,7 +378,8 @@ LValue CodeGenFunction::EmitMaterializeT } else { EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/true); } - pushTemporaryCleanup(*this, M, E, Object); + + pushTemporaryCleanup(*this, M, E, Object, ObjectSize); // Perform derived-to-base casts and/or field accesses, to get from the // temporary object we created (and, potentially, for which we extended Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=218865 <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=218865&r1=218864&r2=218865&view=diff> &r1=218864&r2=218865&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Thu Oct 2 07:19:51 2014 @@ -229,6 +229,11 @@ void CodeGenFunction::FinishFunction(Sou DI->EmitLocation(Builder, EndLoc); } + // Some top level lifetime extended variables may still need + // to have their cleanups called. + if (!LifetimeExtendedCleanupStack.empty()) + MoveDeferedCleanups(0); + // Pop any cleanups that might have been associated with the // parameters. Do this in whatever block we're currently in; it's // important to do this before we enter the return block or return Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=218865 <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=218865&r1=218864&r2=218865&view=diff> &r1=218864&r2=218865&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original) +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Thu Oct 2 07:19:51 2014 @@ -444,6 +444,23 @@ public: new (Buffer + sizeof(Header)) T(a0, a1, a2, a3); } + /// \brief Queue a cleanup to be pushed after finishing the current + /// full-expression. + template <class T, class A0, class A1> + void pushCleanupAfterFullExpr(CleanupKind Kind, A0 a0, A1 a1) { + assert(!isInConditionalBranch() && "can't defer conditional cleanup"); + + LifetimeExtendedCleanupHeader Header = { sizeof(T), Kind }; + + size_t OldSize = LifetimeExtendedCleanupStack.size(); + LifetimeExtendedCleanupStack.resize( + LifetimeExtendedCleanupStack.size() + sizeof(Header) + Header.Size); + + char *Buffer = &LifetimeExtendedCleanupStack[OldSize]; + new (Buffer) LifetimeExtendedCleanupHeader(Header); + new (Buffer + sizeof(Header)) T(a0, a1); + } + /// Set up the last cleaup that was pushed as a conditional /// full-expression cleanup. void initFullExprCleanup(); @@ -596,6 +613,10 @@ public: void PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize, size_t OldLifetimeExtendedStackSize); + /// \brief Moves deferred cleanups from lifetime-extended variables from + /// the given position on top of the stack + void MoveDeferedCleanups(size_t OldLifetimeExtendedSize); + void ResolveBranchFixups(llvm::BasicBlock *Target); /// The given basic block lies in the current EH scope, but may be a @@ -1112,6 +1133,9 @@ public: void pushLifetimeExtendedDestroy(CleanupKind kind, llvm::Value *addr, QualType type, Destroyer *destroyer, bool useEHCleanupForArray); + void pushLifetimeEndMarker(StorageDuration SD, + llvm::Value *ReferenceTemporary, + llvm::Value *SizeForLifeTimeMarkers); void pushStackRestore(CleanupKind kind, llvm::Value *SPMem); void emitDestroy(llvm::Value *addr, QualType type, Destroyer *destroyer, bool useEHCleanupForArray); @@ -1715,6 +1739,9 @@ public: void EmitCXXTemporary(const CXXTemporary *Temporary, QualType TempType, llvm::Value *Ptr); + llvm::Value *EmitLifetimeStart(uint64_t Size, llvm::Value *Addr); + void EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr); + llvm::Value *EmitCXXNewExpr(const CXXNewExpr *E); void EmitCXXDeleteExpr(const CXXDeleteExpr *E); Added: cfe/trunk/test/CodeGenCXX/unnamed-object-lifetime.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/unnamed-object-lifetime.cpp?rev=218865 <http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/unnamed-object-lifetime.cpp?rev=218865&view=auto> &view=auto ============================================================================== --- cfe/trunk/test/CodeGenCXX/unnamed-object-lifetime.cpp (added) +++ cfe/trunk/test/CodeGenCXX/unnamed-object-lifetime.cpp Thu Oct 2 07:19:51 2014 @@ -0,0 +1,290 @@ +// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -o - %s | FileCheck --check-prefix=CHECK-EH %s + +// Test lifetime marker generation for unnamed temporary objects. + +struct X { + X(); + ~X(); + char t[33]; // make the class big enough so that lifetime markers get inserted +}; + +extern void useX(const X &); + +// CHECK-LABEL: define void @_Z6simplev +// CHECK-EH-LABEL: define void @_Z6simplev +void simple() { + // CHECK: [[ALLOCA:%.*]] = alloca %struct.X + // CHECK: [[PTR:%.*]] = getelementptr inbounds %struct.X* [[ALLOCA]], i32 0, i32 0, i32 0 + // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[PTR]]) + // CHECK-NEXT: call void @_ZN1XC1Ev + // CHECK-NEXT: call void @_Z4useXRK1X + // CHECK-NEXT: call void @_ZN1XD1Ev + // CHECK-NEXT: call void @llvm.lifetime.end(i64 33, i8* [[PTR]]) + // + // CHECK-EH: [[ALLOCA:%.*]] = alloca %struct.X + // CHECK-EH: [[PTR:%.*]] = getelementptr inbounds %struct.X* [[ALLOCA]], i32 0, i32 0, i32 0 + // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[PTR]]) + // CHECK-EH-NEXT: call void @_ZN1XC1Ev + // CHECK-EH: invoke void @_Z4useXRK1X + // CHECK-EH: invoke void @_ZN1XD1Ev + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[PTR]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[PTR]]) + useX(X()); +} + +// Same as above, but with a sub-scope +// CHECK-LABEL: define void @_Z6simpleb +// CHECK-EH-LABEL: define void @_Z6simpleb +void simple(bool b) { + // CHECK: [[ALLOCA:%.*]] = alloca %struct.X + // CHECK: br i1 %b + // CHECK: [[PTR:%.*]] = getelementptr inbounds %struct.X* [[ALLOCA]], i32 0, i32 0, i32 0 + // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[PTR]]) + // CHECK-NEXT: call void @_ZN1XC1Ev + // CHECK-NEXT: call void @_Z4useXRK1X + // CHECK-NEXT: call void @_ZN1XD1Ev + // CHECK-NEXT: call void @llvm.lifetime.end(i64 33, i8* [[PTR]]) + // + // CHECK-EH: [[ALLOCA:%.*]] = alloca %struct.X + // CHECK-EH: br i1 %b + // CHECK-EH: [[PTR:%.*]] = getelementptr inbounds %struct.X* [[ALLOCA]], i32 0, i32 0, i32 0 + // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[PTR]]) + // CHECK-EH-NEXT: call void @_ZN1XC1Ev + // CHECK-EH: invoke void @_Z4useXRK1X + // CHECK-EH: invoke void @_ZN1XD1Ev + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[PTR]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[PTR]]) + if (b) { + useX(X()); + } +} + +struct Y { + Y(){} + ~Y(){} + char t[34]; // make the class big enough so that lifetime markers get inserted +}; + +extern void useY(const Y &); + +// Check lifetime markers are inserted, despite Y's trivial constructor & destructor +// CHECK-LABEL: define void @_Z7trivialv +// CHECK-EH-LABEL: define void @_Z7trivialv +void trivial() { + // CHECK: [[ALLOCA:%.*]] = alloca %struct.Y + // CHECK: [[PTR:%.*]] = getelementptr inbounds %struct.Y* [[ALLOCA]], i32 0, i32 0, i32 0 + // CHECK: call void @llvm.lifetime.start(i64 34, i8* [[PTR]]) + // CHECK-NEXT: call void @_Z4useYRK1Y + // CHECK-NEXT: call void @llvm.lifetime.end(i64 34, i8* [[PTR]]) + // + // CHECK-EH: [[ALLOCA:%.*]] = alloca %struct.Y + // CHECK-EH: [[PTR:%.*]] = getelementptr inbounds %struct.Y* [[ALLOCA]], i32 0, i32 0, i32 0 + // CHECK-EH: call void @llvm.lifetime.start(i64 34, i8* [[PTR]]) + // CHECK-EH-NEXT: invoke void @_Z4useYRK1Y + // CHECK-EH: call void @llvm.lifetime.end(i64 34, i8* [[PTR]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 34, i8* [[PTR]]) + useY(Y()); +} + +// Same as above, but with a sub-scope +// CHECK-LABEL: define void @_Z7trivialb +// CHECK-EH-LABEL: define void @_Z7trivialb +void trivial(bool b) { + // CHECK: [[ALLOCA:%.*]] = alloca %struct.Y + // CHECK: br i1 %b + // CHECK: [[PTR:%.*]] = getelementptr inbounds %struct.Y* [[ALLOCA]], i32 0, i32 0, i32 0 + // CHECK: call void @llvm.lifetime.start(i64 34, i8* [[PTR]]) + // CHECK-NEXT: call void @_Z4useYRK1Y + // CHECK-NEXT: call void @llvm.lifetime.end(i64 34, i8* [[PTR]]) + // + // CHECK-EH: [[ALLOCA:%.*]] = alloca %struct.Y + // CHECK-EH: br i1 %b + // CHECK-EH: [[PTR:%.*]] = getelementptr inbounds %struct.Y* [[ALLOCA]], i32 0, i32 0, i32 0 + // CHECK-EH: call void @llvm.lifetime.start(i64 34, i8* [[PTR]]) + // CHECK-EH-NEXT: invoke void @_Z4useYRK1Y + // CHECK-EH: call void @llvm.lifetime.end(i64 34, i8* [[PTR]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 34, i8* [[PTR]]) + if (b) { + useY(Y()); + } +} + +struct Z { + Z(); + ~Z(); + char t; +}; + +extern void useZ(const Z &); + +// Check lifetime markers are not inserted if the unnamed object is too small +// CHECK-LABEL: define void @_Z8tooSmallv +// CHECK-EH-LABEL: define void @_Z8tooSmallv +void tooSmall() { + // CHECK-NOT: call void @llvm.lifetime.start + // CHECK: call void @_Z4useZRK1Z + // CHECK-NOT: call void @llvm.lifetime.end + // CHECK: ret + // + // CHECK-EH-NOT: call void @llvm.lifetime.start + // CHECK-EH: invoke void @_Z4useZRK1Z + // CHECK-EH-NOT: call void @llvm.lifetime.end + // CHECK-EH: ret + useZ(Z()); +} + +// Check the lifetime are inserted at the right place in their respective scope +// CHECK-LABEL: define void @_Z6scopesv +// CHECK-EH-LABEL: define void @_Z6scopesv +void scopes() { + // CHECK: alloca %struct + // CHECK: alloca %struct + // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[X:%.*]]) + // CHECK: call void @llvm.lifetime.end(i64 33, i8* [[X]]) + // CHECK: call void @llvm.lifetime.start(i64 34, i8* [[Y:%.*]]) + // CHECK: call void @llvm.lifetime.end(i64 34, i8* [[Y]]) + // + // CHECK-EH: alloca %struct + // CHECK-EH: alloca %struct + // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[X:%.*]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[X]]) + // CHECK-EH: call void @llvm.lifetime.start(i64 34, i8* [[Y:%.*]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 34, i8* [[Y]]) + useX(X()); + useY(Y()); +} + +struct L { + L(int); + ~L(); + char t[33]; +}; + +// Check the lifetime-extended case, with a non trivial destructor +// and a top level scope +// CHECK-LABEL: define void @_Z16extendedLifetimev +// CHECK-EH-LABEL: define void @_Z16extendedLifetimev +void extendedLifetime() { + extern void useL(const L&); + + // CHECK: [[A:%.*]] = alloca %struct.L + // CHECK: [[P:%.*]] = getelementptr inbounds %struct.L* [[A]], i32 0, i32 0, i32 0 + // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[P]]) + // CHECK: call void @_ZN1LC1Ei(%struct.L* [[A]], i32 2) + // CHECK-NOT: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // CHECK: call void @_Z4useLRK1L(%struct.L* dereferenceable(33) [[A]]) + // CHECK: call void @_ZN1LD1Ev(%struct.L* [[A]]) + // CHECK-NEXT: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // + // CHECK-EH: [[A:%.*]] = alloca %struct.L + // CHECK-EH: [[P:%.*]] = getelementptr inbounds %struct.L* [[A]], i32 0, i32 0, i32 0 + // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[P]]) + // CHECK-EH: call void @_ZN1LC1Ei(%struct.L* [[A]], i32 2) + // CHECK-EH-NOT: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // CHECK-EH: invoke void @_Z4useLRK1L(%struct.L* dereferenceable(33) [[A]]) + // CHECK-EH: invoke void @_ZN1LD1Ev(%struct.L* [[A]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // CHECK-EH: invoke void @_ZN1LD1Ev(%struct.L* [[A]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + const L &l = 2; + useL(l); +} + +// Check the lifetime-extended case, with a non trivial destructor in a +// sub-scope +// CHECK-LABEL: define void @_Z16extendedLifetimeb +// CHECK-EH-LABEL: define void @_Z16extendedLifetimeb +void extendedLifetime(bool b) { + extern void useL(const L&); + + // CHECK: [[A:%.*]] = alloca %struct.L + // CHECK: br i1 %b + // CHECK: [[P:%.*]] = getelementptr inbounds %struct.L* [[A]], i32 0, i32 0, i32 0 + // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[P]]) + // CHECK: call void @_ZN1LC1Ei(%struct.L* [[A]], i32 2) + // CHECK-NOT: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // CHECK: call void @_Z4useLRK1L(%struct.L* dereferenceable(33) [[A]]) + // CHECK: call void @_ZN1LD1Ev(%struct.L* [[A]]) + // CHECK-NEXT: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // + // CHECK-EH: [[A:%.*]] = alloca %struct.L + // CHECK-EH: br i1 %b + // CHECK-EH: [[P:%.*]] = getelementptr inbounds %struct.L* [[A]], i32 0, i32 0, i32 0 + // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[P]]) + // CHECK-EH: call void @_ZN1LC1Ei(%struct.L* [[A]], i32 2) + // CHECK-EH-NOT: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // CHECK-EH: invoke void @_Z4useLRK1L(%struct.L* dereferenceable(33) [[A]]) + // CHECK-EH: invoke void @_ZN1LD1Ev(%struct.L* [[A]]) + // CHECK-EH: invoke void @_ZN1LD1Ev(%struct.L* [[A]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + if (b) { + const L &l = 2; + useL(l); + } +} + +struct T { + T(); + T(int); + char t[33]; +}; + +// Check the lifetime-extended case, with a trivial destructor, +// in a sub-scope +// CHECK-LABEL: define void @_Z37extendedLifetimeWithTrivialDestructorb +// CHECK-EH-LABEL: define void @_Z37extendedLifetimeWithTrivialDestructorb +void extendedLifetimeWithTrivialDestructor(bool b) { + extern void useT(const T &); + + // CHECK: [[A:%.*]] = alloca %struct.T + // CHECK: br i1 %b + // CHECK: [[P:%.*]] = getelementptr inbounds %struct.T* [[A]], i32 0, i32 0, i32 0 + // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[P]]) + // CHECK: call void @_ZN1TC1Ei(%struct.T* [[A]], i32 2) + // CHECK: call void @_Z4useTRK1T(%struct.T* dereferenceable(33) [[A]]) + // CHECK: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // CHECK: br label + // + // CHECK-EH: [[A:%.*]] = alloca %struct.T + // CHECK-EH: br i1 %b + // CHECK-EH: [[P:%.*]] = getelementptr inbounds %struct.T* [[A]], i32 0, i32 0, i32 0 + // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[P]]) + // CHECK-EH: call void @_ZN1TC1Ei(%struct.T* [[A]], i32 2) + // CHECK-EH: invoke void @_Z4useTRK1T(%struct.T* dereferenceable(33) [[A]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // CHECK-EH-NEXT: resume + if (b) { + const T &t = 2; + useT(t); + } +} + +// Check the lifetime-extended case, with a trivial destructor and a top level +// scope +// CHECK-LABEL: define void @_Z37extendedLifetimeWithTrivialDestructorv +// CHECK-EH-LABEL: define void @_Z37extendedLifetimeWithTrivialDestructorv +void extendedLifetimeWithTrivialDestructor() { + extern void useT(const T &); + + // CHECK: [[A:%.*]] = alloca %struct.T + // CHECK: [[P:%.*]] = getelementptr inbounds %struct.T* [[A]], i32 0, i32 0, i32 0 + // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[P]]) + // CHECK: call void @_ZN1TC1Ei(%struct.T* [[A]], i32 3) + // CHECK: call void @_Z4useTRK1T(%struct.T* dereferenceable(33) [[A]]) + // CHECK: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // CHECK-NEXT: ret + // + // CHECK-EH: [[A:%.*]] = alloca %struct.T + // CHECK-EH: [[P:%.*]] = getelementptr inbounds %struct.T* [[A]], i32 0, i32 0, i32 0 + // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[P]]) + // CHECK-EH: call void @_ZN1TC1Ei(%struct.T* [[A]], i32 3) + // CHECK-EH: invoke void @_Z4useTRK1T(%struct.T* dereferenceable(33) [[A]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // CHECK-EH-NEXT: ret + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // CHECK-EH-NEXT: resume + const T &t = 3; + useT(t); +} _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
