24 |
24 |
25 import java.util.ArrayDeque; |
25 import java.util.ArrayDeque; |
26 import java.util.Deque; |
26 import java.util.Deque; |
27 import java.util.List; |
27 import java.util.List; |
28 |
28 |
|
29 import org.graalvm.collections.EconomicMap; |
|
30 import org.graalvm.collections.Equivalence; |
|
31 import org.graalvm.collections.MapCursor; |
|
32 import org.graalvm.collections.Pair; |
29 import org.graalvm.compiler.core.common.cfg.BlockMap; |
33 import org.graalvm.compiler.core.common.cfg.BlockMap; |
30 import org.graalvm.compiler.core.common.type.ArithmeticOpTable; |
34 import org.graalvm.compiler.core.common.type.ArithmeticOpTable; |
31 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp; |
35 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp; |
32 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.And; |
36 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.And; |
33 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Or; |
37 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Or; |
85 import org.graalvm.compiler.nodes.util.GraphUtil; |
89 import org.graalvm.compiler.nodes.util.GraphUtil; |
86 import org.graalvm.compiler.phases.BasePhase; |
90 import org.graalvm.compiler.phases.BasePhase; |
87 import org.graalvm.compiler.phases.schedule.SchedulePhase; |
91 import org.graalvm.compiler.phases.schedule.SchedulePhase; |
88 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; |
92 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; |
89 import org.graalvm.compiler.phases.tiers.PhaseContext; |
93 import org.graalvm.compiler.phases.tiers.PhaseContext; |
90 import org.graalvm.util.EconomicMap; |
|
91 import org.graalvm.util.Equivalence; |
|
92 import org.graalvm.util.MapCursor; |
|
93 import org.graalvm.util.Pair; |
|
94 |
94 |
95 import jdk.vm.ci.meta.JavaConstant; |
95 import jdk.vm.ci.meta.JavaConstant; |
96 import jdk.vm.ci.meta.TriState; |
96 import jdk.vm.ci.meta.TriState; |
97 |
97 |
98 public class ConditionalEliminationPhase extends BasePhase<PhaseContext> { |
98 public class ConditionalEliminationPhase extends BasePhase<PhaseContext> { |
122 ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true); |
122 ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true); |
123 if (fullSchedule) { |
123 if (fullSchedule) { |
124 if (moveGuards) { |
124 if (moveGuards) { |
125 cfg.visitDominatorTree(new MoveGuardsUpwards(), graph.hasValueProxies()); |
125 cfg.visitDominatorTree(new MoveGuardsUpwards(), graph.hasValueProxies()); |
126 } |
126 } |
127 SchedulePhase.run(graph, SchedulingStrategy.EARLIEST, cfg); |
127 try (DebugContext.Scope scheduleScope = graph.getDebug().scope(SchedulePhase.class)) { |
|
128 SchedulePhase.run(graph, SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER, cfg); |
|
129 } catch (Throwable t) { |
|
130 throw graph.getDebug().handle(t); |
|
131 } |
128 ScheduleResult r = graph.getLastSchedule(); |
132 ScheduleResult r = graph.getLastSchedule(); |
129 blockToNodes = r.getBlockToNodesMap(); |
133 blockToNodes = r.getBlockToNodesMap(); |
130 nodeToBlock = r.getNodeToBlockMap(); |
134 nodeToBlock = r.getNodeToBlockMap(); |
131 } else { |
135 } else { |
132 nodeToBlock = cfg.getNodeToBlock(); |
136 nodeToBlock = cfg.getNodeToBlock(); |
660 * be moved up if we're sure there's no schedule dependence. For now limit it to |
664 * be moved up if we're sure there's no schedule dependence. For now limit it to |
661 * the original node and constants. |
665 * the original node and constants. |
662 */ |
666 */ |
663 InputFilter v = new InputFilter(original); |
667 InputFilter v = new InputFilter(original); |
664 thisGuard.getCondition().applyInputs(v); |
668 thisGuard.getCondition().applyInputs(v); |
665 if (v.ok && foldGuard(thisGuard, pendingGuard, newStamp, rewireGuardFunction)) { |
669 if (v.ok && foldGuard(thisGuard, pendingGuard, result.toBoolean(), newStamp, rewireGuardFunction)) { |
666 return true; |
670 return true; |
667 } |
671 } |
668 } |
672 } |
669 } |
673 } |
670 return false; |
674 return false; |
671 } |
675 } |
672 |
676 |
673 protected boolean foldGuard(DeoptimizingGuard thisGuard, DeoptimizingGuard otherGuard, Stamp guardedValueStamp, GuardRewirer rewireGuardFunction) { |
677 protected boolean foldGuard(DeoptimizingGuard thisGuard, DeoptimizingGuard otherGuard, boolean outcome, Stamp guardedValueStamp, GuardRewirer rewireGuardFunction) { |
674 if (otherGuard.getAction() == thisGuard.getAction() && otherGuard.getSpeculation() == thisGuard.getSpeculation()) { |
678 if (otherGuard.getAction() == thisGuard.getAction() && otherGuard.getSpeculation() == thisGuard.getSpeculation()) { |
675 LogicNode condition = (LogicNode) thisGuard.getCondition().copyWithInputs(); |
679 LogicNode condition = (LogicNode) thisGuard.getCondition().copyWithInputs(); |
|
680 /* |
|
681 * We have ...; guard(C1); guard(C2);... |
|
682 * |
|
683 * Where the first guard is `otherGuard` and the second one `thisGuard`. |
|
684 * |
|
685 * Depending on `outcome`, we have C2 => C1 or C2 => !C1. |
|
686 * |
|
687 * - If C2 => C1, `mustDeopt` below is false and we transform to ...; guard(C2); ... |
|
688 * |
|
689 * - If C2 => !C1, `mustDeopt` is true and we transform to ..; guard(C1); deopt; |
|
690 */ |
676 GuardRewirer rewirer = (guard, result, innerGuardedValueStamp, newInput) -> { |
691 GuardRewirer rewirer = (guard, result, innerGuardedValueStamp, newInput) -> { |
677 if (rewireGuardFunction.rewire(guard, result, innerGuardedValueStamp, newInput)) { |
692 // `result` is `outcome`, `guard` is `otherGuard` |
678 otherGuard.setCondition(condition, thisGuard.isNegated()); |
693 boolean mustDeopt = result == otherGuard.isNegated(); |
|
694 if (rewireGuardFunction.rewire(guard, mustDeopt == thisGuard.isNegated(), innerGuardedValueStamp, newInput)) { |
|
695 if (!mustDeopt) { |
|
696 otherGuard.setCondition(condition, thisGuard.isNegated()); |
|
697 } |
679 return true; |
698 return true; |
680 } |
699 } |
681 condition.safeDelete(); |
700 condition.safeDelete(); |
682 return false; |
701 return false; |
683 }; |
702 }; |
684 // Move the later test up |
703 // Move the later test up |
685 return rewireGuards(otherGuard, !thisGuard.isNegated(), null, guardedValueStamp, rewirer); |
704 return rewireGuards(otherGuard, outcome, null, guardedValueStamp, rewirer); |
686 } |
705 } |
687 return false; |
706 return false; |
688 } |
707 } |
689 |
708 |
690 protected void registerCondition(LogicNode condition, boolean negated, GuardingNode guard) { |
709 protected void registerCondition(LogicNode condition, boolean negated, GuardingNode guard) { |