Use backend interface for send statement.
authorIan Lance Taylor <ian@gcc.gnu.org>
Fri, 15 Apr 2011 20:53:04 +0000 (20:53 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Fri, 15 Apr 2011 20:53:04 +0000 (20:53 +0000)
From-SVN: r172519

gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/gogo-tree.cc
gcc/go/gofrontend/gogo.h
gcc/go/gofrontend/statements.cc

index 6e1461852a93c5921f79b53d7513c693484bbac9..5b72c6a0661ff4549c84a961acf8ab76a8623dcf 100644 (file)
@@ -3622,6 +3622,16 @@ Unsafe_type_conversion_expression::do_get_tree(Translate_context* context)
                 && et->interface_type()->is_empty());
       use_view_convert = true;
     }
+  else if (t->integer_type() != NULL)
+    {
+      gcc_assert(et->is_boolean_type()
+                || et->integer_type() != NULL
+                || et->function_type() != NULL
+                || et->points_to() != NULL
+                || et->map_type() != NULL
+                || et->channel_type() != NULL);
+      return convert_to_integer(type_tree, expr_tree);
+    }
   else
     gcc_unreachable();
 
index 1cf36dd731eebd25d3735ac0df15dd59165ce06e..ea4663953d8cd85fd6a409e232e8aea2257e2f57 100644 (file)
@@ -2764,144 +2764,6 @@ Gogo::runtime_error(int code, source_location location)
   return ret;
 }
 
-// Send VAL on CHANNEL.  If BLOCKING is true, the resulting tree has a
-// void type.  If BLOCKING is false, the resulting tree has a boolean
-// type, and it will evaluate as true if the value was sent.  If
-// FOR_SELECT is true, this is being done because it was chosen in a
-// select statement.
-
-tree
-Gogo::send_on_channel(tree channel, tree val, bool blocking, bool for_select,
-                     source_location location)
-{
-  if (channel == error_mark_node || val == error_mark_node)
-    return error_mark_node;
-
-  if (int_size_in_bytes(TREE_TYPE(val)) <= 8
-      && !AGGREGATE_TYPE_P(TREE_TYPE(val))
-      && !FLOAT_TYPE_P(TREE_TYPE(val)))
-    {
-      val = convert_to_integer(uint64_type_node, val);
-      if (blocking)
-       {
-         static tree send_small_fndecl;
-         tree ret = Gogo::call_builtin(&send_small_fndecl,
-                                       location,
-                                       "__go_send_small",
-                                       3,
-                                       void_type_node,
-                                       ptr_type_node,
-                                       channel,
-                                       uint64_type_node,
-                                       val,
-                                       boolean_type_node,
-                                       (for_select
-                                        ? boolean_true_node
-                                        : boolean_false_node));
-         if (ret == error_mark_node)
-           return error_mark_node;
-         // This can panic if there are too many operations on a
-         // closed channel.
-         TREE_NOTHROW(send_small_fndecl) = 0;
-         return ret;
-       }
-      else
-       {
-         gcc_assert(!for_select);
-         static tree send_nonblocking_small_fndecl;
-         tree ret = Gogo::call_builtin(&send_nonblocking_small_fndecl,
-                                       location,
-                                       "__go_send_nonblocking_small",
-                                       2,
-                                       boolean_type_node,
-                                       ptr_type_node,
-                                       channel,
-                                       uint64_type_node,
-                                       val);
-         if (ret == error_mark_node)
-           return error_mark_node;
-         // This can panic if there are too many operations on a
-         // closed channel.
-         TREE_NOTHROW(send_nonblocking_small_fndecl) = 0;
-         return ret;
-       }
-    }
-  else
-    {
-      tree make_tmp;
-      if (TREE_ADDRESSABLE(TREE_TYPE(val)) || TREE_CODE(val) == VAR_DECL)
-       {
-         make_tmp = NULL_TREE;
-         val = build_fold_addr_expr(val);
-         if (DECL_P(val))
-           TREE_ADDRESSABLE(val) = 1;
-       }
-      else
-       {
-         tree tmp = create_tmp_var(TREE_TYPE(val), get_name(val));
-         DECL_IGNORED_P(tmp) = 0;
-         DECL_INITIAL(tmp) = val;
-         TREE_ADDRESSABLE(tmp) = 1;
-         make_tmp = build1(DECL_EXPR, void_type_node, tmp);
-         SET_EXPR_LOCATION(make_tmp, location);
-         val = build_fold_addr_expr(tmp);
-       }
-      val = fold_convert(ptr_type_node, val);
-
-      tree call;
-      if (blocking)
-       {
-         static tree send_big_fndecl;
-         call = Gogo::call_builtin(&send_big_fndecl,
-                                   location,
-                                   "__go_send_big",
-                                   3,
-                                   void_type_node,
-                                   ptr_type_node,
-                                   channel,
-                                   ptr_type_node,
-                                   val,
-                                   boolean_type_node,
-                                   (for_select
-                                    ? boolean_true_node
-                                    : boolean_false_node));
-         if (call == error_mark_node)
-           return error_mark_node;
-         // This can panic if there are too many operations on a
-         // closed channel.
-         TREE_NOTHROW(send_big_fndecl) = 0;
-       }
-      else
-       {
-         gcc_assert(!for_select);
-         static tree send_nonblocking_big_fndecl;
-         call = Gogo::call_builtin(&send_nonblocking_big_fndecl,
-                                   location,
-                                   "__go_send_nonblocking_big",
-                                   2,
-                                   boolean_type_node,
-                                   ptr_type_node,
-                                   channel,
-                                   ptr_type_node,
-                                   val);
-         if (call == error_mark_node)
-           return error_mark_node;
-         // This can panic if there are too many operations on a
-         // closed channel.
-         TREE_NOTHROW(send_nonblocking_big_fndecl) = 0;
-       }
-
-      if (make_tmp == NULL_TREE)
-       return call;
-      else
-       {
-         tree ret = build2(COMPOUND_EXPR, TREE_TYPE(call), make_tmp, call);
-         SET_EXPR_LOCATION(ret, location);
-         return ret;
-       }
-    }
-}
-
 // Return a tree for receiving a value of type TYPE_TREE on CHANNEL.
 // This does a blocking receive and returns the value read from the
 // channel.  If FOR_SELECT is true, this is being done because it was
index f958b9c58ccc493703d491e0c2b5bd4a638b9aa1..b622d049e0569a879876b8789321d2d5df7ab06f 100644 (file)
@@ -526,11 +526,6 @@ class Gogo
   tree
   go_string_constant_tree(const std::string&);
 
-  // Send a value on a channel.
-  static tree
-  send_on_channel(tree channel, tree val, bool blocking, bool for_select,
-                 source_location);
-
   // Receive a value from a channel.
   static tree
   receive_from_channel(tree type_tree, tree channel, bool for_select,
index 0774b83af93e523279aaa250fcdf3369489a0561..4875ed71f6979dc1c96ff08041b5c1af1ba8ca08 100644 (file)
@@ -3779,18 +3779,109 @@ Send_statement::do_check_types(Gogo*)
 tree
 Send_statement::do_get_tree(Translate_context* context)
 {
-  tree channel = this->channel_->get_tree(context);
-  tree val = this->val_->get_tree(context);
-  if (channel == error_mark_node || val == error_mark_node)
-    return error_mark_node;
+  source_location loc = this->location();
+
   Channel_type* channel_type = this->channel_->type()->channel_type();
-  val = Expression::convert_for_assignment(context,
-                                          channel_type->element_type(),
-                                          this->val_->type(),
-                                          val,
-                                          this->location());
-  return Gogo::send_on_channel(channel, val, true, this->for_select_,
-                              this->location());
+  Type* element_type = channel_type->element_type();
+  Expression* val = Expression::make_cast(element_type, this->val_, loc);
+
+  bool is_small;
+  bool can_take_address;
+  switch (element_type->base()->classification())
+    {
+    case Type::TYPE_BOOLEAN:
+    case Type::TYPE_INTEGER:
+    case Type::TYPE_FUNCTION:
+    case Type::TYPE_POINTER:
+    case Type::TYPE_MAP:
+    case Type::TYPE_CHANNEL:
+      is_small = true;
+      can_take_address = false;
+      break;
+
+    case Type::TYPE_FLOAT:
+    case Type::TYPE_COMPLEX:
+    case Type::TYPE_STRING:
+    case Type::TYPE_INTERFACE:
+      is_small = false;
+      can_take_address = false;
+      break;
+
+    case Type::TYPE_STRUCT:
+      is_small = false;
+      can_take_address = true;
+      break;
+
+    case Type::TYPE_ARRAY:
+      is_small = false;
+      can_take_address = !element_type->is_open_array_type();
+      break;
+
+    default:
+    case Type::TYPE_ERROR:
+    case Type::TYPE_VOID:
+    case Type::TYPE_SINK:
+    case Type::TYPE_NIL:
+    case Type::TYPE_NAMED:
+    case Type::TYPE_FORWARD:
+      gcc_assert(saw_errors());
+      return error_mark_node;
+    }
+
+  // Only try to take the address of a variable.  We have already
+  // moved variables to the heap, so this should not cause that to
+  // happen unnecessarily.
+  if (can_take_address
+      && val->var_expression() == NULL
+      && val->temporary_reference_expression() == NULL)
+    can_take_address = false;
+
+  Runtime::Function code;
+  Bstatement* btemp = NULL;
+  Expression* call;
+  if (is_small)
+      {
+       // Type is small enough to handle as uint64.
+       code = Runtime::SEND_SMALL;
+       val = Expression::make_unsafe_cast(Type::lookup_integer_type("uint64"),
+                                          val, loc);
+      }
+  else if (can_take_address)
+    {
+      // Must pass address of value.  The function doesn't change the
+      // value, so just take its address directly.
+      code = Runtime::SEND_BIG;
+      val = Expression::make_unary(OPERATOR_AND, val, loc);
+    }
+  else
+    {
+      // Must pass address of value, but the value is small enough
+      // that it might be in registers.  Copy value into temporary
+      // variable to take address.
+      code = Runtime::SEND_BIG;
+      Temporary_statement* temp = Statement::make_temporary(element_type,
+                                                           val, loc);
+      Expression* ref = Expression::make_temporary_reference(temp, loc);
+      val = Expression::make_unary(OPERATOR_AND, ref, loc);
+      btemp = tree_to_stat(temp->get_tree(context));
+    }
+
+  call = Runtime::make_call(code, loc, 3, this->channel_, val,
+                           Expression::make_boolean(this->for_select_, loc));
+
+  context->gogo()->lower_expression(context->function(), &call);
+  Bexpression* bcall = tree_to_expr(call->get_tree(context));
+  Bstatement* s = context->backend()->expression_statement(bcall);
+
+  if (btemp == NULL)
+    return stat_to_tree(s);
+  else
+    {
+      std::vector<Bstatement*> stats(2);
+      stats[0] = btemp;
+      stats[1] = s;
+      return stat_to_tree(context->backend()->statement_list(stats));
+    }
 }
 
 // Make a send statement.