diff options
-rw-r--r-- | gcc/go/gofrontend/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/export.cc | 43 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 228 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 22 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 44 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 6 | ||||
-rw-r--r-- | gcc/go/gofrontend/import.cc | 34 | ||||
-rw-r--r-- | libgo/go/go/internal/gccgoimporter/parser.go | 17 |
8 files changed, 345 insertions, 51 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index e9072a8..d596f02 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -949c3b7aa603bc09e650d62e82c600b3463802f0 +2609f9b8420e2341fbbe40d7cf6af42b0fba7293 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 108fdac..824f821 100644 --- a/gcc/go/gofrontend/export.cc +++ b/gcc/go/gofrontend/export.cc @@ -133,6 +133,11 @@ Collect_references_from_inline::expression(Expression** pexpr) if (fe != NULL) { Named_object* no = fe->named_object(); + + if (no->is_function_declaration() + && no->func_declaration_value()->type()->is_builtin()) + return TRAVERSE_CONTINUE; + std::pair<Unordered_set(Named_object*)::iterator, bool> ins = this->exports_->insert(no); @@ -247,6 +252,22 @@ Export::export_globals(const std::string& package_name, if ((*p)->is_function() && (*p)->func_value()->export_for_inlining()) check_inline_refs.push_back(*p); + else if ((*p)->is_type()) + { + const Bindings* methods = (*p)->type_value()->local_methods(); + if (methods != NULL) + { + for (Bindings::const_definitions_iterator pm = + methods->begin_definitions(); + pm != methods->end_definitions(); + ++pm) + { + Function* fn = (*pm)->func_value(); + if (fn->export_for_inlining()) + check_inline_refs.push_back(*pm); + } + } + } } } @@ -282,6 +303,9 @@ Export::export_globals(const std::string& package_name, } } + // Track all imported packages mentioned in export data. + Unordered_set(const Package*) all_imports; + // Export the symbols in sorted order. That will reduce cases where // irrelevant changes to the source code affect the exported // interface. @@ -291,15 +315,20 @@ Export::export_globals(const std::string& package_name, for (Unordered_set(Named_object*)::const_iterator p = exports.begin(); p != exports.end(); ++p) - sorted_exports.push_back(*p); + { + sorted_exports.push_back(*p); + + const Package* pkg = (*p)->package(); + if (pkg != NULL) + all_imports.insert(pkg); + } std::sort(sorted_exports.begin(), sorted_exports.end(), Sort_bindings()); // Assign indexes to all exported types and types referenced by // exported types, and collect all packages mentioned. - Unordered_set(const Package*) type_imports; int unexported_type_index = this->prepare_types(&sorted_exports, - &type_imports); + &all_imports); // Although the export data is readable, at least this version is, // it is conceptually a binary format. Start with a four byte @@ -327,7 +356,7 @@ Export::export_globals(const std::string& package_name, this->write_packages(packages); - this->write_imports(imports, type_imports); + this->write_imports(imports, all_imports); this->write_imported_init_fns(package_name, import_init_fn, imported_init_fns); @@ -693,7 +722,7 @@ import_compare(const std::pair<std::string, Package*>& a, void Export::write_imports(const std::map<std::string, Package*>& imports, - const Unordered_set(const Package*)& type_imports) + const Unordered_set(const Package*)& all_imports) { // Sort the imports for more consistent output. Unordered_set(const Package*) seen; @@ -729,8 +758,8 @@ Export::write_imports(const std::map<std::string, Package*>& imports, // Write out a separate list of indirectly imported packages. std::vector<const Package*> indirect_imports; for (Unordered_set(const Package*)::const_iterator p = - type_imports.begin(); - p != type_imports.end(); + all_imports.begin(); + p != all_imports.end(); ++p) { if (seen.find(*p) == seen.end()) diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index d7bf4d7..1493ddc 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -1356,6 +1356,29 @@ Func_expression::do_get_backend(Translate_context* context) return gogo->backend()->convert_expression(btype, bexpr, this->location()); } +// The cost of inlining a function reference. + +int +Func_expression::do_inlining_cost() const +{ + // FIXME: We don't inline references to nested functions. + if (this->closure_ != NULL) + return 0x100000; + if (this->function_->is_function() + && this->function_->func_value()->enclosing() != NULL) + return 0x100000; + + return 1; +} + +// Export a reference to a function. + +void +Func_expression::do_export(Export_function_body* efb) const +{ + Expression::export_name(efb, this->function_); +} + // Ast dump for function. void @@ -10088,38 +10111,82 @@ void Builtin_call_expression::do_export(Export_function_body* efb) const { Numeric_constant nc; - if (!this->numeric_constant_value(&nc)) + if (this->numeric_constant_value(&nc)) { - go_error_at(this->location(), "value is not constant"); - return; - } + if (nc.is_int()) + { + mpz_t val; + nc.get_int(&val); + Integer_expression::export_integer(efb, val); + mpz_clear(val); + } + else if (nc.is_float()) + { + mpfr_t fval; + nc.get_float(&fval); + Float_expression::export_float(efb, fval); + mpfr_clear(fval); + } + else if (nc.is_complex()) + { + mpc_t cval; + nc.get_complex(&cval); + Complex_expression::export_complex(efb, cval); + mpc_clear(cval); + } + else + go_unreachable(); - if (nc.is_int()) - { - mpz_t val; - nc.get_int(&val); - Integer_expression::export_integer(efb, val); - mpz_clear(val); + // A trailing space lets us reliably identify the end of the number. + efb->write_c_string(" "); } - else if (nc.is_float()) - { - mpfr_t fval; - nc.get_float(&fval); - Float_expression::export_float(efb, fval); - mpfr_clear(fval); - } - else if (nc.is_complex()) + else { - mpc_t cval; - nc.get_complex(&cval); - Complex_expression::export_complex(efb, cval); - mpc_clear(cval); + const char *s = NULL; + switch (this->code_) + { + default: + go_unreachable(); + case BUILTIN_APPEND: + s = "append"; + break; + case BUILTIN_COPY: + s = "copy"; + break; + case BUILTIN_LEN: + s = "len"; + break; + case BUILTIN_CAP: + s = "cap"; + break; + case BUILTIN_PRINT: + s = "print"; + break; + case BUILTIN_PRINTLN: + s = "println"; + break; + case BUILTIN_PANIC: + s = "panic"; + break; + case BUILTIN_RECOVER: + s = "recover"; + break; + case BUILTIN_CLOSE: + s = "close"; + break; + case BUILTIN_REAL: + s = "real"; + break; + case BUILTIN_IMAG: + s = "imag"; + break; + case BUILTIN_COMPLEX: + s = "complex"; + break; + } + efb->write_c_string(s); + this->export_arguments(efb); } - else - go_unreachable(); - - // A trailing space lets us reliably identify the end of the number. - efb->write_c_string(" "); } // Class Call_expression. @@ -11637,7 +11704,55 @@ Call_expression::do_get_backend(Translate_context* context) return this->call_; } -// Dump ast representation for a call expressin. +// The cost of inlining a call expression. + +int +Call_expression::do_inlining_cost() const +{ + Func_expression* fn = this->fn_->func_expression(); + + // FIXME: We don't yet support all kinds of calls. + if (fn != NULL && fn->closure() != NULL) + return 0x100000; + if (this->fn_->interface_field_reference_expression()) + return 0x100000; + if (this->get_function_type()->is_method()) + return 0x100000; + + return 5; +} + +// Export a call expression. + +void +Call_expression::do_export(Export_function_body* efb) const +{ + this->fn_->export_expression(efb); + this->export_arguments(efb); +} + +// Export call expression arguments. + +void +Call_expression::export_arguments(Export_function_body* efb) const +{ + efb->write_c_string("("); + if (this->args_ != NULL && !this->args_->empty()) + { + Expression_list::const_iterator pa = this->args_->begin(); + (*pa)->export_expression(efb); + for (pa++; pa != this->args_->end(); pa++) + { + efb->write_c_string(", "); + (*pa)->export_expression(efb); + } + if (this->is_varargs_) + efb->write_c_string("..."); + } + efb->write_c_string(")"); +} + +// Dump ast representation for a call expression. void Call_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const @@ -17523,6 +17638,47 @@ Expression::make_backend(Bexpression* bexpr, Type* type, Location location) Expression* Expression::import_expression(Import_expression* imp, Location loc) { + Expression* expr = Expression::import_expression_without_suffix(imp, loc); + while (true) + { + if (imp->match_c_string("(")) + { + imp->advance(1); + Expression_list* args = new Expression_list(); + bool is_varargs = false; + while (!imp->match_c_string(")")) + { + Expression* arg = Expression::import_expression(imp, loc); + if (arg->is_error_expression()) + return arg; + args->push_back(arg); + if (imp->match_c_string(")")) + break; + else if (imp->match_c_string("...)")) + { + imp->advance(3); + is_varargs = true; + break; + } + imp->require_c_string(", "); + } + imp->require_c_string(")"); + expr = Expression::make_call(expr, args, is_varargs, loc); + } + else + break; + } + + return expr; +} + +// Import an expression without considering a suffix (function +// arguments, index operations, etc.). + +Expression* +Expression::import_expression_without_suffix(Import_expression* imp, + Location loc) +{ int c = imp->peek_char(); if (c == '+' || c == '-' || c == '!' || c == '^' || c == '&' || c == '*') return Unary_expression::do_import(imp, loc); @@ -17608,7 +17764,21 @@ Expression::import_identifier(Import_function_body* ifb, Location loc) return Expression::make_error(loc); } - return Expression::make_var_reference(no, loc); + if (no->is_variable() || no->is_result_variable()) + return Expression::make_var_reference(no, loc); + else if (no->is_function() || no->is_function_declaration()) + return Expression::make_func_reference(no, NULL, loc); + else + { + if (!ifb->saw_error()) + go_error_at(ifb->location(), + ("import error for %qs: " + "unexpected type of identifier %qs (%d)"), + ifb->name().c_str(), + id.c_str(), no->classification()); + ifb->set_saw_error(); + return Expression::make_error(loc); + } } // Class Expression_list. diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index e17e8dc..fc1c5a8 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -1253,6 +1253,9 @@ class Expression static Expression* import_identifier(Import_function_body*, Location); + static Expression* + import_expression_without_suffix(Import_expression*, Location); + // The expression classification. Expression_classification classification_; // The location in the input file. @@ -2409,6 +2412,12 @@ class Call_expression : public Expression virtual Bexpression* do_get_backend(Translate_context*); + int + do_inlining_cost() const; + + void + do_export(Export_function_body*) const; + virtual bool do_is_recover_call() const; @@ -2432,6 +2441,9 @@ class Call_expression : public Expression determining_types(); void + export_arguments(Export_function_body*) const; + + void do_dump_expression(Ast_dump_context*) const; void @@ -2571,6 +2583,10 @@ class Builtin_call_expression : public Call_expression Bexpression* do_get_backend(Translate_context*); + int + do_inlining_cost() const + { return 1; } + void do_export(Export_function_body*) const; @@ -2745,6 +2761,12 @@ class Func_expression : public Expression Bexpression* do_get_backend(Translate_context*); + int + do_inlining_cost() const; + + void + do_export(Export_function_body*) const; + void do_dump_expression(Ast_dump_context*) const; diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index ce9bffb..6e8ccbb 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -5059,6 +5059,9 @@ Mark_inline_candidates::type(Type* t) void Gogo::do_exports() { + if (saw_errors()) + return; + // Mark any functions whose body should be exported for inlining by // other packages. Mark_inline_candidates mic; @@ -5690,7 +5693,7 @@ Function::export_func(Export* exp, const Named_object* no) const block = this->block_; Function::export_func_with_type(exp, no, this->type_, this->results_, this->is_method() && this->nointerface(), - block, this->location_); + this->asm_name(), block, this->location_); } // Export a function with a type. @@ -5699,7 +5702,8 @@ void Function::export_func_with_type(Export* exp, const Named_object* no, const Function_type* fntype, Function::Results* result_vars, - bool nointerface, Block* block, Location loc) + bool nointerface, const std::string& asm_name, + Block* block, Location loc) { exp->write_c_string("func "); @@ -5709,6 +5713,13 @@ Function::export_func_with_type(Export* exp, const Named_object* no, exp->write_c_string("/*nointerface*/ "); } + if (!asm_name.empty()) + { + exp->write_c_string("/*asm "); + exp->write_string(asm_name); + exp->write_c_string(" */ "); + } + if (fntype->is_method()) { exp->write_c_string("("); @@ -5848,16 +5859,37 @@ Function::import_func(Import* imp, std::string* pname, Typed_identifier_list** presults, bool* is_varargs, bool* nointerface, + std::string* asm_name, std::string* body) { imp->require_c_string("func "); *nointerface = false; - if (imp->match_c_string("/*")) + while (imp->match_c_string("/*")) { - imp->require_c_string("/*nointerface*/ "); - *nointerface = true; + imp->advance(2); + if (imp->match_c_string("nointerface")) + { + imp->require_c_string("nointerface*/ "); + *nointerface = true; + } + else if (imp->match_c_string("asm")) + { + imp->require_c_string("asm "); + *asm_name = imp->read_identifier(); + imp->require_c_string(" */ "); + } + else + { + go_error_at(imp->location(), + "import error at %d: unrecognized function comment", + imp->pos()); + return false; + } + } + if (*nointerface) + { // Only a method can be nointerface. go_assert(imp->peek_char() == '('); } @@ -7158,6 +7190,8 @@ Function_declaration::import_function_body(Gogo* gogo, Named_object* no) Named_type* rtype = fntype->receiver()->type()->deref()->named_type(); go_assert(rtype != NULL); no = rtype->add_method(no->name(), fn); + const Package* package = rtype->named_object()->package(); + package->bindings()->add_method(no); } Import_function_body ifb(gogo, this->imp_, no, body, nl + 1, outer, indent); diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index 91e3bdf..1197476 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -1573,7 +1573,7 @@ class Function static void export_func_with_type(Export*, const Named_object*, const Function_type*, Results*, bool nointerface, - Block* block, Location); + const std::string& asm_name, Block* block, Location); // Import a function. Reports whether the import succeeded. static bool @@ -1581,7 +1581,7 @@ class Function bool* is_exported, Typed_identifier** receiver, Typed_identifier_list** pparameters, Typed_identifier_list** presults, bool* is_varargs, - bool* nointerface, std::string* body); + bool* nointerface, std::string* asm_name, std::string* body); private: // Type for mapping from label names to Label objects. @@ -1805,7 +1805,7 @@ class Function_declaration { Function::export_func_with_type(exp, no, this->fntype_, NULL, this->is_method() && this->nointerface(), - NULL, this->location_); + this->asm_name_, NULL, this->location_); } // Check that the types used in this declaration's signature are defined. diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc index ff92b82..1c3f4a4 100644 --- a/gcc/go/gofrontend/import.cc +++ b/gcc/go/gofrontend/import.cc @@ -757,10 +757,11 @@ Import::import_func(Package* package) Typed_identifier_list* results; bool is_varargs; bool nointerface; + std::string asm_name; std::string body; if (!Function::import_func(this, &name, &fpkg, &is_exported, &receiver, ¶meters, &results, &is_varargs, &nointerface, - &body)) + &asm_name, &body)) return; if (fpkg == NULL) fpkg = package; @@ -802,12 +803,14 @@ Import::import_func(Package* package) else { no = fpkg->add_function_declaration(name, fntype, loc); - if (this->add_to_globals_) + if (this->add_to_globals_ && fpkg == package) this->gogo_->add_dot_import_object(no); } if (nointerface) no->func_declaration_value()->set_nointerface(); + if (!asm_name.empty()) + no->func_declaration_value()->set_asm_name(asm_name); if (!body.empty() && !no->func_declaration_value()->has_imported_body()) no->func_declaration_value()->set_imported_body(this, body); } @@ -1231,6 +1234,12 @@ Import::register_builtin_type(Gogo* gogo, const char* name, Builtin_code code) this->builtin_types_[index] = named_object->type_value(); } +// Characters that stop read_identifier. We base this on the +// characters that stop an identifier, without worrying about +// characters that are permitted in an identifier. That lets us skip +// UTF-8 parsing. +static const char * const identifier_stop = " \n;,()[]"; + // Read an identifier from the stream. std::string @@ -1242,8 +1251,14 @@ Import::read_identifier() while (true) { c = stream->peek_char(); - if (c == -1 || c == ' ' || c == '\n' || c == ';' || c == ')') + if (c == -1 || strchr(identifier_stop, c) != NULL) break; + + // FIXME: Probably we shouldn't accept '.', but that might break + // some existing imports. + if (c == '.' && stream->match_c_string("...")) + break; + ret += c; stream->advance(1); } @@ -1521,7 +1536,18 @@ Import_function_body::read_identifier() for (size_t i = start; i < this->body_.length(); i++) { int c = static_cast<unsigned char>(this->body_[i]); - if (c == ' ' || c == '\n' || c == ';' || c == ')') + if (strchr(identifier_stop, c) != NULL) + { + this->off_ = i; + return this->body_.substr(start, i - start); + } + + // FIXME: Probably we shouldn't accept '.', but that might break + // some existing imports. + if (c == '.' + && i + 2 < this->body_.length() + && this->body_[i + 1] == '.' + && this->body_[i + 2] == '.') { this->off_ = i; return this->body_.substr(start, i - start); diff --git a/libgo/go/go/internal/gccgoimporter/parser.go b/libgo/go/go/internal/gccgoimporter/parser.go index 42f43a1..956a9a8 100644 --- a/libgo/go/go/internal/gccgoimporter/parser.go +++ b/libgo/go/go/internal/gccgoimporter/parser.go @@ -539,10 +539,12 @@ func (p *parser) parseNamedType(nlist []int) types.Type { for p.tok == scanner.Ident { p.expectKeyword("func") if p.tok == '/' { - // Skip a /*nointerface*/ comment. + // Skip a /*nointerface*/ or /*asm ID */ comment. p.expect('/') p.expect('*') - p.expect(scanner.Ident) + if p.expect(scanner.Ident) == "asm" { + p.parseUnquotedString() + } p.expect('*') p.expect('/') } @@ -727,6 +729,17 @@ func (p *parser) parseFunctionType(pkg *types.Package, nlist []int) *types.Signa // Func = Name FunctionType [InlineBody] . func (p *parser) parseFunc(pkg *types.Package) *types.Func { + if p.tok == '/' { + // Skip an /*asm ID */ comment. + p.expect('/') + p.expect('*') + if p.expect(scanner.Ident) == "asm" { + p.parseUnquotedString() + } + p.expect('*') + p.expect('/') + } + name := p.parseName() if strings.ContainsRune(name, '$') { // This is a Type$equal or Type$hash function, which we don't want to parse, |