/*
 *  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.ir;

import org.jikesrvm.VM;
import org.jikesrvm.Constants;
import org.jikesrvm.ArchitectureSpecificOpt.PhysicalDefUse;
import org.jikesrvm.compilers.opt.LocalCSE;
import org.jikesrvm.compilers.opt.OptimizingCompilerException;
import org.jikesrvm.compilers.opt.driver.OptConstants;
import org.jikesrvm.compilers.opt.inlining.InlineSequence;
import org.jikesrvm.compilers.opt.ir.operand.BranchOperand;
import org.jikesrvm.compilers.opt.ir.operand.MemoryOperand;
import org.jikesrvm.compilers.opt.ir.operand.MethodOperand;
import org.jikesrvm.compilers.opt.ir.operand.Operand;
import org.jikesrvm.compilers.opt.ir.operand.StackLocationOperand;
import org.vmmagic.pragma.Inline;
import org.vmmagic.pragma.NoInline;

/**
 * Instructions are the basic atomic unit of the IR.
 * An instruction contains an {@link Operator operator} and
 * (optionally) some {@link Operand operands}.
 * In addition, an instruction may (or may not) have
 * valid {@link #bcIndex} and{@link #position} fields that
 * together encode a description of the bytecode that it came from.
 * <p>
 * Although we use a single class, <code>Instruction</code>,
 * to implement all IR instructions, there are logically a number
 * of different kinds of instructions.
 * For example, binary operators, array loads, calls,
 * and null_checks all have different number of operands with differing
 * semantics.  To manage this in an abstract, somewhat object-oriented,
 * but still highly efficient fashion we have the notion of an
 * <em>Instruction Format</em>. An Instruction Format is a class
 * external to Instruction (defined in the instructionFormat package)
 * that provides static methods to create instructions and symbolically
 * access their operands.  Every instance of <code>Operator</code>
 * is assigned to exactly one Instruction Format.  Thus, the instruction's
 * operator implies which Instruction Format class can be used to
 * access the instruction's operands.
 * <p>
 * There are some common logical operands (eg Result, Location) that
 * appear in a large number of Instruction Formats.  In addition to the
 * basic Instruction Format classes, we provided additional classes
 * (eg ResultCarrier, LocationCarrier) that allow manipulation of all
 * instructions that contain a common operands.
 * <p>
 * A configuration (OptOptVIFcopyingGC) is defined in which all methods of
 * all Instruction Format classes verify that the operator of the instruction
 * being manipulated actually belongs to the appropriate Instruction Format.
 * This configuration is quite slow, but is an important sanity check to make
 * sure that Instruction Formats are being used in a consistent fashion.
 * <p>
 * The instruction's operator also has a number of traits.  Methods on
 * <code>Instruction</code> are provided to query these operator traits.
 * In general, clients should use the methods of Instruction to query
 * traits, since a particular instruction may override the operator-provided
 * default in some cases. For example, {@link #isMove()}, {@link #isBranch()},
 * {@link #isPEI()}, and {@link #isCall()} are some of the trait queries.
 * <p>
 * Unfortunately, the combination of operators, operator traits, and
 * Instruction Formats often leads to a tricky decision of which of three
 * roughly equivalent idioms one should use when writing code that
 * needs to manipulate instructions and their operands.
 * For example,
 * <pre>
 * if (Call.conforms(instr)) {
 *    return Call.getResult(instr);
 * }
 * </pre>
 * and
 * <pre>
 * if (instr.operator() == CALL) {
 *    return Call.getResult(instr);
 * }
 * </pre>
 * and
 * <pre>
 * if (instr.isCall()) {
 *    return ResultCarrier.getResult(instr);
 * }
 * </pre>
 * are more or less the same.
 * In some cases, picking an idiom is simply a matter of taste,
 * but in others making the wrong choice can lead to code that is less
 * robust or maintainable as operators and/or instruction formats are added
 * and removed from the IR. One should always think carefully about which
 * idiom is the most concise, maintainable, robust and efficient means of
 * accomplishing a given task.
 * Some general rules of thumb (or at least one person's opinion):
 * <ul>
 * <li> Tests against operator traits should be preferred
 *      to use of the conforms method of an Instruction Format class if
 *      both are possible.  This is definitely true if the code in question
 *      does not need to access specific operands of the instruction.
 *      Things are murkier if the code needs to manipulate specific
 *      (non-common) operands of the instruction.
 * <li> If you find yourself writing long if-then-else constructs using
 *      either Instruction Format conforms or operator traits then you ought to
 *      at least consider writing a switch statement on the opcode of the
 *      operator.  It should be more efficient and, depending on what your
 *      desired default behavior is, may be more robust/maintainable as well.
 * <li> Instruction Format classes are really intended to represent the
 *      "syntactic form" of an instruction, not the semantics of its operator.
 *      Using "conforms" when no specific operands are being manipulated
 *      is almost always not the right way to do things.
 * </ul>
 *
 * @see Operator
 * @see Operand
 * @see BasicBlock
 */
public final class Instruction implements Constants, Operators, OptConstants {

  /**
   * BITFIELD used to encode {@link #operatorInfo}.
   * NB: OI_INVALID must be default value!
   */
  @SuppressWarnings("unused")
  // FIXME use it or lose it!
  private static final byte OI_INVALID = 0x00;
  /** BITFIELD used to encode {@link #operatorInfo}. */
  private static final byte OI_PEI_VALID = 0x01;
  /** BITFIELD used to encode {@link #operatorInfo}. */
  private static final byte OI_PEI = 0x02;
  /** BITFIELD used to encode {@link #operatorInfo}. */
  private static final byte OI_GC_VALID = 0x04;
  /** BITFIELD used to encode {@link #operatorInfo}. */
  private static final byte OI_GC = 0x08;
  /** BITFIELD used to encode {@link #operatorInfo}. */
  private static final byte MARK1 = 0x20;
  /** BITFIELD used to encode {@link #operatorInfo}. */
  private static final byte MARK2 = 0x40;
  /*
   * NOTE: There are currently two free bits: 0x10 and 0x80.
   */

  /**
   * The index of the bytecode that this instruction came from.
   * In combination with the {@link #position}, the bcIndex field
   * uniquely identifies the source postion of the bytecode that
   * this instruction came from.
   */
  public int bcIndex = UNKNOWN_BCI;

  /**
   * A description of the tree of inlined methods that contains the bytecode
   * that this instruction came from.
   * In combination with the {@link #bcIndex}, the position field
   * uniquely identifies the source postion of the bytecode that
   * this instruction came from.
   * A single postion operator can be shared by many instruction objects.
   *
   * @see InlineSequence
   * @see org.jikesrvm.compilers.opt.runtimesupport.OptEncodedCallSiteTree
   */
  public InlineSequence position;

  /**
   * A scratch word to be used as needed by analyses/optimizations to store
   * information during an optimization.
   * Cannot be used to comunicate information between compiler phases since
   * any phase is allowed to mutate it.
   * Cannot safely be assumed to have a particular value at the start of
   * a phase.
   * Typical uses:  scratch bits to encode true/false or numbering
   *                store an index into a lookaside array of other information.
   */
  public int scratch;

  /**
   * A scratch object to be used as needed by analyses/optimizations to store
   * information during an optimization.
   * Cannot be used to comunicate information between compiler phases since
   * any phase is allowed to mutate it.
   * Cannot safely be assumed to have a particular value at the start of
   * a phase.
   * To be used when more than one word of information is needed and
   * lookaside arrays are not desirable.
   * Typical uses:  attribute objects or links to shared data
   */
  public Object scratchObject;

