Commit f54d331e by Ian Lance Taylor Committed by Ian Lance Taylor

Use the backend interface for select statements.

From-SVN: r172468
parent 7427a368
2011-04-14 Ian Lance Taylor <iant@google.com>
* go-gcc.cc (Backend::error_statement): New function.
2011-04-13 Ian Lance Taylor <iant@google.com> 2011-04-13 Ian Lance Taylor <iant@google.com>
* Make-lang.in (go/gogo-tree.o): depend on $(GO_RUNTIME_H). * Make-lang.in (go/gogo-tree.o): depend on $(GO_RUNTIME_H).
......
...@@ -167,6 +167,10 @@ class Gcc_backend : public Backend ...@@ -167,6 +167,10 @@ class Gcc_backend : public Backend
// Statements. // Statements.
Bstatement* Bstatement*
error_statement()
{ return this->make_statement(error_mark_node); }
Bstatement*
expression_statement(Bexpression*); expression_statement(Bexpression*);
Bstatement* Bstatement*
......
...@@ -107,6 +107,12 @@ class Backend ...@@ -107,6 +107,12 @@ class Backend
// Statements. // Statements.
// Create an error statement. This is used for cases which should
// not occur in a correct program, in order to keep the compilation
// going without crashing.
virtual Bstatement*
error_statement() = 0;
// Create an expression statement. // Create an expression statement.
virtual Bstatement* virtual Bstatement*
expression_statement(Bexpression*) = 0; expression_statement(Bexpression*) = 0;
......
...@@ -3603,10 +3603,11 @@ Unsafe_type_conversion_expression::do_get_tree(Translate_context* context) ...@@ -3603,10 +3603,11 @@ Unsafe_type_conversion_expression::do_get_tree(Translate_context* context)
else if (t->channel_type() != NULL) else if (t->channel_type() != NULL)
gcc_assert(et->channel_type() != NULL); gcc_assert(et->channel_type() != NULL);
else if (t->points_to() != NULL && t->points_to()->channel_type() != NULL) else if (t->points_to() != NULL && t->points_to()->channel_type() != NULL)
gcc_assert(et->points_to() != NULL gcc_assert((et->points_to() != NULL
&& et->points_to()->channel_type() != NULL); && et->points_to()->channel_type() != NULL)
|| et->is_nil_type());
else if (t->is_unsafe_pointer_type()) else if (t->is_unsafe_pointer_type())
gcc_assert(et->points_to() != NULL); gcc_assert(et->points_to() != NULL || et->is_nil_type());
else if (et->is_unsafe_pointer_type()) else if (et->is_unsafe_pointer_type())
gcc_assert(t->points_to() != NULL); gcc_assert(t->points_to() != NULL);
else if (t->interface_type() != NULL && !t->interface_type()->is_empty()) else if (t->interface_type() != NULL && !t->interface_type()->is_empty())
......
...@@ -381,3 +381,12 @@ Runtime::map_iteration_type() ...@@ -381,3 +381,12 @@ Runtime::map_iteration_type()
return Type::make_array_type(runtime_function_type(RFT_POINTER), iexpr); return Type::make_array_type(runtime_function_type(RFT_POINTER), iexpr);
} }
// Return the type used to pass a list of general channels to the
// select runtime function.
Type*
Runtime::chanptr_type()
{
return runtime_function_type(RFT_CHANPTR);
}
...@@ -30,15 +30,24 @@ class Runtime ...@@ -30,15 +30,24 @@ class Runtime
NUMBER_OF_FUNCTIONS NUMBER_OF_FUNCTIONS
}; };
// Make a call to a runtime function.
static Call_expression* static Call_expression*
make_call(Function, source_location, int, ...); make_call(Function, source_location, int, ...);
// Convert all the types used by runtime functions to the backend
// representation.
static void static void
convert_types(Gogo*); convert_types(Gogo*);
// Return the type used for iterations over maps.
static Type* static Type*
map_iteration_type(); map_iteration_type();
// Return the type used to pass a list of general channels to the
// select runtime function.
static Type*
chanptr_type();
private: private:
static Named_object* static Named_object*
runtime_declaration(Function); runtime_declaration(Function);
......
...@@ -3974,12 +3974,13 @@ Select_clauses::Select_clause::may_fall_through() const ...@@ -3974,12 +3974,13 @@ Select_clauses::Select_clause::may_fall_through() const
// Return a tree for the statements to execute. // Return a tree for the statements to execute.
tree Bstatement*
Select_clauses::Select_clause::get_statements_tree(Translate_context* context) Select_clauses::Select_clause::get_statements_backend(
Translate_context* context)
{ {
if (this->statements_ == NULL) if (this->statements_ == NULL)
return NULL_TREE; return NULL;
return this->statements_->get_tree(context); return tree_to_stat(this->statements_->get_tree(context));
} }
// Class Select_clauses. // Class Select_clauses.
...@@ -4037,7 +4038,7 @@ Select_clauses::may_fall_through() const ...@@ -4037,7 +4038,7 @@ Select_clauses::may_fall_through() const
return false; return false;
} }
// Return a tree. We build a call to // Convert to the backend representation. We build a call to
// size_t __go_select(size_t count, _Bool has_default, // size_t __go_select(size_t count, _Bool has_default,
// channel* channels, _Bool* is_send) // channel* channels, _Bool* is_send)
// //
...@@ -4051,20 +4052,24 @@ Select_clauses::may_fall_through() const ...@@ -4051,20 +4052,24 @@ Select_clauses::may_fall_through() const
// FIXME: This doesn't handle channels which send interface types // FIXME: This doesn't handle channels which send interface types
// where the receiver has a static type which matches that interface. // where the receiver has a static type which matches that interface.
tree Bstatement*
Select_clauses::get_tree(Translate_context* context, Select_clauses::get_backend(Translate_context* context,
Unnamed_label *break_label, Unnamed_label *break_label,
source_location location) source_location location)
{ {
size_t count = this->clauses_.size(); size_t count = this->clauses_.size();
VEC(constructor_elt, gc)* chan_init = VEC_alloc(constructor_elt, gc, count);
VEC(constructor_elt, gc)* is_send_init = VEC_alloc(constructor_elt, gc,
count);
Select_clause* default_clause = NULL;
tree final_stmt_list = NULL_TREE;
tree channel_type_tree = NULL_TREE;
size_t i = 0; Expression_list* chan_init = new Expression_list();
chan_init->reserve(count);
Expression_list* is_send_init = new Expression_list();
is_send_init->reserve(count);
Select_clause *default_clause = NULL;
Type* runtime_chanptr_type = Runtime::chanptr_type();
Type* runtime_chan_type = runtime_chanptr_type->points_to();
for (Clauses::iterator p = this->clauses_.begin(); for (Clauses::iterator p = this->clauses_.begin();
p != this->clauses_.end(); p != this->clauses_.end();
++p) ++p)
...@@ -4081,153 +4086,182 @@ Select_clauses::get_tree(Translate_context* context, ...@@ -4081,153 +4086,182 @@ Select_clauses::get_tree(Translate_context* context,
// We should have given an error in the send or receive // We should have given an error in the send or receive
// statement we created via lowering. // statement we created via lowering.
gcc_assert(saw_errors()); gcc_assert(saw_errors());
return error_mark_node; return context->backend()->error_statement();
} }
tree channel_tree = p->channel()->get_tree(context); Expression* c = p->channel();
if (channel_tree == error_mark_node) c = Expression::make_unsafe_cast(runtime_chan_type, c, p->location());
return error_mark_node; chan_init->push_back(c);
channel_type_tree = TREE_TYPE(channel_tree);
constructor_elt* elt = VEC_quick_push(constructor_elt, chan_init, NULL);
elt->index = build_int_cstu(sizetype, i);
elt->value = channel_tree;
elt = VEC_quick_push(constructor_elt, is_send_init, NULL); is_send_init->push_back(Expression::make_boolean(p->is_send(),
elt->index = build_int_cstu(sizetype, i); p->location()));
elt->value = p->is_send() ? boolean_true_node : boolean_false_node;
++i;
} }
gcc_assert(i == count);
if (i == 0 && default_clause != NULL) if (chan_init->empty())
{ {
// There is only a default clause. gcc_assert(count == 0);
gcc_assert(final_stmt_list == NULL_TREE); Bstatement* s;
tree stmt_list = NULL_TREE;
append_to_statement_list(default_clause->get_statements_tree(context),
&stmt_list);
Bstatement* ldef = break_label->get_definition(context); Bstatement* ldef = break_label->get_definition(context);
append_to_statement_list(stat_to_tree(ldef), &stmt_list); if (default_clause != NULL)
return stmt_list;
}
tree pointer_chan_type_tree = (channel_type_tree == NULL_TREE
? ptr_type_node
: build_pointer_type(channel_type_tree));
tree chans_arg;
tree pointer_boolean_type_tree = build_pointer_type(boolean_type_node);
tree is_sends_arg;
if (i == 0)
{ {
chans_arg = fold_convert_loc(location, pointer_chan_type_tree, // There is a default clause and no cases. Just execute the
null_pointer_node); // default clause.
is_sends_arg = fold_convert_loc(location, pointer_boolean_type_tree, s = default_clause->get_statements_backend(context);
null_pointer_node);
} }
else else
{ {
tree index_type_tree = build_index_type(size_int(count - 1)); // There isn't even a default clause. In this case select
tree chan_array_type_tree = build_array_type(channel_type_tree, // pauses forever. Call the runtime function with nils.
index_type_tree); mpz_t zval;
tree chan_constructor = build_constructor(chan_array_type_tree, mpz_init_set_ui(zval, 0);
chan_init); Expression* zero = Expression::make_integer(&zval, NULL, location);
tree chan_var = create_tmp_var(chan_array_type_tree, "CHAN"); mpz_clear(zval);
DECL_IGNORED_P(chan_var) = 0; Expression* default_arg = Expression::make_boolean(false, location);
DECL_INITIAL(chan_var) = chan_constructor; Expression* nil1 = Expression::make_nil(location);
DECL_SOURCE_LOCATION(chan_var) = location; Expression* nil2 = nil1->copy();
TREE_ADDRESSABLE(chan_var) = 1; Expression* call = Runtime::make_call(Runtime::SELECT, location, 4,
tree decl_expr = build1(DECL_EXPR, void_type_node, chan_var); zero, default_arg, nil1, nil2);
SET_EXPR_LOCATION(decl_expr, location); context->gogo()->lower_expression(context->function(), &call);
append_to_statement_list(decl_expr, &final_stmt_list); Bexpression* bcall = tree_to_expr(call->get_tree(context));
s = context->backend()->expression_statement(bcall);
tree is_send_array_type_tree = build_array_type(boolean_type_node, }
index_type_tree); if (s == NULL)
tree is_send_constructor = build_constructor(is_send_array_type_tree, return ldef;
is_send_init); std::vector<Bstatement*> stats(2);
tree is_send_var = create_tmp_var(is_send_array_type_tree, "ISSEND"); stats[0] = s;
DECL_IGNORED_P(is_send_var) = 0; stats[1] = ldef;
DECL_INITIAL(is_send_var) = is_send_constructor; return context->backend()->statement_list(stats);
DECL_SOURCE_LOCATION(is_send_var) = location; }
TREE_ADDRESSABLE(is_send_var) = 1; gcc_assert(count > 0);
decl_expr = build1(DECL_EXPR, void_type_node, is_send_var);
SET_EXPR_LOCATION(decl_expr, location);
append_to_statement_list(decl_expr, &final_stmt_list);
chans_arg = fold_convert_loc(location, pointer_chan_type_tree,
build_fold_addr_expr_loc(location,
chan_var));
is_sends_arg = fold_convert_loc(location, pointer_boolean_type_tree,
build_fold_addr_expr_loc(location,
is_send_var));
}
static tree select_fndecl;
tree call = Gogo::call_builtin(&select_fndecl,
location,
"__go_select",
4,
sizetype,
sizetype,
size_int(count),
boolean_type_node,
(default_clause == NULL
? boolean_false_node
: boolean_true_node),
pointer_chan_type_tree,
chans_arg,
pointer_boolean_type_tree,
is_sends_arg);
if (call == error_mark_node)
return error_mark_node;
tree stmt_list = NULL_TREE; std::vector<Bstatement*> statements;
mpz_t ival;
mpz_init_set_ui(ival, count);
Expression* ecount = Expression::make_integer(&ival, NULL, location);
mpz_clear(ival);
Type* chan_array_type = Type::make_array_type(runtime_chan_type, ecount);
Expression* chans = Expression::make_composite_literal(chan_array_type, 0,
false, chan_init,
location);
context->gogo()->lower_expression(context->function(), &chans);
Temporary_statement* chan_temp = Statement::make_temporary(chan_array_type,
chans,
location);
statements.push_back(tree_to_stat(chan_temp->get_tree(context)));
Type* is_send_array_type = Type::make_array_type(Type::lookup_bool_type(),
ecount->copy());
Expression* is_sends = Expression::make_composite_literal(is_send_array_type,
0, false,
is_send_init,
location);
context->gogo()->lower_expression(context->function(), &is_sends);
Temporary_statement* is_send_temp =
Statement::make_temporary(is_send_array_type, is_sends, location);
statements.push_back(tree_to_stat(is_send_temp->get_tree(context)));
mpz_init_set_ui(ival, 0);
Expression* zero = Expression::make_integer(&ival, NULL, location);
mpz_clear(ival);
Expression* ref = Expression::make_temporary_reference(chan_temp, location);
Expression* chan_arg = Expression::make_array_index(ref, zero, NULL,
location);
chan_arg = Expression::make_unary(OPERATOR_AND, chan_arg, location);
chan_arg = Expression::make_unsafe_cast(runtime_chanptr_type, chan_arg,
location);
ref = Expression::make_temporary_reference(is_send_temp, location);
Expression* is_send_arg = Expression::make_array_index(ref, zero->copy(),
NULL, location);
is_send_arg = Expression::make_unary(OPERATOR_AND, is_send_arg, location);
Expression* default_arg = Expression::make_boolean(default_clause != NULL,
location);
Expression* call = Runtime::make_call(Runtime::SELECT, location, 4,
ecount->copy(), default_arg,
chan_arg, is_send_arg);
context->gogo()->lower_expression(context->function(), &call);
Bexpression* bcall = tree_to_expr(call->get_tree(context));
std::vector<std::vector<Bexpression*> > cases;
std::vector<Bstatement*> clauses;
cases.resize(count + (default_clause != NULL ? 1 : 0));
clauses.resize(count + (default_clause != NULL ? 1 : 0));
int index = 0;
if (default_clause != NULL) if (default_clause != NULL)
this->add_clause_tree(context, 0, default_clause, break_label, &stmt_list); {
this->add_clause_backend(context, location, index, 0, default_clause,
break_label, &cases, &clauses);
++index;
}
i = 1; int i = 1;
for (Clauses::iterator p = this->clauses_.begin(); for (Clauses::iterator p = this->clauses_.begin();
p != this->clauses_.end(); p != this->clauses_.end();
++p) ++p)
{ {
if (!p->is_default()) if (!p->is_default())
{ {
this->add_clause_tree(context, i, &*p, break_label, &stmt_list); this->add_clause_backend(context, location, index, i, &*p,
break_label, &cases, &clauses);
++i; ++i;
++index;
} }
} }
Bstatement* ldef = break_label->get_definition(context); Bstatement* switch_stmt = context->backend()->switch_statement(bcall,
append_to_statement_list(stat_to_tree(ldef), &stmt_list); cases,
clauses,
location);
statements.push_back(switch_stmt);
tree switch_stmt = build3(SWITCH_EXPR, sizetype, call, stmt_list, NULL_TREE); Bstatement* ldef = break_label->get_definition(context);
SET_EXPR_LOCATION(switch_stmt, location); statements.push_back(ldef);
append_to_statement_list(switch_stmt, &final_stmt_list);
return final_stmt_list; return context->backend()->statement_list(statements);
} }
// Add the tree for CLAUSE to STMT_LIST. // Add the tree for CLAUSE to STMT_LIST.
void void
Select_clauses::add_clause_tree(Translate_context* context, int case_index, Select_clauses::add_clause_backend(
Translate_context* context,
source_location location,
int index,
int case_value,
Select_clause* clause, Select_clause* clause,
Unnamed_label* bottom_label, tree* stmt_list) Unnamed_label* bottom_label,
{ std::vector<std::vector<Bexpression*> > *cases,
tree label = create_artificial_label(clause->location()); std::vector<Bstatement*>* clauses)
append_to_statement_list(build3(CASE_LABEL_EXPR, void_type_node, {
build_int_cst(sizetype, case_index), mpz_t ival;
NULL_TREE, label), mpz_init_set_ui(ival, case_value);
stmt_list); Expression* e = Expression::make_integer(&ival, NULL, location);
append_to_statement_list(clause->get_statements_tree(context), stmt_list); mpz_clear(ival);
(*cases)[index].push_back(tree_to_expr(e->get_tree(context)));
Bstatement* s = clause->get_statements_backend(context);
source_location gloc = (clause->statements() == NULL source_location gloc = (clause->statements() == NULL
? clause->location() ? clause->location()
: clause->statements()->end_location()); : clause->statements()->end_location());
Bstatement* g = bottom_label->get_goto(context, gloc); Bstatement* g = bottom_label->get_goto(context, gloc);
append_to_statement_list(stat_to_tree(g), stmt_list);
if (s == NULL)
(*clauses)[index] = g;
else
{
std::vector<Bstatement*> stats(2);
stats[0] = s;
stats[1] = g;
(*clauses)[index] = context->backend()->statement_list(stats);
}
} }
// Class Select_statement. // Class Select_statement.
...@@ -4266,8 +4300,9 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function, ...@@ -4266,8 +4300,9 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function,
tree tree
Select_statement::do_get_tree(Translate_context* context) Select_statement::do_get_tree(Translate_context* context)
{ {
return this->clauses_->get_tree(context, this->break_label(), Bstatement* ret = this->clauses_->get_backend(context, this->break_label(),
this->location()); this->location());
return stat_to_tree(ret);
} }
// Make a select statement. // Make a select statement.
......
...@@ -678,9 +678,9 @@ class Select_clauses ...@@ -678,9 +678,9 @@ class Select_clauses
bool bool
may_fall_through() const; may_fall_through() const;
// Return a tree implementing the select statement. // Convert to the backend representation.
tree Bstatement*
get_tree(Translate_context*, Unnamed_label* break_label, source_location); get_backend(Translate_context*, Unnamed_label* break_label, source_location);
private: private:
// A single clause. // A single clause.
...@@ -749,8 +749,8 @@ class Select_clauses ...@@ -749,8 +749,8 @@ class Select_clauses
may_fall_through() const; may_fall_through() const;
// Return a tree for the statements to execute. // Return a tree for the statements to execute.
tree Bstatement*
get_statements_tree(Translate_context*); get_statements_backend(Translate_context*);
private: private:
// The channel. // The channel.
...@@ -778,8 +778,10 @@ class Select_clauses ...@@ -778,8 +778,10 @@ class Select_clauses
}; };
void void
add_clause_tree(Translate_context*, int, Select_clause*, Unnamed_label*, add_clause_backend(Translate_context*, source_location, int index,
tree*); int case_value, Select_clause*, Unnamed_label*,
std::vector<std::vector<Bexpression*> >* cases,
std::vector<Bstatement*>* clauses);
typedef std::vector<Select_clause> Clauses; typedef std::vector<Select_clause> Clauses;
......
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