From patchwork Fri Oct 24 05:01:56 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 402753 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id B42F8140077 for ; Fri, 24 Oct 2014 16:02:11 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:date:message-id:subject:from:to:content-type; q= dns; s=default; b=ww5nxxgpZVi/jJUDxSSggjcoDuHPTokUtbqzw+9GwzmePR WGQORXI41cyXS9OO1/UKbxfaBxmjxw8psXQMddFtEuKPRD+SHx2Qz/MyS2QzjQjq O9XTOtGuocWwod5BGrgxLtk4n9bH/9A4VxsUN6S/sKi/kPmB5PYdtXrOsqVD4= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:date:message-id:subject:from:to:content-type; s= default; bh=ncnj4dXcAR5szNjgjpkvSQYtlPY=; b=PYzEIbF0w/TGrHHuxkyW QzWyE9w1RiWkYbP8nndnMfgFI/8KXwcs2VwyLDIybEJB2gQRGtP2CJnm6uEqgW/d p9m8LgheI9d8j2H4iz6sMz77IgmzxMaIhNizd6A0zf+gWBMK5Sangptl2MKDi1Q6 WLMyp1/Kci8vTSMLdtnm6x0= Received: (qmail 18183 invoked by alias); 24 Oct 2014 05:02:03 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 18162 invoked by uid 89); 24 Oct 2014 05:02:02 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.3 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-yh0-f42.google.com Received: from mail-yh0-f42.google.com (HELO mail-yh0-f42.google.com) (209.85.213.42) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Fri, 24 Oct 2014 05:01:58 +0000 Received: by mail-yh0-f42.google.com with SMTP id t59so2658693yho.15 for ; Thu, 23 Oct 2014 22:01:56 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:date:message-id:subject:from:to :content-type; bh=jCs6k7YR2Tr/nDR6sRXxT+NWro1qihNEl9HSYwiV5dE=; b=F91mtgWyh2yKpDQIVHr01RWFu79E2LoQ/yKDiwND8mLQeBnDzbOe/6+0ws33ZcOAhR zd8mu/UZ8sjnpSxQAqsExAB+W79Vq5PKbyKXBy2tQs+hc4xWyFRRY89OcuK4og+CSx/v 54RpsLFGxeXAFUAewgsfR2hey+KBIVjIL6p7wmgKfuZ0Mv1oaYKjol//ymjxudMUZhWn ID0oBfO7+fXkqjkE/DcWpzTSbR6gpRX4dgUamIi7FyzP+sd0/VdQjN8XL4bcjxbiHx2k ABOsl7xS2cwmjj/+RmtAecyaVu4Lo8gc2vYFDxseUrOtSE+Ekci5uUKB4tArAGcfhc6y QYHw== X-Gm-Message-State: ALoCoQn940mC2rvBAP37GV2n5+ugCA9xzkL6KSj+u+p3T/Wl0KszHvuH/TlES6J0UxZjTM5/+dJ4 MIME-Version: 1.0 X-Received: by 10.170.92.85 with SMTP id j82mr2506131yka.120.1414126916244; Thu, 23 Oct 2014 22:01:56 -0700 (PDT) Received: by 10.170.233.132 with HTTP; Thu, 23 Oct 2014 22:01:56 -0700 (PDT) Date: Thu, 23 Oct 2014 22:01:56 -0700 Message-ID: Subject: Go patch committed: Use MPC library for complex numbers From: Ian Taylor To: gcc-patches@gcc.gnu.org, gofrontend-dev@googlegroups.com This patch to the Go frontend changes it to use the MPC library for complex numbers, rather than using pairs of MPFR values. This is a boilerplate change that lets us get rid of a bunch of code handling complex constant multiplication and division. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline. Ian 2014-10-23 Ian Lance Taylor * go-gcc.cc (Gcc_backend::complex_constant_expression): Take one mpc_t parameter instead of two mpfr_t parameters. Index: gcc/go/go-gcc.cc =================================================================== --- gcc/go/go-gcc.cc (revision 216522) +++ gcc/go/go-gcc.cc (working copy) @@ -247,7 +247,7 @@ class Gcc_backend : public Backend float_constant_expression(Btype* btype, mpfr_t val); Bexpression* - complex_constant_expression(Btype* btype, mpfr_t real, mpfr_t imag); + complex_constant_expression(Btype* btype, mpc_t val); Bexpression* string_constant_expression(const std::string& val); @@ -1241,7 +1241,7 @@ Gcc_backend::float_constant_expression(B // Return a typed real and imaginary value as a constant complex number. Bexpression* -Gcc_backend::complex_constant_expression(Btype* btype, mpfr_t real, mpfr_t imag) +Gcc_backend::complex_constant_expression(Btype* btype, mpc_t val) { tree t = btype->get_tree(); tree ret; @@ -1249,12 +1249,12 @@ Gcc_backend::complex_constant_expression return this->error_expression(); REAL_VALUE_TYPE r1; - real_from_mpfr(&r1, real, TREE_TYPE(t), GMP_RNDN); + real_from_mpfr(&r1, mpc_realref(val), TREE_TYPE(t), GMP_RNDN); REAL_VALUE_TYPE r2; real_convert(&r2, TYPE_MODE(TREE_TYPE(t)), &r1); REAL_VALUE_TYPE r3; - real_from_mpfr(&r3, imag, TREE_TYPE(t), GMP_RNDN); + real_from_mpfr(&r3, mpc_imagref(val), TREE_TYPE(t), GMP_RNDN); REAL_VALUE_TYPE r4; real_convert(&r4, TYPE_MODE(TREE_TYPE(t)), &r3); Index: gcc/go/gofrontend/backend.h =================================================================== --- gcc/go/gofrontend/backend.h (revision 216522) +++ gcc/go/gofrontend/backend.h (working copy) @@ -9,6 +9,7 @@ #include #include +#include #include "operator.h" @@ -277,9 +278,9 @@ class Backend virtual Bexpression* float_constant_expression(Btype* btype, mpfr_t val) = 0; - // Return an expression for the complex value REAL/IMAG in BTYPE. + // Return an expression for the complex value VAL in BTYPE. virtual Bexpression* - complex_constant_expression(Btype* btype, mpfr_t real, mpfr_t imag) = 0; + complex_constant_expression(Btype* btype, mpc_t val) = 0; // Return an expression for the string value VAL. virtual Bexpression* Index: gcc/go/gofrontend/expressions.cc =================================================================== --- gcc/go/gofrontend/expressions.cc (revision 216610) +++ gcc/go/gofrontend/expressions.cc (working copy) @@ -436,16 +436,14 @@ Expression::backend_numeric_constant_exp } else if (type->complex_type() != NULL) { - mpfr_t real; - mpfr_t imag; - if (!val->to_complex(&real, &imag)) + mpc_t cval; + if (!val->to_complex(&cval)) { go_assert(saw_errors()); return gogo->backend()->error_expression(); } - ret = gogo->backend()->complex_constant_expression(btype, real, imag); - mpfr_clear(real); - mpfr_clear(imag); + ret = gogo->backend()->complex_constant_expression(btype, cval); + mpc_clear(cval); } else go_unreachable(); @@ -2016,10 +2014,13 @@ Integer_expression::do_import(Import* im imag_str.c_str()); return Expression::make_error(imp->location()); } - Expression* ret = Expression::make_complex(&real, &imag, NULL, - imp->location()); + mpc_t cval; + mpc_init2(cval, mpc_precision); + mpc_set_fr_fr(cval, real, imag, MPC_RNDNN); mpfr_clear(real); mpfr_clear(imag); + Expression* ret = Expression::make_complex(&cval, NULL, imp->location()); + mpc_clear(cval); return ret; } else if (num.find('.') == std::string::npos @@ -2297,23 +2298,21 @@ Expression::make_float(const mpfr_t* val class Complex_expression : public Expression { public: - Complex_expression(const mpfr_t* real, const mpfr_t* imag, Type* type, - Location location) + Complex_expression(const mpc_t* val, Type* type, Location location) : Expression(EXPRESSION_COMPLEX, location), type_(type) { - mpfr_init_set(this->real_, *real, GMP_RNDN); - mpfr_init_set(this->imag_, *imag, GMP_RNDN); + mpc_init2(this->val_, mpc_precision); + mpc_set(this->val_, *val, MPC_RNDNN); } - // Write REAL/IMAG to string dump. + // Write VAL to string dump. static void - export_complex(String_dump* exp, const mpfr_t real, const mpfr_t val); + export_complex(String_dump* exp, const mpc_t val); // Write REAL/IMAG to dump context. static void - dump_complex(Ast_dump_context* ast_dump_context, - const mpfr_t real, const mpfr_t val); + dump_complex(Ast_dump_context* ast_dump_context, const mpc_t val); protected: bool @@ -2327,7 +2326,7 @@ class Complex_expression : public Expres bool do_numeric_constant_value(Numeric_constant* nc) const { - nc->set_complex(this->type_, this->real_, this->imag_); + nc->set_complex(this->type_, this->val_); return true; } @@ -2343,7 +2342,7 @@ class Complex_expression : public Expres Expression* do_copy() { - return Expression::make_complex(&this->real_, &this->imag_, this->type_, + return Expression::make_complex(&this->val_, this->type_, this->location()); } @@ -2357,10 +2356,8 @@ class Complex_expression : public Expres do_dump_expression(Ast_dump_context*) const; private: - // The real part. - mpfr_t real_; - // The imaginary part; - mpfr_t imag_; + // The complex value. + mpc_t val_; // The type if known. Type* type_; }; @@ -2400,7 +2397,7 @@ Complex_expression::do_check_types(Gogo* if (type == NULL) return; Numeric_constant nc; - nc.set_complex(NULL, this->real_, this->imag_); + nc.set_complex(NULL, this->val_); if (!nc.set_type(this->type_, true, this->location())) this->set_is_error(); } @@ -2432,23 +2429,22 @@ Complex_expression::do_get_backend(Trans } Numeric_constant nc; - nc.set_complex(resolved_type, this->real_, this->imag_); + nc.set_complex(resolved_type, this->val_); return Expression::backend_numeric_constant_expression(context, &nc); } // Write REAL/IMAG to export data. void -Complex_expression::export_complex(String_dump* exp, const mpfr_t real, - const mpfr_t imag) +Complex_expression::export_complex(String_dump* exp, const mpc_t val) { - if (!mpfr_zero_p(real)) + if (!mpfr_zero_p(mpc_realref(val))) { - Float_expression::export_float(exp, real); - if (mpfr_sgn(imag) > 0) + Float_expression::export_float(exp, mpc_realref(val)); + if (mpfr_sgn(mpc_imagref(val)) > 0) exp->write_c_string("+"); } - Float_expression::export_float(exp, imag); + Float_expression::export_float(exp, mpc_imagref(val)); exp->write_c_string("i"); } @@ -2457,7 +2453,7 @@ Complex_expression::export_complex(Strin void Complex_expression::do_export(Export* exp) const { - Complex_expression::export_complex(exp, this->real_, this->imag_); + Complex_expression::export_complex(exp, this->val_); // A trailing space lets us reliably identify the end of the number. exp->write_c_string(" "); } @@ -2467,18 +2463,15 @@ Complex_expression::do_export(Export* ex void Complex_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const { - Complex_expression::export_complex(ast_dump_context, - this->real_, - this->imag_); + Complex_expression::export_complex(ast_dump_context, this->val_); } // Make a complex expression. Expression* -Expression::make_complex(const mpfr_t* real, const mpfr_t* imag, Type* type, - Location location) +Expression::make_complex(const mpc_t* val, Type* type, Location location) { - return new Complex_expression(real, imag, type, location); + return new Complex_expression(val, type, location); } // Find a named object in an expression. @@ -3774,18 +3767,14 @@ Unary_expression::eval_constant(Operator } else if (unc->is_complex()) { - mpfr_t ureal, uimag; - unc->get_complex(&ureal, &uimag); - mpfr_t real, imag; - mpfr_init(real); - mpfr_init(imag); - mpfr_neg(real, ureal, GMP_RNDN); - mpfr_neg(imag, uimag, GMP_RNDN); - nc->set_complex(unc->type(), real, imag); - mpfr_clear(ureal); - mpfr_clear(uimag); - mpfr_clear(real); - mpfr_clear(imag); + mpc_t uval; + unc->get_complex(&uval); + mpc_t val; + mpc_init2(val, mpc_precision); + mpc_neg(val, uval, MPC_RNDNN); + nc->set_complex(unc->type(), val); + mpc_clear(uval); + mpc_clear(val); return true; } else @@ -4505,14 +4494,13 @@ Binary_expression::compare_complex(const const Numeric_constant* right_nc, int* cmp) { - mpfr_t left_real, left_imag; - if (!left_nc->to_complex(&left_real, &left_imag)) + mpc_t left_val; + if (!left_nc->to_complex(&left_val)) return false; - mpfr_t right_real, right_imag; - if (!right_nc->to_complex(&right_real, &right_imag)) + mpc_t right_val; + if (!right_nc->to_complex(&right_val)) { - mpfr_clear(left_real); - mpfr_clear(left_imag); + mpc_clear(left_val); return false; } @@ -4522,19 +4510,16 @@ Binary_expression::compare_complex(const if (!type->is_abstract() && type->complex_type() != NULL) { int bits = type->complex_type()->bits(); - mpfr_prec_round(left_real, bits / 2, GMP_RNDN); - mpfr_prec_round(left_imag, bits / 2, GMP_RNDN); - mpfr_prec_round(right_real, bits / 2, GMP_RNDN); - mpfr_prec_round(right_imag, bits / 2, GMP_RNDN); + mpfr_prec_round(mpc_realref(left_val), bits / 2, GMP_RNDN); + mpfr_prec_round(mpc_imagref(left_val), bits / 2, GMP_RNDN); + mpfr_prec_round(mpc_realref(right_val), bits / 2, GMP_RNDN); + mpfr_prec_round(mpc_imagref(right_val), bits / 2, GMP_RNDN); } - *cmp = (mpfr_cmp(left_real, right_real) != 0 - || mpfr_cmp(left_imag, right_imag) != 0); - - mpfr_clear(left_real); - mpfr_clear(left_imag); - mpfr_clear(right_real); - mpfr_clear(right_imag); + *cmp = mpc_cmp(left_val, right_val) != 0; + + mpc_clear(left_val); + mpc_clear(right_val); return true; } @@ -4805,31 +4790,27 @@ Binary_expression::eval_complex(Operator const Numeric_constant* right_nc, Location location, Numeric_constant* nc) { - mpfr_t left_real, left_imag; - if (!left_nc->to_complex(&left_real, &left_imag)) + mpc_t left_val; + if (!left_nc->to_complex(&left_val)) return false; - mpfr_t right_real, right_imag; - if (!right_nc->to_complex(&right_real, &right_imag)) + mpc_t right_val; + if (!right_nc->to_complex(&right_val)) { - mpfr_clear(left_real); - mpfr_clear(left_imag); + mpc_clear(left_val); return false; } - mpfr_t real, imag; - mpfr_init(real); - mpfr_init(imag); + mpc_t val; + mpc_init2(val, mpc_precision); bool ret = true; switch (op) { case OPERATOR_PLUS: - mpfr_add(real, left_real, right_real, GMP_RNDN); - mpfr_add(imag, left_imag, right_imag, GMP_RNDN); + mpc_add(val, left_val, right_val, MPC_RNDNN); break; case OPERATOR_MINUS: - mpfr_sub(real, left_real, right_real, GMP_RNDN); - mpfr_sub(imag, left_imag, right_imag, GMP_RNDN); + mpc_sub(val, left_val, right_val, MPC_RNDNN); break; case OPERATOR_OR: case OPERATOR_XOR: @@ -4838,310 +4819,30 @@ Binary_expression::eval_complex(Operator case OPERATOR_MOD: case OPERATOR_LSHIFT: case OPERATOR_RSHIFT: - mpfr_set_ui(real, 0, GMP_RNDN); - mpfr_set_ui(imag, 0, GMP_RNDN); + mpc_set_ui(val, 0, MPC_RNDNN); ret = false; break; case OPERATOR_MULT: - { - // You might think that multiplying two complex numbers would - // be simple, and you would be right, until you start to think - // about getting the right answer for infinity. If one - // operand here is infinity and the other is anything other - // than zero or NaN, then we are going to wind up subtracting - // two infinity values. That will give us a NaN, but the - // correct answer is infinity. - - mpfr_t lrrr; - mpfr_init(lrrr); - mpfr_mul(lrrr, left_real, right_real, GMP_RNDN); - - mpfr_t lrri; - mpfr_init(lrri); - mpfr_mul(lrri, left_real, right_imag, GMP_RNDN); - - mpfr_t lirr; - mpfr_init(lirr); - mpfr_mul(lirr, left_imag, right_real, GMP_RNDN); - - mpfr_t liri; - mpfr_init(liri); - mpfr_mul(liri, left_imag, right_imag, GMP_RNDN); - - mpfr_sub(real, lrrr, liri, GMP_RNDN); - mpfr_add(imag, lrri, lirr, GMP_RNDN); - - // If we get NaN on both sides, check whether it should really - // be infinity. The rule is that if either side of the - // complex number is infinity, then the whole value is - // infinity, even if the other side is NaN. So the only case - // we have to fix is the one in which both sides are NaN. - if (mpfr_nan_p(real) && mpfr_nan_p(imag) - && (!mpfr_nan_p(left_real) || !mpfr_nan_p(left_imag)) - && (!mpfr_nan_p(right_real) || !mpfr_nan_p(right_imag))) - { - bool is_infinity = false; - - mpfr_t lr; - mpfr_t li; - mpfr_init_set(lr, left_real, GMP_RNDN); - mpfr_init_set(li, left_imag, GMP_RNDN); - - mpfr_t rr; - mpfr_t ri; - mpfr_init_set(rr, right_real, GMP_RNDN); - mpfr_init_set(ri, right_imag, GMP_RNDN); - - // If the left side is infinity, then the result is - // infinity. - if (mpfr_inf_p(lr) || mpfr_inf_p(li)) - { - mpfr_set_ui(lr, mpfr_inf_p(lr) ? 1 : 0, GMP_RNDN); - mpfr_copysign(lr, lr, left_real, GMP_RNDN); - mpfr_set_ui(li, mpfr_inf_p(li) ? 1 : 0, GMP_RNDN); - mpfr_copysign(li, li, left_imag, GMP_RNDN); - if (mpfr_nan_p(rr)) - { - mpfr_set_ui(rr, 0, GMP_RNDN); - mpfr_copysign(rr, rr, right_real, GMP_RNDN); - } - if (mpfr_nan_p(ri)) - { - mpfr_set_ui(ri, 0, GMP_RNDN); - mpfr_copysign(ri, ri, right_imag, GMP_RNDN); - } - is_infinity = true; - } - - // If the right side is infinity, then the result is - // infinity. - if (mpfr_inf_p(rr) || mpfr_inf_p(ri)) - { - mpfr_set_ui(rr, mpfr_inf_p(rr) ? 1 : 0, GMP_RNDN); - mpfr_copysign(rr, rr, right_real, GMP_RNDN); - mpfr_set_ui(ri, mpfr_inf_p(ri) ? 1 : 0, GMP_RNDN); - mpfr_copysign(ri, ri, right_imag, GMP_RNDN); - if (mpfr_nan_p(lr)) - { - mpfr_set_ui(lr, 0, GMP_RNDN); - mpfr_copysign(lr, lr, left_real, GMP_RNDN); - } - if (mpfr_nan_p(li)) - { - mpfr_set_ui(li, 0, GMP_RNDN); - mpfr_copysign(li, li, left_imag, GMP_RNDN); - } - is_infinity = true; - } - - // If we got an overflow in the intermediate computations, - // then the result is infinity. - if (!is_infinity - && (mpfr_inf_p(lrrr) || mpfr_inf_p(lrri) - || mpfr_inf_p(lirr) || mpfr_inf_p(liri))) - { - if (mpfr_nan_p(lr)) - { - mpfr_set_ui(lr, 0, GMP_RNDN); - mpfr_copysign(lr, lr, left_real, GMP_RNDN); - } - if (mpfr_nan_p(li)) - { - mpfr_set_ui(li, 0, GMP_RNDN); - mpfr_copysign(li, li, left_imag, GMP_RNDN); - } - if (mpfr_nan_p(rr)) - { - mpfr_set_ui(rr, 0, GMP_RNDN); - mpfr_copysign(rr, rr, right_real, GMP_RNDN); - } - if (mpfr_nan_p(ri)) - { - mpfr_set_ui(ri, 0, GMP_RNDN); - mpfr_copysign(ri, ri, right_imag, GMP_RNDN); - } - is_infinity = true; - } - - if (is_infinity) - { - mpfr_mul(lrrr, lr, rr, GMP_RNDN); - mpfr_mul(lrri, lr, ri, GMP_RNDN); - mpfr_mul(lirr, li, rr, GMP_RNDN); - mpfr_mul(liri, li, ri, GMP_RNDN); - mpfr_sub(real, lrrr, liri, GMP_RNDN); - mpfr_add(imag, lrri, lirr, GMP_RNDN); - mpfr_set_inf(real, mpfr_sgn(real)); - mpfr_set_inf(imag, mpfr_sgn(imag)); - } - - mpfr_clear(lr); - mpfr_clear(li); - mpfr_clear(rr); - mpfr_clear(ri); - } - - mpfr_clear(lrrr); - mpfr_clear(lrri); - mpfr_clear(lirr); - mpfr_clear(liri); - } + mpc_mul(val, left_val, right_val, MPC_RNDNN); break; case OPERATOR_DIV: - { - // For complex division we want to avoid having an - // intermediate overflow turn the whole result in a NaN. We - // scale the values to try to avoid this. - - if (mpfr_zero_p(right_real) && mpfr_zero_p(right_imag)) - { - error_at(location, "division by zero"); - mpfr_set_ui(real, 0, GMP_RNDN); - mpfr_set_ui(imag, 0, GMP_RNDN); - break; - } - - mpfr_t rra; - mpfr_t ria; - mpfr_init(rra); - mpfr_init(ria); - mpfr_abs(rra, right_real, GMP_RNDN); - mpfr_abs(ria, right_imag, GMP_RNDN); - mpfr_t t; - mpfr_init(t); - mpfr_max(t, rra, ria, GMP_RNDN); - - mpfr_t rr; - mpfr_t ri; - mpfr_init_set(rr, right_real, GMP_RNDN); - mpfr_init_set(ri, right_imag, GMP_RNDN); - long ilogbw = 0; - if (!mpfr_inf_p(t) && !mpfr_nan_p(t) && !mpfr_zero_p(t)) - { - ilogbw = mpfr_get_exp(t); - mpfr_mul_2si(rr, rr, - ilogbw, GMP_RNDN); - mpfr_mul_2si(ri, ri, - ilogbw, GMP_RNDN); - } - - mpfr_t denom; - mpfr_init(denom); - mpfr_mul(denom, rr, rr, GMP_RNDN); - mpfr_mul(t, ri, ri, GMP_RNDN); - mpfr_add(denom, denom, t, GMP_RNDN); - - mpfr_mul(real, left_real, rr, GMP_RNDN); - mpfr_mul(t, left_imag, ri, GMP_RNDN); - mpfr_add(real, real, t, GMP_RNDN); - mpfr_div(real, real, denom, GMP_RNDN); - mpfr_mul_2si(real, real, - ilogbw, GMP_RNDN); - - mpfr_mul(imag, left_imag, rr, GMP_RNDN); - mpfr_mul(t, left_real, ri, GMP_RNDN); - mpfr_sub(imag, imag, t, GMP_RNDN); - mpfr_div(imag, imag, denom, GMP_RNDN); - mpfr_mul_2si(imag, imag, - ilogbw, GMP_RNDN); - - // If we wind up with NaN on both sides, check whether we - // should really have infinity. The rule is that if either - // side of the complex number is infinity, then the whole - // value is infinity, even if the other side is NaN. So the - // only case we have to fix is the one in which both sides are - // NaN. - if (mpfr_nan_p(real) && mpfr_nan_p(imag) - && (!mpfr_nan_p(left_real) || !mpfr_nan_p(left_imag)) - && (!mpfr_nan_p(right_real) || !mpfr_nan_p(right_imag))) - { - if (mpfr_zero_p(denom)) - { - mpfr_set_inf(real, mpfr_sgn(rr)); - mpfr_mul(real, real, left_real, GMP_RNDN); - mpfr_set_inf(imag, mpfr_sgn(rr)); - mpfr_mul(imag, imag, left_imag, GMP_RNDN); - } - else if ((mpfr_inf_p(left_real) || mpfr_inf_p(left_imag)) - && mpfr_number_p(rr) && mpfr_number_p(ri)) - { - mpfr_set_ui(t, mpfr_inf_p(left_real) ? 1 : 0, GMP_RNDN); - mpfr_copysign(t, t, left_real, GMP_RNDN); - - mpfr_t t2; - mpfr_init_set_ui(t2, mpfr_inf_p(left_imag) ? 1 : 0, GMP_RNDN); - mpfr_copysign(t2, t2, left_imag, GMP_RNDN); - - mpfr_t t3; - mpfr_init(t3); - mpfr_mul(t3, t, rr, GMP_RNDN); - - mpfr_t t4; - mpfr_init(t4); - mpfr_mul(t4, t2, ri, GMP_RNDN); - - mpfr_add(t3, t3, t4, GMP_RNDN); - mpfr_set_inf(real, mpfr_sgn(t3)); - - mpfr_mul(t3, t2, rr, GMP_RNDN); - mpfr_mul(t4, t, ri, GMP_RNDN); - mpfr_sub(t3, t3, t4, GMP_RNDN); - mpfr_set_inf(imag, mpfr_sgn(t3)); - - mpfr_clear(t2); - mpfr_clear(t3); - mpfr_clear(t4); - } - else if ((mpfr_inf_p(right_real) || mpfr_inf_p(right_imag)) - && mpfr_number_p(left_real) && mpfr_number_p(left_imag)) - { - mpfr_set_ui(t, mpfr_inf_p(rr) ? 1 : 0, GMP_RNDN); - mpfr_copysign(t, t, rr, GMP_RNDN); - - mpfr_t t2; - mpfr_init_set_ui(t2, mpfr_inf_p(ri) ? 1 : 0, GMP_RNDN); - mpfr_copysign(t2, t2, ri, GMP_RNDN); - - mpfr_t t3; - mpfr_init(t3); - mpfr_mul(t3, left_real, t, GMP_RNDN); - - mpfr_t t4; - mpfr_init(t4); - mpfr_mul(t4, left_imag, t2, GMP_RNDN); - - mpfr_add(t3, t3, t4, GMP_RNDN); - mpfr_set_ui(real, 0, GMP_RNDN); - mpfr_mul(real, real, t3, GMP_RNDN); - - mpfr_mul(t3, left_imag, t, GMP_RNDN); - mpfr_mul(t4, left_real, t2, GMP_RNDN); - mpfr_sub(t3, t3, t4, GMP_RNDN); - mpfr_set_ui(imag, 0, GMP_RNDN); - mpfr_mul(imag, imag, t3, GMP_RNDN); - - mpfr_clear(t2); - mpfr_clear(t3); - mpfr_clear(t4); - } - } - - mpfr_clear(denom); - mpfr_clear(rr); - mpfr_clear(ri); - mpfr_clear(t); - mpfr_clear(rra); - mpfr_clear(ria); - } + if (mpc_cmp_si(right_val, 0) == 0) + { + error_at(location, "division by zero"); + mpc_set_ui(val, 0, MPC_RNDNN); + break; + } + mpc_div(val, left_val, right_val, MPC_RNDNN); break; default: go_unreachable(); } - mpfr_clear(left_real); - mpfr_clear(left_imag); - mpfr_clear(right_real); - mpfr_clear(right_imag); + mpc_clear(left_val); + mpc_clear(right_val); - nc->set_complex(NULL, real, imag); - mpfr_clear(real); - mpfr_clear(imag); + nc->set_complex(NULL, val); + mpc_clear(val); return ret; } @@ -7397,9 +7098,9 @@ Builtin_call_expression::check_int_value } // Return the type of the real or imag functions, given the type of -// the argument. We need to map complex to float, complex64 to -// float32, and complex128 to float64, so it has to be done by name. -// This returns NULL if it can't figure out the type. +// the argument. We need to map complex64 to float32 and complex128 +// to float64, so it has to be done by name. This returns NULL if it +// can't figure out the type. Type* Builtin_call_expression::real_imag_type(Type* arg_type) @@ -7713,16 +7414,16 @@ Builtin_call_expression::do_numeric_cons if (!arg->numeric_constant_value(&argnc)) return false; - mpfr_t real; - mpfr_t imag; - if (!argnc.to_complex(&real, &imag)) + mpc_t val; + if (!argnc.to_complex(&val)) return false; Type* type = Builtin_call_expression::real_imag_type(argnc.type()); if (this->code_ == BUILTIN_REAL) - nc->set_float(type, real); + nc->set_float(type, mpc_realref(val)); else - nc->set_float(type, imag); + nc->set_float(type, mpc_imagref(val)); + mpc_clear(val); return true; } else if (this->code_ == BUILTIN_COMPLEX) @@ -7759,12 +7460,17 @@ Builtin_call_expression::do_numeric_cons if (arg_type == NULL || arg_type->is_abstract()) arg_type = inc.type(); - Type* type = Builtin_call_expression::complex_type(arg_type); - nc->set_complex(type, r, i); - + mpc_t val; + mpc_init2(val, mpc_precision); + mpc_set_fr_fr(val, r, i, MPC_RNDNN); mpfr_clear(r); mpfr_clear(i); + Type* type = Builtin_call_expression::complex_type(arg_type); + nc->set_complex(type, val); + + mpc_clear(val); + return true; } @@ -8690,11 +8396,10 @@ Builtin_call_expression::do_export(Expor } else if (nc.is_complex()) { - mpfr_t real; - mpfr_t imag; - Complex_expression::export_complex(exp, real, imag); - mpfr_clear(real); - mpfr_clear(imag); + mpc_t cval; + nc.get_complex(&cval); + Complex_expression::export_complex(exp, cval); + mpc_clear(cval); } else go_unreachable(); @@ -15333,10 +15038,8 @@ Numeric_constant::Numeric_constant(const mpfr_init_set(this->u_.float_val, a.u_.float_val, GMP_RNDN); break; case NC_COMPLEX: - mpfr_init_set(this->u_.complex_val.real, a.u_.complex_val.real, - GMP_RNDN); - mpfr_init_set(this->u_.complex_val.imag, a.u_.complex_val.imag, - GMP_RNDN); + mpc_init2(this->u_.complex_val, mpc_precision); + mpc_set(this->u_.complex_val, a.u_.complex_val, MPC_RNDNN); break; default: go_unreachable(); @@ -15363,10 +15066,8 @@ Numeric_constant::operator=(const Numeri mpfr_init_set(this->u_.float_val, a.u_.float_val, GMP_RNDN); break; case NC_COMPLEX: - mpfr_init_set(this->u_.complex_val.real, a.u_.complex_val.real, - GMP_RNDN); - mpfr_init_set(this->u_.complex_val.imag, a.u_.complex_val.imag, - GMP_RNDN); + mpc_init2(this->u_.complex_val, mpc_precision); + mpc_set(this->u_.complex_val, a.u_.complex_val, MPC_RNDNN); break; default: go_unreachable(); @@ -15391,8 +15092,7 @@ Numeric_constant::clear() mpfr_clear(this->u_.float_val); break; case NC_COMPLEX: - mpfr_clear(this->u_.complex_val.real); - mpfr_clear(this->u_.complex_val.imag); + mpc_clear(this->u_.complex_val); break; default: go_unreachable(); @@ -15453,13 +15153,13 @@ Numeric_constant::set_float(Type* type, // Set to a complex value. void -Numeric_constant::set_complex(Type* type, const mpfr_t real, const mpfr_t imag) +Numeric_constant::set_complex(Type* type, const mpc_t val) { this->clear(); this->classification_ = NC_COMPLEX; this->type_ = type; - mpfr_init_set(this->u_.complex_val.real, real, GMP_RNDN); - mpfr_init_set(this->u_.complex_val.imag, imag, GMP_RNDN); + mpc_init2(this->u_.complex_val, mpc_precision); + mpc_set(this->u_.complex_val, val, MPC_RNDNN); } // Get an int value. @@ -15492,11 +15192,11 @@ Numeric_constant::get_float(mpfr_t* val) // Get a complex value. void -Numeric_constant::get_complex(mpfr_t* real, mpfr_t* imag) const +Numeric_constant::get_complex(mpc_t* val) const { go_assert(this->is_complex()); - mpfr_init_set(*real, this->u_.complex_val.real, GMP_RNDN); - mpfr_init_set(*imag, this->u_.complex_val.imag, GMP_RNDN); + mpc_init2(*val, mpc_precision); + mpc_set(*val, this->u_.complex_val, MPC_RNDNN); } // Express value as unsigned long if possible. @@ -15512,9 +15212,10 @@ Numeric_constant::to_unsigned_long(unsig case NC_FLOAT: return this->mpfr_to_unsigned_long(this->u_.float_val, val); case NC_COMPLEX: - if (!mpfr_zero_p(this->u_.complex_val.imag)) + if (!mpfr_zero_p(mpc_imagref(this->u_.complex_val))) return NC_UL_NOTINT; - return this->mpfr_to_unsigned_long(this->u_.complex_val.real, val); + return this->mpfr_to_unsigned_long(mpc_realref(this->u_.complex_val), + val); default: go_unreachable(); } @@ -15569,11 +15270,11 @@ Numeric_constant::to_int(mpz_t* val) con mpfr_get_z(*val, this->u_.float_val, GMP_RNDN); return true; case NC_COMPLEX: - if (!mpfr_zero_p(this->u_.complex_val.imag) - || !mpfr_integer_p(this->u_.complex_val.real)) + if (!mpfr_zero_p(mpc_imagref(this->u_.complex_val)) + || !mpfr_integer_p(mpc_realref(this->u_.complex_val))) return false; mpz_init(*val); - mpfr_get_z(*val, this->u_.complex_val.real, GMP_RNDN); + mpfr_get_z(*val, mpc_realref(this->u_.complex_val), GMP_RNDN); return true; default: go_unreachable(); @@ -15595,9 +15296,9 @@ Numeric_constant::to_float(mpfr_t* val) mpfr_init_set(*val, this->u_.float_val, GMP_RNDN); return true; case NC_COMPLEX: - if (!mpfr_zero_p(this->u_.complex_val.imag)) + if (!mpfr_zero_p(mpc_imagref(this->u_.complex_val))) return false; - mpfr_init_set(*val, this->u_.complex_val.real, GMP_RNDN); + mpfr_init_set(*val, mpc_realref(this->u_.complex_val), GMP_RNDN); return true; default: go_unreachable(); @@ -15607,22 +15308,20 @@ Numeric_constant::to_float(mpfr_t* val) // Convert value to complex. bool -Numeric_constant::to_complex(mpfr_t* vr, mpfr_t* vi) const +Numeric_constant::to_complex(mpc_t* val) const { + mpc_init2(*val, mpc_precision); switch (this->classification_) { case NC_INT: case NC_RUNE: - mpfr_init_set_z(*vr, this->u_.int_val, GMP_RNDN); - mpfr_init_set_ui(*vi, 0, GMP_RNDN); + mpc_set_z(*val, this->u_.int_val, MPC_RNDNN); return true; case NC_FLOAT: - mpfr_init_set(*vr, this->u_.float_val, GMP_RNDN); - mpfr_init_set_ui(*vi, 0, GMP_RNDN); + mpc_set_fr(*val, this->u_.float_val, MPC_RNDNN); return true; case NC_COMPLEX: - mpfr_init_set(*vr, this->u_.complex_val.real, GMP_RNDN); - mpfr_init_set(*vi, this->u_.complex_val.imag, GMP_RNDN); + mpc_set(*val, this->u_.complex_val, MPC_RNDNN); return true; default: go_unreachable(); @@ -15700,15 +15399,15 @@ Numeric_constant::check_int_type(Integer break; case NC_COMPLEX: - if (!mpfr_integer_p(this->u_.complex_val.real) - || !mpfr_zero_p(this->u_.complex_val.imag)) + if (!mpfr_integer_p(mpc_realref(this->u_.complex_val)) + || !mpfr_zero_p(mpc_imagref(this->u_.complex_val))) { if (issue_error) error_at(location, "complex constant truncated to integer"); return false; } mpz_init(val); - mpfr_get_z(val, this->u_.complex_val.real, GMP_RNDN); + mpfr_get_z(val, mpc_realref(this->u_.complex_val), GMP_RNDN); break; default: @@ -15767,13 +15466,13 @@ Numeric_constant::check_float_type(Float break; case NC_COMPLEX: - if (!mpfr_zero_p(this->u_.complex_val.imag)) + if (!mpfr_zero_p(mpc_imagref(this->u_.complex_val))) { if (issue_error) error_at(location, "complex constant truncated to float"); return false; } - mpfr_init_set(val, this->u_.complex_val.real, GMP_RNDN); + mpfr_init_set(val, mpc_realref(this->u_.complex_val), GMP_RNDN); break; default: @@ -15860,24 +15559,21 @@ Numeric_constant::check_complex_type(Com go_unreachable(); } - mpfr_t real; - mpfr_t imag; + mpc_t val; + mpc_init2(val, mpc_precision); switch (this->classification_) { case NC_INT: case NC_RUNE: - mpfr_init_set_z(real, this->u_.int_val, GMP_RNDN); - mpfr_init_set_ui(imag, 0, GMP_RNDN); + mpc_set_z(val, this->u_.int_val, MPC_RNDNN); break; case NC_FLOAT: - mpfr_init_set(real, this->u_.float_val, GMP_RNDN); - mpfr_init_set_ui(imag, 0, GMP_RNDN); + mpc_set_fr(val, this->u_.float_val, MPC_RNDNN); break; case NC_COMPLEX: - mpfr_init_set(real, this->u_.complex_val.real, GMP_RNDN); - mpfr_init_set(imag, this->u_.complex_val.imag, GMP_RNDN); + mpc_set(val, this->u_.complex_val, MPC_RNDNN); break; default: @@ -15885,20 +15581,20 @@ Numeric_constant::check_complex_type(Com } bool ret = true; - if (!mpfr_nan_p(real) - && !mpfr_inf_p(real) - && !mpfr_zero_p(real) - && mpfr_get_exp(real) > max_exp) + if (!mpfr_nan_p(mpc_realref(val)) + && !mpfr_inf_p(mpc_realref(val)) + && !mpfr_zero_p(mpc_realref(val)) + && mpfr_get_exp(mpc_realref(val)) > max_exp) { if (issue_error) error_at(location, "complex real part overflow"); ret = false; } - if (!mpfr_nan_p(imag) - && !mpfr_inf_p(imag) - && !mpfr_zero_p(imag) - && mpfr_get_exp(imag) > max_exp) + if (!mpfr_nan_p(mpc_imagref(val)) + && !mpfr_inf_p(mpc_imagref(val)) + && !mpfr_zero_p(mpc_imagref(val)) + && mpfr_get_exp(mpc_imagref(val)) > max_exp) { if (issue_error) error_at(location, "complex imaginary part overflow"); @@ -15908,30 +15604,26 @@ Numeric_constant::check_complex_type(Com if (ret) { // Round the constant to the desired type. - mpfr_t t; - mpfr_init(t); + mpc_t t; switch (type->bits()) { case 64: - mpfr_set_prec(t, 24); + mpc_init2(t, 24); break; case 128: - mpfr_set_prec(t, 53); + mpc_init2(t, 53); break; default: go_unreachable(); } - mpfr_set(t, real, GMP_RNDN); - mpfr_set(real, t, GMP_RNDN); - mpfr_set(t, imag, GMP_RNDN); - mpfr_set(imag, t, GMP_RNDN); - mpfr_clear(t); + mpc_set(t, val, MPC_RNDNN); + mpc_set(val, t, MPC_RNDNN); + mpc_clear(t); - this->set_complex(type, real, imag); + this->set_complex(type, val); } - mpfr_clear(real); - mpfr_clear(imag); + mpc_clear(val); return ret; } @@ -15950,9 +15642,7 @@ Numeric_constant::expression(Location lo case NC_FLOAT: return Expression::make_float(&this->u_.float_val, this->type_, loc); case NC_COMPLEX: - return Expression::make_complex(&this->u_.complex_val.real, - &this->u_.complex_val.imag, - this->type_, loc); + return Expression::make_complex(&this->u_.complex_val, this->type_, loc); default: go_unreachable(); } Index: gcc/go/gofrontend/expressions.h =================================================================== --- gcc/go/gofrontend/expressions.h (revision 216610) +++ gcc/go/gofrontend/expressions.h (working copy) @@ -8,6 +8,7 @@ #define GO_EXPRESSIONS_H #include +#include #include "operator.h" @@ -52,6 +53,9 @@ class Label; class Ast_dump_context; class String_dump; +// The precision to use for complex values represented as an mpc_t. +const int mpc_precision = 256; + // The base class for all expressions. class Expression @@ -237,7 +241,7 @@ class Expression // Make a constant complex expression. TYPE should be NULL for an // abstract type. static Expression* - make_complex(const mpfr_t* real, const mpfr_t* imag, Type*, Location); + make_complex(const mpc_t*, Type*, Location); // Make a nil expression. static Expression* @@ -2585,7 +2589,7 @@ class Numeric_constant // Set to a complex value. void - set_complex(Type*, const mpfr_t, const mpfr_t); + set_complex(Type*, const mpc_t); // Classifiers. bool @@ -2617,7 +2621,7 @@ class Numeric_constant get_float(mpfr_t*) const; void - get_complex(mpfr_t*, mpfr_t*) const; + get_complex(mpc_t*) const; // Codes returned by to_unsigned_long. enum To_unsigned_long @@ -2653,7 +2657,7 @@ class Numeric_constant // If the value can be expressed as a complex, return true and // initialize and set VR and VI. bool - to_complex(mpfr_t* vr, mpfr_t* vi) const; + to_complex(mpc_t* val) const; // Get the type. Type* @@ -2709,11 +2713,7 @@ class Numeric_constant // If NC_FLOAT. mpfr_t float_val; // If NC_COMPLEX. - struct - { - mpfr_t real; - mpfr_t imag; - } complex_val; + mpc_t complex_val; } u_; // The type if there is one. This will be NULL for an untyped // constant. Index: gcc/go/gofrontend/parse.cc =================================================================== --- gcc/go/gofrontend/parse.cc (revision 216610) +++ gcc/go/gofrontend/parse.cc (working copy) @@ -2525,9 +2525,12 @@ Parse::operand(bool may_be_sink, bool* i { mpfr_t zero; mpfr_init_set_ui(zero, 0, GMP_RNDN); - ret = Expression::make_complex(&zero, token->imaginary_value(), - NULL, token->location()); + mpc_t val; + mpc_init2(val, mpc_precision); + mpc_set_fr_fr(val, zero, *token->imaginary_value(), MPC_RNDNN); mpfr_clear(zero); + ret = Expression::make_complex(&val, NULL, token->location()); + mpc_clear(val); this->advance_token(); return ret; }