From patchwork Tue Sep 5 18:20:50 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ulrich Weigand X-Patchwork-Id: 22634 Received: (qmail 53654 invoked by alias); 5 Sep 2017 18:21:03 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 53609 invoked by uid 89); 5 Sep 2017 18:21:03 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-11.7 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.2 spammy= X-HELO: mx0a-001b2d01.pphosted.com Received: from mx0a-001b2d01.pphosted.com (HELO mx0a-001b2d01.pphosted.com) (148.163.156.1) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 05 Sep 2017 18:20:56 +0000 Received: from pps.filterd (m0098404.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id v85IJKTm033853 for ; Tue, 5 Sep 2017 14:20:55 -0400 Received: from e06smtp10.uk.ibm.com (e06smtp10.uk.ibm.com [195.75.94.106]) by mx0a-001b2d01.pphosted.com with ESMTP id 2csx6d8x5n-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Tue, 05 Sep 2017 14:20:55 -0400 Received: from localhost by e06smtp10.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 5 Sep 2017 19:20:52 +0100 Received: from b06cxnps3075.portsmouth.uk.ibm.com (9.149.109.195) by e06smtp10.uk.ibm.com (192.168.101.140) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Tue, 5 Sep 2017 19:20:51 +0100 Received: from d06av23.portsmouth.uk.ibm.com (d06av23.portsmouth.uk.ibm.com [9.149.105.59]) by b06cxnps3075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id v85IKoDZ28639250 for ; Tue, 5 Sep 2017 18:20:50 GMT Received: from d06av23.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id D185CA404D for ; Tue, 5 Sep 2017 19:17:10 +0100 (BST) Received: from d06av23.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id B29B2A4040 for ; Tue, 5 Sep 2017 19:17:10 +0100 (BST) Received: from oc3748833570.ibm.com (unknown [9.164.150.234]) by d06av23.portsmouth.uk.ibm.com (Postfix) with ESMTP for ; Tue, 5 Sep 2017 19:17:10 +0100 (BST) Received: by oc3748833570.ibm.com (Postfix, from userid 1000) id 23037D8086F; Tue, 5 Sep 2017 20:20:50 +0200 (CEST) Subject: [RFC][04/19] Target FP: Clean up some DFP interfaces To: gdb-patches@sourceware.org Date: Tue, 5 Sep 2017 20:20:50 +0200 (CEST) From: "Ulrich Weigand" MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 17090518-0040-0000-0000-000003D5CD92 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 17090518-0041-0000-0000-000025D652C0 Message-Id: <20170905182050.23037D8086F@oc3748833570.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-09-05_07:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 suspectscore=1 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1707230000 definitions=main-1709050267 [RFC][04/19] Target FP: Clean up some DFP interfaces This cleans up a number of interfaces in dfp.c / dfp.h. Specifically: - The decimal_from_string / decimal_to_string routines are C++-ified to operate on std::string instead of character buffers. In the decimal_from_string, the boolean return value now actually is bool instead of an int. - The decimal_from_integral and decimal_from_doublest routines take an struct value as input. This is not really appropriate at the low level the DFP routines sit, so this replaced them with new routines decimal_from_longest / decimal_from_ulongest / decimal_from_doublest that operate on contents instead. - To mirror the decimal_from_[u]longest, a new decimal_to_longest routine is added as well, which can be used in unpack_long to avoid an unnecessary conversion via DOUBLEST. Note that the decimal_from_longest / decimal_from_ulongest routines are actually more powerful than decimal_from_integral: the old routine would only accept integer *types* of at most four bytes size, while the new routines accept all integer *values* that fit in an [u]int32_t, no matter which type they came from. The DFP tests are updated to allow for this larger range of integers that can be converted. Bye, Ulrich ChangeLog: * dfp.h (MAX_DECIMAL_STRING): Move to dfp.c. (decimal_to_string): Return std::string object. (decimal_from_string): Accept std::string object. Return bool. (decimal_from_integral, decimal_from_doublest): Remove. (decimal_from_longest): Add prototype. (decimal_from_ulongest): Likewise. (decimal_to_longest): Likewise. (decimal_from_doublest): Likewise. * dfp.c: Do not include "gdbtypes.h" or "value.h". (MAX_DECIMAL_STRING): Move here. (decimal_to_string): Return std::string object. (decimal_from_string): Accept std::string object. Return bool. (decimal_from_integral): Remove, replace by ... (decimal_from_longest, decimal_from_ulongest): ... these new functions. (decimal_to_longest): New function. (decimal_from_floating): Remove, replace by ... (decimal_from_doublest): ... this new function. (decimal_to_doublest): Update to new decimal_to_string interface. * value.c (unpack_long): Use decimal_to_longest. * valops.c (value_cast): Use decimal_from_doublest instead of decimal_from_floating. Use decimal_from_[u]longest isntead of decimal_from_integral. * valarith.c (value_args_as_decimal): Likewise. * valprint.c (print_decimal_floating): Update to new decimal_to_string interface. * printcmd.c (printf_decfloat): Likewise. * c-exp.y (parse_number): Update to new decimal_from_string interface. testsuite/ChangeLog: * gdb.base/dfp-exprs.exp: Update tests to larger range of supported integer-to-dfp conversion. * gdb.base/dfp-test.exp: Likewise. Index: binutils-gdb/gdb/dfp.c =================================================================== --- binutils-gdb.orig/gdb/dfp.c +++ binutils-gdb/gdb/dfp.c @@ -19,8 +19,6 @@ #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 @@ -30,6 +28,10 @@ #include "dpd/decimal64.h" #include "dpd/decimal32.h" +/* When using decimal128, this is the maximum string length + 1 + (value comes from libdecnumber's DECIMAL128_String constant). */ +#define MAX_DECIMAL_STRING 43 + /* In GDB, we are using an array of gdb_byte to represent decimal values. They are stored in host byte order. This routine does the conversion if the target byte order is different. */ @@ -142,37 +144,42 @@ decimal_to_number (const gdb_byte *from, /* 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. */ -void +std::string decimal_to_string (const gdb_byte *decbytes, int len, - enum bfd_endian byte_order, char *s) + enum bfd_endian byte_order) { gdb_byte dec[16]; match_endianness (decbytes, len, byte_order, dec); + std::string result; + result.resize (MAX_DECIMAL_STRING); + switch (len) { case 4: - decimal32ToString ((decimal32 *) dec, s); + decimal32ToString ((decimal32 *) dec, &result[0]); break; case 8: - decimal64ToString ((decimal64 *) dec, s); + decimal64ToString ((decimal64 *) dec, &result[0]); break; case 16: - decimal128ToString ((decimal128 *) dec, s); + decimal128ToString ((decimal128 *) dec, &result[0]); break; default: error (_("Unknown decimal floating point type.")); break; } + + return result; } /* Convert the string form of a decimal value to its decimal representation. LEN is the length of the decimal type, 4 bytes for decimal32, 8 bytes for decimal64 and 16 bytes for decimal128. */ -int +bool decimal_from_string (gdb_byte *decbytes, int len, enum bfd_endian byte_order, - const char *string) + std::string string) { decContext set; gdb_byte dec[16]; @@ -182,13 +189,13 @@ decimal_from_string (gdb_byte *decbytes, switch (len) { case 4: - decimal32FromString ((decimal32 *) dec, string, &set); + decimal32FromString ((decimal32 *) dec, string.c_str (), &set); break; case 8: - decimal64FromString ((decimal64 *) dec, string, &set); + decimal64FromString ((decimal64 *) dec, string.c_str (), &set); break; case 16: - decimal128FromString ((decimal128 *) dec, string, &set); + decimal128FromString ((decimal128 *) dec, string.c_str (), &set); break; default: error (_("Unknown decimal floating point type.")); @@ -200,66 +207,77 @@ decimal_from_string (gdb_byte *decbytes, /* Check for errors in the DFP operation. */ decimal_check_errors (&set); - return 1; + return true; } -/* Converts a value of an integral type to a decimal float of - specified LEN bytes. */ +/* Converts a LONGEST to a decimal float of specified LEN bytes. */ void -decimal_from_integral (struct value *from, - gdb_byte *to, int len, enum bfd_endian byte_order) +decimal_from_longest (LONGEST from, + gdb_byte *to, int len, enum bfd_endian byte_order) { - LONGEST l; gdb_byte dec[16]; decNumber number; - struct type *type; + if ((int32_t) from != from) + /* libdecnumber can convert only 32-bit integers. */ + error (_("Conversion of large integer to a " + "decimal floating type is not supported.")); - type = check_typedef (value_type (from)); + decNumberFromInt32 (&number, (int32_t) from); - if (TYPE_LENGTH (type) > 4) + decimal_from_number (&number, dec, len); + match_endianness (dec, len, byte_order, to); +} + +/* Converts a ULONGEST to a decimal float of specified LEN bytes. */ +void +decimal_from_ulongest (ULONGEST from, + gdb_byte *to, int len, enum bfd_endian byte_order) +{ + gdb_byte dec[16]; + decNumber number; + + if ((uint32_t) from != from) /* 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); + decNumberFromUInt32 (&number, (uint32_t) from); decimal_from_number (&number, dec, len); match_endianness (dec, len, byte_order, to); } +/* Converts a decimal float of LEN bytes to a LONGEST. */ +LONGEST +decimal_to_longest (const gdb_byte *from, int len, enum bfd_endian byte_order) +{ + /* libdecnumber has a function to convert from decimal to integer, but + it doesn't work when the decimal number has a fractional part. */ + std::string str = decimal_to_string (from, len, byte_order); + return strtoll (str.c_str (), NULL, 10); +} + /* 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, +decimal_from_doublest (DOUBLEST from, gdb_byte *to, int len, enum bfd_endian byte_order) { - char *buffer; - - buffer = xstrprintf ("%.30" DOUBLEST_PRINT_FORMAT, value_as_double (from)); - - decimal_from_string (to, len, byte_order, buffer); - - xfree (buffer); + std::string str = string_printf ("%.30" DOUBLEST_PRINT_FORMAT, from); + decimal_from_string (to, len, byte_order, str); } /* Converts a decimal float of LEN bytes to a double value. */ DOUBLEST decimal_to_doublest (const gdb_byte *from, int len, enum bfd_endian byte_order) { - 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, byte_order, buffer); - return strtod (buffer, NULL); + std::string str = decimal_to_string (from, len, byte_order); + return strtod (str.c_str (), NULL); } /* Perform operation OP with operands X and Y with sizes LEN_X and LEN_Y Index: binutils-gdb/gdb/dfp.h =================================================================== --- binutils-gdb.orig/gdb/dfp.h +++ binutils-gdb/gdb/dfp.h @@ -28,16 +28,16 @@ #include "doublest.h" /* For DOUBLEST. */ #include "expression.h" /* For enum exp_opcode. */ -/* When using decimal128, this is the maximum string length + 1 - * (value comes from libdecnumber's DECIMAL128_String constant). */ -#define MAX_DECIMAL_STRING 43 - -extern void decimal_to_string (const gdb_byte *, int, enum bfd_endian, char *); -extern int decimal_from_string (gdb_byte *, int, enum bfd_endian, - const char *); -extern void decimal_from_integral (struct value *from, gdb_byte *to, +extern std::string decimal_to_string (const gdb_byte *, int, enum bfd_endian); +extern bool decimal_from_string (gdb_byte *, int, enum bfd_endian, + std::string string); +extern void decimal_from_longest (LONGEST from, gdb_byte *to, + int len, enum bfd_endian byte_order); +extern void decimal_from_ulongest (ULONGEST from, gdb_byte *to, int len, enum bfd_endian byte_order); -extern void decimal_from_floating (struct value *from, gdb_byte *to, +extern LONGEST decimal_to_longest (const gdb_byte *from, int len, + enum bfd_endian byte_order); +extern void decimal_from_doublest (DOUBLEST from, gdb_byte *to, int len, enum bfd_endian byte_order); extern DOUBLEST decimal_to_doublest (const gdb_byte *from, int len, enum bfd_endian byte_order); Index: binutils-gdb/gdb/value.c =================================================================== --- binutils-gdb.orig/gdb/value.c +++ binutils-gdb/gdb/value.c @@ -2931,9 +2931,7 @@ unpack_long (struct type *type, const gd return (LONGEST) 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 (LONGEST) decimal_to_doublest (valaddr, len, byte_order); + return decimal_to_longest (valaddr, len, byte_order); case TYPE_CODE_PTR: case TYPE_CODE_REF: Index: binutils-gdb/gdb/valops.c =================================================================== --- binutils-gdb.orig/gdb/valops.c +++ binutils-gdb/gdb/valops.c @@ -473,13 +473,18 @@ value_cast (struct type *type, struct va gdb_byte dec[16]; if (code2 == TYPE_CODE_FLT) - decimal_from_floating (arg2, dec, dec_len, byte_order); + decimal_from_doublest (value_as_double (arg2), + dec, dec_len, byte_order); else if (code2 == TYPE_CODE_DECFLOAT) decimal_convert (value_contents (arg2), TYPE_LENGTH (type2), byte_order, dec, dec_len, byte_order); + /* The only option left is an integral type. */ + else if (TYPE_UNSIGNED (type2)) + decimal_from_ulongest (value_as_long (arg2), + dec, dec_len, byte_order); else - /* The only option left is an integral type. */ - decimal_from_integral (arg2, dec, dec_len, byte_order); + decimal_from_longest (value_as_long (arg2), + dec, dec_len, byte_order); return value_from_decfloat (to_type, dec); } Index: binutils-gdb/gdb/valarith.c =================================================================== --- binutils-gdb.orig/gdb/valarith.c +++ binutils-gdb/gdb/valarith.c @@ -884,7 +884,10 @@ value_args_as_decimal (struct value *arg { *byte_order_x = gdbarch_byte_order (get_type_arch (type2)); *len_x = TYPE_LENGTH (type2); - decimal_from_integral (arg1, x, *len_x, *byte_order_x); + if (TYPE_UNSIGNED (type1)) + decimal_from_ulongest (value_as_long (arg1), x, *len_x, *byte_order_x); + else + decimal_from_longest (value_as_long (arg1), x, *len_x, *byte_order_x); } else error (_("Don't know how to convert from %s to %s."), TYPE_NAME (type1), @@ -903,7 +906,10 @@ value_args_as_decimal (struct value *arg { *byte_order_y = gdbarch_byte_order (get_type_arch (type1)); *len_y = TYPE_LENGTH (type1); - decimal_from_integral (arg2, y, *len_y, *byte_order_y); + if (TYPE_UNSIGNED (type2)) + decimal_from_ulongest (value_as_long (arg2), y, *len_y, *byte_order_y); + else + decimal_from_longest (value_as_long (arg2), y, *len_y, *byte_order_y); } else error (_("Don't know how to convert from %s to %s."), TYPE_NAME (type1), Index: binutils-gdb/gdb/valprint.c =================================================================== --- binutils-gdb.orig/gdb/valprint.c +++ binutils-gdb/gdb/valprint.c @@ -1478,12 +1478,10 @@ print_decimal_floating (const gdb_byte * struct ui_file *stream) { enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type)); - char decstr[MAX_DECIMAL_STRING]; unsigned len = TYPE_LENGTH (type); - decimal_to_string (valaddr, len, byte_order, decstr); - fputs_filtered (decstr, stream); - return; + std::string str = decimal_to_string (valaddr, len, byte_order); + fputs_filtered (str.c_str (), stream); } void Index: binutils-gdb/gdb/printcmd.c =================================================================== --- binutils-gdb.orig/gdb/printcmd.c +++ binutils-gdb/gdb/printcmd.c @@ -2314,7 +2314,6 @@ printf_decfloat (struct ui_file *stream, int dfp_len = 16; gdb_byte dec[16]; struct type *dfp_type = NULL; - char decstr[MAX_DECIMAL_STRING]; /* Points to the end of the string so that we can go back and check for DFP length modifiers. */ @@ -2362,10 +2361,9 @@ printf_decfloat (struct ui_file *stream, dfp_ptr = (gdb_byte *) value_contents (dfp_value); - decimal_to_string (dfp_ptr, dfp_len, byte_order, decstr); - - /* Print the DFP value. */ - fprintf_filtered (stream, "%s", decstr); + /* Convert the value to a string and print it. */ + std::string str = decimal_to_string (dfp_ptr, dfp_len, byte_order); + fputs_filtered (str.c_str (), stream); #endif } Index: binutils-gdb/gdb/c-exp.y =================================================================== --- binutils-gdb.orig/gdb/c-exp.y +++ binutils-gdb/gdb/c-exp.y @@ -1791,37 +1791,31 @@ parse_number (struct parser_state *par_s if (len >= 2 && p[len - 2] == 'd' && p[len - 1] == 'f') { - p[len - 2] = '\0'; putithere->typed_val_decfloat.type = parse_type (par_state)->builtin_decfloat; decimal_from_string (putithere->typed_val_decfloat.val, 4, gdbarch_byte_order (parse_gdbarch (par_state)), - p); - p[len - 2] = 'd'; + std::string (p, len - 2)); return DECFLOAT; } if (len >= 2 && p[len - 2] == 'd' && p[len - 1] == 'd') { - p[len - 2] = '\0'; putithere->typed_val_decfloat.type = parse_type (par_state)->builtin_decdouble; decimal_from_string (putithere->typed_val_decfloat.val, 8, gdbarch_byte_order (parse_gdbarch (par_state)), - p); - p[len - 2] = 'd'; + std::string (p, len - 2)); return DECFLOAT; } if (len >= 2 && p[len - 2] == 'd' && p[len - 1] == 'l') { - p[len - 2] = '\0'; putithere->typed_val_decfloat.type = parse_type (par_state)->builtin_declong; decimal_from_string (putithere->typed_val_decfloat.val, 16, gdbarch_byte_order (parse_gdbarch (par_state)), - p); - p[len - 2] = 'd'; + std::string (p, len - 2)); return DECFLOAT; } Index: binutils-gdb/gdb/testsuite/gdb.base/dfp-exprs.exp =================================================================== --- binutils-gdb.orig/gdb/testsuite/gdb.base/dfp-exprs.exp +++ binutils-gdb/gdb/testsuite/gdb.base/dfp-exprs.exp @@ -113,7 +113,10 @@ proc test_dfp_arithmetic_expressions {} 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." + gdb_test "p 1.2dd + 2ll" "= 3.2" + gdb_test "p 1.2dd + 2147483648ll" "Conversion of large integer to a decimal floating type is not supported." + gdb_test "p 1.2dd + 2147483648ull" "= 2147483649.2" + gdb_test "p 1.2dd + 4294967296ull" "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." Index: binutils-gdb/gdb/testsuite/gdb.base/dfp-test.exp =================================================================== --- binutils-gdb.orig/gdb/testsuite/gdb.base/dfp-test.exp +++ binutils-gdb/gdb/testsuite/gdb.base/dfp-test.exp @@ -282,6 +282,7 @@ gdb_test "whatis d128 + ds.dec64" " = vo gdb_test "p d32 + 1" " = 1.1" gdb_test "p 2 + d64" " = 2.1" gdb_test "p ds.int4 + d128" " = 1.1" +gdb_test "p d32 + ds.long8" " = 2.1" gdb_test "ptype d32 + 1" " = volatile _Decimal32" gdb_test "ptype ds.int4 + d128" " = volatile _Decimal128" @@ -308,11 +309,6 @@ 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."