/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.compilers.opt.ir.operand; import org.jikesrvm.VM; import org.jikesrvm.classloader.RVMClass; import org.jikesrvm.classloader.TypeReference; import org.jikesrvm.compilers.opt.ir.Register; import org.jikesrvm.compilers.opt.OptimizingCompilerException; /** * A symbolic or physical register. * A wrapper around an Register that may contain program-point specific * information about the value denoted by the Register. * <p> * TODO: This class is due for a refactor into subclasses * to split out the symbolic & physical registers and to create * special behavior for symbolic registers used as phi operands and * as validation (guard) operands. * * @see Operand */ public final class RegisterOperand extends Operand { /** * Converted from a reference? */ private boolean convertedFromRef = false; /** * Register object that this operand uses. */ private Register register; /** * Inferred data type of the contents of the register. */ private TypeReference type; /** * Used to maintain def and use lists. */ private RegisterOperand nextInDefUseList; /** * The guard associated with a RegisterOperand. * <p> * Used in the construction of the high-level intermediate representation. */ private Operand guard; /** * Type of a RegisterOperand can be in one of three states: * * <ol> * <li>a- declared: the type obtained from a * getfield,getstatic,putfield,putstatic,array load</li> * <li>b- precise: obtained from a NEW.</li> * <li>c- computed: (default) computed from propagating types.</li> * </ol> * * If the register is holding an int-like type it can be holding * just positive values. * * For calling conventions registers can be for parameters or * volatile/non-volatile. The value in the register can also be * extant - that is a definite non-null value (e.g. this pointer). */ private byte flags; /** * The type has been declared as obtained from a getfield, * getstatic, putfield, putstatic, array load */ private static final int DECLARED_TYPE = 0x01; /** We know precisely the type as it was create by a NEW */ private static final int PRECISE_TYPE = 0x02; /** Is the contents of the int-like register always positive? */ private static final int POSITIVE = 0x04; /** the register operand is for a parameter */ private static final byte PARAMETER = 0x10; /** is this a non-volatile physical register? */ private static final byte NON_VOLATILE = 0x20; /** is this an extant object? */ private static final byte EXTANT = 0x40; /** * Some bits used to characterize guards. TODO: Maybe declare a * new type GuardOperand extends RegisterOperand, and save * this state there? */ private byte flags2; /** guard operand that represents a taken branch */ private static final byte TAKEN = 0x01; /** guard operand that represents a not taken branch */ private static final byte NOT_TAKEN = 0x02; /** Guard operand that originates from a bounds-check */ private static final byte BOUNDS_CHECK = 0x04; /** Guard operand that originates from a null-check */ private static final byte NULL_CHECK = 0x08; /** * Constructs a new register operand with the given register and data type. * * @param reg register object * @param typ data type */ public RegisterOperand(Register reg, TypeReference typ) { setRegister(reg); setType(typ); } /** * Constructs a new register operand with the given register, data type and flags. * * @param reg register object * @param typ data type * @param inFlags to set for this register * @param isPrecise is this a precise type * @param isDeclared is this a declared type */ public RegisterOperand(Register reg, TypeReference typ, byte inFlags, boolean isPrecise, boolean isDeclared) { setRegister(reg); flags = inFlags; if (isPrecise) { setPreciseType(typ); } else { clearPreciseType(); setType(typ); } if (isDeclared) { setDeclaredType(); } else { clearDeclaredType(); } } /** * Returns a copy of this register operand as an operand */ @Override public Operand copy() { return copyRO(); } /** * Returns a copy of this register operand as a register operand.<p> * * NOTE: preserves the flags, guards and def/use lists. * * @return a copy of this register operand */ public RegisterOperand copyRO() { RegisterOperand temp = new RegisterOperand(register, type); temp.flags = flags; temp.flags2 = flags2; temp.nextInDefUseList = nextInDefUseList; temp.convertedFromRef = convertedFromRef; temp.guard = guard; if (VM.VerifyAssertions) verifyPreciseType(); return temp; } /** * @return a copy of this use register operand as another use reg operand. */ public RegisterOperand copyU2U() { return copyRO(); } /** * @return a copy of this def register operand as a use. */ public RegisterOperand copyD2U() { return copyRO(); } /** * @return a copy of this use register operand as a def. */ public RegisterOperand copyU2D() { return copyRO(); } /** * @return a copy of this def register operand as a def. */ public RegisterOperand copyD2D() { return copyRO(); } /** * @param op operand to compare against * @return whether the given operand is a register operand and has the same * register object. */ @Override public boolean similar(Operand op) { return (op instanceof RegisterOperand) && (register == ((RegisterOperand) op).getRegister()); } /** * Copy type information from the given operand into this one * including flag information on whether this is a precise type or * not * @param rhs the type to copy information from */ public void copyTypeFrom(RegisterOperand rhs) { this.flags = rhs.flags; this.setType(rhs.getType()); // setting type this way will force checking of precision } @Override public boolean isIntLike() { return type.isIntLikeType(); } @Override public boolean isInt() { return type.isIntType(); } @Override public boolean isLong() { return type.isLongType(); } @Override public boolean isFloat() { return type.isFloatType(); } @Override public boolean isDouble() { return type.isDoubleType(); } @Override public boolean isRef() { return type.isReferenceType(); } @Override public boolean isAddress() { return type.isWordLikeType(); } @Override public boolean isDefinitelyNull() { return type == TypeReference.NULL_TYPE; } public boolean isParameter() { return (flags & PARAMETER) != 0; } public void setParameter() { flags |= PARAMETER; } public void clearParameter() { flags &= ~PARAMETER; } public boolean isNonVolatile() { return (flags & NON_VOLATILE) != 0; } public void setNonVolatile() { flags |= NON_VOLATILE; } public void clearNonVolatile() { flags &= ~NON_VOLATILE; } /** * Is this register known to contain either NULL or an object whose class was fully loaded * before the current method was called? * This fact is used to determine whether we can optimize away inline guards * based on pre-existence based inlining. * * @return {@code true} if this register is extant (see above) */ public boolean isExtant() { return (flags & EXTANT) != 0; } /** * Sets this register as holding an extant object (or NULL) * (ie, an object whose class was fully loaded before the current method was called). * This fact is used to determine whether we can optimize away inline guards based on pre-existence * based inlining. */ public void setExtant() { flags |= EXTANT; } public void clearExtant() { flags &= ~EXTANT; } public boolean isDeclaredType() { return (flags & DECLARED_TYPE) != 0; } public void setDeclaredType() { flags |= DECLARED_TYPE; } public void clearDeclaredType() { flags &= ~DECLARED_TYPE; } private void verifyPreciseType() { if (!VM.VerifyAssertions) { VM.sysFail("Calls to verifyPreciseType must always be guarded by if \"(VM.VerifyAssertions)\"!"); } else { if (isPreciseType() && type != null && type.isClassType() && type.isResolved()) { RVMClass preciseClass = type.resolve().asClass(); if (preciseClass.isInterface() || preciseClass.isAbstract()) { VM.sysWriteln("Error processing instruction: ", this.instruction.toString()); throw new OptimizingCompilerException("Unable to set type as it would make this interface/abstract class precise " + preciseClass); } } } } public boolean isPreciseType() { return (flags & PRECISE_TYPE) != 0; } public void setPreciseType() { flags |= PRECISE_TYPE; if (VM.VerifyAssertions) verifyPreciseType(); } public void clearPreciseType() { flags &= ~PRECISE_TYPE; } public boolean isDeclaredOrPreciseType() { return (flags & (DECLARED_TYPE | PRECISE_TYPE)) != 0; } public boolean isPositiveInt() { return (flags & POSITIVE) != 0; } public void setPositiveInt() { flags |= POSITIVE; } /** @return a byte encoding register flags */ public byte getFlags() { return flags; } public void clearFlags() { flags = 0; } /** * Merges two sets of register flags. * @param inFlag the flags to merge to this register's flags */ public void addFlags(byte inFlag) { flags |= inFlag; if (VM.VerifyAssertions) verifyPreciseType(); } /** * Currently all flags are inheritable, so copy all flags from src. * @param src the operand to copy the flags from */ public void setInheritableFlags(RegisterOperand src) { flags = src.getFlags(); if (VM.VerifyAssertions) verifyPreciseType(); } /** * Currently all flags are "meetable", so mask flags together. * @param other the operand to use for computing the meet */ public void meetInheritableFlags(RegisterOperand other) { flags &= other.flags; } /** * @param other operand to compare with * @return {@code true} if we have any bits set (flag true) that other * doesn't. It's ok for other to have bits set true that we have set * to false. */ public boolean hasLessConservativeFlags(RegisterOperand other) { return other.getFlags() != (getFlags() | other.getFlags()); } /** @return {@code true} if this is a guard operand from a taken branch */ public boolean isTaken() { return (flags2 & TAKEN) != 0; } /** Set this a guard operand from a taken branch */ public void setTaken() { flags2 |= TAKEN; } /** Clear this from being a guard operand from a taken branch */ public void clearTaken() { flags2 &= ~TAKEN; } /** @return {@code true} if this is a guard operand from a not taken branch */ public boolean isNotTaken() { return (flags2 & NOT_TAKEN) != 0; } /** Set this a guard operand from a not taken branch */ public void setNotTaken() { flags2 |= NOT_TAKEN; } /** Clear this from being a guard operand from a not taken branch */ public void clearNotTaken() { flags2 &= ~NOT_TAKEN; } public boolean isBoundsCheck() { return (flags2 & BOUNDS_CHECK) != 0; } public void setBoundsCheck() { flags2 |= BOUNDS_CHECK; } public void clearBoundsCheck() { flags2 &= ~BOUNDS_CHECK; } public boolean isNullCheck() { return (flags2 & NULL_CHECK) != 0; } public void setNullCheck() { flags2 |= NULL_CHECK; } public void clearNullCheck() { flags2 &= ~NULL_CHECK; } /** * Sets the next register operand in the def/use list. * * @param next next register operand in the list */ public void setNext(RegisterOperand next) { nextInDefUseList = next; } /** * @return the next operand in the def/use list */ public RegisterOperand getNext() { return nextInDefUseList; } @Override public String toString() { String s = register.toString(); if (type != null) { if (type != TypeReference.VALIDATION_TYPE) { s = s + "(" + type.getName(); if (isExtant()) s += ",x"; if (isDeclaredType()) s += ",d"; if (isPreciseType()) s += ",p"; if (isPositiveInt()) s += ",+"; s += ")"; } else { s += "(GUARD)"; } } return s; } public void setRegister(Register register) { this.register = register; } public Register getRegister() { return register; } /** * Set the {@link TypeReference} of the value represented by the operand. * * @param t the inferred data type of the contents of the register */ public void setType(TypeReference t) { type = t; if (VM.VerifyAssertions) verifyPreciseType(); } /** * Set the {@link TypeReference} of the value represented by the operand and * make the type precise. * * @param t the inferred data type of the contents of the register */ public void setPreciseType(TypeReference t) { setType(t); flags |= PRECISE_TYPE; if (VM.VerifyAssertions) verifyPreciseType(); } /** * Return the {@link TypeReference} of the value represented by the operand. * * @return the inferred data type of the contents of the register */ @Override public TypeReference getType() { return type; } public void flagAsConvertedFromRef() { convertedFromRef = true; } public boolean convertedFromRef() { return convertedFromRef; } /** * Refine the type of the register to t if t is a more precise type than the * register currently holds * * @param t type to try to refine to */ public void refine(TypeReference t) { // TODO: see JIRA RVM-137 if (!isPreciseType()) { setType(t); } } /** * Note: This method is currently used only by test cases.<p> * * Does this operand have the same properties as the given Operand? This method * checks only the properties specific to RegisterOperand. * * @param other the operand to compare with * @return whether the given RegisterOperand could be seen as a copy of this one */ public boolean sameRegisterPropertiesAs(RegisterOperand other) { return this.register == other.register && this.flags == other.flags && this.flags2 == other.flags2 && this.guard == other.guard && this.nextInDefUseList == other.nextInDefUseList; } /** * Note: This method is currently used only by test cases.<p> * * Does this operand have the same properties as the given Operand? This method * checks only the properties specific to RegisterOperand. For guards, similarity * of operands is sufficient. * * @param other the operand to compare with * @return whether the given RegisterOperand could be seen as a copy of this one */ public boolean sameRegisterPropertiesAsExceptForGuardWhichIsSimilar(RegisterOperand other) { boolean guardsSimilar = this.guard == other.guard || this.guard != null && this.guard.similar(other.guard); return this.register == other.register && this.flags == other.flags && this.flags2 == other.flags2 && this.nextInDefUseList == other.nextInDefUseList && guardsSimilar; } public Operand getGuard() { return guard; } public void setGuard(Operand guard) { this.guard = guard; } }