This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
RE: Release novops attribute for external use?
Thanks! I forgot to declare the function as pure. The empty asm
seems to be a clever trick to avoid function being optimized out.
I shall tell our engineers to use this instead of implementing a new
attribute.
Bingfeng
> -----Original Message-----
> From: Richard Guenther [mailto:richard.guenther@gmail.com]
> Sent: 13 April 2010 11:25
> To: Bingfeng Mei
> Cc: Andrew Haley; gcc@gcc.gnu.org
> Subject: 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.
>
>