  /**
   * The operator for this instruction.
   * The prefered idiom is to use the {@link #operator()} accessor method
   * instead of accessing this field directly, but we are still in the process
   * of updating old code.
   * The same operator object can be shared by many instruction objects.
   * TODO: finish conversion and make this field private.
   */
  public Operator operator;

  /**
   * The next instruction in the intra-basic-block list of instructions,
   * will be null if no such instruction exists.
   */
  private Instruction next;

  /**
   * The previous instruction in the intra-basic-block list of instructions,
   * will be null if no such instruction exists.
   */
  private Instruction prev;

  /**
   * Override and refine the operator-based trait (characteristic)
   * information.
   * @see Operator
   */
  private byte operatorInfo;

  /**
   * The operands of this instruction.
   */
  private Operand[] ops;

  /**
   * INTERNAL IR USE ONLY: create a new instruction with the specified number
   * of operands.
   * For internal use only -- general clients must use the appropriate
   * InstructionFormat class's create and mutate methods to create
   * instruction objects!!!  But, because we put the InstructionFormat
   * classes in their own package for name space control, we have to
   * make this constructor public.  What a crock!
   *
   * @param op operator
   * @param size number of operands
   */
  public Instruction(Operator op, int size) {
    operator = op;
    ops = new Operand[size];
  }

  /**
   * Create a copy of this instruction.
   * The copy has the same operator and operands, but is not linked into
   * an instruction list.
   *
   * @return the copy
   */
  public Instruction copyWithoutLinks() {
    Instruction copy = new Instruction(operator, ops.length);
    for (int i = 0; i < ops.length; i++) {
      if (ops[i] != null) {
        copy.ops[i] = ops[i].copy();
        copy.ops[i].instruction = copy;
      }
    }
    copy.bcIndex = bcIndex;
    copy.operatorInfo = operatorInfo;
    copy.position = position;

    return copy;
  }

  /**
   * Returns the string representation of this instruction
   * (mainly intended for use when printing the IR).
   *
   * @return string representation of this instruction.
   */
  public String toString() {
    StringBuilder result = new StringBuilder("    ");
    if (isPEI()) {
      result.setCharAt(0, 'E');
    }
    if (isGCPoint()) {
      result.setCharAt(1, 'G');
    }

    if (operator == LABEL) {
      result.append("LABEL").append(Label.getBlock(this).block.getNumber());
      if (Label.getBlock(this).block.getInfrequent()) result.append(" (Infrequent)");
      return result.toString();
    }

    result.append(operator);
    Operand op;
    int N = getNumberOfOperands();
    int numDefs = getNumberOfDefs();
    //int numIDefs = operator.getNumberOfImplicitDefs();

    // print explicit defs
    int defsPrinted = 0;
    for (int i = 0; i < numDefs; i++) {
      op = getOperand(i);
      if (op != null) {
        if (defsPrinted > 0) result.append(", ");
        if (defsPrinted % 10 == 9) result.append('\n');
        result.append(op);
        defsPrinted++;
      }
    }

    // print implicit defs
    result.append(PhysicalDefUse.getString(operator.implicitDefs));
    defsPrinted += operator.getNumberOfImplicitDefs();

    // print separator
    if (defsPrinted > 0) {
      if (operator.getNumberOfDefUses() == 0) {
        result.append(" = ");
      } else {
        result.append(" <-- ");
      }
    }

    // print explicit uses
    int usesPrinted = 0;
    for (int i = numDefs; i < N; i++) {
      op = getOperand(i);
      if (usesPrinted > 0) result.append(", ");
      if ((defsPrinted + usesPrinted) % 10 == 9) result.append('\n');
      usesPrinted++;
      if (op != null) {
        result.append(op);
      } else {
        result.append("<unused>");
      }
    }

    // print implicit defs
    result.append(PhysicalDefUse.getString(operator.implicitUses));
    usesPrinted += operator.getNumberOfImplicitUses();

    return result.toString();
  }

  /**
   * Return the next instruction with respect to the current
   * code linearization order.
   *
   * @return the next insturction in the code order or
   *         <code>null</code> if no such instruction exists
   */
  public Instruction nextInstructionInCodeOrder() {
    if (next == null) {
      if (VM.VerifyAssertions) VM._assert(BBend.conforms(this));
      BasicBlock nBlock = BBend.getBlock(this).block.nextBasicBlockInCodeOrder();
      if (nBlock == null) {
        return null;
      } else {
        return nBlock.firstInstruction();
      }
    } else {
      return next;
    }
  }

  /**
   * Return the previous instruction with respect to the current
   * code linearization order.
   *
   * @return the previous insturction in the code order or
   *         <code>null</code> if no such instruction exists
   */
  public Instruction prevInstructionInCodeOrder() {
    if (prev == null) {
      BasicBlock nBlock = Label.getBlock(this).block.prevBasicBlockInCodeOrder();
      if (nBlock == null) {
        return null;
      } else {
        return nBlock.lastInstruction();
      }
    } else {
      return prev;
    }
  }

  /**
   * Get the basic block that contains this instruction.
   * Note: this instruction takes O(1) time for LABEL and BBEND
   * instructions, but will take O(# of instrs in the block)
   * for all other instructions. Therefore, although it can be used
   * on any instruction, care must be taken when using it to avoid
   * doing silly O(N^2) work for what could be done in O(N) work.
   */
  public BasicBlock getBasicBlock() {
    if (isBbFirst()) {
      return Label.getBlock(this).block;
    } else if (isBbLast()) {
      return BBend.getBlock(this).block;
    } else {
      // Find basic block by going forwards to BBEND instruction
      Instruction instr = null; // Set = null to avoid compiler warning.
      for (instr = getNext(); !instr.isBbLast(); instr = instr.getNext()) ;
      return BBend.getBlock(instr).block;
    }
  }

  /*
  * Set the source position description ({@link #bcIndex},
  * {@link #position}) for this instruction to be the same as the
  * source instruction's source position description.
  *
  * @param source the instruction to copy the source position from
  */
  public void copyPosition(Instruction source) {
    bcIndex = source.bcIndex;
    position = source.position;
  }

  /**
   * Get the {@link #bcIndex bytecode index} of the instruction.
   *
   * @return the bytecode index of the instruction
   */
  public int getBytecodeIndex() {
    return bcIndex;
  }

  /**
   * Set the {@link #bcIndex bytecode index} of the instruction.
   *
   * @param bci the new bytecode index
   */
  public void setBytecodeIndex(int bci) {
    bcIndex = bci;
  }

  /**
   * Get the offset into the machine code array (in bytes) that
   * corresponds to the first byte after this instruction.
   * This method only returns a valid value after it has been set as a
   * side-effect of {@link org.jikesrvm.ArchitectureSpecificOpt.AssemblerOpt#generateCode final assembly}.
   * To get the offset in INSTRUCTIONs you must shift by LG_INSTURUCTION_SIZE.
   *
   * @return the offset (in bytes) of the machinecode instruction
   *         generated for this IR instruction in the final machinecode
   */
  public int getmcOffset() {
    return scratch;
  }

  /**
   * Only for use by {@link org.jikesrvm.ArchitectureSpecificOpt.AssemblerOpt#generateCode}; sets the machine
   * code offset of the instruction as described in {@link #getmcOffset}.
   *
   * @param mcOffset the offset (in bytes) for this instruction.
   */
  public void setmcOffset(int mcOffset) {
    scratch = mcOffset;
  }

