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