2 * Copyright(c) 2020-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
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.
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.
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/>.
19 * This test checks various FP operations performed on Hexagon
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
;
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;
42 const long long DF_NaN
= 0x7ff8000000000000ULL
;
43 const long long DF_ANY
= 0x3f80000000000000ULL
;
44 const long long DF_HEX_NAN
= 0xffffffffffffffffULL
;
45 const long long DF_small_neg
= 0xbd731f7500000000ULL
;
49 #define CLEAR_FPSTATUS \
51 "r2 = clrbit(r2, #1)\n\t" \
52 "r2 = clrbit(r2, #2)\n\t" \
53 "r2 = clrbit(r2, #3)\n\t" \
54 "r2 = clrbit(r2, #4)\n\t" \
55 "r2 = clrbit(r2, #5)\n\t" \
58 static void check_fpstatus_bit(int usr
, int expect
, int flag
, const char *n
)
61 if ((usr
& bit
) != (expect
& bit
)) {
62 printf("ERROR %s: usr = %d, expect = %d\n", n
,
63 (usr
>> flag
) & 1, (expect
>> flag
) & 1);
68 static void check_fpstatus(int usr
, int expect
)
70 check_fpstatus_bit(usr
, expect
, FPINVF_BIT
, "Invalid");
71 check_fpstatus_bit(usr
, expect
, FPDBZF_BIT
, "Div by zero");
72 check_fpstatus_bit(usr
, expect
, FPOVFF_BIT
, "Overflow");
73 check_fpstatus_bit(usr
, expect
, FPUNFF_BIT
, "Underflow");
74 check_fpstatus_bit(usr
, expect
, FPINPF_BIT
, "Inexact");
77 static void check32(int val
, int expect
)
80 printf("ERROR: 0x%x != 0x%x\n", val
, expect
);
84 static void check64(unsigned long long val
, unsigned long long expect
)
87 printf("ERROR: 0x%llx != 0x%llx\n", val
, expect
);
92 static void check_compare_exception(void)
97 /* Check that FP compares are quiet (don't raise any execptions) */
99 "p0 = sfcmp.eq(%2, %3)\n\t"
102 : "=r"(cmp
), "=r"(usr
) : "r"(SF_NaN
), "r"(SF_ANY
)
103 : "r2", "p0", "usr");
105 check_fpstatus(usr
, 0);
108 "p0 = sfcmp.gt(%2, %3)\n\t"
111 : "=r"(cmp
), "=r"(usr
) : "r"(SF_NaN
), "r"(SF_ANY
)
112 : "r2", "p0", "usr");
114 check_fpstatus(usr
, 0);
117 "p0 = sfcmp.ge(%2, %3)\n\t"
120 : "=r"(cmp
), "=r"(usr
) : "r"(SF_NaN
), "r"(SF_ANY
)
121 : "r2", "p0", "usr");
123 check_fpstatus(usr
, 0);
126 "p0 = dfcmp.eq(%2, %3)\n\t"
129 : "=r"(cmp
), "=r"(usr
) : "r"(DF_NaN
), "r"(DF_ANY
)
130 : "r2", "p0", "usr");
132 check_fpstatus(usr
, 0);
135 "p0 = dfcmp.gt(%2, %3)\n\t"
138 : "=r"(cmp
), "=r"(usr
) : "r"(DF_NaN
), "r"(DF_ANY
)
139 : "r2", "p0", "usr");
141 check_fpstatus(usr
, 0);
144 "p0 = dfcmp.ge(%2, %3)\n\t"
147 : "=r"(cmp
), "=r"(usr
) : "r"(DF_NaN
), "r"(DF_ANY
)
148 : "r2", "p0", "usr");
150 check_fpstatus(usr
, 0);
153 static void check_sfminmax(void)
159 * Execute sfmin/sfmax instructions with one operand as NaN
161 * Result is the other operand
162 * Invalid bit in USR is not set
165 "%0 = sfmin(%2, %3)\n\t"
167 : "=r"(minmax
), "=r"(usr
) : "r"(SF_NaN
), "r"(SF_ANY
)
169 check64(minmax
, SF_ANY
);
170 check_fpstatus(usr
, 0);
173 "%0 = sfmax(%2, %3)\n\t"
175 : "=r"(minmax
), "=r"(usr
) : "r"(SF_NaN
), "r"(SF_ANY
)
177 check64(minmax
, SF_ANY
);
178 check_fpstatus(usr
, 0);
181 * Execute sfmin/sfmax instructions with both operands NaN
183 * Result is SF_HEX_NAN
184 * Invalid bit in USR is set
187 "%0 = sfmin(%2, %3)\n\t"
189 : "=r"(minmax
), "=r"(usr
) : "r"(SF_NaN
), "r"(SF_NaN
)
191 check64(minmax
, SF_HEX_NAN
);
192 check_fpstatus(usr
, 0);
195 "%0 = sfmax(%2, %3)\n\t"
197 : "=r"(minmax
), "=r"(usr
) : "r"(SF_NaN
), "r"(SF_NaN
)
199 check64(minmax
, SF_HEX_NAN
);
200 check_fpstatus(usr
, 0);
203 static void check_dfminmax(void)
205 unsigned long long minmax
;
209 * Execute dfmin/dfmax instructions with one operand as NaN
211 * Result is the other operand
212 * Invalid bit in USR is set
215 "%0 = dfmin(%2, %3)\n\t"
217 : "=r"(minmax
), "=r"(usr
) : "r"(DF_NaN
), "r"(DF_ANY
)
219 check64(minmax
, DF_ANY
);
220 check_fpstatus(usr
, FPINVF
);
223 "%0 = dfmax(%2, %3)\n\t"
225 : "=r"(minmax
), "=r"(usr
) : "r"(DF_NaN
), "r"(DF_ANY
)
227 check64(minmax
, DF_ANY
);
228 check_fpstatus(usr
, FPINVF
);
231 * Execute dfmin/dfmax instructions with both operands NaN
233 * Result is DF_HEX_NAN
234 * Invalid bit in USR is set
237 "%0 = dfmin(%2, %3)\n\t"
239 : "=r"(minmax
), "=r"(usr
) : "r"(DF_NaN
), "r"(DF_NaN
)
241 check64(minmax
, DF_HEX_NAN
);
242 check_fpstatus(usr
, FPINVF
);
245 "%0 = dfmax(%2, %3)\n\t"
247 : "=r"(minmax
), "=r"(usr
) : "r"(DF_NaN
), "r"(DF_NaN
)
249 check64(minmax
, DF_HEX_NAN
);
250 check_fpstatus(usr
, FPINVF
);
253 static void check_recip_exception(void)
259 * Check that sfrecipa doesn't set status bits when
260 * a NaN with bit 22 non-zero is passed
263 "%0,p0 = sfrecipa(%2, %3)\n\t"
265 : "=r"(result
), "=r"(usr
) : "r"(SF_NaN
), "r"(SF_ANY
)
266 : "r2", "p0", "usr");
267 check32(result
, SF_HEX_NAN
);
268 check_fpstatus(usr
, 0);
271 "%0,p0 = sfrecipa(%2, %3)\n\t"
273 : "=r"(result
), "=r"(usr
) : "r"(SF_ANY
), "r"(SF_NaN
)
274 : "r2", "p0", "usr");
275 check32(result
, SF_HEX_NAN
);
276 check_fpstatus(usr
, 0);
279 "%0,p0 = sfrecipa(%2, %2)\n\t"
281 : "=r"(result
), "=r"(usr
) : "r"(SF_NaN
)
282 : "r2", "p0", "usr");
283 check32(result
, SF_HEX_NAN
);
284 check_fpstatus(usr
, 0);
287 * Check that sfrecipa doesn't set status bits when
288 * a NaN with bit 22 zero is passed
291 "%0,p0 = sfrecipa(%2, %3)\n\t"
293 : "=r"(result
), "=r"(usr
) : "r"(SF_NaN_special
), "r"(SF_ANY
)
294 : "r2", "p0", "usr");
295 check32(result
, SF_HEX_NAN
);
296 check_fpstatus(usr
, FPINVF
);
299 "%0,p0 = sfrecipa(%2, %3)\n\t"
301 : "=r"(result
), "=r"(usr
) : "r"(SF_ANY
), "r"(SF_NaN_special
)
302 : "r2", "p0", "usr");
303 check32(result
, SF_HEX_NAN
);
304 check_fpstatus(usr
, FPINVF
);
307 "%0,p0 = sfrecipa(%2, %2)\n\t"
309 : "=r"(result
), "=r"(usr
) : "r"(SF_NaN_special
)
310 : "r2", "p0", "usr");
311 check32(result
, SF_HEX_NAN
);
312 check_fpstatus(usr
, FPINVF
);
315 * Check that sfrecipa properly sets divid-by-zero
318 "%0,p0 = sfrecipa(%2, %3)\n\t"
320 : "=r"(result
), "=r"(usr
) : "r"(0x885dc960), "r"(0x80000000)
321 : "r2", "p0", "usr");
322 check32(result
, 0x3f800000);
323 check_fpstatus(usr
, FPDBZF
);
326 "%0,p0 = sfrecipa(%2, %3)\n\t"
328 : "=r"(result
), "=r"(usr
) : "r"(0x7f800000), "r"(SF_ZERO
)
329 : "r2", "p0", "usr");
330 check32(result
, 0x3f800000);
331 check_fpstatus(usr
, 0);
334 static void check_canonical_NaN(void)
337 unsigned long long df_result
;
340 /* Check that each FP instruction properly returns SF_HEX_NAN/DF_HEX_NAN */
342 "%0 = sfadd(%2, %3)\n\t"
344 : "=r"(sf_result
), "=r"(usr
) : "r"(SF_NaN
), "r"(SF_ANY
)
346 check32(sf_result
, SF_HEX_NAN
);
347 check_fpstatus(usr
, 0);
350 "%0 = sfsub(%2, %3)\n\t"
352 : "=r"(sf_result
), "=r"(usr
) : "r"(SF_NaN
), "r"(SF_ANY
)
354 check32(sf_result
, SF_HEX_NAN
);
355 check_fpstatus(usr
, 0);
358 "%0 = sfmpy(%2, %3)\n\t"
360 : "=r"(sf_result
), "=r"(usr
) : "r"(SF_NaN
), "r"(SF_ANY
)
362 check32(sf_result
, SF_HEX_NAN
);
363 check_fpstatus(usr
, 0);
367 "%0 += sfmpy(%2, %3)\n\t"
369 : "+r"(sf_result
), "=r"(usr
) : "r"(SF_NaN
), "r"(SF_ANY
)
371 check32(sf_result
, SF_HEX_NAN
);
372 check_fpstatus(usr
, 0);
376 "p0 = !cmp.eq(r0, r0)\n\t"
377 "%0 += sfmpy(%2, %3, p0):scale\n\t"
379 : "+r"(sf_result
), "=r"(usr
) : "r"(SF_NaN
), "r"(SF_ANY
)
380 : "r2", "usr", "p0");
381 check32(sf_result
, SF_HEX_NAN
);
382 check_fpstatus(usr
, 0);
386 "%0 -= sfmpy(%2, %3)\n\t"
388 : "+r"(sf_result
), "=r"(usr
) : "r"(SF_NaN
), "r"(SF_ANY
)
390 check32(sf_result
, SF_HEX_NAN
);
391 check_fpstatus(usr
, 0);
395 "%0 += sfmpy(%2, %3):lib\n\t"
397 : "+r"(sf_result
), "=r"(usr
) : "r"(SF_NaN
), "r"(SF_ANY
)
399 check32(sf_result
, SF_HEX_NAN
);
400 check_fpstatus(usr
, 0);
404 "%0 -= sfmpy(%2, %3):lib\n\t"
406 : "+r"(sf_result
), "=r"(usr
) : "r"(SF_NaN
), "r"(SF_ANY
)
408 check32(sf_result
, SF_HEX_NAN
);
409 check_fpstatus(usr
, 0);
412 "%0 = convert_df2sf(%2)\n\t"
414 : "=r"(sf_result
), "=r"(usr
) : "r"(DF_NaN
)
416 check32(sf_result
, SF_HEX_NAN
);
417 check_fpstatus(usr
, 0);
420 "%0 = dfadd(%2, %3)\n\t"
422 : "=r"(df_result
), "=r"(usr
) : "r"(DF_NaN
), "r"(DF_ANY
)
424 check64(df_result
, DF_HEX_NAN
);
425 check_fpstatus(usr
, 0);
428 "%0 = dfsub(%2, %3)\n\t"
430 : "=r"(df_result
), "=r"(usr
) : "r"(DF_NaN
), "r"(DF_ANY
)
432 check64(df_result
, DF_HEX_NAN
);
433 check_fpstatus(usr
, 0);
436 "%0 = convert_sf2df(%2)\n\t"
438 : "=r"(df_result
), "=r"(usr
) : "r"(SF_NaN
)
440 check64(df_result
, DF_HEX_NAN
);
441 check_fpstatus(usr
, 0);
444 static void check_invsqrta(void)
449 asm volatile("%0,p0 = sfinvsqrta(%2)\n\t"
451 : "+r"(result
), "=r"(predval
)
454 check32(result
, 0xff800000);
455 check32(predval
, 0x0);
458 static void check_float2int_convs()
465 * Check that the various forms of float-to-unsigned
466 * check sign before rounding
469 "%0 = convert_sf2uw(%2)\n\t"
471 : "=r"(res32
), "=r"(usr
) : "r"(SF_small_neg
)
474 check_fpstatus(usr
, FPINVF
);
477 "%0 = convert_sf2uw(%2):chop\n\t"
479 : "=r"(res32
), "=r"(usr
) : "r"(SF_small_neg
)
482 check_fpstatus(usr
, FPINVF
);
485 "%0 = convert_sf2ud(%2)\n\t"
487 : "=r"(res64
), "=r"(usr
) : "r"(SF_small_neg
)
490 check_fpstatus(usr
, FPINVF
);
493 "%0 = convert_sf2ud(%2):chop\n\t"
495 : "=r"(res64
), "=r"(usr
) : "r"(SF_small_neg
)
498 check_fpstatus(usr
, FPINVF
);
501 "%0 = convert_df2uw(%2)\n\t"
503 : "=r"(res32
), "=r"(usr
) : "r"(DF_small_neg
)
506 check_fpstatus(usr
, FPINVF
);
509 "%0 = convert_df2uw(%2):chop\n\t"
511 : "=r"(res32
), "=r"(usr
) : "r"(DF_small_neg
)
514 check_fpstatus(usr
, FPINVF
);
517 "%0 = convert_df2ud(%2)\n\t"
519 : "=r"(res64
), "=r"(usr
) : "r"(DF_small_neg
)
522 check_fpstatus(usr
, FPINVF
);
525 "%0 = convert_df2ud(%2):chop\n\t"
527 : "=r"(res64
), "=r"(usr
) : "r"(DF_small_neg
)
530 check_fpstatus(usr
, FPINVF
);
533 * Check that the various forms of float-to-signed return -1 for NaN
536 "%0 = convert_sf2w(%2)\n\t"
538 : "=r"(res32
), "=r"(usr
) : "r"(SF_NaN
)
541 check_fpstatus(usr
, FPINVF
);
544 "%0 = convert_sf2w(%2):chop\n\t"
546 : "=r"(res32
), "=r"(usr
) : "r"(SF_NaN
)
549 check_fpstatus(usr
, FPINVF
);
552 "%0 = convert_sf2d(%2)\n\t"
554 : "=r"(res64
), "=r"(usr
) : "r"(SF_NaN
)
557 check_fpstatus(usr
, FPINVF
);
560 "%0 = convert_sf2d(%2):chop\n\t"
562 : "=r"(res64
), "=r"(usr
) : "r"(SF_NaN
)
565 check_fpstatus(usr
, FPINVF
);
568 "%0 = convert_df2w(%2)\n\t"
570 : "=r"(res32
), "=r"(usr
) : "r"(DF_NaN
)
573 check_fpstatus(usr
, FPINVF
);
576 "%0 = convert_df2w(%2):chop\n\t"
578 : "=r"(res32
), "=r"(usr
) : "r"(DF_NaN
)
581 check_fpstatus(usr
, FPINVF
);
584 "%0 = convert_df2d(%2)\n\t"
586 : "=r"(res64
), "=r"(usr
) : "r"(DF_NaN
)
589 check_fpstatus(usr
, FPINVF
);
592 "%0 = convert_df2d(%2):chop\n\t"
594 : "=r"(res64
), "=r"(usr
) : "r"(DF_NaN
)
597 check_fpstatus(usr
, FPINVF
);
602 check_compare_exception();
605 check_recip_exception();
606 check_canonical_NaN();
608 check_float2int_convs();
610 puts(err
? "FAIL" : "PASS");