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
17unsigned long long res64 = -1;
18unsigned int res32 = -1;
19unsigned short res16 = -1;
20
21int 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	"	fisttp	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	"	fisttp	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	"	fisttp	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	"	fisttp	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
112void sighandler(int sig)
113{
114	printf("[FAIL]\tGot signal %d, exiting\n", sig);
115	exit(1);
116}
117
118int 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