xref: /qemu/tests/tcg/hexagon/fpstuff.c (revision 8b7b9c5c)
1 /*
2  *  Copyright(c) 2020-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /*
19  * This test checks various FP operations performed on Hexagon
20  */
21 
22 #include <stdio.h>
23 #include <stdint.h>
24 #include <float.h>
25 
26 int err;
27 
28 #include "hex_test.h"
29 
30 static void check_fpstatus_bit(uint32_t usr, uint32_t expect, uint32_t flag,
31                                const char *name)
32 {
33     uint32_t bit = 1 << flag;
34     if ((usr & bit) != (expect & bit)) {
35         printf("ERROR %s: usr = %d, expect = %d\n", name,
36                (usr >> flag) & 1, (expect >> flag) & 1);
37         err++;
38     }
39 }
40 
41 static void check_fpstatus(uint32_t usr, uint32_t expect)
42 {
43     check_fpstatus_bit(usr, expect, USR_FPINVF_BIT, "Invalid");
44     check_fpstatus_bit(usr, expect, USR_FPDBZF_BIT, "Div by zero");
45     check_fpstatus_bit(usr, expect, USR_FPOVFF_BIT, "Overflow");
46     check_fpstatus_bit(usr, expect, USR_FPUNFF_BIT, "Underflow");
47     check_fpstatus_bit(usr, expect, USR_FPINPF_BIT, "Inexact");
48 }
49 
50 static void check_compare_exception(void)
51 {
52     uint32_t cmp;
53     uint32_t usr;
54 
55     /* Check that FP compares are quiet (don't raise any exceptions) */
56     asm (CLEAR_FPSTATUS
57          "p0 = sfcmp.eq(%2, %3)\n\t"
58          "%0 = p0\n\t"
59          "%1 = usr\n\t"
60          : "=r"(cmp), "=r"(usr) : "r"(SF_QNaN), "r"(SF_any)
61          : "r2", "p0", "usr");
62     check32(cmp, 0);
63     check_fpstatus(usr, 0);
64 
65     asm (CLEAR_FPSTATUS
66          "p0 = sfcmp.gt(%2, %3)\n\t"
67          "%0 = p0\n\t"
68          "%1 = usr\n\t"
69          : "=r"(cmp), "=r"(usr) : "r"(SF_QNaN), "r"(SF_any)
70          : "r2", "p0", "usr");
71     check32(cmp, 0);
72     check_fpstatus(usr, 0);
73 
74     asm (CLEAR_FPSTATUS
75          "p0 = sfcmp.ge(%2, %3)\n\t"
76          "%0 = p0\n\t"
77          "%1 = usr\n\t"
78          : "=r"(cmp), "=r"(usr) : "r"(SF_QNaN), "r"(SF_any)
79          : "r2", "p0", "usr");
80     check32(cmp, 0);
81     check_fpstatus(usr, 0);
82 
83     asm (CLEAR_FPSTATUS
84          "p0 = dfcmp.eq(%2, %3)\n\t"
85          "%0 = p0\n\t"
86          "%1 = usr\n\t"
87          : "=r"(cmp), "=r"(usr) : "r"(DF_QNaN), "r"(DF_any)
88          : "r2", "p0", "usr");
89     check32(cmp, 0);
90     check_fpstatus(usr, 0);
91 
92     asm (CLEAR_FPSTATUS
93          "p0 = dfcmp.gt(%2, %3)\n\t"
94          "%0 = p0\n\t"
95          "%1 = usr\n\t"
96          : "=r"(cmp), "=r"(usr) : "r"(DF_QNaN), "r"(DF_any)
97          : "r2", "p0", "usr");
98     check32(cmp, 0);
99     check_fpstatus(usr, 0);
100 
101     asm (CLEAR_FPSTATUS
102          "p0 = dfcmp.ge(%2, %3)\n\t"
103          "%0 = p0\n\t"
104          "%1 = usr\n\t"
105          : "=r"(cmp), "=r"(usr) : "r"(DF_QNaN), "r"(DF_any)
106          : "r2", "p0", "usr");
107     check32(cmp, 0);
108     check_fpstatus(usr, 0);
109 }
110 
111 static void check_sfminmax(void)
112 {
113     uint32_t minmax;
114     uint32_t usr;
115 
116     /*
117      * Execute sfmin/sfmax instructions with one operand as NaN
118      * Check that
119      *     Result is the other operand
120      *     Invalid bit in USR is not set
121      */
122      asm (CLEAR_FPSTATUS
123          "%0 = sfmin(%2, %3)\n\t"
124          "%1 = usr\n\t"
125          : "=r"(minmax), "=r"(usr) : "r"(SF_QNaN), "r"(SF_any)
126          : "r2", "usr");
127     check32(minmax, SF_any);
128     check_fpstatus(usr, 0);
129 
130     asm (CLEAR_FPSTATUS
131          "%0 = sfmax(%2, %3)\n\t"
132          "%1 = usr\n\t"
133          : "=r"(minmax), "=r"(usr) : "r"(SF_QNaN), "r"(SF_any)
134          : "r2", "usr");
135     check32(minmax, SF_any);
136     check_fpstatus(usr, 0);
137 
138     /*
139      * Execute sfmin/sfmax instructions with both operands NaN
140      * Check that
141      *     Result is SF_HEX_NaN
142      *     Invalid bit in USR is set
143      */
144     asm (CLEAR_FPSTATUS
145          "%0 = sfmin(%2, %3)\n\t"
146          "%1 = usr\n\t"
147          : "=r"(minmax), "=r"(usr) : "r"(SF_QNaN), "r"(SF_QNaN)
148          : "r2", "usr");
149     check32(minmax, SF_HEX_NaN);
150     check_fpstatus(usr, 0);
151 
152     asm (CLEAR_FPSTATUS
153          "%0 = sfmax(%2, %3)\n\t"
154          "%1 = usr\n\t"
155          : "=r"(minmax), "=r"(usr) : "r"(SF_QNaN), "r"(SF_QNaN)
156          : "r2", "usr");
157     check32(minmax, SF_HEX_NaN);
158     check_fpstatus(usr, 0);
159 }
160 
161 static void check_dfminmax(void)
162 {
163     uint64_t minmax;
164     uint32_t usr;
165 
166     /*
167      * Execute dfmin/dfmax instructions with one operand as SNaN
168      * Check that
169      *     Result is the other operand
170      *     Invalid bit in USR is set
171      */
172      asm (CLEAR_FPSTATUS
173          "%0 = dfmin(%2, %3)\n\t"
174          "%1 = usr\n\t"
175          : "=r"(minmax), "=r"(usr) : "r"(DF_SNaN), "r"(DF_any)
176          : "r2", "usr");
177     check64(minmax, DF_any);
178     check_fpstatus(usr, USR_FPINVF);
179 
180     asm (CLEAR_FPSTATUS
181          "%0 = dfmax(%2, %3)\n\t"
182          "%1 = usr\n\t"
183          : "=r"(minmax), "=r"(usr) : "r"(DF_SNaN), "r"(DF_any)
184          : "r2", "usr");
185     check64(minmax, DF_any);
186     check_fpstatus(usr, USR_FPINVF);
187 
188     /*
189      * Execute dfmin/dfmax instructions with one operand as QNaN
190      * Check that
191      *     Result is the other operand
192      *     No bit in USR is set
193      */
194      asm (CLEAR_FPSTATUS
195          "%0 = dfmin(%2, %3)\n\t"
196          "%1 = usr\n\t"
197          : "=r"(minmax), "=r"(usr) : "r"(DF_QNaN), "r"(DF_any)
198          : "r2", "usr");
199     check64(minmax, DF_any);
200     check_fpstatus(usr, 0);
201 
202     asm (CLEAR_FPSTATUS
203          "%0 = dfmax(%2, %3)\n\t"
204          "%1 = usr\n\t"
205          : "=r"(minmax), "=r"(usr) : "r"(DF_QNaN), "r"(DF_any)
206          : "r2", "usr");
207     check64(minmax, DF_any);
208     check_fpstatus(usr, 0);
209 
210     /*
211      * Execute dfmin/dfmax instructions with both operands SNaN
212      * Check that
213      *     Result is DF_HEX_NaN
214      *     Invalid bit in USR is set
215      */
216     asm (CLEAR_FPSTATUS
217          "%0 = dfmin(%2, %3)\n\t"
218          "%1 = usr\n\t"
219          : "=r"(minmax), "=r"(usr) : "r"(DF_SNaN), "r"(DF_SNaN)
220          : "r2", "usr");
221     check64(minmax, DF_HEX_NaN);
222     check_fpstatus(usr, USR_FPINVF);
223 
224     asm (CLEAR_FPSTATUS
225          "%0 = dfmax(%2, %3)\n\t"
226          "%1 = usr\n\t"
227          : "=r"(minmax), "=r"(usr) : "r"(DF_SNaN), "r"(DF_SNaN)
228          : "r2", "usr");
229     check64(minmax, DF_HEX_NaN);
230     check_fpstatus(usr, USR_FPINVF);
231 
232     /*
233      * Execute dfmin/dfmax instructions with both operands QNaN
234      * Check that
235      *     Result is DF_HEX_NaN
236      *     No bit in USR is set
237      */
238     asm (CLEAR_FPSTATUS
239          "%0 = dfmin(%2, %3)\n\t"
240          "%1 = usr\n\t"
241          : "=r"(minmax), "=r"(usr) : "r"(DF_QNaN), "r"(DF_QNaN)
242          : "r2", "usr");
243     check64(minmax, DF_HEX_NaN);
244     check_fpstatus(usr, 0);
245 
246     asm (CLEAR_FPSTATUS
247          "%0 = dfmax(%2, %3)\n\t"
248          "%1 = usr\n\t"
249          : "=r"(minmax), "=r"(usr) : "r"(DF_QNaN), "r"(DF_QNaN)
250          : "r2", "usr");
251     check64(minmax, DF_HEX_NaN);
252     check_fpstatus(usr, 0);
253 }
254 
255 static void check_sfrecipa(void)
256 {
257     uint32_t result;
258     uint32_t usr;
259     uint32_t pred;
260 
261     /*
262      * Check that sfrecipa doesn't set status bits when
263      * a NaN with bit 22 non-zero is passed
264      */
265     asm (CLEAR_FPSTATUS
266          "%0,p0 = sfrecipa(%2, %3)\n\t"
267          "%1 = usr\n\t"
268          : "=r"(result), "=r"(usr) : "r"(SF_QNaN), "r"(SF_any)
269          : "r2", "p0", "usr");
270     check32(result, SF_HEX_NaN);
271     check_fpstatus(usr, 0);
272 
273     asm (CLEAR_FPSTATUS
274          "%0,p0 = sfrecipa(%2, %3)\n\t"
275          "%1 = usr\n\t"
276          : "=r"(result), "=r"(usr) : "r"(SF_any), "r"(SF_QNaN)
277          : "r2", "p0", "usr");
278     check32(result, SF_HEX_NaN);
279     check_fpstatus(usr, 0);
280 
281     asm (CLEAR_FPSTATUS
282          "%0,p0 = sfrecipa(%2, %2)\n\t"
283          "%1 = usr\n\t"
284          : "=r"(result), "=r"(usr) : "r"(SF_QNaN)
285          : "r2", "p0", "usr");
286     check32(result, SF_HEX_NaN);
287     check_fpstatus(usr, 0);
288 
289     /*
290      * Check that sfrecipa doesn't set status bits when
291      * a NaN with bit 22 zero is passed
292      */
293     asm (CLEAR_FPSTATUS
294          "%0,p0 = sfrecipa(%2, %3)\n\t"
295          "%1 = usr\n\t"
296          : "=r"(result), "=r"(usr) : "r"(SF_QNaN_special), "r"(SF_any)
297          : "r2", "p0", "usr");
298     check32(result, SF_HEX_NaN);
299     check_fpstatus(usr, USR_FPINVF);
300 
301     asm (CLEAR_FPSTATUS
302          "%0,p0 = sfrecipa(%2, %3)\n\t"
303          "%1 = usr\n\t"
304          : "=r"(result), "=r"(usr) : "r"(SF_any), "r"(SF_QNaN_special)
305          : "r2", "p0", "usr");
306     check32(result, SF_HEX_NaN);
307     check_fpstatus(usr, USR_FPINVF);
308 
309     asm (CLEAR_FPSTATUS
310          "%0,p0 = sfrecipa(%2, %2)\n\t"
311          "%1 = usr\n\t"
312          : "=r"(result), "=r"(usr) : "r"(SF_QNaN_special)
313          : "r2", "p0", "usr");
314     check32(result, SF_HEX_NaN);
315     check_fpstatus(usr, USR_FPINVF);
316 
317     /*
318      * Check that sfrecipa properly sets divid-by-zero
319      */
320         asm (CLEAR_FPSTATUS
321          "%0,p0 = sfrecipa(%2, %3)\n\t"
322          "%1 = usr\n\t"
323          : "=r"(result), "=r"(usr) : "r"(0x885dc960), "r"(0x80000000)
324          : "r2", "p0", "usr");
325     check32(result, 0x3f800000);
326     check_fpstatus(usr, USR_FPDBZF);
327 
328     asm (CLEAR_FPSTATUS
329          "%0,p0 = sfrecipa(%2, %3)\n\t"
330          "%1 = usr\n\t"
331          : "=r"(result), "=r"(usr) : "r"(0x7f800000), "r"(SF_zero)
332          : "r2", "p0", "usr");
333     check32(result, 0x3f800000);
334     check_fpstatus(usr, 0);
335 
336     /*
337      * Check that sfrecipa properly handles denorm
338      */
339     asm (CLEAR_FPSTATUS
340          "%0,p0 = sfrecipa(%2, %3)\n\t"
341          "%1 = p0\n\t"
342          : "=r"(result), "=r"(pred) : "r"(SF_denorm), "r"(SF_random)
343          : "p0", "usr");
344     check32(result, 0x6a920001);
345     check32(pred, 0x80);
346 }
347 
348 static void check_canonical_NaN(void)
349 {
350     uint32_t sf_result;
351     uint64_t df_result;
352     uint32_t usr;
353 
354     /* Check that each FP instruction properly returns SF_HEX_NaN/DF_HEX_NaN */
355     asm(CLEAR_FPSTATUS
356         "%0 = sfadd(%2, %3)\n\t"
357         "%1 = usr\n\t"
358         : "=r"(sf_result), "=r"(usr) : "r"(SF_QNaN), "r"(SF_any)
359         : "r2", "usr");
360     check32(sf_result, SF_HEX_NaN);
361     check_fpstatus(usr, 0);
362 
363     asm(CLEAR_FPSTATUS
364         "%0 = sfsub(%2, %3)\n\t"
365         "%1 = usr\n\t"
366         : "=r"(sf_result), "=r"(usr) : "r"(SF_QNaN), "r"(SF_any)
367         : "r2", "usr");
368     check32(sf_result, SF_HEX_NaN);
369     check_fpstatus(usr, 0);
370 
371     asm(CLEAR_FPSTATUS
372         "%0 = sfmpy(%2, %3)\n\t"
373         "%1 = usr\n\t"
374         : "=r"(sf_result), "=r"(usr) : "r"(SF_QNaN), "r"(SF_any)
375         : "r2", "usr");
376     check32(sf_result, SF_HEX_NaN);
377     check_fpstatus(usr, 0);
378 
379     sf_result = SF_zero;
380     asm(CLEAR_FPSTATUS
381         "%0 += sfmpy(%2, %3)\n\t"
382         "%1 = usr\n\t"
383         : "+r"(sf_result), "=r"(usr) : "r"(SF_QNaN), "r"(SF_any)
384         : "r2", "usr");
385     check32(sf_result, SF_HEX_NaN);
386     check_fpstatus(usr, 0);
387 
388     sf_result = SF_zero;
389     asm(CLEAR_FPSTATUS
390         "p0 = !cmp.eq(r0, r0)\n\t"
391         "%0 += sfmpy(%2, %3, p0):scale\n\t"
392         "%1 = usr\n\t"
393         : "+r"(sf_result), "=r"(usr) : "r"(SF_QNaN), "r"(SF_any)
394         : "r2", "usr", "p0");
395     check32(sf_result, SF_HEX_NaN);
396     check_fpstatus(usr, 0);
397 
398     sf_result = SF_zero;
399     asm(CLEAR_FPSTATUS
400         "%0 -= sfmpy(%2, %3)\n\t"
401         "%1 = usr\n\t"
402         : "+r"(sf_result), "=r"(usr) : "r"(SF_QNaN), "r"(SF_any)
403         : "r2", "usr");
404     check32(sf_result, SF_HEX_NaN);
405     check_fpstatus(usr, 0);
406 
407     sf_result = SF_zero;
408     asm(CLEAR_FPSTATUS
409         "%0 += sfmpy(%2, %3):lib\n\t"
410         "%1 = usr\n\t"
411         : "+r"(sf_result), "=r"(usr) : "r"(SF_QNaN), "r"(SF_any)
412         : "r2", "usr");
413     check32(sf_result, SF_HEX_NaN);
414     check_fpstatus(usr, 0);
415 
416     sf_result = SF_zero;
417     asm(CLEAR_FPSTATUS
418         "%0 -= sfmpy(%2, %3):lib\n\t"
419         "%1 = usr\n\t"
420         : "+r"(sf_result), "=r"(usr) : "r"(SF_QNaN), "r"(SF_any)
421         : "r2", "usr");
422     check32(sf_result, SF_HEX_NaN);
423     check_fpstatus(usr, 0);
424 
425     asm(CLEAR_FPSTATUS
426         "%0 = convert_df2sf(%2)\n\t"
427         "%1 = usr\n\t"
428         : "=r"(sf_result), "=r"(usr) : "r"(DF_QNaN)
429         : "r2", "usr");
430     check32(sf_result, SF_HEX_NaN);
431     check_fpstatus(usr, 0);
432 
433     asm(CLEAR_FPSTATUS
434         "%0 = dfadd(%2, %3)\n\t"
435         "%1 = usr\n\t"
436         : "=r"(df_result), "=r"(usr) : "r"(DF_QNaN), "r"(DF_any)
437         : "r2", "usr");
438     check64(df_result, DF_HEX_NaN);
439     check_fpstatus(usr, 0);
440 
441     asm(CLEAR_FPSTATUS
442         "%0 = dfsub(%2, %3)\n\t"
443         "%1 = usr\n\t"
444         : "=r"(df_result), "=r"(usr) : "r"(DF_QNaN), "r"(DF_any)
445         : "r2", "usr");
446     check64(df_result, DF_HEX_NaN);
447     check_fpstatus(usr, 0);
448 
449     asm(CLEAR_FPSTATUS
450         "%0 = convert_sf2df(%2)\n\t"
451         "%1 = usr\n\t"
452         : "=r"(df_result), "=r"(usr) : "r"(SF_QNaN)
453         : "r2", "usr");
454     check64(df_result, DF_HEX_NaN);
455     check_fpstatus(usr, 0);
456 }
457 
458 static void check_invsqrta(void)
459 {
460     uint32_t result;
461     uint32_t predval;
462 
463     asm volatile("%0,p0 = sfinvsqrta(%2)\n\t"
464                  "%1 = p0\n\t"
465                  : "+r"(result), "=r"(predval)
466                  : "r"(0x7f800000)
467                  : "p0");
468     check32(result, 0xff800000);
469     check32(predval, 0x0);
470 }
471 
472 static void check_sffixupn(void)
473 {
474     uint32_t result;
475 
476     /* Check that sffixupn properly deals with denorm */
477     asm volatile("%0 = sffixupn(%1, %2)\n\t"
478                  : "=r"(result)
479                  : "r"(SF_random), "r"(SF_denorm));
480     check32(result, 0x246001d6);
481 }
482 
483 static void check_sffixupd(void)
484 {
485     uint32_t result;
486 
487     /* Check that sffixupd properly deals with denorm */
488     asm volatile("%0 = sffixupd(%1, %2)\n\t"
489                  : "=r"(result)
490                  : "r"(SF_denorm), "r"(SF_random));
491     check32(result, 0x146001d6);
492 }
493 
494 static void check_sffms(void)
495 {
496     uint32_t result;
497 
498     /* Check that sffms properly deals with -0 */
499     result = SF_zero_neg;
500     asm ("%0 -= sfmpy(%1 , %2)\n\t"
501         : "+r"(result)
502         : "r"(SF_zero), "r"(SF_zero)
503         : "r12", "r8");
504     check32(result, SF_zero_neg);
505 
506     result = SF_zero;
507     asm ("%0 -= sfmpy(%1 , %2)\n\t"
508         : "+r"(result)
509         : "r"(SF_zero_neg), "r"(SF_zero)
510         : "r12", "r8");
511     check32(result, SF_zero);
512 
513     result = SF_zero;
514     asm ("%0 -= sfmpy(%1 , %2)\n\t"
515         : "+r"(result)
516         : "r"(SF_zero), "r"(SF_zero_neg)
517         : "r12", "r8");
518     check32(result, SF_zero);
519 }
520 
521 static void check_float2int_convs()
522 {
523     uint32_t res32;
524     uint64_t res64;
525     uint32_t usr;
526 
527     /*
528      * Check that the various forms of float-to-unsigned
529      *  check sign before rounding
530      */
531         asm(CLEAR_FPSTATUS
532         "%0 = convert_sf2uw(%2)\n\t"
533         "%1 = usr\n\t"
534         : "=r"(res32), "=r"(usr) : "r"(SF_small_neg)
535         : "r2", "usr");
536     check32(res32, 0);
537     check_fpstatus(usr, USR_FPINVF);
538 
539     asm(CLEAR_FPSTATUS
540         "%0 = convert_sf2uw(%2):chop\n\t"
541         "%1 = usr\n\t"
542         : "=r"(res32), "=r"(usr) : "r"(SF_small_neg)
543         : "r2", "usr");
544     check32(res32, 0);
545     check_fpstatus(usr, USR_FPINVF);
546 
547     asm(CLEAR_FPSTATUS
548         "%0 = convert_sf2ud(%2)\n\t"
549         "%1 = usr\n\t"
550         : "=r"(res64), "=r"(usr) : "r"(SF_small_neg)
551         : "r2", "usr");
552     check64(res64, 0);
553     check_fpstatus(usr, USR_FPINVF);
554 
555     asm(CLEAR_FPSTATUS
556         "%0 = convert_sf2ud(%2):chop\n\t"
557         "%1 = usr\n\t"
558         : "=r"(res64), "=r"(usr) : "r"(SF_small_neg)
559         : "r2", "usr");
560     check64(res64, 0);
561     check_fpstatus(usr, USR_FPINVF);
562 
563     asm(CLEAR_FPSTATUS
564         "%0 = convert_df2uw(%2)\n\t"
565         "%1 = usr\n\t"
566         : "=r"(res32), "=r"(usr) : "r"(DF_small_neg)
567         : "r2", "usr");
568     check32(res32, 0);
569     check_fpstatus(usr, USR_FPINVF);
570 
571     asm(CLEAR_FPSTATUS
572         "%0 = convert_df2uw(%2):chop\n\t"
573         "%1 = usr\n\t"
574         : "=r"(res32), "=r"(usr) : "r"(DF_small_neg)
575         : "r2", "usr");
576     check32(res32, 0);
577     check_fpstatus(usr, USR_FPINVF);
578 
579     asm(CLEAR_FPSTATUS
580         "%0 = convert_df2ud(%2)\n\t"
581         "%1 = usr\n\t"
582         : "=r"(res64), "=r"(usr) : "r"(DF_small_neg)
583         : "r2", "usr");
584     check64(res64, 0);
585     check_fpstatus(usr, USR_FPINVF);
586 
587     asm(CLEAR_FPSTATUS
588         "%0 = convert_df2ud(%2):chop\n\t"
589         "%1 = usr\n\t"
590         : "=r"(res64), "=r"(usr) : "r"(DF_small_neg)
591         : "r2", "usr");
592     check64(res64, 0);
593     check_fpstatus(usr, USR_FPINVF);
594 
595     /*
596      * Check that the various forms of float-to-signed return -1 for NaN
597      */
598     asm(CLEAR_FPSTATUS
599         "%0 = convert_sf2w(%2)\n\t"
600         "%1 = usr\n\t"
601         : "=r"(res32), "=r"(usr) : "r"(SF_QNaN)
602         : "r2", "usr");
603     check32(res32, -1);
604     check_fpstatus(usr, USR_FPINVF);
605 
606     asm(CLEAR_FPSTATUS
607         "%0 = convert_sf2w(%2):chop\n\t"
608         "%1 = usr\n\t"
609         : "=r"(res32), "=r"(usr) : "r"(SF_QNaN)
610         : "r2", "usr");
611     check32(res32, -1);
612     check_fpstatus(usr, USR_FPINVF);
613 
614     asm(CLEAR_FPSTATUS
615         "%0 = convert_sf2d(%2)\n\t"
616         "%1 = usr\n\t"
617         : "=r"(res64), "=r"(usr) : "r"(SF_QNaN)
618         : "r2", "usr");
619     check64(res64, -1);
620     check_fpstatus(usr, USR_FPINVF);
621 
622     asm(CLEAR_FPSTATUS
623         "%0 = convert_sf2d(%2):chop\n\t"
624         "%1 = usr\n\t"
625         : "=r"(res64), "=r"(usr) : "r"(SF_QNaN)
626         : "r2", "usr");
627     check64(res64, -1);
628     check_fpstatus(usr, USR_FPINVF);
629 
630     asm(CLEAR_FPSTATUS
631         "%0 = convert_df2w(%2)\n\t"
632         "%1 = usr\n\t"
633         : "=r"(res32), "=r"(usr) : "r"(DF_QNaN)
634         : "r2", "usr");
635     check32(res32, -1);
636     check_fpstatus(usr, USR_FPINVF);
637 
638     asm(CLEAR_FPSTATUS
639         "%0 = convert_df2w(%2):chop\n\t"
640         "%1 = usr\n\t"
641         : "=r"(res32), "=r"(usr) : "r"(DF_QNaN)
642         : "r2", "usr");
643     check32(res32, -1);
644     check_fpstatus(usr, USR_FPINVF);
645 
646     asm(CLEAR_FPSTATUS
647         "%0 = convert_df2d(%2)\n\t"
648         "%1 = usr\n\t"
649         : "=r"(res64), "=r"(usr) : "r"(DF_QNaN)
650         : "r2", "usr");
651     check64(res64, -1);
652     check_fpstatus(usr, USR_FPINVF);
653 
654     asm(CLEAR_FPSTATUS
655         "%0 = convert_df2d(%2):chop\n\t"
656         "%1 = usr\n\t"
657         : "=r"(res64), "=r"(usr) : "r"(DF_QNaN)
658         : "r2", "usr");
659     check64(res64, -1);
660     check_fpstatus(usr, USR_FPINVF);
661 }
662 
663 static void check_float_consts(void)
664 {
665     uint32_t res32;
666     uint64_t res64;
667 
668     asm("%0 = sfmake(#%1):neg\n\t" : "=r"(res32) : "i"(0xf));
669     check32(res32, 0xbc9e0000);
670 
671     asm("%0 = sfmake(#%1):pos\n\t" : "=r"(res32) : "i"(0xf));
672     check32(res32, 0x3c9e0000);
673 
674     asm("%0 = dfmake(#%1):neg\n\t" : "=r"(res64) : "i"(0xf));
675     check64(res64, 0xbf93c00000000000ULL);
676 
677     asm("%0 = dfmake(#%1):pos\n\t" : "=r"(res64) : "i"(0xf));
678     check64(res64, 0x3f93c00000000000ULL);
679 }
680 
681 static inline uint64_t dfmpyll(double x, double y)
682 {
683     uint64_t res64;
684     asm("%0 = dfmpyll(%1, %2)" : "=r"(res64) : "r"(x), "r"(y));
685     return res64;
686 }
687 
688 static inline uint64_t dfmpylh(double acc, double x, double y)
689 {
690     uint64_t res64 = *(uint64_t *)&acc;
691     asm("%0 += dfmpylh(%1, %2)" : "+r"(res64) : "r"(x), "r"(y));
692     return res64;
693 }
694 
695 static void check_dfmpyxx(void)
696 {
697     uint64_t res64;
698 
699     res64 = dfmpyll(DBL_MIN, DBL_MIN);
700     check64(res64, 0ULL);
701     res64 = dfmpyll(-1.0, DBL_MIN);
702     check64(res64, 0ULL);
703     res64 = dfmpyll(DBL_MAX, DBL_MAX);
704     check64(res64, 0x1fffffffdULL);
705 
706     res64 = dfmpylh(DBL_MIN, DBL_MIN, DBL_MIN);
707     check64(res64, 0x10000000000000ULL);
708     res64 = dfmpylh(-1.0, DBL_MAX, DBL_MIN);
709     check64(res64, 0xc00fffffffe00000ULL);
710     res64 = dfmpylh(DBL_MAX, 0.0, -1.0);
711     check64(res64, 0x7fefffffffffffffULL);
712 }
713 
714 int main()
715 {
716     check_compare_exception();
717     check_sfminmax();
718     check_dfminmax();
719     check_sfrecipa();
720     check_canonical_NaN();
721     check_invsqrta();
722     check_sffixupn();
723     check_sffixupd();
724     check_sffms();
725     check_float2int_convs();
726     check_float_consts();
727     check_dfmpyxx();
728 
729     puts(err ? "FAIL" : "PASS");
730     return err ? 1 : 0;
731 }
732