diff options
-rw-r--r-- | gcc/go/gofrontend/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 136 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 5 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 6 | ||||
-rw-r--r-- | gcc/go/gofrontend/wb.cc | 4 |
6 files changed, 99 insertions, 56 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 5b45f03..58c881a 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -93380a9126e76b71fa208e62c31c7914084c0e37 +bf35249a7c752836741b1cab43a312f87916fcb0 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 17b4cfd..101cbe7 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -526,7 +526,7 @@ Expression::convert_interface_to_interface(Type *lhs_type, Expression* rhs, // method table. // We are going to evaluate RHS multiple times. - go_assert(rhs->is_variable()); + go_assert(rhs->is_multi_eval_safe()); // Get the type descriptor for the right hand side. This will be // NULL for a nil interface. @@ -569,7 +569,7 @@ Expression::convert_interface_to_type(Gogo* gogo, Type *lhs_type, Expression* rh Location location) { // We are going to evaluate RHS multiple times. - go_assert(rhs->is_variable()); + go_assert(rhs->is_multi_eval_safe()); // Build an expression to check that the type is valid. It will // panic with an appropriate runtime type error if the type is not @@ -707,8 +707,8 @@ Expression::check_bounds(Expression* val, Operator op, Expression* bound, Statement_inserter* inserter, Location loc) { - go_assert(val->is_variable() || val->is_constant()); - go_assert(bound->is_variable() || bound->is_constant()); + go_assert(val->is_multi_eval_safe()); + go_assert(bound->is_multi_eval_safe()); Type* int_type = Type::lookup_integer_type("int"); int int_type_size = int_type->integer_type()->bits(); @@ -3976,7 +3976,7 @@ Type_conversion_expression::do_flatten(Gogo*, Named_object*, if (((this->type()->is_string_type() && this->expr_->type()->is_slice_type()) || this->expr_->type()->interface_type() != NULL) - && !this->expr_->is_variable()) + && !this->expr_->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, this->expr_, this->location()); @@ -4264,7 +4264,7 @@ Type_conversion_expression::do_get_backend(Translate_context* context) Array_type* a = expr_type->array_type(); Type* e = a->element_type()->forwarded(); go_assert(e->integer_type() != NULL); - go_assert(this->expr_->is_variable()); + go_assert(this->expr_->is_multi_eval_safe()); Expression* buf; if (this->no_escape_ && !this->no_copy_) @@ -4711,7 +4711,7 @@ Unary_expression::do_flatten(Gogo* gogo, Named_object*, Location location = this->location(); if (this->op_ == OPERATOR_MULT - && !this->expr_->is_variable()) + && !this->expr_->is_multi_eval_safe()) { go_assert(this->expr_->type()->points_to() != NULL); switch (this->requires_nil_check(gogo)) @@ -4731,7 +4731,7 @@ Unary_expression::do_flatten(Gogo* gogo, Named_object*, } } - if (this->create_temp_ && !this->expr_->is_variable()) + if (this->create_temp_ && !this->expr_->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, this->expr_, location); @@ -5326,7 +5326,7 @@ Unary_expression::do_get_backend(Translate_context* context) bexpr = gogo->backend()->var_expression(decl, loc); } - go_assert(!this->create_temp_ || this->expr_->is_variable()); + go_assert(!this->create_temp_ || this->expr_->is_multi_eval_safe()); ret = gogo->backend()->address_expression(bexpr, loc); break; @@ -5347,7 +5347,7 @@ Unary_expression::do_get_backend(Translate_context* context) } case NIL_CHECK_NEEDED: { - go_assert(this->expr_->is_variable()); + go_assert(this->expr_->is_multi_eval_safe()); // If we're nil-checking the result of a set-and-use-temporary // expression, then pick out the target temp and use that @@ -6496,13 +6496,13 @@ Binary_expression::do_flatten(Gogo* gogo, Named_object*, && (gogo->check_divide_by_zero() || gogo->check_divide_overflow())) || is_string_op) { - if (!this->left_->is_variable() && !this->left_->is_constant()) + if (!this->left_->is_multi_eval_safe()) { temp = Statement::make_temporary(NULL, this->left_, loc); inserter->insert(temp); this->left_ = Expression::make_temporary_reference(temp, loc); } - if (!this->right_->is_variable() && !this->right_->is_constant()) + if (!this->right_->is_multi_eval_safe()) { temp = Statement::make_temporary(NULL, this->right_, loc); @@ -7478,8 +7478,8 @@ Expression::comparison(Translate_context* context, Type* result_type, if (left_type->is_string_type() && right_type->is_string_type()) { - go_assert(left->is_variable() || left->is_constant()); - go_assert(right->is_variable() || right->is_constant()); + go_assert(left->is_multi_eval_safe()); + go_assert(right->is_multi_eval_safe()); if (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ) { @@ -8078,7 +8078,7 @@ Bound_method_expression::do_flatten(Gogo* gogo, Named_object*, // we are going to do nil checks below, but it's easy enough to // always do it. Expression* expr = this->expr_; - if (!expr->is_variable()) + if (!expr->is_multi_eval_safe()) { Temporary_statement* etemp = Statement::make_temporary(NULL, expr, loc); inserter->insert(etemp); @@ -8419,7 +8419,7 @@ Builtin_call_expression::do_lower(Gogo*, Named_object* function, pa != this->args()->end(); ++pa) { - if (!(*pa)->is_variable() && !(*pa)->is_constant()) + if (!(*pa)->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, *pa, loc); @@ -8470,7 +8470,7 @@ Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function, Expression* zero = Expression::make_integer_ul(0, NULL, loc); *pa = Expression::make_slice_value(at, nil, zero, zero, loc); } - if (!(*pa)->is_variable()) + if (!(*pa)->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, *pa, loc); @@ -8484,8 +8484,8 @@ Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function, go_assert(args != NULL && args->size() == 2); Expression* arg1 = args->front(); Expression* arg2 = args->back(); - go_assert(arg1->is_variable()); - go_assert(arg2->is_variable()); + go_assert(arg1->is_multi_eval_safe()); + go_assert(arg2->is_multi_eval_safe()); bool arg2_is_string = arg2->type()->is_string_type(); Expression* ret; @@ -8573,7 +8573,8 @@ Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function, pa != this->args()->end(); ++pa) { - if (!(*pa)->is_variable() && (*pa)->type()->interface_type() != NULL) + if (!(*pa)->is_multi_eval_safe() + && (*pa)->type()->interface_type() != NULL) { Temporary_statement* temp = Statement::make_temporary(NULL, *pa, loc); @@ -8587,7 +8588,7 @@ Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function, case BUILTIN_CAP: { Expression_list::iterator pa = this->args()->begin(); - if (!(*pa)->is_variable() + if (!(*pa)->is_multi_eval_safe() && ((*pa)->type()->map_type() != NULL || (*pa)->type()->channel_type() != NULL)) { @@ -9024,7 +9025,7 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function, Expression_list::const_iterator pa = args->begin(); for (++pa; pa != args->end(); ++pa) { - if ((*pa)->is_variable()) + if ((*pa)->is_multi_eval_safe()) add->push_back(*pa); else { @@ -11235,7 +11236,7 @@ Call_expression::do_flatten(Gogo* gogo, Named_object*, { Location loc = (*pa)->location(); Expression* arg = *pa; - if (!arg->is_variable()) + if (!arg->is_multi_eval_safe()) { Temporary_statement *temp = Statement::make_temporary(NULL, arg, loc); @@ -11457,7 +11458,7 @@ Call_expression::intrinsify(Gogo* gogo, && this->args_ != NULL && this->args_->size() == 1) { Expression* arg = this->args_->front(); - if (!arg->is_variable()) + if (!arg->is_multi_eval_safe()) { Temporary_statement* ts = Statement::make_temporary(uint32_type, arg, loc); inserter->insert(ts); @@ -11476,7 +11477,7 @@ Call_expression::intrinsify(Gogo* gogo, && this->args_ != NULL && this->args_->size() == 1) { Expression* arg = this->args_->front(); - if (!arg->is_variable()) + if (!arg->is_multi_eval_safe()) { Temporary_statement* ts = Statement::make_temporary(uint64_type, arg, loc); inserter->insert(ts); @@ -11526,7 +11527,7 @@ Call_expression::intrinsify(Gogo* gogo, && this->args_ != NULL && this->args_->size() == 1) { Expression* arg = this->args_->front(); - if (!arg->is_variable()) + if (!arg->is_multi_eval_safe()) { Temporary_statement* ts = Statement::make_temporary(uint32_type, arg, loc); inserter->insert(ts); @@ -11549,7 +11550,7 @@ Call_expression::intrinsify(Gogo* gogo, && this->args_ != NULL && this->args_->size() == 1) { Expression* arg = this->args_->front(); - if (!arg->is_variable()) + if (!arg->is_multi_eval_safe()) { Temporary_statement* ts = Statement::make_temporary(uint64_type, arg, loc); inserter->insert(ts); @@ -13087,14 +13088,14 @@ Array_index_expression::do_flatten(Gogo* gogo, Named_object*, } Temporary_statement* temp; - if (array_type->is_slice_type() && !array->is_variable()) + if (array_type->is_slice_type() && !array->is_multi_eval_safe()) { temp = Statement::make_temporary(NULL, array, loc); inserter->insert(temp); this->array_ = Expression::make_temporary_reference(temp, loc); array = this->array_; } - if (!start->is_variable() && !start->is_constant()) + if (!start->is_multi_eval_safe()) { temp = Statement::make_temporary(NULL, start, loc); inserter->insert(temp); @@ -13103,15 +13104,14 @@ Array_index_expression::do_flatten(Gogo* gogo, Named_object*, } if (end != NULL && !end->is_nil_expression() - && !end->is_variable() - && !end->is_constant()) + && !end->is_multi_eval_safe()) { temp = Statement::make_temporary(NULL, end, loc); inserter->insert(temp); this->end_ = Expression::make_temporary_reference(temp, loc); end = this->end_; } - if (cap != NULL && !cap->is_variable() && !cap->is_constant()) + if (cap != NULL && !cap->is_multi_eval_safe()) { temp = Statement::make_temporary(NULL, cap, loc); inserter->insert(temp); @@ -13270,7 +13270,8 @@ Array_index_expression::do_get_backend(Translate_context* context) go_assert(this->array_->type()->is_error()); return context->backend()->error_expression(); } - go_assert(!array_type->is_slice_type() || this->array_->is_variable()); + go_assert(!array_type->is_slice_type() + || this->array_->is_multi_eval_safe()); Location loc = this->location(); Gogo* gogo = context->gogo(); @@ -13484,14 +13485,14 @@ String_index_expression::do_flatten(Gogo*, Named_object*, } Temporary_statement* temp; - if (!string->is_variable()) + if (!string->is_multi_eval_safe()) { temp = Statement::make_temporary(NULL, string, loc); inserter->insert(temp); this->string_ = Expression::make_temporary_reference(temp, loc); string = this->string_; } - if (!start->is_variable()) + if (!start->is_multi_eval_safe()) { temp = Statement::make_temporary(NULL, start, loc); inserter->insert(temp); @@ -13500,7 +13501,7 @@ String_index_expression::do_flatten(Gogo*, Named_object*, } if (end != NULL && !end->is_nil_expression() - && !end->is_variable()) + && !end->is_multi_eval_safe()) { temp = Statement::make_temporary(NULL, end, loc); inserter->insert(temp); @@ -13659,8 +13660,8 @@ String_index_expression::do_get_backend(Translate_context* context) return context->backend()->error_expression(); } - go_assert(this->string_->is_variable()); - go_assert(this->start_->is_variable()); + go_assert(this->string_->is_multi_eval_safe()); + go_assert(this->start_->is_multi_eval_safe()); Expression* start = Expression::make_cast(int_type, this->start_, loc); Bfunction* bfn = context->function()->func_value()->get_decl(); @@ -13685,7 +13686,7 @@ String_index_expression::do_get_backend(Translate_context* context) end = length; else { - go_assert(this->end_->is_variable()); + go_assert(this->end_->is_multi_eval_safe()); end = Expression::make_cast(int_type, this->end_, loc); } @@ -13815,7 +13816,7 @@ Map_index_expression::do_flatten(Gogo* gogo, Named_object*, NULL)) { if (this->index_->type()->interface_type() != NULL - && !this->index_->is_variable()) + && !this->index_->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, this->index_, loc); @@ -13826,7 +13827,7 @@ Map_index_expression::do_flatten(Gogo* gogo, Named_object*, this->index_, loc); } - if (!this->index_->is_variable()) + if (!this->index_->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, this->index_, loc); @@ -13839,7 +13840,7 @@ Map_index_expression::do_flatten(Gogo* gogo, Named_object*, if (this->value_pointer_->is_error_expression() || this->value_pointer_->type()->is_error_type()) return Expression::make_error(loc); - if (!this->value_pointer_->is_variable()) + if (!this->value_pointer_->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, this->value_pointer_, loc); @@ -13923,7 +13924,7 @@ Map_index_expression::do_get_backend(Translate_context* context) } go_assert(this->value_pointer_ != NULL - && this->value_pointer_->is_variable()); + && this->value_pointer_->is_multi_eval_safe()); Expression* val = Expression::make_dereference(this->value_pointer_, NIL_CHECK_NOT_NEEDED, @@ -14268,7 +14269,7 @@ Interface_field_reference_expression::do_flatten(Gogo*, Named_object*, return Expression::make_error(this->location()); } - if (!this->expr_->is_variable()) + if (!this->expr_->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, this->expr_, this->location()); @@ -15165,7 +15166,7 @@ Struct_construction_expression::do_flatten(Gogo*, Named_object*, go_assert(saw_errors()); return Expression::make_error(loc); } - if (!(*pv)->is_variable()) + if (!(*pv)->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, *pv, loc); @@ -15471,7 +15472,7 @@ Array_construction_expression::do_flatten(Gogo*, Named_object*, go_assert(saw_errors()); return Expression::make_error(loc); } - if (!(*pv)->is_variable()) + if (!(*pv)->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, *pv, loc); @@ -15914,7 +15915,8 @@ Map_construction_expression::do_flatten(Gogo* gogo, Named_object*, go_assert(saw_errors()); return Expression::make_error(loc); } - if (key->type()->interface_type() != NULL && !key->is_variable()) + if (key->type()->interface_type() != NULL + && !key->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, key, loc); @@ -15930,7 +15932,8 @@ Map_construction_expression::do_flatten(Gogo* gogo, Named_object*, go_assert(saw_errors()); return Expression::make_error(loc); } - if (val->type()->interface_type() != NULL && !val->is_variable()) + if (val->type()->interface_type() != NULL + && !val->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, val, loc); @@ -17037,6 +17040,41 @@ Expression::is_local_variable() const || (no->is_variable() && !no->var_value()->is_global())); } +// Return true if multiple evaluations are OK. + +bool +Expression::is_multi_eval_safe() +{ + switch (this->classification_) + { + case EXPRESSION_VAR_REFERENCE: + { + // A variable is a simple reference if not stored in the heap. + const Named_object* no = this->var_expression()->named_object(); + if (no->is_variable()) + return !no->var_value()->is_in_heap(); + else if (no->is_result_variable()) + return !no->result_var_value()->is_in_heap(); + else + go_unreachable(); + } + + case EXPRESSION_TEMPORARY_REFERENCE: + return true; + + default: + break; + } + + if (!this->is_constant()) + return false; + + // Only numeric and boolean constants are really multi-evaluation + // safe. We don't want multiple copies of string constants. + Type* type = this->type(); + return type->is_numeric_type() || type->is_boolean_type(); +} + const Named_object* Expression::named_constant() const { @@ -17070,7 +17108,7 @@ Type_guard_expression::do_flatten(Gogo*, Named_object*, return Expression::make_error(this->location()); } - if (!this->expr_->is_variable()) + if (!this->expr_->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, this->expr_, this->location()); diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 712f687..e3747cc 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -916,6 +916,11 @@ class Expression bool is_local_variable() const; + // Return true if multiple evaluations of this expression are OK. + // This is true for simple variable references and constants. + bool + is_multi_eval_safe(); + // Return true if two expressions refer to the same variable or // struct field. static bool diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 9d4150e..93b54fd 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -7579,7 +7579,7 @@ Variable::flatten_init_expression(Gogo* gogo, Named_object* function, Type::COMPARE_ERRORS | Type::COMPARE_TAGS, NULL) && this->init_->type()->interface_type() != NULL - && !this->init_->is_variable()) + && !this->init_->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, this->init_, this->location_); diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index da0e084..7ad7339 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -588,7 +588,7 @@ Temporary_statement::do_flatten(Gogo*, Named_object*, Block*, Type::COMPARE_ERRORS | Type::COMPARE_TAGS, NULL) && this->init_->type()->interface_type() != NULL - && !this->init_->is_variable()) + && !this->init_->is_multi_eval_safe()) { Temporary_statement *temp = Statement::make_temporary(NULL, this->init_, this->location()); @@ -1125,7 +1125,7 @@ Assignment_statement::do_flatten(Gogo*, Named_object*, Block*, Type::COMPARE_ERRORS | Type::COMPARE_TAGS, NULL) && this->rhs_->type()->interface_type() != NULL - && !this->rhs_->is_variable()) + && !this->rhs_->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, this->rhs_, this->location()); @@ -5116,7 +5116,7 @@ Send_statement::do_flatten(Gogo*, Named_object*, Block*, Type::COMPARE_ERRORS | Type::COMPARE_TAGS, NULL) && this->val_->type()->interface_type() != NULL - && !this->val_->is_variable()) + && !this->val_->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, this->val_, this->location()); diff --git a/gcc/go/gofrontend/wb.cc b/gcc/go/gofrontend/wb.cc index ac1f0a1..104c5db 100644 --- a/gcc/go/gofrontend/wb.cc +++ b/gcc/go/gofrontend/wb.cc @@ -883,7 +883,7 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing, Type::COMPARE_ERRORS | Type::COMPARE_TAGS, NULL) && rhs->type()->interface_type() != NULL - && !rhs->is_variable()) + && !rhs->is_multi_eval_safe()) { // May need a temporary for interface conversion. Temporary_statement* temp = Statement::make_temporary(NULL, rhs, loc); @@ -892,7 +892,7 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing, } rhs = Expression::convert_for_assignment(this, type, rhs, loc); Temporary_statement* rhs_temp = NULL; - if (!rhs->is_variable() && !rhs->is_constant()) + if (!rhs->is_multi_eval_safe()) { rhs_temp = Statement::make_temporary(NULL, rhs, loc); inserter->insert(rhs_temp); |