From: Ian Lance Taylor Date: Fri, 15 Apr 2011 04:10:08 +0000 (+0000) Subject: Use the backend interface for select statements. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f54d331e46f11ac7b5876a22b30ba52e69985a48;p=gcc.git Use the backend interface for select statements. From-SVN: r172468 --- 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 + + * go-gcc.cc (Backend::error_statement): New function. + 2011-04-13 Ian Lance Taylor * 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 @@ -166,6 +166,10 @@ class Gcc_backend : public Backend // Statements. + Bstatement* + error_statement() + { return this->make_statement(error_mark_node); } + Bstatement* expression_statement(Bexpression*); 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 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 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 > cases; + std::vector 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 > *cases, + std::vector* 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 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 >* cases, + std::vector* clauses); typedef std::vector Clauses;