This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Functions that are CSEable but not pure


On Thu, Oct 4, 2012 at 7:08 PM, Richard Guenther
<richard.guenther@gmail.com> wrote:
> On Thu, Oct 4, 2012 at 5:22 PM, Jason Merrill <jason@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
>>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]