162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#undef _GNU_SOURCE 362306a36Sopenharmony_ci#define _GNU_SOURCE 1 462306a36Sopenharmony_ci#undef __USE_GNU 562306a36Sopenharmony_ci#define __USE_GNU 1 662306a36Sopenharmony_ci#include <unistd.h> 762306a36Sopenharmony_ci#include <stdlib.h> 862306a36Sopenharmony_ci#include <string.h> 962306a36Sopenharmony_ci#include <stdio.h> 1062306a36Sopenharmony_ci#include <signal.h> 1162306a36Sopenharmony_ci#include <sys/types.h> 1262306a36Sopenharmony_ci#include <sys/select.h> 1362306a36Sopenharmony_ci#include <sys/time.h> 1462306a36Sopenharmony_ci#include <sys/wait.h> 1562306a36Sopenharmony_ci#include <fenv.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cienum { 1862306a36Sopenharmony_ci CF = 1 << 0, 1962306a36Sopenharmony_ci PF = 1 << 2, 2062306a36Sopenharmony_ci ZF = 1 << 6, 2162306a36Sopenharmony_ci ARITH = CF | PF | ZF, 2262306a36Sopenharmony_ci}; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cilong res_fcomi_pi_1; 2562306a36Sopenharmony_cilong res_fcomi_1_pi; 2662306a36Sopenharmony_cilong res_fcomi_1_1; 2762306a36Sopenharmony_cilong res_fcomi_nan_1; 2862306a36Sopenharmony_ci/* sNaN is s|111 1111 1|1xx xxxx xxxx xxxx xxxx xxxx */ 2962306a36Sopenharmony_ci/* qNaN is s|111 1111 1|0xx xxxx xxxx xxxx xxxx xxxx (some x must be nonzero) */ 3062306a36Sopenharmony_ciint snan = 0x7fc11111; 3162306a36Sopenharmony_ciint qnan = 0x7f811111; 3262306a36Sopenharmony_ciunsigned short snan1[5]; 3362306a36Sopenharmony_ci/* sNaN80 is s|111 1111 1111 1111 |10xx xx...xx (some x must be nonzero) */ 3462306a36Sopenharmony_ciunsigned short snan80[5] = { 0x1111, 0x1111, 0x1111, 0x8111, 0x7fff }; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ciint test(long flags) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci asm ("\n" 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci " push %0""\n" 4362306a36Sopenharmony_ci " popf""\n" 4462306a36Sopenharmony_ci " fld1""\n" 4562306a36Sopenharmony_ci " fldpi""\n" 4662306a36Sopenharmony_ci " fcomi %%st(1), %%st" "\n" 4762306a36Sopenharmony_ci " ffree %%st(0)" "\n" 4862306a36Sopenharmony_ci " ffree %%st(1)" "\n" 4962306a36Sopenharmony_ci " pushf""\n" 5062306a36Sopenharmony_ci " pop res_fcomi_1_pi""\n" 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci " push %0""\n" 5362306a36Sopenharmony_ci " popf""\n" 5462306a36Sopenharmony_ci " fldpi""\n" 5562306a36Sopenharmony_ci " fld1""\n" 5662306a36Sopenharmony_ci " fcomi %%st(1), %%st" "\n" 5762306a36Sopenharmony_ci " ffree %%st(0)" "\n" 5862306a36Sopenharmony_ci " ffree %%st(1)" "\n" 5962306a36Sopenharmony_ci " pushf""\n" 6062306a36Sopenharmony_ci " pop res_fcomi_pi_1""\n" 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci " push %0""\n" 6362306a36Sopenharmony_ci " popf""\n" 6462306a36Sopenharmony_ci " fld1""\n" 6562306a36Sopenharmony_ci " fld1""\n" 6662306a36Sopenharmony_ci " fcomi %%st(1), %%st" "\n" 6762306a36Sopenharmony_ci " ffree %%st(0)" "\n" 6862306a36Sopenharmony_ci " ffree %%st(1)" "\n" 6962306a36Sopenharmony_ci " pushf""\n" 7062306a36Sopenharmony_ci " pop res_fcomi_1_1""\n" 7162306a36Sopenharmony_ci : 7262306a36Sopenharmony_ci : "r" (flags) 7362306a36Sopenharmony_ci ); 7462306a36Sopenharmony_ci if ((res_fcomi_1_pi & ARITH) != (0)) { 7562306a36Sopenharmony_ci printf("[BAD]\tfcomi_1_pi with flags:%lx\n", flags); 7662306a36Sopenharmony_ci return 1; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci if ((res_fcomi_pi_1 & ARITH) != (CF)) { 7962306a36Sopenharmony_ci printf("[BAD]\tfcomi_pi_1 with flags:%lx->%lx\n", flags, res_fcomi_pi_1 & ARITH); 8062306a36Sopenharmony_ci return 1; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci if ((res_fcomi_1_1 & ARITH) != (ZF)) { 8362306a36Sopenharmony_ci printf("[BAD]\tfcomi_1_1 with flags:%lx\n", flags); 8462306a36Sopenharmony_ci return 1; 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci if (fetestexcept(FE_INVALID) != 0) { 8762306a36Sopenharmony_ci printf("[BAD]\tFE_INVALID is set in %s\n", __func__); 8862306a36Sopenharmony_ci return 1; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci return 0; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ciint test_qnan(long flags) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci asm ("\n" 9862306a36Sopenharmony_ci " push %0""\n" 9962306a36Sopenharmony_ci " popf""\n" 10062306a36Sopenharmony_ci " flds qnan""\n" 10162306a36Sopenharmony_ci " fld1""\n" 10262306a36Sopenharmony_ci " fnclex""\n" // fld of a qnan raised FE_INVALID, clear it 10362306a36Sopenharmony_ci " fcomi %%st(1), %%st" "\n" 10462306a36Sopenharmony_ci " ffree %%st(0)" "\n" 10562306a36Sopenharmony_ci " ffree %%st(1)" "\n" 10662306a36Sopenharmony_ci " pushf""\n" 10762306a36Sopenharmony_ci " pop res_fcomi_nan_1""\n" 10862306a36Sopenharmony_ci : 10962306a36Sopenharmony_ci : "r" (flags) 11062306a36Sopenharmony_ci ); 11162306a36Sopenharmony_ci if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) { 11262306a36Sopenharmony_ci printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags); 11362306a36Sopenharmony_ci return 1; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci if (fetestexcept(FE_INVALID) != FE_INVALID) { 11662306a36Sopenharmony_ci printf("[BAD]\tFE_INVALID is not set in %s\n", __func__); 11762306a36Sopenharmony_ci return 1; 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci return 0; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ciint testu_qnan(long flags) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci asm ("\n" 12762306a36Sopenharmony_ci " push %0""\n" 12862306a36Sopenharmony_ci " popf""\n" 12962306a36Sopenharmony_ci " flds qnan""\n" 13062306a36Sopenharmony_ci " fld1""\n" 13162306a36Sopenharmony_ci " fnclex""\n" // fld of a qnan raised FE_INVALID, clear it 13262306a36Sopenharmony_ci " fucomi %%st(1), %%st" "\n" 13362306a36Sopenharmony_ci " ffree %%st(0)" "\n" 13462306a36Sopenharmony_ci " ffree %%st(1)" "\n" 13562306a36Sopenharmony_ci " pushf""\n" 13662306a36Sopenharmony_ci " pop res_fcomi_nan_1""\n" 13762306a36Sopenharmony_ci : 13862306a36Sopenharmony_ci : "r" (flags) 13962306a36Sopenharmony_ci ); 14062306a36Sopenharmony_ci if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) { 14162306a36Sopenharmony_ci printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags); 14262306a36Sopenharmony_ci return 1; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci if (fetestexcept(FE_INVALID) != 0) { 14562306a36Sopenharmony_ci printf("[BAD]\tFE_INVALID is set in %s\n", __func__); 14662306a36Sopenharmony_ci return 1; 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci return 0; 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ciint testu_snan(long flags) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci asm ("\n" 15662306a36Sopenharmony_ci " push %0""\n" 15762306a36Sopenharmony_ci " popf""\n" 15862306a36Sopenharmony_ci// " flds snan""\n" // WRONG, this will convert 32-bit fp snan to a *qnan* in 80-bit fp register! 15962306a36Sopenharmony_ci// " fstpt snan1""\n" // if uncommented, it prints "snan1:7fff c111 1100 0000 0000" - c111, not 8111! 16062306a36Sopenharmony_ci// " fnclex""\n" // flds of a snan raised FE_INVALID, clear it 16162306a36Sopenharmony_ci " fldt snan80""\n" // fldt never raise FE_INVALID 16262306a36Sopenharmony_ci " fld1""\n" 16362306a36Sopenharmony_ci " fucomi %%st(1), %%st" "\n" 16462306a36Sopenharmony_ci " ffree %%st(0)" "\n" 16562306a36Sopenharmony_ci " ffree %%st(1)" "\n" 16662306a36Sopenharmony_ci " pushf""\n" 16762306a36Sopenharmony_ci " pop res_fcomi_nan_1""\n" 16862306a36Sopenharmony_ci : 16962306a36Sopenharmony_ci : "r" (flags) 17062306a36Sopenharmony_ci ); 17162306a36Sopenharmony_ci if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) { 17262306a36Sopenharmony_ci printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags); 17362306a36Sopenharmony_ci return 1; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci// printf("snan:%x snan1:%04x %04x %04x %04x %04x\n", snan, snan1[4], snan1[3], snan1[2], snan1[1], snan1[0]); 17662306a36Sopenharmony_ci if (fetestexcept(FE_INVALID) != FE_INVALID) { 17762306a36Sopenharmony_ci printf("[BAD]\tFE_INVALID is not set in %s\n", __func__); 17862306a36Sopenharmony_ci return 1; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci return 0; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ciint testp(long flags) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci asm ("\n" 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci " push %0""\n" 19062306a36Sopenharmony_ci " popf""\n" 19162306a36Sopenharmony_ci " fld1""\n" 19262306a36Sopenharmony_ci " fldpi""\n" 19362306a36Sopenharmony_ci " fcomip %%st(1), %%st" "\n" 19462306a36Sopenharmony_ci " ffree %%st(0)" "\n" 19562306a36Sopenharmony_ci " pushf""\n" 19662306a36Sopenharmony_ci " pop res_fcomi_1_pi""\n" 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci " push %0""\n" 19962306a36Sopenharmony_ci " popf""\n" 20062306a36Sopenharmony_ci " fldpi""\n" 20162306a36Sopenharmony_ci " fld1""\n" 20262306a36Sopenharmony_ci " fcomip %%st(1), %%st" "\n" 20362306a36Sopenharmony_ci " ffree %%st(0)" "\n" 20462306a36Sopenharmony_ci " pushf""\n" 20562306a36Sopenharmony_ci " pop res_fcomi_pi_1""\n" 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci " push %0""\n" 20862306a36Sopenharmony_ci " popf""\n" 20962306a36Sopenharmony_ci " fld1""\n" 21062306a36Sopenharmony_ci " fld1""\n" 21162306a36Sopenharmony_ci " fcomip %%st(1), %%st" "\n" 21262306a36Sopenharmony_ci " ffree %%st(0)" "\n" 21362306a36Sopenharmony_ci " pushf""\n" 21462306a36Sopenharmony_ci " pop res_fcomi_1_1""\n" 21562306a36Sopenharmony_ci : 21662306a36Sopenharmony_ci : "r" (flags) 21762306a36Sopenharmony_ci ); 21862306a36Sopenharmony_ci if ((res_fcomi_1_pi & ARITH) != (0)) { 21962306a36Sopenharmony_ci printf("[BAD]\tfcomi_1_pi with flags:%lx\n", flags); 22062306a36Sopenharmony_ci return 1; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci if ((res_fcomi_pi_1 & ARITH) != (CF)) { 22362306a36Sopenharmony_ci printf("[BAD]\tfcomi_pi_1 with flags:%lx->%lx\n", flags, res_fcomi_pi_1 & ARITH); 22462306a36Sopenharmony_ci return 1; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci if ((res_fcomi_1_1 & ARITH) != (ZF)) { 22762306a36Sopenharmony_ci printf("[BAD]\tfcomi_1_1 with flags:%lx\n", flags); 22862306a36Sopenharmony_ci return 1; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci if (fetestexcept(FE_INVALID) != 0) { 23162306a36Sopenharmony_ci printf("[BAD]\tFE_INVALID is set in %s\n", __func__); 23262306a36Sopenharmony_ci return 1; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci return 0; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ciint testp_qnan(long flags) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci asm ("\n" 24262306a36Sopenharmony_ci " push %0""\n" 24362306a36Sopenharmony_ci " popf""\n" 24462306a36Sopenharmony_ci " flds qnan""\n" 24562306a36Sopenharmony_ci " fld1""\n" 24662306a36Sopenharmony_ci " fnclex""\n" // fld of a qnan raised FE_INVALID, clear it 24762306a36Sopenharmony_ci " fcomip %%st(1), %%st" "\n" 24862306a36Sopenharmony_ci " ffree %%st(0)" "\n" 24962306a36Sopenharmony_ci " pushf""\n" 25062306a36Sopenharmony_ci " pop res_fcomi_nan_1""\n" 25162306a36Sopenharmony_ci : 25262306a36Sopenharmony_ci : "r" (flags) 25362306a36Sopenharmony_ci ); 25462306a36Sopenharmony_ci if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) { 25562306a36Sopenharmony_ci printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags); 25662306a36Sopenharmony_ci return 1; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci if (fetestexcept(FE_INVALID) != FE_INVALID) { 25962306a36Sopenharmony_ci printf("[BAD]\tFE_INVALID is not set in %s\n", __func__); 26062306a36Sopenharmony_ci return 1; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci return 0; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ciint testup_qnan(long flags) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci asm ("\n" 27062306a36Sopenharmony_ci " push %0""\n" 27162306a36Sopenharmony_ci " popf""\n" 27262306a36Sopenharmony_ci " flds qnan""\n" 27362306a36Sopenharmony_ci " fld1""\n" 27462306a36Sopenharmony_ci " fnclex""\n" // fld of a qnan raised FE_INVALID, clear it 27562306a36Sopenharmony_ci " fucomip %%st(1), %%st" "\n" 27662306a36Sopenharmony_ci " ffree %%st(0)" "\n" 27762306a36Sopenharmony_ci " pushf""\n" 27862306a36Sopenharmony_ci " pop res_fcomi_nan_1""\n" 27962306a36Sopenharmony_ci : 28062306a36Sopenharmony_ci : "r" (flags) 28162306a36Sopenharmony_ci ); 28262306a36Sopenharmony_ci if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) { 28362306a36Sopenharmony_ci printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags); 28462306a36Sopenharmony_ci return 1; 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci if (fetestexcept(FE_INVALID) != 0) { 28762306a36Sopenharmony_ci printf("[BAD]\tFE_INVALID is set in %s\n", __func__); 28862306a36Sopenharmony_ci return 1; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci return 0; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_civoid sighandler(int sig) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci printf("[FAIL]\tGot signal %d, exiting\n", sig); 29662306a36Sopenharmony_ci exit(1); 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ciint main(int argc, char **argv, char **envp) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci int err = 0; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci /* SIGILL triggers on 32-bit kernels w/o fcomi emulation 30462306a36Sopenharmony_ci * when run with "no387 nofxsr". Other signals are caught 30562306a36Sopenharmony_ci * just in case. 30662306a36Sopenharmony_ci */ 30762306a36Sopenharmony_ci signal(SIGILL, sighandler); 30862306a36Sopenharmony_ci signal(SIGFPE, sighandler); 30962306a36Sopenharmony_ci signal(SIGSEGV, sighandler); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci printf("[RUN]\tTesting f[u]comi[p] instructions\n"); 31262306a36Sopenharmony_ci err |= test(0); 31362306a36Sopenharmony_ci err |= test_qnan(0); 31462306a36Sopenharmony_ci err |= testu_qnan(0); 31562306a36Sopenharmony_ci err |= testu_snan(0); 31662306a36Sopenharmony_ci err |= test(CF|ZF|PF); 31762306a36Sopenharmony_ci err |= test_qnan(CF|ZF|PF); 31862306a36Sopenharmony_ci err |= testu_qnan(CF|ZF|PF); 31962306a36Sopenharmony_ci err |= testu_snan(CF|ZF|PF); 32062306a36Sopenharmony_ci err |= testp(0); 32162306a36Sopenharmony_ci err |= testp_qnan(0); 32262306a36Sopenharmony_ci err |= testup_qnan(0); 32362306a36Sopenharmony_ci err |= testp(CF|ZF|PF); 32462306a36Sopenharmony_ci err |= testp_qnan(CF|ZF|PF); 32562306a36Sopenharmony_ci err |= testup_qnan(CF|ZF|PF); 32662306a36Sopenharmony_ci if (!err) 32762306a36Sopenharmony_ci printf("[OK]\tf[u]comi[p]\n"); 32862306a36Sopenharmony_ci else 32962306a36Sopenharmony_ci printf("[FAIL]\tf[u]comi[p] errors: %d\n", err); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci return err; 33262306a36Sopenharmony_ci} 333