/* * 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 org.jikesrvm.ArchitectureSpecific.OPT_PhysicalDefUse; import static org.jikesrvm.compilers.opt.OPT_DepGraphConstants.CONTROL; import static org.jikesrvm.compilers.opt.OPT_DepGraphConstants.EXCEPTION_E; import static org.jikesrvm.compilers.opt.OPT_DepGraphConstants.EXCEPTION_MS; import static org.jikesrvm.compilers.opt.OPT_DepGraphConstants.EXCEPTION_R; import static org.jikesrvm.compilers.opt.OPT_DepGraphConstants.GUARD_ANTI; import static org.jikesrvm.compilers.opt.OPT_DepGraphConstants.GUARD_OUTPUT; import static org.jikesrvm.compilers.opt.OPT_DepGraphConstants.GUARD_TRUE; import static org.jikesrvm.compilers.opt.OPT_DepGraphConstants.MEM_ANTI; import static org.jikesrvm.compilers.opt.OPT_DepGraphConstants.MEM_OUTPUT; import static org.jikesrvm.compilers.opt.OPT_DepGraphConstants.MEM_READS_KILL; import static org.jikesrvm.compilers.opt.OPT_DepGraphConstants.MEM_TRUE; import static org.jikesrvm.compilers.opt.OPT_DepGraphConstants.REG_ANTI; import static org.jikesrvm.compilers.opt.OPT_DepGraphConstants.REG_MAY_DEF; import static org.jikesrvm.compilers.opt.OPT_DepGraphConstants.REG_OUTPUT; import static org.jikesrvm.compilers.opt.OPT_DepGraphConstants.REG_TRUE; import org.jikesrvm.compilers.opt.ir.LocationCarrier; import org.jikesrvm.compilers.opt.ir.OPT_BasicBlock; import org.jikesrvm.compilers.opt.ir.OPT_BasicBlockEnumeration; import org.jikesrvm.compilers.opt.ir.OPT_ExceptionHandlerBasicBlock; import org.jikesrvm.compilers.opt.ir.OPT_IR; import org.jikesrvm.compilers.opt.ir.OPT_Instruction; import org.jikesrvm.compilers.opt.ir.OPT_LocationOperand; import org.jikesrvm.compilers.opt.ir.OPT_Operand; import org.jikesrvm.compilers.opt.ir.OPT_OperandEnumeration; import org.jikesrvm.compilers.opt.ir.OPT_Operator; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_CAUGHT_EXCEPTION; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_TIME_BASE; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IR_PROLOGUE; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.SET_CAUGHT_EXCEPTION; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.UNINT_BEGIN; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.UNINT_END; import org.jikesrvm.compilers.opt.ir.OPT_Register; import org.jikesrvm.compilers.opt.ir.OPT_RegisterOperand; /** * Dependence Graph for a single basic block in the program. * * <p> June 1998 extensions by Vivek Sarkar: * <ul> * <li> 1. Fix direction of register anti dependences * <li> 2. Add conservative memory dependences (suitable for low opt level) * </ul> * * <p>Jul 1998, Harini Srinivasan: * made node list doubly linked list. Changes reflected in * depgraph construction. No calls to getDepGraphNode(). * * <p> Dec 1998-March 1999, Mauricio Serrano: * several modifications to the memory efficiency of the graph. * added edges for calls. * * <p> 2000-2001, Dave Grove: * <ul> * <li> add support to handle implicit def/uses of physical registers correctly * <li> large scale refactor and cleanup * <li> more precise treatment of exceptions, control and acquire/release * </ul> */ final class OPT_DepGraph extends OPT_SpaceEffGraph { /** * Set of variables that are live on entry to at least one catch block that * is reachable via a PEI in currentBlock. * This is an approximatation of the more precise set, but can be done in * linear time; doing the most precise thing (computing the set for * every PEI and using each individual set to create the necessary * dependences) is quadratic, and probably doesn't help very much anyways. */ private final OPT_LiveSet handlerLiveSet; /** * The basic block we are processing */ private final OPT_BasicBlock currentBlock; /** * The ir we are processing */ private final OPT_IR ir; /** * Constructor (computes the dependence graph!). * * @param ir the IR to compute the dependence graph for * @param start instruction to start computation from * @param end instruction to end computation at * @param currentBlock the basic block that the instructions are living in */ OPT_DepGraph(OPT_IR ir, OPT_Instruction start, OPT_Instruction end, OPT_BasicBlock currentBlock) { this.currentBlock = currentBlock; this.ir = ir; handlerLiveSet = new OPT_LiveSet(); computeHandlerLiveSet(); createNodes(start, end); computeForwardDependences(start, end); computeBackwardDependences(start, end); computeControlAndBarrierDependences(start, end); } /** * Determine the set of variables live on entry to any handler * block that is reachable from currentBlock */ private void computeHandlerLiveSet() { if (ir.getHandlerLivenessComputed() && currentBlock.hasExceptionHandlers()) { OPT_BasicBlockEnumeration e = currentBlock.getExceptionalOut(); while (e.hasMoreElements()) { OPT_ExceptionHandlerBasicBlock handlerBlock = (OPT_ExceptionHandlerBasicBlock) e.next(); handlerLiveSet.add(handlerBlock.getLiveSet()); } } } /** * Create the dependency graph nodes for instructions start to end */ private void createNodes(OPT_Instruction start, OPT_Instruction end) { for (OPT_Instruction p = start; ; p = p.nextInstructionInCodeOrder()) { OPT_DepGraphNode pnode = new OPT_DepGraphNode(p); addGraphNode(pnode); if (p == end) { break; } } } /** * Compute flow and output dependences by doing a forward * traversal of the instructions from start to end. */ private void computeForwardDependences(OPT_Instruction start, OPT_Instruction end) { boolean readsKill = ir.options.READS_KILL; OPT_DepGraphNode lastStoreNode = null; OPT_DepGraphNode lastExceptionNode = null; OPT_DepGraphNode lastLoadNode = null; // only used if reads kill clearRegisters(start, end); for (OPT_DepGraphNode pnode = (OPT_DepGraphNode) firstNode(); pnode != null; pnode = (OPT_DepGraphNode) pnode.getNext()) { OPT_Instruction p = pnode.instruction(); // (1) Add edges due to registers int useMask = p.operator().implicitUses; int defMask = p.operator().implicitDefs; if (p.isTSPoint()) { useMask |= OPT_PhysicalDefUse.maskTSPUses; defMask |= OPT_PhysicalDefUse.maskTSPDefs; } for (OPT_OperandEnumeration uses = p.getUses(); uses.hasMoreElements();) { computeForwardDependencesUse(uses.next(), pnode, lastExceptionNode); } for (OPT_PhysicalDefUse.PDUEnumeration uses = OPT_PhysicalDefUse.enumerate(useMask, ir); uses.hasMoreElements();) { OPT_Register r = uses.nextElement(); computeImplicitForwardDependencesUse(r, pnode); } for (OPT_OperandEnumeration defs = p.getDefs(); defs.hasMoreElements();) { computeForwardDependencesDef(defs.next(), pnode, lastExceptionNode); } for (OPT_PhysicalDefUse.PDUEnumeration defs = OPT_PhysicalDefUse.enumerate(defMask, ir); defs.hasMoreElements();) { OPT_Register r = defs.nextElement(); computeImplicitForwardDependencesDef(r, pnode); } // (2) Add edges due to memory boolean isStore = p.isImplicitStore(); boolean isLoad = p.isImplicitLoad(); if (isStore || isLoad) { // If readsKill then add memory model memory dependence from prior load // NOTE: In general alias relationships are not transitive and therefore // we cannot exit this loop early. if (readsKill && isLoad) { for (OPT_DepGraphNode lnode = lastLoadNode; lnode != null; lnode = (OPT_DepGraphNode) lnode.getPrev()) { if (lnode.instruction().isImplicitLoad() && OPT_LocationOperand.mayBeAliased(getLocation(p), getLocation(lnode.instruction()))) { lnode.insertOutEdge(pnode, MEM_READS_KILL); } } lastLoadNode = pnode; } // Add output/flow memory dependence from prior potentially aliased stores. // NOTE: In general alias relationships are not transitive and therefore // we cannot exit this loop early. for (OPT_DepGraphNode snode = lastStoreNode; snode != null; snode = (OPT_DepGraphNode) snode.getPrev()) { if (snode.instruction().isImplicitStore() && OPT_LocationOperand.mayBeAliased(getLocation(p), getLocation(snode.instruction()))) { snode.insertOutEdge(pnode, isStore ? MEM_OUTPUT : MEM_TRUE); } } if (isStore) { lastStoreNode = pnode; if (lastExceptionNode != null) { lastExceptionNode.insertOutEdge(pnode, EXCEPTION_MS); } } } // (3) Add edges due to exception state/exceptional control flow. if (p.isPEI()) { if (lastExceptionNode != null) { lastExceptionNode.insertOutEdge(pnode, EXCEPTION_E); } lastExceptionNode = pnode; } } } /** * Compute anti dependences by doing a backwards * traversal of the instructions from start to end. */ private void computeBackwardDependences(OPT_Instruction start, OPT_Instruction end) { clearRegisters(start, end); OPT_DepGraphNode lastStoreNode = null; OPT_DepGraphNode lastExceptionNode = null; for (OPT_DepGraphNode pnode = (OPT_DepGraphNode) lastNode(); pnode != null; pnode = (OPT_DepGraphNode) pnode.getPrev()) { OPT_Instruction p = pnode.instruction(); // (1) Add edges due to registers int useMask = p.operator().implicitUses; int defMask = p.operator().implicitDefs; if (p.isTSPoint()) { useMask |= OPT_PhysicalDefUse.maskTSPUses; defMask |= OPT_PhysicalDefUse.maskTSPDefs; } for (OPT_OperandEnumeration uses = p.getUses(); uses.hasMoreElements();) { computeBackwardDependencesUse(uses.next(), pnode, lastExceptionNode); } for (OPT_PhysicalDefUse.PDUEnumeration uses = OPT_PhysicalDefUse.enumerate(useMask, ir); uses.hasMoreElements();) { OPT_Register r = uses.nextElement(); computeImplicitBackwardDependencesUse(r, pnode); } for (OPT_OperandEnumeration defs = p.getDefs(); defs.hasMoreElements();) { computeBackwardDependencesDef(defs.next(), pnode, lastExceptionNode); } for (OPT_PhysicalDefUse.PDUEnumeration defs = OPT_PhysicalDefUse.enumerate(defMask, ir); defs.hasMoreElements();) { OPT_Register r = defs.nextElement(); computeImplicitBackwardDependencesDef(r, pnode); } // (2) Add edges due to memory boolean isStore = p.isImplicitStore(); boolean isLoad = p.isImplicitLoad(); if (isStore) { if (lastExceptionNode != null) { pnode.insertOutEdge(lastExceptionNode, EXCEPTION_MS); } lastStoreNode = pnode; } else if (isLoad) { // NOTE: In general alias relationships are not transitive and therefore // we cannot exit this loop early. for (OPT_DepGraphNode snode = lastStoreNode; snode != null; snode = (OPT_DepGraphNode) snode.getNext()) { if (snode.instruction().isImplicitStore() && OPT_LocationOperand.mayBeAliased(getLocation(p), getLocation(snode.instruction()))) { pnode.insertOutEdge(snode, MEM_ANTI); } } } if (p.isPEI()) { lastExceptionNode = pnode; } } } /** * Compute control and barrier (acquire/release) dependences * in two passes (one forward, one reverse over the instructions * from start to end. */ private void computeControlAndBarrierDependences(OPT_Instruction start, OPT_Instruction end) { // (1) In a forward pass, we add the following dependences: // a) No load instruction may rise above an acquire // b) No instruction may rise above an UNINT_BEGIN (conservative), // a yieldpoint (we placed the yieldpoints where we wanted them), // a GET_CAUGHT_EXCEPTION, or an IR_PROLOGUE. // c) No GC point may rise above an UNINT_END OPT_DepGraphNode lastTotalBarrier = null; OPT_DepGraphNode lastGCBarrier = null; OPT_DepGraphNode lastAcquire = null; for (OPT_DepGraphNode pnode = (OPT_DepGraphNode) firstNode(); pnode != null; pnode = (OPT_DepGraphNode) pnode.getNext()) { OPT_Instruction p = pnode.instruction(); if (lastTotalBarrier != null) { lastTotalBarrier.insertOutEdge(pnode, CONTROL); } if (lastGCBarrier != null) { lastGCBarrier.insertOutEdge(pnode, CONTROL); } if (lastAcquire != null && p.isImplicitLoad()) { lastAcquire.insertOutEdge(pnode, CONTROL); } OPT_Operator pop = p.operator(); if (p.isYieldPoint() || pop == IR_PROLOGUE || pop == UNINT_BEGIN || pop == GET_TIME_BASE || pop == GET_CAUGHT_EXCEPTION) { lastTotalBarrier = pnode; } if (pop == UNINT_END) { lastGCBarrier = pnode; } if (p.isAcquire() || p.isDynamicLinkingPoint()) { lastAcquire = pnode; } } // (2) In a backward pass we add the following dependences: // a) No store instruction may sink below a release. // b) No instruction may sink below an UNINT_END (conservative), // a branch/return, a SET_CAUGHT_EXCEPTION, or a yieldpoint // (again want to pin yieldpoints). // c) No GC point may sink below an UNINT_BEGIN lastTotalBarrier = null; lastGCBarrier = null; OPT_DepGraphNode lastRelease = null; for (OPT_DepGraphNode pnode = (OPT_DepGraphNode) lastNode(); pnode != null; pnode = (OPT_DepGraphNode) pnode.getPrev()) { OPT_Instruction p = pnode.instruction(); if (lastTotalBarrier != null) { pnode.insertOutEdge(lastTotalBarrier, CONTROL); } if (lastGCBarrier != null) { pnode.insertOutEdge(lastGCBarrier, CONTROL); } if (lastRelease != null && p.isImplicitStore()) { pnode.insertOutEdge(lastRelease, CONTROL); } OPT_Operator pop = p.operator(); if (p.isBranch() || p.isReturn() || p.isYieldPoint() || pop == UNINT_END || pop == GET_TIME_BASE || pop == SET_CAUGHT_EXCEPTION) { lastTotalBarrier = pnode; } if (pop == UNINT_BEGIN) { lastGCBarrier = pnode; } if (p.isRelease() || p.isDynamicLinkingPoint()) { lastRelease = pnode; } } } /** * Compute forward dependences from a given use to a given node. * @param op source operand * @param destNode destination node * @param lastExceptionNode node representing the last PEI */ private void computeForwardDependencesUse(OPT_Operand op, OPT_DepGraphNode destNode, OPT_DepGraphNode lastExceptionNode) { if (!(op instanceof OPT_RegisterOperand)) return; OPT_RegisterOperand regOp = (OPT_RegisterOperand) op; OPT_DepGraphNode sourceNode = regOp.getRegister().dNode(); // if there is an element in the regTableDef[regNum] slot, set // the flow dependence edge. if (sourceNode != null) { if (regOp.getRegister().isValidation()) { sourceNode.insertOutEdge(destNode, GUARD_TRUE); } else { for (OPT_PhysicalDefUse.PDUEnumeration e = OPT_PhysicalDefUse.enumerate(OPT_PhysicalDefUse.maskTSPDefs, ir); e.hasMoreElements();) { OPT_Register r = e.nextElement(); if (regOp.getRegister() == r) { sourceNode.insertOutEdge(destNode, REG_MAY_DEF); return; } } sourceNode.insertRegTrueOutEdge(destNode, regOp); } } } /** * Compute forward dependences from a given def to a given node. * @param op source operand * @param destNode destination node * @param lastExceptionNode node representing the last PEI */ private void computeForwardDependencesDef(OPT_Operand op, OPT_DepGraphNode destNode, OPT_DepGraphNode lastExceptionNode) { if (!(op instanceof OPT_RegisterOperand)) return; OPT_RegisterOperand regOp = (OPT_RegisterOperand) op; OPT_DepGraphNode sourceNode = regOp.getRegister().dNode(); if (sourceNode != null) { // create output dependence edge from sourceNode to destNode. int type = regOp.getRegister().isValidation() ? GUARD_OUTPUT : REG_OUTPUT; sourceNode.insertOutEdge(destNode, type); // pin the def below the previous exception node if the register // being defined may be live in some reachable catch block if (lastExceptionNode != null && regOp.getRegister().spansBasicBlock() && currentBlock.hasExceptionHandlers()) { if (!ir.getHandlerLivenessComputed() || handlerLiveSet.contains(regOp.getRegister())) { lastExceptionNode.insertOutEdge(destNode, EXCEPTION_R); } } } // update depGraphNode information in register. regOp.getRegister().setdNode(destNode); } /** * Compute backward dependences from a given use to a given node. * @param op source operand * @param destNode destination node * @param lastExceptionNode node representing the last PEI */ private void computeBackwardDependencesUse(OPT_Operand op, OPT_DepGraphNode destNode, OPT_DepGraphNode lastExceptionNode) { if (!(op instanceof OPT_RegisterOperand)) return; OPT_RegisterOperand regOp = (OPT_RegisterOperand) op; OPT_DepGraphNode sourceNode = regOp.getRegister().dNode(); if (sourceNode != null) { int type = regOp.getRegister().isValidation() ? GUARD_ANTI : REG_ANTI; // create antidependence edge. // NOTE: sourceNode contains the def and destNode contains the use. destNode.insertOutEdge(sourceNode, type); } } /** * Compute backward dependences from a given def to a given node. * @param op source operand * @param destNode destination node * @param lastExceptionNode node representing the last PEI */ private void computeBackwardDependencesDef(OPT_Operand op, OPT_DepGraphNode destNode, OPT_DepGraphNode lastExceptionNode) { if (!(op instanceof OPT_RegisterOperand)) return; OPT_RegisterOperand regOp = (OPT_RegisterOperand) op; // pin the def above the next exception node if the register // being defined may be live in some reachable catch block if (lastExceptionNode != null && regOp.getRegister().spansBasicBlock() && currentBlock.hasExceptionHandlers()) { if (!ir.getHandlerLivenessComputed() || handlerLiveSet.contains(regOp.getRegister())) { destNode.insertOutEdge(lastExceptionNode, EXCEPTION_R); } } regOp.getRegister().setdNode(destNode); } /** * Compute implicit forward dependences from a given register use * to a given node. * @param r source register * @param destNode destination node */ private void computeImplicitForwardDependencesUse(OPT_Register r, OPT_DepGraphNode destNode) { OPT_DepGraphNode sourceNode = r.dNode(); if (sourceNode != null) { for (OPT_PhysicalDefUse.PDUEnumeration e = OPT_PhysicalDefUse.enumerate(OPT_PhysicalDefUse.maskTSPDefs, ir); e.hasMoreElements();) { OPT_Register r2 = e.nextElement(); if (r == r2) { sourceNode.insertOutEdge(destNode, REG_MAY_DEF); return; } } sourceNode.insertOutEdge(destNode, REG_TRUE); } } /** * Compute implicit forward dependences from a given register def * to a given node. * @param r source register * @param destNode destination node */ private void computeImplicitForwardDependencesDef(OPT_Register r, OPT_DepGraphNode destNode) { OPT_DepGraphNode sourceNode = r.dNode(); if (sourceNode != null) { sourceNode.insertOutEdge(destNode, REG_OUTPUT); } r.setdNode(destNode); } /** * Compute implicit backward dependences from a given register use * to a given node. * @param r source register * @param destNode destination node */ private void computeImplicitBackwardDependencesUse(OPT_Register r, OPT_DepGraphNode destNode) { OPT_DepGraphNode sourceNode = r.dNode(); if (sourceNode != null) { // create antidependence edge. // NOTE: sourceNode contains the def and destNode contains the use. destNode.insertOutEdge(sourceNode, REG_ANTI); } } /** * Compute implicit backward dependences from a given register def * to a given node. * @param r source register * @param destNode destination node */ private void computeImplicitBackwardDependencesDef(OPT_Register r, OPT_DepGraphNode destNode) { r.setdNode(destNode); } /** * Get the location of a given load or store instruction. * @param s the instruction to get the location from. */ private OPT_LocationOperand getLocation(OPT_Instruction s) { // This extra conforms check wouldn't be necessary if the DepGraph // code was distinguishing between explict load/stores which have // locations and implicit load/stores which don't. return LocationCarrier.conforms(s) ? LocationCarrier.getLocation(s) : null; } /** * Initialize (clear) the dNode field in OPT_Register for all registers * in this basic block by setting them to null. * Handles both explicit and implict use/defs. * @param start the first opt instruction in the region * @param end the last opt instruction in the region */ private void clearRegisters(OPT_Instruction start, OPT_Instruction end) { for (OPT_Instruction p = start; ; p = p.nextInstructionInCodeOrder()) { for (OPT_OperandEnumeration ops = p.getOperands(); ops.hasMoreElements();) { OPT_Operand op = ops.next(); if (op instanceof OPT_RegisterOperand) { OPT_RegisterOperand rOp = (OPT_RegisterOperand) op; rOp.getRegister().setdNode(null); } } if (p == end) break; } for (OPT_PhysicalDefUse.PDUEnumeration e = OPT_PhysicalDefUse.enumerateAllImplicitDefUses(ir); e.hasMoreElements();) { OPT_Register r = e.nextElement(); r.setdNode(null); } } /** * Print the dependence graph to standard out. */ public void printDepGraph() { System.out.println(toString()); System.out.println("-----------------------------------"); } /** * Returns a VCG descriptor for the graph which will provide VCG-relevant * information for the graph. * @return graph descriptor * @see OPT_VCGGraph#getVCGDescriptor */ public OPT_VCGGraph.GraphDesc getVCGDescriptor() { return new GraphDesc() { public String getTitle() { return "Dependence Graph"; } }; } }