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

import java.util.Enumeration;
import java.util.HashMap;
import org.jikesrvm.VM;
import org.jikesrvm.compilers.opt.DefUse;
import org.jikesrvm.compilers.opt.OptimizingCompilerException;
import org.jikesrvm.compilers.opt.ir.ALoad;
import org.jikesrvm.compilers.opt.ir.AStore;
import org.jikesrvm.compilers.opt.ir.Attempt;
import org.jikesrvm.compilers.opt.ir.Binary;
import org.jikesrvm.compilers.opt.ir.CacheOp;
import org.jikesrvm.compilers.opt.ir.Call;
import org.jikesrvm.compilers.opt.ir.GuardedBinary;
import org.jikesrvm.compilers.opt.ir.GuardedUnary;
import org.jikesrvm.compilers.opt.ir.IfCmp;
import org.jikesrvm.compilers.opt.ir.InlineGuard;
import org.jikesrvm.compilers.opt.ir.MonitorOp;
import org.jikesrvm.compilers.opt.ir.Move;
import org.jikesrvm.compilers.opt.ir.New;
import org.jikesrvm.compilers.opt.ir.NewArray;
import org.jikesrvm.compilers.opt.ir.NullCheck;
import org.jikesrvm.compilers.opt.ir.BasicBlock;
import org.jikesrvm.compilers.opt.ir.IR;
import org.jikesrvm.compilers.opt.ir.Instruction;
import org.jikesrvm.compilers.opt.ir.OperandEnumeration;
import static org.jikesrvm.compilers.opt.ir.Operators.IG_PATCH_POINT;
import static org.jikesrvm.compilers.opt.ir.Operators.IR_PROLOGUE;
import static org.jikesrvm.compilers.opt.ir.Operators.PI;
import org.jikesrvm.compilers.opt.ir.Register;
import org.jikesrvm.compilers.opt.ir.Phi;
import org.jikesrvm.compilers.opt.ir.Prepare;
import org.jikesrvm.compilers.opt.ir.PutField;
import org.jikesrvm.compilers.opt.ir.PutStatic;
import org.jikesrvm.compilers.opt.ir.Unary;
import org.jikesrvm.compilers.opt.ir.ZeroCheck;
import org.jikesrvm.compilers.opt.ir.operand.ConditionOperand;
import org.jikesrvm.compilers.opt.ir.operand.ConstantOperand;
import org.jikesrvm.compilers.opt.ir.operand.DoubleConstantOperand;
import org.jikesrvm.compilers.opt.ir.operand.FloatConstantOperand;
import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand;
import org.jikesrvm.compilers.opt.ir.operand.LongConstantOperand;
import org.jikesrvm.compilers.opt.ir.operand.MethodOperand;
import org.jikesrvm.compilers.opt.ir.operand.ObjectConstantOperand;
import org.jikesrvm.compilers.opt.ir.operand.Operand;
import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
import org.jikesrvm.compilers.opt.ir.operand.TIBConstantOperand;
import org.jikesrvm.compilers.opt.ir.operand.TrueGuardOperand;
import org.jikesrvm.compilers.opt.ir.operand.TypeOperand;
import org.jikesrvm.compilers.opt.ir.operand.UnreachableOperand;
import org.jikesrvm.compilers.opt.util.GraphNode;
import org.jikesrvm.compilers.opt.util.SpaceEffGraph;

/**
 * This class implements the value graph used in global value numbering
 * a la Alpern, Wegman and Zadeck.  See Muchnick p.348 for a nice
 * discussion.
 *
 * From Muchnick, "the <em>value graph</em> of a procedure is a
 * labeled directed graph whose nodes are labeled with operators,
 * function symbols, or constants, and whose edges represent
 * generating assignments and point from an operator or function to
 * its operands; the edges are labeled with natural numbers that
 * indicate the operand postion that each operand has with repsect to
 * the given operator or function."
 */
final class ValueGraph {

  /**
   * Internal graph structure of the value graph.
   */
  private final SpaceEffGraph graph;
  /**
   * A mapping from name to value graph vertex.
   */
  private final HashMap<Object, ValueGraphVertex> nameMap;

  /**
   *  Construct a value graph from an IR.
   *
   * <p><b> PRECONDITION:</b> The IR <em> must </em> be in SSA form.
   * @param ir the IR
   */
  ValueGraph(IR ir) {
    graph = new SpaceEffGraph();
    nameMap = new HashMap<Object, ValueGraphVertex>();
    // TODO!!: compute register lists incrementally
    // we need register lists in order to call Register.getFirstDef()
    DefUse.computeDU(ir);
    // add value graph nodes for each symbolic register
    addRegisterNodes(ir);
    // go through the IR and add nodes and edges to the value graph
    // for each instruction, as needed
    for (Enumeration<Instruction> e = ir.forwardInstrEnumerator(); e.hasMoreElements();) {
      Instruction s = e.nextElement();
      processInstruction(s);
    }

    computeClosure();
  }

  /**
   * Due to PI nodes and Moves, the initial label for a register may be
   * another register.  Fix up the value graph for cases where the initial
   * register label was not removed.
   */
  private void computeClosure() {
    for (Enumeration<GraphNode> e = enumerateVertices(); e.hasMoreElements();) {
      ValueGraphVertex v = (ValueGraphVertex) e.nextElement();
      if (v.getName() instanceof Register) {
        if (v.getLabel() instanceof Register) {
          if (v.getName() != v.getLabel()) {
            ValueGraphVertex v2 = getVertex(v.getLabel());
            if (VM.VerifyAssertions) {
              if (v2.getName() instanceof Register &&
                  v2.getLabel() instanceof Register &&
                  v2.getLabel() != v2.getName()) {
                VM._assert(false);
              }
            }
            v.copyVertex(v2);
          }
        }
      }
    }
  }

  /**
   * Enumerate the vertices in the value graph.
   *
   * @return an enumeration of the vertices in the value graph
   */
  public Enumeration<GraphNode> enumerateVertices() {
    return graph.enumerateNodes();
  }

  /**
   * Return the vertex which has a given name.
   *
   * @param name the name of the vertex
   * @return the vertex with the name.  null if none found.
   */
  public ValueGraphVertex getVertex(Object name) {
    if (name instanceof RegisterOperand) {
      name = ((RegisterOperand) name).asRegister().getRegister();
    } else if (name instanceof IntConstantOperand) {
      name = ((IntConstantOperand) name).value;
    } else if (name instanceof FloatConstantOperand) {
      name = ((FloatConstantOperand) name).value;
    } else if (name instanceof LongConstantOperand) {
      name = ((LongConstantOperand) name).value;
    } else if (name instanceof DoubleConstantOperand) {
      name = ((DoubleConstantOperand) name).value;
    } else if (name instanceof ObjectConstantOperand) {
      name = ((ObjectConstantOperand) name).value;
    } else if (name instanceof TIBConstantOperand) {
      name = ((TIBConstantOperand) name).value;
    }
    return nameMap.get(name);
  }

  /**
   * Return a String representation of the value graph.
   *
   * @return a String representation of the value graph.
   */
  public String toString() {
    // print the nodes
    StringBuilder s = new StringBuilder("VALUE GRAPH: \n");
    for (Enumeration<GraphNode> n = graph.enumerateNodes(); n.hasMoreElements();) {
      ValueGraphVertex node = (ValueGraphVertex) n.nextElement();
      s.append(node).append("\n");
    }
    return s.toString();
  }

  /**
   * Add a node to the value graph for every symbolic register.
   *
   * <p><b>PRECONDITION:</b> register lists are computed and valid
   *
   * @param ir the governing IR
   */
  private void addRegisterNodes(IR ir) {
    for (Register reg = ir.regpool.getFirstSymbolicRegister(); reg != null; reg = reg.getNext()) {
      findOrCreateVertex(reg);
    }
  }

  /**
   * Update the value graph to account for a given instruction.
   *
   * @param s the instruction in question
   */
  private void processInstruction(Instruction s) {
    // TODO: support all necessary types of instructions
    if (s.isDynamicLinkingPoint()) {
      processCall(s);
    } else if (Move.conforms(s)) {
      processMove(s);
    } else if (s.operator == PI) {
      processPi(s);
    } else if (New.conforms(s)) {
      processNew(s);
    } else if (NewArray.conforms(s)) {
      processNewArray(s);
    } else if (Unary.conforms(s)) {
      processUnary(s);
    } else if (GuardedUnary.conforms(s)) {
      processGuardedUnary(s);
    } else if (NullCheck.conforms(s)) {
      processNullCheck(s);
    } else if (ZeroCheck.conforms(s)) {
      processZeroCheck(s);
    } else if (Binary.conforms(s)) {
      processBinary(s);
    } else if (GuardedBinary.conforms(s)) {
      processGuardedBinary(s);
    } else if (InlineGuard.conforms(s)) {
      processInlineGuard(s);
    } else if (IfCmp.conforms(s)) {
      processIfCmp(s);
    } else if (Call.conforms(s)) {
      processCall(s);
    } else if (MonitorOp.conforms(s)) {
      processCall(s);
    } else if (Prepare.conforms(s)) {
      processCall(s);
    } else if (Attempt.conforms(s)) {
      processCall(s);
    } else if (CacheOp.conforms(s)) {
      processCall(s);
    } else if (ALoad.conforms(s)) {
      processALoad(s);
    } else if (PutField.conforms(s)) {
      processPutField(s);
    } else if (PutStatic.conforms(s)) {
      processPutStatic(s);
    } else if (AStore.conforms(s)) {
      processAStore(s);
    } else if (Phi.conforms(s)) {
      processPhi(s);
    } else if (s.operator() == IR_PROLOGUE) {
      processPrologue(s);
    }
  }

  /**
   * Update the value graph to account for a given MOVE instruction.
   *
   * <p><b>PRECONDITION:</b> <code> Move.conforms(s); </code>
   *
   * @param s the instruction in question
   */
  private void processMove(Instruction s) {
    // ignore instructions that define physical registers
    for (OperandEnumeration e = s.getDefs(); e.hasMoreElements();) {
      Operand current = e.next();
      if (current instanceof RegisterOperand && ((RegisterOperand) current).getRegister().isPhysical()) return;
    }

    Register result = Move.getResult(s).getRegister();
    ValueGraphVertex v = findOrCreateVertex(result);
    Operand val = Move.getVal(s);
    // bypass Move instructions that define the right-hand side
    val = bypassMoves(val);
    v.copyVertex(findOrCreateVertex(val));
  }

  /**
   * Update the value graph to account for a given PI instruction.
   *
   * <p><b>PRECONDITION:</b> <code> s.operator == PI </code>
   *
   * @param s the instruction in question
   */
  private void processPi(Instruction s) {
    Register result = GuardedUnary.getResult(s).getRegister();
    ValueGraphVertex v = findOrCreateVertex(result);
    Operand val = GuardedUnary.getVal(s);
    // bypass Move instructions that define the right-hand side
    val = bypassMoves(val);
    v.copyVertex(findOrCreateVertex(val));
  }

  /**
   * Update the value graph to account for a given NEW instruction.
   *
   * <p><b>PRECONDITION:</b> <code> New.conforms(s); </code>
   *
   * For a new instruction, we always create a new vertex.
   *
   * @param s the instruction in question
   */
  private void processNew(Instruction s) {
    RegisterOperand result = New.getResult(s);
    ValueGraphVertex v = findOrCreateVertex(result.getRegister());
    // set the label for a NEW instruction to be the instruction itself
    // so that no two NEW results get the same value number
    v.setLabel(s, 0);
  }

  /**
   * Update the value graph to account for a given NEWARRAY instruction.
   *
   * <p><b>PRECONDITION:</b> <code> NewArray.conforms(s); </code>
   *
   * For a newarray instruction, we always create a new vertex.
   *
   * @param s the instruction in question
   */
  private void processNewArray(Instruction s) {
    RegisterOperand result = NewArray.getResult(s);
    ValueGraphVertex v = findOrCreateVertex(result.getRegister());
    // set the label for a NEW instruction to be the instruction itself
    // so that no two NEW results get the same value number
    v.setLabel(s, 0);
  }

  /**
   * Update the value graph to account for a given PUTFIELD instruction.
   *
   * <p><b>PRECONDITION:</b> <code> PutField.conforms(s); </code>
   *
   *  Make sure we have value graph nodes for a constant value
   *
   * @param s the instruction in question
   */
  private void processPutField(Instruction s) {
    Operand value = PutField.getValue(s);
    if (value.isConstant()) {
      findOrCreateVertex((ConstantOperand) value);
    }
  }

  /**
   * Update the value graph to account for a given PUTSTATIC instruction.
   *
   * <p><b>PRECONDITION:</b> <code> PutStatic.conforms(s); </code>
   *
   * Make sure we have value graph nodes for a constant value
   *
   * @param s the instruction in question
   */
  private void processPutStatic(Instruction s) {
    Operand value = PutStatic.getValue(s);
    if (value.isConstant()) {
      findOrCreateVertex((ConstantOperand) value);
    }
  }

  /**
   * Update the value graph to account for a given ASTORE instruction.
   *
   * <p><b>PRECONDITION:</b> <code> AStore.conforms(s); </code>
   *
   * Make sure we have value graph nodes for a constant value
   *
   * @param s the instruction in question
   */
  private void processAStore(Instruction s) {
    Operand value = AStore.getValue(s);
    if (value.isConstant()) {
      findOrCreateVertex((ConstantOperand) value);
    }
    Operand index = AStore.getIndex(s);
    if (index.isConstant()) {
      findOrCreateVertex((ConstantOperand) index);
    }
  }

  /**
   * Update the value graph to account for a given ALOAD instruction.
   *
   * <p><b>PRECONDITION:</b> <code> ALoad.conforms(s); </code>
   *
   * Make sure we have value graph nodes for a constant value
   *
   * @param s the instruction in question
   */
  private void processALoad(Instruction s) {
    Operand index = ALoad.getIndex(s);
    if (index.isConstant()) {
      findOrCreateVertex((ConstantOperand) index);
    }
  }

  /**
   * Update the value graph to account for a given Unary instruction.
   *
   * <p><b>PRECONDITION:</b> <code> Unary.conforms(s); </code>
   *
   * @param s the instruction in question
   */
  private void processUnary(Instruction s) {
    // label the vertex corresponding to the result with the operator
    RegisterOperand result = Unary.getResult(s);
    ValueGraphVertex v = findOrCreateVertex(result.getRegister());
    v.setLabel(s.operator(), 1);
    // link node v to the operand it uses
    Operand val = Unary.getVal(s);
    // bypass Move instructions
    val = bypassMoves(val);
    link(v, findOrCreateVertex(val), 0);
  }

  /**
   * Update the value graph to account for a given GuardedUnary instruction.
   *
   * <p><b>PRECONDITION:</b> <code> GuardedUnary.conforms(s); </code>
   *
   * Careful: we define two Guarded Unaries to be equivalent regardless of
   * whether the guards are equivalent!
   *
   * @param s the instruction in question
   */
  private void processGuardedUnary(Instruction s) {
    // label the vertex corresponding to the result with the operator
    RegisterOperand result = GuardedUnary.getResult(s);
    ValueGraphVertex v = findOrCreateVertex(result.getRegister());
    v.setLabel(s.operator(), 1);
    // link node v to the operand it uses
    Operand val = GuardedUnary.getVal(s);
    // bypass Move instructions
    val = bypassMoves(val);
    link(v, findOrCreateVertex(val), 0);
  }

  /**
   * Update the value graph to account for a given NullCheck instruction.
   *
   * <p><b>PRECONDITION:</b> <code> NullCheck.conforms(s); </code>
   *
   * @param s the instruction in question
   */
  private void processNullCheck(Instruction s) {
    // label the vertex corresponding to the result with the operator
    RegisterOperand result = NullCheck.getGuardResult(s);
    ValueGraphVertex v = findOrCreateVertex(result.getRegister());
    v.setLabel(s.operator(), 1);
    // link node v to the operand it uses
    Operand val = NullCheck.getRef(s);
    // bypass Move instructions
    val = bypassMoves(val);
    link(v, findOrCreateVertex(val), 0);
  }

