1 // SPDX-License-Identifier: GPL-2.0
2 #undef _GNU_SOURCE
3 #define _GNU_SOURCE 1
4 #undef __USE_GNU
5 #define __USE_GNU 1
6 #include <unistd.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <stdio.h>
10 #include <signal.h>
11 #include <sys/types.h>
12 #include <sys/select.h>
13 #include <sys/time.h>
14 #include <sys/wait.h>
15 #include <fenv.h>
16
17 unsigned long long res64 = -1;
18 unsigned int res32 = -1;
19 unsigned short res16 = -1;
20
test(void)21 int test(void)
22 {
23 int ex;
24
25 feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
26 asm volatile ("\n"
27 " fld1""\n"
28 #ifdef __clang__
29 " fisttps res16""\n"
30 #else
31 " fisttp res16""\n"
32 #endif
33 " fld1""\n"
34 " fisttpl res32""\n"
35 " fld1""\n"
36 " fisttpll res64""\n"
37 : : : "memory"
38 );
39 if (res16 != 1 || res32 != 1 || res64 != 1) {
40 printf("[BAD]\tfisttp 1\n");
41 return 1;
42 }
43 ex = fetestexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
44 if (ex != 0) {
45 printf("[BAD]\tfisttp 1: wrong exception state\n");
46 return 1;
47 }
48
49 feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
50 asm volatile ("\n"
51 " fldpi""\n"
52 #ifdef __clang__
53 " fisttps res16""\n"
54 #else
55 " fisttp res16""\n"
56 #endif
57 " fldpi""\n"
58 " fisttpl res32""\n"
59 " fldpi""\n"
60 " fisttpll res64""\n"
61 : : : "memory"
62 );
63 if (res16 != 3 || res32 != 3 || res64 != 3) {
64 printf("[BAD]\tfisttp pi\n");
65 return 1;
66 }
67 ex = fetestexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
68 if (ex != FE_INEXACT) {
69 printf("[BAD]\tfisttp pi: wrong exception state\n");
70 return 1;
71 }
72
73 feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
74 asm volatile ("\n"
75 " fldpi""\n"
76 " fchs""\n"
77 #ifdef __clang__
78 " fisttps res16""\n"
79 #else
80 // clang will complain: ambiguous instructions require an explicit suffix
81 // (could be 'fisttps', or 'fisttpl')
82 " fisttp res16""\n"
83 #endif
84 " fldpi""\n"
85 " fchs""\n"
86 " fisttpl res32""\n"
87 " fldpi""\n"
88 " fchs""\n"
89 " fisttpll res64""\n"
90 : : : "memory"
91 );
92 if (res16 != 0xfffd || res32 != 0xfffffffd || res64 != 0xfffffffffffffffdULL) {
93 printf("[BAD]\tfisttp -pi\n");
94 return 1;
95 }
96 ex = fetestexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
97 if (ex != FE_INEXACT) {
98 printf("[BAD]\tfisttp -pi: wrong exception state\n");
99 return 1;
100 }
101
102 feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
103 asm volatile ("\n"
104 " fldln2""\n"
105 #ifdef __clang__
106 " fisttps res16""\n"
107 #else
108 " fisttp res16""\n"
109 #endif
110 " fldln2""\n"
111 " fisttpl res32""\n"
112 " fldln2""\n"
113 " fisttpll res64""\n"
114 : : : "memory"
115 );
116 /* Test truncation to zero (round-to-nearest would give 1 here) */
117 if (res16 != 0 || res32 != 0 || res64 != 0) {
118 printf("[BAD]\tfisttp ln2\n");
119 return 1;
120 }
121 ex = fetestexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
122 if (ex != FE_INEXACT) {
123 printf("[BAD]\tfisttp ln2: wrong exception state\n");
124 return 1;
125 }
126
127 return 0;
128 }
129
sighandler(int sig)130 void sighandler(int sig)
131 {
132 printf("[FAIL]\tGot signal %d, exiting\n", sig);
133 exit(1);
134 }
135
main(int argc,char ** argv,char ** envp)136 int main(int argc, char **argv, char **envp)
137 {
138 int err = 0;
139
140 /* SIGILL triggers on 32-bit kernels w/o fisttp emulation
141 * when run with "no387 nofxsr". Other signals are caught
142 * just in case.
143 */
144 signal(SIGILL, sighandler);
145 signal(SIGFPE, sighandler);
146 signal(SIGSEGV, sighandler);
147
148 printf("[RUN]\tTesting fisttp instructions\n");
149 err |= test();
150 if (!err)
151 printf("[OK]\tfisttp\n");
152 else
153 printf("[FAIL]\tfisttp errors: %d\n", err);
154
155 return err;
156 }
157