Consider the following piece of code:
void innermost_loop(int i, double d1, double d2, double delta, int n, double cells[n]) { int j; const double d1d = d1 * delta; const double d2d = d2 * delta; for (j = 0; j <= i; j++) cells[j] = d1d * cells[j + 1] + d2d * cells[j]; }
When compiling at -Ofast level, after the "Reassociate expressions"
pass, this code is transformed into an equivalent of:
int j; for (j = 0; j <= i; j++) cells[j] = (d1 * cells[j + 1] + d2 * cells[j]) * delta;
Effectively, the computation of those loop invariants isn't done
before the loop anymore, we have one extra multiplication on each
loop iteration instead. Sadly, this results in a significant
performance hit.
This patch makes the OptimizeAdd() function of the "Reassociate
expressions" pass aware of modifying operations in a loop and
bails out when some of the operands are pulled from the outside
of the loop.
These need to be fetched from the pass manager instead.