Use backend interface for send statement.
From-SVN: r172519
This commit is contained in:
parent
2ba172e0df
commit
a6de01a6dd
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user