Skip to content

Commit 99928a1

Browse files
committed
Improve specializations with overflow handling
Use inlined version of the corresponding exact arithmetic operation and return a PInt in case of an overflow. This avoids unnecessary allocations of BigIntegers and PInts.
1 parent 6be4142 commit 99928a1

File tree

1 file changed

+34
-10
lines changed
  • graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints

1 file changed

+34
-10
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntBuiltins.java

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,14 @@ long addLong(long left, long right) {
163163
}
164164

165165
@Specialization
166-
PInt addPInt(long left, long right) {
167-
return factory().createInt(op(PInt.longToBigInteger(left), PInt.longToBigInteger(right)));
166+
Object addLongWithOverflow(long x, long y) {
167+
/* Inlined version of Math.addExact(x, y) with BigInteger fallback. */
168+
long r = x + y;
169+
// HD 2-12 Overflow iff both arguments have the opposite sign of the result
170+
if (((x ^ r) & (y ^ r)) < 0) {
171+
return factory().createInt(op(PInt.longToBigInteger(x), PInt.longToBigInteger(y)));
172+
}
173+
return r;
168174
}
169175

170176
@Specialization
@@ -220,8 +226,15 @@ long doLL(long x, long y) throws ArithmeticException {
220226
}
221227

222228
@Specialization
223-
PInt doLLOvf(long x, long y) {
224-
return factory().createInt(op(PInt.longToBigInteger(x), PInt.longToBigInteger(y)));
229+
Object doLongWithOverflow(long x, long y) {
230+
/* Inlined version of Math.subtractExact(x, y) with BigInteger fallback. */
231+
long r = x - y;
232+
// HD 2-12 Overflow iff the arguments have different signs and
233+
// the sign of the result is different than the sign of x
234+
if (((x ^ y) & (x ^ r)) < 0) {
235+
return factory().createInt(op(PInt.longToBigInteger(x), PInt.longToBigInteger(y)));
236+
}
237+
return r;
225238
}
226239

227240
@Specialization
@@ -272,8 +285,15 @@ long doLL(long y, long x) throws ArithmeticException {
272285
}
273286

274287
@Specialization
275-
PInt doLLOvf(long y, long x) {
276-
return factory().createInt(op(PInt.longToBigInteger(x), PInt.longToBigInteger(y)));
288+
Object doLongWithOverflow(long y, long x) {
289+
/* Inlined version of Math.subtractExact(x, y) with BigInteger fallback. */
290+
long r = x - y;
291+
// HD 2-12 Overflow iff the arguments have different signs and
292+
// the sign of the result is different than the sign of x
293+
if (((x ^ y) & (x ^ r)) < 0) {
294+
return factory().createInt(op(PInt.longToBigInteger(x), PInt.longToBigInteger(y)));
295+
}
296+
return r;
277297
}
278298

279299
@Specialization
@@ -642,17 +662,21 @@ long doLL(long x, long y) {
642662
}
643663

644664
@Specialization
645-
PInt doLLOvf(long x, long y) {
665+
Object doLongWithOverflow(long x, long y) {
666+
/* Inlined version of Math.multiplyExact(x, y) with BigInteger fallback. */
646667
long r = x * y;
647668
long ax = Math.abs(x);
648669
long ay = Math.abs(y);
649670
if (((ax | ay) >>> 31 != 0)) {
650-
int leadingZeros = Long.numberOfLeadingZeros(ax) + Long.numberOfLeadingZeros(ay);
651-
if (leadingZeros < 66) {
671+
// Some bits greater than 2^31 that might cause overflow
672+
// Check the result using the divide operator
673+
// and check for the special case of Long.MIN_VALUE * -1
674+
if (((y != 0) && (r / y != x)) ||
675+
(x == Long.MIN_VALUE && y == -1)) {
652676
return factory().createInt(mul(PInt.longToBigInteger(x), PInt.longToBigInteger(y)));
653677
}
654678
}
655-
return factory().createInt(r);
679+
return r;
656680
}
657681

658682
@Specialization(guards = "right == 0")

0 commit comments

Comments
 (0)