Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.forth > #59178 > unrolled thread

Forth-94 vs. Forth-2012 FP data (long)

Started byanton@mips.complang.tuwien.ac.at (Anton Ertl)
First post2017-05-13 07:34 +0000
Last post2017-05-17 15:02 +0000
Articles 11 on this page of 31 — 9 participants

Back to article view | Back to comp.lang.forth


Contents

  Forth-94 vs. Forth-2012 FP data (long) anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2017-05-13 07:34 +0000
    Re: Forth-94 vs. Forth-2012 FP data (long) pahihu <pahihu@gmail.com> - 2017-05-13 11:16 -0700
      Re: Forth-94 vs. Forth-2012 FP data (long) pahihu <pahihu@gmail.com> - 2017-05-13 11:49 -0700
        Re: Forth-94 vs. Forth-2012 FP data (long) pahihu <pahihu@gmail.com> - 2017-05-13 13:38 -0700
          Re: Forth-94 vs. Forth-2012 FP data (long) mhx@iae.nl - 2017-05-13 15:08 -0700
            Re: Forth-94 vs. Forth-2012 FP data (long) pahihu <pahihu@gmail.com> - 2017-05-14 00:51 -0700
            Re: Forth-94 vs. Forth-2012 FP data (long) anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2017-05-14 07:32 +0000
              Re: Forth-94 vs. Forth-2012 FP data (long) mhx@iae.nl - 2017-05-14 02:46 -0700
                Re: Forth-94 vs. Forth-2012 FP data (long) anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2017-05-14 14:57 +0000
                  Re: Forth-94 vs. Forth-2012 FP data (long) krishna.myneni@ccreweb.org - 2017-05-15 19:11 -0700
      Re: Forth-94 vs. Forth-2012 FP data (long) anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2017-05-14 08:14 +0000
    Re: Forth-94 vs. Forth-2012 FP data (long) Paul Rubin <no.email@nospam.invalid> - 2017-05-13 15:58 -0700
      Re: Forth-94 vs. Forth-2012 FP data (long) anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2017-05-14 07:01 +0000
    Re: Forth-94 vs. Forth-2012 FP data (long) krishna.myneni@ccreweb.org - 2017-05-14 19:04 -0700
      Re: Forth-94 vs. Forth-2012 FP data (long) anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2017-05-15 06:10 +0000
        Re: Forth-94 vs. Forth-2012 FP data (long) krishna.myneni@ccreweb.org - 2017-05-15 01:49 -0700
          Re: Forth-94 vs. Forth-2012 FP data (long) anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2017-05-15 14:33 +0000
    Re: Forth-94 vs. Forth-2012 FP data (long) "HAA" <someone@microsoft.com> - 2017-05-15 13:44 +1000
      Re: Forth-94 vs. Forth-2012 FP data (long) Andrew Haley <andrew29@littlepinkcloud.invalid> - 2017-05-15 04:43 -0500
      Re: Forth-94 vs. Forth-2012 FP data (long) anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2017-05-15 15:03 +0000
        Re: Forth-94 vs. Forth-2012 FP data (long) "HAA" <someone@microsoft.com> - 2017-05-17 00:10 +1000
    Re: Forth-94 vs. Forth-2012 FP data (long) pahihu <pahihu@gmail.com> - 2017-05-16 09:04 -0700
      Re: Forth-94 vs. Forth-2012 FP data (long) anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2017-05-17 15:54 +0000
        Re: Forth-94 vs. Forth-2012 FP data (long) mhx@iae.nl - 2017-05-17 10:29 -0700
        Re: Forth-94 vs. Forth-2012 FP data (long) pahihu <pahihu@gmail.com> - 2017-05-17 23:53 -0700
          Re: Forth-94 vs. Forth-2012 FP data (long) pahihu <pahihu@gmail.com> - 2017-05-19 02:34 -0700
    Re: Forth-94 vs. Forth-2012 FP data (long) Joel Rees <joel.rees@gmail.com> - 2017-05-16 22:48 -0700
      Re: Forth-94 vs. Forth-2012 FP data (long) anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2017-05-17 06:51 +0000
        Re: Forth-94 vs. Forth-2012 FP data (long) Joel Rees <joel.rees@gmail.com> - 2017-05-17 09:29 -0700
      Re: Forth-94 vs. Forth-2012 FP data (long) stephen@mpeforth.com (Stephen Pelc) - 2017-05-17 11:07 +0000
        Re: Forth-94 vs. Forth-2012 FP data (long) anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2017-05-17 15:02 +0000

Page 2 of 2 — ← Prev page 1 [2]


#59371

From"HAA" <someone@microsoft.com>
Date2017-05-17 00:10 +1000
Message-ID<off1fm$f7n$1@gioia.aioe.org>
In reply to#59314
Anton Ertl wrote:
> "HAA" <someone@microsoft.com> writes:
> >How about this for an 'empirical' check.  Write a real-world application
> >for which hardware f/p is not available.  Implement it using combined
> >and separate stack f/p.  Compare the performance and memory used.
> >Expect to see much difference?  Neither do I.
>
> I didn't expect it for the matrix multiplication case, but I actually
> measured it and found a difference, and found an explanation for the
> difference.  Maybe you should actually read the whole posting before
> replying.

Performance has never been the sole criteria by which TC's made
decisions, so let's ditch that as a reason for excluding common
stacks systems from 2012.

What's left is the alleged difficulty ANS imposed on f/p programmers.
It's been claimed by you - and now by 2012 (C.7.2) - that ANS required
programmers to either code for a common stack, or to declare a
dependency on a separate stack.  There is in fact no such stipulation
in ANS - quite the opposite.  Sections or parts thereof in ANS which
dispelled such allegations have been either removed or reworded by
2012, leaving the reader to believe 2012 has given them something
they didn't, or couldn't, have with ANS.  Here's what ANS said
(emphasis added):

12.3.3

    "BY DEFAULT the floating-point stack SHALL be separate from
    the data and return stacks.
    A program MAY determine whether floating-point numbers are
    kept on the data stack by passing the string "FLOATING-STACK"
    to ENVIRONMENT?."

A.12

    "Floating-point stack: BY DEFAULT the floating-point stack IS
    separate from the data and return stacks; HOWEVER, an
    implementation MAY keep floating-point numbers on the data
    stack."

ANS left no doubt "separate stack" is the "default" and common stack
was an option for implementers who wanted or needed it.  ANS went to
pains to over this e.g. FDEPTH refers to the "default separate floating-
point stack".

Is a separate stack program required to declare a dependency on a
separate stack?  Logically it would be redundant since ANS stated
separate stack is the default.  In any case no such dependency is listed:

12.4.2 Program documentation

12.4.2.1 Environmental dependencies
      - requiring the floating-point stack to be larger than six items
     (12.3.3 Floating-point stack).

12.4.2.2 Other program documentation
      - no additional requirements.

