Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d2b194ed authored by Kumar Gala's avatar Kumar Gala
Browse files

powerpc/math-emu: Use kernel generic math-emu code



The math emulation code is centered around a set of generic macros that
provide the core of the emulation that are shared by the various
architectures and other projects (like glibc).  Each arch implements its
own sfp-machine.h to specific various arch specific details.

For historic reasons that are now lost the powerpc math-emu code had
its own version of the common headers.  This moves us to using the
kernel generic version and thus getting fixes when those are updated.

Also cleaned up exception/error reporting from the FP emulation functions.

Signed-off-by: default avatarKumar Gala <galak@kernel.crashing.org>
parent a969e76a
Loading
Loading
Loading
Loading
+45 −69
Original line number Diff line number Diff line
@@ -79,27 +79,44 @@
 * #define _FP_DIV_MEAT_D(R,X,Y)   _FP_DIV_MEAT_2_udiv_64(D,R,X,Y)
 */

#define _FP_MUL_MEAT_S(R,X,Y)   _FP_MUL_MEAT_1_wide(S,R,X,Y,umul_ppmm)
#define _FP_MUL_MEAT_D(R,X,Y)   _FP_MUL_MEAT_2_wide(D,R,X,Y,umul_ppmm)
#define _FP_MUL_MEAT_S(R,X,Y)   _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm)
#define _FP_MUL_MEAT_D(R,X,Y)   _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)

#define _FP_DIV_MEAT_S(R,X,Y)	_FP_DIV_MEAT_1_udiv(S,R,X,Y)
#define _FP_DIV_MEAT_D(R,X,Y)   _FP_DIV_MEAT_2_udiv_64(D,R,X,Y)
#define _FP_DIV_MEAT_D(R,X,Y)	_FP_DIV_MEAT_2_udiv(D,R,X,Y)

/* These macros define what NaN looks like. They're supposed to expand to
 * a comma-separated set of 32bit unsigned ints that encode NaN.
 */
#define _FP_NANFRAC_S		_FP_QNANBIT_S
#define _FP_NANFRAC_D		_FP_QNANBIT_D, 0
#define _FP_NANFRAC_Q           _FP_QNANBIT_Q, 0, 0, 0
#define _FP_NANFRAC_S		((_FP_QNANBIT_S << 1) - 1)
#define _FP_NANFRAC_D		((_FP_QNANBIT_D << 1) - 1), -1
#define _FP_NANFRAC_Q		((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1
#define _FP_NANSIGN_S		0
#define _FP_NANSIGN_D		0
#define _FP_NANSIGN_Q		0

#define _FP_KEEPNANFRACP 1

/* Exception flags.  We use the bit positions of the appropriate bits
   in the FPSCR, which also correspond to the FE_* bits.  This makes
   everything easier ;-).  */
#define FP_EX_INVALID         (1 << (31 - 2))
#define FP_EX_INVALID_SNAN	EFLAG_VXSNAN
#define FP_EX_INVALID_ISI	EFLAG_VXISI
#define FP_EX_INVALID_IDI	EFLAG_VXIDI
#define FP_EX_INVALID_ZDZ	EFLAG_VXZDZ
#define FP_EX_INVALID_IMZ	EFLAG_VXIMZ
#define FP_EX_OVERFLOW        (1 << (31 - 3))
#define FP_EX_UNDERFLOW       (1 << (31 - 4))
#define FP_EX_DIVZERO         (1 << (31 - 5))
#define FP_EX_INEXACT         (1 << (31 - 6))

/* This macro appears to be called when both X and Y are NaNs, and
 * has to choose one and copy it to R. i386 goes for the larger of the
 * two, sparc64 just picks Y. I don't understand this at all so I'll
 * go with sparc64 because it's shorter :->   -- PMM
 */
#define _FP_CHOOSENAN(fs, wc, R, X, Y)			\
#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP)		\
  do {							\
    R##_s = Y##_s;					\
    _FP_FRAC_COPY_##wc(R,Y);				\
@@ -107,62 +124,6 @@
  } while (0)


extern void fp_unpack_d(long *, unsigned long *, unsigned long *,
			long *, long *, void *);
extern int  fp_pack_d(void *, long, unsigned long, unsigned long, long, long);
extern int  fp_pack_ds(void *, long, unsigned long, unsigned long, long, long);

