> On Jul 1, 2026, at 2:32 AM, Richard Biener <[email protected]> wrote:
> 
> On Wed, Apr 15, 2026 at 9:22 AM Chris Copeland <[email protected] 
> <mailto:[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)?

Yes, thanks for the catch.
I've submitted v5 with this change and a corresponding test change.
https://gcc.gnu.org/pipermail/gcc-patches/2026-July/722754.html

> 
> 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

Reply via email to