Rocksolid Light

Welcome to novaBBS (click a section below)

mail  files  register  newsreader  groups  login

Message-ID:  

RIP is irrelevant. Spoofing is futile. Your routes will be aggregated. -- Alex Yuriev


devel / comp.lang.forth / Re: set-optimizer as an API for per-word optimizer

Re: set-optimizer as an API for per-word optimizer

<tlll39$cu1p$1@dont-email.me>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=21367&group=comp.lang.forth#21367

  copy link   Newsgroups: comp.lang.forth
Path: i2pn2.org!i2pn.org!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: ruvim.pi...@gmail.com (Ruvim)
Newsgroups: comp.lang.forth
Subject: Re: set-optimizer as an API for per-word optimizer
Date: Wed, 23 Nov 2022 17:26:00 +0000
Organization: A noiseless patient Spider
Lines: 250
Message-ID: <tlll39$cu1p$1@dont-email.me>
References: <tldhm8$3hk6b$1@dont-email.me>
<2022Nov20.174340@mips.complang.tuwien.ac.at>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Date: Wed, 23 Nov 2022 17:26:02 -0000 (UTC)
Injection-Info: reader01.eternal-september.org; posting-host="612c40cab5beca65707656b3fb56536e";
logging-data="423993"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+Je2pruOqJIBLt7L7H/DOp"
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:102.0) Gecko/20100101
Firefox/102.0
Cancel-Lock: sha1:Ym0cYjvssxakDVLSm2I0V5TEvZM=
Content-Language: en-US
In-Reply-To: <2022Nov20.174340@mips.complang.tuwien.ac.at>
 by: Ruvim - Wed, 23 Nov 2022 17:26 UTC

On 2022-11-20 16:43, Anton Ertl wrote:
> Ruvim <ruvim.pinka@gmail.com> writes:
>> On 2022-10-01 07:06, Anton Ertl wrote:
>>
>>> SET-OPTIMIZER sets the implementation of COMPILE, ( xt -- ) for
>>> the current word. A correct implementation of COMPILE, does not
>>> change the semantics in any way, only the implementation of the
>>> semantics.
>>
>> It seems, "set-optimizer" as a basis for such an API is suboptimal,
>> since you have to describe the same semantics *twice*, and you have a
>> chance to do it incorrectly.
>
> Yes.
>
>> Actually, if we have a definition that compiles some behavior, the
>> definition that performs this behavior can be created automatically.
>
> Yes, but ... [see below].
>
>> I mean, if we have a definition:
>>
>> : compile-foo ( -- ) ... ;
>>
>> that appends behavior "foo" to the current definition,
>> then a word "foo" can be defined as
>>
>> : foo [ compile-foo ] ;
>
> Actually it's
>
> : compile-foo ( xt -- ) ... ;
> : foo recursive [ ' foo compile-foo ] ;
>
> If COMPILE-FOO just drops the xt, you can just pass 0 to COMPILE-FOO.
>
>> Then, why do we need to define both "foo" and "compile-foo" by hands?
>> Having one of them, another can be created automatically.
>
> The usual usage of SET-COMPILER is in defining words, e.g.
>
> : constant1 ( n "name" -- )
> create ,
> ['] @ set-does>
> [: >body @ ]] literal [[ ;] set-optimizer ;

To me, "lit," looks far more comprehensible than "]] literal [["

>
> Here you have the advantage that the constant needs only one cell in
> addition to the header. Yes, you have the disadvantage that the
> SET-DOES> and SET-OPTIMIZER actions might disagree, leading to
> incorrect behaviour. An additional aspect here is that this
> definition assumes that the value of the constant is not changed.
>
> Could we avoid the redundancy and the potential disagreement? You
> suggest creating a colon definition for "name". How could this work?
> We have to store N somewhere. What I can come up with is:
>
> : lit, postpone literal ;
> : constant2 ( n "name" -- )
> >r :noname r> ]] drop literal lit, ; [[ >r
> : 0 r@ execute postpone ; r> set-optimizer ;
>
> The definition
>
> 5 constant1 five1
>
> takes 6 cells (on a 64-bit machine) in the dictionary, while
>
> 5 constant2 five2
>
> takes 16 cells in the dictionary plus 146 Bytes of native code with
> the debugging engine on AMD64.
>

The code is lager since create-does in Gforth avoids duplication of some
code parts (i.e., it utilizes one instance for many definitions). And
since anonymous definition are too heavy in Gforth. For example,
":noname ;" takes 24 bytes (3 cells) in Gforth, 3 bytes (3/4 cells) in
SwiftForth 3.11.6, and 1 byte (1/4 cells) in SP-Forth/4.

For colon definitions this difference should not be so drastic.

OTOH, if you provide an optimizer that generates longer code instead of
a definition call, it's probably not a problem that the definition
itself takes more space.

> Moreover, I had several bugs in CONSTANT2 until I got it right, but
> that could get better with more practice. But will it get better than
> the alternative? The code is larger, so that's far from clear.
>

Having proper tools, it should not be more difficult.

The compiler in "constant1":
[: >body @ ]] literal [[ ;] ( xt )

The compiler in "constant2":
>r :noname r> ]] drop literal lit, ; [[ ( xt )

They can be expressed far simpler as following.

In "constant1":
[: >body @ lit, ;]

In "constant2":
['] lit, partial1

> In any case, it seems to me that the size advantage alone makes the
> CONSTANT1 approach preferable. Yes, you describe the same thing
> twice, and you may get it wrong in one description while getting it
> right in the other, so you have test both implementations separately
> (e.g., interpret the word once, and include it in a colon definition,
> and use the same tests on it; maybe we could automate that), but such
> bugs are rare.
>
>> A better API for per-word optimization should require the user to define
>> only the compiler for a word, and the word itself will be created
>> automatically.
>>
>> For example:
>>
>> [: postpone over postpone over ;] "2dup" define-by-compiler
>>
>> compiler: 2dup ]] over over [[ ;
>>
>> : value
>> create ,
>> [: ( addr -- ) lit, postpone @ ;] does-by-compiler
>> ;
>
> The first two are alternatives, the third one addresses a different
> need. For the VALUE example, how does the implementation work; I can
> imagine how it works for the 2DUP examples.

Ideally, an implementation for such "does-by-compiler" should be
supported by the corresponding implementations for "create" and "does>".

But for the purpose of PoC we can do it less efficiently. So a Gforth
specific PoC is following.

In Gforth, ":" and ":noname" affect "latestxt" (which is used by
"set-does>" and "set-compiler"), but "[: ... ;]" doesn't affect it.
So I use the latter construct to create intermediate helper definitions.
The intermediate definitions are needed to adapt the interface of
"does-by-compiler" to the interface of "set-does>" and "set-optimizer"
in Gforth.

: begin-quot ( C: -- quotation-sys colon-sys ) ['] [: execute ;
: end-quot ( C: quotation-sys colon-sys -- xt ) postpone ;] ;

: does-by-compiler ( xt.compiler -- ) \ xt.compiler ( addr.body -- )
latestxt >body >r >r ( R: addr.body xt.compiler )
begin-quot
postpone drop \ the passed addr.body is not needed
2r@ execute
end-quot set-does>
begin-quot
postpone drop \ the passed xt is not needed
r> r> lit, compile,
end-quot set-optimizer
;

A usage example:

: val ( x "name" -- )
create , [: lit, postpone @ ;] does-by-compiler
;

123 val x
x . \ prints 123
: foo x . ; foo \ prints 123
456 ' x >body !
x . \ prints 456
see foo \ should show an optimized variant

>> BTW, I don't see why xt should be passed to a compiler (as it's done in
>> "set-compiler"). In what cases it's useful?
>
> It's useful for getting the value of the constant in CONSTANT1.

As I can see, what is actually needed in this case is not an xt but a
data field address.

Do we have an example when an xt itself is needed?

> It's also the interface of COMPILE,. SET-OPTIMIZER only defines
> what COMPILE, does for the word that SET-OPTIMIZER is applied to. If
> COMPILE, instead DROPped the xt and only then called the word that we
> pass with SET-OPTIMIZER, that works nicely for the 2DUP example, but
> how would DOES-BY-COMPILER produce the ADDR that is passed to the xt?

From the formal point of view, "does>" in run-time makes partial
application. It partially applies the part "X" in "does> X ;" to the
ADDR, producing a new definition, and replaces the execution semantics
of the most recent definition by the execution semantics of this new
definition.

In the case of "does-by-compiler", this new definition is created by
means of the passed xt.compiler, and then the execution semantics of the
most recent definition is replaced by this new definition.

But it still have to partially apply the xt.compiler to create the full
optimizer. A possible more concise definition for "does-by-compiler":

: does-by-compiler ( xt.compiler -- ) \ xt.compiler ( addr.body -- )
latest-name> >body swap 2>r ( R: addr.body xt.compiler )
begin-quot 2r@ execute end-quot latest-name> replace-behavior
2r> partial1 latest-name> advise-compiler
;

where
partial1 ( x xt1 -- xt2 )
\ xt2 is partially applied xt1 to x
\ This word may use data space.

latest-name> ( -- xt )
\ xt is the execution token of the most recently appended
\ definition in the compilation word list.
\ An ambiguous condition exists if such a definition is absent.

advise-compiler ( xt.compiler xt -- )
\ It makes "compiler," to only perform xt.compiler
\ when it's applied to xt. It may use data space.
\ An ambiguous condition exists if the execution semantics
\ identified by xt.compiler are distinct from appending
\ the execution semantics identified by xt to the current definition.

replace-behavior ( xt.new xt -- )
\ It makes xt to identify the execution semantics identified
\ by xt.new. It may use data space.
\ An ambiguous condition exists if xt is not for a definition
\ that is created by "create".

--
Ruvim

SubjectRepliesAuthor
o set-optimizer as an API for per-word optimizer

By: Ruvim on Sun, 20 Nov 2022

19Ruvim
server_pubkey.txt

rocksolid light 0.9.81
clearnet tor