From 6640579610856168a64e12c097ce012c46648e00 Mon Sep 17 00:00:00 2001 From: Justin Hibbits Date: Wed, 5 May 2021 09:20:56 -0500 Subject: [PATCH] msun fixes for SPE Summary: Fix FPU exception management for powerpcspe. Bits are in a different place from the standard FPSCR, so we need to handle the shifting differences. Also, there's no concept of a "software exception" raise, so we need to do exceptional math to trigger the exception from software. Reviewed By: alfredo Differential Revision: https://reviews.freebsd.org/D22824 --- lib/msun/powerpc/fenv.c | 30 ++++++++++++++++++++++++++++++ lib/msun/powerpc/fenv.h | 19 ++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/lib/msun/powerpc/fenv.c b/lib/msun/powerpc/fenv.c index b7e611ed99a0..7f7d98515995 100644 --- a/lib/msun/powerpc/fenv.c +++ b/lib/msun/powerpc/fenv.c @@ -30,6 +30,10 @@ #define __fenv_static #include "fenv.h" +#ifdef __SPE__ +#include +#include +#endif #ifdef __GNUC_GNU_INLINE__ #error "This file must be compiled with C99 'inline' semantics" @@ -40,7 +44,9 @@ const fenv_t __fe_dfl_env = 0x00000000; extern inline int feclearexcept(int __excepts); extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts); extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts); +#ifndef __SPE__ extern inline int feraiseexcept(int __excepts); +#endif extern inline int fetestexcept(int __excepts); extern inline int fegetround(void); extern inline int fesetround(int __round); @@ -48,3 +54,27 @@ extern inline int fegetenv(fenv_t *__envp); extern inline int feholdexcept(fenv_t *__envp); extern inline int fesetenv(const fenv_t *__envp); extern inline int feupdateenv(const fenv_t *__envp); + +#ifdef __SPE__ +#define PMAX 0x7f7fffff +#define PMIN 0x00800000 +int feraiseexcept(int __excepts) +{ + uint32_t spefscr; + + spefscr = mfspr(SPR_SPEFSCR); + mtspr(SPR_SPEFSCR, spefscr | (__excepts & FE_ALL_EXCEPT)); + + if (__excepts & FE_INVALID) + __asm __volatile ("efsdiv %0, %0, %1" :: "r"(0), "r"(0)); + if (__excepts & FE_DIVBYZERO) + __asm __volatile ("efsdiv %0, %0, %1" :: "r"(1.0f), "r"(0)); + if (__excepts & FE_UNDERFLOW) + __asm __volatile ("efsmul %0, %0, %0" :: "r"(PMIN)); + if (__excepts & FE_OVERFLOW) + __asm __volatile ("efsadd %0, %0, %0" :: "r"(PMAX)); + if (__excepts & FE_INEXACT) + __asm __volatile ("efssub %0, %0, %1" :: "r"(PMIN), "r"(1.0f)); + return (0); +} +#endif diff --git a/lib/msun/powerpc/fenv.h b/lib/msun/powerpc/fenv.h index d054220678c2..21a70df3d104 100644 --- a/lib/msun/powerpc/fenv.h +++ b/lib/msun/powerpc/fenv.h @@ -42,6 +42,17 @@ typedef __uint32_t fenv_t; typedef __uint32_t fexcept_t; /* Exception flags */ +#ifdef __SPE__ +#define FE_OVERFLOW 0x00000100 +#define FE_UNDERFLOW 0x00000200 +#define FE_DIVBYZERO 0x00000400 +#define FE_INVALID 0x00000800 +#define FE_INEXACT 0x00001000 + +#define FE_ALL_INVALID FE_INVALID + +#define _FPUSW_SHIFT 6 +#else #define FE_INEXACT 0x02000000 #define FE_DIVBYZERO 0x04000000 #define FE_UNDERFLOW 0x08000000 @@ -67,6 +78,9 @@ typedef __uint32_t fexcept_t; #define FE_ALL_INVALID (FE_VXCVI | FE_VXSQRT | FE_VXSOFT | FE_VXVC | \ FE_VXIMZ | FE_VXZDZ | FE_VXIDI | FE_VXISI | \ FE_VXSNAN | FE_INVALID) + +#define _FPUSW_SHIFT 22 +#endif #define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | \ FE_ALL_INVALID | FE_OVERFLOW | FE_UNDERFLOW) @@ -85,7 +99,6 @@ extern const fenv_t __fe_dfl_env; #define FE_DFL_ENV (&__fe_dfl_env) /* We need to be able to map status flag positions to mask flag positions */ -#define _FPUSW_SHIFT 22 #define _ENABLE_MASK ((FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \ FE_OVERFLOW | FE_UNDERFLOW) >> _FPUSW_SHIFT) @@ -156,6 +169,9 @@ fesetexceptflag(const fexcept_t *__flagp, int __excepts) return (0); } +#ifdef __SPE__ +extern int feraiseexcept(int __excepts); +#else __fenv_static inline int feraiseexcept(int __excepts) { @@ -168,6 +184,7 @@ feraiseexcept(int __excepts) __mtfsf(__r); return (0); } +#endif __fenv_static inline int fetestexcept(int __excepts)