diff mbox

Go patch committed: Use a single temporary for a call with multiple results

Message ID CAOyqgcX36YPd3uc7-AjZbSwgjGJtAfsW-_D5RmREbhwZ3P7vUw@mail.gmail.com
State New
Headers show

Commit Message

Ian Lance Taylor July 28, 2017, 5:42 p.m. UTC
In the Go frontend, 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.

This patch simplifies 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.

Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu.  Committed
to mainline.

Ian
diff mbox

Patch

Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE	(revision 250588)
+++ gcc/go/gofrontend/MERGE	(working copy)
@@ -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.
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc	(revision 250406)
+++ gcc/go/gofrontend/expressions.cc	(working copy)
@@ -9463,24 +9463,28 @@  Call_expression::do_lower(Gogo* gogo, Na
 				       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)
-    {
-      std::vector<Temporary_statement*>* temps =
-	new std::vector<Temporary_statement*>;
-      temps->reserve(rc);
+  // variable to hold them.
+  if (this->result_count() > 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)
-	{
-	  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,
       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_functi
 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(Translat
     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,89 +10316,26 @@  Call_expression::do_get_backend(Translat
                                                        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->call_ = this->set_results(context);
-
-      Bexpression* set_and_call =
-          gogo->backend()->compound_expression(assn_stmt, this->call_,
-                                               location);
-      return set_and_call;
-    }
-
-  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();
+      // This case occurs when the call returns multiple results.
 
-  Bexpression* results = NULL;
-  Location loc = this->location();
+      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);
 
-  go_assert(this->call_temp_ != NULL);
+      ref = Expression::make_temporary_reference(this->call_temp_, location);
+      this->call_ = ref->get_backend(context);
 
-  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 gogo->backend()->compound_expression(bassn, this->call_,
+						  location);
     }
-  return results;
+
+  this->call_ = call;
+  return this->call_;
 }
 
 // Dump ast representation for a call expressin.
@@ -10528,13 +10458,14 @@  Call_result_expression::do_get_backend(T
       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);
 }
 
Index: gcc/go/gofrontend/expressions.h
===================================================================
--- gcc/go/gofrontend/expressions.h	(revision 250406)
+++ gcc/go/gofrontend/expressions.h	(working copy)
@@ -2115,8 +2115,8 @@  class Call_expression : public Expressio
   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 Expressio
   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 Expressio
   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 Expressio
   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.