I reported https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124218
recently after learning it affects the synchronization interfaces
provided by real-time operating systems when using -fwhole-program or
-flto. For example, this can leads to moving accesses outside of a
section where a FreeRTOS mutex is held. Other ipa passes like
ipa-pure-const and ipa-modref handle memory clobbers in their analysis
already.

I've added a new test that runs on arm-none and will fail without the
change to ipa-reference.cc, by having an assembly statement that
declares a memory clobber and actually writes a global that the previous
version of the analysis would treat as not modified. Please let me know
if there's a more appropriate way to test this. Other tests are passing
on an aarch64 linux host.

        PR ipa/124218
---
 gcc/ChangeLog                       |  6 ++++++
 gcc/ipa-reference.cc                | 23 +++++++++++++++++++++++
 gcc/testsuite/gcc.dg/ipa/pr124218.c | 25 +++++++++++++++++++++++++
 3 files changed, 54 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/ipa/pr124218.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 8f5a62893c1..1be3b678fda 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2026-03-03  Chris Copeland  <[email protected]>
+
+       PR ipa/124218
+       * ipa-reference.cc (analyze_function): Treat memory clobbers as
+       reading/writing all_module_statics.
+
 2026-03-03  H.J. Lu  <[email protected]>
 
        PR target/124165
diff --git a/gcc/ipa-reference.cc b/gcc/ipa-reference.cc
index c5699312c8f..0c50b4b2df7 100644
--- a/gcc/ipa-reference.cc
+++ b/gcc/ipa-reference.cc
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "backend.h"
 #include "tree.h"
 #include "gimple.h"
+#include "gimple-iterator.h"
 #include "tree-pass.h"
 #include "cgraph.h"
 #include "data-streamer.h"
@@ -550,6 +551,28 @@ analyze_function (struct cgraph_node *fn)
 
   if (fn->cannot_return_p ())
     bitmap_clear (local->statics_written);
+
+  /* If the function body contains any asm statement that clobbers memory,
+     mark all module statics as read and written.  */
+  struct function *fun = DECL_STRUCT_FUNCTION (fn->decl);
+  if (fun && fun->cfg)
+    {
+      basic_block bb;
+      FOR_EACH_BB_FN (bb, fun)
+       for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+            !gsi_end_p (gsi); gsi_next (&gsi))
+         {
+           gimple *stmt = gsi_stmt (gsi);
+           if (gimple_code (stmt) == GIMPLE_ASM
+               && gimple_asm_clobbers_memory_p (as_a <gasm *> (stmt)))
+             {
+               local->statics_read = all_module_statics;
+               if (!fn->cannot_return_p ())
+                 local->statics_written = all_module_statics;
+               return;
+             }
+         }
+    }
 }
 
 
diff --git a/gcc/testsuite/gcc.dg/ipa/pr124218.c 
b/gcc/testsuite/gcc.dg/ipa/pr124218.c
new file mode 100644
index 00000000000..7cfb17034c6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/pr124218.c
@@ -0,0 +1,25 @@
+/* { 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__ ((noinline))
+static void
+clobber_and_set (void)
+{
+  __asm__ volatile ("ldr r0, =flag\n\t"
+                   "mov r1, #1\n\t"
+                   "str r1, [r0]"
+                   ::: "r0", "r1", "memory");
+}
+
+int main (void)
+{
+  flag = 0;
+  clobber_and_set ();
+  if (!flag)
+    __builtin_abort ();
+  return 0;
+}
-- 
2.53.0

Reply via email to