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.guent...@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.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. > >