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.ssa; 014 015import static org.jikesrvm.compilers.opt.ir.Operators.*; 016 017import java.lang.reflect.Constructor; 018import java.util.Enumeration; 019import java.util.HashSet; 020import java.util.Iterator; 021import java.util.Map; 022 023import org.jikesrvm.VM; 024import org.jikesrvm.compilers.opt.DefUse; 025import org.jikesrvm.compilers.opt.OptOptions; 026import org.jikesrvm.compilers.opt.controlflow.DominatorInfo; 027import org.jikesrvm.compilers.opt.controlflow.DominatorTree; 028import org.jikesrvm.compilers.opt.controlflow.Dominators; 029import org.jikesrvm.compilers.opt.controlflow.DominatorsPhase; 030import org.jikesrvm.compilers.opt.driver.CompilerPhase; 031import org.jikesrvm.compilers.opt.ir.AStore; 032import org.jikesrvm.compilers.opt.ir.BBend; 033import org.jikesrvm.compilers.opt.ir.BasicBlock; 034import org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlock; 035import org.jikesrvm.compilers.opt.ir.GuardResultCarrier; 036import org.jikesrvm.compilers.opt.ir.IR; 037import org.jikesrvm.compilers.opt.ir.Instruction; 038import org.jikesrvm.compilers.opt.ir.Label; 039import org.jikesrvm.compilers.opt.ir.LocationCarrier; 040import org.jikesrvm.compilers.opt.ir.Operator; 041import org.jikesrvm.compilers.opt.ir.Phi; 042import org.jikesrvm.compilers.opt.ir.PutField; 043import org.jikesrvm.compilers.opt.ir.PutStatic; 044import org.jikesrvm.compilers.opt.ir.Register; 045import org.jikesrvm.compilers.opt.ir.ResultCarrier; 046import org.jikesrvm.compilers.opt.ir.operand.BasicBlockOperand; 047import org.jikesrvm.compilers.opt.ir.operand.HeapOperand; 048import org.jikesrvm.compilers.opt.ir.operand.LocationOperand; 049import org.jikesrvm.compilers.opt.ir.operand.Operand; 050import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand; 051import org.jikesrvm.compilers.opt.liveness.LiveAnalysis; 052import org.jikesrvm.compilers.opt.util.Queue; 053 054/** 055 * This class does loop invariant code movement. It is a subphase of {@link GCP} (global code placement). 056 */ 057public class LICM extends CompilerPhase { 058 /** Generate debug output? */ 059 private static final boolean DEBUG = false; 060 /** Generate verbose debug output? */ 061 private static boolean VERBOSE = false; 062 063 private Map<Instruction, Integer> instructionNumbers; 064 065 /** 066 * Constructor for this compiler phase 067 */ 068 private static final Constructor<CompilerPhase> constructor = getCompilerPhaseConstructor(LICM.class); 069 070 /** 071 * Get a constructor object for this compiler phase 072 * @return compiler phase constructor 073 */ 074 @Override 075 public Constructor<CompilerPhase> getClassConstructor() { 076 return constructor; 077 } 078 079 /** 080 * Execute loop invariant code motion on the given IR. 081 */ 082 @Override 083 public void perform(IR ir) { 084 this.ir = ir; 085 086 if (DEBUG && ir.hasReachableExceptionHandlers()) { 087 VM.sysWrite("] " + ir.method + "\n"); 088 (new LiveAnalysis(false, false, true, false)).perform(ir); 089 Enumeration<BasicBlock> e = ir.getBasicBlocks(); 090 while (e.hasMoreElements()) { 091 BasicBlock b = e.nextElement(); 092 if (b instanceof ExceptionHandlerBasicBlock) { 093 VM.sysWrite("] " + b + ": " + ((ExceptionHandlerBasicBlock) b).getLiveSet() + "\n"); 094 } 095 } 096 } 097 098 if (ir.hasReachableExceptionHandlers() || GCP.tooBig(ir)) { 099 resetLandingPads(); 100 return; 101 } 102 103 VERBOSE = ir.options.DEBUG_GCP; 104 105 if (VERBOSE && ir.options.hasMETHOD_TO_PRINT()) { 106 VERBOSE = ir.options.fuzzyMatchMETHOD_TO_PRINT(ir.method.toString()); 107 if (!VERBOSE) { 108 resetLandingPads(); 109 return; 110 } 111 } 112 113 if (VERBOSE) VM.sysWrite("] " + ir.method + "\n"); 114 initialize(ir); 115 if (VERBOSE) SSA.printInstructions(ir); 116 117 Instruction inst = ir.firstInstructionInCodeOrder(); 118 while (inst != null) { 119 Instruction next = inst.nextInstructionInCodeOrder(); 120 if (DEBUG) System.out.println("scheduleEarly: " + inst); 121 scheduleEarly(inst); 122 inst = next; 123 } 124 125 inst = ir.lastInstructionInCodeOrder(); 126 while (inst != null) { 127 Instruction next = inst.prevInstructionInCodeOrder(); 128 scheduleLate(inst); 129 inst = next; 130 } 131 resetLandingPads(); 132 if (DEBUG) SSA.printInstructions(ir); 133 ir.actualSSAOptions.setScalarValid(false); 134 } 135 136 /** 137 * @return the name of the phase 138 */ 139 @Override 140 public String getName() { 141 return "LICM"; 142 } 143 144 /** 145 * @return <code>true</code> if SSA-based global code placement is being 146 * performed 147 */ 148 @Override 149 public boolean shouldPerform(OptOptions options) { 150 return options.SSA_GCP; 151 } 152 153 //------------------------- Implementation ------------------------- 154 155 /** 156 * @param inst the instruction that might be moved 157 * @param ir the governing iR 158 * @return whether it is safe to move the given instruction, depending on 159 * the properties of the IR (is it in heapSSA form or not?) 160 */ 161 public static boolean shouldMove(Instruction inst, IR ir) { 162 if ((inst.isAllocation()) || inst.isDynamicLinkingPoint() || inst.getOpcode() >= ARCH_INDEPENDENT_END_opcode) { 163 return false; 164 } 165 166 if (ir.IRStage != IR.HIR && 167 ((inst.isPEI()) || inst.isThrow() || inst.isImplicitLoad() || inst.isImplicitStore())) { 168 return false; 169 } 170 171 switch (inst.getOpcode()) { 172 case INT_MOVE_opcode: 173 case LONG_MOVE_opcode: 174 case INT_COND_MOVE_opcode: 175 case LONG_COND_MOVE_opcode: 176 case FLOAT_COND_MOVE_opcode: 177 case DOUBLE_COND_MOVE_opcode: 178 case REF_COND_MOVE_opcode: 179 case PUTSTATIC_opcode: 180 case PUTFIELD_opcode: 181 case GETSTATIC_opcode: 182 case GETFIELD_opcode: 183 case INT_ALOAD_opcode: 184 case LONG_ALOAD_opcode: 185 case FLOAT_ALOAD_opcode: 186 case DOUBLE_ALOAD_opcode: 187 case REF_ALOAD_opcode: 188 case BYTE_ALOAD_opcode: 189 case UBYTE_ALOAD_opcode: 190 case SHORT_ALOAD_opcode: 191 case USHORT_ALOAD_opcode: 192 case INT_ASTORE_opcode: 193 case LONG_ASTORE_opcode: 194 case FLOAT_ASTORE_opcode: 195 case DOUBLE_ASTORE_opcode: 196 case REF_ASTORE_opcode: 197 case BYTE_ASTORE_opcode: 198 case SHORT_ASTORE_opcode: 199 case CHECKCAST_opcode: 200 case CHECKCAST_NOTNULL_opcode: 201 case CHECKCAST_UNRESOLVED_opcode: 202 case MUST_IMPLEMENT_INTERFACE_opcode: 203 case INSTANCEOF_opcode: 204 case INSTANCEOF_NOTNULL_opcode: 205 case INSTANCEOF_UNRESOLVED_opcode: 206 case PI_opcode: 207 case FLOAT_MOVE_opcode: 208 case DOUBLE_MOVE_opcode: 209 case REF_MOVE_opcode: 210 case GUARD_MOVE_opcode: 211 case GUARD_COMBINE_opcode: 212 case TRAP_IF_opcode: 213 case REF_ADD_opcode: 214 case INT_ADD_opcode: 215 case LONG_ADD_opcode: 216 case FLOAT_ADD_opcode: 217 case DOUBLE_ADD_opcode: 218 case REF_SUB_opcode: 219 case INT_SUB_opcode: 220 case LONG_SUB_opcode: 221 case FLOAT_SUB_opcode: 222 case DOUBLE_SUB_opcode: 223 case INT_MUL_opcode: 224 case LONG_MUL_opcode: 225 case FLOAT_MUL_opcode: 226 case DOUBLE_MUL_opcode: 227 case INT_DIV_opcode: 228 case LONG_DIV_opcode: 229 case FLOAT_DIV_opcode: 230 case DOUBLE_DIV_opcode: 231 case INT_REM_opcode: 232 case LONG_REM_opcode: 233 case FLOAT_REM_opcode: 234 case DOUBLE_REM_opcode: 235 case INT_NEG_opcode: 236 case LONG_NEG_opcode: 237 case FLOAT_NEG_opcode: 238 case DOUBLE_NEG_opcode: 239 case REF_SHL_opcode: 240 case INT_SHL_opcode: 241 case LONG_SHL_opcode: 242 case REF_SHR_opcode: 243 case INT_SHR_opcode: 244 case LONG_SHR_opcode: 245 case REF_USHR_opcode: 246 case INT_USHR_opcode: 247 case LONG_USHR_opcode: 248 case REF_AND_opcode: 249 case INT_AND_opcode: 250 case LONG_AND_opcode: 251 case REF_OR_opcode: 252 case INT_OR_opcode: 253 case LONG_OR_opcode: 254 case REF_XOR_opcode: 255 case INT_XOR_opcode: 256 case REF_NOT_opcode: 257 case INT_NOT_opcode: 258 case LONG_NOT_opcode: 259 case LONG_XOR_opcode: 260 case INT_2LONG_opcode: 261 case INT_2FLOAT_opcode: 262 case INT_2DOUBLE_opcode: 263 case INT_2ADDRSigExt_opcode: 264 case INT_2ADDRZerExt_opcode: 265 case LONG_2ADDR_opcode: 266 case ADDR_2INT_opcode: 267 case ADDR_2LONG_opcode: 268 case LONG_2INT_opcode: 269 case LONG_2FLOAT_opcode: 270 case LONG_2DOUBLE_opcode: 271 case FLOAT_2INT_opcode: 272 case FLOAT_2LONG_opcode: 273 case FLOAT_2DOUBLE_opcode: 274 case DOUBLE_2INT_opcode: 275 case DOUBLE_2LONG_opcode: 276 case DOUBLE_2FLOAT_opcode: 277 case INT_2BYTE_opcode: 278 case INT_2USHORT_opcode: 279 case INT_2SHORT_opcode: 280 case LONG_CMP_opcode: 281 case FLOAT_CMPL_opcode: 282 case FLOAT_CMPG_opcode: 283 case DOUBLE_CMPL_opcode: 284 case DOUBLE_CMPG_opcode: 285 case NULL_CHECK_opcode: 286 case BOUNDS_CHECK_opcode: 287 case INT_ZERO_CHECK_opcode: 288 case LONG_ZERO_CHECK_opcode: 289 case OBJARRAY_STORE_CHECK_opcode: 290 case OBJARRAY_STORE_CHECK_NOTNULL_opcode: 291 case BOOLEAN_NOT_opcode: 292 case BOOLEAN_CMP_INT_opcode: 293 case BOOLEAN_CMP_ADDR_opcode: 294 case FLOAT_AS_INT_BITS_opcode: 295 case INT_BITS_AS_FLOAT_opcode: 296 case DOUBLE_AS_LONG_BITS_opcode: 297 case LONG_BITS_AS_DOUBLE_opcode: 298 case ARRAYLENGTH_opcode: 299 case GET_OBJ_TIB_opcode: 300 case GET_CLASS_TIB_opcode: 301 case GET_TYPE_FROM_TIB_opcode: 302 case GET_SUPERCLASS_IDS_FROM_TIB_opcode: 303 case GET_DOES_IMPLEMENT_FROM_TIB_opcode: 304 case GET_ARRAY_ELEMENT_TIB_FROM_TIB_opcode: 305 return !(GCP.usesOrDefsPhysicalRegisterOrAddressType(inst)); 306 } 307 return false; 308 } 309 310 /** 311 * Schedule this instruction as early as possible 312 * @param inst the instruction to schedule 313 * @return the instruction that serves as the new lower bound (exclusive) 314 * for further scheduling 315 */ 316 private Instruction scheduleEarly(Instruction inst) { 317 Instruction _earlyPos; 318 319 if (getState(inst) >= early) return getEarlyPos(inst); 320 321 setState(inst, early); 322 setEarlyPos(inst, inst); 323 324 // already on outer level? 325 //if (ir.HIRInfo.LoopStructureTree.getLoopNestDepth(getBlock(inst)) == 0) 326 // return inst; 327 328 if (ir.options.FREQ_FOCUS_EFFORT && getOrigBlock(inst).getInfrequent()) { 329 return inst; 330 } 331 332 // explicitly INCLUDE instructions 333 if (!shouldMove(inst, ir)) { 334 return inst; 335 } 336 // dependencies via scalar operands 337 _earlyPos = scheduleScalarDefsEarly(inst.getUses(), ir.firstInstructionInCodeOrder(), inst); 338 if (VM.VerifyAssertions) VM._assert(_earlyPos != null); 339 340 // memory dependencies 341 if (ir.IRStage == IR.HIR) { 342 _earlyPos = scheduleHeapDefsEarly(ssad.getHeapUses(inst), _earlyPos, inst); 343 if (VM.VerifyAssertions) VM._assert(_earlyPos != null); 344 } 345 346 /* don't put memory stores or PEIs on speculative path */ 347 if ((inst.isPEI() && !ir.options.SSA_LICM_IGNORE_PEI) || inst.isImplicitStore()) { 348 while (!postDominates(getBlock(inst), getBlock(_earlyPos), ir)) { 349 _earlyPos = dominanceSuccessor(_earlyPos, inst); 350 } 351 } 352 353 setEarlyPos(inst, _earlyPos); 354 355 if (DEBUG && getBlock(_earlyPos) != getBlock(inst)) { 356 VM.sysWrite("new earlyBlock: " + getBlock(_earlyPos) + " for " + getBlock(inst) + ": " + inst + "\n"); 357 } 358 359 setBlock(inst, getBlock(_earlyPos)); 360 return _earlyPos; 361 } 362 363 BasicBlock scheduleLate(Instruction inst) { 364 if (DEBUG) VM.sysWrite("Schedule Late: " + inst + "\n"); 365 366 BasicBlock lateBlock = null; 367 int _state = getState(inst); 368 if (_state == late || _state == done) return getBlock(inst); 369 370 setState(inst, late); 371 372 if (ir.options.FREQ_FOCUS_EFFORT) { 373 BasicBlock _origBlock = getOrigBlock(inst); 374 if (_origBlock.getInfrequent()) { 375 return _origBlock; 376 } 377 } 378 379 // explicitly INCLUDE instructions 380 if (!shouldMove(inst, ir)) { 381 return getOrigBlock(inst); 382 } 383 384 // dependencies via scalar operands 385 lateBlock = scheduleScalarUsesLate(inst, lateBlock); 386 if (DEBUG) VM.sysWrite("lateBlock1: " + lateBlock + " for " + inst + "\n"); 387 388 // dependencies via heap operands 389 if (ir.IRStage == IR.HIR) { 390 lateBlock = scheduleHeapUsesLate(inst, lateBlock); 391 if (DEBUG) VM.sysWrite("lateBlock2: " + lateBlock + " for " + inst + "\n"); 392 } 393 394 // if there are no uses, this instruction is dead. 395 if (lateBlock == null) { 396 if (VERBOSE) VM.sysWrite("deleting " + inst + "\n"); 397 inst.remove(); 398 } else { 399 if (DEBUG && lateBlock != getOrigBlock(inst)) { 400 VM.sysWrite("new lateBlock: " + lateBlock + " for " + getOrigBlock(inst) + ": " + inst + "\n"); 401 } 402 403 BasicBlock to = upto(getEarlyPos(inst), lateBlock, inst); 404 if (to == null) { 405 lateBlock = getOrigBlock(inst); 406 } else { 407 if (VM.VerifyAssertions) VM._assert(getState(inst) != done); 408 lateBlock = to; 409 if (getOrigBlock(inst) != to) move(inst, to); 410 } 411 } 412 setState(inst, done); 413 setBlock(inst, lateBlock); 414 return lateBlock; 415 } 416 417 /** 418 * return `a's successor on the path from `a' to `b' in the dominator 419 * tree. `a' must dominate `b' and `a' and `b' must belong to 420 * different blocks. 421 * 422 * @param a an instruction matching the constraints from the description 423 * @param b another instruction matching the constraints from the description 424 * @return the dominance successor of a 425 */ 426 private Instruction dominanceSuccessor(Instruction a, Instruction b) { 427 BasicBlock aBlock = getBlock(a); 428 BasicBlock bBlock = getBlock(b); 429 430 if (VM.VerifyAssertions) { 431 VM._assert(aBlock != bBlock && dominator.dominates(aBlock, bBlock)); 432 } 433 434 BasicBlock last = null; 435 436 while (bBlock != aBlock) { 437 last = bBlock; 438 bBlock = dominator.getParent(bBlock); 439 } 440 return last.firstInstruction(); 441 } 442 443 /** 444 * Compares two instructions according to their depth in the dominator tree 445 * and return the one with the greatest depth. 446 * 447 * @param a an instruction 448 * @param b another instruction 449 * @return the instruction with the greatest depth in the dominator 450 * tree 451 */ 452 private Instruction maxDominatorDepth(Instruction a, Instruction b) { 453 BasicBlock aBlock = getBlock(a); 454 BasicBlock bBlock = getBlock(b); 455 int aDomDepth = dominator.depth(aBlock); 456 int bDomDepth = dominator.depth(bBlock); 457 458 if (aDomDepth > bDomDepth) return a; 459 if (aDomDepth < bDomDepth) return b; 460 461 if (VM.VerifyAssertions) VM._assert(aBlock == bBlock); 462 463 // if an instruction depends on a branch, it can not be placed in 464 // this block. Make sure we record this fact. We use this 465 // information in upto() 466 return a.isBranch() ? a : b; 467 } 468 469 private BasicBlock commonDominator(BasicBlock a, BasicBlock b) { 470 //VM.sysWrite ("CD: "+a+", "+b); 471 if (a == null) return b; 472 if (b == null) return a; 473 474 while (a != b) { 475 int aDomDepth = dominator.depth(a); 476 int bDomDepth = dominator.depth(b); 477 if (aDomDepth >= bDomDepth) a = dominator.getParent(a); 478 if (bDomDepth >= aDomDepth) b = dominator.getParent(b); 479 } 480 //VM.sysWrite (" = "+a+"\n"); 481 return a; 482 } 483 484 /** 485 * Schedules an instruction as early as possible, 486 * but behind the definitions in e and behind earlyPos 487 * 488 * @param e the definitions that must have been occurred before the new 489 * position of the instruction 490 * @param earlyPos the instruction that serves as a lower bound (exclusive) 491 * for the position 492 * @param inst the instruction to schedule 493 * @return the instruction that serves as the new lower bound (exclusive) 494 * for further scheduling 495 */ 496 private Instruction scheduleScalarDefsEarly(Enumeration<Operand> e, Instruction earlyPos, 497 Instruction inst) { 498 while (e.hasMoreElements()) { 499 Operand op = e.nextElement(); 500 Instruction def = definingInstruction(op); 501 502 scheduleEarly(def); 503 504 if (def.isBranch()) def = dominanceSuccessor(def, inst); 505 506 earlyPos = maxDominatorDepth(def, earlyPos); 507 } 508 return earlyPos; 509 } 510 511 /** 512 * Schedules an instruction as early as possible, 513 * but behind the definitions of op[i] and behind earlyPos. 514 * 515 * @param op the definitions that must have been occurred before the new 516 * position of the instruction 517 * @param earlyPos the instruction that serves as a lower bound (exclusive) 518 * for the position 519 * @param me the instruction to schedule 520 * @return the instruction that serves as the new lower bound (exclusive) 521 * for further scheduling 522 */ 523 Instruction scheduleHeapDefsEarly(HeapOperand<?>[] op, Instruction earlyPos, Instruction me) { 524 if (op == null) return earlyPos; 525 526 for (HeapOperand<?> anOp : op) { 527 Instruction def = definingInstruction(anOp); 528 529 // if (me.isImplicitLoad() || me.isImplicitStore()) 530// def = _getRealDef(def, me) 531// ; 532// else if (me.isPEI()) 533// def = _getRealExceptionDef(def) 534 // ; 535 536 if (VM.VerifyAssertions) VM._assert(def != null); 537 earlyPos = maxDominatorDepth(scheduleEarly(def), earlyPos); 538 } 539 return earlyPos; 540 } 541 542 BasicBlock useBlock(Instruction use, Operand op) { 543 //VM.sysWrite ("UseBlock: "+use+"\n"); 544 BasicBlock res = scheduleLate(use); 545 if (res != null && Phi.conforms(use)) { 546 int i; 547 for (i = Phi.getNumberOfValues(use) - 1; i >= 0; --i) { 548 if (Phi.getValue(use, i) == op) { 549 res = Phi.getPred(use, i).block; 550 break; 551 } 552 } 553 if (VM.VerifyAssertions) VM._assert(i >= 0); 554 } 555 return res; 556 } 557 558 private BasicBlock scheduleScalarUsesLate(Instruction inst, BasicBlock lateBlock) { 559 Operand resOp = getResult(inst); 560 561 if (resOp == null || !(resOp instanceof RegisterOperand)) { 562 return lateBlock; 563 } 564 565 Register res = ((RegisterOperand) resOp).getRegister(); 566 Enumeration<RegisterOperand> e = DefUse.uses(res); 567 568 while (e.hasMoreElements()) { 569 Operand op = e.nextElement(); 570 Instruction use = op.instruction; 571 BasicBlock _block = useBlock(use, op); 572 lateBlock = commonDominator(_block, lateBlock); 573 } 574 return lateBlock; 575 } 576 577 BasicBlock scheduleHeapUsesLate(Instruction inst, BasicBlock lateBlock) { 578 //VM.sysWrite (" scheduleHeapUsesLate\n"); 579 Operand[] defs = ssad.getHeapDefs(inst); 580 if (defs == null) return lateBlock; 581 582 //VM.sysWrite (" defs: "+defs.length+"\n"); 583 for (Operand def : defs) { 584 @SuppressWarnings("unchecked") // Cast to generic HeapOperand 585 HeapOperand<Object> dhop = (HeapOperand) def; 586 HeapVariable<Object> H = dhop.value; 587 if (DEBUG) VM.sysWrite("H: " + H + "\n"); 588 Iterator<HeapOperand<Object>> it = ssad.iterateHeapUses(H); 589 //VM.sysWrite (" H: "+H+" ("+ssad.getNumberOfUses (H)+")\n"); 590 while (it.hasNext()) { 591 HeapOperand<Object> uhop = it.next(); 592 //VM.sysWrite (" uhop: "+uhop+"\n"); 593 Instruction use = uhop.instruction; 594 //VM.sysWrite ("use: "+use+"\n"); 595 BasicBlock _block = useBlock(use, uhop); 596 lateBlock = commonDominator(_block, lateBlock); 597 } 598 } 599 return lateBlock; 600 } 601 602 /** 603 * @param op the operand that's being defined 604 * @return the instruction that defines the operand. 605 */ 606 Instruction definingInstruction(Operand op) { 607 if (op instanceof HeapOperand) { 608 @SuppressWarnings("unchecked") // Cast to generic HeapOperand 609 HeapOperand<Object> hop = (HeapOperand) op; 610 HeapVariable<Object> H = hop.value; 611 HeapOperand<Object> defiOp = ssad.getUniqueDef(H); 612 // Variable may be defined by caller, so depends on method entry 613 if (defiOp == null || defiOp.instruction == null) { 614 return ir.firstInstructionInCodeOrder(); 615 } else { 616 //VM.sysWrite ("def of "+op+" is "+defiOp.instruction+"\n"); 617 return defiOp.instruction; 618 } 619 } else if (op instanceof RegisterOperand) { 620 Register reg = ((RegisterOperand) op).getRegister(); 621 Enumeration<RegisterOperand> defs = DefUse.defs(reg); 622 if (!defs.hasMoreElements()) { // params have no def 623 return ir.firstInstructionInCodeOrder(); 624 } else { 625 Instruction def = defs.nextElement().instruction; 626 // we are in SSA, so there is at most one definition. 627 if (VM.VerifyAssertions) VM._assert(!defs.hasMoreElements()); 628 //if (defs.hasMoreElements()) { 629 // VM.sysWrite("GCP: multiple defs: " + reg + "\n"); 630 // return null; 631 //} 632 return def; 633 } 634 } else { // some constant 635 return ir.firstInstructionInCodeOrder(); 636 } 637 } 638 639 /** 640 * @param inst an instruction 641 * @return the result operand of the instruction 642 */ 643 Operand getResult(Instruction inst) { 644 if (ResultCarrier.conforms(inst)) { 645 return ResultCarrier.getResult(inst); 646 } 647 if (GuardResultCarrier.conforms(inst)) { 648 return GuardResultCarrier.getGuardResult(inst); 649 } 650 if (Phi.conforms(inst)) { 651 return Phi.getResult(inst); 652 } 653 return null; 654 } 655 656 /** 657 * Visits the blocks between the late and the early position along 658 * their path in the dominator tree. 659 * 660 * @param earlyPos the early position 661 * @param lateBlock the late position 662 * @param inst the instruction to schedule 663 * @return the block with the smallest execution costs 664 */ 665 BasicBlock upto(Instruction earlyPos, BasicBlock lateBlock, Instruction inst) { 666 667 BasicBlock _origBlock = getOrigBlock(inst); 668 BasicBlock actBlock = lateBlock; 669 BasicBlock bestBlock = lateBlock; 670 BasicBlock earlyBlock = getBlock(earlyPos); 671 672 if (VM.VerifyAssertions) { 673 if (!dominator.dominates(earlyBlock.getNumber(), _origBlock.getNumber()) || 674 !dominator.dominates(earlyBlock.getNumber(), lateBlock.getNumber())) { 675 SSA.printInstructions(ir); 676 VM.sysWrite("> " + 677 earlyBlock.getNumber() + 678 ", " + 679 _origBlock.getNumber() + 680 ", " + 681 lateBlock.getNumber() + 682 "\n"); 683 VM.sysWrite("" + inst + "\n"); 684 } 685 VM._assert(dominator.dominates(earlyBlock.getNumber(), _origBlock.getNumber())); 686 VM._assert(dominator.dominates(earlyBlock.getNumber(), lateBlock.getNumber())); 687 } 688 for (; ;) { 689 /* is the actual block better (less frequent) 690 than the so far best block? */ 691 if (frequency(actBlock) < frequency(bestBlock)) { 692 if (DEBUG) { 693 VM.sysWrite("going from " + frequency(_origBlock) + " to " + frequency(actBlock) + "\n"); 694 } 695 bestBlock = actBlock; 696 } 697 /* all candidates checked? */ 698 if (actBlock == earlyBlock) { 699 break; 700 } 701 702 /* walk up the dominator tree for next candidate*/ 703 actBlock = dominator.getParent(actBlock); 704 } 705 if (bestBlock == _origBlock) return null; 706 if (DEBUG) VM.sysWrite("best Block: " + bestBlock + "\n"); 707 return bestBlock; 708 } 709 710 /** 711 * Determines how expensive it is to place an instruction in this block. 712 * 713 * @param b a basic block 714 * @return the block's execution frequency 715 */ 716 final float frequency(BasicBlock b) { 717 return b.getExecutionFrequency(); 718 } 719 720 void move(Instruction inst, BasicBlock to) { 721 722 BasicBlock _origBlock = getOrigBlock(inst); 723 Instruction cand = null; 724 725 /* find a position within bestBlock */ 726 if (dominator.dominates(_origBlock.getNumber(), to.getNumber())) { 727 // moved down, so insert in from 728 Instruction last = null; 729 Enumeration<Instruction> e = to.forwardInstrEnumerator(); 730 while (e.hasMoreElements()) { 731 cand = e.nextElement(); 732 if (DEBUG) VM.sysWrite(cand.toString() + "\n"); 733 // skip labels, phis, and yieldpoints 734 if (!Label.conforms(cand) && !cand.isYieldPoint() && !Phi.conforms(cand)) { 735 break; 736 } 737 last = cand; 738 } 739 cand = last; 740 } else { 741 // moved up, so insert at end of block 742 Enumeration<Instruction> e = to.reverseInstrEnumerator(); 743 while (e.hasMoreElements()) { 744 cand = e.nextElement(); 745 if (DEBUG) VM.sysWrite(cand.toString() + "\n"); 746 // skip branches and newly placed insts 747 if (!BBend.conforms(cand) && !cand.isBranch() && !relocated.contains(cand)) { 748 break; 749 } 750 } 751 if (DEBUG) VM.sysWrite("Adding to relocated: " + inst + "\n"); 752 relocated.add(inst); 753 } 754 755 if (DEBUG && moved.add(inst.operator())) { 756 VM.sysWrite("m(" + (ir.IRStage == IR.LIR ? "l" : "h") + ") " + inst.operator() + "\n"); 757 } 758 if (VERBOSE) { 759 VM.sysWrite(ir.IRStage == IR.LIR ? "%" : "#"); 760 VM.sysWrite(" moving " + inst + " from " + _origBlock + " to " + to + "\n" + "behind " + cand + "\n"); 761 762 } 763 inst.remove(); 764 cand.insertAfter(inst); 765 } 766 767 //------------------------------------------------------------ 768 // some helper methods 769 //------------------------------------------------------------ 770 771 /** 772 * does a post dominate b? 773 * @param a the possible post-dominator 774 * @param b the possibly post-dominated block 775 * @param ir the IR that contains the blocks 776 * @return whether the first block post-dominates the second block 777 */ 778 boolean postDominates(BasicBlock a, BasicBlock b, IR ir) { 779 boolean res; 780 if (a == b) { 781 return true; 782 } 783 //VM.sysWrite ("does " + a + " postdominate " + b + "?: "); 784 DominatorInfo info = ir.getDominators().getDominatorInfo(b); 785 res = info.isDominatedBy(a); 786 //VM.sysWrite (res ? "yes\n" : "no\n"); 787 return res; 788 } 789 790 BasicBlock getBlock(Instruction inst) { 791 return block[instructionNumbers.get(inst)]; 792 } 793 794 void setBlock(Instruction inst, BasicBlock b) { 795 block[instructionNumbers.get(inst)] = b; 796 } 797 798 Instruction getEarlyPos(Instruction inst) { 799 return earlyPos[instructionNumbers.get(inst)]; 800 } 801 802 void setEarlyPos(Instruction inst, Instruction pos) { 803 earlyPos[instructionNumbers.get(inst)] = pos; 804 } 805 806 BasicBlock getOrigBlock(Instruction inst) { 807 return origBlock[instructionNumbers.get(inst)]; 808 } 809 810 void setOrigBlock(Instruction inst, BasicBlock b) { 811 origBlock[instructionNumbers.get(inst)] = b; 812 } 813 814 /** 815 * In what state (initial, early, late, done) is this instruction 816 * @param inst the instruction to check 817 * @return the instruction's state 818 */ 819 int getState(Instruction inst) { 820 return state[instructionNumbers.get(inst)]; 821 } 822 823 /** 824 * Set the state (initial, early, late, done) of the instruction 825 * @param inst the instruction 826 * @param s the state 827 */ 828 void setState(Instruction inst, int s) { 829 state[instructionNumbers.get(inst)] = s; 830 } 831 832 //------------------------------------------------------------ 833 // initialization 834 //------------------------------------------------------------ 835 836 void initialize(IR ir) { 837 this.ir = ir; 838 839 relocated = new HashSet<Instruction>(); 840 // Note: the following unfactors the CFG 841 new DominatorsPhase(true).perform(ir); 842 Dominators dominators = new Dominators(); 843 dominators.computeApproxPostdominators(ir); 844 ir.setDominators(dominators); 845 dominator = ir.HIRInfo.dominatorTree; 846 if (DEBUG) VM.sysWrite("" + dominator.toString() + "\n"); 847 848 instructionNumbers = ir.numberInstructionsViaMap(); 849 int instructions = instructionNumbers.size(); 850 851 ssad = ir.HIRInfo.dictionary; 852 DefUse.computeDU(ir); 853 ssad.recomputeArrayDU(); 854 855 // also number implicit heap phis 856 Enumeration<BasicBlock> e = ir.getBasicBlocks(); 857 while (e.hasMoreElements()) { 858 BasicBlock b = e.nextElement(); 859 Iterator<Instruction> pe = ssad.getHeapPhiInstructions(b); 860 while (pe.hasNext()) { 861 Instruction inst = pe.next(); 862 instructionNumbers.put(inst, Integer.valueOf(instructions++)); 863 } 864 } 865 state = new int[instructions]; 866 origBlock = new BasicBlock[instructions]; 867 block = new BasicBlock[instructions]; 868 earlyPos = new Instruction[instructions]; 869 e = ir.getBasicBlocks(); 870 while (e.hasMoreElements()) { 871 BasicBlock b = e.nextElement(); 872 Enumeration<Instruction> ie = ssad.getAllInstructions(b); 873 while (ie.hasMoreElements()) { 874 Instruction inst = ie.nextElement(); 875 setBlock(inst, b); 876 setOrigBlock(inst, b); 877 setState(inst, initial); 878 } 879 } 880 if (ir.IRStage == IR.HIR) { 881 e = ir.getBasicBlocks(); 882 while (e.hasMoreElements()) { 883 BasicBlock b = e.nextElement(); 884 885 if (ir.options.FREQ_FOCUS_EFFORT && b.getInfrequent()) continue; 886 887 Enumeration<Instruction> ie = ssad.getAllInstructions(b); 888 while (ie.hasMoreElements()) { 889 Instruction inst = ie.nextElement(); 890 while (simplify(inst, b)) ; 891 } 892 } 893 ssad.recomputeArrayDU(); 894 } 895 } 896 897 //------------------------------------------------------------ 898 // private state 899 //------------------------------------------------------------ 900 private static final int initial = 0; 901 private static final int early = 1; 902 private static final int late = 2; 903 private static final int done = 3; 904 905 private HashSet<Instruction> relocated; 906 907 private int[] state; 908 private BasicBlock[] block; 909 private BasicBlock[] origBlock; 910 private Instruction[] earlyPos; 911 private SSADictionary ssad; 912 private DominatorTree dominator; 913 private IR ir; 914 private final HashSet<Operator> moved = DEBUG ? new HashSet<Operator>() : null; 915 916 private boolean simplify(Instruction inst, BasicBlock block) { 917 if (!Phi.conforms(inst)) return false; // no phi 918 919 //if (Phi.getNumberOfValues (inst) != 2) return false; // want exactly 2 inputs 920 921 //VM.sysWrite ("Simplify "+inst+"\n"); 922 923 Operand resOp = Phi.getResult(inst); 924 925 if (!(resOp instanceof HeapOperand)) { 926 //VM.sysWrite (" no heap op result\n"); 927 return false; // scalar phi 928 } 929 930 int xidx = -1; 931 Instruction x = null; 932 933 for (int i = Phi.getNumberOfValues(inst) - 1; i >= 0; --i) { 934 Instruction in = definingInstruction(Phi.getValue(inst, i)); 935 if (getOrigBlock(in) != getOrigBlock(inst) && dominator.dominates(getOrigBlock(in), getOrigBlock(inst))) { 936 if (xidx != -1) return false; 937 xidx = i; 938 x = in; 939 } else if (!dominator.dominates(getOrigBlock(inst), getOrigBlock(in))) { 940 return false; 941 } 942 } 943 if (x == null) return false; 944 945 replaceUses(inst, (HeapOperand<?>) Phi.getValue(inst, xidx), Phi.getPred(inst, xidx), true); 946 947 @SuppressWarnings("unchecked") // Cast to generic HeapOperand 948 HeapOperand<Object> hop = (HeapOperand) resOp; 949 if (hop.value.isExceptionHeapType()) return false; 950 951 /* check that inside the loop, the heap variable is only used/defed 952 by simple, non-volatile loads or only by stores 953 954 if so, replace uses of inst (a memory phi) with its dominating input 955 */ 956 int type = checkLoop(inst, hop, xidx, block); 957 if (type == CL_LOADS_ONLY || type == CL_STORES_ONLY || type == CL_NONE) { 958 replaceUses(inst, (HeapOperand<?>) Phi.getValue(inst, xidx), Phi.getPred(inst, xidx), false); 959 } 960 return false; 961 } 962 963 static final int CL_NONE = 0; 964 static final int CL_LOADS_ONLY = 1; 965 static final int CL_STORES_ONLY = 2; 966 static final int CL_LOADS_AND_STORES = 3; 967 static final int CL_COMPLEX = 4; 968 969 /* 970 * check that inside the loop, the heap variable is only used/defed 971 * by simple, non-volatile loads/stores<p> 972 * 973 * returns one of: 974 * CL_LOADS_ONLY, CL_STORES_ONLY, CL_LOADS_AND_STORES, CL_COMPLEX 975 */ 976 @SuppressWarnings("unused") 977 // useful for debugging 978 private int _checkLoop(Instruction inst, HeapOperand<?> hop, int xidx) { 979 for (int i = Phi.getNumberOfValues(inst) - 1; i >= 0; --i) { 980 if (i == xidx) continue; 981 Instruction y = definingInstruction(Phi.getValue(inst, i)); 982 while (y != inst) { 983 //VM.sysWrite (" y: "+y+"\n"); 984 if (y.isImplicitStore() || y.isPEI() || !LocationCarrier.conforms(y)) { 985 return CL_COMPLEX; 986 } 987 988 // check for access to volatile field 989 LocationOperand loc = LocationCarrier.getLocation(y); 990 if (loc == null || loc.mayBeVolatile()) { 991 //VM.sysWrite (" no loc or volatile field\n"); 992 return CL_COMPLEX; 993 } 994 for (HeapOperand<?> op : ssad.getHeapUses(y)) { 995 if (op.value.isExceptionHeapType()) continue; 996 if (op.getHeapType() != hop.getHeapType()) return CL_COMPLEX; 997 y = definingInstruction(op); 998 } 999 } 1000 } 1001 return CL_LOADS_ONLY; 1002 } 1003 1004 /* 1005 * TODO document xidx parameter and turn this comment into proper JavaDoc. 1006 * <p> 1007 * Checks that inside the loop, the heap variable is only used/defed 1008 * by simple, non-volatile loads/stores 1009 * 1010 * @param inst a phi instruction 1011 * @param hop the result operand of the phi instruction 1012 * @param xidx 1013 * @param block the block that contains the phi instruction 1014 * 1015 * @return one of {@link #CL_LOADS_ONLY}, {@link #CL_STORES_ONLY}, 1016 * {@link #CL_LOADS_AND_STORES}, {@link #CL_COMPLEX} 1017 */ 1018 private int checkLoop(Instruction inst, HeapOperand<Object> hop, int xidx, BasicBlock block) { 1019 HashSet<Instruction> seen = new HashSet<Instruction>(); 1020 Queue<Instruction> workList = new Queue<Instruction>(); 1021 int _state = CL_NONE; 1022 int instUses = 0; 1023 1024 seen.add(inst); 1025 for (int i = Phi.getNumberOfValues(inst) - 1; i >= 0; --i) { 1026 if (i == xidx) continue; 1027 Instruction y = definingInstruction(Phi.getValue(inst, i)); 1028 if (y == inst) instUses++; 1029 if (!(seen.contains(y))) { 1030 seen.add(y); 1031 workList.insert(y); 1032 } 1033 } 1034 1035 while (!(workList.isEmpty())) { 1036 Instruction y = workList.remove(); 1037 if (Phi.conforms(y)) { 1038 for (int i = Phi.getNumberOfValues(y) - 1; i >= 0; --i) { 1039 Instruction z = definingInstruction(Phi.getValue(y, i)); 1040 if (z == inst) instUses++; 1041 if (!(seen.contains(z))) { 1042 seen.add(z); 1043 workList.insert(z); 1044 } 1045 } 1046 } else if ((y.isPEI()) || !LocationCarrier.conforms(y) || y.operator().isAcquire() || y.operator().isRelease()) { 1047 return CL_COMPLEX; 1048 } else { 1049 // check for access to volatile field 1050 LocationOperand loc = LocationCarrier.getLocation(y); 1051 if (loc == null || loc.mayBeVolatile()) { 1052 //VM.sysWrite (" no loc or volatile field\n"); 1053 return CL_COMPLEX; 1054 } 1055 if (y.isImplicitStore()) { 1056 // only accept loop-invariant stores 1057 // conservatively estimate loop-invariance by header domination 1058 if (!inVariantLocation(y, block)) return CL_COMPLEX; 1059 _state |= CL_STORES_ONLY; 1060 } else { 1061 _state |= CL_LOADS_ONLY; 1062 } 1063 for (HeapOperand<?> op : ssad.getHeapUses(y)) { 1064 if (op.value.isExceptionHeapType()) continue; 1065 if (op.getHeapType() != hop.getHeapType()) return CL_COMPLEX; 1066 y = definingInstruction(op); 1067 if (y == inst) instUses++; 1068 if (!(seen.contains(y))) { 1069 seen.add(y); 1070 workList.insert(y); 1071 } 1072 } 1073 } 1074 } 1075 if (_state == CL_STORES_ONLY && ssad.getNumberOfUses(hop.value) != instUses) { 1076 return CL_COMPLEX; 1077 } 1078 1079 return _state; 1080 } 1081 1082 private boolean inVariantLocation(Instruction inst, BasicBlock block) { 1083 if (PutStatic.conforms(inst)) return true; 1084 if (PutField.conforms(inst)) { 1085 return useDominates(PutField.getRef(inst), block); 1086 } 1087 if (AStore.conforms(inst)) { 1088 return ((useDominates(AStore.getArray(inst), block)) && useDominates(AStore.getIndex(inst), block)); 1089 } 1090 if (VM.VerifyAssertions) { 1091 String msg = "inst does not conform to PutStatic, Putfield or AStore: " + inst; 1092 VM._assert(VM.NOT_REACHED, msg); 1093 } 1094 return false; 1095 } 1096 1097 private boolean useDominates(Operand op, BasicBlock block) { 1098 if (!(op instanceof RegisterOperand)) return true; 1099 Instruction inst = definingInstruction(op); 1100 BasicBlock b = getOrigBlock(inst); 1101 return b != block && dominator.dominates(b, block); 1102 } 1103 1104 /* 1105 * In the consumers of `inst', replace uses of `inst's result 1106 * with uses of `replacement' 1107 */ 1108 private boolean replaceUses(Instruction inst, HeapOperand<?> replacement, 1109 BasicBlockOperand replacementBlock, boolean onlyPEIs) { 1110 if (VM.VerifyAssertions) VM._assert(Phi.conforms(inst)); 1111 1112 boolean changed = false; 1113 @SuppressWarnings("unchecked") // Cast to generic HeapOperand 1114 HeapOperand<Object> hop = (HeapOperand) Phi.getResult(inst); 1115 HeapVariable<Object> H = hop.value; 1116 Iterator<HeapOperand<Object>> it = ssad.iterateHeapUses(H); 1117 while (it.hasNext()) { 1118 hop = it.next(); 1119 Instruction user = hop.instruction; 1120 if (onlyPEIs && !user.isPEI()) continue; 1121 1122 if (Phi.conforms(user)) { 1123 for (int i = 0; i < Phi.getNumberOfValues(user); i++) { 1124 if (Phi.getValue(user, i) == hop) { 1125 Phi.setValue(user, i, replacement.copy()); 1126 Phi.setPred(user, i, (BasicBlockOperand) replacementBlock.copy()); 1127 } 1128 } 1129 changed |= replacement.value != H; 1130 } else { 1131 HeapOperand<?>[] uses = ssad.getHeapUses(user); 1132 for (int i = uses.length - 1; i >= 0; --i) { 1133 if (uses[i].value == H) { 1134 changed |= replacement.value != H; 1135 uses[i] = replacement.copy(); 1136 uses[i].setInstruction(user); 1137 } 1138 } 1139 } 1140 if (DEBUG && changed) { 1141 VM.sysWrite(" changing dependency of " + user + "\n" + "from " + H + " to " + replacement + "\n"); 1142 } 1143 } 1144 if (!onlyPEIs) { 1145 for (int i = Phi.getNumberOfValues(inst) - 1; i >= 0; --i) { 1146 Phi.setValue(inst, i, replacement.copy()); 1147 } 1148 } 1149 return changed; 1150 } 1151 1152 private void resetLandingPads() { 1153 Enumeration<BasicBlock> e = ir.getBasicBlocks(); 1154 while (e.hasMoreElements()) e.nextElement().clearLandingPad(); 1155 } 1156}