aboutsummaryrefslogtreecommitdiff
path: root/gcc/go
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/go')
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/runtime.def4
-rw-r--r--gcc/go/gofrontend/statements.cc131
-rw-r--r--gcc/go/gofrontend/statements.h48
-rw-r--r--gcc/go/gofrontend/types.cc7
5 files changed, 129 insertions, 63 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index bb537f1..c70b60c 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-eca96e39cb895805b617e0e1f184f893ed3e46bb
+d091cd25a5894ac751fe1868197648fc486cf322
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/runtime.def b/gcc/go/gofrontend/runtime.def
index 4b606a6..7ab94a3 100644
--- a/gcc/go/gofrontend/runtime.def
+++ b/gcc/go/gofrontend/runtime.def
@@ -195,8 +195,8 @@ DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P2(CHAN, POINTER), R1(BOOL))
// Run a select, returning the index of the selected clause and
// whether that channel received a value.
-DEF_GO_RUNTIME(SELECTGO, "runtime.selectgo", P3(POINTER, POINTER, INT),
- R2(INT, BOOL))
+DEF_GO_RUNTIME(SELECTGO, "runtime.selectgo",
+ P5(POINTER, POINTER, INT, INT, BOOL), R2(INT, BOOL))
// Non-blocking send a value on a channel, used for two-case select
// statement with a default case.
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index 398b8fd..da0e084 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -5291,22 +5291,23 @@ Select_clauses::Select_clause::traverse(Traverse* traverse)
void
Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
Block* b, Temporary_statement* scases,
- size_t index, Temporary_statement* recvok)
+ int index, Temporary_statement* recvok)
{
Location loc = this->location_;
- Expression* scase = Expression::make_temporary_reference(scases, loc);
- Expression* index_expr = Expression::make_integer_ul(index, NULL, loc);
- scase = Expression::make_array_index(scase, index_expr, NULL, NULL, loc);
+ this->set_case_index(index);
if (this->is_default_)
{
go_assert(this->channel_ == NULL && this->val_ == NULL);
- this->lower_default(b, scase);
this->is_lowered_ = true;
return;
}
+ Expression* scase = Expression::make_temporary_reference(scases, loc);
+ Expression* index_expr = Expression::make_integer_sl(index, NULL, loc);
+ scase = Expression::make_array_index(scase, index_expr, NULL, NULL, loc);
+
// Evaluate the channel before the select statement.
Temporary_statement* channel_temp = Statement::make_temporary(NULL,
this->channel_,
@@ -5326,15 +5327,6 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
this->val_ = NULL;
}
-// Lower a default clause in a select statement.
-
-void
-Select_clauses::Select_clause::lower_default(Block* b, Expression* scase)
-{
- Location loc = this->location_;
- this->set_case(b, scase, Expression::make_nil(loc), NULL, caseDefault);
-}
-
// Lower a send clause in a select statement.
void
@@ -5366,7 +5358,7 @@ Select_clauses::Select_clause::lower_send(Block* b, Expression* scase,
Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type());
valaddr = Expression::make_cast(unsafe_pointer_type, valaddr, loc);
- this->set_case(b, scase, chanref, valaddr, caseSend);
+ this->set_case(b, scase, chanref, valaddr);
}
// Lower a receive clause in a select statement.
@@ -5392,7 +5384,7 @@ Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function,
Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type());
valaddr = Expression::make_cast(unsafe_pointer_type, valaddr, loc);
- this->set_case(b, scase, chanref, valaddr, caseRecv);
+ this->set_case(b, scase, chanref, valaddr);
// If the block of statements is executed, arrange for the received
// value to move from VAL to the place where the statements expect
@@ -5447,8 +5439,7 @@ void
Select_clauses::Select_clause::set_case(Block* b,
Expression* scase,
Expression* chanref,
- Expression* elem,
- int kind)
+ Expression* elem)
{
Location loc = this->location_;
Struct_type* scase_type = scase->type()->struct_type();
@@ -5469,14 +5460,6 @@ Select_clauses::Select_clause::set_case(Block* b,
s = Statement::make_assignment(ref, elem, loc);
b->add_statement(s);
}
-
- field_index = 2;
- go_assert(scase_type->field(field_index)->is_field_name("kind"));
- Type* uint16_type = Type::lookup_integer_type("uint16");
- Expression* k = Expression::make_integer_ul(kind, uint16_type, loc);
- ref = Expression::make_field_reference(scase->copy(), field_index, loc);
- s = Statement::make_assignment(ref, k, loc);
- b->add_statement(s);
}
// Determine types.
@@ -5577,6 +5560,19 @@ Select_clauses::Select_clause::dump_clause(
// Class Select_clauses.
+// Whether there is a default case.
+
+bool
+Select_clauses::has_default() const
+{
+ for (Clauses::const_iterator p = this->clauses_.begin();
+ p != this->clauses_.end();
+ ++p)
+ if (p->is_default())
+ return true;
+ return false;
+}
+
// Traversal.
int
@@ -5594,17 +5590,60 @@ Select_clauses::traverse(Traverse* traverse)
// Lowering. Here we pull out the channel and the send values, to
// enforce the order of evaluation. We also add explicit send and
-// receive statements to the clauses.
+// receive statements to the clauses. This builds the entries in the
+// local array of scase values. It sets *P_SEND_COUNT and
+// *P_RECV_COUNT.
void
Select_clauses::lower(Gogo* gogo, Named_object* function, Block* b,
- Temporary_statement* scases, Temporary_statement* recvok)
+ Temporary_statement* scases, Temporary_statement* recvok,
+ int *p_send_count, int *p_recv_count)
{
- size_t i = 0;
+ int send_count = 0;
+ int recv_count = 0;
+ bool has_default = false;
for (Clauses::iterator p = this->clauses_.begin();
p != this->clauses_.end();
- ++p, ++i)
- p->lower(gogo, function, b, scases, i, recvok);
+ ++p)
+ {
+ if (p->is_default())
+ has_default = true;
+ else if (p->is_send())
+ ++send_count;
+ else
+ ++recv_count;
+ }
+
+ *p_send_count = send_count;
+ *p_recv_count = recv_count;
+
+ int send_index = 0;
+ int recv_index = send_count;
+ for (Clauses::iterator p = this->clauses_.begin();
+ p != this->clauses_.end();
+ ++p)
+ {
+ int index;
+ if (p->is_default())
+ index = -1;
+ else if (p->is_send())
+ {
+ index = send_index;
+ ++send_index;
+ }
+ else
+ {
+ index = recv_index;
+ ++recv_index;
+ }
+
+ p->lower(gogo, function, b, scases, index, recvok);
+ }
+
+ go_assert(send_index == send_count);
+ go_assert(recv_index == send_count + recv_count);
+ go_assert(static_cast<size_t>(recv_index + (has_default ? 1 : 0))
+ == this->size());
}
// Determine types.
@@ -5664,7 +5703,8 @@ Select_clauses::get_backend(Translate_context* context,
p != this->clauses_.end();
++p, ++i)
{
- Expression* index_expr = Expression::make_integer_ul(i, int_type,
+ Expression* index_expr = Expression::make_integer_sl(p->case_index(),
+ int_type,
location);
cases[i].push_back(index_expr->get_backend(context));
@@ -5749,6 +5789,7 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function,
Block* b = new Block(enclosing, loc);
int ncases = this->clauses_->size();
+ bool has_default = this->clauses_->has_default();
// Zero-case select. Just block the execution.
if (ncases == 0)
@@ -5766,11 +5807,13 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function,
// Two-case select with one default case. It is a non-blocking
// send/receive.
- if (ncases == 2
- && (this->clauses_->at(0).is_default()
- || this->clauses_->at(1).is_default()))
+ if (ncases == 2 && has_default)
return this->lower_two_case(b);
+ // We don't allocate an entry in scases for the default case.
+ if (has_default)
+ --ncases;
+
Type* scase_type = Channel_type::select_case_type();
Expression* ncases_expr =
Expression::make_integer_ul(ncases, NULL,
@@ -5803,7 +5846,10 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function,
b->add_statement(recvok);
// Initialize the scases array.
- this->clauses_->lower(gogo, function, b, scases, recvok);
+ int send_count;
+ int recv_count;
+ this->clauses_->lower(gogo, function, b, scases, recvok, &send_count,
+ &recv_count);
// Build the call to selectgo. Later, in do_get_backend, we will
// build a switch on the result that branches to the various cases.
@@ -5817,11 +5863,18 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function,
order_ref = Expression::make_unary(OPERATOR_AND, order_ref, loc);
order_ref = Expression::make_cast(unsafe_pointer_type, order_ref, loc);
- Expression* count_expr = Expression::make_integer_ul(ncases, int_type, loc);
+ Expression* send_count_expr = Expression::make_integer_sl(send_count,
+ int_type,
+ loc);
+ Expression* recv_count_expr = Expression::make_integer_sl(recv_count,
+ int_type,
+ loc);
+ Expression* block_expr = Expression::make_boolean(!has_default, loc);
- Call_expression* call = Runtime::make_call(Runtime::SELECTGO, loc, 3,
+ Call_expression* call = Runtime::make_call(Runtime::SELECTGO, loc, 5,
scases_ref, order_ref,
- count_expr);
+ send_count_expr, recv_count_expr,
+ block_expr);
Expression* result = Expression::make_call_result(call, 0);
Expression* ref = Expression::make_temporary_reference(this->index_, loc);
diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h
index 47092b4..c08b493 100644
--- a/gcc/go/gofrontend/statements.h
+++ b/gcc/go/gofrontend/statements.h
@@ -1092,6 +1092,9 @@ class Select_clauses
size() const
{ return this->clauses_.size(); }
+ bool
+ has_default() const;
+
// Traverse the select clauses.
int
traverse(Traverse*);
@@ -1099,7 +1102,7 @@ class Select_clauses
// Lower statements.
void
lower(Gogo*, Named_object*, Block*, Temporary_statement*,
- Temporary_statement*);
+ Temporary_statement*, int* send_count, int* recv_count);
// Determine types.
void
@@ -1138,8 +1141,9 @@ class Select_clauses
Named_object* closedvar, bool is_default, Block* statements,
Location location)
: channel_(channel), val_(val), closed_(closed), var_(var),
- closedvar_(closedvar), statements_(statements), location_(location),
- is_send_(is_send), is_default_(is_default), is_lowered_(false)
+ closedvar_(closedvar), statements_(statements), case_index_(0),
+ location_(location), is_send_(is_send), is_default_(is_default),
+ is_lowered_(false), is_case_index_set_(false)
{ go_assert(is_default ? channel == NULL : channel != NULL); }
// Traverse the select clause.
@@ -1148,7 +1152,7 @@ class Select_clauses
// Lower statements.
void
- lower(Gogo*, Named_object*, Block*, Temporary_statement*, size_t,
+ lower(Gogo*, Named_object*, Block*, Temporary_statement*, int,
Temporary_statement*);
// Determine types.
@@ -1210,6 +1214,23 @@ class Select_clauses
location() const
{ return this->location_; }
+ // Return the case index for this clause.
+ int
+ case_index() const
+ {
+ go_assert(this->is_case_index_set_);
+ return this->case_index_;
+ }
+
+ // Set the case index.
+ void
+ set_case_index(int i)
+ {
+ go_assert(!this->is_case_index_set_);
+ this->case_index_ = i;
+ this->is_case_index_set_ = true;
+ }
+
// Whether this clause may fall through to the statement which
// follows the overall select statement.
bool
@@ -1224,17 +1245,6 @@ class Select_clauses
dump_clause(Ast_dump_context*) const;
private:
- // These values must match the values in libgo/go/runtime/select.go.
- enum
- {
- caseRecv = 1,
- caseSend = 2,
- caseDefault = 3,
- };
-
- void
- lower_default(Block*, Expression*);
-
void
lower_send(Block*, Expression*, Expression*);
@@ -1243,7 +1253,7 @@ class Select_clauses
Temporary_statement*);
void
- set_case(Block*, Expression*, Expression*, Expression*, int);
+ set_case(Block*, Expression*, Expression*, Expression*);
// The channel.
Expression* channel_;
@@ -1259,6 +1269,10 @@ class Select_clauses
Named_object* closedvar_;
// The statements to execute.
Block* statements_;
+ // The index of this clause in the switch statement. If
+ // runtime.selectgo returns this index, this clause has been
+ // chosen.
+ int case_index_;
// The location of this clause.
Location location_;
// Whether this is a send or a receive.
@@ -1267,6 +1281,8 @@ class Select_clauses
bool is_default_;
// Whether this has been lowered.
bool is_lowered_;
+ // Whether the case index has been set.
+ bool is_case_index_set_;
};
Select_clause&
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index 12e7830..16f0eb5 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -8905,13 +8905,10 @@ Channel_type::select_case_type()
{
Type* unsafe_pointer_type =
Type::make_pointer_type(Type::make_void_type());
- Type* uint16_type = Type::lookup_integer_type("uint16");
- Type* int64_type = Type::lookup_integer_type("int64");
scase_type =
- Type::make_builtin_struct_type(3,
+ Type::make_builtin_struct_type(2,
"c", unsafe_pointer_type,
- "elem", unsafe_pointer_type,
- "kind", uint16_type);
+ "elem", unsafe_pointer_type);
scase_type->set_is_struct_incomparable();
}
return scase_type;