summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/lib/CodeGen/LiveInterval.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/CodeGen/LiveInterval.cpp')
-rw-r--r--contrib/llvm/lib/CodeGen/LiveInterval.cpp322
1 files changed, 298 insertions, 24 deletions
diff --git a/contrib/llvm/lib/CodeGen/LiveInterval.cpp b/contrib/llvm/lib/CodeGen/LiveInterval.cpp
index ce8ce96..9423edc 100644
--- a/contrib/llvm/lib/CodeGen/LiveInterval.cpp
+++ b/contrib/llvm/lib/CodeGen/LiveInterval.cpp
@@ -26,6 +26,7 @@
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include <algorithm>
@@ -185,6 +186,27 @@ bool LiveRange::overlaps(SlotIndex Start, SlotIndex End) const {
return I != begin() && (--I)->end > Start;
}
+bool LiveRange::covers(const LiveRange &Other) const {
+ if (empty())
+ return Other.empty();
+
+ const_iterator I = begin();
+ for (const Segment &O : Other.segments) {
+ I = advanceTo(I, O.start);
+ if (I == end() || I->start > O.start)
+ return false;
+
+ // Check adjacent live segments and see if we can get behind O.end.
+ while (I->end < O.end) {
+ const_iterator Last = I;
+ // Get next segment and abort if it was not adjacent.
+ ++I;
+ if (I == end() || Last->end != I->start)
+ return false;
+ }
+ }
+ return true;
+}
/// ValNo is dead, remove it. If it is the largest value number, just nuke it
/// (and any other deleted values neighboring it), otherwise mark it as ~1U so
@@ -204,9 +226,9 @@ void LiveRange::markValNoForDeletion(VNInfo *ValNo) {
void LiveRange::RenumberValues() {
SmallPtrSet<VNInfo*, 8> Seen;
valnos.clear();
- for (const_iterator I = begin(), E = end(); I != E; ++I) {
- VNInfo *VNI = I->valno;
- if (!Seen.insert(VNI))
+ for (const Segment &S : segments) {
+ VNInfo *VNI = S.valno;
+ if (!Seen.insert(VNI).second)
continue;
assert(!VNI->isUnused() && "Unused valno used by live segment");
VNI->id = (unsigned)valnos.size();
@@ -278,6 +300,12 @@ LiveRange::extendSegmentStartTo(iterator I, SlotIndex NewStart) {
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) {
SlotIndex Start = S.start, End = S.end;
iterator it = std::upper_bound(From, end(), Start);
@@ -461,8 +489,8 @@ void LiveRange::join(LiveRange &Other,
// This can leave Other in an invalid state because we're not coalescing
// touching segments that now have identical values. That's OK since Other is
// not supposed to be valid after calling join();
- for (iterator I = Other.begin(), E = Other.end(); I != E; ++I)
- I->valno = NewVNInfo[RHSValNoAssignments[I->valno->id]];
+ for (Segment &S : Other.segments)
+ S.valno = NewVNInfo[RHSValNoAssignments[S.valno->id]];
// Update val# info. Renumber them and make sure they all belong to this
// LiveRange now. Also remove dead val#'s.
@@ -482,8 +510,8 @@ void LiveRange::join(LiveRange &Other,
// Okay, now insert the RHS live segments into the LHS.
LiveRangeUpdater Updater(this);
- for (iterator I = Other.begin(), E = Other.end(); I != E; ++I)
- Updater.add(*I);
+ for (Segment &S : Other.segments)
+ Updater.add(S);
}
/// Merge all of the segments in RHS into this live range as the specified
@@ -493,8 +521,8 @@ void LiveRange::join(LiveRange &Other,
void LiveRange::MergeSegmentsInAsValue(const LiveRange &RHS,
VNInfo *LHSValNo) {
LiveRangeUpdater Updater(this);
- for (const_iterator I = RHS.begin(), E = RHS.end(); I != E; ++I)
- Updater.add(I->start, I->end, LHSValNo);
+ for (const Segment &S : RHS.segments)
+ Updater.add(S.start, S.end, LHSValNo);
}
/// MergeValueInAsValue - Merge all of the live segments of a specific val#
@@ -506,9 +534,9 @@ void LiveRange::MergeValueInAsValue(const LiveRange &RHS,
const VNInfo *RHSValNo,
VNInfo *LHSValNo) {
LiveRangeUpdater Updater(this);
- for (const_iterator I = RHS.begin(), E = RHS.end(); I != E; ++I)
- if (I->valno == RHSValNo)
- Updater.add(I->start, I->end, LHSValNo);
+ for (const Segment &S : RHS.segments)
+ if (S.valno == RHSValNo)
+ Updater.add(S.start, S.end, LHSValNo);
}
/// MergeValueNumberInto - This method is called when two value nubmers
@@ -570,10 +598,232 @@ VNInfo *LiveRange::MergeValueNumberInto(VNInfo *V1, VNInfo *V2) {
return V2;
}
+void LiveInterval::removeEmptySubRanges() {
+ SubRange **NextPtr = &SubRanges;
+ SubRange *I = *NextPtr;
+ while (I != nullptr) {
+ if (!I->empty()) {
+ NextPtr = &I->Next;
+ I = *NextPtr;
+ continue;
+ }
+ // Skip empty subranges until we find the first nonempty one.
+ do {
+ I = I->Next;
+ } while (I != nullptr && I->empty());
+ *NextPtr = I;
+ }
+}
+
+/// 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.insert(Pred).second)
+ continue;
+
+ VNI = searchForVNI(Indexes, LR, Pred, Visited);
+ if (VNI != nullptr) {
+ S.valno = VNI;
+ break;
+ }
+ }
+
+ return VNI;
+}
+
+static void determineMissingVNIs(const SlotIndexes &Indexes, LiveInterval &LI) {
+ SmallPtrSet<const MachineBasicBlock*, 5> Visited;
+ for (LiveRange::Segment &S : LI.segments) {
+ if (S.valno != nullptr)
+ continue;
+ // This can only happen at the begin of a basic block.
+ assert(S.start.isBlock() && "valno should only be missing at block begin");
+
+ Visited.clear();
+ const MachineBasicBlock *MBB = Indexes.getMBBFromIndex(S.start);
+ for (const MachineBasicBlock *Pred : MBB->predecessors()) {
+ VNInfo *VNI = searchForVNI(Indexes, LI, Pred, Visited);
+ if (VNI != nullptr) {
+ S.valno = VNI;
+ break;
+ }
+ }
+ assert(S.valno != nullptr && "could not determine valno");
+ }
+}
+
+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() && "expected subranges to be present");
+ 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;
+ }
+
+ // 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;
+ // Which subregister lanes are affected by the current event.
+ unsigned EventMask = 0;
+ // Whether a BEGIN_SEGMENT is also a valno definition point.
+ 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;
+ // Advance iterator of subrange to a segment involving Pos; the earlier
+ // segments are already merged at this point.
+ 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;
+ }
+ }
+ }
+
+ // 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)
+ determineMissingVNIs(Indexes, *this);
+
+ assert(ActiveMask == 0 && !ConstructingSegment && "all segments ended");
+ verify();
+}
+
unsigned LiveInterval::getSize() const {
unsigned Sum = 0;
- for (const_iterator I = begin(), E = end(); I != E; ++I)
- Sum += I->start.distance(I->end);
+ for (const Segment &S : segments)
+ Sum += S.start.distance(S.end);
return Sum;
}
@@ -591,9 +841,9 @@ void LiveRange::print(raw_ostream &OS) const {
if (empty())
OS << "EMPTY";
else {
- for (const_iterator I = begin(), E = end(); I != E; ++I) {
- OS << *I;
- assert(I->valno == getValNumInfo(I->valno->id) && "Bad VNInfo");
+ for (const Segment &S : segments) {
+ OS << S;
+ assert(S.valno == getValNumInfo(S.valno->id) && "Bad VNInfo");
}
}
@@ -620,6 +870,10 @@ void LiveRange::print(raw_ostream &OS) const {
void LiveInterval::print(raw_ostream &OS) const {
OS << PrintReg(reg) << ' ';
super::print(OS);
+ // Print subranges
+ for (const SubRange &SR : subranges()) {
+ OS << format(" L%04X ", SR.LaneMask) << SR;
+ }
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
@@ -648,6 +902,26 @@ void LiveRange::verify() const {
}
}
}
+
+void LiveInterval::verify(const MachineRegisterInfo *MRI) const {
+ super::verify();
+
+ // Make sure SubRanges are fine and LaneMasks are disjunct.
+ unsigned Mask = 0;
+ unsigned MaxMask = MRI != nullptr ? MRI->getMaxLaneMaskForVReg(reg) : ~0u;
+ for (const SubRange &SR : subranges()) {
+ // Subrange lanemask should be disjunct to any previous subrange masks.
+ assert((Mask & SR.LaneMask) == 0);
+ Mask |= SR.LaneMask;
+
+ // subrange mask should not contained in maximum lane mask for the vreg.
+ assert((Mask & ~MaxMask) == 0);
+
+ SR.verify();
+ // Main liverange should cover subrange.
+ assert(covers(SR));
+ }
+}
#endif
@@ -692,14 +966,14 @@ void LiveRangeUpdater::print(raw_ostream &OS) const {
OS << " updater with gap = " << (ReadI - WriteI)
<< ", last start = " << LastStart
<< ":\n Area 1:";
- for (LiveRange::const_iterator I = LR->begin(); I != WriteI; ++I)
- OS << ' ' << *I;
+ for (const auto &S : make_range(LR->begin(), WriteI))
+ OS << ' ' << S;
OS << "\n Spills:";
for (unsigned I = 0, E = Spills.size(); I != E; ++I)
OS << ' ' << Spills[I];
OS << "\n Area 2:";
- for (LiveRange::const_iterator I = ReadI, E = LR->end(); I != E; ++I)
- OS << ' ' << *I;
+ for (const auto &S : make_range(ReadI, LR->end()))
+ OS << ' ' << S;
OS << '\n';
}
@@ -860,9 +1134,7 @@ unsigned ConnectedVNInfoEqClasses::Classify(const LiveInterval *LI) {
const VNInfo *used = nullptr, *unused = nullptr;
// Determine connections.
- for (LiveInterval::const_vni_iterator I = LI->vni_begin(), E = LI->vni_end();
- I != E; ++I) {
- const VNInfo *VNI = *I;
+ for (const VNInfo *VNI : LI->valnos) {
// Group all unused values into one class.
if (VNI->isUnused()) {
if (unused)
@@ -938,6 +1210,8 @@ void ConnectedVNInfoEqClasses::Distribute(LiveInterval *LIV[],
} else
*J++ = *I;
}
+ // TODO: do not cheat anymore by simply cleaning all subranges
+ LI.clearSubRanges();
LI.segments.erase(J, E);
// Transfer VNInfos to their new owners and renumber them.
OpenPOWER on IntegriCloud