diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -1330,7 +1330,8 @@ /// \return a pointer to the temporary size Value if a marker was emitted, null /// otherwise llvm::Value *CodeGenFunction::EmitLifetimeStart(llvm::TypeSize Size, - llvm::Value *Addr) { + llvm::Value *Addr, + bool isBypassed) { if (!ShouldEmitLifetimeMarkers) return nullptr; @@ -1342,6 +1343,8 @@ Addr = Builder.CreateBitCast(Addr, AllocaInt8PtrTy); llvm::CallInst *C = Builder.CreateCall(CGM.getLLVMLifetimeStartFn(), {SizeV, Addr}); + if (isBypassed && CurLexicalScope) + CurLexicalScope->addLifetimeStartMarker(C); C->setDoesNotThrow(); return SizeV; } @@ -1551,24 +1554,10 @@ // Emit a lifetime intrinsic if meaningful. There's no point in doing this // if we don't have a valid insertion point (?). if (HaveInsertPoint() && !IsMSCatchParam) { - // If there's a jump into the lifetime of this variable, its lifetime - // gets broken up into several regions in IR, which requires more work - // to handle correctly. For now, just omit the intrinsics; this is a - // rare case, and it's better to just be conservatively correct. - // PR28267. - // - // We have to do this in all language modes if there's a jump past the - // declaration. We also have to do it in C if there's a jump to an - // earlier point in the current block because non-VLA lifetimes begin as - // soon as the containing block is entered, not when its variables - // actually come into scope; suppressing the lifetime annotations - // completely in this case is unnecessarily pessimistic, but again, this - // is rare. - if (!Bypasses.IsBypassed(&D) && - !(!getLangOpts().CPlusPlus && hasLabelBeenSeenInCurrentScope())) { + if (!(!getLangOpts().CPlusPlus && hasLabelBeenSeenInCurrentScope())) { llvm::TypeSize Size = CGM.getDataLayout().getTypeAllocSize(allocaTy); - emission.SizeForLifetimeMarkers = - EmitLifetimeStart(Size, AllocaAddr.getPointer()); + emission.SizeForLifetimeMarkers = EmitLifetimeStart( + Size, AllocaAddr.getPointer(), Bypasses.IsBypassed(&D)); } } else { assert(!emission.useLifetimeMarkers()); diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -647,6 +647,12 @@ EmitBlock(Dest.getBlock()); + if (CurLexicalScope) + llvm::for_each(CurLexicalScope->getLifetimeStartMarkers(), + [this](const llvm::CallInst *LifetimeStartMarker) { + Builder.Insert(LifetimeStartMarker->clone()); + }); + // Emit debug info for labels. if (CGDebugInfo *DI = getDebugInfo()) { if (CGM.getCodeGenOpts().hasReducedDebugInfo()) { diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -38,6 +38,7 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Frontend/OpenMP/OMPIRBuilder.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Support/Debug.h" #include "llvm/Transforms/Utils/SanitizerStats.h" @@ -931,6 +932,7 @@ class LexicalScope : public RunCleanupsScope { SourceRange Range; SmallVector Labels; + SmallVector LifetimeStartMarkers; LexicalScope *ParentScope; LexicalScope(const LexicalScope &) = delete; @@ -950,6 +952,19 @@ Labels.push_back(label); } + void addLifetimeStartMarker(const llvm::CallInst *LifetimeStartMarker) { + assert(isa(LifetimeStartMarker) && + cast(LifetimeStartMarker)->getIntrinsicID() == + llvm::Intrinsic::lifetime_start && + "LifetimeStartMarker Is not a lifetime start intrinsic"); + LifetimeStartMarkers.push_back(LifetimeStartMarker); + } + + const SmallVector & + getLifetimeStartMarkers() const { + return LifetimeStartMarkers; + } + /// Exit this cleanup scope, emitting any accumulated /// cleanups. ~LexicalScope() { @@ -2922,7 +2937,8 @@ void EmitSehTryScopeBegin(); void EmitSehTryScopeEnd(); - llvm::Value *EmitLifetimeStart(llvm::TypeSize Size, llvm::Value *Addr); + llvm::Value *EmitLifetimeStart(llvm::TypeSize Size, llvm::Value *Addr, + bool isBypassed = false); void EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr); llvm::Value *EmitCXXNewExpr(const CXXNewExpr *E); diff --git a/clang/test/CodeGen/lifetime2.c b/clang/test/CodeGen/lifetime2.c --- a/clang/test/CodeGen/lifetime2.c +++ b/clang/test/CodeGen/lifetime2.c @@ -35,11 +35,12 @@ // CHECK-LABEL: @goto_bypass void goto_bypass(void) { { - // O2-NOT: @llvm.lifetime.start.p0i8(i64 1 - // O2-NOT: @llvm.lifetime.end.p0i8(i64 1 + // O2: @llvm.lifetime.start.p0i8(i64 1 char x; l1: + // O2: @llvm.lifetime.start.p0i8(i64 1 bar(&x, 1); + // O2: @llvm.lifetime.end.p0i8(i64 1 } goto l1; } @@ -69,8 +70,8 @@ switch (n) { case 1: n = n; - // O2-NOT: @llvm.lifetime.start.p0i8(i64 1 - // O2-NOT: @llvm.lifetime.end.p0i8(i64 1 + // O2: @llvm.lifetime.start.p0i8(i64 1 + // O2: @llvm.lifetime.end.p0i8(i64 1 char x; bar(&x, 1); break; @@ -83,7 +84,7 @@ // CHECK-LABEL: @indirect_jump void indirect_jump(int n) { char x; - // O2-NOT: @llvm.lifetime + // O2: @llvm.lifetime void *T[] = {&&L}; goto *T[n]; L: