Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #undef _GNU_SOURCE
0003 #define _GNU_SOURCE 1
0004 #undef __USE_GNU
0005 #define __USE_GNU 1
0006 #include <unistd.h>
0007 #include <stdlib.h>
0008 #include <string.h>
0009 #include <stdio.h>
0010 #include <signal.h>
0011 #include <sys/types.h>
0012 #include <sys/select.h>
0013 #include <sys/time.h>
0014 #include <sys/wait.h>
0015 #include <fenv.h>
0016 
0017 enum {
0018     CF = 1 << 0,
0019     PF = 1 << 2,
0020     ZF = 1 << 6,
0021     ARITH = CF | PF | ZF,
0022 };
0023 
0024 long res_fcomi_pi_1;
0025 long res_fcomi_1_pi;
0026 long res_fcomi_1_1;
0027 long res_fcomi_nan_1;
0028 /* sNaN is s|111 1111 1|1xx xxxx xxxx xxxx xxxx xxxx */
0029 /* qNaN is s|111 1111 1|0xx xxxx xxxx xxxx xxxx xxxx (some x must be nonzero) */
0030 int snan = 0x7fc11111;
0031 int qnan = 0x7f811111;
0032 unsigned short snan1[5];
0033 /* sNaN80 is s|111 1111 1111 1111 |10xx xx...xx (some x must be nonzero) */
0034 unsigned short snan80[5] = { 0x1111, 0x1111, 0x1111, 0x8111, 0x7fff };
0035 
0036 int test(long flags)
0037 {
0038     feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
0039 
0040     asm ("\n"
0041 
0042     "   push    %0""\n"
0043     "   popf""\n"
0044     "   fld1""\n"
0045     "   fldpi""\n"
0046     "   fcomi   %%st(1), %%st" "\n"
0047     "   ffree   %%st(0)" "\n"
0048     "   ffree   %%st(1)" "\n"
0049     "   pushf""\n"
0050     "   pop res_fcomi_1_pi""\n"
0051 
0052     "   push    %0""\n"
0053     "   popf""\n"
0054     "   fldpi""\n"
0055     "   fld1""\n"
0056     "   fcomi   %%st(1), %%st" "\n"
0057     "   ffree   %%st(0)" "\n"
0058     "   ffree   %%st(1)" "\n"
0059     "   pushf""\n"
0060     "   pop res_fcomi_pi_1""\n"
0061 
0062     "   push    %0""\n"
0063     "   popf""\n"
0064     "   fld1""\n"
0065     "   fld1""\n"
0066     "   fcomi   %%st(1), %%st" "\n"
0067     "   ffree   %%st(0)" "\n"
0068     "   ffree   %%st(1)" "\n"
0069     "   pushf""\n"
0070     "   pop res_fcomi_1_1""\n"
0071     :
0072     : "r" (flags)
0073     );
0074     if ((res_fcomi_1_pi & ARITH) != (0)) {
0075         printf("[BAD]\tfcomi_1_pi with flags:%lx\n", flags);
0076         return 1;
0077     }
0078     if ((res_fcomi_pi_1 & ARITH) != (CF)) {
0079         printf("[BAD]\tfcomi_pi_1 with flags:%lx->%lx\n", flags, res_fcomi_pi_1 & ARITH);
0080         return 1;
0081     }
0082     if ((res_fcomi_1_1 & ARITH) != (ZF)) {
0083         printf("[BAD]\tfcomi_1_1 with flags:%lx\n", flags);
0084         return 1;
0085     }
0086     if (fetestexcept(FE_INVALID) != 0) {
0087         printf("[BAD]\tFE_INVALID is set in %s\n", __func__);
0088         return 1;
0089     }
0090     return 0;
0091 }
0092 
0093 int test_qnan(long flags)
0094 {
0095     feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
0096 
0097     asm ("\n"
0098     "   push    %0""\n"
0099     "   popf""\n"
0100     "   flds    qnan""\n"
0101     "   fld1""\n"
0102     "   fnclex""\n"     // fld of a qnan raised FE_INVALID, clear it
0103     "   fcomi   %%st(1), %%st" "\n"
0104     "   ffree   %%st(0)" "\n"
0105     "   ffree   %%st(1)" "\n"
0106     "   pushf""\n"
0107     "   pop res_fcomi_nan_1""\n"
0108     :
0109     : "r" (flags)
0110     );
0111     if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {
0112         printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);
0113         return 1;
0114     }
0115     if (fetestexcept(FE_INVALID) != FE_INVALID) {
0116         printf("[BAD]\tFE_INVALID is not set in %s\n", __func__);
0117         return 1;
0118     }
0119     return 0;
0120 }
0121 
0122 int testu_qnan(long flags)
0123 {
0124     feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
0125 
0126     asm ("\n"
0127     "   push    %0""\n"
0128     "   popf""\n"
0129     "   flds    qnan""\n"
0130     "   fld1""\n"
0131     "   fnclex""\n"     // fld of a qnan raised FE_INVALID, clear it
0132     "   fucomi  %%st(1), %%st" "\n"
0133     "   ffree   %%st(0)" "\n"
0134     "   ffree   %%st(1)" "\n"
0135     "   pushf""\n"
0136     "   pop res_fcomi_nan_1""\n"
0137     :
0138     : "r" (flags)
0139     );
0140     if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {
0141         printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);
0142         return 1;
0143     }
0144     if (fetestexcept(FE_INVALID) != 0) {
0145         printf("[BAD]\tFE_INVALID is set in %s\n", __func__);
0146         return 1;
0147     }
0148     return 0;
0149 }
0150 
0151 int testu_snan(long flags)
0152 {
0153     feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
0154 
0155     asm ("\n"
0156     "   push    %0""\n"
0157     "   popf""\n"
0158 //  "   flds    snan""\n"   // WRONG, this will convert 32-bit fp snan to a *qnan* in 80-bit fp register!
0159 //  "   fstpt   snan1""\n"  // if uncommented, it prints "snan1:7fff c111 1100 0000 0000" - c111, not 8111!
0160 //  "   fnclex""\n"     // flds of a snan raised FE_INVALID, clear it
0161     "   fldt    snan80""\n" // fldt never raise FE_INVALID
0162     "   fld1""\n"
0163     "   fucomi  %%st(1), %%st" "\n"
0164     "   ffree   %%st(0)" "\n"
0165     "   ffree   %%st(1)" "\n"
0166     "   pushf""\n"
0167     "   pop res_fcomi_nan_1""\n"
0168     :
0169     : "r" (flags)
0170     );
0171     if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {
0172         printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);
0173         return 1;
0174     }
0175 //  printf("snan:%x snan1:%04x %04x %04x %04x %04x\n", snan, snan1[4], snan1[3], snan1[2], snan1[1], snan1[0]);
0176     if (fetestexcept(FE_INVALID) != FE_INVALID) {
0177         printf("[BAD]\tFE_INVALID is not set in %s\n", __func__);
0178         return 1;
0179     }
0180     return 0;
0181 }
0182 
0183 int testp(long flags)
0184 {
0185     feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
0186 
0187     asm ("\n"
0188 
0189     "   push    %0""\n"
0190     "   popf""\n"
0191     "   fld1""\n"
0192     "   fldpi""\n"
0193     "   fcomip  %%st(1), %%st" "\n"
0194     "   ffree   %%st(0)" "\n"
0195     "   pushf""\n"
0196     "   pop res_fcomi_1_pi""\n"
0197 
0198     "   push    %0""\n"
0199     "   popf""\n"
0200     "   fldpi""\n"
0201     "   fld1""\n"
0202     "   fcomip  %%st(1), %%st" "\n"
0203     "   ffree   %%st(0)" "\n"
0204     "   pushf""\n"
0205     "   pop res_fcomi_pi_1""\n"
0206 
0207     "   push    %0""\n"
0208     "   popf""\n"
0209     "   fld1""\n"
0210     "   fld1""\n"
0211     "   fcomip  %%st(1), %%st" "\n"
0212     "   ffree   %%st(0)" "\n"
0213     "   pushf""\n"
0214     "   pop res_fcomi_1_1""\n"
0215     :
0216     : "r" (flags)
0217     );
0218     if ((res_fcomi_1_pi & ARITH) != (0)) {
0219         printf("[BAD]\tfcomi_1_pi with flags:%lx\n", flags);
0220         return 1;
0221     }
0222     if ((res_fcomi_pi_1 & ARITH) != (CF)) {
0223         printf("[BAD]\tfcomi_pi_1 with flags:%lx->%lx\n", flags, res_fcomi_pi_1 & ARITH);
0224         return 1;
0225     }
0226     if ((res_fcomi_1_1 & ARITH) != (ZF)) {
0227         printf("[BAD]\tfcomi_1_1 with flags:%lx\n", flags);
0228         return 1;
0229     }
0230     if (fetestexcept(FE_INVALID) != 0) {
0231         printf("[BAD]\tFE_INVALID is set in %s\n", __func__);
0232         return 1;
0233     }
0234     return 0;
0235 }
0236 
0237 int testp_qnan(long flags)
0238 {
0239     feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
0240 
0241     asm ("\n"
0242     "   push    %0""\n"
0243     "   popf""\n"
0244     "   flds    qnan""\n"
0245     "   fld1""\n"
0246     "   fnclex""\n"     // fld of a qnan raised FE_INVALID, clear it
0247     "   fcomip  %%st(1), %%st" "\n"
0248     "   ffree   %%st(0)" "\n"
0249     "   pushf""\n"
0250     "   pop res_fcomi_nan_1""\n"
0251     :
0252     : "r" (flags)
0253     );
0254     if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {
0255         printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);
0256         return 1;
0257     }
0258     if (fetestexcept(FE_INVALID) != FE_INVALID) {
0259         printf("[BAD]\tFE_INVALID is not set in %s\n", __func__);
0260         return 1;
0261     }
0262     return 0;
0263 }
0264 
0265 int testup_qnan(long flags)
0266 {
0267     feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
0268 
0269     asm ("\n"
0270     "   push    %0""\n"
0271     "   popf""\n"
0272     "   flds    qnan""\n"
0273     "   fld1""\n"
0274     "   fnclex""\n"     // fld of a qnan raised FE_INVALID, clear it
0275     "   fucomip %%st(1), %%st" "\n"
0276     "   ffree   %%st(0)" "\n"
0277     "   pushf""\n"
0278     "   pop res_fcomi_nan_1""\n"
0279     :
0280     : "r" (flags)
0281     );
0282     if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {
0283         printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);
0284         return 1;
0285     }
0286     if (fetestexcept(FE_INVALID) != 0) {
0287         printf("[BAD]\tFE_INVALID is set in %s\n", __func__);
0288         return 1;
0289     }
0290     return 0;
0291 }
0292 
0293 void sighandler(int sig)
0294 {
0295     printf("[FAIL]\tGot signal %d, exiting\n", sig);
0296     exit(1);
0297 }
0298 
0299 int main(int argc, char **argv, char **envp)
0300 {
0301     int err = 0;
0302 
0303     /* SIGILL triggers on 32-bit kernels w/o fcomi emulation
0304      * when run with "no387 nofxsr". Other signals are caught
0305      * just in case.
0306      */
0307     signal(SIGILL, sighandler);
0308     signal(SIGFPE, sighandler);
0309     signal(SIGSEGV, sighandler);
0310 
0311     printf("[RUN]\tTesting f[u]comi[p] instructions\n");
0312     err |= test(0);
0313     err |= test_qnan(0);
0314     err |= testu_qnan(0);
0315     err |= testu_snan(0);
0316     err |= test(CF|ZF|PF);
0317     err |= test_qnan(CF|ZF|PF);
0318     err |= testu_qnan(CF|ZF|PF);
0319     err |= testu_snan(CF|ZF|PF);
0320     err |= testp(0);
0321     err |= testp_qnan(0);
0322     err |= testup_qnan(0);
0323     err |= testp(CF|ZF|PF);
0324     err |= testp_qnan(CF|ZF|PF);
0325     err |= testup_qnan(CF|ZF|PF);
0326     if (!err)
0327         printf("[OK]\tf[u]comi[p]\n");
0328     else
0329         printf("[FAIL]\tf[u]comi[p] errors: %d\n", err);
0330 
0331     return err;
0332 }