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