I made a minor modification to my rather old and well tested FFT unit, and suddenly got an error 216 at runtime, when having compiled with optimisation level 2. Range Check ON makes the issue disappear, so this is NOT an issue related to violation of array bounds or similar.
I stripped the code down into a small compilable program, and am fairly certain this is a bug in the L2 optimiser. The behaviour is strange, the error happens in line 42 but disappears when making trivial changes almost anywhere in procedure FFT. I did not manage to reduce the code any further without the issue diappearing.
Can someone please confirm before I file a bug report. I used the textmode IDE under windows, FPC 3.2.0, i386-win32. Settings which matter are optimizer level 2, range checks OFF, generate smaller code OFF, integer overflow checking OFF.
Or just compile with fpc -O2 crashme, and run.
{$mode objfpc}
type float = double;
complex = record re, im: float; end;
TRealVec = array of float;
TComplexVec = array of complex;
var TwiTab: TComplexVec;
procedure CalcTable (len: longint);
begin
SetLength (TwiTab, len);
writeln ('TwiTab set to size ',len);
end;
function WindowVec (len: longint): TRealVec;
begin
SetLength (result, len);
writeln ('Result set to size ',len);
end;
procedure FFT (const Z: TRealVec; var OutVec: TComplexVec);
var j, i, M, Half_M: longint;
V1, V2, W1, W2 : complex;
scale: float;
WinVec: TRealVec;
BufVec: TComplexVec;
begin
M := length (Z);
if (M <= 1) or (M and (M-1) <> 0) then halt;
Half_M := M div 2;
SetLength (OutVec, M);
SetLength (BufVec, Half_M);
scale := sqrt(2)/Half_M/4;
WinVec := WindowVec (M);
for i := 0 to Half_M-1 do begin
Bufvec[i].Re := Z[2*i ] * WinVec[2*i] * scale; // runtime error 216 here
Bufvec[i].Im := Z[2*i+1] * WinVec[2*i+1] * scale;
end;
CalcTable (Half_M);
writeln ('We never arrive at this point ');
//we never arrive here, but nonetheless changes to the code further down solve the issue
SetLength (BufVec, Half_M+1);
BufVec[Half_M] := BufVec[0];
for i := 0 to Half_M -1 do begin
j := Half_M-i;
V1.re := BufVec[i].re + BufVec[j].re;
V1.im := BufVec[i].im - BufVec[j].im;
V2.re := BufVec[i].im + BufVec[j].im;
V2.im := -BufVec[i].re + BufVec[j].re;
with TwiTab[i] do begin
OutVec[i].re := V1.re + V2.re * re + V2.im * im;
OutVec[i].im := V1.im + V2.im * re - V2.re * im;
end;
end;
for i := 1 to Half_M -1 do begin
// writeln (i:4,Half_M-i:4); // dummy code here solves the issue in line 42
OutVec[M-i].re := OutVec[i].re;
OutVec[M-i].im := -OutVec[i].im;
end;
end;
var Z: TRealVec;
C: TComplexVec;
begin
SetLength (Z,32);
FFT (Z, C);
end.