commit 6fe12160abed3e3ebc51e913f2650ee3f57c610d
parent 2507af22d83b05bb2c5048011d7401df9f964b5f
Author: Virgil Dupras <hsoft@hardcoded.net>
Date: Sun, 19 Mar 2023 16:07:37 -0400
halcc: binopcondeval()
Diffstat:
8 files changed, 119 insertions(+), 34 deletions(-)
diff --git a/fs/comp/c/egen.fs b/fs/comp/c/egen.fs
@@ -65,7 +65,7 @@ UOPSCNT wordtbl _tbl ( res -- res )
of uopid ( opid )
nextt parseFactor ( opid res ) _tbl rot wexec endof
of isIdent? \ lvalue, FunCall or macro
- r@ findIdent ?dup _assert CType :halop Result :hal ( parsePostfixOp ) endof
+ r@ findIdent ?dup _assert Result :ctype ( parsePostfixOp ) endof
r@ parse if Result :const else _err then
endcase ;
current ' parseFactor realias
@@ -83,11 +83,23 @@ fixed _<<, <<, fixed _>>, >>,
: _=, ( left right ) Result :>W Result :hal# !, Result :W ;
-BOPSCNT wordtbl _tbl ( -- )
+\ 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
+\ will always be ran, regardless of the choice. So, we go like this: we generate
+\ 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 )
+ PS- W=0>Z, 0 Z) branchC,
+ drop, [compile] else nip, swap 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 _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 'w _err 'w _err 'w _err 'w _err '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
@@ -1,5 +1,7 @@
\ Expression parsing and constexpr resolving
?f<< /comp/c/op.fs
+?f<< /comp/c/type.fs
+?f<< /comp/c/glob.fs
: _err ( -- ) tokdbg abort" expr error" ;
: _assert ( f -- ) not if _err then ;
@@ -7,22 +9,23 @@
struct[ Result
0 const CONST \ Is a constant (value in arg)
1 const W \ Value in W register
- 2 const HALOP \ Value in memory, HAL operand is in arg.
+ 2 const CTYPE \ CType pointer is in arg.
sfield type
- sfield arg \ either HAL operand or constant value
+ sfield arg \ either CType or constant value
: :new ( arg type -- res ) SZ syspad :allot dup >r !+ ! r> ;
: :const ( n -- res ) CONST :new ;
: :W ( -- res ) 0 W :new ;
- : :hal ( operand -- res ) HALOP :new ;
+ : :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
- HALOP of = @, endof
+ CTYPE of = CType :halop @, endof
_err endcase W swap to type ;
: :hal# ( self -- halop ) dup type case ( self )
- HALOP of = arg endof
+ CTYPE of = arg CType :halop endof
CONST of = arg i) endof
_err endcase ;
: :isconst? ( self -- f ) type CONST = ;
@@ -30,6 +33,7 @@ struct[ Result
: :isone? bi arg 1 = | :isconst? and ;
: :isW? ( self -- f ) type W = ;
: :const# dup :isconst? _assert arg ;
+ : :>PS :>W dup, PS+ ;
]struct
BOPSCNT wordtbl _tbl ( a b -- n )
diff --git a/fs/comp/c/fgen.fs b/fs/comp/c/fgen.fs
@@ -9,7 +9,7 @@
: _postlude
_curfunc CType :argssize ?dup if ps+, then
- _locvars CType :size rs+, ;
+ _locvars CType :size ?dup if rs+, then ;
: emitRet ( res -- ) Result :>W _postlude exit, ;
: emitNullRet ( -- ) _postlude drop, exit, ;
@@ -72,7 +72,7 @@ current ' parseStatement realias
here _curfunc to CType offset ( )
_curfunc ?updateFunctionPrototype _curfunc addSymbol
\ prelude: space for stack frame. "dup," is wiggle room for W
- dup, _locvars CType :size neg rs+,
+ dup, _locvars CType :size ?dup if neg rs+, then
_initcode ?dup if [compile] again r> [compile] then then
0 to _laststmtid parseStatements
_laststmtid 1 <> if emitRet then \ emit implicit return if needed
diff --git a/fs/comp/c/glob.fs b/fs/comp/c/glob.fs
@@ -0,0 +1,11 @@
+\ Global variables affecting the whole CC
+
+\ A function prelude always starts a "PS neutral" and should always be at
+\ "PS neutral" when exiting from it. When we push something to PS, we increase
+\ psoff, when we pop, we decrease it. This allows us to reliably access the
+\ argument space of the function which lives in PS.
+0 value psoff
+
+: PS+ CELLSZ to+ psoff ;
+: PS- CELLSZ neg to+ psoff ;
+: psneutral# psoff if abort" psoff not neutral!" then ;
diff --git a/fs/comp/c/type.fs b/fs/comp/c/type.fs
@@ -4,6 +4,7 @@
?f<< /lib/meta.fs
?f<< /lib/ll.fs
?f<< /comp/c/tok.fs
+?f<< /comp/c/glob.fs
\ When we parse a type, we can almost never write it directly to "here" because
\ there's always the chance that we're in the middle of a code generation op.
@@ -106,7 +107,7 @@ struct[ CType
: :halop ( self -- operand ) dup bi offset | storage case ( self offset )
STORAGE_SF of = RSP) swap +) endof
- STORAGE_PS of = PSP) swap +) endof
+ STORAGE_PS of = PSP) swap psoff + +) endof
STORAGE_MEM of = m) endof _err endcase ( self operand )
swap type _typesize case 1 of = 8b) endof 2 of = 16b) endof endcase ;
diff --git a/fs/tests/comp/c/cc.fs b/fs/tests/comp/c/cc.fs
@@ -16,9 +16,9 @@ binopshl 336 #eq
binopshr 10 #eq
binopdiv 14 #eq
binopmod 1 #eq
-testend \s
1 binopcondeval 42 #eq
0 binopcondeval 12 #eq
+testend \s
assignops 83 #eq
boolops 0 #eq
funcall 42 #eq
diff --git a/fs/tests/comp/c/test2.c b/fs/tests/comp/c/test2.c
@@ -52,3 +52,6 @@ int binopmod() {
int a=43;
return a % 3;
}
+int binopcondeval(int x) {
+ return x ? 42 : 12 ;
+}
diff --git a/posix/dis.c b/posix/dis.c
@@ -22,7 +22,7 @@ struct op {
int arg;
};
-#define OPCNT 0x78
+#define OPCNT 0xa8
static struct op ops[OPCNT] = {
{"BR", ARGINT},
{"CALL", ARGINT},
@@ -73,9 +73,9 @@ static struct op ops[OPCNT] = {
{"BOOTRD", ARGNONE},
{"STDOUT", ARGNONE},
{"MAYBEKEY", ARGNONE},
- {NULL, ARGERR},
- {NULL, ARGERR},
- {NULL, ARGERR},
+ {"HBANKGET", ARGNONE},
+ {"MAKEMEM", ARGNONE},
+ {"ADDDISP", ARGNONE},
{NULL, ARGERR},
{"MAYBEWORD", ARGNONE},
@@ -94,7 +94,7 @@ static struct op ops[OPCNT] = {
{"STARTCOMP", ARGNONE},
{"STOPCOMP", ARGNONE},
{"RSADDWR", ARGNONE},
- {NULL, ARGERR},
+ {"COMPOP", ARGNONE},
{"ALIGN4", ARGNONE},
{"ENTRY", ARGNONE},
@@ -105,22 +105,13 @@ static struct op ops[OPCNT] = {
{NULL, ARGERR},
{NULL, ARGERR},
- {"SUB", ARGNONE},
- {"MUL", ARGNONE},
- {"DIVMOD", ARGNONE},
- {"LSHIFT", ARGNONE},
- {"RSHIFT", ARGNONE},
- {"LT", ARGNONE},
- {NULL, ARGERR},
- {NULL, ARGERR},
-
- {"AND", ARGNONE},
- {"OR", ARGNONE},
- {"XOR", ARGNONE},
{NULL, ARGERR},
{NULL, ARGERR},
{NULL, ARGERR},
+ {"DIVMOD", ARGNONE},
{NULL, ARGERR},
+ {"LT", ARGNONE},
+ {"NEG", ARGNONE},
{NULL, ARGERR},
{"BYE", ARGNONE},
@@ -132,13 +123,76 @@ static struct op ops[OPCNT] = {
{NULL, ARGERR},
{NULL, ARGERR},
- {"SHLN", ARGBYTE},
- {"SHRN", ARGBYTE},
- {"ANDN", ARGINT},
- {"ORN", ARGINT},
- {"XORN", ARGINT},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
{"CHECKZ", ARGNONE},
{"STOREZ", ARGNONE},
+ {"ACHECKZ", ARGNONE},
+
+ {"WSUB", ARGOP},
+ {"WMUL", ARGOP},
+ {"WDIV", ARGOP},
+ {"WMOD", ARGOPN},
+ {"WSHL", ARGOP},
+ {"WSHR", ARGOP},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+
+ {"WSUB16", ARGOP},
+ {"WMUL16", ARGOP},
+ {"WDIV16", ARGOP},
+ {"WMOD16", ARGOPN},
+ {"WSHL16", ARGOP},
+ {"WSHR16", ARGOP},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+
+ {"WSUB8", ARGOP},
+ {"WMUL8", ARGOP},
+ {"WDIV8", ARGOP},
+ {"WMOD8", ARGOPN},
+ {"WSHL8", ARGOP},
+ {"WSHR8", ARGOP},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+
+ {"WAND", ARGOP},
+ {"WOR", ARGOP},
+ {"WXOR", ARGOP},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+
+ {"WAND16", ARGOP},
+ {"WOR16", ARGOP},
+ {"WXOR16", ARGOP},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+
+ {"WAND8", ARGOP},
+ {"WOR8", ARGOP},
+ {"WXOR8", ARGOP},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
+ {NULL, ARGERR},
{NULL, ARGERR},
{"FCHILD", ARGNONE},