/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.compilers.opt; import java.util.Enumeration; import java.util.HashMap; import org.jikesrvm.VM; 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.OPT_BasicBlock; import org.jikesrvm.compilers.opt.ir.OPT_ConditionOperand; import org.jikesrvm.compilers.opt.ir.OPT_ConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_DoubleConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_FloatConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_IR; import org.jikesrvm.compilers.opt.ir.OPT_Instruction; import org.jikesrvm.compilers.opt.ir.OPT_IntConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_LongConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_MethodOperand; import org.jikesrvm.compilers.opt.ir.OPT_ObjectConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_Operand; import org.jikesrvm.compilers.opt.ir.OPT_OperandEnumeration; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IG_PATCH_POINT; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IR_PROLOGUE; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PI; import org.jikesrvm.compilers.opt.ir.OPT_Register; import org.jikesrvm.compilers.opt.ir.OPT_RegisterOperand; import org.jikesrvm.compilers.opt.ir.OPT_TIBConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_TrueGuardOperand; import org.jikesrvm.compilers.opt.ir.OPT_TypeOperand; import org.jikesrvm.compilers.opt.ir.OPT_UnreachableOperand; 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; /** * 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 OPT_ValueGraph { /** * Internal graph structure of the value graph. */ private final OPT_SpaceEffGraph graph; /** * A mapping from name to value graph vertex. */ private final HashMap<Object, OPT_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 */ OPT_ValueGraph(OPT_IR ir) { graph = new OPT_SpaceEffGraph(); nameMap = new HashMap<Object, OPT_ValueGraphVertex>(); // TODO!!: compute register lists incrementally // we need register lists in order to call OPT_Register.getFirstDef() OPT_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<OPT_Instruction> e = ir.forwardInstrEnumerator(); e.hasMoreElements();) { OPT_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<OPT_GraphNode> e = enumerateVertices(); e.hasMoreElements();) { OPT_ValueGraphVertex v = (OPT_ValueGraphVertex) e.nextElement(); if (v.getName() instanceof OPT_Register) { if (v.getLabel() instanceof OPT_Register) { if (v.getName() != v.getLabel()) { OPT_ValueGraphVertex v2 = getVertex(v.getLabel()); if (VM.VerifyAssertions) { if (v2.getName() instanceof OPT_Register && v2.getLabel() instanceof OPT_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<OPT_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 OPT_ValueGraphVertex getVertex(Object name) { if (name instanceof OPT_RegisterOperand) { name = ((OPT_RegisterOperand) name).asRegister().getRegister(); } else if (name instanceof OPT_IntConstantOperand) { name = ((OPT_IntConstantOperand) name).value; } else if (name instanceof OPT_FloatConstantOperand) { name = ((OPT_FloatConstantOperand) name).value; } else if (name instanceof OPT_LongConstantOperand) { name = ((OPT_LongConstantOperand) name).value; } else if (name instanceof OPT_DoubleConstantOperand) { name = ((OPT_DoubleConstantOperand) name).value; } else if (name instanceof OPT_ObjectConstantOperand) { name = ((OPT_ObjectConstantOperand) name).value; } else if (name instanceof OPT_TIBConstantOperand) { name = ((OPT_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<OPT_GraphNode> n = graph.enumerateNodes(); n.hasMoreElements();) { OPT_ValueGraphVertex node = (OPT_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(OPT_IR ir) { for (OPT_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(OPT_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(OPT_Instruction s) { // ignore instructions that define physical registers for (OPT_OperandEnumeration e = s.getDefs(); e.hasMoreElements();) { OPT_Operand current = e.next(); if (current instanceof OPT_RegisterOperand && ((OPT_RegisterOperand) current).getRegister().isPhysical()) return; } OPT_Register result = Move.getResult(s).getRegister(); OPT_ValueGraphVertex v = findOrCreateVertex(result); OPT_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(OPT_Instruction s) { OPT_Register result = GuardedUnary.getResult(s).getRegister(); OPT_ValueGraphVertex v = findOrCreateVertex(result); OPT_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(OPT_Instruction s) { OPT_RegisterOperand result = New.getResult(s); OPT_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(OPT_Instruction s) { OPT_RegisterOperand result = NewArray.getResult(s); OPT_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(OPT_Instruction s) { OPT_Operand value = PutField.getValue(s); if (value.isConstant()) { findOrCreateVertex((OPT_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(OPT_Instruction s) { OPT_Operand value = PutStatic.getValue(s); if (value.isConstant()) { findOrCreateVertex((OPT_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(OPT_Instruction s) { OPT_Operand value = AStore.getValue(s); if (value.isConstant()) { findOrCreateVertex((OPT_ConstantOperand) value); } OPT_Operand index = AStore.getIndex(s); if (index.isConstant()) { findOrCreateVertex((OPT_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(OPT_Instruction s) { OPT_Operand index = ALoad.getIndex(s); if (index.isConstant()) { findOrCreateVertex((OPT_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(OPT_Instruction s) { // label the vertex corresponding to the result with the operator OPT_RegisterOperand result = Unary.getResult(s); OPT_ValueGraphVertex v = findOrCreateVertex(result.getRegister()); v.setLabel(s.operator(), 1); // link node v to the operand it uses OPT_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(OPT_Instruction s) { // label the vertex corresponding to the result with the operator OPT_RegisterOperand result = GuardedUnary.getResult(s); OPT_ValueGraphVertex v = findOrCreateVertex(result.getRegister()); v.setLabel(s.operator(), 1); // link node v to the operand it uses OPT_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(OPT_Instruction s) { // label the vertex corresponding to the result with the operator OPT_RegisterOperand result = NullCheck.getGuardResult(s); OPT_ValueGraphVertex v = findOrCreateVertex(result.getRegister()); v.setLabel(s.operator(), 1); // link node v to the operand it uses OPT_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(OPT_Instruction s) { // label the vertex corresponding to the result with the operator OPT_RegisterOperand result = ZeroCheck.getGuardResult(s); OPT_ValueGraphVertex v = findOrCreateVertex(result.getRegister()); v.setLabel(s.operator(), 1); // link node v to the operand it uses OPT_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(OPT_Instruction s) { // label the vertex corresponding to the result with the operator OPT_RegisterOperand result = Binary.getResult(s); OPT_ValueGraphVertex v = findOrCreateVertex(result.getRegister()); v.setLabel(s.operator(), 2); // link node v to the two operands it uses // first link the first val OPT_Operand val = Binary.getVal1(s); val = bypassMoves(val); link(v, findOrCreateVertex(val), 0); OPT_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(OPT_Instruction s) { // label the vertex corresponding to the result with the operator OPT_RegisterOperand result = GuardedBinary.getResult(s); OPT_ValueGraphVertex v = findOrCreateVertex(result.getRegister()); v.setLabel(s.operator(), 2); // link node v to the two operands it uses // first link the first val OPT_Operand val = GuardedBinary.getVal1(s); val = bypassMoves(val); link(v, findOrCreateVertex(val), 0); OPT_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(OPT_Instruction s) { OPT_ValueGraphVertex v = new OPT_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(OPT_Instruction s) { OPT_ValueGraphVertex v = new OPT_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(OPT_Instruction s) { // the label for a PHI instruction is the basic block // in which it appears OPT_Register result = Phi.getResult(s).asRegister().getRegister(); OPT_ValueGraphVertex v = findOrCreateVertex(result); OPT_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++) { OPT_Operand val = Phi.getValue(s, i); val = bypassMoves(val); OPT_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(OPT_Instruction s) { int numArgs = 0; for (OPT_OperandEnumeration e = s.getDefs(); e.hasMoreElements(); numArgs++) { OPT_Register formal = ((OPT_RegisterOperand) e.next()).getRegister(); OPT_ValueGraphVertex v = findOrCreateVertex(formal); v.setLabel(new OPT_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(OPT_Instruction s) { // do nothing. // TODO: someday, maybe exploit interprocedural information } /** * Find or create an OPT_ValueGraphVertex corresponding to a * given variable. * * @param var The variable * @return A value graph vertex corresponding to this variable */ private OPT_ValueGraphVertex findOrCreateVertex(Object var) { if (var instanceof OPT_Register) { return findOrCreateVertex((OPT_Register) var); } else if (var instanceof OPT_RegisterOperand) { return findOrCreateVertex(((OPT_RegisterOperand) var).getRegister()); } else if (var instanceof OPT_ConstantOperand) { return findOrCreateVertex((OPT_ConstantOperand) var); } else if (var instanceof OPT_TypeOperand) { return findOrCreateVertex((OPT_TypeOperand) var); } else if (var instanceof OPT_MethodOperand) { return findOrCreateVertex((OPT_MethodOperand) var); } else if (var instanceof OPT_ConditionOperand) { return findOrCreateVertex((OPT_ConditionOperand) var); } else { throw new OPT_OptimizingCompilerException("OPT_ValueGraph.findOrCreateVertex: unexpected type " + var.getClass()); } } /** * Find or create an OPT_ValueGraphVertex corresponding to a * given register * * @param r the register * @return a value graph vertex corresponding to this variable */ private OPT_ValueGraphVertex findOrCreateVertex(OPT_Register r) { OPT_ValueGraphVertex v = getVertex(r); if (v == null) { v = new OPT_ValueGraphVertex(r); v.setLabel(r, 0); graph.addGraphNode(v); nameMap.put(r, v); } return v; } /** * Find or create an OPT_ValueGraphVertex corresponding to a * given constant operand * * @param op the constant operand * @return a value graph vertex corresponding to this variable */ private OPT_ValueGraphVertex findOrCreateVertex(OPT_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 OPT_ObjectConstantOperand) { name = op.asObjectConstant().value; } else if (op instanceof OPT_TIBConstantOperand) { name = op.asTIBConstant().value; } else if (op.isNullConstant()) { name = op; } else if (op instanceof OPT_TrueGuardOperand) { name = op; } else if (op instanceof OPT_UnreachableOperand) { name = op; } else { throw new OPT_OptimizingCompilerException("OPT_ValueGraph.findOrCreateVertex: unexpected constant operand: " + op); } OPT_ValueGraphVertex v = getVertex(name); if (v == null) { v = new OPT_ValueGraphVertex(op); v.setLabel(op, 0); graph.addGraphNode(v); nameMap.put(name, v); } return v; } /** * Find or create an OPT_ValueGraphVertex corresponding to a * given type operand * * @param op the operand in question * @return a value graph vertex corresponding to this type */ private OPT_ValueGraphVertex findOrCreateVertex(OPT_TypeOperand op) { Object name = op.getTypeRef(); OPT_ValueGraphVertex v = getVertex(name); if (v == null) { v = new OPT_ValueGraphVertex(op); v.setLabel(op, 0); graph.addGraphNode(v); nameMap.put(name, v); } return v; } /** * Find or create an OPT_ValueGraphVertex corresponding to a * given method operand * * @param op the operand in question * @return a value graph vertex corresponding to this type */ private OPT_ValueGraphVertex findOrCreateVertex(OPT_MethodOperand op) { Object name; if (op.hasTarget()) { name = op.getTarget(); } else { name = op.getMemberRef(); } OPT_ValueGraphVertex v = getVertex(name); if (v == null) { v = new OPT_ValueGraphVertex(op); v.setLabel(op, 0); graph.addGraphNode(v); nameMap.put(name, v); } return v; } /** * Find or create an OPT_ValueGraphVertex corresponding to a * given method operand * * @param op the operand in question * @return a value graph vertex corresponding to this type */ private OPT_ValueGraphVertex findOrCreateVertex(OPT_ConditionOperand op) { Object name = op.value; // kludge. OPT_ValueGraphVertex v = getVertex(name); if (v == null) { v = new OPT_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(OPT_ValueGraphVertex src, OPT_ValueGraphVertex target, int pos) { OPT_ValueGraphEdge e = new OPT_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 OPT_RegisterOperand */ private OPT_Operand bypassMoves(OPT_Operand op) { if (!op.isRegister()) return op; OPT_Register r = op.asRegister().getRegister(); OPT_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; } } }