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}