[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