]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - tools/testing/selftests/x86/test_FCOMI.c
Merge remote-tracking branch 'ipsec/master'
[karo-tx-linux.git] / tools / testing / selftests / x86 / test_FCOMI.c
1 #undef _GNU_SOURCE
2 #define _GNU_SOURCE 1
3 #undef __USE_GNU
4 #define __USE_GNU 1
5 #include <unistd.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <signal.h>
10 #include <sys/types.h>
11 #include <sys/select.h>
12 #include <sys/time.h>
13 #include <sys/wait.h>
14 #include <fenv.h>
15
16 enum {
17         CF = 1 << 0,
18         PF = 1 << 2,
19         ZF = 1 << 6,
20         ARITH = CF | PF | ZF,
21 };
22
23 long res_fcomi_pi_1;
24 long res_fcomi_1_pi;
25 long res_fcomi_1_1;
26 long res_fcomi_nan_1;
27 /* sNaN is s|111 1111 1|1xx xxxx xxxx xxxx xxxx xxxx */
28 /* qNaN is s|111 1111 1|0xx xxxx xxxx xxxx xxxx xxxx (some x must be nonzero) */
29 int snan = 0x7fc11111;
30 int qnan = 0x7f811111;
31 unsigned short snan1[5];
32 /* sNaN80 is s|111 1111 1111 1111 |10xx xx...xx (some x must be nonzero) */
33 unsigned short snan80[5] = { 0x1111, 0x1111, 0x1111, 0x8111, 0x7fff };
34
35 int test(long flags)
36 {
37         feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
38
39         asm ("\n"
40
41         "       push    %0""\n"
42         "       popf""\n"
43         "       fld1""\n"
44         "       fldpi""\n"
45         "       fcomi   %%st(1), %%st" "\n"
46         "       ffree   %%st(0)" "\n"
47         "       ffree   %%st(1)" "\n"
48         "       pushf""\n"
49         "       pop     res_fcomi_1_pi""\n"
50
51         "       push    %0""\n"
52         "       popf""\n"
53         "       fldpi""\n"
54         "       fld1""\n"
55         "       fcomi   %%st(1), %%st" "\n"
56         "       ffree   %%st(0)" "\n"
57         "       ffree   %%st(1)" "\n"
58         "       pushf""\n"
59         "       pop     res_fcomi_pi_1""\n"
60
61         "       push    %0""\n"
62         "       popf""\n"
63         "       fld1""\n"
64         "       fld1""\n"
65         "       fcomi   %%st(1), %%st" "\n"
66         "       ffree   %%st(0)" "\n"
67         "       ffree   %%st(1)" "\n"
68         "       pushf""\n"
69         "       pop     res_fcomi_1_1""\n"
70         :
71         : "r" (flags)
72         );
73         if ((res_fcomi_1_pi & ARITH) != (0)) {
74                 printf("[BAD]\tfcomi_1_pi with flags:%lx\n", flags);
75                 return 1;
76         }
77         if ((res_fcomi_pi_1 & ARITH) != (CF)) {
78                 printf("[BAD]\tfcomi_pi_1 with flags:%lx->%lx\n", flags, res_fcomi_pi_1 & ARITH);
79                 return 1;
80         }
81         if ((res_fcomi_1_1 & ARITH) != (ZF)) {
82                 printf("[BAD]\tfcomi_1_1 with flags:%lx\n", flags);
83                 return 1;
84         }
85         if (fetestexcept(FE_INVALID) != 0) {
86                 printf("[BAD]\tFE_INVALID is set in %s\n", __func__);
87                 return 1;
88         }
89         return 0;
90 }
91
92 int test_qnan(long flags)
93 {
94         feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
95
96         asm ("\n"
97         "       push    %0""\n"
98         "       popf""\n"
99         "       flds    qnan""\n"
100         "       fld1""\n"
101         "       fnclex""\n"             // fld of a qnan raised FE_INVALID, clear it
102         "       fcomi   %%st(1), %%st" "\n"
103         "       ffree   %%st(0)" "\n"
104         "       ffree   %%st(1)" "\n"
105         "       pushf""\n"
106         "       pop     res_fcomi_nan_1""\n"
107         :
108         : "r" (flags)
109         );
110         if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {
111                 printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);
112                 return 1;
113         }
114         if (fetestexcept(FE_INVALID) != FE_INVALID) {
115                 printf("[BAD]\tFE_INVALID is not set in %s\n", __func__);
116                 return 1;
117         }
118         return 0;
119 }
120
121 int testu_qnan(long flags)
122 {
123         feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
124
125         asm ("\n"
126         "       push    %0""\n"
127         "       popf""\n"
128         "       flds    qnan""\n"
129         "       fld1""\n"
130         "       fnclex""\n"             // fld of a qnan raised FE_INVALID, clear it
131         "       fucomi  %%st(1), %%st" "\n"
132         "       ffree   %%st(0)" "\n"
133         "       ffree   %%st(1)" "\n"
134         "       pushf""\n"
135         "       pop     res_fcomi_nan_1""\n"
136         :
137         : "r" (flags)
138         );
139         if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {
140                 printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);
141                 return 1;
142         }
143         if (fetestexcept(FE_INVALID) != 0) {
144                 printf("[BAD]\tFE_INVALID is set in %s\n", __func__);
145                 return 1;
146         }
147         return 0;
148 }
149
150 int testu_snan(long flags)
151 {
152         feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
153
154         asm ("\n"
155         "       push    %0""\n"
156         "       popf""\n"
157 //      "       flds    snan""\n"       // WRONG, this will convert 32-bit fp snan to a *qnan* in 80-bit fp register!
158 //      "       fstpt   snan1""\n"      // if uncommented, it prints "snan1:7fff c111 1100 0000 0000" - c111, not 8111!
159 //      "       fnclex""\n"             // flds of a snan raised FE_INVALID, clear it
160         "       fldt    snan80""\n"     // fldt never raise FE_INVALID
161         "       fld1""\n"
162         "       fucomi  %%st(1), %%st" "\n"
163         "       ffree   %%st(0)" "\n"
164         "       ffree   %%st(1)" "\n"
165         "       pushf""\n"
166         "       pop     res_fcomi_nan_1""\n"
167         :
168         : "r" (flags)
169         );
170         if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {
171                 printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);
172                 return 1;
173         }
174 //      printf("snan:%x snan1:%04x %04x %04x %04x %04x\n", snan, snan1[4], snan1[3], snan1[2], snan1[1], snan1[0]);
175         if (fetestexcept(FE_INVALID) != FE_INVALID) {
176                 printf("[BAD]\tFE_INVALID is not set in %s\n", __func__);
177                 return 1;
178         }
179         return 0;
180 }
181
182 int testp(long flags)
183 {
184         feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
185
186         asm ("\n"
187
188         "       push    %0""\n"
189         "       popf""\n"
190         "       fld1""\n"
191         "       fldpi""\n"
192         "       fcomip  %%st(1), %%st" "\n"
193         "       ffree   %%st(0)" "\n"
194         "       pushf""\n"
195         "       pop     res_fcomi_1_pi""\n"
196
197         "       push    %0""\n"
198         "       popf""\n"
199         "       fldpi""\n"
200         "       fld1""\n"
201         "       fcomip  %%st(1), %%st" "\n"
202         "       ffree   %%st(0)" "\n"
203         "       pushf""\n"
204         "       pop     res_fcomi_pi_1""\n"
205
206         "       push    %0""\n"
207         "       popf""\n"
208         "       fld1""\n"
209         "       fld1""\n"
210         "       fcomip  %%st(1), %%st" "\n"
211         "       ffree   %%st(0)" "\n"
212         "       pushf""\n"
213         "       pop     res_fcomi_1_1""\n"
214         :
215         : "r" (flags)
216         );
217         if ((res_fcomi_1_pi & ARITH) != (0)) {
218                 printf("[BAD]\tfcomi_1_pi with flags:%lx\n", flags);
219                 return 1;
220         }
221         if ((res_fcomi_pi_1 & ARITH) != (CF)) {
222                 printf("[BAD]\tfcomi_pi_1 with flags:%lx->%lx\n", flags, res_fcomi_pi_1 & ARITH);
223                 return 1;
224         }
225         if ((res_fcomi_1_1 & ARITH) != (ZF)) {
226                 printf("[BAD]\tfcomi_1_1 with flags:%lx\n", flags);
227                 return 1;
228         }
229         if (fetestexcept(FE_INVALID) != 0) {
230                 printf("[BAD]\tFE_INVALID is set in %s\n", __func__);
231                 return 1;
232         }
233         return 0;
234 }
235
236 int testp_qnan(long flags)
237 {
238         feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
239
240         asm ("\n"
241         "       push    %0""\n"
242         "       popf""\n"
243         "       flds    qnan""\n"
244         "       fld1""\n"
245         "       fnclex""\n"             // fld of a qnan raised FE_INVALID, clear it
246         "       fcomip  %%st(1), %%st" "\n"
247         "       ffree   %%st(0)" "\n"
248         "       pushf""\n"
249         "       pop     res_fcomi_nan_1""\n"
250         :
251         : "r" (flags)
252         );
253         if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {
254                 printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);
255                 return 1;
256         }
257         if (fetestexcept(FE_INVALID) != FE_INVALID) {
258                 printf("[BAD]\tFE_INVALID is not set in %s\n", __func__);
259                 return 1;
260         }
261         return 0;
262 }
263
264 int testup_qnan(long flags)
265 {
266         feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
267
268         asm ("\n"
269         "       push    %0""\n"
270         "       popf""\n"
271         "       flds    qnan""\n"
272         "       fld1""\n"
273         "       fnclex""\n"             // fld of a qnan raised FE_INVALID, clear it
274         "       fucomip %%st(1), %%st" "\n"
275         "       ffree   %%st(0)" "\n"
276         "       pushf""\n"
277         "       pop     res_fcomi_nan_1""\n"
278         :
279         : "r" (flags)
280         );
281         if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {
282                 printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);
283                 return 1;
284         }
285         if (fetestexcept(FE_INVALID) != 0) {
286                 printf("[BAD]\tFE_INVALID is set in %s\n", __func__);
287                 return 1;
288         }
289         return 0;
290 }
291
292 void sighandler(int sig)
293 {
294         printf("[FAIL]\tGot signal %d, exiting\n", sig);
295         exit(1);
296 }
297
298 int main(int argc, char **argv, char **envp)
299 {
300         int err = 0;
301
302         /* SIGILL triggers on 32-bit kernels w/o fcomi emulation
303          * when run with "no387 nofxsr". Other signals are caught
304          * just in case.
305          */
306         signal(SIGILL, sighandler);
307         signal(SIGFPE, sighandler);
308         signal(SIGSEGV, sighandler);
309
310         printf("[RUN]\tTesting f[u]comi[p] instructions\n");
311         err |= test(0);
312         err |= test_qnan(0);
313         err |= testu_qnan(0);
314         err |= testu_snan(0);
315         err |= test(CF|ZF|PF);
316         err |= test_qnan(CF|ZF|PF);
317         err |= testu_qnan(CF|ZF|PF);
318         err |= testu_snan(CF|ZF|PF);
319         err |= testp(0);
320         err |= testp_qnan(0);
321         err |= testup_qnan(0);
322         err |= testp(CF|ZF|PF);
323         err |= testp_qnan(CF|ZF|PF);
324         err |= testup_qnan(CF|ZF|PF);
325         if (!err)
326                 printf("[OK]\tf[u]comi[p]\n");
327         else
328                 printf("[FAIL]\tf[u]comi[p] errors: %d\n", err);
329
330         return err;
331 }