~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/x86/test_FCOMI.c

Version: ~ [ linux-5.5-rc1 ] ~ [ linux-5.4.2 ] ~ [ linux-5.3.15 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.88 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.158 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.206 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.206 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.78 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp