aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2017-07-28 17:42:05 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2017-07-28 17:42:05 +0000
commit97a0928c524753bcebed187fb087862705fcdda3 (patch)
treefa10dc5e6dd7a1545853a515294f4213cdb38e31
parent9de009354e6e6fb7dd0c97186ec6f9b7aa92f3a4 (diff)
downloadgcc-97a0928c524753bcebed187fb087862705fcdda3.zip
gcc-97a0928c524753bcebed187fb087862705fcdda3.tar.gz
gcc-97a0928c524753bcebed187fb087862705fcdda3.tar.bz2
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
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/expressions.cc175
-rw-r--r--gcc/go/gofrontend/expressions.h18
3 files changed, 60 insertions, 135 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index 722c0a1..1c649cb 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 96a0731..79a2f52 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<Temporary_statement*>* temps =
- new std::vector<Temporary_statement*>;
- 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 a144ff4..0c742fd 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<Temporary_statement*>* 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.