/* * 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.HashSet; import java.util.Iterator; import java.util.Map; import org.jikesrvm.compilers.opt.ir.GenericPhysicalRegisterSet; import org.jikesrvm.compilers.opt.ir.IR; import org.jikesrvm.compilers.opt.ir.Register; import org.jikesrvm.compilers.opt.util.GraphEdge; import org.jikesrvm.compilers.opt.util.SpaceEffGraphNode; /** * The following class manages allocation and reuse of spill locations. */ class SpillLocationManager { /** * The governing IR */ private final IR ir; /** * Set of spill locations which were previously allocated, but may be * free since the assigned register is no longer live. */ final HashSet<SpillLocationInterval> freeIntervals = new HashSet<SpillLocationInterval>(); /** * @param ci a compound interval that we want to spill * @return a spill location that is valid to hold the contents of * the compound interval */ SpillLocationInterval findOrCreateSpillLocation(CompoundInterval ci) { SpillLocationInterval result = null; Register r = ci.getRegister(); int type = GenericPhysicalRegisterSet.getPhysicalRegisterType(r); int spillSize = ir.stackManager.getSpillSize(type); // Search the free intervals and try to find an interval to // reuse. First look for the preferred interval. if (ir.options.REGALLOC_COALESCE_SPILLS) { result = getSpillPreference(ci, spillSize, type); if (result != null) { if (LinearScan.DEBUG_COALESCE) { System.out.println("SPILL PREFERENCE " + ci + " " + result); } freeIntervals.remove(result); } } // Now search for any free interval. if (result == null) { Iterator<SpillLocationInterval> iter = freeIntervals.iterator(); while (iter.hasNext()) { SpillLocationInterval s = iter.next(); if (s.getSize() == spillSize && !s.intersects(ci) && s.getType() == type) { result = s; iter.remove(); break; } } } if (result == null) { // Could not find an interval to reuse. Create a new interval. int location = ir.stackManager.allocateNewSpillLocation(type); result = new SpillLocationInterval(location, spillSize, type); } // Update the spill location interval to hold the new spill result.addAll(ci); return result; } /** * Records that a particular interval is potentially available for * reuse. * * @param i the interval to free */ void freeInterval(SpillLocationInterval i) { freeIntervals.add(i); } SpillLocationManager(IR ir) { this.ir = ir; } /** * Given the current state of the register allocator, compute the * available spill location to which ci has the highest preference. * * @param ci the interval to spill * @param spillSize the size of spill location needed * @param type the physical register's type * @return the interval to spill to. null if no preference found. */ SpillLocationInterval getSpillPreference(CompoundInterval ci, int spillSize, int type) { // a mapping from SpillLocationInterval to Integer // (spill location to weight); HashMap<SpillLocationInterval, Integer> map = new HashMap<SpillLocationInterval, 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; RegisterAllocatorState regAllocState = ir.MIRInfo.regAllocState; // walk through all in edges of the node, searching for spill // location 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() && neighbor.isSpilled()) { int spillOffset = regAllocState.getSpill(neighbor); // if this is a candidate interval, update its weight for (SpillLocationInterval s : freeIntervals) { if (s.getOffset() == spillOffset && s.getSize() == spillSize && !s.intersects(ci) && s.getType() == type) { int w = edge.getWeight(); Integer oldW = map.get(s); if (oldW == null) { map.put(s, w); } else { map.put(s, oldW + w); } break; } } } } // walk through all out edges of the node, searching for spill // location affinity for (Enumeration<GraphEdge> in = node.inEdges(); in.hasMoreElements();) { CoalesceGraph.Edge edge = (CoalesceGraph.Edge) in.nextElement(); CoalesceGraph.Node dest = (CoalesceGraph.Node) edge.to(); Register neighbor = dest.getRegister(); if (neighbor.isSymbolic() && neighbor.isSpilled()) { int spillOffset = regAllocState.getSpill(neighbor); // if this is a candidate interval, update its weight for (SpillLocationInterval s : freeIntervals) { if (s.getOffset() == spillOffset && s.getSize() == spillSize && !s.intersects(ci) && s.getType() == type) { int w = edge.getWeight(); Integer oldW = map.get(s); if (oldW == null) { map.put(s, w); } else { map.put(s, oldW + w); } break; } } } } // OK, now find the highest preference. SpillLocationInterval result = null; int weight = -1; for (Map.Entry<SpillLocationInterval, Integer> entry : map.entrySet()) { int w = entry.getValue(); if (w > weight) { weight = w; result = entry.getKey(); } } return result; } }