|
7 | 7 | //===----------------------------------------------------------------------===// |
8 | 8 |
|
9 | 9 | #include "llvm/IR/ConstantFPRange.h" |
| 10 | +#include "llvm/ADT/APFloat.h" |
10 | 11 | #include "llvm/IR/Instructions.h" |
11 | 12 | #include "llvm/IR/Operator.h" |
12 | 13 | #include "gtest/gtest.h" |
@@ -818,4 +819,110 @@ TEST_F(ConstantFPRangeTest, getWithout) { |
818 | 819 | APFloat::getLargest(Sem, /*Negative=*/true), APFloat(3.0))); |
819 | 820 | } |
820 | 821 |
|
| 822 | +TEST_F(ConstantFPRangeTest, cast) { |
| 823 | + const fltSemantics &F16Sem = APFloat::IEEEhalf(); |
| 824 | + const fltSemantics &BF16Sem = APFloat::BFloat(); |
| 825 | + const fltSemantics &F32Sem = APFloat::IEEEsingle(); |
| 826 | + const fltSemantics &F8NanOnlySem = APFloat::Float8E4M3FN(); |
| 827 | + // normal -> normal (exact) |
| 828 | + EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0)).cast(F32Sem), |
| 829 | + ConstantFPRange::getNonNaN(APFloat(1.0f), APFloat(2.0f))); |
| 830 | + EXPECT_EQ( |
| 831 | + ConstantFPRange::getNonNaN(APFloat(-2.0f), APFloat(-1.0f)).cast(Sem), |
| 832 | + ConstantFPRange::getNonNaN(APFloat(-2.0), APFloat(-1.0))); |
| 833 | + // normal -> normal (inexact) |
| 834 | + EXPECT_EQ( |
| 835 | + ConstantFPRange::getNonNaN(APFloat(3.141592653589793), |
| 836 | + APFloat(6.283185307179586)) |
| 837 | + .cast(F32Sem), |
| 838 | + ConstantFPRange::getNonNaN(APFloat(3.14159274f), APFloat(6.28318548f))); |
| 839 | + // normal -> subnormal |
| 840 | + EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat(-5e-8), APFloat(5e-8)) |
| 841 | + .cast(F16Sem) |
| 842 | + .classify(), |
| 843 | + fcSubnormal | fcZero); |
| 844 | + // normal -> zero |
| 845 | + EXPECT_EQ(ConstantFPRange::getNonNaN( |
| 846 | + APFloat::getSmallestNormalized(Sem, /*Negative=*/true), |
| 847 | + APFloat::getSmallestNormalized(Sem, /*Negative=*/false)) |
| 848 | + .cast(F32Sem) |
| 849 | + .classify(), |
| 850 | + fcZero); |
| 851 | + // normal -> inf |
| 852 | + EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat(-65536.0), APFloat(65536.0)) |
| 853 | + .cast(F16Sem), |
| 854 | + ConstantFPRange::getNonNaN(F16Sem)); |
| 855 | + // nan -> qnan |
| 856 | + EXPECT_EQ( |
| 857 | + ConstantFPRange::getNaNOnly(Sem, /*MayBeQNaN=*/true, /*MayBeSNaN=*/false) |
| 858 | + .cast(F32Sem), |
| 859 | + ConstantFPRange::getNaNOnly(F32Sem, /*MayBeQNaN=*/true, |
| 860 | + /*MayBeSNaN=*/false)); |
| 861 | + EXPECT_EQ( |
| 862 | + ConstantFPRange::getNaNOnly(Sem, /*MayBeQNaN=*/false, /*MayBeSNaN=*/true) |
| 863 | + .cast(F32Sem), |
| 864 | + ConstantFPRange::getNaNOnly(F32Sem, /*MayBeQNaN=*/true, |
| 865 | + /*MayBeSNaN=*/false)); |
| 866 | + EXPECT_EQ( |
| 867 | + ConstantFPRange::getNaNOnly(Sem, /*MayBeQNaN=*/true, /*MayBeSNaN=*/true) |
| 868 | + .cast(F32Sem), |
| 869 | + ConstantFPRange::getNaNOnly(F32Sem, /*MayBeQNaN=*/true, |
| 870 | + /*MayBeSNaN=*/false)); |
| 871 | + // For BF16 -> F32, signaling bit is still lost. |
| 872 | + EXPECT_EQ(ConstantFPRange::getNaNOnly(BF16Sem, /*MayBeQNaN=*/true, |
| 873 | + /*MayBeSNaN=*/true) |
| 874 | + .cast(F32Sem), |
| 875 | + ConstantFPRange::getNaNOnly(F32Sem, /*MayBeQNaN=*/true, |
| 876 | + /*MayBeSNaN=*/false)); |
| 877 | + // inf -> nan only (return full set for now) |
| 878 | + EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat::getInf(Sem, /*Negative=*/true), |
| 879 | + APFloat::getInf(Sem, /*Negative=*/false)) |
| 880 | + .cast(F8NanOnlySem), |
| 881 | + ConstantFPRange::getFull(F8NanOnlySem)); |
| 882 | + // other rounding modes |
| 883 | + EXPECT_EQ( |
| 884 | + ConstantFPRange::getNonNaN(APFloat::getSmallest(Sem, /*Negative=*/true), |
| 885 | + APFloat::getSmallest(Sem, /*Negative=*/false)) |
| 886 | + .cast(F32Sem, APFloat::rmTowardNegative), |
| 887 | + ConstantFPRange::getNonNaN( |
| 888 | + APFloat::getSmallest(F32Sem, /*Negative=*/true), |
| 889 | + APFloat::getZero(F32Sem, /*Negative=*/false))); |
| 890 | + EXPECT_EQ( |
| 891 | + ConstantFPRange::getNonNaN(APFloat::getSmallest(Sem, /*Negative=*/true), |
| 892 | + APFloat::getSmallest(Sem, /*Negative=*/false)) |
| 893 | + .cast(F32Sem, APFloat::rmTowardPositive), |
| 894 | + ConstantFPRange::getNonNaN( |
| 895 | + APFloat::getZero(F32Sem, /*Negative=*/true), |
| 896 | + APFloat::getSmallest(F32Sem, /*Negative=*/false))); |
| 897 | + EXPECT_EQ( |
| 898 | + ConstantFPRange::getNonNaN( |
| 899 | + APFloat::getSmallestNormalized(Sem, /*Negative=*/true), |
| 900 | + APFloat::getSmallestNormalized(Sem, /*Negative=*/false)) |
| 901 | + .cast(F32Sem, APFloat::rmTowardZero), |
| 902 | + ConstantFPRange::getNonNaN(APFloat::getZero(F32Sem, /*Negative=*/true), |
| 903 | + APFloat::getZero(F32Sem, /*Negative=*/false))); |
| 904 | + |
| 905 | + EnumerateValuesInConstantFPRange( |
| 906 | + ConstantFPRange::getFull(APFloat::Float8E4M3()), |
| 907 | + [&](const APFloat &V) { |
| 908 | + bool LosesInfo = false; |
| 909 | + |
| 910 | + APFloat DoubleV = V; |
| 911 | + DoubleV.convert(Sem, APFloat::rmNearestTiesToEven, &LosesInfo); |
| 912 | + ConstantFPRange DoubleCR = ConstantFPRange(V).cast(Sem); |
| 913 | + EXPECT_TRUE(DoubleCR.contains(DoubleV)) |
| 914 | + << "Casting " << V << " to double failed. " << DoubleCR |
| 915 | + << " doesn't contain " << DoubleV; |
| 916 | + |
| 917 | + auto &FP4Sem = APFloat::Float4E2M1FN(); |
| 918 | + APFloat FP4V = V; |
| 919 | + FP4V.convert(FP4Sem, APFloat::rmNearestTiesToEven, &LosesInfo); |
| 920 | + ConstantFPRange FP4CR = ConstantFPRange(V).cast(FP4Sem); |
| 921 | + EXPECT_TRUE(FP4CR.contains(FP4V)) |
| 922 | + << "Casting " << V << " to FP4E2M1FN failed. " << FP4CR |
| 923 | + << " doesn't contain " << FP4V; |
| 924 | + }, |
| 925 | + /*IgnoreNaNPayload=*/true); |
| 926 | +} |
| 927 | + |
821 | 928 | } // anonymous namespace |
0 commit comments