aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2016-10-10 16:52:09 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2016-10-10 16:52:09 +0000
commit5d8c099edebfe908256c2bd77a0e2b67182b0f57 (patch)
tree6033d9fc6d1e3f5c3019c9b13d28e70655697a67 /gcc
parent40962ac03a869cf7e07e0672c0a649371896277b (diff)
downloadgcc-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/MERGE2
-rw-r--r--gcc/go/gofrontend/escape.cc4
-rw-r--r--gcc/go/gofrontend/expressions.cc38
-rw-r--r--gcc/go/gofrontend/runtime.def19
-rw-r--r--gcc/go/gofrontend/statements.cc62
-rw-r--r--gcc/go/gofrontend/types.cc47
-rw-r--r--gcc/go/gofrontend/types.h3
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)