fp-bit.c (clzusi): New function.
* config/fp-bit.c (clzusi): New function. (si_to_float, usi_to_float): Use it to compute proper shift. (usi_to_float): Preserve guard bits when shifting right. * libgcc-std.ver (GCC_4.2.0): New version. * libgcc2.c (__floatundixf, __floatunditf, __floatundidf, __floatundisf): New functions. * libgcc2.h (__floatundixf, __floatunditf, __floatundidf, __floatundisf): Declare. * mklibgcc.in (lib2funcs): Add _floatundidf, _floatundisf, _floatundixf, and _floatunditf. * optabs.c (expand_float): If target does not define a pattern for signed or unsigned conversion, use an unsigned libcall instead of a signed one. (init_optabs): Initialize ufloat_optab. testsuite: * gcc.c-torture/execute/floatunsisf-1.c: New test. From-SVN: r107345
This commit is contained in:
parent
131aeb82d1
commit
d773588022
9 changed files with 231 additions and 17 deletions
|
@ -1,3 +1,20 @@
|
|||
2005-11-22 Joseph S. Myers <joseph@codesourcery.com>
|
||||
|
||||
* config/fp-bit.c (clzusi): New function.
|
||||
(si_to_float, usi_to_float): Use it to compute proper shift.
|
||||
(usi_to_float): Preserve guard bits when shifting right.
|
||||
* libgcc-std.ver (GCC_4.2.0): New version.
|
||||
* libgcc2.c (__floatundixf, __floatunditf, __floatundidf,
|
||||
__floatundisf): New functions.
|
||||
* libgcc2.h (__floatundixf, __floatunditf, __floatundidf,
|
||||
__floatundisf): Declare.
|
||||
* mklibgcc.in (lib2funcs): Add _floatundidf, _floatundisf,
|
||||
_floatundixf, and _floatunditf.
|
||||
* optabs.c (expand_float): If target does not define a pattern for
|
||||
signed or unsigned conversion, use an unsigned libcall instead of
|
||||
a signed one.
|
||||
(init_optabs): Initialize ufloat_optab.
|
||||
|
||||
2005-11-22 Joseph S. Myers <joseph@codesourcery.com>
|
||||
|
||||
* config/rs6000/rs6000.opt (mmulhw): New option.
|
||||
|
|
|
@ -186,6 +186,22 @@ flip_sign ( fp_number_type * x)
|
|||
x->sign = !x->sign;
|
||||
}
|
||||
|
||||
/* Count leading zeroes in N. */
|
||||
INLINE
|
||||
static int
|
||||
clzusi (USItype n)
|
||||
{
|
||||
extern int __clzsi2 (USItype);
|
||||
if (sizeof (USItype) == sizeof (unsigned int))
|
||||
return __builtin_clz (n);
|
||||
else if (sizeof (USItype) == sizeof (unsigned long))
|
||||
return __builtin_clzl (n);
|
||||
else if (sizeof (USItype) == sizeof (unsigned long long))
|
||||
return __builtin_clzll (n);
|
||||
else
|
||||
return __clzsi2 (n);
|
||||
}
|
||||
|
||||
extern FLO_type pack_d ( fp_number_type * );
|
||||
|
||||
#if defined(L_pack_df) || defined(L_pack_sf) || defined(L_pack_tf)
|
||||
|
@ -1334,6 +1350,8 @@ si_to_float (SItype arg_a)
|
|||
}
|
||||
else
|
||||
{
|
||||
USItype uarg;
|
||||
int shift;
|
||||
in.normal_exp = FRACBITS + NGARDS;
|
||||
if (in.sign)
|
||||
{
|
||||
|
@ -1343,15 +1361,17 @@ si_to_float (SItype arg_a)
|
|||
{
|
||||
return (FLO_type)(- MAX_SI_INT - 1);
|
||||
}
|
||||
in.fraction.ll = (-arg_a);
|
||||
uarg = (-arg_a);
|
||||
}
|
||||
else
|
||||
in.fraction.ll = arg_a;
|
||||
uarg = arg_a;
|
||||
|
||||
while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS)))
|
||||
in.fraction.ll = uarg;
|
||||
shift = clzusi (uarg) - (BITS_PER_SI - 1 - FRACBITS - NGARDS);
|
||||
if (shift > 0)
|
||||
{
|
||||
in.fraction.ll <<= 1;
|
||||
in.normal_exp -= 1;
|
||||
in.fraction.ll <<= shift;
|
||||
in.normal_exp -= shift;
|
||||
}
|
||||
}
|
||||
return pack_d (&in);
|
||||
|
@ -1371,19 +1391,23 @@ usi_to_float (USItype arg_a)
|
|||
}
|
||||
else
|
||||
{
|
||||
int shift;
|
||||
in.class = CLASS_NUMBER;
|
||||
in.normal_exp = FRACBITS + NGARDS;
|
||||
in.fraction.ll = arg_a;
|
||||
|
||||
while (in.fraction.ll > ((fractype)1 << (FRACBITS + NGARDS)))
|
||||
{
|
||||
in.fraction.ll >>= 1;
|
||||
in.normal_exp += 1;
|
||||
}
|
||||
while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS)))
|
||||
shift = clzusi (arg_a) - (BITS_PER_SI - 1 - FRACBITS - NGARDS);
|
||||
if (shift < 0)
|
||||
{
|
||||
in.fraction.ll <<= 1;
|
||||
in.normal_exp -= 1;
|
||||
fractype guard = in.fraction.ll & (((fractype)1 << -shift) - 1);
|
||||
in.fraction.ll >>= -shift;
|
||||
in.fraction.ll |= (guard != 0);
|
||||
in.normal_exp -= shift;
|
||||
}
|
||||
else if (shift > 0)
|
||||
{
|
||||
in.fraction.ll <<= shift;
|
||||
in.normal_exp -= shift;
|
||||
}
|
||||
}
|
||||
return pack_d (&in);
|
||||
|
|
|
@ -252,3 +252,20 @@ GCC_4.0.0 {
|
|||
__mulxc3
|
||||
__multc3
|
||||
}
|
||||
|
||||
%inherit GCC_4.2.0 GCC_4.0.0
|
||||
GCC_4.2.0 {
|
||||
# unsigned-to-floating conversions
|
||||
__floatunsisf
|
||||
__floatunsidf
|
||||
__floatunsixf
|
||||
__floatunsitf
|
||||
__floatundidf
|
||||
__floatundisf
|
||||
__floatundixf
|
||||
__floatunditf
|
||||
__floatuntidf
|
||||
__floatuntisf
|
||||
__floatuntixf
|
||||
__floatuntitf
|
||||
}
|
||||
|
|
114
gcc/libgcc2.c
114
gcc/libgcc2.c
|
@ -1323,6 +1323,17 @@ __floatdixf (DWtype u)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(L_floatundixf) && LIBGCC2_HAS_XF_MODE
|
||||
XFtype
|
||||
__floatundixf (UDWtype u)
|
||||
{
|
||||
XFtype d = (UWtype) (u >> W_TYPE_SIZE);
|
||||
d *= Wtype_MAXp1_F;
|
||||
d += (UWtype)u;
|
||||
return d;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(L_floatditf) && LIBGCC2_HAS_TF_MODE
|
||||
TFtype
|
||||
__floatditf (DWtype u)
|
||||
|
@ -1334,6 +1345,17 @@ __floatditf (DWtype u)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(L_floatunditf) && LIBGCC2_HAS_TF_MODE
|
||||
TFtype
|
||||
__floatunditf (UDWtype u)
|
||||
{
|
||||
TFtype d = (UWtype) (u >> W_TYPE_SIZE);
|
||||
d *= Wtype_MAXp1_F;
|
||||
d += (UWtype)u;
|
||||
return d;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(L_floatdidf) && LIBGCC2_HAS_DF_MODE
|
||||
DFtype
|
||||
__floatdidf (DWtype u)
|
||||
|
@ -1345,6 +1367,17 @@ __floatdidf (DWtype u)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(L_floatundidf) && LIBGCC2_HAS_DF_MODE
|
||||
DFtype
|
||||
__floatundidf (UDWtype u)
|
||||
{
|
||||
DFtype d = (UWtype) (u >> W_TYPE_SIZE);
|
||||
d *= Wtype_MAXp1_F;
|
||||
d += (UWtype)u;
|
||||
return d;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(L_floatdisf) && LIBGCC2_HAS_SF_MODE
|
||||
#define DI_SIZE (W_TYPE_SIZE * 2)
|
||||
#define SF_SIZE FLT_MANT_DIG
|
||||
|
@ -1433,6 +1466,87 @@ __floatdisf (DWtype u)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(L_floatundisf) && LIBGCC2_HAS_SF_MODE
|
||||
#define DI_SIZE (W_TYPE_SIZE * 2)
|
||||
#define SF_SIZE FLT_MANT_DIG
|
||||
|
||||
SFtype
|
||||
__floatundisf (UDWtype u)
|
||||
{
|
||||
#if SF_SIZE >= W_TYPE_SIZE
|
||||
/* When the word size is small, we never get any rounding error. */
|
||||
SFtype f = (UWtype) (u >> W_TYPE_SIZE);
|
||||
f *= Wtype_MAXp1_F;
|
||||
f += (UWtype)u;
|
||||
return f;
|
||||
#elif LIBGCC2_HAS_DF_MODE
|
||||
|
||||
#if LIBGCC2_DOUBLE_TYPE_SIZE == 64
|
||||
#define DF_SIZE DBL_MANT_DIG
|
||||
#elif LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 64
|
||||
#define DF_SIZE LDBL_MANT_DIG
|
||||
#else
|
||||
# error
|
||||
#endif
|
||||
|
||||
#define REP_BIT ((UDWtype) 1 << (DI_SIZE - DF_SIZE))
|
||||
|
||||
/* Protect against double-rounding error.
|
||||
Represent any low-order bits, that might be truncated by a bit that
|
||||
won't be lost. The bit can go in anywhere below the rounding position
|
||||
of the SFmode. A fixed mask and bit position handles all usual
|
||||
configurations. It doesn't handle the case of 128-bit DImode, however. */
|
||||
if (DF_SIZE < DI_SIZE
|
||||
&& DF_SIZE > (DI_SIZE - DF_SIZE + SF_SIZE))
|
||||
{
|
||||
if (u >= ((UDWtype) 1 << DF_SIZE))
|
||||
{
|
||||
if ((UDWtype) u & (REP_BIT - 1))
|
||||
{
|
||||
u &= ~ (REP_BIT - 1);
|
||||
u |= REP_BIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Do the calculation in DFmode so that we don't lose any of the
|
||||
precision of the high word while multiplying it. */
|
||||
DFtype f = (UWtype) (u >> W_TYPE_SIZE);
|
||||
f *= Wtype_MAXp1_F;
|
||||
f += (UWtype)u;
|
||||
return (SFtype) f;
|
||||
#else
|
||||
/* Finally, the word size is larger than the number of bits in SFmode,
|
||||
and we've got no DFmode. The only way to avoid double rounding is
|
||||
to special case the extraction. */
|
||||
|
||||
/* If there are no high bits set, fall back to one conversion. */
|
||||
if ((UWtype)u == u)
|
||||
return (SFtype)(UWtype)u;
|
||||
|
||||
/* Otherwise, find the power of two. */
|
||||
UWtype hi = u >> W_TYPE_SIZE;
|
||||
|
||||
UWtype count, shift;
|
||||
count_leading_zeros (count, hi);
|
||||
|
||||
shift = W_TYPE_SIZE - count;
|
||||
|
||||
/* Shift down the most significant bits. */
|
||||
hi = u >> shift;
|
||||
|
||||
/* If we lost any nonzero bits, set the lsb to ensure correct rounding. */
|
||||
if (u & ((1 << shift) - 1))
|
||||
hi |= 1;
|
||||
|
||||
/* Convert the one word of data, and rescale. */
|
||||
SFtype f = hi;
|
||||
f *= (UWtype)1 << shift;
|
||||
return f;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(L_fixunsxfsi) && LIBGCC2_HAS_XF_MODE
|
||||
/* Reenable the normal types, in case limits.h needs them. */
|
||||
#undef char
|
||||
|
|
|
@ -238,6 +238,10 @@ typedef int word_type __attribute__ ((mode (__word__)));
|
|||
#define __floatditf __NDW(float,tf)
|
||||
#define __floatdidf __NDW(float,df)
|
||||
#define __floatdisf __NDW(float,sf)
|
||||
#define __floatundixf __NDW(floatun,xf)
|
||||
#define __floatunditf __NDW(floatun,tf)
|
||||
#define __floatundidf __NDW(floatun,df)
|
||||
#define __floatundisf __NDW(floatun,sf)
|
||||
#define __fixunsxfSI __NW(fixunsxf,)
|
||||
#define __fixunstfSI __NW(fixunstf,)
|
||||
#define __fixunsdfSI __NW(fixunsdf,)
|
||||
|
@ -318,6 +322,7 @@ extern SItype __negvsi2 (SItype);
|
|||
#if LIBGCC2_HAS_SF_MODE
|
||||
extern DWtype __fixsfdi (SFtype);
|
||||
extern SFtype __floatdisf (DWtype);
|
||||
extern SFtype __floatundisf (UDWtype);
|
||||
extern UWtype __fixunssfSI (SFtype);
|
||||
extern DWtype __fixunssfDI (SFtype);
|
||||
extern SFtype __powisf2 (SFtype, int);
|
||||
|
@ -327,6 +332,7 @@ extern SCtype __mulsc3 (SFtype, SFtype, SFtype, SFtype);
|
|||
#if LIBGCC2_HAS_DF_MODE
|
||||
extern DWtype __fixdfdi (DFtype);
|
||||
extern DFtype __floatdidf (DWtype);
|
||||
extern DFtype __floatundidf (UDWtype);
|
||||
extern UWtype __fixunsdfSI (DFtype);
|
||||
extern DWtype __fixunsdfDI (DFtype);
|
||||
extern DFtype __powidf2 (DFtype, int);
|
||||
|
@ -338,6 +344,7 @@ extern DCtype __muldc3 (DFtype, DFtype, DFtype, DFtype);
|
|||
extern DWtype __fixxfdi (XFtype);
|
||||
extern DWtype __fixunsxfDI (XFtype);
|
||||
extern XFtype __floatdixf (DWtype);
|
||||
extern XFtype __floatundixf (UDWtype);
|
||||
extern UWtype __fixunsxfSI (XFtype);
|
||||
extern XFtype __powixf2 (XFtype, int);
|
||||
extern XCtype __divxc3 (XFtype, XFtype, XFtype, XFtype);
|
||||
|
@ -348,6 +355,7 @@ extern XCtype __mulxc3 (XFtype, XFtype, XFtype, XFtype);
|
|||
extern DWtype __fixunstfDI (TFtype);
|
||||
extern DWtype __fixtfdi (TFtype);
|
||||
extern TFtype __floatditf (DWtype);
|
||||
extern TFtype __floatunditf (UDWtype);
|
||||
extern TFtype __powitf2 (TFtype, int);
|
||||
extern TCtype __divtc3 (TFtype, TFtype, TFtype, TFtype);
|
||||
extern TCtype __multc3 (TFtype, TFtype, TFtype, TFtype);
|
||||
|
|
|
@ -63,7 +63,7 @@ lib2funcs='_muldi3 _negdi2 _lshrdi3 _ashldi3 _ashrdi3
|
|||
_ffssi2 _ffsdi2 _clz _clzsi2 _clzdi2 _ctzsi2 _ctzdi2 _popcount_tab
|
||||
_popcountsi2 _popcountdi2 _paritysi2 _paritydi2 _powisf2 _powidf2
|
||||
_powixf2 _powitf2 _mulsc3 _muldc3 _mulxc3 _multc3 _divsc3 _divdc3
|
||||
_divxc3 _divtc3'
|
||||
_divxc3 _divtc3 _floatundidf _floatundisf _floatundixf _floatunditf'
|
||||
|
||||
# Disable SHLIB_LINK if shared libgcc not enabled.
|
||||
if [ "@enable_shared@" = "no" ]; then
|
||||
|
|
15
gcc/optabs.c
15
gcc/optabs.c
|
@ -4310,6 +4310,7 @@ expand_float (rtx to, rtx from, int unsignedp)
|
|||
enum insn_code icode;
|
||||
rtx target = to;
|
||||
enum machine_mode fmode, imode;
|
||||
bool can_do_signed = false;
|
||||
|
||||
/* Crash now, because we won't be able to decide which mode to use. */
|
||||
gcc_assert (GET_MODE (from) != VOIDmode);
|
||||
|
@ -4331,8 +4332,14 @@ expand_float (rtx to, rtx from, int unsignedp)
|
|||
continue;
|
||||
|
||||
icode = can_float_p (fmode, imode, unsignedp);
|
||||
if (icode == CODE_FOR_nothing && imode != GET_MODE (from) && unsignedp)
|
||||
icode = can_float_p (fmode, imode, 0), doing_unsigned = 0;
|
||||
if (icode == CODE_FOR_nothing && unsignedp)
|
||||
{
|
||||
enum insn_code scode = can_float_p (fmode, imode, 0);
|
||||
if (scode != CODE_FOR_nothing)
|
||||
can_do_signed = true;
|
||||
if (imode != GET_MODE (from))
|
||||
icode = scode, doing_unsigned = 0;
|
||||
}
|
||||
|
||||
if (icode != CODE_FOR_nothing)
|
||||
{
|
||||
|
@ -4353,7 +4360,7 @@ expand_float (rtx to, rtx from, int unsignedp)
|
|||
|
||||
/* Unsigned integer, and no way to convert directly.
|
||||
Convert as signed, then conditionally adjust the result. */
|
||||
if (unsignedp)
|
||||
if (unsignedp && can_do_signed)
|
||||
{
|
||||
rtx label = gen_label_rtx ();
|
||||
rtx temp;
|
||||
|
@ -5232,6 +5239,8 @@ init_optabs (void)
|
|||
/* Conversions. */
|
||||
init_interclass_conv_libfuncs (sfloat_optab, "float",
|
||||
MODE_INT, MODE_FLOAT);
|
||||
init_interclass_conv_libfuncs (ufloat_optab, "floatun",
|
||||
MODE_INT, MODE_FLOAT);
|
||||
init_interclass_conv_libfuncs (sfix_optab, "fix",
|
||||
MODE_FLOAT, MODE_INT);
|
||||
init_interclass_conv_libfuncs (ufix_optab, "fixuns",
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
2005-11-22 Joseph S. Myers <joseph@codesourcery.com>
|
||||
|
||||
* gcc.c-torture/execute/floatunsisf-1.c: New test.
|
||||
|
||||
2005-11-22 Joseph S. Myers <joseph@codesourcery.com>
|
||||
|
||||
* gcc.target/powerpc/405-macchw-1.c,
|
||||
|
|
21
gcc/testsuite/gcc.c-torture/execute/floatunsisf-1.c
Normal file
21
gcc/testsuite/gcc.c-torture/execute/floatunsisf-1.c
Normal file
|
@ -0,0 +1,21 @@
|
|||
/* The fp-bit.c function __floatunsisf had a latent bug where guard bits
|
||||
could be lost leading to incorrect rounding. */
|
||||
/* Origin: Joseph Myers <joseph@codesourcery.com> */
|
||||
|
||||
extern void abort (void);
|
||||
extern void exit (int);
|
||||
#if __INT_MAX__ >= 0x7fffffff
|
||||
volatile unsigned u = 0x80000081;
|
||||
#else
|
||||
volatile unsigned long u = 0x80000081;
|
||||
#endif
|
||||
volatile float f1, f2;
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
f1 = (float) u;
|
||||
f2 = (float) 0x80000081;
|
||||
if (f1 != f2)
|
||||
abort ();
|
||||
exit (0);
|
||||
}
|
Loading…
Add table
Reference in a new issue