Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* GDB/libiberty support for IBM long double
@ 2007-10-26  0:25 Joseph S. Myers
  2007-10-26  0:37 ` DJ Delorie
  2007-10-26  8:05 ` Mark Kettenis
  0 siblings, 2 replies; 23+ messages in thread
From: Joseph S. Myers @ 2007-10-26  0:25 UTC (permalink / raw)
  To: gdb-patches; +Cc: gcc-patches

[gcc-patches included because of the libiberty patch; note this part
of libiberty isn't used by GCC.  If approved I'll commit just the
libiberty and include parts to GCC then the whole patch to src.]

This patch adds 128-bit IBM long double support for Power GNU/Linux to
GDB.  It's based on a tree with Daniel's ABI detection patch
<http://sourceware.org/ml/gdb-patches/2007-10/msg00672.html> applied.
The approach taken by this patch is described in my message
<http://sourceware.org/ml/gdb-patches/2007-08/msg00557.html>.  The IBM
long double format is the same format as used on IRIX so the
mips-tdep.c kludge to use just the high part of a long double there is
replaced by a use of floatformats_ibm_long_double.

Tested with cross to powerpc-linux-gnu, hard-float, soft-float and
-m64.  OK to commit once Daniel's patch is in?

include:
2007-10-25  Joseph Myers  <joseph@codesourcery.com>
	    Daniel Jacobowitz  <dan@codesourcery.com>

	* floatformat.h (struct floatformat): Add split_half field.
	(floatformat_ibm_long_double): New.

libiberty:
2007-10-25  Joseph Myers  <joseph@codesourcery.com>
	    Daniel Jacobowitz  <dan@codesourcery.com>

	* floatformat.c (mant_bits_set): New.
	(floatformat_to_double): Use it.  Note no special handling of
	split formats.
	(floatformat_from_double): Note no special handing of split
	formats.
	(floatformat_ibm_long_double_is_valid,
	floatformat_ibm_long_double): New.
	(floatformat_ieee_single_big, floatformat_ieee_single_little,
	floatformat_ieee_double_big, floatformat_ieee_double_little,
	floatformat_ieee_double_littlebyte_bigword, floatformat_vax_f,
	floatformat_vax_d, floatformat_vax_g, floatformat_i387_ext,
	floatformat_m68881_ext, floatformat_i960_ext,
	floatformat_m88110_ext, floatformat_m88110_harris_ext,
	floatformat_arm_ext_big, floatformat_arm_ext_littlebyte_bigword,
	floatformat_ia64_spill_big, floatformat_ia64_spill_little,
	floatformat_ia64_quad_big, floatformat_ia64_quad_little): Update
	for addition of split_half field.

gdb:
2007-10-25  Joseph Myers  <joseph@codesourcery.com>
	    Daniel Jacobowitz  <dan@codesourcery.com>

	* gdbtypes.c (floatformats_ibm_long_double): New.
	* gdbtypes.h (floatformats_ibm_long_double): Declare.
	* ia64-tdep.c (floatformat_ia64_ext): Update for addition of
	split_half field.
	* mips-tdep.c (n32n64_floatformat_always_valid,
	floatformat_n32n64_long_double_big, floatformats_n32n64_long):
	Remove.
	(mips_gdbarch_init): Use floatformats_ibm_long_double instead of
	floatformats_n32n64_long.
	* ppc-linux-tdep.c (ppc_linux_init_abi): Use 128-bit IBM long
	double.
	* doublest.c (convert_floatformat_to_doublest,
	convert_doublest_to_floatformat): Handle split floating-point
	formats.
	* ppc-sysv-tdep.c (ppc_sysv_abi_push_dummy_call): Handle IBM long
	double arguments.
	(ppc64_sysv_abi_push_dummy_call): Likewise.
	(do_ppc_sysv_return_value): Handle IBM long double return.

diff -rupN gdb-mainline.orig/gdb/doublest.c gdb-mainline/gdb/doublest.c
--- gdb-mainline.orig/gdb/doublest.c	2007-08-23 11:08:28.000000000 -0700
+++ gdb-mainline/gdb/doublest.c	2007-10-25 15:08:22.000000000 -0700
@@ -200,6 +200,24 @@ convert_floatformat_to_doublest (const s
   if (order != fmt->byteorder)
     ufrom = newfrom;
 
+  if (fmt->split_half)
+    {
+      double dtop, dbot;
+      floatformat_to_double (fmt->split_half, ufrom, &dtop);
+      /* Preserve the sign of 0, which is the sign of the top
+	 half.  */
+      if (dtop == 0.0)
+	{
+	  *to = (DOUBLEST) dtop;
+	  return;
+	}
+      floatformat_to_double (fmt->split_half,
+			     ufrom + fmt->totalsize / FLOATFORMAT_CHAR_BIT / 2,
+			     &dbot);
+      *to = (DOUBLEST) dtop + (DOUBLEST) dbot;
+      return;
+    }
+
   exponent = get_field (ufrom, order, fmt->totalsize, fmt->exp_start,
 			fmt->exp_len);
   /* Note that if exponent indicates a NaN, we can't really do anything useful
@@ -392,6 +410,30 @@ convert_doublest_to_floatformat (CONST s
   memcpy (&dfrom, from, sizeof (dfrom));
   memset (uto, 0, (fmt->totalsize + FLOATFORMAT_CHAR_BIT - 1) 
                     / FLOATFORMAT_CHAR_BIT);
+
+  if (fmt->split_half)
+    {
+      /* Use static volatile to ensure that any excess precision is
+	 removed via storing in memory, and so the top half really is
+	 the result of converting to double.  */
+      static volatile double dtop, dbot;
+      double dtopnv, dbotnv;
+      dtop = (double) dfrom;
+      /* If the rounded top half is Inf, the bottom must be 0 not NaN
+	 or Inf.  */
+      if (dtop + dtop == dtop && dtop != 0.0)
+	dbot = 0.0;
+      else
+	dbot = (double) (dfrom - (DOUBLEST) dtop);
+      dtopnv = dtop;
+      dbotnv = dbot;
+      floatformat_from_double (fmt->split_half, &dtopnv, uto);
+      floatformat_from_double (fmt->split_half, &dbotnv,
+			       (uto
+				+ fmt->totalsize / FLOATFORMAT_CHAR_BIT / 2));
+      return;
+    }
+
   if (dfrom == 0)
     return;			/* Result is zero */
   if (dfrom != dfrom)		/* Result is NaN */
diff -rupN gdb-mainline.orig/gdb/gdbtypes.c gdb-mainline/gdb/gdbtypes.c
--- gdb-mainline.orig/gdb/gdbtypes.c	2007-10-25 10:57:34.000000000 -0700
+++ gdb-mainline/gdb/gdbtypes.c	2007-10-25 15:08:22.000000000 -0700
@@ -95,6 +95,10 @@ const struct floatformat *floatformats_v
   &floatformat_vax_d,
   &floatformat_vax_d
 };
+const struct floatformat *floatformats_ibm_long_double[BFD_ENDIAN_UNKNOWN] = {
+  &floatformat_ibm_long_double,
+  &floatformat_ibm_long_double
+};
 
 struct type *builtin_type_ieee_single;
 struct type *builtin_type_ieee_double;
diff -rupN gdb-mainline.orig/gdb/gdbtypes.h gdb-mainline/gdb/gdbtypes.h
--- gdb-mainline.orig/gdb/gdbtypes.h	2007-10-25 10:57:34.000000000 -0700
+++ gdb-mainline/gdb/gdbtypes.h	2007-10-25 15:08:22.000000000 -0700
@@ -1131,6 +1131,7 @@ extern const struct floatformat *floatfo
 extern const struct floatformat *floatformats_ia64_quad[BFD_ENDIAN_UNKNOWN];
 extern const struct floatformat *floatformats_vax_f[BFD_ENDIAN_UNKNOWN];
 extern const struct floatformat *floatformats_vax_d[BFD_ENDIAN_UNKNOWN];
+extern const struct floatformat *floatformats_ibm_long_double[BFD_ENDIAN_UNKNOWN];
 
 extern struct type *builtin_type_ieee_single;
 extern struct type *builtin_type_ieee_double;
diff -rupN gdb-mainline.orig/gdb/ia64-tdep.c gdb-mainline/gdb/ia64-tdep.c
--- gdb-mainline.orig/gdb/ia64-tdep.c	2007-10-24 13:29:14.000000000 -0700
+++ gdb-mainline/gdb/ia64-tdep.c	2007-10-25 15:08:22.000000000 -0700
@@ -329,7 +329,7 @@ floatformat_valid (const struct floatfor
 const struct floatformat floatformat_ia64_ext =
 {
   floatformat_little, 82, 0, 1, 17, 65535, 0x1ffff, 18, 64,
-  floatformat_intbit_yes, "floatformat_ia64_ext", floatformat_valid
+  floatformat_intbit_yes, NULL, "floatformat_ia64_ext", floatformat_valid
 };
 
 const struct floatformat *floatformats_ia64_ext[2] =
diff -rupN gdb-mainline.orig/gdb/mips-tdep.c gdb-mainline/gdb/mips-tdep.c
--- gdb-mainline.orig/gdb/mips-tdep.c	2007-10-23 06:11:47.000000000 -0700
+++ gdb-mainline/gdb/mips-tdep.c	2007-10-25 15:08:22.000000000 -0700
@@ -199,38 +199,6 @@ struct gdbarch_tdep
   int register_size;
 };
 
-static int
-n32n64_floatformat_always_valid (const struct floatformat *fmt,
-                                 const void *from)
-{
-  return 1;
-}
-
-/* FIXME: brobecker/2004-08-08: Long Double values are 128 bit long.
-   They are implemented as a pair of 64bit doubles where the high
-   part holds the result of the operation rounded to double, and
-   the low double holds the difference between the exact result and
-   the rounded result.  So "high" + "low" contains the result with
-   added precision.  Unfortunately, the floatformat structure used
-   by GDB is not powerful enough to describe this format.  As a temporary
-   measure, we define a 128bit floatformat that only uses the high part.
-   We lose a bit of precision but that's probably the best we can do
-   for now with the current infrastructure.  */
-
-static const struct floatformat floatformat_n32n64_long_double_big =
-{
-  floatformat_big, 128, 0, 1, 11, 1023, 2047, 12, 52,
-  floatformat_intbit_no,
-  "floatformat_n32n64_long_double_big",
-  n32n64_floatformat_always_valid
-};
-
-static const struct floatformat *floatformats_n32n64_long[BFD_ENDIAN_UNKNOWN] =
-{
-  &floatformat_n32n64_long_double_big,
-  &floatformat_n32n64_long_double_big
-};
-
 const struct mips_regnum *
 mips_regnum (struct gdbarch *gdbarch)
 {
@@ -5584,7 +5552,7 @@ mips_gdbarch_init (struct gdbarch_info i
       set_gdbarch_ptr_bit (gdbarch, 32);
       set_gdbarch_long_long_bit (gdbarch, 64);
       set_gdbarch_long_double_bit (gdbarch, 128);
-      set_gdbarch_long_double_format (gdbarch, floatformats_n32n64_long);
+      set_gdbarch_long_double_format (gdbarch, floatformats_ibm_long_double);
       break;
     case MIPS_ABI_N64:
       set_gdbarch_push_dummy_call (gdbarch, mips_n32n64_push_dummy_call);
@@ -5596,7 +5564,7 @@ mips_gdbarch_init (struct gdbarch_info i
       set_gdbarch_ptr_bit (gdbarch, 64);
       set_gdbarch_long_long_bit (gdbarch, 64);
       set_gdbarch_long_double_bit (gdbarch, 128);
-      set_gdbarch_long_double_format (gdbarch, floatformats_n32n64_long);
+      set_gdbarch_long_double_format (gdbarch, floatformats_ibm_long_double);
       break;
     default:
       internal_error (__FILE__, __LINE__, _("unknown ABI in switch"));
diff -rupN gdb-mainline.orig/gdb/ppc-linux-tdep.c gdb-mainline/gdb/ppc-linux-tdep.c
--- gdb-mainline.orig/gdb/ppc-linux-tdep.c	2007-08-30 06:13:59.000000000 -0700
+++ gdb-mainline/gdb/ppc-linux-tdep.c	2007-10-25 15:08:22.000000000 -0700
@@ -887,15 +887,13 @@ ppc_linux_init_abi (struct gdbarch_info 
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  /* NOTE: jimb/2004-03-26: The System V ABI PowerPC Processor
-     Supplement says that long doubles are sixteen bytes long.
-     However, as one of the known warts of its ABI, PPC GNU/Linux uses
-     eight-byte long doubles.  GCC only recently got 128-bit long
-     double support on PPC, so it may be changing soon.  The
-     Linux[sic] Standards Base says that programs that use 'long
-     double' on PPC GNU/Linux are non-conformant.  */
-  /* NOTE: cagney/2005-01-25: True for both 32- and 64-bit.  */
-  set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+  /* PPC GNU/Linux uses either 64-bit or 128-bit long doubles; where
+     128-bit, they are IBM long double, not IEEE quad long double as
+     in the System V ABI PowerPC Processor Supplement.  We can safely
+     let them default to 128-bit, since the debug info will give the
+     size of type actually used in each case.  */
+  set_gdbarch_long_double_bit (gdbarch, 16 * TARGET_CHAR_BIT);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ibm_long_double);
 
   /* Handle PPC GNU/Linux 64-bit function pointers (which are really
      function descriptors) and 32-bit secure PLT entries.  */
diff -rupN gdb-mainline.orig/gdb/ppc-sysv-tdep.c gdb-mainline/gdb/ppc-sysv-tdep.c
--- gdb-mainline.orig/gdb/ppc-sysv-tdep.c	2007-10-25 14:57:44.000000000 -0700
+++ gdb-mainline/gdb/ppc-sysv-tdep.c	2007-10-25 15:08:22.000000000 -0700
@@ -53,6 +53,8 @@ ppc_sysv_abi_push_dummy_call (struct gdb
   int argspace = 0;		/* 0 is an initial wrong guess.  */
   int write_pass;
 
+  gdb_assert (tdep->wordsize == 4);
+
   regcache_cooked_read_unsigned (regcache,
 				 gdbarch_sp_regnum (current_gdbarch),
 				 &saved_sp);
@@ -141,6 +143,35 @@ ppc_sysv_abi_push_dummy_call (struct gdb
 		  argoffset += 8;
 		}
 	    }
+	  else if (TYPE_CODE (type) == TYPE_CODE_FLT
+		   && len == 16
+		   && !tdep->soft_float
+		   && (gdbarch_long_double_format (current_gdbarch)
+		       == floatformats_ibm_long_double))
+	    {
+	      /* IBM long double passed in two FP registers if
+		 available, otherwise 8-byte aligned stack.  */
+	      if (freg <= 7)
+		{
+		  if (write_pass)
+		    {
+		      regcache_cooked_write (regcache,
+					     tdep->ppc_fp0_regnum + freg,
+					     val);
+		      regcache_cooked_write (regcache,
+					     tdep->ppc_fp0_regnum + freg + 1,
+					     val + 8);
+		    }
+		  freg += 2;
+		}
+	      else
+		{
+		  argoffset = align_up (argoffset, 8);
+		  if (write_pass)
+		    write_memory (sp + argoffset, val, len);
+		  argoffset += 16;
+		}
+	    }
 	  else if (len == 8
 		   && (TYPE_CODE (type) == TYPE_CODE_INT	/* long long */
 		       || TYPE_CODE (type) == TYPE_CODE_FLT))	/* double */
@@ -159,13 +190,6 @@ ppc_sysv_abi_push_dummy_call (struct gdb
 		    write_memory (sp + argoffset, val, len);
 		  argoffset += 8;
 		}
-	      else if (tdep->wordsize == 8)
-		{
-		  if (write_pass)
-		    regcache_cooked_write (regcache,
-					   tdep->ppc_gp0_regnum + greg, val);
-		  greg += 1;
-		}
 	      else
 		{
 		  /* Must start on an odd register - r3/r4 etc.  */
@@ -183,6 +207,41 @@ ppc_sysv_abi_push_dummy_call (struct gdb
 		  greg += 2;
 		}
 	    }
+	  else if (len == 16 && TYPE_CODE (type) == TYPE_CODE_FLT
+		   && (gdbarch_long_double_format (current_gdbarch)
+		       == floatformats_ibm_long_double))
+	    {
+	      /* Soft-float IBM long double passed in four consecutive
+		 registers, or on the stack.  The registers are not
+		 necessarily odd/even pairs.  */
+	      if (greg > 7)
+		{
+		  greg = 11;
+		  argoffset = align_up (argoffset, 8);
+		  if (write_pass)
+		    write_memory (sp + argoffset, val, len);
+		  argoffset += 16;
+		}
+	      else
+		{
+		  if (write_pass)
+		    {
+		      regcache_cooked_write (regcache,
+					     tdep->ppc_gp0_regnum + greg + 0,
+					     val + 0);
+		      regcache_cooked_write (regcache,
+					     tdep->ppc_gp0_regnum + greg + 1,
+					     val + 4);
+		      regcache_cooked_write (regcache,
+					     tdep->ppc_gp0_regnum + greg + 2,
+					     val + 8);
+		      regcache_cooked_write (regcache,
+					     tdep->ppc_gp0_regnum + greg + 3,
+					     val + 12);
+		    }
+		  greg += 4;
+		}
+	    }
 	  else if (len == 16
 		   && TYPE_CODE (type) == TYPE_CODE_ARRAY
 		   && TYPE_VECTOR (type)
@@ -370,6 +429,55 @@ do_ppc_sysv_return_value (struct gdbarch
 	}
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
+  if (TYPE_CODE (type) == TYPE_CODE_FLT
+      && TYPE_LENGTH (type) == 16
+      && !tdep->soft_float
+      && (gdbarch_long_double_format (current_gdbarch)
+	  == floatformats_ibm_long_double))
+    {
+      /* IBM long double stored in f1 and f2.  */
+      if (readbuf)
+	{
+	  regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1, readbuf);
+	  regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 2,
+				readbuf + 8);
+	}
+      if (writebuf)
+	{
+	  regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1, writebuf);
+	  regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 2,
+				 writebuf + 8);
+	}
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  if (TYPE_CODE (type) == TYPE_CODE_FLT
+      && TYPE_LENGTH (type) == 16
+      && (gdbarch_long_double_format (current_gdbarch)
+	  == floatformats_ibm_long_double))
+    {
+      /* Soft-float IBM long double stored in r3, r4, r5, r6.  */
+      if (readbuf)
+	{
+	  regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3, readbuf);
+	  regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 4,
+				readbuf + 4);
+	  regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 5,
+				readbuf + 8);
+	  regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 6,
+				readbuf + 12);
+	}
+      if (writebuf)
+	{
+	  regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3, writebuf);
+	  regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 4,
+				 writebuf + 4);
+	  regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 5,
+				 writebuf + 8);
+	  regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 6,
+				 writebuf + 12);
+	}
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
   if ((TYPE_CODE (type) == TYPE_CODE_INT && TYPE_LENGTH (type) == 8)
       || (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8))
     {
@@ -730,6 +838,41 @@ ppc64_sysv_abi_push_dummy_call (struct g
 	      greg++;
 	      gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
 	    }
+	  else if (TYPE_CODE (type) == TYPE_CODE_FLT
+		   && TYPE_LENGTH (type) == 16
+		   && (gdbarch_long_double_format (current_gdbarch)
+		       == floatformats_ibm_long_double))
+	    {
+	      /* IBM long double stored in two doublewords of the
+		 parameter save area and corresponding registers.  */
+	      if (write_pass)
+		{
+		  if (!tdep->soft_float && freg <= 13)
+		    {
+		      regcache_cooked_write (regcache,
+                                             tdep->ppc_fp0_regnum + freg,
+					     val);
+		      if (freg <= 12)
+			regcache_cooked_write (regcache,
+					       tdep->ppc_fp0_regnum + freg + 1,
+					       val + 8);
+		    }
+		  if (greg <= 10)
+		    {
+		      regcache_cooked_write (regcache,
+					     tdep->ppc_gp0_regnum + greg,
+					     val);
+		      if (greg <= 9)
+			regcache_cooked_write (regcache,
+					       tdep->ppc_gp0_regnum + greg + 1,
+					       val + 8);
+		    }
+		  write_memory (gparam, val, TYPE_LENGTH (type));
+		}
+	      freg += 2;
+	      greg += 2;
+	      gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+	    }
 	  else if (TYPE_LENGTH (type) == 16 && TYPE_VECTOR (type)
 		   && TYPE_CODE (type) == TYPE_CODE_ARRAY
 		   && tdep->ppc_vr0_regnum >= 0)
diff -rupN gdb-mainline.orig/include/floatformat.h gdb-mainline/include/floatformat.h
--- gdb-mainline.orig/include/floatformat.h	2005-10-31 10:01:16.000000000 -0800
+++ gdb-mainline/include/floatformat.h	2007-10-25 15:08:22.000000000 -0700
@@ -80,6 +80,13 @@ struct floatformat
   /* Is the integer bit explicit or implicit?  */
   enum floatformat_intbit intbit;
 
+  /* Is the format actually the sum of two smaller floating point
+     formats (IBM long double, as described in
+     gcc/config/rs6000/darwin-ldouble-format)?  If so, this is the
+     smaller format in question, and the fields sign_start through
+     intbit describe the first half.  If not, this is NULL.  */
+  const struct floatformat *split_half;
+
   /* Internal name for debugging. */
   const char *name;
 
@@ -118,6 +125,8 @@ extern const struct floatformat floatfor
 extern const struct floatformat floatformat_ia64_spill_little;
 extern const struct floatformat floatformat_ia64_quad_big;
 extern const struct floatformat floatformat_ia64_quad_little;
+/* IBM long double (double+double).  */
+extern const struct floatformat floatformat_ibm_long_double;
 
 /* Convert from FMT to a double.
    FROM is the address of the extended float.
diff -rupN gdb-mainline.orig/libiberty/floatformat.c gdb-mainline/libiberty/floatformat.c
--- gdb-mainline.orig/libiberty/floatformat.c	2006-11-07 07:17:40.000000000 -0800
+++ gdb-mainline/libiberty/floatformat.c	2007-10-25 15:08:22.000000000 -0700
@@ -56,6 +56,7 @@ Foundation, Inc., 51 Franklin Street - F
 #endif
 #endif
 
+static int mant_bits_set (const struct floatformat *, const unsigned char *);
 static unsigned long get_field (const unsigned char *,
                                 enum floatformat_byteorders,
                                 unsigned int,
@@ -81,6 +82,7 @@ const struct floatformat floatformat_iee
 {
   floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23,
   floatformat_intbit_no,
+  NULL,
   "floatformat_ieee_single_big",
   floatformat_always_valid
 };
@@ -88,6 +90,7 @@ const struct floatformat floatformat_iee
 {
   floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23,
   floatformat_intbit_no,
+  NULL,
   "floatformat_ieee_single_little",
   floatformat_always_valid
 };
@@ -95,6 +98,7 @@ const struct floatformat floatformat_iee
 {
   floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52,
   floatformat_intbit_no,
+  NULL,
   "floatformat_ieee_double_big",
   floatformat_always_valid
 };
@@ -102,6 +106,7 @@ const struct floatformat floatformat_iee
 {
   floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52,
   floatformat_intbit_no,
+  NULL,
   "floatformat_ieee_double_little",
   floatformat_always_valid
 };
@@ -113,6 +118,7 @@ const struct floatformat floatformat_iee
 {
   floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52,
   floatformat_intbit_no,
+  NULL,
   "floatformat_ieee_double_littlebyte_bigword",
   floatformat_always_valid
 };
@@ -123,6 +129,7 @@ const struct floatformat floatformat_vax
 {
   floatformat_vax, 32, 0, 1, 8, 129, 0, 9, 23,
   floatformat_intbit_no,
+  NULL,
   "floatformat_vax_f",
   floatformat_always_valid
 };
@@ -130,6 +137,7 @@ const struct floatformat floatformat_vax
 {
   floatformat_vax, 64, 0, 1, 8, 129, 0, 9, 55,
   floatformat_intbit_no,
+  NULL,
   "floatformat_vax_d",
   floatformat_always_valid
 };
@@ -137,6 +145,7 @@ const struct floatformat floatformat_vax
 {
   floatformat_vax, 64, 0, 1, 11, 1025, 0, 12, 52,
   floatformat_intbit_no,
+  NULL,
   "floatformat_vax_g",
   floatformat_always_valid
 };
@@ -169,6 +178,7 @@ const struct floatformat floatformat_i38
 {
   floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
   floatformat_intbit_yes,
+  NULL,
   "floatformat_i387_ext",
   floatformat_i387_ext_is_valid
 };
@@ -177,6 +187,7 @@ const struct floatformat floatformat_m68
   /* Note that the bits from 16 to 31 are unused.  */
   floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64,
   floatformat_intbit_yes,
+  NULL,
   "floatformat_m68881_ext",
   floatformat_always_valid
 };
@@ -185,6 +196,7 @@ const struct floatformat floatformat_i96
   /* Note that the bits from 0 to 15 are unused.  */
   floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64,
   floatformat_intbit_yes,
+  NULL,
   "floatformat_i960_ext",
   floatformat_always_valid
 };
@@ -192,6 +204,7 @@ const struct floatformat floatformat_m88
 {
   floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
   floatformat_intbit_yes,
+  NULL,
   "floatformat_m88110_ext",
   floatformat_always_valid
 };
@@ -201,6 +214,7 @@ const struct floatformat floatformat_m88
      double, and the last 64 bits are wasted. */
   floatformat_big,128, 0, 1, 11,  0x3ff,  0x7ff, 12, 52,
   floatformat_intbit_no,
+  NULL,
   "floatformat_m88110_ext_harris",
   floatformat_always_valid
 };
@@ -209,6 +223,7 @@ const struct floatformat floatformat_arm
   /* Bits 1 to 16 are unused.  */
   floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
   floatformat_intbit_yes,
+  NULL,
   "floatformat_arm_ext_big",
   floatformat_always_valid
 };
@@ -217,6 +232,7 @@ const struct floatformat floatformat_arm
   /* Bits 1 to 16 are unused.  */
   floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
   floatformat_intbit_yes,
+  NULL,
   "floatformat_arm_ext_littlebyte_bigword",
   floatformat_always_valid
 };
@@ -224,6 +240,7 @@ const struct floatformat floatformat_ia6
 {
   floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
   floatformat_intbit_yes,
+  NULL,
   "floatformat_ia64_spill_big",
   floatformat_always_valid
 };
@@ -231,6 +248,7 @@ const struct floatformat floatformat_ia6
 {
   floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
   floatformat_intbit_yes,
+  NULL,
   "floatformat_ia64_spill_little",
   floatformat_always_valid
 };
@@ -238,6 +256,7 @@ const struct floatformat floatformat_ia6
 {
   floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
   floatformat_intbit_no,
+  NULL,
   "floatformat_ia64_quad_big",
   floatformat_always_valid
 };
@@ -245,15 +264,138 @@ const struct floatformat floatformat_ia6
 {
   floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
   floatformat_intbit_no,
+  NULL,
   "floatformat_ia64_quad_little",
   floatformat_always_valid
 };
+
+static int
+floatformat_ibm_long_double_is_valid (const struct floatformat *fmt,
+				      const void *from)
+{
+  const unsigned char *ufrom = (const unsigned char *) from;
+  const struct floatformat *hfmt = fmt->split_half;
+  long top_exp, bot_exp;
+  int top_nan = 0;
+
+  top_exp = get_field (ufrom, hfmt->byteorder, hfmt->totalsize,
+		       hfmt->exp_start, hfmt->exp_len);
+  bot_exp = get_field (ufrom + 8, hfmt->byteorder, hfmt->totalsize,
+		       hfmt->exp_start, hfmt->exp_len);
+
+  if (top_exp == hfmt->exp_nan)
+    top_nan = mant_bits_set (hfmt, ufrom);
+
+  /* A NaN is valid with any low part.  */
+  if (top_nan)
+    return 1;
+
+  /* An infinity, zero or denormal requires low part 0 (positive or
+     negative).  */
+  if (top_exp == hfmt->exp_nan || top_exp == 0)
+    {
+      unsigned int mant_bits, mant_off;
+      int mant_bits_left;
+
+      if (bot_exp != 0)
+	return 0;
+
+      return !mant_bits_set (hfmt, ufrom + 8);
+    }
+
+  /* The top part is now a finite normal value.  The long double value
+     is the sum of the two parts, and the top part must equal the
+     result of rounding the long double value to nearest double.  Thus
+     the bottom part must be <= 0.5ulp of the top part in absolute
+     value, and if it is < 0.5ulp then the long double is definitely
+     valid.  */
+  if (bot_exp < top_exp - 53)
+    return 1;
+  if (bot_exp > top_exp - 53 && bot_exp != 0)
+    return 0;
+  if (bot_exp == 0)
+    {
+      /* The bottom part is 0 or denormal.  Determine which, and if
+	 denormal the first two set bits.  */
+      int first_bit = -1, second_bit = -1, cur_bit;
+      for (cur_bit = 0; cur_bit < hfmt->man_len; cur_bit++)
+	if (get_field (ufrom + 8, hfmt->byteorder, hfmt->totalsize,
+		       hfmt->man_start + cur_bit, 1))
+	  {
+	    if (first_bit == -1)
+	      first_bit = cur_bit;
+	    else
+	      {
+		second_bit = cur_bit;
+		break;
+	      }
+	  }
+      /* Bottom part 0 is OK.  */
+      if (first_bit == -1)
+	return 1;
+      /* The real exponent of the bottom part is -first_bit.  */
+      if (-first_bit < top_exp - 53)
+	return 1;
+      if (-first_bit > top_exp - 53)
+	return 0;
+      /* The bottom part is at least 0.5ulp of the top part.  For this
+	 to be OK, the bottom part must be exactly 0.5ulp (i.e. no
+	 more bits set) and the top part must have last bit 0.  */
+      if (second_bit != -1)
+	return 0;
+      return !get_field (ufrom, hfmt->byteorder, hfmt->totalsize,
+			 hfmt->man_start + hfmt->man_len - 1, 1);
+    }
+  else
+    {
+      /* The bottom part is at least 0.5ulp of the top part.  For this
+	 to be OK, it must be exactly 0.5ulp (i.e. no explicit bits
+	 set) and the top part must have last bit 0.  */
+      if (get_field (ufrom, hfmt->byteorder, hfmt->totalsize,
+		     hfmt->man_start + hfmt->man_len - 1, 1))
+	return 0;
+      return !mant_bits_set (hfmt, ufrom + 8);
+    }
+}
+
+const struct floatformat floatformat_ibm_long_double =
+{
+  floatformat_big, 128, 0, 1, 11, 1023, 2047, 12, 52,
+  floatformat_intbit_no,
+  &floatformat_ieee_double_big,
+  "floatformat_ibm_long_double",
+  floatformat_always_valid
+};
 \f
 
 #ifndef min
 #define min(a, b) ((a) < (b) ? (a) : (b))
 #endif
 
+/* Return 1 if any bits are explicitly set in the mantissa of UFROM,
+   format FMT, 0 otherwise.  */
+static int
+mant_bits_set (const struct floatformat *fmt, const unsigned char *ufrom)
+{
+  unsigned int mant_bits, mant_off;
+  int mant_bits_left;
+
+  mant_off = fmt->man_start;
+  mant_bits_left = fmt->man_len;
+  while (mant_bits_left > 0)
+    {
+      mant_bits = min (mant_bits_left, 32);
+
+      if (get_field (ufrom, fmt->byteorder, fmt->totalsize,
+		     mant_off, mant_bits) != 0)
+	return 1;
+
+      mant_off += mant_bits;
+      mant_bits_left -= mant_bits;
+    }
+  return 0;
+}
+
 /* Extract a field which starts at START and is LEN bits long.  DATA and
    TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER.  */
 static unsigned long
@@ -310,6 +452,10 @@ floatformat_to_double (const struct floa
   int mant_bits_left;
   int special_exponent;		/* It's a NaN, denorm or zero */
 
+  /* Split values are not handled specially, since the top half has
+     the correctly rounded double value (in the only supported case of
+     split values).  */
+
   exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
 			fmt->exp_start, fmt->exp_len);
 
