Prechádzať zdrojové kódy

Support powerpc

This fixes #113, based on files from FreeBSD. Tested on machine hosted by [OSUOSL](http://osuosl.org/services/powerdev/).
Simon Byrne 9 rokov pred
rodič
commit
830dc991f3

+ 5 - 0
Make.inc

@@ -48,7 +48,12 @@ endif
 CFLAGS_add += -std=c99 -Wall -I$(OPENLIBM_HOME) -I$(OPENLIBM_HOME)/include -I$(OPENLIBM_HOME)/ld80 -I$(OPENLIBM_HOME)/$(ARCH) -I$(OPENLIBM_HOME)/src -DASSEMBLER -D__BSD_VISIBLE -Wno-implicit-function-declaration
 
 # The optimization flag may be overriden with the environment variable CFLAGS.
+ifeq ($(ARCH),powerpc)
+# tests hang at higher optimization levels
+CFLAGS ?= -O0
+else
 CFLAGS ?= -O2
+endif
 
 default: all
 

+ 3 - 1
Makefile

@@ -3,8 +3,10 @@ include ./Make.inc
 
 SUBDIRS = src $(ARCH) bsdsrc
 ifneq ($(ARCH), arm)
+ifneq ($(ARCH), powerpc)
 SUBDIRS += ld80
 endif
+endif
 
 define INC_template
 TEST=test
