Invalid code generation for intel mode asm block with constants usage in reference expression
Summary
When using constants inside of asm block (in intel syntax) reference expression ([BASE + INDEX*SIZE + OFFSET]
, where SIZE and OFFSET are used as constants) the compiler produces invalid code.
I am worried about if it is a real bug or my misunderstanding on how it should work
System Information
- Operating system: Linux (Kubuntu 24.04)
- Processor architecture: x86-64
-
Compiler version:
Free Pascal Compiler version 3.3.1-18107-g994ebf55ec-dirty [2025/07/06] for x86_64
- Device: Compiler
Steps to reproduce
- Compile the example code
- Disassemble the binary
- Examine produced assembler
Example Project
program test_asm_bug;
{$Mode ObjFPC}
{$AsmMode Intel}
const
SizeConst = 4;
procedure Test; assembler;
asm
LEA RAX, [RCX + RDX*4 - 4]
LEA RAX, [RCX + RDX*SizeConst - SizeConst]
LEA RAX, [RCX + RDX*4 + 4]
LEA RAX, [RCX + RDX*SizeConst + SizeConst]
MOV RAX, [RCX + RDX*4 - 4]
MOV RAX, [RCX + RDX*SizeConst - SizeConst]
end;
begin
end.
What is the current bug behavior?
Produced assembler (dumped by objdump):
0000000000401090 <P$TEST_ASM_BUG_$$_TEST>:
const
SizeConst = 4;
procedure Test; assembler;
asm
401090: 50 push %rax
LEA RAX, [RCX + RDX*4 - 4]
401091: 48 8d 44 91 fc lea -0x4(%rcx,%rdx,4),%rax
LEA RAX, [RCX + RDX*SizeConst - SizeConst]
401096: 48 8d 04 11 lea (%rcx,%rdx,1),%rax
LEA RAX, [RCX + RDX*4 + 4]
40109a: 48 8d 44 91 04 lea 0x4(%rcx,%rdx,4),%rax
LEA RAX, [RCX + RDX*SizeConst + SizeConst]
40109f: 48 8d 04 d1 lea (%rcx,%rdx,8),%rax
MOV RAX, [RCX + RDX*4 - 4]
4010a3: 48 8b 44 91 fc mov -0x4(%rcx,%rdx,4),%rax
MOV RAX, [RCX + RDX*SizeConst - SizeConst]
4010a8: 48 8b 04 11 mov (%rcx,%rdx,1),%rax
end;
4010ac: 59 pop %rcx
4010ad: c3 ret
First, second and third pairs of instructions should provide the same code, because they are equal, yet compiler produces different instructions (and for expressions with constant it is wrong)
EDIT: When using LEA RAX,[RCX + SizeConst*RDX - SizeConst]
the compiler emits valid code
What is the expected (correct) behavior?
Corresponding pairs of LEA/MOV with and without constants usage should provide the same code
Relevant logs and/or screenshots
The bug reproduces even on the FPC 3.2.2 (tested on godbolt), this snippet:
unit output;
{$Mode ObjFPC}
{$AsmMode Intel}
interface
implementation
// Type your code here, or load an example.
const
SizeConst = 4;
procedure Test; assembler;
asm
LEA RAX, [RCX + RDX*4 - 4]
LEA RAX, [RCX + RDX*SizeConst - SizeConst]
LEA RAX, [RCX + RDX*4 + 4]
LEA RAX, [RCX + RDX*SizeConst + SizeConst]
MOV RAX, [RCX + RDX*4 - 4]
MOV RAX, [RCX + RDX*SizeConst - SizeConst]
end;
end.
provides
test():
leaq -8(%rsp),%rsp
leaq -4(%rcx,%rdx,4),%rax
leaq (%rcx,%rdx,1),%rax
leaq 4(%rcx,%rdx,4),%rax
leaq (%rcx,%rdx,8),%rax
movq -4(%rcx,%rdx,4),%rax
movq (%rcx,%rdx,1),%rax
leaq 8(%rsp),%rsp
ret