xref: /qemu/tests/tcg/arm/fcvt.c (revision f2cb4026fccfe073f84a4b440e41d3ed0c3134f6)
18ec8a55eSAlex Bennée /*
28ec8a55eSAlex Bennée  * Test Floating Point Conversion
38ec8a55eSAlex Bennée  */
48ec8a55eSAlex Bennée 
58ec8a55eSAlex Bennée /* we want additional float type definitions */
68ec8a55eSAlex Bennée #define __STDC_WANT_IEC_60559_BFP_EXT__
78ec8a55eSAlex Bennée #define __STDC_WANT_IEC_60559_TYPES_EXT__
88ec8a55eSAlex Bennée 
98ec8a55eSAlex Bennée #include <stdio.h>
108ec8a55eSAlex Bennée #include <inttypes.h>
118ec8a55eSAlex Bennée #include <math.h>
128ec8a55eSAlex Bennée #include <float.h>
138ec8a55eSAlex Bennée #include <fenv.h>
148ec8a55eSAlex Bennée 
158ec8a55eSAlex Bennée #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
168ec8a55eSAlex Bennée 
178ec8a55eSAlex Bennée static char flag_str[256];
188ec8a55eSAlex Bennée 
get_flag_state(int flags)198ec8a55eSAlex Bennée static char *get_flag_state(int flags)
208ec8a55eSAlex Bennée {
218ec8a55eSAlex Bennée     if (flags) {
228ec8a55eSAlex Bennée         snprintf(flag_str, sizeof(flag_str), "%s %s %s %s %s",
238ec8a55eSAlex Bennée                  flags & FE_OVERFLOW ? "OVERFLOW" : "",
248ec8a55eSAlex Bennée                  flags & FE_UNDERFLOW ? "UNDERFLOW" : "",
258ec8a55eSAlex Bennée                  flags & FE_DIVBYZERO ? "DIV0" : "",
268ec8a55eSAlex Bennée                  flags & FE_INEXACT ? "INEXACT" : "",
278ec8a55eSAlex Bennée                  flags & FE_INVALID ? "INVALID" : "");
288ec8a55eSAlex Bennée     } else {
298ec8a55eSAlex Bennée         snprintf(flag_str, sizeof(flag_str), "OK");
308ec8a55eSAlex Bennée     }
318ec8a55eSAlex Bennée 
328ec8a55eSAlex Bennée     return flag_str;
338ec8a55eSAlex Bennée }
348ec8a55eSAlex Bennée 
print_double_number(int i,double num)358ec8a55eSAlex Bennée static void print_double_number(int i, double num)
368ec8a55eSAlex Bennée {
378ec8a55eSAlex Bennée     uint64_t double_as_hex = *(uint64_t *) &num;
388ec8a55eSAlex Bennée     int flags = fetestexcept(FE_ALL_EXCEPT);
398ec8a55eSAlex Bennée     char *fstr = get_flag_state(flags);
408ec8a55eSAlex Bennée 
418ec8a55eSAlex Bennée     printf("%02d DOUBLE: %02.20e / %#020" PRIx64 " (%#x => %s)\n",
428ec8a55eSAlex Bennée            i, num, double_as_hex, flags, fstr);
438ec8a55eSAlex Bennée }
448ec8a55eSAlex Bennée 
print_single_number(int i,float num)458ec8a55eSAlex Bennée static void print_single_number(int i, float num)
468ec8a55eSAlex Bennée {
478ec8a55eSAlex Bennée     uint32_t single_as_hex = *(uint32_t *) &num;
488ec8a55eSAlex Bennée     int flags = fetestexcept(FE_ALL_EXCEPT);
498ec8a55eSAlex Bennée     char *fstr = get_flag_state(flags);
508ec8a55eSAlex Bennée 
518ec8a55eSAlex Bennée     printf("%02d SINGLE: %02.20e / %#010x  (%#x => %s)\n",
528ec8a55eSAlex Bennée            i, num, single_as_hex, flags, fstr);
538ec8a55eSAlex Bennée }
548ec8a55eSAlex Bennée 
print_half_number(int i,uint16_t num)558ec8a55eSAlex Bennée static void print_half_number(int i, uint16_t num)
568ec8a55eSAlex Bennée {
578ec8a55eSAlex Bennée     int flags = fetestexcept(FE_ALL_EXCEPT);
588ec8a55eSAlex Bennée     char *fstr = get_flag_state(flags);
598ec8a55eSAlex Bennée 
608ec8a55eSAlex Bennée     printf("%02d   HALF: %#04x  (%#x => %s)\n",
618ec8a55eSAlex Bennée            i, num, flags, fstr);
628ec8a55eSAlex Bennée }
638ec8a55eSAlex Bennée 
print_int64(int i,int64_t num)648ec8a55eSAlex Bennée static void print_int64(int i, int64_t num)
658ec8a55eSAlex Bennée {
668ec8a55eSAlex Bennée     uint64_t int64_as_hex = *(uint64_t *) &num;
678ec8a55eSAlex Bennée     int flags = fetestexcept(FE_ALL_EXCEPT);
688ec8a55eSAlex Bennée     char *fstr = get_flag_state(flags);
698ec8a55eSAlex Bennée 
708ec8a55eSAlex Bennée     printf("%02d   INT64: %20" PRId64 "/%#020" PRIx64 " (%#x => %s)\n",
718ec8a55eSAlex Bennée            i, num, int64_as_hex, flags, fstr);
728ec8a55eSAlex Bennée }
738ec8a55eSAlex Bennée 
748ec8a55eSAlex Bennée #ifndef SNANF
758ec8a55eSAlex Bennée /* Signaling NaN macros, if supported.  */
768ec8a55eSAlex Bennée # define SNANF (__builtin_nansf (""))
778ec8a55eSAlex Bennée # define SNAN (__builtin_nans (""))
788ec8a55eSAlex Bennée # define SNANL (__builtin_nansl (""))
798ec8a55eSAlex Bennée #endif
808ec8a55eSAlex Bennée 
818ec8a55eSAlex Bennée float single_numbers[] = { -SNANF,
828ec8a55eSAlex Bennée                            -NAN,
838ec8a55eSAlex Bennée                            -INFINITY,
848ec8a55eSAlex Bennée                            -FLT_MAX,
858ec8a55eSAlex Bennée                            -1.111E+31,
868ec8a55eSAlex Bennée                            -1.111E+30,
878ec8a55eSAlex Bennée                            -1.08700982e-12,
888ec8a55eSAlex Bennée                            -1.78051176e-20,
898ec8a55eSAlex Bennée                            -FLT_MIN,
908ec8a55eSAlex Bennée                            0.0,
918ec8a55eSAlex Bennée                            FLT_MIN,
928ec8a55eSAlex Bennée                            2.98023224e-08,
938ec8a55eSAlex Bennée                            5.96046E-8, /* min positive FP16 subnormal */
948ec8a55eSAlex Bennée                            6.09756E-5, /* max subnormal FP16 */
958ec8a55eSAlex Bennée                            6.10352E-5, /* min positive normal FP16 */
968ec8a55eSAlex Bennée                            1.0,
978ec8a55eSAlex Bennée                            1.0009765625, /* smallest float after 1.0 FP16 */
988ec8a55eSAlex Bennée                            2.0,
998ec8a55eSAlex Bennée                            M_E, M_PI,
1008ec8a55eSAlex Bennée                            65503.0,
1018ec8a55eSAlex Bennée                            65504.0, /* max FP16 */
1028ec8a55eSAlex Bennée                            65505.0,
1038ec8a55eSAlex Bennée                            131007.0,
1048ec8a55eSAlex Bennée                            131008.0, /* max AFP */
1058ec8a55eSAlex Bennée                            131009.0,
1068ec8a55eSAlex Bennée                            1.111E+30,
1078ec8a55eSAlex Bennée                            FLT_MAX,
1088ec8a55eSAlex Bennée                            INFINITY,
1098ec8a55eSAlex Bennée                            NAN,
1108ec8a55eSAlex Bennée                            SNANF };
1118ec8a55eSAlex Bennée 
convert_single_to_half(void)1128ec8a55eSAlex Bennée static void convert_single_to_half(void)
1138ec8a55eSAlex Bennée {
1148ec8a55eSAlex Bennée     int i;
1158ec8a55eSAlex Bennée 
1168ec8a55eSAlex Bennée     printf("Converting single-precision to half-precision\n");
1178ec8a55eSAlex Bennée 
1188ec8a55eSAlex Bennée     for (i = 0; i < ARRAY_SIZE(single_numbers); ++i) {
1198ec8a55eSAlex Bennée         float input = single_numbers[i];
1208ec8a55eSAlex Bennée 
1218ec8a55eSAlex Bennée         feclearexcept(FE_ALL_EXCEPT);
1228ec8a55eSAlex Bennée 
1238ec8a55eSAlex Bennée         print_single_number(i, input);
1248ec8a55eSAlex Bennée #if defined(__arm__)
1258ec8a55eSAlex Bennée         uint32_t output;
1268ec8a55eSAlex Bennée         asm("vcvtb.f16.f32 %0, %1" : "=t" (output) : "x" (input));
1278ec8a55eSAlex Bennée #else
1288ec8a55eSAlex Bennée         uint16_t output;
12998b323faSAkihiko Odaki         asm("fcvt %h0, %s1" : "=w" (output) : "w" (input));
1308ec8a55eSAlex Bennée #endif
1318ec8a55eSAlex Bennée         print_half_number(i, output);
1328ec8a55eSAlex Bennée     }
1338ec8a55eSAlex Bennée }
1348ec8a55eSAlex Bennée 
convert_single_to_double(void)1358ec8a55eSAlex Bennée static void convert_single_to_double(void)
1368ec8a55eSAlex Bennée {
1378ec8a55eSAlex Bennée     int i;
1388ec8a55eSAlex Bennée 
1398ec8a55eSAlex Bennée     printf("Converting single-precision to double-precision\n");
1408ec8a55eSAlex Bennée 
1418ec8a55eSAlex Bennée     for (i = 0; i < ARRAY_SIZE(single_numbers); ++i) {
1428ec8a55eSAlex Bennée         float input = single_numbers[i];
1438ec8a55eSAlex Bennée         /* uint64_t output; */
1448ec8a55eSAlex Bennée         double output;
1458ec8a55eSAlex Bennée 
1468ec8a55eSAlex Bennée         feclearexcept(FE_ALL_EXCEPT);
1478ec8a55eSAlex Bennée 
1488ec8a55eSAlex Bennée         print_single_number(i, input);
1498ec8a55eSAlex Bennée #if defined(__arm__)
1508ec8a55eSAlex Bennée         asm("vcvt.f64.f32 %P0, %1" : "=w" (output) : "t" (input));
1518ec8a55eSAlex Bennée #else
15298b323faSAkihiko Odaki         asm("fcvt %d0, %s1" : "=w" (output) : "w" (input));
1538ec8a55eSAlex Bennée #endif
1548ec8a55eSAlex Bennée         print_double_number(i, output);
1558ec8a55eSAlex Bennée     }
1568ec8a55eSAlex Bennée }
1578ec8a55eSAlex Bennée 
convert_single_to_integer(void)1588ec8a55eSAlex Bennée static void convert_single_to_integer(void)
1598ec8a55eSAlex Bennée {
1608ec8a55eSAlex Bennée     int i;
1618ec8a55eSAlex Bennée 
1628ec8a55eSAlex Bennée     printf("Converting single-precision to integer\n");
1638ec8a55eSAlex Bennée 
1648ec8a55eSAlex Bennée     for (i = 0; i < ARRAY_SIZE(single_numbers); ++i) {
1658ec8a55eSAlex Bennée         float input = single_numbers[i];
1668ec8a55eSAlex Bennée         int64_t output;
1678ec8a55eSAlex Bennée 
1688ec8a55eSAlex Bennée         feclearexcept(FE_ALL_EXCEPT);
1698ec8a55eSAlex Bennée 
1708ec8a55eSAlex Bennée         print_single_number(i, input);
1718ec8a55eSAlex Bennée #if defined(__arm__)
1728ec8a55eSAlex Bennée         /* asm("vcvt.s32.f32 %s0, %s1" : "=t" (output) : "t" (input)); */
1738ec8a55eSAlex Bennée         output = input;
1748ec8a55eSAlex Bennée #else
1758ec8a55eSAlex Bennée         asm("fcvtzs %0, %s1" : "=r" (output) : "w" (input));
1768ec8a55eSAlex Bennée #endif
1778ec8a55eSAlex Bennée         print_int64(i, output);
1788ec8a55eSAlex Bennée     }
1798ec8a55eSAlex Bennée }
1808ec8a55eSAlex Bennée 
1818ec8a55eSAlex Bennée /* This allows us to initialise some doubles as pure hex */
1828ec8a55eSAlex Bennée typedef union {
1838ec8a55eSAlex Bennée     double d;
1848ec8a55eSAlex Bennée     uint64_t h;
1858ec8a55eSAlex Bennée } test_doubles;
1868ec8a55eSAlex Bennée 
1878ec8a55eSAlex Bennée test_doubles double_numbers[] = {
1888ec8a55eSAlex Bennée     {SNAN},
1898ec8a55eSAlex Bennée     {-NAN},
1908ec8a55eSAlex Bennée     {-INFINITY},
1918ec8a55eSAlex Bennée     {-DBL_MAX},
1928ec8a55eSAlex Bennée     {-FLT_MAX-1.0},
1938ec8a55eSAlex Bennée     {-FLT_MAX},
1948ec8a55eSAlex Bennée     {-1.111E+31},
1958ec8a55eSAlex Bennée     {-1.111E+30}, /* half prec */
1968ec8a55eSAlex Bennée     {-2.0}, {-1.0},
1978ec8a55eSAlex Bennée     {-DBL_MIN},
1988ec8a55eSAlex Bennée     {-FLT_MIN},
1998ec8a55eSAlex Bennée     {0.0},
2008ec8a55eSAlex Bennée     {FLT_MIN},
2018ec8a55eSAlex Bennée     {2.98023224e-08},
2028ec8a55eSAlex Bennée     {5.96046E-8}, /* min positive FP16 subnormal */
2038ec8a55eSAlex Bennée     {6.09756E-5}, /* max subnormal FP16 */
2048ec8a55eSAlex Bennée     {6.10352E-5}, /* min positive normal FP16 */
2058ec8a55eSAlex Bennée     {1.0},
2068ec8a55eSAlex Bennée     {1.0009765625}, /* smallest float after 1.0 FP16 */
2078ec8a55eSAlex Bennée     {DBL_MIN},
2088ec8a55eSAlex Bennée     {1.3789972848607228e-308},
2098ec8a55eSAlex Bennée     {1.4914738736681624e-308},
2108ec8a55eSAlex Bennée     {1.0}, {2.0},
2118ec8a55eSAlex Bennée     {M_E}, {M_PI},
2128ec8a55eSAlex Bennée     {65503.0},
2138ec8a55eSAlex Bennée     {65504.0}, /* max FP16 */
2148ec8a55eSAlex Bennée     {65505.0},
2158ec8a55eSAlex Bennée     {131007.0},
2168ec8a55eSAlex Bennée     {131008.0}, /* max AFP */
2178ec8a55eSAlex Bennée     {131009.0},
2188ec8a55eSAlex Bennée     {.h = 0x41dfffffffc00000 }, /* to int = 0x7fffffff */
2198ec8a55eSAlex Bennée     {FLT_MAX},
2208ec8a55eSAlex Bennée     {FLT_MAX + 1.0},
2218ec8a55eSAlex Bennée     {DBL_MAX},
2228ec8a55eSAlex Bennée     {INFINITY},
2238ec8a55eSAlex Bennée     {NAN},
2248ec8a55eSAlex Bennée     {.h = 0x7ff0000000000001}, /* SNAN */
2258ec8a55eSAlex Bennée     {SNAN},
2268ec8a55eSAlex Bennée };
2278ec8a55eSAlex Bennée 
convert_double_to_half(void)2288ec8a55eSAlex Bennée static void convert_double_to_half(void)
2298ec8a55eSAlex Bennée {
2308ec8a55eSAlex Bennée     int i;
2318ec8a55eSAlex Bennée 
2328ec8a55eSAlex Bennée     printf("Converting double-precision to half-precision\n");
2338ec8a55eSAlex Bennée 
2348ec8a55eSAlex Bennée     for (i = 0; i < ARRAY_SIZE(double_numbers); ++i) {
2358ec8a55eSAlex Bennée         double input = double_numbers[i].d;
2368ec8a55eSAlex Bennée         uint16_t output;
2378ec8a55eSAlex Bennée 
2388ec8a55eSAlex Bennée         feclearexcept(FE_ALL_EXCEPT);
2398ec8a55eSAlex Bennée 
2408ec8a55eSAlex Bennée         print_double_number(i, input);
2418ec8a55eSAlex Bennée 
2428ec8a55eSAlex Bennée         /* as we don't have _Float16 support */
2438ec8a55eSAlex Bennée #if defined(__arm__)
2448ec8a55eSAlex Bennée         /* asm("vcvtb.f16.f64 %0, %P1" : "=t" (output) : "x" (input)); */
2458ec8a55eSAlex Bennée         output = input;
2468ec8a55eSAlex Bennée #else
24798b323faSAkihiko Odaki         asm("fcvt %h0, %d1" : "=w" (output) : "w" (input));
2488ec8a55eSAlex Bennée #endif
2498ec8a55eSAlex Bennée         print_half_number(i, output);
2508ec8a55eSAlex Bennée     }
2518ec8a55eSAlex Bennée }
2528ec8a55eSAlex Bennée 
convert_double_to_single(void)2538ec8a55eSAlex Bennée static void convert_double_to_single(void)
2548ec8a55eSAlex Bennée {
2558ec8a55eSAlex Bennée     int i;
2568ec8a55eSAlex Bennée 
2578ec8a55eSAlex Bennée     printf("Converting double-precision to single-precision\n");
2588ec8a55eSAlex Bennée 
2598ec8a55eSAlex Bennée     for (i = 0; i < ARRAY_SIZE(double_numbers); ++i) {
2608ec8a55eSAlex Bennée         double input = double_numbers[i].d;
2613693408cSAkihiko Odaki         float output;
2628ec8a55eSAlex Bennée 
2638ec8a55eSAlex Bennée         feclearexcept(FE_ALL_EXCEPT);
2648ec8a55eSAlex Bennée 
2658ec8a55eSAlex Bennée         print_double_number(i, input);
2668ec8a55eSAlex Bennée 
2678ec8a55eSAlex Bennée #if defined(__arm__)
2688ec8a55eSAlex Bennée         asm("vcvt.f32.f64 %0, %P1" : "=w" (output) : "x" (input));
2698ec8a55eSAlex Bennée #else
27098b323faSAkihiko Odaki         asm("fcvt %s0, %d1" : "=w" (output) : "w" (input));
2718ec8a55eSAlex Bennée #endif
2728ec8a55eSAlex Bennée 
2738ec8a55eSAlex Bennée         print_single_number(i, output);
2748ec8a55eSAlex Bennée     }
2758ec8a55eSAlex Bennée }
2768ec8a55eSAlex Bennée 
convert_double_to_integer(void)2778ec8a55eSAlex Bennée static void convert_double_to_integer(void)
2788ec8a55eSAlex Bennée {
2798ec8a55eSAlex Bennée     int i;
2808ec8a55eSAlex Bennée 
2818ec8a55eSAlex Bennée     printf("Converting double-precision to integer\n");
2828ec8a55eSAlex Bennée 
2838ec8a55eSAlex Bennée     for (i = 0; i < ARRAY_SIZE(double_numbers); ++i) {
2848ec8a55eSAlex Bennée         double input = double_numbers[i].d;
2858ec8a55eSAlex Bennée         int64_t output;
2868ec8a55eSAlex Bennée 
2878ec8a55eSAlex Bennée         feclearexcept(FE_ALL_EXCEPT);
2888ec8a55eSAlex Bennée 
2898ec8a55eSAlex Bennée         print_double_number(i, input);
2908ec8a55eSAlex Bennée #if defined(__arm__)
2918ec8a55eSAlex Bennée         /* asm("vcvt.s32.f32 %s0, %s1" : "=t" (output) : "t" (input)); */
2928ec8a55eSAlex Bennée         output = input;
2938ec8a55eSAlex Bennée #else
2948ec8a55eSAlex Bennée         asm("fcvtzs %0, %d1" : "=r" (output) : "w" (input));
2958ec8a55eSAlex Bennée #endif
2968ec8a55eSAlex Bennée         print_int64(i, output);
2978ec8a55eSAlex Bennée     }
2988ec8a55eSAlex Bennée }
2998ec8a55eSAlex Bennée 
3008ec8a55eSAlex Bennée /* no handy defines for these numbers */
3018ec8a55eSAlex Bennée uint16_t half_numbers[] = {
3028ec8a55eSAlex Bennée     0xffff, /* -NaN / AHP -Max */
3038ec8a55eSAlex Bennée     0xfcff, /* -NaN / AHP */
3048ec8a55eSAlex Bennée     0xfc01, /* -NaN / AHP */
3058ec8a55eSAlex Bennée     0xfc00, /* -Inf */
3068ec8a55eSAlex Bennée     0xfbff, /* -Max */
3078ec8a55eSAlex Bennée     0xc000, /* -2 */
3088ec8a55eSAlex Bennée     0xbc00, /* -1 */
3098ec8a55eSAlex Bennée     0x8001, /* -MIN subnormal */
3108ec8a55eSAlex Bennée     0x8000, /* -0 */
3118ec8a55eSAlex Bennée     0x0000, /* +0 */
3128ec8a55eSAlex Bennée     0x0001, /* MIN subnormal */
3138ec8a55eSAlex Bennée     0x3c00, /* 1 */
3148ec8a55eSAlex Bennée     0x7bff, /* Max */
3158ec8a55eSAlex Bennée     0x7c00, /* Inf */
3168ec8a55eSAlex Bennée     0x7c01, /* NaN / AHP */
3178ec8a55eSAlex Bennée     0x7cff, /* NaN / AHP */
3188ec8a55eSAlex Bennée     0x7fff, /* NaN / AHP +Max*/
3198ec8a55eSAlex Bennée };
3208ec8a55eSAlex Bennée 
convert_half_to_double(void)3218ec8a55eSAlex Bennée static void convert_half_to_double(void)
3228ec8a55eSAlex Bennée {
3238ec8a55eSAlex Bennée     int i;
3248ec8a55eSAlex Bennée 
3258ec8a55eSAlex Bennée     printf("Converting half-precision to double-precision\n");
3268ec8a55eSAlex Bennée 
3278ec8a55eSAlex Bennée     for (i = 0; i < ARRAY_SIZE(half_numbers); ++i) {
3288ec8a55eSAlex Bennée         uint16_t input = half_numbers[i];
3298ec8a55eSAlex Bennée         double output;
3308ec8a55eSAlex Bennée 
3318ec8a55eSAlex Bennée         feclearexcept(FE_ALL_EXCEPT);
3328ec8a55eSAlex Bennée 
3338ec8a55eSAlex Bennée         print_half_number(i, input);
3348ec8a55eSAlex Bennée #if defined(__arm__)
3358ec8a55eSAlex Bennée         /* asm("vcvtb.f64.f16 %P0, %1" : "=w" (output) : "t" (input)); */
3368ec8a55eSAlex Bennée         output = input;
3378ec8a55eSAlex Bennée #else
33898b323faSAkihiko Odaki         asm("fcvt %d0, %h1" : "=w" (output) : "w" (input));
3398ec8a55eSAlex Bennée #endif
3408ec8a55eSAlex Bennée         print_double_number(i, output);
3418ec8a55eSAlex Bennée     }
3428ec8a55eSAlex Bennée }
3438ec8a55eSAlex Bennée 
convert_half_to_single(void)3448ec8a55eSAlex Bennée static void convert_half_to_single(void)
3458ec8a55eSAlex Bennée {
3468ec8a55eSAlex Bennée     int i;
3478ec8a55eSAlex Bennée 
3488ec8a55eSAlex Bennée     printf("Converting half-precision to single-precision\n");
3498ec8a55eSAlex Bennée 
3508ec8a55eSAlex Bennée     for (i = 0; i < ARRAY_SIZE(half_numbers); ++i) {
3518ec8a55eSAlex Bennée         uint16_t input = half_numbers[i];
3528ec8a55eSAlex Bennée         float output;
3538ec8a55eSAlex Bennée 
3548ec8a55eSAlex Bennée         feclearexcept(FE_ALL_EXCEPT);
3558ec8a55eSAlex Bennée 
3568ec8a55eSAlex Bennée         print_half_number(i, input);
3578ec8a55eSAlex Bennée #if defined(__arm__)
3581e7c9ba4SAkihiko Odaki         /*
3591e7c9ba4SAkihiko Odaki          * Clang refuses to allocate an integer to a fp register.
3601e7c9ba4SAkihiko Odaki          * Perform the move from a general register by hand.
3611e7c9ba4SAkihiko Odaki          */
3621e7c9ba4SAkihiko Odaki         asm("vmov %0, %1\n\t"
3631e7c9ba4SAkihiko Odaki             "vcvtb.f32.f16 %0, %0" : "=w" (output) : "r" (input));
3648ec8a55eSAlex Bennée #else
36598b323faSAkihiko Odaki         asm("fcvt %s0, %h1" : "=w" (output) : "w" (input));
3668ec8a55eSAlex Bennée #endif
3678ec8a55eSAlex Bennée         print_single_number(i, output);
3688ec8a55eSAlex Bennée     }
3698ec8a55eSAlex Bennée }
3708ec8a55eSAlex Bennée 
convert_half_to_integer(void)3718ec8a55eSAlex Bennée static void convert_half_to_integer(void)
3728ec8a55eSAlex Bennée {
3738ec8a55eSAlex Bennée     int i;
3748ec8a55eSAlex Bennée 
3758ec8a55eSAlex Bennée     printf("Converting half-precision to integer\n");
3768ec8a55eSAlex Bennée 
3778ec8a55eSAlex Bennée     for (i = 0; i < ARRAY_SIZE(half_numbers); ++i) {
3788ec8a55eSAlex Bennée         uint16_t input = half_numbers[i];
3798ec8a55eSAlex Bennée         int64_t output;
3808ec8a55eSAlex Bennée 
3818ec8a55eSAlex Bennée         feclearexcept(FE_ALL_EXCEPT);
3828ec8a55eSAlex Bennée 
3838ec8a55eSAlex Bennée         print_half_number(i, input);
3848ec8a55eSAlex Bennée #if defined(__arm__)
3858ec8a55eSAlex Bennée         /* asm("vcvt.s32.f16 %0, %1" : "=t" (output) : "t" (input)); v8.2*/
3868ec8a55eSAlex Bennée         output = input;
3878ec8a55eSAlex Bennée #else
38898b323faSAkihiko Odaki         asm("fcvt %s0, %h1" : "=w" (output) : "w" (input));
3898ec8a55eSAlex Bennée #endif
3908ec8a55eSAlex Bennée         print_int64(i, output);
3918ec8a55eSAlex Bennée     }
3928ec8a55eSAlex Bennée }
3938ec8a55eSAlex Bennée 
3948ec8a55eSAlex Bennée typedef struct {
3958ec8a55eSAlex Bennée     int flag;
3968ec8a55eSAlex Bennée     char *desc;
3978ec8a55eSAlex Bennée } float_mapping;
3988ec8a55eSAlex Bennée 
3998ec8a55eSAlex Bennée float_mapping round_flags[] = {
4008ec8a55eSAlex Bennée     { FE_TONEAREST, "to nearest" },
4018ec8a55eSAlex Bennée     { FE_UPWARD, "upwards" },
4028ec8a55eSAlex Bennée     { FE_DOWNWARD, "downwards" },
4038ec8a55eSAlex Bennée     { FE_TOWARDZERO, "to zero" }
4048ec8a55eSAlex Bennée };
4058ec8a55eSAlex Bennée 
main(int argc,char * argv[argc])4068ec8a55eSAlex Bennée int main(int argc, char *argv[argc])
4078ec8a55eSAlex Bennée {
4088ec8a55eSAlex Bennée     int i;
4098ec8a55eSAlex Bennée 
4108ec8a55eSAlex Bennée     printf("#### Enabling IEEE Half Precision\n");
4118ec8a55eSAlex Bennée 
4128ec8a55eSAlex Bennée     for (i = 0; i < ARRAY_SIZE(round_flags); ++i) {
4138ec8a55eSAlex Bennée         fesetround(round_flags[i].flag);
4148ec8a55eSAlex Bennée         printf("### Rounding %s\n", round_flags[i].desc);
4158ec8a55eSAlex Bennée         convert_single_to_half();
4168ec8a55eSAlex Bennée         convert_single_to_double();
4178ec8a55eSAlex Bennée         convert_double_to_half();
4188ec8a55eSAlex Bennée         convert_double_to_single();
4198ec8a55eSAlex Bennée         convert_half_to_single();
4208ec8a55eSAlex Bennée         convert_half_to_double();
4218ec8a55eSAlex Bennée     }
4228ec8a55eSAlex Bennée 
4238ec8a55eSAlex Bennée     /* convert to integer */
4248ec8a55eSAlex Bennée     convert_single_to_integer();
4258ec8a55eSAlex Bennée     convert_double_to_integer();
4268ec8a55eSAlex Bennée     convert_half_to_integer();
4278ec8a55eSAlex Bennée 
4288ec8a55eSAlex Bennée     /* And now with ARM alternative FP16 */
4298ec8a55eSAlex Bennée #if defined(__arm__)
430*2f93ff31SRichard Henderson     asm("vmrs r1, fpscr\n\t"
4318ec8a55eSAlex Bennée         "orr r1, r1, %[flags]\n\t"
432*2f93ff31SRichard Henderson         "vmsr fpscr, r1"
4338ec8a55eSAlex Bennée         : /* no output */ : [flags] "n" (1 << 26) : "r1" );
4348ec8a55eSAlex Bennée #else
4358ec8a55eSAlex Bennée     asm("mrs x1, fpcr\n\t"
4368ec8a55eSAlex Bennée         "orr x1, x1, %[flags]\n\t"
4378ec8a55eSAlex Bennée         "msr fpcr, x1\n\t"
4388ec8a55eSAlex Bennée         : /* no output */ : [flags] "n" (1 << 26) : "x1" );
4398ec8a55eSAlex Bennée #endif
4408ec8a55eSAlex Bennée 
4418ec8a55eSAlex Bennée     printf("#### Enabling ARM Alternative Half Precision\n");
4428ec8a55eSAlex Bennée 
4438ec8a55eSAlex Bennée     for (i = 0; i < ARRAY_SIZE(round_flags); ++i) {
4448ec8a55eSAlex Bennée         fesetround(round_flags[i].flag);
4458ec8a55eSAlex Bennée         printf("### Rounding %s\n", round_flags[i].desc);
4468ec8a55eSAlex Bennée         convert_single_to_half();
4478ec8a55eSAlex Bennée         convert_single_to_double();
4488ec8a55eSAlex Bennée         convert_double_to_half();
4498ec8a55eSAlex Bennée         convert_double_to_single();
4508ec8a55eSAlex Bennée         convert_half_to_single();
4518ec8a55eSAlex Bennée         convert_half_to_double();
4528ec8a55eSAlex Bennée     }
4538ec8a55eSAlex Bennée 
4548ec8a55eSAlex Bennée     /* convert to integer */
4558ec8a55eSAlex Bennée     convert_single_to_integer();
4568ec8a55eSAlex Bennée     convert_double_to_integer();
4578ec8a55eSAlex Bennée     convert_half_to_integer();
4588ec8a55eSAlex Bennée 
4598ec8a55eSAlex Bennée     return 0;
4608ec8a55eSAlex Bennée }
461