&& 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();
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
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,
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.