Skip to content

Commit 812049f

Browse files
committed
[GR-51666] Backport to 24.0: Use safe abs in loop opts.
PullRequest: graal/16925
2 parents 738a5e0 + 917983d commit 812049f

File tree

3 files changed

+46
-5
lines changed

3 files changed

+46
-5
lines changed

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/LoopPredicationPhase.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,8 @@ protected void run(StructuredGraph graph, MidTierContext context) {
112112
final InductionVariable counter = counted.getLimitCheckedIV();
113113
final Condition condition = ((CompareNode) counted.getLimitTest().condition()).condition().asCondition();
114114
final boolean inverted = loop.counted().isInverted();
115-
if ((((IntegerStamp) counter.valueNode().stamp(NodeView.DEFAULT)).getBits() == 32) &&
116-
!counted.isUnsignedCheck() &&
117-
((condition != NE && condition != EQ) || (counter.isConstantStride() && Math.abs(counter.constantStride()) == 1)) &&
115+
if ((((IntegerStamp) counter.valueNode().stamp(NodeView.DEFAULT)).getBits() == 32) && !counted.isUnsignedCheck() &&
116+
((condition != NE && condition != EQ) || (counter.isConstantStride() && LoopEx.absStrideIsOne(counter))) &&
118117
(loop.loopBegin().isMainLoop() || loop.loopBegin().isSimpleLoop())) {
119118
NodeIterable<GuardNode> guards = loop.whole().nodes().filter(GuardNode.class);
120119
if (LoopPredicationMainPath.getValue(graph.getOptions())) {

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/LoopEx.java

+11-2
Original file line numberDiff line numberDiff line change
@@ -334,15 +334,15 @@ public boolean detectCounted() {
334334
// signed: i < MAX_INT
335335
} else if (limitStamp.asConstant() != null && limitStamp.asConstant().asLong() == counterStamp.unsignedUpperBound()) {
336336
unsigned = true;
337-
} else if (!iv.isConstantStride() || Math.abs(iv.constantStride()) != 1 || initStamp.upperBound() > limitStamp.lowerBound()) {
337+
} else if (!iv.isConstantStride() || !absStrideIsOne(iv) || initStamp.upperBound() > limitStamp.lowerBound()) {
338338
return false;
339339
}
340340
} else if (iv.direction() == InductionVariable.Direction.Down) {
341341
if (limitStamp.asConstant() != null && limitStamp.asConstant().asLong() == counterStamp.lowerBound()) {
342342
// signed: MIN_INT > i
343343
} else if (limitStamp.asConstant() != null && limitStamp.asConstant().asLong() == counterStamp.unsignedLowerBound()) {
344344
unsigned = true;
345-
} else if (!iv.isConstantStride() || Math.abs(iv.constantStride()) != 1 || initStamp.lowerBound() < limitStamp.upperBound()) {
345+
} else if (!iv.isConstantStride() || !absStrideIsOne(iv) || initStamp.lowerBound() < limitStamp.upperBound()) {
346346
return false;
347347
}
348348
} else {
@@ -389,6 +389,15 @@ public boolean detectCounted() {
389389
return false;
390390
}
391391

392+
public static boolean absStrideIsOne(InductionVariable limitCheckedIV) {
393+
/*
394+
* While Math.abs can overflow for MIN_VALUE it is fine here. In case of overflow we still
395+
* get a value != 1 (namely MIN_VALUE again). Overflow handling for the limit checked IV is
396+
* done in CountedLoopInfo and is an orthogonal issue.
397+
*/
398+
return Math.abs(limitCheckedIV.constantStride()) == 1;
399+
}
400+
392401
public boolean isCfgLoopExit(AbstractBeginNode begin) {
393402
HIRBlock block = data.getCFG().blockFor(begin);
394403
return loop.getDepth() > block.getLoopDepth() || loop.isNaturalExit(block);

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/util/LoopUtility.java

+33
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import jdk.graal.compiler.core.common.cfg.Loop;
3030
import jdk.graal.compiler.core.common.type.IntegerStamp;
3131
import jdk.graal.compiler.core.common.type.Stamp;
32+
import jdk.graal.compiler.debug.GraalError;
3233
import jdk.graal.compiler.graph.Graph.NodeEvent;
3334
import jdk.graal.compiler.graph.Graph.NodeEventScope;
3435
import jdk.graal.compiler.graph.Node;
@@ -54,6 +55,38 @@
5455

5556
public class LoopUtility {
5657

58+
public static boolean canTakeAbs(long l, int bits) {
59+
try {
60+
abs(l, bits);
61+
return true;
62+
} catch (ArithmeticException e) {
63+
return false;
64+
}
65+
}
66+
67+
/**
68+
* Compute {@link Math#abs(long)} for the given arguments and the given bit size. Throw a
69+
* {@link ArithmeticException} if the abs operation would overflow.
70+
*/
71+
public static long abs(long l, int bits) throws ArithmeticException {
72+
if (bits == 32) {
73+
if (l == Integer.MIN_VALUE) {
74+
throw new ArithmeticException("Abs on Integer.MIN_VALUE would cause an overflow because abs(Integer.MIN_VALUE) = Integer.MAX_VALUE + 1 which does not fit in int (32 bits)");
75+
} else {
76+
final int i = (int) l;
77+
return Math.abs(i);
78+
}
79+
} else if (bits == 64) {
80+
if (l == Long.MIN_VALUE) {
81+
throw new ArithmeticException("Abs on Long.MIN_VALUE would cause an overflow because abs(Long.MIN_VALUE) = Long.MAX_VALUE + 1 which does not fit in long (64 bits)");
82+
} else {
83+
return Math.abs(l);
84+
}
85+
} else {
86+
throw GraalError.shouldNotReachHere("Must be one of java's core datatypes int/long but is " + bits);
87+
}
88+
}
89+
5790
/**
5891
* Determine if the def can use node {@code use} without the need for value proxies. This means
5992
* there is no loop exit between the schedule point of def and use that would require a

0 commit comments

Comments
 (0)