[PATCH] Add a case to LiveIntervalAnalysis::HandleMoveUp

Vincent Lejeune vljn at ovi.com
Sat Feb 23 09:46:50 PST 2013








>________________________________
> De : Jakob Stoklund Olesen <stoklund at 2pi.dk>
>À : Vincent Lejeune <vljn at ovi.com> 
>Cc : "llvm-commits at cs.uiuc.edu" <llvm-commits at cs.uiuc.edu> 
>Envoyé le : Dimanche 10 février 2013 17h32
>Objet : Re: [PATCH] Add a case to LiveIntervalAnalysis::HandleMoveUp
> 
>
>
>
>On Feb 9, 2013, at 4:14 PM, Vincent Lejeune <vljn at ovi.com> wrote:
>
>I'd like to reorder subregisters as part of pre RA scheduling machine instruction, in order to maximise bundling opportunities later.
>>In R600 there are 128 bits registers, Tn_XYZW, and 4 more times 32 bits registers, Tn_X, Tn_Y, TnZ and Tn_W,  with n between 0 and 127 in both case.
>>The Tn_X, Tn_Y, Tn_Z and Tn_W register are also subregister of the Tn_XYZW register. They map to what the R600 doc calls "channel", that is T1_X is 
>>channel Y of register 1.
>>
>
>That's fine, but when a VNInfo is live out of a basic block, it can have a very complicated live ranges with multiple discontiguous segments. Your patch didn't account for that.
>
>
>This is why I suggested that you work through an example with a live-out value number.
>
>
>/jakob
>
>
>
>

Sorry for the delay, I reworked our scheduler to make it able to do bottom up scheduling as well as top down scheduling.
An updated patch is below.
I don't completly understand what the various getter of SlotIndexes represent, so I'm not that confident in my code. It works
on piglit test suites, which cover a lot of cases (loop, break, if/then/else...), but for instance I don't understand why the NewIdx.getRegSlot()
instruction in the last hunk does not work for earlyClobber = false for instance ; in addition, the code handling live-in case in handleMoveDown
and handleMoveUp may sometimes change I->end value (and sometimes change it to an invalid value) and I'm not sure my workaround is 

solid.


For an example of what I want it to do when there is a live out:

if I have the following LI :
%vreg16 = 
[48r,64r:2)[64r,80r:3)[80r,96B:4)[96B,336r:0)[448B,640r:0)[640r,672r:1)[672r,688r:5)[688r,704r:6)[704r,816B:7)  0 at 96B-phi 1 at 640r 2 at 48r 3 at 64r 4 at 80r 5 at 672r 6 at 688r 7 at 704r
A sequence of move :80B -> 8B:
     %vreg16:    [48r,64r:2)[64r,80r:3)[80r,96B:4)[96B,336r:0)[448B,640r:0)[640r,672r:1)[672r,688r:5)[688r,704r:6)[704r,816B:7)  0 at 96B-phi 1 at 640r 2 at 48r 3 at 64r 4 at 80r 5 at 672r 6 at 688r 7 at 704r
        -->    [8r,48r:4)[48r,64r:2)[64r,96B:3)[96B,336r:0)[448B,640r:0)[640r,672r:1)[672r,688r:5)[688r,704r:6)[704r,816B:7)  0 at 96B-phi 1 at 640r 2 at 48r 3 at 64r 4 at 8r 5 at 672r 6 at 688r 7 at 704r
64B -> 12B:
     %vreg16:    [8r,48r:4)[48r,64r:2)[64r,96B:3)[96B,336r:0)[448B,640r:0)[640r,672r:1)[672r,688r:5)[688r,704r:6)[704r,816B:7)  0 at 96B-phi 1 at 640r 2 at 48r 3 at 64r 4 at 8r 5 at 672r 6 at 688r 7 at 704r
        -->    [8r,12r:4)[12r,48r:3)[48r,96B:2)[96B,336r:0)[448B,640r:0)[640r,672r:1)[672r,688r:5)[688r,704r:6)[704r,816B:7)  0 at 96B-phi 1 at 640r 2 at 48r 3 at 12r 4 at 8r 5 at 672r 6 at 688r 7 at 704r
