This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

long double support for powerpc64-linux


This patch borrows Geoff's darwin long double support for powerpc64-linux,
so we can finally comply with the ABI.  In making these changes, I ran
into a couple of latent bugs.

One bug occurred in passing variable arguments.  These are supposed to
go in r3..r10 then on the stack.  When a long double was split over r10
and the stack, the part in r10 only had the low 32 bits.  The
function_arg change to use Pmode fixes this one.

The other bug was with returning a complex long double, which gcc tried
to return in (f1,f2) and (f2,f3).  The problem here was that
rs6000_complex_function_value assumed that the two element of the
parallel it returns were on consecutive registers.  That's obviously
wrong in the case of multi-reg elements.  On the patch itself, it might
seem wrong that I'm always testing inner_bytes against 8, but the only
case where we might have multiple 32 bit registers is already handled
just above.


gcc/ChangeLog
	* config/rs6000/t-linux64 (LIB2FUNCS_EXTRA): Add darwin-ldouble.c.
	(SHLIB_MAPFILES): Add libgcc-ppc64.ver.
	(SHLIB_MKMAP_OPTS): Delete.
GNU ld no longer needs this.  Anyone using an old ld without this
feature will suffer from many other problems.

	* config/rs6000/libgcc-ppc64.ver: New file.
	* config/rs6000/linux64.h (SUBSUBTARGET_OVERRIDE_OPTIONS): Default
	to 128 bit long double.
	* config/rs6000/ppc64-fp.c (__fixtfdi, __floatditf): New functions.
	(__floatdidf, __floatdisf): Optimize multiply.
Saves a runtime multiply.  gcc doesn't recognize the constants are
powers of two, and thus safe to combine.

	(__fixunstfdi): New function.
	* config/rs6000/rs6000.c (rs6000_complex_function_value): Allow for
	real and imag parts larger than one register.
	(function_arg): Correct type of reg used when fp arg split partially
	to stack.
	* config/rs6000/darwin-ldouble.c: Protect with #if !_SOFT_FLOAT.
asm with float regs used herein.


libffi/ChangeLog
	* src/types.c: Use 16 byte long double for POWERPC64.

Regression testing powerpc64-linux in progress.  OK to install assuming
no regressions?

Index: gcc/config/rs6000/t-linux64
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/t-linux64,v
retrieving revision 1.5
diff -u -p -r1.5 t-linux64
--- gcc/config/rs6000/t-linux64	4 Jun 2003 15:23:42 -0000	1.5
+++ gcc/config/rs6000/t-linux64	27 Jan 2004 06:42:32 -0000
@@ -1,8 +1,12 @@
-# These functions are needed for soft-float on powerpc64-linux.
-LIB2FUNCS_EXTRA = tramp.S $(srcdir)/config/rs6000/ppc64-fp.c
 
-# Modify the shared lib version file
-SHLIB_MKMAP_OPTS = -v dotsyms=1
+#rs6000/t-linux64
+
+LIB2FUNCS_EXTRA = tramp.S $(srcdir)/config/rs6000/ppc64-fp.c \
+	$(srcdir)/config/rs6000/darwin-ldouble.c
+
+TARGET_LIBGCC2_CFLAGS = -mno-minimal-toc -fPIC
+
+SHLIB_MAPFILES += $(srcdir)/config/rs6000/libgcc-ppc64.ver
 
 MULTILIB_OPTIONS        = m64/m32 msoft-float
 MULTILIB_DIRNAMES       = 64 32 nof
@@ -11,8 +15,6 @@ MULTILIB_EXCEPTIONS     = m64/msoft-floa
 MULTILIB_EXCLUSIONS     = m64/!m32/msoft-float
 MULTILIB_OSDIRNAMES	= ../lib64 ../lib nof
 MULTILIB_MATCHES        = $(MULTILIB_MATCHES_FLOAT)
-
-TARGET_LIBGCC2_CFLAGS = -mno-minimal-toc -fPIC
 
 # We want fine grained libraries, so use the new code to build the
 # floating point emulation libraries.
