Skip to content

Inline generates invalid code / bug in code-generator / 3.2.3 (likely 3.2.4 RC and also likely 3.3.1)

Summary

When inlining code the compiler generates bad/incorrect code.

Under some circumstances inlined code will use the same physical memory in its stackframe for one of its own locals (params), as the containing code does use for one of its locals.

The inlined function incorrectly changes the callers local var

Tt behaves as if the param was a "var param" => but it is not...

This happens

  • with peephole disabled. / also happens with its enabled.
  • opt regvar can also be enabled or disabled

System Information

  • Operating system: Windows 10 / 64bit Intel
  • Compiler version: 3.2.3 420f7af2 // likely also 3.3.1 and the RC of 3.2.4

Steps to reproduce

See attached. Compile with fpc.exe -O1 -vn- -vw- -Sa -uni -gw3 prog.lpr

Example Project

fpc_inline.zip

Relevant logs and/or screenshots

  • procedure TTestRunnerListAnsiString.DoTestInsert; invokes TstLst.InsertRows(i,1); (which is inlined )
  • function TGenLazRoundList.InsertRows(AIndex, ACount: Integer): TPItemT; inlines function TGenLazRoundList.GetItemPointerFast(Index: Integer): TPItemT;
  • TGenLazRoundList.InsertRows calls PSource := PByte(ItemPointerFast[Cnt]); (line 817) in the "else" block
  • GetItemPointerFast changes the local var Cnt of the caller.
  • GetItemPointerFast does not have a var param, so it should not change the callers local

In the zip is also an asm extract (from the debugger) of TGenLazRoundList.InsertRows with some blocks commented to which line they belong.

At the start

####  Cnt := FMem.Count;
                      ################ cnt in [rbp-$34]
0000000100002482 C745CC00000000           mov [rbp-$34],$00000000
0000000100002489 EB0A                     jmp +$0A    # $0000000100002495 DoTestInsert+165 prog.lpr:90
000000010000248B 488B45F0                 mov rax,[rbp-$10]
000000010000248F 8B4008                   mov eax,[rax+$08]
0000000100002492 8945CC                   mov [rbp-$34],eax

Cnt is stored in [rbp-$34]

Rbp does not change when ItemPointerFast is entered (the inlined copy)

From within the inlined ItemPointerFast:

#########################<<<<<<<<<<<<<<<<<<<<<<<<<<
#<<##    Index := Index - c;
00000001000026F4 8B45CC                   mov eax,[rbp-$34]
00000001000026F7 8B5588                   mov edx,[rbp-$78]
00000001000026FA 29D0                     sub eax,edx
00000001000026FC 8945CC                   mov [rbp-$34],eax
00000001000026FF 90                       nop
#########################<<<<<<<<<<<<<<<<<<<<<<<<<<

When the local value of Index in ItemPointerFast is stored, it is stored to [rbp-$34] and change the value of Cnt for the caller.

Index needs a separate location on the stack

Note, the code has various optimizations turned off. Not sure if they mattered / left overs from tracking the issue down.

But this does include

  {$Optimization noREGVAR}
  {$Optimization noPEEPHOLE}

So it is not the peephole. (or it should not be?)

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information