From 5eda5bad3c455d499b6a3611b433f2945caa239d Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 24 Oct 2014 05:01:50 +0000 Subject: [PATCH] compiler: Use MPC library for complex numbers. * go-gcc.cc (Gcc_backend::complex_constant_expression): Take one mpc_t parameter instead of two mpfr_t parameters. From-SVN: r216611 --- gcc/go/ChangeLog | 5 + gcc/go/go-gcc.cc | 8 +- gcc/go/gofrontend/backend.h | 5 +- gcc/go/gofrontend/expressions.cc | 596 ++++++++----------------------- gcc/go/gofrontend/expressions.h | 18 +- gcc/go/gofrontend/parse.cc | 7 +- 6 files changed, 169 insertions(+), 470 deletions(-) diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 06a83f1320f..22078f0b0fb 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,8 @@ +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. + 2014-09-15 Jakub Jelinek * Make-lang.in (check_go_parallelize): Change to just an upper bound diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index 6bac84f2565..caf66db72f6 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -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(Btype* btype, mpfr_t val) // 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(Btype* btype, mpfr_t real, mpfr_t imag) 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); diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h index 98c36c1f5f8..46b2a6d6906 100644 --- a/gcc/go/gofrontend/backend.h +++ b/gcc/go/gofrontend/backend.h @@ -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* diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 0ec65691dd8..6f2b07ca97a 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -436,16 +436,14 @@ Expression::backend_numeric_constant_expression(Translate_context* context, } 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* imp) 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, Type* type, Location location) 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 Expression 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 Expression 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 Expression 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(Translate_context* context) } 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(String_dump* exp, const mpfr_t real, 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* exp) const 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 op, const Numeric_constant* unc, } 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 Numeric_constant* left_nc, 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 Numeric_constant* left_nc, 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); + *cmp = mpc_cmp(left_val, right_val) != 0; - mpfr_clear(left_real); - mpfr_clear(left_imag); - mpfr_clear(right_real); - mpfr_clear(right_imag); + mpc_clear(left_val); + mpc_clear(right_val); return true; } @@ -4805,31 +4790,27 @@ Binary_expression::eval_complex(Operator op, const Numeric_constant* left_nc, 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 op, const Numeric_constant* left_nc, 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(Expression* e, bool is_length) } // 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_constant_value(Numeric_constant* nc) const 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_constant_value(Numeric_constant* nc) const 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(Export* exp) const } 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 Numeric_constant& a) 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 Numeric_constant& a) 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, const mpfr_t val) // 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) const // 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(unsigned long* val) const 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) const 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) const 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) const // 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_type* type, bool issue_error, 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_type* type, bool issue_error, 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(Complex_type* type, bool issue_error, 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(Complex_type* type, bool issue_error, } 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(Complex_type* type, bool issue_error, 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 loc) const 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(); } diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 7bf38d7f49f..b7e1806040d 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -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. diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index dfb3380c90b..d806b4789f1 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -2525,9 +2525,12 @@ Parse::operand(bool may_be_sink, bool* is_parenthesized) { 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; } -- 2.30.2