/** * 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); }
void mergeClasses(ValueGraphVertex v1, ValueGraphVertex v2) { if (DEBUG) { System.out.println("@@@@ mergeClasses called with v1 = " + v1 + " ; v2 = " + v2); } int val1 = v1.getValueNumber(); int val2 = v2.getValueNumber(); if (val1 == val2) return; GVCongruenceClass class1 = B.get(val1); while (true) { GVCongruenceClass class2 = B.get(val2); Iterator<ValueGraphVertex> i = class2.iterator(); if (!i.hasNext()) break; ValueGraphVertex v = i.next(); if (DEBUG) { System.out.println("@@@@ moving vertex " + v + " from class " + val2 + " to class " + val1); } class1.addVertex(v); class2.removeVertex(v); v.setValueNumber(val1); } // Null out entry for val2 B.set(val2, null); }
/** * Return the (integer) value number for a given variable * * @param name name of the variable to look up * @return its value number */ int getValueNumber(Object name) { ValueGraphVertex v = valueGraph.getVertex(name); if (v == null) { return UNKNOWN; } return v.getValueNumber(); }
/** * 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 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 (Enumeration<Operand> e = s.getDefs(); e.hasMoreElements(); numArgs++) { Register formal = ((RegisterOperand) e.nextElement()).getRegister(); ValueGraphVertex v = findOrCreateVertex(formal); v.setLabel(new ValueGraphParamLabel(numArgs), 0); } }
/** Print the value numbers for each node in the value graph. */ void printValueNumbers() { for (Enumeration<GraphNode> e = valueGraph.enumerateVertices(); e.hasMoreElements(); ) { ValueGraphVertex v = (ValueGraphVertex) e.nextElement(); int valueNumber = v.getValueNumber(); GVCongruenceClass c = B.get(valueNumber); System.out.println(v.getName() + " " + valueNumber + " " + c.getLabel()); } }
/** * 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); }
/** * 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 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(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; }
/** * 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); }
/** * Assuming congruence class c has changed: find all other classes that might be affected, and add * them to the worklist * * @param c the congruence class that has changed */ private void addDependentClassesToWorklist(GVCongruenceClass c) { // for each element of this congruence class: for (ValueGraphVertex v : c) { // for each vertex which points to v in the value graph for (Enumeration<GraphNode> e = v.inNodes(); e.hasMoreElements(); ) { ValueGraphVertex in = (ValueGraphVertex) e.nextElement(); int vn = in.getValueNumber(); GVCongruenceClass x = B.get(vn); workList.push(x); } } }
/** * Initialize the congruence classes, assuming that all nodes with the same label are congruent. */ private void initialize() { // store a map from label -> congruenceClass HashMap<Object, GVCongruenceClass> labelMap = new HashMap<Object, GVCongruenceClass>(10); for (Enumeration<GraphNode> e = valueGraph.enumerateVertices(); e.hasMoreElements(); ) { ValueGraphVertex v = (ValueGraphVertex) e.nextElement(); Object label = v.getLabel(); GVCongruenceClass c = findOrCreateCongruenceClass(label, labelMap); // add this node to the congruence class c.addVertex(v); // set the value number for the node v.setValueNumber(c.getValueNumber()); } }
/** * Partition a congruence class. * * @param partition the class to partition */ private void partitionClass(GVCongruenceClass partition) { // store a reference to the first node in c, which will serve // as a representative for this class Iterator<ValueGraphVertex> i = partition.iterator(); ValueGraphVertex first = i.next(); ArrayList<GVCongruenceClass> newClasses = new ArrayList<GVCongruenceClass>(); // now check each other node in c, to see if it matches the // representative ArrayList<ValueGraphVertex> toRemove = new ArrayList<ValueGraphVertex>(); while (i.hasNext()) { ValueGraphVertex v = i.next(); if (!checkCongruence(first, v)) { // NOT CONGRUENT!! split the partition. first check if // v fits in any other newly created congruence classes int index = findCongruenceMatch(newClasses, v); if (index > -1) { // MATCH FOUND!! place v in newClasses[index] GVCongruenceClass match = B.get(index); match.addVertex(v); v.setValueNumber(match.getValueNumber()); } else { // NO MATCH FOUND!! create a new congruence class // find the appropriate label for the new congruence class // and create a new congruence class with this label GVCongruenceClass c = createCongruenceClass(v); newClasses.add(c); c.addVertex(v); v.setValueNumber(c.getValueNumber()); } // mark v as to be removed from partition // (Can't remove it yet while iterating over the set); toRemove.add(v); } } // remove necessary vertices for (ValueGraphVertex v : toRemove) { partition.removeVertex(v); } // if needed place the original partition back on the work list if ((!newClasses.isEmpty()) && (partition.size() > 1)) { workList.push(partition); } // place any new congruence classes with size > 1 on the worklist // also place any classes which might indirectly be affected for (GVCongruenceClass c : newClasses) { if (c.size() > 1) { workList.push(c); } addDependentClassesToWorklist(c); } }
/** * 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 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 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 (Enumeration<Operand> e = s.getDefs(); e.hasMoreElements(); ) { Operand current = e.nextElement(); 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 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); } }
/** * 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; }
/** * Transform to eliminate redundant branches passed on GVNs and dominator information. * * @param ir The IR on which to apply the phase */ public void perform(IR ir) { // (1) Remove redundant conditional branches and locally fix the PHIs GlobalValueNumberState gvns = ir.HIRInfo.valueNumbers; DominatorTree dt = ir.HIRInfo.dominatorTree; for (BasicBlockEnumeration bbs = ir.getBasicBlocks(); bbs.hasMoreElements(); ) { BasicBlock candBB = bbs.next(); Instruction candTest = candBB.firstBranchInstruction(); if (candTest == null) continue; if (!(IfCmp.conforms(candTest) || InlineGuard.conforms(candTest))) continue; GVCongruenceClass cc = gvns.congruenceClass(candTest); if (cc.size() > 1) { for (ValueGraphVertex vertex : cc) { Instruction poss = (Instruction) vertex.getName(); if (poss != candTest) { BasicBlock notTaken = getNotTakenBlock(poss); BasicBlock taken = poss.getBranchTarget(); if (taken == notTaken) continue; // both go to same block, so we don't know anything! if (notTaken.hasOneIn() && dt.dominates(notTaken, candBB)) { if (DEBUG) VM.sysWrite(candTest + " is dominated by not-taken branch of " + poss + "\n"); removeCondBranch(candBB, candTest, ir, poss); cc.removeVertex(gvns.valueGraph.getVertex(candTest)); break; } if (taken.hasOneIn() && dt.dominates(taken, candBB)) { if (DEBUG) VM.sysWrite(candTest + " is dominated by taken branch of " + poss + "\n"); takeCondBranch(candBB, candTest, ir); cc.removeVertex(gvns.valueGraph.getVertex(candTest)); break; } } } } } // (2) perform a Depth-first search of the control flow graph, // and remove any nodes we have made unreachable removeUnreachableCode(ir); }
/** * 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; }
/** * Does the current state of the algorithm optimistically assume that two nodes are congruent? * Note: this can return false even if the value numbers are currently the same. * * @param v1 first vertex * @param v2 second vertex * @return whether the notes are assumed to be congruent */ private boolean checkCongruence(ValueGraphVertex v1, ValueGraphVertex v2) { if (v1 == v2) { return true; } // make sure the two nodes have the same label if (v1.getLabel() != v2.getLabel()) { return false; } // make sure that the operands match int arity = v1.getArity(); for (int i = 0; i < arity; i++) { ValueGraphVertex target1 = v1.getTarget(i); ValueGraphVertex target2 = v2.getTarget(i); // if either target is null, then that particular control // flow path is never realized, so assume TOP if ((target1 == null) || (target2 == null)) { continue; } if (target1.getValueNumber() != target2.getValueNumber()) { return false; } } return true; }
/** * Definitely-different relation. Returns true for the following cases: * * <ul> * <li>name1 and name2 are both constants, but don't match * <li>name1 and name2 both result from NEW statements, but don't match * <li>one of name1 and name2 is a parameter, and the other results from a new statement * </ul> * * <p>TODO: add more smarts * * @param name1 name of first object to compare * @param name2 name of second object to compare * @return true iff the value numbers for two variables are definitely different */ boolean DD(Object name1, Object name2) { ValueGraphVertex v1 = valueGraph.getVertex(name1); ValueGraphVertex v2 = valueGraph.getVertex(name2); return DD(v1.getValueNumber(), v2.getValueNumber()); }
/** * 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); }
/** * 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(VM.NOT_REACHED); } } v.copyVertex(v2); } } } } }
/** * Definitely-same relation. * * @param name1 first variable * @param name2 second variable * @return true iff the value numbers for two variables are equal */ boolean DS(Object name1, Object name2) { ValueGraphVertex v1 = valueGraph.getVertex(name1); ValueGraphVertex v2 = valueGraph.getVertex(name2); return v1.getValueNumber() == v2.getValueNumber(); }
GVCongruenceClass congruenceClass(Object name) { ValueGraphVertex v = valueGraph.getVertex(name); return B.get(v.getValueNumber()); }