diff options
| author | Denys Vlasenko <dvlasenk@redhat.com> | 2015-09-17 09:02:13 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2015-09-20 04:19:52 -0400 |
| commit | 57ca6897cd134efd8914cc230f602abad431c7db (patch) | |
| tree | cb71434e669b053f27de7f70248e860620f8ab7c /tools | |
| parent | 73477bbb09e7022063d1737c7322ad2e08968c23 (diff) | |
x86/fpu/math-emu, selftests: Add tests for FCMOV and FCOMI insns
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Shuah Khan <shuahkh@osg.samsung.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/1442494933-13798-1-git-send-email-dvlasenk@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/testing/selftests/x86/Makefile | 5 | ||||
| -rw-r--r-- | tools/testing/selftests/x86/test_FCMOV.c | 93 | ||||
| -rw-r--r-- | tools/testing/selftests/x86/test_FCOMI.c | 331 |
3 files changed, 427 insertions, 2 deletions
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index 29089b24d18b..c4c9b9088998 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile | |||
| @@ -5,7 +5,8 @@ include ../lib.mk | |||
| 5 | .PHONY: all all_32 all_64 warn_32bit_failure clean | 5 | .PHONY: all all_32 all_64 warn_32bit_failure clean |
| 6 | 6 | ||
| 7 | TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs ldt_gdt syscall_nt | 7 | TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs ldt_gdt syscall_nt |
| 8 | TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault sigreturn | 8 | TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault sigreturn \ |
| 9 | test_FCMOV test_FCOMI | ||
| 9 | 10 | ||
| 10 | TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY) | 11 | TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY) |
| 11 | BINARIES_32 := $(TARGETS_C_32BIT_ALL:%=%_32) | 12 | BINARIES_32 := $(TARGETS_C_32BIT_ALL:%=%_32) |
| @@ -35,7 +36,7 @@ clean: | |||
| 35 | $(RM) $(BINARIES_32) $(BINARIES_64) | 36 | $(RM) $(BINARIES_32) $(BINARIES_64) |
| 36 | 37 | ||
| 37 | $(TARGETS_C_32BIT_ALL:%=%_32): %_32: %.c | 38 | $(TARGETS_C_32BIT_ALL:%=%_32): %_32: %.c |
| 38 | $(CC) -m32 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl | 39 | $(CC) -m32 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl -lm |
| 39 | 40 | ||
| 40 | $(TARGETS_C_BOTHBITS:%=%_64): %_64: %.c | 41 | $(TARGETS_C_BOTHBITS:%=%_64): %_64: %.c |
| 41 | $(CC) -m64 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl | 42 | $(CC) -m64 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl |
diff --git a/tools/testing/selftests/x86/test_FCMOV.c b/tools/testing/selftests/x86/test_FCMOV.c new file mode 100644 index 000000000000..4adcca0c80c4 --- /dev/null +++ b/tools/testing/selftests/x86/test_FCMOV.c | |||
| @@ -0,0 +1,93 @@ | |||
| 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 | |||
| 15 | #define TEST(insn) \ | ||
| 16 | long double __attribute__((noinline)) insn(long flags) \ | ||
| 17 | { \ | ||
| 18 | long double out; \ | ||
| 19 | asm ("\n" \ | ||
| 20 | " push %1""\n" \ | ||
| 21 | " popf""\n" \ | ||
| 22 | " fldpi""\n" \ | ||
| 23 | " fld1""\n" \ | ||
| 24 | " " #insn " %%st(1), %%st" "\n" \ | ||
| 25 | " ffree %%st(1)" "\n" \ | ||
| 26 | : "=t" (out) \ | ||
| 27 | : "r" (flags) \ | ||
| 28 | ); \ | ||
| 29 | return out; \ | ||
| 30 | } | ||
| 31 | |||
| 32 | TEST(fcmovb) | ||
| 33 | TEST(fcmove) | ||
| 34 | TEST(fcmovbe) | ||
| 35 | TEST(fcmovu) | ||
| 36 | TEST(fcmovnb) | ||
| 37 | TEST(fcmovne) | ||
| 38 | TEST(fcmovnbe) | ||
| 39 | TEST(fcmovnu) | ||
| 40 | |||
| 41 | enum { | ||
| 42 | CF = 1 << 0, | ||
| 43 | PF = 1 << 2, | ||
| 44 | ZF = 1 << 6, | ||
| 45 | }; | ||
| 46 | |||
| 47 | void sighandler(int sig) | ||
| 48 | { | ||
| 49 | printf("[FAIL]\tGot signal %d, exiting\n", sig); | ||
| 50 | exit(1); | ||
| 51 | } | ||
| 52 | |||
| 53 | int main(int argc, char **argv, char **envp) | ||
| 54 | { | ||
| 55 | int err = 0; | ||
| 56 | |||
| 57 | /* SIGILL triggers on 32-bit kernels w/o fcomi emulation | ||
| 58 | * when run with "no387 nofxsr". Other signals are caught | ||
| 59 | * just in case. | ||
| 60 | */ | ||
| 61 | signal(SIGILL, sighandler); | ||
| 62 | signal(SIGFPE, sighandler); | ||
| 63 | signal(SIGSEGV, sighandler); | ||
| 64 | |||
| 65 | printf("[RUN]\tTesting fcmovCC instructions\n"); | ||
| 66 | /* If fcmovCC() returns 1.0, the move wasn't done */ | ||
| 67 | err |= !(fcmovb(0) == 1.0); err |= !(fcmovnb(0) != 1.0); | ||
| 68 | err |= !(fcmove(0) == 1.0); err |= !(fcmovne(0) != 1.0); | ||
| 69 | err |= !(fcmovbe(0) == 1.0); err |= !(fcmovnbe(0) != 1.0); | ||
| 70 | err |= !(fcmovu(0) == 1.0); err |= !(fcmovnu(0) != 1.0); | ||
| 71 | |||
| 72 | err |= !(fcmovb(CF) != 1.0); err |= !(fcmovnb(CF) == 1.0); | ||
| 73 | err |= !(fcmove(CF) == 1.0); err |= !(fcmovne(CF) != 1.0); | ||
| 74 | err |= !(fcmovbe(CF) != 1.0); err |= !(fcmovnbe(CF) == 1.0); | ||
| 75 | err |= !(fcmovu(CF) == 1.0); err |= !(fcmovnu(CF) != 1.0); | ||
| 76 | |||
| 77 | err |= !(fcmovb(ZF) == 1.0); err |= !(fcmovnb(ZF) != 1.0); | ||
| 78 | err |= !(fcmove(ZF) != 1.0); err |= !(fcmovne(ZF) == 1.0); | ||
| 79 | err |= !(fcmovbe(ZF) != 1.0); err |= !(fcmovnbe(ZF) == 1.0); | ||
| 80 | err |= !(fcmovu(ZF) == 1.0); err |= !(fcmovnu(ZF) != 1.0); | ||
| 81 | |||
| 82 | err |= !(fcmovb(PF) == 1.0); err |= !(fcmovnb(PF) != 1.0); | ||
| 83 | err |= !(fcmove(PF) == 1.0); err |= !(fcmovne(PF) != 1.0); | ||
| 84 | err |= !(fcmovbe(PF) == 1.0); err |= !(fcmovnbe(PF) != 1.0); | ||
| 85 | err |= !(fcmovu(PF) != 1.0); err |= !(fcmovnu(PF) == 1.0); | ||
| 86 | |||
| 87 | if (!err) | ||
| 88 | printf("[OK]\tfcmovCC\n"); | ||
| 89 | else | ||
| 90 | printf("[FAIL]\tfcmovCC errors: %d\n", err); | ||
| 91 | |||
| 92 | return err; | ||
| 93 | } | ||
diff --git a/tools/testing/selftests/x86/test_FCOMI.c b/tools/testing/selftests/x86/test_FCOMI.c new file mode 100644 index 000000000000..db4933e31af9 --- /dev/null +++ b/tools/testing/selftests/x86/test_FCOMI.c | |||
| @@ -0,0 +1,331 @@ | |||
| 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 | } | ||
