Re: Printing decimal128 types out of registers

Thiago Jung Bauermann
2008-01-30T21:03:45Z

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

On Wed, 2008-01-30 at 19:52 +0100, Mark Kettenis wrote:
> > From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> > ppc_dl0_upper_regnum is used ppc_pseudo_register_{read,write}. Are you
> > saying that given it always has the value of ppc_fp0_regnum, I should
> > use that instead? Could be, but then there's the lack of symmetry in
> > using an fp variable in dl-related code. But that's minor.
>
> Yes, I think that using ppc_fp0_regnum is better, since it makes it
> explicit in the code that the decimal float (pseudo) registers are
> just a different representation of the floating point registers.
>
> > ppcdl15_regnum is indeed unused. I kept it also for symmetry reasons,
> > since there's ppc_ev31_regnum. But it can be removed (specially if the
> > later is removed as well as you suggested).
>
> Yes, that was what I was thinking. The less uneeded clutter, the better.

Ok, removed those. I also refreshed it against the reworked SPE macro
cleanup patch. What about this?
--
[]'s
Thiago Jung Bauermann
Software Engineer
IBM Linux Technology Center

[-- Attachment #2: dec128-regs-rev2.diff --]
[-- Type: text/x-patch, Size: 18562 bytes --]

2008-01-30 Luis Machado <luisgpm@br.ibm.com>
Thiago Jung Bauermann <bauerman@br.ibm.com>

gdb/
* infcmd.c (default_print_registers_info): Also print hex
raw contents for TYPE_CODE_DECFLOAT registers.
* ppc-tdep.h (gdbarch_tdep): Add ppc_dl0_regnum member.
* rs6000-tdep.c (IS_DFP_PSEUDOREG): New macro.
(rs6000_register_name): Add support for DFP pseudo-registers.
(rs6000_pseudo_register_type): Likewise.
rs6000_pseudo_register_reggroup_p): Likewise.
(ppc_pseudo_register_read): New function.
(ppc_pseudo_register_write): Likewise.
(rs6000_pseudo_register_read): Likewise.
(rs6000_pseudo_register_write): Likewise.
(e500_pseudo_register_read): Move checks to
rs6000_pseudo_register_read.
(e500_pseudo_register_write): Move checks to
rs6000_pseudo_register_write.
(rs6000_gdbarch_init): Initialize tdep->ppc_dl0_regnum. Install
rs6000_pseudo_register_read and rs6000_pseudo_register_write
in gdbarch if SPE or DFP is available. Adjust gdbarch's
num_pseudo_regs to account for DFP pseudo regs.

gdb/testsuite/
* gdb.arch/powerpc-d128-regs.exp: New testcase expect file.
* gdb.arch/powerpc-d128-regs.c: New testcase source file.

gdb/doc/
* gdb.texinfo: (Decimal Floating Point): Mention pseudo-registers
available in PowerPC architecture.
(Embedded Processors): Change node name of PowerPC item in menu.
(PowerPC): Rename to...
(PowerPC Embedded): this.
(Architectures): Add new PowerPC item in menu.
(PowerPC): New node.

