src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java
changeset 48861 47f19ff9903c
parent 47798 9fe9292f5931
child 49873 26ebfe8ce852
equal deleted inserted replaced
48860:5bce1b7e7800 48861:47f19ff9903c
    20  * or visit www.oracle.com if you need additional information or have any
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    21  * questions.
    22  */
    22  */
    23 package org.graalvm.compiler.phases.schedule;
    23 package org.graalvm.compiler.phases.schedule;
    24 
    24 
       
    25 import static org.graalvm.collections.Equivalence.IDENTITY;
       
    26 import static org.graalvm.compiler.core.common.GraalOptions.GuardPriorities;
    25 import static org.graalvm.compiler.core.common.GraalOptions.OptScheduleOutOfLoops;
    27 import static org.graalvm.compiler.core.common.GraalOptions.OptScheduleOutOfLoops;
    26 import static org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph.strictlyDominates;
    28 import static org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph.strictlyDominates;
    27 
    29 
    28 import java.util.ArrayList;
    30 import java.util.ArrayList;
    29 import java.util.Arrays;
    31 import java.util.Arrays;
       
    32 import java.util.Comparator;
       
    33 import java.util.EnumMap;
    30 import java.util.Formatter;
    34 import java.util.Formatter;
       
    35 import java.util.Iterator;
    31 import java.util.List;
    36 import java.util.List;
    32 
    37 import java.util.SortedSet;
       
    38 import java.util.TreeSet;
       
    39 import java.util.function.Function;
       
    40 
       
    41 import org.graalvm.collections.EconomicSet;
    33 import org.graalvm.compiler.core.common.SuppressFBWarnings;
    42 import org.graalvm.compiler.core.common.SuppressFBWarnings;
    34 import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph;
    43 import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph;
    35 import org.graalvm.compiler.core.common.cfg.BlockMap;
    44 import org.graalvm.compiler.core.common.cfg.BlockMap;
    36 import org.graalvm.compiler.debug.Assertions;
    45 import org.graalvm.compiler.debug.Assertions;
    37 import org.graalvm.compiler.graph.Graph.NodeEvent;
    46 import org.graalvm.compiler.graph.Graph.NodeEvent;
    46 import org.graalvm.compiler.nodes.AbstractMergeNode;
    55 import org.graalvm.compiler.nodes.AbstractMergeNode;
    47 import org.graalvm.compiler.nodes.ControlSinkNode;
    56 import org.graalvm.compiler.nodes.ControlSinkNode;
    48 import org.graalvm.compiler.nodes.ControlSplitNode;
    57 import org.graalvm.compiler.nodes.ControlSplitNode;
    49 import org.graalvm.compiler.nodes.DeoptimizeNode;
    58 import org.graalvm.compiler.nodes.DeoptimizeNode;
    50 import org.graalvm.compiler.nodes.FixedNode;
    59 import org.graalvm.compiler.nodes.FixedNode;
    51 import org.graalvm.compiler.nodes.FixedWithNextNode;
       
    52 import org.graalvm.compiler.nodes.GuardNode;
    60 import org.graalvm.compiler.nodes.GuardNode;
    53 import org.graalvm.compiler.nodes.IfNode;
    61 import org.graalvm.compiler.nodes.IfNode;
    54 import org.graalvm.compiler.nodes.KillingBeginNode;
    62 import org.graalvm.compiler.nodes.KillingBeginNode;
    55 import org.graalvm.compiler.nodes.LoopBeginNode;
    63 import org.graalvm.compiler.nodes.LoopBeginNode;
    56 import org.graalvm.compiler.nodes.LoopExitNode;
    64 import org.graalvm.compiler.nodes.LoopExitNode;
    57 import org.graalvm.compiler.nodes.PhiNode;
    65 import org.graalvm.compiler.nodes.PhiNode;
    58 import org.graalvm.compiler.nodes.ProxyNode;
    66 import org.graalvm.compiler.nodes.ProxyNode;
    59 import org.graalvm.compiler.nodes.StartNode;
    67 import org.graalvm.compiler.nodes.StartNode;
       
    68 import org.graalvm.compiler.nodes.StaticDeoptimizingNode;
       
    69 import org.graalvm.compiler.nodes.StaticDeoptimizingNode.GuardPriority;
    60 import org.graalvm.compiler.nodes.StructuredGraph;
    70 import org.graalvm.compiler.nodes.StructuredGraph;
    61 import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
    71 import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
    62 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
    72 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
    63 import org.graalvm.compiler.nodes.ValueNode;
    73 import org.graalvm.compiler.nodes.ValueNode;
    64 import org.graalvm.compiler.nodes.VirtualState;
    74 import org.graalvm.compiler.nodes.VirtualState;
    76 import org.graalvm.word.LocationIdentity;
    86 import org.graalvm.word.LocationIdentity;
    77 
    87 
    78 public final class SchedulePhase extends Phase {
    88 public final class SchedulePhase extends Phase {
    79 
    89 
    80     public enum SchedulingStrategy {
    90     public enum SchedulingStrategy {
       
    91         EARLIEST_WITH_GUARD_ORDER,
    81         EARLIEST,
    92         EARLIEST,
    82         LATEST,
    93         LATEST,
    83         LATEST_OUT_OF_LOOPS,
    94         LATEST_OUT_OF_LOOPS,
    84         FINAL_SCHEDULE
    95         FINAL_SCHEDULE;
       
    96 
       
    97         public boolean isEarliest() {
       
    98             return this == EARLIEST || this == EARLIEST_WITH_GUARD_ORDER;
       
    99         }
       
   100 
       
   101         public boolean isLatest() {
       
   102             return !isEarliest();
       
   103         }
    85     }
   104     }
    86 
   105 
    87     private final SchedulingStrategy selectedStrategy;
   106     private final SchedulingStrategy selectedStrategy;
    88 
   107 
    89     private final boolean immutableGraph;
   108     private final boolean immutableGraph;
   162             NodeBitMap visited = graph.createNodeBitMap();
   181             NodeBitMap visited = graph.createNodeBitMap();
   163             BlockMap<List<Node>> earliestBlockToNodesMap = new BlockMap<>(cfg);
   182             BlockMap<List<Node>> earliestBlockToNodesMap = new BlockMap<>(cfg);
   164             this.nodeToBlockMap = currentNodeMap;
   183             this.nodeToBlockMap = currentNodeMap;
   165             this.blockToNodesMap = earliestBlockToNodesMap;
   184             this.blockToNodesMap = earliestBlockToNodesMap;
   166 
   185 
   167             scheduleEarliestIterative(earliestBlockToNodesMap, currentNodeMap, visited, graph, immutableGraph);
   186             scheduleEarliestIterative(earliestBlockToNodesMap, currentNodeMap, visited, graph, immutableGraph, selectedStrategy == SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER);
   168 
   187 
   169             if (selectedStrategy != SchedulingStrategy.EARLIEST) {
   188             if (!selectedStrategy.isEarliest()) {
   170                 // For non-earliest schedules, we need to do a second pass.
   189                 // For non-earliest schedules, we need to do a second pass.
   171                 BlockMap<List<Node>> latestBlockToNodesMap = new BlockMap<>(cfg);
   190                 BlockMap<List<Node>> latestBlockToNodesMap = new BlockMap<>(cfg);
   172                 for (Block b : cfg.getBlocks()) {
   191                 for (Block b : cfg.getBlocks()) {
   173                     latestBlockToNodesMap.put(b, new ArrayList<Node>());
   192                     latestBlockToNodesMap.put(b, new ArrayList<>());
   174                 }
   193                 }
   175 
   194 
   176                 BlockMap<ArrayList<FloatingReadNode>> watchListMap = calcLatestBlocks(selectedStrategy, currentNodeMap, earliestBlockToNodesMap, visited, latestBlockToNodesMap, immutableGraph);
   195                 BlockMap<ArrayList<FloatingReadNode>> watchListMap = calcLatestBlocks(selectedStrategy, currentNodeMap, earliestBlockToNodesMap, visited, latestBlockToNodesMap, immutableGraph);
   177                 sortNodesLatestWithinBlock(cfg, earliestBlockToNodesMap, latestBlockToNodesMap, currentNodeMap, watchListMap, visited);
   196                 sortNodesLatestWithinBlock(cfg, earliestBlockToNodesMap, latestBlockToNodesMap, currentNodeMap, watchListMap, visited);
   178 
   197 
   179                 assert verifySchedule(cfg, latestBlockToNodesMap, currentNodeMap);
   198                 assert verifySchedule(cfg, latestBlockToNodesMap, currentNodeMap);
   180                 assert (!Assertions.detailedAssertionsEnabled(graph.getOptions())) || MemoryScheduleVerification.check(cfg.getStartBlock(), latestBlockToNodesMap);
   199                 assert (!Assertions.detailedAssertionsEnabled(graph.getOptions())) || MemoryScheduleVerification.check(cfg.getStartBlock(), latestBlockToNodesMap);
   181 
   200 
   182                 this.blockToNodesMap = latestBlockToNodesMap;
   201                 this.blockToNodesMap = latestBlockToNodesMap;
   183 
   202 
   184                 cfg.setNodeToBlock(currentNodeMap);
   203             }
   185             }
   204             cfg.setNodeToBlock(currentNodeMap);
   186 
   205 
   187             graph.setLastSchedule(new ScheduleResult(this.cfg, this.nodeToBlockMap, this.blockToNodesMap));
   206             graph.setLastSchedule(new ScheduleResult(this.cfg, this.nodeToBlockMap, this.blockToNodesMap));
   188         }
   207         }
   189 
   208 
   190         @SuppressFBWarnings(value = "RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE", justification = "false positive found by findbugs")
   209         @SuppressFBWarnings(value = "RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE", justification = "false positive found by findbugs")
   522                 }
   541                 }
   523 
   542 
   524                 assert latestBlock != null : currentNode;
   543                 assert latestBlock != null : currentNode;
   525 
   544 
   526                 if (strategy == SchedulingStrategy.FINAL_SCHEDULE || strategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS) {
   545                 if (strategy == SchedulingStrategy.FINAL_SCHEDULE || strategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS) {
   527                     assert latestBlock != null;
       
   528                     Block currentBlock = latestBlock;
   546                     Block currentBlock = latestBlock;
   529                     while (currentBlock.getLoopDepth() > earliestBlock.getLoopDepth() && currentBlock != earliestBlock.getDominator()) {
   547                     while (currentBlock.getLoopDepth() > earliestBlock.getLoopDepth() && currentBlock != earliestBlock.getDominator()) {
   530                         Block previousCurrentBlock = currentBlock;
   548                         Block previousCurrentBlock = currentBlock;
   531                         currentBlock = currentBlock.getDominator();
   549                         currentBlock = currentBlock.getDominator();
   532                         if (previousCurrentBlock.isLoopHeader()) {
   550                         if (previousCurrentBlock.isLoopHeader()) {
   643             /**
   661             /**
   644              * Adds a new floating node into the micro block.
   662              * Adds a new floating node into the micro block.
   645              */
   663              */
   646             public void add(Node node) {
   664             public void add(Node node) {
   647                 assert !(node instanceof FixedNode) : node;
   665                 assert !(node instanceof FixedNode) : node;
   648                 NodeEntry newTail = new NodeEntry(node, null);
   666                 NodeEntry newTail = new NodeEntry(node);
   649                 if (tail == null) {
   667                 if (tail == null) {
   650                     tail = head = newTail;
   668                     tail = head = newTail;
   651                 } else {
   669                 } else {
   652                     tail.next = newTail;
   670                     tail.next = newTail;
   653                     tail = newTail;
   671                     tail = newTail;
   657 
   675 
   658             /**
   676             /**
   659              * Number of nodes in this micro block.
   677              * Number of nodes in this micro block.
   660              */
   678              */
   661             public int getNodeCount() {
   679             public int getNodeCount() {
       
   680                 assert getActualNodeCount() == nodeCount : getActualNodeCount() + " != " + nodeCount;
   662                 return nodeCount;
   681                 return nodeCount;
       
   682             }
       
   683 
       
   684             private int getActualNodeCount() {
       
   685                 int count = 0;
       
   686                 for (NodeEntry e = head; e != null; e = e.next) {
       
   687                     count++;
       
   688                 }
       
   689                 return count;
   663             }
   690             }
   664 
   691 
   665             /**
   692             /**
   666              * The id of the micro block, with a block always associated with a lower id than its
   693              * The id of the micro block, with a block always associated with a lower id than its
   667              * successors.
   694              * successors.
   683              *
   710              *
   684              * @param newBlock the new block for the nodes
   711              * @param newBlock the new block for the nodes
   685              */
   712              */
   686             public void prependChildrenTo(MicroBlock newBlock) {
   713             public void prependChildrenTo(MicroBlock newBlock) {
   687                 if (tail != null) {
   714                 if (tail != null) {
       
   715                     assert head != null;
   688                     tail.next = newBlock.head;
   716                     tail.next = newBlock.head;
   689                     newBlock.head = head;
   717                     newBlock.head = head;
   690                     head = tail = null;
   718                     head = tail = null;
   691                     newBlock.nodeCount += nodeCount;
   719                     newBlock.nodeCount += nodeCount;
   692                     nodeCount = 0;
   720                     nodeCount = 0;
   694             }
   722             }
   695 
   723 
   696             @Override
   724             @Override
   697             public String toString() {
   725             public String toString() {
   698                 return String.format("MicroBlock[id=%d]", id);
   726                 return String.format("MicroBlock[id=%d]", id);
       
   727             }
       
   728 
       
   729             @Override
       
   730             public int hashCode() {
       
   731                 return id;
   699             }
   732             }
   700         }
   733         }
   701 
   734 
   702         /**
   735         /**
   703          * Entry in the linked list of nodes.
   736          * Entry in the linked list of nodes.
   704          */
   737          */
   705         private static class NodeEntry {
   738         private static class NodeEntry {
   706             private final Node node;
   739             private final Node node;
   707             private NodeEntry next;
   740             private NodeEntry next;
   708 
   741 
   709             NodeEntry(Node node, NodeEntry next) {
   742             NodeEntry(Node node) {
   710                 this.node = node;
   743                 this.node = node;
   711                 this.next = next;
   744                 this.next = null;
   712             }
   745             }
   713 
   746 
   714             public NodeEntry getNext() {
   747             public NodeEntry getNext() {
   715                 return next;
   748                 return next;
   716             }
   749             }
   718             public Node getNode() {
   751             public Node getNode() {
   719                 return node;
   752                 return node;
   720             }
   753             }
   721         }
   754         }
   722 
   755 
   723         private void scheduleEarliestIterative(BlockMap<List<Node>> blockToNodes, NodeMap<Block> nodeToBlock, NodeBitMap visited, StructuredGraph graph, boolean immutableGraph) {
   756         private void scheduleEarliestIterative(BlockMap<List<Node>> blockToNodes, NodeMap<Block> nodeToBlock, NodeBitMap visited, StructuredGraph graph, boolean immutableGraph,
       
   757                         boolean withGuardOrder) {
   724 
   758 
   725             NodeMap<MicroBlock> entries = graph.createNodeMap();
   759             NodeMap<MicroBlock> entries = graph.createNodeMap();
   726             NodeStack stack = new NodeStack();
   760             NodeStack stack = new NodeStack();
   727 
   761 
   728             // Initialize with fixed nodes.
   762             // Initialize with fixed nodes.
   729             MicroBlock startBlock = null;
   763             MicroBlock startBlock = null;
   730             int nextId = 1;
   764             int nextId = 1;
   731             for (Block b : cfg.reversePostOrder()) {
   765             for (Block b : cfg.reversePostOrder()) {
   732                 FixedNode current = b.getBeginNode();
   766                 for (FixedNode current : b.getBeginNode().getBlockNodes()) {
   733                 while (true) {
       
   734                     MicroBlock microBlock = new MicroBlock(nextId++);
   767                     MicroBlock microBlock = new MicroBlock(nextId++);
   735                     entries.put(current, microBlock);
   768                     entries.set(current, microBlock);
   736                     visited.checkAndMarkInc(current);
   769                     boolean isNew = visited.checkAndMarkInc(current);
   737 
   770                     assert isNew;
   738                     if (startBlock == null) {
   771                     if (startBlock == null) {
   739                         startBlock = microBlock;
   772                         startBlock = microBlock;
   740                     }
   773                     }
   741 
   774                 }
   742                     // Process inputs of this fixed node.
   775             }
   743                     for (Node input : current.inputs()) {
   776 
   744                         if (entries.get(input) == null) {
   777             if (graph.getGuardsStage().allowsFloatingGuards() && graph.getNodes(GuardNode.TYPE).isNotEmpty()) {
   745                             processStack(input, startBlock, entries, visited, stack);
   778                 // Now process guards.
   746                         }
   779                 if (GuardPriorities.getValue(graph.getOptions()) && withGuardOrder) {
   747                     }
   780                     EnumMap<GuardPriority, List<GuardNode>> guardsByPriority = new EnumMap<>(GuardPriority.class);
   748 
   781                     for (GuardNode guard : graph.getNodes(GuardNode.TYPE)) {
   749                     if (current == b.getEndNode()) {
   782                         guardsByPriority.computeIfAbsent(guard.computePriority(), p -> new ArrayList<>()).add(guard);
   750                         // Break loop when reaching end node.
   783                     }
   751                         break;
   784                     // `EnumMap.values` returns values in "natural" key order
   752                     }
   785                     for (List<GuardNode> guards : guardsByPriority.values()) {
   753 
   786                         processNodes(visited, entries, stack, startBlock, guards);
   754                     current = ((FixedWithNextNode) current).next();
   787                     }
   755                 }
   788                     GuardOrder.resortGuards(graph, entries, stack);
   756             }
   789                 } else {
   757 
   790                     processNodes(visited, entries, stack, startBlock, graph.getNodes(GuardNode.TYPE));
   758             // Now process guards.
   791                 }
   759             for (GuardNode guardNode : graph.getNodes(GuardNode.TYPE)) {
   792             } else {
   760                 if (entries.get(guardNode) == null) {
   793                 assert graph.getNodes(GuardNode.TYPE).isEmpty();
   761                     processStack(guardNode, startBlock, entries, visited, stack);
       
   762                 }
       
   763             }
   794             }
   764 
   795 
   765             // Now process inputs of fixed nodes.
   796             // Now process inputs of fixed nodes.
   766             for (Block b : cfg.reversePostOrder()) {
   797             for (Block b : cfg.reversePostOrder()) {
   767                 FixedNode current = b.getBeginNode();
   798                 for (FixedNode current : b.getBeginNode().getBlockNodes()) {
   768                 while (true) {
   799                     processNodes(visited, entries, stack, startBlock, current.inputs());
   769 
       
   770                     // Process inputs of this fixed node.
       
   771                     for (Node input : current.inputs()) {
       
   772                         if (entries.get(input) == null) {
       
   773                             processStack(input, startBlock, entries, visited, stack);
       
   774                         }
       
   775                     }
       
   776 
       
   777                     if (current == b.getEndNode()) {
       
   778                         // Break loop when reaching end node.
       
   779                         break;
       
   780                     }
       
   781 
       
   782                     current = ((FixedWithNextNode) current).next();
       
   783                 }
   800                 }
   784             }
   801             }
   785 
   802 
   786             if (visited.getCounter() < graph.getNodeCount()) {
   803             if (visited.getCounter() < graph.getNodeCount()) {
   787 
       
   788                 // Visit back input edges of loop phis.
   804                 // Visit back input edges of loop phis.
   789                 boolean changed;
   805                 boolean changed;
   790                 boolean unmarkedPhi;
   806                 boolean unmarkedPhi;
   791                 do {
   807                 do {
   792                     changed = false;
   808                     changed = false;
   827             for (Block b : cfg.reversePostOrder()) {
   843             for (Block b : cfg.reversePostOrder()) {
   828                 FixedNode fixedNode = b.getEndNode();
   844                 FixedNode fixedNode = b.getEndNode();
   829                 if (fixedNode instanceof ControlSplitNode) {
   845                 if (fixedNode instanceof ControlSplitNode) {
   830                     ControlSplitNode controlSplitNode = (ControlSplitNode) fixedNode;
   846                     ControlSplitNode controlSplitNode = (ControlSplitNode) fixedNode;
   831                     MicroBlock endBlock = entries.get(fixedNode);
   847                     MicroBlock endBlock = entries.get(fixedNode);
   832                     MicroBlock primarySuccessor = entries.get(controlSplitNode.getPrimarySuccessor());
   848                     AbstractBeginNode primarySuccessor = controlSplitNode.getPrimarySuccessor();
   833                     endBlock.prependChildrenTo(primarySuccessor);
   849                     if (primarySuccessor != null) {
   834                 }
   850                         endBlock.prependChildrenTo(entries.get(primarySuccessor));
   835             }
   851                     } else {
   836 
   852                         assert endBlock.tail == null;
   837             // Initialize with begin nodes
   853                     }
       
   854                 }
       
   855             }
       
   856 
       
   857             // Create lists for each block
   838             for (Block b : cfg.reversePostOrder()) {
   858             for (Block b : cfg.reversePostOrder()) {
   839 
   859                 // Count nodes in block
   840                 FixedNode current = b.getBeginNode();
       
   841                 int totalCount = 0;
   860                 int totalCount = 0;
   842                 while (true) {
   861                 for (FixedNode current : b.getBeginNode().getBlockNodes()) {
   843 
       
   844                     MicroBlock microBlock = entries.get(current);
   862                     MicroBlock microBlock = entries.get(current);
   845                     totalCount += microBlock.getNodeCount() + 1;
   863                     totalCount += microBlock.getNodeCount() + 1;
   846 
       
   847                     if (current == b.getEndNode()) {
       
   848                         // Break loop when reaching end node.
       
   849                         break;
       
   850                     }
       
   851 
       
   852                     current = ((FixedWithNextNode) current).next();
       
   853                 }
   864                 }
   854 
   865 
   855                 // Initialize with begin node, it is always the first node.
   866                 // Initialize with begin node, it is always the first node.
   856                 ArrayList<Node> nodes = new ArrayList<>(totalCount);
   867                 ArrayList<Node> nodes = new ArrayList<>(totalCount);
   857                 blockToNodes.put(b, nodes);
   868                 blockToNodes.put(b, nodes);
   858 
   869 
   859                 current = b.getBeginNode();
   870                 for (FixedNode current : b.getBeginNode().getBlockNodes()) {
   860                 while (true) {
       
   861 
       
   862                     MicroBlock microBlock = entries.get(current);
   871                     MicroBlock microBlock = entries.get(current);
   863                     nodeToBlock.set(current, b);
   872                     nodeToBlock.set(current, b);
   864                     nodes.add(current);
   873                     nodes.add(current);
   865                     NodeEntry next = microBlock.getFirstNode();
   874                     NodeEntry next = microBlock.getFirstNode();
   866                     while (next != null) {
   875                     while (next != null) {
   867                         Node nextNode = next.getNode();
   876                         Node nextNode = next.getNode();
   868                         nodeToBlock.set(nextNode, b);
   877                         nodeToBlock.set(nextNode, b);
   869                         nodes.add(nextNode);
   878                         nodes.add(nextNode);
   870                         next = next.getNext();
   879                         next = next.getNext();
   871                     }
   880                     }
   872 
       
   873                     if (current == b.getEndNode()) {
       
   874                         // Break loop when reaching end node.
       
   875                         break;
       
   876                     }
       
   877 
       
   878                     current = ((FixedWithNextNode) current).next();
       
   879                 }
   881                 }
   880             }
   882             }
   881 
   883 
   882             assert (!Assertions.detailedAssertionsEnabled(cfg.graph.getOptions())) || MemoryScheduleVerification.check(cfg.getStartBlock(), blockToNodes);
   884             assert (!Assertions.detailedAssertionsEnabled(cfg.graph.getOptions())) || MemoryScheduleVerification.check(cfg.getStartBlock(), blockToNodes);
       
   885         }
       
   886 
       
   887         private static void processNodes(NodeBitMap visited, NodeMap<MicroBlock> entries, NodeStack stack, MicroBlock startBlock, Iterable<? extends Node> nodes) {
       
   888             for (Node node : nodes) {
       
   889                 if (entries.get(node) == null) {
       
   890                     processStack(node, startBlock, entries, visited, stack);
       
   891                 }
       
   892             }
   883         }
   893         }
   884 
   894 
   885         private static void processStackPhi(NodeStack stack, PhiNode phiNode, NodeMap<MicroBlock> nodeToBlock, NodeBitMap visited) {
   895         private static void processStackPhi(NodeStack stack, PhiNode phiNode, NodeMap<MicroBlock> nodeToBlock, NodeBitMap visited) {
   886             stack.pop();
   896             stack.pop();
   887             if (visited.checkAndMarkInc(phiNode)) {
   897             if (visited.checkAndMarkInc(phiNode)) {
   942                 }
   952                 }
   943                 current = stack.peek();
   953                 current = stack.peek();
   944             }
   954             }
   945         }
   955         }
   946 
   956 
       
   957         private static class GuardOrder {
       
   958             /**
       
   959              * After an earliest schedule, this will re-sort guards to honor their
       
   960              * {@linkplain StaticDeoptimizingNode#computePriority() priority}.
       
   961              *
       
   962              * Note that this only changes the order of nodes within {@linkplain MicroBlock
       
   963              * micro-blocks}, nodes will not be moved from one micro-block to another.
       
   964              */
       
   965             private static void resortGuards(StructuredGraph graph, NodeMap<MicroBlock> entries, NodeStack stack) {
       
   966                 assert stack.isEmpty();
       
   967                 EconomicSet<MicroBlock> blocksWithGuards = EconomicSet.create(IDENTITY);
       
   968                 for (GuardNode guard : graph.getNodes(GuardNode.TYPE)) {
       
   969                     MicroBlock block = entries.get(guard);
       
   970                     assert block != null : guard + "should already be scheduled to a micro-block";
       
   971                     blocksWithGuards.add(block);
       
   972                 }
       
   973                 assert !blocksWithGuards.isEmpty();
       
   974                 NodeMap<GuardPriority> priorities = graph.createNodeMap();
       
   975                 NodeBitMap blockNodes = graph.createNodeBitMap();
       
   976                 for (MicroBlock block : blocksWithGuards) {
       
   977                     MicroBlock newBlock = resortGuards(block, stack, blockNodes, priorities);
       
   978                     assert stack.isEmpty();
       
   979                     assert blockNodes.isEmpty();
       
   980                     if (newBlock != null) {
       
   981                         assert block.getNodeCount() == newBlock.getNodeCount();
       
   982                         block.head = newBlock.head;
       
   983                         block.tail = newBlock.tail;
       
   984                     }
       
   985                 }
       
   986             }
       
   987 
       
   988             /**
       
   989              * This resorts guards within one micro-block.
       
   990              *
       
   991              * {@code stack}, {@code blockNodes} and {@code priorities} are just temporary
       
   992              * data-structures which are allocated once by the callers of this method. They should
       
   993              * be in their "initial"/"empty" state when calling this method and when it returns.
       
   994              */
       
   995             private static MicroBlock resortGuards(MicroBlock block, NodeStack stack, NodeBitMap blockNodes, NodeMap<GuardPriority> priorities) {
       
   996                 if (!propagatePriority(block, stack, priorities, blockNodes)) {
       
   997                     return null;
       
   998                 }
       
   999 
       
  1000                 Function<GuardNode, GuardPriority> transitiveGuardPriorityGetter = priorities::get;
       
  1001                 Comparator<GuardNode> globalGuardPriorityComparator = Comparator.comparing(transitiveGuardPriorityGetter).thenComparing(GuardNode::computePriority).thenComparingInt(Node::hashCode);
       
  1002 
       
  1003                 SortedSet<GuardNode> availableGuards = new TreeSet<>(globalGuardPriorityComparator);
       
  1004                 MicroBlock newBlock = new MicroBlock(block.getId());
       
  1005 
       
  1006                 NodeBitMap sorted = blockNodes;
       
  1007                 sorted.invert();
       
  1008 
       
  1009                 for (NodeEntry e = block.head; e != null; e = e.next) {
       
  1010                     checkIfAvailable(e.node, stack, sorted, newBlock, availableGuards, false);
       
  1011                 }
       
  1012                 do {
       
  1013                     while (!stack.isEmpty()) {
       
  1014                         checkIfAvailable(stack.pop(), stack, sorted, newBlock, availableGuards, true);
       
  1015                     }
       
  1016                     Iterator<GuardNode> iterator = availableGuards.iterator();
       
  1017                     if (iterator.hasNext()) {
       
  1018                         addNodeToResort(iterator.next(), stack, sorted, newBlock, true);
       
  1019                         iterator.remove();
       
  1020                     }
       
  1021                 } while (!stack.isEmpty() || !availableGuards.isEmpty());
       
  1022 
       
  1023                 blockNodes.clearAll();
       
  1024                 return newBlock;
       
  1025             }
       
  1026 
       
  1027             /**
       
  1028              * This checks if {@code n} can be scheduled, if it is the case, it schedules it now by
       
  1029              * calling {@link #addNodeToResort(Node, NodeStack, NodeBitMap, MicroBlock, boolean)}.
       
  1030              */
       
  1031             private static void checkIfAvailable(Node n, NodeStack stack, NodeBitMap sorted, Instance.MicroBlock newBlock, SortedSet<GuardNode> availableGuardNodes, boolean pushUsages) {
       
  1032                 if (sorted.isMarked(n)) {
       
  1033                     return;
       
  1034                 }
       
  1035                 for (Node in : n.inputs()) {
       
  1036                     if (!sorted.isMarked(in)) {
       
  1037                         return;
       
  1038                     }
       
  1039                 }
       
  1040                 if (n instanceof GuardNode) {
       
  1041                     availableGuardNodes.add((GuardNode) n);
       
  1042                 } else {
       
  1043                     addNodeToResort(n, stack, sorted, newBlock, pushUsages);
       
  1044                 }
       
  1045             }
       
  1046 
       
  1047             /**
       
  1048              * Add a node to the re-sorted micro-block. This also pushes nodes that need to be
       
  1049              * (re-)examined on the stack.
       
  1050              */
       
  1051             private static void addNodeToResort(Node n, NodeStack stack, NodeBitMap sorted, MicroBlock newBlock, boolean pushUsages) {
       
  1052                 sorted.mark(n);
       
  1053                 newBlock.add(n);
       
  1054                 if (pushUsages) {
       
  1055                     for (Node u : n.usages()) {
       
  1056                         if (!sorted.isMarked(u)) {
       
  1057                             stack.push(u);
       
  1058                         }
       
  1059                     }
       
  1060                 }
       
  1061             }
       
  1062 
       
  1063             /**
       
  1064              * This fills in a map of transitive priorities ({@code priorities}). It also marks the
       
  1065              * nodes from this micro-block in {@code blockNodes}.
       
  1066              *
       
  1067              * The transitive priority of a guard is the highest of its priority and the priority of
       
  1068              * the guards that depend on it (transitively).
       
  1069              *
       
  1070              * This method returns {@code false} if no re-ordering is necessary in this micro-block.
       
  1071              */
       
  1072             private static boolean propagatePriority(MicroBlock block, NodeStack stack, NodeMap<GuardPriority> priorities, NodeBitMap blockNodes) {
       
  1073                 assert stack.isEmpty();
       
  1074                 assert blockNodes.isEmpty();
       
  1075                 GuardPriority lowestPriority = GuardPriority.highest();
       
  1076                 for (NodeEntry e = block.head; e != null; e = e.next) {
       
  1077                     blockNodes.mark(e.node);
       
  1078                     if (e.node instanceof GuardNode) {
       
  1079                         GuardNode guard = (GuardNode) e.node;
       
  1080                         GuardPriority priority = guard.computePriority();
       
  1081                         if (lowestPriority != null) {
       
  1082                             if (priority.isLowerPriorityThan(lowestPriority)) {
       
  1083                                 lowestPriority = priority;
       
  1084                             } else if (priority.isHigherPriorityThan(lowestPriority)) {
       
  1085                                 lowestPriority = null;
       
  1086                             }
       
  1087                         }
       
  1088                         stack.push(guard);
       
  1089                         priorities.set(guard, priority);
       
  1090                     }
       
  1091                 }
       
  1092                 if (lowestPriority != null) {
       
  1093                     stack.clear();
       
  1094                     blockNodes.clearAll();
       
  1095                     return false;
       
  1096                 }
       
  1097 
       
  1098                 do {
       
  1099                     Node current = stack.pop();
       
  1100                     assert blockNodes.isMarked(current);
       
  1101                     GuardPriority priority = priorities.get(current);
       
  1102                     for (Node input : current.inputs()) {
       
  1103                         if (!blockNodes.isMarked(input)) {
       
  1104                             continue;
       
  1105                         }
       
  1106                         GuardPriority inputPriority = priorities.get(input);
       
  1107                         if (inputPriority == null || inputPriority.isLowerPriorityThan(priority)) {
       
  1108                             priorities.set(input, priority);
       
  1109                             stack.push(input);
       
  1110                         }
       
  1111                     }
       
  1112                 } while (!stack.isEmpty());
       
  1113                 return true;
       
  1114             }
       
  1115         }
       
  1116 
   947         /**
  1117         /**
   948          * Processes the inputs of given block. Pushes unprocessed inputs onto the stack. Returns
  1118          * Processes the inputs of given block. Pushes unprocessed inputs onto the stack. Returns
   949          * null if there were still unprocessed inputs, otherwise returns the earliest block given
  1119          * null if there were still unprocessed inputs, otherwise returns the earliest block given
   950          * node can be scheduled in.
  1120          * node can be scheduled in.
   951          */
  1121          */
   958             for (Node input : current.inputs()) {
  1128             for (Node input : current.inputs()) {
   959                 MicroBlock inputBlock = nodeToBlock.get(input);
  1129                 MicroBlock inputBlock = nodeToBlock.get(input);
   960                 if (inputBlock == null) {
  1130                 if (inputBlock == null) {
   961                     earliestBlock = null;
  1131                     earliestBlock = null;
   962                     stack.push(input);
  1132                     stack.push(input);
   963                 } else if (earliestBlock != null && inputBlock.getId() >= earliestBlock.getId()) {
  1133                 } else if (earliestBlock != null && inputBlock.getId() > earliestBlock.getId()) {
   964                     earliestBlock = inputBlock;
  1134                     earliestBlock = inputBlock;
   965                 }
  1135                 }
   966             }
  1136             }
   967             return earliestBlock;
  1137             return earliestBlock;
   968         }
  1138         }