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}