Record the presence of asm memory clobbers in ipa_fn_summary and use it
in ipa-reference's analyze_function to mark all module statics as read
and written.  Move pass_ipa_reference before pass_ipa_free_fn_summary so
the summary is still available when needed.

gcc/ChangeLog:

        PR ipa/124218
        * ipa-fnsummary.h (ipa_fn_summary): Add asm_memory_clobber field.
        * ipa-fnsummary.cc (analyze_function_body): Set asm_memory_clobber
        when a GIMPLE_ASM with a memory clobber is found.
        (ipa_merge_fn_summary_after_inlining): Merge asm_memory_clobber.
        (inline_read_section): Stream in asm_memory_clobber.
        (ipa_fn_summary_write): Stream out asm_memory_clobber.
        * ipa-reference.cc (analyze_function): Use asm_memory_clobber from
        fn summary to mark all module statics as read and written.
        * passes.def: Move pass_ipa_reference before pass_ipa_free_fn_summary.

gcc/testsuite/ChangeLog:

        PR ipa/124218
        * gcc.dg/ipa/pr124218.c: New test.
---
 gcc/ChangeLog                       | 13 +++++++++++++
 gcc/ipa-fnsummary.cc                |  9 +++++++++
 gcc/ipa-fnsummary.h                 |  6 +++++-
 gcc/ipa-reference.cc                | 13 +++++++++++++
 gcc/passes.def                      |  2 +-
 gcc/testsuite/ChangeLog             |  5 +++++
 gcc/testsuite/gcc.dg/ipa/pr124218.c | 30 +++++++++++++++++++++++++++++
 7 files changed, 76 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/ipa/pr124218.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 1a6bab7bc65..57c67037c77 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,16 @@
+2026-03-15  Chris Copeland  <[email protected]>
+
+       PR ipa/124218
+       * ipa-fnsummary.h (ipa_fn_summary): Add asm_memory_clobber field.
+       * ipa-fnsummary.cc (analyze_function_body): Set asm_memory_clobber
+       when a GIMPLE_ASM with a memory clobber is found.
+       (ipa_merge_fn_summary_after_inlining): Merge asm_memory_clobber.
+       (inline_read_section): Stream in asm_memory_clobber.
+       (ipa_fn_summary_write): Stream out asm_memory_clobber.
+       * ipa-reference.cc (analyze_function): Use asm_memory_clobber from
+       fn summary to mark all module statics as read and written.
+       * passes.def: Move pass_ipa_reference before pass_ipa_free_fn_summary.
+
 2026-03-14  Jakub Jelinek  <[email protected]>
 
        PR other/124508
diff --git a/gcc/ipa-fnsummary.cc b/gcc/ipa-fnsummary.cc
index e187231dfb6..2e1387ec746 100644
--- a/gcc/ipa-fnsummary.cc
+++ b/gcc/ipa-fnsummary.cc
@@ -3200,6 +3200,11 @@ analyze_function_body (struct cgraph_node *node, bool 
early)
                }
            }
 
+         if (!info->asm_memory_clobber
+             && gimple_code (stmt) == GIMPLE_ASM
+             && gimple_asm_clobbers_memory_p (as_a <gasm *> (stmt)))
+           info->asm_memory_clobber = true;
+
          /* For target specific information, we want to scan all statements
             rather than those statements with non-zero weights, to avoid
             missing to scan something interesting for target information,
@@ -4492,6 +4497,7 @@ ipa_merge_fn_summary_after_inlining (struct cgraph_edge 
*edge)
     toplev_predicate = true;
 
   info->fp_expressions |= callee_info->fp_expressions;
+  info->asm_memory_clobber |= callee_info->asm_memory_clobber;
   info->target_info |= callee_info->target_info;
 
   if (callee_info->conds)
@@ -4838,11 +4844,13 @@ inline_read_section (struct lto_file_decl_data 
*file_data, const char *data,
        {
          info->inlinable = bp_unpack_value (&bp, 1);
          info->fp_expressions = bp_unpack_value (&bp, 1);
+         info->asm_memory_clobber = bp_unpack_value (&bp, 1);
          if (!lto_stream_offload_p)
            info->target_info = streamer_read_uhwi (&ib);
        }
       else
        {
+         bp_unpack_value (&bp, 1);
          bp_unpack_value (&bp, 1);
          bp_unpack_value (&bp, 1);
          if (!lto_stream_offload_p)
@@ -5084,6 +5092,7 @@ ipa_fn_summary_write (void)
          bp = bitpack_create (ob->main_stream);
          bp_pack_value (&bp, info->inlinable, 1);
          bp_pack_value (&bp, info->fp_expressions, 1);
+         bp_pack_value (&bp, info->asm_memory_clobber, 1);
          streamer_write_bitpack (&bp);
          if (!lto_stream_offload_p)
            streamer_write_uhwi (ob, info->target_info);
diff --git a/gcc/ipa-fnsummary.h b/gcc/ipa-fnsummary.h
index de7b7f61cb1..896cb6c1725 100644
--- a/gcc/ipa-fnsummary.h
+++ b/gcc/ipa-fnsummary.h
@@ -126,7 +126,8 @@ public:
   ipa_fn_summary ()
     : min_size (0),
       inlinable (false), single_caller (false),
-      fp_expressions (false), safe_to_inline_to_always_inline (0),
+      fp_expressions (false), asm_memory_clobber (false),
+      safe_to_inline_to_always_inline (0),
       target_info (0), estimated_stack_size (false),
       time (0), conds (NULL),
       size_time_table (), call_size_time_table (vNULL),
@@ -141,6 +142,7 @@ public:
     : min_size (s.min_size),
     inlinable (s.inlinable), single_caller (s.single_caller),
     fp_expressions (s.fp_expressions),
+    asm_memory_clobber (s.asm_memory_clobber),
     target_info (s.target_info),
     estimated_stack_size (s.estimated_stack_size),
     time (s.time), conds (s.conds), size_time_table (),
@@ -165,6 +167,8 @@ public:
   unsigned int single_caller : 1;
   /* True if function contains any floating point expressions.  */
   unsigned int fp_expressions : 1;