  /**
   * Update the value graph to account for a given NullCheck instruction.
   *
   * <p><b>PRECONDITION:</b> <code> ZeroCheck.conforms(s); </code>
   *
   * @param s the instruction in question
   */
  private void processZeroCheck(Instruction s) {
    // label the vertex corresponding to the result with the operator
    RegisterOperand result = ZeroCheck.getGuardResult(s);
    ValueGraphVertex v = findOrCreateVertex(result.getRegister());
    v.setLabel(s.operator(), 1);
    // link node v to the operand it uses
    Operand val = ZeroCheck.getValue(s);
    // bypass Move instructions
    val = bypassMoves(val);
    link(v, findOrCreateVertex(val), 0);
  }

  /**
   * Update the value graph to account for a given Binary instruction.
   *
   * <p><b>PRECONDITION:</b> <code> Binary.conforms(s); </code>
   *
   * @param s the instruction in question
   */
  private void processBinary(Instruction s) {
    // label the vertex corresponding to the result with the operator
    RegisterOperand result = Binary.getResult(s);
    ValueGraphVertex v = findOrCreateVertex(result.getRegister());
    v.setLabel(s.operator(), 2);
    // link node v to the two operands it uses
    // first link the first val
    Operand val = Binary.getVal1(s);
    val = bypassMoves(val);
    link(v, findOrCreateVertex(val), 0);
    Operand val2 = Binary.getVal2(s);
    val2 = bypassMoves(val2);
    link(v, findOrCreateVertex(val2), 1);
  }

  /**
   * Update the value graph to account for a given GuardedBinary instruction.
   *
   * <p><b>PRECONDITION:</b> <code> GuardedBinary.conforms(s); </code>
   *
   * Careful: we define two Guarded Binaries to be equivalent regardless of
   * whether the guards are equivalent!
   *
   * @param s the instruction in question
   */
  private void processGuardedBinary(Instruction s) {
    // label the vertex corresponding to the result with the operator
    RegisterOperand result = GuardedBinary.getResult(s);
    ValueGraphVertex v = findOrCreateVertex(result.getRegister());
    v.setLabel(s.operator(), 2);
    // link node v to the two operands it uses
    // first link the first val
    Operand val = GuardedBinary.getVal1(s);
    val = bypassMoves(val);
    link(v, findOrCreateVertex(val), 0);
    Operand val2 = GuardedBinary.getVal2(s);
    val2 = bypassMoves(val2);
    link(v, findOrCreateVertex(val2), 1);
  }

  /**
   * Update the value graph to account for a given InlineGuard instruction.
   *
   * <p><b>PRECONDITION:</b> <code> InlineGuard.conforms(s); </code>
   *
   * @param s the instruction in question
   */
  private void processInlineGuard(Instruction s) {
    ValueGraphVertex v = new ValueGraphVertex(s);
    graph.addGraphNode(v);
    nameMap.put(s, v);
    if (s.operator() == IG_PATCH_POINT) {
      // the 'goal' is irrelevant for patch_point guards.
      v.setLabel(s.operator(), 1);
      link(v, findOrCreateVertex(bypassMoves(InlineGuard.getValue(s))), 0);
    } else {
      v.setLabel(s.operator(), 2);
      link(v, findOrCreateVertex(bypassMoves(InlineGuard.getValue(s))), 0);
      link(v, findOrCreateVertex(InlineGuard.getGoal(s)), 1);
    }
  }

  /**
   * Update the value graph to account for a given IfCmp instruction.
   *
   * <p><b>PRECONDITION:</b> <code> IfCmp.conforms(s); </code>
   *
   * @param s the instruction in question
   */
  private void processIfCmp(Instruction s) {
    ValueGraphVertex v = new ValueGraphVertex(s);
    graph.addGraphNode(v);
    nameMap.put(s, v);
    v.setLabel(s.operator(), 3);
    link(v, findOrCreateVertex(bypassMoves(IfCmp.getVal1(s))), 0);
    link(v, findOrCreateVertex(bypassMoves(IfCmp.getVal2(s))), 1);
    link(v, findOrCreateVertex(IfCmp.getCond(s)), 2);
  }

