From eb49f7de9341cb464327234c3a673ce3ef642e01 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 12 Apr 2021 14:15:16 -0700 Subject: libgo: update to Go1.16.3 release Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/309490 --- gcc/go/gofrontend/MERGE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index a3eef23..efb7a77 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -4bdff733a0c2a9ddc3eff104b1be03df058a79c4 +9782e85bef1c16c72a4980856d921cea104b129c The first line of this file holds the git revision number of the last merge done from the gofrontend repository. -- cgit v1.1 From 6ba3079dce89d9b63bf5dbd5e320ea2bf96f196b Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Wed, 17 Mar 2021 16:36:44 +0100 Subject: Come up with startswith function. gcc/ada/ChangeLog: * gcc-interface/utils.c (def_builtin_1): Use startswith function instead of strncmp. gcc/analyzer/ChangeLog: * sm-file.cc (is_file_using_fn_p): Use startswith function instead of strncmp. gcc/ChangeLog: * builtins.c (is_builtin_name): Use startswith function instead of strncmp. * collect2.c (main): Likewise. (has_lto_section): Likewise. (scan_libraries): Likewise. * coverage.c (coverage_checksum_string): Likewise. (coverage_init): Likewise. * dwarf2out.c (is_cxx): Likewise. (gen_compile_unit_die): Likewise. * gcc-ar.c (main): Likewise. * gcc.c (init_spec): Likewise. (read_specs): Likewise. (execute): Likewise. (check_live_switch): Likewise. * genattrtab.c (write_attr_case): Likewise. (IS_ATTR_GROUP): Likewise. * gencfn-macros.c (main): Likewise. * gengtype.c (type_for_name): Likewise. (gen_rtx_next): Likewise. (get_file_langdir): Likewise. (write_local): Likewise. * genmatch.c (get_operator): Likewise. (get_operand_type): Likewise. (expr::gen_transform): Likewise. * genoutput.c (validate_optab_operands): Likewise. * incpath.c (add_sysroot_to_chain): Likewise. * langhooks.c (lang_GNU_C): Likewise. (lang_GNU_CXX): Likewise. (lang_GNU_Fortran): Likewise. (lang_GNU_OBJC): Likewise. * lto-wrapper.c (run_gcc): Likewise. * omp-general.c (omp_max_simt_vf): Likewise. * omp-low.c (omp_runtime_api_call): Likewise. * opts-common.c (parse_options_from_collect_gcc_options): Likewise. * read-rtl-function.c (function_reader::read_rtx_operand_r): Likewise. * real.c (real_from_string): Likewise. * selftest.c (assert_str_startswith): Likewise. * timevar.c (timer::validate_phases): Likewise. * tree.c (get_file_function_name): Likewise. * ubsan.c (ubsan_use_new_style_p): Likewise. * varasm.c (default_function_rodata_section): Likewise. (incorporeal_function_p): Likewise. (default_section_type_flags): Likewise. * system.h (startswith): Define startswith. gcc/c-family/ChangeLog: * c-ada-spec.c (print_destructor): Use startswith function instead of strncmp. (dump_ada_declaration): Likewise. * c-common.c (disable_builtin_function): Likewise. (def_builtin_1): Likewise. * c-format.c (check_tokens): Likewise. (check_plain): Likewise. (convert_format_name_to_system_name): Likewise. gcc/c/ChangeLog: * c-aux-info.c (affix_data_type): Use startswith function instead of strncmp. * c-typeck.c (build_function_call_vec): Likewise. * gimple-parser.c (c_parser_gimple_parse_bb_spec): Likewise. gcc/cp/ChangeLog: * decl.c (duplicate_decls): Use startswith function instead of strncmp. (cxx_builtin_function): Likewise. (omp_declare_variant_finalize_one): Likewise. (grokfndecl): Likewise. * error.c (dump_decl_name): Likewise. * mangle.c (find_decomp_unqualified_name): Likewise. (write_guarded_var_name): Likewise. (decl_tls_wrapper_p): Likewise. * parser.c (cp_parser_simple_type_specifier): Likewise. (cp_parser_tx_qualifier_opt): Likewise. * pt.c (template_parm_object_p): Likewise. (dguide_name_p): Likewise. gcc/d/ChangeLog: * d-builtins.cc (do_build_builtin_fn): Use startswith function instead of strncmp. * dmd/dinterpret.c (evaluateIfBuiltin): Likewise. * dmd/dmangle.c: Likewise. * dmd/hdrgen.c: Likewise. * dmd/identifier.c (Identifier::toHChars2): Likewise. gcc/fortran/ChangeLog: * decl.c (variable_decl): Use startswith function instead of strncmp. (gfc_match_end): Likewise. * gfortran.h (gfc_str_startswith): Likewise. * module.c (load_omp_udrs): Likewise. (read_module): Likewise. * options.c (gfc_handle_runtime_check_option): Likewise. * primary.c (match_arg_list_function): Likewise. * trans-decl.c (gfc_get_symbol_decl): Likewise. * trans-expr.c (gfc_conv_procedure_call): Likewise. * trans-intrinsic.c (gfc_conv_ieee_arithmetic_function): Likewise. gcc/go/ChangeLog: * gofrontend/runtime.cc (Runtime::name_to_code): Use startswith function instead of strncmp. gcc/objc/ChangeLog: * objc-act.c (objc_string_ref_type_p): Use startswith function instead of strncmp. * objc-encoding.c (encode_type): Likewise. * objc-next-runtime-abi-02.c (has_load_impl): Likewise. --- gcc/go/gofrontend/runtime.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/runtime.cc b/gcc/go/gofrontend/runtime.cc index 3cc5ded..514c045 100644 --- a/gcc/go/gofrontend/runtime.cc +++ b/gcc/go/gofrontend/runtime.cc @@ -463,7 +463,7 @@ Runtime::name_to_code(const std::string& name) // The names in the table have "runtime." prefix. We may be // called with a name without the prefix. Try matching // without the prefix as well. - if (strncmp(runtime_function_name, "runtime.", 8) == 0 + if (startswith(runtime_function_name, "runtime.") && strcmp(runtime_function_name + 8, name.c_str()) == 0) code = static_cast(i); } -- cgit v1.1 From aa891c56f25baac94db004e309d1b6e40b770a95 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 11 May 2021 00:16:36 +0000 Subject: Daily bump. --- gcc/go/ChangeLog | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'gcc/go') diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 85bd343..5c5d332 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,8 @@ +2021-05-10 Martin Liska + + * gofrontend/runtime.cc (Runtime::name_to_code): Use startswith + function instead of strncmp. + 2021-01-28 Ian Lance Taylor * gospec.c (lang_specific_driver): Add -g if no debugging options -- cgit v1.1 From c922c6539e63a775ee29751320d678f0a0a33d07 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 18 May 2021 18:09:27 -0700 Subject: libgo: update configure to current sources Change-Id: I12766baf02bfdf2233f1c5bde1a270f06b020aa7 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/321076 Trust: Ian Lance Taylor Reviewed-by: Cherry Mui Reviewed-by: Than McIntosh --- gcc/go/gofrontend/MERGE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index efb7a77..373b58c 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -9782e85bef1c16c72a4980856d921cea104b129c +38228e7a91d37588463307ec60420c8f17f1aee4 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. -- cgit v1.1 From 2ebddf2ec55a77d6bd5aaad0f753a173054787a7 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 18 May 2021 20:07:29 -0700 Subject: gofrontend: revert startswith change This file is copied from a different repo and should not be changed directly in the GCC repo. --- gcc/go/gofrontend/runtime.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/runtime.cc b/gcc/go/gofrontend/runtime.cc index 514c045..3cc5ded 100644 --- a/gcc/go/gofrontend/runtime.cc +++ b/gcc/go/gofrontend/runtime.cc @@ -463,7 +463,7 @@ Runtime::name_to_code(const std::string& name) // The names in the table have "runtime." prefix. We may be // called with a name without the prefix. Try matching // without the prefix as well. - if (startswith(runtime_function_name, "runtime.") + if (strncmp(runtime_function_name, "runtime.", 8) == 0 && strcmp(runtime_function_name + 8, name.c_str()) == 0) code = static_cast(i); } -- cgit v1.1 From c6c62ba41d905db5c10f573d0e0faa84656f1731 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 18 May 2021 20:08:22 -0700 Subject: gcc/go/ChangeLog: remove entry for reverted change --- gcc/go/ChangeLog | 5 ----- 1 file changed, 5 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 5c5d332..85bd343 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,8 +1,3 @@ -2021-05-10 Martin Liska - - * gofrontend/runtime.cc (Runtime::name_to_code): Use startswith - function instead of strncmp. - 2021-01-28 Ian Lance Taylor * gospec.c (lang_specific_driver): Add -g if no debugging options -- cgit v1.1 From 358832c46a378e5a0b8a2fa3c2739125e3e680c7 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sat, 22 May 2021 19:19:13 -0700 Subject: compiler: mark global variables whose address is taken To implement this, change the backend to use flag bits for variables. Fixes https://gcc.gnu.org/PR100537 PR go/100537 * go-gcc.cc (class Gcc_backend): Update methods that create variables to take a flags parameter. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/322129 --- gcc/go/go-gcc.cc | 155 ++++++++++++++++++++++++++------------- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/backend.h | 145 +++++++++++++++++++----------------- gcc/go/gofrontend/expressions.cc | 63 +++++++++------- gcc/go/gofrontend/gogo.cc | 54 ++++++++------ gcc/go/gofrontend/statements.cc | 6 +- gcc/go/gofrontend/types.cc | 35 +++++---- 7 files changed, 276 insertions(+), 184 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index 5d9dbb5..41f309e 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -415,47 +415,46 @@ class Gcc_backend : public Backend global_variable(const std::string& var_name, const std::string& asm_name, Btype* btype, - bool is_external, - bool is_hidden, - bool in_unique_section, + unsigned int flags, Location location); void global_variable_set_init(Bvariable*, Bexpression*); Bvariable* - local_variable(Bfunction*, const std::string&, Btype*, Bvariable*, bool, - Location); + local_variable(Bfunction*, const std::string&, Btype*, Bvariable*, + unsigned int, Location); Bvariable* - parameter_variable(Bfunction*, const std::string&, Btype*, bool, + parameter_variable(Bfunction*, const std::string&, Btype*, unsigned int, Location); Bvariable* - static_chain_variable(Bfunction*, const std::string&, Btype*, Location); + static_chain_variable(Bfunction*, const std::string&, Btype*, unsigned int, + Location); Bvariable* - temporary_variable(Bfunction*, Bblock*, Btype*, Bexpression*, bool, + temporary_variable(Bfunction*, Bblock*, Btype*, Bexpression*, unsigned int, Location, Bstatement**); Bvariable* implicit_variable(const std::string&, const std::string&, Btype*, - bool, bool, bool, int64_t); + unsigned int, int64_t); void implicit_variable_set_init(Bvariable*, const std::string&, Btype*, - bool, bool, bool, Bexpression*); + unsigned int, Bexpression*); Bvariable* implicit_variable_reference(const std::string&, const std::string&, Btype*); Bvariable* immutable_struct(const std::string&, const std::string&, - bool, bool, Btype*, Location); + unsigned int, Btype*, Location); void - immutable_struct_set_init(Bvariable*, const std::string&, bool, bool, Btype*, - Location, Bexpression*); + immutable_struct_set_init(Bvariable*, const std::string&, unsigned int, + Btype*, Location, Bexpression*); Bvariable* immutable_struct_reference(const std::string&, const std::string&, @@ -2696,9 +2695,7 @@ Bvariable* Gcc_backend::global_variable(const std::string& var_name, const std::string& asm_name, Btype* btype, - bool is_external, - bool is_hidden, - bool in_unique_section, + unsigned int flags, Location location) { tree type_tree = btype->get_tree(); @@ -2707,30 +2704,49 @@ Gcc_backend::global_variable(const std::string& var_name, // The GNU linker does not like dynamic variables with zero size. tree orig_type_tree = type_tree; + bool is_external = (flags & variable_is_external) != 0; + bool is_hidden = (flags & variable_is_hidden) != 0; if ((is_external || !is_hidden) && int_size_in_bytes(type_tree) == 0) type_tree = this->non_zero_size_type(type_tree); tree decl = build_decl(location.gcc_location(), VAR_DECL, get_identifier_from_string(var_name), type_tree); - if (is_external) - DECL_EXTERNAL(decl) = 1; - else - TREE_STATIC(decl) = 1; - if (!is_hidden) + if ((flags & variable_is_external) != 0) { - TREE_PUBLIC(decl) = 1; - SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name)); + DECL_EXTERNAL(decl) = 1; + flags &=~ variable_is_external; } else + TREE_STATIC(decl) = 1; + + if ((flags & variable_is_hidden) == 0) + TREE_PUBLIC(decl) = 1; + else + flags &=~ variable_is_hidden; + + if ((flags & variable_address_is_taken) != 0) { - SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name)); + TREE_ADDRESSABLE(decl) = 1; + flags &=~ variable_address_is_taken; } + // We take the address in Bvariable::get_tree if orig_type_tree is + // different from type_tree. + if (orig_type_tree != type_tree) + TREE_ADDRESSABLE(decl) = 1; + + SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name)); + TREE_USED(decl) = 1; - if (in_unique_section) - resolve_unique_section (decl, 0, 1); + if ((flags & variable_in_unique_section) != 0) + { + resolve_unique_section (decl, 0, 1); + flags &=~ variable_in_unique_section; + } + + gcc_assert(flags == 0); go_preserve_from_gc(decl); @@ -2768,7 +2784,7 @@ Gcc_backend::global_variable_set_init(Bvariable* var, Bexpression* expr) Bvariable* Gcc_backend::local_variable(Bfunction* function, const std::string& name, Btype* btype, Bvariable* decl_var, - bool is_address_taken, Location location) + unsigned int flags, Location location) { tree type_tree = btype->get_tree(); if (type_tree == error_mark_node) @@ -2778,13 +2794,17 @@ Gcc_backend::local_variable(Bfunction* function, const std::string& name, type_tree); DECL_CONTEXT(decl) = function->get_tree(); TREE_USED(decl) = 1; - if (is_address_taken) - TREE_ADDRESSABLE(decl) = 1; + if ((flags & variable_address_is_taken) != 0) + { + TREE_ADDRESSABLE(decl) = 1; + flags &=~ variable_address_is_taken; + } if (decl_var != NULL) { DECL_HAS_VALUE_EXPR_P(decl) = 1; SET_DECL_VALUE_EXPR(decl, decl_var->get_decl()); } + go_assert(flags == 0); go_preserve_from_gc(decl); return new Bvariable(decl); } @@ -2793,7 +2813,7 @@ Gcc_backend::local_variable(Bfunction* function, const std::string& name, Bvariable* Gcc_backend::parameter_variable(Bfunction* function, const std::string& name, - Btype* btype, bool is_address_taken, + Btype* btype, unsigned int flags, Location location) { tree type_tree = btype->get_tree(); @@ -2805,8 +2825,12 @@ Gcc_backend::parameter_variable(Bfunction* function, const std::string& name, DECL_CONTEXT(decl) = function->get_tree(); DECL_ARG_TYPE(decl) = type_tree; TREE_USED(decl) = 1; - if (is_address_taken) - TREE_ADDRESSABLE(decl) = 1; + if ((flags & variable_address_is_taken) != 0) + { + TREE_ADDRESSABLE(decl) = 1; + flags &=~ variable_address_is_taken; + } + go_assert(flags == 0); go_preserve_from_gc(decl); return new Bvariable(decl); } @@ -2815,7 +2839,8 @@ Gcc_backend::parameter_variable(Bfunction* function, const std::string& name, Bvariable* Gcc_backend::static_chain_variable(Bfunction* function, const std::string& name, - Btype* btype, Location location) + Btype* btype, unsigned int flags, + Location location) { tree type_tree = btype->get_tree(); if (type_tree == error_mark_node) @@ -2840,6 +2865,7 @@ Gcc_backend::static_chain_variable(Bfunction* function, const std::string& name, gcc_assert(f->static_chain_decl == NULL); f->static_chain_decl = decl; DECL_STATIC_CHAIN(fndecl) = 1; + go_assert(flags == 0); go_preserve_from_gc(decl); return new Bvariable(decl); @@ -2850,7 +2876,7 @@ Gcc_backend::static_chain_variable(Bfunction* function, const std::string& name, Bvariable* Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock, Btype* btype, Bexpression* binit, - bool is_address_taken, + unsigned int flags, Location location, Bstatement** pstatement) { @@ -2904,8 +2930,13 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock, && TREE_TYPE(init_tree) != void_type_node) DECL_INITIAL(var) = this->convert_tree(type_tree, init_tree, location); - if (is_address_taken) - TREE_ADDRESSABLE(var) = 1; + if ((flags & variable_address_is_taken) != 0) + { + TREE_ADDRESSABLE(var) = 1; + flags &=~ variable_address_is_taken; + } + + gcc_assert(flags == 0); *pstatement = this->make_statement(build1_loc(location.gcc_location(), DECL_EXPR, @@ -2929,8 +2960,8 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock, Bvariable* Gcc_backend::implicit_variable(const std::string& name, const std::string& asm_name, - Btype* type, bool is_hidden, bool is_constant, - bool is_common, int64_t alignment) + Btype* type, unsigned int flags, + int64_t alignment) { tree type_tree = type->get_tree(); if (type_tree == error_mark_node) @@ -2939,11 +2970,14 @@ Gcc_backend::implicit_variable(const std::string& name, tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, get_identifier_from_string(name), type_tree); DECL_EXTERNAL(decl) = 0; - TREE_PUBLIC(decl) = !is_hidden; + if ((flags & variable_is_hidden) != 0) + flags &=~ variable_is_hidden; + else + TREE_PUBLIC(decl) = 1; TREE_STATIC(decl) = 1; TREE_USED(decl) = 1; DECL_ARTIFICIAL(decl) = 1; - if (is_common) + if ((flags & variable_is_common) != 0) { DECL_COMMON(decl) = 1; @@ -2960,11 +2994,19 @@ Gcc_backend::implicit_variable(const std::string& name, // mark this symbol as weak here. We undo that below in // immutable_struct_set_init before calling mark_decl_one_only. DECL_WEAK(decl) = 1; + + flags &=~ variable_is_common; } - if (is_constant) + if ((flags & variable_is_constant) != 0) { TREE_READONLY(decl) = 1; TREE_CONSTANT(decl) = 1; + flags &=~ variable_is_constant; + } + if ((flags & variable_address_is_taken) != 0) + { + TREE_ADDRESSABLE(decl) = 1; + flags &=~ variable_address_is_taken; } if (alignment != 0) { @@ -2973,6 +3015,7 @@ Gcc_backend::implicit_variable(const std::string& name, } if (! asm_name.empty()) SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name)); + gcc_assert(flags == 0); go_preserve_from_gc(decl); return new Bvariable(decl); @@ -2983,7 +3026,7 @@ Gcc_backend::implicit_variable(const std::string& name, void Gcc_backend::implicit_variable_set_init(Bvariable* var, const std::string&, - Btype*, bool, bool, bool is_common, + Btype*, unsigned int flags, Bexpression* init) { tree decl = var->get_decl(); @@ -2999,7 +3042,7 @@ Gcc_backend::implicit_variable_set_init(Bvariable* var, const std::string&, // Now that DECL_INITIAL is set, we can't call make_decl_one_only. // See the comment where DECL_WEAK is set in implicit_variable. - if (is_common) + if ((flags & variable_is_common) != 0) { DECL_WEAK(decl) = 0; make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl)); @@ -3038,8 +3081,8 @@ Gcc_backend::implicit_variable_reference(const std::string& name, Bvariable* Gcc_backend::immutable_struct(const std::string& name, const std::string& asm_name, - bool is_hidden, - bool is_common, Btype* btype, Location location) + unsigned int flags, Btype* btype, + Location location) { tree type_tree = btype->get_tree(); if (type_tree == error_mark_node) @@ -3053,10 +3096,17 @@ Gcc_backend::immutable_struct(const std::string& name, TREE_READONLY(decl) = 1; TREE_CONSTANT(decl) = 1; DECL_ARTIFICIAL(decl) = 1; - if (!is_hidden) + if ((flags & variable_is_hidden) != 0) + flags &=~ variable_is_hidden; + else TREE_PUBLIC(decl) = 1; if (! asm_name.empty()) SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name)); + if ((flags & variable_address_is_taken) != 0) + { + TREE_ADDRESSABLE(decl) = 1; + flags &=~ variable_address_is_taken; + } // When the initializer for one immutable_struct refers to another, // it needs to know the visibility of the referenced struct so that @@ -3070,8 +3120,13 @@ Gcc_backend::immutable_struct(const std::string& name, // the right value if some other initializer refers to this one, we // mark this symbol as weak here. We undo that below in // immutable_struct_set_init before calling mark_decl_one_only. - if (is_common) - DECL_WEAK(decl) = 1; + if ((flags & variable_is_common) != 0) + { + DECL_WEAK(decl) = 1; + flags &=~ variable_is_common; + } + + gcc_assert(flags == 0); // We don't call rest_of_decl_compilation until we have the // initializer. @@ -3085,7 +3140,7 @@ Gcc_backend::immutable_struct(const std::string& name, void Gcc_backend::immutable_struct_set_init(Bvariable* var, const std::string&, - bool, bool is_common, Btype*, Location, + unsigned int flags, Btype*, Location, Bexpression* initializer) { tree decl = var->get_decl(); @@ -3097,7 +3152,7 @@ Gcc_backend::immutable_struct_set_init(Bvariable* var, const std::string&, // Now that DECL_INITIAL is set, we can't call make_decl_one_only. // See the comment where DECL_WEAK is set in immutable_struct. - if (is_common) + if ((flags & variable_is_common) != 0) { DECL_WEAK(decl) = 0; make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl)); diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 373b58c..1f38c911 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -38228e7a91d37588463307ec60420c8f17f1aee4 +5a801b15699cced5203af5c7339b375cd55ecbac 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/backend.h b/gcc/go/gofrontend/backend.h index c5b5d8f..5b6ffea 100644 --- a/gcc/go/gofrontend/backend.h +++ b/gcc/go/gofrontend/backend.h @@ -481,24 +481,51 @@ class Backend virtual Bvariable* error_variable() = 0; + // Bit flags to pass to the various methods that return Bvariable*. + // Not all flags are meaningful for all methods. + + // Set if the variable's address is taken. For a local variable + // this implies that the address does not escape the function, as + // otherwise the variable would be on the heap. + static const unsigned int variable_address_is_taken = 1 << 0; + + // Set if the variable is defined in some other package. Only + // meaningful for the global_variable method. At most one of + // is_external, is_hidden, and is_common may be set. + static const unsigned int variable_is_external = 1 << 1; + + // Set if the variable is not exported, and as such is only defined + // in the current package. Only meaningful for global_variable, + // implicit_variable, and immutable_struct. At most one of + // is_external, is_hidden, and is_common may be set. + static const unsigned variable_is_hidden = 1 << 2; + + // Set if the variable should be treated as a common variable: + // multiple definitions with different sizes permitted in different + // object files, all merged into the largest definition at link + // time. Only meaningful for implicit_variable and immutable_struct. + // At most one of is_external, is_hidden, and is_common may be set. + static const unsigned int variable_is_common = 1 << 3; + + // Set if the variable should be put into a unique section if + // possible; this is intended to permit the linker to garbage + // collect the value if it is not referenced. Only meaningful for + // global_variable. + static const unsigned int variable_in_unique_section = 1 << 4; + + // Set if the variable should be treated as immutable. Only + // meaningful for implicit_variable. For example, this is set for + // slice initializers if the values must be copied to the heap. + static const unsigned int variable_is_constant = 1 << 5; + // Create a global variable. NAME is the package-qualified name of // the variable. ASM_NAME is the encoded identifier for the // variable, incorporating the package, and made safe for the - // assembler. BTYPE is the type of the variable. IS_EXTERNAL is - // true if the variable is defined in some other package. IS_HIDDEN - // is true if the variable is not exported (name begins with a lower - // case letter). IN_UNIQUE_SECTION is true if the variable should - // be put into a unique section if possible; this is intended to - // permit the linker to garbage collect the variable if it is not - // referenced. LOCATION is where the variable was defined. + // assembler. BTYPE is the type of the variable. FLAGS is the bit + // flags defined above. LOCATION is where the variable was defined. virtual Bvariable* - global_variable(const std::string& name, - const std::string& asm_name, - Btype* btype, - bool is_external, - bool is_hidden, - bool in_unique_section, - Location location) = 0; + global_variable(const std::string& name, const std::string& asm_name, + Btype* btype, unsigned int flags, Location location) = 0; // A global variable will 1) be initialized to zero, or 2) be // initialized to a constant value, or 3) be initialized in the init @@ -516,42 +543,40 @@ class Backend // null, gives the location at which the value of this variable may // be found, typically used to create an inner-scope reference to an // outer-scope variable, to extend the lifetime of the variable beyond - // the inner scope. IS_ADDRESS_TAKEN is true if the address of this - // variable is taken (this implies that the address does not escape - // the function, as otherwise the variable would be on the heap). + // the inner scope. FLAGS is the bit flags defined above. // LOCATION is where the variable is defined. For each local variable // the frontend will call init_statement to set the initial value. virtual Bvariable* local_variable(Bfunction* function, const std::string& name, Btype* type, - Bvariable* decl_var, bool is_address_taken, Location location) = 0; + Bvariable* decl_var, unsigned int flags, + Location location) = 0; // Create a function parameter. This is an incoming parameter, not // a result parameter (result parameters are treated as local // variables). The arguments are as for local_variable. virtual Bvariable* parameter_variable(Bfunction* function, const std::string& name, - Btype* type, bool is_address_taken, - Location location) = 0; + Btype* type, unsigned int flags, Location location) = 0; // Create a static chain parameter. This is the closure parameter. virtual Bvariable* static_chain_variable(Bfunction* function, const std::string& name, - Btype* type, Location location) = 0; + Btype* type, unsigned int flags, + Location location) = 0; // Create a temporary variable. A temporary variable has no name, // just a type. We pass in FUNCTION and BLOCK in case they are // needed. If INIT is not NULL, the variable should be initialized // to that value. Otherwise the initial value is irrelevant--the // backend does not have to explicitly initialize it to zero. - // ADDRESS_IS_TAKEN is true if the programs needs to take the - // address of this temporary variable. LOCATION is the location of + // FLAGS is the bit flags defined above. LOCATION is the location of // the statement or expression which requires creating the temporary // variable, and may not be very useful. This function should // return a variable which can be referenced later and should set // *PSTATEMENT to a statement which initializes the variable. virtual Bvariable* temporary_variable(Bfunction*, Bblock*, Btype*, Bexpression* init, - bool address_is_taken, Location location, + unsigned int flags, Location location, Bstatement** pstatement) = 0; // Create an implicit variable that is compiler-defined. This is @@ -566,46 +591,33 @@ class Backend // // TYPE is the type of the implicit variable. // - // IS_HIDDEN will be true if the descriptor should only be visible - // within the current object. - // - // IS_CONSTANT is true if the implicit variable should be treated like it is - // immutable. For slice initializers, if the values must be copied to the - // heap, the variable IS_CONSTANT. - // - // IS_COMMON is true if the implicit variable should - // be treated as a common variable (multiple definitions with - // different sizes permitted in different object files, all merged - // into the largest definition at link time); this will be true for - // the zero value. IS_HIDDEN and IS_COMMON will never both be true. + // FLAGS is the bit flags defined above. // // If ALIGNMENT is not zero, it is the desired alignment of the variable. virtual Bvariable* implicit_variable(const std::string& name, const std::string& asm_name, - Btype* type, bool is_hidden, bool is_constant, - bool is_common, int64_t alignment) = 0; + Btype* type, unsigned int flags, int64_t alignment) = 0; // Set the initial value of a variable created by implicit_variable. // This must be called even if there is no initializer, i.e., INIT is NULL. - // The NAME, TYPE, IS_HIDDEN, IS_CONSTANT, and IS_COMMON parameters are - // the same ones passed to implicit_variable. INIT will be a composite - // literal of type TYPE. It will not contain any function calls or anything - // else that can not be put into a read-only data section. - // It may contain the address of variables created by implicit_variable. + // The NAME, TYPE, and FLAGS parameters are the same ones passed to + // implicit_variable. INIT will be a composite literal of type + // TYPE. It will not contain any function calls or anything else + // that can not be put into a read-only data section. It may + // contain the address of variables created by implicit_variable. // - // If IS_COMMON is true, INIT will be NULL, and the + // If variable_is_common is set in FLAGS, INIT will be NULL, and the // variable should be initialized to all zeros. virtual void implicit_variable_set_init(Bvariable*, const std::string& name, Btype* type, - bool is_hidden, bool is_constant, bool is_common, - Bexpression* init) = 0; + unsigned int flags, Bexpression* init) = 0; // Create a reference to a named implicit variable defined in some // other package. This will be a variable created by a call to // implicit_variable with the same NAME, ASM_NAME and TYPE and with - // IS_COMMON passed as false. This corresponds to an extern global - // variable in C. + // variable_is_common not set in FLAGS. This corresponds to an + // extern global variable in C. virtual Bvariable* implicit_variable_reference(const std::string& name, const std::string& asm_name, @@ -622,15 +634,12 @@ class Backend // ASM_NAME is the encoded, assembler-friendly version of NAME, or // the empty string if no encoding is needed. // - // IS_HIDDEN will be true if the descriptor should only be visible - // within the current object. - // - // IS_COMMON is true if NAME may be defined by several packages, and - // the linker should merge all such definitions. If IS_COMMON is - // false, NAME should be defined in only one file. In general - // IS_COMMON will be true for the type descriptor of an unnamed type - // or a builtin type. IS_HIDDEN and IS_COMMON will never both be - // true. + // FLAGS is the bit flags defined above. The variable_is_common + // flag will be set if NAME may be defined by several packages, and + // the linker should merge all such definitions. If the + // variable_is_common flag is not set, NAME should be defined in + // only one file. In general variable_is_common will be set for the + // type descriptor of an unnamed type or a builtin type. // // TYPE will be a struct type; the type of the returned expression // must be a pointer to this struct type. @@ -640,28 +649,26 @@ class Backend // address. After calling this the frontend will call // immutable_struct_set_init. virtual Bvariable* - immutable_struct(const std::string& name, - const std::string& asm_name, - bool is_hidden, bool is_common, - Btype* type, Location) = 0; + immutable_struct(const std::string& name, const std::string& asm_name, + unsigned int flags, Btype* type, Location) = 0; // Set the initial value of a variable created by immutable_struct. - // The NAME, IS_HIDDEN, IS_COMMON, TYPE, and location parameters are - // the same ones passed to immutable_struct. INITIALIZER will be a - // composite literal of type TYPE. It will not contain any function - // calls or anything else that can not be put into a read-only data - // section. It may contain the address of variables created by + // The NAME, FLAGS, TYPE, and location parameters are the same ones + // passed to immutable_struct. INITIALIZER will be a composite + // literal of type TYPE. It will not contain any function calls or + // anything else that can not be put into a read-only data section. + // It may contain the address of variables created by // immutable_struct. virtual void immutable_struct_set_init(Bvariable*, const std::string& name, - bool is_hidden, bool is_common, Btype* type, + unsigned int flags, Btype* type, Location, Bexpression* initializer) = 0; // Create a reference to a named immutable initialized data // structure defined in some other package. This will be a // structure created by a call to immutable_struct with the same - // NAME, ASM_NAME and TYPE and with IS_COMMON passed as false. This - // corresponds to an extern const global variable in C. + // NAME, ASM_NAME and TYPE and with variable_is_common not set in + // flags. This corresponds to an extern const global variable in C. virtual Bvariable* immutable_struct_reference(const std::string& name, const std::string& asm_name, diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 5409d26..5d45e4b 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -1427,7 +1427,7 @@ Sink_expression::do_get_backend(Translate_context* context) Bstatement* decl; this->bvar_ = gogo->backend()->temporary_variable(fn_ctx, context->bblock(), bt, NULL, - false, loc, &decl); + 0, loc, &decl); Bexpression* var_ref = gogo->backend()->var_expression(this->bvar_, loc); var_ref = gogo->backend()->compound_expression(decl, var_ref, loc); @@ -1724,10 +1724,12 @@ Func_descriptor_expression::do_get_backend(Translate_context* context) if (no->is_function() && no->func_value()->is_referenced_by_inline()) is_hidden = false; + unsigned int flags = 0; + if (is_hidden) + flags |= Backend::variable_is_hidden; bvar = context->backend()->immutable_struct(bname.name(), bname.optional_asm_name(), - is_hidden, false, - btype, bloc); + flags, btype, bloc); Expression_list* vals = new Expression_list(); vals->push_back(Expression::make_func_code_reference(this->fn_, bloc)); Expression* init = @@ -1736,8 +1738,7 @@ Func_descriptor_expression::do_get_backend(Translate_context* context) bcontext.set_is_const(); Bexpression* binit = init->get_backend(&bcontext); context->backend()->immutable_struct_set_init(bvar, bname.name(), - is_hidden, false, btype, - bloc, binit); + flags, btype, bloc, binit); } this->dvar_ = bvar; @@ -5280,12 +5281,14 @@ Unary_expression::do_get_backend(Translate_context* context) copy_to_heap = (context->function() != NULL || context->is_const()); } + unsigned int flags = (Backend::variable_is_hidden + | Backend::variable_address_is_taken); + if (copy_to_heap) + flags |= Backend::variable_is_constant; Bvariable* implicit = - gogo->backend()->implicit_variable(var_name, "", btype, true, - copy_to_heap, false, 0); + gogo->backend()->implicit_variable(var_name, "", btype, flags, 0); gogo->backend()->implicit_variable_set_init(implicit, var_name, btype, - true, copy_to_heap, false, - bexpr); + flags, bexpr); bexpr = gogo->backend()->var_expression(implicit, loc); // If we are not copying a slice initializer to the heap, @@ -5307,22 +5310,24 @@ Unary_expression::do_get_backend(Translate_context* context) && this->expr_->is_static_initializer()) { std::string var_name(gogo->initializer_name()); + unsigned int flags = (Backend::variable_is_hidden + | Backend::variable_address_is_taken); Bvariable* decl = - gogo->backend()->immutable_struct(var_name, "", true, false, - btype, loc); - gogo->backend()->immutable_struct_set_init(decl, var_name, true, - false, btype, loc, bexpr); + gogo->backend()->immutable_struct(var_name, "", flags, btype, loc); + gogo->backend()->immutable_struct_set_init(decl, var_name, flags, + btype, loc, bexpr); bexpr = gogo->backend()->var_expression(decl, loc); } else if (this->expr_->is_constant()) { std::string var_name(gogo->initializer_name()); + unsigned int flags = (Backend::variable_is_hidden + | Backend::variable_is_constant + | Backend::variable_address_is_taken); Bvariable* decl = - gogo->backend()->implicit_variable(var_name, "", btype, - true, true, false, 0); + gogo->backend()->implicit_variable(var_name, "", btype, flags, 0); gogo->backend()->implicit_variable_set_init(decl, var_name, btype, - true, true, false, - bexpr); + flags, bexpr); bexpr = gogo->backend()->var_expression(decl, loc); } @@ -14888,7 +14893,9 @@ Allocation_expression::do_get_backend(Translate_context* context) : gogo->backend()->zero_expression(btype)); Bvariable* temp = gogo->backend()->temporary_variable(fndecl, context->bblock(), btype, - init, true, loc, &decl); + init, + Backend::variable_address_is_taken, + loc, &decl); Bexpression* ret = gogo->backend()->var_expression(temp, loc); ret = gogo->backend()->address_expression(ret, loc); ret = gogo->backend()->compound_expression(decl, ret, loc); @@ -17238,7 +17245,9 @@ Heap_expression::do_get_backend(Translate_context* context) Bfunction* fndecl = fn->func_value()->get_or_make_decl(gogo, fn); Bvariable* space_temp = gogo->backend()->temporary_variable(fndecl, context->bblock(), btype, - space, true, loc, &decl); + space, + Backend::variable_address_is_taken, + loc, &decl); Btype* expr_btype = etype->get_backend(gogo); Bexpression* bexpr = this->expr_->get_backend(context); @@ -17259,8 +17268,9 @@ Heap_expression::do_get_backend(Translate_context* context) Bstatement* edecl; Bvariable* btemp = gogo->backend()->temporary_variable(fndecl, context->bblock(), - expr_btype, bexpr, true, loc, - &edecl); + expr_btype, bexpr, + Backend::variable_address_is_taken, + loc, &edecl); Bexpression* btempref = gogo->backend()->var_expression(btemp, loc); space = gogo->backend()->var_expression(space_temp, loc); @@ -18478,10 +18488,13 @@ Interface_mtable_expression::do_get_backend(Translate_context* context) Bexpression* ctor = gogo->backend()->constructor_expression(btype, ctor_bexprs, loc); - this->bvar_ = gogo->backend()->immutable_struct(mangled_name, "", false, - !is_public, btype, loc); - gogo->backend()->immutable_struct_set_init(this->bvar_, mangled_name, false, - !is_public, btype, loc, ctor); + unsigned int flags = 0; + if (!is_public) + flags |= Backend::variable_is_hidden; + this->bvar_ = gogo->backend()->immutable_struct(mangled_name, "", flags, + btype, loc); + gogo->backend()->immutable_struct_set_init(this->bvar_, mangled_name, flags, + btype, loc, ctor); return gogo->backend()->var_expression(this->bvar_, loc); } diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 93b54fd..2872d2e 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -918,9 +918,8 @@ Gogo::build_type_descriptor_list() // Create the variable std::string name = this->type_descriptor_list_symbol(this->pkgpath_symbol()); - Bvariable* bv = this->backend()->implicit_variable(name, name, bt, - false, true, false, - 0); + unsigned int flags = Backend::variable_is_constant; + Bvariable* bv = this->backend()->implicit_variable(name, name, bt, flags, 0); // Build the initializer std::vector indexes; @@ -946,8 +945,7 @@ Gogo::build_type_descriptor_list() Bexpression* binit = this->backend()->constructor_expression(bt, fields, builtin_loc); - this->backend()->implicit_variable_set_init(bv, name, bt, false, - true, false, binit); + this->backend()->implicit_variable_set_init(bv, name, bt, flags, binit); } // Register the type descriptors with the runtime. This is to help @@ -1002,11 +1000,11 @@ Gogo::register_type_descriptors(std::vector& init_stmts, // Create a variable holding the list. std::string name = this->typelists_symbol(); - Bvariable* bv = this->backend()->implicit_variable(name, name, bat, - true, true, false, + unsigned int flags = (Backend::variable_is_hidden + | Backend::variable_is_constant); + Bvariable* bv = this->backend()->implicit_variable(name, name, bat, flags, 0); - this->backend()->implicit_variable_set_init(bv, name, bat, true, true, - false, barray); + this->backend()->implicit_variable_set_init(bv, name, bat, flags, barray); // Build the call in main package's init function. Translate_context context(this, NULL, NULL, NULL); @@ -8062,16 +8060,24 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function, if (package != NULL) is_hidden = false; + unsigned int flags = 0; + if (this->is_address_taken_ + || this->is_non_escaping_address_taken_) + flags |= Backend::variable_address_is_taken; + if (package != NULL) + flags |= Backend::variable_is_external; + if (is_hidden) + flags |= Backend::variable_is_hidden; + if (this->in_unique_section_) + flags |= Backend::variable_in_unique_section; + // For some reason asm_name can't be the empty string // for global_variable, so we call asm_name rather than // optional_asm_name here. FIXME. bvar = backend->global_variable(bname.name(), bname.asm_name(), - btype, - package != NULL, - is_hidden, - this->in_unique_section_, + btype, flags, this->location_); } else if (function == NULL) @@ -8083,15 +8089,16 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function, { const std::string n = Gogo::unpack_hidden_name(name); Bfunction* bfunction = function->func_value()->get_decl(); - bool is_address_taken = (this->is_non_escaping_address_taken_ - && !this->is_in_heap()); + unsigned int flags = 0; + if (this->is_non_escaping_address_taken_ + && !this->is_in_heap()) + flags |= Backend::variable_address_is_taken; if (this->is_closure()) bvar = backend->static_chain_variable(bfunction, n, btype, - this->location_); + flags, this->location_); else if (is_parameter) bvar = backend->parameter_variable(bfunction, n, btype, - is_address_taken, - this->location_); + flags, this->location_); else { Bvariable* bvar_decl = NULL; @@ -8102,8 +8109,7 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function, ->get_backend_variable(&context); } bvar = backend->local_variable(bfunction, n, btype, - bvar_decl, - is_address_taken, + bvar_decl, flags, this->location_); } } @@ -8134,10 +8140,12 @@ Result_variable::get_backend_variable(Gogo* gogo, Named_object* function, Btype* btype = type->get_backend(gogo); Bfunction* bfunction = function->func_value()->get_decl(); std::string n = Gogo::unpack_hidden_name(name); - bool is_address_taken = (this->is_non_escaping_address_taken_ - && !this->is_in_heap()); + unsigned int flags = 0; + if (this->is_non_escaping_address_taken_ + && !this->is_in_heap()) + flags |= Backend::variable_address_is_taken; this->backend_ = backend->local_variable(bfunction, n, btype, - NULL, is_address_taken, + NULL, flags, this->location_); } } diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index b066011..9643d1b 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -643,11 +643,13 @@ Temporary_statement::do_get_backend(Translate_context* context) binit = context->backend()->convert_expression(btype, binit, this->location()); + unsigned int flags = 0; + if (this->is_address_taken_) + flags |= Backend::variable_address_is_taken; Bstatement* statement; this->bvariable_ = context->backend()->temporary_variable(bfunction, context->bblock(), - btype, binit, - this->is_address_taken_, + btype, binit, flags, this->location(), &statement); return statement; } diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 7d4c47f..d08cbc9 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -1410,10 +1410,12 @@ Type::make_type_descriptor_var(Gogo* gogo) // ensure that type_descriptor_pointer will work if called while // converting INITIALIZER. + unsigned int flags = 0; + if (is_common) + flags |= Backend::variable_is_common; this->type_descriptor_var_ = gogo->backend()->immutable_struct(bname.name(), bname.optional_asm_name(), - false, is_common, initializer_btype, - loc); + flags, initializer_btype, loc); if (phash != NULL) *phash = this->type_descriptor_var_; @@ -1422,7 +1424,7 @@ Type::make_type_descriptor_var(Gogo* gogo) Bexpression* binitializer = initializer->get_backend(&context); gogo->backend()->immutable_struct_set_init(this->type_descriptor_var_, - bname.name(), false, is_common, + bname.name(), flags, initializer_btype, loc, binitializer); @@ -2714,9 +2716,13 @@ Type::make_gc_symbol_var(Gogo* gogo) // Since we are building the GC symbol in this package, we must create the // variable before converting the initializer to its backend representation // because the initializer may refer to the GC symbol for this type. + unsigned int flags = Backend::variable_is_constant; + if (is_common) + flags |= Backend::variable_is_common; + else + flags |= Backend::variable_is_hidden; this->gc_symbol_var_ = - gogo->backend()->implicit_variable(sym_name, "", sym_btype, false, true, - is_common, 0); + gogo->backend()->implicit_variable(sym_name, "", sym_btype, flags, 0); if (phash != NULL) *phash = this->gc_symbol_var_; @@ -2724,8 +2730,7 @@ Type::make_gc_symbol_var(Gogo* gogo) context.set_is_const(); Bexpression* sym_binit = sym_init->get_backend(&context); gogo->backend()->implicit_variable_set_init(this->gc_symbol_var_, sym_name, - sym_btype, false, true, is_common, - sym_binit); + sym_btype, flags, sym_binit); } // Return whether this type needs a GC program, and set *PTRDATA to @@ -3013,11 +3018,12 @@ Type::gc_ptrmask_var(Gogo* gogo, int64_t ptrsize, int64_t ptrdata) Bexpression* bval = val->get_backend(&context); Btype *btype = val->type()->get_backend(gogo); + unsigned int flags = (Backend::variable_is_constant + | Backend::variable_is_common); Bvariable* ret = gogo->backend()->implicit_variable(sym_name, "", - btype, false, true, - true, 0); - gogo->backend()->implicit_variable_set_init(ret, sym_name, btype, false, - true, true, bval); + btype, flags, 0); + gogo->backend()->implicit_variable_set_init(ret, sym_name, btype, flags, + bval); ins.first->second = ret; return ret; } @@ -8145,11 +8151,12 @@ Map_type::backend_zero_value(Gogo* gogo) Btype* barray_type = gogo->backend()->array_type(buint8_type, blength); std::string zname = Map_type::zero_value->name(); + unsigned int flags = Backend::variable_is_common; Bvariable* zvar = - gogo->backend()->implicit_variable(zname, "", barray_type, false, false, - true, Map_type::zero_value_align); + gogo->backend()->implicit_variable(zname, "", barray_type, flags, + Map_type::zero_value_align); gogo->backend()->implicit_variable_set_init(zvar, zname, barray_type, - false, false, true, NULL); + flags, NULL); return zvar; } -- cgit v1.1 From 637569df03507cfd603d0979652b0a936d9b122d Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 25 May 2021 00:16:53 +0000 Subject: Daily bump. --- gcc/go/ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'gcc/go') diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 85bd343..7cc756b 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,9 @@ +2021-05-24 Ian Lance Taylor + + PR go/100537 + * go-gcc.cc (class Gcc_backend): Update methods that create + variables to take a flags parameter. + 2021-01-28 Ian Lance Taylor * gospec.c (lang_specific_driver): Add -g if no debugging options -- cgit v1.1 From 4774807e6e535597676473051aa00aabac075327 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 27 May 2021 15:32:28 -0700 Subject: gccgo.texi: remove HTML quoting * gccgo.texi (Function Names): Don't HTML quote ampersand. --- gcc/go/gccgo.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/go') diff --git a/gcc/go/gccgo.texi b/gcc/go/gccgo.texi index ce6b518..fa0e488 100644 --- a/gcc/go/gccgo.texi +++ b/gcc/go/gccgo.texi @@ -495,7 +495,7 @@ like (after importing the @code{os} package): @smallexample var name = [4]byte@{'f', 'o', 'o', 0@}; -i := c_open(&name[0], os.O_RDONLY, 0); +i := c_open(&name[0], os.O_RDONLY, 0); @end smallexample Note that this serves as an example only. To open a file in Go please -- cgit v1.1 From cd62d089f6021fd1ad4537b8182836d15b14514f Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 28 May 2021 00:16:38 +0000 Subject: Daily bump. --- gcc/go/ChangeLog | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gcc/go') diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 7cc756b..b6ec83c 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,7 @@ +2021-05-27 Ian Lance Taylor + + * gccgo.texi (Function Names): Don't HTML quote ampersand. + 2021-05-24 Ian Lance Taylor PR go/100537 -- cgit v1.1 From ee52bf609bac45b3c251858a69071262f46ee89c Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 10 Jun 2021 12:37:34 -0700 Subject: libgo: update to Go1.16.5 release Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/326772 --- gcc/go/gofrontend/MERGE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 1f38c911..f16fb9f 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -5a801b15699cced5203af5c7339b375cd55ecbac +bcafcb3c39530bb325514d6377747eb3127d1a03 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. -- cgit v1.1 From 8a8a7d332d5d01db5aea7336a36d9fd71a679fb1 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 28 Jun 2021 16:47:55 -0700 Subject: compiler: in composite literals use temps only for interfaces For a composite literal we only need to introduce a temporary variable if we may be converting to an interface type, so only do it then. This saves over 80% of compilation time when using gccgo to compile cmd/internal/obj/x86, as the GCC middle-end spends a lot of time pointlessly computing interactions between temporary variables. For PR debug/101064 For golang/go#46600 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/331513 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index f16fb9f..f7bcc8c 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -bcafcb3c39530bb325514d6377747eb3127d1a03 +cad187fe3aceb2a7d964b64c70dfa8c8ad24ce65 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 5d45e4b..94342b2 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -15148,7 +15148,7 @@ Struct_construction_expression::do_copy() } // Flatten a struct construction expression. Store the values into -// temporaries in case they need interface conversion. +// temporaries if they may need interface conversion. Expression* Struct_construction_expression::do_flatten(Gogo*, Named_object*, @@ -15162,10 +15162,13 @@ Struct_construction_expression::do_flatten(Gogo*, Named_object*, return this; Location loc = this->location(); + const Struct_field_list* fields = this->type_->struct_type()->fields(); + Struct_field_list::const_iterator pf = fields->begin(); for (Expression_list::iterator pv = this->vals()->begin(); pv != this->vals()->end(); - ++pv) + ++pv, ++pf) { + go_assert(pf != fields->end()); if (*pv != NULL) { if ((*pv)->is_error_expression() || (*pv)->type()->is_error_type()) @@ -15173,7 +15176,8 @@ Struct_construction_expression::do_flatten(Gogo*, Named_object*, go_assert(saw_errors()); return Expression::make_error(loc); } - if (!(*pv)->is_multi_eval_safe()) + if (pf->type()->interface_type() != NULL + && !(*pv)->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, *pv, loc); @@ -15448,7 +15452,7 @@ Array_construction_expression::do_check_types(Gogo*) } // Flatten an array construction expression. Store the values into -// temporaries in case they need interface conversion. +// temporaries if they may need interface conversion. Expression* Array_construction_expression::do_flatten(Gogo*, Named_object*, @@ -15467,6 +15471,11 @@ Array_construction_expression::do_flatten(Gogo*, Named_object*, if (this->is_constant_array() || this->is_static_initializer()) return this; + // If the array element type is not an interface type, we don't need + // temporaries. + if (this->type_->array_type()->element_type()->interface_type() == NULL) + return this; + Location loc = this->location(); for (Expression_list::iterator pv = this->vals()->begin(); pv != this->vals()->end(); -- cgit v1.1 From cca7eb8f7cc157ed1b351cbaa10a4066f8065c3a Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 29 Jun 2021 12:12:16 -0700 Subject: go-gcc: set DECL_NAMELESS for temporary variables * go-gcc.cc (Gcc_backend::static_chain_variable): Set DECL_NAMELESS on the new decl. (Gcc_backend::temporary_variable): Likewise. (Gcc_backend::function): Set DECL_NAMELESS on the result decl. --- gcc/go/go-gcc.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'gcc/go') diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index 41f309e..f812796 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -2853,6 +2853,7 @@ Gcc_backend::static_chain_variable(Bfunction* function, const std::string& name, TREE_USED(decl) = 1; DECL_ARTIFICIAL(decl) = 1; DECL_IGNORED_P(decl) = 1; + DECL_NAMELESS(decl) = 1; TREE_READONLY(decl) = 1; struct function *f = DECL_STRUCT_FUNCTION(fndecl); @@ -2912,6 +2913,7 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock, type_tree); DECL_ARTIFICIAL(var) = 1; DECL_IGNORED_P(var) = 1; + DECL_NAMELESS(var) = 1; TREE_USED(var) = 1; DECL_CONTEXT(var) = decl; @@ -3290,6 +3292,7 @@ Gcc_backend::function(Btype* fntype, const std::string& name, build_decl(location.gcc_location(), RESULT_DECL, NULL_TREE, restype); DECL_ARTIFICIAL(resdecl) = 1; DECL_IGNORED_P(resdecl) = 1; + DECL_NAMELESS(resdecl) = 1; DECL_CONTEXT(resdecl) = decl; DECL_RESULT(decl) = resdecl; } -- cgit v1.1 From 13c906f43f473ee9ff16d80590789d719f2190a4 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 29 Jun 2021 12:53:02 -0700 Subject: compiler: don't generate temporaries for composite literals We were generating temporaries for composite literals when a conversion to interface type was required. However, Cherry's https://golang.org/cl/176459 changed the compiler to insert explicit type conversions. And those explicit type conversions insert the required temporaries in Type_conversion_expression::do_flatten. So in practice the composite literal do_flatten methods would never insert temporaries, as the values they see would always be multi_eval_safe. So just remove the unnecessary do_flatten methods. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/331691 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 103 +++------------------------------------ gcc/go/gofrontend/expressions.h | 6 --- 3 files changed, 7 insertions(+), 104 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index f7bcc8c..ab1384d 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -cad187fe3aceb2a7d964b64c70dfa8c8ad24ce65 +01cb2b5e69a2d08ef3cc1ea023c22ed9b79f5114 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 94342b2..a0472ac 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -15147,48 +15147,6 @@ Struct_construction_expression::do_copy() return ret; } -// Flatten a struct construction expression. Store the values into -// temporaries if they may need interface conversion. - -Expression* -Struct_construction_expression::do_flatten(Gogo*, Named_object*, - Statement_inserter* inserter) -{ - if (this->vals() == NULL) - return this; - - // If this is a constant struct, we don't need temporaries. - if (this->is_constant_struct() || this->is_static_initializer()) - return this; - - Location loc = this->location(); - const Struct_field_list* fields = this->type_->struct_type()->fields(); - Struct_field_list::const_iterator pf = fields->begin(); - for (Expression_list::iterator pv = this->vals()->begin(); - pv != this->vals()->end(); - ++pv, ++pf) - { - go_assert(pf != fields->end()); - if (*pv != NULL) - { - if ((*pv)->is_error_expression() || (*pv)->type()->is_error_type()) - { - go_assert(saw_errors()); - return Expression::make_error(loc); - } - if (pf->type()->interface_type() != NULL - && !(*pv)->is_multi_eval_safe()) - { - Temporary_statement* temp = - Statement::make_temporary(NULL, *pv, loc); - inserter->insert(temp); - *pv = Expression::make_temporary_reference(temp, loc); - } - } - } - return this; -} - // Make implicit type conversions explicit. void @@ -15451,55 +15409,6 @@ Array_construction_expression::do_check_types(Gogo*) } } -// Flatten an array construction expression. Store the values into -// temporaries if they may need interface conversion. - -Expression* -Array_construction_expression::do_flatten(Gogo*, Named_object*, - Statement_inserter* inserter) -{ - if (this->is_error_expression()) - { - go_assert(saw_errors()); - return this; - } - - if (this->vals() == NULL) - return this; - - // If this is a constant array, we don't need temporaries. - if (this->is_constant_array() || this->is_static_initializer()) - return this; - - // If the array element type is not an interface type, we don't need - // temporaries. - if (this->type_->array_type()->element_type()->interface_type() == NULL) - return this; - - Location loc = this->location(); - for (Expression_list::iterator pv = this->vals()->begin(); - pv != this->vals()->end(); - ++pv) - { - if (*pv != NULL) - { - if ((*pv)->is_error_expression() || (*pv)->type()->is_error_type()) - { - go_assert(saw_errors()); - return Expression::make_error(loc); - } - if (!(*pv)->is_multi_eval_safe()) - { - Temporary_statement* temp = - Statement::make_temporary(NULL, *pv, loc); - inserter->insert(temp); - *pv = Expression::make_temporary_reference(temp, loc); - } - } - } - return this; -} - // Make implicit type conversions explicit. void @@ -15768,14 +15677,14 @@ Slice_construction_expression::create_array_val() // the new temp statement. Expression* -Slice_construction_expression::do_flatten(Gogo* gogo, Named_object* no, +Slice_construction_expression::do_flatten(Gogo*, Named_object*, Statement_inserter* inserter) { if (this->type()->array_type() == NULL) - return NULL; - - // Base class flattening first - this->Array_construction_expression::do_flatten(gogo, no, inserter); + { + go_assert(saw_errors()); + return Expression::make_error(this->location()); + } // Create a stack-allocated storage temp if storage won't escape if (!this->storage_escapes_ @@ -15784,7 +15693,7 @@ Slice_construction_expression::do_flatten(Gogo* gogo, Named_object* no, { Location loc = this->location(); this->array_val_ = this->create_array_val(); - go_assert(this->array_val_); + go_assert(this->array_val_ != NULL); Temporary_statement* temp = Statement::make_temporary(this->valtype_, this->array_val_, loc); inserter->insert(temp); diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index e3747cc..57c974d 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -3806,9 +3806,6 @@ class Struct_construction_expression : public Expression, Expression* do_copy(); - Expression* - do_flatten(Gogo*, Named_object*, Statement_inserter*); - Bexpression* do_get_backend(Translate_context*); @@ -3881,9 +3878,6 @@ protected: indexes() { return this->indexes_; } - Expression* - do_flatten(Gogo*, Named_object*, Statement_inserter*); - // Get the backend constructor for the array values. Bexpression* get_constructor(Translate_context* context, Btype* btype); -- cgit v1.1 From 6bc18203dd2a696cdfcd9d45eae3b9cce7b08822 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 30 Jun 2021 00:16:52 +0000 Subject: Daily bump. --- gcc/go/ChangeLog | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'gcc/go') diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index b6ec83c..60ebb89 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,10 @@ +2021-06-29 Ian Lance Taylor + + * go-gcc.cc (Gcc_backend::static_chain_variable): Set + DECL_NAMELESS on the new decl. + (Gcc_backend::temporary_variable): Likewise. + (Gcc_backend::function): Set DECL_NAMELESS on the result decl. + 2021-05-27 Ian Lance Taylor * gccgo.texi (Function Names): Don't HTML quote ampersand. -- cgit v1.1 From 1798cac7a8b3331a277da1f106752ce0a34f8937 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 8 Jul 2021 19:25:55 -0700 Subject: runtime: remove direct assignments to memory locations PR bootstrap/101374 They cause a warning with the updated GCC -Warray-bounds option. Replace them with calls to abort, which for our purposes is fine. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/333409 --- gcc/go/gofrontend/MERGE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index ab1384d..4d0f44f 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -01cb2b5e69a2d08ef3cc1ea023c22ed9b79f5114 +adcf10890833026437a94da54934ce50c0018309 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. -- cgit v1.1 From 476242fa5ceaa91393562814471c385ebfdd41f3 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 19 Jul 2021 11:53:05 -0700 Subject: compiler: avoid aliases in receiver types If a package declares a method on an alias type, the alias would be used in the export data. This would then trigger a compiler assertion on import: we should not be adding methods to aliases. Fix the problem by ensuring that receiver types do not use alias types. This seems preferable to consistently avoiding aliases in export data, as aliases can cross packages. And it's painful to try to patch this while writing the export data, as at that point all the types are known. Test case is https://golang.org/cl/335172. Fixes golang/go#47131 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/335729 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/gogo.cc | 40 ++++++++++++++++++++++++++++++++++++ gcc/go/gofrontend/gogo.h | 8 ++++++++ gcc/go/gofrontend/types.cc | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+), 1 deletion(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 4d0f44f..5323e18 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -adcf10890833026437a94da54934ce50c0018309 +920549b6382a2623538d31001271941f0e9e5a51 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/gogo.cc b/gcc/go/gofrontend/gogo.cc index 2872d2e..95b76bd 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -5763,6 +5763,26 @@ Function::check_labels() const } } +// Set the receiver type. This is used to remove aliases. + +void +Function::set_receiver_type(Type* rtype) +{ + Function_type* oft = this->type_; + Typed_identifier* rec = new Typed_identifier(oft->receiver()->name(), + rtype, + oft->receiver()->location()); + Typed_identifier_list* parameters = NULL; + if (oft->parameters() != NULL) + parameters = oft->parameters()->copy(); + Typed_identifier_list* results = NULL; + if (oft->results() != NULL) + results = oft->results()->copy(); + Function_type* nft = Type::make_function_type(rec, parameters, results, + oft->location()); + this->type_ = nft; +} + // Swap one function with another. This is used when building the // thunk we use to call a function which calls recover. It may not // work for any other case. @@ -7285,6 +7305,26 @@ Function_declaration::set_nointerface() this->pragmas_ |= GOPRAGMA_NOINTERFACE; } +// Set the receiver type. This is used to remove aliases. + +void +Function_declaration::set_receiver_type(Type* rtype) +{ + Function_type* oft = this->fntype_; + Typed_identifier* rec = new Typed_identifier(oft->receiver()->name(), + rtype, + oft->receiver()->location()); + Typed_identifier_list* parameters = NULL; + if (oft->parameters() != NULL) + parameters = oft->parameters()->copy(); + Typed_identifier_list* results = NULL; + if (oft->results() != NULL) + results = oft->results()->copy(); + Function_type* nft = Type::make_function_type(rec, parameters, results, + oft->location()); + this->fntype_ = nft; +} + // Import an inlinable function. This is used for an inlinable // function whose body is recorded in the export data. Parse the // export data into a Block and create a regular function using that diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index f4155a2..c49bc92 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -1724,6 +1724,10 @@ class Function set_is_referenced_by_inline() { this->is_referenced_by_inline_ = true; } + // Set the receiver type. This is used to remove aliases. + void + set_receiver_type(Type* rtype); + // Swap with another function. Used only for the thunk which calls // recover. void @@ -1990,6 +1994,10 @@ class Function_declaration set_is_on_inlinable_list() { this->is_on_inlinable_list_ = true; } + // Set the receiver type. This is used to remove aliases. + void + set_receiver_type(Type* rtype); + // Import the function body, creating a function. void import_function_body(Gogo*, Named_object*); diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index d08cbc9..ab7166b 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -10416,6 +10416,57 @@ Named_type::finalize_methods(Gogo* gogo) return; } + // Remove any aliases in the local method receiver types. + Bindings* methods = this->local_methods_; + if (methods != NULL) + { + for (Bindings::const_declarations_iterator p = + methods->begin_declarations(); + p != methods->end_declarations(); + ++p) + { + Named_object* no = p->second; + Function_type* fntype; + if (no->is_function()) + fntype = no->func_value()->type(); + else if (no->is_function_declaration()) + fntype = no->func_declaration_value()->type(); + else + { + go_assert(saw_errors()); + continue; + } + + Type* rtype = fntype->receiver()->type(); + bool is_pointer = false; + Type* pt = rtype->points_to(); + if (pt != NULL) + { + rtype = pt; + is_pointer = true; + } + if (rtype->named_type() != this) + { + if (rtype->unalias() != this) + { + go_assert(saw_errors()); + continue; + } + + rtype = this; + if (is_pointer) + rtype = Type::make_pointer_type(rtype); + + if (no->is_function()) + no->func_value()->set_receiver_type(rtype); + else if (no->is_function_declaration()) + no->func_declaration_value()->set_receiver_type(rtype); + else + go_unreachable(); + } + } + } + Type::finalize_methods(gogo, this, this->location_, &this->all_methods_); } -- cgit v1.1 From 06d0437d4a5faca2b695918cbe1d54a61935c98b Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sat, 31 Jul 2021 19:28:51 -0700 Subject: compiler, runtime: support unsafe.Add and unsafe.Slice For golang/go#19367 For golang/go#40481 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/338949 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 227 +++++++++++++++++++++++++++++++++++++++ gcc/go/gofrontend/expressions.h | 4 +- gcc/go/gofrontend/runtime.def | 6 ++ gcc/go/gofrontend/unsafe.cc | 16 +++ 5 files changed, 253 insertions(+), 2 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 5323e18..19fbd64 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -920549b6382a2623538d31001271941f0e9e5a51 +ad667e7c70cea9fa5730660d72ad891b5753eb62 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 a0472ac..46e71e5 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -8252,12 +8252,16 @@ Builtin_call_expression::Builtin_call_expression(Gogo* gogo, this->code_ = BUILTIN_REAL; else if (name == "recover") this->code_ = BUILTIN_RECOVER; + else if (name == "Add") + this->code_ = BUILTIN_ADD; else if (name == "Alignof") this->code_ = BUILTIN_ALIGNOF; else if (name == "Offsetof") this->code_ = BUILTIN_OFFSETOF; else if (name == "Sizeof") this->code_ = BUILTIN_SIZEOF; + else if (name == "Slice") + this->code_ = BUILTIN_SLICE; else go_unreachable(); } @@ -8694,6 +8698,119 @@ Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function, return Runtime::make_call(code, loc, 3, e1, e2, e3); } + + case BUILTIN_ADD: + { + Expression* ptr = this->args()->front(); + Type* uintptr_type = Type::lookup_integer_type("uintptr"); + ptr = Expression::make_cast(uintptr_type, ptr, loc); + Expression* len = this->args()->back(); + len = Expression::make_cast(uintptr_type, len, loc); + Expression* add = Expression::make_binary(OPERATOR_PLUS, ptr, len, + loc); + return Expression::make_cast(this->args()->front()->type(), add, loc); + } + + case BUILTIN_SLICE: + { + Expression* ptr = this->args()->front(); + Temporary_statement* ptr_temp = NULL; + if (!ptr->is_multi_eval_safe()) + { + ptr_temp = Statement::make_temporary(NULL, ptr, loc); + inserter->insert(ptr_temp); + ptr = Expression::make_temporary_reference(ptr_temp, loc); + } + + Expression* len = this->args()->back(); + Temporary_statement* len_temp = NULL; + if (!len->is_multi_eval_safe()) + { + len_temp = Statement::make_temporary(NULL, len, loc); + inserter->insert(len_temp); + len = Expression::make_temporary_reference(len_temp, loc); + } + + bool fits_in_int; + Numeric_constant nc; + if (this->args()->back()->numeric_constant_value(&nc)) + { + // We gave an error for constants that don't fit in int in + // check_types. + fits_in_int = true; + } + else + { + Integer_type* itype = this->args()->back()->type()->integer_type(); + go_assert(itype != NULL); + int ebits = itype->bits(); + int intbits = + Type::lookup_integer_type("int")->integer_type()->bits(); + + // We can treat ebits == intbits as small even for an + // unsigned integer type, because we will convert the + // value to int and then reject it in the runtime if it is + // negative. + + fits_in_int = ebits <= intbits; + } + + Runtime::Function code = (fits_in_int + ? Runtime::UNSAFESLICE + : Runtime::UNSAFESLICE64); + Expression* td = + Expression::make_type_descriptor(ptr->type()->points_to(), loc); + Expression* check = Runtime::make_call(code, loc, 3, + td, ptr, len); + + if (ptr_temp == NULL) + ptr = ptr->copy(); + else + ptr = Expression::make_temporary_reference(ptr_temp, loc); + Expression* nil = Expression::make_nil(loc); + nil = Expression::make_cast(ptr->type(), nil, loc); + Expression* is_nil = Expression::make_binary(OPERATOR_EQEQ, ptr, nil, + loc); + + if (len_temp == NULL) + len = len->copy(); + else + len = Expression::make_temporary_reference(len_temp, loc); + Expression* zero = Expression::make_integer_ul(0, len->type(), loc); + Expression* is_zero = Expression::make_binary(OPERATOR_EQEQ, len, zero, + loc); + + Expression* cond = Expression::make_binary(OPERATOR_ANDAND, is_nil, + is_zero, loc); + + Type* slice_type = Type::make_array_type(ptr->type()->points_to(), + NULL); + nil = Expression::make_nil(loc); + Expression* nil_slice = Expression::make_cast(slice_type, nil, loc); + + if (ptr_temp == NULL) + ptr = ptr->copy(); + else + ptr = Expression::make_temporary_reference(ptr_temp, loc); + + if (len_temp == NULL) + len = len->copy(); + else + len = Expression::make_temporary_reference(len_temp, loc); + + Expression* cap; + if (len_temp == NULL) + cap = len->copy(); + else + cap = Expression::make_temporary_reference(len_temp, loc); + + Expression* slice = Expression::make_slice_value(slice_type, ptr, + len, cap, loc); + + slice = Expression::make_conditional(cond, nil_slice, slice, loc); + + return Expression::make_compound(check, slice, loc); + } } return this; @@ -9781,9 +9898,11 @@ Builtin_call_expression::do_discarding_value() case BUILTIN_MAKE: case BUILTIN_NEW: case BUILTIN_REAL: + case BUILTIN_ADD: case BUILTIN_ALIGNOF: case BUILTIN_OFFSETOF: case BUILTIN_SIZEOF: + case BUILTIN_SLICE: this->unused_value_error(); return false; @@ -9890,6 +10009,18 @@ Builtin_call_expression::do_type() t = Type::make_error_type(); return t; } + + case BUILTIN_ADD: + return Type::make_pointer_type(Type::make_void_type()); + + case BUILTIN_SLICE: + const Expression_list* args = this->args(); + if (args == NULL || args->size() != 2) + return Type::make_error_type(); + Type* pt = args->front()->type()->points_to(); + if (pt == NULL) + return Type::make_error_type(); + return Type::make_array_type(pt, NULL); } } @@ -9954,6 +10085,28 @@ Builtin_call_expression::do_determine_type(const Type_context* context) is_print = false; break; + case BUILTIN_ADD: + case BUILTIN_SLICE: + // Both unsafe.Add and unsafe.Slice take two arguments, and the + // second arguments defaults to "int". + if (args != NULL && args->size() == 2) + { + if (this->code_ == BUILTIN_SLICE) + args->front()->determine_type_no_context(); + else + { + Type* pointer = Type::make_pointer_type(Type::make_void_type()); + Type_context subcontext(pointer, false); + args->front()->determine_type(&subcontext); + } + Type* int_type = Type::lookup_integer_type("int"); + Type_context subcontext(int_type, false); + args->back()->determine_type(&subcontext); + return; + } + is_print = false; + break; + default: is_print = false; break; @@ -10353,6 +10506,78 @@ Builtin_call_expression::do_check_types(Gogo*) } break; + case BUILTIN_ADD: + case BUILTIN_SLICE: + { + Numeric_constant nc; + unsigned long v; + const Expression_list* args = this->args(); + if (args == NULL || args->size() < 2) + this->report_error(_("not enough arguments")); + else if (args->size() > 2) + this->report_error(_("too many arguments")); + else if (args->front()->is_error_expression() + || args->front()->type()->is_error() + || args->back()->is_error_expression() + || args->back()->type()->is_error()) + this->set_is_error(); + else if (args->back()->type()->integer_type() == NULL + && (!args->back()->type()->is_abstract() + || !args->back()->numeric_constant_value(&nc) + || (nc.to_unsigned_long(&v) + == Numeric_constant::NC_UL_NOTINT))) + { + if (this->code_ == BUILTIN_ADD) + go_error_at(args->back()->location(), "non-integer offset"); + else + go_error_at(args->back()->location(), "non-integer size"); + } + else if (this->code_ == BUILTIN_ADD) + { + Type* pointer_type = + Type::make_pointer_type(Type::make_void_type()); + std::string reason; + if (!Type::are_assignable(pointer_type, args->front()->type(), + &reason)) + { + if (reason.empty()) + go_error_at(args->front()->location(), + "argument 1 has incompatible type"); + else + go_error_at(args->front()->location(), + "argument 1 has incompatible type (%s)", + reason.c_str()); + this->set_is_error(); + } + } + else + { + if (args->front()->type()->points_to() == NULL) + { + go_error_at(args->front()->location(), + "argument 1 must be a pointer"); + this->set_is_error(); + } + + unsigned int int_bits = + Type::lookup_integer_type("int")->integer_type()->bits(); + + mpz_t ival; + if (args->back()->numeric_constant_value(&nc) && nc.to_int(&ival)) + { + if (mpz_sgn(ival) < 0 + || mpz_sizeinbase(ival, 2) >= int_bits) + { + go_error_at(args->back()->location(), + "slice length out of range"); + this->set_is_error(); + } + mpz_clear(ival); + } + } + } + break; + default: go_unreachable(); } @@ -10397,6 +10622,8 @@ Builtin_call_expression::do_get_backend(Translate_context* context) case BUILTIN_INVALID: case BUILTIN_NEW: case BUILTIN_MAKE: + case BUILTIN_ADD: + case BUILTIN_SLICE: go_unreachable(); case BUILTIN_LEN: diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 57c974d..492849b 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -2608,9 +2608,11 @@ class Builtin_call_expression : public Call_expression BUILTIN_RECOVER, // Builtin functions from the unsafe package. + BUILTIN_ADD, BUILTIN_ALIGNOF, BUILTIN_OFFSETOF, - BUILTIN_SIZEOF + BUILTIN_SIZEOF, + BUILTIN_SLICE }; Builtin_function_code diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def index ec01be0..231d92d 100644 --- a/gcc/go/gofrontend/runtime.def +++ b/gcc/go/gofrontend/runtime.def @@ -489,6 +489,12 @@ DEF_GO_RUNTIME(ATOMIC_OR_FETCH_1, "__atomic_or_fetch_1", P3(POINTER, UINT8, INT32), R1(UINT8)) +// Check the length of an unsafe slice. +DEF_GO_RUNTIME(UNSAFESLICE, "runtime.unsafeslice", + P3(TYPE, POINTER, INT), R0()) +DEF_GO_RUNTIME(UNSAFESLICE64, "runtime.unsafeslice64", + P3(TYPE, POINTER, INT64), R0()) + // Panic reporting a division by zero. DEF_GO_RUNTIME(PANIC_DIVIDE, "runtime.panicdivide", P0(), R0()) diff --git a/gcc/go/gofrontend/unsafe.cc b/gcc/go/gofrontend/unsafe.cc index 9ed5b9d..18bd99e 100644 --- a/gcc/go/gofrontend/unsafe.cc +++ b/gcc/go/gofrontend/unsafe.cc @@ -86,6 +86,22 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported, if (add_to_globals) this->add_dot_import_object(no); + // Add. + results = new Typed_identifier_list; + results->push_back(Typed_identifier("", pointer_type, bloc)); + fntype = Type::make_function_type(NULL, NULL, results, bloc); + fntype->set_is_builtin(); + no = bindings->add_function_declaration("Add", package, fntype, bloc); + if (add_to_globals) + this->add_dot_import_object(no); + + // Slice. + fntype = Type::make_function_type(NULL, NULL, NULL, bloc); + fntype->set_is_builtin(); + no = bindings->add_function_declaration("Slice", package, fntype, bloc); + if (add_to_globals) + this->add_dot_import_object(no); + if (!this->imported_unsafe_) { go_imported_unsafe(); -- cgit v1.1 From 7459bfa8a37a4fbd6ed5153bff76f49d372b4ace Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 30 Jul 2021 17:19:42 -0700 Subject: compiler, runtime: allow slice to array pointer conversion Panic if the slice is too short. For golang/go#395 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/338630 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 53 ++++++++++++++++++++++++++++++++++++++-- gcc/go/gofrontend/runtime.def | 5 ++++ gcc/go/gofrontend/types.cc | 7 ++++++ 4 files changed, 64 insertions(+), 3 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 19fbd64..95b9340 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -ad667e7c70cea9fa5730660d72ad891b5753eb62 +0a4d612e6b211780b294717503fc739bbd1f509c 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 46e71e5..15c9eab 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -3866,11 +3866,12 @@ Type_conversion_expression::do_traverse(Traverse* traverse) return TRAVERSE_CONTINUE; } -// Convert to a constant at lowering time. +// Convert to a constant at lowering time. Also lower conversions +// from slice to pointer-to-array, as they can panic. Expression* Type_conversion_expression::do_lower(Gogo*, Named_object*, - Statement_inserter*, int) + Statement_inserter* inserter, int) { Type* type = this->type_; Expression* val = this->expr_; @@ -3958,6 +3959,54 @@ Type_conversion_expression::do_lower(Gogo*, Named_object*, } } + if (type->points_to() != NULL + && type->points_to()->array_type() != NULL + && !type->points_to()->is_slice_type() + && val->type()->is_slice_type()) + { + Temporary_statement* val_temp = NULL; + if (!val->is_multi_eval_safe()) + { + val_temp = Statement::make_temporary(val->type(), NULL, location); + inserter->insert(val_temp); + val = Expression::make_set_and_use_temporary(val_temp, val, + location); + } + + Type* int_type = Type::lookup_integer_type("int"); + Temporary_statement* vallen_temp = + Statement::make_temporary(int_type, NULL, location); + inserter->insert(vallen_temp); + + Expression* arrlen = type->points_to()->array_type()->length(); + Expression* vallen = + Expression::make_slice_info(val, Expression::SLICE_INFO_LENGTH, + location); + vallen = Expression::make_set_and_use_temporary(vallen_temp, vallen, + location); + Expression* cond = Expression::make_binary(OPERATOR_GT, arrlen, vallen, + location); + + vallen = Expression::make_temporary_reference(vallen_temp, location); + Expression* panic = Runtime::make_call(Runtime::PANIC_SLICE_CONVERT, + location, 2, arrlen, vallen); + + Expression* nil = Expression::make_nil(location); + Expression* check = Expression::make_conditional(cond, panic, nil, + location); + + if (val_temp == NULL) + val = val->copy(); + else + val = Expression::make_temporary_reference(val_temp, location); + Expression* ptr = + Expression::make_slice_info(val, Expression::SLICE_INFO_VALUE_POINTER, + location); + ptr = Expression::make_unsafe_cast(type, ptr, location); + + return Expression::make_compound(check, ptr, location); + } + return this; } diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def index 231d92d..fad8ceb 100644 --- a/gcc/go/gofrontend/runtime.def +++ b/gcc/go/gofrontend/runtime.def @@ -582,6 +582,11 @@ DEF_GO_RUNTIME(PANIC_EXTEND_SLICE3_C, "runtime.goPanicExtendSlice3C", DEF_GO_RUNTIME(PANIC_EXTEND_SLICE3_C_U, "runtime.goPanicExtendSlice3CU", P2(UINT64, INT), R0()) +// Panic for conversion of slice to pointer-to-array if the slice is +// too short. +DEF_GO_RUNTIME(PANIC_SLICE_CONVERT, "runtime.goPanicSliceConvert", + P2(INT, INT), R0()) + // Remove helper macros. #undef ABFT6 #undef ABFT2 diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index ab7166b..7c7b2eb 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -842,6 +842,13 @@ Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason) return true; } + // A slice may be converted to a pointer-to-array. + if (rhs->is_slice_type() + && lhs->points_to() != NULL + && lhs->points_to()->array_type() != NULL + && !lhs->points_to()->is_slice_type()) + return true; + // An unsafe.Pointer type may be converted to any pointer type or to // a type whose underlying type is uintptr, and vice-versa. if (lhs->is_unsafe_pointer_type() -- cgit v1.1 From cbbd439a33e889a1a47b103951c53472fc8558eb Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 2 Aug 2021 16:27:02 -0700 Subject: compiler: check slice to pointer-to-array conversion element type When checking a slice to pointer-to-array conversion, I forgot to verify that the elements types are identical. For golang/go#395 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/339329 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 5 ++++- gcc/go/gofrontend/types.cc | 4 +++- 3 files changed, 8 insertions(+), 3 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 95b9340..801e039 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -0a4d612e6b211780b294717503fc739bbd1f509c +54361805bd611d896042b879ee7f6d2d4d088537 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 15c9eab..51a8b7e 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -3962,7 +3962,10 @@ Type_conversion_expression::do_lower(Gogo*, Named_object*, if (type->points_to() != NULL && type->points_to()->array_type() != NULL && !type->points_to()->is_slice_type() - && val->type()->is_slice_type()) + && val->type()->is_slice_type() + && Type::are_identical(type->points_to()->array_type()->element_type(), + val->type()->array_type()->element_type(), + 0, NULL)) { Temporary_statement* val_temp = NULL; if (!val->is_multi_eval_safe()) diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 7c7b2eb..0c44186 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -846,7 +846,9 @@ Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason) if (rhs->is_slice_type() && lhs->points_to() != NULL && lhs->points_to()->array_type() != NULL - && !lhs->points_to()->is_slice_type()) + && !lhs->points_to()->is_slice_type() + && Type::are_identical(lhs->points_to()->array_type()->element_type(), + rhs->array_type()->element_type(), 0, reason)) return true; // An unsafe.Pointer type may be converted to any pointer type or to -- cgit v1.1 From e435e72ad713cadd661072427588ec1c777c04e3 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 3 Aug 2021 11:36:24 -0700 Subject: compile, runtime: make selectnbrecv return two values The only different between selectnbrecv and selectnbrecv2 is the later set the input pointer value by second return value from chanrecv. So by making selectnbrecv return two values from chanrecv, we can get rid of selectnbrecv2, the compiler can now call only selectnbrecv and generate simpler code. This is the gofrontend version of https://golang.org/cl/292890. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/339529 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/runtime.def | 8 ++---- gcc/go/gofrontend/statements.cc | 59 ++++++++++++++++++++++------------------- 3 files changed, 34 insertions(+), 35 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 801e039..5a097ff 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -54361805bd611d896042b879ee7f6d2d4d088537 +2031f0be9c0b5fda6421d290a0261eb6bd1c8205 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/runtime.def b/gcc/go/gofrontend/runtime.def index fad8ceb..87a2708 100644 --- a/gcc/go/gofrontend/runtime.def +++ b/gcc/go/gofrontend/runtime.def @@ -204,12 +204,8 @@ DEF_GO_RUNTIME(SELECTNBSEND, "runtime.selectnbsend", P2(CHAN, POINTER), R1(BOOL) // Non-blocking receive a value from a channel, used for two-case select // statement with a default case. -DEF_GO_RUNTIME(SELECTNBRECV, "runtime.selectnbrecv", P2(POINTER, CHAN), R1(BOOL)) - -// Non-blocking tuple receive from a channel, used for two-case select -// statement with a default case. -DEF_GO_RUNTIME(SELECTNBRECV2, "runtime.selectnbrecv2", P3(POINTER, POINTER, CHAN), - R1(BOOL)) +DEF_GO_RUNTIME(SELECTNBRECV, "runtime.selectnbrecv", P2(POINTER, CHAN), + R2(BOOL, BOOL)) // Block execution. Used for zero-case select. DEF_GO_RUNTIME(BLOCK, "runtime.block", P0(), R0()) diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index 9643d1b..95fa3c4 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -6051,7 +6051,7 @@ Select_statement::lower_two_case(Block* b) Expression* chanref = Expression::make_temporary_reference(chantmp, loc); Block* bchan; - Expression* call; + Expression* cond; if (chancase.is_send()) { // if selectnbsend(chan, &val) { body } else { default body } @@ -6065,7 +6065,7 @@ Select_statement::lower_two_case(Block* b) Expression* ref = Expression::make_temporary_reference(ts, loc); Expression* addr = Expression::make_unary(OPERATOR_AND, ref, loc); - call = Runtime::make_call(Runtime::SELECTNBSEND, loc, 2, chanref, addr); + cond = Runtime::make_call(Runtime::SELECTNBSEND, loc, 2, chanref, addr); bchan = chancase.statements(); } else @@ -6075,34 +6075,31 @@ Select_statement::lower_two_case(Block* b) Expression* ref = Expression::make_temporary_reference(ts, loc); Expression* addr = Expression::make_unary(OPERATOR_AND, ref, loc); - Expression* okref = NULL; - if (chancase.closed() == NULL && chancase.closedvar() == NULL) - { - // Simple receive. - // if selectnbrecv(&lhs, chan) { body } else { default body } - call = Runtime::make_call(Runtime::SELECTNBRECV, loc, 2, addr, chanref); - } - else - { - // Tuple receive. - // if selectnbrecv2(&lhs, &ok, chan) { body } else { default body } - - Type* booltype = Type::make_boolean_type(); - Temporary_statement* okts = Statement::make_temporary(booltype, NULL, - loc); - b->add_statement(okts); - - okref = Expression::make_temporary_reference(okts, loc); - Expression* okaddr = Expression::make_unary(OPERATOR_AND, okref, loc); - call = Runtime::make_call(Runtime::SELECTNBRECV2, loc, 3, addr, okaddr, - chanref); - } + + // selected, ok = selectnbrecv(&lhs, chan) + Call_expression* call = Runtime::make_call(Runtime::SELECTNBRECV, loc, 2, + addr, chanref); + + Temporary_statement* selected_temp = + Statement::make_temporary(Type::make_boolean_type(), + Expression::make_call_result(call, 0), + loc); + b->add_statement(selected_temp); + + Temporary_statement* ok_temp = + Statement::make_temporary(Type::make_boolean_type(), + Expression::make_call_result(call, 1), + loc); + b->add_statement(ok_temp); + + cond = Expression::make_temporary_reference(selected_temp, loc); Location cloc = chancase.location(); bchan = new Block(b, loc); if (chancase.val() != NULL && !chancase.val()->is_sink_expression()) { - Statement* as = Statement::make_assignment(chancase.val(), ref->copy(), + Statement* as = Statement::make_assignment(chancase.val(), + ref->copy(), cloc); bchan->add_statement(as); } @@ -6114,12 +6111,18 @@ Select_statement::lower_two_case(Block* b) if (chancase.closed() != NULL && !chancase.closed()->is_sink_expression()) { + Expression* okref = Expression::make_temporary_reference(ok_temp, + cloc); Statement* as = Statement::make_assignment(chancase.closed(), - okref->copy(), cloc); + okref, cloc); bchan->add_statement(as); } else if (chancase.closedvar() != NULL) - chancase.closedvar()->var_value()->set_init(okref->copy()); + { + Expression* okref = Expression::make_temporary_reference(ok_temp, + cloc); + chancase.closedvar()->var_value()->set_init(okref); + } Statement* bs = Statement::make_block_statement(chancase.statements(), cloc); @@ -6127,7 +6130,7 @@ Select_statement::lower_two_case(Block* b) } Statement* ifs = - Statement::make_if_statement(call, bchan, defcase.statements(), loc); + Statement::make_if_statement(cond, bchan, defcase.statements(), loc); b->add_statement(ifs); Statement* label = -- cgit v1.1 From 22e40cc7feb8abda85762e4f07719836d5c57f1a Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 3 Aug 2021 19:35:55 -0400 Subject: compiler: support new language constructs in escape analysis Previous CLs add new language constructs in Go 1.17, specifically, unsafe.Add, unsafe.Slice, and conversion from a slice to a pointer to an array. This CL handles them in the escape analysis. At the point of the escape analysis, unsafe.Add and unsafe.Slice are still builtin calls, so just handle them in data flow. Conversion from a slice to a pointer to an array has already been lowered to a combination of compound expression, conditional expression and slice info expressions, so handle them in the escape analysis. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/339671 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/escape.cc | 63 +++++++++++++++++++++++++++++---- gcc/go/gofrontend/expressions.cc | 44 +---------------------- gcc/go/gofrontend/expressions.h | 75 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 134 insertions(+), 50 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 5a097ff..be1a90f 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -2031f0be9c0b5fda6421d290a0261eb6bd1c8205 +616ee658a6238e7de53592ebda5997f6de6a00de 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/escape.cc b/gcc/go/gofrontend/escape.cc index cf68874..347ac25 100644 --- a/gcc/go/gofrontend/escape.cc +++ b/gcc/go/gofrontend/escape.cc @@ -2325,19 +2325,55 @@ Escape_analysis_assign::assign(Node* dst, Node* src) } break; + case Expression::EXPRESSION_SLICE_INFO: + { + Slice_info_expression* sie = e->slice_info_expression(); + if (sie->info() == Expression::SLICE_INFO_VALUE_POINTER) + { + Node* slice = Node::make_node(sie->slice()); + this->assign(dst, slice); + } + } + break; + case Expression::EXPRESSION_CALL: { Call_expression* call = e->call_expression(); if (call->is_builtin()) { Builtin_call_expression* bce = call->builtin_call_expression(); - if (bce->code() == Builtin_call_expression::BUILTIN_APPEND) + switch (bce->code()) { - // Append returns the first argument. - // The subsequent arguments are already leaked because - // they are operands to append. - Node* appendee = Node::make_node(call->args()->front()); - this->assign(dst, appendee); + case Builtin_call_expression::BUILTIN_APPEND: + { + // Append returns the first argument. + // The subsequent arguments are already leaked because + // they are operands to append. + Node* appendee = Node::make_node(call->args()->front()); + this->assign(dst, appendee); + } + break; + + case Builtin_call_expression::BUILTIN_ADD: + { + // unsafe.Add(p, off). + // Flow p to result. + Node* arg = Node::make_node(call->args()->front()); + this->assign(dst, arg); + } + break; + + case Builtin_call_expression::BUILTIN_SLICE: + { + // unsafe.Slice(p, len). + // The resulting slice has the same backing store as p. Flow p to result. + Node* arg = Node::make_node(call->args()->front()); + this->assign(dst, arg); + } + break; + + default: + break; } break; } @@ -2592,6 +2628,21 @@ Escape_analysis_assign::assign(Node* dst, Node* src) } break; + case Expression::EXPRESSION_CONDITIONAL: + { + Conditional_expression* ce = e->conditional_expression(); + this->assign(dst, Node::make_node(ce->then_expr())); + this->assign(dst, Node::make_node(ce->else_expr())); + } + break; + + case Expression::EXPRESSION_COMPOUND: + { + Compound_expression* ce = e->compound_expression(); + this->assign(dst, Node::make_node(ce->expr())); + } + break; + default: // TODO(cmang): Add debug info here; this should not be reachable. // For now, just to be conservative, we'll just say dst flows to src. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 51a8b7e..3e433d6 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -18009,49 +18009,7 @@ Expression::make_type_info(Type* type, Type_info type_info) return new Type_info_expression(type, type_info); } -// An expression that evaluates to some characteristic of a slice. -// This is used when indexing, bound-checking, or nil checking a slice. - -class Slice_info_expression : public Expression -{ - public: - Slice_info_expression(Expression* slice, Slice_info slice_info, - Location location) - : Expression(EXPRESSION_SLICE_INFO, location), - slice_(slice), slice_info_(slice_info) - { } - - protected: - Type* - do_type(); - - void - do_determine_type(const Type_context*) - { } - - Expression* - do_copy() - { - return new Slice_info_expression(this->slice_->copy(), this->slice_info_, - this->location()); - } - - Bexpression* - do_get_backend(Translate_context* context); - - void - do_dump_expression(Ast_dump_context*) const; - - void - do_issue_nil_check() - { this->slice_->issue_nil_check(); } - - private: - // The slice for which we are getting information. - Expression* slice_; - // What information we want. - Slice_info slice_info_; -}; +// Slice_info_expression. // Return the type of the slice info. diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 492849b..79a8785 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -62,6 +62,7 @@ class Type_guard_expression; class Heap_expression; class Receive_expression; class Slice_value_expression; +class Slice_info_expression; class Conditional_expression; class Compound_expression; class Numeric_constant; @@ -900,6 +901,14 @@ class Expression compound_expression() { return this->convert(); } + // If this is a slice info expression, return the + // Slice_info_expression structure. Otherwise, return NULL. + Slice_info_expression* + slice_info_expression() + { + return this->convert(); + } + // Return true if this is a composite literal. bool is_composite_literal() const; @@ -4262,6 +4271,60 @@ class Slice_value_expression : public Expression Expression* cap_; }; +// An expression that evaluates to some characteristic of a slice. +// This is used when indexing, bound-checking, or nil checking a slice. + +class Slice_info_expression : public Expression +{ + public: + Slice_info_expression(Expression* slice, Slice_info slice_info, + Location location) + : Expression(EXPRESSION_SLICE_INFO, location), + slice_(slice), slice_info_(slice_info) + { } + + // The slice operand of this slice info expression. + Expression* + slice() const + { return this->slice_; } + + // The info this expression is about. + Slice_info + info() const + { return this->slice_info_; } + + protected: + Type* + do_type(); + + void + do_determine_type(const Type_context*) + { } + + Expression* + do_copy() + { + return new Slice_info_expression(this->slice_->copy(), this->slice_info_, + this->location()); + } + + Bexpression* + do_get_backend(Translate_context* context); + + void + do_dump_expression(Ast_dump_context*) const; + + void + do_issue_nil_check() + { this->slice_->issue_nil_check(); } + + private: + // The slice for which we are getting information. + Expression* slice_; + // What information we want. + Slice_info slice_info_; +}; + // Conditional expressions. class Conditional_expression : public Expression @@ -4277,6 +4340,14 @@ class Conditional_expression : public Expression condition() const { return this->cond_; } + Expression* + then_expr() const + { return this->then_; } + + Expression* + else_expr() const + { return this->else_; } + protected: int do_traverse(Traverse*); @@ -4322,6 +4393,10 @@ class Compound_expression : public Expression init() const { return this->init_; } + Expression* + expr() const + { return this->expr_; } + protected: int do_traverse(Traverse*); -- cgit v1.1 From ac8a2fbedf59eecda6d1c049952e10946ffc4a61 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 4 Aug 2021 18:24:47 -0400 Subject: compiler: make escape analysis more robust about builtin functions In the places where we handle builtin functions, list all supported ones, and fail if an unexpected one is seen. So if a new builtin function is added in the future we can detect it, instead of silently treating it as nonescaping. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/339992 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/escape.cc | 56 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 3 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index be1a90f..394530c 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -616ee658a6238e7de53592ebda5997f6de6a00de +b47bcf942daa9a0c252db9b57b8f138adbfcdaa2 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/escape.cc b/gcc/go/gofrontend/escape.cc index 347ac25..c8978ac 100644 --- a/gcc/go/gofrontend/escape.cc +++ b/gcc/go/gofrontend/escape.cc @@ -1608,8 +1608,33 @@ Escape_analysis_assign::expression(Expression** pexpr) } break; - default: + case Builtin_call_expression::BUILTIN_CLOSE: + case Builtin_call_expression::BUILTIN_DELETE: + case Builtin_call_expression::BUILTIN_PRINT: + case Builtin_call_expression::BUILTIN_PRINTLN: + case Builtin_call_expression::BUILTIN_LEN: + case Builtin_call_expression::BUILTIN_CAP: + case Builtin_call_expression::BUILTIN_COMPLEX: + case Builtin_call_expression::BUILTIN_REAL: + case Builtin_call_expression::BUILTIN_IMAG: + case Builtin_call_expression::BUILTIN_RECOVER: + case Builtin_call_expression::BUILTIN_ALIGNOF: + case Builtin_call_expression::BUILTIN_OFFSETOF: + case Builtin_call_expression::BUILTIN_SIZEOF: + // these do not escape. + break; + + case Builtin_call_expression::BUILTIN_ADD: + case Builtin_call_expression::BUILTIN_SLICE: + // handled in ::assign. break; + + case Builtin_call_expression::BUILTIN_MAKE: + case Builtin_call_expression::BUILTIN_NEW: + // should have been lowered to runtime calls at this point. + // fallthrough + default: + go_unreachable(); } break; } @@ -2372,8 +2397,35 @@ Escape_analysis_assign::assign(Node* dst, Node* src) } break; - default: + case Builtin_call_expression::BUILTIN_LEN: + case Builtin_call_expression::BUILTIN_CAP: + case Builtin_call_expression::BUILTIN_COMPLEX: + case Builtin_call_expression::BUILTIN_REAL: + case Builtin_call_expression::BUILTIN_IMAG: + case Builtin_call_expression::BUILTIN_RECOVER: + case Builtin_call_expression::BUILTIN_ALIGNOF: + case Builtin_call_expression::BUILTIN_OFFSETOF: + case Builtin_call_expression::BUILTIN_SIZEOF: + // these do not escape. + break; + + case Builtin_call_expression::BUILTIN_COPY: + // handled in ::expression. break; + + case Builtin_call_expression::BUILTIN_CLOSE: + case Builtin_call_expression::BUILTIN_DELETE: + case Builtin_call_expression::BUILTIN_PRINT: + case Builtin_call_expression::BUILTIN_PRINTLN: + case Builtin_call_expression::BUILTIN_PANIC: + // these do not have result. + // fallthrough + case Builtin_call_expression::BUILTIN_MAKE: + case Builtin_call_expression::BUILTIN_NEW: + // should have been lowered to runtime calls at this point. + // fallthrough + default: + go_unreachable(); } break; } -- cgit v1.1 From 582c24e9fe81f75684892de0bf580e6918695dd9 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 3 Aug 2021 16:22:48 -0700 Subject: runtime: extend internal atomics to comply with sync/atomic This is the gofrontend version of https://golang.org/cl/289152. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/339690 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 48 +++++++++++++++++++--------------------- 2 files changed, 24 insertions(+), 26 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 394530c..19ab2de 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -b47bcf942daa9a0c252db9b57b8f138adbfcdaa2 +32590102c464679f845667b5554e1dcce2549ad2 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 3e433d6..33177a7 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -11590,12 +11590,10 @@ Call_expression::intrinsify(Gogo* gogo, // 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. - // In case there is no equivalent functions (slight variance - // in types), we just make an artificial name (begin with '$'). // Note: no StorePointer, SwapPointer, and CompareAndSwapPointer, // as they need write barriers. if (name == "LoadInt32") - name = "$Loadint32"; + name = "Loadint32"; else if (name == "LoadInt64") name = "Loadint64"; else if (name == "LoadUint32") @@ -11607,9 +11605,9 @@ Call_expression::intrinsify(Gogo* gogo, else if (name == "LoadPointer") name = "Loadp"; else if (name == "StoreInt32") - name = "$Storeint32"; + name = "Storeint32"; else if (name == "StoreInt64") - name = "$Storeint64"; + name = "Storeint64"; else if (name == "StoreUint32") name = "Store"; else if (name == "StoreUint64") @@ -11617,7 +11615,7 @@ Call_expression::intrinsify(Gogo* gogo, else if (name == "StoreUintptr") name = "Storeuintptr"; else if (name == "AddInt32") - name = "$Xaddint32"; + name = "Xaddint32"; else if (name == "AddInt64") name = "Xaddint64"; else if (name == "AddUint32") @@ -11627,9 +11625,9 @@ Call_expression::intrinsify(Gogo* gogo, else if (name == "AddUintptr") name = "Xadduintptr"; else if (name == "SwapInt32") - name = "$Xchgint32"; + name = "Xchgint32"; else if (name == "SwapInt64") - name = "$Xchgint64"; + name = "Xchgint64"; else if (name == "SwapUint32") name = "Xchg"; else if (name == "SwapUint64") @@ -11637,9 +11635,9 @@ Call_expression::intrinsify(Gogo* gogo, else if (name == "SwapUintptr") name = "Xchguintptr"; else if (name == "CompareAndSwapInt32") - name = "$Casint32"; + name = "Casint32"; else if (name == "CompareAndSwapInt64") - name = "$Casint64"; + name = "Casint64"; else if (name == "CompareAndSwapUint32") name = "Cas"; else if (name == "CompareAndSwapUint64") @@ -11875,7 +11873,7 @@ Call_expression::intrinsify(Gogo* gogo, if ((name == "Load" || name == "Load64" || name == "Loadint64" || name == "Loadp" || name == "Loaduint" || name == "Loaduintptr" || name == "LoadAcq" - || name == "$Loadint32") + || name == "Loadint32") && this->args_ != NULL && this->args_->size() == 1) { if (int_size < 8 && (name == "Load64" || name == "Loadint64")) @@ -11895,7 +11893,7 @@ Call_expression::intrinsify(Gogo* gogo, code = Runtime::ATOMIC_LOAD_8; res_type = uint64_type; } - else if (name == "$Loadint32") + else if (name == "Loadint32") { code = Runtime::ATOMIC_LOAD_4; res_type = int32_type; @@ -11942,10 +11940,10 @@ Call_expression::intrinsify(Gogo* gogo, if ((name == "Store" || name == "Store64" || name == "StorepNoWB" || name == "Storeuintptr" || name == "StoreRel" - || name == "$Storeint32" || name == "$Storeint64") + || name == "Storeint32" || name == "Storeint64") && this->args_ != NULL && this->args_->size() == 2) { - if (int_size < 8 && (name == "Store64" || name == "$Storeint64")) + if (int_size < 8 && (name == "Store64" || name == "Storeint64")) return NULL; Runtime::Function code; @@ -11955,9 +11953,9 @@ Call_expression::intrinsify(Gogo* gogo, code = Runtime::ATOMIC_STORE_4; else if (name == "Store64") code = Runtime::ATOMIC_STORE_8; - else if (name == "$Storeint32") + else if (name == "Storeint32") code = Runtime::ATOMIC_STORE_4; - else if (name == "$Storeint64") + else if (name == "Storeint64") code = Runtime::ATOMIC_STORE_8; else if (name == "Storeuintptr") code = (ptr_size == 8 ? Runtime::ATOMIC_STORE_8 : Runtime::ATOMIC_STORE_4); @@ -11979,7 +11977,7 @@ Call_expression::intrinsify(Gogo* gogo, } if ((name == "Xchg" || name == "Xchg64" || name == "Xchguintptr" - || name == "$Xchgint32" || name == "$Xchgint64") + || name == "Xchgint32" || name == "Xchgint64") && this->args_ != NULL && this->args_->size() == 2) { if (int_size < 8 && (name == "Xchg64" || name == "Xchgint64")) @@ -11997,12 +11995,12 @@ Call_expression::intrinsify(Gogo* gogo, code = Runtime::ATOMIC_EXCHANGE_8; res_type = uint64_type; } - else if (name == "$Xchgint32") + else if (name == "Xchgint32") { code = Runtime::ATOMIC_EXCHANGE_4; res_type = int32_type; } - else if (name == "$Xchgint64") + else if (name == "Xchgint64") { code = Runtime::ATOMIC_EXCHANGE_8; res_type = int64_type; @@ -12025,10 +12023,10 @@ Call_expression::intrinsify(Gogo* gogo, if ((name == "Cas" || name == "Cas64" || name == "Casuintptr" || name == "Casp1" || name == "CasRel" - || name == "$Casint32" || name == "$Casint64") + || name == "Casint32" || name == "Casint64") && this->args_ != NULL && this->args_->size() == 3) { - if (int_size < 8 && (name == "Cas64" || name == "$Casint64")) + if (int_size < 8 && (name == "Cas64" || name == "Casint64")) return NULL; Runtime::Function code; @@ -12047,9 +12045,9 @@ Call_expression::intrinsify(Gogo* gogo, code = Runtime::ATOMIC_COMPARE_EXCHANGE_4; else if (name == "Cas64") code = Runtime::ATOMIC_COMPARE_EXCHANGE_8; - else if (name == "$Casint32") + else if (name == "Casint32") code = Runtime::ATOMIC_COMPARE_EXCHANGE_4; - else if (name == "$Casint64") + else if (name == "Casint64") code = Runtime::ATOMIC_COMPARE_EXCHANGE_8; else if (name == "Casuintptr") code = (ptr_size == 8 @@ -12077,7 +12075,7 @@ Call_expression::intrinsify(Gogo* gogo, } if ((name == "Xadd" || name == "Xadd64" || name == "Xaddint64" - || name == "Xadduintptr" || name == "$Xaddint32") + || name == "Xadduintptr" || name == "Xaddint32") && this->args_ != NULL && this->args_->size() == 2) { if (int_size < 8 && (name == "Xadd64" || name == "Xaddint64")) @@ -12095,7 +12093,7 @@ Call_expression::intrinsify(Gogo* gogo, code = Runtime::ATOMIC_ADD_FETCH_8; res_type = uint64_type; } - else if (name == "$Xaddint32") + else if (name == "Xaddint32") { code = Runtime::ATOMIC_ADD_FETCH_4; res_type = int32_type; -- cgit v1.1 From 629b5699fb555b30c25ebc0b503e87b470bed076 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 6 Aug 2021 11:03:47 -0400 Subject: compiler: make escape analysis more strict about runtime calls Following the previous CL, in the escape analysis list all the expected runtime calls, and fail if an unexpected one is seen. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/340397 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/escape.cc | 47 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 2 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 19ab2de..9ed527f 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -32590102c464679f845667b5554e1dcce2549ad2 +747f3a2d78c073e9b03dd81914d0edb7ddc5be14 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/escape.cc b/gcc/go/gofrontend/escape.cc index c8978ac..6da29ed 100644 --- a/gcc/go/gofrontend/escape.cc +++ b/gcc/go/gofrontend/escape.cc @@ -1646,6 +1646,7 @@ Escape_analysis_assign::expression(Expression** pexpr) case Runtime::MAKECHAN: case Runtime::MAKECHAN64: case Runtime::MAKEMAP: + case Runtime::MAKEMAP64: case Runtime::MAKESLICE: case Runtime::MAKESLICE64: this->context_->track(n); @@ -1705,8 +1706,52 @@ Escape_analysis_assign::expression(Expression** pexpr) } break; + case Runtime::MEMCMP: + case Runtime::DECODERUNE: + case Runtime::INTSTRING: + case Runtime::MAKEMAP_SMALL: + case Runtime::MAPACCESS1: + case Runtime::MAPACCESS1_FAST32: + case Runtime::MAPACCESS1_FAST64: + case Runtime::MAPACCESS1_FASTSTR: + case Runtime::MAPACCESS1_FAT: + case Runtime::MAPACCESS2: + case Runtime::MAPACCESS2_FAST32: + case Runtime::MAPACCESS2_FAST64: + case Runtime::MAPACCESS2_FASTSTR: + case Runtime::MAPACCESS2_FAT: + case Runtime::MAPASSIGN_FAST32: + case Runtime::MAPASSIGN_FAST64: + case Runtime::MAPITERINIT: + case Runtime::MAPITERNEXT: + case Runtime::MAPCLEAR: + case Runtime::CHANRECV2: + case Runtime::SELECTGO: + case Runtime::SELECTNBSEND: + case Runtime::SELECTNBRECV: + case Runtime::BLOCK: + case Runtime::IFACET2IP: + case Runtime::EQTYPE: + case Runtime::MEMCLRHASPTR: + case Runtime::FIELDTRACK: + case Runtime::BUILTIN_MEMSET: + case Runtime::PANIC_SLICE_CONVERT: + // these do not escape. + break; + + case Runtime::IFACEE2E2: + case Runtime::IFACEI2E2: + case Runtime::IFACEE2I2: + case Runtime::IFACEI2I2: + case Runtime::IFACEE2T2P: + case Runtime::IFACEI2T2P: + // handled in ::assign. + break; + default: - break; + // should not see other runtime calls. they are not yet + // lowered to runtime calls at this point. + go_unreachable(); } } else -- cgit v1.1 From 307e0d40367996031e9b734ba0ab44ff0b290c79 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 6 Aug 2021 12:01:04 -0700 Subject: compiler: support export/import of unsafe.Add/Slice For golang/go#19367 For golang/go#40481 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/340549 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/export.cc | 44 +++++++++++++++++++++++++-- gcc/go/gofrontend/export.h | 10 +++++++ gcc/go/gofrontend/expressions.cc | 8 +++++ gcc/go/gofrontend/expressions.h | 21 +++++++++++-- gcc/go/gofrontend/gogo.h | 4 +++ gcc/go/gofrontend/import.cc | 6 ++++ gcc/go/gofrontend/unsafe.cc | 64 +++++++++++++++++++++++++--------------- 8 files changed, 130 insertions(+), 29 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 9ed527f..b983fda 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -747f3a2d78c073e9b03dd81914d0edb7ddc5be14 +d5d51242efc432fa62d4e9b141b01c280af32d19 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 e99c680..3d11334 100644 --- a/gcc/go/gofrontend/export.cc +++ b/gcc/go/gofrontend/export.cc @@ -106,11 +106,12 @@ class Collect_export_references : public Traverse { public: Collect_export_references(Export* exp, + const std::map& packages, Unordered_set(Named_object*)* exports, Unordered_set(const Package*)* imports) : Traverse(traverse_expressions | traverse_types), - exp_(exp), exports_(exports), imports_(imports), + exp_(exp), packages_(packages), exports_(exports), imports_(imports), inline_fcn_worklist_(NULL), exports_finalized_(false) { } @@ -150,6 +151,8 @@ class Collect_export_references : public Traverse // The exporter. Export* exp_; + // The list of packages known to this compilation. + const std::map& packages_; // The set of named objects to export. Unordered_set(Named_object*)* exports_; // Set containing all directly and indirectly imported packages. @@ -257,6 +260,24 @@ Collect_export_references::expression(Expression** pexpr) return TRAVERSE_CONTINUE; } + const Call_expression* call = expr->call_expression(); + if (call != NULL) + { + const Builtin_call_expression* bce = call->builtin_call_expression(); + if (bce != NULL + && (bce->code() == Builtin_call_expression::BUILTIN_ADD + || bce->code() == Builtin_call_expression::BUILTIN_SLICE)) + { + // This is a reference to unsafe.Add or unsafe.Slice. Make + // sure we list the "unsafe" package in the imports and give + // it a package index. + const std::map::const_iterator p = + this->packages_.find("unsafe"); + go_assert(p != this->packages_.end()); + this->imports_->insert(p->second); + } + } + return TRAVERSE_CONTINUE; } @@ -589,7 +610,7 @@ Export::export_globals(const std::string& package_name, // Track all imported packages mentioned in export data. Unordered_set(const Package*) all_imports; - Collect_export_references collect(this, &exports, &all_imports); + Collect_export_references collect(this, packages, &exports, &all_imports); // Walk the set of inlinable routine bodies collected above. This // can potentially expand the exports set. @@ -1274,6 +1295,25 @@ Export::package_index(const Package* pkg) const return index; } +// Return the index of the "unsafe" package. + +int +Export::unsafe_package_index() const +{ + for (Unordered_map(const Package*, int)::const_iterator p = + this->packages_.begin(); + p != this->packages_.end(); + ++p) + { + if (p->first->pkgpath() == "unsafe") + { + go_assert(p->second != 0); + return p->second; + } + } + go_unreachable(); +} + // Return the index of a type. int diff --git a/gcc/go/gofrontend/export.h b/gcc/go/gofrontend/export.h index c93bced..1f61343 100644 --- a/gcc/go/gofrontend/export.h +++ b/gcc/go/gofrontend/export.h @@ -216,6 +216,11 @@ class Export : public String_dump int package_index(const Package* p) const; + // Return the index of the "unsafe" package, which must be one of + // the exported packages. + int + unsafe_package_index() const; + private: Export(const Export&); Export& operator=(const Export&); @@ -377,6 +382,11 @@ class Export_function_body : public String_dump package_index(const Package* p) const { return this->exp_->package_index(p); } + // Return the index of the "unsafe" package. + int + unsafe_package_index() const + { return this->exp_->unsafe_package_index(); } + // Record a temporary statement and return its index. unsigned int record_temporary(const Temporary_statement*); diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 33177a7..f462b0e 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -11039,6 +11039,14 @@ Builtin_call_expression::do_export(Export_function_body* efb) const // A trailing space lets us reliably identify the end of the number. efb->write_c_string(" "); } + else if (this->code_ == BUILTIN_ADD || this->code_ == BUILTIN_SLICE) + { + char buf[50]; + snprintf(buf, sizeof buf, "%s", efb->unsafe_package_index(), + (this->code_ == BUILTIN_ADD ? "Add" : "Slice")); + efb->write_c_string(buf); + this->export_arguments(efb); + } else { const char *s = NULL; diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 79a8785..9f8f4e9 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -732,6 +732,10 @@ class Expression call_expression() { return this->convert(); } + const Call_expression* + call_expression() const + { return this->convert(); } + // If this is a call_result expression, return the Call_result_expression // structure. Otherwise, return NULL. This is a controlled dynamic // cast. @@ -2460,13 +2464,16 @@ class Call_expression : public Expression // Whether this is a call to builtin function. virtual bool - is_builtin() + is_builtin() const { return false; } // Convert to a Builtin_call_expression, or return NULL. inline Builtin_call_expression* builtin_call_expression(); + inline const Builtin_call_expression* + builtin_call_expression() const; + protected: int do_traverse(Traverse*); @@ -2625,12 +2632,12 @@ class Builtin_call_expression : public Call_expression }; Builtin_function_code - code() + code() const { return this->code_; } // This overrides Call_expression::is_builtin. bool - is_builtin() + is_builtin() const { return true; } // Return whether EXPR, of array type, is a constant if passed to @@ -2726,6 +2733,14 @@ Call_expression::builtin_call_expression() : NULL); } +inline const Builtin_call_expression* +Call_expression::builtin_call_expression() const +{ + return (this->is_builtin() + ? static_cast(this) + : NULL); +} + // A single result from a call which returns multiple results. class Call_result_expression : public Expression diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index c49bc92..9ffd120 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -533,6 +533,10 @@ class Gogo register_package(const std::string& pkgpath, const std::string& pkgpath_symbol, Location); + // Add the unsafe bindings to the unsafe package. + void + add_unsafe_bindings(Package*); + // Look up a package by pkgpath, and return its pkgpath_symbol. std::string pkgpath_symbol_for_package(const std::string&); diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc index f671416..6a5491b 100644 --- a/gcc/go/gofrontend/import.cc +++ b/gcc/go/gofrontend/import.cc @@ -497,6 +497,9 @@ Import::read_one_import() p->set_package_name(package_name, this->location()); this->packages_.push_back(p); + + if (pkgpath == "unsafe") + this->gogo_->add_unsafe_bindings(p); } // Read an indirectimport line. @@ -515,6 +518,9 @@ Import::read_one_indirect_import() p->set_package_name(package_name, this->location()); this->packages_.push_back(p); + + if (pkgpath == "unsafe") + this->gogo_->add_unsafe_bindings(p); } // Read the list of import control functions and/or init graph. diff --git a/gcc/go/gofrontend/unsafe.cc b/gcc/go/gofrontend/unsafe.cc index 18bd99e..c4a9346 100644 --- a/gcc/go/gofrontend/unsafe.cc +++ b/gcc/go/gofrontend/unsafe.cc @@ -10,15 +10,12 @@ #include "types.h" #include "gogo.h" -// Set up the builtin unsafe package. This should probably be driven -// by a table. +// Set up the builtin unsafe package. void Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported, Location location) { - Location bloc = Linemap::predeclared_location(); - bool add_to_globals; Package* package = this->add_imported_package("unsafe", local_name, is_local_name_exported, @@ -34,10 +31,40 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported, package->set_location(location); this->imports_.insert(std::make_pair("unsafe", package)); + this->add_unsafe_bindings(package); + + Named_object* pointer_no = package->bindings()->lookup_local("Pointer"); + pointer_no->type_value()->set_is_visible(); + + if (add_to_globals) + { + Bindings* bindings = package->bindings(); + for (Bindings::const_declarations_iterator p = + bindings->begin_declarations(); + p != bindings->end_declarations(); + ++p) + this->add_dot_import_object(p->second); + } +} + +// Add the unsafe bindings to the Package object. This should +// probably be driven by a table. + +void +Gogo::add_unsafe_bindings(Package* package) +{ Bindings* bindings = package->bindings(); + if (bindings->lookup_local("Sizeof") != NULL) + { + // Already done by an earlier import. + return; + } + + Location bloc = Linemap::predeclared_location(); + // The type may have already been created by an import. - Named_object* no = package->bindings()->lookup("Pointer"); + Named_object* no = bindings->lookup("Pointer"); if (no == NULL) { Type* type = Type::make_pointer_type(Type::make_void_type()); @@ -49,11 +76,12 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported, go_assert(no->package() == package); go_assert(no->is_type()); go_assert(no->type_value()->is_unsafe_pointer_type()); - no->type_value()->set_is_visible(); } Named_type* pointer_type = no->type_value(); - if (add_to_globals) - this->add_named_type(pointer_type); + + // This may be called during an import, so the type may not be + // visible yet. + pointer_type->clear_is_visible(); Type* uintptr_type = Type::lookup_integer_type("uintptr"); @@ -62,9 +90,7 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported, results->push_back(Typed_identifier("", uintptr_type, bloc)); Function_type* fntype = Type::make_function_type(NULL, NULL, results, bloc); fntype->set_is_builtin(); - no = bindings->add_function_declaration("Sizeof", package, fntype, bloc); - if (add_to_globals) - this->add_dot_import_object(no); + bindings->add_function_declaration("Sizeof", package, fntype, bloc); // Offsetof. results = new Typed_identifier_list; @@ -72,9 +98,7 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported, fntype = Type::make_function_type(NULL, NULL, results, bloc); fntype->set_is_varargs(); fntype->set_is_builtin(); - no = bindings->add_function_declaration("Offsetof", package, fntype, bloc); - if (add_to_globals) - this->add_dot_import_object(no); + bindings->add_function_declaration("Offsetof", package, fntype, bloc); // Alignof. results = new Typed_identifier_list; @@ -82,25 +106,19 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported, fntype = Type::make_function_type(NULL, NULL, results, bloc); fntype->set_is_varargs(); fntype->set_is_builtin(); - no = bindings->add_function_declaration("Alignof", package, fntype, bloc); - if (add_to_globals) - this->add_dot_import_object(no); + bindings->add_function_declaration("Alignof", package, fntype, bloc); // Add. results = new Typed_identifier_list; results->push_back(Typed_identifier("", pointer_type, bloc)); fntype = Type::make_function_type(NULL, NULL, results, bloc); fntype->set_is_builtin(); - no = bindings->add_function_declaration("Add", package, fntype, bloc); - if (add_to_globals) - this->add_dot_import_object(no); + bindings->add_function_declaration("Add", package, fntype, bloc); // Slice. fntype = Type::make_function_type(NULL, NULL, NULL, bloc); fntype->set_is_builtin(); - no = bindings->add_function_declaration("Slice", package, fntype, bloc); - if (add_to_globals) - this->add_dot_import_object(no); + bindings->add_function_declaration("Slice", package, fntype, bloc); if (!this->imported_unsafe_) { -- cgit v1.1 From fed7c1634e8e50600e20cb97dbfbd74ecbd5ba22 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 10 Aug 2021 16:13:01 -0700 Subject: compiler: don't crash on a, b := int(0) Fixes PR go/101851 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/341330 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index b983fda..be092de 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -d5d51242efc432fa62d4e9b141b01c280af32d19 +7e092d2cc5af7648036496485b639f2c9db2f2d8 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 f462b0e..67917da 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -11202,12 +11202,23 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, { Location loc = this->location(); + if (this->is_error_expression()) + return Expression::make_error(loc); + // A type cast can look like a function call. if (this->fn_->is_type_expression() && this->args_ != NULL && this->args_->size() == 1) - return Expression::make_cast(this->fn_->type(), this->args_->front(), - loc); + { + if (this->expected_result_count_ != 0 + && this->expected_result_count_ != 1) + { + this->report_error(_("type conversion result count mismatch")); + return Expression::make_error(loc); + } + return Expression::make_cast(this->fn_->type(), this->args_->front(), + loc); + } // Because do_type will return an error type and thus prevent future // errors, check for that case now to ensure that the error gets -- cgit v1.1 From 1196b60f8fc5a169e01ac859712013a4d3d8de96 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 6 Aug 2021 18:04:43 -0700 Subject: compiler: store pointers to go:notinheap types indirectly This is the gofrontend version of https://golang.org/cl/264480. For golang/go#42076 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/340609 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 30 ++++++++++++---- gcc/go/gofrontend/types.cc | 75 +++++++++++++++++++++++++++++++++++----- gcc/go/gofrontend/types.h | 3 +- 4 files changed, 92 insertions(+), 18 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index be092de..539d886 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -7e092d2cc5af7648036496485b639f2c9db2f2d8 +5edbb624b2595d644eb6842c952a292c41f7d6fa 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 67917da..8d4d168 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -408,7 +408,14 @@ Expression::convert_type_to_interface(Type* lhs_type, Expression* rhs, { // We are assigning a non-pointer value to the interface; the // interface gets a copy of the value in the heap if it escapes. - if (rhs->is_constant()) + + // An exception is &global if global is notinheap, which is a + // pointer value but not a direct-iface type and we can't simply + // take its address. + bool is_address = (rhs->unary_expression() != NULL + && rhs->unary_expression()->op() == OPERATOR_AND); + + if (rhs->is_constant() && !is_address) obj = Expression::make_unary(OPERATOR_AND, rhs, location); else { @@ -11331,6 +11338,7 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, // We always pass a pointer when calling a method, except for // direct interface types when calling a value method. if (!first_arg->type()->is_error() + && first_arg->type()->points_to() == NULL && !first_arg->type()->is_direct_iface_type()) { first_arg = Expression::make_unary(OPERATOR_AND, first_arg, loc); @@ -18630,12 +18638,20 @@ Interface_mtable_expression::do_get_backend(Translate_context* context) else m = st->method_function(p->name(), &is_ambiguous); go_assert(m != NULL); - Named_object* no = - (this->is_pointer_ - && this->type_->is_direct_iface_type() - && m->is_value_method() - ? m->iface_stub_object() - : m->named_object()); + + // See the comment in Type::method_constructor. + bool use_direct_iface_stub = false; + if (m->is_value_method() + && this->is_pointer_ + && this->type_->is_direct_iface_type()) + use_direct_iface_stub = true; + if (!m->is_value_method() + && this->is_pointer_ + && !this->type_->in_heap()) + use_direct_iface_stub = true; + Named_object* no = (use_direct_iface_stub + ? m->iface_stub_object() + : m->named_object()); go_assert(no->is_function() || no->is_function_declaration()); diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 0c44186..e76600d 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -2464,8 +2464,16 @@ Type::is_direct_iface_type() const bool Type::is_direct_iface_type_helper(Unordered_set(const Type*)* visited) const { - if (this->points_to() != NULL - || this->channel_type() != NULL + if (this->points_to() != NULL) + { + // Pointers to notinheap types must be stored indirectly. See + // https://golang.org/issue/42076. + if (!this->points_to()->in_heap()) + return false; + return true; + } + + if (this->channel_type() != NULL || this->function_type() != NULL || this->map_type() != NULL) return true; @@ -3597,10 +3605,36 @@ Type::method_constructor(Gogo*, Type* method_type, vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc)); } - bool use_direct_iface_stub = - this->points_to() != NULL - && this->points_to()->is_direct_iface_type() - && m->is_value_method(); + // The direct_iface_stub dereferences the value stored in the + // interface when calling the method. + // + // We need this for a value method if this type is a pointer to a + // direct-iface type. For example, if we have "type C chan int" and M + // is a value method on C, then since a channel is a direct-iface type + // M expects a value of type C. We are generating the method table + // for *C, so the value stored in the interface is *C. We have to + // call the direct-iface stub to dereference *C to get C to pass to M. + // + // We also need this for a pointer method if the pointer itself is not + // a direct-iface type, as arises for notinheap types. In this case + // we have "type NIH ..." where NIH is go:notinheap. Since NIH is + // notinheap, *NIH is a pointer type that is not a direct-iface type, + // so the value stored in the interface is actually **NIH. The method + // expects *NIH, so we have to call the direct-iface stub to + // dereference **NIH to get *NIH to pass to M. (This case doesn't + // arise for value methods because pointer types can't have methods, + // so there is no such thing as a value method for type *NIH.) + + bool use_direct_iface_stub = false; + if (m->is_value_method() + && this->points_to() != NULL + && this->points_to()->is_direct_iface_type()) + use_direct_iface_stub = true; + if (!m->is_value_method() + && this->points_to() != NULL + && !this->is_direct_iface_type()) + use_direct_iface_stub = true; + Named_object* no = (use_direct_iface_stub ? m->iface_stub_object() : (m->needs_stub_method() @@ -10902,6 +10936,20 @@ Named_type::do_needs_key_update() return ret; } +// Return whether this type is permitted in the heap. +bool +Named_type::do_in_heap() const +{ + if (!this->in_heap_) + return false; + if (this->seen_) + return true; + this->seen_ = true; + bool ret = this->type_->in_heap(); + this->seen_ = false; + return ret; +} + // Return a hash code. This is used for method lookup. We simply // hash on the name itself. @@ -11434,7 +11482,7 @@ Type::finalize_methods(Gogo* gogo, const Type* type, Location location, *all_methods = NULL; } Type::build_stub_methods(gogo, type, *all_methods, location); - if (type->is_direct_iface_type()) + if (type->is_direct_iface_type() || !type->in_heap()) Type::build_direct_iface_stub_methods(gogo, type, *all_methods, location); } @@ -11814,12 +11862,23 @@ Type::build_direct_iface_stub_methods(Gogo* gogo, const Type* type, if (methods == NULL) return; + bool is_direct_iface = type->is_direct_iface_type(); + bool in_heap = type->in_heap(); for (Methods::const_iterator p = methods->begin(); p != methods->end(); ++p) { Method* m = p->second; - if (!m->is_value_method()) + + // We need a direct-iface stub for a value method for a + // direct-iface type, and for a pointer method for a not-in-heap + // type. + bool need_stub = false; + if (is_direct_iface && m->is_value_method()) + need_stub = true; + if (!in_heap && !m->is_value_method()) + need_stub = true; + if (!need_stub) continue; Type* receiver_type = const_cast(type); diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index f2880f9..ca1ab49 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -3605,8 +3605,7 @@ class Named_type : public Type do_needs_key_update(); bool - do_in_heap() const - { return this->in_heap_ && this->type_->in_heap(); } + do_in_heap() const; unsigned int do_hash_for_method(Gogo*, int) const; -- cgit v1.1 From c5b21c3f4c17b0649155035d2f9aa97b2da8a813 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 30 Jul 2021 14:28:58 -0700 Subject: libgo: update to Go1.17rc2 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/341629 --- gcc/go/gofrontend/MERGE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 539d886..bcbe1d9 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -5edbb624b2595d644eb6842c952a292c41f7d6fa +33f65dce43bd01c1fa38cd90a78c9aea6ca6dd59 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. -- cgit v1.1 From e5c00544cce1feb2c8c4e9aad766315d389c69c4 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 13 Aug 2021 10:15:45 -0700 Subject: runtime: use C cast syntax in stack.c Didn't notice earlier because this code is only used on systems that do not support -fsplit-stack. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/342051 --- gcc/go/gofrontend/MERGE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index bcbe1d9..3000285 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -33f65dce43bd01c1fa38cd90a78c9aea6ca6dd59 +f2b7a2ce94127ad444a772bd1631516c5c67fb73 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. -- cgit v1.1 From 829931ec93ab7d5ab73f31be9da504abb6ae459e Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 13 Aug 2021 17:21:54 -0700 Subject: libgo: various fixes for Solaris support Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/342189 --- gcc/go/gofrontend/MERGE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 3000285..950f179 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -f2b7a2ce94127ad444a772bd1631516c5c67fb73 +77bc32767b61feb6499ca7921e96b356603517dc The first line of this file holds the git revision number of the last merge done from the gofrontend repository. -- cgit v1.1 From 74df79ec3e0a1af87e2619fc07533aba58680f0a Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 19 Aug 2021 12:29:54 -0700 Subject: libgo: update to final Go 1.17 release Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/343729 --- gcc/go/gofrontend/MERGE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 950f179..e9f38d4 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -77bc32767b61feb6499ca7921e96b356603517dc +b3fad6957a04520013197ea7cab11bec3298d552 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. -- cgit v1.1 From 21b046bade1c2666b82139d18c8b318bb051415e Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 7 Sep 2021 14:37:55 -0700 Subject: runtime: use hash32, not hash64, for amd64p32, mips64p32, mips64p32le Fixes PR go/102102 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/348015 --- gcc/go/gofrontend/MERGE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index e9f38d4..c377269 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -b3fad6957a04520013197ea7cab11bec3298d552 +e42c7c0216aec70834e8827174458aa4a50169fa The first line of this file holds the git revision number of the last merge done from the gofrontend repository. -- cgit v1.1 From b7f84702b364d49824ca97d4a2fc01567301d784 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sat, 21 Aug 2021 12:42:19 -0700 Subject: compiler: correct condition for calling memclrHasPointers When compiling append(s, make([]typ, ln)...), where typ has a pointer, and the append fits within the existing capacity of s, the condition used to clear out the new elements was reversed. Fixes golang/go#47771 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/344189 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index c377269..ff41af7 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -e42c7c0216aec70834e8827174458aa4a50169fa +21b30eddc59d92a07264c3b21eb032d6c303d16f 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 8d4d168..ddb1d91 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -9350,7 +9350,7 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function, ref2 = Expression::make_cast(uint_type, ref2, loc); cond = Expression::make_binary(OPERATOR_GT, ref, ref2, loc); zero = Expression::make_integer_ul(0, int_type, loc); - call = Expression::make_conditional(cond, call, zero, loc); + call = Expression::make_conditional(cond, zero, call, loc); } } else -- cgit v1.1 From 79513dc0b2d980bfd1b109d0d502de487c02b894 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 20 Aug 2021 11:33:29 -0700 Subject: compiler: don't pad zero-sized trailing field in results struct Nothing can take the address of that field anyhow. Fixes PR go/101994 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/343873 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/types.cc | 3 ++- gcc/go/gofrontend/types.h | 17 ++++++++++++++++- 3 files changed, 19 insertions(+), 3 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index ff41af7..f481681 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -21b30eddc59d92a07264c3b21eb032d6c303d16f +c11d9f8275f2bbe9b05cdd815c79ac331f78e15c 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/types.cc b/gcc/go/gofrontend/types.cc index e76600d..cd69250 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -5050,6 +5050,7 @@ Function_type::get_backend_fntype(Gogo* gogo) Struct_type* st = Type::make_struct_type(sfl, this->location()); st->set_is_struct_incomparable(); + st->set_is_results_struct(); ins.first->second = st->get_backend(gogo); } bresult_struct = ins.first->second; @@ -6458,7 +6459,7 @@ get_backend_struct_fields(Gogo* gogo, Struct_type* type, bool use_placeholder, saw_nonzero = true; } go_assert(i == fields->size()); - if (saw_nonzero && lastsize == 0) + if (saw_nonzero && lastsize == 0 && !type->is_results_struct()) { // For nonzero-sized structs which end in a zero-sized thing, we add // an extra byte of padding to the type. This padding ensures that diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index ca1ab49..0c51806 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -2501,7 +2501,8 @@ class Struct_type : public Type Struct_type(Struct_field_list* fields, Location location) : Type(TYPE_STRUCT), fields_(fields), location_(location), all_methods_(NULL), - is_struct_incomparable_(false), has_padding_(false) + is_struct_incomparable_(false), has_padding_(false), + is_results_struct_(false) { } // Return the field NAME. This only looks at local fields, not at @@ -2632,6 +2633,17 @@ class Struct_type : public Type set_has_padding() { this->has_padding_ = true; } + // Return whether this is a results struct created to hold the + // results of a function that returns multiple results. + bool + is_results_struct() const + { return this->is_results_struct_; } + + // Record that this is a results struct. + void + set_is_results_struct() + { this->is_results_struct_ = true; } + // Write the hash function for this type. void write_hash_function(Gogo*, Function_type*); @@ -2742,6 +2754,9 @@ class Struct_type : public Type // True if this struct's backend type has padding, due to trailing // zero-sized field. bool has_padding_; + // True if this is a results struct created to hold the results of a + // function that returns multiple results. + bool is_results_struct_; }; // The type of an array. -- cgit v1.1