public class DeadCodeEliminationPhase extends Phase { public static class Options { // @formatter:off @Option(help = "Disable optional dead code eliminations", type = OptionType.Debug) public static final OptionValue<Boolean> ReduceDCE = new OptionValue<>(true); // @formatter:on } // Metrics private static final DebugMetric metricNodesRemoved = Debug.metric("NodesRemoved"); public enum Optionality { Optional, Required; } /** * Creates a dead code elimination phase that will be run irrespective of {@link * Options#ReduceDCE}. */ public DeadCodeEliminationPhase() { this(Optionality.Required); } /** * Creates a dead code elimination phase that will be run only if it is {@linkplain * Optionality#Required non-optional} or {@link Options#ReduceDCE} is false. */ public DeadCodeEliminationPhase(Optionality optionality) { this.optional = optionality == Optionality.Optional; } private final boolean optional; @Override public void run(StructuredGraph graph) { if (optional && Options.ReduceDCE.getValue()) { return; } NodeFlood flood = graph.createNodeFlood(); int totalNodeCount = graph.getNodeCount(); flood.add(graph.start()); iterateSuccessorsAndInputs(flood); int totalMarkedCount = flood.getTotalMarkedCount(); if (totalNodeCount == totalMarkedCount) { // All nodes are live => nothing more to do. return; } else { // Some nodes are not marked alive and therefore dead => proceed. assert totalNodeCount > totalMarkedCount; } deleteNodes(flood, graph); } private static void iterateSuccessorsAndInputs(NodeFlood flood) { BiConsumer<Node, Node> consumer = (n, succOrInput) -> { assert succOrInput.isAlive() : "dead successor or input " + succOrInput + " in " + n; flood.add(succOrInput); }; for (Node current : flood) { if (current instanceof AbstractEndNode) { AbstractEndNode end = (AbstractEndNode) current; flood.add(end.merge()); } else { current.acceptSuccessors(consumer); current.acceptInputs(consumer); } } } private static void deleteNodes(NodeFlood flood, StructuredGraph graph) { BiConsumer<Node, Node> consumer = (n, input) -> { if (input.isAlive() && flood.isMarked(input)) { input.removeUsage(n); } }; for (Node node : graph.getNodes()) { if (!flood.isMarked(node)) { node.markDeleted(); node.acceptInputs(consumer); metricNodesRemoved.increment(); } } } }
public class GreedyInliningPolicy extends AbstractInliningPolicy { private static final DebugMetric metricInliningStoppedByMaxDesiredSize = Debug.metric("InliningStoppedByMaxDesiredSize"); public GreedyInliningPolicy(Map<Invoke, Double> hints) { super(hints); } public boolean continueInlining(StructuredGraph currentGraph) { if (currentGraph.getNodeCount() >= MaximumDesiredSize.getValue()) { InliningUtil.logInliningDecision("inlining is cut off by MaximumDesiredSize"); metricInliningStoppedByMaxDesiredSize.increment(); return false; } return true; } @Override public boolean isWorthInlining( Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed) { final InlineInfo info = invocation.callee(); final double probability = invocation.probability(); final double relevance = invocation.relevance(); if (InlineEverything.getValue()) { InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything"); return true; } if (isIntrinsic(replacements, info)) { InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic"); return true; } if (info.shouldInline()) { InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining"); return true; } double inliningBonus = getInliningBonus(info); int nodes = info.determineNodeCount(); int lowLevelGraphSize = previousLowLevelGraphSize(info); if (SmallCompiledLowLevelGraphSize.getValue() > 0 && lowLevelGraphSize > SmallCompiledLowLevelGraphSize.getValue() * inliningBonus) { InliningUtil.logNotInlinedMethod( info, inliningDepth, "too large previous low-level graph (low-level-nodes: %d, relevance=%f, probability=%f, bonus=%f, nodes=%d)", lowLevelGraphSize, relevance, probability, inliningBonus, nodes); return false; } if (nodes < TrivialInliningSize.getValue() * inliningBonus) { InliningUtil.logInlinedMethod( info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes); return true; } /* * TODO (chaeubl): invoked methods that are on important paths but not yet compiled -> will * be compiled anyways and it is likely that we are the only caller... might be useful to * inline those methods but increases bootstrap time (maybe those methods are also getting * queued in the compilation queue concurrently) */ double invokes = determineInvokeProbability(info); if (LimitInlinedInvokes.getValue() > 0 && fullyProcessed && invokes > LimitInlinedInvokes.getValue() * inliningBonus) { InliningUtil.logNotInlinedMethod( info, inliningDepth, "callee invoke probability is too high (invokeP=%f, relevance=%f, probability=%f, bonus=%f, nodes=%d)", invokes, relevance, probability, inliningBonus, nodes); return false; } double maximumNodes = computeMaximumSize(relevance, (int) (MaximumInliningSize.getValue() * inliningBonus)); if (nodes <= maximumNodes) { InliningUtil.logInlinedMethod( info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus, nodes, maximumNodes); return true; } InliningUtil.logNotInlinedMethod( info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes); return false; } }