Commit 5456f30d by Ian Lance Taylor

compiler: inline functions with assignments and return statements

    
    Support inlining functions that contain only assignments and return
    statements, with expressions of either constants or parameters.
    Functions that contain other kinds of statements or expressions are
    not yet inlined.  With this change, about 100 functions in the
    standard library are inlinable.
    
    Reviewed-on: https://go-review.googlesource.com/c/150073

From-SVN: r266573
parent 85041a5b
b013405f2c66596c47cb9be493c798db1087c0f0 a8f768d68760768da5e86a8e63ef1ad5691c3ae8
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.
...@@ -786,6 +786,31 @@ Var_expression::do_address_taken(bool escapes) ...@@ -786,6 +786,31 @@ Var_expression::do_address_taken(bool escapes)
} }
} }
// The cost to inline a variable reference. We currently only support
// references to parameters.
int
Var_expression::do_inlining_cost() const
{
if (this->variable_->is_variable())
{
if (this->variable_->var_value()->is_parameter())
return 1;
}
else if (this->variable_->is_result_variable())
return 1;
return 0x100000;
}
// Export a reference to a variable.
void
Var_expression::do_export(Export_function_body* efb) const
{
efb->write_string(Gogo::unpack_hidden_name(this->variable_->name()));
}
// Get the backend representation for a reference to a variable. // Get the backend representation for a reference to a variable.
Bexpression* Bexpression*
...@@ -1608,6 +1633,10 @@ class Boolean_expression : public Expression ...@@ -1608,6 +1633,10 @@ class Boolean_expression : public Expression
do_get_backend(Translate_context* context) do_get_backend(Translate_context* context)
{ return context->backend()->boolean_constant_expression(this->val_); } { return context->backend()->boolean_constant_expression(this->val_); }
int
do_inlining_cost() const
{ return 1; }
void void
do_export(Export_function_body* efb) const do_export(Export_function_body* efb) const
{ efb->write_c_string(this->val_ ? "$true" : "$false"); } { efb->write_c_string(this->val_ ? "$true" : "$false"); }
...@@ -1997,6 +2026,10 @@ class Integer_expression : public Expression ...@@ -1997,6 +2026,10 @@ class Integer_expression : public Expression
this->location()); this->location());
} }
int
do_inlining_cost() const
{ return 1; }
void void
do_export(Export_function_body*) const; do_export(Export_function_body*) const;
...@@ -2408,6 +2441,10 @@ class Float_expression : public Expression ...@@ -2408,6 +2441,10 @@ class Float_expression : public Expression
Bexpression* Bexpression*
do_get_backend(Translate_context*); do_get_backend(Translate_context*);
int
do_inlining_cost() const
{ return 1; }
void void
do_export(Export_function_body*) const; do_export(Export_function_body*) const;
...@@ -2617,6 +2654,10 @@ class Complex_expression : public Expression ...@@ -2617,6 +2654,10 @@ class Complex_expression : public Expression
Bexpression* Bexpression*
do_get_backend(Translate_context*); do_get_backend(Translate_context*);
int
do_inlining_cost() const
{ return 2; }
void void
do_export(Export_function_body*) const; do_export(Export_function_body*) const;
...@@ -3204,6 +3245,10 @@ class Nil_expression : public Expression ...@@ -3204,6 +3245,10 @@ class Nil_expression : public Expression
do_get_backend(Translate_context* context) do_get_backend(Translate_context* context)
{ return context->backend()->nil_pointer_expression(); } { return context->backend()->nil_pointer_expression(); }
int
do_inlining_cost() const
{ return 1; }
void void
do_export(Export_function_body* efb) const do_export(Export_function_body* efb) const
{ efb->write_c_string("$nil"); } { efb->write_c_string("$nil"); }
...@@ -3654,6 +3699,25 @@ Type_conversion_expression::do_get_backend(Translate_context* context) ...@@ -3654,6 +3699,25 @@ Type_conversion_expression::do_get_backend(Translate_context* context)
} }
} }
// Cost of inlining a type conversion.
int
Type_conversion_expression::do_inlining_cost() const
{
Type* type = this->type_;
Type* expr_type = this->expr_->type();
if (type->interface_type() != NULL || expr_type->interface_type() != NULL)
return 10;
else if (type->is_string_type() && expr_type->integer_type() != NULL)
return 10;
else if (type->is_string_type() && expr_type->is_slice_type())
return 10;
else if (type->is_slice_type() && expr_type->is_string_type())
return 10;
else
return 1;
}
// Output a type conversion in a constant expression. // Output a type conversion in a constant expression.
void void
...@@ -4677,7 +4741,11 @@ Unary_expression::do_export(Export_function_body* efb) const ...@@ -4677,7 +4741,11 @@ Unary_expression::do_export(Export_function_body* efb) const
efb->write_c_string("^"); efb->write_c_string("^");
break; break;
case OPERATOR_AND: case OPERATOR_AND:
efb->write_c_string("&");
break;
case OPERATOR_MULT: case OPERATOR_MULT:
efb->write_c_string("*");
break;
default: default:
go_unreachable(); go_unreachable();
} }
...@@ -4704,6 +4772,12 @@ Unary_expression::do_import(Import_expression* imp, Location loc) ...@@ -4704,6 +4772,12 @@ Unary_expression::do_import(Import_expression* imp, Location loc)
case '^': case '^':
op = OPERATOR_XOR; op = OPERATOR_XOR;
break; break;
case '&':
op = OPERATOR_AND;
break;
case '*':
op = OPERATOR_MULT;
break;
default: default:
go_unreachable(); go_unreachable();
} }
...@@ -16195,7 +16269,7 @@ Expression* ...@@ -16195,7 +16269,7 @@ Expression*
Expression::import_expression(Import_expression* imp, Location loc) Expression::import_expression(Import_expression* imp, Location loc)
{ {
int c = imp->peek_char(); int c = imp->peek_char();
if (c == '+' || c == '-' || c == '!' || c == '^') if (c == '+' || c == '-' || c == '!' || c == '^' || c == '&' || c == '*')
return Unary_expression::do_import(imp, loc); return Unary_expression::do_import(imp, loc);
else if (c == '(') else if (c == '(')
return Binary_expression::do_import(imp, loc); return Binary_expression::do_import(imp, loc);
...@@ -16220,11 +16294,35 @@ Expression::import_expression(Import_expression* imp, Location loc) ...@@ -16220,11 +16294,35 @@ Expression::import_expression(Import_expression* imp, Location loc)
|| (imp->version() < EXPORT_FORMAT_V3 || (imp->version() < EXPORT_FORMAT_V3
&& imp->match_c_string("convert"))) && imp->match_c_string("convert")))
return Type_conversion_expression::do_import(imp, loc); return Type_conversion_expression::do_import(imp, loc);
else
Import_function_body* ifb = imp->ifb();
if (ifb == NULL)
{ {
go_error_at(imp->location(), "import error: expected expression"); go_error_at(imp->location(), "import error: expected expression");
return Expression::make_error(loc); return Expression::make_error(loc);
} }
if (ifb->saw_error())
return Expression::make_error(loc);
std::string id = ifb->read_identifier();
if (id.empty())
{
if (!ifb->saw_error())
go_error_at(imp->location(),
"import error: expected identifier at %lu",
static_cast<unsigned long>(ifb->off()));
ifb->set_saw_error();
return Expression::make_error(loc);
}
Named_object* var = ifb->block()->bindings()->lookup(id);
if (var == NULL)
{
if (!ifb->saw_error())
go_error_at(imp->location(), "import error: lookup of %qs failed",
id.c_str());
ifb->set_saw_error();
return Expression::make_error(loc);
}
return Expression::make_var_reference(var, loc);
} }
// Class Expression_list. // Class Expression_list.
......
...@@ -941,7 +941,7 @@ class Expression ...@@ -941,7 +941,7 @@ class Expression
// Return the cost of this statement for inlining purposes. // Return the cost of this statement for inlining purposes.
int int
inlining_cost() inlining_cost() const
{ return this->do_inlining_cost(); } { return this->do_inlining_cost(); }
// Return whether the expression is addressable--something which may // Return whether the expression is addressable--something which may
...@@ -1093,7 +1093,7 @@ class Expression ...@@ -1093,7 +1093,7 @@ class Expression
// inlining. The default cost is high, so we only need to define // inlining. The default cost is high, so we only need to define
// this method for expressions that can be inlined. // this method for expressions that can be inlined.
virtual int virtual int
do_inlining_cost() do_inlining_cost() const
{ return 0x100000; } { return 0x100000; }
// Child class implements whether the expression is addressable. // Child class implements whether the expression is addressable.
...@@ -1355,6 +1355,12 @@ class Var_expression : public Expression ...@@ -1355,6 +1355,12 @@ class Var_expression : public Expression
do_copy() do_copy()
{ return this; } { return this; }
int
do_inlining_cost() const;
void
do_export(Export_function_body*) const;
bool bool
do_is_addressable() const do_is_addressable() const
{ return true; } { return true; }
...@@ -1602,6 +1608,12 @@ class String_expression : public Expression ...@@ -1602,6 +1608,12 @@ class String_expression : public Expression
static void static void
export_string(String_dump* exp, const String_expression* str); export_string(String_dump* exp, const String_expression* str);
// Set the inlining cost a bit high since inlining may cause
// duplicated string literals.
int
do_inlining_cost() const
{ return 5; }
void void
do_export(Export_function_body*) const; do_export(Export_function_body*) const;
...@@ -1686,6 +1698,9 @@ class Type_conversion_expression : public Expression ...@@ -1686,6 +1698,9 @@ class Type_conversion_expression : public Expression
Bexpression* Bexpression*
do_get_backend(Translate_context* context); do_get_backend(Translate_context* context);
int
do_inlining_cost() const;
void void
do_export(Export_function_body*) const; do_export(Export_function_body*) const;
...@@ -1877,6 +1892,10 @@ class Unary_expression : public Expression ...@@ -1877,6 +1892,10 @@ class Unary_expression : public Expression
Bexpression* Bexpression*
do_get_backend(Translate_context*); do_get_backend(Translate_context*);
int
do_inlining_cost() const
{ return 1; }
void void
do_export(Export_function_body*) const; do_export(Export_function_body*) const;
...@@ -2022,6 +2041,10 @@ class Binary_expression : public Expression ...@@ -2022,6 +2041,10 @@ class Binary_expression : public Expression
Bexpression* Bexpression*
do_get_backend(Translate_context*); do_get_backend(Translate_context*);
int
do_inlining_cost() const
{ return 1; }
void void
do_export(Export_function_body*) const; do_export(Export_function_body*) const;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "expressions.h" #include "expressions.h"
#include "gogo.h" #include "gogo.h"
#include "export.h" #include "export.h"
#include "import.h"
#include "runtime.h" #include "runtime.h"
#include "backend.h" #include "backend.h"
#include "statements.h" #include "statements.h"
...@@ -124,9 +125,41 @@ Statement::determine_types() ...@@ -124,9 +125,41 @@ Statement::determine_types()
// Read a statement from export data. // Read a statement from export data.
Statement* Statement*
Statement::import_statement(Import_function_body*, Location) Statement::import_statement(Import_function_body* ifb, Location loc)
{ {
go_unreachable(); if (ifb->match_c_string("{"))
{
size_t nl = ifb->body().find('\n', ifb->off());
if (nl == std::string::npos)
{
if (!ifb->saw_error())
go_error_at(ifb->location(),
"import error: no newline after { at %lu",
static_cast<unsigned long>(ifb->off()));
ifb->set_saw_error();
return Statement::make_error_statement(loc);
}
ifb->set_off(nl + 1);
ifb->increment_indent();
Block* block = new Block(ifb->block(), loc);
bool ok = Block::import_block(block, ifb, loc);
ifb->decrement_indent();
if (!ok)
return Statement::make_error_statement(loc);
return Statement::make_block_statement(block, loc);
}
else if (ifb->match_c_string("return"))
{
// After lowering return statements have no expressions. The
// return expressions are assigned to result parameters.
ifb->advance(6);
return Statement::make_return_statement(NULL, loc);
}
Expression* lhs = Expression::import_expression(ifb, loc);
ifb->require_c_string(" = ");
Expression* rhs = Expression::import_expression(ifb, loc);
return Statement::make_assignment(lhs, rhs, loc);
} }
// If this is a thunk statement, return it. // If this is a thunk statement, return it.
...@@ -834,6 +867,14 @@ Assignment_statement::do_check_types(Gogo*) ...@@ -834,6 +867,14 @@ Assignment_statement::do_check_types(Gogo*)
this->set_is_error(); this->set_is_error();
} }
void
Assignment_statement::do_export_statement(Export_function_body* efb)
{
this->lhs_->export_expression(efb);
efb->write_c_string(" = ");
this->rhs_->export_expression(efb);
}
// Flatten an assignment statement. We may need a temporary for // Flatten an assignment statement. We may need a temporary for
// interface conversion. // interface conversion.
...@@ -2844,6 +2885,16 @@ Return_statement::do_get_backend(Translate_context* context) ...@@ -2844,6 +2885,16 @@ Return_statement::do_get_backend(Translate_context* context)
retvals, loc); retvals, loc);
} }
// Export a return statement. At this point all the expressions have
// been converted to assignments to the result variables, so this is
// simple.
void
Return_statement::do_export_statement(Export_function_body* efb)
{
efb->write_c_string("return");
}
// Dump the AST representation for a return statement. // Dump the AST representation for a return statement.
void void
......
...@@ -631,6 +631,13 @@ class Assignment_statement : public Statement ...@@ -631,6 +631,13 @@ class Assignment_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*);
...@@ -792,6 +799,13 @@ class Return_statement : public Statement ...@@ -792,6 +799,13 @@ class Return_statement : public Statement
do_may_fall_through() const do_may_fall_through() const
{ return false; } { return false; }
int
do_inlining_cost()
{ return 1; }
void
do_export_statement(Export_function_body*);
Bstatement* Bstatement*
do_get_backend(Translate_context*); do_get_backend(Translate_context*);
......
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