summaryrefslogtreecommitdiff
path: root/lib/CodeGen/LiveIntervalUnion.cpp
blob: 51789998c6527c0ad4d468eed2b548cf94311943 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
//===-- LiveIntervalUnion.cpp - Live interval union data structure --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// LiveIntervalUnion represents a coalesced set of live intervals. This may be
// used during coalescing to represent a congruence class, or during register
// allocation to model liveness of a physical register.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "regalloc"
#include "LiveIntervalUnion.h"
#include "llvm/ADT/SparseBitVector.h"
#include "llvm/CodeGen/MachineLoopRanges.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetRegisterInfo.h"

using namespace llvm;


// Merge a LiveInterval's segments. Guarantee no overlaps.
void LiveIntervalUnion::unify(LiveInterval &VirtReg) {
  if (VirtReg.empty())
    return;
  ++Tag;

  // Insert each of the virtual register's live segments into the map.
  LiveInterval::iterator RegPos = VirtReg.begin();
  LiveInterval::iterator RegEnd = VirtReg.end();
  SegmentIter SegPos = Segments.find(RegPos->start);

  while (SegPos.valid()) {
    SegPos.insert(RegPos->start, RegPos->end, &VirtReg);
    if (++RegPos == RegEnd)
      return;
    SegPos.advanceTo(RegPos->start);
  }

  // We have reached the end of Segments, so it is no longer necessary to search
  // for the insertion position.
  // It is faster to insert the end first.
  --RegEnd;
  SegPos.insert(RegEnd->start, RegEnd->end, &VirtReg);
  for (; RegPos != RegEnd; ++RegPos, ++SegPos)
    SegPos.insert(RegPos->start, RegPos->end, &VirtReg);
}

// Remove a live virtual register's segments from this union.
void LiveIntervalUnion::extract(LiveInterval &VirtReg) {
  if (VirtReg.empty())
    return;
  ++Tag;

  // Remove each of the virtual register's live segments from the map.
  LiveInterval::iterator RegPos = VirtReg.begin();
  LiveInterval::iterator RegEnd = VirtReg.end();
  SegmentIter SegPos = Segments.find(RegPos->start);

  for (;;) {
    assert(SegPos.value() == &VirtReg && "Inconsistent LiveInterval");
    SegPos.erase();
    if (!SegPos.valid())
      return;

    // Skip all segments that may have been coalesced.
    RegPos = VirtReg.advanceTo(RegPos, SegPos.start());
    if (RegPos == RegEnd)
      return;

    SegPos.advanceTo(RegPos->start);
  }
}

void
LiveIntervalUnion::print(raw_ostream &OS, const TargetRegisterInfo *TRI) const {
  OS << "LIU " << PrintReg(RepReg, TRI);
  if (empty()) {
    OS << " empty\n";
    return;
  }
  for (LiveSegments::const_iterator SI = Segments.begin(); SI.valid(); ++SI) {
    OS << " [" << SI.start() << ' ' << SI.stop() << "):"
       << PrintReg(SI.value()->reg, TRI);
  }
  OS << '\n';
}

void LiveIntervalUnion::InterferenceResult::print(raw_ostream &OS,
                                          const TargetRegisterInfo *TRI) const {
  OS << '[' << start() << ';' << stop() << "):"
     << PrintReg(interference()->reg, TRI);
}

void LiveIntervalUnion::Query::print(raw_ostream &OS,
                                     const TargetRegisterInfo *TRI) {
  OS << "Interferences with ";
  LiveUnion->print(OS, TRI);
  InterferenceResult IR = firstInterference();
  while (isInterference(IR)) {
    OS << "  ";
    IR.print(OS, TRI);
    OS << '\n';
    nextInterference(IR);
  }
}

#ifndef NDEBUG
// Verify the live intervals in this union and add them to the visited set.
void LiveIntervalUnion::verify(LiveVirtRegBitSet& VisitedVRegs) {
  for (SegmentIter SI = Segments.begin(); SI.valid(); ++SI)
    VisitedVRegs.set(SI.value()->reg);
}
#endif //!NDEBUG

