<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"><meta name=Generator content="Microsoft Word 14 (filtered medium)"><style><!--
/* Font Definitions */
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:Tahoma;
        panose-1:2 11 6 4 3 5 4 4 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0cm;
        margin-bottom:.0001pt;
        font-size:12.0pt;
        font-family:"Times New Roman","serif";}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:purple;
        text-decoration:underline;}
span.EmailStyle17
        {mso-style-type:personal-reply;
        font-family:"Calibri","sans-serif";
        color:#1F497D;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-family:"Calibri","sans-serif";
        mso-fareast-language:EN-US;}
@page WordSection1
        {size:612.0pt 792.0pt;
        margin:72.0pt 72.0pt 72.0pt 72.0pt;}
div.WordSection1
        {page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]--></head><body lang=EN-GB link=blue vlink=purple><div class=WordSection1><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>I will look into it. Thanks for the testcase.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>We also have PR21220, which is about switch/case statements.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>Cheers,<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>Arnaud<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p><p class=MsoNormal style='margin-left:36.0pt'><b><span lang=EN-US style='font-size:10.0pt;font-family:"Tahoma","sans-serif"'>From:</span></b><span lang=EN-US style='font-size:10.0pt;font-family:"Tahoma","sans-serif"'> Nick Lewycky [mailto:nlewycky@google.com] <br><b>Sent:</b> 10 October 2014 06:13<br><b>To:</b> Arnaud De Grandmaison<br><b>Cc:</b> llvm cfe<br><b>Subject:</b> Re: r218865 - Emit lifetime.start / lifetime.end markers for unnamed temporary objects.<o:p></o:p></span></p><p class=MsoNormal style='margin-left:36.0pt'><o:p> </o:p></p><div><div><div><p class=MsoNormal style='margin-left:36.0pt'>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!<o:p></o:p></p></div><div><p class=MsoNormal style='margin-left:36.0pt'><o:p> </o:p></p></div><div><p class=MsoNormal style='margin-left:36.0pt'>On 2 October 2014 05:19, Arnaud A. de Grandmaison <<a href="mailto:arnaud.degrandmaison@arm.com" target="_blank">arnaud.degrandmaison@arm.com</a>> wrote:<o:p></o:p></p><p class=MsoNormal style='margin-left:36.0pt'>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><o:p></o:p></p></div><p class=MsoNormal style='margin-left:36.0pt'><o:p> </o:p></p></div></div></div></body></html>