https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120972
--- Comment #5 from rguenther at suse dot de <rguenther at suse dot de> --- On Tue, 8 Jul 2025, fxue at os dot amperecomputing.com wrote: > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120972 > > --- Comment #4 from Feng Xue <fxue at os dot amperecomputing.com> --- > (In reply to Richard Biener from comment #3) > > (In reply to Feng Xue from comment #2) > > > (In reply to Richard Biener from comment #1) > > > > Yes, it's not possible to implement the standards restrict qualification > > > > constraints reliably for pointers not in the outermost scope of a > > > > function > > > > and after the compiler was allowed to do CSE or other code transforms. > > > > > > > > For simplicity only function parameters (and select "global" cases) > > > > are handled in the implementation which resides in points-to analysis. > > > > > > > > In principle 'restrict' should be handled in the C/C++ language > > > > frontends > > > > instead. > > > > > > Maybe, I caught your point, w/o front-end scope information, we do not > > > know > > > the effective lifetime of "__restrict__" pointer merely from def/use chain > > > in the gimple. An example: > > > > > > void foo (int *p) > > > { > > > int *a_escaped; > > > > > > { > > > int * __restrict__ a = ...; > > > > > > /* no alias between "a" and "p" */ > > > *a = ...; > > > > > > /* Make "a" escaped from block scope */ > > > a_escaped = a + offset; > > > } > > > > > > /* By source-level declaration syntax, "a_escaped" and "p" may be > > > aliased. But in the gimple, we do not know usage of "a_escaped" does not > > > belongs to lifetime constrainted by "__restrict__", and could lead to an > > > incorrect conclusion that "a_escaped" and "p" are alias-free. */ > > > > > > *a_escaped = ...; > > > > > > ... > > > } > > > > > > But for the 2nd case, all pointers are defined in the outermost scope of > > > function. How about an enhancement? Besides parameters, we could also mark > > > all __restrict__ pointers declared in the outermost scope, and ignore > > > others > > > in any enclosed scopes, as you said, probably this could be done that at > > > the > > > front-end stage. > > > > Outermost scope would work as long as there is no inlining or optimization > > happening before since we happily elide scopes and "globalize" variables. > > inline void goo() > { > int * __restrict__ p; > > ... > } > > void foo() > { > goo(); > } > > -> > > void foo() > { > > // goo(); > { > > // Would DECL_CONTEXT(p) become "foo" from "goo" after inline? > int * __restrict__ p; > > ... > > } > } > > I do not deep dive into related code how DECL_CONTEXT() varies with inline or > optimization. If this is quite compilicated to track, my thought is to > introduce another DECL_CONTEXT_RAW() or similar stuff, that is set to its > original function, when analyzing alias for a restrict var, we would also > check > if DECL_CONTEXT and DECL_CONTEXT_RAW is matched or not. > > > That is, it's quite difficult to prove handling user(!) variables in the > > outermost scope is correct. You'd check that DECL_CONTEXT of a variable > > is the same as DECL_INITIAL (cfun->decl), but I'm not sure this will > > never "break". Depending on frontends there might or might not be an > > additional "outer" scope from DECL_INITIAL IIRC. > > > > Does handling variables in the outermost scope matter in practice? > > In reality, we encounter an application with a hot loop containing lots of > memory accesses, whose pointers are defined as __restrict__ variables > initialized in the outermost scope, and those fake aliasing relations prevent > vectorization. I see. I see annotating loops with pragmas as a more user-friendly way of getting there. What we have at our disposal in terms of pragmas is quite limiting though, and if the application is a benchmark where changes are not allowed this doesn't help, of course. Handling outermost scope variables is reasonable I think. I'll note another problem though, which is void foo (int *a, int *b) { int * __restrict p = a; *p = *b; p = b; *p = *a; } I'd have to re-read the standard wording but since on GIMPLE we can't restrict ourselves to variables with initializer (that distinction is lost), we have to deal with possibly multiple assignments to the restrict qualified pointer (and the "first" one possibly being DCEd already). Another issue is that of propagation. We are happily replacing int * __restrict p = a; *p = *b; with *a = *b; but you can't reply on all uses of 'p' being replaced, so you might get an invalid mix of accesses via the restrict qualified and the not restrict qualified pointer from the initializer.