+  /* True if function contains an asm statement that clobbers memory.  */
+  unsigned int asm_memory_clobber : 1;
   /* Cache for analysis of can_early_inline_edge_p.  */
   unsigned int safe_to_inline_to_always_inline : 2;
   /* Like fp_expressions field above, but it's to hold some target specific
diff --git a/gcc/ipa-reference.cc b/gcc/ipa-reference.cc
index c5699312c8f..12b593b0f50 100644
--- a/gcc/ipa-reference.cc
+++ b/gcc/ipa-reference.cc
@@ -50,6 +50,11 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-reference.h"
 #include "alloc-pool.h"
 #include "symbol-summary.h"
+#include "tree-vrp.h"
+#include "sreal.h"
+#include "ipa-cp.h"
+#include "ipa-prop.h"
+#include "ipa-fnsummary.h"
 
 /* The static variables defined within the compilation unit that are
    loaded or stored directly by function that owns this structure.  */
@@ -507,6 +512,7 @@ analyze_function (struct cgraph_node *fn)
 {
   ipa_reference_local_vars_info_t local;
   struct ipa_ref *ref = NULL;
+  ipa_fn_summary *sum;
   int i;
   tree var;
 
@@ -548,6 +554,13 @@ analyze_function (struct cgraph_node *fn)
        }
     }
 
+  sum = ipa_fn_summaries->get (fn);
+  if (sum && sum->asm_memory_clobber)
+    {
+      local->statics_read = all_module_statics;
+      local->statics_written = all_module_statics;
+    }
+
   if (fn->cannot_return_p ())
     bitmap_clear (local->statics_written);
 }
diff --git a/gcc/passes.def b/gcc/passes.def
index cdddb87302f..8344ea1a584 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -176,8 +176,8 @@ along with GCC; see the file COPYING3.  If not see
   NEXT_PASS (pass_ipa_locality_cloning);
   NEXT_PASS (pass_ipa_pure_const);
   NEXT_PASS (pass_ipa_modref);
-  NEXT_PASS (pass_ipa_free_fn_summary, false /* small_p */);
   NEXT_PASS (pass_ipa_reference);
+  NEXT_PASS (pass_ipa_free_fn_summary, false /* small_p */);
   /* This pass needs to be scheduled after any IP code duplication.   */
   NEXT_PASS (pass_ipa_single_use);
   /* Comdat privatization come last, as direct references to comdat local
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index f0b92db69fc..0337f6192f6 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2026-03-15  Chris Copeland  <[email protected]>
+
+       PR ipa/124218
+       * gcc.dg/ipa/pr124218.c: New test.
+
 2026-03-14  Jakub Jelinek  <[email protected]>
 
        PR c++/124399
diff --git a/gcc/testsuite/gcc.dg/ipa/pr124218.c 
b/gcc/testsuite/gcc.dg/ipa/pr124218.c
new file mode 100644
index 00000000000..67e95914d6b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/pr124218.c
@@ -0,0 +1,30 @@
+/* { dg-do run { target arm*-*-eabi* } } */
+/* { dg-options "-O1 -fwhole-program" } */
+
+/* PR ipa/124218: ipa-reference must honor memory clobbers in inline asm.  */
+
+int flag;
+
+__attribute__ ((used))
+void
+asm_set (void)
+{
+  flag = 1;
+}
+
+__attribute__ ((noinline))
+static void
+clobber_and_set (void)
+{
+  __asm__ volatile ("bl asm_set" ::: "r0", "r1", "r2", "r3",
+                   "ip", "lr", "memory", "cc");
+}
+
+int main (void)
+{
+  flag = 0;
+  clobber_and_set ();
+  if (!flag)
+    __builtin_abort ();
+  return 0;
+}
-- 
2.53.0

Reply via email to