  /**
   * Return the instruction's operator.
   *
   * @return the operator
   */
  public Operator operator() {
    return operator;
  }

  /**
   * Return the opcode of the instruction's operator
   * (a unique id suitable for use in switches); see
   * {@link Operator#opcode}.
   *
   * @return the operator's opcode
   */
  public char getOpcode() {
    return operator.opcode;
  }

  /*
  * Functions dealing with the instruction's operands.
  * Clients currently are grudgingly allowed (but definitely NOT encouraged)
  * to depend on the fact that operands are partially ordered:
  * first all the defs, then all the def/uses, then all the uses.
  * This may change in the future, so please try not to depend on it unless
  * absolutely necessary.
  *
  * Clients are NOT allowed to assume that specific operands appear in
  * a particular order or at a particular index in the operand array.
  * Doing so results in fragile code and is generally evil.
  * Virtually all access to operands should be through the OperandEnumerations
  * or through accessor functions of the InstructionFormat classes.
  */

  /**
   * Get the number of operands in this instruction.
   *
   * @return number of operands
   */
  public int getNumberOfOperands() {
    if (operator.hasVarUsesOrDefs()) {
      return getNumberOfOperandsVarUsesOrDefs();
    } else {
      return operator.getNumberOfDefs() + operator.getNumberOfPureUses();
    }
  }

  // isolate uncommon cases to enable inlined common case of getNumberOfOperands
  private int getNumberOfOperandsVarUsesOrDefs() {
    int numOps = ops.length - 1;
    int minOps;
    if (operator().hasVarUses()) {
      minOps = operator.getNumberOfDefs() + operator.getNumberOfPureFixedUses() - 1;
    } else {
      minOps = operator.getNumberOfFixedPureDefs() - 1;
    }
    while (numOps > minOps && ops[numOps] == null) numOps--;
    return numOps + 1;
  }

  /**
   * Returns the number of operands that are defs
   * (either pure defs or combined def/uses).
   * By convention, operands are ordered in instructions
   * such that all defs are first, followed by all
   * combined defs/uses, followed by all pure uses.
   *
   * @return number of operands that are defs
   */
  public int getNumberOfDefs() {
    if (operator.hasVarDefs()) {
      int numOps = operator.getNumberOfFixedPureDefs();
      for (; numOps < ops.length; numOps++) {
        if (ops[numOps] == null) break;
      }
      return numOps;
    } else {
      return operator.getNumberOfDefs();
    }
  }

  /**
   * Returns the number of operands that are pure defs.
   * By convention, operands are ordered in instructions
   * such that all defs are first, followed by all
   * combined defs/uses, followed by all pure uses.
   *
   * @return number of operands that are defs
   */
  public int getNumberOfPureDefs() {
    if (operator.hasVarDefs()) {
      if (VM.VerifyAssertions) {
        VM._assert(operator.getNumberOfDefUses() == 0);
      }
      int numOps = operator.getNumberOfFixedPureDefs();
      for (; numOps < ops.length; numOps++) {
        if (ops[numOps] == null) break;
      }
      return numOps;
    } else {
      return operator.getNumberOfFixedPureDefs();
    }
  }

  /**
   * Returns the number of operands that are pure uses.
   * By convention, operands are ordered in instructions
   * such that all defs are first, followed by all
   * combined defs/uses, followed by all pure uses.
   *
   * @return number of operands that are defs
   */
  public int getNumberOfPureUses() {
    if (operator.hasVarDefs()) {
      if (VM.VerifyAssertions) {
        VM._assert(operator.getNumberOfDefUses() == 0);
      }
      int numOps = operator.getNumberOfFixedPureUses();
      int i = getNumberOfDefs() + numOps;
      for (; i < ops.length; i++) {
        if (ops[i] == null) break;
        numOps++;
      }
      return numOps;
    } else {
      if (operator.hasVarUses()) {
        return getNumberOfOperands() - operator.getNumberOfDefs();
      } else {
        return operator.getNumberOfFixedPureUses();
      }
    }
  }

  /**
   * Returns the number of operands that are uses
   * (either combined def/uses or pure uses).
   * By convention, operands are ordered in instructions
   * such that all defs are first, followed by all
   * combined defs/uses, followed by all pure uses.
   *
   * @return how many operands are uses
   */
  public int getNumberOfUses() {
    if (operator.hasVarUses()) {
      return getNumberOfOperands() - operator.getNumberOfPureDefs();
    } else {
      return operator.getNumberOfUses();
    }
  }

  /**
   * Replace all occurances of the first operand with the second.
   *
   * @param oldOp   The operand to replace
   * @param newOp   The new one to replace it with
   */
  public void replaceOperand(Operand oldOp, Operand newOp) {
    for (int i = 0; i < ops.length; i++) {
      if (getOperand(i) == oldOp) {
        putOperand(i, newOp);
      }
    }
  }

  /**
   * Replace any operands that are similar to the first operand
   * with a copy of the second operand.
   *
   * @param oldOp   The operand whose similar operands should be replaced
   * @param newOp   The new one to replace it with
   */
  public void replaceSimilarOperands(Operand oldOp, Operand newOp) {
    for (int i = 0; i < ops.length; i++) {
      if (oldOp.similar(getOperand(i))) {
        putOperand(i, newOp.copy());
      }
    }
  }

  /**
   * Replace all occurances of register r with register n
   *
   * @param r the old register
   * @param n the new register
   */
  public void replaceRegister(Register r, Register n) {
    for (OperandEnumeration u = getUses(); u.hasMoreElements();) {
      Operand use = u.nextElement();
      if (use.isRegister()) {
        if (use.asRegister().getRegister() == r) {
          use.asRegister().setRegister(n);
        }
      }
    }
    for (OperandEnumeration d = getDefs(); d.hasMoreElements();) {
      Operand def = d.nextElement();
      if (def.isRegister()) {
        if (def.asRegister().getRegister() == r) {
          def.asRegister().setRegister(n);
        }
      }
    }
  }

  /**
   * Does this instruction hold any memory or stack location operands?
   */
  public boolean hasMemoryOperand() {
    for (int i = 0; i < ops.length; i++) {
      Operand op = getOperand(i);
      if (op instanceof MemoryOperand || op instanceof StackLocationOperand) {
        return true;
      }
    }
    return false;
  }

  /**
   * Enumerate all "leaf" operands of an instruction.
   * NOTE: DOES NOT RETURN MEMORY OPERANDS, ONLY
   *       THEIR CONTAINED OPERANDS!!!!!
   *
   * @return an enumeration of the instruction's operands.
   */
  public OperandEnumeration getOperands() {
    // By passing -1 as the last parameter we pretending
    // that treating all operands are uses. Somewhat ugly,
    // but avoids a third OE class.
    return new OE(this, 0, getNumberOfOperands() - 1, -1);
  }

  /**
   * Enumerate all memory operands of an instruction
   *
   * @return an enumeration of the instruction's operands.
   */
  public OperandEnumeration getMemoryOperands() {
    return new MOE(this, 0, getNumberOfOperands() - 1);
  }

  /**
   * Enumerate all the root operands of an instruction
   * (DOES NOT ENUMERATE CONTAINED OPERANDS OF MEMORY OPERANDS)
   *
   * @return an enumeration of the instruction's operands.
   */
  public OperandEnumeration getRootOperands() {
    return new ROE(this, 0, getNumberOfOperands() - 1);
  }