diff -r 168620c4b9da -r 5d0fad100af7 gdb/doc/gdb.texinfo
--- a/gdb/doc/gdb.texinfo Wed Jan 30 16:49:16 2008 -0200
+++ b/gdb/doc/gdb.texinfo Wed Jan 30 18:54:00 2008 -0200
@@ -9670,6 +9670,10 @@ In addition, in order to imitate @value{
In addition, in order to imitate @value{GDBN}'s behaviour with binary floating
point computations, error checking in decimal float operations ignores
underflow, overflow and divide by zero exceptions.
+
+In the PowerPC architecture, @value{GDBN} provides a set of pseudo-registers
+to inspect @code{_Decimal128} values stored in floating point registers. See
+@ref{PowerPC,,PowerPC} for more details.

@node Objective-C
@subsection Objective-C
@@ -14602,7 +14606,7 @@ acceptable commands.
* MIPS Embedded:: MIPS Embedded
* OpenRISC 1000:: OpenRisc 1000
* PA:: HP PA Embedded
-* PowerPC:: PowerPC
+* PowerPC Embedded:: PowerPC Embedded
* Sparclet:: Tsqware Sparclet
* Sparclite:: Fujitsu Sparclite
* Z8000:: Zilog Z8000
@@ -15111,8 +15115,8 @@ Set suspend trace mode.

@end table

-@node PowerPC
-@subsection PowerPC
+@node PowerPC Embedded
+@subsection PowerPC Embedded

@value{GDBN} provides the following PowerPC-specific commands:

@@ -15475,6 +15479,7 @@ all uses of @value{GDBN} with the archit
* MIPS::
* HPPA:: HP PA architecture
* SPU:: Cell Broadband Engine SPU architecture
+* PowerPC::
@end menu

@node i386
@@ -15691,6 +15696,20 @@ and local store addresses and transfer s

@end table

+@node PowerPC
+@subsection PowerPC
+@cindex PowerPC architecture
+
+When @value{GDBN} is debugging the PowerPC architecture, it provides a set of
+pseudo-registers to enable inspection of 128-bit wide Decimal Floating Point
+numbers stored in the floating point registers. These values must be stored
+in two consecutive registers, always starting at an even register like
+@code{f0} or @code{f2}.
+
+The pseudo-registers go from @code{$dl0} through @code{$dl15}, and are formed
+by joining the even/odd register pairs @code{f0} and @code{f1} for @code{$dl0},
+@code{f2} and @code{f3} for @code{$dl1} and so on.
+

@node Controlling GDB
@chapter Controlling @value{GDBN}
diff -r 168620c4b9da -r 5d0fad100af7 gdb/infcmd.c
--- a/gdb/infcmd.c Wed Jan 30 16:49:16 2008 -0200
+++ b/gdb/infcmd.c Wed Jan 30 18:54:00 2008 -0200
@@ -1624,7 +1624,8 @@ default_print_registers_info (struct gdb

/* If virtual format is floating, print it that way, and in raw
hex. */
- if (TYPE_CODE (register_type (gdbarch, i)) == TYPE_CODE_FLT)
+ if (TYPE_CODE (register_type (gdbarch, i)) == TYPE_CODE_FLT
+ || TYPE_CODE (register_type (gdbarch, i)) == TYPE_CODE_DECFLOAT)
{
int j;

diff -r 168620c4b9da -r 5d0fad100af7 gdb/ppc-tdep.h
--- a/gdb/ppc-tdep.h Wed Jan 30 16:49:16 2008 -0200
+++ b/gdb/ppc-tdep.h Wed Jan 30 18:54:00 2008 -0200
@@ -204,6 +204,9 @@ struct gdbarch_tdep
int ppc_acc_regnum; /* SPE 'acc' register */
int ppc_spefscr_regnum; /* SPE 'spefscr' register */

+ /* Decimal 128 registers. */
+ int ppc_dl0_regnum; /* First Decimal128 argument register pair. */
+
/* Offset to ABI specific location where link register is saved. */
int lr_frame_offset;

diff -r 168620c4b9da -r 5d0fad100af7 gdb/rs6000-tdep.c
--- a/gdb/rs6000-tdep.c Wed Jan 30 16:49:16 2008 -0200
+++ b/gdb/rs6000-tdep.c Wed Jan 30 18:54:00 2008 -0200
@@ -82,6 +82,11 @@
#define IS_SPE_PSEUDOREG(tdep, regnum) ((tdep)->ppc_ev0_regnum >= 0 \
&& (regnum) >= (tdep)->ppc_ev0_regnum \
&& (regnum) < (tdep)->ppc_ev0_regnum + 32)
+
+/* Determine if regnum is a decimal float pseudo-register. */
+#define IS_DFP_PSEUDOREG(tdep, regnum) ((tdep)->ppc_dl0_regnum >= 0 \
+ && (regnum) >= (tdep)->ppc_dl0_regnum \
+ && (regnum) < (tdep)->ppc_dl0_regnum + 16)

/* The list of available "set powerpc ..." and "show powerpc ..."
commands. */
@@ -2385,6 +2390,18 @@ rs6000_register_name (struct gdbarch *gd
return spe_regnames[regno - tdep->ppc_ev0_regnum];
}

+ /* Check if the decimal128 pseudo-registers are available. */
+ if (IS_DFP_PSEUDOREG (tdep, regno))
+ {
+ static const char *const dfp128_regnames[] = {
+ "dl0", "dl1", "dl2", "dl3",
+ "dl4", "dl5", "dl6", "dl7",
+ "dl8", "dl9", "dl10", "dl11",
+ "dl12", "dl13", "dl14", "dl15"
+ };
+ return dfp128_regnames[regno - tdep->ppc_dl0_regnum];
+ }
+
return tdesc_register_name (gdbarch, regno);
}

