On Thu, Oct 4, 2012 at 7:08 PM, Richard Guenther <richard.guent...@gmail.com> wrote: > 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?
Or similar: int main() { sink = init_count; int *p = get_me(); if (init_count != 1) __builtin_abort(); } is this required to not abort? p is unused and with 'pure' you'd DCE the call. That is, I am confused about the distinction you seem to make between the static variable 'initialized' and the global 'init_count'. You seem to imply that the attribute would mean that we can CSE side-effects to global memory but that those side-effects may be value-changing! In practice for any CSE implementation this hypotetical "cse-side-effects" attribute would only allow us to CSE if there are no intermediate side-effects between two such calls, and as soon as the second get_me call would be CSEd we'd also CSE the init_count value (which you didn't want to CSE?!) Still confused ;) Richard. > 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 >>