r218865 - Emit lifetime.start / lifetime.end markers for unnamed temporary objects.
Nick Lewycky
nlewycky at google.com
Thu Oct 9 21:12:38 PDT 2014
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 <
arnaud.degrandmaison at arm.com> 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
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20141009/42284b71/attachment.html>
More information about the cfe-commits
mailing list