@@ -2397,9 +2414,15 @@ rs6000_pseudo_register_type (struct gdba
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

/* These are the only pseudo-registers we support. */
- gdb_assert (IS_SPE_PSEUDOREG (tdep, regnum));
+ gdb_assert (IS_SPE_PSEUDOREG (tdep, regnum)
+ || IS_DFP_PSEUDOREG (tdep, regnum));

- return rs6000_builtin_type_vec64 (gdbarch);
+ /* These are the e500 pseudo-registers. */
+ if (IS_SPE_PSEUDOREG (tdep, regnum))
+ return rs6000_builtin_type_vec64 (gdbarch);
+ else
+ /* Could only be the ppc decimal128 pseudo-registers. */
+ return builtin_type (current_gdbarch)->builtin_declong;
}

/* Is REGNUM a member of REGGROUP? */
@@ -2410,12 +2433,15 @@ rs6000_pseudo_register_reggroup_p (struc
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

/* These are the only pseudo-registers we support. */
- gdb_assert (IS_SPE_PSEUDOREG (tdep, regnum));
+ gdb_assert (IS_SPE_PSEUDOREG (tdep, regnum)
+ || IS_DFP_PSEUDOREG (tdep, regnum));

- if (group == all_reggroup || group == vector_reggroup)
- return 1;
+ /* These are the e500 pseudo-registers. */
+ if (IS_SPE_PSEUDOREG (tdep, regnum))
+ return group == all_reggroup || group == vector_reggroup;
else
- return 0;
+ /* Could only be the ppc decimal128 pseudo-registers. */
+ return group == all_reggroup || group == float_reggroup;
}

