Skip to content

Commit d091cd2

Browse files
runtime: eliminate scase.kind field
This is the gofrontend version of https://golang.org/cl/245125. Original CL description: Currently, we include a "kind" field on scase to distinguish the three kinds of cases in a select statement: sends, receives, and defaults. This commit removes by kind field by instead arranging for the compiler to always place sends before receives, and to provide their counts separately. It also passes an explicit "block bool" parameter to avoid needing to include a default case in the array. It's safe to shuffle cases like this because the runtime will randomize the order they're polled in anyway. For golang/go#40410. This is being brought over to gofrontend as a step toward upgrading to Go1.16beta1. Change-Id: I39a0a83c25e15fbd3cdfac7f31e01df9f2cddd3f Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/279735 Trust: Ian Lance Taylor <iant@golang.org> Reviewed-by: Than McIntosh <thanm@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com>
1 parent eca96e3 commit d091cd2

File tree

5 files changed

+181
-102
lines changed

5 files changed

+181
-102
lines changed

go/runtime.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,8 @@ DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P2(CHAN, POINTER), R1(BOOL))
195195

196196
// Run a select, returning the index of the selected clause and
197197
// whether that channel received a value.
198-
DEF_GO_RUNTIME(SELECTGO, "runtime.selectgo", P3(POINTER, POINTER, INT),
199-
R2(INT, BOOL))
198+
DEF_GO_RUNTIME(SELECTGO, "runtime.selectgo",
199+
P5(POINTER, POINTER, INT, INT, BOOL), R2(INT, BOOL))
200200

201201
// Non-blocking send a value on a channel, used for two-case select
202202
// statement with a default case.

go/statements.cc

Lines changed: 92 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5291,22 +5291,23 @@ Select_clauses::Select_clause::traverse(Traverse* traverse)
52915291
void
52925292
Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
52935293
Block* b, Temporary_statement* scases,
5294-
size_t index, Temporary_statement* recvok)
5294+
int index, Temporary_statement* recvok)
52955295
{
52965296
Location loc = this->location_;
52975297

5298-
Expression* scase = Expression::make_temporary_reference(scases, loc);
5299-
Expression* index_expr = Expression::make_integer_ul(index, NULL, loc);
5300-
scase = Expression::make_array_index(scase, index_expr, NULL, NULL, loc);
5298+
this->set_case_index(index);
53015299

53025300
if (this->is_default_)
53035301
{
53045302
go_assert(this->channel_ == NULL && this->val_ == NULL);
5305-
this->lower_default(b, scase);
53065303
this->is_lowered_ = true;
53075304
return;
53085305
}
53095306

5307+
Expression* scase = Expression::make_temporary_reference(scases, loc);
5308+
Expression* index_expr = Expression::make_integer_sl(index, NULL, loc);
5309+
scase = Expression::make_array_index(scase, index_expr, NULL, NULL, loc);
5310+
53105311
// Evaluate the channel before the select statement.
53115312
Temporary_statement* channel_temp = Statement::make_temporary(NULL,
53125313
this->channel_,
@@ -5326,15 +5327,6 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
53265327
this->val_ = NULL;
53275328
}
53285329

5329-
// Lower a default clause in a select statement.
5330-
5331-
void
5332-
Select_clauses::Select_clause::lower_default(Block* b, Expression* scase)
5333-
{
5334-
Location loc = this->location_;
5335-
this->set_case(b, scase, Expression::make_nil(loc), NULL, caseDefault);
5336-
}
5337-
53385330
// Lower a send clause in a select statement.
53395331

53405332
void
@@ -5366,7 +5358,7 @@ Select_clauses::Select_clause::lower_send(Block* b, Expression* scase,
53665358
Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type());
53675359
valaddr = Expression::make_cast(unsafe_pointer_type, valaddr, loc);
53685360

5369-
this->set_case(b, scase, chanref, valaddr, caseSend);
5361+
this->set_case(b, scase, chanref, valaddr);
53705362
}
53715363

53725364
// Lower a receive clause in a select statement.
@@ -5392,7 +5384,7 @@ Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function,
53925384
Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type());
53935385
valaddr = Expression::make_cast(unsafe_pointer_type, valaddr, loc);
53945386

