Mailing lists / fpc-pascal / 2013-10
Argument evaluation order in Free Pascal and Delphi
11 messages · 6 people · –
- JJonas Maebe 3
- MMichael Van Canneyt 3
- SSven Barth 2
- DDmitry Pribysh 1
- Lleledumbo 1
- MMichael Schnell 1
Reply by email Subscribe to this list Your subscription
Read-only archive. Use j and k to move between messages.
And is there any way to force left-to-right parameter evalution order?
Evaluate the parameter separately from the function call, in your expected order.
Dmitry Pribysh wroteHi, As it is written in Free Pascal wiki, order of parameter evaluation is not defined in FPC, but it is defined in Delphi (Delphi guarantees left-to-right evaluation order).
Strange. Where is that documented ?
Michael.
"Michael Van Canneyt" wrote 8 lines
not defined in FPC, but it is defined in Delphi (Delphi
> guarantees left-to-right evaluation order). Strange. Where is that documented ?
We document it ourselves here:
http://wiki.freepascal.org/Code_Conversion_Guide#Order_of_parameter_evaluation The Delphi documentation is however rather vague:
http://docwiki.embarcadero.com/RADStudio/XE5/en/Procedures_and_Functions#Calling_Conventions
Regards,
Sven
Strange. Where is that documented ? Michael.
Michael Van Canneyt wrote 6 lines
In the Delphi documentation in the past, but apparently this has changed (both the documentation and the implementation). Now it says that the order is undefined. See http://stackoverflow.com/questions/11010456/in-delphi-are-parameters-evaluated-in-order-when-passed-into-a-method, the linked Delphi documentation page at http://docwiki.embarcadero.com/RADStudio/XE5/en/Procedures_and_Functions#Calling_Conventions and Barry Kelly's blog post from 2008 at http://blog.barrkel.com/2008/04/c-evaluation-order-gotcha.html?m=1
Jonas
not defined in FPC, but it is defined in Delphi (Delphi We document it ourselves here:…
Sven Barth wrote 18 lines
This I know, I meant where is the delphi documentation of left-to-right evaluation order ?
The Delphi documentation is however rather vague: http://docwiki.embarcadero.com/RADStudio/XE5/en/Procedures_and_Functions#Calling_Conventions
I know this, and it says explicitly
"For the register and pascal conventions, the evaluation order is not defined."
Which is why I thought the original poster's statement to be wrong.
But maybe Delphi changed since I last read that, but apparently not.
Michael.
Michael Van Canneyt wrote 9 lines
I think they use "evaluation order" as a synonym for "parameter passing order" on that page, given the table below: it says that the order in which the parameters are passed for register/pascal is undefined. That basically means that pure assembler routines using the register or pascal calling conventions are no longer supported in Delphi, since you can't know how the parameters are passed (or at least there are no guarantees about it).
Jonas
Jonas Maebe wrote 19 lines
Probably a consequence of their adding a new llvm backend architecture.
Michael.
Michael Van Canneyt wrote 14 lines
I also thought that at first, but on the other hand LLVM doesn't have any built-in support for "a calling convention that passes parameters in registers whereby the callee is responsible for the stack cleanup", and yet Embarcardero still advertises the "register" calling convention as doing exactly that (I guess as an alternative for "pascal", they can use stdcall since that one also passes everything on the stack and has callee-side cleanup iirc). If they added it themselves in a private LLVM branch, I don't understand why they didn't implement it in a way that was compatible with existing code.
Jonas
Dmitry Pribysh wrote 5 lines
IMHO =in fact evaluation of a parameter should not be compiler should be free to inline a function, detect that the parameter is not necessary for the evaluation of the function result and drop the evaluation of the parameter (maybe giving a warning or error message if that might trigger side-effects).
-Michael
Michael Schnell wrote 12 lines
1. FPC does not guarantee evaluation order exactly for this reason
2. The compiler already does this inlining already in that way (at least partially).
Take this code:
=== code begin ===
program tinlinetest;
{$mode objfpc}
function GetStr1: String; inline;
begin
Result := 'Hello World';
end;
function GetStr2: String;
begin
Result := 'Hello World';
end;
function Test(aArg1: Integer; aArg2: String): Integer; inline;
begin
Result := aArg1 * 42;
end;
begin
Writeln(Test(42, 'Hello World'));
Writeln(Test(42, GetStr1));
Writeln(Test(42, GetStr2));
end.=== code end ===
this will produce this output in the main function (2.7.1 and compiled with -O2):
=== assembler begin ===
PASCALMAIN:
.globl _main
_main:
# Temps allocated between esp+0 and esp+512
# [20] begin
pushl %ebx
addl $-512,%esp
call FPC_INITIALIZEUNITS
# [21] Writeln(Test(42, 'Hello World'));
// No usage of 'Hello World' constant here
call fpc_get_output
movl %eax,%ebx
movl %ebx,%edx
movl $1764,%ecx
movl $0,%eax
call fpc_write_text_sint
call FPC_IOCHECK
movl %ebx,%eax
call fpc_writeln_end
call FPC_IOCHECK# [22] Writeln(Test(42, GetStr1));
// here this might be a bug... the compiler inlines GetStr1, but doesnot detect that its result is constant and not used... call fpc_get_output
movl %eax,%ebx
movl $_$TINLINETEST$_Ld1,%ecx
leal 256(%esp),%eax
movl $255,%edx
call fpc_shortstr_to_shortstr
leal 256(%esp),%ecx
movl %esp,%eax
movl $255,%edx
call fpc_shortstr_to_shortstr
movl $1764,%ecx
movl %ebx,%edx
movl $0,%eax
call fpc_write_text_sint
call FPC_IOCHECK
movl %ebx,%eax
call fpc_writeln_end
call FPC_IOCHECK
# [23] Writeln(Test(42, GetStr2));
// here it can not inline GetStr2, because it can not detect whetherGetStr2 is sideeffect free
call fpc_get_output
movl %eax,%ebx
leal 256(%esp),%eax
call P$TINLINETEST_$$_GETSTR2$$SHORTSTRING
leal 256(%esp),%ecx
movl %esp,%eax
movl $255,%edx
call fpc_shortstr_to_shortstr
movl $1764,%ecx
movl %ebx,%edx
movl $0,%eax
call fpc_write_text_sint
call FPC_IOCHECK
movl %ebx,%eax
call fpc_writeln_end
call FPC_IOCHECK
# [24] end.
call FPC_DO_EXIT
addl $512,%esp
popl %ebx
ret
=== assembler end ===
So case 2 could be improved a bit.
And for case 3 it might be interesting to have the compiler mark functions with additional flags to check whether they are e.g. "constant" or access memory (aside from parameters) in a writing way, etc. This *might* improve some optimizations...
Regards,
Sven