@@ -318,26 +464,7 @@ floatformat_to_double (const struct floa
      don't try to preserve the type of NaN.  FIXME.  */
   if ((unsigned long) exponent == fmt->exp_nan)
     {
-      int nan;
-
-      mant_off = fmt->man_start;
-      mant_bits_left = fmt->man_len;
-      nan = 0;
-      while (mant_bits_left > 0)
-	{
-	  mant_bits = min (mant_bits_left, 32);
-
-	  if (get_field (ufrom, fmt->byteorder, fmt->totalsize,
-			 mant_off, mant_bits) != 0)
-	    {
-	      /* This is a NaN.  */
-	      nan = 1;
-	      break;
-	    }
-
-	  mant_off += mant_bits;
-	  mant_bits_left -= mant_bits;
-	}
+      int nan = mant_bits_set (fmt, ufrom);
 
       /* On certain systems (such as GNU/Linux), the use of the
 	 INFINITY macro below may generate a warning that can not be
@@ -474,6 +601,10 @@ floatformat_from_double (const struct fl
   dfrom = *from;
   memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT);
 
+  /* Split values are not handled specially, since a bottom half of
+     zero is correct for any value representable as double (in the
+     only supported case of split values).  */
+
   /* If negative, set the sign bit.  */
   if (dfrom < 0)
     {

-- 
Joseph S. Myers
joseph@codesourcery.com


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: GDB/libiberty support for IBM long double
  2007-10-26  0:25 GDB/libiberty support for IBM long double Joseph S. Myers
@ 2007-10-26  0:37 ` DJ Delorie
  2007-10-29  1:31   ` Joseph S. Myers
  2007-10-26  8:05 ` Mark Kettenis
  1 sibling, 1 reply; 23+ messages in thread
From: DJ Delorie @ 2007-10-26  0:37 UTC (permalink / raw)
  To: joseph; +Cc: gdb-patches, gcc-patches


I'd rather see the new field at the end of the structure, not the
middle.  Unfortunately, there are some platforms that install
libiberty as a system-wide shared library, so we need to be aware of
binary compatibility issues, and not needlessly break them.

Other than that, the libiberty parts look OK.


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: GDB/libiberty support for IBM long double
  2007-10-26  0:25 GDB/libiberty support for IBM long double Joseph S. Myers
  2007-10-26  0:37 ` DJ Delorie
@ 2007-10-26  8:05 ` Mark Kettenis
  2007-10-26 15:01   ` Joseph S. Myers
  1 sibling, 1 reply; 23+ messages in thread
From: Mark Kettenis @ 2007-10-26  8:05 UTC (permalink / raw)
  To: joseph; +Cc: gdb-patches, gcc-patches

> Date: Fri, 26 Oct 2007 00:13:20 +0000 (UTC)
> From: "Joseph S. Myers" <joseph@codesourcery.com>
> 
> [gcc-patches included because of the libiberty patch; note this part
> of libiberty isn't used by GCC.  If approved I'll commit just the
> libiberty and include parts to GCC then the whole patch to src.]
> 
> This patch adds 128-bit IBM long double support for Power GNU/Linux to
> GDB.  It's based on a tree with Daniel's ABI detection patch
> <http://sourceware.org/ml/gdb-patches/2007-10/msg00672.html> applied.
> The approach taken by this patch is described in my message
> <http://sourceware.org/ml/gdb-patches/2007-08/msg00557.html>.  The IBM
> long double format is the same format as used on IRIX so the
> mips-tdep.c kludge to use just the high part of a long double there is
> replaced by a use of floatformats_ibm_long_double.

Hmm, can't we have a somewhat better (more general) name than
floatformats_ibm_long_double (especially since it is no exclusively
used for IBM hardware).


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: GDB/libiberty support for IBM long double
  2007-10-26  8:05 ` Mark Kettenis
@ 2007-10-26 15:01   ` Joseph S. Myers
  0 siblings, 0 replies; 23+ messages in thread
From: Joseph S. Myers @ 2007-10-26 15:01 UTC (permalink / raw)
  To: Mark Kettenis; +Cc: gdb-patches, gcc-patches

On Fri, 26 Oct 2007, Mark Kettenis wrote:

> Hmm, can't we have a somewhat better (more general) name than
> floatformats_ibm_long_double (especially since it is no exclusively
> used for IBM hardware).

IBM long double is the name used in the GCC ABI option 
(-mabi=ibmlongdouble) and in the taxonomy in use by the Power ABI working 
group (ATR-LONG-DOUBLE-IBM).  The alternative I've seen is "double double" 
but that looks rather like a typo.

-- 
Joseph S. Myers
joseph@codesourcery.com


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: GDB/libiberty support for IBM long double
  2007-10-26  0:37 ` DJ Delorie
@ 2007-10-29  1:31   ` Joseph S. Myers
  2007-11-05 22:33     ` Ping " Joseph S. Myers
                       ` (2 more replies)
  0 siblings, 3 replies; 23+ messages in thread
From: Joseph S. Myers @ 2007-10-29  1:31 UTC (permalink / raw)
  To: DJ Delorie; +Cc: gdb-patches, gcc-patches

This revised version moves the split_half field to the end of the
structure as requested; everything else remains as in the original
patch <http://sourceware.org/ml/gdb-patches/2007-10/msg00687.html>,
and it's been tested in the same way.  OK to commit once Daniel's ABI
detection patch is in?

include:
2007-10-27  Joseph Myers  <joseph@codesourcery.com>
	    Daniel Jacobowitz  <dan@codesourcery.com>

	* floatformat.h (struct floatformat): Add split_half field.
	(floatformat_ibm_long_double): New.

libiberty:
2007-10-27  Joseph Myers  <joseph@codesourcery.com>
	    Daniel Jacobowitz  <dan@codesourcery.com>

	* floatformat.c (mant_bits_set): New.
	(floatformat_to_double): Use it.  Note no special handling of
	split formats.
	(floatformat_from_double): Note no special handing of split
	formats.
	(floatformat_ibm_long_double_is_valid,
	floatformat_ibm_long_double): New.
	(floatformat_ieee_single_big, floatformat_ieee_single_little,
	floatformat_ieee_double_big, floatformat_ieee_double_little,
	floatformat_ieee_double_littlebyte_bigword, floatformat_vax_f,
	floatformat_vax_d, floatformat_vax_g, floatformat_i387_ext,
	floatformat_m68881_ext, floatformat_i960_ext,
	floatformat_m88110_ext, floatformat_m88110_harris_ext,
	floatformat_arm_ext_big, floatformat_arm_ext_littlebyte_bigword,
	floatformat_ia64_spill_big, floatformat_ia64_spill_little,
	floatformat_ia64_quad_big, floatformat_ia64_quad_little): Update
	for addition of split_half field.

gdb:
2007-10-27  Joseph Myers  <joseph@codesourcery.com>
	    Daniel Jacobowitz  <dan@codesourcery.com>

	* gdbtypes.c (floatformats_ibm_long_double): New.
	* gdbtypes.h (floatformats_ibm_long_double): Declare.
	* ia64-tdep.c (floatformat_ia64_ext): Update for addition of
	split_half field.
	* mips-tdep.c (n32n64_floatformat_always_valid,
	floatformat_n32n64_long_double_big, floatformats_n32n64_long):
	Remove.
	(mips_gdbarch_init): Use floatformats_ibm_long_double instead of
	floatformats_n32n64_long.
	* ppc-linux-tdep.c (ppc_linux_init_abi): Use 128-bit IBM long
	double.
	* doublest.c (convert_floatformat_to_doublest,
	convert_doublest_to_floatformat): Handle split floating-point
	formats.
	* ppc-sysv-tdep.c (ppc_sysv_abi_push_dummy_call): Handle IBM long
	double arguments.
	(ppc64_sysv_abi_push_dummy_call): Likewise.
	(do_ppc_sysv_return_value): Handle IBM long double return.

diff -rupN gdb-mainline.orig/gdb/doublest.c gdb-mainline/gdb/doublest.c
--- gdb-mainline.orig/gdb/doublest.c	2007-08-23 11:08:28.000000000 -0700
+++ gdb-mainline/gdb/doublest.c	2007-10-25 15:08:22.000000000 -0700
@@ -200,6 +200,24 @@ convert_floatformat_to_doublest (const s
   if (order != fmt->byteorder)
     ufrom = newfrom;
 
+  if (fmt->split_half)
+    {
+      double dtop, dbot;
+      floatformat_to_double (fmt->split_half, ufrom, &dtop);
+      /* Preserve the sign of 0, which is the sign of the top
+	 half.  */
+      if (dtop == 0.0)
+	{
+	  *to = (DOUBLEST) dtop;
+	  return;
+	}
+      floatformat_to_double (fmt->split_half,
+			     ufrom + fmt->totalsize / FLOATFORMAT_CHAR_BIT / 2,
+			     &dbot);
+      *to = (DOUBLEST) dtop + (DOUBLEST) dbot;
+      return;
+    }
+
   exponent = get_field (ufrom, order, fmt->totalsize, fmt->exp_start,
 			fmt->exp_len);
   /* Note that if exponent indicates a NaN, we can't really do anything useful
@@ -392,6 +410,30 @@ convert_doublest_to_floatformat (CONST s
   memcpy (&dfrom, from, sizeof (dfrom));
   memset (uto, 0, (fmt->totalsize + FLOATFORMAT_CHAR_BIT - 1) 
                     / FLOATFORMAT_CHAR_BIT);
+
+  if (fmt->split_half)
+    {
+      /* Use static volatile to ensure that any excess precision is
+	 removed via storing in memory, and so the top half really is
+	 the result of converting to double.  */
+      static volatile double dtop, dbot;
+      double dtopnv, dbotnv;
+      dtop = (double) dfrom;
+      /* If the rounded top half is Inf, the bottom must be 0 not NaN
+	 or Inf.  */
+      if (dtop + dtop == dtop && dtop != 0.0)
+	dbot = 0.0;
+      else
+	dbot = (double) (dfrom - (DOUBLEST) dtop);
+      dtopnv = dtop;
+      dbotnv = dbot;
+      floatformat_from_double (fmt->split_half, &dtopnv, uto);
+      floatformat_from_double (fmt->split_half, &dbotnv,
+			       (uto
+				+ fmt->totalsize / FLOATFORMAT_CHAR_BIT / 2));
+      return;
+    }
+
   if (dfrom == 0)
     return;			/* Result is zero */
   if (dfrom != dfrom)		/* Result is NaN */
diff -rupN gdb-mainline.orig/gdb/gdbtypes.c gdb-mainline/gdb/gdbtypes.c
--- gdb-mainline.orig/gdb/gdbtypes.c	2007-10-25 10:57:34.000000000 -0700
+++ gdb-mainline/gdb/gdbtypes.c	2007-10-25 15:08:22.000000000 -0700
@@ -95,6 +95,10 @@ const struct floatformat *floatformats_v
   &floatformat_vax_d,
   &floatformat_vax_d
 };
+const struct floatformat *floatformats_ibm_long_double[BFD_ENDIAN_UNKNOWN] = {
+  &floatformat_ibm_long_double,
+  &floatformat_ibm_long_double
+};
 
 struct type *builtin_type_ieee_single;
 struct type *builtin_type_ieee_double;
diff -rupN gdb-mainline.orig/gdb/gdbtypes.h gdb-mainline/gdb/gdbtypes.h
--- gdb-mainline.orig/gdb/gdbtypes.h	2007-10-25 10:57:34.000000000 -0700
+++ gdb-mainline/gdb/gdbtypes.h	2007-10-25 15:08:22.000000000 -0700
@@ -1131,6 +1131,7 @@ extern const struct floatformat *floatfo
 extern const struct floatformat *floatformats_ia64_quad[BFD_ENDIAN_UNKNOWN];
 extern const struct floatformat *floatformats_vax_f[BFD_ENDIAN_UNKNOWN];
 extern const struct floatformat *floatformats_vax_d[BFD_ENDIAN_UNKNOWN];
+extern const struct floatformat *floatformats_ibm_long_double[BFD_ENDIAN_UNKNOWN];
 
 extern struct type *builtin_type_ieee_single;
 extern struct type *builtin_type_ieee_double;
diff -rupN gdb-mainline.orig/gdb/ia64-tdep.c gdb-mainline/gdb/ia64-tdep.c
--- gdb-mainline.orig/gdb/ia64-tdep.c	2007-10-24 13:29:14.000000000 -0700
+++ gdb-mainline/gdb/ia64-tdep.c	2007-10-27 10:39:21.000000000 -0700
@@ -329,7 +329,7 @@ floatformat_valid (const struct floatfor
 const struct floatformat floatformat_ia64_ext =
 {
   floatformat_little, 82, 0, 1, 17, 65535, 0x1ffff, 18, 64,
-  floatformat_intbit_yes, "floatformat_ia64_ext", floatformat_valid
+  floatformat_intbit_yes, "floatformat_ia64_ext", floatformat_valid, NULL
 };
 
 const struct floatformat *floatformats_ia64_ext[2] =
diff -rupN gdb-mainline.orig/gdb/mips-tdep.c gdb-mainline/gdb/mips-tdep.c
--- gdb-mainline.orig/gdb/mips-tdep.c	2007-10-23 06:11:47.000000000 -0700
+++ gdb-mainline/gdb/mips-tdep.c	2007-10-25 15:08:22.000000000 -0700
@@ -199,38 +199,6 @@ struct gdbarch_tdep
   int register_size;
 };
 
-static int
-n32n64_floatformat_always_valid (const struct floatformat *fmt,
-                                 const void *from)
-{
-  return 1;
-}
-
-/* FIXME: brobecker/2004-08-08: Long Double values are 128 bit long.
-   They are implemented as a pair of 64bit doubles where the high
-   part holds the result of the operation rounded to double, and
-   the low double holds the difference between the exact result and
-   the rounded result.  So "high" + "low" contains the result with
-   added precision.  Unfortunately, the floatformat structure used
-   by GDB is not powerful enough to describe this format.  As a temporary
-   measure, we define a 128bit floatformat that only uses the high part.
-   We lose a bit of precision but that's probably the best we can do
-   for now with the current infrastructure.  */
-
-static const struct floatformat floatformat_n32n64_long_double_big =
-{
-  floatformat_big, 128, 0, 1, 11, 1023, 2047, 12, 52,
-  floatformat_intbit_no,
-  "floatformat_n32n64_long_double_big",
-  n32n64_floatformat_always_valid
-};
-
-static const struct floatformat *floatformats_n32n64_long[BFD_ENDIAN_UNKNOWN] =
-{
-  &floatformat_n32n64_long_double_big,
-  &floatformat_n32n64_long_double_big
-};
-
 const struct mips_regnum *
 mips_regnum (struct gdbarch *gdbarch)
 {
@@ -5584,7 +5552,7 @@ mips_gdbarch_init (struct gdbarch_info i
       set_gdbarch_ptr_bit (gdbarch, 32);
       set_gdbarch_long_long_bit (gdbarch, 64);
       set_gdbarch_long_double_bit (gdbarch, 128);
-      set_gdbarch_long_double_format (gdbarch, floatformats_n32n64_long);
+      set_gdbarch_long_double_format (gdbarch, floatformats_ibm_long_double);
       break;
     case MIPS_ABI_N64:
       set_gdbarch_push_dummy_call (gdbarch, mips_n32n64_push_dummy_call);
@@ -5596,7 +5564,7 @@ mips_gdbarch_init (struct gdbarch_info i
       set_gdbarch_ptr_bit (gdbarch, 64);
       set_gdbarch_long_long_bit (gdbarch, 64);
       set_gdbarch_long_double_bit (gdbarch, 128);
-      set_gdbarch_long_double_format (gdbarch, floatformats_n32n64_long);
+      set_gdbarch_long_double_format (gdbarch, floatformats_ibm_long_double);
       break;
     default:
       internal_error (__FILE__, __LINE__, _("unknown ABI in switch"));
diff -rupN gdb-mainline.orig/gdb/ppc-linux-tdep.c gdb-mainline/gdb/ppc-linux-tdep.c
--- gdb-mainline.orig/gdb/ppc-linux-tdep.c	2007-08-30 06:13:59.000000000 -0700
+++ gdb-mainline/gdb/ppc-linux-tdep.c	2007-10-25 15:08:22.000000000 -0700
@@ -887,15 +887,13 @@ ppc_linux_init_abi (struct gdbarch_info 
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  /* NOTE: jimb/2004-03-26: The System V ABI PowerPC Processor
-     Supplement says that long doubles are sixteen bytes long.
-     However, as one of the known warts of its ABI, PPC GNU/Linux uses
-     eight-byte long doubles.  GCC only recently got 128-bit long
-     double support on PPC, so it may be changing soon.  The
-     Linux[sic] Standards Base says that programs that use 'long
-     double' on PPC GNU/Linux are non-conformant.  */
-  /* NOTE: cagney/2005-01-25: True for both 32- and 64-bit.  */
-  set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+  /* PPC GNU/Linux uses either 64-bit or 128-bit long doubles; where
+     128-bit, they are IBM long double, not IEEE quad long double as
+     in the System V ABI PowerPC Processor Supplement.  We can safely
+     let them default to 128-bit, since the debug info will give the
+     size of type actually used in each case.  */
+  set_gdbarch_long_double_bit (gdbarch, 16 * TARGET_CHAR_BIT);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ibm_long_double);
 
   /* Handle PPC GNU/Linux 64-bit function pointers (which are really
      function descriptors) and 32-bit secure PLT entries.  */
diff -rupN gdb-mainline.orig/gdb/ppc-sysv-tdep.c gdb-mainline/gdb/ppc-sysv-tdep.c
--- gdb-mainline.orig/gdb/ppc-sysv-tdep.c	2007-10-25 14:57:44.000000000 -0700
+++ gdb-mainline/gdb/ppc-sysv-tdep.c	2007-10-25 15:08:22.000000000 -0700
@@ -53,6 +53,8 @@ ppc_sysv_abi_push_dummy_call (struct gdb
   int argspace = 0;		/* 0 is an initial wrong guess.  */
   int write_pass;
 
+  gdb_assert (tdep->wordsize == 4);
+
   regcache_cooked_read_unsigned (regcache,
 				 gdbarch_sp_regnum (current_gdbarch),
 				 &saved_sp);
@@ -141,6 +143,35 @@ ppc_sysv_abi_push_dummy_call (struct gdb
 		  argoffset += 8;
 		}
 	    }
+	  else if (TYPE_CODE (type) == TYPE_CODE_FLT
+		   && len == 16
+		   && !tdep->soft_float
+		   && (gdbarch_long_double_format (current_gdbarch)
+		       == floatformats_ibm_long_double))
+	    {
+	      /* IBM long double passed in two FP registers if
+		 available, otherwise 8-byte aligned stack.  */
+	      if (freg <= 7)
+		{
+		  if (write_pass)
+		    {
+		      regcache_cooked_write (regcache,
+					     tdep->ppc_fp0_regnum + freg,
+					     val);
+		      regcache_cooked_write (regcache,
+					     tdep->ppc_fp0_regnum + freg + 1,
+					     val + 8);
+		    }
+		  freg += 2;
+		}
+	      else
+		{
+		  argoffset = align_up (argoffset, 8);
+		  if (write_pass)
+		    write_memory (sp + argoffset, val, len);
+		  argoffset += 16;
+		}
+	    }
 	  else if (len == 8
 		   && (TYPE_CODE (type) == TYPE_CODE_INT	/* long long */
 		       || TYPE_CODE (type) == TYPE_CODE_FLT))	/* double */
@@ -159,13 +190,6 @@ ppc_sysv_abi_push_dummy_call (struct gdb
 		    write_memory (sp + argoffset, val, len);
 		  argoffset += 8;
 		}
-	      else if (tdep->wordsize == 8)
-		{
-		  if (write_pass)
-		    regcache_cooked_write (regcache,
-					   tdep->ppc_gp0_regnum + greg, val);
-		  greg += 1;
-		}
 	      else
 		{
 		  /* Must start on an odd register - r3/r4 etc.  */
@@ -183,6 +207,41 @@ ppc_sysv_abi_push_dummy_call (struct gdb
 		  greg += 2;
 		}
 	    }
+	  else if (len == 16 && TYPE_CODE (type) == TYPE_CODE_FLT
+		   && (gdbarch_long_double_format (current_gdbarch)
+		       == floatformats_ibm_long_double))
+	    {
+	      /* Soft-float IBM long double passed in four consecutive
+		 registers, or on the stack.  The registers are not
+		 necessarily odd/even pairs.  */
+	      if (greg > 7)
+		{
+		  greg = 11;
+		  argoffset = align_up (argoffset, 8);
+		  if (write_pass)
+		    write_memory (sp + argoffset, val, len);
+		  argoffset += 16;
+		}
+	      else
+		{
+		  if (write_pass)
+		    {
+		      regcache_cooked_write (regcache,
+					     tdep->ppc_gp0_regnum + greg + 0,
+					     val + 0);
+		      regcache_cooked_write (regcache,
+					     tdep->ppc_gp0_regnum + greg + 1,
+					     val + 4);
+		      regcache_cooked_write (regcache,
+					     tdep->ppc_gp0_regnum + greg + 2,
+					     val + 8);
+		      regcache_cooked_write (regcache,
+					     tdep->ppc_gp0_regnum + greg + 3,
+					     val + 12);
+		    }
+		  greg += 4;
+		}
+	    }
 	  else if (len == 16
 		   && TYPE_CODE (type) == TYPE_CODE_ARRAY
 		   && TYPE_VECTOR (type)
@@ -370,6 +429,55 @@ do_ppc_sysv_return_value (struct gdbarch
 	}
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
+  if (TYPE_CODE (type) == TYPE_CODE_FLT
+      && TYPE_LENGTH (type) == 16
+      && !tdep->soft_float
+      && (gdbarch_long_double_format (current_gdbarch)
+	  == floatformats_ibm_long_double))
+    {
+      /* IBM long double stored in f1 and f2.  */
+      if (readbuf)
+	{
+	  regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1, readbuf);
+	  regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 2,
+				readbuf + 8);
+	}
+      if (writebuf)
+	{
+	  regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1, writebuf);
+	  regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 2,
+				 writebuf + 8);
+	}
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  if (TYPE_CODE (type) == TYPE_CODE_FLT
+      && TYPE_LENGTH (type) == 16
+      && (gdbarch_long_double_format (current_gdbarch)
+	  == floatformats_ibm_long_double))
+    {
+      /* Soft-float IBM long double stored in r3, r4, r5, r6.  */
+      if (readbuf)
+	{
+	  regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3, readbuf);
+	  regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 4,
+				readbuf + 4);
+	  regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 5,
+				readbuf + 8);
+	  regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 6,
+				readbuf + 12);
+	}
+      if (writebuf)
+	{
+	  regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3, writebuf);
+	  regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 4,
+				 writebuf + 4);
+	  regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 5,
+				 writebuf + 8);
+	  regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 6,
+				 writebuf + 12);
+	}
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
   if ((TYPE_CODE (type) == TYPE_CODE_INT && TYPE_LENGTH (type) == 8)
       || (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8))
     {
@@ -730,6 +838,41 @@ ppc64_sysv_abi_push_dummy_call (struct g
 	      greg++;
 	      gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
 	    }
+	  else if (TYPE_CODE (type) == TYPE_CODE_FLT
+		   && TYPE_LENGTH (type) == 16
+		   && (gdbarch_long_double_format (current_gdbarch)
+		       == floatformats_ibm_long_double))
+	    {
+	      /* IBM long double stored in two doublewords of the
+		 parameter save area and corresponding registers.  */
+	      if (write_pass)
+		{
+		  if (!tdep->soft_float && freg <= 13)
+		    {
+		      regcache_cooked_write (regcache,
+                                             tdep->ppc_fp0_regnum + freg,
+					     val);
+		      if (freg <= 12)
+			regcache_cooked_write (regcache,
+					       tdep->ppc_fp0_regnum + freg + 1,
+					       val + 8);
+		    }
+		  if (greg <= 10)
+		    {
+		      regcache_cooked_write (regcache,
+					     tdep->ppc_gp0_regnum + greg,
+					     val);
+		      if (greg <= 9)
+			regcache_cooked_write (regcache,
+					       tdep->ppc_gp0_regnum + greg + 1,
+					       val + 8);
+		    }
+		  write_memory (gparam, val, TYPE_LENGTH (type));
+		}
+	      freg += 2;
+	      greg += 2;
+	      gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+	    }
 	  else if (TYPE_LENGTH (type) == 16 && TYPE_VECTOR (type)
 		   && TYPE_CODE (type) == TYPE_CODE_ARRAY
 		   && tdep->ppc_vr0_regnum >= 0)
diff -rupN gdb-mainline.orig/include/floatformat.h gdb-mainline/include/floatformat.h
--- gdb-mainline.orig/include/floatformat.h	2005-10-31 10:01:16.000000000 -0800
+++ gdb-mainline/include/floatformat.h	2007-10-27 10:38:33.000000000 -0700
@@ -85,6 +85,13 @@ struct floatformat
 
   /* Validator method.  */
   int (*is_valid) (const struct floatformat *fmt, const void *from);
+
+  /* Is the format actually the sum of two smaller floating point
+     formats (IBM long double, as described in
+     gcc/config/rs6000/darwin-ldouble-format)?  If so, this is the
+     smaller format in question, and the fields sign_start through
+     intbit describe the first half.  If not, this is NULL.  */
+  const struct floatformat *split_half;
 };
 
 /* floatformats for IEEE single and double, big and little endian.  */
