The Compiler Will Not Reassociate

This double-precision sum runs at 3.01 cycles per element, matching the 3-cycle FP add latency:

double s = 0.0;
for (long i = 0; i < n; i++)
    s = s + d[i];

You rewrite it by hand with four accumulators and get 1.01, the best this part can do for scalar FP addition. A reviewer objects:

Delete the hand-rolled version. -O3 unrolls loops; the compiler will do this transformation itself and the original is readable.

You check the assembly at -O3 and the compiler did unroll the loop, but kept one accumulator and the CPE is still 3.01. Why?

A

The compiler cannot prove the array does not alias the accumulator, so it must reload after every store.

B

Floating-point addition is not associative, so splitting the sum into four partial sums can change the result; the compiler is not allowed to do it unless you pass a flag such as -ffast-math that waives IEEE semantics.

C

-O3 unrolls only loops whose trip count is a compile-time constant, and this one is not.

D

Four accumulators exceed the number of available architectural registers, so the compiler spills them and gains nothing.