/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.compilers.opt.ir.operand; import org.jikesrvm.compilers.opt.OptimizingCompilerException; import org.vmmagic.unboxed.Address; import org.jikesrvm.runtime.Magic; /** * Encodes the condition codes for branches. * * @see Operand */ public final class ConditionOperand extends Operand { /* signed integer arithmetic */ /** Integer equal == */ public static final int EQUAL = 0; /** Integer not equal != */ public static final int NOT_EQUAL = 1; /** Signed integer < */ public static final int LESS = 2; /** Signed integer >= */ public static final int GREATER_EQUAL = 3; /** Signed integer > */ public static final int GREATER = 4; /** Signed integer <= */ public static final int LESS_EQUAL = 5; /* unsigned integer arithmetic */ /** Unsigned integer > - >U */ public static final int HIGHER = 6; /** Unsigned integer < - <U */ public static final int LOWER = 7; /** Unsigned integer >= - >=U */ public static final int HIGHER_EQUAL = 8; /** Unsigned integer <= - <=U */ public static final int LOWER_EQUAL = 9; /* floating-point arithmethic */ // branches that fall through when unordered /** Branch if == (equivalent to CMPG_EQUAL) - ==F */ public static final int CMPL_EQUAL = 10; /** Branch if > - >F */ public static final int CMPL_GREATER = 11; /** Branch if < - <F */ public static final int CMPG_LESS = 12; /** Branch if >= - >=F */ public static final int CMPL_GREATER_EQUAL = 13; /** Branch if <= - <=F */ public static final int CMPG_LESS_EQUAL = 14; // branches that are taken when unordered /** Branch if != (equivalent to CMPG_NOT_EQUAL) - !=FU */ public static final int CMPL_NOT_EQUAL = 15; /** Branch if < or unordered - <FU */ public static final int CMPL_LESS = 16; /** Brach if >= or unordered - >=FU */ public static final int CMPG_GREATER_EQUAL = 17; /** Branch if > or unordered - >FU */ public static final int CMPG_GREATER = 18; /** Branch if <= or unordered - <=FU */ public static final int CMPL_LESS_EQUAL = 19; /* integer arithmetic flag operations */ /** Would a+b produce a carry? */ public static final int CARRY_FROM_ADD = 20; /** Would a+b not produce a carry? */ public static final int NO_CARRY_FROM_ADD = 21; /** Would a+b cause an overflow? */ public static final int OVERFLOW_FROM_ADD = 22; /** Would a+b not cause an overflow? */ public static final int NO_OVERFLOW_FROM_ADD = 23; /** Would a-b produce a borrow? */ public static final int BORROW_FROM_SUB = 24; /** Would a-b not produce a borrow? */ public static final int NO_BORROW_FROM_SUB = 25; /** Would b-a produce a borrow? */ public static final int BORROW_FROM_RSUB = 26; /** Would b-a not produce a borrow? */ public static final int NO_BORROW_FROM_RSUB = 27; /** Would a-b cause an overflow? */ public static final int OVERFLOW_FROM_SUB = 28; /** Would a-b not cause an overflow? */ public static final int NO_OVERFLOW_FROM_SUB = 29; /** Would b-a cause an overflow? */ public static final int OVERFLOW_FROM_RSUB = 30; /** Would b-a not cause an overflow? */ public static final int NO_OVERFLOW_FROM_RSUB = 31; /** Would is bit b set in a? */ public static final int BIT_TEST = 32; /** Would is bit b not set in a? */ public static final int NO_BIT_TEST = 33; /** Would is bit a set in b? */ public static final int RBIT_TEST = 34; /** Would is bit a not set in b? */ public static final int NO_RBIT_TEST = 35; /** Would a*b cause an overflow? */ public static final int OVERFLOW_FROM_MUL = 36; /** Would a*b not cause an overflow? */ public static final int NO_OVERFLOW_FROM_MUL = 37; /* Results from evaluations */ /** Evaluation result is false */ public static final int FALSE = 0; /** Evaluation result is true */ public static final int TRUE = 1; /** Evaluation result is unknown */ public static final int UNKNOWN = 2; /** * Value of this operand. */ public int value; /** * @param code the condition code */ private ConditionOperand(int code) { value = code; } /** * Create the condition code operand for EQUAL * * @return a new condition code operand */ public static ConditionOperand EQUAL() { return new ConditionOperand(EQUAL); } /** * Create the condition code operand for NOT_EQUAL * * @return a newly created condition code operand */ public static ConditionOperand NOT_EQUAL() { return new ConditionOperand(NOT_EQUAL); } /** * Create the condition code operand for LESS * * @return a newly created condition code operand */ public static ConditionOperand LESS() { return new ConditionOperand(LESS); } /** * Create the condition code operand for GREATER_EQUAL * * @return a newly created condition code operand */ public static ConditionOperand GREATER_EQUAL() { return new ConditionOperand(GREATER_EQUAL); } /** * Create the condition code operand for GREATER * * @return a newly created condition code operand */ public static ConditionOperand GREATER() { return new ConditionOperand(GREATER); } /** * Create the condition code operand for LESS_EQUAL * * @return a newly created condition code operand */ public static ConditionOperand LESS_EQUAL() { return new ConditionOperand(LESS_EQUAL); } /** * Create the condition code operand for HIGHER * * @return a newly created condition code operand */ public static ConditionOperand HIGHER() { return new ConditionOperand(HIGHER); } /** * Create the condition code operand for LOWER * * @return a newly created condition code operand */ public static ConditionOperand LOWER() { return new ConditionOperand(LOWER); } /** * Create the condition code operand for HIGHER_EQUAL * * @return a newly created condition code operand */ public static ConditionOperand HIGHER_EQUAL() { return new ConditionOperand(HIGHER_EQUAL); } /** * Create the condition code operand for LOWER_EQUAL * * @return a newly created condition code operand */ public static ConditionOperand LOWER_EQUAL() { return new ConditionOperand(LOWER_EQUAL); } /** * Create the condition code operand for CMPL_EQUAL * * @return a newly created condition code operand */ public static ConditionOperand CMPL_EQUAL() { return new ConditionOperand(CMPL_EQUAL); } /** * Create the condition code operand for CMPL_NOT_EQUAL * * @return a newly created condition code operand */ public static ConditionOperand CMPL_NOT_EQUAL() { return new ConditionOperand(CMPL_NOT_EQUAL); } /** * Create the condition code operand for CMPL_GREATER * * @return a newly created condition code operand */ public static ConditionOperand CMPL_GREATER() { return new ConditionOperand(CMPL_GREATER); } /** * Create the condition code operand for CMPL_GREATER_EQUAL * * @return a newly created condition code operand */ public static ConditionOperand CMPL_GREATER_EQUAL() { return new ConditionOperand(CMPL_GREATER_EQUAL); } /** * Create the condition code operand for CMPG_LESS * * @return a newly created condition code operand */ public static ConditionOperand CMPG_LESS() { return new ConditionOperand(CMPG_LESS); } /** * Create the condition code operand for CARRY_FROM_ADD * * @return a newly created condition code operand */ public static ConditionOperand CARRY_FROM_ADD() { return new ConditionOperand(CARRY_FROM_ADD); } /** * Create the condition code operand for OVERFLOW_FROM_ADD * * @return a newly created condition code operand */ public static ConditionOperand OVERFLOW_FROM_ADD() { return new ConditionOperand(OVERFLOW_FROM_ADD); } /** * Create the condition code operand for BORROW_FROM_SUB * * @return a newly created condition code operand */ public static ConditionOperand BORROW_FROM_SUB() { return new ConditionOperand(BORROW_FROM_SUB); } /** * Create the condition code operand for OVERFLOW_FROM_SUB * * @return a newly created condition code operand */ public static ConditionOperand OVERFLOW_FROM_SUB() { return new ConditionOperand(OVERFLOW_FROM_SUB); } /** * Create the condition code operand for BIT_TEST * * @return a newly created condition code operand */ public static ConditionOperand BIT_TEST() { return new ConditionOperand(BIT_TEST); } /** * Create the condition code operand for OVERFLOW_FROM_ADD * * @return a newly created condition code operand */ public static ConditionOperand OVERFLOW_FROM_MUL() { return new ConditionOperand(OVERFLOW_FROM_MUL); } /** * Is x higher (unsigned >) than y? * @param x first value for comparison * @param y second value for comparison * @return {@code true} if x is higher (unsigned >) * than y, {@code false} otherwise */ private static boolean higher(int x, int y) { return (x & 0xFFFFFFFFL) > ((long)y & 0xFFFFFFFF); } /** * Is x lower (unsigned <) than y? * @param x first value for comparison * @param y second value for comparison * @return {@code true} if x is lower (unsigned <) * than y, {@code false} otherwise */ private static boolean lower(int x, int y) { return (x & 0xFFFFFFFFL) < ((long)y & 0xFFFFFFFF); } /** * Is x higher equal (unsigned >=) than y? * @param x first value for comparison * @param y second value for comparison * @return {@code true} if x is higher equal (unsigned >=) * than y, {@code false} otherwise */ private static boolean higher_equal(int x, int y) { return (x & 0xFFFFFFFFL) >= ((long)y & 0xFFFFFFFF); } /** * Is x lower equal (unsigned <=) than y? * @param x first value for comparison * @param y second value for comparison * @return {@code true} if x is lower equal (unsigned <=) * than y, {@code false} otherwise */ private static boolean lower_equal(int x, int y) { return (x & 0xFFFFFFFFL) <= ((long)y & 0xFFFFFFFF); } /** * Would {@code x + y} produce a carry? * @param x first summand * @param y second summand * @return {@code true} if the addition would produce * a carry, {@code false} otherwise */ private static boolean carry_from_add(int x, int y) { int sum = x + y; return lower(sum, x); } /** * Would {@code x - y} produce a borrow? * @param x minuend * @param y subtrahend * @return {@code true} if the subtraction would produce * a borrow, {@code false} otherwise */ private static boolean borrow_from_sub(int x, int y) { return lower(x, y); } /** * Would {@code x + y} overflow a register? * @param x first summand * @param y second summand * @return {@code true} if the addition would overflow, * {@code false} otherwise */ private static boolean overflow_from_add(int x, int y) { if (y >= 0) return x > (Integer.MAX_VALUE - y); else return x < (Integer.MIN_VALUE - y); } /** * Would {@code x - y} overflow a register? * @param x minuend * @param y subtrahend * @return {@code true} if the subtraction would overflow, * {@code false} otherwise */ private static boolean overflow_from_sub(int x, int y) { if (y >= 0) return x < (Integer.MIN_VALUE + y); else return x > (Integer.MAX_VALUE + y); } /** * Would {@code x * y} overflow a register? * @param x first factor * @param y second factor * @return {@code true} if the multiplication would overflow, * {@code false} otherwise */ private static boolean overflow_from_mul(int x, int y) { int z = x * y; long z2 = ((long)x) * ((long)y); return z != z2; } /** * Is bit y of x set? * * @param x the number to check * @param y the bit position (0 is least significant bit) * @return whether bit position y of x is set (LSB is 0) */ private static boolean bit_test(int x, int y) { return (x & (1 << y)) != 0; } /** * Is the condition code EQUAL? * * @return <code>true</code> if it is or <code>false</code> if it is not */ public boolean isEQUAL() { return value == EQUAL; } /** * Is the condition code NOT_EQUAL? * * @return <code>true</code> if it is or <code>false</code> if it is not */ public boolean isNOT_EQUAL() { return value == NOT_EQUAL; } /** * Is the condition code LESS EQUAL? * * @return <code>true</code> if it is or <code>false</code> if it is not */ public boolean isLESS_EQUAL() { return value == LESS_EQUAL; } /** * Is the condition code GREATER_EQUAL? * * @return <code>true</code> if it is or <code>false</code> if it is not */ public boolean isGREATER_EQUAL() { return value == GREATER_EQUAL; } /** * Is the condition code GREATER? * * @return <code>true</code> if it is or <code>false</code> if it is not */ public boolean isGREATER() { return value == GREATER; } /** * Is the condition code LESS? * * @return <code>true</code> if it is or <code>false</code> if it is not */ public boolean isLESS() { return value == LESS; } /** * Is the condition code HIGHER? * * @return <code>true</code> if it is or <code>false</code> if it is not */ public boolean isHIGHER() { return value == HIGHER; } /** * Is the condition code LOWER? * * @return <code>true</code> if it is or <code>false</code> if it is not */ public boolean isLOWER() { return value == LOWER; } /** * Is the condition code HIGHER_EQUAL? * * @return <code>true</code> if it is or <code>false</code> if it is not */ public boolean isHIGHER_EQUAL() { return value == HIGHER_EQUAL; } /** * Is the condition code LOWER_EQUAL? * * @return <code>true</code> if it is or <code>false</code> if it is not */ public boolean isLOWER_EQUAL() { return value == LOWER_EQUAL; } /** * Is the condition code an unsigned comparison? * @return <code>true</code> if it is or <code>false</code> if it is not */ public boolean isUNSIGNED() { switch (value) { case HIGHER: case LOWER: case HIGHER_EQUAL: case LOWER_EQUAL: return true; default: return false; } } /** * Is the condition code a flag operation? * @return <code>true</code> if it is or <code>false</code> if it is not */ public boolean isFLAG_OPERATION() { switch (value) { case CARRY_FROM_ADD: case NO_CARRY_FROM_ADD: case OVERFLOW_FROM_ADD: case NO_OVERFLOW_FROM_ADD: case BORROW_FROM_SUB: case NO_BORROW_FROM_SUB: case OVERFLOW_FROM_SUB: case NO_OVERFLOW_FROM_SUB: case BORROW_FROM_RSUB: case NO_BORROW_FROM_RSUB: case OVERFLOW_FROM_RSUB: case NO_OVERFLOW_FROM_RSUB: case BIT_TEST: case NO_BIT_TEST: case RBIT_TEST: case NO_RBIT_TEST: case OVERFLOW_FROM_MUL: case NO_OVERFLOW_FROM_MUL: return true; default: return false; } } /** * Is the condition code a flag operation following an add? * @return <code>true</code> if it is or <code>false</code> if it is not */ public boolean isFLAG_OPERATION_FROM_ADD() { switch (value) { case CARRY_FROM_ADD: case NO_CARRY_FROM_ADD: case OVERFLOW_FROM_ADD: case NO_OVERFLOW_FROM_ADD: return true; default: return false; } } /** * Is the condition code a flag operation following a subtract? * @return <code>true</code> if it is or <code>false</code> if it is not */ public boolean isFLAG_OPERATION_FROM_SUB() { switch (value) { case BORROW_FROM_SUB: case NO_BORROW_FROM_SUB: case OVERFLOW_FROM_SUB: case NO_OVERFLOW_FROM_SUB: return true; default: return false; } } /** * Is the condition code a flag operation following a reversed subtract? * @return <code>true</code> if it is or <code>false</code> if it is not */ public boolean isFLAG_OPERATION_FROM_RSUB() { switch (value) { case BORROW_FROM_RSUB: case NO_BORROW_FROM_RSUB: case OVERFLOW_FROM_RSUB: case NO_OVERFLOW_FROM_RSUB: return true; default: return false; } } /** * Is the condition code a flag operation following a bit test? * @return <code>true</code> if it is or <code>false</code> if it is not */ public boolean isBIT_TEST() { switch (value) { case BIT_TEST: case NO_BIT_TEST: return true; default: return false; } } /** * Is the condition code a flag operation following a reversed bit test? * @return <code>true</code> if it is or <code>false</code> if it is not */ public boolean isRBIT_TEST() { switch (value) { case RBIT_TEST: case NO_RBIT_TEST: return true; default: return false; } } /** * Is the condition code a floating point compare? * @return <code>true</code> if it is or <code>false</code> if it is not */ public boolean isFLOATINGPOINT() { switch (value) { case CMPL_EQUAL: case CMPL_GREATER: case CMPG_LESS: case CMPL_GREATER_EQUAL: case CMPG_LESS_EQUAL: case CMPL_NOT_EQUAL: case CMPL_LESS: case CMPG_GREATER_EQUAL: case CMPG_GREATER: case CMPL_LESS_EQUAL: return true; default: return false; } } /** * Will this floating point compare branch if the results are * unordered? * @return <code>true</code> if it is or <code>false</code> if it is not */ public boolean branchIfUnordered() { switch (value) { case CMPL_EQUAL: case CMPL_GREATER: case CMPG_LESS: case CMPL_GREATER_EQUAL: case CMPG_LESS_EQUAL: return false; case CMPL_NOT_EQUAL: case CMPL_LESS: case CMPG_GREATER_EQUAL: case CMPG_GREATER: case CMPL_LESS_EQUAL: return true; default: throw new OptimizingCompilerException("invalid condition " + this); } } /** * Convert this integer compare to a floating point cmpl * compare. Used during BC2IR. */ public void translateCMPL() { switch (value) { case EQUAL: value = CMPL_EQUAL; break; case NOT_EQUAL: value = CMPL_NOT_EQUAL; break; case LESS: value = CMPL_LESS; break; case GREATER_EQUAL: value = CMPL_GREATER_EQUAL; break; case GREATER: value = CMPL_GREATER; break; case LESS_EQUAL: value = CMPL_LESS_EQUAL; break; default: throw new OptimizingCompilerException("invalid condition " + this); } } /** * Convert this integer compare to a floating point cmpg * compare. Used during BC2IR. */ public void translateCMPG() { switch (value) { case EQUAL: value = CMPL_EQUAL; break; case NOT_EQUAL: value = CMPL_NOT_EQUAL; break; case LESS: value = CMPG_LESS; break; case GREATER_EQUAL: value = CMPG_GREATER_EQUAL; break; case GREATER: value = CMPG_GREATER; break; case LESS_EQUAL: value = CMPG_LESS_EQUAL; break; default: throw new OptimizingCompilerException("invalid condition " + this); } } /** * Convert this floating point compare to the equivalent unsigned * integer compare. Used during IA-32 BURS.<p> * * NB this doesn't respect ordered/unordered operation, so it * should only be used when it's safe to. * * @return this */ public ConditionOperand translateUNSIGNED() { switch (value) { case CMPL_EQUAL: value = EQUAL; break; case CMPL_GREATER: value = HIGHER; break; case CMPG_LESS: value = LOWER; break; case CMPL_GREATER_EQUAL: value = HIGHER_EQUAL; break; case CMPG_LESS_EQUAL: value = LOWER_EQUAL; break; case CMPL_NOT_EQUAL: value = NOT_EQUAL; break; case CMPL_LESS: value = LOWER; break; case CMPG_GREATER_EQUAL: value = HIGHER_EQUAL; break; case CMPG_GREATER: value = HIGHER; break; case CMPL_LESS_EQUAL: value = LOWER_EQUAL; break; default: throw new OptimizingCompilerException("invalid condition " + this); } return this; } @Override public Operand copy() { return new ConditionOperand(value); } @Override public boolean similar(Operand op) { return (op instanceof ConditionOperand) && (((ConditionOperand) op).value == value); } /** * Given two operands, evaluate the condition on them. * * @param v1 first operand to condition * @param v2 second operand to condition * @return <code>TRUE</code> if (v1 cond v2) or * <code>FALSE</code> if !(v1 cond v2) or * <code>UNKNOWN</code> */ public int evaluate(Operand v1, Operand v2) { if (v1.isAddressConstant()) { if (v2.isAddressConstant()) { return evaluate(v1.asAddressConstant().value, v2.asAddressConstant().value); } else if (v2.isNullConstant()) { return evaluate(v1.asAddressConstant().value, Address.zero()); } else if (v2.isIntConstant()) { return evaluate(v1.asAddressConstant().value, Address.fromIntSignExtend(v2.asIntConstant().value)); } else if (v2.isObjectConstant() && !v2.isMovableObjectConstant()) { return evaluate(v1.asAddressConstant().value, Magic.objectAsAddress(v2.asObjectConstant().value)); } } else if (v1.isIntConstant()) { if (v2.isIntConstant()) { return evaluate(v1.asIntConstant().value, v2.asIntConstant().value); } else if (v2.isNullConstant()) { return evaluate(v1.asIntConstant().value, 0); } else if (v2.isAddressConstant()) { return evaluate(Address.fromIntSignExtend(v1.asIntConstant().value), v2.asAddressConstant().value); } else if (v2.isObjectConstant() && !v2.isMovableObjectConstant()) { return evaluate(Address.fromIntSignExtend(v1.asIntConstant().value), Magic.objectAsAddress(v2.asObjectConstant().value)); } } else if (v1.isLongConstant()) { if (v2.isLongConstant()) { return evaluate(v1.asLongConstant().value, v2.asLongConstant().value); } } else if (v1.isFloatConstant()) { if (v2.isFloatConstant()) { return evaluate(v1.asFloatConstant().value, v2.asFloatConstant().value); } } else if (v1.isDoubleConstant()) { if (v2.isDoubleConstant()) { return evaluate(v1.asDoubleConstant().value, v2.asDoubleConstant().value); } } else if (v1.isObjectConstant()) { if (v2.isObjectConstant()) { if (!v1.isMovableObjectConstant() && !v2.isMovableObjectConstant()) { return evaluate(Magic.objectAsAddress(v1.asObjectConstant().value), Magic.objectAsAddress(v2.asObjectConstant().value)); } else if (isEQUAL()) { return (v1.asObjectConstant().value == v2.asObjectConstant().value) ? TRUE : FALSE; } else if (isNOT_EQUAL()) { return (v1.asObjectConstant().value != v2.asObjectConstant().value) ? TRUE : FALSE; } } if (v2.isNullConstant() || (v2.isIntConstant() && v2.asIntConstant().value == 0)) { return evaluate(1,0); } if (!v1.isMovableObjectConstant()) { if (v2.isIntConstant()) { return evaluate(Magic.objectAsAddress(v1.asObjectConstant().value), Address.fromIntSignExtend(v2.asIntConstant().value)); } else if (v2.isAddressConstant()) { return evaluate(Magic.objectAsAddress(v1.asObjectConstant().value), v2.asAddressConstant().value); } else if (v2.isNullConstant()) { return evaluate(Magic.objectAsAddress(v1.asObjectConstant().value), Address.zero()); } } } else if (v1.isNullConstant()) { if (v2.isNullConstant()) { return evaluate(0, 0); } else if (v2.isIntConstant()) { return evaluate(0, v2.asIntConstant().value); } else if (v2.isAddressConstant()) { return evaluate(Address.zero(), v2.asAddressConstant().value); } else if (v2.isObjectConstant()) { if (!v2.isMovableObjectConstant()) { return evaluate(Address.zero(), Magic.objectAsAddress(v2.asObjectConstant().value)); } else if (isEQUAL()) { return FALSE; } else if (isNOT_EQUAL()) { return TRUE; } } } else if (v1.similar(v2) && !isFLOATINGPOINT()) { // comparisons of identical operands can be evaluated, except // for floating point NaN cases switch (value) { case EQUAL: case GREATER_EQUAL: case LESS_EQUAL: case HIGHER_EQUAL: case LOWER_EQUAL: return TRUE; case NOT_EQUAL: case LESS: case GREATER: case HIGHER: case LOWER: case BORROW_FROM_SUB: case NO_BORROW_FROM_SUB: case BORROW_FROM_RSUB: case NO_BORROW_FROM_RSUB: case OVERFLOW_FROM_SUB: case NO_OVERFLOW_FROM_SUB: case OVERFLOW_FROM_RSUB: case NO_OVERFLOW_FROM_RSUB: return FALSE; case CARRY_FROM_ADD: case NO_CARRY_FROM_ADD: case OVERFLOW_FROM_ADD: case NO_OVERFLOW_FROM_ADD: case BIT_TEST: case NO_BIT_TEST: case RBIT_TEST: case NO_RBIT_TEST: case OVERFLOW_FROM_MUL: case NO_OVERFLOW_FROM_MUL: return UNKNOWN; default: throw new OptimizingCompilerException("invalid condition " + this); } } return UNKNOWN; } /** * Given two ints, evaluate the condition on them. * * @param v1 first operand to condition * @param v2 second operand to condition * @return <code>TRUE</code> if (v1 cond v2) or * <code>FALSE</code> if !(v1 cond v2) or * <code>UNKNOWN</code> */ public int evaluate(int v1, int v2) { switch (value) { case EQUAL: return (v1 == v2) ? TRUE : FALSE; case NOT_EQUAL: return (v1 != v2) ? TRUE : FALSE; case GREATER: return (v1 > v2) ? TRUE : FALSE; case LESS: return (v1 < v2) ? TRUE : FALSE; case GREATER_EQUAL: return (v1 >= v2) ? TRUE : FALSE; case LESS_EQUAL: return (v1 <= v2) ? TRUE : FALSE; case LOWER: return lower(v1, v2) ? TRUE : FALSE; case LOWER_EQUAL: return lower_equal(v1, v2) ? TRUE : FALSE; case HIGHER: return higher(v1, v2) ? TRUE : FALSE; case HIGHER_EQUAL: return higher_equal(v1, v2) ? TRUE : FALSE; case CARRY_FROM_ADD: return carry_from_add(v1, v2) ? TRUE : FALSE; case NO_CARRY_FROM_ADD: return carry_from_add(v1, v2) ? FALSE : TRUE; case OVERFLOW_FROM_ADD: return overflow_from_add(v1, v2) ? TRUE : FALSE; case NO_OVERFLOW_FROM_ADD: return overflow_from_add(v1, v2) ? FALSE : TRUE; case BORROW_FROM_SUB: return borrow_from_sub(v1, v2) ? TRUE : FALSE; case NO_BORROW_FROM_SUB: return borrow_from_sub(v1, v2) ? FALSE : TRUE; case BORROW_FROM_RSUB: return borrow_from_sub(v2, v1) ? TRUE : FALSE; case NO_BORROW_FROM_RSUB: return borrow_from_sub(v2, v1) ? FALSE : TRUE; case OVERFLOW_FROM_SUB: return overflow_from_sub(v1, v2) ? TRUE : FALSE; case NO_OVERFLOW_FROM_SUB: return overflow_from_sub(v1, v2) ? FALSE : TRUE; case OVERFLOW_FROM_RSUB: return overflow_from_sub(v2, v1) ? TRUE : FALSE; case NO_OVERFLOW_FROM_RSUB: return overflow_from_sub(v2, v1) ? FALSE : TRUE; case BIT_TEST: return bit_test(v1, v2) ? TRUE : FALSE; case NO_BIT_TEST: return bit_test(v1, v2) ? FALSE : TRUE; case RBIT_TEST: return bit_test(v2, v1) ? TRUE : FALSE; case NO_RBIT_TEST: return bit_test(v2, v1) ? FALSE : TRUE; case OVERFLOW_FROM_MUL: return overflow_from_mul(v1, v2) ? TRUE : FALSE; case NO_OVERFLOW_FROM_MUL: return overflow_from_mul(v1, v2) ? FALSE : TRUE; } throw new OptimizingCompilerException("invalid condition " + this); } /** * Given two longs, evaluate the condition on them. * * @param v1 first operand to condition * @param v2 second operand to condition * @return <code>TRUE</code> if (v1 cond v2) or * <code>FALSE</code> if !(v1 cond v2) or * <code>UNKNOWN</code> */ public int evaluate(long v1, long v2) { switch (value) { case EQUAL: return (v1 == v2) ? TRUE : FALSE; case NOT_EQUAL: return (v1 != v2) ? TRUE : FALSE; case GREATER: return (v1 > v2) ? TRUE : FALSE; case LESS: return (v1 < v2) ? TRUE : FALSE; case GREATER_EQUAL: return (v1 >= v2) ? TRUE : FALSE; case LESS_EQUAL: return (v1 <= v2) ? TRUE : FALSE; } throw new OptimizingCompilerException("invalid condition " + this); } /** * Given two floats, evaluate the condition on them. * * @param v1 first operand to condition * @param v2 second operand to condition * @return <code>true</code> if (v1 cond v2) or * <code>false</code> otherwise */ public int evaluate(float v1, float v2) { switch (value) { // Return FALSE when UNORDERED case CMPL_EQUAL: return (v1 == v2) ? TRUE : FALSE; case CMPL_GREATER: return (v1 > v2) ? TRUE : FALSE; case CMPG_LESS: return (v1 < v2) ? TRUE : FALSE; case CMPL_GREATER_EQUAL: return (v1 >= v2) ? TRUE : FALSE; case CMPG_LESS_EQUAL: return (v1 <= v2) ? TRUE : FALSE; // Return TRUE when UNORDERED case CMPL_NOT_EQUAL: return (v1 == v2) ? FALSE : TRUE; case CMPL_LESS: return (v1 >= v2) ? FALSE : TRUE; case CMPG_GREATER_EQUAL: return (v1 < v2) ? FALSE : TRUE; case CMPG_GREATER: return (v1 <= v2) ? FALSE : TRUE; case CMPL_LESS_EQUAL: return (v1 > v2) ? FALSE : TRUE; } throw new OptimizingCompilerException("invalid condition " + this); } /** * Given two doubles, evaluate the condition on them. * * @param v1 first operand to condition * @param v2 second operand to condition * @return <code>true</code> if (v1 cond v2) or * <code>false</code> otherwise */ public int evaluate(double v1, double v2) { switch (value) { // Return FALSE when UNORDERED case CMPL_EQUAL: return (v1 == v2) ? TRUE : FALSE; case CMPL_GREATER: return (v1 > v2) ? TRUE : FALSE; case CMPG_LESS: return (v1 < v2) ? TRUE : FALSE; case CMPL_GREATER_EQUAL: return (v1 >= v2) ? TRUE : FALSE; case CMPG_LESS_EQUAL: return (v1 <= v2) ? TRUE : FALSE; // Return TRUE when UNORDERED case CMPL_NOT_EQUAL: return (v1 == v2) ? FALSE : TRUE; case CMPL_LESS: return (v1 >= v2) ? FALSE : TRUE; case CMPG_GREATER_EQUAL: return (v1 < v2) ? FALSE : TRUE; case CMPG_GREATER: return (v1 <= v2) ? FALSE : TRUE; case CMPL_LESS_EQUAL: return (v1 > v2) ? FALSE : TRUE; } throw new OptimizingCompilerException("invalid condition " + this); } /** * Given two Addresses, evaluate the condition on them. * * @param v1 first operand to condition * @param v2 second operand to condition * @return <code>TRUE</code> if (v1 cond v2) or * <code>FALSE</code> if !(v1 cond v2) or * <code>UNKNOWN</code> */ public int evaluate(Address v1, Address v2) { switch (value) { case EQUAL: return (v1.EQ(v2)) ? TRUE : FALSE; case NOT_EQUAL: return (v1.NE(v2)) ? TRUE : FALSE; case GREATER: return (v1.toWord().toOffset().sGT(v2.toWord().toOffset())) ? TRUE : FALSE; case LESS: return (v1.toWord().toOffset().sLT(v2.toWord().toOffset())) ? TRUE : FALSE; case GREATER_EQUAL: return (v1.toWord().toOffset().sGE(v2.toWord().toOffset())) ? TRUE : FALSE; case LESS_EQUAL: return (v1.toWord().toOffset().sLE(v2.toWord().toOffset())) ? TRUE : FALSE; case LOWER: return (v1.LT(v2)) ? TRUE : FALSE; case LOWER_EQUAL: return (v1.LE(v2)) ? TRUE : FALSE; case HIGHER: return (v1.GT(v2)) ? TRUE : FALSE; case HIGHER_EQUAL: return (v1.GE(v2)) ? TRUE : FALSE; } throw new OptimizingCompilerException("invalid condition " + this); } /** * Flip the direction of the condition. Typical use is if you want to * change the direction of a branch. i.e. to transform: * <code> * if (condition) goto A * goto B * A: * </code> * into: * <code> * if (!condition) goto B * A: * </code> * Note that this is not the same as calling {@link #flipOperands}. * * @return this */ public ConditionOperand flipCode() { switch (value) { case EQUAL: value = NOT_EQUAL; break; case NOT_EQUAL: value = EQUAL; break; case LESS: value = GREATER_EQUAL; break; case LESS_EQUAL: value = GREATER; break; case GREATER: value = LESS_EQUAL; break; case GREATER_EQUAL: value = LESS; break; case HIGHER: value = LOWER_EQUAL; break; case LOWER: value = HIGHER_EQUAL; break; case HIGHER_EQUAL: value = LOWER; break; case LOWER_EQUAL: value = HIGHER; break; case CMPL_EQUAL: value = CMPL_NOT_EQUAL; break; case CMPL_GREATER: value = CMPL_LESS_EQUAL; break; case CMPG_LESS: value = CMPG_GREATER_EQUAL; break; case CMPL_GREATER_EQUAL: value = CMPL_LESS; break; case CMPG_LESS_EQUAL: value = CMPG_GREATER; break; case CMPL_NOT_EQUAL: value = CMPL_EQUAL; break; case CMPL_LESS: value = CMPL_GREATER_EQUAL; break; case CMPG_GREATER_EQUAL: value = CMPG_LESS; break; case CMPG_GREATER: value = CMPG_LESS_EQUAL; break; case CMPL_LESS_EQUAL: value = CMPL_GREATER; break; case CARRY_FROM_ADD: value = NO_CARRY_FROM_ADD; break; case NO_CARRY_FROM_ADD: value = CARRY_FROM_ADD; break; case OVERFLOW_FROM_ADD: value = NO_OVERFLOW_FROM_ADD; break; case NO_OVERFLOW_FROM_ADD: value = OVERFLOW_FROM_ADD; break; case BORROW_FROM_SUB: value = NO_BORROW_FROM_SUB; break; case NO_BORROW_FROM_SUB: value = BORROW_FROM_SUB; break; case BORROW_FROM_RSUB: value = NO_BORROW_FROM_RSUB; break; case NO_BORROW_FROM_RSUB: value = BORROW_FROM_RSUB; break; case OVERFLOW_FROM_SUB: value = NO_OVERFLOW_FROM_SUB; break; case NO_OVERFLOW_FROM_SUB: value = OVERFLOW_FROM_SUB; break; case OVERFLOW_FROM_RSUB: value = NO_OVERFLOW_FROM_RSUB; break; case NO_OVERFLOW_FROM_RSUB: value = OVERFLOW_FROM_RSUB; break; case BIT_TEST: value = NO_BIT_TEST; break; case NO_BIT_TEST: value = BIT_TEST; break; case RBIT_TEST: value = NO_RBIT_TEST; break; case NO_RBIT_TEST: value = RBIT_TEST; break; case OVERFLOW_FROM_MUL: value = NO_OVERFLOW_FROM_MUL; break; case NO_OVERFLOW_FROM_MUL: value = OVERFLOW_FROM_MUL; break; default: OptimizingCompilerException.UNREACHABLE(); } return this; } /** * Change the condition code to allow the order of the operands to * be flipped. i.e. So that: * <code> * if x < y then goto A * </code> * becomes: * <code> * if y > x then goto A * </code> * Note that this is not the same as calling {@link #flipCode}. * * @return this */ public ConditionOperand flipOperands() { switch (value) { case EQUAL: value = EQUAL; break; case NOT_EQUAL: value = NOT_EQUAL; break; case LESS: value = GREATER; break; case LESS_EQUAL: value = GREATER_EQUAL; break; case GREATER: value = LESS; break; case GREATER_EQUAL: value = LESS_EQUAL; break; case HIGHER: value = LOWER; break; case LOWER: value = HIGHER; break; case HIGHER_EQUAL: value = LOWER_EQUAL; break; case LOWER_EQUAL: value = HIGHER_EQUAL; break; case CMPL_EQUAL: value = CMPL_EQUAL; break; case CMPL_GREATER: value = CMPG_LESS; break; case CMPG_LESS: value = CMPL_GREATER; break; case CMPL_GREATER_EQUAL: value = CMPG_LESS_EQUAL; break; case CMPG_LESS_EQUAL: value = CMPL_GREATER_EQUAL; break; case CMPL_NOT_EQUAL: value = CMPL_NOT_EQUAL; break; case CMPL_LESS: value = CMPG_GREATER; break; case CMPG_GREATER_EQUAL: value = CMPL_LESS_EQUAL; break; case CMPG_GREATER: value = CMPL_LESS; break; case CMPL_LESS_EQUAL: value = CMPG_GREATER_EQUAL; break; case CARRY_FROM_ADD: break; // add is commutative case NO_CARRY_FROM_ADD: break; case OVERFLOW_FROM_ADD: break; case NO_OVERFLOW_FROM_ADD: break; case BORROW_FROM_SUB: value = BORROW_FROM_RSUB; break; case NO_BORROW_FROM_SUB: value = NO_BORROW_FROM_RSUB; break; case BORROW_FROM_RSUB: value = BORROW_FROM_SUB; break; case NO_BORROW_FROM_RSUB: value = NO_BORROW_FROM_SUB; break; case OVERFLOW_FROM_SUB: value = OVERFLOW_FROM_RSUB; break; case NO_OVERFLOW_FROM_SUB: value = NO_OVERFLOW_FROM_RSUB; break; case OVERFLOW_FROM_RSUB: value = OVERFLOW_FROM_SUB; break; case NO_OVERFLOW_FROM_RSUB: value = NO_OVERFLOW_FROM_SUB; break; case BIT_TEST: value = RBIT_TEST; break; case NO_BIT_TEST: value = NO_RBIT_TEST; break; case RBIT_TEST: value = BIT_TEST; break; case NO_RBIT_TEST: value = NO_BIT_TEST; break; case OVERFLOW_FROM_MUL: break; // mul is commutative case NO_OVERFLOW_FROM_MUL: break; default: OptimizingCompilerException.UNREACHABLE(); } return this; } /** * Returns the string representation of this operand. Postfix * meanings: * <ul><li>U - unsigned comparison</li> * <li>F - floating point compare that doesn't branch when * operands are unordered</li> * <li>FU - floating point compare that does branch when * operands are unordered</li> * </ul> * * @return a string representation of this operand. */ @Override public String toString() { switch (value) { case EQUAL: return "=="; case NOT_EQUAL: return "!="; case LESS: return "<"; case LESS_EQUAL: return "<="; case GREATER: return ">"; case GREATER_EQUAL: return ">="; case HIGHER: return ">U"; case LOWER: return "<U"; case HIGHER_EQUAL: return ">=U"; case LOWER_EQUAL: return "<=U"; case CMPL_EQUAL: return "==F"; case CMPL_GREATER: return ">F"; case CMPG_LESS: return "<F"; case CMPL_GREATER_EQUAL: return ">=F"; case CMPG_LESS_EQUAL: return "<=F"; case CMPL_NOT_EQUAL: return "!=FU"; case CMPL_LESS: return "<FU"; case CMPG_GREATER_EQUAL: return ">=FU"; case CMPG_GREATER: return ">FU"; case CMPL_LESS_EQUAL: return "<=FU"; case CARRY_FROM_ADD: return "carry(+)"; case NO_CARRY_FROM_ADD: return "nocarry(+)"; case OVERFLOW_FROM_ADD: return "overflow(+)"; case NO_OVERFLOW_FROM_ADD: return "nooverflow(+)"; case BORROW_FROM_SUB: return "borrow(-)"; case NO_BORROW_FROM_SUB: return "noborrow(-)"; case BORROW_FROM_RSUB: return "borrow(r-)"; case NO_BORROW_FROM_RSUB: return "noborrow(r-)"; case OVERFLOW_FROM_SUB: return "overflow(-)"; case NO_OVERFLOW_FROM_SUB: return "nooverflow(-)"; case OVERFLOW_FROM_RSUB: return "overflow(r-)"; case NO_OVERFLOW_FROM_RSUB: return "nooverflow(r-)"; case BIT_TEST: return "bt"; case NO_BIT_TEST: return "!bt"; case RBIT_TEST: return "rbt"; case NO_RBIT_TEST: return "!rbt"; case OVERFLOW_FROM_MUL: return "overflow(*)"; case NO_OVERFLOW_FROM_MUL: return "nooverflow(*)"; default: return "UNKNOWN"; } } }