  /**
   * Update the value graph to account for a given Phi instruction.
   *
   * <p><b>PRECONDITION:</b> <code> Phi.conforms(s); </code>
   *
   * @param s the instruction in question
   */
  private void processPhi(Instruction s) {
    // the label for a PHI instruction is the basic block
    // in which it appears
    Register result = Phi.getResult(s).asRegister().getRegister();
    ValueGraphVertex v = findOrCreateVertex(result);
    BasicBlock bb = s.getBasicBlock();
    v.setLabel(bb, bb.getNumberOfIn());
    // link node v to all operands it uses
    for (int i = 0; i < Phi.getNumberOfValues(s); i++) {
      Operand val = Phi.getValue(s, i);
      val = bypassMoves(val);
      ValueGraphVertex target = findOrCreateVertex(val);
      link(v, target, i);
    }
  }

  /**
   * Update the value graph to account for an IR_PROLOGUE instruction
   *
   * <p><b>PRECONDITION:</b> <code> Prologue.conforms(s); </code>
   *
   * @param s the instruction in question
   */
  private void processPrologue(Instruction s) {
    int numArgs = 0;
    for (OperandEnumeration e = s.getDefs(); e.hasMoreElements(); numArgs++) {
      Register formal = ((RegisterOperand) e.next()).getRegister();
      ValueGraphVertex v = findOrCreateVertex(formal);
      v.setLabel(new ValueGraphParamLabel(numArgs), 0);
    }
  }

  /**
   * Update the value graph to account for a given Call instruction.
   *
   * <p><b>PRECONDITION:</b> <code> Call.conforms(s); </code>
   *
   * @param s the instruction in question
   */
  private void processCall(Instruction s) {
    // do nothing.
    // TODO: someday, maybe exploit interprocedural information
  }

  /**
   * Find or create an ValueGraphVertex corresponding to a
   * given variable.
   *
   * @param var   The variable
   * @return A value graph vertex corresponding to this variable
   */
  private ValueGraphVertex findOrCreateVertex(Object var) {
    if (var instanceof Register) {
      return findOrCreateVertex((Register) var);
    } else if (var instanceof RegisterOperand) {
      return findOrCreateVertex(((RegisterOperand) var).getRegister());
    } else if (var instanceof ConstantOperand) {
      return findOrCreateVertex((ConstantOperand) var);
    } else if (var instanceof TypeOperand) {
      return findOrCreateVertex((TypeOperand) var);
    } else if (var instanceof MethodOperand) {
      return findOrCreateVertex((MethodOperand) var);
    } else if (var instanceof ConditionOperand) {
      return findOrCreateVertex((ConditionOperand) var);
    } else {
      throw new OptimizingCompilerException("ValueGraph.findOrCreateVertex: unexpected type " + var.getClass());
    }
  }

  /**
   * Find or create an ValueGraphVertex corresponding to a
   * given register
   *
   * @param r the register
   * @return a value graph vertex corresponding to this variable
   */
  private ValueGraphVertex findOrCreateVertex(Register r) {
    ValueGraphVertex v = getVertex(r);
    if (v == null) {
      v = new ValueGraphVertex(r);
      v.setLabel(r, 0);
      graph.addGraphNode(v);
      nameMap.put(r, v);
    }
    return v;
  }

