summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2011-04-15 04:10:08 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2011-04-15 04:10:08 +0000
commitde0e0814318021b05ef36109c0ccae41571f1478 (patch)
tree7b20c37532b2390ef74bb6aab95ec57585f0de03
parent219110b4d6e43dcdbc9e55ffa3ee3ca9bc06a84a (diff)
downloadgcc-de0e0814318021b05ef36109c0ccae41571f1478.tar.gz
Use the backend interface for select statements.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@172468 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/go/ChangeLog4
-rw-r--r--gcc/go/go-gcc.cc4
-rw-r--r--gcc/go/gofrontend/backend.h6
-rw-r--r--gcc/go/gofrontend/expressions.cc7
-rw-r--r--gcc/go/gofrontend/runtime.cc9
-rw-r--r--gcc/go/gofrontend/runtime.h9
-rw-r--r--gcc/go/gofrontend/statements.cc293
-rw-r--r--gcc/go/gofrontend/statements.h16
8 files changed, 209 insertions, 139 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog
index 002c9e36c0e..0b4c721130f 100644
--- a/gcc/go/ChangeLog
+++ b/gcc/go/ChangeLog
@@ -1,3 +1,7 @@
+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>
* Make-lang.in (go/gogo-tree.o): depend on $(GO_RUNTIME_H).
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index f9efb3c9e9b..acdbfd0153c 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -167,6 +167,10 @@ class Gcc_backend : public Backend
// Statements.
Bstatement*
+ error_statement()
+ { return this->make_statement(error_mark_node); }
+
+ Bstatement*
expression_statement(Bexpression*);
Bstatement*
diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h
index 01f3cfa4c2b..516ace93759 100644
--- a/gcc/go/gofrontend/backend.h
+++ b/gcc/go/gofrontend/backend.h
@@ -107,6 +107,12 @@ class Backend
// 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.
virtual Bstatement*
expression_statement(Bexpression*) = 0;
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 7f291d40a76..6e1461852a9 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -3603,10 +3603,11 @@ Unsafe_type_conversion_expression::do_get_tree(Translate_context* context)
else if (t->channel_type() != NULL)
gcc_assert(et->channel_type() != NULL);
else if (t->points_to() != NULL && t->points_to()->channel_type() != NULL)
- gcc_assert(et->points_to() != NULL
- && et->points_to()->channel_type() != NULL);
+ gcc_assert((et->points_to() != NULL
+ && et->points_to()->channel_type() != NULL)
+ || et->is_nil_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())
gcc_assert(t->points_to() != NULL);
else if (t->interface_type() != NULL && !t->interface_type()->is_empty())
diff --git a/gcc/go/gofrontend/runtime.cc b/gcc/go/gofrontend/runtime.cc
index 7249dff739b..b10a1b63c7a 100644
--- a/gcc/go/gofrontend/runtime.cc
+++ b/gcc/go/gofrontend/runtime.cc
@@ -381,3 +381,12 @@ Runtime::map_iteration_type()
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);
+}
diff --git a/gcc/go/gofrontend/runtime.h b/gcc/go/gofrontend/runtime.h
index d8fb00c2725..f7c878e73b9 100644
--- a/gcc/go/gofrontend/runtime.h
+++ b/gcc/go/gofrontend/runtime.h
@@ -30,15 +30,24 @@ class Runtime
NUMBER_OF_FUNCTIONS
};
+ // Make a call to a runtime function.
static Call_expression*
make_call(Function, source_location, int, ...);
+ // Convert all the types used by runtime functions to the backend
+ // representation.
static void
convert_types(Gogo*);
+ // Return the type used for iterations over maps.
static 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:
static Named_object*
runtime_declaration(Function);
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index 6ca8bf54a36..0774b83af93 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -3974,12 +3974,13 @@ Select_clauses::Select_clause::may_fall_through() const
// Return a tree for the statements to execute.
-tree
-Select_clauses::Select_clause::get_statements_tree(Translate_context* context)
+Bstatement*
+Select_clauses::Select_clause::get_statements_backend(
+ Translate_context* context)
{
if (this->statements_ == NULL)
- return NULL_TREE;
- return this->statements_->get_tree(context);
+ return NULL;
+ return tree_to_stat(this->statements_->get_tree(context));
}
// Class Select_clauses.
@@ -4037,7 +4038,7 @@ Select_clauses::may_fall_through() const
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,
// channel* channels, _Bool* is_send)
//
@@ -4051,20 +4052,24 @@ Select_clauses::may_fall_through() const
// FIXME: This doesn't handle channels which send interface types
// where the receiver has a static type which matches that interface.
-tree
-Select_clauses::get_tree(Translate_context* context,
- Unnamed_label *break_label,
- source_location location)
+Bstatement*
+Select_clauses::get_backend(Translate_context* context,
+ Unnamed_label *break_label,
+ source_location location)
{
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();
p != this->clauses_.end();
++p)
@@ -4081,153 +4086,182 @@ Select_clauses::get_tree(Translate_context* context,
// We should have given an error in the send or receive
// statement we created via lowering.
gcc_assert(saw_errors());
- return error_mark_node;
+ return context->backend()->error_statement();
}
- tree channel_tree = p->channel()->get_tree(context);
- if (channel_tree == error_mark_node)
- return error_mark_node;
- 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);
- elt->index = build_int_cstu(sizetype, i);
- elt->value = p->is_send() ? boolean_true_node : boolean_false_node;
+ Expression* c = p->channel();
+ c = Expression::make_unsafe_cast(runtime_chan_type, c, p->location());
+ chan_init->push_back(c);
- ++i;
+ is_send_init->push_back(Expression::make_boolean(p->is_send(),
+ p->location()));
}
- gcc_assert(i == count);
- if (i == 0 && default_clause != NULL)
+ if (chan_init->empty())
{
- // There is only a default clause.
- gcc_assert(final_stmt_list == NULL_TREE);
- tree stmt_list = NULL_TREE;
- append_to_statement_list(default_clause->get_statements_tree(context),
- &stmt_list);
+ gcc_assert(count == 0);
+ Bstatement* s;
Bstatement* ldef = break_label->get_definition(context);
- append_to_statement_list(stat_to_tree(ldef), &stmt_list);
- return stmt_list;
+ if (default_clause != NULL)
+ {
+ // There is a default clause and no cases. Just execute the
+ // default clause.
+ s = default_clause->get_statements_backend(context);
+ }
+ else
+ {
+ // There isn't even a default clause. In this case select
+ // pauses forever. Call the runtime function with nils.
+ mpz_t zval;
+ mpz_init_set_ui(zval, 0);
+ Expression* zero = Expression::make_integer(&zval, NULL, location);
+ mpz_clear(zval);
+ Expression* default_arg = Expression::make_boolean(false, location);
+ Expression* nil1 = Expression::make_nil(location);
+ Expression* nil2 = nil1->copy();
+ Expression* call = Runtime::make_call(Runtime::SELECT, location, 4,
+ zero, default_arg, nil1, nil2);
+ context->gogo()->lower_expression(context->function(), &call);
+ Bexpression* bcall = tree_to_expr(call->get_tree(context));
+ s = context->backend()->expression_statement(bcall);
+ }
+ if (s == NULL)
+ return ldef;
+ std::vector<Bstatement*> stats(2);
+ stats[0] = s;
+ stats[1] = ldef;
+ return context->backend()->statement_list(stats);
}
+ gcc_assert(count > 0);
- 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;
+ std::vector<Bstatement*> statements;
- if (i == 0)
- {
- chans_arg = fold_convert_loc(location, pointer_chan_type_tree,
- null_pointer_node);
- is_sends_arg = fold_convert_loc(location, pointer_boolean_type_tree,
- null_pointer_node);
- }
- else
- {
- tree index_type_tree = build_index_type(size_int(count - 1));
- tree chan_array_type_tree = build_array_type(channel_type_tree,
- index_type_tree);
- tree chan_constructor = build_constructor(chan_array_type_tree,
- chan_init);
- tree chan_var = create_tmp_var(chan_array_type_tree, "CHAN");
- DECL_IGNORED_P(chan_var) = 0;
- DECL_INITIAL(chan_var) = chan_constructor;
- DECL_SOURCE_LOCATION(chan_var) = location;
- TREE_ADDRESSABLE(chan_var) = 1;
- tree decl_expr = build1(DECL_EXPR, void_type_node, chan_var);
- SET_EXPR_LOCATION(decl_expr, location);
- append_to_statement_list(decl_expr, &final_stmt_list);
-
- tree is_send_array_type_tree = build_array_type(boolean_type_node,
- index_type_tree);
- tree is_send_constructor = build_constructor(is_send_array_type_tree,
- is_send_init);
- tree is_send_var = create_tmp_var(is_send_array_type_tree, "ISSEND");
- DECL_IGNORED_P(is_send_var) = 0;
- DECL_INITIAL(is_send_var) = is_send_constructor;
- DECL_SOURCE_LOCATION(is_send_var) = location;
- TREE_ADDRESSABLE(is_send_var) = 1;
- 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));
- }
+ mpz_t ival;
+ mpz_init_set_ui(ival, count);
+ Expression* ecount = Expression::make_integer(&ival, NULL, location);
+ mpz_clear(ival);
- 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;
+ 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));
- tree stmt_list = NULL_TREE;
+ 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)
- 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();
p != this->clauses_.end();
++p)
{
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;
+ ++index;
}
}
- Bstatement* ldef = break_label->get_definition(context);
- append_to_statement_list(stat_to_tree(ldef), &stmt_list);
+ Bstatement* switch_stmt = context->backend()->switch_statement(bcall,
+ cases,
+ clauses,
+ location);
+ statements.push_back(switch_stmt);
- tree switch_stmt = build3(SWITCH_EXPR, sizetype, call, stmt_list, NULL_TREE);
- SET_EXPR_LOCATION(switch_stmt, location);
- append_to_statement_list(switch_stmt, &final_stmt_list);
+ Bstatement* ldef = break_label->get_definition(context);
+ statements.push_back(ldef);
- return final_stmt_list;
+ return context->backend()->statement_list(statements);
}
// Add the tree for CLAUSE to STMT_LIST.
void
-Select_clauses::add_clause_tree(Translate_context* context, int case_index,
- Select_clause* clause,
- Unnamed_label* bottom_label, tree* stmt_list)
-{
- tree label = create_artificial_label(clause->location());
- append_to_statement_list(build3(CASE_LABEL_EXPR, void_type_node,
- build_int_cst(sizetype, case_index),
- NULL_TREE, label),
- stmt_list);
- append_to_statement_list(clause->get_statements_tree(context), stmt_list);
+Select_clauses::add_clause_backend(
+ Translate_context* context,
+ source_location location,
+ int index,
+ int case_value,
+ Select_clause* clause,
+ Unnamed_label* bottom_label,
+ std::vector<std::vector<Bexpression*> > *cases,
+ std::vector<Bstatement*>* clauses)
+{
+ mpz_t ival;
+ mpz_init_set_ui(ival, case_value);
+ Expression* e = Expression::make_integer(&ival, NULL, location);
+ 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
? clause->location()
: clause->statements()->end_location());
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.
@@ -4266,8 +4300,9 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function,
tree
Select_statement::do_get_tree(Translate_context* context)
{
- return this->clauses_->get_tree(context, this->break_label(),
- this->location());
+ Bstatement* ret = this->clauses_->get_backend(context, this->break_label(),
+ this->location());
+ return stat_to_tree(ret);
}
// Make a select statement.
diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h
index 2436bb54aa8..1958bf9b947 100644
--- a/gcc/go/gofrontend/statements.h
+++ b/gcc/go/gofrontend/statements.h
@@ -678,9 +678,9 @@ class Select_clauses
bool
may_fall_through() const;
- // Return a tree implementing the select statement.
- tree
- get_tree(Translate_context*, Unnamed_label* break_label, source_location);
+ // Convert to the backend representation.
+ Bstatement*
+ get_backend(Translate_context*, Unnamed_label* break_label, source_location);
private:
// A single clause.
@@ -749,8 +749,8 @@ class Select_clauses
may_fall_through() const;
// Return a tree for the statements to execute.
- tree
- get_statements_tree(Translate_context*);
+ Bstatement*
+ get_statements_backend(Translate_context*);
private:
// The channel.
@@ -778,8 +778,10 @@ class Select_clauses
};
void
- add_clause_tree(Translate_context*, int, Select_clause*, Unnamed_label*,
- tree*);
+ add_clause_backend(Translate_context*, source_location, int index,
+ int case_value, Select_clause*, Unnamed_label*,
+ std::vector<std::vector<Bexpression*> >* cases,
+ std::vector<Bstatement*>* clauses);
typedef std::vector<Select_clause> Clauses;