aboutsummaryrefslogtreecommitdiff
path: root/gcc/go/gofrontend
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/go/gofrontend')
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/export.cc23
-rw-r--r--gcc/go/gofrontend/export.h13
-rw-r--r--gcc/go/gofrontend/import.cc46
-rw-r--r--gcc/go/gofrontend/import.h14
-rw-r--r--gcc/go/gofrontend/statements.cc204
-rw-r--r--gcc/go/gofrontend/statements.h44
7 files changed, 321 insertions, 25 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index 05959f2..9dfa067 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-3f7dcb98df3ce1d4e02d0072fd21e70dc08351db
+11d96c36198b75b0485d16524d521e558cf03312
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
diff --git a/gcc/go/gofrontend/export.cc b/gcc/go/gofrontend/export.cc
index 0890b09..a48ca07 100644
--- a/gcc/go/gofrontend/export.cc
+++ b/gcc/go/gofrontend/export.cc
@@ -1326,3 +1326,26 @@ Export_function_body::temporary_index(const Temporary_statement* temp)
go_assert(p != this->temporary_indexes_.end());
return p->second;
}
+
+// Return the index of an unnamed label. If it doesn't already have
+// an index, give it one.
+
+unsigned int
+Export_function_body::unnamed_label_index(const Unnamed_label* label)
+{
+ unsigned int next = this->next_label_index_;
+ std::pair<const Unnamed_label*, unsigned int> val(label, next);
+ std::pair<Unordered_map(const Unnamed_label*, unsigned int)::iterator,
+ bool> ins =
+ this->label_indexes_.insert(val);
+ if (!ins.second)
+ return ins.first->second;
+ else
+ {
+ if (next > 0x7fffffff)
+ go_error_at(label->location(),
+ "too many unnamed labels in export data");
+ ++this->next_label_index_;
+ return next;
+ }
+}
diff --git a/gcc/go/gofrontend/export.h b/gcc/go/gofrontend/export.h
index 92d0180..910b1db 100644
--- a/gcc/go/gofrontend/export.h
+++ b/gcc/go/gofrontend/export.h
@@ -21,6 +21,7 @@ class Package;
class Import_init_set;
class Backend;
class Temporary_statement;
+class Unnamed_label;
// Codes used for the builtin types. These are all negative to make
// them easily distinct from the codes assigned by Export::write_type.
@@ -309,7 +310,8 @@ class Export_function_body : public String_dump
public:
Export_function_body(Export* exp, int indent)
: exp_(exp), body_(), type_context_(NULL), next_temporary_index_(0),
- temporary_indexes_(), indent_(indent)
+ temporary_indexes_(), next_label_index_(0), label_indexes_(),
+ indent_(indent)
{ }
// Write a character to the body.
@@ -373,6 +375,11 @@ class Export_function_body : public String_dump
unsigned int
temporary_index(const Temporary_statement*);
+ // Return the index of an unnamed label. If it doesn't already have
+ // an index, give it one.
+ unsigned int
+ unnamed_label_index(const Unnamed_label*);
+
// Return a reference to the completed body.
const std::string&
body() const
@@ -389,6 +396,10 @@ class Export_function_body : public String_dump
unsigned int next_temporary_index_;
// Map temporary statements to indexes.
Unordered_map(const Temporary_statement*, unsigned int) temporary_indexes_;
+ // Index to give to the next unnamed label.
+ unsigned int next_label_index_;
+ // Map unnamed labels to indexes.
+ Unordered_map(const Unnamed_label*, unsigned int) label_indexes_;
// Current indentation level: the number of spaces before each statement.
int indent_;
};
diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc
index 70e92ab..02c1c48 100644
--- a/gcc/go/gofrontend/import.cc
+++ b/gcc/go/gofrontend/import.cc
@@ -1612,6 +1612,19 @@ Import_function_body::read_type()
return type;
}
+// Return the next size to use for a vector mapping indexes to values.
+
+size_t
+Import_function_body::next_size(size_t have)
+{
+ if (have == 0)
+ return 8;
+ else if (have < 256)
+ return have * 2;
+ else
+ return have + 64;
+}
+
// Record the index of a temporary statement.
void
@@ -1619,16 +1632,11 @@ Import_function_body::record_temporary(Temporary_statement* temp,
unsigned int idx)
{
size_t have = this->temporaries_.size();
- if (static_cast<size_t>(idx) >= have)
+ while (static_cast<size_t>(idx) >= have)
{
- size_t want;
- if (have == 0)
- want = 8;
- else if (have < 256)
- want = have * 2;
- else
- want = have + 64;
+ size_t want = Import_function_body::next_size(have);
this->temporaries_.resize(want, NULL);
+ have = want;
}
this->temporaries_[idx] = temp;
}
@@ -1642,3 +1650,25 @@ Import_function_body::temporary_statement(unsigned int idx)
return NULL;
return this->temporaries_[idx];
}
+
+// Return an unnamed label given an index, defining the label if we
+// haven't seen it already.
+
+Unnamed_label*
+Import_function_body::unnamed_label(unsigned int idx, Location loc)
+{
+ size_t have = this->labels_.size();
+ while (static_cast<size_t>(idx) >= have)
+ {
+ size_t want = Import_function_body::next_size(have);
+ this->labels_.resize(want, NULL);
+ have = want;
+ }
+ Unnamed_label* label = this->labels_[idx];
+ if (label == NULL)
+ {
+ label = new Unnamed_label(loc);
+ this->labels_[idx] = label;
+ }
+ return label;
+}
diff --git a/gcc/go/gofrontend/import.h b/gcc/go/gofrontend/import.h
index 4afeb4a..db51f72 100644
--- a/gcc/go/gofrontend/import.h
+++ b/gcc/go/gofrontend/import.h
@@ -18,6 +18,8 @@ class Named_object;
class Named_type;
class Expression;
class Import_function_body;
+class Temporary_statement;
+class Unnamed_label;
// Expressions can be imported either directly from import data (for
// simple constant expressions that can appear in a const declaration
@@ -587,7 +589,7 @@ class Import_function_body : public Import_expression
const std::string& body, size_t off, Block* block,
int indent)
: gogo_(gogo), imp_(imp), named_object_(named_object), body_(body),
- off_(off), block_(block), indent_(indent), temporaries_(),
+ off_(off), block_(block), indent_(indent), temporaries_(), labels_(),
saw_error_(false)
{ }
@@ -704,6 +706,11 @@ class Import_function_body : public Import_expression
Temporary_statement*
temporary_statement(unsigned int);
+ // Return an unnamed label given an index, defining the label if we
+ // haven't seen it already.
+ Unnamed_label*
+ unnamed_label(unsigned int, Location);
+
// Implement Import_expression.
Import_function_body*
ifb()
@@ -730,6 +737,9 @@ class Import_function_body : public Import_expression
{ this->saw_error_ = true; }
private:
+ static size_t
+ next_size(size_t);
+
// The IR.
Gogo* gogo_;
// The importer.
@@ -747,6 +757,8 @@ class Import_function_body : public Import_expression
int indent_;
// Temporary statements by index.
std::vector<Temporary_statement*> temporaries_;
+ // Unnamed labels by index.
+ std::vector<Unnamed_label*> labels_;
// Whether we've seen an error. Used to avoid reporting excess
// errors.
bool saw_error_;
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index f680a0a..9ab1172 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -129,10 +129,15 @@ Statement::import_statement(Import_function_body* ifb, Location loc)
{
if (ifb->match_c_string("{"))
{
- Block* block = Block_statement::do_import(ifb, loc);
+ bool is_lowered_for_statement;
+ Block* block = Block_statement::do_import(ifb, loc,
+ &is_lowered_for_statement);
if (block == NULL)
return Statement::make_error_statement(loc);
- return Statement::make_block_statement(block, loc);
+ Block_statement* s = Statement::make_block_statement(block, loc);
+ if (is_lowered_for_statement)
+ s->set_is_lowered_for_statement();
+ return s;
}
else if (ifb->match_c_string("return"))
{
@@ -147,6 +152,10 @@ Statement::import_statement(Import_function_body* ifb, Location loc)
return Variable_declaration_statement::do_import(ifb, loc);
else if (ifb->match_c_string("if "))
return If_statement::do_import(ifb, loc);
+ else if (ifb->match_c_string(":"))
+ return Label_statement::do_import(ifb, loc);
+ else if (ifb->match_c_string("goto "))
+ return Goto_statement::do_import(ifb, loc);
Expression* lhs = Expression::import_expression(ifb, loc);
ifb->require_c_string(" = ");
@@ -2109,15 +2118,20 @@ Statement::make_statement(Expression* expr, bool is_ignored)
void
Block_statement::do_export_statement(Export_function_body* efb)
{
- Block_statement::export_block(efb, this->block_);
+ Block_statement::export_block(efb, this->block_,
+ this->is_lowered_for_statement_);
}
void
-Block_statement::export_block(Export_function_body* efb, Block* block)
+Block_statement::export_block(Export_function_body* efb, Block* block,
+ bool is_lowered_for_statement)
{
// We are already indented to the right position.
char buf[50];
- snprintf(buf, sizeof buf, "{ //%d\n",
+ efb->write_c_string("{");
+ if (is_lowered_for_statement)
+ efb->write_c_string(" /*for*/");
+ snprintf(buf, sizeof buf, " //%d\n",
Linemap::location_to_line(block->start_location()));
efb->write_c_string(buf);
@@ -2134,9 +2148,16 @@ Block_statement::export_block(Export_function_body* efb, Block* block)
// Import a block statement, returning the block.
Block*
-Block_statement::do_import(Import_function_body* ifb, Location loc)
+Block_statement::do_import(Import_function_body* ifb, Location loc,
+ bool* is_lowered_for_statement)
{
go_assert(ifb->match_c_string("{"));
+ *is_lowered_for_statement = false;
+ if (ifb->match_c_string(" /*for*/"))
+ {
+ ifb->advance(8);
+ *is_lowered_for_statement = true;
+ }
size_t nl = ifb->body().find('\n', ifb->off());
if (nl == std::string::npos)
{
@@ -2176,7 +2197,7 @@ Block_statement::do_dump_statement(Ast_dump_context*) const
// Make a block statement.
-Statement*
+Block_statement*
Statement::make_block_statement(Block* block, Location location)
{
return new Block_statement(block, location);
@@ -3344,6 +3365,61 @@ Goto_statement::do_get_backend(Translate_context* context)
return context->backend()->goto_statement(blabel, this->location());
}
+// Export a goto statement.
+
+void
+Goto_statement::do_export_statement(Export_function_body *efb)
+{
+ efb->write_c_string("goto ");
+ efb->write_string(this->label_->name());
+}
+
+// Import a goto or goto unnamed statement.
+
+Statement*
+Goto_statement::do_import(Import_function_body* ifb, Location loc)
+{
+ ifb->require_c_string("goto ");
+ std::string id = ifb->read_identifier();
+ if (id[0] != '$')
+ {
+ Function* fn = ifb->function()->func_value();
+ Label* label = fn->add_label_reference(ifb->gogo(), id, loc, false);
+ return Statement::make_goto_statement(label, loc);
+ }
+ else
+ {
+ if (id[1] != 'l')
+ {
+ if (!ifb->saw_error())
+ go_error_at(loc,
+ ("invalid export data for %qs: "
+ "bad unnamed label at %lu"),
+ ifb->name().c_str(),
+ static_cast<unsigned long>(ifb->off()));
+ ifb->set_saw_error();
+ return Statement::make_error_statement(loc);
+ }
+ const char* p = id.c_str();
+ char* end;
+ long idx = strtol(p + 2, &end, 10);
+ if (*end != '\0' || idx > 0x7fffffff)
+ {
+ if (!ifb->saw_error())
+ go_error_at(loc,
+ ("invalid export data for %qs: "
+ "bad unnamed label index at %lu"),
+ ifb->name().c_str(),
+ static_cast<unsigned long>(ifb->off()));
+ ifb->set_saw_error();
+ return Statement::make_error_statement(loc);
+ }
+
+ Unnamed_label* label = ifb->unnamed_label(idx, loc);
+ return Statement::make_goto_unnamed_statement(label, loc);
+ }
+}
+
// Dump the AST representation for a goto statement.
void
@@ -3377,6 +3453,17 @@ Goto_unnamed_statement::do_get_backend(Translate_context* context)
return this->label_->get_goto(context, this->location());
}
+// Export a goto unnamed statement.
+
+void
+Goto_unnamed_statement::do_export_statement(Export_function_body *efb)
+{
+ unsigned int index = efb->unnamed_label_index(this->label_);
+ char buf[100];
+ snprintf(buf, sizeof buf, "goto $l%u", index);
+ efb->write_c_string(buf);
+}
+
// Dump the AST representation for an unnamed goto statement
void
@@ -3424,6 +3511,64 @@ Label_statement::do_get_backend(Translate_context* context)
return context->backend()->label_definition_statement(blabel);
}
+// Export a label.
+
+void
+Label_statement::do_export_statement(Export_function_body* efb)
+{
+ if (this->label_->is_dummy_label())
+ return;
+ // We use a leading colon, not a trailing one, to simplify import.
+ efb->write_c_string(":");
+ efb->write_string(this->label_->name());
+}
+
+// Import a label or an unnamed label.
+
+Statement*
+Label_statement::do_import(Import_function_body* ifb, Location loc)
+{
+ ifb->require_c_string(":");
+ std::string id = ifb->read_identifier();
+ if (id[0] != '$')
+ {
+ Function* fn = ifb->function()->func_value();
+ Label* label = fn->add_label_definition(ifb->gogo(), id, loc);
+ return Statement::make_label_statement(label, loc);
+ }
+ else
+ {
+ if (id[1] != 'l')
+ {
+ if (!ifb->saw_error())
+ go_error_at(loc,
+ ("invalid export data for %qs: "
+ "bad unnamed label at %lu"),
+ ifb->name().c_str(),
+ static_cast<unsigned long>(ifb->off()));
+ ifb->set_saw_error();
+ return Statement::make_error_statement(loc);
+ }
+ const char* p = id.c_str();
+ char* end;
+ long idx = strtol(p + 2, &end, 10);
+ if (*end != '\0' || idx > 0x7fffffff)
+ {
+ if (!ifb->saw_error())
+ go_error_at(loc,
+ ("invalid export data for %qs: "
+ "bad unnamed label index at %lu"),
+ ifb->name().c_str(),
+ static_cast<unsigned long>(ifb->off()));
+ ifb->set_saw_error();
+ return Statement::make_error_statement(loc);
+ }
+
+ Unnamed_label* label = ifb->unnamed_label(idx, loc);
+ return Statement::make_unnamed_label_statement(label);
+ }
+}
+
// Dump the AST for a label definition statement.
void
@@ -3462,6 +3607,18 @@ Unnamed_label_statement::do_get_backend(Translate_context* context)
return this->label_->get_definition(context);
}
+// Export an unnamed label.
+
+void
+Unnamed_label_statement::do_export_statement(Export_function_body* efb)
+{
+ unsigned int index = efb->unnamed_label_index(this->label_);
+ char buf[50];
+ // We use a leading colon, not a trailing one, to simplify import.
+ snprintf(buf, sizeof buf, ":$l%u", index);
+ efb->write_c_string(buf);
+}
+
// Dump the AST representation for an unnamed label definition statement.
void
@@ -3557,11 +3714,11 @@ If_statement::do_export_statement(Export_function_body* efb)
efb->write_c_string("if ");
this->cond_->export_expression(efb);
efb->write_c_string(" ");
- Block_statement::export_block(efb, this->then_block_);
+ Block_statement::export_block(efb, this->then_block_, false);
if (this->else_block_ != NULL)
{
efb->write_c_string(" else ");
- Block_statement::export_block(efb, this->else_block_);
+ Block_statement::export_block(efb, this->else_block_, false);
}
}
@@ -3588,9 +3745,22 @@ If_statement::do_import(Import_function_body* ifb, Location loc)
return Statement::make_error_statement(loc);
}
- Block* then_block = Block_statement::do_import(ifb, loc);
+ bool is_lowered_for_statement;
+ Block* then_block = Block_statement::do_import(ifb, loc,
+ &is_lowered_for_statement);
if (then_block == NULL)
return Statement::make_error_statement(loc);
+ if (is_lowered_for_statement)
+ {
+ if (!ifb->saw_error())
+ go_error_at(ifb->location(),
+ ("import error for %qs: "
+ "unexpected lowered for in if statement at %lu"),
+ ifb->name().c_str(),
+ static_cast<unsigned long>(ifb->off()));
+ ifb->set_saw_error();
+ return Statement::make_error_statement(loc);
+ }
Block* else_block = NULL;
if (ifb->match_c_string(" else "))
@@ -3608,9 +3778,21 @@ If_statement::do_import(Import_function_body* ifb, Location loc)
return Statement::make_error_statement(loc);
}
- else_block = Block_statement::do_import(ifb, loc);
+ else_block = Block_statement::do_import(ifb, loc,
+ &is_lowered_for_statement);
if (else_block == NULL)
return Statement::make_error_statement(loc);
+ if (is_lowered_for_statement)
+ {
+ if (!ifb->saw_error())
+ go_error_at(ifb->location(),
+ ("import error for %qs: "
+ "unexpected lowered for in if statement at %lu"),
+ ifb->name().c_str(),
+ static_cast<unsigned long>(ifb->off()));
+ ifb->set_saw_error();
+ return Statement::make_error_statement(loc);
+ }
}
return Statement::make_if_statement(cond, then_block, else_block, loc);
diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h
index 3e85243..432da30 100644
--- a/gcc/go/gofrontend/statements.h
+++ b/gcc/go/gofrontend/statements.h
@@ -187,7 +187,7 @@ class Statement
// Make a block statement from a Block. This is an embedded list of
// statements which may also include variable definitions.
- static Statement*
+ static Block_statement*
make_block_statement(Block*, Location);
// Make an increment statement.
@@ -956,11 +956,13 @@ class Block_statement : public Statement
// Export a block for a block statement.
static void
- export_block(Export_function_body*, Block*);
+ export_block(Export_function_body*, Block*, bool is_lowered_for_statement);
// Import a block statement, returning the block.
+ // *IS_LOWERED_FOR_STATEMENT reports whether this block statement
+ // was lowered from a for statement.
static Block*
- do_import(Import_function_body*, Location);
+ do_import(Import_function_body*, Location, bool* is_lowered_for_statement);
protected:
int
@@ -1409,6 +1411,10 @@ class Goto_statement : public Statement
label() const
{ return this->label_; }
+ // Import a goto statement.
+ static Statement*
+ do_import(Import_function_body*, Location);
+
protected:
int
do_traverse(Traverse*);
@@ -1423,6 +1429,13 @@ class Goto_statement : public Statement
Bstatement*
do_get_backend(Translate_context*);
+ int
+ do_inlining_cost()
+ { return 5; }
+
+ void
+ do_export_statement(Export_function_body*);
+
void
do_dump_statement(Ast_dump_context*) const;
@@ -1455,6 +1468,13 @@ class Goto_unnamed_statement : public Statement
Bstatement*
do_get_backend(Translate_context* context);
+ int
+ do_inlining_cost()
+ { return 5; }
+
+ void
+ do_export_statement(Export_function_body*);
+
void
do_dump_statement(Ast_dump_context*) const;
@@ -1477,6 +1497,10 @@ class Label_statement : public Statement
label() const
{ return this->label_; }
+ // Import a label or unnamed label.
+ static Statement*
+ do_import(Import_function_body*, Location);
+
protected:
int
do_traverse(Traverse*);
@@ -1484,6 +1508,13 @@ class Label_statement : public Statement
Bstatement*
do_get_backend(Translate_context*);
+ int
+ do_inlining_cost()
+ { return 1; }
+
+ void
+ do_export_statement(Export_function_body*);
+
void
do_dump_statement(Ast_dump_context*) const;
@@ -1506,6 +1537,13 @@ class Unnamed_label_statement : public Statement
Bstatement*
do_get_backend(Translate_context* context);
+ int
+ do_inlining_cost()
+ { return 1; }
+
+ void
+ do_export_statement(Export_function_body*);
+
void
do_dump_statement(Ast_dump_context*) const;