/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Common Public License (CPL);
* 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/cpl1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.opt;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.*;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import org.jikesrvm.VM;
import org.jikesrvm.compilers.opt.ir.Binary;
import org.jikesrvm.compilers.opt.ir.BooleanCmp;
import org.jikesrvm.compilers.opt.ir.CondMove;
import org.jikesrvm.compilers.opt.ir.GuardedBinary;
import org.jikesrvm.compilers.opt.ir.IfCmp;
import org.jikesrvm.compilers.opt.ir.IfCmp2;
import org.jikesrvm.compilers.opt.ir.Move;
import org.jikesrvm.compilers.opt.ir.OPT_AddressConstantOperand;
import org.jikesrvm.compilers.opt.ir.OPT_BranchOperand;
import org.jikesrvm.compilers.opt.ir.OPT_BranchProfileOperand;
import org.jikesrvm.compilers.opt.ir.OPT_ConditionOperand;
import org.jikesrvm.compilers.opt.ir.OPT_DoubleConstantOperand;
import org.jikesrvm.compilers.opt.ir.OPT_FloatConstantOperand;
import org.jikesrvm.compilers.opt.ir.OPT_IR;
import org.jikesrvm.compilers.opt.ir.OPT_IRTools;
import org.jikesrvm.compilers.opt.ir.OPT_Instruction;
import org.jikesrvm.compilers.opt.ir.OPT_IntConstantOperand;
import org.jikesrvm.compilers.opt.ir.OPT_LongConstantOperand;
import org.jikesrvm.compilers.opt.ir.OPT_NullConstantOperand;
import org.jikesrvm.compilers.opt.ir.OPT_ObjectConstantOperand;
import org.jikesrvm.compilers.opt.ir.OPT_Operand;
import org.jikesrvm.compilers.opt.ir.OPT_OperandEnumeration;
import org.jikesrvm.compilers.opt.ir.OPT_Register;
import org.jikesrvm.compilers.opt.ir.OPT_RegisterOperand;
import org.jikesrvm.compilers.opt.ir.Unary;
import org.jikesrvm.compilers.opt.ir.ZeroCheck;
import org.jikesrvm.runtime.VM_Magic;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.Word;
/**
* This class simplifies expressions in SSA form.
*/
class OPT_ExpressionFolding extends OPT_IRTools {
/**
* Only fold operations when the result of the 1st operation becomes dead
* after folding
* TODO: doesn't apply to local folding
*/
private static final boolean RESTRICT_TO_DEAD_EXPRESSIONS = true;
/**
* Fold operations on ints
*/
private static final boolean FOLD_INTS = true;
/**
* Fold operations on word like things
*/
private static final boolean FOLD_REFS = false;
/**
* Fold operations on longs
*/
private static final boolean FOLD_LONGS = true;
/**
* Fold operations on floats
*/
private static final boolean FOLD_FLOATS = true;
/**
* Fold operations on doubles
*/
private static final boolean FOLD_DOUBLES = true;
/**
* Fold binary SUB operations
*/
private static final boolean FOLD_SUBS = true;
/**
* Fold binary ADD operations
*/
private static final boolean FOLD_ADDS = true;
/**
* Fold binary multiply operations
*/
private static final boolean FOLD_MULTS = true;
/**
* Fold binary divide operations
*/
private static final boolean FOLD_DIVS = true;
/**
* Fold binary shift left operations
*/
private static final boolean FOLD_SHIFTLS = true;
/**
* Fold binary shift right operations
*/
private static final boolean FOLD_SHIFTRS = true;
/**
* Fold binary CMP operations
*/
private static final boolean FOLD_CMPS = true;
/**
* Fold binary XOR operations
*/
private static final boolean FOLD_XORS = true;
/**
* Fold binary OR operations
*/
private static final boolean FOLD_ORS = true;
/**
* Fold binary AND operations
*/
private static final boolean FOLD_ANDS = true;
/**
* Fold unary NEG operations
*/
private static final boolean FOLD_NEGS = true;
/**
* Fold unary NOT operations
*/
private static final boolean FOLD_NOTS = true;
/**
* Fold operations that create a constant on the LHS? This may produce less
* optimal code on 2 address architectures where the constant would need
* loading into a register prior to the operation.
*/
private static final boolean FOLD_CONSTANTS_TO_LHS = true;
/**
* Fold IFCMP operations
*/
private static final boolean FOLD_IFCMPS = false;
/**
* Fold COND_MOVE operations
*/
private static final boolean FOLD_CONDMOVES = false;
/**
* Fold xxx_2xxx where the precision is increased then decreased achieving a
* nop effect
*/
private static final boolean FOLD_2CONVERSION = true;
/**
* Fold ZeroCheck where we're testing whether a value is 0 or not
*/
private static final boolean FOLD_CHECKS = true;
/**
* Perform expression folding on individual basic blocks
*/
public static boolean performLocal(OPT_IR ir) {
OPT_Instruction outer = ir.cfg.entry().firstRealInstruction();
boolean didSomething = false;
loop_over_outer_instructions:
while (outer != null) {
OPT_Register outerDef = isCandidateExpression(outer, false);
if (outerDef != null) {
OPT_Instruction inner = outer.nextInstructionInCodeOrder();
loop_over_inner_instructions:
while ((inner != null) && (inner.operator() != BBEND)) {
OPT_Register innerDef = isCandidateExpression(inner, false);
// 1. check for true dependence (does inner use outer's def?)
if (innerDef != null) {
OPT_OperandEnumeration uses = inner.getUses();
loop_over_inner_uses:
while(uses.hasMoreElements()) {
OPT_Operand use = uses.nextElement();
if (use.isRegister() && (use.asRegister().getRegister() == outerDef)) {
// Optimization case
OPT_Instruction newInner = transform(inner, outer);
if (newInner != null) {
OPT_DefUse.replaceInstructionAndUpdateDU(inner, CPOS(inner,newInner));
inner = newInner;
didSomething = true;
}
break loop_over_inner_uses;
}
}
}
// 2. check for output dependence (does inner kill outer's def?)
if (innerDef == outerDef) {
break loop_over_inner_instructions;
}
if (innerDef == null) {
OPT_OperandEnumeration defs = inner.getDefs();
while(defs.hasMoreElements()) {
OPT_Operand def = defs.nextElement();
if (def.isRegister()) {
OPT_Register defReg = def.asRegister().getRegister();
if (defReg == outerDef) {
break loop_over_inner_instructions;
}
}
}
}
// 3. check for anti dependence (do we define something that outer uses?)
if (innerDef != null) {
OPT_OperandEnumeration uses = outer.getUses();
loop_over_outer_uses:
while(uses.hasMoreElements()) {
OPT_Operand use = uses.nextElement();
if (use.isRegister() && (use.asRegister().getRegister() == innerDef)) {
break loop_over_inner_instructions;
}
}
} else {
OPT_OperandEnumeration defs = inner.getDefs();
while(defs.hasMoreElements()) {
OPT_Operand def = defs.nextElement();
if (def.isRegister()) {
OPT_OperandEnumeration uses = outer.getUses();
loop_over_outer_uses:
while(uses.hasMoreElements()) {
OPT_Operand use = uses.nextElement();
if (use.similar(def)) {
break loop_over_inner_instructions;
}
}
}
}
}
inner = inner.nextInstructionInCodeOrder();
} // loop over inner instructions
}
outer = outer.nextInstructionInCodeOrder();
} // loop over outer instructions
return didSomething;
}
/**
* Perform the transformation.
*
* If we have, in SSA form,
*
* <pre>
* x = a op1 c1
* y = x op2 c2
* </pre>
*
* where c1 and c2 are constants, replace the def of y by
*
* <pre>
* y = a op1 (c1 op3 c2)
* </pre>
*
* Where op1, op2 and op3 are add, subtract, multiply, and, or, xor and
* compare. Repeatedly apply transformation until all expressions are folded.
*
* <p>
* PRECONDITIONS: SSA form, register lists computed
*
* @param ir
* the governing IR
*/
public static void perform(OPT_IR ir) {
// Create a set of potential computations to fold.
HashSet<OPT_Register> candidates = new HashSet<OPT_Register>(20);
for (Enumeration<OPT_Instruction> e = ir.forwardInstrEnumerator(); e.hasMoreElements();) {
OPT_Instruction s = e.nextElement();
// Check if s is a candidate for expression folding
OPT_Register r = isCandidateExpression(s, true);
if (r != null) {
candidates.add(r);
}
}
if (RESTRICT_TO_DEAD_EXPRESSIONS) {
pruneCandidates(candidates);
}
boolean didSomething = true;
while (didSomething) {
didSomething = false;
iterate_over_candidates:
for (Iterator<OPT_Register> it = candidates.iterator(); it.hasNext();) {
OPT_Register r = it.next();
OPT_Instruction s = r.getFirstDef();
OPT_Operand val1;
if (Binary.conforms(s)) {
val1 = Binary.getVal1(s);
} else if (Unary.conforms(s)) {
val1 = Unary.getVal(s);
} else if (BooleanCmp.conforms(s)) {
val1 = BooleanCmp.getVal1(s);
} else if (IfCmp.conforms(s)) {
val1 = IfCmp.getVal1(s);
} else if (IfCmp2.conforms(s)) {
val1 = IfCmp2.getVal1(s);
} else if (CondMove.conforms(s)) {
val1 = CondMove.getVal1(s);
} else if (ZeroCheck.conforms(s)) {
val1 = ZeroCheck.getValue(s);
} else {
// we're not optimising any other instruction types
continue;
}
if (candidates.contains(val1.asRegister().getRegister())) {
OPT_Instruction def = val1.asRegister().getRegister().getFirstDef();
// filter out moves to get the real defining instruction
while (Move.conforms(def)) {
OPT_Operand op = Move.getVal(def);
if (op.isRegister()) {
def = op.asRegister().getRegister().getFirstDef();
} else {
// The non-constant operand of the candidate expression is the
// result of moving a constant. Remove as a candidate and leave
// for constant propagation and simplification.
it.remove();
continue iterate_over_candidates;
}
}
// check if the defining instruction has not mutated yet
if (isCandidateExpression(def, true) == null) {
continue;
}
OPT_Instruction newS = transform(s, def);
if (newS != null) {
// check if this expression is still an optimisation candidate
if (isCandidateExpression(newS, true) == null) {
it.remove();
}
OPT_DefUse.replaceInstructionAndUpdateDU(s, CPOS(s,newS));
didSomething = true;
}
}
}
}
}
/**
* Prune the candidate set; restrict candidates to only allow transformations
* that result in dead code to be eliminated
*/
private static void pruneCandidates(HashSet<OPT_Register> candidates) {
for (Iterator<OPT_Register> i = candidates.iterator(); i.hasNext();) {
OPT_Register r = i.next();
OPT_Instruction s = r.getFirstDef();
OPT_Operand val1;
if (Binary.conforms(s)) {
val1 = Binary.getVal1(s);
} else if (GuardedBinary.conforms(s)) {
val1 = GuardedBinary.getVal1(s);
} else if (Unary.conforms(s)) {
val1 = Unary.getVal(s);
} else if (BooleanCmp.conforms(s)) {
val1 = BooleanCmp.getVal1(s);
} else if (IfCmp.conforms(s)) {
val1 = IfCmp.getVal1(s);
} else if (IfCmp2.conforms(s)) {
val1 = IfCmp2.getVal1(s);
} else if (CondMove.conforms(s)) {
val1 = CondMove.getVal1(s);
} else if (ZeroCheck.conforms(s)) {
val1 = ZeroCheck.getValue(s);
} else {
OPT_OptimizingCompilerException.UNREACHABLE();
return;
}
if (VM.VerifyAssertions) {
VM._assert(val1.isRegister(), "Error with val1 of " + s);
}
OPT_Register v1 = val1.asRegister().getRegister();
if (candidates.contains(v1)) {
for (Enumeration<OPT_RegisterOperand> uses = OPT_DefUse.uses(v1); uses
.hasMoreElements();) {
OPT_RegisterOperand op = uses.nextElement();
OPT_Instruction u = op.instruction;
if ((isCandidateExpression(u, true) == null) && !Move.conforms(u)) {
i.remove();
break;
}
}
}
}
}
/**
* Perform the transformation on the instruction
*
* @param s
* the instruction to transform of the form y = x op c1
* @param def
* the definition of x, the defining instruction is of the form x = a
* op c2
* @return the new instruction to replace s;
*/
private static OPT_Instruction transform(OPT_Instruction s, OPT_Instruction def) {
// x = a op1 c1 <-- def
// y = x op2 c2 <-- s
OPT_RegisterOperand a;
OPT_RegisterOperand y;
if (Binary.conforms(def)) {
a = Binary.getVal1(def).asRegister();
} else if (GuardedBinary.conforms(def)) {
a = GuardedBinary.getVal1(def).asRegister();
} else if (Unary.conforms(def)) {
a = Unary.getVal(def).asRegister();
} else if (BooleanCmp.conforms(def)) {
a = BooleanCmp.getVal1(def).asRegister();
} else if (IfCmp.conforms(def) || IfCmp2.conforms(def) || CondMove.conforms(def)) {
// we don't fold in case of a IfCmp/CondMove coming before
// the instruction to be folded
return null;
} else {
OPT_OptimizingCompilerException.UNREACHABLE();
return null;
}
if (Binary.conforms(s)) {
y = Binary.getResult(s);
} else if (GuardedBinary.conforms(s)) {
y = GuardedBinary.getResult(s);
} else if (Unary.conforms(s)) {
y = Unary.getResult(s);
} else if (BooleanCmp.conforms(s)) {
y = BooleanCmp.getResult(s);
} else if (IfCmp.conforms(s)) {
y = IfCmp.getGuardResult(s);
} else if (IfCmp2.conforms(s)) {
y = IfCmp2.getGuardResult(s);
} else if (CondMove.conforms(s)) {
y = CondMove.getResult(s);
} else if (ZeroCheck.conforms(s)) {
y = ZeroCheck.getGuardResult(s);
} else {
OPT_OptimizingCompilerException.UNREACHABLE();
return null;
}
if (VM.VerifyAssertions) {
VM._assert(a.isRegister(), "Expected register not " + a);
VM._assert(y.isRegister(), "Expected register not " + y);
if (OPT_IR.PARANOID) {
OPT_RegisterOperand x1, x2;
if (Binary.conforms(s)) {
x1 = Binary.getVal1(s).asRegister();
} else if (GuardedBinary.conforms(s)) {
x1 = GuardedBinary.getVal1(s).asRegister();
} else if (Unary.conforms(s)) {
x1 = Unary.getVal(s).asRegister();
} else if (BooleanCmp.conforms(s)) {
x1 = BooleanCmp.getVal1(s).asRegister();
} else if (IfCmp.conforms(s)) {
x1 = IfCmp.getVal1(s).asRegister();
} else if (IfCmp2.conforms(s)) {
x1 = IfCmp2.getVal1(s).asRegister();
} else if (CondMove.conforms(s)) {
x1 = CondMove.getVal1(s).asRegister();
} else if (ZeroCheck.conforms(s)) {
x1 = ZeroCheck.getValue(s).asRegister();
} else {
OPT_OptimizingCompilerException.UNREACHABLE();
return null;
}
if (Binary.conforms(def)) {
x2 = Binary.getResult(def);
} else if (GuardedBinary.conforms(def)) {
x2 = GuardedBinary.getResult(def);
} else if (Unary.conforms(def)) {
x2 = Unary.getResult(def);
} else if (BooleanCmp.conforms(def)) {
x2 = BooleanCmp.getResult(def);
} else if (IfCmp.conforms(def)) {
x2 = IfCmp.getGuardResult(def);
} else if (IfCmp2.conforms(def)) {
x2 = IfCmp2.getGuardResult(def);
} else if (CondMove.conforms(def)) {
x2 = CondMove.getResult(def);
} else if (ZeroCheck.conforms(def)) {
x2 = ZeroCheck.getValue(def).asRegister();
} else {
OPT_OptimizingCompilerException.UNREACHABLE();
return null;
}
VM._assert(x1.similar(x2));
}
}
switch (s.operator.opcode) {
// Foldable operators
case INT_ADD_opcode: {
if (FOLD_INTS && FOLD_ADDS) {
int c2 = getIntValue(Binary.getVal2(s));
if (def.operator == INT_ADD) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a + c1; y = x + c2
return Binary.create(INT_ADD, y.copyRO(), a.copyRO(), IC(c1 + c2));
} else if (def.operator == INT_SUB) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a - c1; y = x + c2
return Binary.create(INT_ADD, y.copyRO(), a.copyRO(), IC(c2 - c1));
} else if (def.operator == INT_NEG && FOLD_CONSTANTS_TO_LHS) {
// x = -a; y = x + c2;
return Binary.create(INT_SUB, y.copyRO(), IC(c2), a.copyRO());
}
}
return null;
}
case REF_ADD_opcode: {
if (FOLD_REFS && FOLD_ADDS) {
Address c2 = getAddressValue(Binary.getVal2(s));
if (def.operator == REF_ADD) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a + c1; y = x + c2
return Binary.create(REF_ADD, y.copyRO(), a.copyRO(), AC(c1.toWord().plus(c2.toWord()).toAddress()));
} else if (def.operator == REF_SUB) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a - c1; y = x + c2
return Binary.create(REF_ADD, y.copyRO(), a.copyRO(), AC(c2.toWord().minus(c1.toWord()).toAddress()));
} else if (def.operator == REF_NEG && FOLD_CONSTANTS_TO_LHS) {
// x = -a; y = x + c2;
return Binary.create(REF_SUB, y.copyRO(), AC(c2), a.copyRO());
}
}
return null;
}
case LONG_ADD_opcode: {
if (FOLD_LONGS && FOLD_ADDS) {
long c2 = getLongValue(Binary.getVal2(s));
if (def.operator == LONG_ADD) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a + c1; y = x + c2
return Binary.create(LONG_ADD, y.copyRO(), a.copyRO(), LC(c1 + c2));
} else if (def.operator == LONG_SUB) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a - c1; y = x + c2
return Binary.create(LONG_ADD, y.copyRO(), a.copyRO(), LC(c2 - c1));
} else if (def.operator == LONG_NEG && FOLD_CONSTANTS_TO_LHS) {
// x = -a; y = x + c2;
return Binary.create(LONG_SUB, y.copyRO(), LC(c2), a.copyRO());
}
}
return null;
}
case FLOAT_ADD_opcode: {
if (FOLD_FLOATS && FOLD_ADDS) {
float c2 = getFloatValue(Binary.getVal2(s));
if (def.operator == FLOAT_ADD) {
float c1 = getFloatValue(Binary.getVal2(def));
// x = a + c1; y = x + c2
return Binary.create(FLOAT_ADD, y.copyRO(), a.copyRO(), FC(c1 + c2));
} else if (def.operator == FLOAT_SUB) {
float c1 = getFloatValue(Binary.getVal2(def));
// x = a - c1; y = x + c2
return Binary.create(FLOAT_ADD, y.copyRO(), a.copyRO(), FC(c2 - c1));
} else if (def.operator == FLOAT_NEG && FOLD_CONSTANTS_TO_LHS) {
// x = -a; y = x + c2;
return Binary.create(FLOAT_SUB, y.copyRO(), FC(c2), a.copyRO());
}
}
return null;
}
case DOUBLE_ADD_opcode: {
if (FOLD_DOUBLES && FOLD_ADDS) {
double c2 = getDoubleValue(Binary.getVal2(s));
if (def.operator == DOUBLE_ADD) {
double c1 = getDoubleValue(Binary.getVal2(def));
// x = a + c1; y = x + c2
return Binary.create(DOUBLE_ADD, y.copyRO(), a.copyRO(), DC(c1 + c2));
} else if (def.operator == DOUBLE_SUB) {
double c1 = getDoubleValue(Binary.getVal2(def));
// x = a - c1; y = x + c2
return Binary.create(DOUBLE_ADD, y.copyRO(), a.copyRO(), DC(c2 - c1));
} else if (def.operator == DOUBLE_NEG && FOLD_CONSTANTS_TO_LHS) {
// x = -a; y = x + c2;
return Binary.create(DOUBLE_SUB, y.copyRO(), DC(c2), a.copyRO());
}
}
return null;
}
case INT_SUB_opcode: {
if (FOLD_INTS && FOLD_SUBS) {
int c2 = getIntValue(Binary.getVal2(s));
if (def.operator == INT_ADD) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a + c1; y = x - c2
return Binary.create(INT_ADD, y.copyRO(), a.copyRO(), IC(c1 - c2));
} else if (def.operator == INT_SUB) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a - c1; y = x - c2
return Binary.create(INT_ADD, y.copyRO(), a.copyRO(), IC(-c1 - c2));
} else if (def.operator == INT_NEG && FOLD_CONSTANTS_TO_LHS) {
// x = -a; y = x - c2;
return Binary.create(INT_SUB, y.copyRO(), IC(-c2), a.copyRO());
}
}
return null;
}
case REF_SUB_opcode: {
if (FOLD_REFS && FOLD_SUBS) {
Address c2 = getAddressValue(Binary.getVal2(s));
if (def.operator == REF_ADD) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a + c1; y = x - c2
return Binary.create(REF_ADD, y.copyRO(), a.copyRO(), AC(c1.toWord().minus(c2.toWord()).toAddress()));
} else if (def.operator == REF_SUB) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a - c1; y = x - c2
return Binary.create(REF_ADD,
y.copyRO(),
a.copyRO(),
AC(Word.zero().minus(c1.toWord()).minus(c2.toWord()).toAddress()));
} else if (def.operator == REF_NEG && FOLD_CONSTANTS_TO_LHS) {
// x = -a; y = x - c2;
return Binary.create(REF_SUB, y.copyRO(), AC(Word.zero().minus(c2.toWord()).toAddress()), a.copyRO());
}
}
return null;
}
case LONG_SUB_opcode: {
if (FOLD_LONGS && FOLD_SUBS) {
long c2 = getLongValue(Binary.getVal2(s));
if (def.operator == LONG_ADD) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a + c1; y = x - c2
return Binary.create(LONG_ADD, y.copyRO(), a.copyRO(), LC(c1 - c2));
} else if (def.operator == LONG_SUB) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a - c1; y = x - c2
return Binary.create(LONG_ADD, y.copyRO(), a.copyRO(), LC(-c1 - c2));
} else if (def.operator == LONG_NEG && FOLD_CONSTANTS_TO_LHS) {
// x = -a; y = x - c2;
return Binary.create(LONG_SUB, y.copyRO(), LC(-c2), a.copyRO());
}
}
return null;
}
case FLOAT_SUB_opcode: {
if (FOLD_FLOATS && FOLD_SUBS) {
float c2 = getFloatValue(Binary.getVal2(s));
if (def.operator == FLOAT_ADD) {
float c1 = getFloatValue(Binary.getVal2(def));
// x = a + c1; y = x - c2
return Binary.create(FLOAT_ADD, y.copyRO(), a.copyRO(), FC(c1 - c2));
} else if (def.operator == FLOAT_SUB) {
float c1 = getFloatValue(Binary.getVal2(def));
// x = a - c1; y = x - c2
return Binary.create(FLOAT_ADD, y.copyRO(), a.copyRO(), FC(-c1 - c2));
} else if (def.operator == FLOAT_NEG && FOLD_CONSTANTS_TO_LHS) {
// x = -a; y = x - c2;
return Binary.create(FLOAT_SUB, y.copyRO(), FC(-c2), a.copyRO());
}
}
return null;
}
case DOUBLE_SUB_opcode: {
if (FOLD_DOUBLES && FOLD_SUBS) {
double c2 = getDoubleValue(Binary.getVal2(s));
if (def.operator == FLOAT_ADD) {
double c1 = getDoubleValue(Binary.getVal2(def));
// x = a + c1; y = x - c2
return Binary.create(DOUBLE_ADD, y.copyRO(), a.copyRO(), DC(c1 - c2));
} else if (def.operator == DOUBLE_SUB) {
double c1 = getDoubleValue(Binary.getVal2(def));
// x = a - c1; y = x + c2
return Binary.create(DOUBLE_ADD, y.copyRO(), a.copyRO(), DC(-c1 - c2));
} else if (def.operator == DOUBLE_NEG && FOLD_CONSTANTS_TO_LHS) {
// x = -a; y = x - c2;
return Binary.create(DOUBLE_SUB, y.copyRO(), DC(-c2), a.copyRO());
}
}
return null;
}
case INT_MUL_opcode: {
if (FOLD_INTS && FOLD_MULTS) {
int c2 = getIntValue(Binary.getVal2(s));
if (def.operator == INT_MUL) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a * c1; y = x * c2
return Binary.create(INT_MUL, y.copyRO(), a.copyRO(), IC(c1 * c2));
} else if (def.operator == INT_NEG) {
// x = -a; y = x * c2;
return Binary.create(INT_MUL, y.copyRO(), a.copyRO(), IC(-c2));
}
}
return null;
}
case LONG_MUL_opcode: {
if (FOLD_LONGS && FOLD_MULTS) {
long c2 = getLongValue(Binary.getVal2(s));
if (def.operator == LONG_MUL) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a * c1; y = x * c2
return Binary.create(LONG_MUL, y.copyRO(), a.copyRO(), LC(c1 * c2));
} else if (def.operator == LONG_NEG) {
// x = -a; y = x * c2;
return Binary.create(LONG_MUL, y.copyRO(), a.copyRO(), LC(-c2));
}
}
return null;
}
case FLOAT_MUL_opcode: {
if (FOLD_FLOATS && FOLD_MULTS) {
float c2 = getFloatValue(Binary.getVal2(s));
if (def.operator == FLOAT_MUL) {
float c1 = getFloatValue(Binary.getVal2(def));
// x = a * c1; y = x * c2
return Binary.create(FLOAT_MUL, y.copyRO(), a.copyRO(), FC(c1 * c2));
} else if (def.operator == FLOAT_NEG) {
// x = -a; y = x * c2;
return Binary.create(FLOAT_MUL, y.copyRO(), a.copyRO(), FC(-c2));
}
}
return null;
}
case DOUBLE_MUL_opcode: {
if (FOLD_DOUBLES && FOLD_MULTS) {
double c2 = getDoubleValue(Binary.getVal2(s));
if (def.operator == DOUBLE_MUL) {
double c1 = getDoubleValue(Binary.getVal2(def));
// x = a * c1; y = x * c2
return Binary.create(DOUBLE_MUL, y.copyRO(), a.copyRO(), DC(c1 * c2));
} else if (def.operator == DOUBLE_NEG) {
// x = -a; y = x * c2;
return Binary.create(DOUBLE_MUL, y.copyRO(), a.copyRO(), DC(-c2));
}
}
return null;
}
case INT_DIV_opcode: {
if (FOLD_INTS && FOLD_DIVS) {
int c2 = getIntValue(GuardedBinary.getVal2(s));
if (def.operator == INT_DIV) {
int c1 = getIntValue(GuardedBinary.getVal2(def));
OPT_Operand guard = GuardedBinary.getGuard(def);
// x = a / c1; y = x / c2
return GuardedBinary.create(INT_DIV, y.copyRO(), a.copyRO(), IC(c1 * c2), guard);
} else if (def.operator == INT_NEG) {
OPT_Operand guard = GuardedBinary.getGuard(s);
// x = -a; y = x / c2;
return GuardedBinary.create(INT_DIV, y.copyRO(), a.copyRO(), IC(-c2), guard);
}
}
return null;
}
case LONG_DIV_opcode: {
if (FOLD_LONGS && FOLD_DIVS) {
long c2 = getLongValue(GuardedBinary.getVal2(s));
if (def.operator == LONG_DIV) {
long c1 = getLongValue(GuardedBinary.getVal2(def));
OPT_Operand guard = GuardedBinary.getGuard(def);
// x = a / c1; y = x / c2
return GuardedBinary.create(LONG_DIV, y.copyRO(), a.copyRO(), LC(c1 * c2), guard);
} else if (def.operator == LONG_NEG) {
OPT_Operand guard = GuardedBinary.getGuard(s);
// x = -a; y = x / c2;
return GuardedBinary.create(LONG_DIV, y.copyRO(), a.copyRO(), LC(-c2), guard);
}
}
return null;
}
case FLOAT_DIV_opcode: {
if (FOLD_FLOATS && FOLD_DIVS) {
float c2 = getFloatValue(Binary.getVal2(s));
if (def.operator == FLOAT_DIV) {
float c1 = getFloatValue(Binary.getVal2(def));
// x = a / c1; y = x / c2
return Binary.create(FLOAT_DIV, y.copyRO(), a.copyRO(), FC(c1 * c2));
} else if (def.operator == FLOAT_NEG) {
// x = -a; y = x / c2;
return Binary.create(FLOAT_DIV, y.copyRO(), a.copyRO(), FC(-c2));
}
}
return null;
}
case DOUBLE_DIV_opcode: {
if (FOLD_DOUBLES && FOLD_DIVS) {
double c2 = getDoubleValue(Binary.getVal2(s));
if (def.operator == DOUBLE_DIV) {
double c1 = getDoubleValue(Binary.getVal2(def));
// x = a / c1; y = x / c2
return Binary.create(DOUBLE_DIV, y.copyRO(), a.copyRO(), DC(c1 * c2));
} else if (def.operator == DOUBLE_NEG) {
// x = -a; y = x / c2;
return Binary.create(DOUBLE_DIV, y.copyRO(), a.copyRO(), DC(-c2));
}
}
return null;
}
case INT_SHL_opcode: {
if (FOLD_INTS && FOLD_SHIFTLS) {
int c2 = getIntValue(Binary.getVal2(s));
if (def.operator == INT_SHL) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a << c1; y = x << c2
return Binary.create(INT_SHL, y.copyRO(), a.copyRO(), IC(c1 + c2));
} else if ((def.operator == INT_SHR) || (def.operator == INT_USHR)) {
int c1 = getIntValue(Binary.getVal2(def));
if (c1 == c2) {
// x = a >> c1; y = x << c1
return Binary.create(INT_AND, y.copyRO(), a.copyRO(), IC(-1 << c1));
}
} else if (def.operator == INT_AND) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a & c1; y = << c2
if ((c1 << c2) == (-1 << c2)) {
// the first mask is redundant
return Binary.create(INT_SHL, y.copyRO(), a.copyRO(), IC(c2));
}
} else if ((def.operator == INT_OR)||(def.operator == INT_XOR)) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a | c1; y = << c2
if ((c1 << c2) == 0) {
// the first mask is redundant
return Binary.create(INT_SHL, y.copyRO(), a.copyRO(), IC(c2));
}
}
}
return null;
}
case REF_SHL_opcode: {
if (FOLD_REFS && FOLD_SHIFTLS) {
int c2 = getIntValue(Binary.getVal2(s));
if (def.operator == REF_SHL) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a << c1; y = x << c2
return Binary.create(REF_SHL, y.copyRO(), a.copyRO(), IC(c1 + c2));
} else if ((def.operator == REF_SHR) || (def.operator == REF_USHR)) {
int c1 = getIntValue(Binary.getVal2(def));
if (c1 == c2) {
// x = a >> c1; y = x << c1
return Binary.create(REF_AND,
y.copyRO(),
a.copyRO(),
AC(Word.zero().minus(Word.one()).lsh(c1).toAddress()));
}
} else if (def.operator == REF_AND) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a & c1; y = << c2
if (c1.toWord().lsh(c2).EQ(Word.fromIntSignExtend(-1).lsh(c2))) {
// the first mask is redundant
return Binary.create(REF_SHL, y.copyRO(), a.copyRO(), IC(c2));
}
} else if ((def.operator == REF_OR)||(def.operator == REF_XOR)) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a | c1; y = << c2
if (c1.toWord().lsh(c2).EQ(Word.zero())) {
// the first mask is redundant
return Binary.create(REF_SHL, y.copyRO(), a.copyRO(), IC(c2));
}
}
}
return null;
}
case LONG_SHL_opcode: {
if (FOLD_LONGS && FOLD_SHIFTLS) {
int c2 = getIntValue(Binary.getVal2(s));
if (def.operator == LONG_SHL) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a << c1; y = x << c2
return Binary.create(LONG_SHL, y.copyRO(), a.copyRO(), IC(c1 + c2));
} else if ((def.operator == LONG_SHR) || (def.operator == LONG_USHR)) {
int c1 = getIntValue(Binary.getVal2(def));
if (c1 == c2) {
// x = a >> c1; y = x << c1
return Binary.create(LONG_AND, y.copyRO(), a.copyRO(), LC(-1L << c1));
}
} else if (def.operator == LONG_AND) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a & c1; y = << c2
if ((c1 << c2) == (-1L << c2)) {
// the first mask is redundant
return Binary.create(LONG_SHL, y.copyRO(), a.copyRO(), IC(c2));
}
} else if ((def.operator == LONG_OR)||(def.operator == LONG_XOR)) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a | c1; y = << c2
if ((c1 << c2) == 0L) {
// the first mask is redundant
return Binary.create(LONG_SHL, y.copyRO(), a.copyRO(), IC(c2));
}
}
}
return null;
}
case INT_SHR_opcode: {
if (FOLD_INTS && FOLD_SHIFTRS) {
int c2 = getIntValue(Binary.getVal2(s));
if (def.operator == INT_SHR) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a >> c1; y = x >> c2
return Binary.create(INT_SHR, y.copyRO(), a.copyRO(), IC(c1 + c2));
} else if (def.operator == INT_SHL) {
int c1 = getIntValue(Binary.getVal2(def));
if (c1 == c2) {
if (c1 == 24) {
// x = a << 24; y = x >> 24
return Unary.create(INT_2BYTE, y.copyRO(), a.copyRO());
} else if (c1 == 16) {
// x = a << 16; y = x >> 16
return Unary.create(INT_2SHORT, y.copyRO(), a.copyRO());
}
}
} else if (def.operator == INT_AND) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a & c1; y = >> c2
if ((c1 >> c2) == -1) {
// the first mask is redundant
return Binary.create(INT_SHR, y.copyRO(), a.copyRO(), IC(c2));
}
} else if ((def.operator == INT_OR)||(def.operator == INT_XOR)) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a | c1; y = >> c2
if ((c1 >>> c2) == 0) {
// the first mask is redundant
return Binary.create(INT_SHR, y.copyRO(), a.copyRO(), IC(c2));
}
}
}
return null;
}
case REF_SHR_opcode: {
if (FOLD_REFS && FOLD_SHIFTRS) {
int c2 = getIntValue(Binary.getVal2(s));
if (def.operator == REF_SHR) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a >> c1; y = x >> c2
return Binary.create(REF_SHR, y.copyRO(), a.copyRO(), IC(c1 + c2));
} else if (def.operator == REF_AND) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a & c1; y = >> c2
if (c1.toWord().rsha(c2).EQ(Word.zero().minus(Word.one()))) {
// the first mask is redundant
return Binary.create(REF_SHR, y.copyRO(), a.copyRO(), IC(c2));
}
} else if ((def.operator == REF_OR)||(def.operator == REF_XOR)) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a | c1; y = >> c2
if (c1.toWord().rshl(c2).EQ(Word.zero())) {
// the first mask is redundant
return Binary.create(REF_SHR, y.copyRO(), a.copyRO(), IC(c2));
}
}
}
return null;
}
case LONG_SHR_opcode: {
if (FOLD_LONGS && FOLD_SHIFTRS) {
int c2 = getIntValue(Binary.getVal2(s));
if (def.operator == LONG_SHR) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a >> c1; y = x >> c2
return Binary.create(LONG_SHR, y.copyRO(), a.copyRO(), IC(c1 + c2));
} else if (def.operator == LONG_AND) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a & c1; y = >> c2
if ((c1 >> c2) == -1L) {
// the first mask is redundant
return Binary.create(LONG_SHR, y.copyRO(), a.copyRO(), IC(c2));
}
} else if ((def.operator == LONG_OR)||(def.operator == LONG_XOR)) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a & c1; y = >> c2
if ((c1 >>> c2) == 0L) {
// the first mask is redundant
return Binary.create(LONG_SHR, y.copyRO(), a.copyRO(), IC(c2));
}
}
}
return null;
}
case INT_USHR_opcode: {
if (FOLD_INTS && FOLD_SHIFTRS) {
int c2 = getIntValue(Binary.getVal2(s));
if (def.operator == INT_USHR) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a >>> c1; y = x >>> c2
return Binary.create(INT_USHR, y.copyRO(), a.copyRO(), IC(c1 + c2));
} else if (def.operator == INT_SHL) {
int c1 = getIntValue(Binary.getVal2(def));
if (c1 == c2) {
// x = a << c1; y = x >>> c1
return Binary.create(INT_AND, y.copyRO(), a.copyRO(), IC(-1 >>> c1));
}
} else if (def.operator == INT_AND) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a & c1; y = >>> c2
if ((c1 >> c2) == -1L) {
// the first mask is redundant
return Binary.create(INT_USHR, y.copyRO(), a.copyRO(), IC(c2));
}
} else if ((def.operator == INT_OR)||(def.operator == INT_XOR)) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a | c1; y = >>> c2
if ((c1 >>> c2) == 0) {
// the first mask is redundant
return Binary.create(INT_USHR, y.copyRO(), a.copyRO(), IC(c2));
}
}
}
return null;
}
case REF_USHR_opcode: {
if (FOLD_REFS && FOLD_SHIFTRS) {
int c2 = getIntValue(Binary.getVal2(s));
if (def.operator == REF_USHR) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a >>> c1; y = x >>> c2
return Binary.create(REF_USHR, y.copyRO(), a.copyRO(), IC(c1 + c2));
} else if (def.operator == REF_SHL) {
int c1 = getIntValue(Binary.getVal2(def));
if (c1 == c2) {
// x = a << c1; y = x >>> c1
return Binary.create(REF_AND,
y.copyRO(),
a.copyRO(),
AC(Word.zero().minus(Word.one()).rshl(c1).toAddress()));
}
} else if (def.operator == REF_AND) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a & c1; y = >>> c2
if (c1.toWord().rsha(c2).EQ(Word.zero().minus(Word.one()))) {
// the first mask is redundant
return Binary.create(REF_USHR, y.copyRO(), a.copyRO(), IC(c2));
}
} else if ((def.operator == REF_OR)||(def.operator == REF_XOR)) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a | c1; y = >>> c2
if (c1.toWord().rshl(c2).EQ(Word.zero())) {
// the first mask is redundant
return Binary.create(REF_USHR, y.copyRO(), a.copyRO(), IC(c2));
}
}
}
return null;
}
case LONG_USHR_opcode: {
if (FOLD_LONGS && FOLD_SHIFTRS) {
int c2 = getIntValue(Binary.getVal2(s));
if (def.operator == LONG_USHR) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a >>> c1; y = x >>> c2
return Binary.create(LONG_USHR, y.copyRO(), a.copyRO(), IC(c1 + c2));
} else if (def.operator == LONG_SHL) {
int c1 = getIntValue(Binary.getVal2(def));
if (c1 == c2) {
// x = a << c1; y = x >>> c1
return Binary.create(LONG_AND, y.copyRO(), a.copyRO(), LC(-1L >>> c1));
}
} else if (def.operator == LONG_AND) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a & c1; y = >>> c2
if ((c1 >> c2) == -1L) {
// the first mask is redundant
return Binary.create(LONG_USHR, y.copyRO(), a.copyRO(), IC(c2));
}
} else if ((def.operator == LONG_OR)||(def.operator == LONG_XOR)) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a & c1; y = >>> c2
if ((c1 >>> c2) == 0L) {
// the first mask is redundant
return Binary.create(LONG_USHR, y.copyRO(), a.copyRO(), IC(c2));
}
}
}
return null;
}
case INT_AND_opcode: {
if (FOLD_INTS && FOLD_ANDS) {
int c2 = getIntValue(Binary.getVal2(s));
if (def.operator == INT_AND) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a & c1; y = x & c2
return Binary.create(INT_AND, y.copyRO(), a.copyRO(), IC(c1 & c2));
} else if (def.operator == INT_OR) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a | c1; y = x & c2
if ((c1 & c2) == 0) {
return Binary.create(INT_AND, y.copyRO(), a.copyRO(), IC(c2));
}
} else if (def.operator == INT_XOR) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a ^ c1; y = x & c2
if ((c1 & c2) == 0) {
return Binary.create(INT_AND, y.copyRO(), a.copyRO(), IC(c2));
}
} else if (def.operator == INT_SHR) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a >> c1; y = x & c2
if ((-1 >>> c1) == c2) {
// turn arithmetic shifts into logical shifts if possible
return Binary.create(INT_USHR, y.copyRO(), a.copyRO(), IC(c1));
}
} else if (def.operator == INT_SHL) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a << c1; y = x & c2
if (((-1 << c1) & c2) == (-1 << c1)) {
// does the mask zero bits already cleared by the shift?
return Binary.create(INT_SHL, y.copyRO(), a.copyRO(), IC(c1));
}
} else if (def.operator == INT_USHR) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a >>> c1; y = x & c2
if (((-1 >>> c1) & c2) == (-1 >>> c1)) {
// does the mask zero bits already cleared by the shift?
return Binary.create(INT_USHR, y.copyRO(), a.copyRO(), IC(c1));
}
}
}
return null;
}
case REF_AND_opcode: {
if (FOLD_REFS && FOLD_ANDS) {
Address c2 = getAddressValue(Binary.getVal2(s));
if (def.operator == REF_AND) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a & c1; y = x & c2
return Binary.create(REF_AND, y.copyRO(), a.copyRO(), AC(c1.toWord().and(c2.toWord()).toAddress()));
} else if (def.operator == REF_OR) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a | c1; y = x & c2
if (c1.toWord().and(c2.toWord()).EQ(Word.zero())) {
return Binary.create(REF_AND, y.copyRO(), a.copyRO(), AC(c2));
}
} else if (def.operator == REF_XOR) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a ^ c1; y = x & c2
if (c1.toWord().and(c2.toWord()).EQ(Word.zero())) {
return Binary.create(REF_AND, y.copyRO(), a.copyRO(), AC(c2));
}
} else if (def.operator == REF_SHR) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a >> c1; y = x & c2
if (Word.zero().minus(Word.one()).rshl(c1).toAddress().EQ(c2)) {
// turn arithmetic shifts into logical ones if possible
return Binary.create(REF_USHR, y.copyRO(), a.copyRO(), IC(c1));
}
} else if (def.operator == REF_SHL) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a << c1; y = x & c2
if (Word.zero().minus(Word.one()).lsh(c1).and(c2.toWord()).EQ(Word.zero().minus(Word.one()).lsh(c1))) {
// does the mask zero bits already cleared by the shift?
return Binary.create(REF_SHL, y.copyRO(), a.copyRO(), IC(c1));
}
} else if (def.operator == REF_USHR) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a >>> c1; y = x & c2
if (Word.zero().minus(Word.one()).rshl(c1).and(c2.toWord()).EQ(Word.zero().minus(Word.one()).rshl(c1))) {
// does the mask zero bits already cleared by the shift?
return Binary.create(REF_USHR, y.copyRO(), a.copyRO(), IC(c1));
}
}
}
return null;
}
case LONG_AND_opcode: {
if (FOLD_LONGS && FOLD_ANDS) {
long c2 = getLongValue(Binary.getVal2(s));
if (def.operator == LONG_AND) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a & c1; y = x & c2
return Binary.create(LONG_AND, y.copyRO(), a.copyRO(), LC(c1 & c2));
} else if (def.operator == LONG_OR) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a | c1; y = x & c2
if ((c1 & c2) == 0) {
return Binary.create(LONG_AND, y.copyRO(), a.copyRO(), LC(c2));
}
} else if (def.operator == LONG_XOR) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a ^ c1; y = x & c2
if ((c1 & c2) == 0) {
return Binary.create(LONG_AND, y.copyRO(), a.copyRO(), LC(c2));
}
} else if (def.operator == LONG_SHR) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a >> c1; y = x & c2
if ((-1L >>> c1) == c2) {
// turn arithmetic shifts into logical ones if possible
return Binary.create(LONG_USHR, y.copyRO(), a.copyRO(), IC(c1));
}
} else if (def.operator == LONG_SHL) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a << c1; y = x & c2
if (((-1L << c1) & c2) == (-1L << c1)) {
// does the mask zero bits already cleared by the shift?
return Binary.create(LONG_SHL, y.copyRO(), a.copyRO(), IC(c1));
}
} else if (def.operator == LONG_USHR) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a >>> c1; y = x & c2
if (((-1L >>> c1) & c2) == (-1L >>> c1)) {
// does the mask zero bits already cleared by the shift?
return Binary.create(LONG_USHR, y.copyRO(), a.copyRO(), IC(c1));
}
}
}
return null;
}
case INT_OR_opcode: {
if (FOLD_INTS && FOLD_ORS) {
int c2 = getIntValue(Binary.getVal2(s));
if (def.operator == INT_OR) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a | c1; y = x | c2
return Binary.create(INT_OR, y.copyRO(), a.copyRO(), IC(c1 | c2));
} else if (def.operator == INT_AND) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a & c1; y = x | c2
if ((~c1 | c2) == c2) {
return Binary.create(INT_OR, y.copyRO(), a.copyRO(), IC(c2));
}
} else if (def.operator == INT_XOR) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a ^ c1; y = x | c2
if ((c1 | c2) == c2) {
return Binary.create(INT_OR, y.copyRO(), a.copyRO(), IC(c2));
}
}
}
return null;
}
case REF_OR_opcode: {
if (FOLD_REFS && FOLD_ORS) {
Address c2 = getAddressValue(Binary.getVal2(s));
if (def.operator == REF_OR) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a | c1; y = x | c2
return Binary.create(REF_OR, y.copyRO(), a.copyRO(), AC(c1.toWord().or(c2.toWord()).toAddress()));
} else if (def.operator == REF_AND) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a & c1; y = x | c2
if (c1.toWord().not().or(c2.toWord()).EQ(c2.toWord())) {
return Binary.create(REF_OR, y.copyRO(), a.copyRO(), AC(c2));
}
} else if (def.operator == REF_XOR) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a ^ c1; y = x | c2
if (c1.toWord().or(c2.toWord()).EQ(c2.toWord())) {
return Binary.create(REF_OR, y.copyRO(), a.copyRO(), AC(c2));
}
}
}
return null;
}
case LONG_OR_opcode: {
if (FOLD_LONGS && FOLD_ORS) {
long c2 = getLongValue(Binary.getVal2(s));
if (def.operator == LONG_OR) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a | c1; y = x | c2
return Binary.create(LONG_OR, y.copyRO(), a.copyRO(), LC(c1 | c2));
} else if (def.operator == LONG_AND) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a & c1; y = x | c2
if ((~c1 | c2) == c2) {
return Binary.create(LONG_OR, y.copyRO(), a.copyRO(), LC(c2));
}
} else if (def.operator == LONG_XOR) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a ^ c1; y = x | c2
if ((c1 | c2) == c2) {
return Binary.create(LONG_OR, y.copyRO(), a.copyRO(), LC(c2));
}
}
}
return null;
}
case INT_XOR_opcode: {
if (FOLD_INTS && FOLD_XORS) {
int c2 = getIntValue(Binary.getVal2(s));
if (def.operator == INT_XOR) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a ^ c1; y = x ^ c2
return Binary.create(INT_XOR, y.copyRO(), a.copyRO(), IC(c1 ^ c2));
} else if (def.operator == INT_NOT) {
// x = ~a; y = x ^ c2
return Binary.create(INT_XOR, y.copyRO(), a.copyRO(), IC(~c2));
} else if (def.operator == BOOLEAN_NOT) {
// x = !a; y = x ^ c2
return Binary.create(INT_XOR, y.copyRO(), a.copyRO(), IC(c2 ^ 1));
}
}
return null;
}
case REF_XOR_opcode: {
if (FOLD_REFS && FOLD_XORS) {
Address c2 = getAddressValue(Binary.getVal2(s));
if (def.operator == REF_XOR) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a ^ c1; y = x ^ c2
return Binary.create(REF_XOR, y.copyRO(), a.copyRO(), AC(c1.toWord().xor(c2.toWord()).toAddress()));
} else if (def.operator == REF_NOT) {
// x = ~a; y = x ^ c2
return Binary.create(REF_XOR, y.copyRO(), a.copyRO(), AC(c2.toWord().not().toAddress()));
}
}
return null;
}
case LONG_XOR_opcode: {
if (FOLD_LONGS && FOLD_XORS) {
long c2 = getLongValue(Binary.getVal2(s));
if (def.operator == LONG_XOR) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a ^ c1; y = x ^ c2
return Binary.create(LONG_XOR, y.copyRO(), a.copyRO(), LC(c1 ^ c2));
} else if (def.operator == LONG_NOT) {
// x = ~a; y = x ^ c2
return Binary.create(LONG_XOR, y.copyRO(), a.copyRO(), LC(~c2));
}
}
return null;
}
case LONG_CMP_opcode: {
if (FOLD_LONGS && FOLD_CMPS) {
long c2 = getLongValue(Binary.getVal2(s));
if (def.operator == LONG_ADD) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a + c1; y = x cmp c2
return Binary.create(LONG_CMP, y.copyRO(), a.copyRO(), LC(c2 - c1));
} else if (def.operator == LONG_SUB) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a - c1; y = x cmp c2
return Binary.create(LONG_CMP, y.copyRO(), a.copyRO(), LC(c1 + c2));
} else if (def.operator == LONG_NEG) {
// x = -a; y = x cmp c2
return Binary.create(LONG_CMP, y.copyRO(), LC(-c2), a.copyRO());
}
}
return null;
}
case FLOAT_CMPL_opcode:
case FLOAT_CMPG_opcode: {
if (FOLD_FLOATS && FOLD_CMPS) {
float c2 = getFloatValue(Binary.getVal2(s));
if (def.operator == FLOAT_ADD) {
float c1 = getFloatValue(Binary.getVal2(def));
// x = a + c1; y = x cmp c2
return Binary.create(s.operator, y.copyRO(), a.copyRO(), FC(c2 - c1));
} else if (def.operator == FLOAT_SUB) {
float c1 = getFloatValue(Binary.getVal2(def));
// x = a - c1; y = x cmp c2
return Binary.create(s.operator, y.copyRO(), a.copyRO(), FC(c1 + c2));
} else if (def.operator == FLOAT_NEG) {
// x = -a; y = x cmp c2
return Binary.create(s.operator, y.copyRO(), FC(-c2), a.copyRO());
}
}
return null;
}
case DOUBLE_CMPL_opcode:
case DOUBLE_CMPG_opcode: {
if (FOLD_DOUBLES && FOLD_CMPS) {
double c2 = getDoubleValue(Binary.getVal2(s));
if (def.operator == DOUBLE_ADD) {
double c1 = getDoubleValue(Binary.getVal2(def));
// x = a + c1; y = x cmp c2
return Binary.create(s.operator, y.copyRO(), a.copyRO(), DC(c2 - c1));
} else if (def.operator == DOUBLE_SUB) {
double c1 = getDoubleValue(Binary.getVal2(def));
// x = a - c1; y = x cmp c2
return Binary.create(s.operator, y.copyRO(), a.copyRO(), DC(c1 + c2));
} else if (def.operator == DOUBLE_NEG) {
// x = -a; y = x cmp c2
return Binary.create(s.operator, y.copyRO(), DC(-c2), a.copyRO());
}
}
return null;
}
case BOOLEAN_CMP_INT_opcode: {
if (FOLD_INTS && FOLD_CMPS) {
int c2 = getIntValue(BooleanCmp.getVal2(s));
OPT_ConditionOperand cond = (OPT_ConditionOperand) BooleanCmp.getCond(s).copy();
OPT_BranchProfileOperand prof = (OPT_BranchProfileOperand) BooleanCmp.getBranchProfile(s).copy();
if (def.operator == INT_ADD) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a + c1; y = x cmp c2
return BooleanCmp.create(BOOLEAN_CMP_INT, y.copyRO(), a.copyRO(), IC(c2 - c1), cond, prof);
} else if (def.operator == INT_SUB) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a - c1; y = x cmp c2
return BooleanCmp.create(BOOLEAN_CMP_INT, y.copyRO(), a.copyRO(), IC(c1 + c2), cond, prof);
} else if (def.operator == INT_NEG) {
// x = -a; y = x cmp c2
return BooleanCmp.create(BOOLEAN_CMP_INT, y.copyRO(), a.copyRO(), IC(-c2), cond.flipOperands(), prof);
} else if (def.operator == BOOLEAN_CMP_INT) {
int c1 = getIntValue(BooleanCmp.getVal2(def));
OPT_ConditionOperand cond2 = BooleanCmp.getCond(def).copy().asCondition();
// x = a cmp c1 ? true : false; y = x cmp c2 ? true : false
if ((cond.isEQUAL() && c2 == 1)||
(cond.isNOT_EQUAL() && c2 == 0)) {
// Fold away redundancy boolean_cmp
return BooleanCmp.create(BOOLEAN_CMP_INT, y.copyRO(), a.copyRO(), IC(c1), cond2, prof);
} else if ((cond.isEQUAL() && c2 == 0)||
(cond.isNOT_EQUAL() && c2 == 1)) {
// Fold away redundancy boolean_cmp
return BooleanCmp.create(BOOLEAN_CMP_INT, y.copyRO(), a.copyRO(), IC(c1), cond2.flipCode(), prof);
}
} else if (def.operator == BOOLEAN_CMP_LONG) {
long c1 = getLongValue(BooleanCmp.getVal2(def));
OPT_ConditionOperand cond2 = BooleanCmp.getCond(def).copy().asCondition();
// x = a cmp c1 ? true : false; y = x cmp c2 ? true : false
if ((cond.isEQUAL() && c2 == 1)||
(cond.isNOT_EQUAL() && c2 == 0)) {
// Fold away redundancy boolean_cmp
return BooleanCmp.create(BOOLEAN_CMP_LONG, y.copyRO(), a.copyRO(), LC(c1), cond2, prof);
} else if ((cond.isEQUAL() && c2 == 0)||
(cond.isNOT_EQUAL() && c2 == 1)) {
// Fold away redundancy boolean_cmp
return BooleanCmp.create(BOOLEAN_CMP_LONG, y.copyRO(), a.copyRO(), LC(c1), cond2.flipCode(), prof);
}
} else if (def.operator == BOOLEAN_CMP_ADDR) {
Address c1 = getAddressValue(BooleanCmp.getVal2(def));
OPT_ConditionOperand cond2 = BooleanCmp.getCond(def).copy().asCondition();
// x = a cmp c1 ? true : false; y = x cmp c2 ? true : false
if ((cond.isEQUAL() && c2 == 1)||
(cond.isNOT_EQUAL() && c2 == 0)) {
// Fold away redundancy boolean_cmp
return BooleanCmp.create(BOOLEAN_CMP_ADDR, y.copyRO(), a.copyRO(), AC(c1), cond2, prof);
} else if ((cond.isEQUAL() && c2 == 0)||
(cond.isNOT_EQUAL() && c2 == 1)) {
// Fold away redundancy boolean_cmp
return BooleanCmp.create(BOOLEAN_CMP_ADDR, y.copyRO(), a.copyRO(), AC(c1), cond2.flipCode(), prof);
}
} else if (def.operator == BOOLEAN_CMP_FLOAT) {
float c1 = getFloatValue(BooleanCmp.getVal2(def));
OPT_ConditionOperand cond2 = BooleanCmp.getCond(def).copy().asCondition();
// x = a cmp c1 ? true : false; y = x cmp c2 ? true : false
if ((cond.isEQUAL() && c2 == 1)||
(cond.isNOT_EQUAL() && c2 == 0)) {
// Fold away redundancy boolean_cmp
return BooleanCmp.create(BOOLEAN_CMP_FLOAT, y.copyRO(), a.copyRO(), FC(c1), cond2, prof);
} else if ((cond.isEQUAL() && c2 == 0)||
(cond.isNOT_EQUAL() && c2 == 1)) {
// Fold away redundancy boolean_cmp
return BooleanCmp.create(BOOLEAN_CMP_FLOAT, y.copyRO(), a.copyRO(), FC(c1), cond2.flipCode(), prof);
}
} else if (def.operator == BOOLEAN_CMP_DOUBLE) {
double c1 = getDoubleValue(BooleanCmp.getVal2(def));
OPT_ConditionOperand cond2 = BooleanCmp.getCond(def).copy().asCondition();
// x = a cmp c1 ? true : false; y = x cmp c2 ? true : false
if ((cond.isEQUAL() && c2 == 1)||
(cond.isNOT_EQUAL() && c2 == 0)) {
// Fold away redundancy boolean_cmp
return BooleanCmp.create(BOOLEAN_CMP_DOUBLE, y.copyRO(), a.copyRO(), DC(c1), cond2, prof);
} else if ((cond.isEQUAL() && c2 == 0)||
(cond.isNOT_EQUAL() && c2 == 1)) {
// Fold away redundancy boolean_cmp
return BooleanCmp.create(BOOLEAN_CMP_DOUBLE, y.copyRO(), a.copyRO(), DC(c1), cond2.flipCode(), prof);
}
} else if (def.operator == LONG_CMP) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a lcmp c1; y = y = x cmp c2 ? true : false
if (cond.isEQUAL() && c2 == 0) {
return BooleanCmp.create(BOOLEAN_CMP_LONG, y.copyRO(), a.copyRO(), LC(c1),
OPT_ConditionOperand.EQUAL(), prof);
} else if (cond.isNOT_EQUAL() && c2 == 0) {
return BooleanCmp.create(BOOLEAN_CMP_LONG, y.copyRO(), a.copyRO(), LC(c1),
OPT_ConditionOperand.NOT_EQUAL(), prof);
} else if ((cond.isEQUAL() && c2 == 1)||(cond.isGREATER() && c2 == 0)){
return BooleanCmp.create(BOOLEAN_CMP_LONG, y.copyRO(), a.copyRO(), LC(c1),
OPT_ConditionOperand.GREATER(), prof);
} else if (cond.isGREATER_EQUAL() && c2 == 0){
return BooleanCmp.create(BOOLEAN_CMP_LONG, y.copyRO(), a.copyRO(), LC(c1),
OPT_ConditionOperand.GREATER_EQUAL(), prof);
} else if ((cond.isEQUAL() && c2 == -1)||(cond.isLESS() && c2 == 0)) {
return BooleanCmp.create(BOOLEAN_CMP_LONG, y.copyRO(), a.copyRO(), LC(c1),
OPT_ConditionOperand.LESS(), prof);
} else if (cond.isLESS_EQUAL() && c2 == 0) {
return BooleanCmp.create(BOOLEAN_CMP_LONG, y.copyRO(), a.copyRO(), LC(c1),
OPT_ConditionOperand.LESS_EQUAL(), prof);
}
}
}
return null;
}
case BOOLEAN_CMP_LONG_opcode: {
if (FOLD_LONGS && FOLD_CMPS) {
long c2 = getLongValue(BooleanCmp.getVal2(s));
OPT_ConditionOperand cond = (OPT_ConditionOperand) BooleanCmp.getCond(s).copy();
OPT_BranchProfileOperand prof = (OPT_BranchProfileOperand) BooleanCmp.getBranchProfile(s).copy();
if (def.operator == LONG_ADD) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a + c1; y = x cmp c2
return BooleanCmp.create(BOOLEAN_CMP_LONG, y.copyRO(), a.copyRO(), LC(c2 - c1), cond, prof);
} else if (def.operator == LONG_SUB) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a - c1; y = x cmp c2
return BooleanCmp.create(BOOLEAN_CMP_LONG, y.copyRO(), a.copyRO(), LC(c1 + c2), cond, prof);
} else if (def.operator == LONG_NEG) {
// x = -a; y = x cmp c2
return BooleanCmp.create(BOOLEAN_CMP_INT, y.copyRO(), a.copyRO(), LC(-c2), cond.flipOperands(), prof);
}
}
return null;
}
case BOOLEAN_CMP_ADDR_opcode: {
if (FOLD_REFS && FOLD_CMPS) {
Address c2 = getAddressValue(BooleanCmp.getVal2(s));
OPT_ConditionOperand cond = (OPT_ConditionOperand) BooleanCmp.getCond(s).copy();
OPT_BranchProfileOperand prof = (OPT_BranchProfileOperand) BooleanCmp.getBranchProfile(s).copy();
if (def.operator == REF_ADD) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a + c1; y = x cmp c2
return BooleanCmp.create(BOOLEAN_CMP_ADDR,
y.copyRO(),
a.copyRO(),
AC(c2.toWord().minus(c1.toWord()).toAddress()),
cond,
prof);
} else if (def.operator == REF_SUB) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a - c1; y = x cmp c2
return BooleanCmp.create(BOOLEAN_CMP_ADDR,
y.copyRO(),
a.copyRO(),
AC(c1.toWord().plus(c2.toWord()).toAddress()),
cond,
prof);
} else if (def.operator == REF_NEG) {
// x = -a; y = x cmp c2
return BooleanCmp.create(BOOLEAN_CMP_ADDR,
y.copyRO(),
a.copyRO(),
AC(Word.zero().minus(c2.toWord()).toAddress()),
cond.flipOperands(),
prof);
}
}
return null;
}
case INT_IFCMP_opcode: {
if (FOLD_INTS && FOLD_IFCMPS) {
int c2 = getIntValue(IfCmp.getVal2(s));
OPT_ConditionOperand cond = (OPT_ConditionOperand) IfCmp.getCond(s).copy();
OPT_BranchOperand target = (OPT_BranchOperand) IfCmp.getTarget(s).copy();
OPT_BranchProfileOperand prof = (OPT_BranchProfileOperand) IfCmp.getBranchProfile(s).copy();
if (def.operator == INT_ADD) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a + c1; y = x cmp c2
return IfCmp.create(INT_IFCMP, y.copyRO(), a.copyRO(), IC(c2 - c1), cond, target, prof);
} else if (def.operator == INT_SUB) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a - c1; y = x cmp c2
return IfCmp.create(INT_IFCMP, y.copyRO(), a.copyRO(), IC(c1 + c2), cond, target, prof);
} else if (def.operator == INT_NEG) {
// x = -a; y = x cmp c2
return IfCmp.create(INT_IFCMP, y.copyRO(), a.copyRO(), IC(-c2), cond.flipOperands(), target, prof);
} else if (def.operator == BOOLEAN_CMP_INT) {
int c1 = getIntValue(BooleanCmp.getVal2(def));
OPT_ConditionOperand cond2 = BooleanCmp.getCond(def).copy().asCondition();
// x = a cmp c1 ? true : false; y = x cmp c2
if ((cond.isEQUAL() && c2 == 1)||
(cond.isNOT_EQUAL() && c2 == 0)) {
// Fold away redundancy boolean_cmp
return IfCmp.create(INT_IFCMP, y.copyRO(), a.copyRO(), IC(c1), cond2, target, prof);
} else if ((cond.isEQUAL() && c2 == 0)||
(cond.isNOT_EQUAL() && c2 == 1)) {
// Fold away redundancy boolean_cmp
return IfCmp.create(INT_IFCMP, y.copyRO(), a.copyRO(), IC(c1), cond2.flipCode(), target, prof);
}
} else if (def.operator == BOOLEAN_CMP_LONG) {
long c1 = getLongValue(BooleanCmp.getVal2(def));
OPT_ConditionOperand cond2 = BooleanCmp.getCond(def).copy().asCondition();
// x = a cmp c1 ? true : false; y = x cmp c2
if ((cond.isEQUAL() && c2 == 1)||
(cond.isNOT_EQUAL() && c2 == 0)) {
// Fold away redundancy boolean_cmp
return IfCmp.create(LONG_IFCMP, y.copyRO(), a.copyRO(), LC(c1), cond2, target, prof);
} else if ((cond.isEQUAL() && c2 == 0)||
(cond.isNOT_EQUAL() && c2 == 1)) {
// Fold away redundancy boolean_cmp
return IfCmp.create(LONG_IFCMP, y.copyRO(), a.copyRO(), LC(c1), cond2.flipCode(), target, prof);
}
} else if (def.operator == BOOLEAN_CMP_ADDR) {
Address c1 = getAddressValue(BooleanCmp.getVal2(def));
OPT_ConditionOperand cond2 = BooleanCmp.getCond(def).copy().asCondition();
// x = a cmp c1 ? true : false; y = x cmp c2
if ((cond.isEQUAL() && c2 == 1)||
(cond.isNOT_EQUAL() && c2 == 0)) {
// Fold away redundancy boolean_cmp
return IfCmp.create(REF_IFCMP, y.copyRO(), a.copyRO(), AC(c1), cond2, target, prof);
} else if ((cond.isEQUAL() && c2 == 0)||
(cond.isNOT_EQUAL() && c2 == 1)) {
// Fold away redundancy boolean_cmp
return IfCmp.create(REF_IFCMP, y.copyRO(), a.copyRO(), AC(c1), cond2.flipCode(), target, prof);
}
} else if (def.operator == BOOLEAN_CMP_FLOAT) {
float c1 = getFloatValue(BooleanCmp.getVal2(def));
OPT_ConditionOperand cond2 = BooleanCmp.getCond(def).copy().asCondition();
// x = a cmp c1 ? true : false; y = x cmp c2
if ((cond.isEQUAL() && c2 == 1)||
(cond.isNOT_EQUAL() && c2 == 0)) {
// Fold away redundancy boolean_cmp
return IfCmp.create(REF_IFCMP, y.copyRO(), a.copyRO(), FC(c1), cond2, target, prof);
} else if ((cond.isEQUAL() && c2 == 0)||
(cond.isNOT_EQUAL() && c2 == 1)) {
// Fold away redundancy boolean_cmp
return IfCmp.create(REF_IFCMP, y.copyRO(), a.copyRO(), FC(c1), cond2.flipCode(), target, prof);
}
} else if (def.operator == BOOLEAN_CMP_DOUBLE) {
double c1 = getDoubleValue(BooleanCmp.getVal2(def));
OPT_ConditionOperand cond2 = BooleanCmp.getCond(def).copy().asCondition();
// x = a cmp c1 ? true : false; y = x cmp c2
if ((cond.isEQUAL() && c2 == 1)||
(cond.isNOT_EQUAL() && c2 == 0)) {
// Fold away redundancy boolean_cmp
return IfCmp.create(REF_IFCMP, y.copyRO(), a.copyRO(), DC(c1), cond2, target, prof);
} else if ((cond.isEQUAL() && c2 == 0)||
(cond.isNOT_EQUAL() && c2 == 1)) {
// Fold away redundancy boolean_cmp
return IfCmp.create(REF_IFCMP, y.copyRO(), a.copyRO(), DC(c1), cond2.flipCode(), target, prof);
}
} else if (def.operator == LONG_CMP) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a lcmp c1; y = y = x cmp c2
if (cond.isEQUAL() && c2 == 0) {
return IfCmp.create(LONG_IFCMP, y.copyRO(), a.copyRO(), LC(c1),
OPT_ConditionOperand.EQUAL(), target, prof);
} else if (cond.isNOT_EQUAL() && c2 == 0) {
return IfCmp.create(LONG_IFCMP, y.copyRO(), a.copyRO(), LC(c1),
OPT_ConditionOperand.NOT_EQUAL(), target, prof);
} else if ((cond.isEQUAL() && c2 == 1)||(cond.isGREATER() && c2 == 0)){
return IfCmp.create(LONG_IFCMP, y.copyRO(), a.copyRO(), LC(c1),
OPT_ConditionOperand.GREATER(), target, prof);
} else if (cond.isGREATER_EQUAL() && c2 == 0){
return IfCmp.create(LONG_IFCMP, y.copyRO(), a.copyRO(), LC(c1),
OPT_ConditionOperand.GREATER_EQUAL(), target, prof);
} else if ((cond.isEQUAL() && c2 == -1)||(cond.isLESS() && c2 == 0)) {
return IfCmp.create(LONG_IFCMP, y.copyRO(), a.copyRO(), LC(c1),
OPT_ConditionOperand.LESS(), target, prof);
} else if (cond.isLESS_EQUAL() && c2 == 0) {
return IfCmp.create(LONG_IFCMP, y.copyRO(), a.copyRO(), LC(c1),
OPT_ConditionOperand.LESS_EQUAL(), target, prof);
}
}
}
return null;
}
case LONG_IFCMP_opcode: {
if (FOLD_LONGS && FOLD_IFCMPS) {
long c2 = getLongValue(IfCmp.getVal2(s));
OPT_ConditionOperand cond = (OPT_ConditionOperand) IfCmp.getCond(s).copy();
OPT_BranchOperand target = (OPT_BranchOperand) IfCmp.getTarget(s).copy();
OPT_BranchProfileOperand prof = (OPT_BranchProfileOperand) IfCmp.getBranchProfile(s).copy();
if (def.operator == LONG_ADD) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a + c1; y = x cmp c2
return IfCmp.create(LONG_IFCMP, y.copyRO(), a.copyRO(), LC(c2 - c1), cond, target, prof);
} else if (def.operator == LONG_SUB) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a - c1; y = x cmp c2
return IfCmp.create(LONG_IFCMP, y.copyRO(), a.copyRO(), LC(c1 + c2), cond, target, prof);
} else if (def.operator == LONG_NEG) {
// x = -a; y = x cmp c2
return IfCmp.create(LONG_IFCMP, y.copyRO(), a.copyRO(), LC(-c2), cond.flipOperands(), target, prof);
}
}
return null;
}
case FLOAT_IFCMP_opcode: {
if (FOLD_FLOATS && FOLD_IFCMPS) {
float c2 = getFloatValue(IfCmp.getVal2(s));
OPT_ConditionOperand cond = (OPT_ConditionOperand) IfCmp.getCond(s).copy();
OPT_BranchOperand target = (OPT_BranchOperand) IfCmp.getTarget(s).copy();
OPT_BranchProfileOperand prof = (OPT_BranchProfileOperand) IfCmp.getBranchProfile(s).copy();
if (def.operator == FLOAT_ADD) {
float c1 = getFloatValue(Binary.getVal2(def));
// x = a + c1; y = x cmp c2
return IfCmp.create(FLOAT_IFCMP, y.copyRO(), a.copyRO(), FC(c2 - c1), cond, target, prof);
} else if (def.operator == FLOAT_SUB) {
float c1 = getFloatValue(Binary.getVal2(def));
// x = a - c1; y = x cmp c2
return IfCmp.create(FLOAT_IFCMP, y.copyRO(), a.copyRO(), FC(c1 + c2), cond, target, prof);
} else if (def.operator == FLOAT_NEG) {
// x = -a; y = x cmp c2
return IfCmp.create(FLOAT_IFCMP, y.copyRO(), a.copyRO(), FC(-c2), cond.flipOperands(), target, prof);
}
}
return null;
}
case DOUBLE_IFCMP_opcode: {
if (FOLD_DOUBLES && FOLD_IFCMPS) {
double c2 = getDoubleValue(IfCmp.getVal2(s));
OPT_ConditionOperand cond = (OPT_ConditionOperand) IfCmp.getCond(s).copy();
OPT_BranchOperand target = (OPT_BranchOperand) IfCmp.getTarget(s).copy();
OPT_BranchProfileOperand prof = (OPT_BranchProfileOperand) IfCmp.getBranchProfile(s).copy();
if (def.operator == DOUBLE_ADD) {
double c1 = getDoubleValue(Binary.getVal2(def));
// x = a + c1; y = x cmp c2
return IfCmp.create(DOUBLE_IFCMP, y.copyRO(), a.copyRO(), DC(c2 - c1), cond, target, prof);
} else if (def.operator == DOUBLE_SUB) {
double c1 = getDoubleValue(Binary.getVal2(def));
// x = a - c1; y = x cmp c2
return IfCmp.create(DOUBLE_IFCMP, y.copyRO(), a.copyRO(), DC(c1 + c2), cond, target, prof);
} else if (def.operator == DOUBLE_NEG) {
// x = -a; y = x cmp c2
return IfCmp.create(DOUBLE_IFCMP, y.copyRO(), a.copyRO(), DC(-c2), cond.flipOperands(), target, prof);
}
}
return null;
}
case REF_IFCMP_opcode: {
if (FOLD_REFS && FOLD_IFCMPS) {
Address c2 = getAddressValue(IfCmp.getVal2(s));
OPT_ConditionOperand cond = (OPT_ConditionOperand) IfCmp.getCond(s).copy();
OPT_BranchOperand target = (OPT_BranchOperand) IfCmp.getTarget(s).copy();
OPT_BranchProfileOperand prof = (OPT_BranchProfileOperand) IfCmp.getBranchProfile(s).copy();
if (def.operator == REF_ADD) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a + c1; y = x cmp c2
return IfCmp.create(REF_IFCMP,
y.copyRO(),
a.copyRO(),
AC(c2.toWord().minus(c1.toWord()).toAddress()),
cond,
target,
prof);
} else if (def.operator == REF_SUB) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a - c1; y = x cmp c2
return IfCmp.create(REF_IFCMP,
y.copyRO(),
a.copyRO(),
AC(c1.toWord().plus(c2.toWord()).toAddress()),
cond,
target,
prof);
} else if (def.operator == REF_NEG) {
// x = -a; y = x cmp c2
return IfCmp.create(REF_IFCMP,
y.copyRO(),
a.copyRO(),
AC(Word.zero().minus(c2.toWord()).toAddress()),
cond.flipOperands(),
target,
prof);
}
}
return null;
}
case INT_IFCMP2_opcode: {
if (FOLD_INTS && FOLD_IFCMPS) {
int c2 = getIntValue(IfCmp.getVal2(s));
OPT_ConditionOperand cond1 = (OPT_ConditionOperand) IfCmp2.getCond1(s).copy();
OPT_ConditionOperand cond2 = (OPT_ConditionOperand) IfCmp2.getCond2(s).copy();
OPT_BranchOperand target1 = (OPT_BranchOperand) IfCmp2.getTarget1(s).copy();
OPT_BranchOperand target2 = (OPT_BranchOperand) IfCmp2.getTarget2(s).copy();
OPT_BranchProfileOperand prof1 = (OPT_BranchProfileOperand) IfCmp2.getBranchProfile1(s).copy();
OPT_BranchProfileOperand prof2 = (OPT_BranchProfileOperand) IfCmp2.getBranchProfile2(s).copy();
if (def.operator == INT_ADD) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a + c1; y = x cmp c2
return IfCmp2.create(INT_IFCMP2,
y.copyRO(),
a.copyRO(),
IC(c2 - c1),
cond1,
target1,
prof1,
cond2,
target2,
prof2);
} else if (def.operator == INT_SUB) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a - c1; y = x cmp c2
return IfCmp2.create(INT_IFCMP2,
y.copyRO(),
a.copyRO(),
IC(c1 + c2),
cond1,
target1,
prof1,
cond2,
target2,
prof2);
} else if (def.operator == INT_NEG) {
// x = -a; y = x cmp c2
return IfCmp2.create(INT_IFCMP2,
y.copyRO(),
a.copyRO(),
IC(-c2),
cond1.flipOperands(),
target1,
prof1,
cond2.flipOperands(),
target2,
prof2);
}
}
return null;
}
case INT_COND_MOVE_opcode:
case LONG_COND_MOVE_opcode:
case REF_COND_MOVE_opcode:
case FLOAT_COND_MOVE_opcode:
case DOUBLE_COND_MOVE_opcode:
case GUARD_COND_MOVE_opcode: {
if (FOLD_INTS && FOLD_CONDMOVES) {
OPT_Operand trueValue = CondMove.getTrueValue(s);
OPT_Operand falseValue = CondMove.getFalseValue(s);
OPT_ConditionOperand cond = (OPT_ConditionOperand) CondMove.getCond(s).copy();
switch (def.operator.opcode) {
case INT_ADD_opcode: {
int c1 = getIntValue(Binary.getVal2(def));
int c2 = getIntValue(CondMove.getVal2(s));
// x = a + c1; y = x cmp c2 ? trueValue : falseValue
return CondMove.create(s.operator(), y.copyRO(), a.copyRO(), IC(c2 - c1), cond, trueValue, falseValue);
}
case LONG_ADD_opcode: {
long c1 = getLongValue(Binary.getVal2(def));
long c2 = getLongValue(CondMove.getVal2(s));
// x = a + c1; y = x cmp c2 ? trueValue : falseValue
return CondMove.create(s.operator(), y.copyRO(), a.copyRO(), LC(c2 - c1), cond, trueValue, falseValue);
}
case REF_ADD_opcode: {
Address c1 = getAddressValue(Binary.getVal2(def));
Address c2 = getAddressValue(CondMove.getVal2(s));
// x = a + c1; y = x cmp c2 ? trueValue : falseValue
return CondMove.create(s.operator(),
y.copyRO(),
a.copyRO(),
AC(c2.toWord().minus(c1.toWord()).toAddress()),
cond,
trueValue,
falseValue);
}
case FLOAT_ADD_opcode: {
float c1 = getFloatValue(Binary.getVal2(def));
float c2 = getFloatValue(CondMove.getVal2(s));
// x = a + c1; y = x cmp c2 ? trueValue : falseValue
return CondMove.create(s.operator(), y.copyRO(), a.copyRO(), FC(c2 - c1), cond, trueValue, falseValue);
}
case DOUBLE_ADD_opcode: {
double c1 = getDoubleValue(Binary.getVal2(def));
double c2 = getDoubleValue(CondMove.getVal2(s));
// x = a + c1; y = x cmp c2 ? trueValue : falseValue
return CondMove.create(s.operator(), y.copyRO(), a.copyRO(), DC(c2 - c1), cond, trueValue, falseValue);
}
case INT_SUB_opcode: {
int c1 = getIntValue(Binary.getVal2(def));
int c2 = getIntValue(CondMove.getVal2(s));
// x = a - c1; y = x cmp c2 ? trueValue : falseValue
return CondMove.create(s.operator(), y.copyRO(), a.copyRO(), IC(c1 + c2), cond, trueValue, falseValue);
}
case LONG_SUB_opcode: {
long c1 = getLongValue(Binary.getVal2(def));
long c2 = getLongValue(CondMove.getVal2(s));
// x = a - c1; y = x cmp c2 ? trueValue : falseValue
return CondMove.create(s.operator(), y.copyRO(), a.copyRO(), LC(c1 + c2), cond, trueValue, falseValue);
}
case REF_SUB_opcode: {
Address c1 = getAddressValue(Binary.getVal2(def));
Address c2 = getAddressValue(CondMove.getVal2(s));
// x = a - c1; y = x cmp c2 ? trueValue : falseValue
return CondMove.create(s.operator(),
y.copyRO(),
a.copyRO(),
AC(c1.toWord().plus(c2.toWord()).toAddress()),
cond,
trueValue,
falseValue);
}
case FLOAT_SUB_opcode: {
float c1 = getFloatValue(Binary.getVal2(def));
float c2 = getFloatValue(CondMove.getVal2(s));
// x = a - c1; y = x cmp c2 ? trueValue : falseValue
return CondMove.create(s.operator(), y.copyRO(), a.copyRO(), FC(c1 + c2), cond, trueValue, falseValue);
}
case DOUBLE_SUB_opcode: {
double c1 = getDoubleValue(Binary.getVal2(def));
double c2 = getDoubleValue(CondMove.getVal2(s));
// x = a - c1; y = x cmp c2 ? trueValue : falseValue
return CondMove.create(s.operator(), y.copyRO(), a.copyRO(), DC(c1 + c2), cond, trueValue, falseValue);
}
case INT_NEG_opcode: {
int c2 = getIntValue(CondMove.getVal2(s));
// x = -a; y = x cmp c2 ? trueValue : falseValue
return CondMove.create(s.operator(),
y.copyRO(),
a.copyRO(),
IC(-c2),
cond.flipOperands(),
trueValue,
falseValue);
}
case LONG_NEG_opcode: {
long c2 = getLongValue(CondMove.getVal2(s));
// x = -a; y = x cmp c2 ? trueValue : falseValue
return CondMove.create(s.operator(),
y.copyRO(),
a.copyRO(),
LC(-c2),
cond.flipOperands(),
trueValue,
falseValue);
}
case REF_NEG_opcode: {
Address c2 = getAddressValue(CondMove.getVal2(s));
// x = -a; y = x cmp c2 ? trueValue : falseValue
return CondMove.create(s.operator(),
y.copyRO(),
a.copyRO(),
AC(Word.zero().minus(c2.toWord()).toAddress()),
cond.flipOperands(),
trueValue,
falseValue);
}
case FLOAT_NEG_opcode: {
float c2 = getFloatValue(CondMove.getVal2(s));
// x = -a; y = x cmp c2 ? trueValue : falseValue
return CondMove.create(s.operator(),
y.copyRO(),
a.copyRO(),
FC(-c2),
cond.flipOperands(),
trueValue,
falseValue);
}
case DOUBLE_NEG_opcode: {
double c2 = getDoubleValue(CondMove.getVal2(s));
// x = -a; y = x cmp c2 ? trueValue : falseValue
return CondMove.create(s.operator(),
y.copyRO(),
a.copyRO(),
DC(-c2),
cond.flipOperands(),
trueValue,
falseValue);
}
case BOOLEAN_CMP_INT_opcode: {
int c1 = getIntValue(BooleanCmp.getVal2(def));
int c2 = getIntValue(CondMove.getVal2(s));
// x = a cmp c1 ? true : false; y = x cmp c2 ? trueValue : falseValue
if ((cond.isEQUAL() && c2 == 1)||
(cond.isNOT_EQUAL() && c2 == 0)) {
return CondMove.create(INT_COND_MOVE,
y.copyRO(),
a.copyRO(),
IC(c1),
BooleanCmp.getCond(def).copy().asCondition(),
trueValue,
falseValue);
} else if ((cond.isEQUAL() && c2 == 0)||
(cond.isNOT_EQUAL() && c2 == 1)) {
return CondMove.create(INT_COND_MOVE,
y.copyRO(),
a.copyRO(),
IC(c1),
BooleanCmp.getCond(def).copy().asCondition().flipCode(),
trueValue,
falseValue);
} else {
return null;
}
}
case BOOLEAN_CMP_ADDR_opcode: {
Address c1 = getAddressValue(BooleanCmp.getVal2(def));
int c2 = getIntValue(CondMove.getVal2(s));
// x = a cmp c1 ? true : false; y = x cmp c2 ? trueValue : falseValue
if ((cond.isEQUAL() && c2 == 1)||
(cond.isNOT_EQUAL() && c2 == 0)) {
return CondMove.create(REF_COND_MOVE,
y.copyRO(),
a.copyRO(),
AC(c1),
BooleanCmp.getCond(def).copy().asCondition(),
trueValue,
falseValue);
} else if ((cond.isEQUAL() && c2 == 0)||
(cond.isNOT_EQUAL() && c2 == 1)) {
return CondMove.create(REF_COND_MOVE,
y.copyRO(),
a.copyRO(),
AC(c1),
BooleanCmp.getCond(def).flipCode(),
trueValue,
falseValue);
} else {
return null;
}
}
case BOOLEAN_CMP_LONG_opcode: {
long c1 = getLongValue(BooleanCmp.getVal2(def));
int c2 = getIntValue(CondMove.getVal2(s));
// x = a cmp c1 ? true : false; y = x cmp c2 ? trueValue : falseValue
if ((cond.isEQUAL() && c2 == 1)||
(cond.isNOT_EQUAL() && c2 == 0)) {
return CondMove.create(LONG_COND_MOVE,
y.copyRO(),
a.copyRO(),
LC(c1),
BooleanCmp.getCond(def).copy().asCondition(),
trueValue,
falseValue);
} else if ((cond.isEQUAL() && c2 == 0)||
(cond.isNOT_EQUAL() && c2 == 1)) {
return CondMove.create(LONG_COND_MOVE,
y.copyRO(),
a.copyRO(),
LC(c1),
BooleanCmp.getCond(def).copy().asCondition().flipCode(),
trueValue,
falseValue);
} else {
return null;
}
}
case BOOLEAN_CMP_DOUBLE_opcode: {
double c1 = getDoubleValue(BooleanCmp.getVal2(def));
int c2 = getIntValue(CondMove.getVal2(s));
// x = a cmp c1 ? true : false; y = x cmp c2 ? trueValue : falseValue
if ((cond.isEQUAL() && c2 == 1)||
(cond.isNOT_EQUAL() && c2 == 0)) {
return CondMove.create(DOUBLE_COND_MOVE,
y.copyRO(),
a.copyRO(),
DC(c1),
BooleanCmp.getCond(def).copy().asCondition(),
trueValue,
falseValue);
} else if ((cond.isEQUAL() && c2 == 0)||
(cond.isNOT_EQUAL() && c2 == 1)) {
return CondMove.create(DOUBLE_COND_MOVE,
y.copyRO(),
a.copyRO(),
DC(c1),
BooleanCmp.getCond(def).copy().asCondition().flipCode(),
trueValue,
falseValue);
} else {
return null;
}
}
case BOOLEAN_CMP_FLOAT_opcode: {
float c1 = getFloatValue(BooleanCmp.getVal2(def));
int c2 = getIntValue(CondMove.getVal2(s));
// x = a cmp c1 ? true : false; y = x cmp c2 ? trueValue : falseValue
if ((cond.isEQUAL() && c2 == 1)||
(cond.isNOT_EQUAL() && c2 == 0)) {
return CondMove.create(FLOAT_COND_MOVE,
y.copyRO(),
a.copyRO(),
FC(c1),
BooleanCmp.getCond(def).copy().asCondition(),
trueValue,
falseValue);
} else if ((cond.isEQUAL() && c2 == 0)||
(cond.isNOT_EQUAL() && c2 == 1)) {
return CondMove.create(FLOAT_COND_MOVE,
y.copyRO(),
a.copyRO(),
FC(c1),
BooleanCmp.getCond(def).copy().asCondition().flipCode(),
trueValue,
falseValue);
} else {
return null;
}
}
case LONG_CMP_opcode: {
long c1 = getLongValue(Binary.getVal2(def));
int c2 = getIntValue(CondMove.getVal2(s));
// x = a lcmp c1; y = y = x cmp c2 ? trueValue : falseValue
if (cond.isEQUAL() && c2 == 0) {
return CondMove.create(LONG_COND_MOVE,
y.copyRO(),
a.copyRO(),
LC(c1),
OPT_ConditionOperand.EQUAL(),
trueValue,
falseValue);
} else if (cond.isNOT_EQUAL() && c2 == 0) {
return CondMove.create(LONG_COND_MOVE,
y.copyRO(),
a.copyRO(),
LC(c1),
OPT_ConditionOperand.NOT_EQUAL(),
trueValue,
falseValue);
} else if ((cond.isEQUAL() && c2 == 1)||(cond.isGREATER() && c2 == 0)){
return CondMove.create(LONG_COND_MOVE,
y.copyRO(),
a.copyRO(),
LC(c1),
OPT_ConditionOperand.GREATER(),
trueValue,
falseValue);
} else if (cond.isGREATER_EQUAL() && c2 == 0){
return CondMove.create(LONG_COND_MOVE,
y.copyRO(),
a.copyRO(),
LC(c1),
OPT_ConditionOperand.GREATER_EQUAL(),
trueValue,
falseValue);
} else if ((cond.isEQUAL() && c2 == -1)||(cond.isLESS() && c2 == 0)) {
return CondMove.create(LONG_COND_MOVE,
y.copyRO(),
a.copyRO(),
LC(c1),
OPT_ConditionOperand.LESS(),
trueValue,
falseValue);
} else if (cond.isLESS_EQUAL() && c2 == 0) {
return CondMove.create(LONG_COND_MOVE,
y.copyRO(),
a.copyRO(),
LC(c1),
OPT_ConditionOperand.LESS_EQUAL(),
trueValue,
falseValue);
} else {
return null;
}
}
default:
}
}
return null;
}
case INT_NEG_opcode: {
if (FOLD_INTS && FOLD_NEGS) {
if (def.operator == INT_NEG) {
// x = -z; y = -x;
return Move.create(INT_MOVE, y.copyRO(), Unary.getVal(def).copy());
} else if (def.operator == INT_MUL) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a * c1; y = -x;
return Binary.create(INT_MUL, y.copyRO(), a.copyRO(), IC(-c1));
} else if (def.operator == INT_DIV) {
int c1 = getIntValue(GuardedBinary.getVal2(def));
OPT_Operand guard = GuardedBinary.getGuard(def);
// x = a / c1; y = -x;
return GuardedBinary.create(INT_DIV, y.copyRO(), a.copyRO(), IC(-c1), guard.copy());
} else if (FOLD_CONSTANTS_TO_LHS && (def.operator == INT_ADD)) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a + c1; y = -x;
return Binary.create(INT_SUB, y.copyRO(), IC(-c1), a.copyRO());
} else if (FOLD_CONSTANTS_TO_LHS && (def.operator == INT_SUB)) {
int c1 = getIntValue(Binary.getVal2(def));
// x = a - c1; y = -x;
return Binary.create(INT_SUB, y.copyRO(), IC(c1), a.copyRO());
}
}
return null;
}
case REF_NEG_opcode: {
if (FOLD_REFS && FOLD_NEGS) {
if (def.operator == REF_NEG) {
// x = -z; y = -x;
return Move.create(REF_MOVE, y.copyRO(), Unary.getVal(def).copy());
} else if (FOLD_CONSTANTS_TO_LHS && (def.operator == REF_ADD)) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a + c1; y = -x;
return Binary.create(REF_SUB, y.copyRO(), AC(Word.zero().minus(c1.toWord()).toAddress()), a.copyRO());
} else if (FOLD_CONSTANTS_TO_LHS && (def.operator == REF_SUB)) {
Address c1 = getAddressValue(Binary.getVal2(def));
// x = a - c1; y = -x;
return Binary.create(REF_SUB, y.copyRO(), AC(c1), a.copyRO());
}
}
return null;
}
case LONG_NEG_opcode: {
if (FOLD_LONGS && FOLD_NEGS) {
if (def.operator == LONG_NEG) {
// x = -z; y = -x;
return Move.create(LONG_MOVE, y.copyRO(), Unary.getVal(def).copy());
} else if (def.operator == LONG_MUL) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a * c1; y = -x;
return Binary.create(LONG_MUL, y.copyRO(), a.copyRO(), LC(-c1));
} else if (def.operator == LONG_DIV) {
long c1 = getLongValue(GuardedBinary.getVal2(def));
OPT_Operand guard = GuardedBinary.getGuard(def);
// x = a / c1; y = -x;
return GuardedBinary.create(LONG_DIV, y.copyRO(), a.copyRO(), LC(-c1), guard.copy());
} else if (FOLD_CONSTANTS_TO_LHS && (def.operator == LONG_ADD)) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a + c1; y = -x;
return Binary.create(LONG_SUB, y.copyRO(), LC(-c1), a.copyRO());
} else if (FOLD_CONSTANTS_TO_LHS && (def.operator == LONG_SUB)) {
long c1 = getLongValue(Binary.getVal2(def));
// x = a - c1; y = -x;
return Binary.create(LONG_SUB, y.copyRO(), LC(c1), a.copyRO());
}
}
return null;
}
case FLOAT_NEG_opcode: {
if (FOLD_FLOATS && FOLD_NEGS) {
if (def.operator == FLOAT_NEG) {
// x = -z; y = -x;
return Move.create(FLOAT_MOVE, y.copyRO(), Unary.getVal(def).copy());
} else if (def.operator == FLOAT_MUL) {
float c1 = getFloatValue(Binary.getVal2(def));
// x = a * c1; y = -x;
return Binary.create(FLOAT_MUL, y.copyRO(), a.copyRO(), FC(-c1));
} else if (def.operator == FLOAT_DIV) {
float c1 = getFloatValue(Binary.getVal2(def));
// x = a / c1; y = -x;
return Binary.create(FLOAT_DIV, y.copyRO(), a.copyRO(), FC(-c1));
} else if (FOLD_CONSTANTS_TO_LHS && (def.operator == FLOAT_ADD)) {
float c1 = getFloatValue(Binary.getVal2(def));
// x = a + c1; y = -x;
return Binary.create(FLOAT_SUB, y.copyRO(), FC(-c1), a.copyRO());
} else if (FOLD_CONSTANTS_TO_LHS && (def.operator == FLOAT_SUB)) {
float c1 = getFloatValue(Binary.getVal2(def));
// x = a - c1; y = -x;
return Binary.create(FLOAT_SUB, y.copyRO(), FC(c1), a.copyRO());
}
}
return null;
}
case DOUBLE_NEG_opcode: {
if (FOLD_DOUBLES && FOLD_NEGS) {
if (def.operator == DOUBLE_NEG) {
// x = -z; y = -x;
return Move.create(DOUBLE_MOVE, y.copyRO(), Unary.getVal(def).copy());
} else if (def.operator == DOUBLE_MUL) {
double c1 = getDoubleValue(Binary.getVal2(def));
// x = a * c1; y = -x;
return Binary.create(DOUBLE_MUL, y.copyRO(), a.copyRO(), DC(-c1));
} else if (def.operator == DOUBLE_DIV) {
double c1 = getDoubleValue(Binary.getVal2(def));
// x = a / c1; y = -x;
return Binary.create(DOUBLE_DIV, y.copyRO(), a.copyRO(), DC(-c1));
} else if (FOLD_CONSTANTS_TO_LHS && (def.operator == DOUBLE_ADD)) {
double c1 = getDoubleValue(Binary.getVal2(def));
// x = a + c1; y = -x;
return Binary.create(DOUBLE_SUB, y.copyRO(), DC(-c1), a.copyRO());
} else if (FOLD_CONSTANTS_TO_LHS && (def.operator == DOUBLE_SUB)) {
double c1 = getDoubleValue(Binary.getVal2(def));
// x = a - c1; y = -x;
return Binary.create(DOUBLE_SUB, y.copyRO(), DC(c1), a.copyRO());
}
}
return null;
}
case BOOLEAN_NOT_opcode: {
if (FOLD_INTS && FOLD_NOTS) {
if (def.operator == BOOLEAN_NOT) {
// x = 1 ^ z; y = 1 ^ x;
return Move.create(INT_MOVE, y.copyRO(), Unary.getVal(def).copy());
} else if (BooleanCmp.conforms(def)) {
// x = a cmp b; y = !x
return BooleanCmp.create(def.operator,
y.copyRO(),
BooleanCmp.getVal1(def).copy(),
BooleanCmp.getVal2(def).copy(),
((OPT_ConditionOperand) BooleanCmp.getCond(def).copy()).flipCode(),
((OPT_BranchProfileOperand) BooleanCmp.getBranchProfile(def).copy()));
}
}
return null;
}
case INT_NOT_opcode: {
if (FOLD_INTS && FOLD_NOTS) {
if (def.operator == INT_NOT) {
// x = -1 ^ z; y = -1 ^ x;
return Move.create(INT_MOVE, y.copyRO(), Unary.getVal(def).copy());
}
}
return null;
}
case REF_NOT_opcode: {
if (FOLD_REFS && FOLD_NOTS) {
if (def.operator == REF_NOT) {
// x = -1 ^ z; y = -1 ^ x;
return Move.create(REF_MOVE, y.copyRO(), Unary.getVal(def).copy());
}
}
return null;
}
case LONG_NOT_opcode: {
if (FOLD_LONGS && FOLD_NOTS) {
if (def.operator == LONG_NOT) {
// x = -1 ^ z; y = -1 ^ x;
return Move.create(LONG_MOVE, y.copyRO(), Unary.getVal(def).copy());
}
}
return null;
}
case INT_2BYTE_opcode: {
if (FOLD_INTS && FOLD_2CONVERSION) {
if ((def.operator == INT_2BYTE) || (def.operator == INT_2SHORT)) {
// x = (short)z; y = (byte)x;
return Unary.create(INT_2BYTE, y.copyRO(), Unary.getVal(def).copy());
} else if (def.operator == INT_2USHORT) {
// x = (char)z; y = (byte)x;
return Binary.create(INT_AND, y.copyRO(), Unary.getVal(def).copy(), IC(0xFF));
}
}
return null;
}
case INT_2SHORT_opcode: {
if (FOLD_INTS && FOLD_2CONVERSION) {
if (def.operator == INT_2BYTE) {
// x = (byte)z; y = (short)x;
return Unary.create(INT_2BYTE, y.copyRO(), Unary.getVal(def).copy());
} else if (def.operator == INT_2SHORT) {
// x = (short)z; y = (short)x;
return Unary.create(INT_2SHORT, y.copyRO(), Unary.getVal(def).copy());
} else if (def.operator == INT_2USHORT) {
// x = (char)z; y = (short)x;
return Unary.create(INT_2USHORT, y.copyRO(), Unary.getVal(def).copy());
}
}
return null;
}
case INT_2USHORT_opcode: {
if (FOLD_INTS && FOLD_2CONVERSION) {
if ((def.operator == INT_2SHORT) || (def.operator == INT_2USHORT)) {
// x = (short)z; y = (char)x;
return Unary.create(INT_2USHORT, y.copyRO(), Unary.getVal(def).copy());
}
}
return null;
}
case LONG_2INT_opcode: {
if (FOLD_LONGS && FOLD_2CONVERSION) {
if (def.operator == INT_2LONG) {
// x = (long)z; y = (int)x;
return Move.create(INT_MOVE, y.copyRO(), Unary.getVal(def).copy());
}
}
return null;
}
case INT_2LONG_opcode:
// unused
return null;
case DOUBLE_2FLOAT_opcode: {
if (FOLD_DOUBLES && FOLD_2CONVERSION) {
if (def.operator == FLOAT_2DOUBLE) {
// x = (double)z; y = (float)x;
return Move.create(FLOAT_MOVE, y.copyRO(), Unary.getVal(def).copy());
}
}
return null;
}
case FLOAT_2DOUBLE_opcode:
// unused
return null;
case INT_ZERO_CHECK_opcode: {
if (FOLD_INTS && FOLD_CHECKS) {
if (def.operator == INT_NEG) {
// x = -z; y = zerocheck x;
return ZeroCheck.create(INT_ZERO_CHECK, y.copyRO(), Unary.getVal(def).copy());
}
}
return null;
}
case LONG_ZERO_CHECK_opcode: {
if (FOLD_INTS && FOLD_CHECKS) {
if (def.operator == INT_NEG) {
// x = -z; y = zerocheck x;
return ZeroCheck.create(INT_ZERO_CHECK, y.copyRO(), Unary.getVal(def).copy());
}
}
return null;
}
default:
OPT_OptimizingCompilerException.UNREACHABLE();
return null;
}
}
/**
* Does instruction s compute a register r = candidate expression?
*
* @param s the instruction
* @param ssa are we in SSA form?
* @return the computed register, or null
*/
private static OPT_Register isCandidateExpression(OPT_Instruction s, boolean ssa) {
switch (s.operator.opcode) {
// Foldable operators
case BOOLEAN_NOT_opcode:
case INT_NOT_opcode:
case REF_NOT_opcode:
case LONG_NOT_opcode:
case INT_NEG_opcode:
case REF_NEG_opcode:
case LONG_NEG_opcode:
case FLOAT_NEG_opcode:
case DOUBLE_NEG_opcode:
case INT_2BYTE_opcode:
case INT_2SHORT_opcode:
case INT_2USHORT_opcode:
case INT_2LONG_opcode:
case LONG_2INT_opcode:
case FLOAT_2DOUBLE_opcode:
case DOUBLE_2FLOAT_opcode: {
OPT_Operand val1 = Unary.getVal(s);
// if val1 is constant too, this should've been constant folded
// beforehand. Give up.
if (val1.isConstant()) {
return null;
}
OPT_Register result = Unary.getResult(s).asRegister().getRegister();
if (ssa) {
return result;
} else if (val1.asRegister().getRegister() != result) {
return result;
} else {
return null;
}
}
case INT_ADD_opcode:
case REF_ADD_opcode:
case LONG_ADD_opcode:
case FLOAT_ADD_opcode:
case DOUBLE_ADD_opcode:
case INT_SUB_opcode:
case REF_SUB_opcode:
case LONG_SUB_opcode:
case FLOAT_SUB_opcode:
case DOUBLE_SUB_opcode:
case INT_MUL_opcode:
case LONG_MUL_opcode:
case FLOAT_MUL_opcode:
case DOUBLE_MUL_opcode:
case FLOAT_DIV_opcode:
case DOUBLE_DIV_opcode:
case INT_SHL_opcode:
case REF_SHL_opcode:
case LONG_SHL_opcode:
case INT_SHR_opcode:
case REF_SHR_opcode:
case LONG_SHR_opcode:
case INT_USHR_opcode:
case REF_USHR_opcode:
case LONG_USHR_opcode:
case INT_AND_opcode:
case REF_AND_opcode:
case LONG_AND_opcode:
case INT_OR_opcode:
case REF_OR_opcode:
case LONG_OR_opcode:
case INT_XOR_opcode:
case REF_XOR_opcode:
case LONG_XOR_opcode:
case LONG_CMP_opcode:
case FLOAT_CMPL_opcode:
case DOUBLE_CMPL_opcode:
case FLOAT_CMPG_opcode:
case DOUBLE_CMPG_opcode: {
OPT_Operand val2 = Binary.getVal2(s);
if (!val2.isObjectConstant() && !val2.isTIBConstant()) {
if (val2.isConstant()) {
OPT_Operand val1 = Binary.getVal1(s);
// if val1 is constant too, this should've been constant folded
// beforehand. Give up.
if (val1.isConstant()) {
return null;
}
OPT_Register result = Binary.getResult(s).asRegister().getRegister();
if (ssa) {
return result;
} else if (val1.asRegister().getRegister() != result) {
return result;
} else {
return null;
}
} else {
if (VM.VerifyAssertions) {
VM._assert(val2.isRegister());
}
OPT_Operand val1 = Binary.getVal1(s);
if (s.operator.isCommutative() && val1.isConstant() && !val1.isMoveableObjectConstant() && !val1.isTIBConstant()) {
Binary.setVal1(s, Binary.getClearVal2(s));
Binary.setVal2(s, val1);
OPT_Register result = Binary.getResult(s).asRegister().getRegister();
if (ssa) {
return result;
} else if (val2.asRegister().getRegister() != result) {
return result;
} else {
return null;
}
}
}
}
return null;
}
case INT_DIV_opcode:
case LONG_DIV_opcode: {
OPT_Operand val2 = GuardedBinary.getVal2(s);
if (val2.isConstant()) {
OPT_Operand val1 = GuardedBinary.getVal1(s);
// if val1 is constant too, this should've been constant folded
// beforehand. Give up.
if (val1.isConstant()) {
return null;
}
OPT_Register result = GuardedBinary.getResult(s).asRegister().getRegister();
if (ssa) {
return result;
} else if (val1.asRegister().getRegister() != result) {
return result;
}
}
return null;
}
case BOOLEAN_CMP_INT_opcode:
case BOOLEAN_CMP_LONG_opcode:
case BOOLEAN_CMP_ADDR_opcode: {
OPT_Operand val2 = BooleanCmp.getVal2(s);
if (!val2.isObjectConstant() && !val2.isTIBConstant()) {
if (val2.isConstant()) {
OPT_Operand val1 = BooleanCmp.getVal1(s);
// if val1 is constant too, this should've been constant folded
// beforehand. Give up.
if (val1.isConstant()) {
return null;
}
OPT_Register result = BooleanCmp.getResult(s).asRegister().getRegister();
if (ssa) {
return result;
} else if (val1.asRegister().getRegister() != result) {
return result;
}
} else {
if (VM.VerifyAssertions) {
VM._assert(val2.isRegister());
}
OPT_Operand val1 = BooleanCmp.getVal1(s);
if (val1.isConstant() && !val1.isMoveableObjectConstant() && !val1.isTIBConstant()) {
BooleanCmp.setVal1(s, BooleanCmp.getClearVal2(s));
BooleanCmp.setVal2(s, val1);
BooleanCmp.getCond(s).flipOperands();
OPT_Register result = BooleanCmp.getResult(s).asRegister().getRegister();
if (ssa) {
return result;
} else if (val2.asRegister().getRegister() != result) {
return result;
}
}
}
}
return null;
}
case INT_IFCMP_opcode:
case LONG_IFCMP_opcode:
case FLOAT_IFCMP_opcode:
case DOUBLE_IFCMP_opcode:
case REF_IFCMP_opcode: {
OPT_Operand val2 = IfCmp.getVal2(s);
if (!val2.isObjectConstant() && !val2.isTIBConstant()) {
if (val2.isConstant()) {
OPT_Operand val1 = IfCmp.getVal1(s);
// if val1 is constant too, this should've been constant folded
// beforehand. Give up.
if (val1.isConstant()) {
return null;
}
OPT_Register result = IfCmp.getGuardResult(s).asRegister().getRegister();
if (ssa) {
return result;
} else if (val1.asRegister().getRegister() != result) {
return result;
}
} else {
if (VM.VerifyAssertions) {
VM._assert(val2.isRegister());
}
OPT_Operand val1 = IfCmp.getVal1(s);
if (val1.isConstant() && !val1.isMoveableObjectConstant() && !val1.isTIBConstant()) {
IfCmp.setVal1(s, IfCmp.getClearVal2(s));
IfCmp.setVal2(s, val1);
IfCmp.getCond(s).flipOperands();
OPT_Register result = IfCmp.getGuardResult(s).asRegister().getRegister();
if (ssa) {
return result;
} else if (val2.asRegister().getRegister() != result) {
return result;
}
}
}
}
return null;
}
case INT_IFCMP2_opcode: {
OPT_Operand val2 = IfCmp2.getVal2(s);
if (!val2.isObjectConstant() && !val2.isTIBConstant()) {
if (val2.isConstant()) {
OPT_Operand val1 = IfCmp2.getVal1(s);
// if val1 is constant too, this should've been constant folded
// beforehand. Give up.
if (val1.isConstant()) {
return null;
}
OPT_Register result = IfCmp2.getGuardResult(s).asRegister().getRegister();
if (ssa) {
return result;
} else if (val1.asRegister().getRegister() != result) {
return result;
}
} else {
if (VM.VerifyAssertions) {
VM._assert(val2.isRegister());
}
OPT_Operand val1 = IfCmp2.getVal1(s);
if (val1.isConstant() && !val1.isMoveableObjectConstant() && !val1.isTIBConstant()) {
IfCmp2.setVal1(s, IfCmp2.getClearVal2(s));
IfCmp2.setVal2(s, val1);
IfCmp2.getCond1(s).flipOperands();
IfCmp2.getCond2(s).flipOperands();
OPT_Register result = IfCmp2.getGuardResult(s).asRegister().getRegister();
if (ssa) {
return result;
} else if (val2.asRegister().getRegister() != result) {
return result;
}
}
}
}
return null;
}
case INT_COND_MOVE_opcode:
case LONG_COND_MOVE_opcode:
case REF_COND_MOVE_opcode:
case FLOAT_COND_MOVE_opcode:
case DOUBLE_COND_MOVE_opcode:
case GUARD_COND_MOVE_opcode: {
OPT_Operand val2 = CondMove.getVal2(s);
if (!val2.isObjectConstant()) {
if (val2.isConstant()) {
OPT_Operand val1 = CondMove.getVal1(s);
// if val1 is constant too, this should've been constant folded
// beforehand. Give up.
if (val1.isConstant()) {
return null;
}
OPT_Register result = CondMove.getResult(s).asRegister().getRegister();
if (ssa) {
return result;
} else if (val1.asRegister().getRegister() != result) {
return result;
}
} else {
if (VM.VerifyAssertions) {
VM._assert(val2.isRegister());
}
OPT_Operand val1 = CondMove.getVal1(s);
if (val1.isConstant() && !val1.isMoveableObjectConstant()) {
CondMove.setVal1(s, CondMove.getClearVal2(s));
CondMove.setVal2(s, val1);
CondMove.getCond(s).flipOperands();
OPT_Register result = CondMove.getResult(s).asRegister().getRegister();
if (ssa) {
return result;
} else if (val2.asRegister().getRegister() != result) {
return result;
}
}
}
}
return null;
}
case INT_ZERO_CHECK_opcode:
case LONG_ZERO_CHECK_opcode: {
OPT_Operand val1 = ZeroCheck.getValue(s);
// if val1 is constant too, this should've been constant folded
// beforehand. Give up.
if (val1.isConstant()) {
return null;
}
OPT_Register result = ZeroCheck.getGuardResult(s).asRegister().getRegister();
if (ssa) {
return result;
} else if (val1.asRegister().getRegister() != result) {
return result;
} else {
return null;
}
}
default:
// Operator can't be folded
return null;
}
}
private static int getIntValue(OPT_Operand op) {
if (op instanceof OPT_IntConstantOperand)
return op.asIntConstant().value;
throw new OPT_OptimizingCompilerException(
"Cannot getIntValue from this operand " + op +
" of instruction " + op.instruction);
}
private static long getLongValue(OPT_Operand op) {
if (op instanceof OPT_LongConstantOperand)
return op.asLongConstant().value;
throw new OPT_OptimizingCompilerException(
"Cannot getLongValue from this operand " + op +
" of instruction " + op.instruction);
}
private static float getFloatValue(OPT_Operand op) {
if (op instanceof OPT_FloatConstantOperand)
return op.asFloatConstant().value;
throw new OPT_OptimizingCompilerException(
"Cannot getFloatValue from this operand " + op +
" of instruction " + op.instruction);
}
private static double getDoubleValue(OPT_Operand op) {
if (op instanceof OPT_DoubleConstantOperand)
return op.asDoubleConstant().value;
throw new OPT_OptimizingCompilerException(
"Cannot getDoubleValue from this operand " + op +
" of instruction " + op.instruction);
}
private static Address getAddressValue(OPT_Operand op) {
if (op instanceof OPT_NullConstantOperand) {
return Address.zero();
}
if (op instanceof OPT_AddressConstantOperand) {
return op.asAddressConstant().value;
}
if (op instanceof OPT_IntConstantOperand) {
return Address.fromIntSignExtend(op.asIntConstant().value);
}
if (VM.BuildFor64Addr && op instanceof OPT_LongConstantOperand) {
return Address.fromLong(op.asLongConstant().value);
}
if (op instanceof OPT_ObjectConstantOperand) {
if (VM.VerifyAssertions) VM._assert(!op.isMoveableObjectConstant());
return VM_Magic.objectAsAddress(op.asObjectConstant().value);
}
throw new OPT_OptimizingCompilerException(
"Cannot getAddressValue from this operand " + op +
" of instruction " + op.instruction);
}
}