[fpc-devel] "Blank slate" next version of FPC

Benito van der Zander benito at benibela.de
Sat Feb 23 01:17:29 CET 2019


Hi,

> The trick with enumerators is to never make them classes, and use 
> advanced records instead, I've found. This way you avoid the heap 
> allocation and the implicit try/finally. Also make sure you inline the 
> MoveNext and GetCurrent!

that's what I do.


But the generated assembly is still worse than an old for loop, because 
it keeps all the fields of the record in memory.

for example

 >   for I in TSlice<SizeUInt>.TakeWhile(Arr, Test) do J := I;

generates something like this

0000000000401290 488b45f0                 mov -0x10(%rbp),%rax
0000000000401294 488b00                   mov    (%rax),%rax
0000000000401297 488905b22a0300           mov %rax,0x32ab2(%rip)        
# 0x433d50 <U_$P$PROJECT1_$$_I>
project1.lpr:75                           J := I;
000000000040129E 488905bb2a0300           mov %rax,0x32abb(%rip)        
# 0x433d60 <U_$P$PROJECT1_$$_J>
project1.lpr:74                           for I in 
TSlice<SizeUInt>.TakeWhile(Arr, Test) do
00000000004012A5 488345f008               addq   $0x8,-0x10(%rbp)
project1.lpr:69                           begin
00000000004012AA 488b45e8                 mov    -0x18(%rbp),%rax
project1.lpr:74                           for I in 
TSlice<SizeUInt>.TakeWhile(Arr, Test) do
00000000004012AE 483b45f0                 cmp    -0x10(%rbp),%rax
00000000004012B2 720a                     jb     0x4012be <main+334>
00000000004012B4 483b45e0                 cmp    -0x20(%rbp),%rax
00000000004012B8 7404                     je     0x4012be <main+334>
00000000004012BA b001                     mov    $0x1,%al
00000000004012BC eb02                     jmp    0x4012c0 <main+336>
00000000004012BE 30c0                     xor    %al,%al
00000000004012C0 84c0                     test   %al,%al
00000000004012C2 75cc                     jne    0x401290 <main+288>

Nearly every line is accessing some memory, when it could keep 
everything in a few registers. amd64 has 16 registers, but fpc seems to 
only know three when records are involved



Cheers,
Benito

Am 22.02.19 um 16:51 schrieb Ben Grasset:
> On Fri, Feb 22, 2019 at 1:07 AM Paul van Helden <paul at planetgis.co.za 
> <mailto:paul at planetgis.co.za>> wrote:
>
>      How do you make a (for in) enumerator with a record? I don't use
>     them for exactly this reason, and they did seem to be another
>     useful language feature that turned out to be poorly implemented
>     by Embarcadero. (Haven't checked with FPC).
>
>
> Here's an example (for FPC) that demonstrates it by implementing the 
> "take-while" pattern:
>
> program TakeWhileExample;
>
> {$mode Delphi}{$H+}{$J-}
> {$modeswitch NestedProcVars}
> {$ImplicitExceptions Off}
> {$PointerMath On}
>
> type
>   TSlice<T> = record
>   public type
>     PT = ^T;
>     ArrayType = array of T;
>   private
>     FFirst, FLast, FCurrent: PT;
>     function GetCurrent: T; inline;
>   public
>     function GetEnumerator: TSlice<T>; inline;
>     function MoveNext: Boolean; inline;
>     class function TakeWhile(const A: ArrayType; function F(const Val: 
> T): Boolean): TSlice<T>; static; inline;
>     property Current: T read GetCurrent;
>   end;
>
>   TTestFunc<T> = function(const Val: T): Boolean;
>
>   function TSlice<T>.GetCurrent: T;
>   begin
>     Result := FCurrent^;
>   end;
>
>   function TSlice<T>.GetEnumerator: TSlice<T>;
>   begin
>     Result := Self;
>     with Result do FCurrent := FFirst - 1;
>   end;
>
>   function TSlice<T>.MoveNext: Boolean;
>   begin
>     Inc(FCurrent);
>     Exit((FCurrent <= FLast) and (FFirst <> FLast));
>   end;
>
>   function Test(const Val: SizeUInt): Boolean; inline;
>   begin
>     Exit((Val < 50000000));
>   end;
>
>   class function TSlice<T>.TakeWhile(const A: ArrayType; function 
> F(const Val: T): Boolean): TSlice<T>;
>   var
>     I: SizeUInt;
>     X: TTestFunc<T> absolute F;
>     //FPC generates slightly better code for the "absolute" way, not 
> sure why...
>   begin
>     with Result do begin
>       FFirst := @A[0];
>       FLast := @A[0];
>       for I := 0 to High(A) do
>         case X(A[I]) of
>           True: Inc(FLast);
>           False: Exit();
>         end;
>     end;
>   end;
>
> var
>   I, J: SizeUInt;
>   Arr: TSlice<SizeUInt>.ArrayType;
>
> begin
>   SetLength(Arr, 100000000);
>   for I := 0 to 99999999 do Arr[I] := I;
>   I := 0;
>   J := 0;
>   for I in TSlice<SizeUInt>.TakeWhile(Arr, Test) do J := I;
>   WriteLn(J);
> end.
>
> _______________________________________________
> fpc-devel maillist  -  fpc-devel at lists.freepascal.org
> http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freepascal.org/pipermail/fpc-devel/attachments/20190223/67aff17f/attachment.html>


More information about the fpc-devel mailing list