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; 014 015import static org.jikesrvm.compilers.opt.ir.Operators.PHI; 016 017import java.util.Arrays; 018import java.util.Enumeration; 019 020import org.jikesrvm.VM; 021import org.jikesrvm.classloader.TypeReference; 022import org.jikesrvm.compilers.opt.ir.BasicBlock; 023import org.jikesrvm.compilers.opt.ir.IR; 024import org.jikesrvm.compilers.opt.ir.Instruction; 025import org.jikesrvm.compilers.opt.ir.Register; 026import org.jikesrvm.compilers.opt.ir.operand.Operand; 027import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand; 028import org.vmmagic.pragma.NoInline; 029 030/** 031 * This class computes du-lists and associated information. 032 * 033 * <P> Note: DU operands are stored on the USE lists, but not the DEF 034 * lists. 035 */ 036public final class DefUse { 037 static final boolean DEBUG = false; 038 static final boolean TRACE_DU_ACTIONS = false; 039 static final boolean SUPRESS_DU_FOR_PHYSICALS = true; 040 041 /** 042 * Clear defList, useList for an IR. 043 * 044 * @param ir the IR in question 045 */ 046 public static void clearDU(IR ir) { 047 for (Register reg = ir.regpool.getFirstSymbolicRegister(); reg != null; reg = reg.getNext()) { 048 reg.defList = null; 049 reg.useList = null; 050 reg.clearSeenUse(); 051 } 052 for (Enumeration<Register> e = ir.regpool.getPhysicalRegisterSet().enumerateAll(); e.hasMoreElements();) { 053 Register reg = e.nextElement(); 054 reg.defList = null; 055 reg.useList = null; 056 reg.clearSeenUse(); 057 } 058 059 if (TRACE_DU_ACTIONS || DEBUG) { 060 VM.sysWrite("Cleared DU\n"); 061 } 062 } 063 064 /** 065 * Compute the register list and def-use lists for a method. 066 * 067 * @param ir the IR in question 068 */ 069 @NoInline 070 public static void computeDU(IR ir) { 071 // Clear old register list (if any) 072 clearDU(ir); 073 // Create register defList and useList 074 for (Instruction instr = ir.firstInstructionInCodeOrder(); instr != null; instr = 075 instr.nextInstructionInCodeOrder()) { 076 077 Enumeration<Operand> defs = instr.getPureDefs(); 078 Enumeration<Operand> uses = instr.getUses(); 079 080 while (defs.hasMoreElements()) { 081 Operand op = defs.nextElement(); 082 if (op instanceof RegisterOperand) { 083 RegisterOperand rop = (RegisterOperand) op; 084 recordDef(rop); 085 } 086 } // for ( defs = ... ) 087 088 while (uses.hasMoreElements()) { 089 Operand op = uses.nextElement(); 090 if (op instanceof RegisterOperand) { 091 RegisterOperand rop = (RegisterOperand) op; 092 recordUse(rop); 093 } 094 } // for ( uses = ... ) 095 } // for ( instr = ... ) 096 // Remove any symbloic registers with no uses/defs from 097 // the register pool. We'll waste analysis time keeping them around. 098 Register next; 099 for (Register reg = ir.regpool.getFirstSymbolicRegister(); reg != null; reg = next) { 100 next = reg.getNext(); 101 if (reg.defList == null && reg.useList == null) { 102 if (DEBUG) { 103 VM.sysWrite("Removing " + reg + " from the register pool\n"); 104 } 105 ir.regpool.removeRegister(reg); 106 } 107 } 108 } 109 110 /** 111 * Record a use of a register 112 * @param regOp the operand that uses the register 113 */ 114 public static void recordUse(RegisterOperand regOp) { 115 Register reg = regOp.getRegister(); 116 regOp.setNext(reg.useList); 117 reg.useList = regOp; 118 reg.useCount++; 119 } 120 121 /** 122 * Record a def/use of a register 123 * TODO: For now we just pretend this is a use!!!! 124 * 125 * @param regOp the operand that uses the register 126 */ 127 public static void recordDefUse(RegisterOperand regOp) { 128 Register reg = regOp.getRegister(); 129 if (SUPRESS_DU_FOR_PHYSICALS && reg.isPhysical()) return; 130 regOp.setNext(reg.useList); 131 reg.useList = regOp; 132 } 133 134 /** 135 * Record a def of a register 136 * @param regOp the operand that uses the register 137 */ 138 public static void recordDef(RegisterOperand regOp) { 139 Register reg = regOp.getRegister(); 140 if (SUPRESS_DU_FOR_PHYSICALS && reg.isPhysical()) return; 141 regOp.setNext(reg.defList); 142 reg.defList = regOp; 143 } 144 145 /** 146 * Record that a use of a register no longer applies 147 * @param regOp the operand that uses the register 148 */ 149 public static void removeUse(RegisterOperand regOp) { 150 Register reg = regOp.getRegister(); 151 if (SUPRESS_DU_FOR_PHYSICALS && reg.isPhysical()) return; 152 if (regOp == reg.useList) { 153 reg.useList = reg.useList.getNext(); 154 } else { 155 RegisterOperand prev = reg.useList; 156 RegisterOperand curr = prev.getNext(); 157 while (curr != regOp) { 158 prev = curr; 159 curr = curr.getNext(); 160 } 161 prev.setNext(curr.getNext()); 162 } 163 reg.useCount--; 164 if (DEBUG) { 165 VM.sysWrite("removed a use " + regOp.instruction + "\n"); 166 printUses(reg); 167 } 168 } 169 170 /** 171 * Record that a def of a register no longer applies 172 * @param regOp the operand that uses the register 173 */ 174 public static void removeDef(RegisterOperand regOp) { 175 Register reg = regOp.getRegister(); 176 if (SUPRESS_DU_FOR_PHYSICALS && reg.isPhysical()) return; 177 if (regOp == reg.defList) { 178 reg.defList = reg.defList.getNext(); 179 } else { 180 RegisterOperand prev = reg.defList; 181 RegisterOperand curr = prev.getNext(); 182 while (curr != regOp) { 183 prev = curr; 184 curr = curr.getNext(); 185 } 186 prev.setNext(curr.getNext()); 187 } 188 if (DEBUG) { 189 VM.sysWrite("removed a def " + regOp.instruction + "\n"); 190 printDefs(reg); 191 } 192 } 193 194 /** 195 * This code changes the use in <code>origRegOp</code> to use 196 * the use in <code>newRegOp</code>. 197 * 198 * <p> If the type of <code>origRegOp</code> is not a reference, but the 199 * type of <code>newRegOp</code> is a reference, we need to update 200 * <code>origRegOp</code> to be a reference. 201 * Otherwise, the GC map code will be incorrect. -- Mike Hind 202 * @param origRegOp the register operand to change 203 * @param newRegOp the register operand to use for the change 204 */ 205 public static void transferUse(RegisterOperand origRegOp, RegisterOperand newRegOp) { 206 if (VM.VerifyAssertions) { 207 VM._assert(origRegOp.getRegister().getType() == newRegOp.getRegister().getType()); 208 } 209 Instruction inst = origRegOp.instruction; 210 if (DEBUG) { 211 VM.sysWrite("Transfering a use of " + origRegOp + " in " + inst + " to " + newRegOp + "\n"); 212 } 213 removeUse(origRegOp); 214 // check to see if the regOp type is NOT a ref, but the newRegOp type 215 // is a reference. This can occur because of magic calls. 216 if (!origRegOp.getType().isReferenceType() && newRegOp.getType().isReferenceType()) { 217 // clone the newRegOp object and use it to replace the regOp object 218 RegisterOperand copiedRegOp = (RegisterOperand) newRegOp.copy(); 219 inst.replaceOperand(origRegOp, copiedRegOp); 220 recordUse(copiedRegOp); 221 } else { 222 // just copy the register 223 origRegOp.setRegister(newRegOp.getRegister()); 224 if (newRegOp.getType() != TypeReference.ObjectReference && 225 !newRegOp.getType().isUnboxedType() && !origRegOp.isPreciseType()) { 226 // copy type information from new to orig unless its an unboxed type 227 // (we don't want to copy type information for unboxed types as it is 228 // likely the result of inlining new) or the type of the original is 229 // precise 230 origRegOp.copyTypeFrom(newRegOp); 231 } 232 recordUse(origRegOp); 233 } 234 if (DEBUG) { 235 printUses(origRegOp.getRegister()); 236 printUses(newRegOp.getRegister()); 237 } 238 } 239 240 public static void removeInstructionAndUpdateDU(Instruction s) { 241 for (Enumeration<Operand> e = s.getPureDefs(); e.hasMoreElements();) { 242 Operand op = e.nextElement(); 243 if (op instanceof RegisterOperand) { 244 removeDef((RegisterOperand) op); 245 } 246 } 247 for (Enumeration<Operand> e = s.getUses(); e.hasMoreElements();) { 248 Operand op = e.nextElement(); 249 if (op instanceof RegisterOperand) { 250 removeUse((RegisterOperand) op); 251 } 252 } 253 s.remove(); 254 } 255 256 public static void updateDUForNewInstruction(Instruction s) { 257 for (Enumeration<Operand> e = s.getPureDefs(); e.hasMoreElements();) { 258 Operand op = e.nextElement(); 259 if (op instanceof RegisterOperand) { 260 recordDef((RegisterOperand) op); 261 } 262 } 263 for (Enumeration<Operand> e = s.getUses(); e.hasMoreElements();) { 264 Operand op = e.nextElement(); 265 if (op instanceof RegisterOperand) { 266 recordUse((RegisterOperand) op); 267 } 268 } 269 } 270 271 public static void replaceInstructionAndUpdateDU(Instruction oldI, Instruction newI) { 272 oldI.insertBefore(newI); 273 removeInstructionAndUpdateDU(oldI); 274 updateDUForNewInstruction(newI); 275 } 276 277 public static Enumeration<RegisterOperand> uses(Register reg) { 278 return new RegOpListWalker(reg.useList); 279 } 280 281 public static Enumeration<RegisterOperand> defs(Register reg) { 282 return new RegOpListWalker(reg.defList); 283 } 284 285 static boolean exactlyOneUse(Register reg) { 286 return (reg.useList != null) && (reg.useList.getNext() == null); 287 } 288 289 static void printDefs(Register reg) { 290 VM.sysWrite("Definitions of " + reg + '\n'); 291 for (Enumeration<RegisterOperand> e = defs(reg); e.hasMoreElements();) { 292 VM.sysWrite("\t" + e.nextElement().instruction + "\n"); 293 } 294 } 295 296 static void printUses(Register reg) { 297 VM.sysWrite("Uses of " + reg + '\n'); 298 for (Enumeration<RegisterOperand> e = uses(reg); e.hasMoreElements();) { 299 VM.sysWrite("\t" + e.nextElement().instruction + "\n"); 300 } 301 } 302 303 /** 304 * Recompute <code> isSSA </code> for all registers by traversing register 305 * list. 306 * NOTE: the DU MUST be computed BEFORE calling this function 307 * 308 * @param ir the IR in question 309 */ 310 public static void recomputeSSA(IR ir) { 311 // Use register /ist to enumerate register objects (FAST) 312 for (Register reg = ir.regpool.getFirstSymbolicRegister(); reg != null; reg = reg.getNext()) { 313 // Set isSSA = true iff reg has exactly one static definition. 314 reg.putSSA((reg.defList != null && reg.defList.getNext() == null)); 315 } 316 } 317 318 /** 319 * Merges a register into another register and removes the 320 * merged register from the DU information. 321 * 322 * @param reg1 the register that is being merged into 323 * @param reg2 the register that's being merged (and then removed from the 324 * DU information) 325 * @param ir the governing IR 326 */ 327 public static void mergeRegisters(IR ir, Register reg1, Register reg2) { 328 RegisterOperand lastOperand; 329 if (reg1 == reg2) { 330 return; 331 } 332 if (DEBUG) { 333 VM.sysWrite("Merging " + reg2 + " into " + reg1 + "\n"); 334 printDefs(reg2); 335 printUses(reg2); 336 printDefs(reg1); 337 printUses(reg1); 338 } 339 // first loop through defs of reg2 (currently, there will only be one def) 340 lastOperand = null; 341 for (RegisterOperand def = reg2.defList; def != null; lastOperand = def, def = def.getNext()) { 342 // Change def to refer to reg1 instead 343 def.setRegister(reg1); 344 // Track lastOperand 345 lastOperand = def; 346 } 347 if (lastOperand != null) { 348 // Set reg1.defList = concat(reg2.defList, reg1.deflist) 349 lastOperand.setNext(reg1.defList); 350 reg1.defList = reg2.defList; 351 } 352 // now loop through uses 353 lastOperand = null; 354 for (RegisterOperand use = reg2.useList; use != null; use = use.getNext()) { 355 // Change use to refer to reg1 instead 356 use.setRegister(reg1); 357 // Track lastOperand 358 lastOperand = use; 359 } 360 if (lastOperand != null) { 361 // Set reg1.useList = concat(reg2.useList, reg1.uselist) 362 lastOperand.setNext(reg1.useList); 363 reg1.useList = reg2.useList; 364 } 365 // Remove reg2 from RegisterPool 366 ir.regpool.removeRegister(reg2); 367 if (DEBUG) { 368 VM.sysWrite("Merge complete\n"); 369 printDefs(reg1); 370 printUses(reg1); 371 } 372 } 373 374 /** 375 * Recompute spansBasicBlock flags for all registers. 376 * 377 * @param ir the IR in question 378 */ 379 public static void recomputeSpansBasicBlock(IR ir) { 380 // clear fields 381 for (Register reg = ir.regpool.getFirstSymbolicRegister(); reg != null; reg = reg.getNext()) { 382 reg.clearSpansBasicBlock(); 383 } 384 385 int[] lastBBNums = new int[ir.regpool.getTotalNumberOfRegisters()]; 386 Arrays.fill(lastBBNums, -1); 387 // iterate over the basic blocks 388 for (BasicBlock bb = ir.firstBasicBlockInCodeOrder(); bb != null; bb = bb.nextBasicBlockInCodeOrder()) { 389 int bbNum = bb.getNumber(); 390 // enumerate the instructions in the basic block 391 for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements();) { 392 Instruction inst = e.nextElement(); 393 // check each Operand in the instruction 394 for (Enumeration<Operand> ops = inst.getOperands(); ops.hasMoreElements();) { 395 Operand op = ops.nextElement(); 396 if (op instanceof RegisterOperand) { 397 Register reg = ((RegisterOperand) op).getRegister(); 398 if (reg.isPhysical()) { 399 continue; 400 } 401 if (reg.spansBasicBlock()) { 402 continue; 403 } 404 if (seenInDifferentBlock(reg, bbNum, lastBBNums)) { 405 reg.setSpansBasicBlock(); 406 continue; 407 } 408 if (inst.operator() == PHI) { 409 reg.setSpansBasicBlock(); 410 continue; 411 } 412 logAppearance(reg, bbNum, lastBBNums); 413 } 414 } 415 } 416 } 417 } 418 419 /** 420 * Mark that we have seen a register in a particular 421 * basic block. 422 * 423 * @param reg the register 424 * @param bbNum the number of the basic block 425 * @param bbNums last block were each register was seen 426 */ 427 private static void logAppearance(Register reg, int bbNum, int[] bbNums) { 428 bbNums[reg.number] = bbNum; 429 } 430 431 /** 432 * @param reg the register 433 * @param bbNum the number of the basic block 434 * @param bbNums last block were each register was seen 435 * @return {@code true} if the register was seen in a different basic block 436 * than the one that was passed to this method 437 */ 438 private static boolean seenInDifferentBlock(Register reg, int bbNum, int[] bbNums) { 439 int bb = bbNums[reg.number]; 440 return (bb != -1) && (bb != bbNum); 441 } 442 443 /** 444 * Utility class to encapsulate walking a use/def list. 445 */ 446 private static final class RegOpListWalker implements Enumeration<RegisterOperand> { 447 448 private RegisterOperand current; 449 450 RegOpListWalker(RegisterOperand start) { 451 current = start; 452 } 453 454 @Override 455 public boolean hasMoreElements() { 456 return current != null; 457 } 458 459 @Override 460 public RegisterOperand nextElement() { 461 if (current == null) raiseNoSuchElementException(); 462 RegisterOperand tmp = current; 463 current = current.getNext(); 464 return tmp; 465 } 466 467 @NoInline 468 private static void raiseNoSuchElementException() { 469 throw new java.util.NoSuchElementException("RegOpListWalker"); 470 } 471 } 472}