/*
* 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 static org.jikesrvm.compilers.opt.bc2ir.IRGenOptions.DBG_OPERAND_LATTICE;
import static org.jikesrvm.compilers.opt.driver.OptConstants.YES;
import org.jikesrvm.VM;
import org.jikesrvm.classloader.TypeReference;
import org.jikesrvm.compilers.opt.ClassLoaderProxy;
import org.jikesrvm.compilers.opt.OptimizingCompilerException;
import org.jikesrvm.compilers.opt.bc2ir.BC2IR;
import org.jikesrvm.compilers.opt.bc2ir.ReturnAddressOperand;
import org.jikesrvm.compilers.opt.ir.Instruction;
import org.jikesrvm.compilers.opt.ir.Register;
import org.vmmagic.unboxed.Address;
/**
* An <code>Operand</code> identifies an operand for an
* {@link Instruction}. A single Operand object should
* not be shared between instructions (or even be used twice in
* the same instruction). Operands should not be shared between
* instructions because we use the
* {@link #instruction reference to the operand's containing instruction}
* to construct use/def chains. We also store program-point specific
* information about an {@link Register symbolic register}
* in the {@link RegisterOperand RegisterOperands} that
* {@link RegisterOperand#register refer} to the
* <code>Register</code>.
* <p>
* Operands are divided into several primary categories
* <ul>
* <li> {@link RegisterOperand} represent symbolic and
* and physical registers.
* <li> The subclasses of {@link ConstantOperand}
* represent various kinds of constant operands.
* <li> {@link MethodOperand} represents the targets of CALL instructions.
* <li> {@link BranchOperand}, {@link BasicBlockOperand},
* and {@link BranchOperand} are used to encode CFG
* information in LABEL, BBEND, and branch instructions.
* <li> {@link ConditionOperand} and {@link TrapCodeOperand}
* encode the conditions tested by conditional branches and
* trap instructions.
* <li> {@link LocationOperand} represents the memory location
* accessed by a load or store operation.
* <li> {@link TypeOperand} encodes a {@link org.jikesrvm.classloader.RVMType} for use
* in instructions such as NEW or INSTANCEOF that operate on the
* type hierarchy.
* </ul>
*
* @see Instruction
* @see BasicBlockOperand
* @see BranchOperand
* @see ConditionOperand
* @see ConstantOperand
* @see DoubleConstantOperand
* @see FloatConstantOperand
* @see IntConstantOperand
* @see LocationOperand
* @see LongConstantOperand
* @see MethodOperand
* @see NullConstantOperand
* @see RegisterOperand
* @see StringConstantOperand
* @see TrapCodeOperand
* @see TrueGuardOperand
* @see TypeOperand
*/
public abstract class Operand {
/**
* Handle back to containing instruction.
*/
public Instruction instruction;
/**
* Is the operand an {@link RegisterOperand}?
*
* @return <code>true</code> if <code>this</code> is an
* <code>instanceof</code> an {@link RegisterOperand}
* or <code>false</code> if it is not.
*/
public final boolean isRegister() {
return this instanceof RegisterOperand;
}
/**
* Is the operand an {@link ConstantOperand}?
*
* @return <code>true</code> if <code>this</code> is an
* <code>instanceof</code> an {@link ConstantOperand}
* or <code>false</code> if it is not.
*/
public final boolean isConstant() {
return this instanceof ConstantOperand;
}
/**
* Is the operand an {@link IntConstantOperand}?
*
* @return <code>true</code> if <code>this</code> is an
* <code>instanceof</code> an {@link IntConstantOperand}
* or <code>false</code> if it is not.
*/
public final boolean isIntConstant() {
return this instanceof IntConstantOperand;
}
/**
* Is the operand an {@link AddressConstantOperand}?
*
* @return <code>true</code> if <code>this</code> is an
* <code>instanceof</code> an {@link AddressConstantOperand}
* or <code>false</code> if it is not.
*/
public final boolean isAddressConstant() {
return this instanceof AddressConstantOperand;
}
/**
* Is the operand an {@link FloatConstantOperand}?
*
* @return <code>true</code> if <code>this</code> is an
* <code>instanceof</code> an {@link FloatConstantOperand}
* or <code>false</code> if it is not.
*/
public final boolean isFloatConstant() {
return this instanceof FloatConstantOperand;
}
/**
* Is the operand an {@link LongConstantOperand}?
*
* @return <code>true</code> if <code>this</code> is an
* <code>instanceof</code> an {@link LongConstantOperand}
* or <code>false</code> if it is not.
*/
public final boolean isLongConstant() {
return this instanceof LongConstantOperand;
}
/**
* Is the operand an {@link DoubleConstantOperand}?
*
* @return <code>true</code> if <code>this</code> is an
* <code>instanceof</code> an {@link DoubleConstantOperand}
* or <code>false</code> if it is not.
*/
public final boolean isDoubleConstant() {
return this instanceof DoubleConstantOperand;
}
/**
* Is the operand an {@link StringConstantOperand}?
*
* @return <code>true</code> if <code>this</code> is an
* <code>instanceof</code> an {@link StringConstantOperand}
* or <code>false</code> if it is not.
*/
public final boolean isStringConstant() {
return this instanceof StringConstantOperand;
}
/**
* Is the operand an {@link ClassConstantOperand}?
*
* @return <code>true</code> if <code>this</code> is an
* <code>instanceof</code> an {@link ClassConstantOperand}
* or <code>false</code> if it is not.
*/
public final boolean isClassConstant() {
return this instanceof ClassConstantOperand;
}
/**
* Is the operand an {@link ObjectConstantOperand}?
*
* @return <code>true</code> if <code>this</code> is an
* <code>instanceof</code> an {@link ObjectConstantOperand}
* or <code>false</code> if it is not.
*/
public final boolean isObjectConstant() {
return this instanceof ObjectConstantOperand;
}
/**
* Is the operand a movable {@link ObjectConstantOperand}?
*
* @return false
*/
public boolean isMovableObjectConstant() {
return false;
}
/**
* Is the operand an {@link TIBConstantOperand}?
*
* @return <code>true</code> if <code>this</code> is an
* <code>instanceof</code> an {@link TIBConstantOperand}
* or <code>false</code> if it is not.
*/
public final boolean isTIBConstant() {
return this instanceof TIBConstantOperand;
}
/**
* Is the operand an {@link NullConstantOperand}?
*
* @return <code>true</code> if <code>this</code> is an
* <code>instanceof</code> an {@link NullConstantOperand}
* or <code>false</code> if it is not.
*/
public final boolean isNullConstant() {
return this instanceof NullConstantOperand;
}
/**
* Is the operand an {@link TrueGuardOperand}?
*
* @return <code>true</code> if <code>this</code> is an
* <code>instanceof</code> an {@link TrueGuardOperand}
* or <code>false</code> if it is not.
*/
public final boolean isTrueGuard() {
return this instanceof TrueGuardOperand;
}
/**
* Is the operand an {@link BranchOperand}?
*
* @return <code>true</code> if <code>this</code> is an
* <code>instanceof</code> an {@link BranchOperand}
* or <code>false</code> if it is not.
*/
public final boolean isBranch() {
return this instanceof BranchOperand;
}
/**
* Is the operand an {@link BasicBlockOperand}?
*
* @return <code>true</code> if <code>this</code> is an
* <code>instanceof</code> an {@link BasicBlockOperand}
* or <code>false</code> if it is not.
*/
public final boolean isBlock() {
return this instanceof BasicBlockOperand;
}
/**
* Is the operand an {@link MemoryOperand}?
*
* @return <code>true</code> if <code>this</code> is an
* <code>instanceof</code> an {@link MemoryOperand}
* or <code>false</code> if it is not.
*/
public final boolean isMemory() {
return this instanceof MemoryOperand;
}
/**
* Is the operand an {@link StackLocationOperand}?
*
* @return <code>true</code> if <code>this</code> is an
* <code>instanceof</code> an {@link StackLocationOperand}
* or <code>false</code> if it is not.
*/
public final boolean isStackLocation() {
return this instanceof StackLocationOperand;
}
/**
* Is the operand an {@link MethodOperand}?
*
* @return <code>true</code> if <code>this</code> is an
* <code>instanceof</code> an {@link MethodOperand}
* or <code>false</code> if it is not.
*/
public final boolean isMethod() {
return this instanceof MethodOperand;
}
/**
* Is the operand an {@link LocationOperand}?
*
* @return <code>true</code> if <code>this</code> is an
* <code>instanceof</code> an {@link LocationOperand}
* or <code>false</code> if it is not.
*/
public final boolean isLocation() {
return this instanceof LocationOperand;
}
/**
* Is the operand an {@link TypeOperand}?
*
* @return <code>true</code> if <code>this</code> is an
* <code>instanceof</code> an {@link TypeOperand}
* or <code>false</code> if it is not.
*/
public final boolean isType() {
return this instanceof TypeOperand;
}
/**
* Cast to an {@link RegisterOperand}.
*
* @return <code>this</code> cast as an {@link RegisterOperand}
*/
public final RegisterOperand asRegister() {
return (RegisterOperand) this;
}
/**
* Cast to an {@link IntConstantOperand}.
*
* @return <code>this</code> cast as an {@link IntConstantOperand}
*/
public final IntConstantOperand asIntConstant() {
return (IntConstantOperand) this;
}
/**
* Cast to an {@link AddressConstantOperand}.
*
* @return <code>this</code> cast as an {@link AddressConstantOperand}
*/
public final AddressConstantOperand asAddressConstant() {
return (AddressConstantOperand) this;
}
/**
* Cast to an {@link FloatConstantOperand}.
*
* @return <code>this</code> cast as an {@link FloatConstantOperand}
*/
public final FloatConstantOperand asFloatConstant() {
return (FloatConstantOperand) this;
}
/**
* Cast to an {@link LongConstantOperand}.
*
* @return <code>this</code> cast as an {@link LongConstantOperand}
*/
public final LongConstantOperand asLongConstant() {
return (LongConstantOperand) this;
}
/**
* Cast to an {@link DoubleConstantOperand}.
*
* @return <code>this</code> cast as an {@link DoubleConstantOperand}
*/
public final DoubleConstantOperand asDoubleConstant() {
return (DoubleConstantOperand) this;
}
/**
* Cast to an {@link StringConstantOperand}.
*
* @return <code>this</code> cast as an {@link StringConstantOperand}
*/
public final StringConstantOperand asStringConstant() {
return (StringConstantOperand) this;
}
/**
* Cast to an {@link ClassConstantOperand}.
*
* @return <code>this</code> cast as an {@link ClassConstantOperand}
*/
public final ClassConstantOperand asClassConstant() {
return (ClassConstantOperand) this;
}
/**
* Cast to an {@link ObjectConstantOperand}.
*
* @return <code>this</code> cast as an {@link ObjectConstantOperand}
*/
public final ObjectConstantOperand asObjectConstant() {
return (ObjectConstantOperand) this;
}
/**
* Cast to an {@link TIBConstantOperand}.
*
* @return <code>this</code> cast as an {@link TIBConstantOperand}
*/
public final TIBConstantOperand asTIBConstant() {
return (TIBConstantOperand) this;
}
/**
* Cast to an {@link NullConstantOperand}.
*
* @return <code>this</code> cast as an {@link NullConstantOperand}
*/
public final NullConstantOperand asNullConstant() {
return (NullConstantOperand) this;
}
/**
* Cast to an {@link BranchOperand}.
*
* @return <code>this</code> cast as an {@link BranchOperand}
*/
public final BranchOperand asBranch() {
return (BranchOperand) this;
}
/**
* Cast to an {@link BasicBlockOperand}.
*
* @return <code>this</code> cast as an {@link BasicBlockOperand}
*/
public final BasicBlockOperand asBlock() {
return (BasicBlockOperand) this;
}
/**
* Cast to an {@link MemoryOperand}.
*
* @return <code>this</code> cast as an {@link MemoryOperand}
*/
public final MemoryOperand asMemory() {
return (MemoryOperand) this;
}
/**
* Cast to an {@link StackLocationOperand}.
*
* @return <code>this</code> cast as an {@link StackLocationOperand}
*/
public final StackLocationOperand asStackLocation() {
return (StackLocationOperand) this;
}
/**
* Cast to an {@link MethodOperand}.
*
* @return <code>this</code> cast as an {@link MethodOperand}
*/
public final MethodOperand asMethod() {
return (MethodOperand) this;
}
/**
* Cast to an {@link TypeOperand}.
*
* @return <code>this</code> cast as an {@link TypeOperand}
*/
public final TypeOperand asType() {
return (TypeOperand) this;
}
/**
* Cast to an {@link ConditionOperand}.
*
* @return <code>this</code> cast as an {@link ConditionOperand}
*/
public final ConditionOperand asCondition() {
return (ConditionOperand) this;
}
/**
* Cast to an {@link LocationOperand}.
*
* @return <code>this</code> cast as an {@link LocationOperand}
*/
public final LocationOperand asLocation() {
return (LocationOperand) this;
}
/**
* Does the operand represent a value of an int-like data type?
*
* @return <code>true</code> if the data type of <code>this</code>
* is int-like as defined by {@link TypeReference#isIntLikeType}
* or <code>false</code> if it is not.
*/
public boolean isIntLike() {
// default to false and then override in subclasses
return false;
}
/**
* Does the operand represent a value of the int data type?
*
* @return <code>true</code> if the data type of <code>this</code>
* is an int as defined by {@link TypeReference#isIntType}
* or <code>false</code> if it is not.
*/
public boolean isInt() {
// default to false and then override in subclasses
return false;
}
/**
* Does the operand represent a value of the long data type?
*
* @return <code>true</code> if the data type of <code>this</code>
* is a long as defined by {@link TypeReference#isLongType}
* or <code>false</code> if it is not.
*/
public boolean isLong() {
// default to false and then override in subclasses
return false;
}
/**
* Does the operand represent a value of the float data type?
*
* @return <code>true</code> if the data type of <code>this</code>
* is a float as defined by {@link TypeReference#isFloatType}
* or <code>false</code> if it is not.
*/
public boolean isFloat() {
// default to false and then override in subclasses
return false;
}
/**
* Does the operand represent a value of the double data type?
*
* @return <code>true</code> if the data type of <code>this</code>
* is a double as defined by {@link TypeReference#isDoubleType}
* or <code>false</code> if it is not.
*/
public boolean isDouble() {
// default to false and then override in subclasses
return false;
}
/**
* Does the operand represent a value of the reference data type?
*
* @return <code>true</code> if the data type of <code>this</code>
* is a reference as defined by {@link TypeReference#isReferenceType}
* or <code>false</code> if it is not.
*/
public boolean isRef() {
// default to false and then override in subclasses
return false;
}
/**
* Does the operand represent a value of the address data type?
*
* @return <code>true</code> if the data type of <code>this</code>
* is an address as defined by {@link TypeReference#isAddressType}
* or <code>false</code> if it is not.
*/
public boolean isAddress() {
// default to false and then override in subclasses
return false;
}
/**
* Does the operand definitely represent <code>null</code>?
*
* @return <code>true</code> if the operand definitely represents
* <code>null</code> or <code>false</code> if it does not.
*/
public boolean isDefinitelyNull() {
// default to false and then override in subclasses
return false;
}
/**
* Return a new operand that is semantically equivalent to <code>this</code>.
*
* @return a copy of <code>this</code>
*/
public abstract Operand copy();
/**
* Are two operands semantically equivalent?
*
* @param op other operand
* @return <code>true</code> if <code>this</code> and <code>op</code>
* are semantically equivalent or <code>false</code>
* if they are not.
*/
public abstract boolean similar(Operand op);
/**
* Return the {@link TypeReference} of the value represented by the operand.
*
* @return the type of the value represented by the operand
*/
public TypeReference getType() {
// by default throw OptimizingCompilerException as not all
// operands have a type.
throw new OptimizingCompilerException("Getting the type for this operand has no defined meaning: " + this);
}
/**
* Return the index of the operand in its containing instruction (SLOW).
*
* @return the index of the operand in its containing instruction
*/
public int getIndexInInstruction() {
for (int i = 0; i < instruction.getNumberOfOperands(); i++) {
Operand op = instruction.getOperand(i);
if (op == this) return i;
}
throw new OptimizingCompilerException("Operand.getIndexInInstruction");
}
/**
* Compare two operands based on their positions in the operand lattice.
* For the purposes of doing dataflow analysis, Operands can be
* thought of as forming a lattice.
* This function compares two operands and returns whether or
* not op1 is a conservative approximation of op2.
* Or in other words, if conservativelyApproximates(op1, op2)
* then meet(op1, op2) = op1.
* Note that lattices are partial orders, so it is quite
* possible for both conservativelyApproximates(op1, op2)
* and conservativelyApproximates(op2, op1) to return false.
*
* @param op1 the first operand to compare
* @param op2 the second operand to compare
* @return <code>true</code> if op1 conservatively approximates op2 or
* <code>false</code> if it does not.
*/
public static boolean conservativelyApproximates(Operand op1, Operand op2) {
// Step 1: Handle pointer equality and bottom
if (op1 == op2) {
if (DBG_OPERAND_LATTICE) {
if (op2 == null) {
VM.sysWriteln("operands are both bottom therefore trivially true");
} else {
VM.sysWriteln("operands are identical therefore trivially true");
}
}
return true;
}
if (op1 == null) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("op1 is bottom, therefore trivially true");
}
return true;
}
if (op2 == null) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("op2 is bottom, therefore trivially false");
}
return false;
}
// Now, handle the non-trivial cases:
// Step 2: op1 is a constant but op2 is not the same constant
if (op1.isConstant()) {
if (op1.similar(op2)) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("operands are similar constants");
}
return true;
} else {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("op1 is a constant but op2 is not the same constant");
}
return false;
}
}
// Step 3: op1 is a RegisterOperand
// This case is complicated by the need to ensure that the
// various Flag bits are considered as well....
if (op1.isRegister()) {
RegisterOperand rop1 = op1.asRegister();
TypeReference type1 = rop1.getType();
if (op2.isRegister()) {
RegisterOperand rop2 = op2.asRegister();
TypeReference type2 = rop2.getType();
if (type1 == type2) {
if (rop1.hasLessConservativeFlags(rop2)) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("Operands are registers of identical type, but incompatible flags");
}
return false;
} else if (BC2IR.hasLessConservativeGuard(rop1, rop2)) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("Operands are registers of identical type, but with incompatible non-null guards");
}
return false;
} else {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("Operands are compatible register operands");
}
return true;
}
} else if (compatiblePrimitives(type1, type2) ||
ClassLoaderProxy.includesType(type1, type2) == YES) {
// types are ok, only have to worry about the flags
if (rop1.isPreciseType() || rop1.hasLessConservativeFlags(rop2)) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("Flag mismatch between type compatible register operands");
}
return false;
} else if (BC2IR.hasLessConservativeGuard(rop1, rop2)) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("Non-null guard mismatch between type compatible register operands");
}
return false;
} else {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("Operands are compatible register operands");
}
return true;
}
} else {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("Operands are type incompatible register operands");
}
return false;
}
} else {
// op2 is not a register
if (op2 instanceof ReturnAddressOperand || op2 == BC2IR.DUMMY) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("Operands are incompatibale values");
}
return false;
}
TypeReference type2 = op2.getType();
if (type1 == type2 ||
compatiblePrimitives(type1, type2) ||
(ClassLoaderProxy.includesType(type1, type2) == YES)) {
// only have to consider state of op1's flags. Types are ok.
if (rop1.isPreciseType() && (type1 != type2)) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("op1 preciseType bit will be incorrect");
}
return false;
}
if ((rop1.getGuard() instanceof Operand) &&
((type2 == TypeReference.NULL_TYPE) ||
(type2.isIntLikeType() && op2.asIntConstant().value == 0) ||
(type2.isWordLikeType() && op2.asAddressConstant().value.EQ(Address.zero())) ||
(type2.isLongType() && op2.asLongConstant().value == 0L))) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("op1 non null guard will be incorrect");
}
return false;
}
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("(Constant) op2 was compatible with register op1");
}
return true;
} else {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("Op2 not compatible with register op1");
}
return false;
}
}
}
// Step 4: op1 is a IRGEN operand of some form
if (op1.similar(op2)) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("Compatible BC2IR.* operands");
}
return true;
} else {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("Incompatible BC2IR.* operands");
}
return false;
}
}
/**
* Meet two operands based on their positions in the operand lattice.
* For the purposes of doing dataflow analysis, Operands can be
* thought of as forming a lattice.
* This function takes two operands and returns their meet (glb).
* We use <code>null</code> to stand for bottom (the meet of
* the two operands is an illegal value). For exmaple,
* meet(5.0, "hi") would evalaute to bottom.
* Meet returns op1 iff conservativelyApproximates(op1, op2):
* this is exploited in BC2IR to avoid doing redundant
* work.
* <p>
* Unfortunately there is a fair amount of code duplication
* between {@link #conservativelyApproximates} and
* {@link #meet}, but factoring out the common control logic
* is a non-trivial task.
*
* @param op1 the first operand to meet
* @param op2 the second operand to meet
* @param reg the <code>Register</code> to use to
* create a new <code>RegisterOperand</code>
* if meeting op1 and op2 requires doing so.
* @return the Operand that is the meet of op1 and op2.
* This function will return <code>null</code> when
* the meet evaluates to bottom. It will return
* op1 when conservativelyApproximates(op1, op2)
* evaluates to <code>true</code>.
*/
public static Operand meet(Operand op1, Operand op2, Register reg) {
// Step 1: Handler pointer equality and bottom
if (op1 == op2) {
if (DBG_OPERAND_LATTICE) {
if (op1 == null) {
VM.sysWriteln("Both operands are bottom");
} else {
VM.sysWriteln("Operands are identical");
}
}
return op1;
}
if (op1 == null) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("Op1 was already bottom");
}
return op1;
}
if (op2 == null) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("Op2 is bottom (but op1 was not)");
}
return op2;
}
// Now handle the nontrivial cases...
// Step 2: op1 is <null> (the null constant)
if (op1 instanceof NullConstantOperand) {
if (op2 instanceof NullConstantOperand) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("Both operands are <null>");
}
return op1;
} else {
/*
* XXX Opt compiler guru please check :)
*
* Protect this code from crashing if op2 is DUMMY. As I understand
* the calling code this shouldn't happen, but the case for RegisterOperand
* handles it so I guess it's not too bad for a NullConstantOperand
* to do so.
*
* -- Robin Garner 1 Feb 7
*/
if (op2 instanceof ReturnAddressOperand || op2 == BC2IR.DUMMY) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("Incompatabily typed operands");
}
return null; // bottom
}
TypeReference type2 = op2.getType();
if (type2.isReferenceType()) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("op1 is <null>, but op2 is other ref type");
}
return new RegisterOperand(reg, type2);
} else {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("op1 is <null>, but op2 is not a ref type");
}
return null; // bottom
}
}
}
// Step 3: op1 is some other constant
if (op1.isConstant()) {
if (op1.similar(op2)) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("op1 and op2 are similar constants");
}
return op1;
} else {
TypeReference superType = ClassLoaderProxy.findCommonSuperclass(op1.getType(), op2.getType());
if (superType == null) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("op1 and op2 have incompatible types");
}
return null; // bottom
} else {
return new RegisterOperand(reg, superType);
}
}
}
// Step 4: op1 is a register operand
// This case is complicated by the need to ensure that
// the various Flag bits are considered as well....
if (op1.isRegister()) {
RegisterOperand rop1 = op1.asRegister();
TypeReference type1 = rop1.getType();
if (op2.isRegister()) {
RegisterOperand rop2 = op2.asRegister();
TypeReference type2 = rop2.getType();
if (type1 == type2) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("Identically typed register operands, checking flags...");
}
if (rop1.hasLessConservativeFlags(rop2)) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("mismatch");
}
RegisterOperand res = new RegisterOperand(reg, type1, rop1.getFlags(), rop1.isPreciseType(), rop1.isDeclaredType());
if (rop1.getGuard() instanceof Operand &&
rop2.getGuard() instanceof Operand &&
(rop1.getGuard().similar((rop2.getGuard())))) {
res.setGuard(rop1.getGuard()); // compatible, so preserve onto res
}
res.meetInheritableFlags(rop2);
return res;
} else if (BC2IR.hasLessConservativeGuard(rop1, rop2)) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln(
"Operands are registers of identical type with compatible flags but with incompatible non-null guards");
}
// by not setting guard we mark as possible null
return new RegisterOperand(reg, type1, rop1.getFlags(), rop1.isPreciseType(), rop1.isDeclaredType());
} else {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("match");
}
return op1;
}
} else if (compatiblePrimitives(type1, type2) ||
ClassLoaderProxy.includesType(type1, type2) == YES) {
if (DBG_OPERAND_LATTICE) {
VM.sysWrite("Compatibly typed register operands, checking flags...");
}
if (rop1.isPreciseType() || rop1.hasLessConservativeFlags(rop2)) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("mismatch");
}
RegisterOperand res = new RegisterOperand(reg, type1, rop1.getFlags(), rop1.isPreciseType(), rop1.isDeclaredType());
res.meetInheritableFlags(rop2);
// even if both op1 & op2 are precise,
// op1.type != op2.type, so clear it on res
res.clearPreciseType();
if (rop1.getGuard() instanceof Operand &&
rop2.getGuard() instanceof Operand &&
(rop1.getGuard().similar((rop2.getGuard())))) {
// it matched, so preserve onto res.
res.setGuard(rop1.getGuard());
}
return res;
} else if (BC2IR.hasLessConservativeGuard(rop1, rop2)) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("Operands are registers of compatible type and flags but with incompatible non-null guards");
}
return new RegisterOperand(reg, type1, rop1.getFlags(), rop1.isPreciseType(), rop1.isDeclaredType());
} else {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("match");
}
return op1;
}
} else {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("Incompatibly typed register operands...(" + type1 + ", " + type2 + ")...");
}
TypeReference resType = ClassLoaderProxy.findCommonSuperclass(type1, type2);
if (resType == null) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("no common supertype, returning bottom");
}
return null; // bottom
} else {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("found common supertype");
}
RegisterOperand res = new RegisterOperand(reg, resType, rop1.getFlags(), false, false);
res.meetInheritableFlags(rop2);
res.clearPreciseType(); // invalid on res
res.clearDeclaredType(); // invalid on res
if (rop1.getGuard() instanceof Operand &&
rop2.getGuard() instanceof Operand &&
(rop1.getGuard().similar((rop2.getGuard())))) {
// it matched, so preserve onto res.
res.setGuard(rop1.getGuard());
}
return res;
}
}
} else {
if (op2 instanceof ReturnAddressOperand || op2 == BC2IR.DUMMY) {
if (DBG_OPERAND_LATTICE) {
VM.sysWrite("Incompatibly typed operands");
}
return null; // bottom
}
TypeReference type2 = op2.getType();
if (type1 == type2 ||
compatiblePrimitives(type1, type2) ||
(ClassLoaderProxy.includesType(type1, type2) == YES)) {
if (DBG_OPERAND_LATTICE) {
VM.sysWrite("Compatibly typed register & other operand, checking flags...");
}
RegisterOperand res = rop1;
if (res.isPreciseType() && type1 != type2) {
res = res.copyU2U();
res.clearPreciseType();
}
if ((rop1.getGuard() instanceof Operand) &&
((type2 == TypeReference.NULL_TYPE) ||
(type2.isIntLikeType() && op2.asIntConstant().value == 0) ||
(type2.isWordLikeType() && op2.asAddressConstant().value.isZero()) ||
(type2.isLongType() && op2.asLongConstant().value == 0L))) {
res = res.copyU2U();
res.setGuard(null);
}
if (DBG_OPERAND_LATTICE) {
if (res == rop1) {
VM.sysWriteln("match");
} else {
VM.sysWriteln("mismatch");
}
}
return res;
} else {
if (DBG_OPERAND_LATTICE) {
VM.sysWrite("Incompatibly typed register & other operand...(" + type1 + ", " + type2 + ")...");
}
TypeReference resType = ClassLoaderProxy.findCommonSuperclass(type1, type2);
if (resType == null) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("no common supertype, returning bottom");
}
return null; // bottom
} else {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("found common supertype");
}
return new RegisterOperand(reg, resType);
}
}
}
}
// Step 5: op1 is some IRGEN operand
if (op1.similar(op2)) {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("Compatible BC2IR.* operands");
}
return op1;
} else {
if (DBG_OPERAND_LATTICE) {
VM.sysWriteln("Incompatible BC2IR.* operands, returning bottom");
}
return null; // bottom
}
}
private static boolean compatiblePrimitives(TypeReference type1, TypeReference type2) {
if (type1.isIntLikeType() && type2.isIntLikeType()) {
if (type1.isIntType()) {
return type2.isBooleanType() || type2.isByteType() || type2.isShortType() || type2.isIntType();
}
if (type1.isShortType()) {
return type2.isBooleanType() || type2.isByteType() || type2.isShortType();
}
if (type1.isByteType()) {
return type2.isBooleanType() || type2.isByteType();
}
if (type1.isBooleanType()) {
return type2.isBooleanType();
}
}
return false;
}
}