48B -> 20B:
     %vreg16:    [8r,12r:4)[12r,48r:3)[48r,96B:2)[96B,336r:0)[448B,640r:0)[640r,672r:1)[672r,688r:5)[688r,704r:6)[704r,816B:7)  0 at 96B-phi 1 at 640r 2 at 48r 3 at 12r 4 at 8r 5 at 672r 6 at 688r 7 at 704r
        -->    [8r,12r:4)[12r,20r:3)[20r,96B:2)[96B,336r:0)[448B,640r:0)[640r,672r:1)[672r,688r:5)[688r,704r:6)[704r,816B:7)  0 at 96B-phi 1 at 640r 2 at 20r 3 at 12r 4 at 8r 5 at 672r 6 at 688r 7 at 704r



For instance, the following code :

********** INTERVALS **********
ZERO = EMPTY
%vreg10 = [176r,208r:0)  0 at 176r
%vreg15 = [464r,480r:0)[480r,496r:1)[496r,512r:2)[512r,656r:3)  0 at 464r 1 at 480r 2 at 496r 3 at 512r
%vreg16 = [48r,64r:2)[64r,80r:3)[80r,96B:4)[96B,336r:0)[448B,640r:0)[640r,672r:1)[672r,688r:5)[688r,704r:6)[704r,816B:7)  0 at 96B-phi 1 at 640r 2 at 48r 3 at 64r 4 at 80r 5 at 672r 6 at 688r 7 at 704r
%vreg17 = [656r,688r:0)  0 at 656r
%vreg18 = [272r,288r:0)  0 at 272r
%vreg23 = [288r,304r:0)[304r,320r:1)[320r,336r:2)[336r,416r:3)  0 at 288r 1 at 304r 2 at 320r 3 at 336r
%vreg24 = [32r,96B:0)[96B,256B:1)[448B,720r:1)[720r,816B:2)  0 at 32r 1 at 96B-phi 2 at 720r
RegMasks:
********** MACHINEINSTRS **********
# Machine code for function main: Post SSA

0B    BB#0: derived from LLVM BB %main_body
32B        %vreg24<def> = COPY %ZERO; R600_Reg32:%vreg24
48B        %vreg16:sub2<def,read-undef> = COPY %ZERO; R600_Reg128:%vreg16
64B        %vreg16:sub1<def> = COPY %ZERO; R600_Reg128:%vreg16
80B        %vreg16:sub0<def> = COPY %ZERO; R600_Reg128:%vreg16
        Successors according to CFG: BB#1

96B    BB#1: derived from LLVM BB %LOOP
        Predecessors according to CFG: BB#0 BB#3
176B        %vreg10<def> = SETGT_INT 0, 0, 1, 0, 0, 0, %ALU_CONST, 0, 0, 0, 2048, %vreg24, 0, 0, 0, -1, 1, pred:%PRED_SEL_OFF, 0; R600_Reg32:%vreg10,%vreg24
208B        %PREDICATE_BIT<def> = PRED_X %vreg10, 169, 16; R600_Reg32:%vreg10
224B        JUMP <BB#3>, pred:%PREDICATE_BIT
240B        JUMP <BB#2>, pred:%noreg
        Successors according to CFG: BB#2(4) BB#3(124)

256B    BB#2: derived from LLVM BB %IF
        Predecessors according to CFG: BB#1
