Commit 84cdf51d by Ian Lance Taylor

compiler, runtime: open code select

    
    This is the gofrontend version of https://golang.org/cl/37933,
    https://golang.org/cl/37934, and https://golang.org/cl/37935.
    Open code the initialization of select cases.
    
    This is a step toward updating libgo to the 1.11 release.
    
    Reviewed-on: https://go-review.googlesource.com/135000

From-SVN: r264290
parent 283b9caf
f68c03e509b26e7f483f2800eb70a5fbf3f74d0b f2cd046a4e0d681c3d21ee547b437d3eab8af268
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -1361,7 +1361,13 @@ Escape_analysis_assign::statement(Block*, size_t*, Statement* s) ...@@ -1361,7 +1361,13 @@ Escape_analysis_assign::statement(Block*, size_t*, Statement* s)
{ {
Expression* init = s->temporary_statement()->init(); Expression* init = s->temporary_statement()->init();
if (init != NULL) if (init != NULL)
this->assign(Node::make_node(s), Node::make_node(init)); {
Node* n = Node::make_node(init);
if (s->temporary_statement()->value_escapes())
this->assign(this->context_->sink(), n);
else
this->assign(Node::make_node(s), n);
}
} }
break; break;
...@@ -1616,15 +1622,6 @@ Escape_analysis_assign::expression(Expression** pexpr) ...@@ -1616,15 +1622,6 @@ Escape_analysis_assign::expression(Expression** pexpr)
} }
break; break;
case Runtime::SELECTSEND:
{
// Send to a channel, lose track. The last argument is
// the address of the value to send.
Node* arg_node = Node::make_node(call->args()->back());
this->assign_deref(this->context_->sink(), arg_node);
}
break;
case Runtime::IFACEE2T2: case Runtime::IFACEE2T2:
case Runtime::IFACEI2T2: case Runtime::IFACEI2T2:
{ {
...@@ -2228,8 +2225,12 @@ Escape_analysis_assign::assign(Node* dst, Node* src) ...@@ -2228,8 +2225,12 @@ Escape_analysis_assign::assign(Node* dst, Node* src)
case Expression::EXPRESSION_TEMPORARY_REFERENCE: case Expression::EXPRESSION_TEMPORARY_REFERENCE:
{ {
// Temporary is tracked through the underlying Temporary_statement. // Temporary is tracked through the underlying Temporary_statement.
Statement* t = dst->expr()->temporary_reference_expression()->statement(); Temporary_statement* t =
dst = Node::make_node(t); dst->expr()->temporary_reference_expression()->statement();
if (t->value_escapes())
dst = this->context_->sink();
else
dst = Node::make_node(t);
} }
break; break;
......
...@@ -152,22 +152,10 @@ DEF_GO_RUNTIME(CHANRECV1, "runtime.chanrecv1", P2(CHAN, POINTER), R0()) ...@@ -152,22 +152,10 @@ DEF_GO_RUNTIME(CHANRECV1, "runtime.chanrecv1", P2(CHAN, POINTER), R0())
DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P2(CHAN, POINTER), R1(BOOL)) DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P2(CHAN, POINTER), R1(BOOL))
// Start building a select statement. // Run a select, returning the index of the selected clause and
DEF_GO_RUNTIME(NEWSELECT, "runtime.newselect", P3(POINTER, INT64, INT32), R0()) // whether that channel received a value.
DEF_GO_RUNTIME(SELECTGO, "runtime.selectgo", P3(POINTER, POINTER, INT),
// Add a default clause to a select statement. R2(INT, BOOL))
DEF_GO_RUNTIME(SELECTDEFAULT, "runtime.selectdefault", P1(POINTER), R0())
// Add a send clause to a select statement.
DEF_GO_RUNTIME(SELECTSEND, "runtime.selectsend", P3(POINTER, CHAN, POINTER),
R0())
// Add a receive clause to a select statement.
DEF_GO_RUNTIME(SELECTRECV, "runtime.selectrecv",
P4(POINTER, CHAN, POINTER, BOOLPTR), R0())
// Run a select, returning the index of the selected clause.
DEF_GO_RUNTIME(SELECTGO, "runtime.selectgo", P1(POINTER), R1(INT))
// Panic. // Panic.
......
...@@ -622,7 +622,8 @@ class Temporary_statement : public Statement ...@@ -622,7 +622,8 @@ class Temporary_statement : public Statement
public: public:
Temporary_statement(Type* type, Expression* init, Location location) Temporary_statement(Type* type, Expression* init, Location location)
: Statement(STATEMENT_TEMPORARY, location), : Statement(STATEMENT_TEMPORARY, location),
type_(type), init_(init), bvariable_(NULL), is_address_taken_(false) type_(type), init_(init), bvariable_(NULL), is_address_taken_(false),
value_escapes_(false)
{ } { }
// Return the type of the temporary variable. // Return the type of the temporary variable.
...@@ -640,6 +641,16 @@ class Temporary_statement : public Statement ...@@ -640,6 +641,16 @@ class Temporary_statement : public Statement
set_is_address_taken() set_is_address_taken()
{ this->is_address_taken_ = true; } { this->is_address_taken_ = true; }
// Whether the value escapes.
bool
value_escapes() const
{ return this->value_escapes_; }
// Record that the value escapes.
void
set_value_escapes()
{ this->value_escapes_ = true; }
// Return the temporary variable. This should not be called until // Return the temporary variable. This should not be called until
// after the statement itself has been converted. // after the statement itself has been converted.
Bvariable* Bvariable*
...@@ -676,6 +687,9 @@ class Temporary_statement : public Statement ...@@ -676,6 +687,9 @@ class Temporary_statement : public Statement
Bvariable* bvariable_; Bvariable* bvariable_;
// True if something takes the address of this temporary variable. // True if something takes the address of this temporary variable.
bool is_address_taken_; bool is_address_taken_;
// True if the value assigned to this temporary variable escapes.
// This is used for select statements.
bool value_escapes_;
}; };
// A variable declaration. This marks the point in the code where a // A variable declaration. This marks the point in the code where a
...@@ -851,7 +865,7 @@ class Send_statement : public Statement ...@@ -851,7 +865,7 @@ class Send_statement : public Statement
Expression* Expression*
channel() channel()
{ return this->channel_; } { return this->channel_; }
Expression* Expression*
val() val()
...@@ -924,7 +938,8 @@ class Select_clauses ...@@ -924,7 +938,8 @@ class Select_clauses
// Lower statements. // Lower statements.
void void
lower(Gogo*, Named_object*, Block*, Temporary_statement*); lower(Gogo*, Named_object*, Block*, Temporary_statement*,
Temporary_statement*);
// Determine types. // Determine types.
void void
...@@ -941,7 +956,7 @@ class Select_clauses ...@@ -941,7 +956,7 @@ class Select_clauses
// Convert to the backend representation. // Convert to the backend representation.
Bstatement* Bstatement*
get_backend(Translate_context*, Temporary_statement* sel, get_backend(Translate_context*, Temporary_statement* index,
Unnamed_label* break_label, Location); Unnamed_label* break_label, Location);
// Dump AST representation. // Dump AST representation.
...@@ -974,7 +989,8 @@ class Select_clauses ...@@ -974,7 +989,8 @@ class Select_clauses
// Lower statements. // Lower statements.
void void
lower(Gogo*, Named_object*, Block*, Temporary_statement*); lower(Gogo*, Named_object*, Block*, Temporary_statement*, size_t,
Temporary_statement*);
// Determine types. // Determine types.
void void
...@@ -1027,6 +1043,14 @@ class Select_clauses ...@@ -1027,6 +1043,14 @@ class Select_clauses
dump_clause(Ast_dump_context*) const; dump_clause(Ast_dump_context*) const;
private: private:
// These values must match the values in libgo/go/runtime/select.go.
enum
{
caseRecv = 1,
caseSend = 2,
caseDefault = 3,
};
void void
lower_default(Block*, Expression*); lower_default(Block*, Expression*);
...@@ -1034,7 +1058,11 @@ class Select_clauses ...@@ -1034,7 +1058,11 @@ class Select_clauses
lower_send(Block*, Expression*, Expression*); lower_send(Block*, Expression*, Expression*);
void void
lower_recv(Gogo*, Named_object*, Block*, Expression*, Expression*); lower_recv(Gogo*, Named_object*, Block*, Expression*, Expression*,
Temporary_statement*);
void
set_case(Block*, Expression*, Expression*, Expression*, int);
// The channel. // The channel.
Expression* channel_; Expression* channel_;
...@@ -1072,7 +1100,7 @@ class Select_statement : public Statement ...@@ -1072,7 +1100,7 @@ class Select_statement : public Statement
public: public:
Select_statement(Location location) Select_statement(Location location)
: Statement(STATEMENT_SELECT, location), : Statement(STATEMENT_SELECT, location),
clauses_(NULL), sel_(NULL), break_label_(NULL), is_lowered_(false) clauses_(NULL), index_(NULL), break_label_(NULL), is_lowered_(false)
{ } { }
// Add the clauses. // Add the clauses.
...@@ -1115,8 +1143,8 @@ class Select_statement : public Statement ...@@ -1115,8 +1143,8 @@ class Select_statement : public Statement
private: private:
// The select clauses. // The select clauses.
Select_clauses* clauses_; Select_clauses* clauses_;
// A temporary which holds the select structure we build up at runtime. // A temporary that holds the index value returned by selectgo.
Temporary_statement* sel_; Temporary_statement* index_;
// The break label. // The break label.
Unnamed_label* break_label_; Unnamed_label* break_label_;
// Whether this statement has been lowered. // Whether this statement has been lowered.
...@@ -1609,7 +1637,7 @@ class Case_clauses ...@@ -1609,7 +1637,7 @@ class Case_clauses
// Dump the AST representation to a dump context. // Dump the AST representation to a dump context.
void void
dump_clauses(Ast_dump_context*) const; dump_clauses(Ast_dump_context*) const;
private: private:
// For a constant switch we need to keep a record of constants we // For a constant switch we need to keep a record of constants we
// have already seen. // have already seen.
...@@ -1683,7 +1711,7 @@ class Case_clauses ...@@ -1683,7 +1711,7 @@ class Case_clauses
// Dump the AST representation to a dump context. // Dump the AST representation to a dump context.
void void
dump_clause(Ast_dump_context*) const; dump_clause(Ast_dump_context*) const;
private: private:
// The list of case expressions. // The list of case expressions.
Expression_list* cases_; Expression_list* cases_;
......
...@@ -8557,51 +8557,29 @@ Channel_type::do_import(Import* imp) ...@@ -8557,51 +8557,29 @@ Channel_type::do_import(Import* imp)
return Type::make_channel_type(may_send, may_receive, element_type); return Type::make_channel_type(may_send, may_receive, element_type);
} }
// Return the type to manage a select statement with ncases case // Return the type that the runtime package uses for one case of a
// statements. A value of this type is allocated on the stack. This // select statement. An array of values of this type is allocated on
// must match the type hselect in libgo/go/runtime/select.go. // the stack. This must match scase in libgo/go/runtime/select.go.
Type* Type*
Channel_type::select_type(int ncases) 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");
static Struct_type* scase_type; static Struct_type* scase_type;
if (scase_type == NULL) if (scase_type == NULL)
{ {
Type* uintptr_type = Type::lookup_integer_type("uintptr"); Type* unsafe_pointer_type =
Type* uint64_type = Type::lookup_integer_type("uint64"); 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 = scase_type =
Type::make_builtin_struct_type(7, Type::make_builtin_struct_type(4,
"c", unsafe_pointer_type,
"elem", unsafe_pointer_type, "elem", unsafe_pointer_type,
"chan", unsafe_pointer_type,
"pc", uintptr_type,
"kind", uint16_type, "kind", uint16_type,
"index", uint16_type, "releasetime", int64_type);
"receivedp", unsafe_pointer_type,
"releasetime", uint64_type);
scase_type->set_is_struct_incomparable(); scase_type->set_is_struct_incomparable();
} }
return scase_type;
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. // Make a new channel type.
......
...@@ -2981,7 +2981,7 @@ class Channel_type : public Type ...@@ -2981,7 +2981,7 @@ class Channel_type : public Type
make_chan_type_descriptor_type(); make_chan_type_descriptor_type();
static Type* static Type*
select_type(int ncases); select_case_type();
protected: protected:
int int
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment