From: Ian Lance Taylor Date: Wed, 28 Nov 2018 18:08:21 +0000 (+0000) Subject: compiler: inline functions with assignments and return statements X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=5456f30d92062d234208cd8634e54787f6e2664f;p=gcc.git 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 --- diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 8e220f50bf6..74806a23cbe 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -b013405f2c66596c47cb9be493c798db1087c0f0 +a8f768d68760768da5e86a8e63ef1ad5691c3ae8 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/expressions.cc b/gcc/go/gofrontend/expressions.cc index 5f00eff5655..7c464ce7f54 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -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(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. diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 70616571922..a18322cfb91 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -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; diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index 60b7a701df2..4d10f60e6c2 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -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(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 diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h index 3b5c68a3f6c..621d301fb82 100644 --- a/gcc/go/gofrontend/statements.h +++ b/gcc/go/gofrontend/statements.h @@ -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*);