duskos

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

commit d53a7652bfbb94f9296649cd514dbb2478d67102
parent a34fd780e9c40b9c1444893ef069de1e567de42c
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Wed, 15 Jun 2022 12:51:09 -0400

cc: make some more of cc/gen use cc/vm

Diffstat:
Mfs/asm.fs | 1+
Mfs/cc/gen.fs | 96+++++++++++++++++++++++++++----------------------------------------------------
Mfs/cc/vm.fs | 91+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Mfs/tests/cc/vm.fs | 73++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 163 insertions(+), 98 deletions(-)

diff --git a/fs/asm.fs b/fs/asm.fs @@ -47,6 +47,7 @@ : ebp BP r! ; : edi DI r! ; : [eax] AX [r]! ; +: [ebx] BX [r]! ; : [ebp] BP [r]+8b! 0 to disp ; : [edi] DI [r]! ; : [ebp]+ ( disp -- ) BP [r]+8b! to disp ; diff --git a/fs/cc/gen.fs b/fs/cc/gen.fs @@ -7,17 +7,6 @@ \ Code generation -\ lvallvl indicates the current indirection level. The next time a LValue is -\ resolved, it will apply this indirection level and reset it to 0. -\ a negative level means "&" level. only "-1" is possible. Positive levels means -\ "*". These dereferences can happen multiple times. -0 value lvallvl - -\ When a AST_LVALUE is on the left side of an assign, we want to set it. When -\ "lvalset" is set, the LVALUE handler sets the effective address of the LVALUE -\ to the value in EAX and resets the "lvalset" flag. -0 value lvalset - : _err ( node -- ) printast abort" unexpected node" ; UOPSCNT wordtbl uopgentbl ( -- ) @@ -29,8 +18,8 @@ UOPSCNT wordtbl uopgentbl ( -- ) al setz, ; LOPSCNT wordtbl lopgentbl ( -- ) -:w ( & ) -1 to+ lvallvl ; -:w ( * ) 1 to+ lvallvl ; +'w operand>&operand ( & ) +'w operand>[operand] ( * ) \ In binary Ops, the result is in EAX and the source operand is EBX. BOPSCNT wordtbl bopgentblmiddle ( node -- node ) @@ -45,28 +34,22 @@ BOPSCNT wordtbl bopgentblmiddle ( node -- node ) 'w noop ( == ) 'w noop ( != ) :w ( && ) ( node -- jump_addr node ) - eax eax test, + eax eax test, 0 to resultset? 0 jz, here 4 - swap ; :w ( || ) ( node -- jump_addr node ) - eax eax test, + eax eax test, 0 to resultset? 0 jnz, here 4 - swap ; BOPSCNT wordtbl bopgentblpost ( -- ) -:w ( + ) eax ebx add, ; -:w ( - ) eax ebx sub, ; -:w ( * ) ebx mul, ; +'w vmadd, ( + ) +'w vmsub, ( - ) +'w vmmul, ( * ) :w ( / ) abort" TODO" ; -:w ( < ) - eax ebx cmp, - eax 0 i32 mov, - al setg, ; +'w vm<, ( < ) :w ( > ) abort" TODO" ; :w ( <= ) abort" TODO" ; :w ( >= ) abort" TODO" ; -:w ( == ) - eax ebx cmp, - eax 0 i32 mov, - al setz, ; +'w vm==, ( == ) :w ( != ) abort" TODO" ; :w ( && ) ( jump_addr -- ) here over - 4 - swap ! ; :w ( || ) ( jump_addr -- ) here over - 4 - swap ! ; @@ -88,71 +71,58 @@ ASTIDCNT wordtbl gentbl ( node -- ) 'w genchildren ( Unit ) :w ( Function ) _debug if ." debugging: " dup data1 stype nl> then + vm$ dup data1 entry dup data2 ( astfunc mapfunc ) here over fmap.address! \ set address dup fmap.argsize swap fmap.sfsize over - ( argsz locsz ) vmprelude, genchildren _debug if current here current - spit nl> then ; -:w ( Return ) genchildren ( node ) +:w ( Return ) + genchildren operand?>result 1 to resultset? vmret, ; -:w ( Constant ) eax data1 i32 mov, ; +:w ( Constant ) data1 const>operand ; :w ( Statements ) genchildren ; 'w genchildren ( ArgSpecs ) -:w ( LValue ) - _debug if ." lvalue: " dup printast spc> lvallvl .x1 spc> lvalset .x1 nl> then - lvalset if ( node ) - 0 to lvalset - lvallvl 0< if _err then - lvallvl if ( node ) - edi ebp mov, - edi lvsfoff i32 add, - begin edi [edi] mov, -1 to+ lvallvl lvallvl not until - [edi] eax mov, - else ( node ) - lvsfoff [ebp]+ eax mov, then - else ( node ) - lvallvl 0< if ( node ) - 1 to+ lvallvl - lvallvl if _err then - eax ebp mov, - eax lvsfoff i32 add, - else ( node ) - eax lvsfoff [ebp]+ mov, - then - lvallvl if - begin eax [eax] mov, -1 to+ lvallvl lvallvl not until then - then ; -:w ( UnaryOp ) dup genchildren data1 uopgentbl swap wexec ; +:w ( LValue ) lvsfoff sf+>operand ; +:w ( UnaryOp ) + dup genchildren + operand?>result + data1 uopgentbl swap wexec ; :w ( Assign ) firstchild ?dup not if _err then ( lvnode ) dup nextsibling ?dup not if _err then ( lvnode exprnode ) - gennode \ result in EAX - 1 to lvalset gennode ; + gennode operand?>result \ result=set + gennode \ operand=set + result>operand ; :w ( BinaryOp ) ( node ) >r r@ childcount 2 = not if abort" binop node with more than 2 children!" then - r@ firstchild dup nextsibling swap ( n1 n2 ) - gennode bopgentblmiddle r@ data1 wexec eax push, - gennode ebx pop, bopgentblpost r> data1 wexec ; + r@ firstchild dup nextsibling swap ( n2 n1 ) + gennode bopgentblmiddle r@ data1 wexec + operand?>result + resultset? if + pushresult, gennode operand?>result popresult, else + gennode operand?>result then + bopgentblpost r> data1 wexec ; :w ( LValueOp ) - dup data1 lopgentbl swap wexec - firstchild ?dup not if _err then gennode ; + dup firstchild ?dup not if _err then gennode + data1 lopgentbl swap wexec ; 'w _err ( unused ) 'w _err ( unused ) :w ( FunCall ) \ pass arguments dup firstchild ?dup if begin ( argnode ) - dup gennode + dup gennode operand?>result ebp 4 i32 sub, - [ebp] eax mov, + [ebp] eax mov, 0 to resultset? nextsibling ?dup not until then \ find in map data1 ( name ) findfuncinmap ( mapfunc ) \ call! fmap.address call, \ get result - eax [ebp] mov, + eax [ebp] mov, 1 to resultset? ebp 4 i32 add, ; : _ ( node -- ) gentbl over astid wexec ; diff --git a/fs/cc/vm.fs b/fs/cc/vm.fs @@ -29,57 +29,36 @@ \ To avoid errors, moving an operand to a non-empty and non-pushed Result is an \ error. To set the operand when it's not None is also an error. -\ For example, let's solve this: -\ binop[+](binop[*](const[2],const[3]),const[1]) - -\ 2 const>operand --> operand = const(2) -\ operand>result --> operand = None, result=set -\ 3 const>operand --> operand = const(3) -\ vmmul, --> operand = None, result=set -\ 1 const>operand --> operand = const(1) -\ vmadd, --> operand = None, result=set - -\ Another example involving push/popping: -\ binop[+](binop[-](const[2], const[1]),binop[*](const[2],const[3])) - -\ 2 const>operand --> operand = const(2) -\ operand>result --> operand = None, result=set -\ 1 const>operand --> operand = const(1) -\ vmsub, --> operand = None, result = set -\ pushresult --> result = none -\ 2 const>operand --> operand = const(2) -\ operand>result --> operand = None, result=set -\ 3 const>operand --> operand = const(3) -\ vmmul, --> operand = None, result = set -\ popresult --> operand = register -\ vmadd, --> operand = none, result = set - -0 const VM_NONE -1 const VM_CONSTANT -2 const VM_STACKFRAME -3 const VM_REGISTER +\ For usage example, see tests/cc/vm.fs + +$00 const VM_NONE +$01 const VM_CONSTANT +$02 const VM_STACKFRAME +$03 const VM_REGISTER 0 value resultset? \ 0 = no result, 1=result set VM_NONE value operand \ For VM_CONSTANT, this contains the actual value \ For VM_STACKFRAME, this contains the SF offset 0 value operandarg +0 value operandlvl \ -1 means "&", 1 means "*", 2 means "**" etc. 0 value argsz \ size of the argument portion of the SF. 0 value locsz \ size of the "local vars" portion of the SF. -: vm$ 0 to resultset? VM_NONE to operand ; +: vm$ 0 to resultset? VM_NONE to operand 0 to operandlvl ; : _err abort" vm error" ; : _assert not if _err then ; -\ Resolve current operand as an assembler "src" argument +\ Resolve current operand as an assembler "src" argument. : operandAsm ( -- ) operand VM_CONSTANT = if operandarg i32 else operand VM_REGISTER = if ebx - else operand VM_STACKFRAME = if - operandarg [ebp]+ else _err then then then + else operand VM_STACKFRAME = if + operandarg [ebp]+ + else _err then then then VM_NONE to operand ; : result! 1 to resultset? ; @@ -89,6 +68,17 @@ VM_NONE value operand operand VM_REGISTER = not if ebx operandAsm mov, VM_REGISTER to operand then ; +\ emit, if necessary, the code necessary to resolve "positive" operandlvl +: resolvederef + operandlvl if + operandlvl 0< if + 0 to operandlvl + VM_REGISTER to operand + ebx ebp mov, + operandarg if ebx operandarg i32 add, then + else operand>reg begin + ebx [ebx] mov, -1 to+ operandlvl operandlvl not until then then ; + : const>operand ( n -- ) VM_NONE operand = _assert VM_CONSTANT to operand to operandarg ; @@ -99,7 +89,32 @@ VM_NONE value operand : operand>result ( -- ) resultset? not _assert - eax operandAsm mov, ; + resolvederef + eax operandAsm mov, result! ; + +: operand?>result operand VM_NONE = not if operand>result then ; + +: operand>&operand + operand VM_STACKFRAME = _assert + operandlvl 0>= _assert + -1 to operandlvl ; + +: operand>[operand] + operand VM_STACKFRAME = operand VM_REGISTER = or _assert + 1 to+ operandlvl ; + +: result>operand + resultset? _assert + operand VM_STACKFRAME = if + operandlvl if + -1 to+ operandlvl operand>reg resolvederef + [ebx] eax mov, + else operandAsm eax mov, then + else operand VM_REGISTER = if + -1 to+ operandlvl resolvederef + [ebx] eax mov, + else _err then then + 0 to resultset? VM_NONE to operand ; \ generate function prelude code by allocating "locsz" bytes on PS. : vmprelude, ( argsz locsz -- ) @@ -120,3 +135,11 @@ VM_NONE value operand : vmadd, eax operandAsm add, result! ; : vmsub, eax operandAsm sub, result! ; : vmmul, operand>reg operandAsm mul, result! ; +: vm<, + eax operandAsm cmp, + eax 0 i32 mov, + al setg, ; +: vm==, + eax operandAsm cmp, + eax 0 i32 mov, + al setz, ; diff --git a/fs/tests/cc/vm.fs b/fs/tests/cc/vm.fs @@ -35,8 +35,9 @@ code test2 vmret, test2 8 #eq +\ sub 2 args vm$ -code test3 \ sub 2 args +code test3 8 0 vmprelude, 4 sf+>operand operand>result @@ -45,4 +46,74 @@ code test3 \ sub 2 args vmret, 54 12 test3 42 #eq +\ assign 2 local vars +vm$ +code test4 + 0 8 vmprelude, + \ foo = 42 + 42 const>operand + operand>result + 4 sf+>operand + result>operand + \ bar = 5 + 5 const>operand + operand>result + 0 sf+>operand + result>operand + \ return foo + bar + 4 sf+>operand + operand>result + 0 sf+>operand + vmadd, + vmret, +test4 47 #eq + +\ variable reference and dereference +vm$ +code test5 + 0 8 vmprelude, + \ foo = 42 + 42 const>operand + operand>result + 4 sf+>operand + result>operand + \ bar = &foo + 4 sf+>operand + operand>&operand + operand>result + 0 sf+>operand + result>operand + \ return *bar + 0 sf+>operand + operand>[operand] + operand>result + vmret, +test5 42 #eq + +\ assign and dereference +vm$ +code test6 + 0 8 vmprelude, + \ foo = 42 + 42 const>operand + operand>result + 4 sf+>operand + result>operand + \ bar = &foo + 4 sf+>operand + operand>&operand + operand>result + 0 sf+>operand + result>operand + \ *bar = 54 + 54 const>operand + operand>result + 0 sf+>operand + operand>[operand] + result>operand + \ return foo + 4 sf+>operand + operand>result + vmret, +test6 54 #eq testend