On Tue, Apr 13, 2010 at 12:23 PM, Richard Guenther
<richard.guent...@gmail.com> wrote:
> On Tue, Apr 13, 2010 at 12:15 PM, Bingfeng Mei <b...@broadcom.com> wrote:
>>>
>>> Surely printf writes to global memory (it clobbers the stdout FILE*)
>>>
>> OK, the point is not about whether printf is pure or not. Instead, if
>> programmer knows the callee function such as printf contains no
>> memory access that affects operations inside caller function, and he
>> would like to have a way to optimize the code. Our engineer gave following
>> example:
>>
>>    void myfunc(MyStruct *myStruct)
>>    {
>>      int a,b;
>>      a = myStruct->a;
>>      printf("a=%d\n",a);
>>      b = 2*mystruct->a;      // I would like to have the compiler acting as 
>> if I had written b = 2*a;
>>     ...
>>    }
>> Providing such attribute may be potentially dangerous. But it is just
>> like "restrict" qualifier and some other attributes, putting responsibilty
>> of correctness on the programmer. "novops" seems to achieve that effect,
>> though its semantics doesn't match exactly what I described.
>
> Indeed.  IPA pointer analysis will probably figure it out
> automagically - that *myStruct didn't escape the unit.
> Being able to annotate incoming pointers this way would
> maybe be useful.
>
>>> As for the original question - novops is internal only because its
>>> semantics is purely internal and changes with internal aliasing
>>> changes.
>>>
>>> Now, we still lack a compelling example to see what exact semantics
>>> you are requesting?  I suppose it might be close to a pure but
>>> volatile function?  Which you could simulate by
>>>
>>> dummy = pure_fn ();
>>> asm ("" : "g" (dummy));
>>>
>>> or even
>>>
>>> volatile int dummy = pure_fn ();
>>
>> These two methods still generate extra code to reload variables
>
> The latter works for me (ok, the store to dummy is retained):
>
> extern int myprintf(int) __attribute__((pure));
> int myfunc (int *p)
> {
>  int a;
>  a = *p;
>  volatile int dummy = myprintf(a);
>  return a + *p;
> }
>
> myfunc:
> .LFB0:
>        pushq   %rbx
> .LCFI0:
>        subq    $16, %rsp
> .LCFI1:
>        movl    (%rdi), %ebx
>        movl    %ebx, %edi
>        call    myprintf
>        movl    %eax, 12(%rsp)
>        leal    (%rbx,%rbx), %eax
>        addq    $16, %rsp
> .LCFI2:
>        popq    %rbx
> .LCFI3:
>        ret
>
> so we load from %rdi only once.

And

extern int myprintf(int) __attribute__((pure));
int myfunc (int *p)
{
  int a;
  a = *p;
  int dummy = myprintf(a);
  asm ("" : : "g" (dummy));
  return a + *p;
}

produces

myfunc:
.LFB0:
        pushq   %rbx
.LCFI0:
        movl    (%rdi), %ebx
        movl    %ebx, %edi
        call    myprintf
        leal    (%rbx,%rbx), %eax
        popq    %rbx
.LCFI1:
        ret

even better.

Richard.

Reply via email to