summaryrefslogtreecommitdiff
path: root/gcc/go/gofrontend
diff options
context:
space:
mode:
authorbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2014-01-23 11:48:32 +0000
committerbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2014-01-23 11:48:32 +0000
commitf6fc17d03f28a94e35a53d0562595ea179ae2629 (patch)
treee32f9a0a6bdc05a424906b384d8c31c4fa78eb35 /gcc/go/gofrontend
parent8e6ce8a843f5da1c63f8e21c58188e7b7f1a471f (diff)
downloadgcc-f6fc17d03f28a94e35a53d0562595ea179ae2629.tar.gz
2014-01-23 Basile Starynkevitch <basile@starynkevitch.net>
{{merge using svnmerge.py with trunk GCC 4.9 svn rev.206958. All is well compiled.}} git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@206959 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/go/gofrontend')
-rw-r--r--gcc/go/gofrontend/backend.h22
-rw-r--r--gcc/go/gofrontend/expressions.cc1090
-rw-r--r--gcc/go/gofrontend/expressions.h89
-rw-r--r--gcc/go/gofrontend/go.cc5
-rw-r--r--gcc/go/gofrontend/gogo.cc215
-rw-r--r--gcc/go/gofrontend/gogo.h18
-rw-r--r--gcc/go/gofrontend/statements.cc11
-rw-r--r--gcc/go/gofrontend/statements.h19
-rw-r--r--gcc/go/gofrontend/types.cc92
-rw-r--r--gcc/go/gofrontend/types.h42
10 files changed, 1084 insertions, 519 deletions
diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h
index 55805941da6..e3025167fd4 100644
--- a/gcc/go/gofrontend/backend.h
+++ b/gcc/go/gofrontend/backend.h
@@ -10,6 +10,8 @@
#include <gmp.h>
#include <mpfr.h>
+#include "operator.h"
+
// Pointers to these types are created by the backend, passed to the
// frontend, and passed back to the backend. The types must be
// defined by the backend using these names.
@@ -284,6 +286,26 @@ class Backend
virtual Bexpression*
struct_field_expression(Bexpression* bstruct, size_t index, Location) = 0;
+ // Create an expression that executes BSTAT before BEXPR.
+ virtual Bexpression*
+ compound_expression(Bstatement* bstat, Bexpression* bexpr, Location) = 0;
+
+ // Return an expression that executes THEN_EXPR if CONDITION is true, or
+ // ELSE_EXPR otherwise and returns the result as type BTYPE. ELSE_EXPR
+ // may be NULL. BTYPE may be NULL.
+ virtual Bexpression*
+ conditional_expression(Btype* btype, Bexpression* condition,
+ Bexpression* then_expr, Bexpression* else_expr,
+ Location) = 0;
+
+ // Return an expression for the binary operation LEFT OP RIGHT.
+ // Supported values of OP are (from operators.h):
+ // EQEQ, NOTEQ, LT, LE, GT, GE, PLUS, MINUS, OR, XOR, MULT, DIV, MOD,
+ // LSHIFT, RSHIFT, AND, NOT.
+ virtual Bexpression*
+ binary_expression(Operator op, Bexpression* left, Bexpression* right,
+ Location) = 0;
+
// Statements.
// Create an error statement. This is used for cases which should
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 2f1c026c983..544996ea6cb 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -3060,6 +3060,9 @@ class Type_conversion_expression : public Expression
Expression*
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
+ Expression*
+ do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
bool
do_is_constant() const;
@@ -3203,6 +3206,25 @@ Type_conversion_expression::do_lower(Gogo*, Named_object*,
return this;
}
+// Flatten a type conversion by using a temporary variable for the slice
+// in slice to string conversions.
+
+Expression*
+Type_conversion_expression::do_flatten(Gogo*, Named_object*,
+ Statement_inserter* inserter)
+{
+ if (this->type()->is_string_type()
+ && this->expr_->type()->is_slice_type()
+ && !this->expr_->is_variable())
+ {
+ Temporary_statement* temp =
+ Statement::make_temporary(NULL, this->expr_, this->location());
+ inserter->insert(temp);
+ this->expr_ = Expression::make_temporary_reference(temp, this->location());
+ }
+ return this;
+}
+
// Return whether a type conversion is a constant.
bool
@@ -3361,47 +3383,24 @@ Type_conversion_expression::do_get_tree(Translate_context* context)
}
else if (type->is_string_type() && expr_type->is_slice_type())
{
- if (!DECL_P(expr_tree))
- expr_tree = save_expr(expr_tree);
-
- Type* int_type = Type::lookup_integer_type("int");
- tree int_type_tree = type_to_tree(int_type->get_backend(gogo));
-
+ Location location = this->location();
Array_type* a = expr_type->array_type();
Type* e = a->element_type()->forwarded();
go_assert(e->integer_type() != NULL);
- tree valptr = fold_convert(const_ptr_type_node,
- a->value_pointer_tree(gogo, expr_tree));
- tree len = a->length_tree(gogo, expr_tree);
- len = fold_convert_loc(this->location().gcc_location(), int_type_tree,
- len);
+ go_assert(this->expr_->is_variable());
+
+ Runtime::Function code;
if (e->integer_type()->is_byte())
- {
- static tree byte_array_to_string_fndecl;
- ret = Gogo::call_builtin(&byte_array_to_string_fndecl,
- this->location(),
- "__go_byte_array_to_string",
- 2,
- type_tree,
- const_ptr_type_node,
- valptr,
- int_type_tree,
- len);
- }
+ code = Runtime::BYTE_ARRAY_TO_STRING;
else
- {
- go_assert(e->integer_type()->is_rune());
- static tree int_array_to_string_fndecl;
- ret = Gogo::call_builtin(&int_array_to_string_fndecl,
- this->location(),
- "__go_int_array_to_string",
- 2,
- type_tree,
- const_ptr_type_node,
- valptr,
- int_type_tree,
- len);
- }
+ {
+ go_assert(e->integer_type()->is_rune());
+ code = Runtime::INT_ARRAY_TO_STRING;
+ }
+ Expression* valptr = a->get_value_pointer(gogo, this->expr_);
+ Expression* len = a->get_length(gogo, this->expr_);
+ Expression* a2s_expr = Runtime::make_call(code, location, 2, valptr, len);
+ ret = a2s_expr->get_tree(context);
}
else if (type->is_slice_type() && expr_type->is_string_type())
{
@@ -5537,6 +5536,61 @@ Binary_expression::lower_compare_to_memcmp(Gogo*, Statement_inserter* inserter)
return Expression::make_binary(this->op_, call, zero, loc);
}
+Expression*
+Binary_expression::do_flatten(Gogo*, Named_object*,
+ Statement_inserter* inserter)
+{
+ Location loc = this->location();
+ Temporary_statement* temp;
+ if (this->left_->type()->is_string_type()
+ && this->op_ == OPERATOR_PLUS)
+ {
+ if (!this->left_->is_variable())
+ {
+ temp = Statement::make_temporary(NULL, this->left_, loc);
+ inserter->insert(temp);
+ this->left_ = Expression::make_temporary_reference(temp, loc);
+ }
+ if (!this->right_->is_variable())
+ {
+ temp =
+ Statement::make_temporary(this->left_->type(), this->right_, loc);
+ this->right_ = Expression::make_temporary_reference(temp, loc);
+ inserter->insert(temp);
+ }
+ }
+
+ Type* left_type = this->left_->type();
+ bool is_shift_op = (this->op_ == OPERATOR_LSHIFT
+ || this->op_ == OPERATOR_RSHIFT);
+ bool is_idiv_op = ((this->op_ == OPERATOR_DIV &&
+ left_type->integer_type() != NULL)
+ || this->op_ == OPERATOR_MOD);
+
+ // FIXME: go_check_divide_zero and go_check_divide_overflow are globals
+ // defined in gcc/go/lang.opt. These should be defined in go_create_gogo
+ // and accessed from the Gogo* passed to do_flatten.
+ if (is_shift_op
+ || (is_idiv_op && (go_check_divide_zero || go_check_divide_overflow)))
+ {
+ if (!this->left_->is_variable())
+ {
+ temp = Statement::make_temporary(NULL, this->left_, loc);
+ inserter->insert(temp);
+ this->left_ = Expression::make_temporary_reference(temp, loc);
+ }
+ if (!this->right_->is_variable())
+ {
+ temp =
+ Statement::make_temporary(NULL, this->right_, loc);
+ this->right_ = Expression::make_temporary_reference(temp, loc);
+ inserter->insert(temp);
+ }
+ }
+ return this;
+}
+
+
// Return the address of EXPR, cast to unsafe.Pointer.
Expression*
@@ -5957,14 +6011,10 @@ tree
Binary_expression::do_get_tree(Translate_context* context)
{
Gogo* gogo = context->gogo();
+ Location loc = this->location();
+ Type* left_type = this->left_->type();
+ Type* right_type = this->right_->type();
- tree left = this->left_->get_tree(context);
- tree right = this->right_->get_tree(context);
-
- if (left == error_mark_node || right == error_mark_node)
- return error_mark_node;
-
- enum tree_code code;
bool use_left_type = true;
bool is_shift_op = false;
bool is_idiv_op = false;
@@ -5976,198 +6026,126 @@ Binary_expression::do_get_tree(Translate_context* context)
case OPERATOR_LE:
case OPERATOR_GT:
case OPERATOR_GE:
- return Expression::comparison_tree(context, this->type_, this->op_,
- this->left_, this->right_,
- this->location());
+ {
+ Bexpression* ret =
+ Expression::comparison(context, this->type_, this->op_,
+ this->left_, this->right_, loc);
+ return expr_to_tree(ret);
+ }
case OPERATOR_OROR:
- code = TRUTH_ORIF_EXPR;
- use_left_type = false;
- break;
case OPERATOR_ANDAND:
- code = TRUTH_ANDIF_EXPR;
use_left_type = false;
break;
case OPERATOR_PLUS:
- code = PLUS_EXPR;
- break;
case OPERATOR_MINUS:
- code = MINUS_EXPR;
- break;
case OPERATOR_OR:
- code = BIT_IOR_EXPR;
- break;
case OPERATOR_XOR:
- code = BIT_XOR_EXPR;
- break;
case OPERATOR_MULT:
- code = MULT_EXPR;
break;
case OPERATOR_DIV:
- {
- Type *t = this->left_->type();
- if (t->float_type() != NULL || t->complex_type() != NULL)
- code = RDIV_EXPR;
- else
- {
- code = TRUNC_DIV_EXPR;
- is_idiv_op = true;
- }
- }
- break;
+ if (left_type->float_type() != NULL || left_type->complex_type() != NULL)
+ break;
case OPERATOR_MOD:
- code = TRUNC_MOD_EXPR;
is_idiv_op = true;
break;
case OPERATOR_LSHIFT:
- code = LSHIFT_EXPR;
- is_shift_op = true;
- break;
case OPERATOR_RSHIFT:
- code = RSHIFT_EXPR;
is_shift_op = true;
break;
- case OPERATOR_AND:
- code = BIT_AND_EXPR;
- break;
case OPERATOR_BITCLEAR:
- right = fold_build1(BIT_NOT_EXPR, TREE_TYPE(right), right);
- code = BIT_AND_EXPR;
+ this->right_ = Expression::make_unary(OPERATOR_XOR, this->right_, loc);
+ case OPERATOR_AND:
break;
default:
go_unreachable();
}
- location_t gccloc = this->location().gcc_location();
- tree type = use_left_type ? TREE_TYPE(left) : TREE_TYPE(right);
-
- if (this->left_->type()->is_string_type())
+ if (left_type->is_string_type())
{
go_assert(this->op_ == OPERATOR_PLUS);
- Type* st = Type::make_string_type();
- tree string_type = type_to_tree(st->get_backend(gogo));
- static tree string_plus_decl;
- return Gogo::call_builtin(&string_plus_decl,
- this->location(),
- "__go_string_plus",
- 2,
- string_type,
- string_type,
- left,
- string_type,
- right);
- }
-
- // For complex division Go wants slightly different results than the
- // GCC library provides, so we have our own runtime routine.
+ Expression* string_plus =
+ Runtime::make_call(Runtime::STRING_PLUS, loc, 2,
+ this->left_, this->right_);
+ return string_plus->get_tree(context);
+ }
+
+ // For complex division Go might want slightly different results than the
+ // backend implementation provides, so we have our own runtime routine.
if (this->op_ == OPERATOR_DIV && this->left_->type()->complex_type() != NULL)
{
- const char *name;
- tree *pdecl;
- Type* ctype;
- static tree complex64_div_decl;
- static tree complex128_div_decl;
+ Runtime::Function complex_code;
switch (this->left_->type()->complex_type()->bits())
{
case 64:
- name = "__go_complex64_div";
- pdecl = &complex64_div_decl;
- ctype = Type::lookup_complex_type("complex64");
+ complex_code = Runtime::COMPLEX64_DIV;
break;
case 128:
- name = "__go_complex128_div";
- pdecl = &complex128_div_decl;
- ctype = Type::lookup_complex_type("complex128");
+ complex_code = Runtime::COMPLEX128_DIV;
break;
default:
go_unreachable();
}
- Btype* cbtype = ctype->get_backend(gogo);
- tree ctype_tree = type_to_tree(cbtype);
- return Gogo::call_builtin(pdecl,
- this->location(),
- name,
- 2,
- ctype_tree,
- ctype_tree,
- fold_convert_loc(gccloc, ctype_tree, left),
- type,
- fold_convert_loc(gccloc, ctype_tree, right));
+ Expression* complex_div =
+ Runtime::make_call(complex_code, loc, 2, this->left_, this->right_);
+ return complex_div->get_tree(context);
}
- tree compute_type = excess_precision_type(type);
- if (compute_type != NULL_TREE)
- {
- left = ::convert(compute_type, left);
- right = ::convert(compute_type, right);
- }
+ Bexpression* left = tree_to_expr(this->left_->get_tree(context));
+ Bexpression* right = tree_to_expr(this->right_->get_tree(context));
- tree eval_saved = NULL_TREE;
- if (is_shift_op
- || (is_idiv_op && (go_check_divide_zero || go_check_divide_overflow)))
- {
- // Make sure the values are evaluated.
- if (!DECL_P(left))
- {
- left = save_expr(left);
- eval_saved = left;
- }
- if (!DECL_P(right))
- {
- right = save_expr(right);
- if (eval_saved == NULL_TREE)
- eval_saved = right;
- else
- eval_saved = fold_build2_loc(gccloc, COMPOUND_EXPR,
- void_type_node, eval_saved, right);
- }
- }
+ Type* type = use_left_type ? left_type : right_type;
+ Btype* btype = type->get_backend(gogo);
+
+ Bexpression* ret =
+ gogo->backend()->binary_expression(this->op_, left, right, loc);
+ ret = gogo->backend()->convert_expression(btype, ret, loc);
- tree ret = fold_build2_loc(gccloc, code,
- compute_type != NULL_TREE ? compute_type : type,
- left, right);
+ // Initialize overflow constants.
+ Bexpression* overflow;
+ mpz_t zero;
+ mpz_init_set_ui(zero, 0UL);
+ mpz_t one;
+ mpz_init_set_ui(one, 1UL);
+ mpz_t neg_one;
+ mpz_init_set_si(neg_one, -1);
- if (compute_type != NULL_TREE)
- ret = ::convert(type, ret);
+ Btype* left_btype = left_type->get_backend(gogo);
+ Btype* right_btype = right_type->get_backend(gogo);
// 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.
+ // This is not true in C, so we need to insert a conditional.
if (is_shift_op)
{
- go_assert(INTEGRAL_TYPE_P(TREE_TYPE(left)));
- go_assert(this->left_->type()->integer_type() != NULL);
- int bits = TYPE_PRECISION(TREE_TYPE(left));
+ go_assert(left_type->integer_type() != NULL);
- tree compare = fold_build2(LT_EXPR, boolean_type_node, right,
- build_int_cst_type(TREE_TYPE(right), bits));
+ mpz_t bitsval;
+ int bits = left_type->integer_type()->bits();
+ mpz_init_set_ui(bitsval, bits);
+ Bexpression* bits_expr =
+ gogo->backend()->integer_constant_expression(right_btype, bitsval);
+ Bexpression* compare =
+ gogo->backend()->binary_expression(OPERATOR_LT,
+ right, bits_expr, loc);
- tree overflow_result = fold_convert_loc(gccloc, TREE_TYPE(left),
- integer_zero_node);
+ Bexpression* zero_expr =
+ gogo->backend()->integer_constant_expression(left_btype, zero);
+ overflow = zero_expr;
if (this->op_ == OPERATOR_RSHIFT
- && !this->left_->type()->integer_type()->is_unsigned())
+ && !left_type->integer_type()->is_unsigned())
{
- tree neg =
- fold_build2_loc(gccloc, LT_EXPR, boolean_type_node,
- left,
- fold_convert_loc(gccloc, TREE_TYPE(left),
- integer_zero_node));
- tree neg_one =
- fold_build2_loc(gccloc, MINUS_EXPR, TREE_TYPE(left),
- fold_convert_loc(gccloc, TREE_TYPE(left),
- integer_zero_node),
- fold_convert_loc(gccloc, TREE_TYPE(left),
- integer_one_node));
- overflow_result =
- fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(left),
- neg, neg_one, overflow_result);
+ Bexpression* neg_expr =
+ gogo->backend()->binary_expression(OPERATOR_LT, left,
+ zero_expr, loc);
+ Bexpression* neg_one_expr =
+ gogo->backend()->integer_constant_expression(left_btype, neg_one);
+ overflow = gogo->backend()->conditional_expression(btype, neg_expr,
+ neg_one_expr,
+ zero_expr, loc);
}
-
- ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(left),
- compare, ret, overflow_result);
-
- if (eval_saved != NULL_TREE)
- ret = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret),
- eval_saved, ret);
+ ret = gogo->backend()->conditional_expression(btype, compare, ret,
+ overflow, loc);
+ mpz_clear(bitsval);
}
// Add checks for division by zero and division overflow as needed.
@@ -6176,23 +6154,20 @@ Binary_expression::do_get_tree(Translate_context* context)
if (go_check_divide_zero)
{
// right == 0
- tree check = fold_build2_loc(gccloc, EQ_EXPR, boolean_type_node,
- right,
- fold_convert_loc(gccloc,
- TREE_TYPE(right),
- integer_zero_node));
+ Bexpression* zero_expr =
+ gogo->backend()->integer_constant_expression(right_btype, zero);
+ Bexpression* check =
+ gogo->backend()->binary_expression(OPERATOR_EQEQ,
+ right, zero_expr, loc);
- // __go_runtime_error(RUNTIME_ERROR_DIVISION_BY_ZERO), 0
+ // __go_runtime_error(RUNTIME_ERROR_DIVISION_BY_ZERO)
int errcode = RUNTIME_ERROR_DIVISION_BY_ZERO;
- Expression* crash = gogo->runtime_error(errcode, this->location());
- tree panic = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret),
- crash->get_tree(context),
- fold_convert_loc(gccloc, TREE_TYPE(ret),
- integer_zero_node));
+ Expression* crash = gogo->runtime_error(errcode, loc);
+ Bexpression* crash_expr = tree_to_expr(crash->get_tree(context));
// right == 0 ? (__go_runtime_error(...), 0) : ret
- ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
- check, panic, ret);
+ ret = gogo->backend()->conditional_expression(btype, check,
+ crash_expr, ret, loc);
}
if (go_check_divide_overflow)
@@ -6200,60 +6175,62 @@ Binary_expression::do_get_tree(Translate_context* context)
// right == -1
// FIXME: It would be nice to say that this test is expected
// to return false.
- tree m1 = integer_minus_one_node;
- tree check = fold_build2_loc(gccloc, EQ_EXPR, boolean_type_node,
- right,
- fold_convert_loc(gccloc,
- TREE_TYPE(right),
- m1));
-
- tree overflow;
- if (TYPE_UNSIGNED(TREE_TYPE(ret)))
+
+ Bexpression* neg_one_expr =
+ gogo->backend()->integer_constant_expression(right_btype, neg_one);
+ Bexpression* check =
+ gogo->backend()->binary_expression(OPERATOR_EQEQ,
+ right, neg_one_expr, loc);
+
+ Bexpression* zero_expr =
+ gogo->backend()->integer_constant_expression(btype, zero);
+ Bexpression* one_expr =
+ gogo->backend()->integer_constant_expression(btype, one);
+
+ if (type->integer_type()->is_unsigned())
{
// An unsigned -1 is the largest possible number, so
// dividing is always 1 or 0.
- tree cmp = fold_build2_loc(gccloc, EQ_EXPR, boolean_type_node,
- left, right);
+
+ Bexpression* cmp =
+ gogo->backend()->binary_expression(OPERATOR_EQEQ,
+ left, right, loc);
if (this->op_ == OPERATOR_DIV)
- overflow = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
- cmp,
- fold_convert_loc(gccloc,
- TREE_TYPE(ret),
- integer_one_node),
- fold_convert_loc(gccloc,
- TREE_TYPE(ret),
- integer_zero_node));
+ overflow =
+ gogo->backend()->conditional_expression(btype, cmp,
+ one_expr, zero_expr,
+ loc);
else
- overflow = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
- cmp,
- fold_convert_loc(gccloc,
- TREE_TYPE(ret),
- integer_zero_node),
- left);
+ overflow =
+ gogo->backend()->conditional_expression(btype, cmp,
+ zero_expr, left,
+ loc);
}
else
{
// Computing left / -1 is the same as computing - left,
// which does not overflow since Go sets -fwrapv.
if (this->op_ == OPERATOR_DIV)
- overflow = fold_build1_loc(gccloc, NEGATE_EXPR, TREE_TYPE(left),
- left);
+ {
+ Expression* negate_expr =
+ Expression::make_unary(OPERATOR_MINUS, this->left_, loc);
+ overflow = tree_to_expr(negate_expr->get_tree(context));
+ }
else
- overflow = integer_zero_node;
+ overflow = zero_expr;
}
- overflow = fold_convert_loc(gccloc, TREE_TYPE(ret), overflow);
+ overflow = gogo->backend()->convert_expression(btype, overflow, loc);
// right == -1 ? - left : ret
- ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
- check, overflow, ret);
+ ret = gogo->backend()->conditional_expression(btype, check, overflow,
+ ret, loc);
}
-
- if (eval_saved != NULL_TREE)
- ret = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret),
- eval_saved, ret);
}
- return ret;
+ mpz_clear(zero);
+ mpz_clear(one);
+ mpz_clear(neg_one);
+ return expr_to_tree(ret);
}
// Export a binary expression.
@@ -6472,55 +6449,24 @@ Expression::make_binary(Operator op, Expression* left, Expression* right,
// Implement a comparison.
-tree
-Expression::comparison_tree(Translate_context* context, Type* result_type,
- Operator op, Expression* left_expr,
- Expression* right_expr, Location location)
+Bexpression*
+Expression::comparison(Translate_context* context, Type* result_type,
+ Operator op, Expression* left, Expression* right,
+ Location location)
{
- Type* left_type = left_expr->type();
- Type* right_type = right_expr->type();
+ Type* left_type = left->type();
+ Type* right_type = right->type();
mpz_t zval;
mpz_init_set_ui(zval, 0UL);
Expression* zexpr = Expression::make_integer(&zval, NULL, location);
mpz_clear(zval);
- enum tree_code code;
- switch (op)
- {
- case OPERATOR_EQEQ:
- code = EQ_EXPR;
- break;
- case OPERATOR_NOTEQ:
- code = NE_EXPR;
- break;
- case OPERATOR_LT:
- code = LT_EXPR;
- break;
- case OPERATOR_LE:
- code = LE_EXPR;
- break;
- case OPERATOR_GT:
- code = GT_EXPR;
- break;
- case OPERATOR_GE:
- code = GE_EXPR;
- break;
- default:
- go_unreachable();
- }
-
- // FIXME: Computing the tree here means it will be computed multiple times,
- // which is wasteful. This is a temporary modification until all tree code
- // here can be replaced with frontend expressions.
- tree left_tree = left_expr->get_tree(context);
- tree right_tree = right_expr->get_tree(context);
if (left_type->is_string_type() && right_type->is_string_type())
{
- Expression* strcmp_call = Runtime::make_call(Runtime::STRCMP, location, 2,
- left_expr, right_expr);
- left_tree = strcmp_call->get_tree(context);
- right_tree = zexpr->get_tree(context);
+ left = Runtime::make_call(Runtime::STRCMP, location, 2,
+ left, right);
+ right = zexpr;
}
else if ((left_type->interface_type() != NULL
&& right_type->interface_type() == NULL
@@ -6533,31 +6479,30 @@ Expression::comparison_tree(Translate_context* context, Type* result_type,
if (left_type->interface_type() == NULL)
{
std::swap(left_type, right_type);
- std::swap(left_expr, right_expr);
+ std::swap(left, right);
}
// The right operand is not an interface. We need to take its
// address if it is not a pointer.
Expression* pointer_arg = NULL;
if (right_type->points_to() != NULL)
- pointer_arg = right_expr;
+ pointer_arg = right;
else
{
- go_assert(right_expr->is_addressable());
- pointer_arg = Expression::make_unary(OPERATOR_AND, right_expr,
+ go_assert(right->is_addressable());
+ pointer_arg = Expression::make_unary(OPERATOR_AND, right,
location);
}
- Expression* descriptor_expr = Expression::make_type_descriptor(right_type,
- location);
- Call_expression* iface_valcmp =
+ Expression* descriptor =
+ Expression::make_type_descriptor(right_type, location);
+ left =
Runtime::make_call((left_type->interface_type()->is_empty()
? Runtime::EMPTY_INTERFACE_VALUE_COMPARE
: Runtime::INTERFACE_VALUE_COMPARE),
- location, 3, left_expr, descriptor_expr,
+ location, 3, left, descriptor,
pointer_arg);
- left_tree = iface_valcmp->get_tree(context);
- right_tree = zexpr->get_tree(context);
+ right = zexpr;
}
else if (left_type->interface_type() != NULL
&& right_type->interface_type() != NULL)
@@ -6575,66 +6520,49 @@ Expression::comparison_tree(Translate_context* context, Type* result_type,
{
go_assert(op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ);
std::swap(left_type, right_type);
- std::swap(left_expr, right_expr);
+ std::swap(left, right);
}
go_assert(!left_type->interface_type()->is_empty());
go_assert(right_type->interface_type()->is_empty());
compare_function = Runtime::INTERFACE_EMPTY_COMPARE;
}
- Call_expression* ifacecmp_call =
- Runtime::make_call(compare_function, location, 2,
- left_expr, right_expr);
-
- left_tree = ifacecmp_call->get_tree(context);
- right_tree = zexpr->get_tree(context);
+ left = Runtime::make_call(compare_function, location, 2, left, right);
+ right = zexpr;
}
if (left_type->is_nil_type()
&& (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ))
{
std::swap(left_type, right_type);
- std::swap(left_tree, right_tree);
+ std::swap(left, right);
}
if (right_type->is_nil_type())
{
+ right = Expression::make_nil(location);
if (left_type->array_type() != NULL
&& left_type->array_type()->length() == NULL)
{
Array_type* at = left_type->array_type();
- left_tree = at->value_pointer_tree(context->gogo(), left_tree);
- right_tree = fold_convert(TREE_TYPE(left_tree), null_pointer_node);
+ left = at->get_value_pointer(context->gogo(), left);
}
else if (left_type->interface_type() != NULL)
{
// An interface is nil if the first field is nil.
- tree left_type_tree = TREE_TYPE(left_tree);
- go_assert(TREE_CODE(left_type_tree) == RECORD_TYPE);
- tree field = TYPE_FIELDS(left_type_tree);
- left_tree = build3(COMPONENT_REF, TREE_TYPE(field), left_tree,
- field, NULL_TREE);
- right_tree = fold_convert(TREE_TYPE(left_tree), null_pointer_node);
- }
- else
- {
- go_assert(POINTER_TYPE_P(TREE_TYPE(left_tree)));
- right_tree = fold_convert(TREE_TYPE(left_tree), null_pointer_node);
+ left = Expression::make_field_reference(left, 0, location);
}
}
- if (left_tree == error_mark_node || right_tree == error_mark_node)
- return error_mark_node;
+ Bexpression* left_bexpr = tree_to_expr(left->get_tree(context));
+ Bexpression* right_bexpr = tree_to_expr(right->get_tree(context));
- tree result_type_tree;
- if (result_type == NULL)
- result_type_tree = boolean_type_node;
- else
- result_type_tree = type_to_tree(result_type->get_backend(context->gogo()));
-
- tree ret = fold_build2(code, result_type_tree, left_tree, right_tree);
- if (CAN_HAVE_LOCATION_P(ret))
- SET_EXPR_LOCATION(ret, location.gcc_location());
+ Gogo* gogo = context->gogo();
+ Bexpression* ret = gogo->backend()->binary_expression(op, left_bexpr,
+ right_bexpr, location);
+ if (result_type != NULL)
+ ret = gogo->backend()->convert_expression(result_type->get_backend(gogo),
+ ret, location);
return ret;
}
@@ -6850,6 +6778,7 @@ Bound_method_expression::create_thunk(Gogo* gogo, const Method* method,
Block* b = gogo->finish_block(loc);
gogo->add_block(b, loc);
gogo->lower_block(new_no, b);
+ gogo->flatten_block(new_no, b);
gogo->finish_function(loc);
ins.first->second = new_no;
@@ -7037,6 +6966,9 @@ class Builtin_call_expression : public Call_expression
Expression*
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
+ Expression*
+ do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
bool
do_is_constant() const;
@@ -7367,6 +7299,36 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
return this;
}
+// Flatten a builtin call expression. This turns the arguments of copy and
+// append into temporary expressions.
+
+Expression*
+Builtin_call_expression::do_flatten(Gogo*, Named_object*,
+ Statement_inserter* inserter)
+{
+ if (this->code_ == BUILTIN_APPEND
+ || this->code_ == BUILTIN_COPY)
+ {
+ Location loc = this->location();
+ Type* at = this->args()->front()->type();
+ for (Expression_list::iterator pa = this->args()->begin();
+ pa != this->args()->end();
+ ++pa)
+ {
+ if ((*pa)->is_nil_expression())
+ *pa = Expression::make_slice_composite_literal(at, NULL, loc);
+ if (!(*pa)->is_variable())
+ {
+ Temporary_statement* temp =
+ Statement::make_temporary(NULL, *pa, loc);
+ inserter->insert(temp);
+ *pa = Expression::make_temporary_reference(temp, loc);
+ }
+ }
+ }
+ return this;
+}
+
// Lower a make expression.
Expression*
@@ -8503,7 +8465,8 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
return error_mark_node;
}
this->seen_ = true;
- val_tree = arg_type->array_type()->length_tree(gogo, arg_tree);
+ Expression* len = arg_type->array_type()->get_length(gogo, arg);
+ val_tree = len->get_tree(context);
this->seen_ = false;
}
else if (arg_type->map_type() != NULL)
@@ -8543,8 +8506,9 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
return error_mark_node;
}
this->seen_ = true;
- val_tree = arg_type->array_type()->capacity_tree(gogo,
- arg_tree);
+ Expression* cap =
+ arg_type->array_type()->get_capacity(gogo, arg);
+ val_tree = cap->get_tree(context);
this->seen_ = false;
}
else if (arg_type->channel_type() != NULL)
@@ -8848,9 +8812,11 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
Type* arg1_type = arg1->type();
Array_type* at = arg1_type->array_type();
- arg1_tree = save_expr(arg1_tree);
- tree arg1_val = at->value_pointer_tree(gogo, arg1_tree);
- tree arg1_len = at->length_tree(gogo, arg1_tree);
+ go_assert(arg1->is_variable());
+ Expression* arg1_valptr = at->get_value_pointer(gogo, arg1);
+ Expression* arg1_len_expr = at->get_length(gogo, arg1);
+ tree arg1_val = arg1_valptr->get_tree(context);
+ tree arg1_len = arg1_len_expr->get_tree(context);
if (arg1_val == error_mark_node || arg1_len == error_mark_node)
return error_mark_node;
@@ -8860,9 +8826,11 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
if (arg2_type->is_slice_type())
{
at = arg2_type->array_type();
- arg2_tree = save_expr(arg2_tree);
- arg2_val = at->value_pointer_tree(gogo, arg2_tree);
- arg2_len = at->length_tree(gogo, arg2_tree);
+ go_assert(arg2->is_variable());
+ Expression* arg2_valptr = at->get_value_pointer(gogo, arg2);
+ Expression* arg2_len_expr = at->get_length(gogo, arg2);
+ arg2_val = arg2_valptr->get_tree(context);
+ arg2_len = arg2_len_expr->get_tree(context);
}
else
{
@@ -8950,23 +8918,15 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
}
else
{
- arg2_tree = Expression::convert_for_assignment(context, at,
- arg2->type(),
- arg2_tree,
- location);
- if (arg2_tree == error_mark_node)
+ go_assert(arg2->is_variable());
+ arg2_val =
+ at->get_value_pointer(gogo, arg2)->get_tree(context);
+ arg2_len = at->get_length(gogo, arg2)->get_tree(context);
+ Btype* element_btype = element_type->get_backend(gogo);
+ tree element_type_tree = type_to_tree(element_btype);
+ if (element_type_tree == error_mark_node)
return error_mark_node;
-
- arg2_tree = save_expr(arg2_tree);
-
- arg2_val = at->value_pointer_tree(gogo, arg2_tree);
- arg2_len = at->length_tree(gogo, arg2_tree);
-
- Btype* element_btype = element_type->get_backend(gogo);
- tree element_type_tree = type_to_tree(element_btype);
- if (element_type_tree == error_mark_node)
- return error_mark_node;
- element_size = TYPE_SIZE_UNIT(element_type_tree);
+ element_size = TYPE_SIZE_UNIT(element_type_tree);
}
arg2_val = fold_convert_loc(location.gcc_location(), ptr_type_node,
@@ -9713,21 +9673,13 @@ Call_expression::do_must_eval_in_order() const
// Get the function and the first argument to use when calling an
// interface method.
-tree
+Expression*
Call_expression::interface_method_function(
- Translate_context* context,
Interface_field_reference_expression* interface_method,
- tree* first_arg_ptr)
+ Expression** first_arg_ptr)
{
- tree expr = interface_method->expr()->get_tree(context);
- if (expr == error_mark_node)
- return error_mark_node;
- expr = save_expr(expr);
- tree first_arg = interface_method->get_underlying_object_tree(context, expr);
- if (first_arg == error_mark_node)
- return error_mark_node;
- *first_arg_ptr = first_arg;
- return interface_method->get_function_tree(context, expr);
+ *first_arg_ptr = interface_method->get_underlying_object();
+ return interface_method->get_function();
}
// Build the call expression.
@@ -9857,8 +9809,12 @@ Call_expression::do_get_tree(Translate_context* context)
}
else
{
- fn = this->interface_method_function(context, interface_method,
- &args[0]);
+ Expression* first_arg;
+ Expression* fn_expr =
+ this->interface_method_function(interface_method, &first_arg);
+ args[0] = first_arg->get_tree(context);
+ fn = fn_expr->get_tree(context);
+
if (fn == error_mark_node)
return error_mark_node;
closure_tree = NULL_TREE;
@@ -10371,6 +10327,9 @@ class Array_index_expression : public Expression
do_check_types(Gogo*);
Expression*
+ do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
+ Expression*
do_copy()
{
return Expression::make_array_index(this->array_->copy(),
@@ -10611,6 +10570,22 @@ Array_index_expression::do_check_types(Gogo*)
}
}
+// Flatten array indexing by using a temporary variable for slices.
+
+Expression*
+Array_index_expression::do_flatten(Gogo*, Named_object*,
+ Statement_inserter* inserter)
+{
+ Location loc = this->location();
+ if (this->array_->type()->is_slice_type() && !this->array_->is_variable())
+ {
+ Temporary_statement* temp = Statement::make_temporary(NULL, this->array_, loc);
+ inserter->insert(temp);
+ this->array_ = Expression::make_temporary_reference(temp, loc);
+ }
+ return this;
+}
+
// Return whether this expression is addressable.
bool
@@ -10643,22 +10618,17 @@ Array_index_expression::do_get_tree(Translate_context* context)
go_assert(this->array_->type()->is_error());
return error_mark_node;
}
+ go_assert(!array_type->is_slice_type() || this->array_->is_variable());
tree type_tree = type_to_tree(array_type->get_backend(gogo));
if (type_tree == error_mark_node)
return error_mark_node;
- tree array_tree = this->array_->get_tree(context);
- if (array_tree == error_mark_node)
- return error_mark_node;
-
- if (array_type->length() == NULL && !DECL_P(array_tree))
- array_tree = save_expr(array_tree);
-
tree length_tree = NULL_TREE;
if (this->end_ == NULL || this->end_->is_nil_expression())
{
- length_tree = array_type->length_tree(gogo, array_tree);
+ Expression* len = array_type->get_length(gogo, this->array_);
+ length_tree = len->get_tree(context);
if (length_tree == error_mark_node)
return error_mark_node;
length_tree = save_expr(length_tree);
@@ -10667,7 +10637,8 @@ Array_index_expression::do_get_tree(Translate_context* context)
tree capacity_tree = NULL_TREE;
if (this->end_ != NULL)
{
- capacity_tree = array_type->capacity_tree(gogo, array_tree);
+ Expression* cap = array_type->get_capacity(gogo, this->array_);
+ capacity_tree = cap->get_tree(context);
if (capacity_tree == error_mark_node)
return error_mark_node;
capacity_tree = save_expr(capacity_tree);
@@ -10732,13 +10703,18 @@ Array_index_expression::do_get_tree(Translate_context* context)
if (array_type->length() != NULL)
{
// Fixed array.
+ tree array_tree = this->array_->get_tree(context);
+ if (array_tree == error_mark_node)
+ return error_mark_node;
return build4(ARRAY_REF, TREE_TYPE(type_tree), array_tree,
start_tree, NULL_TREE, NULL_TREE);
}
else
{
// Open array.
- tree values = array_type->value_pointer_tree(gogo, array_tree);
+ Expression* valptr =
+ array_type->get_value_pointer(gogo, this->array_);
+ tree values = valptr->get_tree(context);
Type* element_type = array_type->element_type();
Btype* belement_type = element_type->get_backend(gogo);
tree element_type_tree = type_to_tree(belement_type);
@@ -10820,7 +10796,8 @@ Array_index_expression::do_get_tree(Translate_context* context)
start_tree),
element_size);
- tree value_pointer = array_type->value_pointer_tree(gogo, array_tree);
+ Expression* valptr = array_type->get_value_pointer(gogo, this->array_);
+ tree value_pointer = valptr->get_tree(context);
if (value_pointer == error_mark_node)
return error_mark_node;
@@ -11570,58 +11547,39 @@ Expression::make_field_reference(Expression* expr, unsigned int field_index,
// Class Interface_field_reference_expression.
-// Return a tree for the pointer to the function to call.
+// Return an expression for the pointer to the function to call.
-tree
-Interface_field_reference_expression::get_function_tree(Translate_context*,
- tree expr)
+Expression*
+Interface_field_reference_expression::get_function()
{
- if (this->expr_->type()->points_to() != NULL)
- expr = build_fold_indirect_ref(expr);
-
- tree expr_type = TREE_TYPE(expr);
- go_assert(TREE_CODE(expr_type) == RECORD_TYPE);
-
- tree field = TYPE_FIELDS(expr_type);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__methods") == 0);
-
- tree table = build3(COMPONENT_REF, TREE_TYPE(field), expr, field, NULL_TREE);
- go_assert(POINTER_TYPE_P(TREE_TYPE(table)));
+ Expression* ref = this->expr_;
+ Location loc = this->location();
+ if (ref->type()->points_to() != NULL)
+ ref = Expression::make_unary(OPERATOR_MULT, ref, loc);
- table = build_fold_indirect_ref(table);
- go_assert(TREE_CODE(TREE_TYPE(table)) == RECORD_TYPE);
+ Expression* mtable =
+ Expression::make_interface_info(ref, INTERFACE_INFO_METHODS, loc);
+ Struct_type* mtable_type = mtable->type()->points_to()->struct_type();
std::string name = Gogo::unpack_hidden_name(this->name_);
- for (field = DECL_CHAIN(TYPE_FIELDS(TREE_TYPE(table)));
- field != NULL_TREE;
- field = DECL_CHAIN(field))
- {
- if (name == IDENTIFIER_POINTER(DECL_NAME(field)))
- break;
- }
- go_assert(field != NULL_TREE);
-
- return build3(COMPONENT_REF, TREE_TYPE(field), table, field, NULL_TREE);
+ unsigned int index;
+ const Struct_field* field = mtable_type->find_local_field(name, &index);
+ go_assert(field != NULL);
+ mtable = Expression::make_unary(OPERATOR_MULT, mtable, loc);
+ return Expression::make_field_reference(mtable, index, loc);
}
-// Return a tree for the first argument to pass to the interface
+// Return an expression for the first argument to pass to the interface
// function.
-tree
-Interface_field_reference_expression::get_underlying_object_tree(
- Translate_context*,
- tree expr)
+Expression*
+Interface_field_reference_expression::get_underlying_object()
{
- if (this->expr_->type()->points_to() != NULL)
- expr = build_fold_indirect_ref(expr);
-
- tree expr_type = TREE_TYPE(expr);
- go_assert(TREE_CODE(expr_type) == RECORD_TYPE);
-
- tree field = DECL_CHAIN(TYPE_FIELDS(expr_type));
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__object") == 0);
-
- return build3(COMPONENT_REF, TREE_TYPE(field), expr, field, NULL_TREE);
+ Expression* expr = this->expr_;
+ if (expr->type()->points_to() != NULL)
+ expr = Expression::make_unary(OPERATOR_MULT, expr, this->location());
+ return Expression::make_interface_info(expr, INTERFACE_INFO_OBJECT,
+ this->location());
}
// Traversal.
@@ -11641,9 +11599,7 @@ Interface_field_reference_expression::do_lower(Gogo*, Named_object*,
Statement_inserter* inserter,
int)
{
- if (this->expr_->var_expression() == NULL
- && this->expr_->temporary_reference_expression() == NULL
- && this->expr_->set_and_use_temporary_expression() == NULL)
+ if (!this->expr_->is_variable())
{
Temporary_statement* temp =
Statement::make_temporary(this->expr_->type(), NULL, this->location());
@@ -11820,6 +11776,7 @@ Interface_field_reference_expression::create_thunk(Gogo* gogo,
Block* b = gogo->finish_block(loc);
gogo->add_block(b, loc);
gogo->lower_block(new_no, b);
+ gogo->flatten_block(new_no, b);
gogo->finish_function(loc);
ins.first->second->push_back(std::make_pair(name, new_no));
@@ -11870,30 +11827,22 @@ Interface_field_reference_expression::do_get_tree(Translate_context* context)
Expression* expr = Expression::make_struct_composite_literal(st, vals, loc);
expr = Expression::make_heap_composite(expr, loc);
- tree closure_tree = expr->get_tree(context);
+ Bexpression* bclosure = tree_to_expr(expr->get_tree(context));
+ Expression* nil_check =
+ Expression::make_binary(OPERATOR_EQEQ, this->expr_,
+ Expression::make_nil(loc), loc);
+ Bexpression* bnil_check = tree_to_expr(nil_check->get_tree(context));
- // Note that we are evaluating this->expr_ twice, but that is OK
- // because in the lowering pass we forced it into a temporary
- // variable.
- tree nil_check_tree = Expression::comparison_tree(context,
- Type::lookup_bool_type(),
- OPERATOR_EQEQ,
- this->expr_,
- Expression::make_nil(loc),
- loc);
- Expression* crash_expr =
- context->gogo()->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, loc);
- tree crash = crash_expr->get_tree(context);
- if (closure_tree == error_mark_node
- || nil_check_tree == error_mark_node
- || crash == error_mark_node)
- return error_mark_node;
- return fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR,
- TREE_TYPE(closure_tree),
- build3_loc(loc.gcc_location(), COND_EXPR,
- void_type_node, nil_check_tree, crash,
- NULL_TREE),
- closure_tree);
+ Gogo* gogo = context->gogo();
+ Expression* crash = gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, loc);
+ Bexpression* bcrash = tree_to_expr(crash->get_tree(context));
+
+ Bexpression* bcond =
+ gogo->backend()->conditional_expression(NULL, bnil_check, bcrash, NULL, loc);
+ Bstatement* cond_statement = gogo->backend()->expression_statement(bcond);
+ Bexpression* ret =
+ gogo->backend()->compound_expression(cond_statement, bclosure, loc);
+ return expr_to_tree(ret);
}
// Dump ast representation for an interface field reference.
@@ -12158,6 +12107,7 @@ Selector_expression::lower_method_expression(Gogo* gogo)
// Lower the call in case there are multiple results.
gogo->lower_block(no, b);
+ gogo->flatten_block(no, b);
gogo->finish_function(location);
@@ -14133,6 +14083,22 @@ Expression::is_nonconstant_composite_literal() const
}
}
+// Return true if this is a variable or temporary_variable.
+
+bool
+Expression::is_variable() const
+{
+ switch (this->classification_)
+ {
+ case EXPRESSION_VAR_REFERENCE:
+ case EXPRESSION_TEMPORARY_REFERENCE:
+ case EXPRESSION_SET_AND_USE_TEMPORARY:
+ return true;
+ default:
+ return false;
+ }
+}
+
// Return true if this is a reference to a local variable.
bool
@@ -14574,6 +14540,266 @@ Expression::make_type_info(Type* type, Type_info type_info)
return new Type_info_expression(type, type_info);
}
+// An expression that evaluates to some characteristic of a slice.
+// This is used when indexing, bound-checking, or nil checking a slice.
+
+class Slice_info_expression : public Expression
+{
+ public:
+ Slice_info_expression(Expression* slice, Slice_info slice_info,
+ Location location)
+ : Expression(EXPRESSION_SLICE_INFO, location),
+ slice_(slice), slice_info_(slice_info)
+ { }
+
+ protected:
+ Type*
+ do_type();
+
+ void
+ do_determine_type(const Type_context*)
+ { }
+
+ Expression*
+ do_copy()
+ {
+ return new Slice_info_expression(this->slice_->copy(), this->slice_info_,
+ this->location());
+ }
+
+ tree
+ do_get_tree(Translate_context* context);
+
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
+ void
+ do_issue_nil_check()
+ { this->slice_->issue_nil_check(); }
+
+ private:
+ // The slice for which we are getting information.
+ Expression* slice_;
+ // What information we want.
+ Slice_info slice_info_;
+};
+
+// Return the type of the slice info.
+
+Type*
+Slice_info_expression::do_type()
+{
+ switch (this->slice_info_)
+ {
+ case SLICE_INFO_VALUE_POINTER:
+ return Type::make_pointer_type(
+ this->slice_->type()->array_type()->element_type());
+ case SLICE_INFO_LENGTH:
+ case SLICE_INFO_CAPACITY:
+ return Type::lookup_integer_type("int");
+ default:
+ go_unreachable();
+ }
+}
+
+// Return slice information in GENERIC.
+
+tree
+Slice_info_expression::do_get_tree(Translate_context* context)
+{
+ Gogo* gogo = context->gogo();
+
+ Bexpression* bslice = tree_to_expr(this->slice_->get_tree(context));
+ Bexpression* ret;
+ switch (this->slice_info_)
+ {
+ case SLICE_INFO_VALUE_POINTER:
+ case SLICE_INFO_LENGTH:
+ case SLICE_INFO_CAPACITY:
+ ret = gogo->backend()->struct_field_expression(bslice, this->slice_info_,
+ this->location());
+ break;
+ default:
+ go_unreachable();
+ }
+ return expr_to_tree(ret);
+}
+
+// Dump ast representation for a type info expression.
+
+void
+Slice_info_expression::do_dump_expression(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->ostream() << "sliceinfo(";
+ this->slice_->dump_expression(ast_dump_context);
+ ast_dump_context->ostream() << ",";
+ ast_dump_context->ostream() <<
+ (this->slice_info_ == SLICE_INFO_VALUE_POINTER ? "values"
+ : this->slice_info_ == SLICE_INFO_LENGTH ? "length"
+ : this->slice_info_ == SLICE_INFO_CAPACITY ? "capacity "
+ : "unknown");
+ ast_dump_context->ostream() << ")";
+}
+
+// Make a slice info expression.
+
+Expression*
+Expression::make_slice_info(Expression* slice, Slice_info slice_info,
+ Location location)
+{
+ return new Slice_info_expression(slice, slice_info, location);
+}
+
+
+// An expression that evaluates to some characteristic of a non-empty interface.
+// This is used to access the method table or underlying object of an interface.
+
+class Interface_info_expression : public Expression
+{
+ public:
+ Interface_info_expression(Expression* iface, Interface_info iface_info,
+ Location location)
+ : Expression(EXPRESSION_INTERFACE_INFO, location),
+ iface_(iface), iface_info_(iface_info)
+ { }
+
+ protected:
+ Type*
+ do_type();
+
+ void
+ do_determine_type(const Type_context*)
+ { }
+
+ Expression*
+ do_copy()
+ {
+ return new Interface_info_expression(this->iface_->copy(),
+ this->iface_info_, this->location());
+ }
+
+ tree
+ do_get_tree(Translate_context* context);
+
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
+ void
+ do_issue_nil_check()
+ { this->iface_->issue_nil_check(); }
+
+ private:
+ // The interface for which we are getting information.
+ Expression* iface_;
+ // What information we want.
+ Interface_info iface_info_;
+};
+
+// Return the type of the interface info.
+
+Type*
+Interface_info_expression::do_type()
+{
+ switch (this->iface_info_)
+ {
+ case INTERFACE_INFO_METHODS:
+ {
+ Location loc = this->location();
+ Struct_field_list* sfl = new Struct_field_list();
+ Type* pdt = Type::make_type_descriptor_ptr_type();
+ sfl->push_back(
+ Struct_field(Typed_identifier("__type_descriptor", pdt, loc)));
+
+ Interface_type* itype = this->iface_->type()->interface_type();
+ for (Typed_identifier_list::const_iterator p = itype->methods()->begin();
+ p != itype->methods()->end();
+ ++p)
+ {
+ Function_type* ft = p->type()->function_type();
+ go_assert(ft->receiver() == NULL);
+
+ const Typed_identifier_list* params = ft->parameters();
+ Typed_identifier_list* mparams = new Typed_identifier_list();
+ if (params != NULL)
+ mparams->reserve(params->size() + 1);
+ Type* vt = Type::make_pointer_type(Type::make_void_type());
+ mparams->push_back(Typed_identifier("", vt, ft->location()));
+ if (params != NULL)
+ {
+ for (Typed_identifier_list::const_iterator pp = params->begin();
+ pp != params->end();
+ ++pp)
+ mparams->push_back(*pp);
+ }
+
+ Typed_identifier_list* mresults = (ft->results() == NULL
+ ? NULL
+ : ft->results()->copy());
+ Backend_function_type* mft =
+ Type::make_backend_function_type(NULL, mparams, mresults,
+ ft->location());
+
+ std::string fname = Gogo::unpack_hidden_name(p->name());
+ sfl->push_back(Struct_field(Typed_identifier(fname, mft, loc)));
+ }
+
+ return Type::make_pointer_type(Type::make_struct_type(sfl, loc));
+ }
+ case INTERFACE_INFO_OBJECT:
+ return Type::make_pointer_type(Type::make_void_type());
+ default:
+ go_unreachable();
+ }
+}
+
+// Return interface information in GENERIC.
+
+tree
+Interface_info_expression::do_get_tree(Translate_context* context)
+{
+ Gogo* gogo = context->gogo();
+
+ Bexpression* biface = tree_to_expr(this->iface_->get_tree(context));
+ Bexpression* ret;
+ switch (this->iface_info_)
+ {
+ case INTERFACE_INFO_METHODS:
+ case INTERFACE_INFO_OBJECT:
+ ret = gogo->backend()->struct_field_expression(biface, this->iface_info_,
+ this->location());
+ break;
+ default:
+ go_unreachable();
+ }
+ return expr_to_tree(ret);
+}
+
+// Dump ast representation for an interface info expression.
+
+void
+Interface_info_expression::do_dump_expression(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->ostream() << "interfaceinfo(";
+ this->iface_->dump_expression(ast_dump_context);
+ ast_dump_context->ostream() << ",";
+ ast_dump_context->ostream() <<
+ (this->iface_info_ == INTERFACE_INFO_METHODS ? "methods"
+ : this->iface_info_ == INTERFACE_INFO_OBJECT ? "object"
+ : "unknown");
+ ast_dump_context->ostream() << ")";
+}
+
+// Make an interface info expression.
+
+Expression*
+Expression::make_interface_info(Expression* iface, Interface_info iface_info,
+ Location location)
+{
+ return new Interface_info_expression(iface, iface_info, location);
+}
+
// An expression which evaluates to the offset of a field within a
// struct. This, like Type_info_expression, q.v., is only used to
// initialize fields of a type descriptor.
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index e447418b949..9ddd17122f2 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -102,6 +102,8 @@ class Expression
EXPRESSION_RECEIVE,
EXPRESSION_TYPE_DESCRIPTOR,
EXPRESSION_TYPE_INFO,
+ EXPRESSION_SLICE_INFO,
+ EXPRESSION_INTERFACE_INFO,
EXPRESSION_STRUCT_FIELD_OFFSET,
EXPRESSION_MAP_DESCRIPTOR,
EXPRESSION_LABEL_ADDR
@@ -339,6 +341,37 @@ class Expression
static Expression*
make_type_info(Type* type, Type_info);
+ // Make an expression that evaluates to some characteristic of a
+ // slice. For simplicity, the enum values must match the field indexes
+ // in the underlying struct.
+ enum Slice_info
+ {
+ // The underlying data of the slice.
+ SLICE_INFO_VALUE_POINTER,
+ // The length of the slice.
+ SLICE_INFO_LENGTH,
+ // The capacity of the slice.
+ SLICE_INFO_CAPACITY
+ };
+
+ static Expression*
+ make_slice_info(Expression* slice, Slice_info, Location);
+
+
+ // Make an expression that evaluates to some characteristic of a
+ // interface. For simplicity, the enum values must match the field indexes
+ // of a non-empty interface in the underlying struct.
+ enum Interface_info
+ {
+ // The methods of an interface.
+ INTERFACE_INFO_METHODS,
+ // The first argument to pass to an interface method.
+ INTERFACE_INFO_OBJECT
+ };
+
+ static Expression*
+ make_interface_info(Expression* iface, Interface_info, Location);
+
// Make an expression which evaluates to the offset of a field in a
// struct. This is only used for type descriptors, so there is no
// location parameter.
@@ -544,6 +577,10 @@ class Expression
bool
is_nonconstant_composite_literal() const;
+ // Return true if this is a variable or temporary variable.
+ bool
+ is_variable() const;
+
// Return true if this is a reference to a local variable.
bool
is_local_variable() const;
@@ -575,6 +612,18 @@ class Expression
int iota_value)
{ return this->do_lower(gogo, function, inserter, iota_value); }
+ // Flatten an expression. This is called after order_evaluation.
+ // FUNCTION is the function we are in; it will be NULL for an
+ // expression initializing a global variable. INSERTER may be used
+ // to insert statements before the statement or initializer
+ // containing this expression; it is normally used to create
+ // temporary variables. This function must resolve expressions
+ // which could not be fully parsed into their final form. It
+ // returns the same Expression or a new one.
+ Expression*
+ flatten(Gogo* gogo, Named_object* function, Statement_inserter* inserter)
+ { return this->do_flatten(gogo, function, inserter); }
+
// Determine the real type of an expression with abstract integer,
// floating point, or complex type. TYPE_CONTEXT describes the
// expected type.
@@ -655,11 +704,11 @@ class Expression
Type* rhs_type, tree rhs_tree,
bool for_type_guard, Location);
- // Return a tree implementing the comparison LHS_EXPR OP RHS_EXPR.
+ // Return a backend expression implementing the comparison LEFT OP RIGHT.
// TYPE is the type of both sides.
- static tree
- comparison_tree(Translate_context*, Type* result_type, Operator op,
- Expression* left_expr, Expression* right_expr, Location);
+ static Bexpression*
+ comparison(Translate_context*, Type* result_type, Operator op,
+ Expression* left, Expression* right, Location);
// Return the backend expression for the numeric constant VAL.
static Bexpression*
@@ -698,6 +747,12 @@ class Expression
do_lower(Gogo*, Named_object*, Statement_inserter*, int)
{ return this; }
+ // Return a flattened expression.
+ virtual Expression*
+ do_flatten(Gogo*, Named_object*, Statement_inserter*)
+ { return this; }
+
+
// Return whether this is a constant expression.
virtual bool
do_is_constant() const
@@ -1234,6 +1289,9 @@ class Binary_expression : public Expression
Expression*
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
+ Expression*
+ do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
bool
do_is_constant() const
{ return this->left_->is_constant() && this->right_->is_constant(); }
@@ -1469,10 +1527,9 @@ class Call_expression : public Expression
bool
check_argument_type(int, const Type*, const Type*, Location, bool);
- tree
- interface_method_function(Translate_context*,
- Interface_field_reference_expression*,
- tree*);
+ Expression*
+ interface_method_function(Interface_field_reference_expression*,
+ Expression**);
tree
set_results(Translate_context*, tree);
@@ -2076,16 +2133,14 @@ class Interface_field_reference_expression : public Expression
static Named_object*
create_thunk(Gogo*, Interface_type* type, const std::string& name);
- // Return a tree for the pointer to the function to call, given a
- // tree for the expression.
- tree
- get_function_tree(Translate_context*, tree);
+ // Return an expression for the pointer to the function to call.
+ Expression*
+ get_function();
- // Return a tree for the first argument to pass to the interface
- // function, given a tree for the expression. This is the real
- // object associated with the interface object.
- tree
- get_underlying_object_tree(Translate_context*, tree);
+ // Return an expression for the first argument to pass to the interface
+ // function. This is the real object associated with the interface object.
+ Expression*
+ get_underlying_object();
protected:
int
diff --git a/gcc/go/gofrontend/go.cc b/gcc/go/gofrontend/go.cc
index 55b4dca8579..26e83a1db64 100644
--- a/gcc/go/gofrontend/go.cc
+++ b/gcc/go/gofrontend/go.cc
@@ -119,12 +119,15 @@ go_parse_input_files(const char** filenames, unsigned int filename_count,
// Use temporary variables to force order of evaluation.
::gogo->order_evaluations();
+ // Flatten the parse tree.
+ ::gogo->flatten();
+
// Build thunks for functions which call recover.
::gogo->build_recover_thunks();
// Convert complicated go and defer statements into simpler ones.
::gogo->simplify_thunk_statements();
-
+
// Dump ast, use filename[0] as the base name
::gogo->dump_ast(filenames[0]);
}
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index e46bf9c4193..6ecc6cd0f0f 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -2703,6 +2703,178 @@ Gogo::order_evaluations()
this->traverse(&order_eval);
}
+// Traversal to flatten parse tree after order of evaluation rules are applied.
+
+class Flatten : public Traverse
+{
+ public:
+ Flatten(Gogo* gogo, Named_object* function)
+ : Traverse(traverse_variables
+ | traverse_functions
+ | traverse_statements
+ | traverse_expressions),
+ gogo_(gogo), function_(function), inserter_()
+ { }
+
+ void
+ set_inserter(const Statement_inserter* inserter)
+ { this->inserter_ = *inserter; }
+
+ int
+ variable(Named_object*);
+
+ int
+ function(Named_object*);
+
+ int
+ statement(Block*, size_t* pindex, Statement*);
+
+ int
+ expression(Expression**);
+
+ private:
+ // General IR.
+ Gogo* gogo_;
+ // The function we are traversing.
+ Named_object* function_;
+ // Current statement inserter for use by expressions.
+ Statement_inserter inserter_;
+};
+
+// Flatten variables.
+
+int
+Flatten::variable(Named_object* no)
+{
+ if (!no->is_variable())
+ return TRAVERSE_CONTINUE;
+
+ if (no->is_variable() && no->var_value()->is_global())
+ {
+ // Global variables can have loops in their initialization
+ // expressions. This is handled in flatten_init_expression.
+ no->var_value()->flatten_init_expression(this->gogo_, this->function_,
+ &this->inserter_);
+ return TRAVERSE_CONTINUE;
+ }
+
+ go_assert(!no->var_value()->has_pre_init());
+
+ return TRAVERSE_SKIP_COMPONENTS;
+}
+
+// Flatten the body of a function. Record the function while flattening it,
+// so that we can pass it down when flattening an expression.
+
+int
+Flatten::function(Named_object* no)
+{
+ go_assert(this->function_ == NULL);
+ this->function_ = no;
+ int t = no->func_value()->traverse(this);
+ this->function_ = NULL;
+
+ if (t == TRAVERSE_EXIT)
+ return t;
+ return TRAVERSE_SKIP_COMPONENTS;
+}
+
+// Flatten statement parse trees.
+
+int
+Flatten::statement(Block* block, size_t* pindex, Statement* sorig)
+{
+ // Because we explicitly traverse the statement's contents
+ // ourselves, we want to skip block statements here. There is
+ // nothing to flatten in a block statement.
+ if (sorig->is_block_statement())
+ return TRAVERSE_CONTINUE;
+
+ Statement_inserter hold_inserter(this->inserter_);
+ this->inserter_ = Statement_inserter(block, pindex);
+
+ // Flatten the expressions first.
+ int t = sorig->traverse_contents(this);
+ if (t == TRAVERSE_EXIT)
+ {
+ this->inserter_ = hold_inserter;
+ return t;
+ }
+
+ // Keep flattening until nothing changes.
+ Statement* s = sorig;
+ while (true)
+ {
+ Statement* snew = s->flatten(this->gogo_, this->function_, block,
+ &this->inserter_);
+ if (snew == s)
+ break;
+ s = snew;
+ t = s->traverse_contents(this);
+ if (t == TRAVERSE_EXIT)
+ {
+ this->inserter_ = hold_inserter;
+ return t;
+ }
+ }
+
+ if (s != sorig)
+ block->replace_statement(*pindex, s);
+
+ this->inserter_ = hold_inserter;
+ return TRAVERSE_SKIP_COMPONENTS;
+}
+
+// Flatten expression parse trees.
+
+int
+Flatten::expression(Expression** pexpr)
+{
+ // Keep flattening until nothing changes.
+ while (true)
+ {
+ Expression* e = *pexpr;
+ if (e->traverse_subexpressions(this) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
+
+ Expression* enew = e->flatten(this->gogo_, this->function_,
+ &this->inserter_);
+ if (enew == e)
+ break;
+ *pexpr = enew;
+ }
+ return TRAVERSE_SKIP_COMPONENTS;
+}
+
+// Flatten a block.
+
+void
+Gogo::flatten_block(Named_object* function, Block* block)
+{
+ Flatten flatten(this, function);
+ block->traverse(&flatten);
+}
+
+// Flatten an expression. INSERTER may be NULL, in which case the
+// expression had better not need to create any temporaries.
+
+void
+Gogo::flatten_expression(Named_object* function, Statement_inserter* inserter,
+ Expression** pexpr)
+{
+ Flatten flatten(this, function);
+ if (inserter != NULL)
+ flatten.set_inserter(inserter);
+ flatten.expression(pexpr);
+}
+
+void
+Gogo::flatten()
+{
+ Flatten flatten(this, NULL);
+ this->traverse(&flatten);
+}
+
// Traversal to convert calls to the predeclared recover function to
// pass in an argument indicating whether it can recover from a panic
// or not.
@@ -4286,10 +4458,11 @@ Variable::Variable(Type* type, Expression* init, bool is_global,
backend_(NULL), is_global_(is_global), is_parameter_(is_parameter),
is_receiver_(is_receiver), is_varargs_parameter_(false), is_used_(false),
is_address_taken_(false), is_non_escaping_address_taken_(false),
- seen_(false), init_is_lowered_(false), type_from_init_tuple_(false),
- type_from_range_index_(false), type_from_range_value_(false),
- type_from_chan_element_(false), is_type_switch_var_(false),
- determined_type_(false), in_unique_section_(false)
+ seen_(false), init_is_lowered_(false), init_is_flattened_(false),
+ type_from_init_tuple_(false), type_from_range_index_(false),
+ type_from_range_value_(false), type_from_chan_element_(false),
+ is_type_switch_var_(false), determined_type_(false),
+ in_unique_section_(false)
{
go_assert(type != NULL || init != NULL);
go_assert(!is_parameter || init == NULL);
@@ -4351,6 +4524,40 @@ Variable::lower_init_expression(Gogo* gogo, Named_object* function,
}
}
+// Flatten the initialization expression after ordering evaluations.
+
+void
+Variable::flatten_init_expression(Gogo* gogo, Named_object* function,
+ Statement_inserter* inserter)
+{
+ Named_object* dep = gogo->var_depends_on(this);
+ if (dep != NULL && dep->is_variable())
+ dep->var_value()->flatten_init_expression(gogo, function, inserter);
+
+ if (this->init_ != NULL && !this->init_is_flattened_)
+ {
+ if (this->seen_)
+ {
+ // We will give an error elsewhere, this is just to prevent
+ // an infinite loop.
+ return;
+ }
+ this->seen_ = true;
+
+ Statement_inserter global_inserter;
+ if (this->is_global_)
+ {
+ global_inserter = Statement_inserter(gogo, this);
+ inserter = &global_inserter;
+ }
+
+ gogo->flatten_expression(function, inserter, &this->init_);
+
+ this->seen_ = false;
+ this->init_is_flattened_ = true;
+ }
+}
+
// Get the preinit block.
Block*
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index a9a56815c17..3f2808781b7 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -487,6 +487,14 @@ class Gogo
void
lower_constant(Named_object*);
+ // Flatten all the statements in a block.
+ void
+ flatten_block(Named_object* function, Block*);
+
+ // Flatten an expression.
+ void
+ flatten_expression(Named_object* function, Statement_inserter*, Expression**);
+
// Create all necessary function descriptors.
void
create_function_descriptors();
@@ -531,6 +539,10 @@ class Gogo
void
order_evaluations();
+ // Flatten parse tree.
+ void
+ flatten();
+
// Build thunks for functions which call recover.
void
build_recover_thunks();
@@ -1447,6 +1459,10 @@ class Variable
void
lower_init_expression(Gogo*, Named_object*, Statement_inserter*);
+ // Flatten the initialization expression after ordering evaluations.
+ void
+ flatten_init_expression(Gogo*, Named_object*, Statement_inserter*);
+
// A special case: the init value is used only to determine the
// type. This is used if the variable is defined using := with the
// comma-ok form of a map index or a receive expression. The init
@@ -1580,6 +1596,8 @@ class Variable
bool seen_ : 1;
// True if we have lowered the initialization expression.
bool init_is_lowered_ : 1;
+ // True if we have flattened the initialization expression.
+ bool init_is_flattened_ : 1;
// True if init is a tuple used to set the type.
bool type_from_init_tuple_ : 1;
// True if init is a range clause and the type is the index type.
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index 3a0bc3b9739..d195ab9845a 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -246,6 +246,16 @@ Variable_declaration_statement::do_lower(Gogo* gogo, Named_object* function,
return this;
}
+// Flatten the variable's initialization expression.
+
+Statement*
+Variable_declaration_statement::do_flatten(Gogo* gogo, Named_object* function,
+ Block*, Statement_inserter* inserter)
+{
+ this->var_->var_value()->flatten_init_expression(gogo, function, inserter);
+ return this;
+}
+
// Convert a variable declaration to the backend representation.
Bstatement*
@@ -2461,6 +2471,7 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
gogo->add_block(b, location);
gogo->lower_block(function, b);
+ gogo->flatten_block(function, b);
// We already ran the determine_types pass, so we need to run it
// just for the call statement now. The other types are known.
diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h
index b128fa0a8eb..7d9bcfde8b7 100644
--- a/gcc/go/gofrontend/statements.h
+++ b/gcc/go/gofrontend/statements.h
@@ -306,6 +306,16 @@ class Statement
Statement_inserter* inserter)
{ return this->do_lower(gogo, function, block, inserter); }
+ // Flatten a statement. This is called immediately after the order of
+ // evaluation rules are applied to statements. It returns the same
+ // Statement or a new one. FUNCTION is the function containing this
+ // statement. BLOCK is the block containing this statement.
+ // INSERTER can be used to insert new statements before this one.
+ Statement*
+ flatten(Gogo* gogo, Named_object* function, Block* block,
+ Statement_inserter* inserter)
+ { return this->do_flatten(gogo, function, block, inserter); }
+
// Set type information for unnamed constants.
void
determine_types();
@@ -412,6 +422,12 @@ class Statement
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*)
{ return this; }
+ // Implemented by the child class: lower this statement to a simpler
+ // one.
+ virtual Statement*
+ do_flatten(Gogo*, Named_object*, Block*, Statement_inserter*)
+ { return this; }
+
// Implemented by child class: set type information for unnamed
// constants. Any statement which includes an expression needs to
// implement this.
@@ -583,6 +599,9 @@ class Variable_declaration_statement : public Statement
Statement*
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
+ Statement*
+ do_flatten(Gogo*, Named_object*, Block*, Statement_inserter*);
+
Bstatement*
do_get_backend(Translate_context*);
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index d079565d18b..2148a1a43e6 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -4066,6 +4066,17 @@ Type::make_function_type(Typed_identifier* receiver,
return new Function_type(receiver, parameters, results, location);
}
+// Make a backend function type.
+
+Backend_function_type*
+Type::make_backend_function_type(Typed_identifier* receiver,
+ Typed_identifier_list* parameters,
+ Typed_identifier_list* results,
+ Location location)
+{
+ return new Backend_function_type(receiver, parameters, results, location);
+}
+
// Class Pointer_type.
// Traversal.
@@ -6000,84 +6011,53 @@ Array_type::finish_backend_element(Gogo* gogo)
}
}
-// Return a tree for a pointer to the values in ARRAY.
+// Return an expression for a pointer to the values in ARRAY.
-tree
-Array_type::value_pointer_tree(Gogo*, tree array) const
+Expression*
+Array_type::get_value_pointer(Gogo*, Expression* array) const
{
- tree ret;
if (this->length() != NULL)
{
// Fixed array.
- ret = fold_convert(build_pointer_type(TREE_TYPE(TREE_TYPE(array))),
- build_fold_addr_expr(array));
+ go_assert(array->type()->array_type() != NULL);
+ Type* etype = array->type()->array_type()->element_type();
+ array = Expression::make_unary(OPERATOR_AND, array, array->location());
+ return Expression::make_cast(Type::make_pointer_type(etype), array,
+ array->location());
}
- else
- {
- // Open array.
- tree field = TYPE_FIELDS(TREE_TYPE(array));
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
- "__values") == 0);
- ret = fold_build3(COMPONENT_REF, TREE_TYPE(field), array, field,
- NULL_TREE);
- }
- if (TREE_CONSTANT(array))
- TREE_CONSTANT(ret) = 1;
- return ret;
+
+ // Open array.
+ return Expression::make_slice_info(array,
+ Expression::SLICE_INFO_VALUE_POINTER,
+ array->location());
}
-// Return a tree for the length of the array ARRAY which has this
+// Return an expression for the length of the array ARRAY which has this
// type.
-tree
-Array_type::length_tree(Gogo* gogo, tree array)
+Expression*
+Array_type::get_length(Gogo*, Expression* array) const
{
if (this->length_ != NULL)
- {
- if (TREE_CODE(array) == SAVE_EXPR)
- return this->get_length_tree(gogo);
- else
- {
- tree len = this->get_length_tree(gogo);
- return omit_one_operand(TREE_TYPE(len), len, array);
- }
- }
+ return this->length_;
// This is an open array. We need to read the length field.
-
- tree type = TREE_TYPE(array);
- go_assert(TREE_CODE(type) == RECORD_TYPE);
-
- tree field = DECL_CHAIN(TYPE_FIELDS(type));
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0);
-
- tree ret = build3(COMPONENT_REF, TREE_TYPE(field), array, field, NULL_TREE);
- if (TREE_CONSTANT(array))
- TREE_CONSTANT(ret) = 1;
- return ret;
+ return Expression::make_slice_info(array, Expression::SLICE_INFO_LENGTH,
+ array->location());
}
-// Return a tree for the capacity of the array ARRAY which has this
+// Return an expression for the capacity of the array ARRAY which has this
// type.
-tree
-Array_type::capacity_tree(Gogo* gogo, tree array)
+Expression*
+Array_type::get_capacity(Gogo*, Expression* array) const
{
if (this->length_ != NULL)
- {
- tree len = this->get_length_tree(gogo);
- return omit_one_operand(TREE_TYPE(len), len, array);
- }
+ return this->length_;
// This is an open array. We need to read the capacity field.
-
- tree type = TREE_TYPE(array);
- go_assert(TREE_CODE(type) == RECORD_TYPE);
-
- tree field = DECL_CHAIN(DECL_CHAIN(TYPE_FIELDS(type)));
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__capacity") == 0);
-
- return build3(COMPONENT_REF, TREE_TYPE(field), array, field, NULL_TREE);
+ return Expression::make_slice_info(array, Expression::SLICE_INFO_CAPACITY,
+ array->location());
}
// Export.
diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h
index 9f965916131..5fda4e7285e 100644
--- a/gcc/go/gofrontend/types.h
+++ b/gcc/go/gofrontend/types.h
@@ -19,6 +19,7 @@ class Float_type;
class Complex_type;
class String_type;
class Function_type;
+class Backend_function_type;
class Struct_field;
class Struct_field_list;
class Struct_type;
@@ -484,6 +485,12 @@ class Type
Typed_identifier_list* results,
Location);
+ static Backend_function_type*
+ make_backend_function_type(Typed_identifier* receiver,
+ Typed_identifier_list* parameters,
+ Typed_identifier_list* results,
+ Location);
+
static Pointer_type*
make_pointer_type(Type*);
@@ -1896,6 +1903,23 @@ class Function_type : public Type
Btype* fnbtype_;
};
+// The type of a function's backend representation.
+
+class Backend_function_type : public Function_type
+{
+ public:
+ Backend_function_type(Typed_identifier* receiver,
+ Typed_identifier_list* parameters,
+ Typed_identifier_list* results, Location location)
+ : Function_type(receiver, parameters, results, location)
+ { }
+
+ protected:
+ Btype*
+ do_get_backend(Gogo* gogo)
+ { return this->get_backend_fntype(gogo); }
+};
+
// The type of a pointer.
class Pointer_type : public Type
@@ -2312,17 +2336,17 @@ class Array_type : public Type
array_has_hidden_fields(const Named_type* within, std::string* reason) const
{ return this->element_type_->has_hidden_fields(within, reason); }
- // Return a tree for the pointer to the values in an array.
- tree
- value_pointer_tree(Gogo*, tree array) const;
+ // Return an expression for the pointer to the values in an array.
+ Expression*
+ get_value_pointer(Gogo*, Expression* array) const;
- // Return a tree for the length of an array with this type.
- tree
- length_tree(Gogo*, tree array);
+ // Return an expression for the length of an array with this type.
+ Expression*
+ get_length(Gogo*, Expression* array) const;
- // Return a tree for the capacity of an array with this type.
- tree
- capacity_tree(Gogo*, tree array);
+ // Return an expression for the capacity of an array with this type.
+ Expression*
+ get_capacity(Gogo*, Expression* array) const;
// Import an array type.
static Array_type*