use of org.graalvm.compiler.nodes.AbstractMergeNode in project graal by oracle.
the class InliningUtil method fixFrameStates.
private static void fixFrameStates(StructuredGraph graph, MergeNode originalMerge, PhiNode returnPhi) {
// It is possible that some of the frame states that came from AFTER_BCI reference a Phi
// node that was created to merge multiple returns. This can create cycles
// (see GR-3949 and GR-3957).
// To detect this, we follow the control paths starting from the merge node,
// split the Phi node inputs at merges and assign the proper input to each frame state.
NodeMap<Node> seen = new NodeMap<>(graph);
ArrayDeque<Node> workList = new ArrayDeque<>();
ArrayDeque<ValueNode> valueList = new ArrayDeque<>();
workList.push(originalMerge);
valueList.push(returnPhi);
while (!workList.isEmpty()) {
Node current = workList.pop();
ValueNode currentValue = valueList.pop();
if (seen.containsKey(current)) {
continue;
}
seen.put(current, current);
if (current instanceof StateSplit && current != originalMerge) {
StateSplit stateSplit = (StateSplit) current;
FrameState state = stateSplit.stateAfter();
if (state != null && state.values().contains(returnPhi)) {
int index = 0;
FrameState duplicate = state.duplicate();
for (ValueNode value : state.values()) {
if (value == returnPhi) {
duplicate.values().set(index, currentValue);
}
index++;
}
stateSplit.setStateAfter(duplicate);
GraphUtil.tryKillUnused(state);
}
}
if (current instanceof AbstractMergeNode) {
AbstractMergeNode currentMerge = (AbstractMergeNode) current;
for (EndNode pred : currentMerge.cfgPredecessors()) {
ValueNode newValue = currentValue;
if (currentMerge.isPhiAtMerge(currentValue)) {
PhiNode currentPhi = (PhiNode) currentValue;
newValue = currentPhi.valueAt(pred);
}
workList.push(pred);
valueList.push(newValue);
}
} else if (current.predecessor() != null) {
workList.push(current.predecessor());
valueList.push(currentValue);
}
}
}
use of org.graalvm.compiler.nodes.AbstractMergeNode in project graal by oracle.
the class MultiTypeGuardInlineInfo method inlineMultipleMethods.
private EconomicSet<Node> inlineMultipleMethods(StructuredGraph graph, Providers providers) {
int numberOfMethods = concretes.size();
FixedNode continuation = invoke.next();
// setup merge and phi nodes for results and exceptions
AbstractMergeNode returnMerge = graph.add(new MergeNode());
returnMerge.setStateAfter(invoke.stateAfter());
PhiNode returnValuePhi = null;
if (invoke.asNode().getStackKind() != JavaKind.Void) {
returnValuePhi = graph.addWithoutUnique(new ValuePhiNode(invoke.asNode().stamp(NodeView.DEFAULT).unrestricted(), returnMerge));
}
AbstractMergeNode exceptionMerge = null;
PhiNode exceptionObjectPhi = null;
if (invoke instanceof InvokeWithExceptionNode) {
InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithException.exceptionEdge();
exceptionMerge = graph.add(new MergeNode());
FixedNode exceptionSux = exceptionEdge.next();
graph.addBeforeFixed(exceptionSux, exceptionMerge);
exceptionObjectPhi = graph.addWithoutUnique(new ValuePhiNode(StampFactory.forKind(JavaKind.Object), exceptionMerge));
exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(invoke.stateAfter().bci, true, JavaKind.Object, new JavaKind[] { JavaKind.Object }, new ValueNode[] { exceptionObjectPhi }));
}
// create one separate block for each invoked method
AbstractBeginNode[] successors = new AbstractBeginNode[numberOfMethods + 1];
for (int i = 0; i < numberOfMethods; i++) {
successors[i] = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, true);
}
// create the successor for an unknown type
FixedNode unknownTypeSux;
if (shouldFallbackToInvoke()) {
unknownTypeSux = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, false);
} else {
unknownTypeSux = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated));
}
successors[successors.length - 1] = BeginNode.begin(unknownTypeSux);
// replace the invoke exception edge
if (invoke instanceof InvokeWithExceptionNode) {
InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invoke;
ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithExceptionNode.exceptionEdge();
exceptionEdge.replaceAtUsages(exceptionObjectPhi);
exceptionEdge.setNext(null);
GraphUtil.killCFG(invokeWithExceptionNode.exceptionEdge());
}
assert invoke.asNode().isAlive();
// replace the invoke with a switch on the type of the actual receiver
boolean methodDispatch = createDispatchOnTypeBeforeInvoke(graph, successors, false, providers.getStampProvider(), providers.getConstantReflection());
assert invoke.next() == continuation;
invoke.setNext(null);
returnMerge.setNext(continuation);
if (returnValuePhi != null) {
invoke.asNode().replaceAtUsages(returnValuePhi);
}
invoke.asNode().safeDelete();
ArrayList<PiNode> replacementNodes = new ArrayList<>();
// prepare the anchors for the invokes
for (int i = 0; i < numberOfMethods; i++) {
AbstractBeginNode node = successors[i];
Invoke invokeForInlining = (Invoke) node.next();
ResolvedJavaType commonType;
if (methodDispatch) {
commonType = concretes.get(i).getDeclaringClass();
} else {
commonType = getLeastCommonType(i);
}
ValueNode receiver = ((MethodCallTargetNode) invokeForInlining.callTarget()).receiver();
boolean exact = (getTypeCount(i) == 1 && !methodDispatch);
PiNode anchoredReceiver = InliningUtil.createAnchoredReceiver(graph, node, commonType, receiver, exact);
invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver);
assert !anchoredReceiver.isDeleted() : anchoredReceiver;
replacementNodes.add(anchoredReceiver);
}
if (shouldFallbackToInvoke()) {
replacementNodes.add(null);
}
EconomicSet<Node> canonicalizeNodes = EconomicSet.create(Equivalence.DEFAULT);
// do the actual inlining for every invoke
for (int i = 0; i < numberOfMethods; i++) {
Invoke invokeForInlining = (Invoke) successors[i].next();
canonicalizeNodes.addAll(doInline(i, invokeForInlining));
}
if (returnValuePhi != null) {
canonicalizeNodes.add(returnValuePhi);
}
return canonicalizeNodes;
}
use of org.graalvm.compiler.nodes.AbstractMergeNode in project graal by oracle.
the class GraphUtil method fixSurvivingAffectedMerges.
private static void fixSurvivingAffectedMerges(EconomicSet<Node> markedNodes, EconomicMap<AbstractMergeNode, List<AbstractEndNode>> unmarkedMerges) {
MapCursor<AbstractMergeNode, List<AbstractEndNode>> cursor = unmarkedMerges.getEntries();
while (cursor.advance()) {
AbstractMergeNode merge = cursor.getKey();
for (AbstractEndNode end : cursor.getValue()) {
merge.removeEnd(end);
}
if (merge.phiPredecessorCount() == 1) {
if (merge instanceof LoopBeginNode) {
LoopBeginNode loopBegin = (LoopBeginNode) merge;
assert merge.forwardEndCount() == 1;
for (LoopExitNode loopExit : loopBegin.loopExits().snapshot()) {
if (markedNodes.contains(loopExit)) {
/*
* disconnect from loop begin so that reduceDegenerateLoopBegin doesn't
* transform it into a new beginNode
*/
loopExit.replaceFirstInput(loopBegin, null);
}
}
merge.graph().reduceDegenerateLoopBegin(loopBegin);
} else {
merge.graph().reduceTrivialMerge(merge);
}
} else {
assert merge.phiPredecessorCount() > 1 : merge;
}
}
}
use of org.graalvm.compiler.nodes.AbstractMergeNode in project graal by oracle.
the class GraphUtil method markFixedNodes.
private static void markFixedNodes(FixedNode node, EconomicSet<Node> markedNodes, EconomicMap<AbstractMergeNode, List<AbstractEndNode>> unmarkedMerges) {
NodeStack workStack = new NodeStack();
workStack.push(node);
while (!workStack.isEmpty()) {
Node fixedNode = workStack.pop();
markedNodes.add(fixedNode);
if (fixedNode instanceof AbstractMergeNode) {
unmarkedMerges.removeKey((AbstractMergeNode) fixedNode);
}
while (fixedNode instanceof FixedWithNextNode) {
fixedNode = ((FixedWithNextNode) fixedNode).next();
if (fixedNode != null) {
markedNodes.add(fixedNode);
}
}
if (fixedNode instanceof ControlSplitNode) {
for (Node successor : fixedNode.successors()) {
workStack.push(successor);
}
} else if (fixedNode instanceof AbstractEndNode) {
AbstractEndNode end = (AbstractEndNode) fixedNode;
AbstractMergeNode merge = end.merge();
if (merge != null) {
assert !markedNodes.contains(merge) || (merge instanceof LoopBeginNode && end instanceof LoopEndNode) : merge;
if (merge instanceof LoopBeginNode) {
if (end == ((LoopBeginNode) merge).forwardEnd()) {
workStack.push(merge);
continue;
}
if (markedNodes.contains(merge)) {
continue;
}
}
List<AbstractEndNode> endsSeen = unmarkedMerges.get(merge);
if (endsSeen == null) {
endsSeen = new ArrayList<>(merge.forwardEndCount());
unmarkedMerges.put(merge, endsSeen);
}
endsSeen.add(end);
if (!(end instanceof LoopEndNode) && endsSeen.size() == merge.forwardEndCount()) {
assert merge.forwardEnds().filter(n -> !markedNodes.contains(n)).isEmpty();
// all this merge's forward ends are marked: it needs to be killed
workStack.push(merge);
}
}
}
}
}
use of org.graalvm.compiler.nodes.AbstractMergeNode in project graal by oracle.
the class SimpleCFGTest method testImplies.
@Test
public void testImplies() {
OptionValues options = getInitialOptions();
DebugContext debug = DebugContext.create(options, new GraalDebugHandlersFactory(getSnippetReflection()));
StructuredGraph graph = new StructuredGraph.Builder(options, debug, AllowAssumptions.YES).build();
EndNode trueEnd = graph.add(new EndNode());
EndNode falseEnd = graph.add(new EndNode());
AbstractBeginNode trueBegin = graph.add(new BeginNode());
trueBegin.setNext(trueEnd);
AbstractBeginNode falseBegin = graph.add(new BeginNode());
falseBegin.setNext(falseEnd);
IfNode ifNode = graph.add(new IfNode(null, trueBegin, falseBegin, 0.5));
graph.start().setNext(ifNode);
AbstractMergeNode merge = graph.add(new MergeNode());
merge.addForwardEnd(trueEnd);
merge.addForwardEnd(falseEnd);
ReturnNode returnNode = graph.add(new ReturnNode(null));
merge.setNext(returnNode);
dumpGraph(graph);
ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true);
Block[] blocks = cfg.getBlocks();
// check number of blocks
assertDeepEquals(4, blocks.length);
// check block - node assignment
assertDeepEquals(blocks[0], cfg.blockFor(graph.start()));
assertDeepEquals(blocks[0], cfg.blockFor(ifNode));
assertDeepEquals(blocks[1], cfg.blockFor(trueBegin));
assertDeepEquals(blocks[1], cfg.blockFor(trueEnd));
assertDeepEquals(blocks[2], cfg.blockFor(falseBegin));
assertDeepEquals(blocks[2], cfg.blockFor(falseEnd));
assertDeepEquals(blocks[3], cfg.blockFor(merge));
assertDeepEquals(blocks[3], cfg.blockFor(returnNode));
// check dominators
assertDominator(blocks[0], null);
assertDominator(blocks[1], blocks[0]);
assertDominator(blocks[2], blocks[0]);
assertDominator(blocks[3], blocks[0]);
// check dominated
assertDominatedSize(blocks[0], 3);
assertDominatedSize(blocks[1], 0);
assertDominatedSize(blocks[2], 0);
assertDominatedSize(blocks[3], 0);
// check postdominators
assertPostdominator(blocks[0], blocks[3]);
assertPostdominator(blocks[1], blocks[3]);
assertPostdominator(blocks[2], blocks[3]);
assertPostdominator(blocks[3], null);
}
Aggregations