alpha: Streamline __setfpucw

The convert_bit macro allows the compiler to translate the bit
positions more efficiently.  The assumption of only running at
program startup allows eliding the __ieee_get_fp_control call.
This commit is contained in:
Richard Henderson 2012-09-13 12:54:03 -07:00
parent c899d15cbd
commit 01e80428f7
2 changed files with 33 additions and 48 deletions

View file

@ -1,5 +1,8 @@
2012-12-13 Richard Henderson <rth@redhat.com>
* sysdeps/unix/sysv/linux/alpha/setfpucw.c (__setfpucw): Rewrite
with the assumption of being used at program startup only.
* sysdeps/unix/sysv/linux/alpha/nptl/localplt.data: Add optional
entries for _OtsConvertFloatTX, _OtsCvtQUX, _OtsCvtXQ, _OtsGtrX,
_OtsLeqX, _OtsNintXQ.

View file

@ -1,5 +1,5 @@
/* Set FP exception mask and rounding mode.
Copyright (C) 1996, 1997, 1998, 2003 Free Software Foundation, Inc.
Copyright (C) 1996-2012 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@ -17,63 +17,45 @@
<http://www.gnu.org/licenses/>. */
#include <fpu_control.h>
#include <asm/fpu.h>
extern void __ieee_set_fp_control (unsigned long);
libc_hidden_proto(__ieee_set_fp_control)
extern unsigned long __ieee_get_fp_control (void);
libc_hidden_proto(__ieee_get_fp_control)
static inline unsigned long
rdfpcr (void)
{
unsigned long fpcr;
asm ("excb; mf_fpcr %0" : "=f"(fpcr));
return fpcr;
}
#include <fenv_libc.h>
static inline void
wrfpcr (unsigned long fpcr)
{
asm volatile ("mt_fpcr %0; excb" : : "f"(fpcr));
}
#define convert_bit(M, F, T) \
((T) < (F) \
? ((M) / ((F) / (T))) & (T) \
: ((M) & (F)) * ((T) / (F)))
void
__setfpucw (fpu_control_t fpu_control)
{
unsigned long fpcr = 0, fpcw = 0;
unsigned long fpcr, swcr, fc = (int)fpu_control;
if (!fpu_control)
fpu_control = _FPU_DEFAULT;
/* ??? If this was a real external interface we'd want to read the current
exception state with __ieee_get_fp_control. But this is an internal
function only called at process startup, so there's no point in trying
to preserve exceptions that cannot have been raised yet. Indeed, this
entire function is likely to be one big nop unless the user overrides
the default __fpu_control variable. */
/* first, set dynamic rounding mode: */
/* Convert the rounding mode from fpu_control.h format. */
const unsigned long conv_rnd
= ( (FE_TOWARDZERO << (_FPU_RC_ZERO >> 8))
| (FE_DOWNWARD << (_FPU_RC_DOWN >> 8))
| (FE_TONEAREST << (_FPU_RC_NEAREST >> 8))
| (FE_UPWARD << (_FPU_RC_UP >> 8)));
fpcr = rdfpcr();
fpcr &= ~FPCR_DYN_MASK;
switch (fpu_control & 0xc00)
{
case _FPU_RC_NEAREST: fpcr |= FPCR_DYN_NORMAL; break;
case _FPU_RC_DOWN: fpcr |= FPCR_DYN_MINUS; break;
case _FPU_RC_UP: fpcr |= FPCR_DYN_PLUS; break;
case _FPU_RC_ZERO: fpcr |= FPCR_DYN_CHOPPED; break;
}
wrfpcr(fpcr);
fpcr = ((conv_rnd >> ((fc >> 8) & 3)) & 3) << FPCR_ROUND_SHIFT;
/* now tell kernel about traps that we like to hear about: */
/* Convert the exception mask from fpu_control.h format. */
swcr = convert_bit (~fc, _FPU_MASK_IM, FE_INVALID >> SWCR_ENABLE_SHIFT);
swcr |= convert_bit (~fc, _FPU_MASK_DM, FE_UNDERFLOW >> SWCR_ENABLE_SHIFT);
swcr |= convert_bit (~fc, _FPU_MASK_ZM, FE_DIVBYZERO >> SWCR_ENABLE_SHIFT);
swcr |= convert_bit (~fc, _FPU_MASK_OM, FE_OVERFLOW >> SWCR_ENABLE_SHIFT);
swcr |= convert_bit (~fc, _FPU_MASK_PM, FE_INEXACT >> SWCR_ENABLE_SHIFT);
fpcw = __ieee_get_fp_control();
fpcw &= ~IEEE_TRAP_ENABLE_MASK;
if (!(fpu_control & _FPU_MASK_IM)) fpcw |= IEEE_TRAP_ENABLE_INV;
if (!(fpu_control & _FPU_MASK_DM)) fpcw |= IEEE_TRAP_ENABLE_UNF;
if (!(fpu_control & _FPU_MASK_ZM)) fpcw |= IEEE_TRAP_ENABLE_DZE;
if (!(fpu_control & _FPU_MASK_OM)) fpcw |= IEEE_TRAP_ENABLE_OVF;
if (!(fpu_control & _FPU_MASK_PM)) fpcw |= IEEE_TRAP_ENABLE_INE;
__fpu_control = fpu_control; /* update global copy */
__ieee_set_fp_control(fpcw);
/* Install everything. */
__fpu_control = fc;
asm volatile ("mt_fpcr %0" : : "f"(fpcr));
__ieee_set_fp_control(swcr);
}