From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from rock.gnat.com (rock.gnat.com [205.232.38.15]) by sourceware.org (Postfix) with ESMTP id 07628385E005 for ; Sun, 8 Nov 2020 06:30:58 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 07628385E005 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=adacore.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=brobecke@adacore.com Received: from localhost (localhost.localdomain [127.0.0.1]) by filtered-rock.gnat.com (Postfix) with ESMTP id D89BB1168E3; Sun, 8 Nov 2020 01:30:57 -0500 (EST) X-Virus-Scanned: Debian amavisd-new at gnat.com Received: from rock.gnat.com ([127.0.0.1]) by localhost (rock.gnat.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id 6fI5mjet+gIY; Sun, 8 Nov 2020 01:30:57 -0500 (EST) Received: from tron.gnat.com (tron.gnat.com [IPv6:2620:20:4000:0:46a8:42ff:fe0e:e294]) by rock.gnat.com (Postfix) with ESMTP id C8BA11164A5; Sun, 8 Nov 2020 01:30:57 -0500 (EST) Received: by tron.gnat.com (Postfix, from userid 4233) id C7BA7103; Sun, 8 Nov 2020 01:30:57 -0500 (EST) From: Joel Brobecker To: gdb-patches@sourceware.org Cc: Joel Brobecker Subject: [PATCH 8/9] Add support for fixed-point type arithmetic Date: Sun, 8 Nov 2020 01:30:16 -0500 Message-Id: <1604817017-25807-9-git-send-email-brobecker@adacore.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1604817017-25807-1-git-send-email-brobecker@adacore.com> References: <1604817017-25807-1-git-send-email-brobecker@adacore.com> X-Spam-Status: No, score=-9.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 08 Nov 2020 06:30:59 -0000 This patch adds support for binary operations on fixed-point values, as well as for the negative unary operator. gdb/ChangeLog: * eval.c (binop_promote): Add fixed-point type handling. * valarith.c (fixed_point_binop): New function. (scalar_binop): Add fixed-point type handling. (value_neg): Add fixed-point type handling. * valops.c (value_cast_to_fixed_point): New function. (value_cast): Add fixed-point type handling. gdb/testsuite/ChangeLog: * gdb.dwarf2/dw2-fixed-point.exp: Add arithmetic tests. --- gdb/eval.c | 3 + gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp | 18 ++++++ gdb/valarith.c | 91 +++++++++++++++++++++++++++- gdb/valops.c | 74 +++++++++++++++++++++- 4 files changed, 183 insertions(+), 3 deletions(-) diff --git a/gdb/eval.c b/gdb/eval.c index 8d0c574..308f477 100644 --- a/gdb/eval.c +++ b/gdb/eval.c @@ -430,6 +430,9 @@ binop_promote (const struct language_defn *language, struct gdbarch *gdbarch, && !is_integral_type (type2))) return; + if (is_fixed_point_type (type1) || is_fixed_point_type (type2)) + return; + if (type1->code () == TYPE_CODE_DECFLOAT || type2->code () == TYPE_CODE_DECFLOAT) { diff --git a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp index 2e72bff..a3c8ff1 100644 --- a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp +++ b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp @@ -143,6 +143,24 @@ gdb_test "print pck.fp1_range_var" \ gdb_test "print /x pck.fp1_range_var" \ " = 0x1" +gdb_test "print pck.fp1_var + 0.25" \ + " = 0.5" + +gdb_test "print pck.fp2_var - pck.fp2_var" \ + " = 0" + +gdb_test "print pck.fp3_var * 1" \ + " = 0.1" + +gdb_test "print pck.fp3_var / pck.fp3_var" \ + " = 1" + +gdb_test "print pck.fp1_range_var - 0.5" \ + " = 0.5" + +gdb_test "print -pck.fp1_var" \ + " = -0.25" + # Set the language to LANG and do a ptype test on pck__fp1_var, # pck__fp2_var and pck__fp3_var, verifying that the output matches # FP1_RE, FP2_RE, FP2_RE (resp.). diff --git a/gdb/valarith.c b/gdb/valarith.c index f6caf3d..65a6f13 100644 --- a/gdb/valarith.c +++ b/gdb/valarith.c @@ -881,6 +881,84 @@ value_args_as_target_float (struct value *arg1, struct value *arg2, type2->name ()); } +/* Assuming at last one of ARG1 or ARG2 is a fixed point value, + perform the binary operation OP on these two operands, and return + the resulting value (also as a fixed point). */ + +static struct value * +fixed_point_binop (struct value *arg1, struct value *arg2, enum exp_opcode op) +{ + struct type *type1 = check_typedef (value_type (arg1)); + struct type *type2 = check_typedef (value_type (arg2)); + + struct value *val; + + gdb_assert (is_fixed_point_type (type1) || is_fixed_point_type (type2)); + if (!is_fixed_point_type (type1)) + { + arg1 = value_cast (type2, arg1); + type1 = type2; + } + if (!is_fixed_point_type (type2)) + { + arg2 = value_cast (type1, arg2); + type2 = type1; + } + + gdb_mpq v1, v2, res; + v1.read_fixed_point (value_contents (arg1), TYPE_LENGTH (type1), + type_byte_order (type1), type1->is_unsigned (), + fixed_point_scaling_factor (type1)); + v2.read_fixed_point (value_contents (arg2), TYPE_LENGTH (type2), + type_byte_order (type2), type2->is_unsigned (), + fixed_point_scaling_factor (type2)); + +#define INIT_VAL_WITH_FIXED_POINT_VAL(RESULT) \ + do { \ + val = allocate_value (type1); \ + (RESULT).write_fixed_point \ + (value_contents_raw (val), TYPE_LENGTH (type1), \ + type_byte_order (type1), type1->is_unsigned (), \ + fixed_point_scaling_factor (type1)); \ + } while (0) + + switch (op) + { + case BINOP_ADD: + mpq_add (res.val, v1.val, v2.val); + INIT_VAL_WITH_FIXED_POINT_VAL (res); + break; + + case BINOP_SUB: + mpq_sub (res.val, v1.val, v2.val); + INIT_VAL_WITH_FIXED_POINT_VAL (res); + break; + + case BINOP_MIN: + INIT_VAL_WITH_FIXED_POINT_VAL (mpq_cmp (v1.val, v2.val) < 0 ? v1 : v2); + break; + + case BINOP_MAX: + INIT_VAL_WITH_FIXED_POINT_VAL (mpq_cmp (v1.val, v2.val) > 0 ? v1 : v2); + break; + + case BINOP_MUL: + mpq_mul (res.val, v1.val, v2.val); + INIT_VAL_WITH_FIXED_POINT_VAL (res); + break; + + case BINOP_DIV: + mpq_div (res.val, v1.val, v2.val); + INIT_VAL_WITH_FIXED_POINT_VAL (res); + break; + + default: + error (_("Integer-only operation on fixed point number.")); + } + + return val; +} + /* A helper function that finds the type to use for a binary operation involving TYPE1 and TYPE2. */ @@ -1054,10 +1132,17 @@ scalar_binop (struct value *arg1, struct value *arg2, enum exp_opcode op) || type2->code () == TYPE_CODE_COMPLEX) return complex_binop (arg1, arg2, op); - if ((!is_floating_value (arg1) && !is_integral_type (type1)) - || (!is_floating_value (arg2) && !is_integral_type (type2))) + if ((!is_floating_value (arg1) + && !is_integral_type (type1) + && !is_fixed_point_type (type1)) + || (!is_floating_value (arg2) + && !is_integral_type (type2) + && !is_fixed_point_type (type2))) error (_("Argument to arithmetic operation not a number or boolean.")); + if (is_fixed_point_type (type1) || is_fixed_point_type (type2)) + return fixed_point_binop (arg1, arg2, op); + if (is_floating_type (type1) || is_floating_type (type2)) { result_type = promotion_type (type1, type2); @@ -1753,6 +1838,8 @@ value_neg (struct value *arg1) if (is_integral_type (type) || is_floating_type (type)) return value_binop (value_from_longest (type, 0), arg1, BINOP_SUB); + else if (is_fixed_point_type (type)) + return value_binop (value_zero (type, not_lval), arg1, BINOP_SUB); else if (type->code () == TYPE_CODE_ARRAY && type->is_vector ()) { struct value *tmp, *val = allocate_value (type); diff --git a/gdb/valops.c b/gdb/valops.c index 4df2538..0f84a70 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -331,6 +331,60 @@ value_cast_pointers (struct type *type, struct value *arg2, return arg2; } +/* Assuming that TO_TYPE is a fixed point type, return a value + corresponding to the cast of FROM_VAL to that type. */ + +static struct value * +value_cast_to_fixed_point (struct type *to_type, struct value *from_val) +{ + struct type *from_type = value_type (from_val); + + if (from_type == to_type) + return from_val; + + gdb_mpq vq; + + /* Extract the value as a rational number. */ + + if (is_floating_type (from_type)) + { + double d = target_float_to_host_double (value_contents (from_val), + from_type); + mpq_set_d (vq.val, d); + } + + else if (is_integral_type (from_type) || is_fixed_point_type (from_type)) + { + gdb_mpz vz; + + vz.read (value_contents (from_val), TYPE_LENGTH (from_type), + type_byte_order (from_type), from_type->is_unsigned ()); + mpq_set_z (vq.val, vz.val); + + if (is_fixed_point_type (from_type)) + mpq_mul (vq.val, vq.val, fixed_point_scaling_factor (from_type).val); + } + + else + error (_("Invalid conversion from type %s to fixed point type %s"), + from_type->name (), to_type->name ()); + + /* Divide that value by the scaling factor to obtain the unscaled + value, first in rational form, and then in integer form. */ + + mpq_div (vq.val, vq.val, fixed_point_scaling_factor (to_type).val); + gdb_mpz unscaled = vq.get_rounded (); + + /* Finally, create the result value, and pack the unscaled value + in it. */ + struct value *result = allocate_value (to_type); + unscaled.write (value_contents_raw (result), + TYPE_LENGTH (to_type), type_byte_order (to_type), + to_type->is_unsigned ()); + + return result; +} + /* Cast value ARG2 to type TYPE and return as a value. More general than a C cast: accepts any two types of the same length, and if ARG2 is an lvalue it can be cast into anything at all. */ @@ -349,6 +403,9 @@ value_cast (struct type *type, struct value *arg2) if (value_type (arg2) == type) return arg2; + if (is_fixed_point_type (type)) + return value_cast_to_fixed_point (type, arg2); + /* Check if we are casting struct reference to struct reference. */ if (TYPE_IS_REFERENCE (check_typedef (type))) { @@ -439,7 +496,8 @@ value_cast (struct type *type, struct value *arg2) scalar = (code2 == TYPE_CODE_INT || code2 == TYPE_CODE_FLT || code2 == TYPE_CODE_DECFLOAT || code2 == TYPE_CODE_ENUM - || code2 == TYPE_CODE_RANGE); + || code2 == TYPE_CODE_RANGE + || is_fixed_point_type (type2)); if ((code1 == TYPE_CODE_STRUCT || code1 == TYPE_CODE_UNION) && (code2 == TYPE_CODE_STRUCT || code2 == TYPE_CODE_UNION) @@ -460,6 +518,20 @@ value_cast (struct type *type, struct value *arg2) value_contents_raw (v), type); return v; } + else if (is_fixed_point_type (type2)) + { + gdb_mpq fp_val; + + fp_val.read_fixed_point + (value_contents (arg2), TYPE_LENGTH (type2), + type_byte_order (type2), type2->is_unsigned (), + fixed_point_scaling_factor (type2)); + + struct value *v = allocate_value (to_type); + target_float_from_host_double (value_contents_raw (v), + to_type, mpq_get_d (fp_val.val)); + return v; + } /* The only option left is an integral type. */ if (type2->is_unsigned ()) -- 2.1.4