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: Release novops attribute for external use?


On Tue, Apr 13, 2010 at 12:23 PM, Richard Guenther
<richard.guenther@gmail.com> wrote:
> On Tue, Apr 13, 2010 at 12:15 PM, Bingfeng Mei <bmei@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.


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