xref: /freebsd-src/contrib/netbsd-tests/lib/libc/gen/t_fpsetmask.c (revision 57718be8fa0bd5edc11ab9a72e68cc71982939a6)
1*57718be8SEnji Cooper /*	$NetBSD: t_fpsetmask.c,v 1.13 2014/02/09 21:26:07 jmmv Exp $ */
2*57718be8SEnji Cooper 
3*57718be8SEnji Cooper /*-
4*57718be8SEnji Cooper  * Copyright (c) 1995 The NetBSD Foundation, Inc.
5*57718be8SEnji Cooper  * All rights reserved.
6*57718be8SEnji Cooper  *
7*57718be8SEnji Cooper  * Redistribution and use in source and binary forms, with or without
8*57718be8SEnji Cooper  * modification, are permitted provided that the following conditions
9*57718be8SEnji Cooper  * are met:
10*57718be8SEnji Cooper  * 1. Redistributions of source code must retain the above copyright
11*57718be8SEnji Cooper  *    notice, this list of conditions and the following disclaimer.
12*57718be8SEnji Cooper  * 2. Redistributions in binary form must reproduce the above copyright
13*57718be8SEnji Cooper  *    notice, this list of conditions and the following disclaimer in the
14*57718be8SEnji Cooper  *    documentation and/or other materials provided with the distribution.
15*57718be8SEnji Cooper  *
16*57718be8SEnji Cooper  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17*57718be8SEnji Cooper  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18*57718be8SEnji Cooper  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19*57718be8SEnji Cooper  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20*57718be8SEnji Cooper  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21*57718be8SEnji Cooper  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22*57718be8SEnji Cooper  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23*57718be8SEnji Cooper  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24*57718be8SEnji Cooper  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25*57718be8SEnji Cooper  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26*57718be8SEnji Cooper  * POSSIBILITY OF SUCH DAMAGE.
27*57718be8SEnji Cooper  */
28*57718be8SEnji Cooper 
29*57718be8SEnji Cooper #include <sys/param.h>
30*57718be8SEnji Cooper 
31*57718be8SEnji Cooper #include <atf-c.h>
32*57718be8SEnji Cooper #include <atf-c/config.h>
33*57718be8SEnji Cooper 
34*57718be8SEnji Cooper #include <stdio.h>
35*57718be8SEnji Cooper #include <signal.h>
36*57718be8SEnji Cooper #include <float.h>
37*57718be8SEnji Cooper #include <setjmp.h>
38*57718be8SEnji Cooper #include <stdlib.h>
39*57718be8SEnji Cooper #include <string.h>
40*57718be8SEnji Cooper 
41*57718be8SEnji Cooper #include "isqemu.h"
42*57718be8SEnji Cooper 
43*57718be8SEnji Cooper #ifndef _FLOAT_IEEE754
44*57718be8SEnji Cooper 
45*57718be8SEnji Cooper ATF_TC(no_test);
46*57718be8SEnji Cooper ATF_TC_HEAD(no_test, tc)
47*57718be8SEnji Cooper {
48*57718be8SEnji Cooper 
49*57718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Dummy test case");
50*57718be8SEnji Cooper }
51*57718be8SEnji Cooper 
52*57718be8SEnji Cooper ATF_TC_BODY(no_test, tc)
53*57718be8SEnji Cooper {
54*57718be8SEnji Cooper 
55*57718be8SEnji Cooper 	atf_tc_skip("Test not available on this architecture.");
56*57718be8SEnji Cooper }
57*57718be8SEnji Cooper 
58*57718be8SEnji Cooper #else /* defined(_FLOAT_IEEE754) */
59*57718be8SEnji Cooper 
60*57718be8SEnji Cooper #include <ieeefp.h>
61*57718be8SEnji Cooper 
62*57718be8SEnji Cooper const char *skip_mesg;
63*57718be8SEnji Cooper const char *skip_arch;
64*57718be8SEnji Cooper 
65*57718be8SEnji Cooper void		sigfpe(int, siginfo_t *, void *);
66*57718be8SEnji Cooper 
67*57718be8SEnji Cooper volatile sig_atomic_t signal_caught;
68*57718be8SEnji Cooper volatile int sicode;
69*57718be8SEnji Cooper 
70*57718be8SEnji Cooper static volatile const float	f_one   = 1.0;
71*57718be8SEnji Cooper static volatile const float	f_zero  = 0.0;
72*57718be8SEnji Cooper static volatile const double	d_one   = 1.0;
73*57718be8SEnji Cooper static volatile const double	d_zero  = 0.0;
74*57718be8SEnji Cooper static volatile const long double ld_one  = 1.0;
75*57718be8SEnji Cooper static volatile const long double ld_zero = 0.0;
76*57718be8SEnji Cooper 
77*57718be8SEnji Cooper static volatile const float	f_huge = FLT_MAX;
78*57718be8SEnji Cooper static volatile const float	f_tiny = FLT_MIN;
79*57718be8SEnji Cooper static volatile const double	d_huge = DBL_MAX;
80*57718be8SEnji Cooper static volatile const double	d_tiny = DBL_MIN;
81*57718be8SEnji Cooper static volatile const long double ld_huge = LDBL_MAX;
82*57718be8SEnji Cooper static volatile const long double ld_tiny = LDBL_MIN;
83*57718be8SEnji Cooper 
84*57718be8SEnji Cooper static volatile float f_x;
85*57718be8SEnji Cooper static volatile double d_x;
86*57718be8SEnji Cooper static volatile long double ld_x;
87*57718be8SEnji Cooper 
88*57718be8SEnji Cooper /* trip divide by zero */
89*57718be8SEnji Cooper static void
90*57718be8SEnji Cooper f_dz(void)
91*57718be8SEnji Cooper {
92*57718be8SEnji Cooper 
93*57718be8SEnji Cooper 	f_x = f_one / f_zero;
94*57718be8SEnji Cooper }
95*57718be8SEnji Cooper 
96*57718be8SEnji Cooper static void
97*57718be8SEnji Cooper d_dz(void)
98*57718be8SEnji Cooper {
99*57718be8SEnji Cooper 
100*57718be8SEnji Cooper 	d_x = d_one / d_zero;
101*57718be8SEnji Cooper }
102*57718be8SEnji Cooper 
103*57718be8SEnji Cooper static void
104*57718be8SEnji Cooper ld_dz(void)
105*57718be8SEnji Cooper {
106*57718be8SEnji Cooper 
107*57718be8SEnji Cooper 	ld_x = ld_one / ld_zero;
108*57718be8SEnji Cooper }
109*57718be8SEnji Cooper 
110*57718be8SEnji Cooper /* trip invalid operation */
111*57718be8SEnji Cooper static void
112*57718be8SEnji Cooper d_inv(void)
113*57718be8SEnji Cooper {
114*57718be8SEnji Cooper 
115*57718be8SEnji Cooper 	d_x = d_zero / d_zero;
116*57718be8SEnji Cooper }
117*57718be8SEnji Cooper 
118*57718be8SEnji Cooper static void
119*57718be8SEnji Cooper ld_inv(void)
120*57718be8SEnji Cooper {
121*57718be8SEnji Cooper 
122*57718be8SEnji Cooper 	ld_x = ld_zero / ld_zero;
123*57718be8SEnji Cooper }
124*57718be8SEnji Cooper 
125*57718be8SEnji Cooper static void
126*57718be8SEnji Cooper f_inv(void)
127*57718be8SEnji Cooper {
128*57718be8SEnji Cooper 
129*57718be8SEnji Cooper 	f_x = f_zero / f_zero;
130*57718be8SEnji Cooper }
131*57718be8SEnji Cooper 
132*57718be8SEnji Cooper /* trip overflow */
133*57718be8SEnji Cooper static void
134*57718be8SEnji Cooper f_ofl(void)
135*57718be8SEnji Cooper {
136*57718be8SEnji Cooper 
137*57718be8SEnji Cooper 	f_x = f_huge * f_huge;
138*57718be8SEnji Cooper }
139*57718be8SEnji Cooper 
140*57718be8SEnji Cooper static void
141*57718be8SEnji Cooper d_ofl(void)
142*57718be8SEnji Cooper {
143*57718be8SEnji Cooper 
144*57718be8SEnji Cooper 	d_x = d_huge * d_huge;
145*57718be8SEnji Cooper }
146*57718be8SEnji Cooper 
147*57718be8SEnji Cooper static void
148*57718be8SEnji Cooper ld_ofl(void)
149*57718be8SEnji Cooper {
150*57718be8SEnji Cooper 
151*57718be8SEnji Cooper 	ld_x = ld_huge * ld_huge;
152*57718be8SEnji Cooper }
153*57718be8SEnji Cooper 
154*57718be8SEnji Cooper /* trip underflow */
155*57718be8SEnji Cooper static void
156*57718be8SEnji Cooper f_ufl(void)
157*57718be8SEnji Cooper {
158*57718be8SEnji Cooper 
159*57718be8SEnji Cooper 	f_x = f_tiny * f_tiny;
160*57718be8SEnji Cooper }
161*57718be8SEnji Cooper 
162*57718be8SEnji Cooper static void
163*57718be8SEnji Cooper d_ufl(void)
164*57718be8SEnji Cooper {
165*57718be8SEnji Cooper 
166*57718be8SEnji Cooper 	d_x = d_tiny * d_tiny;
167*57718be8SEnji Cooper }
168*57718be8SEnji Cooper 
169*57718be8SEnji Cooper static void
170*57718be8SEnji Cooper ld_ufl(void)
171*57718be8SEnji Cooper {
172*57718be8SEnji Cooper 
173*57718be8SEnji Cooper 	ld_x = ld_tiny * ld_tiny;
174*57718be8SEnji Cooper }
175*57718be8SEnji Cooper 
176*57718be8SEnji Cooper struct ops {
177*57718be8SEnji Cooper 	void (*op)(void);
178*57718be8SEnji Cooper 	fp_except mask;
179*57718be8SEnji Cooper 	int sicode;
180*57718be8SEnji Cooper };
181*57718be8SEnji Cooper 
182*57718be8SEnji Cooper static const struct ops float_ops[] = {
183*57718be8SEnji Cooper 	{ f_dz, FP_X_DZ, FPE_FLTDIV },
184*57718be8SEnji Cooper 	{ f_inv, FP_X_INV, FPE_FLTINV },
185*57718be8SEnji Cooper 	{ f_ofl, FP_X_OFL, FPE_FLTOVF },
186*57718be8SEnji Cooper 	{ f_ufl, FP_X_UFL, FPE_FLTUND },
187*57718be8SEnji Cooper 	{ NULL, 0, 0 }
188*57718be8SEnji Cooper };
189*57718be8SEnji Cooper 
190*57718be8SEnji Cooper static const struct ops double_ops[] = {
191*57718be8SEnji Cooper 	{ d_dz, FP_X_DZ, FPE_FLTDIV },
192*57718be8SEnji Cooper 	{ d_inv, FP_X_INV, FPE_FLTINV },
193*57718be8SEnji Cooper 	{ d_ofl, FP_X_OFL, FPE_FLTOVF },
194*57718be8SEnji Cooper 	{ d_ufl, FP_X_UFL, FPE_FLTUND },
195*57718be8SEnji Cooper 	{ NULL, 0, 0 }
196*57718be8SEnji Cooper };
197*57718be8SEnji Cooper 
198*57718be8SEnji Cooper static const struct ops long_double_ops[] = {
199*57718be8SEnji Cooper 	{ ld_dz, FP_X_DZ, FPE_FLTDIV },
200*57718be8SEnji Cooper 	{ ld_inv, FP_X_INV, FPE_FLTINV },
201*57718be8SEnji Cooper 	{ ld_ofl, FP_X_OFL, FPE_FLTOVF },
202*57718be8SEnji Cooper 	{ ld_ufl, FP_X_UFL, FPE_FLTUND },
203*57718be8SEnji Cooper 	{ NULL, 0, 0 }
204*57718be8SEnji Cooper };
205*57718be8SEnji Cooper 
206*57718be8SEnji Cooper static sigjmp_buf b;
207*57718be8SEnji Cooper 
208*57718be8SEnji Cooper static void
209*57718be8SEnji Cooper fpsetmask_masked(const struct ops *test_ops)
210*57718be8SEnji Cooper {
211*57718be8SEnji Cooper 	struct sigaction sa;
212*57718be8SEnji Cooper 	fp_except ex1, ex2;
213*57718be8SEnji Cooper 	const struct ops *t;
214*57718be8SEnji Cooper 
215*57718be8SEnji Cooper 	/* mask all exceptions, clear history */
216*57718be8SEnji Cooper 	fpsetmask(0);
217*57718be8SEnji Cooper 	fpsetsticky(0);
218*57718be8SEnji Cooper 
219*57718be8SEnji Cooper 	/* set up signal handler */
220*57718be8SEnji Cooper 	sa.sa_sigaction = sigfpe;
221*57718be8SEnji Cooper 	sigemptyset(&sa.sa_mask);
222*57718be8SEnji Cooper 	sa.sa_flags = SA_SIGINFO;
223*57718be8SEnji Cooper 	sigaction(SIGFPE, &sa, 0);
224*57718be8SEnji Cooper 	signal_caught = 0;
225*57718be8SEnji Cooper 
226*57718be8SEnji Cooper 	/*
227*57718be8SEnji Cooper 	 * exceptions masked, check whether "sticky" bits are set correctly
228*57718be8SEnji Cooper 	 */
229*57718be8SEnji Cooper 	for (t = test_ops; t->op != NULL; t++) {
230*57718be8SEnji Cooper 		(*t->op)();
231*57718be8SEnji Cooper 		ex1 = fpgetsticky();
232*57718be8SEnji Cooper 		ATF_CHECK_EQ(ex1 & t->mask, t->mask);
233*57718be8SEnji Cooper 		ATF_CHECK_EQ(signal_caught, 0);
234*57718be8SEnji Cooper 
235*57718be8SEnji Cooper 		/* check correct fpsetsticky() behaviour */
236*57718be8SEnji Cooper 		ex2 = fpsetsticky(0);
237*57718be8SEnji Cooper 		ATF_CHECK_EQ(fpgetsticky(), 0);
238*57718be8SEnji Cooper 		ATF_CHECK_EQ(ex1, ex2);
239*57718be8SEnji Cooper 	}
240*57718be8SEnji Cooper }
241*57718be8SEnji Cooper 
242*57718be8SEnji Cooper /* force delayed exceptions to be delivered */
243*57718be8SEnji Cooper #define BARRIER() fpsetmask(0); f_x = f_one * f_one
244*57718be8SEnji Cooper 
245*57718be8SEnji Cooper static void
246*57718be8SEnji Cooper fpsetmask_unmasked(const struct ops *test_ops)
247*57718be8SEnji Cooper {
248*57718be8SEnji Cooper 	struct sigaction sa;
249*57718be8SEnji Cooper 	int r;
250*57718be8SEnji Cooper 	const struct ops *volatile t;
251*57718be8SEnji Cooper 
252*57718be8SEnji Cooper 	/* mask all exceptions, clear history */
253*57718be8SEnji Cooper 	fpsetmask(0);
254*57718be8SEnji Cooper 	fpsetsticky(0);
255*57718be8SEnji Cooper 
256*57718be8SEnji Cooper 	/* set up signal handler */
257*57718be8SEnji Cooper 	sa.sa_sigaction = sigfpe;
258*57718be8SEnji Cooper 	sigemptyset(&sa.sa_mask);
259*57718be8SEnji Cooper 	sa.sa_flags = SA_SIGINFO;
260*57718be8SEnji Cooper 	sigaction(SIGFPE, &sa, 0);
261*57718be8SEnji Cooper 	signal_caught = 0;
262*57718be8SEnji Cooper 
263*57718be8SEnji Cooper 	/*
264*57718be8SEnji Cooper 	 * exception unmasked, check SIGFPE delivery and correct siginfo
265*57718be8SEnji Cooper 	 */
266*57718be8SEnji Cooper 	for (t = test_ops; t->op != NULL; t++) {
267*57718be8SEnji Cooper 		fpsetmask(t->mask);
268*57718be8SEnji Cooper 		r = sigsetjmp(b, 1);
269*57718be8SEnji Cooper 		if (!r) {
270*57718be8SEnji Cooper 			(*t->op)();
271*57718be8SEnji Cooper 			BARRIER();
272*57718be8SEnji Cooper 		}
273*57718be8SEnji Cooper 		ATF_CHECK_EQ(signal_caught, 1);
274*57718be8SEnji Cooper 		ATF_CHECK_EQ(sicode, t->sicode);
275*57718be8SEnji Cooper 		signal_caught = 0;
276*57718be8SEnji Cooper 	}
277*57718be8SEnji Cooper }
278*57718be8SEnji Cooper 
279*57718be8SEnji Cooper void
280*57718be8SEnji Cooper sigfpe(int s, siginfo_t *si, void *c)
281*57718be8SEnji Cooper {
282*57718be8SEnji Cooper 	signal_caught = 1;
283*57718be8SEnji Cooper 	sicode = si->si_code;
284*57718be8SEnji Cooper 	siglongjmp(b, 1);
285*57718be8SEnji Cooper }
286*57718be8SEnji Cooper 
287*57718be8SEnji Cooper #define TEST(m, t)							\
288*57718be8SEnji Cooper 	ATF_TC(m##_##t);						\
289*57718be8SEnji Cooper 									\
290*57718be8SEnji Cooper 	ATF_TC_HEAD(m##_##t, tc)					\
291*57718be8SEnji Cooper 	{								\
292*57718be8SEnji Cooper 									\
293*57718be8SEnji Cooper 		atf_tc_set_md_var(tc, "descr",				\
294*57718be8SEnji Cooper 		    "Test " ___STRING(m) " exceptions for "		\
295*57718be8SEnji Cooper 		    ___STRING(t) "values");				\
296*57718be8SEnji Cooper 	}								\
297*57718be8SEnji Cooper 									\
298*57718be8SEnji Cooper 	ATF_TC_BODY(m##_##t, tc)					\
299*57718be8SEnji Cooper 	{								\
300*57718be8SEnji Cooper 		if (strcmp(MACHINE, "macppc") == 0)			\
301*57718be8SEnji Cooper 			atf_tc_expect_fail("PR port-macppc/46319");	\
302*57718be8SEnji Cooper 									\
303*57718be8SEnji Cooper 		if (isQEMU())						\
304*57718be8SEnji Cooper 			atf_tc_expect_fail("PR misc/44767");		\
305*57718be8SEnji Cooper 									\
306*57718be8SEnji Cooper 		m(t##_ops);						\
307*57718be8SEnji Cooper 	}
308*57718be8SEnji Cooper 
309*57718be8SEnji Cooper TEST(fpsetmask_masked, float)
310*57718be8SEnji Cooper TEST(fpsetmask_masked, double)
311*57718be8SEnji Cooper TEST(fpsetmask_masked, long_double)
312*57718be8SEnji Cooper TEST(fpsetmask_unmasked, float)
313*57718be8SEnji Cooper TEST(fpsetmask_unmasked, double)
314*57718be8SEnji Cooper TEST(fpsetmask_unmasked, long_double)
315*57718be8SEnji Cooper 
316*57718be8SEnji Cooper ATF_TC(fpsetmask_basic);
317*57718be8SEnji Cooper ATF_TC_HEAD(fpsetmask_basic, tc)
318*57718be8SEnji Cooper {
319*57718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "A basic test of fpsetmask(3)");
320*57718be8SEnji Cooper }
321*57718be8SEnji Cooper 
322*57718be8SEnji Cooper ATF_TC_BODY(fpsetmask_basic, tc)
323*57718be8SEnji Cooper {
324*57718be8SEnji Cooper 	size_t i;
325*57718be8SEnji Cooper 	fp_except_t msk, lst[] = { FP_X_INV, FP_X_DZ, FP_X_OFL, FP_X_UFL };
326*57718be8SEnji Cooper 
327*57718be8SEnji Cooper 	msk = fpgetmask();
328*57718be8SEnji Cooper 	for (i = 0; i < __arraycount(lst); i++) {
329*57718be8SEnji Cooper 		fpsetmask(msk | lst[i]);
330*57718be8SEnji Cooper 		ATF_CHECK((fpgetmask() & lst[i]) != 0);
331*57718be8SEnji Cooper 		fpsetmask(msk & lst[i]);
332*57718be8SEnji Cooper 		ATF_CHECK((fpgetmask() & lst[i]) == 0);
333*57718be8SEnji Cooper 	}
334*57718be8SEnji Cooper 
335*57718be8SEnji Cooper }
336*57718be8SEnji Cooper 
337*57718be8SEnji Cooper #endif /* defined(_FLOAT_IEEE754) */
338*57718be8SEnji Cooper 
339*57718be8SEnji Cooper ATF_TP_ADD_TCS(tp)
340*57718be8SEnji Cooper {
341*57718be8SEnji Cooper 
342*57718be8SEnji Cooper #ifndef _FLOAT_IEEE754
343*57718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, no_test);
344*57718be8SEnji Cooper #else
345*57718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, fpsetmask_basic);
346*57718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, fpsetmask_masked_float);
347*57718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, fpsetmask_masked_double);
348*57718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, fpsetmask_masked_long_double);
349*57718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, fpsetmask_unmasked_float);
350*57718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, fpsetmask_unmasked_double);
351*57718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, fpsetmask_unmasked_long_double);
352*57718be8SEnji Cooper #endif
353*57718be8SEnji Cooper 
354*57718be8SEnji Cooper 	return atf_no_error();
355*57718be8SEnji Cooper }
356