@@ -118,6 +125,8 @@ extern const struct floatformat floatfor
 extern const struct floatformat floatformat_ia64_spill_little;
 extern const struct floatformat floatformat_ia64_quad_big;
 extern const struct floatformat floatformat_ia64_quad_little;
+/* IBM long double (double+double).  */
+extern const struct floatformat floatformat_ibm_long_double;
 
 /* Convert from FMT to a double.
    FROM is the address of the extended float.
diff -rupN gdb-mainline.orig/libiberty/floatformat.c gdb-mainline/libiberty/floatformat.c
--- gdb-mainline.orig/libiberty/floatformat.c	2006-11-07 07:17:40.000000000 -0800
+++ gdb-mainline/libiberty/floatformat.c	2007-10-27 10:43:10.000000000 -0700
@@ -56,6 +56,7 @@ Foundation, Inc., 51 Franklin Street - F
 #endif
 #endif
 
+static int mant_bits_set (const struct floatformat *, const unsigned char *);
 static unsigned long get_field (const unsigned char *,
                                 enum floatformat_byteorders,
                                 unsigned int,
@@ -82,28 +83,32 @@ const struct floatformat floatformat_iee
   floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23,
   floatformat_intbit_no,
   "floatformat_ieee_single_big",
-  floatformat_always_valid
+  floatformat_always_valid,
+  NULL
 };
 const struct floatformat floatformat_ieee_single_little =
 {
   floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23,
   floatformat_intbit_no,
   "floatformat_ieee_single_little",
-  floatformat_always_valid
+  floatformat_always_valid,
+  NULL
 };
 const struct floatformat floatformat_ieee_double_big =
 {
   floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52,
   floatformat_intbit_no,
   "floatformat_ieee_double_big",
-  floatformat_always_valid
+  floatformat_always_valid,
+  NULL
 };
 const struct floatformat floatformat_ieee_double_little =
 {
   floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52,
   floatformat_intbit_no,
   "floatformat_ieee_double_little",
-  floatformat_always_valid
+  floatformat_always_valid,
+  NULL
 };
 
 /* floatformat for IEEE double, little endian byte order, with big endian word
@@ -114,7 +119,8 @@ const struct floatformat floatformat_iee
   floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52,
   floatformat_intbit_no,
   "floatformat_ieee_double_littlebyte_bigword",
-  floatformat_always_valid
+  floatformat_always_valid,
+  NULL
 };
 
 /* floatformat for VAX.  Not quite IEEE, but close enough.  */
@@ -124,21 +130,24 @@ const struct floatformat floatformat_vax
   floatformat_vax, 32, 0, 1, 8, 129, 0, 9, 23,
   floatformat_intbit_no,
   "floatformat_vax_f",
-  floatformat_always_valid
+  floatformat_always_valid,
+  NULL
 };
 const struct floatformat floatformat_vax_d =
 {
   floatformat_vax, 64, 0, 1, 8, 129, 0, 9, 55,
   floatformat_intbit_no,
   "floatformat_vax_d",
-  floatformat_always_valid
+  floatformat_always_valid,
+  NULL
 };
 const struct floatformat floatformat_vax_g =
 {
   floatformat_vax, 64, 0, 1, 11, 1025, 0, 12, 52,
   floatformat_intbit_no,
   "floatformat_vax_g",
-  floatformat_always_valid
+  floatformat_always_valid,
+  NULL
 };
 
 static int floatformat_i387_ext_is_valid (const struct floatformat *fmt,
@@ -170,7 +179,8 @@ const struct floatformat floatformat_i38
   floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
   floatformat_intbit_yes,
   "floatformat_i387_ext",
-  floatformat_i387_ext_is_valid
+  floatformat_i387_ext_is_valid,
+  NULL
 };
 const struct floatformat floatformat_m68881_ext =
 {
@@ -178,7 +188,8 @@ const struct floatformat floatformat_m68
   floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64,
   floatformat_intbit_yes,
   "floatformat_m68881_ext",
-  floatformat_always_valid
+  floatformat_always_valid,
+  NULL
 };
 const struct floatformat floatformat_i960_ext =
 {
@@ -186,14 +197,16 @@ const struct floatformat floatformat_i96
   floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64,
   floatformat_intbit_yes,
   "floatformat_i960_ext",
-  floatformat_always_valid
+  floatformat_always_valid,
+  NULL
 };
 const struct floatformat floatformat_m88110_ext =
 {
   floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
   floatformat_intbit_yes,
   "floatformat_m88110_ext",
-  floatformat_always_valid
+  floatformat_always_valid,
+  NULL
 };
 const struct floatformat floatformat_m88110_harris_ext =
 {
@@ -202,7 +215,8 @@ const struct floatformat floatformat_m88
   floatformat_big,128, 0, 1, 11,  0x3ff,  0x7ff, 12, 52,
   floatformat_intbit_no,
   "floatformat_m88110_ext_harris",
-  floatformat_always_valid
+  floatformat_always_valid,
+  NULL
 };
 const struct floatformat floatformat_arm_ext_big =
 {
@@ -210,7 +224,8 @@ const struct floatformat floatformat_arm
   floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
   floatformat_intbit_yes,
   "floatformat_arm_ext_big",
-  floatformat_always_valid
+  floatformat_always_valid,
+  NULL
 };
 const struct floatformat floatformat_arm_ext_littlebyte_bigword =
 {
@@ -218,35 +233,138 @@ const struct floatformat floatformat_arm
   floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
   floatformat_intbit_yes,
   "floatformat_arm_ext_littlebyte_bigword",
-  floatformat_always_valid
+  floatformat_always_valid,
+  NULL
 };
 const struct floatformat floatformat_ia64_spill_big =
 {
   floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
   floatformat_intbit_yes,
   "floatformat_ia64_spill_big",
-  floatformat_always_valid
+  floatformat_always_valid,
+  NULL
 };
 const struct floatformat floatformat_ia64_spill_little =
 {
   floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
   floatformat_intbit_yes,
   "floatformat_ia64_spill_little",
-  floatformat_always_valid
+  floatformat_always_valid,
+  NULL
 };
 const struct floatformat floatformat_ia64_quad_big =
 {
   floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
   floatformat_intbit_no,
   "floatformat_ia64_quad_big",
-  floatformat_always_valid
+  floatformat_always_valid,
+  NULL
 };
 const struct floatformat floatformat_ia64_quad_little =
 {
   floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
   floatformat_intbit_no,
   "floatformat_ia64_quad_little",
-  floatformat_always_valid
+  floatformat_always_valid,
+  NULL
+};
+
+static int
+floatformat_ibm_long_double_is_valid (const struct floatformat *fmt,
+				      const void *from)
+{
+  const unsigned char *ufrom = (const unsigned char *) from;
+  const struct floatformat *hfmt = fmt->split_half;
+  long top_exp, bot_exp;
+  int top_nan = 0;
+
+  top_exp = get_field (ufrom, hfmt->byteorder, hfmt->totalsize,
+		       hfmt->exp_start, hfmt->exp_len);
+  bot_exp = get_field (ufrom + 8, hfmt->byteorder, hfmt->totalsize,
+		       hfmt->exp_start, hfmt->exp_len);
+
+  if (top_exp == hfmt->exp_nan)
+    top_nan = mant_bits_set (hfmt, ufrom);
+
+  /* A NaN is valid with any low part.  */
+  if (top_nan)
+    return 1;
+
+  /* An infinity, zero or denormal requires low part 0 (positive or
+     negative).  */
+  if (top_exp == hfmt->exp_nan || top_exp == 0)
+    {
+      unsigned int mant_bits, mant_off;
+      int mant_bits_left;
+
+      if (bot_exp != 0)
+	return 0;
+
+      return !mant_bits_set (hfmt, ufrom + 8);
+    }
+
+  /* The top part is now a finite normal value.  The long double value
+     is the sum of the two parts, and the top part must equal the
+     result of rounding the long double value to nearest double.  Thus
+     the bottom part must be <= 0.5ulp of the top part in absolute
+     value, and if it is < 0.5ulp then the long double is definitely
+     valid.  */
+  if (bot_exp < top_exp - 53)
+    return 1;
+  if (bot_exp > top_exp - 53 && bot_exp != 0)
+    return 0;
+  if (bot_exp == 0)
+    {
+      /* The bottom part is 0 or denormal.  Determine which, and if
+	 denormal the first two set bits.  */
+      int first_bit = -1, second_bit = -1, cur_bit;
+      for (cur_bit = 0; cur_bit < hfmt->man_len; cur_bit++)
+	if (get_field (ufrom + 8, hfmt->byteorder, hfmt->totalsize,
+		       hfmt->man_start + cur_bit, 1))
+	  {
+	    if (first_bit == -1)
+	      first_bit = cur_bit;
+	    else
+	      {
+		second_bit = cur_bit;
+		break;
+	      }
+	  }
+      /* Bottom part 0 is OK.  */
+      if (first_bit == -1)
+	return 1;
+      /* The real exponent of the bottom part is -first_bit.  */
+      if (-first_bit < top_exp - 53)
+	return 1;
+      if (-first_bit > top_exp - 53)
+	return 0;
+      /* The bottom part is at least 0.5ulp of the top part.  For this
+	 to be OK, the bottom part must be exactly 0.5ulp (i.e. no
+	 more bits set) and the top part must have last bit 0.  */
+      if (second_bit != -1)
+	return 0;
+      return !get_field (ufrom, hfmt->byteorder, hfmt->totalsize,
+			 hfmt->man_start + hfmt->man_len - 1, 1);
+    }
+  else
+    {
+      /* The bottom part is at least 0.5ulp of the top part.  For this
+	 to be OK, it must be exactly 0.5ulp (i.e. no explicit bits
+	 set) and the top part must have last bit 0.  */
+      if (get_field (ufrom, hfmt->byteorder, hfmt->totalsize,
+		     hfmt->man_start + hfmt->man_len - 1, 1))
+	return 0;
+      return !mant_bits_set (hfmt, ufrom + 8);
+    }
+}
+
+const struct floatformat floatformat_ibm_long_double =
+{
+  floatformat_big, 128, 0, 1, 11, 1023, 2047, 12, 52,
+  floatformat_intbit_no,
+  "floatformat_ibm_long_double",
+  floatformat_always_valid,
+  &floatformat_ieee_double_big
 };
 \f
 
@@ -254,6 +372,30 @@ const struct floatformat floatformat_ia6
 #define min(a, b) ((a) < (b) ? (a) : (b))
 #endif
 
+/* Return 1 if any bits are explicitly set in the mantissa of UFROM,
+   format FMT, 0 otherwise.  */
+static int
+mant_bits_set (const struct floatformat *fmt, const unsigned char *ufrom)
+{
+  unsigned int mant_bits, mant_off;
+  int mant_bits_left;
+
+  mant_off = fmt->man_start;
+  mant_bits_left = fmt->man_len;
+  while (mant_bits_left > 0)
+    {
+      mant_bits = min (mant_bits_left, 32);
+
+      if (get_field (ufrom, fmt->byteorder, fmt->totalsize,
+		     mant_off, mant_bits) != 0)
+	return 1;
+
+      mant_off += mant_bits;
+      mant_bits_left -= mant_bits;
+    }
+  return 0;
+}
+
 /* Extract a field which starts at START and is LEN bits long.  DATA and
    TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER.  */
 static unsigned long
@@ -310,6 +452,10 @@ floatformat_to_double (const struct floa
   int mant_bits_left;
   int special_exponent;		/* It's a NaN, denorm or zero */
 
+  /* Split values are not handled specially, since the top half has
+     the correctly rounded double value (in the only supported case of
+     split values).  */
+
   exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
 			fmt->exp_start, fmt->exp_len);
 