Had 200x TC found ANS' statements ambiguous (hard to believe had they
actually read ANS), could they have rewritten them without having to remove
common stack systems?  I don't see why not.  So why were common stack
systems excluded from 2012?  I believe the answer can be found here:

    "Whilst every sane Forth has a separate floating-point stack,
    it is not strictly required; an ANS Forth system could theoretically
    keep floating-point numbers on the data stack.  As an additional
    difficulty, you don't know how many cells a floating-point number
    takes. It is reportedly possible to write words in a way that they
    work also for a unified stack model, but we do not recommend
    trying it."

That statement, which has appeared in gforth's documentation since
at least 1998, presents an opinion.  It is clear the author holds a view
that is intolerant of combined stack f/p and of those who implement it.

> If we did not put common practice in the standard, we would
> not be doing our job.

Removing common stack implementations with no technical justification.
Propagating opinion and statements known to be fallacious, or at the
very least, contentious.  Including these in a Standard document as fact.
Is this the job of a responsible technical committee which claims to
speak on behalf of Forth users?


[toc] | [prev] | [next] | [standalone]


#59379

Frompahihu <pahihu@gmail.com>
Date2017-05-16 09:04 -0700
Message-ID<047bed2a-b743-40dc-b978-aa592d3797f9@googlegroups.com>
In reply to#59178
> If you don't have a compiler that optimizes PICK (e.g., gforth-fast),
> Forth-2012 provides a significant performance benefit (in addition to
> the programming convenience benefit) over Forth-94; even for VFX with
> Ndp387, there is a small benefit for the Forth-2012 variant.

You can even write a PICK-less variant in ANS-94, which does not depend
on the FP cell width. Testing on SwiftForth, iForth, VFX, gforth I don't
see clear performance advantage of the separate FP stack version either.

pahihu

fvariable faxpy-ra \ should be a user variable
: faxpy-nostride941 ( ra f_x f_y ucount -- )
    \ vy=ra*vx+vy
    >r 2>r faxpy-ra f! 2r> r>
    0 ?DO ( f_x1 f_y1 )
        >R
        dup float+ swap f@
        faxpy-ra f@ f*
        R@ f@ f+ R@ f!
        R> float+
  LOOP
  2drop ;

[toc] | [prev] | [next] | [standalone]


#59432

Fromanton@mips.complang.tuwien.ac.at (Anton Ertl)
Date2017-05-17 15:54 +0000
Message-ID<2017May17.175419@mips.complang.tuwien.ac.at>
In reply to#59379
pahihu <pahihu@gmail.com> writes:
>You can even write a PICK-less variant in ANS-94, which does not depend
>on the FP cell width. Testing on SwiftForth, iForth, VFX, gforth I don't
>see clear performance advantage of the separate FP stack version either.
>
>pahihu
>
>fvariable faxpy-ra \ should be a user variable
>: faxpy-nostride941 ( ra f_x f_y ucount -- )
>    \ vy=ra*vx+vy
>    >r 2>r faxpy-ra f! 2r> r>
>    0 ?DO ( f_x1 f_y1 )
>        >R
>        dup float+ swap f@
>        faxpy-ra f@ f*
>        R@ f@ f+ R@ f!
>        R> float+
>  LOOP
>  2drop ;

Looks better than the PICK-heavy variant, but still cumbersome
compared to the Forth-2012 version.

Performance: On a Core i7-4690K (no SwiftForth or iForth installed),
with the unrolled versions:

cycles
Forth-2012 Forth-94  Forth-94
           Rees/Ertl pahihu
2929M      3691M     3480M  gforth-fast
1289M      1414M     1574M  vfxlin Ndp387

Looks like a win for the Forth-2012 code to me.

The inner loop for the non-unrolled variants are on VFX:

Forth-2012             Forth-94 Rees/Ertl        Forth-94 pahihu
FLD   ST               MOV   EDX, [EBP]          PUSH  EBX             
MOV   EDX, [EBP]       FLD   TBYTE 0 [EDX]       MOV   EBX, [EBP]      
FLD   TBYTE 0 [EDX]    FLD   TBYTE [080A3460]    MOV   EDX, EBX        
FMULP ST(1), ST        FMULP ST(1), ST           ADD   EBX, 0A         
FLD   TBYTE 0 [EBX]    FLD   TBYTE 0 [EBX]       FLD   TBYTE 0 [EDX]   
FADDP ST(1), ST        FADDP ST(1), ST           FLD   TBYTE [080A3460]
FSTP  TBYTE 0 [EBX]    FSTP  TBYTE 0 [EBX]       FMULP ST(1), ST       
ADD   EBX, 0A          ADD   EBX, 0A             MOV   EDX, [ESP]      
MOV   EDX, [EBP]       MOV   EDX, [EBP]          FLD   TBYTE 0 [EDX]   
ADD   EDX, 0A          ADD   EDX, 0A             FADDP ST(1), ST       
ADD   [ESP], 01        ADD   [ESP], 01           MOV   EDX, [ESP]      
ADD   [ESP+04], 01     ADD   [ESP+04], 01        FSTP  TBYTE 0 [EDX]   
MOV   [EBP], EDX       MOV   [EBP], EDX          POP   EDX             
JNO   080C6D78         JNO   080C6DB8            ADD   EDX, 0A         
                                                 ADD   [ESP], 01       
                                                 ADD   [ESP+04], 01    
                                                 MOV   [EBP], EBX      
                                                 MOV   EBX, EDX        
                                                 JNO   080C6A88        

VFX does not (yet?) analyse and optimize the return stack; or, if you
feel nasty, you could say: it optimizes PICK better than >R R> and R@.

- anton
-- 
M. Anton Ertl  http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
     New standard: http://www.forth200x.org/forth200x.html
   EuroForth 2017: http://www.euroforth.org/ef17/

[toc] | [prev] | [next] | [standalone]


#59439

