| // Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| package com.android.tools.r8.ir.desugar.backports; |
| |
| public final class MathMethods { |
| |
| public static int addExactInt(int x, int y) { |
| long longResult = (long) x + y; |
| int intResult = (int) longResult; |
| if (longResult == intResult) { |
| return intResult; |
| } |
| throw new ArithmeticException(); |
| } |
| |
| public static long addExactLong(long x, long y) { |
| long result = x + y; |
| if ((x ^ y) < 0L | (x ^ result) >= 0L) { |
| return result; |
| } |
| throw new ArithmeticException(); |
| } |
| |
| public static int decrementExactInt(int value) { |
| if (value == Integer.MIN_VALUE) { |
| throw new ArithmeticException(); |
| } |
| return value - 1; |
| } |
| |
| public static long decrementExactLong(long value) { |
| if (value == Long.MIN_VALUE) { |
| throw new ArithmeticException(); |
| } |
| return value - 1L; |
| } |
| |
| public static int floorDivInt(int dividend, int divisor) { |
| int div = dividend / divisor; |
| int rem = dividend - divisor * div; |
| if (rem == 0) { |
| return div; |
| } |
| // Normal Java division rounds towards 0. We just have to deal with the cases where rounding |
| // towards 0 is wrong, which typically depends on the sign of dividend / divisor. |
| // |
| // signum is 1 if dividend and divisor are both nonnegative or negative, and -1 otherwise. |
| int signum = 1 | ((dividend ^ divisor) >> (Integer.SIZE - 1)); |
| return signum < 0 ? div - 1 : div; |
| } |
| |
| public static long floorDivLong(long dividend, long divisor) { |
| long div = dividend / divisor; |
| long rem = dividend - divisor * div; |
| if (rem == 0L) { |
| return div; |
| } |
| // Normal Java division rounds towards 0. We just have to deal with the cases where rounding |
| // towards 0 is wrong, which typically depends on the sign of dividend / divisor. |
| // |
| // signum is 1 if dividend and divisor are both nonnegative or negative, and -1 otherwise. |
| long signum = 1L | ((dividend ^ divisor) >> (Long.SIZE - 1)); |
| return signum < 0L ? div - 1L : div; |
| } |
| |
| public static long floorDivLongInt(long dividend, int divisor) { |
| return Math.floorDiv(dividend, (long) divisor); |
| } |
| |
| public static int floorModInt(int dividend, int divisor) { |
| int rem = dividend % divisor; |
| if (rem == 0) { |
| return 0; |
| } |
| // Normal Java remainder tracks the sign of the dividend. We just have to deal with the case |
| // where the resulting sign is incorrect which is when the signs do not match. |
| // |
| // signum is 1 if dividend and divisor are both nonnegative or negative, and -1 otherwise. |
| int signum = 1 | ((dividend ^ divisor) >> (Integer.SIZE - 1)); |
| return signum > 0 ? rem : rem + divisor; |
| } |
| |
| public static long floorModLong(long dividend, long divisor) { |
| long rem = dividend % divisor; |
| if (rem == 0L) { |
| return 0L; |
| } |
| // Normal Java remainder tracks the sign of the dividend. We just have to deal with the case |
| // where the resulting sign is incorrect which is when the signs do not match. |
| // |
| // signum is 1 if dividend and divisor are both nonnegative or negative, and -1 otherwise. |
| long signum = 1L | ((dividend ^ divisor) >> (Long.SIZE - 1)); |
| return signum > 0L ? rem : rem + divisor; |
| } |
| |
| public static int floorModLongInt(long dividend, int divisor) { |
| return (int) Math.floorMod(dividend, (long) divisor); |
| } |
| |
| public static int incrementExactInt(int value) { |
| if (value == Integer.MAX_VALUE) { |
| throw new ArithmeticException(); |
| } |
| return value + 1; |
| } |
| |
| public static long incrementExactLong(long value) { |
| if (value == Long.MAX_VALUE) { |
| throw new ArithmeticException(); |
| } |
| return value + 1; |
| } |
| |
| public static int multiplyExactInt(int x, int y) { |
| long longResult = (long) x * y; |
| int intResult = (int) longResult; |
| if (longResult == intResult) { |
| return intResult; |
| } |
| throw new ArithmeticException(); |
| } |
| |
| public static long multiplyExactLong(long x, long y) { |
| // Hacker's Delight, Section 2-12 |
| int leadingZeros = |
| Long.numberOfLeadingZeros(x) |
| + Long.numberOfLeadingZeros(~x) |
| + Long.numberOfLeadingZeros(y) |
| + Long.numberOfLeadingZeros(~y); |
| |
| // If leadingZeros > Long.SIZE + 1 it's definitely fine, if it's < Long.SIZE it's definitely |
| // bad. We do the leadingZeros check to avoid the division below if at all possible. |
| // |
| // Otherwise, if y == Long.MIN_VALUE, then the only allowed values of x are 0 and 1. We take |
| // care of all x < 0 with their own check, because in particular, the case x == -1 will |
| // incorrectly pass the division check below. |
| // |
| // In all other cases, we check that either x is 0 or the result is consistent with division. |
| if (leadingZeros > Long.SIZE + 1) { |
| return x * y; |
| } |
| if (leadingZeros >= Long.SIZE && (x >= 0 | y != Long.MIN_VALUE)) { |
| long result = x * y; |
| if (x == 0 || result / x == y) { |
| return result; |
| } |
| } |
| throw new ArithmeticException(); |
| } |
| |
| public static long multiplyExactLongInt(long x, int y) { |
| return Math.multiplyExact(x, (long) y); |
| } |
| |
| public static long multiplyFull(int x, int y) { |
| return (long) x * y; |
| } |
| |
| public static long multiplyHigh(long x, long y) { |
| // Adapted from Hacker's Delight (2nd ed), 8-2. |
| long xLow = x & 0xFFFFFFFFL; |
| long xHigh = x >> 32; |
| long yLow = y & 0xFFFFFFFFL; |
| long yHigh = y >> 32; |
| |
| long lowLow = xLow * yLow; |
| long lowLowCarry = lowLow >>> 32; |
| |
| long highLow = xHigh * yLow; |
| long mid1 = highLow + lowLowCarry; |
| long mid1Low = mid1 & 0xFFFFFFFFL; |
| long mid1High = mid1 >> 32; |
| |
| long lowHigh = xLow * yHigh; |
| long mid2 = lowHigh + mid1Low; |
| long mid2High = mid2 >> 32; |
| |
| long highHigh = xHigh * yHigh; |
| return highHigh + mid1High + mid2High; |
| } |
| |
| public static int negateExactInt(int value) { |
| if (value == Integer.MIN_VALUE) { |
| throw new ArithmeticException(); |
| } |
| return -value; |
| } |
| |
| public static long negateExactLong(long value) { |
| if (value == Long.MIN_VALUE) { |
| throw new ArithmeticException(); |
| } |
| return -value; |
| } |
| |
| public static double nextDownDouble(double value) { |
| return -Math.nextUp(-value); |
| } |
| |
| public static float nextDownFloat(float value) { |
| return -Math.nextUp(-value); |
| } |
| |
| public static int subtractExactInt(int x, int y) { |
| long longResult = (long) x - y; |
| int intResult = (int) longResult; |
| if (longResult == intResult) { |
| return intResult; |
| } |
| throw new ArithmeticException(); |
| } |
| |
| public static long subtractExactLong(long x, long y) { |
| long result = x - y; |
| if ((x ^ y) >= 0 | (x ^ result) >= 0) { |
| return result; |
| } |
| throw new ArithmeticException(); |
| } |
| |
| public static int toIntExact(long value) { |
| int result = (int) value; |
| if (value != result) { |
| throw new ArithmeticException(); |
| } |
| return result; |
| } |
| } |