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 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 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 *) # 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 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 *) # 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 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 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 *) # 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 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 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 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 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 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 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 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 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__) 358*1e7c9ba4SAkihiko Odaki /* 359*1e7c9ba4SAkihiko Odaki * Clang refuses to allocate an integer to a fp register. 360*1e7c9ba4SAkihiko Odaki * Perform the move from a general register by hand. 361*1e7c9ba4SAkihiko Odaki */ 362*1e7c9ba4SAkihiko Odaki asm("vmov %0, %1\n\t" 363*1e7c9ba4SAkihiko 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 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 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__) 4308ec8a55eSAlex Bennée /* See glibc sysdeps/arm/fpu_control.h */ 4318ec8a55eSAlex Bennée asm("mrc p10, 7, r1, cr1, cr0, 0\n\t" 4328ec8a55eSAlex Bennée "orr r1, r1, %[flags]\n\t" 4338ec8a55eSAlex Bennée "mcr p10, 7, r1, cr1, cr0, 0\n\t" 4348ec8a55eSAlex Bennée : /* no output */ : [flags] "n" (1 << 26) : "r1" ); 4358ec8a55eSAlex Bennée #else 4368ec8a55eSAlex Bennée asm("mrs x1, fpcr\n\t" 4378ec8a55eSAlex Bennée "orr x1, x1, %[flags]\n\t" 4388ec8a55eSAlex Bennée "msr fpcr, x1\n\t" 4398ec8a55eSAlex Bennée : /* no output */ : [flags] "n" (1 << 26) : "x1" ); 4408ec8a55eSAlex Bennée #endif 4418ec8a55eSAlex Bennée 4428ec8a55eSAlex Bennée printf("#### Enabling ARM Alternative Half Precision\n"); 4438ec8a55eSAlex Bennée 4448ec8a55eSAlex Bennée for (i = 0; i < ARRAY_SIZE(round_flags); ++i) { 4458ec8a55eSAlex Bennée fesetround(round_flags[i].flag); 4468ec8a55eSAlex Bennée printf("### Rounding %s\n", round_flags[i].desc); 4478ec8a55eSAlex Bennée convert_single_to_half(); 4488ec8a55eSAlex Bennée convert_single_to_double(); 4498ec8a55eSAlex Bennée convert_double_to_half(); 4508ec8a55eSAlex Bennée convert_double_to_single(); 4518ec8a55eSAlex Bennée convert_half_to_single(); 4528ec8a55eSAlex Bennée convert_half_to_double(); 4538ec8a55eSAlex Bennée } 4548ec8a55eSAlex Bennée 4558ec8a55eSAlex Bennée /* convert to integer */ 4568ec8a55eSAlex Bennée convert_single_to_integer(); 4578ec8a55eSAlex Bennée convert_double_to_integer(); 4588ec8a55eSAlex Bennée convert_half_to_integer(); 4598ec8a55eSAlex Bennée 4608ec8a55eSAlex Bennée return 0; 4618ec8a55eSAlex Bennée } 462