@@ -26,7 +28,7 @@ OBJS =  $(patsubst %.f,%.f.o,\
 
 .PHONY: all check test clean distclean install
 
-all: libopenlibm.a libopenlibm.$(SHLIB_EXT) 
+all: libopenlibm.a libopenlibm.$(SHLIB_EXT)
 
 check test: test/test-double test/test-float
 	test/test-double

+ 2 - 0
include/openlibm_fenv.h

@@ -8,6 +8,8 @@
 #include <openlibm_fenv_amd64.h>
 #elif defined(__i386__)
 #include <openlibm_fenv_i387.h>
+#elif defined(__powerpc__)
+#include <openlibm_fenv_powerpc.h>
 #else
 #error "Unsupported platform"
 #endif

+ 274 - 0
include/openlibm_fenv_powerpc.h

@@ -0,0 +1,274 @@
+/*-
+ * Copyright (c) 2004-2005 David Schultz <[email protected]>
+ * 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$
+ */
+
+#ifndef	_FENV_H_
+#define	_FENV_H_
+
+#include <sys/types.h>
+
+#ifndef	__fenv_static
+#define	__fenv_static	static
+#endif
+
+typedef	__uint32_t	fenv_t;
+typedef	__uint32_t	fexcept_t;
+
+/* Exception flags */
+#define	FE_INEXACT	0x02000000
+#define	FE_DIVBYZERO	0x04000000
+#define	FE_UNDERFLOW	0x08000000
+#define	FE_OVERFLOW	0x10000000
+#define	FE_INVALID	0x20000000	/* all types of invalid FP ops */
+
+/*
+ * The PowerPC architecture has extra invalid flags that indicate the
+ * specific type of invalid operation occurred.  These flags may be
+ * tested, set, and cleared---but not masked---separately.  All of
+ * these bits are cleared when FE_INVALID is cleared, but only
+ * FE_VXSOFT is set when FE_INVALID is explicitly set in software.
+ */
+#define	FE_VXCVI	0x00000100	/* invalid integer convert */
+#define	FE_VXSQRT	0x00000200	/* square root of a negative */
+#define	FE_VXSOFT	0x00000400	/* software-requested exception */
+#define	FE_VXVC		0x00080000	/* ordered comparison involving NaN */
+#define	FE_VXIMZ	0x00100000	/* inf * 0 */
+#define	FE_VXZDZ	0x00200000	/* 0 / 0 */
+#define	FE_VXIDI	0x00400000	/* inf / inf */
+#define	FE_VXISI	0x00800000	/* inf - inf */
+#define	FE_VXSNAN	0x01000000	/* operation on a signalling NaN */
+#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	FE_ALL_EXCEPT	(FE_DIVBYZERO | FE_INEXACT | \
+			 FE_ALL_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
+
+/* Rounding modes */
+#define	FE_TONEAREST	0x0000
+#define	FE_TOWARDZERO	0x0001
+#define	FE_UPWARD	0x0002
+#define	FE_DOWNWARD	0x0003
+#define	_ROUND_MASK	(FE_TONEAREST | FE_DOWNWARD | \
+			 FE_UPWARD | FE_TOWARDZERO)
+
+__BEGIN_DECLS
+
+/* Default floating-point environment */
+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)
+
+#ifndef _SOFT_FLOAT
+#define	__mffs(__env)	__asm __volatile("mffs %0" : "=f" (*(__env)))
+#define	__mtfsf(__env)	__asm __volatile("mtfsf 255,%0" : : "f" (__env))
+#else
+#define	__mffs(__env)
+#define	__mtfsf(__env)
+#endif
+
+union __fpscr {
+	double __d;
+	struct {
+		__uint32_t __junk;
+		fenv_t __reg;
+	} __bits;
+};
+
+__fenv_static inline int
+feclearexcept(int __excepts)
+{
+	union __fpscr __r;
+
+	if (__excepts & FE_INVALID)
+		__excepts |= FE_ALL_INVALID;
+	__mffs(&__r.__d);
+	__r.__bits.__reg &= ~__excepts;
+	__mtfsf(__r.__d);
+	return (0);
+}
+
+__fenv_static inline int
+fegetexceptflag(fexcept_t *__flagp, int __excepts)
+{
+	union __fpscr __r;
+
+	__mffs(&__r.__d);
+	*__flagp = __r.__bits.__reg & __excepts;
+	return (0);
+}
+
+__fenv_static inline int
+fesetexceptflag(const fexcept_t *__flagp, int __excepts)
+{
+	union __fpscr __r;
+
+	if (__excepts & FE_INVALID)
+		__excepts |= FE_ALL_EXCEPT;
+	__mffs(&__r.__d);
+	__r.__bits.__reg &= ~__excepts;
+	__r.__bits.__reg |= *__flagp & __excepts;
+	__mtfsf(__r.__d);
+	return (0);
+}
+
+__fenv_static inline int
+feraiseexcept(int __excepts)
+{
+	union __fpscr __r;
+
+	if (__excepts & FE_INVALID)
+		__excepts |= FE_VXSOFT;
+	__mffs(&__r.__d);
+	__r.__bits.__reg |= __excepts;
+	__mtfsf(__r.__d);
+	return (0);
+}
+
+__fenv_static inline int
+fetestexcept(int __excepts)
+{
+	union __fpscr __r;
+
+	__mffs(&__r.__d);
+	return (__r.__bits.__reg & __excepts);
+}
+
+__fenv_static inline int
+fegetround(void)
+{
+	union __fpscr __r;
+
+	__mffs(&__r.__d);
+	return (__r.__bits.__reg & _ROUND_MASK);
+}
+
+__fenv_static inline int
+fesetround(int __round)
+{
+	union __fpscr __r;
+
+	if (__round & ~_ROUND_MASK)
+		return (-1);
+	__mffs(&__r.__d);
+	__r.__bits.__reg &= ~_ROUND_MASK;
+	__r.__bits.__reg |= __round;
+	__mtfsf(__r.__d);
+	return (0);
+}
+
+__fenv_static inline int
+fegetenv(fenv_t *__envp)
+{
+	union __fpscr __r;
+
+	__mffs(&__r.__d);
+	*__envp = __r.__bits.__reg;
+	return (0);
+}
+
+__fenv_static inline int
+feholdexcept(fenv_t *__envp)
+{
+	union __fpscr __r;
+
+	__mffs(&__r.__d);
+	*__envp = __r.__d;
+	__r.__bits.__reg &= ~(FE_ALL_EXCEPT | _ENABLE_MASK);
+	__mtfsf(__r.__d);
+	return (0);
+}
+
+__fenv_static inline int
+fesetenv(const fenv_t *__envp)
+{
+	union __fpscr __r;
+
+	__r.__bits.__reg = *__envp;
+	__mtfsf(__r.__d);
+	return (0);
+}
+
+__fenv_static inline int
+feupdateenv(const fenv_t *__envp)
+{
+	union __fpscr __r;
+
+	__mffs(&__r.__d);
+	__r.__bits.__reg &= FE_ALL_EXCEPT;
+	__r.__bits.__reg |= *__envp;
+	__mtfsf(__r.__d);
+	return (0);
+}
+
+#if __BSD_VISIBLE
+
+/* We currently provide no external definitions of the functions below. */
+
+static inline int
+feenableexcept(int __mask)
+{
+	union __fpscr __r;
+	fenv_t __oldmask;
+
+	__mffs(&__r.__d);
+	__oldmask = __r.__bits.__reg;
+	__r.__bits.__reg |= (__mask & FE_ALL_EXCEPT) >> _FPUSW_SHIFT;
+	__mtfsf(__r.__d);
+	return ((__oldmask & _ENABLE_MASK) << _FPUSW_SHIFT);
+}
+
+static inline int
+fedisableexcept(int __mask)
+{
+	union __fpscr __r;
+	fenv_t __oldmask;
+
+	__mffs(&__r.__d);
+	__oldmask = __r.__bits.__reg;
+	__r.__bits.__reg &= ~((__mask & FE_ALL_EXCEPT) >> _FPUSW_SHIFT);
+	__mtfsf(__r.__d);
+	return ((__oldmask & _ENABLE_MASK) << _FPUSW_SHIFT);
+}
+
+static inline int
+fegetexcept(void)
+{
+	union __fpscr __r;
+
+	__mffs(&__r.__d);
+	return ((__r.__bits.__reg & _ENABLE_MASK) << _FPUSW_SHIFT);
+}
+
+#endif /* __BSD_VISIBLE */
+
+__END_DECLS
+
+#endif	/* !_FENV_H_ */