// Private interface accessed by Query.
//
// Find a pair of segments that intersect, one in the live virtual register
// (LiveInterval), and the other in this LiveIntervalUnion. The caller (Query)
// is responsible for advancing the LiveIntervalUnion segments to find a
// "notable" intersection, which requires query-specific logic.
//
// This design assumes only a fast mechanism for intersecting a single live
// virtual register segment with a set of LiveIntervalUnion segments.  This may
// be ok since most virtual registers have very few segments.  If we had a data
// structure that optimizd MxN intersection of segments, then we would bypass
// the loop that advances within the LiveInterval.
//
// If no intersection exists, set VirtRegI = VirtRegEnd, and set SI to the first
// segment whose start point is greater than LiveInterval's end point.
//
// Assumes that segments are sorted by start position in both
// LiveInterval and LiveSegments.
void LiveIntervalUnion::Query::findIntersection(InterferenceResult &IR) const {
  // Search until reaching the end of the LiveUnion segments.
  LiveInterval::iterator VirtRegEnd = VirtReg->end();
  if (IR.VirtRegI == VirtRegEnd)
    return;
  while (IR.LiveUnionI.valid()) {
    // Slowly advance the live virtual reg iterator until we surpass the next
    // segment in LiveUnion.
    //
    // Note: If this is ever used for coalescing of fixed registers and we have
    // a live vreg with thousands of segments, then change this code to use
    // upperBound instead.
    IR.VirtRegI = VirtReg->advanceTo(IR.VirtRegI, IR.LiveUnionI.start());
    if (IR.VirtRegI == VirtRegEnd)
      break; // Retain current (nonoverlapping) LiveUnionI

    // VirtRegI may have advanced far beyond LiveUnionI, catch up.
    IR.LiveUnionI.advanceTo(IR.VirtRegI->start);

    // Check if no LiveUnionI exists with VirtRegI->Start < LiveUnionI.end
    if (!IR.LiveUnionI.valid())
      break;
    if (IR.LiveUnionI.start() < IR.VirtRegI->end) {
      assert(overlap(*IR.VirtRegI, IR.LiveUnionI) &&
             "upperBound postcondition");
      break;
    }
  }
  if (!IR.LiveUnionI.valid())
    IR.VirtRegI = VirtRegEnd;
}

// Find the first intersection, and cache interference info
// (retain segment iterators into both VirtReg and LiveUnion).
const LiveIntervalUnion::InterferenceResult &
LiveIntervalUnion::Query::firstInterference() {
  if (CheckedFirstInterference)
    return FirstInterference;
  CheckedFirstInterference = true;
  InterferenceResult &IR = FirstInterference;

  // Quickly skip interference check for empty sets.
  if (VirtReg->empty() || LiveUnion->empty()) {
    IR.VirtRegI = VirtReg->end();
  } else if (VirtReg->beginIndex() < LiveUnion->startIndex()) {
    // VirtReg starts first, perform double binary search.
    IR.VirtRegI = VirtReg->find(LiveUnion->startIndex());
    if (IR.VirtRegI != VirtReg->end())
      IR.LiveUnionI = LiveUnion->find(IR.VirtRegI->start);
  } else {
    // LiveUnion starts first, perform double binary search.
    IR.LiveUnionI = LiveUnion->find(VirtReg->beginIndex());
    if (IR.LiveUnionI.valid())
      IR.VirtRegI = VirtReg->find(IR.LiveUnionI.start());
    else
      IR.VirtRegI = VirtReg->end();
  }
  findIntersection(FirstInterference);
  assert((IR.VirtRegI == VirtReg->end() || IR.LiveUnionI.valid())
         && "Uninitialized iterator");
  return FirstInterference;
}

// Treat the result as an iterator and advance to the next interfering pair
// of segments. This is a plain iterator with no filter.
bool LiveIntervalUnion::Query::nextInterference(InterferenceResult &IR) const {
  assert(isInterference(IR) && "iteration past end of interferences");

  // Advance either the VirtReg or LiveUnion segment to ensure that we visit all
  // unique overlapping pairs.
  if (IR.VirtRegI->end < IR.LiveUnionI.stop()) {
    if (++IR.VirtRegI == VirtReg->end())
      return false;
  }
  else {
    if (!(++IR.LiveUnionI).valid()) {
      IR.VirtRegI = VirtReg->end();
      return false;
    }
  }
  // Short-circuit findIntersection() if possible.
  if (overlap(*IR.VirtRegI, IR.LiveUnionI))
    return true;

  // Find the next intersection.
  findIntersection(IR);
  return isInterference(IR);
}

