diff mbox

[9/9,v2] Support 128-bit IEEE floating-point types on Intel and Power

Message ID 20160826181830.CE9991309C@oc7340732750.ibm.com
State New
Headers show

Commit Message

Ulrich Weigand Aug. 26, 2016, 6:18 p.m. UTC
Joseph Myers wrote:
> On Thu, 25 Aug 2016, Ulrich Weigand wrote:
> 
> > Since at this point we do not yet have any indication in the debug info to
> > distinguish different floating-point formats of the same length, we simply
> > use the type name as hint.  Types named "__float128" get the IEEE format.
> 
> Note that now (GCC 7) __float128 is a built-in typedef (i.e. a name 
> registered with the register_builtin_type langhook) for _Float128, and 
> _Float128 is the primary name used when the type is created.  If I build a 
> program with GCC 7 that uses __float128, the debug info I get references 
> _Float128 (and not __float128 as far as I can see).
> 
> Obviously debugging should work whether someone uses _Float128 or 
> __float128 (and in C++, right now they can only use __float128, as the 
> keyword _Float128 is C-specific).  Then on Power, _Float64x is also 
> binary128 when available (but is a distinct type at the C level from 
> _Float128), but on x86 it has the Intel extended format (but is a distinct 
> type from long double).

Ah, good point, I hadn't tested against current GCC mainline.

The version below adds support to handle _Float128 (on Power and Intel)
and _Float64x (on Power only) as 128-bit IEEE format.  Because the rest
of the new types already match what GDB will choose by default for a
type of their size, this means all of them should now work correctly.

I've also added a test case to verify that all the supported _FloatN
and _FloatNx types work correctly.  This passes when using GCC 7 on
both Power and Intel.  (The __float128 test still passes when using
GCC 6.)

Tested on x64_64-linux and powerpc64le-linux.

Bye,
Ulrich

ChangeLog:

	* i386-tdep.c (i386_floatformat_for_type): New function.
	(i386_gdbarch_init): Install it.
	* ppc-linux-tdep.c (ppc_floatformat_for_type): New function.
	(ppc_linux_init_abi): Install it.

testsuite/ChangeLog:

	* gdb.base/float128.c: New file.
	* gdb.base/float128.exp: Likewise.
	* gdb.base/floatn.c: Likewise.
	* gdb.base/floatn.exp: Likewise.
diff mbox

Patch

Index: binutils-gdb/gdb/i386-tdep.c
===================================================================
--- binutils-gdb.orig/gdb/i386-tdep.c	2016-08-25 13:11:56.778869254 +0200
+++ binutils-gdb/gdb/i386-tdep.c	2016-08-26 19:47:23.246447990 +0200
@@ -8161,6 +8161,23 @@  i386_fast_tracepoint_valid_at (struct gd
     }
 }
 
+/* Return a floating-point format for a floating-point variable of
+   length LEN in bits.  If non-NULL, NAME is the name of its type.
+   If no suitable type is found, return NULL.  */
+
+const struct floatformat **
+i386_floatformat_for_type (struct gdbarch *gdbarch,
+			   const char *name, int len)
+{
+  if (len == 128 && name)
+    if (strcmp (name, "__float128") == 0
+	|| strcmp (name, "_Float128") == 0
+	|| strcmp (name, "complex _Float128") == 0)
+      return floatformats_ia64_quad;
+
+  return default_floatformat_for_type (gdbarch, name, len);
+}
+
 static int
 i386_validate_tdesc_p (struct gdbarch_tdep *tdep,
 		       struct tdesc_arch_data *tdesc_data)