  /**
   * Enumerate all defs (both pure defs and def/uses) of an instruction.
   *
   * @return an enumeration of the instruction's defs.
   */
  public OperandEnumeration getDefs() {
    return new OEDefsOnly(this, 0, getNumberOfDefs() - 1);
  }

  /**
   * Enumerate all the pure defs (ie not including def/uses) of an instruction.
   *
   * @return an enumeration of the instruction's pure defs.
   */
  public OperandEnumeration getPureDefs() {
    return new OEDefsOnly(this, 0, getNumberOfPureDefs() - 1);
  }

  /**
   * Enumerate all the pure uses (ie not including def/uses) of an instruction.
   *
   * @return an enumeration of the instruction's pure defs.
   */
  public OperandEnumeration getPureUses() {
    return new OEDefsOnly(this, getNumberOfDefs(), getNumberOfOperands() - 1);
  }

  /**
   * Enumerate all the def/uses of an instruction.
   *
   * @return an enumeration of the instruction's def/uses.
   */
  public OperandEnumeration getDefUses() {
    return new OEDefsOnly(this, getNumberOfPureDefs(), getNumberOfDefs() - 1);
  }

  /**
   * Enumerate all uses of an instruction (includes def/use).
   *
   * @return an enumeration of the instruction's uses.
   */
  @Inline
  public OperandEnumeration getUses() {
    int numOps = getNumberOfOperands() - 1;
    int defsEnd = operator.hasVarDefs() ? numOps : operator.getNumberOfPureDefs() - 1;
    return new OE(this, 0, numOps, defsEnd);
  }

  /**
   * Enumerate all root uses of an instruction.
   *
   * @return an enumeration of the instruction's uses.
   */
  public OperandEnumeration getRootUses() {
    return new ROE(this, getNumberOfPureDefs(), getNumberOfOperands() - 1);
  }

  /*
  * Methods dealing with the instruction's operator.
  * In the HIR and LIR these methods act simply as forwarding
  * methods to the Operator method.  In the MIR, they allow
  * us to override the operator-level defaults. Overrides mainly
  * occur from null-check combining (the null check gets folded into
  * a load/store instruction which does the check in hardware via
  * a segv when the ptr is null), but may occur for other reasons as well.
  * In the future, we may allow overrides on the HIR/LIR as well.
  * Thus, it is generally a good idea for clients to always use the
  * instruction variant of these methods rather than calling the
  * corresponding method directly on the operator.
  */

  /**
   * Does the instruction represent a simple move (the value is unchanged)
   * from one "register" location to another "register" location?
   *
   * @return <code>true</code> if the instruction is a simple move
   *         or <code>false</code> if it is not.
   */
  public boolean isMove() {
    return operator.isMove();
  }

  /**
   * Is the instruction an intraprocedural branch?
   *
   * @return <code>true</code> if the instruction is am
   *         intraprocedural branch or <code>false</code> if it is not.
   */
  public boolean isBranch() {
    return operator.isBranch();
  }

  /**
   * Is the instruction a conditional intraprocedural branch?
   *
   * @return <code>true</code> if the instruction is a conditional
   *         intraprocedural branch or <code>false</code> if it is not.
   */
  public boolean isConditionalBranch() {
    return operator.isConditionalBranch();
  }

  /**
   * Is this instruction a branch that has that has only two possible
   * successors?
   *
   * @return <code>true</code> if the instruction is an
   * interprocedural conditional branch with only two possible
   * outcomes (taken or not taken).
   */
  public boolean isTwoWayBranch() {
    // Is there a cleaner way to answer this question?
    return (isConditionalBranch() && !IfCmp2.conforms(this) && !MIR_CondBranch2.conforms(this));
  }

  /**
   * Is the instruction an unconditional intraprocedural branch?
   * We consider various forms of switches to be unconditional
   * intraprocedural branches, even though they are multi-way branches
   * and we may not no exactly which target will be taken.
   * This turns out to be the right thing to do, since some
   * arm of the switch will always be taken (unlike conditional branches).
   *
   * @return <code>true</code> if the instruction is an unconditional
   *         intraprocedural branch or <code>false</code> if it is not.
   */
  public boolean isUnconditionalBranch() {
    return operator.isUnconditionalBranch();
  }

  /**
   * Is the instruction a direct intraprocedural branch?
   * In the HIR and LIR we consider switches to be direct branches,
   * because their targets are known precisely.
   *
   * @return <code>true</code> if the instruction is a direct
   *         intraprocedural branch or <code>false</code> if it is not.
   */
  public boolean isDirectBranch() {
    return operator.isDirectBranch();
  }

  /**
   * Is the instruction an indirect intraprocedural branch?
   *
   * @return <code>true</code> if the instruction is an indirect
   *         interprocedural branch or <code>false</code> if it is not.
   */
  public boolean isIndirectBranch() {
    return operator.isIndirectBranch();
  }

  /**
   * Is the instruction a call (one kind of interprocedural branch)?
   *
   * @return <code>true</code> if the instruction is a call
   *         or <code>false</code> if it is not.
   */
  public boolean isCall() {
    return operator.isCall();
  }

  /**
   * Is the instruction a pure call (one kind of interprocedural branch)?
   *
   * @return <code>true</code> if the instruction is a pure call
   *         or <code>false</code> if it is not.
   */
  public boolean isPureCall() {
    if (operator.isCall()) {
      MethodOperand methOp = Call.getMethod(this);
      // DIFC: we DON'T include methods without side effects, since these method are called
      // in order to do optimizations to methods that can be evaluated once
      // (which doesn't apply to DIFC instrumentation)
      if (methOp != null && methOp.hasPreciseTarget() && methOp.getTarget().isPure()) {
        return true;
      }
    }
    return false;
  }

  /**
   * Is the instruction a call but not a pure call (one kind of interprocedural branch)?
   *
   * @return <code>true</code> if the instruction is a nonpure call
   *         or <code>false</code> if it is not.
   */
  public boolean isNonPureCall() {
    if (operator.isCall()) {
      MethodOperand methOp = Call.getMethod(this);
      // DIFC: also for methods without side effects
      boolean isPure = methOp != null && methOp.hasPreciseTarget() && (methOp.getTarget().isPure() || methOp.getTarget().hasNoSideEffects());
      return !isPure;
    }
    return false;
  }

  /**
   * Is the instruction a conditional call?
   * We only allow conditional calls in the MIR, since they
   * tend to only be directly implementable on some architecutres.
   *
   * @return <code>true</code> if the instruction is a
   *         conditional call or <code>false</code> if it is not.
   */
  public boolean isConditionalCall() {
    return operator.isConditionalCall();
  }

  /**
   * Is the instruction an unconditional call?
   * Really only an interesting question in the MIR, since
   * it is by definition true for all HIR and LIR calls.
   *
   * @return <code>true</code> if the instruction is an unconditional
   *         call or <code>false</code> if it is not.
   */
  public boolean isUnconditionalCall() {
    return operator.isUnconditionalCall();
  }

  /**
   * Is the instruction a direct call?
   * Only interesting on the MIR.  In the HIR and LIR we pretend that
   * all calls are "direct" even though most of them aren't.
   *
   * @return <code>true</code> if the instruction is a direct call
   *         or <code>false</code> if it is not.
   */
  public boolean isDirectCalll() {
    return operator.isDirectCall();
  }

  /**
   * Is the instruction an indirect call?
   * Only interesting on the MIR.  In the HIR and LIR we pretend that
   * all calls are "direct" even though most of them aren't.
   *
   * @return <code>true</code> if the instruction is an indirect call
   *         or <code>false</code> if it is not.
   */
  public boolean isIndirectCall() {
    return operator.isIndirectCall();
  }

