duskos

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

commit b47a95af1dc3b96de4c8e2aa50cec43fc0fdddc3
parent a028adb413830bd7305484f57687b8df19f42972
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Sun, 19 Mar 2023 22:08:02 -0400

halcc: boolops()

This required the development of a "W locking" mechanism as well as a "push to
PS when W is locked" one.

Diffstat:
Mfs/comp/c/egen.fs | 32+++++++++++++++++++++-----------
Mfs/comp/c/expr.fs | 47++++++++++++++++++++++++++++++-----------------
Mfs/comp/c/fgen.fs | 7++++---
Mfs/comp/c/glob.fs | 2+-
Mfs/tests/comp/c/cc.fs | 2+-
Mfs/tests/comp/c/test2.c | 4++++
Mposix/vm.c | 23+++++++++++++++--------
7 files changed, 76 insertions(+), 41 deletions(-)

diff --git a/fs/comp/c/egen.fs b/fs/comp/c/egen.fs @@ -72,24 +72,34 @@ current ' parseFactor realias \ ops that can freely swap their operands : swappable doer ' , does> @ ( left right w ) >r - dup Result :isW? if swap then over Result :>W Result :hal# r> execute ; -swappable _+, +, swappable _*, *, -swappable _&, and, swappable _^, xor, swappable _|, or, + dup Result :isW? if swap then over Result :?>W Result :hal# r> execute ; +swappable _+, +, swappable _*, *, +swappable _&, and, swappable _^, xor, swappable _|, or, +: _ ( halop -- ) W=0>Z, 0 Z) branchC, @, W=0>Z, [compile] then NZ) C>W, ; +swappable _&&, and, +: _ ( halop -- ) or, W=0>Z, NZ) C>W, ; +swappable _||, _ : fixed doer ' , does> @ ( left right w ) >r - Result :?>T over Result :>W r> execute ; + Result :?>T over Result :?>W r> execute ; fixed _-, -, fixed _/, /, fixed _%, %, fixed _<<, <<, fixed _>>, >>, : assign doer ' , does> @ ( left right w ) >r Result :?>T over Result :hal# lea, W>A, ( res-w rightop ) - over Result :>W r> execute A) !, ; + over Result :?>W r> execute A) !, ; assign _=, drop assign _+=, +, assign _*=, *, assign _/=, /, assign _%=, %, assign _&=, and, assign _^=, xor, assign _|=, or, assign _-=, -, assign _/=, /, assign _%=, %, assign _<<=, <<, assign _>>=, >>, +: cmpop doer , does> @ ( left right cond ) >r + Result :?>T over Result :?>W cmp, r> C>W, ; +Z) cmpop _==, NZ) cmpop _!=, +<) cmpop _<, <=) cmpop _<=, >) cmpop _>, >=) cmpop _>=, + + \ Our implementation of "x ? y : z" suffers a significant limitation because \ we're single pass: by the time _? is called, it's possible that code \ generating the right part of it has already been generated, so the "true" part @@ -97,15 +107,15 @@ assign _<<=, <<, assign _>>=, >>, \ the "true" hand, push it to PS, then generate the "cond", keep it in W. When \ we encounter the "false" hand, *then* we generate conditional code which \ cleans up PS. -: _?, ( left right -- res ) Result :>PS dup Result :>W ; +: _?, ( left right -- res ) Result :>PS ; : _:, ( left right -- res ) - PS- W=0>Z, 0 Z) branchC, - drop, [compile] else nip, swap Result :>W [compile] then ; + swap Result :>W$ PS- W=0>Z, 0 Z) branchC, + drop, [compile] else nip, over Result :>W [compile] then ; BOPSCNT wordtbl _tbl ( left right -- res ) -'w _+, 'w _-, 'w _*, 'w _/, 'w _%, 'w _<<, 'w _>>, 'w _err -'w _err 'w _err 'w _err 'w _err 'w _err 'w _&, 'w _^, 'w _|, -'w _err 'w _err 'w _=, 'w _+=, 'w _-=, 'w _*=, 'w _/=, 'w _%=, +'w _+, 'w _-, 'w _*, 'w _/, 'w _%, 'w _<<, 'w _>>, 'w _<, +'w _>, 'w _<=, 'w _>=, 'w _==, 'w _!=, 'w _&, 'w _^, 'w _|, +'w _&&, 'w _||, 'w _=, 'w _+=, 'w _-=, 'w _*=, 'w _/=, 'w _%=, 'w _<<=, 'w _>>=, 'w _&=, 'w _^=, 'w _|=, 'w _?, 'w _:, : bothconst? ( left right -- f ) Result :isconst? swap Result :isconst? and ; diff --git a/fs/comp/c/expr.fs b/fs/comp/c/expr.fs @@ -7,41 +7,54 @@ : _assert ( f -- ) not if _err then ; struct[ Result - 0 const CONST \ Is a constant (value in arg) - 1 const W \ Value in W register - 2 const CTYPE \ CType pointer is in arg. + 0 const NONE \ Nothing (probably a released W) + 1 const CONST \ Is a constant (value in arg) + 2 const W \ Value in W register + 3 const CTYPE \ CType pointer is in arg. + 4 const PS \ Result pushed to PS, offset in arg sfield type - sfield arg \ either CType or constant value + sfield arg + + \ There can only be one result using W at once. Whenever a W result is + \ created, it takes the lock. If it's already taken, there's an error. + 0 value currentW \ link to Result + : :Wfree# currentW if abort" W is already taken!" then ; : :new ( arg type -- res ) SZ syspad :allot dup >r !+ ! r> ; : :const ( n -- res ) CONST :new ; - : :W ( -- res ) 0 W :new ; + : :W ( -- res ) :Wfree# 0 W :new dup to currentW ; : :ctype ( ctype -- res ) CTYPE :new ; - \ TODO: manage W "locks" so that we push to PS when we need intermediate res. - : :>W ( self -- ) dup bi arg | type case ( self arg ) - CONST of = LIT>W, endof - W of = drop endof - CTYPE of = CType :halop @, endof - _err endcase W swap to type ; + : :isW? ( self -- f ) type W = ; + : :release ( self -- ) dup :isW? if 0 to currentW then NONE swap to type ; : :hal# ( self -- halop ) dup type case ( self ) - CTYPE of = arg CType :halop endof CONST of = arg i) endof - _err endcase ; + CTYPE of = arg CType :halop endof + PS of = PSP) swap arg psoff + +) endof + abort" :hal# error" endcase ; + : :>W ( self -- ) dup type case ( self ) + W of = endof + CONST of = :Wfree# dup arg LIT>W, endof + CTYPE of = :Wfree# dup :hal# @, endof + PS of = :Wfree# dup :hal# @, endof + abort" :>W error" endcase ( self ) + dup to currentW W swap to type ; + : :>W$ ( self -- ) dup :>W :release ; : :isconst? ( self -- f ) type CONST = ; : :iszero? bi arg 0 = | :isconst? and ; : :isone? bi arg 1 = | :isconst? and ; - : :isW? ( self -- f ) type W = ; : :const# dup :isconst? _assert arg ; - : :>PS :>W dup, PS+ ; + : :>PS dup :>W$ dup, PS+ PS over to type psoff neg swap to arg ; + : :?>W dup :isW? if drop else currentW ?dup if :>PS then :>W then ; \ Free up W by sending it to T (if needed). - : :?>T ( self -- halop ) dup :isW? if drop T) dup !, else :hal# then ; + : :?>T ( self -- halop ) + dup :isW? if :release T) dup !, else :hal# then ; ]struct BOPSCNT wordtbl _tbl ( a b -- n ) 'w + 'w - 'w * 'w / 'w mod 'w << 'w >> 'w < 'w > 'w <= 'w >= 'w = 'w <> 'w and 'w xor 'w or -'w _err 'w _err 'w _err 'w _err 'w _err 'w _err 'w _err 'w _err +'w and? 'w or? 'w _err 'w _err 'w _err 'w _err 'w _err 'w _err 'w _err 'w _err 'w _err 'w _err 'w _err 'w _err 'w _err : applyConstBinop ( left right opid -- res ) diff --git a/fs/comp/c/fgen.fs b/fs/comp/c/fgen.fs @@ -10,7 +10,7 @@ : _postlude _curfunc CType :argssize ?dup if ps+, then _locvars CType :size ?dup if rs+, then ; -: emitRet ( res -- ) Result :>W _postlude exit, ; +: emitRet ( res -- ) Result :>W$ psneutral _postlude exit, ; : emitNullRet ( -- ) _postlude drop, exit, ; alias noop parseStatement ( tok -- ) \ forward declaration @@ -31,7 +31,8 @@ alias noop parseStatement ( tok -- ) \ forward declaration 0 value _laststmtid : _ ( tok -- ) \ parseStatement dup statementnames sfind dup >r dup 0< if ( tok -1 ) \ V1=stmtidx - drop parseExpression drop read; else nip statementhandler swap wexec then + drop parseExpression Result :release psneutral read; + else nip statementhandler swap wexec then r> to _laststmtid ; current ' parseStatement realias @@ -45,7 +46,7 @@ current ' parseStatement realias '=' readChar? if ( ctype ) _initcode not if here to _initcode then nextt parseExpression ( ctype res ) - Result :>W dup CType :halop !, nextt then ( ctype tok ) + Result :>W$ dup CType :halop !, psneutral nextt then ( ctype tok ) dup ';' isChar? not while ( ctype tok ) ',' expectChar CType type parseDeclarator ( ctype ) dup _locvars CType :append repeat ( ctype tok ) 2drop ; diff --git a/fs/comp/c/glob.fs b/fs/comp/c/glob.fs @@ -8,4 +8,4 @@ : PS+ CELLSZ to+ psoff ; : PS- CELLSZ neg to+ psoff ; -: psneutral# psoff if abort" psoff not neutral!" then ; +: psneutral 0 to@! psoff ?dup if ps+, then ; diff --git a/fs/tests/comp/c/cc.fs b/fs/tests/comp/c/cc.fs @@ -19,8 +19,8 @@ binopmod 1 #eq 1 binopcondeval 42 #eq 0 binopcondeval 12 #eq assignops 83 #eq -testend \s boolops 0 #eq +testend \s funcall 42 #eq 42 pushpop 42 #eq 3 2 subber 1 #eq diff --git a/fs/tests/comp/c/test2.c b/fs/tests/comp/c/test2.c @@ -63,3 +63,7 @@ int assignops() { a |= c; // 83 return a; } +int boolops() { + int a=66, b=2; + return a < 54 && 2 == b; +} diff --git a/posix/vm.c b/posix/vm.c @@ -54,10 +54,13 @@ no assembler to complete the HAL to "full" level later. It's all in there. #define OPHASDISP 0x08 #define OP16B 0x100 #define OP8B 0x200 -#define CONDZ 0x11 -#define CONDNZ 0x01 -#define CONDC 0x22 -#define CONDNC 0x02 +// Condition structure: b6:0 condition ID b7 invert +#define CONDZ 0x00 +#define CONDNZ 0x80 +#define CONDC 0x01 +#define CONDNC 0x81 +#define CONDA 0x02 // above (unsigned gt) +#define CONDNA 0x82 #define EMETA_8B 0x10 #define EMETA_16B 0x11 @@ -204,11 +207,14 @@ static void RET() { vm.PC = rpop(); } static void BRWR() { dwrite(vm.W); vm.W = here()-4; } static void BRA() { vm.PC = vm.A; } static int checkcond(byte cond) { - switch (cond&0xf) { - case 0x01: return vm.Z == ((cond >> 4) & 1); - case 0x02: return vm.C == ((cond >> 5) & 1); - default: return 0; + int r = 0; + switch (cond&0x7f) { + case CONDZ: r = vm.Z; break; + case CONDC: r = vm.C; break; + case CONDA: r = !vm.C && !vm.Z; break; } + if (cond&0x80) r = !r; + return r; } static void BRC() { byte cond = gpcb(); dword a = gpc(); if (checkcond(cond)) vm.PC = a; } static void YIELD() { dword pc = vm.PC; vm.PC = rpop(); rpush(pc); } @@ -899,6 +905,7 @@ static void buildsysdict() { sysconst("Z)", CONDZ); sysconst("NZ)", CONDNZ); sysconst("C)", CONDC); sysconst("NC)", CONDNC); sysconst("<)", CONDC); sysconst(">=)", CONDNC); + sysconst(">)", CONDA); sysconst("<=)", CONDNA); for (int i=0; i<OPCNT-0x28; i++) { if (opnames[i]) wentry(opnames[i], i+0x28); }