+ 1 - 0
powerpc/Make.files

@@ -0,0 +1 @@
+$(CUR_SRCS) = fenv.c

+ 48 - 0
powerpc/fenv.c

@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2004 David Schultz <[email protected]>
+ * 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$
+ */
+
+#define	__fenv_static
+#include <openlibm_fenv.h>
+
+#ifdef __GNUC_GNU_INLINE__
+#error "This file must be compiled with C99 'inline' semantics"
+#endif
+
+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);
+extern inline int feraiseexcept(int __excepts);
+extern inline int fetestexcept(int __excepts);
+extern inline int fegetround(void);
+extern inline int fesetround(int __round);
+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);

+ 9 - 6
src/Make.files

@@ -4,7 +4,7 @@ $(CUR_SRCS) = common.c \
 	e_expf.c e_fmod.c e_fmodf.c \
 	e_hypot.c e_hypotf.c e_j0.c e_j0f.c e_j1.c e_j1f.c \
 	e_jn.c e_jnf.c e_lgamma.c e_lgamma_r.c e_lgammaf.c e_lgammaf_r.c \
-	e_lgammal.c e_log.c e_log10.c e_log10f.c e_log2.c e_log2f.c e_logf.c \
+	e_log.c e_log10.c e_log10f.c e_log2.c e_log2f.c e_logf.c \
 	e_pow.c e_powf.c e_remainder.c e_remainderf.c \
 	e_rem_pio2.c e_rem_pio2f.c \
 	e_sinh.c e_sinhf.c e_sqrt.c e_sqrtf.c \
@@ -20,12 +20,12 @@ $(CUR_SRCS) = common.c \
 	s_fminf.c s_fpclassify.c \
 	s_frexp.c s_frexpf.c s_ilogb.c s_ilogbf.c \
 	s_isinf.c s_isfinite.c s_isnormal.c s_isnan.c \
-	s_llrint.c s_llrintf.c s_llround.c s_llroundf.c s_llroundl.c \
+	s_llrint.c s_llrintf.c s_llround.c s_llroundf.c  \
 	s_log1p.c s_log1pf.c s_logb.c s_logbf.c s_lrint.c s_lrintf.c \
-	s_lround.c s_lroundf.c s_lroundl.c s_modf.c s_modff.c \
+	s_lround.c s_lroundf.c s_modf.c s_modff.c \
 	s_nearbyint.c s_nextafter.c s_nextafterf.c \
 	s_nexttowardf.c s_remquo.c s_remquof.c \
-	s_rint.c s_rintf.c s_round.c s_roundf.c s_roundl.c \
+	s_rint.c s_rintf.c s_round.c s_roundf.c \
 	s_scalbln.c s_scalbn.c s_scalbnf.c s_signbit.c \
 	s_signgam.c s_sin.c s_sincos.c \
 	s_sinf.c s_sincosf.c s_tan.c s_tanf.c s_tanh.c s_tanhf.c s_tgammaf.c \
@@ -37,17 +37,19 @@ $(CUR_SRCS) += s_nan.c
 endif
 
 ifneq ($(ARCH), arm)
