root/tools/testing/selftests/x86/test_FCOMI.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. test
  2. test_qnan
  3. testu_qnan
  4. testu_snan
  5. testp
  6. testp_qnan
  7. testup_qnan
  8. sighandler
  9. main

   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 }

/* [<][>][^][v][top][bottom][index][help] */