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.