[Libre-soc-dev] my current plan regarding simdsignal
Jacob Lifshay
programmerjake at gmail.com
Fri Oct 22 18:28:29 BST 2021
On Fri, Oct 22, 2021, 04:05 lkcl <luke.leighton at gmail.com> wrote:
> also: given the "carrying of context" (PartType), the idea of throwing
> out SimdSignal.ptype and making it a global is *definitely* a nonstarter.
> it was already a non-starter due to being global (which is frowned
> on in general, in python, so please don't start making design assumptions
> that rely on any globals of any kind, please) but it's just not going to
work.
To be clear, SimdSignal would always access its SimdScope through a member
variable, specifically: self.shape.scope. The SimdScope global is just so
end-user code doesn't have to pass in a SimdScope instance everywhere,
since that is useless verbosity. SimdShape/SimdSignal constructors always,
as their first step, retrieve the current global SimdScope instance *only
if* a specific instance is not passed in. All SimdShape/SimdSignal
implementation code will pass scope=self.shape.scope.
Example:
with SimdScope(...) as s:
s1 = SimdShape(5) # scope retrieved in constructor from SimdScope.get()
by default
assert s1.scope is s
s2 = SimdShape(5, scope=s) # we can explicitly pass in a scope
assert s2.scope is s
assert s1 == s2
a = SimdSignal(5) # scope retrieved in constructor from SimdScope.get()
by default
assert a.shape == s1
assert a.shape.scope is s
b = SimdSignal(5, scope=s) # we can explicitly pass in a scope
assert b.shape.scope is s
assert b.shape == s1
c = SimdSignal(s1) # we can explicitly pass in a shape, scope read from
shape
assert c.shape.scope is s
assert c.shape is s1
Also, do note that SimdScope can explicitly represent the state of
SimdSignal becoming unvectorized scalar code:
SimdScope(module=..., scalar=True), which produces a SimdScope instance
with member variables set to:
self.module = module
self.vec_el_counts = SimdMap({IntElWid.I64: 1})
self.full_el_count = 1
self.elwid = IntElWid.I64 # constant, not a Signal
self.elwid_type = IntElWid
# no self.scalar member variable, if we want one it should be a property:
class SimdScope:
...
@property
def scalar(self):
retval = False
for index, el_count in enumerate(self.vec_el_counts.values()):
if index != 0 or el_count != 1:
return False
retval = True
if retval:
assert isinstance(self.elwid, self.elwid_type)
else:
assert isinstance(self.elwid, Value)
return retval
This allows SimdSignal to easily detect if it should act like a scalar:
class SimdSignal(...):
def __init__(self, shape, *, sig=None, scope=None, src_loc_at=0,
**kwargs):
self.shape = SimdShape.cast(shape, scope=scope) # calls
SimdScope.get if needed
if sig is None:
sig = Signal(self.shape.width, src_loc_at=1 + src_loc_at,
**kwargs)
self.sig = sig
"""if self.shape.scope.scalar, then `sig` is our scalar Value"""
@staticmethod
def cast(value, *, scope=None):
if isinstance(value, SimdSignal):
assert scope is None or value.shape.scope is scope, (
"incompatible SimdScopes, everything in an ALU must "
"use the exact same SimdScope instance")
return value
if scope is None:
scope = SimdScope.get()
value = Value.cast(value)
if scope.scalar:
# scalar, so we return a SimdSignal with sig set to value
return SimdSignal(value.shape(), scope=scope, sig=value)
# TODO: splat to convert scalar to SIMD
# all operations detect scalar-ness and short-circuit
def __add__(self, other):
other = SimdSignal.cast(other, scope=self.shape.scope)
if self.shape.scope.scalar:
return SimdSignal.cast(self.sig + other.sig,
scope=self.shape.scope)
# normal SIMD path
Jacob
>
More information about the Libre-soc-dev
mailing list