MIPS64 soft-float: missing definition for __floatdidf and friends

Adam Nemet anemet@caviumnetworks.com
Tue May 9 17:59:00 GMT 2006


It seems that after the fix from Roger in
http://gcc.gnu.org/ml/gcc-patches/2006-02/msg00409.html libgcc no
longer provides DF<->DI conversion functions.

Specifically, on mipsisa64-elf with -msoft-float, this testcase fails
to link with missing definitions for __fixdfdi, __fixunsdfsi (!),
__floatdidf and __floatundidf:

  long long    f  (double d)             { return d; }
  double       g  (long long l)          { return l; }
  unsigned int ff (double d)             { return d; }
  double       gg (unsigned long long l) { return l; }
  main () {}

Before the patch there was implementation for each DF<->DI conversion
function in either libgcc2.c or fp-bit.c:

                  fix             fixuns          float           floatun
  
  SF<->SI         fp-bit          libgcc2         fp-bit          fp-bit
  SF<->DI         libgcc2         libgcc2         libgcc2         libgcc2
  SF<->TI
  
  DF<->SI         fp-bit          libgcc2         fp-bit          fp-bit
  DF<->DI         libgcc2         libgcc2         libgcc2         libgcc2
  DF<->TI
  
  TF<->SI                                                            
  TF<->DI         libgcc2         libgcc2         libgcc2         libgcc2
  TF<->TI

After the patch, DWtype is TItype (since MIN_UNITS_PER_WORD is 8) so
the definitions for DI will be "moved up to" TImode:

                  fix             fixuns          float           floatun
  
  SF<->SI         fp-bit                          fp-bit          fp-bit
  SF<->DI                         libgcc2                            
  SF<->TI         libgcc2         libgcc2         libgcc2         libgcc2
  
  DF<->SI         fp-bit                          fp-bit          fp-bit
  DF<->DI                         libgcc2                            
  DF<->TI         libgcc2         libgcc2         libgcc2         libgcc2
  
  TF<->SI                                                            
  TF<->DI         config/         config/         config/         config/
  TF<->TI         libgcc2         libgcc2         libgcc2         libgcc2

As apparent from the table we are now missing most of the definitions
for DI mode conversions and some for SI mode.

The patch below follows the precedent set by Joseph and Roger and adds
definitions for the missing functions under config/.  PPC64 solves the
same problem by defining similar wrappers in ppc64-fp.c.

With the patch, soft-float testresults are back to where they were
before Roger's patch (+162 passes) with one exception.  The failure of
gcc.dg/ftrapv-2.c seems to unrelated to this isssue and soft-float
altogether because it fails with hard-float too.  I also tested the
default multilib with no regressions.  This is all on mipsisa64-elf.

OK to apply to mainline and to 4.1 later?

	* config/fixsfdi.c: New file.
	* config/fixdfdi.c: New file.
	* config/fixunsdfsi.c: New file.
	* config/fixunssfsi.c: New file.
	* config/floatdisf.c: New file.
	* config/floatdidf.c: New file.
	* config/floatundisf.c: New file.
	* config/floatundidf.c: New file.
	* config/mips/t-mips (LIB2FUNCS_EXTRA): Set it.
	* config/mips/t-linux64 (LIB2FUNCS_EXTRA): Append to value set in
	t-mips.
	* config/mips/t-iris6 (LIB2FUNCS_EXTRA): Same.