5395-
this->set_case(b, scase, chanref, valaddr, caseRecv);
5387+
this->set_case(b, scase, chanref, valaddr);
53965388

53975389
// If the block of statements is executed, arrange for the received
53985390
// value to move from VAL to the place where the statements expect
@@ -5447,8 +5439,7 @@ void
54475439
Select_clauses::Select_clause::set_case(Block* b,
54485440
Expression* scase,
54495441
Expression* chanref,
5450-
Expression* elem,
5451-
int kind)
5442+
Expression* elem)
54525443
{
54535444
Location loc = this->location_;
54545445
Struct_type* scase_type = scase->type()->struct_type();
@@ -5469,14 +5460,6 @@ Select_clauses::Select_clause::set_case(Block* b,
54695460
s = Statement::make_assignment(ref, elem, loc);
54705461
b->add_statement(s);
54715462
}
5472-
5473-
field_index = 2;
5474-
go_assert(scase_type->field(field_index)->is_field_name("kind"));
5475-
Type* uint16_type = Type::lookup_integer_type("uint16");
5476-
Expression* k = Expression::make_integer_ul(kind, uint16_type, loc);
5477-
ref = Expression::make_field_reference(scase->copy(), field_index, loc);
5478-
s = Statement::make_assignment(ref, k, loc);
5479-
b->add_statement(s);
54805463
}
54815464

54825465
// Determine types.
@@ -5577,6 +5560,19 @@ Select_clauses::Select_clause::dump_clause(
55775560

55785561
// Class Select_clauses.
55795562

5563+
// Whether there is a default case.
5564+
5565+
bool
5566+
Select_clauses::has_default() const
5567+
{
5568+
for (Clauses::const_iterator p = this->clauses_.begin();
5569+
p != this->clauses_.end();
5570+
++p)
5571+
if (p->is_default())
5572+
return true;
5573+
return false;
5574+
}
5575+
55805576
// Traversal.
55815577

55825578
int
@@ -5594,17 +5590,60 @@ Select_clauses::traverse(Traverse* traverse)
55945590

55955591
// Lowering. Here we pull out the channel and the send values, to
55965592
// enforce the order of evaluation. We also add explicit send and
5597-
// receive statements to the clauses.
5593+
// receive statements to the clauses. This builds the entries in the
5594+
// local array of scase values. It sets *P_SEND_COUNT and
5595+
// *P_RECV_COUNT.
55985596

55995597
void
56005598
Select_clauses::lower(Gogo* gogo, Named_object* function, Block* b,
5601-
Temporary_statement* scases, Temporary_statement* recvok)
5599+
Temporary_statement* scases, Temporary_statement* recvok,
5600+
int *p_send_count, int *p_recv_count)
56025601
{
5603-
size_t i = 0;
5602+
int send_count = 0;
5603+
int recv_count = 0;
5604+
bool has_default = false;
56045605
for (Clauses::iterator p = this->clauses_.begin();
56055606
p != this->clauses_.end();
5606-
++p, ++i)
5607-
p->lower(gogo, function, b, scases, i, recvok);
5607+
++p)
5608+
{
5609+
if (p->is_default())
5610+
has_default = true;
5611+
else if (p->is_send())
5612+
++send_count;
5613+
else
5614+
++recv_count;
5615+
}
5616+
5617+
*p_send_count = send_count;
5618+
*p_recv_count = recv_count;
5619+
5620+
int send_index = 0;
5621+
int recv_index = send_count;
5622+
for (Clauses::iterator p = this->clauses_.begin();
5623+
p != this->clauses_.end();
5624+
++p)
5625+
{
5626+
int index;
5627+
if (p->is_default())
5628+
index = -1;
5629+
else if (p->is_send())
5630+
{
5631+
index = send_index;
5632+
++send_index;
5633+
}
5634+
else
5635+
{
5636+
index = recv_index;
5637+
++recv_index;
5638+
}
5639+
5640+
p->lower(gogo, function, b, scases, index, recvok);
5641+
}
5642+
5643+
go_assert(send_index == send_count);
5644+
go_assert(recv_index == send_count + recv_count);
5645+
go_assert(static_cast<size_t>(recv_index + (has_default ? 1 : 0))
5646+
== this->size());
56085647
}
56095648