  /**
   * Is the instruction an explicit load of a finite set of values from
   * a finite set of memory locations (load, load multiple, _not_ call)?
   *
   * @return <code>true</code> if the instruction is an explicit load
   *         or <code>false</code> if it is not.
   */
  public boolean isExplicitLoad() {
    return operator.isExplicitLoad();
  }

  /**
   * Should the instruction be treated as a load from some unknown location(s)
   * for the purposes of scheduling and/or modeling the memory subsystem?
   *
   * @return <code>true</code> if the instruction is an implicit load
   *         or <code>false</code> if it is not.
   */
  public boolean isImplicitLoad() {
    return operator.isImplicitLoad();
  }

  /**
   * Is the instruction an explicit store of a finite set of values to
   * a finite set of memory locations (store, store multiple, _not_ call)?
   *
   * @return <code>true</code> if the instruction is an explicit store
   *         or <code>false</code> if it is not.
   */
  public boolean isExplicitStore() {
    return operator.isExplicitStore();
  }

  /**
   * Should the instruction be treated as a store to some unknown location(s)
   * for the purposes of scheduling and/or modeling the memory subsystem?
   *
   * @return <code>true</code> if the instruction is an implicit store
   *         or <code>false</code> if it is not.
   */
  public boolean isImplicitStore() {
    return operator.isImplicitStore();
  }

  /**
   * Is the instruction a throw of a Java exception?
   *
   * @return <code>true</code> if the instruction is a throw
   *         or <code>false</code> if it is not.
   */
  public boolean isThrow() {
    return operator.isThrow();
  }

  /**
   * Is the instruction a PEI (Potentially Excepting Instruction)?
   *
   * @return <code>true</code> if the instruction is a PEI
   *         or <code>false</code> if it is not.
   */
  public boolean isPEI() {
    // The operator level default may be overriden by instr specific info.
    if ((operatorInfo & OI_PEI_VALID) != 0) {
      return (operatorInfo & OI_PEI) != 0;
    } else {
      return operator.isPEI();
    }
  }

  /**
   * Has the instruction been explictly marked as a a PEI (Potentially Excepting Instruction)?
   *
   * @return <code>true</code> if the instruction is explicitly marked as a PEI
   *         or <code>false</code> if it is not.
   */
  public boolean isMarkedAsPEI() {
    if ((operatorInfo & OI_PEI_VALID) != 0) {
      return (operatorInfo & OI_PEI) != 0;
    } else {
      return false;
    }
  }

  /**
   * Is the instruction a potential GC point?
   *
   * @return <code>true</code> if the instruction is a potential
   *         GC point or <code>false</code> if it is not.
   */
  public boolean isGCPoint() {
    // The operator level default may be overridden by instr specific info.
    if ((operatorInfo & OI_GC_VALID) != 0) {
      return (operatorInfo & OI_GC) != 0;
    } else {
      return operator.isGCPoint();
    }
  }

  /**
   * Is the instruction a potential thread switch point?
   *
   * @return <code>true</code> if the instruction is a potential
   *         thread switch point or <code>false</code> if it is not.
   */
  public boolean isTSPoint() {
    // Currently the same as asking if the instruction is a GCPoint, but
    // give it a separate name for documentation & future flexibility
    return isGCPoint();
  }

  /**
   * Is the instruction a compare (val,val) => condition?
   *
   * @return <code>true</code> if the instruction is a compare
   *         or <code>false</code> if it is not.
   */
  public boolean isCompare() {
    return operator.isCompare();
  }

  /**
   * Is the instruction an actual memory allocation instruction
   * (NEW, NEWARRAY, etc)?
   *
   * @return <code>true</code> if the instruction is an allocation
   *         or <code>false</code> if it is not.
   */
  public boolean isAllocation() {
    return operator.isAllocation();
  }

  /**
   * Is the instruction a return (interprocedural branch)?
   *
   * @return <code>true</code> if the instruction is a return
   *         or <code>false</code> if it is not.
   */
  public boolean isReturn() {
    return operator.isReturn();
  }

  /**
   * Is the instruction an acquire (monitorenter/lock)?
   *
   * @return <code>true</code> if the instruction is an acquire
   *         or <code>false</code> if it is not.
   */
  public boolean isAcquire() {
    return operator.isAcquire();
  }

  /**
   * Is the instruction a release (monitorexit/unlock)?
   *
   * @return <code>true</code> if the instruction is a release
   *         or <code>false</code> if it is not.
   */
  public boolean isRelease() {
    return operator.isRelease();
  }

  /**
   * Could the instruction either directly or indirectly
   * cause dynamic class loading?
   *
   * @return <code>true</code> if the instruction is a dynamic linking point
   *         or <code>false</code> if it is not.
   */
  public boolean isDynamicLinkingPoint() {
    return operator.isDynamicLinkingPoint();
  }

  /**
   * Is the instruction a yield point?
   *
   * @return <code>true</code> if the instruction is a yield point
   *          or <code>false</code> if it is not.
   */
  public boolean isYieldPoint() {
    return operator.isYieldPoint();
  }

  /**
   * Record that this instruction is not a PEI.
   * Leave GCPoint status (if any) unchanged.
   */
  public void markAsNonPEI() {
    operatorInfo &= ~OI_PEI;
    operatorInfo |= OI_PEI_VALID;
  }

  /**
   * NOTE: ONLY FOR USE ON MIR INSTRUCTIONS!!!!
   * Record that this instruction is a PEI.
   * Note that marking as a PEI implies marking as GCpoint.
   */
  public void markAsPEI() {
    if (VM.VerifyAssertions) VM._assert(getOpcode() > MIR_START_opcode);
    operatorInfo |= (OI_PEI_VALID | OI_PEI | OI_GC_VALID | OI_GC);
  }

  /**
   * NOTE: ONLY FOR USE ON MIR INSTRUCTIONS!!!!
   * Record that this instruction does not represent a potential GC point.
   * Leave exception state (if any) unchanged.
   */
  public void markAsNonGCPoint() {
    if (VM.VerifyAssertions) VM._assert(getOpcode() > MIR_START_opcode);
    operatorInfo &= ~OI_GC;
    operatorInfo |= OI_GC_VALID;
  }

  /**
   * NOTE: ONLY FOR USE ON MIR INSTRUCTIONS!!!!
   * Record that this instruction is a potential GC point.
   * Leave PEI status (if any) unchanged.
   */
  public void markAsGCPoint() {
    if (VM.VerifyAssertions) VM._assert(getOpcode() > MIR_START_opcode);
    operatorInfo |= (OI_GC_VALID | OI_GC);
  }

  /**
   * NOTE: ONLY FOR USE ON MIR INSTRUCTIONS!!!!
   * Mark this instruction as being neither an exception or GC point.
   */
  public void markAsNonPEINonGCPoint() {
    if (VM.VerifyAssertions) VM._assert(getOpcode() > MIR_START_opcode);
    operatorInfo &= ~(OI_PEI | OI_GC);
    operatorInfo |= (OI_PEI_VALID | OI_GC_VALID);
  }

  /**
   * Is the first mark bit of the instruction set?
   *
   * @return <code>true</code> if the first mark bit is set
   *         or <code>false</code> if it is not.
   */
  boolean isMarked1() {
    return (operatorInfo & MARK1) != 0;
  }

