Get or2 working again via the assembler

This commit is contained in:
Reid 'arrdem' McKenzie 2022-08-17 00:07:09 -06:00
parent 5a3a6bc96f
commit 2c92447947
5 changed files with 115 additions and 40 deletions

View file

@ -26,6 +26,7 @@ class FuncBuilder(object):
if not self._straightline:
return
start_stack = self._stack
match op:
case isa.Label(_):
# Labels abort
@ -35,6 +36,15 @@ class FuncBuilder(object):
# Control ops abort
self._straightline = False
case isa.CLOSUREC(n) | isa.CLOSUREF(n):
self._stack -= n
case isa.TYPEREF():
pass
case isa.ARMREF():
self._stack -= 1
case isa.DROP(n):
self._stack -= n
@ -48,6 +58,8 @@ class FuncBuilder(object):
self._stack -= getattr(op, "nargs", 0)
self._stack += 1
print(op, "pre", start_stack, "post", self._stack)
def write(self, op: Union[isa.Opcode, isa.Label, Sequence[isa.Opcode]]):
def flatten(o):
@ -58,15 +70,24 @@ class FuncBuilder(object):
yield from flatten(e)
if isinstance(op, (isa.Opcode, isa.Label)):
self._opcodes.append(op)
self._write(op)
else:
for e in op:
for e in flatten(op):
self.write(e)
def make_label(self, prefix: Optional[str] = ""):
return gensym(prefix)
def mark_argument(self, prefix: Optional[str] = ""):
if not self._opcodes:
s = gensym(prefix)
self._stack += 1
self._slots[s] = self._stack - 1
return s
else:
raise Exception("Cannot mark arguments after writing opcodes")
def mark_label(self, prefix: Optional[str] = ""):
l = self.make_label(prefix=prefix)
self.write(l)
@ -80,7 +101,8 @@ class FuncBuilder(object):
elif self._straightline:
s = gensym(prefix)
self._slots[s] = self._stack
assert self._stack > 0
self._slots[s] = self._stack - 1
return s
else:

View file

@ -5,6 +5,7 @@ Hopefully no "real" interpreter ever uses this code, since it's obviously replac
"""
from ichor import isa
from ichor.assembler import FuncBuilder
from ichor.state import Module, Variant
@ -42,45 +43,87 @@ NOT1 = BOOTSTRAP.define_function(
],
)
_b = FuncBuilder()
# Capture args
_x = _b.mark_argument()
_y = _b.mark_argument()
# Const
_b.write(isa.IDENTIFIERC("bool"))
_b.write(isa.TYPEREF())
_bool_t = _b.mark_slot()
_b.write(isa.SLOT(_bool_t))
_b.write(isa.IDENTIFIERC("true"))
_b.write(isa.ARMREF())
_true_t = _b.mark_slot()
_b.write(isa.SLOT(_bool_t))
_b.write(isa.IDENTIFIERC("false"))
_b.write(isa.ARMREF())
_false_t = _b.mark_slot()
# x: Bool, x: Bool -> Bool
_true_l = _b.make_label()
_b.write(isa.SLOT(_x))
_b.write(isa.SLOT(_true_t))
_b.write(isa.ATEST(_true_l))
_b.write(isa.SLOT(_y))
_b.write(isa.SLOT(_true_t))
_b.write(isa.ATEST(_true_l))
_b.write(isa.SLOT(_false_t))
_b.write(isa.ARM(0))
_b.write(isa.RETURN())
_b.write(_true_l)
_b.write(isa.SLOT(_true_t))
_b.write(isa.ARM(0))
_b.write(isa.RETURN())
OR2 = BOOTSTRAP.define_function(
f";or;{BOOL},{BOOL};{BOOL}",
[
isa.BREAK(),
],
_b.build()
)
_b = FuncBuilder()
_b.write(isa.BREAK())
OR3 = BOOTSTRAP.define_function(
f";or;{BOOL},{BOOL},{BOOL};{BOOL}",
[
isa.BREAK(),
]
_b.build()
)
_b = FuncBuilder()
_b.write(isa.BREAK())
AND2 = BOOTSTRAP.define_function(
f";and;{BOOL},{BOOL};{BOOL}",
[
isa.BREAK(),
],
_b.build()
)
_b = FuncBuilder()
_b.write(isa.BREAK())
AND3 = BOOTSTRAP.define_function(
f";and;{BOOL},{BOOL},{BOOL};{BOOL}",
[
isa.BREAK(),
],
_b.build()
)
_b = FuncBuilder()
_b.write(isa.BREAK())
XOR2 = BOOTSTRAP.define_function(
f";xor;{BOOL},{BOOL};{BOOL}",
[
isa.BREAK(),
],
_b.build()
)
_b = FuncBuilder()
_b.write(isa.BREAK())
XOR3 = BOOTSTRAP.define_function(
f";xor;{BOOL},{BOOL},{BOOL};{BOOL}",
[
# A^B|B^C
isa.BREAK(),
]
_b.build()
)

View file

@ -264,11 +264,11 @@ class Interpreter(BaseInterpreter):
def handle_atest(self, state: InterpreterState, opcode: isa.ATEST) -> InterpreterState:
armref: VariantRef = state.stackframe.pop()
if not isinstance(armref, VariantRef):
return self.handle_fault(state, opcode, "VTEST must be given a variant reference")
return self.handle_fault(state, opcode, "ATEST must be given a variant reference")
inst: Variant = state.stackframe.pop()
if not isinstance(inst, Variant):
return self.handle_fault(state, opcode, "VTEST must be given an instance of a variant")
return self.handle_fault(state, opcode, "ATEST must be given an instance of a variant")
if inst.type == armref.type.name and inst.variant == armref.arm:
state.stackframe.goto(opcode.target)

View file

@ -19,8 +19,9 @@ class LoggingInterpreter(Interpreter):
b.append(" stack:")
for offset, it in zip(range(0, len(state.stackframe), 1), state.stackframe):
b.append(f" {offset: <3} {it}")
b.append(f" op: {opcode}")
print(indent("\n".join(b), " " * state.stackframe.depth))
b.append(f" op: {opcode}")
print(indent("\n".join(b), " " * state.stackframe.depth))
return state

View file

@ -3,7 +3,13 @@
from .fixtures import * # noqa
from ichor import isa
from ichor.bootstrap import FALSE, NOT1, TRUE
from ichor.bootstrap import (
FALSE,
NOT1,
OR2,
OR2_INSTRS,
TRUE,
)
import pytest
@ -20,19 +26,22 @@ def test_not(vm, stack, ret):
], stack = stack) == ret
# @pytest.mark.parametrize("stack,ret", [
# [[False, False], [False]],
# [[True, False], [True]],
# [[False, True], [True]],
# [[True, True], [True]],
# ])
# def test_or(vm, stack, ret):
# assert vm.run([
# isa.IDENTIFIERC(OR2),
# isa.FUNREF(),
# isa.CALLF(2),
# isa.RETURN(1)
# ], stack = stack) == ret
@pytest.mark.parametrize("stack,ret", [
[[FALSE, FALSE], [FALSE]],
[[TRUE, FALSE], [TRUE]],
[[FALSE, TRUE], [TRUE]],
[[TRUE, TRUE], [TRUE]],
])
def test_or(vm, stack, ret):
for idx, i in zip(range(512), OR2_INSTRS):
print(f"{idx:>3} {i}")
assert vm.run([
isa.IDENTIFIERC(OR2),
isa.FUNREF(),
isa.CALLF(2),
isa.RETURN()
], stack = stack) == ret
# @pytest.mark.parametrize("stack,ret", [