| // SPDX-License-Identifier: GPL-2.0 | |
| #undef _GNU_SOURCE | |
| #define _GNU_SOURCE 1 | |
| #undef __USE_GNU | |
| #define __USE_GNU 1 | |
| #include <unistd.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <stdio.h> | |
| #include <signal.h> | |
| #include <sys/types.h> | |
| #include <sys/select.h> | |
| #include <sys/time.h> | |
| #include <sys/wait.h> | |
| #include <fenv.h> | |
| unsigned long long res64 = -1; | |
| unsigned int res32 = -1; | |
| unsigned short res16 = -1; | |
| int test(void) | |
| { | |
| int ex; | |
| feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW); | |
| asm volatile ("\n" | |
| " fld1""\n" | |
| " fisttp res16""\n" | |
| " fld1""\n" | |
| " fisttpl res32""\n" | |
| " fld1""\n" | |
| " fisttpll res64""\n" | |
| : : : "memory" | |
| ); | |
| if (res16 != 1 || res32 != 1 || res64 != 1) { | |
| printf("[BAD]\tfisttp 1\n"); | |
| return 1; | |
| } | |
| ex = fetestexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW); | |
| if (ex != 0) { | |
| printf("[BAD]\tfisttp 1: wrong exception state\n"); | |
| return 1; | |
| } | |
| feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW); | |
| asm volatile ("\n" | |
| " fldpi""\n" | |
| " fisttp res16""\n" | |
| " fldpi""\n" | |
| " fisttpl res32""\n" | |
| " fldpi""\n" | |
| " fisttpll res64""\n" | |
| : : : "memory" | |
| ); | |
| if (res16 != 3 || res32 != 3 || res64 != 3) { | |
| printf("[BAD]\tfisttp pi\n"); | |
| return 1; | |
| } | |
| ex = fetestexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW); | |
| if (ex != FE_INEXACT) { | |
| printf("[BAD]\tfisttp pi: wrong exception state\n"); | |
| return 1; | |
| } | |
| feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW); | |
| asm volatile ("\n" | |
| " fldpi""\n" | |
| " fchs""\n" | |
| " fisttp res16""\n" | |
| " fldpi""\n" | |
| " fchs""\n" | |
| " fisttpl res32""\n" | |
| " fldpi""\n" | |
| " fchs""\n" | |
| " fisttpll res64""\n" | |
| : : : "memory" | |
| ); | |
| if (res16 != 0xfffd || res32 != 0xfffffffd || res64 != 0xfffffffffffffffdULL) { | |
| printf("[BAD]\tfisttp -pi\n"); | |
| return 1; | |
| } | |
| ex = fetestexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW); | |
| if (ex != FE_INEXACT) { | |
| printf("[BAD]\tfisttp -pi: wrong exception state\n"); | |
| return 1; | |
| } | |
| feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW); | |
| asm volatile ("\n" | |
| " fldln2""\n" | |
| " fisttp res16""\n" | |
| " fldln2""\n" | |
| " fisttpl res32""\n" | |
| " fldln2""\n" | |
| " fisttpll res64""\n" | |
| : : : "memory" | |
| ); | |
| /* Test truncation to zero (round-to-nearest would give 1 here) */ | |
| if (res16 != 0 || res32 != 0 || res64 != 0) { | |
| printf("[BAD]\tfisttp ln2\n"); | |
| return 1; | |
| } | |
| ex = fetestexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW); | |
| if (ex != FE_INEXACT) { | |
| printf("[BAD]\tfisttp ln2: wrong exception state\n"); | |
| return 1; | |
| } | |
| return 0; | |
| } | |
| void sighandler(int sig) | |
| { | |
| printf("[FAIL]\tGot signal %d, exiting\n", sig); | |
| exit(1); | |
| } | |
| int main(int argc, char **argv, char **envp) | |
| { | |
| int err = 0; | |
| /* SIGILL triggers on 32-bit kernels w/o fisttp emulation | |
| * when run with "no387 nofxsr". Other signals are caught | |
| * just in case. | |
| */ | |
| signal(SIGILL, sighandler); | |
| signal(SIGFPE, sighandler); | |
| signal(SIGSEGV, sighandler); | |
| printf("[RUN]\tTesting fisttp instructions\n"); | |
| err |= test(); | |
| if (!err) | |
| printf("[OK]\tfisttp\n"); | |
| else | |
| printf("[FAIL]\tfisttp errors: %d\n", err); | |
| return err; | |
| } |