Index: gcc/config/rs6000/linux64.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/linux64.h,v
retrieving revision 1.55
diff -u -p -r1.55 linux64.h
--- gcc/config/rs6000/linux64.h	23 Jan 2004 17:32:11 -0000	1.55
+++ gcc/config/rs6000/linux64.h	27 Jan 2004 06:42:22 -0000
@@ -70,6 +73,8 @@
 	rs6000_alignment_flags = MASK_ALIGN_NATURAL;		\
       if (TARGET_64BIT)						\
 	{							\
+	  if (rs6000_long_double_size_string == 0)		\
+	    rs6000_long_double_type_size = 128;			\
 	  if (DEFAULT_ABI != ABI_AIX)				\
 	    {							\
 	      rs6000_current_abi = ABI_AIX;			\
Index: gcc/config/rs6000/libgcc-ppc64.ver
===================================================================
RCS file: gcc/config/rs6000/libgcc-ppc64.ver
diff -N gcc/config/rs6000/libgcc-ppc64.ver
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gcc/config/rs6000/libgcc-ppc64.ver	27 Jan 2004 06:45:34 -0000
@@ -0,0 +1,7 @@
+GCC_3.4 {
+  # long double support
+  _xlqadd
+  _xlqsub
+  _xlqmul
+  _xlqdiv
+}
Index: gcc/config/rs6000/ppc64-fp.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/ppc64-fp.c,v
retrieving revision 1.2
diff -u -p -r1.2 ppc64-fp.c
--- gcc/config/rs6000/ppc64-fp.c	22 Aug 2003 09:33:25 -0000	1.2
+++ gcc/config/rs6000/ppc64-fp.c	27 Jan 2004 06:42:22 -0000
@@ -33,17 +33,28 @@ Software Foundation, 59 Temple Place - S
 #if defined(__powerpc64__)
 #include "config/fp-bit.h"
 
+extern DItype __fixtfdi (TFtype);
 extern DItype __fixdfdi (DFtype);
 extern DItype __fixsfdi (SFtype);
 extern USItype __fixunsdfsi (DFtype);
 extern USItype __fixunssfsi (SFtype);
+extern TFtype __floatditf (DItype);
 extern DFtype __floatdidf (DItype);
 extern SFtype __floatdisf (DItype);
+extern DItype __fixunstfdi (TFtype);
 
 static DItype local_fixunssfdi (SFtype);
 static DItype local_fixunsdfdi (DFtype);
 
 DItype
+__fixtfdi (TFtype a)
+{
+  if (a < 0)
+    return - __fixunstfdi (-a);
+  return __fixunstfdi (a);
+}
+
+DItype
 __fixdfdi (DFtype a)
 {
   if (a < 0)
@@ -77,14 +88,25 @@ __fixunssfsi (SFtype a)
   return (SItype) a;
 }
 
+TFtype
+__floatditf (DItype u)
+{
+  DFtype dh, dl;
+
+  dh = (SItype) (u >> (sizeof (SItype) * 8));
+  dh *= 2.0 * (((UDItype) 1) << ((sizeof (SItype) * 8) - 1));
+  dl = (USItype) (u & ((((UDItype) 1) << (sizeof (SItype) * 8)) - 1));
+
+  return (TFtype) dh + (TFtype) dl;
+}
+
 DFtype
 __floatdidf (DItype u)
 {
   DFtype d;
 
   d = (SItype) (u >> (sizeof (SItype) * 8));
-  d *= (((UDItype) 1) << ((sizeof (SItype) * 8) / 2));
-  d *= (((UDItype) 1) << ((sizeof (SItype) * 8) / 2));
+  d *= 2.0 * (((UDItype) 1) << ((sizeof (SItype) * 8) - 1));
   d += (USItype) (u & ((((UDItype) 1) << (sizeof (SItype) * 8)) - 1));
 
   return d;
@@ -109,11 +131,34 @@ __floatdisf (DItype u)
         }
     }
   f = (SItype) (u >> (sizeof (SItype) * 8));
-  f *= (((UDItype) 1) << ((sizeof (SItype) * 8) / 2));
-  f *= (((UDItype) 1) << ((sizeof (SItype) * 8) / 2));
+  f *= 2.0 * (((UDItype) 1) << ((sizeof (SItype) * 8) - 1));
   f += (USItype) (u & ((((UDItype) 1) << (sizeof (SItype) * 8)) - 1));
 
   return (SFtype) f;
+}
+
+DItype
+__fixunstfdi (TFtype a)
+{
+  if (a < 0)
+    return 0;
+
+  /* Compute high word of result, as a flonum.  */
+  const TFtype b = (a / (((UDItype) 1) << (sizeof (SItype) * 8)));
+  /* Convert that to fixed (but not to DItype!),
+     and shift it into the high word.  */
+  UDItype v = (USItype) b;
+  v <<= (sizeof (SItype) * 8);
+  /* Remove high part from the TFtype, leaving the low part as flonum.  */
+  a -= (TFtype) v;
+  /* Convert that to fixed (but not to DItype!) and add it in.
+     Sometimes A comes out negative.  This is significant, since
+     A has more bits than a long int does.  */
+  if (a < 0)
+    v -= (USItype) (-a);
+  else
+    v += (USItype) a;
+  return v;
 }
 
 /* This version is needed to prevent recursion; fixunsdfdi in libgcc
Index: gcc/config/rs6000/rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.582
diff -u -p -r1.582 rs6000.c
--- gcc/config/rs6000/rs6000.c	26 Jan 2004 17:40:06 -0000	1.582
+++ gcc/config/rs6000/rs6000.c	28 Jan 2004 00:21:18 -0000
@@ -4424,7 +4424,7 @@ function_arg (CUMULATIVE_ARGS *cum, enum
 				    /* If this is partially on the stack, then
 				       we only include the portion actually
 				       in registers here.  */
