001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.compilers.opt;
014
015import static org.jikesrvm.compilers.opt.driver.OptConstants.NO;
016import static org.jikesrvm.compilers.opt.driver.OptConstants.YES;
017import static org.jikesrvm.compilers.opt.ir.Operators.*;
018import static org.jikesrvm.runtime.JavaSizeConstants.BITS_IN_INT;
019import static org.jikesrvm.runtime.JavaSizeConstants.BITS_IN_LONG;
020import static org.jikesrvm.runtime.UnboxedSizeConstants.BITS_IN_ADDRESS;
021import static org.jikesrvm.runtime.UnboxedSizeConstants.LOG_BYTES_IN_ADDRESS;
022
023import java.lang.reflect.Array;
024import java.lang.reflect.Method;
025
026import org.jikesrvm.VM;
027import org.jikesrvm.classloader.RVMField;
028import org.jikesrvm.classloader.RVMMethod;
029import org.jikesrvm.classloader.RVMType;
030import org.jikesrvm.classloader.TypeReference;
031import org.jikesrvm.compilers.common.CodeArray;
032import org.jikesrvm.compilers.opt.inlining.InlineSequence;
033import org.jikesrvm.compilers.opt.ir.AbstractRegisterPool;
034import org.jikesrvm.compilers.opt.ir.Binary;
035import org.jikesrvm.compilers.opt.ir.BooleanCmp;
036import org.jikesrvm.compilers.opt.ir.BoundsCheck;
037import org.jikesrvm.compilers.opt.ir.Call;
038import org.jikesrvm.compilers.opt.ir.CondMove;
039import org.jikesrvm.compilers.opt.ir.Empty;
040import org.jikesrvm.compilers.opt.ir.GetField;
041import org.jikesrvm.compilers.opt.ir.GuardedBinary;
042import org.jikesrvm.compilers.opt.ir.GuardedUnary;
043import org.jikesrvm.compilers.opt.ir.IRTools;
044import org.jikesrvm.compilers.opt.ir.InstanceOf;
045import org.jikesrvm.compilers.opt.ir.Instruction;
046import org.jikesrvm.compilers.opt.ir.Load;
047import org.jikesrvm.compilers.opt.ir.Move;
048import org.jikesrvm.compilers.opt.ir.NullCheck;
049import org.jikesrvm.compilers.opt.ir.Operator;
050import org.jikesrvm.compilers.opt.ir.StoreCheck;
051import org.jikesrvm.compilers.opt.ir.Trap;
052import org.jikesrvm.compilers.opt.ir.TrapIf;
053import org.jikesrvm.compilers.opt.ir.TypeCheck;
054import org.jikesrvm.compilers.opt.ir.Unary;
055import org.jikesrvm.compilers.opt.ir.ZeroCheck;
056import org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand;
057import org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand;
058import org.jikesrvm.compilers.opt.ir.operand.CodeConstantOperand;
059import org.jikesrvm.compilers.opt.ir.operand.ConditionOperand;
060import org.jikesrvm.compilers.opt.ir.operand.ConstantOperand;
061import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand;
062import org.jikesrvm.compilers.opt.ir.operand.LongConstantOperand;
063import org.jikesrvm.compilers.opt.ir.operand.MethodOperand;
064import org.jikesrvm.compilers.opt.ir.operand.NullConstantOperand;
065import org.jikesrvm.compilers.opt.ir.operand.ObjectConstantOperand;
066import org.jikesrvm.compilers.opt.ir.operand.Operand;
067import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
068import org.jikesrvm.compilers.opt.ir.operand.TIBConstantOperand;
069import org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand;
070import org.jikesrvm.compilers.opt.ir.operand.TrueGuardOperand;
071import org.jikesrvm.compilers.opt.ir.operand.TypeOperand;
072import org.jikesrvm.compilers.opt.ir.operand.UnreachableOperand;
073import org.jikesrvm.objectmodel.TIB;
074import org.jikesrvm.runtime.Entrypoints;
075import org.jikesrvm.runtime.Magic;
076import org.jikesrvm.runtime.Reflection;
077import org.vmmagic.unboxed.Address;
078import org.vmmagic.unboxed.Offset;
079import org.vmmagic.unboxed.Word;
080
081/**
082 * A constant folder, strength reducer and axiomatic simplifier.
083 *
084 * <p> This module performs no analysis, it simply attempts to
085 * simplify the instruction as is. The intent is that
086 * analysis modules can call this transformation engine, allowing us to
087 * share the tedious simplification code among multiple analysis modules.
088 *
089 * <p> NOTE: For maintainability purposes, I've intentionally avoided being
090 * clever about combining 'similar' operators together into a combined case
091 * of the main switch switch statement. Also, operators are in sorted ordered
092 * within each major grouping.  Please maintain this coding style.
093 * I'd rather have this module be 2000 lines of obviously correct code than
094 * 500 lines of clever code.
095 */
096public abstract class Simplifier extends IRTools {
097  /**
098   * Effect of the simplification on Def-Use chains
099   */
100  public enum DefUseEffect {
101    /**
102     * Enumeration value to indicate an operation is unchanged,
103     * although the order of operands may have been canonicalized and
104     * type information strengthened.
105     */
106    UNCHANGED,
107    /**
108     * Enumeration value to indicate an operation has been replaced by
109     * a move instruction with a constant right hand side.
110     */
111    MOVE_FOLDED,
112    /**
113     * Enumeration value to indicate an operation has been replaced by
114     * a move instruction with a non-constant right hand side.
115     */
116    MOVE_REDUCED,
117    /**
118     * Enumeration value to indicate an operation has been replaced by
119     * an unconditional trap instruction.
120     */
121    TRAP_REDUCED,
122    /**
123     * Enumeration value to indicate an operation has been replaced by
124     * a cheaper, but non-move instruction.
125     */
126    REDUCED
127  }
128
129  /**
130   * Given an instruction, attempt to simplify it.
131   * The instruction will be mutated in place.
132   *
133   * <p> We don't deal with branching operations here --
134   * doing peephole optimizations of branches
135   * is the job of a separate module.
136   *
137   * @param hir is this the HIR phase?
138   * @param regpool register pool in case simplification requires a temporary register
139   * @param opts options for this compilation
140   * @param s the instruction to simplify
141   * @return one of UNCHANGED, MOVE_FOLDED, MOVE_REDUCED, TRAP_REDUCED, REDUCED
142   */
143  public static DefUseEffect simplify(boolean hir, AbstractRegisterPool regpool, OptOptions opts, Instruction s) {
144    DefUseEffect result;
145    char opcode = s.getOpcode();
146    switch (opcode) {
147      ////////////////////
148      // GUARD operations
149      ////////////////////
150      case GUARD_COMBINE_opcode:
151        result = guardCombine(s, opts);
152        break;
153        ////////////////////
154        // TRAP operations
155        ////////////////////
156      case TRAP_IF_opcode:
157        result = trapIf(s, opts);
158        break;
159      case NULL_CHECK_opcode:
160        result = nullCheck(s, opts);
161        break;
162      case INT_ZERO_CHECK_opcode:
163        result = intZeroCheck(s, opts);
164        break;
165      case LONG_ZERO_CHECK_opcode:
166        result = longZeroCheck(s, opts);
167        break;
168      case CHECKCAST_opcode:
169        result = checkcast(s, opts);
170        break;
171      case CHECKCAST_UNRESOLVED_opcode:
172        result = checkcast(s, opts);
173        break;
174      case CHECKCAST_NOTNULL_opcode:
175        result = checkcastNotNull(s, opts);
176        break;
177      case INSTANCEOF_opcode:
178        result = instanceOf(s, opts);
179        break;
180      case INSTANCEOF_NOTNULL_opcode:
181        result = instanceOfNotNull(s, opts);
182        break;
183      case OBJARRAY_STORE_CHECK_opcode:
184        result = objarrayStoreCheck(s, opts);
185        break;
186      case OBJARRAY_STORE_CHECK_NOTNULL_opcode:
187        result = objarrayStoreCheckNotNull(s, opts);
188        break;
189      case MUST_IMPLEMENT_INTERFACE_opcode:
190        result = mustImplementInterface(s, opts);
191        break;
192        ////////////////////
193        // Conditional moves
194        ////////////////////
195      case INT_COND_MOVE_opcode:
196        result = intCondMove(s, opts);
197        break;
198      case LONG_COND_MOVE_opcode:
199        result = longCondMove(s, opts);
200        break;
201      case FLOAT_COND_MOVE_opcode:
202        result = floatCondMove(s, opts);
203        break;
204      case DOUBLE_COND_MOVE_opcode:
205        result = doubleCondMove(s, opts);
206        break;
207      case REF_COND_MOVE_opcode:
208        result = refCondMove(s, opts);
209        break;
210      case GUARD_COND_MOVE_opcode:
211        result = guardCondMove(s, opts);
212        break;
213        ////////////////////
214        // INT ALU operations
215        ////////////////////
216      case BOOLEAN_NOT_opcode:
217        result = booleanNot(s, opts);
218        break;
219      case BOOLEAN_CMP_INT_opcode:
220        result = booleanCmpInt(s, opts);
221        break;
222      case BOOLEAN_CMP_ADDR_opcode:
223        result = booleanCmpAddr(s, opts);
224        break;
225      case INT_ADD_opcode:
226        result = intAdd(s, opts);
227        break;
228      case INT_AND_opcode:
229        result = intAnd(s, opts);
230        break;
231      case INT_DIV_opcode:
232        result = intDiv(regpool, s, opts);
233        break;
234      case INT_MUL_opcode:
235        result = intMul(regpool, s, opts);
236        break;
237      case INT_NEG_opcode:
238        result = intNeg(s, opts);
239        break;
240      case INT_NOT_opcode:
241        result = intNot(s, opts);
242        break;
243      case INT_OR_opcode:
244        result = intOr(s, opts);
245        break;
246      case INT_REM_opcode:
247        result = intRem(s, opts);
248        break;
249      case INT_SHL_opcode:
250        result = intShl(s, opts);
251        break;
252      case INT_SHR_opcode:
253        result = intShr(s, opts);
254        break;
255      case INT_SUB_opcode:
256        result = intSub(s, opts);
257        break;
258      case INT_USHR_opcode:
259        result = intUshr(s, opts);
260        break;
261      case INT_XOR_opcode:
262        result = intXor(s, opts);
263        break;
264        ////////////////////
265        // WORD ALU operations
266        ////////////////////
267      case REF_ADD_opcode:
268        result = refAdd(s, opts);
269        break;
270      case REF_AND_opcode:
271        result = refAnd(s, opts);
272        break;
273      case REF_SHL_opcode:
274        result = refShl(s, opts);
275        break;
276      case REF_SHR_opcode:
277        result = refShr(s, opts);
278        break;
279      case REF_NEG_opcode:
280        result = refNeg(s, opts);
281        break;
282      case REF_NOT_opcode:
283        result = refNot(s, opts);
284        break;
285      case REF_OR_opcode:
286        result = refOr(s, opts);
287        break;
288      case REF_SUB_opcode:
289        result = refSub(s, opts);
290        break;
291      case REF_USHR_opcode:
292        result = refUshr(s, opts);
293        break;
294      case REF_XOR_opcode:
295        result = refXor(s, opts);
296        break;
297        ////////////////////
298        // LONG ALU operations
299        ////////////////////
300      case LONG_ADD_opcode:
301        result = longAdd(s, opts);
302        break;
303      case LONG_AND_opcode:
304        result = longAnd(s, opts);
305        break;
306      case LONG_CMP_opcode:
307        result = longCmp(s, opts);
308        break;
309      case LONG_DIV_opcode:
310        result = longDiv(s, opts);
311        break;
312      case LONG_MUL_opcode:
313        result = longMul(regpool, s, opts);
314        break;
315      case LONG_NEG_opcode:
316        result = longNeg(s, opts);
317        break;
318      case LONG_NOT_opcode:
319        result = longNot(s, opts);
320        break;
321      case LONG_OR_opcode:
322        result = longOr(s, opts);
323        break;
324      case LONG_REM_opcode:
325        result = longRem(s, opts);
326        break;
327      case LONG_SHL_opcode:
328        result = longShl(s, opts);
329        break;
330      case LONG_SHR_opcode:
331        result = longShr(s, opts);
332        break;
333      case LONG_SUB_opcode:
334        result = longSub(s, opts);
335        break;
336      case LONG_USHR_opcode:
337        result = longUshr(s, opts);
338        break;
339      case LONG_XOR_opcode:
340        result = longXor(s, opts);
341        break;
342        ////////////////////
343        // FLOAT ALU operations
344        ////////////////////
345      case FLOAT_ADD_opcode:
346        result = floatAdd(s, opts);
347        break;
348      case FLOAT_CMPG_opcode:
349        result = floatCmpg(s, opts);
350        break;
351      case FLOAT_CMPL_opcode:
352        result = floatCmpl(s, opts);
353        break;
354      case FLOAT_DIV_opcode:
355        result = floatDiv(s, opts);
356        break;
357      case FLOAT_MUL_opcode:
358        result = floatMul(s, opts);
359        break;
360      case FLOAT_NEG_opcode:
361        result = floatNeg(s, opts);
362        break;
363      case FLOAT_REM_opcode:
364        result = floatRem(s, opts);
365        break;
366      case FLOAT_SUB_opcode:
367        result = floatSub(s, opts);
368        break;
369      case FLOAT_SQRT_opcode:
370        result = floatSqrt(s, opts);
371        break;
372        ////////////////////
373        // DOUBLE ALU operations
374        ////////////////////
375      case DOUBLE_ADD_opcode:
376        result = doubleAdd(s, opts);
377        break;
378      case DOUBLE_CMPG_opcode:
379        result = doubleCmpg(s, opts);
380        break;
381      case DOUBLE_CMPL_opcode:
382        result = doubleCmpl(s, opts);
383        break;
384      case DOUBLE_DIV_opcode:
385        result = doubleDiv(s, opts);
386        break;
387      case DOUBLE_MUL_opcode:
388        result = doubleMul(s, opts);
389        break;
390      case DOUBLE_NEG_opcode:
391        result = doubleNeg(s, opts);
392        break;
393      case DOUBLE_REM_opcode:
394        result = doubleRem(s, opts);
395        break;
396      case DOUBLE_SUB_opcode:
397        result = doubleSub(s, opts);
398        break;
399      case DOUBLE_SQRT_opcode:
400        result = doubleSqrt(s, opts);
401        break;
402        ////////////////////
403        // CONVERSION operations
404        ////////////////////
405      case DOUBLE_2FLOAT_opcode:
406        result = double2Float(s, opts);
407        break;
408      case DOUBLE_2INT_opcode:
409        result = double2Int(s, opts);
410        break;
411      case DOUBLE_2LONG_opcode:
412        result = double2Long(s, opts);
413        break;
414      case DOUBLE_AS_LONG_BITS_opcode:
415        result = doubleAsLongBits(s, opts);
416        break;
417      case INT_2DOUBLE_opcode:
418        result = int2Double(s, opts);
419        break;
420      case INT_2BYTE_opcode:
421        result = int2Byte(s, opts);
422        break;
423      case INT_2USHORT_opcode:
424        result = int2UShort(s, opts);
425        break;
426      case INT_2FLOAT_opcode:
427        result = int2Float(s, opts);
428        break;
429      case INT_2LONG_opcode:
430        result = int2Long(s, opts);
431        break;
432      case INT_2ADDRSigExt_opcode:
433        result = int2AddrSigExt(s, opts);
434        break;
435      case INT_2ADDRZerExt_opcode:
436        result = int2AddrZerExt(s, opts);
437        break;
438      case LONG_2ADDR_opcode:
439        result = long2Addr(s, opts);
440        break;
441      case INT_2SHORT_opcode:
442        result = int2Short(s, opts);
443        break;
444      case INT_BITS_AS_FLOAT_opcode:
445        result = intBitsAsFloat(s, opts);
446        break;
447      case ADDR_2INT_opcode:
448        result = addr2Int(s, opts);
449        break;
450      case ADDR_2LONG_opcode:
451        result = addr2Long(s, opts);
452        break;
453      case FLOAT_2DOUBLE_opcode:
454        result = float2Double(s, opts);
455        break;
456      case FLOAT_2INT_opcode:
457        result = float2Int(s, opts);
458        break;
459      case FLOAT_2LONG_opcode:
460        result = float2Long(s, opts);
461        break;
462      case FLOAT_AS_INT_BITS_opcode:
463        result = floatAsIntBits(s, opts);
464        break;
465      case LONG_2FLOAT_opcode:
466        result = long2Float(s, opts);
467        break;
468      case LONG_2INT_opcode:
469        result = long2Int(s, opts);
470        break;
471      case LONG_2DOUBLE_opcode:
472        result = long2Double(s, opts);
473        break;
474      case LONG_BITS_AS_DOUBLE_opcode:
475        result = longBitsAsDouble(s, opts);
476        break;
477        ////////////////////
478        // Field operations
479        ////////////////////
480      case ARRAYLENGTH_opcode:
481        result = arrayLength(s, opts);
482        break;
483      case BOUNDS_CHECK_opcode:
484        result = boundsCheck(s, opts);
485        break;
486      case CALL_opcode:
487        result = call(hir, regpool, s, opts);
488        break;
489      case GETFIELD_opcode:
490        result = getField(s, opts);
491        break;
492      case GET_OBJ_TIB_opcode:
493        result = getObjTib(s, opts);
494        break;
495      case GET_CLASS_TIB_opcode:
496        result = getClassTib(s, opts);
497        break;
498      case GET_TYPE_FROM_TIB_opcode:
499        result = getTypeFromTib(s, opts);
500        break;
501      case GET_ARRAY_ELEMENT_TIB_FROM_TIB_opcode:
502        result = getArrayElementTibFromTib(s, opts);
503        break;
504      case GET_SUPERCLASS_IDS_FROM_TIB_opcode:
505        result = getSuperclassIdsFromTib(s, opts);
506        break;
507      case GET_DOES_IMPLEMENT_FROM_TIB_opcode:
508        result = getDoesImplementFromTib(s, opts);
509        break;
510      case REF_LOAD_opcode:
511        result = refLoad(s, opts);
512        break;
513      default:
514        result = DefUseEffect.UNCHANGED;
515    }
516    if (VM.VerifyAssertions) {
517      switch (result) {
518        case MOVE_FOLDED:
519          // Check move has constant RHS
520          boolean moveHasConstantRHS = Move.conforms(s) && (Move.getVal(s) instanceof ConstantOperand);
521          if (!moveHasConstantRHS) {
522            String msg = "RHS of move " + s + " should be constant during simplification of " +
523                s.operator();
524            VM._assert(VM.NOT_REACHED, msg);
525          }
526          break;
527        case MOVE_REDUCED:
528          // Check move has non-constant RHS
529          boolean moveHasNonConstantRHS = Move.conforms(s) && !(Move.getVal(s) instanceof ConstantOperand);
530          if (!moveHasNonConstantRHS) {
531            String msg = "RHS of move " + s + " shouldn't be constant during simplification of " +
532                s.operator();
533            VM._assert(moveHasNonConstantRHS, msg);
534          }
535          break;
536        default:
537          // Nothing to check
538      }
539    }
540    return result;
541  }
542
543  private static DefUseEffect guardCombine(Instruction s, OptOptions opts) {
544    Operand op1 = Binary.getVal1(s);
545    Operand op2 = Binary.getVal2(s);
546    if (op1.similar(op2) || (op2 instanceof TrueGuardOperand)) {
547      Move.mutate(s, GUARD_MOVE, Binary.getClearResult(s), op1);
548      if (op1 instanceof TrueGuardOperand) {
549        // BOTH true guards: FOLD
550        return DefUseEffect.MOVE_FOLDED;
551      } else {
552        // ONLY OP2 IS TrueGuard: MOVE REDUCE
553        return DefUseEffect.MOVE_REDUCED;
554      }
555    } else if (op1 instanceof TrueGuardOperand) {
556      // ONLY OP1 IS TrueGuard: MOVE REDUCE
557      Move.mutate(s, GUARD_MOVE, Binary.getClearResult(s), op2);
558      return DefUseEffect.MOVE_REDUCED;
559    } else {
560      return DefUseEffect.UNCHANGED;
561    }
562  }
563
564  private static DefUseEffect trapIf(Instruction s, OptOptions opts) {
565    {
566      Operand op1 = TrapIf.getVal1(s);
567      Operand op2 = TrapIf.getVal2(s);
568      if (op1.isConstant()) {
569        if (op2.isConstant()) {
570          int willTrap = TrapIf.getCond(s).evaluate(op1, op2);
571          if (willTrap == ConditionOperand.TRUE) {
572            Trap.mutate(s, TRAP, TrapIf.getClearGuardResult(s), TrapIf.getClearTCode(s));
573            return DefUseEffect.TRAP_REDUCED;
574          } else if (willTrap == ConditionOperand.FALSE) {
575            Move.mutate(s, GUARD_MOVE, TrapIf.getClearGuardResult(s), TG());
576            return DefUseEffect.MOVE_FOLDED;
577          }
578        } else {
579          // canonicalize
580          TrapIf.mutate(s,
581                        TRAP_IF,
582                        TrapIf.getClearGuardResult(s),
583                        TrapIf.getClearVal2(s),
584                        TrapIf.getClearVal1(s),
585                        TrapIf.getClearCond(s).flipOperands(),
586                        TrapIf.getClearTCode(s));
587        }
588      }
589    }
590    return DefUseEffect.UNCHANGED;
591  }
592
593  private static DefUseEffect nullCheck(Instruction s, OptOptions opts) {
594    Operand ref = NullCheck.getRef(s);
595    if (ref.isNullConstant() || (ref.isAddressConstant() && ref.asAddressConstant().value.isZero())) {
596      Trap.mutate(s, TRAP, NullCheck.getClearGuardResult(s), TrapCodeOperand.NullPtr());
597      return DefUseEffect.TRAP_REDUCED;
598    } else if (ref.isConstant()) {
599      // object, string, class or non-null address constant
600
601      // Make the slightly suspect assumption that all non-zero address
602      // constants are actually valid pointers. Not necessarily true,
603      // but unclear what else we can do.
604      Move.mutate(s, GUARD_MOVE, NullCheck.getClearGuardResult(s), TG());
605      return DefUseEffect.MOVE_FOLDED;
606    } else {
607      return DefUseEffect.UNCHANGED;
608    }
609  }
610
611  private static DefUseEffect intZeroCheck(Instruction s, OptOptions opts) {
612    {
613      Operand op = ZeroCheck.getValue(s);
614      if (op.isIntConstant()) {
615        int val = op.asIntConstant().value;
616        if (val == 0) {
617          Trap.mutate(s, TRAP, ZeroCheck.getClearGuardResult(s), TrapCodeOperand.DivByZero());
618          return DefUseEffect.TRAP_REDUCED;
619        } else {
620          Move.mutate(s, GUARD_MOVE, ZeroCheck.getClearGuardResult(s), TG());
621          return DefUseEffect.MOVE_FOLDED;
622        }
623      }
624    }
625    return DefUseEffect.UNCHANGED;
626  }
627
628  private static DefUseEffect longZeroCheck(Instruction s, OptOptions opts) {
629    {
630      Operand op = ZeroCheck.getValue(s);
631      if (op.isLongConstant()) {
632        long val = op.asLongConstant().value;
633        if (val == 0L) {
634          Trap.mutate(s, TRAP, ZeroCheck.getClearGuardResult(s), TrapCodeOperand.DivByZero());
635          return DefUseEffect.TRAP_REDUCED;
636        } else {
637          Move.mutate(s, GUARD_MOVE, ZeroCheck.getClearGuardResult(s), TG());
638          return DefUseEffect.MOVE_FOLDED;
639        }
640      }
641    }
642    return DefUseEffect.UNCHANGED;
643  }
644  private static DefUseEffect checkcast(Instruction s, OptOptions opts) {
645    Operand ref = TypeCheck.getRef(s);
646    if (ref.isNullConstant()) {
647      Move.mutate(s, REF_MOVE, TypeCheck.getResult(s), ref);
648      if (ref.isConstant())
649        return DefUseEffect.MOVE_FOLDED;
650      else
651        return DefUseEffect.MOVE_REDUCED;
652    } else if (ref.isConstant()) {
653      s.changeOperatorTo(CHECKCAST_NOTNULL);
654      return checkcastNotNull(s, opts);
655    } else {
656      TypeReference lhsType = TypeCheck.getType(s).getTypeRef();
657      TypeReference rhsType = ref.getType();
658      byte ans = ClassLoaderProxy.includesType(lhsType, rhsType);
659      if (ans == YES) {
660        Move.mutate(s, REF_MOVE, TypeCheck.getResult(s), ref);
661        if (ref.isConstant())
662          return DefUseEffect.MOVE_FOLDED;
663        else
664          return DefUseEffect.MOVE_REDUCED;
665      } else {
666        // NOTE: Constants.NO can't help us because (T)null always succeeds
667        return DefUseEffect.UNCHANGED;
668      }
669    }
670  }
671
672  private static DefUseEffect checkcastNotNull(Instruction s, OptOptions opts) {
673    Operand ref = TypeCheck.getRef(s);
674    TypeReference lhsType = TypeCheck.getType(s).getTypeRef();
675    TypeReference rhsType = ref.getType();
676    byte ans = ClassLoaderProxy.includesType(lhsType, rhsType);
677    if (ans == YES) {
678      Move.mutate(s, REF_MOVE, TypeCheck.getResult(s), ref);
679      if (ref.isConstant())
680        return DefUseEffect.MOVE_FOLDED;
681      else
682        return DefUseEffect.MOVE_REDUCED;
683    } else if (ans == NO) {
684      RVMType rType = rhsType.peekType();
685      if (rType != null && rType.isClassType() && rType.asClass().isFinal()) {
686        // only final (or precise) rhs types can be optimized since rhsType may be conservative
687        Trap.mutate(s, TRAP, null, TrapCodeOperand.CheckCast());
688        return DefUseEffect.TRAP_REDUCED;
689      } else {
690        return DefUseEffect.UNCHANGED;
691      }
692    } else {
693      return DefUseEffect.UNCHANGED;
694    }
695  }
696  private static DefUseEffect instanceOf(Instruction s, OptOptions opts) {
697    Operand ref = InstanceOf.getRef(s);
698    if (ref.isNullConstant()) {
699      Move.mutate(s, INT_MOVE, InstanceOf.getClearResult(s), IC(0));
700      return DefUseEffect.MOVE_FOLDED;
701    } else if (ref.isConstant()) {
702      s.changeOperatorTo(INSTANCEOF_NOTNULL);
703      return instanceOfNotNull(s, opts);
704    } else {
705      TypeReference lhsType = InstanceOf.getType(s).getTypeRef();
706      TypeReference rhsType = ref.getType();
707      byte ans = ClassLoaderProxy.includesType(lhsType, rhsType);
708      // NOTE: Constants.YES doesn't help because ref may be null and null instanceof T is false
709      if (ans == NO) {
710        RVMType rType = rhsType.peekType();
711        if (rType != null && rType.isClassType() && rType.asClass().isFinal()) {
712          // only final (or precise) rhs types can be optimized since rhsType may be conservative
713          Move.mutate(s, INT_MOVE, InstanceOf.getClearResult(s), IC(0));
714          return DefUseEffect.MOVE_FOLDED;
715        } else {
716          return DefUseEffect.UNCHANGED;
717        }
718      } else {
719        return DefUseEffect.UNCHANGED;
720      }
721    }
722  }
723
724  private static DefUseEffect instanceOfNotNull(Instruction s, OptOptions opts) {
725    {
726      Operand ref = InstanceOf.getRef(s);
727      TypeReference lhsType = InstanceOf.getType(s).getTypeRef();
728      TypeReference rhsType = ref.getType();
729      byte ans = ClassLoaderProxy.includesType(lhsType, rhsType);
730      if (ans == YES) {
731        Move.mutate(s, INT_MOVE, InstanceOf.getClearResult(s), IC(1));
732        return DefUseEffect.MOVE_FOLDED;
733      } else if (ans == NO) {
734        RVMType rType = rhsType.peekType();
735        if (rType != null && rType.isClassType() && rType.asClass().isFinal()) {
736          // only final (or precise) rhs types can be optimized since rhsType may be conservative
737          Move.mutate(s, INT_MOVE, InstanceOf.getClearResult(s), IC(0));
738          return DefUseEffect.MOVE_FOLDED;
739        }
740      }
741    }
742    return DefUseEffect.UNCHANGED;
743  }
744
745  private static DefUseEffect objarrayStoreCheck(Instruction s, OptOptions opts) {
746    Operand val = StoreCheck.getVal(s);
747    if (val.isNullConstant()) {
748      // Writing null into an array is trivially safe
749      Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck.getClearGuard(s));
750      return DefUseEffect.MOVE_REDUCED;
751    } else {
752      Operand ref = StoreCheck.getRef(s);
753      TypeReference arrayTypeRef = ref.getType();
754      if (!arrayTypeRef.isArrayType()) {
755        // Caused by inlining new and type propogation
756        return DefUseEffect.UNCHANGED;
757      }
758      RVMType typeOfIMElem = arrayTypeRef.getInnermostElementType().peekType();
759      if (typeOfIMElem != null) {
760        RVMType typeOfVal = val.getType().peekType();
761        if ((typeOfIMElem == typeOfVal) &&
762            (typeOfIMElem.isPrimitiveType() || typeOfIMElem.isUnboxedType() || typeOfIMElem.asClass().isFinal())) {
763          // Writing something of a final type to an array of that
764          // final type is safe
765          Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck.getClearGuard(s));
766          return DefUseEffect.MOVE_REDUCED;
767        }
768      }
769      final boolean refIsPrecise = ref.isConstant() || (ref.isRegister() && ref.asRegister().isPreciseType());
770      if ((arrayTypeRef == TypeReference.JavaLangObjectArray) && refIsPrecise) {
771        // We know this to be an array of objects so any store must
772        // be safe
773        Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck.getClearGuard(s));
774        return DefUseEffect.MOVE_REDUCED;
775      }
776      final boolean valIsPrecise = val.isConstant() || (val.isRegister() && val.asRegister().isPreciseType());
777      if (refIsPrecise && valIsPrecise) {
778        // writing a known type of value into a known type of array
779        byte ans = ClassLoaderProxy.includesType(arrayTypeRef.getArrayElementType(), val.getType());
780        if (ans == YES) {
781          // all stores should succeed
782          Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck.getClearGuard(s));
783          return DefUseEffect.MOVE_REDUCED;
784        } else if (ans == NO) {
785          // all stores will fail
786          Trap.mutate(s, TRAP, StoreCheck.getClearGuardResult(s), TrapCodeOperand.StoreCheck());
787          return DefUseEffect.TRAP_REDUCED;
788        }
789      }
790      return DefUseEffect.UNCHANGED;
791    }
792  }
793
794  private static DefUseEffect objarrayStoreCheckNotNull(Instruction s, OptOptions opts) {
795    Operand val = StoreCheck.getVal(s);
796    Operand ref = StoreCheck.getRef(s);
797    TypeReference arrayTypeRef = ref.getType();
798    if (!arrayTypeRef.isArrayType()) {
799      // Caused by inlining new and type propogation
800      return DefUseEffect.UNCHANGED;
801    }
802    RVMType typeOfIMElem = arrayTypeRef.getInnermostElementType().peekType();
803    if (typeOfIMElem != null) {
804      RVMType typeOfVal = val.getType().peekType();
805      if ((typeOfIMElem == typeOfVal) &&
806          (typeOfIMElem.isPrimitiveType() || typeOfIMElem.isUnboxedType() || typeOfIMElem.asClass().isFinal())) {
807        // Writing something of a final type to an array of that
808        // final type is safe
809        Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck.getClearGuard(s));
810        return DefUseEffect.MOVE_REDUCED;
811      }
812    }
813    final boolean refIsPrecise = ref.isConstant() || (ref.isRegister() && ref.asRegister().isPreciseType());
814    if ((arrayTypeRef == TypeReference.JavaLangObjectArray) && refIsPrecise) {
815      // We know this to be an array of objects so any store must
816      // be safe
817      Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck.getClearGuard(s));
818      return DefUseEffect.MOVE_REDUCED;
819    }
820    final boolean valIsPrecise = val.isConstant() || (val.isRegister() && val.asRegister().isPreciseType());
821    if (refIsPrecise && valIsPrecise) {
822      // writing a known type of value into a known type of array
823      byte ans = ClassLoaderProxy.includesType(arrayTypeRef.getArrayElementType(), val.getType());
824      if (ans == YES) {
825        // all stores should succeed
826        Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck.getClearGuard(s));
827        return DefUseEffect.MOVE_REDUCED;
828      } else if (ans == NO) {
829        // all stores will fail
830        Trap.mutate(s, TRAP, StoreCheck.getClearGuardResult(s), TrapCodeOperand.StoreCheck());
831        return DefUseEffect.TRAP_REDUCED;
832      }
833    }
834    return DefUseEffect.UNCHANGED;
835  }
836
837  private static DefUseEffect mustImplementInterface(Instruction s, OptOptions opts) {
838    Operand ref = TypeCheck.getRef(s);
839    if (ref.isNullConstant()) {
840      // Possible situation from constant propagation. This operation
841      // is really a nop as a null_check should have happened already
842      Trap.mutate(s, TRAP, null, TrapCodeOperand.NullPtr());
843      return DefUseEffect.TRAP_REDUCED;
844    } else {
845      TypeReference lhsType = TypeCheck.getType(s).getTypeRef(); // the interface that must be implemented
846      TypeReference rhsType = ref.getType();                     // our type
847      byte ans = ClassLoaderProxy.includesType(lhsType, rhsType);
848      if (ans == YES) {
849        RVMType rType = rhsType.peekType();
850        if (rType != null) {
851          if (rType.isClassType() && rType.asClass().isInterface()) {
852            /* This is exactly the kind of typing that could require us to raise an IncompatibleClassChangeError */
853            return DefUseEffect.UNCHANGED;
854          }
855          Move.mutate(s, REF_MOVE, TypeCheck.getResult(s), ref);
856          if (ref.isConstant())
857            return DefUseEffect.MOVE_FOLDED;
858          else
859            return DefUseEffect.MOVE_REDUCED;
860        } else {
861          return DefUseEffect.UNCHANGED;
862        }
863      } else if (ans == NO) {
864        RVMType rType = rhsType.peekType();
865        if (rType != null && rType.isClassType() && rType.asClass().isFinal()) {
866          // only final (or precise) rhs types can be optimized since rhsType may be conservative
867          Trap.mutate(s, TRAP, null, TrapCodeOperand.MustImplement());
868          return DefUseEffect.TRAP_REDUCED;
869        }
870      }
871      return DefUseEffect.UNCHANGED;
872    }
873  }
874
875  private static DefUseEffect intCondMove(Instruction s, OptOptions opts) {
876    {
877      Operand val1 = CondMove.getVal1(s);
878      Operand val2 = CondMove.getVal2(s);
879      int cond = CondMove.getCond(s).evaluate(val1, val2);
880      if (cond != ConditionOperand.UNKNOWN) {
881        // BOTH CONSTANTS OR SIMILAR: FOLD
882        Operand val =
883            (cond == ConditionOperand.TRUE) ? CondMove.getClearTrueValue(s) : CondMove.getClearFalseValue(s);
884        Move.mutate(s, INT_MOVE, CondMove.getClearResult(s), val);
885        return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED;
886      }
887      if (val1.isConstant() && !val2.isConstant()) {
888        // Canonicalize by switching operands and fliping code.
889        Operand tmp = CondMove.getClearVal1(s);
890        CondMove.setVal1(s, CondMove.getClearVal2(s));
891        CondMove.setVal2(s, tmp);
892        CondMove.getCond(s).flipOperands();
893      }
894      Operand tv = CondMove.getTrueValue(s);
895      Operand fv = CondMove.getFalseValue(s);
896      if (tv.similar(fv)) {
897        Move.mutate(s, INT_MOVE, CondMove.getClearResult(s), tv);
898        return tv.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED;
899      }
900      if (tv.isIntConstant() && fv.isIntConstant() && !CondMove.getCond(s).isFLOATINGPOINT()) {
901        int itv = tv.asIntConstant().value;
902        int ifv = fv.asIntConstant().value;
903        Operator op = null;
904        if (val1.isLong()) {
905          op = BOOLEAN_CMP_LONG;
906        } else if (val1.isFloat()) {
907          op = BOOLEAN_CMP_FLOAT;
908        } else if (val1.isDouble()) {
909          op = BOOLEAN_CMP_DOUBLE;
910        } else if (val1.isRef()) {
911          op = BOOLEAN_CMP_ADDR;
912        } else {
913          op = BOOLEAN_CMP_INT;
914        }
915        if (itv == 1 && ifv == 0) {
916          BooleanCmp.mutate(s,
917                            op,
918                            CondMove.getClearResult(s),
919                            CondMove.getClearVal1(s),
920                            CondMove.getClearVal2(s),
921                            CondMove.getClearCond(s),
922                            new BranchProfileOperand());
923          return DefUseEffect.REDUCED;
924        }
925        if (itv == 0 && ifv == 1) {
926          BooleanCmp.mutate(s,
927                            op,
928                            CondMove.getClearResult(s),
929                            CondMove.getClearVal1(s),
930                            CondMove.getClearVal2(s),
931                            CondMove.getClearCond(s).flipCode(),
932                            new BranchProfileOperand());
933          return DefUseEffect.REDUCED;
934        }
935      }
936    }
937    return DefUseEffect.UNCHANGED;
938  }
939
940  private static DefUseEffect longCondMove(Instruction s, OptOptions opts) {
941    {
942      Operand val1 = CondMove.getVal1(s);
943      Operand val2 = CondMove.getVal2(s);
944      int cond = CondMove.getCond(s).evaluate(val1, val2);
945      if (cond != ConditionOperand.UNKNOWN) {
946        // BOTH CONSTANTS OR SIMILAR: FOLD
947        Operand val =
948            (cond == ConditionOperand.TRUE) ? CondMove.getClearTrueValue(s) : CondMove.getClearFalseValue(s);
949        Move.mutate(s, LONG_MOVE, CondMove.getClearResult(s), val);
950        return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED;
951      }
952      if (val1.isConstant() && !val2.isConstant()) {
953        // Canonicalize by switching operands and fliping code.
954        Operand tmp = CondMove.getClearVal1(s);
955        CondMove.setVal1(s, CondMove.getClearVal2(s));
956        CondMove.setVal2(s, tmp);
957        CondMove.getCond(s).flipOperands();
958      }
959      Operand tv = CondMove.getTrueValue(s);
960      Operand fv = CondMove.getFalseValue(s);
961      if (tv.similar(fv)) {
962        Move.mutate(s, LONG_MOVE, CondMove.getClearResult(s), tv);
963        return tv.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED;
964      }
965      if (tv.isLongConstant() && fv.isLongConstant() && !CondMove.getCond(s).isFLOATINGPOINT()) {
966        long itv = tv.asLongConstant().value;
967        long ifv = fv.asLongConstant().value;
968        Operator op = null;
969        if (val1.isLong()) {
970          op = BOOLEAN_CMP_LONG;
971        } else if (val1.isFloat()) {
972          op = BOOLEAN_CMP_FLOAT;
973        } else if (val1.isDouble()) {
974          op = BOOLEAN_CMP_DOUBLE;
975        } else {
976          op = BOOLEAN_CMP_INT;
977        }
978        if (itv == 1 && ifv == 0) {
979          BooleanCmp.mutate(s,
980                            op,
981                            CondMove.getClearResult(s),
982                            CondMove.getClearVal1(s),
983                            CondMove.getClearVal2(s),
984                            CondMove.getClearCond(s),
985                            new BranchProfileOperand());
986          return DefUseEffect.REDUCED;
987        }
988        if (itv == 0 && ifv == 1) {
989          BooleanCmp.mutate(s,
990                            op,
991                            CondMove.getClearResult(s),
992                            CondMove.getClearVal1(s),
993                            CondMove.getClearVal2(s),
994                            CondMove.getClearCond(s).flipCode(),
995                            new BranchProfileOperand());
996          return DefUseEffect.REDUCED;
997        }
998      }
999    }
1000    return DefUseEffect.UNCHANGED;
1001  }
1002
1003  private static DefUseEffect floatCondMove(Instruction s, OptOptions opts) {
1004    {
1005      Operand val1 = CondMove.getVal1(s);
1006      Operand val2 = CondMove.getVal2(s);
1007      int cond = CondMove.getCond(s).evaluate(val1, val2);
1008      if (cond != ConditionOperand.UNKNOWN) {
1009        // BOTH CONSTANTS OR SIMILAR: FOLD
1010        Operand val =
1011            (cond == ConditionOperand.TRUE) ? CondMove.getClearTrueValue(s) : CondMove.getClearFalseValue(s);
1012        Move.mutate(s, FLOAT_MOVE, CondMove.getClearResult(s), val);
1013        return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED;
1014      }
1015      if (val1.isConstant() && !val2.isConstant()) {
1016        // Canonicalize by switching operands and fliping code.
1017        Operand tmp = CondMove.getClearVal1(s);
1018        CondMove.setVal1(s, CondMove.getClearVal2(s));
1019        CondMove.setVal2(s, tmp);
1020        CondMove.getCond(s).flipOperands();
1021      }
1022      Operand tv = CondMove.getTrueValue(s);
1023      Operand fv = CondMove.getFalseValue(s);
1024      if (tv.similar(fv)) {
1025        Move.mutate(s, FLOAT_MOVE, CondMove.getClearResult(s), tv);
1026        return tv.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED;
1027      }
1028    }
1029    return DefUseEffect.UNCHANGED;
1030  }
1031
1032  private static DefUseEffect doubleCondMove(Instruction s, OptOptions opts) {
1033    {
1034      Operand val1 = CondMove.getVal1(s);
1035      Operand val2 = CondMove.getVal2(s);
1036      int cond = CondMove.getCond(s).evaluate(val1, val2);
1037      if (cond != ConditionOperand.UNKNOWN) {
1038        // BOTH CONSTANTS OR SIMILAR: FOLD
1039        Operand val =
1040            (cond == ConditionOperand.TRUE) ? CondMove.getClearTrueValue(s) : CondMove.getClearFalseValue(s);
1041        Move.mutate(s, DOUBLE_MOVE, CondMove.getClearResult(s), val);
1042        return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED;
1043      }
1044      if (val1.isConstant() && !val2.isConstant()) {
1045        // Canonicalize by switching operands and fliping code.
1046        Operand tmp = CondMove.getClearVal1(s);
1047        CondMove.setVal1(s, CondMove.getClearVal2(s));
1048        CondMove.setVal2(s, tmp);
1049        CondMove.getCond(s).flipOperands();
1050      }
1051      Operand tv = CondMove.getTrueValue(s);
1052      Operand fv = CondMove.getFalseValue(s);
1053      if (tv.similar(fv)) {
1054        Move.mutate(s, DOUBLE_MOVE, CondMove.getClearResult(s), tv);
1055        return tv.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED;
1056      }
1057    }
1058    return DefUseEffect.UNCHANGED;
1059  }
1060
1061  private static DefUseEffect refCondMove(Instruction s, OptOptions opts) {
1062    {
1063      Operand val1 = CondMove.getVal1(s);
1064      if (val1.isConstant()) {
1065        Operand val2 = CondMove.getVal2(s);
1066        if (val2.isConstant()) {
1067          // BOTH CONSTANTS: FOLD
1068          int cond = CondMove.getCond(s).evaluate(val1, val2);
1069          if (cond != ConditionOperand.UNKNOWN) {
1070            Operand val =
1071                (cond == ConditionOperand.TRUE) ? CondMove.getClearTrueValue(s) : CondMove.getClearFalseValue(s);
1072            Move.mutate(s, REF_MOVE, CondMove.getClearResult(s), val);
1073            return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED;
1074          }
1075        } else {
1076          // Canonicalize by switching operands and fliping code.
1077          Operand tmp = CondMove.getClearVal1(s);
1078          CondMove.setVal1(s, CondMove.getClearVal2(s));
1079          CondMove.setVal2(s, tmp);
1080          CondMove.getCond(s).flipOperands();
1081        }
1082      }
1083      if (CondMove.getTrueValue(s).similar(CondMove.getFalseValue(s))) {
1084        Operand val = CondMove.getClearTrueValue(s);
1085        Move.mutate(s, REF_MOVE, CondMove.getClearResult(s), val);
1086        return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED;
1087      }
1088    }
1089    return DefUseEffect.UNCHANGED;
1090  }
1091
1092  private static DefUseEffect guardCondMove(Instruction s, OptOptions opts) {
1093    {
1094      Operand val1 = CondMove.getVal1(s);
1095      if (val1.isConstant()) {
1096        Operand val2 = CondMove.getVal2(s);
1097        if (val2.isConstant()) {
1098          // BOTH CONSTANTS: FOLD
1099          int cond = CondMove.getCond(s).evaluate(val1, val2);
1100          if (cond == ConditionOperand.UNKNOWN) {
1101            Operand val =
1102                (cond == ConditionOperand.TRUE) ? CondMove.getClearTrueValue(s) : CondMove.getClearFalseValue(s);
1103            Move.mutate(s, GUARD_MOVE, CondMove.getClearResult(s), val);
1104            return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED;
1105          }
1106        } else {
1107          // Canonicalize by switching operands and fliping code.
1108          Operand tmp = CondMove.getClearVal1(s);
1109          CondMove.setVal1(s, CondMove.getClearVal2(s));
1110          CondMove.setVal2(s, tmp);
1111          CondMove.getCond(s).flipOperands();
1112        }
1113      }
1114      if (CondMove.getTrueValue(s).similar(CondMove.getFalseValue(s))) {
1115        Operand val = CondMove.getClearTrueValue(s);
1116        Move.mutate(s, GUARD_MOVE, CondMove.getClearResult(s), val);
1117        return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED;
1118      }
1119    }
1120    return DefUseEffect.UNCHANGED;
1121  }
1122
1123  private static DefUseEffect booleanNot(Instruction s, OptOptions opts) {
1124    if (opts.SIMPLIFY_INTEGER_OPS) {
1125      Operand op = Unary.getVal(s);
1126      if (op.isIntConstant()) {
1127        // CONSTANT: FOLD
1128        int val = op.asIntConstant().value;
1129        if (val == 0) {
1130          Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC(1));
1131        } else {
1132          Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC(0));
1133        }
1134        return DefUseEffect.MOVE_FOLDED;
1135      }
1136    }
1137    return DefUseEffect.UNCHANGED;
1138  }
1139
1140  private static DefUseEffect booleanCmpInt(Instruction s, OptOptions opts) {
1141    if (opts.SIMPLIFY_INTEGER_OPS) {
1142      Operand op1 = BooleanCmp.getVal1(s);
1143      Operand op2 = BooleanCmp.getVal2(s);
1144      if (op1.isConstant()) {
1145        if (op2.isConstant()) {
1146          // BOTH CONSTANTS: FOLD
1147          int cond = BooleanCmp.getCond(s).evaluate(op1, op2);
1148          if (cond != ConditionOperand.UNKNOWN) {
1149            Move.mutate(s, INT_MOVE, BooleanCmp.getResult(s), (cond == ConditionOperand.TRUE) ? IC(1) : IC(0));
1150            return DefUseEffect.MOVE_FOLDED;
1151          }
1152        } else {
1153          // Canonicalize by switching operands and fliping code.
1154          BooleanCmp.setVal1(s, op2);
1155          BooleanCmp.setVal2(s, op1);
1156          BooleanCmp.getCond(s).flipOperands();
1157          op2 = op1;
1158          op1 = BooleanCmp.getVal1(s);
1159        }
1160      }
1161      // try to fold boolean compares involving one boolean constant
1162      // e.g.: x = (y == true)  ? true : false ==> x = y
1163      // or:   x = (y == false) ? true : false ==> x = !y
1164      if (op1.getType().isBooleanType() && op2.isConstant()) {
1165        ConditionOperand cond = BooleanCmp.getCond(s);
1166        int op2value = op2.asIntConstant().value;
1167        if ((cond.isNOT_EQUAL() && (op2value == 0)) || (cond.isEQUAL() && (op2value == 1))) {
1168          Move.mutate(s, INT_MOVE, BooleanCmp.getResult(s), op1);
1169          return DefUseEffect.MOVE_REDUCED;
1170        } else if ((cond.isEQUAL() && (op2value == 0)) || (cond.isNOT_EQUAL() && (op2value == 1))) {
1171          Unary.mutate(s, BOOLEAN_NOT, BooleanCmp.getResult(s), op1);
1172          return DefUseEffect.REDUCED;
1173        }
1174      }
1175    }
1176    return DefUseEffect.UNCHANGED;
1177  }
1178
1179  private static DefUseEffect booleanCmpAddr(Instruction s, OptOptions opts) {
1180    if (opts.SIMPLIFY_REF_OPS) {
1181      Operand op1 = BooleanCmp.getVal1(s);
1182      Operand op2 = BooleanCmp.getVal2(s);
1183      if (op1.isConstant()) {
1184        if (op2.isConstant()) {
1185          // BOTH CONSTANTS: FOLD
1186          int cond = BooleanCmp.getCond(s).evaluate(op1, op2);
1187          if (cond != ConditionOperand.UNKNOWN) {
1188            Move.mutate(s, REF_MOVE, BooleanCmp.getResult(s), (cond == ConditionOperand.TRUE) ? IC(1) : IC(0));
1189            return DefUseEffect.MOVE_FOLDED;
1190          }
1191        } else {
1192          // Canonicalize by switching operands and fliping code.
1193          Operand tmp = BooleanCmp.getClearVal1(s);
1194          BooleanCmp.setVal1(s, BooleanCmp.getClearVal2(s));
1195          BooleanCmp.setVal2(s, tmp);
1196          BooleanCmp.getCond(s).flipOperands();
1197        }
1198      }
1199    }
1200    return DefUseEffect.UNCHANGED;
1201  }
1202
1203  private static DefUseEffect intAdd(Instruction s, OptOptions opts) {
1204    if (opts.SIMPLIFY_INTEGER_OPS) {
1205      canonicalizeCommutativeOperator(s);
1206      Operand op2 = Binary.getVal2(s);
1207      if (op2.isIntConstant()) {
1208        int val2 = op2.asIntConstant().value;
1209        Operand op1 = Binary.getVal1(s);
1210        if (op1.isIntConstant()) {
1211          // BOTH CONSTANTS: FOLD
1212          int val1 = op1.asIntConstant().value;
1213          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 + val2));
1214          return DefUseEffect.MOVE_FOLDED;
1215        } else {
1216          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
1217          if (val2 == 0) {
1218            Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
1219            return DefUseEffect.MOVE_REDUCED;
1220          }
1221        }
1222      } else {
1223        Operand op1 = Binary.getVal1(s);
1224        if (op1.similar(op2)) {
1225          // Adding something to itself is the same as a multiply by 2 so
1226          // canonicalize as a shift left
1227          Binary.mutate(s, INT_SHL, Binary.getClearResult(s), op1, IC(1));
1228          return DefUseEffect.UNCHANGED;
1229        }
1230      }
1231    }
1232    return DefUseEffect.UNCHANGED;
1233  }
1234
1235  private static DefUseEffect intAnd(Instruction s, OptOptions opts) {
1236    if (opts.SIMPLIFY_INTEGER_OPS) {
1237      canonicalizeCommutativeOperator(s);
1238      Operand op1 = Binary.getVal1(s);
1239      Operand op2 = Binary.getVal2(s);
1240      if (op1.similar(op2)) {
1241        // THE SAME OPERAND: x & x == x
1242        Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
1243        return op1.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED;
1244      }
1245      if (op2.isIntConstant()) {
1246        int val2 = op2.asIntConstant().value;
1247        if (op1.isIntConstant()) {
1248          // BOTH CONSTANTS: FOLD
1249          int val1 = op1.asIntConstant().value;
1250          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 & val2));
1251          return DefUseEffect.MOVE_FOLDED;
1252        } else {
1253          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
1254          if (val2 == 0) {                  // x & 0 == 0
1255            Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0));
1256            return DefUseEffect.MOVE_FOLDED;
1257          }
1258          if (val2 == -1) {                 // x & -1 == x & 0xffffffff == x
1259            Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
1260            return DefUseEffect.MOVE_REDUCED;
1261          }
1262        }
1263      }
1264    }
1265    return DefUseEffect.UNCHANGED;
1266  }
1267
1268  private static DefUseEffect intDiv(AbstractRegisterPool regpool, Instruction s, OptOptions opts) {
1269    if (opts.SIMPLIFY_INTEGER_OPS) {
1270      Operand op1 = GuardedBinary.getVal1(s);
1271      Operand op2 = GuardedBinary.getVal2(s);
1272      if (op1.similar(op2)) {
1273        // THE SAME OPERAND: x / x == 1
1274        Move.mutate(s, INT_MOVE, GuardedBinary.getClearResult(s), IC(1));
1275        return DefUseEffect.MOVE_FOLDED;
1276      }
1277      if (op2.isIntConstant()) {
1278        int val2 = op2.asIntConstant().value;
1279        if (val2 == 0) {
1280          // TODO: This instruction is actually unreachable.
1281          // There will be an INT_ZERO_CHECK
1282          // guarding this instruction that will result in an
1283          // ArithmeticException.  We
1284          // should probabbly just remove the INT_DIV as dead code.
1285          return DefUseEffect.UNCHANGED;
1286        }
1287        if (op1.isIntConstant()) {
1288          // BOTH CONSTANTS: FOLD
1289          int val1 = op1.asIntConstant().value;
1290          Move.mutate(s, INT_MOVE, GuardedBinary.getClearResult(s), IC(val1 / val2));
1291          return DefUseEffect.MOVE_FOLDED;
1292        } else {
1293          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
1294          if (val2 == 1) {                  // x / 1 == x;
1295            Move.mutate(s, INT_MOVE, GuardedBinary.getClearResult(s), GuardedBinary.getClearVal1(s));
1296            return DefUseEffect.MOVE_REDUCED;
1297          }
1298          // x / c == (x + (((1 << c) - 1) & (x >> 31))) >> c .. if c is power of 2
1299          if (s.hasPrev()) {
1300            int power = PowerOf2(val2);
1301            if (power != -1) {
1302              RegisterOperand tempInt1 = regpool.makeTempInt();
1303              RegisterOperand tempInt2 = regpool.makeTempInt();
1304              RegisterOperand tempInt3 = regpool.makeTempInt();
1305              Instruction sign = Binary.create(INT_SHR, tempInt1, GuardedBinary.getVal1(s).copy(), IC(31));
1306              sign.copyPosition(s);
1307              s.insertBefore(sign);
1308              Instruction masked = Binary.create(INT_AND, tempInt2, tempInt1.copyRO(), IC((1 << power) - 1));
1309              masked.copyPosition(s);
1310              s.insertBefore(masked);
1311              Instruction adjusted = Binary.create(INT_ADD, tempInt3, tempInt2.copyRO(), GuardedBinary.getClearVal1(s));
1312              adjusted.copyPosition(s);
1313              s.insertBefore(adjusted);
1314              Binary.mutate(s, INT_SHR, GuardedBinary.getClearResult(s), tempInt3.copyRO(), IC(power));
1315              return DefUseEffect.REDUCED;
1316            }
1317          }
1318        }
1319      }
1320    }
1321    return DefUseEffect.UNCHANGED;
1322  }
1323
1324  private static DefUseEffect intMul(AbstractRegisterPool regpool, Instruction s, OptOptions opts) {
1325    if (opts.SIMPLIFY_INTEGER_OPS) {
1326      canonicalizeCommutativeOperator(s);
1327      Operand op2 = Binary.getVal2(s);
1328      if (op2.isIntConstant()) {
1329        Operand op1 = Binary.getVal1(s);
1330        if (op1.isIntConstant()) {
1331          // BOTH CONSTANTS: FOLD
1332          int val1 = op1.asIntConstant().value;
1333          int val2 = op2.asIntConstant().value;
1334          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 * val2));
1335          return DefUseEffect.MOVE_FOLDED;
1336        } else {
1337          // ONLY OP2 IS CONSTANT
1338          return multiplyByConstant(regpool, s, op1, op2, opts);
1339        }
1340      }
1341    }
1342    return DefUseEffect.UNCHANGED;
1343  }
1344
1345  private static DefUseEffect multiplyByConstant(AbstractRegisterPool regpool, Instruction s, Operand op1, Operand op2, OptOptions opts) {
1346    Operator addOperator, moveOperator, negateOperator, shiftLeftOperator;
1347    ConstantOperand zero;
1348    long val2;
1349    int numBits;
1350    if (op2.isIntConstant()) {
1351      val2 = op2.asIntConstant().value;
1352      addOperator = INT_ADD;
1353      moveOperator = INT_MOVE;
1354      negateOperator = INT_NEG;
1355      shiftLeftOperator = INT_SHL;
1356      zero = IntConstantOperand.zero;
1357      numBits = 32;
1358    } else {
1359      val2 = op2.asLongConstant().value;
1360      addOperator = LONG_ADD;
1361      moveOperator = LONG_MOVE;
1362      negateOperator = LONG_NEG;
1363      shiftLeftOperator = LONG_SHL;
1364      zero = LongConstantOperand.zero;
1365      numBits = 64;
1366    }
1367    // ATTEMPT TO APPLY AXIOMS
1368    if (val2 == 0) {                  // x * 0 == 0
1369      Move.mutate(s, moveOperator, Binary.getClearResult(s), zero.copy());
1370      return DefUseEffect.MOVE_FOLDED;
1371    } else if (numBits == 32 && ((int)val2 == ((int)-val2))) { // x * MIN_INT == x << 31
1372      Binary.mutate(s, INT_SHL, Binary.getClearResult(s), op1, IC(31));
1373      return DefUseEffect.REDUCED;
1374    } else if (numBits == 64 && val2 == -val2) { // x * MIN_LONG == x << 63
1375      Binary.mutate(s, LONG_SHL, Binary.getClearResult(s), op1, IC(63));
1376      return DefUseEffect.REDUCED;
1377    }
1378    // Try to reduce x*c into shift and adds, but only if cost is cheap
1379    if (s.hasPrev()) {
1380      // don't attempt to reduce if this instruction isn't
1381      // part of a well-formed sequence
1382
1383      // Cost of shift and add replacement
1384      int cost = 0;
1385      boolean negative = val2 < 0;
1386      if (negative) {
1387        val2 = -val2;
1388        cost++;
1389      }
1390      if (VM.BuildForIA32 && numBits <= BITS_IN_ADDRESS) {
1391        int lastShift = 0;
1392        boolean lastShiftWasShort = false;
1393        for (int i = 1; i < numBits; i++) {
1394          if ((val2 & (1L << i)) != 0) {
1395            // LEA shift and add uses 1 instruction, try to determine if we can
1396            // use in favour to separate shift and adds
1397            // NB LEA shift needs to be of size 1, 2 or 3 and if the last
1398            // shift used an LEA then the add can't be merged
1399            // (so we can allow better ILP by just using a regular shift of
1400            // the original operand)
1401            if (i < 4) {
1402              // can use LEA of operand
1403              cost++;
1404            } else if ((i - lastShift) < 4 && !lastShiftWasShort) {
1405              // can use LEA of last shift
1406              cost++;
1407              lastShiftWasShort = true;
1408            } else {
1409              // need separate shift and add
1410              cost += 2;
1411              lastShiftWasShort = false;
1412            }
1413            lastShift = i;
1414          }
1415        }
1416      } else if (numBits > BITS_IN_ADDRESS) {
1417        for (int i = 1; i < BITS_IN_ADDRESS; i++) {
1418          if ((val2 & (1L << i)) != 0) {
1419            // each 1 requires a shift and add
1420            cost += 2;
1421          }
1422        }
1423        for (int i = BITS_IN_ADDRESS; i < numBits; i++) {
1424          if ((val2 & (1L << i)) != 0) {
1425            // when the shift is > than the bits in the address we can just 0
1426            // the bottom word, make the cost cheaper
1427            cost++;
1428          }
1429        }
1430      } else {
1431        for (int i = 1; i < numBits; i++) {
1432          if ((val2 & (1L << i)) != 0) {
1433            // each 1 requires a shift and add
1434            cost += 2;
1435          }
1436        }
1437      }
1438      int targetCost;
1439      if (VM.BuildForIA32) {
1440        targetCost = numBits == 64 ? 6 : 4;
1441      } else {
1442        targetCost = 2;
1443      }
1444      if (cost <= targetCost) {
1445        // generate shift and adds
1446        RegisterOperand val1Operand = op1.asRegister();
1447        RegisterOperand resultOperand = numBits == 32 ? regpool.makeTempInt() : regpool.makeTempLong();
1448        Instruction move;
1449        if ((val2 & 1) == 1) {
1450          // result = val1 * 1
1451          move = Move.create(moveOperator, resultOperand, val1Operand);
1452        } else {
1453          // result = 0
1454          move = Move.create(moveOperator, resultOperand, zero.copy());
1455        }
1456        move.copyPosition(s);
1457        s.insertBefore(move);
1458        int lastShift = 0;
1459        RegisterOperand lastShiftResult = null;
1460        boolean lastShiftWasShort = false;
1461        for (int i = 1; i < numBits; i++) {
1462          if ((val2 & (1L << i)) != 0) {
1463            Instruction shift;
1464            RegisterOperand shiftResult = numBits == 32 ? regpool.makeTempInt() : regpool.makeTempLong();
1465            if (VM.BuildForIA32 && numBits <= BITS_IN_ADDRESS &&
1466                lastShiftResult != null && ((i - lastShift) <= 3) && (i > 3) && !lastShiftWasShort) {
1467              // We can produce a short shift (1, 2 or 3) using the result of the last shift
1468              shift = Binary.create(shiftLeftOperator, shiftResult, lastShiftResult.copyRO(), IC(i - lastShift));
1469              lastShiftWasShort = true;
1470            } else {
1471              shift = Binary.create(shiftLeftOperator, shiftResult, val1Operand.copyRO(), IC(i));
1472              lastShiftWasShort = false;
1473            }
1474            shift.copyPosition(s);
1475            s.insertBefore(shift);
1476            lastShiftResult = shiftResult;
1477            lastShift = i;
1478            RegisterOperand addResult = numBits == 32 ? regpool.makeTempInt() : regpool.makeTempLong();
1479            Instruction add = Binary.create(addOperator, addResult, resultOperand.copyRO(), shiftResult.copyRO());
1480            add.copyPosition(s);
1481            s.insertBefore(add);
1482            resultOperand = addResult;
1483          }
1484        }
1485        if (negative) {
1486          Unary.mutate(s, negateOperator, Binary.getClearResult(s), resultOperand.copyRO());
1487        } else {
1488          Move.mutate(s, moveOperator, Binary.getClearResult(s), resultOperand.copyRO());
1489        }
1490        return DefUseEffect.REDUCED;
1491      }
1492    }
1493    return DefUseEffect.UNCHANGED;
1494  }
1495
1496  private static DefUseEffect intNeg(Instruction s, OptOptions opts) {
1497    if (opts.SIMPLIFY_INTEGER_OPS) {
1498      Operand op = Unary.getVal(s);
1499      if (op.isIntConstant()) {
1500        // CONSTANT: FOLD
1501        int val = op.asIntConstant().value;
1502        Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC(-val));
1503        return DefUseEffect.MOVE_FOLDED;
1504      }
1505    }
1506    return DefUseEffect.UNCHANGED;
1507  }
1508
1509  private static DefUseEffect intNot(Instruction s, OptOptions opts) {
1510    if (opts.SIMPLIFY_INTEGER_OPS) {
1511      Operand op = Unary.getVal(s);
1512      if (op.isIntConstant()) {
1513        // CONSTANT: FOLD
1514        int val = op.asIntConstant().value;
1515        Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC(~val));
1516        return DefUseEffect.MOVE_FOLDED;
1517      }
1518    }
1519    return DefUseEffect.UNCHANGED;
1520  }
1521
1522  private static DefUseEffect intOr(Instruction s, OptOptions opts) {
1523    if (opts.SIMPLIFY_INTEGER_OPS) {
1524      canonicalizeCommutativeOperator(s);
1525      Operand op1 = Binary.getVal1(s);
1526      Operand op2 = Binary.getVal2(s);
1527      if (op1.similar(op2)) {
1528        // THE SAME OPERAND: x | x == x
1529        Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
1530        return op1.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED;
1531      }
1532      if (op2.isIntConstant()) {
1533        int val2 = op2.asIntConstant().value;
1534        if (op1.isIntConstant()) {
1535          // BOTH CONSTANTS: FOLD
1536          int val1 = op1.asIntConstant().value;
1537          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 | val2));
1538          return DefUseEffect.MOVE_FOLDED;
1539        } else {
1540          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
1541          if (val2 == -1) { // x | -1 == x | 0xffffffff == 0xffffffff == -1
1542            Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(-1));
1543            return DefUseEffect.MOVE_FOLDED;
1544          }
1545          if (val2 == 0) {                  // x | 0 == x
1546            Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
1547            return DefUseEffect.MOVE_REDUCED;
1548          }
1549        }
1550      }
1551    }
1552    return DefUseEffect.UNCHANGED;
1553  }
1554
1555  private static DefUseEffect intRem(Instruction s, OptOptions opts) {
1556    if (opts.SIMPLIFY_INTEGER_OPS) {
1557      Operand op1 = GuardedBinary.getVal1(s);
1558      Operand op2 = GuardedBinary.getVal2(s);
1559      if (op1.similar(op2)) {
1560        // THE SAME OPERAND: x % x == 0
1561        Move.mutate(s, INT_MOVE, GuardedBinary.getClearResult(s), IC(0));
1562        return DefUseEffect.MOVE_FOLDED;
1563      }
1564      if (op2.isIntConstant()) {
1565        int val2 = op2.asIntConstant().value;
1566        if (val2 == 0) {
1567          // TODO: This instruction is actually unreachable.
1568          // There will be an INT_ZERO_CHECK
1569          // guarding this instruction that will result in an
1570          // ArithmeticException.  We
1571          // should probably just remove the INT_REM as dead code.
1572          return DefUseEffect.UNCHANGED;
1573        }
1574        if (op1.isIntConstant()) {
1575          // BOTH CONSTANTS: FOLD
1576          int val1 = op1.asIntConstant().value;
1577          Move.mutate(s, INT_MOVE, GuardedBinary.getClearResult(s), IC(val1 % val2));
1578          return DefUseEffect.MOVE_FOLDED;
1579        } else {
1580          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
1581          if ((val2 == 1) || (val2 == -1)) {             // x % 1 == 0
1582            Move.mutate(s, INT_MOVE, GuardedBinary.getClearResult(s), IC(0));
1583            return DefUseEffect.MOVE_FOLDED;
1584          }
1585        }
1586      }
1587    }
1588    return DefUseEffect.UNCHANGED;
1589  }
1590
1591  private static DefUseEffect intShl(Instruction s, OptOptions opts) {
1592    if (opts.SIMPLIFY_INTEGER_OPS) {
1593      Operand op2 = Binary.getVal2(s);
1594      Operand op1 = Binary.getVal1(s);
1595      if (op2.isIntConstant()) {
1596        int val2 = op2.asIntConstant().value;
1597        if (op1.isIntConstant()) {
1598          // BOTH CONSTANTS: FOLD
1599          int val1 = op1.asIntConstant().value;
1600          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 << val2));
1601          return DefUseEffect.MOVE_FOLDED;
1602        } else {
1603          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
1604          if (val2 == 0) {                  // x << 0 == x
1605            Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
1606            return DefUseEffect.MOVE_REDUCED;
1607          }
1608          if ((val2 >= BITS_IN_INT) || (val2 < 0)) {  // x << 32 == 0
1609            Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0));
1610            return DefUseEffect.MOVE_FOLDED;
1611          }
1612        }
1613      } else if (op1.isIntConstant()) {
1614        int val1 = op1.asIntConstant().value;
1615        // ONLY OP1 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
1616        if (val1 == 0) {                  // 0 << x == 0
1617          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0));
1618          return DefUseEffect.MOVE_FOLDED;
1619        }
1620      }
1621    }
1622    return DefUseEffect.UNCHANGED;
1623  }
1624
1625  private static DefUseEffect intShr(Instruction s, OptOptions opts) {
1626    if (opts.SIMPLIFY_INTEGER_OPS) {
1627      Operand op1 = Binary.getVal1(s);
1628      Operand op2 = Binary.getVal2(s);
1629      if (op2.isIntConstant()) {
1630        int val2 = op2.asIntConstant().value;
1631        if (op1.isIntConstant()) {
1632          // BOTH CONSTANTS: FOLD
1633          int val1 = op1.asIntConstant().value;
1634          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 >> val2));
1635          return DefUseEffect.MOVE_FOLDED;
1636        } else {
1637          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
1638          if (val2 == 0) {                  // x >> 0 == x
1639            Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
1640            return DefUseEffect.MOVE_REDUCED;
1641          }
1642          if ((val2 >= BITS_IN_INT) || (val2 < 0)) { // x >> 32 == x >> 31
1643            Binary.setVal2(s, IC(31));
1644            return DefUseEffect.UNCHANGED;
1645          }
1646        }
1647      } else if (op1.isIntConstant()) {
1648        int val1 = op1.asIntConstant().value;
1649        // ONLY OP1 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
1650        if ((val1 == -1) || (val1 == 0)) { // -1 >> x == -1,0 >> x == 0
1651          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), op1);
1652          return DefUseEffect.MOVE_FOLDED;
1653        }
1654      }
1655    }
1656    return DefUseEffect.UNCHANGED;
1657  }
1658
1659  private static DefUseEffect intSub(Instruction s, OptOptions opts) {
1660    if (opts.SIMPLIFY_INTEGER_OPS) {
1661      Operand op1 = Binary.getVal1(s);
1662      Operand op2 = Binary.getVal2(s);
1663      if (op1.similar(op2)) {
1664        // THE SAME OPERAND: x - x == 0
1665        Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0));
1666        return DefUseEffect.MOVE_FOLDED;
1667      }
1668      if (op2.isIntConstant()) {
1669        int val2 = op2.asIntConstant().value;
1670        if (op1.isIntConstant()) {
1671          // BOTH CONSTANTS: FOLD
1672          int val1 = op1.asIntConstant().value;
1673          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 - val2));
1674          return DefUseEffect.MOVE_FOLDED;
1675        } else {
1676          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
1677          if (val2 == 0) {                  // x - 0 == x
1678            Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
1679            return DefUseEffect.MOVE_REDUCED;
1680          }
1681          // x - c = x + -c
1682          // prefer adds, since some architectures have addi but not subi, also
1683          // add is commutative and gives greater flexibility to LIR/MIR phases
1684          // without possibly introducing temporary variables
1685          Binary.mutate(s, INT_ADD, Binary.getClearResult(s), Binary.getClearVal1(s), IC(-val2));
1686          return DefUseEffect.REDUCED;
1687        }
1688      } else if (op1.isIntConstant() && (op1.asIntConstant().value == 0)) {
1689        Unary.mutate(s, INT_NEG, Binary.getClearResult(s), Binary.getClearVal2(s));
1690        return DefUseEffect.REDUCED;
1691      }
1692    }
1693    return DefUseEffect.UNCHANGED;
1694  }
1695
1696  private static DefUseEffect intUshr(Instruction s, OptOptions opts) {
1697    if (opts.SIMPLIFY_INTEGER_OPS) {
1698      Operand op2 = Binary.getVal2(s);
1699      Operand op1 = Binary.getVal1(s);
1700      if (op2.isIntConstant()) {
1701        int val2 = op2.asIntConstant().value;
1702        if (op1.isIntConstant()) {
1703          // BOTH CONSTANTS: FOLD
1704          int val1 = op1.asIntConstant().value;
1705          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 >>> val2));
1706          return DefUseEffect.MOVE_FOLDED;
1707        } else {
1708          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
1709          if (val2 == 0) {                  // x >>> 0 == x
1710            Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
1711            return DefUseEffect.MOVE_REDUCED;
1712          }
1713          if ((val2 >= BITS_IN_INT) || (val2 < 0)) { // x >>> 32 == 0
1714            Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0));
1715            return DefUseEffect.MOVE_FOLDED;
1716          }
1717        }
1718      } else if (op1.isIntConstant()) {
1719        int val1 = op1.asIntConstant().value;
1720        // ONLY OP1 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
1721        if (val1 == 0) {                  // 0 >>> x == 0
1722          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0));
1723          return DefUseEffect.MOVE_FOLDED;
1724        }
1725      }
1726    }
1727    return DefUseEffect.UNCHANGED;
1728  }
1729
1730  private static DefUseEffect intXor(Instruction s, OptOptions opts) {
1731    if (opts.SIMPLIFY_INTEGER_OPS) {
1732      canonicalizeCommutativeOperator(s);
1733      Operand op1 = Binary.getVal1(s);
1734      Operand op2 = Binary.getVal2(s);
1735      if (op1.similar(op2)) {
1736        // THE SAME OPERAND: x ^ x == 0
1737        Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0));
1738        return DefUseEffect.MOVE_FOLDED;
1739      }
1740      if (op2.isIntConstant()) {
1741        int val2 = op2.asIntConstant().value;
1742
1743        if (op1.isIntConstant()) {
1744          // BOTH CONSTANTS: FOLD
1745          int val1 = op1.asIntConstant().value;
1746          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 ^ val2));
1747          return DefUseEffect.MOVE_FOLDED;
1748        } else {
1749          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
1750          if (val2 == -1) {                 // x ^ -1 == x ^ 0xffffffff = ~x
1751            Unary.mutate(s, INT_NOT, Binary.getClearResult(s), Binary.getClearVal1(s));
1752            return DefUseEffect.REDUCED;
1753          }
1754          if (val2 == 0) {                  // x ^ 0 == x
1755            Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
1756            return DefUseEffect.MOVE_REDUCED;
1757          }
1758        }
1759      }
1760    }
1761    return DefUseEffect.UNCHANGED;
1762  }
1763
1764  private static DefUseEffect refAdd(Instruction s, OptOptions opts) {
1765    if (opts.SIMPLIFY_REF_OPS) {
1766      canonicalizeCommutativeOperator(s);
1767      Operand op2 = Binary.getVal2(s);
1768      if (op2.isConstant() && !op2.isMovableObjectConstant()) {
1769        Address val2 = getAddressValue(op2);
1770        Operand op1 = Binary.getVal1(s);
1771        if (op1.isConstant() && !op1.isMovableObjectConstant()) {
1772          // BOTH CONSTANTS: FOLD
1773          Address val1 = getAddressValue(op1);
1774          Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(val1.plus(val2.toWord().toOffset())));
1775          return DefUseEffect.MOVE_FOLDED;
1776        } else {
1777          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
1778          if (val2.isZero()) {                 // x + 0 == x
1779            if (op1.isIntLike()) {
1780              Unary.mutate(s, INT_2ADDRSigExt, Binary.getClearResult(s), Binary.getClearVal1(s));
1781              return DefUseEffect.REDUCED;
1782            } else {
1783              Move.mutate(s, REF_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
1784              return op1.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED;
1785            }
1786          }
1787        }
1788      } else {
1789        Operand op1 = Binary.getVal1(s);
1790        if (op1.similar(op2)) {
1791          // Adding something to itself is the same as a multiply by 2 so
1792          // canonicalize as a shift left
1793          Binary.mutate(s, REF_SHL, Binary.getClearResult(s), op1, IC(1));
1794          return DefUseEffect.UNCHANGED;
1795        }
1796      }
1797    }
1798    return DefUseEffect.UNCHANGED;
1799  }
1800
1801  private static DefUseEffect refAnd(Instruction s, OptOptions opts) {
1802    if (opts.SIMPLIFY_REF_OPS) {
1803      canonicalizeCommutativeOperator(s);
1804      Operand op1 = Binary.getVal1(s);
1805      Operand op2 = Binary.getVal2(s);
1806      if (op1.similar(op2)) {
1807        // THE SAME OPERAND: x & x == x
1808        Move.mutate(s, REF_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
1809        return op1.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED;
1810      }
1811      if (op2.isConstant() && !op2.isMovableObjectConstant()) {
1812        Word val2 = getAddressValue(op2).toWord();
1813        if (op1.isConstant() && !op1.isMovableObjectConstant()) {
1814          // BOTH CONSTANTS: FOLD
1815          Word val1 = getAddressValue(op1).toWord();
1816          Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(val1.and(val2).toAddress()));
1817          return DefUseEffect.MOVE_FOLDED;
1818        } else {
1819          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
1820          if (val2.isZero()) {                  // x & 0 == 0
1821            Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(Address.zero()));
1822            return DefUseEffect.MOVE_FOLDED;
1823          }
1824          if (val2.isMax()) {                 // x & -1 == x & 0xffffffff == x
1825            Move.mutate(s, REF_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
1826            return DefUseEffect.MOVE_REDUCED;
1827          }
1828        }
1829      }
1830    }
1831    return DefUseEffect.UNCHANGED;
1832  }
1833
1834  private static DefUseEffect refShl(Instruction s, OptOptions opts) {
1835    if (opts.SIMPLIFY_REF_OPS) {
1836      Operand op2 = Binary.getVal2(s);
1837      Operand op1 = Binary.getVal1(s);
1838      if (op2.isIntConstant()) {
1839        int val2 = op2.asIntConstant().value;
1840        if (op1.isConstant() && !op1.isMovableObjectConstant()) {
1841          // BOTH CONSTANTS: FOLD
1842          Word val1 = getAddressValue(op1).toWord();
1843          Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(val1.lsh(val2).toAddress()));
1844          return DefUseEffect.MOVE_FOLDED;
1845        } else {
1846          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
1847          if (val2 == 0) {                  // x << 0 == x
1848            Move.mutate(s, REF_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
1849            return DefUseEffect.MOVE_REDUCED;
1850          }
1851          if ((val2 >= BITS_IN_ADDRESS) || (val2 < 0)) { // x << 32 == 0
1852            Move.mutate(s, REF_MOVE, Binary.getClearResult(s), IC(0));
1853            return DefUseEffect.MOVE_FOLDED;
1854          }
1855        }
1856      } else if (op1.isConstant() && !op1.isMovableObjectConstant()) {
1857        Word val1 = getAddressValue(op1).toWord();
1858        // ONLY OP1 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
1859        if (val1.isZero()) {                  // 0 << x == 0
1860          Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(Address.zero()));
1861          return DefUseEffect.MOVE_FOLDED;
1862        }
1863      }
1864    }
1865    return DefUseEffect.UNCHANGED;
1866  }
1867
1868  private static DefUseEffect refShr(Instruction s, OptOptions opts) {
1869    if (opts.SIMPLIFY_REF_OPS) {
1870      Operand op1 = Binary.getVal1(s);
1871      Operand op2 = Binary.getVal2(s);
1872      if (op2.isIntConstant()) {
1873        int val2 = op2.asIntConstant().value;
1874        if (op1.isConstant() && !op1.isMovableObjectConstant()) {
1875          // BOTH CONSTANTS: FOLD
1876          Word val1 = getAddressValue(op1).toWord();
1877          Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(val1.rsha(val2).toAddress()));
1878          return DefUseEffect.MOVE_FOLDED;
1879        } else {
1880          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
1881          if (val2 == 0) {                  // x >> 0 == x
1882            Move.mutate(s, REF_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
1883            return DefUseEffect.MOVE_REDUCED;
1884          }
1885          if ((val2 >= BITS_IN_ADDRESS) || (val2 < 0)) { // x >> 32 == x >> 31
1886            Binary.setVal2(s, IC(BITS_IN_ADDRESS - 1));
1887            return DefUseEffect.UNCHANGED;
1888          }
1889        }
1890      } else if (op1.isConstant() && !op1.isMovableObjectConstant()) {
1891        Word val1 = getAddressValue(op1).toWord();
1892        // ONLY OP1 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
1893        // -1 >> x == -1, 0 >> x == 0
1894        if (val1.EQ(Word.zero()) || val1.EQ(Word.zero().minus(Word.one()))) {
1895          Move.mutate(s, REF_MOVE, Binary.getClearResult(s), op1);
1896          return DefUseEffect.MOVE_FOLDED;
1897        }
1898      }
1899    }
1900    return DefUseEffect.UNCHANGED;
1901  }
1902
1903  private static DefUseEffect refNeg(Instruction s, OptOptions opts) {
1904    if (opts.SIMPLIFY_REF_OPS) {
1905      Operand op = Unary.getVal(s);
1906      if (op.isConstant() && !op.isMovableObjectConstant()) {
1907        // CONSTANT: FOLD
1908        Word val = getAddressValue(op).toWord();
1909        Word negVal = Word.zero().minus(val);
1910        Move.mutate(s, REF_MOVE, Unary.getClearResult(s), AC(negVal.toAddress()));
1911        return DefUseEffect.MOVE_FOLDED;
1912      }
1913    }
1914    return DefUseEffect.UNCHANGED;
1915  }
1916
1917  private static DefUseEffect refNot(Instruction s, OptOptions opts) {
1918    if (opts.SIMPLIFY_REF_OPS) {
1919      Operand op = Unary.getVal(s);
1920      if (op.isConstant() && !op.isMovableObjectConstant()) {
1921        // CONSTANT: FOLD
1922        Word val = getAddressValue(op).toWord();
1923        Move.mutate(s, REF_MOVE, Unary.getClearResult(s), AC(val.not().toAddress()));
1924        return DefUseEffect.MOVE_FOLDED;
1925      }
1926    }
1927    return DefUseEffect.UNCHANGED;
1928  }
1929
1930  private static DefUseEffect refOr(Instruction s, OptOptions opts) {
1931    if (opts.SIMPLIFY_REF_OPS) {
1932      canonicalizeCommutativeOperator(s);
1933      Operand op1 = Binary.getVal1(s);
1934      Operand op2 = Binary.getVal2(s);
1935      if (op1.similar(op2)) {
1936        // THE SAME OPERAND: x | x == x
1937        Move.mutate(s, REF_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
1938        return op1.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED;
1939      }
1940      if (op2.isConstant() && !op2.isMovableObjectConstant()) {
1941        Word val2 = getAddressValue(op2).toWord();
1942        if (op1.isAddressConstant()) {
1943          // BOTH CONSTANTS: FOLD
1944          Word val1 = getAddressValue(op1).toWord();
1945          Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(val1.or(val2).toAddress()));
1946          return DefUseEffect.MOVE_FOLDED;
1947        } else {
1948          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
1949          if (val2.isMax()) { // x | -1 == x | 0xffffffff == 0xffffffff == -1
1950            Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(Address.max()));
1951            return DefUseEffect.MOVE_FOLDED;
1952          }
1953          if (val2.isZero()) {                  // x | 0 == x
1954            Move.mutate(s, REF_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
1955            return DefUseEffect.MOVE_REDUCED;
1956          }
1957        }
1958      }
1959    }
1960    return DefUseEffect.UNCHANGED;
1961  }
1962
1963  private static DefUseEffect refSub(Instruction s, OptOptions opts) {
1964    if (opts.SIMPLIFY_REF_OPS) {
1965      Operand op1 = Binary.getVal1(s);
1966      Operand op2 = Binary.getVal2(s);
1967      if (op1.similar(op2)) {
1968        // THE SAME OPERAND: x - x == 0
1969        Move.mutate(s, REF_MOVE, Binary.getClearResult(s), IC(0));
1970        return DefUseEffect.MOVE_FOLDED;
1971      }
1972      if (op2.isConstant() && !op2.isMovableObjectConstant()) {
1973        Address val2 = getAddressValue(op2);
1974        if (op1.isConstant() && !op1.isMovableObjectConstant()) {
1975          // BOTH CONSTANTS: FOLD
1976          Address val1 = getAddressValue(op1);
1977          Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(val1.minus(val2.toWord().toOffset())));
1978          return DefUseEffect.MOVE_FOLDED;
1979        } else {
1980          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
1981          if (val2.isZero()) {                 // x - 0 == x
1982            if (op1.isIntLike()) {
1983              Unary.mutate(s, INT_2ADDRSigExt, Binary.getClearResult(s), Binary.getClearVal1(s));
1984              return DefUseEffect.REDUCED;
1985            } else {
1986              Move.mutate(s, REF_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
1987              return op1.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED;
1988            }
1989          }
1990          // x - c = x + -c
1991          // prefer adds, since some architectures have addi but not subi
1992          Binary.mutate(s,
1993                        REF_ADD,
1994                        Binary.getClearResult(s),
1995                        Binary.getClearVal1(s),
1996                        AC(Address.zero().minus(val2.toWord().toOffset())));
1997          return DefUseEffect.REDUCED;
1998        }
1999      } else if (op1.isConstant() && !op1.isMovableObjectConstant()) {
2000        Address val1 = getAddressValue(op1);
2001        if (val1.EQ(Address.zero())) {
2002          Unary.mutate(s, REF_NEG, Binary.getClearResult(s), Binary.getClearVal2(s));
2003          return DefUseEffect.REDUCED;
2004        }
2005      }
2006    }
2007    return DefUseEffect.UNCHANGED;
2008  }
2009
2010  private static DefUseEffect refUshr(Instruction s, OptOptions opts) {
2011    if (opts.SIMPLIFY_REF_OPS) {
2012      Operand op2 = Binary.getVal2(s);
2013      Operand op1 = Binary.getVal1(s);
2014      if (op2.isIntConstant()) {
2015        int val2 = op2.asIntConstant().value;
2016        if (op1.isConstant() && !op1.isMovableObjectConstant()) {
2017          // BOTH CONSTANTS: FOLD
2018          Word val1 = getAddressValue(op1).toWord();
2019          Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(val1.rshl(val2).toAddress()));
2020          return DefUseEffect.MOVE_FOLDED;
2021        } else {
2022          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
2023          if (val2 == 0) {                  // x >>> 0 == x
2024            Move.mutate(s, REF_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
2025            return DefUseEffect.MOVE_REDUCED;
2026          }
2027          if ((val2 >= BITS_IN_ADDRESS) || (val2 < 0)) { // x >>> 32 == 0
2028            Move.mutate(s, REF_MOVE, Binary.getClearResult(s), IC(0));
2029            return DefUseEffect.MOVE_FOLDED;
2030          }
2031        }
2032      } else if (op1.isConstant() && !op1.isMovableObjectConstant()) {
2033        Word val1 = getAddressValue(op1).toWord();
2034        // ONLY OP1 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
2035        if (val1.EQ(Word.zero())) {                  // 0 >>> x == 0
2036          Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(Address.zero()));
2037          return DefUseEffect.MOVE_FOLDED;
2038        }
2039      }
2040    }
2041    return DefUseEffect.UNCHANGED;
2042  }
2043
2044  private static DefUseEffect refXor(Instruction s, OptOptions opts) {
2045    if (opts.SIMPLIFY_REF_OPS) {
2046      canonicalizeCommutativeOperator(s);
2047      Operand op1 = Binary.getVal1(s);
2048      Operand op2 = Binary.getVal2(s);
2049      if (op1.similar(op2)) {
2050        // THE SAME OPERAND: x ^ x == 0
2051        Move.mutate(s, REF_MOVE, Binary.getClearResult(s), IC(0));
2052        return DefUseEffect.MOVE_FOLDED;
2053      }
2054      if (op2.isConstant() && !op2.isMovableObjectConstant()) {
2055        Word val2 = getAddressValue(op2).toWord();
2056        if (op1.isConstant() && !op1.isMovableObjectConstant()) {
2057          // BOTH CONSTANTS: FOLD
2058          Word val1 = getAddressValue(op1).toWord();
2059          Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(val1.xor(val2).toAddress()));
2060          return DefUseEffect.MOVE_FOLDED;
2061        } else {
2062          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
2063          if (val2.isMax()) {                 // x ^ -1 == x ^ 0xffffffff = ~x
2064            Unary.mutate(s, REF_NOT, Binary.getClearResult(s), Binary.getClearVal1(s));
2065            return DefUseEffect.REDUCED;
2066          }
2067          if (val2.isZero()) {                  // x ^ 0 == x
2068            Move.mutate(s, REF_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
2069            return DefUseEffect.MOVE_REDUCED;
2070          }
2071        }
2072      }
2073    }
2074    return DefUseEffect.UNCHANGED;
2075  }
2076
2077  private static DefUseEffect longAdd(Instruction s, OptOptions opts) {
2078    if (opts.SIMPLIFY_LONG_OPS) {
2079      canonicalizeCommutativeOperator(s);
2080      Operand op2 = Binary.getVal2(s);
2081      if (op2.isLongConstant()) {
2082        long val2 = op2.asLongConstant().value;
2083        Operand op1 = Binary.getVal1(s);
2084        if (op1.isLongConstant()) {
2085          // BOTH CONSTANTS: FOLD
2086          long val1 = op1.asLongConstant().value;
2087          Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(val1 + val2));
2088          return DefUseEffect.MOVE_FOLDED;
2089        } else {
2090          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
2091          if (val2 == 0L) {                 // x + 0 == x
2092            Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
2093            return DefUseEffect.MOVE_REDUCED;
2094          }
2095        }
2096      } else {
2097        Operand op1 = Binary.getVal1(s);
2098        if (op1.similar(op2)) {
2099          // Adding something to itself is the same as a multiply by 2 so
2100          // canonicalize as a shift left
2101          Binary.mutate(s, LONG_SHL, Binary.getClearResult(s), op1, IC(1));
2102          return DefUseEffect.UNCHANGED;
2103        }
2104      }
2105    }
2106    return DefUseEffect.UNCHANGED;
2107  }
2108
2109  private static DefUseEffect longAnd(Instruction s, OptOptions opts) {
2110    if (opts.SIMPLIFY_LONG_OPS) {
2111      canonicalizeCommutativeOperator(s);
2112      Operand op1 = Binary.getVal1(s);
2113      Operand op2 = Binary.getVal2(s);
2114      if (op1.similar(op2)) {
2115        // THE SAME OPERAND: x & x == x
2116        Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
2117        return op1.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED;
2118      }
2119      if (op2.isLongConstant()) {
2120        long val2 = op2.asLongConstant().value;
2121        if (op1.isLongConstant()) {
2122          // BOTH CONSTANTS: FOLD
2123          long val1 = op1.asLongConstant().value;
2124          Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(val1 & val2));
2125          return DefUseEffect.MOVE_FOLDED;
2126        } else {
2127          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
2128          if (val2 == 0L) {                 // x & 0L == 0L
2129            Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(0L));
2130            return DefUseEffect.MOVE_FOLDED;
2131          }
2132          if (val2 == -1) {                 // x & -1L == x & 0xff...ff == x
2133            Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
2134            return DefUseEffect.MOVE_REDUCED;
2135          }
2136        }
2137      }
2138    }
2139    return DefUseEffect.UNCHANGED;
2140  }
2141
2142  private static DefUseEffect longCmp(Instruction s, OptOptions opts) {
2143    if (opts.SIMPLIFY_LONG_OPS) {
2144      Operand op1 = Binary.getVal1(s);
2145      Operand op2 = Binary.getVal2(s);
2146      if (op1.similar(op2)) {
2147        // THE SAME OPERAND: op1 == op2
2148        Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0));
2149        return DefUseEffect.MOVE_FOLDED;
2150      }
2151      if (op2.isLongConstant()) {
2152        if (op1.isLongConstant()) {
2153          // BOTH CONSTANTS: FOLD
2154          long val1 = op1.asLongConstant().value;
2155          long val2 = op2.asLongConstant().value;
2156          int result = (val1 > val2) ? 1 : ((val1 == val2) ? 0 : -1);
2157          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(result));
2158          return DefUseEffect.MOVE_FOLDED;
2159        }
2160      }
2161    }
2162    return DefUseEffect.UNCHANGED;
2163  }
2164
2165  private static DefUseEffect longDiv(Instruction s, OptOptions opts) {
2166    if (opts.SIMPLIFY_LONG_OPS) {
2167      Operand op1 = GuardedBinary.getVal1(s);
2168      Operand op2 = GuardedBinary.getVal2(s);
2169      if (op1.similar(op2)) {
2170        // THE SAME OPERAND: x / x == 1
2171        Move.mutate(s, LONG_MOVE, GuardedBinary.getClearResult(s), LC(1));
2172        return DefUseEffect.MOVE_FOLDED;
2173      }
2174      if (op2.isLongConstant()) {
2175        long val2 = op2.asLongConstant().value;
2176        if (val2 == 0L) {
2177          // TODO: This instruction is actually unreachable.
2178          // There will be a LONG_ZERO_CHECK
2179          // guarding this instruction that will result in an
2180          // ArithmeticException.  We
2181          // should probably just remove the LONG_DIV as dead code.
2182          return DefUseEffect.UNCHANGED;
2183        }
2184        if (op1.isLongConstant()) {
2185          // BOTH CONSTANTS: FOLD
2186          long val1 = op1.asLongConstant().value;
2187          Move.mutate(s, LONG_MOVE, GuardedBinary.getClearResult(s), LC(val1 / val2));
2188          return DefUseEffect.MOVE_FOLDED;
2189        } else {
2190          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
2191          if (val2 == 1L) {                 // x / 1L == x
2192            Move.mutate(s, LONG_MOVE, GuardedBinary.getClearResult(s), GuardedBinary.getClearVal1(s));
2193            return DefUseEffect.MOVE_REDUCED;
2194          }
2195        }
2196      }
2197    }
2198    return DefUseEffect.UNCHANGED;
2199  }
2200  private static DefUseEffect longMul(AbstractRegisterPool regpool, Instruction s, OptOptions opts) {
2201    if (opts.SIMPLIFY_LONG_OPS) {
2202      canonicalizeCommutativeOperator(s);
2203      Operand op2 = Binary.getVal2(s);
2204      if (op2.isLongConstant()) {
2205        Operand op1 = Binary.getVal1(s);
2206        if (op1.isLongConstant()) {
2207          // BOTH CONSTANTS: FOLD
2208          long val1 = op1.asLongConstant().value;
2209          long val2 = op2.asLongConstant().value;
2210          Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(val1 * val2));
2211          return DefUseEffect.MOVE_FOLDED;
2212        } else {
2213          // ONLY OP2 IS CONSTANT
2214          return multiplyByConstant(regpool, s, op1, op2, opts);
2215        }
2216      }
2217    }
2218    return DefUseEffect.UNCHANGED;
2219  }
2220
2221  private static DefUseEffect longNeg(Instruction s, OptOptions opts) {
2222    if (opts.SIMPLIFY_LONG_OPS) {
2223      Operand op = Unary.getVal(s);
2224      if (op.isLongConstant()) {
2225        // CONSTANT: FOLD
2226        long val = op.asLongConstant().value;
2227        Move.mutate(s, LONG_MOVE, Unary.getClearResult(s), LC(-val));
2228        return DefUseEffect.MOVE_FOLDED;
2229      }
2230    }
2231    return DefUseEffect.UNCHANGED;
2232  }
2233
2234  private static DefUseEffect longNot(Instruction s, OptOptions opts) {
2235    if (opts.SIMPLIFY_LONG_OPS) {
2236      Operand op = Unary.getVal(s);
2237      if (op.isLongConstant()) {
2238        long val = op.asLongConstant().value;
2239        // CONSTANT: FOLD
2240        Move.mutate(s, LONG_MOVE, Unary.getClearResult(s), LC(~val));
2241        return DefUseEffect.MOVE_FOLDED;
2242      }
2243    }
2244    return DefUseEffect.UNCHANGED;
2245  }
2246
2247  private static DefUseEffect longOr(Instruction s, OptOptions opts) {
2248    if (opts.SIMPLIFY_LONG_OPS) {
2249      canonicalizeCommutativeOperator(s);
2250      Operand op1 = Binary.getVal1(s);
2251      Operand op2 = Binary.getVal2(s);
2252      if (op1.similar(op2)) {
2253        // THE SAME OPERAND: x | x == x
2254        Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
2255        return op1.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED;
2256      }
2257      if (op2.isLongConstant()) {
2258        long val2 = op2.asLongConstant().value;
2259        if (op1.isLongConstant()) {
2260          // BOTH CONSTANTS: FOLD
2261          long val1 = op1.asLongConstant().value;
2262          Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(val1 | val2));
2263          return DefUseEffect.MOVE_FOLDED;
2264        } else {
2265          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
2266          if (val2 == 0L) {                 // x | 0L == x
2267            Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
2268            return DefUseEffect.MOVE_REDUCED;
2269          }
2270          if (val2 == -1L) { // x | -1L == x | 0xff..ff == 0xff..ff == -1L
2271            Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(-1L));
2272            return DefUseEffect.MOVE_FOLDED;
2273          }
2274        }
2275      }
2276    }
2277    return DefUseEffect.UNCHANGED;
2278  }
2279
2280  private static DefUseEffect longRem(Instruction s, OptOptions opts) {
2281    if (opts.SIMPLIFY_LONG_OPS) {
2282      Operand op1 = GuardedBinary.getVal1(s);
2283      Operand op2 = GuardedBinary.getVal2(s);
2284      if (op1.similar(op2)) {
2285        // THE SAME OPERAND: x % x == 0
2286        Move.mutate(s, LONG_MOVE, GuardedBinary.getClearResult(s), LC(0));
2287        return DefUseEffect.MOVE_FOLDED;
2288      }
2289      if (op2.isLongConstant()) {
2290        long val2 = op2.asLongConstant().value;
2291        if (val2 == 0L) {
2292          // TODO: This instruction is actually unreachable.
2293          // There will be a LONG_ZERO_CHECK
2294          // guarding this instruction that will result in an
2295          // ArithmeticException.  We
2296          // should probably just remove the LONG_REM as dead code.
2297          return DefUseEffect.UNCHANGED;
2298        }
2299        if (op1.isLongConstant()) {
2300          // BOTH CONSTANTS: FOLD
2301          long val1 = op1.asLongConstant().value;
2302          Move.mutate(s, LONG_MOVE, GuardedBinary.getClearResult(s), LC(val1 % val2));
2303          return DefUseEffect.MOVE_FOLDED;
2304        } else {
2305          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
2306          if ((val2 == 1L) || (val2 == -1L)) {                 // x % 1L == 0
2307            Move.mutate(s, LONG_MOVE, GuardedBinary.getClearResult(s), LC(0));
2308            return DefUseEffect.MOVE_FOLDED;
2309          }
2310        }
2311      }
2312    }
2313    return DefUseEffect.UNCHANGED;
2314  }
2315
2316  private static DefUseEffect longShl(Instruction s, OptOptions opts) {
2317    if (opts.SIMPLIFY_LONG_OPS) {
2318      Operand op2 = Binary.getVal2(s);
2319      Operand op1 = Binary.getVal1(s);
2320      if (op2.isIntConstant()) {
2321        int val2 = op2.asIntConstant().value;
2322        if (op1.isLongConstant()) {
2323          // BOTH CONSTANTS: FOLD
2324          long val1 = op1.asLongConstant().value;
2325          Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(val1 << val2));
2326          return DefUseEffect.MOVE_FOLDED;
2327        } else {
2328          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
2329          if (val2 == 0) {                  // x << 0 == x
2330            Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
2331            return DefUseEffect.MOVE_REDUCED;
2332          }
2333          if ((val2 >= BITS_IN_LONG) || (val2 < 0)) { // x << 64 == 0
2334            Move.mutate(s, INT_MOVE, Binary.getClearResult(s), LC(0));
2335            return DefUseEffect.MOVE_FOLDED;
2336          }
2337        }
2338      } else if (op1.isLongConstant()) {
2339        long val1 = op1.asLongConstant().value;
2340        // ONLY OP1 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
2341        if (val1 == 0L) {                  // 0 << x == 0
2342          Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), op1);
2343          return DefUseEffect.MOVE_FOLDED;
2344        }
2345      }
2346    }
2347    return DefUseEffect.UNCHANGED;
2348  }
2349
2350  private static DefUseEffect longShr(Instruction s, OptOptions opts) {
2351    if (opts.SIMPLIFY_LONG_OPS) {
2352      Operand op1 = Binary.getVal1(s);
2353      Operand op2 = Binary.getVal2(s);
2354      if (op2.isIntConstant()) {
2355        int val2 = op2.asIntConstant().value;
2356        if (op1.isLongConstant()) {
2357          // BOTH CONSTANTS: FOLD
2358          long val1 = op1.asLongConstant().value;
2359          Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(val1 >> val2));
2360          return DefUseEffect.MOVE_FOLDED;
2361        } else {
2362          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
2363          if (val2 == 0) {                  // x >> 0L == x
2364            Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
2365            return DefUseEffect.MOVE_REDUCED;
2366          }
2367          if ((val2 >= BITS_IN_LONG) || (val2 < 0)) { // x >> 64 == x >> 63
2368            Binary.setVal2(s, LC(63));
2369            return DefUseEffect.UNCHANGED;
2370          }
2371        }
2372      } else if (op1.isLongConstant()) {
2373        long val1 = op1.asLongConstant().value;
2374        // ONLY OP1 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
2375        if ((val1 == -1L) || (val1 == 0L)) {  // -1 >> x == -1, 0 >> x == 0
2376          Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), op1);
2377          return DefUseEffect.MOVE_FOLDED;
2378        }
2379      }
2380    }
2381    return DefUseEffect.UNCHANGED;
2382  }
2383
2384  private static DefUseEffect longSub(Instruction s, OptOptions opts) {
2385    if (opts.SIMPLIFY_LONG_OPS) {
2386      Operand op1 = Binary.getVal1(s);
2387      Operand op2 = Binary.getVal2(s);
2388      if (op1.similar(op2)) {
2389        // THE SAME OPERAND: x - x == 0
2390        Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(0));
2391        return DefUseEffect.MOVE_FOLDED;
2392      }
2393      if (op2.isLongConstant()) {
2394        long val2 = op2.asLongConstant().value;
2395        if (op1.isLongConstant()) {
2396          // BOTH CONSTANTS: FOLD
2397          long val1 = op1.asLongConstant().value;
2398          Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(val1 - val2));
2399          return DefUseEffect.MOVE_FOLDED;
2400        } else {
2401          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
2402          if (val2 == 0L) {                 // x - 0 == x
2403            Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
2404            return DefUseEffect.MOVE_REDUCED;
2405          }
2406          // x - c = x + -c
2407          // prefer adds, since some architectures have addi but not subi, also
2408          // add is commutative and gives greater flexibility to LIR/MIR phases
2409          // without possibly introducing temporary variables
2410          Binary.mutate(s, LONG_ADD, Binary.getClearResult(s),
2411              Binary.getClearVal1(s), LC(-val2));
2412          return DefUseEffect.REDUCED;
2413        }
2414      } else if (op1.isLongConstant() && (op1.asLongConstant().value == 0)) {
2415        Unary.mutate(s, LONG_NEG, Binary.getClearResult(s), Binary.getClearVal2(s));
2416        return DefUseEffect.REDUCED;
2417      }
2418    }
2419    return DefUseEffect.UNCHANGED;
2420  }
2421
2422  private static DefUseEffect longUshr(Instruction s, OptOptions opts) {
2423    if (opts.SIMPLIFY_LONG_OPS) {
2424      Operand op2 = Binary.getVal2(s);
2425      Operand op1 = Binary.getVal1(s);
2426      if (op2.isIntConstant()) {
2427        int val2 = op2.asIntConstant().value;
2428        if (op1.isLongConstant()) {
2429          // BOTH CONSTANTS: FOLD
2430          long val1 = op1.asLongConstant().value;
2431          Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(val1 >>> val2));
2432          return DefUseEffect.MOVE_FOLDED;
2433        } else {
2434          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
2435          if (val2 == 0) {                  // x >>> 0L == x
2436            Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
2437            return DefUseEffect.MOVE_REDUCED;
2438          }
2439          if ((val2 >= BITS_IN_LONG) || (val2 < 0)) {  // x >>> 64 == 0
2440            Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(0));
2441            return DefUseEffect.MOVE_FOLDED;
2442          }
2443        }
2444      } else if (op1.isLongConstant()) {
2445        long val1 = op1.asLongConstant().value;
2446        // ONLY OP1 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
2447        if (val1 == 0L) {                  // 0 >>> x == 0
2448          Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), op1);
2449          return DefUseEffect.MOVE_FOLDED;
2450        }
2451      }
2452    }
2453    return DefUseEffect.UNCHANGED;
2454  }
2455
2456  private static DefUseEffect longXor(Instruction s, OptOptions opts) {
2457    if (opts.SIMPLIFY_LONG_OPS) {
2458      canonicalizeCommutativeOperator(s);
2459      Operand op1 = Binary.getVal1(s);
2460      Operand op2 = Binary.getVal2(s);
2461      if (op1.similar(op2)) {
2462        // THE SAME OPERAND: x ^ x == 0
2463        Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(0));
2464        return DefUseEffect.MOVE_FOLDED;
2465      }
2466      if (op2.isLongConstant()) {
2467        long val2 = op2.asLongConstant().value;
2468        if (op1.isLongConstant()) {
2469          // BOTH CONSTANTS: FOLD
2470          long val1 = op1.asLongConstant().value;
2471          Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(val1 ^ val2));
2472          return DefUseEffect.MOVE_FOLDED;
2473        } else {
2474          // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS
2475          if (val2 == -1L) {                // x ^ -1L == x ^ 0xff..ff = ~x
2476            Unary.mutate(s, LONG_NOT, Binary.getClearResult(s), Binary.getClearVal1(s));
2477            return DefUseEffect.REDUCED;
2478          }
2479          if (val2 == 0L) {                 // x ^ 0L == x
2480            Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
2481            return DefUseEffect.MOVE_REDUCED;
2482          }
2483        }
2484      }
2485    }
2486    return DefUseEffect.UNCHANGED;
2487  }
2488
2489  private static DefUseEffect floatAdd(Instruction s, OptOptions opts) {
2490    if (opts.SIMPLIFY_FLOAT_OPS) {
2491      canonicalizeCommutativeOperator(s);
2492      Operand op2 = Binary.getVal2(s);
2493      if (op2.isFloatConstant()) {
2494        float val2 = op2.asFloatConstant().value;
2495        Operand op1 = Binary.getVal1(s);
2496        if (op1.isFloatConstant()) {
2497          // BOTH CONSTANTS: FOLD
2498          float val1 = op1.asFloatConstant().value;
2499          Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(val1 + val2));
2500          return DefUseEffect.MOVE_FOLDED;
2501        }
2502        if (val2 == 0.0f) {
2503          // x + 0.0 is x (even is x is a NaN).
2504          Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
2505          return DefUseEffect.MOVE_REDUCED;
2506        }
2507        if (Float.isNaN(val2)) {
2508          // x + NaN is NaN
2509          Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(Float.NaN));
2510          return DefUseEffect.MOVE_FOLDED;
2511        }
2512      }
2513    }
2514    return DefUseEffect.UNCHANGED;
2515  }
2516
2517  private static DefUseEffect floatCmpg(Instruction s, OptOptions opts) {
2518    if (opts.SIMPLIFY_FLOAT_OPS) {
2519      Operand op1 = Binary.getVal1(s);
2520      Operand op2 = Binary.getVal2(s);
2521      if (op2.isFloatConstant()) {
2522        float val2 = op2.asFloatConstant().value;
2523        if (op1.isFloatConstant()) {
2524          // BOTH CONSTANTS: FOLD
2525          float val1 = op1.asFloatConstant().value;
2526          int result = (val1 < val2) ? -1 : ((val1 == val2) ? 0 : 1);
2527          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(result));
2528          return DefUseEffect.MOVE_FOLDED;
2529        }
2530        if (Float.isNaN(val2)) {
2531          // result is unordered => 1
2532          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(1));
2533          return DefUseEffect.MOVE_FOLDED;
2534        }
2535      }
2536      if (op1.isFloatConstant()) {
2537        float val1 = op1.asFloatConstant().value;
2538        if (Float.isNaN(val1)) {
2539          // result is unordered => 1
2540          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(1));
2541          return DefUseEffect.MOVE_FOLDED;
2542        }
2543      }
2544    }
2545    return DefUseEffect.UNCHANGED;
2546  }
2547
2548  private static DefUseEffect floatCmpl(Instruction s, OptOptions opts) {
2549    if (opts.SIMPLIFY_FLOAT_OPS) {
2550      Operand op1 = Binary.getVal1(s);
2551      Operand op2 = Binary.getVal2(s);
2552      if (op2.isFloatConstant()) {
2553        float val2 = op2.asFloatConstant().value;
2554        if (op1.isFloatConstant()) {
2555          // BOTH CONSTANTS: FOLD
2556          float val1 = op1.asFloatConstant().value;
2557          int result = (val1 > val2) ? 1 : ((val1 == val2) ? 0 : -1);
2558          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(result));
2559          return DefUseEffect.MOVE_FOLDED;
2560        }
2561        if (Float.isNaN(val2)) {
2562          // result is unordered => -1
2563          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(-1));
2564          return DefUseEffect.MOVE_FOLDED;
2565        }
2566      }
2567      if (op1.isFloatConstant()) {
2568        float val1 = op1.asFloatConstant().value;
2569        if (Float.isNaN(val1)) {
2570          // result is unordered => -1
2571          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(-1));
2572          return DefUseEffect.MOVE_FOLDED;
2573        }
2574      }
2575    }
2576    return DefUseEffect.UNCHANGED;
2577  }
2578
2579  private static DefUseEffect floatDiv(Instruction s, OptOptions opts) {
2580    if (opts.SIMPLIFY_FLOAT_OPS) {
2581      Operand op1 = Binary.getVal1(s);
2582      Operand op2 = Binary.getVal2(s);
2583      if (op2.isFloatConstant()) {
2584        float val2 = op2.asFloatConstant().value;
2585        if (op1.isFloatConstant()) {
2586          // BOTH CONSTANTS: FOLD
2587          float val1 = op1.asFloatConstant().value;
2588          Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(val1 / val2));
2589          return DefUseEffect.MOVE_FOLDED;
2590        }
2591        if (Float.isNaN(val2)) {
2592          // x / NaN is NaN
2593          Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(Float.NaN));
2594          return DefUseEffect.MOVE_FOLDED;
2595        }
2596      }
2597      if (op1.isFloatConstant()) {
2598        float val1 = op1.asFloatConstant().value;
2599        if (Float.isNaN(val1)) {
2600          // NaN / x is NaN
2601          Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(Float.NaN));
2602          return DefUseEffect.MOVE_FOLDED;
2603        }
2604      }
2605    }
2606    return DefUseEffect.UNCHANGED;
2607  }
2608
2609  private static DefUseEffect floatMul(Instruction s, OptOptions opts) {
2610    if (opts.SIMPLIFY_FLOAT_OPS) {
2611      canonicalizeCommutativeOperator(s);
2612      Operand op2 = Binary.getVal2(s);
2613      if (op2.isFloatConstant()) {
2614        float val2 = op2.asFloatConstant().value;
2615        Operand op1 = Binary.getVal1(s);
2616        if (op1.isFloatConstant()) {
2617          // BOTH CONSTANTS: FOLD
2618          float val1 = op1.asFloatConstant().value;
2619          Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(val1 * val2));
2620          return DefUseEffect.MOVE_FOLDED;
2621        }
2622        if (val2 == 1.0f) {
2623          // x * 1.0 is x, even if x is a NaN
2624          Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
2625          return DefUseEffect.MOVE_REDUCED;
2626        }
2627        if (Float.isNaN(val2)) {
2628          // x * NaN is NaN
2629          Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(Float.NaN));
2630          return DefUseEffect.MOVE_FOLDED;
2631        }
2632      }
2633    }
2634    return DefUseEffect.UNCHANGED;
2635  }
2636
2637  private static DefUseEffect floatNeg(Instruction s, OptOptions opts) {
2638    if (opts.SIMPLIFY_FLOAT_OPS) {
2639      Operand op = Unary.getVal(s);
2640      if (op.isFloatConstant()) {
2641        // CONSTANT: FOLD
2642        float val = op.asFloatConstant().value;
2643        Move.mutate(s, FLOAT_MOVE, Unary.getClearResult(s), FC(-val));
2644        return DefUseEffect.MOVE_FOLDED;
2645      }
2646    }
2647    return DefUseEffect.UNCHANGED;
2648  }
2649
2650  private static DefUseEffect floatRem(Instruction s, OptOptions opts) {
2651    if (opts.SIMPLIFY_FLOAT_OPS) {
2652      Operand op1 = Binary.getVal1(s);
2653      Operand op2 = Binary.getVal2(s);
2654      if (op2.isFloatConstant()) {
2655        float val2 = op2.asFloatConstant().value;
2656        if (op1.isFloatConstant()) {
2657          // BOTH CONSTANTS: FOLD
2658          float val1 = op1.asFloatConstant().value;
2659          Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(val1 % val2));
2660          return DefUseEffect.MOVE_FOLDED;
2661        }
2662        if (Float.isNaN(val2)) {
2663          // x % NaN is NaN
2664          Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(Float.NaN));
2665          return DefUseEffect.MOVE_FOLDED;
2666        }
2667      }
2668      if (op1.isFloatConstant()) {
2669        float val1 = op1.asFloatConstant().value;
2670        if (Float.isNaN(val1)) {
2671          // NaN % x is NaN
2672          Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(Float.NaN));
2673          return DefUseEffect.MOVE_FOLDED;
2674        }
2675      }
2676    }
2677    return DefUseEffect.UNCHANGED;
2678  }
2679
2680  private static DefUseEffect floatSub(Instruction s, OptOptions opts) {
2681    if (opts.SIMPLIFY_FLOAT_OPS) {
2682      Operand op1 = Binary.getVal1(s);
2683      Operand op2 = Binary.getVal2(s);
2684      if (op2.isFloatConstant()) {
2685        float val2 = op2.asFloatConstant().value;
2686        if (op1.isFloatConstant()) {
2687          // BOTH CONSTANTS: FOLD
2688          float val1 = op1.asFloatConstant().value;
2689          Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(val1 - val2));
2690          return DefUseEffect.MOVE_FOLDED;
2691        }
2692        if (val2 == 0.0f) {
2693          // x - 0.0 is x, even if x is a NaN
2694          Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
2695          return DefUseEffect.MOVE_REDUCED;
2696        }
2697        if (Float.isNaN(val2)) {
2698          // x - NaN is NaN
2699          Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(Float.NaN));
2700          return DefUseEffect.MOVE_FOLDED;
2701        }
2702      }
2703      if (op1.isFloatConstant()) {
2704        float val1 = op1.asFloatConstant().value;
2705        if (val1 == 0.0f) {
2706          // 0.0 - x is -x
2707          Unary.mutate(s, FLOAT_NEG, Binary.getClearResult(s), Binary.getClearVal2(s));
2708          return DefUseEffect.REDUCED;
2709        }
2710        if (Float.isNaN(val1)) {
2711          // x - NaN is NaN
2712          Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(Float.NaN));
2713          return DefUseEffect.MOVE_FOLDED;
2714        }
2715      }
2716    }
2717    return DefUseEffect.UNCHANGED;
2718  }
2719
2720  private static DefUseEffect floatSqrt(Instruction s, OptOptions opts) {
2721    if (opts.SIMPLIFY_FLOAT_OPS) {
2722      Operand op = Unary.getVal(s);
2723      if (op.isFloatConstant()) {
2724        // CONSTANT: FOLD
2725        float val = op.asFloatConstant().value;
2726        Move.mutate(s, FLOAT_MOVE, Unary.getClearResult(s), FC((float)Math.sqrt(val)));
2727        return DefUseEffect.MOVE_FOLDED;
2728      }
2729    }
2730    return DefUseEffect.UNCHANGED;
2731  }
2732
2733  private static DefUseEffect doubleAdd(Instruction s, OptOptions opts) {
2734    if (opts.SIMPLIFY_DOUBLE_OPS) {
2735      canonicalizeCommutativeOperator(s);
2736      Operand op2 = Binary.getVal2(s);
2737      if (op2.isDoubleConstant()) {
2738        double val2 = op2.asDoubleConstant().value;
2739        Operand op1 = Binary.getVal1(s);
2740        if (op1.isDoubleConstant()) {
2741          // BOTH CONSTANTS: FOLD
2742          double val1 = op1.asDoubleConstant().value;
2743          Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(val1 + val2));
2744          return DefUseEffect.MOVE_FOLDED;
2745        }
2746        if (val2 == 0.0) {
2747          // x + 0.0 is x, even if x is a NaN
2748          Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
2749          return DefUseEffect.MOVE_REDUCED;
2750        }
2751        if (Double.isNaN(val2)) {
2752          // x + NaN is NaN
2753          Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(Double.NaN));
2754          return DefUseEffect.MOVE_FOLDED;
2755        }
2756      }
2757    }
2758    return DefUseEffect.UNCHANGED;
2759  }
2760
2761  private static DefUseEffect doubleCmpg(Instruction s, OptOptions opts) {
2762    if (opts.SIMPLIFY_DOUBLE_OPS) {
2763      Operand op1 = Binary.getVal1(s);
2764      Operand op2 = Binary.getVal2(s);
2765      if (op2.isDoubleConstant()) {
2766        double val2 = op2.asDoubleConstant().value;
2767        if (op1.isDoubleConstant()) {
2768          // BOTH CONSTANTS: FOLD
2769          double val1 = op1.asDoubleConstant().value;
2770          int result = (val1 < val2) ? -1 : ((val1 == val2) ? 0 : 1);
2771          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(result));
2772          return DefUseEffect.MOVE_FOLDED;
2773        }
2774        if (Double.isNaN(val2)) {
2775          // result is unordered => 1
2776          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(1));
2777          return DefUseEffect.MOVE_FOLDED;
2778        }
2779      }
2780      if (op1.isDoubleConstant()) {
2781        double val1 = op1.asDoubleConstant().value;
2782        if (Double.isNaN(val1)) {
2783          // result is unordered => 1
2784          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(1));
2785          return DefUseEffect.MOVE_FOLDED;
2786        }
2787      }
2788    }
2789    return DefUseEffect.UNCHANGED;
2790  }
2791
2792  private static DefUseEffect doubleCmpl(Instruction s, OptOptions opts) {
2793    if (opts.SIMPLIFY_DOUBLE_OPS) {
2794      Operand op1 = Binary.getVal1(s);
2795      Operand op2 = Binary.getVal2(s);
2796      if (op2.isDoubleConstant()) {
2797        double val2 = op2.asDoubleConstant().value;
2798        if (op1.isDoubleConstant()) {
2799          // BOTH CONSTANTS: FOLD
2800          double val1 = op1.asDoubleConstant().value;
2801          int result = (val1 > val2) ? 1 : ((val1 == val2) ? 0 : -1);
2802          Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), IC(result));
2803          return DefUseEffect.MOVE_FOLDED;
2804        }
2805        if (Double.isNaN(val2)) {
2806          // result is unordered => -1
2807          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(-1));
2808          return DefUseEffect.MOVE_FOLDED;
2809        }
2810      }
2811      if (op1.isDoubleConstant()) {
2812        double val1 = op1.asDoubleConstant().value;
2813        if (Double.isNaN(val1)) {
2814          // result is unordered => -1
2815          Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(-1));
2816          return DefUseEffect.MOVE_FOLDED;
2817        }
2818      }
2819    }
2820    return DefUseEffect.UNCHANGED;
2821  }
2822
2823  private static DefUseEffect doubleDiv(Instruction s, OptOptions opts) {
2824    if (opts.SIMPLIFY_DOUBLE_OPS) {
2825      Operand op1 = Binary.getVal1(s);
2826      Operand op2 = Binary.getVal2(s);
2827      if (op2.isDoubleConstant()) {
2828        double val2 = op2.asDoubleConstant().value;
2829        if (op1.isDoubleConstant()) {
2830          // BOTH CONSTANTS: FOLD
2831          double val1 = op1.asDoubleConstant().value;
2832          Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(val1 / val2));
2833          return DefUseEffect.MOVE_FOLDED;
2834        }
2835        if (Double.isNaN(val2)) {
2836          // x / NaN is NaN
2837          Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(Double.NaN));
2838          return DefUseEffect.MOVE_FOLDED;
2839        }
2840      }
2841      if (op1.isDoubleConstant()) {
2842        double val1 = op1.asDoubleConstant().value;
2843        if (Double.isNaN(val1)) {
2844          // x / NaN is NaN
2845          Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(Double.NaN));
2846          return DefUseEffect.MOVE_FOLDED;
2847        }
2848      }
2849    }
2850    return DefUseEffect.UNCHANGED;
2851  }
2852
2853  private static DefUseEffect doubleMul(Instruction s, OptOptions opts) {
2854    if (opts.SIMPLIFY_DOUBLE_OPS) {
2855      canonicalizeCommutativeOperator(s);
2856      Operand op2 = Binary.getVal2(s);
2857      if (op2.isDoubleConstant()) {
2858        double val2 = op2.asDoubleConstant().value;
2859        Operand op1 = Binary.getVal1(s);
2860        if (op1.isDoubleConstant()) {
2861          // BOTH CONSTANTS: FOLD
2862          double val1 = op1.asDoubleConstant().value;
2863          Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(val1 * val2));
2864          return DefUseEffect.MOVE_FOLDED;
2865        }
2866        if (val2 == 1.0) {
2867          // x * 1.0 is x even if x is a NaN
2868          Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
2869          return DefUseEffect.MOVE_REDUCED;
2870        }
2871        if (Double.isNaN(val2)) {
2872          // x * NaN is NaN
2873          Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(Double.NaN));
2874          return DefUseEffect.MOVE_FOLDED;
2875        }
2876      }
2877    }
2878    return DefUseEffect.UNCHANGED;
2879  }
2880
2881  private static DefUseEffect doubleNeg(Instruction s, OptOptions opts) {
2882    if (opts.SIMPLIFY_DOUBLE_OPS) {
2883      Operand op = Unary.getVal(s);
2884      if (op.isDoubleConstant()) {
2885        // CONSTANT: FOLD
2886        double val = op.asDoubleConstant().value;
2887        Move.mutate(s, DOUBLE_MOVE, Unary.getClearResult(s), DC(-val));
2888        return DefUseEffect.MOVE_FOLDED;
2889      }
2890    }
2891    return DefUseEffect.UNCHANGED;
2892  }
2893
2894
2895  private static DefUseEffect doubleRem(Instruction s, OptOptions opts) {
2896    if (opts.SIMPLIFY_DOUBLE_OPS) {
2897      Operand op1 = Binary.getVal1(s);
2898      Operand op2 = Binary.getVal2(s);
2899      if (op2.isDoubleConstant()) {
2900        double val2 = op2.asDoubleConstant().value;
2901        if (op1.isDoubleConstant()) {
2902          // BOTH CONSTANTS: FOLD
2903          double val1 = op1.asDoubleConstant().value;
2904          Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(val1 % val2));
2905          return DefUseEffect.MOVE_FOLDED;
2906        }
2907        if (Double.isNaN(val2)) {
2908          // x % NaN is NaN
2909          Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(Double.NaN));
2910          return DefUseEffect.MOVE_FOLDED;
2911        }
2912      }
2913      if (op1.isDoubleConstant()) {
2914        double val1 = op1.asDoubleConstant().value;
2915        if (Double.isNaN(val1)) {
2916          // x % NaN is NaN
2917          Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(Double.NaN));
2918          return DefUseEffect.MOVE_FOLDED;
2919        }
2920      }
2921    }
2922    return DefUseEffect.UNCHANGED;
2923  }
2924
2925  private static DefUseEffect doubleSub(Instruction s, OptOptions opts) {
2926    if (opts.SIMPLIFY_DOUBLE_OPS) {
2927      Operand op1 = Binary.getVal1(s);
2928      Operand op2 = Binary.getVal2(s);
2929      if (op2.isDoubleConstant()) {
2930        double val2 = op2.asDoubleConstant().value;
2931        if (op1.isDoubleConstant()) {
2932          // BOTH CONSTANTS: FOLD
2933          double val1 = op1.asDoubleConstant().value;
2934          Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(val1 - val2));
2935          return DefUseEffect.MOVE_FOLDED;
2936        }
2937        if (val2 == 0.0) {
2938          // x - 0.0 is x, even if x is a NaN
2939          Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s));
2940          return DefUseEffect.MOVE_REDUCED;
2941        }
2942        if (Double.isNaN(val2)) {
2943          // x - NaN is NaN
2944          Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(Double.NaN));
2945          return DefUseEffect.MOVE_FOLDED;
2946        }
2947      }
2948      if (op1.isDoubleConstant()) {
2949        double val1 = op1.asDoubleConstant().value;
2950        if (val1 == 0.0) {
2951          // 0.0 - x is -x
2952          Unary.mutate(s, DOUBLE_NEG, Binary.getClearResult(s), Binary.getClearVal2(s));
2953          return DefUseEffect.REDUCED;
2954        }
2955        if (Double.isNaN(val1)) {
2956          // x - NaN is NaN
2957          Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(Double.NaN));
2958          return DefUseEffect.MOVE_FOLDED;
2959        }
2960      }
2961    }
2962    return DefUseEffect.UNCHANGED;
2963  }
2964
2965  private static DefUseEffect doubleSqrt(Instruction s, OptOptions opts) {
2966    if (opts.SIMPLIFY_DOUBLE_OPS) {
2967      Operand op = Unary.getVal(s);
2968      if (op.isDoubleConstant()) {
2969        // CONSTANT: FOLD
2970        double val = op.asDoubleConstant().value;
2971        Move.mutate(s, DOUBLE_MOVE, Unary.getClearResult(s), DC(Math.sqrt(val)));
2972        return DefUseEffect.MOVE_FOLDED;
2973      }
2974    }
2975    return DefUseEffect.UNCHANGED;
2976  }
2977
2978  private static DefUseEffect double2Float(Instruction s, OptOptions opts) {
2979    if (opts.SIMPLIFY_FLOAT_OPS) {
2980      Operand op = Unary.getVal(s);
2981      if (op.isDoubleConstant()) {
2982        // CONSTANT: FOLD
2983        double val = op.asDoubleConstant().value;
2984        Move.mutate(s, FLOAT_MOVE, Unary.getClearResult(s), FC((float) val));
2985        return DefUseEffect.MOVE_FOLDED;
2986      }
2987    }
2988    return DefUseEffect.UNCHANGED;
2989  }
2990
2991  private static DefUseEffect double2Int(Instruction s, OptOptions opts) {
2992    if (opts.SIMPLIFY_INTEGER_OPS) {
2993      Operand op = Unary.getVal(s);
2994      if (op.isDoubleConstant()) {
2995        // CONSTANT: FOLD
2996        double val = op.asDoubleConstant().value;
2997        Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC((int) val));
2998        return DefUseEffect.MOVE_FOLDED;
2999      }
3000    }
3001    return DefUseEffect.UNCHANGED;
3002  }
3003
3004  private static DefUseEffect double2Long(Instruction s, OptOptions opts) {
3005    if (opts.SIMPLIFY_LONG_OPS) {
3006      Operand op = Unary.getVal(s);
3007      if (op.isDoubleConstant()) {
3008        // CONSTANT: FOLD
3009        double val = op.asDoubleConstant().value;
3010        Move.mutate(s, LONG_MOVE, Unary.getClearResult(s), LC((long) val));
3011        return DefUseEffect.MOVE_FOLDED;
3012      }
3013    }
3014    return DefUseEffect.UNCHANGED;
3015  }
3016
3017  private static DefUseEffect doubleAsLongBits(Instruction s, OptOptions opts) {
3018    if (opts.SIMPLIFY_LONG_OPS) {
3019      Operand op = Unary.getVal(s);
3020      if (op.isDoubleConstant()) {
3021        // CONSTANT: FOLD
3022        double val = op.asDoubleConstant().value;
3023        Move.mutate(s, LONG_MOVE, Unary.getClearResult(s), LC(Double.doubleToLongBits(val)));
3024        return DefUseEffect.MOVE_FOLDED;
3025      }
3026    }
3027    return DefUseEffect.UNCHANGED;
3028  }
3029
3030  private static DefUseEffect int2Double(Instruction s, OptOptions opts) {
3031    if (opts.SIMPLIFY_DOUBLE_OPS) {
3032      Operand op = Unary.getVal(s);
3033      if (op.isIntConstant()) {
3034        // CONSTANT: FOLD
3035        int val = op.asIntConstant().value;
3036        Move.mutate(s, DOUBLE_MOVE, Unary.getClearResult(s), DC(val));
3037        return DefUseEffect.MOVE_FOLDED;
3038      }
3039    }
3040    return DefUseEffect.UNCHANGED;
3041  }
3042
3043  private static DefUseEffect int2Byte(Instruction s, OptOptions opts) {
3044    if (opts.SIMPLIFY_INTEGER_OPS) {
3045      Operand op = Unary.getVal(s);
3046      if (op.isIntConstant()) {
3047        // CONSTANT: FOLD
3048        int val = op.asIntConstant().value;
3049        Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC((byte) val));
3050        return DefUseEffect.MOVE_FOLDED;
3051      }
3052    }
3053    return DefUseEffect.UNCHANGED;
3054  }
3055
3056  private static DefUseEffect int2UShort(Instruction s, OptOptions opts) {
3057    if (opts.SIMPLIFY_INTEGER_OPS) {
3058      Operand op = Unary.getVal(s);
3059      if (op.isIntConstant()) {
3060        // CONSTANT: FOLD
3061        int val = op.asIntConstant().value;
3062        Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC((char) val));
3063        return DefUseEffect.MOVE_FOLDED;
3064      }
3065    }
3066    return DefUseEffect.UNCHANGED;
3067  }
3068
3069  private static DefUseEffect int2Float(Instruction s, OptOptions opts) {
3070    if (opts.SIMPLIFY_FLOAT_OPS) {
3071      Operand op = Unary.getVal(s);
3072      if (op.isIntConstant()) {
3073        // CONSTANT: FOLD
3074        int val = op.asIntConstant().value;
3075        Move.mutate(s, FLOAT_MOVE, Unary.getClearResult(s), FC(val));
3076        return DefUseEffect.MOVE_FOLDED;
3077      }
3078    }
3079    return DefUseEffect.UNCHANGED;
3080  }
3081
3082  private static DefUseEffect int2Long(Instruction s, OptOptions opts) {
3083    if (opts.SIMPLIFY_LONG_OPS) {
3084      Operand op = Unary.getVal(s);
3085      if (op.isIntConstant()) {
3086        // CONSTANT: FOLD
3087        int val = op.asIntConstant().value;
3088        Move.mutate(s, LONG_MOVE, Unary.getClearResult(s), LC(val));
3089        return DefUseEffect.MOVE_FOLDED;
3090      }
3091    }
3092    return DefUseEffect.UNCHANGED;
3093  }
3094
3095  private static DefUseEffect int2AddrSigExt(Instruction s, OptOptions opts) {
3096    if (opts.SIMPLIFY_REF_OPS) {
3097      Operand op = Unary.getVal(s);
3098      if (op.isIntConstant()) {
3099        // CONSTANT: FOLD
3100        int val = op.asIntConstant().value;
3101        Move.mutate(s, REF_MOVE, Unary.getClearResult(s), AC(Address.fromIntSignExtend(val)));
3102        return DefUseEffect.MOVE_FOLDED;
3103      }
3104    }
3105    return DefUseEffect.UNCHANGED;
3106  }
3107
3108  private static DefUseEffect int2AddrZerExt(Instruction s, OptOptions opts) {
3109    if (opts.SIMPLIFY_REF_OPS) {
3110      Operand op = Unary.getVal(s);
3111      if (op.isIntConstant()) {
3112        // CONSTANT: FOLD
3113        int val = op.asIntConstant().value;
3114        Move.mutate(s, REF_MOVE, Unary.getClearResult(s), AC(Address.fromIntZeroExtend(val)));
3115        return DefUseEffect.MOVE_FOLDED;
3116      }
3117    }
3118    return DefUseEffect.UNCHANGED;
3119  }
3120
3121  private static DefUseEffect long2Addr(Instruction s, OptOptions opts) {
3122    if (opts.SIMPLIFY_REF_OPS) {
3123      Operand op = Unary.getVal(s);
3124      if (op.isLongConstant()) {
3125        if (VM.BuildFor64Addr) {
3126          // CONSTANT: FOLD
3127          long val = op.asLongConstant().value;
3128          Move.mutate(s, REF_MOVE, Unary.getClearResult(s), AC(Address.fromLong(val)));
3129          return DefUseEffect.MOVE_FOLDED;
3130        } else {
3131          // CONSTANT: FOLD
3132          int val = (int) op.asLongConstant().value;
3133          Move.mutate(s, REF_MOVE, Unary.getClearResult(s), AC(Address.fromIntZeroExtend(val)));
3134          return DefUseEffect.MOVE_FOLDED;
3135        }
3136      }
3137    }
3138    return DefUseEffect.UNCHANGED;
3139  }
3140
3141  private static DefUseEffect int2Short(Instruction s, OptOptions opts) {
3142    if (opts.SIMPLIFY_INTEGER_OPS) {
3143      Operand op = Unary.getVal(s);
3144      if (op.isIntConstant()) {
3145        // CONSTANT: FOLD
3146        int val = op.asIntConstant().value;
3147        Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC((short) val));
3148        return DefUseEffect.MOVE_FOLDED;
3149      }
3150    }
3151    return DefUseEffect.UNCHANGED;
3152  }
3153
3154  private static DefUseEffect intBitsAsFloat(Instruction s, OptOptions opts) {
3155    if (opts.SIMPLIFY_FLOAT_OPS) {
3156      Operand op = Unary.getVal(s);
3157      if (op.isIntConstant()) {
3158        // CONSTANT: FOLD
3159        int val = op.asIntConstant().value;
3160        Move.mutate(s, FLOAT_MOVE, Unary.getClearResult(s), FC(Float.intBitsToFloat(val)));
3161        return DefUseEffect.MOVE_FOLDED;
3162      }
3163    }
3164    return DefUseEffect.UNCHANGED;
3165  }
3166
3167  private static DefUseEffect addr2Int(Instruction s, OptOptions opts) {
3168    if (opts.SIMPLIFY_INTEGER_OPS) {
3169      Operand op = Unary.getVal(s);
3170      if (op.isConstant() && !op.isMovableObjectConstant()) {
3171        // CONSTANT: FOLD
3172        Address val = getAddressValue(op);
3173        Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC(val.toInt()));
3174        return DefUseEffect.MOVE_FOLDED;
3175      }
3176    }
3177    return DefUseEffect.UNCHANGED;
3178  }
3179
3180  private static DefUseEffect addr2Long(Instruction s, OptOptions opts) {
3181    if (opts.SIMPLIFY_LONG_OPS) {
3182      Operand op = Unary.getVal(s);
3183      if (op.isConstant() && !op.isMovableObjectConstant()) {
3184        // CONSTANT: FOLD
3185        Address val = getAddressValue(op);
3186        Move.mutate(s, LONG_MOVE, Unary.getClearResult(s), LC(val.toLong()));
3187        return DefUseEffect.MOVE_FOLDED;
3188      }
3189    }
3190    return DefUseEffect.UNCHANGED;
3191  }
3192
3193  private static DefUseEffect float2Double(Instruction s, OptOptions opts) {
3194    if (opts.SIMPLIFY_DOUBLE_OPS) {
3195      Operand op = Unary.getVal(s);
3196      if (op.isFloatConstant()) {
3197        // CONSTANT: FOLD
3198        float val = op.asFloatConstant().value;
3199        Move.mutate(s, DOUBLE_MOVE, Unary.getClearResult(s), DC(val));
3200        return DefUseEffect.MOVE_FOLDED;
3201      }
3202    }
3203    return DefUseEffect.UNCHANGED;
3204  }
3205
3206  private static DefUseEffect float2Int(Instruction s, OptOptions opts) {
3207    if (opts.SIMPLIFY_INTEGER_OPS) {
3208      Operand op = Unary.getVal(s);
3209      if (op.isFloatConstant()) {
3210        // CONSTANT: FOLD
3211        float val = op.asFloatConstant().value;
3212        Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC((int) val));
3213        return DefUseEffect.MOVE_FOLDED;
3214      }
3215    }
3216    return DefUseEffect.UNCHANGED;
3217  }
3218
3219  private static DefUseEffect float2Long(Instruction s, OptOptions opts) {
3220    if (opts.SIMPLIFY_LONG_OPS) {
3221      Operand op = Unary.getVal(s);
3222      if (op.isFloatConstant()) {
3223        // CONSTANT: FOLD
3224        float val = op.asFloatConstant().value;
3225        Move.mutate(s, LONG_MOVE, Unary.getClearResult(s), LC((long) val));
3226        return DefUseEffect.MOVE_FOLDED;
3227      }
3228    }
3229    return DefUseEffect.UNCHANGED;
3230  }
3231
3232  private static DefUseEffect floatAsIntBits(Instruction s, OptOptions opts) {
3233    if (opts.SIMPLIFY_INTEGER_OPS) {
3234      Operand op = Unary.getVal(s);
3235      if (op.isFloatConstant()) {
3236        // CONSTANT: FOLD
3237        float val = op.asFloatConstant().value;
3238        Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC(Float.floatToIntBits(val)));
3239        return DefUseEffect.MOVE_FOLDED;
3240      }
3241    }
3242    return DefUseEffect.UNCHANGED;
3243  }
3244
3245  private static DefUseEffect long2Float(Instruction s, OptOptions opts) {
3246    if (opts.SIMPLIFY_FLOAT_OPS) {
3247      Operand op = Unary.getVal(s);
3248      if (op.isLongConstant()) {
3249        // CONSTANT: FOLD
3250        long val = op.asLongConstant().value;
3251        Move.mutate(s, FLOAT_MOVE, Unary.getClearResult(s), FC(val));
3252        return DefUseEffect.MOVE_FOLDED;
3253      }
3254    }
3255    return DefUseEffect.UNCHANGED;
3256  }
3257
3258  private static DefUseEffect long2Int(Instruction s, OptOptions opts) {
3259    if (opts.SIMPLIFY_INTEGER_OPS) {
3260      Operand op = Unary.getVal(s);
3261      if (op.isLongConstant()) {
3262        // CONSTANT: FOLD
3263        long val = op.asLongConstant().value;
3264        Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC((int) val));
3265        return DefUseEffect.MOVE_FOLDED;
3266      }
3267    }
3268    return DefUseEffect.UNCHANGED;
3269  }
3270
3271  private static DefUseEffect long2Double(Instruction s, OptOptions opts) {
3272    if (opts.SIMPLIFY_DOUBLE_OPS) {
3273      Operand op = Unary.getVal(s);
3274      if (op.isLongConstant()) {
3275        // CONSTANT: FOLD
3276        long val = op.asLongConstant().value;
3277        Move.mutate(s, DOUBLE_MOVE, Unary.getClearResult(s), DC(val));
3278        return DefUseEffect.MOVE_FOLDED;
3279      }
3280    }
3281    return DefUseEffect.UNCHANGED;
3282  }
3283
3284  private static DefUseEffect longBitsAsDouble(Instruction s, OptOptions opts) {
3285    if (opts.SIMPLIFY_DOUBLE_OPS) {
3286      Operand op = Unary.getVal(s);
3287      if (op.isLongConstant()) {
3288        // CONSTANT: FOLD
3289        long val = op.asLongConstant().value;
3290        Move.mutate(s, DOUBLE_MOVE, Unary.getClearResult(s), DC(Double.longBitsToDouble(val)));
3291        return DefUseEffect.MOVE_FOLDED;
3292      }
3293    }
3294    return DefUseEffect.UNCHANGED;
3295  }
3296
3297  private static DefUseEffect arrayLength(Instruction s, OptOptions opts) {
3298    if (opts.SIMPLIFY_FIELD_OPS) {
3299      Operand op = GuardedUnary.getVal(s);
3300      if (op.isObjectConstant()) {
3301        int length = 0;
3302        if (op.getType().getArrayElementType().isCodeType()) {
3303          length = ((CodeArray)(op.asObjectConstant().value)).length();
3304        } else {
3305          length = Array.getLength(op.asObjectConstant().value);
3306        }
3307        Move.mutate(s, INT_MOVE, GuardedUnary.getClearResult(s), IC(length));
3308        return DefUseEffect.MOVE_FOLDED;
3309      } else if (op.isNullConstant()) {
3310        // TODO: this arraylength operation is junk so destroy
3311        return DefUseEffect.UNCHANGED;
3312      }
3313    }
3314    return DefUseEffect.UNCHANGED;
3315  }
3316
3317  private static DefUseEffect boundsCheck(Instruction s, OptOptions opts) {
3318    if (opts.SIMPLIFY_FIELD_OPS) {
3319      Operand ref = BoundsCheck.getRef(s);
3320      Operand index = BoundsCheck.getIndex(s);
3321      if (ref.isNullConstant()) {
3322        // Should already be caught by nullcheck simplification
3323        return DefUseEffect.UNCHANGED;
3324      } else if (index.isIntConstant()) {
3325        int indexAsInt = index.asIntConstant().value;
3326        if (indexAsInt < 0) {
3327          Trap.mutate(s, TRAP, BoundsCheck.getClearGuardResult(s), TrapCodeOperand.ArrayBounds());
3328          return DefUseEffect.TRAP_REDUCED;
3329        } else if (ref.isConstant()) {
3330          if (ref.isObjectConstant()) {
3331            int refLength = Array.getLength(ref.asObjectConstant().value);
3332            if (indexAsInt < refLength) {
3333              Move.mutate(s, GUARD_MOVE, BoundsCheck.getClearGuardResult(s), BoundsCheck.getClearGuard(s));
3334              return Move.getVal(s).isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED;
3335            } else {
3336              Trap.mutate(s, TRAP, BoundsCheck.getClearGuardResult(s), TrapCodeOperand.ArrayBounds());
3337              return DefUseEffect.TRAP_REDUCED;
3338            }
3339          }
3340        }
3341      }
3342    }
3343    return DefUseEffect.UNCHANGED;
3344  }
3345
3346  private static DefUseEffect call(boolean HIR, AbstractRegisterPool regpool, Instruction s, OptOptions opts) {
3347    if (opts.SIMPLIFY_FIELD_OPS) {
3348      MethodOperand methOp = Call.getMethod(s);
3349      if (methOp == null) {
3350        return DefUseEffect.UNCHANGED;
3351      }
3352      if (methOp.isVirtual() && !methOp.hasPreciseTarget()) {
3353        Operand calleeThis = Call.getParam(s, 0);
3354        if (calleeThis.isNullConstant()) {
3355          // Should already be caught by nullcheck simplification
3356          return DefUseEffect.UNCHANGED;
3357        } else if (calleeThis.isConstant() || calleeThis.asRegister().isPreciseType()) {
3358          TypeReference calleeClass = calleeThis.getType();
3359          if (calleeClass.isResolved()) {
3360            methOp.refine(calleeClass.peekType());
3361            return DefUseEffect.UNCHANGED;
3362          }
3363        }
3364      } else if (methOp.isStatic() && methOp.hasPreciseTarget() && HIR) {
3365        RVMMethod method = methOp.getTarget();
3366        // Can we remove the need for RVMClass.getClass...FromStackFrame to walk the stack?
3367        if (method == Entrypoints.getClassLoaderFromStackFrame ||
3368            method == Entrypoints.getClassFromStackFrame) {
3369          Operand frameOp = Call.getParam(s, 0);
3370          if (frameOp.isIntConstant()) {
3371            int frame = frameOp.asIntConstant().value;
3372            InlineSequence currentFrame = s.position;
3373            while (frame > 0 && currentFrame != null) {
3374              currentFrame = currentFrame.caller;
3375              frame--;
3376            }
3377            if (currentFrame != null) {
3378              // we found the caller
3379              ObjectConstantOperand cop;
3380              if (method == Entrypoints.getClassLoaderFromStackFrame) {
3381                cop = new ObjectConstantOperand(currentFrame.method.getDeclaringClass().getTypeRef().getClassLoader(), Offset.zero());
3382              } else {
3383                cop = new ObjectConstantOperand(currentFrame.method.getDeclaringClass(), Offset.zero());
3384              }
3385              Move.mutate(s, REF_MOVE, Call.getClearResult(s), cop);
3386              return DefUseEffect.MOVE_FOLDED;
3387            }
3388          }
3389        }
3390      }
3391      if (!VM.runningVM && methOp.hasPreciseTarget() && methOp.getTarget().isRuntimePure()) {
3392        RVMMethod method = methOp.getTarget();
3393        switch(method.getAnnotation(org.vmmagic.pragma.RuntimePure.class).value()) {
3394        case Unavailable: // not available at boot image write time
3395          return DefUseEffect.UNCHANGED;
3396        default:
3397          throw new Error("Unhandled RuntimePure value: " +
3398            method.getAnnotation(org.vmmagic.pragma.RuntimePure.class).value());
3399        }
3400      } else if (methOp.hasPreciseTarget() && methOp.getTarget().isPure()) {
3401        // Look for a precise method call to a pure method with all constant arguments
3402        RVMMethod method = methOp.getTarget();
3403        int n = Call.getNumberOfParams(s);
3404        for (int i = 0; i < n; i++) {
3405          Operand param = Call.getParam(s,i);
3406          if (!param.isConstant() || param.isNullConstant()) {
3407            return DefUseEffect.UNCHANGED;
3408          }
3409        }
3410        // Pure method with all constant arguments. Perform reflective method call
3411        Object thisArg = null;
3412        TypeReference[] paramTypes = method.getParameterTypes();
3413        Object[] otherArgs;
3414        Object result = null;
3415        if (!methOp.isStatic()) {
3416          thisArg = boxConstantOperand((ConstantOperand)Call.getParam(s,0), method.getDeclaringClass().getTypeRef());
3417          n--;
3418          otherArgs = new Object[n];
3419          for (int i = 0; i < n; i++) {
3420            otherArgs[i] = boxConstantOperand((ConstantOperand)Call.getParam(s,i + 1),paramTypes[i]);
3421          }
3422        } else {
3423          otherArgs = new Object[n];
3424          for (int i = 0; i < n; i++) {
3425            otherArgs[i] = boxConstantOperand((ConstantOperand)Call.getParam(s,i),paramTypes[i]);
3426          }
3427        }
3428        Throwable t = null;
3429        Method m = null;
3430        try {
3431          if (VM.runningVM) {
3432            result = Reflection.invoke(method, null, thisArg, otherArgs, false);
3433          } else {
3434            Class<?>[] argTypes = new Class<?>[n];
3435            for (int i = 0; i < n; i++) {
3436              argTypes[i] = Call.getParam(s,i).getType().resolve().getClassForType();
3437            }
3438            m = method.getDeclaringClass().getClassForType().getDeclaredMethod(method.getName().toString(), argTypes);
3439            result = m.invoke(thisArg, otherArgs);
3440          }
3441        } catch (Throwable e) {
3442          t = e;
3443        }
3444        if (t != null) {
3445          // Call threw exception so leave in to generate at execution time
3446          return DefUseEffect.UNCHANGED;
3447        }
3448        if (result == null) throw new OptimizingCompilerException("Method " + m + "/" + method + " returned null");
3449        if (method.getReturnType().isVoidType()) {
3450          Empty.mutate(s, NOP);
3451          return DefUseEffect.REDUCED;
3452        } else {
3453          Operator moveOp = IRTools.getMoveOp(method.getReturnType());
3454          Move.mutate(s,moveOp, Call.getClearResult(s),
3455                      boxConstantObjectAsOperand(result, method.getReturnType()));
3456          return DefUseEffect.MOVE_FOLDED;
3457        }
3458      }
3459    }
3460    return DefUseEffect.UNCHANGED;
3461  }
3462
3463  /**
3464   * Package up a constant operand as an object
3465   * @param op the constant operand to package
3466   * @param t the type of the object (needed to differentiate primitive from numeric types..)
3467   * @return the object
3468   */
3469  private static Object boxConstantOperand(ConstantOperand op, TypeReference t) {
3470    if (op.isObjectConstant()) {
3471      return op.asObjectConstant().value;
3472    } else if (op.isLongConstant()) {
3473      return op.asLongConstant().value;
3474    } else if (op.isFloatConstant()) {
3475      return op.asFloatConstant().value;
3476    } else if (op.isDoubleConstant()) {
3477      return op.asDoubleConstant().value;
3478    } else if (t.isIntType()) {
3479      return op.asIntConstant().value;
3480    } else if (t.isBooleanType()) {
3481      return op.asIntConstant().value == 1;
3482    } else if (t.isByteType()) {
3483      return (byte)op.asIntConstant().value;
3484    } else if (t.isCharType()) {
3485      return (char)op.asIntConstant().value;
3486    } else if (t.isShortType()) {
3487      return (short)op.asIntConstant().value;
3488    } else {
3489      throw new OptimizingCompilerException("Trying to box an VM magic unboxed type (" + op +
3490                                            ")for a pure method call is not possible:\n" + op.instruction +
3491                                            "\n at " + op.instruction.position);
3492    }
3493  }
3494  /**
3495   * Package up an object as a constant operand
3496   * @param x the object to package
3497   * @param t the type of the object (needed to differentiate primitive from numeric types..)
3498   * @return the constant operand
3499   */
3500  private static ConstantOperand boxConstantObjectAsOperand(Object x, TypeReference t) {
3501    if (VM.VerifyAssertions) VM._assert(!t.isUnboxedType());
3502    if (x == null) {
3503      throw new Error("Field of type: " + t + " is null");
3504    }
3505    if (t.isIntType()) {
3506      return IC((Integer)x);
3507    } else if (t.isBooleanType()) {
3508      return IC((Boolean)x ? 1 : 0);
3509    } else if (t.isByteType()) {
3510      return IC((Byte)x);
3511    } else if (t.isCharType()) {
3512      return IC((Character)x);
3513    } else if (t.isShortType()) {
3514      return IC((Short)x);
3515    } else if (t.isLongType()) {
3516      return LC((Long)x);
3517    } else if (t.isFloatType()) {
3518      return FC((Float)x);
3519    } else if (t.isDoubleType()) {
3520      return DC((Double)x);
3521    } else if (x instanceof String) {
3522      // Handle as object constant but make sure to use interned String
3523      x = ((String)x).intern();
3524      return new ObjectConstantOperand(x, Offset.zero());
3525    } else if (x instanceof Class) {
3526      // Handle as object constant
3527      return new ObjectConstantOperand(x, Offset.zero());
3528    } else {
3529      return new ObjectConstantOperand(x, Offset.zero());
3530    }
3531  }
3532
3533  private static DefUseEffect getField(Instruction s, OptOptions opts) {
3534    if (opts.SIMPLIFY_FIELD_OPS) {
3535      Operand ref = GetField.getRef(s);
3536      if (VM.VerifyAssertions && ref.isNullConstant()) {
3537        // Simplify to an unreachable operand, this instruction is dead code
3538        // guarded by a nullcheck that should already have been simplified
3539        RegisterOperand result = GetField.getClearResult(s);
3540        Move.mutate(s, IRTools.getMoveOp(result.getType()), result, new UnreachableOperand());
3541        return DefUseEffect.MOVE_FOLDED;
3542      } else if (opts.SIMPLIFY_CHASE_FINAL_FIELDS && ref.isObjectConstant()) {
3543        // A constant object references this field which is
3544        // final. As the reference is final the constructor
3545        // of the referred object MUST have already completed.
3546        // This also implies that the type MUST have been resolved.
3547        RVMField field = GetField.getLocation(s).getFieldRef().resolve();
3548        if (field.isFinal() && field.getDeclaringClass().isInitialized()) {
3549          try {
3550            ConstantOperand op = StaticFieldReader.getFieldValueAsConstant(field, ref.asObjectConstant().value);
3551            Move.mutate(s, IRTools.getMoveOp(field.getType()), GetField.getClearResult(s), op);
3552            return DefUseEffect.MOVE_FOLDED;
3553          } catch (NoSuchFieldException e) {
3554            if (VM.runningVM) {
3555              // this is unexpected
3556              throw new Error("Unexpected exception", e);
3557            } else {
3558              // Field not found during bootstrap due to chasing a field
3559              // only valid in the bootstrap JVM
3560            }
3561          }
3562        }
3563      }
3564    }
3565    return DefUseEffect.UNCHANGED;
3566  }
3567
3568  private static DefUseEffect getObjTib(Instruction s, OptOptions opts) {
3569    if (opts.SIMPLIFY_TIB_OPS) {
3570      Operand op = GuardedUnary.getVal(s);
3571      if (op.isNullConstant()) {
3572        // Simplify to an unreachable operand, this instruction is dead code
3573        // guarded by a nullcheck that should already have been simplified
3574        RegisterOperand result = GetField.getClearResult(s);
3575        Move.mutate(s, IRTools.getMoveOp(result.getType()), result, new UnreachableOperand());
3576        return DefUseEffect.MOVE_FOLDED;
3577      } else if (op.isConstant()) {
3578        final TypeReference typeRef = op.getType();
3579        if (typeRef.isResolved()) {
3580          Move.mutate(s, REF_MOVE, GuardedUnary.getClearResult(s), new TIBConstantOperand(op.getType().peekType()));
3581          return DefUseEffect.MOVE_FOLDED;
3582        }
3583      } else {
3584        RegisterOperand rop = op.asRegister();
3585        TypeReference typeRef = rop.getType();
3586        // Is the type of this register only one possible type?
3587        if (typeRef.isResolved() && rop.isPreciseType() && typeRef.resolve().isInstantiated()) {
3588          // before simplifying ensure that the type is instantiated, this stops
3589          // constant propagation potentially moving the TIB constant before the
3590          // runtime call that instantiates it
3591          Move.mutate(s,
3592                      REF_MOVE,
3593                      GuardedUnary.getClearResult(s),
3594                      new TIBConstantOperand(typeRef.peekType()));
3595          return DefUseEffect.MOVE_FOLDED;
3596        }
3597      }
3598    }
3599    return DefUseEffect.UNCHANGED;
3600  }
3601
3602  private static DefUseEffect getClassTib(Instruction s, OptOptions opts) {
3603    if (opts.SIMPLIFY_TIB_OPS) {
3604      TypeOperand typeOp = Unary.getVal(s).asType();
3605      if (typeOp.getTypeRef().isResolved()) {
3606        Move.mutate(s,
3607                    REF_MOVE,
3608                    Unary.getClearResult(s),
3609                    new TIBConstantOperand(typeOp.getTypeRef().peekType()));
3610        return DefUseEffect.MOVE_FOLDED;
3611      }
3612    }
3613    return DefUseEffect.UNCHANGED;
3614  }
3615
3616  private static DefUseEffect getTypeFromTib(Instruction s, OptOptions opts) {
3617    if (opts.SIMPLIFY_TIB_OPS) {
3618      Operand tibOp = Unary.getVal(s);
3619      if (tibOp.isTIBConstant()) {
3620        TIBConstantOperand tib = tibOp.asTIBConstant();
3621        Move.mutate(s, REF_MOVE, Unary.getClearResult(s), new ObjectConstantOperand(tib.value, Offset.zero()));
3622        return DefUseEffect.MOVE_FOLDED;
3623      }
3624    }
3625    return DefUseEffect.UNCHANGED;
3626  }
3627
3628  private static DefUseEffect getArrayElementTibFromTib(Instruction s, OptOptions opts) {
3629    if (opts.SIMPLIFY_TIB_OPS) {
3630      Operand tibOp = Unary.getVal(s);
3631      if (tibOp.isTIBConstant()) {
3632        TIBConstantOperand tib = tibOp.asTIBConstant();
3633        Move.mutate(s,
3634                    REF_MOVE,
3635                    Unary.getClearResult(s),
3636                    new TIBConstantOperand(tib.value.asArray().getElementType()));
3637        return DefUseEffect.MOVE_FOLDED;
3638      }
3639    }
3640    return DefUseEffect.UNCHANGED;
3641  }
3642
3643  private static DefUseEffect getSuperclassIdsFromTib(Instruction s, OptOptions opts) {
3644    if (opts.SIMPLIFY_TIB_OPS) {
3645      Operand tibOp = Unary.getVal(s);
3646      if (tibOp.isTIBConstant()) {
3647        TIBConstantOperand tib = tibOp.asTIBConstant();
3648        Move.mutate(s,
3649                    REF_MOVE,
3650                    Unary.getClearResult(s),
3651                    new ObjectConstantOperand(tib.value.getSuperclassIds(), Offset.zero()));
3652        return DefUseEffect.MOVE_FOLDED;
3653      }
3654    }
3655    return DefUseEffect.UNCHANGED;
3656  }
3657
3658  private static DefUseEffect getDoesImplementFromTib(Instruction s, OptOptions opts) {
3659    if (opts.SIMPLIFY_TIB_OPS) {
3660      Operand tibOp = Unary.getVal(s);
3661      if (tibOp.isTIBConstant()) {
3662        TIBConstantOperand tib = tibOp.asTIBConstant();
3663        Move.mutate(s,
3664                    REF_MOVE,
3665                    Unary.getClearResult(s),
3666                    new ObjectConstantOperand(tib.value.getDoesImplement(), Offset.zero()));
3667        return DefUseEffect.MOVE_FOLDED;
3668      }
3669    }
3670    return DefUseEffect.UNCHANGED;
3671  }
3672
3673  private static DefUseEffect refLoad(Instruction s, OptOptions opts) {
3674    if (opts.SIMPLIFY_TIB_OPS) {
3675      Operand base = Load.getAddress(s);
3676      if (base.isTIBConstant()) {
3677        TIBConstantOperand tib = base.asTIBConstant();
3678        Operand offset = Load.getOffset(s);
3679        if (tib.value.isInstantiated() && offset.isConstant()) {
3680          // Reading from a fixed offset from an effectively
3681          // constant array
3682          int intOffset;
3683          if (offset.isIntConstant()) {
3684            intOffset = offset.asIntConstant().value;
3685          } else {
3686            intOffset = offset.asAddressConstant().value.toInt();
3687          }
3688          int intSlot = intOffset >> LOG_BYTES_IN_ADDRESS;
3689
3690          // Create appropriate constant operand for TIB slot
3691          ConstantOperand result;
3692          TIB tibArray = tib.value.getTypeInformationBlock();
3693          if (tibArray.slotContainsTib(intSlot)) {
3694            RVMType typeOfTIB = ((TIB)tibArray.get(intSlot)).getType();
3695            result = new TIBConstantOperand(typeOfTIB);
3696          } else if (tibArray.slotContainsCode(intSlot)) {
3697            // Only generate code constants when we want to make
3698            // some virtual calls go via the JTOC
3699            if (opts.H2L_CALL_VIA_JTOC) {
3700              RVMMethod method = tib.value.getTIBMethodAtSlot(intSlot);
3701              result = new CodeConstantOperand(method);
3702            } else {
3703              return DefUseEffect.UNCHANGED;
3704            }
3705          } else {
3706            if (tibArray.get(intSlot) == null) {
3707              result = new NullConstantOperand();
3708            } else {
3709              result = new ObjectConstantOperand(tibArray.get(intSlot), Offset.zero());
3710            }
3711          }
3712          Move.mutate(s, REF_MOVE, Load.getClearResult(s), result);
3713          return DefUseEffect.MOVE_FOLDED;
3714        }
3715      }
3716    }
3717    return DefUseEffect.UNCHANGED;
3718  }
3719
3720  /**
3721   * To reduce the number of conditions to consider, we transform all commutative
3722   * operators to a canoncial form.  The following forms are considered
3723   * canonical:
3724   * <ul>
3725   * <li> <code> Reg = Reg &lt;op&gt; Reg </code>
3726   * <li> <code> Reg = Reg &lt;op&gt; Constant </code>
3727   * <li> <code> Reg = Constant &lt;op&gt; Constant </code>
3728   * </ul>
3729   * For object constant operands we treat movable objects like registers.
3730   * @param instr the instruction to consider
3731   */
3732  private static void canonicalizeCommutativeOperator(Instruction instr) {
3733    Operand op1 = Binary.getVal1(instr);
3734    if (op1.isConstant() && !op1.isMovableObjectConstant()) {
3735      Operand tmp = Binary.getClearVal1(instr);
3736      Binary.setVal1(instr, Binary.getClearVal2(instr));
3737      Binary.setVal2(instr, tmp);
3738    }
3739  }
3740
3741  private static int PowerOf2(int v) {
3742    int i = 31;
3743    int power = -1;
3744    for (; v != 0; v = v << 1, i--) {
3745      if (v < 0) {
3746        if (power == -1) {
3747          power = i;
3748        } else {
3749          return -1;
3750        }
3751      }
3752    }
3753    return power;
3754  }
3755
3756  /**
3757   * Turns the given operand encoding an address constant into an Address.
3758   *
3759   * @param op the operand
3760   * @return the address that was extracted from the operand
3761   */
3762  private static Address getAddressValue(Operand op) {
3763    if (op instanceof NullConstantOperand) {
3764      return Address.zero();
3765    }
3766    if (op instanceof AddressConstantOperand) {
3767      return op.asAddressConstant().value;
3768    }
3769    if (op instanceof IntConstantOperand) {
3770      return Address.fromIntSignExtend(op.asIntConstant().value);
3771    }
3772    if (op instanceof LongConstantOperand) {
3773      if (VM.BuildFor64Addr) {
3774          return Address.fromLong(op.asLongConstant().value);
3775      } else {
3776          return Address.fromIntZeroExtend((int)op.asLongConstant().value);
3777      }
3778    }
3779    if (op instanceof ObjectConstantOperand) {
3780      if (VM.VerifyAssertions) VM._assert(!op.isMovableObjectConstant());
3781      return Magic.objectAsAddress(op.asObjectConstant().value);
3782    }
3783    throw new OptimizingCompilerException("Cannot getAddressValue from this operand " + op);
3784  }
3785}