diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2016-10-10 16:52:09 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2016-10-10 16:52:09 +0000 |
commit | 5d8c099edebfe908256c2bd77a0e2b67182b0f57 (patch) | |
tree | 6033d9fc6d1e3f5c3019c9b13d28e70655697a67 /gcc | |
parent | 40962ac03a869cf7e07e0672c0a649371896277b (diff) | |
download | gcc-5d8c099edebfe908256c2bd77a0e2b67182b0f57.zip gcc-5d8c099edebfe908256c2bd77a0e2b67182b0f57.tar.gz gcc-5d8c099edebfe908256c2bd77a0e2b67182b0f57.tar.bz2 |
runtime: copy channel code from Go 1.7 runtime
Change the compiler to use the new routines. Drop the separation of
small and large values when sending on a channel. Allocate the select
struct on the stack. Remove the old C implementation of channels. Adjust
the garbage collector for the new data structure.
Bring in part of the tracing code, enough for the channel code to call.
Bump the permitted number of allocations in one of the tests in
context_test.go. The difference is that now receiving from a channel
allocates a sudog, which the C code used to simply put on the
stack. This will be somewhat better when we port proc.go.
Reviewed-on: https://go-review.googlesource.com/30714
From-SVN: r240941
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/go/gofrontend/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/escape.cc | 4 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 38 | ||||
-rw-r--r-- | gcc/go/gofrontend/runtime.def | 19 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 62 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.cc | 47 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.h | 3 |
7 files changed, 118 insertions, 57 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index dc9e1f4..05752dac 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -2431267d513804a3b1aa71adde9aefba9e3c3c59 +9401e714d690e3907a64ac5c8cd5aed9e28f511b The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/escape.cc b/gcc/go/gofrontend/escape.cc index ba82d80..e0df77d 100644 --- a/gcc/go/gofrontend/escape.cc +++ b/gcc/go/gofrontend/escape.cc @@ -293,7 +293,6 @@ Node::op_format() const break; case Runtime::MAKECHAN: - case Runtime::MAKECHANBIG: case Runtime::MAKEMAP: case Runtime::MAKESLICE1: case Runtime::MAKESLICE2: @@ -1229,7 +1228,6 @@ Escape_analysis_assign::expression(Expression** pexpr) break; case Runtime::MAKECHAN: - case Runtime::MAKECHANBIG: case Runtime::MAKEMAP: case Runtime::MAKESLICE1: case Runtime::MAKESLICE2: @@ -1838,7 +1836,6 @@ Escape_analysis_assign::assign(Node* dst, Node* src) } case Runtime::MAKECHAN: - case Runtime::MAKECHANBIG: case Runtime::MAKEMAP: case Runtime::MAKESLICE1: case Runtime::MAKESLICE2: @@ -2612,7 +2609,6 @@ Escape_analysis_flood::flood(Level level, Node* dst, Node* src, break; case Runtime::MAKECHAN: - case Runtime::MAKECHANBIG: case Runtime::MAKEMAP: case Runtime::MAKESLICE1: case Runtime::MAKESLICE2: diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 343d354..36000ea 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -3604,6 +3604,7 @@ Unsafe_type_conversion_expression::do_get_backend(Translate_context* context) || et->channel_type() != NULL || et->map_type() != NULL || et->function_type() != NULL + || et->integer_type() != NULL || et->is_nil_type()); else if (et->is_unsafe_pointer_type()) go_assert(t->points_to() != NULL); @@ -7077,6 +7078,7 @@ Builtin_call_expression::do_flatten(Gogo*, Named_object*, break; case BUILTIN_LEN: + case BUILTIN_CAP: Expression_list::iterator pa = this->args()->begin(); if (!(*pa)->is_variable() && ((*pa)->type()->map_type() != NULL @@ -7217,10 +7219,7 @@ Builtin_call_expression::lower_make() Expression::make_nil(loc), Expression::make_nil(loc)); else if (is_chan) - call = Runtime::make_call((have_big_args - ? Runtime::MAKECHANBIG - : Runtime::MAKECHAN), - loc, 2, type_arg, len_arg); + call = Runtime::make_call(Runtime::MAKECHAN, loc, 2, type_arg, len_arg); else go_unreachable(); @@ -8300,7 +8299,31 @@ Builtin_call_expression::do_get_backend(Translate_context* context) this->seen_ = false; } else if (arg_type->channel_type() != NULL) - val = Runtime::make_call(Runtime::CHAN_CAP, location, 1, arg); + { + // The second field is the capacity. If the pointer + // is nil, the capacity is zero. + Type* uintptr_type = Type::lookup_integer_type("uintptr"); + Type* pint_type = Type::make_pointer_type(int_type); + Expression* parg = Expression::make_unsafe_cast(uintptr_type, + arg, + location); + int off = int_type->integer_type()->bits() / 8; + Expression* eoff = Expression::make_integer_ul(off, + uintptr_type, + location); + parg = Expression::make_binary(OPERATOR_PLUS, parg, eoff, + location); + parg = Expression::make_unsafe_cast(pint_type, parg, location); + Expression* nil = Expression::make_nil(location); + nil = Expression::make_cast(pint_type, nil, location); + Expression* cmp = Expression::make_binary(OPERATOR_EQEQ, + arg, nil, location); + Expression* zero = Expression::make_integer_ul(0, int_type, + location); + Expression* indir = Expression::make_unary(OPERATOR_MULT, + parg, location); + val = Expression::make_conditional(cmp, zero, indir, location); + } else go_unreachable(); } @@ -13729,9 +13752,8 @@ Receive_expression::do_get_backend(Translate_context* context) Expression* recv_addr = Expression::make_temporary_reference(this->temp_receiver_, loc); recv_addr = Expression::make_unary(OPERATOR_AND, recv_addr, loc); - Expression* recv = - Runtime::make_call(Runtime::RECEIVE, loc, 3, - td, this->channel_, recv_addr); + Expression* recv = Runtime::make_call(Runtime::CHANRECV1, loc, 3, + td, this->channel_, recv_addr); return Expression::make_compound(recv, recv_ref, loc)->get_backend(context); } diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def index 2be772b..168f473 100644 --- a/gcc/go/gofrontend/runtime.def +++ b/gcc/go/gofrontend/runtime.def @@ -127,20 +127,13 @@ DEF_GO_RUNTIME(MAPITERNEXT, "runtime.mapiternext", P1(POINTER), R0()) // Make a channel. -DEF_GO_RUNTIME(MAKECHAN, "__go_new_channel", P2(TYPE, UINTPTR), R1(CHAN)) -DEF_GO_RUNTIME(MAKECHANBIG, "__go_new_channel_big", P2(TYPE, UINT64), R1(CHAN)) +DEF_GO_RUNTIME(MAKECHAN, "runtime.makechan", P2(TYPE, INT64), R1(CHAN)) -// Get the capacity of a channel (the size of the buffer). -DEF_GO_RUNTIME(CHAN_CAP, "__go_chan_cap", P1(CHAN), R1(INT)) - -// Send a small value on a channel. -DEF_GO_RUNTIME(SEND_SMALL, "__go_send_small", P3(TYPE, CHAN, UINT64), R0()) - -// Send a big value on a channel. -DEF_GO_RUNTIME(SEND_BIG, "__go_send_big", P3(TYPE, CHAN, POINTER), R0()) +// Send a value on a channel. +DEF_GO_RUNTIME(CHANSEND, "runtime.chansend1", P3(TYPE, CHAN, POINTER), R0()) // Receive a value from a channel. -DEF_GO_RUNTIME(RECEIVE, "__go_receive", P3(TYPE, CHAN, POINTER), R0()) +DEF_GO_RUNTIME(CHANRECV1, "runtime.chanrecv1", P3(TYPE, CHAN, POINTER), R0()) // Receive a value from a channel returning whether it is closed. DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P3(TYPE, CHAN, POINTER), @@ -148,7 +141,7 @@ DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P3(TYPE, CHAN, POINTER), // Start building a select statement. -DEF_GO_RUNTIME(NEWSELECT, "runtime.newselect", P1(INT32), R1(POINTER)) +DEF_GO_RUNTIME(NEWSELECT, "runtime.newselect", P3(POINTER, INT64, INT32), R0()) // Add a default clause to a select statement. DEF_GO_RUNTIME(SELECTDEFAULT, "runtime.selectdefault", @@ -202,7 +195,7 @@ DEF_GO_RUNTIME(RUNTIME_ERROR, "__go_runtime_error", P1(INT32), R0()) // Close. -DEF_GO_RUNTIME(CLOSE, "__go_builtin_close", P1(CHAN), R0()) +DEF_GO_RUNTIME(CLOSE, "runtime.closechan", P1(CHAN), R0()) // Copy. diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index 2eb363a..41f1ffb 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -4330,7 +4330,6 @@ Send_statement::do_get_backend(Translate_context* context) element_type, this->val_, loc); - bool is_small; bool can_take_address; switch (element_type->base()->classification()) { @@ -4340,25 +4339,18 @@ Send_statement::do_get_backend(Translate_context* context) 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_slice_type(); break; @@ -4384,28 +4376,19 @@ Send_statement::do_get_backend(Translate_context* context) Expression* td = Expression::make_type_descriptor(this->channel_->type(), loc); - Runtime::Function code; Bstatement* btemp = NULL; - 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; + if (can_take_address) + { + // The function doesn't change the value, so just take its + // address directly. 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; + // The value is not in a variable, or is small enough that it + // might be in a register, and taking the address would push it + // on the stack. Copy it into a temporary variable to take the + // address. Temporary_statement* temp = Statement::make_temporary(element_type, val, loc); Expression* ref = Expression::make_temporary_reference(temp, loc); @@ -4413,7 +4396,8 @@ Send_statement::do_get_backend(Translate_context* context) btemp = temp->get_backend(context); } - Expression* call = Runtime::make_call(code, loc, 3, td, this->channel_, val); + Expression* call = Runtime::make_call(Runtime::CHANSEND, loc, 3, td, + this->channel_, val); context->gogo()->lower_expression(context->function(), NULL, &call); Bexpression* bcall = call->get_backend(context); @@ -4491,6 +4475,7 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function, Location loc = this->location_; Expression* selref = Expression::make_temporary_reference(sel, loc); + selref = Expression::make_unary(OPERATOR_AND, selref, loc); Expression* index_expr = Expression::make_integer_ul(this->index_, NULL, loc); @@ -4854,6 +4839,7 @@ Select_clauses::get_backend(Translate_context* context, } Expression* selref = Expression::make_temporary_reference(sel, location); + selref = Expression::make_unary(OPERATOR_AND, selref, location); Expression* call = Runtime::make_call(Runtime::SELECTGO, location, 1, selref); context->gogo()->lower_expression(context->function(), NULL, &call); @@ -4920,13 +4906,27 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function, go_assert(this->sel_ == NULL); - Expression* size_expr = Expression::make_integer_ul(this->clauses_->size(), - NULL, loc); - Expression* call = Runtime::make_call(Runtime::NEWSELECT, loc, 1, size_expr); - - this->sel_ = Statement::make_temporary(NULL, call, loc); + int ncases = this->clauses_->size(); + Type* selstruct_type = Channel_type::select_type(ncases); + this->sel_ = Statement::make_temporary(selstruct_type, NULL, loc); b->add_statement(this->sel_); + int64_t selstruct_size; + if (!selstruct_type->backend_type_size(gogo, &selstruct_size)) + { + go_assert(saw_errors()); + return Statement::make_error_statement(loc); + } + + Expression* ref = Expression::make_temporary_reference(this->sel_, loc); + ref = Expression::make_unary(OPERATOR_AND, ref, loc); + Expression* selstruct_size_expr = + Expression::make_integer_int64(selstruct_size, NULL, loc); + Expression* size_expr = Expression::make_integer_ul(ncases, NULL, loc); + Expression* call = Runtime::make_call(Runtime::NEWSELECT, loc, 3, + ref, selstruct_size_expr, size_expr); + b->add_statement(Statement::make_statement(call, true)); + this->clauses_->lower(gogo, function, b, this->sel_); this->is_lowered_ = true; b->add_statement(this); diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 01af8f3..38613bb 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -7771,6 +7771,53 @@ Channel_type::do_import(Import* imp) return Type::make_channel_type(may_send, may_receive, element_type); } +// Return the type to manage a select statement with ncases case +// statements. A value of this type is allocated on the stack. This +// must match the type hselect in libgo/go/runtime/select.go. + +Type* +Channel_type::select_type(int ncases) +{ + Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type()); + Type* uint16_type = Type::lookup_integer_type("uint16"); + + static Struct_type* scase_type; + if (scase_type == NULL) + { + Type* uintptr_type = Type::lookup_integer_type("uintptr"); + Type* uint64_type = Type::lookup_integer_type("uint64"); + scase_type = + Type::make_builtin_struct_type(7, + "elem", unsafe_pointer_type, + "chan", unsafe_pointer_type, + "pc", uintptr_type, + "kind", uint16_type, + "index", uint16_type, + "receivedp", unsafe_pointer_type, + "releasetime", uint64_type); + scase_type->set_is_struct_incomparable(); + } + + Expression* ncases_expr = + Expression::make_integer_ul(ncases, NULL, Linemap::predeclared_location()); + Array_type* scases = Type::make_array_type(scase_type, ncases_expr); + scases->set_is_array_incomparable(); + Array_type* order = Type::make_array_type(uint16_type, ncases_expr); + order->set_is_array_incomparable(); + + Struct_type* ret = + Type::make_builtin_struct_type(7, + "tcase", uint16_type, + "ncase", uint16_type, + "pollorder", unsafe_pointer_type, + "lockorder", unsafe_pointer_type, + "scase", scases, + "lockorderarr", order, + "pollorderarr", order); + ret->set_is_struct_incomparable(); + return ret; +} + // Make a new channel type. Channel_type* diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index 3d9a3c4..58d60e5 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -2809,6 +2809,9 @@ class Channel_type : public Type static Type* make_chan_type_descriptor_type(); + static Type* + select_type(int ncases); + protected: int do_traverse(Traverse* traverse) |