Index: config/floatundidf.c
===================================================================
--- config/floatundidf.c	(revision 0)
+++ config/floatundidf.c	(revision 0)
@@ -0,0 +1,16 @@
+/* Public domain.  */
+typedef unsigned int USItype __attribute__ ((mode (SI)));
+typedef unsigned int UDItype __attribute__ ((mode (DI)));
+typedef float DFtype __attribute__ ((mode (DF)));
+
+DFtype __floatundidf (UDItype);
+
+DFtype
+__floatundidf (UDItype u)
+{
+  /* When the word size is small, we never get any rounding error.  */
+  DFtype f = (USItype) (u >> (sizeof (USItype) * 8));
+  f *= 0x1p32f;
+  f += (USItype) u;
+  return f;
+}
Index: config/fixdfdi.c
===================================================================
--- config/fixdfdi.c	(revision 0)
+++ config/fixdfdi.c	(revision 0)
@@ -0,0 +1,28 @@
+/* Public domain.  */
+typedef unsigned int USItype __attribute__ ((mode (SI)));
+typedef int DItype __attribute__ ((mode (DI)));
+typedef unsigned int UDItype __attribute__ ((mode (DI)));
+typedef float DFtype __attribute__ ((mode (DF)));
+
+DItype __fixdfdi (DFtype);
+
+/* This version is needed to prevent recursion; fixunsdfdi in libgcc
+   calls fixdfdi, which in turn calls calls fixunsdfdi.  */
+
+static DItype
+local_fixunsdfdi (DFtype a)
+{
+  USItype hi, lo;
+
+  hi = a / (((UDItype) 1) << (sizeof (USItype) * 8));
+  lo = a - ((DFtype) hi) * (((UDItype) 1) << (sizeof (USItype) * 8));
+  return ((UDItype) hi << (sizeof (USItype) * 8)) | lo;
+}
+
+DItype
+__fixdfdi (DFtype a)
+{
+  if (a < 0)
+    return - local_fixunsdfdi (-a);
+  return local_fixunsdfdi (a);
+}
Index: config/fixunsdfsi.c
===================================================================
--- config/fixunsdfsi.c	(revision 0)
+++ config/fixunsdfsi.c	(revision 0)
@@ -0,0 +1,18 @@
+/* Public domain.  */
+typedef unsigned int USItype __attribute__ ((mode (SI)));
+typedef int SItype __attribute__ ((mode (SI)));
+typedef float SFtype __attribute__ ((mode (SF)));
+typedef float DFtype __attribute__ ((mode (DF)));
+
+USItype __fixunsdfsi (DFtype);
+
+#define SItype_MIN \
+  (- ((SItype) (((USItype) 1 << ((sizeof (SItype) * 8) - 1)) - 1)) - 1)
+
+USItype
+__fixunsdfsi (DFtype a)
+{
+  if (a >= - (DFtype) SItype_MIN)
+    return (SItype) (a + SItype_MIN) - SItype_MIN;
+  return (SItype) a;
+}
Index: config/floatdisf.c
===================================================================
--- config/floatdisf.c	(revision 0)
+++ config/floatdisf.c	(revision 0)
@@ -0,0 +1,38 @@
+/* Public domain.  */
+typedef int DItype __attribute__ ((mode (DI)));
+typedef unsigned int UDItype __attribute__ ((mode (DI)));
+typedef int SItype __attribute__ ((mode (SI)));
+typedef unsigned int USItype __attribute__ ((mode (SI)));
+typedef float SFtype __attribute__ ((mode (SF)));
+typedef float DFtype __attribute__ ((mode (DF)));
+
+SFtype __floatdisf (DItype);
+
+SFtype
+__floatdisf (DItype u)
+{
+  /* 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 SFtype.  A fixed mask and bit position handles all usual
+     configurations.  */
+  if (53 < (sizeof (DItype) * 8)
+      && 53 > ((sizeof (DItype) * 8) - 53 + 24))
+    {
+      if (!(- ((DItype) 1 << 53) < u
+	    && u < ((DItype) 1 << 53)))
+	{
+	  if ((UDItype) u & (((UDItype) 1 << (sizeof (DItype) * 8 - 53)) - 1))
+	    {
+	      u &= ~ (((UDItype) 1 << (sizeof (DItype) * 8 - 53)) - 1);
+	      u |= (UDItype) 1 << (sizeof (DItype) * 8 - 53);
+	    }
+	}
+    }
+  /* Do the calculation in a wider type so that we don't lose any of
+     the precision of the high word while multiplying it.  */
+  DFtype f = (SItype) (u >> (sizeof (SItype) * 8));
+  f *= 0x1p32f;
+  f += (USItype) u;
+  return (SFtype) f;
+}
Index: config/fixsfdi.c
===================================================================
--- config/fixsfdi.c	(revision 0)
+++ config/fixsfdi.c	(revision 0)
@@ -0,0 +1,30 @@
+/* Public domain.  */
+typedef unsigned int USItype __attribute__ ((mode (SI)));
+typedef int DItype __attribute__ ((mode (DI)));
+typedef unsigned int UDItype __attribute__ ((mode (DI)));
+typedef float SFtype __attribute__ ((mode (SF)));
+typedef float DFtype __attribute__ ((mode (DF)));
+
+DItype __fixsfdi (SFtype);
+
+/* This version is needed to prevent recursion; fixunssfdi in libgcc
+   calls fixsfdi, which in turn calls calls fixunssfdi.  */
+
+static DItype
+local_fixunssfdi (SFtype original_a)
+{
+  DFtype a = original_a;
+  USItype hi, lo;
+
+  hi = a / (((UDItype) 1) << (sizeof (USItype) * 8));
+  lo = a - ((DFtype) hi) * (((UDItype) 1) << (sizeof (USItype) * 8));
+  return ((UDItype) hi << (sizeof (USItype) * 8)) | lo;
+}
+
+DItype
+__fixsfdi (SFtype a)
+{
+  if (a < 0)
+    return - local_fixunssfdi (-a);
+  return local_fixunssfdi (a);
+}
Index: config/floatundisf.c
===================================================================
--- config/floatundisf.c	(revision 0)
+++ config/floatundisf.c	(revision 0)
@@ -0,0 +1,36 @@
+/* Public domain.  */
+typedef int DItype __attribute__ ((mode (DI)));
+typedef unsigned int UDItype __attribute__ ((mode (DI)));
+typedef unsigned int USItype __attribute__ ((mode (SI)));
+typedef float SFtype __attribute__ ((mode (SF)));
+typedef float DFtype __attribute__ ((mode (DF)));
+
+SFtype __floatundisf (UDItype);
+
+SFtype
+__floatundisf (UDItype u)
+{
+  /* 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 SFTYPE.  A fixed mask and bit position handles all usual
+     configurations.  */
+  if (53 < (sizeof (DItype) * 8)
+      && 53 > ((sizeof (DItype) * 8) - 53 + 24))
+    {
+      if (u >= ((UDItype) 1 << 53))
+	{
+	  if ((UDItype) u & (((UDItype) 1 << (sizeof (DItype) * 8 - 53)) - 1))
+	    {
+	      u &= ~ (((UDItype) 1 << (sizeof (DItype) * 8 - 53)) - 1);
+	      u |= (UDItype) 1 << (sizeof (DItype) * 8 - 53);
+	    }
+	}
+    }
+  /* Do the calculation in a wider type so that we don't lose any of
+     the precision of the high word while multiplying it.  */
+  DFtype f = (USItype) (u >> (sizeof (USItype) * 8));
+  f *= 0x1p32f;
+  f += (USItype) u;
+  return (SFtype) f;
+}
Index: config/mips/t-iris6
===================================================================
--- config/mips/t-iris6	(revision 113576)
+++ config/mips/t-iris6	(working copy)
@@ -6,7 +6,7 @@ MULTILIB_OSDIRNAMES=../lib32 ../lib ../l
 LIBGCC = stmp-multilib
 INSTALL_LIBGCC = install-multilib
 
-LIB2FUNCS_EXTRA = $(srcdir)/config/fixtfdi.c $(srcdir)/config/fixunstfdi.c $(srcdir)/config/floatditf.c $(srcdir)/config/floatunditf.c
+LIB2FUNCS_EXTRA += $(srcdir)/config/fixtfdi.c $(srcdir)/config/fixunstfdi.c $(srcdir)/config/floatditf.c $(srcdir)/config/floatunditf.c
 
 TPBIT = tp-bit.c
 
Index: config/mips/t-linux64
===================================================================
--- config/mips/t-linux64	(revision 113576)
+++ config/mips/t-linux64	(working copy)
@@ -4,7 +4,7 @@ MULTILIB_OSDIRNAMES = ../lib32 ../lib ..
 
 EXTRA_MULTILIB_PARTS=crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o
 
-LIB2FUNCS_EXTRA = $(srcdir)/config/fixtfdi.c $(srcdir)/config/fixunstfdi.c $(srcdir)/config/floatditf.c $(srcdir)/config/floatunditf.c
+LIB2FUNCS_EXTRA += $(srcdir)/config/fixtfdi.c $(srcdir)/config/fixunstfdi.c $(srcdir)/config/floatditf.c $(srcdir)/config/floatunditf.c
 
 TPBIT = tp-bit.c
 
Index: config/mips/t-mips
===================================================================
--- config/mips/t-mips	(revision 113576)
+++ config/mips/t-mips	(working copy)
@@ -19,3 +19,8 @@ fp-bit.c: $(srcdir)/config/fp-bit.c
 	echo '#endif' >> fp-bit.c
 	echo '#define QUIET_NAN_NEGATED' >> fp-bit.c
 	cat $(srcdir)/config/fp-bit.c >> fp-bit.c
+
+LIB2FUNCS_EXTRA = $(srcdir)/config/fixsfdi.c $(srcdir)/config/fixdfdi.c \
+  $(srcdir)/config/fixunssfsi.c $(srcdir)/config/fixunsdfsi.c \
+  $(srcdir)/config/floatdisf.c $(srcdir)/config/floatdidf.c \
+  $(srcdir)/config/floatundisf.c $(srcdir)/config/floatundidf.c
Index: config/floatdidf.c
===================================================================
--- config/floatdidf.c	(revision 0)
+++ config/floatdidf.c	(revision 0)
@@ -0,0 +1,17 @@
+/* Public domain.  */
+typedef int SItype __attribute__ ((mode (SI)));
+typedef unsigned int USItype __attribute__ ((mode (SI)));
+typedef int DItype __attribute__ ((mode (DI)));
+typedef float DFtype __attribute__ ((mode (DF)));
+
+DFtype __floatdidf (DItype);
+
+DFtype
+__floatdidf (DItype u)
+{
+  /* When the word size is small, we never get any rounding error.  */
+  DFtype f = (SItype) (u >> (sizeof (SItype) * 8));
+  f *= 0x1p32f;
+  f += (USItype) u;
+  return f;
+}
Index: config/fixunssfsi.c
===================================================================
--- config/fixunssfsi.c	(revision 0)
+++ config/fixunssfsi.c	(revision 0)
@@ -0,0 +1,17 @@
+/* Public domain.  */
+typedef unsigned int USItype __attribute__ ((mode (SI)));
+typedef int SItype __attribute__ ((mode (SI)));
+typedef float SFtype __attribute__ ((mode (SF)));
+
+USItype __fixunssfsi (SFtype);
+
+#define SItype_MIN \
+  (- ((SItype) (((USItype) 1 << ((sizeof (SItype) * 8) - 1)) - 1)) - 1)
+
+USItype
+__fixunssfsi (SFtype a)
+{
+  if (a >= - (SFtype) SItype_MIN)
+    return (SItype) (a + SItype_MIN) - SItype_MIN;
+  return (SItype) a;
+}



More information about the Gcc-patches mailing list