Commit 93cbebde by Ian Lance Taylor

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
parent 5e664ed0
bc7374913367fba9b10dc284af87eb539fb6c5b2 015785baa74629baafe520367b9c71707366c6eb
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -6,15 +6,14 @@ ...@@ -6,15 +6,14 @@
#include "go-system.h" #include "go-system.h"
#include "go-sha1.h"
#include "go-c.h" #include "go-c.h"
#include "go-diagnostics.h"
#include "go-sha1.h"
#include "gogo.h" #include "gogo.h"
#include "types.h" #include "types.h"
#include "expressions.h" #include "expressions.h"
#include "statements.h" #include "statements.h"
#include "export.h" #include "export.h"
#include "go-linemap.h" #include "go-linemap.h"
#include "backend.h" #include "backend.h"
...@@ -1297,3 +1296,33 @@ Stream_to_section::do_write(const char* bytes, size_t length) ...@@ -1297,3 +1296,33 @@ Stream_to_section::do_write(const char* bytes, size_t length)
{ {
this->backend_->write_export_data (bytes, 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;
}
...@@ -20,6 +20,7 @@ class Type; ...@@ -20,6 +20,7 @@ class Type;
class Package; class Package;
class Import_init_set; class Import_init_set;
class Backend; class Backend;
class Temporary_statement;
// Codes used for the builtin types. These are all negative to make // Codes used for the builtin types. These are all negative to make
// them easily distinct from the codes assigned by Export::write_type. // them easily distinct from the codes assigned by Export::write_type.
...@@ -307,7 +308,8 @@ class Export_function_body : public String_dump ...@@ -307,7 +308,8 @@ class Export_function_body : public String_dump
{ {
public: public:
Export_function_body(Export* exp, int indent) 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. // Write a character to the body.
...@@ -363,6 +365,14 @@ class Export_function_body : public String_dump ...@@ -363,6 +365,14 @@ class Export_function_body : public String_dump
package_index(const Package* p) const package_index(const Package* p) const
{ return this->exp_->package_index(p); } { 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. // Return a reference to the completed body.
const std::string& const std::string&
body() const body() const
...@@ -375,6 +385,10 @@ class Export_function_body : public String_dump ...@@ -375,6 +385,10 @@ class Export_function_body : public String_dump
std::string body_; std::string body_;
// Current type context. Used to avoid duplicate type conversions. // Current type context. Used to avoid duplicate type conversions.
Type* type_context_; 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. // Current indentation level: the number of spaces before each statement.
int indent_; int indent_;
}; };
......
...@@ -1025,6 +1025,57 @@ Temporary_reference_expression::do_address_taken(bool) ...@@ -1025,6 +1025,57 @@ Temporary_reference_expression::do_address_taken(bool)
this->statement_->set_is_address_taken(); 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. // Get a backend expression referring to the variable.
Bexpression* Bexpression*
...@@ -17819,6 +17870,10 @@ Expression::import_expression_without_suffix(Import_expression* imp, ...@@ -17819,6 +17870,10 @@ Expression::import_expression_without_suffix(Import_expression* imp,
} }
if (ifb->saw_error()) if (ifb->saw_error())
return Expression::make_error(loc); 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); return Expression::import_identifier(ifb, loc);
} }
......
...@@ -1531,6 +1531,9 @@ class Temporary_reference_expression : public Expression ...@@ -1531,6 +1531,9 @@ class Temporary_reference_expression : public Expression
set_is_lvalue() set_is_lvalue()
{ this->is_lvalue_ = true; } { this->is_lvalue_ = true; }
static Expression*
do_import(Import_function_body*, Location);
protected: protected:
Type* Type*
do_type(); do_type();
...@@ -1543,6 +1546,13 @@ class Temporary_reference_expression : public Expression ...@@ -1543,6 +1546,13 @@ class Temporary_reference_expression : public Expression
do_copy() do_copy()
{ return make_temporary_reference(this->statement_, this->location()); } { return make_temporary_reference(this->statement_, this->location()); }
int
do_inlining_cost() const
{ return 1; }
void
do_export(Export_function_body*) const;
bool bool
do_is_addressable() const do_is_addressable() const
{ return true; } { return true; }
......
...@@ -1611,3 +1611,34 @@ Import_function_body::read_type() ...@@ -1611,3 +1611,34 @@ Import_function_body::read_type()
return 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];
}
...@@ -587,7 +587,8 @@ class Import_function_body : public Import_expression ...@@ -587,7 +587,8 @@ class Import_function_body : public Import_expression
const std::string& body, size_t off, Block* block, const std::string& body, size_t off, Block* block,
int indent) int indent)
: gogo_(gogo), imp_(imp), named_object_(named_object), body_(body), : 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. // The IR.
...@@ -695,6 +696,14 @@ class Import_function_body : public Import_expression ...@@ -695,6 +696,14 @@ class Import_function_body : public Import_expression
version() const version() const
{ return this->imp_->version(); } { 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. // Implement Import_expression.
Import_function_body* Import_function_body*
ifb() ifb()
...@@ -736,6 +745,8 @@ class Import_function_body : public Import_expression ...@@ -736,6 +745,8 @@ class Import_function_body : public Import_expression
Block* block_; Block* block_;
// Current expected indentation level. // Current expected indentation level.
int indent_; int indent_;
// Temporary statements by index.
std::vector<Temporary_statement*> temporaries_;
// Whether we've seen an error. Used to avoid reporting excess // Whether we've seen an error. Used to avoid reporting excess
// errors. // errors.
bool saw_error_; bool saw_error_;
......
...@@ -155,6 +155,8 @@ Statement::import_statement(Import_function_body* ifb, Location loc) ...@@ -155,6 +155,8 @@ Statement::import_statement(Import_function_body* ifb, Location loc)
ifb->advance(6); ifb->advance(6);
return Statement::make_return_statement(NULL, loc); 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 ")) else if (ifb->match_c_string("var "))
return Variable_declaration_statement::do_import(ifb, loc); return Variable_declaration_statement::do_import(ifb, loc);
...@@ -693,6 +695,92 @@ Statement::make_temporary(Type* type, Expression* init, ...@@ -693,6 +695,92 @@ Statement::make_temporary(Type* type, Expression* init,
return new Temporary_statement(type, init, location); 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 // The Move_subexpressions class is used to move all top-level
// subexpressions of an expression. This is used for things like // subexpressions of an expression. This is used for things like
// index expressions in which we must evaluate the index value before // index expressions in which we must evaluate the index value before
......
...@@ -739,6 +739,10 @@ class Temporary_statement : public Statement ...@@ -739,6 +739,10 @@ class Temporary_statement : public Statement
Bvariable* Bvariable*
get_backend_variable(Translate_context*) const; get_backend_variable(Translate_context*) const;
// Import the declaration of a temporary.
static Statement*
do_import(Import_function_body*, Location);
protected: protected:
int int
do_traverse(Traverse*); do_traverse(Traverse*);
...@@ -752,6 +756,13 @@ class Temporary_statement : public Statement ...@@ -752,6 +756,13 @@ class Temporary_statement : public Statement
void void
do_check_types(Gogo*); do_check_types(Gogo*);
int
do_inlining_cost()
{ return 1; }
void
do_export_statement(Export_function_body*);
Statement* Statement*
do_flatten(Gogo*, Named_object*, Block*, Statement_inserter*); do_flatten(Gogo*, Named_object*, Block*, Statement_inserter*);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment