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