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 } 332