On Wed, Apr 15, 2026 at 9:22 AM Chris Copeland <[email protected]> wrote:
>
> v4: Remove ChangeLog edits from the patch.
>
> ---
>
> 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.
> * g++.dg/guality/pr55665.C: Remove memory clobber. This memory clobber
> was being ignored before, and leaving it in now triggers PR124864,
> breaking the test. Correct PR number in first comment.
> ---
> gcc/ipa-fnsummary.cc | 9 ++++++++
> gcc/ipa-fnsummary.h | 6 +++++-
> gcc/ipa-reference.cc | 13 +++++++++++
> gcc/passes.def | 2 +-
> gcc/testsuite/g++.dg/guality/pr55665.C | 4 ++--
> gcc/testsuite/gcc.dg/ipa/pr124218.c | 30 ++++++++++++++++++++++++++
> 6 files changed, 60 insertions(+), 4 deletions(-)
> create mode 100644 gcc/testsuite/gcc.dg/ipa/pr124218.c
>
> 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)
Don't we need to treat the sum == NULL case conservatively,
thus if (!sum || sum->asm_memory_clobber)?
Otherwise looks OK.
Thanks,
Richard.
> + {
> + 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/g++.dg/guality/pr55665.C
> b/gcc/testsuite/g++.dg/guality/pr55665.C
> index 16c6d281661..d100d0abc29 100644
> --- a/gcc/testsuite/g++.dg/guality/pr55665.C
> +++ b/gcc/testsuite/g++.dg/guality/pr55665.C
> @@ -1,4 +1,4 @@
> -// PR debug/55655
> +// PR debug/55665
> // { dg-do run }
> // { dg-options "-g" }
>
> @@ -14,7 +14,7 @@ bar (void)
> __attribute__((noinline, noclone)) void
> foo (int x)
> {
> - __asm volatile ("" : : "r" (x) : "memory");
> + __asm volatile ("" : : "r" (x));
> }
>
> A::A (int x)
> 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
>