231 public InfoElement get(EndNode end) {
232 if (infoElements == null) {
233 return null;
234 }
235 return infoElements.get(end);
236 }
237 }
238
239 public static class Instance implements ControlFlowGraph.RecursiveVisitor<Integer> {
240 protected final NodeMap<InfoElement> map;
241 protected final BlockMap<List<Node>> blockToNodes;
242 protected final CanonicalizerTool tool;
243 protected final NodeStack undoOperations;
244 protected final StructuredGraph graph;
245 protected final DebugContext debug;
246 protected final EconomicMap<MergeNode, EconomicMap<ValuePhiNode, PhiInfoElement>> mergeMaps;
247
248 /**
249 * Tests which may be eliminated because post dominating tests to prove a broader condition.
250 */
251 private Deque<PendingTest> pendingTests;
252
253 public Instance(StructuredGraph graph, BlockMap<List<Node>> blockToNodes, PhaseContext context) {
254 this.graph = graph;
255 this.debug = graph.getDebug();
256 this.blockToNodes = blockToNodes;
257 this.undoOperations = new NodeStack();
258 this.map = graph.createNodeMap();
259 pendingTests = new ArrayDeque<>();
260 tool = GraphUtil.getDefaultSimplifier(context.getMetaAccess(), context.getConstantReflection(), context.getConstantFieldProvider(), false, graph.getAssumptions(), graph.getOptions(),
261 context.getLowerer());
262 mergeMaps = EconomicMap.create();
263 }
264
265 protected void processConditionAnchor(ConditionAnchorNode node) {
266 tryProveCondition(node.condition(), (guard, result, guardedValueStamp, newInput) -> {
267 if (result != node.isNegated()) {
268 node.replaceAtUsages(guard.asNode());
269 GraphUtil.unlinkFixedNode(node);
270 GraphUtil.killWithUnusedFloatingInputs(node);
271 } else {
538 }
539
540 if (condition instanceof IntegerEqualsNode && guard instanceof DeoptimizingGuard && !negated) {
541 if (y.isConstant() && x instanceof AndNode) {
542 AndNode and = (AndNode) x;
543 ValueNode andX = and.getX();
544 if (and.getY() == y && maybeMultipleUsages(andX)) {
545 /*
546 * This 'and' proves something about some of the bits in and.getX().
547 * It's equivalent to or'ing in the mask value since those values are
548 * known to be set.
549 */
550 BinaryOp<Or> op = ArithmeticOpTable.forStamp(x.stamp()).getOr();
551 IntegerStamp newStampX = (IntegerStamp) op.foldStamp(getSafeStamp(andX), getOtherSafeStamp(y));
552 registerNewStamp(andX, newStampX, guard);
553 }
554 }
555 }
556 }
557 if (guard instanceof DeoptimizingGuard) {
558 pendingTests.push(new PendingTest(condition, (DeoptimizingGuard) guard));
559 }
560 registerCondition(condition, negated, guard);
561 }
562
563 Pair<InfoElement, Stamp> recursiveFoldStamp(Node node) {
564 if (node instanceof UnaryNode) {
565 UnaryNode unary = (UnaryNode) node;
566 ValueNode value = unary.getValue();
567 InfoElement infoElement = getInfoElements(value);
568 while (infoElement != null) {
569 Stamp result = unary.foldStamp(infoElement.getStamp());
570 if (result != null) {
571 return Pair.create(infoElement, result);
572 }
573 infoElement = nextElement(infoElement);
574 }
575 } else if (node instanceof BinaryNode) {
576 BinaryNode binary = (BinaryNode) node;
577 ValueNode y = binary.getY();
578 ValueNode x = binary.getX();
611 if (x.isConstant()) {
612 return x.stamp();
613 }
614 return x.stamp().unrestricted();
615 }
616
617 /**
618 * Recursively try to fold stamps within this expression using information from
619 * {@link #getInfoElements(ValueNode)}. It's only safe to use constants and one
620 * {@link InfoElement} otherwise more than one guard would be required.
621 *
622 * @param node
623 * @return the pair of the @{link InfoElement} used and the stamp produced for the whole
624 * expression
625 */
626 Pair<InfoElement, Stamp> recursiveFoldStampFromInfo(Node node) {
627 return recursiveFoldStamp(node);
628 }
629
630 protected boolean foldPendingTest(DeoptimizingGuard thisGuard, ValueNode original, Stamp newStamp, GuardRewirer rewireGuardFunction) {
631 for (PendingTest pending : pendingTests) {
632 TriState result = TriState.UNKNOWN;
633 if (pending.condition instanceof UnaryOpLogicNode) {
634 UnaryOpLogicNode unaryLogicNode = (UnaryOpLogicNode) pending.condition;
635 if (unaryLogicNode.getValue() == original) {
636 result = unaryLogicNode.tryFold(newStamp);
637 }
638 } else if (pending.condition instanceof BinaryOpLogicNode) {
639 BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) pending.condition;
640 ValueNode x = binaryOpLogicNode.getX();
641 ValueNode y = binaryOpLogicNode.getY();
642 if (x == original) {
643 result = binaryOpLogicNode.tryFold(newStamp, getOtherSafeStamp(y));
644 } else if (y == original) {
645 result = binaryOpLogicNode.tryFold(getOtherSafeStamp(x), newStamp);
646 } else if (binaryOpLogicNode instanceof IntegerEqualsNode && y.isConstant() && x instanceof AndNode) {
647 AndNode and = (AndNode) x;
648 if (and.getY() == y && and.getX() == original) {
649 BinaryOp<And> andOp = ArithmeticOpTable.forStamp(newStamp).getAnd();
650 result = binaryOpLogicNode.tryFold(andOp.foldStamp(newStamp, getOtherSafeStamp(y)), getOtherSafeStamp(y));
651 }
652 }
653 }
654 if (result.isKnown()) {
655 /*
656 * The test case be folded using the information available but the test can only
657 * be moved up if we're sure there's no schedule dependence. For now limit it to
658 * the original node and constants.
659 */
660 InputFilter v = new InputFilter(original);
661 thisGuard.getCondition().applyInputs(v);
662 if (v.ok && foldGuard(thisGuard, pending.guard, newStamp, rewireGuardFunction)) {
663 return true;
664 }
665 }
666 }
667 return false;
668 }
669
670 protected boolean foldGuard(DeoptimizingGuard thisGuard, DeoptimizingGuard otherGuard, Stamp guardedValueStamp, GuardRewirer rewireGuardFunction) {
671 if (otherGuard.getAction() == thisGuard.getAction() && otherGuard.getSpeculation() == thisGuard.getSpeculation()) {
672 LogicNode condition = (LogicNode) thisGuard.getCondition().copyWithInputs();
673 GuardRewirer rewirer = (guard, result, innerGuardedValueStamp, newInput) -> {
674 if (rewireGuardFunction.rewire(guard, result, innerGuardedValueStamp, newInput)) {
675 otherGuard.setCondition(condition, thisGuard.isNegated());
676 return true;
677 }
678 condition.safeDelete();
679 return false;
680 };
681 // Move the later test up
682 return rewireGuards(otherGuard, !thisGuard.isNegated(), null, guardedValueStamp, rewirer);
1007 curValue.applyInputs(this);
1008 } else {
1009 ok = false;
1010 }
1011 return curNode;
1012 }
1013 }
1014
1015 @FunctionalInterface
1016 protected interface GuardRewirer {
1017 /**
1018 * Called if the condition could be proven to have a constant value ({@code result}) under
1019 * {@code guard}.
1020 *
1021 * @param guard the guard whose result is proven
1022 * @param result the known result of the guard
1023 * @param newInput new input to pi nodes depending on the new guard
1024 * @return whether the transformation could be applied
1025 */
1026 boolean rewire(GuardingNode guard, boolean result, Stamp guardedValueStamp, ValueNode newInput);
1027 }
1028
1029 protected static class PendingTest {
1030 private final LogicNode condition;
1031 private final DeoptimizingGuard guard;
1032
1033 public PendingTest(LogicNode condition, DeoptimizingGuard guard) {
1034 this.condition = condition;
1035 this.guard = guard;
1036 }
1037 }
1038
1039 protected static final class InfoElement {
1040 private final Stamp stamp;
1041 private final GuardingNode guard;
1042 private final ValueNode proxifiedInput;
1043 private final InfoElement parent;
1044
1045 public InfoElement(Stamp stamp, GuardingNode guard, ValueNode proxifiedInput, InfoElement parent) {
1046 this.stamp = stamp;
1047 this.guard = guard;
1048 this.proxifiedInput = proxifiedInput;
1049 this.parent = parent;
1050 }
1051
1052 public InfoElement getParent() {
1053 return parent;
1054 }
1055
1056 public Stamp getStamp() {
|
231 public InfoElement get(EndNode end) {
232 if (infoElements == null) {
233 return null;
234 }
235 return infoElements.get(end);
236 }
237 }
238
239 public static class Instance implements ControlFlowGraph.RecursiveVisitor<Integer> {
240 protected final NodeMap<InfoElement> map;
241 protected final BlockMap<List<Node>> blockToNodes;
242 protected final CanonicalizerTool tool;
243 protected final NodeStack undoOperations;
244 protected final StructuredGraph graph;
245 protected final DebugContext debug;
246 protected final EconomicMap<MergeNode, EconomicMap<ValuePhiNode, PhiInfoElement>> mergeMaps;
247
248 /**
249 * Tests which may be eliminated because post dominating tests to prove a broader condition.
250 */
251 private Deque<DeoptimizingGuard> pendingTests;
252
253 public Instance(StructuredGraph graph, BlockMap<List<Node>> blockToNodes, PhaseContext context) {
254 this.graph = graph;
255 this.debug = graph.getDebug();
256 this.blockToNodes = blockToNodes;
257 this.undoOperations = new NodeStack();
258 this.map = graph.createNodeMap();
259 pendingTests = new ArrayDeque<>();
260 tool = GraphUtil.getDefaultSimplifier(context.getMetaAccess(), context.getConstantReflection(), context.getConstantFieldProvider(), false, graph.getAssumptions(), graph.getOptions(),
261 context.getLowerer());
262 mergeMaps = EconomicMap.create();
263 }
264
265 protected void processConditionAnchor(ConditionAnchorNode node) {
266 tryProveCondition(node.condition(), (guard, result, guardedValueStamp, newInput) -> {
267 if (result != node.isNegated()) {
268 node.replaceAtUsages(guard.asNode());
269 GraphUtil.unlinkFixedNode(node);
270 GraphUtil.killWithUnusedFloatingInputs(node);
271 } else {
538 }
539
540 if (condition instanceof IntegerEqualsNode && guard instanceof DeoptimizingGuard && !negated) {
541 if (y.isConstant() && x instanceof AndNode) {
542 AndNode and = (AndNode) x;
543 ValueNode andX = and.getX();
544 if (and.getY() == y && maybeMultipleUsages(andX)) {
545 /*
546 * This 'and' proves something about some of the bits in and.getX().
547 * It's equivalent to or'ing in the mask value since those values are
548 * known to be set.
549 */
550 BinaryOp<Or> op = ArithmeticOpTable.forStamp(x.stamp()).getOr();
551 IntegerStamp newStampX = (IntegerStamp) op.foldStamp(getSafeStamp(andX), getOtherSafeStamp(y));
552 registerNewStamp(andX, newStampX, guard);
553 }
554 }
555 }
556 }
557 if (guard instanceof DeoptimizingGuard) {
558 assert ((DeoptimizingGuard) guard).getCondition() == condition;
559 pendingTests.push((DeoptimizingGuard) guard);
560 }
561 registerCondition(condition, negated, guard);
562 }
563
564 Pair<InfoElement, Stamp> recursiveFoldStamp(Node node) {
565 if (node instanceof UnaryNode) {
566 UnaryNode unary = (UnaryNode) node;
567 ValueNode value = unary.getValue();
568 InfoElement infoElement = getInfoElements(value);
569 while (infoElement != null) {
570 Stamp result = unary.foldStamp(infoElement.getStamp());
571 if (result != null) {
572 return Pair.create(infoElement, result);
573 }
574 infoElement = nextElement(infoElement);
575 }
576 } else if (node instanceof BinaryNode) {
577 BinaryNode binary = (BinaryNode) node;
578 ValueNode y = binary.getY();
579 ValueNode x = binary.getX();
612 if (x.isConstant()) {
613 return x.stamp();
614 }
615 return x.stamp().unrestricted();
616 }
617
618 /**
619 * Recursively try to fold stamps within this expression using information from
620 * {@link #getInfoElements(ValueNode)}. It's only safe to use constants and one
621 * {@link InfoElement} otherwise more than one guard would be required.
622 *
623 * @param node
624 * @return the pair of the @{link InfoElement} used and the stamp produced for the whole
625 * expression
626 */
627 Pair<InfoElement, Stamp> recursiveFoldStampFromInfo(Node node) {
628 return recursiveFoldStamp(node);
629 }
630
631 protected boolean foldPendingTest(DeoptimizingGuard thisGuard, ValueNode original, Stamp newStamp, GuardRewirer rewireGuardFunction) {
632 for (DeoptimizingGuard pendingGuard : pendingTests) {
633 LogicNode pendingCondition = pendingGuard.getCondition();
634 TriState result = TriState.UNKNOWN;
635 if (pendingCondition instanceof UnaryOpLogicNode) {
636 UnaryOpLogicNode unaryLogicNode = (UnaryOpLogicNode) pendingCondition;
637 if (unaryLogicNode.getValue() == original) {
638 result = unaryLogicNode.tryFold(newStamp);
639 }
640 } else if (pendingCondition instanceof BinaryOpLogicNode) {
641 BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) pendingCondition;
642 ValueNode x = binaryOpLogicNode.getX();
643 ValueNode y = binaryOpLogicNode.getY();
644 if (x == original) {
645 result = binaryOpLogicNode.tryFold(newStamp, getOtherSafeStamp(y));
646 } else if (y == original) {
647 result = binaryOpLogicNode.tryFold(getOtherSafeStamp(x), newStamp);
648 } else if (binaryOpLogicNode instanceof IntegerEqualsNode && y.isConstant() && x instanceof AndNode) {
649 AndNode and = (AndNode) x;
650 if (and.getY() == y && and.getX() == original) {
651 BinaryOp<And> andOp = ArithmeticOpTable.forStamp(newStamp).getAnd();
652 result = binaryOpLogicNode.tryFold(andOp.foldStamp(newStamp, getOtherSafeStamp(y)), getOtherSafeStamp(y));
653 }
654 }
655 }
656 if (result.isKnown()) {
657 /*
658 * The test case be folded using the information available but the test can only
659 * be moved up if we're sure there's no schedule dependence. For now limit it to
660 * the original node and constants.
661 */
662 InputFilter v = new InputFilter(original);
663 thisGuard.getCondition().applyInputs(v);
664 if (v.ok && foldGuard(thisGuard, pendingGuard, newStamp, rewireGuardFunction)) {
665 return true;
666 }
667 }
668 }
669 return false;
670 }
671
672 protected boolean foldGuard(DeoptimizingGuard thisGuard, DeoptimizingGuard otherGuard, Stamp guardedValueStamp, GuardRewirer rewireGuardFunction) {
673 if (otherGuard.getAction() == thisGuard.getAction() && otherGuard.getSpeculation() == thisGuard.getSpeculation()) {
674 LogicNode condition = (LogicNode) thisGuard.getCondition().copyWithInputs();
675 GuardRewirer rewirer = (guard, result, innerGuardedValueStamp, newInput) -> {
676 if (rewireGuardFunction.rewire(guard, result, innerGuardedValueStamp, newInput)) {
677 otherGuard.setCondition(condition, thisGuard.isNegated());
678 return true;
679 }
680 condition.safeDelete();
681 return false;
682 };
683 // Move the later test up
684 return rewireGuards(otherGuard, !thisGuard.isNegated(), null, guardedValueStamp, rewirer);
1009 curValue.applyInputs(this);
1010 } else {
1011 ok = false;
1012 }
1013 return curNode;
1014 }
1015 }
1016
1017 @FunctionalInterface
1018 protected interface GuardRewirer {
1019 /**
1020 * Called if the condition could be proven to have a constant value ({@code result}) under
1021 * {@code guard}.
1022 *
1023 * @param guard the guard whose result is proven
1024 * @param result the known result of the guard
1025 * @param newInput new input to pi nodes depending on the new guard
1026 * @return whether the transformation could be applied
1027 */
1028 boolean rewire(GuardingNode guard, boolean result, Stamp guardedValueStamp, ValueNode newInput);
1029 }
1030
1031 protected static final class InfoElement {
1032 private final Stamp stamp;
1033 private final GuardingNode guard;
1034 private final ValueNode proxifiedInput;
1035 private final InfoElement parent;
1036
1037 public InfoElement(Stamp stamp, GuardingNode guard, ValueNode proxifiedInput, InfoElement parent) {
1038 this.stamp = stamp;
1039 this.guard = guard;
1040 this.proxifiedInput = proxifiedInput;
1041 this.parent = parent;
1042 }
1043
1044 public InfoElement getParent() {
1045 return parent;
1046 }
1047
1048 public Stamp getStamp() {
|