272B        %vreg18<def> = MOV 1, 0, 0, 0, %ALU_LITERAL_X, 0, 0, 0, -1, 1, pred:%PRED_SEL_OFF, 1065353216; R600_Reg32:%vreg18
288B        %vreg23:sub3<def,read-undef> = MOV 1, 0, 0, 1, %vreg18, 0, 0, 0, -1, 1, pred:%PRED_SEL_OFF, 0; R600_Reg128:%vreg23 R600_Reg32:%vreg18
304B        %vreg23:sub1<def> = MOV 1, 0, 0, 1, %vreg16:sub1, 0, 0, 0, -1, 1, pred:%PRED_SEL_OFF, 0; R600_Reg128:%vreg23,%vreg16
320B        %vreg23:sub2<def> = MOV 1, 0, 0, 1, %vreg16:sub2, 0, 0, 0, -1, 1, pred:%PRED_SEL_OFF, 0; R600_Reg128:%vreg23,%vreg16
336B        %vreg23:sub0<def> = MOV 1, 0, 0, 1, %vreg16:sub0, 0, 0, 0, -1, 1, pred:%PRED_SEL_OFF, 0; R600_Reg128:%vreg23,%vreg16
416B        EG_ExportSwz %vreg23, 0, 0, 0, 1, 2, 3, 84, 1; R600_Reg128:%vreg23
432B        RETURN

448B    BB#3: derived from LLVM BB %ENDIF
        Predecessors according to CFG: BB#1
464B        %vreg15:sub1<def,read-undef> = ADD 0, 0, 1, 0, 0, 0, %vreg16:sub1, 0, 0, 0, -1, %ONE, 0, 0, 0, -1, 1, pred:%PRED_SEL_OFF, 0; R600_Reg128:%vreg15,%vreg16
480B        %vreg15:sub2<def> = ADD 0, 0, 1, 0, 0, 0, %vreg16:sub2, 0, 0, 0, -1, %ONE, 0, 0, 0, -1, 1, pred:%PRED_SEL_OFF, 0; R600_Reg128:%vreg15,%vreg16
496B        %vreg15:sub0<def> = ADD 0, 0, 1, 0, 0, 0, %vreg16:sub0, 0, 0, 0, -1, %ONE, 0, 0, 0, -1, 1, pred:%PRED_SEL_OFF, 0; R600_Reg128:%vreg15,%vreg16
512B        %vreg15:sub3<def> = MOV 1, 0, 0, 0, %ALU_LITERAL_X, 0, 0, 0, -1, 1, pred:%PRED_SEL_OFF, 0; R600_Reg128:%vreg15
640B        %vreg16:sub3<def> = COPY %vreg15:sub3; R600_Reg128:%vreg16,%vreg15
656B        %vreg17<def> = DOT4_eg_pseudo %vreg16, %vreg15; R600_Reg32:%vreg17 R600_Reg128:%vreg16,%vreg15
672B        %vreg16:sub2<def> = ADD 0, 0, 1, 0, 0, 0, %vreg16:sub2, 0, 0, 0, -1, %vreg17, 0, 0, 0, -1, 1, pred:%PRED_SEL_OFF, 0; R600_Reg128:%vreg16 R600_Reg32:%vreg17
688B        %vreg16:sub0<def> = ADD 0, 0, 1, 0, 0, 0, %vreg16:sub0, 0, 0, 0, -1, %vreg17, 0, 0, 0, -1, 1, pred:%PRED_SEL_OFF, 0; R600_Reg128:%vreg16 R600_Reg32:%vreg17
704B        %vreg16:sub1<def> = ADD 0, 0, 1, 0, 0, 0, %vreg16:sub1, 0, 0, 0, -1, %vreg16:sub1, 0, 0, 0, -1, 1, pred:%PRED_SEL_OFF, 0; R600_Reg128:%vreg16
720B        %vreg24<def> = ADD_INT 0, 0, 1, 0, 0, 0, %vreg24, 0, 0, 0, -1, %ONE_INT, 0, 0, 0, -1, 1, pred:%PRED_SEL_OFF, 0; R600_Reg32:%vreg24
800B        JUMP <BB#1>, pred:%noreg
        Successors according to CFG: BB#1

