* [patch 0/2] Complete expression support for Decimal Floating Point @ 2007-12-20 5:55 Thiago Jung Bauermann 2007-12-20 5:55 ` [patch 1/2] Recognize DFP types in casts Thiago Jung Bauermann 2007-12-20 8:03 ` [patch 2/2] Wrap-up expression support for DFP Thiago Jung Bauermann 0 siblings, 2 replies; 22+ messages in thread From: Thiago Jung Bauermann @ 2007-12-20 5:55 UTC (permalink / raw) To: gdb-patches :ADDPATCH language-feature: Hi, These patches are intended to wrap-up decimal floating support in expressions. I am now working on teaching GDB how to call inferior functions with DFP arguments and/or return value on Linux/ppc32 and Linux ppc64, which I will submit shortly. After these patches and Luis' pending (hint, hint! :-) ) patch "PPC - Printing Decimal 128 types out of registers" are commited, I will submit a NEWS entry for the new decimal floating point support in GDB. With the already-incorporated DFP support plus the the patches mentioned above, GDB is be able to: - parse DFP constants; - recognize DFP types from DWARF2 debuginfo; - read and write to DFP variables; - show DFP values with appropriate printf masks; - use DFP values (constants and variables) in expressions; - cast to/from DFP types; - print 128-bit DFP values split in two FP registers (Power6 feature); - call inferior functions with DFP arguments and/or return value. I think that the above completes all needed DFP support in GDB. If anything is missing, please point out and I can work on it. -- []'s Thiago Jung Bauermann Software Engineer IBM Linux Technology Center ^ permalink raw reply [flat|nested] 22+ messages in thread
* [patch 1/2] Recognize DFP types in casts. 2007-12-20 5:55 [patch 0/2] Complete expression support for Decimal Floating Point Thiago Jung Bauermann @ 2007-12-20 5:55 ` Thiago Jung Bauermann 2007-12-20 15:24 ` Daniel Jacobowitz 2007-12-20 8:03 ` [patch 2/2] Wrap-up expression support for DFP Thiago Jung Bauermann 1 sibling, 1 reply; 22+ messages in thread From: Thiago Jung Bauermann @ 2007-12-20 5:55 UTC (permalink / raw) To: gdb-patches [-- Attachment #1: decimal-cast-support.diff --] [-- Type: text/plain, Size: 3796 bytes --] Convinces GDB to recognize DFP types in casts when no binary with debuginfo for DFP types is loaded. Before: (gdb) p (decimal float) 1 No symbol table is loaded. Use the "file" command. After: (gdb) p (_Decimal32) 1 $1 = 1E-101 Don't worry about the result. It will be fixed in the next patch. This should logically be part of the next patch, but the C parser is scary code and I don't feel very confident that this is indeed the right way to do it. It works, though, and introduces no regressions. I am also not sure of the ChangeLog format for .y files. Ok to commit? -- []'s Thiago Jung Bauermann Software Engineer IBM Linux Technology Center 2007-12-19 Thiago Jung Bauermann <bauerman@br.ibm.com> * c-exp.y: Add DECFLOAT_KEYWORD, DECDOUBLE_KEYWORD and DECLONG_KEYWORD for Decimal Floating Point types. Add typebase rule for DECFLOAT_KEYWORD, DECDOUBLE_KEYWORD and DECLONG_KEYWORD. (yylex): Recognize _Decimal32, _Decimal64 and _Decimal128 keywords. * gdbtypes.c (gdbtypes_post_init): Change names of decimal float types to conform to C extension for decimal float. Index: src-git/gdb/c-exp.y =================================================================== --- src-git.orig/gdb/c-exp.y 2007-10-26 14:00:29.000000000 -0200 +++ src-git/gdb/c-exp.y 2007-12-14 15:31:04.000000000 -0200 @@ -197,7 +197,7 @@ static int parse_number (char *, int, in /* Special type cases, put in to allow the parser to distinguish different legal basetypes. */ -%token SIGNED_KEYWORD LONG SHORT INT_KEYWORD CONST_KEYWORD VOLATILE_KEYWORD DOUBLE_KEYWORD +%token SIGNED_KEYWORD LONG SHORT INT_KEYWORD CONST_KEYWORD VOLATILE_KEYWORD DOUBLE_KEYWORD DECFLOAT_KEYWORD DECDOUBLE_KEYWORD DECLONG_KEYWORD %token <voidval> VARIABLE @@ -872,6 +872,12 @@ typebase /* Implements (approximately): { $$ = builtin_type (current_gdbarch)->builtin_double; } | LONG DOUBLE_KEYWORD { $$ = builtin_type (current_gdbarch)->builtin_long_double; } + | DECFLOAT_KEYWORD + { $$ = builtin_type (current_gdbarch)->builtin_decfloat; } + | DECDOUBLE_KEYWORD + { $$ = builtin_type (current_gdbarch)->builtin_decdouble; } + | DECLONG_KEYWORD + { $$ = builtin_type (current_gdbarch)->builtin_declong; } | STRUCT name { $$ = lookup_struct (copy_name ($2), expression_context_block); } @@ -1677,6 +1683,14 @@ yylex () /* Catch specific keywords. Should be done with a data structure. */ switch (namelen) { + case 11: + if (strncmp (tokstart, "_Decimal128", 11) == 0) + return DECLONG_KEYWORD; + case 10: + if (strncmp (tokstart, "_Decimal32", 10) == 0) + return DECFLOAT_KEYWORD; + if (strncmp (tokstart, "_Decimal64", 10) == 0) + return DECDOUBLE_KEYWORD; case 8: if (strncmp (tokstart, "unsigned", 8) == 0) return UNSIGNED; Index: src-git/gdb/gdbtypes.c =================================================================== --- src-git.orig/gdb/gdbtypes.c 2007-12-10 16:10:58.000000000 -0200 +++ src-git/gdb/gdbtypes.c 2007-12-14 15:31:04.000000000 -0200 @@ -3122,15 +3122,15 @@ gdbtypes_post_init (struct gdbarch *gdba builtin_type->builtin_decfloat = init_type (TYPE_CODE_DECFLOAT, 32 / 8, 0, - "decimal float", (struct objfile *) NULL); + "_Decimal32", (struct objfile *) NULL); builtin_type->builtin_decdouble = init_type (TYPE_CODE_DECFLOAT, 64 / 8, 0, - "decimal double", (struct objfile *) NULL); + "_Decimal64", (struct objfile *) NULL); builtin_type->builtin_declong = init_type (TYPE_CODE_DECFLOAT, 128 / 8, 0, - "decimal long double", (struct objfile *) NULL); + "_Decimal128", (struct objfile *) NULL); /* Pointer/Address types. */ -- -- []'s Thiago Jung Bauermann Software Engineer IBM Linux Technology Center ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [patch 1/2] Recognize DFP types in casts. 2007-12-20 5:55 ` [patch 1/2] Recognize DFP types in casts Thiago Jung Bauermann @ 2007-12-20 15:24 ` Daniel Jacobowitz 2007-12-20 16:48 ` Thiago Jung Bauermann 0 siblings, 1 reply; 22+ messages in thread From: Daniel Jacobowitz @ 2007-12-20 15:24 UTC (permalink / raw) To: Thiago Jung Bauermann; +Cc: gdb-patches On Thu, Dec 20, 2007 at 03:49:27AM -0200, Thiago Jung Bauermann wrote: > This should logically be part of the next patch, but the C parser is > scary code and I don't feel very confident that this is indeed the > right way to do it. It works, though, and introduces no regressions. Do you need parser changes for this? "unsigned" is a C keyword, and a bit special (e.g. in combinations with "int"); but doesn't _Decimal32 act syntactically like a TYPENAME? Try following language_lookup_primitive_type_by_name around to c_language_arch_info (and cplus_language_arch_info). -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [patch 1/2] Recognize DFP types in casts. 2007-12-20 15:24 ` Daniel Jacobowitz @ 2007-12-20 16:48 ` Thiago Jung Bauermann 2007-12-20 16:54 ` Thiago Jung Bauermann 2007-12-20 16:57 ` Daniel Jacobowitz 0 siblings, 2 replies; 22+ messages in thread From: Thiago Jung Bauermann @ 2007-12-20 16:48 UTC (permalink / raw) To: Daniel Jacobowitz; +Cc: gdb-patches [-- Attachment #1: Type: text/plain, Size: 808 bytes --] On Thu, 2007-12-20 at 09:08 -0500, Daniel Jacobowitz wrote: > On Thu, Dec 20, 2007 at 03:49:27AM -0200, Thiago Jung Bauermann wrote: > > This should logically be part of the next patch, but the C parser is > > scary code and I don't feel very confident that this is indeed the > > right way to do it. It works, though, and introduces no regressions. > > Do you need parser changes for this? "unsigned" is a C keyword, and a > bit special (e.g. in combinations with "int"); but doesn't _Decimal32 > act syntactically like a TYPENAME? > > Try following language_lookup_primitive_type_by_name around to > c_language_arch_info (and cplus_language_arch_info). Thanks for the tip. The below implements this approach and works well. -- []'s Thiago Jung Bauermann Software Engineer IBM Linux Technology Center [-- Attachment #2: decimal-cast-support-alt.diff --] [-- Type: text/x-patch, Size: 3573 bytes --] 2007-12-20 Thiago Jung Bauermann <bauerman@br.ibm.com> * c-exp.y: Add DECFLOAT_KEYWORD, DECDOUBLE_KEYWORD and DECLONG_KEYWORD for Decimal Floating Point types. Add typebase rule for DECFLOAT_KEYWORD, DECDOUBLE_KEYWORD and DECLONG_KEYWORD. (yylex): Recognize _Decimal32, _Decimal64 and _Decimal128 keywords. * gdbtypes.c (gdbtypes_post_init): Change names of decimal float types to conform to C extension for decimal float. * c-lang.c (enum c_primitive_types): Add entries for Decimal Floating Point types. (enum cplus_primitive_types): Likewise. (c_language_arch_info): Add Decimal Floating Point builtin types to the primitive_type_vector. (cplus_language_arch_info): Likewise. Index: src-git/gdb/gdbtypes.c =================================================================== --- src-git.orig/gdb/gdbtypes.c 2007-12-19 16:23:29.000000000 -0200 +++ src-git/gdb/gdbtypes.c 2007-12-19 16:24:01.000000000 -0200 @@ -3122,15 +3122,15 @@ gdbtypes_post_init (struct gdbarch *gdba builtin_type->builtin_decfloat = init_type (TYPE_CODE_DECFLOAT, 32 / 8, 0, - "decimal float", (struct objfile *) NULL); + "_Decimal32", (struct objfile *) NULL); builtin_type->builtin_decdouble = init_type (TYPE_CODE_DECFLOAT, 64 / 8, 0, - "decimal double", (struct objfile *) NULL); + "_Decimal64", (struct objfile *) NULL); builtin_type->builtin_declong = init_type (TYPE_CODE_DECFLOAT, 128 / 8, 0, - "decimal long double", (struct objfile *) NULL); + "_Decimal128", (struct objfile *) NULL); /* Pointer/Address types. */ Index: src-git/gdb/c-lang.c =================================================================== --- src-git.orig/gdb/c-lang.c 2007-12-20 14:14:49.000000000 -0200 +++ src-git/gdb/c-lang.c 2007-12-20 14:18:28.000000000 -0200 @@ -358,6 +358,9 @@ enum c_primitive_types { c_primitive_type_long_double, c_primitive_type_complex, c_primitive_type_double_complex, + c_primitive_type_decfloat, + c_primitive_type_decdouble, + c_primitive_type_declong, nr_c_primitive_types }; @@ -387,6 +390,9 @@ c_language_arch_info (struct gdbarch *gd lai->primitive_type_vector [c_primitive_type_long_double] = builtin->builtin_long_double; lai->primitive_type_vector [c_primitive_type_complex] = builtin->builtin_complex; lai->primitive_type_vector [c_primitive_type_double_complex] = builtin->builtin_double_complex; + lai->primitive_type_vector [c_primitive_type_decfloat] = builtin->builtin_decfloat; + lai->primitive_type_vector [c_primitive_type_decdouble] = builtin->builtin_decdouble; + lai->primitive_type_vector [c_primitive_type_declong] = builtin->builtin_declong; } const struct language_defn c_language_defn = @@ -442,6 +448,9 @@ enum cplus_primitive_types { cplus_primitive_type_complex, cplus_primitive_type_double_complex, cplus_primitive_type_bool, + cplus_primitive_type_decfloat, + cplus_primitive_type_decdouble, + cplus_primitive_type_declong, nr_cplus_primitive_types }; @@ -490,6 +499,12 @@ cplus_language_arch_info (struct gdbarch = builtin->builtin_double_complex; lai->primitive_type_vector [cplus_primitive_type_bool] = builtin->builtin_bool; + lai->primitive_type_vector [cplus_primitive_type_decfloat] + = builtin->builtin_decfloat; + lai->primitive_type_vector [cplus_primitive_type_decdouble] + = builtin->builtin_decdouble; + lai->primitive_type_vector [cplus_primitive_type_declong] + = builtin->builtin_declong; } const struct language_defn cplus_language_defn = ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [patch 1/2] Recognize DFP types in casts. 2007-12-20 16:48 ` Thiago Jung Bauermann @ 2007-12-20 16:54 ` Thiago Jung Bauermann 2007-12-20 16:57 ` Daniel Jacobowitz 1 sibling, 0 replies; 22+ messages in thread From: Thiago Jung Bauermann @ 2007-12-20 16:54 UTC (permalink / raw) To: Daniel Jacobowitz; +Cc: gdb-patches On Thu, 2007-12-20 at 14:40 -0200, Thiago Jung Bauermann wrote: > * c-exp.y: Add DECFLOAT_KEYWORD, DECDOUBLE_KEYWORD and > DECLONG_KEYWORD > for Decimal Floating Point types. > Add typebase rule for DECFLOAT_KEYWORD, DECDOUBLE_KEYWORD and > DECLONG_KEYWORD. > (yylex): Recognize _Decimal32, _Decimal64 and _Decimal128 > keywords. Forgot to delete this ChangeLog entry. -- []'s Thiago Jung Bauermann Software Engineer IBM Linux Technology Center ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [patch 1/2] Recognize DFP types in casts. 2007-12-20 16:48 ` Thiago Jung Bauermann 2007-12-20 16:54 ` Thiago Jung Bauermann @ 2007-12-20 16:57 ` Daniel Jacobowitz 2007-12-20 17:21 ` Thiago Jung Bauermann 1 sibling, 1 reply; 22+ messages in thread From: Daniel Jacobowitz @ 2007-12-20 16:57 UTC (permalink / raw) To: Thiago Jung Bauermann; +Cc: gdb-patches On Thu, Dec 20, 2007 at 02:40:49PM -0200, Thiago Jung Bauermann wrote: > 2007-12-20 Thiago Jung Bauermann <bauerman@br.ibm.com> > > * gdbtypes.c (gdbtypes_post_init): Change names of decimal float types > to conform to C extension for decimal float. > * c-lang.c (enum c_primitive_types): Add entries for Decimal Floating > Point types. > (enum cplus_primitive_types): Likewise. > (c_language_arch_info): Add Decimal Floating Point builtin types to > the primitive_type_vector. > (cplus_language_arch_info): Likewise. This version is OK. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [patch 1/2] Recognize DFP types in casts. 2007-12-20 16:57 ` Daniel Jacobowitz @ 2007-12-20 17:21 ` Thiago Jung Bauermann 0 siblings, 0 replies; 22+ messages in thread From: Thiago Jung Bauermann @ 2007-12-20 17:21 UTC (permalink / raw) To: Daniel Jacobowitz; +Cc: gdb-patches On Thu, 2007-12-20 at 11:54 -0500, Daniel Jacobowitz wrote: > On Thu, Dec 20, 2007 at 02:40:49PM -0200, Thiago Jung Bauermann wrote: > > 2007-12-20 Thiago Jung Bauermann <bauerman@br.ibm.com> > > > > * gdbtypes.c (gdbtypes_post_init): Change names of decimal float types > > to conform to C extension for decimal float. > > * c-lang.c (enum c_primitive_types): Add entries for Decimal Floating > > Point types. > > (enum cplus_primitive_types): Likewise. > > (c_language_arch_info): Add Decimal Floating Point builtin types to > > the primitive_type_vector. > > (cplus_language_arch_info): Likewise. > > This version is OK. Commited. Thanks for your review! -- []'s Thiago Jung Bauermann Software Engineer IBM Linux Technology Center ^ permalink raw reply [flat|nested] 22+ messages in thread
* [patch 2/2] Wrap-up expression support for DFP. 2007-12-20 5:55 [patch 0/2] Complete expression support for Decimal Floating Point Thiago Jung Bauermann 2007-12-20 5:55 ` [patch 1/2] Recognize DFP types in casts Thiago Jung Bauermann @ 2007-12-20 8:03 ` Thiago Jung Bauermann 2007-12-21 16:12 ` Eli Zaretskii 1 sibling, 1 reply; 22+ messages in thread From: Thiago Jung Bauermann @ 2007-12-20 8:03 UTC (permalink / raw) To: gdb-patches [-- Attachment #1: expressions.diff --] [-- Type: text/plain, Size: 39799 bytes --] This patch implements all the missing expression support for decimal floating point that I could find: - +, -, *, /, exp, <, = with operands of same or different sizes of DFP, or a DFP and an integer type; - negation (C's !), unary +; - casting to and from decimal float. If anything else is missing I'll be glad to add it. Notes: - doesn't support conversion of 64-bit integers to decimal float, because of libdecnumber limitation; - error checking in decimal float operations ignore underflow, overflow and divide by zero to imitate binary float implementation; - decimal_from_floating is not very nice because it uses sprintf, but I couldn't think of a better way. Tested with no regressions on Linux/ppc32 and Linux/ppc64. Ok to commit? -- []'s Thiago Jung Bauermann Software Engineer IBM Linux Technology Center gdb/ 2007-12-19 Thiago Jung Bauermann <bauerman@br.ibm.com> * Makefile.in (dfp.o): Depend on expression.h, gdbtypes.h and value.h. (valarith.o): Depend on dfp.h. (valops.o): Likewise. * dfp.c: Include expression.h, gdbtypes.h, value.h and dfp.h. (set_decnumber_context): New function. (decimal_check_errors): Likewise. (decimal_from_number): Likewise. (decimal_to_number): Likewise. (decimal_from_string): Use set_decnumber_context and decimal_check_errors. (decimal_from_integral): New function. (decimal_from_floating): Likewise. (decimal_to_double): Likewise. (promote_decimal): Likewise. (decimal_binop): Likewise. (decimal_is_zero): Likewise. (decimal_compare): Likewise. (decimal_convert): Likewise. * dfp.h (decimal_from_integral): New prototype. (decimal_from_floating): Likewise. (decimal_to_double): Likewise. (decimal_binop): Likewise. (decimal_is_zero): Likewise. (decimal_compare): Likewise. (decimal_convert): Likewise. * eval.c (evaluate_subexp_standard): Remove expect_type argument from call to value_from_decfloat. * valarith.c: Include dfp.h. (value_args_as_decimal): New function. (value_binop): Add if block to handle TYPE_CODE_DECFLOAT values. (value_logical_not): Likewise. (value_equal): Likewise. (value_less): Likewise. (value_pos): Likewise. (value_neg): Formatting fix. * valops.c: Include dfp.h. (value_cast): Add if block to handle TYPE_CODE_DECFLOAT values. * value.c (unpack_long): Add case to handle TYPE_CODE_DECFLOAT. (unpack_double): Add if block to handle TYPE_CODE_DECFLOAT. (value_from_decfloat): Remove expect_type argument. * value.h (value_from_decfloat): Update prototype. gdb/testsuite/ 2007-12-19 Thiago Jung Bauermann <bauerman@br.ibm.com> * gdb.base/dfp-exprs.exp (test_dfp_arithmetic_expressions): Add tests for expressions with decimal float values. (test_dfp_conversions): New function to test casts to and from decimal float types. Call test_dfp_conversions. * gdb.base/dfp-test.c (struct decstruct): Add float4 and double8 elements. (main): Initialize ds.float4 and ds.double8 elements. * gdb.base/dfp-test.exp (d32_set_tests): Fix typo. Adjust expect string to new error message. (d64_set_tests): Likewise. (d128_set_tests): Likewise. Add tests for expressions with decimal float variables. Add tests for conversions to and from decimal float types. Index: src-git/gdb/Makefile.in =================================================================== --- src-git.orig/gdb/Makefile.in 2007-12-19 16:34:35.000000000 -0200 +++ src-git/gdb/Makefile.in 2007-12-19 16:55:05.000000000 -0200 @@ -2046,7 +2046,8 @@ dsrec.o: dsrec.c $(defs_h) $(serial_h) $ dummy-frame.o: dummy-frame.c $(defs_h) $(dummy_frame_h) $(regcache_h) \ $(frame_h) $(inferior_h) $(gdb_assert_h) $(frame_unwind_h) \ $(command_h) $(gdbcmd_h) $(gdb_string_h) -dfp.o: dfp.c $(defs_h) $(dfp_h) $(decimal128_h) $(decimal64_h) $(decimal32_h) +dfp.o: dfp.c $(defs_h) $(expression_h) $(gdbtypes_h) $(value_h) $(dfp_h) \ + $(decimal128_h) $(decimal64_h) $(decimal32_h) dwarf2expr.o: dwarf2expr.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(value_h) \ $(gdbcore_h) $(elf_dwarf2_h) $(dwarf2expr_h) dwarf2-frame.o: dwarf2-frame.c $(defs_h) $(dwarf2expr_h) $(elf_dwarf2_h) \ @@ -2910,12 +2911,12 @@ v850-tdep.o: v850-tdep.c $(defs_h) $(fra $(regcache_h) $(dis_asm_h) $(osabi_h) valarith.o: valarith.c $(defs_h) $(value_h) $(symtab_h) $(gdbtypes_h) \ $(expression_h) $(target_h) $(language_h) $(gdb_string_h) \ - $(doublest_h) $(infcall_h) + $(doublest_h) $(dfp_h) $(infcall_h) valops.o: valops.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(value_h) $(frame_h) \ $(inferior_h) $(gdbcore_h) $(target_h) $(demangle_h) $(language_h) \ $(gdbcmd_h) $(regcache_h) $(cp_abi_h) $(block_h) $(infcall_h) \ $(dictionary_h) $(cp_support_h) $(gdb_string_h) $(gdb_assert_h) \ - $(cp_support_h) $(observer_h) + $(cp_support_h) $(observer_h) $(dfp_h) valprint.o: valprint.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \ $(value_h) $(gdbcore_h) $(gdbcmd_h) $(target_h) $(language_h) \ $(annotate_h) $(valprint_h) $(floatformat_h) $(doublest_h) \ Index: src-git/gdb/dfp.c =================================================================== --- src-git.orig/gdb/dfp.c 2007-12-19 16:34:35.000000000 -0200 +++ src-git/gdb/dfp.c 2007-12-19 19:55:11.000000000 -0200 @@ -18,6 +18,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "defs.h" +#include "expression.h" +#include "gdbtypes.h" +#include "value.h" +#include "dfp.h" /* The order of the following headers is important for making sure decNumber structure is large enough to hold decimal128 digits. */ @@ -50,6 +54,89 @@ match_endianness (const gdb_byte *from, return; } +/* Helper function to get the appropriate libdecnumber context for each size + of decimal float. */ +static void +set_decnumber_context (decContext *ctx, int len) +{ + switch (len) + { + case 4: + decContextDefault (ctx, DEC_INIT_DECIMAL32); + break; + case 8: + decContextDefault (ctx, DEC_INIT_DECIMAL64); + break; + case 16: + decContextDefault (ctx, DEC_INIT_DECIMAL128); + break; + } + + ctx->traps = 0; +} + +/* Check for errors signaled in the decimal context structure. */ +static void +decimal_check_errors (decContext *ctx) +{ + /* An error here could be a division by zero, an overflow, an underflow or + an invalid operation (from the DEC_Errors constant in decContext.h). + Since GDB doesn't complain about division by zero, overflow or underflow + errors for binary floating, we won't complain about them for decimal + floating either. */ + if (ctx->status & DEC_IEEE_854_Invalid_operation) + { + /* Leave only the error bits in the status flags. */ + ctx->status &= DEC_IEEE_854_Invalid_operation; + error (_("Cannot perform operation: %s"), decContextStatusToString (ctx)); + } +} + +/* Helper function to convert from libdecnumber's appropriate representation + for computation to each size of decimal float. */ +static void +decimal_from_number (const decNumber *from, gdb_byte *to, int len) +{ + decContext set; + + set_decnumber_context (&set, len); + + switch (len) + { + case 4: + decimal32FromNumber ((decimal32 *) to, from, &set); + break; + case 8: + decimal64FromNumber ((decimal64 *) to, from, &set); + break; + case 16: + decimal128FromNumber ((decimal128 *) to, from, &set); + break; + } +} + +/* Helper function to convert each size of decimal float to libdecnumber's + appropriate representation for computation. */ +static void +decimal_to_number (const gdb_byte *from, int len, decNumber *to) +{ + switch (len) + { + case 4: + decimal32ToNumber ((decimal32 *) from, to); + break; + case 8: + decimal64ToNumber ((decimal64 *) from, to); + break; + case 16: + decimal128ToNumber ((decimal128 *) from, to); + break; + default: + error (_("Unknown decimal floating point type.\n")); + break; + } +} + /* Convert decimal type to its string representation. LEN is the length of the decimal type, 4 bytes for decimal32, 8 bytes for decimal64 and 16 bytes for decimal128. */ @@ -59,6 +146,7 @@ decimal_to_string (const gdb_byte *decby gdb_byte dec[16]; match_endianness (decbytes, len, dec); + switch (len) { case 4: @@ -85,21 +173,17 @@ decimal_from_string (gdb_byte *decbytes, decContext set; gdb_byte dec[16]; + set_decnumber_context (&set, len); + switch (len) { case 4: - decContextDefault (&set, DEC_INIT_DECIMAL32); - set.traps = 0; decimal32FromString ((decimal32 *) dec, string, &set); break; case 8: - decContextDefault (&set, DEC_INIT_DECIMAL64); - set.traps = 0; decimal64FromString ((decimal64 *) dec, string, &set); break; case 16: - decContextDefault (&set, DEC_INIT_DECIMAL128); - set.traps = 0; decimal128FromString ((decimal128 *) dec, string, &set); break; default: @@ -109,5 +193,206 @@ decimal_from_string (gdb_byte *decbytes, match_endianness (dec, len, decbytes); + /* Check for errors in the DFP operation. */ + decimal_check_errors (&set); + return 1; } + +/* Converts a value of an integral type to a decimal float of + specified LEN bytes. */ +void +decimal_from_integral (struct value *from, gdb_byte *to, int len) +{ + LONGEST l; + gdb_byte dec[16]; + decNumber number; + struct type *type; + + type = check_typedef (value_type (from)); + + if (TYPE_LENGTH (type) > 4) + /* libdecnumber can convert only 32-bit integers. */ + error (_("Conversion of large integer to a decimal floating type is not supported.")); + + l = value_as_long (from); + + if (TYPE_UNSIGNED (type)) + decNumberFromUInt32 (&number, (unsigned int) l); + else + decNumberFromInt32 (&number, (int) l); + + decimal_from_number (&number, dec, len); + match_endianness (dec, len, to); +} + +/* Converts a value of a float type to a decimal float of + specified LEN bytes. + + This is an ugly way to do the conversion, but libdecnumber does + not offer a direct way to do it. */ +void +decimal_from_floating (struct value *from, gdb_byte *to, int len) +{ + /* The size of this buffer is a conservative guess: assumes an 128-bit + long double could have 40 decimal digits, plus 4 for exponent, plus + 3 for mantissa and exponent signs and 'E', plus '\0'. */ + char buffer[48]; + + /* We cannot use snprintf here because it is defined only in C99. + We have to assume buffer size is sufficient. */ + sprintf (buffer, "%Lf", value_as_double (from)); + decimal_from_string (to, len, buffer); +} + +/* Converts a decimal float of LEN bytes to a double value. */ +DOUBLEST +decimal_to_double (const gdb_byte *from, int len) +{ + char buffer[MAX_DECIMAL_STRING]; + + /* This is an ugly way to do the conversion, but libdecnumber does + not offer a direct way to do it. */ + decimal_to_string (from, len, buffer); + return atof (buffer); +} + +/* Check if operands have the same size and convert them to the + biggest of the two if necessary. */ +static int +promote_decimal (gdb_byte *x, int len_x, gdb_byte *y, int len_y) +{ + int len_result; + decNumber number; + + if (len_x < len_y) + { + decimal_to_number (x, len_x, &number); + decimal_from_number (&number, x, len_y); + len_result = len_y; + } + else if (len_x > len_y) + { + decimal_to_number (y, len_y, &number); + decimal_from_number (&number, y, len_x); + len_result = len_x; + } + else + len_result = len_x; + + return len_result; +} + +/* Perform operation OP with operands X and Y and store value in RESULT. + If LEN_X and LEN_Y are not equal, RESULT will have the size of the biggest + of the two, and LEN_RESULT will be set accordingly. */ +void +decimal_binop (enum exp_opcode op, const gdb_byte *x, int len_x, + const gdb_byte *y, int len_y, gdb_byte *result, int *len_result) +{ + decContext set; + decNumber number1, number2, number3; + gdb_byte dec1[16], dec2[16], dec3[16]; + + match_endianness (x, len_x, dec1); + match_endianness (y, len_y, dec2); + + *len_result = promote_decimal (dec1, len_x, dec2, len_y); + + /* Both operands are of size *len_result from now on. */ + + decimal_to_number (dec1, *len_result, &number1); + decimal_to_number (dec2, *len_result, &number2); + + set_decnumber_context (&set, *len_result); + + switch (op) + { + case BINOP_ADD: + decNumberAdd (&number3, &number1, &number2, &set); + break; + case BINOP_SUB: + decNumberSubtract (&number3, &number1, &number2, &set); + break; + case BINOP_MUL: + decNumberMultiply (&number3, &number1, &number2, &set); + break; + case BINOP_DIV: + decNumberDivide (&number3, &number1, &number2, &set); + break; + case BINOP_EXP: + decNumberPower (&number3, &number1, &number2, &set); + break; + default: + error (_("Unknown decimal floating point operation.")); + break; + } + + /* Check for errors in the DFP operation. */ + decimal_check_errors (&set); + + decimal_from_number (&number3, dec3, *len_result); + + match_endianness (dec3, *len_result, result); +} + +/* Returns true if X (which is LEN bytes wide) is the number zero. */ +int +decimal_is_zero (const gdb_byte *x, int len) +{ + decNumber number; + gdb_byte dec[16]; + + match_endianness (x, len, dec); + decimal_to_number (dec, len, &number); + + return decNumberIsZero (&number); +} + +/* Compares two numbers numerically. If X is less than Y then the return value + will be -1. If they are equal, then the return value will be 0. If X is + greater than the Y then the return value will be 1. */ +int +decimal_compare (const gdb_byte *x, int len_x, const gdb_byte *y, int len_y) +{ + decNumber number1, number2, result; + decContext set; + gdb_byte dec1[16], dec2[16]; + int len_result; + + match_endianness (x, len_x, dec1); + match_endianness (y, len_y, dec2); + + len_result = promote_decimal (dec1, len_x, dec2, len_y); + + decimal_to_number (dec1, len_result, &number1); + decimal_to_number (dec2, len_result, &number2); + + set_decnumber_context (&set, len_result); + + decNumberCompare (&result, &number1, &number2, &set); + + /* Check for errors in the DFP operation. */ + decimal_check_errors (&set); + + if (decNumberIsNaN (&result)) + error (_("Comparison with an invalid number (NaN).")); + else if (decNumberIsZero (&result)) + return 0; + else if (decNumberIsNegative (&result)) + return -1; + else + return 1; +} + +/* Convert a decimal value from a decimal type with LEN_FROM bytes to a + decimal type with LEN_TO bytes. */ +void +decimal_convert (const gdb_byte *from, int len_from, gdb_byte *to, + int len_to) +{ + decNumber number; + + decimal_to_number (from, len_from, &number); + decimal_from_number (&number, to, len_to); +} Index: src-git/gdb/dfp.h =================================================================== --- src-git.orig/gdb/dfp.h 2007-12-19 16:34:35.000000000 -0200 +++ src-git/gdb/dfp.h 2007-12-19 19:54:58.000000000 -0200 @@ -31,5 +31,14 @@ extern void decimal_to_string (const gdb_byte *, int, char *); extern int decimal_from_string (gdb_byte *, int, const char *); +extern void decimal_from_integral (struct value *from, gdb_byte *to, int len); +extern void decimal_from_floating (struct value *from, gdb_byte *to, int len); +extern DOUBLEST decimal_to_double (const gdb_byte *from, int len); +extern void decimal_binop (enum exp_opcode, const gdb_byte *, int, + const gdb_byte *, int, gdb_byte *, int *); +extern int decimal_is_zero (const gdb_byte *x, int len); +extern int decimal_compare (const gdb_byte *x, int len_x, const gdb_byte *y, int len_y); +extern void decimal_convert (const gdb_byte *from, int len_from, gdb_byte *to, + int len_to); #endif Index: src-git/gdb/eval.c =================================================================== --- src-git.orig/gdb/eval.c 2007-12-19 16:34:35.000000000 -0200 +++ src-git/gdb/eval.c 2007-12-19 16:55:05.000000000 -0200 @@ -458,8 +458,8 @@ evaluate_subexp_standard (struct type *e case OP_DECFLOAT: (*pos) += 3; - return value_from_decfloat (expect_type, exp->elts[pc + 1].type, - exp->elts[pc + 2].decfloatconst); + return value_from_decfloat (exp->elts[pc + 1].type, + exp->elts[pc + 2].decfloatconst); case OP_VAR_VALUE: (*pos) += 3; Index: src-git/gdb/testsuite/gdb.base/dfp-exprs.exp =================================================================== --- src-git.orig/gdb/testsuite/gdb.base/dfp-exprs.exp 2007-12-19 16:34:35.000000000 -0200 +++ src-git/gdb/testsuite/gdb.base/dfp-exprs.exp 2007-12-19 16:55:05.000000000 -0200 @@ -74,14 +74,102 @@ proc test_dfp_literals_accepted {} { proc test_dfp_arithmetic_expressions {} { -# Arithmetic operations for DFP types are not yet implemented in GDB. -# These tests are to verify that they will generate expected error messages. + # _Decimal32 operands. + gdb_test "p 1.4df + 1.2df" " = 2.6" + gdb_test "p 1.4df - 1.2df" " = 0.2" + gdb_test "p 1.4df * 1.2df" " = 1.68" + gdb_test "p 1.4df / 1.2df" " = 1.166667" + + # _Decimal64 operands. + gdb_test "p 1.4dd + 1.2dd" " = 2.6" + gdb_test "p 1.4dd - 1.2dd" " = 0.2" + gdb_test "p 1.4dd * 1.2dd" " = 1.68" + gdb_test "p 1.4dd / 1.2dd" " = 1.166666666666667" + + # _Decimal128 operands. + gdb_test "p 1.4dl + 1.2dl" " = 2.6" + gdb_test "p 1.4dl - 1.2dl" " = 0.2" + gdb_test "p 1.4dl * 1.2dl" " = 1.68" + gdb_test "p 1.4dl / 1.2dl" " = 1.166666666666666666666666666666667" + + # Test type of operation result. + gdb_test "ptype 2.df + 2.df" "= _Decimal32" + gdb_test "ptype 2.dd + 2.dd" "= _Decimal64" + gdb_test "ptype 2.dl + 2.dl" "= _Decimal128" + + # Mixture of different _Decimal sizes. + gdb_test "p 2.1df + 2.7dd" "= 4.8" + gdb_test "p 2.1dd + 2.7df" "= 4.8" + gdb_test "p 2.6df + 2.7dl" "= 5.3" + gdb_test "p 2.6dl + 2.7df" "= 5.3" + gdb_test "p 2.3dd + 2.2dl" "= 4.5" + gdb_test "p 2.3dl + 2.2dd" "= 4.5" + gdb_test "ptype 2.df + 2.dd" "= _Decimal64" + gdb_test "ptype 2.df + 2.dl" "= _Decimal128" + gdb_test "ptype 2.dd + 2.dl" "= _Decimal128" + + # Mixture of Decimal and integral operands + gdb_test "p 1.2df + 1" " = 2.2" + gdb_test "p 2 + 1.7dd" " = 3.7" + gdb_test "p 3 + 2.1dl" " = 5.1" + gdb_test "ptype 1.2df + 1" " = _Decimal32" + gdb_test "ptype 2 + 1.7dd" " = _Decimal64" + gdb_test "ptype 3 + 2.1dl" " = _Decimal128" + + # Reject operation with integral larger than 32-bits + gdb_test "p 1.2df + 2ll" "Conversion of large integer to a decimal floating type is not supported." + + # Reject operation with DFP and Binary FP + gdb_test "p 1.2df + 1.2f" "Mixing decimal floating types with other floating types is not allowed." + + # Test other operations with DFP operands + gdb_test "p !0.df" " = 1" + gdb_test "p !0.dd" " = 1" + gdb_test "p !0.dl" " = 1" + gdb_test "p !0.5df" " = 0" + gdb_test "p !0.5dd" " = 0" + gdb_test "p !0.5dl" " = 0" + + gdb_test "p 1.2df == 1.2df" " = 1" + gdb_test "p 1.2df == 1.2dd" " = 1" + gdb_test "p 1.2df == 1.2dl" " = 1" + gdb_test "p 1.2dd == 1.2df" " = 1" + gdb_test "p 1.2dd == 1.2dl" " = 1" + gdb_test "p 1.2dl == 1.2df" " = 1" + gdb_test "p 1.2dl == 1.2dd" " = 1" + gdb_test "p 1.2df == 1.3df" " = 0" + gdb_test "p 1.2df == 1.3dd" " = 0" + gdb_test "p 1.2df == 1.3dl" " = 0" + gdb_test "p 1.2dd == 1.3df" " = 0" + gdb_test "p 1.2dd == 1.3dl" " = 0" + gdb_test "p 1.2dl == 1.3df" " = 0" + gdb_test "p 1.2dl == 1.3dd" " = 0" + + gdb_test "p +1.2df" " = 1.2" + gdb_test "p +1.2dd" " = 1.2" + gdb_test "p +1.2dl" " = 1.2" + + gdb_test "p 1.2df < 1.3df" " = 1" + gdb_test "p 1.2df < 1.3dd" " = 1" + gdb_test "p 1.2dl < 1.3df" " = 1" + gdb_test "p 1.2dd < 1.3dd" " = 1" + gdb_test "p 1.2dd < 1.3dl" " = 1" + gdb_test "p 1.2dl < 1.3dl" " = 1" + gdb_test "p 1.2dl < 1.3df" " = 1" + gdb_test "p 1.2df > 1" " = 1" + gdb_test "p 1.2dl > 2" " = 0" + gdb_test "p 2 > 1.2dd" " = 1" + gdb_test "p 2 > 3.1dl" " = 0" +} - gdb_test "p 1.4df + 1.2df" "Argument to arithmetic operation not a number or boolean.*" - gdb_test "p 1.4df - 1.2df" ".*Argument to arithmetic operation not a number or boolean.*" - gdb_test "p 1.4df * 1.2df" "Argument to arithmetic operation not a number or boolean.*" - gdb_test "p 1.4df / 1.2df" "Argument to arithmetic operation not a number or boolean.*" +proc test_dfp_conversions {} { + # Test cast to and from DFP values, and between DFPs of different sizes + gdb_test "p (float) -0.1df" " = -0.099999994" + gdb_test "p (int) 8.3dd" " = 8" + gdb_test "p (_Decimal64) 3.1" " = 3.100000" + gdb_test "p (_Decimal128) 3.7df" " = 3.7" + gdb_test "p (_Decimal32) 4" " = 4" } # Start with a fresh gdb. @@ -92,3 +180,4 @@ gdb_reinitialize_dir $srcdir/$subdir test_dfp_literals_accepted test_dfp_arithmetic_expressions +test_dfp_conversions Index: src-git/gdb/testsuite/gdb.base/dfp-test.c =================================================================== --- src-git.orig/gdb/testsuite/gdb.base/dfp-test.c 2007-12-19 16:34:35.000000000 -0200 +++ src-git/gdb/testsuite/gdb.base/dfp-test.c 2007-12-19 16:55:05.000000000 -0200 @@ -26,6 +26,8 @@ struct decstruct { int int4; long long8; + float float4; + double double8; _Decimal32 dec32; _Decimal64 dec64; _Decimal128 dec128; @@ -85,6 +87,8 @@ int main() ds.int4 = 1; ds.long8 = 2; + ds.float4 = 3.1; + ds.double8 = 4.2; ds.dec32 = 1.2345df; ds.dec64 = 1.2345dd; ds.dec128 = 1.2345dl; Index: src-git/gdb/testsuite/gdb.base/dfp-test.exp =================================================================== --- src-git.orig/gdb/testsuite/gdb.base/dfp-test.exp 2007-12-19 16:34:35.000000000 -0200 +++ src-git/gdb/testsuite/gdb.base/dfp-test.exp 2007-12-20 01:39:19.000000000 -0200 @@ -18,6 +18,53 @@ # This file is part of the gdb testsuite. It is intended to test that # gdb could correctly handle decimal floating point introduced in IEEE 754R. +if $tracelevel then { + strace $tracelevel +} + +set testfile "dfp-test" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +# Try to compile the test case. If we can't, assume the +# toolchain does not yet provide DFP support and bail out. +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {quiet debug}] != "" } { + verbose "Skipping DFP tests." + 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 +} + +# Detect the size of the target's basic types (from gdb.base/long_long.exp). + +proc get_valueof { fmt exp default } { + global gdb_prompt + send_gdb "print${fmt} ${exp}\n" + gdb_expect { + -re "\\$\[0-9\]* = (\[-\]*\[0-9\]*).*$gdb_prompt $" { + set val $expect_out(1,string) + } + timeout { + set val ${default} + } + } + return ${val} +} + +proc get_sizeof { type default } { + return [get_valueof "/d" "sizeof (${type})" $default] +} + +set sizeof_long [get_sizeof "long" 4] + proc d32_set_tests {} { gdb_test "p d32=123.45df" " = 123.45" @@ -43,10 +90,10 @@ proc d32_set_tests {} { 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=12345.df" " = 12345" "12345. is a 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)" + gdb_test "p d32=1.23Edf" ".*Conversion syntax.*" "1.23E is an invalid number" + gdb_test "p d32=1.23E45Adf" ".*Conversion syntax.*" "1.23E45A is an invalid number" } proc d64_set_tests {} { @@ -75,8 +122,8 @@ proc d64_set_tests {} { # 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)" + gdb_test "p d64=1.23Edd" ".*Conversion syntax.*" "1.23E is an invalid number" + gdb_test "p d64=1.23E45Add" ".*Conversion syntax.*" "1.23E45A is an invalid number" } proc d128_set_tests {} { @@ -104,33 +151,8 @@ proc d128_set_tests {} { # 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} -# Try to compile the test case. If we can't, assume the -# toolchain does not yet provide DFP support and bail out. -if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {quiet debug}] != "" } { - verbose "Skipping DFP tests." - 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 + gdb_test "p d128=1.23Edl" ".*Conversion syntax.*" "1.23E is an invalid number" + gdb_test "p d128=1.23E45Adl" ".*Conversion syntax.*" "1.23E45A is an invalid number" } # Different tests on 32-bits decimal floating point, including the printing @@ -237,6 +259,57 @@ gdb_test "print ds.dec32" " = 1.2345" gdb_test "print ds.dec64" " = 1.2345" gdb_test "print ds.dec128" " = 1.2345" +# Test expressions with DFP variables. + +gdb_test "print d32 + ds.dec32" " = 1.3345" +gdb_test "print d64 + ds.dec64" " = 1.3345" +gdb_test "print d128 + ds.dec128" " = 1.3345" + +# Test conversion between different _Decimal sizes. + +gdb_test "ptype d64 + ds.dec32" " = volatile _Decimal64" +gdb_test "ptype d128 + ds.dec32" " = volatile _Decimal128" +gdb_test "ptype d128 + ds.dec64" " = volatile _Decimal128" + +# Mixture of Decimal and integral operands +gdb_test "p d32 + 1" " = 1.1" +gdb_test "p 2 + d64" " = 2.1" +gdb_test "p ds.int4 + d128" " = 1.1" +gdb_test "ptype d32 + 1" " = volatile _Decimal32" +gdb_test "ptype ds.int4 + d128" " = volatile _Decimal128" + +# Test other operations with DFP operands +gdb_test "p !d32" " = 0" +gdb_test "p !d64" " = 0" +gdb_test "p !d128" " = 0" +gdb_test "p +d32" " = 0.1" +gdb_test "p +d64" " = 0.1" +gdb_test "p +d128" " = 0.1" +gdb_test "p d64 == d128" " = 1" +gdb_test "p d128 == ds.dec32" " = 0" +gdb_test "p d128 == d32" " = 1" +gdb_test "p ds.dec32 == ds.dec64" " = 1" +gdb_test "p d32 < ds.dec32" " = 1" +gdb_test "p d64 < ds.dec64" " = 1" +gdb_test "p d128 < ds.dec128" " = 1" +gdb_test "p ds.dec32 < d32" " = 0" +gdb_test "p d64 > ds.dec64" " = 0" +gdb_test "p ds.dec128 > d128 " " = 1" +gdb_test "p d32 < ds.int4" " = 1" +gdb_test "p ds.int4 > d32" " = 1" +gdb_test "p ds.dec32 < ds.int4" " = 0" +gdb_test "p ds.int4 > ds.dec64" " = 0" +gdb_test "p ds.dec128 > ds.int4" " = 1" + +# Reject operation with integral larger than 32-bits +if { ${sizeof_long} > 4 } { + gdb_test "p d32 + ds.long8" "Conversion of large integer to a decimal floating type is not supported." +} + +# Reject operation with DFP and Binary FP +gdb_test "p d64 + ds.float4" "Mixing decimal floating types with other floating types is not allowed." +gdb_test "p ds.double8 + d128" "Mixing decimal floating types with other floating types is not allowed." + # The following tests are intended to verify that gdb can handle "d1=d2" # and "d1=-d2" correctly. @@ -246,3 +319,12 @@ 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" + +# Test cast to and from DFP values + +gdb_test "print ds.double8 = ds.dec64" " = -0.10000000000000001" +gdb_test "print ds.dec64 = ds.float4" " = 3.100000" +gdb_test "print ds.dec128 = -ds.double8" " = 0.100000" +gdb_test "print ds.dec128 = ds.dec32" " = -0.1" +gdb_test "print ds.dec32 = ds.int4" " = 1" +gdb_test "print ds.int4 = 7.3dl" " = 7" Index: src-git/gdb/valarith.c =================================================================== --- src-git.orig/gdb/valarith.c 2007-12-19 16:34:35.000000000 -0200 +++ src-git/gdb/valarith.c 2007-12-19 16:55:05.000000000 -0200 @@ -28,6 +28,7 @@ #include "language.h" #include "gdb_string.h" #include "doublest.h" +#include "dfp.h" #include <math.h> #include "infcall.h" @@ -741,6 +742,60 @@ value_concat (struct value *arg1, struct } \f +/* Obtain decimal value of arguments for binary operation, converting from + other types if one of them is not decimal floating point. */ +static void +value_args_as_decimal (struct value *arg1, struct value *arg2, + gdb_byte *x, int *len_x, gdb_byte *y, int *len_y) +{ + struct type *type1, *type2; + + type1 = check_typedef (value_type (arg1)); + type2 = check_typedef (value_type (arg2)); + + /* At least one of the arguments must be of decimal float type. */ + gdb_assert (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT + || TYPE_CODE (type2) == TYPE_CODE_DECFLOAT); + + if (TYPE_CODE (type1) == TYPE_CODE_FLT + || TYPE_CODE (type2) == TYPE_CODE_FLT) + /* The DFP extension to the C language does not allow mixing of + * decimal float types with other float types in expressions + * (see WDTR 24732, page 12). */ + error (_("Mixing decimal floating types with other floating types is not allowed.")); + + /* Obtain decimal value of arg1, converting from other types + if necessary. */ + + if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT) + { + *len_x = TYPE_LENGTH (type1); + memcpy (x, value_contents (arg1), *len_x); + } + else if (is_integral_type (type1)) + { + *len_x = TYPE_LENGTH (type2); + decimal_from_integral (arg1, x, *len_x); + } + else + error (_("Don't know how to convert to decimal floating type.")); + + /* Obtain decimal value of arg2, converting from other types + if necessary. */ + + if (TYPE_CODE (type2) == TYPE_CODE_DECFLOAT) + { + *len_y = TYPE_LENGTH (type2); + memcpy (y, value_contents (arg2), *len_y); + } + else if (is_integral_type (type2)) + { + *len_y = TYPE_LENGTH (type1); + decimal_from_integral (arg2, y, *len_y); + } + else + error (_("Don't know how to convert to decimal floating type.")); +} /* Perform a binary operation on two operands which have reasonable representations as integers or floats. This includes booleans, @@ -759,14 +814,55 @@ value_binop (struct value *arg1, struct type1 = check_typedef (value_type (arg1)); type2 = check_typedef (value_type (arg2)); - if ((TYPE_CODE (type1) != TYPE_CODE_FLT && !is_integral_type (type1)) + if ((TYPE_CODE (type1) != TYPE_CODE_FLT + && TYPE_CODE (type1) != TYPE_CODE_DECFLOAT && !is_integral_type (type1)) || - (TYPE_CODE (type2) != TYPE_CODE_FLT && !is_integral_type (type2))) + (TYPE_CODE (type2) != TYPE_CODE_FLT + && TYPE_CODE (type2) != TYPE_CODE_DECFLOAT && !is_integral_type (type2))) error (_("Argument to arithmetic operation not a number or boolean.")); - if (TYPE_CODE (type1) == TYPE_CODE_FLT + if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT || - TYPE_CODE (type2) == TYPE_CODE_FLT) + TYPE_CODE (type2) == TYPE_CODE_DECFLOAT) + { + struct type *v_type; + int len_v1, len_v2, len_v; + gdb_byte v1[16], v2[16]; + gdb_byte v[16]; + + value_args_as_decimal (arg1, arg2, v1, &len_v1, v2, &len_v2); + + switch (op) + { + case BINOP_ADD: + case BINOP_SUB: + case BINOP_MUL: + case BINOP_DIV: + case BINOP_EXP: + decimal_binop (op, v1, len_v1, v2, len_v2, v, &len_v); + break; + + default: + error (_("Integer-only operation on floating point number.")); + } + + if (TYPE_CODE (type1) != TYPE_CODE_DECFLOAT) + /* If arg1 is not a decimal float, the type of the result is the type + of the decimal float argument, arg2. */ + v_type = type2; + else if (TYPE_CODE (type2) != TYPE_CODE_DECFLOAT) + /* Same logic, for the case where arg2 is not a decimal float. */ + v_type = type1; + else + /* len_v is equal either to len_v1 or to len_v2. the type of the + result is the type of the argument with the same length as v. */ + v_type = (len_v == len_v1)? type1 : type2; + + val = value_from_decfloat (v_type, v); + } + else if (TYPE_CODE (type1) == TYPE_CODE_FLT + || + TYPE_CODE (type2) == TYPE_CODE_FLT) { /* FIXME-if-picky-about-floating-accuracy: Should be doing this in target format. real.c in GCC probably has the necessary @@ -1177,6 +1273,8 @@ value_logical_not (struct value *arg1) if (TYPE_CODE (type1) == TYPE_CODE_FLT) return 0 == value_as_double (arg1); + else if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT) + return decimal_is_zero (value_contents (arg1), TYPE_LENGTH (type1)); len = TYPE_LENGTH (type1); p = value_contents (arg1); @@ -1255,6 +1353,16 @@ value_equal (struct value *arg1, struct DOUBLEST d = value_as_double (arg1); return d == value_as_double (arg2); } + else if ((code1 == TYPE_CODE_DECFLOAT || is_int1) + && (code2 == TYPE_CODE_DECFLOAT || is_int2)) + { + gdb_byte v1[16], v2[16]; + int len_v1, len_v2; + + value_args_as_decimal (arg1, arg2, v1, &len_v1, v2, &len_v2); + + return decimal_compare (v1, len_v1, v2, len_v2) == 0; + } /* FIXME: Need to promote to either CORE_ADDR or LONGEST, whichever is bigger. */ @@ -1319,6 +1427,16 @@ value_less (struct value *arg1, struct v DOUBLEST d = value_as_double (arg1); return d < value_as_double (arg2); } + else if ((code1 == TYPE_CODE_DECFLOAT || is_int1) + && (code2 == TYPE_CODE_DECFLOAT || is_int2)) + { + gdb_byte v1[16], v2[16]; + int len_v1, len_v2; + + value_args_as_decimal (arg1, arg2, v1, &len_v1, v2, &len_v2); + + return decimal_compare (v1, len_v1, v2, len_v2) == -1; + } else if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR) return value_as_address (arg1) < value_as_address (arg2); @@ -1350,6 +1468,8 @@ value_pos (struct value *arg1) if (TYPE_CODE (type) == TYPE_CODE_FLT) return value_from_double (type, value_as_double (arg1)); + else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT) + return value_from_decfloat (type, value_contents (arg1)); else if (is_integral_type (type)) { /* Perform integral promotion for ANSI C/C++. FIXME: What about @@ -1382,7 +1502,7 @@ value_neg (struct value *arg1) int len = TYPE_LENGTH (type); gdb_byte decbytes[16]; /* a decfloat is at most 128 bits long */ - memcpy(decbytes, value_contents(arg1), len); + memcpy (decbytes, value_contents (arg1), len); if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_LITTLE) decbytes[len-1] = decbytes[len - 1] | 0x80; Index: src-git/gdb/valops.c =================================================================== --- src-git.orig/gdb/valops.c 2007-12-19 16:34:35.000000000 -0200 +++ src-git/gdb/valops.c 2007-12-19 19:54:50.000000000 -0200 @@ -36,6 +36,7 @@ #include "infcall.h" #include "dictionary.h" #include "cp-support.h" +#include "dfp.h" #include <errno.h> #include "gdb_string.h" @@ -338,7 +339,8 @@ value_cast (struct type *type, struct va code2 = TYPE_CODE_INT; scalar = (code2 == TYPE_CODE_INT || code2 == TYPE_CODE_FLT - || code2 == TYPE_CODE_ENUM || code2 == TYPE_CODE_RANGE); + || code2 == TYPE_CODE_DECFLOAT || code2 == TYPE_CODE_ENUM + || code2 == TYPE_CODE_RANGE); if (code1 == TYPE_CODE_STRUCT && code2 == TYPE_CODE_STRUCT @@ -357,6 +359,22 @@ value_cast (struct type *type, struct va } if (code1 == TYPE_CODE_FLT && scalar) return value_from_double (type, value_as_double (arg2)); + else if (code1 == TYPE_CODE_DECFLOAT && scalar) + { + int dec_len = TYPE_LENGTH (type); + gdb_byte dec[16]; + + if (code2 == TYPE_CODE_FLT) + decimal_from_floating (arg2, dec, dec_len); + else if (code2 == TYPE_CODE_DECFLOAT) + decimal_convert (value_contents (arg2), TYPE_LENGTH (type2), + dec, dec_len); + else + /* The only option left is an integral type. */ + decimal_from_integral (arg2, dec, dec_len); + + return value_from_decfloat (type, dec); + } else if ((code1 == TYPE_CODE_INT || code1 == TYPE_CODE_ENUM || code1 == TYPE_CODE_RANGE) && (scalar || code2 == TYPE_CODE_PTR Index: src-git/gdb/value.c =================================================================== --- src-git.orig/gdb/value.c 2007-12-19 16:34:35.000000000 -0200 +++ src-git/gdb/value.c 2007-12-19 17:57:08.000000000 -0200 @@ -982,6 +982,7 @@ value_as_double (struct value *val) error (_("Invalid floating value found in program.")); return foo; } + /* Extract a value as a C pointer. Does not deallocate the value. Note that val's type may not actually be a pointer; value_as_long handles all the cases. */ @@ -1127,6 +1128,11 @@ unpack_long (struct type *type, const gd case TYPE_CODE_FLT: return extract_typed_floating (valaddr, type); + case TYPE_CODE_DECFLOAT: + /* libdecnumber has a function to convert from decimal to integer, but + it doesn't work when the decimal number has a fractional part. */ + return decimal_to_double (valaddr, len); + case TYPE_CODE_PTR: case TYPE_CODE_REF: /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure @@ -1184,6 +1190,8 @@ unpack_double (struct type *type, const return extract_typed_floating (valaddr, type); } + else if (code == TYPE_CODE_DECFLOAT) + return decimal_to_double (valaddr, len); else if (nosign) { /* Unsigned -- be sure we compensate for signed LONGEST. */ @@ -1643,23 +1651,12 @@ value_from_double (struct type *type, DO } struct value * -value_from_decfloat (struct type *expect_type, struct type *type, - gdb_byte decbytes[16]) +value_from_decfloat (struct type *type, const gdb_byte *dec) { struct value *val = allocate_value (type); - int len = TYPE_LENGTH (type); - if (expect_type) - { - int expect_len = TYPE_LENGTH (expect_type); - char decstr[MAX_DECIMAL_STRING]; - int real_len; - - decimal_to_string (decbytes, len, decstr); - decimal_from_string (decbytes, expect_len, decstr); - } + memcpy (value_contents_raw (val), dec, TYPE_LENGTH (type)); - memcpy (value_contents_raw (val), decbytes, len); return val; } Index: src-git/gdb/value.h =================================================================== --- src-git.orig/gdb/value.h 2007-12-19 16:34:35.000000000 -0200 +++ src-git/gdb/value.h 2007-12-19 16:55:05.000000000 -0200 @@ -280,9 +280,8 @@ extern void pack_long (gdb_byte *buf, st extern struct value *value_from_longest (struct type *type, LONGEST num); extern struct value *value_from_pointer (struct type *type, CORE_ADDR addr); extern struct value *value_from_double (struct type *type, DOUBLEST num); -extern struct value *value_from_decfloat (struct type *expect_type, - struct type *type, - gdb_byte decbytes[16]); +extern struct value *value_from_decfloat (struct type *type, + const gdb_byte *decbytes); extern struct value *value_from_string (char *string); extern struct value *value_at (struct type *type, CORE_ADDR addr); -- -- []'s Thiago Jung Bauermann Software Engineer IBM Linux Technology Center ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [patch 2/2] Wrap-up expression support for DFP. 2007-12-20 8:03 ` [patch 2/2] Wrap-up expression support for DFP Thiago Jung Bauermann @ 2007-12-21 16:12 ` Eli Zaretskii 2007-12-21 16:30 ` Andreas Schwab ` (2 more replies) 0 siblings, 3 replies; 22+ messages in thread From: Eli Zaretskii @ 2007-12-21 16:12 UTC (permalink / raw) To: Thiago Jung Bauermann; +Cc: gdb-patches > Date: Thu, 20 Dec 2007 03:49:28 -0200 > From: Thiago Jung Bauermann <bauerman@br.ibm.com> > > - doesn't support conversion of 64-bit integers to decimal float, > because of libdecnumber limitation; > - error checking in decimal float operations ignore underflow, overflow > and divide by zero to imitate binary float implementation; These limitations should be documented in the manual, I think: they will affect GDB users, right? > - decimal_from_floating is not very nice because it uses sprintf, but > I couldn't think of a better way. Yuck! I don't know anything about libdecnumber, but is there _really_ no other way? What about producing the two parts before and after the decimal point as integers, then combine them with arithmetic operations? > +static void > +set_decnumber_context (decContext *ctx, int len) > +{ > + switch (len) > + { > + case 4: > + decContextDefault (ctx, DEC_INIT_DECIMAL32); > + break; > + case 8: > + decContextDefault (ctx, DEC_INIT_DECIMAL64); > + break; > + case 16: > + decContextDefault (ctx, DEC_INIT_DECIMAL128); > + break; > + } I don't think our coding style includes mixed-case symbols. Are these library functions? > +void > +decimal_from_floating (struct value *from, gdb_byte *to, int len) > +{ > + /* The size of this buffer is a conservative guess: assumes an 128-bit > + long double could have 40 decimal digits, plus 4 for exponent, plus > + 3 for mantissa and exponent signs and 'E', plus '\0'. */ > + char buffer[48]; Are the sizes of the exponent, mantissa, etc. available as parameters from libdecnumber? If so, it would be better to use them explicitly in allocating buffer[] off the stack (e.g., with alloca). That way, if your assumptions will ever become incorrect, the code will adapt automatically. > + /* We cannot use snprintf here because it is defined only in C99. We have portable substitutes for snprintf, I think. Take a look at libiberty, for example. > + sprintf (buffer, "%Lf", value_as_double (from)); If we must live with going through the printed representation, at the very least please use "%.30Lf", so as not to lose precision due to the default number of significant digits produced under "%Lf", arbitrarily chosen by the libc implementation. > + /* This is an ugly way to do the conversion, but libdecnumber does > + not offer a direct way to do it. */ > + decimal_to_string (from, len, buffer); > + return atof (buffer); Isn't strtold better here? ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [patch 2/2] Wrap-up expression support for DFP. 2007-12-21 16:12 ` Eli Zaretskii @ 2007-12-21 16:30 ` Andreas Schwab 2007-12-21 16:38 ` Eli Zaretskii 2007-12-27 7:40 ` Thiago Jung Bauermann 2007-12-28 6:16 ` Thiago Jung Bauermann 2 siblings, 1 reply; 22+ messages in thread From: Andreas Schwab @ 2007-12-21 16:30 UTC (permalink / raw) To: Eli Zaretskii; +Cc: Thiago Jung Bauermann, gdb-patches Eli Zaretskii <eliz@gnu.org> writes: >> Date: Thu, 20 Dec 2007 03:49:28 -0200 >> From: Thiago Jung Bauermann <bauerman@br.ibm.com> >> >> + sprintf (buffer, "%Lf", value_as_double (from)); > > If we must live with going through the printed representation, at the > very least please use "%.30Lf", so as not to lose precision due to the > default number of significant digits produced under "%Lf", arbitrarily > chosen by the libc implementation. Shouldn't that be better "%.30Lg"? 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] 22+ messages in thread
* Re: [patch 2/2] Wrap-up expression support for DFP. 2007-12-21 16:30 ` Andreas Schwab @ 2007-12-21 16:38 ` Eli Zaretskii 0 siblings, 0 replies; 22+ messages in thread From: Eli Zaretskii @ 2007-12-21 16:38 UTC (permalink / raw) To: Andreas Schwab; +Cc: bauerman, gdb-patches > From: Andreas Schwab <schwab@suse.de> > Cc: Thiago Jung Bauermann <bauerman@br.ibm.com>, > gdb-patches@sourceware.org > Date: Fri, 21 Dec 2007 17:19:17 +0100 > > Shouldn't that be better "%.30Lg"? Yes, that's what I meant, but forgot to change f into g. Thanks for catching it. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [patch 2/2] Wrap-up expression support for DFP. 2007-12-21 16:12 ` Eli Zaretskii 2007-12-21 16:30 ` Andreas Schwab @ 2007-12-27 7:40 ` Thiago Jung Bauermann 2007-12-29 11:21 ` Eli Zaretskii 2007-12-28 6:16 ` Thiago Jung Bauermann 2 siblings, 1 reply; 22+ messages in thread From: Thiago Jung Bauermann @ 2007-12-27 7:40 UTC (permalink / raw) To: Eli Zaretskii; +Cc: gdb-patches Hi, On Fri, 2007-12-21 at 18:04 +0200, Eli Zaretskii wrote: > > Date: Thu, 20 Dec 2007 03:49:28 -0200 > > From: Thiago Jung Bauermann <bauerman@br.ibm.com> > > > > - doesn't support conversion of 64-bit integers to decimal float, > > because of libdecnumber limitation; > > - error checking in decimal float operations ignore underflow, overflow > > and divide by zero to imitate binary float implementation; > > These limitations should be documented in the manual, I think: they > will affect GDB users, right? Actually, the second one is an implementation choice, not really a limitation. But I agree that both should be in the manual. I will update the patch to include a documentation addition. > > - decimal_from_floating is not very nice because it uses sprintf, but > > I couldn't think of a better way. > > Yuck! I don't know anything about libdecnumber, but is there _really_ > no other way? What about producing the two parts before and after the > decimal point as integers, then combine them with arithmetic > operations? I took (quite) some time to implement something following those lines, and came up with a naïve function which was able to convert binary float to decimal float using arithmetic operations. It's less precise than the printf version, though: (gdb) p (_Decimal128) 1.2 $1 = 1.1999999997206032276153564453125 Compared to the printf one: (gdb) p (_Decimal128) 1.2 $1 = 1.19999999999999995559107901499 Besides, it has problems with very small numbers (needs better stop criterion) or very large ones (right now it has a limit at INT_MAX). It's possible that those limitations can be removed or attenuated, but I'm not experienced with numerical algorithms so it would take me great work, and I don't think it would pay off. Going through the string representation is not elegant, but provides good results and solves the problem at hand with no drawbacks since snprintf is provided by libiberty (thanks for the pointer). > > +static void > > +set_decnumber_context (decContext *ctx, int len) > > +{ > > + switch (len) > > + { > > + case 4: > > + decContextDefault (ctx, DEC_INIT_DECIMAL32); > > + break; > > + case 8: > > + decContextDefault (ctx, DEC_INIT_DECIMAL64); > > + break; > > + case 16: > > + decContextDefault (ctx, DEC_INIT_DECIMAL128); > > + break; > > + } > > I don't think our coding style includes mixed-case symbols. Are these > library functions? Yes, they are from libdecnumber. The library is also used by GCC to provide decimal floating point support. > > +void > > +decimal_from_floating (struct value *from, gdb_byte *to, int len) > > +{ > > + /* The size of this buffer is a conservative guess: assumes an 128-bit > > + long double could have 40 decimal digits, plus 4 for exponent, plus > > + 3 for mantissa and exponent signs and 'E', plus '\0'. */ > > + char buffer[48]; > > Are the sizes of the exponent, mantissa, etc. available as parameters > from libdecnumber? If so, it would be better to use them explicitly > in allocating buffer[] off the stack (e.g., with alloca). That way, > if your assumptions will ever become incorrect, the code will adapt > automatically. Actually, these numbers refer to the double representation in the target system, not to the decimal float representation used in libdecnumber. By the way, since libiberty also has an implementation for asprintf, I could do away with these estimates and just use this function instead. > > + /* We cannot use snprintf here because it is defined only in C99. > > We have portable substitutes for snprintf, I think. Take a look at > libiberty, for example. Yes, it is there. I didn't find any .h, though, so I don't really know the proper way to use them. Maybe the configure system will set things up behind my back for the functions which are not provided by the host? > > + sprintf (buffer, "%Lf", value_as_double (from)); > > If we must live with going through the printed representation, at the > very least please use "%.30Lf", so as not to lose precision due to the > default number of significant digits produced under "%Lf", arbitrarily > chosen by the libc implementation. Done, thanks. > > > + /* This is an ugly way to do the conversion, but libdecnumber does > > + not offer a direct way to do it. */ > > + decimal_to_string (from, len, buffer); > > + return atof (buffer); > > Isn't strtold better here? It's C99 and not in libiberty. -- []'s Thiago Jung Bauermann Software Engineer IBM Linux Technology Center ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [patch 2/2] Wrap-up expression support for DFP. 2007-12-27 7:40 ` Thiago Jung Bauermann @ 2007-12-29 11:21 ` Eli Zaretskii 2008-01-02 20:07 ` Thiago Jung Bauermann 0 siblings, 1 reply; 22+ messages in thread From: Eli Zaretskii @ 2007-12-29 11:21 UTC (permalink / raw) To: Thiago Jung Bauermann; +Cc: gdb-patches > From: Thiago Jung Bauermann <bauerman@br.ibm.com> > Cc: gdb-patches@sourceware.org > Date: Wed, 26 Dec 2007 19:41:17 -0200 > > Actually, these numbers refer to the double representation in the target > system, not to the decimal float representation used in libdecnumber. By > the way, since libiberty also has an implementation for asprintf, I > could do away with these estimates and just use this function instead. > > > > + /* We cannot use snprintf here because it is defined only in C99. > > > > We have portable substitutes for snprintf, I think. Take a look at > > libiberty, for example. > > Yes, it is there. I didn't find any .h, though, so I don't really know > the proper way to use them. There's include/libiberty.h, where all libiberty functions are declared, conditioned by corresponding preprocessor defines. Those preprocessor defines should be defined by the configure script for platforms that don't have those functions in their native libraries. > > > + /* This is an ugly way to do the conversion, but libdecnumber does > > > + not offer a direct way to do it. */ > > > + decimal_to_string (from, len, buffer); > > > + return atof (buffer); > > > > Isn't strtold better here? > > It's C99 and not in libiberty. Then how about using strtod? ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [patch 2/2] Wrap-up expression support for DFP. 2007-12-29 11:21 ` Eli Zaretskii @ 2008-01-02 20:07 ` Thiago Jung Bauermann 2008-01-05 11:30 ` Eli Zaretskii 0 siblings, 1 reply; 22+ messages in thread From: Thiago Jung Bauermann @ 2008-01-02 20:07 UTC (permalink / raw) To: Eli Zaretskii; +Cc: gdb-patches [-- Attachment #1: Type: text/plain, Size: 1548 bytes --] On Sat, 2007-12-29 at 13:18 +0200, Eli Zaretskii wrote: > > > We have portable substitutes for snprintf, I think. Take a look at > > > libiberty, for example. > > > > Yes, it is there. I didn't find any .h, though, so I don't really know > > the proper way to use them. > > There's include/libiberty.h, where all libiberty functions are > declared, conditioned by corresponding preprocessor defines. Those > preprocessor defines should be defined by the configure script for > platforms that don't have those functions in their native libraries. Ok, since libiberty.h is already included by defs.h, I don't need to worry about it. Thanks for the explanation. > > > > + /* This is an ugly way to do the conversion, but libdecnumber does > > > > + not offer a direct way to do it. */ > > > > + decimal_to_string (from, len, buffer); > > > > + return atof (buffer); > > > > > > Isn't strtold better here? > > > > It's C99 and not in libiberty. > > Then how about using strtod? Fine by me. Thanks for your review, Eli. The attached patch has the following changes from the one I originally posted: - includes documentation update to GDB manual, under the "C and C++" subsection; - uses asprintf instead of sprintf, with "%.30Lg" in decimal_from_floating; - uses strtod instead of atof in decimal_to_double; - decimal/binary FP conversion tests now accept some rounding variation: gdb_test "p (_Decimal64) 3.1" " = 3.(0999.*|1000.*)" Is this version ok? -- []'s Thiago Jung Bauermann Software Engineer IBM Linux Technology Center [-- Attachment #2: expressions.diff --] [-- Type: text/x-patch, Size: 40786 bytes --] gdb/ 2008-01-02 Thiago Jung Bauermann <bauerman@br.ibm.com> * Makefile.in (dfp.o): Depend on expression.h, gdbtypes.h and value.h. (valarith.o): Depend on dfp.h. (valops.o): Likewise. * dfp.c: Include expression.h, gdbtypes.h, value.h and dfp.h. (set_decnumber_context): New function. (decimal_check_errors): Likewise. (decimal_from_number): Likewise. (decimal_to_number): Likewise. (decimal_from_string): Use set_decnumber_context and decimal_check_errors. (decimal_from_integral): New function. (decimal_from_floating): Likewise. (decimal_to_double): Likewise. (promote_decimal): Likewise. (decimal_binop): Likewise. (decimal_is_zero): Likewise. (decimal_compare): Likewise. (decimal_convert): Likewise. * dfp.h (decimal_from_integral): New prototype. (decimal_from_floating): Likewise. (decimal_to_double): Likewise. (decimal_binop): Likewise. (decimal_is_zero): Likewise. (decimal_compare): Likewise. (decimal_convert): Likewise. * eval.c (evaluate_subexp_standard): Remove expect_type argument from call to value_from_decfloat. * valarith.c: Include dfp.h. (value_args_as_decimal): New function. (value_binop): Add if block to handle TYPE_CODE_DECFLOAT values. (value_logical_not): Likewise. (value_equal): Likewise. (value_less): Likewise. (value_pos): Likewise. (value_neg): Formatting fix. * valops.c: Include dfp.h. (value_cast): Add if block to handle TYPE_CODE_DECFLOAT values. * value.c (unpack_long): Add case to handle TYPE_CODE_DECFLOAT. (unpack_double): Add if block to handle TYPE_CODE_DECFLOAT. (value_from_decfloat): Remove expect_type argument. * value.h (value_from_decfloat): Update prototype. gdb/testsuite/ 2008-01-02 Thiago Jung Bauermann <bauerman@br.ibm.com> * gdb.base/dfp-exprs.exp (test_dfp_arithmetic_expressions): Add tests for expressions with decimal float values. (test_dfp_conversions): New function to test casts to and from decimal float types. Call test_dfp_conversions. * gdb.base/dfp-test.c (struct decstruct): Add float4 and double8 elements. (main): Initialize ds.float4 and ds.double8 elements. * gdb.base/dfp-test.exp (d32_set_tests): Fix typo. Adjust expect string to new error message. (d64_set_tests): Likewise. (d128_set_tests): Likewise. Add tests for expressions with decimal float variables. Add tests for conversions to and from decimal float types. gdb/doc 2008-01-02 Thiago Jung Bauermann <bauerman@br.ibm.com> * gdb.texinfo (C and C++): Add Decimal Floating Point format subsubsection. (Decimal Floating Point format): New subsubsection. Index: src-git/gdb/Makefile.in =================================================================== --- src-git.orig/gdb/Makefile.in 2007-12-26 18:59:12.000000000 -0200 +++ src-git/gdb/Makefile.in 2007-12-26 18:59:27.000000000 -0200 @@ -2046,7 +2046,8 @@ dsrec.o: dsrec.c $(defs_h) $(serial_h) $ dummy-frame.o: dummy-frame.c $(defs_h) $(dummy_frame_h) $(regcache_h) \ $(frame_h) $(inferior_h) $(gdb_assert_h) $(frame_unwind_h) \ $(command_h) $(gdbcmd_h) $(gdb_string_h) -dfp.o: dfp.c $(defs_h) $(dfp_h) $(decimal128_h) $(decimal64_h) $(decimal32_h) +dfp.o: dfp.c $(defs_h) $(expression_h) $(gdbtypes_h) $(value_h) $(dfp_h) \ + $(decimal128_h) $(decimal64_h) $(decimal32_h) dwarf2expr.o: dwarf2expr.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(value_h) \ $(gdbcore_h) $(elf_dwarf2_h) $(dwarf2expr_h) dwarf2-frame.o: dwarf2-frame.c $(defs_h) $(dwarf2expr_h) $(elf_dwarf2_h) \ @@ -2910,12 +2911,12 @@ v850-tdep.o: v850-tdep.c $(defs_h) $(fra $(regcache_h) $(dis_asm_h) $(osabi_h) valarith.o: valarith.c $(defs_h) $(value_h) $(symtab_h) $(gdbtypes_h) \ $(expression_h) $(target_h) $(language_h) $(gdb_string_h) \ - $(doublest_h) $(infcall_h) + $(doublest_h) $(dfp_h) $(infcall_h) valops.o: valops.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(value_h) $(frame_h) \ $(inferior_h) $(gdbcore_h) $(target_h) $(demangle_h) $(language_h) \ $(gdbcmd_h) $(regcache_h) $(cp_abi_h) $(block_h) $(infcall_h) \ $(dictionary_h) $(cp_support_h) $(gdb_string_h) $(gdb_assert_h) \ - $(cp_support_h) $(observer_h) + $(cp_support_h) $(observer_h) $(dfp_h) valprint.o: valprint.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \ $(value_h) $(gdbcore_h) $(gdbcmd_h) $(target_h) $(language_h) \ $(annotate_h) $(valprint_h) $(floatformat_h) $(doublest_h) \ Index: src-git/gdb/dfp.c =================================================================== --- src-git.orig/gdb/dfp.c 2007-12-26 18:59:12.000000000 -0200 +++ src-git/gdb/dfp.c 2008-01-02 15:59:08.000000000 -0200 @@ -18,6 +18,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "defs.h" +#include "expression.h" +#include "gdbtypes.h" +#include "value.h" +#include "dfp.h" /* The order of the following headers is important for making sure decNumber structure is large enough to hold decimal128 digits. */ @@ -50,6 +54,89 @@ match_endianness (const gdb_byte *from, return; } +/* Helper function to get the appropriate libdecnumber context for each size + of decimal float. */ +static void +set_decnumber_context (decContext *ctx, int len) +{ + switch (len) + { + case 4: + decContextDefault (ctx, DEC_INIT_DECIMAL32); + break; + case 8: + decContextDefault (ctx, DEC_INIT_DECIMAL64); + break; + case 16: + decContextDefault (ctx, DEC_INIT_DECIMAL128); + break; + } + + ctx->traps = 0; +} + +/* Check for errors signaled in the decimal context structure. */ +static void +decimal_check_errors (decContext *ctx) +{ + /* An error here could be a division by zero, an overflow, an underflow or + an invalid operation (from the DEC_Errors constant in decContext.h). + Since GDB doesn't complain about division by zero, overflow or underflow + errors for binary floating, we won't complain about them for decimal + floating either. */ + if (ctx->status & DEC_IEEE_854_Invalid_operation) + { + /* Leave only the error bits in the status flags. */ + ctx->status &= DEC_IEEE_854_Invalid_operation; + error (_("Cannot perform operation: %s"), decContextStatusToString (ctx)); + } +} + +/* Helper function to convert from libdecnumber's appropriate representation + for computation to each size of decimal float. */ +static void +decimal_from_number (const decNumber *from, gdb_byte *to, int len) +{ + decContext set; + + set_decnumber_context (&set, len); + + switch (len) + { + case 4: + decimal32FromNumber ((decimal32 *) to, from, &set); + break; + case 8: + decimal64FromNumber ((decimal64 *) to, from, &set); + break; + case 16: + decimal128FromNumber ((decimal128 *) to, from, &set); + break; + } +} + +/* Helper function to convert each size of decimal float to libdecnumber's + appropriate representation for computation. */ +static void +decimal_to_number (const gdb_byte *from, int len, decNumber *to) +{ + switch (len) + { + case 4: + decimal32ToNumber ((decimal32 *) from, to); + break; + case 8: + decimal64ToNumber ((decimal64 *) from, to); + break; + case 16: + decimal128ToNumber ((decimal128 *) from, to); + break; + default: + error (_("Unknown decimal floating point type.\n")); + break; + } +} + /* Convert decimal type to its string representation. LEN is the length of the decimal type, 4 bytes for decimal32, 8 bytes for decimal64 and 16 bytes for decimal128. */ @@ -59,6 +146,7 @@ decimal_to_string (const gdb_byte *decby gdb_byte dec[16]; match_endianness (decbytes, len, dec); + switch (len) { case 4: @@ -85,21 +173,17 @@ decimal_from_string (gdb_byte *decbytes, decContext set; gdb_byte dec[16]; + set_decnumber_context (&set, len); + switch (len) { case 4: - decContextDefault (&set, DEC_INIT_DECIMAL32); - set.traps = 0; decimal32FromString ((decimal32 *) dec, string, &set); break; case 8: - decContextDefault (&set, DEC_INIT_DECIMAL64); - set.traps = 0; decimal64FromString ((decimal64 *) dec, string, &set); break; case 16: - decContextDefault (&set, DEC_INIT_DECIMAL128); - set.traps = 0; decimal128FromString ((decimal128 *) dec, string, &set); break; default: @@ -109,5 +193,207 @@ decimal_from_string (gdb_byte *decbytes, match_endianness (dec, len, decbytes); + /* Check for errors in the DFP operation. */ + decimal_check_errors (&set); + return 1; } + +/* Converts a value of an integral type to a decimal float of + specified LEN bytes. */ +void +decimal_from_integral (struct value *from, gdb_byte *to, int len) +{ + LONGEST l; + gdb_byte dec[16]; + decNumber number; + struct type *type; + + type = check_typedef (value_type (from)); + + if (TYPE_LENGTH (type) > 4) + /* libdecnumber can convert only 32-bit integers. */ + error (_("Conversion of large integer to a decimal floating type is not supported.")); + + l = value_as_long (from); + + if (TYPE_UNSIGNED (type)) + decNumberFromUInt32 (&number, (unsigned int) l); + else + decNumberFromInt32 (&number, (int) l); + + decimal_from_number (&number, dec, len); + match_endianness (dec, len, to); +} + +/* Converts a value of a float type to a decimal float of + specified LEN bytes. + + This is an ugly way to do the conversion, but libdecnumber does + not offer a direct way to do it. */ +void +decimal_from_floating (struct value *from, gdb_byte *to, int len) +{ + char *buffer; + int ret; + + ret = asprintf (&buffer, "%.30Lg", value_as_double (from)); + if (ret == -1) + error (_("Error in conversion to decimal float.")); + + decimal_from_string (to, len, buffer); + + free (buffer); +} + +/* Converts a decimal float of LEN bytes to a double value. */ +DOUBLEST +decimal_to_double (const gdb_byte *from, int len) +{ + char buffer[MAX_DECIMAL_STRING]; + + /* This is an ugly way to do the conversion, but libdecnumber does + not offer a direct way to do it. */ + decimal_to_string (from, len, buffer); + return strtod (buffer, NULL); +} + +/* Check if operands have the same size and convert them to the + biggest of the two if necessary. */ +static int +promote_decimal (gdb_byte *x, int len_x, gdb_byte *y, int len_y) +{ + int len_result; + decNumber number; + + if (len_x < len_y) + { + decimal_to_number (x, len_x, &number); + decimal_from_number (&number, x, len_y); + len_result = len_y; + } + else if (len_x > len_y) + { + decimal_to_number (y, len_y, &number); + decimal_from_number (&number, y, len_x); + len_result = len_x; + } + else + len_result = len_x; + + return len_result; +} + +/* Perform operation OP with operands X and Y and store value in RESULT. + If LEN_X and LEN_Y are not equal, RESULT will have the size of the biggest + of the two, and LEN_RESULT will be set accordingly. */ +void +decimal_binop (enum exp_opcode op, const gdb_byte *x, int len_x, + const gdb_byte *y, int len_y, gdb_byte *result, int *len_result) +{ + decContext set; + decNumber number1, number2, number3; + gdb_byte dec1[16], dec2[16], dec3[16]; + + match_endianness (x, len_x, dec1); + match_endianness (y, len_y, dec2); + + *len_result = promote_decimal (dec1, len_x, dec2, len_y); + + /* Both operands are of size *len_result from now on. */ + + decimal_to_number (dec1, *len_result, &number1); + decimal_to_number (dec2, *len_result, &number2); + + set_decnumber_context (&set, *len_result); + + switch (op) + { + case BINOP_ADD: + decNumberAdd (&number3, &number1, &number2, &set); + break; + case BINOP_SUB: + decNumberSubtract (&number3, &number1, &number2, &set); + break; + case BINOP_MUL: + decNumberMultiply (&number3, &number1, &number2, &set); + break; + case BINOP_DIV: + decNumberDivide (&number3, &number1, &number2, &set); + break; + case BINOP_EXP: + decNumberPower (&number3, &number1, &number2, &set); + break; + default: + error (_("Unknown decimal floating point operation.")); + break; + } + + /* Check for errors in the DFP operation. */ + decimal_check_errors (&set); + + decimal_from_number (&number3, dec3, *len_result); + + match_endianness (dec3, *len_result, result); +} + +/* Returns true if X (which is LEN bytes wide) is the number zero. */ +int +decimal_is_zero (const gdb_byte *x, int len) +{ + decNumber number; + gdb_byte dec[16]; + + match_endianness (x, len, dec); + decimal_to_number (dec, len, &number); + + return decNumberIsZero (&number); +} + +/* Compares two numbers numerically. If X is less than Y then the return value + will be -1. If they are equal, then the return value will be 0. If X is + greater than the Y then the return value will be 1. */ +int +decimal_compare (const gdb_byte *x, int len_x, const gdb_byte *y, int len_y) +{ + decNumber number1, number2, result; + decContext set; + gdb_byte dec1[16], dec2[16]; + int len_result; + + match_endianness (x, len_x, dec1); + match_endianness (y, len_y, dec2); + + len_result = promote_decimal (dec1, len_x, dec2, len_y); + + decimal_to_number (dec1, len_result, &number1); + decimal_to_number (dec2, len_result, &number2); + + set_decnumber_context (&set, len_result); + + decNumberCompare (&result, &number1, &number2, &set); + + /* Check for errors in the DFP operation. */ + decimal_check_errors (&set); + + if (decNumberIsNaN (&result)) + error (_("Comparison with an invalid number (NaN).")); + else if (decNumberIsZero (&result)) + return 0; + else if (decNumberIsNegative (&result)) + return -1; + else + return 1; +} + +/* Convert a decimal value from a decimal type with LEN_FROM bytes to a + decimal type with LEN_TO bytes. */ +void +decimal_convert (const gdb_byte *from, int len_from, gdb_byte *to, + int len_to) +{ + decNumber number; + + decimal_to_number (from, len_from, &number); + decimal_from_number (&number, to, len_to); +} Index: src-git/gdb/dfp.h =================================================================== --- src-git.orig/gdb/dfp.h 2007-12-26 18:59:12.000000000 -0200 +++ src-git/gdb/dfp.h 2007-12-26 18:59:27.000000000 -0200 @@ -31,5 +31,14 @@ extern void decimal_to_string (const gdb_byte *, int, char *); extern int decimal_from_string (gdb_byte *, int, const char *); +extern void decimal_from_integral (struct value *from, gdb_byte *to, int len); +extern void decimal_from_floating (struct value *from, gdb_byte *to, int len); +extern DOUBLEST decimal_to_double (const gdb_byte *from, int len); +extern void decimal_binop (enum exp_opcode, const gdb_byte *, int, + const gdb_byte *, int, gdb_byte *, int *); +extern int decimal_is_zero (const gdb_byte *x, int len); +extern int decimal_compare (const gdb_byte *x, int len_x, const gdb_byte *y, int len_y); +extern void decimal_convert (const gdb_byte *from, int len_from, gdb_byte *to, + int len_to); #endif Index: src-git/gdb/eval.c =================================================================== --- src-git.orig/gdb/eval.c 2007-12-26 18:59:12.000000000 -0200 +++ src-git/gdb/eval.c 2007-12-26 18:59:27.000000000 -0200 @@ -458,8 +458,8 @@ evaluate_subexp_standard (struct type *e case OP_DECFLOAT: (*pos) += 3; - return value_from_decfloat (expect_type, exp->elts[pc + 1].type, - exp->elts[pc + 2].decfloatconst); + return value_from_decfloat (exp->elts[pc + 1].type, + exp->elts[pc + 2].decfloatconst); case OP_VAR_VALUE: (*pos) += 3; Index: src-git/gdb/testsuite/gdb.base/dfp-exprs.exp =================================================================== --- src-git.orig/gdb/testsuite/gdb.base/dfp-exprs.exp 2007-12-26 18:59:12.000000000 -0200 +++ src-git/gdb/testsuite/gdb.base/dfp-exprs.exp 2008-01-02 17:43:58.000000000 -0200 @@ -74,14 +74,102 @@ proc test_dfp_literals_accepted {} { proc test_dfp_arithmetic_expressions {} { -# Arithmetic operations for DFP types are not yet implemented in GDB. -# These tests are to verify that they will generate expected error messages. + # _Decimal32 operands. + gdb_test "p 1.4df + 1.2df" " = 2.6" + gdb_test "p 1.4df - 1.2df" " = 0.2" + gdb_test "p 1.4df * 1.2df" " = 1.68" + gdb_test "p 1.4df / 1.2df" " = 1.166667" + + # _Decimal64 operands. + gdb_test "p 1.4dd + 1.2dd" " = 2.6" + gdb_test "p 1.4dd - 1.2dd" " = 0.2" + gdb_test "p 1.4dd * 1.2dd" " = 1.68" + gdb_test "p 1.4dd / 1.2dd" " = 1.166666666666667" + + # _Decimal128 operands. + gdb_test "p 1.4dl + 1.2dl" " = 2.6" + gdb_test "p 1.4dl - 1.2dl" " = 0.2" + gdb_test "p 1.4dl * 1.2dl" " = 1.68" + gdb_test "p 1.4dl / 1.2dl" " = 1.166666666666666666666666666666667" + + # Test type of operation result. + gdb_test "ptype 2.df + 2.df" "= _Decimal32" + gdb_test "ptype 2.dd + 2.dd" "= _Decimal64" + gdb_test "ptype 2.dl + 2.dl" "= _Decimal128" + + # Mixture of different _Decimal sizes. + gdb_test "p 2.1df + 2.7dd" "= 4.8" + gdb_test "p 2.1dd + 2.7df" "= 4.8" + gdb_test "p 2.6df + 2.7dl" "= 5.3" + gdb_test "p 2.6dl + 2.7df" "= 5.3" + gdb_test "p 2.3dd + 2.2dl" "= 4.5" + gdb_test "p 2.3dl + 2.2dd" "= 4.5" + gdb_test "ptype 2.df + 2.dd" "= _Decimal64" + gdb_test "ptype 2.df + 2.dl" "= _Decimal128" + gdb_test "ptype 2.dd + 2.dl" "= _Decimal128" + + # Mixture of Decimal and integral operands + gdb_test "p 1.2df + 1" " = 2.2" + gdb_test "p 2 + 1.7dd" " = 3.7" + gdb_test "p 3 + 2.1dl" " = 5.1" + gdb_test "ptype 1.2df + 1" " = _Decimal32" + gdb_test "ptype 2 + 1.7dd" " = _Decimal64" + gdb_test "ptype 3 + 2.1dl" " = _Decimal128" + + # Reject operation with integral larger than 32-bits + gdb_test "p 1.2df + 2ll" "Conversion of large integer to a decimal floating type is not supported." + + # Reject operation with DFP and Binary FP + gdb_test "p 1.2df + 1.2f" "Mixing decimal floating types with other floating types is not allowed." + + # Test other operations with DFP operands + gdb_test "p !0.df" " = 1" + gdb_test "p !0.dd" " = 1" + gdb_test "p !0.dl" " = 1" + gdb_test "p !0.5df" " = 0" + gdb_test "p !0.5dd" " = 0" + gdb_test "p !0.5dl" " = 0" + + gdb_test "p 1.2df == 1.2df" " = 1" + gdb_test "p 1.2df == 1.2dd" " = 1" + gdb_test "p 1.2df == 1.2dl" " = 1" + gdb_test "p 1.2dd == 1.2df" " = 1" + gdb_test "p 1.2dd == 1.2dl" " = 1" + gdb_test "p 1.2dl == 1.2df" " = 1" + gdb_test "p 1.2dl == 1.2dd" " = 1" + gdb_test "p 1.2df == 1.3df" " = 0" + gdb_test "p 1.2df == 1.3dd" " = 0" + gdb_test "p 1.2df == 1.3dl" " = 0" + gdb_test "p 1.2dd == 1.3df" " = 0" + gdb_test "p 1.2dd == 1.3dl" " = 0" + gdb_test "p 1.2dl == 1.3df" " = 0" + gdb_test "p 1.2dl == 1.3dd" " = 0" + + gdb_test "p +1.2df" " = 1.2" + gdb_test "p +1.2dd" " = 1.2" + gdb_test "p +1.2dl" " = 1.2" + + gdb_test "p 1.2df < 1.3df" " = 1" + gdb_test "p 1.2df < 1.3dd" " = 1" + gdb_test "p 1.2dl < 1.3df" " = 1" + gdb_test "p 1.2dd < 1.3dd" " = 1" + gdb_test "p 1.2dd < 1.3dl" " = 1" + gdb_test "p 1.2dl < 1.3dl" " = 1" + gdb_test "p 1.2dl < 1.3df" " = 1" + gdb_test "p 1.2df > 1" " = 1" + gdb_test "p 1.2dl > 2" " = 0" + gdb_test "p 2 > 1.2dd" " = 1" + gdb_test "p 2 > 3.1dl" " = 0" +} - gdb_test "p 1.4df + 1.2df" "Argument to arithmetic operation not a number or boolean.*" - gdb_test "p 1.4df - 1.2df" ".*Argument to arithmetic operation not a number or boolean.*" - gdb_test "p 1.4df * 1.2df" "Argument to arithmetic operation not a number or boolean.*" - gdb_test "p 1.4df / 1.2df" "Argument to arithmetic operation not a number or boolean.*" +proc test_dfp_conversions {} { + # Test cast to and from DFP values, and between DFPs of different sizes + gdb_test "p (float) -0.1df" " = -0.(0999.*|1000.*)" + gdb_test "p (int) 8.3dd" " = 8" + gdb_test "p (_Decimal64) 3.1" " = 3.(0999.*|1000.*)" + gdb_test "p (_Decimal128) 3.7df" " = 3.7" + gdb_test "p (_Decimal32) 4" " = 4" } # Start with a fresh gdb. @@ -92,3 +180,4 @@ gdb_reinitialize_dir $srcdir/$subdir test_dfp_literals_accepted test_dfp_arithmetic_expressions +test_dfp_conversions Index: src-git/gdb/testsuite/gdb.base/dfp-test.c =================================================================== --- src-git.orig/gdb/testsuite/gdb.base/dfp-test.c 2007-12-26 18:59:12.000000000 -0200 +++ src-git/gdb/testsuite/gdb.base/dfp-test.c 2007-12-26 18:59:27.000000000 -0200 @@ -26,6 +26,8 @@ struct decstruct { int int4; long long8; + float float4; + double double8; _Decimal32 dec32; _Decimal64 dec64; _Decimal128 dec128; @@ -85,6 +87,8 @@ int main() ds.int4 = 1; ds.long8 = 2; + ds.float4 = 3.1; + ds.double8 = 4.2; ds.dec32 = 1.2345df; ds.dec64 = 1.2345dd; ds.dec128 = 1.2345dl; Index: src-git/gdb/testsuite/gdb.base/dfp-test.exp =================================================================== --- src-git.orig/gdb/testsuite/gdb.base/dfp-test.exp 2007-12-26 18:59:12.000000000 -0200 +++ src-git/gdb/testsuite/gdb.base/dfp-test.exp 2008-01-02 17:33:40.000000000 -0200 @@ -18,6 +18,53 @@ # This file is part of the gdb testsuite. It is intended to test that # gdb could correctly handle decimal floating point introduced in IEEE 754R. +if $tracelevel then { + strace $tracelevel +} + +set testfile "dfp-test" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +# Try to compile the test case. If we can't, assume the +# toolchain does not yet provide DFP support and bail out. +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {quiet debug}] != "" } { + verbose "Skipping DFP tests." + 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 +} + +# Detect the size of the target's basic types (from gdb.base/long_long.exp). + +proc get_valueof { fmt exp default } { + global gdb_prompt + send_gdb "print${fmt} ${exp}\n" + gdb_expect { + -re "\\$\[0-9\]* = (\[-\]*\[0-9\]*).*$gdb_prompt $" { + set val $expect_out(1,string) + } + timeout { + set val ${default} + } + } + return ${val} +} + +proc get_sizeof { type default } { + return [get_valueof "/d" "sizeof (${type})" $default] +} + +set sizeof_long [get_sizeof "long" 4] + proc d32_set_tests {} { gdb_test "p d32=123.45df" " = 123.45" @@ -43,10 +90,10 @@ proc d32_set_tests {} { 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=12345.df" " = 12345" "12345. is a 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)" + gdb_test "p d32=1.23Edf" ".*Conversion syntax.*" "1.23E is an invalid number" + gdb_test "p d32=1.23E45Adf" ".*Conversion syntax.*" "1.23E45A is an invalid number" } proc d64_set_tests {} { @@ -75,8 +122,8 @@ proc d64_set_tests {} { # 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)" + gdb_test "p d64=1.23Edd" ".*Conversion syntax.*" "1.23E is an invalid number" + gdb_test "p d64=1.23E45Add" ".*Conversion syntax.*" "1.23E45A is an invalid number" } proc d128_set_tests {} { @@ -104,33 +151,8 @@ proc d128_set_tests {} { # 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} -# Try to compile the test case. If we can't, assume the -# toolchain does not yet provide DFP support and bail out. -if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {quiet debug}] != "" } { - verbose "Skipping DFP tests." - 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 + gdb_test "p d128=1.23Edl" ".*Conversion syntax.*" "1.23E is an invalid number" + gdb_test "p d128=1.23E45Adl" ".*Conversion syntax.*" "1.23E45A is an invalid number" } # Different tests on 32-bits decimal floating point, including the printing @@ -237,6 +259,57 @@ gdb_test "print ds.dec32" " = 1.2345" gdb_test "print ds.dec64" " = 1.2345" gdb_test "print ds.dec128" " = 1.2345" +# Test expressions with DFP variables. + +gdb_test "print d32 + ds.dec32" " = 1.3345" +gdb_test "print d64 + ds.dec64" " = 1.3345" +gdb_test "print d128 + ds.dec128" " = 1.3345" + +# Test conversion between different _Decimal sizes. + +gdb_test "ptype d64 + ds.dec32" " = volatile _Decimal64" +gdb_test "ptype d128 + ds.dec32" " = volatile _Decimal128" +gdb_test "ptype d128 + ds.dec64" " = volatile _Decimal128" + +# Mixture of Decimal and integral operands +gdb_test "p d32 + 1" " = 1.1" +gdb_test "p 2 + d64" " = 2.1" +gdb_test "p ds.int4 + d128" " = 1.1" +gdb_test "ptype d32 + 1" " = volatile _Decimal32" +gdb_test "ptype ds.int4 + d128" " = volatile _Decimal128" + +# Test other operations with DFP operands +gdb_test "p !d32" " = 0" +gdb_test "p !d64" " = 0" +gdb_test "p !d128" " = 0" +gdb_test "p +d32" " = 0.1" +gdb_test "p +d64" " = 0.1" +gdb_test "p +d128" " = 0.1" +gdb_test "p d64 == d128" " = 1" +gdb_test "p d128 == ds.dec32" " = 0" +gdb_test "p d128 == d32" " = 1" +gdb_test "p ds.dec32 == ds.dec64" " = 1" +gdb_test "p d32 < ds.dec32" " = 1" +gdb_test "p d64 < ds.dec64" " = 1" +gdb_test "p d128 < ds.dec128" " = 1" +gdb_test "p ds.dec32 < d32" " = 0" +gdb_test "p d64 > ds.dec64" " = 0" +gdb_test "p ds.dec128 > d128 " " = 1" +gdb_test "p d32 < ds.int4" " = 1" +gdb_test "p ds.int4 > d32" " = 1" +gdb_test "p ds.dec32 < ds.int4" " = 0" +gdb_test "p ds.int4 > ds.dec64" " = 0" +gdb_test "p ds.dec128 > ds.int4" " = 1" + +# Reject operation with integral larger than 32-bits +if { ${sizeof_long} > 4 } { + gdb_test "p d32 + ds.long8" "Conversion of large integer to a decimal floating type is not supported." +} + +# Reject operation with DFP and Binary FP +gdb_test "p d64 + ds.float4" "Mixing decimal floating types with other floating types is not allowed." +gdb_test "p ds.double8 + d128" "Mixing decimal floating types with other floating types is not allowed." + # The following tests are intended to verify that gdb can handle "d1=d2" # and "d1=-d2" correctly. @@ -246,3 +319,12 @@ 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" + +# Test cast to and from DFP values + +gdb_test "print ds.double8 = ds.dec64" " = -0.(0999.*|1000.*)" +gdb_test "print ds.dec64 = ds.float4" " = 3.(0999.*|1000.*)" +gdb_test "print ds.dec128 = -ds.double8" " = 0.(0999.*|1000.*)" +gdb_test "print ds.dec128 = ds.dec32" " = -0.1" +gdb_test "print ds.dec32 = ds.int4" " = 1" +gdb_test "print ds.int4 = 7.3dl" " = 7" Index: src-git/gdb/valarith.c =================================================================== --- src-git.orig/gdb/valarith.c 2007-12-26 18:59:12.000000000 -0200 +++ src-git/gdb/valarith.c 2007-12-26 18:59:27.000000000 -0200 @@ -28,6 +28,7 @@ #include "language.h" #include "gdb_string.h" #include "doublest.h" +#include "dfp.h" #include <math.h> #include "infcall.h" @@ -741,6 +742,60 @@ value_concat (struct value *arg1, struct } \f +/* Obtain decimal value of arguments for binary operation, converting from + other types if one of them is not decimal floating point. */ +static void +value_args_as_decimal (struct value *arg1, struct value *arg2, + gdb_byte *x, int *len_x, gdb_byte *y, int *len_y) +{ + struct type *type1, *type2; + + type1 = check_typedef (value_type (arg1)); + type2 = check_typedef (value_type (arg2)); + + /* At least one of the arguments must be of decimal float type. */ + gdb_assert (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT + || TYPE_CODE (type2) == TYPE_CODE_DECFLOAT); + + if (TYPE_CODE (type1) == TYPE_CODE_FLT + || TYPE_CODE (type2) == TYPE_CODE_FLT) + /* The DFP extension to the C language does not allow mixing of + * decimal float types with other float types in expressions + * (see WDTR 24732, page 12). */ + error (_("Mixing decimal floating types with other floating types is not allowed.")); + + /* Obtain decimal value of arg1, converting from other types + if necessary. */ + + if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT) + { + *len_x = TYPE_LENGTH (type1); + memcpy (x, value_contents (arg1), *len_x); + } + else if (is_integral_type (type1)) + { + *len_x = TYPE_LENGTH (type2); + decimal_from_integral (arg1, x, *len_x); + } + else + error (_("Don't know how to convert to decimal floating type.")); + + /* Obtain decimal value of arg2, converting from other types + if necessary. */ + + if (TYPE_CODE (type2) == TYPE_CODE_DECFLOAT) + { + *len_y = TYPE_LENGTH (type2); + memcpy (y, value_contents (arg2), *len_y); + } + else if (is_integral_type (type2)) + { + *len_y = TYPE_LENGTH (type1); + decimal_from_integral (arg2, y, *len_y); + } + else + error (_("Don't know how to convert to decimal floating type.")); +} /* Perform a binary operation on two operands which have reasonable representations as integers or floats. This includes booleans, @@ -759,14 +814,55 @@ value_binop (struct value *arg1, struct type1 = check_typedef (value_type (arg1)); type2 = check_typedef (value_type (arg2)); - if ((TYPE_CODE (type1) != TYPE_CODE_FLT && !is_integral_type (type1)) + if ((TYPE_CODE (type1) != TYPE_CODE_FLT + && TYPE_CODE (type1) != TYPE_CODE_DECFLOAT && !is_integral_type (type1)) || - (TYPE_CODE (type2) != TYPE_CODE_FLT && !is_integral_type (type2))) + (TYPE_CODE (type2) != TYPE_CODE_FLT + && TYPE_CODE (type2) != TYPE_CODE_DECFLOAT && !is_integral_type (type2))) error (_("Argument to arithmetic operation not a number or boolean.")); - if (TYPE_CODE (type1) == TYPE_CODE_FLT + if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT || - TYPE_CODE (type2) == TYPE_CODE_FLT) + TYPE_CODE (type2) == TYPE_CODE_DECFLOAT) + { + struct type *v_type; + int len_v1, len_v2, len_v; + gdb_byte v1[16], v2[16]; + gdb_byte v[16]; + + value_args_as_decimal (arg1, arg2, v1, &len_v1, v2, &len_v2); + + switch (op) + { + case BINOP_ADD: + case BINOP_SUB: + case BINOP_MUL: + case BINOP_DIV: + case BINOP_EXP: + decimal_binop (op, v1, len_v1, v2, len_v2, v, &len_v); + break; + + default: + error (_("Integer-only operation on floating point number.")); + } + + if (TYPE_CODE (type1) != TYPE_CODE_DECFLOAT) + /* If arg1 is not a decimal float, the type of the result is the type + of the decimal float argument, arg2. */ + v_type = type2; + else if (TYPE_CODE (type2) != TYPE_CODE_DECFLOAT) + /* Same logic, for the case where arg2 is not a decimal float. */ + v_type = type1; + else + /* len_v is equal either to len_v1 or to len_v2. the type of the + result is the type of the argument with the same length as v. */ + v_type = (len_v == len_v1)? type1 : type2; + + val = value_from_decfloat (v_type, v); + } + else if (TYPE_CODE (type1) == TYPE_CODE_FLT + || + TYPE_CODE (type2) == TYPE_CODE_FLT) { /* FIXME-if-picky-about-floating-accuracy: Should be doing this in target format. real.c in GCC probably has the necessary @@ -1177,6 +1273,8 @@ value_logical_not (struct value *arg1) if (TYPE_CODE (type1) == TYPE_CODE_FLT) return 0 == value_as_double (arg1); + else if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT) + return decimal_is_zero (value_contents (arg1), TYPE_LENGTH (type1)); len = TYPE_LENGTH (type1); p = value_contents (arg1); @@ -1255,6 +1353,16 @@ value_equal (struct value *arg1, struct DOUBLEST d = value_as_double (arg1); return d == value_as_double (arg2); } + else if ((code1 == TYPE_CODE_DECFLOAT || is_int1) + && (code2 == TYPE_CODE_DECFLOAT || is_int2)) + { + gdb_byte v1[16], v2[16]; + int len_v1, len_v2; + + value_args_as_decimal (arg1, arg2, v1, &len_v1, v2, &len_v2); + + return decimal_compare (v1, len_v1, v2, len_v2) == 0; + } /* FIXME: Need to promote to either CORE_ADDR or LONGEST, whichever is bigger. */ @@ -1319,6 +1427,16 @@ value_less (struct value *arg1, struct v DOUBLEST d = value_as_double (arg1); return d < value_as_double (arg2); } + else if ((code1 == TYPE_CODE_DECFLOAT || is_int1) + && (code2 == TYPE_CODE_DECFLOAT || is_int2)) + { + gdb_byte v1[16], v2[16]; + int len_v1, len_v2; + + value_args_as_decimal (arg1, arg2, v1, &len_v1, v2, &len_v2); + + return decimal_compare (v1, len_v1, v2, len_v2) == -1; + } else if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR) return value_as_address (arg1) < value_as_address (arg2); @@ -1350,6 +1468,8 @@ value_pos (struct value *arg1) if (TYPE_CODE (type) == TYPE_CODE_FLT) return value_from_double (type, value_as_double (arg1)); + else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT) + return value_from_decfloat (type, value_contents (arg1)); else if (is_integral_type (type)) { /* Perform integral promotion for ANSI C/C++. FIXME: What about @@ -1382,7 +1502,7 @@ value_neg (struct value *arg1) int len = TYPE_LENGTH (type); gdb_byte decbytes[16]; /* a decfloat is at most 128 bits long */ - memcpy(decbytes, value_contents(arg1), len); + memcpy (decbytes, value_contents (arg1), len); if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_LITTLE) decbytes[len-1] = decbytes[len - 1] | 0x80; Index: src-git/gdb/valops.c =================================================================== --- src-git.orig/gdb/valops.c 2007-12-26 18:59:12.000000000 -0200 +++ src-git/gdb/valops.c 2007-12-26 18:59:27.000000000 -0200 @@ -36,6 +36,7 @@ #include "infcall.h" #include "dictionary.h" #include "cp-support.h" +#include "dfp.h" #include <errno.h> #include "gdb_string.h" @@ -338,7 +339,8 @@ value_cast (struct type *type, struct va code2 = TYPE_CODE_INT; scalar = (code2 == TYPE_CODE_INT || code2 == TYPE_CODE_FLT - || code2 == TYPE_CODE_ENUM || code2 == TYPE_CODE_RANGE); + || code2 == TYPE_CODE_DECFLOAT || code2 == TYPE_CODE_ENUM + || code2 == TYPE_CODE_RANGE); if (code1 == TYPE_CODE_STRUCT && code2 == TYPE_CODE_STRUCT @@ -357,6 +359,22 @@ value_cast (struct type *type, struct va } if (code1 == TYPE_CODE_FLT && scalar) return value_from_double (type, value_as_double (arg2)); + else if (code1 == TYPE_CODE_DECFLOAT && scalar) + { + int dec_len = TYPE_LENGTH (type); + gdb_byte dec[16]; + + if (code2 == TYPE_CODE_FLT) + decimal_from_floating (arg2, dec, dec_len); + else if (code2 == TYPE_CODE_DECFLOAT) + decimal_convert (value_contents (arg2), TYPE_LENGTH (type2), + dec, dec_len); + else + /* The only option left is an integral type. */ + decimal_from_integral (arg2, dec, dec_len); + + return value_from_decfloat (type, dec); + } else if ((code1 == TYPE_CODE_INT || code1 == TYPE_CODE_ENUM || code1 == TYPE_CODE_RANGE) && (scalar || code2 == TYPE_CODE_PTR Index: src-git/gdb/value.c =================================================================== --- src-git.orig/gdb/value.c 2007-12-26 18:59:12.000000000 -0200 +++ src-git/gdb/value.c 2007-12-26 18:59:27.000000000 -0200 @@ -982,6 +982,7 @@ value_as_double (struct value *val) error (_("Invalid floating value found in program.")); return foo; } + /* Extract a value as a C pointer. Does not deallocate the value. Note that val's type may not actually be a pointer; value_as_long handles all the cases. */ @@ -1127,6 +1128,11 @@ unpack_long (struct type *type, const gd case TYPE_CODE_FLT: return extract_typed_floating (valaddr, type); + case TYPE_CODE_DECFLOAT: + /* libdecnumber has a function to convert from decimal to integer, but + it doesn't work when the decimal number has a fractional part. */ + return decimal_to_double (valaddr, len); + case TYPE_CODE_PTR: case TYPE_CODE_REF: /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure @@ -1184,6 +1190,8 @@ unpack_double (struct type *type, const return extract_typed_floating (valaddr, type); } + else if (code == TYPE_CODE_DECFLOAT) + return decimal_to_double (valaddr, len); else if (nosign) { /* Unsigned -- be sure we compensate for signed LONGEST. */ @@ -1643,23 +1651,12 @@ value_from_double (struct type *type, DO } struct value * -value_from_decfloat (struct type *expect_type, struct type *type, - gdb_byte decbytes[16]) +value_from_decfloat (struct type *type, const gdb_byte *dec) { struct value *val = allocate_value (type); - int len = TYPE_LENGTH (type); - if (expect_type) - { - int expect_len = TYPE_LENGTH (expect_type); - char decstr[MAX_DECIMAL_STRING]; - int real_len; - - decimal_to_string (decbytes, len, decstr); - decimal_from_string (decbytes, expect_len, decstr); - } + memcpy (value_contents_raw (val), dec, TYPE_LENGTH (type)); - memcpy (value_contents_raw (val), decbytes, len); return val; } Index: src-git/gdb/value.h =================================================================== --- src-git.orig/gdb/value.h 2007-12-26 18:59:12.000000000 -0200 +++ src-git/gdb/value.h 2007-12-26 18:59:27.000000000 -0200 @@ -280,9 +280,8 @@ extern void pack_long (gdb_byte *buf, st extern struct value *value_from_longest (struct type *type, LONGEST num); extern struct value *value_from_pointer (struct type *type, CORE_ADDR addr); extern struct value *value_from_double (struct type *type, DOUBLEST num); -extern struct value *value_from_decfloat (struct type *expect_type, - struct type *type, - gdb_byte decbytes[16]); +extern struct value *value_from_decfloat (struct type *type, + const gdb_byte *decbytes); extern struct value *value_from_string (char *string); extern struct value *value_at (struct type *type, CORE_ADDR addr); Index: src-git/gdb/doc/gdb.texinfo =================================================================== --- src-git.orig/gdb/doc/gdb.texinfo 2007-12-28 01:11:37.000000000 -0200 +++ src-git/gdb/doc/gdb.texinfo 2008-01-02 14:14:48.000000000 -0200 @@ -9139,6 +9139,7 @@ gcc.info, Using the @sc{gnu} Compiler Co * C Checks:: C and C@t{++} type and range checks * Debugging C:: @value{GDBN} and C * Debugging C Plus Plus:: @value{GDBN} features for C@t{++} +* Decimal Floating Point:: Numbers in Decimal Floating Point format @end menu @node C Operators @@ -9607,6 +9608,28 @@ available choices, or to finish the type @xref{Completion,, Command Completion}, for details on how to do this. @end table +@node Decimal Floating Point +@subsubsection Decimal Floating Point format +@cindex decimal floating point format + +@value{GDBN} can examine, set and perform computations with numbers in +decimal floating point format, which in the C language correspond to the +@code{_Decimal32}, @code{_Decimal64} and @code{_Decimal128} types as +specified by the extension to support decimal floating-point arithmetic. + +There are two encodings in use, depending on the architecture: BID (Binary +Integer Decimal) for x86 and x86-64, and DPD (Densely Packed Decimal) for +PowerPC. @value{GDBN} will use the appropriate encoding for the configured +target. + +Because of a limitation in @file{libdecnumber}, the library used by @value{GDBN} +to manipulate decimal floating point numbers, it is not possible to convert +(using a cast, for example) integers wider than 32-bit to decimal float. + +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. + @node Objective-C @subsection Objective-C ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [patch 2/2] Wrap-up expression support for DFP. 2008-01-02 20:07 ` Thiago Jung Bauermann @ 2008-01-05 11:30 ` Eli Zaretskii 2008-01-07 16:20 ` Thiago Jung Bauermann 0 siblings, 1 reply; 22+ messages in thread From: Eli Zaretskii @ 2008-01-05 11:30 UTC (permalink / raw) To: Thiago Jung Bauermann; +Cc: gdb-patches > From: Thiago Jung Bauermann <bauerman@br.ibm.com> > Cc: gdb-patches@sourceware.org > Date: Wed, 02 Jan 2008 18:00:46 -0200 > > Fine by me. Thanks for your review, Eli. The attached patch has the > following changes from the one I originally posted: > > - includes documentation update to GDB manual, under the "C and C++" > subsection; > - uses asprintf instead of sprintf, with "%.30Lg" in > decimal_from_floating; > - uses strtod instead of atof in decimal_to_double; > - decimal/binary FP conversion tests now accept some rounding variation: > > gdb_test "p (_Decimal64) 3.1" " = 3.(0999.*|1000.*)" > > > Is this version ok? Yes, but. I took a look on the error messages you added, and found a few that need some fixing: > + ret = asprintf (&buffer, "%.30Lg", value_as_double (from)); > + if (ret == -1) > + error (_("Error in conversion to decimal float.")); The documentation of asprintf says that -1 is returned if it fails to allocate memory for the buffer. So I think our error message should say the same. In any case, "error in conversion" is too vague to be useful. > + error (_("Unknown decimal floating point operation.")); Shouldn't this be internal_error? I mean, there couldn't be any valid op at this point, so this is a kind-of "can't happen" situation, isn't it? > + error (_("Don't know how to convert to decimal floating type.")); Wouldn't it be better to state the source type (from which we tried to convert) here as well? > + error (_("Integer-only operation on floating point number.")); Did you mean to say "Integer-only operation on floating point number is not allowed."? Or something else? As a GDB user, I'd be quite confused about the actual problem if I were to see this message. > Index: src-git/gdb/doc/gdb.texinfo > =================================================================== > --- src-git.orig/gdb/doc/gdb.texinfo 2007-12-28 01:11:37.000000000 -0200 > +++ src-git/gdb/doc/gdb.texinfo 2008-01-02 14:14:48.000000000 -0200 This part of your patch is approved. Thanks. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [patch 2/2] Wrap-up expression support for DFP. 2008-01-05 11:30 ` Eli Zaretskii @ 2008-01-07 16:20 ` Thiago Jung Bauermann 2008-01-07 17:09 ` Thiago Jung Bauermann 2008-01-07 21:09 ` Eli Zaretskii 0 siblings, 2 replies; 22+ messages in thread From: Thiago Jung Bauermann @ 2008-01-07 16:20 UTC (permalink / raw) To: Eli Zaretskii; +Cc: gdb-patches On Sat, 2008-01-05 at 13:30 +0200, Eli Zaretskii wrote: > > Is this version ok? > > Yes, but. I took a look on the error messages you added, and found a > few that need some fixing: Ok. > > + ret = asprintf (&buffer, "%.30Lg", value_as_double (from)); > > + if (ret == -1) > > + error (_("Error in conversion to decimal float.")); > > The documentation of asprintf says that -1 is returned if it fails to > allocate memory for the buffer. So I think our error message should > say the same. In any case, "error in conversion" is too vague to be > useful. Yes, that's what the libiberty implementation says. The Linux manpage is somewhat vague, though: "If memory allocation wasnât possible, or some other error occurs, these functions will return -1". The glibc implementation returns -1 for memory errors, or the return value of vfprintf, the manpage of which says that "If an output error is encountered, a negative value is returned.". So it seems that these functions don't let the caller know exactly what led them to failure. But it seems unlikely that an output error would happen when writing to a string, so I guess we could assume that negative return values are memory allocation errors. Then the error message could be changed to: error (_("Error in memory allocation for conversion to decimal float.")); > > > + error (_("Unknown decimal floating point operation.")); > > Shouldn't this be internal_error? I mean, there couldn't be any valid > op at this point, so this is a kind-of "can't happen" situation, isn't > it? > > > + error (_("Don't know how to convert to decimal floating type.")); > > Wouldn't it be better to state the source type (from which we tried to > convert) here as well? Actually, it turns out this else block is unreachable in the current code. All callers of value_args_as_decimal check if the types are either decfloat or integral before calling it. I'm not sure if it's better to leave the else part just in case the code changes, or remove it. If the message is left there, it can be changed to: error (_("Don't know how to convert from %s to %s."), TYPE_NAME (type1), TYPE_NAME (type2)); > > + error (_("Integer-only operation on floating point number.")); > > Did you mean to say "Integer-only operation on floating point number > is not allowed."? Or something else? As a GDB user, I'd be quite > confused about the actual problem if I were to see this message. I thought "Integer-only operation" already told the user that it's not allowed on floating point number. But I changed it to: error (_("Operation not valid for decimal floating point number.")); What do you think of the above? > > > Index: src-git/gdb/doc/gdb.texinfo > > =================================================================== > > --- src-git.orig/gdb/doc/gdb.texinfo 2007-12-28 01:11:37.000000000 -0200 > > +++ src-git/gdb/doc/gdb.texinfo 2008-01-02 14:14:48.000000000 -0200 > > This part of your patch is approved. Thanks. -- []'s Thiago Jung Bauermann Software Engineer IBM Linux Technology Center ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [patch 2/2] Wrap-up expression support for DFP. 2008-01-07 16:20 ` Thiago Jung Bauermann @ 2008-01-07 17:09 ` Thiago Jung Bauermann 2008-01-07 21:09 ` Eli Zaretskii 1 sibling, 0 replies; 22+ messages in thread From: Thiago Jung Bauermann @ 2008-01-07 17:09 UTC (permalink / raw) To: Eli Zaretskii; +Cc: gdb-patches > > > + error (_("Unknown decimal floating point operation.")); > > > > Shouldn't this be internal_error? I mean, there couldn't be any valid > > op at this point, so this is a kind-of "can't happen" situation, isn't > > it? Sorry, I skipped this one. You are right. I changed it to an internal_error. -- []'s Thiago Jung Bauermann Software Engineer IBM Linux Technology Center ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [patch 2/2] Wrap-up expression support for DFP. 2008-01-07 16:20 ` Thiago Jung Bauermann 2008-01-07 17:09 ` Thiago Jung Bauermann @ 2008-01-07 21:09 ` Eli Zaretskii 2008-01-07 22:39 ` Thiago Jung Bauermann 1 sibling, 1 reply; 22+ messages in thread From: Eli Zaretskii @ 2008-01-07 21:09 UTC (permalink / raw) To: Thiago Jung Bauermann; +Cc: gdb-patches > From: Thiago Jung Bauermann <bauerman@br.ibm.com> > Cc: gdb-patches@sourceware.org > Date: Mon, 07 Jan 2008 14:19:58 -0200 > > What do you think of the above? Fine with me, thanks. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [patch 2/2] Wrap-up expression support for DFP. 2008-01-07 21:09 ` Eli Zaretskii @ 2008-01-07 22:39 ` Thiago Jung Bauermann 0 siblings, 0 replies; 22+ messages in thread From: Thiago Jung Bauermann @ 2008-01-07 22:39 UTC (permalink / raw) To: Eli Zaretskii; +Cc: gdb-patches [-- Attachment #1: Type: text/plain, Size: 395 bytes --] On Mon, 2008-01-07 at 23:08 +0200, Eli Zaretskii wrote: > > From: Thiago Jung Bauermann <bauerman@br.ibm.com> > > Cc: gdb-patches@sourceware.org > > Date: Mon, 07 Jan 2008 14:19:58 -0200 > > > > What do you think of the above? > > Fine with me, thanks. Committed the attached version. Thanks again for your review. -- []'s Thiago Jung Bauermann Software Engineer IBM Linux Technology Center [-- Attachment #2: expressions.diff --] [-- Type: text/x-patch, Size: 40335 bytes --] gdb/ 2008-01-07 Thiago Jung Bauermann <bauerman@br.ibm.com> * Makefile.in (dfp.o): Depend on expression.h, gdbtypes.h and value.h. (valarith.o): Depend on dfp.h. (valops.o): Likewise. * dfp.c: Include expression.h, gdbtypes.h, value.h and dfp.h. (set_decnumber_context): New function. (decimal_check_errors): Likewise. (decimal_from_number): Likewise. (decimal_to_number): Likewise. (decimal_from_string): Use set_decnumber_context and decimal_check_errors. (decimal_from_integral): New function. (decimal_from_floating): Likewise. (decimal_to_double): Likewise. (promote_decimal): Likewise. (decimal_binop): Likewise. (decimal_is_zero): Likewise. (decimal_compare): Likewise. (decimal_convert): Likewise. * dfp.h (decimal_from_integral): New prototype. (decimal_from_floating): Likewise. (decimal_to_double): Likewise. (decimal_binop): Likewise. (decimal_is_zero): Likewise. (decimal_compare): Likewise. (decimal_convert): Likewise. * eval.c (evaluate_subexp_standard): Remove expect_type argument from call to value_from_decfloat. * valarith.c: Include dfp.h. (value_args_as_decimal): New function. (value_binop): Add if block to handle TYPE_CODE_DECFLOAT values. (value_logical_not): Likewise. (value_equal): Likewise. (value_less): Likewise. (value_pos): Likewise. (value_neg): Formatting fix. * valops.c: Include dfp.h. (value_cast): Add if block to handle TYPE_CODE_DECFLOAT values. * value.c (unpack_long): Add case to handle TYPE_CODE_DECFLOAT. (unpack_double): Add if block to handle TYPE_CODE_DECFLOAT. (value_from_decfloat): Remove expect_type argument. * value.h (value_from_decfloat): Update prototype. gdb/testsuite/ 2008-01-07 Thiago Jung Bauermann <bauerman@br.ibm.com> * gdb.base/dfp-exprs.exp (test_dfp_arithmetic_expressions): Add tests for expressions with decimal float values. (test_dfp_conversions): New function to test casts to and from decimal float types. Call test_dfp_conversions. * gdb.base/dfp-test.c (struct decstruct): Add float4 and double8 elements. (main): Initialize ds.float4 and ds.double8 elements. * gdb.base/dfp-test.exp (d32_set_tests): Fix typo. Adjust expect string to new error message. (d64_set_tests): Likewise. (d128_set_tests): Likewise. Add tests for expressions with decimal float variables. Add tests for conversions to and from decimal float types. gdb/doc 2008-01-07 Thiago Jung Bauermann <bauerman@br.ibm.com> * gdb.texinfo (C and C++): Add Decimal Floating Point format subsubsection. (Decimal Floating Point format): New subsubsection. Index: gdb/Makefile.in =================================================================== RCS file: /cvs/src/src/gdb/Makefile.in,v retrieving revision 1.971 diff -u -r1.971 Makefile.in --- gdb/Makefile.in 1 Jan 2008 22:53:09 -0000 1.971 +++ gdb/Makefile.in 7 Jan 2008 22:28:40 -0000 @@ -2046,7 +2046,8 @@ dummy-frame.o: dummy-frame.c $(defs_h) $(dummy_frame_h) $(regcache_h) \ $(frame_h) $(inferior_h) $(gdb_assert_h) $(frame_unwind_h) \ $(command_h) $(gdbcmd_h) $(gdb_string_h) -dfp.o: dfp.c $(defs_h) $(dfp_h) $(decimal128_h) $(decimal64_h) $(decimal32_h) +dfp.o: dfp.c $(defs_h) $(expression_h) $(gdbtypes_h) $(value_h) $(dfp_h) \ + $(decimal128_h) $(decimal64_h) $(decimal32_h) dwarf2expr.o: dwarf2expr.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(value_h) \ $(gdbcore_h) $(elf_dwarf2_h) $(dwarf2expr_h) dwarf2-frame.o: dwarf2-frame.c $(defs_h) $(dwarf2expr_h) $(elf_dwarf2_h) \ @@ -2910,12 +2911,12 @@ $(regcache_h) $(dis_asm_h) $(osabi_h) valarith.o: valarith.c $(defs_h) $(value_h) $(symtab_h) $(gdbtypes_h) \ $(expression_h) $(target_h) $(language_h) $(gdb_string_h) \ - $(doublest_h) $(infcall_h) + $(doublest_h) $(dfp_h) $(infcall_h) valops.o: valops.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(value_h) $(frame_h) \ $(inferior_h) $(gdbcore_h) $(target_h) $(demangle_h) $(language_h) \ $(gdbcmd_h) $(regcache_h) $(cp_abi_h) $(block_h) $(infcall_h) \ $(dictionary_h) $(cp_support_h) $(gdb_string_h) $(gdb_assert_h) \ - $(cp_support_h) $(observer_h) + $(cp_support_h) $(observer_h) $(dfp_h) valprint.o: valprint.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \ $(value_h) $(gdbcore_h) $(gdbcmd_h) $(target_h) $(language_h) \ $(annotate_h) $(valprint_h) $(floatformat_h) $(doublest_h) \ Index: gdb/dfp.c =================================================================== RCS file: /cvs/src/src/gdb/dfp.c,v retrieving revision 1.3 diff -u -r1.3 dfp.c --- gdb/dfp.c 1 Jan 2008 22:53:09 -0000 1.3 +++ gdb/dfp.c 7 Jan 2008 22:28:40 -0000 @@ -18,6 +18,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "defs.h" +#include "expression.h" +#include "gdbtypes.h" +#include "value.h" +#include "dfp.h" /* The order of the following headers is important for making sure decNumber structure is large enough to hold decimal128 digits. */ @@ -50,6 +54,89 @@ return; } +/* Helper function to get the appropriate libdecnumber context for each size + of decimal float. */ +static void +set_decnumber_context (decContext *ctx, int len) +{ + switch (len) + { + case 4: + decContextDefault (ctx, DEC_INIT_DECIMAL32); + break; + case 8: + decContextDefault (ctx, DEC_INIT_DECIMAL64); + break; + case 16: + decContextDefault (ctx, DEC_INIT_DECIMAL128); + break; + } + + ctx->traps = 0; +} + +/* Check for errors signaled in the decimal context structure. */ +static void +decimal_check_errors (decContext *ctx) +{ + /* An error here could be a division by zero, an overflow, an underflow or + an invalid operation (from the DEC_Errors constant in decContext.h). + Since GDB doesn't complain about division by zero, overflow or underflow + errors for binary floating, we won't complain about them for decimal + floating either. */ + if (ctx->status & DEC_IEEE_854_Invalid_operation) + { + /* Leave only the error bits in the status flags. */ + ctx->status &= DEC_IEEE_854_Invalid_operation; + error (_("Cannot perform operation: %s"), decContextStatusToString (ctx)); + } +} + +/* Helper function to convert from libdecnumber's appropriate representation + for computation to each size of decimal float. */ +static void +decimal_from_number (const decNumber *from, gdb_byte *to, int len) +{ + decContext set; + + set_decnumber_context (&set, len); + + switch (len) + { + case 4: + decimal32FromNumber ((decimal32 *) to, from, &set); + break; + case 8: + decimal64FromNumber ((decimal64 *) to, from, &set); + break; + case 16: + decimal128FromNumber ((decimal128 *) to, from, &set); + break; + } +} + +/* Helper function to convert each size of decimal float to libdecnumber's + appropriate representation for computation. */ +static void +decimal_to_number (const gdb_byte *from, int len, decNumber *to) +{ + switch (len) + { + case 4: + decimal32ToNumber ((decimal32 *) from, to); + break; + case 8: + decimal64ToNumber ((decimal64 *) from, to); + break; + case 16: + decimal128ToNumber ((decimal128 *) from, to); + break; + default: + error (_("Unknown decimal floating point type.\n")); + break; + } +} + /* Convert decimal type to its string representation. LEN is the length of the decimal type, 4 bytes for decimal32, 8 bytes for decimal64 and 16 bytes for decimal128. */ @@ -59,6 +146,7 @@ gdb_byte dec[16]; match_endianness (decbytes, len, dec); + switch (len) { case 4: @@ -85,21 +173,17 @@ decContext set; gdb_byte dec[16]; + set_decnumber_context (&set, len); + switch (len) { case 4: - decContextDefault (&set, DEC_INIT_DECIMAL32); - set.traps = 0; decimal32FromString ((decimal32 *) dec, string, &set); break; case 8: - decContextDefault (&set, DEC_INIT_DECIMAL64); - set.traps = 0; decimal64FromString ((decimal64 *) dec, string, &set); break; case 16: - decContextDefault (&set, DEC_INIT_DECIMAL128); - set.traps = 0; decimal128FromString ((decimal128 *) dec, string, &set); break; default: @@ -109,5 +193,208 @@ match_endianness (dec, len, decbytes); + /* Check for errors in the DFP operation. */ + decimal_check_errors (&set); + return 1; } + +/* Converts a value of an integral type to a decimal float of + specified LEN bytes. */ +void +decimal_from_integral (struct value *from, gdb_byte *to, int len) +{ + LONGEST l; + gdb_byte dec[16]; + decNumber number; + struct type *type; + + type = check_typedef (value_type (from)); + + if (TYPE_LENGTH (type) > 4) + /* libdecnumber can convert only 32-bit integers. */ + error (_("Conversion of large integer to a decimal floating type is not supported.")); + + l = value_as_long (from); + + if (TYPE_UNSIGNED (type)) + decNumberFromUInt32 (&number, (unsigned int) l); + else + decNumberFromInt32 (&number, (int) l); + + decimal_from_number (&number, dec, len); + match_endianness (dec, len, to); +} + +/* Converts a value of a float type to a decimal float of + specified LEN bytes. + + This is an ugly way to do the conversion, but libdecnumber does + not offer a direct way to do it. */ +void +decimal_from_floating (struct value *from, gdb_byte *to, int len) +{ + char *buffer; + int ret; + + ret = asprintf (&buffer, "%.30Lg", value_as_double (from)); + if (ret < 0) + error (_("Error in memory allocation for conversion to decimal float.")); + + decimal_from_string (to, len, buffer); + + free (buffer); +} + +/* Converts a decimal float of LEN bytes to a double value. */ +DOUBLEST +decimal_to_double (const gdb_byte *from, int len) +{ + char buffer[MAX_DECIMAL_STRING]; + + /* This is an ugly way to do the conversion, but libdecnumber does + not offer a direct way to do it. */ + decimal_to_string (from, len, buffer); + return strtod (buffer, NULL); +} + +/* Check if operands have the same size and convert them to the + biggest of the two if necessary. */ +static int +promote_decimal (gdb_byte *x, int len_x, gdb_byte *y, int len_y) +{ + int len_result; + decNumber number; + + if (len_x < len_y) + { + decimal_to_number (x, len_x, &number); + decimal_from_number (&number, x, len_y); + len_result = len_y; + } + else if (len_x > len_y) + { + decimal_to_number (y, len_y, &number); + decimal_from_number (&number, y, len_x); + len_result = len_x; + } + else + len_result = len_x; + + return len_result; +} + +/* Perform operation OP with operands X and Y and store value in RESULT. + If LEN_X and LEN_Y are not equal, RESULT will have the size of the biggest + of the two, and LEN_RESULT will be set accordingly. */ +void +decimal_binop (enum exp_opcode op, const gdb_byte *x, int len_x, + const gdb_byte *y, int len_y, gdb_byte *result, int *len_result) +{ + decContext set; + decNumber number1, number2, number3; + gdb_byte dec1[16], dec2[16], dec3[16]; + + match_endianness (x, len_x, dec1); + match_endianness (y, len_y, dec2); + + *len_result = promote_decimal (dec1, len_x, dec2, len_y); + + /* Both operands are of size *len_result from now on. */ + + decimal_to_number (dec1, *len_result, &number1); + decimal_to_number (dec2, *len_result, &number2); + + set_decnumber_context (&set, *len_result); + + switch (op) + { + case BINOP_ADD: + decNumberAdd (&number3, &number1, &number2, &set); + break; + case BINOP_SUB: + decNumberSubtract (&number3, &number1, &number2, &set); + break; + case BINOP_MUL: + decNumberMultiply (&number3, &number1, &number2, &set); + break; + case BINOP_DIV: + decNumberDivide (&number3, &number1, &number2, &set); + break; + case BINOP_EXP: + decNumberPower (&number3, &number1, &number2, &set); + break; + default: + internal_error (__FILE__, __LINE__, + _("Unknown decimal floating point operation.")); + break; + } + + /* Check for errors in the DFP operation. */ + decimal_check_errors (&set); + + decimal_from_number (&number3, dec3, *len_result); + + match_endianness (dec3, *len_result, result); +} + +/* Returns true if X (which is LEN bytes wide) is the number zero. */ +int +decimal_is_zero (const gdb_byte *x, int len) +{ + decNumber number; + gdb_byte dec[16]; + + match_endianness (x, len, dec); + decimal_to_number (dec, len, &number); + + return decNumberIsZero (&number); +} + +/* Compares two numbers numerically. If X is less than Y then the return value + will be -1. If they are equal, then the return value will be 0. If X is + greater than the Y then the return value will be 1. */ +int +decimal_compare (const gdb_byte *x, int len_x, const gdb_byte *y, int len_y) +{ + decNumber number1, number2, result; + decContext set; + gdb_byte dec1[16], dec2[16]; + int len_result; + + match_endianness (x, len_x, dec1); + match_endianness (y, len_y, dec2); + + len_result = promote_decimal (dec1, len_x, dec2, len_y); + + decimal_to_number (dec1, len_result, &number1); + decimal_to_number (dec2, len_result, &number2); + + set_decnumber_context (&set, len_result); + + decNumberCompare (&result, &number1, &number2, &set); + + /* Check for errors in the DFP operation. */ + decimal_check_errors (&set); + + if (decNumberIsNaN (&result)) + error (_("Comparison with an invalid number (NaN).")); + else if (decNumberIsZero (&result)) + return 0; + else if (decNumberIsNegative (&result)) + return -1; + else + return 1; +} + +/* Convert a decimal value from a decimal type with LEN_FROM bytes to a + decimal type with LEN_TO bytes. */ +void +decimal_convert (const gdb_byte *from, int len_from, gdb_byte *to, + int len_to) +{ + decNumber number; + + decimal_to_number (from, len_from, &number); + decimal_from_number (&number, to, len_to); +} Index: gdb/dfp.h =================================================================== RCS file: /cvs/src/src/gdb/dfp.h,v retrieving revision 1.2 diff -u -r1.2 dfp.h --- gdb/dfp.h 1 Jan 2008 22:53:09 -0000 1.2 +++ gdb/dfp.h 7 Jan 2008 22:28:40 -0000 @@ -31,5 +31,14 @@ extern void decimal_to_string (const gdb_byte *, int, char *); extern int decimal_from_string (gdb_byte *, int, const char *); +extern void decimal_from_integral (struct value *from, gdb_byte *to, int len); +extern void decimal_from_floating (struct value *from, gdb_byte *to, int len); +extern DOUBLEST decimal_to_double (const gdb_byte *from, int len); +extern void decimal_binop (enum exp_opcode, const gdb_byte *, int, + const gdb_byte *, int, gdb_byte *, int *); +extern int decimal_is_zero (const gdb_byte *x, int len); +extern int decimal_compare (const gdb_byte *x, int len_x, const gdb_byte *y, int len_y); +extern void decimal_convert (const gdb_byte *from, int len_from, gdb_byte *to, + int len_to); #endif Index: gdb/eval.c =================================================================== RCS file: /cvs/src/src/gdb/eval.c,v retrieving revision 1.75 diff -u -r1.75 eval.c --- gdb/eval.c 3 Jan 2008 04:11:15 -0000 1.75 +++ gdb/eval.c 7 Jan 2008 22:28:41 -0000 @@ -458,8 +458,8 @@ case OP_DECFLOAT: (*pos) += 3; - return value_from_decfloat (expect_type, exp->elts[pc + 1].type, - exp->elts[pc + 2].decfloatconst); + return value_from_decfloat (exp->elts[pc + 1].type, + exp->elts[pc + 2].decfloatconst); case OP_VAR_VALUE: (*pos) += 3; Index: gdb/valarith.c =================================================================== RCS file: /cvs/src/src/gdb/valarith.c,v retrieving revision 1.51 diff -u -r1.51 valarith.c --- gdb/valarith.c 1 Jan 2008 22:53:13 -0000 1.51 +++ gdb/valarith.c 7 Jan 2008 22:28:42 -0000 @@ -28,6 +28,7 @@ #include "language.h" #include "gdb_string.h" #include "doublest.h" +#include "dfp.h" #include <math.h> #include "infcall.h" @@ -741,6 +742,62 @@ } \f +/* Obtain decimal value of arguments for binary operation, converting from + other types if one of them is not decimal floating point. */ +static void +value_args_as_decimal (struct value *arg1, struct value *arg2, + gdb_byte *x, int *len_x, gdb_byte *y, int *len_y) +{ + struct type *type1, *type2; + + type1 = check_typedef (value_type (arg1)); + type2 = check_typedef (value_type (arg2)); + + /* At least one of the arguments must be of decimal float type. */ + gdb_assert (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT + || TYPE_CODE (type2) == TYPE_CODE_DECFLOAT); + + if (TYPE_CODE (type1) == TYPE_CODE_FLT + || TYPE_CODE (type2) == TYPE_CODE_FLT) + /* The DFP extension to the C language does not allow mixing of + * decimal float types with other float types in expressions + * (see WDTR 24732, page 12). */ + error (_("Mixing decimal floating types with other floating types is not allowed.")); + + /* Obtain decimal value of arg1, converting from other types + if necessary. */ + + if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT) + { + *len_x = TYPE_LENGTH (type1); + memcpy (x, value_contents (arg1), *len_x); + } + else if (is_integral_type (type1)) + { + *len_x = TYPE_LENGTH (type2); + decimal_from_integral (arg1, x, *len_x); + } + else + error (_("Don't know how to convert from %s to %s."), TYPE_NAME (type1), + TYPE_NAME (type2)); + + /* Obtain decimal value of arg2, converting from other types + if necessary. */ + + if (TYPE_CODE (type2) == TYPE_CODE_DECFLOAT) + { + *len_y = TYPE_LENGTH (type2); + memcpy (y, value_contents (arg2), *len_y); + } + else if (is_integral_type (type2)) + { + *len_y = TYPE_LENGTH (type1); + decimal_from_integral (arg2, y, *len_y); + } + else + error (_("Don't know how to convert from %s to %s."), TYPE_NAME (type1), + TYPE_NAME (type2)); +} /* Perform a binary operation on two operands which have reasonable representations as integers or floats. This includes booleans, @@ -759,14 +816,55 @@ type1 = check_typedef (value_type (arg1)); type2 = check_typedef (value_type (arg2)); - if ((TYPE_CODE (type1) != TYPE_CODE_FLT && !is_integral_type (type1)) + if ((TYPE_CODE (type1) != TYPE_CODE_FLT + && TYPE_CODE (type1) != TYPE_CODE_DECFLOAT && !is_integral_type (type1)) || - (TYPE_CODE (type2) != TYPE_CODE_FLT && !is_integral_type (type2))) + (TYPE_CODE (type2) != TYPE_CODE_FLT + && TYPE_CODE (type2) != TYPE_CODE_DECFLOAT && !is_integral_type (type2))) error (_("Argument to arithmetic operation not a number or boolean.")); - if (TYPE_CODE (type1) == TYPE_CODE_FLT + if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT || - TYPE_CODE (type2) == TYPE_CODE_FLT) + TYPE_CODE (type2) == TYPE_CODE_DECFLOAT) + { + struct type *v_type; + int len_v1, len_v2, len_v; + gdb_byte v1[16], v2[16]; + gdb_byte v[16]; + + value_args_as_decimal (arg1, arg2, v1, &len_v1, v2, &len_v2); + + switch (op) + { + case BINOP_ADD: + case BINOP_SUB: + case BINOP_MUL: + case BINOP_DIV: + case BINOP_EXP: + decimal_binop (op, v1, len_v1, v2, len_v2, v, &len_v); + break; + + default: + error (_("Operation not valid for decimal floating point number.")); + } + + if (TYPE_CODE (type1) != TYPE_CODE_DECFLOAT) + /* If arg1 is not a decimal float, the type of the result is the type + of the decimal float argument, arg2. */ + v_type = type2; + else if (TYPE_CODE (type2) != TYPE_CODE_DECFLOAT) + /* Same logic, for the case where arg2 is not a decimal float. */ + v_type = type1; + else + /* len_v is equal either to len_v1 or to len_v2. the type of the + result is the type of the argument with the same length as v. */ + v_type = (len_v == len_v1)? type1 : type2; + + val = value_from_decfloat (v_type, v); + } + else if (TYPE_CODE (type1) == TYPE_CODE_FLT + || + TYPE_CODE (type2) == TYPE_CODE_FLT) { /* FIXME-if-picky-about-floating-accuracy: Should be doing this in target format. real.c in GCC probably has the necessary @@ -1177,6 +1275,8 @@ if (TYPE_CODE (type1) == TYPE_CODE_FLT) return 0 == value_as_double (arg1); + else if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT) + return decimal_is_zero (value_contents (arg1), TYPE_LENGTH (type1)); len = TYPE_LENGTH (type1); p = value_contents (arg1); @@ -1255,6 +1355,16 @@ DOUBLEST d = value_as_double (arg1); return d == value_as_double (arg2); } + else if ((code1 == TYPE_CODE_DECFLOAT || is_int1) + && (code2 == TYPE_CODE_DECFLOAT || is_int2)) + { + gdb_byte v1[16], v2[16]; + int len_v1, len_v2; + + value_args_as_decimal (arg1, arg2, v1, &len_v1, v2, &len_v2); + + return decimal_compare (v1, len_v1, v2, len_v2) == 0; + } /* FIXME: Need to promote to either CORE_ADDR or LONGEST, whichever is bigger. */ @@ -1319,6 +1429,16 @@ DOUBLEST d = value_as_double (arg1); return d < value_as_double (arg2); } + else if ((code1 == TYPE_CODE_DECFLOAT || is_int1) + && (code2 == TYPE_CODE_DECFLOAT || is_int2)) + { + gdb_byte v1[16], v2[16]; + int len_v1, len_v2; + + value_args_as_decimal (arg1, arg2, v1, &len_v1, v2, &len_v2); + + return decimal_compare (v1, len_v1, v2, len_v2) == -1; + } else if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR) return value_as_address (arg1) < value_as_address (arg2); @@ -1350,6 +1470,8 @@ if (TYPE_CODE (type) == TYPE_CODE_FLT) return value_from_double (type, value_as_double (arg1)); + else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT) + return value_from_decfloat (type, value_contents (arg1)); else if (is_integral_type (type)) { /* Perform integral promotion for ANSI C/C++. FIXME: What about @@ -1382,7 +1504,7 @@ int len = TYPE_LENGTH (type); gdb_byte decbytes[16]; /* a decfloat is at most 128 bits long */ - memcpy(decbytes, value_contents(arg1), len); + memcpy (decbytes, value_contents (arg1), len); if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_LITTLE) decbytes[len-1] = decbytes[len - 1] | 0x80; Index: gdb/valops.c =================================================================== RCS file: /cvs/src/src/gdb/valops.c,v retrieving revision 1.180 diff -u -r1.180 valops.c --- gdb/valops.c 1 Jan 2008 22:53:13 -0000 1.180 +++ gdb/valops.c 7 Jan 2008 22:28:43 -0000 @@ -36,6 +36,7 @@ #include "infcall.h" #include "dictionary.h" #include "cp-support.h" +#include "dfp.h" #include <errno.h> #include "gdb_string.h" @@ -338,7 +339,8 @@ code2 = TYPE_CODE_INT; scalar = (code2 == TYPE_CODE_INT || code2 == TYPE_CODE_FLT - || code2 == TYPE_CODE_ENUM || code2 == TYPE_CODE_RANGE); + || code2 == TYPE_CODE_DECFLOAT || code2 == TYPE_CODE_ENUM + || code2 == TYPE_CODE_RANGE); if (code1 == TYPE_CODE_STRUCT && code2 == TYPE_CODE_STRUCT @@ -357,6 +359,22 @@ } if (code1 == TYPE_CODE_FLT && scalar) return value_from_double (type, value_as_double (arg2)); + else if (code1 == TYPE_CODE_DECFLOAT && scalar) + { + int dec_len = TYPE_LENGTH (type); + gdb_byte dec[16]; + + if (code2 == TYPE_CODE_FLT) + decimal_from_floating (arg2, dec, dec_len); + else if (code2 == TYPE_CODE_DECFLOAT) + decimal_convert (value_contents (arg2), TYPE_LENGTH (type2), + dec, dec_len); + else + /* The only option left is an integral type. */ + decimal_from_integral (arg2, dec, dec_len); + + return value_from_decfloat (type, dec); + } else if ((code1 == TYPE_CODE_INT || code1 == TYPE_CODE_ENUM || code1 == TYPE_CODE_RANGE) && (scalar || code2 == TYPE_CODE_PTR Index: gdb/value.c =================================================================== RCS file: /cvs/src/src/gdb/value.c,v retrieving revision 1.54 diff -u -r1.54 value.c --- gdb/value.c 1 Jan 2008 22:53:13 -0000 1.54 +++ gdb/value.c 7 Jan 2008 22:28:44 -0000 @@ -982,6 +982,7 @@ error (_("Invalid floating value found in program.")); return foo; } + /* Extract a value as a C pointer. Does not deallocate the value. Note that val's type may not actually be a pointer; value_as_long handles all the cases. */ @@ -1127,6 +1128,11 @@ case TYPE_CODE_FLT: return extract_typed_floating (valaddr, type); + case TYPE_CODE_DECFLOAT: + /* libdecnumber has a function to convert from decimal to integer, but + it doesn't work when the decimal number has a fractional part. */ + return decimal_to_double (valaddr, len); + case TYPE_CODE_PTR: case TYPE_CODE_REF: /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure @@ -1184,6 +1190,8 @@ return extract_typed_floating (valaddr, type); } + else if (code == TYPE_CODE_DECFLOAT) + return decimal_to_double (valaddr, len); else if (nosign) { /* Unsigned -- be sure we compensate for signed LONGEST. */ @@ -1643,23 +1651,12 @@ } struct value * -value_from_decfloat (struct type *expect_type, struct type *type, - gdb_byte decbytes[16]) +value_from_decfloat (struct type *type, const gdb_byte *dec) { struct value *val = allocate_value (type); - int len = TYPE_LENGTH (type); - if (expect_type) - { - int expect_len = TYPE_LENGTH (expect_type); - char decstr[MAX_DECIMAL_STRING]; - int real_len; - - decimal_to_string (decbytes, len, decstr); - decimal_from_string (decbytes, expect_len, decstr); - } + memcpy (value_contents_raw (val), dec, TYPE_LENGTH (type)); - memcpy (value_contents_raw (val), decbytes, len); return val; } Index: gdb/value.h =================================================================== RCS file: /cvs/src/src/gdb/value.h,v retrieving revision 1.105 diff -u -r1.105 value.h --- gdb/value.h 1 Jan 2008 22:53:13 -0000 1.105 +++ gdb/value.h 7 Jan 2008 22:28:44 -0000 @@ -280,9 +280,8 @@ extern struct value *value_from_longest (struct type *type, LONGEST num); extern struct value *value_from_pointer (struct type *type, CORE_ADDR addr); extern struct value *value_from_double (struct type *type, DOUBLEST num); -extern struct value *value_from_decfloat (struct type *expect_type, - struct type *type, - gdb_byte decbytes[16]); +extern struct value *value_from_decfloat (struct type *type, + const gdb_byte *decbytes); extern struct value *value_from_string (char *string); extern struct value *value_at (struct type *type, CORE_ADDR addr); Index: gdb/doc/gdb.texinfo =================================================================== RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v retrieving revision 1.454 diff -u -r1.454 gdb.texinfo --- gdb/doc/gdb.texinfo 5 Jan 2008 21:50:44 -0000 1.454 +++ gdb/doc/gdb.texinfo 7 Jan 2008 22:28:52 -0000 @@ -9136,6 +9136,7 @@ * C Checks:: C and C@t{++} type and range checks * Debugging C:: @value{GDBN} and C * Debugging C Plus Plus:: @value{GDBN} features for C@t{++} +* Decimal Floating Point:: Numbers in Decimal Floating Point format @end menu @node C Operators @@ -9604,6 +9605,28 @@ @xref{Completion,, Command Completion}, for details on how to do this. @end table +@node Decimal Floating Point +@subsubsection Decimal Floating Point format +@cindex decimal floating point format + +@value{GDBN} can examine, set and perform computations with numbers in +decimal floating point format, which in the C language correspond to the +@code{_Decimal32}, @code{_Decimal64} and @code{_Decimal128} types as +specified by the extension to support decimal floating-point arithmetic. + +There are two encodings in use, depending on the architecture: BID (Binary +Integer Decimal) for x86 and x86-64, and DPD (Densely Packed Decimal) for +PowerPC. @value{GDBN} will use the appropriate encoding for the configured +target. + +Because of a limitation in @file{libdecnumber}, the library used by @value{GDBN} +to manipulate decimal floating point numbers, it is not possible to convert +(using a cast, for example) integers wider than 32-bit to decimal float. + +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. + @node Objective-C @subsection Objective-C Index: gdb/testsuite/gdb.base/dfp-exprs.exp =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.base/dfp-exprs.exp,v retrieving revision 1.2 diff -u -r1.2 dfp-exprs.exp --- gdb/testsuite/gdb.base/dfp-exprs.exp 1 Jan 2008 22:53:18 -0000 1.2 +++ gdb/testsuite/gdb.base/dfp-exprs.exp 7 Jan 2008 22:28:52 -0000 @@ -74,14 +74,102 @@ proc test_dfp_arithmetic_expressions {} { -# Arithmetic operations for DFP types are not yet implemented in GDB. -# These tests are to verify that they will generate expected error messages. + # _Decimal32 operands. + gdb_test "p 1.4df + 1.2df" " = 2.6" + gdb_test "p 1.4df - 1.2df" " = 0.2" + gdb_test "p 1.4df * 1.2df" " = 1.68" + gdb_test "p 1.4df / 1.2df" " = 1.166667" - gdb_test "p 1.4df + 1.2df" "Argument to arithmetic operation not a number or boolean.*" - gdb_test "p 1.4df - 1.2df" ".*Argument to arithmetic operation not a number or boolean.*" - gdb_test "p 1.4df * 1.2df" "Argument to arithmetic operation not a number or boolean.*" - gdb_test "p 1.4df / 1.2df" "Argument to arithmetic operation not a number or boolean.*" + # _Decimal64 operands. + gdb_test "p 1.4dd + 1.2dd" " = 2.6" + gdb_test "p 1.4dd - 1.2dd" " = 0.2" + gdb_test "p 1.4dd * 1.2dd" " = 1.68" + gdb_test "p 1.4dd / 1.2dd" " = 1.166666666666667" + # _Decimal128 operands. + gdb_test "p 1.4dl + 1.2dl" " = 2.6" + gdb_test "p 1.4dl - 1.2dl" " = 0.2" + gdb_test "p 1.4dl * 1.2dl" " = 1.68" + gdb_test "p 1.4dl / 1.2dl" " = 1.166666666666666666666666666666667" + + # Test type of operation result. + gdb_test "ptype 2.df + 2.df" "= _Decimal32" + gdb_test "ptype 2.dd + 2.dd" "= _Decimal64" + gdb_test "ptype 2.dl + 2.dl" "= _Decimal128" + + # Mixture of different _Decimal sizes. + gdb_test "p 2.1df + 2.7dd" "= 4.8" + gdb_test "p 2.1dd + 2.7df" "= 4.8" + gdb_test "p 2.6df + 2.7dl" "= 5.3" + gdb_test "p 2.6dl + 2.7df" "= 5.3" + gdb_test "p 2.3dd + 2.2dl" "= 4.5" + gdb_test "p 2.3dl + 2.2dd" "= 4.5" + gdb_test "ptype 2.df + 2.dd" "= _Decimal64" + gdb_test "ptype 2.df + 2.dl" "= _Decimal128" + gdb_test "ptype 2.dd + 2.dl" "= _Decimal128" + + # Mixture of Decimal and integral operands + gdb_test "p 1.2df + 1" " = 2.2" + gdb_test "p 2 + 1.7dd" " = 3.7" + gdb_test "p 3 + 2.1dl" " = 5.1" + gdb_test "ptype 1.2df + 1" " = _Decimal32" + gdb_test "ptype 2 + 1.7dd" " = _Decimal64" + gdb_test "ptype 3 + 2.1dl" " = _Decimal128" + + # Reject operation with integral larger than 32-bits + gdb_test "p 1.2df + 2ll" "Conversion of large integer to a decimal floating type is not supported." + + # Reject operation with DFP and Binary FP + gdb_test "p 1.2df + 1.2f" "Mixing decimal floating types with other floating types is not allowed." + + # Test other operations with DFP operands + gdb_test "p !0.df" " = 1" + gdb_test "p !0.dd" " = 1" + gdb_test "p !0.dl" " = 1" + gdb_test "p !0.5df" " = 0" + gdb_test "p !0.5dd" " = 0" + gdb_test "p !0.5dl" " = 0" + + gdb_test "p 1.2df == 1.2df" " = 1" + gdb_test "p 1.2df == 1.2dd" " = 1" + gdb_test "p 1.2df == 1.2dl" " = 1" + gdb_test "p 1.2dd == 1.2df" " = 1" + gdb_test "p 1.2dd == 1.2dl" " = 1" + gdb_test "p 1.2dl == 1.2df" " = 1" + gdb_test "p 1.2dl == 1.2dd" " = 1" + gdb_test "p 1.2df == 1.3df" " = 0" + gdb_test "p 1.2df == 1.3dd" " = 0" + gdb_test "p 1.2df == 1.3dl" " = 0" + gdb_test "p 1.2dd == 1.3df" " = 0" + gdb_test "p 1.2dd == 1.3dl" " = 0" + gdb_test "p 1.2dl == 1.3df" " = 0" + gdb_test "p 1.2dl == 1.3dd" " = 0" + + gdb_test "p +1.2df" " = 1.2" + gdb_test "p +1.2dd" " = 1.2" + gdb_test "p +1.2dl" " = 1.2" + + gdb_test "p 1.2df < 1.3df" " = 1" + gdb_test "p 1.2df < 1.3dd" " = 1" + gdb_test "p 1.2dl < 1.3df" " = 1" + gdb_test "p 1.2dd < 1.3dd" " = 1" + gdb_test "p 1.2dd < 1.3dl" " = 1" + gdb_test "p 1.2dl < 1.3dl" " = 1" + gdb_test "p 1.2dl < 1.3df" " = 1" + gdb_test "p 1.2df > 1" " = 1" + gdb_test "p 1.2dl > 2" " = 0" + gdb_test "p 2 > 1.2dd" " = 1" + gdb_test "p 2 > 3.1dl" " = 0" +} + +proc test_dfp_conversions {} { + # Test cast to and from DFP values, and between DFPs of different sizes + + gdb_test "p (float) -0.1df" " = -0.(0999.*|1000.*)" + gdb_test "p (int) 8.3dd" " = 8" + gdb_test "p (_Decimal64) 3.1" " = 3.(0999.*|1000.*)" + gdb_test "p (_Decimal128) 3.7df" " = 3.7" + gdb_test "p (_Decimal32) 4" " = 4" } # Start with a fresh gdb. @@ -92,3 +180,4 @@ test_dfp_literals_accepted test_dfp_arithmetic_expressions +test_dfp_conversions Index: gdb/testsuite/gdb.base/dfp-test.c =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.base/dfp-test.c,v retrieving revision 1.2 diff -u -r1.2 dfp-test.c --- gdb/testsuite/gdb.base/dfp-test.c 1 Jan 2008 22:53:18 -0000 1.2 +++ gdb/testsuite/gdb.base/dfp-test.c 7 Jan 2008 22:28:52 -0000 @@ -26,6 +26,8 @@ { int int4; long long8; + float float4; + double double8; _Decimal32 dec32; _Decimal64 dec64; _Decimal128 dec128; @@ -85,6 +87,8 @@ ds.int4 = 1; ds.long8 = 2; + ds.float4 = 3.1; + ds.double8 = 4.2; ds.dec32 = 1.2345df; ds.dec64 = 1.2345dd; ds.dec128 = 1.2345dl; Index: gdb/testsuite/gdb.base/dfp-test.exp =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.base/dfp-test.exp,v retrieving revision 1.3 diff -u -r1.3 dfp-test.exp --- gdb/testsuite/gdb.base/dfp-test.exp 1 Jan 2008 22:53:18 -0000 1.3 +++ gdb/testsuite/gdb.base/dfp-test.exp 7 Jan 2008 22:28:52 -0000 @@ -18,6 +18,53 @@ # This file is part of the gdb testsuite. It is intended to test that # gdb could correctly handle decimal floating point introduced in IEEE 754R. +if $tracelevel then { + strace $tracelevel +} + +set testfile "dfp-test" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +# Try to compile the test case. If we can't, assume the +# toolchain does not yet provide DFP support and bail out. +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {quiet debug}] != "" } { + verbose "Skipping DFP tests." + 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 +} + +# Detect the size of the target's basic types (from gdb.base/long_long.exp). + +proc get_valueof { fmt exp default } { + global gdb_prompt + send_gdb "print${fmt} ${exp}\n" + gdb_expect { + -re "\\$\[0-9\]* = (\[-\]*\[0-9\]*).*$gdb_prompt $" { + set val $expect_out(1,string) + } + timeout { + set val ${default} + } + } + return ${val} +} + +proc get_sizeof { type default } { + return [get_valueof "/d" "sizeof (${type})" $default] +} + +set sizeof_long [get_sizeof "long" 4] + proc d32_set_tests {} { gdb_test "p d32=123.45df" " = 123.45" @@ -43,10 +90,10 @@ 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=12345.df" " = 12345" "12345. is a 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)" + gdb_test "p d32=1.23Edf" ".*Conversion syntax.*" "1.23E is an invalid number" + gdb_test "p d32=1.23E45Adf" ".*Conversion syntax.*" "1.23E45A is an invalid number" } proc d64_set_tests {} { @@ -75,8 +122,8 @@ # 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)" + gdb_test "p d64=1.23Edd" ".*Conversion syntax.*" "1.23E is an invalid number" + gdb_test "p d64=1.23E45Add" ".*Conversion syntax.*" "1.23E45A is an invalid number" } proc d128_set_tests {} { @@ -104,33 +151,8 @@ # 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} -# Try to compile the test case. If we can't, assume the -# toolchain does not yet provide DFP support and bail out. -if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {quiet debug}] != "" } { - verbose "Skipping DFP tests." - 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 + gdb_test "p d128=1.23Edl" ".*Conversion syntax.*" "1.23E is an invalid number" + gdb_test "p d128=1.23E45Adl" ".*Conversion syntax.*" "1.23E45A is an invalid number" } # Different tests on 32-bits decimal floating point, including the printing @@ -237,6 +259,57 @@ gdb_test "print ds.dec64" " = 1.2345" gdb_test "print ds.dec128" " = 1.2345" +# Test expressions with DFP variables. + +gdb_test "print d32 + ds.dec32" " = 1.3345" +gdb_test "print d64 + ds.dec64" " = 1.3345" +gdb_test "print d128 + ds.dec128" " = 1.3345" + +# Test conversion between different _Decimal sizes. + +gdb_test "ptype d64 + ds.dec32" " = volatile _Decimal64" +gdb_test "ptype d128 + ds.dec32" " = volatile _Decimal128" +gdb_test "ptype d128 + ds.dec64" " = volatile _Decimal128" + +# Mixture of Decimal and integral operands +gdb_test "p d32 + 1" " = 1.1" +gdb_test "p 2 + d64" " = 2.1" +gdb_test "p ds.int4 + d128" " = 1.1" +gdb_test "ptype d32 + 1" " = volatile _Decimal32" +gdb_test "ptype ds.int4 + d128" " = volatile _Decimal128" + +# Test other operations with DFP operands +gdb_test "p !d32" " = 0" +gdb_test "p !d64" " = 0" +gdb_test "p !d128" " = 0" +gdb_test "p +d32" " = 0.1" +gdb_test "p +d64" " = 0.1" +gdb_test "p +d128" " = 0.1" +gdb_test "p d64 == d128" " = 1" +gdb_test "p d128 == ds.dec32" " = 0" +gdb_test "p d128 == d32" " = 1" +gdb_test "p ds.dec32 == ds.dec64" " = 1" +gdb_test "p d32 < ds.dec32" " = 1" +gdb_test "p d64 < ds.dec64" " = 1" +gdb_test "p d128 < ds.dec128" " = 1" +gdb_test "p ds.dec32 < d32" " = 0" +gdb_test "p d64 > ds.dec64" " = 0" +gdb_test "p ds.dec128 > d128 " " = 1" +gdb_test "p d32 < ds.int4" " = 1" +gdb_test "p ds.int4 > d32" " = 1" +gdb_test "p ds.dec32 < ds.int4" " = 0" +gdb_test "p ds.int4 > ds.dec64" " = 0" +gdb_test "p ds.dec128 > ds.int4" " = 1" + +# Reject operation with integral larger than 32-bits +if { ${sizeof_long} > 4 } { + gdb_test "p d32 + ds.long8" "Conversion of large integer to a decimal floating type is not supported." +} + +# Reject operation with DFP and Binary FP +gdb_test "p d64 + ds.float4" "Mixing decimal floating types with other floating types is not allowed." +gdb_test "p ds.double8 + d128" "Mixing decimal floating types with other floating types is not allowed." + # The following tests are intended to verify that gdb can handle "d1=d2" # and "d1=-d2" correctly. @@ -246,3 +319,12 @@ gdb_test "print ds.dec32 = -d32" " = -0.1" gdb_test "print ds.dec64 = -d64" " = -0.1" gdb_test "print ds.dec128 = -d128" " = -0.1" + +# Test cast to and from DFP values + +gdb_test "print ds.double8 = ds.dec64" " = -0.(0999.*|1000.*)" +gdb_test "print ds.dec64 = ds.float4" " = 3.(0999.*|1000.*)" +gdb_test "print ds.dec128 = -ds.double8" " = 0.(0999.*|1000.*)" +gdb_test "print ds.dec128 = ds.dec32" " = -0.1" +gdb_test "print ds.dec32 = ds.int4" " = 1" +gdb_test "print ds.int4 = 7.3dl" " = 7" ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [patch 2/2] Wrap-up expression support for DFP. 2007-12-21 16:12 ` Eli Zaretskii 2007-12-21 16:30 ` Andreas Schwab 2007-12-27 7:40 ` Thiago Jung Bauermann @ 2007-12-28 6:16 ` Thiago Jung Bauermann 2007-12-29 12:53 ` Eli Zaretskii 2 siblings, 1 reply; 22+ messages in thread From: Thiago Jung Bauermann @ 2007-12-28 6:16 UTC (permalink / raw) To: Eli Zaretskii; +Cc: gdb-patches [-- Attachment #1: Type: text/plain, Size: 748 bytes --] On Fri, 2007-12-21 at 18:04 +0200, Eli Zaretskii wrote: > > Date: Thu, 20 Dec 2007 03:49:28 -0200 > > From: Thiago Jung Bauermann <bauerman@br.ibm.com> > > > > - doesn't support conversion of 64-bit integers to decimal float, > > because of libdecnumber limitation; > > - error checking in decimal float operations ignore underflow, overflow > > and divide by zero to imitate binary float implementation; > > These limitations should be documented in the manual, I think: they > will affect GDB users, right? I couldn't find an appropriate place to put these in the manual, so I went ahead and created a new sub-section, under "Examining Data". What do you think? -- []'s Thiago Jung Bauermann Software Engineer IBM Linux Technology Center [-- Attachment #2: dfp-doc.diff --] [-- Type: text/x-patch, Size: 1947 bytes --] 2007-12-28 Thiago Jung Bauermann <bauerman@br.ibm.com> * gdb.texinfo (Examining Data): Add Decimal Floating Point format subsection. (Decimal Floating Point format): New subsection. Index: src-git/gdb/doc/gdb.texinfo =================================================================== --- src-git.orig/gdb/doc/gdb.texinfo 2007-12-28 01:11:37.000000000 -0200 +++ src-git/gdb/doc/gdb.texinfo 2007-12-28 02:16:56.000000000 -0200 @@ -5494,6 +5494,7 @@ Table}. * Character Sets:: Debugging programs that use a different character set than GDB does * Caching Remote Data:: Data caching for remote targets +* Decimal Floating Point:: Numbers in Decimal Floating Point format @end menu @node Expressions @@ -7473,6 +7474,28 @@ the data cache operation. @end table +@node Decimal Floating Point +@section Decimal Floating Point format +@cindex decimal floating point format + +@value{GDBN} can examine, set and perform computations with numbers in +decimal floating point format, which in the C language correspond to the +@code{_Decimal32}, @code{_Decimal64} and @code{_Decimal128} types as +specified by the extension to support decimal floating-point arithmetic. + +There are two encodings in use, depending on the architecture: BID (Binary +Integer Decimal) for x86 and x86-64, and DPD (Densely Packed Decimal) for +PowerPC. GDB will use the appropriate encoding for the configured target. + +Because of a limitation in libdecnumber, the library used by @value{GDBN} +to manipulate decimal floating point numbers, it is not possible to convert +(using a cast, for example) integers wider than 32-bit to decimal float. + +In addition, in order to imitate @value{GDBN}'s behaviour with binary floating +point computations, error checking in decimal float operations ignore underflow, +overflow and divide by zero exceptions. + + @node Macros @chapter C Preprocessor Macros ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [patch 2/2] Wrap-up expression support for DFP. 2007-12-28 6:16 ` Thiago Jung Bauermann @ 2007-12-29 12:53 ` Eli Zaretskii 2008-01-02 16:42 ` Thiago Jung Bauermann 0 siblings, 1 reply; 22+ messages in thread From: Eli Zaretskii @ 2007-12-29 12:53 UTC (permalink / raw) To: Thiago Jung Bauermann; +Cc: gdb-patches > From: Thiago Jung Bauermann <bauerman@br.ibm.com> > Cc: gdb-patches@sourceware.org > Date: Fri, 28 Dec 2007 02:33:07 -0200 > > I couldn't find an appropriate place to put these in the manual, so I > went ahead and created a new sub-section, under "Examining Data". What > do you think? I think a better place is in the "C and C++" section. These are C/C++ data types, aren't they? > +There are two encodings in use, depending on the architecture: BID (Binary > +Integer Decimal) for x86 and x86-64, and DPD (Densely Packed Decimal) for > +PowerPC. GDB will use the appropriate encoding for the configured target. PLease use "@value{GDBN}" instead of a literal "GDB". > +Because of a limitation in libdecnumber, the library used by @value{GDBN} "libdecnumber" is a file name, so it should have the @file markup. > +point computations, error checking in decimal float operations ignore underflow, "ignores". Other than these comments, the patch is okay to go in (as a subsection of the "C and C++" section. Thanks. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [patch 2/2] Wrap-up expression support for DFP. 2007-12-29 12:53 ` Eli Zaretskii @ 2008-01-02 16:42 ` Thiago Jung Bauermann 0 siblings, 0 replies; 22+ messages in thread From: Thiago Jung Bauermann @ 2008-01-02 16:42 UTC (permalink / raw) To: Eli Zaretskii; +Cc: gdb-patches On Sat, 2007-12-29 at 13:47 +0200, Eli Zaretskii wrote: > > From: Thiago Jung Bauermann <bauerman@br.ibm.com> > > Cc: gdb-patches@sourceware.org > > Date: Fri, 28 Dec 2007 02:33:07 -0200 > > > > I couldn't find an appropriate place to put these in the manual, so I > > went ahead and created a new sub-section, under "Examining Data". What > > do you think? > > I think a better place is in the "C and C++" section. These are C/C++ > data types, aren't they? > > > +There are two encodings in use, depending on the architecture: BID (Binary > > +Integer Decimal) for x86 and x86-64, and DPD (Densely Packed Decimal) for > > +PowerPC. GDB will use the appropriate encoding for the configured target. > > PLease use "@value{GDBN}" instead of a literal "GDB". > > > +Because of a limitation in libdecnumber, the library used by @value{GDBN} > > "libdecnumber" is a file name, so it should have the @file markup. > > > +point computations, error checking in decimal float operations ignore underflow, > > "ignores". > > Other than these comments, the patch is okay to go in (as a subsection > of the "C and C++" section. Ok, changed the patch to abide to all observations above. I will commit it when the code patch is approved as well. Thanks for your review. -- []'s Thiago Jung Bauermann Software Engineer IBM Linux Technology Center ^ permalink raw reply [flat|nested] 22+ messages in thread
end of thread, other threads:[~2008-01-07 22:39 UTC | newest] Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2007-12-20 5:55 [patch 0/2] Complete expression support for Decimal Floating Point Thiago Jung Bauermann 2007-12-20 5:55 ` [patch 1/2] Recognize DFP types in casts Thiago Jung Bauermann 2007-12-20 15:24 ` Daniel Jacobowitz 2007-12-20 16:48 ` Thiago Jung Bauermann 2007-12-20 16:54 ` Thiago Jung Bauermann 2007-12-20 16:57 ` Daniel Jacobowitz 2007-12-20 17:21 ` Thiago Jung Bauermann 2007-12-20 8:03 ` [patch 2/2] Wrap-up expression support for DFP Thiago Jung Bauermann 2007-12-21 16:12 ` Eli Zaretskii 2007-12-21 16:30 ` Andreas Schwab 2007-12-21 16:38 ` Eli Zaretskii 2007-12-27 7:40 ` Thiago Jung Bauermann 2007-12-29 11:21 ` Eli Zaretskii 2008-01-02 20:07 ` Thiago Jung Bauermann 2008-01-05 11:30 ` Eli Zaretskii 2008-01-07 16:20 ` Thiago Jung Bauermann 2008-01-07 17:09 ` Thiago Jung Bauermann 2008-01-07 21:09 ` Eli Zaretskii 2008-01-07 22:39 ` Thiago Jung Bauermann 2007-12-28 6:16 ` Thiago Jung Bauermann 2007-12-29 12:53 ` Eli Zaretskii 2008-01-02 16:42 ` Thiago Jung Bauermann
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox