On 8/30/24 13:32, minforth wrote:
use locals if you have too many parameters
I like this quite a bit. Tell me if I like it too much.
: CylVolLoop {: W: StartHeight W: FinalHeight F: Radius -- Tabular Output :} cr ." Radius " Radius fe.
StartHeight
begin dup FinalHeight <=
while
dup
ffdup
cr ." Height " fe.
Radius
VolOfCyl
." Volume " fe.
1 +
repeat
drop
cr ;
Under VFX Forth:...
\ Without locals...
: CylVolLoop ( StartHeight FinalHeight Radius -- )
cr ." Radius " fdup fe.
swap ( FinalHeight Height)
begin 2dup >= while
dup s>f fdup cr ." Height " fe.
fover ( Height Radius) VolOfCyl ." Volume " fe.
1+
repeat 2drop fdrop
cr ;
see CylVolLoop
...
( 148 bytes, 27 instructions )
On 9/2/24 18:23, dxf wrote:
Under VFX Forth:...
\ Without locals...
: CylVolLoop ( StartHeight FinalHeight Radius -- )
cr ." Radius " fdup fe.
swap ( FinalHeight Height)
begin 2dup >= while
dup s>f fdup cr ." Height " fe.
fover ( Height Radius) VolOfCyl ." Volume " fe.
1+
repeat 2drop fdrop
cr ;
see CylVolLoop
...
( 148 bytes, 27 instructions )
Nice. I will study your technique.
On 8/30/24 18:05, dxf wrote:Given that the area of the circle doesn't change - why recalculate that
On 31/08/2024 2:04 am, Buzz McCool wrote:
...
Does anyone have suggestions on a better approach when you have
several parameters and loop counts to deal with?
I see little wrong with your example other than cosmetics - excess
comments
that don't add value and missing stack parameter comment in colon
definitions.
Thanks for the feedback. Yes I do need to work on my stack parameter comments.
On 31-08-2024 07:59, BuzzMcCool wrote:
On 8/30/24 18:05, dxf wrote:Given that the area of the circle doesn't change - why recalculate that every time? Ok, I changed VolOfCirc a bit, but it saves me both time and complexity. Note this only works if there is a separate FP stack. Which
On 31/08/2024 2:04 am, Buzz McCool wrote:
...
Does anyone have suggestions on a better approach when you have
several parameters and loop counts to deal with?
I see little wrong with your example other than cosmetics - excess
comments
that don't add value and missing stack parameter comment in colon
definitions.
Thanks for the feedback. Yes I do need to work on my stack parameter
comments.
is the standard nowadays.
Alternatives:
1. Change the order of parameters (float last);
2. Change the order of parameters (carnal knowledge of the size of a
float);
3. Specify the radius as an integer.
f% 1.2 1 20 CylVolLoop
Radius 1.E0
Given that the area of the circle doesn't change - why recalculate that every time?
On 9/5/2024 8:18 AM, Hans Bezemer wrote:Oh, I talk a lot about locals: don't use them. The point is: you have
Given that the area of the circle doesn't change - why recalculate
that every time?
Excellent observation.
Would you have any videos talking about Forth locals? You and dxf are
far more adept at stack manipulations than I. I'm thinking I can get a
word up and working with locals and then convert to manual stack manipulations afterwards if necessary.
When is it necessary? dxf showed a word w/o locals to have ~%30 fewer instructions than a word with locals. Is that a common occurrence?
Would you have any videos talking about Forth locals? You and dxf are
far more adept at stack manipulations than I. I'm thinking I can get a
word up and working with locals and then convert to manual stack manipulations afterwards if necessary.
When is it necessary? dxf showed a word w/o locals to have ~%30 fewer instructions than a word with locals. Is that a common occurrence?
On 6 Sep 2024 at 23:03:38 CEST, "Buzz McCool" <buzz_mccool@yahoo.com>
wrote:
Would you have any videos talking about Forth locals? You and dxf are
far more adept at stack manipulations than I. I'm thinking I can get a
word up and working with locals and then convert to manual stack
manipulations afterwards if necessary.
Don't. You will only become dependent on locals. Use of locals should
be a considered decision.
When is it necessary? dxf showed a word w/o locals to have ~%30 fewer
instructions than a word with locals. Is that a common occurrence?
We (MPE) converted much of our TCP/IP stack not to use locals. This
was mostly on ARM7 devices, but the figures for other 32 bit CPUs of
the period (say 15 years ago) were similar. Code density improved by
about 25% and performance by about 50%.
Don't. You will only become dependent on locals. Use of locals should
be a considered decision.
When is it necessary? dxf showed a word w/o locals to have ~%30 fewer
instructions than a word with locals. Is that a common occurrence?
We (MPE) converted much of our TCP/IP stack not to use locals. This
was mostly on ARM7 devices, but the figures for other 32 bit CPUs of
the period (say 15 years ago) were similar. Code density improved by
about 25% and performance by about 50%.
Another observation is that many Forthers do not seem to put much
emphasis
on programming time and code maintainability or readability, which is
easier to achieve by using locals.
author = {M. Anton Ertl},
title = {Are Locals Inevitably Slow?},
crossref = {euroforth22},
pages = {48--49},
url = {http://www.euroforth.org/ef22/papers/ertl-locals.pdf},
url-slides = {http://www.euroforth.org/ef22/papers/ertl-locals-slides.pdf},
video = {https://www.youtube.com/watch?v=tPjSKetEJn0},
OPTnote = {presentation slides},
abstract = {Code quality of locals on two code examples on
various systems}
}
An update on the table for the example:
: 3dup.3 {: a b c :} a b c a b c ;
instr. bytes system
31 117 Gforth AMD64
16 44 iforth 5.0.27 (plus 20 bytes entry and return code)
7 19 lxf 1.6-982-823 32-bit
32 127 SwiftForth 4.0.0-RC89 (calls LSPACE)
26 92 VFX Forth 64 5.11 RC2
I won't dispute that using the "locals" shortcut *may* save some
programming time - but to me, the moment you decide to put the whole
shebang in locals, you enter another mindset. Because at that moment you cease to consider the algorithm itself, but start banging out code.
You no longer consider "do I need that, do I need that now, do I need
that here", you just start creating more local variables. Somehow that
kills my train of mind..
...
Since such algorithms/tasks are mostly formulated mathematically or logically, an almost 1:1 translation of such formulations by using
locals
is straightforward and less error prone. Use descriptive names and the
code
becomes quasi commented simultaneously.
On 08-09-2024 18:09, minforth wrote:
Another observation is that many Forthers do not seem to put much
emphasis
on programming time and code maintainability or readability, which is
easier to achieve by using locals.
I won't dispute that using the "locals" shortcut *may* save some
programming time - but to me, the moment you decide to put the whole
shebang in locals, you enter another mindset. Because at that moment you >cease to consider the algorithm itself, but start banging out code.
You no longer consider "do I need that, do I need that now, do I need
that here", you just start creating more local variables. Somehow that
kills my train of mind..
I do dispute that "no locals" Forth kills maintainability - or
readability. I'm always happy to see a whole bunch of one-liners.
Doesn't happen to me every day, but often enough. And then you can >functionally comment your code. I usually comment it from column 40 on
and at the top of a word.
I've maintained non-trivial programs for *DECADES* without any trouble.
I've plugged in a garbage collection module in my uBasic/4tH interpreter
- and radically changed it later. My rule is: if you can't figure it
out, rewrite it until you do. It happens, but not frequently.
Hans Bezemer
What bothers me most technologically is that parameters flow through
the stack undisturbed. You break that paradigm when using locals. With locals you *HAVE TO* create some kind of stack frame that you have to
destroy when you exit.
Needless to say this copying, releasing and stuff takes time.
In all honesty I must state that this overhead is not always
translated to a diminished performance
TL;DR my objections are mostly based on pure architectural arguments,
rather than practicality.
I also don't like Python, PHP and Perl for those very same reasons -
Hans Bezemer <the.beez.speaks@gmail.com> writes:
What bothers me most technologically is that parameters flow through
the stack undisturbed. You break that paradigm when using locals. With
locals you *HAVE TO* create some kind of stack frame that you have to
destroy when you exit.
Forth programs very frequently end up juggling parameters and other data
to and from the return stack, instead of using locals. Simple implementations of locals put them in the return stack too.
"Destroying" the stack frame just means adjusting RP when the function
exits. Usually a single instruction.
...
Hans Bezemer <the.beez.speaks@gmail.com> writes:
What bothers me most technologically is that parameters flow through
the stack undisturbed. You break that paradigm when using locals. With
locals you *HAVE TO* create some kind of stack frame that you have to
destroy when you exit.
Forth programs very frequently end up juggling parameters and other data
to and from the return stack, instead of using locals.
On 10/09/2024 9:26 pm, Paul Rubin wrote:
Hans Bezemer <the.beez.speaks@gmail.com> writes:
What bothers me most technologically is that parameters flow through
the stack undisturbed. You break that paradigm when using locals. With
locals you *HAVE TO* create some kind of stack frame that you have to
destroy when you exit.
Forth programs very frequently end up juggling parameters and other data
to and from the return stack, instead of using locals.
Looking at an application with 154 colon definitions, only 2 were found
to use the return stack for temporary storage. Even I was surprised :)
r 22swap 1
2
Hans Bezemer <the.beez.speaks@gmail.com> writes:A lot depends on how solid you want to make your implementation. I got
What bothers me most technologically is that parameters flow through
the stack undisturbed. You break that paradigm when using locals. With
locals you *HAVE TO* create some kind of stack frame that you have to
destroy when you exit.
Forth programs very frequently end up juggling parameters and other data
to and from the return stack, instead of using locals. Simple implementations of locals put them in the return stack too.
"Destroying" the stack frame just means adjusting RP when the function exits. Usually a single instruction.
Needless to say this copying, releasing and stuff takes time.
Similar to DUP (copy) or DROP (release).
In all honesty I must state that this overhead is not always
translated to a diminished performance
Right, I don't think one can assert a performance hit without
measurements supporting the idea.
TL;DR my objections are mostly based on pure architectural arguments,
rather than practicality.
Sure, that's reasonable, it's a matter of what you prefer. That's
harder to take issue with than claims about performance.
I also don't like Python, PHP and Perl for those very same reasons -
Those are at a totally different level than Forth, in terms of layers of implementation and runtime libraries, overhead, etc. It's better to
compare to something like C, or a hypothetical cleaned up version of C,
or even to Forth with locals ;).
Those are at a totally different level than Forth, in terms of layers of implementation and runtime libraries, overhead, etc. It's better to
compare to something like C, or a hypothetical cleaned up version of C,
or even to Forth with locals ;).
Two classic answers:
use DO..LOOPs to hide away loop indices
use locals if you have too many parameters
(some technical/physical formulas are difficult
or impossible to factorise into smaller words
which would otherwise be the classic Forth mantra)
Tips:
- Use multiple Return Stack registers (R@, R'@, R"@);
- If parameters come in duplets or triplets, use corresponding stack operators (3DUP, 3OVER, 3DROP);
- Reorganize parameters at the *very start* of the program in a more palatable order. It saves stack juggling later on;
- Maybe a strange one, but codify stack patterns!
E.g. SPIN ( a b c -- c b a)
STOW ( a b -- a a b)
RISE ( a b c -- b a c)
It helps you to THINK in these patterns and more easily recognize them.
It depends highly on your coding habits, so it helps to analyze your
legacy code to see if they often occur.
Now, I won't say Forth doesn't have its issues. I think IN ESSENCE >recognizers are a beautiful idea. Extend it to strings and you could >eradicate "parsing words" and have something like:
"lib/mylib.4th" include
"Square" : "the square is:" print dup * cr ;
But okay, we'll do with what we have ;-) And BTW, TURNKEY should be
standard. Clean up the dictionary, pump out an executable.
Hans Bezemer
On Wed, 11 Sep 2024 9:20:14 +0000, Hans Bezemer wrote:
Tips:
- Use multiple Return Stack registers (R@, R'@, R"@);
- If parameters come in duplets or triplets, use corresponding stack
operators (3DUP, 3OVER, 3DROP);
- Reorganize parameters at the *very start* of the program in a more
palatable order. It saves stack juggling later on;
- Maybe a strange one, but codify stack patterns!
E.g. SPIN ( a b c -- c b a)
STOW ( a b -- a a b)
RISE ( a b c -- b a c)
It helps you to THINK in these patterns and more easily recognize them.
It depends highly on your coding habits, so it helps to analyze your
legacy code to see if they often occur.
Good advice if you can access the return stack directly.
Otherwise, for non-trivial words, it is preferable to let the compiler recognise patterns and save your precious human time. If the compiled
code is too bad, profile and optimise it afterwards.
On 30-08-2024 22:32, minforth wrote:
Two classic answers:
use DO..LOOPs to hide away loop indices
use locals if you have too many parameters
(some technical/physical formulas are difficult
or impossible to factorise into smaller words
which would otherwise be the classic Forth mantra)
Tips:
- Use multiple Return Stack registers (R@, R'@, R"@);
- If parameters come in duplets or triplets, use corresponding stack operators (3DUP, 3OVER, 3DROP);
- Reorganize parameters at the *very start* of the program in a more palatable order. It saves stack juggling later on;
- Maybe a strange one, but codify stack patterns!
E.g. SPIN ( a b c -- c b a)
STOW ( a b -- a a b)
RISE ( a b c -- b a c)
It helps you to THINK in these patterns and more easily recognize them. It depends highly on your coding habits, so it helps to analyze your legacy code to see if they often occur.
Looking at an application with 154 colon definitions...From the same app:
The easiest stack operations (DUP DROP) account for most.
SWAP averaged 1 in 7 definitions. OVER 1 in 9. Is 'stack juggling' a problem in forth? It doesn't appear to be.
You comfortable left out the initialization of the stack
frame. Agreed, if ALL values are transferred to the return stack the
overhead is minimal. But how often happens that?
True - but that's not the level of abstraction I'm considering. I
think a language should have a well designed core, surrounded by a constellation of extensions. Like C with its standard library and
Forth with its word sets.
dxf <dxforth@gmail.com> writes:
Looking at an application with 154 colon definitions...From the same app:
The easiest stack operations (DUP DROP) account for most.
Is the code for this app available?
SWAP averaged 1 in 7 definitions. OVER 1 in 9. Is 'stack juggling' a
problem in forth? It doesn't appear to be.
The 100+ occurrences of DUP, DROP, and SWAP are either an abstraction inversion (with a smart compiler, the data ends up in registers that
could be named by locals) or they are stack traffic whose cost has to be compared with the cost of indexed references to locals in the return
stack. I'd agree that they aren't necessary "juggling" which evokes permuting stuff in the stack outside the usual FIFO order. That does
happpen a little bit though, with OVER, ROT, etc.
If a cost, it's one the programmer can keep to minimum. With locals
there's
an upfront cost that can't be avoided. Using registers is appealing
until
one realizes a call to an external function necessitates placing it back
on
the stack. Costs multiply in the face of many small functions.
This is history (or your archaic compiler). Modern compilers try to pass
most parameters through registers.
The 100+ occurrences of DUP, DROP, and SWAP are either an abstraction >inversion (with a smart compiler, the data ends up in registers that
could be named by locals)
or they are stack traffic whose cost has to be
compared with the cost of indexed references to locals in the return
stack.
I'd agree that they aren't necessary "juggling" which evokes
permuting stuff in the stack outside the usual FIFO order. That does
happpen a little bit though, with OVER, ROT, etc.
Using registers is appealing until
one realizes a call to an external function necessitates placing it back on >the stack.
Costs multiply in the face of many small functions.
dxf <dxforth@gmail.com> writes:
Using registers is appealing until
one realizes a call to an external function necessitates placing it back on >> the stack.
Not if the stack item does not live across the call. And even if it
lives across the call and cannot be placed in a callee-saved register,
the save before and restore after the call is amortized typically
across more than one register access on each side of the call.
Register allocation is one of the most effective optimizations in
compilers. That's also true of Forth.
Costs multiply in the face of many small functions.
Register allocation is also effective for small functions.
On 12/09/2024 8:19 pm, Anton Ertl wrote:
Register allocation is one of the most effective optimizations in
compilers. That's also true of Forth.
Costs multiply in the face of many small functions.
Register allocation is also effective for small functions.
Moore talked about registers. It's worth repeating for those who may be
new
to forth.
"But such registers raises the question of local variables. There is a
lot of
discussion about local variables. That is another aspect of your application
where you can save 100% of the code. I remain adamant that local
variables
are not only useless, they are harmful. If you are writing code that
needs
them you are writing, non-optimal code" - Chuck Moore 1999
On Thu, 12 Sep 2024 23:37:29 +0000, dxf wrote:
On 12/09/2024 8:19 pm, Anton Ertl wrote:
Register allocation is one of the most effective optimizations in
compilers. That's also true of Forth.
Costs multiply in the face of many small functions.
Register allocation is also effective for small functions.
Moore talked about registers. It's worth repeating for those who may be
new
to forth.
"But such registers raises the question of local variables. There is a
lot of
discussion about local variables. That is another aspect of your
application
where you can save 100% of the code. I remain adamant that local
variables
are not only useless, they are harmful. If you are writing code that
needs
them you are writing, non-optimal code" - Chuck Moore 1999
The only thing that can be deduced from this is that back in 1999
this was Moore's opinion in the specific context of his work.
Besides, the world has changed a wee bit since then...
"I remain adamant that local variables are not only useless, they
are harmful. If you are writing code that needs them you are
writing, non-optimal code" - Chuck Moore 1999 ...
Claims made in respect of locals in forth - ease of use, better
performance through less 'stack juggling', better
readability/maintainability - were all made in the 1980's. What has
changed? Forthers today are more willing to believe, to accept the
word of authority, lack the interest to discover the truth for
themselves?
On 13/09/2024 5:56 pm, minforth wrote:
On Thu, 12 Sep 2024 23:37:29 +0000, dxf wrote:
On 12/09/2024 8:19 pm, Anton Ertl wrote:
Register allocation is one of the most effective optimizations in
compilers. That's also true of Forth.
Costs multiply in the face of many small functions.
Register allocation is also effective for small functions.
Moore talked about registers. It's worth repeating for those who may be >>> new
to forth.
"But such registers raises the question of local variables. There is a >>> lot of
discussion about local variables. That is another aspect of your
application
where you can save 100% of the code. I remain adamant that local
variables
are not only useless, they are harmful. If you are writing code that >>> needs
them you are writing, non-optimal code" - Chuck Moore 1999
The only thing that can be deduced from this is that back in 1999
this was Moore's opinion in the specific context of his work.
Besides, the world has changed a wee bit since then...
Claims made in respect of locals in forth - ease of use, better performance >through less 'stack juggling', better readability/maintainability - were all >made in the 1980's. What has changed? Forthers today are more willing to >believe, to accept the word of authority, lack the interest to discover the >truth for themselves? If so, that would be a pity.
I would say that the claim of better performance from locals depends
on the implementation[...]
dxf <dxforth@gmail.com> writes:
"I remain adamant that local variables are not only useless, they
are harmful. If you are writing code that needs them you are
writing, non-optimal code" - Chuck Moore 1999 ...
Claims made in respect of locals in forth - ease of use, better
performance through less 'stack juggling', better
readability/maintainability - were all made in the 1980's. What has
changed? Forthers today are more willing to believe, to accept the
word of authority, lack the interest to discover the truth for
themselves?
Is avoiding locals because of the Chuck Moore quote not an example of accepting the word of authority?
Absolutely. As Chucks prime target of interest (hardware) uses LIFO >registers for stacks, only the top top one, or so, R stack items could
be used for restricted local storage (which is also common practice).
I accept that locals are useful, and would like to see hardware stack
engine implementations that support this better while retaining the >performance advantage of a stack cache implemented as LIFO registers
rather than in RAM.
Claims made in respect of locals in forth - ease of use, better performance >through less 'stack juggling', better readability/maintainability - were all >made in the 1980's.
What has changed? Forthers today are more willing to
believe, to accept the word of authority
dxf <dxforth@gmail.com> writes:
Claims made in respect of locals in forth - ease of use, better performance >> through less 'stack juggling', better readability/maintainability - were all >> made in the 1980's.
Where can I find claims about better performance? All I have read is
claims about worse performance.
What has changed? Forthers today are more willing to
believe, to accept the word of authority
Is that why you cite Chuck Moore on locals rather than arguing from
facts?
The facts AFAICT is locals are an appeal to prejudice.
On 14/09/2024 4:07 am, Anton Ertl wrote:
Where can I find claims about better performance? All I have read is
claims about worse performance.
'Eliminate stack juggling' sounds like an argument for better performance.
dxf <dxforth@gmail.com> writes:
On 14/09/2024 4:07 am, Anton Ertl wrote:
Where can I find claims about better performance? All I have read is
claims about worse performance.
'Eliminate stack juggling' sounds like an argument for better performance.
Not to me. To me it sounds like a statement about the ease of writing
and reading the code.
The performance of locals vs. stack juggling depends on the
implementation.
...
You have the source to my app. Perhaps you can nominate where locals
could have been used to better effect.
dxf <dxforth@gmail.com> writes:
You have the source to my app. Perhaps you can nominate where locals
could have been used to better effect.
: EMITS ( n char -- ) swap 0 ?do dup emit loop drop ;
could be written:
: EMITS {: n char -- :} n 0 ?do char emit loop ;
On 12/09/2024 4:51 pm, Paul Rubin wrote:
dxf <dxforth@gmail.com> writes:https://pastebin.com/2xcRSbQW
SWAP averaged 1 in 7 definitions. OVER 1 in 9. Is 'stack juggling' a
problem in forth? It doesn't appear to be.
Hi,
In fuzzy logic, a triangular membership function mf(x;a,b,c) is defined
as:
mf(x;a,b,c) = (x-a)/(b-a) for a <= x < b,
(c-x)/(c-b) for b <= x < c,
0e elsewere.
defining it with locals:
: tri_mf() { f: x f: a f: b f: c } ( f: x a b c -- mv)
x a f>= x b f< and if x a f- b a f- f/ exit then
x b f>= x c f< and if c x f- c b f- f/ exit then
0e
;
But defining it without locals ????!!!!!
: tri_mf() ( f: x a b c -- mv) ....
How?
Compiling under DX-Forth resulted in a code size of 23 and 26 bytes respectively. Under VFX ...
Not only were you able to read forth code, the result was more
efficient.
I wonder if the notation "mf(x;a,b,c)" indicates that a,b,c is a tuble
that tends to get passed around without changing it. In that case
defining it as a structure in memory and accessing its members there
might be a solution.
But OTOH, unless you see programming in Forth as a religious exercise,
why worry, as long as your solution works.
utime 0.1e neg_big utime d- dnegate d.Oops.
with locals: about 19 ms
without locals: about 18 ms
Ahmed
On Sat, 14 Sep 2024 17:13:51 +0000, Ahmed wrote:
utime 0.1e neg_big utime d- dnegate d.Oops.
with locals: about 19 ms
without locals: about 18 ms
Ahmed
Please read micro seconds (us) instead of milli seconds (ms).
with locals: about 19 us
without locals: about 18 us
That can't be correct.You are right.
FORTH> tnb
\ no locals: 4.9ns/call.
\ locals: 21.3ns/call. ok
-marcel
dxf <dxforth@gmail.com> writes:
Compiling under DX-Forth resulted in a code size of 23 and 26 bytes
respectively. Under VFX ...
I can't help it if those compilers generate worse code for the locals version. Can you conveniently try lxf?
Not only were you able to read forth code, the result was more
efficient.
Sometimes it isn't too hard to read, sometimes it takes head scratching,
and sometimes I can't make any sense of it. The function Anton posted
was an example that didn't make sense. I remember thinking I might sit
down and try to figure it out to rewrite it, but it doesn't seem worth
the effort.
Anyway, if efficiency was important for that example, I'd use CODE.
dxf <dxforth@gmail.com> writes:
On 12/09/2024 4:51 pm, Paul Rubin wrote:
dxf <dxforth@gmail.com> writes:https://pastebin.com/2xcRSbQW
SWAP averaged 1 in 7 definitions. OVER 1 in 9. Is 'stack juggling' a >>>> problem in forth? It doesn't appear to be.
: ARG ( n -- adr len -1 | 0 )
>r 0 0 cmdtail r> 0 ?do
2nip
bl skip 2dup bl scan
rot over - -rot
loop 2drop
dup if -1 end and ;
The heavy use of global variables in this program also does not
support the idea that proper usage of the stacks makes locals
unnecessary.
You are right.
I find with gforth:
: go 0 do -0.1e neg_big fdrop loop ;
without locals:
utime 100000000 go utime d>f d>f f- 1e-8 f* f. 0.06762074 us ok for 1e8 times: (67.62 ns)
and with locals:
utime 100000000 go utime d>f d>f f- 1e-8 f* f. 0.09961387 us ok for
1e8 times: (99.61 ns)
I missused the timing in the previous post.
Thanks for the correction.
So with gforth it's about 30 nanosecs runtime disadvantage.
IOW if you run the code 3*10^7 times it adds up to 1 sec disadvantage.
While the locals version was easy to code, pretty straightforward and probably bug-free out of the box, how long did it take to code and debug
the stack juggling version?
On Sun, 15 Sep 2024 6:17:18 +0000, minforth wrote:
So with gforth it's about 30 nanosecs runtime disadvantage.
IOW if you run the code 3*10^7 times it adds up to 1 sec disadvantage.
I think you mean: if you run the code 3*10^8 times it adds up to 1 sec disadvantage.
On Sat, 14 Sep 2024 15:08:36 +0000, Anton Ertl wrote:
I wonder if the notation "mf(x;a,b,c)" indicates that a,b,c is a tuble
that tends to get passed around without changing it. In that case
defining it as a structure in memory and accessing its members there
might be a solution.
a, b and are the parameters of the membership function.
Yes, we can use structures, arrays ...
But OTOH, unless you see programming in Forth as a religious exercise,
why worry, as long as your solution works.
I did it without locals as an exercise. Here it is:
Without locals:
: tri_mf: ( f: a b c )
create frot f, fswap f, f,
does> ( ad_a) ( f: x) dup fdup ( ad_a ad_a) ( f: x x)
f@ ( ad_a) ( f: x x a)
f>= ( ad_a -1|0) ( f: x) over float+ ( ad_a -1|0 ad_b) ( f: x)
fdup f@ ( ad_a -1|0) ( f: x x b) f< and if ( ad_a) ( f: x) dup f@ f- ( ad_a) ( f: x-a) dup f@ ( ad_a) ( f: x-a a) float+ ( ad_b) ( f: x-a a) f@ fswap f- ( f: x-a b-a)
f/ ( f: [x-a]/[b-a])
exit
then
float+ ( ad_b) ( f: x) dup fdup ( ad_b ad_b) ( f: x x)
f@ ( ad_b) ( f: x x b)
f>= ( ad_b -1|0) ( f: x) over float+ ( ad_b -1|0 ad_c) ( f: x)
fdup f@ ( ad_b -1|0) ( f: x x c) f< and if ( ad_b) ( f: x) dup float+ f@ ( ad_b) ( f: x c) f- ( ad_b) ( f: x-c) dup float+ ( ad_b ad_c) ( f: x-c) swap f@ f@ f- ( f: x-c b-c)
f/ ( f: [x-c]/[b-c])
exit
then
drop fdrop
0e
;
That appears no better than FVALUEs ...
0e fvalue a
0e fvalue b
0e fvalue c
0e fvalue x
: tri_mf() ( f: x a b c -- mv)
to c to b to a to x
x a f>=
x b f< and if
x a f- b a f- f/ exit
then
x b f>=
x c f< and if
c x f- c b f- f/ exit
then
0e
;
dxf <dxforth@gmail.com> writes:
You have the source to my app. Perhaps you can nominate where locals
could have been used to better effect.
: EMITS ( n char -- ) swap 0 ?do dup emit loop drop ;
could be written:
: EMITS {: n char -- :} n 0 ?do char emit loop ;
Hi,
In fuzzy logic, a triangular membership function mf(x;a,b,c) is defined
as:
mf(x;a,b,c) = (x-a)/(b-a) for a <= x < b,
(c-x)/(c-b) for b <= x < c,
0e elsewere.
defining it with locals:
: tri_mf() { f: x f: a f: b f: c } ( f: x a b c -- mv)
x a f>= x b f< and if x a f- b a f- f/ exit then
x b f>= x c f< and if c x f- c b f- f/ exit then
0e
;
But defining it without locals ????!!!!!
: tri_mf() ( f: x a b c -- mv) ....
How?
Ahmed--
On Sat, 14 Sep 2024 17:41:23 +0000, Ahmed wrote:
On Sat, 14 Sep 2024 17:13:51 +0000, Ahmed wrote:
utime 0.1e neg_big utime d- dnegate d.Oops.
with locals: about 19 ms
without locals: about 18 ms
Ahmed
Please read micro seconds (us) instead of milli seconds (ms).
with locals: about 19 us
without locals: about 18 us
That can't be correct.
In iForth I used dfloats instead of floats
( 4.9ns instead of 7.3ns).
Using structs is not a great idea in this case.
anew -testlocals
: tri_mf: ( f: a b c )
create frot df, fswap df, df,
does> ( F: x -- y )
( ad_a) ( f: x)
dup fdup ( ad_a ad_a) ( f: x x)
df@ ( ad_a) ( f: x x a)
f>= ( ad_a -1|0) ( f: x)
over dfloat+ ( ad_a -1|0 ad_b) ( f: x)
fdup df@ ( ad_a -1|0) ( f: x x b)
f< and if ( ad_a) ( f: x)
dup df@ f- ( ad_a) ( f: x-a)
dup df@ ( ad_a) ( f: x-a a)
dfloat+ ( ad_b) ( f: x-a a)
f@ fswap f- ( f: x-a b-a)
f/ ( f: [x-a]/[b-a])
exit
then
dfloat+ ( ad_b) ( f: x)
dup fdup ( ad_b ad_b) ( f: x x)
df@ ( ad_b) ( f: x x b)
f>= ( ad_b -1|0) ( f: x)
over dfloat+ ( ad_b -1|0 ad_c) ( f: x)
fdup df@ ( ad_b -1|0) ( f: x x c)
f< and if ( ad_b) ( f: x)
dup dfloat+ df@ ( ad_b) ( f: x c)
f- ( ad_b) ( f: x-c)
dup dfloat+ ( ad_b ad_c) ( f: x-c)
swap df@ df@ f- ( f: x-c b-c)
f/ ( f: [x-c]/[b-c])
exit
then
drop fdrop
0e
;
-1e309 -1e 0e tri_mf: nol_neg_big
: (tri_mf) ( f: x a b c -- mv)
FLOCALS| c b a x |
x a f>= x b f< and if x a f- b a f- f/ exit then
x b f>= x c f< and if c x f- c b f- f/ exit then
0e ;
: loc_neg_big -1e309 -1e 0e (tri_mf) ;
: .timing MS? S>F 1e-3 F* 1e7 F/ F.N2 ." s/call." ;
: tnb CR ." \ no locals: " TIMER-RESET #10000000 ( 1e7 times )
0 DO -10e nol_neg_big FDROP LOOP .timing
CR ." \ locals: " TIMER-RESET #10000000 ( 1e7 times )
0 DO -10e loc_neg_big FDROP LOOP .timing ;
FORTH> tnb--
\ no locals: 4.9ns/call.
\ locals: 21.3ns/call. ok
-marcel
On 14/09/2024 10:32 pm, Anton Ertl wrote:
The heavy use of global variables in this program also does not
support the idea that proper usage of the stacks makes locals
unnecessary.
I see many small colon definitions and very few variables - global or
local:
integer #TERMS \ number of terminals in DTA file
integer TERM \ working terminal#
variable #DIGIT
variable LEN
integer MAXCHR
The first two are necessarily global and would exist regardless.
The remaining three are used by a group of functions with the view of
keeping them simple. The alternative would be to carry them around as >parameters shuffling them from one function to another. That seems
worse to me.
This unearthed a "bug": -1e309 does not fit in a dfloat,
it prints as -Inf.
locals stack
401 336 gforth-fast (AMD64)
179 132 lxf 1.6-982-823 (IA-32)
182 119 VFX FX Forth for Linux IA32 Version: 4.72 (IA-32)
241 159 VFX Forth 64 5.43 (AMD64)
163 175 iforth-5.1 mini (AMD64)
Going back to the EMITS example:
- despite lack of comments you quickly deduced what it did
- stack operations were few and simple and still you didn't like it
- your ideal is that every stack operation should go, which is what
you did
If one takes from forth that which makes it efficient, then one takes away its reason for existence. Unfortunately for forth, this is what locals
users are doing, whether they're aware of it or not.
Anyway, if efficiency was important for that example, I'd use CODE.In other words forth is not important to you.
That appears no better than FVALUEs ...
On 14 Sep 2024 at 08:19:52 CEST, "Anton Ertl" <Anton Ertl> wrote:
locals stack
401 336 gforth-fast (AMD64)
179 132 lxf 1.6-982-823 (IA-32)
182 119 VFX FX Forth for Linux IA32 Version: 4.72 (IA-32)
241 159 VFX Forth 64 5.43 (AMD64)
163 175 iforth-5.1 mini (AMD64)
There are design decisions within locals that can impact optimisation.
The design of locals in VFX was influenced by Don Colburn's Forth's
and by a desire to use locals to simplify source code when interfacing
to a host operating system. Many operating systems return data
to the caller by passing the address of a variable/buffer as an input >parameter. Locals that can have an accessible address make such
code much easier to read and write.
In the last
decade or so there has been very little customer demand for
faster code.
However, higher level source code has been much
in demand. An example is Nick Nelson's value flavoured structures,
which are of particular merit when converting code from 32 bit to
64 bit host Forths.
Just because many of the Forth applications visible to the Forth
community now run on CPUs with 16 or 32 address registers
does not mean that all systems can implement the compiler
techniques required for high-performance locals.
I can buy a lot of CPU cycles for the cost of one day of programmer
time.
So by keeping the values on the stack you not just eliminate their
repeated mention, but also eliminate one branch of the IF.
I can buy a lot of CPU cycles for the cost of one day of programmer
time.
Some guy called Stephen Pelc (must be a different one) recentlu posted <vbkdu0$1v8lq$1@dont-email.me>:
|We (MPE) converted much of our TCP/IP stack not to use locals. This
|was mostly on ARM7 devices, but the figures for other 32 bit CPUs of
|the period (say 15 years ago) were similar. Code density improved by
|about 25% and performance by about 50%.
How much time did that conversion cost? And this Stephen Pelc
suggested that Buzz McCool (and probably everyone else) should also
spend their time on avoiding and eliminating locals from their code.
I am with you here, not with the other Stephen Pelc: Programmers
should use locals liberally if it saves them time, even in the face of
slow locals implementations, because you can buy a lot of CPU cycles
for the additional programming cost of avoiding locals.
I would not make that trade off today.
So there's only one Stephen Pelc but two application domains.
dxf <dxforth@gmail.com> writes:
Going back to the EMITS example:
- despite lack of comments you quickly deduced what it did
- stack operations were few and simple and still you didn't like it
- your ideal is that every stack operation should go, which is what
you did
It was the first word in the program that used any stack operations at
all. I saw that it was more concise and imho more readable without
them. Other words there were much harder to read.
If one takes from forth that which makes it efficient, then one takes away >> its reason for existence. Unfortunately for forth, this is what locals
users are doing, whether they're aware of it or not.
I'm not persuaded that the stack ops make Forth efficient.
Certainly
not as much as advanced compilers do, and yet one of the big attractions
of Forth has been very simple interpreters.
On my x86-64 laptop, gcc -c -S -Os on
void emit(char);
void emits(char c, int n) {
while (n-- > 0) emit(c);
}
gives me 27 bytes, 15 instructions, beating all of the Forth examples. Several of the 14 instructions seem related to passing parameters in registers. Passing on the stack like in old fashioned systems would
save a few more, at the expense of some speed. So if I want efficiency,
I should use C.
Anyway, if efficiency was important for that example, I'd use CODE.In other words forth is not important to you.
I would say efficiency is usually not very important to me, whether in
forth or any other language. It's the usual story of programs having
hot spots. Aim for efficiency in the hot spots and readability and ease
of implementation everywhere else.
Also, you define "forth" as using stack ops instead of locals. I don't define it that way. Forth with locals is still Forth. They are in the standard after all.
dxf <dxforth@gmail.com> writes:
That appears no better than FVALUEs ...
Those are essentially global variables, with all of their issues.
With apparently little issue for the case presented. The push is
to write idiot-proof code that can be used anywhere. Moore calls
that 'solving the general problem' - which he eschews.
Moore calls that 'solving the general problem' - which he eschews.
dxf <dxforth@gmail.com> writes:
With apparently little issue for the case presented. The push is
to write idiot-proof code that can be used anywhere. Moore calls
that 'solving the general problem' - which he eschews.
Didn't one of the Chuck Moore quotes you posted say using the stacks was better for information hiding than using globals?
That includes the
return or locals stack, of course. Your computer hardware has the
capability of accessing inside the stack randomly, and Forth has words
like 2ROT which reach up to 6 levels deep in the parameter stack.
What's wrong with being able to give names to the cells? I don't
understand the obsession with refusing to use those capabilities of your hardware.
The central idea of Forth to me is its traditional implementation as a threaded interpreter with its extremely simple one-pass compiler. That
made it possible to make a complete interactive development environment
on a 1970s minicomputer with a floppy disc. All the language features
like the stack oriented VM are just incidental affordances on the route
to that simple interpreter. To the extent that there is a cult of the
stack machine, I don't belong to it.
Moore calls that 'solving the general problem' - which he eschews.
The idea as I saw it was don't do extra work to solve the general
problem, if a simpler approach solves the immediate problem at hand.
If the general solution takes LESS work then the limited one, then doing
the extra work for the limited solution is just masochism.
Stephen Pelc <stephen@vfxforth.com> writes:
I would not make that trade off today.
So there's only one Stephen Pelc but two application domains.
I wonder how much effort de-localizing the TCP/IP stack took, compared
to hypothetically updating the compiler to optimize locals more. If the TCP/IP stack code can compile with iForth or lxf, is there a way to
compare the code size with VFX's? I can understand wanting to use VFX
for actual delivery, of course.
[..]
FORTH> tnb
\ no locals: 5ns/call.
\ locals: 18.2ns/call.
\ globals: 6ns/call.
\ no locals2: 21.9ns/call. ok
This appears not to be a good idea.
The root cause is piling up too many
items on the F-stack (exceeding the
hardware FPU stack limits).
On 16/09/2024 8:13 pm, mhx wrote:
[..]
FORTH> tnb
\ no locals: 5ns/call.
\ locals: 18.2ns/call.
\ globals: 6ns/call.
\ no locals2: 21.9ns/call. ok
This appears not to be a good idea.
The root cause is piling up too many
items on the F-stack (exceeding the
hardware FPU stack limits).
FVALUEs may be the way to go for hardware stack.
Is this any better?
: tri_mf ( f: x a b c -- mv)
3 fpick ( x) 3 fpick ( x a) f>=
3 fpick ( x) 2 fpick ( x b) f< and if
fdrop \ x a b
frot 2 fpick f- \ a b x-a
fswap frot f- \ x-a b-a
f/ exit
then
3 fpick ( x) 2 fpick ( x b) f>=
3 fpick ( x) 1 fpick ( x c) f< and if
frot fdrop \ x b c
frot fover fswap f- \ b c c-x
fswap frot f- \ c-x c-b
f/ exit
then
fdrop fdrop fdrop fdrop 0e
;
FVALUEs may be the way to go for hardware stack.
Is this any better?
: tri_mf ( f: x a b c -- mv)
3 fpick ( x) 3 fpick ( x a) f>=
3 fpick ( x) 2 fpick ( x b) f< and if
fdrop \ x a b
frot 2 fpick f- \ a b x-a
fswap frot f- \ x-a b-a
f/ exit
then
3 fpick ( x) 2 fpick ( x b) f>=
3 fpick ( x) 1 fpick ( x c) f< and if
frot fdrop \ x b c
frot fover fswap f- \ b c c-x
fswap frot f- \ c-x c-b
f/ exit
then
fdrop fdrop fdrop fdrop 0e
;
Local buffers are remarkably useful.
anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
So by keeping the values on the stack you not just eliminate their
repeated mention, but also eliminate one branch of the IF.
Is the repeated mention just a matter of DRY, assuming the compiler puts
the locals in registers so that the extra mention doesn't transfer them >between stacks a second time?
I wonder whether Moore's 1999 aversion to locals had something to do
with his hardware designs of that era, where having more registers
(besides T and N) connected to the ALU would have cost silicon and
created timing bottlenecks.
Today's mainstream processors have GPR's
anyway, but I wonder what the real problem was with stack caches like
the CRISP: https://thechipletter.substack.com/p/at-and-ts-crisp-hobbits
I remember the SPARC had "register windows" but I don't know if that's >similar or what went wrong with them.
On 15 Sep 2024 at 18:16:34 CEST, "Anton Ertl" <Anton Ertl> wrote:
I can buy a lot of CPU cycles for the cost of one day of programmer
time.
Some guy called Stephen Pelc (must be a different one) recentlu posted
<vbkdu0$1v8lq$1@dont-email.me>:
|We (MPE) converted much of our TCP/IP stack not to use locals. This
|was mostly on ARM7 devices, but the figures for other 32 bit CPUs of
|the period (say 15 years ago) were similar. Code density improved by
|about 25% and performance by about 50%.
How much time did that conversion cost? And this Stephen Pelc
suggested that Buzz McCool (and probably everyone else) should also
spend their time on avoiding and eliminating locals from their code.
I am with you here, not with the other Stephen Pelc: Programmers
should use locals liberally if it saves them time, even in the face of
slow locals implementations, because you can buy a lot of CPU cycles
for the additional programming cost of avoiding locals.
What you ignore is that the constraints of embedded systems with small
alow CPUs (by comparison with desktop CPUs) are very different from
those of desktop CPUs. Converting the TCP/IP stack was driven by the
client requirement to fit a TCP/IP app into 128k/256k Flash and 16k RAM.
I would not make that trade off today.
On 15 Sep 2024 at 23:45:22 CEST, "Paul Rubin" <no.email@nospam.invalid> wrote:
Stephen Pelc <stephen@vfxforth.com> writes:
I would not make that trade off today.
So there's only one Stephen Pelc but two application domains.
I wonder how much effort de-localizing the TCP/IP stack took, compared
to hypothetically updating the compiler to optimize locals more. If the
TCP/IP stack code can compile with iForth or lxf, is there a way to
compare the code size with VFX's? I can understand wanting to use VFX
for actual delivery, of course.
On modern desktop CPUs, I would probably spend the effort on
optimising locals more. However, the ability to provide the address
of a local is essential in our world. I have not inspected our code
base to see how many uses of a local declaration of a buffer
: bah {: ... | FOO[ cell ] ... -- :}
there are compared to the use of the ADDR (address) operator
applied to a normally defined local
: bah {: ... | FOO ... -- :}
...
addr FOO
Yes, that's why Gforth does not support ADDR for locals by default:
This appears not to be a good idea. The root cause is piling up too
many items on the F-stack (exceeding the hardware FPU stack limits).
The experimental PARAMS| a | construct does not support 'OF and tries
to keep integer locals in a register.
mhx@iae.nl (mhx) writes:
This appears not to be a good idea. The root cause is piling up too
many items on the F-stack (exceeding the hardware FPU stack limits).
I wonder if any Forth compilers use SSE instead of the x86 FPU stack.
mhx@iae.nl (mhx) writes:
This appears not to be a good idea. The root cause is piling up too
many items on the F-stack (exceeding the hardware FPU stack limits).
I wonder if any Forth compilers use SSE instead of the x86 FPU stack.
mhx@iae.nl (mhx) writes:[..]
The experimental PARAMS| a | construct does not support 'OF and tries
to keep integer locals in a register.
Yes, in the right setting PARAMS| is very nice, too bad it's not used
for (LOCAL) (or directly for {:).
mhx@iae.nl (mhx) writes:
This appears not to be a good idea. The root cause is piling up too
many items on the F-stack (exceeding the hardware FPU stack limits).
I wonder if any Forth compilers use SSE instead of the x86 FPU stack.
On Mon, 16 Sep 2024 19:16:09 +0000, Paul Rubin wrote:
mhx@iae.nl (mhx) writes:
This appears not to be a good idea. The root cause is piling up too
many items on the F-stack (exceeding the hardware FPU stack limits).
I wonder if any Forth compilers use SSE instead of the x86 FPU stack.
iForth would, if my tests had showed any positive effect.
(The effect has to be substantial to outweigh the advantage of 80-bit
floats whenever accuracy counts.)
I wrote routines to process 4 floats. For unfathomable reasons, they
are not nearly as good a pre-packaged library code. There is only
limited potential for standard FP code to benefit from SSE. If
parallelism can't be exploited, SSE does not seem to bring
anything over the old FPU. But maybe my hardware was not
good enough a few years back.
With SSE I need a substantial library for special functions,
which then become relatively slow DLL calls.
The only thing wrong with the FPU is that the special stack
overflow interrupts don't work.
-marcel--
In ciforth:
I added floating point support using the FPU with relatively
little work, especially because the transcendentals are easy.
I suspect that it might be not standard. E.g. F+ exhibits
more precision in 80 bits, and we are supposed to use
either IEEE 32 or 64 bits. Apparently I'm in good company
(iforth and vfxforth).
What does the language lawyers say?
That, too, but the elimination of the ELSE has more weight with me.
: WORD1 {: x1 x2 -- :}
... ( f ) if ( )
... x1 ... x2 ...
then ;
: WORD2 ( x1 x2 -- )
... ( f ) if ( x1 x2 )
...
else
2drop
then ;
Forth has a special word ?DUP for one specific variant of thisThat's one of the reasons I don't like it - and don't support it
situation, but it helps only in specific cases.
The current VFX 64 bit systems for x64 allow you to select float packs for
80x87 8 item internal stack
hfp87 80x87 external stack
SSE external stack
Paul Rubin <no.email@nospam.invalid> writes:
...
I wonder whether Moore's 1999 aversion to locals had something to do
with his hardware designs of that era, where having more registers
(besides T and N) connected to the ALU would have cost silicon and
created timing bottlenecks.
I think he had the aversion long before he did such hardware designs.
He has been quoted as thinking that humans should do all they can to
make the computer's work easier (or something like that). While his
sayings, like any religious text, are sufficiently fuzzy to be
interpretable in many ways, his denouncing of locals over the years
makes it clear that he thinks that humans should invest time to write
code with stack manipulation words and globals, so that the compiler
does not need to be bloated by the code for dealing with locals.
...Moore has never changed his position, switched his tune, introduced
locals and mega-compilers - as the latter do today in an attempt to
maintain the interest, maintain a following.
dxf <dxforth@gmail.com> writes:
...Moore has never changed his position, switched his tune, introduced
locals and mega-compilers - as the latter do today in an attempt to
maintain the interest, maintain a following.
Weren't we just quibbling about small (few percent) efficency
differences between using locals and using stack words? You get far
greater efficiency gains by using optimizing compilers. If you feel
like the optimizing compiler is needless bloat and want to use an
interpreter instead, that's fine, it just means that (like most of us), you've found that code speed isn't that important for whatever you're
doing. Stephen Pelc posted a few days ago that in the past decade, his customers have stopped asking for faster code.
I think that is a better takeaway than "well we can give up the
optimizing compiler, because using stack words instead of locals
recovers a few percent of the lost speed".
I think we're retreading old ground. Orders of 30% reduction in code
size were in respect of optimizing compilers (VFX).
I can assure you I don't find using stack operators a burden. Indeed
I find them reassuring as it puts me in control.
Forth is a niche language. If there's success to be had, it will be
on its own merits and not ideas imported from other languages.
dxf <dxforth@gmail.com> writes:
I think we're retreading old ground. Orders of 30% reduction in code
size were in respect of optimizing compilers (VFX).
That 30% difference was because VFX doesn't attempt to optimize locals.
If two pieces of code are obviously equivalent (the locals and no-locals version of EMITS) then a fancier optimizing compiler is likely to
generate the same code for both.
...
Forth is a niche language. If there's success to be had, it will be
on its own merits and not ideas imported from other languages.
That seems to support looking at any particular feature on its merits.
Adding to that a dislike of standardization, it would seem to be up to
the programmer, with most choices being legitmate for any particular programmer.
That 30% difference was because VFX doesn't attempt to optimize locals.What's the evidence? My observation is compilers do not generate
native code independently of the language. Parameter passing
strategies differ between C and Forth and this necessarily affects the
code compilers lay down.
For me it comes down why have I chosen to use Forth. The philosophy
of it appeals to me in a way other languages don't. There's the
question which forth - because forth has essentially split down two
paths with rather incompatible motivations.
FWIW 2, I suspect most computing operations in the real world right
now are spent in GPU kernels or large parallel batch jobs, rather
than in ordinary single-CPU programs.
dxf <dxforth@gmail.com> writes:
That 30% difference was because VFX doesn't attempt to optimize locals.What's the evidence? My observation is compilers do not generate
native code independently of the language. Parameter passing
strategies differ between C and Forth and this necessarily affects the
code compilers lay down.
1) comparisons between VFX and other compilers like iForth, 2) the observation that there is any difference at all between the generated
code for the two versions of EMITS under VFX.
This isn't a question of C vs Forth.
It's two equivalent pieces of
Forth code being compiled by the same optimizing Forth compiler, one
version resulting in worse code instead of identical code.
For me it comes down why have I chosen to use Forth. The philosophy
of it appeals to me in a way other languages don't. There's the
question which forth - because forth has essentially split down two
paths with rather incompatible motivations.
I gather that one path is industrial users who want there to be a
standard with well-supported commercial implementations, and who want to
run development projects with large teams of programmers (the Saudi
airport being the classic example).
I guess the other path is something like solo practitioners who don't
really care about standardization, perhaps because they just want the
most direct way to an end result. Philosophical appeal is another such motivation. That's fine too, but partly a matter of personal taste.
What I'm unclear about is what the philosophical purist path has to say
about optimizing compilers. I think anyone wanting to reject locals for >reasons of code efficiency, probably should be using a VFX-style
compiler. My own idea of purity says to use a simple interpreter and
accept the speed penalty, using CODE when needed.
Maybe I'm a purist. Indirect threaded code is a clear expression
of programmers intent. That is the ideal foundation on which to
build optimisers.
My own idea of purity says to use a simple interpreter and accept the
speed penalty, using CODE when needed.
Indirect threaded code is a clear expression of programmers intent.
The only requirement for an optimiser is that the results are the
same. The program can be shorter or faster. Locals are a hindrance.
Perhaps I misunderstood. So we agree Forth locals are unlikely to
ever match C locals for performance?
I don't know whether it's possible to make forth code using locals as efficient as forth code using stack operations. What I do question is
the necessity for it and the wisdom of it.
Certainly Forth Inc's early successes didn't rely on the existence of
a standard.
https://www.ultratechnology.com/antiansi.htm
dxf <dxforth@gmail.com> writes:
Perhaps I misunderstood. So we agree Forth locals are unlikely to
ever match C locals for performance?
This I don't know. If the issue is parameter passing in registers,
maybe a fancy enough Forth compiler could do that.
I don't know whether it's possible to make forth code using locals as
efficient as forth code using stack operations. What I do question is
the necessity for it and the wisdom of it.
I think in case of an interpreter, locals might be more efficient, since
as the thread title says, they treat the stack as an array. The
hardware is built to do that, so why not use it? With an optimizing compiler, I think they should usually be equivalent in principle.
...
Do you still use blocks instead of files nowadays?
Sysop: | DaiTengu |
---|---|
Location: | Appleton, WI |
Users: | 991 |
Nodes: | 10 (1 / 9) |
Uptime: | 133:11:42 |
Calls: | 12,960 |
Calls today: | 2 |
Files: | 186,574 |
Messages: | 3,266,161 |