// Scan the vector of interfering virtual registers in this union. Assume it's
// quite small.
bool LiveIntervalUnion::Query::isSeenInterference(LiveInterval *VirtReg) const {
  SmallVectorImpl<LiveInterval*>::const_iterator I =
    std::find(InterferingVRegs.begin(), InterferingVRegs.end(), VirtReg);
  return I != InterferingVRegs.end();
}

// Count the number of virtual registers in this union that interfere with this
// query's live virtual register.
//
// The number of times that we either advance IR.VirtRegI or call
// LiveUnion.upperBound() will be no more than the number of holes in
// VirtReg. So each invocation of collectInterferingVRegs() takes
// time proportional to |VirtReg Holes| * time(LiveUnion.upperBound()).
//
// For comments on how to speed it up, see Query::findIntersection().
unsigned LiveIntervalUnion::Query::
collectInterferingVRegs(unsigned MaxInterferingRegs) {
  InterferenceResult IR = firstInterference();
  LiveInterval::iterator VirtRegEnd = VirtReg->end();
  LiveInterval *RecentInterferingVReg = NULL;
  if (IR.VirtRegI != VirtRegEnd) while (IR.LiveUnionI.valid()) {
    // Advance the union's iterator to reach an unseen interfering vreg.
    do {
      if (IR.LiveUnionI.value() == RecentInterferingVReg)
        continue;

      if (!isSeenInterference(IR.LiveUnionI.value()))
        break;

      // Cache the most recent interfering vreg to bypass isSeenInterference.
      RecentInterferingVReg = IR.LiveUnionI.value();

    } while ((++IR.LiveUnionI).valid());
    if (!IR.LiveUnionI.valid())
      break;

    // Advance the VirtReg iterator until surpassing the next segment in
    // LiveUnion.
    IR.VirtRegI = VirtReg->advanceTo(IR.VirtRegI, IR.LiveUnionI.start());
    if (IR.VirtRegI == VirtRegEnd)
      break;

    // Check for intersection with the union's segment.
    if (overlap(*IR.VirtRegI, IR.LiveUnionI)) {

      if (!IR.LiveUnionI.value()->isSpillable())
        SeenUnspillableVReg = true;

      if (InterferingVRegs.size() == MaxInterferingRegs)
        // Leave SeenAllInterferences set to false to indicate that at least one
        // interference exists beyond those we collected.
        return MaxInterferingRegs;

      InterferingVRegs.push_back(IR.LiveUnionI.value());

      // Cache the most recent interfering vreg to bypass isSeenInterference.
      RecentInterferingVReg = IR.LiveUnionI.value();
      ++IR.LiveUnionI;
      continue;
    }
    // VirtRegI may have advanced far beyond LiveUnionI,
    // do a fast intersection test to "catch up"
    IR.LiveUnionI.advanceTo(IR.VirtRegI->start);
  }
  SeenAllInterferences = true;
  return InterferingVRegs.size();
}

bool LiveIntervalUnion::Query::checkLoopInterference(MachineLoopRange *Loop) {
  // VirtReg is likely live throughout the loop, so start by checking LIU-Loop
  // overlaps.
  IntervalMapOverlaps<LiveIntervalUnion::Map, MachineLoopRange::Map>
    Overlaps(LiveUnion->getMap(), Loop->getMap());
  if (!Overlaps.valid())
    return false;

  // The loop is overlapping an LIU assignment. Check VirtReg as well.
  LiveInterval::iterator VRI = VirtReg->find(Overlaps.start());

  for (;;) {
    if (VRI == VirtReg->end())
      return false;
    if (VRI->start < Overlaps.stop())
      return true;

    Overlaps.advanceTo(VRI->start);
    if (!Overlaps.valid())
      return false;
    if (Overlaps.start() < VRI->end)
      return true;

    VRI = VirtReg->advanceTo(VRI, Overlaps.start());
  }
}