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() { }

Reply via email to