package org.graalvm.compiler.phases.common;
import org.graalvm.compiler.debug.CounterKey;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeFlood;
import org.graalvm.compiler.nodes.AbstractEndNode;
import org.graalvm.compiler.nodes.GuardNode;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.options.Option;
import org.graalvm.compiler.options.OptionKey;
import org.graalvm.compiler.options.OptionType;
import org.graalvm.compiler.phases.Phase;
public class DeadCodeEliminationPhase extends Phase {
public static class Options {
@Option(help = "Disable optional dead code eliminations", type = OptionType.Debug)
public static final OptionKey<Boolean> ReduceDCE = new OptionKey<>(true);
}
private static final CounterKey counterNodesRemoved = DebugContext.counter("NodesRemoved");
public enum Optionality {
Optional,
Required;
}
public DeadCodeEliminationPhase() {
this(Optionality.Required);
}
public DeadCodeEliminationPhase(Optionality optionality) {
this.optional = optionality == Optionality.Optional;
}
private final boolean optional;
@Override
public void run(StructuredGraph graph) {
if (optional && Options.ReduceDCE.getValue(graph.getOptions())) {
return;
}
NodeFlood flood = graph.createNodeFlood();
int totalNodeCount = graph.getNodeCount();
flood.add(graph.start());
iterateSuccessorsAndInputs(flood);
boolean changed = false;
for (GuardNode guard : graph.getNodes(GuardNode.TYPE)) {
if (flood.isMarked(guard.getAnchor().asNode())) {
flood.add(guard);
changed = true;
}
}
if (changed) {
iterateSuccessorsAndInputs(flood);
}
int totalMarkedCount = flood.getTotalMarkedCount();
if (totalNodeCount == totalMarkedCount) {
return;
} else {
assert totalNodeCount > totalMarkedCount;
}
deleteNodes(flood, graph);
}
private static void iterateSuccessorsAndInputs(NodeFlood flood) {
Node.EdgeVisitor consumer = new Node.EdgeVisitor() {
@Override
public Node apply(Node n, Node succOrInput) {
assert succOrInput.isAlive() : "dead successor or input " + succOrInput + " in " + n;
flood.add(succOrInput);
return succOrInput;
}
};
for (Node current : flood) {
if (current instanceof AbstractEndNode) {
AbstractEndNode end = (AbstractEndNode) current;
flood.add(end.merge());
} else {
current.applySuccessors(consumer);
current.applyInputs(consumer);
}
}
}
private static void deleteNodes(NodeFlood flood, StructuredGraph graph) {
Node.EdgeVisitor consumer = new Node.EdgeVisitor() {
@Override
public Node apply(Node n, Node input) {
if (input.isAlive() && flood.isMarked(input)) {
input.removeUsage(n);
}
return input;
}
};
DebugContext debug = graph.getDebug();
for (Node node : graph.getNodes()) {
if (!flood.isMarked(node)) {
node.markDeleted();
node.applyInputs(consumer);
counterNodesRemoved.increment(debug);
}
}
}
}