On Thu, Oct 4, 2012 at 5:22 PM, Jason Merrill <ja...@redhat.com> wrote: > On 10/04/2012 09:07 AM, Richard Guenther wrote: >> >> Ugh. Especially with the above (you can DCE those calls) makes this >> severly mis-specified ... and any implementation error-prone (look what >> mess our losely defined 'malloc' attribute opened ...). >> >> I thought of a testcase like >> >> int *p = get_me (); >> .. = *p; >> int *q = get_me (); >> .. = *q; >> >> and get_me allocating/initalizing and returning a singleton. > > > Right. > > >> But you tell me it's more complicated and get_me () needs to >> be a barrier for any load/store (as it may modify arbitrary memory, >> but only on the "first" call). > > > Yes, because the initialization is user-written code. > > >> I think that "may modify arbitrary memory" isn't going to fly and >> my answer would be, better don't try to optimize anything here, >> at least not in generic terms. How would you handle this in >> the alias oracle? How would you then make CSE recognize >> two functions return the same value and are CSEable? > > > For aliasing purposes, the call is like a call to a normal function. For CSE > purposes, we want to recognize identical calls and combine them. I don't > know the GCC bits well enough to be any more specific. > > >> Can you come up with a short but complete testcase illustrating the issue >> better (preferably C, so I don't need to read-in magic points where >> construction >> happens)? > > > int init_count; > int data; > > void init() > { > static int initialized; > if (!initialized) > { > data = ++init_count; > initialized = 1; > } > } > > inline int *get_me() __attribute ((pure)); > inline int *get_me() > { > init (); > return &data; > } > > int sink; > > int main() > { > sink = init_count; > int *p = get_me(); > if (init_count != 1) > __builtin_abort(); > int *q = get_me(); > if (init_count != 1) > __builtin_abort(); > return *p + *q; > } > > On this testcase, gcc -O2 doesn't reload init_count after the call to get_me > because it thinks that the call can't have modified init_count. I want the > compiler to know that it is safe to discard the redundant assignment, but > not make assumptions about memory.
But isn't it a fact that it _cannot_ modify init_count? If the second call is CSEable then it cannot have side-effects that are observable at the call site. Is the following an example you would consider to fall under your CSEing? int init_count; int data; int initialized; void init() { if (!initialized) { data = ++init_count; initialized = 1; } } inline int *get_me() __attribute ((pure)); inline int *get_me() { init (); return &data; } int sink; int main() { sink = init_count; int *p = get_me(); if (init_count != 1) __builtin_abort(); initialized = 0; int *q = get_me(); if (init_count != 2) __builtin_abort(); return *p + *q; } ? If so, then why can we assume get_me returns the same pointer even here? Richard. > > On 10/04/2012 08:59 AM, Jakub Jelinek wrote:> On Thu, Oct 04, 2012 at > 08:56:03AM -0400, Jason Merrill wrote: >> Sure, but I thought you want to inline the wrapper function as soon as >> possible. Or do you want to keep it as some kind of builtin that gets >> expanded during expansion to the test and call? > > Ah, I see your point; if get_me is inlined we end up with two calls to init, > so it would be good to mark init with the same hypothetical attribute. > > Jason >