From: Ian Lance Taylor Date: Thu, 6 Jun 2019 23:34:00 +0000 (+0000) Subject: compiler: permit inlining temporary statements and references X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=93cbebde76ac7de2d69b223d99acb39e0370687f;p=gcc.git 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 --- diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 2b7525548f2..4d455ea8023 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 824f821be73..0890b0961f7 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 val(temp, ret); + std::pair 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 e3932d48130..92d0180dde6 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 061db5aa8b9..273c8f074c7 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(ifb->off())); + ifb->set_saw_error(); + return Expression::make_error(loc); + } + + Temporary_statement* temp = + ifb->temporary_statement(static_cast(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(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 fc1c5a80ff8..09c71adbd31 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 1c3f4a498b5..70e92ab9d3b 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(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(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 ab30aed0ae5..4afeb4a2958 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 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 8368c5b72bb..cd7b8568a12 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(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(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(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 d621a9af7d8..bb715016433 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*);