+ifneq ($(ARCH), powerpc)
 # C99 long double functions
 $(CUR_SRCS) +=	s_copysignl.c s_fabsl.c s_llrintl.c s_lrintl.c s_modfl.c
 
 # If long double != double use these; otherwise, we alias the double versions.
 $(CUR_SRCS) +=	e_acosl.c e_asinl.c e_atan2l.c e_fmodl.c \
 	s_fmaxl.c s_fminl.c s_ilogbl.c \
-	e_hypotl.c e_remainderl.c e_sqrtl.c \
+	e_hypotl.c e_lgammal.c e_remainderl.c e_sqrtl.c \
 	s_atanl.c s_ceill.c s_cosl.c s_cprojl.c \
 	s_csqrtl.c s_floorl.c s_fmal.c \
 	s_frexpl.c s_logbl.c s_nexttoward.c \
-	s_remquol.c s_cpowl.c s_cargl.c \
+	s_remquol.c s_roundl.c s_lroundl.c s_llroundl.c \
+	s_cpowl.c s_cargl.c \
 	s_sinl.c s_sincosl.c s_tanl.c s_truncl.c w_cabsl.c \
 	s_nextafterl.c s_rintl.c s_scalbnl.c polevll.c \
 	s_casinl.c s_ctanl.c \
@@ -55,6 +57,7 @@ $(CUR_SRCS) +=	e_acosl.c e_asinl.c e_atan2l.c e_fmodl.c \
 	s_catanl.c s_csinl.c s_cacosl.c s_cexpl.c s_csinhl.c s_ccoshl.c \
 	s_clogl.c s_ctanhl.c s_ccosl.c s_cbrtl.c
 endif
+endif
 
 # C99 complex functions
 $(CUR_SRCS) +=	s_ccosh.c s_ccoshf.c s_cexp.c s_cexpf.c \

+ 2 - 0
src/fpmath.h

@@ -37,6 +37,8 @@
 #else 
 #include "i386_fpmath.h"
 #endif
+#elif defined(__powerpc__)
+#include "powerpc_fpmath.h"
 #endif
 
 #if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__)

+ 49 - 0
src/powerpc_fpmath.h

@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2003 David Schultz <[email protected]>
+ * 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$
+ */
+
+union IEEEl2bits {
+	long double	e;
+	struct {
+		unsigned int		sign	:1;
+		unsigned int		exp	:11;
+		unsigned int		manh	:20;
+		unsigned int		manl	:32;
+	} bits;
+};
+
+#define	mask_nbit_l(u)	((void)0)
+#define	LDBL_IMPLICIT_NBIT
+#define	LDBL_NBIT	0
+
+#define	LDBL_MANH_SIZE	20
+#define	LDBL_MANL_SIZE	32
+
+#define	LDBL_TO_ARRAY32(u, a) do {			\
+	(a)[0] = (uint32_t)(u).bits.manl;		\
+	(a)[1] = (uint32_t)(u).bits.manh;		\
+} while(0)

+ 0 - 1
src/s_nearbyint.c

@@ -54,4 +54,3 @@ fn(type x)			\
 
 DECL(double, nearbyint, rint)
 DECL(float, nearbyintf, rintf)
-DECL(long double, nearbyintl, rintl)

+ 22 - 0
src/s_rintl.c

@@ -28,6 +28,7 @@
 //__FBSDID("$FreeBSD: src/lib/msun/src/s_rintl.c,v 1.5 2008/02/22 11:59:05 bde Exp $");
 
 #include <float.h>
+#include <openlibm_fenv.h>
 #include <openlibm_math.h>
 
 #include "fpmath.h"
@@ -92,3 +93,24 @@ rintl(long double x)
 
 	return (x);
 }
+
+/*
+ * We save and restore the floating-point environment to avoid raising
+ * an inexact exception.  We can get away with using fesetenv()
+ * instead of feclearexcept()/feupdateenv() to restore the environment
+ * because the only exception defined for rint() is overflow, and
+ * rounding can't overflow as long as emax >= p.
+ */
+#define	DECL(type, fn, rint)	\
+DLLEXPORT type				\
+fn(type x)			\
+{				\
+	type ret;		\
+	fenv_t env;		\
+				\
+	fegetenv(&env);		\
+	ret = rint(x);		\
+	fesetenv(&env);		\
+	return (ret);		\
+}
+DECL(long double, nearbyintl, rintl)