xref: /openbmc/qemu/tests/tcg/hexagon/fpstuff.c (revision 6f03770d)
1 /*
2  *  Copyright(c) 2020-2021 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 
41 const long long DF_NaN =                  0x7ff8000000000000ULL;
42 const long long DF_ANY =                  0x3f80000000000000ULL;
43 const long long DF_HEX_NAN =              0xffffffffffffffffULL;
44 
45 int err;
46 
47 #define CLEAR_FPSTATUS \
48     "r2 = usr\n\t" \
49     "r2 = clrbit(r2, #1)\n\t" \
50     "r2 = clrbit(r2, #2)\n\t" \
51     "r2 = clrbit(r2, #3)\n\t" \
52     "r2 = clrbit(r2, #4)\n\t" \
53     "r2 = clrbit(r2, #5)\n\t" \
54     "usr = r2\n\t"
55 
56 static void check_fpstatus_bit(int usr, int expect, int flag, const char *n)
57 {
58     int bit = 1 << flag;
59     if ((usr & bit) != (expect & bit)) {
60         printf("ERROR %s: usr = %d, expect = %d\n", n,
61                (usr >> flag) & 1, (expect >> flag) & 1);
62         err++;
63     }
64 }
65 
66 static void check_fpstatus(int usr, int expect)
67 {
68     check_fpstatus_bit(usr, expect, FPINVF_BIT, "Invalid");
69     check_fpstatus_bit(usr, expect, FPDBZF_BIT, "Div by zero");
70     check_fpstatus_bit(usr, expect, FPOVFF_BIT, "Overflow");
71     check_fpstatus_bit(usr, expect, FPUNFF_BIT, "Underflow");
72     check_fpstatus_bit(usr, expect, FPINPF_BIT, "Inexact");
73 }
74 
75 static void check32(int val, int expect)
76 {
77     if (val != expect) {
78         printf("ERROR: 0x%x != 0x%x\n", val, expect);
79         err++;
80     }
81 }
82 static void check64(unsigned long long val, unsigned long long expect)
83 {
84     if (val != expect) {
85         printf("ERROR: 0x%llx != 0x%llx\n", val, expect);
86         err++;
87     }
88 }
89 
90 static void check_compare_exception(void)
91 {
92     int cmp;
93     int usr;
94 
95     /* Check that FP compares are quiet (don't raise any execptions) */
96     asm (CLEAR_FPSTATUS
97          "p0 = sfcmp.eq(%2, %3)\n\t"
98          "%0 = p0\n\t"
99          "%1 = usr\n\t"
100          : "=r"(cmp), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY)
101          : "r2", "p0", "usr");
102     check32(cmp, 0);
103     check_fpstatus(usr, 0);
104 
105     asm (CLEAR_FPSTATUS
106          "p0 = sfcmp.gt(%2, %3)\n\t"
107          "%0 = p0\n\t"
108          "%1 = usr\n\t"
109          : "=r"(cmp), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY)
110          : "r2", "p0", "usr");
111     check32(cmp, 0);
112     check_fpstatus(usr, 0);
113 
114     asm (CLEAR_FPSTATUS
115          "p0 = sfcmp.ge(%2, %3)\n\t"
116          "%0 = p0\n\t"
117          "%1 = usr\n\t"
118          : "=r"(cmp), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY)
119          : "r2", "p0", "usr");
120     check32(cmp, 0);
121     check_fpstatus(usr, 0);
122 
123     asm (CLEAR_FPSTATUS
124          "p0 = dfcmp.eq(%2, %3)\n\t"
125          "%0 = p0\n\t"
126          "%1 = usr\n\t"
127          : "=r"(cmp), "=r"(usr) : "r"(DF_NaN), "r"(DF_ANY)
128          : "r2", "p0", "usr");
129     check32(cmp, 0);
130     check_fpstatus(usr, 0);
131 
132     asm (CLEAR_FPSTATUS
133          "p0 = dfcmp.gt(%2, %3)\n\t"
134          "%0 = p0\n\t"
135          "%1 = usr\n\t"
136          : "=r"(cmp), "=r"(usr) : "r"(DF_NaN), "r"(DF_ANY)
137          : "r2", "p0", "usr");
138     check32(cmp, 0);
139     check_fpstatus(usr, 0);
140 
141     asm (CLEAR_FPSTATUS
142          "p0 = dfcmp.ge(%2, %3)\n\t"
143          "%0 = p0\n\t"
144          "%1 = usr\n\t"
145          : "=r"(cmp), "=r"(usr) : "r"(DF_NaN), "r"(DF_ANY)
146          : "r2", "p0", "usr");
147     check32(cmp, 0);
148     check_fpstatus(usr, 0);
149 }
150 
151 static void check_sfminmax(void)
152 {
153     int minmax;
154     int usr;
155 
156     /*
157      * Execute sfmin/sfmax instructions with one operand as NaN
158      * Check that
159      *     Result is the other operand
160      *     Invalid bit in USR is not set
161      */
162      asm (CLEAR_FPSTATUS
163          "%0 = sfmin(%2, %3)\n\t"
164          "%1 = usr\n\t"
165          : "=r"(minmax), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY)
166          : "r2", "usr");
167     check64(minmax, SF_ANY);
168     check_fpstatus(usr, 0);
169 
170     asm (CLEAR_FPSTATUS
171          "%0 = sfmax(%2, %3)\n\t"
172          "%1 = usr\n\t"
173          : "=r"(minmax), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY)
174          : "r2", "usr");
175     check64(minmax, SF_ANY);
176     check_fpstatus(usr, 0);
177 
178     /*
179      * Execute sfmin/sfmax instructions with both operands NaN
180      * Check that
181      *     Result is SF_HEX_NAN
182      *     Invalid bit in USR is set
183      */
184     asm (CLEAR_FPSTATUS
185          "%0 = sfmin(%2, %3)\n\t"
186          "%1 = usr\n\t"
187          : "=r"(minmax), "=r"(usr) : "r"(SF_NaN), "r"(SF_NaN)
188          : "r2", "usr");
189     check64(minmax, SF_HEX_NAN);
190     check_fpstatus(usr, 0);
191 
192     asm (CLEAR_FPSTATUS
193          "%0 = sfmax(%2, %3)\n\t"
194          "%1 = usr\n\t"
195          : "=r"(minmax), "=r"(usr) : "r"(SF_NaN), "r"(SF_NaN)
196          : "r2", "usr");
197     check64(minmax, SF_HEX_NAN);
198     check_fpstatus(usr, 0);
199 }
200 
201 static void check_dfminmax(void)
202 {
203     unsigned long long minmax;
204     int usr;
205 
206     /*
207      * Execute dfmin/dfmax instructions with one operand as NaN
208      * Check that
209      *     Result is the other operand
210      *     Invalid bit in USR is set
211      */
212      asm (CLEAR_FPSTATUS
213          "%0 = dfmin(%2, %3)\n\t"
214          "%1 = usr\n\t"
215          : "=r"(minmax), "=r"(usr) : "r"(DF_NaN), "r"(DF_ANY)
216          : "r2", "usr");
217     check64(minmax, DF_ANY);
218     check_fpstatus(usr, FPINVF);
219 
220     asm (CLEAR_FPSTATUS
221          "%0 = dfmax(%2, %3)\n\t"
222          "%1 = usr\n\t"
223          : "=r"(minmax), "=r"(usr) : "r"(DF_NaN), "r"(DF_ANY)
224          : "r2", "usr");
225     check64(minmax, DF_ANY);
226     check_fpstatus(usr, FPINVF);
227 
228     /*
229      * Execute dfmin/dfmax instructions with both operands NaN
230      * Check that
231      *     Result is DF_HEX_NAN
232      *     Invalid bit in USR is set
233      */
234     asm (CLEAR_FPSTATUS
235          "%0 = dfmin(%2, %3)\n\t"
236          "%1 = usr\n\t"
237          : "=r"(minmax), "=r"(usr) : "r"(DF_NaN), "r"(DF_NaN)
238          : "r2", "usr");
239     check64(minmax, DF_HEX_NAN);
240     check_fpstatus(usr, FPINVF);
241 
242     asm (CLEAR_FPSTATUS
243          "%0 = dfmax(%2, %3)\n\t"
244          "%1 = usr\n\t"
245          : "=r"(minmax), "=r"(usr) : "r"(DF_NaN), "r"(DF_NaN)
246          : "r2", "usr");
247     check64(minmax, DF_HEX_NAN);
248     check_fpstatus(usr, FPINVF);
249 }
250 
251 static void check_canonical_NaN(void)
252 {
253     int sf_result;
254     unsigned long long df_result;
255     int usr;
256 
257     /* Check that each FP instruction properly returns SF_HEX_NAN/DF_HEX_NAN */
258     asm(CLEAR_FPSTATUS
259         "%0 = sfadd(%2, %3)\n\t"
260         "%1 = usr\n\t"
261         : "=r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY)
262         : "r2", "usr");
263     check32(sf_result, SF_HEX_NAN);
264     check_fpstatus(usr, 0);
265 
266     asm(CLEAR_FPSTATUS
267         "%0 = sfsub(%2, %3)\n\t"
268         "%1 = usr\n\t"
269         : "=r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY)
270         : "r2", "usr");
271     check32(sf_result, SF_HEX_NAN);
272     check_fpstatus(usr, 0);
273 
274     asm(CLEAR_FPSTATUS
275         "%0 = sfmpy(%2, %3)\n\t"
276         "%1 = usr\n\t"
277         : "=r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY)
278         : "r2", "usr");
279     check32(sf_result, SF_HEX_NAN);
280     check_fpstatus(usr, 0);
281 
282     sf_result = SF_ZERO;
283     asm(CLEAR_FPSTATUS
284         "%0 += sfmpy(%2, %3)\n\t"
285         "%1 = usr\n\t"
286         : "+r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY)
287         : "r2", "usr");
288     check32(sf_result, SF_HEX_NAN);
289     check_fpstatus(usr, 0);
290 
291     sf_result = SF_ZERO;
292     asm(CLEAR_FPSTATUS
293         "p0 = !cmp.eq(r0, r0)\n\t"
294         "%0 += sfmpy(%2, %3, p0):scale\n\t"
295         "%1 = usr\n\t"
296         : "+r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY)
297         : "r2", "usr", "p0");
298     check32(sf_result, SF_HEX_NAN);
299     check_fpstatus(usr, 0);
300 
301     sf_result = SF_ZERO;
302     asm(CLEAR_FPSTATUS
303         "%0 -= sfmpy(%2, %3)\n\t"
304         "%1 = usr\n\t"
305         : "+r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY)
306         : "r2", "usr");
307     check32(sf_result, SF_HEX_NAN);
308     check_fpstatus(usr, 0);
309 
310     sf_result = SF_ZERO;
311     asm(CLEAR_FPSTATUS
312         "%0 += sfmpy(%2, %3):lib\n\t"
313         "%1 = usr\n\t"
314         : "+r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY)
315         : "r2", "usr");
316     check32(sf_result, SF_HEX_NAN);
317     check_fpstatus(usr, 0);
318 
319     sf_result = SF_ZERO;
320     asm(CLEAR_FPSTATUS
321         "%0 -= sfmpy(%2, %3):lib\n\t"
322         "%1 = usr\n\t"
323         : "+r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY)
324         : "r2", "usr");
325     check32(sf_result, SF_HEX_NAN);
326     check_fpstatus(usr, 0);
327 
328     asm(CLEAR_FPSTATUS
329         "%0 = convert_df2sf(%2)\n\t"
330         "%1 = usr\n\t"
331         : "=r"(sf_result), "=r"(usr) : "r"(DF_NaN)
332         : "r2", "usr");
333     check32(sf_result, SF_HEX_NAN);
334     check_fpstatus(usr, 0);
335 
336     asm(CLEAR_FPSTATUS
337         "%0 = dfadd(%2, %3)\n\t"
338         "%1 = usr\n\t"
339         : "=r"(df_result), "=r"(usr) : "r"(DF_NaN), "r"(DF_ANY)
340         : "r2", "usr");
341     check64(df_result, DF_HEX_NAN);
342     check_fpstatus(usr, 0);
343 
344     asm(CLEAR_FPSTATUS
345         "%0 = dfsub(%2, %3)\n\t"
346         "%1 = usr\n\t"
347         : "=r"(df_result), "=r"(usr) : "r"(DF_NaN), "r"(DF_ANY)
348         : "r2", "usr");
349     check64(df_result, DF_HEX_NAN);
350     check_fpstatus(usr, 0);
351 
352     asm(CLEAR_FPSTATUS
353         "%0 = convert_sf2df(%2)\n\t"
354         "%1 = usr\n\t"
355         : "=r"(df_result), "=r"(usr) : "r"(SF_NaN)
356         : "r2", "usr");
357     check64(df_result, DF_HEX_NAN);
358     check_fpstatus(usr, 0);
359 }
360 
361 int main()
362 {
363     check_compare_exception();
364     check_sfminmax();
365     check_dfminmax();
366     check_canonical_NaN();
367 
368     puts(err ? "FAIL" : "PASS");
369     return err ? 1 : 0;
370 }
371