On Tue, Apr 13, 2010 at 12:23 PM, Richard Guenther
<[email protected]> wrote:
> On Tue, Apr 13, 2010 at 12:15 PM, Bingfeng Mei <[email protected]> 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.