aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2019-06-10 21:02:20 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2019-06-10 21:02:20 +0000
commitfc917b42658000f0c4dc87f6602336eef899fadf (patch)
treea86e9441caa7fe457bf8274f297f2267ad7a5f0a
parentd480455f2ddc3b89d8547969be9cda939c41da56 (diff)
downloadgcc-fc917b42658000f0c4dc87f6602336eef899fadf.zip
gcc-fc917b42658000f0c4dc87f6602336eef899fadf.tar.gz
gcc-fc917b42658000f0c4dc87f6602336eef899fadf.tar.bz2
compiler: permit inlining functions with labels and goto statements
This permits inlining functions with for loops and some switches, as they are lowered to if and goto statements before exporting them. This by itself only adds three new inlinable functions in the standard library: sort.Search, context.(*emptyCtx).String, and cmd/go/internal/work.(*Builder).disableBuildID. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/181197 From-SVN: r272131
-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;