xref: /qemu/tests/tcg/arm/fcvt.c (revision 77d35c83)
1*8ec8a55eSAlex Bennée /*
2*8ec8a55eSAlex Bennée  * Test Floating Point Conversion
3*8ec8a55eSAlex Bennée  */
4*8ec8a55eSAlex Bennée 
5*8ec8a55eSAlex Bennée /* we want additional float type definitions */
6*8ec8a55eSAlex Bennée #define __STDC_WANT_IEC_60559_BFP_EXT__
7*8ec8a55eSAlex Bennée #define __STDC_WANT_IEC_60559_TYPES_EXT__
8*8ec8a55eSAlex Bennée 
9*8ec8a55eSAlex Bennée #include <stdio.h>
10*8ec8a55eSAlex Bennée #include <inttypes.h>
11*8ec8a55eSAlex Bennée #include <math.h>
12*8ec8a55eSAlex Bennée #include <float.h>
13*8ec8a55eSAlex Bennée #include <fenv.h>
14*8ec8a55eSAlex Bennée 
15*8ec8a55eSAlex Bennée #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
16*8ec8a55eSAlex Bennée 
17*8ec8a55eSAlex Bennée static char flag_str[256];
18*8ec8a55eSAlex Bennée 
get_flag_state(int flags)19*8ec8a55eSAlex Bennée static char *get_flag_state(int flags)
20*8ec8a55eSAlex Bennée {
21*8ec8a55eSAlex Bennée     if (flags) {
22*8ec8a55eSAlex Bennée         snprintf(flag_str, sizeof(flag_str), "%s %s %s %s %s",
23*8ec8a55eSAlex Bennée                  flags & FE_OVERFLOW ? "OVERFLOW" : "",
24*8ec8a55eSAlex Bennée                  flags & FE_UNDERFLOW ? "UNDERFLOW" : "",
25*8ec8a55eSAlex Bennée                  flags & FE_DIVBYZERO ? "DIV0" : "",
26*8ec8a55eSAlex Bennée                  flags & FE_INEXACT ? "INEXACT" : "",
27*8ec8a55eSAlex Bennée                  flags & FE_INVALID ? "INVALID" : "");
28*8ec8a55eSAlex Bennée     } else {
29*8ec8a55eSAlex Bennée         snprintf(flag_str, sizeof(flag_str), "OK");
30*8ec8a55eSAlex Bennée     }
31*8ec8a55eSAlex Bennée 
32*8ec8a55eSAlex Bennée     return flag_str;
33*8ec8a55eSAlex Bennée }
34*8ec8a55eSAlex Bennée 
print_double_number(int i,double num)35*8ec8a55eSAlex Bennée static void print_double_number(int i, double num)
36*8ec8a55eSAlex Bennée {
37*8ec8a55eSAlex Bennée     uint64_t double_as_hex = *(uint64_t *) &num;
38*8ec8a55eSAlex Bennée     int flags = fetestexcept(FE_ALL_EXCEPT);
39*8ec8a55eSAlex Bennée     char *fstr = get_flag_state(flags);
40*8ec8a55eSAlex Bennée 
41*8ec8a55eSAlex Bennée     printf("%02d DOUBLE: %02.20e / %#020" PRIx64 " (%#x => %s)\n",
42*8ec8a55eSAlex Bennée            i, num, double_as_hex, flags, fstr);
43*8ec8a55eSAlex Bennée }
44*8ec8a55eSAlex Bennée 
print_single_number(int i,float num)45*8ec8a55eSAlex Bennée static void print_single_number(int i, float num)
46*8ec8a55eSAlex Bennée {
47*8ec8a55eSAlex Bennée     uint32_t single_as_hex = *(uint32_t *) &num;
48*8ec8a55eSAlex Bennée     int flags = fetestexcept(FE_ALL_EXCEPT);
49*8ec8a55eSAlex Bennée     char *fstr = get_flag_state(flags);
50*8ec8a55eSAlex Bennée 
51*8ec8a55eSAlex Bennée     printf("%02d SINGLE: %02.20e / %#010x  (%#x => %s)\n",
52*8ec8a55eSAlex Bennée            i, num, single_as_hex, flags, fstr);
53*8ec8a55eSAlex Bennée }
54*8ec8a55eSAlex Bennée 
print_half_number(int i,uint16_t num)55*8ec8a55eSAlex Bennée static void print_half_number(int i, uint16_t num)
56*8ec8a55eSAlex Bennée {
57*8ec8a55eSAlex Bennée     int flags = fetestexcept(FE_ALL_EXCEPT);
58*8ec8a55eSAlex Bennée     char *fstr = get_flag_state(flags);
59*8ec8a55eSAlex Bennée 
60*8ec8a55eSAlex Bennée     printf("%02d   HALF: %#04x  (%#x => %s)\n",
61*8ec8a55eSAlex Bennée            i, num, flags, fstr);
62*8ec8a55eSAlex Bennée }
63*8ec8a55eSAlex Bennée 
print_int64(int i,int64_t num)64*8ec8a55eSAlex Bennée static void print_int64(int i, int64_t num)
65*8ec8a55eSAlex Bennée {
66*8ec8a55eSAlex Bennée     uint64_t int64_as_hex = *(uint64_t *) &num;
67*8ec8a55eSAlex Bennée     int flags = fetestexcept(FE_ALL_EXCEPT);
68*8ec8a55eSAlex Bennée     char *fstr = get_flag_state(flags);
69*8ec8a55eSAlex Bennée 
70*8ec8a55eSAlex Bennée     printf("%02d   INT64: %20" PRId64 "/%#020" PRIx64 " (%#x => %s)\n",
71*8ec8a55eSAlex Bennée            i, num, int64_as_hex, flags, fstr);
72*8ec8a55eSAlex Bennée }
73*8ec8a55eSAlex Bennée 
74*8ec8a55eSAlex Bennée #ifndef SNANF
75*8ec8a55eSAlex Bennée /* Signaling NaN macros, if supported.  */
76*8ec8a55eSAlex Bennée # define SNANF (__builtin_nansf (""))
77*8ec8a55eSAlex Bennée # define SNAN (__builtin_nans (""))
78*8ec8a55eSAlex Bennée # define SNANL (__builtin_nansl (""))
79*8ec8a55eSAlex Bennée #endif
80*8ec8a55eSAlex Bennée 
81*8ec8a55eSAlex Bennée float single_numbers[] = { -SNANF,
82*8ec8a55eSAlex Bennée                            -NAN,
83*8ec8a55eSAlex Bennée                            -INFINITY,
84*8ec8a55eSAlex Bennée                            -FLT_MAX,
85*8ec8a55eSAlex Bennée                            -1.111E+31,
86*8ec8a55eSAlex Bennée                            -1.111E+30,
87*8ec8a55eSAlex Bennée                            -1.08700982e-12,
88*8ec8a55eSAlex Bennée                            -1.78051176e-20,
89*8ec8a55eSAlex Bennée                            -FLT_MIN,
90*8ec8a55eSAlex Bennée                            0.0,
91*8ec8a55eSAlex Bennée                            FLT_MIN,
92*8ec8a55eSAlex Bennée                            2.98023224e-08,
93*8ec8a55eSAlex Bennée                            5.96046E-8, /* min positive FP16 subnormal */
94*8ec8a55eSAlex Bennée                            6.09756E-5, /* max subnormal FP16 */
95*8ec8a55eSAlex Bennée                            6.10352E-5, /* min positive normal FP16 */
96*8ec8a55eSAlex Bennée                            1.0,
97*8ec8a55eSAlex Bennée                            1.0009765625, /* smallest float after 1.0 FP16 */
98*8ec8a55eSAlex Bennée                            2.0,
99*8ec8a55eSAlex Bennée                            M_E, M_PI,
100*8ec8a55eSAlex Bennée                            65503.0,
101*8ec8a55eSAlex Bennée                            65504.0, /* max FP16 */
102*8ec8a55eSAlex Bennée                            65505.0,
103*8ec8a55eSAlex Bennée                            131007.0,
104*8ec8a55eSAlex Bennée                            131008.0, /* max AFP */
105*8ec8a55eSAlex Bennée                            131009.0,
106*8ec8a55eSAlex Bennée                            1.111E+30,
107*8ec8a55eSAlex Bennée                            FLT_MAX,
108*8ec8a55eSAlex Bennée                            INFINITY,
109*8ec8a55eSAlex Bennée                            NAN,
110*8ec8a55eSAlex Bennée                            SNANF };
111*8ec8a55eSAlex Bennée 
convert_single_to_half(void)112*8ec8a55eSAlex Bennée static void convert_single_to_half(void)
113*8ec8a55eSAlex Bennée {
114*8ec8a55eSAlex Bennée     int i;
115*8ec8a55eSAlex Bennée 
116*8ec8a55eSAlex Bennée     printf("Converting single-precision to half-precision\n");
117*8ec8a55eSAlex Bennée 
118*8ec8a55eSAlex Bennée     for (i = 0; i < ARRAY_SIZE(single_numbers); ++i) {
119*8ec8a55eSAlex Bennée         float input = single_numbers[i];
120*8ec8a55eSAlex Bennée 
121*8ec8a55eSAlex Bennée         feclearexcept(FE_ALL_EXCEPT);
122*8ec8a55eSAlex Bennée 
123*8ec8a55eSAlex Bennée         print_single_number(i, input);
124*8ec8a55eSAlex Bennée #if defined(__arm__)
125*8ec8a55eSAlex Bennée         uint32_t output;
126*8ec8a55eSAlex Bennée         asm("vcvtb.f16.f32 %0, %1" : "=t" (output) : "x" (input));
127*8ec8a55eSAlex Bennée #else
128*8ec8a55eSAlex Bennée         uint16_t output;
129*8ec8a55eSAlex Bennée         asm("fcvt %h0, %s1" : "=w" (output) : "x" (input));
130*8ec8a55eSAlex Bennée #endif
131*8ec8a55eSAlex Bennée         print_half_number(i, output);
132*8ec8a55eSAlex Bennée     }
133*8ec8a55eSAlex Bennée }
134*8ec8a55eSAlex Bennée 
convert_single_to_double(void)135*8ec8a55eSAlex Bennée static void convert_single_to_double(void)
136*8ec8a55eSAlex Bennée {
137*8ec8a55eSAlex Bennée     int i;
138*8ec8a55eSAlex Bennée 
139*8ec8a55eSAlex Bennée     printf("Converting single-precision to double-precision\n");
140*8ec8a55eSAlex Bennée 
141*8ec8a55eSAlex Bennée     for (i = 0; i < ARRAY_SIZE(single_numbers); ++i) {
142*8ec8a55eSAlex Bennée         float input = single_numbers[i];
143*8ec8a55eSAlex Bennée         /* uint64_t output; */
144*8ec8a55eSAlex Bennée         double output;
145*8ec8a55eSAlex Bennée 
146*8ec8a55eSAlex Bennée         feclearexcept(FE_ALL_EXCEPT);
147*8ec8a55eSAlex Bennée 
148*8ec8a55eSAlex Bennée         print_single_number(i, input);
149*8ec8a55eSAlex Bennée #if defined(__arm__)
150*8ec8a55eSAlex Bennée         asm("vcvt.f64.f32 %P0, %1" : "=w" (output) : "t" (input));
151*8ec8a55eSAlex Bennée #else
152*8ec8a55eSAlex Bennée         asm("fcvt %d0, %s1" : "=w" (output) : "x" (input));
153*8ec8a55eSAlex Bennée #endif
154*8ec8a55eSAlex Bennée         print_double_number(i, output);
155*8ec8a55eSAlex Bennée     }
156*8ec8a55eSAlex Bennée }
157*8ec8a55eSAlex Bennée 
convert_single_to_integer(void)158*8ec8a55eSAlex Bennée static void convert_single_to_integer(void)
159*8ec8a55eSAlex Bennée {
160*8ec8a55eSAlex Bennée     int i;
161*8ec8a55eSAlex Bennée 
162*8ec8a55eSAlex Bennée     printf("Converting single-precision to integer\n");
163*8ec8a55eSAlex Bennée 
164*8ec8a55eSAlex Bennée     for (i = 0; i < ARRAY_SIZE(single_numbers); ++i) {
165*8ec8a55eSAlex Bennée         float input = single_numbers[i];
166*8ec8a55eSAlex Bennée         int64_t output;
167*8ec8a55eSAlex Bennée 
168*8ec8a55eSAlex Bennée         feclearexcept(FE_ALL_EXCEPT);
169*8ec8a55eSAlex Bennée 
170*8ec8a55eSAlex Bennée         print_single_number(i, input);
171*8ec8a55eSAlex Bennée #if defined(__arm__)
172*8ec8a55eSAlex Bennée         /* asm("vcvt.s32.f32 %s0, %s1" : "=t" (output) : "t" (input)); */
173*8ec8a55eSAlex Bennée         output = input;
174*8ec8a55eSAlex Bennée #else
175*8ec8a55eSAlex Bennée         asm("fcvtzs %0, %s1" : "=r" (output) : "w" (input));
176*8ec8a55eSAlex Bennée #endif
177*8ec8a55eSAlex Bennée         print_int64(i, output);
178*8ec8a55eSAlex Bennée     }
179*8ec8a55eSAlex Bennée }
180*8ec8a55eSAlex Bennée 
181*8ec8a55eSAlex Bennée /* This allows us to initialise some doubles as pure hex */
182*8ec8a55eSAlex Bennée typedef union {
183*8ec8a55eSAlex Bennée     double d;
184*8ec8a55eSAlex Bennée     uint64_t h;
185*8ec8a55eSAlex Bennée } test_doubles;
186*8ec8a55eSAlex Bennée 
187*8ec8a55eSAlex Bennée test_doubles double_numbers[] = {
188*8ec8a55eSAlex Bennée     {SNAN},
189*8ec8a55eSAlex Bennée     {-NAN},
190*8ec8a55eSAlex Bennée     {-INFINITY},
191*8ec8a55eSAlex Bennée     {-DBL_MAX},
192*8ec8a55eSAlex Bennée     {-FLT_MAX-1.0},
193*8ec8a55eSAlex Bennée     {-FLT_MAX},
194*8ec8a55eSAlex Bennée     {-1.111E+31},
195*8ec8a55eSAlex Bennée     {-1.111E+30}, /* half prec */
196*8ec8a55eSAlex Bennée     {-2.0}, {-1.0},
197*8ec8a55eSAlex Bennée     {-DBL_MIN},
198*8ec8a55eSAlex Bennée     {-FLT_MIN},
199*8ec8a55eSAlex Bennée     {0.0},
200*8ec8a55eSAlex Bennée     {FLT_MIN},
201*8ec8a55eSAlex Bennée     {2.98023224e-08},
202*8ec8a55eSAlex Bennée     {5.96046E-8}, /* min positive FP16 subnormal */
203*8ec8a55eSAlex Bennée     {6.09756E-5}, /* max subnormal FP16 */
204*8ec8a55eSAlex Bennée     {6.10352E-5}, /* min positive normal FP16 */
205*8ec8a55eSAlex Bennée     {1.0},
206*8ec8a55eSAlex Bennée     {1.0009765625}, /* smallest float after 1.0 FP16 */
207*8ec8a55eSAlex Bennée     {DBL_MIN},
208*8ec8a55eSAlex Bennée     {1.3789972848607228e-308},
209*8ec8a55eSAlex Bennée     {1.4914738736681624e-308},
210*8ec8a55eSAlex Bennée     {1.0}, {2.0},
211*8ec8a55eSAlex Bennée     {M_E}, {M_PI},
212*8ec8a55eSAlex Bennée     {65503.0},
213*8ec8a55eSAlex Bennée     {65504.0}, /* max FP16 */
214*8ec8a55eSAlex Bennée     {65505.0},
215*8ec8a55eSAlex Bennée     {131007.0},
216*8ec8a55eSAlex Bennée     {131008.0}, /* max AFP */
217*8ec8a55eSAlex Bennée     {131009.0},
218*8ec8a55eSAlex Bennée     {.h = 0x41dfffffffc00000 }, /* to int = 0x7fffffff */
219*8ec8a55eSAlex Bennée     {FLT_MAX},
220*8ec8a55eSAlex Bennée     {FLT_MAX + 1.0},
221*8ec8a55eSAlex Bennée     {DBL_MAX},
222*8ec8a55eSAlex Bennée     {INFINITY},
223*8ec8a55eSAlex Bennée     {NAN},
224*8ec8a55eSAlex Bennée     {.h = 0x7ff0000000000001}, /* SNAN */
225*8ec8a55eSAlex Bennée     {SNAN},
226*8ec8a55eSAlex Bennée };
227*8ec8a55eSAlex Bennée 
convert_double_to_half(void)228*8ec8a55eSAlex Bennée static void convert_double_to_half(void)
229*8ec8a55eSAlex Bennée {
230*8ec8a55eSAlex Bennée     int i;
231*8ec8a55eSAlex Bennée 
232*8ec8a55eSAlex Bennée     printf("Converting double-precision to half-precision\n");
233*8ec8a55eSAlex Bennée 
234*8ec8a55eSAlex Bennée     for (i = 0; i < ARRAY_SIZE(double_numbers); ++i) {
235*8ec8a55eSAlex Bennée         double input = double_numbers[i].d;
236*8ec8a55eSAlex Bennée         uint16_t output;
237*8ec8a55eSAlex Bennée 
238*8ec8a55eSAlex Bennée         feclearexcept(FE_ALL_EXCEPT);
239*8ec8a55eSAlex Bennée 
240*8ec8a55eSAlex Bennée         print_double_number(i, input);
241*8ec8a55eSAlex Bennée 
242*8ec8a55eSAlex Bennée         /* as we don't have _Float16 support */
243*8ec8a55eSAlex Bennée #if defined(__arm__)
244*8ec8a55eSAlex Bennée         /* asm("vcvtb.f16.f64 %0, %P1" : "=t" (output) : "x" (input)); */
245*8ec8a55eSAlex Bennée         output = input;
246*8ec8a55eSAlex Bennée #else
247*8ec8a55eSAlex Bennée         asm("fcvt %h0, %d1" : "=w" (output) : "x" (input));
248*8ec8a55eSAlex Bennée #endif
249*8ec8a55eSAlex Bennée         print_half_number(i, output);
250*8ec8a55eSAlex Bennée     }
251*8ec8a55eSAlex Bennée }
252*8ec8a55eSAlex Bennée 
convert_double_to_single(void)253*8ec8a55eSAlex Bennée static void convert_double_to_single(void)
254*8ec8a55eSAlex Bennée {
255*8ec8a55eSAlex Bennée     int i;
256*8ec8a55eSAlex Bennée 
257*8ec8a55eSAlex Bennée     printf("Converting double-precision to single-precision\n");
258*8ec8a55eSAlex Bennée 
259*8ec8a55eSAlex Bennée     for (i = 0; i < ARRAY_SIZE(double_numbers); ++i) {
260*8ec8a55eSAlex Bennée         double input = double_numbers[i].d;
261*8ec8a55eSAlex Bennée         uint32_t output;
262*8ec8a55eSAlex Bennée 
263*8ec8a55eSAlex Bennée         feclearexcept(FE_ALL_EXCEPT);
264*8ec8a55eSAlex Bennée 
265*8ec8a55eSAlex Bennée         print_double_number(i, input);
266*8ec8a55eSAlex Bennée 
267*8ec8a55eSAlex Bennée #if defined(__arm__)
268*8ec8a55eSAlex Bennée         asm("vcvt.f32.f64 %0, %P1" : "=w" (output) : "x" (input));
269*8ec8a55eSAlex Bennée #else
270*8ec8a55eSAlex Bennée         asm("fcvt %s0, %d1" : "=w" (output) : "x" (input));
271*8ec8a55eSAlex Bennée #endif
272*8ec8a55eSAlex Bennée 
273*8ec8a55eSAlex Bennée         print_single_number(i, output);
274*8ec8a55eSAlex Bennée     }
275*8ec8a55eSAlex Bennée }
276*8ec8a55eSAlex Bennée 
convert_double_to_integer(void)277*8ec8a55eSAlex Bennée static void convert_double_to_integer(void)
278*8ec8a55eSAlex Bennée {
279*8ec8a55eSAlex Bennée     int i;
280*8ec8a55eSAlex Bennée 
281*8ec8a55eSAlex Bennée     printf("Converting double-precision to integer\n");
282*8ec8a55eSAlex Bennée 
283*8ec8a55eSAlex Bennée     for (i = 0; i < ARRAY_SIZE(double_numbers); ++i) {
284*8ec8a55eSAlex Bennée         double input = double_numbers[i].d;
285*8ec8a55eSAlex Bennée         int64_t output;
286*8ec8a55eSAlex Bennée 
287*8ec8a55eSAlex Bennée         feclearexcept(FE_ALL_EXCEPT);
288*8ec8a55eSAlex Bennée 
289*8ec8a55eSAlex Bennée         print_double_number(i, input);
290*8ec8a55eSAlex Bennée #if defined(__arm__)
291*8ec8a55eSAlex Bennée         /* asm("vcvt.s32.f32 %s0, %s1" : "=t" (output) : "t" (input)); */
292*8ec8a55eSAlex Bennée         output = input;
293*8ec8a55eSAlex Bennée #else
294*8ec8a55eSAlex Bennée         asm("fcvtzs %0, %d1" : "=r" (output) : "w" (input));
295*8ec8a55eSAlex Bennée #endif
296*8ec8a55eSAlex Bennée         print_int64(i, output);
297*8ec8a55eSAlex Bennée     }
298*8ec8a55eSAlex Bennée }
299*8ec8a55eSAlex Bennée 
300*8ec8a55eSAlex Bennée /* no handy defines for these numbers */
301*8ec8a55eSAlex Bennée uint16_t half_numbers[] = {
302*8ec8a55eSAlex Bennée     0xffff, /* -NaN / AHP -Max */
303*8ec8a55eSAlex Bennée     0xfcff, /* -NaN / AHP */
304*8ec8a55eSAlex Bennée     0xfc01, /* -NaN / AHP */
305*8ec8a55eSAlex Bennée     0xfc00, /* -Inf */
306*8ec8a55eSAlex Bennée     0xfbff, /* -Max */
307*8ec8a55eSAlex Bennée     0xc000, /* -2 */
308*8ec8a55eSAlex Bennée     0xbc00, /* -1 */
309*8ec8a55eSAlex Bennée     0x8001, /* -MIN subnormal */
310*8ec8a55eSAlex Bennée     0x8000, /* -0 */
311*8ec8a55eSAlex Bennée     0x0000, /* +0 */
312*8ec8a55eSAlex Bennée     0x0001, /* MIN subnormal */
313*8ec8a55eSAlex Bennée     0x3c00, /* 1 */
314*8ec8a55eSAlex Bennée     0x7bff, /* Max */
315*8ec8a55eSAlex Bennée     0x7c00, /* Inf */
316*8ec8a55eSAlex Bennée     0x7c01, /* NaN / AHP */
317*8ec8a55eSAlex Bennée     0x7cff, /* NaN / AHP */
318*8ec8a55eSAlex Bennée     0x7fff, /* NaN / AHP +Max*/
319*8ec8a55eSAlex Bennée };
320*8ec8a55eSAlex Bennée 
convert_half_to_double(void)321*8ec8a55eSAlex Bennée static void convert_half_to_double(void)
322*8ec8a55eSAlex Bennée {
323*8ec8a55eSAlex Bennée     int i;
324*8ec8a55eSAlex Bennée 
325*8ec8a55eSAlex Bennée     printf("Converting half-precision to double-precision\n");
326*8ec8a55eSAlex Bennée 
327*8ec8a55eSAlex Bennée     for (i = 0; i < ARRAY_SIZE(half_numbers); ++i) {
328*8ec8a55eSAlex Bennée         uint16_t input = half_numbers[i];
329*8ec8a55eSAlex Bennée         double output;
330*8ec8a55eSAlex Bennée 
331*8ec8a55eSAlex Bennée         feclearexcept(FE_ALL_EXCEPT);
332*8ec8a55eSAlex Bennée 
333*8ec8a55eSAlex Bennée         print_half_number(i, input);
334*8ec8a55eSAlex Bennée #if defined(__arm__)
335*8ec8a55eSAlex Bennée         /* asm("vcvtb.f64.f16 %P0, %1" : "=w" (output) : "t" (input)); */
336*8ec8a55eSAlex Bennée         output = input;
337*8ec8a55eSAlex Bennée #else
338*8ec8a55eSAlex Bennée         asm("fcvt %d0, %h1" : "=w" (output) : "x" (input));
339*8ec8a55eSAlex Bennée #endif
340*8ec8a55eSAlex Bennée         print_double_number(i, output);
341*8ec8a55eSAlex Bennée     }
342*8ec8a55eSAlex Bennée }
343*8ec8a55eSAlex Bennée 
convert_half_to_single(void)344*8ec8a55eSAlex Bennée static void convert_half_to_single(void)
345*8ec8a55eSAlex Bennée {
346*8ec8a55eSAlex Bennée     int i;
347*8ec8a55eSAlex Bennée 
348*8ec8a55eSAlex Bennée     printf("Converting half-precision to single-precision\n");
349*8ec8a55eSAlex Bennée 
350*8ec8a55eSAlex Bennée     for (i = 0; i < ARRAY_SIZE(half_numbers); ++i) {
351*8ec8a55eSAlex Bennée         uint16_t input = half_numbers[i];
352*8ec8a55eSAlex Bennée         float output;
353*8ec8a55eSAlex Bennée 
354*8ec8a55eSAlex Bennée         feclearexcept(FE_ALL_EXCEPT);
355*8ec8a55eSAlex Bennée 
356*8ec8a55eSAlex Bennée         print_half_number(i, input);
357*8ec8a55eSAlex Bennée #if defined(__arm__)
358*8ec8a55eSAlex Bennée         asm("vcvtb.f32.f16 %0, %1" : "=w" (output) : "x" ((uint32_t)input));
359*8ec8a55eSAlex Bennée #else
360*8ec8a55eSAlex Bennée         asm("fcvt %s0, %h1" : "=w" (output) : "x" (input));
361*8ec8a55eSAlex Bennée #endif
362*8ec8a55eSAlex Bennée         print_single_number(i, output);
363*8ec8a55eSAlex Bennée     }
364*8ec8a55eSAlex Bennée }
365*8ec8a55eSAlex Bennée 
convert_half_to_integer(void)366*8ec8a55eSAlex Bennée static void convert_half_to_integer(void)
367*8ec8a55eSAlex Bennée {
368*8ec8a55eSAlex Bennée     int i;
369*8ec8a55eSAlex Bennée 
370*8ec8a55eSAlex Bennée     printf("Converting half-precision to integer\n");
371*8ec8a55eSAlex Bennée 
372*8ec8a55eSAlex Bennée     for (i = 0; i < ARRAY_SIZE(half_numbers); ++i) {
373*8ec8a55eSAlex Bennée         uint16_t input = half_numbers[i];
374*8ec8a55eSAlex Bennée         int64_t output;
375*8ec8a55eSAlex Bennée 
376*8ec8a55eSAlex Bennée         feclearexcept(FE_ALL_EXCEPT);
377*8ec8a55eSAlex Bennée 
378*8ec8a55eSAlex Bennée         print_half_number(i, input);
379*8ec8a55eSAlex Bennée #if defined(__arm__)
380*8ec8a55eSAlex Bennée         /* asm("vcvt.s32.f16 %0, %1" : "=t" (output) : "t" (input)); v8.2*/
381*8ec8a55eSAlex Bennée         output = input;
382*8ec8a55eSAlex Bennée #else
383*8ec8a55eSAlex Bennée         asm("fcvt %s0, %h1" : "=w" (output) : "x" (input));
384*8ec8a55eSAlex Bennée #endif
385*8ec8a55eSAlex Bennée         print_int64(i, output);
386*8ec8a55eSAlex Bennée     }
387*8ec8a55eSAlex Bennée }
388*8ec8a55eSAlex Bennée 
389*8ec8a55eSAlex Bennée typedef struct {
390*8ec8a55eSAlex Bennée     int flag;
391*8ec8a55eSAlex Bennée     char *desc;
392*8ec8a55eSAlex Bennée } float_mapping;
393*8ec8a55eSAlex Bennée 
394*8ec8a55eSAlex Bennée float_mapping round_flags[] = {
395*8ec8a55eSAlex Bennée     { FE_TONEAREST, "to nearest" },
396*8ec8a55eSAlex Bennée     { FE_UPWARD, "upwards" },
397*8ec8a55eSAlex Bennée     { FE_DOWNWARD, "downwards" },
398*8ec8a55eSAlex Bennée     { FE_TOWARDZERO, "to zero" }
399*8ec8a55eSAlex Bennée };
400*8ec8a55eSAlex Bennée 
main(int argc,char * argv[argc])401*8ec8a55eSAlex Bennée int main(int argc, char *argv[argc])
402*8ec8a55eSAlex Bennée {
403*8ec8a55eSAlex Bennée     int i;
404*8ec8a55eSAlex Bennée 
405*8ec8a55eSAlex Bennée     printf("#### Enabling IEEE Half Precision\n");
406*8ec8a55eSAlex Bennée 
407*8ec8a55eSAlex Bennée     for (i = 0; i < ARRAY_SIZE(round_flags); ++i) {
408*8ec8a55eSAlex Bennée         fesetround(round_flags[i].flag);
409*8ec8a55eSAlex Bennée         printf("### Rounding %s\n", round_flags[i].desc);
410*8ec8a55eSAlex Bennée         convert_single_to_half();
411*8ec8a55eSAlex Bennée         convert_single_to_double();
412*8ec8a55eSAlex Bennée         convert_double_to_half();
413*8ec8a55eSAlex Bennée         convert_double_to_single();
414*8ec8a55eSAlex Bennée         convert_half_to_single();
415*8ec8a55eSAlex Bennée         convert_half_to_double();
416*8ec8a55eSAlex Bennée     }
417*8ec8a55eSAlex Bennée 
418*8ec8a55eSAlex Bennée     /* convert to integer */
419*8ec8a55eSAlex Bennée     convert_single_to_integer();
420*8ec8a55eSAlex Bennée     convert_double_to_integer();
421*8ec8a55eSAlex Bennée     convert_half_to_integer();
422*8ec8a55eSAlex Bennée 
423*8ec8a55eSAlex Bennée     /* And now with ARM alternative FP16 */
424*8ec8a55eSAlex Bennée #if defined(__arm__)
425*8ec8a55eSAlex Bennée     /* See glibc sysdeps/arm/fpu_control.h */
426*8ec8a55eSAlex Bennée     asm("mrc p10, 7, r1, cr1, cr0, 0\n\t"
427*8ec8a55eSAlex Bennée         "orr r1, r1, %[flags]\n\t"
428*8ec8a55eSAlex Bennée         "mcr p10, 7, r1, cr1, cr0, 0\n\t"
429*8ec8a55eSAlex Bennée         : /* no output */ : [flags] "n" (1 << 26) : "r1" );
430*8ec8a55eSAlex Bennée #else
431*8ec8a55eSAlex Bennée     asm("mrs x1, fpcr\n\t"
432*8ec8a55eSAlex Bennée         "orr x1, x1, %[flags]\n\t"
433*8ec8a55eSAlex Bennée         "msr fpcr, x1\n\t"
434*8ec8a55eSAlex Bennée         : /* no output */ : [flags] "n" (1 << 26) : "x1" );
435*8ec8a55eSAlex Bennée #endif
436*8ec8a55eSAlex Bennée 
437*8ec8a55eSAlex Bennée     printf("#### Enabling ARM Alternative Half Precision\n");
438*8ec8a55eSAlex Bennée 
439*8ec8a55eSAlex Bennée     for (i = 0; i < ARRAY_SIZE(round_flags); ++i) {
440*8ec8a55eSAlex Bennée         fesetround(round_flags[i].flag);
441*8ec8a55eSAlex Bennée         printf("### Rounding %s\n", round_flags[i].desc);
442*8ec8a55eSAlex Bennée         convert_single_to_half();
443*8ec8a55eSAlex Bennée         convert_single_to_double();
444*8ec8a55eSAlex Bennée         convert_double_to_half();
445*8ec8a55eSAlex Bennée         convert_double_to_single();
446*8ec8a55eSAlex Bennée         convert_half_to_single();
447*8ec8a55eSAlex Bennée         convert_half_to_double();
448*8ec8a55eSAlex Bennée     }
449*8ec8a55eSAlex Bennée 
450*8ec8a55eSAlex Bennée     /* convert to integer */
451*8ec8a55eSAlex Bennée     convert_single_to_integer();
452*8ec8a55eSAlex Bennée     convert_double_to_integer();
453*8ec8a55eSAlex Bennée     convert_half_to_integer();
454*8ec8a55eSAlex Bennée 
455*8ec8a55eSAlex Bennée     return 0;
456*8ec8a55eSAlex Bennée }
457