On Mon, Jul 07, 2025 at 07:21:26AM -0400, Siddhesh Poyarekar wrote:
> > is .ACCESS_WITH_SIZE documented?  I can't find it documented in the
> > internals manual, internal-fn.def has
> 
> It's documented in tree-object-size.cc as:
> 
> /* Compute __builtin_object_size for a CALL to .ACCESS_WITH_SIZE,
>    OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
>    The 2nd, 3rd, and the 4th parameters of the call determine the size of
>    the CALL:
> 
>    2nd argument REF_TO_SIZE: The reference to the size of the object,
>    3rd argument CLASS_OF_SIZE: The size referenced by the REF_TO_SIZE
> represents
>      0: the number of bytes;
>      1: the number of the elements of the object type;
>    4th argument TYPE_OF_SIZE: A constant 0 with its TYPE being the same as
> the TYPE
>     of the object referenced by REF_TO_SIZE
>    6th argument: A constant 0 with the pointer TYPE to the original flexible
>      array type or pointer field type.
> 
>    The size of the element can be retrived from the TYPE of the 6th argument
>    of the call, which is the pointer to the original flexible array type or
>    the type of the original pointer field.  */
> 
> which doesn't document the return either.  This should have more verbose
> documentation in the internals, including the rationale for its existence.
> 
> > /* A function to associate the access size and access mode information
> >     with the corresponding reference to an object.  It only reads from the
> >     2nd argument.  */
> > DEF_INTERNAL_FN (ACCESS_WITH_SIZE, ECF_PURE | ECF_LEAF | ECF_NOTHROW, NULL)
> > 
> > that suggests .ACCESS_WITH_SIZE performs a read on the size.  It doesn't
> > say what the function returns at all.
> 
> In practice the function is a nop, it gets optimized away during RTL
> expansion.  The aim is simply to pretend that the reference of the size may
> escape pointer to make sure that any preceding updates to size don't get
> reordered w.r.t. __builtin_dynamic_object_size since the latter could get
> expanded to that size.
> 
> The return value of .ACCESS_WITH_SIZE clobbering PTR (that subsequently gets
> passed to __builtin_dynamic_object_size) should be sufficient to fully
> prevent the reordering, it shouldn't have to clobber &PTR, I think.

The original use of .ACCESS_WITH_SIZE was designed for FAMs, for those
it IMHO does the right thing, it is a pass through first arg function
which attaches size information to the passed as well as returned pointer.
That pointer is &FAM, so address of the containing structure plus offsetof
of the FAM first element.

The way it is used for non-FAMs looks just wrong.
It passes as first argument the address of the pointer, not the pointer
itself.  So we have ifn used for two completely different purposes with
different meanings, while the arguments are otherwise pretty much the same
(or how do you uniquely distinguish the cases where it provides object
size for what it returns vs. where it provides object size for what the
pointer it returns points to).  That is like the spaghetti code in certain
middle end warnings.  For warnings it is really bad, for code generation
decisions it is a fatal design flaw.

So, either you need a different ifn, or add some flag in bitfield
that clearly distinguishes the 2 cases, or different number of arguments,
or perhaps most easily, why do the dereference at all?
When I have
  struct U { int n; int fam[n] __attribute__((counted_by (n))); } *u;
continue passing &u->fam as first argument and &u->n as second, while for
  struct S {
    int n;
    int (*p)[n] __attribute__((counted_by(n)));
  } *f;
don't pass &f->p to the builtin but pass f->p.  You are providing size
for f->p pointer, not for &f->p pointer, while for FAM it is for &u->fam
pointer.  The second argument would be &f->n.

So, my recommendation would be to revert the counted_by GCC 16 series,
rework it and submit again.  Unless you can fix it up in a day or two.

        Jakub

Reply via email to