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

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

           What    |Removed                     |Added
----------------------------------------------------------------------------
     Ever confirmed|0                           |1
           Keywords|                            |alias, missed-optimization
             Status|UNCONFIRMED                 |NEW
   Last reconfirmed|                            |2026-07-06
                 CC|                            |rguenth at gcc dot gnu.org

--- Comment #3 from Richard Biener <rguenth at gcc dot gnu.org> ---
The interesting correctness case is indirectly called variadic functions and
setting/accessing the variadic arguments.  For

#include <stdarg.h>

static int q (int n, ...)
{
  va_list va;
  va_start (va, n);
  int *a = va_arg (va, int *);
  int *b = va_arg (va, int *);
  va_end (va);
  return *a + *b;
}

int foo (int (*p)(int, ...))
{
  int i = 1, j = 3;
  return p(2, &i, &j);
}

int main()
{
  if (foo (q) != 4)
    __builtin_abort ();
}


we generate

Generating constraints for main/3 (main)

foo.arg0 = &q
_1 = foo.result
...

Generating constraints for foo/2 (foo)

ESCAPED = foo.result
foo.arg0 = &NONLOCAL
i = &NONLOCAL
j = &NONLOCAL
derefaddrtmp(31) = &NONLOCAL
*foo.arg0 + 5 = derefaddrtmp(31)
derefaddrtmp(32) = &i
*foo.arg0 + 6 = derefaddrtmp(32)
derefaddrtmp(33) = &j
*foo.arg0 + 7 = derefaddrtmp(33)
_6 = *foo.arg0 + 4
foo.use = &i
foo.use = &j
foo.clobber = *foo.arg0 + 1
foo.use = *foo.arg0 + 2
foo.result = _6

Generating constraints for q/1 (q)

va = &q.varargs
CALLCLOBBERED(37) = &va
ANYTHING = &va
ANYTHING = &NULL
ANYTHING = &NULL
a_6 = ANYTHING
q.use = &va
q.clobber = &ANYTHING
q.use = &ANYTHING
ANYTHING = &va
ANYTHING = &NULL
ANYTHING = &NULL
b_8 = ANYTHING
q.use = &va
q.clobber = &ANYTHING
q.use = &ANYTHING
_1 = *a_6
q.use = a_6
_2 = *b_8
q.use = b_8
_10 = _1
_10 = _2
q.result = _10


and we correctly get i and j included in q.varargs:

q.varargs = { ESCAPED NONLOCAL i j }

q.use ends up as { NULL ANYTHING ESCAPED NONLOCAL va }

Making foo static and forcing -fno-inline makes the result a little bit
more precise.  I believe we miss handling of .VA_ARG from

int q (int n)
{
  int * b;
  int * a;
  struct  va[1];
  int _1;
  int _2;
  int _10;

  <bb 2> [local count: 1073741824]:
  __builtin_va_start (&va, 0);
  a_6 = .VA_ARG (&va, 0B, 0B);
  b_8 = .VA_ARG (&va, 0B, 0B);
  __builtin_va_end (&va);
  _1 = *a_6;
  _2 = *b_8;
  _10 = _1 + _2;
  va ={v} {CLOBBER(eos)};
  return _10;

}

that should just return what &va points to.

I'm not sure we ever need to "expand" a fn_info, but as with Steensgard
Andersen can end up unifying nodes, so if one is a function pointer and
one a variable we can have a + UNKNOWN constraint for the latter.  The
question is what we should semantically do here.

That said, it seems the .use/clobber, etc. variables are made pointed-to
by the solver in build_pred_graph:

      else if (rhs.type == ADDRESSOF)
        {
...
          /* All related variables are no longer direct nodes.  */
          bitmap_clear_bit (graph->direct_nodes, rhsvar);
          v = get_varinfo (rhsvar);
          if (!v->is_full_var)
            {
              v = get_varinfo (v->head);
              do
                {
                  bitmap_clear_bit (graph->direct_nodes, v->id);
                  v = vi_next (v);

we do need to make the argument slots indirect nodes to make the

*foo.arg0 + 5 = derefaddrtmp(31)

constraints work though.  But not the use/clobber part.  But neither
blocking the use/clobber from the above nor making them artificial vars
helps your testcase.

Reply via email to