diff options
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) |