xref: /linux/tools/testing/selftests/x86/test_FISTTP.c (revision 5a4332062e9e71de8e78dc1b389d21e0dd44848b)
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 
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 	"	fisttps	res16""\n"
29 	"	fld1""\n"
30 	"	fisttpl	res32""\n"
31 	"	fld1""\n"
32 	"	fisttpll res64""\n"
33 	: : : "memory"
34 	);
35 	if (res16 != 1 || res32 != 1 || res64 != 1) {
36 		printf("[BAD]\tfisttp 1\n");
37 		return 1;
38 	}
39 	ex = fetestexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
40 	if (ex != 0) {
41 		printf("[BAD]\tfisttp 1: wrong exception state\n");
42 		return 1;
43 	}
44 
45 	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
46 	asm volatile ("\n"
47 	"	fldpi""\n"
48 	"	fisttps	res16""\n"
49 	"	fldpi""\n"
50 	"	fisttpl	res32""\n"
51 	"	fldpi""\n"
52 	"	fisttpll res64""\n"
53 	: : : "memory"
54 	);
55 	if (res16 != 3 || res32 != 3 || res64 != 3) {
56 		printf("[BAD]\tfisttp pi\n");
57 		return 1;
58 	}
59 	ex = fetestexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
60 	if (ex != FE_INEXACT) {
61 		printf("[BAD]\tfisttp pi: wrong exception state\n");
62 		return 1;
63 	}
64 
65 	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
66 	asm volatile ("\n"
67 	"	fldpi""\n"
68 	"	fchs""\n"
69 	"	fisttps	res16""\n"
70 	"	fldpi""\n"
71 	"	fchs""\n"
72 	"	fisttpl	res32""\n"
73 	"	fldpi""\n"
74 	"	fchs""\n"
75 	"	fisttpll res64""\n"
76 	: : : "memory"
77 	);
78 	if (res16 != 0xfffd || res32 != 0xfffffffd || res64 != 0xfffffffffffffffdULL) {
79 		printf("[BAD]\tfisttp -pi\n");
80 		return 1;
81 	}
82 	ex = fetestexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
83 	if (ex != FE_INEXACT) {
84 		printf("[BAD]\tfisttp -pi: wrong exception state\n");
85 		return 1;
86 	}
87 
88 	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
89 	asm volatile ("\n"
90 	"	fldln2""\n"
91 	"	fisttps	res16""\n"
92 	"	fldln2""\n"
93 	"	fisttpl	res32""\n"
94 	"	fldln2""\n"
95 	"	fisttpll res64""\n"
96 	: : : "memory"
97 	);
98 	/* Test truncation to zero (round-to-nearest would give 1 here) */
99 	if (res16 != 0 || res32 != 0 || res64 != 0) {
100 		printf("[BAD]\tfisttp ln2\n");
101 		return 1;
102 	}
103 	ex = fetestexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
104 	if (ex != FE_INEXACT) {
105 		printf("[BAD]\tfisttp ln2: wrong exception state\n");
106 		return 1;
107 	}
108 
109 	return 0;
110 }
111 
112 void sighandler(int sig)
113 {
114 	printf("[FAIL]\tGot signal %d, exiting\n", sig);
115 	exit(1);
116 }
117 
118 int main(int argc, char **argv, char **envp)
119 {
120 	int err = 0;
121 
122 	/* SIGILL triggers on 32-bit kernels w/o fisttp emulation
123 	 * when run with "no387 nofxsr". Other signals are caught
124 	 * just in case.
125 	 */
126 	signal(SIGILL, sighandler);
127 	signal(SIGFPE, sighandler);
128 	signal(SIGSEGV, sighandler);
129 
130 	printf("[RUN]\tTesting fisttp instructions\n");
131 	err |= test();
132 	if (!err)
133 		printf("[OK]\tfisttp\n");
134 	else
135 		printf("[FAIL]\tfisttp errors: %d\n", err);
136 
137 	return err;
138 }
139