Skip to content

Commit

Permalink
#16 [asm] added asmik with virtual registers, arithmetics, branches (#17
Browse files Browse the repository at this point in the history
)
  • Loading branch information
vityaman authored Feb 6, 2024
2 parents 40f1b8d + 7e06050 commit d227ef2
Show file tree
Hide file tree
Showing 30 changed files with 1,130 additions and 77 deletions.
42 changes: 21 additions & 21 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions sleepy/asmik/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .emit import AsmikUnit, asmik_emit
67 changes: 67 additions & 0 deletions sleepy/asmik/argument.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import override


class Argument(ABC):
@abstractmethod
def __repr__(self) -> str:
raise NotImplementedError


class Register(Argument):
@staticmethod
def ze() -> "PhysicalRegister":
return PhysicalRegister("ze")

@staticmethod
def a1() -> "PhysicalRegister":
return PhysicalRegister("a1")

@staticmethod
def ra() -> "PhysicalRegister":
return PhysicalRegister("ra")

@staticmethod
def ip() -> "PhysicalRegister":
return PhysicalRegister("ip")


@dataclass(repr=False)
class VirtualRegister(Register):
number: int

@override
def __repr__(self) -> str:
return f"v{self.number}"


@dataclass(repr=False)
class PhysicalRegister(Register):
name: str

@override
def __repr__(self) -> str:
return self.name


class Immediate(Argument):
pass


@dataclass(repr=False)
class Integer(Immediate):
value: int

@override
def __repr__(self) -> str:
return f"{self.value}"


@dataclass(repr=False)
class Unassigned(Immediate):
label: str

@override
def __repr__(self) -> str:
return f"<{self.label}>"
30 changes: 30 additions & 0 deletions sleepy/asmik/data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from abc import ABC, abstractmethod, abstractproperty
from typing import override


class Data(ABC):
@abstractproperty
def size_in_bytes(self) -> int:
raise NotImplementedError

@abstractmethod
def __repr__(self) -> str:
raise NotImplementedError

@property
def identifier(self) -> str:
return repr(self)


class IntegerData(Data):
def __init__(self, value: int) -> None:
self.value = value

@override
@property
def size_in_bytes(self) -> int:
return 8

@override
def __repr__(self) -> str:
return f"{self.value} # const({self.value}): int"
208 changes: 208 additions & 0 deletions sleepy/asmik/emit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
import sleepy.tafka.representation as tafka
from sleepy.tafka.emit import TafkaUnit

from .argument import Immediate, Integer, Unassigned
from .argument import Register as Reg
from .argument import VirtualRegister as VirtReg
from .data import IntegerData
from .instruction import (
Addi,
Addim,
Andb,
Brn,
Divi,
Instruction,
Load,
Muli,
Orb,
Remi,
Slti,
Xorb,
mov,
movi,
)
from .memory import Memory


class AsmikEmiter:
def __init__(self) -> None:
self.virt_regs = (VirtReg(n) for n in range(10000))
self.unassigned: dict[str, int] = {}
self.memory = Memory()
self.regs: dict[str, VirtReg] = {}

self.resolved: dict[str, int] = {}

self.block: tafka.Block
self.block_until: list[tafka.Block] = []

def emit_block(self, block: tafka.Block) -> None:
if (
len(self.block_until) > 0
and self.block_until[-1].label == block.label
):
return

self.resolved[repr(block.label)] = len(self.memory.instr) * 4

self.block = block
for statement in block.statements:
self.emit_stmt(statement)

def emit_stmt(self, stmt: tafka.Statement) -> None:
match stmt:
case tafka.Jump() as jump:
self.emit_jump(jump)
case tafka.Set() as set_stmt:
self.emit_set_stmt(set_stmt)

def emit_jump(self, jump: tafka.Jump) -> None:
match jump:
case tafka.Return() as ret:
self.emit_jump_return(ret)
case tafka.Goto() as goto:
self.emit_jump_goto(goto)
case tafka.Conditional() as cond:
self.emit_jump_cond(cond)

def emit_jump_return(self, stmt: tafka.Return) -> None:
self.emit_i(mov(Reg.a1(), self.reg_var(stmt.value)))
false = self.reg_tmp()
self.emit_i(movi(false, Integer(0)))
self.emit_i(Brn(false, Reg.ra()))

def emit_jump_goto(self, stmt: tafka.Goto) -> None:
false = self.reg_tmp()
false_val = Integer(0)
self.emit_i(movi(false, false_val))

