fenv.c revision 226218
11206Ssundar/*-
21206Ssundar * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
31206Ssundar * All rights reserved.
41206Ssundar *
51206Ssundar * Redistribution and use in source and binary forms, with or without
61206Ssundar * modification, are permitted provided that the following conditions
71206Ssundar * are met:
81206Ssundar * 1. Redistributions of source code must retain the above copyright
91206Ssundar *    notice, this list of conditions and the following disclaimer.
101206Ssundar * 2. Redistributions in binary form must reproduce the above copyright
111206Ssundar *    notice, this list of conditions and the following disclaimer in the
121206Ssundar *    documentation and/or other materials provided with the distribution.
131206Ssundar *
141206Ssundar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151206Ssundar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161206Ssundar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171206Ssundar * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181206Ssundar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191206Ssundar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201206Ssundar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211206Ssundar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221206Ssundar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231206Ssundar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241206Ssundar * SUCH DAMAGE.
251206Ssundar *
261206Ssundar * $FreeBSD: head/lib/msun/amd64/fenv.c 226218 2011-10-10 15:43:09Z das $
271206Ssundar */
281206Ssundar
291206Ssundar#include <sys/cdefs.h>
301206Ssundar#include <sys/types.h>
311206Ssundar#include <machine/fpu.h>
321206Ssundar
331206Ssundar#define	__fenv_static
341206Ssundar#include <fenv.h>
351206Ssundar
361206Ssundar#ifdef __GNUC_GNU_INLINE__
371206Ssundar#error "This file must be compiled with C99 'inline' semantics"
381206Ssundar#endif
391206Ssundar
401206Ssundarconst fenv_t __fe_dfl_env = {
411206Ssundar	{ 0xffff0000 | __INITIAL_FPUCW__,
421206Ssundar	  0xffff0000,
431206Ssundar	  0xffffffff,
441206Ssundar	  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
451206Ssundar	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff }
461206Ssundar	},
471206Ssundar	__INITIAL_MXCSR__
481206Ssundar};
491206Ssundar
501206Ssundarextern inline int feclearexcept(int __excepts);
511206Ssundarextern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts);
521206Ssundar
531206Ssundarint
541206Ssundarfesetexceptflag(const fexcept_t *flagp, int excepts)
551206Ssundar{
561206Ssundar	fenv_t env;
571206Ssundar
581206Ssundar	__fnstenv(&env.__x87);
591206Ssundar	env.__x87.__status &= ~excepts;
601206Ssundar	env.__x87.__status |= *flagp & excepts;
611206Ssundar	__fldenv(env.__x87);
621206Ssundar
631206Ssundar	__stmxcsr(&env.__mxcsr);
641206Ssundar	env.__mxcsr &= ~excepts;
651206Ssundar	env.__mxcsr |= *flagp & excepts;
661206Ssundar	__ldmxcsr(env.__mxcsr);
671206Ssundar
681206Ssundar	return (0);
691206Ssundar}
701206Ssundar
711206Ssundarint
721206Ssundarferaiseexcept(int excepts)
731206Ssundar{
741206Ssundar	fexcept_t ex = excepts;
751206Ssundar
761206Ssundar	fesetexceptflag(&ex, excepts);
771206Ssundar	__fwait();
781206Ssundar	return (0);
791206Ssundar}
801206Ssundar
811206Ssundarextern inline int fetestexcept(int __excepts);
821206Ssundarextern inline int fegetround(void);
831206Ssundarextern inline int fesetround(int __round);
841206Ssundar
851206Ssundarint
861206Ssundarfegetenv(fenv_t *envp)
871206Ssundar{
881206Ssundar
891206Ssundar	__fnstenv(&envp->__x87);
901206Ssundar	__stmxcsr(&envp->__mxcsr);
911206Ssundar	/*
921206Ssundar	 * fnstenv masks all exceptions, so we need to restore the
931206Ssundar	 * control word to avoid this side effect.
941206Ssundar	 */
951206Ssundar	__fldcw(envp->__x87.__control);
961206Ssundar	return (0);
971206Ssundar}
981206Ssundar
991206Ssundarint
1001206Ssundarfeholdexcept(fenv_t *envp)
1011206Ssundar{
1021206Ssundar	__uint32_t mxcsr;
1031206Ssundar
1041206Ssundar	__stmxcsr(&mxcsr);
1051206Ssundar	__fnstenv(&envp->__x87);
1061206Ssundar	__fnclex();
1071206Ssundar	envp->__mxcsr = mxcsr;
1081206Ssundar	mxcsr &= ~FE_ALL_EXCEPT;
1091206Ssundar	mxcsr |= FE_ALL_EXCEPT << _SSE_EMASK_SHIFT;
1101206Ssundar	__ldmxcsr(mxcsr);
1111206Ssundar	return (0);
1121206Ssundar}
1131206Ssundar
114extern inline int fesetenv(const fenv_t *__envp);
115
116int
117feupdateenv(const fenv_t *envp)
118{
119	__uint32_t mxcsr;
120	__uint16_t status;
121
122	__fnstsw(&status);
123	__stmxcsr(&mxcsr);
124	fesetenv(envp);
125	feraiseexcept((mxcsr | status) & FE_ALL_EXCEPT);
126	return (0);
127}
128
129int
130__feenableexcept(int mask)
131{
132	__uint32_t mxcsr, omask;
133	__uint16_t control;
134
135	mask &= FE_ALL_EXCEPT;
136	__fnstcw(&control);
137	__stmxcsr(&mxcsr);
138	omask = (control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
139	control &= ~mask;
140	__fldcw(control);
141	mxcsr &= ~(mask << _SSE_EMASK_SHIFT);
142	__ldmxcsr(mxcsr);
143	return (~omask);
144}
145
146int
147__fedisableexcept(int mask)
148{
149	__uint32_t mxcsr, omask;
150	__uint16_t control;
151
152	mask &= FE_ALL_EXCEPT;
153	__fnstcw(&control);
154	__stmxcsr(&mxcsr);
155	omask = (control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
156	control |= mask;
157	__fldcw(control);
158	mxcsr |= mask << _SSE_EMASK_SHIFT;
159	__ldmxcsr(mxcsr);
160	return (~omask);
161}
162
163__weak_reference(__feenableexcept, feenableexcept);
164__weak_reference(__fedisableexcept, fedisableexcept);
165