diff options
Diffstat (limited to 'gcc/go')
-rw-r--r-- | gcc/go/gofrontend/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/export.cc | 23 | ||||
-rw-r--r-- | gcc/go/gofrontend/export.h | 13 | ||||
-rw-r--r-- | gcc/go/gofrontend/import.cc | 46 | ||||
-rw-r--r-- | gcc/go/gofrontend/import.h | 14 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 204 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.h | 44 |
7 files changed, 321 insertions, 25 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 05959f2..9dfa067 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -3f7dcb98df3ce1d4e02d0072fd21e70dc08351db +11d96c36198b75b0485d16524d521e558cf03312 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/export.cc b/gcc/go/gofrontend/export.cc index 0890b09..a48ca07 100644 --- a/gcc/go/gofrontend/export.cc +++ b/gcc/go/gofrontend/export.cc @@ -1326,3 +1326,26 @@ Export_function_body::temporary_index(const Temporary_statement* temp) go_assert(p != this->temporary_indexes_.end()); return p->second; } + +// Return the index of an unnamed label. If it doesn't already have +// an index, give it one. + +unsigned int +Export_function_body::unnamed_label_index(const Unnamed_label* label) +{ + unsigned int next = this->next_label_index_; + std::pair<const Unnamed_label*, unsigned int> val(label, next); + std::pair<Unordered_map(const Unnamed_label*, unsigned int)::iterator, + bool> ins = + this->label_indexes_.insert(val); + if (!ins.second) + return ins.first->second; + else + { + if (next > 0x7fffffff) + go_error_at(label->location(), + "too many unnamed labels in export data"); + ++this->next_label_index_; + return next; + } +} diff --git a/gcc/go/gofrontend/export.h b/gcc/go/gofrontend/export.h index 92d0180..910b1db 100644 --- a/gcc/go/gofrontend/export.h +++ b/gcc/go/gofrontend/export.h @@ -21,6 +21,7 @@ class Package; class Import_init_set; class Backend; class Temporary_statement; +class Unnamed_label; // Codes used for the builtin types. These are all negative to make // them easily distinct from the codes assigned by Export::write_type. @@ -309,7 +310,8 @@ class Export_function_body : public String_dump public: Export_function_body(Export* exp, int indent) : exp_(exp), body_(), type_context_(NULL), next_temporary_index_(0), - temporary_indexes_(), indent_(indent) + temporary_indexes_(), next_label_index_(0), label_indexes_(), + indent_(indent) { } // Write a character to the body. @@ -373,6 +375,11 @@ class Export_function_body : public String_dump unsigned int temporary_index(const Temporary_statement*); + // Return the index of an unnamed label. If it doesn't already have + // an index, give it one. + unsigned int + unnamed_label_index(const Unnamed_label*); + // Return a reference to the completed body. const std::string& body() const @@ -389,6 +396,10 @@ class Export_function_body : public String_dump unsigned int next_temporary_index_; // Map temporary statements to indexes. Unordered_map(const Temporary_statement*, unsigned int) temporary_indexes_; + // Index to give to the next unnamed label. + unsigned int next_label_index_; + // Map unnamed labels to indexes. + Unordered_map(const Unnamed_label*, unsigned int) label_indexes_; // Current indentation level: the number of spaces before each statement. int indent_; }; diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc index 70e92ab..02c1c48 100644 --- a/gcc/go/gofrontend/import.cc +++ b/gcc/go/gofrontend/import.cc @@ -1612,6 +1612,19 @@ Import_function_body::read_type() return type; } +// Return the next size to use for a vector mapping indexes to values. + +size_t +Import_function_body::next_size(size_t have) +{ + if (have == 0) + return 8; + else if (have < 256) + return have * 2; + else + return have + 64; +} + // Record the index of a temporary statement. void @@ -1619,16 +1632,11 @@ Import_function_body::record_temporary(Temporary_statement* temp, unsigned int idx) { size_t have = this->temporaries_.size(); - if (static_cast<size_t>(idx) >= have) + while (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; + size_t want = Import_function_body::next_size(have); this->temporaries_.resize(want, NULL); + have = want; } this->temporaries_[idx] = temp; } @@ -1642,3 +1650,25 @@ Import_function_body::temporary_statement(unsigned int idx) return NULL; return this->temporaries_[idx]; } + +// Return an unnamed label given an index, defining the label if we +// haven't seen it already. + +Unnamed_label* +Import_function_body::unnamed_label(unsigned int idx, Location loc) +{ + size_t have = this->labels_.size(); + while (static_cast<size_t>(idx) >= have) + { + size_t want = Import_function_body::next_size(have); + this->labels_.resize(want, NULL); + have = want; + } + Unnamed_label* label = this->labels_[idx]; + if (label == NULL) + { + label = new Unnamed_label(loc); + this->labels_[idx] = label; + } + return label; +} diff --git a/gcc/go/gofrontend/import.h b/gcc/go/gofrontend/import.h index 4afeb4a..db51f72 100644 --- a/gcc/go/gofrontend/import.h +++ b/gcc/go/gofrontend/import.h @@ -18,6 +18,8 @@ class Named_object; class Named_type; class Expression; class Import_function_body; +class Temporary_statement; +class Unnamed_label; // Expressions can be imported either directly from import data (for // simple constant expressions that can appear in a const declaration @@ -587,7 +589,7 @@ class Import_function_body : public Import_expression const std::string& body, size_t off, Block* block, int indent) : gogo_(gogo), imp_(imp), named_object_(named_object), body_(body), - off_(off), block_(block), indent_(indent), temporaries_(), + off_(off), block_(block), indent_(indent), temporaries_(), labels_(), saw_error_(false) { } @@ -704,6 +706,11 @@ class Import_function_body : public Import_expression Temporary_statement* temporary_statement(unsigned int); + // Return an unnamed label given an index, defining the label if we + // haven't seen it already. + Unnamed_label* + unnamed_label(unsigned int, Location); + // Implement Import_expression. Import_function_body* ifb() @@ -730,6 +737,9 @@ class Import_function_body : public Import_expression { this->saw_error_ = true; } private: + static size_t + next_size(size_t); + // The IR. Gogo* gogo_; // The importer. @@ -747,6 +757,8 @@ class Import_function_body : public Import_expression int indent_; // Temporary statements by index. std::vector<Temporary_statement*> temporaries_; + // Unnamed labels by index. + std::vector<Unnamed_label*> labels_; // Whether we've seen an error. Used to avoid reporting excess // errors. bool saw_error_; diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index f680a0a..9ab1172 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -129,10 +129,15 @@ Statement::import_statement(Import_function_body* ifb, Location loc) { if (ifb->match_c_string("{")) { - Block* block = Block_statement::do_import(ifb, loc); + bool is_lowered_for_statement; + Block* block = Block_statement::do_import(ifb, loc, + &is_lowered_for_statement); if (block == NULL) return Statement::make_error_statement(loc); - return Statement::make_block_statement(block, loc); + Block_statement* s = Statement::make_block_statement(block, loc); + if (is_lowered_for_statement) + s->set_is_lowered_for_statement(); + return s; } else if (ifb->match_c_string("return")) { @@ -147,6 +152,10 @@ Statement::import_statement(Import_function_body* ifb, Location loc) return Variable_declaration_statement::do_import(ifb, loc); else if (ifb->match_c_string("if ")) return If_statement::do_import(ifb, loc); + else if (ifb->match_c_string(":")) + return Label_statement::do_import(ifb, loc); + else if (ifb->match_c_string("goto ")) + return Goto_statement::do_import(ifb, loc); Expression* lhs = Expression::import_expression(ifb, loc); ifb->require_c_string(" = "); @@ -2109,15 +2118,20 @@ Statement::make_statement(Expression* expr, bool is_ignored) void Block_statement::do_export_statement(Export_function_body* efb) { - Block_statement::export_block(efb, this->block_); + Block_statement::export_block(efb, this->block_, + this->is_lowered_for_statement_); } void -Block_statement::export_block(Export_function_body* efb, Block* block) +Block_statement::export_block(Export_function_body* efb, Block* block, + bool is_lowered_for_statement) { // We are already indented to the right position. char buf[50]; - snprintf(buf, sizeof buf, "{ //%d\n", + efb->write_c_string("{"); + if (is_lowered_for_statement) + efb->write_c_string(" /*for*/"); + snprintf(buf, sizeof buf, " //%d\n", Linemap::location_to_line(block->start_location())); efb->write_c_string(buf); @@ -2134,9 +2148,16 @@ Block_statement::export_block(Export_function_body* efb, Block* block) // Import a block statement, returning the block. Block* -Block_statement::do_import(Import_function_body* ifb, Location loc) +Block_statement::do_import(Import_function_body* ifb, Location loc, + bool* is_lowered_for_statement) { go_assert(ifb->match_c_string("{")); + *is_lowered_for_statement = false; + if (ifb->match_c_string(" /*for*/")) + { + ifb->advance(8); + *is_lowered_for_statement = true; + } size_t nl = ifb->body().find('\n', ifb->off()); if (nl == std::string::npos) { @@ -2176,7 +2197,7 @@ Block_statement::do_dump_statement(Ast_dump_context*) const // Make a block statement. -Statement* +Block_statement* Statement::make_block_statement(Block* block, Location location) { return new Block_statement(block, location); @@ -3344,6 +3365,61 @@ Goto_statement::do_get_backend(Translate_context* context) return context->backend()->goto_statement(blabel, this->location()); } +// Export a goto statement. + +void +Goto_statement::do_export_statement(Export_function_body *efb) +{ + efb->write_c_string("goto "); + efb->write_string(this->label_->name()); +} + +// Import a goto or goto unnamed statement. + +Statement* +Goto_statement::do_import(Import_function_body* ifb, Location loc) +{ + ifb->require_c_string("goto "); + std::string id = ifb->read_identifier(); + if (id[0] != '$') + { + Function* fn = ifb->function()->func_value(); + Label* label = fn->add_label_reference(ifb->gogo(), id, loc, false); + return Statement::make_goto_statement(label, loc); + } + else + { + if (id[1] != 'l') + { + if (!ifb->saw_error()) + go_error_at(loc, + ("invalid export data for %qs: " + "bad unnamed label at %lu"), + ifb->name().c_str(), + static_cast<unsigned long>(ifb->off())); + ifb->set_saw_error(); + return Statement::make_error_statement(loc); + } + 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 unnamed label index at %lu"), + ifb->name().c_str(), + static_cast<unsigned long>(ifb->off())); + ifb->set_saw_error(); + return Statement::make_error_statement(loc); + } + + Unnamed_label* label = ifb->unnamed_label(idx, loc); + return Statement::make_goto_unnamed_statement(label, loc); + } +} + // Dump the AST representation for a goto statement. void @@ -3377,6 +3453,17 @@ Goto_unnamed_statement::do_get_backend(Translate_context* context) return this->label_->get_goto(context, this->location()); } +// Export a goto unnamed statement. + +void +Goto_unnamed_statement::do_export_statement(Export_function_body *efb) +{ + unsigned int index = efb->unnamed_label_index(this->label_); + char buf[100]; + snprintf(buf, sizeof buf, "goto $l%u", index); + efb->write_c_string(buf); +} + // Dump the AST representation for an unnamed goto statement void @@ -3424,6 +3511,64 @@ Label_statement::do_get_backend(Translate_context* context) return context->backend()->label_definition_statement(blabel); } +// Export a label. + +void +Label_statement::do_export_statement(Export_function_body* efb) +{ + if (this->label_->is_dummy_label()) + return; + // We use a leading colon, not a trailing one, to simplify import. + efb->write_c_string(":"); + efb->write_string(this->label_->name()); +} + +// Import a label or an unnamed label. + +Statement* +Label_statement::do_import(Import_function_body* ifb, Location loc) +{ + ifb->require_c_string(":"); + std::string id = ifb->read_identifier(); + if (id[0] != '$') + { + Function* fn = ifb->function()->func_value(); + Label* label = fn->add_label_definition(ifb->gogo(), id, loc); + return Statement::make_label_statement(label, loc); + } + else + { + if (id[1] != 'l') + { + if (!ifb->saw_error()) + go_error_at(loc, + ("invalid export data for %qs: " + "bad unnamed label at %lu"), + ifb->name().c_str(), + static_cast<unsigned long>(ifb->off())); + ifb->set_saw_error(); + return Statement::make_error_statement(loc); + } + 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 unnamed label index at %lu"), + ifb->name().c_str(), + static_cast<unsigned long>(ifb->off())); + ifb->set_saw_error(); + return Statement::make_error_statement(loc); + } + + Unnamed_label* label = ifb->unnamed_label(idx, loc); + return Statement::make_unnamed_label_statement(label); + } +} + // Dump the AST for a label definition statement. void @@ -3462,6 +3607,18 @@ Unnamed_label_statement::do_get_backend(Translate_context* context) return this->label_->get_definition(context); } +// Export an unnamed label. + +void +Unnamed_label_statement::do_export_statement(Export_function_body* efb) +{ + unsigned int index = efb->unnamed_label_index(this->label_); + char buf[50]; + // We use a leading colon, not a trailing one, to simplify import. + snprintf(buf, sizeof buf, ":$l%u", index); + efb->write_c_string(buf); +} + // Dump the AST representation for an unnamed label definition statement. void @@ -3557,11 +3714,11 @@ 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_); + Block_statement::export_block(efb, this->then_block_, false); if (this->else_block_ != NULL) { efb->write_c_string(" else "); - Block_statement::export_block(efb, this->else_block_); + Block_statement::export_block(efb, this->else_block_, false); } } @@ -3588,9 +3745,22 @@ If_statement::do_import(Import_function_body* ifb, Location loc) return Statement::make_error_statement(loc); } - Block* then_block = Block_statement::do_import(ifb, loc); + bool is_lowered_for_statement; + Block* then_block = Block_statement::do_import(ifb, loc, + &is_lowered_for_statement); if (then_block == NULL) return Statement::make_error_statement(loc); + if (is_lowered_for_statement) + { + if (!ifb->saw_error()) + go_error_at(ifb->location(), + ("import error for %qs: " + "unexpected lowered for in 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* else_block = NULL; if (ifb->match_c_string(" else ")) @@ -3608,9 +3778,21 @@ If_statement::do_import(Import_function_body* ifb, Location loc) return Statement::make_error_statement(loc); } - else_block = Block_statement::do_import(ifb, loc); + else_block = Block_statement::do_import(ifb, loc, + &is_lowered_for_statement); if (else_block == NULL) return Statement::make_error_statement(loc); + if (is_lowered_for_statement) + { + if (!ifb->saw_error()) + go_error_at(ifb->location(), + ("import error for %qs: " + "unexpected lowered for in if statement at %lu"), + ifb->name().c_str(), + static_cast<unsigned long>(ifb->off())); + ifb->set_saw_error(); + return Statement::make_error_statement(loc); + } } return Statement::make_if_statement(cond, then_block, else_block, loc); diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h index 3e85243..432da30 100644 --- a/gcc/go/gofrontend/statements.h +++ b/gcc/go/gofrontend/statements.h @@ -187,7 +187,7 @@ class Statement // Make a block statement from a Block. This is an embedded list of // statements which may also include variable definitions. - static Statement* + static Block_statement* make_block_statement(Block*, Location); // Make an increment statement. @@ -956,11 +956,13 @@ class Block_statement : public Statement // Export a block for a block statement. static void - export_block(Export_function_body*, Block*); + export_block(Export_function_body*, Block*, bool is_lowered_for_statement); // Import a block statement, returning the block. + // *IS_LOWERED_FOR_STATEMENT reports whether this block statement + // was lowered from a for statement. static Block* - do_import(Import_function_body*, Location); + do_import(Import_function_body*, Location, bool* is_lowered_for_statement); protected: int @@ -1409,6 +1411,10 @@ class Goto_statement : public Statement label() const { return this->label_; } + // Import a goto statement. + static Statement* + do_import(Import_function_body*, Location); + protected: int do_traverse(Traverse*); @@ -1423,6 +1429,13 @@ class Goto_statement : public Statement Bstatement* do_get_backend(Translate_context*); + int + do_inlining_cost() + { return 5; } + + void + do_export_statement(Export_function_body*); + void do_dump_statement(Ast_dump_context*) const; @@ -1455,6 +1468,13 @@ class Goto_unnamed_statement : public Statement Bstatement* do_get_backend(Translate_context* context); + int + do_inlining_cost() + { return 5; } + + void + do_export_statement(Export_function_body*); + void do_dump_statement(Ast_dump_context*) const; @@ -1477,6 +1497,10 @@ class Label_statement : public Statement label() const { return this->label_; } + // Import a label or unnamed label. + static Statement* + do_import(Import_function_body*, Location); + protected: int do_traverse(Traverse*); @@ -1484,6 +1508,13 @@ class Label_statement : public Statement Bstatement* do_get_backend(Translate_context*); + int + do_inlining_cost() + { return 1; } + + void + do_export_statement(Export_function_body*); + void do_dump_statement(Ast_dump_context*) const; @@ -1506,6 +1537,13 @@ class Unnamed_label_statement : public Statement Bstatement* do_get_backend(Translate_context* context); + int + do_inlining_cost() + { return 1; } + + void + do_export_statement(Export_function_body*); + void do_dump_statement(Ast_dump_context*) const; |