aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2019-06-06 23:34:00 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2019-06-06 23:34:00 +0000
commit93cbebde76ac7de2d69b223d99acb39e0370687f (patch)
tree66c133d573a219583b5c460b329b900c18ee0ac6 /gcc
parent5e664ed0938357392823d2a43be8a196526dd97c (diff)
downloadgcc-93cbebde76ac7de2d69b223d99acb39e0370687f.zip
gcc-93cbebde76ac7de2d69b223d99acb39e0370687f.tar.gz
gcc-93cbebde76ac7de2d69b223d99acb39e0370687f.tar.bz2
compiler: permit inlining temporary statements and references
This increases the number of inlinable functions from 439 to 455. An example is math/bits.Mul32, which uses temporaries to handle the tuple assignment. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/180837 From-SVN: r272022
Diffstat (limited to 'gcc')
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/export.cc35
-rw-r--r--gcc/go/gofrontend/export.h16
-rw-r--r--gcc/go/gofrontend/expressions.cc55
-rw-r--r--gcc/go/gofrontend/expressions.h10
-rw-r--r--gcc/go/gofrontend/import.cc31
-rw-r--r--gcc/go/gofrontend/import.h13
-rw-r--r--gcc/go/gofrontend/statements.cc88
-rw-r--r--gcc/go/gofrontend/statements.h11
9 files changed, 255 insertions, 6 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index 2b75255..4d455ea 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-bc7374913367fba9b10dc284af87eb539fb6c5b2
+015785baa74629baafe520367b9c71707366c6eb
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 824f821..0890b09 100644
--- a/gcc/go/gofrontend/export.cc
+++ b/gcc/go/gofrontend/export.cc
@@ -6,15 +6,14 @@
#include "go-system.h"
-#include "go-sha1.h"
#include "go-c.h"
-
+#include "go-diagnostics.h"
+#include "go-sha1.h"
#include "gogo.h"
#include "types.h"
#include "expressions.h"
#include "statements.h"
#include "export.h"
-
#include "go-linemap.h"
#include "backend.h"
@@ -1297,3 +1296,33 @@ Stream_to_section::do_write(const char* bytes, size_t length)
{
this->backend_->write_export_data (bytes, length);
}
+
+// Class Export_function_body.
+
+// Record a temporary statement.
+
+unsigned int
+Export_function_body::record_temporary(const Temporary_statement* temp)
+{
+ unsigned int ret = this->next_temporary_index_;
+ if (ret > 0x7fffffff)
+ go_error_at(temp->location(),
+ "too many temporary statements in export data");
+ ++this->next_temporary_index_;
+ std::pair<const Temporary_statement*, unsigned int> val(temp, ret);
+ std::pair<Unordered_map(const Temporary_statement*, unsigned int)::iterator,
+ bool> ins = this->temporary_indexes_.insert(val);
+ go_assert(ins.second);
+ return ret;
+}
+
+// Return the index of a temporary statement.
+
+unsigned int
+Export_function_body::temporary_index(const Temporary_statement* temp)
+{
+ Unordered_map(const Temporary_statement*, unsigned int)::const_iterator p =
+ this->temporary_indexes_.find(temp);
+ go_assert(p != this->temporary_indexes_.end());
+ return p->second;
+}
diff --git a/gcc/go/gofrontend/export.h b/gcc/go/gofrontend/export.h
index e3932d4..92d0180 100644
--- a/gcc/go/gofrontend/export.h
+++ b/gcc/go/gofrontend/export.h
@@ -20,6 +20,7 @@ class Type;
class Package;
class Import_init_set;
class Backend;
+class Temporary_statement;
// Codes used for the builtin types. These are all negative to make
// them easily distinct from the codes assigned by Export::write_type.
@@ -307,7 +308,8 @@ class Export_function_body : public String_dump
{
public:
Export_function_body(Export* exp, int indent)
- : exp_(exp), type_context_(NULL), indent_(indent)
+ : exp_(exp), body_(), type_context_(NULL), next_temporary_index_(0),
+ temporary_indexes_(), indent_(indent)
{ }
// Write a character to the body.
@@ -363,6 +365,14 @@ class Export_function_body : public String_dump
package_index(const Package* p) const
{ return this->exp_->package_index(p); }
+ // Record a temporary statement and return its index.
+ unsigned int
+ record_temporary(const Temporary_statement*);
+
+ // Return the index of a temporary statement.
+ unsigned int
+ temporary_index(const Temporary_statement*);
+
// Return a reference to the completed body.
const std::string&
body() const
@@ -375,6 +385,10 @@ class Export_function_body : public String_dump
std::string body_;
// Current type context. Used to avoid duplicate type conversions.
Type* type_context_;
+ // Index to give to next temporary statement.
+ unsigned int next_temporary_index_;
+ // Map temporary statements to indexes.
+ Unordered_map(const Temporary_statement*, unsigned int) temporary_indexes_;
// Current indentation level: the number of spaces before each statement.
int indent_;
};
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 061db5a..273c8f0 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -1025,6 +1025,57 @@ Temporary_reference_expression::do_address_taken(bool)
this->statement_->set_is_address_taken();
}
+// Export a reference to a temporary.
+
+void
+Temporary_reference_expression::do_export(Export_function_body* efb) const
+{
+ unsigned int idx = efb->temporary_index(this->statement_);
+ char buf[50];
+ snprintf(buf, sizeof buf, "$t%u", idx);
+ efb->write_c_string(buf);
+}
+
+// Import a reference to a temporary.
+
+Expression*
+Temporary_reference_expression::do_import(Import_function_body* ifb,
+ Location loc)
+{
+ std::string id = ifb->read_identifier();
+ go_assert(id[0] == '$' && id[1] == 't');
+ 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: "
+ "invalid temporary reference index at %lu"),
+ ifb->name().c_str(),
+ static_cast<unsigned long>(ifb->off()));
+ ifb->set_saw_error();
+ return Expression::make_error(loc);
+ }
+
+ Temporary_statement* temp =
+ ifb->temporary_statement(static_cast<unsigned int>(idx));
+ if (temp == NULL)
+ {
+ if (!ifb->saw_error())
+ go_error_at(loc,
+ ("invalid export data for %qs: "
+ "undefined temporary reference index at %lu"),
+ ifb->name().c_str(),
+ static_cast<unsigned long>(ifb->off()));
+ ifb->set_saw_error();
+ return Expression::make_error(loc);
+ }
+
+ return Expression::make_temporary_reference(temp, loc);
+}
+
// Get a backend expression referring to the variable.
Bexpression*
@@ -17819,6 +17870,10 @@ Expression::import_expression_without_suffix(Import_expression* imp,
}
if (ifb->saw_error())
return Expression::make_error(loc);
+
+ if (ifb->match_c_string("$t"))
+ return Temporary_reference_expression::do_import(ifb, loc);
+
return Expression::import_identifier(ifb, loc);
}
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index fc1c5a8..09c71ad 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -1531,6 +1531,9 @@ class Temporary_reference_expression : public Expression
set_is_lvalue()
{ this->is_lvalue_ = true; }
+ static Expression*
+ do_import(Import_function_body*, Location);
+
protected:
Type*
do_type();
@@ -1543,6 +1546,13 @@ class Temporary_reference_expression : public Expression
do_copy()
{ return make_temporary_reference(this->statement_, this->location()); }
+ int
+ do_inlining_cost() const
+ { return 1; }
+
+ void
+ do_export(Export_function_body*) const;
+
bool
do_is_addressable() const
{ return true; }
diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc
index 1c3f4a4..70e92ab 100644
--- a/gcc/go/gofrontend/import.cc
+++ b/gcc/go/gofrontend/import.cc
@@ -1611,3 +1611,34 @@ Import_function_body::read_type()
return type;
}
+
+// Record the index of a temporary statement.
+
+void
+Import_function_body::record_temporary(Temporary_statement* temp,
+ unsigned int idx)
+{
+ size_t have = this->temporaries_.size();
+ if (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;
+ this->temporaries_.resize(want, NULL);
+ }
+ this->temporaries_[idx] = temp;
+}
+
+// Return a temporary statement given an index.
+
+Temporary_statement*
+Import_function_body::temporary_statement(unsigned int idx)
+{
+ if (static_cast<size_t>(idx) >= this->temporaries_.size())
+ return NULL;
+ return this->temporaries_[idx];
+}
diff --git a/gcc/go/gofrontend/import.h b/gcc/go/gofrontend/import.h
index ab30aed..4afeb4a 100644
--- a/gcc/go/gofrontend/import.h
+++ b/gcc/go/gofrontend/import.h
@@ -587,7 +587,8 @@ 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), saw_error_(false)
+ off_(off), block_(block), indent_(indent), temporaries_(),
+ saw_error_(false)
{ }
// The IR.
@@ -695,6 +696,14 @@ class Import_function_body : public Import_expression
version() const
{ return this->imp_->version(); }
+ // Record the index of a temporary statement.
+ void
+ record_temporary(Temporary_statement*, unsigned int);
+
+ // Return a temporary statement given an index.
+ Temporary_statement*
+ temporary_statement(unsigned int);
+
// Implement Import_expression.
Import_function_body*
ifb()
@@ -736,6 +745,8 @@ class Import_function_body : public Import_expression
Block* block_;
// Current expected indentation level.
int indent_;
+ // Temporary statements by index.
+ std::vector<Temporary_statement*> temporaries_;
// 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 8368c5b..cd7b856 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -155,6 +155,8 @@ Statement::import_statement(Import_function_body* ifb, Location loc)
ifb->advance(6);
return Statement::make_return_statement(NULL, loc);
}
+ else if (ifb->match_c_string("var $t"))
+ return Temporary_statement::do_import(ifb, loc);
else if (ifb->match_c_string("var "))
return Variable_declaration_statement::do_import(ifb, loc);
@@ -693,6 +695,92 @@ Statement::make_temporary(Type* type, Expression* init,
return new Temporary_statement(type, init, location);
}
+// Export a temporary statement.
+
+void
+Temporary_statement::do_export_statement(Export_function_body* efb)
+{
+ unsigned int idx = efb->record_temporary(this);
+ char buf[100];
+ snprintf(buf, sizeof buf, "var $t%u", idx);
+ efb->write_c_string(buf);
+ if (this->type_ != NULL)
+ {
+ efb->write_c_string(" ");
+ efb->write_type(this->type_);
+ }
+ if (this->init_ != NULL)
+ {
+ efb->write_c_string(" = ");
+
+ go_assert(efb->type_context() == NULL);
+ efb->set_type_context(this->type_);
+
+ this->init_->export_expression(efb);
+
+ efb->set_type_context(NULL);
+ }
+}
+
+// Import a temporary statement.
+
+Statement*
+Temporary_statement::do_import(Import_function_body* ifb, Location loc)
+{
+ ifb->require_c_string("var ");
+ std::string id = ifb->read_identifier();
+ go_assert(id[0] == '$' && id[1] == 't');
+ 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 temporary statement index at %lu"),
+ ifb->name().c_str(),
+ static_cast<unsigned long>(ifb->off()));
+ ifb->set_saw_error();
+ return Statement::make_error_statement(loc);
+ }
+
+ Type* type = NULL;
+ if (!ifb->match_c_string(" = "))
+ {
+ ifb->require_c_string(" ");
+ type = ifb->read_type();
+ }
+ Expression* init = NULL;
+ if (ifb->match_c_string(" = "))
+ {
+ ifb->advance(3);
+ init = Expression::import_expression(ifb, loc);
+ if (type != NULL)
+ {
+ Type_context context(type, false);
+ init->determine_type(&context);
+ }
+ }
+ if (type == NULL && init == NULL)
+ {
+ if (!ifb->saw_error())
+ go_error_at(loc,
+ ("invalid export data for %qs: "
+ "temporary statement has neither type nor init at %lu"),
+ ifb->name().c_str(),
+ static_cast<unsigned long>(ifb->off()));
+ ifb->set_saw_error();
+ return Statement::make_error_statement(loc);
+ }
+
+ Temporary_statement* temp = Statement::make_temporary(type, init, loc);
+
+ ifb->record_temporary(temp, static_cast<unsigned int>(idx));
+
+ return temp;
+}
+
// The Move_subexpressions class is used to move all top-level
// subexpressions of an expression. This is used for things like
// index expressions in which we must evaluate the index value before
diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h
index d621a9a..bb71501 100644
--- a/gcc/go/gofrontend/statements.h
+++ b/gcc/go/gofrontend/statements.h
@@ -739,6 +739,10 @@ class Temporary_statement : public Statement
Bvariable*
get_backend_variable(Translate_context*) const;
+ // Import the declaration of a temporary.
+ static Statement*
+ do_import(Import_function_body*, Location);
+
protected:
int
do_traverse(Traverse*);
@@ -752,6 +756,13 @@ class Temporary_statement : public Statement
void
do_check_types(Gogo*);
+ int
+ do_inlining_cost()
+ { return 1; }
+
+ void
+ do_export_statement(Export_function_body*);
+
Statement*
do_flatten(Gogo*, Named_object*, Block*, Statement_inserter*);