Index: lib/CodeGen/CGDecl.cpp =================================================================== --- lib/CodeGen/CGDecl.cpp +++ lib/CodeGen/CGDecl.cpp @@ -889,7 +889,7 @@ /// 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::CallInst *CodeGenFunction::EmitLifetimeStart(uint64_t Size, llvm::Value *Addr) { if (!ShouldEmitLifetimeMarkers) return nullptr; @@ -899,7 +899,7 @@ llvm::CallInst *C = Builder.CreateCall(CGM.getLLVMLifetimeStartFn(), {SizeV, Addr}); C->setDoesNotThrow(); - return SizeV; + return C; } void CodeGenFunction::EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr) { @@ -1024,7 +1024,7 @@ // them incorrectly placed. if (!Bypasses.IsBypassed(&D)) { uint64_t size = CGM.getDataLayout().getTypeAllocSize(allocaTy); - emission.SizeForLifetimeMarkers = + emission.LifetimeStart = EmitLifetimeStart(size, address.getPointer()); } } else { @@ -1374,7 +1374,8 @@ if (emission.useLifetimeMarkers()) EHStack.pushCleanup(NormalEHLifetimeMarker, emission.getAllocatedAddress(), - emission.getSizeForLifetimeMarkers()); + emission.getSizeForLifetimeMarkers(), + emission.getLifetimeStartMarker()); // Check the type for a cleanup. if (QualType::DestructionKind dtorKind = D.getType().isDestructedType()) Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -427,9 +427,10 @@ switch (M->getStorageDuration()) { case SD_Automatic: case SD_FullExpression: - if (auto *Size = EmitLifetimeStart( + if (auto *LifetimeStart = EmitLifetimeStart( CGM.getDataLayout().getTypeAllocSize(Object.getElementType()), Object.getPointer())) { + auto *Size = LifetimeStart->getOperand(0); if (M->getStorageDuration() == SD_Automatic) pushCleanupAfterFullExpr(NormalEHLifetimeMarker, Object, Size); Index: lib/CodeGen/CGStmt.cpp =================================================================== --- lib/CodeGen/CGStmt.cpp +++ lib/CodeGen/CGStmt.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenFunction.h" +#include "CGCleanup.h" #include "CGDebugInfo.h" #include "CodeGenModule.h" #include "TargetInfo.h" @@ -551,6 +552,35 @@ } } +/// Move LifetimeStart to the beginning of lexical scope LS. +static void moveLifetimeStart(llvm::CallInst *&LifetimeStart, + CodeGenFunction::LexicalScope *LS, + CodeGenFunction *CGF) { + llvm::BasicBlock *EntryBlock = &CGF->CurFn->getEntryBlock(); + llvm::BasicBlock *BB = LS ? LS->getBasicBlock() : EntryBlock; + auto I = BB->begin(); + + // If BB is the entry block, move the lifetime marker to after the alloca + // insertion point. + if (BB == EntryBlock) + I = CGF->AllocaInsertPt->getIterator(); + + // Move the lifetime marker. + LifetimeStart->removeFromParent(); + BB->getInstList().insertAfter(I, LifetimeStart); + + // Move the bitcast instruction too. + auto *Ptr = cast(LifetimeStart->getOperand(1)); + if (isa(Ptr)) { + assert(isa(cast(Ptr)->getOperand(0)) && + "this should be a bitcast of an alloca"); + Ptr->removeFromParent(); + BB->getInstList().insertAfter(I, Ptr); + } + + LifetimeStart = nullptr; +} + void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) { // If this code is reachable then emit a stop point (if generating // debug info). We have to do this ourselves because we are on the @@ -558,7 +588,44 @@ if (HaveInsertPoint()) EmitStopPoint(&S); - EmitBranchThroughCleanup(getJumpDestForLabel(S.getLabel())); + auto Dest = getJumpDestForLabel(S.getLabel()); + auto JumpDestIdx = Dest.getScopeDepth(); + + // If we are compiling for C and the goto's destination label has been seen, + // move the lifetime.start markers. + if (!getLangOpts().CPlusPlus && JumpDestIdx.isValid()) { + LexicalScope *LS = CurLexicalScope; + auto SI = EHStack.getInnermostNormalCleanup(); + + // Search for the lexical scope enclosing the destination label. Note that + // LS will be null if the function body is the enclosing lexical scope. + while (LS) { + if (LS->hasLabel(S.getLabel())) + break; + SI = LS->getCleanupStackDepth(); + LS = LS->getParentScope(); + } + + // Move all the lifetime.start markers of the scopes in range + // [SI, JumpDestIdx) to the beginning of the enclosing lexical scope. + while (SI != JumpDestIdx) { + auto *Scope = &cast(*EHStack.find(SI)); + SI = Scope->getEnclosingNormalCleanup(); + + if (!Scope->isLifetimeMarker()) + continue; + + auto *C = static_cast(Scope->getCleanup()); + llvm::CallInst *&LifetimeStart = C->getLifetimeStart(); + + if (!LifetimeStart) + continue; + + moveLifetimeStart(LifetimeStart, LS, this); + } + } + + EmitBranchThroughCleanup(Dest); } Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -322,14 +322,20 @@ class CallLifetimeEnd final : public EHScopeStack::Cleanup { llvm::Value *Addr; llvm::Value *Size; + llvm::CallInst *LifetimeStart; public: - CallLifetimeEnd(Address addr, llvm::Value *size) - : Addr(addr.getPointer()), Size(size) {} + CallLifetimeEnd(Address addr, llvm::Value *size, + llvm::CallInst *lifetimeStart = nullptr) + : Addr(addr.getPointer()), Size(size), LifetimeStart(lifetimeStart) {} void Emit(CodeGenFunction &CGF, Flags flags) override { CGF.EmitLifetimeEnd(Size, Addr); } + + llvm::CallInst *&getLifetimeStart() { + return LifetimeStart; + } }; /// Header for data within LifetimeExtendedCleanupStack. @@ -497,10 +503,10 @@ /// \brief Enters a new scope for capturing cleanups, all of which /// will be executed once the scope is exited. class RunCleanupsScope { - EHScopeStack::stable_iterator CleanupStackDepth; size_t LifetimeExtendedCleanupStackSize; bool OldDidCallStackSave; protected: + EHScopeStack::stable_iterator CleanupStackDepth; bool PerformCleanup; private: @@ -552,6 +558,7 @@ SourceRange Range; SmallVector Labels; LexicalScope *ParentScope; + llvm::BasicBlock *BB; LexicalScope(const LexicalScope &) = delete; void operator=(const LexicalScope &) = delete; @@ -563,6 +570,8 @@ CGF.CurLexicalScope = this; if (CGDebugInfo *DI = CGF.getDebugInfo()) DI->EmitLexicalBlockStart(CGF.Builder, Range.getBegin()); + CGF.EnsureInsertPoint(); + BB = CGF.Builder.GetInsertBlock(); } void addLabel(const LabelDecl *label) { @@ -570,6 +579,18 @@ Labels.push_back(label); } + EHScopeStack::stable_iterator getCleanupStackDepth() const { + return CleanupStackDepth; + } + + llvm::BasicBlock *getBasicBlock() const { + return BB; + } + + LexicalScope *getParentScope() const { + return ParentScope; + } + /// \brief Exit this cleanup scope, emitting any accumulated /// cleanups. ~LexicalScope() { @@ -594,6 +615,10 @@ rescopeLabels(); } + bool hasLabel(const LabelDecl *LD) const { + return llvm::is_contained(Labels, LD); + } + void rescopeLabels(); }; @@ -2124,7 +2149,7 @@ void EmitCXXTemporary(const CXXTemporary *Temporary, QualType TempType, Address Ptr); - llvm::Value *EmitLifetimeStart(uint64_t Size, llvm::Value *Addr); + llvm::CallInst *EmitLifetimeStart(uint64_t Size, llvm::Value *Addr); void EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr); llvm::Value *EmitCXXNewExpr(const CXXNewExpr *E); @@ -2253,15 +2278,14 @@ bool IsConstantAggregate; /// Non-null if we should use lifetime annotations. - llvm::Value *SizeForLifetimeMarkers; + llvm::CallInst *LifetimeStart; struct Invalid {}; AutoVarEmission(Invalid) : Variable(nullptr), Addr(Address::invalid()) {} AutoVarEmission(const VarDecl &variable) : Variable(&variable), Addr(Address::invalid()), NRVOFlag(nullptr), - IsByRef(false), IsConstantAggregate(false), - SizeForLifetimeMarkers(nullptr) {} + IsByRef(false), IsConstantAggregate(false), LifetimeStart(nullptr) {} bool wasEmittedAsGlobal() const { return !Addr.isValid(); } @@ -2269,11 +2293,15 @@ static AutoVarEmission invalid() { return AutoVarEmission(Invalid()); } bool useLifetimeMarkers() const { - return SizeForLifetimeMarkers != nullptr; + return LifetimeStart != nullptr; } llvm::Value *getSizeForLifetimeMarkers() const { + return LifetimeStart->getOperand(0); + } + + llvm::CallInst *getLifetimeStartMarker() const { assert(useLifetimeMarkers()); - return SizeForLifetimeMarkers; + return LifetimeStart; } /// Returns the raw, allocated address, which is not necessarily Index: test/CodeGen/lifetime2.c =================================================================== --- test/CodeGen/lifetime2.c +++ test/CodeGen/lifetime2.c @@ -19,11 +19,11 @@ // CHECK-LABEL: @no_goto_bypass void no_goto_bypass() { + // O2: @llvm.lifetime.start(i64 5 // O2: @llvm.lifetime.start(i64 1 char x; l1: bar(&x, 1); - // O2: @llvm.lifetime.start(i64 5 // O2: @llvm.lifetime.end(i64 5 char y[5]; bar(y, 5); @@ -89,3 +89,27 @@ L: bar(&x, 1); } + +// O2: %[[ALLOCA:[a-z0-9]+]] = alloca i32, align 4 +// O2: %[[BITCAST:[0-9]+]] = bitcast i32* %[[ALLOCA]] to i8* +// O2: call void @llvm.lifetime.start(i64 4, i8* nonnull %[[BITCAST]]) +// O2: [[DESTLABEL:[a-z0-9]+]]: +// O2: br {{.*}} label %[[DESTLABEL]] + +extern void foo2(int p); + +int move_lifetime_start(int a) { + int *p = 0; + label1: + if (p) { + foo2(*p); + return 0; + } + + int i = 999; + if (a != 2) { + p = &i; + goto label1; + } + return -1; +}