[fpc-pascal] Broken code with PEEPHOLE & REGVAR

Peter peter at pblackman.plus.com
Thu Mar 10 23:31:45 CET 2022


I've been working with a fork of C-evo for a while now.
Its been very stable for at least a year.
However, recently a game locked up in a (wide) cpu loop.
The broken code is in the shared library, built with FPC 3.2.2,
its nothing to do with Lazarus, except that Lazarus code calls the library.

I compiled a debug version to investigate and the problem went away.
It seemed likely that the issue was optimisations, and sure enough, O1 is fine but O2 broken.
Trying the optimisations individually I found that PEEPHOLE + REGVAR alone caused the problem.
The code actually works fine at O4, providing either PEEPHOLE or REGVAR is disabled.

This is with x64 on Debian Linux, but the problem is also on Arch Linux, so nothing specific with the Debian build.
Other options like Ct, Ci, Co, CR, Cr make no difference.
I tried FPC versions back to 3.0.4, and the issue is still there, so its not a recent regression.

Its unlikely that I can reproduce this problem with a small program,
but compiling the offending code to assembler, the problem seems rather obvious.

Its in a method function,

[500]  function TBarbarina.DoAttack(uix, AttackLoc: integer): boolean;

It seems that parameter AttackLoc is corrupted halfway through the routine, just after being used in an assignment,

[587]      TestLoc := AttackLoc;

If the parameter AttackLoc is used immediately after this statement, for example in a Writeln, its OK.
But if not, its corrupted when used later.

The problem looks like the register allocator,
as at line 587 the assembler comment says that AttackLoc is now in r13d,
but r13d has not been initialised. AttackLoc was in 83288(%rsp) up to this point.

Here is an extract of the assembler showing statements where AttackLoc is used
(to around the point where the problem occurs)

.....

# Var uix located in register eax
     movl    %edx,%eax
     movq    %rax,83288(%rsp)
# Var AttackLoc located in register eax
# [503] var

.....

# [514] IsBombardment := AttackLoc = maNextCity;
     movl    83288(%rsp),%eax
     cmpl    $-1,%eax

.....

# [531] if (TestTime >= $800) or (AttackLoc = maNextCity) and (TestTime > $800 - 100) then
     cmpl    $2048,%edx
     jge    .Lj281
     movl    83288(%rsp),%eax
     cmpl    $-1,%eax
     jne    .Lj284
     cmpl    $1948,%edx
     jg    .Lj281
.Lj284:

.....

# [548] AttackLoc := NextLoc;
     movl    %ebx,%eax
     movq    %rax,83288(%rsp)
.Lj298:
.Lj294:
# [550] if (NextLoc = AttackLoc) and ((MyModel[mix].Domain <> dSea) or
     movl    83288(%rsp),%eax
     cmpl    %ebx,%eax
     jne    .Lj301
     movq    83272(%rsp),%rax
     movq    48(%rax),%rcx
     movq    83280(%rsp),%rax
     movzwl    14(%rax),%edx
     imulq    $68,%rdx,%rax
     cmpb    $1,17(%rcx,%rax)
     jne    .Lj302

.....

# [587] TestLoc := AttackLoc;
     movl    83288(%rsp),%eax
# Var AttackLoc located in register r13d        ****************** !!!!
     movl    %eax,24(%rsp)

.....

# [605] until (NextLoc = AttackLoc) or (MoveResult and rExecuted = 0) or
     cmpl    %r12d,%r13d
     je    .Lj332
     movl    %ebx,%eax
     andl    $1073741824,%eax
     je    .Lj332

.....

# [607] Result := (NextLoc = AttackLoc) and (MoveResult and rExecuted <> 0);
     cmpl    %r12d,%r13d
     jne    .Lj338
     movl    %ebx,%eax
     andl    $1073741824,%eax
     je    .Lj338
     movb    $1,83240(%rsp)
     jmp    .Lj340
.Lj338:
     movb    $0,83240(%rsp)

.....


There are four source files, around 250k, to compile this library. I can supply them if anyone wants to investigate.
Is this sufficient for a bug report?  Does anyone know of any existing bugs like this? Maybe already fixed?

I'll attach the source and assembler for this routine in a follow up mail.


Cheers,
Peter








More information about the fpc-pascal mailing list