label = self.reg_tmp()
label_val = Unassigned(repr(stmt.block.label))
self.emit_i(movi(label, label_val))

self.emit_i(Brn(false, label))

def emit_jump_cond(self, conditional: tafka.Conditional) -> None:
self.block_until.append(conditional.next_block)

cond = self.reg_var(conditional.condition)

els = self.reg_tmp()
els_val = Unassigned(repr(conditional.else_branch.label))
self.emit_i(movi(els, els_val))

self.emit_i(Brn(cond, els))

self.emit_block(conditional.then_branch)
self.emit_block(conditional.else_branch)

self.block_until.pop()

self.emit_block(conditional.next_block)

def emit_set_stmt(self, stmt: tafka.Set) -> None:
match stmt.source:
case tafka.Intrinsic() as intrinsic:
self.emit_intrinsic(stmt.target, intrinsic)
case tafka.Invokation() as invokation:
self.emit_invokation(stmt.target, invokation)

def emit_intrinsic(
self,
target: tafka.Var,
source: tafka.Intrinsic,
) -> None:
dst = self.reg_var(target)
match source:
case tafka.Load(cnst):
self.emit_i(Addim(dst, Reg.ze(), self.addr_of(cnst)))
self.emit_i(Load(dst, dst))
case tafka.Copy(var):
src = self.reg_var(var)
self.emit_i(mov(dst, src))
case tafka.Sum(lhs, rhs):
lhsr = self.reg_var(lhs)
rhsr = self.reg_var(rhs)
self.emit_i(Addi(dst, lhsr, rhsr))
case tafka.Mul(lhs, rhs):
lhsr = self.reg_var(lhs)
rhsr = self.reg_var(rhs)
self.emit_i(Muli(dst, lhsr, rhsr))
case tafka.Div(lhs, rhs):
lhsr = self.reg_var(lhs)
rhsr = self.reg_var(rhs)
self.emit_i(Divi(dst, lhsr, rhsr))
case tafka.Rem(lhs, rhs):
lhsr = self.reg_var(lhs)
rhsr = self.reg_var(rhs)
self.emit_i(Remi(dst, lhsr, rhsr))
case tafka.Eq(lhs, rhs):
lhsr = self.reg_var(lhs)
rhsr = self.reg_var(rhs)

l2r = orb = dst
r2l = self.reg_tmp()
neg = self.reg_tmp()

self.emit_i(Slti(l2r, lhsr, rhsr))
self.emit_i(Slti(r2l, rhsr, lhsr))
self.emit_i(Orb(orb, l2r, r2l))
self.emit_i(Addim(neg, Reg.ze(), Integer(2**64 - 1)))
self.emit_i(Xorb(dst, orb, neg))
case tafka.Lt(lhs, rhs):
lhsr = self.reg_var(lhs)
rhsr = self.reg_var(rhs)
self.emit_i(Slti(dst, lhsr, rhsr))
case tafka.And(lhs, rhs):
lhsr = self.reg_var(lhs)
rhsr = self.reg_var(rhs)
self.emit_i(Andb(dst, lhsr, rhsr))
case _:
raise NotImplementedError(str(source))

def emit_invokation(
self,
target: tafka.Var,
source: tafka.Invokation,
) -> None:
raise NotImplementedError

def emit_i(self, instr: Instruction) -> None:
self.memory.instr.append(instr)

def reg_var(self, var: tafka.Var) -> VirtReg:
var_repr = repr(var)
if var_repr not in self.regs:
self.regs[var_repr] = self.reg_tmp()
return self.regs[var_repr]

def reg_tmp(self) -> VirtReg:
return next(self.virt_regs)

def addr_of(self, cnst: tafka.Const) -> Immediate:
match cnst.kind:
case tafka.Int():
data = IntegerData(int(cnst.name))
addr = self.memory.data_put(data)
return Integer(addr)
raise NotImplementedError


AsmikUnit = AsmikEmiter


def asmik_resolve(asmik: AsmikUnit) -> None:
for instr in asmik.memory.instr:
if (
isinstance(instr, Addim) #
and isinstance(instr.rhs, Unassigned)
):
label = instr.rhs.label
instr.rhs = Integer(asmik.resolved[label])


def asmik_emit(tafka: TafkaUnit) -> AsmikUnit:
asmik = AsmikEmiter()
asmik.emit_block(tafka.main)
asmik_resolve(asmik)
return asmik
Loading

0 comments on commit d227ef2

Please sign in to comment.