[RFC] decimal float point patch based on libdecnumber: testcase

Wu Zhou
2006-06-21T21:03:44Z

Hello Daniel/all,

About one week ago, I said that I will rework my dfp patch based on libdecnumber.
OK. Here it is. This post is about what it can support right now. The
testcase can tell easily about this. The gdb patch will be posted in
another email.

The functions this patch provides are much the same as before. But it is
more exensible because it is based on libdecnumber. I list here what is
available now. If you think any functionality is desirable, please tell
me. I will try to add them in.

- for dfp constants, this patch supports two kind of representation:
scientific one and non-scientific one. To input any dfp constants, you
need to add suffix to differentiate it from binary float: "df" for deciaml
float (32 bits), "dd" for deciaml double (64 bits), and "dl" for deciaml
long (128 bits). When printing dfp constants, it will strip the suffix.

- it supports the displaying of dfp values in variables, struct, function
argument and also back trace. Any more is needed?

- it support the negation operation (-dfp), assign operation (d1 = d2 or
d1 = -d2),

- it can handle finite dfp numbers, infinity (positive and negative), and
NaN (not a number).

- it can also support the max, normalized min and subnormalized min well.

- we can't do conversion between binary float and decimal float right, or
between two different dfp types right now

Here goes the testcase. Please review. Any comment or suggestion is
highly appreciated.

P.S: I am trying to make it self explanatory. But if you think more
comment is needed in some place, feel free to tell me.

2006-06-21 Wu Zhou <woodzltc@cn.ibm.com>

* gdb.base/dfp-exprs.exp: New testcase to verify that gdb can
handle dfp constants correctly.
* gdb.base/dfp-test.c: New test file, used for dfp-test.exp.
* gdb.base/dfp-test.exp: New testcase toverify that gdb can handle
dfp related operation.

