/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.compilers.opt.regalloc; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.jikesrvm.VM; import org.jikesrvm.compilers.opt.OptimizingCompilerException; import org.jikesrvm.compilers.opt.ir.GenericPhysicalRegisterSet; import org.jikesrvm.compilers.opt.ir.IR; import org.jikesrvm.compilers.opt.ir.Instruction; import org.jikesrvm.compilers.opt.ir.Register; import org.jikesrvm.compilers.opt.util.GraphEdge; import org.jikesrvm.compilers.opt.util.SpaceEffGraphNode; /** * "Active set" for linear scan register allocation. * This version is maintained sorted in order of increasing * live interval end point. */ final class ActiveSet extends IncreasingEndMappedIntervalSet { /** Support for Set serialization */ static final long serialVersionUID = 2570397490575294294L; /** * Governing ir */ private final IR ir; private final RegisterAllocatorState regAllocState; /** * Manager of spill locations; */ private final SpillLocationManager spillManager; /** * An object to help estimate spill costs */ private final transient SpillCostEstimator spillCost; /** * Have we spilled anything? */ private boolean spilled; ActiveSet(IR ir, SpillLocationManager sm, SpillCostEstimator cost) { super(); spilled = false; this.ir = ir; this.regAllocState = ir.MIRInfo.regAllocState; this.spillManager = sm; this.spillCost = cost; } boolean spilledSomething() { return spilled; } /** * For each new basic interval, we scan the list of active basic * intervals in order of increasing end point. We remove any "expired" * intervals - those * intervals that no longer overlap the new interval because their * end point precedes the new interval's start point - and makes the * corresponding register available for allocation * * @param newInterval the new interval */ void expireOldIntervals(BasicInterval newInterval) { for (Iterator<BasicInterval> e = iterator(); e.hasNext();) { MappedBasicInterval bi = (MappedBasicInterval) e.next(); // break out of the loop when we reach an interval that is still // alive int newStart = newInterval.getBegin(); if (bi.endsAfter(newStart)) break; if (LinearScan.VERBOSE_DEBUG) System.out.println("Expire " + bi); // note that the bi interval no longer is live freeInterval(bi); // remove bi from the active set e.remove(); } } void freeInterval(MappedBasicInterval bi) { CompoundInterval container = bi.container; Register r = container.getRegister(); if (r.isPhysical()) { r.deallocateRegister(); return; } if (container.isSpilled(regAllocState)) { // free the spill location iff this is the last interval in the // compound interval. BasicInterval last = container.last(); if (last.sameRange(bi)) { spillManager.freeInterval(container.getSpillInterval()); } } else { // free the assigned register if (VM.VerifyAssertions) VM._assert(container.getAssignment(regAllocState).isAllocated()); container.getAssignment(regAllocState).deallocateRegister(); } } void allocate(BasicInterval newInterval, CompoundInterval container) { if (LinearScan.DEBUG) { System.out.println("Allocate " + newInterval + " " + container.getRegister()); } Register r = container.getRegister(); if (container.isSpilled(regAllocState)) { // We previously decided to spill the compound interval. No further // action is needed. if (LinearScan.VERBOSE_DEBUG) System.out.println("Previously spilled " + container); } else { if (container.isAssigned(regAllocState)) { // The compound interval was previously assigned to a physical // register. Register phys = container.getAssignment(regAllocState); if (!currentlyActive(phys)) { // The assignment of newInterval to phys is still OK. // Update the live ranges of phys to include the new basic // interval if (LinearScan.VERBOSE_DEBUG) { System.out.println("Previously assigned to " + phys + " " + container + " phys interval " + regAllocState.getInterval(phys)); } updatePhysicalInterval(phys, newInterval); if (LinearScan.VERBOSE_DEBUG) { System.out.println(" now phys interval " + regAllocState.getInterval(phys)); } // Mark the physical register as currently allocated phys.allocateRegister(); } else { // The previous assignment is not OK, since the physical // register is now in use elsewhere. if (LinearScan.DEBUG) { System.out.println("Previously assigned, " + phys + " " + container); } // first look and see if there's another free register for // container. if (LinearScan.VERBOSE_DEBUG) System.out.println("Looking for free register"); Register freeR = findAvailableRegister(container); if (LinearScan.VERBOSE_DEBUG) System.out.println("Free register? " + freeR); if (freeR == null) { // Did not find a free register to assign. So, spill one of // the two intervals concurrently allocated to phys. CompoundInterval currentAssignment = getCurrentInterval(phys); // choose which of the two intervals to spill double costA = spillCost.getCost(container.getRegister()); double costB = spillCost.getCost(currentAssignment.getRegister()); if (LinearScan.VERBOSE_DEBUG) { System.out.println("Current assignment " + currentAssignment + " cost " + costB); } if (LinearScan.VERBOSE_DEBUG) { System.out.println("Cost of spilling" + container + " cost " + costA); } CompoundInterval toSpill = (costA < costB) ? container : currentAssignment; // spill it. Register p = toSpill.getAssignment(regAllocState); toSpill.spill(spillManager, regAllocState); spilled = true; if (LinearScan.VERBOSE_DEBUG) { System.out.println("Spilled " + toSpill + " from " + p); } CompoundInterval physInterval = regAllocState.getInterval(p); physInterval.removeAll(toSpill); if (LinearScan.VERBOSE_DEBUG) System.out.println(" after spill phys" + regAllocState.getInterval(p)); if (toSpill != container) updatePhysicalInterval(p, newInterval); if (LinearScan.VERBOSE_DEBUG) { System.out.println(" now phys interval " + regAllocState.getInterval(p)); } } else { // found a free register for container! use it! if (LinearScan.DEBUG) { System.out.println("Switch container " + container + "from " + phys + " to " + freeR); } CompoundInterval physInterval = regAllocState.getInterval(phys); if (LinearScan.DEBUG) { System.out.println("Before switch phys interval" + physInterval); } physInterval.removeAll(container); if (LinearScan.DEBUG) { System.out.println("Intervals of " + phys + " now " + physInterval); } container.assign(freeR); updatePhysicalInterval(freeR, container, newInterval); if (LinearScan.VERBOSE_DEBUG) { System.out.println("Intervals of " + freeR + " now " + regAllocState.getInterval(freeR)); } // mark the free register found as currently allocated. freeR.allocateRegister(); } } } else { // This is the first attempt to allocate the compound interval. // Attempt to find a free physical register for this interval. Register phys = findAvailableRegister(r); if (phys != null) { // Found a free register. Perform the register assignment. container.assign(phys); if (LinearScan.DEBUG) { System.out.println("First allocation " + phys + " " + container); } updatePhysicalInterval(phys, newInterval); if (LinearScan.VERBOSE_DEBUG) System.out.println(" now phys" + regAllocState.getInterval(phys)); // Mark the physical register as currently allocated. phys.allocateRegister(); } else { // Could not find a free physical register. Some member of the // active set must be spilled. Choose a spill candidate. CompoundInterval spillCandidate = getSpillCandidate(container); if (VM.VerifyAssertions) { VM._assert(!spillCandidate.isSpilled(regAllocState)); VM._assert((spillCandidate.getRegister().getType() == r.getType()) || (spillCandidate.getRegister().isNatural() && r.isNatural())); VM._assert(!ir.stackManager.getRestrictions().mustNotSpill(spillCandidate.getRegister())); if (spillCandidate.getAssignment(regAllocState) != null) { VM._assert(!ir.stackManager.getRestrictions(). isForbidden(r, spillCandidate.getAssignment(regAllocState))); } } if (spillCandidate != container) { // spill a previously allocated interval. phys = spillCandidate.getAssignment(regAllocState); spillCandidate.spill(spillManager, regAllocState); spilled = true; if (LinearScan.VERBOSE_DEBUG) { System.out.println("Spilled " + spillCandidate + " from " + phys); } CompoundInterval physInterval = regAllocState.getInterval(phys); if (LinearScan.VERBOSE_DEBUG) { System.out.println(" assigned " + phys + " to " + container); } physInterval.removeAll(spillCandidate); if (LinearScan.VERBOSE_DEBUG) System.out.println(" after spill phys" + regAllocState.getInterval(phys)); updatePhysicalInterval(phys, newInterval); if (LinearScan.VERBOSE_DEBUG) { System.out.println(" now phys interval " + regAllocState.getInterval(phys)); } container.assign(phys); } else { // spill the new interval. if (LinearScan.VERBOSE_DEBUG) System.out.println("spilled " + container); container.spill(spillManager, regAllocState); spilled = true; } } } } } /** * Updates the interval representing the allocations of a physical * register p to include a new interval i. * * @param p a physical register * @param i the new interval */ private void updatePhysicalInterval(Register p, BasicInterval i) { // Get a representation of the intervals already assigned to p. CompoundInterval physInterval = regAllocState.getInterval(p); if (physInterval == null) { // no interval yet. create one. regAllocState.setInterval(p, new CompoundInterval(i, p)); } else { // incorporate i into the set of intervals assigned to p CompoundInterval ci = new CompoundInterval(i, p); if (VM.VerifyAssertions) VM._assert(!ci.intersects(physInterval)); physInterval.addAll(ci); } } /** * Update the interval representing the allocations of a physical * register p to include a new compound interval c. Include only * those basic intervals in c up to and including basic interval stop. * * @param p a physical register * @param c the new interval * @param stop the last interval to be included */ private void updatePhysicalInterval(Register p, CompoundInterval c, BasicInterval stop) { // Get a representation of the intervals already assigned to p. CompoundInterval physInterval = regAllocState.getInterval(p); if (physInterval == null) { // no interval yet. create one. regAllocState.setInterval(p, c.copy(p, stop)); } else { // incorporate c into the set of intervals assigned to p if (VM.VerifyAssertions) VM._assert(!c.intersects(physInterval)); // copy to a new BasicInterval so "equals" will work as expected, // since "stop" may be a MappedBasicInterval. stop = new BasicInterval(stop.getBegin(), stop.getEnd()); physInterval.addNonIntersectingInterval(c, stop); } } /** * @param r a physical register * @return whether the particular physical register is currently allocated to an * interval in the active set */ boolean currentlyActive(Register r) { for (Iterator<BasicInterval> e = iterator(); e.hasNext();) { MappedBasicInterval i = (MappedBasicInterval) e.next(); CompoundInterval container = i.container; if (regAllocState.getMapping(container.getRegister()) == r) { return true; } } return false; } /** * @param r a physical register * @return the interval that the physical register is allocated to * @throws OptimizingCompilerException if the register is not currently * allocated to any interval */ CompoundInterval getCurrentInterval(Register r) { for (Iterator<BasicInterval> e = iterator(); e.hasNext();) { MappedBasicInterval i = (MappedBasicInterval) e.next(); CompoundInterval container = i.container; if (regAllocState.getMapping(container.getRegister()) == r) { return container; } } OptimizingCompilerException.UNREACHABLE("getCurrentInterval", "Not Currently Active ", r.toString()); return null; } /** * @param ci interval to allocate * @return a free physical register to allocate to the compound * interval, {@code null} if no free physical register is found */ Register findAvailableRegister(CompoundInterval ci) { if (ir.options.FREQ_FOCUS_EFFORT && ci.isInfrequent()) { // don't bother trying to find an available register return null; } Register r = ci.getRegister(); GenericRegisterRestrictions restrict = ir.stackManager.getRestrictions(); // first attempt to allocate to the preferred register if (ir.options.REGALLOC_COALESCE_MOVES) { Register p = getPhysicalPreference(ci); if (p != null) { if (LinearScan.DEBUG_COALESCE) { System.out.println("REGISTER PREFERENCE " + ci + " " + p); } return p; } } GenericPhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); int type = GenericPhysicalRegisterSet.getPhysicalRegisterType(r); // next attempt to allocate to a volatile if (!restrict.allVolatilesForbidden(r)) { for (Enumeration<Register> e = phys.enumerateVolatiles(type); e.hasMoreElements();) { Register p = e.nextElement(); if (allocateToPhysical(ci, p)) { return p; } } } // next attempt to allocate to a Nonvolatile. we allocate the // novolatiles backwards. for (Enumeration<Register> e = phys.enumerateNonvolatilesBackwards(type); e.hasMoreElements();) { Register p = e.nextElement(); if (allocateToPhysical(ci, p)) { return p; } } // no allocation succeeded. return null; } /** * @param symb symbolic register to allocate * @return a free physical register to allocate to the symbolic * register, {@code null} if no free physical register is found */ Register findAvailableRegister(Register symb) { GenericRegisterRestrictions restrict = ir.stackManager.getRestrictions(); // first attempt to allocate to the preferred register if (ir.options.REGALLOC_COALESCE_MOVES) { Register p = getPhysicalPreference(symb); if (p != null) { if (LinearScan.DEBUG_COALESCE) { System.out.println("REGISTER PREFERENCE " + symb + " " + p); } return p; } } GenericPhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); int type = GenericPhysicalRegisterSet.getPhysicalRegisterType(symb); // next attempt to allocate to a volatile if (!restrict.allVolatilesForbidden(symb)) { for (Enumeration<Register> e = phys.enumerateVolatiles(type); e.hasMoreElements();) { Register p = e.nextElement(); if (allocateNewSymbolicToPhysical(symb, p)) { return p; } } } // next attempt to allocate to a Nonvolatile. we allocate the // novolatiles backwards. for (Enumeration<Register> e = phys.enumerateNonvolatilesBackwards(type); e.hasMoreElements();) { Register p = e.nextElement(); if (allocateNewSymbolicToPhysical(symb, p)) { return p; } } // no allocation succeeded. return null; } /** * Given the current state of the register allocator, compute the * available physical register to which a symbolic register has the * highest preference. * * @param r the symbolic register in question. * @return the preferred register, {@code null} if no preference found. */ private Register getPhysicalPreference(Register r) { // a mapping from Register to Integer // (physical register to weight); HashMap<Register, Integer> map = new HashMap<Register, Integer>(); CoalesceGraph graph = ir.stackManager.getPreferences().getGraph(); SpaceEffGraphNode node = graph.findNode(r); // Return null if no affinities. if (node == null) return null; // walk through all in edges of the node, searching for affinity for (Enumeration<GraphEdge> in = node.inEdges(); in.hasMoreElements();) { CoalesceGraph.Edge edge = (CoalesceGraph.Edge) in.nextElement(); CoalesceGraph.Node src = (CoalesceGraph.Node) edge.from(); Register neighbor = src.getRegister(); if (neighbor.isSymbolic()) { // if r is assigned to a physical register r2, treat the // affinity as an affinity for r2 Register r2 = regAllocState.getMapping(r); if (r2 != null && r2.isPhysical()) { neighbor = r2; } } if (neighbor.isPhysical()) { // if this is a candidate interval, update its weight if (allocateNewSymbolicToPhysical(r, neighbor)) { int w = edge.getWeight(); Integer oldW = map.get(neighbor); if (oldW == null) { map.put(neighbor, w); } else { map.put(neighbor, oldW + w); } break; } } } // walk through all out edges of the node, searching for affinity for (Enumeration<GraphEdge> in = node.outEdges(); in.hasMoreElements();) { CoalesceGraph.Edge edge = (CoalesceGraph.Edge) in.nextElement(); CoalesceGraph.Node dest = (CoalesceGraph.Node) edge.to(); Register neighbor = dest.getRegister(); if (neighbor.isSymbolic()) { // if r is assigned to a physical register r2, treat the // affinity as an affinity for r2 Register r2 = regAllocState.getMapping(r); if (r2 != null && r2.isPhysical()) { neighbor = r2; } } if (neighbor.isPhysical()) { // if this is a candidate interval, update its weight if (allocateNewSymbolicToPhysical(r, neighbor)) { int w = edge.getWeight(); Integer oldW = map.get(neighbor); if (oldW == null) { map.put(neighbor, w); } else { map.put(neighbor, oldW + w); } break; } } } // OK, now find the highest preference. Register result = null; int weight = -1; for (Map.Entry<Register, Integer> entry : map.entrySet()) { int w = entry.getValue(); if (w > weight) { weight = w; result = entry.getKey(); } } return result; } /** * Given the current state of the register allocator, compute the * available physical register to which an interval has the highest * preference. * * @param ci the interval in question * @return the preferred register, {@code null} if no preference found */ private Register getPhysicalPreference(CompoundInterval ci) { // a mapping from Register to Integer // (physical register to weight); HashMap<Register, Integer> map = new HashMap<Register, Integer>(); Register r = ci.getRegister(); CoalesceGraph graph = ir.stackManager.getPreferences().getGraph(); SpaceEffGraphNode node = graph.findNode(r); // Return null if no affinities. if (node == null) return null; // walk through all in edges of the node, searching for affinity for (Enumeration<GraphEdge> in = node.inEdges(); in.hasMoreElements();) { CoalesceGraph.Edge edge = (CoalesceGraph.Edge) in.nextElement(); CoalesceGraph.Node src = (CoalesceGraph.Node) edge.from(); Register neighbor = src.getRegister(); if (neighbor.isSymbolic()) { // if r is assigned to a physical register r2, treat the // affinity as an affinity for r2 Register r2 = regAllocState.getMapping(r); if (r2 != null && r2.isPhysical()) { neighbor = r2; } } if (neighbor.isPhysical()) { // if this is a candidate interval, update its weight if (allocateToPhysical(ci, neighbor)) { int w = edge.getWeight(); Integer oldW = map.get(neighbor); if (oldW == null) { map.put(neighbor, w); } else { map.put(neighbor, oldW + w); } break; } } } // walk through all out edges of the node, searching for affinity for (Enumeration<GraphEdge> in = node.outEdges(); in.hasMoreElements();) { CoalesceGraph.Edge edge = (CoalesceGraph.Edge) in.nextElement(); CoalesceGraph.Node dest = (CoalesceGraph.Node) edge.to(); Register neighbor = dest.getRegister(); if (neighbor.isSymbolic()) { // if r is assigned to a physical register r2, treat the // affinity as an affinity for r2 Register r2 = regAllocState.getMapping(r); if (r2 != null && r2.isPhysical()) { neighbor = r2; } } if (neighbor.isPhysical()) { // if this is a candidate interval, update its weight if (allocateToPhysical(ci, neighbor)) { int w = edge.getWeight(); Integer oldW = map.get(neighbor); if (oldW == null) { map.put(neighbor, w); } else { map.put(neighbor, oldW + w); } break; } } } // OK, now find the highest preference. Register result = null; int weight = -1; for (Map.Entry<Register, Integer> entry : map.entrySet()) { int w = entry.getValue(); if (w > weight) { weight = w; result = entry.getKey(); } } return result; } /** * Checks whether it's ok to allocate an interval to a physical * register. * * @param i the interval to allocate * @param p the physical register * @return {@code true} if it's ok to allocate the interval to the * given physical register, {@code false} otherwise */ private boolean allocateToPhysical(CompoundInterval i, Register p) { GenericRegisterRestrictions restrict = ir.stackManager.getRestrictions(); Register r = i.getRegister(); GenericPhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); if (p != null && !phys.isAllocatable(p)) return false; if (LinearScan.VERBOSE_DEBUG && p != null) { if (!p.isAvailable()) System.out.println("unavailable " + i + p); if (restrict.isForbidden(r, p)) System.out.println("forbidden" + i + p); } if ((p != null) && p.isAvailable() && !restrict.isForbidden(r, p)) { CompoundInterval pInterval = regAllocState.getInterval(p); if (pInterval == null) { // no assignment to p yet return true; } else { if (!i.intersects(pInterval)) { return true; } } } return false; } /** * NOTE: This routine assumes we're processing the first interval of * register symb; so p.isAvailable() is the key information needed. * * @param symb the symbolic register * @param p the physical register * @return whether it's ok to allocate the symbolic register to the physical * register */ private boolean allocateNewSymbolicToPhysical(Register symb, Register p) { GenericRegisterRestrictions restrict = ir.stackManager.getRestrictions(); GenericPhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); if (p != null && !phys.isAllocatable(p)) return false; if (LinearScan.VERBOSE_DEBUG && p != null) { if (!p.isAvailable()) System.out.println("unavailable " + symb + p); if (restrict.isForbidden(symb, p)) System.out.println("forbidden" + symb + p); } return (p != null) && p.isAvailable() && !restrict.isForbidden(symb, p); } /** * @param newInterval a new interval * @return an interval that can be spilled. This may be chosen from the * existing candidates and the new interval */ private CompoundInterval getSpillCandidate(CompoundInterval newInterval) { if (LinearScan.VERBOSE_DEBUG) System.out.println("GetSpillCandidate from " + this); if (ir.options.FREQ_FOCUS_EFFORT && newInterval.isInfrequent()) { // if it's legal to spill this infrequent interval, then just do so! // don't spend any more effort. GenericRegisterRestrictions restrict = ir.stackManager.getRestrictions(); if (!restrict.mustNotSpill(newInterval.getRegister())) { return newInterval; } } return spillMinUnitCost(newInterval); } /** * Chooses the interval with the minimal unit cost (defined as the number * of defs and uses). * * @param newInterval a new interval * @return the interval with the minimal number of defs and uses */ private CompoundInterval spillMinUnitCost(CompoundInterval newInterval) { if (LinearScan.VERBOSE_DEBUG) { System.out.println(" interval caused a spill: " + newInterval); } GenericRegisterRestrictions restrict = ir.stackManager.getRestrictions(); Register r = newInterval.getRegister(); double minCost = spillCost.getCost(r); if (LinearScan.VERBOSE_DEBUG) { System.out.println(" spill cost: " + r + " " + minCost); } CompoundInterval result = newInterval; if (restrict.mustNotSpill(result.getRegister())) { if (LinearScan.VERBOSE_DEBUG) { System.out.println(" must not spill: " + result.getRegister()); } result = null; minCost = Double.MAX_VALUE; } for (Iterator<BasicInterval> e = iterator(); e.hasNext();) { MappedBasicInterval b = (MappedBasicInterval) e.next(); CompoundInterval i = b.container; Register newR = i.getRegister(); if (LinearScan.VERBOSE_DEBUG) { if (i.isSpilled(regAllocState)) { System.out.println(" not candidate, already spilled: " + newR); } if ((r.getType() != newR.getType()) || (r.isNatural() && newR.isNatural())) { System.out.println(" not candidate, type mismatch : " + r.getType() + " " + newR + " " + newR.getType()); } if (restrict.mustNotSpill(newR)) { System.out.println(" not candidate, must not spill: " + newR); } } if (!newR.isPhysical() && !i.isSpilled(regAllocState) && (r.getType() == newR.getType() || (r.isNatural() && newR.isNatural())) && !restrict.mustNotSpill(newR)) { // Found a potential spill interval. Check if the assignment // works if we spill this interval. if (checkAssignmentIfSpilled(newInterval, i)) { double iCost = spillCost.getCost(newR); if (LinearScan.VERBOSE_DEBUG) { System.out.println(" potential candidate " + i + " cost " + iCost); } if (iCost < minCost) { if (LinearScan.VERBOSE_DEBUG) System.out.println(" best candidate so far" + i); minCost = iCost; result = i; } } else { if (LinearScan.VERBOSE_DEBUG) { System.out.println(" not a candidate, insufficient range: " + i); } } } } if (VM.VerifyAssertions) { VM._assert(result != null); } return result; } /** * Checks if it would be possible to assign an interval to the physical * register of another interval if that other interval were spilled. * * @param spill the interval that's a candidate for spilling * @param i the interval that we want to assign to the register of the spill interval * @return {@code true} if the allocation would fit, {@code false} otherwise */ private boolean checkAssignmentIfSpilled(CompoundInterval i, CompoundInterval spill) { Register r = spill.getAssignment(regAllocState); GenericRegisterRestrictions restrict = ir.stackManager.getRestrictions(); if (restrict.isForbidden(i.getRegister(), r)) return false; // 1. Speculatively simulate the spill. CompoundInterval rI = regAllocState.getInterval(r); CompoundInterval cache = rI.removeIntervalsAndCache(spill); // 2. Check the fit. boolean result = !rI.intersects(i); // 3. Undo the simulated spill. rI.addAll(cache); return result; } /** * Finds a basic interval for a register so that the interval contains * the instruction. * * @param r the register whose interval is desired * @param s the reference instruction * @return {@code null} if there is no basic interval for the given register * that contains the instruction, the interval otherwise. If there are * multiple intervals, the first one will be returned. */ BasicInterval getBasicInterval(Register r, Instruction s) { CompoundInterval c = regAllocState.getInterval(r); if (c == null) return null; return c.getBasicInterval(regAllocState, s); } }