diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/DerivedOffsetInductionVariable.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/DerivedOffsetInductionVariable.java index e4f68c70adc7..e1427ba4a598 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/DerivedOffsetInductionVariable.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/DerivedOffsetInductionVariable.java @@ -85,6 +85,16 @@ public boolean isConstantInit() { @Override public boolean isConstantStride() { + if (isMaskedNegateStride()) { + if (base.isConstantStride()) { + try { + LoopUtility.multiplyExact(IntegerStamp.getBits(offset.stamp(NodeView.DEFAULT)), base.constantStride(), -1); + return true; + } catch (ArithmeticException e) { + return false; + } + } + } return base.isConstantStride(); } @@ -103,12 +113,31 @@ public long constantStride() { } private long constantStrideSafe() throws ArithmeticException { - if (value instanceof SubNode && base.valueNode() == value.getY()) { + if (isMaskedNegateStride()) { return LoopUtility.multiplyExact(IntegerStamp.getBits(offset.stamp(NodeView.DEFAULT)), base.constantStride(), -1); } return base.constantStride(); } + /** + * Determine if the current induction variable's stride is actually one that represents a + * negation instead of a normal offset calculation. For example + * + *
+     * int i = 0;
+     * while (i < limit) {
+     *     int reversIv = off - i;
+     *     i++;
+     * }
+     * 
+ * + * here {@code reverseIv} stride node is actually {@code i} negated since the IV is not + * {@code i op off} but {@code off op i} where {@code op} is a subtraction. + */ + private boolean isMaskedNegateStride() { + return value instanceof SubNode && base.valueNode() == value.getY(); + } + @Override public boolean isConstantExtremum() { try {