Home | History | Annotate | Line # | Download | only in libm
t_fenv.c revision 1.7
      1 /* $NetBSD: t_fenv.c,v 1.7 2023/11/05 15:27:40 riastradh Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2014 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Martin Husemann.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 #include <sys/cdefs.h>
     32 __RCSID("$NetBSD: t_fenv.c,v 1.7 2023/11/05 15:27:40 riastradh Exp $");
     33 
     34 #include <atf-c.h>
     35 
     36 #include <fenv.h>
     37 #ifdef __HAVE_FENV
     38 
     39 #include <ieeefp.h>
     40 #include <stdlib.h>
     41 
     42 
     43 #if (__arm__ && !__SOFTFP__) || __aarch64__
     44 	/*
     45 	 * Some NEON fpus  do not trap on IEEE 754 FP exceptions.
     46 	 * Skip these tests if running on them and compiled for
     47 	 * hard float.
     48 	 */
     49 #define	FPU_EXC_PREREQ()						\
     50 	if (0 == fpsetmask(fpsetmask(FP_X_INV)))			\
     51 		atf_tc_skip("FPU does not implement traps on FP exceptions");
     52 
     53 	/*
     54 	 * Same as above: some don't allow configuring the rounding mode.
     55 	 */
     56 #define	FPU_RND_PREREQ()						\
     57 	if (0 == fpsetround(fpsetround(FP_RZ)))				\
     58 		atf_tc_skip("FPU does not implement configurable "	\
     59 		    "rounding modes");
     60 #endif
     61 
     62 #ifndef FPU_EXC_PREREQ
     63 #define	FPU_EXC_PREREQ()	/* nothing */
     64 #endif
     65 #ifndef FPU_RND_PREREQ
     66 #define	FPU_RND_PREREQ()	/* nothing */
     67 #endif
     68 
     69 
     70 ATF_TC(fegetround);
     71 
     72 ATF_TC_HEAD(fegetround, tc)
     73 {
     74 	atf_tc_set_md_var(tc, "descr",
     75 	    "verify the fegetround() function agrees with the legacy "
     76 	    "fpsetround");
     77 }
     78 
     79 ATF_TC_BODY(fegetround, tc)
     80 {
     81 	FPU_RND_PREREQ();
     82 
     83 	fpsetround(FP_RZ);
     84 	ATF_CHECK_EQ_MSG(fegetround(), FE_TOWARDZERO,
     85 	    "fegetround()=%d FE_TOWARDZERO=%d",
     86 	    fegetround(), FE_TOWARDZERO);
     87 	fpsetround(FP_RM);
     88 	ATF_CHECK_EQ_MSG(fegetround(), FE_DOWNWARD,
     89 	    "fegetround()=%d FE_DOWNWARD=%d",
     90 	    fegetround(), FE_DOWNWARD);
     91 	fpsetround(FP_RN);
     92 	ATF_CHECK_EQ_MSG(fegetround(), FE_TONEAREST,
     93 	    "fegetround()=%d FE_TONEAREST=%d",
     94 	    fegetround(), FE_TONEAREST);
     95 	fpsetround(FP_RP);
     96 	ATF_CHECK_EQ_MSG(fegetround(), FE_UPWARD,
     97 	    "fegetround()=%d FE_UPWARD=%d",
     98 	    fegetround(), FE_UPWARD);
     99 }
    100 
    101 ATF_TC(fesetround);
    102 
    103 ATF_TC_HEAD(fesetround, tc)
    104 {
    105 	atf_tc_set_md_var(tc, "descr",
    106 	    "verify the fesetround() function agrees with the legacy "
    107 	    "fpgetround");
    108 }
    109 
    110 ATF_TC_BODY(fesetround, tc)
    111 {
    112 	FPU_RND_PREREQ();
    113 
    114 	fesetround(FE_TOWARDZERO);
    115 	ATF_CHECK_EQ_MSG(fpgetround(), FP_RZ,
    116 	    "fpgetround()=%d FP_RZ=%d",
    117 	    (int)fpgetround(), (int)FP_RZ);
    118 	fesetround(FE_DOWNWARD);
    119 	ATF_CHECK_EQ_MSG(fpgetround(), FP_RM,
    120 	    "fpgetround()=%d FP_RM=%d",
    121 	    (int)fpgetround(), (int)FP_RM);
    122 	fesetround(FE_TONEAREST);
    123 	ATF_CHECK_EQ_MSG(fpgetround(), FP_RN,
    124 	    "fpgetround()=%d FP_RN=%d",
    125 	    (int)fpgetround(), (int)FP_RN);
    126 	fesetround(FE_UPWARD);
    127 	ATF_CHECK_EQ_MSG(fpgetround(), FP_RP,
    128 	    "fpgetround()=%d FP_RP=%d",
    129 	    (int)fpgetround(), (int)FP_RP);
    130 }
    131 
    132 ATF_TC(fegetexcept);
    133 
    134 ATF_TC_HEAD(fegetexcept, tc)
    135 {
    136 	atf_tc_set_md_var(tc, "descr",
    137 	    "verify the fegetexcept() function agrees with the legacy "
    138 	    "fpsetmask()");
    139 }
    140 
    141 ATF_TC_BODY(fegetexcept, tc)
    142 {
    143 	FPU_EXC_PREREQ();
    144 
    145 	fpsetmask(0);
    146 	ATF_CHECK_EQ_MSG(fegetexcept(), 0,
    147 	    "fegetexcept()=%d",
    148 	    fegetexcept());
    149 
    150 	fpsetmask(FP_X_INV|FP_X_DZ|FP_X_OFL|FP_X_UFL|FP_X_IMP);
    151 	ATF_CHECK(fegetexcept() == (FE_INVALID|FE_DIVBYZERO|FE_OVERFLOW
    152 	    |FE_UNDERFLOW|FE_INEXACT));
    153 
    154 	fpsetmask(FP_X_INV);
    155 	ATF_CHECK_EQ_MSG(fegetexcept(), FE_INVALID,
    156 	    "fegetexcept()=%d FE_INVALID=%d",
    157 	    fegetexcept(), FE_INVALID);
    158 
    159 	fpsetmask(FP_X_DZ);
    160 	ATF_CHECK_EQ_MSG(fegetexcept(), FE_DIVBYZERO,
    161 	    "fegetexcept()=%d FE_DIVBYZERO=%d",
    162 	    fegetexcept(), FE_DIVBYZERO);
    163 
    164 	fpsetmask(FP_X_OFL);
    165 	ATF_CHECK_EQ_MSG(fegetexcept(), FE_OVERFLOW,
    166 	    "fegetexcept()=%d FE_OVERFLOW=%d",
    167 	    fegetexcept(), FE_OVERFLOW);
    168 
    169 	fpsetmask(FP_X_UFL);
    170 	ATF_CHECK_EQ_MSG(fegetexcept(), FE_UNDERFLOW,
    171 	    "fegetexcept()=%d FE_UNDERFLOW=%d",
    172 	    fegetexcept(), FE_UNDERFLOW);
    173 
    174 	fpsetmask(FP_X_IMP);
    175 	ATF_CHECK_EQ_MSG(fegetexcept(), FE_INEXACT,
    176 	    "fegetexcept()=%d FE_INEXACT=%d",
    177 	    fegetexcept(), FE_INEXACT);
    178 }
    179 
    180 ATF_TC(feenableexcept);
    181 
    182 ATF_TC_HEAD(feenableexcept, tc)
    183 {
    184 	atf_tc_set_md_var(tc, "descr",
    185 	    "verify the feenableexcept() function agrees with the legacy "
    186 	    "fpgetmask()");
    187 }
    188 
    189 ATF_TC_BODY(feenableexcept, tc)
    190 {
    191 	FPU_EXC_PREREQ();
    192 
    193 	fedisableexcept(FE_ALL_EXCEPT);
    194 	ATF_CHECK_EQ_MSG(fpgetmask(), 0,
    195 	    "fpgetmask()=%d",
    196 	    (int)fpgetmask());
    197 
    198 	feenableexcept(FE_UNDERFLOW);
    199 	ATF_CHECK_EQ_MSG(fpgetmask(), FP_X_UFL,
    200 	    "fpgetmask()=%d FP_X_UFL=%d",
    201 	    (int)fpgetmask(), (int)FP_X_UFL);
    202 
    203 	fedisableexcept(FE_ALL_EXCEPT);
    204 	feenableexcept(FE_OVERFLOW);
    205 	ATF_CHECK_EQ_MSG(fpgetmask(), FP_X_OFL,
    206 	    "fpgetmask()=%d FP_X_OFL=%d",
    207 	    (int)fpgetmask(), (int)FP_X_OFL);
    208 
    209 	fedisableexcept(FE_ALL_EXCEPT);
    210 	feenableexcept(FE_DIVBYZERO);
    211 	ATF_CHECK_EQ_MSG(fpgetmask(), FP_X_DZ,
    212 	    "fpgetmask()=%d FP_X_DZ=%d",
    213 	    (int)fpgetmask(), (int)FP_X_DZ);
    214 
    215 	fedisableexcept(FE_ALL_EXCEPT);
    216 	feenableexcept(FE_INEXACT);
    217 	ATF_CHECK_EQ_MSG(fpgetmask(), FP_X_IMP,
    218 	    "fpgetmask()=%d FP_X_IMP=%d",
    219 	    (int)fpgetmask(), (int)FP_X_IMP);
    220 
    221 	fedisableexcept(FE_ALL_EXCEPT);
    222 	feenableexcept(FE_INVALID);
    223 	ATF_CHECK_EQ_MSG(fpgetmask(), FP_X_INV,
    224 	    "fpgetmask()=%d FP_X_INV=%d",
    225 	    (int)fpgetmask(), (int)FP_X_INV);
    226 }
    227 
    228 ATF_TP_ADD_TCS(tp)
    229 {
    230 	ATF_TP_ADD_TC(tp, fegetround);
    231 	ATF_TP_ADD_TC(tp, fesetround);
    232 	ATF_TP_ADD_TC(tp, fegetexcept);
    233 	ATF_TP_ADD_TC(tp, feenableexcept);
    234 
    235 	return atf_no_error();
    236 }
    237 
    238 #else	/* no fenv.h support */
    239 
    240 ATF_TC(t_nofenv);
    241 
    242 ATF_TC_HEAD(t_nofenv, tc)
    243 {
    244 	atf_tc_set_md_var(tc, "descr",
    245 	    "dummy test case - no fenv.h support");
    246 }
    247 
    248 
    249 ATF_TC_BODY(t_nofenv, tc)
    250 {
    251 	atf_tc_skip("no fenv.h support on this architecture");
    252 }
    253 
    254 ATF_TP_ADD_TCS(tp)
    255 {
    256 	ATF_TP_ADD_TC(tp, t_nofenv);
    257 	return atf_no_error();
    258 }
    259 
    260 #endif
    261