0001
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
0029
0030 int snan = 0x7fc11111;
0031 int qnan = 0x7f811111;
0032 unsigned short snan1[5];
0033
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"
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"
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
0159
0160
0161 " fldt snan80""\n"
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
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"
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"
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
0304
0305
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 }