1
1
/*
2
- * Copyright (c) 2012, 2024 , Oracle and/or its affiliates. All rights reserved.
2
+ * Copyright (c) 2012, 2025 , Oracle and/or its affiliates. All rights reserved.
3
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
4
*
5
5
* This code is free software; you can redistribute it and/or modify it
27
27
import static jdk .graal .compiler .core .common .calc .FloatConvert .D2F ;
28
28
import static jdk .graal .compiler .core .common .calc .FloatConvert .D2I ;
29
29
import static jdk .graal .compiler .core .common .calc .FloatConvert .D2L ;
30
+ import static jdk .graal .compiler .core .common .calc .FloatConvert .D2UI ;
31
+ import static jdk .graal .compiler .core .common .calc .FloatConvert .D2UL ;
30
32
import static jdk .graal .compiler .core .common .calc .FloatConvert .F2D ;
31
33
import static jdk .graal .compiler .core .common .calc .FloatConvert .F2I ;
32
34
import static jdk .graal .compiler .core .common .calc .FloatConvert .F2L ;
35
+ import static jdk .graal .compiler .core .common .calc .FloatConvert .F2UI ;
36
+ import static jdk .graal .compiler .core .common .calc .FloatConvert .F2UL ;
33
37
34
38
import java .nio .ByteBuffer ;
35
39
import java .util .function .DoubleBinaryOperator ;
@@ -456,21 +460,27 @@ private static Stamp maybeFoldConstant(ArithmeticOpTable.BinaryOp<?> op, FloatSt
456
460
}
457
461
458
462
public static boolean floatingToIntegerCanOverflow (FloatStamp floatStamp , int integerBits ) {
463
+ return floatingToIntegerCanOverflow (floatStamp , integerBits , false );
464
+ }
465
+
466
+ public static boolean floatingToIntegerCanOverflow (FloatStamp floatStamp , int integerBits , boolean unsigned ) {
459
467
final boolean canBeInfinity = Double .isInfinite (floatStamp .lowerBound ()) || Double .isInfinite (floatStamp .upperBound ());
460
468
if (canBeInfinity ) {
461
469
return true ;
462
470
}
463
- final boolean conversionCanOverflow = integralPartLargerMaxValue (floatStamp , integerBits ) || integralPartSmallerMinValue (floatStamp , integerBits );
471
+ final boolean conversionCanOverflow = integralPartLargerMaxValue (floatStamp , integerBits , unsigned ) || integralPartSmallerMinValue (floatStamp , integerBits , unsigned );
464
472
return conversionCanOverflow ;
465
473
}
466
474
467
- private static boolean integralPartLargerMaxValue (FloatStamp floatStamp , int integerBits ) {
475
+ private static boolean integralPartLargerMaxValue (FloatStamp floatStamp , int integerBits , boolean unsigned ) {
468
476
double upperBound = floatStamp .upperBound ();
469
477
if (Double .isInfinite (upperBound ) || Double .isNaN (upperBound )) {
470
478
return true ;
471
479
}
472
480
assert integerBits == 32 || integerBits == 64 : "Must be int or long " + Assertions .errorMessage (integerBits , upperBound );
473
- long maxValue = NumUtil .maxValue (integerBits );
481
+ double maxValue = unsigned
482
+ ? NumUtil .unsignedToDouble (NumUtil .maxValueUnsigned (integerBits ))
483
+ : NumUtil .maxValue (integerBits );
474
484
/*
475
485
* There could be conversion loss here when casting maxValue from long to double - given
476
486
* that max can be Long.MAX_VALUE. In order to avoid checking if upperBound is larger than
@@ -482,17 +492,23 @@ private static boolean integralPartLargerMaxValue(FloatStamp floatStamp, int int
482
492
* Long.MAX_VALUE) == 9223372036854774784, which fits into long. So if upperBound >=
483
493
* (double) maxValue does not hold, i.e., upperBound < (double) maxValue does hold, then
484
494
* (long) upperBound will not overflow.
495
+ *
496
+ * Similarly, for the unsigned case, unsignedToDouble(-1L) is 18446744073709551616 (2**64),
497
+ * which is 1 more than the unsigned long max value, i.e. 18446744073709551615 (2**64 - 1).
498
+ * So toUnsignedLong(unsignedToDouble(-1L)) will already overflow. The next lower double
499
+ * value is Math.nextDown(0x1p64) == 18446744073709549568, which fits into unsigned long.
500
+ * The same overflow condition reasoning as for the signed long case applies.
485
501
*/
486
502
return upperBound >= maxValue ;
487
503
}
488
504
489
- private static boolean integralPartSmallerMinValue (FloatStamp floatStamp , int integerBits ) {
505
+ private static boolean integralPartSmallerMinValue (FloatStamp floatStamp , int integerBits , boolean unsigned ) {
490
506
double lowerBound = floatStamp .lowerBound ();
491
507
if (Double .isInfinite (lowerBound ) || Double .isNaN (lowerBound )) {
492
508
return true ;
493
509
}
494
510
assert integerBits == 32 || integerBits == 64 : "Must be int or long " + Assertions .errorMessage (integerBits , lowerBound );
495
- long minValue = NumUtil .minValue (integerBits );
511
+ double minValue = unsigned ? 0 : NumUtil .minValue (integerBits );
496
512
return lowerBound <= minValue ;
497
513
}
498
514
@@ -1677,6 +1693,114 @@ protected Stamp foldStampImpl(Stamp stamp) {
1677
1693
assert floatStamp .getBits () == 64 : Assertions .errorMessage (floatStamp );
1678
1694
return StampFactory .forFloat (JavaKind .Float , (float ) floatStamp .lowerBound (), (float ) floatStamp .upperBound (), floatStamp .isNonNaN ());
1679
1695
}
1696
+ },
1697
+
1698
+ new ArithmeticOpTable .FloatConvertOp (F2UI ) {
1699
+
1700
+ @ Override
1701
+ public Constant foldConstant (Constant c ) {
1702
+ PrimitiveConstant value = (PrimitiveConstant ) c ;
1703
+ return JavaConstant .forInt ((int ) NumUtil .minUnsigned (NumUtil .toUnsignedLong (value .asFloat ()), 0xffff_ffffL ));
1704
+ }
1705
+
1706
+ @ Override
1707
+ protected Stamp foldStampImpl (Stamp stamp ) {
1708
+ if (stamp .isEmpty ()) {
1709
+ return StampFactory .empty (JavaKind .Int );
1710
+ }
1711
+ FloatStamp floatStamp = (FloatStamp ) stamp ;
1712
+ assert floatStamp .getBits () == 32 : floatStamp ;
1713
+ long lowerBound = floatStamp .canBeNaN () ? 0
1714
+ : NumUtil .minUnsigned (NumUtil .toUnsignedLong (floatStamp .lowerBound ()), 0xffff_ffffL );
1715
+ long upperBound = NumUtil .minUnsigned (NumUtil .toUnsignedLong (floatStamp .upperBound ()), 0xffff_ffffL );
1716
+ return StampFactory .forUnsignedInteger (JavaKind .Int .getBitCount (), lowerBound , upperBound );
1717
+ }
1718
+
1719
+ @ Override
1720
+ public boolean canOverflowInteger (Stamp inputStamp ) {
1721
+ return inputStamp instanceof FloatStamp floatStamp && floatingToIntegerCanOverflow (floatStamp , Integer .SIZE , true );
1722
+ }
1723
+ },
1724
+
1725
+ new ArithmeticOpTable .FloatConvertOp (F2UL ) {
1726
+
1727
+ @ Override
1728
+ public Constant foldConstant (Constant c ) {
1729
+ PrimitiveConstant value = (PrimitiveConstant ) c ;
1730
+ return JavaConstant .forLong (NumUtil .toUnsignedLong (value .asFloat ()));
1731
+ }
1732
+
1733
+ @ Override
1734
+ protected Stamp foldStampImpl (Stamp stamp ) {
1735
+ if (stamp .isEmpty ()) {
1736
+ return StampFactory .empty (JavaKind .Long );
1737
+ }
1738
+ FloatStamp floatStamp = (FloatStamp ) stamp ;
1739
+ assert floatStamp .getBits () == 32 : floatStamp ;
1740
+ long lowerBound = floatStamp .canBeNaN () ? 0
1741
+ : NumUtil .toUnsignedLong (floatStamp .lowerBound ());
1742
+ long upperBound = NumUtil .toUnsignedLong (floatStamp .upperBound ());
1743
+ return StampFactory .forUnsignedInteger (JavaKind .Long .getBitCount (), lowerBound , upperBound );
1744
+ }
1745
+
1746
+ @ Override
1747
+ public boolean canOverflowInteger (Stamp inputStamp ) {
1748
+ return inputStamp instanceof FloatStamp floatStamp && floatingToIntegerCanOverflow (floatStamp , Long .SIZE , true );
1749
+ }
1750
+ },
1751
+
1752
+ new ArithmeticOpTable .FloatConvertOp (D2UI ) {
1753
+
1754
+ @ Override
1755
+ public Constant foldConstant (Constant c ) {
1756
+ PrimitiveConstant value = (PrimitiveConstant ) c ;
1757
+ return JavaConstant .forInt ((int ) NumUtil .minUnsigned (NumUtil .toUnsignedLong (value .asDouble ()), 0xffff_ffffL ));
1758
+ }
1759
+
1760
+ @ Override
1761
+ protected Stamp foldStampImpl (Stamp stamp ) {
1762
+ if (stamp .isEmpty ()) {
1763
+ return StampFactory .empty (JavaKind .Int );
1764
+ }
1765
+ FloatStamp floatStamp = (FloatStamp ) stamp ;
1766
+ assert floatStamp .getBits () == 64 : floatStamp ;
1767
+ long lowerBound = floatStamp .canBeNaN () ? 0
1768
+ : NumUtil .minUnsigned (NumUtil .toUnsignedLong (floatStamp .lowerBound ()), 0xffff_ffffL );
1769
+ long upperBound = NumUtil .minUnsigned (NumUtil .toUnsignedLong (floatStamp .upperBound ()), 0xffff_ffffL );
1770
+ return StampFactory .forUnsignedInteger (JavaKind .Int .getBitCount (), lowerBound , upperBound );
1771
+ }
1772
+
1773
+ @ Override
1774
+ public boolean canOverflowInteger (Stamp inputStamp ) {
1775
+ return inputStamp instanceof FloatStamp floatStamp && floatingToIntegerCanOverflow (floatStamp , Integer .SIZE , true );
1776
+ }
1777
+ },
1778
+
1779
+ new ArithmeticOpTable .FloatConvertOp (D2UL ) {
1780
+
1781
+ @ Override
1782
+ public Constant foldConstant (Constant c ) {
1783
+ PrimitiveConstant value = (PrimitiveConstant ) c ;
1784
+ return JavaConstant .forLong (NumUtil .toUnsignedLong (value .asDouble ()));
1785
+ }
1786
+
1787
+ @ Override
1788
+ protected Stamp foldStampImpl (Stamp stamp ) {
1789
+ if (stamp .isEmpty ()) {
1790
+ return StampFactory .empty (JavaKind .Long );
1791
+ }
1792
+ FloatStamp floatStamp = (FloatStamp ) stamp ;
1793
+ assert floatStamp .getBits () == 64 : floatStamp ;
1794
+ long lowerBound = floatStamp .canBeNaN () ? 0
1795
+ : NumUtil .toUnsignedLong (floatStamp .lowerBound ());
1796
+ long upperBound = NumUtil .toUnsignedLong (floatStamp .upperBound ());
1797
+ return StampFactory .forUnsignedInteger (JavaKind .Long .getBitCount (), lowerBound , upperBound );
1798
+ }
1799
+
1800
+ @ Override
1801
+ public boolean canOverflowInteger (Stamp inputStamp ) {
1802
+ return inputStamp instanceof FloatStamp floatStamp && floatingToIntegerCanOverflow (floatStamp , Long .SIZE , true );
1803
+ }
1680
1804
});
1681
1805
1682
1806
// Use a separate class to avoid initialization cycles
0 commit comments