Frommhx@iae.nl
Date2017-05-17 10:29 -0700
Message-ID<d86e3505-db26-4e5b-b615-e61cea93c9f6@googlegroups.com>
In reply to#59432
On Wednesday, May 17, 2017 at 6:14:04 PM UTC+2, Anton Ertl wrote:
> pahihu <pahihu@gmail.com> writes:
> >You can even write a PICK-less variant in ANS-94, which does not depend
> >on the FP cell width. Testing on SwiftForth, iForth, VFX, gforth I don't
> >see clear performance advantage of the separate FP stack version either.
> >
> >pahihu
> >
> >fvariable faxpy-ra \ should be a user variable
> >: faxpy-nostride941 ( ra f_x f_y ucount -- )
> >    \ vy=ra*vx+vy
> >    >r 2>r faxpy-ra f! 2r> r>
> >    0 ?DO ( f_x1 f_y1 )
> >        >R
> >        dup float+ swap f@
> >        faxpy-ra f@ f*
> >        R@ f@ f+ R@ f!
> >        R> float+
> >  LOOP
> >  2drop ;
> 
> Looks better than the PICK-heavy variant, but still cumbersome
> compared to the Forth-2012 version.
> 
> Performance: On a Core i7-4690K (no SwiftForth or iForth installed),
> with the unrolled versions:
> 
> cycles
> Forth-2012 Forth-94  Forth-94
>            Rees/Ertl pahihu
> 2929M      3691M     3480M  gforth-fast
> 1289M      1414M     1574M  vfxlin Ndp387
> 
> Looks like a win for the Forth-2012 code to me.
> 
> The inner loop for the non-unrolled variants are on VFX:
> 
> Forth-2012             Forth-94 Rees/Ertl        Forth-94 pahihu
> FLD   ST               MOV   EDX, [EBP]          PUSH  EBX             
> MOV   EDX, [EBP]       FLD   TBYTE 0 [EDX]       MOV   EBX, [EBP]      
> FLD   TBYTE 0 [EDX]    FLD   TBYTE [080A3460]    MOV   EDX, EBX        
> FMULP ST(1), ST        FMULP ST(1), ST           ADD   EBX, 0A         
> FLD   TBYTE 0 [EBX]    FLD   TBYTE 0 [EBX]       FLD   TBYTE 0 [EDX]   
> FADDP ST(1), ST        FADDP ST(1), ST           FLD   TBYTE [080A3460]
> FSTP  TBYTE 0 [EBX]    FSTP  TBYTE 0 [EBX]       FMULP ST(1), ST       
> ADD   EBX, 0A          ADD   EBX, 0A             MOV   EDX, [ESP]      
> MOV   EDX, [EBP]       MOV   EDX, [EBP]          FLD   TBYTE 0 [EDX]   
> ADD   EDX, 0A          ADD   EDX, 0A             FADDP ST(1), ST       
> ADD   [ESP], 01        ADD   [ESP], 01           MOV   EDX, [ESP]      
> ADD   [ESP+04], 01     ADD   [ESP+04], 01        FSTP  TBYTE 0 [EDX]   
> MOV   [EBP], EDX       MOV   [EBP], EDX          POP   EDX             
> JNO   080C6D78         JNO   080C6DB8            ADD   EDX, 0A         
>                                                  ADD   [ESP], 01       
>                                                  ADD   [ESP+04], 01    
>                                                  MOV   [EBP], EBX      
>                                                  MOV   EBX, EDX        
>                                                  JNO   080C6A88        
> 
> VFX does not (yet?) analyse and optimize the return stack; or, if you
> feel nasty, you could say: it optimizes PICK better than >R R> and R@.

In iForth the 4 times unrolled variant with visible arguments will be
something like

0e dfvalue faxpy-ra

: faxpy-nostride941 ( ra f_x f_y ucount )
    \ vy=ra*vx+vy
    >r 2>r TO faxpy-ra 2r> r>
    0 ?DO ( f_x1 f_y1 )
        >R  df@+   faxpy-ra f*    R@ df@ f+ R@ df!   R> dfloat+
        >R  df@+   faxpy-ra f*    R@ df@ f+ R@ df!   R> dfloat+
        >R  df@+   faxpy-ra f*    R@ df@ f+ R@ df!   R> dfloat+
        >R  df@+   faxpy-ra f*    R@ df@ f+ R@ df!   R> dfloat+
  LOOP
  2drop ;

create f[] 16 dfloats allot 
create g[] 16 dfloats allot 
: test 23e f[] g[] 4 faxpy-nostride941 ;  