#define __FP_UNPACK_RAW_1(fs, X, val)			\
  do {							\
    union _FP_UNION_##fs *_flo =			\
    	(union _FP_UNION_##fs *)val;			\
							\
    X##_f = _flo->bits.frac;				\
    X##_e = _flo->bits.exp;				\
    X##_s = _flo->bits.sign;				\
  } while (0)

#define __FP_UNPACK_RAW_2(fs, X, val)			\
  do {							\
    union _FP_UNION_##fs *_flo =			\
    	(union _FP_UNION_##fs *)val;			\
							\
    X##_f0 = _flo->bits.frac0;				\
    X##_f1 = _flo->bits.frac1;				\
    X##_e  = _flo->bits.exp;				\
    X##_s  = _flo->bits.sign;				\
  } while (0)

#define __FP_UNPACK_S(X,val)		\
  do {					\
    __FP_UNPACK_RAW_1(S,X,val);		\
    _FP_UNPACK_CANONICAL(S,1,X);	\
  } while (0)

#define __FP_UNPACK_D(X,val)		\
	fp_unpack_d(&X##_s, &X##_f1, &X##_f0, &X##_e, &X##_c, val)

#define __FP_PACK_RAW_1(fs, val, X)			\
  do {							\
    union _FP_UNION_##fs *_flo =			\
    	(union _FP_UNION_##fs *)val;			\
							\
    _flo->bits.frac = X##_f;				\
    _flo->bits.exp  = X##_e;				\
    _flo->bits.sign = X##_s;				\
  } while (0)

#define __FP_PACK_RAW_2(fs, val, X)			\
  do {							\
    union _FP_UNION_##fs *_flo =			\
    	(union _FP_UNION_##fs *)val;			\
							\
    _flo->bits.frac0 = X##_f0;				\
    _flo->bits.frac1 = X##_f1;				\
    _flo->bits.exp   = X##_e;				\
    _flo->bits.sign  = X##_s;				\
  } while (0)

#include <linux/kernel.h>
#include <linux/sched.h>

@@ -182,15 +143,30 @@ extern int fp_pack_ds(void *, long, unsigned long, unsigned long, long, long);
#define __FP_PACK_S(val,X)			\
({  int __exc = _FP_PACK_CANONICAL(S,1,X);	\
    if(!__exc || !__FPU_TRAP_P(__exc))		\
        __FP_PACK_RAW_1(S,val,X);		\
        _FP_PACK_RAW_1_P(S,val,X);		\
    __exc;					\
})

#define __FP_PACK_D(val,X)			\
	fp_pack_d(val, X##_s, X##_f1, X##_f0, X##_e, X##_c)
   do {									\
	_FP_PACK_CANONICAL(D, 2, X);					\
	if (!FP_CUR_EXCEPTIONS || !__FPU_TRAP_P(FP_CUR_EXCEPTIONS))	\
		_FP_PACK_RAW_2_P(D, val, X);				\
   } while (0)

#define __FP_PACK_DS(val,X)							\
	fp_pack_ds(val, X##_s, X##_f1, X##_f0, X##_e, X##_c)
   do {										\
	   FP_DECL_S(__X);							\
	   FP_CONV(S, D, 1, 2, __X, X);						\
	   _FP_PACK_CANONICAL(S, 1, __X);					\
	   if (!FP_CUR_EXCEPTIONS || !__FPU_TRAP_P(FP_CUR_EXCEPTIONS)) {	\
		   _FP_UNPACK_CANONICAL(S, 1, __X);				\
		   FP_CONV(D, S, 2, 1, X, __X);					\
		   _FP_PACK_CANONICAL(D, 2, X);					\
		   if (!FP_CUR_EXCEPTIONS || !__FPU_TRAP_P(FP_CUR_EXCEPTIONS))	\
		   _FP_PACK_RAW_2_P(D, val, X);					\
	   }									\
   } while (0)

/* Obtain the current rounding mode. */
#define FP_ROUNDMODE			\
+4 −3
Original line number Diff line number Diff line
@@ -4,13 +4,14 @@ obj-y := math.o fmr.o lfd.o stfd.o
obj-$(CONFIG_MATH_EMULATION)	+= fabs.o fadd.o fadds.o fcmpo.o fcmpu.o \
					fctiw.o fctiwz.o fdiv.o fdivs.o \
					fmadd.o fmadds.o fmsub.o fmsubs.o \
					fmul.o fmuls.o fnabs.o fneg.o types.o \
					fmul.o fmuls.o fnabs.o fneg.o \
					fnmadd.o fnmadds.o fnmsub.o fnmsubs.o \
					fres.o frsp.o frsqrte.o fsel.o lfs.o \
					fsqrt.o	fsqrts.o fsub.o fsubs.o \
					mcrfs.o mffs.o mtfsb0.o mtfsb1.o \
					mtfsf.o mtfsfi.o stfiwx.o stfs.o \
					udivmodti4.o
					mtfsf.o mtfsfi.o stfiwx.o stfs.o

CFLAGS_fabs.o = -fno-builtin-fabs
CFLAGS_math.o = -fno-builtin-fabs

EXTRA_CFLAGS = -I. -Iinclude/math-emu -w

arch/powerpc/math-emu/double.h

deleted100644 → 0
+0 −129
Original line number Diff line number Diff line
/*
 * Definitions for IEEE Double Precision
 */

#if _FP_W_TYPE_SIZE < 32
#error "Here's a nickel kid.  Go buy yourself a real computer."
#endif

#if _FP_W_TYPE_SIZE < 64
#define _FP_FRACTBITS_D		(2 * _FP_W_TYPE_SIZE)
#else
#define _FP_FRACTBITS_D		_FP_W_TYPE_SIZE
#endif

#define _FP_FRACBITS_D		53
#define _FP_FRACXBITS_D		(_FP_FRACTBITS_D - _FP_FRACBITS_D)
#define _FP_WFRACBITS_D		(_FP_WORKBITS + _FP_FRACBITS_D)
#define _FP_WFRACXBITS_D	(_FP_FRACTBITS_D - _FP_WFRACBITS_D)
#define _FP_EXPBITS_D		11
#define _FP_EXPBIAS_D		1023
#define _FP_EXPMAX_D		2047

#define _FP_QNANBIT_D		\
	((_FP_W_TYPE)1 << ((_FP_FRACBITS_D-2) % _FP_W_TYPE_SIZE))
#define _FP_IMPLBIT_D		\
	((_FP_W_TYPE)1 << ((_FP_FRACBITS_D-1) % _FP_W_TYPE_SIZE))
#define _FP_OVERFLOW_D		\
	((_FP_W_TYPE)1 << (_FP_WFRACBITS_D % _FP_W_TYPE_SIZE))

#if _FP_W_TYPE_SIZE < 64

union _FP_UNION_D
{
  double flt;
  struct {
#if __BYTE_ORDER == __BIG_ENDIAN
    unsigned sign  : 1;
    unsigned exp   : _FP_EXPBITS_D;
    unsigned frac1 : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0) - _FP_W_TYPE_SIZE;
    unsigned frac0 : _FP_W_TYPE_SIZE;
#else
    unsigned frac0 : _FP_W_TYPE_SIZE;
    unsigned frac1 : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0) - _FP_W_TYPE_SIZE;
    unsigned exp   : _FP_EXPBITS_D;
    unsigned sign  : 1;
#endif
  } bits __attribute__((packed));
};

#define FP_DECL_D(X)		_FP_DECL(2,X)
#define FP_UNPACK_RAW_D(X,val)	_FP_UNPACK_RAW_2(D,X,val)
#define FP_PACK_RAW_D(val,X)	_FP_PACK_RAW_2(D,val,X)

#define FP_UNPACK_D(X,val)		\
  do {					\
    _FP_UNPACK_RAW_2(D,X,val);		\
    _FP_UNPACK_CANONICAL(D,2,X);	\
  } while (0)

#define FP_PACK_D(val,X)		\
  do {					\
    _FP_PACK_CANONICAL(D,2,X);		\
    _FP_PACK_RAW_2(D,val,X);		\
  } while (0)

#define FP_NEG_D(R,X)		_FP_NEG(D,2,R,X)
#define FP_ADD_D(R,X,Y)		_FP_ADD(D,2,R,X,Y)
#define FP_SUB_D(R,X,Y)		_FP_SUB(D,2,R,X,Y)
#define FP_MUL_D(R,X,Y)		_FP_MUL(D,2,R,X,Y)
#define FP_DIV_D(R,X,Y)		_FP_DIV(D,2,R,X,Y)
#define FP_SQRT_D(R,X)		_FP_SQRT(D,2,R,X)

#define FP_CMP_D(r,X,Y,un)	_FP_CMP(D,2,r,X,Y,un)
#define FP_CMP_EQ_D(r,X,Y)	_FP_CMP_EQ(D,2,r,X,Y)

#define FP_TO_INT_D(r,X,rsz,rsg)  _FP_TO_INT(D,2,r,X,rsz,rsg)
#define FP_FROM_INT_D(X,r,rs,rt)  _FP_FROM_INT(D,2,X,r,rs,rt)

#else

union _FP_UNION_D
{
  double flt;
  struct {
#if __BYTE_ORDER == __BIG_ENDIAN
    unsigned sign : 1;
    unsigned exp  : _FP_EXPBITS_D;
    unsigned long frac : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0);
#else
    unsigned long frac : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0);
    unsigned exp  : _FP_EXPBITS_D;
    unsigned sign : 1;
#endif
  } bits __attribute__((packed));
};

#define FP_DECL_D(X)		_FP_DECL(1,X)
#define FP_UNPACK_RAW_D(X,val)	_FP_UNPACK_RAW_1(D,X,val)
#define FP_PACK_RAW_D(val,X)	_FP_PACK_RAW_1(D,val,X)

#define FP_UNPACK_D(X,val)		\
  do {					\
    _FP_UNPACK_RAW_1(D,X,val);		\
    _FP_UNPACK_CANONICAL(D,1,X);	\
  } while (0)

#define FP_PACK_D(val,X)		\
  do {					\
    _FP_PACK_CANONICAL(D,1,X);		\
    _FP_PACK_RAW_1(D,val,X);		\
  } while (0)

#define FP_NEG_D(R,X)		_FP_NEG(D,1,R,X)
#define FP_ADD_D(R,X,Y)		_FP_ADD(D,1,R,X,Y)
#define FP_SUB_D(R,X,Y)		_FP_SUB(D,1,R,X,Y)
#define FP_MUL_D(R,X,Y)		_FP_MUL(D,1,R,X,Y)
#define FP_DIV_D(R,X,Y)		_FP_DIV(D,1,R,X,Y)
#define FP_SQRT_D(R,X)		_FP_SQRT(D,1,R,X)

/* The implementation of _FP_MUL_D and _FP_DIV_D should be chosen by
   the target machine.  */

#define FP_CMP_D(r,X,Y,un)	_FP_CMP(D,1,r,X,Y,un)
#define FP_CMP_EQ_D(r,X,Y)	_FP_CMP_EQ(D,1,r,X,Y)

#define FP_TO_INT_D(r,X,rsz,rsg)  _FP_TO_INT(D,1,r,X,rsz,rsg)
#define FP_FROM_INT_D(X,r,rs,rt)  _FP_FROM_INT(D,1,X,r,rs,rt)

#endif /* W_TYPE_SIZE < 64 */
+9 −8
Original line number Diff line number Diff line
@@ -2,8 +2,9 @@
#include <linux/errno.h>
#include <asm/uaccess.h>

#include "soft-fp.h"
#include "double.h"
#include <asm/sfp-machine.h>
#include <math-emu/soft-fp.h>
#include <math-emu/double.h>

int
fadd(void *frD, void *frA, void *frB)
@@ -11,28 +12,28 @@ fadd(void *frD, void *frA, void *frB)
	FP_DECL_D(A);
	FP_DECL_D(B);
	FP_DECL_D(R);
	FP_DECL_EX;
	int ret = 0;

#ifdef DEBUG
	printk("%s: %p %p %p\n", __func__, frD, frA, frB);
#endif

	__FP_UNPACK_D(A, frA);
	__FP_UNPACK_D(B, frB);
	FP_UNPACK_DP(A, frA);
	FP_UNPACK_DP(B, frB);

#ifdef DEBUG
	printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
	printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
#endif

	if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF)
		ret |= EFLAG_VXISI;

	FP_ADD_D(R, A, B);

#ifdef DEBUG
	printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
#endif

	return (ret | __FP_PACK_D(frD, R));
	__FP_PACK_D(frD, R);

	return FP_CUR_EXCEPTIONS;
}
+10 −10
Original line number Diff line number Diff line
@@ -2,9 +2,10 @@
#include <linux/errno.h>
#include <asm/uaccess.h>

#include "soft-fp.h"
#include "double.h"
#include "single.h"
#include <asm/sfp-machine.h>
#include <math-emu/soft-fp.h>
#include <math-emu/double.h>
#include <math-emu/single.h>

int
fadds(void *frD, void *frA, void *frB)
@@ -12,28 +13,27 @@ fadds(void *frD, void *frA, void *frB)
	FP_DECL_D(A);
	FP_DECL_D(B);
	FP_DECL_D(R);
	int ret = 0;
	FP_DECL_EX;

#ifdef DEBUG
	printk("%s: %p %p %p\n", __func__, frD, frA, frB);
#endif

	__FP_UNPACK_D(A, frA);
	__FP_UNPACK_D(B, frB);
	FP_UNPACK_DP(A, frA);
	FP_UNPACK_DP(B, frB);

#ifdef DEBUG
	printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
	printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
#endif

	if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF)
		ret |= EFLAG_VXISI;

	FP_ADD_D(R, A, B);

#ifdef DEBUG
	printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
#endif

	return (ret | __FP_PACK_DS(frD, R));
	__FP_PACK_DS(frD, R);

	return FP_CUR_EXCEPTIONS;
}
Loading