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.Enumeration; 016import java.util.HashMap; 017import java.util.HashSet; 018import java.util.Iterator; 019import java.util.Map; 020 021import org.jikesrvm.compilers.opt.ir.GenericPhysicalRegisterSet; 022import org.jikesrvm.compilers.opt.ir.IR; 023import org.jikesrvm.compilers.opt.ir.Register; 024import org.jikesrvm.compilers.opt.util.GraphEdge; 025import org.jikesrvm.compilers.opt.util.SpaceEffGraphNode; 026 027/** 028 * The following class manages allocation and reuse of spill locations. 029 */ 030class SpillLocationManager { 031 032 /** 033 * The governing IR 034 */ 035 private final IR ir; 036 037 /** 038 * Set of spill locations which were previously allocated, but may be 039 * free since the assigned register is no longer live. 040 */ 041 final HashSet<SpillLocationInterval> freeIntervals = new HashSet<SpillLocationInterval>(); 042 043 /** 044 * @param ci a compound interval that we want to spill 045 * @return a spill location that is valid to hold the contents of 046 * the compound interval 047 */ 048 SpillLocationInterval findOrCreateSpillLocation(CompoundInterval ci) { 049 SpillLocationInterval result = null; 050 051 Register r = ci.getRegister(); 052 int type = GenericPhysicalRegisterSet.getPhysicalRegisterType(r); 053 int spillSize = GenericPhysicalRegisterSet.getSpillSize(type); 054 055 // Search the free intervals and try to find an interval to 056 // reuse. First look for the preferred interval. 057 if (ir.options.REGALLOC_COALESCE_SPILLS) { 058 result = getSpillPreference(ci, spillSize, type); 059 if (result != null) { 060 if (LinearScan.DEBUG_COALESCE) { 061 System.out.println("SPILL PREFERENCE " + ci + " " + result); 062 } 063 freeIntervals.remove(result); 064 } 065 } 066 067 // Now search for any free interval. 068 if (result == null) { 069 Iterator<SpillLocationInterval> iter = freeIntervals.iterator(); 070 while (iter.hasNext()) { 071 SpillLocationInterval s = iter.next(); 072 if (s.getSize() == spillSize && !s.intersects(ci) && s.getType() == type) { 073 result = s; 074 iter.remove(); 075 break; 076 } 077 } 078 } 079 080 if (result == null) { 081 // Could not find an interval to reuse. Create a new interval. 082 int location = ir.stackManager.allocateNewSpillLocation(type); 083 result = new SpillLocationInterval(location, spillSize, type); 084 } 085 086 // Update the spill location interval to hold the new spill 087 result.addAll(ci); 088 089 return result; 090 } 091 092 /** 093 * Records that a particular interval is potentially available for 094 * reuse. 095 * 096 * @param i the interval to free 097 */ 098 void freeInterval(SpillLocationInterval i) { 099 freeIntervals.add(i); 100 } 101 102 SpillLocationManager(IR ir) { 103 this.ir = ir; 104 } 105 106 /** 107 * Given the current state of the register allocator, compute the 108 * available spill location to which ci has the highest preference. 109 * 110 * @param ci the interval to spill 111 * @param spillSize the size of spill location needed 112 * @param type the physical register's type 113 * @return the interval to spill to. null if no preference found. 114 */ 115 SpillLocationInterval getSpillPreference(CompoundInterval ci, int spillSize, int type) { 116 // a mapping from SpillLocationInterval to Integer 117 // (spill location to weight); 118 HashMap<SpillLocationInterval, Integer> map = new HashMap<SpillLocationInterval, Integer>(); 119 Register r = ci.getRegister(); 120 121 CoalesceGraph graph = ir.stackManager.getPreferences().getGraph(); 122 SpaceEffGraphNode node = graph.findNode(r); 123 124 // Return null if no affinities. 125 if (node == null) return null; 126 127 RegisterAllocatorState regAllocState = ir.MIRInfo.regAllocState; 128 129 // walk through all in edges of the node, searching for spill 130 // location affinity 131 for (Enumeration<GraphEdge> in = node.inEdges(); in.hasMoreElements();) { 132 CoalesceGraph.Edge edge = (CoalesceGraph.Edge) in.nextElement(); 133 CoalesceGraph.Node src = (CoalesceGraph.Node) edge.from(); 134 Register neighbor = src.getRegister(); 135 if (neighbor.isSymbolic() && neighbor.isSpilled()) { 136 int spillOffset = regAllocState.getSpill(neighbor); 137 // if this is a candidate interval, update its weight 138 for (SpillLocationInterval s : freeIntervals) { 139 if (s.getOffset() == spillOffset && s.getSize() == spillSize && 140 !s.intersects(ci) && s.getType() == type) { 141 int w = edge.getWeight(); 142 Integer oldW = map.get(s); 143 if (oldW == null) { 144 map.put(s, w); 145 } else { 146 map.put(s, oldW + w); 147 } 148 break; 149 } 150 } 151 } 152 } 153 154 // walk through all out edges of the node, searching for spill 155 // location affinity 156 for (Enumeration<GraphEdge> in = node.inEdges(); in.hasMoreElements();) { 157 CoalesceGraph.Edge edge = (CoalesceGraph.Edge) in.nextElement(); 158 CoalesceGraph.Node dest = (CoalesceGraph.Node) edge.to(); 159 Register neighbor = dest.getRegister(); 160 if (neighbor.isSymbolic() && neighbor.isSpilled()) { 161 int spillOffset = regAllocState.getSpill(neighbor); 162 // if this is a candidate interval, update its weight 163 for (SpillLocationInterval s : freeIntervals) { 164 if (s.getOffset() == spillOffset && s.getSize() == spillSize && 165 !s.intersects(ci) && s.getType() == type) { 166 int w = edge.getWeight(); 167 Integer oldW = map.get(s); 168 if (oldW == null) { 169 map.put(s, w); 170 } else { 171 map.put(s, oldW + w); 172 } 173 break; 174 } 175 } 176 } 177 } 178 179 // OK, now find the highest preference. 180 SpillLocationInterval result = null; 181 int weight = -1; 182 for (Map.Entry<SpillLocationInterval, Integer> entry : map.entrySet()) { 183 int w = entry.getValue(); 184 if (w > weight) { 185 weight = w; 186 result = entry.getKey(); 187 } 188 } 189 return result; 190 } 191}