FORTH> ' test idis
$01326C00  : test
$01326C0A  fld           $012BCAC0 tbyte-offset
$01326C10  fstp          $01325D90 qword-offset
$01326C16  push          $013266C0 d#
$01326C1B  push          $01326750 d#
$01326C20  mov           rcx, 4 d#
$01326C27  xor           rbx, rbx
$01326C2A  call          (?DO) offset NEAR
$01326C34  lea           rax, [rax 0 +] qword
$01326C38  pop           rdi
$01326C39  fld           [rdi] qword
$01326C3B  fld           $01325D90 qword-offset
$01326C41  fmulp         ST(1), ST
$01326C43  fld           [rbx] qword
$01326C45  faddp         ST(1), ST
$01326C47  fstp          [rbx] qword
$01326C49  fld           [rdi 8 +] qword
$01326C4C  fld           $01325D90 qword-offset
$01326C52  fmulp         ST(1), ST
$01326C54  fld           [rbx 8 +] qword
$01326C57  faddp         ST(1), ST
$01326C59  fstp          [rbx 8 +] qword
$01326C5C  fld           [rdi #16 +] qword
$01326C5F  fld           $01325D90 qword-offset
$01326C65  fmulp         ST(1), ST
$01326C67  fld           [rbx #16 +] qword
$01326C6A  faddp         ST(1), ST
$01326C6C  fstp          [rbx #16 +] qword
$01326C6F  fld           [rdi #24 +] qword
$01326C72  fld           $01325D90 qword-offset
$01326C78  fmulp         ST(1), ST
$01326C7A  fld           [rbx #24 +] qword
$01326C7D  faddp         ST(1), ST
$01326C7F  fstp          [rbx #24 +] qword
$01326C82  lea           rdi, [rdi #32 +] qword
$01326C86  push          rdi
$01326C87  lea           rbx, [rbx #32 +] qword
$01326C8B  add           [rbp 0 +] qword, 1 b#
$01326C90  add           [rbp 8 +] qword, 1 b#
$01326C95  jno           $01326C38 offset NEAR
$01326C9B  add           rbp, #24 b#
$01326C9F  pop           rdi
$01326CA0  ;

-marcel

[toc] | [prev] | [next] | [standalone]


#59463

Frompahihu <pahihu@gmail.com>
Date2017-05-17 23:53 -0700
Message-ID<14adb3ac-9b58-47b7-9d76-954a42a787b9@googlegroups.com>
In reply to#59432
2017. május 17., szerda 18:14:04 UTC+2 időpontban Anton Ertl a következőt írta:
> Performance: On a Core i7-4690K (no SwiftForth or iForth installed),
> with the unrolled versions:
> 
> cycles
> Forth-2012 Forth-94  Forth-94
>            Rees/Ertl pahihu
> 2929M      3691M     3480M  gforth-fast
> 1289M      1414M     1574M  vfxlin Ndp387
> 
> Looks like a win for the Forth-2012 code to me.

My test was run on an i7-3630QM under Win7Pro 64bit. All times in milliseconds.
The SwiftForth version uses a modified fpmath.f which uses inlining:

\              SF3   iForth5  VFX4  gforth32 gforth64
\  94-ertl     1100   464      310  2700     2090
\  94-pahihu   1030   281      360  2620     1760
\  20-ertl      870   281      297  2340     1760

For SwiftForth, VFX4 and gforth32 Forth-2012 wins, but for iForth5 and
gforth64 I don't see any advantage on this CPU and OS.

> VFX does not (yet?) analyse and optimize the return stack; or, if you
> feel nasty, you could say: it optimizes PICK better than >R R> and R@.

Agreed.

You write Forth code for a virtual stack machine, you use a particular
Forth compiler which translates the code to a register based CPU and you
run the code on a particular CPU and measure the cycles/times.

Using SwiftForth I checked how can I approach a baseline GCC 4.9.2 performance
(110/125 ms). The baseline was your Forth-2012 code (880 ms):

- using "F+!" instead of "DUP F@ F+ DUP F!" resulted in 660 ms

- using the code below I reached 520 ms

: faxpy-nostride ( ra f_x f_y ucount -- )
   \ vy=ra*vx+vy
   0 ?DO      
      fdup over  I     floats +  f@ f* dup  I     floats +  f+!
      fdup over  I 1+  floats +  f@ f* dup  I 1+  floats +  f+!
      fdup over  I 2+  floats +  f@ f* dup  I 2+  floats +  f+!
      fdup over  I 3 + floats +  f@ f* dup  I 3 + floats +  f+!
   4 +LOOP  2drop fdrop ;

- I added the DF@+ and DF+!+ primitives from iForth, this resulted in 290 ms

: faxpy-nostride ( ra f_x f_y ucount -- )
   \ vy=ra*vx+vy
   0 ?DO
      fdup swap df@+ f* swap df+!+
      fdup swap df@+ f* swap df+!+
      fdup swap df@+ f* swap df+!+
      fdup swap df@+ f* swap df+!+
   4 +LOOP  2drop fdrop ;

- using the idea of Stephen Pelc from EuroForth 2008, I reached 140 ms
  FA is a floating point pointer held in a register, >FA stores a
  value from the data stack to the reg, FA@+ fetches a float using the
  pointer and increments it

: faxpy-nostride ( ra f_x f_y ucount -- )
   \ vy=ra*vx+vy
   >R swap >FA R>
   0 ?DO
      fdup FA@+ f* df+!+
      fdup FA@+ f* df+!+
      fdup FA@+ f* df+!+
      fdup FA@+ f* df+!+
   4 +LOOP  drop fdrop ;

- using FOR ... NEXT, loop counter in another register, resulted in 120 ms
  OK, I cheated, because /NEXT decrements the counter by 4

: faxpy-nostride ( ra f_x f_y ucount -- )
   \ vy=ra*vx+vy
   >R swap >FA R>
   FOR
      fdup FA@+ f* df+!+
      fdup FA@+ f* df+!+
      fdup FA@+ f* df+!+
      fdup FA@+ f* df+!+
   /NEXT  drop fdrop ;

This final version which shines on i7 was just marginally better than the
original Forth-2012 code on a Core2 Duo 3.0GHz...

pahihu

[toc] | [prev] | [next] | [standalone]


#59540

Frompahihu <pahihu@gmail.com>
Date2017-05-19 02:34 -0700
Message-ID<02b68980-120c-433c-91fd-004f81856552@googlegroups.com>
In reply to#59463
2017. május 18., csütörtök 8:53:18 UTC+2 időpontban pahihu a következőt írta:
> This final version which shines on i7 was just marginally better than the
> original Forth-2012 code on a Core2 Duo 3.0GHz...

Found it, was an alignment problem for the test arrays. (4bytes aligned instead of 8bytes)

pahihu

[toc] | [prev] | [next] | [standalone]


#59417

FromJoel Rees <joel.rees@gmail.com>
Date2017-05-16 22:48 -0700
Message-ID<a561c81c-8478-4528-ad63-7c3524bef94c@googlegroups.com>
In reply to#59178
Sorry, Anton, I didn't know PICK was a Forth-94 thing, so I hadn't 
read this until today.

On Sunday, May 14, 2017 at 12:29:04 AM UTC+9, Anton Ertl wrote:
> In the last few days I and others have made some claims about the
> performance effects of a separate FP stack vs. a combined stack, and
> also on the Forth-94 vs. the Forth-2012 standard, i.e, the benefit (to
> programmers) of being guaranteed a separate FP stack (Forth-2012)
> vs. having to write code that works for a separate FP stack as well as
> with a combined stack with any number of cells per FP item (Forth-94).
> 
> I decided to try to check these claims empirically.  To that end I
> wrote a Forth-94 version of FAXPY-NOSTRIDE based on Joel Rees' code,
> wrote a matrix multiplication routine, and benchmarked multiplying 2
> 500x500 matrices (once per benchmark run).  Results are from a 4GHz
> Core i7-6600K.
> 
> Here's the code for the Forth-94 and Forth-2012 versions of
> FAXPY-NOSTRIDE:
> 
> \ Forth-94
> :noname depth >r 0 s>f depth r> - >r fdrop r> ; execute
> constant FPCELLWIDTH
> fvariable faxpy-ra \ should be a user variable

Did I put this in a user variable? 

If we don't want to see whether the compiler does a nice job with 
constant expressions we could do this, instead:

2 CELLWIDTH * constant ra_offset

(I forget what you guys call CELLWIDTH.)

> : faxpy-nostride ( ra f_x f_y ucount -- )
>     \ vy=ra*vx+vy
>     >r 2>r faxpy-ra f! 2r> r>
>     0 ?DO ( f_x1 f_y1 )
>         over f@ faxpy-ra f@ f*

Thus,

         over f@ ra_offset sp@ + f@ f*

or, if we had fPICK,

         over f@ 2 fPICK f*

>         FPCELLWIDTH pick f@ f+ 
>         FPCELLWIDTH pick f!
>         float+ swap float+ swap
>   LOOP
>   2drop ;

I think I showed the high-level definition of fPICK:

: fPICK ( n -- f )
  CELLWIDTH * sp@ + f@ ;

And I think I mumbled something about defining it low-level, instead.

> \ Forth-2012
> : faxpy-nostride ( ra f_x f_y ucount -- )
>     \ vy=ra*vx+vy
>     0 ?do
> 	fdup over f@ f* dup f@ f+ dup f! 
> 	float+ swap float+ swap
>     loop
>     2drop fdrop ;
> 
> The benchmark executes faxpy-nostride 250k times, and the inner loop
> 125M times.  Here's the inner loop of these two words on VFX with
> Ndp387.fth, as well as the inner loop of Gforth's FAXPY primitive
> (based on straighforward C code; I guess calling the BLAS routine
> daxpy would produce better performance; I show this version to show
> what a compiler can do and to get a feeling for how close to the limit
> the Forth results are):
> 
> VFX Forth-2012         VFX Forth-94              gcc (faxpy)
> FLD   ST               MOV   EDX, [EBP]          movsd  (%rdi),%xmm1      
> MOV   EDX, [EBP]       FLD   TBYTE 0 [EDX]       add    %rsi,%rdi         
> FLD   TBYTE 0 [EDX]    FLD   TBYTE [080A3460]    mulsd  %xmm0,%xmm1       
> FMULP ST(1), ST        FMULP ST(1), ST           addsd  (%rdx),%xmm1      
> FLD   TBYTE 0 [EBX]    FLD   TBYTE 0 [EBX]       movsd  %xmm1,(%rdx)      
> FADDP ST(1), ST        FADDP ST(1), ST           add    %rcx,%rdx         
> FSTP  TBYTE 0 [EBX]    FSTP  TBYTE 0 [EBX]       sub    $0x1,%r8          
> ADD   EBX, 0A          ADD   EBX, 0A             jne    0x4180b8 <faxpy+8>
> MOV   EDX, [EBP]       MOV   EDX, [EBP]      
> ADD   EDX, 0A          ADD   EDX, 0A         
> ADD   [ESP], 01        ADD   [ESP], 01       
> ADD   [ESP+04], 01     ADD   [ESP+04], 01    
> MOV   [EBP], EDX       MOV   [EBP], EDX      
> JNO   080C6D78         JNO   080C6DB8        
>
> So VFX works nicely for optimizing the PICKs, DUPs etc. away here,

Indeed. gcc, too.

Reading the compiled C,

> gcc (faxpy)

(We aren't seeing the factor in %xmm0 get initialized.)

0x4180b8:

> movsd  (%rdi),%xmm1    
Grab the left-hand operand, store in FP register.

> add    %rsi,%rdi         
FP width in %rsi, so update left-hand operator pointer.

> mulsd  %xmm0,%xmm1       
FP multiply.

> addsd  (%rdx),%xmm1      
FP sum with right-hand.

> movsd  %xmm1,(%rdx)      
Store result to right-hand operand.

> add    %rcx,%rdx      
Update right-hand pointer.
This appears to be the with-stride version in C.
   
> sub    $0x1,%r8          
Count the loop.

> jne    0x4180b8 <faxpy+8>       

---------------------

> VFX Forth-2012    

080C6D78? 
> FLD   ST             
Factor?  

080C6D78?
> MOV   EDX, [EBP]       
> FLD   TBYTE 0 [EDX]    
Left-hand operand

> FMULP ST(1), ST       
Product 

> FLD   TBYTE 0 [EBX]    
> FADDP ST(1), ST        
Sum with right-hand operand.

> FSTP  TBYTE 0 [EBX]    
Store to right-hand operand.

> ADD   EBX, 0A          
Update right-hand operand pointer.

> MOV   EDX, [EBP]       
For some reason, it has lost track of the left-hand operand pointer.

> ADD   EDX, 0A          
Update for left-hand operand pointer not complete.

> ADD   [ESP], 01        
Count the loop.

> ADD   [ESP+04], 01     
Outer loop? That would be a lot of code flattening going on.

> MOV   [EBP], EDX   
Left-hand operand now up-to-date.
    
> JNO   080C6D78         

---------------------

> VFX Forth-94  

080C6DB8:            
> MOV   EDX, [EBP]          
Pointer to left-hand

> FLD   TBYTE 0 [EDX]       
Left-hand.

> FLD   TBYTE [080A3460]    
Factor.

> FMULP ST(1), ST           
Product.

> FLD   TBYTE 0 [EBX]       
Right-hand.

> FADDP ST(1), ST           
Sum with right-hand.

> FSTP  TBYTE 0 [EBX]     
Store result to right-hand operand.
  
> ADD   EBX, 0A           
Update right-hand pointer.
  
> MOV   EDX, [EBP]      
Again, for some reason, we have lost track of the left-hand pointer in EDX.

> ADD   EDX, 0A         
Incomplete update of left-hand pointer.

> ADD   [ESP], 01       
Loop counter.

> ADD   [ESP+04], 01    
Whatever this is.

> MOV   [EBP], EDX      
Complete update of left-hand pointer.

> JNO   080C6DB8        

> and
> even the variable access does not cause an extra instruction. 

Depends on where the start of the loop was, I think.

Also, there may be cache issues when the factor is not on a stack.

> One
> weakness of the VFX code is that the loop control works through
> memory, so each iteration takes at least 5 or 6 cycles; the whole FP
> part of each iteration looks independent of the other operations, so
> the out-of-order execution engine of this CPU should be able to
> exploit a lot of parallelism, if we solve the loop control problem.
> So I also wrote an unrolled (factor 4) version of the loop, which
> should solve the problem.  The results are:
> 
> gforth    VFX/2012      VFX/2012 
> C faxpy  no unrolling   unrolled
>   1155M     1818M        1259M  instructions
>    316M     1432M        1036M  cycles
> 
> So unrolling buys some speedup and I will show the unrolled results in
> the rest of this posting for simplicity of exposition.  But despite
> this speedup, the result is still more than tree times slower than the
> C code, even though the number of instructions is similar.  I.e.,
> there is still something holding back the out-of-order CPU when
> running the VFX code.

If ST(1) is not aliased to a floating point register, I can see a good 
reason for slowdown. I'm not sure if three times makes sense, but at 
least double. 

> One theory I pursued is that the memory accesses for the 10-byte
> floats of VFX are at fault, i.e., that there is a false memory
> dependency from the fstp of one iteration to the third fld of the next
> in many cases, because they access the same word; I successfully
> falsified this theory by redefining FLOATS and FLOAT+ for 16-byte
> units, and observing that the results did not change.  So there must
> be some other reason for the performance difference.

I wouldn't think the size would be the issue.

> Another theory I pursued is that the 387 instructions are no longer
> supported well, and that the slowdown is due to this.  I checked this
> by compiling gforth with "gcc -mfpmath=387".  Here are the results:
> 
>  gforth    gforth   VFX/2012 
> C faxpy   C faxpy   unrolled
>     SSE       387        387
>   1155M     1157M      1259M  instructions
>    316M      561M      1036M  cycles
> 
> So, while 387 instructions cause some slowdown (from
> 2.5cycles/iteration to 4.5), there are still almost 4 cycles per
> iteration unexplained in the VFX results.  In the rest of this posting
> the gforth results are with SSE instructions (otherwise gcc does not
> keep the FTOS in a register).

Interesting, but red-herring.

> Anyway, back to the question of Forth-94 vs. Forth-2012 code:
> 
> cycles
>   2012      94
>  1036M   1163M vfxlin Ndp387.fth
>  2222M   2949M gforth-fast
> 12434M  10193M SwiftForth
> 
> On VFX the Forth-94 variant is slower by 1 cycle/iteration, on
> gforth-fast (which does not optimize stack manipulation much) by 5.8
> cycles.  On SwiftForth the Forth-94 variant is faster (by 18
> cycles/iteration, and it also executes 3.5 instructions/iteration
> less), but even the Forth-94 variant is so slow on SwiftForth (81.5
> cycles/iteration) that you won't use SwiftForth for this kind of thing
> if performance matters.

True. The optimization is still just a shade short of the C optimization.

I get after the current troop of gcc maintainers, but they are getting 
a bit better handle on how data migrates between registers and memory. 
gcc output code is really tight.

> Looking at the SwiftForth code, the loop body of the Forth-94 variant
> is longer by 4 instructions; the code performs a call for every FP
> word, and the code for FDUP executes 6 instructions more than that for
> F@, explaining 2 of the 3.5 instructions/iteration difference.  The
> implementations of the floating-point words are not written for time
> (or space) efficiency: The FTOS is not cached on the FP stack, and
> there is a WAIT instruction (2 cycles on Skylake) at the end of every
> FP word.  Indeed, FDUP looks as if it was written to perform
> pessimally: It loads an FP value from memory to the FPU stack, DUPs it
> there, then uses a loop to store these two FP values to memory (i.e.,
> including storing to the position where it had just fetched from).
> 
> Back to topic: these are all systems/packages that use a separate FP
> stack.  How well does a combined stack perform?  VFX provides 5
> different FP packages, three with a separate FP stack, two with a
> combined stack.
> 
> x86/Ndp387.fth uses the 387 stack as FP stack.
> x86/Hfp387.fth uses a stack in memory as FP stack, FTOS on 387 stack
> x86/HfpGL32.fth uses a combined stack (32-bit floats)
> SoftFP32.separate.fth implements FP using integer arithmetic, separate
> SoftFP32.combined.fth implements FP using integer arithmetic, combined
> 
> Let's see how they perform:
> 
>   2012      94
>  2222M   2949M gforth-fast (for reference)
>  1036M   1163M vfxlin Ndp387.fth
>  5156M   7402M vfxlin Hfp387.fth
>          2596M vfxlin HfpGL32.fth
> 18967M  19140M vfxlin SoftFP32.separate.fth
>         10307M vfxlin SoftFP32.combined.fth
> 
> Ndp387 performs best by far, but that approach is limited to the 387
> (and, less importantly, to 8 FP stack items).
> 
> Hfp387 benefits a lot from the Forth-2012 variant, but is surprisingly
> slow in either case (41 and 59 instructions/iteration).  The source
> code looks reasonable (FTOS cached in the FPU, no obvious
> inefficiencies), so the slowdown is surprising, especially compared to
> gforth-fast, which uses similar techniques.
> 
> It storess the F-Stack pointer in a user variable and updates it
> there, once for each of the 6 FP operations in the loop, which leads
> to dependences through memory, and unlike the loads and stores from f@
> and f! in this loop, these are loop-carried dependencies, and thus
> their latency determines the performance of this loop; for 6 cycles
> latency per update through memory, one iteration takes at least 36
> cycles (pretty close to the measures 41 cycles).  I have no
> explanation for the additional 18 cycles of the Forth-94 variant,
> though.  By contrast, gforth-fast stores the FP stack pointer in a
> register.
> 
> The moral: Keeping the FP stack pointer in memory is not necessarily
> bad, but don't update it once per FP operation; instead, be a little
> more analytical, and update it at the end of the basic block.  Or keep
> the FP stack pointer in a register, like gforth.
> 
> HfpGL32 surprises with its performance, especially once I looked at
> the source and object code for F+, which does not look like it is
> written for efficiency (it takes 15 instructions compared to 6 for
> Hfp387).  Looking at the code generated for the inner loop, it becomes
> obvious what happens here: having the FP items on the data stack
> brought F@ and F! into the realm of VFX's analytical compiler, and we
> get pretty good code for everything in the loop except F+ and F*;
> that's apparently good enough to get this relatively good result.
> 
> But note that HfpGL32 still is slower than gforth-fast with Forth-2012
> code, even though gforth-fast has no analytical compiler.  My
> expectation is that on a variant of VFX with an analytical compiler
> that encompasses the FP stack, Hfp387 would outperform HfpGL32 by a
> good margin, even if the FP stack pointer is kept in memory between
> basic blocks.
> 
> The SoftFP32 variants are, unsurprisingly, slow, but it's interesting
> that they are not that far off, given that they are written in Forth.
> SoftFP32.separate is 71 cycles slower on the Forth-94 variant than
> SoftFP32.combined. 
> 
> My expectation was that the speed difference is small relative to the
> overhead of the software FP.  But we already saw for the hardware FP
> variants that the analytical compiler of VFX does nicely for the
> combined stack, so much of these 10M cycles is probably spent in the
> software implementations of F* and F+, with the rest of the loop
> condensed nicely by the analytical compiler.
> 
> By contrast, SoftFP32.separate contains a lot of >FS and FS>, each
> time updating the FP stack pointer in memory; and it's not written for
> performance: F+ starts with FS> FS> 2SWAP, i.e., two dependent updates
> of the FP stack pointer, and ends with >FS.  At least that could be
> handled better without too much effort.
> 
> Conclusion: If we want good performance beyond using the 387 stack as
> FP stack, we need an analytical compiler; in that case, keeping the FP
> stack pointer in memory is probably good enough.  If we don't want to
> go there, keeping the FP stack pointer in a register is essential.  If
> you don't have a compiler that optimizes PICK (e.g., gforth-fast),
> Forth-2012 provides a significant performance benefit (in addition to
> the programming convenience benefit) over Forth-94; even for VFX with
> Ndp387, there is a small benefit for the Forth-2012 variant.
> 
> - anton
> -- 
> M. Anton Ertl  http://www.complang.tuwien.ac.at/anton/home.html
> comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
>      New standard: http://www.forth200x.org/forth200x.html
>    EuroForth 2017: http://www.euroforth.org/ef17/

My conclusion is a little different, but I'm living in a dreamworld 
where I can dream about building CPUs the way I think they should be 
built.

I'd like to see what a conventional CPU (preferably not Intel) would 
do with separate fast spill/fill cache for three stacks -- return,
parameter, and the alternate stack I'm suggesting; and conventional 
fast cache for non-stack references.

The parameter and alternate stack caches could be peers to the 
conventional fast cache between the CPU and the intermediate or slow
cache, but, for security, I'd like to keep the path to the return 
cache clean and restrict access to it to access by the return stack 
pointer.

--
Joel Rees

Delusions of reinventing the industry all by myself:
http://defining-computers.blogspot.com/

[toc] | [prev] | [next] | [standalone]


#59422

Fromanton@mips.complang.tuwien.ac.at (Anton Ertl)
Date2017-05-17 06:51 +0000
Message-ID<2017May17.085155@mips.complang.tuwien.ac.at>
In reply to#59417
Joel Rees <joel.rees@gmail.com> writes:
>Sorry, Anton, I didn't know PICK was a Forth-94 thing, so I hadn't 
>read this until today.

I am not sure what you mean by that.  The "Forth-94" in the title
refers to the requirement that programs using FP words must work on
separate-stack systems and on combined-stack systems with any number
of cells per FP item.

>> Here's the code for the Forth-94 and Forth-2012 versions of
>> FAXPY-NOSTRIDE:
>> 
>> \ Forth-94
>> :noname depth >r 0 s>f depth r> - >r fdrop r> ; execute
>> constant FPCELLWIDTH
>> fvariable faxpy-ra \ should be a user variable
>
>Did I put this in a user variable? 

No, you used a cell-based FPICK instead.  FPICK is not a Forth-94
word, so I replaced your use of FPICK with a variable access.
Moreover, Gforth has an FPICK that uses the FP item index as input;
i.e., 1 FPICK is equivalent to FOVER; and I expect that other systems
providing FPICK work the same way.

>If we don't want to see whether the compiler does a nice job with 
>constant expressions we could do this, instead:
>
>2 CELLWIDTH * constant ra_offset
>
>(I forget what you guys call CELLWIDTH.)
>
>> : faxpy-nostride ( ra f_x f_y ucount -- )
>>     \ vy=ra*vx+vy
>>     >r 2>r faxpy-ra f! 2r> r>
>>     0 ?DO ( f_x1 f_y1 )
>>         over f@ faxpy-ra f@ f*
>
>Thus,
>
>         over f@ ra_offset sp@ + f@ f*

SP@ is not Forth-94, either.

>> So VFX works nicely for optimizing the PICKs, DUPs etc. away here,
>
>Indeed. gcc, too.

The source for the gcc faxpy code was a piece of C code (no PICKs or
DUPs), not Forth code.

>This appears to be the with-stride version in C.

Right.

>> VFX Forth-2012    
>
>080C6D78? 
>> FLD   ST             
>Factor?  

fdup

I.e., yes, it's the RA parameter.

>> ADD   [ESP], 01        
>Count the loop.

Update I.

>> ADD   [ESP+04], 01     
>Outer loop? That would be a lot of code flattening going on.

Update max_n-limit+1+i.  This, together with JNO, gives the wraparound
semantics for LOOP that is standard.

>Also, there may be cache issues when the factor is not on a stack.

The item is accessed so often that it stays in the cache.

>> But despite
>> this speedup, the result is still more than tree times slower than the
>> C code, even though the number of instructions is similar.  I.e.,
>> there is still something holding back the out-of-order CPU when
>> running the VFX code.
>
>If ST(1) is not aliased to a floating point register, I can see a good 
>reason for slowdown. I'm not sure if three times makes sense, but at 
>least double. 

ST(1) is a floating-point register.

- anton
-- 
M. Anton Ertl  http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
     New standard: http://www.forth200x.org/forth200x.html
   EuroForth 2017: http://www.euroforth.org/ef17/

[toc] | [prev] | [next] | [standalone]


#59434

FromJoel Rees <joel.rees@gmail.com>
Date2017-05-17 09:29 -0700
Message-ID<4c48dc62-3942-4e45-9e4b-438b21693bb5@googlegroups.com>
In reply to#59422
On Wednesday, May 17, 2017 at 7:14:00 PM UTC+9, Anton Ertl wrote:
> Joel Rees <joel rees@somewhere> writes:
> >Sorry, Anton, I didn't know PICK was a Forth-94 thing, so I hadn't 
> >read this until today.
> 
> I am not sure what you mean by that.  The "Forth-94" in the title
> refers to the requirement that programs using FP words must work on
> separate-stack systems and on combined-stack systems with any number
> of cells per FP item.

And I am completely oblivious to any requirements the standards impose.

So we are, to a certain extent, talking past each other.

> >> Here's the code for the Forth-94 and Forth-2012 versions of
> >> FAXPY-NOSTRIDE:
> >> 
> >> \ Forth-94
> >> :noname depth >r 0 s>f depth r> - >r fdrop r> ; execute
> >> constant FPCELLWIDTH
> >> fvariable faxpy-ra \ should be a user variable
> >
> >Did I put this in a user variable? 
> 
> No, you used a cell-based FPICK instead.  FPICK is not a Forth-94
> word, so I replaced your use of FPICK with a variable access.
> Moreover, Gforth has an FPICK that uses the FP item index as input;
> i.e., 1 FPICK is equivalent to FOVER; and I expect that other systems
> providing FPICK work the same way.

Okay, so FPICK was not the name to give it.

I've been using LC@, but I think that is already defined by something else in gforth, too. 

> >If we don't want to see whether the compiler does a nice job with 
> >constant expressions we could do this, instead:
> >
> >2 CELLWIDTH * constant ra_offset
> >
> >(I forget what you guys call CELLWIDTH.)
> >
> >> : faxpy-nostride ( ra f_x f_y ucount -- )
> >>     \ vy=ra*vx+vy
> >>     >r 2>r faxpy-ra f! 2r> r>
> >>     0 ?DO ( f_x1 f_y1 )
> >>         over f@ faxpy-ra f@ f*
> >
> >Thus,
> >
> >         over f@ ra_offset sp@ + f@ f*
> 
> SP@ is not Forth-94, either.

But it is defined in gforth.

Still, I'd define the PICK-like access word in assembler before trying 
benchmark, I think. It makes absolutely no sense not to be able, when 
code calls for it, to access memory at a fairly arbitrary offset from a stack pointer.

> >> So VFX works nicely for optimizing the PICKs, DUPs etc. away here,
> >
> >Indeed. gcc, too.
> 
> The source for the gcc faxpy code was a piece of C code (no PICKs or
> DUPs), not Forth code.

I didn't realize I was implying otherwise.

> >This appears to be the with-stride version in C.
> 
> Right.
> 
> >> VFX Forth-2012    
> >
> >080C6D78? 
> >> FLD   ST             
> >Factor?  
> 
> fdup
> 
> I.e., yes, it's the RA parameter.
> 
> >> ADD   [ESP], 01        
> >Count the loop.
> 
> Update I.
> 
> >> ADD   [ESP+04], 01     
> >Outer loop? That would be a lot of code flattening going on.
> 
> Update max_n-limit+1+i.  This, together with JNO, gives the wraparound
> semantics for LOOP that is standard.

I'll have to think that one through.

> >Also, there may be cache issues when the factor is not on a stack.
> 
> The item is accessed so often that it stays in the cache.

If the cache line it's on isn't bumped ... 

> >> But despite
> >> this speedup, the result is still more than tree times slower than the
> >> C code, even though the number of instructions is similar.  I.e.,
> >> there is still something holding back the out-of-order CPU when
> >> running the VFX code.
> >
> >If ST(1) is not aliased to a floating point register, I can see a good 
> >reason for slowdown. I'm not sure if three times makes sense, but at 
> >least double. 
> 
> ST(1) is a floating-point register.

That shoots that theory.

> - anton
> -- 
> M. Anton Ertl  http://www.complang.tuwien.ac.at/anton/home.html
> comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
>      New standard: http://www.forth200x.org/forth200x.html
>    EuroForth 2017: http://www.euroforth.org/ef17/

--
Joel Rees

Delusions of being a novelist:
http://joel-rees-economics.blogspot.com/2017/01/soc500-00-00-toc.html

[toc] | [prev] | [next] | [standalone]


#59423

Fromstephen@mpeforth.com (Stephen Pelc)
Date2017-05-17 11:07 +0000
Message-ID<591c2dab.599913139@news.eternal-september.org>
In reply to#59417
On Tue, 16 May 2017 22:48:04 -0700 (PDT), Joel Rees
<joel.rees@gmail.com> wrote:

>> daxpy would produce better performance; I show this version to show
>> what a compiler can do and to get a feeling for how close to the limit
>> the Forth results are):
>> 
>> VFX Forth-2012         VFX Forth-94              gcc (faxpy)
>> FLD   ST               MOV   EDX, [EBP]          movsd  (%rdi),%xmm1      
>> MOV   EDX, [EBP]       FLD   TBYTE 0 [EDX]       add    %rsi,%rdi         
>> FLD   TBYTE 0 [EDX]    FLD   TBYTE [080A3460]    mulsd  %xmm0,%xmm1       
>> FMULP ST(1), ST        FMULP ST(1), ST           addsd  (%rdx),%xmm1      
>> FLD   TBYTE 0 [EBX]    FLD   TBYTE 0 [EBX]       movsd  %xmm1,(%rdx)      
>> FADDP ST(1), ST        FADDP ST(1), ST           add    %rcx,%rdx         
>> FSTP  TBYTE 0 [EBX]    FSTP  TBYTE 0 [EBX]       sub    $0x1,%r8          
>> ADD   EBX, 0A          ADD   EBX, 0A             jne    0x4180b8 <faxpy+8>
>> MOV   EDX, [EBP]       MOV   EDX, [EBP]      
>> ADD   EDX, 0A          ADD   EDX, 0A         
>> ADD   [ESP], 01        ADD   [ESP], 01       
>> ADD   [ESP+04], 01     ADD   [ESP+04], 01    
>> MOV   [EBP], EDX       MOV   [EBP], EDX      
>> JNO   080C6D78         JNO   080C6DB8        
>>
>> So VFX works nicely for optimizing the PICKs, DUPs etc. away here,

Note also that ?DO ... LOOP is not optimal here as it maintains two
items in memory. See the last four instructions in the VFX listings.
A simple BEGIN ... UNTIL may be better.

In general, DO LOOP is only optimal if the loop count is used more
than once on register-starved CPUs. If you have 16 or more registers
using two for DO ... LOOP may be more effective. Measurement will
prove it when we ave the time and resources.

Stephen

-- 
Stephen Pelc, stephenXXX@mpeforth.com
MicroProcessor Engineering Ltd - More Real, Less Time
133 Hill Lane, Southampton SO15 5AF, England
tel: +44 (0)23 8063 1441, fax: +44 (0)23 8033 9691
web: http://www.mpeforth.com - free VFX Forth downloads

[toc] | [prev] | [next] | [standalone]


#59431

Fromanton@mips.complang.tuwien.ac.at (Anton Ertl)
Date2017-05-17 15:02 +0000
Message-ID<2017May17.170216@mips.complang.tuwien.ac.at>
In reply to#59423
stephen@mpeforth.com (Stephen Pelc) writes:
>On Tue, 16 May 2017 22:48:04 -0700 (PDT), Joel Rees
><joel.rees@gmail.com> wrote:
>
>>> daxpy would produce better performance; I show this version to show
>>> what a compiler can do and to get a feeling for how close to the limit
>>> the Forth results are):
>>> 
>>> VFX Forth-2012         VFX Forth-94              gcc (faxpy)
>>> FLD   ST               MOV   EDX, [EBP]          movsd  (%rdi),%xmm1      
>>> MOV   EDX, [EBP]       FLD   TBYTE 0 [EDX]       add    %rsi,%rdi         
>>> FLD   TBYTE 0 [EDX]    FLD   TBYTE [080A3460]    mulsd  %xmm0,%xmm1       
>>> FMULP ST(1), ST        FMULP ST(1), ST           addsd  (%rdx),%xmm1      
>>> FLD   TBYTE 0 [EBX]    FLD   TBYTE 0 [EBX]       movsd  %xmm1,(%rdx)      
>>> FADDP ST(1), ST        FADDP ST(1), ST           add    %rcx,%rdx         
>>> FSTP  TBYTE 0 [EBX]    FSTP  TBYTE 0 [EBX]       sub    $0x1,%r8          
>>> ADD   EBX, 0A          ADD   EBX, 0A             jne    0x4180b8 <faxpy+8>
>>> MOV   EDX, [EBP]       MOV   EDX, [EBP]      
>>> ADD   EDX, 0A          ADD   EDX, 0A         
>>> ADD   [ESP], 01        ADD   [ESP], 01       
>>> ADD   [ESP+04], 01     ADD   [ESP+04], 01    
>>> MOV   [EBP], EDX       MOV   [EBP], EDX      
>>> JNO   080C6D78         JNO   080C6DB8        
>>>
>>> So VFX works nicely for optimizing the PICKs, DUPs etc. away here,
>
>Note also that ?DO ... LOOP is not optimal here as it maintains two
>items in memory. See the last four instructions in the VFX listings.
>A simple BEGIN ... UNTIL may be better.

There is nothing in ?DO...LOOP that prevents a compiler from
generating as good code for it as from BEGIN...WHILE...REPEAT
(BEGIN...UNTIL would be more appropriate for DO...LOOP).  Moreover,
DO...LOOP is a way to reduce stack load, and is therefore usually
preferred by programmers when they program counted loops.  But you can
try to convince me otherwise 

> If you have 16 or more registers
>using two for DO ... LOOP may be more effective.

My suggestion is to use one register (containing the index) and one
memory location (containing the limit) on Intel/AMD CPUs, even with
only 8 registers.  I.e., something like:

inc ecx
cmp ecx, [esp]
jne right-after-do

This means that you can LOOP at up to one iteration per cycle (instead
of 1 per 5 or 6 cycles with the current scheme).  You may worry about
the [esp] memory access, but it does not depend on anything in the
loop, so it can be executed early by out-of-order execution.  And if
you don't put anything else between the cmp and the jne, recent Intel
CPUs will combine (macro-fuse) them, reducing resource consumption,
and maybe increasing performance.

Anyway, as I described in the posting, I unrolled the loop (by a
factor of 4) to reduce the impact of loop overhead.

- anton
-- 
M. Anton Ertl  http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
     New standard: http://www.forth200x.org/forth200x.html
   EuroForth 2017: http://www.euroforth.org/ef17/

[toc] | [prev] | [standalone]


Page 2 of 2 — ← Prev page 1 [2]

Back to top | Article view | comp.lang.forth


csiph-web