001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.compilers.opt.regalloc;
014
015import java.util.Iterator;
016import java.util.SortedSet;
017
018import org.jikesrvm.VM;
019import org.jikesrvm.compilers.opt.ir.BasicBlock;
020import org.jikesrvm.compilers.opt.ir.Instruction;
021import org.jikesrvm.compilers.opt.ir.Register;
022
023/**
024 * Implements a live interval with holes; i.e. an ordered set of basic live
025 * intervals. There is exactly one instance of this class for each
026 * Register.
027 * <p>
028 * The order that this set imposes is inconsistent with equals.
029 * <p>
030 * This class is designed for use by a single thread.
031 */
032class CompoundInterval extends IncreasingStartIntervalSet {
033  /** Support for Set serialization */
034  static final long serialVersionUID = 7423553044815762071L;
035  /**
036   * Is this compound interval fully contained in infrequent code?
037   */
038  private boolean _infrequent = true;
039
040  final void setFrequent() {
041    _infrequent = false;
042  }
043
044  final boolean isInfrequent() {
045    return _infrequent;
046  }
047
048  /**
049   * The register this compound interval represents or {@code null}
050   * if this interval is not associated with a register (i.e. if it
051   * represents a spill location).
052   */
053  private final Register reg;
054
055  /**
056   * A spill location assigned for this interval.
057   */
058  private SpillLocationInterval spillInterval;
059
060  SpillLocationInterval getSpillInterval() {
061    return spillInterval;
062  }
063
064  /**
065   * @return the register this interval represents
066   */
067  Register getRegister() {
068    return reg;
069  }
070
071  /**
072   * Creates a new compound interval of a single Basic interval.
073   *
074   * @param dfnBegin interval's begin
075   * @param dfnEnd interval's end
076   * @param register the register for the compound interval
077   */
078  CompoundInterval(int dfnBegin, int dfnEnd, Register register) {
079    BasicInterval newInterval = new MappedBasicInterval(dfnBegin, dfnEnd, this);
080    add(newInterval);
081    reg = register;
082  }
083
084  /**
085   * Creates a new compound interval of a single Basic interval.
086   *
087   * @param i interval providing start and end for the new interval
088   * @param register the register for the compound interval
089   */
090  CompoundInterval(BasicInterval i, Register register) {
091    BasicInterval newInterval = new MappedBasicInterval(i.getBegin(), i.getEnd(), this);
092    add(newInterval);
093    reg = register;
094  }
095
096  /**
097   * Dangerous constructor: use with care.
098   * <p>
099   * Creates a compound interval with a register but doesn't actually
100   * add any intervals to the compound interval.
101   *
102   * @param r a register
103   */
104  protected CompoundInterval(Register r) {
105    reg = r;
106  }
107
108  /**
109   * Copies the ranges from this interval into a new interval associated
110   * with a register.
111   *
112   * @param r the register for the new interval
113   * @return the new interval
114   */
115  CompoundInterval copy(Register r) {
116    CompoundInterval result = new CompoundInterval(r);
117
118    for (Iterator<BasicInterval> i = iterator(); i.hasNext();) {
119      BasicInterval b = i.next();
120      result.add(b);
121    }
122    return result;
123  }
124
125  /**
126   * Copies the basic intervals up to and including stop into a new interval.
127   * The new interval is associated with the given register.
128   *
129   * @param r the register for the new interval
130   * @param stop the interval to stop at
131   * @return the new interval
132   */
133  CompoundInterval copy(Register r, BasicInterval stop) {
134    CompoundInterval result = new CompoundInterval(r);
135
136    for (Iterator<BasicInterval> i = iterator(); i.hasNext();) {
137      BasicInterval b = i.next();
138      result.add(b);
139      if (b.sameRange(stop)) return result;
140    }
141    return result;
142  }
143
144  /**
145   * Add a new live range to this compound interval.
146   * @param regAllocState depth-first numbers for for instructions
147   * @param live the new live range
148   * @param bb the basic block for live
149   *
150   * @return the new basic interval if one was created; null otherwise
151   */
152  BasicInterval addRange(RegisterAllocatorState regAllocState, LiveIntervalElement live, BasicBlock bb) {
153    if (shouldConcatenate(regAllocState, live, bb)) {
154      // concatenate with the last basic interval
155      BasicInterval last = last();
156      last.setEnd(regAllocState.getDfnEnd(live, bb));
157      return null;
158    } else {
159      // create a new basic interval and append it to the list.
160      BasicInterval newInterval = new MappedBasicInterval(regAllocState.getDfnBegin(live, bb), regAllocState.getDfnEnd(live, bb), this);
161      add(newInterval);
162      return newInterval;
163    }
164  }
165
166  /**
167   * Should we simply merge the live interval <code>live</code> into a
168   *  previous BasicInterval?
169   * @param regAllocState depth-first numbers for for instructions
170   * @param live the live interval being queried
171   * @param bb the basic block in which live resides.
172   *
173   * @return {@code true} if the interval should be concatenated, {@code false}
174   *  if it should'nt
175   */
176  private boolean shouldConcatenate(RegisterAllocatorState regAllocState, LiveIntervalElement live, BasicBlock bb) {
177
178    BasicInterval last = last();
179
180    // Make sure the new live range starts after the last basic interval
181    if (VM.VerifyAssertions) {
182      VM._assert(last.getEnd() <= regAllocState.getDfnBegin(live, bb));
183    }
184
185    int dfnBegin = regAllocState.getDfnBegin(live, bb);
186    if (live.getBegin() != null) {
187      if (live.getBegin() == bb.firstRealInstruction()) {
188        // live starts the basic block.  Now make sure it is contiguous
189        // with the last interval.
190        return last.getEnd() + 1 >= dfnBegin;
191      } else {
192        // live does not start the basic block.  Merge with last iff
193        // last and live share an instruction.  This happens when a
194        // register is def'ed and use'd in the same instruction.
195        return last.getEnd() == dfnBegin;
196      }
197    } else {
198      // live.getBegin == null.
199      // Merge if it is contiguous with the last interval.
200      int dBegin = regAllocState.getDFN(bb.firstInstruction());
201      return last.getEnd() + 1 >= dBegin;
202    }
203  }
204
205  /**
206   * Assign this compound interval to a free spill location.
207   *
208   * @param spillManager governing spill location manager
209   * @param regAllocState current state of the register allocator
210   */
211  void spill(SpillLocationManager spillManager, RegisterAllocatorState regAllocState) {
212    spillInterval = spillManager.findOrCreateSpillLocation(this);
213    regAllocState.setSpill(reg, spillInterval.getOffset());
214    regAllocState.clearOneToOne(reg);
215    if (LinearScan.VERBOSE_DEBUG) {
216      System.out.println("Assigned " + reg + " to location " + spillInterval.getOffset());
217    }
218  }
219
220  boolean isSpilled(RegisterAllocatorState regAllocState) {
221    return (regAllocState.getSpill(getRegister()) != 0);
222  }
223
224  /**
225   * Assign this compound interval to a physical register.
226   *
227   * @param r the register to assign to
228   */
229  void assign(Register r) {
230    getRegister().allocateToRegister(r);
231  }
232
233  /**
234   * @param regAllocState current state of the register allocator
235   * @return {@code true} if this interval has been assigned to
236   *  a physical register
237   */
238  boolean isAssigned(RegisterAllocatorState regAllocState) {
239    return (regAllocState.getMapping(getRegister()) != null);
240  }
241
242  /**
243   * @param regAllocState current state of the register allocator
244   * @return the physical register this interval is assigned to, {@code null}
245   *  if none assigned
246   */
247  Register getAssignment(RegisterAllocatorState regAllocState) {
248    return regAllocState.getMapping(getRegister());
249  }
250
251  /**
252   * Merges this interval with another, non-intersecting interval.
253   * <p>
254   * Precondition: BasicInterval stop is an interval in i.  This version
255   * will only merge basic intervals up to and including stop into this.
256   *
257   * @param i a non-intersecting interval for merging
258   * @param stop a interval to stop at
259   */
260  void addNonIntersectingInterval(CompoundInterval i, BasicInterval stop) {
261    SortedSet<BasicInterval> headSet = i.headSetInclusive(stop);
262    addAll(headSet);
263  }
264
265  /**
266   * Computes the headSet() [from java.util.SortedSet] but includes all
267   * elements less than upperBound <em>inclusive</em>.
268   *
269   * @param upperBound the interval acting as upper bound
270   * @return the head set
271   * @see SortedSet#headSet(Object)
272   */
273  SortedSet<BasicInterval> headSetInclusive(BasicInterval upperBound) {
274    BasicInterval newUpperBound = new BasicInterval(upperBound.getBegin() + 1, upperBound.getEnd());
275    return headSet(newUpperBound);
276  }
277
278  /**
279   * Computes the headSet() [from java.util.SortedSet] but includes all
280   * elements less than upperBound <em>inclusive</em>.
281   *
282   * @param upperBound the instruction number acting as upper bound
283   * @return the head set
284   * @see SortedSet#headSet(Object)
285   */
286  SortedSet<BasicInterval> headSetInclusive(int upperBound) {
287    BasicInterval newUpperBound = new BasicInterval(upperBound + 1, upperBound + 1);
288    return headSet(newUpperBound);
289  }
290
291  /**
292   * Computes the tailSet() [from java.util.SortedSet] but includes all
293   * elements greater than lowerBound <em>inclusive</em>.
294   *
295   * @param lowerBound the instruction number acting as lower bound
296   * @return the tail set
297   * @see SortedSet#tailSet(Object)
298   */
299  SortedSet<BasicInterval> tailSetInclusive(int lowerBound) {
300    BasicInterval newLowerBound = new BasicInterval(lowerBound - 1, lowerBound - 1);
301    return tailSet(newLowerBound);
302  }
303
304  /**
305   * Removes some basic intervals from this compound interval, and returns
306   * the intervals actually removed.
307   * <p>
308   * PRECONDITION: All basic intervals in the other interval that have the
309   * same begin as an interval in this compound interval must have the same
310   * end. For example, for a compound interval {@code [(1,2)(2,3)]},
311   * the other interval would be allowed to contain {@code (1,2)} and/or
312   * {@code (2,2)} but not {@code (1,3)}.
313   * <p>
314   * A violation of the precondition that would have an effect will trigger
315   * an assertion failure in assertion-enabled builds.
316   *
317   * @param other interval to check for intervals that we want to remove
318   *  from this
319   * @return the basic intervals that were removed
320   */
321  CompoundInterval removeIntervalsAndCache(CompoundInterval other) {
322    CompoundInterval result = new CompoundInterval(other.getRegister());
323    Iterator<BasicInterval> myIterator = iterator();
324    Iterator<BasicInterval> otherIterator = other.iterator();
325    BasicInterval current = myIterator.hasNext() ? myIterator.next() : null;
326    BasicInterval otherCurrent = otherIterator.hasNext() ? otherIterator.next() : null;
327
328    while (otherCurrent != null && current != null) {
329      if (current.startsBefore(otherCurrent)) {
330        current = myIterator.hasNext() ? myIterator.next() : null;
331      } else if (otherCurrent.startsBefore(current)) {
332        otherCurrent = otherIterator.hasNext() ? otherIterator.next() : null;
333      } else {
334        if (VM.VerifyAssertions) VM._assert(current.sameRange(otherCurrent));
335
336        otherCurrent = otherIterator.hasNext() ? otherIterator.next() : null;
337        BasicInterval next = myIterator.hasNext() ? myIterator.next() : null;
338        // add the interval to the cache
339        result.add(current);
340        current = next;
341      }
342    }
343
344    removeAll(result);
345    return result;
346  }
347
348  /**
349   * @return the lowest DFN in this compound interval at this time
350   */
351  int getLowerBound() {
352    BasicInterval b = first();
353    return b.getBegin();
354  }
355
356  /**
357   * @return the highest DFN in this compound interval at this time
358   */
359  int getUpperBound() {
360    BasicInterval b = last();
361    return b.getEnd();
362  }
363
364  boolean intersects(CompoundInterval i) {
365
366    if (isEmpty()) return false;
367    if (i.isEmpty()) return false;
368
369    // Walk over the basic intervals of this interval and i.
370    // Restrict the walking to intervals that might intersect.
371    int lower = Math.max(getLowerBound(), i.getLowerBound());
372    int upper = Math.min(getUpperBound(), i.getUpperBound());
373
374    // we may have to move one interval lower on each side.
375    BasicInterval b = getBasicInterval(lower);
376    int myLower = (b == null) ? lower : b.getBegin();
377    if (myLower > upper) return false;
378    b = i.getBasicInterval(lower);
379    int otherLower = (b == null) ? lower : b.getBegin();
380    if (otherLower > upper) return false;
381
382    SortedSet<BasicInterval> myTailSet = tailSetInclusive(myLower);
383    SortedSet<BasicInterval> otherTailSet = i.tailSetInclusive(otherLower);
384    Iterator<BasicInterval> myIterator = myTailSet.iterator();
385    Iterator<BasicInterval> otherIterator = otherTailSet.iterator();
386
387    BasicInterval current = myIterator.hasNext() ? myIterator.next() : null;
388    BasicInterval currentI = otherIterator.hasNext() ? otherIterator.next() : null;
389
390    while (current != null && currentI != null) {
391      if (current.getBegin() > upper) break;
392      if (currentI.getBegin() > upper) break;
393      if (current.intersects(currentI)) return true;
394
395      if (current.startsBefore(currentI)) {
396        current = myIterator.hasNext() ? myIterator.next() : null;
397      } else {
398        currentI = otherIterator.hasNext() ? otherIterator.next() : null;
399      }
400    }
401    return false;
402  }
403
404  /**
405   * @param dfnNumbers depth-first numbers for for instructions
406   * @param s   The instruction in question
407   * @return the first basic interval that contains a given
408   * instruction, {@code null} if there is no such interval
409
410   */
411  BasicInterval getBasicInterval(RegisterAllocatorState dfnNumbers, Instruction s) {
412    return getBasicInterval(dfnNumbers.getDFN(s));
413  }
414
415  /**
416   * @param n The DFN of the instruction in question
417   * @return the first basic interval that contains a given
418   * instruction, {@code null} if there is no such interval
419   */
420  BasicInterval getBasicInterval(int n) {
421    SortedSet<BasicInterval> headSet = headSetInclusive(n);
422    if (!headSet.isEmpty()) {
423      BasicInterval last = headSet.last();
424      return last.contains(n) ? last : null;
425    } else {
426      return null;
427    }
428  }
429
430  @Override
431  public String toString() {
432    StringBuilder str = new StringBuilder("[");
433    str.append(getRegister());
434    str.append("]:");
435    for (Iterator<BasicInterval> i = iterator(); i.hasNext();) {
436      BasicInterval b = i.next();
437      str.append(b);
438    }
439    return str.toString();
440  }
441}