From 3fde53501d6fd13daa168378d3f8ae8f3ca6bafd Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Fri, 27 Jul 2012 15:21:41 +0100 Subject: [PATCH] Updated x86_64 fenv.h and added fenv.c. --- headers/posix/arch/x86_64/fenv.h | 13 +- headers/posix/arch/x86_64/fpu.h | 218 +++++++++++++++++++ headers/posix/fenv.h | 2 +- src/system/libroot/posix/arch/x86_64/Jamfile | 2 +- src/system/libroot/posix/arch/x86_64/fenv.c | 158 ++++++++++++++ 5 files changed, 386 insertions(+), 7 deletions(-) create mode 100644 headers/posix/arch/x86_64/fpu.h create mode 100644 src/system/libroot/posix/arch/x86_64/fenv.c diff --git a/headers/posix/arch/x86_64/fenv.h b/headers/posix/arch/x86_64/fenv.h index a9992f9fad..9a3df8eb9d 100644 --- a/headers/posix/arch/x86_64/fenv.h +++ b/headers/posix/arch/x86_64/fenv.h @@ -111,7 +111,8 @@ feclearexcept(int __excepts) static __inline int fegetexceptflag(fexcept_t *__flagp, int __excepts) { - int __mxcsr, __status; + uint32_t __mxcsr; + uint16_t __status; __stmxcsr(&__mxcsr); __fnstsw(&__status); @@ -125,7 +126,8 @@ int feraiseexcept(int __excepts); static __inline int fetestexcept(int __excepts) { - int __mxcsr, __status; + uint32_t __mxcsr; + uint16_t __status; __stmxcsr(&__mxcsr); __fnstsw(&__status); @@ -135,7 +137,7 @@ fetestexcept(int __excepts) static __inline int fegetround(void) { - int __control; + uint16_t __control; /* * We assume that the x87 and the SSE unit agree on the @@ -150,7 +152,8 @@ fegetround(void) static __inline int fesetround(int __round) { - int __mxcsr, __control; + uint32_t __mxcsr; + uint16_t __control; if (__round & ~_ROUND_MASK) return (-1); @@ -198,7 +201,7 @@ int fedisableexcept(int __mask); static __inline int fegetexcept(void) { - int __control; + uint16_t __control; /* * We assume that the masks for the x87 and the SSE unit are diff --git a/headers/posix/arch/x86_64/fpu.h b/headers/posix/arch/x86_64/fpu.h new file mode 100644 index 0000000000..a22d8ca1f8 --- /dev/null +++ b/headers/posix/arch/x86_64/fpu.h @@ -0,0 +1,218 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)npx.h 5.3 (Berkeley) 1/18/91 + * $FreeBSD$ + */ + +/* + * Floating Point Data Structures and Constants + * W. Jolitz 1/90 + */ + +#ifndef _X86_FPU_H_ +#define _X86_FPU_H_ + +#define __aligned(x) __attribute__((__aligned__(x))) + +/* Environment information of floating point unit. */ +struct env87 { + int32_t en_cw; /* control word (16bits) */ + int32_t en_sw; /* status word (16bits) */ + int32_t en_tw; /* tag word (16bits) */ + int32_t en_fip; /* fp instruction pointer */ + uint16_t en_fcs; /* fp code segment selector */ + uint16_t en_opcode; /* opcode last executed (11 bits) */ + int32_t en_foo; /* fp operand offset */ + int32_t en_fos; /* fp operand segment selector */ +}; + +/* Contents of each x87 floating point accumulator. */ +struct fpacc87 { + uint8_t fp_bytes[10]; +}; + +/* Floating point context. (i386 fnsave/frstor) */ +struct save87 { + struct env87 sv_env; /* floating point control/status */ + struct fpacc87 sv_ac[8]; /* accumulator contents, 0-7 */ + uint8_t sv_pad0[4]; /* saved status word (now unused) */ + /* + * Bogus padding for emulators. Emulators should use their own + * struct and arrange to store into this struct (ending here) + * before it is inspected for ptracing or for core dumps. Some + * emulators overwrite the whole struct. We have no good way of + * knowing how much padding to leave. Leave just enough for the + * GPL emulator's i387_union (176 bytes total). + */ + uint8_t sv_pad[64]; /* padding; used by emulators */ +}; + +/* Contents of each SSE extended accumulator. */ +struct xmmacc { + uint8_t xmm_bytes[16]; +}; + +/* Contents of the upper 16 bytes of each AVX extended accumulator. */ +struct ymmacc { + uint8_t ymm_bytes[16]; +}; + +/* Rename structs below depending on machine architecture. */ +#ifdef __i386__ +#define __envxmm32 envxmm +#else +#define __envxmm32 envxmm32 +#define __envxmm64 envxmm +#endif + +struct __envxmm32 { + uint16_t en_cw; /* control word (16bits) */ + uint16_t en_sw; /* status word (16bits) */ + uint16_t en_tw; /* tag word (16bits) */ + uint16_t en_opcode; /* opcode last executed (11 bits) */ + uint32_t en_fip; /* fp instruction pointer */ + uint16_t en_fcs; /* fp code segment selector */ + uint16_t en_pad0; /* padding */ + uint32_t en_foo; /* fp operand offset */ + uint16_t en_fos; /* fp operand segment selector */ + uint16_t en_pad1; /* padding */ + uint32_t en_mxcsr; /* SSE control/status register */ + uint32_t en_mxcsr_mask; /* valid bits in mxcsr */ +}; + +struct __envxmm64 { + uint16_t en_cw; /* control word (16bits) */ + uint16_t en_sw; /* status word (16bits) */ + uint8_t en_tw; /* tag word (8bits) */ + uint8_t en_zero; + uint16_t en_opcode; /* opcode last executed (11 bits ) */ + uint64_t en_rip; /* fp instruction pointer */ + uint64_t en_rdp; /* fp operand pointer */ + uint32_t en_mxcsr; /* SSE control/status register */ + uint32_t en_mxcsr_mask; /* valid bits in mxcsr */ +}; + +/* Floating point context. (i386 fxsave/fxrstor) */ +struct savexmm { + struct __envxmm32 sv_env; + struct { + struct fpacc87 fp_acc; + uint8_t fp_pad[6]; /* padding */ + } sv_fp[8]; + struct xmmacc sv_xmm[8]; + uint8_t sv_pad[224]; +} __aligned(16); + +#ifdef __i386__ +union savefpu { + struct save87 sv_87; + struct savexmm sv_xmm; +}; +#else +/* Floating point context. (amd64 fxsave/fxrstor) */ +struct savefpu { + struct __envxmm64 sv_env; + struct { + struct fpacc87 fp_acc; + uint8_t fp_pad[6]; /* padding */ + } sv_fp[8]; + struct xmmacc sv_xmm[16]; + uint8_t sv_pad[96]; +} __aligned(16); +#endif + +struct xstate_hdr { + uint64_t xstate_bv; + uint8_t xstate_rsrv0[16]; + uint8_t xstate_rsrv[40]; +}; + +struct savexmm_xstate { + struct xstate_hdr sx_hd; + struct ymmacc sx_ymm[16]; +}; + +struct savexmm_ymm { + struct __envxmm32 sv_env; + struct { + struct fpacc87 fp_acc; + int8_t fp_pad[6]; /* padding */ + } sv_fp[8]; + struct xmmacc sv_xmm[16]; + uint8_t sv_pad[96]; + struct savexmm_xstate sv_xstate; +} __aligned(64); + +struct savefpu_xstate { + struct xstate_hdr sx_hd; + struct ymmacc sx_ymm[16]; +}; + +struct savefpu_ymm { + struct __envxmm64 sv_env; + struct { + struct fpacc87 fp_acc; + int8_t fp_pad[6]; /* padding */ + } sv_fp[8]; + struct xmmacc sv_xmm[16]; + uint8_t sv_pad[96]; + struct savefpu_xstate sv_xstate; +} __aligned(64); + +#undef __envxmm32 +#undef __envxmm64 + +/* + * The hardware default control word for i387's and later coprocessors is + * 0x37F, giving: + * + * round to nearest + * 64-bit precision + * all exceptions masked. + * + * FreeBSD/i386 uses 53 bit precision for things like fadd/fsub/fsqrt etc + * because of the difference between memory and fpu register stack arguments. + * If its using an intermediate fpu register, it has 80/64 bits to work + * with. If it uses memory, it has 64/53 bits to work with. However, + * gcc is aware of this and goes to a fair bit of trouble to make the + * best use of it. + * + * This is mostly academic for AMD64, because the ABI prefers the use + * SSE2 based math. For FreeBSD/amd64, we go with the default settings. + */ +#define __INITIAL_FPUCW__ 0x037F +#define __INITIAL_FPUCW_I386__ 0x127F +#define __INITIAL_NPXCW__ __INITIAL_FPUCW_I386__ +#define __INITIAL_MXCSR__ 0x1F80 +#define __INITIAL_MXCSR_MASK__ 0xFFBF + +#endif /* !_X86_FPU_H_ */ diff --git a/headers/posix/fenv.h b/headers/posix/fenv.h index 0fb1e203c9..31fdd0b851 100644 --- a/headers/posix/fenv.h +++ b/headers/posix/fenv.h @@ -3,7 +3,7 @@ #if defined(__INTEL__) # include -#elif defined(_x86_64_) +#elif defined(__x86_64__) # include #elif defined(__ARM__) # include diff --git a/src/system/libroot/posix/arch/x86_64/Jamfile b/src/system/libroot/posix/arch/x86_64/Jamfile index cbbe85108d..5891f1b3e5 100644 --- a/src/system/libroot/posix/arch/x86_64/Jamfile +++ b/src/system/libroot/posix/arch/x86_64/Jamfile @@ -8,7 +8,7 @@ local genericSources = ; MergeObject posix_arch_$(TARGET_ARCH).o : - #fenv.c + fenv.c sigsetjmp.S siglongjmp.S diff --git a/src/system/libroot/posix/arch/x86_64/fenv.c b/src/system/libroot/posix/arch/x86_64/fenv.c new file mode 100644 index 0000000000..861f6217a9 --- /dev/null +++ b/src/system/libroot/posix/arch/x86_64/fenv.c @@ -0,0 +1,158 @@ +/*- + * Copyright (c) 2004-2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include + +const fenv_t __fe_dfl_env = { + { 0xffff0000 | __INITIAL_FPUCW__, + 0xffff0000, + 0xffffffff, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff } + }, + __INITIAL_MXCSR__ +}; + +extern inline int feclearexcept(int __excepts); +extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts); + +int +fesetexceptflag(const fexcept_t *flagp, int excepts) +{ + fenv_t env; + + __fnstenv(&env.__x87); + env.__x87.__status &= ~excepts; + env.__x87.__status |= *flagp & excepts; + __fldenv(env.__x87); + + __stmxcsr(&env.__mxcsr); + env.__mxcsr &= ~excepts; + env.__mxcsr |= *flagp & excepts; + __ldmxcsr(env.__mxcsr); + + return (0); +} + +int +feraiseexcept(int excepts) +{ + fexcept_t ex = excepts; + + fesetexceptflag(&ex, excepts); + __fwait(); + return (0); +} + +extern inline int fetestexcept(int __excepts); +extern inline int fegetround(void); +extern inline int fesetround(int __round); + +int +fegetenv(fenv_t *envp) +{ + + __fnstenv(&envp->__x87); + __stmxcsr(&envp->__mxcsr); + /* + * fnstenv masks all exceptions, so we need to restore the + * control word to avoid this side effect. + */ + __fldcw(envp->__x87.__control); + return (0); +} + +int +feholdexcept(fenv_t *envp) +{ + uint32_t mxcsr; + + __stmxcsr(&mxcsr); + __fnstenv(&envp->__x87); + __fnclex(); + envp->__mxcsr = mxcsr; + mxcsr &= ~FE_ALL_EXCEPT; + mxcsr |= FE_ALL_EXCEPT << _SSE_EMASK_SHIFT; + __ldmxcsr(mxcsr); + return (0); +} + +extern inline int fesetenv(const fenv_t *__envp); + +int +feupdateenv(const fenv_t *envp) +{ + uint32_t mxcsr; + uint16_t status; + + __fnstsw(&status); + __stmxcsr(&mxcsr); + fesetenv(envp); + feraiseexcept((mxcsr | status) & FE_ALL_EXCEPT); + return (0); +} + +int +__feenableexcept(int mask) +{ + uint32_t mxcsr, omask; + uint16_t control; + + mask &= FE_ALL_EXCEPT; + __fnstcw(&control); + __stmxcsr(&mxcsr); + omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; + control &= ~mask; + __fldcw(control); + mxcsr &= ~(mask << _SSE_EMASK_SHIFT); + __ldmxcsr(mxcsr); + return (omask); +} + +int +__fedisableexcept(int mask) +{ + uint32_t mxcsr, omask; + uint16_t control; + + mask &= FE_ALL_EXCEPT; + __fnstcw(&control); + __stmxcsr(&mxcsr); + omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; + control |= mask; + __fldcw(control); + mxcsr |= mask << _SSE_EMASK_SHIFT; + __ldmxcsr(mxcsr); + return (omask); +} + +__weak_reference(__feenableexcept, feenableexcept); +__weak_reference(__fedisableexcept, fedisableexcept);