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
Relevant logs and/or screenshots
-
procedure TTestRunnerListAnsiString.DoTestInsert;
invokesTstLst.InsertRows(i,1);
(which is inlined ) -
function TGenLazRoundList.InsertRows(AIndex, ACount: Integer): TPItemT;
inlinesfunction TGenLazRoundList.GetItemPointerFast(Index: Integer): TPItemT;
-
TGenLazRoundList.InsertRows
callsPSource := PByte(ItemPointerFast[Cnt]);
(line 817) in the "else" block -
GetItemPointerFast
changes the local varCnt
of the caller. -
GetItemPointerFast
does not have avar 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?)