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