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
merge done from the gofrontend repository.
......@@ -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.
Bexpression*
......@@ -1608,6 +1633,10 @@ class Boolean_expression : public Expression
do_get_backend(Translate_context* context)
{ return context->backend()->boolean_constant_expression(this->val_); }
int
do_inlining_cost() const
{ return 1; }
void
do_export(Export_function_body* efb) const
{ efb->write_c_string(this->val_ ? "$true" : "$false"); }
......@@ -1997,6 +2026,10 @@ class Integer_expression : public Expression
this->location());
}
int
do_inlining_cost() const
{ return 1; }
void
do_export(Export_function_body*) const;
......@@ -2408,6 +2441,10 @@ class Float_expression : public Expression
Bexpression*
do_get_backend(Translate_context*);
int
do_inlining_cost() const
{ return 1; }
void
do_export(Export_function_body*) const;
......@@ -2617,6 +2654,10 @@ class Complex_expression : public Expression
Bexpression*
do_get_backend(Translate_context*);
int
do_inlining_cost() const
{ return 2; }
void
do_export(Export_function_body*) const;
......@@ -3204,6 +3245,10 @@ class Nil_expression : public Expression
do_get_backend(Translate_context* context)
{ return context->backend()->nil_pointer_expression(); }
int
do_inlining_cost() const
{ return 1; }
void
do_export(Export_function_body* efb) const
{ efb->write_c_string("$nil"); }
......@@ -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.
void
......@@ -4677,7 +4741,11 @@ Unary_expression::do_export(Export_function_body* efb) const
efb->write_c_string("^");
break;
case OPERATOR_AND:
efb->write_c_string("&");
break;
case OPERATOR_MULT:
efb->write_c_string("*");
break;
default:
go_unreachable();
}
......@@ -4704,6 +4772,12 @@ Unary_expression::do_import(Import_expression* imp, Location loc)
case '^':
op = OPERATOR_XOR;
break;
case '&':
op = OPERATOR_AND;
break;
case '*':
op = OPERATOR_MULT;
break;
default:
go_unreachable();
}
......@@ -16195,7 +16269,7 @@ Expression*
Expression::import_expression(Import_expression* imp, Location loc)
{
int c = imp->peek_char();
if (c == '+' || c == '-' || c == '!' || c == '^')
if (c == '+' || c == '-' || c == '!' || c == '^' || c == '&' || c == '*')
return Unary_expression::do_import(imp, loc);
else if (c == '(')
return Binary_expression::do_import(imp, loc);
......@@ -16220,11 +16294,35 @@ Expression::import_expression(Import_expression* imp, Location loc)
|| (imp->version() < EXPORT_FORMAT_V3
&& imp->match_c_string("convert")))
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");
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.
......
......@@ -941,7 +941,7 @@ class Expression
// Return the cost of this statement for inlining purposes.
int
inlining_cost()
inlining_cost() const
{ return this->do_inlining_cost(); }
// Return whether the expression is addressable--something which may
......@@ -1093,7 +1093,7 @@ class Expression
// inlining. The default cost is high, so we only need to define
// this method for expressions that can be inlined.
virtual int
do_inlining_cost()
do_inlining_cost() const
{ return 0x100000; }
// Child class implements whether the expression is addressable.
......@@ -1355,6 +1355,12 @@ class Var_expression : public Expression
do_copy()
{ return this; }
int
do_inlining_cost() const;
void
do_export(Export_function_body*) const;
bool
do_is_addressable() const
{ return true; }
......@@ -1602,6 +1608,12 @@ class String_expression : public Expression
static void
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
do_export(Export_function_body*) const;
......@@ -1686,6 +1698,9 @@ class Type_conversion_expression : public Expression
Bexpression*
do_get_backend(Translate_context* context);
int
do_inlining_cost() const;
void
do_export(Export_function_body*) const;
......@@ -1877,6 +1892,10 @@ class Unary_expression : public Expression
Bexpression*
do_get_backend(Translate_context*);
int
do_inlining_cost() const
{ return 1; }
void
do_export(Export_function_body*) const;
......@@ -2022,6 +2041,10 @@ class Binary_expression : public Expression
Bexpression*
do_get_backend(Translate_context*);
int
do_inlining_cost() const
{ return 1; }
void
do_export(Export_function_body*) const;
......
......@@ -12,6 +12,7 @@
#include "expressions.h"
#include "gogo.h"
#include "export.h"
#include "import.h"
#include "runtime.h"
#include "backend.h"
#include "statements.h"
......@@ -124,9 +125,41 @@ Statement::determine_types()
// Read a statement from export data.
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.
......@@ -834,6 +867,14 @@ Assignment_statement::do_check_types(Gogo*)
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
// interface conversion.
......@@ -2844,6 +2885,16 @@ Return_statement::do_get_backend(Translate_context* context)
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.
void
......
......@@ -631,6 +631,13 @@ class Assignment_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*);
......@@ -792,6 +799,13 @@ class Return_statement : public Statement
do_may_fall_through() const
{ return false; }
int
do_inlining_cost()
{ return 1; }
void
do_export_statement(Export_function_body*);
Bstatement*
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