|
1 | | -from __future__ import annotations |
2 | | - |
3 | | -from functools import reduce |
4 | | -from typing import Any, Callable, TYPE_CHECKING, Union, List, Dict |
| 1 | +from typing import Any, Callable, TYPE_CHECKING, Union |
5 | 2 |
|
6 | 3 | if TYPE_CHECKING: |
7 | 4 | from .language import core |
8 | 5 | IterableType = Union[list[Any], tuple[Any, ...], core.tuple, core.tuple_type] |
9 | 6 | ObjPath = tuple[int, ...] |
10 | 7 |
|
11 | | -TRITON_MAX_TENSOR_NUMEL = 1048576 |
12 | | - |
13 | | - |
14 | | -def get_iterable_path(iterable: IterableType, path: ObjPath) -> Any: |
15 | | - return reduce(lambda a, idx: a[idx], path, iterable) # type: ignore[index] |
16 | | - |
17 | | - |
18 | | -def set_iterable_path(iterable: IterableType, path: tuple[int, ...], val: Any): |
19 | | - from .language import core |
20 | | - assert len(path) != 0 |
21 | | - prev = iterable if len(path) == 1 else get_iterable_path(iterable, path[:-1]) |
22 | | - assert isinstance(prev, core.tuple) |
23 | | - prev._setitem(path[-1], val) |
24 | | - |
25 | | - |
26 | | -def is_iterable(x): |
27 | | - from .language import core |
28 | | - return isinstance(x, (list, tuple, core.tuple, core.tuple_type)) |
29 | | - |
30 | 8 |
|
31 | 9 | def apply_with_path(value: Any, fn: Callable[[ObjPath, Any], None], _path=None) -> None: |
32 | 10 | if _path is None: |
33 | 11 | _path = () |
34 | 12 |
|
| 13 | + from triton._utils import is_iterable |
35 | 14 | if is_iterable(value): |
36 | 15 | for idx, item in enumerate(value): |
37 | 16 | apply_with_path(item, fn, _path=(*_path, idx)) |
38 | 17 | else: |
39 | 18 | fn(_path, value) |
40 | 19 |
|
41 | 20 |
|
42 | | -def find_paths_if(iterable: Union[IterableType, Any], pred: Callable[[ObjPath, Any], bool]) -> list[ObjPath]: |
43 | | - # We need to use dict so that ordering is maintained, while set doesn't guarantee order |
44 | | - ret: dict[ObjPath, None] = {} |
45 | | - |
46 | | - def _impl(path: tuple[int, ...], current: Any): |
47 | | - if is_iterable(current): |
48 | | - for idx, item in enumerate(current): |
49 | | - _impl((*path, idx), item) |
50 | | - elif pred(path, current): |
51 | | - ret[path] = None |
52 | | - |
53 | | - _impl((), iterable) |
54 | | - |
55 | | - return list(ret.keys()) |
56 | | - |
57 | | - |
58 | | -def is_power_of_two(x): |
59 | | - return (x & (x - 1)) == 0 |
60 | | - |
61 | | - |
62 | | -def validate_block_shape(shape: List[int]): |
63 | | - numel = 1 |
64 | | - for i, d in enumerate(shape): |
65 | | - if not isinstance(d, int): |
66 | | - raise TypeError(f"Shape element {i} must have type `constexpr[int]`, got `constexpr[{type(d)}]") |
67 | | - if not is_power_of_two(d): |
68 | | - raise ValueError(f"Shape element {i} must be a power of 2") |
69 | | - numel *= d |
70 | | - |
71 | | - if numel > TRITON_MAX_TENSOR_NUMEL: |
72 | | - raise ValueError(f"numel ({numel}) exceeds triton maximum tensor numel ({TRITON_MAX_TENSOR_NUMEL})") |
73 | | - return numel |
74 | | - |
75 | | - |
76 | | -type_canonicalisation_dict = { |
77 | | - # we canonicalise all bools to be unsigned: |
78 | | - "bool": "u1", |
79 | | - "int1": "u1", |
80 | | - "uint1": "u1", |
81 | | - "i1": "u1", |
82 | | - # floating-point dtypes: |
83 | | - "float8e4nv": "fp8e4nv", |
84 | | - "float8e5": "fp8e5", |
85 | | - "float8e4b15": "fp8e4b15", |
86 | | - "float8_e4m3fn": "fp8e4nv", |
87 | | - "float8e4b8": "fp8e4b8", |
88 | | - "float8_e4m3fnuz": "fp8e4b8", |
89 | | - "float8_e5m2": "fp8e5", |
90 | | - "float8e5b16": "fp8e5b16", |
91 | | - "float8_e5m2fnuz": "fp8e5b16", |
92 | | - "half": "fp16", |
93 | | - "float16": "fp16", |
94 | | - "bfloat16": "bf16", |
95 | | - "float": "fp32", |
96 | | - "float32": "fp32", |
97 | | - "double": "fp64", |
98 | | - "float64": "fp64", |
99 | | - # signed integers: |
100 | | - "int8": "i8", |
101 | | - "int16": "i16", |
102 | | - "int": "i32", |
103 | | - "int32": "i32", |
104 | | - "int64": "i64", |
105 | | - # unsigned integers: |
106 | | - "uint8": "u8", |
107 | | - "uint16": "u16", |
108 | | - "uint32": "u32", |
109 | | - "uint64": "u64", |
110 | | - "void": "void", |
111 | | -} |
112 | | - |
113 | | -for v in list(type_canonicalisation_dict.values()): |
114 | | - type_canonicalisation_dict[v] = v |
115 | | - |
116 | | - |
117 | | -def canonicalize_dtype(dtype): |
118 | | - dtype_str = str(dtype).split(".")[-1] |
119 | | - return type_canonicalisation_dict[dtype_str] |
120 | | - |
121 | | - |
122 | | -def canonicalize_ptr_dtype(dtype, is_const): |
123 | | - return f"{'*k' if is_const else '*'}{canonicalize_dtype(dtype)}" |
124 | | - |
125 | | - |
126 | | -BITWIDTH_DICT: Dict[str, int] = { |
127 | | - **{f"u{n}": n |
128 | | - for n in (1, 8, 16, 32, 64)}, |
129 | | - **{f"i{n}": n |
130 | | - for n in (1, 8, 16, 32, 64)}, |
131 | | - **{f"fp{n}": n |
132 | | - for n in (16, 32, 64)}, |
133 | | - **{f"fp8{suffix}": 8 |
134 | | - for suffix in ("e4nv", "e4b15", "e4b8", "e5", "e5b16")}, |
135 | | - "bf16": 16, |
136 | | - "void": 0, |
137 | | -} |
138 | | - |
139 | | -for k, v in type_canonicalisation_dict.items(): |
140 | | - BITWIDTH_DICT[k] = BITWIDTH_DICT[v] |
141 | | - |
142 | | - |
143 | | -def get_primitive_bitwidth(dtype: str) -> int: |
144 | | - return BITWIDTH_DICT[dtype] |
145 | | - |
146 | | - |
147 | | -def is_namedtuple(val): |
148 | | - return isinstance(val, type) and issubclass(val, tuple) and hasattr(val, "_fields") |
149 | | - |
150 | | - |
151 | 21 | def _tuple_create(arg, contents): |
152 | 22 | # NamedTuples and tuples have different construction semantics. NamedTuple |
153 | 23 | # has a constructor that takes individual arguments, while tuple takes an |
|
0 commit comments