From 97a0928c524753bcebed187fb087862705fcdda3 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 28 Jul 2017 17:42:05 +0000 Subject: [PATCH] compiler: use a single temporary for calls with multiple results For calls that return multiple results we used to create a temporary of struct type to hold the results, and also create a separate temporary for each result. Then the call expression would copy each result out of the struct to the temporary, and Call_result_expression would refer to the desired temporary. Simplify this to just use a single temporary of struct type, and change Call_result_expression to fetch a field of the struct. This may reduce some incorrect tree sharing in the backend code. Reviewed-on: https://go-review.googlesource.com/51770 From-SVN: r250682 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 175 ++++++++++--------------------- gcc/go/gofrontend/expressions.h | 18 ++-- 3 files changed, 60 insertions(+), 135 deletions(-) diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 722c0a1ab06..1c649cb6ca9 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -feb26fbb5065eadfe1f8610e9b74b3749a87c52d +27804ec53590e3644e030c9860822139a0cfb03f 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 96a0731c222..79a2f524aa7 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -9463,24 +9463,28 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, this->is_varargs_, loc); // If this call returns multiple results, create a temporary - // variable for each result. - size_t rc = this->result_count(); - if (rc > 1 && this->results_ == NULL) + // variable to hold them. + if (this->result_count() > 1 && this->call_temp_ == NULL) { - std::vector* temps = - new std::vector; - temps->reserve(rc); + Struct_field_list* sfl = new Struct_field_list(); + Function_type* fntype = this->get_function_type(); const Typed_identifier_list* results = fntype->results(); + Location loc = this->location(); + + int i = 0; + char buf[20]; for (Typed_identifier_list::const_iterator p = results->begin(); - p != results->end(); - ++p) - { - Temporary_statement* temp = Statement::make_temporary(p->type(), - NULL, loc); - inserter->insert(temp); - temps->push_back(temp); - } - this->results_ = temps; + p != results->end(); + ++p, ++i) + { + snprintf(buf, sizeof buf, "res%d", i); + sfl->push_back(Struct_field(Typed_identifier(buf, p->type(), loc))); + } + + Struct_type* st = Type::make_struct_type(sfl, loc); + st->set_is_struct_incomparable(); + this->call_temp_ = Statement::make_temporary(st, NULL, loc); + inserter->insert(this->call_temp_); } // Handle a call to a varargs function by packaging up the extra @@ -9779,30 +9783,6 @@ Call_expression::do_flatten(Gogo* gogo, Named_object*, this->args_ = args; } - size_t rc = this->result_count(); - if (rc > 1 && this->call_temp_ == NULL) - { - Struct_field_list* sfl = new Struct_field_list(); - Function_type* fntype = this->get_function_type(); - const Typed_identifier_list* results = fntype->results(); - Location loc = this->location(); - - int i = 0; - char buf[20]; - for (Typed_identifier_list::const_iterator p = results->begin(); - p != results->end(); - ++p, ++i) - { - snprintf(buf, sizeof buf, "res%d", i); - sfl->push_back(Struct_field(Typed_identifier(buf, p->type(), loc))); - } - - Struct_type* st = Type::make_struct_type(sfl, loc); - st->set_is_struct_incomparable(); - this->call_temp_ = Statement::make_temporary(st, NULL, loc); - inserter->insert(this->call_temp_); - } - return this; } @@ -9827,17 +9807,18 @@ Call_expression::result_count() const return fntype->results()->size(); } -// Return the temporary which holds a result. +// Return the temporary that holds the result for a call with multiple +// results. Temporary_statement* -Call_expression::result(size_t i) const +Call_expression::results() const { - if (this->results_ == NULL || this->results_->size() <= i) + if (this->call_temp_ == NULL) { go_assert(saw_errors()); return NULL; } - return (*this->results_)[i]; + return this->call_temp_; } // Set the number of results expected from a call expression. @@ -10191,8 +10172,21 @@ Call_expression::interface_method_function( Bexpression* Call_expression::do_get_backend(Translate_context* context) { + Location location = this->location(); + if (this->call_ != NULL) - return this->call_; + { + // If the call returns multiple results, make a new reference to + // the temporary. + if (this->call_temp_ != NULL) + { + Expression* ref = + Expression::make_temporary_reference(this->call_temp_, location); + return ref->get_backend(context); + } + + return this->call_; + } Function_type* fntype = this->get_function_type(); if (fntype == NULL) @@ -10202,7 +10196,6 @@ Call_expression::do_get_backend(Translate_context* context) return context->backend()->error_expression(); Gogo* gogo = context->gogo(); - Location location = this->location(); Func_expression* func = this->fn_->func_expression(); Interface_field_reference_expression* interface_method = @@ -10323,91 +10316,28 @@ Call_expression::do_get_backend(Translate_context* context) fn_args, bclosure, location); - if (this->results_ != NULL) + if (this->call_temp_ != NULL) { - Bexpression* bcall_ref = this->call_result_ref(context); - Bstatement* assn_stmt = - gogo->backend()->assignment_statement(bfunction, - bcall_ref, call, location); + // This case occurs when the call returns multiple results. - this->call_ = this->set_results(context); + Expression* ref = Expression::make_temporary_reference(this->call_temp_, + location); + Bexpression* bref = ref->get_backend(context); + Bstatement* bassn = gogo->backend()->assignment_statement(bfunction, + bref, call, + location); - Bexpression* set_and_call = - gogo->backend()->compound_expression(assn_stmt, this->call_, - location); - return set_and_call; + ref = Expression::make_temporary_reference(this->call_temp_, location); + this->call_ = ref->get_backend(context); + + return gogo->backend()->compound_expression(bassn, this->call_, + location); } this->call_ = call; return this->call_; } -// Return the backend representation of a reference to the struct used -// to capture the result of a multiple-output call. - -Bexpression* -Call_expression::call_result_ref(Translate_context* context) -{ - go_assert(this->call_temp_ != NULL); - Location location = this->location(); - Expression* call_ref = - Expression::make_temporary_reference(this->call_temp_, location); - Bexpression* bcall_ref = call_ref->get_backend(context); - return bcall_ref; -} - -// Set the result variables if this call returns multiple results. - -Bexpression* -Call_expression::set_results(Translate_context* context) -{ - Gogo* gogo = context->gogo(); - - Bexpression* results = NULL; - Location loc = this->location(); - - go_assert(this->call_temp_ != NULL); - - size_t rc = this->result_count(); - for (size_t i = 0; i < rc; ++i) - { - Temporary_statement* temp = this->result(i); - if (temp == NULL) - { - go_assert(saw_errors()); - return gogo->backend()->error_expression(); - } - Temporary_reference_expression* ref = - Expression::make_temporary_reference(temp, loc); - ref->set_is_lvalue(); - - Bfunction* bfunction = context->function()->func_value()->get_decl(); - Bexpression* result_ref = ref->get_backend(context); - Bexpression* bcall_ref = this->call_result_ref(context); - Bexpression* call_result = - gogo->backend()->struct_field_expression(bcall_ref, i, loc); - Bstatement* assn_stmt = - gogo->backend()->assignment_statement(bfunction, - result_ref, call_result, loc); - - bcall_ref = this->call_result_ref(context); - call_result = gogo->backend()->struct_field_expression(bcall_ref, i, loc); - Bexpression* result = - gogo->backend()->compound_expression(assn_stmt, call_result, loc); - - if (results == NULL) - results = result; - else - { - Bstatement* expr_stmt = - gogo->backend()->expression_statement(bfunction, result); - results = - gogo->backend()->compound_expression(expr_stmt, results, loc); - } - } - return results; -} - // Dump ast representation for a call expressin. void @@ -10528,13 +10458,14 @@ Call_result_expression::do_get_backend(Translate_context* context) go_assert(this->call_->is_error_expression()); return context->backend()->error_expression(); } - Temporary_statement* ts = ce->result(this->index_); + Temporary_statement* ts = ce->results(); if (ts == NULL) { go_assert(saw_errors()); return context->backend()->error_expression(); } Expression* ref = Expression::make_temporary_reference(ts, this->location()); + ref = Expression::make_field_reference(ref, this->index_, this->location()); return ref->get_backend(context); } diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index a144ff4168b..0c742fd92df 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -2115,8 +2115,8 @@ class Call_expression : public Expression Call_expression(Expression* fn, Expression_list* args, bool is_varargs, Location location) : Expression(EXPRESSION_CALL, location), - fn_(fn), args_(args), type_(NULL), results_(NULL), call_(NULL), - call_temp_(NULL), expected_result_count_(0), is_varargs_(is_varargs), + fn_(fn), args_(args), type_(NULL), call_(NULL), call_temp_(NULL) + , expected_result_count_(0), is_varargs_(is_varargs), varargs_are_lowered_(false), types_are_determined_(false), is_deferred_(false), is_concurrent_(false), issued_error_(false), is_multi_value_arg_(false), is_flattened_(false) @@ -2144,11 +2144,11 @@ class Call_expression : public Expression size_t result_count() const; - // Return the temporary variable which holds result I. This is only - // valid after the expression has been lowered, and is only valid - // for calls which return multiple results. + // Return the temporary variable that holds the results. This is + // only valid after the expression has been lowered, and is only + // valid for calls which return multiple results. Temporary_statement* - result(size_t i) const; + results() const; // Set the number of results expected from this call. This is used // when the call appears in a context that expects multiple results, @@ -2292,9 +2292,6 @@ class Call_expression : public Expression Bexpression* set_results(Translate_context*); - Bexpression* - call_result_ref(Translate_context* context); - // The function to call. Expression* fn_; // The arguments to pass. This may be NULL if there are no @@ -2302,9 +2299,6 @@ class Call_expression : public Expression Expression_list* args_; // The type of the expression, to avoid recomputing it. Type* type_; - // The list of temporaries which will hold the results if the - // function returns a tuple. - std::vector* results_; // The backend expression for the call, used for a call which returns a tuple. Bexpression* call_; // A temporary variable to store this call if the function returns a tuple. -- 2.30.2