# HG changeset patch # User Thomas Wuerthinger # Date 1379366276 -7200 # Node ID 8505bcff4bdc9f314a0da4b188cfd22ea3d20d73 # Parent 1c5bc8307c763301d4bdd2e1283746d56907a047 New graph duplication mechanism that allows in-place fixing of edges. diff -r 1c5bc8307c76 -r 8505bcff4bdc graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Mon Sep 16 20:37:44 2013 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Mon Sep 16 23:17:56 2013 +0200 @@ -594,6 +594,10 @@ static int count = 0; public Node clone(Graph into) { + return clone(into, true); + } + + Node clone(Graph into, boolean clearInputsAndSuccessors) { NodeClass nodeClass = getNodeClass(); if (nodeClass.valueNumberable() && nodeClass.isLeafNode()) { Node otherNode = into.findNodeInCache(this); @@ -608,8 +612,10 @@ } catch (CloneNotSupportedException e) { throw new GraalInternalError(e).addContext(this); } - nodeClass.clearInputs(newNode); - nodeClass.clearSuccessors(newNode); + if (clearInputsAndSuccessors) { + nodeClass.clearInputs(newNode); + nodeClass.clearSuccessors(newNode); + } newNode.graph = into; newNode.typeCacheNext = null; newNode.id = INITIAL_ID; diff -r 1c5bc8307c76 -r 8505bcff4bdc graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Mon Sep 16 20:37:44 2013 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Mon Sep 16 23:17:56 2013 +0200 @@ -674,6 +674,84 @@ return fieldNames.get(pos.input ? inputOffsets[pos.index] : successorOffsets[pos.index]); } + void updateInputSuccInPlace(Node node, DuplicationReplacement duplicationReplacement) { + int index = 0; + while (index < directInputCount) { + Node input = getNode(node, inputOffsets[index]); + if (input != null) { + Node newInput = duplicationReplacement.replacement(input); + node.updateUsages(null, newInput); + putNode(node, inputOffsets[index], newInput); + } + index++; + } + + if (index < inputOffsets.length) { + updateInputLists(node, duplicationReplacement, index); + } + + index = 0; + while (index < directSuccessorCount) { + Node successor = getNode(node, successorOffsets[index]); + if (successor != null) { + Node newSucc = duplicationReplacement.replacement(successor); + node.updatePredecessor(null, newSucc); + putNode(node, successorOffsets[index], newSucc); + } + index++; + } + + if (index < successorOffsets.length) { + updateSuccLists(node, duplicationReplacement, index); + } + } + + private void updateInputLists(Node node, DuplicationReplacement duplicationReplacement, int startIndex) { + int index = startIndex; + while (index < inputOffsets.length) { + NodeList list = getNodeList(node, inputOffsets[index]); + putNodeList(node, inputOffsets[index], updateInputListCopy(list, node, duplicationReplacement)); + assert list != null : clazz; + index++; + } + } + + private void updateSuccLists(Node node, DuplicationReplacement duplicationReplacement, int startIndex) { + int index = startIndex; + while (index < successorOffsets.length) { + NodeList list = getNodeList(node, successorOffsets[index]); + putNodeList(node, successorOffsets[index], updateSuccListCopy(list, node, duplicationReplacement)); + assert list != null : clazz; + index++; + } + } + + private static NodeInputList updateInputListCopy(NodeList list, Node node, DuplicationReplacement duplicationReplacement) { + int size = list.size(); + NodeInputList result = new NodeInputList<>(node, size); + for (int i = 0; i < list.count(); ++i) { + Node oldNode = list.get(i); + if (oldNode != null) { + Node newNode = duplicationReplacement.replacement(oldNode); + result.set(i, newNode); + } + } + return result; + } + + private static NodeSuccessorList updateSuccListCopy(NodeList list, Node node, DuplicationReplacement duplicationReplacement) { + int size = list.size(); + NodeSuccessorList result = new NodeSuccessorList<>(node, size); + for (int i = 0; i < list.count(); ++i) { + Node oldNode = list.get(i); + if (oldNode != null) { + Node newNode = duplicationReplacement.replacement(oldNode); + result.set(i, newNode); + } + } + return result; + } + public void set(Node node, Position pos, Node x) { long offset = pos.input ? inputOffsets[pos.index] : successorOffsets[pos.index]; if (pos.subIndex == NOT_ITERABLE) { @@ -970,9 +1048,48 @@ return nameTemplate; } - static Map addGraphDuplicate(Graph graph, Iterable nodes, DuplicationReplacement replacements) { - IdentityHashMap newNodes = new IdentityHashMap<>(); - // create node duplicates + static Map addGraphDuplicate(final Graph graph, Iterable nodes, final DuplicationReplacement replacements) { + final IdentityHashMap newNodes = new IdentityHashMap<>(); + createNodeDuplicates(graph, nodes, replacements, newNodes); + + DuplicationReplacement replacementClosure = new DuplicationReplacement() { + + public Node replacement(Node input) { + Node target = newNodes.get(input); + if (target == null) { + Node replacement = input; + if (replacements != null) { + replacement = replacements.replacement(input); + } + if (replacement != input) { + target = replacement; + } else if (input.graph() == graph) { // patch to the outer world + target = input; + } + + } + return target; + } + + }; + + // re-wire inputs + for (Entry entry : newNodes.entrySet()) { + Node oldNode = entry.getKey(); + Node node = entry.getValue(); + NodeClass oldNodeClass = oldNode.getNodeClass(); + NodeClass nodeClass = node.getNodeClass(); + if (oldNodeClass == nodeClass && (replacements == null || replacements.replacement(oldNode) == oldNode)) { + nodeClass.updateInputSuccInPlace(node, replacementClosure); + } else { + transferValuesDifferentNodeClass(graph, replacements, newNodes, oldNode, node, oldNodeClass, nodeClass); + } + } + + return newNodes; + } + + private static void createNodeDuplicates(final Graph graph, Iterable nodes, final DuplicationReplacement replacements, final IdentityHashMap newNodes) { for (Node node : nodes) { if (node != null) { assert !node.isDeleted() : "trying to duplicate deleted node: " + node; @@ -984,58 +1101,55 @@ assert replacement != null; newNodes.put(node, replacement); } else { - Node newNode = node.clone(graph); + Node newNode = node.clone(graph, false); + assert newNode.usages().count() == 0 || newNode.inputs().count() == 0; assert newNode.getClass() == node.getClass(); newNodes.put(node, newNode); } } } - // re-wire inputs - for (Entry entry : newNodes.entrySet()) { - Node oldNode = entry.getKey(); - Node node = entry.getValue(); - NodeClass oldNodeClass = oldNode.getNodeClass(); - NodeClass nodeClass = node.getNodeClass(); - for (NodeClassIterator iter = oldNode.inputs().iterator(); iter.hasNext();) { - Position pos = iter.nextPosition(); - if (!nodeClass.isValid(pos, oldNodeClass)) { - continue; + } + + private static void transferValuesDifferentNodeClass(final Graph graph, final DuplicationReplacement replacements, final IdentityHashMap newNodes, Node oldNode, Node node, + NodeClass oldNodeClass, NodeClass nodeClass) { + for (NodeClassIterator iter = oldNode.inputs().iterator(); iter.hasNext();) { + Position pos = iter.nextPosition(); + if (!nodeClass.isValid(pos, oldNodeClass)) { + continue; + } + Node input = oldNodeClass.get(oldNode, pos); + Node target = newNodes.get(input); + if (target == null) { + Node replacement = input; + if (replacements != null) { + replacement = replacements.replacement(input); } - Node input = oldNodeClass.get(oldNode, pos); - Node target = newNodes.get(input); - if (target == null) { - Node replacement = input; - if (replacements != null) { - replacement = replacements.replacement(input); - } - if (replacement != input) { - assert isAssignable(nodeClass.fieldTypes.get(nodeClass.inputOffsets[pos.index]), replacement); - target = replacement; - } else if (input.graph() == graph) { // patch to the outer world - target = input; - } + if (replacement != input) { + assert isAssignable(nodeClass.fieldTypes.get(nodeClass.inputOffsets[pos.index]), replacement); + target = replacement; + } else if (input.graph() == graph) { // patch to the outer world + target = input; } - nodeClass.set(node, pos, target); } + nodeClass.set(node, pos, target); + } - for (NodeClassIterator iter = oldNode.successors().iterator(); iter.hasNext();) { - Position pos = iter.nextPosition(); - if (!nodeClass.isValid(pos, oldNodeClass)) { - continue; + for (NodeClassIterator iter = oldNode.successors().iterator(); iter.hasNext();) { + Position pos = iter.nextPosition(); + if (!nodeClass.isValid(pos, oldNodeClass)) { + continue; + } + Node succ = oldNodeClass.get(oldNode, pos); + Node target = newNodes.get(succ); + if (target == null) { + Node replacement = replacements.replacement(succ); + if (replacement != succ) { + assert isAssignable(nodeClass.fieldTypes.get(node.getNodeClass().successorOffsets[pos.index]), replacement); + target = replacement; } - Node succ = oldNodeClass.get(oldNode, pos); - Node target = newNodes.get(succ); - if (target == null) { - Node replacement = replacements.replacement(succ); - if (replacement != succ) { - assert isAssignable(nodeClass.fieldTypes.get(node.getNodeClass().successorOffsets[pos.index]), replacement); - target = replacement; - } - } - nodeClass.set(node, pos, target); } + nodeClass.set(node, pos, target); } - return newNodes; } private static boolean isAssignable(Class fieldType, Node replacement) {