LiveInterval: Introduce createMainRangeFromSubranges().

This function constructs the main liverange by merging all subranges if
subregister liveness tracking is available. This should be slightly
faster to compute instead of performing the liveness calculation again
for the main range. More importantly it avoids cases where the main
liverange would cover positions where no subrange was live. These cases
happened for partial definitions where the actual defined part was dead
and only the undefined parts used later.

The register coalescing requires that every part covered by the main
live range has at least one subrange live.

I also expect this function to become usefull later for places where the
subranges are modified in a way that it is hard to correctly fix the
main liverange in the machine scheduler, we can simply reconstruct it
from subranges then.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@224806 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Matthias Braun 2014-12-24 02:11:51 +00:00
parent 02add3f1a6
commit 8882414a11
3 changed files with 234 additions and 7 deletions

View File

@ -552,6 +552,10 @@ namespace llvm {
void verify() const; void verify() const;
#endif #endif
protected:
/// Append a segment to the list of segments.
void append(const LiveRange::Segment S);
private: private:
iterator addSegmentFrom(Segment S, iterator From); iterator addSegmentFrom(Segment S, iterator From);
@ -685,6 +689,10 @@ namespace llvm {
/// are not considered valid and should only exist temporarily). /// are not considered valid and should only exist temporarily).
void removeEmptySubRanges(); void removeEmptySubRanges();
/// Construct main live range by merging the SubRanges of @p LI.
void constructMainRangeFromSubranges(const SlotIndexes &Indexes,
VNInfo::Allocator &VNIAllocator);
/// getSize - Returns the sum of sizes of all the LiveRange's. /// getSize - Returns the sum of sizes of all the LiveRange's.
/// ///
unsigned getSize() const; unsigned getSize() const;

View File

@ -300,6 +300,12 @@ LiveRange::extendSegmentStartTo(iterator I, SlotIndex NewStart) {
return MergeTo; return MergeTo;
} }
void LiveRange::append(const Segment S) {
// Check that the segment belongs to the back of the list.
assert(segments.empty() || segments.back().end <= S.start);
segments.push_back(S);
}
LiveRange::iterator LiveRange::addSegmentFrom(Segment S, iterator From) { LiveRange::iterator LiveRange::addSegmentFrom(Segment S, iterator From) {
SlotIndex Start = S.start, End = S.end; SlotIndex Start = S.start, End = S.end;
iterator it = std::upper_bound(From, end(), Start); iterator it = std::upper_bound(From, end(), Start);
@ -609,6 +615,214 @@ void LiveInterval::removeEmptySubRanges() {
} }
} }
/// Helper function for constructMainRangeFromSubranges(): Search the CFG
/// backwards until we find a place covered by a LiveRange segment that actually
/// has a valno set.
static VNInfo *searchForVNI(const SlotIndexes &Indexes, LiveRange &LR,
const MachineBasicBlock *MBB,
SmallPtrSetImpl<const MachineBasicBlock*> &Visited) {
// We start the search at the end of MBB.
SlotIndex EndIdx = Indexes.getMBBEndIdx(MBB);
// In our use case we can't live the area covered by the live segments without
// finding an actual VNI def.
LiveRange::iterator I = LR.find(EndIdx.getPrevSlot());
assert(I != LR.end());
LiveRange::Segment &S = *I;
if (S.valno != nullptr)
return S.valno;
VNInfo *VNI = nullptr;
// Continue at predecessors (we could even go to idom with domtree available).
for (const MachineBasicBlock *Pred : MBB->predecessors()) {
// Avoid going in circles.
if (Visited.count(Pred))
continue;
Visited.insert(Pred);
VNI = searchForVNI(Indexes, LR, Pred, Visited);
if (VNI != nullptr) {
S.valno = VNI;
break;
}
}
return VNI;
}
void LiveInterval::constructMainRangeFromSubranges(
const SlotIndexes &Indexes, VNInfo::Allocator &VNIAllocator) {
// The basic observations on which this algorithm is based:
// - Each Def/ValNo in a subrange must have a corresponding def on the main
// range, but not further defs/valnos are necessary.
// - If any of the subranges is live at a point the main liverange has to be
// live too, conversily if no subrange is live the main range mustn't be
// live either.
// We do this by scannig through all the subranges simultaneously creating new
// segments in the main range as segments start/ends come up in the subranges.
assert(hasSubRanges());
assert(segments.empty() && valnos.empty() && "expected empty main range");
// Collect subrange, iterator pairs for the walk and determine first and last
// SlotIndex involved.
SmallVector<std::pair<const SubRange*, const_iterator>, 4> SRs;
SlotIndex First;
SlotIndex Last;
for (const SubRange &SR : subranges()) {
if (SR.empty())
continue;
SRs.push_back(std::make_pair(&SR, SR.begin()));
if (!First.isValid() || SR.segments.front().start < First)
First = SR.segments.front().start;
if (!Last.isValid() || SR.segments.back().end > Last)
Last = SR.segments.back().end;
}
errs() << "Compute: " << *this << "\n";
// Walk over all subranges simultaneously.
Segment CurrentSegment;
bool ConstructingSegment = false;
bool NeedVNIFixup = false;
unsigned ActiveMask = 0;
SlotIndex Pos = First;
while (true) {
SlotIndex NextPos = Last;
enum {
NOTHING,
BEGIN_SEGMENT,
END_SEGMENT,
} Event = NOTHING;
unsigned EventMask = 0;
bool IsDef = false;
// Find the next begin or end of a subrange segment. Combine masks if we
// have multiple begins/ends at the same position. Ends take precedence over
// Begins.
for (auto &SRP : SRs) {
const SubRange &SR = *SRP.first;
const_iterator &I = SRP.second;
while (I != SR.end() &&
(I->end < Pos ||
(I->end == Pos && (ActiveMask & SR.LaneMask) == 0)))
++I;
if (I == SR.end())
continue;
if ((ActiveMask & SR.LaneMask) == 0 &&
Pos <= I->start && I->start <= NextPos) {
// Merge multiple begins at the same position
if (I->start == NextPos && Event == BEGIN_SEGMENT) {
EventMask |= SR.LaneMask;
IsDef |= I->valno->def == I->start;
} else if (I->start < NextPos || Event != END_SEGMENT) {
Event = BEGIN_SEGMENT;
NextPos = I->start;
EventMask = SR.LaneMask;
IsDef = I->valno->def == I->start;
}
}
if ((ActiveMask & SR.LaneMask) != 0 &&
Pos <= I->end && I->end <= NextPos) {
// Merge multiple ends at the same position.
if (I->end == NextPos && Event == END_SEGMENT)
EventMask |= SR.LaneMask;
else {
Event = END_SEGMENT;
NextPos = I->end;
EventMask = SR.LaneMask;
}
}
}
#if 1
errs() << '\t' << (Event == NOTHING ? "nothing "
: Event == BEGIN_SEGMENT ? "begin "
: "end ")
<< NextPos << " mask " << ActiveMask << " evmask " << EventMask << " def " << IsDef << "\n";
#endif
// Advance scan position.
Pos = NextPos;
if (Event == BEGIN_SEGMENT) {
if (ConstructingSegment && IsDef) {
// Finish previous segment because we have to start a new one.
CurrentSegment.end = Pos;
append(CurrentSegment);
ConstructingSegment = false;
}
// Start a new segment if necessary.
if (!ConstructingSegment) {
// Determine value number for the segment.
VNInfo *VNI;
if (IsDef) {
VNI = getNextValue(Pos, VNIAllocator);
} else {
// We have to reuse an existing value number, if we are lucky
// then we already passed one of the predecessor blocks and determined
// its value number (with blocks in reverse postorder this would be
// always true but we have no such guarantee).
assert(Pos.isBlock());
const MachineBasicBlock *MBB = Indexes.getMBBFromIndex(Pos);
// See if any of the predecessor blocks has a lower number and a VNI
for (const MachineBasicBlock *Pred : MBB->predecessors()) {
SlotIndex PredEnd = Indexes.getMBBEndIdx(Pred);
VNI = getVNInfoBefore(PredEnd);
if (VNI != nullptr)
break;
}
// Def will come later: We have to do an extra fixup pass.
if (VNI == nullptr)
NeedVNIFixup = true;
}
CurrentSegment.start = Pos;
CurrentSegment.valno = VNI;
ConstructingSegment = true;
}
ActiveMask |= EventMask;
} else if (Event == END_SEGMENT) {
assert(ConstructingSegment);
// Finish segment if no lane is active anymore.
ActiveMask &= ~EventMask;
if (ActiveMask == 0) {
CurrentSegment.end = Pos;
append(CurrentSegment);
ConstructingSegment = false;
}
} else {
// We reached the end of the last subranges and can stop.
assert(Event == NOTHING);
break;
}
}
// We might not be able to assign new valnos for all segments if the basic
// block containing the definition comes after a segment using the valno.
// Do a fixup pass for this uncommon case.
if (NeedVNIFixup) {
SmallPtrSet<const MachineBasicBlock*, 5> Visited;
for (Segment &S : segments) {
if (S.valno != nullptr)
continue;
// This can only happen at the begin of a basic block.
assert(S.start.isBlock());
Visited.clear();
const MachineBasicBlock *MBB = Indexes.getMBBFromIndex(S.start);
for (const MachineBasicBlock *Pred : MBB->predecessors()) {
VNInfo *VNI = searchForVNI(Indexes, *this, Pred, Visited);
if (VNI != nullptr) {
S.valno = VNI;
break;
}
}
assert(S.valno != nullptr);
}
}
assert(ActiveMask == 0 && !ConstructingSegment);
errs() << "Result: " << *this << "\n";
verify();
}
unsigned LiveInterval::getSize() const { unsigned LiveInterval::getSize() const {
unsigned Sum = 0; unsigned Sum = 0;
for (const Segment &S : segments) for (const Segment &S : segments)

View File

@ -105,8 +105,9 @@ void LiveRangeCalc::calculate(LiveInterval &LI) {
} }
} }
// Create the def in the main liverange. // Create the def in the main liverange. We do not have to do this if
if (MO.isDef()) // subranges are tracked as we recreate the main range later in this case.
if (MO.isDef() && !LI.hasSubRanges())
createDeadDef(*Indexes, *Alloc, LI, MO); createDeadDef(*Indexes, *Alloc, LI, MO);
} }
@ -116,14 +117,18 @@ void LiveRangeCalc::calculate(LiveInterval &LI) {
// Step 2: Extend live segments to all uses, constructing SSA form as // Step 2: Extend live segments to all uses, constructing SSA form as
// necessary. // necessary.
if (LI.hasSubRanges()) {
for (LiveInterval::SubRange &S : LI.subranges()) { for (LiveInterval::SubRange &S : LI.subranges()) {
resetLiveOutMap(); resetLiveOutMap();
extendToUses(S, Reg, S.LaneMask); extendToUses(S, Reg, S.LaneMask);
} }
LI.clear();
LI.constructMainRangeFromSubranges(*Indexes, *Alloc);
} else {
resetLiveOutMap(); resetLiveOutMap();
extendToUses(LI, Reg, ~0u); extendToUses(LI, Reg, ~0u);
} }
}
void LiveRangeCalc::createDeadDefs(LiveRange &LR, unsigned Reg) { void LiveRangeCalc::createDeadDefs(LiveRange &LR, unsigned Reg) {