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&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&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&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&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&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&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&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
