9898
9999public final class SchedulePhase extends BasePhase <CoreProviders > {
100100
101+ /**
102+ * Defines the strategies for scheduling nodes in the compiler's intermediate representation.
103+ * The chosen strategy affects the order in which nodes are executed, impacting performance and
104+ * potentially the effectiveness of other optimizations.
105+ */
101106 public enum SchedulingStrategy {
102- EARLIEST_WITH_GUARD_ORDER ,
107+
108+ /**
109+ * Schedules nodes in the earliest possible block. This minimizes the distance between a
110+ * node's definition and its usage, reducing register pressure. It can also move nodes out
111+ * of loops, decreasing the number of times they are executed. However, if a node is moved
112+ * out of a conditional execution (e.g. an if) into the dominating block, it will always be
113+ * executed, even if the condition is not satisfied, thereby increasing the number of times
114+ * it is executed. In general this effect seems to be greater than the efficiency gains, by
115+ * scheduling nodes out of loops.
116+ */
103117 EARLIEST ,
118+
119+ /**
120+ * Similar to {@link #EARLIEST}, but preserves the original order of guards. This ensures
121+ * that guard-related nodes are not reordered, maintaining the original guarding behavior.
122+ */
123+ EARLIEST_WITH_GUARD_ORDER ,
124+
125+ /**
126+ * Schedules nodes in the latest possible block to minimize unnecessary executions, thereby
127+ * reducing register pressure and the number of node executions. However, when sinking a
128+ * usage into a loop, this may lead to increased executions and register pressure.
129+ *
130+ * <p>
131+ * Example:
132+ * </p>
133+ *
134+ * <pre>
135+ * b = some calculation
136+ * if (a) {
137+ * some calculation using b
138+ * }
139+ * // no further usages of b
140+ * </pre>
141+ *
142+ * <p>
143+ * In this example, deferring the calculation of 'b' until it's actually needed reduces its
144+ * execution frequency, resulting in improved performance.
145+ * </p>
146+ */
104147 LATEST ,
148+
149+ /**
150+ * Similar to {@link #LATEST}, but ensures that nodes are not scheduled into loops. This
151+ * balances the benefits of early and late scheduling.
152+ */
105153 LATEST_OUT_OF_LOOPS ,
106- LATEST_OUT_OF_LOOPS_IMPLICIT_NULL_CHECKS ;
154+
155+ /**
156+ * Extends {@link #LATEST_OUT_OF_LOOPS} by actively preserving implicit null checks, to
157+ * reduce memory access.
158+ *
159+ * <p>
160+ * An implicit null check occurs when a null check is folded into a memory access operation.
161+ * For example, accessing a field on a potentially null object reference implicitly checks
162+ * for null and throws a NullPointerException if the object is null.
163+ *
164+ * <pre>
165+ * Consider the following example:
166+ * (1) read(a.length) // implicit null check of 'a'
167+ * (2) read(a.sth) // requires 'a' to be non-null
168+ *
169+ * Preserving implicit null checks ensures that (1) remains before (2) in the execution order.
170+ * If (2) is reordered before (1), an additional explicit null check is required before (2).
171+ * </pre>
172+ *
173+ * <p>
174+ * This optimization helps reduce the number of null checks required.
175+ */
176+ LATEST_OUT_OF_LOOPS_IMPLICIT_NULL_CHECKS ,
177+
178+ /**
179+ * This scheduling is run after {@link FinalSchedulePhase} to reduce register pressure or
180+ * latency by reordering the nodes within a {@link HIRBlock}.
181+ */
182+ BASIC_BLOCK_LOCAL_SCHEDULING ;
107183
108184 public boolean isEarliest () {
109185 return this == EARLIEST || this == EARLIEST_WITH_GUARD_ORDER ;
@@ -113,6 +189,10 @@ public boolean isLatest() {
113189 return !isEarliest ();
114190 }
115191
192+ public boolean isBasicBlockLocalScheduling () {
193+ return this == BASIC_BLOCK_LOCAL_SCHEDULING ;
194+ }
195+
116196 public boolean scheduleOutOfLoops () {
117197 return this == LATEST_OUT_OF_LOOPS || this == LATEST_OUT_OF_LOOPS_IMPLICIT_NULL_CHECKS ;
118198 }
0 commit comments