[PATCH] Bug 23438. Support for 128-bit long double types on PowerPC 64]

Pete Carr
2006-07-11T22:17:12Z

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

:ADDPATCH PowerPC-64:

Resubmitting. Using the patch tracker.

[-- Attachment #2: [PATCH] Bug 23438. Support for 128-bit long double types on PowerPC 64] --]
[-- Type: message/rfc822, Size: 18489 bytes --]

[-- Attachment #2.1.1: Type: text/plain, Size: 824 bytes --]

Hi,
I'm submitting this patch for bugzilla bug #23438 [Novell180103 - GDB does
not print a long double variable when the size of the long double data type
is 128-bit.]

Andreas Schwab is responsible for one part of this change (in
ppc-linux-tdep.c)
and his change suppresses the error message about unsupported 128-bit types.

My additions support the full precision available from the long double
format.
Andreas's change is a necessary part of the change to support full precision
expressions.

I have also added a small test case to add to the testsuite.
Please note that there are changes to floatformat.h and floatformat.c which
are held under include and libiberty subdirectories.

This is my first patch submission so I'd appreciate guidance if I have
not followed the rules.

Pete Carr.
IBM Linux Toolchain Group.

[-- Attachment #2.1.2: [PATCH] Bug 23438. Support for 128-bit long double types on PowerPC 64 --]
[-- Type: message/rfc822, Size: 14785 bytes --]

[-- Attachment #2.1.2.1.1: Type: text/plain, Size: 824 bytes --]

Hi,
I'm submitting this patch for bugzilla bug #23438 [Novell180103 - GDB does
not print a long double variable when the size of the long double data type
is 128-bit.]

Andreas Schwab is responsible for one part of this change (in ppc-linux-tdep.c)
and his change suppresses the error message about unsupported 128-bit types.

My additions support the full precision available from the long double format.
Andreas's change is a necessary part of the change to support full precision
expressions.

I have also added a small test case to add to the testsuite.
Please note that there are changes to floatformat.h and floatformat.c which
are held under include and libiberty subdirectories.

This is my first patch submission so I'd appreciate guidance if I have
not followed the rules.

Pete Carr.
IBM Linux Toolchain Group.

[-- Attachment #2.1.2.1.2: my.patch --]
[-- Type: text/x-patch, Size: 11664 bytes --]

2006-06-19 Pete Carr <pecarr@us.ibm.com>

* rs6000-tdep.c (rs6000_gdbarch_init): Set the long double format for
powerpc64.
* configure.host : Set the host long double format for powerpc64 to be
a 128-bit type defined in libiberty/floatformat.c.
* gdbarch.sh (function_list): Use the default_long_double_format for
the long double type.
* ppc-linux-tdep.c (ppc_linux_init_abi): Remove code that sets long double
size to 8 bytes. This breaks expression evaluation by overriding the
default.

* floatformat.c : Introduce default floatformat structs to describe the
128-bit long double found on the powerpc64. Description does not fully
describe this format which is actually a pair of 64-bit doubles. However
we are relying on floatformat_to_doublest() recognizing that this is
also the default host floatformat.
* floatformat.h : Default floatformat structs for powerpc64 128-bit
long doubles.
* powerpc64-ld128.c: Test program for 128-bit long doubles on powerpc64
* powerpc64-ld128.exp: Test program expect script for 128-bit long doubles
on powerpc64

Index: gdb/configure.host
===================================================================
RCS file: /cvs/src/src/gdb/configure.host,v
retrieving revision 1.94
diff -a -u -p -r1.94 configure.host
--- gdb/configure.host 10 Feb 2006 21:53:51 -0000 1.94
+++ gdb/configure.host 19 Jun 2006 21:32:07 -0000
@@ -179,6 +179,11 @@ m68*-*-*)
gdb_host_double_format="&floatformat_ieee_double_big"
gdb_host_long_double_format="&floatformat_m68881_ext"
;;
+powerpc64-*-*-*)
+ gdb_host_float_format=0
+ gdb_host_double_format=0
+ gdb_host_long_double_format="&floatformat_ppc64_long_double_big"
+ ;;
*)
gdb_host_float_format=0
gdb_host_double_format=0
Index: gdb/gdbarch.sh
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.sh,v
retrieving revision 1.364
diff -a -u -p -r1.364 gdbarch.sh
--- gdb/gdbarch.sh 18 Apr 2006 19:20:06 -0000 1.364
+++ gdb/gdbarch.sh 19 Jun 2006 21:32:08 -0000
@@ -395,7 +395,7 @@ v:TARGET_FLOAT_FORMAT:const struct float
v:TARGET_DOUBLE_BIT:int:double_bit:::8 * sizeof (double):8*TARGET_CHAR_BIT::0
v:TARGET_DOUBLE_FORMAT:const struct floatformat *:double_format:::::default_double_format (current_gdbarch)::pformat (current_gdbarch->double_format)
v:TARGET_LONG_DOUBLE_BIT:int:long_double_bit:::8 * sizeof (long double):8*TARGET_CHAR_BIT::0
-v:TARGET_LONG_DOUBLE_FORMAT:const struct floatformat *:long_double_format:::::default_double_format (current_gdbarch)::pformat (current_gdbarch->long_double_format)
+v:TARGET_LONG_DOUBLE_FORMAT:const struct floatformat *:long_double_format:::::default_long_double_format (current_gdbarch)::pformat (current_gdbarch->long_double_format)

