1 # SPDX-License-Identifier: LGPL-3-or-later
2 # See Notices.txt for copyright information
5 from typing
import Mapping
8 from types
import MappingProxyType
13 return super().__str
__()
23 class IntElWid(ElWid
):
31 """A map from ElWid values to Python values.
32 SimdMap instances are immutable."""
34 ALL_ELWIDTHS
= (*FpElWid
, *IntElWid
)
35 __slots__
= ("__map",)
38 def extract_value_algo(values
, default
=None, *, simd_map_get
, mapping_get
):
40 while values
is not None:
41 # specifically use base class to catch all SimdMap instances
42 if isinstance(values
, SimdMap
):
43 values
= simd_map_get(values
)
44 elif isinstance(values
, Mapping
):
45 values
= mapping_get(values
)
49 # use object.__repr__ since repr() would probably recurse forever
50 assert step
< 10000, (f
"can't resolve infinitely recursive "
51 f
"value {object.__repr__(values)}")
55 def extract_value(cls
, elwid
, values
, default
=None):
56 """get the value for elwid.
57 if `values` is a `SimdMap` or a `Mapping`, then return the
58 corresponding value for `elwid`, recursing until finding a non-map.
59 if `values` ever ends up not existing (in the case of a map) or being
60 `None`, return `default`.
63 SimdMap.extract_value(IntElWid.I8, 5) == 5
64 SimdMap.extract_value(IntElWid.I8, None) == None
65 SimdMap.extract_value(IntElWid.I8, None, 3) == 3
66 SimdMap.extract_value(IntElWid.I8, {}) == None
67 SimdMap.extract_value(IntElWid.I8, {IntElWid.I8: 5}) == 5
68 SimdMap.extract_value(IntElWid.I8, {
69 IntElWid.I8: {IntElWid.I8: 5},
71 SimdMap.extract_value(IntElWid.I8, {
72 IntElWid.I8: SimdMap({IntElWid.I8: 5}),
75 assert elwid
in cls
.ALL_ELWIDTHS
76 return SimdMap
.extract_value_algo(
78 simd_map_get
=lambda v
: v
.__map
.get(elwid
),
79 mapping_get
=lambda v
: v
.get(elwid
))
81 def __init__(self
, values
=None):
82 """construct a SimdMap"""
84 for elwid
in self
.ALL_ELWIDTHS
:
85 v
= self
.extract_value(elwid
, values
)
88 self
.__map
= MappingProxyType(mapping
)
92 """the values as a read-only Mapping[ElWid, Any]"""
96 return self
.__map
.values()
99 return self
.__map
.keys()
102 return self
.__map
.items()
105 def map_with_elwid(cls
, f
, *args
):
106 """get the SimdMap of the results of calling
107 `f(elwid, value1, value2, value3, ...)` where
108 `value1`, `value2`, `value3`, ... are the results of calling
109 `cls.extract_value` on each `args`.
111 This is similar to Python's built-in `map` function.
114 SimdMap.map_with_elwid(lambda elwid, a: a + 1, {IntElWid.I32: 5}) ==
115 SimdMap({IntElWid.I32: 6})
116 SimdMap.map_with_elwid(lambda elwid, a: a + 1, 3) ==
117 SimdMap({IntElWid.I8: 4, IntElWid.I16: 4, ...})
118 SimdMap.map_with_elwid(lambda elwid, a, b: a + b,
120 ) == SimdMap({IntElWid.I8: 7})
121 SimdMap.map_with_elwid(lambda elwid: elwid.name) ==
122 SimdMap({IntElWid.I8: "I8", IntElWid.I16: "I16"})
125 for elwid
in cls
.ALL_ELWIDTHS
:
126 extracted_args
= [cls
.extract_value(elwid
, arg
) for arg
in args
]
127 if None not in extracted_args
:
128 retval
[elwid
] = f(elwid
, *extracted_args
)
132 def map(cls
, f
, *args
):
133 """get the SimdMap of the results of calling
134 `f(value1, value2, value3, ...)` where
135 `value1`, `value2`, `value3`, ... are the results of calling
136 `cls.extract_value` on each `args`.
138 This is similar to Python's built-in `map` function.
141 SimdMap.map(lambda a: a + 1, {IntElWid.I32: 5}) ==
142 SimdMap({IntElWid.I32: 6})
143 SimdMap.map(lambda a: a + 1, 3) ==
144 SimdMap({IntElWid.I8: 4, IntElWid.I16: 4, ...})
145 SimdMap.map(lambda a, b: a + b,
147 ) == SimdMap({IntElWid.I8: 7})
149 return cls
.map_with_elwid(lambda elwid
, *args2
: f(*args2
), *args
)
151 def get(self
, elwid
, default
=None, *, raise_key_error
=False):
153 retval
= self
.extract_value(elwid
, self
)
157 return self
.extract_value(elwid
, self
, default
)
160 """return an iterator of (elwid, value) pairs"""
161 return iter(self
.__map
.items())
163 def __add__(self
, other
):
164 return self
.map(operator
.add
, self
, other
)
166 def __radd__(self
, other
):
167 return self
.map(operator
.add
, other
, self
)
169 def __sub__(self
, other
):
170 return self
.map(operator
.sub
, self
, other
)
172 def __rsub__(self
, other
):
173 return self
.map(operator
.sub
, other
, self
)
175 def __mul__(self
, other
):
176 return self
.map(operator
.mul
, self
, other
)
178 def __rmul__(self
, other
):
179 return self
.map(operator
.mul
, other
, self
)
181 def __floordiv__(self
, other
):
182 return self
.map(operator
.floordiv
, self
, other
)
184 def __rfloordiv__(self
, other
):
185 return self
.map(operator
.floordiv
, other
, self
)
187 def __truediv__(self
, other
):
188 return self
.map(operator
.truediv
, self
, other
)
190 def __rtruediv__(self
, other
):
191 return self
.map(operator
.truediv
, other
, self
)
193 def __mod__(self
, other
):
194 return self
.map(operator
.mod
, self
, other
)
196 def __rmod__(self
, other
):
197 return self
.map(operator
.mod
, other
, self
)
200 return self
.map(abs, self
)
202 def __and__(self
, other
):
203 return self
.map(operator
.and_
, self
, other
)
205 def __rand__(self
, other
):
206 return self
.map(operator
.and_
, other
, self
)
208 def __divmod__(self
, other
):
209 return self
.map(divmod, self
, other
)
212 return self
.map(math
.ceil
, self
)
215 return self
.map(float, self
)
218 return self
.map(math
.floor
, self
)
220 def __eq__(self
, other
):
221 if isinstance(other
, SimdMap
):
222 return self
.mapping
== other
.mapping
223 return NotImplemented
226 return hash(tuple(self
.mapping
.get(i
) for i
in self
.ALL_ELWIDTHS
))
229 return f
"{self.__class__.__name__}({dict(self.mapping)})"
231 def __invert__(self
):
232 return self
.map(operator
.invert
, self
)
234 def __lshift__(self
, other
):
235 return self
.map(operator
.lshift
, self
, other
)
237 def __rlshift__(self
, other
):
238 return self
.map(operator
.lshift
, other
, self
)
240 def __rshift__(self
, other
):
241 return self
.map(operator
.rshift
, self
, other
)
243 def __rrshift__(self
, other
):
244 return self
.map(operator
.rshift
, other
, self
)
247 return self
.map(operator
.neg
, self
)
250 return self
.map(operator
.pos
, self
)
252 def __or__(self
, other
):
253 return self
.map(operator
.or_
, self
, other
)
255 def __ror__(self
, other
):
256 return self
.map(operator
.or_
, other
, self
)
258 def __xor__(self
, other
):
259 return self
.map(operator
.xor
, self
, other
)
261 def __rxor__(self
, other
):
262 return self
.map(operator
.xor
, other
, self
)
264 def missing_elwidths(self
, *, all_elwidths
=None):
265 """an iterator of the elwidths where self doesn't have a corresponding
267 if all_elwidths
is None:
268 all_elwidths
= self
.ALL_ELWIDTHS
269 for elwid
in all_elwidths
:
270 if elwid
not in self
.keys():
274 class SimdWHintMap(SimdMap
):
275 """SimdMap with a width hint."""
277 __slots__
= ("__width_hint",)
280 def extract_width_hint(cls
, values
, default
=None):
281 """get the value for width hint."""
283 return v
.width_hint
if isinstance(v
, SimdWHintMap
) else None
284 return SimdMap
.extract_value_algo(
286 simd_map_get
=simd_map_get
,
287 mapping_get
=lambda _
: None)
289 def __init__(self
, values
=None, *, width_hint
=None):
290 """construct a SimdWHintMap"""
291 super().__init
__(values
)
292 if width_hint
is None:
295 self
.__width
_hint
= self
.extract_width_hint(width_hint
)
298 def width_hint(self
):
299 return self
.__width
_hint
301 def __eq__(self
, other
):
302 if isinstance(other
, SimdMap
):
303 return self
.mapping
== other
.mapping \
304 and self
.width_hint
== self
.extract_width_hint(other
)
305 return NotImplemented
308 if self
.width_hint
is None:
309 return super().__hash
__()
310 return hash((tuple(self
.mapping
.get(i
) for i
in self
.ALL_ELWIDTHS
),
315 if self
.width_hint
is not None:
316 wh
= f
", width_hint={self.width_hint!r}"
317 return f
"{self.__class__.__name__}({dict(self.mapping)}{wh})"
320 def map(cls
, f
, *args
):
321 """get the SimdWHintMap of the results of calling
322 `f(value1, value2, value3, ...)` where
323 `value1`, `value2`, `value3`, ... are the results of calling
324 `cls.extract_value` on each `args`.
327 for elwid
in cls
.ALL_ELWIDTHS
:
328 extracted_args
= [cls
.extract_value(elwid
, arg
) for arg
in args
]
329 if None not in extracted_args
:
330 retval
[elwid
] = f(*extracted_args
)
333 extracted_args
= [cls
.extract_width_hint(arg
) for arg
in args
]
334 if None not in extracted_args
:
335 width_hint
= f(*extracted_args
)
336 except (ArithmeticError, LookupError, ValueError):
337 # ignore some errors and just clear width_hint
339 return cls(retval
, width_hint
=width_hint
)
342 def _check_for_missing_elwidths(name
, all_elwidths
=None):
343 missing
= list(globals()[name
].missing_elwidths(all_elwidths
=all_elwidths
))
344 assert missing
== [], f
"{name} is missing entries for {missing}"
347 XLEN
= SimdWHintMap({
358 DEFAULT_FP_VEC_EL_COUNTS
= SimdMap({
365 DEFAULT_INT_VEC_EL_COUNTS
= SimdMap({
372 _check_for_missing_elwidths("XLEN")
373 _check_for_missing_elwidths("DEFAULT_FP_VEC_EL_COUNTS", FpElWid
)
374 _check_for_missing_elwidths("DEFAULT_INT_VEC_EL_COUNTS", IntElWid
)