From bc3b0e98dcf3ce6e9cfe657326fb29611a85914c Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 10 Oct 2014 04:05:00 +0000 Subject: [PATCH] Revert r218865 because it introduced PR21236, a crash in codegen emitting the try block. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@219470 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGCleanup.cpp | 20 +- lib/CodeGen/CGDecl.cpp | 66 +---- lib/CodeGen/CGExpr.cpp | 38 +-- lib/CodeGen/CodeGenFunction.cpp | 5 - lib/CodeGen/CodeGenFunction.h | 27 -- test/CodeGenCXX/unnamed-object-lifetime.cpp | 290 -------------------- 6 files changed, 32 insertions(+), 414 deletions(-) delete mode 100644 test/CodeGenCXX/unnamed-object-lifetime.cpp diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp index 12c587ee95..4482f1c1d6 100644 --- a/lib/CodeGen/CGCleanup.cpp +++ b/lib/CodeGen/CGCleanup.cpp @@ -387,9 +387,14 @@ void CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old) { } } -/// Move our deferred cleanups onto the EH stack. +/// Pops cleanup blocks until the given savepoint is reached, then add the +/// cleanups from the given savepoint in the lifetime-extended cleanups stack. void -CodeGenFunction::MoveDeferedCleanups(size_t OldLifetimeExtendedSize) { +CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old, + size_t OldLifetimeExtendedSize) { + PopCleanupBlocks(Old); + + // Move our deferred cleanups onto the EH stack. for (size_t I = OldLifetimeExtendedSize, E = LifetimeExtendedCleanupStack.size(); I != E; /**/) { // Alignment should be guaranteed by the vptrs in the individual cleanups. @@ -409,17 +414,6 @@ CodeGenFunction::MoveDeferedCleanups(size_t OldLifetimeExtendedSize) { LifetimeExtendedCleanupStack.resize(OldLifetimeExtendedSize); } -/// Pops cleanup blocks until the given savepoint is reached, then add the -/// cleanups from the given savepoint in the lifetime-extended cleanups stack. -void -CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old, - size_t OldLifetimeExtendedSize) { - PopCleanupBlocks(Old); - - // Move our deferred cleanups onto the EH stack. - MoveDeferedCleanups(OldLifetimeExtendedSize); -} - static llvm::BasicBlock *CreateNormalEntry(CodeGenFunction &CGF, EHCleanupScope &Scope) { assert(Scope.isNormalCleanup()); diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 24575ce6d4..81ca2e6f83 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -504,10 +504,12 @@ namespace { : Addr(addr), Size(size) {} void Emit(CodeGenFunction &CGF, Flags flags) override { - CGF.EmitLifetimeEnd(Size, Addr); + llvm::Value *castAddr = CGF.Builder.CreateBitCast(Addr, CGF.Int8PtrTy); + CGF.Builder.CreateCall2(CGF.CGM.getLLVMLifetimeEndFn(), + Size, castAddr) + ->setDoesNotThrow(); } }; - } /// EmitAutoVarWithLifetime - Does the setup required for an automatic @@ -826,7 +828,8 @@ static bool shouldUseMemSetPlusStoresToInitialize(llvm::Constant *Init, } /// Should we use the LLVM lifetime intrinsics for the given local variable? -static bool shouldUseLifetimeMarkers(CodeGenFunction &CGF, uint64_t Size) { +static bool shouldUseLifetimeMarkers(CodeGenFunction &CGF, const VarDecl &D, + unsigned Size) { // For now, only in optimized builds. if (CGF.CGM.getCodeGenOpts().OptimizationLevel == 0) return false; @@ -838,6 +841,7 @@ static bool shouldUseLifetimeMarkers(CodeGenFunction &CGF, uint64_t Size) { return Size > SizeThreshold; } + /// EmitAutoVarDecl - Emit code and set up an entry in LocalDeclMap for a /// variable declaration with auto, register, or no storage class specifier. /// These turn into simple stack objects, or GlobalValues depending on target. @@ -847,27 +851,6 @@ void CodeGenFunction::EmitAutoVarDecl(const VarDecl &D) { EmitAutoVarCleanups(emission); } -/// Emit a lifetime.begin marker if some criteria are satisfied. -/// \return a pointer to the temporary size Value if a marker was emitted, null -/// otherwise -llvm::Value *CodeGenFunction::EmitLifetimeStart(uint64_t Size, - llvm::Value *Addr) { - if (!shouldUseLifetimeMarkers(*this, Size)) - return nullptr; - - llvm::Value *SizeV = llvm::ConstantInt::get(Int64Ty, Size); - llvm::Value *CastAddr = Builder.CreateBitCast(Addr, Int8PtrTy); - Builder.CreateCall2(CGM.getLLVMLifetimeStartFn(), SizeV, CastAddr) - ->setDoesNotThrow(); - return SizeV; -} - -void CodeGenFunction::EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr) { - llvm::Value *CastAddr = Builder.CreateBitCast(Addr, Int8PtrTy); - Builder.CreateCall2(CGM.getLLVMLifetimeEndFn(), Size, CastAddr) - ->setDoesNotThrow(); -} - /// EmitAutoVarAlloca - Emit the alloca and debug information for a /// local variable. Does not emit initialization or destruction. CodeGenFunction::AutoVarEmission @@ -963,8 +946,13 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { // Emit a lifetime intrinsic if meaningful. There's no point // in doing this if we don't have a valid insertion point (?). uint64_t size = CGM.getDataLayout().getTypeAllocSize(LTy); - if (HaveInsertPoint() && EmitLifetimeStart(size, Alloc)) { - emission.SizeForLifetimeMarkers = llvm::ConstantInt::get(Int64Ty, size); + if (HaveInsertPoint() && shouldUseLifetimeMarkers(*this, D, size)) { + llvm::Value *sizeV = llvm::ConstantInt::get(Int64Ty, size); + + emission.SizeForLifetimeMarkers = sizeV; + llvm::Value *castAddr = Builder.CreateBitCast(Alloc, Int8PtrTy); + Builder.CreateCall2(CGM.getLLVMLifetimeStartFn(), sizeV, castAddr) + ->setDoesNotThrow(); } else { assert(!emission.useLifetimeMarkers()); } @@ -1406,32 +1394,6 @@ void CodeGenFunction::pushLifetimeExtendedDestroy( cleanupKind, addr, type, destroyer, useEHCleanupForArray); } -void -CodeGenFunction::pushLifetimeEndMarker(StorageDuration SD, - llvm::Value *ReferenceTemporary, - llvm::Value *SizeForLifeTimeMarkers) { - // SizeForLifeTimeMarkers is null in case no corresponding - // @llvm.lifetime.start was emitted: there is nothing to do then. - if (!SizeForLifeTimeMarkers) - return; - - switch (SD) { - case SD_FullExpression: - pushFullExprCleanup(NormalAndEHCleanup, ReferenceTemporary, - SizeForLifeTimeMarkers); - return; - case SD_Automatic: - EHStack.pushCleanup(static_cast(EHCleanup), - ReferenceTemporary, - SizeForLifeTimeMarkers); - pushCleanupAfterFullExpr( - NormalAndEHCleanup, ReferenceTemporary, SizeForLifeTimeMarkers); - return; - default: - llvm_unreachable("unexpected storage duration for Lifetime markers"); - } -} - /// emitDestroy - Immediately perform the destruction of the given /// object. /// diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 19f6e94999..54c2fd2647 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -174,10 +174,9 @@ void CodeGenFunction::EmitAnyExprToMem(const Expr *E, llvm_unreachable("bad evaluation kind"); } -static void pushTemporaryCleanup(CodeGenFunction &CGF, - const MaterializeTemporaryExpr *M, - const Expr *E, llvm::Value *ReferenceTemporary, - llvm::Value *SizeForLifeTimeMarkers) { +static void +pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M, + const Expr *E, llvm::Value *ReferenceTemporary) { // Objective-C++ ARC: // If we are binding a reference to a temporary that has ownership, we // need to perform retain/release operations on the temporary. @@ -244,10 +243,6 @@ static void pushTemporaryCleanup(CodeGenFunction &CGF, } } - // Call @llvm.lifetime.end marker for the temporary. - CGF.pushLifetimeEndMarker(M->getStorageDuration(), ReferenceTemporary, - SizeForLifeTimeMarkers); - CXXDestructorDecl *ReferenceTemporaryDtor = nullptr; if (const RecordType *RT = E->getType()->getBaseElementTypeUnsafe()->getAs()) { @@ -302,18 +297,11 @@ static void pushTemporaryCleanup(CodeGenFunction &CGF, static llvm::Value * createReferenceTemporary(CodeGenFunction &CGF, - const MaterializeTemporaryExpr *M, const Expr *Inner, - llvm::Value *&SizeForLifeTimeMarkers) { - SizeForLifeTimeMarkers = nullptr; + const MaterializeTemporaryExpr *M, const Expr *Inner) { switch (M->getStorageDuration()) { case SD_FullExpression: - case SD_Automatic: { - llvm::Value *RefTemp = CGF.CreateMemTemp(Inner->getType(), "ref.tmp"); - uint64_t TempSize = CGF.CGM.getDataLayout().getTypeStoreSize( - CGF.ConvertTypeForMem(Inner->getType())); - SizeForLifeTimeMarkers = CGF.EmitLifetimeStart(TempSize, RefTemp); - return RefTemp; - } + case SD_Automatic: + return CGF.CreateMemTemp(Inner->getType(), "ref.tmp"); case SD_Thread: case SD_Static: @@ -334,8 +322,7 @@ LValue CodeGenFunction::EmitMaterializeTemporaryExpr( M->getType().getObjCLifetime() != Qualifiers::OCL_None && M->getType().getObjCLifetime() != Qualifiers::OCL_ExplicitNone) { // FIXME: Fold this into the general case below. - llvm::Value *ObjectSize; - llvm::Value *Object = createReferenceTemporary(*this, M, E, ObjectSize); + llvm::Value *Object = createReferenceTemporary(*this, M, E); LValue RefTempDst = MakeAddrLValue(Object, M->getType()); if (auto *Var = dyn_cast(Object)) { @@ -347,7 +334,7 @@ LValue CodeGenFunction::EmitMaterializeTemporaryExpr( EmitScalarInit(E, M->getExtendingDecl(), RefTempDst, false); - pushTemporaryCleanup(*this, M, E, Object, ObjectSize); + pushTemporaryCleanup(*this, M, E, Object); return RefTempDst; } @@ -365,10 +352,8 @@ LValue CodeGenFunction::EmitMaterializeTemporaryExpr( } } - // Create and initialize the reference temporary and get the temporary size - llvm::Value *ObjectSize; - llvm::Value *Object = createReferenceTemporary(*this, M, E, ObjectSize); - + // Create and initialize the reference temporary. + llvm::Value *Object = createReferenceTemporary(*this, M, E); if (auto *Var = dyn_cast(Object)) { // If the temporary is a global and has a constant initializer, we may // have already initialized it. @@ -379,8 +364,7 @@ LValue CodeGenFunction::EmitMaterializeTemporaryExpr( } else { EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/true); } - - pushTemporaryCleanup(*this, M, E, Object, ObjectSize); + pushTemporaryCleanup(*this, M, E, Object); // Perform derived-to-base casts and/or field accesses, to get from the // temporary object we created (and, potentially, for which we extended diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 9361771834..9f35918538 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -229,11 +229,6 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { DI->EmitLocation(Builder, EndLoc); } - // Some top level lifetime extended variables may still need - // to have their cleanups called. - if (!LifetimeExtendedCleanupStack.empty()) - MoveDeferedCleanups(0); - // Pop any cleanups that might have been associated with the // parameters. Do this in whatever block we're currently in; it's // important to do this before we enter the return block or return diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 1c5111a598..92a743160e 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -445,23 +445,6 @@ public: new (Buffer + sizeof(Header)) T(a0, a1, a2, a3); } - /// \brief Queue a cleanup to be pushed after finishing the current - /// full-expression. - template - void pushCleanupAfterFullExpr(CleanupKind Kind, A0 a0, A1 a1) { - assert(!isInConditionalBranch() && "can't defer conditional cleanup"); - - LifetimeExtendedCleanupHeader Header = { sizeof(T), Kind }; - - size_t OldSize = LifetimeExtendedCleanupStack.size(); - LifetimeExtendedCleanupStack.resize( - LifetimeExtendedCleanupStack.size() + sizeof(Header) + Header.Size); - - char *Buffer = &LifetimeExtendedCleanupStack[OldSize]; - new (Buffer) LifetimeExtendedCleanupHeader(Header); - new (Buffer + sizeof(Header)) T(a0, a1); - } - /// Set up the last cleaup that was pushed as a conditional /// full-expression cleanup. void initFullExprCleanup(); @@ -614,10 +597,6 @@ public: void PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize, size_t OldLifetimeExtendedStackSize); - /// \brief Moves deferred cleanups from lifetime-extended variables from - /// the given position on top of the stack - void MoveDeferedCleanups(size_t OldLifetimeExtendedSize); - void ResolveBranchFixups(llvm::BasicBlock *Target); /// The given basic block lies in the current EH scope, but may be a @@ -1134,9 +1113,6 @@ public: void pushLifetimeExtendedDestroy(CleanupKind kind, llvm::Value *addr, QualType type, Destroyer *destroyer, bool useEHCleanupForArray); - void pushLifetimeEndMarker(StorageDuration SD, - llvm::Value *ReferenceTemporary, - llvm::Value *SizeForLifeTimeMarkers); void pushStackRestore(CleanupKind kind, llvm::Value *SPMem); void emitDestroy(llvm::Value *addr, QualType type, Destroyer *destroyer, bool useEHCleanupForArray); @@ -1740,9 +1716,6 @@ public: void EmitCXXTemporary(const CXXTemporary *Temporary, QualType TempType, llvm::Value *Ptr); - llvm::Value *EmitLifetimeStart(uint64_t Size, llvm::Value *Addr); - void EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr); - llvm::Value *EmitCXXNewExpr(const CXXNewExpr *E); void EmitCXXDeleteExpr(const CXXDeleteExpr *E); diff --git a/test/CodeGenCXX/unnamed-object-lifetime.cpp b/test/CodeGenCXX/unnamed-object-lifetime.cpp deleted file mode 100644 index 22a64bcd4d..0000000000 --- a/test/CodeGenCXX/unnamed-object-lifetime.cpp +++ /dev/null @@ -1,290 +0,0 @@ -// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -o - %s | FileCheck %s -// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -o - %s | FileCheck --check-prefix=CHECK-EH %s - -// Test lifetime marker generation for unnamed temporary objects. - -struct X { - X(); - ~X(); - char t[33]; // make the class big enough so that lifetime markers get inserted -}; - -extern void useX(const X &); - -// CHECK-LABEL: define void @_Z6simplev -// CHECK-EH-LABEL: define void @_Z6simplev -void simple() { - // CHECK: [[ALLOCA:%.*]] = alloca %struct.X - // CHECK: [[PTR:%.*]] = getelementptr inbounds %struct.X* [[ALLOCA]], i32 0, i32 0, i32 0 - // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[PTR]]) - // CHECK-NEXT: call void @_ZN1XC1Ev - // CHECK-NEXT: call void @_Z4useXRK1X - // CHECK-NEXT: call void @_ZN1XD1Ev - // CHECK-NEXT: call void @llvm.lifetime.end(i64 33, i8* [[PTR]]) - // - // CHECK-EH: [[ALLOCA:%.*]] = alloca %struct.X - // CHECK-EH: [[PTR:%.*]] = getelementptr inbounds %struct.X* [[ALLOCA]], i32 0, i32 0, i32 0 - // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[PTR]]) - // CHECK-EH-NEXT: call void @_ZN1XC1Ev - // CHECK-EH: invoke void @_Z4useXRK1X - // CHECK-EH: invoke void @_ZN1XD1Ev - // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[PTR]]) - // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[PTR]]) - useX(X()); -} - -// Same as above, but with a sub-scope -// CHECK-LABEL: define void @_Z6simpleb -// CHECK-EH-LABEL: define void @_Z6simpleb -void simple(bool b) { - // CHECK: [[ALLOCA:%.*]] = alloca %struct.X - // CHECK: br i1 %b - // CHECK: [[PTR:%.*]] = getelementptr inbounds %struct.X* [[ALLOCA]], i32 0, i32 0, i32 0 - // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[PTR]]) - // CHECK-NEXT: call void @_ZN1XC1Ev - // CHECK-NEXT: call void @_Z4useXRK1X - // CHECK-NEXT: call void @_ZN1XD1Ev - // CHECK-NEXT: call void @llvm.lifetime.end(i64 33, i8* [[PTR]]) - // - // CHECK-EH: [[ALLOCA:%.*]] = alloca %struct.X - // CHECK-EH: br i1 %b - // CHECK-EH: [[PTR:%.*]] = getelementptr inbounds %struct.X* [[ALLOCA]], i32 0, i32 0, i32 0 - // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[PTR]]) - // CHECK-EH-NEXT: call void @_ZN1XC1Ev - // CHECK-EH: invoke void @_Z4useXRK1X - // CHECK-EH: invoke void @_ZN1XD1Ev - // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[PTR]]) - // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[PTR]]) - if (b) { - useX(X()); - } -} - -struct Y { - Y(){} - ~Y(){} - char t[34]; // make the class big enough so that lifetime markers get inserted -}; - -extern void useY(const Y &); - -// Check lifetime markers are inserted, despite Y's trivial constructor & destructor -// CHECK-LABEL: define void @_Z7trivialv -// CHECK-EH-LABEL: define void @_Z7trivialv -void trivial() { - // CHECK: [[ALLOCA:%.*]] = alloca %struct.Y - // CHECK: [[PTR:%.*]] = getelementptr inbounds %struct.Y* [[ALLOCA]], i32 0, i32 0, i32 0 - // CHECK: call void @llvm.lifetime.start(i64 34, i8* [[PTR]]) - // CHECK-NEXT: call void @_Z4useYRK1Y - // CHECK-NEXT: call void @llvm.lifetime.end(i64 34, i8* [[PTR]]) - // - // CHECK-EH: [[ALLOCA:%.*]] = alloca %struct.Y - // CHECK-EH: [[PTR:%.*]] = getelementptr inbounds %struct.Y* [[ALLOCA]], i32 0, i32 0, i32 0 - // CHECK-EH: call void @llvm.lifetime.start(i64 34, i8* [[PTR]]) - // CHECK-EH-NEXT: invoke void @_Z4useYRK1Y - // CHECK-EH: call void @llvm.lifetime.end(i64 34, i8* [[PTR]]) - // CHECK-EH: call void @llvm.lifetime.end(i64 34, i8* [[PTR]]) - useY(Y()); -} - -// Same as above, but with a sub-scope -// CHECK-LABEL: define void @_Z7trivialb -// CHECK-EH-LABEL: define void @_Z7trivialb -void trivial(bool b) { - // CHECK: [[ALLOCA:%.*]] = alloca %struct.Y - // CHECK: br i1 %b - // CHECK: [[PTR:%.*]] = getelementptr inbounds %struct.Y* [[ALLOCA]], i32 0, i32 0, i32 0 - // CHECK: call void @llvm.lifetime.start(i64 34, i8* [[PTR]]) - // CHECK-NEXT: call void @_Z4useYRK1Y - // CHECK-NEXT: call void @llvm.lifetime.end(i64 34, i8* [[PTR]]) - // - // CHECK-EH: [[ALLOCA:%.*]] = alloca %struct.Y - // CHECK-EH: br i1 %b - // CHECK-EH: [[PTR:%.*]] = getelementptr inbounds %struct.Y* [[ALLOCA]], i32 0, i32 0, i32 0 - // CHECK-EH: call void @llvm.lifetime.start(i64 34, i8* [[PTR]]) - // CHECK-EH-NEXT: invoke void @_Z4useYRK1Y - // CHECK-EH: call void @llvm.lifetime.end(i64 34, i8* [[PTR]]) - // CHECK-EH: call void @llvm.lifetime.end(i64 34, i8* [[PTR]]) - if (b) { - useY(Y()); - } -} - -struct Z { - Z(); - ~Z(); - char t; -}; - -extern void useZ(const Z &); - -// Check lifetime markers are not inserted if the unnamed object is too small -// CHECK-LABEL: define void @_Z8tooSmallv -// CHECK-EH-LABEL: define void @_Z8tooSmallv -void tooSmall() { - // CHECK-NOT: call void @llvm.lifetime.start - // CHECK: call void @_Z4useZRK1Z - // CHECK-NOT: call void @llvm.lifetime.end - // CHECK: ret - // - // CHECK-EH-NOT: call void @llvm.lifetime.start - // CHECK-EH: invoke void @_Z4useZRK1Z - // CHECK-EH-NOT: call void @llvm.lifetime.end - // CHECK-EH: ret - useZ(Z()); -} - -// Check the lifetime are inserted at the right place in their respective scope -// CHECK-LABEL: define void @_Z6scopesv -// CHECK-EH-LABEL: define void @_Z6scopesv -void scopes() { - // CHECK: alloca %struct - // CHECK: alloca %struct - // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[X:%.*]]) - // CHECK: call void @llvm.lifetime.end(i64 33, i8* [[X]]) - // CHECK: call void @llvm.lifetime.start(i64 34, i8* [[Y:%.*]]) - // CHECK: call void @llvm.lifetime.end(i64 34, i8* [[Y]]) - // - // CHECK-EH: alloca %struct - // CHECK-EH: alloca %struct - // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[X:%.*]]) - // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[X]]) - // CHECK-EH: call void @llvm.lifetime.start(i64 34, i8* [[Y:%.*]]) - // CHECK-EH: call void @llvm.lifetime.end(i64 34, i8* [[Y]]) - useX(X()); - useY(Y()); -} - -struct L { - L(int); - ~L(); - char t[33]; -}; - -// Check the lifetime-extended case, with a non trivial destructor -// and a top level scope -// CHECK-LABEL: define void @_Z16extendedLifetimev -// CHECK-EH-LABEL: define void @_Z16extendedLifetimev -void extendedLifetime() { - extern void useL(const L&); - - // CHECK: [[A:%.*]] = alloca %struct.L - // CHECK: [[P:%.*]] = getelementptr inbounds %struct.L* [[A]], i32 0, i32 0, i32 0 - // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[P]]) - // CHECK: call void @_ZN1LC1Ei(%struct.L* [[A]], i32 2) - // CHECK-NOT: call void @llvm.lifetime.end(i64 33, i8* [[P]]) - // CHECK: call void @_Z4useLRK1L(%struct.L* dereferenceable(33) [[A]]) - // CHECK: call void @_ZN1LD1Ev(%struct.L* [[A]]) - // CHECK-NEXT: call void @llvm.lifetime.end(i64 33, i8* [[P]]) - // - // CHECK-EH: [[A:%.*]] = alloca %struct.L - // CHECK-EH: [[P:%.*]] = getelementptr inbounds %struct.L* [[A]], i32 0, i32 0, i32 0 - // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[P]]) - // CHECK-EH: call void @_ZN1LC1Ei(%struct.L* [[A]], i32 2) - // CHECK-EH-NOT: call void @llvm.lifetime.end(i64 33, i8* [[P]]) - // CHECK-EH: invoke void @_Z4useLRK1L(%struct.L* dereferenceable(33) [[A]]) - // CHECK-EH: invoke void @_ZN1LD1Ev(%struct.L* [[A]]) - // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]]) - // CHECK-EH: invoke void @_ZN1LD1Ev(%struct.L* [[A]]) - // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]]) - const L &l = 2; - useL(l); -} - -// Check the lifetime-extended case, with a non trivial destructor in a -// sub-scope -// CHECK-LABEL: define void @_Z16extendedLifetimeb -// CHECK-EH-LABEL: define void @_Z16extendedLifetimeb -void extendedLifetime(bool b) { - extern void useL(const L&); - - // CHECK: [[A:%.*]] = alloca %struct.L - // CHECK: br i1 %b - // CHECK: [[P:%.*]] = getelementptr inbounds %struct.L* [[A]], i32 0, i32 0, i32 0 - // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[P]]) - // CHECK: call void @_ZN1LC1Ei(%struct.L* [[A]], i32 2) - // CHECK-NOT: call void @llvm.lifetime.end(i64 33, i8* [[P]]) - // CHECK: call void @_Z4useLRK1L(%struct.L* dereferenceable(33) [[A]]) - // CHECK: call void @_ZN1LD1Ev(%struct.L* [[A]]) - // CHECK-NEXT: call void @llvm.lifetime.end(i64 33, i8* [[P]]) - // - // CHECK-EH: [[A:%.*]] = alloca %struct.L - // CHECK-EH: br i1 %b - // CHECK-EH: [[P:%.*]] = getelementptr inbounds %struct.L* [[A]], i32 0, i32 0, i32 0 - // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[P]]) - // CHECK-EH: call void @_ZN1LC1Ei(%struct.L* [[A]], i32 2) - // CHECK-EH-NOT: call void @llvm.lifetime.end(i64 33, i8* [[P]]) - // CHECK-EH: invoke void @_Z4useLRK1L(%struct.L* dereferenceable(33) [[A]]) - // CHECK-EH: invoke void @_ZN1LD1Ev(%struct.L* [[A]]) - // CHECK-EH: invoke void @_ZN1LD1Ev(%struct.L* [[A]]) - // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]]) - if (b) { - const L &l = 2; - useL(l); - } -} - -struct T { - T(); - T(int); - char t[33]; -}; - -// Check the lifetime-extended case, with a trivial destructor, -// in a sub-scope -// CHECK-LABEL: define void @_Z37extendedLifetimeWithTrivialDestructorb -// CHECK-EH-LABEL: define void @_Z37extendedLifetimeWithTrivialDestructorb -void extendedLifetimeWithTrivialDestructor(bool b) { - extern void useT(const T &); - - // CHECK: [[A:%.*]] = alloca %struct.T - // CHECK: br i1 %b - // CHECK: [[P:%.*]] = getelementptr inbounds %struct.T* [[A]], i32 0, i32 0, i32 0 - // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[P]]) - // CHECK: call void @_ZN1TC1Ei(%struct.T* [[A]], i32 2) - // CHECK: call void @_Z4useTRK1T(%struct.T* dereferenceable(33) [[A]]) - // CHECK: call void @llvm.lifetime.end(i64 33, i8* [[P]]) - // CHECK: br label - // - // CHECK-EH: [[A:%.*]] = alloca %struct.T - // CHECK-EH: br i1 %b - // CHECK-EH: [[P:%.*]] = getelementptr inbounds %struct.T* [[A]], i32 0, i32 0, i32 0 - // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[P]]) - // CHECK-EH: call void @_ZN1TC1Ei(%struct.T* [[A]], i32 2) - // CHECK-EH: invoke void @_Z4useTRK1T(%struct.T* dereferenceable(33) [[A]]) - // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]]) - // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]]) - // CHECK-EH-NEXT: resume - if (b) { - const T &t = 2; - useT(t); - } -} - -// Check the lifetime-extended case, with a trivial destructor and a top level -// scope -// CHECK-LABEL: define void @_Z37extendedLifetimeWithTrivialDestructorv -// CHECK-EH-LABEL: define void @_Z37extendedLifetimeWithTrivialDestructorv -void extendedLifetimeWithTrivialDestructor() { - extern void useT(const T &); - - // CHECK: [[A:%.*]] = alloca %struct.T - // CHECK: [[P:%.*]] = getelementptr inbounds %struct.T* [[A]], i32 0, i32 0, i32 0 - // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[P]]) - // CHECK: call void @_ZN1TC1Ei(%struct.T* [[A]], i32 3) - // CHECK: call void @_Z4useTRK1T(%struct.T* dereferenceable(33) [[A]]) - // CHECK: call void @llvm.lifetime.end(i64 33, i8* [[P]]) - // CHECK-NEXT: ret - // - // CHECK-EH: [[A:%.*]] = alloca %struct.T - // CHECK-EH: [[P:%.*]] = getelementptr inbounds %struct.T* [[A]], i32 0, i32 0, i32 0 - // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[P]]) - // CHECK-EH: call void @_ZN1TC1Ei(%struct.T* [[A]], i32 3) - // CHECK-EH: invoke void @_Z4useTRK1T(%struct.T* dereferenceable(33) [[A]]) - // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]]) - // CHECK-EH-NEXT: ret - // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]]) - // CHECK-EH-NEXT: resume - const T &t = 3; - useT(t); -} -- 2.40.0