  /**
   * Find or create an ValueGraphVertex corresponding to a
   * given constant operand
   *
   * @param op the constant operand
   * @return a value graph vertex corresponding to this variable
   */
  private ValueGraphVertex findOrCreateVertex(ConstantOperand op) {
    Object name;
    if (op.isAddressConstant()) {
      name = (VM.BuildFor32Addr) ? op.asAddressConstant().value.toInt() : op.asAddressConstant().value.toLong();
    } else if (op.isIntConstant()) {
      name = op.asIntConstant().value;
    } else if (op.isFloatConstant()) {
      name = op.asFloatConstant().value;
    } else if (op.isLongConstant()) {
      name = op.asLongConstant().value;
    } else if (op.isDoubleConstant()) {
      name = op.asDoubleConstant().value;
    } else if (op instanceof ObjectConstantOperand) {
      name = op.asObjectConstant().value;
    } else if (op instanceof TIBConstantOperand) {
      name = op.asTIBConstant().value;
    } else if (op.isNullConstant()) {
      name = op;
    } else if (op instanceof TrueGuardOperand) {
      name = op;
    } else if (op instanceof UnreachableOperand) {
      name = op;
    } else {
      throw new OptimizingCompilerException("ValueGraph.findOrCreateVertex: unexpected constant operand: " +
                                                op);
    }
    ValueGraphVertex v = getVertex(name);
    if (v == null) {
      v = new ValueGraphVertex(op);
      v.setLabel(op, 0);
      graph.addGraphNode(v);
      nameMap.put(name, v);
    }
    return v;
  }

  /**
   * Find or create an ValueGraphVertex corresponding to a
   * given type operand
   *
   * @param op the operand in question
   * @return a value graph vertex corresponding to this type
   */
  private ValueGraphVertex findOrCreateVertex(TypeOperand op) {
    Object name = op.getTypeRef();
    ValueGraphVertex v = getVertex(name);
    if (v == null) {
      v = new ValueGraphVertex(op);
      v.setLabel(op, 0);
      graph.addGraphNode(v);
      nameMap.put(name, v);
    }
    return v;
  }

  /**
   * Find or create an ValueGraphVertex corresponding to a
   * given method operand
   *
   * @param op the operand in question
   * @return a value graph vertex corresponding to this type
   */
  private ValueGraphVertex findOrCreateVertex(MethodOperand op) {
    Object name;
    if (op.hasTarget()) {
      name = op.getTarget();
    } else {
      name = op.getMemberRef();
    }
    ValueGraphVertex v = getVertex(name);
    if (v == null) {
      v = new ValueGraphVertex(op);
      v.setLabel(op, 0);
      graph.addGraphNode(v);
      nameMap.put(name, v);
    }
    return v;
  }

  /**
   * Find or create an ValueGraphVertex corresponding to a
   * given method operand
   *
   * @param op the operand in question
   * @return a value graph vertex corresponding to this type
   */
  private ValueGraphVertex findOrCreateVertex(ConditionOperand op) {
    Object name = op.value; // kludge.
    ValueGraphVertex v = getVertex(name);
    if (v == null) {
      v = new ValueGraphVertex(op);
      v.setLabel(op, 0);
      graph.addGraphNode(v);
      nameMap.put(name, v);
    }
    return v;
  }

  /**
   * Link two vertices in the value graph
   *
   * @param src the def
   * @param target the use
   * @param pos the position of target in the set of uses
   */
  private void link(ValueGraphVertex src, ValueGraphVertex target, int pos) {
    ValueGraphEdge e = new ValueGraphEdge(src, target);
    src.addTarget(target, pos);
    graph.addGraphEdge(e);
  }

  /**
   * Bypass MOVE instructions that def an operand: return the first def
   * in the chain that is not the result of a MOVE instruction.
   *
   * Note: treat PI instructions like MOVES
   *
   * @param op the RegisterOperand
   */
  private Operand bypassMoves(Operand op) {
    if (!op.isRegister()) return op;
    Register r = op.asRegister().getRegister();
    Instruction def = r.getFirstDef();
    if (def == null) {
      return op;
    }
    if (r.isPhysical()) {
      return op;
    }
    if (Move.conforms(def)) {
      //   In a perfect world, this shouldn't happen. Copy propagation
      //   in SSA form should remove all 'normal' moves.
      //   We can't simply bypass this move, since it may lead to
      //   infinite mutual recursion.
      return op;
    } else if (def.operator == PI) {
      return bypassMoves(GuardedUnary.getVal(def));
    } else {
      return op;
    }
  }
}
