This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[gccgo] Lower tuple receive statements
- From: Ian Lance Taylor <iant at google dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sat, 16 Jan 2010 19:43:34 -0800
- Subject: [gccgo] Lower tuple receive statements
I committed this patch to lower tuple receive statements, which look
like v, present = <-c.
Ian
Index: libgo/runtime/chan.cgo
===================================================================
--- libgo/runtime/chan.cgo (revision 0)
+++ libgo/runtime/chan.cgo (revision 0)
@@ -0,0 +1,38 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+#include "config.h"
+#include "channel.h"
+
+typedef _Bool bool;
+typedef unsigned char byte;
+typedef struct __go_channel chan;
+
+/* Do a nonblocking channel receive. */
+
+func chanrecv2(c *chan, val *byte) (pres bool) {
+ if (c->element_size > 8) {
+ return __go_receive_nonblocking_big(c, val);
+ } else {
+ struct __go_receive_nonblocking_small rs;
+ union {
+ char b[8];
+ uint64_t v;
+ } u;
+
+ rs = __go_receive_nonblocking_small (c);
+ if (!rs.__success) {
+ return 0;
+ }
+ u.v = rs.__val;
+#ifndef WORDS_BIGENDIAN
+ __builtin_memcpy(val, u.b, c->element_size);
+#else
+ __builtin_memcpy(val, u.b + 8 - c->element_size,
+ c->element_size);
+#endif
+ return 1;
+ }
+}
Index: libgo/Makefile.am
===================================================================
--- libgo/Makefile.am (revision 155929)
+++ libgo/Makefile.am (working copy)
@@ -310,6 +310,7 @@ runtime_files = \
runtime/msize.c \
runtime/proc.c \
malloc_go.c \
+ chan.c \
map.c \
sigqueue.c \
string.c
Index: gcc/go/statements.cc
===================================================================
--- gcc/go/statements.cc (revision 155952)
+++ gcc/go/statements.cc (working copy)
@@ -1227,16 +1227,15 @@ class Tuple_receive_assignment_statement
do_traverse(Traverse* traverse);
bool
- do_traverse_assignments(Traverse_assignments*);
+ do_traverse_assignments(Traverse_assignments*)
+ { gcc_unreachable(); }
- void
- do_determine_types();
-
- void
- do_check_types(Gogo*);
+ Statement*
+ do_lower(Gogo*, Block*);
tree
- do_get_tree(Translate_context*);
+ do_get_tree(Translate_context*)
+ { gcc_unreachable(); }
private:
// Lvalue which receives the value from the channel.
@@ -1258,155 +1257,85 @@ Tuple_receive_assignment_statement::do_t
return this->traverse_expression(traverse, &this->channel_);
}
-bool
-Tuple_receive_assignment_statement::do_traverse_assignments(
- Traverse_assignments* tassign)
-{
- tassign->assignment(&this->val_, NULL);
- tassign->assignment(&this->success_, NULL);
- tassign->value(&this->channel_, false, this->val_->is_local_variable());
- return true;
-}
+// Lower to a function call.
-// Set types if necessary.
-
-void
-Tuple_receive_assignment_statement::do_determine_types()
+Statement*
+Tuple_receive_assignment_statement::do_lower(Gogo*, Block* enclosing)
{
- this->channel_->determine_type_no_context();
- Type* type = this->channel_->type();
- Channel_type* channel_type = type->channel_type();
-
- Type_context subcontext1((channel_type != NULL
- ? channel_type->element_type()
- : NULL),
- false);
- this->val_->determine_type(&subcontext1);
-
- Type_context subcontext2(Type::lookup_bool_type(), false);
- this->success_->determine_type(&subcontext2);
-}
-
-// Check types.
+ source_location loc = this->location();
-void
-Tuple_receive_assignment_statement::do_check_types(Gogo*)
-{
- Type* type = this->channel_->type();
- if (type->channel_type() == NULL)
+ Channel_type* channel_type = this->channel_->type()->channel_type();
+ if (channel_type == NULL)
{
this->report_error(_("expected channel"));
- return;
+ return Statement::make_error_statement(loc);
}
- if (!type->channel_type()->may_receive())
+ if (!channel_type->may_receive())
{
this->report_error(_("invalid receive on send-only channel"));
- return;
- }
-
- if (!this->val_->is_lvalue() || !this->success_->is_lvalue())
- {
- this->report_error(_("invalid left hand side of assignment"));
- return;
+ return Statement::make_error_statement(loc);
}
- std::string reason;
- if (!Type::are_compatible_for_assign(this->val_->type(),
- type->channel_type()->element_type(),
- &reason))
- {
- if (reason.empty())
- error_at(this->val_->location(),
- "incompatible types for variable and channel");
- else
- error_at(this->val_->location(),
- "incompatible types for variable and channel (%s)",
- reason.c_str());
- this->set_is_error();
- }
+ Block* b = new Block(enclosing, loc);
- if (!Type::are_compatible_for_assign(this->success_->type(),
- Type::lookup_bool_type(),
- &reason))
- {
- if (reason.empty())
- error_at(this->success_->location(), "incompatible type for receive");
- else
- error_at(this->success_->location(),
- "incompatible type for receive (%s)",
- reason.c_str());
- this->set_is_error();
- }
-}
+ // Make sure that any subexpressions on the left hand side are
+ // evaluated in the right order.
+ Move_ordered_evals moe(b);
+ this->val_->traverse_subexpressions(&moe);
+ this->success_->traverse_subexpressions(&moe);
-// Get a tree for a nonblocking receive statement.
+ // var val_temp ELEMENT_TYPE
+ Temporary_statement* val_temp =
+ Statement::make_temporary(channel_type->element_type(), NULL, loc);
+ b->add_statement(val_temp);
-tree
-Tuple_receive_assignment_statement::do_get_tree(Translate_context* context)
-{
- Gogo* gogo = context->gogo();
+ // var success_temp bool
+ Temporary_statement* success_temp =
+ Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
+ b->add_statement(success_temp);
- Channel_type* channel_type = this->channel_->type()->channel_type();
- gcc_assert(channel_type != NULL);
- Type* element_type = channel_type->element_type();
- tree element_type_tree = element_type->get_tree(gogo);
+ // func chanrecv2(c chan T, val *T) bool
+ source_location bloc = BUILTINS_LOCATION;
+ Typed_identifier_list* param_types = new Typed_identifier_list();
+ param_types->push_back(Typed_identifier("c", channel_type, bloc));
+ Type* pelement_type = Type::make_pointer_type(channel_type->element_type());
+ param_types->push_back(Typed_identifier("val", pelement_type, bloc));
+
+ Typed_identifier_list* ret_types = new Typed_identifier_list();
+ ret_types->push_back(Typed_identifier("", Type::lookup_bool_type(), bloc));
+
+ Function_type* fntype = Type::make_function_type(NULL, param_types,
+ ret_types, bloc);
+ Named_object* chanrecv2 =
+ Named_object::make_function_declaration("chanrecv2", NULL, fntype, bloc);
+ chanrecv2->func_declaration_value()->set_asm_name("runtime.chanrecv2");
- tree stmt_list = NULL_TREE;
+ // success_temp = chanrecv2(channel, &val_temp)
+ Expression* func = Expression::make_func_reference(chanrecv2, NULL, loc);
+ Expression_list* params = new Expression_list();
+ params->push_back(this->channel_);
+ Expression* ref = Expression::make_temporary_reference(val_temp, loc);
+ params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
+ Expression* call = Expression::make_call(func, params, loc);
+ ref = Expression::make_temporary_reference(success_temp, loc);
+ Statement* s = Statement::make_assignment(OPERATOR_EQ, ref, call, loc);
+ b->add_statement(s);
- tree channel_tree = this->channel_->get_tree(context);
- if (element_type_tree == error_mark_node || channel_tree == error_mark_node)
- return error_mark_node;
+ // if success_temp { val = val_temp }
+ Block* then_block = new Block(b, loc);
+ ref = Expression::make_temporary_reference(val_temp, loc);
+ s = Statement::make_assignment(OPERATOR_EQ, this->val_, ref, loc);
+ then_block->add_statement(s);
+ ref = Expression::make_temporary_reference(success_temp, loc);
+ s = Statement::make_if_statement(ref, then_block, NULL, loc);
+ b->add_statement(s);
- tree val_success = Gogo::receive_from_channel(element_type_tree,
- channel_tree, false, false,
- this->location());
- val_success = save_expr(val_success);
-
- // VAL_SUCCESS is a struct. The first field is the value. The
- // second field is whether the receive succeeded.
- tree val_field = TYPE_FIELDS(TREE_TYPE(val_success));
- tree success_field = TREE_CHAIN(val_field);
- gcc_assert(TREE_TYPE(success_field) == boolean_type_node);
-
- tree success = build3(COMPONENT_REF, boolean_type_node, val_success,
- success_field, NULL_TREE);
-
- tree set_success =
- Assignment_statement::get_assignment_tree(context, OPERATOR_EQ,
- this->success_, NULL_TREE,
- NULL,
- Type::lookup_bool_type(),
- success,
- this->location());
- append_to_statement_list(set_success, &stmt_list);
-
- tree val_rhs = build3(COMPONENT_REF, TREE_TYPE(val_field), val_success,
- val_field, NULL_TREE);
-
- tree val_type_tree = this->val_->type()->get_tree(gogo);
-
- // FIXME: Duplicates Gogo::receive_from_channel.
- if (int_size_in_bytes(element_type_tree) <= 8
- && !AGGREGATE_TYPE_P(element_type_tree))
- {
- int bitsize = GET_MODE_BITSIZE(TYPE_MODE(val_type_tree));
- tree int_type_tree = go_type_for_size(bitsize, 1);
- val_rhs = fold_convert_loc(this->location(), int_type_tree, val_rhs);
- }
-
- val_rhs = fold_convert_loc(this->location(), val_type_tree, val_rhs);
- tree sval = Assignment_statement::get_assignment_tree(context,
- OPERATOR_EQ,
- this->val_,
- NULL_TREE,
- NULL,
- element_type,
- val_rhs,
- this->location());
- tree cmove = build3(COND_EXPR, void_type_node, success, sval, NULL_TREE);
- append_to_statement_list(cmove, &stmt_list);
+ // success = success_temp
+ ref = Expression::make_temporary_reference(success_temp, loc);
+ s = Statement::make_assignment(OPERATOR_EQ, this->success_, ref, loc);
+ b->add_statement(s);
- return stmt_list;
+ return Statement::make_block_statement(b, loc);
}
// Make a nonblocking receive statement.
Index: gcc/go/statements.h
===================================================================
--- gcc/go/statements.h (revision 155952)
+++ gcc/go/statements.h (working copy)
@@ -91,7 +91,6 @@ class Statement
STATEMENT_TEMPORARY,
STATEMENT_DESTROY_TEMPORARY,
STATEMENT_ASSIGNMENT,
- STATEMENT_TUPLE_RECEIVE_ASSIGNMENT,
STATEMENT_TUPLE_TYPE_GUARD_ASSIGNMENT,
STATEMENT_EXPRESSION,
STATEMENT_BLOCK,
@@ -115,6 +114,7 @@ class Statement
STATEMENT_TUPLE_ASSIGNMENT,
STATEMENT_TUPLE_MAP_ASSIGNMENT,
STATEMENT_MAP_ASSIGNMENT,
+ STATEMENT_TUPLE_RECEIVE_ASSIGNMENT,
STATEMENT_FOR,
STATEMENT_FOR_RANGE
};