https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128185

Richard Biener <rguenth at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |hubicka at gcc dot gnu.org,
                   |                            |rguenth at gcc dot gnu.org

--- Comment #2 from Richard Biener <rguenth at gcc dot gnu.org> ---
OK, so the issue is that IPA modref does not record any kills for A::A(),
instead we just have

  loads:
  stores:
      Base 0: alias set 0
        Ref 0: alias set 0
          access: Parm 0 param offset:0 offset:0 size:-1 max_size:8192
  Side effects
  Nondeterministic
  parm 0 flags: no_indirect_clobber no_direct_escape no_indirect_escape
no_indirect_read

otherwise it should work.  modref sees

__attribute__((noinline))
void A::A (struct A * const this)
{
  char[1024] * _1;

  <bb 2> [local count: 1073741824]:
  _1 = &this_2(D)->buf;
  __builtin_memset (_1, 120, 1024);
  return;

}

I'm not sure why for the store size is -1 even.  Analyzing does

 - Analyzing call:__builtin_memset (_1, 120, 1024);
 - Function availability <= AVAIL_INTERPOSABLE.

and fnspec does not provide more specifics.

The following fixes it, but I suppose a "size specified by arg" fnspec
might be better.  In theory 'a'...'i' would be still available for that...
Oh, and fnspec only says the argument _might_ be written(?) ...

diff --git a/gcc/ipa-modref.cc b/gcc/ipa-modref.cc
index 7883a90bcdd..8a1d5ec0079 100644
--- a/gcc/ipa-modref.cc
+++ b/gcc/ipa-modref.cc
@@ -1491,6 +1491,38 @@ modref_access_analysis::process_fnspec (gcall *call)
   if (flags & (ECF_CONST | ECF_NOVOPS))
     return;

+  if (gimple_call_builtin_p (call, BUILT_IN_MEMSET))
+    {
+      modref_parm_map map = parm_map_for_ptr (gimple_call_arg (call, 0));
+      if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
+       ;
+      else if (map.parm_index == MODREF_UNKNOWN_PARM)
+       record_unknown_store ();
+      else
+       {
+         modref_access_node a
+           = { 0, -1, -1, map.parm_offset, map.parm_index,
+               map.parm_offset_known, 0 };
+         tree size = gimple_call_arg (call, 2);
+         poly_int64 size_hwi;
+         if (poly_int_tree_p (size, &size_hwi))
+           a.size = a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
+         if (m_summary)
+           m_summary->stores->insert (current_function_decl, 0, 0, a, false);
+         if (m_summary_lto)
+           m_summary_lto->stores->insert (current_function_decl,
+                                          0, 0, a, false);
+         if (m_always_executed && a.useful_for_kill_p ())
+           {
+             if (m_summary)
+               modref_access_node::insert_kill (m_summary->kills, a, false);
+             if (m_summary_lto)
+               modref_access_node::insert_kill (m_summary_lto->kills, a,
false);
+           }
+       }
+      return;
+    }
+
   attr_fnspec fnspec = gimple_call_fnspec (call);
   /* If there is no fnpec we know nothing about loads & stores.  */
   if (!fnspec.known_p ())

Reply via email to