/* The register format for RS/6000 floating point registers is always
@@ -2516,38 +2542,110 @@ e500_pseudo_register_read (struct gdbarc
e500_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
int reg_nr, gdb_byte *buffer)
{
- struct gdbarch *regcache_arch = get_regcache_arch (regcache);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-
- gdb_assert (regcache_arch == gdbarch);
-
- if (IS_SPE_PSEUDOREG (tdep, reg_nr))
- e500_move_ev_register (regcache_raw_read, regcache, reg_nr, buffer);
- else
- internal_error (__FILE__, __LINE__,
- _("e500_pseudo_register_read: "
- "called on unexpected register '%s' (%d)"),
- gdbarch_register_name (gdbarch, reg_nr), reg_nr);
+ e500_move_ev_register (regcache_raw_read, regcache, reg_nr, buffer);
}

static void
e500_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
int reg_nr, const gdb_byte *buffer)
{
+ e500_move_ev_register ((void (*) (struct regcache *, int, gdb_byte *))
+ regcache_raw_write,
+ regcache, reg_nr, (gdb_byte *) buffer);
+}
+
+/* Read method for PPC pseudo-registers. Currently this is handling the
+ 16 decimal128 registers that map into 16 pairs of FP registers. */
+static void
+ppc_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
+ int reg_nr, gdb_byte *buffer)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int reg_index = reg_nr - tdep->ppc_dl0_regnum;
+
+ if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+ {
+ /* Read two FP registers to form a whole dl register. */
+ regcache_raw_read (regcache, tdep->ppc_fp0_regnum +
+ 2 * reg_index, buffer);
+ regcache_raw_read (regcache, tdep->ppc_fp0_regnum +
+ 2 * reg_index + 1, buffer + 8);
+ }
+ else
+ {
+ regcache_raw_read (regcache, tdep->ppc_fp0_regnum +
+ 2 * reg_index + 1, buffer + 8);
+ regcache_raw_read (regcache, tdep->ppc_fp0_regnum +
+ 2 * reg_index, buffer);
+ }
+}
+
+/* Write method for PPC pseudo-registers. Currently this is handling the
+ 16 decimal128 registers that map into 16 pairs of FP registers. */
+static void
+ppc_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
+ int reg_nr, const gdb_byte *buffer)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int reg_index = reg_nr - tdep->ppc_dl0_regnum;
+
+ if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+ {
+ /* Write each half of the dl register into a separate
+ FP register. */
+ regcache_raw_write (regcache, tdep->ppc_fp0_regnum +
+ 2 * reg_index, buffer);
+ regcache_raw_write (regcache, tdep->ppc_fp0_regnum +
+ 2 * reg_index + 1, buffer + 8);
+ }
+ else
+ {
+ regcache_raw_write (regcache, tdep->ppc_fp0_regnum +
+ 2 * reg_index + 1, buffer + 8);
+ regcache_raw_write (regcache, tdep->ppc_fp0_regnum +
+ 2 * reg_index, buffer);
+ }
+}
+
+static void
+rs6000_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
+ int reg_nr, gdb_byte *buffer)
+{
struct gdbarch *regcache_arch = get_regcache_arch (regcache);
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

gdb_assert (regcache_arch == gdbarch);
-
+
if (IS_SPE_PSEUDOREG (tdep, reg_nr))
- e500_move_ev_register ((void (*) (struct regcache *, int, gdb_byte *))
- regcache_raw_write,
- regcache, reg_nr, (gdb_byte *) buffer);
+ e500_pseudo_register_read (gdbarch, regcache, reg_nr, buffer);
+ else if (IS_DFP_PSEUDOREG (tdep, reg_nr))
+ ppc_pseudo_register_read (gdbarch, regcache, reg_nr, buffer);
else
internal_error (__FILE__, __LINE__,
- _("e500_pseudo_register_read: "
- "called on unexpected register '%s' (%d)"),
- gdbarch_register_name (gdbarch, reg_nr), reg_nr);
+ _("rs6000_pseudo_register_read: "
+ "called on unexpected register '%s' (%d)"),
+ gdbarch_register_name (gdbarch, reg_nr), reg_nr);
+}
+
+static void
+rs6000_pseudo_register_write (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ int reg_nr, const gdb_byte *buffer)
+{
+ struct gdbarch *regcache_arch = get_regcache_arch (regcache);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ gdb_assert (regcache_arch == gdbarch);
+
+ if (IS_SPE_PSEUDOREG (tdep, reg_nr))
+ e500_pseudo_register_write (gdbarch, regcache, reg_nr, buffer);
+ else if (IS_DFP_PSEUDOREG (tdep, reg_nr))
+ ppc_pseudo_register_write (gdbarch, regcache, reg_nr, buffer);
+ else
+ internal_error (__FILE__, __LINE__,
+ _("rs6000_pseudo_register_write: "
+ "called on unexpected register '%s' (%d)"),
+ gdbarch_register_name (gdbarch, reg_nr), reg_nr);
}