# End machine code for function main.

the first BB becomes :

0B    BB#0: derived from LLVM BB %main_body
8B        %vreg16:sub0<def> = COPY %ZERO; R600_Reg128:%vreg16
12B        %vreg16:sub1<def> = COPY %ZERO; R600_Reg128:%vreg16
20B        %vreg16:sub2<def> = COPY %ZERO; R600_Reg128:%vreg16
32B        %vreg24<def> = COPY %ZERO; R600_Reg32:%vreg24
        Successors according to CFG: BB#1



Vincent



>From 53278ee51b3eee6f3c85663708e59ad508e74675 Mon Sep 17 00:00:00 2001
From: Vincent Lejeune <vljn at ovi.com>
Date: Sat, 2 Feb 2013 19:05:50 +0100
Subject: [PATCH] Add a case to LiveIntervalAnalysis::HandleMove

Some target like R600 may want to swap LiveRange order for a same register.
Subregister writes are independant and can be reorder to improve scheduling.
This patch allows LiveIntervals to support moving intervals accross some others.
---
 lib/CodeGen/LiveIntervalAnalysis.cpp | 69 +++++++++++++++++++++++++++++++++---
 1 file changed, 65 insertions(+), 4 deletions(-)

diff --git a/lib/CodeGen/LiveIntervalAnalysis.cpp b/lib/CodeGen/LiveIntervalAnalysis.cpp
index 0978d73..6105184 100644
--- a/lib/CodeGen/LiveIntervalAnalysis.cpp
+++ b/lib/CodeGen/LiveIntervalAnalysis.cpp
@@ -787,6 +787,18 @@ private:
     LI.verify();
   }
 
+  /// Split the Range interval = [a, b) in two at SplitPos.
+  /// Range becomes [a, SplitPos) and its (overwritten) successor is
+  /// [SplitPos, b), the value of the later being DefVNI.
+  ///
+  void splitRange(LiveRange *Range, SlotIndex SplitPos, VNInfo *DefVNI) {
+    assert(Range->contains(SplitPos) && "SplitPos not inside Range");
+    SlotIndex RangeEnd = Range->end;
+    Range->end = SplitPos;
+    // Finally we insert a new range
+    *llvm::next(Range) = LiveRange(SplitPos, RangeEnd, DefVNI);
+  }
+
   /// Update LI to reflect an instruction has been moved downwards from OldIdx
   /// to NewIdx.
   ///
@@ -807,6 +819,11 @@ private:
   /// 5. Value read at OldIdx, killed before NewIdx:
   ///    Extend kill to NewIdx.
   ///
