]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
lto: Stream toplevel extended assembly
authorMichal Jires <mjires@suse.cz>
Thu, 8 Jan 2026 00:40:07 +0000 (01:40 +0100)
committerMichal Jires <mjires@suse.cz>
Sun, 11 Jan 2026 21:48:54 +0000 (22:48 +0100)
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.

gcc/ipa-free-lang-data.cc
gcc/lto-cgraph.cc
gcc/lto-streamer-in.cc
gcc/lto-streamer-out.cc
gcc/lto-streamer.h
gcc/lto/lto-common.cc
gcc/testsuite/g++.dg/lto/toplevel_asm-0_0.C [new file with mode: 0644]

index a655a1da5f46c5357bb18cba9734756589e42a94..edc4f1aed8111bd3f11593aceca41fbbdc9a6648 100644 (file)
@@ -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.  */
index 50635f3f8a43c30a8fc4d8babd5776e92a231a85..cbb37875b89e09bbafc884d45caad67c8730431b 100644 (file)
@@ -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)
 {
index 6261b37f9afaaabfafa175fd4959c466cf8172d5..9659d4aa532e0c44ec0c3caea6d318f6240a25f8 100644 (file)
@@ -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;
index 24cbf4995493ad9d3f16a2b35d2dd66c1348e792..293871cd7edc24bdbf2ccfcdf8ddd256d44570b4 100644 (file)
@@ -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);
index 4e43f60f562cef6f6d63327023734543c904bce5..f8aa8465b7c76b56c0b9884ba67ca0e4719399d1 100644 (file)
@@ -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 *,
index 37888361904c47947f455fc92565373b4e613b28..e5c5bc6c675e45c13a2cc1948a2ec59f70f8f85d 100644 (file)
@@ -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 (file)
index 0000000..4bfe6b1
--- /dev/null
@@ -0,0 +1,7 @@
+// { dg-lto-do link }
+
+// Test that type of asm string is not removed.
+char c;
+asm("");
+
+int main() { }