The real and imag-pointers should be marked with "restrict"-keyword to enable aliasing optimizations. This goes for all other pointers also. And as others have already said, leaving optimzation at -O1 and not targeting your architecture (-march) can also have big impact.
real[j + halfsize] = real[j] - tpre;
imag[j + halfsize] = imag[j] - tpim; // 1. Reading imag[j]
real[j] += tpre; // 2. Writing real[j], which could be same data as imag[j]
imag[j] += tpim; // 3. Must re-read imag[j] even though we read it in #1, because real[j] might alias it