  /**
   * Is the second mark bit of the instruction set?
   *
   * @return <code>true</code> if the first mark bit is set
   *         or <code>false</code> if it is not.
   */
  boolean isMarked2() {
    return (operatorInfo & MARK2) != 0;
  }

  /**
   * Set the first mark bit of the instruction.
   */
  void setMark1() {
    operatorInfo |= MARK1;
  }

  /**
   * Set the second mark bit of the instruction.
   */
  void setMark2() {
    operatorInfo |= MARK2;
  }

  /**
   * Clear the first mark bit of the instruction.
   */
  void clearMark1() {
    operatorInfo &= ~MARK1;
  }

  /**
   * Clear the second mark bit of the instruction.
   */
  void clearMark2() {
    operatorInfo &= ~MARK2;
  }

  /**
   * Return the probability (in the range 0.0 - 1.0) that this two-way
   * branch instruction is taken (as opposed to falling through).
   *
   * @return The probability that the branch is taken.
   */
  public float getBranchProbability() {
    if (VM.VerifyAssertions) VM._assert(isTwoWayBranch());
    return BranchProfileCarrier.getBranchProfile(this).takenProbability;
  }

  /**
   * Record the probability (in the range 0.0 - 1.0) that this two-way
   * branch instruction is taken (as opposed to falling through).
   *
   * @param takenProbability    The probability that the branch is taken.
   */
  public void setBranchProbability(float takenProbability) {
    if (VM.VerifyAssertions) VM._assert(isTwoWayBranch());
    BranchProfileCarrier.getBranchProfile(this).takenProbability = takenProbability;
  }

  /**
   * Invert the probabilty of this branch being taken.  This method
   * should be called on a branch instruction when its condition is
   * reversed using flipCode().
   */
  public void flipBranchProbability() {
    if (VM.VerifyAssertions) VM._assert(isTwoWayBranch());
    setBranchProbability(1.0f - getBranchProbability());
  }

  /**
   * Returns the basic block jumped to by this BRANCH instruction.
   * TODO: Not all types of branches supported yet.
   *
   * @return the target of this branch instruction
   */
  public BasicBlock getBranchTarget() {
    switch (getOpcode()) {
      case GOTO_opcode:
        return Goto.getTarget(this).target.getBasicBlock();

      case INT_IFCMP_opcode:
      case REF_IFCMP_opcode:
      case LONG_IFCMP_opcode:
      case FLOAT_IFCMP_opcode:
      case DOUBLE_IFCMP_opcode:
        return IfCmp.getTarget(this).target.getBasicBlock();

      case IG_CLASS_TEST_opcode:
      case IG_METHOD_TEST_opcode:
      case IG_PATCH_POINT_opcode:
        return InlineGuard.getTarget(this).target.getBasicBlock();

      default:
        if (MIR_Branch.conforms(this)) {
          return MIR_Branch.getTarget(this).target.getBasicBlock();
        } else if (MIR_CondBranch.conforms(this)) {
          return MIR_CondBranch.getTarget(this).target.getBasicBlock();
        } else {
          throw new OptimizingCompilerException("getBranchTarget()",
                                                    "operator not implemented",
                                                    operator.toString());
        }

    }
  }

  /**
   * Return an enumeration of the basic blocks that are targets of this
   * branch instruction.
   *
   * @return the targets of this branch instruction
   */
  public BasicBlockEnumeration getBranchTargets() {
    int n = getNumberOfOperands();
    BasicBlock.ComputedBBEnum e = new BasicBlock.ComputedBBEnum(n);

    switch (getOpcode()) {
      case GOTO_opcode: {
        BranchOperand tgt = Goto.getTarget(this);
        e.addElement(tgt.target.getBasicBlock());
      }
      break;

      case INT_IFCMP2_opcode:
        e.addElement(IfCmp2.getTarget1(this).target.getBasicBlock());
        e.addPossiblyDuplicateElement(IfCmp2.getTarget2(this).target.getBasicBlock());
        break;

      case INT_IFCMP_opcode:
      case REF_IFCMP_opcode:
      case LONG_IFCMP_opcode:
      case FLOAT_IFCMP_opcode:
      case DOUBLE_IFCMP_opcode:
        e.addElement(IfCmp.getTarget(this).target.getBasicBlock());
        break;

      case IG_PATCH_POINT_opcode:
      case IG_CLASS_TEST_opcode:
      case IG_METHOD_TEST_opcode:
        e.addElement(InlineGuard.getTarget(this).target.getBasicBlock());
        break;

      case TABLESWITCH_opcode:
        e.addElement(TableSwitch.getDefault(this).target.getBasicBlock());
        for (int i = 0; i < TableSwitch.getNumberOfTargets(this); i++) {
          e.addPossiblyDuplicateElement(TableSwitch.getTarget(this, i).target.getBasicBlock());
        }
        break;

      case LOWTABLESWITCH_opcode:
        for (int i = 0; i < LowTableSwitch.getNumberOfTargets(this); i++) {
          e.addPossiblyDuplicateElement(LowTableSwitch.getTarget(this, i).target.getBasicBlock());
        }
        break;

      case LOOKUPSWITCH_opcode:
        e.addElement(LookupSwitch.getDefault(this).target.getBasicBlock());
        for (int i = 0; i < LookupSwitch.getNumberOfTargets(this); i++) {
          e.addPossiblyDuplicateElement(LookupSwitch.getTarget(this, i).target.getBasicBlock());
        }
        break;

      default:
        if (MIR_Branch.conforms(this)) {
          e.addElement(MIR_Branch.getTarget(this).target.getBasicBlock());
        } else if (MIR_CondBranch.conforms(this)) {
          e.addElement(MIR_CondBranch.getTarget(this).target.getBasicBlock());
        } else if (MIR_CondBranch2.conforms(this)) {
          e.addElement(MIR_CondBranch2.getTarget1(this).target.getBasicBlock());
          e.addPossiblyDuplicateElement(MIR_CondBranch2.getTarget2(this).target.getBasicBlock());
        } else if (VM.BuildForIA32 && MIR_LowTableSwitch.conforms(this)) {
          for (int i = 0; i < MIR_LowTableSwitch.getNumberOfTargets(this); i++) {
            e.addPossiblyDuplicateElement(MIR_LowTableSwitch.getTarget(this, i).
                target.getBasicBlock());
          }
        } else if (MIR_CondBranch2.conforms(this)) {
          throw new OptimizingCompilerException("getBranchTargets()",
                                                    "operator not implemented",
                                                    operator().toString());
        } else {
          throw new OptimizingCompilerException("getBranchTargets()",
                                                    "operator not implemented",
                                                    operator().toString());
        }
    }

    return e;
  }

  /**
   * Return true if this instruction is the first instruction in a
   * basic block.  By convention (construction) every basic block starts
   * with a label instruction and a label instruction only appears at
   * the start of a basic block
   *
   * @return <code>true</code> if the instruction is the first instruction
   *         in its basic block or <code>false</code> if it is not.
   */
  public boolean isBbFirst() {
    return operator == LABEL;
  }

  /**
   * Return true if this instruction is the last instruction in a
   * basic block.  By convention (construction) every basic block ends
   * with a BBEND instruction and a BBEND instruction only appears at the
   * end of a basic block
   *
   * @return <code>true</code> if the instruction is the last instruction
   *         in its basic block or <code>false</code> if it is not.
   */
  public boolean isBbLast() {
    return operator == BBEND;
  }

