]> granicus.if.org Git - llvm/commitdiff
[CodeExtractor] Do not lift lifetime.end markers for region inputs
authorVedant Kumar <vsk@apple.com>
Fri, 15 Feb 2019 18:46:58 +0000 (18:46 +0000)
committerVedant Kumar <vsk@apple.com>
Fri, 15 Feb 2019 18:46:58 +0000 (18:46 +0000)
If a lifetime.end marker occurs along one path through the extraction
region, but not another, then it's still incorrect to lift the marker,
because there is some path through the extracted function which would
ordinarily not reach the marker. If the call to the extracted function
is in a loop, unrolling can cause inputs to the function to become
optimized out as undef after the first iteration.

To prevent incorrect stack slot merging in the calling function, it
should be sufficient to lift lifetime.start markers for region inputs.
I've tested this theory out by doing a stage2 check-all with randomized
splitting enabled.

This is a follow-up to r353973, and there's additional context for this
change in https://reviews.llvm.org/D57834.

rdar://47896986

Differential Revision: https://reviews.llvm.org/D58253

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@354159 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/Utils/CodeExtractor.cpp
test/Transforms/CodeExtractor/PartialInlineAlloca4.ll
test/Transforms/HotColdSplit/lifetime-markers-on-inputs-1.ll
test/Transforms/HotColdSplit/lifetime-markers-on-inputs-2.ll

index 2e073e89dde99b084663068380bde388ebffc4b7..023ab76d0012d2c0d509b3fdbdee433b09d9706a 100644 (file)
@@ -886,16 +886,14 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
 }
 
 /// 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<BasicBlock *> &Blocks,
                                          const SetVector<Value *> &SunkAllocas,
-                                         SetVector<Value *> &LifetimesStart,
-                                         SetVector<Value *> &LifetimesEnd) {
+                                         SetVector<Value *> &LifetimesStart) {
   for (BasicBlock *BB : Blocks) {
     for (auto It = BB->begin(), End = BB->end(); It != End;) {
       auto *II = dyn_cast<IntrinsicInst>(&*It);
@@ -912,8 +910,6 @@ static void eraseLifetimeMarkersOnInputs(const SetVector<BasicBlock *> &Blocks,
 
       if (II->getIntrinsicID() == Intrinsic::lifetime_start)
         LifetimesStart.insert(Mem);
-      else
-        LifetimesEnd.insert(Mem);
       II->eraseFromParent();
     }
   }
@@ -1421,12 +1417,11 @@ Function *CodeExtractor::extractCodeRegion() {
   }
 
   // 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 @@ Function *CodeExtractor::extractCodeRegion() {
 
   // 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 04789eaad29eba9a04226241414b09554b6e8894..5112135b166a0275b0b50c62b40d538ac2d90011 100644 (file)
@@ -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 e80e2b970772a32dc228b1ca4d29fa26da2f1bff..6d9214482c8cee2af89179e0042e034f04bed122 100644 (file)
@@ -34,8 +34,6 @@ normalPath:
 ; 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 d9a30f78f76552e502e4b91f2bddbde3f18e0e4a..e0df965632abfcecea11a3db87f61a671c74cfd1 100644 (file)
@@ -7,6 +7,8 @@ declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
 
 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 @@ exit:
 }
 
 ; 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 @@ exit:
 ;         (lt.start)
 ;        /          \
 ;   no-extract1  codeRepl
-;    (lt.end)    (lt.end)
+;    (lt.end)
 ;        \         /
 ;            exit
 define void @only_lifetime_end_is_cold() {
@@ -105,9 +106,7 @@ define void @only_lifetime_end_is_cold() {
 ; 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 @@ extract1:
 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
+}