From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gateway30.websitewelcome.com (gateway30.websitewelcome.com [192.185.197.25]) by sourceware.org (Postfix) with ESMTPS id BC826394880C for ; Fri, 20 Mar 2020 21:53:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org BC826394880C Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=tromey.com Authentication-Results: sourceware.org; spf=fail smtp.mailfrom=tom@tromey.com Received: from cm11.websitewelcome.com (cm11.websitewelcome.com [100.42.49.5]) by gateway30.websitewelcome.com (Postfix) with ESMTP id 5E78B1037 for ; Fri, 20 Mar 2020 16:53:43 -0500 (CDT) Received: from box5379.bluehost.com ([162.241.216.53]) by cmsmtp with SMTP id FPaJjfieJSl8qFPaJjE8bm; Fri, 20 Mar 2020 16:53:43 -0500 X-Authority-Reason: nr=8 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=tromey.com; s=default; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Sender:Reply-To:MIME-Version:Content-Type:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=WHkgSjIpkBsdFjfxEYP8LLt56LuSuj2E3/U03uamr2s=; b=TcQOyAF5P67IfUXukjd6HnRv/B 4c5tG8Ix8FQhNoXG+l7JdFWol94QBroDGykJvdfQE1PbYgvxluRpXFx19Dx+BsojO4lhZJCNT3tml MhGWnWNDpnxkBEbzRvfrbECbU; Received: from 97-118-117-21.hlrn.qwest.net ([97.118.117.21]:35792 helo=bapiya.Home) by box5379.bluehost.com with esmtpsa (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92) (envelope-from ) id 1jFPaJ-003c6k-45; Fri, 20 Mar 2020 15:53:43 -0600 From: Tom Tromey To: gdb-patches@sourceware.org Cc: Tom Tromey Subject: [PATCH v2 5/7] Implement complex arithmetic Date: Fri, 20 Mar 2020 15:53:38 -0600 Message-Id: <20200320215340.16749-6-tom@tromey.com> X-Mailer: git-send-email 2.17.2 In-Reply-To: <20200320215340.16749-1-tom@tromey.com> References: <20200320215340.16749-1-tom@tromey.com> X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - box5379.bluehost.com X-AntiAbuse: Original Domain - sourceware.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - tromey.com X-BWhitelist: no X-Source-IP: 97.118.117.21 X-Source-L: No X-Exim-ID: 1jFPaJ-003c6k-45 X-Source: X-Source-Args: X-Source-Dir: X-Source-Sender: 97-118-117-21.hlrn.qwest.net (bapiya.Home) [97.118.117.21]:35792 X-Source-Auth: tom+tromey.com X-Email-Count: 7 X-Source-Cap: ZWx5bnJvYmk7ZWx5bnJvYmk7Ym94NTM3OS5ibHVlaG9zdC5jb20= X-Local-Domain: yes X-Spam-Status: No, score=-19.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, JMQ_SPF_NEUTRAL, RCVD_IN_ABUSEAT, RCVD_IN_DNSWL_NONE, RCVD_IN_SBL_CSS, SPF_HELO_PASS, SPF_NEUTRAL, URIBL_CSS, URIBL_CSS_A 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: Fri, 20 Mar 2020 21:53:46 -0000 This adds support for complex arithmetic to gdb. Now something like "print 23 + 7i" will work. Addition, subtraction, multiplication, division, and equality testing are supported binary operations. Unary +, negation, and complement are supported. Following GCC, the ~ operator computes the complex conjugate. gdb/ChangeLog 2020-03-20 Tom Tromey PR exp/25299: * valarith.c (promotion_type, complex_binop): New functions. (scalar_binop): Handle complex numbers. Use promotion_type. (value_pos, value_neg, value_complement): Handle complex numbers. gdb/testsuite/ChangeLog 2020-03-20 Tom Tromey * gdb.base/complex-parts.exp: Add arithmetic tests. --- gdb/ChangeLog | 7 + gdb/testsuite/ChangeLog | 4 + gdb/testsuite/gdb.base/complex-parts.exp | 26 +++ gdb/valarith.c | 199 ++++++++++++++++++++--- 4 files changed, 215 insertions(+), 21 deletions(-) diff --git a/gdb/testsuite/gdb.base/complex-parts.exp b/gdb/testsuite/gdb.base/complex-parts.exp index 071de5c56d7..0cf4abf56ec 100644 --- a/gdb/testsuite/gdb.base/complex-parts.exp +++ b/gdb/testsuite/gdb.base/complex-parts.exp @@ -60,3 +60,29 @@ gdb_test "p \$_cimag (i1)" "expected a complex number" gdb_test "p \$_creal (d1)" "expected a complex number" gdb_test "p \$_creal (f1)" "expected a complex number" gdb_test "p \$_creal (i1)" "expected a complex number" + +# +# General complex number tests. +# + +gdb_test "print 23 + 7i" " = 23 \\+ 7i" +gdb_test "print 23.125f + 7i" " = 23.125 \\+ 7i" +gdb_test "print 23 + 7.25fi" " = 23 \\+ 7.25i" +gdb_test "print (23 + 7i) + (17 + 10i)" " = 40 \\+ 17i" +gdb_test "print 23 + -7i" " = 23 \\+ -7i" +gdb_test "print 23 - 7i" " = 23 \\+ -7i" + +gdb_test "print -(23 + 7i)" " = -23 \\+ -7i" +gdb_test "print +(23 + 7i)" " = 23 \\+ 7i" +gdb_test "print ~(23 + 7i)" " = 23 \\+ -7i" + +gdb_test "print (5 + 5i) * (2 + 2i)" " = 0 \\+ 20i" + +gdb_test "print (5 + 7i) == (5 + 7i)" " = 1" +gdb_test "print (5 + 7i) == (8 + 7i)" " = 0" +gdb_test "print (5 + 7i) == (5 + 92i)" " = 0" +gdb_test "print (5 + 7i) != (5 + 7i)" " = 0" +gdb_test "print (5 + 7i) != (8 + 7i)" " = 1" +gdb_test "print (5 + 7i) != (5 + 92i)" " = 1" + +gdb_test "print (20 - 4i) / (3 + 2i)" " = 4 \\+ -4i" diff --git a/gdb/valarith.c b/gdb/valarith.c index be0e0731bee..07cb5014bb2 100644 --- a/gdb/valarith.c +++ b/gdb/valarith.c @@ -911,6 +911,157 @@ value_args_as_target_float (struct value *arg1, struct value *arg2, TYPE_NAME (type2)); } +/* A helper function that finds the type to use for a binary operation + involving TYPE1 and TYPE2. */ + +static struct type * +promotion_type (struct type *type1, struct type *type2) +{ + struct type *result_type; + + if (is_floating_type (type1) || is_floating_type (type2)) + { + /* If only one type is floating-point, use its type. + Otherwise use the bigger type. */ + if (!is_floating_type (type1)) + result_type = type2; + else if (!is_floating_type (type2)) + result_type = type1; + else if (TYPE_LENGTH (type2) > TYPE_LENGTH (type1)) + result_type = type2; + else + result_type = type1; + } + else + { + /* Integer types. */ + if (TYPE_LENGTH (type1) > TYPE_LENGTH (type2)) + result_type = type1; + else if (TYPE_LENGTH (type2) > TYPE_LENGTH (type1)) + result_type = type2; + else if (TYPE_UNSIGNED (type1)) + result_type = type1; + else if (TYPE_UNSIGNED (type2)) + result_type = type2; + else + result_type = type1; + } + + return result_type; +} + +static struct value *scalar_binop (struct value *arg1, struct value *arg2, + enum exp_opcode op); + +/* Perform a binary operation on complex operands. */ + +static struct value * +complex_binop (struct value *arg1, struct value *arg2, enum exp_opcode op) +{ + struct type *arg1_type = check_typedef (value_type (arg1)); + struct type *arg2_type = check_typedef (value_type (arg2)); + + struct value *arg1_real, *arg1_imag, *arg2_real, *arg2_imag; + if (TYPE_CODE (arg1_type) == TYPE_CODE_COMPLEX) + { + arg1_real = value_real_part (arg1); + arg1_imag = value_imaginary_part (arg1); + } + else + { + arg1_real = arg1; + arg1_imag = value_zero (arg1_type, not_lval); + } + if (TYPE_CODE (arg2_type) == TYPE_CODE_COMPLEX) + { + arg2_real = value_real_part (arg2); + arg2_imag = value_imaginary_part (arg2); + } + else + { + arg2_real = arg2; + arg2_imag = value_zero (arg2_type, not_lval); + } + + struct type *comp_type = promotion_type (value_type (arg1_real), + value_type (arg2_real)); + arg1_real = value_cast (comp_type, arg1_real); + arg1_imag = value_cast (comp_type, arg1_imag); + arg2_real = value_cast (comp_type, arg2_real); + arg2_imag = value_cast (comp_type, arg2_imag); + + struct type *result_type = init_complex_type (nullptr, comp_type); + + struct value *result_real, *result_imag; + switch (op) + { + case BINOP_ADD: + case BINOP_SUB: + result_real = scalar_binop (arg1_real, arg2_real, op); + result_imag = scalar_binop (arg1_imag, arg2_imag, op); + break; + + case BINOP_MUL: + { + struct value *x1 = scalar_binop (arg1_real, arg2_real, op); + struct value *x2 = scalar_binop (arg1_imag, arg2_imag, op); + result_real = scalar_binop (x1, x2, BINOP_SUB); + + x1 = scalar_binop (arg1_real, arg2_imag, op); + x2 = scalar_binop (arg1_imag, arg2_real, op); + result_imag = scalar_binop (x1, x2, BINOP_ADD); + } + break; + + case BINOP_DIV: + { + if (TYPE_CODE (arg2_type) == TYPE_CODE_COMPLEX) + { + struct value *conjugate = value_complement (arg2); + /* We have to reconstruct ARG1, in case the type was + promoted. */ + arg1 = value_literal_complex (arg1_real, arg1_imag, result_type); + + struct value *numerator = scalar_binop (arg1, conjugate, + BINOP_MUL); + arg1_real = value_real_part (numerator); + arg1_imag = value_imaginary_part (numerator); + + struct value *x1 = scalar_binop (arg2_real, arg2_real, BINOP_MUL); + struct value *x2 = scalar_binop (arg2_imag, arg2_imag, BINOP_MUL); + arg2_real = scalar_binop (x1, x2, BINOP_ADD); + } + + result_real = scalar_binop (arg1_real, arg2_real, op); + result_imag = scalar_binop (arg1_imag, arg2_real, op); + } + break; + + case BINOP_EQUAL: + case BINOP_NOTEQUAL: + { + struct value *x1 = scalar_binop (arg1_real, arg2_real, op); + struct value *x2 = scalar_binop (arg1_imag, arg2_imag, op); + + LONGEST v1 = value_as_long (x1); + LONGEST v2 = value_as_long (x2); + + if (op == BINOP_EQUAL) + v1 = v1 && v2; + else + v1 = v1 || v2; + + return value_from_longest (value_type (x1), v1); + } + break; + + default: + error (_("Invalid binary operation on numbers.")); + } + + return value_literal_complex (result_real, result_imag, result_type); +} + /* Perform a binary operation on two operands which have reasonable representations as integers or floats. This includes booleans, characters, integers, or floats. @@ -929,23 +1080,17 @@ scalar_binop (struct value *arg1, struct value *arg2, enum exp_opcode op) type1 = check_typedef (value_type (arg1)); type2 = check_typedef (value_type (arg2)); + if (TYPE_CODE (type1) == TYPE_CODE_COMPLEX + || TYPE_CODE (type2) == 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))) error (_("Argument to arithmetic operation not a number or boolean.")); if (is_floating_type (type1) || is_floating_type (type2)) { - /* If only one type is floating-point, use its type. - Otherwise use the bigger type. */ - if (!is_floating_type (type1)) - result_type = type2; - else if (!is_floating_type (type2)) - result_type = type1; - else if (TYPE_LENGTH (type2) > TYPE_LENGTH (type1)) - result_type = type2; - else - result_type = type1; - + result_type = promotion_type (type1, type2); val = allocate_value (result_type); struct type *eff_type_v1, *eff_type_v2; @@ -1013,16 +1158,8 @@ scalar_binop (struct value *arg1, struct value *arg2, enum exp_opcode op) if one of the operands is unsigned. */ if (op == BINOP_RSH || op == BINOP_LSH || op == BINOP_EXP) result_type = type1; - else if (TYPE_LENGTH (type1) > TYPE_LENGTH (type2)) - result_type = type1; - else if (TYPE_LENGTH (type2) > TYPE_LENGTH (type1)) - result_type = type2; - else if (TYPE_UNSIGNED (type1)) - result_type = type1; - else if (TYPE_UNSIGNED (type2)) - result_type = type2; else - result_type = type1; + result_type = promotion_type (type1, type2); if (TYPE_UNSIGNED (result_type)) { @@ -1629,7 +1766,8 @@ value_pos (struct value *arg1) type = check_typedef (value_type (arg1)); if (is_integral_type (type) || is_floating_value (arg1) - || (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type))) + || (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type)) + || TYPE_CODE (type) == TYPE_CODE_COMPLEX) return value_from_contents (type, value_contents (arg1)); else error (_("Argument to positive operation not a number.")); @@ -1663,6 +1801,15 @@ value_neg (struct value *arg1) } return val; } + else if (TYPE_CODE (type) == TYPE_CODE_COMPLEX) + { + struct value *real = value_real_part (arg1); + struct value *imag = value_imaginary_part (arg1); + + real = value_neg (real); + imag = value_neg (imag); + return value_literal_complex (real, imag, type); + } else error (_("Argument to negate operation not a number.")); } @@ -1696,6 +1843,16 @@ value_complement (struct value *arg1) value_contents_all (tmp), TYPE_LENGTH (eltype)); } } + else if (TYPE_CODE (type) == TYPE_CODE_COMPLEX) + { + /* GCC has an extension that treats ~complex as the complex + conjugate. */ + struct value *real = value_real_part (arg1); + struct value *imag = value_imaginary_part (arg1); + + imag = value_neg (imag); + return value_literal_complex (real, imag, type); + } else error (_("Argument to complement operation not an integer, boolean.")); -- 2.17.2