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 *) #
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 *) #
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 *) #
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