duskos

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

commit 68b95efc36ff812e8de90bd4d7545b1c2f5c2c81
parent e0edbbe1c8735a497322d034e8de1b335d5e0113
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Sat, 12 Nov 2022 20:06:58 -0500

cc: move pointer arithmetic logic from ast/ttr to vm

I was hitting a wall with a missing pointer arithmetic logic implementation for
++op, --op, op++ and op--. Implementing those through AST manipulation was more
complicated than it should. Deferring this task to the VM layer ended up being
simpler.

Diffstat:
Mfs/cc/ast.fs | 28----------------------------
Mfs/cc/ttr.fs | 2+-
Mfs/cc/type.fs | 7+++++++
Mfs/cc/vm/commonhi.fs | 21+++++++++++++++++++--
Mfs/cc/vm/commonlo.fs | 7+++++--
Mfs/cc/vm/forth.fs | 8+++++---
Mfs/cc/vm/i386.fs | 3+++
7 files changed, 40 insertions(+), 36 deletions(-)

diff --git a/fs/cc/ast.fs b/fs/cc/ast.fs @@ -142,16 +142,6 @@ extends ASTNode struct[ Arrow ]struct struct+[ ASTNode - : _ ( opid n self -- ) >r ( opid n ) - Constant :new ( opid cnode ) - swap AST_BINARYOP Op :new dup r@ Node :replace ( cnode bnode ) - r> over Node :add ( cnode bnode ) Node :add ; - - \ Multiply the value of "node" by a factor of "n" - : :*=n ( n self -- ) 2 ( * ) rot> _ ; - \ Divide the value of "node" by a factor of "n" - : :/=n ( n self -- ) 3 ( / ) rot> _ ; - : :type dup id case ( self ) AST_IDENT of = Ident :finddecl ?dup _assert CType :type endof @@ -166,10 +156,6 @@ struct+[ ASTNode ctype' dup CType :struct? _assert ( name ctype ) CType :find# ( field-ctype ) CType :type endof drop TYPE_INT endcase ; - - \ Return the "pointer arithmetic size" of "node". - : :*arisz ( self -- n ) :type *ariunitsz ; - : :ptr? :type type*lvl bool ; ]struct extends Op struct[ UnaryOp @@ -186,20 +172,6 @@ extends Op struct[ BinaryOp : :new ( opid -- node ) AST_BINARYOP Op :new ; : :new+ 0 ( + opid ) :new ; : :new= 18 ( = opid ) :new ; - - \ given a BinaryOp node "bnode", verify whether pointer arithmetic adjustments - \ are necessary. If one of the operands is a pointer and the other is not, - \ multiply the "not a pointer" one by the pointer's "arithmetic size". - : :*ari ( self -- ) - dup opid ptrbop? not if drop exit then - dup firstchild ?dup _assert dup nextsibling ?dup _assert ( self n1 n2 ) - over :ptr? if \ n1 is a pointer - swap :*arisz over :ptr? if ( self n2 sz ) \ both are pointers - nip swap :/=n else ( self n2 sz ) \ only n1 is a pointer - swap :*=n drop then ( ) - else ( self n1 n2 ) \ n1 is not a pointer - dup :ptr? if ( self n1 n2 ) \ only n2 is a pointer - :*arisz swap :*=n else 2drop then ( self ) drop then ; ]struct extends ASTNode struct[ StrLit diff --git a/fs/cc/ttr.fs b/fs/cc/ttr.fs @@ -93,7 +93,7 @@ ASTIDCNT wordtbl trtbl ( node -- ) 'w drop ( Ident ) :w ( UnaryOp ) dup trchildren UnaryOp :?fold ; 'w trchildren ( PostfixOp ) -:w ( BinaryOp ) dup BinaryOp :*ari dup trchildren BinaryOp :?fold ; +:w ( BinaryOp ) dup trchildren BinaryOp :?fold ; 'w trchildren ( List ) 'w trchildren ( If ) 'w drop ( StrLit ) diff --git a/fs/cc/type.fs b/fs/cc/type.fs @@ -178,6 +178,13 @@ current to _typesize 4 of = TYPE_INT endof _err endcase ; +\ TODO: this is a temporary crutch, will reorganize +: typesize>pow2 ( size -- pow2 ) case + 0 of = 0 endof + 1 of = 0 endof + 2 of = 1 endof + 4 of = 2 endof + _err endcase ; \ Returns the "pointer arithmetics unit size" for type, that is, the size of \ a "single element" in pointer arithmetics. This allows, for example, "ptr + 1" \ to generate "ptr + 4" in native code if "ptr" is a "int*". diff --git a/fs/cc/vm/commonhi.fs b/fs/cc/vm/commonhi.fs @@ -8,16 +8,33 @@ : unopmut doer , does> @ unopmut, ; 0 unopmut vm++op, 1 unopmut vm--op, 2 unopmut vmop++, 3 unopmut vmop--, +\ perform necessary adjustments if we have pointer +/- scalar. +: _ptrariadj ( -- ) + vmop :typeptr? vmop^ :typeptr? not and if + vmop :*arisz typesize>pow2 vmop^ :<<n then + vmop^ :typeptr? vmop :typeptr? not and if + vmop^ :*arisz typesize>pow2 vmop :<<n then ; + : ariop doer , does> @ ariop, ; -0 ariop vm+, 1 ariop vm-, 2 ariop vm*, 3 ariop vm/, +2 ariop vm*, 3 ariop vm/, 4 ariop vm%, 5 ariop vm&, 6 ariop vm|, 7 ariop vm^, 8 ariop vm<<, 9 ariop vm>>, +: vm+, _ptrariadj 0 ( + ) ariop, ; + +\ vm-, is special because it handles the special "pointer-pointer" situation. +: vm-, _ptrariadj vmop :typeptr? vmop^ :typeptr? and if + vmop :*arisz typesize>pow2 1 ( - ) ariop, ( shr ) vmop :>>n + else 1 ( - ) ariop, then ; + : assignop doer , does> @ assignop, ; -0 assignop vm+=, 1 assignop vm-=, 2 assignop vm*=, 3 assignop vm/=, +2 assignop vm*=, 3 assignop vm/=, 4 assignop vm%=, 5 assignop vm&=, 6 assignop vm|=, 7 assignop vm^=, 8 assignop vm<<=, 9 assignop vm>>=, 10 assignop vm=, +: vm+=, _ptrariadj 0 ( + ) assignop, ; +: vm-=, _ptrariadj 1 ( - ) assignop, ; + : logop doer , does> @ logop, ; 0 logop vm<, 1 logop vm>, 2 logop vm<=, 3 logop vm>=, 4 logop vm==, 5 logop vm!=, 6 logop vm&&, 7 logop vm||, diff --git a/fs/cc/vm/commonlo.fs b/fs/cc/vm/commonlo.fs @@ -55,7 +55,9 @@ struct[ VMOp : :init VM_NONE over to loc TYPE_INT swap to type ; : :loclo loc $f and ; \ Is loc a pointer? - : :pointer? loc $10 and bool ; + : :locptr? loc $10 and bool ; + \ Is type a pointer? + : :typeptr? type type*lvl bool ; : :isconst? loc VM_CONSTANT = ; : :noop# loc VM_NONE = _assert ; : :hasop# loc VM_NONE <> _assert ; @@ -65,7 +67,7 @@ struct[ VMOp : :push ( self -- 'copy ) dup >r :keep VM_NONE to r> loc ; : :pop ( 'copy self -- ) dup :noop# 12 move ; : :swap ( 'copy self -- 'copy ) dup :push rot> :pop ; - : :&loc dup :pointer? _assert dup :loclo swap to loc ; + : :&loc dup :locptr? _assert dup :loclo swap to loc ; : :&op dup :&loc dup type type*lvl+ swap to type ; : :*op dup loc case VM_CONSTANT of = endof @@ -75,6 +77,7 @@ struct[ VMOp VM_TOS of = endof _err endcase dup loc $10 or over to loc dup type type*lvl- swap to type ; + : :*arisz ( self -- n ) type *ariunitsz ; ]struct create operands VMOp SZ 2 * allot diff --git a/fs/cc/vm/forth.fs b/fs/cc/vm/forth.fs @@ -40,16 +40,18 @@ struct+[ VMOp \ Resolve current operand and compile a push to PS as either VM_TOS or \ VM_*TOS. : :compile& >r - r@ :pointer? if r@ :loclo r@ _ r> :>*TOS else r@ loc r@ _ r> :>TOS then ; + r@ :locptr? if r@ :loclo r@ _ r> :>*TOS else r@ loc r@ _ r> :>TOS then ; : :typesz! type typesize sz! ; \ Resolve current operand and forces dereferencing. Always yields VM_TOS. : :compile ( -- ) >r r@ :compile& r@ loc VM_*TOS = if r@ :typesz! compile @ r@ :>TOS then rdrop ; : :>reg dup :loclo VM_REGISTER = if drop exit then >r - r@ :hasop# r@ :pointer? ( f ) r@ :compile& r@ 'arg litn compile ! PS- ( f ) + r@ :hasop# r@ :locptr? ( f ) r@ :compile& r@ 'arg litn compile ! PS- ( f ) 4 lshift VM_REGISTER or to r> loc ; \ dereference current operand - : :*op dup :pointer? if dup :compile dup :>reg then VMOp :*op ; + : :*op dup :locptr? if dup :compile dup :>reg then VMOp :*op ; + : :<<n ( n self -- ) tuck :compile litn compile lshift :>reg ; + : :>>n ( n self -- ) tuck :compile litn compile rshift :>reg ; ]struct \ Verify that we're in "neutral" position with regards to PS diff --git a/fs/cc/vm/i386.fs b/fs/cc/vm/i386.fs @@ -106,6 +106,9 @@ struct+[ VMOp \ Ensure that vmop is a proper "result", that is, a proper destination operand \ that is not going to mutate its original value. : :>res dup :>reg :>simple ; + + : :<<n ( n self -- ) dup :>res :compile i) shl, ; + : :>>n ( n self -- ) dup :>res :compile i) shr, ; ]struct \ Verify that we're in "neutral" position with regards to registers