Skip to content

Commit

Permalink
#16 [asmik] recursive functions with stack context storage work
Browse files Browse the repository at this point in the history
  • Loading branch information
vityaman committed Feb 12, 2024
1 parent 69e5ab1 commit 502a207
Show file tree
Hide file tree
Showing 20 changed files with 349 additions and 106 deletions.
61 changes: 34 additions & 27 deletions sleepy/asmik/emit.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,13 @@ def __init__(self) -> None:

@override
def enter_procedure(self, procedure: taf.Procedure) -> None:
super().enter_procedure(procedure)

self.usages = Usages.analyzed(procedure)
self.procedure = procedure

addr = self.memory.data_put(IntegerData(self.next_instr_addr))
self.resolved[repr(procedure.const)] = addr
self.resolved[f"${procedure.const.name}"] = addr
for i, param in enumerate(procedure.parameters):
register = self.registers.binded_to(param)
self.emit(mov(register, PhysReg.arg(i + 1)))
Expand Down Expand Up @@ -108,28 +110,35 @@ def on_conditional(self, conditional: taf.Conditional) -> None:
self.emit(movi(else_address, Unassigned(else_label)))
self.emit(Brn(condition, else_address))

@override
def on_invokation(
self,
target: taf.Var,
source: taf.Invokation,
) -> None:
def push_context(self, variables: list[taf.Var]) -> None:
def push(register: Reg) -> None:
print(f"push {register}")
self.emit(Stor(Reg.sp(), register))
self.emit(Addim(Reg.sp(), Reg.sp(), Integer(8)))

for local in variables:
if self.is_alive(local):
push(self.registers.binded_to(local))
push(Reg.ra())

def pop_context(self, variables: list[taf.Var]) -> None:
def pop(register: Reg) -> None:
print(f"pop {register}")
self.emit(Addim(Reg.sp(), Reg.sp(), Integer(-8)))
self.emit(Load(register, Reg.sp()))

local_vars = list(self.procedure.locals)

for local in local_vars:
pop(Reg.ra())
for local in variables[::-1]:
if self.is_alive(local):
push(self.registers.binded_to(local))
push(Reg.ra())
pop(self.registers.binded_to(local))

@override
def on_invokation(
self,
target: taf.Var,
source: taf.Invokation,
) -> None:
variables = list(self.procedure.locals)

self.push_context(variables)

for i, arg in enumerate(source.args):
arg_reg = self.registers.binded_to(arg)
Expand All @@ -139,14 +148,11 @@ def pop(register: Reg) -> None:
self.emit(Addim(Reg.ra(), Reg.ip(), Integer(4)))
self.emit(Brn(Reg.ze(), proc_reg))

pop(Reg.ra())
for local in local_vars[::-1]:
if self.is_alive(local):
pop(self.registers.binded_to(local))

result = self.registers.binded_to(target)
self.emit(mov(result, Reg.a1()))

self.pop_context(variables)

@override
def on_load(self, target: taf.Var, source: taf.Load) -> None:
dst = self.registers.binded_to(target)
Expand Down Expand Up @@ -242,18 +248,19 @@ def addr_of(self, cnst: taf.Const) -> Immediate:
addr = self.memory.data_put(data)
return Integer(addr)
case taf.Signature():
return Unassigned(repr(cnst))
return Unassigned(f"${cnst.name}")
case _:
raise NotImplementedError

def is_alive(self, var: taf.Var) -> bool:
nxt = self.usages.next_read(var, self.context)
prv = self.usages.next_write(var, Context(-1, self.procedure.entry))
return (
nxt is not None #
and prv is not None #
and prv < self.position
)
read = self.usages.next_read(var, self.context)
write = self.usages.next_write(var, self.context)
init = self.usages.next_write(var, Context(-1, self.procedure.entry))

assert init is not None # noqa: S101
if write is not None:
return read is not None and read <= write
return read is not None and init < self.position

@property
def next_instr_addr(self) -> int:
Expand Down
1 change: 0 additions & 1 deletion sleepy/interpreter/asmik.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ def run(self) -> None:
self.running = False

def execute(self, instr: Instruction) -> None:
print(f"exec {instr}")
match instr:
case Addi(dst, lhs, rhs):
self.write(dst, self.read(lhs) + self.read(rhs))
Expand Down
14 changes: 7 additions & 7 deletions sleepy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@

def main() -> None:
source = """
(def id (lambda (n int) n))
(def a (id 1))
(def b (id 11))
(def c (id 111))
(if (and (eq a 1)
(and (eq b 11)
(eq c 111))) 1 0)
(def fibb (lambda (n int)
(if (or (eq n 0) (eq n 1))
1
(sum
(self (sum n -1))
(self (sum n -2))))))
(fibb 13)
"""

parser = LarkParser()
Expand Down
3 changes: 3 additions & 0 deletions sleepy/program/representation.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,11 @@ class Intrinsic(Atom):

@dataclass
class Closure(Expression):
from .namespace import Namespace

parameters: list[Parameter]
statements: list[Expression]
namespace: Namespace


