1*2c53affbSjmc /* $OpenBSD: fenv.c,v 1.6 2022/12/27 17:10:07 jmc Exp $ */
23c6363cfSpatrick /*-
33c6363cfSpatrick * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
43c6363cfSpatrick * All rights reserved.
53c6363cfSpatrick *
63c6363cfSpatrick * Redistribution and use in source and binary forms, with or without
73c6363cfSpatrick * modification, are permitted provided that the following conditions
83c6363cfSpatrick * are met:
93c6363cfSpatrick * 1. Redistributions of source code must retain the above copyright
103c6363cfSpatrick * notice, this list of conditions and the following disclaimer.
113c6363cfSpatrick * 2. Redistributions in binary form must reproduce the above copyright
123c6363cfSpatrick * notice, this list of conditions and the following disclaimer in the
133c6363cfSpatrick * documentation and/or other materials provided with the distribution.
143c6363cfSpatrick *
153c6363cfSpatrick * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
163c6363cfSpatrick * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
173c6363cfSpatrick * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
183c6363cfSpatrick * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
193c6363cfSpatrick * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
203c6363cfSpatrick * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
213c6363cfSpatrick * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
223c6363cfSpatrick * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
233c6363cfSpatrick * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
243c6363cfSpatrick * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
253c6363cfSpatrick * SUCH DAMAGE.
263c6363cfSpatrick *
273c6363cfSpatrick * $FreeBSD: head/lib/msun/aarch64/fenv.h 280857 2015-03-30 16:42:08Z emaste $
283c6363cfSpatrick */
293c6363cfSpatrick
303c6363cfSpatrick #include <fenv.h>
313c6363cfSpatrick #include <machine/ieeefp.h>
323c6363cfSpatrick
333c6363cfSpatrick /* We need to be able to map status flag positions to mask flag positions */
343c6363cfSpatrick #define _FPUSW_SHIFT 8
353c6363cfSpatrick #define _ENABLE_MASK (FE_ALL_EXCEPT << _FPUSW_SHIFT)
363c6363cfSpatrick
37dd81489dSjsg #define __mrs_fpcr(r) __asm volatile("mrs %x0, fpcr" : "=r" (r))
38dd81489dSjsg #define __msr_fpcr(r) __asm volatile("msr fpcr, %x0" : : "r" (r))
393c6363cfSpatrick
40dd81489dSjsg #define __mrs_fpsr(r) __asm volatile("mrs %x0, fpsr" : "=r" (r))
41dd81489dSjsg #define __msr_fpsr(r) __asm volatile("msr fpsr, %x0" : : "r" (r))
423c6363cfSpatrick
433c6363cfSpatrick /*
443c6363cfSpatrick * The following constant represents the default floating-point environment
453c6363cfSpatrick * (that is, the one installed at program startup) and has type pointer to
463c6363cfSpatrick * const-qualified fenv_t.
473c6363cfSpatrick *
483c6363cfSpatrick * It can be used as an argument to the functions within the <fenv.h> header
493c6363cfSpatrick * that manage the floating-point environment, namely fesetenv() and
503c6363cfSpatrick * feupdateenv().
513c6363cfSpatrick */
523c6363cfSpatrick fenv_t __fe_dfl_env = 0;
533c6363cfSpatrick
543c6363cfSpatrick /*
553c6363cfSpatrick * The feclearexcept() function clears the supported floating-point exceptions
563c6363cfSpatrick * represented by `excepts'.
573c6363cfSpatrick */
583c6363cfSpatrick int
feclearexcept(int excepts)593c6363cfSpatrick feclearexcept(int excepts)
603c6363cfSpatrick {
613c6363cfSpatrick fexcept_t r;
623c6363cfSpatrick
6353b00876Spatrick excepts &= FE_ALL_EXCEPT;
643c6363cfSpatrick __mrs_fpsr(r);
653c6363cfSpatrick r &= ~excepts;
663c6363cfSpatrick __msr_fpsr(r);
673c6363cfSpatrick return (0);
683c6363cfSpatrick }
693c6363cfSpatrick DEF_STD(feclearexcept);
703c6363cfSpatrick
713c6363cfSpatrick /*
723c6363cfSpatrick * The fegetexceptflag() function stores an implementation-defined
733c6363cfSpatrick * representation of the states of the floating-point status flags indicated by
743c6363cfSpatrick * the argument excepts in the object pointed to by the argument flagp.
753c6363cfSpatrick */
763c6363cfSpatrick int
fegetexceptflag(fexcept_t * flagp,int excepts)773c6363cfSpatrick fegetexceptflag(fexcept_t *flagp, int excepts)
783c6363cfSpatrick {
793c6363cfSpatrick fexcept_t r;
803c6363cfSpatrick
8153b00876Spatrick excepts &= FE_ALL_EXCEPT;
823c6363cfSpatrick __mrs_fpsr(r);
833c6363cfSpatrick *flagp = r & excepts;
843c6363cfSpatrick return (0);
853c6363cfSpatrick }
863c6363cfSpatrick
873c6363cfSpatrick /*
883c6363cfSpatrick * The feraiseexcept() function raises the supported floating-point exceptions
893c6363cfSpatrick * represented by the argument `excepts'.
903c6363cfSpatrick */
913c6363cfSpatrick int
feraiseexcept(int excepts)923c6363cfSpatrick feraiseexcept(int excepts)
933c6363cfSpatrick {
943c6363cfSpatrick fexcept_t r;
953c6363cfSpatrick
9653b00876Spatrick excepts &= FE_ALL_EXCEPT;
973c6363cfSpatrick __mrs_fpsr(r);
983c6363cfSpatrick r |= excepts;
993c6363cfSpatrick __msr_fpsr(r);
1003c6363cfSpatrick return (0);
1013c6363cfSpatrick }
1023c6363cfSpatrick DEF_STD(feraiseexcept);
1033c6363cfSpatrick
1043c6363cfSpatrick /*
1053c6363cfSpatrick * This function sets the floating-point status flags indicated by the argument
1063c6363cfSpatrick * `excepts' to the states stored in the object pointed to by `flagp'. It does
1073c6363cfSpatrick * NOT raise any floating-point exceptions, but only sets the state of the flags.
1083c6363cfSpatrick */
1093c6363cfSpatrick int
fesetexceptflag(const fexcept_t * flagp,int excepts)1103c6363cfSpatrick fesetexceptflag(const fexcept_t *flagp, int excepts)
1113c6363cfSpatrick {
1123c6363cfSpatrick fexcept_t r;
1133c6363cfSpatrick
11453b00876Spatrick excepts &= FE_ALL_EXCEPT;
1153c6363cfSpatrick __mrs_fpsr(r);
1163c6363cfSpatrick r &= ~excepts;
1173c6363cfSpatrick r |= *flagp & excepts;
1183c6363cfSpatrick __msr_fpsr(r);
1193c6363cfSpatrick return (0);
1203c6363cfSpatrick }
1213c6363cfSpatrick DEF_STD(fesetexceptflag);
1223c6363cfSpatrick
1233c6363cfSpatrick /*
1243c6363cfSpatrick * The fetestexcept() function determines which of a specified subset of the
1253c6363cfSpatrick * floating-point exception flags are currently set. The `excepts' argument
1263c6363cfSpatrick * specifies the floating-point status flags to be queried.
1273c6363cfSpatrick */
1283c6363cfSpatrick int
fetestexcept(int excepts)1293c6363cfSpatrick fetestexcept(int excepts)
1303c6363cfSpatrick {
1313c6363cfSpatrick fexcept_t r;
1323c6363cfSpatrick
13353b00876Spatrick excepts &= FE_ALL_EXCEPT;
1343c6363cfSpatrick __mrs_fpsr(r);
1353c6363cfSpatrick return (r & excepts);
1363c6363cfSpatrick }
1373c6363cfSpatrick DEF_STD(fetestexcept);
1383c6363cfSpatrick
1393c6363cfSpatrick /*
1403c6363cfSpatrick * The fegetround() function gets the current rounding direction.
1413c6363cfSpatrick */
1423c6363cfSpatrick int
fegetround(void)1433c6363cfSpatrick fegetround(void)
1443c6363cfSpatrick {
1453c6363cfSpatrick fenv_t r;
1463c6363cfSpatrick
1473c6363cfSpatrick __mrs_fpcr(r);
1483c6363cfSpatrick return ((r >> _ROUND_SHIFT) & _ROUND_MASK);
1493c6363cfSpatrick }
1503c6363cfSpatrick DEF_STD(fegetround);
1513c6363cfSpatrick
1523c6363cfSpatrick /*
1533c6363cfSpatrick * The fesetround() function establishes the rounding direction represented by
1543c6363cfSpatrick * its argument `round'. If the argument is not equal to the value of a rounding
1553c6363cfSpatrick * direction macro, the rounding direction is not changed.
1563c6363cfSpatrick */
1573c6363cfSpatrick int
fesetround(int round)1583c6363cfSpatrick fesetround(int round)
1593c6363cfSpatrick {
1603c6363cfSpatrick fenv_t r;
1613c6363cfSpatrick
1623c6363cfSpatrick if (round & ~_ROUND_MASK)
1633c6363cfSpatrick return (-1);
1643c6363cfSpatrick __mrs_fpcr(r);
1653c6363cfSpatrick r &= ~(_ROUND_MASK << _ROUND_SHIFT);
1663c6363cfSpatrick r |= round << _ROUND_SHIFT;
1673c6363cfSpatrick __msr_fpcr(r);
1683c6363cfSpatrick return (0);
1693c6363cfSpatrick }
1703c6363cfSpatrick DEF_STD(fesetround);
1713c6363cfSpatrick
1723c6363cfSpatrick /*
1733c6363cfSpatrick * The fegetenv() function attempts to store the current floating-point
1743c6363cfSpatrick * environment in the object pointed to by envp.
1753c6363cfSpatrick */
1763c6363cfSpatrick int
fegetenv(fenv_t * envp)1773c6363cfSpatrick fegetenv(fenv_t *envp)
1783c6363cfSpatrick {
1793c6363cfSpatrick fenv_t r;
1803c6363cfSpatrick
1813c6363cfSpatrick __mrs_fpcr(r);
18253b00876Spatrick *envp = r;
1833c6363cfSpatrick
1843c6363cfSpatrick __mrs_fpsr(r);
18553b00876Spatrick *envp |= (r << 32);
1863c6363cfSpatrick
1873c6363cfSpatrick return (0);
1883c6363cfSpatrick }
1893c6363cfSpatrick DEF_STD(fegetenv);
1903c6363cfSpatrick
1913c6363cfSpatrick /*
1923c6363cfSpatrick * The feholdexcept() function saves the current floating-point environment
1933c6363cfSpatrick * in the object pointed to by envp, clears the floating-point status flags, and
1943c6363cfSpatrick * then installs a non-stop (continue on floating-point exceptions) mode, if
1953c6363cfSpatrick * available, for all floating-point exceptions.
1963c6363cfSpatrick */
1973c6363cfSpatrick int
feholdexcept(fenv_t * envp)1983c6363cfSpatrick feholdexcept(fenv_t *envp)
1993c6363cfSpatrick {
2003c6363cfSpatrick fenv_t r;
2013c6363cfSpatrick
2023c6363cfSpatrick __mrs_fpcr(r);
20353b00876Spatrick *envp = r;
20453b00876Spatrick r &= ~_ENABLE_MASK;
2053c6363cfSpatrick __msr_fpcr(r);
2063c6363cfSpatrick
2073c6363cfSpatrick __mrs_fpsr(r);
20853b00876Spatrick *envp |= (r << 32);
20953b00876Spatrick r &= ~FE_ALL_EXCEPT;
2103c6363cfSpatrick __msr_fpsr(r);
2113c6363cfSpatrick return (0);
2123c6363cfSpatrick }
2133c6363cfSpatrick DEF_STD(feholdexcept);
2143c6363cfSpatrick
2153c6363cfSpatrick /*
2163c6363cfSpatrick * The fesetenv() function attempts to establish the floating-point environment
2173c6363cfSpatrick * represented by the object pointed to by envp. The argument `envp' points
2183c6363cfSpatrick * to an object set by a call to fegetenv() or feholdexcept(), or equal a
2193c6363cfSpatrick * floating-point environment macro. The fesetenv() function does not raise
2203c6363cfSpatrick * floating-point exceptions, but only installs the state of the floating-point
2213c6363cfSpatrick * status flags represented through its argument.
2223c6363cfSpatrick */
2233c6363cfSpatrick int
fesetenv(const fenv_t * envp)2243c6363cfSpatrick fesetenv(const fenv_t *envp)
2253c6363cfSpatrick {
2263c6363cfSpatrick
22753b00876Spatrick __msr_fpcr(*envp & 0xffffffff);
22853b00876Spatrick __msr_fpsr(*envp >> 32);
2293c6363cfSpatrick return (0);
2303c6363cfSpatrick }
2313c6363cfSpatrick DEF_STD(fesetenv);
2323c6363cfSpatrick
2333c6363cfSpatrick /*
2343c6363cfSpatrick * The feupdateenv() function saves the currently raised floating-point
2353c6363cfSpatrick * exceptions in its automatic storage, installs the floating-point environment
2363c6363cfSpatrick * represented by the object pointed to by `envp', and then raises the saved
2373c6363cfSpatrick * floating-point exceptions. The argument `envp' shall point to an object set
2383c6363cfSpatrick * by a call to feholdexcept() or fegetenv(), or equal a floating-point
2393c6363cfSpatrick * environment macro.
2403c6363cfSpatrick */
2413c6363cfSpatrick int
feupdateenv(const fenv_t * envp)2423c6363cfSpatrick feupdateenv(const fenv_t *envp)
2433c6363cfSpatrick {
2443c6363cfSpatrick fexcept_t r;
2453c6363cfSpatrick
2463c6363cfSpatrick __mrs_fpsr(r);
2473c6363cfSpatrick fesetenv(envp);
2483c6363cfSpatrick feraiseexcept(r & FE_ALL_EXCEPT);
2493c6363cfSpatrick return (0);
2503c6363cfSpatrick }
2513c6363cfSpatrick DEF_STD(feupdateenv);
2523c6363cfSpatrick
2533c6363cfSpatrick /*
254*2c53affbSjmc * The following functions are extensions to the standard
2553c6363cfSpatrick */
2563c6363cfSpatrick int
feenableexcept(int mask)2573c6363cfSpatrick feenableexcept(int mask)
2583c6363cfSpatrick {
2591ff8d394Skettenis return -1;
2603c6363cfSpatrick }
2613c6363cfSpatrick
2623c6363cfSpatrick int
fedisableexcept(int mask)2633c6363cfSpatrick fedisableexcept(int mask)
2643c6363cfSpatrick {
2651ff8d394Skettenis return 0;
2663c6363cfSpatrick }
2673c6363cfSpatrick
2683c6363cfSpatrick int
fegetexcept(void)2693c6363cfSpatrick fegetexcept(void)
2703c6363cfSpatrick {
2711ff8d394Skettenis return 0;
2723c6363cfSpatrick }
273