diff options
author | Ian Lance Taylor <iant@golang.org> | 2022-02-11 15:02:44 -0800 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2022-02-11 15:02:44 -0800 |
commit | 9a510fb0970d3d9a4201bce8965cabe67850386b (patch) | |
tree | 43d7fd2bbfd7ad8c9625a718a5e8718889351994 /gcc/go | |
parent | a6d3012b274f38b20e2a57162106f625746af6c6 (diff) | |
parent | 8dc2499aa62f768c6395c9754b8cabc1ce25c494 (diff) | |
download | gcc-9a510fb0970d3d9a4201bce8965cabe67850386b.zip gcc-9a510fb0970d3d9a4201bce8965cabe67850386b.tar.gz gcc-9a510fb0970d3d9a4201bce8965cabe67850386b.tar.bz2 |
Merge from trunk revision 8dc2499aa62f768c6395c9754b8cabc1ce25c494
Diffstat (limited to 'gcc/go')
-rw-r--r-- | gcc/go/ChangeLog | 43 | ||||
-rw-r--r-- | gcc/go/Make-lang.in | 6 | ||||
-rw-r--r-- | gcc/go/config-lang.in | 4 | ||||
-rw-r--r-- | gcc/go/gccgo.texi | 6 | ||||
-rw-r--r-- | gcc/go/go-backend.cc (renamed from gcc/go/go-backend.c) | 4 | ||||
-rw-r--r-- | gcc/go/go-c.h | 2 | ||||
-rw-r--r-- | gcc/go/go-gcc-diagnostics.cc | 2 | ||||
-rw-r--r-- | gcc/go/go-gcc.cc | 16 | ||||
-rw-r--r-- | gcc/go/go-gcc.h | 2 | ||||
-rw-r--r-- | gcc/go/go-lang.cc (renamed from gcc/go/go-lang.c) | 4 | ||||
-rw-r--r-- | gcc/go/go-sha1.cc | 2 | ||||
-rw-r--r-- | gcc/go/go-system.h | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 280 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 8 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 266 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 4 | ||||
-rw-r--r-- | gcc/go/gofrontend/runtime.def | 4 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.cc | 43 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.h | 5 | ||||
-rw-r--r-- | gcc/go/gospec.cc (renamed from gcc/go/gospec.c) | 46 | ||||
-rw-r--r-- | gcc/go/lang-specs.h | 4 | ||||
-rw-r--r-- | gcc/go/lang.opt | 2 |
23 files changed, 541 insertions, 216 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index c17e3a4..dd94ab3 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,44 @@ +2022-02-09 Ian Lance Taylor <iant@golang.org> + + * gospec.cc (RTLIB, RT_LIBRARY): Define. + (lang_specific_driver): Add -lrt if linking statically on + GNU/Linux. + +2022-02-09 Ian Lance Taylor <iant@golang.org> + + * go-gcc.cc (Gcc_backend::Gcc_backend): Define builtins + __atomic_load_1 and __atomic_store_1. + +2022-01-17 Martin Liska <mliska@suse.cz> + + * config-lang.in: Rename .c names to .cc. + * go-backend.cc: Likewise. + * go-lang.cc: Likewise. + * gospec.cc: Likewise. + * lang-specs.h: Likewise. + +2022-01-17 Martin Liska <mliska@suse.cz> + + * go-backend.c: Moved to... + * go-backend.cc: ...here. + * go-lang.c: Moved to... + * go-lang.cc: ...here. + * gospec.c: Moved to... + * gospec.cc: ...here. + +2022-01-03 Jakub Jelinek <jakub@redhat.com> + + * gccgo.texi: Bump @copyrights-go year. + +2021-12-28 Martin Liska <mliska@suse.cz> + + * gccgo.texi: Replace http:// with https. + +2021-11-29 Eric Gallager <egallager@gcc.gnu.org> + + PR other/103021 + * Make-lang.in: Use ETAGS variable in TAGS target. + 2021-09-27 Martin Liska <mliska@suse.cz> * go-lang.c (go_langhook_init_options_struct): Set also @@ -1792,7 +1833,7 @@ Go frontend added to gcc repository. -Copyright (C) 2010-2021 Free Software Foundation, Inc. +Copyright (C) 2010-2022 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright diff --git a/gcc/go/Make-lang.in b/gcc/go/Make-lang.in index 4bdc8f6..31c6773 100644 --- a/gcc/go/Make-lang.in +++ b/gcc/go/Make-lang.in @@ -1,6 +1,6 @@ # Make-lang.in -- Top level -*- makefile -*- fragment for gcc Go frontend. -# Copyright (C) 2009-2021 Free Software Foundation, Inc. +# Copyright (C) 2009-2022 Free Software Foundation, Inc. # This file is part of GCC. @@ -133,8 +133,8 @@ go.srcinfo: doc/gccgo.info go.srcextra: go.tags: force cd $(srcdir)/go; \ - etags -o TAGS.sub *.c *.h gofrontend/*.h gofrontend/*.cc; \ - etags --include TAGS.sub --include ../TAGS.sub + $(ETAGS) -o TAGS.sub *.c *.h gofrontend/*.h gofrontend/*.cc; \ + $(ETAGS) --include TAGS.sub --include ../TAGS.sub go.man: doc/gccgo.1 go.srcman: doc/gccgo.1 -cp -p $^ $(srcdir)/doc diff --git a/gcc/go/config-lang.in b/gcc/go/config-lang.in index 18fcaba..19fdbc3 100644 --- a/gcc/go/config-lang.in +++ b/gcc/go/config-lang.in @@ -1,6 +1,6 @@ # config-lang.in -- Top level configure fragment for gcc Go frontend. -# Copyright (C) 2009-2021 Free Software Foundation, Inc. +# Copyright (C) 2009-2022 Free Software Foundation, Inc. # This file is part of GCC. @@ -31,7 +31,7 @@ compilers="go1\$(exeext)" target_libs="target-libgo target-libffi target-libbacktrace" lang_dirs="gotools" -gtfiles="\$(srcdir)/go/go-lang.c \$(srcdir)/go/go-c.h" +gtfiles="\$(srcdir)/go/go-lang.cc \$(srcdir)/go/go-c.h" # Do not build by default. build_by_default="no" diff --git a/gcc/go/gccgo.texi b/gcc/go/gccgo.texi index fa0e488..66020aa7 100644 --- a/gcc/go/gccgo.texi +++ b/gcc/go/gccgo.texi @@ -12,7 +12,7 @@ @include gcc-common.texi @c Copyright years for this manual. -@set copyrights-go 2010-2021 +@set copyrights-go 2010-2022 @copying @c man begin COPYRIGHT @@ -80,7 +80,7 @@ This manual describes how to use @command{gccgo}, the GNU compiler for the Go programming language. This manual is specifically about @command{gccgo}. For more information about the Go programming language in general, including language specifications and standard -package documentation, see @uref{http://golang.org/}. +package documentation, see @uref{https://golang.org/}. @menu * Copying:: The GNU General Public License. @@ -382,7 +382,7 @@ or with C++ code compiled using @code{extern "C"}. This information is provided largely for documentation purposes. For ordinary use it is best to build programs with the go tool and then use @code{import "C"}, as described at -@url{http://golang.org/cmd/cgo}. +@url{https://golang.org/cmd/cgo}. @menu * C Type Interoperability:: How C and Go types match up. diff --git a/gcc/go/go-backend.c b/gcc/go/go-backend.cc index 7a223e5..7eed943 100644 --- a/gcc/go/go-backend.c +++ b/gcc/go/go-backend.cc @@ -1,5 +1,5 @@ -/* go-backend.c -- Go frontend interface to gcc backend. - Copyright (C) 2010-2021 Free Software Foundation, Inc. +/* go-backend.cc -- Go frontend interface to gcc backend. + Copyright (C) 2010-2022 Free Software Foundation, Inc. This file is part of GCC. diff --git a/gcc/go/go-c.h b/gcc/go/go-c.h index 5930ead..d2de9e7 100644 --- a/gcc/go/go-c.h +++ b/gcc/go/go-c.h @@ -1,5 +1,5 @@ /* go-c.h -- Header file for go frontend gcc C interface. - Copyright (C) 2009-2021 Free Software Foundation, Inc. + Copyright (C) 2009-2022 Free Software Foundation, Inc. This file is part of GCC. diff --git a/gcc/go/go-gcc-diagnostics.cc b/gcc/go/go-gcc-diagnostics.cc index 1a678ed..23c3c07 100644 --- a/gcc/go/go-gcc-diagnostics.cc +++ b/gcc/go/go-gcc-diagnostics.cc @@ -1,5 +1,5 @@ // go-gcc-diagnostics.cc -- GCC implementation of go diagnostics interface. -// Copyright (C) 2016-2021 Free Software Foundation, Inc. +// Copyright (C) 2016-2022 Free Software Foundation, Inc. // Contributed by Than McIntosh, Google. // This file is part of GCC. diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index f812796..f3de7a8 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -1,5 +1,5 @@ // go-gcc.cc -- Go frontend to gcc IR. -// Copyright (C) 2011-2021 Free Software Foundation, Inc. +// Copyright (C) 2011-2022 Free Software Foundation, Inc. // Contributed by Ian Lance Taylor, Google. // This file is part of GCC. @@ -898,6 +898,20 @@ Gcc_backend::Gcc_backend() t, 0); t = build_function_type_list(unsigned_char_type_node, + ptr_type_node, + integer_type_node, + NULL_TREE); + this->define_builtin(BUILT_IN_ATOMIC_LOAD_1, "__atomic_load_1", NULL, t, 0); + + t = build_function_type_list(void_type_node, + ptr_type_node, + unsigned_char_type_node, + integer_type_node, + NULL_TREE); + this->define_builtin(BUILT_IN_ATOMIC_STORE_1, "__atomic_store_1", NULL, + t, 0); + + t = build_function_type_list(unsigned_char_type_node, ptr_type_node, unsigned_char_type_node, integer_type_node, diff --git a/gcc/go/go-gcc.h b/gcc/go/go-gcc.h index bff4307..86f027d 100644 --- a/gcc/go/go-gcc.h +++ b/gcc/go/go-gcc.h @@ -1,5 +1,5 @@ /* go-gcc.h -- Header file for go backend-specific interfaces. - Copyright (C) 2016-2021 Free Software Foundation, Inc. + Copyright (C) 2016-2022 Free Software Foundation, Inc. This file is part of GCC. diff --git a/gcc/go/go-lang.c b/gcc/go/go-lang.cc index c3ae6f0..c8365d2 100644 --- a/gcc/go/go-lang.c +++ b/gcc/go/go-lang.cc @@ -1,5 +1,5 @@ -/* go-lang.c -- Go frontend gcc interface. - Copyright (C) 2009-2021 Free Software Foundation, Inc. +/* go-lang.cc -- Go frontend gcc interface. + Copyright (C) 2009-2022 Free Software Foundation, Inc. This file is part of GCC. diff --git a/gcc/go/go-sha1.cc b/gcc/go/go-sha1.cc index 1d6f7de..ab74414 100644 --- a/gcc/go/go-sha1.cc +++ b/gcc/go/go-sha1.cc @@ -1,5 +1,5 @@ /* go-sha1.cc -- Go frontend interface to gcc backend. - Copyright (C) 2016-2021 Free Software Foundation, Inc. + Copyright (C) 2016-2022 Free Software Foundation, Inc. This file is part of GCC. diff --git a/gcc/go/go-system.h b/gcc/go/go-system.h index 9b0d18f..7ea1057 100644 --- a/gcc/go/go-system.h +++ b/gcc/go/go-system.h @@ -1,5 +1,5 @@ // go-system.h -- Go frontend inclusion of gcc header files -*- C++ -*- -// Copyright (C) 2009-2021 Free Software Foundation, Inc. +// Copyright (C) 2009-2022 Free Software Foundation, Inc. // This file is part of GCC. diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index e7ff670..4e6bac7 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -128ea3dce9b8753167f33d0a96bd093a6cbd58b8 +47380f733ca932384e59492d2f04374edd8ec95e 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 ddb1d91..1b3b3bf 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -2123,9 +2123,15 @@ String_expression::do_get_backend(Translate_context* context) Location loc = this->location(); std::vector<Bexpression*> init(2); - Bexpression* str_cst = - gogo->backend()->string_constant_expression(this->val_); - init[0] = gogo->backend()->address_expression(str_cst, loc); + + if (this->val_.size() == 0) + init[0] = gogo->backend()->nil_pointer_expression(); + else + { + Bexpression* str_cst = + gogo->backend()->string_constant_expression(this->val_); + init[0] = gogo->backend()->address_expression(str_cst, loc); + } Btype* int_btype = Type::lookup_integer_type("int")->get_backend(gogo); mpz_t lenval; @@ -7981,7 +7987,7 @@ Bound_method_expression::do_check_types(Gogo*) Bound_method_expression::Method_value_thunks Bound_method_expression::method_value_thunks; -// Find or create the thunk for METHOD. +// Find or create the thunk for FN. Named_object* Bound_method_expression::create_thunk(Gogo* gogo, const Method* method, @@ -8078,14 +8084,28 @@ Bound_method_expression::create_thunk(Gogo* gogo, const Method* method, gogo->add_statement(s); Block* b = gogo->finish_block(loc); gogo->add_block(b, loc); + + // This is called after lowering but before determine_types. gogo->lower_block(new_no, b); - gogo->flatten_block(new_no, b); + gogo->finish_function(loc); ins.first->second = new_no; return new_no; } +// Look up a thunk for FN. + +Named_object* +Bound_method_expression::lookup_thunk(Named_object* fn) +{ + Method_value_thunks::const_iterator p = + Bound_method_expression::method_value_thunks.find(fn); + if (p == Bound_method_expression::method_value_thunks.end()) + return NULL; + return p->second; +} + // Return an expression to check *REF for nil while dereferencing // according to FIELD_INDEXES. Update *REF to build up the field // reference. This is a static function so that we don't have to @@ -8129,10 +8149,11 @@ Bound_method_expression::do_flatten(Gogo* gogo, Named_object*, { Location loc = this->location(); - Named_object* thunk = Bound_method_expression::create_thunk(gogo, - this->method_, - this->function_); - if (thunk->is_erroneous()) + Named_object* thunk = Bound_method_expression::lookup_thunk(this->function_); + + // The thunk should have been created during the + // create_function_descriptors pass. + if (thunk == NULL || thunk->is_erroneous()) { go_assert(saw_errors()); return Expression::make_error(loc); @@ -10311,16 +10332,7 @@ Builtin_call_expression::do_check_types(Gogo*) case BUILTIN_PRINTLN: { const Expression_list* args = this->args(); - if (args == NULL) - { - if (this->code_ == BUILTIN_PRINT) - go_warning_at(this->location(), 0, - "no arguments for built-in function %<%s%>", - (this->code_ == BUILTIN_PRINT - ? "print" - : "println")); - } - else + if (args != NULL) { for (Expression_list::const_iterator p = args->begin(); p != args->end(); @@ -11598,12 +11610,16 @@ Call_expression::intrinsify(Gogo* gogo, std::string package = (no->package() != NULL ? no->package()->pkgpath() : gogo->pkgpath()); + bool is_method = ((no->is_function() && no->func_value()->is_method()) + || (no->is_function_declaration() + && no->func_declaration_value()->is_method())); Location loc = this->location(); Type* int_type = Type::lookup_integer_type("int"); Type* int32_type = Type::lookup_integer_type("int32"); Type* int64_type = Type::lookup_integer_type("int64"); Type* uint_type = Type::lookup_integer_type("uint"); + Type* uint8_type = Type::lookup_integer_type("uint8"); Type* uint32_type = Type::lookup_integer_type("uint32"); Type* uint64_type = Type::lookup_integer_type("uint64"); Type* uintptr_type = Type::lookup_integer_type("uintptr"); @@ -11614,6 +11630,9 @@ Call_expression::intrinsify(Gogo* gogo, if (package == "sync/atomic") { + if (is_method) + return NULL; + // sync/atomic functions and runtime/internal/atomic functions // are very similar. In order not to duplicate code, we just // redirect to the latter and let the code below to handle them. @@ -11679,6 +11698,9 @@ Call_expression::intrinsify(Gogo* gogo, if (package == "runtime/internal/sys") { + if (is_method) + return NULL; + // runtime/internal/sys functions and math/bits functions // are very similar. In order not to duplicate code, we just // redirect to the latter and let the code below to handle them. @@ -11698,6 +11720,9 @@ Call_expression::intrinsify(Gogo* gogo, if (package == "runtime") { + if (is_method) + return NULL; + // Handle a couple of special runtime functions. In the runtime // package, getcallerpc returns the PC of the caller, and // getcallersp returns the frame pointer of the caller. Implement @@ -11728,6 +11753,9 @@ Call_expression::intrinsify(Gogo* gogo, } else if (package == "math/bits") { + if (is_method) + return NULL; + if ((name == "ReverseBytes16" || name == "ReverseBytes32" || name == "ReverseBytes64" || name == "ReverseBytes") && this->args_ != NULL && this->args_->size() == 1) @@ -11898,9 +11926,137 @@ Call_expression::intrinsify(Gogo* gogo, { int memorder = __ATOMIC_SEQ_CST; + if (is_method) + { + Function_type* ftype = (no->is_function() + ? no->func_value()->type() + : no->func_declaration_value()->type()); + Type* rtype = ftype->receiver()->type()->deref(); + go_assert(rtype->named_type() != NULL); + const std::string& rname(rtype->named_type()->name()); + if (rname == "Int32") + { + if (name == "Load") + name = "LoadInt32"; + else if (name == "Store") + name = "Storeint32"; + else if (name == "CompareAndSwap") + name = "Casint32"; + else if (name == "Swap") + name = "Xchgint32"; + else if (name == "Add") + name = "Xaddint32"; + else + go_unreachable(); + } + else if (rname == "Int64") + { + if (name == "Load") + name = "LoadInt64"; + else if (name == "Store") + name = "Storeint64"; + else if (name == "CompareAndSwap") + name = "Casint64"; + else if (name == "Swap") + name = "Xchgint64"; + else if (name == "Add") + name = "Xaddint64"; + else + go_unreachable(); + } + else if (rname == "Uint8") + { + if (name == "Load") + name = "Load8"; + else if (name == "Store") + name = "Store8"; + else if (name == "And") + name = "And8"; + else if (name == "Or") + name = "Or8"; + else + go_unreachable(); + } + else if (rname == "Uint32") + { + if (name == "Load") + name = "Load"; + else if (name == "LoadAcquire") + name = "LoadAcq"; + else if (name == "Store") + name = "Store"; + else if (name == "CompareAndSwap") + name = "Cas"; + else if (name == "CompareAndSwapRelease") + name = "CasRel"; + else if (name == "Swap") + name = "Xchg"; + else if (name == "And") + name = "And"; + else if (name == "Or") + name = "Or"; + else if (name == "Add") + name = "Xadd"; + else + go_unreachable(); + } + else if (rname == "Uint64") + { + if (name == "Load") + name = "Load64"; + else if (name == "Store") + name = "Store64"; + else if (name == "CompareAndSwap") + name = "Cas64"; + else if (name == "Swap") + name = "Xchgt64"; + else if (name == "Add") + name = "Xadd64"; + else + go_unreachable(); + } + else if (rname == "Uintptr") + { + if (name == "Load") + name = "Loaduintptr"; + else if (name == "LoadAcquire") + name = "Loadacquintptr"; + else if (name == "Store") + name = "Storeuintptr"; + else if (name == "StoreRelease") + name = "StoreReluintptr"; + else if (name == "CompareAndSwap") + name = "Casuintptr"; + else if (name == "Swap") + name = "Xchguintptr"; + else if (name == "Add") + name = "Xadduintptr"; + else + go_unreachable(); + } + else if (rname == "Float64") + { + // Needs unsafe type conversion. Don't intrinsify for now. + return NULL; + } + else if (rname == "UnsafePointer") + { + if (name == "Load") + name = "Loadp"; + else if (name == "StoreNoWB") + name = "StorepoWB"; + else if (name == "CompareAndSwapNoWB") + name = "Casp1"; + else + go_unreachable(); + } + else + go_unreachable(); + } + if ((name == "Load" || name == "Load64" || name == "Loadint64" || name == "Loadp" || name == "Loaduint" || name == "Loaduintptr" || name == "LoadAcq" - || name == "Loadint32") + || name == "Loadint32" || name == "Load8") && this->args_ != NULL && this->args_->size() == 1) { if (int_size < 8 && (name == "Load64" || name == "Loadint64")) @@ -11957,6 +12113,11 @@ Call_expression::intrinsify(Gogo* gogo, res_type = uint32_type; memorder = __ATOMIC_ACQUIRE; } + else if (name == "Load8") + { + code = Runtime::ATOMIC_LOAD_1; + res_type = uint8_type; + } else go_unreachable(); Expression* a1 = this->args_->front(); @@ -11997,6 +12158,8 @@ Call_expression::intrinsify(Gogo* gogo, code = Runtime::ATOMIC_STORE_4; memorder = __ATOMIC_RELEASE; } + else if (name == "Store8") + code = Runtime::ATOMIC_STORE_1; else go_unreachable(); Expression* a3 = Expression::make_integer_ul(memorder, int32_type, loc); @@ -12162,6 +12325,53 @@ Call_expression::intrinsify(Gogo* gogo, return Runtime::make_call(code, loc, 3, a1, a2, a3); } } + else if (package == "internal/abi") + { + if (is_method) + return NULL; + + if ((name == "FuncPCABI0" || name == "FuncPCABIInternal") + && this->args_ != NULL + && this->args_->size() == 1) + { + // We expect to see a conversion from the expression to "any". + Expression* expr = this->args_->front(); + Type_conversion_expression* tce = expr->conversion_expression(); + if (tce != NULL) + expr = tce->expr(); + Func_expression* fe = expr->func_expression(); + Interface_field_reference_expression* interface_method = + expr->interface_field_reference_expression(); + if (fe != NULL) + { + Named_object* no = fe->named_object(); + Expression* ref = Expression::make_func_code_reference(no, loc); + Type* uintptr_type = Type::lookup_integer_type("uintptr"); + return Expression::make_cast(uintptr_type, ref, loc); + } + else if (interface_method != NULL) + return interface_method->get_function(); + else + { + expr = this->args_->front(); + go_assert(expr->type()->interface_type() != NULL + && expr->type()->interface_type()->is_empty()); + expr = Expression::make_interface_info(expr, + INTERFACE_INFO_OBJECT, + loc); + // Trust that this is a function type, which means that + // it is a direct iface type and we can use EXPR + // directly. The backend representation of this + // function is a pointer to a struct whose first field + // is the actual function to call. + Type* pvoid = Type::make_pointer_type(Type::make_void_type()); + Type* pfntype = Type::make_pointer_type(pvoid); + Expression* ref = make_unsafe_cast(pfntype, expr, loc); + return Expression::make_dereference(ref, NIL_CHECK_NOT_NEEDED, + loc); + } + } + } return NULL; } @@ -14757,14 +14967,34 @@ Interface_field_reference_expression::create_thunk(Gogo* gogo, gogo->add_statement(s); Block* b = gogo->finish_block(loc); gogo->add_block(b, loc); + + // This is called after lowering but before determine_types. gogo->lower_block(new_no, b); - gogo->flatten_block(new_no, b); + gogo->finish_function(loc); ins.first->second->push_back(std::make_pair(name, new_no)); return new_no; } +// Lookup a thunk to call method NAME on TYPE. + +Named_object* +Interface_field_reference_expression::lookup_thunk(Interface_type* type, + const std::string& name) +{ + Interface_method_thunks::const_iterator p = + Interface_field_reference_expression::interface_method_thunks.find(type); + if (p == Interface_field_reference_expression::interface_method_thunks.end()) + return NULL; + for (Method_thunks::const_iterator pm = p->second->begin(); + pm != p->second->end(); + ++pm) + if (pm->first == name) + return pm->second; + return NULL; +} + // Get the backend representation for a method value. Bexpression* @@ -14778,9 +15008,11 @@ Interface_field_reference_expression::do_get_backend(Translate_context* context) } Named_object* thunk = - Interface_field_reference_expression::create_thunk(context->gogo(), - type, this->name_); - if (thunk->is_erroneous()) + Interface_field_reference_expression::lookup_thunk(type, this->name_); + + // The thunk should have been created during the + // create_function_descriptors pass. + if (thunk == NULL || thunk->is_erroneous()) { go_assert(saw_errors()); return context->backend()->error_expression(); diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 9348354..92e8d8d 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -3405,6 +3405,10 @@ class Bound_method_expression : public Expression static Named_object* create_thunk(Gogo*, const Method* method, Named_object* function); + // Look up a thunk. + static Named_object* + lookup_thunk(Named_object* function); + protected: int do_traverse(Traverse*); @@ -3578,6 +3582,10 @@ class Interface_field_reference_expression : public Expression static Named_object* create_thunk(Gogo*, Interface_type* type, const std::string& name); + // Look up a thunk. + static Named_object* + lookup_thunk(Interface_type* type, const std::string& name); + // Return an expression for the pointer to the function to call. Expression* get_function(); diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 95b76bd..30d5c9f 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -141,6 +141,15 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size) this->add_named_type(error_type); } + // "any" is an alias for the empty interface type. + { + Type* empty = Type::make_empty_interface_type(loc); + Named_object* no = Named_object::make_type("any", NULL, empty, loc); + Named_type* nt = no->type_value(); + nt->set_is_alias(); + this->add_named_type(nt); + } + this->globals_->add_constant(Typed_identifier("true", Type::make_boolean_type(), loc), @@ -3430,6 +3439,11 @@ Create_function_descriptors::expression(Expression** pexpr) if (args->traverse(this) == TRAVERSE_EXIT) return TRAVERSE_EXIT; } + + // Traverse the subexpressions of the function, if any. + if (fn->traverse_subexpressions(this) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + return TRAVERSE_SKIP_COMPONENTS; } } @@ -6885,80 +6899,12 @@ Block::traverse(Traverse* traverse) | Traverse::traverse_expressions | Traverse::traverse_types)) != 0) { - const unsigned int e_or_t = (Traverse::traverse_expressions - | Traverse::traverse_types); - const unsigned int e_or_t_or_s = (e_or_t - | Traverse::traverse_statements); for (Bindings::const_definitions_iterator pb = this->bindings_->begin_definitions(); pb != this->bindings_->end_definitions(); ++pb) { - int t = TRAVERSE_CONTINUE; - switch ((*pb)->classification()) - { - case Named_object::NAMED_OBJECT_CONST: - if ((traverse_mask & Traverse::traverse_constants) != 0) - t = traverse->constant(*pb, false); - if (t == TRAVERSE_CONTINUE - && (traverse_mask & e_or_t) != 0) - { - Type* tc = (*pb)->const_value()->type(); - if (tc != NULL - && Type::traverse(tc, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - t = (*pb)->const_value()->traverse_expression(traverse); - } - break; - - case Named_object::NAMED_OBJECT_VAR: - case Named_object::NAMED_OBJECT_RESULT_VAR: - if ((traverse_mask & Traverse::traverse_variables) != 0) - t = traverse->variable(*pb); - if (t == TRAVERSE_CONTINUE - && (traverse_mask & e_or_t) != 0) - { - if ((*pb)->is_result_variable() - || (*pb)->var_value()->has_type()) - { - Type* tv = ((*pb)->is_variable() - ? (*pb)->var_value()->type() - : (*pb)->result_var_value()->type()); - if (tv != NULL - && Type::traverse(tv, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - if (t == TRAVERSE_CONTINUE - && (traverse_mask & e_or_t_or_s) != 0 - && (*pb)->is_variable()) - t = (*pb)->var_value()->traverse_expression(traverse, - traverse_mask); - break; - - case Named_object::NAMED_OBJECT_FUNC: - case Named_object::NAMED_OBJECT_FUNC_DECLARATION: - go_unreachable(); - - case Named_object::NAMED_OBJECT_TYPE: - if ((traverse_mask & e_or_t) != 0) - t = Type::traverse((*pb)->type_value(), traverse); - break; - - case Named_object::NAMED_OBJECT_TYPE_DECLARATION: - case Named_object::NAMED_OBJECT_UNKNOWN: - case Named_object::NAMED_OBJECT_ERRONEOUS: - break; - - case Named_object::NAMED_OBJECT_PACKAGE: - case Named_object::NAMED_OBJECT_SINK: - go_unreachable(); - - default: - go_unreachable(); - } - - if (t == TRAVERSE_EXIT) + if ((*pb)->traverse(traverse, false) == TRAVERSE_EXIT) return TRAVERSE_EXIT; } } @@ -8668,6 +8614,99 @@ Named_object::location() const } } +// Traverse a Named_object. + +int +Named_object::traverse(Traverse* traverse, bool is_global) +{ + const unsigned int traverse_mask = traverse->traverse_mask(); + const unsigned int e_or_t = (Traverse::traverse_expressions + | Traverse::traverse_types); + const unsigned int e_or_t_or_s = (e_or_t + | Traverse::traverse_statements); + + int t = TRAVERSE_CONTINUE; + switch (this->classification_) + { + case Named_object::NAMED_OBJECT_CONST: + if ((traverse_mask & Traverse::traverse_constants) != 0) + t = traverse->constant(this, is_global); + if (t == TRAVERSE_CONTINUE + && (traverse_mask & e_or_t) != 0) + { + Type* tc = this->const_value()->type(); + if (tc != NULL) + { + if (Type::traverse(tc, traverse) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + } + t = this->const_value()->traverse_expression(traverse); + } + break; + + case Named_object::NAMED_OBJECT_VAR: + case Named_object::NAMED_OBJECT_RESULT_VAR: + if ((traverse_mask & Traverse::traverse_variables) != 0) + t = traverse->variable(this); + if (t == TRAVERSE_CONTINUE + && (traverse_mask & e_or_t) != 0) + { + if (this->is_result_variable() || this->var_value()->has_type()) + { + Type* tv = (this->is_variable() + ? this->var_value()->type() + : this->result_var_value()->type()); + if (tv != NULL) + { + if (Type::traverse(tv, traverse) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + } + } + } + if (t == TRAVERSE_CONTINUE + && (traverse_mask & e_or_t_or_s) != 0 + && this->is_variable()) + t = this->var_value()->traverse_expression(traverse, + traverse_mask); + break; + + case Named_object::NAMED_OBJECT_FUNC: + if ((traverse_mask & Traverse::traverse_functions) != 0) + t = traverse->function(this); + if (t == TRAVERSE_CONTINUE + && (traverse_mask + & (Traverse::traverse_variables + | Traverse::traverse_constants + | Traverse::traverse_functions + | Traverse::traverse_blocks + | Traverse::traverse_statements + | Traverse::traverse_expressions + | Traverse::traverse_types)) != 0) + t = this->func_value()->traverse(traverse); + break; + + case Named_object::NAMED_OBJECT_TYPE: + if ((traverse_mask & e_or_t) != 0) + t = Type::traverse(this->type_value(), traverse); + break; + + case Named_object::NAMED_OBJECT_PACKAGE: + case Named_object::NAMED_OBJECT_FUNC_DECLARATION: + case Named_object::NAMED_OBJECT_TYPE_DECLARATION: + case Named_object::NAMED_OBJECT_UNKNOWN: + case Named_object::NAMED_OBJECT_ERRONEOUS: + break; + + case Named_object::NAMED_OBJECT_SINK: + go_unreachable(); + + default: + go_unreachable(); + } + + return t; +} + // Export a named object. void @@ -8830,10 +8869,13 @@ Named_object::get_backend(Gogo* gogo, std::vector<Bexpression*>& const_decls, { named_type-> type_descriptor_pointer(gogo, Linemap::predeclared_location()); - named_type->gc_symbol_pointer(gogo); Type* pn = Type::make_pointer_type(named_type); pn->type_descriptor_pointer(gogo, Linemap::predeclared_location()); - pn->gc_symbol_pointer(gogo); + if (named_type->in_heap()) + { + named_type->gc_symbol_pointer(gogo); + pn->gc_symbol_pointer(gogo); + } } } break; @@ -9193,90 +9235,10 @@ Bindings::traverse(Traverse* traverse, bool is_global) // new global objects. const unsigned int e_or_t = (Traverse::traverse_expressions | Traverse::traverse_types); - const unsigned int e_or_t_or_s = (e_or_t - | Traverse::traverse_statements); for (size_t i = 0; i < this->named_objects_.size(); ++i) { Named_object* p = this->named_objects_[i]; - int t = TRAVERSE_CONTINUE; - switch (p->classification()) - { - case Named_object::NAMED_OBJECT_CONST: - if ((traverse_mask & Traverse::traverse_constants) != 0) - t = traverse->constant(p, is_global); - if (t == TRAVERSE_CONTINUE - && (traverse_mask & e_or_t) != 0) - { - Type* tc = p->const_value()->type(); - if (tc != NULL - && Type::traverse(tc, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - t = p->const_value()->traverse_expression(traverse); - } - break; - - case Named_object::NAMED_OBJECT_VAR: - case Named_object::NAMED_OBJECT_RESULT_VAR: - if ((traverse_mask & Traverse::traverse_variables) != 0) - t = traverse->variable(p); - if (t == TRAVERSE_CONTINUE - && (traverse_mask & e_or_t) != 0) - { - if (p->is_result_variable() - || p->var_value()->has_type()) - { - Type* tv = (p->is_variable() - ? p->var_value()->type() - : p->result_var_value()->type()); - if (tv != NULL - && Type::traverse(tv, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - if (t == TRAVERSE_CONTINUE - && (traverse_mask & e_or_t_or_s) != 0 - && p->is_variable()) - t = p->var_value()->traverse_expression(traverse, traverse_mask); - break; - - case Named_object::NAMED_OBJECT_FUNC: - if ((traverse_mask & Traverse::traverse_functions) != 0) - t = traverse->function(p); - - if (t == TRAVERSE_CONTINUE - && (traverse_mask - & (Traverse::traverse_variables - | Traverse::traverse_constants - | Traverse::traverse_functions - | Traverse::traverse_blocks - | Traverse::traverse_statements - | Traverse::traverse_expressions - | Traverse::traverse_types)) != 0) - t = p->func_value()->traverse(traverse); - break; - - case Named_object::NAMED_OBJECT_PACKAGE: - // These are traversed in Gogo::traverse. - go_assert(is_global); - break; - - case Named_object::NAMED_OBJECT_TYPE: - if ((traverse_mask & e_or_t) != 0) - t = Type::traverse(p->type_value(), traverse); - break; - - case Named_object::NAMED_OBJECT_TYPE_DECLARATION: - case Named_object::NAMED_OBJECT_FUNC_DECLARATION: - case Named_object::NAMED_OBJECT_UNKNOWN: - case Named_object::NAMED_OBJECT_ERRONEOUS: - break; - - case Named_object::NAMED_OBJECT_SINK: - default: - go_unreachable(); - } - - if (t == TRAVERSE_EXIT) + if (p->traverse(traverse, is_global) == TRAVERSE_EXIT) return TRAVERSE_EXIT; } diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index 9ffd120..2ee0fda 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -3047,6 +3047,10 @@ class Named_object Location location() const; + // Traverse a Named_object. + int + traverse(Traverse*, bool is_global); + // Convert a variable to the backend representation. Bvariable* get_backend_variable(Gogo*, Named_object* function); diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def index 87a2708..b7dd445 100644 --- a/gcc/go/gofrontend/runtime.def +++ b/gcc/go/gofrontend/runtime.def @@ -478,6 +478,10 @@ DEF_GO_RUNTIME(ATOMIC_ADD_FETCH_4, "__atomic_add_fetch_4", DEF_GO_RUNTIME(ATOMIC_ADD_FETCH_8, "__atomic_add_fetch_8", P3(POINTER, UINT64, INT32), R1(UINT64)) +DEF_GO_RUNTIME(ATOMIC_LOAD_1, "__atomic_load_1", P2(POINTER, INT32), + R1(UINT8)) +DEF_GO_RUNTIME(ATOMIC_STORE_1, "__atomic_store_1", P3(POINTER, UINT8, INT32), + R0()) DEF_GO_RUNTIME(ATOMIC_AND_FETCH_1, "__atomic_and_fetch_1", P3(POINTER, UINT8, INT32), R1(UINT8)) diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 0f66661..ee34676 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -791,8 +791,7 @@ Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason) // The types are convertible if they have identical underlying // types, ignoring struct field tags. - if ((lhs->named_type() != NULL || rhs->named_type() != NULL) - && Type::are_identical(lhs->base(), rhs->base(), 0, reason)) + if (Type::are_identical(lhs->base(), rhs->base(), 0, reason)) return true; // The types are convertible if they are both unnamed pointer types @@ -2514,13 +2513,18 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind, Expression_list* vals = new Expression_list(); vals->reserve(12); - if (!this->has_pointer()) + bool has_pointer; + if (name != NULL) + has_pointer = name->has_pointer(); + else + has_pointer = this->has_pointer(); + if (!has_pointer) runtime_type_kind |= RUNTIME_TYPE_KIND_NO_POINTERS; if (this->is_direct_iface_type()) runtime_type_kind |= RUNTIME_TYPE_KIND_DIRECT_IFACE; int64_t ptrsize; int64_t ptrdata; - if (this->needs_gcprog(gogo, &ptrsize, &ptrdata)) + if (has_pointer && this->needs_gcprog(gogo, &ptrsize, &ptrdata)) runtime_type_kind |= RUNTIME_TYPE_KIND_GC_PROG; Struct_field_list::const_iterator p = fields->begin(); @@ -2531,7 +2535,10 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind, ++p; go_assert(p->is_field_name("ptrdata")); type_info = Expression::TYPE_INFO_DESCRIPTOR_PTRDATA; - vals->push_back(Expression::make_type_info(this, type_info)); + if (has_pointer) + vals->push_back(Expression::make_type_info(this, type_info)); + else + vals->push_back(Expression::make_integer_ul(0, p->type(), bloc)); ++p; go_assert(p->is_field_name("hash")); @@ -2577,7 +2584,12 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind, ++p; go_assert(p->is_field_name("gcdata")); - vals->push_back(Expression::make_gc_symbol(this)); + if (has_pointer) + vals->push_back(Expression::make_gc_symbol(this)); + else + vals->push_back(Expression::make_cast(p->type(), + Expression::make_nil(bloc), + bloc)); ++p; go_assert(p->is_field_name("string")); @@ -6454,9 +6466,18 @@ get_backend_struct_fields(Gogo* gogo, Struct_type* type, bool use_placeholder, ? p->type()->get_backend_placeholder(gogo) : p->type()->get_backend(gogo)); (*bfields)[i].location = p->location(); - lastsize = gogo->backend()->type_size((*bfields)[i].btype); - if (lastsize != 0) - saw_nonzero = true; + int64_t size = gogo->backend()->type_size((*bfields)[i].btype); + if (size != 0) + saw_nonzero = true; + + if (size > 0 || !Gogo::is_sink_name(p->field_name())) + lastsize = size; + else + { + // There is an unreferenceable field of zero size. This + // doesn't affect whether we may need zero padding, so leave + // lastsize unchanged. + } } go_assert(i == fields->size()); if (saw_nonzero && lastsize == 0 && !type->is_results_struct()) @@ -10886,6 +10907,10 @@ Named_type::do_verify() bool Named_type::do_has_pointer() const { + // A type that is not in the heap has no pointers that we care about. + if (!this->in_heap_) + return false; + if (this->seen_) return false; this->seen_ = true; diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index a33453a..c55345a 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -2300,9 +2300,12 @@ class Pointer_type : public Type do_verify() { return this->to_type_->verify(); } + // If this is a pointer to a type that can't be in the heap, then + // the garbage collector does not have to look at this, so pretend + // that this is not a pointer at all. bool do_has_pointer() const - { return true; } + { return this->to_type_->in_heap(); } bool do_compare_is_identity(Gogo*) diff --git a/gcc/go/gospec.c b/gcc/go/gospec.cc index cf8d0f2..ba7ba4e 100644 --- a/gcc/go/gospec.c +++ b/gcc/go/gospec.cc @@ -1,5 +1,5 @@ -/* gospec.c -- Specific flags and argument handling of the gcc Go front end. - Copyright (C) 2009-2021 Free Software Foundation, Inc. +/* gospec.cc -- Specific flags and argument handling of the gcc Go front end. + Copyright (C) 2009-2022 Free Software Foundation, Inc. This file is part of GCC. @@ -29,10 +29,12 @@ along with GCC; see the file COPYING3. If not see #define MATHLIB (1<<2) /* This bit is set if they did `-lpthread'. */ #define THREADLIB (1<<3) +/* This bit is set if they did `-lrt'. */ +#define RTLIB (1<<4) /* This bit is set if they did `-lc'. */ -#define WITHLIBC (1<<4) +#define WITHLIBC (1<<5) /* Skip this option. */ -#define SKIPOPT (1<<5) +#define SKIPOPT (1<<6) #ifndef MATH_LIBRARY #define MATH_LIBRARY "m" @@ -44,6 +46,8 @@ along with GCC; see the file COPYING3. If not see #define THREAD_LIBRARY "pthread" #define THREAD_LIBRARY_PROFILE THREAD_LIBRARY +#define RT_LIBRARY "rt" + #define LIBGO "go" #define LIBGO_PROFILE LIBGO #define LIBGOBEGIN "gobegin" @@ -74,6 +78,9 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options, /* "-lpthread" if it appears on the command line. */ const struct cl_decoded_option *saw_thread = 0; + /* "-lrt" if it appears on the command line. */ + const struct cl_decoded_option *saw_rt = 0; + /* "-lc" if it appears on the command line. */ const struct cl_decoded_option *saw_libc = 0; @@ -84,6 +91,9 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options, /* Whether we need the thread library. */ int need_thread = 0; + /* Whether we need the rt library. */ + int need_rt = 0; + /* By default, we throw on the math library if we have one. */ int need_math = (MATH_LIBRARY[0] != '\0'); @@ -156,6 +166,8 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options, } else if (strcmp (arg, THREAD_LIBRARY) == 0) args[i] |= THREADLIB; + else if (strcmp (arg, RT_LIBRARY) == 0) + args[i] |= RTLIB; else if (strcmp (arg, "c") == 0) args[i] |= WITHLIBC; else @@ -260,7 +272,7 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options, #endif /* Make sure to have room for the trailing NULL argument. */ - num_args = argc + need_math + shared_libgcc + (library > 0) * 5 + 10; + num_args = argc + need_math + shared_libgcc + (library > 0) * 6 + 10; new_decoded_options = XNEWVEC (struct cl_decoded_option, num_args); i = 0; @@ -314,6 +326,12 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options, saw_thread = &decoded_options[i]; } + if (!saw_rt && (args[i] & RTLIB) && library > 0) + { + --j; + saw_rt = &decoded_options[i]; + } + if (!saw_libc && (args[i] & WITHLIBC) && library > 0) { --j; @@ -395,9 +413,23 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options, #endif /* When linking libgo statically we also need to link with the - pthread library. */ + pthread and (on GNU/Linux) the rt library. */ if (library > 1 || static_link) - need_thread = 1; + { + need_thread = 1; + if (strstr (DEFAULT_TARGET_MACHINE, "linux") != NULL) + need_rt = 1; + } + } + + if (saw_rt) + new_decoded_options[j++] = *saw_rt; + else if (library > 0 && need_rt) + { + generate_option (OPT_l, RT_LIBRARY, 1, CL_DRIVER, + &new_decoded_options[j]); + added_libraries++; + j++; } if (saw_thread) diff --git a/gcc/go/lang-specs.h b/gcc/go/lang-specs.h index 09df4aa..0c6005a 100644 --- a/gcc/go/lang-specs.h +++ b/gcc/go/lang-specs.h @@ -1,5 +1,5 @@ /* lang-specs.h -- gcc driver specs for Go frontend. - Copyright (C) 2009-2021 Free Software Foundation, Inc. + Copyright (C) 2009-2022 Free Software Foundation, Inc. This file is part of GCC. @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -/* This is the contribution to the `default_compilers' array in gcc.c +/* This is the contribution to the `default_compilers' array in gcc.cc for the Go language. */ {".go", "@go", 0, 1, 0}, diff --git a/gcc/go/lang.opt b/gcc/go/lang.opt index c870acf..e487319 100644 --- a/gcc/go/lang.opt +++ b/gcc/go/lang.opt @@ -1,6 +1,6 @@ ; lang.opt -- Options for the gcc Go front end. -; Copyright (C) 2009-2021 Free Software Foundation, Inc. +; Copyright (C) 2009-2022 Free Software Foundation, Inc. ; ; This file is part of GCC. ; |