--- /dev/null
+import unittest
+from bigint_presentation_code.compiler_ir import GPR_SIZE_IN_BYTES
+
+from bigint_presentation_code.compiler_ir2 import (Fn, OpKind, PreRASimState)
+
+
+class TestCompilerIR(unittest.TestCase):
+ maxDiff = None
+
+ def test_sim(self):
+ fn = Fn()
+ op0 = fn.append_new_op(OpKind.FuncArgR3, name="arg")
+ arg = op0.outputs[0]
+ MAXVL = 32
+ op1 = fn.append_new_op(OpKind.SetVLI, immediates=[MAXVL], name="vl")
+ vl = op1.outputs[0]
+ op2 = fn.append_new_op(
+ OpKind.SvLd, inputs=[arg, vl], immediates=[0], maxvl=MAXVL,
+ name="ld")
+ a = op2.outputs[0]
+ op3 = fn.append_new_op(
+ OpKind.SvLI, inputs=[vl], immediates=[0], maxvl=MAXVL, name="li")
+ b = op3.outputs[0]
+ op4 = fn.append_new_op(OpKind.SetCA, name="ca")
+ ca = op4.outputs[0]
+ op5 = fn.append_new_op(
+ OpKind.SvAddE, inputs=[a, b, ca, vl], maxvl=MAXVL, name="add")
+ s = op5.outputs[0]
+ fn.append_new_op(
+ OpKind.SvStd, inputs=[s, arg, vl], immediates=[0], maxvl=MAXVL,
+ name="st")
+
+ self.assertEqual([repr(i) for i in fn.ops], [
+ "Op(fn=<Fn>, properties=OpProperties(kind=OpKind.FuncArgR3, "
+ "inputs=(), outputs=("
+ "OperandDesc(loc_set_before_spread=LocSet(starts=FMap({"
+ "LocKind.GPR: FBitSet([3])}), "
+ "ty=Ty(base_ty=BaseTy.I64, reg_len=1)), "
+ "tied_input_index=None, spread_index=None),), maxvl=1), "
+ "inputs=OpInputs([], op=...), "
+ "immediates=OpImmediates([], op=...), "
+ "outputs=(<arg#0>,), "
+ "name='arg')",
+ "Op(fn=<Fn>, properties=OpProperties(kind=OpKind.SetVLI, "
+ "inputs=(), outputs=("
+ "OperandDesc(loc_set_before_spread=LocSet(starts=FMap({"
+ "LocKind.VL_MAXVL: FBitSet([0])}), "
+ "ty=Ty(base_ty=BaseTy.VL_MAXVL, reg_len=1)), "
+ "tied_input_index=None, spread_index=None),), maxvl=1), "
+ "inputs=OpInputs([], op=...), "
+ "immediates=OpImmediates([32], op=...), "
+ "outputs=(<vl#0>,), "
+ "name='vl')",
+ "Op(fn=<Fn>, properties=OpProperties(kind=OpKind.SvLd, "
+ "inputs=("
+ "OperandDesc(loc_set_before_spread=LocSet(starts=FMap({"
+ "LocKind.GPR: FBitSet([*range(3, 13), *range(14, 128)])}), "
+ "ty=Ty(base_ty=BaseTy.I64, reg_len=1)), "
+ "tied_input_index=None, spread_index=None), "
+ "OperandDesc(loc_set_before_spread=LocSet(starts=FMap({"
+ "LocKind.VL_MAXVL: FBitSet([0])}), "
+ "ty=Ty(base_ty=BaseTy.VL_MAXVL, reg_len=1)), "
+ "tied_input_index=None, spread_index=None)), "
+ "outputs=("
+ "OperandDesc(loc_set_before_spread=LocSet(starts=FMap({"
+ "LocKind.GPR: FBitSet(range(14, 97))}), "
+ "ty=Ty(base_ty=BaseTy.I64, reg_len=32)), "
+ "tied_input_index=None, spread_index=None),), maxvl=32), "
+ "inputs=OpInputs([<arg#0>, <vl#0>], op=...), "
+ "immediates=OpImmediates([0], op=...), "
+ "outputs=(<ld#0>,), "
+ "name='ld')",
+ "Op(fn=<Fn>, properties=OpProperties(kind=OpKind.SvLI, "
+ "inputs=("
+ "OperandDesc(loc_set_before_spread=LocSet(starts=FMap({"
+ "LocKind.VL_MAXVL: FBitSet([0])}), "
+ "ty=Ty(base_ty=BaseTy.VL_MAXVL, reg_len=1)), "
+ "tied_input_index=None, spread_index=None),), outputs=("
+ "OperandDesc(loc_set_before_spread=LocSet(starts=FMap({"
+ "LocKind.GPR: FBitSet(range(14, 97))}), "
+ "ty=Ty(base_ty=BaseTy.I64, reg_len=32)), "
+ "tied_input_index=None, spread_index=None),), maxvl=32), "
+ "inputs=OpInputs([<vl#0>], op=...), "
+ "immediates=OpImmediates([0], op=...), "
+ "outputs=(<li#0>,), "
+ "name='li')",
+ "Op(fn=<Fn>, properties=OpProperties(kind=OpKind.SetCA, "
+ "inputs=(), outputs=("
+ "OperandDesc(loc_set_before_spread=LocSet(starts=FMap({"
+ "LocKind.CA: FBitSet([0])}), "
+ "ty=Ty(base_ty=BaseTy.CA, reg_len=1)), "
+ "tied_input_index=None, spread_index=None),), maxvl=1), "
+ "inputs=OpInputs([], op=...), "
+ "immediates=OpImmediates([], op=...), "
+ "outputs=(<ca#0>,), "
+ "name='ca')",
+ "Op(fn=<Fn>, properties=OpProperties(kind=OpKind.SvAddE, "
+ "inputs=("
+ "OperandDesc(loc_set_before_spread=LocSet(starts=FMap({"
+ "LocKind.GPR: FBitSet(range(14, 97))}), "
+ "ty=Ty(base_ty=BaseTy.I64, reg_len=32)), "
+ "tied_input_index=None, spread_index=None), "
+ "OperandDesc(loc_set_before_spread=LocSet(starts=FMap({"
+ "LocKind.GPR: FBitSet(range(14, 97))}), "
+ "ty=Ty(base_ty=BaseTy.I64, reg_len=32)), "
+ "tied_input_index=None, spread_index=None), "
+ "OperandDesc(loc_set_before_spread=LocSet(starts=FMap({"
+ "LocKind.CA: FBitSet([0])}), "
+ "ty=Ty(base_ty=BaseTy.CA, reg_len=1)), "
+ "tied_input_index=None, spread_index=None), "
+ "OperandDesc(loc_set_before_spread=LocSet(starts=FMap({"
+ "LocKind.VL_MAXVL: FBitSet([0])}), "
+ "ty=Ty(base_ty=BaseTy.VL_MAXVL, reg_len=1)), "
+ "tied_input_index=None, spread_index=None)), outputs=("
+ "OperandDesc(loc_set_before_spread=LocSet(starts=FMap({"
+ "LocKind.GPR: FBitSet(range(14, 97))}), "
+ "ty=Ty(base_ty=BaseTy.I64, reg_len=32)), "
+ "tied_input_index=None, spread_index=None), "
+ "OperandDesc(loc_set_before_spread=LocSet(starts=FMap({"
+ "LocKind.CA: FBitSet([0])}), "
+ "ty=Ty(base_ty=BaseTy.CA, reg_len=1)), "
+ "tied_input_index=None, spread_index=None)), maxvl=32), "
+ "inputs=OpInputs([<ld#0>, <li#0>, <ca#0>, <vl#0>], op=...), "
+ "immediates=OpImmediates([], op=...), "
+ "outputs=(<add#0>, <add#1>), "
+ "name='add')",
+ "Op(fn=<Fn>, properties=OpProperties(kind=OpKind.SvStd, "
+ "inputs=("
+ "OperandDesc(loc_set_before_spread=LocSet(starts=FMap({"
+ "LocKind.GPR: FBitSet(range(14, 97))}), "
+ "ty=Ty(base_ty=BaseTy.I64, reg_len=32)), "
+ "tied_input_index=None, spread_index=None), "
+ "OperandDesc(loc_set_before_spread=LocSet(starts=FMap({"
+ "LocKind.GPR: FBitSet([*range(3, 13), *range(14, 128)])}), "
+ "ty=Ty(base_ty=BaseTy.I64, reg_len=1)), "
+ "tied_input_index=None, spread_index=None), "
+ "OperandDesc(loc_set_before_spread=LocSet(starts=FMap({"
+ "LocKind.VL_MAXVL: FBitSet([0])}), "
+ "ty=Ty(base_ty=BaseTy.VL_MAXVL, reg_len=1)), "
+ "tied_input_index=None, spread_index=None)), "
+ "outputs=(), maxvl=32), "
+ "inputs=OpInputs([<add#0>, <arg#0>, <vl#0>], op=...), "
+ "immediates=OpImmediates([0], op=...), outputs=(), "
+ "name='st')",
+ ])
+
+ addr = 0x100
+ state = PreRASimState(ssa_vals={arg: (addr,)}, memory={})
+ state.store(addr=addr, value=0xffffffff_ffffffff,
+ size_in_bytes=GPR_SIZE_IN_BYTES)
+ state.store(addr=addr + GPR_SIZE_IN_BYTES, value=0xabcdef01_23456789,
+ size_in_bytes=GPR_SIZE_IN_BYTES)
+ self.assertEqual(
+ repr(state),
+ "PreRASimState(ssa_vals={<arg#0>: (0x100,)}, memory={\n"
+ "0x00100: <0xffffffffffffffff>,\n"
+ "0x00108: <0xabcdef0123456789>})")
+ fn.pre_ra_sim(state)
+ self.assertEqual(
+ repr(state),
+ "PreRASimState(ssa_vals={\n"
+ "<arg#0>: (0x100,),\n"
+ "<vl#0>: (0x20,),\n"
+ "<ld#0>: (\n"
+ " 0xffffffffffffffff, 0xabcdef0123456789, 0x0, 0x0,\n"
+ " 0x0, 0x0, 0x0, 0x0,\n"
+ " 0x0, 0x0, 0x0, 0x0,\n"
+ " 0x0, 0x0, 0x0, 0x0,\n"
+ " 0x0, 0x0, 0x0, 0x0,\n"
+ " 0x0, 0x0, 0x0, 0x0,\n"
+ " 0x0, 0x0, 0x0, 0x0,\n"
+ " 0x0, 0x0, 0x0, 0x0),\n"
+ "<li#0>: (\n"
+ " 0x0, 0x0, 0x0, 0x0,\n"
+ " 0x0, 0x0, 0x0, 0x0,\n"
+ " 0x0, 0x0, 0x0, 0x0,\n"
+ " 0x0, 0x0, 0x0, 0x0,\n"
+ " 0x0, 0x0, 0x0, 0x0,\n"
+ " 0x0, 0x0, 0x0, 0x0,\n"
+ " 0x0, 0x0, 0x0, 0x0,\n"
+ " 0x0, 0x0, 0x0, 0x0),\n"
+ "<ca#0>: (0x1,),\n"
+ "<add#0>: (\n"
+ " 0x0, 0xabcdef012345678a, 0x0, 0x0,\n"
+ " 0x0, 0x0, 0x0, 0x0,\n"
+ " 0x0, 0x0, 0x0, 0x0,\n"
+ " 0x0, 0x0, 0x0, 0x0,\n"
+ " 0x0, 0x0, 0x0, 0x0,\n"
+ " 0x0, 0x0, 0x0, 0x0,\n"
+ " 0x0, 0x0, 0x0, 0x0,\n"
+ " 0x0, 0x0, 0x0, 0x0),\n"
+ "<add#1>: (0x0,),\n"
+ "}, memory={\n"
+ "0x00100: <0x0000000000000000>,\n"
+ "0x00108: <0xabcdef012345678a>,\n"
+ "0x00110: <0x0000000000000000>,\n"
+ "0x00118: <0x0000000000000000>,\n"
+ "0x00120: <0x0000000000000000>,\n"
+ "0x00128: <0x0000000000000000>,\n"
+ "0x00130: <0x0000000000000000>,\n"
+ "0x00138: <0x0000000000000000>,\n"
+ "0x00140: <0x0000000000000000>,\n"
+ "0x00148: <0x0000000000000000>,\n"
+ "0x00150: <0x0000000000000000>,\n"
+ "0x00158: <0x0000000000000000>,\n"
+ "0x00160: <0x0000000000000000>,\n"
+ "0x00168: <0x0000000000000000>,\n"
+ "0x00170: <0x0000000000000000>,\n"
+ "0x00178: <0x0000000000000000>,\n"
+ "0x00180: <0x0000000000000000>,\n"
+ "0x00188: <0x0000000000000000>,\n"
+ "0x00190: <0x0000000000000000>,\n"
+ "0x00198: <0x0000000000000000>,\n"
+ "0x001a0: <0x0000000000000000>,\n"
+ "0x001a8: <0x0000000000000000>,\n"
+ "0x001b0: <0x0000000000000000>,\n"
+ "0x001b8: <0x0000000000000000>,\n"
+ "0x001c0: <0x0000000000000000>,\n"
+ "0x001c8: <0x0000000000000000>,\n"
+ "0x001d0: <0x0000000000000000>,\n"
+ "0x001d8: <0x0000000000000000>,\n"
+ "0x001e0: <0x0000000000000000>,\n"
+ "0x001e8: <0x0000000000000000>,\n"
+ "0x001f0: <0x0000000000000000>,\n"
+ "0x001f8: <0x0000000000000000>})")
+
+
+if __name__ == "__main__":
+ unittest.main()
from abc import abstractmethod
from enum import Enum, unique
from functools import lru_cache
-from typing import (AbstractSet, Any, Generic, Iterable, Iterator, Sequence,
- TypeVar, overload)
+from typing import (AbstractSet, Any, Callable, Generic, Iterable, Iterator,
+ Sequence, TypeVar, overload)
from weakref import WeakValueDictionary as _WeakVDict
from cached_property import cached_property
-from nmutil.plain_data import plain_data
+from nmutil.plain_data import fields, plain_data
from bigint_presentation_code.type_util import Self, assert_never, final
from bigint_presentation_code.util import BitSet, FBitSet, FMap, OFSet
raise ValueError("Op already named")
orig_name = name
while True:
- if name not in self.__op_names:
+ if name != "" and name not in self.__op_names:
self.__op_names[name] = op
return name
name = orig_name + str(self.__next_name_suffix)
# type: () -> str
return "<Fn>"
+ def append_op(self, op):
+ # type: (Op) -> None
+ if op.fn is not self:
+ raise ValueError("can't add Op to wrong Fn")
+ self.ops.append(op)
+
+ def append_new_op(self, kind, inputs=(), immediates=(), name="", maxvl=1):
+ # type: (OpKind, Iterable[SSAVal], Iterable[int], str, int) -> Op
+ retval = Op(fn=self, properties=kind.instantiate(maxvl=maxvl),
+ inputs=inputs, immediates=immediates, name=name)
+ self.append_op(retval)
+ return retval
+
+ def pre_ra_sim(self, state):
+ # type: (PreRASimState) -> None
+ for op in self.ops:
+ op.pre_ra_sim(state)
+
@unique
@final
# type: (Ty) -> LocSet
if ty.base_ty != self.base_ty:
raise ValueError("type mismatch")
- raise NotImplementedError # FIXME: finish
+ if self is LocSubKind.BASE_GPR:
+ starts = range(32)
+ elif self is LocSubKind.SV_EXTRA2_VGPR:
+ starts = range(0, 128, 2)
+ elif self is LocSubKind.SV_EXTRA2_SGPR:
+ starts = range(64)
+ elif self is LocSubKind.SV_EXTRA3_VGPR \
+ or self is LocSubKind.SV_EXTRA3_SGPR:
+ starts = range(128)
+ elif self is LocSubKind.StackI64:
+ starts = range(LocKind.StackI64.loc_count)
+ elif self is LocSubKind.CA or self is LocSubKind.VL_MAXVL:
+ return LocSet([Loc(kind=self.kind, start=0, reg_len=1)])
+ else:
+ assert_never(self)
+ retval = [] # type: list[Loc]
+ for start in starts:
+ loc = Loc.try_make(kind=self.kind, start=start, reg_len=ty.reg_len)
+ if loc is None:
+ continue
+ conflicts = False
+ for special_loc in SPECIAL_GPRS:
+ if loc.conflicts(special_loc):
+ conflicts = True
+ break
+ if not conflicts:
+ retval.append(loc)
+ return LocSet(retval)
+
+ def __repr__(self):
+ return "LocSubKind." + self._name_
@plain_data(frozen=True, unsafe_hash=True)
def try_make(kind, start, reg_len):
# type: (LocKind, int, int) -> Loc | None
msg = Loc.validate(kind=kind, start=start, reg_len=reg_len)
- if msg is None:
+ if msg is not None:
return None
return Loc(kind=kind, start=start, reg_len=reg_len)
def conflicts(self, other):
# type: (Loc) -> bool
- return (self.kind != other.kind
+ return (self.kind == other.kind
and self.start < other.stop and other.start < self.stop)
@staticmethod
return Loc(kind=self.kind, start=self.start, reg_len=reg_len)
-@plain_data(frozen=True, eq=False, repr=False)
+SPECIAL_GPRS = (
+ Loc(kind=LocKind.GPR, start=0, reg_len=1),
+ Loc(kind=LocKind.GPR, start=1, reg_len=1),
+ Loc(kind=LocKind.GPR, start=2, reg_len=1),
+ Loc(kind=LocKind.GPR, start=13, reg_len=1),
+)
+
+
+@plain_data(frozen=True, eq=False)
@final
class LocSet(AbstractSet[Loc]):
__slots__ = "starts", "ty"
def __contains__(self, loc):
# type: (Loc | Any) -> bool
- if not isinstance(loc, Loc) or loc.ty == self.ty:
+ if not isinstance(loc, Loc) or loc.ty != self.ty:
return False
if loc.kind not in self.starts:
return False
__slots__ = ("demo_asm", "inputs", "outputs", "immediates",
"is_copy", "is_load_immediate", "has_side_effects")
- def __init__(self, demo_asm, # type: str
- inputs, # type: Iterable[GenericOperandDesc]
- outputs, # type: Iterable[GenericOperandDesc]
- immediates=(), # type: Iterable[range]
- is_copy=False, # type: bool
- is_load_immediate=False, # type: bool
- has_side_effects=False, # type: bool
- ):
+ def __init__(
+ self, demo_asm, # type: str
+ inputs, # type: Iterable[GenericOperandDesc]
+ outputs, # type: Iterable[GenericOperandDesc]
+ immediates=(), # type: Iterable[range]
+ is_copy=False, # type: bool
+ is_load_immediate=False, # type: bool
+ has_side_effects=False, # type: bool
+ ):
# type: (...) -> None
self.demo_asm = demo_asm
self.inputs = tuple(inputs)
return self.generic.has_side_effects
+IMM_S16 = range(-1 << 15, 1 << 15)
+
+_PRE_RA_SIM_FN = Callable[["Op", "PreRASimState"], None]
+_PRE_RA_SIM_FN2 = Callable[[], _PRE_RA_SIM_FN]
+_PRE_RA_SIMS = {} # type: dict[GenericOpProperties | Any, _PRE_RA_SIM_FN2]
+
+
@unique
@final
class OpKind(Enum):
# type: () -> GenericOpProperties
return self.__properties
+ def instantiate(self, maxvl):
+ # type: (int) -> OpProperties
+ return OpProperties(self, maxvl=maxvl)
+
+ def __repr__(self):
+ return "OpKind." + self._name_
+
+ @cached_property
+ def pre_ra_sim(self):
+ # type: () -> _PRE_RA_SIM_FN
+ return _PRE_RA_SIMS[self.properties]()
+
+ @staticmethod
+ def __clearca_pre_ra_sim(op, state):
+ # type: (Op, PreRASimState) -> None
+ state.ssa_vals[op.outputs[0]] = False,
+ ClearCA = GenericOpProperties(
+ demo_asm="addic 0, 0, 0",
+ inputs=[],
+ outputs=[OD_CA],
+ )
+ _PRE_RA_SIMS[ClearCA] = lambda: OpKind.__clearca_pre_ra_sim
+
+ @staticmethod
+ def __setca_pre_ra_sim(op, state):
+ # type: (Op, PreRASimState) -> None
+ state.ssa_vals[op.outputs[0]] = True,
+ SetCA = GenericOpProperties(
+ demo_asm="subfc 0, 0, 0",
+ inputs=[],
+ outputs=[OD_CA],
+ )
+ _PRE_RA_SIMS[SetCA] = lambda: OpKind.__setca_pre_ra_sim
+
+ @staticmethod
+ def __svadde_pre_ra_sim(op, state):
+ # type: (Op, PreRASimState) -> None
+ RA = state.ssa_vals[op.inputs[0]]
+ RB = state.ssa_vals[op.inputs[1]]
+ carry, = state.ssa_vals[op.inputs[2]]
+ VL, = state.ssa_vals[op.inputs[3]]
+ RT = [] # type: list[int]
+ for i in range(VL):
+ v = RA[i] + RB[i] + carry
+ RT.append(v & GPR_VALUE_MASK)
+ carry = (v >> GPR_SIZE_IN_BITS) != 0
+ state.ssa_vals[op.outputs[0]] = tuple(RT)
+ state.ssa_vals[op.outputs[1]] = carry,
SvAddE = GenericOpProperties(
demo_asm="sv.adde *RT, *RA, *RB",
- inputs=(OD_EXTRA3_VGPR, OD_EXTRA3_VGPR, OD_CA, OD_VL),
- outputs=(OD_EXTRA3_VGPR, OD_CA),
+ inputs=[OD_EXTRA3_VGPR, OD_EXTRA3_VGPR, OD_CA, OD_VL],
+ outputs=[OD_EXTRA3_VGPR, OD_CA],
)
+ _PRE_RA_SIMS[SvAddE] = lambda: OpKind.__svadde_pre_ra_sim
+
+ @staticmethod
+ def __svsubfe_pre_ra_sim(op, state):
+ # type: (Op, PreRASimState) -> None
+ RA = state.ssa_vals[op.inputs[0]]
+ RB = state.ssa_vals[op.inputs[1]]
+ carry, = state.ssa_vals[op.inputs[2]]
+ VL, = state.ssa_vals[op.inputs[3]]
+ RT = [] # type: list[int]
+ for i in range(VL):
+ v = (~RA[i] & GPR_VALUE_MASK) + RB[i] + carry
+ RT.append(v & GPR_VALUE_MASK)
+ carry = (v >> GPR_SIZE_IN_BITS) != 0
+ state.ssa_vals[op.outputs[0]] = tuple(RT)
+ state.ssa_vals[op.outputs[1]] = carry,
SvSubFE = GenericOpProperties(
demo_asm="sv.subfe *RT, *RA, *RB",
- inputs=(OD_EXTRA3_VGPR, OD_EXTRA3_VGPR, OD_CA, OD_VL),
- outputs=(OD_EXTRA3_VGPR, OD_CA),
+ inputs=[OD_EXTRA3_VGPR, OD_EXTRA3_VGPR, OD_CA, OD_VL],
+ outputs=[OD_EXTRA3_VGPR, OD_CA],
)
+ _PRE_RA_SIMS[SvSubFE] = lambda: OpKind.__svsubfe_pre_ra_sim
+
+ @staticmethod
+ def __svmaddedu_pre_ra_sim(op, state):
+ # type: (Op, PreRASimState) -> None
+ RA = state.ssa_vals[op.inputs[0]]
+ RB, = state.ssa_vals[op.inputs[1]]
+ carry, = state.ssa_vals[op.inputs[2]]
+ VL, = state.ssa_vals[op.inputs[3]]
+ RT = [] # type: list[int]
+ for i in range(VL):
+ v = RA[i] * RB + carry
+ RT.append(v & GPR_VALUE_MASK)
+ carry = v >> GPR_SIZE_IN_BITS
+ state.ssa_vals[op.outputs[0]] = tuple(RT)
+ state.ssa_vals[op.outputs[1]] = carry,
SvMAddEDU = GenericOpProperties(
demo_asm="sv.maddedu *RT, *RA, RB, RC",
- inputs=(OD_EXTRA2_VGPR, OD_EXTRA2_VGPR, OD_EXTRA2_SGPR,
- OD_EXTRA2_SGPR, OD_VL),
- outputs=(OD_EXTRA3_VGPR, OD_EXTRA2_SGPR.tied_to_input(3)),
+ inputs=[OD_EXTRA2_VGPR, OD_EXTRA2_SGPR, OD_EXTRA2_SGPR, OD_VL],
+ outputs=[OD_EXTRA3_VGPR, OD_EXTRA2_SGPR.tied_to_input(2)],
)
+ _PRE_RA_SIMS[SvMAddEDU] = lambda: OpKind.__svmaddedu_pre_ra_sim
+
+ @staticmethod
+ def __setvli_pre_ra_sim(op, state):
+ # type: (Op, PreRASimState) -> None
+ state.ssa_vals[op.outputs[0]] = op.immediates[0],
SetVLI = GenericOpProperties(
demo_asm="setvl 0, 0, imm, 0, 1, 1",
inputs=(),
- outputs=(OD_VL,),
- immediates=(range(1, 65),),
+ outputs=[OD_VL],
+ immediates=[range(1, 65)],
is_load_immediate=True,
)
+ _PRE_RA_SIMS[SetVLI] = lambda: OpKind.__setvli_pre_ra_sim
+
+ @staticmethod
+ def __svli_pre_ra_sim(op, state):
+ # type: (Op, PreRASimState) -> None
+ VL, = state.ssa_vals[op.inputs[0]]
+ imm = op.immediates[0] & GPR_VALUE_MASK
+ state.ssa_vals[op.outputs[0]] = (imm,) * VL
SvLI = GenericOpProperties(
demo_asm="sv.addi *RT, 0, imm",
- inputs=(OD_VL,),
- outputs=(OD_EXTRA3_VGPR,),
- immediates=(range(-2 ** 15, 2 ** 15),),
+ inputs=[OD_VL],
+ outputs=[OD_EXTRA3_VGPR],
+ immediates=[IMM_S16],
is_load_immediate=True,
)
+ _PRE_RA_SIMS[SvLI] = lambda: OpKind.__svli_pre_ra_sim
+
+ @staticmethod
+ def __li_pre_ra_sim(op, state):
+ # type: (Op, PreRASimState) -> None
+ imm = op.immediates[0] & GPR_VALUE_MASK
+ state.ssa_vals[op.outputs[0]] = imm,
LI = GenericOpProperties(
demo_asm="addi RT, 0, imm",
inputs=(),
- outputs=(OD_BASE_SGPR,),
- immediates=(range(-2 ** 15, 2 ** 15),),
+ outputs=[OD_BASE_SGPR],
+ immediates=[IMM_S16],
is_load_immediate=True,
)
+ _PRE_RA_SIMS[LI] = lambda: OpKind.__li_pre_ra_sim
+
+ @staticmethod
+ def __veccopytoreg_pre_ra_sim(op, state):
+ # type: (Op, PreRASimState) -> None
+ state.ssa_vals[op.outputs[0]] = state.ssa_vals[op.inputs[0]]
VecCopyToReg = GenericOpProperties(
demo_asm="sv.mv dest, src",
- inputs=(GenericOperandDesc(
+ inputs=[GenericOperandDesc(
ty=GenericTy(BaseTy.I64, is_vec=True),
- sub_kinds=(LocSubKind.SV_EXTRA3_VGPR, LocSubKind.StackI64),
- ), OD_VL),
- outputs=(OD_EXTRA3_VGPR,),
+ sub_kinds=[LocSubKind.SV_EXTRA3_VGPR, LocSubKind.StackI64],
+ ), OD_VL],
+ outputs=[OD_EXTRA3_VGPR],
is_copy=True,
)
+ _PRE_RA_SIMS[VecCopyToReg] = lambda: OpKind.__veccopytoreg_pre_ra_sim
+
+ @staticmethod
+ def __veccopyfromreg_pre_ra_sim(op, state):
+ # type: (Op, PreRASimState) -> None
+ state.ssa_vals[op.outputs[0]] = state.ssa_vals[op.inputs[0]]
VecCopyFromReg = GenericOpProperties(
demo_asm="sv.mv dest, src",
- inputs=(OD_EXTRA3_VGPR, OD_VL),
- outputs=(GenericOperandDesc(
+ inputs=[OD_EXTRA3_VGPR, OD_VL],
+ outputs=[GenericOperandDesc(
ty=GenericTy(BaseTy.I64, is_vec=True),
- sub_kinds=(LocSubKind.SV_EXTRA3_VGPR, LocSubKind.StackI64),
- ),),
+ sub_kinds=[LocSubKind.SV_EXTRA3_VGPR, LocSubKind.StackI64],
+ )],
is_copy=True,
)
+ _PRE_RA_SIMS[VecCopyFromReg] = lambda: OpKind.__veccopyfromreg_pre_ra_sim
+
+ @staticmethod
+ def __copytoreg_pre_ra_sim(op, state):
+ # type: (Op, PreRASimState) -> None
+ state.ssa_vals[op.outputs[0]] = state.ssa_vals[op.inputs[0]]
CopyToReg = GenericOpProperties(
demo_asm="mv dest, src",
- inputs=(GenericOperandDesc(
+ inputs=[GenericOperandDesc(
ty=GenericTy(BaseTy.I64, is_vec=False),
- sub_kinds=(LocSubKind.SV_EXTRA3_SGPR, LocSubKind.BASE_GPR,
- LocSubKind.StackI64),
- ),),
- outputs=(GenericOperandDesc(
+ sub_kinds=[LocSubKind.SV_EXTRA3_SGPR, LocSubKind.BASE_GPR,
+ LocSubKind.StackI64],
+ )],
+ outputs=[GenericOperandDesc(
ty=GenericTy(BaseTy.I64, is_vec=False),
- sub_kinds=(LocSubKind.SV_EXTRA3_SGPR, LocSubKind.BASE_GPR),
- ),),
+ sub_kinds=[LocSubKind.SV_EXTRA3_SGPR, LocSubKind.BASE_GPR],
+ )],
is_copy=True,
)
+ _PRE_RA_SIMS[CopyToReg] = lambda: OpKind.__copytoreg_pre_ra_sim
+
+ @staticmethod
+ def __copyfromreg_pre_ra_sim(op, state):
+ # type: (Op, PreRASimState) -> None
+ state.ssa_vals[op.outputs[0]] = state.ssa_vals[op.inputs[0]]
CopyFromReg = GenericOpProperties(
demo_asm="mv dest, src",
- inputs=(GenericOperandDesc(
+ inputs=[GenericOperandDesc(
ty=GenericTy(BaseTy.I64, is_vec=False),
- sub_kinds=(LocSubKind.SV_EXTRA3_SGPR, LocSubKind.BASE_GPR),
- ),),
- outputs=(GenericOperandDesc(
+ sub_kinds=[LocSubKind.SV_EXTRA3_SGPR, LocSubKind.BASE_GPR],
+ )],
+ outputs=[GenericOperandDesc(
ty=GenericTy(BaseTy.I64, is_vec=False),
- sub_kinds=(LocSubKind.SV_EXTRA3_SGPR, LocSubKind.BASE_GPR,
- LocSubKind.StackI64),
- ),),
+ sub_kinds=[LocSubKind.SV_EXTRA3_SGPR, LocSubKind.BASE_GPR,
+ LocSubKind.StackI64],
+ )],
is_copy=True,
)
+ _PRE_RA_SIMS[CopyFromReg] = lambda: OpKind.__copyfromreg_pre_ra_sim
+
+ @staticmethod
+ def __concat_pre_ra_sim(op, state):
+ # type: (Op, PreRASimState) -> None
+ state.ssa_vals[op.outputs[0]] = tuple(
+ state.ssa_vals[i][0] for i in op.inputs[:-1])
Concat = GenericOpProperties(
demo_asm="sv.mv dest, src",
- inputs=(GenericOperandDesc(
+ inputs=[GenericOperandDesc(
ty=GenericTy(BaseTy.I64, is_vec=False),
- sub_kinds=(LocSubKind.SV_EXTRA3_VGPR,),
+ sub_kinds=[LocSubKind.SV_EXTRA3_VGPR],
spread=True,
- ), OD_VL),
- outputs=(OD_EXTRA3_VGPR,),
+ ), OD_VL],
+ outputs=[OD_EXTRA3_VGPR],
is_copy=True,
)
+ _PRE_RA_SIMS[Concat] = lambda: OpKind.__concat_pre_ra_sim
+
+ @staticmethod
+ def __spread_pre_ra_sim(op, state):
+ # type: (Op, PreRASimState) -> None
+ for idx, inp in enumerate(state.ssa_vals[op.inputs[0]]):
+ state.ssa_vals[op.outputs[idx]] = inp,
Spread = GenericOpProperties(
demo_asm="sv.mv dest, src",
- inputs=(OD_EXTRA3_VGPR, OD_VL),
- outputs=(GenericOperandDesc(
+ inputs=[OD_EXTRA3_VGPR, OD_VL],
+ outputs=[GenericOperandDesc(
ty=GenericTy(BaseTy.I64, is_vec=False),
- sub_kinds=(LocSubKind.SV_EXTRA3_VGPR,),
+ sub_kinds=[LocSubKind.SV_EXTRA3_VGPR],
spread=True,
- ),),
+ )],
is_copy=True,
)
+ _PRE_RA_SIMS[Spread] = lambda: OpKind.__spread_pre_ra_sim
+
+ @staticmethod
+ def __svld_pre_ra_sim(op, state):
+ # type: (Op, PreRASimState) -> None
+ RA, = state.ssa_vals[op.inputs[0]]
+ VL, = state.ssa_vals[op.inputs[1]]
+ addr = RA + op.immediates[0]
+ RT = [] # type: list[int]
+ for i in range(VL):
+ v = state.load(addr + GPR_SIZE_IN_BYTES * i)
+ RT.append(v & GPR_VALUE_MASK)
+ state.ssa_vals[op.outputs[0]] = tuple(RT)
+ SvLd = GenericOpProperties(
+ demo_asm="sv.ld *RT, imm(RA)",
+ inputs=[OD_EXTRA3_SGPR, OD_VL],
+ outputs=[OD_EXTRA3_VGPR],
+ immediates=[IMM_S16],
+ )
+ _PRE_RA_SIMS[SvLd] = lambda: OpKind.__svld_pre_ra_sim
+
+ @staticmethod
+ def __ld_pre_ra_sim(op, state):
+ # type: (Op, PreRASimState) -> None
+ RA, = state.ssa_vals[op.inputs[0]]
+ addr = RA + op.immediates[0]
+ v = state.load(addr)
+ state.ssa_vals[op.outputs[0]] = v & GPR_VALUE_MASK,
+ Ld = GenericOpProperties(
+ demo_asm="ld RT, imm(RA)",
+ inputs=[OD_BASE_SGPR],
+ outputs=[OD_BASE_SGPR],
+ immediates=[IMM_S16],
+ )
+ _PRE_RA_SIMS[Ld] = lambda: OpKind.__ld_pre_ra_sim
+
+ @staticmethod
+ def __svstd_pre_ra_sim(op, state):
+ # type: (Op, PreRASimState) -> None
+ RS = state.ssa_vals[op.inputs[0]]
+ RA, = state.ssa_vals[op.inputs[1]]
+ VL, = state.ssa_vals[op.inputs[2]]
+ addr = RA + op.immediates[0]
+ for i in range(VL):
+ state.store(addr + GPR_SIZE_IN_BYTES * i, value=RS[i])
+ SvStd = GenericOpProperties(
+ demo_asm="sv.std *RS, imm(RA)",
+ inputs=[OD_EXTRA3_VGPR, OD_EXTRA3_SGPR, OD_VL],
+ outputs=[],
+ immediates=[IMM_S16],
+ has_side_effects=True,
+ )
+ _PRE_RA_SIMS[SvStd] = lambda: OpKind.__svstd_pre_ra_sim
+
+ @staticmethod
+ def __std_pre_ra_sim(op, state):
+ # type: (Op, PreRASimState) -> None
+ RS, = state.ssa_vals[op.inputs[0]]
+ RA, = state.ssa_vals[op.inputs[1]]
+ addr = RA + op.immediates[0]
+ state.store(addr, value=RS)
+ Std = GenericOpProperties(
+ demo_asm="std RT, imm(RA)",
+ inputs=[OD_BASE_SGPR, OD_BASE_SGPR],
+ outputs=[],
+ immediates=[IMM_S16],
+ has_side_effects=True,
+ )
+ _PRE_RA_SIMS[Std] = lambda: OpKind.__std_pre_ra_sim
+
+ @staticmethod
+ def __funcargr3_pre_ra_sim(op, state):
+ # type: (Op, PreRASimState) -> None
+ pass # return value set before simulation
+ FuncArgR3 = GenericOpProperties(
+ demo_asm="",
+ inputs=[],
+ outputs=[OD_BASE_SGPR.with_fixed_loc(
+ Loc(kind=LocKind.GPR, start=3, reg_len=1))],
+ )
+ _PRE_RA_SIMS[FuncArgR3] = lambda: OpKind.__funcargr3_pre_ra_sim
@plain_data(frozen=True, unsafe_hash=True, repr=False)
# type: () -> int
return len(self.__items)
+ def __repr__(self):
+ return f"{self.__class__.__name__}({self.__items}, op=...)"
+
@final
class OpInputs(OpInputSeq[SSAVal, OperandDesc]):
def __hash__(self):
return object.__hash__(self)
+
+ def pre_ra_sim(self, state):
+ # type: (PreRASimState) -> None
+ for inp in self.inputs:
+ if inp not in state.ssa_vals:
+ raise ValueError(f"SSAVal {inp} not yet assigned when "
+ f"running {self}")
+ if len(state.ssa_vals[inp]) != inp.ty.reg_len:
+ raise ValueError(
+ f"value of SSAVal {inp} has wrong number of elements: "
+ f"expected {inp.ty.reg_len} found "
+ f"{len(state.ssa_vals[inp])}: {state.ssa_vals[inp]!r}")
+ for out in self.outputs:
+ if out in state.ssa_vals:
+ if self.kind is OpKind.FuncArgR3:
+ continue
+ raise ValueError(f"SSAVal {out} already assigned before "
+ f"running {self}")
+ self.kind.pre_ra_sim(self, state)
+ for out in self.outputs:
+ if out not in state.ssa_vals:
+ raise ValueError(f"running {self} failed to assign to {out}")
+ if len(state.ssa_vals[out]) != out.ty.reg_len:
+ raise ValueError(
+ f"value of SSAVal {out} has wrong number of elements: "
+ f"expected {out.ty.reg_len} found "
+ f"{len(state.ssa_vals[out])}: {state.ssa_vals[out]!r}")
+
+
+GPR_SIZE_IN_BYTES = 8
+BITS_IN_BYTE = 8
+GPR_SIZE_IN_BITS = GPR_SIZE_IN_BYTES * BITS_IN_BYTE
+GPR_VALUE_MASK = (1 << GPR_SIZE_IN_BITS) - 1
+
+
+@plain_data(frozen=True, repr=False)
+@final
+class PreRASimState:
+ __slots__ = "ssa_vals", "memory"
+
+ def __init__(self, ssa_vals, memory):
+ # type: (dict[SSAVal, tuple[int, ...]], dict[int, int]) -> None
+ self.ssa_vals = ssa_vals
+ self.memory = memory
+
+ def load_byte(self, addr):
+ # type: (int) -> int
+ addr &= GPR_VALUE_MASK
+ return self.memory.get(addr, 0) & 0xFF
+
+ def store_byte(self, addr, value):
+ # type: (int, int) -> None
+ addr &= GPR_VALUE_MASK
+ value &= 0xFF
+ self.memory[addr] = value
+
+ def load(self, addr, size_in_bytes=GPR_SIZE_IN_BYTES, signed=False):
+ # type: (int, int, bool) -> int
+ if addr % size_in_bytes != 0:
+ raise ValueError(f"address not aligned: {hex(addr)} "
+ f"required alignment: {size_in_bytes}")
+ retval = 0
+ for i in range(size_in_bytes):
+ retval |= self.load_byte(addr + i) << i * BITS_IN_BYTE
+ if signed and retval >> (size_in_bytes * BITS_IN_BYTE - 1) != 0:
+ retval -= 1 << size_in_bytes * BITS_IN_BYTE
+ return retval
+
+ def store(self, addr, value, size_in_bytes=GPR_SIZE_IN_BYTES):
+ # type: (int, int, int) -> None
+ if addr % size_in_bytes != 0:
+ raise ValueError(f"address not aligned: {hex(addr)} "
+ f"required alignment: {size_in_bytes}")
+ for i in range(size_in_bytes):
+ self.store_byte(addr + i, (value >> i * BITS_IN_BYTE) & 0xFF)
+
+ def _memory__repr(self):
+ # type: () -> str
+ if len(self.memory) == 0:
+ return "{}"
+ keys = sorted(self.memory.keys(), reverse=True)
+ CHUNK_SIZE = GPR_SIZE_IN_BYTES
+ items = [] # type: list[str]
+ while len(keys) != 0:
+ addr = keys[-1]
+ if (len(keys) >= CHUNK_SIZE
+ and addr % CHUNK_SIZE == 0
+ and keys[-CHUNK_SIZE:]
+ == list(reversed(range(addr, addr + CHUNK_SIZE)))):
+ value = self.load(addr, size_in_bytes=CHUNK_SIZE)
+ items.append(f"0x{addr:05x}: <0x{value:0{CHUNK_SIZE * 2}x}>")
+ keys[-CHUNK_SIZE:] = ()
+ else:
+ items.append(f"0x{addr:05x}: 0x{self.memory[keys.pop()]:02x}")
+ if len(items) == 1:
+ return f"{{{items[0]}}}"
+ items_str = ",\n".join(items)
+ return f"{{\n{items_str}}}"
+
+ def _ssa_vals__repr(self):
+ # type: () -> str
+ if len(self.ssa_vals) == 0:
+ return "{}"
+ items = [] # type: list[str]
+ CHUNK_SIZE = 4
+ for k, v in self.ssa_vals.items():
+ element_strs = [] # type: list[str]
+ for i, el in enumerate(v):
+ if i % CHUNK_SIZE != 0:
+ element_strs.append(" " + hex(el))
+ else:
+ element_strs.append("\n " + hex(el))
+ if len(element_strs) <= CHUNK_SIZE:
+ element_strs[0] = element_strs[0].lstrip()
+ if len(element_strs) == 1:
+ element_strs.append("")
+ v_str = ",".join(element_strs)
+ items.append(f"{k!r}: ({v_str})")
+ if len(items) == 1 and "\n" not in items[0]:
+ return f"{{{items[0]}}}"
+ items_str = ",\n".join(items)
+ return f"{{\n{items_str},\n}}"
+
+ def __repr__(self):
+ # type: () -> str
+ field_vals = [] # type: list[str]
+ for name in fields(self):
+ try:
+ value = getattr(self, name)
+ except AttributeError:
+ field_vals.append(f"{name}=<not set>")
+ continue
+ repr_fn = getattr(self, f"_{name}__repr", None)
+ if callable(repr_fn):
+ field_vals.append(f"{name}={repr_fn()}")
+ else:
+ field_vals.append(f"{name}={value!r}")
+ field_vals_str = ", ".join(field_vals)
+ return f"PreRASimState({field_vals_str})"