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