  /**
   * Mainly intended for assertion checking;  returns true if the instruction
   * is expected to appear on the "inside" of a basic block, false otherwise.
   *
   * @return <code>true</code> if the instruction is expected to appear
   *         on the inside (not first or last) of its basic block
   *         or <code>false</code> if it is expected to be a first/last
   *         instruction.
   */
  public boolean isBbInside() {
    return !(operator == LABEL || operator == BBEND);
  }

  /*
  * Primitive Instruction List manipulation routines.
  * All of these operations assume that the IR invariants
  * (mostly well-formedness of the data structures) are true
  * when they are invoked.
  * Effectively, the IR invariants are defined by IR.verify().
  * These primitive functions will locally check their invariants
  * when IR.PARANOID is true.
  * If the precondition is met, then the IR invariants will be true when
  * the operation completes.
  */

  /**
   * Insertion: Insert newInstr immediately after this in the
   * instruction stream.
   * Can't insert after a BBEND instruction, since it must be the last
   * instruction in its basic block.
   *
   * @param newInstr the instruction to insert, must not be in an
   *                 instruction list already.
   */
  public void insertAfter(Instruction newInstr) {
    if (IR.PARANOID) {
      isForwardLinked();
      newInstr.isNotLinked();
      VM._assert(!isBbLast(), "cannot insert after last instruction of block");
    }

    // set position unless someone else has
    if (newInstr.position == null) {
      newInstr.position = position;
      newInstr.bcIndex = bcIndex;
    }

    // Splice newInstr into the doubly linked list of instructions
    Instruction old_next = next;
    next = newInstr;
    newInstr.prev = this;
    newInstr.next = old_next;
    old_next.prev = newInstr;
  }

  /**
   * Insertion: Insert newInstr immediately before this in the
   * instruction stream.
   * Can't insert before a LABEL instruction, since it must be the last
   * instruction in its basic block.
   *
   * @param newInstr the instruction to insert, must not be in
   *                 an instruction list already.
   */
  public void insertBefore(Instruction newInstr) {
    if (IR.PARANOID) {
      isBackwardLinked();
      newInstr.isNotLinked();
      VM._assert(!isBbFirst(), "Cannot insert before first instruction of block");
    }

    // set position unless someone else has
    if (newInstr.position == null) {
      newInstr.position = position;
      newInstr.bcIndex = bcIndex;
    }

    // Splice newInstr into the doubly linked list of instructions
    Instruction old_prev = prev;
    prev = newInstr;
    newInstr.next = this;
    newInstr.prev = old_prev;
    old_prev.next = newInstr;
  }

  /**
   * Replacement: Replace this with newInstr.
   * We could allow replacement of first & last instrs in the basic block,
   * but it would be a fair amount of work to update everything, and probably
   * isn't useful, so we'll simply disallow it for now.
   *
   * @param newInstr  the replacement instruction must not be in an
   *                  instruction list already and must not be a
   *                  LABEL or BBEND instruction.
   */
  public void replace(Instruction newInstr) {
    if (IR.PARANOID) {
      isLinked();
      newInstr.isNotLinked();
      VM._assert(isBbInside(), "Can only replace BbInside instructions");
    }

    Instruction old_prev = prev;
    Instruction old_next = next;

    // Splice newInstr into the doubly linked list of instructions
    newInstr.prev = old_prev;
    old_prev.next = newInstr;
    newInstr.next = old_next;
    old_next.prev = newInstr;
    next = null;
    prev = null;
  }

  /**
   * Removal: Remove this from the instruction stream.
   *
   *  We currently forbid the removal of LABEL instructions to avoid
   *  problems updating branch instructions that reference the label.
   *  We also outlaw removal of BBEND instructions.
   *  <p>
   *  NOTE: We allow the removal of branch instructions, but don't update the
   *  CFG data structure.....right now we just assume the caller knows what
   *  they are doing and takes care of it.
   *  <p>
   *  NB: execution of this method nulls out the prev & next fields of this
   *
   * @return the previous instruction in the instruction stream
   */
  public Instruction remove() {
    if (IR.PARANOID) {
      isLinked();
      VM._assert(!isBbFirst() && !isBbLast(), "Removal of first/last instructions in block not supported");
    }

    // Splice this out of instr list
    Instruction Prev = prev, Next = next;
    Prev.next = Next;
    Next.prev = Prev;
    next = null;
    prev = null;
    return Prev;
  }

  /*
   * Helper routines to verify instruction list invariants.
   * Invocations to these functions are guarded by IR.PARANOID and thus
   * the calls to VM.Assert don't need to be guarded by VM.VerifyAssertions.
   */
  private void isLinked() {
    VM._assert(prev.next == this, "is_linked: failure (1)");
    VM._assert(next.prev == this, "is_linked: failure (2)");
  }

  private void isBackwardLinked() {
    VM._assert(prev.next == this, "is_backward_linked: failure (1)");
    // OK if next is null (IR under construction)
    VM._assert(next == null || next.prev == this, "is_backward_linked: failure (2)");
  }

  private void isForwardLinked() {
    // OK if prev is null (IR under construction)
    VM._assert(prev == null || prev.next == this, "is_forward_linked: failure (1)");
    VM._assert(next.prev == this, "is_forward_linked (2)");
  }

  private void isNotLinked() {
    VM._assert(prev == null && next == null, "is_not_linked: failure (1)");
  }

  /*
  * Implementation: Operand enumeration classes
  */
  // Shared functionality
  private abstract static class BASE_OE implements OperandEnumeration {
    protected final Instruction instr;
    protected int i;
    protected final int end;
    protected Operand nextElem;
    protected static final boolean DEBUG = false;

    protected BASE_OE(Instruction instr, int start, int end) {
      this.instr = instr;
      this.i = start - 1;
      this.end = end;
      this.nextElem = null;
    }

    public final boolean hasMoreElements() { return nextElem != null; }

    public final Operand nextElement() { return next(); }

    public final Operand next() {
      Operand temp = nextElem;
      if (temp == null) fail();
      advance();
      if (DEBUG) { System.out.println(" next() returning: " + temp); }
      return temp;
    }

    protected abstract void advance();

    @NoInline
    private static void fail() {
      throw new java.util.NoSuchElementException("OperandEnumerator");
    }
  }

  // enumerate leaf operands in the given ranges
  private static final class OE extends BASE_OE {
    private final int defEnd;
    private Operand deferredMOReg;

    public OE(Instruction instr, int start, int end, int defEnd) {
      super(instr, start, end);
      this.defEnd = defEnd;
      if (DEBUG) {
        System.out.println(" --> OE called with inst\n" +
                           instr +
                           "\n start: " +
                           start +
                           ", end: " +
                           end +
                           ", defEnd: " +
                           defEnd);
      }
      advance();
    }

    protected void advance() {
      if (deferredMOReg != null) {
        nextElem = deferredMOReg;
        deferredMOReg = null;
      } else {
        Operand temp;
        do {
          i++;
          if (i > end) {
            temp = null;
            break;
          }
          temp = instr.getOperand(i);
          if (temp instanceof MemoryOperand) {
            MemoryOperand mo = (MemoryOperand) temp;
            if (mo.base != null) {
              temp = mo.base;
              deferredMOReg = mo.index;
              break;
            } else {
              temp = mo.index;
            }
          } else {
            if (i <= defEnd) {
              // if i is in the defs, ignore non memory operands
              temp = null;
            }
          }
        } while (temp == null);
        nextElem = temp;
      }
    }
  }

