summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>2005-11-22 00:38:30 +0000
committerjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>2005-11-22 00:38:30 +0000
commit4f5bcdbdf334ba80e3f4890bb752e457601f3e9e (patch)
treecf1224f63a9636c4333be5cb2d3cabfe2eec233d
parent624e1eec9297f70ad0a205f71092eaa6863dc87b (diff)
downloadgcc-4f5bcdbdf334ba80e3f4890bb752e457601f3e9e.tar.gz
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@107345 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog17
-rw-r--r--gcc/config/fp-bit.c50
-rw-r--r--gcc/libgcc-std.ver17
-rw-r--r--gcc/libgcc2.c114
-rw-r--r--gcc/libgcc2.h8
-rw-r--r--gcc/mklibgcc.in2
-rw-r--r--gcc/optabs.c15
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/floatunsisf-1.c21
9 files changed, 231 insertions, 17 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 1adc088a2ab..0fa5ae51e40 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,22 @@
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
diff --git a/gcc/config/fp-bit.c b/gcc/config/fp-bit.c
index 4c637cb70ae..ccf927e8c3b 100644
--- a/gcc/config/fp-bit.c
+++ b/gcc/config/fp-bit.c
@@ -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);
diff --git a/gcc/libgcc-std.ver b/gcc/libgcc-std.ver
index 341cf7a481b..a98ddb463a2 100644
--- a/gcc/libgcc-std.ver
+++ b/gcc/libgcc-std.ver
@@ -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
+}
diff --git a/gcc/libgcc2.c b/gcc/libgcc2.c
index 8838c308c7f..94f4b30006a 100644
--- a/gcc/libgcc2.c
+++ b/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
diff --git a/gcc/libgcc2.h b/gcc/libgcc2.h
index 56ffc61f4be..11a1d9a3ff8 100644
--- a/gcc/libgcc2.h
+++ b/gcc/libgcc2.h
@@ -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);
diff --git a/gcc/mklibgcc.in b/gcc/mklibgcc.in
index 6517b1d6fce..816e301023b 100644
--- a/gcc/mklibgcc.in
+++ b/gcc/mklibgcc.in
@@ -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
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 6b681a350c1..d764017a5d9 100644
--- a/gcc/optabs.c
+++ b/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",
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 40b1ecaa0b5..c75ea547a70 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,9 @@
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,
diff --git a/gcc/testsuite/gcc.c-torture/execute/floatunsisf-1.c b/gcc/testsuite/gcc.c-torture/execute/floatunsisf-1.c
new file mode 100644
index 00000000000..cc4c49bbe05
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/floatunsisf-1.c
@@ -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);
+}