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