I'm looking into a case where TER is forward propagating a series of
additions across a call.
extern void foo(void);
int bar(int a, int b, int c, int d, int e, int f, int g, int h) {
int ret;
ret = a + b + c + d + e + f + g + h;
foo();
return ret; /* 'ret' use replaced by rhs above */
}
Unfortunately by moving all the additions across the call we've extended
the lifetimes of the parm regs across the call also and therefor they
need to be copied into callee-saved regs to preserve their value across
the call, which means bar() will have save/restore code for 8 regs
instead of just 1 (to thold the result across the call).
I tried hacking tree-ssa-ter.c to not perform the replacement if the def
and use cross a call (i.e. cross an is_gimple_call() stmt), but ran into
cases where we don't do a valid replacement because things like
__builtin_sqrtf()/__builtin_powf() are marked as calls but expand to
simple instructions (on PPC anyway). The __builtin_powf() calls were
actually introduced on a transformation of y*y => __builtin_powf(y,2.0).
A couple of questions:
1) Is this a valid optimization in general to attempt wrt other targets
(i.e. prevent replacement across calls)? I assume this could further be
refined so that we still do replacement across calls if the source
operands of the expression are already live at the use point, but
haven't looked into that.
2) Is there a way to recognize the __builtin_XXX() calls such that we
know they result in simple insns an not a real call?
-Pat