Commit d7735880 by Joseph Myers Committed by Joseph Myers

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
parent 131aeb82
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.
* doc/invoke.texi (-mmulhw): Document.
* config/rs6000/rs6000.c (rs6000_override_options): Enable -mmulhw
......
......@@ -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)
{
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 <<= 1;
in.normal_exp -= 1;
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
}
......@@ -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
......
......@@ -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",
......
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,
gcc.target/powerpc/405-macchw-2.c,
gcc.target/powerpc/405-macchwu-1.c,
/* 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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment