diff mbox

Go patch committed: Use MPC library for complex numbers

Message ID CAOyqgcVty+J5hCRwoEO5nvhZiNGnN+=0C5P_M290NAgctDpmVA@mail.gmail.com
State New
Headers show

Commit Message

Ian Lance Taylor Oct. 24, 2014, 5:01 a.m. UTC
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  <iant@google.com>

* go-gcc.cc (Gcc_backend::complex_constant_expression): Take one
mpc_t parameter instead of two mpfr_t parameters.
diff mbox

Patch

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 <gmp.h>
 #include <mpfr.h>
+#include <mpc.h>
 
 #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 <mpfr.h>
+#include <mpc.h>
 
 #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;
       }