[Libre-soc-bugs] [Bug 713] PartitionedSignal enhancement to add partition-context-aware lengths

bugzilla-daemon at libre-soc.org bugzilla-daemon at libre-soc.org
Tue Oct 12 06:13:24 BST 2021


https://bugs.libre-soc.org/show_bug.cgi?id=713

--- Comment #69 from Jacob Lifshay <programmerjake at gmail.com> ---
reading through what you wrote on the wiki:
https://libre-soc.org/3d_gpu/architecture/dynamic_simd/shape/

You appear to want to keep forcing SimdShape into being a Shape, and that
causes problems with SimdShape's current design...

SimdShape can't be an instance of Shape as you are trying to do, because
Shape.width is the width of a nmigen scalar Signal/Value, when vectorizing
scalar code, Shape.width ends up being the lane width (excluding padding). The
problem arises because lanes have different widths for different elwid values,
so there *isn't* a single consistent integer value for Shape.width. Shape.width
*is not* the same as SimdShape.width, since SimdShape.width is the width of the
whole SIMD signal, which is, from the perspective of user code in an ALU, an
arbitrary multiple of Shape.width. That multiplication factor is determined by
the calling code and can arbitrarily vary (e.g. we could decide that we want
256-bit wide SIMD ALUs, or we could decide that we want to make a tiny 32-bit
cpu and we want 32-bit wide SIMD ALUs (which have 0 64-bit lanes, 1 32-bit
lane, 2 16-bit lanes, or 4 8-bit lanes)).

A possible solution that keeps SimdShape as a subclass of Shape is to rename
the current SimdShape.width to something like .simd_width, allowing us to
instead have SimdShape.width be a SimdMapInt (a subclass of SimdMap and int) of
lane widths (the .width components of lane_shapes), that would meet the
semantic requirements of Shape.

e.g.:

class SimdShape(Shape): # aka. SimdLayout
    def __init__(self, lane_shapes):
        if isinstance(lane_shapes, SimdShape):
            self.lane_shapes = lane_shapes.lane_shapes
        else:
            # convert to SimdMap with Shapes for values, handles
            # input dicts, SimdMaps, Shapes, ints, Enums, etc.
            self.lane_shapes = SimdMap.map(Shape.cast, lane_shapes)
        signed = None
        for elwid in global_scope().lane_counts.keys():
            lane_shape = self.lane_shapes.values[elwid]
            if signed is None:
                signed = lane_shape.signed
            else:
                assert signed == lane_shape.signed
            assert not isinstance(lane_shape, SimdShape), \
                "can't have a SimdShape for a lane's shape"
        # Shape.__init__ doesn't like non-int widths, so pass in fake width for
now
        super().__init__(1, signed)
        # width is a SimdMap with each lane's bit width for values
        width = SimdMapInt(SimdMap.map(lambda s: s.width, self.lane_shapes))
        # finish calculating layout...
        ...

# needed since Shape requires width to be an int
class SimdMapInt(SimdMap, int):
    def __init__(self, values):
        # convert every value to an int
        values = SimdMap.map(int, values)
        super().__init__(values)

so, a SimdShape would end up with fields like so:
part_counts = {
    ElWid.F16: 1, # f16 takes 1 16-bit word
    ElWid.BF16: 1, # bf16 takes 1 16-bit word
    ElWid.F32: 2, # f32 takes 2 16-bit words
    ElWid.F64: 4, # f64 takes 4 16-bit words
}
with simd_scope(part_counts, total_parts=8): # 8 16-bit parts for 128-bit SIMD
    s = SimdShape(XLEN)

s.signed == False
s.width == SimdMapInt({
    ElWid.F16: 16,
    ElWid.BF16: 16,
    ElWid.F32: 32,
    ElWid.F64: 64,
})
s.lane_shapes == SimdMap({
    ElWid.F16: unsigned(16),
    ElWid.BF16: unsigned(16),
    ElWid.F32: unsigned(32),
    ElWid.F64: unsigned(64),
})
s.simd_width == 128 # what used to be SimdShape.width, since renamed
s.part_count = 8 # 8 16-bit parts
s.part_width = 16
... # rest of `s`'es fields omitted

sig = SimdSignal(s)
sig.shape() == s
sig.sig.shape() == unsigned(128)


another example:
with simd_scope(part_counts, total_parts=4): # 4 16-bit parts for 64-bit SIMD
    s = SimdShape(XLEN)

s.signed == False
s.width == SimdMapInt({
    ElWid.F16: 16,
    ElWid.BF16: 16,
    ElWid.F32: 32,
    ElWid.F64: 64,
})
s.lane_shapes == SimdMap({
    ElWid.F16: unsigned(16),
    ElWid.BF16: unsigned(16),
    ElWid.F32: unsigned(32),
    ElWid.F64: unsigned(64),
})
s.simd_width == 64 # what used to be SimdShape.width, since renamed
s.part_count = 4 # 4 16-bit parts
s.part_width = 16
... # rest of `s`'es fields omitted

sig = SimdSignal(s)
sig.shape() == s
sig.sig.shape() == unsigned(64)

-- 
You are receiving this mail because:
You are on the CC list for the bug.


More information about the libre-soc-bugs mailing list