# For most targets, a pointer on the target and its representation as an
# address in GDB have the same size and "look the same". For such a
Index: gdb/ppc-linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ppc-linux-tdep.c,v
retrieving revision 1.78
diff -a -u -p -r1.78 ppc-linux-tdep.c
--- gdb/ppc-linux-tdep.c 18 Apr 2006 19:20:06 -0000 1.78
+++ gdb/ppc-linux-tdep.c 19 Jun 2006 21:32:08 -0000
@@ -1032,7 +1032,9 @@ ppc_linux_init_abi (struct gdbarch_info
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. */
+#if 0
set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+#endif

if (tdep->wordsize == 4)
{
Index: gdb/rs6000-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/rs6000-tdep.c,v
retrieving revision 1.258
diff -a -u -p -r1.258 rs6000-tdep.c
--- gdb/rs6000-tdep.c 23 Apr 2006 14:15:01 -0000 1.258
+++ gdb/rs6000-tdep.c 19 Jun 2006 21:32:08 -0000
@@ -3391,7 +3391,19 @@ rs6000_gdbarch_init (struct gdbarch_info
set_gdbarch_float_bit (gdbarch, 4 * TARGET_CHAR_BIT);
set_gdbarch_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
if (sysv_abi)
- set_gdbarch_long_double_bit (gdbarch, 16 * TARGET_CHAR_BIT);
+ {
+ int byte_order = gdbarch_byte_order (gdbarch);
+
+ if (byte_order == BFD_ENDIAN_BIG)
+ set_gdbarch_long_double_format (gdbarch, &floatformat_ppc64_long_double_big);
+ else if (byte_order == BFD_ENDIAN_LITTLE)
+ set_gdbarch_long_double_format (gdbarch, &floatformat_ppc64_long_double_little);
+ else
+ internal_error (__FILE__, __LINE__,
+ _("rs6000_gdbarch_init: "
+ "bad byte order"));
+ set_gdbarch_long_double_bit (gdbarch, 16 * TARGET_CHAR_BIT);
+ }
else
set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
set_gdbarch_char_signed (gdbarch, 0);
Index: include/floatformat.h
===================================================================
RCS file: /cvs/src/src/include/floatformat.h,v
retrieving revision 1.13
diff -a -u -p -r1.13 floatformat.h
--- include/floatformat.h 31 Oct 2005 18:01:16 -0000 1.13
+++ include/floatformat.h 19 Jun 2006 21:32:09 -0000
@@ -118,6 +118,9 @@ 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;
+/* ppc64 long double implemented as 2 doubles */
+extern const struct floatformat floatformat_ppc64_long_double_big;
+extern const struct floatformat floatformat_ppc64_long_double_little;

/* Convert from FMT to a double.
FROM is the address of the extended float.
Index: libiberty/floatformat.c
===================================================================
RCS file: /cvs/src/src/libiberty/floatformat.c,v
retrieving revision 1.20
diff -a -u -p -r1.20 floatformat.c
--- libiberty/floatformat.c 24 Apr 2006 21:34:41 -0000 1.20
+++ libiberty/floatformat.c 19 Jun 2006 21:32:09 -0000
@@ -106,6 +106,25 @@ const struct floatformat floatformat_iee
floatformat_always_valid
};

+/* floatformats for ppc64 long double, big and little endian. */
+/* The layout is a pair of doubles. Don't use this description to pass */
+/* information to get_field(). The bit size is the important thing. */
+const struct floatformat floatformat_ppc64_long_double_big =
+{
+ floatformat_big, 128, 0, 1, 11, 1023, 2047, 12, 52,
+ floatformat_intbit_no,
+ "floatformat_ppc64_long_double_big",
+ floatformat_always_valid
+};
+
+const struct floatformat floatformat_ppc64_long_double_little =
+{
+ floatformat_little, 128, 0, 1, 11, 1023, 2047, 12, 52,
+ floatformat_intbit_no,
+ "floatformat_ppc64_long_double_little",
+ floatformat_always_valid
+};
+
/* floatformat for IEEE double, little endian byte order, with big endian word
ordering, as on the ARM. */

Index: gdb/testsuite/gdb.arch/powerpc64-ld128.c
===================================================================
/* This testcase is part of GDB, the GNU debugger.

Copyright 2006 Free Software Foundation, Inc.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */

#include <stdio.h>
#include <stdlib.h>

long double b1;
long double b2;
long double b3;
long double b4;

int main()
{
b1 = 1.2345678901234567890000000L;
b2 = -1.2345678901234567890000000L;
b3 = 123456789.0000000001234567890123456789L;
b4 = -123456789.0000000001234567890123456789L;

return 0;
}

Index: gdb/testsuite/gdb.arch/powerpc64-ld128.exp
===================================================================
# Copyright 2006 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# This file is part of the gdb testsuite.

if $tracelevel {
strace $tracelevel
}

# Test powerpc64 128-bit long double support.

set prms_id 0
set bug_id 0

if ![istarget "powerpc64-*"] then {
verbose "Skipping powerpc64 128-bit long double tests."
return
}

set testfile "powerpc64-ld128"
set srcfile ${testfile}.c
set binfile ${objdir}/${subdir}/${testfile}
set compile_flags "debug"
# "additional_flags=-mlong-double-64"

if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable ${compile_flags}] != "" } {
unsupported "Testcase compile failed."
return -1
}

gdb_exit
gdb_start
gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}

