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