56105649
// Determine types.
@@ -5664,7 +5703,8 @@ Select_clauses::get_backend(Translate_context* context,
56645703
p != this->clauses_.end();
56655704
++p, ++i)
56665705
{
5667-
Expression* index_expr = Expression::make_integer_ul(i, int_type,
5706+
Expression* index_expr = Expression::make_integer_sl(p->case_index(),
5707+
int_type,
56685708
location);
56695709
cases[i].push_back(index_expr->get_backend(context));
56705710

@@ -5749,6 +5789,7 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function,
57495789
Block* b = new Block(enclosing, loc);
57505790

57515791
int ncases = this->clauses_->size();
5792+
bool has_default = this->clauses_->has_default();
57525793

57535794
// Zero-case select. Just block the execution.
57545795
if (ncases == 0)
@@ -5766,11 +5807,13 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function,
57665807

57675808
// Two-case select with one default case. It is a non-blocking
57685809
// send/receive.
5769-
if (ncases == 2
5770-
&& (this->clauses_->at(0).is_default()
5771-
|| this->clauses_->at(1).is_default()))
5810+
if (ncases == 2 && has_default)
57725811
return this->lower_two_case(b);
57735812

5813+
// We don't allocate an entry in scases for the default case.
5814+
if (has_default)
5815+
--ncases;
5816+
57745817
Type* scase_type = Channel_type::select_case_type();
57755818
Expression* ncases_expr =
57765819
Expression::make_integer_ul(ncases, NULL,
@@ -5803,7 +5846,10 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function,
58035846
b->add_statement(recvok);
58045847

58055848
// Initialize the scases array.
5806-
this->clauses_->lower(gogo, function, b, scases, recvok);
5849+
int send_count;
5850+
int recv_count;
5851+
this->clauses_->lower(gogo, function, b, scases, recvok, &send_count,
5852+
&recv_count);
58075853

58085854
// Build the call to selectgo. Later, in do_get_backend, we will
58095855
// 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,
58175863
order_ref = Expression::make_unary(OPERATOR_AND, order_ref, loc);
58185864
order_ref = Expression::make_cast(unsafe_pointer_type, order_ref, loc);
58195865

5820-
Expression* count_expr = Expression::make_integer_ul(ncases, int_type, loc);
5866+
Expression* send_count_expr = Expression::make_integer_sl(send_count,
5867+
int_type,
5868+
loc);
5869+
Expression* recv_count_expr = Expression::make_integer_sl(recv_count,
5870+
int_type,
5871+
loc);
5872+
Expression* block_expr = Expression::make_boolean(!has_default, loc);
58215873

5822-
Call_expression* call = Runtime::make_call(Runtime::SELECTGO, loc, 3,
5874+
Call_expression* call = Runtime::make_call(Runtime::SELECTGO, loc, 5,
58235875
scases_ref, order_ref,
5824-
count_expr);
5876+
send_count_expr, recv_count_expr,
5877+
block_expr);
58255878

58265879
Expression* result = Expression::make_call_result(call, 0);
58275880
Expression* ref = Expression::make_temporary_reference(this->index_, loc);

go/statements.h

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,14 +1092,17 @@ class Select_clauses
10921092
size() const
10931093
{ return this->clauses_.size(); }
10941094

1095+
bool
1096+
has_default() const;
1097+
10951098
// Traverse the select clauses.
10961099
int
10971100
traverse(Traverse*);
10981101

10991102
// Lower statements.
11001103
void
11011104
lower(Gogo*, Named_object*, Block*, Temporary_statement*,
1102-
Temporary_statement*);
1105+
Temporary_statement*, int* send_count, int* recv_count);
11031106

11041107
// Determine types.
11051108
void
@@ -1138,8 +1141,9 @@ class Select_clauses
11381141
Named_object* closedvar, bool is_default, Block* statements,
11391142
Location location)
11401143
: channel_(channel), val_(val), closed_(closed), var_(var),
1141-
closedvar_(closedvar), statements_(statements), location_(location),
1142-
is_send_(is_send), is_default_(is_default), is_lowered_(false)
1144+
closedvar_(closedvar), statements_(statements), case_index_(0),
1145+
location_(location), is_send_(is_send), is_default_(is_default),
1146+
is_lowered_(false), is_case_index_set_(false)
11431147
{ go_assert(is_default ? channel == NULL : channel != NULL); }
11441148

11451149
// Traverse the select clause.
@@ -1148,7 +1152,7 @@ class Select_clauses
11481152

11491153
// Lower statements.
11501154
void
1151-
lower(Gogo*, Named_object*, Block*, Temporary_statement*, size_t,
1155+
lower(Gogo*, Named_object*, Block*, Temporary_statement*, int,
11521156
Temporary_statement*);
11531157

11541158
// Determine types.
@@ -1210,6 +1214,23 @@ class Select_clauses
12101214
location() const
12111215
{ return this->location_; }
12121216

1217+
// Return the case index for this clause.
1218+
int
1219+
case_index() const
1220+
{
1221+
go_assert(this->is_case_index_set_);
1222+
return this->case_index_;
1223+
}
1224+
1225+
// Set the case index.
1226+
void
1227+
set_case_index(int i)
1228+
{
1229+
go_assert(!this->is_case_index_set_);
1230+
this->case_index_ = i;
1231+
this->is_case_index_set_ = true;
1232+
}
1233+
12131234
// Whether this clause may fall through to the statement which
12141235
// follows the overall select statement.
12151236
bool
@@ -1224,17 +1245,6 @@ class Select_clauses
12241245
dump_clause(Ast_dump_context*) const;
12251246

12261247
private:
1227-
// These values must match the values in libgo/go/runtime/select.go.
1228-
enum
1229-
{
1230-
caseRecv = 1,
1231-
caseSend = 2,
1232-
caseDefault = 3,
1233-
};
1234-
1235-
void
1236-
lower_default(Block*, Expression*);
1237-
12381248
void
12391249
lower_send(Block*, Expression*, Expression*);
12401250

@@ -1243,7 +1253,7 @@ class Select_clauses
12431253
Temporary_statement*);
12441254

12451255
void
1246-
set_case(Block*, Expression*, Expression*, Expression*, int);
1256+
set_case(Block*, Expression*, Expression*, Expression*);
12471257

12481258
// The channel.
12491259
Expression* channel_;
@@ -1259,6 +1269,10 @@ class Select_clauses
12591269
Named_object* closedvar_;
12601270
// The statements to execute.
12611271
Block* statements_;
1272+
// The index of this clause in the switch statement. If
1273+
// runtime.selectgo returns this index, this clause has been
1274+
// chosen.
1275+
int case_index_;
12621276
// The location of this clause.
12631277
Location location_;
12641278
// Whether this is a send or a receive.
@@ -1267,6 +1281,8 @@ class Select_clauses
12671281
bool is_default_;
12681282
// Whether this has been lowered.
12691283
bool is_lowered_;
1284+
// Whether the case index has been set.
1285+
bool is_case_index_set_;
12701286
};
12711287

12721288
Select_clause&

go/types.cc

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8905,13 +8905,10 @@ Channel_type::select_case_type()
89058905
{
89068906
Type* unsafe_pointer_type =
89078907
Type::make_pointer_type(Type::make_void_type());
8908-
Type* uint16_type = Type::lookup_integer_type("uint16");
8909-
Type* int64_type = Type::lookup_integer_type("int64");
89108908
scase_type =
8911-
Type::make_builtin_struct_type(3,
8909+
Type::make_builtin_struct_type(2,
89128910
"c", unsafe_pointer_type,
8913-
"elem", unsafe_pointer_type,
8914-
"kind", uint16_type);
8911+
"elem", unsafe_pointer_type);
89158912
scase_type->set_is_struct_incomparable();
89168913
}
89178914
return scase_type;

0 commit comments

Comments
 (0)