@dataclass
Expand Down
2 changes: 1 addition & 1 deletion sleepy/syntax/s2p.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def visit_lambda(self, tree: LambdaAST) -> Closure:
for parameter in parameters:
self.bindings.bind(parameter.name, parameter)

closure = Closure(parameters, statements=[])
closure = Closure(parameters, statements=[], namespace=self.namespace)
self.bindings.bind(self.namespace.define(Symbol("self")), closure)

closure.statements = [
Expand Down
16 changes: 12 additions & 4 deletions sleepy/tafka/emit.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,26 +131,34 @@ def visit_lambda(self, tree: program.Closure) -> None:
procedure = taf.Procedure(
name=label.name,
entry=taf.Block(label, statements=[]),
parameters=[
self.next_var(taf.Kind.from_sleepy(param.kind))
for param in tree.parameters
],
parameters=[],
value=taf.Unknown(),
)

self.current_procedure = procedure
self.current_block = procedure.entry

procedure.parameters = [
self.next_var(taf.Kind.from_sleepy(param.kind))
for param in tree.parameters
]

for param, var in zip(
tree.parameters,
procedure.parameters,
strict=True,
):
self.vars[param.name] = var

self.emit_intermidiate(
taf.Load(taf.Const(label.name, procedure.signature)),
)
self.vars[tree.namespace.resolved("self")] = self.last_result

for statement in tree.statements:
self.visit_expression(statement)
self.emit_statement(taf.Return(self.last_result))
procedure.value = self.last_result.kind

self.current_block = current_block
self.current_procedure = current_procedure
Expand Down
3 changes: 2 additions & 1 deletion sleepy/tafka/usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ def __init__(self) -> None:

@override
def enter_procedure(self, procedure: taf.Procedure) -> None:
pass
for argument in procedure.parameters:
self.write(argument)

@override
def exit_procedure(self, procedure: taf.Procedure) -> None:
Expand Down
4 changes: 4 additions & 0 deletions sleepy/tafka/walker.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ def __init__(self) -> None:
self.position = 0
self.block: Block

@override
def enter_procedure(self, procedure: Procedure) -> None:
self.position = 0

@override
def enter_block(self, block: Block) -> None:
self.block = block
Expand Down
27 changes: 27 additions & 0 deletions test/asmik/test_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,33 @@
""",
"1",
),
(
"""
(def id (lambda (n int)
(if (eq n 0) 0 (sum (self (sum n -1)) 1))))
(if (and (eq (id 1) 1)
(and (eq (id 2) 2)
(eq (id 3) 3))) 1 0)
""",
"1",
),
(
"""
(def fibb (lambda (n int)
(if (or (eq n 0) (eq n 1))
1
(sum
(self (sum n -1))
(self (sum n -2))))))
(if (and (eq (fibb 0) 1)
(and (eq (fibb 1) 1)
(and (eq (fibb 2) 2)
(and (eq (fibb 3) 3)
(and (eq (fibb 4) 5)
(eq (fibb 5) 8)))))) 1 0)
""",
"1",
),
],
)
def test_evaluate(src: str, res: str) -> None:
Expand Down
1 change: 1 addition & 0 deletions test/golden/group/arithmetics/1.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ tafka: |-
010. }
tafka-usages: |
$main: () -> int:
001. %0: r3 w0
002. %1: r3 w0
003. %0: r0 w0, %1: r0 w0, %2: r9 w0
Expand Down
1 change: 1 addition & 0 deletions test/golden/group/conditional/1.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ tafka: |-
010. }
tafka-usages: |
$main: () -> int:
001. %0: r3 w0
002. %1: r3 w0
003. %0: r0 w0, %1: r0 w0, %2: r4 w0
Expand Down
1 change: 1 addition & 0 deletions test/golden/group/conditional/2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ tafka: |-
026. }
tafka-usages: |
$main: () -> int:
001. %0: r3 w0
002. %1: r3 w0
003. %0: r0 w0, %1: r0 w0, %2: r4 w0
Expand Down
1 change: 1 addition & 0 deletions test/golden/group/conditional/3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ tafka: |-
030. }
tafka-usages: |
$main: () -> int:
001. %0: r3 w0
002. %1: r3 w0
003. %0: r0 w0, %1: r0 w0, %2: r5 w0
Expand Down
1 change: 1 addition & 0 deletions test/golden/group/definition/1.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ tafka: |-
006. }
tafka-usages: |
$main: () -> int:
001. %0: r5 w0
002. %1: r4 w0
003. %2: r4 w0
Expand Down
1 change: 1 addition & 0 deletions test/golden/group/definition/2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ tafka: |-
009. }
tafka-usages: |
$main: () -> bool:
001. %0: r3 w0
002. %1: r3 w0
003. %0: r0 w0, %1: r0 w0, %2: r0 w0
Expand Down
1 change: 1 addition & 0 deletions test/golden/group/definition/3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ tafka: |-
011. }
tafka-usages: |
$main: () -> bool:
001. %0: r3 w0
002. %1: r3 w0
003. %0: r0 w0, %1: r0 w0, %2: r4 w0
Expand Down
Loading

0 comments on commit 502a207

Please sign in to comment.