From a6de01a6ddfb5bab044091548df0f868bc208646 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 15 Apr 2011 20:53:04 +0000 Subject: [PATCH] Use backend interface for send statement. From-SVN: r172519 --- gcc/go/gofrontend/expressions.cc | 10 +++ gcc/go/gofrontend/gogo-tree.cc | 138 ------------------------------- gcc/go/gofrontend/gogo.h | 5 -- gcc/go/gofrontend/statements.cc | 113 ++++++++++++++++++++++--- 4 files changed, 112 insertions(+), 154 deletions(-) diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 6e1461852a9..5b72c6a0661 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -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(); diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc index 1cf36dd731e..ea4663953d8 100644 --- a/gcc/go/gofrontend/gogo-tree.cc +++ b/gcc/go/gofrontend/gogo-tree.cc @@ -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 diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index f958b9c58cc..b622d049e05 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -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, diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index 0774b83af93..4875ed71f69 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -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 stats(2); + stats[0] = btemp; + stats[1] = s; + return stat_to_tree(context->backend()->statement_list(stats)); + } } // Make a send statement. -- 2.30.2