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.ArrayList; 016import java.util.HashMap; 017import java.util.HashSet; 018import org.jikesrvm.compilers.opt.ir.Instruction; 019import org.jikesrvm.compilers.opt.ir.Register; 020 021/** 022 * This class holds information on scratch register usage, needed to 023 * adjust GC Maps. 024 */ 025public final class ScratchMap { 026 027 private static final boolean DEBUG = false; 028 029 /** 030 * For each register, the set of intervals describing the register. 031 */ 032 private final HashMap<Register, ArrayList<Interval>> map = new HashMap<Register, ArrayList<Interval>>(); 033 034 /** 035 * For each register, a pending (incomplete) interval under 036 * construction. 037 */ 038 private final HashMap<Register, Interval> pending = new HashMap<Register, Interval>(); 039 040 /** 041 * For each GC Point s, a set of symbolic registers that are cached in 042 * dirty scratch registers before s. 043 */ 044 private final HashMap<Instruction, HashSet<Register>> dirtyMap = 045 new HashMap<Instruction, HashSet<Register>>(); 046 047 private final RegisterAllocatorState regAllocState; 048 049 public ScratchMap(RegisterAllocatorState regAllocState) { 050 this.regAllocState = regAllocState; 051 } 052 053 /** 054 * Begin a new interval of scratch-ness for a symbolic register. 055 * 056 * @param r the symbolic register being moved into scratch 057 * @param scratch the physical register being used as a scratch 058 * @param begin the instruction before which the physical register is 059 * vacated. 060 */ 061 void beginSymbolicInterval(Register r, Register scratch, Instruction begin) { 062 if (DEBUG) { 063 System.out.println("beginSymbolicInterval " + r + " " + scratch + " " + 064 regAllocState.getDFN(begin)); 065 } 066 067 SymbolicInterval i = new SymbolicInterval(r, scratch); 068 i.begin = begin; 069 ArrayList<Interval> v = findOrCreateIntervalSet(r); 070 v.add(i); 071 pending.put(r, i); 072 } 073 074 /** 075 * End an interval of scratch-ness for a symbolic register. 076 * 077 * @param r the symbolic register being moved into scratch 078 * @param end the instruction before which the scratch interval ends 079 */ 080 public void endSymbolicInterval(Register r, Instruction end) { 081 if (DEBUG) { 082 System.out.println("endSymbolicInterval " + r + " " + 083 regAllocState.getDFN(end)); 084 } 085 086 SymbolicInterval i = (SymbolicInterval) pending.get(r); 087 i.end = end; 088 pending.remove(r); 089 } 090 091 /** 092 * Begin a new interval of scratch-ness for a physical register. 093 * 094 * @param r the physical register being used as a scratch 095 * @param begin the instruction before which the physical register is 096 * vacated. 097 */ 098 void beginScratchInterval(Register r, Instruction begin) { 099 if (DEBUG) { 100 System.out.println("beginScratchInterval " + r + " " + 101 regAllocState.getDFN(begin)); 102 } 103 PhysicalInterval p = new PhysicalInterval(r); 104 p.begin = begin; 105 ArrayList<Interval> v = findOrCreateIntervalSet(r); 106 v.add(p); 107 pending.put(r, p); 108 } 109 110 /** 111 * End an interval of scratch-ness for a physical register. 112 * 113 * @param r the physical register being used as a scratch 114 * @param end the instruction before which the physical register is 115 * vacated. 116 */ 117 public void endScratchInterval(Register r, Instruction end) { 118 if (DEBUG) { 119 System.out.println("endScratchInterval " + r + " " + 120 regAllocState.getDFN(end)); 121 } 122 PhysicalInterval p = (PhysicalInterval) pending.get(r); 123 p.end = end; 124 pending.remove(r); 125 } 126 127 /** 128 * Find or create the set of intervals corresponding to a register r. 129 * 130 * @param r the register to check 131 * @return a possibly empty list of intervals 132 */ 133 private ArrayList<Interval> findOrCreateIntervalSet(Register r) { 134 ArrayList<Interval> v = map.get(r); 135 if (v == null) { 136 v = new ArrayList<Interval>(); 137 map.put(r, v); 138 } 139 return v; 140 } 141 142 /** 143 * Is the given physical register being used as a scratch register 144 * in the given instruction? 145 * @param r a physical register 146 * @param n the instruction's number 147 * @return {@code true} if the register is used as a scratch register 148 * in the instruction, {@code false} otherwise 149 */ 150 boolean isScratch(Register r, int n) { 151 ArrayList<Interval> v = map.get(r); 152 if (v == null) return false; 153 for (final Interval interval : v) { 154 if (interval.contains(n)) return true; 155 } 156 return false; 157 } 158 159 /** 160 * Gets the scratch register if a matching one exists. 161 * 162 * @param r a symbolic register 163 * @param n the instruction number 164 * @return if a symbolic register resides in a scratch register at an 165 * instruction with the given number, then return the scratch register. Else, 166 * return {@code null}. 167 */ 168 Register getScratch(Register r, int n) { 169 ArrayList<Interval> v = map.get(r); 170 if (v == null) return null; 171 for (Interval i : v) { 172 if (i.contains(n)) return i.scratch; 173 } 174 return null; 175 } 176 177 public boolean isEmpty() { 178 return map.isEmpty(); 179 } 180 181 /** 182 * Records that the real value of a symbolic register is cached in 183 * a dirty scratch register at a given instruction that is a GC point. 184 * 185 * @param s an instruction that is a GC point. Note: it is the caller's 186 * responsibility to check this 187 * @param symb the symbolic register 188 */ 189 public void markDirty(Instruction s, Register symb) { 190 HashSet<Register> set = dirtyMap.get(s); 191 if (set == null) { 192 set = new HashSet<Register>(3); 193 dirtyMap.put(s, set); 194 } 195 set.add(symb); 196 } 197 198 /** 199 * At GC point s, is the value of register r cached in a dirty scratch 200 * register? 201 * 202 * @param s an instruction that is a GC point 203 * @param r register to check 204 * @return {@code true} if the register is in a scratch register and 205 * the scratch register is dirty, {@code false} otherwise 206 */ 207 public boolean isDirty(Instruction s, Register r) { 208 HashSet<Register> set = dirtyMap.get(s); 209 if (set == null) { 210 return false; 211 } else { 212 return set.contains(r); 213 } 214 } 215 216 @Override 217 public String toString() { 218 StringBuilder result = new StringBuilder(); 219 for (ArrayList<Interval> v : map.values()) { 220 for (Interval i : v) { 221 result.append(i); 222 result.append("\n"); 223 } 224 } 225 return result.toString(); 226 } 227 228 /** 229 * Super class of physical and symbolic intervals 230 */ 231 private abstract class Interval { 232 /** 233 * The instruction before which the scratch range begins. 234 */ 235 protected Instruction begin; 236 /** 237 * The instruction before which the scratch range ends. 238 */ 239 protected Instruction end; 240 /** 241 * The physical scratch register or register evicted. 242 */ 243 protected final Register scratch; 244 245 protected Interval(Register scratch) { 246 this.scratch = scratch; 247 } 248 249 /** 250 * Does this interval contain the instruction numbered n? 251 * 252 * @param n instruction number 253 * @return {@code true} if and only if the instruction with the 254 * given number is contained n this interval 255 */ 256 protected final boolean contains(int n) { 257 return (regAllocState.getDFN(begin) <= n && 258 regAllocState.getDFN(end) > n); 259 } 260 } 261 262 /** 263 * An object that represents an interval where a symbolic register 264 * resides in a scratch register.<p> 265 * 266 * Note that this interval must not span a basic block. 267 */ 268 private final class SymbolicInterval extends Interval { 269 /** 270 * The symbolic register 271 */ 272 private final Register symbolic; 273 274 SymbolicInterval(Register symbolic, Register scratch) { 275 super(scratch); 276 this.symbolic = symbolic; 277 } 278 279 /** 280 * Return a string representation, assuming the 'scratch' field of 281 * Instruction identifies an instruction. 282 * 283 * @return a string representation of this interval 284 */ 285 @Override 286 public String toString() { 287 return "SI: " + symbolic + " " + scratch + " [" + 288 regAllocState.getDFN(begin) + "," + regAllocState.getDFN(end) + "]"; 289 } 290 } 291 292 /** 293 * An object that represents an interval where a physical register's 294 * contents are evicted so that the physical register can be used as a 295 * scratch.<p> 296 * 297 * Note that this interval must not span a basic block. 298 */ 299 private final class PhysicalInterval extends Interval { 300 PhysicalInterval(Register scratch) { 301 super(scratch); 302 } 303 304 /** 305 * Return a string representation, assuming the 'scratch' field of 306 * Instruction identifies an instruction. 307 * 308 * @return a string representation of this interval 309 */ 310 @Override 311 public String toString() { 312 return "PI: " + scratch + " [" + regAllocState.getDFN(begin) + 313 "," + regAllocState.getDFN(end) + "]"; 314 } 315 } 316}