Skip to content

Commit

Permalink
LiveIntervalAnalysis: Support moving of subregister defs in handleMove
Browse files Browse the repository at this point in the history
If two definitions write to independent subregisters then they can be
put in any order. LiveIntervalAnalysis::handleMove() did not support
this previously because it looks like moving a definition of a vreg past
another one.

This is a modified version of a patch proposed (two years ago) by
Vincent Lejeune! This version does not touch the read-undef flags and is
extended for the case of moving a subregister def behind all uses - this
can happen for subregister defs that are completely unused.

Differential Revision: http://reviews.llvm.org/D9067

llvm-svn: 260565
  • Loading branch information
MatzeB committed Feb 11, 2016
1 parent 669e87c commit 33c641b
Showing 1 changed file with 152 additions and 34 deletions.
186 changes: 152 additions & 34 deletions llvm/lib/CodeGen/LiveIntervalAnalysis.cpp
Expand Up @@ -1044,6 +1044,24 @@ class LiveIntervals::HMEditor {
for (MIBundleOperands MO(KillMI); MO.isValid(); ++MO)
if (MO->isReg() && MO->isUse())
MO->setIsKill(false);

// Is there a def before NewIdx which is not OldIdx?
LiveRange::iterator Next = std::next(OldIdxIn);
if (Next != E && !SlotIndex::isSameInstr(OldIdx, Next->start) &&
SlotIndex::isEarlierInstr(Next->start, NewIdx)) {
// If we are here then OldIdx was just a use but not a def. We only have
// to ensure liveness extends to NewIdx.
LiveRange::iterator NewIdxIn =
LR.advanceTo(Next, NewIdx.getBaseIndex());
// Extend the segment before NewIdx if necessary.
if (NewIdxIn == E ||
!SlotIndex::isEarlierInstr(NewIdxIn->start, NewIdx)) {
LiveRange::iterator Prev = std::prev(NewIdxIn);
Prev->end = NewIdx.getRegSlot();
}
return;
}

// Adjust OldIdxIn->end to reach NewIdx. This may temporarily make LR
// invalid by overlapping ranges.
bool isKill = SlotIndex::isSameInstr(OldIdx, OldIdxIn->end);
Expand All @@ -1053,7 +1071,7 @@ class LiveIntervals::HMEditor {
return;

// Did we have a Def at OldIdx?
OldIdxOut = std::next(OldIdxIn);
OldIdxOut = Next;
if (OldIdxOut == E || !SlotIndex::isSameInstr(OldIdx, OldIdxOut->start))
return;
} else {
Expand All @@ -1077,14 +1095,80 @@ class LiveIntervals::HMEditor {
}

// If we are here then we have a Definition at OldIdx which ends before
// NewIdx. Moving across unrelated defs is not allowed; That means we either
// had a dead-def at OldIdx or the OldIdxOut segment ends at NewIdx.
assert((OldIdxOut->end == OldIdx.getDeadSlot() ||
SlotIndex::isSameInstr(OldIdxOut->end, NewIdxDef)) &&
"Cannot move def below kill");
// NewIdx.

// Is there an existing Def at NewIdx?
LiveRange::iterator AfterNewIdx
= LR.advanceTo(OldIdxOut, NewIdx.getRegSlot());
bool OldIdxDefIsDead = OldIdxOut->end.isDead();
if (!OldIdxDefIsDead &&
SlotIndex::isEarlierInstr(OldIdxOut->end, NewIdxDef)) {
// OldIdx is not a dead def, and NewIdxDef is inside a new interval.
VNInfo *DefVNI;
if (OldIdxOut != LR.begin() &&
!SlotIndex::isEarlierInstr(std::prev(OldIdxOut)->end,
OldIdxOut->start)) {
// There is no gap between OldIdxOut and its predecessor anymore,
// merge them
LiveRange::iterator IPrev = std::prev(OldIdxOut);
DefVNI = OldIdxVNI;
IPrev->end = OldIdxOut->end;
} else {
// The value is live in to OldIdx
LiveRange::iterator INext = std::next(OldIdxOut);
assert(INext != E && "Must have following segment");
// We merge OldIdxOut and its successor. As we're dealing with subreg
// reordering, there is always a successor to OldIdxOut in the same BB
// We don't need INext->valno anymore and will reuse for the new segment
// we create later.
DefVNI = INext->valno;
INext->start = OldIdxOut->end;
INext->valno = OldIdxVNI;
INext->valno->def = INext->start;
}
// If NewIdx is behind the last segment, extend that and append a new one.
if (AfterNewIdx == E) {
// OldIdxOut is undef at this point, Slide (OldIdxOut;AfterNewIdx] up
// one position.
// |- ?/OldIdxOut -| |- X0 -| ... |- Xn -| end
// => |- X0/OldIdxOut -| ... |- Xn -| |- undef/NewS -| end
std::copy(std::next(OldIdxOut), E, OldIdxOut);
// The last segment is undefined now, reuse it for a dead def.
LiveRange::iterator NewSegment = std::prev(E);
*NewSegment = LiveRange::Segment(NewIdxDef, NewIdxDef.getDeadSlot(),
DefVNI);
DefVNI->def = NewIdxDef;

LiveRange::iterator Prev = std::prev(NewSegment);
Prev->end = NewIdxDef;
} else {
// OldIdxOut is undef at this point, Slide (OldIdxOut;AfterNewIdx] up
// one position.
// |- ?/OldIdxOut -| |- X0 -| ... |- Xn/AfterNewIdx -| |- Next -|
// => |- X0/OldIdxOut -| ... |- Xn -| |- Xn/AfterNewIdx -| |- Next -|
std::copy(std::next(OldIdxOut), std::next(AfterNewIdx), OldIdxOut);
LiveRange::iterator Prev = std::prev(AfterNewIdx);
// We have two cases:
if (SlotIndex::isEarlierInstr(Prev->start, NewIdxDef)) {
// Case 1: NewIdx is inside a liverange. Split this liverange at
// NewIdxDef into the segment "Prev" followed by "NewSegment".
LiveRange::iterator NewSegment = AfterNewIdx;
*NewSegment = LiveRange::Segment(NewIdxDef, Prev->end, Prev->valno);
Prev->valno->def = NewIdxDef;

*Prev = LiveRange::Segment(Prev->start, NewIdxDef, DefVNI);
DefVNI->def = Prev->start;
} else {
// Case 2: NewIdx is in a lifetime hole. Keep AfterNewIdx as is and
// turn Prev into a segment from NewIdx to AfterNewIdx->start.
*Prev = LiveRange::Segment(NewIdxDef, AfterNewIdx->start, DefVNI);
DefVNI->def = NewIdxDef;
assert(DefVNI != AfterNewIdx->valno);
}
}
return;
}

if (AfterNewIdx != E &&
SlotIndex::isSameInstr(AfterNewIdx->start, NewIdxDef)) {
// There is an existing def at NewIdx. The def at OldIdx is coalesced into
Expand Down Expand Up @@ -1130,24 +1214,18 @@ class LiveIntervals::HMEditor {
return;

// At this point we have to move OldIdxIn->end back to the nearest
// previous use but no further than NewIdx. Moreover OldIdx is a Def then
// we cannot have any intermediate uses or the move would be illegal.
// previous use or (dead-)def but no further than NewIdx.
SlotIndex DefBeforeOldIdx = std::max(OldIdxIn->start.getDeadSlot(),
NewIdx.getRegSlot());
OldIdxIn->end = findLastUseBefore(DefBeforeOldIdx, Reg, LaneMask);

// Did we have a Def at OldIdx? If not we are done now.
OldIdxOut = std::next(OldIdxIn);
// Did we have a Def at OldIdx?
if (OldIdxOut == E || !SlotIndex::isSameInstr(OldIdx, OldIdxOut->start)) {
// No def, search for the nearest previous use.
// This can never be an early clobber kill since there is no def.
OldIdxIn->end = findLastUseBefore(Reg, LaneMask).getRegSlot();
// We are done if there is no def at OldIdx.
if (OldIdxOut == E || !SlotIndex::isSameInstr(OldIdx, OldIdxOut->start))
return;
} else {
// There can't have been any intermediate uses or defs, so move
// OldIdxIn->end to NewIdx.
OldIdxIn->end = NewIdx.getRegSlot(OldIdxIn->end.isEarlyClobber());
}
} else {
OldIdxOut = OldIdxIn;
OldIdxIn = OldIdxOut != LR.begin() ? std::prev(OldIdxOut) : E;
}

// If we are here then there is a Definition at OldIdx. OldIdxOut points
Expand Down Expand Up @@ -1179,9 +1257,49 @@ class LiveIntervals::HMEditor {
// Previously nothing was live after NewIdx, so all we have to do now is
// move the begin of OldIdxOut to NewIdx.
if (!OldIdxDefIsDead) {
// Leave the end point of a live def.
OldIdxVNI->def = NewIdxDef;
OldIdxOut->start = NewIdxDef;
// Do we have any intermediate Defs between OldIdx and NewIdx?
if (OldIdxIn != E &&
SlotIndex::isEarlierInstr(NewIdxDef, OldIdxIn->start)) {
// OldIdx is not a dead def and NewIdx is before predecessor start
LiveRange::iterator NewIdxIn = NewIdxOut;
assert(NewIdxIn == LR.find(NewIdx.getBaseIndex()));
const SlotIndex SplitPos = NewIdxDef;

// Merge the OldIdxIn and OldIdxOut segments into OldIdxOut.
*OldIdxOut = LiveRange::Segment(OldIdxIn->start, OldIdxOut->end,
OldIdxIn->valno);
// OldIdxIn and OldIdxVNI are now undef and can be overridden.
// We Slide [NewIdxIn, OldIdxIn) down one position.
// |- X0/NewIdxIn -| ... |- Xn-1 -||- Xn/OldIdxIn -||- OldIdxOut -|
// => |- undef/NexIdxIn -| |- X0 -| ... |- Xn-1 -| |- Xn/OldIdxOut -|
std::copy_backward(NewIdxIn, OldIdxIn, OldIdxOut);
// NewIdxIn is now considered undef so we can reuse it for the moved
// value.
LiveRange::iterator NewSegment = NewIdxIn;
LiveRange::iterator Next = std::next(NewSegment);
NewSegment->valno = OldIdxVNI;
if (SlotIndex::isEarlierInstr(Next->start, NewIdx)) {
// There is no gap between NewSegment and its predecessor
*NewSegment = LiveRange::Segment(Next->start, SplitPos,
NewSegment->valno);
NewSegment->valno->def = Next->start;

*Next = LiveRange::Segment(SplitPos, Next->end, Next->valno);
Next->valno->def = SplitPos;
} else {
// There is a gap between NewSegment and its predecessor
// Value become live in
*NewSegment = LiveRange::Segment(SplitPos, Next->start,
NewSegment->valno);
NewSegment->valno->def = SplitPos;
}
} else {
// Leave the end point of a live def.
OldIdxOut->start = NewIdxDef;
OldIdxVNI->def = NewIdxDef;
if (OldIdxIn != E && SlotIndex::isEarlierInstr(NewIdx, OldIdxIn->end))
OldIdxIn->end = NewIdx.getRegSlot();
}
} else {
// OldIdxVNI is a dead def. It may have been moved across other values
// in LR, so move OldIdxOut up to NewIdxOut. Slide [NewIdxOut;OldIdxOut)
Expand Down Expand Up @@ -1215,10 +1333,10 @@ class LiveIntervals::HMEditor {
}

// Return the last use of reg between NewIdx and OldIdx.
SlotIndex findLastUseBefore(unsigned Reg, LaneBitmask LaneMask) {

SlotIndex findLastUseBefore(SlotIndex Before, unsigned Reg,
LaneBitmask LaneMask) {
if (TargetRegisterInfo::isVirtualRegister(Reg)) {
SlotIndex LastUse = NewIdx;
SlotIndex LastUse = Before;
for (MachineOperand &MO : MRI.use_nodbg_operands(Reg)) {
unsigned SubReg = MO.getSubReg();
if (SubReg != 0 && LaneMask != 0
Expand All @@ -1228,16 +1346,16 @@ class LiveIntervals::HMEditor {
const MachineInstr *MI = MO.getParent();
SlotIndex InstSlot = LIS.getSlotIndexes()->getInstructionIndex(MI);
if (InstSlot > LastUse && InstSlot < OldIdx)
LastUse = InstSlot;
LastUse = InstSlot.getRegSlot();
}
return LastUse;
}

// This is a regunit interval, so scanning the use list could be very
// expensive. Scan upwards from OldIdx instead.
assert(NewIdx < OldIdx && "Expected upwards move");
assert(Before < OldIdx && "Expected upwards move");
SlotIndexes *Indexes = LIS.getSlotIndexes();
MachineBasicBlock *MBB = Indexes->getMBBFromIndex(NewIdx);
MachineBasicBlock *MBB = Indexes->getMBBFromIndex(Before);

// OldIdx may not correspond to an instruction any longer, so set MII to
// point to the next instruction after OldIdx, or MBB->end().
Expand All @@ -1253,19 +1371,19 @@ class LiveIntervals::HMEditor {
continue;
SlotIndex Idx = Indexes->getInstructionIndex(MII);

// Stop searching when NewIdx is reached.
if (!SlotIndex::isEarlierInstr(NewIdx, Idx))
return NewIdx;
// Stop searching when Before is reached.
if (!SlotIndex::isEarlierInstr(Before, Idx))
return Before;

// Check if MII uses Reg.
for (MIBundleOperands MO(MII); MO.isValid(); ++MO)
if (MO->isReg() &&
TargetRegisterInfo::isPhysicalRegister(MO->getReg()) &&
TRI.hasRegUnit(MO->getReg(), Reg))
return Idx;
return Idx.getRegSlot();
}
// Didn't reach NewIdx. It must be the first instruction in the block.
return NewIdx;
// Didn't reach Before. It must be the first instruction in the block.
return Before;
}
};

Expand Down

0 comments on commit 33c641b

Please sign in to comment.