* [gccgo] Add complex numbers
@ 2010-03-10 23:26 Ian Lance Taylor
2010-03-11 16:21 ` Richard Henderson
0 siblings, 1 reply; 7+ messages in thread
From: Ian Lance Taylor @ 2010-03-10 23:26 UTC (permalink / raw)
To: gcc-patches
[-- Attachment #1: Type: text/plain, Size: 120 bytes --]
Complex numbers were recently added to the Go language. I committed
this patch to add support for them to gccgo.
Ian
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: complex --]
[-- Type: text/x-diff, Size: 105873 bytes --]
diff -r 56cbaf257cf7 go/export.cc
--- a/go/export.cc Thu Mar 04 17:00:54 2010 -0800
+++ b/go/export.cc Wed Mar 10 14:43:36 2010 -0800
@@ -344,10 +344,13 @@
this->register_builtin_type(gogo, "uint64", BUILTIN_UINT64);
this->register_builtin_type(gogo, "float32", BUILTIN_FLOAT32);
this->register_builtin_type(gogo, "float64", BUILTIN_FLOAT64);
+ this->register_builtin_type(gogo, "complex64", BUILTIN_COMPLEX64);
+ this->register_builtin_type(gogo, "complex128", BUILTIN_COMPLEX128);
this->register_builtin_type(gogo, "int", BUILTIN_INT);
this->register_builtin_type(gogo, "uint", BUILTIN_UINT);
this->register_builtin_type(gogo, "uintptr", BUILTIN_UINTPTR);
this->register_builtin_type(gogo, "float", BUILTIN_FLOAT);
+ this->register_builtin_type(gogo, "complex", BUILTIN_COMPLEX);
this->register_builtin_type(gogo, "bool", BUILTIN_BOOL);
this->register_builtin_type(gogo, "string", BUILTIN_STRING);
}
diff -r 56cbaf257cf7 go/export.h
--- a/go/export.h Thu Mar 04 17:00:54 2010 -0800
+++ b/go/export.h Wed Mar 10 14:43:36 2010 -0800
@@ -38,8 +38,11 @@
BUILTIN_FLOAT = -14,
BUILTIN_BOOL = -15,
BUILTIN_STRING = -16,
+ BUILTIN_COMPLEX64 = -17,
+ BUILTIN_COMPLEX128 = -18,
+ BUILTIN_COMPLEX = -19,
- SMALLEST_BUILTIN_CODE = -16
+ SMALLEST_BUILTIN_CODE = -19
};
// This class manages exporting Go declarations. It handles the main
diff -r 56cbaf257cf7 go/expressions.cc
--- a/go/expressions.cc Thu Mar 04 17:00:54 2010 -0800
+++ b/go/expressions.cc Wed Mar 10 14:43:36 2010 -0800
@@ -74,6 +74,24 @@
return ret;
}
+// If this expression has a constant complex value, return it.
+
+bool
+Expression::complex_constant_value(mpfr_t real, mpfr_t imag,
+ Type** ptype) const
+{
+ *ptype = NULL;
+ if (this->do_complex_constant_value(real, imag, ptype))
+ return true;
+ Type *t;
+ if (this->float_constant_value(real, &t))
+ {
+ mpfr_set_ui(imag, 0, GMP_RNDN);
+ return true;
+ }
+ return false;
+}
+
// Traverse the expressions.
int
@@ -607,7 +625,8 @@
}
else if (POINTER_TYPE_P(lhs_type_tree)
|| INTEGRAL_TYPE_P(lhs_type_tree)
- || SCALAR_FLOAT_TYPE_P(lhs_type_tree))
+ || SCALAR_FLOAT_TYPE_P(lhs_type_tree)
+ || COMPLEX_FLOAT_TYPE_P(lhs_type_tree))
return fold_convert_loc(location, lhs_type_tree, rhs_tree);
else if (TREE_CODE(lhs_type_tree) == RECORD_TYPE
&& TREE_CODE(TREE_TYPE(rhs_tree)) == RECORD_TYPE)
@@ -658,6 +677,16 @@
mpfr_clear(fval);
return ret;
}
+ else if (TREE_CODE(type) == COMPLEX_TYPE)
+ {
+ mpfr_t fval;
+ mpfr_init_set_z(fval, val, GMP_RNDN);
+ tree real = Expression::float_constant_tree(fval, TREE_TYPE(type));
+ mpfr_clear(fval);
+ tree imag = build_real_from_int_cst(TREE_TYPE(type),
+ integer_zero_node);
+ return build_complex(type, real, imag);
+ }
else
gcc_unreachable();
}
@@ -686,6 +715,40 @@
real_convert(&r2, TYPE_MODE(type), &r1);
return build_real(type, r2);
}
+ else if (TREE_CODE(type) == COMPLEX_TYPE)
+ {
+ REAL_VALUE_TYPE r1;
+ real_from_mpfr(&r1, val, TREE_TYPE(type), GMP_RNDN);
+ REAL_VALUE_TYPE r2;
+ real_convert(&r2, TYPE_MODE(TREE_TYPE(type)), &r1);
+ tree imag = build_real_from_int_cst(TREE_TYPE(type),
+ integer_zero_node);
+ return build_complex(type, build_real(TREE_TYPE(type), r2), imag);
+ }
+ else
+ gcc_unreachable();
+}
+
+// Return a tree for REAL/IMAG in TYPE.
+
+tree
+Expression::complex_constant_tree(mpfr_t real, mpfr_t imag, tree type)
+{
+ if (TREE_CODE(type) == COMPLEX_TYPE)
+ {
+ REAL_VALUE_TYPE r1;
+ real_from_mpfr(&r1, real, TREE_TYPE(type), GMP_RNDN);
+ REAL_VALUE_TYPE r2;
+ real_convert(&r2, TYPE_MODE(TREE_TYPE(type)), &r1);
+
+ REAL_VALUE_TYPE r3;
+ real_from_mpfr(&r3, imag, TREE_TYPE(type), GMP_RNDN);
+ REAL_VALUE_TYPE r4;
+ real_convert(&r4, TYPE_MODE(TREE_TYPE(type)), &r3);
+
+ return build_complex(type, build_real(TREE_TYPE(type), r2),
+ build_real(TREE_TYPE(type), r4));
+ }
else
gcc_unreachable();
}
@@ -718,6 +781,14 @@
return true;
}
+ bool
+ do_complex_constant_value(mpfr_t real, mpfr_t imag, Type**) const
+ {
+ mpfr_set_ui(real, 0, GMP_RNDN);
+ mpfr_set_ui(imag, 0, GMP_RNDN);
+ return true;
+ }
+
void
do_discarding_value()
{ }
@@ -1481,6 +1552,10 @@
static bool
check_constant(mpz_t val, Type*, source_location);
+ // Write VAL to export data.
+ static void
+ export_integer(Export* exp, const mpz_t val);
+
protected:
bool
do_is_constant() const
@@ -1549,7 +1624,8 @@
;
else if (context->type != NULL
&& (context->type->integer_type() != NULL
- || context->type->float_type() != NULL))
+ || context->type->float_type() != NULL
+ || context->type->complex_type() != NULL))
this->type_ = context->type;
else if (!context->may_be_abstract)
this->type_ = Type::lookup_integer_type("int");
@@ -1621,6 +1697,11 @@
// We are converting to an abstract floating point type.
type = Type::lookup_float_type("float64")->get_tree(gogo);
}
+ else if (this->type_ != NULL && this->type_->complex_type() != NULL)
+ {
+ // We are converting to an abstract complex type.
+ type = Type::lookup_complex_type("complex128")->get_tree(gogo);
+ }
else
{
// If we still have an abstract type here, then this is being
@@ -1638,35 +1719,92 @@
return Expression::integer_constant_tree(this->val_, type);
}
-// Export an integer in a constant expression.
-
-void
-Integer_expression::do_export(Export* exp) const
-{
- char* s = mpz_get_str(NULL, 10, this->val_);
+// Write VAL to export data.
+
+void
+Integer_expression::export_integer(Export* exp, const mpz_t val)
+{
+ char* s = mpz_get_str(NULL, 10, val);
exp->write_c_string(s);
free(s);
+}
+
+// Export an integer in a constant expression.
+
+void
+Integer_expression::do_export(Export* exp) const
+{
+ Integer_expression::export_integer(exp, this->val_);
// A trailing space lets us reliably identify the end of the number.
exp->write_c_string(" ");
}
-// Import an integer or floating point value. This handles both
-// because they both start with digits.
+// Import an integer, floating point, or complex value. This handles
+// all these types because they all start with digits.
Expression*
Integer_expression::do_import(Import* imp)
{
std::string num = imp->read_identifier();
imp->require_c_string(" ");
- if (num.find('.') == std::string::npos && num.find('E') == std::string::npos)
- {
- mpz_t val;
- if (mpz_init_set_str(val, num.c_str(), 10) != 0)
+ if (!num.empty() && num[num.length() - 1] == 'i')
+ {
+ mpfr_t real;
+ size_t plus_pos = num.find('+', 1);
+ size_t minus_pos = num.find('-', 1);
+ size_t pos;
+ if (plus_pos == std::string::npos)
+ pos = minus_pos;
+ else if (minus_pos == std::string::npos)
+ pos = plus_pos;
+ else
{
error_at(imp->location(), "bad number in import data: %qs",
num.c_str());
return Expression::make_error(imp->location());
}
+ if (pos == std::string::npos)
+ mpfr_set_ui(real, 0, GMP_RNDN);
+ else
+ {
+ std::string real_str = num.substr(0, pos);
+ if (mpfr_init_set_str(real, real_str.c_str(), 10, GMP_RNDN) != 0)
+ {
+ error_at(imp->location(), "bad number in import data: %qs",
+ real_str.c_str());
+ return Expression::make_error(imp->location());
+ }
+ }
+
+ std::string imag_str;
+ if (pos == std::string::npos)
+ imag_str = num;
+ else
+ imag_str = num.substr(pos);
+ imag_str = imag_str.substr(0, imag_str.size() - 1);
+ mpfr_t imag;
+ if (mpfr_init_set_str(imag, imag_str.c_str(), 10, GMP_RNDN) != 0)
+ {
+ error_at(imp->location(), "bad number in import data: %qs",
+ imag_str.c_str());
+ return Expression::make_error(imp->location());
+ }
+ Expression* ret = Expression::make_complex(&real, &imag, NULL,
+ imp->location());
+ mpfr_clear(real);
+ mpfr_clear(imag);
+ return ret;
+ }
+ else if (num.find('.') == std::string::npos
+ && num.find('E') == std::string::npos)
+ {
+ mpz_t val;
+ if (mpz_init_set_str(val, num.c_str(), 10) != 0)
+ {
+ error_at(imp->location(), "bad number in import data: %qs",
+ num.c_str());
+ return Expression::make_error(imp->location());
+ }
Expression* ret = Expression::make_integer(&val, NULL, imp->location());
mpz_clear(val);
return ret;
@@ -1715,6 +1853,10 @@
static bool
check_constant(mpfr_t val, Type*, source_location);
+ // Write VAL to export data.
+ static void
+ export_float(Export* exp, const mpfr_t val);
+
protected:
bool
do_is_constant() const
@@ -1798,7 +1940,8 @@
;
else if (context->type != NULL
&& (context->type->integer_type() != NULL
- || context->type->float_type() != NULL))
+ || context->type->float_type() != NULL
+ || context->type->complex_type() != NULL))
this->type_ = context->type;
else if (!context->may_be_abstract)
this->type_ = Type::lookup_float_type("float");
@@ -1814,7 +1957,7 @@
{
if (type == NULL)
return true;
- Float_type* ftype= type->float_type();
+ Float_type* ftype = type->float_type();
if (ftype == NULL || ftype->is_abstract())
return true;
@@ -1897,18 +2040,29 @@
return Expression::float_constant_tree(this->val_, type);
}
-// Export a floating point number in a constant expression.
-
-void
-Float_expression::do_export(Export* exp) const
-{
+// Write a floating point number to export data.
+
+void
+Float_expression::export_float(Export *exp, const mpfr_t val)
+{
+ mp_exp_t exponent;
+ char* s = mpfr_get_str(NULL, &exponent, 10, 0, val, GMP_RNDN);
+ if (*s == '-')
+ exp->write_c_string("-");
exp->write_c_string("0.");
- mp_exp_t exponent;
- char* s = mpfr_get_str(NULL, &exponent, 10, 0, this->val_, GMP_RNDN);
- exp->write_c_string(s);
+ exp->write_c_string(*s == '-' ? s + 1 : s);
+ mpfr_free_str(s);
char buf[30];
snprintf(buf, sizeof buf, "E%ld", exponent);
exp->write_c_string(buf);
+}
+
+// Export a floating point number in a constant expression.
+
+void
+Float_expression::do_export(Export* exp) const
+{
+ Float_expression::export_float(exp, this->val_);
// A trailing space lets us reliably identify the end of the number.
exp->write_c_string(" ");
}
@@ -1921,6 +2075,247 @@
return new Float_expression(val, type, location);
}
+// Complex numbers.
+
+class Complex_expression : public Expression
+{
+ public:
+ Complex_expression(const mpfr_t* real, const mpfr_t* imag, Type* type,
+ source_location location)
+ : Expression(EXPRESSION_COMPLEX, location),
+ type_(type)
+ {
+ mpfr_init_set(this->real_, *real, GMP_RNDN);
+ mpfr_init_set(this->imag_, *imag, GMP_RNDN);
+ }
+
+ // Constrain REAL/IMAG to fit into TYPE.
+ static void
+ constrain_complex(mpfr_t real, mpfr_t imag, Type* type);
+
+ // Return whether REAL/IMAG fits in the type.
+ static bool
+ check_constant(mpfr_t real, mpfr_t imag, Type*, source_location);
+
+ // Write REAL/IMAG to export data.
+ static void
+ export_complex(Export* exp, const mpfr_t real, const mpfr_t val);
+
+ protected:
+ bool
+ do_is_constant() const
+ { return true; }
+
+ bool
+ do_complex_constant_value(mpfr_t real, mpfr_t imag, Type**) const;
+
+ Type*
+ do_type();
+
+ void
+ do_determine_type(const Type_context*);
+
+ void
+ do_check_types(Gogo*);
+
+ Expression*
+ do_copy()
+ {
+ return Expression::make_complex(&this->real_, &this->imag_, this->type_,
+ this->location());
+ }
+
+ tree
+ do_get_tree(Translate_context*);
+
+ void
+ do_export(Export*) const;
+
+ private:
+ // The real part.
+ mpfr_t real_;
+ // The imaginary part;
+ mpfr_t imag_;
+ // The type if known.
+ Type* type_;
+};
+
+// Constrain REAL/IMAG to fit into TYPE.
+
+void
+Complex_expression::constrain_complex(mpfr_t real, mpfr_t imag, Type* type)
+{
+ Complex_type* ctype = type->complex_type();
+ if (ctype != NULL && !ctype->is_abstract())
+ {
+ tree type_tree = ctype->type_tree();
+
+ REAL_VALUE_TYPE rvt;
+ real_from_mpfr(&rvt, real, TREE_TYPE(type_tree), GMP_RNDN);
+ real_convert(&rvt, TYPE_MODE(TREE_TYPE(type_tree)), &rvt);
+ mpfr_from_real(real, &rvt, GMP_RNDN);
+
+ real_from_mpfr(&rvt, imag, TREE_TYPE(type_tree), GMP_RNDN);
+ real_convert(&rvt, TYPE_MODE(TREE_TYPE(type_tree)), &rvt);
+ mpfr_from_real(imag, &rvt, GMP_RNDN);
+ }
+}
+
+// Return a complex constant value.
+
+bool
+Complex_expression::do_complex_constant_value(mpfr_t real, mpfr_t imag,
+ Type** ptype) const
+{
+ if (this->type_ != NULL)
+ *ptype = this->type_;
+ mpfr_set(real, this->real_, GMP_RNDN);
+ mpfr_set(imag, this->imag_, GMP_RNDN);
+ return true;
+}
+
+// Return the current type. If we haven't set the type yet, we return
+// an abstract complex type.
+
+Type*
+Complex_expression::do_type()
+{
+ if (this->type_ == NULL)
+ this->type_ = Type::make_abstract_complex_type();
+ return this->type_;
+}
+
+// Set the type of the complex value. Here we may switch from an
+// abstract type to a real type.
+
+void
+Complex_expression::do_determine_type(const Type_context* context)
+{
+ if (this->type_ != NULL && !this->type_->is_abstract())
+ ;
+ else if (context->type != NULL
+ && context->type->complex_type() != NULL)
+ this->type_ = context->type;
+ else if (!context->may_be_abstract)
+ this->type_ = Type::lookup_complex_type("complex");
+}
+
+// Return true if the complex value REAL/IMAG fits in the range of the
+// type TYPE. Otherwise give an error and return false. TYPE may be
+// NULL.
+
+bool
+Complex_expression::check_constant(mpfr_t real, mpfr_t imag, Type* type,
+ source_location location)
+{
+ if (type == NULL)
+ return true;
+ Complex_type* ctype = type->complex_type();
+ if (ctype == NULL || ctype->is_abstract())
+ return true;
+
+ mp_exp_t max_exp;
+ switch (ctype->bits())
+ {
+ case 64:
+ max_exp = 128;
+ break;
+ case 128:
+ max_exp = 1024;
+ break;
+ default:
+ gcc_unreachable();
+ }
+
+ // A NaN or Infinity always fits in the range of the type.
+ if (!mpfr_nan_p(real) && !mpfr_inf_p(real) && !mpfr_zero_p(real))
+ {
+ if (mpfr_get_exp(real) > max_exp)
+ {
+ error_at(location, "complex real part constant overflow");
+ return false;
+ }
+ }
+
+ if (!mpfr_nan_p(imag) && !mpfr_inf_p(imag) && !mpfr_zero_p(imag))
+ {
+ if (mpfr_get_exp(imag) > max_exp)
+ {
+ error_at(location, "complex imaginary part constant overflow");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Check the type of a complex value.
+
+void
+Complex_expression::do_check_types(Gogo*)
+{
+ if (this->type_ == NULL)
+ return;
+
+ if (!Complex_expression::check_constant(this->real_, this->imag_,
+ this->type_, this->location()))
+ this->set_is_error();
+}
+
+// Get a tree for a complex constant.
+
+tree
+Complex_expression::do_get_tree(Translate_context* context)
+{
+ Gogo* gogo = context->gogo();
+ tree type;
+ if (this->type_ != NULL && !this->type_->is_abstract())
+ type = this->type_->get_tree(gogo);
+ else
+ {
+ // If we still have an abstract type here, this this is being
+ // used in a constant expression which didn't get reduced. We
+ // just use complex128 and hope for the best.
+ type = Type::lookup_complex_type("complex128")->get_tree(gogo);
+ }
+ return Expression::complex_constant_tree(this->real_, this->imag_, type);
+}
+
+// Write REAL/IMAG to export data.
+
+void
+Complex_expression::export_complex(Export* exp, const mpfr_t real,
+ const mpfr_t imag)
+{
+ if (!mpfr_zero_p(real))
+ {
+ Float_expression::export_float(exp, real);
+ if (mpfr_sgn(imag) > 0)
+ exp->write_c_string("+");
+ }
+ Float_expression::export_float(exp, imag);
+ exp->write_c_string("i");
+}
+
+// Export a complex number in a constant expression.
+
+void
+Complex_expression::do_export(Export* exp) const
+{
+ Complex_expression::export_complex(exp, this->real_, this->imag_);
+ // A trailing space lets us reliably identify the end of the number.
+ exp->write_c_string(" ");
+}
+
+// Make a complex expression.
+
+Expression*
+Expression::make_complex(const mpfr_t* real, const mpfr_t* imag, Type* type,
+ source_location location)
+{
+ return new Complex_expression(real, imag, type, location);
+}
+
// A reference to a const in an expression.
class Const_expression : public Expression
@@ -1950,6 +2345,9 @@
do_float_constant_value(mpfr_t val, Type**) const;
bool
+ do_complex_constant_value(mpfr_t real, mpfr_t imag, Type**) const;
+
+ bool
do_string_constant_value(std::string* val) const
{ return this->constant_->const_value()->expr()->string_constant_value(val); }
@@ -2080,6 +2478,35 @@
return r;
}
+// Return a complex constant value.
+
+bool
+Const_expression::do_complex_constant_value(mpfr_t real, mpfr_t imag,
+ Type **ptype) const
+{
+ Type* ctype;
+ if (this->type_ != NULL)
+ ctype = this->type_;
+ else
+ ctype = this->constant_->const_value()->type();
+ if (ctype != NULL && ctype->complex_type() == NULL)
+ return false;
+
+ Type *t;
+ bool r = this->constant_->const_value()->expr()->complex_constant_value(real,
+ imag,
+ &t);
+ if (r && ctype != NULL)
+ {
+ if (!Complex_expression::check_constant(real, imag, ctype,
+ this->location()))
+ return false;
+ Complex_expression::constrain_complex(real, imag, ctype);
+ }
+ *ptype = ctype != NULL ? ctype : t;
+ return r;
+}
+
// Return the type of the const reference.
Type*
@@ -2106,7 +2533,8 @@
;
else if (context->type != NULL
&& (context->type->integer_type() != NULL
- || context->type->float_type() != NULL))
+ || context->type->float_type() != NULL
+ || context->type->complex_type() != NULL))
this->type_ = context->type;
else if (!context->may_be_abstract)
{
@@ -2223,6 +2651,17 @@
mpfr_clear(fval);
return ret;
}
+
+ mpfr_t imag;
+ mpfr_init(imag);
+ if (expr->complex_constant_value(fval, imag, &t))
+ {
+ tree ret = Expression::complex_constant_tree(fval, imag, type_tree);
+ mpfr_clear(fval);
+ mpfr_clear(imag);
+ return ret;
+ }
+ mpfr_clear(imag);
mpfr_clear(fval);
}
@@ -2239,6 +2678,8 @@
ret = fold(convert_to_integer(type_tree, const_tree));
else if (TREE_CODE(type_tree) == REAL_TYPE)
ret = fold(convert_to_real(type_tree, const_tree));
+ else if (TREE_CODE(type_tree) == COMPLEX_TYPE)
+ ret = fold(convert_to_complex(type_tree, const_tree));
else
gcc_unreachable();
return ret;
@@ -2383,6 +2824,9 @@
do_float_constant_value(mpfr_t, Type**) const;
bool
+ do_complex_constant_value(mpfr_t, mpfr_t, Type**) const;
+
+ bool
do_string_constant_value(std::string*) const;
Type*
@@ -2456,7 +2900,9 @@
{
if (!Integer_expression::check_constant(ival, type, location))
mpz_set_ui(ival, 0);
- return Expression::make_integer(&ival, type, location);
+ Expression* ret = Expression::make_integer(&ival, type, location);
+ mpz_clear(ival);
+ return ret;
}
mpfr_t fval;
@@ -2472,7 +2918,10 @@
mpfr_get_z(ival, fval, GMP_RNDN);
if (!Integer_expression::check_constant(ival, type, location))
mpz_set_ui(ival, 0);
- return Expression::make_integer(&ival, type, location);
+ Expression* ret = Expression::make_integer(&ival, type, location);
+ mpfr_clear(fval);
+ mpz_clear(ival);
+ return ret;
}
mpfr_clear(fval);
mpz_clear(ival);
@@ -2488,11 +2937,38 @@
if (!Float_expression::check_constant(fval, type, location))
mpfr_set_ui(fval, 0, GMP_RNDN);
Float_expression::constrain_float(fval, type);
- return Expression::make_float(&fval, type, location);
+ Expression *ret = Expression::make_float(&fval, type, location);
+ mpfr_clear(fval);
+ return ret;
}
mpfr_clear(fval);
}
+ if (type->complex_type() != NULL)
+ {
+ mpfr_t real;
+ mpfr_t imag;
+ mpfr_init(real);
+ mpfr_init(imag);
+ Type* dummy;
+ if (val->complex_constant_value(real, imag, &dummy))
+ {
+ if (!Complex_expression::check_constant(real, imag, type, location))
+ {
+ mpfr_set_ui(real, 0, GMP_RNDN);
+ mpfr_set_ui(imag, 0, GMP_RNDN);
+ }
+ Complex_expression::constrain_complex(real, imag, type);
+ Expression* ret = Expression::make_complex(&real, &imag, type,
+ location);
+ mpfr_clear(real);
+ mpfr_clear(imag);
+ return ret;
+ }
+ mpfr_clear(real);
+ mpfr_clear(imag);
+ }
+
return this;
}
@@ -2569,22 +3045,45 @@
}
mpfr_clear(fval);
- mpz_t ival;
- mpz_init(ival);
- if (this->expr_->integer_constant_value(false, ival, &dummy))
- {
- mpfr_set_z(val, ival, GMP_RNDN);
- mpz_clear(ival);
- if (!Float_expression::check_constant(val, this->type_,
- this->location()))
- return false;
- Float_expression::constrain_float(val, this->type_);
+ return false;
+}
+
+// Return the constant complex value if there is one.
+
+bool
+Type_conversion_expression::do_complex_constant_value(mpfr_t real,
+ mpfr_t imag,
+ Type **ptype) const
+{
+ if (this->type_->complex_type() == NULL)
+ return false;
+
+ mpfr_t rval;
+ mpfr_t ival;
+ mpfr_init(rval);
+ mpfr_init(ival);
+ Type* dummy;
+ if (this->expr_->complex_constant_value(rval, ival, &dummy))
+ {
+ if (!Complex_expression::check_constant(rval, ival, this->type_,
+ this->location()))
+ {
+ mpfr_clear(rval);
+ mpfr_clear(ival);
+ return false;
+ }
+ mpfr_set(real, rval, GMP_RNDN);
+ mpfr_set(imag, ival, GMP_RNDN);
+ mpfr_clear(rval);
+ mpfr_clear(ival);
+ Complex_expression::constrain_complex(real, imag, this->type_);
*ptype = this->type_;
return true;
}
- mpz_clear(ival);
-
- return false;
+ mpfr_clear(rval);
+ mpfr_clear(ival);
+
+ return false;
}
// Return the constant string value if there is one.
@@ -2633,6 +3132,9 @@
&& (expr_type->integer_type() != NULL
|| expr_type->float_type() != NULL))
ok = true;
+ else if (type->complex_type() != NULL
+ && expr_type->complex_type() != NULL)
+ ok = true;
else if (type->is_string_type())
{
if (expr_type->integer_type() != NULL)
@@ -2791,6 +3293,13 @@
else
gcc_unreachable();
}
+ else if (type->complex_type() != NULL)
+ {
+ if (expr_type->complex_type() != NULL)
+ ret = fold(convert_to_complex(type_tree, expr_tree));
+ else
+ gcc_unreachable();
+ }
else if (type->is_string_type()
&& expr_type->integer_type() != NULL)
{
@@ -2979,6 +3488,12 @@
static bool
eval_float(Operator op, mpfr_t uval, mpfr_t val);
+ // Apply unary opcode OP to UREAL/UIMAG, setting REAL/IMAG. Return
+ // true if this could be done, false if not.
+ static bool
+ eval_complex(Operator op, mpfr_t ureal, mpfr_t uimag, mpfr_t real,
+ mpfr_t imag);
+
static Expression*
do_import(Import*);
@@ -2999,6 +3514,9 @@
bool
do_float_constant_value(mpfr_t, Type**) const;
+ bool
+ do_complex_constant_value(mpfr_t, mpfr_t, Type**) const;
+
Type*
do_type();
@@ -3123,6 +3641,26 @@
ret = Expression::make_float(&val, ftype, loc);
mpfr_clear(val);
}
+ if (ret != NULL)
+ {
+ mpfr_clear(fval);
+ return ret;
+ }
+
+ mpfr_t ival;
+ mpfr_init(ival);
+ if (expr->complex_constant_value(fval, ival, &ftype))
+ {
+ mpfr_t real;
+ mpfr_t imag;
+ mpfr_init(real);
+ mpfr_init(imag);
+ if (Unary_expression::eval_complex(op, fval, ival, real, imag))
+ ret = Expression::make_complex(&real, &imag, ftype, loc);
+ mpfr_clear(real);
+ mpfr_clear(imag);
+ }
+ mpfr_clear(ival);
mpfr_clear(fval);
if (ret != NULL)
return ret;
@@ -3254,6 +3792,33 @@
}
}
+// Apply unary opcode OP to RVAL/IVAL, setting REAL/IMAG. Return true
+// if this could be done, false if not.
+
+bool
+Unary_expression::eval_complex(Operator op, mpfr_t rval, mpfr_t ival,
+ mpfr_t real, mpfr_t imag)
+{
+ switch (op)
+ {
+ case OPERATOR_PLUS:
+ mpfr_set(real, rval, GMP_RNDN);
+ mpfr_set(imag, ival, GMP_RNDN);
+ return true;
+ case OPERATOR_MINUS:
+ mpfr_neg(real, rval, GMP_RNDN);
+ mpfr_neg(imag, ival, GMP_RNDN);
+ return true;
+ case OPERATOR_NOT:
+ case OPERATOR_XOR:
+ case OPERATOR_AND:
+ case OPERATOR_MULT:
+ return false;
+ default:
+ gcc_unreachable();
+ }
+}
+
// Return the integral constant value of a unary expression, if it has one.
bool
@@ -3289,6 +3854,27 @@
return ret;
}
+// Return the complex constant value of a unary expression, if it has
+// one.
+
+bool
+Unary_expression::do_complex_constant_value(mpfr_t real, mpfr_t imag,
+ Type** ptype) const
+{
+ mpfr_t rval;
+ mpfr_t ival;
+ mpfr_init(rval);
+ mpfr_init(ival);
+ bool ret;
+ if (!this->expr_->complex_constant_value(rval, ival, ptype))
+ ret = false;
+ else
+ ret = Unary_expression::eval_complex(this->op_, rval, ival, real, imag);
+ mpfr_clear(rval);
+ mpfr_clear(ival);
+ return ret;
+}
+
// Return the type of a unary expression.
Type*
@@ -3373,6 +3959,7 @@
Type* type = this->expr_->type();
if (type->integer_type() == NULL
&& type->float_type() == NULL
+ && type->complex_type() == NULL
&& !type->is_error_type())
this->report_error(_("expected numeric type"));
}
@@ -3486,14 +4073,14 @@
tree type = TREE_TYPE(expr);
tree compute_type = excess_precision_type(type);
if (compute_type != NULL_TREE)
- expr = convert_to_real(compute_type, expr);
+ expr = ::convert(compute_type, expr);
tree ret = fold_build1_loc(loc, NEGATE_EXPR,
(compute_type != NULL_TREE
? compute_type
: type),
expr);
if (compute_type != NULL_TREE)
- ret = convert_to_real(type, ret);
+ ret = ::convert(type, ret);
return ret;
}
@@ -3683,6 +4270,47 @@
}
}
+// Compare complex constants according to OP. Complex numbers may
+// only be compared for equality.
+
+bool
+Binary_expression::compare_complex(Operator op, Type* type,
+ mpfr_t left_real, mpfr_t left_imag,
+ mpfr_t right_real, mpfr_t right_imag)
+{
+ bool is_equal;
+ if (type == NULL)
+ is_equal = (mpfr_cmp(left_real, right_real) == 0
+ && mpfr_cmp(left_imag, right_imag) == 0);
+ else
+ {
+ 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);
+ Complex_expression::constrain_complex(lr, li, type);
+ Complex_expression::constrain_complex(rr, ri, type);
+ is_equal = mpfr_cmp(lr, rr) == 0 && mpfr_cmp(li, ri) == 0;
+ mpfr_clear(lr);
+ mpfr_clear(li);
+ mpfr_clear(rr);
+ mpfr_clear(ri);
+ }
+ switch (op)
+ {
+ case OPERATOR_EQEQ:
+ return is_equal;
+ case OPERATOR_NOTEQ:
+ return !is_equal;
+ default:
+ gcc_unreachable();
+ }
+}
+
// Apply binary opcode OP to LEFT_VAL and RIGHT_VAL, setting VAL.
// LEFT_TYPE is the type of LEFT_VAL, RIGHT_TYPE is the type of
// RIGHT_VAL; LEFT_TYPE and/or RIGHT_TYPE may be NULL. Return true if
@@ -3904,6 +4532,370 @@
return true;
}
+// Apply binary opcode OP to LEFT_REAL/LEFT_IMAG and
+// RIGHT_REAL/RIGHT_IMAG, setting REAL/IMAG. Return true if this
+// could be done, false if not.
+
+bool
+Binary_expression::eval_complex(Operator op, Type* left_type,
+ mpfr_t left_real, mpfr_t left_imag,
+ Type *right_type,
+ mpfr_t right_real, mpfr_t right_imag,
+ mpfr_t real, mpfr_t imag,
+ source_location location)
+{
+ switch (op)
+ {
+ case OPERATOR_OROR:
+ case OPERATOR_ANDAND:
+ case OPERATOR_EQEQ:
+ case OPERATOR_NOTEQ:
+ case OPERATOR_LT:
+ case OPERATOR_LE:
+ case OPERATOR_GT:
+ case OPERATOR_GE:
+ // These return boolean values and must be handled differently.
+ return false;
+ case OPERATOR_PLUS:
+ mpfr_add(real, left_real, right_real, GMP_RNDN);
+ mpfr_add(imag, left_imag, right_imag, GMP_RNDN);
+ break;
+ case OPERATOR_MINUS:
+ mpfr_sub(real, left_real, right_real, GMP_RNDN);
+ mpfr_sub(imag, left_imag, right_imag, GMP_RNDN);
+ break;
+ case OPERATOR_OR:
+ case OPERATOR_XOR:
+ case OPERATOR_AND:
+ case OPERATOR_BITCLEAR:
+ return false;
+ 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);
+ }
+ 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_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);
+ }
+ break;
+ case OPERATOR_MOD:
+ return false;
+ case OPERATOR_LSHIFT:
+ case OPERATOR_RSHIFT:
+ return false;
+ default:
+ gcc_unreachable();
+ }
+
+ Type* type = left_type;
+ if (type == NULL)
+ type = right_type;
+ else if (type != right_type && right_type != NULL)
+ {
+ if (type->is_abstract())
+ type = right_type;
+ else if (!right_type->is_abstract())
+ {
+ // This looks like a type error which should be diagnosed
+ // elsewhere. Don't do anything here, to avoid an unhelpful
+ // chain of error messages.
+ return true;
+ }
+ }
+
+ if (type != NULL && !type->is_abstract())
+ {
+ if ((type != left_type
+ && !Complex_expression::check_constant(left_real, left_imag,
+ type, location))
+ || (type != right_type
+ && !Complex_expression::check_constant(right_real, right_imag,
+ type, location))
+ || !Complex_expression::check_constant(real, imag, type,
+ location))
+ {
+ mpfr_set_ui(real, 0, GMP_RNDN);
+ mpfr_set_ui(imag, 0, GMP_RNDN);
+ }
+ }
+
+ return true;
+}
+
// Lower a binary expression. We have to evaluate constant
// expressions now, in order to implement Go's unlimited precision
// constants.
@@ -3983,6 +4975,10 @@
type = left_type;
else if (right_type->float_type() != NULL)
type = right_type;
+ else if (left_type->complex_type() != NULL)
+ type = left_type;
+ else if (right_type->complex_type() != NULL)
+ type = right_type;
else
type = left_type;
ret = Expression::make_integer(&val, type, location);
@@ -4049,7 +5045,7 @@
else if (right_type == NULL)
type = left_type;
else if (!left_type->is_abstract()
- && left_type->named_type() != NULL)
+ && left_type->named_type() != NULL)
type = left_type;
else if (!right_type->is_abstract()
&& right_type->named_type() != NULL)
@@ -4081,6 +5077,103 @@
mpfr_clear(left_val);
}
+ // Complex constant expressions.
+ {
+ mpfr_t left_real;
+ mpfr_t left_imag;
+ mpfr_init(left_real);
+ mpfr_init(left_imag);
+ Type* left_type;
+
+ mpfr_t right_real;
+ mpfr_t right_imag;
+ mpfr_init(right_real);
+ mpfr_init(right_imag);
+ Type* right_type;
+
+ if (left->complex_constant_value(left_real, left_imag, &left_type)
+ && right->complex_constant_value(right_real, right_imag, &right_type))
+ {
+ Expression* ret = NULL;
+ if (left_type != right_type
+ && left_type != NULL
+ && right_type != NULL
+ && left_type->base() != right_type->base())
+ {
+ // May be a type error--let it be diagnosed later.
+ }
+ else if (is_comparison)
+ {
+ bool b = Binary_expression::compare_complex(op,
+ (left_type != NULL
+ ? left_type
+ : right_type),
+ left_real,
+ left_imag,
+ right_real,
+ right_imag);
+ ret = Expression::make_boolean(b, location);
+ }
+ else
+ {
+ mpfr_t real;
+ mpfr_t imag;
+ mpfr_init(real);
+ mpfr_init(imag);
+
+ if (Binary_expression::eval_complex(op, left_type,
+ left_real, left_imag,
+ right_type,
+ right_real, right_imag,
+ real, imag,
+ location))
+ {
+ gcc_assert(op != OPERATOR_OROR && op != OPERATOR_ANDAND
+ && op != OPERATOR_LSHIFT && op != OPERATOR_RSHIFT);
+ Type* type;
+ if (left_type == NULL)
+ type = right_type;
+ else if (right_type == NULL)
+ type = left_type;
+ else if (!left_type->is_abstract()
+ && left_type->named_type() != NULL)
+ type = left_type;
+ else if (!right_type->is_abstract()
+ && right_type->named_type() != NULL)
+ type = right_type;
+ else if (!left_type->is_abstract())
+ type = left_type;
+ else if (!right_type->is_abstract())
+ type = right_type;
+ else if (left_type->complex_type() != NULL)
+ type = left_type;
+ else if (right_type->complex_type() != NULL)
+ type = right_type;
+ else
+ type = left_type;
+ ret = Expression::make_complex(&real, &imag, type,
+ location);
+ }
+ mpfr_clear(real);
+ mpfr_clear(imag);
+ }
+
+ if (ret != NULL)
+ {
+ mpfr_clear(left_real);
+ mpfr_clear(left_imag);
+ mpfr_clear(right_real);
+ mpfr_clear(right_imag);
+ return ret;
+ }
+ }
+
+ mpfr_clear(left_real);
+ mpfr_clear(left_imag);
+ mpfr_clear(right_real);
+ mpfr_clear(right_imag);
+ }
+
// String constant expressions.
if (op == OPERATOR_PLUS
&& left->type()->is_string_type()
@@ -4140,9 +5233,7 @@
mpz_clear(left_val);
if (ret)
- *ptype = (this->op_ == OPERATOR_OROR || this->op_ == OPERATOR_OROR
- ? right_type
- : left_type);
+ *ptype = left_type;
return ret;
}
@@ -4186,9 +5277,64 @@
mpfr_clear(right_val);
if (ret)
- *ptype = (this->op_ == OPERATOR_OROR || this->op_ == OPERATOR_OROR
- ? right_type
- : left_type);
+ *ptype = left_type;
+
+ return ret;
+}
+
+// Return the complex constant value, if it has one.
+
+bool
+Binary_expression::do_complex_constant_value(mpfr_t real, mpfr_t imag,
+ Type** ptype) const
+{
+ mpfr_t left_real;
+ mpfr_t left_imag;
+ mpfr_init(left_real);
+ mpfr_init(left_imag);
+ Type* left_type;
+ if (!this->left_->complex_constant_value(left_real, left_imag, &left_type))
+ {
+ mpfr_clear(left_real);
+ mpfr_clear(left_imag);
+ return false;
+ }
+
+ mpfr_t right_real;
+ mpfr_t right_imag;
+ mpfr_init(right_real);
+ mpfr_init(right_imag);
+ Type* right_type;
+ if (!this->right_->complex_constant_value(right_real, right_imag,
+ &right_type))
+ {
+ mpfr_clear(left_real);
+ mpfr_clear(left_imag);
+ mpfr_clear(right_real);
+ mpfr_clear(right_imag);
+ return false;
+ }
+
+ bool ret;
+ if (left_type != right_type
+ && left_type != NULL
+ && right_type != NULL
+ && left_type->base() != right_type->base())
+ ret = false;
+ else
+ ret = Binary_expression::eval_complex(this->op_, left_type,
+ left_real, left_imag,
+ right_type,
+ right_real, right_imag,
+ real, imag,
+ this->location());
+ mpfr_clear(left_real);
+ mpfr_clear(left_imag);
+ mpfr_clear(right_real);
+ mpfr_clear(right_imag);
+
+ if (ret)
+ *ptype = left_type;
return ret;
}
@@ -4241,6 +5387,10 @@
return left_type;
else if (!right_type->is_abstract())
return right_type;
+ else if (left_type->complex_type() != NULL)
+ return left_type;
+ else if (right_type->complex_type() != NULL)
+ return right_type;
else if (left_type->float_type() != NULL)
return left_type;
else if (right_type->float_type() != NULL)
@@ -4308,19 +5458,23 @@
else if (subcontext.type == NULL)
{
if ((tleft->integer_type() != NULL && tright->integer_type() != NULL)
- || (tleft->float_type() != NULL && tright->float_type() != NULL))
- {
- // Both sides have an abstract integer type or both sides
- // have an abstract float type. Just let CONTEXT determine
+ || (tleft->float_type() != NULL && tright->float_type() != NULL)
+ || (tleft->complex_type() != NULL && tright->complex_type() != NULL))
+ {
+ // Both sides have an abstract integer, abstract float, or
+ // abstract complex type. Just let CONTEXT determine
// whether they may remain abstract or not.
}
- else
- {
- // Both sides are abstract, but one is integer and one is
- // floating point. Convert the abstract integer to floating
- // point.
- subcontext.type = tleft->float_type() != NULL ? tleft : tright;
- }
+ else if (tleft->complex_type() != NULL)
+ subcontext.type = tleft;
+ else if (tright->complex_type() != NULL)
+ subcontext.type = tright;
+ else if (tleft->float_type() != NULL)
+ subcontext.type = tleft;
+ else if (tright->float_type() != NULL)
+ subcontext.type = tright;
+ else
+ subcontext.type = tleft;
}
this->left_->determine_type(&subcontext);
@@ -4359,6 +5513,7 @@
case OPERATOR_NOTEQ:
if (type->integer_type() == NULL
&& type->float_type() == NULL
+ && type->complex_type() == NULL
&& !type->is_string_type()
&& type->points_to() == NULL
&& !type->is_nil_type()
@@ -4371,8 +5526,9 @@
&& type->function_type() == NULL)
{
error_at(location,
- _("expected integer, floating, string, pointer, boolean, "
- "interface, slice, map, channel, or function type"));
+ _("expected integer, floating, complex, string, pointer, "
+ "boolean, interface, slice, map, channel, "
+ "or function type"));
return false;
}
break;
@@ -4381,14 +5537,25 @@
case OPERATOR_LE:
case OPERATOR_GT:
case OPERATOR_GE:
+ if (type->integer_type() == NULL
+ && type->float_type() == NULL
+ && !type->is_string_type())
+ {
+ error_at(location,
+ _("expected integer, floating, or string type"));
+ return false;
+ }
+ break;
+
case OPERATOR_PLUS:
case OPERATOR_PLUSEQ:
if (type->integer_type() == NULL
&& type->float_type() == NULL
+ && type->complex_type() == NULL
&& !type->is_string_type())
{
error_at(location,
- _("expected integer, floating, or string type"));
+ _("expected integer, floating, complex, or string type"));
return false;
}
break;
@@ -4400,9 +5567,10 @@
case OPERATOR_DIV:
case OPERATOR_DIVEQ:
if (type->integer_type() == NULL
- && type->float_type() == NULL)
- {
- error_at(location, _("expected integer or floating type"));
+ && type->float_type() == NULL
+ && type->complex_type() == NULL)
+ {
+ error_at(location, _("expected integer, floating, or complex type"));
return false;
}
break;
@@ -4559,11 +5727,15 @@
code = MULT_EXPR;
break;
case OPERATOR_DIV:
- // FIXME: Code depends on whether integer or floating point.
- code = TRUNC_DIV_EXPR;
+ {
+ Type *t = this->left_->type();
+ if (t->float_type() != NULL || t->complex_type() != NULL)
+ code = RDIV_EXPR;
+ else
+ code = TRUNC_DIV_EXPR;
+ }
break;
case OPERATOR_MOD:
- // FIXME: Code depends on whether integer or floating point.
code = TRUNC_MOD_EXPR;
break;
case OPERATOR_LSHIFT:
@@ -4606,8 +5778,8 @@
tree compute_type = excess_precision_type(type);
if (compute_type != NULL_TREE)
{
- left = convert_to_real(compute_type, left);
- right = convert_to_real(compute_type, right);
+ left = ::convert(compute_type, left);
+ right = ::convert(compute_type, right);
}
tree eval_saved = NULL_TREE;
@@ -4628,7 +5800,7 @@
left, right);
if (compute_type != NULL_TREE)
- ret = convert_to_real(type, ret);
+ ret = ::convert(type, ret);
// In Go, a shift larger than the size of the type is well-defined.
// This is not true in GENERIC, so we need to insert a conditional.
@@ -5074,6 +6246,12 @@
bool
do_integer_constant_value(bool, mpz_t, Type**) const;
+ bool
+ do_float_constant_value(mpfr_t, Type**) const;
+
+ bool
+ do_complex_constant_value(mpfr_t, mpfr_t, Type**) const;
+
Type*
do_type();
@@ -5107,7 +6285,9 @@
BUILTIN_CAP,
BUILTIN_CLOSE,
BUILTIN_CLOSED,
+ BUILTIN_CMPLX,
BUILTIN_COPY,
+ BUILTIN_IMAG,
BUILTIN_LEN,
BUILTIN_MAKE,
BUILTIN_NEW,
@@ -5115,6 +6295,7 @@
BUILTIN_PANICLN,
BUILTIN_PRINT,
BUILTIN_PRINTLN,
+ BUILTIN_REAL,
// Builtin functions from the unsafe package.
BUILTIN_ALIGNOF,
@@ -5128,6 +6309,12 @@
bool
check_one_arg();
+ static Type*
+ real_imag_type(Type*);
+
+ static Type*
+ cmplx_type(Type*);
+
// A pointer back to the general IR structure. This avoids a global
// variable, or passing it around everywhere.
Gogo* gogo_;
@@ -5151,8 +6338,12 @@
this->code_ = BUILTIN_CLOSE;
else if (name == "closed")
this->code_ = BUILTIN_CLOSED;
+ else if (name == "cmplx")
+ this->code_ = BUILTIN_CMPLX;
else if (name == "copy")
this->code_ = BUILTIN_COPY;
+ else if (name == "imag")
+ this->code_ = BUILTIN_IMAG;
else if (name == "len")
this->code_ = BUILTIN_LEN;
else if (name == "make")
@@ -5167,6 +6358,8 @@
this->code_ = BUILTIN_PRINT;
else if (name == "println")
this->code_ = BUILTIN_PRINTLN;
+ else if (name == "real")
+ this->code_ = BUILTIN_REAL;
else if (name == "Alignof")
this->code_ = BUILTIN_ALIGNOF;
else if (name == "Offsetof")
@@ -5246,9 +6439,80 @@
return ret;
}
mpz_clear(ival);
- }
-
- return this;
+
+ mpfr_t rval;
+ mpfr_init(rval);
+ if (this->float_constant_value(rval, &type))
+ {
+ Expression* ret = Expression::make_float(&rval, type,
+ this->location());
+ mpfr_clear(rval);
+ return ret;
+ }
+
+ mpfr_t imag;
+ mpfr_init(imag);
+ if (this->complex_constant_value(rval, imag, &type))
+ {
+ Expression* ret = Expression::make_complex(&rval, &imag, type,
+ this->location());
+ mpfr_clear(rval);
+ mpfr_clear(imag);
+ return ret;
+ }
+ mpfr_clear(rval);
+ mpfr_clear(imag);
+ }
+
+ return this;
+}
+
+// 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.
+
+Type*
+Builtin_call_expression::real_imag_type(Type* arg_type)
+{
+ if (arg_type == NULL || arg_type->is_abstract())
+ return NULL;
+ Named_type* nt = arg_type->named_type();
+ if (nt == NULL)
+ return NULL;
+ while (nt->real_type()->named_type() != NULL)
+ nt = nt->real_type()->named_type();
+ if (nt->name() == "complex")
+ return Type::lookup_float_type("float");
+ else if (nt->name() == "complex64")
+ return Type::lookup_float_type("float32");
+ else if (nt->name() == "complex128")
+ return Type::lookup_float_type("float64");
+ else
+ return NULL;
+}
+
+// Return the type of the cmplx function, given the type of one of the
+// argments. Like real_imag_type, we have to map by name.
+
+Type*
+Builtin_call_expression::cmplx_type(Type* arg_type)
+{
+ if (arg_type == NULL || arg_type->is_abstract())
+ return NULL;
+ Named_type* nt = arg_type->named_type();
+ if (nt == NULL)
+ return NULL;
+ while (nt->real_type()->named_type() != NULL)
+ nt = nt->real_type()->named_type();
+ if (nt->name() == "float")
+ return Type::lookup_complex_type("complex");
+ else if (nt->name() == "float32")
+ return Type::lookup_complex_type("complex64");
+ else if (nt->name() == "float64")
+ return Type::lookup_complex_type("complex128");
+ else
+ return NULL;
}
// Return a single argument, or NULL if there isn't one.
@@ -5268,36 +6532,61 @@
bool
Builtin_call_expression::do_is_constant() const
{
- if (this->code_ == BUILTIN_LEN
- || this->code_ == BUILTIN_CAP)
- {
- Expression* arg = this->one_arg();
- if (arg == NULL)
- return false;
- Type* arg_type = arg->type();
-
- if (arg_type->points_to() != NULL
- && arg_type->points_to()->array_type() != NULL
- && !arg_type->points_to()->is_open_array_type())
- arg_type = arg_type->points_to();
-
- if (arg_type->array_type() != NULL
- && arg_type->array_type()->length() != NULL)
- return arg_type->array_type()->length()->is_constant();
-
- if (this->code_ == BUILTIN_LEN && arg_type->is_string_type())
- return arg->is_constant();
- }
- else if (this->code_ == BUILTIN_SIZEOF
- || this->code_ == BUILTIN_ALIGNOF)
- return this->one_arg() != NULL;
- else if (this->code_ == BUILTIN_OFFSETOF)
- {
- Expression* arg = this->one_arg();
- if (arg == NULL)
- return false;
- return arg->field_reference_expression() != NULL;
- }
+ switch (this->code_)
+ {
+ case BUILTIN_LEN:
+ case BUILTIN_CAP:
+ {
+ Expression* arg = this->one_arg();
+ if (arg == NULL)
+ return false;
+ Type* arg_type = arg->type();
+
+ if (arg_type->points_to() != NULL
+ && arg_type->points_to()->array_type() != NULL
+ && !arg_type->points_to()->is_open_array_type())
+ arg_type = arg_type->points_to();
+
+ if (arg_type->array_type() != NULL
+ && arg_type->array_type()->length() != NULL)
+ return arg_type->array_type()->length()->is_constant();
+
+ if (this->code_ == BUILTIN_LEN && arg_type->is_string_type())
+ return arg->is_constant();
+ }
+ break;
+
+ case BUILTIN_SIZEOF:
+ case BUILTIN_ALIGNOF:
+ return this->one_arg() != NULL;
+
+ case BUILTIN_OFFSETOF:
+ {
+ Expression* arg = this->one_arg();
+ if (arg == NULL)
+ return false;
+ return arg->field_reference_expression() != NULL;
+ }
+
+ case BUILTIN_CMPLX:
+ {
+ const Expression_list* args = this->args();
+ if (args != NULL && args->size() == 2)
+ return args->front()->is_constant() && args->back()->is_constant();
+ }
+ break;
+
+ case BUILTIN_REAL:
+ case BUILTIN_IMAG:
+ {
+ Expression* arg = this->one_arg();
+ return arg != NULL && arg->is_constant();
+ }
+
+ default:
+ break;
+ }
+
return false;
}
@@ -5427,6 +6716,87 @@
return false;
}
+// Return a floating point constant value if possible.
+
+bool
+Builtin_call_expression::do_float_constant_value(mpfr_t val,
+ Type** ptype) const
+{
+ if (this->code_ == BUILTIN_REAL || this->code_ == BUILTIN_IMAG)
+ {
+ Expression* arg = this->one_arg();
+ if (arg == NULL)
+ return false;
+
+ mpfr_t real;
+ mpfr_t imag;
+ mpfr_init(real);
+ mpfr_init(imag);
+
+ bool ret = false;
+ Type* type;
+ if (arg->complex_constant_value(real, imag, &type))
+ {
+ if (this->code_ == BUILTIN_REAL)
+ mpfr_set(val, real, GMP_RNDN);
+ else
+ mpfr_set(val, imag, GMP_RNDN);
+ *ptype = Builtin_call_expression::real_imag_type(type);
+ ret = true;
+ }
+
+ mpfr_clear(real);
+ mpfr_clear(imag);
+ return ret;
+ }
+
+ return false;
+}
+
+// Return a complex constant value if possible.
+
+bool
+Builtin_call_expression::do_complex_constant_value(mpfr_t real, mpfr_t imag,
+ Type** ptype) const
+{
+ if (this->code_ == BUILTIN_CMPLX)
+ {
+ const Expression_list* args = this->args();
+ if (args == NULL || args->size() != 2)
+ return false;
+
+ mpfr_t r;
+ mpfr_init(r);
+ Type* rtype;
+ if (!args->front()->float_constant_value(r, &rtype))
+ {
+ mpfr_clear(r);
+ return false;
+ }
+
+ mpfr_t i;
+ mpfr_init(i);
+
+ bool ret = false;
+ Type* itype;
+ if (args->back()->float_constant_value(i, &itype)
+ && Type::are_identical(rtype, itype))
+ {
+ mpfr_set(real, r, GMP_RNDN);
+ mpfr_set(imag, i, GMP_RNDN);
+ *ptype = Builtin_call_expression::cmplx_type(rtype);
+ ret = true;
+ }
+
+ mpfr_clear(r);
+ mpfr_clear(i);
+
+ return ret;
+ }
+
+ return false;
+}
+
// Return the type.
Type*
@@ -5464,17 +6834,51 @@
case BUILTIN_CLOSED:
return Type::lookup_bool_type();
+
+ case BUILTIN_REAL:
+ case BUILTIN_IMAG:
+ {
+ Expression* arg = this->one_arg();
+ if (arg == NULL)
+ return Type::make_error_type();
+ Type* t = arg->type();
+ if (t->is_abstract())
+ t = t->make_non_abstract_type();
+ t = Builtin_call_expression::real_imag_type(t);
+ if (t == NULL)
+ t = Type::make_error_type();
+ return t;
+ }
+
+ case BUILTIN_CMPLX:
+ {
+ const Expression_list* args = this->args();
+ if (args == NULL || args->size() != 2)
+ return Type::make_error_type();
+ Type* t = args->front()->type();
+ if (t->is_abstract())
+ {
+ t = args->back()->type();
+ if (t->is_abstract())
+ t = t->make_non_abstract_type();
+ }
+ t = Builtin_call_expression::cmplx_type(t);
+ if (t == NULL)
+ t = Type::make_error_type();
+ return t;
+ }
}
}
// Determine the type.
void
-Builtin_call_expression::do_determine_type(const Type_context*)
+Builtin_call_expression::do_determine_type(const Type_context* context)
{
this->fn()->determine_type_no_context();
bool is_print;
+ Type* arg_type = NULL;
switch (this->code_)
{
case BUILTIN_PANIC:
@@ -5485,6 +6889,17 @@
is_print = true;
break;
+ case BUILTIN_REAL:
+ case BUILTIN_IMAG:
+ arg_type = Builtin_call_expression::cmplx_type(context->type);
+ is_print = false;
+ break;
+
+ case BUILTIN_CMPLX:
+ arg_type = Builtin_call_expression::real_imag_type(context->type);
+ is_print = false;
+ break;
+
default:
is_print = false;
break;
@@ -5498,6 +6913,7 @@
++pa)
{
Type_context subcontext;
+ subcontext.type = arg_type;
if (is_print)
{
@@ -5505,7 +6921,7 @@
// use the appropriate nonabstract type. Use uint64 for
// an integer if we know it is nonnegative, otherwise
// use int64 for a integer, otherwise use float64 for a
- // float.
+ // float or complex128 for a complex.
Type* want_type = NULL;
Type* atype = (*pa)->type();
if (atype->is_abstract())
@@ -5522,11 +6938,12 @@
want_type = Type::lookup_integer_type("int64");
mpz_clear(val);
}
+ else if (atype->float_type() != NULL)
+ want_type = Type::lookup_float_type("float64");
+ else if (atype->complex_type() != NULL)
+ want_type = Type::lookup_complex_type("complex128");
else
- {
- gcc_assert(atype->float_type() != NULL);
- want_type = Type::lookup_float_type("float64");
- }
+ gcc_unreachable();
subcontext.type = want_type;
}
}
@@ -5634,6 +7051,7 @@
|| type->is_string_type()
|| type->integer_type() != NULL
|| type->float_type() != NULL
+ || type->complex_type() != NULL
|| type->is_boolean_type()
|| type->points_to() != NULL
|| type->interface_type() != NULL
@@ -5722,6 +7140,35 @@
}
break;
+ case BUILTIN_REAL:
+ case BUILTIN_IMAG:
+ if (this->check_one_arg())
+ {
+ if (this->one_arg()->type()->complex_type() == NULL)
+ this->report_error(_("argument must have complex type"));
+ }
+ break;
+
+ case BUILTIN_CMPLX:
+ {
+ const Expression_list* args = this->args();
+ if (args == NULL || args->size() < 2)
+ this->report_error(_("not enough arguments"));
+ else if (args->size() > 2)
+ this->report_error(_("too many arguments"));
+ else if (args->front()->is_error_expression()
+ || args->front()->type()->is_error_type()
+ || args->back()->is_error_expression()
+ || args->back()->type()->is_error_type())
+ this->set_is_error();
+ else if (!Type::are_identical(args->front()->type(),
+ args->back()->type()))
+ this->report_error(_("arguments must have identical types"));
+ else if (args->front()->type()->float_type() == NULL)
+ this->report_error(_("arguments must have floating-point type"));
+ }
+ break;
+
default:
gcc_unreachable();
}
@@ -5892,6 +7339,14 @@
fnname = "__go_print_double";
arg = fold_convert_loc(location, double_type_node, arg);
}
+ else if (type->complex_type() != NULL)
+ {
+ static tree print_complex_fndecl;
+ pfndecl = &print_complex_fndecl;
+ fnname = "__go_print_complex";
+ arg = fold_convert_loc(location, complex_double_type_node,
+ arg);
+ }
else if (type->is_boolean_type())
{
static tree print_bool_fndecl;
@@ -6086,6 +7541,42 @@
call, len);
}
+ case BUILTIN_REAL:
+ case BUILTIN_IMAG:
+ {
+ const Expression_list* args = this->args();
+ gcc_assert(args != NULL && args->size() == 1);
+ Expression* arg = args->front();
+ tree arg_tree = arg->get_tree(context);
+ if (arg_tree == error_mark_node)
+ return error_mark_node;
+ gcc_assert(COMPLEX_FLOAT_TYPE_P(TREE_TYPE(arg_tree)));
+ if (this->code_ == BUILTIN_REAL)
+ return fold_build1_loc(location, REALPART_EXPR,
+ TREE_TYPE(TREE_TYPE(arg_tree)),
+ arg_tree);
+ else
+ return fold_build1_loc(location, IMAGPART_EXPR,
+ TREE_TYPE(TREE_TYPE(arg_tree)),
+ arg_tree);
+ }
+
+ case BUILTIN_CMPLX:
+ {
+ const Expression_list* args = this->args();
+ gcc_assert(args != NULL && args->size() == 2);
+ tree r = args->front()->get_tree(context);
+ tree i = args->back()->get_tree(context);
+ if (r == error_mark_node || i == error_mark_node)
+ return error_mark_node;
+ gcc_assert(TYPE_MAIN_VARIANT(TREE_TYPE(r))
+ == TYPE_MAIN_VARIANT(TREE_TYPE(i)));
+ gcc_assert(SCALAR_FLOAT_TYPE_P(TREE_TYPE(r)));
+ return fold_build2_loc(location, COMPLEX_EXPR,
+ build_complex_type(TREE_TYPE(r)),
+ r, i);
+ }
+
default:
gcc_unreachable();
}
@@ -6097,18 +7588,53 @@
void
Builtin_call_expression::do_export(Export* exp) const
{
+ bool ok = false;
+
mpz_t val;
mpz_init(val);
Type* dummy;
- bool b = this->integer_constant_value(true, val, &dummy);
- if (!b)
- error_at(this->location(), "value is not constant");
- char* s = mpz_get_str(NULL, 10, val);
- exp->write_c_string(s);
- free(s);
+ if (this->integer_constant_value(true, val, &dummy))
+ {
+ Integer_expression::export_integer(exp, val);
+ ok = true;
+ }
+ mpz_clear(val);
+
+ if (!ok)
+ {
+ mpfr_t fval;
+ mpfr_init(fval);
+ if (this->float_constant_value(fval, &dummy))
+ {
+ Float_expression::export_float(exp, fval);
+ ok = true;
+ }
+ mpfr_clear(fval);
+ }
+
+ if (!ok)
+ {
+ mpfr_t real;
+ mpfr_t imag;
+ mpfr_init(real);
+ mpfr_init(imag);
+ if (this->complex_constant_value(real, imag, &dummy))
+ {
+ Complex_expression::export_complex(exp, real, imag);
+ ok = true;
+ }
+ mpfr_clear(real);
+ mpfr_clear(imag);
+ }
+
+ if (!ok)
+ {
+ error_at(this->location(), "value is not constant");
+ return;
+ }
+
// A trailing space lets us reliably identify the end of the number.
exp->write_c_string(" ");
- mpz_clear(val);
}
// Class Call_expression.
@@ -6813,8 +8339,10 @@
&& DECL_IS_BUILTIN(fndecl)
&& DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_NORMAL
&& nargs > 0
- && SCALAR_FLOAT_TYPE_P(rettype)
- && SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[0])))
+ && ((SCALAR_FLOAT_TYPE_P(rettype)
+ && SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[0])))
+ || (COMPLEX_FLOAT_TYPE_P(rettype)
+ && COMPLEX_FLOAT_TYPE_P(TREE_TYPE(args[0])))))
{
excess_type = excess_precision_type(TREE_TYPE(args[0]));
if (excess_type != NULL_TREE)
@@ -6827,10 +8355,7 @@
{
fn = build_fold_addr_expr_loc(location, excess_fndecl);
for (int i = 0; i < nargs; ++i)
- {
- if (SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[i])))
- args[i] = convert_to_real(excess_type, args[i]);
- }
+ args[i] = ::convert(excess_type, args[i]);
}
}
}
@@ -6850,8 +8375,8 @@
if (excess_type != NULL_TREE)
{
- // Calling convert_to_real here can undo our excess precision
- // change. That may or may not be a bug in convert_to_real.
+ // Calling convert here can undo our excess precision change.
+ // That may or may not be a bug in convert_to_real.
ret = build1(NOP_EXPR, rettype, ret);
}
@@ -10892,7 +12417,7 @@
return String_expression::do_import(imp);
else if (c == '-' || (c >= '0' && c <= '9'))
{
- // This handles both integers and floats.
+ // This handles integers, floats and complex constants.
return Integer_expression::do_import(imp);
}
else if (imp->match_c_string("nil"))
diff -r 56cbaf257cf7 go/expressions.h
--- a/go/expressions.h Thu Mar 04 17:00:54 2010 -0800
+++ b/go/expressions.h Wed Mar 10 14:43:36 2010 -0800
@@ -66,6 +66,7 @@
EXPRESSION_STRING,
EXPRESSION_INTEGER,
EXPRESSION_FLOAT,
+ EXPRESSION_COMPLEX,
EXPRESSION_NIL,
EXPRESSION_IOTA,
EXPRESSION_CALL,
@@ -162,6 +163,11 @@
static Expression*
make_float(const mpfr_t*, Type*, source_location);
+ // 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*, source_location);
+
// Make a nil expression.
static Expression*
make_nil(source_location);
@@ -314,6 +320,14 @@
bool
float_constant_value(mpfr_t val, Type** ptype) const;
+ // If this is not a constant expression with complex type, return
+ // false. If it is one, return true, and set REAL and IMAG to the
+ // value. REAL and IMAG should already be initialized. If this
+ // return strue, it sets *PTYPE to the type of the value, or NULL
+ // for an abstract type.
+ bool
+ complex_constant_value(mpfr_t real, mpfr_t imag, Type** ptype) const;
+
// If this is not a constant expression with string type, return
// false. If it is one, return true, and set VAL to the value.
bool
@@ -507,8 +521,9 @@
lower(Gogo* gogo, Named_object* function, int iota_value)
{ return this->do_lower(gogo, function, iota_value); }
- // Determine the real type of an expression with abstract integer or
- // floating point type. TYPE_CONTEXT describes the expected type.
+ // Determine the real type of an expression with abstract integer,
+ // floating point, or complex type. TYPE_CONTEXT describes the
+ // expected type.
void
determine_type(const Type_context*);
@@ -613,6 +628,10 @@
static tree
float_constant_tree(mpfr_t val, tree type);
+ // Return a tree for the complex value REAL/IMAG in TYPE.
+ static tree
+ complex_constant_tree(mpfr_t real, mpfr_t imag, tree type);
+
// Export the expression. This is only used for constants. It will
// be used for things like values of named constants and sizes of
// arrays.
@@ -651,6 +670,12 @@
do_float_constant_value(mpfr_t, Type**) const
{ return false; }
+ // Return whether this is a constant expression of complex type, and
+ // set REAL and IMAGE to the value.
+ virtual bool
+ do_complex_constant_value(mpfr_t, mpfr_t, Type**) const
+ { return false; }
+
// Return whether this is a constant expression of string type, and
// set VAL to the value.
virtual bool
@@ -1077,6 +1102,14 @@
Type* right_type, mpfr_t right_val, mpfr_t val,
source_location);
+ // Apply binary opcode OP to LEFT_REAL/LEFT_IMAG and
+ // RIGHT_REAL/RIGHT_IMAG, setting REAL/IMAG. Return true if this
+ // could be done, false if not.
+ static bool
+ eval_complex(Operator op, Type* left_type, mpfr_t left_real,
+ mpfr_t left_imag, Type* right_type, mpfr_t right_real,
+ mpfr_t right_imag, mpfr_t real, mpfr_t imag, source_location);
+
// Compare integer constants according to OP.
static bool
compare_integer(Operator op, mpz_t left_val, mpz_t right_val);
@@ -1085,6 +1118,11 @@
static bool
compare_float(Operator op, Type* type, mpfr_t left_val, mpfr_t right_val);
+ // Compare complex constants according to OP.
+ static bool
+ compare_complex(Operator op, Type* type, mpfr_t left_real, mpfr_t left_imag,
+ mpfr_t right_val, mpfr_t right_imag);
+
static Expression*
do_import(Import*);
@@ -1110,6 +1148,9 @@
bool
do_float_constant_value(mpfr_t val, Type**) const;
+ bool
+ do_complex_constant_value(mpfr_t real, mpfr_t imag, Type**) const;
+
void
do_discarding_value();
diff -r 56cbaf257cf7 go/go-lang.c
--- a/go/go-lang.c Thu Mar 04 17:00:54 2010 -0800
+++ b/go/go-lang.c Wed Mar 10 14:43:36 2010 -0800
@@ -114,6 +114,10 @@
requirements. */
flag_strict_aliasing = 1;
+ /* Default to avoiding range issues for complex multiply and
+ divide. */
+ flag_complex_method = 2;
+
/* The builtin math functions should not set errno. */
flag_errno_math = 0;
@@ -285,6 +289,8 @@
return fold (convert_to_pointer (type, expr));
case REAL_TYPE:
return fold (convert_to_real (type, expr));
+ case COMPLEX_TYPE:
+ return fold (convert_to_complex (type, expr));
default:
break;
}
diff -r 56cbaf257cf7 go/gogo-tree.cc
--- a/go/gogo-tree.cc Thu Mar 04 17:00:54 2010 -0800
+++ b/go/gogo-tree.cc Wed Mar 10 14:43:36 2010 -0800
@@ -1686,10 +1686,34 @@
type = Type::lookup_float_type("float64");
break;
default:
+ // We have to check for long double in order to support
+ // i386 excess precision.
+ if (mode == TYPE_MODE(long_double_type_node))
+ return long_double_type_node;
return NULL_TREE;
}
return type->float_type()->type_tree();
}
+ else if (mc == MODE_COMPLEX_FLOAT)
+ {
+ Type *type;
+ switch (GET_MODE_BITSIZE (mode))
+ {
+ case 64:
+ type = Type::lookup_complex_type("complex64");
+ break;
+ case 128:
+ type = Type::lookup_complex_type("complex128");
+ break;
+ default:
+ // We have to check for long double in order to support
+ // i386 excess precision.
+ if (mode == TYPE_MODE(complex_long_double_type_node))
+ return complex_long_double_type_node;
+ return NULL_TREE;
+ }
+ return type->complex_type()->type_tree();
+ }
else
return NULL_TREE;
}
@@ -2111,6 +2135,7 @@
case Type::TYPE_BOOLEAN:
case Type::TYPE_INTEGER:
case Type::TYPE_FLOAT:
+ case Type::TYPE_COMPLEX:
case Type::TYPE_POINTER:
case Type::TYPE_FUNCTION:
case Type::TYPE_CHANNEL:
@@ -3778,7 +3803,8 @@
source_location location)
{
if (int_size_in_bytes(TREE_TYPE(val)) <= 8
- && !AGGREGATE_TYPE_P(TREE_TYPE(val)))
+ && !AGGREGATE_TYPE_P(TREE_TYPE(val))
+ && !FLOAT_TYPE_P(TREE_TYPE(val)))
{
val = convert_to_integer(uint64_type_node, val);
if (blocking)
@@ -3889,7 +3915,8 @@
source_location location)
{
if (int_size_in_bytes(type_tree) <= 8
- && !AGGREGATE_TYPE_P(type_tree))
+ && !AGGREGATE_TYPE_P(type_tree)
+ && !FLOAT_TYPE_P(type_tree))
{
static tree receive_small_fndecl;
tree call = Gogo::call_builtin(&receive_small_fndecl,
diff -r 56cbaf257cf7 go/gogo.cc
--- a/go/gogo.cc Thu Mar 04 17:00:54 2010 -0800
+++ b/go/gogo.cc Wed Mar 10 14:43:36 2010 -0800
@@ -63,6 +63,11 @@
this->add_named_type(Type::make_float_type("float64", 64,
RUNTIME_TYPE_CODE_FLOAT64));
+ this->add_named_type(Type::make_complex_type("complex64", 64,
+ RUNTIME_TYPE_CODE_COMPLEX64));
+ this->add_named_type(Type::make_complex_type("complex128", 128,
+ RUNTIME_TYPE_CODE_COMPLEX128));
+
const int int_type_size = std::max(INT_TYPE_SIZE, 32);
this->add_named_type(Type::make_integer_type("uint", true,
int_type_size,
@@ -85,6 +90,9 @@
this->add_named_type(Type::make_float_type("float", FLOAT_TYPE_SIZE,
RUNTIME_TYPE_CODE_FLOAT));
+ this->add_named_type(Type::make_complex_type("complex", FLOAT_TYPE_SIZE * 2,
+ RUNTIME_TYPE_CODE_COMPLEX));
+
this->add_named_type(Type::make_named_bool_type());
this->add_named_type(Type::make_named_string_type());
@@ -181,6 +189,21 @@
copy_type->set_is_builtin();
this->globals_->add_function_declaration("copy", NULL, copy_type, loc);
+ Function_type* cmplx_type = Type::make_function_type(NULL, NULL, NULL, loc);
+ cmplx_type->set_is_varargs();
+ cmplx_type->set_is_builtin();
+ this->globals_->add_function_declaration("cmplx", NULL, cmplx_type, loc);
+
+ Function_type* real_type = Type::make_function_type(NULL, NULL, NULL, loc);
+ real_type->set_is_varargs();
+ real_type->set_is_builtin();
+ this->globals_->add_function_declaration("real", NULL, real_type, loc);
+
+ Function_type* imag_type = Type::make_function_type(NULL, NULL, NULL, loc);
+ imag_type->set_is_varargs();
+ imag_type->set_is_builtin();
+ this->globals_->add_function_declaration("imag", NULL, cmplx_type, loc);
+
this->define_builtin_function_trees();
// Declare "init", to ensure that it is not defined with parameters
@@ -1401,6 +1424,7 @@
Type* ctype = constant->type();
if (ctype->integer_type() == NULL
&& ctype->float_type() == NULL
+ && ctype->complex_type() == NULL
&& !ctype->is_boolean_type()
&& !ctype->is_string_type())
{
diff -r 56cbaf257cf7 go/import.cc
--- a/go/import.cc Thu Mar 04 17:00:54 2010 -0800
+++ b/go/import.cc Wed Mar 10 14:43:36 2010 -0800
@@ -632,10 +632,13 @@
this->register_builtin_type(gogo, "uint64", BUILTIN_UINT64);
this->register_builtin_type(gogo, "float32", BUILTIN_FLOAT32);
this->register_builtin_type(gogo, "float64", BUILTIN_FLOAT64);
+ this->register_builtin_type(gogo, "complex64", BUILTIN_COMPLEX64);
+ this->register_builtin_type(gogo, "complex128", BUILTIN_COMPLEX128);
this->register_builtin_type(gogo, "int", BUILTIN_INT);
this->register_builtin_type(gogo, "uint", BUILTIN_UINT);
this->register_builtin_type(gogo, "uintptr", BUILTIN_UINTPTR);
this->register_builtin_type(gogo, "float", BUILTIN_FLOAT);
+ this->register_builtin_type(gogo, "complex", BUILTIN_COMPLEX);
this->register_builtin_type(gogo, "bool", BUILTIN_BOOL);
this->register_builtin_type(gogo, "string", BUILTIN_STRING);
}
diff -r 56cbaf257cf7 go/lex.cc
--- a/go/lex.cc Thu Mar 04 17:00:54 2010 -0800
+++ b/go/lex.cc Wed Mar 10 14:43:36 2010 -0800
@@ -169,7 +169,8 @@
{
if (this->classification_ == TOKEN_INTEGER)
mpz_clear(this->u_.integer_value);
- else if (this->classification_ == TOKEN_FLOAT)
+ else if (this->classification_ == TOKEN_FLOAT
+ || this->classification_ == TOKEN_IMAGINARY)
mpfr_clear(this->u_.float_value);
}
@@ -197,6 +198,7 @@
mpz_init_set(this->u_.integer_value, tok.u_.integer_value);
break;
case TOKEN_FLOAT:
+ case TOKEN_IMAGINARY:
mpfr_init_set(this->u_.float_value, tok.u_.float_value, GMP_RNDN);
break;
default:
@@ -235,6 +237,7 @@
mpz_init_set(this->u_.integer_value, tok.u_.integer_value);
break;
case TOKEN_FLOAT:
+ case TOKEN_IMAGINARY:
mpfr_init_set(this->u_.float_value, tok.u_.float_value, GMP_RNDN);
break;
default:
@@ -273,6 +276,10 @@
fprintf(file, "float ");
mpfr_out_str(file, 10, 0, this->u_.float_value, GMP_RNDN);
break;
+ case TOKEN_IMAGINARY:
+ fprintf(file, "imaginary ");
+ mpfr_out_str(file, 10, 0, this->u_.float_value, GMP_RNDN);
+ break;
case TOKEN_OPERATOR:
fprintf(file, "operator ");
switch (this->u_.op)
@@ -948,7 +955,7 @@
}
}
- if (*p != '.' && *p != 'e' && *p != 'E')
+ if (*p != '.' && *p != 'e' && *p != 'E' && *p != 'i')
{
std::string s(pnum, p - pnum);
mpz_t val;
@@ -972,7 +979,7 @@
++p;
}
- if (*p != '.' && *p != 'E' && *p != 'e')
+ if (*p != '.' && *p != 'E' && *p != 'e' && *p != 'i')
{
std::string s(pnum, p - pnum);
mpz_t val;
@@ -988,34 +995,37 @@
return ret;
}
- bool dot = *p == '.';
+ if (*p != 'i')
+ {
+ bool dot = *p == '.';
- ++p;
+ ++p;
- if (!dot)
- {
- if (*p == '+' || *p == '-')
- ++p;
- }
+ if (!dot)
+ {
+ if (*p == '+' || *p == '-')
+ ++p;
+ }
- while (p < pend)
- {
- if (*p < '0' || *p > '9')
- break;
- ++p;
- }
-
- if (dot && (*p == 'E' || *p == 'e'))
- {
- ++p;
- if (*p == '+' || *p == '-')
- ++p;
while (p < pend)
{
if (*p < '0' || *p > '9')
break;
++p;
}
+
+ if (dot && (*p == 'E' || *p == 'e'))
+ {
+ ++p;
+ if (*p == '+' || *p == '-')
+ ++p;
+ while (p < pend)
+ {
+ if (*p < '0' || *p > '9')
+ break;
+ ++p;
+ }
+ }
}
std::string s(pnum, p - pnum);
@@ -1026,10 +1036,23 @@
if (neg)
mpfr_neg(val, val, GMP_RNDN);
+ bool is_imaginary = *p == 'i';
+ if (is_imaginary)
+ ++p;
+
this->lineoff_ = p - this->linebuf_;
- Token ret = Token::make_float_token(val, location);
- mpfr_clear(val);
- return ret;
+ if (is_imaginary)
+ {
+ Token ret = Token::make_imaginary_token(val, location);
+ mpfr_clear(val);
+ return ret;
+ }
+ else
+ {
+ Token ret = Token::make_float_token(val, location);
+ mpfr_clear(val);
+ return ret;
+ }
}
// Advance one character, possibly escaped. Return the pointer beyond
diff -r 56cbaf257cf7 go/lex.h
--- a/go/lex.h Thu Mar 04 17:00:54 2010 -0800
+++ b/go/lex.h Wed Mar 10 14:43:36 2010 -0800
@@ -72,7 +72,9 @@
// Token is an integer.
TOKEN_INTEGER,
// Token is a floating point number.
- TOKEN_FLOAT
+ TOKEN_FLOAT,
+ // Token is an imaginary number.
+ TOKEN_IMAGINARY
};
~Token();
@@ -152,6 +154,16 @@
return tok;
}
+ // Make a token for an imaginary number.
+ static Token
+ make_imaginary_token(mpfr_t val, source_location location)
+ {
+ Token tok(TOKEN_IMAGINARY, location);
+ mpfr_init(tok.u_.float_value);
+ mpfr_swap(tok.u_.float_value, val);
+ return tok;
+ }
+
// Get the location of the token.
source_location
location() const
@@ -228,6 +240,14 @@
return &this->u_.float_value;
}
+ // Return the value of an imaginary number.
+ const mpfr_t*
+ imaginary_value() const
+ {
+ gcc_assert(this->classification_ == TOKEN_IMAGINARY);
+ return &this->u_.float_value;
+ }
+
// Return the operator value for an operator token.
Operator
op() const
@@ -281,7 +301,7 @@
std::string* string_value;
// The token value for TOKEN_INTEGER.
mpz_t integer_value;
- // The token value for TOKEN_FLOAT.
+ // The token value for TOKEN_FLOAT or TOKEN_IMAGINARY.
mpfr_t float_value;
// The token value for TOKEN_OPERATOR or the keyword value
Operator op;
diff -r 56cbaf257cf7 go/parse.cc
--- a/go/parse.cc Thu Mar 04 17:00:54 2010 -0800
+++ b/go/parse.cc Wed Mar 10 14:43:36 2010 -0800
@@ -2035,9 +2035,9 @@
return new Typed_identifier(name, type, location);
}
-// Operand = Literal | QualifiedIdent | "(" Expression ")" .
-// Literal = int_lit | float_lit | char_lit | string_lit |
-// CompositeLit | FunctionLit .
+// Operand = Literal | QualifiedIdent | MethodExpr | "(" Expression ")" .
+// Literal = BasicLit | CompositeLit | FunctionLit .
+// BasicLit = int_lit | float_lit | imaginary_lit | char_lit | string_lit .
// If MAY_BE_SINK is true, this operand may be "_".
@@ -2171,6 +2171,17 @@
this->advance_token();
return ret;
+ case Token::TOKEN_IMAGINARY:
+ {
+ mpfr_t zero;
+ mpfr_init_set_ui(zero, 0, GMP_RNDN);
+ ret = Expression::make_complex(&zero, token->imaginary_value(),
+ NULL, token->location());
+ mpfr_clear(zero);
+ this->advance_token();
+ return ret;
+ }
+
case Token::TOKEN_KEYWORD:
switch (token->keyword())
{
@@ -2809,6 +2820,7 @@
}
case Token::TOKEN_INTEGER:
case Token::TOKEN_FLOAT:
+ case Token::TOKEN_IMAGINARY:
return true;
default:
gcc_unreachable();
@@ -2971,6 +2983,7 @@
case Token::TOKEN_STRING:
case Token::TOKEN_INTEGER:
case Token::TOKEN_FLOAT:
+ case Token::TOKEN_IMAGINARY:
this->simple_stat(true, false, NULL, NULL);
break;
@@ -3029,6 +3042,7 @@
case Token::TOKEN_STRING:
case Token::TOKEN_INTEGER:
case Token::TOKEN_FLOAT:
+ case Token::TOKEN_IMAGINARY:
return true;
default:
diff -r 56cbaf257cf7 go/types.cc
--- a/go/types.cc Thu Mar 04 17:00:54 2010 -0800
+++ b/go/types.cc Wed Mar 10 14:43:36 2010 -0800
@@ -134,6 +134,7 @@
{
case TYPE_INTEGER:
case TYPE_FLOAT:
+ case TYPE_COMPLEX:
case TYPE_BOOLEAN:
case TYPE_STRING:
case TYPE_NIL:
@@ -164,13 +165,17 @@
bool
Type::is_abstract() const
{
- const Integer_type* it = this->integer_type();
- if (it != NULL)
- return it->is_abstract();
- const Float_type* ft = this->float_type();
- if (ft != NULL)
- return ft->is_abstract();
- return false;
+ switch (this->classification())
+ {
+ case TYPE_INTEGER:
+ return this->integer_type()->is_abstract();
+ case TYPE_FLOAT:
+ return this->float_type()->is_abstract();
+ case TYPE_COMPLEX:
+ return this->complex_type()->is_abstract();
+ default:
+ return false;
+ }
}
// Return a non-abstract version of an abstract type.
@@ -179,12 +184,17 @@
Type::make_non_abstract_type()
{
gcc_assert(this->is_abstract());
- if (this->integer_type() != NULL)
- return Type::lookup_integer_type("int");
- else if (this->float_type() != NULL)
- return Type::lookup_float_type("float");
- else
- gcc_unreachable();
+ switch (this->classification())
+ {
+ case TYPE_INTEGER:
+ return Type::lookup_integer_type("int");
+ case TYPE_FLOAT:
+ return Type::lookup_float_type("float");
+ case TYPE_COMPLEX:
+ return Type::lookup_complex_type("complex");
+ default:
+ gcc_unreachable();
+ }
}
// Add entries to the reference count queue for this type. This is
@@ -360,6 +370,9 @@
case TYPE_FLOAT:
return t1base->float_type()->is_compatible(t2base->float_type());
+ case TYPE_COMPLEX:
+ return t1base->complex_type()->is_compatible(t2base->complex_type());
+
case TYPE_FUNCTION:
return t1base->function_type()->is_compatible(t2base->function_type(),
compatible,
@@ -406,12 +419,16 @@
lhs = lhs->base();
rhs = rhs->base();
- // A constant of abstract integer or float type may be mixed with an
- // integer or float type.
+ // A constant of abstract integer, float, or complex type may be
+ // mixed with an integer, float, or complex type.
if ((rhs->is_abstract()
- && (lhs->integer_type() != NULL || lhs->float_type() != NULL))
+ && (lhs->integer_type() != NULL
+ || lhs->float_type() != NULL
+ || lhs->complex_type() != NULL))
|| (lhs->is_abstract()
- && (rhs->integer_type() != NULL || rhs->float_type() != NULL)))
+ && (rhs->integer_type() != NULL
+ || rhs->float_type() != NULL
+ || rhs->complex_type() != NULL)))
return true;
// The nil type may be compared to a pointer, an interface type, a
@@ -526,9 +543,11 @@
return true;
// A constant of abstract integer or float type may be assigned to
- // integer or float type.
+ // integer, float, or complex type.
if (rhs->is_abstract()
- && (lhs->integer_type() != NULL || lhs->float_type() != NULL))
+ && (lhs->integer_type() != NULL
+ || lhs->float_type() != NULL
+ || lhs->complex_type() != NULL))
return true;
// The nil type may be assigned to a pointer type, an interface
@@ -1253,6 +1272,169 @@
return Float_type::lookup_float_type(name);
}
+// Class Complex_type.
+
+Complex_type::Named_complex_types Complex_type::named_complex_types;
+
+// Create a new complex type. Non-abstract complex types always have
+// names.
+
+Named_type*
+Complex_type::create_complex_type(const char* name, int bits,
+ int runtime_type_code)
+{
+ Complex_type* complex_type = new Complex_type(false, bits,
+ runtime_type_code);
+ std::string sname(name);
+ Named_object* named_object = Named_object::make_type(sname, NULL,
+ complex_type,
+ BUILTINS_LOCATION);
+ Named_type* named_type = named_object->type_value();
+ std::pair<Named_complex_types::iterator, bool> ins =
+ Complex_type::named_complex_types.insert(std::make_pair(sname,
+ named_type));
+ gcc_assert(ins.second);
+ return named_type;
+}
+
+// Look up an existing complex type.
+
+Named_type*
+Complex_type::lookup_complex_type(const char* name)
+{
+ Named_complex_types::const_iterator p =
+ Complex_type::named_complex_types.find(name);
+ gcc_assert(p != Complex_type::named_complex_types.end());
+ return p->second;
+}
+
+// Create a new abstract complex type.
+
+Complex_type*
+Complex_type::create_abstract_complex_type()
+{
+ static Complex_type* abstract_type;
+ if (abstract_type == NULL)
+ abstract_type = new Complex_type(true, FLOAT_TYPE_SIZE * 2,
+ RUNTIME_TYPE_CODE_FLOAT);
+ return abstract_type;
+}
+
+// Whether this type is compatible with T.
+
+bool
+Complex_type::is_compatible(const Complex_type *t) const
+{
+ if (this->bits_ != t->bits_)
+ return false;
+ return this->is_abstract_ == t->is_abstract_;
+}
+
+// Hash code.
+
+unsigned int
+Complex_type::do_hash_for_method(Gogo*) const
+{
+ return (this->bits_ << 4) + ((this->is_abstract_ ? 1 : 0) << 8);
+}
+
+// Get a tree without using a Gogo*.
+
+tree
+Complex_type::type_tree() const
+{
+ if (this->bits_ == FLOAT_TYPE_SIZE * 2)
+ return complex_float_type_node;
+ else if (this->bits_ == DOUBLE_TYPE_SIZE * 2)
+ return complex_double_type_node;
+ else if (this->bits_ == LONG_DOUBLE_TYPE_SIZE * 2)
+ return complex_long_double_type_node;
+ else
+ {
+ tree ret = make_node(REAL_TYPE);
+ TYPE_PRECISION(ret) = this->bits_ / 2;
+ layout_type(ret);
+ return build_complex_type(ret);
+ }
+}
+
+// Get a tree.
+
+tree
+Complex_type::do_get_tree(Gogo*)
+{
+ return this->type_tree();
+}
+
+// Zero initializer.
+
+tree
+Complex_type::do_init_tree(Gogo* gogo, bool is_clear)
+{
+ if (is_clear)
+ return NULL;
+ tree type = this->get_tree(gogo);
+ REAL_VALUE_TYPE r;
+ real_from_integer(&r, TYPE_MODE(TREE_TYPE(type)), 0, 0, 0);
+ return build_complex(type, build_real(TREE_TYPE(type), r),
+ build_real(TREE_TYPE(type), r));
+}
+
+// The type descriptor for a complex type. Complex types are always
+// named.
+
+void
+Complex_type::do_type_descriptor_decl(Gogo* gogo, Named_type* name,
+ tree* pdecl)
+{
+ gcc_assert(name != NULL);
+ gogo->type_descriptor_decl(this->runtime_type_code_, this, name, pdecl);
+}
+
+// We should not be asked for the reflection string of a basic type.
+
+void
+Complex_type::do_reflection(Gogo*, std::string*) const
+{
+ gcc_unreachable();
+}
+
+// Mangled name.
+
+void
+Complex_type::do_mangled_name(Gogo*, std::string* ret) const
+{
+ char buf[100];
+ snprintf(buf, sizeof buf, "c%s%de",
+ this->is_abstract_ ? "a" : "",
+ this->bits_);
+ ret->append(buf);
+}
+
+// Make a complex type.
+
+Named_type*
+Type::make_complex_type(const char* name, int bits, int runtime_type_code)
+{
+ return Complex_type::create_complex_type(name, bits, runtime_type_code);
+}
+
+// Make an abstract complex type.
+
+Complex_type*
+Type::make_abstract_complex_type()
+{
+ return Complex_type::create_abstract_complex_type();
+}
+
+// Look up a complex type.
+
+Named_type*
+Type::lookup_complex_type(const char* name)
+{
+ return Complex_type::lookup_complex_type(name);
+}
+
// Class String_type.
// Return the tree for String_type. We represent strings as a pointer
diff -r 56cbaf257cf7 go/types.h
--- a/go/types.h Thu Mar 04 17:00:54 2010 -0800
+++ b/go/types.h Wed Mar 10 14:43:36 2010 -0800
@@ -17,6 +17,7 @@
class Typed_identifier_list;
class Integer_type;
class Float_type;
+class Complex_type;
class String_type;
class Function_type;
class Struct_field;
@@ -75,6 +76,9 @@
static const int RUNTIME_TYPE_CODE_MAP = 22;
static const int RUNTIME_TYPE_CODE_PTR = 23;
static const int RUNTIME_TYPE_CODE_STRUCT = 24;
+static const int RUNTIME_TYPE_CODE_COMPLEX64 = 25;
+static const int RUNTIME_TYPE_CODE_COMPLEX128 = 26;
+static const int RUNTIME_TYPE_CODE_COMPLEX = 27;
// To build the complete list of methods for a named type we need to
// gather all methods from anonymous fields. Those methods may
@@ -345,6 +349,7 @@
TYPE_BOOLEAN,
TYPE_INTEGER,
TYPE_FLOAT,
+ TYPE_COMPLEX,
TYPE_STRING,
TYPE_SINK,
TYPE_FUNCTION,
@@ -411,6 +416,20 @@
static Named_type*
lookup_float_type(const char* name);
+ // Make an abstract complex type.
+ static Complex_type*
+ make_abstract_complex_type();
+
+ // Make a named complex type with a specific size.
+ // RUNTIME_TYPE_CODE is the code to use in reflection information,
+ // to distinguish complex and complex64.
+ static Named_type*
+ make_complex_type(const char* name, int bits, int runtime_type_code);
+
+ // Look up a named complex type.
+ static Named_type*
+ lookup_complex_type(const char* name);
+
// Get the unnamed string type.
static Type*
make_string_type();
@@ -555,8 +574,8 @@
bool
is_basic_type() const;
- // Return true if this is an abstract type--an integer or floating
- // point type whose size has not been determined.
+ // Return true if this is an abstract type--an integer, floating
+ // point, or complex type whose size has not been determined.
bool
is_abstract() const;
@@ -615,6 +634,16 @@
float_type() const
{ return this->convert<const Float_type, TYPE_FLOAT>(); }
+ // If this is a complex type, return the Complex_type. Otherwise,
+ // return NULL.
+ Complex_type*
+ complex_type()
+ { return this->convert<Complex_type, TYPE_COMPLEX>(); }
+
+ const Complex_type*
+ complex_type() const
+ { return this->convert<const Complex_type, TYPE_COMPLEX>(); }
+
// Return true if this is a boolean type.
bool
is_boolean_type() const
@@ -1364,6 +1393,78 @@
int runtime_type_code_;
};
+// The type of a complex number.
+
+class Complex_type : public Type
+{
+ public:
+ // Create a new complex type.
+ static Named_type*
+ create_complex_type(const char* name, int bits, int runtime_type_code);
+
+ // Look up an existing complex type.
+ static Named_type*
+ lookup_complex_type(const char* name);
+
+ // Create an abstract complex type.
+ static Complex_type*
+ create_abstract_complex_type();
+
+ // Whether this is an abstract complex type.
+ bool
+ is_abstract() const
+ { return this->is_abstract_; }
+
+ // The number of bits: 64 or 128.
+ int bits() const
+ { return this->bits_; }
+
+ // Whether this type is the same as T.
+ bool
+ is_compatible(const Complex_type* t) const;
+
+ // Return a tree for this type without using a Gogo*.
+ tree
+ type_tree() const;
+
+ protected:
+ unsigned int
+ do_hash_for_method(Gogo*) const;
+
+ tree
+ do_get_tree(Gogo*);
+
+ tree
+ do_init_tree(Gogo*, bool);
+
+ void
+ do_type_descriptor_decl(Gogo*, Named_type*, tree*);
+
+ void
+ do_reflection(Gogo*, std::string*) const;
+
+ void
+ do_mangled_name(Gogo*, std::string*) const;
+
+ private:
+ Complex_type(bool is_abstract, int bits, int runtime_type_code)
+ : Type(TYPE_COMPLEX),
+ is_abstract_(is_abstract), bits_(bits),
+ runtime_type_code_(runtime_type_code)
+ { }
+
+ // Map names of complex types to the types themselves.
+ typedef std::map<std::string, Named_type*> Named_complex_types;
+ static Named_complex_types named_complex_types;
+
+ // True if this is an abstract type.
+ bool is_abstract_;
+ // The number of bits in the complex value--64 or 128.
+ int bits_;
+ // The runtime type code used in the type descriptor for this type.
+ int runtime_type_code_;
+};
+
// The type of a string.
class String_type : public Type
diff -r 56cbaf257cf7 libgo/go/fmt/format.go
--- a/libgo/go/fmt/format.go Thu Mar 04 17:00:54 2010 -0800
+++ b/libgo/go/fmt/format.go Wed Mar 10 14:43:36 2010 -0800
@@ -42,13 +42,14 @@
wid int
prec int
// flags
- widPresent bool
- precPresent bool
- minus bool
- plus bool
- sharp bool
- space bool
- zero bool
+ widPresent bool
+ precPresent bool
+ minus bool
+ plus bool
+ sharp bool
+ space bool
+ zero bool
+ preserveFlags bool // don't clear flags after this print; used to carry over in complex prints
}
func (f *fmt) clearflags() {
@@ -118,7 +119,9 @@
if right > 0 {
f.writePadding(right, padding)
}
- f.clearflags()
+ if !f.preserveFlags {
+ f.clearflags()
+ }
}
// append s to buf, padded on left (w > 0) or right (w < 0 or f.minus).
@@ -136,7 +139,9 @@
if right > 0 {
f.writePadding(right, padding)
}
- f.clearflags()
+ if !f.preserveFlags {
+ f.clearflags()
+ }
}
func putint(buf []byte, base, val uint64, digits string) int {
@@ -419,6 +424,64 @@
// fmt_fb32 formats a float32 in the form -123p3 (exponent is power of 2).
func (f *fmt) fmt_fb32(v float32) { f.padString(strconv.Ftoa32(v, 'b', 0)) }
+// fmt_c64 formats a complex64 according to its fmt_x argument.
+// TODO pass in a method rather than a byte when the compilers mature.
+func (f *fmt) fmt_c64(v complex64, fmt_x byte) {
+ f.buf.WriteByte('(')
+ r := real(v)
+ f.preserveFlags = true
+ for i := 0; ; i++ {
+ switch fmt_x {
+ case 'e':
+ f.fmt_e32(r)
+ case 'E':
+ f.fmt_E32(r)
+ case 'f':
+ f.fmt_f32(r)
+ case 'g':
+ f.fmt_g32(r)
+ case 'G':
+ f.fmt_G32(r)
+ }
+ f.preserveFlags = false
+ if i != 0 {
+ break
+ }
+ f.plus = true
+ r = imag(v)
+ }
+ f.buf.Write(irparenBytes)
+}
+
+// fmt_c128 formats a complex128 according to its fmt_x argument.
+// TODO pass in a method rather than a byte when the compilers mature.
+func (f *fmt) fmt_c128(v complex128, fmt_x byte) {
+ f.buf.WriteByte('(')
+ r := real(v)
+ f.preserveFlags = true
+ for i := 0; ; i++ {
+ switch fmt_x {
+ case 'e':
+ f.fmt_e64(r)
+ case 'E':
+ f.fmt_E64(r)
+ case 'f':
+ f.fmt_f64(r)
+ case 'g':
+ f.fmt_g64(r)
+ case 'G':
+ f.fmt_G64(r)
+ }
+ f.preserveFlags = false
+ if i != 0 {
+ break
+ }
+ f.plus = true
+ r = imag(v)
+ }
+ f.buf.Write(irparenBytes)
+}
+
// float
func (x *fmt) f(a float) {
if strconv.FloatSize == 32 {
diff -r 56cbaf257cf7 libgo/go/fmt/print.go
--- a/libgo/go/fmt/print.go Thu Mar 04 17:00:54 2010 -0800
+++ b/libgo/go/fmt/print.go Wed Mar 10 14:43:36 2010 -0800
@@ -24,7 +24,7 @@
%o base 8
%x base 16, with lower-case letters for a-f
%X base 16, with upper-case letters for A-F
- Floating-point:
+ Floating-point and complex constituents:
%e scientific notation, e.g. -1234.456e+78
%E scientific notation, e.g. -1234.456E+78
%f decimal point but no exponent, e.g. 123.456
@@ -87,15 +87,16 @@
// Some constants in the form of bytes, to avoid string overhead.
// Needlessly fastidious, I suppose.
var (
- trueBytes = []byte{'t', 'r', 'u', 'e'}
- falseBytes = []byte{'f', 'a', 'l', 's', 'e'}
- commaSpaceBytes = []byte{',', ' '}
- nilAngleBytes = []byte{'<', 'n', 'i', 'l', '>'}
- nilParenBytes = []byte{'(', 'n', 'i', 'l', ')'}
- nilBytes = []byte{'n', 'i', 'l'}
- mapBytes = []byte{'m', 'a', 'p', '['}
- missingBytes = []byte{'m', 'i', 's', 's', 'i', 'n', 'g'}
- extraBytes = []byte{'?', '(', 'e', 'x', 't', 'r', 'a', ' '}
+ trueBytes = []byte("true")
+ falseBytes = []byte("false")
+ commaSpaceBytes = []byte(", ")
+ nilAngleBytes = []byte("<nil>")
+ nilParenBytes = []byte("(nil)")
+ nilBytes = []byte("nil")
+ mapBytes = []byte("map[")
+ missingBytes = []byte("missing")
+ extraBytes = []byte("?(extra ")
+ irparenBytes = []byte("i)")
)
// State represents the printer state passed to custom formatters.
@@ -445,6 +446,52 @@
return
}
+var complexBits = reflect.Typeof(complex(0i)).Size() * 8
+
+func getComplex64(a interface{}) (val complex64, ok bool) {
+ // Is it a regular complex type?
+ switch c := a.(type) {
+ case complex64:
+ return c, true
+ case complex:
+ if complexBits == 64 {
+ return complex64(c), true
+ }
+ }
+ // Must be a renamed complex type.
+ switch c := reflect.NewValue(a).(type) {
+ case *reflect.Complex64Value:
+ return complex64(c.Get()), true
+ case *reflect.ComplexValue:
+ if complexBits == 64 {
+ return complex64(c.Get()), true
+ }
+ }
+ return
+}
+
+func getComplex128(a interface{}) (val complex128, ok bool) {
+ // Is it a regular complex type?
+ switch c := a.(type) {
+ case complex128:
+ return c, true
+ case complex:
+ if complexBits == 128 {
+ return complex128(c), true
+ }
+ }
+ // Must be a renamed complex type.
+ switch c := reflect.NewValue(a).(type) {
+ case *reflect.Complex128Value:
+ return complex128(c.Get()), true
+ case *reflect.ComplexValue:
+ if complexBits == 128 {
+ return complex128(c.Get()), true
+ }
+ }
+ return
+}
+
// Convert ASCII to integer. n is 0 (and got is false) if no number present.
func parsenum(s string, start, end int) (n int, got bool, newi int) {
@@ -509,6 +556,19 @@
p.fmt.fmt_g64(float64(f))
}
return false
+ case complex64:
+ p.fmt.fmt_c64(f, 'g')
+ return false
+ case complex128:
+ p.fmt.fmt_c128(f, 'g')
+ return false
+ case complex:
+ if complexBits == 64 {
+ p.fmt.fmt_c64(complex64(f), 'g')
+ } else {
+ p.fmt.fmt_c128(complex128(f), 'g')
+ }
+ return false
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr:
v, signed, ok := getInt(field)
if !ok {
@@ -855,12 +915,16 @@
goto badtype
}
- // float
+ // float/complex
case 'e':
if v, ok := getFloat32(field); ok {
p.fmt.fmt_e32(v)
} else if v, ok := getFloat64(field); ok {
p.fmt.fmt_e64(v)
+ } else if v, ok := getComplex64(field); ok {
+ p.fmt.fmt_c64(v, 'e')
+ } else if v, ok := getComplex128(field); ok {
+ p.fmt.fmt_c128(v, 'e')
} else {
goto badtype
}
@@ -869,6 +933,10 @@
p.fmt.fmt_E32(v)
} else if v, ok := getFloat64(field); ok {
p.fmt.fmt_E64(v)
+ } else if v, ok := getComplex64(field); ok {
+ p.fmt.fmt_c64(v, 'E')
+ } else if v, ok := getComplex128(field); ok {
+ p.fmt.fmt_c128(v, 'E')
} else {
goto badtype
}
@@ -877,6 +945,10 @@
p.fmt.fmt_f32(v)
} else if v, ok := getFloat64(field); ok {
p.fmt.fmt_f64(v)
+ } else if v, ok := getComplex64(field); ok {
+ p.fmt.fmt_c64(v, 'f')
+ } else if v, ok := getComplex128(field); ok {
+ p.fmt.fmt_c128(v, 'f')
} else {
goto badtype
}
@@ -885,6 +957,10 @@
p.fmt.fmt_g32(v)
} else if v, ok := getFloat64(field); ok {
p.fmt.fmt_g64(v)
+ } else if v, ok := getComplex64(field); ok {
+ p.fmt.fmt_c64(v, 'g')
+ } else if v, ok := getComplex128(field); ok {
+ p.fmt.fmt_c128(v, 'g')
} else {
goto badtype
}
@@ -893,6 +969,10 @@
p.fmt.fmt_G32(v)
} else if v, ok := getFloat64(field); ok {
p.fmt.fmt_G64(v)
+ } else if v, ok := getComplex64(field); ok {
+ p.fmt.fmt_c64(v, 'G')
+ } else if v, ok := getComplex128(field); ok {
+ p.fmt.fmt_c128(v, 'G')
} else {
goto badtype
}
diff -r 56cbaf257cf7 libgo/go/reflect/type.go
--- a/libgo/go/reflect/type.go Thu Mar 04 17:00:54 2010 -0800
+++ b/libgo/go/reflect/type.go Wed Mar 10 14:43:36 2010 -0800
@@ -80,6 +80,21 @@
commonType
}
+// Complex64Type represents a complex64 type.
+type Complex64Type struct {
+ commonType
+}
+
+// Complex128Type represents acomplex128 type.
+type Complex128Type struct {
+ commonType
+}
+
+// ComplexType represents a complex type.
+type ComplexType struct {
+ commonType
+}
+
// Int16Type represents an int16 type.
type Int16Type struct {
commonType
@@ -604,6 +619,12 @@
return (*Float32Type)(unsafe.Pointer(v))
case *runtime.Float64Type:
return (*Float64Type)(unsafe.Pointer(v))
+ case *runtime.ComplexType:
+ return (*ComplexType)(unsafe.Pointer(v))
+ case *runtime.Complex64Type:
+ return (*Complex64Type)(unsafe.Pointer(v))
+ case *runtime.Complex128Type:
+ return (*Complex128Type)(unsafe.Pointer(v))
case *runtime.IntType:
return (*IntType)(unsafe.Pointer(v))
case *runtime.Int8Type:
@@ -662,6 +683,12 @@
r = (*Float32Type)(unsafe.Pointer(v))
case runtime.Float64TypeCode:
r = (*Float64Type)(unsafe.Pointer(v))
+ case runtime.ComplexTypeCode:
+ r = (*ComplexType)(unsafe.Pointer(v))
+ case runtime.Complex64TypeCode:
+ r = (*Complex64Type)(unsafe.Pointer(v))
+ case runtime.Complex128TypeCode:
+ r = (*Complex128Type)(unsafe.Pointer(v))
case runtime.IntTypeCode:
r = (*IntType)(unsafe.Pointer(v))
case runtime.Int8TypeCode:
diff -r 56cbaf257cf7 libgo/go/reflect/value.go
--- a/libgo/go/reflect/value.go Thu Mar 04 17:00:54 2010 -0800
+++ b/libgo/go/reflect/value.go Wed Mar 10 14:43:36 2010 -0800
@@ -186,6 +186,63 @@
// Set sets v to the value x.
func (v *Float64Value) SetValue(x Value) { v.Set(x.(*Float64Value).Get()) }
+// ComplexValue represents a complex value.
+type ComplexValue struct {
+ value
+}
+
+// Get returns the underlying complex value.
+func (v *ComplexValue) Get() complex { return *(*complex)(v.addr) }
+
+// Set sets v to the value x.
+func (v *ComplexValue) Set(x complex) {
+ if !v.canSet {
+ panic(cannotSet)
+ }
+ *(*complex)(v.addr) = x
+}
+
+// Set sets v to the value x.
+func (v *ComplexValue) SetValue(x Value) { v.Set(x.(*ComplexValue).Get()) }
+
+// Complex64Value represents a complex64 value.
+type Complex64Value struct {
+ value
+}
+
+// Get returns the underlying complex64 value.
+func (v *Complex64Value) Get() complex64 { return *(*complex64)(v.addr) }
+
+// Set sets v to the value x.
+func (v *Complex64Value) Set(x complex64) {
+ if !v.canSet {
+ panic(cannotSet)
+ }
+ *(*complex64)(v.addr) = x
+}
+
+// Set sets v to the value x.
+func (v *Complex64Value) SetValue(x Value) { v.Set(x.(*Complex64Value).Get()) }
+
+// Complex128Value represents a complex128 value.
+type Complex128Value struct {
+ value
+}
+
+// Get returns the underlying complex128 value.
+func (v *Complex128Value) Get() complex128 { return *(*complex128)(v.addr) }
+
+// Set sets v to the value x.
+func (v *Complex128Value) Set(x complex128) {
+ if !v.canSet {
+ panic(cannotSet)
+ }
+ *(*complex128)(v.addr) = x
+}
+
+// Set sets v to the value x.
+func (v *Complex128Value) SetValue(x Value) { v.Set(x.(*Complex128Value).Get()) }
+
// IntValue represents an int value.
type IntValue struct {
value
@@ -1242,6 +1299,12 @@
return (*Float32Value)(v)
case *Float64Type:
return (*Float64Value)(v)
+ case *ComplexType:
+ return (*ComplexValue)(v)
+ case *Complex64Type:
+ return (*Complex64Value)(v)
+ case *Complex128Type:
+ return (*Complex128Value)(v)
case *IntType:
return (*IntValue)(v)
case *Int8Type:
diff -r 56cbaf257cf7 libgo/go/runtime/type.go
--- a/libgo/go/runtime/type.go Thu Mar 04 17:00:54 2010 -0800
+++ b/libgo/go/runtime/type.go Wed Mar 10 14:43:36 2010 -0800
@@ -45,6 +45,9 @@
MapTypeCode = 22
PtrTypeCode = 23
StructTypeCode = 24
+ Complex64TypeCode = 25
+ Complex128TypeCode = 26
+ ComplexTypeCode = 27
)
// All types begin with a few common fields needed for
diff -r 56cbaf257cf7 libgo/runtime/go-print.c
--- a/libgo/runtime/go-print.c Thu Mar 04 17:00:54 2010 -0800
+++ b/libgo/runtime/go-print.c Wed Mar 10 14:43:36 2010 -0800
@@ -52,6 +52,15 @@
}
void
+__go_print_complex (_Bool is_panic, __complex double val)
+{
+ fprintf (is_panic ? stderr : stdout, "(%.24g%s%.24gi)",
+ __builtin_creal (val),
+ __builtin_cimag (val) >= 0 ? "+" : "",
+ __builtin_cimag (val));
+}
+
+void
__go_print_bool (_Bool is_panic, _Bool val)
{
fputs (val ? "true" : "false", is_panic ? stderr : stdout);
diff -r 56cbaf257cf7 libgo/runtime/go-reflect-call.c
--- a/libgo/runtime/go-reflect-call.c Thu Mar 04 17:00:54 2010 -0800
+++ b/libgo/runtime/go-reflect-call.c Wed Mar 10 14:43:36 2010 -0800
@@ -108,6 +108,10 @@
abort ();
case GO_FLOAT:
return &ffi_type_float;
+ case GO_COMPLEX64:
+ case GO_COMPLEX128:
+ case GO_COMPLEX:
+ abort ();
case GO_INT16:
return &ffi_type_sint16;
case GO_INT32:
diff -r 56cbaf257cf7 libgo/runtime/go-reflect.c
--- a/libgo/runtime/go-reflect.c Thu Mar 04 17:00:54 2010 -0800
+++ b/libgo/runtime/go-reflect.c Wed Mar 10 14:43:36 2010 -0800
@@ -31,6 +31,12 @@
asm ("__go_td_pN33_libgo_runtime.runtime.Float64Type");
extern const struct __go_type_descriptor ptr_float_descriptor
asm ("__go_td_pN31_libgo_runtime.runtime.FloatType");
+extern const struct __go_type_descriptor ptr_complex64_descriptor
+ asm ("__go_td_pN35_libgo_runtime.runtime.Complex64Type");
+extern const struct __go_type_descriptor ptr_complex128_descriptor
+ asm ("__go_td_pN36_libgo_runtime.runtime.Complex128Type");
+extern const struct __go_type_descriptor ptr_complex_descriptor
+ asm ("__go_td_pN33_libgo_runtime.runtime.ComplexType");
extern const struct __go_type_descriptor ptr_int16_descriptor
asm ("__go_td_pN31_libgo_runtime.runtime.Int16Type");
extern const struct __go_type_descriptor ptr_int32_descriptor
@@ -87,6 +93,12 @@
return &ptr_float64_descriptor;
case GO_FLOAT:
return &ptr_float_descriptor;
+ case GO_COMPLEX64:
+ return &ptr_complex64_descriptor;
+ case GO_COMPLEX128:
+ return &ptr_complex128_descriptor;
+ case GO_COMPLEX:
+ return &ptr_complex_descriptor;
case GO_INT16:
return &ptr_int16_descriptor;
case GO_INT32:
diff -r 56cbaf257cf7 libgo/runtime/go-type.h
--- a/libgo/runtime/go-type.h Thu Mar 04 17:00:54 2010 -0800
+++ b/libgo/runtime/go-type.h Wed Mar 10 14:43:36 2010 -0800
@@ -54,6 +54,9 @@
#define GO_MAP 22
#define GO_PTR 23
#define GO_STRUCT 24
+#define GO_COMPLEX64 25
+#define GO_COMPLEX128 26
+#define GO_COMPLEX 27
/* For each Go type the compiler constructs one of these structures.
This is used for type reflectin, interfaces, maps, and reference
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [gccgo] Add complex numbers
2010-03-10 23:26 [gccgo] Add complex numbers Ian Lance Taylor
@ 2010-03-11 16:21 ` Richard Henderson
2010-03-11 16:44 ` Ian Lance Taylor
0 siblings, 1 reply; 7+ messages in thread
From: Richard Henderson @ 2010-03-11 16:21 UTC (permalink / raw)
To: Ian Lance Taylor; +Cc: gcc-patches
> + 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.
...
We already require the mpc library. Surely some of this
can be simplified...
r~
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [gccgo] Add complex numbers
2010-03-11 16:21 ` Richard Henderson
@ 2010-03-11 16:44 ` Ian Lance Taylor
2010-03-11 18:23 ` Kaveh R. GHAZI
0 siblings, 1 reply; 7+ messages in thread
From: Ian Lance Taylor @ 2010-03-11 16:44 UTC (permalink / raw)
To: Richard Henderson; +Cc: gcc-patches
Richard Henderson <rth@redhat.com> writes:
>> + 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.
> ...
>
> We already require the mpc library. Surely some of this
> can be simplified...
Probably. I haven't looked into mpc at all yet.
Ian
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [gccgo] Add complex numbers
2010-03-11 16:44 ` Ian Lance Taylor
@ 2010-03-11 18:23 ` Kaveh R. GHAZI
2010-03-14 20:35 ` Ian Lance Taylor
0 siblings, 1 reply; 7+ messages in thread
From: Kaveh R. GHAZI @ 2010-03-11 18:23 UTC (permalink / raw)
To: Ian Lance Taylor; +Cc: Richard Henderson, gcc-patches
On Thu, 11 Mar 2010, Ian Lance Taylor wrote:
> Richard Henderson <rth@redhat.com> writes:
>
> >> + 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.
> > ...
> >
> > We already require the mpc library. Surely some of this
> > can be simplified...
>
> Probably. I haven't looked into mpc at all yet.
> Ian
FWIW, I was able to convert the fortran frontend to use mpc_t for complex
numbers. It was pretty simple, I just changed the expression type in
gfortran.h from a struct containing a pair of mpfr_t to a field of type
mpc_t. Then see what broke when bootstrapping, repair and repeat. It was
entirely a compile-time fixup.
I think it was easier because the fortran frontend used explicit
alloc/dealloc calls when necessary. If garbage collection is involved
then it will be harder. (Note mpfr_t and mpc_t both suffer from this via
GMP's memory alloc model.)
I had toyed with the idea of replacing all tree-based floating point stuff
with mpfr_t/mpc_t for all frontends and the middle-end. This would solve
most (all?) of our accuracy problems. E.g. see:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21718#c7
But I got stuck on the GC issues.
--Kaveh
--- orig/egcc-SVN20100311/gcc/tree.h 2010-02-19 02:00:33.000000000
+0100
+++ egcc-SVN20100311/gcc/tree.h 2010-03-11 18:41:37.000000000 +0100
@@ -1396,7 +1396,7 @@ struct real_value;
struct GTY(()) tree_real_cst {
struct tree_common common;
- struct real_value * real_cst_ptr;
+ mpfr_t real_cst_ptr;
};
/* In a FIXED_CST node. */
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [gccgo] Add complex numbers
2010-03-11 18:23 ` Kaveh R. GHAZI
@ 2010-03-14 20:35 ` Ian Lance Taylor
2010-03-14 22:16 ` Kaveh R. Ghazi
0 siblings, 1 reply; 7+ messages in thread
From: Ian Lance Taylor @ 2010-03-14 20:35 UTC (permalink / raw)
To: Kaveh R. GHAZI; +Cc: Richard Henderson, gcc-patches
"Kaveh R. GHAZI" <ghazi@caip.rutgers.edu> writes:
> I had toyed with the idea of replacing all tree-based floating point stuff
> with mpfr_t/mpc_t for all frontends and the middle-end. This would solve
> most (all?) of our accuracy problems. E.g. see:
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21718#c7
>
> But I got stuck on the GC issues.
What were the issues? It ought to be more or less straightforward to
simply add mpfr_t and mpc_t to gengtype.
Ian
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [gccgo] Add complex numbers
2010-03-14 20:35 ` Ian Lance Taylor
@ 2010-03-14 22:16 ` Kaveh R. Ghazi
2010-03-16 17:03 ` Tom Tromey
0 siblings, 1 reply; 7+ messages in thread
From: Kaveh R. Ghazi @ 2010-03-14 22:16 UTC (permalink / raw)
To: Ian Lance Taylor; +Cc: Richard Henderson, gcc-patches
From: "Ian Lance Taylor" <iant@google.com>
> "Kaveh R. GHAZI" <ghazi@caip.rutgers.edu> writes:
>
>> I had toyed with the idea of replacing all tree-based floating point
>> stuff
>> with mpfr_t/mpc_t for all frontends and the middle-end. This would solve
>> most (all?) of our accuracy problems. E.g. see:
>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21718#c7
>>
>> But I got stuck on the GC issues.
>
> What were the issues? It ought to be more or less straightforward to
> simply add mpfr_t and mpc_t to gengtype.
> Ian
Well perhaps it is straightforward, but I couldn't figure out how to do it.
:-/
Also having gengtype recognize mpfr_t/mpc_t is one step. Then you have to
get it to call the mp*_init() function when allocating one of these and the
corresponding mp*_clear() when garbage collecting. I assume the init call
is simply put into tree.c:build_real(). But the clear call, I don't know
how to hook that into GC.
--Kaveh
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [gccgo] Add complex numbers
2010-03-14 22:16 ` Kaveh R. Ghazi
@ 2010-03-16 17:03 ` Tom Tromey
0 siblings, 0 replies; 7+ messages in thread
From: Tom Tromey @ 2010-03-16 17:03 UTC (permalink / raw)
To: Kaveh R. Ghazi; +Cc: Ian Lance Taylor, Richard Henderson, gcc-patches
>>>>> "Kaveh" == Kaveh R Ghazi <ghazi@caip.rutgers.edu> writes:
Kaveh> Also having gengtype recognize mpfr_t/mpc_t is one step. Then
Kaveh> you have to get it to call the mp*_init() function when
Kaveh> allocating one of these and the corresponding mp*_clear() when
Kaveh> garbage collecting. I assume the init call is simply put into
Kaveh> tree.c:build_real(). But the clear call, I don't know how to
Kaveh> hook that into GC.
Put all the objects into a global hash table that has the `if_marked'
GTY marker. Have this marker refer to a function that does something
like:
if (ggc_marked_p (obj))
return true;
mpmumble_clear (obj);
return false;
I think that ought to work and not require GGC changes.
Tom
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2010-03-16 17:03 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-03-10 23:26 [gccgo] Add complex numbers Ian Lance Taylor
2010-03-11 16:21 ` Richard Henderson
2010-03-11 16:44 ` Ian Lance Taylor
2010-03-11 18:23 ` Kaveh R. GHAZI
2010-03-14 20:35 ` Ian Lance Taylor
2010-03-14 22:16 ` Kaveh R. Ghazi
2010-03-16 17:03 ` Tom Tromey
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).