Index: llvm/trunk/lib/Transforms/Utils/CodeExtractor.cpp =================================================================== --- llvm/trunk/lib/Transforms/Utils/CodeExtractor.cpp +++ llvm/trunk/lib/Transforms/Utils/CodeExtractor.cpp @@ -886,16 +886,14 @@ } /// Erase lifetime.start markers which reference inputs to the extraction -/// region, and insert the referenced memory into \p LifetimesStart. Do the same -/// with lifetime.end markers (but insert them into \p LifetimesEnd). +/// region, and insert the referenced memory into \p LifetimesStart. /// /// The extraction region is defined by a set of blocks (\p Blocks), and a set /// of allocas which will be moved from the caller function into the extracted /// function (\p SunkAllocas). static void eraseLifetimeMarkersOnInputs(const SetVector &Blocks, const SetVector &SunkAllocas, - SetVector &LifetimesStart, - SetVector &LifetimesEnd) { + SetVector &LifetimesStart) { for (BasicBlock *BB : Blocks) { for (auto It = BB->begin(), End = BB->end(); It != End;) { auto *II = dyn_cast(&*It); @@ -912,8 +910,6 @@ if (II->getIntrinsicID() == Intrinsic::lifetime_start) LifetimesStart.insert(Mem); - else - LifetimesEnd.insert(Mem); II->eraseFromParent(); } } @@ -1421,12 +1417,11 @@ } // Collect objects which are inputs to the extraction region and also - // referenced by lifetime start/end markers within it. The effects of these + // referenced by lifetime start markers within it. The effects of these // markers must be replicated in the calling function to prevent the stack // coloring pass from merging slots which store input objects. - ValueSet LifetimesStart, LifetimesEnd; - eraseLifetimeMarkersOnInputs(Blocks, SinkingCands, LifetimesStart, - LifetimesEnd); + ValueSet LifetimesStart; + eraseLifetimeMarkersOnInputs(Blocks, SinkingCands, LifetimesStart); // Construct new function based on inputs/outputs & add allocas for all defs. Function *newFunction = @@ -1449,9 +1444,8 @@ // Replicate the effects of any lifetime start/end markers which referenced // input objects in the extraction region by placing markers around the call. - insertLifetimeMarkersSurroundingCall(oldFunction->getParent(), - LifetimesStart.getArrayRef(), - LifetimesEnd.getArrayRef(), TheCall); + insertLifetimeMarkersSurroundingCall( + oldFunction->getParent(), LifetimesStart.getArrayRef(), {}, TheCall); // Propagate personality info to the new function if there is one. if (oldFunction->hasPersonalityFn()) Index: llvm/trunk/test/Transforms/CodeExtractor/PartialInlineAlloca4.ll =================================================================== --- llvm/trunk/test/Transforms/CodeExtractor/PartialInlineAlloca4.ll +++ llvm/trunk/test/Transforms/CodeExtractor/PartialInlineAlloca4.ll @@ -9,7 +9,6 @@ ; CHECK-LABEL: define{{.*}}@caller( ; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %tmp.i) ; CHECK-NEXT: call void @callee_unknown_use1.{{.*}}(i8* %tmp.i -; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %tmp.i) define i32 @callee_unknown_use1(i32 %arg) local_unnamed_addr #0 { ; CHECK-LABEL:define{{.*}}@callee_unknown_use1.{{[0-9]}} Index: llvm/trunk/test/Transforms/HotColdSplit/lifetime-markers-on-inputs-1.ll =================================================================== --- llvm/trunk/test/Transforms/HotColdSplit/lifetime-markers-on-inputs-1.ll +++ llvm/trunk/test/Transforms/HotColdSplit/lifetime-markers-on-inputs-1.ll @@ -34,8 +34,6 @@ ; CHECK-NEXT: [[local2_cast:%.*]] = bitcast i256* %local2 to i8* ; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 -1, i8* [[local2_cast]]) ; CHECK-NEXT: call i1 @foo.cold.1(i8* %local1_cast, i8* %local2_cast) -; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 -1, i8* [[local1_cast]]) -; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 -1, i8* [[local2_cast]]) ; CHECK-NEXT: br i1 outlinedPath: Index: llvm/trunk/test/Transforms/HotColdSplit/lifetime-markers-on-inputs-2.ll =================================================================== --- llvm/trunk/test/Transforms/HotColdSplit/lifetime-markers-on-inputs-2.ll +++ llvm/trunk/test/Transforms/HotColdSplit/lifetime-markers-on-inputs-2.ll @@ -7,6 +7,8 @@ declare void @cold_use(i8*) cold +declare void @use(i8*) + ; In this CFG, splitting will extract the blocks extract{1,2}. I.e., it will ; extract a lifetime.start marker, but not the corresponding lifetime.end ; marker. Make sure that a lifetime.start marker is emitted before the call to @@ -73,9 +75,8 @@ } ; In this CFG, splitting will extract the block extract1. I.e., it will extract -; a lifetime.end marker, but not the corresponding lifetime.start marker. Make -; sure that a lifetime.end marker is emitted after the call to the split -; function, and *only* that marker. +; a lifetime.end marker, but not the corresponding lifetime.start marker. Do +; not emit a lifetime.end marker after the call to the split function. ; ; entry ; (lt.start) @@ -91,7 +92,7 @@ ; (lt.start) ; / \ ; no-extract1 codeRepl -; (lt.end) (lt.end) +; (lt.end) ; \ / ; exit define void @only_lifetime_end_is_cold() { @@ -105,9 +106,7 @@ ; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[LOCAL1_CAST]]) ; CHECK-NEXT: br label [[EXIT:%.*]] ; CHECK: codeRepl: -; CHECK-NEXT: [[LT_CAST:%.*]] = bitcast i256* [[LOCAL1]] to i8* ; CHECK-NEXT: call void @only_lifetime_end_is_cold.cold.1(i8* [[LOCAL1_CAST]]) #3 -; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 -1, i8* [[LT_CAST]]) ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void @@ -133,3 +132,51 @@ exit: ret void } + +; In this CFG, splitting will extract the blocks extract{1,2,3}. Lifting the +; lifetime.end marker would be a miscompile. +define void @do_not_lift_lifetime_end() { +; CHECK-LABEL: @do_not_lift_lifetime_end( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[LOCAL1:%.*]] = alloca i256 +; CHECK-NEXT: [[LOCAL1_CAST:%.*]] = bitcast i256* [[LOCAL1]] to i8* +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[LOCAL1_CAST]]) +; CHECK-NEXT: br label [[HEADER:%.*]] +; CHECK: header: +; CHECK-NEXT: call void @use(i8* [[LOCAL1_CAST]]) +; CHECK-NEXT: br i1 undef, label [[EXIT:%.*]], label [[CODEREPL:%.*]] +; CHECK: codeRepl: +; CHECK-NEXT: [[TARGETBLOCK:%.*]] = call i1 @do_not_lift_lifetime_end.cold.1(i8* [[LOCAL1_CAST]]) #3 +; CHECK-NEXT: br i1 [[TARGETBLOCK]], label [[HEADER]], label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + ; lt.start + %local1 = alloca i256 + %local1_cast = bitcast i256* %local1 to i8* + call void @llvm.lifetime.start.p0i8(i64 1, i8* %local1_cast) + br label %header + +header: + ; If the lifetime.end marker is lifted, this use becomes dead the second time + ; the header block is executed. + call void @use(i8* %local1_cast) + br i1 undef, label %exit, label %extract1 + +extract1: + call void @cold_use(i8* %local1_cast) + br i1 undef, label %extract2, label %extract3 + +extract2: + ; Backedge. + br label %header + +extract3: + ; lt.end + call void @llvm.lifetime.end.p0i8(i64 1, i8* %local1_cast) + br label %exit + +exit: + ret void +}