03b623dafbf5f80ebdc96e487088552a42ffe040
2 from abc
import ABCMeta
, abstractmethod
3 from enum
import Enum
, unique
4 from functools
import lru_cache
5 from typing
import (AbstractSet
, Any
, Callable
, Generic
, Iterable
, Iterator
,
6 Sequence
, TypeVar
, overload
)
7 from weakref
import WeakValueDictionary
as _WeakVDict
9 from cached_property
import cached_property
10 from nmutil
.plain_data
import fields
, plain_data
12 from bigint_presentation_code
.type_util
import Self
, assert_never
, final
13 from bigint_presentation_code
.util
import BitSet
, FBitSet
, FMap
, OFSet
, OSet
19 self
.ops
= [] # type: list[Op]
20 self
.__op
_names
= _WeakVDict() # type: _WeakVDict[str, Op]
21 self
.__next
_name
_suffix
= 2
23 def _add_op_with_unused_name(self
, op
, name
=""):
24 # type: (Op, str) -> str
26 raise ValueError("can't add Op to wrong Fn")
27 if hasattr(op
, "name"):
28 raise ValueError("Op already named")
31 if name
!= "" and name
not in self
.__op
_names
:
32 self
.__op
_names
[name
] = op
34 name
= orig_name
+ str(self
.__next
_name
_suffix
)
35 self
.__next
_name
_suffix
+= 1
41 def append_op(self
, op
):
44 raise ValueError("can't add Op to wrong Fn")
47 def append_new_op(self
, kind
, input_vals
=(), immediates
=(), name
="",
49 # type: (OpKind, Iterable[SSAVal], Iterable[int], str, int) -> Op
50 retval
= Op(fn
=self
, properties
=kind
.instantiate(maxvl
=maxvl
),
51 input_vals
=input_vals
, immediates
=immediates
, name
=name
)
52 self
.append_op(retval
)
55 def pre_ra_sim(self
, state
):
56 # type: (PreRASimState) -> None
60 def pre_ra_insert_copies(self
):
62 orig_ops
= list(self
.ops
)
63 copied_outputs
= {} # type: dict[SSAVal, SSAVal]
66 for i
in range(len(op
.input_vals
)):
67 inp
= copied_outputs
[op
.input_vals
[i
]]
68 if inp
.ty
.base_ty
is BaseTy
.I64
:
69 maxvl
= inp
.ty
.reg_len
70 if inp
.ty
.reg_len
!= 1:
71 setvl
= self
.append_new_op(
72 OpKind
.SetVLI
, immediates
=[maxvl
],
73 name
=f
"{op.name}.inp{i}.setvl")
75 mv
= self
.append_new_op(
76 OpKind
.VecCopyToReg
, input_vals
=[inp
, vl
],
77 maxvl
=maxvl
, name
=f
"{op.name}.inp{i}.copy")
79 mv
= self
.append_new_op(
80 OpKind
.CopyToReg
, input_vals
=[inp
],
81 name
=f
"{op.name}.inp{i}.copy")
82 op
.input_vals
[i
] = mv
.outputs
[0]
83 elif inp
.ty
.base_ty
is BaseTy
.CA \
84 or inp
.ty
.base_ty
is BaseTy
.VL_MAXVL
:
85 # all copies would be no-ops, so we don't need to copy
86 op
.input_vals
[i
] = inp
88 assert_never(inp
.ty
.base_ty
)
90 for i
, out
in enumerate(op
.outputs
):
91 if out
.ty
.base_ty
is BaseTy
.I64
:
92 maxvl
= out
.ty
.reg_len
93 if out
.ty
.reg_len
!= 1:
94 setvl
= self
.append_new_op(
95 OpKind
.SetVLI
, immediates
=[maxvl
],
96 name
=f
"{op.name}.out{i}.setvl")
98 mv
= self
.append_new_op(
99 OpKind
.VecCopyFromReg
, input_vals
=[out
, vl
],
100 maxvl
=maxvl
, name
=f
"{op.name}.out{i}.copy")
102 mv
= self
.append_new_op(
103 OpKind
.CopyFromReg
, input_vals
=[out
],
104 name
=f
"{op.name}.out{i}.copy")
105 copied_outputs
[out
] = mv
.outputs
[0]
106 elif out
.ty
.base_ty
is BaseTy
.CA \
107 or out
.ty
.base_ty
is BaseTy
.VL_MAXVL
:
108 # all copies would be no-ops, so we don't need to copy
109 copied_outputs
[out
] = out
111 assert_never(out
.ty
.base_ty
)
114 @plain_data(frozen
=True, eq
=False)
117 __slots__
= "fn", "uses"
119 def __init__(self
, fn
):
122 retval
= {} # type: dict[SSAVal, OSet[SSAUse]]
124 for idx
, inp
in enumerate(op
.input_vals
):
125 retval
[inp
].add(SSAUse(op
, idx
))
126 for out
in op
.outputs
:
128 self
.uses
= FMap((k
, OFSet(v
)) for k
, v
in retval
.items())
130 def __eq__(self
, other
):
131 # type: (FnWithUses | Any) -> bool
132 if isinstance(other
, FnWithUses
):
133 return self
.fn
== other
.fn
134 return NotImplemented
146 VL_MAXVL
= enum
.auto()
149 def only_scalar(self
):
151 if self
is BaseTy
.I64
:
153 elif self
is BaseTy
.CA
or self
is BaseTy
.VL_MAXVL
:
159 def max_reg_len(self
):
161 if self
is BaseTy
.I64
:
163 elif self
is BaseTy
.CA
or self
is BaseTy
.VL_MAXVL
:
169 return "BaseTy." + self
._name
_
172 @plain_data(frozen
=True, unsafe_hash
=True, repr=False)
175 __slots__
= "base_ty", "reg_len"
178 def validate(base_ty
, reg_len
):
179 # type: (BaseTy, int) -> str | None
180 """ return a string with the error if the combination is invalid,
181 otherwise return None
183 if base_ty
.only_scalar
and reg_len
!= 1:
184 return f
"can't create a vector of an only-scalar type: {base_ty}"
185 if reg_len
< 1 or reg_len
> base_ty
.max_reg_len
:
186 return "reg_len out of range"
189 def __init__(self
, base_ty
, reg_len
):
190 # type: (BaseTy, int) -> None
191 msg
= self
.validate(base_ty
=base_ty
, reg_len
=reg_len
)
193 raise ValueError(msg
)
194 self
.base_ty
= base_ty
195 self
.reg_len
= reg_len
199 if self
.reg_len
!= 1:
200 reg_len
= f
"*{self.reg_len}"
203 return f
"<{self.base_ty._name_}{reg_len}>"
210 StackI64
= enum
.auto()
212 VL_MAXVL
= enum
.auto()
217 if self
is LocKind
.GPR
or self
is LocKind
.StackI64
:
219 if self
is LocKind
.CA
:
221 if self
is LocKind
.VL_MAXVL
:
222 return BaseTy
.VL_MAXVL
229 if self
is LocKind
.StackI64
:
231 if self
is LocKind
.GPR
or self
is LocKind
.CA \
232 or self
is LocKind
.VL_MAXVL
:
233 return self
.base_ty
.max_reg_len
238 return "LocKind." + self
._name
_
243 class LocSubKind(Enum
):
244 BASE_GPR
= enum
.auto()
245 SV_EXTRA2_VGPR
= enum
.auto()
246 SV_EXTRA2_SGPR
= enum
.auto()
247 SV_EXTRA3_VGPR
= enum
.auto()
248 SV_EXTRA3_SGPR
= enum
.auto()
249 StackI64
= enum
.auto()
251 VL_MAXVL
= enum
.auto()
255 # type: () -> LocKind
256 # pyright fails typechecking when using `in` here:
257 # reported: https://github.com/microsoft/pyright/issues/4102
258 if self
is LocSubKind
.BASE_GPR
or self
is LocSubKind
.SV_EXTRA2_VGPR \
259 or self
is LocSubKind
.SV_EXTRA2_SGPR \
260 or self
is LocSubKind
.SV_EXTRA3_VGPR \
261 or self
is LocSubKind
.SV_EXTRA3_SGPR
:
263 if self
is LocSubKind
.StackI64
:
264 return LocKind
.StackI64
265 if self
is LocSubKind
.CA
:
267 if self
is LocSubKind
.VL_MAXVL
:
268 return LocKind
.VL_MAXVL
273 return self
.kind
.base_ty
276 def allocatable_locs(self
, ty
):
277 # type: (Ty) -> LocSet
278 if ty
.base_ty
!= self
.base_ty
:
279 raise ValueError("type mismatch")
280 if self
is LocSubKind
.BASE_GPR
:
282 elif self
is LocSubKind
.SV_EXTRA2_VGPR
:
283 starts
= range(0, 128, 2)
284 elif self
is LocSubKind
.SV_EXTRA2_SGPR
:
286 elif self
is LocSubKind
.SV_EXTRA3_VGPR \
287 or self
is LocSubKind
.SV_EXTRA3_SGPR
:
289 elif self
is LocSubKind
.StackI64
:
290 starts
= range(LocKind
.StackI64
.loc_count
)
291 elif self
is LocSubKind
.CA
or self
is LocSubKind
.VL_MAXVL
:
292 return LocSet([Loc(kind
=self
.kind
, start
=0, reg_len
=1)])
295 retval
= [] # type: list[Loc]
297 loc
= Loc
.try_make(kind
=self
.kind
, start
=start
, reg_len
=ty
.reg_len
)
301 for special_loc
in SPECIAL_GPRS
:
302 if loc
.conflicts(special_loc
):
307 return LocSet(retval
)
310 return "LocSubKind." + self
._name
_
313 @plain_data(frozen
=True, unsafe_hash
=True)
316 __slots__
= "base_ty", "is_vec"
318 def __init__(self
, base_ty
, is_vec
):
319 # type: (BaseTy, bool) -> None
320 self
.base_ty
= base_ty
321 if base_ty
.only_scalar
and is_vec
:
322 raise ValueError(f
"base_ty={base_ty} requires is_vec=False")
325 def instantiate(self
, maxvl
):
327 # here's where subvl and elwid would be accounted for
329 return Ty(self
.base_ty
, maxvl
)
330 return Ty(self
.base_ty
, 1)
332 def can_instantiate_to(self
, ty
):
334 if self
.base_ty
!= ty
.base_ty
:
338 return ty
.reg_len
== 1
341 @plain_data(frozen
=True, unsafe_hash
=True)
344 __slots__
= "kind", "start", "reg_len"
347 def validate(kind
, start
, reg_len
):
348 # type: (LocKind, int, int) -> str | None
349 msg
= Ty
.validate(base_ty
=kind
.base_ty
, reg_len
=reg_len
)
352 if reg_len
> kind
.loc_count
:
353 return "invalid reg_len"
354 if start
< 0 or start
+ reg_len
> kind
.loc_count
:
355 return "start not in valid range"
359 def try_make(kind
, start
, reg_len
):
360 # type: (LocKind, int, int) -> Loc | None
361 msg
= Loc
.validate(kind
=kind
, start
=start
, reg_len
=reg_len
)
364 return Loc(kind
=kind
, start
=start
, reg_len
=reg_len
)
366 def __init__(self
, kind
, start
, reg_len
):
367 # type: (LocKind, int, int) -> None
368 msg
= self
.validate(kind
=kind
, start
=start
, reg_len
=reg_len
)
370 raise ValueError(msg
)
372 self
.reg_len
= reg_len
375 def conflicts(self
, other
):
376 # type: (Loc) -> bool
377 return (self
.kind
== other
.kind
378 and self
.start
< other
.stop
and other
.start
< self
.stop
)
381 def make_ty(kind
, reg_len
):
382 # type: (LocKind, int) -> Ty
383 return Ty(base_ty
=kind
.base_ty
, reg_len
=reg_len
)
388 return self
.make_ty(kind
=self
.kind
, reg_len
=self
.reg_len
)
393 return self
.start
+ self
.reg_len
395 def try_concat(self
, *others
):
396 # type: (*Loc | None) -> Loc | None
397 reg_len
= self
.reg_len
400 if other
is None or other
.kind
!= self
.kind
:
402 if stop
!= other
.start
:
405 reg_len
+= other
.reg_len
406 return Loc(kind
=self
.kind
, start
=self
.start
, reg_len
=reg_len
)
410 Loc(kind
=LocKind
.GPR
, start
=0, reg_len
=1),
411 Loc(kind
=LocKind
.GPR
, start
=1, reg_len
=1),
412 Loc(kind
=LocKind
.GPR
, start
=2, reg_len
=1),
413 Loc(kind
=LocKind
.GPR
, start
=13, reg_len
=1),
417 @plain_data(frozen
=True, eq
=False)
419 class LocSet(AbstractSet
[Loc
]):
420 __slots__
= "starts", "ty"
422 def __init__(self
, __locs
=()):
423 # type: (Iterable[Loc]) -> None
424 if isinstance(__locs
, LocSet
):
425 self
.starts
= __locs
.starts
# type: FMap[LocKind, FBitSet]
426 self
.ty
= __locs
.ty
# type: Ty | None
428 starts
= {i
: BitSet() for i
in LocKind
}
434 raise ValueError(f
"conflicting types: {ty} != {loc.ty}")
435 starts
[loc
.kind
].add(loc
.start
)
437 (k
, FBitSet(v
)) for k
, v
in starts
.items() if len(v
) != 0)
442 # type: () -> FMap[LocKind, FBitSet]
447 (k
, FBitSet(bits
=v
.bits
<< sh
)) for k
, v
in self
.starts
.items())
451 # type: () -> AbstractSet[LocKind]
452 return self
.starts
.keys()
456 # type: () -> int | None
459 return self
.ty
.reg_len
463 # type: () -> BaseTy | None
466 return self
.ty
.base_ty
468 def concat(self
, *others
):
469 # type: (*LocSet) -> LocSet
472 base_ty
= self
.ty
.base_ty
473 reg_len
= self
.ty
.reg_len
474 starts
= {k
: BitSet(v
) for k
, v
in self
.starts
.items()}
478 if other
.ty
.base_ty
!= base_ty
:
480 for kind
, other_starts
in other
.starts
.items():
481 if kind
not in starts
:
483 starts
[kind
].bits
&= other_starts
.bits
>> reg_len
484 if starts
[kind
] == 0:
488 reg_len
+= other
.ty
.reg_len
491 # type: () -> Iterable[Loc]
492 for kind
, v
in starts
.items():
494 loc
= Loc
.try_make(kind
=kind
, start
=start
, reg_len
=reg_len
)
497 return LocSet(locs())
499 def __contains__(self
, loc
):
500 # type: (Loc | Any) -> bool
501 if not isinstance(loc
, Loc
) or loc
.ty
!= self
.ty
:
503 if loc
.kind
not in self
.starts
:
505 return loc
.start
in self
.starts
[loc
.kind
]
508 # type: () -> Iterator[Loc]
511 for kind
, starts
in self
.starts
.items():
513 yield Loc(kind
=kind
, start
=start
, reg_len
=self
.ty
.reg_len
)
517 return sum((len(v
) for v
in self
.starts
.values()), 0)
524 return super()._hash
()
530 @plain_data(frozen
=True, unsafe_hash
=True)
532 class GenericOperandDesc
:
533 """generic Op operand descriptor"""
534 __slots__
= "ty", "fixed_loc", "sub_kinds", "tied_input_index", "spread"
537 self
, ty
, # type: GenericTy
538 sub_kinds
, # type: Iterable[LocSubKind]
540 fixed_loc
=None, # type: Loc | None
541 tied_input_index
=None, # type: int | None
542 spread
=False, # type: bool
544 # type: (...) -> None
546 self
.sub_kinds
= OFSet(sub_kinds
)
547 if len(self
.sub_kinds
) == 0:
548 raise ValueError("sub_kinds can't be empty")
549 self
.fixed_loc
= fixed_loc
550 if fixed_loc
is not None:
551 if tied_input_index
is not None:
552 raise ValueError("operand can't be both tied and fixed")
553 if not ty
.can_instantiate_to(fixed_loc
.ty
):
555 f
"fixed_loc has incompatible type for given generic "
556 f
"type: fixed_loc={fixed_loc} generic ty={ty}")
557 if len(self
.sub_kinds
) != 1:
559 "multiple sub_kinds not allowed for fixed operand")
560 for sub_kind
in self
.sub_kinds
:
561 if fixed_loc
not in sub_kind
.allocatable_locs(fixed_loc
.ty
):
563 f
"fixed_loc not in given sub_kind: "
564 f
"fixed_loc={fixed_loc} sub_kind={sub_kind}")
565 for sub_kind
in self
.sub_kinds
:
566 if sub_kind
.base_ty
!= ty
.base_ty
:
567 raise ValueError(f
"sub_kind is incompatible with type: "
568 f
"sub_kind={sub_kind} ty={ty}")
569 if tied_input_index
is not None and tied_input_index
< 0:
570 raise ValueError("invalid tied_input_index")
571 self
.tied_input_index
= tied_input_index
574 if self
.tied_input_index
is not None:
575 raise ValueError("operand can't be both spread and tied")
576 if self
.fixed_loc
is not None:
577 raise ValueError("operand can't be both spread and fixed")
579 raise ValueError("operand can't be both spread and vector")
581 def tied_to_input(self
, tied_input_index
):
582 # type: (int) -> Self
583 return GenericOperandDesc(self
.ty
, self
.sub_kinds
,
584 tied_input_index
=tied_input_index
)
586 def with_fixed_loc(self
, fixed_loc
):
587 # type: (Loc) -> Self
588 return GenericOperandDesc(self
.ty
, self
.sub_kinds
, fixed_loc
=fixed_loc
)
590 def instantiate(self
, maxvl
):
591 # type: (int) -> Iterable[OperandDesc]
592 # assumes all spread operands have ty.reg_len = 1
597 ty
= self
.ty
.instantiate(maxvl
=maxvl
)
600 # type: () -> Iterable[Loc]
601 if self
.fixed_loc
is not None:
602 if ty
!= self
.fixed_loc
.ty
:
604 f
"instantiation failed: type mismatch with fixed_loc: "
605 f
"instantiated type: {ty} fixed_loc: {self.fixed_loc}")
608 for sub_kind
in self
.sub_kinds
:
609 yield from sub_kind
.allocatable_locs(ty
)
610 loc_set_before_spread
= LocSet(locs())
611 for idx
in range(rep_count
):
614 yield OperandDesc(loc_set_before_spread
=loc_set_before_spread
,
615 tied_input_index
=self
.tied_input_index
,
619 @plain_data(frozen
=True, unsafe_hash
=True)
622 """Op operand descriptor"""
623 __slots__
= "loc_set_before_spread", "tied_input_index", "spread_index"
625 def __init__(self
, loc_set_before_spread
, tied_input_index
, spread_index
):
626 # type: (LocSet, int | None, int | None) -> None
627 if len(loc_set_before_spread
) == 0:
628 raise ValueError("loc_set_before_spread must not be empty")
629 self
.loc_set_before_spread
= loc_set_before_spread
630 self
.tied_input_index
= tied_input_index
631 if self
.tied_input_index
is not None and self
.spread_index
is not None:
632 raise ValueError("operand can't be both spread and tied")
633 self
.spread_index
= spread_index
636 def ty_before_spread(self
):
638 ty
= self
.loc_set_before_spread
.ty
639 assert ty
is not None, (
640 "__init__ checked that the LocSet isn't empty, "
641 "non-empty LocSets should always have ty set")
646 """ Ty after any spread is applied """
647 if self
.spread_index
is not None:
648 # assumes all spread operands have ty.reg_len = 1
649 return Ty(base_ty
=self
.ty_before_spread
.base_ty
, reg_len
=1)
650 return self
.ty_before_spread
653 def reg_offset_in_unspread(self
):
654 """ the number of reg-sized slots in the unspread Loc before self's Loc
656 e.g. if the unspread Loc containing self is:
657 `Loc(kind=LocKind.GPR, start=8, reg_len=4)`
658 and self's Loc is `Loc(kind=LocKind.GPR, start=10, reg_len=1)`
659 then reg_offset_into_unspread == 2 == 10 - 8
661 if self
.spread_index
is None:
663 return self
.spread_index
* self
.ty
.reg_len
666 OD_BASE_SGPR
= GenericOperandDesc(
667 ty
=GenericTy(base_ty
=BaseTy
.I64
, is_vec
=False),
668 sub_kinds
=[LocSubKind
.BASE_GPR
])
669 OD_EXTRA3_SGPR
= GenericOperandDesc(
670 ty
=GenericTy(base_ty
=BaseTy
.I64
, is_vec
=False),
671 sub_kinds
=[LocSubKind
.SV_EXTRA3_SGPR
])
672 OD_EXTRA3_VGPR
= GenericOperandDesc(
673 ty
=GenericTy(base_ty
=BaseTy
.I64
, is_vec
=True),
674 sub_kinds
=[LocSubKind
.SV_EXTRA3_VGPR
])
675 OD_EXTRA2_SGPR
= GenericOperandDesc(
676 ty
=GenericTy(base_ty
=BaseTy
.I64
, is_vec
=False),
677 sub_kinds
=[LocSubKind
.SV_EXTRA2_SGPR
])
678 OD_EXTRA2_VGPR
= GenericOperandDesc(
679 ty
=GenericTy(base_ty
=BaseTy
.I64
, is_vec
=True),
680 sub_kinds
=[LocSubKind
.SV_EXTRA2_VGPR
])
681 OD_CA
= GenericOperandDesc(
682 ty
=GenericTy(base_ty
=BaseTy
.CA
, is_vec
=False),
683 sub_kinds
=[LocSubKind
.CA
])
684 OD_VL
= GenericOperandDesc(
685 ty
=GenericTy(base_ty
=BaseTy
.VL_MAXVL
, is_vec
=False),
686 sub_kinds
=[LocSubKind
.VL_MAXVL
])
689 @plain_data(frozen
=True, unsafe_hash
=True)
691 class GenericOpProperties
:
692 __slots__
= ("demo_asm", "inputs", "outputs", "immediates",
693 "is_copy", "is_load_immediate", "has_side_effects")
696 self
, demo_asm
, # type: str
697 inputs
, # type: Iterable[GenericOperandDesc]
698 outputs
, # type: Iterable[GenericOperandDesc]
699 immediates
=(), # type: Iterable[range]
700 is_copy
=False, # type: bool
701 is_load_immediate
=False, # type: bool
702 has_side_effects
=False, # type: bool
704 # type: (...) -> None
705 self
.demo_asm
= demo_asm
706 self
.inputs
= tuple(inputs
)
707 for inp
in self
.inputs
:
708 if inp
.tied_input_index
is not None:
710 f
"tied_input_index is not allowed on inputs: {inp}")
711 self
.outputs
= tuple(outputs
)
712 fixed_locs
= [] # type: list[tuple[Loc, int]]
713 for idx
, out
in enumerate(self
.outputs
):
714 if out
.tied_input_index
is not None:
715 if out
.tied_input_index
>= len(self
.inputs
):
716 raise ValueError(f
"tied_input_index out of range: {out}")
717 tied_inp
= self
.inputs
[out
.tied_input_index
]
718 if tied_inp
.tied_to_input(out
.tied_input_index
) != out
:
719 raise ValueError(f
"output can't be tied to non-equivalent "
720 f
"input: {out} tied to {tied_inp}")
721 if out
.fixed_loc
is not None:
722 for other_fixed_loc
, other_idx
in fixed_locs
:
723 if not other_fixed_loc
.conflicts(out
.fixed_loc
):
726 f
"conflicting fixed_locs: outputs[{idx}] and "
727 f
"outputs[{other_idx}]: {out.fixed_loc} conflicts "
728 f
"with {other_fixed_loc}")
729 fixed_locs
.append((out
.fixed_loc
, idx
))
730 self
.immediates
= tuple(immediates
)
731 self
.is_copy
= is_copy
732 self
.is_load_immediate
= is_load_immediate
733 self
.has_side_effects
= has_side_effects
736 @plain_data(frozen
=True, unsafe_hash
=True)
739 __slots__
= "kind", "inputs", "outputs", "maxvl"
741 def __init__(self
, kind
, maxvl
):
742 # type: (OpKind, int) -> None
744 inputs
= [] # type: list[OperandDesc]
745 for inp
in self
.generic
.inputs
:
746 inputs
.extend(inp
.instantiate(maxvl
=maxvl
))
747 self
.inputs
= tuple(inputs
)
748 outputs
= [] # type: list[OperandDesc]
749 for out
in self
.generic
.outputs
:
750 outputs
.extend(out
.instantiate(maxvl
=maxvl
))
751 self
.outputs
= tuple(outputs
)
756 # type: () -> GenericOpProperties
757 return self
.kind
.properties
760 def immediates(self
):
761 # type: () -> tuple[range, ...]
762 return self
.generic
.immediates
767 return self
.generic
.demo_asm
772 return self
.generic
.is_copy
775 def is_load_immediate(self
):
777 return self
.generic
.is_load_immediate
780 def has_side_effects(self
):
782 return self
.generic
.has_side_effects
785 IMM_S16
= range(-1 << 15, 1 << 15)
787 _PRE_RA_SIM_FN
= Callable
[["Op", "PreRASimState"], None]
788 _PRE_RA_SIM_FN2
= Callable
[[], _PRE_RA_SIM_FN
]
789 _PRE_RA_SIMS
= {} # type: dict[GenericOpProperties | Any, _PRE_RA_SIM_FN2]
795 def __init__(self
, properties
):
796 # type: (GenericOpProperties) -> None
798 self
.__properties
= properties
801 def properties(self
):
802 # type: () -> GenericOpProperties
803 return self
.__properties
805 def instantiate(self
, maxvl
):
806 # type: (int) -> OpProperties
807 return OpProperties(self
, maxvl
=maxvl
)
810 return "OpKind." + self
._name
_
813 def pre_ra_sim(self
):
814 # type: () -> _PRE_RA_SIM_FN
815 return _PRE_RA_SIMS
[self
.properties
]()
818 def __clearca_pre_ra_sim(op
, state
):
819 # type: (Op, PreRASimState) -> None
820 state
.ssa_vals
[op
.outputs
[0]] = False,
821 ClearCA
= GenericOpProperties(
822 demo_asm
="addic 0, 0, 0",
826 _PRE_RA_SIMS
[ClearCA
] = lambda: OpKind
.__clearca
_pre
_ra
_sim
829 def __setca_pre_ra_sim(op
, state
):
830 # type: (Op, PreRASimState) -> None
831 state
.ssa_vals
[op
.outputs
[0]] = True,
832 SetCA
= GenericOpProperties(
833 demo_asm
="subfc 0, 0, 0",
837 _PRE_RA_SIMS
[SetCA
] = lambda: OpKind
.__setca
_pre
_ra
_sim
840 def __svadde_pre_ra_sim(op
, state
):
841 # type: (Op, PreRASimState) -> None
842 RA
= state
.ssa_vals
[op
.input_vals
[0]]
843 RB
= state
.ssa_vals
[op
.input_vals
[1]]
844 carry
, = state
.ssa_vals
[op
.input_vals
[2]]
845 VL
, = state
.ssa_vals
[op
.input_vals
[3]]
846 RT
= [] # type: list[int]
848 v
= RA
[i
] + RB
[i
] + carry
849 RT
.append(v
& GPR_VALUE_MASK
)
850 carry
= (v
>> GPR_SIZE_IN_BITS
) != 0
851 state
.ssa_vals
[op
.outputs
[0]] = tuple(RT
)
852 state
.ssa_vals
[op
.outputs
[1]] = carry
,
853 SvAddE
= GenericOpProperties(
854 demo_asm
="sv.adde *RT, *RA, *RB",
855 inputs
=[OD_EXTRA3_VGPR
, OD_EXTRA3_VGPR
, OD_CA
, OD_VL
],
856 outputs
=[OD_EXTRA3_VGPR
, OD_CA
],
858 _PRE_RA_SIMS
[SvAddE
] = lambda: OpKind
.__svadde
_pre
_ra
_sim
861 def __svsubfe_pre_ra_sim(op
, state
):
862 # type: (Op, PreRASimState) -> None
863 RA
= state
.ssa_vals
[op
.input_vals
[0]]
864 RB
= state
.ssa_vals
[op
.input_vals
[1]]
865 carry
, = state
.ssa_vals
[op
.input_vals
[2]]
866 VL
, = state
.ssa_vals
[op
.input_vals
[3]]
867 RT
= [] # type: list[int]
869 v
= (~RA
[i
] & GPR_VALUE_MASK
) + RB
[i
] + carry
870 RT
.append(v
& GPR_VALUE_MASK
)
871 carry
= (v
>> GPR_SIZE_IN_BITS
) != 0
872 state
.ssa_vals
[op
.outputs
[0]] = tuple(RT
)
873 state
.ssa_vals
[op
.outputs
[1]] = carry
,
874 SvSubFE
= GenericOpProperties(
875 demo_asm
="sv.subfe *RT, *RA, *RB",
876 inputs
=[OD_EXTRA3_VGPR
, OD_EXTRA3_VGPR
, OD_CA
, OD_VL
],
877 outputs
=[OD_EXTRA3_VGPR
, OD_CA
],
879 _PRE_RA_SIMS
[SvSubFE
] = lambda: OpKind
.__svsubfe
_pre
_ra
_sim
882 def __svmaddedu_pre_ra_sim(op
, state
):
883 # type: (Op, PreRASimState) -> None
884 RA
= state
.ssa_vals
[op
.input_vals
[0]]
885 RB
, = state
.ssa_vals
[op
.input_vals
[1]]
886 carry
, = state
.ssa_vals
[op
.input_vals
[2]]
887 VL
, = state
.ssa_vals
[op
.input_vals
[3]]
888 RT
= [] # type: list[int]
890 v
= RA
[i
] * RB
+ carry
891 RT
.append(v
& GPR_VALUE_MASK
)
892 carry
= v
>> GPR_SIZE_IN_BITS
893 state
.ssa_vals
[op
.outputs
[0]] = tuple(RT
)
894 state
.ssa_vals
[op
.outputs
[1]] = carry
,
895 SvMAddEDU
= GenericOpProperties(
896 demo_asm
="sv.maddedu *RT, *RA, RB, RC",
897 inputs
=[OD_EXTRA2_VGPR
, OD_EXTRA2_SGPR
, OD_EXTRA2_SGPR
, OD_VL
],
898 outputs
=[OD_EXTRA3_VGPR
, OD_EXTRA2_SGPR
.tied_to_input(2)],
900 _PRE_RA_SIMS
[SvMAddEDU
] = lambda: OpKind
.__svmaddedu
_pre
_ra
_sim
903 def __setvli_pre_ra_sim(op
, state
):
904 # type: (Op, PreRASimState) -> None
905 state
.ssa_vals
[op
.outputs
[0]] = op
.immediates
[0],
906 SetVLI
= GenericOpProperties(
907 demo_asm
="setvl 0, 0, imm, 0, 1, 1",
910 immediates
=[range(1, 65)],
911 is_load_immediate
=True,
913 _PRE_RA_SIMS
[SetVLI
] = lambda: OpKind
.__setvli
_pre
_ra
_sim
916 def __svli_pre_ra_sim(op
, state
):
917 # type: (Op, PreRASimState) -> None
918 VL
, = state
.ssa_vals
[op
.input_vals
[0]]
919 imm
= op
.immediates
[0] & GPR_VALUE_MASK
920 state
.ssa_vals
[op
.outputs
[0]] = (imm
,) * VL
921 SvLI
= GenericOpProperties(
922 demo_asm
="sv.addi *RT, 0, imm",
924 outputs
=[OD_EXTRA3_VGPR
],
925 immediates
=[IMM_S16
],
926 is_load_immediate
=True,
928 _PRE_RA_SIMS
[SvLI
] = lambda: OpKind
.__svli
_pre
_ra
_sim
931 def __li_pre_ra_sim(op
, state
):
932 # type: (Op, PreRASimState) -> None
933 imm
= op
.immediates
[0] & GPR_VALUE_MASK
934 state
.ssa_vals
[op
.outputs
[0]] = imm
,
935 LI
= GenericOpProperties(
936 demo_asm
="addi RT, 0, imm",
938 outputs
=[OD_BASE_SGPR
],
939 immediates
=[IMM_S16
],
940 is_load_immediate
=True,
942 _PRE_RA_SIMS
[LI
] = lambda: OpKind
.__li
_pre
_ra
_sim
945 def __veccopytoreg_pre_ra_sim(op
, state
):
946 # type: (Op, PreRASimState) -> None
947 state
.ssa_vals
[op
.outputs
[0]] = state
.ssa_vals
[op
.input_vals
[0]]
948 VecCopyToReg
= GenericOpProperties(
949 demo_asm
="sv.mv dest, src",
950 inputs
=[GenericOperandDesc(
951 ty
=GenericTy(BaseTy
.I64
, is_vec
=True),
952 sub_kinds
=[LocSubKind
.SV_EXTRA3_VGPR
, LocSubKind
.StackI64
],
954 outputs
=[OD_EXTRA3_VGPR
],
957 _PRE_RA_SIMS
[VecCopyToReg
] = lambda: OpKind
.__veccopytoreg
_pre
_ra
_sim
960 def __veccopyfromreg_pre_ra_sim(op
, state
):
961 # type: (Op, PreRASimState) -> None
962 state
.ssa_vals
[op
.outputs
[0]] = state
.ssa_vals
[op
.input_vals
[0]]
963 VecCopyFromReg
= GenericOpProperties(
964 demo_asm
="sv.mv dest, src",
965 inputs
=[OD_EXTRA3_VGPR
, OD_VL
],
966 outputs
=[GenericOperandDesc(
967 ty
=GenericTy(BaseTy
.I64
, is_vec
=True),
968 sub_kinds
=[LocSubKind
.SV_EXTRA3_VGPR
, LocSubKind
.StackI64
],
972 _PRE_RA_SIMS
[VecCopyFromReg
] = lambda: OpKind
.__veccopyfromreg
_pre
_ra
_sim
975 def __copytoreg_pre_ra_sim(op
, state
):
976 # type: (Op, PreRASimState) -> None
977 state
.ssa_vals
[op
.outputs
[0]] = state
.ssa_vals
[op
.input_vals
[0]]
978 CopyToReg
= GenericOpProperties(
979 demo_asm
="mv dest, src",
980 inputs
=[GenericOperandDesc(
981 ty
=GenericTy(BaseTy
.I64
, is_vec
=False),
982 sub_kinds
=[LocSubKind
.SV_EXTRA3_SGPR
, LocSubKind
.BASE_GPR
,
983 LocSubKind
.StackI64
],
985 outputs
=[GenericOperandDesc(
986 ty
=GenericTy(BaseTy
.I64
, is_vec
=False),
987 sub_kinds
=[LocSubKind
.SV_EXTRA3_SGPR
, LocSubKind
.BASE_GPR
],
991 _PRE_RA_SIMS
[CopyToReg
] = lambda: OpKind
.__copytoreg
_pre
_ra
_sim
994 def __copyfromreg_pre_ra_sim(op
, state
):
995 # type: (Op, PreRASimState) -> None
996 state
.ssa_vals
[op
.outputs
[0]] = state
.ssa_vals
[op
.input_vals
[0]]
997 CopyFromReg
= GenericOpProperties(
998 demo_asm
="mv dest, src",
999 inputs
=[GenericOperandDesc(
1000 ty
=GenericTy(BaseTy
.I64
, is_vec
=False),
1001 sub_kinds
=[LocSubKind
.SV_EXTRA3_SGPR
, LocSubKind
.BASE_GPR
],
1003 outputs
=[GenericOperandDesc(
1004 ty
=GenericTy(BaseTy
.I64
, is_vec
=False),
1005 sub_kinds
=[LocSubKind
.SV_EXTRA3_SGPR
, LocSubKind
.BASE_GPR
,
1006 LocSubKind
.StackI64
],
1010 _PRE_RA_SIMS
[CopyFromReg
] = lambda: OpKind
.__copyfromreg
_pre
_ra
_sim
1013 def __concat_pre_ra_sim(op
, state
):
1014 # type: (Op, PreRASimState) -> None
1015 state
.ssa_vals
[op
.outputs
[0]] = tuple(
1016 state
.ssa_vals
[i
][0] for i
in op
.input_vals
[:-1])
1017 Concat
= GenericOpProperties(
1018 demo_asm
="sv.mv dest, src",
1019 inputs
=[GenericOperandDesc(
1020 ty
=GenericTy(BaseTy
.I64
, is_vec
=False),
1021 sub_kinds
=[LocSubKind
.SV_EXTRA3_VGPR
],
1024 outputs
=[OD_EXTRA3_VGPR
],
1027 _PRE_RA_SIMS
[Concat
] = lambda: OpKind
.__concat
_pre
_ra
_sim
1030 def __spread_pre_ra_sim(op
, state
):
1031 # type: (Op, PreRASimState) -> None
1032 for idx
, inp
in enumerate(state
.ssa_vals
[op
.input_vals
[0]]):
1033 state
.ssa_vals
[op
.outputs
[idx
]] = inp
,
1034 Spread
= GenericOpProperties(
1035 demo_asm
="sv.mv dest, src",
1036 inputs
=[OD_EXTRA3_VGPR
, OD_VL
],
1037 outputs
=[GenericOperandDesc(
1038 ty
=GenericTy(BaseTy
.I64
, is_vec
=False),
1039 sub_kinds
=[LocSubKind
.SV_EXTRA3_VGPR
],
1044 _PRE_RA_SIMS
[Spread
] = lambda: OpKind
.__spread
_pre
_ra
_sim
1047 def __svld_pre_ra_sim(op
, state
):
1048 # type: (Op, PreRASimState) -> None
1049 RA
, = state
.ssa_vals
[op
.input_vals
[0]]
1050 VL
, = state
.ssa_vals
[op
.input_vals
[1]]
1051 addr
= RA
+ op
.immediates
[0]
1052 RT
= [] # type: list[int]
1054 v
= state
.load(addr
+ GPR_SIZE_IN_BYTES
* i
)
1055 RT
.append(v
& GPR_VALUE_MASK
)
1056 state
.ssa_vals
[op
.outputs
[0]] = tuple(RT
)
1057 SvLd
= GenericOpProperties(
1058 demo_asm
="sv.ld *RT, imm(RA)",
1059 inputs
=[OD_EXTRA3_SGPR
, OD_VL
],
1060 outputs
=[OD_EXTRA3_VGPR
],
1061 immediates
=[IMM_S16
],
1063 _PRE_RA_SIMS
[SvLd
] = lambda: OpKind
.__svld
_pre
_ra
_sim
1066 def __ld_pre_ra_sim(op
, state
):
1067 # type: (Op, PreRASimState) -> None
1068 RA
, = state
.ssa_vals
[op
.input_vals
[0]]
1069 addr
= RA
+ op
.immediates
[0]
1070 v
= state
.load(addr
)
1071 state
.ssa_vals
[op
.outputs
[0]] = v
& GPR_VALUE_MASK
,
1072 Ld
= GenericOpProperties(
1073 demo_asm
="ld RT, imm(RA)",
1074 inputs
=[OD_BASE_SGPR
],
1075 outputs
=[OD_BASE_SGPR
],
1076 immediates
=[IMM_S16
],
1078 _PRE_RA_SIMS
[Ld
] = lambda: OpKind
.__ld
_pre
_ra
_sim
1081 def __svstd_pre_ra_sim(op
, state
):
1082 # type: (Op, PreRASimState) -> None
1083 RS
= state
.ssa_vals
[op
.input_vals
[0]]
1084 RA
, = state
.ssa_vals
[op
.input_vals
[1]]
1085 VL
, = state
.ssa_vals
[op
.input_vals
[2]]
1086 addr
= RA
+ op
.immediates
[0]
1088 state
.store(addr
+ GPR_SIZE_IN_BYTES
* i
, value
=RS
[i
])
1089 SvStd
= GenericOpProperties(
1090 demo_asm
="sv.std *RS, imm(RA)",
1091 inputs
=[OD_EXTRA3_VGPR
, OD_EXTRA3_SGPR
, OD_VL
],
1093 immediates
=[IMM_S16
],
1094 has_side_effects
=True,
1096 _PRE_RA_SIMS
[SvStd
] = lambda: OpKind
.__svstd
_pre
_ra
_sim
1099 def __std_pre_ra_sim(op
, state
):
1100 # type: (Op, PreRASimState) -> None
1101 RS
, = state
.ssa_vals
[op
.input_vals
[0]]
1102 RA
, = state
.ssa_vals
[op
.input_vals
[1]]
1103 addr
= RA
+ op
.immediates
[0]
1104 state
.store(addr
, value
=RS
)
1105 Std
= GenericOpProperties(
1106 demo_asm
="std RT, imm(RA)",
1107 inputs
=[OD_BASE_SGPR
, OD_BASE_SGPR
],
1109 immediates
=[IMM_S16
],
1110 has_side_effects
=True,
1112 _PRE_RA_SIMS
[Std
] = lambda: OpKind
.__std
_pre
_ra
_sim
1115 def __funcargr3_pre_ra_sim(op
, state
):
1116 # type: (Op, PreRASimState) -> None
1117 pass # return value set before simulation
1118 FuncArgR3
= GenericOpProperties(
1121 outputs
=[OD_BASE_SGPR
.with_fixed_loc(
1122 Loc(kind
=LocKind
.GPR
, start
=3, reg_len
=1))],
1124 _PRE_RA_SIMS
[FuncArgR3
] = lambda: OpKind
.__funcargr
3_pre
_ra
_sim
1127 @plain_data(frozen
=True, unsafe_hash
=True, repr=False)
1128 class SSAValOrUse(metaclass
=ABCMeta
):
1129 __slots__
= "op", "operand_idx"
1131 def __init__(self
, op
, operand_idx
):
1132 # type: (Op, int) -> None
1134 if operand_idx
< 0 or operand_idx
>= len(self
.descriptor_array
):
1135 raise ValueError("invalid operand_idx")
1136 self
.operand_idx
= operand_idx
1145 def descriptor_array(self
):
1146 # type: () -> tuple[OperandDesc, ...]
1150 def defining_descriptor(self
):
1151 # type: () -> OperandDesc
1152 return self
.descriptor_array
[self
.operand_idx
]
1157 return self
.defining_descriptor
.ty
1160 def ty_before_spread(self
):
1162 return self
.defining_descriptor
.ty_before_spread
1166 # type: () -> BaseTy
1167 return self
.ty_before_spread
.base_ty
1170 def reg_offset_in_unspread(self
):
1171 """ the number of reg-sized slots in the unspread Loc before self's Loc
1173 e.g. if the unspread Loc containing self is:
1174 `Loc(kind=LocKind.GPR, start=8, reg_len=4)`
1175 and self's Loc is `Loc(kind=LocKind.GPR, start=10, reg_len=1)`
1176 then reg_offset_into_unspread == 2 == 10 - 8
1178 return self
.defining_descriptor
.reg_offset_in_unspread
1181 def unspread_start_idx(self
):
1183 return self
.operand_idx
- (self
.defining_descriptor
.spread_index
or 0)
1186 def unspread_start(self
):
1188 return self
.__class
__(op
=self
.op
, operand_idx
=self
.unspread_start_idx
)
1191 @plain_data(frozen
=True, unsafe_hash
=True, repr=False)
1193 class SSAVal(SSAValOrUse
):
1198 return f
"<{self.op.name}.outputs[{self.operand_idx}]: {self.ty}>"
1201 def def_loc_set_before_spread(self
):
1202 # type: () -> LocSet
1203 return self
.defining_descriptor
.loc_set_before_spread
1206 def descriptor_array(self
):
1207 # type: () -> tuple[OperandDesc, ...]
1208 return self
.op
.properties
.outputs
1211 def tied_input(self
):
1212 # type: () -> None | SSAUse
1213 if self
.defining_descriptor
.tied_input_index
is None:
1215 return SSAUse(op
=self
.op
,
1216 operand_idx
=self
.defining_descriptor
.tied_input_index
)
1219 @plain_data(frozen
=True, unsafe_hash
=True, repr=False)
1221 class SSAUse(SSAValOrUse
):
1225 def use_loc_set_before_spread(self
):
1226 # type: () -> LocSet
1227 return self
.defining_descriptor
.loc_set_before_spread
1230 def descriptor_array(self
):
1231 # type: () -> tuple[OperandDesc, ...]
1232 return self
.op
.properties
.inputs
1236 return f
"<{self.op.name}.input_uses[{self.operand_idx}]: {self.ty}>"
1240 # type: () -> SSAVal
1241 return self
.op
.input_vals
[self
.operand_idx
]
1244 def ssa_val(self
, ssa_val
):
1245 # type: (SSAVal) -> None
1246 self
.op
.input_vals
[self
.operand_idx
] = ssa_val
1250 _Desc
= TypeVar("_Desc")
1253 class OpInputSeq(Sequence
[_T
], Generic
[_T
, _Desc
]):
1255 def _verify_write_with_desc(self
, idx
, item
, desc
):
1256 # type: (int, _T | Any, _Desc) -> None
1257 raise NotImplementedError
1260 def _verify_write(self
, idx
, item
):
1261 # type: (int | Any, _T | Any) -> int
1262 if not isinstance(idx
, int):
1263 if isinstance(idx
, slice):
1265 f
"can't write to slice of {self.__class__.__name__}")
1266 raise TypeError(f
"can't write with index {idx!r}")
1267 # normalize idx, raising IndexError if it is out of range
1268 idx
= range(len(self
.descriptors
))[idx
]
1269 desc
= self
.descriptors
[idx
]
1270 self
._verify
_write
_with
_desc
(idx
, item
, desc
)
1273 def _on_set(self
, idx
, new_item
, old_item
):
1274 # type: (int, _T, _T | None) -> None
1278 def _get_descriptors(self
):
1279 # type: () -> tuple[_Desc, ...]
1280 raise NotImplementedError
1284 def descriptors(self
):
1285 # type: () -> tuple[_Desc, ...]
1286 return self
._get
_descriptors
()
1293 def __init__(self
, items
, op
):
1294 # type: (Iterable[_T], Op) -> None
1296 self
.__items
= [] # type: list[_T]
1297 for idx
, item
in enumerate(items
):
1298 if idx
>= len(self
.descriptors
):
1299 raise ValueError("too many items")
1300 self
._verify
_write
(idx
, item
)
1301 self
.__items
.append(item
)
1302 if len(self
.__items
) < len(self
.descriptors
):
1303 raise ValueError("not enough items")
1307 # type: () -> Iterator[_T]
1308 yield from self
.__items
1311 def __getitem__(self
, idx
):
1316 def __getitem__(self
, idx
):
1317 # type: (slice) -> list[_T]
1321 def __getitem__(self
, idx
):
1322 # type: (int | slice) -> _T | list[_T]
1323 return self
.__items
[idx
]
1326 def __setitem__(self
, idx
, item
):
1327 # type: (int, _T) -> None
1328 idx
= self
._verify
_write
(idx
, item
)
1329 self
.__items
[idx
] = item
1334 return len(self
.__items
)
1337 return f
"{self.__class__.__name__}({self.__items}, op=...)"
1341 class OpInputVals(OpInputSeq
[SSAVal
, OperandDesc
]):
1342 def _get_descriptors(self
):
1343 # type: () -> tuple[OperandDesc, ...]
1344 return self
.op
.properties
.inputs
1346 def _verify_write_with_desc(self
, idx
, item
, desc
):
1347 # type: (int, SSAVal | Any, OperandDesc) -> None
1348 if not isinstance(item
, SSAVal
):
1349 raise TypeError("expected value of type SSAVal")
1350 if item
.ty
!= desc
.ty
:
1351 raise ValueError(f
"assigned item's type {item.ty!r} doesn't match "
1352 f
"corresponding input's type {desc.ty!r}")
1354 def _on_set(self
, idx
, new_item
, old_item
):
1355 # type: (int, SSAVal, SSAVal | None) -> None
1356 SSAUses
._on
_op
_input
_set
(self
, idx
, new_item
, old_item
) # type: ignore
1358 def __init__(self
, items
, op
):
1359 # type: (Iterable[SSAVal], Op) -> None
1360 if hasattr(op
, "inputs"):
1361 raise ValueError("Op.inputs already set")
1362 super().__init
__(items
, op
)
1366 class OpImmediates(OpInputSeq
[int, range]):
1367 def _get_descriptors(self
):
1368 # type: () -> tuple[range, ...]
1369 return self
.op
.properties
.immediates
1371 def _verify_write_with_desc(self
, idx
, item
, desc
):
1372 # type: (int, int | Any, range) -> None
1373 if not isinstance(item
, int):
1374 raise TypeError("expected value of type int")
1375 if item
not in desc
:
1376 raise ValueError(f
"immediate value {item!r} not in {desc!r}")
1378 def __init__(self
, items
, op
):
1379 # type: (Iterable[int], Op) -> None
1380 if hasattr(op
, "immediates"):
1381 raise ValueError("Op.immediates already set")
1382 super().__init
__(items
, op
)
1385 @plain_data(frozen
=True, eq
=False, repr=False)
1388 __slots__
= ("fn", "properties", "input_vals", "input_uses", "immediates",
1391 def __init__(self
, fn
, properties
, input_vals
, immediates
, name
=""):
1392 # type: (Fn, OpProperties, Iterable[SSAVal], Iterable[int], str) -> None
1394 self
.properties
= properties
1395 self
.input_vals
= OpInputVals(input_vals
, op
=self
)
1396 inputs_len
= len(self
.properties
.inputs
)
1397 self
.input_uses
= tuple(SSAUse(self
, i
) for i
in range(inputs_len
))
1398 self
.immediates
= OpImmediates(immediates
, op
=self
)
1399 outputs_len
= len(self
.properties
.outputs
)
1400 self
.outputs
= tuple(SSAVal(self
, i
) for i
in range(outputs_len
))
1401 self
.name
= fn
._add
_op
_with
_unused
_name
(self
, name
) # type: ignore
1405 return self
.properties
.kind
1407 def __eq__(self
, other
):
1408 # type: (Op | Any) -> bool
1409 if isinstance(other
, Op
):
1410 return self
is other
1411 return NotImplemented
1414 return object.__hash
__(self
)
1418 field_vals
= [] # type: list[str]
1419 for name
in fields(self
):
1420 if name
== "properties":
1425 value
= getattr(self
, name
)
1426 except AttributeError:
1427 field_vals
.append(f
"{name}=<not set>")
1429 if isinstance(value
, OpInputSeq
):
1430 value
= list(value
) # type: ignore
1431 field_vals
.append(f
"{name}={value!r}")
1432 field_vals_str
= ", ".join(field_vals
)
1433 return f
"Op({field_vals_str})"
1435 def pre_ra_sim(self
, state
):
1436 # type: (PreRASimState) -> None
1437 for inp
in self
.input_vals
:
1438 if inp
not in state
.ssa_vals
:
1439 raise ValueError(f
"SSAVal {inp} not yet assigned when "
1441 if len(state
.ssa_vals
[inp
]) != inp
.ty
.reg_len
:
1443 f
"value of SSAVal {inp} has wrong number of elements: "
1444 f
"expected {inp.ty.reg_len} found "
1445 f
"{len(state.ssa_vals[inp])}: {state.ssa_vals[inp]!r}")
1446 for out
in self
.outputs
:
1447 if out
in state
.ssa_vals
:
1448 if self
.kind
is OpKind
.FuncArgR3
:
1450 raise ValueError(f
"SSAVal {out} already assigned before "
1452 self
.kind
.pre_ra_sim(self
, state
)
1453 for out
in self
.outputs
:
1454 if out
not in state
.ssa_vals
:
1455 raise ValueError(f
"running {self} failed to assign to {out}")
1456 if len(state
.ssa_vals
[out
]) != out
.ty
.reg_len
:
1458 f
"value of SSAVal {out} has wrong number of elements: "
1459 f
"expected {out.ty.reg_len} found "
1460 f
"{len(state.ssa_vals[out])}: {state.ssa_vals[out]!r}")
1463 GPR_SIZE_IN_BYTES
= 8
1465 GPR_SIZE_IN_BITS
= GPR_SIZE_IN_BYTES
* BITS_IN_BYTE
1466 GPR_VALUE_MASK
= (1 << GPR_SIZE_IN_BITS
) - 1
1469 @plain_data(frozen
=True, repr=False)
1471 class PreRASimState
:
1472 __slots__
= "ssa_vals", "memory"
1474 def __init__(self
, ssa_vals
, memory
):
1475 # type: (dict[SSAVal, tuple[int, ...]], dict[int, int]) -> None
1476 self
.ssa_vals
= ssa_vals
1477 self
.memory
= memory
1479 def load_byte(self
, addr
):
1480 # type: (int) -> int
1481 addr
&= GPR_VALUE_MASK
1482 return self
.memory
.get(addr
, 0) & 0xFF
1484 def store_byte(self
, addr
, value
):
1485 # type: (int, int) -> None
1486 addr
&= GPR_VALUE_MASK
1488 self
.memory
[addr
] = value
1490 def load(self
, addr
, size_in_bytes
=GPR_SIZE_IN_BYTES
, signed
=False):
1491 # type: (int, int, bool) -> int
1492 if addr
% size_in_bytes
!= 0:
1493 raise ValueError(f
"address not aligned: {hex(addr)} "
1494 f
"required alignment: {size_in_bytes}")
1496 for i
in range(size_in_bytes
):
1497 retval |
= self
.load_byte(addr
+ i
) << i
* BITS_IN_BYTE
1498 if signed
and retval
>> (size_in_bytes
* BITS_IN_BYTE
- 1) != 0:
1499 retval
-= 1 << size_in_bytes
* BITS_IN_BYTE
1502 def store(self
, addr
, value
, size_in_bytes
=GPR_SIZE_IN_BYTES
):
1503 # type: (int, int, int) -> None
1504 if addr
% size_in_bytes
!= 0:
1505 raise ValueError(f
"address not aligned: {hex(addr)} "
1506 f
"required alignment: {size_in_bytes}")
1507 for i
in range(size_in_bytes
):
1508 self
.store_byte(addr
+ i
, (value
>> i
* BITS_IN_BYTE
) & 0xFF)
1510 def _memory__repr(self
):
1512 if len(self
.memory
) == 0:
1514 keys
= sorted(self
.memory
.keys(), reverse
=True)
1515 CHUNK_SIZE
= GPR_SIZE_IN_BYTES
1516 items
= [] # type: list[str]
1517 while len(keys
) != 0:
1519 if (len(keys
) >= CHUNK_SIZE
1520 and addr
% CHUNK_SIZE
== 0
1521 and keys
[-CHUNK_SIZE
:]
1522 == list(reversed(range(addr
, addr
+ CHUNK_SIZE
)))):
1523 value
= self
.load(addr
, size_in_bytes
=CHUNK_SIZE
)
1524 items
.append(f
"0x{addr:05x}: <0x{value:0{CHUNK_SIZE * 2}x}>")
1525 keys
[-CHUNK_SIZE
:] = ()
1527 items
.append(f
"0x{addr:05x}: 0x{self.memory[keys.pop()]:02x}")
1529 return f
"{{{items[0]}}}"
1530 items_str
= ",\n".join(items
)
1531 return f
"{{\n{items_str}}}"
1533 def _ssa_vals__repr(self
):
1535 if len(self
.ssa_vals
) == 0:
1537 items
= [] # type: list[str]
1539 for k
, v
in self
.ssa_vals
.items():
1540 element_strs
= [] # type: list[str]
1541 for i
, el
in enumerate(v
):
1542 if i
% CHUNK_SIZE
!= 0:
1543 element_strs
.append(" " + hex(el
))
1545 element_strs
.append("\n " + hex(el
))
1546 if len(element_strs
) <= CHUNK_SIZE
:
1547 element_strs
[0] = element_strs
[0].lstrip()
1548 if len(element_strs
) == 1:
1549 element_strs
.append("")
1550 v_str
= ",".join(element_strs
)
1551 items
.append(f
"{k!r}: ({v_str})")
1552 if len(items
) == 1 and "\n" not in items
[0]:
1553 return f
"{{{items[0]}}}"
1554 items_str
= ",\n".join(items
)
1555 return f
"{{\n{items_str},\n}}"
1559 field_vals
= [] # type: list[str]
1560 for name
in fields(self
):
1562 value
= getattr(self
, name
)
1563 except AttributeError:
1564 field_vals
.append(f
"{name}=<not set>")
1566 repr_fn
= getattr(self
, f
"_{name}__repr", None)
1567 if callable(repr_fn
):
1568 field_vals
.append(f
"{name}={repr_fn()}")
1570 field_vals
.append(f
"{name}={value!r}")
1571 field_vals_str
= ", ".join(field_vals
)
1572 return f
"PreRASimState({field_vals_str})"