  // Enumerate the def operands of an instruction (ignores memory
  // operands, since the contained operands of a MO are uses).
  private static final class OEDefsOnly extends BASE_OE {
    public OEDefsOnly(Instruction instr, int start, int end) {
      super(instr, start, end);
      if (DEBUG) {
        System.out.println(" --> OEDefsOnly called with inst\n" + instr + "\n start: " + start + ", end: " + end);
      }
      advance();
    }

    protected void advance() {
      Operand temp;
      do {
        i++;
        if (i > end) {
          temp = null;
          break;
        }
        temp = instr.getOperand(i);
      } while (temp == null || temp instanceof MemoryOperand);
      nextElem = temp;
      // (i>end and nextElem == null) or nextElem is neither memory nor null
    }
  }

  // Enumerate the memory operands of an instruction
  private static final class MOE extends BASE_OE {
    public MOE(Instruction instr, int start, int end) {
      super(instr, start, end);
      if (DEBUG) {
        System.out.println(" --> MOE called with inst\n" + instr + "\n start: " + start + ", end: " + end);
      }
      advance();
    }

    protected void advance() {
      Operand temp;
      do {
        i++;
        if (i > end) {
          temp = null;
          break;
        }
        temp = instr.getOperand(i);
      } while (!(temp instanceof MemoryOperand));
      nextElem = temp;
      // (i>end and nextElem == null) or nextElem is memory
    }
  }

  // Enumerate the root operands of an instruction
  private static final class ROE extends BASE_OE {
    public ROE(Instruction instr, int start, int end) {
      super(instr, start, end);
      if (DEBUG) {
        System.out.println(" --> ROE called with inst\n" + instr + "\n start: " + start + ", end: " + end);
      }
      advance();
    }

    protected void advance() {
      Operand temp;
      do {
        i++;
        if (i > end) {
          temp = null;
          break;
        }
        temp = instr.getOperand(i);
      } while (temp == null);
      nextElem = temp;
      // (i>end and nextElem == null) or nextElem != null
    }
  }

  /*
  * The following operand functions are really only meant to be
  * used in the classes (such as instruction formats) that
  * collaborate in the low-level implementation of the IR.
  * General clients are strongly discouraged from using them.
  */

  /**
   * NOTE: It is incorrect to use getOperand with a constant argument
   * outside of the automatically generated code in Operators.
   * The only approved direct use of getOperand is in a loop over
   * some subset of an instructions operands (all of them, all uses, all defs).
   *
   * @param i which operand to return
   * @return the ith operand
   */
  public Operand getOperand(int i) {
    return ops[i];
  }

  /**
   * NOTE: It is incorrect to use getClearOperand with a constant argument
   * outside of the automatically generated code in Operators.
   * The only approved direct use of getOperand is in a loop over
   * some subset of an instructions operands (all of them, all uses, all defs).
   *
   * @param i which operand to return
   * @return the ith operand detatching it from the instruction
   */
  public Operand getClearOperand(int i) {
    Operand o = ops[i];
    if (o != null) {
      o.instruction = null;
    }
    ops[i] = null;
    return o;
  }

  /**
   * NOTE: It is incorrect to use putOperand with a constant argument
   * outside of the automatically generated code in Operators.
   * The only approved direct use of getOperand is in a loop over
   * some subset of an instruction's operands (all of them, all uses, all defs).
   *
   * @param i which operand to set
   * @param op the operand to set it to
   */
  public void putOperand(int i, Operand op) {
    if (op == null) {
      ops[i] = null;
    } else {
      // TODO: Replace this silly copying code with an assertion that operands
      //       are not shared between instructions and force people to be
      //       more careful!
      if (op.instruction != null) {
        op = outOfLineCopy(op);
      }
      op.instruction = this;
      ops[i] = op;
      if (op instanceof MemoryOperand) {
        MemoryOperand mOp = op.asMemory();
        op = mOp.loc;
        if (op != null) op.instruction = this;
        op = mOp.guard;
        if (op != null) op.instruction = this;
        op = mOp.base;
        if (op != null) op.instruction = this;
        op = mOp.index;
        if (op != null) op.instruction = this;
      }
    }
  }

  @NoInline
  private Operand outOfLineCopy(Operand op) {
    return op.copy();
  }

  /**
   * Enlarge the number of operands in this instruction, if necessary.
   * Only meant to be used by InstructionFormat classes.
   *
   * @param newSize the new minimum number of operands.
   */
  void resizeNumberOfOperands(int newSize) {
    int oldSize = ops.length;
    if (oldSize != newSize) {
      Operand[] newOps = new Operand[newSize];
      int min = oldSize;
      if (newSize < oldSize) {
        min = newSize;
      }
      for (int i = 0; i < min; i++) {
        newOps[i] = ops[i];
      }
      ops = newOps;
    }
  }

  /**
   * For IR internal use only; general clients should use
   * {@link #nextInstructionInCodeOrder()}.
   *
   * @return the contents of {@link #next}
   */
   public Instruction getNext() {
    return next;
  }

  /**
   * For IR internal use only;   general clients should always use higer level
   * mutation functions.
   * Set the {@link #next} field of the instruction.
   *
   * @param n the new value for next
   */
  void setNext(Instruction n) {
    next = n;
  }

  /**
   * For IR internal use only; General clients should use
   * {@link #prevInstructionInCodeOrder()}.
   *
   * @return the contents of {@link #prev}
   */
  public Instruction getPrev() {
    return prev;
  }

  /**
   * For IR internal use only;   general clients should always use higer level
   * mutation functions.
   * Set the {@link #prev} field of the instruction.
   *
   * @param p the new value for prev
   */
  void setPrev(Instruction p) {
    prev = p;
  }

  /**
   * For IR internal use only;   general clients should always use higer level
   * mutation functions.
   * Clear the {@link #prev} and {@link #next} fields of the instruction.
   */
  void clearLinks() {
    next = null;
    prev = null;
  }

  /**
   * Are two instructions similar, i.e. having the same operator and
   * the same number of similar operands?
   * @param similarInstr instruction to compare against
   * @return true if they are similar
   */
  public boolean similar(Instruction similarInstr) {
    if (similarInstr.operator != operator) {
      return false;
    } else {
      int num_operands = getNumberOfOperands();
      if (similarInstr.getNumberOfOperands() != num_operands) {
        return false;
      } else {
        for (int i = 0; i < num_operands; i++) {
          Operand op1 = getOperand(i);
          Operand op2 = similarInstr.getOperand(i);
          if ((op1 == null) && (op2 == null)) {
            return true;
          }
          if ((op1 == null) || (op2 == null) || !op1.similar(op2)) {
            return false;
          }
        }
        return true;
      }
    }
  }

  /**
   * For IR internal use only;   general clients should always use higer level
   * mutation functions.
   * Link this and other together by setting this's {@link #next} field to
   * point to other and other's {@link #prev} field to point to this.
   *
   * @param other the instruction to link with.
   */
  void linkWithNext(Instruction other) {
    next = other;
    other.prev = this;
  }

  /**
   * Temp kludge for BURS as we bring the ir package on line
   * @deprecated
   */
  @Deprecated
  public void BURS_KLUDGE_linkWithNext(Instruction other) {
    linkWithNext(other);
  }

  /**
   * Might this instruction be a load from a field that is declared
   * to be volatile?
   *
   * @return <code>true</code> if the instruction might be a load
   *         from a volatile field or <code>false</code> if it
   *         cannot be a load from a volatile field
   */
  public boolean mayBeVolatileFieldLoad() {
    if (LocalCSE.isLoadInstruction(this)) {
      return LocationCarrier.getLocation(this).mayBeVolatile();
    }
    return false;
  }
}