+  /// 6. Live def at OldIdx AND several other values between NewIdx and OldIdx
+  ///    Extend the range that precedes OldIdx one and split the range that
+  ///    contains NewIdx.
+  ///    (Happens when reordering independant partial write to a register)
+  ///
   void handleMoveDown(LiveInterval &LI) {
     // First look for a kill at OldIdx.
     LiveInterval::iterator I = LI.find(OldIdx.getBaseIndex());
@@ -821,6 +838,12 @@ private:
       // If the live-in value already extends to NewIdx, there is nothing to do.
       if (!SlotIndex::isEarlierInstr(I->end, NewIdx))
         return;
+      // If value is used at OldIdx and is moved to another interval, it's a
+      // consequence of subreg write reordering, do not go further
+      if (llvm::next(I) != E &&
+          !SlotIndex::isSameInstr(OldIdx, llvm::next(I)->start) &&
+          SlotIndex::isEarlierInstr(llvm::next(I)->start, NewIdx))
+        return;
       // Aggressively remove all kill flags from the old kill point.
       // Kill flags shouldn't be used while live intervals exist, they will be
       // reinserted by VirtRegRewriter.
@@ -853,11 +876,26 @@ private:
     // The remaining possibilities are now:
     // 2. Live def at OldIdx, killed at NewIdx: isSameInstr(I->end, NewIdx).
     // 3. Dead def at OldIdx: I->end = OldIdx.getDeadSlot().
+    // 6. Live def at OldIdx moving accross several others values
     // In either case, it is possible that there is an existing def at NewIdx.
-    assert((I->end == OldIdx.getDeadSlot() ||
-            SlotIndex::isSameInstr(I->end, NewIdx)) &&
-            "Cannot move def below kill");
     LiveInterval::iterator NewI = LI.advanceTo(I, NewIdx.getRegSlot());
+    if (!SlotIndex::isSameInstr(I->start, I->end) &&
+        SlotIndex::isEarlierInstr(I->end, NewIdx)) {
+      // OldIdx is not a dead def, and NewIdx is inside a new interval.
+      // Case 6 above.
+      if (I != LI.begin() &&
+          !SlotIndex::isEarlierInstr(llvm::prior(I)->end, I->start)) {
+        // There is no gap between I and its predecessor, merge them
+        // (We may fix the extension of the predecessor made in the live in
+        // case)
+        llvm::prior(I)->end = I->end;
+      }
+      std::copy(llvm::next(I), llvm::next(NewI), I);
+      splitRange(llvm::prior(NewI), DefVNI->def, DefVNI);
+      return;
+    }
+
+
     if (NewI != E && SlotIndex::isSameInstr(NewI->start, NewIdx)) {
       // There is an existing def at NewIdx, case 4 above. The def at OldIdx is
       // coalesced into that value.
@@ -894,6 +932,11 @@ private:
   ///    Hoist kill to NewIdx, then scan for last kill between NewIdx and
   ///    OldIdx.
   ///
+  /// 6. Live def at OldIdx AND several other values between NewIdx and OldIdx
+  ///    Extend the range that precedes OldIdx one and split the range that
+  ///    contains NewIdx.
+  ///    (Happens when reordering independant partial write to a register)
+  ///
   void handleMoveUp(LiveInterval &LI) {
     // First look for a kill at OldIdx.
     LiveInterval::iterator I = LI.find(OldIdx.getBaseIndex());
@@ -909,7 +952,9 @@ private:
         return;
       // Adjust I->end to end at NewIdx. If we are hoisting a kill above
       // another use, we need to search for that use. Case 5 above.
-      I->end = NewIdx.getRegSlot(I->end.isEarlyClobber());
+      SlotIndex NewEnd = NewIdx.getRegSlot(I->end.isEarlyClobber());;
+      if (llvm::next(I) == E || SlotIndex::isEarlierInstr(NewEnd, llvm::next(I)->start))
+        I->end = NewEnd;
       ++I;
       // If OldIdx also defines a value, there couldn't have been another use.
       if (I == E || !SlotIndex::isSameInstr(I->start, OldIdx)) {
@@ -942,6 +987,22 @@ private:
       return;
     }
 
+    if (!SlotIndex::isSameInstr(I->start, I->end) && I != LI.begin() &&
+        SlotIndex::isEarlierInstr(NewIdx, llvm::prior(I)->start)) {
+        // Case 6:
+        // OldIdx is not a dead def and NewIdx is before predecessor start
+        // First we extand range prior to I
+      LiveInterval::iterator NewI = LI.find(NewIdx.getRegSlot(true));
+      llvm::prior(I)->end = I->end;
+      std::copy_backward(NewI, I, llvm::next(I));
+      if (SlotIndex::isEarlierInstr(NewI->start, NewIdx)) {
+        splitRange(NewI, DefVNI->def, DefVNI);
+      } else {
+        *NewI = LiveRange(DefVNI->def, llvm::next(NewI)->start, DefVNI);
+      }
+      return;
+    }
+
     // There is no existing def at NewIdx. Hoist DefVNI.
     if (!I->end.isDead()) {
       // Leave the end point of a live def.
-- 
1.8.1.2




More information about the llvm-commits mailing list