[fpc-pascal] Setting record values

Sven Barth pascaldragon at googlemail.com
Sun Apr 2 17:51:38 CEST 2017


On 01.04.2017 09:59, Ryan Joseph wrote:
> 
>> On Apr 1, 2017, at 2:46 PM, Sven Barth via fpc-pascal <fpc-pascal at lists.freepascal.org> wrote:
>>
>> I haven't looked at it in detail, but it could be that both have similar efficiency. You could also add "inline" to the MakePoint function which should get rid of a potential temporary variable if the compiler doesn't do that already anyway.
>> Alternatively you could also declare a constructor "TPoint.Make" or so (that despite its name doesn't do any dynamic memory allocation either) which you can declare as inline as well.
> 
> How is the constructor any different from the function?

In case of constructor vs. global function the encapsulation is more clear.
In case of constructor vs. class function there isn't really that much
difference except that through the name alone ("constructor blabla")
it's clear what the purpose of the function should be.

(Though I now also noticed that you can't use "inline" with constructors...)

>>
>> In the end you can always check the assembler code.
> 
> Not sure how to do that or what to look for. It appears to me without knowing how the compiler works that there would be some allocating and copying of memory which is more overhead than assigning a value directly. Maybe it’s totally trivial but if it is it’s something I should cut out of my design going forward.

The compiler keeps the assembler code with line information around if
you pass "-al".

If you are so concerned about the differences in performance regarding
using a setter and a construction function you should really learn at
least in principle how typical assembler code generated by the compiler
looks like (same for your query about dynamic arrays by the way, though
there you should also take a look at the implementation of the RTL).

Here is an example compiled without optimizations aside from inline:

=== code begin ===

# [47] p.&Set(42, 21);
        movq    $U_$P$TRECFUNCS_$$_P,%rax
        movl    $21,%edx
        movl    $42,%esi
        movq    %rax,%rdi
        call    P$TRECFUNCS$_$TPOINT_$__$$_SET$LONGINT$LONGINT
# [48] p := TPoint.Make(42, 21);
        leaq    -8(%rbp),%rdi
        movl    $21,%edx
        movl    $42,%esi
        call    P$TRECFUNCS$_$TPOINT_$__$$_MAKE$LONGINT$LONGINT$$TPOINT
        movq    -8(%rbp),%rax
        movq    %rax,U_$P$TRECFUNCS_$$_P
# [49] p := TPoint.Make2(42, 21);
        movl    $42,U_$P$TRECFUNCS_$$_P
        movl    $21,U_$P$TRECFUNCS_$$_P+4
# [50] p := MakePoint(42, 21);
        movl    $21,%esi
        movl    $42,%edi
        call    P$TRECFUNCS_$$_MAKEPOINT$LONGINT$LONGINT$$TPOINT
        movq    %rax,U_$P$TRECFUNCS_$$_P
# [51] p := MakePoint2(42, 21);
        movl    $42,U_$P$TRECFUNCS_$$_P
        movl    $21,U_$P$TRECFUNCS_$$_P+4

=== code end ===

"&Set" is essentially your "SetPoint" method. "Make" is a constructor.
"Make2" is a static class function with "inline". "MakePoint" is your
creation function and "MakePoint2" is the same with an inline modifier.

As you can see the two inline variants ("Make2" and "MakePoint2") are
the most effective as there's no call and only the two loads of the values.

Regards,
Sven



More information about the fpc-pascal mailing list