@@ -8370,6 +8387,9 @@  i386_gdbarch_init (struct gdbarch_info i
      alignment.  */
   set_gdbarch_long_double_bit (gdbarch, 96);
 
+  /* Support for floating-point data type variants.  */
+  set_gdbarch_floatformat_for_type (gdbarch, i386_floatformat_for_type);
+
   /* Register numbers of various important registers.  */
   set_gdbarch_sp_regnum (gdbarch, I386_ESP_REGNUM); /* %esp */
   set_gdbarch_pc_regnum (gdbarch, I386_EIP_REGNUM); /* %eip */
Index: binutils-gdb/gdb/ppc-linux-tdep.c
===================================================================
--- binutils-gdb.orig/gdb/ppc-linux-tdep.c	2016-08-25 13:11:56.779869258 +0200
+++ binutils-gdb/gdb/ppc-linux-tdep.c	2016-08-26 19:14:45.210254378 +0200
@@ -1628,6 +1628,25 @@  ppc_init_linux_record_tdep (struct linux
   record_tdep->ioctl_FIOQSIZE = 0x40086680;
 }
 
+/* Return a floating-point format for a floating-point variable of
+   length LEN in bits.  If non-NULL, NAME is the name of its type.
+   If no suitable type is found, return NULL.  */
+
+const struct floatformat **
+ppc_floatformat_for_type (struct gdbarch *gdbarch,
+                          const char *name, int len)
+{
+  if (len == 128 && name)
+    if (strcmp (name, "__float128") == 0
+        || strcmp (name, "_Float128") == 0
+        || strcmp (name, "_Float64x") == 0
+        || strcmp (name, "complex _Float128") == 0
+        || strcmp (name, "complex _Float64x") == 0)
+      return floatformats_ia64_quad;
+
+  return default_floatformat_for_type (gdbarch, name, len);
+}
+
 static void
 ppc_linux_init_abi (struct gdbarch_info info,
                     struct gdbarch *gdbarch)
@@ -1651,6 +1670,9 @@  ppc_linux_init_abi (struct gdbarch_info 
   set_gdbarch_long_double_bit (gdbarch, 16 * TARGET_CHAR_BIT);
   set_gdbarch_long_double_format (gdbarch, floatformats_ibm_long_double);
 
+  /* Support for floating-point data type variants.  */
+  set_gdbarch_floatformat_for_type (gdbarch, ppc_floatformat_for_type);
+
   /* Handle inferior calls during interrupted system calls.  */
   set_gdbarch_write_pc (gdbarch, ppc_linux_write_pc);
 
Index: binutils-gdb/gdb/testsuite/gdb.base/float128.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ binutils-gdb/gdb/testsuite/gdb.base/float128.c	2016-08-26 19:14:45.213254397 +0200
@@ -0,0 +1,30 @@ 
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2016 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 3 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, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+long double ld;
+__float128 f128;
+
+int main()
+{
+  ld = 1.375l;
+  f128 = 2.375q;
+
+  return 0;
+}
Index: binutils-gdb/gdb/testsuite/gdb.base/float128.exp
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ binutils-gdb/gdb/testsuite/gdb.base/float128.exp	2016-08-26 19:14:45.217254424 +0200
@@ -0,0 +1,76 @@ 
+# Copyright 2016 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 3 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, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the gdb testsuite.  It is intended to test that
+# gdb could correctly handle floating point constant with a suffix.
+
+standard_testfile .c
+
+proc do_compile { {opts {}} } {
+    global srcdir subdir srcfile binfile
+    set ccopts {debug quiet}
+    foreach opt $opts {lappend ccopts "additional_flags=$opt"}
+    gdb_compile "${srcdir}/${subdir}/${srcfile}" "$binfile" executable $ccopts
+}
+
+if { [do_compile] != "" && [do_compile {-mfloat128}] != "" } {
+    untested "compiler can't handle __float128 type?"
+    return -1
+}
+
+clean_restart ${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"
+
+# Print the original value of ld and f128
+gdb_test "print ld" ".* = 1\\.375.*" "The original value of ld is 1.375"
+gdb_test "print f128" ".* = 2\\.375.*" "The original value of f128 is 2.375"
+
+# Test that gdb could correctly recognize float constant expression with a suffix.
+# FIXME: gdb does not yet recognize the GNU extension 'q' suffix for __float128 constants.
+gdb_test "print ld=-1.375l" ".* = -1\\.375.*" "Try to change ld to -1.375 with 'print ld=-1.375l'"
+gdb_test "print f128=-2.375l" ".* = -2\\.375.*" "Try to change f128 to -2.375 with 'print f128=-2.375l'"
+
+# Test that gdb could handle the above correctly with "set var" command.
+set test "set variable ld=10.375l"
+gdb_test_multiple "set var ld=10.375l" "$test" {
+    -re "$gdb_prompt $" {
+	pass "$test"
+    }
+    -re "Invalid number.*$gdb_prompt $" {
+	fail "$test (do not recognize 10.375l)"
+    }
+}
+
+set test "set variable f128=20.375l"
+gdb_test_multiple "set var f128=20.375l" "$test" {
+    -re "$gdb_prompt $" {
+	pass "$test"
+    }
+    -re "Invalid number.*$gdb_prompt $" {
+	fail "$test (do not recognize 20.375l)"
+    }
+}
+
+gdb_test "print ld" ".* = 10\\.375.*" "The value of ld is changed to 10.375"
+gdb_test "print f128" ".* = 20\\.375.*" "The value of f128 is changed to 20.375"
+
Index: binutils-gdb/gdb/testsuite/gdb.base/floatn.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ binutils-gdb/gdb/testsuite/gdb.base/floatn.c	2016-08-26 19:14:45.221254450 +0200
@@ -0,0 +1,48 @@ 
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2016 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 3 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, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+_Float32 f32;
+_Float64 f64;
+_Float128 f128;
+_Float32x f32x;
+_Float64x f64x;
+
+_Complex _Float32 c32;
+_Complex _Float64 c64;
+_Complex _Float128 c128;
+_Complex _Float32x c32x;
+_Complex _Float64x c64x;
+
+int main()
+{
+  f32 = 1.5f32;
+  f64 = 2.25f64;
+  f128 = 3.375f128;
+  f32x = 10.5f32x;
+  f64x = 20.25f64x;
+
+  c32 = 1.5f32 + 1.0if;
+  c64 = 2.25f64 + 1.0if;
+  c128 = 3.375f128 + 1.0if;
+  c32x = 10.5f32x + 1.0if;
+  c64x = 20.25f64x + 1.0if;
+
+  return 0;
+}
Index: binutils-gdb/gdb/testsuite/gdb.base/floatn.exp
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ binutils-gdb/gdb/testsuite/gdb.base/floatn.exp	2016-08-26 19:14:45.225254476 +0200
@@ -0,0 +1,124 @@ 
+# Copyright 2016 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 3 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, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the gdb testsuite.  It is intended to test that
+# gdb could correctly handle floating point constant with a suffix.
+
+standard_testfile .c
+
+proc do_compile { {opts {}} } {
+    global srcdir subdir srcfile binfile
+    set ccopts {debug quiet}
+    foreach opt $opts {lappend ccopts "additional_flags=$opt"}
+    gdb_compile "${srcdir}/${subdir}/${srcfile}" "$binfile" executable $ccopts
+}
+
+if { [do_compile] != "" && [do_compile {-mfloat128}] != "" } {
+    untested "compiler can't handle _FloatN/_FloatNx types?"
+    return -1
+}
+
+clean_restart ${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"
+
+# Print the original values of f32, f64, f128, f32x, f64x.
+gdb_test "print f32" ".* = 1\\.5.*" "The original value of f32 is 1.5"
+gdb_test "print f64" ".* = 2\\.25.*" "The original value of f64 is 2.25"
+gdb_test "print f128" ".* = 3\\.375.*" "The original value of f128 is 3.375"
+gdb_test "print f32x" ".* = 10\\.5.*" "The original value of f32x is 10.5"
+gdb_test "print f64x" ".* = 20\\.25.*" "The original value of f64x is 20.25"
+
+# Test that gdb could correctly recognize float constant expression with a suffix.
+# FIXME: gdb does not yet recognize the suffix for _FloatN/_FloatNx types.
+gdb_test "print f32=-1.5" ".* = -1\\.5.*" "Try to change f32 to -1.5 with 'print f32=-1.5'"
+gdb_test "print f64=-2.25" ".* = -2\\.25.*" "Try to change f64 to -2.25 with 'print f64=-2.25'"
+gdb_test "print f128=-3.375" ".* = -3\\.375.*" "Try to change f128 to -3.375 with 'print f128=-3.375'"
+gdb_test "print f32x=-10.5" ".* = -10\\.5.*" "Try to change f32x to -10.5 with 'print f32=-1.5x'"
+gdb_test "print f64x=-20.25" ".* = -20\\.25.*" "Try to change f64x to -20.25 with 'print f64=-2.25x'"
+
+# Test that gdb could handle the above correctly with "set var" command.
+set test "set variable f32 = 10.5"
+gdb_test_multiple "set var f32=10.5" "$test" {
+    -re "$gdb_prompt $" {
+	pass "$test"
+    }
+    -re "Invalid number.*$gdb_prompt $" {
+	fail "$test (do not recognize 10.5)"
+    }
+}
+
+set test "set variable f64 = 20.25"
+gdb_test_multiple "set var f64=20.25" "$test" {
+    -re "$gdb_prompt $" {
+	pass "$test"
+    }
+    -re "Invalid number.*$gdb_prompt $" {
+	fail "$test (do not recognize 20.25)"
+    }
+}
+
+set test "set variable f128 = 30.375"
+gdb_test_multiple "set var f128=30.375" "$test" {
+    -re "$gdb_prompt $" {
+	pass "$test"
+    }
+    -re "Invalid number.*$gdb_prompt $" {
+	fail "$test (do not recognize 30.375)"
+    }
+}
+
+set test "set variable f32x = 100.5"
+gdb_test_multiple "set var f32x=100.5" "$test" {
+    -re "$gdb_prompt $" {
+	pass "$test"
+    }
+    -re "Invalid number.*$gdb_prompt $" {
+	fail "$test (do not recognize 100.5)"
+    }
+}
+
+set test "set variable f64x = 200.25"
+gdb_test_multiple "set var f64x=200.25" "$test" {
+    -re "$gdb_prompt $" {
+	pass "$test"
+    }
+    -re "Invalid number.*$gdb_prompt $" {
+	fail "$test (do not recognize 200.25)"
+    }
+}
+
+gdb_test "print f32" ".* = 10\\.5.*" "The value of f32 is changed to 10.5"
+gdb_test "print f64" ".* = 20\\.25.*" "The value of f64 is changed to 20.25"
+gdb_test "print f128" ".* = 30\\.375.*" "The value of f128 is changed to 30.375"
+gdb_test "print f32x" ".* = 100\\.5.*" "The value of f32x is changed to 100.5"
+gdb_test "print f64x" ".* = 200\\.25.*" "The value of f64x is changed to 200.25"
+
+# Print the original values of c32, c64, c128, c32x, c64x.
+gdb_test "print c32" ".* = 1\\.5 \\+ 1 \\* I.*" "The original value of c32 is 1.5 + 1 * I"
+gdb_test "print c64" ".* = 2\\.25 \\+ 1 \\* I.*" "The original value of c64 is 2.25 + 1 * I"
+gdb_test "print c128" ".* = 3\\.375 \\+ 1 \\* I.*" "The original value of c128 is 3.375 + 1 * I"
+gdb_test "print c32x" ".* = 10\\.5 \\+ 1 \\* I.*" "The original value of c32x is 10.5 + 1 * I"
+gdb_test "print c64x" ".* = 20\\.25 \\+ 1 \\* I.*" "The original value of c64x is 20.25 + 1 * I"
+
+# FIXME: GDB cannot parse non-trivial complex constants yet.
+