aboutsummaryrefslogtreecommitdiff
path: root/gcc/go
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2011-04-06 23:07:13 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2011-04-06 23:07:13 +0000
commit8d0b03a22da97caa72c0e6e6c3020b87c06ef03a (patch)
tree023ebebfe6e01bf9532e434a4cd616d10b5c4872 /gcc/go
parentd17b0ae1cab1220ed4e43c8972bb962379ef1f7d (diff)
downloadgcc-8d0b03a22da97caa72c0e6e6c3020b87c06ef03a.zip
gcc-8d0b03a22da97caa72c0e6e6c3020b87c06ef03a.tar.gz
gcc-8d0b03a22da97caa72c0e6e6c3020b87c06ef03a.tar.bz2
Use backend interface for constant switch statements.
* go-gcc.cc (if_statement): Use build3_loc. (Gcc_backend::switch_statement): New function. (Gcc_backend::statement_list): New function. From-SVN: r172066
Diffstat (limited to 'gcc/go')
-rw-r--r--gcc/go/ChangeLog6
-rw-r--r--gcc/go/go-gcc.cc93
-rw-r--r--gcc/go/gofrontend/backend.h17
-rw-r--r--gcc/go/gofrontend/statements.cc213
-rw-r--r--gcc/go/gofrontend/statements.h23
5 files changed, 271 insertions, 81 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog
index ff56bfe..3ee5fb1 100644
--- a/gcc/go/ChangeLog
+++ b/gcc/go/ChangeLog
@@ -1,5 +1,11 @@
2011-04-06 Ian Lance Taylor <iant@google.com>
+ * go-gcc.cc (if_statement): Use build3_loc.
+ (Gcc_backend::switch_statement): New function.
+ (Gcc_backend::statement_list): New function.
+
+2011-04-06 Ian Lance Taylor <iant@google.com>
+
* go-gcc.cc (Gcc_backend::if_statement): New function.
(tree_to_stat): New function.
(expr_to_tree): Renamed from expression_to_tree.
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index de689f8..f9efb3c 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -180,6 +180,15 @@ class Gcc_backend : public Backend
if_statement(Bexpression* condition, Bstatement* then_block,
Bstatement* else_block, source_location);
+ Bstatement*
+ switch_statement(Bexpression* value,
+ const std::vector<std::vector<Bexpression*> >& cases,
+ const std::vector<Bstatement*>& statements,
+ source_location);
+
+ Bstatement*
+ statement_list(const std::vector<Bstatement*>&);
+
// Labels.
Blabel*
@@ -310,12 +319,90 @@ Gcc_backend::if_statement(Bexpression* condition, Bstatement* then_block,
|| then_tree == error_mark_node
|| else_tree == error_mark_node)
return this->make_statement(error_mark_node);
- tree ret = build3(COND_EXPR, void_type_node, cond_tree, then_tree,
- else_tree);
- SET_EXPR_LOCATION(ret, location);
+ tree ret = build3_loc(location, COND_EXPR, void_type_node, cond_tree,
+ then_tree, else_tree);
return this->make_statement(ret);
}
+// Switch.
+
+Bstatement*
+Gcc_backend::switch_statement(
+ Bexpression* value,
+ const std::vector<std::vector<Bexpression*> >& cases,
+ const std::vector<Bstatement*>& statements,
+ source_location switch_location)
+{
+ gcc_assert(cases.size() == statements.size());
+
+ tree stmt_list = NULL_TREE;
+ std::vector<std::vector<Bexpression*> >::const_iterator pc = cases.begin();
+ for (std::vector<Bstatement*>::const_iterator ps = statements.begin();
+ ps != statements.end();
+ ++ps, ++pc)
+ {
+ if (pc->empty())
+ {
+ source_location loc = (*ps != NULL
+ ? EXPR_LOCATION((*ps)->get_tree())
+ : UNKNOWN_LOCATION);
+ tree label = create_artificial_label(loc);
+ tree c = build3_loc(loc, CASE_LABEL_EXPR, void_type_node, NULL_TREE,
+ NULL_TREE, label);
+ append_to_statement_list(c, &stmt_list);
+ }
+ else
+ {
+ for (std::vector<Bexpression*>::const_iterator pcv = pc->begin();
+ pcv != pc->end();
+ ++pcv)
+ {
+ tree t = (*pcv)->get_tree();
+ if (t == error_mark_node)
+ return this->make_statement(error_mark_node);
+ source_location loc = EXPR_LOCATION(t);
+ tree label = create_artificial_label(loc);
+ tree c = build3_loc(loc, CASE_LABEL_EXPR, void_type_node,
+ (*pcv)->get_tree(), NULL_TREE, label);
+ append_to_statement_list(c, &stmt_list);
+ }
+ }
+
+ if (*ps != NULL)
+ {
+ tree t = (*ps)->get_tree();
+ if (t == error_mark_node)
+ return this->make_statement(error_mark_node);
+ append_to_statement_list(t, &stmt_list);
+ }
+ }
+
+ tree tv = value->get_tree();
+ if (tv == error_mark_node)
+ return this->make_statement(error_mark_node);
+ tree t = build3_loc(switch_location, SWITCH_EXPR, void_type_node,
+ tv, stmt_list, NULL_TREE);
+ return this->make_statement(t);
+}
+
+// List of statements.
+
+Bstatement*
+Gcc_backend::statement_list(const std::vector<Bstatement*>& statements)
+{
+ tree stmt_list = NULL_TREE;
+ for (std::vector<Bstatement*>::const_iterator p = statements.begin();
+ p != statements.end();
+ ++p)
+ {
+ tree t = (*p)->get_tree();
+ if (t == error_mark_node)
+ return this->make_statement(error_mark_node);
+ append_to_statement_list(t, &stmt_list);
+ }
+ return this->make_statement(stmt_list);
+}
+
// Make a label.
Blabel*
diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h
index a6c2426..01f3cfa 100644
--- a/gcc/go/gofrontend/backend.h
+++ b/gcc/go/gofrontend/backend.h
@@ -127,6 +127,23 @@ class Backend
if_statement(Bexpression* condition, Bstatement* then_block,
Bstatement* else_block, source_location) = 0;
+ // Create a switch statement where the case values are constants.
+ // CASES and STATEMENTS must have the same number of entries. If
+ // VALUE matches any of the list in CASES[i], which will all be
+ // integers, then STATEMENTS[i] is executed. STATEMENTS[i] will
+ // either end with a goto statement or will fall through into
+ // STATEMENTS[i + 1]. CASES[i] is empty for the default clause,
+ // which need not be last.
+ virtual Bstatement*
+ switch_statement(Bexpression* value,
+ const std::vector<std::vector<Bexpression*> >& cases,
+ const std::vector<Bstatement*>& statements,
+ source_location) = 0;
+
+ // Create a single statement from a list of statements.
+ virtual Bstatement*
+ statement_list(const std::vector<Bstatement*>&) = 0;
+
// Labels.
// Create a new label. NAME will be empty if this is a label
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.
diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h
index 986d72b..826cd0c 100644
--- a/gcc/go/gofrontend/statements.h
+++ b/gcc/go/gofrontend/statements.h
@@ -39,6 +39,8 @@ class Case_clauses;
class Type_case_clauses;
class Select_clauses;
class Typed_identifier_list;
+class Bexpression;
+class Bstatement;
// This class is used to traverse assignments made by a statement
// which makes assignments.
@@ -1162,13 +1164,18 @@ class Case_clauses
// Return the body of a SWITCH_EXPR when all the clauses are
// constants.
- tree
- get_constant_tree(Translate_context*, Unnamed_label* break_label) const;
+ void
+ get_backend(Translate_context*, Unnamed_label* break_label,
+ std::vector<std::vector<Bexpression*> >* all_cases,
+ std::vector<Bstatement*>* all_statements) const;
private:
// For a constant tree we need to keep a record of constants we have
// already seen. Note that INTEGER_CST trees are interned.
- typedef Unordered_set(tree) Case_constants;
+ class Hash_integer_value;
+ class Eq_integer_value;
+ typedef Unordered_set_hash(Expression*, Hash_integer_value,
+ Eq_integer_value) Case_constants;
// One case clause.
class Case_clause
@@ -1226,11 +1233,11 @@ class Case_clauses
bool
may_fall_through() const;
- // Build up the body of a SWITCH_EXPR when the case expressions
- // are constant.
- void
- get_constant_tree(Translate_context*, Unnamed_label* break_label,
- Case_constants* case_constants, tree* stmt_list) const;
+ // Convert the case values and statements to the backend
+ // representation.
+ Bstatement*
+ get_backend(Translate_context*, Unnamed_label* break_label,
+ Case_constants*, std::vector<Bexpression*>* cases) const;
private:
// The list of case expressions.