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