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) + BypassedLifetimeStartMarkers[CurLexicalScope].push_back(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 @@ -646,6 +646,7 @@ } EmitBlock(Dest.getBlock()); + restartBypassedVariable(); // Emit debug info for labels. if (CGDebugInfo *DI = getDebugInfo()) { 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" @@ -1926,6 +1927,14 @@ /// The current lexical scope. LexicalScope *CurLexicalScope = nullptr; + /// Map from lexical socpe to vector of bypassed lifetime start markers. + /// NOTE: If a lifetime start marker isn't defined in any lexical scope( + /// defining while CurLexicalScope is nullptr), its key is nullptr; + std::map> + BypassedLifetimeStartMarkers; + + void restartBypassedVariable(); + /// The current source location that should be used for exception /// handling code. SourceLocation CurEHLocation; @@ -2922,7 +2931,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/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -1233,6 +1233,8 @@ EmitBranch(SkipCountBB); } EmitBlock(BB); + restartBypassedVariable(); + uint64_t CurrentCount = getCurrentProfileCount(); incrementProfileCounter(S); setCurrentProfileCount(getCurrentProfileCount() + CurrentCount); @@ -1299,6 +1301,14 @@ return ResTy; } +void CodeGenFunction::restartBypassedVariable() { + if (BypassedLifetimeStartMarkers.count(CurLexicalScope)) + llvm::for_each(BypassedLifetimeStartMarkers[CurLexicalScope], + [this](const llvm::CallInst *LifetimeStartMarker) { + Builder.Insert(LifetimeStartMarker->clone()); + }); +} + void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, const CGFunctionInfo &FnInfo) { assert(Fn && "generating code for null Function"); @@ -1454,6 +1464,8 @@ // a quick pass now to see if we can. if (!CurFn->doesNotThrow()) TryMarkNoThrow(CurFn); + + BypassedLifetimeStartMarkers.clear(); } /// ContainsLabel - Return true if the statement contains a label in it. If 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,24 +70,26 @@ 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 char x; bar(&x, 1); break; case 2: + // O2: @llvm.lifetime.start.p0i8(i64 1 bar(&x, 1); break; + // O2: @llvm.lifetime.end.p0i8(i64 1 } } // CHECK-LABEL: @indirect_jump void indirect_jump(int n) { char x; - // O2-NOT: @llvm.lifetime + // O2: @llvm.lifetime.start void *T[] = {&&L}; goto *T[n]; L: + // O2: @llvm.lifetime.start bar(&x, 1); }