/* Convert a DBX STABS register number to a GDB register number. */
@@ -3168,10 +3266,11 @@ rs6000_gdbarch_init (struct gdbarch_info
enum auto_boolean soft_float_flag = powerpc_soft_float_global;
int soft_float;
enum powerpc_vector_abi vector_abi = powerpc_vector_abi_global;
- int have_fpu = 1, have_spe = 0, have_mq = 0, have_altivec = 0;
+ int have_fpu = 1, have_spe = 0, have_mq = 0, have_altivec = 0, have_dfp = 0;
int tdesc_wordsize = -1;
const struct target_desc *tdesc = info.target_desc;
struct tdesc_arch_data *tdesc_data = NULL;
+ int num_pseudoregs = 0;

from_xcoff_exec = info.abfd && info.abfd->format == bfd_object &&
bfd_get_flavour (info.abfd) == bfd_target_xcoff_flavour;
@@ -3341,6 +3440,10 @@ rs6000_gdbarch_init (struct gdbarch_info
}
else
have_fpu = 0;
+
+ /* The DFP pseudo-registers will be available when there are floating
+ point registers. */
+ have_dfp = have_fpu;

feature = tdesc_find_feature (tdesc,
"org.gnu.gdb.power.altivec");
@@ -3588,10 +3691,10 @@ rs6000_gdbarch_init (struct gdbarch_info
else
tdep->lr_frame_offset = 8;

- if (have_spe)
+ if (have_spe || have_dfp)
{
- set_gdbarch_pseudo_register_read (gdbarch, e500_pseudo_register_read);
- set_gdbarch_pseudo_register_write (gdbarch, e500_pseudo_register_write);
+ set_gdbarch_pseudo_register_read (gdbarch, rs6000_pseudo_register_read);
+ set_gdbarch_pseudo_register_write (gdbarch, rs6000_pseudo_register_write);
}

set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
@@ -3603,7 +3706,13 @@ rs6000_gdbarch_init (struct gdbarch_info
set_gdbarch_print_insn (gdbarch, gdb_print_insn_powerpc);

set_gdbarch_num_regs (gdbarch, PPC_NUM_REGS);
- set_gdbarch_num_pseudo_regs (gdbarch, have_spe ? 32 : 0);
+
+ if (have_spe)
+ num_pseudoregs += 32;
+ if (have_dfp)
+ num_pseudoregs += 16;
+
+ set_gdbarch_num_pseudo_regs (gdbarch, num_pseudoregs);

set_gdbarch_ptr_bit (gdbarch, wordsize * TARGET_CHAR_BIT);
set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT);
@@ -3726,6 +3835,13 @@ rs6000_gdbarch_init (struct gdbarch_info
/* Recording the numbering of pseudo registers. */
tdep->ppc_ev0_regnum = have_spe ? gdbarch_num_regs (gdbarch) : -1;

+ /* Set the register number for _Decimal128 pseudo-registers. */
+ tdep->ppc_dl0_regnum = have_dfp? gdbarch_num_regs (gdbarch) : -1;
+
+ if (have_dfp && have_spe)
+ /* Put the _Decimal128 pseudo-registers after the SPE registers. */
+ tdep->ppc_dl0_regnum += 32;
+
return gdbarch;
}

diff -r 168620c4b9da -r 5d0fad100af7 gdb/testsuite/gdb.arch/powerpc-d128-regs.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gdb/testsuite/gdb.arch/powerpc-d128-regs.c Wed Jan 30 18:54:00 2008 -0200
@@ -0,0 +1,25 @@
+/* This file is part of GDB, the GNU debugger.
+
+ Copyright 2008 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/>. */
+
+/* Tests ppc decimal128 pseudo-registers. */
+
+int main(void)
+{
+ _Decimal128 d128 = 1.2345678910dl;
+
+ return 0;
+}
diff -r 168620c4b9da -r 5d0fad100af7 gdb/testsuite/gdb.arch/powerpc-d128-regs.exp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gdb/testsuite/gdb.arch/powerpc-d128-regs.exp Wed Jan 30 18:54:00 2008 -0200
@@ -0,0 +1,77 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2008
+# 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/>.
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@gnu.org
+
+# Testcase for ppc decimal128 pseudo-registers.
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+if ![istarget "powerpc64-*"] then {
+ verbose "Skipping powerpc Decimal128 pseudo-registers testcase."
+ return
+}
+
+set testfile "powerpc-d128-regs"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {quiet debug}] != "" } {
+ untested powerpc-d128-regs.exp
+ return -1
+}
+
+# Start with a fresh gdb.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if { ![runto main] } then {
+ fail "run to main"
+ return
+}
+
+if [gdb_test "show arch" ".*currently powerpc:common.*" "Checking for PPC arch"] {
+ return -1;
+}
+
+gdb_test "next" ""
+
+for {set i 0} {$i < 16} {incr i 1} {
+gdb_test "set \$dl$i=d128" "" "Set dl$i register"
+
+gdb_test "print \$dl$i" "\\\$$decimal = 1\.2345678910" "Print dl$i register as DFP"
+
+gdb_test "info reg dl$i" \
+ "dl$i\[ \]*1\.2345678910\[\t\]*\\(raw 0x2205800000000000000000049c5de09c\\)" \
+ "Print dl$i register with the info reg command"
+
+gdb_test "info reg f[expr 2*$i]" \
+ "f[expr 2*$i]\[ \]*8\.608957309287334e\-145\[\t\]*\\(raw 0x2205800000000000\\)" \
+ "Testing lower half of dl$i register"
+
+gdb_test "info reg f[expr 2*$i+1]" \
+ "f[expr 2*$i+1]\[ \]*9\.7841140127686122e\-314\[\t\]*\\(raw 0x000000049c5de09c\\)" \
+ "Testing upper half of dl$i register"
+
+}