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; |
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") |
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 */ |