-				    ? gen_rtx_REG (SImode,
+				    ? gen_rtx_REG (Pmode,
 					       GP_ARG_MIN_REG + align_words)
 				    : gen_rtx_REG (mode,
 					       GP_ARG_MIN_REG + align_words))),
@@ -15737,6 +15739,7 @@ rs6000_complex_function_value (enum mach
   unsigned int regno;
   rtx r1, r2;
   enum machine_mode inner = GET_MODE_INNER (mode);
+  unsigned int inner_bytes = GET_MODE_SIZE (inner);
 
   if (FLOAT_MODE_P (mode))
     regno = FP_ARG_RETURN;
@@ -15745,15 +15748,17 @@ rs6000_complex_function_value (enum mach
       regno = GP_ARG_RETURN;
 
       /* 32-bit is OK since it'll go in r3/r4.  */
-      if (TARGET_32BIT
-	  && GET_MODE_BITSIZE (inner) >= 32)
+      if (TARGET_32BIT && inner_bytes >= 4)
 	return gen_rtx_REG (mode, regno);
     }
 
+  if (inner_bytes >= 8)
+    return gen_rtx_REG (mode, regno);
+
   r1 = gen_rtx_EXPR_LIST (inner, gen_rtx_REG (inner, regno),
 			  const0_rtx);
   r2 = gen_rtx_EXPR_LIST (inner, gen_rtx_REG (inner, regno + 1),
-			  GEN_INT (GET_MODE_UNIT_SIZE (inner)));
+			  GEN_INT (inner_bytes));
   return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2));
 }
 
Index: gcc/config/rs6000/darwin-ldouble.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/darwin-ldouble.c,v
retrieving revision 1.3
diff -u -p -r1.3 darwin-ldouble.c
--- gcc/config/rs6000/darwin-ldouble.c	12 Jan 2004 18:37:40 -0000	1.3
+++ gcc/config/rs6000/darwin-ldouble.c	29 Jan 2004 15:03:29 -0000
@@ -48,6 +48,8 @@ Software Foundation, 59 Temple Place - S
 
    This code currently assumes big-endian.  */
 
+#if !_SOFT_FLOAT
+
 #define fabs(x) __builtin_fabs(x)
 
 #define unlikely(x) __builtin_expect ((x), 0)
@@ -199,3 +201,5 @@ _xlqdiv (double a, double b, double c, d
   z.dval[1] = (t - u) + tau;
   return z.ldval;
 }
+
+#endif
Index: libffi/src/types.c
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/types.c,v
retrieving revision 1.12
diff -u -p -r1.12 types.c
--- libffi/src/types.c	21 Oct 2003 19:01:54 -0000	1.12
+++ libffi/src/types.c	28 Jan 2004 02:01:22 -0000
@@ -90,7 +90,7 @@ FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16,
 FFI_INTEGRAL_TYPEDEF(longdouble, 16, 8, FFI_TYPE_LONGDOUBLE);
 #endif
 
-#elif defined X86_64
+#elif defined X86_64 || defined POWERPC64
 
 FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE);
 FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE);

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]