< prev index next >

src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java

Print this page




 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() {


< prev index next >