@@ -318,26 +464,7 @@ floatformat_to_double (const struct floa
      don't try to preserve the type of NaN.  FIXME.  */
   if ((unsigned long) exponent == fmt->exp_nan)
     {
-      int nan;
-
-      mant_off = fmt->man_start;
-      mant_bits_left = fmt->man_len;
-      nan = 0;
-      while (mant_bits_left > 0)
-	{
-	  mant_bits = min (mant_bits_left, 32);
-
-	  if (get_field (ufrom, fmt->byteorder, fmt->totalsize,
-			 mant_off, mant_bits) != 0)
-	    {
-	      /* This is a NaN.  */
-	      nan = 1;
-	      break;
-	    }
-
-	  mant_off += mant_bits;
-	  mant_bits_left -= mant_bits;
-	}
+      int nan = mant_bits_set (fmt, ufrom);
 
       /* On certain systems (such as GNU/Linux), the use of the
 	 INFINITY macro below may generate a warning that can not be
@@ -474,6 +601,10 @@ floatformat_from_double (const struct fl
   dfrom = *from;
   memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT);
 
+  /* Split values are not handled specially, since a bottom half of
+     zero is correct for any value representable as double (in the
+     only supported case of split values).  */
+
   /* If negative, set the sign bit.  */
   if (dfrom < 0)
     {

-- 
Joseph S. Myers
joseph@codesourcery.com


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Ping Re: GDB/libiberty support for IBM long double
  2007-10-29  1:31   ` Joseph S. Myers
@ 2007-11-05 22:33     ` Joseph S. Myers
  2007-11-07 22:43     ` Daniel Jacobowitz
  2007-11-09  1:07     ` Ulrich Weigand
  2 siblings, 0 replies; 23+ messages in thread
From: Joseph S. Myers @ 2007-11-05 22:33 UTC (permalink / raw)
  To: gdb-patches

Ping.  This patch 
<http://sourceware.org/ml/gdb-patches/2007-10/msg00743.html> is pending 
review.  So is the structs ABI patch 
<http://sourceware.org/ml/gdb-patches/2007-10/msg00689.html> that depends 
on this one.

-- 
Joseph S. Myers
joseph@codesourcery.com


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: GDB/libiberty support for IBM long double
  2007-10-29  1:31   ` Joseph S. Myers
  2007-11-05 22:33     ` Ping " Joseph S. Myers
@ 2007-11-07 22:43     ` Daniel Jacobowitz
  2007-11-07 23:26       ` DJ Delorie
  2007-11-09  1:07     ` Ulrich Weigand
  2 siblings, 1 reply; 23+ messages in thread
From: Daniel Jacobowitz @ 2007-11-07 22:43 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: DJ Delorie, gdb-patches, gcc-patches

On Sat, Oct 27, 2007 at 07:16:17PM +0000, Joseph S. Myers wrote:
> This revised version moves the split_half field to the end of the
> structure as requested; everything else remains as in the original
> patch <http://sourceware.org/ml/gdb-patches/2007-10/msg00687.html>,
> and it's been tested in the same way.  OK to commit once Daniel's ABI
> detection patch is in?

DJ, are the libiberty and include bits of this OK now?  If so, Joseph,
the patch is OK to commit.

-- 
Daniel Jacobowitz
CodeSourcery


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: GDB/libiberty support for IBM long double
  2007-11-07 22:43     ` Daniel Jacobowitz
@ 2007-11-07 23:26       ` DJ Delorie
  0 siblings, 0 replies; 23+ messages in thread
From: DJ Delorie @ 2007-11-07 23:26 UTC (permalink / raw)
  To: drow; +Cc: joseph, gdb-patches, gcc-patches


> DJ, are the libiberty and include bits of this OK now?

I pre-approved them with those changes already.


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: GDB/libiberty support for IBM long double
  2007-10-29  1:31   ` Joseph S. Myers
  2007-11-05 22:33     ` Ping " Joseph S. Myers
  2007-11-07 22:43     ` Daniel Jacobowitz
@ 2007-11-09  1:07     ` Ulrich Weigand
  2007-11-13  0:39       ` Joseph S. Myers
  2 siblings, 1 reply; 23+ messages in thread
From: Ulrich Weigand @ 2007-11-09  1:07 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: DJ Delorie, gdb-patches, gcc-patches

Joseph S. Myers wrote:

> 	(floatformat_ibm_long_double_is_valid,
> 	floatformat_ibm_long_double): New.

Looks like something isn't quite right here:

/home/uweigand/fsf/gdb-head/libiberty/floatformat.c: In function 'floatformat_ibm_long_double_is_valid':
/home/uweigand/fsf/gdb-head/libiberty/floatformat.c:286: warning: comparison between signed and unsigned
/home/uweigand/fsf/gdb-head/libiberty/floatformat.c:295: warning: comparison between signed and unsigned
/home/uweigand/fsf/gdb-head/libiberty/floatformat.c:298: warning: unused variable 'mant_bits_left'
/home/uweigand/fsf/gdb-head/libiberty/floatformat.c:297: warning: unused variable 'mant_off'
/home/uweigand/fsf/gdb-head/libiberty/floatformat.c:297: warning: unused variable 'mant_bits'
/home/uweigand/fsf/gdb-head/libiberty/floatformat.c:321: warning: comparison between signed and unsigned
/home/uweigand/fsf/gdb-head/libiberty/floatformat.c: At top level:
/home/uweigand/fsf/gdb-head/libiberty/floatformat.c:275: warning: 'floatformat_ibm_long_double_is_valid' defined but not used


floatformat_ibm_long_double uses floatformat_always_valid
instead of floatformat_ibm_long_double_is_valid ...


Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: GDB/libiberty support for IBM long double
  2007-11-09  1:07     ` Ulrich Weigand
@ 2007-11-13  0:39       ` Joseph S. Myers
  2007-11-13 13:56         ` Ulrich Weigand
  2007-12-28  1:20         ` Luis Machado
  0 siblings, 2 replies; 23+ messages in thread
From: Joseph S. Myers @ 2007-11-13  0:39 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: DJ Delorie, gdb-patches, gcc-patches

On Fri, 9 Nov 2007, Ulrich Weigand wrote:

> Joseph S. Myers wrote:
> 
> > 	(floatformat_ibm_long_double_is_valid,
> > 	floatformat_ibm_long_double): New.
> 
> Looks like something isn't quite right here:
> 
> /home/uweigand/fsf/gdb-head/libiberty/floatformat.c: In function 'floatformat_ibm_long_double_is_valid':
> /home/uweigand/fsf/gdb-head/libiberty/floatformat.c:286: warning: comparison between signed and unsigned
> /home/uweigand/fsf/gdb-head/libiberty/floatformat.c:295: warning: comparison between signed and unsigned
> /home/uweigand/fsf/gdb-head/libiberty/floatformat.c:298: warning: unused variable 'mant_bits_left'
> /home/uweigand/fsf/gdb-head/libiberty/floatformat.c:297: warning: unused variable 'mant_off'
> /home/uweigand/fsf/gdb-head/libiberty/floatformat.c:297: warning: unused variable 'mant_bits'
> /home/uweigand/fsf/gdb-head/libiberty/floatformat.c:321: warning: comparison between signed and unsigned
> /home/uweigand/fsf/gdb-head/libiberty/floatformat.c: At top level:
> /home/uweigand/fsf/gdb-head/libiberty/floatformat.c:275: warning: 'floatformat_ibm_long_double_is_valid' defined but not used
> 
> 
> floatformat_ibm_long_double uses floatformat_always_valid
> instead of floatformat_ibm_long_double_is_valid ...

Thanks, I've applied this patch as obvious after testing.

2007-11-12  Joseph Myers  <joseph@codesourcery.com>

	* floatformat.c (floatformat_ibm_long_double_is_valid): Fix
	compiler warnings.
	(floatformat_ibm_long_double): Use
	floatformat_ibm_long_double_is_valid.

Index: libiberty/floatformat.c
===================================================================
RCS file: /cvs/src/src/libiberty/floatformat.c,v
retrieving revision 1.22
diff -u -r1.22 floatformat.c
--- libiberty/floatformat.c	8 Nov 2007 00:08:48 -0000	1.22
+++ libiberty/floatformat.c	12 Nov 2007 23:32:04 -0000
@@ -283,7 +283,7 @@
   bot_exp = get_field (ufrom + 8, hfmt->byteorder, hfmt->totalsize,
 		       hfmt->exp_start, hfmt->exp_len);
 
-  if (top_exp == hfmt->exp_nan)
+  if ((unsigned long) top_exp == hfmt->exp_nan)
     top_nan = mant_bits_set (hfmt, ufrom);
 
   /* A NaN is valid with any low part.  */
@@ -292,11 +292,8 @@
 
   /* An infinity, zero or denormal requires low part 0 (positive or
      negative).  */
-  if (top_exp == hfmt->exp_nan || top_exp == 0)
+  if ((unsigned long) top_exp == hfmt->exp_nan || top_exp == 0)
     {
-      unsigned int mant_bits, mant_off;
-      int mant_bits_left;
-
       if (bot_exp != 0)
 	return 0;
 
@@ -318,7 +315,7 @@
       /* The bottom part is 0 or denormal.  Determine which, and if
 	 denormal the first two set bits.  */
       int first_bit = -1, second_bit = -1, cur_bit;
-      for (cur_bit = 0; cur_bit < hfmt->man_len; cur_bit++)
+      for (cur_bit = 0; (unsigned int) cur_bit < hfmt->man_len; cur_bit++)
 	if (get_field (ufrom + 8, hfmt->byteorder, hfmt->totalsize,
 		       hfmt->man_start + cur_bit, 1))
 	  {
@@ -363,7 +360,7 @@
   floatformat_big, 128, 0, 1, 11, 1023, 2047, 12, 52,
   floatformat_intbit_no,
   "floatformat_ibm_long_double",
-  floatformat_always_valid,
+  floatformat_ibm_long_double_is_valid,
   &floatformat_ieee_double_big
 };
 \f

-- 
Joseph S. Myers
joseph@codesourcery.com


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: GDB/libiberty support for IBM long double
  2007-11-13  0:39       ` Joseph S. Myers
@ 2007-11-13 13:56         ` Ulrich Weigand
  2007-11-13 14:37           ` Joseph S. Myers
  2007-12-28  1:20         ` Luis Machado
  1 sibling, 1 reply; 23+ messages in thread
From: Ulrich Weigand @ 2007-11-13 13:56 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: DJ Delorie, gdb-patches, gcc-patches

Joseph S. Myers wrote:

> 2007-11-12  Joseph Myers  <joseph@codesourcery.com>
> 
> 	* floatformat.c (floatformat_ibm_long_double_is_valid): Fix
> 	compiler warnings.
> 	(floatformat_ibm_long_double): Use
> 	floatformat_ibm_long_double_is_valid.

Thanks!  Would you mind checking this in to the src repository as well?

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: GDB/libiberty support for IBM long double
  2007-11-13 13:56         ` Ulrich Weigand
@ 2007-11-13 14:37           ` Joseph S. Myers
  2007-11-13 15:15             ` DJ Delorie
  0 siblings, 1 reply; 23+ messages in thread
From: Joseph S. Myers @ 2007-11-13 14:37 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: DJ Delorie, gdb-patches, gcc-patches

On Tue, 13 Nov 2007, Ulrich Weigand wrote:

> Joseph S. Myers wrote:
> 
> > 2007-11-12  Joseph Myers  <joseph@codesourcery.com>
> > 
> > 	* floatformat.c (floatformat_ibm_long_double_is_valid): Fix
> > 	compiler warnings.
> > 	(floatformat_ibm_long_double): Use
> > 	floatformat_ibm_long_double_is_valid.
> 
> Thanks!  Would you mind checking this in to the src repository as well?

I did check it in (to gcc, then to src), then DJ's automatic merge process 
appears to have reverted it.  DJ, will it unrevert it in due course?

----------------------------
revision 1.24
date: 2007/11/13 01:00:40;  author: dj;  state: Exp;  lines: +7 -4
merge from gcc
----------------------------
revision 1.23
date: 2007/11/13 00:38:30;  author: jsm28;  state: Exp;  lines: +4 -7
        * floatformat.c (floatformat_ibm_long_double_is_valid): Fix
        compiler warnings.
        (floatformat_ibm_long_double): Use
        floatformat_ibm_long_double_is_valid.

(GCC checkin:

------------------------------------------------------------------------
r130131 | jsm28 | 2007-11-13 00:37:43 +0000 (Tue, 13 Nov 2007) | 5 lines

        * floatformat.c (floatformat_ibm_long_double_is_valid): Fix
        compiler warnings.
        (floatformat_ibm_long_double): Use
        floatformat_ibm_long_double_is_valid.
)

-- 
Joseph S. Myers
joseph@codesourcery.com


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: GDB/libiberty support for IBM long double
  2007-11-13 14:37           ` Joseph S. Myers
@ 2007-11-13 15:15             ` DJ Delorie
  2007-11-13 17:58               ` Ulrich Weigand
  0 siblings, 1 reply; 23+ messages in thread
From: DJ Delorie @ 2007-11-13 15:15 UTC (permalink / raw)
  To: joseph; +Cc: uweigand, gdb-patches, gcc-patches


> I did check it in (to gcc, then to src), then DJ's automatic merge
> process appears to have reverted it.  DJ, will it unrevert it in due
> course?

Grrr, my gcc svn checkout got "locked" so it wasn't updating.  I'm
rerunning it now.


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: GDB/libiberty support for IBM long double
  2007-11-13 15:15             ` DJ Delorie
@ 2007-11-13 17:58               ` Ulrich Weigand
  0 siblings, 0 replies; 23+ messages in thread
From: Ulrich Weigand @ 2007-11-13 17:58 UTC (permalink / raw)
  To: DJ Delorie; +Cc: joseph, gdb-patches, gcc-patches

DJ Delorie wrote:

> > I did check it in (to gcc, then to src), then DJ's automatic merge
> > process appears to have reverted it.  DJ, will it unrevert it in due
> > course?
> 
> Grrr, my gcc svn checkout got "locked" so it wasn't updating.  I'm
> rerunning it now.

Looks like the changes have been mirrored now, thanks!

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: GDB/libiberty support for IBM long double
  2007-11-13  0:39       ` Joseph S. Myers
  2007-11-13 13:56         ` Ulrich Weigand
@ 2007-12-28  1:20         ` Luis Machado
  2007-12-28 12:29           ` Andreas Schwab
  1 sibling, 1 reply; 23+ messages in thread
From: Luis Machado @ 2007-12-28  1:20 UTC (permalink / raw)
  To: gdb-patches

Hi folks,

There appears to be a problem with the use of IBM long doubles. In
specific situations the values are being shown in a wrong way.

Follows an example of GDB HEAD:

(gdb) ptype ld0
type = long double
(gdb) p sizeof(ld0)
$8 = 16
(gdb) set ld0=1.2
(gdb) p ld0
$9 = 1.39999980921857059001922607421875
(gdb) printf "Long Double 128: %.30Lg \n",ld0
Long Double 128: 1.39999980921857059001922607422
(gdb) printf "Long Double 128: %.30Lg \n",1.2
Long Double 128: 1.19999999999999995559107901499
(gdb) printf "Long Double 128: %.30Lg \n",(long double)1.2
Long Double 128: 1.39999980921857059001922607422
(gdb)                        

The only correct value is when we don't have a value that is explicitly
a long double, in which case we have 1.19999999999999995559107901499. 

I've tracked down the problem and it appears libiberty is doing wrong
calculations when we have a long double. In particular, this piece of
code from "floatformat_to_double:libiberty/floatformat.c:527":

===> code <====
if (exponent != 0)
  exponent -= mant_bits;
===> code <====

We really need to be able to decrement EXPONENT (even if it's zero) to
get the right exponent value to call the ldexp(mant, exponent) function
for the next iteration, thus leading to a correct long double value.

Removing this condition fixes the problem, but i'm not sure this is 100%
safe as this condition must have a purpose.

Any ideas?

Best regards,

-- 
Luis Machado
Software Engineer 
IBM Linux Technology Center


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: GDB/libiberty support for IBM long double
  2007-12-28  1:20         ` Luis Machado
@ 2007-12-28 12:29           ` Andreas Schwab
  2007-12-28 21:40             ` Luis Machado
  0 siblings, 1 reply; 23+ messages in thread
From: Andreas Schwab @ 2007-12-28 12:29 UTC (permalink / raw)
  To: luisgpm; +Cc: gdb-patches

Luis Machado <luisgpm@linux.vnet.ibm.com> writes:

> Removing this condition fixes the problem, but i'm not sure this is 100%
> safe as this condition must have a purpose.
>
> Any ideas?

That part of the function can be simplified quite a bit.  For example,
NaNs and infinities are already handled at this point, thus
special_exponent can only be true when the biased exponent is zero.

--- libiberty/floatformat.c.~1.25.~	2007-11-16 11:17:29.000000000 +0100
+++ libiberty/floatformat.c	2007-12-28 11:26:21.000000000 +0100
@@ -487,9 +487,9 @@ floatformat_to_double (const struct floa
   mant_off = fmt->man_start;
   dto = 0.0;
 
-  special_exponent = exponent == 0 || (unsigned long) exponent == fmt->exp_nan;
+  special_exponent = exponent == 0;
 
-  /* Don't bias zero's, denorms or NaNs.  */
+  /* Don't bias zeros or denorms.  */
   if (!special_exponent)
     exponent -= fmt->exp_bias;
 
@@ -516,16 +516,15 @@ floatformat_to_double (const struct floa
 
       /* Handle denormalized numbers.  FIXME: What should we do for
 	 non-IEEE formats?  */
-      if (special_exponent && exponent == 0 && mant != 0)
-	dto += ldexp ((double)mant,
+      if (special_exponent)
+	dto += ldexp ((double) mant,
 		      (- fmt->exp_bias
 		       - mant_bits
 		       - (mant_off - fmt->man_start)
 		       + 1));
       else
-	dto += ldexp ((double)mant, exponent - mant_bits);
-      if (exponent != 0)
-	exponent -= mant_bits;
+	dto += ldexp ((double) mant, exponent - mant_bits);
+      exponent -= mant_bits;
       mant_off += mant_bits;
       mant_bits_left -= mant_bits;
     }

Andreas.

-- 
Andreas Schwab, SuSE Labs, schwab@suse.de
SuSE Linux Products GmbH, Maxfeldstraße 5, 90409 Nürnberg, Germany
PGP key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: GDB/libiberty support for IBM long double
  2007-12-28 12:29           ` Andreas Schwab
@ 2007-12-28 21:40             ` Luis Machado
  2007-12-30 11:25               ` Daniel Jacobowitz
  0 siblings, 1 reply; 23+ messages in thread
From: Luis Machado @ 2007-12-28 21:40 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: gdb-patches

On Fri, 2007-12-28 at 11:33 +0100, Andreas Schwab wrote:
> That part of the function can be simplified quite a bit.  For example,
> NaNs and infinities are already handled at this point, thus
> special_exponent can only be true when the biased exponent is zero.

Thanks for the feedback Andreas. How should we proceed to get code
included on libiberty?

Best regards,
> 
-- 
Luis Machado
Software Engineer 
IBM Linux Technology Center


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: GDB/libiberty support for IBM long double
  2007-12-28 21:40             ` Luis Machado
@ 2007-12-30 11:25               ` Daniel Jacobowitz
  2008-01-02 16:17                 ` Luis Machado
  0 siblings, 1 reply; 23+ messages in thread
From: Daniel Jacobowitz @ 2007-12-30 11:25 UTC (permalink / raw)
  To: Luis Machado; +Cc: Andreas Schwab, gdb-patches

On Fri, Dec 28, 2007 at 12:31:27PM -0200, Luis Machado wrote:
> On Fri, 2007-12-28 at 11:33 +0100, Andreas Schwab wrote:
> > That part of the function can be simplified quite a bit.  For example,
> > NaNs and infinities are already handled at this point, thus
> > special_exponent can only be true when the biased exponent is zero.
> 
> Thanks for the feedback Andreas. How should we proceed to get code
> included on libiberty?

Post a patch to gcc-patches.  You may want to compare the libiberty
version with the gdb/doublest.c version, which is used otherwise;
I believe I introduced a use of the libiberty version for NaNs and
Joseph added some others for IBM split long double, but no other
platform uses them.  So problems are not unlikely.

I wonder if we really need to use floatformat_to_double instead of
floatformat_to_doublest for the split_half cases.  It seems like that
relies unnecessarily on the host double format.  Do things work better
if you use floatformat_to_doublest and DOUBLEST variables, instead
of floatformat_to_double (likewise floatformat_from_doublest)?

-- 
Daniel Jacobowitz
CodeSourcery


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: GDB/libiberty support for IBM long double
  2007-12-30 11:25               ` Daniel Jacobowitz
@ 2008-01-02 16:17                 ` Luis Machado
  2008-01-02 17:01                   ` Daniel Jacobowitz
  0 siblings, 1 reply; 23+ messages in thread
From: Luis Machado @ 2008-01-02 16:17 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: Andreas Schwab, gdb-patches

[-- Attachment #1: Type: text/plain, Size: 787 bytes --]

Hi,

> I wonder if we really need to use floatformat_to_double instead of
> floatformat_to_doublest for the split_half cases.  It seems like that
> relies unnecessarily on the host double format.  Do things work better
> if you use floatformat_to_doublest and DOUBLEST variables, instead
> of floatformat_to_double (likewise floatformat_from_doublest)?

The attached patch replaces the use of floatformat_to_double with
floatformat_to_doublest, fixing the problem.

There are other uses of floatformat_to_double in the function, by i'm
not sure if we should just replace every call of that function with the
"doublest" version (likewise with the floatformat_from_double ->
floatformat_from_doublest replacement).

Regards,
-- 
Luis Machado
Software Engineer 
IBM Linux Technology Center

[-- Attachment #2: fix_long_double.diff --]
[-- Type: text/x-patch, Size: 1072 bytes --]

2008-01-02  Luis Machado  <luisgpm@br.ibm.com>

        * doublest.c (convert_floatformat_to_doublest): Call 
	floatformat_to_doublest instead of floatformat_to_double and use
	DOUBLEST variables.

Index: gdb/doublest.c
===================================================================
--- gdb.orig/doublest.c	2008-01-02 07:52:14.000000000 -0800
+++ gdb/doublest.c	2008-01-02 07:53:06.000000000 -0800
@@ -202,19 +202,19 @@
 
   if (fmt->split_half)
     {
-      double dtop, dbot;
-      floatformat_to_double (fmt->split_half, ufrom, &dtop);
+      DOUBLEST dtop, dbot;
+      floatformat_to_doublest (fmt->split_half, ufrom, &dtop);
       /* Preserve the sign of 0, which is the sign of the top
 	 half.  */
       if (dtop == 0.0)
 	{
-	  *to = (DOUBLEST) dtop;
+	  *to = dtop;
 	  return;
 	}
-      floatformat_to_double (fmt->split_half,
+      floatformat_to_doublest (fmt->split_half,
 			     ufrom + fmt->totalsize / FLOATFORMAT_CHAR_BIT / 2,
 			     &dbot);
-      *to = (DOUBLEST) dtop + (DOUBLEST) dbot;
+      *to = dtop + dbot;
       return;
     }
 

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: GDB/libiberty support for IBM long double
  2008-01-02 16:17                 ` Luis Machado
@ 2008-01-02 17:01                   ` Daniel Jacobowitz
  2008-01-02 18:12                     ` Luis Machado
  0 siblings, 1 reply; 23+ messages in thread
From: Daniel Jacobowitz @ 2008-01-02 17:01 UTC (permalink / raw)
  To: Luis Machado; +Cc: Andreas Schwab, gdb-patches

On Wed, Jan 02, 2008 at 02:11:27PM -0200, Luis Machado wrote:
> Hi,
> 
> > I wonder if we really need to use floatformat_to_double instead of
> > floatformat_to_doublest for the split_half cases.  It seems like that
> > relies unnecessarily on the host double format.  Do things work better
> > if you use floatformat_to_doublest and DOUBLEST variables, instead
> > of floatformat_to_double (likewise floatformat_from_doublest)?
> 
> The attached patch replaces the use of floatformat_to_double with
> floatformat_to_doublest, fixing the problem.
> 
> There are other uses of floatformat_to_double in the function, by i'm
> not sure if we should just replace every call of that function with the
> "doublest" version (likewise with the floatformat_from_double ->
> floatformat_from_doublest replacement).

There is one other call, for NaN and infinity.  That one should be
left alone, since we don't duplicate the necessary bits and the
precision is irrelevant.

However, could you test also replacing the two floatformat_from_double
calls in convert_doublest_to_floatformat?

-- 
Daniel Jacobowitz
CodeSourcery


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: GDB/libiberty support for IBM long double
  2008-01-02 17:01                   ` Daniel Jacobowitz
@ 2008-01-02 18:12                     ` Luis Machado
  2008-01-02 18:32                       ` Daniel Jacobowitz
  0 siblings, 1 reply; 23+ messages in thread
From: Luis Machado @ 2008-01-02 18:12 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: Andreas Schwab, gdb-patches

[-- Attachment #1: Type: text/plain, Size: 568 bytes --]

> However, could you test also replacing the two floatformat_from_double
> calls in convert_doublest_to_floatformat?

Sure. Follows the patch.

The results still show up correctly, casting doubles to long doubles and
long doubles to doubles.

===> Output <===
(gdb) set $ld=(long double)1.2
(gdb) p $ld
$8 = 1.1999999999999999555910790149937384
(gdb) p (double) $ld
$9 = 1.2

(gdb) set $ld=(double)1.2
(gdb) p $ld
$12 = 1.2
(gdb) p (long double) $ld
$13 = 1.1999999999999999555910790149937384


Regards,
-- 
Luis Machado
Software Engineer 
IBM Linux Technology Center

[-- Attachment #2: fix_long_double.diff --]
[-- Type: text/x-patch, Size: 1990 bytes --]

2008-01-02  Luis Machado  <luisgpm@br.ibm.com>

        * doublest.c (convert_floatformat_to_doublest): Call 
	floatformat_to_doublest instead of floatformat_to_double and use
	DOUBLEST variables.
	(convert_doublest_to_floatformat): Call floatformat_from_doublest
	instead of floatformat_from_double and use DOUBLEST variables.

Index: gdb/doublest.c
===================================================================
--- gdb.orig/doublest.c	2008-01-02 08:24:41.000000000 -0800
+++ gdb/doublest.c	2008-01-02 09:53:55.000000000 -0800
@@ -202,19 +202,19 @@
 
   if (fmt->split_half)
     {
-      double dtop, dbot;
-      floatformat_to_double (fmt->split_half, ufrom, &dtop);
+      DOUBLEST dtop, dbot;
+      floatformat_to_doublest (fmt->split_half, ufrom, &dtop);
       /* Preserve the sign of 0, which is the sign of the top
 	 half.  */
       if (dtop == 0.0)
 	{
-	  *to = (DOUBLEST) dtop;
+	  *to = dtop;
 	  return;
 	}
-      floatformat_to_double (fmt->split_half,
+      floatformat_to_doublest (fmt->split_half,
 			     ufrom + fmt->totalsize / FLOATFORMAT_CHAR_BIT / 2,
 			     &dbot);
-      *to = (DOUBLEST) dtop + (DOUBLEST) dbot;
+      *to = dtop + dbot;
       return;
     }
 
@@ -417,7 +417,7 @@
 	 removed via storing in memory, and so the top half really is
 	 the result of converting to double.  */
       static volatile double dtop, dbot;
-      double dtopnv, dbotnv;
+      DOUBLEST dtopnv, dbotnv;
       dtop = (double) dfrom;
       /* If the rounded top half is Inf, the bottom must be 0 not NaN
 	 or Inf.  */
@@ -427,8 +427,8 @@
 	dbot = (double) (dfrom - (DOUBLEST) dtop);
       dtopnv = dtop;
       dbotnv = dbot;
-      floatformat_from_double (fmt->split_half, &dtopnv, uto);
-      floatformat_from_double (fmt->split_half, &dbotnv,
+      floatformat_from_doublest (fmt->split_half, &dtopnv, uto);
+      floatformat_from_doublest (fmt->split_half, &dbotnv,
 			       (uto
 				+ fmt->totalsize / FLOATFORMAT_CHAR_BIT / 2));
       return;

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: GDB/libiberty support for IBM long double
  2008-01-02 18:12                     ` Luis Machado
@ 2008-01-02 18:32                       ` Daniel Jacobowitz
  2008-01-03 11:47                         ` Luis Machado
  0 siblings, 1 reply; 23+ messages in thread
From: Daniel Jacobowitz @ 2008-01-02 18:32 UTC (permalink / raw)
  To: Luis Machado; +Cc: Andreas Schwab, gdb-patches

On Wed, Jan 02, 2008 at 04:05:26PM -0200, Luis Machado wrote:
> 2008-01-02  Luis Machado  <luisgpm@br.ibm.com>
> 
>         * doublest.c (convert_floatformat_to_doublest): Call 
> 	floatformat_to_doublest instead of floatformat_to_double and use
> 	DOUBLEST variables.
> 	(convert_doublest_to_floatformat): Call floatformat_from_doublest
> 	instead of floatformat_from_double and use DOUBLEST variables.

OK.

-- 
Daniel Jacobowitz
CodeSourcery


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: GDB/libiberty support for IBM long double
  2008-01-02 18:32                       ` Daniel Jacobowitz
@ 2008-01-03 11:47                         ` Luis Machado
  0 siblings, 0 replies; 23+ messages in thread
From: Luis Machado @ 2008-01-03 11:47 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 602 bytes --]

Thanks Daniel. I've checked in this version.

On Wed, 2008-01-02 at 13:27 -0500, Daniel Jacobowitz wrote:
> On Wed, Jan 02, 2008 at 04:05:26PM -0200, Luis Machado wrote:
> > 2008-01-02  Luis Machado  <luisgpm@br.ibm.com>
> > 
> >         * doublest.c (convert_floatformat_to_doublest): Call 
> > 	floatformat_to_doublest instead of floatformat_to_double and use
> > 	DOUBLEST variables.
> > 	(convert_doublest_to_floatformat): Call floatformat_from_doublest
> > 	instead of floatformat_from_double and use DOUBLEST variables.
> 
> OK.
> 
-- 
Luis Machado
Software Engineer 
IBM Linux Technology Center

[-- Attachment #2: fix_long_double.diff --]
[-- Type: text/x-patch, Size: 1990 bytes --]

2008-01-03  Luis Machado  <luisgpm@br.ibm.com>

        * doublest.c (convert_floatformat_to_doublest): Call 
	floatformat_to_doublest instead of floatformat_to_double and use
	DOUBLEST variables.
	(convert_doublest_to_floatformat): Call floatformat_from_doublest
	instead of floatformat_from_double and use DOUBLEST variables.

Index: gdb/doublest.c
===================================================================
--- gdb.orig/doublest.c	2008-01-02 08:24:41.000000000 -0800
+++ gdb/doublest.c	2008-01-02 09:53:55.000000000 -0800
@@ -202,19 +202,19 @@
 
   if (fmt->split_half)
     {
-      double dtop, dbot;
-      floatformat_to_double (fmt->split_half, ufrom, &dtop);
+      DOUBLEST dtop, dbot;
+      floatformat_to_doublest (fmt->split_half, ufrom, &dtop);
       /* Preserve the sign of 0, which is the sign of the top
 	 half.  */
       if (dtop == 0.0)
 	{
-	  *to = (DOUBLEST) dtop;
+	  *to = dtop;
 	  return;
 	}
-      floatformat_to_double (fmt->split_half,
+      floatformat_to_doublest (fmt->split_half,
 			     ufrom + fmt->totalsize / FLOATFORMAT_CHAR_BIT / 2,
 			     &dbot);
-      *to = (DOUBLEST) dtop + (DOUBLEST) dbot;
+      *to = dtop + dbot;
       return;
     }
 
@@ -417,7 +417,7 @@
 	 removed via storing in memory, and so the top half really is
 	 the result of converting to double.  */
       static volatile double dtop, dbot;
-      double dtopnv, dbotnv;
+      DOUBLEST dtopnv, dbotnv;
       dtop = (double) dfrom;
       /* If the rounded top half is Inf, the bottom must be 0 not NaN
 	 or Inf.  */
@@ -427,8 +427,8 @@
 	dbot = (double) (dfrom - (DOUBLEST) dtop);
       dtopnv = dtop;
       dbotnv = dbot;
-      floatformat_from_double (fmt->split_half, &dtopnv, uto);
-      floatformat_from_double (fmt->split_half, &dbotnv,
+      floatformat_from_doublest (fmt->split_half, &dtopnv, uto);
+      floatformat_from_doublest (fmt->split_half, &dbotnv,
 			       (uto
 				+ fmt->totalsize / FLOATFORMAT_CHAR_BIT / 2));
       return;

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2008-01-03 11:47 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-10-26  0:25 GDB/libiberty support for IBM long double Joseph S. Myers
2007-10-26  0:37 ` DJ Delorie
2007-10-29  1:31   ` Joseph S. Myers
2007-11-05 22:33     ` Ping " Joseph S. Myers
2007-11-07 22:43     ` Daniel Jacobowitz
2007-11-07 23:26       ` DJ Delorie
2007-11-09  1:07     ` Ulrich Weigand
2007-11-13  0:39       ` Joseph S. Myers
2007-11-13 13:56         ` Ulrich Weigand
2007-11-13 14:37           ` Joseph S. Myers
2007-11-13 15:15             ` DJ Delorie
2007-11-13 17:58               ` Ulrich Weigand
2007-12-28  1:20         ` Luis Machado
2007-12-28 12:29           ` Andreas Schwab
2007-12-28 21:40             ` Luis Machado
2007-12-30 11:25               ` Daniel Jacobowitz
2008-01-02 16:17                 ` Luis Machado
2008-01-02 17:01                   ` Daniel Jacobowitz
2008-01-02 18:12                     ` Luis Machado
2008-01-02 18:32                       ` Daniel Jacobowitz
2008-01-03 11:47                         ` Luis Machado
2007-10-26  8:05 ` Mark Kettenis
2007-10-26 15:01   ` Joseph S. Myers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox