On 11/7/25 11:15, Andrew MacLeod wrote:
On 11/7/25 00:46, Andrew Pinski wrote:
On Thu, Nov 6, 2025 at 6:22 PM Andrew MacLeod <[email protected]>
wrote:
I can add a check in the inferred range manager for atomic loads to
resolve this PR.
The IL sequence tends to look like:
_1 = &this_2(D)->b;
__atomic_load_8 (_1, 0);
Just want to make sure I get this right since memory operations are not
my strong suit.
The first argument to the atomic load is non-null (so _1), as well as
the base of the RHS of the address expression that defines _1 are
non-zero?. (this_2)
The attached patch scavenges a little code from
fold_using_range::range_of_address that I think works... but perhaps
there is a more efficient way to do this? Is this likely to work OK
and
be safe? or are there additional checks I need to be doing?
And I suppose there is an entire range of atomic operations this
applies
to? certainly atomic_store should qualify...
Bootstraps on x86_64-pc-linux-gnu with no regressions, but I'm not sure
that is a really extensive test for this..
Isn't the other route on fixing this is by adding the nonnull
attribute to these builtins? I tried looking to see if anyone had
mentioned why these builtins didn't have the nonnull attribute on them
but I didn't find anything.
The nonnull attribute support for builtins has been there since 2002
and atomic builtins were added afterwards (towards 2011).
DEF_ATTR_TREE_LIST (ATTR_NONNULL_1_NOTHROW_LEAF_LIST,
ATTR_NONNULL, \
ATTR_LIST_1, ATTR_NOTHROW_LEAF_LIST)
DEF_ATTR_TREE_LIST (ATTR_NONNULL_1_LEAF_LIST , ATTR_NONNULL, \
ATTR_LIST_1, ATTR_LEAF_LIST )
#define ATTR_NONNULL_1_NOTHROWCALL_LEAF_LIST
(flag_non_call_exceptions ? \
ATTR_NONNULL_1_LEAF_LIST : ATTR_NONNULL_1_NOTHROW_LEAF_LIST)
And then use ATTR_NONNULL_1_NOTHROWCALL_LEAF_LIST instead of
ATTR_NOTHROWCALL_LEAF_LIST in DEF_SYNC_BUILTIN for the builtins in
sync-builtins.def that are non null for the 1st argument.
I can only think that nobody has looked into the code generation
enough here to make a big difference. This would also handle isolate
paths too without any extra coding so I suspect special casing these
builtins everywhere is not a route which we want just for nonnullness.
Thanks,
Andrew
_1 = &this_2(D)->b;
__atomic_load_8 (_1, 0);
That would tag _1 as non_null, but that won't tag 'this_2' as
non-zero. I think the goal is to treat the use of _1 in the
__atomic_load as if it was dereferenced...
ie
struct d {
long a;
long b;
};
void call ();
void call2 ();
void fake (long *) __attribute__((nonnull));
void q (d *j)
{
long *p = &j->b;
fake (p);
if (j)
call ();
}
Replicates a similar thing. we know p is non-null, but never figure
out that j is. I guess we do not know that p is dereferenced in the
call to fake().
If however we add a derefernce:
void t (d *j)
{
long *p = &j->b;
fake (p);
if (*p)
call2 ()
if (j)
call ();
}
we *DO* know that j is non-null due to the
_1 = MEM[(long int *)j_4(D) + 8B];
That is introduced by the de-reference, and the 'if (j)' is removed.
So I think the goal is to treat the argument to the atomic calls as if
they are memory de-references, not just non-null? I don't suppose we
have anything like that already available :-P
Which means I probably need to do the same thing that the
non_null_loadstore () callback does at the very least.
Does any of this make sense?
Andrew
That got me to thinking... Should this maybe be an enhancement to
walk_stmt_load_store_ops() ? Where if the stmt is an atomic load (or
whatever operation) and the argument being operated on is an ssa_name,
that we do equivalent processing of the defining statement? It is
technically a load or store operation that isn't being processed. Do we
do anything for other builtins? like builtin_strcpy.? it also does
impliciit loads and stores like this
p_5 = &j_4(D)->b;
atomic_load_8 (p_5, 0);
_1 = MEM[(long int *)j_4(D) + 8B];
The _1 is the result of '*p'.. we want the equivalent effect for the
atomic load... In walk_load_store_ops () can we detect an atomic load,
expand the defining statement of p_5, so &j_4(D)-B into a MEM tree and
the walk that? or is that overthinking what needs to be done or wrong
path completely?
Andrew