I think I found something, see below. Answering the question first ;-)
Florian Klämpfl wroteHow big is the project? Normally, the number of unrolled loops is reasonable small so comparing the
generated assembler with and without unrolling should be feasible.According to cloc, 40kLOC, 10kLOC of which are DSP code, not counting packages
that are not in the source repo. With the very spurious crashes, not the best test case...
I did, however, do the insane thing and diff Lazarus (or rather, IDAs output). There are a lot of unrolled loops in the LCL alone, but the code reordering for the first 15% or so that I checked looks fine. {Off-Topic: could parts of that variable rewriting be used for more aggressive inlining?}
Some more testing with Lazarus and -gt has shown that at some variables are uninitialized with -Ooloopunroll. There is a fairly common case where removing the variable is not good:
-------------
for Result:= alow to ahigh do
if Something(Result) then exit;
-------------
If that gets unrolled, Result is undefined, and whatever it gets assigned to receives the random content of r/eax.
I'm 90% sure that global variables and the Result variable are *not* supposed to be undefined after the loop (in contrast to Delphi-compatible locals), but can't seem to find a reference for that. This pattern is used all over the place, so somebody else must have thought so too? Grepping for "for result:=" over the FPC source tree gives 10 matches, Lazarus has over 100 results.
Test case:
-------------
{$Optimization LOOPUNROLL}
var
i : integer;
s : single;
function tfun: integer;
begin
for Result:=1 to 10 do
s:=s+1;
end;
begin
s:=0.0;
for i:=1 to 2 do
s:=s+1;
if i 2 then
halt(1);
i:= tfun();
if i 10 then
halt(2);
if s 12 then
halt(3);
writeln('ok');
end.
-------------
I would very much expect that to be the main cause of the observed crashes.
Regards,
Martok