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