diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/FloatDivNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/FloatDivNode.java index 5143d98730f8..d59ae612adfe 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/FloatDivNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/FloatDivNode.java @@ -24,7 +24,7 @@ */ package jdk.graal.compiler.nodes.calc; -import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_32; +import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_16; import jdk.graal.compiler.core.common.type.ArithmeticOpTable; import jdk.graal.compiler.core.common.type.ArithmeticOpTable.BinaryOp; @@ -41,7 +41,10 @@ import jdk.vm.ci.meta.Constant; -@NodeInfo(shortName = "/", cycles = CYCLES_32) +/** + * Floating point division node. + */ +@NodeInfo(shortName = "/", cycles = CYCLES_16, cyclesRationale = "The node cycle estimate is taken from Agner Fog's instruction tables (https://www.agner.org/optimize/instruction_tables.pdf).") public class FloatDivNode extends BinaryArithmeticNode
+ * Example: + *
+ * + *
+ * b = some calculation
+ * if (a) {
+ * some calculation using b
+ * }
+ * // no further usages of b
+ *
+ *
+ * + * In this example, deferring the calculation of 'b' until it's actually needed reduces its + * execution frequency, resulting in improved performance. + *
+ */ LATEST, + + /** + * Similar to {@link #LATEST}, but ensures that nodes are not scheduled into loops. This + * balances the benefits of early and late scheduling. + */ LATEST_OUT_OF_LOOPS, - LATEST_OUT_OF_LOOPS_IMPLICIT_NULL_CHECKS; + + /** + * Extends {@link #LATEST_OUT_OF_LOOPS} by actively preserving implicit null checks, to + * reduce memory access. + * + *+ * An implicit null check occurs when a null check is folded into a memory access operation. + * For example, accessing a field on a potentially null object reference implicitly checks + * for null and throws a NullPointerException if the object is null. + * + *
+ * Consider the following example: + * (1) read(a.length) // implicit null check of 'a' + * (2) read(a.sth) // requires 'a' to be non-null + * + * Preserving implicit null checks ensures that (1) remains before (2) in the execution order. + * If (2) is reordered before (1), an additional explicit null check is required before (2). + *+ * + *
+ * This optimization helps reduce the number of null checks required. + */ + LATEST_OUT_OF_LOOPS_IMPLICIT_NULL_CHECKS, + + /** + * This scheduling is run after {@link FinalSchedulePhase} to reduce register pressure or + * latency by reordering the nodes within a {@link HIRBlock}. + */ + BASIC_BLOCK_LOCAL_SCHEDULING; public boolean isEarliest() { return this == EARLIEST || this == EARLIEST_WITH_GUARD_ORDER; @@ -113,6 +189,10 @@ public boolean isLatest() { return !isEarliest(); } + public boolean isBasicBlockLocalScheduling() { + return this == BASIC_BLOCK_LOCAL_SCHEDULING; + } + public boolean scheduleOutOfLoops() { return this == LATEST_OUT_OF_LOOPS || this == LATEST_OUT_OF_LOOPS_IMPLICIT_NULL_CHECKS; }