duskos

dusk os fork
git clone git://git.alexwennerberg.com/duskos
Log | Files | Refs | README | LICENSE

commit 42115cb411e1f7b5293b2d1137765169030a5902
parent e93e3e8781343062d2fe479cf4ff1ab718d1b6c6
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Fri,  7 Oct 2022 17:52:05 -0400

cc: simplify Arrow generation with the addition of vm+n, op

Previously, Arrow AST element was generated in the same was as a binop with the
field offset as a constant operand. This worked in simple cases, but this
created a problem in AST trees with nested binary ops: to properly generate
those, we would have had to :push/:pop vmop like what we do in BinOp
generation.

It's simpler to add a new vm-level word, vm+n, which is a unary op adding a
constant number to the target operand. This way, no :push/:pop necessary.

Diffstat:
Mfs/cc/gen.fs | 2+-
Mfs/cc/vm/forth.fs | 2++
Mfs/cc/vm/i386.fs | 32+++++++++++++++++++-------------
3 files changed, 22 insertions(+), 14 deletions(-)

diff --git a/fs/cc/gen.fs b/fs/cc/gen.fs @@ -267,7 +267,7 @@ ASTIDCNT wordtbl gentbl ( node -- ) vmop type dup ctype? _assert dup type*lvl 1 = _assert ( name type ) ctype' dup CType :struct? _assert ( name ctype ) CType :find ( field-ctype ) - dup CType offset vmop^ :>const vm+, vmop :*op ( field-ctype ) + dup CType offset vm+n, vmop :*op ( field-ctype ) dup CType type to vmop type CType nbelem if vmop :&op then ; diff --git a/fs/cc/vm/forth.fs b/fs/cc/vm/forth.fs @@ -131,6 +131,8 @@ unop vmboolnot, not unopmut vm++op, 1+ unopmut vm--op, 1- +: vm+n, ( n -- ) vmop :compile litn compile + ; + \ post-inc/dec op1 \ We need to copy the old value to TOS and then inc or dec the reference. : apply ( w a -- n ) \ Same as unop's apply, but yield old value diff --git a/fs/cc/vm/i386.fs b/fs/cc/vm/i386.fs @@ -48,6 +48,8 @@ struct+[ VMOp VM_*REGISTER of = r! 0 d) endof _err endcase ; + : :compileDest dup loc VM_CONSTANT <> _assert :compile ; + \ Force current operand to be copied to a register : _ regallot dup r! ( self regid ) over :compile movclr, swap to arg ; : :>reg dup >r loc case \ V1=self @@ -66,7 +68,7 @@ struct+[ VMOp : :complex? dup loc VM_*REGISTER = over :loclo VM_STACKFRAME = or - swap loc VM_*ARGSFRAME = or ; + over loc VM_*ARGSFRAME = or swap loc VM_*CONSTANT = or ; \ Resolve any referencing into a "simple" operand, that is, an operand that \ can be combined to a "complex" operand. There are 2 options: VM_REGISTER and @@ -146,7 +148,7 @@ struct+[ VMOp \ Code generation - Binary ops : binop doer ' , does> ( 'w ) @ - vmop :>res vmop :compile vmop^ :compile execute vmop^ :init ; + vmop :>res vmop :compileDest vmop^ :compile execute vmop^ :init ; binop vm+, add, binop vm-, sub, binop vm&, and, @@ -162,15 +164,15 @@ binop vm>>, shr, vmop^ loc VM_CONSTARRAY = if \ special case, we have a {1, 2, 3} assign vmop loc VM_STACKFRAME = _assert vmop :*op vmop^ arg dup @ ( a len ) >r begin ( a ) - vmop :compile 4 + dup @ i) mov, ( a+4 ) + vmop :compileDest 4 + dup @ i) mov, ( a+4 ) vmop arg 4 + to vmop arg next ( a ) drop else - vmop :?>simple vmop :compile vmop^ :compile mov, then + vmop :?>simple vmop :compileDest vmop^ :compile mov, then vmop^ :init ; : binop= doer ' , does> ( 'w ) @ - vmop :?>simple vmop :compile vmop^ :hasop# vmop^ :compile + vmop :?>simple vmop :compileDest vmop^ :hasop# vmop^ :compile execute vmop^ :init ; binop= vm+=, add, binop= vm-=, sub, @@ -191,7 +193,7 @@ binop= vm>>=, shr, : _post vmop^ :init vmop :isAX? not if - vmop :compile ax mov, regfree + vmop :compileDest ax mov, regfree reglvl if ax pop, then then ; : vm*=, _pre vmop^ :compile mul, _post ; : vm/=, _pre dx dx xor, vmop^ :compile div, _post ; @@ -204,21 +206,25 @@ binop= vm>>=, shr, \ Unary operations are performed on the selected op, which can be either op1 or \ op2. -: unaryop doer ' , does> ( 'w ) @ vmop :>reg vmop :compile execute ; +: unaryop doer ' , does> ( 'w ) @ vmop :>reg vmop :compileDest execute ; unaryop vmneg, neg, unaryop vmnot, not, ( ~ ) : vmboolify, vmneg, vmop :compile 0 i) mov, vmop :compile setnz, ; : vmboolnot, vmneg, vmop :compile 0 i) mov, vmop :compile setz, ; \ pre-inc/dec op1 -: vm++op, vmop :compile inc, ; -: vm--op, vmop :compile dec, ; +: vm++op, vmop :compileDest inc, ; +: vm--op, vmop :compileDest dec, ; + +: vm+n, ( n -- ) vmop :loclo VM_CONSTANT = if + to+ vmop arg + else vmop :compileDest i) add, then ; \ post-inc/dec op1 \ It's a bit complicated here. Before we inc/dec, we need a copy of the current \ value in a new register, which will be our result. : _ ( 'w -- ) - vmop :keep vmop :>reg vmop :swap vmop :compile swap execute + vmop :keep vmop :>reg vmop :swap vmop :compileDest swap execute vmop :init vmop :pop ; : vmop++, ['] inc, _ ; : vmop--, ['] dec, _ ; @@ -226,7 +232,7 @@ unaryop vmnot, not, ( ~ ) \ Code generation - Logic : _ - vmop :>reg vmop :compile vmop^ :compile cmp, vmop^ :init + vmop :>reg vmop :compileDest vmop^ :compile cmp, vmop^ :init vmop :compile 0 i) mov, ; : vm<, _ vmop :compile vmop type typeunsigned? if setb, else setl, then ; : vm>, _ vmop :compile vmop type typeunsigned? if seta, else setg, then ; @@ -235,7 +241,7 @@ unaryop vmnot, not, ( ~ ) : vm==, _ vmop :compile setz, ; : vm!=, _ vmop :compile setnz, ; : _ ( 'w -- ) - vmop :compile vmop^ :compile execute + vmop :compileDest vmop^ :compile execute vmop^ :init vmboolify, ; : vm&&, ['] and, _ ; : vm||, ['] or, _ ; @@ -262,7 +268,7 @@ unaryop vmnot, not, ( ~ ) \ simple register, the "test eax, eax" form is more compact. Otherwise, use \ test ..., -1. : vmtest, - vmop :compile vmop loc $f and VM_REGISTER = if + vmop :compileDest vmop loc $f and VM_REGISTER = if vmop :compile else -1 i) then test, ( sets Z ) vmop :init ; : vmjz, ( a -- ) vmtest, abs>rel jz, ;