brintos

brintos / linux-shallow public Read only

0
0
Text · 7.2 KiB · aec6692 Raw
333 lines · c
1// SPDX-License-Identifier: GPL-2.02#undef _GNU_SOURCE3#define _GNU_SOURCE 14#undef __USE_GNU5#define __USE_GNU 16#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 17enum {18	CF = 1 << 0,19	PF = 1 << 2,20	ZF = 1 << 6,21	ARITH = CF | PF | ZF,22};23 24long res_fcomi_pi_1;25long res_fcomi_1_pi;26long res_fcomi_1_1;27long res_fcomi_nan_1;28/* sNaN is s|111 1111 1|1xx xxxx xxxx xxxx xxxx xxxx */29/* qNaN is s|111 1111 1|0xx xxxx xxxx xxxx xxxx xxxx (some x must be nonzero) */30int snan = 0x7fc11111;31int qnan = 0x7f811111;32unsigned short snan1[5];33/* sNaN80 is s|111 1111 1111 1111 |10xx xx...xx (some x must be nonzero) */34unsigned short snan80[5] = { 0x1111, 0x1111, 0x1111, 0x8111, 0x7fff };35 36int test(long flags)37{38	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);39 40	asm ("\n"41 42	"	push	%0""\n"43	"	popf""\n"44	"	fld1""\n"45	"	fldpi""\n"46	"	fcomi	%%st(1), %%st" "\n"47	"	ffree	%%st(0)" "\n"48	"	ffree	%%st(1)" "\n"49	"	pushf""\n"50	"	pop	res_fcomi_1_pi""\n"51 52	"	push	%0""\n"53	"	popf""\n"54	"	fldpi""\n"55	"	fld1""\n"56	"	fcomi	%%st(1), %%st" "\n"57	"	ffree	%%st(0)" "\n"58	"	ffree	%%st(1)" "\n"59	"	pushf""\n"60	"	pop	res_fcomi_pi_1""\n"61 62	"	push	%0""\n"63	"	popf""\n"64	"	fld1""\n"65	"	fld1""\n"66	"	fcomi	%%st(1), %%st" "\n"67	"	ffree	%%st(0)" "\n"68	"	ffree	%%st(1)" "\n"69	"	pushf""\n"70	"	pop	res_fcomi_1_1""\n"71	:72	: "r" (flags)73	);74	if ((res_fcomi_1_pi & ARITH) != (0)) {75		printf("[BAD]\tfcomi_1_pi with flags:%lx\n", flags);76		return 1;77	}78	if ((res_fcomi_pi_1 & ARITH) != (CF)) {79		printf("[BAD]\tfcomi_pi_1 with flags:%lx->%lx\n", flags, res_fcomi_pi_1 & ARITH);80		return 1;81	}82	if ((res_fcomi_1_1 & ARITH) != (ZF)) {83		printf("[BAD]\tfcomi_1_1 with flags:%lx\n", flags);84		return 1;85	}86	if (fetestexcept(FE_INVALID) != 0) {87		printf("[BAD]\tFE_INVALID is set in %s\n", __func__);88		return 1;89	}90	return 0;91}92 93int test_qnan(long flags)94{95	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);96 97	asm ("\n"98	"	push	%0""\n"99	"	popf""\n"100	"	flds	qnan""\n"101	"	fld1""\n"102	"	fnclex""\n"		// fld of a qnan raised FE_INVALID, clear it103	"	fcomi	%%st(1), %%st" "\n"104	"	ffree	%%st(0)" "\n"105	"	ffree	%%st(1)" "\n"106	"	pushf""\n"107	"	pop	res_fcomi_nan_1""\n"108	:109	: "r" (flags)110	);111	if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {112		printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);113		return 1;114	}115	if (fetestexcept(FE_INVALID) != FE_INVALID) {116		printf("[BAD]\tFE_INVALID is not set in %s\n", __func__);117		return 1;118	}119	return 0;120}121 122int testu_qnan(long flags)123{124	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);125 126	asm ("\n"127	"	push	%0""\n"128	"	popf""\n"129	"	flds	qnan""\n"130	"	fld1""\n"131	"	fnclex""\n"		// fld of a qnan raised FE_INVALID, clear it132	"	fucomi	%%st(1), %%st" "\n"133	"	ffree	%%st(0)" "\n"134	"	ffree	%%st(1)" "\n"135	"	pushf""\n"136	"	pop	res_fcomi_nan_1""\n"137	:138	: "r" (flags)139	);140	if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {141		printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);142		return 1;143	}144	if (fetestexcept(FE_INVALID) != 0) {145		printf("[BAD]\tFE_INVALID is set in %s\n", __func__);146		return 1;147	}148	return 0;149}150 151int testu_snan(long flags)152{153	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);154 155	asm ("\n"156	"	push	%0""\n"157	"	popf""\n"158//	"	flds	snan""\n"	// WRONG, this will convert 32-bit fp snan to a *qnan* in 80-bit fp register!159//	"	fstpt	snan1""\n"	// if uncommented, it prints "snan1:7fff c111 1100 0000 0000" - c111, not 8111!160//	"	fnclex""\n"		// flds of a snan raised FE_INVALID, clear it161	"	fldt	snan80""\n"	// fldt never raise FE_INVALID162	"	fld1""\n"163	"	fucomi	%%st(1), %%st" "\n"164	"	ffree	%%st(0)" "\n"165	"	ffree	%%st(1)" "\n"166	"	pushf""\n"167	"	pop	res_fcomi_nan_1""\n"168	:169	: "r" (flags)170	);171	if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {172		printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);173		return 1;174	}175//	printf("snan:%x snan1:%04x %04x %04x %04x %04x\n", snan, snan1[4], snan1[3], snan1[2], snan1[1], snan1[0]);176	if (fetestexcept(FE_INVALID) != FE_INVALID) {177		printf("[BAD]\tFE_INVALID is not set in %s\n", __func__);178		return 1;179	}180	return 0;181}182 183int testp(long flags)184{185	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);186 187	asm ("\n"188 189	"	push	%0""\n"190	"	popf""\n"191	"	fld1""\n"192	"	fldpi""\n"193	"	fcomip	%%st(1), %%st" "\n"194	"	ffree	%%st(0)" "\n"195	"	pushf""\n"196	"	pop	res_fcomi_1_pi""\n"197 198	"	push	%0""\n"199	"	popf""\n"200	"	fldpi""\n"201	"	fld1""\n"202	"	fcomip	%%st(1), %%st" "\n"203	"	ffree	%%st(0)" "\n"204	"	pushf""\n"205	"	pop	res_fcomi_pi_1""\n"206 207	"	push	%0""\n"208	"	popf""\n"209	"	fld1""\n"210	"	fld1""\n"211	"	fcomip	%%st(1), %%st" "\n"212	"	ffree	%%st(0)" "\n"213	"	pushf""\n"214	"	pop	res_fcomi_1_1""\n"215	:216	: "r" (flags)217	);218	if ((res_fcomi_1_pi & ARITH) != (0)) {219		printf("[BAD]\tfcomi_1_pi with flags:%lx\n", flags);220		return 1;221	}222	if ((res_fcomi_pi_1 & ARITH) != (CF)) {223		printf("[BAD]\tfcomi_pi_1 with flags:%lx->%lx\n", flags, res_fcomi_pi_1 & ARITH);224		return 1;225	}226	if ((res_fcomi_1_1 & ARITH) != (ZF)) {227		printf("[BAD]\tfcomi_1_1 with flags:%lx\n", flags);228		return 1;229	}230	if (fetestexcept(FE_INVALID) != 0) {231		printf("[BAD]\tFE_INVALID is set in %s\n", __func__);232		return 1;233	}234	return 0;235}236 237int testp_qnan(long flags)238{239	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);240 241	asm ("\n"242	"	push	%0""\n"243	"	popf""\n"244	"	flds	qnan""\n"245	"	fld1""\n"246	"	fnclex""\n"		// fld of a qnan raised FE_INVALID, clear it247	"	fcomip	%%st(1), %%st" "\n"248	"	ffree	%%st(0)" "\n"249	"	pushf""\n"250	"	pop	res_fcomi_nan_1""\n"251	:252	: "r" (flags)253	);254	if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {255		printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);256		return 1;257	}258	if (fetestexcept(FE_INVALID) != FE_INVALID) {259		printf("[BAD]\tFE_INVALID is not set in %s\n", __func__);260		return 1;261	}262	return 0;263}264 265int testup_qnan(long flags)266{267	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);268 269	asm ("\n"270	"	push	%0""\n"271	"	popf""\n"272	"	flds	qnan""\n"273	"	fld1""\n"274	"	fnclex""\n"		// fld of a qnan raised FE_INVALID, clear it275	"	fucomip	%%st(1), %%st" "\n"276	"	ffree	%%st(0)" "\n"277	"	pushf""\n"278	"	pop	res_fcomi_nan_1""\n"279	:280	: "r" (flags)281	);282	if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {283		printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);284		return 1;285	}286	if (fetestexcept(FE_INVALID) != 0) {287		printf("[BAD]\tFE_INVALID is set in %s\n", __func__);288		return 1;289	}290	return 0;291}292 293void sighandler(int sig)294{295	printf("[FAIL]\tGot signal %d, exiting\n", sig);296	exit(1);297}298 299int main(int argc, char **argv, char **envp)300{301	int err = 0;302 303	/* SIGILL triggers on 32-bit kernels w/o fcomi emulation304	 * when run with "no387 nofxsr". Other signals are caught305	 * just in case.306	 */307	signal(SIGILL, sighandler);308	signal(SIGFPE, sighandler);309	signal(SIGSEGV, sighandler);310 311	printf("[RUN]\tTesting f[u]comi[p] instructions\n");312	err |= test(0);313	err |= test_qnan(0);314	err |= testu_qnan(0);315	err |= testu_snan(0);316	err |= test(CF|ZF|PF);317	err |= test_qnan(CF|ZF|PF);318	err |= testu_qnan(CF|ZF|PF);319	err |= testu_snan(CF|ZF|PF);320	err |= testp(0);321	err |= testp_qnan(0);322	err |= testup_qnan(0);323	err |= testp(CF|ZF|PF);324	err |= testp_qnan(CF|ZF|PF);325	err |= testup_qnan(CF|ZF|PF);326	if (!err)327		printf("[OK]\tf[u]comi[p]\n");328	else329		printf("[FAIL]\tf[u]comi[p] errors: %d\n", err);330 331	return err;332}333