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

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

           What    |Removed                     |Added
----------------------------------------------------------------------------
     Ever confirmed|0                           |1
             Status|UNCONFIRMED                 |NEW
                 CC|                            |hubicka at gcc dot gnu.org,
                   |                            |rguenth at gcc dot gnu.org
           Keywords|                            |wrong-code
   Last reconfirmed|                            |2025-09-08

--- Comment #13 from Richard Biener <rguenth at gcc dot gnu.org> ---
So we have

ESCAPED, points-to non-local, points-to NULL, points-to const-pool, points-to
vars: { D.43798 D.54465 D.58783 } (nonlocal, escaped, escaped heap,
interposable)

  # PT = nonlocal escaped null { D.54465 } (escaped)
  pi_13 = tmpD.54466;
  if (&iD.54461 != pi_13)

and for

  putD.54384 (&ss_01D.54465, &iD.54461);

we generate the constraints

callescape(13) = NONLOCAL
CALLUSED(14) = callescape(13)
callarg(16) = &ss_01.0+64
callarg(16) = callarg(16) + UNKNOWN
callarg(16) = *callarg(16) + UNKNOWN
CALLUSED(14) = callarg(16)
*callarg(16) = callescape(13)
CALLCLOBBERED(15) = callarg(16)
callescape(13) = callarg(16)
ESCAPED = &ss_01.0+64

'put's only use of the 2nd arg is

  <bb 2> :
  __v_11 = (long unsigned intD.16) __vv_10(D);

and modref computes for this argument

  parm 1 flags: no_direct_clobber no_indirect_clobber no_direct_escape
no_indirect_escape no_direct_read no_indirect_read

I'll note this is inconsistent with what points-to itself would compute
when inlining 'put', since we'd track the pointer through the transform
to a string.

I'm not sure where modref stops tracking - the most precise answer would
be that parameter 1 escapes to what parameter 0 points to?  For simple
testcases this works fine, "simple" as in as complicated as

void foo (unsigned long *p, int *q)
{
  for (int i = 0; i < 8; ++i)
    ((char *)p)[i] = (unsigned long)q >> (i * 8);
}

With -fno-ipa-modref we inline stuff (but not 'put') and then end up with

  # PT = nonlocal null 
  __ul.4_45 = (voidD.54 *) __result_44; 
  __begD.58822 ={v} {CLOBBER(eos)};
  if (&iD.54461 != __ul.4_45)

somewhere the 'escaped' gets lost.  The issue is the pointer tracking
through equivalences here:

  if (_53 == &MEM <const charD.10[16]> [(voidD.54 *)&s_in_atomsD.56708 + 16B])
    goto <bb 13>; [5.50%]
  else
    goto <bb 9>; [94.50%]

  <bb 9> [local count: 1014686025]:
  _34 = _53 - &s_in_atomsD.56708;
  __digit_35 = (intD.9) _34;

basically we track pointers as you store them piecewise, but when you then
extract them by if (p == q) .. use q .., then we lose the association.

This is a known issue, there's duplicates of this.  And the modref issue
is exactly the same.

In principle for the constraint-based points-to any equality compare
would need a unification constraint.  Likewise modref would need to
handle things this way.

Reply via email to