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}