* * *

Author Topic: code generation for var and out parameters  (Read 528 times)

440bx

  • Sr. Member
  • ****
  • Posts: 256
code generation for var and out parameters
« on: July 11, 2018, 10:24:33 am »

Hello,

I'm currently RTFM Programmer's Reference and getting acquainted with FPC.  On page 198, the following program appears to illustrate the use of out vs var.

What is interesting is that the code that is generated to pass an out parameter is different than the code generated to pass a var parameter.
Code: Pascal  [Select]
  1. {$H-}
  2.  
  3. program OutParameters;
  4.  
  5. Procedure DoA(var A : integer);
  6. begin
  7.   A := 2;
  8.   writeln(A);
  9. end;
  10.  
  11. procedure DoB(out B : integer);
  12. begin
  13.   B := 3;
  14.   writeln(B);
  15. end;
  16.  
  17. var
  18.   C, D : integer;
  19.  
  20. begin
  21.   DoA(C);
  22.   DoB(D);
  23. end.
  24.  
In the case of the var parameter, the address of the parameter is first loaded into rax then moved into rcx as shown below (debugger assembly view) whereas in the case of the out parameter, the address is loaded directly into rcx.

Quote
OutParameters.lpr:21                      DoA(C);
000000010000150A 488d05efda0000           lea    0xdaef(%rip),%rax       
0000000100001511 4889c1                   mov    %rax,%rcx
0000000100001514 e847ffffff               callq  0x100001460 <DOA>

In the case of the out parameter, the address of the parameter is directly
loaded into rcx.

OutParameters.lpr:22                      DoB(D);
0000000100001519 488d0df0da0000           lea    0xdaf0(%rip),%rcx       
0000000100001520 e88bffffff               callq  0x1000014b0
<DOB>


It seems that when using a var parameter, the address of the parameter is not passed optimally, yet the compiler knows how to generate optimal code since it does for the out parameter.

Note: The above code is the result of compiling with -03 optimizations.


Jonas Maebe

  • Hero Member
  • *****
  • Posts: 578
Re: code generation for var and out parameters
« Reply #1 on: July 11, 2018, 10:34:35 am »
When code initially gets generated, it is full of those superfluous register move operations. The register allocator then removes most of them, but it indeed does not always succeed. There is no inherent difference between the code generation for var and out parameters.

It's possible that if you reverse the order of the calls, the extra move will appear for the other one instead.

ASerge

  • Hero Member
  • *****
  • Posts: 904
Re: code generation for var and out parameters
« Reply #2 on: July 11, 2018, 10:51:01 am »
It's possible that if you reverse the order of the calls, the extra move will appear for the other one instead.
+1
For
Code: Pascal  [Select]
  1. begin
  2.   DoB(D);
  3.   DoA(C);
  4.   DoA(C);
  5.   DoB(D);
  6. end.
generate
Code: ASM  [Select]
  1. project1.lpr:18                           DoB(D);
  2. 000000010000155E 488d059f0a0100           lea    0x10a9f(%rip),%rax        # 0x100012004
  3. 0000000100001565 4889c1                   mov    %rax,%rcx
  4. 0000000100001568 e883ffffff               callq  0x1000014f0 <DOB>
  5. project1.lpr:19                           DoA(C);
  6. 000000010000156D 488d0d8c0a0100           lea    0x10a8c(%rip),%rcx        # 0x100012000
  7. 0000000100001574 e817ffffff               callq  0x100001490 <DOA>
  8. project1.lpr:20                           DoA(C);
  9. 0000000100001579 488d0d800a0100           lea    0x10a80(%rip),%rcx        # 0x100012000
  10. 0000000100001580 e80bffffff               callq  0x100001490 <DOA>
  11. project1.lpr:21                           DoB(D);
  12. 0000000100001585 488d0d780a0100           lea    0x10a78(%rip),%rcx        # 0x100012004
  13. 000000010000158C e85fffffff               callq  0x1000014f0 <DOB>]

440bx

  • Sr. Member
  • ****
  • Posts: 256
Re: code generation for var and out parameters
« Reply #3 on: July 11, 2018, 11:01:53 am »
The register allocator then removes most of them, but it indeed does not always succeed. There is no inherent difference between the code generation for var and out parameters.

I thought the optimizer might have been a bit lazy with -01 and thought that with -03, it would probably take care of it.  As far as there not being a difference for var and out parameters, I concur, that's why I was a bit surprised that the generated code was not the same and thought asking the compiler for deeper/greater optimization would make the superfluous load be eliminated. 

It's possible that if you reverse the order of the calls, the extra move will appear for the other one instead.

As Serge's code above showed, the superfluous load/move only occurs for the first call.  That is very interesting.

Thank you and thank Serge for your comments on this.
« Last Edit: July 11, 2018, 11:07:23 am by 440bx »

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus