https://gcc.gnu.org/g:f7a08611ee6eea1d76c10013e42974cd0c314d74
commit r16-6690-gf7a08611ee6eea1d76c10013e42974cd0c314d74 Author: Michal Jires <[email protected]> Date: Thu Jan 8 01:40:07 2026 +0100 lto: Stream toplevel extended assembly Streaming of toplevel extended assembly was missing implementation. Streaming must be after merging of decls, otherwise we would have to fix the pointers to new decls. gcc/ChangeLog: * ipa-free-lang-data.cc (find_decls_types_in_asm): New. (free_lang_data_in_cgraph): Use find_decls_types_in_asm. * lto-cgraph.cc (input_cgraph_1): Move asm to.. (input_toplevel_asms): ..here. * lto-streamer-in.cc (lto_input_toplevel_asms): Allow extended asm. * lto-streamer-out.cc (lto_output_toplevel_asms): Allow extended asm. (lto_output_toplevel_asms): Allow ASM_EXPR. * lto-streamer.h (input_toplevel_asms): New. gcc/lto/ChangeLog: * lto-common.cc (read_cgraph_and_symbols): Call input_toplevel_asms after decl merging. gcc/testsuite/ChangeLog: * g++.dg/lto/toplevel_asm-0_0.C: New test. Diff: --- gcc/ipa-free-lang-data.cc | 19 +++++++++++++++++++ gcc/lto-cgraph.cc | 15 +++++++++++++-- gcc/lto-streamer-in.cc | 5 +++-- gcc/lto-streamer-out.cc | 26 +++++++++----------------- gcc/lto-streamer.h | 1 + gcc/lto/lto-common.cc | 3 +++ gcc/testsuite/g++.dg/lto/toplevel_asm-0_0.C | 7 +++++++ 7 files changed, 55 insertions(+), 21 deletions(-) diff --git a/gcc/ipa-free-lang-data.cc b/gcc/ipa-free-lang-data.cc index a655a1da5f46..edc4f1aed811 100644 --- a/gcc/ipa-free-lang-data.cc +++ b/gcc/ipa-free-lang-data.cc @@ -1036,6 +1036,19 @@ find_decls_types_in_var (varpool_node *v, class free_lang_data_d *fld) find_decls_types (v->decl, fld); } +/* Find decls and types referenced in asm node N and store them in + FLD->DECLS and FLD->TYPES. + Asm strings are represented as a C/C++/etc. strings. If there is + no other string, we would delete/prune/unify the type and cause + issues in verify_type(tree). + Likely we could just add the string type, but we scan the whole + tree to be sure. */ +static void +find_decls_types_in_asm (asm_node *v, class free_lang_data_d *fld) +{ + find_decls_types (v->asm_str, fld); +} + /* Free language specific information for every operand and expression in every node of the call graph. This process operates in three stages: @@ -1073,6 +1086,12 @@ free_lang_data_in_cgraph (class free_lang_data_d *fld) FOR_EACH_VARIABLE (v) find_decls_types_in_var (v, fld); + /* Find the decls and types in every asm node. + Should only be a string type. */ + for (asm_node* anode = symtab->first_asm_symbol (); anode; + anode = safe_as_a<asm_node*> (anode->next)) + find_decls_types_in_asm (anode, fld); + /* Set the assembler name on every decl found. We need to do this now because free_lang_data_in_decl will invalidate data needed for mangling. This breaks mangling on interdependent decls. */ diff --git a/gcc/lto-cgraph.cc b/gcc/lto-cgraph.cc index 50635f3f8a43..cbb37875b89e 100644 --- a/gcc/lto-cgraph.cc +++ b/gcc/lto-cgraph.cc @@ -1641,8 +1641,6 @@ input_cgraph_1 (struct lto_file_decl_data *file_data, tag = streamer_read_enum (ib, LTO_symtab_tags, LTO_symtab_last_tag); } - lto_input_toplevel_asms (file_data, file_data->order_base); - /* AUX pointers should be all non-zero for function nodes read from the stream. */ if (flag_checking) { @@ -1860,6 +1858,19 @@ input_symtab (void) } } +/* Input toplevel asms from each of the .o files passed to lto1. + Must be called after merging of decls. */ +void +input_toplevel_asms (void) +{ + struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data (); + struct lto_file_decl_data *file_data; + unsigned int j = 0; + + while ((file_data = file_data_vec[j++])) + lto_input_toplevel_asms (file_data, file_data->order_base); +} + static void omp_requires_to_name (char *buf, size_t size, HOST_WIDE_INT requires_mask) { diff --git a/gcc/lto-streamer-in.cc b/gcc/lto-streamer-in.cc index 6261b37f9afa..9659d4aa532e 100644 --- a/gcc/lto-streamer-in.cc +++ b/gcc/lto-streamer-in.cc @@ -1987,7 +1987,6 @@ lto_input_toplevel_asms (struct lto_file_decl_data *file_data, int order_base) = (const struct lto_simple_header_with_strings *) data; int string_offset; class data_in *data_in; - tree str; if (! data) return; @@ -2000,8 +1999,10 @@ lto_input_toplevel_asms (struct lto_file_decl_data *file_data, int order_base) data_in = lto_data_in_create (file_data, data + string_offset, header->string_size, vNULL); - while ((str = streamer_read_string_cst (data_in, &ib))) + unsigned asm_count = streamer_read_uhwi (&ib); + for (unsigned i = 0; i < asm_count; i++) { + tree str = stream_read_tree (&ib, data_in); asm_node *node = symtab->finalize_toplevel_asm (str); node->order = streamer_read_hwi (&ib) + order_base; node->lto_file_data = file_data; diff --git a/gcc/lto-streamer-out.cc b/gcc/lto-streamer-out.cc index 24cbf4995493..293871cd7edc 100644 --- a/gcc/lto-streamer-out.cc +++ b/gcc/lto-streamer-out.cc @@ -384,6 +384,7 @@ lto_is_streamable (tree expr) && code != STATEMENT_LIST && (code == CASE_LABEL_EXPR || code == DECL_EXPR + || code == ASM_EXPR || TREE_CODE_CLASS (code) != tcc_statement); } @@ -2560,19 +2561,18 @@ lto_output_toplevel_asms (lto_symtab_encoder_t encoder) char *section_name; struct lto_simple_header_with_strings header; - bool any_asm = false; + unsigned asm_count = 0; for (int i = 0; i < lto_symtab_encoder_size (encoder); i++) if (is_a <asm_node*> (lto_symtab_encoder_deref (encoder, i))) - any_asm = true; + asm_count++; - if (!any_asm) + if (!asm_count) return; ob = create_output_block (LTO_section_asm); - /* Make string 0 be a NULL string. */ - streamer_write_char_stream (ob->string_stream, 0); - + /* Stream the length. */ + streamer_write_uhwi (ob, asm_count); for (int i = 0; i < lto_symtab_encoder_size (encoder); i++) { toplevel_node *tnode = lto_symtab_encoder_deref (encoder, i); @@ -2580,19 +2580,11 @@ lto_output_toplevel_asms (lto_symtab_encoder_t encoder) if (!anode) continue; - if (TREE_CODE (anode->asm_str) != STRING_CST) - { - sorry_at (EXPR_LOCATION (anode->asm_str), - "LTO streaming of toplevel extended %<asm%> " - "unimplemented"); - continue; - } - streamer_write_string_cst (ob, ob->main_stream, anode->asm_str); - streamer_write_hwi (ob, anode->order); + int output_order = *encoder->order_remap->get (anode->order); + stream_write_tree (ob, anode->asm_str, true); + streamer_write_hwi (ob, output_order); } - streamer_write_string_cst (ob, ob->main_stream, NULL_TREE); - section_name = lto_get_section_name (LTO_section_asm, NULL, 0, NULL); lto_begin_section (section_name, !flag_wpa); free (section_name); diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h index 4e43f60f562c..f8aa8465b7c7 100644 --- a/gcc/lto-streamer.h +++ b/gcc/lto-streamer.h @@ -933,6 +933,7 @@ bool lto_symtab_encoder_encode_initializer_p (lto_symtab_encoder_t, varpool_node *); void output_symtab (void); void input_symtab (void); +void input_toplevel_asms (void); void output_offload_tables (void); void input_offload_tables (bool); bool referenced_from_other_partition_p (struct ipa_ref_list *, diff --git a/gcc/lto/lto-common.cc b/gcc/lto/lto-common.cc index 37888361904c..e5c5bc6c675e 100644 --- a/gcc/lto/lto-common.cc +++ b/gcc/lto/lto-common.cc @@ -2948,6 +2948,9 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames) if (tree_with_vars) ggc_free (tree_with_vars); tree_with_vars = NULL; + + input_toplevel_asms (); + /* During WPA we want to prevent ggc collecting by default. Grow limits until after the IPA summaries are streamed in. Basically all IPA memory is explcitly managed by ggc_free and ggc collect is not useful. diff --git a/gcc/testsuite/g++.dg/lto/toplevel_asm-0_0.C b/gcc/testsuite/g++.dg/lto/toplevel_asm-0_0.C new file mode 100644 index 000000000000..4bfe6b1852de --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/toplevel_asm-0_0.C @@ -0,0 +1,7 @@ +// { dg-lto-do link } + +// Test that type of asm string is not removed. +char c; +asm(""); + +int main() { }
