xref: /freebsd/lib/msun/amd64/fenv.c (revision a259b98fa211ed87bfee58c575de4e2de94ee0fa)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/types.h>
30 #include <machine/fpu.h>
31 
32 #include "fenv.h"
33 
34 const fenv_t __fe_dfl_env = {
35 	{ 0xffff0000 | __INITIAL_FPUCW__,
36 	  0xffff0000,
37 	  0xffffffff,
38 	  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
39 	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff }
40 	},
41 	__INITIAL_MXCSR__
42 };
43 
44 const femode_t __fe_dfl_mode = {
45 	.__control = __INITIAL_FPUCW__,
46 	.__reserved = 0,
47 	.__mxcsr = __INITIAL_MXCSR__
48 };
49 
50 int
51 (feclearexcept)(int excepts)
52 {
53 	return (__feclearexcept_int(excepts));
54 }
55 
56 int
57 (fegetexceptflag)(fexcept_t *flagp, int excepts)
58 {
59 	return (__fegetexceptflag_int(flagp, excepts));
60 }
61 
62 int
63 fesetexceptflag(const fexcept_t *flagp, int excepts)
64 {
65 	fenv_t env;
66 
67 	__fnstenv(&env.__x87);
68 	env.__x87.__status &= ~excepts;
69 	env.__x87.__status |= *flagp & excepts;
70 	__fldenv(&env.__x87);
71 
72 	__stmxcsr(&env.__mxcsr);
73 	env.__mxcsr &= ~excepts;
74 	env.__mxcsr |= *flagp & excepts;
75 	__ldmxcsr(&env.__mxcsr);
76 
77 	return (0);
78 }
79 
80 int
81 feraiseexcept(int excepts)
82 {
83 	fexcept_t ex = excepts;
84 
85 	fesetexceptflag(&ex, excepts);
86 	__fwait();
87 	return (0);
88 }
89 
90 int
91 (fetestexcept)(int excepts)
92 {
93 	return (__fetestexcept_int(excepts));
94 }
95 
96 int
97 (fegetround)(void)
98 {
99 	return (__fegetround_int());
100 }
101 
102 int
103 (fesetround)(int round)
104 {
105 	return (__fesetround_int(round));
106 }
107 
108 int
109 (fegetmode)(femode_t *modep)
110 {
111 	return (__fegetmode_int(modep));
112 }
113 
114 int
115 (fesetmode)(const femode_t *modep)
116 {
117 	return (__fesetmode_int(modep));
118 }
119 
120 int
121 fegetenv(fenv_t *envp)
122 {
123 
124 	__fnstenv(&envp->__x87);
125 	__stmxcsr(&envp->__mxcsr);
126 	/*
127 	 * fnstenv masks all exceptions, so we need to restore the
128 	 * control word to avoid this side effect.
129 	 */
130 	__fldcw(&envp->__x87.__control);
131 	return (0);
132 }
133 
134 int
135 feholdexcept(fenv_t *envp)
136 {
137 	__uint32_t mxcsr;
138 
139 	__stmxcsr(&mxcsr);
140 	__fnstenv(&envp->__x87);
141 	__fnclex();
142 	envp->__mxcsr = mxcsr;
143 	mxcsr &= ~FE_ALL_EXCEPT;
144 	mxcsr |= FE_ALL_EXCEPT << _SSE_EMASK_SHIFT;
145 	__ldmxcsr(&mxcsr);
146 	return (0);
147 }
148 
149 int
150 (fesetenv)(const fenv_t *envp)
151 {
152 	return (__fesetenv_int(envp));
153 }
154 
155 int
156 feupdateenv(const fenv_t *envp)
157 {
158 	__uint32_t mxcsr;
159 	__uint16_t status;
160 
161 	__fnstsw(&status);
162 	__stmxcsr(&mxcsr);
163 	fesetenv(envp);
164 	feraiseexcept((mxcsr | status) & FE_ALL_EXCEPT);
165 	return (0);
166 }
167 
168 int
169 __feenableexcept(int mask)
170 {
171 	__uint32_t mxcsr, omask;
172 	__uint16_t control;
173 
174 	mask &= FE_ALL_EXCEPT;
175 	__fnstcw(&control);
176 	__stmxcsr(&mxcsr);
177 	omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
178 	control &= ~mask;
179 	__fldcw(&control);
180 	mxcsr &= ~(mask << _SSE_EMASK_SHIFT);
181 	__ldmxcsr(&mxcsr);
182 	return (omask);
183 }
184 
185 int
186 __fedisableexcept(int mask)
187 {
188 	__uint32_t mxcsr, omask;
189 	__uint16_t control;
190 
191 	mask &= FE_ALL_EXCEPT;
192 	__fnstcw(&control);
193 	__stmxcsr(&mxcsr);
194 	omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
195 	control |= mask;
196 	__fldcw(&control);
197 	mxcsr |= mask << _SSE_EMASK_SHIFT;
198 	__ldmxcsr(&mxcsr);
199 	return (omask);
200 }
201 
202 __weak_reference(__feenableexcept, feenableexcept);
203 __weak_reference(__fedisableexcept, fedisableexcept);
204