if ![runto_main] then {
perror "couldn't run to breakpoint"
continue
}

# Run to the breakpoint at return.
gdb_breakpoint [gdb_get_line_number "return"]
gdb_continue_to_breakpoint "return"

gdb_test_multiple "print sizeof(b1)" "" {
-re ".*1 = 16." {
pass "b1 should be 16 bytes long"
}
-re ".*1 = 8." {
pass "b1 is 8 bytes long, test does not apply"
return
}
}

# Print the original value of b1, b2 and b3.
gdb_test "print b1" ".*2 = 1\.2345678901234567890000000*.*" "The original value of b1 is 1.2345678901234567890000000 "
gdb_test "print b2" ".*3 = -1\.2345678901234567890000000*.*" "The original value of b2 is -1.2345678901234567890000000"
gdb_test "print b3" ".*4 = 123456789\.000000000123456789012345*.*" "The original value of b3 is 123456789.000000000123456789012345 "
gdb_test "print b4" ".*5 = -123456789\.000000000123456789012345*.*" "The original value of b4 is -123456789.000000000123456789012345 "

gdb_test "print sizeof(long double)" ".*6 = 16." "Long double should be 16 bytes long"
# Try setting variable.
gdb_test "set variable b1=1.11111111111111111111111111111111111L"
gdb_test "print b1" ".*7 = 1\.11111111111111111111111111111111*.*"
gdb_test "print *(long double *)&b1" ".*8 = 1\.11111111111111111111111111111111*.*"
# Try some simple expressions
gdb_test "set variable b1 = b1*2.0L"
gdb_test "print b1" ".*9 = 2.22222222222222222222222222222222*.*"
gdb_test "set variable b1 = b1/2.0L"
gdb_test "print b1" ".*10 = 1\.11111111111111111111111111111111*.*"
gdb_test "print *(long double *)&b1" ".*11 = 1\.11111111111111111111111111111111*.*"
gdb_test "set variable b1 = b1*5.0"
gdb_test "print b1" ".*12 = 5.5555555555555555555555555555555*.*"
gdb_test "set variable b1 = b1/5.0"
gdb_test "print b1" ".*13 = 1.11111111111111111111111111111111*.*"
gdb_test "set variable b1 = 1.0e-31L"
gdb_test "print b1" ".*14 = 1.000000000000000000000000000000*.*"
gdb_test "set variable b1 = b1+1.0"
gdb_test "print b1" ".*15 = 1.0000000000000000000000000000000*.*"