compiler: use a single temporary for calls with multiple results
authorIan Lance Taylor <ian@gcc.gnu.org>
Fri, 28 Jul 2017 17:42:05 +0000 (17:42 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Fri, 28 Jul 2017 17:42:05 +0000 (17:42 +0000)
    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
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/expressions.h

index 722c0a1ab063011e0600c552e1027a34bcebdd83..1c649cb6ca95e4716d213bf67530e2dcfcd5c876 100644 (file)
@@ -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 96a0731c222ce122adc340545ea09d828b7685e9..79a2f524aa734568c9163e196e05facc825ec3ac 100644 (file)
@@ -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);
 }
 
index a144ff4168ba22375dc3fc9142547cad2467a630..0c742fd92dfff6e11149427a41e00287db1ccdda 100644 (file)
@@ -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.