| 147 | return [(pxls//ALIGN//k, ALIGN*k) for k in range(ceildiv(pxls//ALIGN, MAXW), min(pxls//ALIGN, MAXW//ALIGN)+1) if (pxls//ALIGN)%k == 0] |
| 148 | |
| 149 | class dtypes: |
| 150 | @staticmethod |
| 151 | @functools.cache |
| 152 | def is_float(x: DType) -> bool: return x.scalar() in dtypes.floats or isinstance(x, ImageDType) |
| 153 | @staticmethod # static methods on top, or bool in the type info will refer to dtypes.bool |
| 154 | @functools.cache |
| 155 | def is_int(x: DType) -> bool: return x.scalar() in (dtypes.ints + (dtypes.weakint,)) |
| 156 | @staticmethod |
| 157 | @functools.cache |
| 158 | def is_unsigned(x: DType) -> bool: return x.scalar() in dtypes.uints |
| 159 | @staticmethod |
| 160 | def is_bool(x: DType) -> bool: return x.scalar() == dtypes.bool |
| 161 | @staticmethod |
| 162 | def from_py(x) -> DType: |
| 163 | # NOTE: isinstance(True, int) is True, so bool must be checked before int |
| 164 | if isinstance(x, bool): return dtypes.bool |
| 165 | if isinstance(x, float): return dtypes.default_float |
| 166 | if isinstance(x, int): return dtypes.default_int |
| 167 | # put this in the last is faster because there are more items than lists/tuples to check |
| 168 | if isinstance(x, (list, tuple)): return max(dtypes.from_py(xi) for xi in x) if x else dtypes.default_float |
| 169 | raise RuntimeError(f"Could not infer dtype of {x} with type {type(x)}") |
| 170 | @staticmethod |
| 171 | def finfo(dtype:DType) -> tuple[int, int]: |
| 172 | """(exponent, mantissa)""" |
| 173 | if not dtypes.is_float(dtype): raise ValueError(f"{dtype} is not a floating point type") |
| 174 | return {dtypes.float16: (5, 10), dtypes.bfloat16: (8, 7), dtypes.float32: (8, 23), dtypes.float64: (11, 52), |
| 175 | dtypes.fp8e4m3: (4, 3), dtypes.fp8e5m2: (5, 2), dtypes.fp8e4m3fnuz: (4, 3), dtypes.fp8e5m2fnuz: (5, 2)}[dtype] |
| 176 | void: Final[DType] = DType.new(-1, 0, "void", None) |
| 177 | weakint: Final[DType] = DType.new(0, 800, "weakint", None) |
| 178 | bool: Final[DType] = DType.new(0, 1, "bool", '?') |
| 179 | int8: Final[DType] = DType.new(1, 8, "signed char", 'b') |
| 180 | uint8: Final[DType] = DType.new(2, 8, "unsigned char", 'B') |
| 181 | int16: Final[DType] = DType.new(3, 16, "short", 'h') |
| 182 | uint16: Final[DType] = DType.new(4, 16, "unsigned short", 'H') |
| 183 | int32: Final[DType] = DType.new(5, 32, "int", 'i') |
| 184 | uint32: Final[DType] = DType.new(6, 32, "unsigned int", 'I') |
| 185 | int64: Final[DType] = DType.new(7, 64, "long", 'q') |
| 186 | uint64: Final[DType] = DType.new(8, 64, "unsigned long", 'Q') |
| 187 | _uint128: Final[DType] = DType.new(8, 128, "uint128", None) |
| 188 | _uint256: Final[DType] = DType.new(8, 256, "uint256", None) |
| 189 | fp8e4m3: Final[DType] = DType.new(9, 8, "float8_e4m3", None) |
| 190 | fp8e5m2: Final[DType] = DType.new(10, 8, "float8_e5m2", None) |
| 191 | fp8e4m3fnuz: Final[DType] = DType.new(9, 8, "float8_e4m3fnuz", None) |
| 192 | fp8e5m2fnuz: Final[DType] = DType.new(10, 8, "float8_e5m2fnuz", None) |
| 193 | float16: Final[DType] = DType.new(11, 16, "half", 'e') |
| 194 | # bfloat16 has higher priority than float16, so least_upper_dtype(dtypes.int64, dtypes.uint64) = dtypes.float16 |
| 195 | bfloat16: Final[DType] = DType.new(12, 16, "__bf16", None) |
| 196 | float32: Final[DType] = DType.new(13, 32, "float", 'f') |
| 197 | float64: Final[DType] = DType.new(14, 64, "double", 'd') |
| 198 | |
| 199 | # dtype aliases |
| 200 | half = float16; float = float32; double = float64 # noqa: E702 |
| 201 | uchar = uint8; ushort = uint16; uint = uint32; ulong = uint64 # noqa: E702 |
| 202 | char = int8; short = int16; int = int32; long = int64 # noqa: E702 |
| 203 | |
| 204 | # NOTE: these are image dtypes |
| 205 | @staticmethod |
| 206 | def imageh(shp): return ImageDType(100, 16, "imageh", 'e', 1, None, dtypes.float32, AddrSpace.GLOBAL, 1, prod(shp), shp) |
nothing calls this directly
no test coverage detected
searching dependent graphs…