Hi, I implemented simple propagation of EAF arguments for ipa-modref (that is not hard to do). My main aim was to detect cases where THIS parameter does not escape but is used to read/write pointed to memory. This is meant to avoid poor code produced when we i.e. offline destructors on cold path.
Unfortunately detecting EAF_NOESCAPE for such parameters breaks. This is already visible on memcpy if we let it to be be handled via its fnspec attribute. If I disable special handling in structalias: diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index a4832b75436..2b614913b57 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -4389,7 +4389,6 @@ find_func_aliases_for_builtin_call (struct function *fn, gcall *t) case BUILT_IN_STRCPY: case BUILT_IN_STRNCPY: case BUILT_IN_BCOPY: - case BUILT_IN_MEMCPY: case BUILT_IN_MEMMOVE: case BUILT_IN_MEMPCPY: case BUILT_IN_STPCPY: In the following testcase we miss the fact that memcpy may merge i4p PTA set to i3p. extern void exit (int); extern void abort (void); int size = 8; int main (void) { int i3 = -1, i4 = 55; int *i3p = &i3; int *i4p = &i4; memcpy(&i3p, &i4p, size); if (i3p != i4p) abort (); exit (0); } This seems to be documented for some degree: /* Add *tem = nonlocal, do not add *tem = callused as EAF_NOESCAPE parameters do not escape to other parameters and all other uses appear in NONLOCAL as well. */ But it also means that some of our FNSPECs are wrong now. I wonder if we can split this porperty to two different flags like EAF_NOEASCAPE and EAF_INDIRECT_NOESCAPE? Auto-detecting EAF_INDIRECT_NOESCAPE seems bit harder at least assuming that any read can actually load few bits of pointer possibly written there beause if simple member functions accesses values pointer by THIS and return them we lose a track if the returned value is an escape point I would say. The difference in constraints are: --- good/a.c.035t.ealias 2020-11-08 13:34:04.397499515 +0100 +++ a.c.035t.ealias 2020-11-08 13:39:15.483438469 +0100 @@ -106,7 +106,15 @@ size = NONLOCAL size.0_1 = size _2 = size.0_1 -i3p = i4p +callarg(18) = &i3p +callarg(18) = callarg(18) + UNKNOWN +CALLUSED(16) = callarg(18) +CALLCLOBBERED(17) = callarg(18) +*callarg(18) = NONLOCAL +callarg(19) = &i4p +callarg(19) = callarg(19) + UNKNOWN +CALLUSED(16) = callarg(19) +ESCAPED = _2 i3p.1_3 = i3p i4p.2_4 = i4p ESCAPED = &NULL ... Call clobber information -ESCAPED, points-to NULL, points-to vars: { } +ESCAPED, points-to non-local, points-to NULL, points-to vars: { } Flow-insensitive points-to information -i3p.1_3, points-to NULL, points-to vars: { D.1947 D.1948 } +i3p.1_3, points-to non-local, points-to escaped, points-to NULL, points-to vars: { D.1947 } i4p.2_4, points-to NULL, points-to vars: { D.1948 } main () Honza