aboutsummaryrefslogtreecommitdiff
path: root/gcc/go/gofrontend/statements.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/go/gofrontend/statements.cc')
-rw-r--r--gcc/go/gofrontend/statements.cc213
1 files changed, 143 insertions, 70 deletions
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index 131001a..f84b2d4 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -2934,6 +2934,55 @@ Statement::make_if_statement(Expression* cond, Block* then_block,
return new If_statement(cond, then_block, else_block, location);
}
+// Class Case_clauses::Hash_integer_value.
+
+class Case_clauses::Hash_integer_value
+{
+ public:
+ size_t
+ operator()(Expression*) const;
+};
+
+size_t
+Case_clauses::Hash_integer_value::operator()(Expression* pe) const
+{
+ Type* itype;
+ mpz_t ival;
+ mpz_init(ival);
+ if (!pe->integer_constant_value(true, ival, &itype))
+ gcc_unreachable();
+ size_t ret = mpz_get_ui(ival);
+ mpz_clear(ival);
+ return ret;
+}
+
+// Class Case_clauses::Eq_integer_value.
+
+class Case_clauses::Eq_integer_value
+{
+ public:
+ bool
+ operator()(Expression*, Expression*) const;
+};
+
+bool
+Case_clauses::Eq_integer_value::operator()(Expression* a, Expression* b) const
+{
+ Type* atype;
+ Type* btype;
+ mpz_t aval;
+ mpz_t bval;
+ mpz_init(aval);
+ mpz_init(bval);
+ if (!a->integer_constant_value(true, aval, &atype)
+ || !b->integer_constant_value(true, bval, &btype))
+ gcc_unreachable();
+ bool ret = mpz_cmp(aval, bval) == 0;
+ mpz_clear(aval);
+ mpz_clear(bval);
+ return ret;
+}
+
// Class Case_clauses::Case_clause.
// Traversal.
@@ -3090,76 +3139,82 @@ Case_clauses::Case_clause::may_fall_through() const
return this->statements_->may_fall_through();
}
-// Build up the body of a SWITCH_EXPR.
+// Convert the case values and statements to the backend
+// representation. BREAK_LABEL is the label which break statements
+// should branch to. CASE_CONSTANTS is used to detect duplicate
+// constants. *CASES should be passed as an empty vector; the values
+// for this case will be added to it. If this is the default case,
+// *CASES will remain empty. This returns the statement to execute if
+// one of these cases is selected.
-void
-Case_clauses::Case_clause::get_constant_tree(Translate_context* context,
- Unnamed_label* break_label,
- Case_constants* case_constants,
- tree* stmt_list) const
+Bstatement*
+Case_clauses::Case_clause::get_backend(Translate_context* context,
+ Unnamed_label* break_label,
+ Case_constants* case_constants,
+ std::vector<Bexpression*>* cases) const
{
if (this->cases_ != NULL)
{
+ gcc_assert(!this->is_default_);
for (Expression_list::const_iterator p = this->cases_->begin();
p != this->cases_->end();
++p)
{
- Type* itype;
- mpz_t ival;
- mpz_init(ival);
- if (!(*p)->integer_constant_value(true, ival, &itype))
+ Expression* e = *p;
+ if (e->classification() != Expression::EXPRESSION_INTEGER)
{
- // Something went wrong. This can happen with a
- // negative constant and an unsigned switch value.
- gcc_assert(saw_errors());
- continue;
- }
- gcc_assert(itype != NULL);
- tree type_tree = itype->get_tree(context->gogo());
- tree val = Expression::integer_constant_tree(ival, type_tree);
- mpz_clear(ival);
-
- if (val != error_mark_node)
- {
- gcc_assert(TREE_CODE(val) == INTEGER_CST);
-
- std::pair<Case_constants::iterator, bool> ins =
- case_constants->insert(val);
- if (!ins.second)
+ Type* itype;
+ mpz_t ival;
+ mpz_init(ival);
+ if (!(*p)->integer_constant_value(true, ival, &itype))
{
- // Value was already present.
- warning_at(this->location_, 0,
- "duplicate case value will never match");
+ // Something went wrong. This can happen with a
+ // negative constant and an unsigned switch value.
+ gcc_assert(saw_errors());
continue;
}
+ gcc_assert(itype != NULL);
+ e = Expression::make_integer(&ival, itype, e->location());
+ mpz_clear(ival);
+ }
- tree label = create_artificial_label(this->location_);
- append_to_statement_list(build3(CASE_LABEL_EXPR, void_type_node,
- val, NULL_TREE, label),
- stmt_list);
+ std::pair<Case_constants::iterator, bool> ins =
+ case_constants->insert(e);
+ if (!ins.second)
+ {
+ // Value was already present.
+ error_at(this->location_, "duplicate case in switch");
+ continue;
}
+
+ tree case_tree = e->get_tree(context);
+ Bexpression* case_expr = tree_to_expr(case_tree);
+ cases->push_back(case_expr);
}
}
- if (this->is_default_)
- {
- tree label = create_artificial_label(this->location_);
- append_to_statement_list(build3(CASE_LABEL_EXPR, void_type_node,
- NULL_TREE, NULL_TREE, label),
- stmt_list);
- }
+ Bstatement* statements;
+ if (this->statements_ == NULL)
+ statements = NULL;
+ else
+ statements = tree_to_stat(this->statements_->get_tree(context));
- if (this->statements_ != NULL)
- {
- tree block_tree = this->statements_->get_tree(context);
- if (block_tree != error_mark_node)
- append_to_statement_list(block_tree, stmt_list);
- }
+ Bstatement* break_stat;
+ if (this->is_fallthrough_)
+ break_stat = NULL;
+ else
+ break_stat = break_label->get_goto(context, this->location_);
- if (!this->is_fallthrough_)
+ if (statements == NULL)
+ return break_stat;
+ else if (break_stat == NULL)
+ return statements;
+ else
{
- Bstatement* g = break_label->get_goto(context, this->location_);
- append_to_statement_list(stat_to_tree(g), stmt_list);
+ std::vector<Bstatement*> list(2);
+ list[0] = statements;
+ list[1] = break_stat;
+ return context->backend()->statement_list(list);
}
}
@@ -3297,20 +3352,32 @@ Case_clauses::may_fall_through() const
return !found_default;
}
-// Return a tree when all case expressions are constants.
+// Convert the cases to the backend representation. This sets
+// *ALL_CASES and *ALL_STATEMENTS.
-tree
-Case_clauses::get_constant_tree(Translate_context* context,
- Unnamed_label* break_label) const
+void
+Case_clauses::get_backend(Translate_context* context,
+ Unnamed_label* break_label,
+ std::vector<std::vector<Bexpression*> >* all_cases,
+ std::vector<Bstatement*>* all_statements) const
{
Case_constants case_constants;
- tree stmt_list = NULL_TREE;
+
+ size_t c = this->clauses_.size();
+ all_cases->resize(c);
+ all_statements->resize(c);
+
+ size_t i = 0;
for (Clauses::const_iterator p = this->clauses_.begin();
p != this->clauses_.end();
- ++p)
- p->get_constant_tree(context, break_label, &case_constants,
- &stmt_list);
- return stmt_list;
+ ++p, ++i)
+ {
+ std::vector<Bexpression*> cases;
+ Bstatement* stat = p->get_backend(context, break_label, &case_constants,
+ &cases);
+ (*all_cases)[i].swap(cases);
+ (*all_statements)[i] = stat;
+ }
}
// A constant switch statement. A Switch_statement is lowered to this
@@ -3401,22 +3468,28 @@ tree
Constant_switch_statement::do_get_tree(Translate_context* context)
{
tree switch_val_tree = this->val_->get_tree(context);
+ Bexpression* switch_val_expr = tree_to_expr(switch_val_tree);
Unnamed_label* break_label = this->break_label_;
if (break_label == NULL)
break_label = new Unnamed_label(this->location());
- tree stmt_list = NULL_TREE;
- tree s = build3(SWITCH_EXPR, void_type_node, switch_val_tree,
- this->clauses_->get_constant_tree(context, break_label),
- NULL_TREE);
- SET_EXPR_LOCATION(s, this->location());
- append_to_statement_list(s, &stmt_list);
-
- Bstatement* ldef = break_label->get_definition(context);
- append_to_statement_list(stat_to_tree(ldef), &stmt_list);
-
- return stmt_list;
+ std::vector<std::vector<Bexpression*> > all_cases;
+ std::vector<Bstatement*> all_statements;
+ this->clauses_->get_backend(context, break_label, &all_cases,
+ &all_statements);
+
+ Bstatement* switch_statement;
+ switch_statement = context->backend()->switch_statement(switch_val_expr,
+ all_cases,
+ all_statements,
+ this->location());
+
+ std::vector<Bstatement*> stats(2);
+ stats[0] = switch_statement;
+ stats[1] = break_label->get_definition(context);
+ Bstatement* ret = context->backend()->statement_list(stats);
+ return stat_to_tree(ret);
}
// Class Switch_statement.