Validate that *shape* / *dtype* / *swizzle_mode* are mutually compatible. ``mma_shared_layout`` tiles a swizzle atom of shape ``[8, swizzle_bytes / dtype_bytes]`` over the last two logical dimensions of *shape*. If the row width or row count of the request is smaller than (or not a mult
(shape, dtype, swizzle_mode)
| 100 | |
| 101 | |
| 102 | def _validate_mma_alloc_shape(shape, dtype, swizzle_mode): |
| 103 | """Validate that *shape* / *dtype* / *swizzle_mode* are mutually compatible. |
| 104 | |
| 105 | ``mma_shared_layout`` tiles a swizzle atom of shape ``[8, swizzle_bytes / dtype_bytes]`` |
| 106 | over the last two logical dimensions of *shape*. If the row width or row count of |
| 107 | the request is smaller than (or not a multiple of) the atom, the underlying |
| 108 | ``Layout.tile_to`` lowers to a ``floordiv``/``floormod`` by zero and raises an |
| 109 | opaque internal "Divide by zero" diagnostic from ``tile_tile_ops.cc``. Catch the |
| 110 | misconfiguration here so callers see *what* is wrong and *how* to fix it. |
| 111 | |
| 112 | Validation skipped when *swizzle_mode* is ``SWIZZLE_NONE`` (no atom). |
| 113 | """ |
| 114 | from tvm.backend.cuda.operator.tile_primitive.tma_utils import SwizzleMode |
| 115 | |
| 116 | if swizzle_mode == SwizzleMode.SWIZZLE_NONE: |
| 117 | return |
| 118 | |
| 119 | if len(shape) < 2: |
| 120 | raise ValueError( |
| 121 | f"alloc_mma shape={tuple(shape)} has fewer than 2 dimensions; " |
| 122 | f"swizzled MMA layouts tile over the last two dims (rows, cols). " |
| 123 | f"Use swizzle_mode='none' for 1-D allocations." |
| 124 | ) |
| 125 | |
| 126 | # Only validate concrete int dims; symbolic dims fall through (the analyzer |
| 127 | # in C++ will still ICHECK on them, but at least we don't false-positive). |
| 128 | rows = shape[-2] |
| 129 | cols = shape[-1] |
| 130 | if not (isinstance(rows, int) and isinstance(cols, int)): |
| 131 | return |
| 132 | |
| 133 | dtype_bytes = DataType(dtype).bits // 8 |
| 134 | if dtype_bytes == 0: |
| 135 | # Sub-byte dtype (e.g. float4); ``cols`` is already in element units, so |
| 136 | # use a fractional check expressed via bits. |
| 137 | col_bits = cols * DataType(dtype).bits |
| 138 | atom_bits = _swizzle_atom_bytes(swizzle_mode) * 8 |
| 139 | if col_bits < atom_bits or col_bits % atom_bits != 0: |
| 140 | row_bytes = col_bits // 8 if col_bits % 8 == 0 else col_bits / 8 |
| 141 | atom_bytes = _swizzle_atom_bytes(swizzle_mode) |
| 142 | suggestion = _suggest_swizzle_for_row_bytes(col_bits // 8 if col_bits >= 8 else 0) |
| 143 | raise ValueError( |
| 144 | f"alloc_mma shape={tuple(shape)} with dtype={dtype!r} produces " |
| 145 | f"{row_bytes}B rows, which is incompatible with the {atom_bytes}B " |
| 146 | f"swizzle atom selected by {swizzle_mode.name}. " |
| 147 | f"Use swizzle_mode=SwizzleMode.{suggestion}, or widen shape[-1] " |
| 148 | f"to a multiple of " |
| 149 | f"{(atom_bits + DataType(dtype).bits - 1) // DataType(dtype).bits} elements." |
| 150 | ) |
| 151 | else: |
| 152 | row_bytes = cols * dtype_bytes |
| 153 | atom_bytes = _swizzle_atom_bytes(swizzle_mode) |
| 154 | if row_bytes < atom_bytes or row_bytes % atom_bytes != 0: |
| 155 | suggestion = _suggest_swizzle_for_row_bytes(row_bytes) |
| 156 | min_cols = atom_bytes // dtype_bytes |
| 157 | raise ValueError( |
| 158 | f"alloc_mma shape={tuple(shape)} with dtype={dtype!r} produces " |
| 159 | f"{row_bytes}B rows, which is incompatible with the {atom_bytes}B " |
searching dependent graphs…