This patch to the Go frontend supports inlining functions with if statements. This increases the number of inlinable functions from 455 to 500. An example of a newly inlinable function is strings.Compare. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline.
Ian
Index: gcc/go/gofrontend/MERGE =================================================================== --- gcc/go/gofrontend/MERGE (revision 272043) +++ gcc/go/gofrontend/MERGE (working copy) @@ -1,4 +1,4 @@ -46329dd9e6473fff46df6b310c11116d1558e470 +9df825b5f142ac2b6f48a8dac94fcff740acd411 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. Index: gcc/go/gofrontend/gogo.cc =================================================================== --- gcc/go/gofrontend/gogo.cc (revision 272043) +++ gcc/go/gofrontend/gogo.cc (working copy) @@ -6941,7 +6941,12 @@ Block::import_block(Block* set, Import_f if (at_end) { - off = nl + 1; + // An if statement can have an "else" following the "}", in + // which case we want to leave the offset where it is, just + // after the "}". We don't get the block ending location + // quite right for if statements. + if (body.compare(off, 6, " else ") != 0) + off = nl + 1; break; } Index: gcc/go/gofrontend/statements.cc =================================================================== --- gcc/go/gofrontend/statements.cc (revision 272022) +++ gcc/go/gofrontend/statements.cc (working copy) @@ -129,22 +129,8 @@ Statement::import_statement(Import_funct { 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) + Block* block = Block_statement::do_import(ifb, loc); + if (block == NULL) return Statement::make_error_statement(loc); return Statement::make_block_statement(block, loc); } @@ -159,6 +145,8 @@ Statement::import_statement(Import_funct return Temporary_statement::do_import(ifb, loc); else if (ifb->match_c_string("var ")) return Variable_declaration_statement::do_import(ifb, loc); + else if (ifb->match_c_string("if ")) + return If_statement::do_import(ifb, loc); Expression* lhs = Expression::import_expression(ifb, loc); ifb->require_c_string(" = "); @@ -2121,13 +2109,19 @@ Statement::make_statement(Expression* ex void Block_statement::do_export_statement(Export_function_body* efb) { + Block_statement::export_block(efb, this->block_); +} + +void +Block_statement::export_block(Export_function_body* efb, Block* block) +{ // We are already indented to the right position. char buf[50]; snprintf(buf, sizeof buf, "{ //%d\n", - Linemap::location_to_line(this->block_->start_location())); + Linemap::location_to_line(block->start_location())); efb->write_c_string(buf); - this->block_->export_block(efb); + block->export_block(efb); // The indentation is correct for the statements in the block, so // subtract one for the closing curly brace. efb->decrement_indent(); @@ -2137,6 +2131,32 @@ Block_statement::do_export_statement(Exp efb->increment_indent(); } +// Import a block statement, returning the block. + +Block* +Block_statement::do_import(Import_function_body* ifb, Location loc) +{ + go_assert(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 NULL; + } + 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 NULL; + return block; +} + // Convert a block to the backend representation of a statement. Bstatement* @@ -3529,6 +3549,73 @@ If_statement::do_get_backend(Translate_c this->location()); } +// Export an if statement. + +void +If_statement::do_export_statement(Export_function_body* efb) +{ + efb->write_c_string("if "); + this->cond_->export_expression(efb); + efb->write_c_string(" "); + Block_statement::export_block(efb, this->then_block_); + if (this->else_block_ != NULL) + { + efb->write_c_string(" else "); + Block_statement::export_block(efb, this->else_block_); + } +} + +// Import an if statement. + +Statement* +If_statement::do_import(Import_function_body* ifb, Location loc) +{ + ifb->require_c_string("if "); + + Expression* cond = Expression::import_expression(ifb, loc); + Type_context context(Type::lookup_bool_type(), false); + cond->determine_type(&context); + ifb->require_c_string(" "); + + if (!ifb->match_c_string("{")) + { + if (!ifb->saw_error()) + go_error_at(ifb->location(), + "import error for %qs: no block for if statement at %lu", + ifb->name().c_str(), + static_cast<unsigned long>(ifb->off())); + ifb->set_saw_error(); + return Statement::make_error_statement(loc); + } + + Block* then_block = Block_statement::do_import(ifb, loc); + if (then_block == NULL) + return Statement::make_error_statement(loc); + + Block* else_block = NULL; + if (ifb->match_c_string(" else ")) + { + ifb->advance(6); + if (!ifb->match_c_string("{")) + { + if (!ifb->saw_error()) + go_error_at(ifb->location(), + ("import error for %qs: no else block " + "for if statement at %lu"), + ifb->name().c_str(), + static_cast<unsigned long>(ifb->off())); + ifb->set_saw_error(); + return Statement::make_error_statement(loc); + } + + else_block = Block_statement::do_import(ifb, loc); + if (else_block == NULL) + return Statement::make_error_statement(loc); + } + + return Statement::make_if_statement(cond, then_block, else_block, loc); +} + // Dump the AST representation for an if statement void Index: gcc/go/gofrontend/statements.h =================================================================== --- gcc/go/gofrontend/statements.h (revision 272043) +++ gcc/go/gofrontend/statements.h (working copy) @@ -954,6 +954,14 @@ class Block_statement : public Statement is_lowered_for_statement() { return this->is_lowered_for_statement_; } + // Export a block for a block statement. + static void + export_block(Export_function_body*, Block*); + + // Import a block statement, returning the block. + static Block* + do_import(Import_function_body*, Location); + protected: int do_traverse(Traverse* traverse) @@ -1529,6 +1537,10 @@ class If_statement : public Statement else_block() const { return this->else_block_; } + // Import an if statement. + static Statement* + do_import(Import_function_body*, Location); + protected: int do_traverse(Traverse*); @@ -1539,6 +1551,13 @@ class If_statement : public Statement void do_check_types(Gogo*); + int + do_inlining_cost() + { return 5; } + + void + do_export_statement(Export_function_body*); + bool do_may_fall_through() const;