Index: gdb.base/dfp-exprs.exp
===================================================================
RCS file: gdb.base/dfp-exprs.exp
diff -N gdb.base/dfp-exprs.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb.base/dfp-exprs.exp 21 Jun 2006 21:00:23 -0000
@@ -0,0 +1,88 @@
+# Copyright (C) 2005 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 was written by Wu Zhou. (woodzltc@cn.ibm.com)
+
+# This file is part of the gdb testsuite. It contains test for evaluating
+# simple decimal floating point (DFP) expression.
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+proc test_dfp_literals_accepted {} {
+
+ # Test various dfp values, covering 32-bit, 64-bit and 128-bit ones
+
+ # _Decimal32 constants, which can support up to 7 digits
+ gdb_test "p 1.2df" " = 1.2"
+ gdb_test "p -1.2df" " = -1.2"
+ gdb_test "p 1.234567df" " = 1.234567"
+ gdb_test "p -1.234567df" " = -1.234567"
+ gdb_test "p 1234567.df" " = 1234567"
+ gdb_test "p -1234567.df" " = -1234567"
+
+ gdb_test "p 1.2E1df" " = 12"
+ gdb_test "p 1.2E10df" " = 1.2E\\+10"
+ gdb_test "p 1.2E-10df" " = 1.2E-10"
+
+ # The largest exponent for 32-bit dfp value is 96.
+ gdb_test "p 1.2E96df" " = 1.200000E\\+96"
+
+ # _Decimal64 constants, which can support up to 16 digits
+ gdb_test "p 1.2dd" " = 1.2"
+ gdb_test "p -1.2dd" " = -1.2"
+ gdb_test "p 1.234567890123456dd" " = 1.234567890123456"
+ gdb_test "p -1.234567890123456dd" " = -1.234567890123456"
+ gdb_test "p 1234567890123456.dd" " = 1234567890123456"
+ gdb_test "p -1234567890123456.dd" " = -1234567890123456"
+
+ gdb_test "p 1.2E1dd" " = 12"
+ gdb_test "p 1.2E10dd" " = 1.2E\\+10"
+ gdb_test "p 1.2E-10dd" " = 1.2E-10"
+
+ # The largest exponent for 64-bit dfp value is 384.
+ gdb_test "p 1.2E384dd" " = 1.200000000000000E\\+384"
+
+ # _Decimal128 constants, which can support up to 34 digits
+ gdb_test "p 1.2dl" " = 1.2"
+ gdb_test "p -1.2dl" " = -1.2"
+ gdb_test "p 1.234567890123456789012345678901234dl" " = 1.234567890123456789012345678901234"
+ gdb_test "p -1.234567890123456789012345678901234dl" " = -1.234567890123456789012345678901234"
+ gdb_test "p 1234567890123456789012345678901234.dl" " = 1234567890123456789012345678901234"
+ gdb_test "p -1234567890123456789012345678901234.dl" " = -1234567890123456789012345678901234"
+
+ gdb_test "p 1.2E1dl" " = 12"
+ gdb_test "p 1.2E10dl" " = 1.2E\\+10"
+ gdb_test "p 1.2E-10dl" " = 1.2E-10"
+
+ # The largest exponent for 128-bit dfp value is 6144.
+ gdb_test "p 1.2E6144dl" " = 1.200000000000000000000000000000000E\\+6144"
+}
+
+proc test_arithmetic_expressions {} {
+
+# Arithmetic operations for DFP types are not yet implemented in GDB.
+
+}
+
+# Start with a fresh gdb.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+
+test_dfp_literals_accepted
Index: gdb.base/dfp-test.c
===================================================================
RCS file: gdb.base/dfp-test.c
diff -N gdb.base/dfp-test.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb.base/dfp-test.c 21 Jun 2006 21:00:23 -0000
@@ -0,0 +1,95 @@
+/* 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>
+
+volatile _Decimal32 d32;
+volatile _Decimal64 d64;
+volatile _Decimal128 d128;
+
+struct decstruct
+{
+ int int4;
+ long long8;
+ _Decimal32 dec32;
+ _Decimal64 dec64;
+ _Decimal128 dec128;
+} ds;
+
+static _Decimal32
+arg0_32 (_Decimal32 arg0, _Decimal32 arg1, _Decimal32 arg2,
+ _Decimal32 arg3, _Decimal32 arg4, _Decimal32 arg5)
+{
+ return arg0;
+}
+
+static _Decimal64
+arg0_64 (_Decimal64 arg0, _Decimal64 arg1, _Decimal64 arg2,
+ _Decimal64 arg3, _Decimal64 arg4, _Decimal64 arg5)
+{
+ return arg0;
+}
+
+static _Decimal128
+arg0_128 (_Decimal128 arg0, _Decimal128 arg1, _Decimal128 arg2,
+ _Decimal128 arg3, _Decimal128 arg4, _Decimal128 arg5)
+{
+ return arg0;
+}
+
+int main()
+{
+ /* An finite 32-bits decimal floating point. */
+ d32 = 1.2345df; /* Initialize d32. */
+
+ /* Non-finite 32-bits decimal floating point: infinity and NaN. */
+ d32 = __builtin_infd32(); /* Positive infd32. */
+ d32 = -__builtin_infd32(); /* Negative infd32. */
+ d32 = __builtin_nand32("");
+
+ /* An finite 64-bits decimal floating point. */
+ d64 = 1.2345dd; /* Initialize d64. */
+
+ /* Non-finite 64-bits decimal floating point: infinity and NaN. */
+ d64 = __builtin_infd64(); /* Positive infd64. */
+ d64 = -__builtin_infd64(); /* Negative infd64. */
+ d64 = __builtin_nand64("");
+
+ /* An finite 128-bits decimal floating point. */
+ d128 = 1.2345dl; /* Initialize d128. */
+
+ /* Non-finite 128-bits decimal floating point: infinity and NaN. */
+ d128 = __builtin_infd128(); /* Positive infd128. */
+ d128 = -__builtin_infd128(); /* Negative infd128. */
+ d128 = __builtin_nand128("");
+
+ /* Functions with decimal floating point as parameter and return value. */
+ d32 = arg0_32 (0.1df, 1.0df, 2.0df, 3.0df, 4.0df, 5.0df);
+ d64 = arg0_64 (0.1dd, 1.0dd, 2.0dd, 3.0dd, 4.0dd, 5.0dd);
+ d128 = arg0_128 (0.1dl, 1.0dl, 2.0dl, 3.0dl, 4.0dl, 5.0dl);
+
+ ds.int4 = 1;
+ ds.long8 = 2;
+ ds.dec32 = 1.2345df;
+ ds.dec64 = 1.2345dd;
+ ds.dec128 = 1.2345dl;
+
+ return 0; /* Exit point. */
+}
Index: gdb.base/dfp-test.exp
===================================================================
RCS file: gdb.base/dfp-test.exp
diff -N gdb.base/dfp-test.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb.base/dfp-test.exp 21 Jun 2006 21:00:23 -0000
@@ -0,0 +1,247 @@
+# Copyright 2005 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 was written by Wu Zhou. (woodzltc@cn.ibm.com)
+
+# This file is part of the gdb testsuite. It is intended to test that
+# gdb could correctly hane decimal floating point introduced in IEEE 754R.
+
+proc d32_set_tests {} {
+
+ gdb_test "p d32=123.45df" " = 123.45"
+ gdb_test "p d32=12345.df" " = 12345"
+ gdb_test "p d32=12345.67df" " = 12345.67"
+ gdb_test "p d32=1234567.df" " = 1234567"
+
+ gdb_test "p d32=1.234567E0df" " = 1.234567"
+ gdb_test "p d32=1.234567E10df" " = 1.234567E\\+10"
+ gdb_test "p d32=1.234567E+96df" " = 1.234567E\\+96"
+
+ # Test that gdb could handle the max, normalized min and subnormalized min.
+ gdb_test "p d32=9.999999E96df" " = 9.999999E\\+96"
+ gdb_test "p d32=1.0E-95df" " = 1.0E\\-95"
+ gdb_test "p d32=1.E-101df" " = 1E\\-101"
+ gdb_test "p d32=0.000001E-95df" " = 1E\\-101"
+
+ # Test that gdb could detect coefficient/exponent out of range.
+ # The coefficient out of range will be rounded to its nearest value.
+ # And the exponent out of range will be handled as infinity.
+ gdb_test "p d32=1.2345678df" " = 1.234568" "1.2345678 is rounded to 1.234568"
+ gdb_test "p d32=1.0E-101df" " = 1E-101" "1.0E-101 is rounded to 1E-101"
+ gdb_test "p d32=1.234567E+97df" " = Infinity" "1.234567E+97 is Infinity"
+
+ # Test that gdb could detect the errors in the string representation of _Decimal32
+ gdb_test "p d32=12345.df" " = 12345" "12345. is an valid number"
+ gdb_test "p d32=12345df" ".*Invalid number.*" "12345 is an invalid number"
+ gdb_test "p d32=1.23Edf" " = NaN" "1.23E is NaN (not a number)"
+ gdb_test "p d32=1.23E45Adf" " = NaN" "1.23E45A is NaN (not a number)"
+}
+
+proc d64_set_tests {} {
+
+ gdb_test "p d64=123.45dd" " = 123.45"
+ gdb_test "p d64=12345.dd" " = 12345"
+ gdb_test "p d64=12345.67dd" " = 12345.67"
+ gdb_test "p d64=1.234567890123456dd" " = 1.234567890123456"
+
+ gdb_test "p d64=1.234567890123456E10dd" " = 12345678901.23456"
+ gdb_test "p d64=1.234567890123456E100dd" " = 1.234567890123456E\\+100"
+ gdb_test "p d64=1.234567890123456E384dd" " = 1.234567890123456E\\+384"
+
+ # Test that gdb could handle the max, normalized min and subnormalized min.
+ gdb_test "p d64=9.999999999999999E384dd" " = 9.999999999999999E\\+384"
+ gdb_test "p d64=1.E-383dd" " = 1E\\-383"
+ gdb_test "p d64=1.E-398dd" " = 1E\\-398"
+ gdb_test "p d64=0.000000000000001E-383dd" " = 1E\\-398"
+
+ # Test that gdb could detect coefficient/exponent out of range.
+ # The coefficient out of range will be rounded to its nearest value.
+ # And the exponent out of range will be handled as infinity.
+ gdb_test "p d64=1.2345678901234567dd" " = 1.234567890123457" "1.2345678901234567 is rounded to 1.234567890123457"
+ gdb_test "p d64=9.9999999999999999E384dd" " = Infinity" "d64=9.9999999999999999E384 is Infinity"
+ gdb_test "p d64=1.234567890123456E385dd" " = Infinity" "d64=1.234567890123456E385 is Infinity"
+
+ # Test that gdb could detect the errors in the string representation of _Decimal64
+ gdb_test "p d64=12345dd" ".*Invalid number.*" "12345dd is an invalid number"
+ gdb_test "p d64=1.23Edd" " = NaN" "1.23E is NaN (not a number)"
+ gdb_test "p d64=1.23E45Add" "= NaN" "1.23E45A is NaN (not a number)"
+}
+
+proc d128_set_tests {} {
+
+ gdb_test "p d128=123.45dl" " = 123.45"
+ gdb_test "p d128=12345.dl" " = 12345"
+ gdb_test "p d128=12345.67dl" " = 12345.67"
+ gdb_test "p d128=1.234567890123456789012345678901234dl" " = 1.234567890123456789012345678901234"
+
+ gdb_test "p d128=1.234567890123456E10dl" " = 12345678901.23456"
+ gdb_test "p d128=1.234567890123456E100dl" " = 1.234567890123456E\\+100"
+ gdb_test "p d128=1.234567890123456E1000dl" " = 1.234567890123456E\\+1000"
+
+ # Test that gdb could handle the max, normalized min and subnormalized min.
+ gdb_test "p d128=9.999999999999999999999999999999999E6144dl" " = 9.999999999999999999999999999999999E\\+6144"
+ gdb_test "p d128=1.E-6143dl" " = 1E\\-6143"
+ gdb_test "p d128=1.E-6176dl" " = 1E\\-6176"
+ gdb_test "p d128=0.000000000000000000000000000000001E-6143dl" " = 1E\\-6176"
+
+ # Test that gdb could detect coefficient/exponent out of range.
+ # The coefficient out of range will be rounded to its nearest value.
+ # And the exponent out of range will be handled as infinity.
+ gdb_test "p d128=1.2345678901234567890123456789012345dl" "1.234567890123456789012345678901234" "1.2345678901234567890123456789012345 is rounded to 1.234567890123456789012345678901234"
+ gdb_test "p d128=1.234567890123456E6145dl" "Infinity" "d128=1.234567890123456E6145 is Infinity"
+
+ # Test that gdb could detect the errors in the string representation of _Decimal128
+ gdb_test "p d128=12345dl" ".*Invalid number.*" "12345dl is an invalid number"
+ gdb_test "p d128=1.23Edl" " = NaN" "1.23E is NaN (not a number)"
+ gdb_test "p d128=1.23E45Adl" "= NaN" "1.23E45A is NaN (not a number)"
+}
+
+
+if $tracelevel {
+ strace $tracelevel
+}
+
+set testfile "dfp-test"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ untested "Couldn't compile ${srcfile}"
+ 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
+}
+
+# Different tests on 32-bits decimal floating point, including the printing
+# of finite numbers, infinite and NaN, and also the setting of different
+# decimal value.
+
+if [gdb_test "next" \
+ ".*Positive infd32.*" \
+ "next after initializing d32"] then { gdb_suppress_tests }
+gdb_test "print d32" "1.2345" "d32 is initialized to 1.2345"
+
+if [gdb_test "next" \
+ ".*Negative infd32.*" \
+ "next after assigning builtin infinity to d32"] then { gdb_suppress_tests }
+gdb_test "print d32" "Infinity" "d32 is positive Infinity"
+
+if [gdb_test "next" \
+ ".*__builtin_nand32.*" \
+ "next after assigning negative builtin infinity to d32"] then { gdb_suppress_tests }
+gdb_test "print d32" "-Infinity" "d32 is negative Infinity"
+
+if [gdb_test "next" \
+ ".*d64 = 1.2345.*" \
+ "next after assigning builtin NaN to d32"] then { gdb_suppress_tests }
+gdb_test "print d32" "NaN" "d32 is NaN"
+
+d32_set_tests
+
+
+# Different tests on 64-bits decimal floating point, including the display
+# of finite number, infinite and NaN, and also the setting of different
+# decimal value.
+
+if [gdb_test "next" \
+ ".*Positive infd64.*" \
+ "next after initializing d64"] then { gdb_suppress_tests }
+gdb_test "print d64" "1.2345" "d64 is initialized to 1.2345"
+
+if [gdb_test "next" \
+ ".*Negative infd64.*" \
+ "next after assigning builtin infinity to d64"] then { gdb_suppress_tests }
+gdb_test "print d64" "Infinity" "d64 is positive Infinity"
+
+if [gdb_test "next" \
+ ".*__builtin_nand64.*" \
+ "next after assigning negative builtin infinity to d64"] then { gdb_suppress_tests }
+gdb_test "print d64" "-Infinity" "d64 is negative Infinity"
+
+if [gdb_test "next" \
+ ".*d128 = 1.2345.*" \
+ "next after assigning builtin NaN to d64"] then { gdb_suppress_tests }
+gdb_test "print d64" "NaN" "d64 is NaN"
+
+d64_set_tests
+
+
+# Different tests on 128-bits decimal floating point, including the display
+# of finite number, infinite and NaN, and also the setting of different
+# decimal value.
+
+if [gdb_test "next" \
+ ".*Positive infd128.*" \
+ "next after initializing d128"] then { gdb_suppress_tests }
+gdb_test "print d128" "1.2345" "d128 is initialized to 1.2345"
+
+d128_set_tests
+
+if [gdb_test "next" \
+ ".*Negative infd128.*" \
+ "next after assigning builtin infinity to d128"] then { gdb_suppress_tests }
+gdb_test "print d128" "Infinity" "d128 is positive Infinity"
+
+if [gdb_test "next" \
+ ".*__builtin_nand128.*" \
+ "next after assigning negative builtin infinity to d128"] then { gdb_suppress_tests }
+gdb_test "print d128" "-Infinity" "d128 is negative Infinity"
+
+if [gdb_test "next" \
+ ".*arg0_32.*" \
+ "next after assigning builtin NaN to d128"] then { gdb_suppress_tests }
+gdb_test "print d128" "NaN" "d128 is NaN"
+
+# The following tests are intended to verify that gdb can correctly handle
+# DFP types in function arguments.
+
+gdb_breakpoint arg0_32
+gdb_continue_to_breakpoint "entry to arg0_32"
+gdb_test "backtrace" ".*arg0_32 \\(arg0=0.1, arg1=1.0, arg2=2.0, arg3=3.0, arg4=4.0, arg5=5.0\\).*" "backtrace at arg0_32"
+
+gdb_breakpoint arg0_64
+gdb_continue_to_breakpoint "entry to arg0_64"
+gdb_test "backtrace" ".*arg0_64 \\(arg0=0.1, arg1=1.0, arg2=2.0, arg3=3.0, arg4=4.0, arg5=5.0\\).*" "backtrace at arg0_64"
+
+gdb_breakpoint arg0_128
+gdb_continue_to_breakpoint "entry to arg0_128"
+gdb_test "backtrace" ".*arg0_128 \\(arg0=0.1, arg1=1.0, arg2=2.0, arg3=3.0, arg4=4.0, arg5=5.0\\).*" "backtrace at arg0_128"
+
+# The following tests are intended to verify that gdb can handle DFP types
+# correctly in struct.
+
+gdb_breakpoint [gdb_get_line_number "Exit point"]
+gdb_continue_to_breakpoint "Setting a decimal struct"
+gdb_test "print ds.dec32" " = 1.2345"
+gdb_test "print ds.dec64" " = 1.2345"
+gdb_test "print ds.dec128" " = 1.2345"
+
+# The following tests are intended to verify that gdb can handle "d1=d2"
+# and "d1=-d2" correctly.
+
+gdb_test "print ds.dec32=d32" " = 0.1"
+gdb_test "print ds.dec64=d64" " = 0.1"
+gdb_test "print ds.dec128=d128" " = 0.1"
+gdb_test "print ds.dec32 = -d32" " = -0.1"
+gdb_test "print ds.dec64 = -d64" " = -0.1"
+gdb_test "print ds.dec128 = -d128" " = -0.1"

Regards
- Wu Zhou