nvmath-python 0.9.0__cp314-cp314-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (309) hide show
  1. nvmath/__init__.pxd +0 -0
  2. nvmath/__init__.py +45 -0
  3. nvmath/_internal/__init__.py +0 -0
  4. nvmath/_internal/attribute_ifc_factory.py +330 -0
  5. nvmath/_internal/layout.py +70 -0
  6. nvmath/_internal/templates.py +383 -0
  7. nvmath/_utils.py +150 -0
  8. nvmath/bindings/__init__.py +51 -0
  9. nvmath/bindings/_internal/__init__.pxd +0 -0
  10. nvmath/bindings/_internal/__init__.py +0 -0
  11. nvmath/bindings/_internal/cublas.cp314-win_amd64.pyd +0 -0
  12. nvmath/bindings/_internal/cublas.pxd +530 -0
  13. nvmath/bindings/_internal/cublasLt.cp314-win_amd64.pyd +0 -0
  14. nvmath/bindings/_internal/cublasLt.pxd +59 -0
  15. nvmath/bindings/_internal/cublasMp.pxd +52 -0
  16. nvmath/bindings/_internal/cudss.cp314-win_amd64.pyd +0 -0
  17. nvmath/bindings/_internal/cudss.pxd +47 -0
  18. nvmath/bindings/_internal/cufft.cp314-win_amd64.pyd +0 -0
  19. nvmath/bindings/_internal/cufft.pxd +70 -0
  20. nvmath/bindings/_internal/cufftMp.pxd +77 -0
  21. nvmath/bindings/_internal/curand.cp314-win_amd64.pyd +0 -0
  22. nvmath/bindings/_internal/curand.pxd +42 -0
  23. nvmath/bindings/_internal/cusolver.cp314-win_amd64.pyd +0 -0
  24. nvmath/bindings/_internal/cusolver.pxd +15 -0
  25. nvmath/bindings/_internal/cusolverDn.cp314-win_amd64.pyd +0 -0
  26. nvmath/bindings/_internal/cusolverDn.pxd +406 -0
  27. nvmath/bindings/_internal/cusparse.cp314-win_amd64.pyd +0 -0
  28. nvmath/bindings/_internal/cusparse.pxd +277 -0
  29. nvmath/bindings/_internal/cusparseLt.cp314-win_amd64.pyd +0 -0
  30. nvmath/bindings/_internal/cusparseLt.pxd +48 -0
  31. nvmath/bindings/_internal/cutensor.cp314-win_amd64.pyd +0 -0
  32. nvmath/bindings/_internal/cutensor.pxd +58 -0
  33. nvmath/bindings/_internal/mathdx.cp314-win_amd64.pyd +0 -0
  34. nvmath/bindings/_internal/mathdx.pxd +116 -0
  35. nvmath/bindings/_internal/nvshmem.pxd +29 -0
  36. nvmath/bindings/_internal/utils.cp314-win_amd64.pyd +0 -0
  37. nvmath/bindings/_internal/utils.pxd +179 -0
  38. nvmath/bindings/_internal/utils.pyi +10 -0
  39. nvmath/bindings/cublas.cp314-win_amd64.pyd +0 -0
  40. nvmath/bindings/cublas.pxd +558 -0
  41. nvmath/bindings/cublas.pyi +746 -0
  42. nvmath/bindings/cublasLt.cp314-win_amd64.pyd +0 -0
  43. nvmath/bindings/cublasLt.pxd +109 -0
  44. nvmath/bindings/cublasLt.pyi +1337 -0
  45. nvmath/bindings/cublasMp.pxd +85 -0
  46. nvmath/bindings/cublasMp.pyi +219 -0
  47. nvmath/bindings/cudss.cp314-win_amd64.pyd +0 -0
  48. nvmath/bindings/cudss.pxd +86 -0
  49. nvmath/bindings/cudss.pyi +282 -0
  50. nvmath/bindings/cufft.cp314-win_amd64.pyd +0 -0
  51. nvmath/bindings/cufft.pxd +118 -0
  52. nvmath/bindings/cufft.pyi +241 -0
  53. nvmath/bindings/cufftMp.pxd +124 -0
  54. nvmath/bindings/cufftMp.pyi +260 -0
  55. nvmath/bindings/curand.cp314-win_amd64.pyd +0 -0
  56. nvmath/bindings/curand.pxd +71 -0
  57. nvmath/bindings/curand.pyi +159 -0
  58. nvmath/bindings/cusolver.cp314-win_amd64.pyd +0 -0
  59. nvmath/bindings/cusolver.pxd +62 -0
  60. nvmath/bindings/cusolver.pyi +242 -0
  61. nvmath/bindings/cusolverDn.cp314-win_amd64.pyd +0 -0
  62. nvmath/bindings/cusolverDn.pxd +430 -0
  63. nvmath/bindings/cusolverDn.pyi +416 -0
  64. nvmath/bindings/cusparse.cp314-win_amd64.pyd +0 -0
  65. nvmath/bindings/cusparse.pxd +338 -0
  66. nvmath/bindings/cusparse.pyi +659 -0
  67. nvmath/bindings/cusparseLt.cp314-win_amd64.pyd +0 -0
  68. nvmath/bindings/cusparseLt.pxd +99 -0
  69. nvmath/bindings/cusparseLt.pyi +198 -0
  70. nvmath/bindings/cutensor.cp314-win_amd64.pyd +0 -0
  71. nvmath/bindings/cutensor.pxd +98 -0
  72. nvmath/bindings/cutensor.pyi +294 -0
  73. nvmath/bindings/cycublas.cp314-win_amd64.pyd +0 -0
  74. nvmath/bindings/cycublas.pxd +684 -0
  75. nvmath/bindings/cycublasLt.cp314-win_amd64.pyd +0 -0
  76. nvmath/bindings/cycublasLt.pxd +1055 -0
  77. nvmath/bindings/cycublasMp.pxd +183 -0
  78. nvmath/bindings/cycudss.cp314-win_amd64.pyd +0 -0
  79. nvmath/bindings/cycudss.pxd +224 -0
  80. nvmath/bindings/cycufft.cp314-win_amd64.pyd +0 -0
  81. nvmath/bindings/cycufft.pxd +326 -0
  82. nvmath/bindings/cycufftMp.pxd +334 -0
  83. nvmath/bindings/cycurand.cp314-win_amd64.pyd +0 -0
  84. nvmath/bindings/cycurand.pxd +146 -0
  85. nvmath/bindings/cycusolver.cp314-win_amd64.pyd +0 -0
  86. nvmath/bindings/cycusolver.pxd +154 -0
  87. nvmath/bindings/cycusolverDn.cp314-win_amd64.pyd +0 -0
  88. nvmath/bindings/cycusolverDn.pxd +446 -0
  89. nvmath/bindings/cycusparse.cp314-win_amd64.pyd +0 -0
  90. nvmath/bindings/cycusparse.pxd +470 -0
  91. nvmath/bindings/cycusparseLt.cp314-win_amd64.pyd +0 -0
  92. nvmath/bindings/cycusparseLt.pxd +150 -0
  93. nvmath/bindings/cycutensor.cp314-win_amd64.pyd +0 -0
  94. nvmath/bindings/cycutensor.pxd +192 -0
  95. nvmath/bindings/cymathdx.cp314-win_amd64.pyd +0 -0
  96. nvmath/bindings/cymathdx.pxd +552 -0
  97. nvmath/bindings/cynvshmem.pxd +126 -0
  98. nvmath/bindings/mathdx.cp314-win_amd64.pyd +0 -0
  99. nvmath/bindings/mathdx.pxd +182 -0
  100. nvmath/bindings/mathdx.pyi +1244 -0
  101. nvmath/bindings/nvpl/__init__.pxd +0 -0
  102. nvmath/bindings/nvpl/__init__.py +13 -0
  103. nvmath/bindings/nvpl/_internal/__init__.pxd +0 -0
  104. nvmath/bindings/nvpl/_internal/__init__.py +0 -0
  105. nvmath/bindings/nvpl/_internal/blas.cp314-win_amd64.pyd +0 -0
  106. nvmath/bindings/nvpl/_internal/blas.pxd +125 -0
  107. nvmath/bindings/nvpl/_internal/fft.cp314-win_amd64.pyd +0 -0
  108. nvmath/bindings/nvpl/_internal/fft.pxd +36 -0
  109. nvmath/bindings/nvpl/blas.cp314-win_amd64.pyd +0 -0
  110. nvmath/bindings/nvpl/blas.pxd +85 -0
  111. nvmath/bindings/nvpl/blas.pyi +122 -0
  112. nvmath/bindings/nvpl/cyblas.cp314-win_amd64.pyd +0 -0
  113. nvmath/bindings/nvpl/cyblas.pxd +166 -0
  114. nvmath/bindings/nvpl/cyfft.cp314-win_amd64.pyd +0 -0
  115. nvmath/bindings/nvpl/cyfft.pxd +92 -0
  116. nvmath/bindings/nvpl/fft.cp314-win_amd64.pyd +0 -0
  117. nvmath/bindings/nvpl/fft.pxd +100 -0
  118. nvmath/bindings/nvpl/fft.pyi +100 -0
  119. nvmath/bindings/nvshmem.pxd +54 -0
  120. nvmath/bindings/nvshmem.pyi +179 -0
  121. nvmath/device/__init__.py +21 -0
  122. nvmath/device/_deprecated.py +33 -0
  123. nvmath/device/common.py +313 -0
  124. nvmath/device/common_backend.py +131 -0
  125. nvmath/device/common_cuda.py +201 -0
  126. nvmath/device/common_numba.py +310 -0
  127. nvmath/device/common_opaque_tensor.py +201 -0
  128. nvmath/device/cublasdx.py +1805 -0
  129. nvmath/device/cublasdx_backend.py +807 -0
  130. nvmath/device/cublasdx_numba.py +1612 -0
  131. nvmath/device/cufftdx.py +510 -0
  132. nvmath/device/cufftdx_backend.py +196 -0
  133. nvmath/device/cufftdx_numba.py +196 -0
  134. nvmath/device/curand_kernel.py +9147 -0
  135. nvmath/device/cusolverdx.py +2690 -0
  136. nvmath/device/cusolverdx_backend.py +440 -0
  137. nvmath/device/cusolverdx_numba.py +1624 -0
  138. nvmath/device/llvm_array.py +29 -0
  139. nvmath/device/random.py +445 -0
  140. nvmath/device/random_helpers.py +23 -0
  141. nvmath/device/random_states.py +187 -0
  142. nvmath/device/types.py +147 -0
  143. nvmath/device/vector_types_numba.py +203 -0
  144. nvmath/distributed/__init__.py +205 -0
  145. nvmath/distributed/_internal/__init__.py +0 -0
  146. nvmath/distributed/_internal/nvshmem.py +302 -0
  147. nvmath/distributed/_internal/tensor_ifc.py +67 -0
  148. nvmath/distributed/_internal/tensor_ifc_cupy.py +62 -0
  149. nvmath/distributed/_internal/tensor_ifc_host_device.py +165 -0
  150. nvmath/distributed/_internal/tensor_ifc_numpy.py +41 -0
  151. nvmath/distributed/_internal/tensor_ifc_torch.py +141 -0
  152. nvmath/distributed/_internal/tensor_wrapper.py +78 -0
  153. nvmath/distributed/_utils.py +167 -0
  154. nvmath/distributed/distribution.py +770 -0
  155. nvmath/distributed/fft/__init__.py +7 -0
  156. nvmath/distributed/fft/_configuration.py +79 -0
  157. nvmath/distributed/fft/fft.py +2801 -0
  158. nvmath/distributed/linalg/__init__.py +12 -0
  159. nvmath/distributed/linalg/_internal/__init__.py +3 -0
  160. nvmath/distributed/linalg/_internal/epilog_protocol.py +496 -0
  161. nvmath/distributed/linalg/_internal/matmul_desc_ifc.py +28 -0
  162. nvmath/distributed/linalg/advanced/__init__.py +8 -0
  163. nvmath/distributed/linalg/advanced/_configuration.py +166 -0
  164. nvmath/distributed/linalg/advanced/matmulmod.py +2908 -0
  165. nvmath/distributed/process_group.py +408 -0
  166. nvmath/distributed/reshape/__init__.py +6 -0
  167. nvmath/distributed/reshape/_configuration.py +39 -0
  168. nvmath/distributed/reshape/reshape.py +1256 -0
  169. nvmath/fft/__init__.py +7 -0
  170. nvmath/fft/_configuration.py +208 -0
  171. nvmath/fft/_exec_utils.py +109 -0
  172. nvmath/fft/_helpers.py +237 -0
  173. nvmath/fft/fft.py +2903 -0
  174. nvmath/internal/__init__.pxd +3 -0
  175. nvmath/internal/__init__.py +10 -0
  176. nvmath/internal/_bindings.cp314-win_amd64.pyd +0 -0
  177. nvmath/internal/_bindings.pxd +12 -0
  178. nvmath/internal/_device_utils.py +54 -0
  179. nvmath/internal/enum_utils.py +142 -0
  180. nvmath/internal/formatters.py +87 -0
  181. nvmath/internal/mem_limit.py +51 -0
  182. nvmath/internal/memory.cp314-win_amd64.pyd +0 -0
  183. nvmath/internal/memory.pxd +10 -0
  184. nvmath/internal/memory.pyi +46 -0
  185. nvmath/internal/ndbuffer/__init__.pxd +3 -0
  186. nvmath/internal/ndbuffer/__init__.py +7 -0
  187. nvmath/internal/ndbuffer/copy_kernel/args.h +34 -0
  188. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/array_view.h +52 -0
  189. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/elementwise.h +68 -0
  190. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/grid_indexer.h +69 -0
  191. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/transposed.h +240 -0
  192. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/type_utils.h +39 -0
  193. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/utils.h +132 -0
  194. nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/vec.h +159 -0
  195. nvmath/internal/ndbuffer/copy_kernel/elementwise.h +53 -0
  196. nvmath/internal/ndbuffer/copy_kernel/transposed.h +58 -0
  197. nvmath/internal/ndbuffer/copy_kernel.cp314-win_amd64.pyd +0 -0
  198. nvmath/internal/ndbuffer/copy_kernel.pxd +9 -0
  199. nvmath/internal/ndbuffer/copy_kernel.pyi +9 -0
  200. nvmath/internal/ndbuffer/data_layout.cp314-win_amd64.pyd +0 -0
  201. nvmath/internal/ndbuffer/data_layout.pxd +72 -0
  202. nvmath/internal/ndbuffer/data_layout.pyi +23 -0
  203. nvmath/internal/ndbuffer/jit.cp314-win_amd64.pyd +0 -0
  204. nvmath/internal/ndbuffer/jit.pxd +7 -0
  205. nvmath/internal/ndbuffer/jit.pyi +6 -0
  206. nvmath/internal/ndbuffer/ndbuffer.cp314-win_amd64.pyd +0 -0
  207. nvmath/internal/ndbuffer/ndbuffer.pxd +36 -0
  208. nvmath/internal/ndbuffer/ndbuffer.pyi +41 -0
  209. nvmath/internal/ndbuffer/package_utils.cp314-win_amd64.pyd +0 -0
  210. nvmath/internal/ndbuffer/package_utils.pxd +11 -0
  211. nvmath/internal/ndbuffer/package_utils.pyi +12 -0
  212. nvmath/internal/package_ifc.py +147 -0
  213. nvmath/internal/package_ifc_cuda.py +49 -0
  214. nvmath/internal/package_ifc_cupy.py +49 -0
  215. nvmath/internal/package_ifc_torch.py +31 -0
  216. nvmath/internal/package_wrapper.py +14 -0
  217. nvmath/internal/tensor_ifc.py +194 -0
  218. nvmath/internal/tensor_ifc_cupy.py +241 -0
  219. nvmath/internal/tensor_ifc_ndbuffer.py +153 -0
  220. nvmath/internal/tensor_ifc_numpy.py +183 -0
  221. nvmath/internal/tensor_ifc_torch.py +176 -0
  222. nvmath/internal/tensor_wrapper.py +157 -0
  223. nvmath/internal/typemaps.py +162 -0
  224. nvmath/internal/utils.py +771 -0
  225. nvmath/linalg/__init__.py +46 -0
  226. nvmath/linalg/_internal/__init__.py +3 -0
  227. nvmath/linalg/_internal/algo_cap_ifc.py +82 -0
  228. nvmath/linalg/_internal/algo_config_ifc.py +43 -0
  229. nvmath/linalg/_internal/batch.py +217 -0
  230. nvmath/linalg/_internal/enum_to_tuples.py +64 -0
  231. nvmath/linalg/_internal/epilog_protocol.py +766 -0
  232. nvmath/linalg/_internal/layout.py +624 -0
  233. nvmath/linalg/_internal/matmul_desc_ifc.py +28 -0
  234. nvmath/linalg/_internal/matmul_pref_ifc.py +27 -0
  235. nvmath/linalg/_internal/matrix_layout_ifc.py +26 -0
  236. nvmath/linalg/_internal/typemaps.py +144 -0
  237. nvmath/linalg/_internal/utils.py +134 -0
  238. nvmath/linalg/advanced/__init__.py +8 -0
  239. nvmath/linalg/advanced/_algorithmmod.py +149 -0
  240. nvmath/linalg/advanced/_configuration.py +349 -0
  241. nvmath/linalg/advanced/helpers/__init__.py +5 -0
  242. nvmath/linalg/advanced/helpers/matmul.py +1348 -0
  243. nvmath/linalg/advanced/matmulmod.py +3937 -0
  244. nvmath/linalg/generic/__init__.py +43 -0
  245. nvmath/linalg/generic/_configuration/__init__.py +37 -0
  246. nvmath/linalg/generic/_configuration/layout.py +263 -0
  247. nvmath/linalg/generic/_configuration/match.py +609 -0
  248. nvmath/linalg/generic/_configuration/qualifiers.py +494 -0
  249. nvmath/linalg/generic/_configuration/wrap.py +217 -0
  250. nvmath/linalg/generic/_dtype.py +15 -0
  251. nvmath/linalg/generic/matmulmod.py +1060 -0
  252. nvmath/memory.py +282 -0
  253. nvmath/sparse/__init__.py +38 -0
  254. nvmath/sparse/_internal/__init__.py +21 -0
  255. nvmath/sparse/_internal/common_utils.py +144 -0
  256. nvmath/sparse/_internal/cudss_config_ifc.py +741 -0
  257. nvmath/sparse/_internal/cudss_data_ifc.py +399 -0
  258. nvmath/sparse/_internal/cudss_utils.py +445 -0
  259. nvmath/sparse/_internal/cusparse_utils.py +382 -0
  260. nvmath/sparse/_internal/sparse_bsc_ifc.py +300 -0
  261. nvmath/sparse/_internal/sparse_bsr_ifc.py +303 -0
  262. nvmath/sparse/_internal/sparse_coo_ifc.py +254 -0
  263. nvmath/sparse/_internal/sparse_csc_ifc.py +266 -0
  264. nvmath/sparse/_internal/sparse_csr_ifc.py +266 -0
  265. nvmath/sparse/_internal/sparse_dia_ifc.py +239 -0
  266. nvmath/sparse/_internal/sparse_format_helpers.py +601 -0
  267. nvmath/sparse/_internal/sparse_tensor_ifc.py +121 -0
  268. nvmath/sparse/_internal/sparse_ust_ifc.py +146 -0
  269. nvmath/sparse/_internal/utils.py +56 -0
  270. nvmath/sparse/advanced/__init__.py +7 -0
  271. nvmath/sparse/advanced/_configuration.py +230 -0
  272. nvmath/sparse/advanced/direct_solver.py +1884 -0
  273. nvmath/sparse/generic/__init__.py +7 -0
  274. nvmath/sparse/generic/_configuration.py +129 -0
  275. nvmath/sparse/generic/_helpers.py +137 -0
  276. nvmath/sparse/generic/_thunks.py +21 -0
  277. nvmath/sparse/generic/matmulmod.py +2426 -0
  278. nvmath/sparse/ust/__init__.py +7 -0
  279. nvmath/sparse/ust/_converters.py +378 -0
  280. nvmath/sparse/ust/_drawer.py +552 -0
  281. nvmath/sparse/ust/_emitter.py +553 -0
  282. nvmath/sparse/ust/_jit.py +212 -0
  283. nvmath/sparse/ust/_kernel.py +346 -0
  284. nvmath/sparse/ust/_semiring.py +71 -0
  285. nvmath/sparse/ust/_utils.py +102 -0
  286. nvmath/sparse/ust/interfaces/__init__.py +0 -0
  287. nvmath/sparse/ust/interfaces/torch_interface.py +476 -0
  288. nvmath/sparse/ust/semiring_ops.py +71 -0
  289. nvmath/sparse/ust/tensor.py +1027 -0
  290. nvmath/sparse/ust/tensor_drawer.py +552 -0
  291. nvmath/sparse/ust/tensor_emitter.py +558 -0
  292. nvmath/sparse/ust/tensor_format.py +935 -0
  293. nvmath/sparse/ust/tensor_jit.py +212 -0
  294. nvmath/sparse/ust/tensor_kernel.py +348 -0
  295. nvmath/sparse/ust/tensor_utils.py +380 -0
  296. nvmath/tensor/__init__.py +6 -0
  297. nvmath/tensor/_configuration.py +95 -0
  298. nvmath/tensor/_internal/__init__.py +3 -0
  299. nvmath/tensor/_internal/cutensor_config_ifc.py +247 -0
  300. nvmath/tensor/_internal/cutensor_utils.py +162 -0
  301. nvmath/tensor/_internal/data.py +43 -0
  302. nvmath/tensor/_internal/einsum_parser.py +444 -0
  303. nvmath/tensor/_internal/typemaps.py +96 -0
  304. nvmath/tensor/contract.py +1861 -0
  305. nvmath_python-0.9.0.dist-info/METADATA +127 -0
  306. nvmath_python-0.9.0.dist-info/RECORD +309 -0
  307. nvmath_python-0.9.0.dist-info/WHEEL +5 -0
  308. nvmath_python-0.9.0.dist-info/licenses/LICENSE +177 -0
  309. nvmath_python-0.9.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,1612 @@
1
+ # Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ import numbers
6
+ import operator
7
+ from collections.abc import Callable
8
+ from functools import cached_property
9
+
10
+ import llvmlite.ir as llvmir
11
+ import numba
12
+ import numpy
13
+ from numba import cuda
14
+ from numba.core import cgutils, typing
15
+ from numba.core.base import BaseContext
16
+ from numba.core.errors import TypingError
17
+ from numba.core.extending import models
18
+ from numba.cuda.cudaimpl import lower_constant
19
+ from numba.cuda.cudaimpl import registry as cuda_registry
20
+ from numba.cuda.extending import intrinsic, overload, overload_method, typeof_impl
21
+ from numba.cuda.models import StructModel, register_model
22
+ from numba.extending import types, utils
23
+ from numba.np import numpy_support
24
+
25
+ from nvmath.device.common_cuda import get_default_code_type
26
+ from nvmath.device.cublasdx_backend import generate_copy_wait_lto
27
+
28
+ from .common import OpaqueTensor, axpby, clear, copy, copy_fragment, copy_wait, make_fragment_like, make_tensor
29
+ from .common_numba import (
30
+ NUMBA_FE_TYPES_TO_NUMBA_IR,
31
+ EmptyStructModel,
32
+ MathdxOpaqueTensorType,
33
+ MathdxPipelineType,
34
+ cast_to_void_pointer,
35
+ declare_cabi_device,
36
+ get_array_ptr,
37
+ get_value_ptr,
38
+ overload_type_attribute,
39
+ )
40
+ from .common_opaque_tensor import (
41
+ LayoutModel,
42
+ LayoutType,
43
+ OpaqueTensorModel,
44
+ OpaqueTensorType,
45
+ )
46
+ from .cublasdx import (
47
+ DevicePipeline,
48
+ Matmul,
49
+ Partitioner,
50
+ TilePipeline,
51
+ _BlasMatmulLayout,
52
+ _BlasMatmulLikeLayout,
53
+ compile_blas_accumulator_init,
54
+ compile_blas_axpby,
55
+ compile_blas_clear,
56
+ compile_blas_copy,
57
+ compile_blas_device_pipeline_reset_tile,
58
+ compile_blas_execute,
59
+ compile_blas_is_index_in_bounds,
60
+ compile_blas_is_predicated,
61
+ compile_blas_is_thread_active,
62
+ compile_blas_map_idx2crd_partitioner,
63
+ compile_blas_tile_pipeline_destroy,
64
+ compile_blas_tile_pipeline_execute,
65
+ compile_blas_tile_pipeline_init,
66
+ )
67
+
68
+ _BLAS_DEFINITION_ARGS = [
69
+ "size",
70
+ "precision",
71
+ "data_type",
72
+ "sm",
73
+ "block_size",
74
+ "block_dim",
75
+ "leading_dimension",
76
+ "transpose_mode",
77
+ "arrangement",
78
+ "function",
79
+ "execution",
80
+ "alignment",
81
+ "with_pipeline",
82
+ "enable_input_streaming",
83
+ "static_block_dim",
84
+ ]
85
+
86
+ _BLAS_COMPILED_ARGS = [
87
+ "a_value_type",
88
+ "b_value_type",
89
+ "c_value_type",
90
+ # value_type, input_type, and output_type not included intentionally,
91
+ # because they are deprecated.
92
+ "a_dim",
93
+ "b_dim",
94
+ "c_dim",
95
+ "a_size",
96
+ "b_size",
97
+ "c_size",
98
+ "leading_dimension",
99
+ "shared_memory_size",
100
+ "max_threads_per_block",
101
+ ]
102
+
103
+ _DEVICE_PIPELINE_DEFINITION_ARGS = [
104
+ "mm",
105
+ "pipeline_depth",
106
+ "a",
107
+ "b",
108
+ ]
109
+
110
+ _DEVICE_PIPELINE_COMPILED_ARGS = [
111
+ "buffer_alignment",
112
+ "buffer_size",
113
+ "storage_bytes",
114
+ "storage_alignment",
115
+ ]
116
+
117
+ _TILE_PIPELINE_DEFINITION_ARGS = [
118
+ "device_pipeline",
119
+ ]
120
+
121
+ _TILE_PIPELINE_COMPILED_ARGS = [
122
+ "storage_bytes",
123
+ "storage_alignment",
124
+ ]
125
+
126
+
127
+ class BlasType(types.Type):
128
+ """
129
+ Type class associated with the `cublasdx.Matmul`.
130
+ """
131
+
132
+ def __init__(self, blas: Matmul):
133
+ assert isinstance(blas, Matmul)
134
+ self._blas = blas
135
+ attributes = [f"{attr}={getattr(blas, attr)}" for attr in _BLAS_DEFINITION_ARGS if getattr(blas, attr)]
136
+ attributes.sort()
137
+
138
+ self.name = "BlasNumba(" + ",".join(attributes) + ")"
139
+
140
+ @property
141
+ def blas(self) -> Matmul:
142
+ return self._blas
143
+
144
+
145
+ register_model(BlasType)(EmptyStructModel)
146
+
147
+
148
+ @lower_constant(BlasType)
149
+ def constant_dummy(context, builder, typ, pyval):
150
+ struct_ptr = cgutils.create_struct_proxy(typ)(context, builder)
151
+ return struct_ptr._getvalue()
152
+
153
+
154
+ @typeof_impl.register(Matmul)
155
+ def typeof_blas_numba(val: Matmul, c: typing.Context) -> BlasType:
156
+ return BlasType(val)
157
+
158
+
159
+ for attribute in _BLAS_COMPILED_ARGS + _BLAS_DEFINITION_ARGS:
160
+ overload_type_attribute(BlasType, "blas", attribute)
161
+
162
+
163
+ class DevicePipelineType(types.Type):
164
+ """
165
+ Type class associated with the `cublasdx.DevicePipeline`.
166
+ """
167
+
168
+ def __init__(self, pipeline: DevicePipeline):
169
+ assert isinstance(pipeline, DevicePipeline)
170
+ self._pipeline = pipeline
171
+ MM_type = BlasType(pipeline.mm)
172
+ attributes = [
173
+ f"a_layout=(dtype={pipeline.a.dtype},shape={pipeline.a.shape},strides={pipeline.a_strides})",
174
+ f"b_layout=(dtype={pipeline.b.dtype},shape={pipeline.b.shape},strides={pipeline.b_strides})",
175
+ f"pipeline_depth={pipeline.pipeline_depth}",
176
+ f"mm={MM_type}",
177
+ ]
178
+ attributes.sort()
179
+
180
+ self.name = "DevicePipeline(" + ",".join(attributes) + ")"
181
+
182
+ @property
183
+ def _buffer(self):
184
+ return self._pipeline._storage
185
+
186
+ @property
187
+ def pipeline(self) -> DevicePipeline:
188
+ return self._pipeline
189
+
190
+
191
+ class PipelineModel(models.StructModel):
192
+ def __init__(self, dmm, fe_type: DevicePipelineType):
193
+ members = [
194
+ ("ptr", types.voidptr),
195
+ ]
196
+ models.StructModel.__init__(self, dmm, fe_type, members)
197
+
198
+
199
+ register_model(DevicePipelineType)(PipelineModel)
200
+
201
+
202
+ @typeof_impl.register(DevicePipeline)
203
+ def typeof_device_pipeline_numba(val: DevicePipeline, c: typing.Context) -> DevicePipelineType:
204
+ return DevicePipelineType(val)
205
+
206
+
207
+ for attribute in _DEVICE_PIPELINE_DEFINITION_ARGS + _DEVICE_PIPELINE_COMPILED_ARGS:
208
+ overload_type_attribute(DevicePipelineType, "pipeline", attribute)
209
+
210
+
211
+ class TilePipelineType(types.Type):
212
+ """
213
+ Type class associated with the `cublasdx.DevicePipeline`.
214
+ """
215
+
216
+ def __init__(self, pipeline: TilePipeline):
217
+ assert isinstance(pipeline, TilePipeline)
218
+ self._pipeline = pipeline
219
+ device_pipeline_type = DevicePipelineType(pipeline.device_pipeline)
220
+ self.name = f"TilePipeline(device_pipeline={device_pipeline_type})"
221
+
222
+ @property
223
+ def pipeline(self) -> TilePipeline:
224
+ return self._pipeline
225
+
226
+
227
+ register_model(TilePipelineType)(PipelineModel)
228
+
229
+
230
+ @typeof_impl.register(TilePipeline)
231
+ def typeof_tile_pipeline_numba(val: TilePipeline, c: typing.Context) -> TilePipelineType:
232
+ return TilePipelineType(val)
233
+
234
+
235
+ @intrinsic
236
+ def get_mathdx_tensor(typingctx: typing.Context, value):
237
+ """Cast value to MathdxOpaqueTensorType."""
238
+ if not isinstance(value, (OpaqueTensorType, BlasAccumulatorType)):
239
+ raise TypingError("get_mathdx_tensor expects an OpaqueTensorType or BlasAccumulatorType")
240
+
241
+ dynamic_strides_size = getattr(value.layout.layout, "dynamic_strides_size", 0)
242
+ dynamic_shape_size = getattr(value.layout.layout, "dynamic_shape_size", 0)
243
+
244
+ op_ty = MathdxOpaqueTensorType(dynamic_strides_size=dynamic_strides_size, dynamic_shape_size=dynamic_shape_size)
245
+ sig = typing.signature(op_ty, value)
246
+
247
+ def codegen(context: BaseContext, builder, sig, args):
248
+ input = cgutils.create_struct_proxy(sig.args[0])(context, builder, args[0])
249
+ output = cgutils.create_struct_proxy(sig.return_type)(context, builder)
250
+ output.ptr = input.ptr
251
+ if dynamic_strides_size > 0:
252
+ output.strides = input.strides
253
+ if dynamic_shape_size > 0:
254
+ output.shape = input.shape
255
+ return output._getvalue()
256
+
257
+ return sig, codegen
258
+
259
+
260
+ @intrinsic
261
+ def get_mathdx_pipeline(typingctx: typing.Context, value):
262
+ """Cast value to MathdxPipelineType."""
263
+ if not isinstance(value, (DevicePipelineType, TilePipelineType)):
264
+ raise TypingError("get_mathdx_pipeline expects a DevicePipelineType or TilePipelineType")
265
+
266
+ op_ty = MathdxPipelineType()
267
+ sig = typing.signature(op_ty, value)
268
+
269
+ def codegen(context: BaseContext, builder, sig, args):
270
+ input = cgutils.create_struct_proxy(sig.args[0])(context, builder, args[0])
271
+ output = cgutils.create_struct_proxy(sig.return_type)(context, builder)
272
+ output.ptr = input.ptr
273
+ return output._getvalue()
274
+
275
+ return sig, codegen
276
+
277
+
278
+ for attribute in _TILE_PIPELINE_DEFINITION_ARGS + _TILE_PIPELINE_COMPILED_ARGS:
279
+ overload_type_attribute(TilePipelineType, "pipeline", attribute)
280
+
281
+
282
+ @intrinsic
283
+ def _create_tile_pipeline(typingctx: typing.Context, device_pipeline_type: DevicePipelineType):
284
+ """Create a new BLAS tile pipeline object."""
285
+
286
+ tile_pipeline = TilePipeline(device_pipeline_type.pipeline)
287
+ tile_pipeline_type = TilePipelineType(tile_pipeline)
288
+
289
+ return_ty = tile_pipeline_type
290
+ sig = typing.signature(return_ty, device_pipeline_type)
291
+
292
+ def codegen(context: BaseContext, builder, sig, args):
293
+ tile_pipeline_type = sig.return_type
294
+ struct_ptr = cgutils.create_struct_proxy(tile_pipeline_type)(context, builder)
295
+ return struct_ptr._getvalue()
296
+
297
+ return sig, codegen
298
+
299
+
300
+ @intrinsic
301
+ def _set_tile_pipeline_buffer(typingctx: typing.Context, tile_pipeline_type: TilePipelineType, buffer: types.Array):
302
+ """Create a new BLAS tile pipeline object."""
303
+
304
+ return_ty = tile_pipeline_type
305
+ sig = typing.signature(return_ty, tile_pipeline_type, buffer)
306
+
307
+ def codegen(context: BaseContext, builder, sig, args):
308
+ tile_pipeline_type, tile_pipeline = sig.args[0], args[0]
309
+ buffer_type, buffer = sig.args[1], args[1]
310
+ buffer_ptr = cgutils.create_struct_proxy(buffer_type)(context, builder, buffer).data
311
+ struct_ptr = cgutils.create_struct_proxy(tile_pipeline_type)(context, builder, tile_pipeline)
312
+ struct_ptr.ptr = buffer_ptr
313
+
314
+ return struct_ptr._getvalue()
315
+
316
+ return sig, codegen
317
+
318
+
319
+ # Numba does not support method overload or variadic arguments, so we using
320
+ # default values as a workaround
321
+ # https://github.com/numba/numba/issues/9980
322
+ # https://github.com/numba/numba/issues/9979
323
+ # https://github.com/numba/numba/issues/10143
324
+ @overload_method(BlasType, "execute", jit_options={"forceinline": True}, strict=False)
325
+ def ol_blas_numba_execute(
326
+ blas_numba: BlasType, _arg1, _arg2, _arg3, _arg4=None, _arg5=None, _arg6=None, _arg7=None, _arg8=None
327
+ ):
328
+ return ol_blas_numba(blas_numba, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8)
329
+
330
+
331
+ @overload_method(BlasType, "__call__", strict=False)
332
+ def ol_blas_numba_call(blas_numba: BlasType, _arg1, _arg2, _arg3, _arg4=None, _arg5=None, _arg6=None, _arg7=None, _arg8=None):
333
+ return ol_blas_numba(blas_numba, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8)
334
+
335
+
336
+ def ol_blas_numba(blas_numba: BlasType, _arg1, _arg2, _arg3, _arg4=None, _arg5=None, _arg6=None, _arg7=None, _arg8=None):
337
+ none_set = {None, types.Omitted(None)}
338
+ if {_arg4, _arg5, _arg6, _arg7, _arg8} <= none_set:
339
+ return lambda _, a, b, c, _arg4=None, _arg5=None, _arg6=None, _arg7=None, _arg8=None: _bals_type___call__(_, a, b, c)
340
+ elif {_arg6, _arg7, _arg8} <= none_set:
341
+ return lambda _, alpha, a, b, beta, c, _arg6=None, _arg7=None, _arg8=None: _bals_type___call__(_, alpha, a, b, beta, c)
342
+ else:
343
+ return lambda _, alpha, a, lda, b, ldb, beta, c, ldc: _bals_type___call__(_, alpha, a, lda, b, ldb, beta, c, ldc)
344
+
345
+
346
+ # TODO: use overload_method when supported
347
+ def _bals_type___call__(*args):
348
+ raise Exception("Stub for overloads")
349
+
350
+
351
+ def assert_suggested_tensors(tensor_types: tuple[types.Type, ...]):
352
+ """
353
+ Verify that all tensors are suggested or not suggested at the same time.
354
+ """
355
+ suggested_flags = []
356
+ for t in tensor_types:
357
+ assert isinstance(t, (OpaqueTensorType, BlasAccumulatorType))
358
+ layout_type = t.layout
359
+ assert isinstance(layout_type, BlasLayoutType)
360
+ suggested_flags.append(layout_type.layout.suggested)
361
+
362
+ if not all(suggested_flags) and any(suggested_flags):
363
+ raise TypingError("All tensors must be either suggested or not suggested at the same time.")
364
+
365
+
366
+ @overload(_bals_type___call__, jit_options={"forceinline": True}, strict=False)
367
+ def ol_blas_type___call___tensors_rmem(
368
+ blas_numba: BlasType,
369
+ a: OpaqueTensorType,
370
+ b: OpaqueTensorType,
371
+ c: OpaqueTensorType,
372
+ ):
373
+ if not isinstance(blas_numba, BlasType):
374
+ return
375
+ MM = blas_numba.blas
376
+ if not all(isinstance(t, OpaqueTensorType) for t in (a, b)):
377
+ return
378
+ if not (isinstance(c, (OpaqueTensorType, BlasAccumulatorType))):
379
+ return
380
+
381
+ a_layout, b_layout, c_layout = a.layout.layout, b.layout.layout, c.layout.layout
382
+ assert isinstance(a_layout, _BlasMatmulLayout)
383
+ assert isinstance(b_layout, _BlasMatmulLayout)
384
+ assert isinstance(c_layout, _BlasMatmulLayout)
385
+
386
+ if c_layout.memory_space != "r" and not c_layout.accumulator:
387
+ return
388
+
389
+ assert_suggested_tensors((a, b, c))
390
+
391
+ return_type = types.void
392
+ mathdx_a = MathdxOpaqueTensorType(a_layout.dynamic_strides_size, a_layout.dynamic_shape_size)
393
+ mathdx_b = MathdxOpaqueTensorType(b_layout.dynamic_strides_size, b_layout.dynamic_shape_size)
394
+ mathdx_c = MathdxOpaqueTensorType(c_layout.dynamic_strides_size, c_layout.dynamic_shape_size)
395
+ sig = typing.signature(return_type, mathdx_a, mathdx_b, mathdx_c)
396
+
397
+ code, symbol = compile_blas_execute(
398
+ MM,
399
+ code_type=get_default_code_type(),
400
+ execute_api="tensors",
401
+ tensor_types=(a_layout.tensor_type, b_layout.tensor_type, c_layout.tensor_type),
402
+ )
403
+
404
+ lto = cuda.LTOIR(code.data)
405
+ blas_device_func = declare_cabi_device(symbol, sig, link=lto)
406
+
407
+ def impl(_, a, b, c):
408
+ blas_device_func(get_mathdx_tensor(a), get_mathdx_tensor(b), get_mathdx_tensor(c))
409
+
410
+ return impl
411
+
412
+
413
+ @overload(_bals_type___call__, jit_options={"forceinline": True}, strict=False)
414
+ def ol_blas_type___call___tensors_smem(
415
+ blas_numba: BlasType,
416
+ alpha: types.Number,
417
+ a: OpaqueTensorType,
418
+ b: OpaqueTensorType,
419
+ beta: types.Number,
420
+ c: OpaqueTensorType,
421
+ ):
422
+ if not isinstance(blas_numba, BlasType):
423
+ return
424
+ MM = blas_numba.blas
425
+ if not all(isinstance(a, types.Number) for a in (alpha, beta)):
426
+ return
427
+ if not all(isinstance(a, OpaqueTensorType) for a in (a, b, c)):
428
+ return
429
+ a_layout, b_layout, c_layout = a.layout.layout, b.layout.layout, c.layout.layout
430
+ assert isinstance(a_layout, _BlasMatmulLayout)
431
+ assert isinstance(b_layout, _BlasMatmulLayout)
432
+ assert isinstance(c_layout, _BlasMatmulLayout)
433
+ if c_layout.memory_space != "s":
434
+ return
435
+
436
+ return_type = types.void
437
+ mathdx_a = MathdxOpaqueTensorType(a_layout.dynamic_strides_size, a_layout.dynamic_shape_size)
438
+ mathdx_b = MathdxOpaqueTensorType(b_layout.dynamic_strides_size, b_layout.dynamic_shape_size)
439
+ mathdx_c = MathdxOpaqueTensorType(c_layout.dynamic_strides_size, c_layout.dynamic_shape_size)
440
+ c_ptr = types.CPointer(c.dtype)
441
+ sig = typing.signature(return_type, c_ptr, mathdx_a, mathdx_b, c_ptr, mathdx_c)
442
+
443
+ code, symbol = compile_blas_execute(
444
+ MM,
445
+ code_type=get_default_code_type(),
446
+ execute_api="tensors",
447
+ tensor_types=(a_layout.tensor_type, b_layout.tensor_type, c_layout.tensor_type),
448
+ )
449
+
450
+ lto = cuda.LTOIR(code.data)
451
+ blas_device_func = declare_cabi_device(symbol, sig, link=lto)
452
+
453
+ dtype = c.dtype
454
+
455
+ def impl(_, alpha, a, b, beta, c):
456
+ alpha_ptr = get_value_ptr(dtype(alpha))
457
+ beta_ptr = get_value_ptr(dtype(beta))
458
+
459
+ blas_device_func(alpha_ptr, get_mathdx_tensor(a), get_mathdx_tensor(b), beta_ptr, get_mathdx_tensor(c))
460
+
461
+ return impl
462
+
463
+
464
+ @overload(_bals_type___call__, jit_options={"forceinline": True}, strict=False)
465
+ def ol_blas_type___call___basic(
466
+ blas_numba: BlasType,
467
+ alpha: types.Number,
468
+ a: types.Array,
469
+ b: types.Array,
470
+ beta: types.Number,
471
+ c: types.Array,
472
+ ):
473
+ if not isinstance(blas_numba, BlasType):
474
+ return
475
+ MM = blas_numba.blas
476
+ if not all(isinstance(a, types.Number) for a in (alpha, beta)):
477
+ return
478
+ if not all(isinstance(a, types.Array) for a in (a, b, c)):
479
+ return
480
+ if (a.dtype, b.dtype, c.dtype) != tuple(NUMBA_FE_TYPES_TO_NUMBA_IR[vt] for vt in MM._traits.value_types):
481
+ return
482
+
483
+ # setting signature for intrinsic to much calling conventions. Numba will
484
+ # automatically cast to desired values.
485
+ return_type = types.void
486
+ c_ptr = types.CPointer(c.dtype)
487
+ sig = typing.signature(return_type, c_ptr, types.CPointer(a.dtype), types.CPointer(b.dtype), c_ptr, c_ptr)
488
+
489
+ code, symbol = compile_blas_execute(
490
+ MM,
491
+ code_type=get_default_code_type(),
492
+ execute_api="static_leading_dimensions",
493
+ )
494
+
495
+ lto = cuda.LTOIR(code.data)
496
+
497
+ blas_device_func = declare_cabi_device(symbol, sig, link=lto)
498
+
499
+ def impl(_, alpha, a, b, beta, c):
500
+ aptr = get_array_ptr(a)
501
+ bptr = get_array_ptr(b)
502
+ cptr = get_array_ptr(c)
503
+ alpha = get_value_ptr(c.dtype.type(alpha))
504
+ beta = get_value_ptr(c.dtype.type(beta))
505
+
506
+ blas_device_func(alpha, aptr, bptr, beta, cptr)
507
+
508
+ return impl
509
+
510
+
511
+ @overload(_bals_type___call__, jit_options={"forceinline": True}, strict=False)
512
+ def ol_blas_type___call___ldabc(
513
+ blas_numba: BlasType,
514
+ alpha: types.Number,
515
+ a: types.Array,
516
+ lda: types.Integer,
517
+ b: types.Array,
518
+ ldb: types.Integer,
519
+ beta: types.Number,
520
+ c: types.Array,
521
+ ldc: types.Integer,
522
+ ):
523
+ if not isinstance(blas_numba, BlasType):
524
+ return
525
+ MM = blas_numba.blas
526
+ if not all(isinstance(a, types.Number) for a in (alpha, beta)):
527
+ return
528
+ if not all(isinstance(a, types.Array) for a in (a, b, c)):
529
+ return
530
+ if (a.dtype, b.dtype, c.dtype) != tuple(NUMBA_FE_TYPES_TO_NUMBA_IR[vt] for vt in MM._traits.value_types):
531
+ return
532
+ if not all(isinstance(a, types.Integer) for a in (lda, ldb, ldc)):
533
+ return
534
+
535
+ ld_type = types.uint32
536
+ ld_ptr = types.CPointer(ld_type)
537
+ return_type = types.void
538
+ c_ptr = types.CPointer(c.dtype)
539
+ sig = typing.signature(
540
+ return_type, c_ptr, types.CPointer(a.dtype), ld_ptr, types.CPointer(b.dtype), ld_ptr, c_ptr, c_ptr, ld_ptr
541
+ )
542
+
543
+ code, symbol = compile_blas_execute(
544
+ MM,
545
+ code_type=get_default_code_type(),
546
+ execute_api="dynamic_leading_dimensions",
547
+ )
548
+
549
+ lto = cuda.LTOIR(code.data)
550
+ blas_device_func = declare_cabi_device(symbol, sig, link=lto)
551
+
552
+ def impl(_, alpha, a, lda, b, ldb, beta, c, ldc):
553
+ aptr = get_array_ptr(a)
554
+ bptr = get_array_ptr(b)
555
+ cptr = get_array_ptr(c)
556
+ alpha = get_value_ptr(c.dtype.type(alpha))
557
+ beta = get_value_ptr(c.dtype.type(beta))
558
+ lda = get_value_ptr(ld_type(lda))
559
+ ldb = get_value_ptr(ld_type(ldb))
560
+ ldc = get_value_ptr(ld_type(ldc))
561
+
562
+ blas_device_func(alpha, aptr, lda, bptr, ldb, beta, cptr, ldc)
563
+
564
+ return impl
565
+
566
+
567
+ # __call__ overload is not supported by numba, however adding this overload
568
+ # kind of activates proper behaviour and works like magic.
569
+ # Issue reference: https://github.com/numba/numba/issues/5885
570
+ # TODO: remove once supported
571
+ @cuda_registry.lower(BlasType, BlasType, types.VarArg(types.Any))
572
+ def method_impl(context, builder, sig, args):
573
+ typing_context = context.typing_context
574
+ fnty = typing_context.resolve_value_type(ol_blas_numba_call)
575
+ sig = fnty.get_call_type(typing_context, sig.args, {})
576
+ sig = sig.replace(pysig=utils.pysignature(ol_blas_numba_call))
577
+
578
+ call = context.get_function(fnty, sig)
579
+ # Link dependent library
580
+ context.add_linking_libs(getattr(call, "libs", ()))
581
+ return call(builder, args)
582
+
583
+
584
+ @overload(copy, jit_options={"forceinline": True}, strict=False)
585
+ def ol_blas_copy(src: OpaqueTensorType, dst: OpaqueTensorType, alignment=None):
586
+ return ol_blas_copy_generic(src, dst, alignment, "copy")
587
+
588
+
589
+ @overload(copy_fragment, jit_options={"forceinline": True}, strict=False)
590
+ def ol_blas_copy_fragment(src: OpaqueTensorType, dst: OpaqueTensorType, alignment=None):
591
+ return ol_blas_copy_generic(src, dst, alignment, "copy_fragment")
592
+
593
+
594
+ def ol_blas_copy_generic(src: OpaqueTensorType, dst: OpaqueTensorType, alignment_ty: types.Type | None, func: str):
595
+ assert isinstance(src, (OpaqueTensorType, BlasAccumulatorType))
596
+ assert isinstance(dst, OpaqueTensorType)
597
+ src_layout_ty = src.layout
598
+ dst_layout_ty = dst.layout
599
+ assert isinstance(src_layout_ty, BlasLayoutType)
600
+ assert isinstance(dst_layout_ty, BlasLayoutType)
601
+
602
+ alignment: int | None = None
603
+ if alignment_ty not in {None, types.Omitted(None)}:
604
+ if not isinstance(alignment_ty, types.Literal):
605
+ return lambda src, dst, alignment: numba.literally(alignment)
606
+ alignment = alignment_ty.literal_value
607
+ if alignment not in {1, 2, 4, 8, 16}:
608
+ raise TypingError(f"Alignment must be one of (1, 2, 4, 8, 16), got {alignment}")
609
+
610
+ rmem = dst_layout_ty.layout.memory_space == "r" or src_layout_ty.layout.memory_space == "r"
611
+
612
+ if func == "copy_fragment":
613
+ if not rmem:
614
+ raise TypingError("copy_fragment is only supported for rmem tensors. Please use copy instead.")
615
+ else:
616
+ assert func == "copy"
617
+ if rmem:
618
+ raise TypingError("copy is not supported for rmem tensors. Please use copy_fragment instead.")
619
+
620
+ if alignment is not None:
621
+ dtype = numpy_support.as_dtype(src.layout.dtype)
622
+ if alignment < dtype.itemsize:
623
+ raise TypingError(f"Alignment must be at least the size of the data type {dtype.itemsize}, got {alignment}")
624
+
625
+ code, symbol = compile_blas_copy(
626
+ src_tensor=src_layout_ty.layout,
627
+ dst_tensor=dst_layout_ty.layout,
628
+ code_type=get_default_code_type(),
629
+ alignment=alignment,
630
+ )
631
+
632
+ return_type = types.void
633
+ mathdx_src = MathdxOpaqueTensorType(src_layout_ty.layout.dynamic_strides_size, src_layout_ty.layout.dynamic_shape_size)
634
+ mathdx_dst = MathdxOpaqueTensorType(dst_layout_ty.layout.dynamic_strides_size, dst_layout_ty.layout.dynamic_shape_size)
635
+ sig = typing.signature(return_type, mathdx_src, mathdx_dst)
636
+
637
+ lto = cuda.LTOIR(code.data)
638
+ blas_device_func = declare_cabi_device(symbol, sig, link=lto)
639
+
640
+ def impl(src, dst, alignment=None):
641
+ return blas_device_func(get_mathdx_tensor(src), get_mathdx_tensor(dst))
642
+
643
+ return impl
644
+
645
+
646
+ @overload(clear, jit_options={"forceinline": True}, strict=False)
647
+ def ol_blas_clear(arr: OpaqueTensorType):
648
+ assert isinstance(arr, OpaqueTensorType)
649
+ assert isinstance(arr.layout, BlasLayoutType)
650
+
651
+ code, symbol = compile_blas_clear(
652
+ tensor=arr.layout.layout,
653
+ code_type=get_default_code_type(),
654
+ )
655
+
656
+ lto = cuda.LTOIR(code.data)
657
+
658
+ return_type = types.void
659
+ mathdx_arr = MathdxOpaqueTensorType(arr.layout.layout.dynamic_strides_size, arr.layout.layout.dynamic_shape_size)
660
+ sig = typing.signature(return_type, mathdx_arr)
661
+ blas_device_func = declare_cabi_device(symbol, sig, link=lto)
662
+
663
+ def impl(arr):
664
+ return blas_device_func(get_mathdx_tensor(arr))
665
+
666
+ return impl
667
+
668
+
669
+ class BlasLayoutType(LayoutType):
670
+ """
671
+ Type class associated with opaque tensor layouts.
672
+ """
673
+
674
+ def __init__(self, layout: _BlasMatmulLayout):
675
+ assert isinstance(layout, _BlasMatmulLayout)
676
+ super().__init__(layout)
677
+ # Using handle descriptor in the type name to avoid symbol copy caching
678
+ # by numba.
679
+ MM_type = BlasType(layout.MM)
680
+ self.name = f"BlasLayout(uid={layout.uid},layout={layout.layout},dtype={layout.dtype},MM={MM_type})"
681
+
682
+ @property
683
+ def layout(self) -> _BlasMatmulLayout:
684
+ assert isinstance(self._layout, _BlasMatmulLayout)
685
+ return self._layout
686
+
687
+ def make_layout_like(self, dtype: numpy.number) -> "BlasLayoutType":
688
+ src_layout = self.layout
689
+ dst_layout = _BlasMatmulLikeLayout(
690
+ src_layout.MM,
691
+ src_layout.layout,
692
+ dtype,
693
+ leading_dimension=src_layout._default_ld,
694
+ )
695
+
696
+ return BlasLayoutType(dst_layout)
697
+
698
+
699
+ register_model(BlasLayoutType)(LayoutModel)
700
+
701
+
702
+ def lower_blas_layout_codegen(
703
+ context: BaseContext,
704
+ builder: llvmir.IRBuilder,
705
+ layout_type: BlasLayoutType,
706
+ ld_val: llvmir.NamedValue | numbers.Number | None,
707
+ ld_type: types.Type | None = None,
708
+ ):
709
+ layout = cgutils.create_struct_proxy(layout_type)(context, builder)
710
+ if layout_type.layout.dynamic_strides_size > 0:
711
+ assert layout_type.layout.dynamic_strides_size == 1
712
+ if ld_val is None:
713
+ # Use default MM ld when value is not provided
714
+ ld_val = layout_type.layout.MM.leading_dimension[layout_type.layout.tensor_index]
715
+ if isinstance(ld_val, numbers.Number):
716
+ ld = context.get_constant(types.int64, ld_val)
717
+ else:
718
+ ld = context.cast(builder, ld_val, ld_type, types.int64)
719
+ layout.strides = cgutils.pack_array(builder, [ld])
720
+ else:
721
+ assert ld_val is None
722
+ return layout._getvalue()
723
+
724
+
725
+ @lower_constant(BlasLayoutType)
726
+ def constant_blas_layout(context, builder, typ, pyval):
727
+ assert isinstance(typ, BlasLayoutType)
728
+ assert isinstance(pyval, _BlasMatmulLayout)
729
+ return lower_blas_layout_codegen(context, builder, typ, pyval.default_ld)
730
+
731
+
732
+ @typeof_impl.register(_BlasMatmulLayout)
733
+ def typeof_blas_mm_layout(layout: _BlasMatmulLayout, c: typing.Context) -> BlasLayoutType:
734
+ # We are clearing ld from the layout because it is a runtime value.
735
+ layout_no_ld = _BlasMatmulLayout(layout.MM, layout.layout)
736
+ return BlasLayoutType(layout_no_ld)
737
+
738
+
739
+ @typeof_impl.register(_BlasMatmulLikeLayout)
740
+ def typeof_blas_mm_like_layout(layout: _BlasMatmulLikeLayout, c: typing.Context) -> BlasLayoutType:
741
+ # We are clearing ld from the layout because it is a runtime value.
742
+ layout_no_ld = _BlasMatmulLikeLayout(layout.MM, layout.layout, layout.dtype)
743
+ return BlasLayoutType(layout_no_ld)
744
+
745
+
746
+ for attribute in ["size", "cosize", "alignment"]:
747
+ overload_type_attribute(BlasLayoutType, "_layout", attribute)
748
+
749
+
750
+ def ol_blas_layout(blas_numba: BlasType, method: str, leading_dimension: types.Number | None = None):
751
+ # leading_dimension is available only for global memory
752
+ if ("gmem" not in method) and (leading_dimension not in {None, types.Omitted(None)}):
753
+ return
754
+ MM = blas_numba.blas
755
+
756
+ layout = getattr(MM, method)()
757
+ return_type = BlasLayoutType(layout)
758
+
759
+ @intrinsic
760
+ def _intrinsic(typingctx, leading_dimension=None):
761
+ def codegen(context: BaseContext, builder: llvmir.IRBuilder, signature, args):
762
+ ld = args[0] if not isinstance(leading_dimension, types.NoneType) else None
763
+ ld_type = signature.args[0] if ld is not None else None
764
+ return lower_blas_layout_codegen(context, builder, return_type, ld, ld_type)
765
+
766
+ return typing.signature(return_type, leading_dimension), codegen
767
+
768
+ return lambda blas_numba, leading_dimension=None: _intrinsic(leading_dimension)
769
+
770
+
771
+ def overload_blas_layout_method(method: str):
772
+ overload_method(
773
+ BlasType,
774
+ method,
775
+ jit_options={"forceinline": True},
776
+ strict=False,
777
+ )(lambda blas_numba, leading_dimension=None: ol_blas_layout(blas_numba, method, leading_dimension))
778
+
779
+
780
+ for method in [
781
+ "get_layout_smem_a",
782
+ "get_layout_smem_b",
783
+ "get_layout_smem_c",
784
+ "get_layout_gmem_a",
785
+ "get_layout_gmem_b",
786
+ "get_layout_gmem_c",
787
+ "suggest_layout_smem_a",
788
+ "suggest_layout_smem_b",
789
+ "suggest_layout_smem_c",
790
+ "suggest_layout_rmem_c",
791
+ "get_layout_rmem_c",
792
+ "_get_accumulator_c",
793
+ "_suggest_accumulator_c",
794
+ ]:
795
+ overload_blas_layout_method(method)
796
+
797
+
798
+ @overload(make_tensor, jit_options={"forceinline": True}, strict=False)
799
+ def ol_make_tensor(array, layout):
800
+ assert isinstance(array, types.Array)
801
+ assert isinstance(layout, BlasLayoutType)
802
+
803
+ if array.dtype == layout.dtype:
804
+ return lambda array, layout: OpaqueTensor(array, layout)
805
+ else:
806
+
807
+ @intrinsic
808
+ def copy_strides(typingctx, array_type, layout_type):
809
+ def codegen(context: BaseContext, builder: llvmir.IRBuilder, signature, args):
810
+ array_type, layout_type = signature.args
811
+ array = cgutils.create_struct_proxy(array_type)(context, builder, args[0])
812
+ layout = cgutils.create_struct_proxy(layout_type)(context, builder, args[1])
813
+ if array_type.layout.layout.dynamic_strides_size > 0:
814
+ array.strides = layout.strides
815
+ return array._getvalue()
816
+
817
+ return typing.signature(array_type, array_type, layout_type), codegen
818
+
819
+ np_dtype = numpy.dtype(numpy_support.as_dtype(array.dtype)).type
820
+ dst_layout_ty = layout.make_layout_like(np_dtype)
821
+ dst_layout = dst_layout_ty.layout
822
+
823
+ def impl(array, layout):
824
+ tensor = OpaqueTensor(array, dst_layout)
825
+ return copy_strides(tensor, layout)
826
+
827
+ return impl
828
+
829
+
830
+ @overload(make_fragment_like, inline="always", strict=False)
831
+ def ol_make_fragment_like(tensor, dtype):
832
+ assert isinstance(tensor, OpaqueTensorType)
833
+ layout = tensor.layout
834
+ assert isinstance(layout, BlasLayoutType)
835
+ assert layout.layout.memory_space == "r"
836
+
837
+ assert isinstance(dtype, types.NumberClass)
838
+ np_dtype = numpy.dtype(numpy_support.as_dtype(dtype)).type
839
+
840
+ dst_layout_ty = layout.make_layout_like(np_dtype)
841
+ dst_layout = dst_layout_ty.layout
842
+
843
+ def impl(tensor, dtype):
844
+ buff = cuda.local.array(dst_layout.cosize, dtype=dtype, alignment=dst_layout.alignment)
845
+ return OpaqueTensor(buff, dst_layout)
846
+
847
+ return impl
848
+
849
+
850
+ @overload(copy_wait, jit_options={"forceinline": True}, strict=False)
851
+ def ol_copy_wait():
852
+ # numba has cache per compute capability, so the function won't end up
853
+ # cached for the wrong compute capability.
854
+ return_type = types.void
855
+ sig = typing.signature(return_type)
856
+
857
+ ct = get_default_code_type()
858
+ symbol, code = generate_copy_wait_lto(ct.cc)
859
+
860
+ lto = cuda.LTOIR(code)
861
+ blas_device_func = declare_cabi_device(symbol, sig, link=lto)
862
+
863
+ return lambda: blas_device_func()
864
+
865
+
866
+ @overload(axpby, jit_options={"forceinline": True}, strict=False)
867
+ def ol_axpby(a, x, b, y):
868
+ if not isinstance(a, types.Number):
869
+ return
870
+ if not isinstance(x, OpaqueTensorType):
871
+ return
872
+ if not isinstance(b, types.Number):
873
+ return
874
+ if not isinstance(y, OpaqueTensorType):
875
+ return
876
+ if x.layout.layout.memory_space != "r":
877
+ raise TypeError("axpby is only supported for rmem tensors. x is not")
878
+ if y.layout.layout.memory_space != "r":
879
+ raise TypeError("axpby is only supported for rmem tensors. y is not")
880
+
881
+ code, symbol = compile_blas_axpby(
882
+ x_tensor=x.layout.layout,
883
+ y_tensor=y.layout.layout,
884
+ code_type=get_default_code_type(),
885
+ )
886
+
887
+ lto = cuda.LTOIR(code.data)
888
+
889
+ return_type = types.void
890
+ alpha_beta_ptr = types.CPointer(types.uint8)
891
+ mathdx_x = MathdxOpaqueTensorType(x.layout.layout.dynamic_strides_size, x.layout.layout.dynamic_shape_size)
892
+ mathdx_y = MathdxOpaqueTensorType(y.layout.layout.dynamic_strides_size, y.layout.layout.dynamic_shape_size)
893
+ sig = typing.signature(return_type, alpha_beta_ptr, mathdx_x, alpha_beta_ptr, mathdx_y)
894
+ blas_device_func = declare_cabi_device(symbol, sig, link=lto)
895
+
896
+ x_dtype = x.dtype
897
+ y_dtype = y.dtype
898
+
899
+ def impl(a, x, b, y):
900
+ a_ptr = cast_to_void_pointer(get_value_ptr(x_dtype(a)))
901
+ b_ptr = cast_to_void_pointer(get_value_ptr(y_dtype(b)))
902
+ return blas_device_func(a_ptr, get_mathdx_tensor(x), b_ptr, get_mathdx_tensor(y))
903
+
904
+ return impl
905
+
906
+
907
+ class BlasPartitionerType(types.Type):
908
+ """
909
+ Type class for Blas partitioner.
910
+ """
911
+
912
+ def __init__(self, MM: Matmul, suggested: bool):
913
+ assert isinstance(MM, Matmul)
914
+ self._MM = MM
915
+ mm_type = BlasType(MM)
916
+ self._suggested = suggested
917
+ super().__init__(f"BlasPartitioner(MM={mm_type}, suggested={suggested})")
918
+
919
+ @property
920
+ def MM(self) -> Matmul:
921
+ return self._MM
922
+
923
+ @property
924
+ def suggested(self) -> bool:
925
+ return self._suggested
926
+
927
+ @property
928
+ def dtype(self) -> types.Number:
929
+ return NUMBA_FE_TYPES_TO_NUMBA_IR[self._MM._traits.value_types[2]]
930
+
931
+ @property
932
+ def fragment_layout(self) -> BlasLayoutType:
933
+ MM = self.MM
934
+ if self.suggested:
935
+ layout = MM.suggest_layout_rmem_c()
936
+ else:
937
+ layout = MM.get_layout_rmem_c()
938
+
939
+ assert isinstance(layout, _BlasMatmulLayout)
940
+
941
+ return BlasLayoutType(layout)
942
+
943
+
944
+ @register_model(BlasPartitionerType)
945
+ class PartitionerModel(StructModel):
946
+ def __init__(self, dmm, fe_type: BlasPartitionerType):
947
+ StructModel.__init__(self, dmm, fe_type, [])
948
+
949
+
950
+ class BlasAccumulatorType(BlasPartitionerType):
951
+ """
952
+ Type class for Blas partitioner.
953
+ """
954
+
955
+ def __init__(self, MM: Matmul, suggested: bool):
956
+ super().__init__(MM, suggested)
957
+ mm = BlasType(MM)
958
+ self.name = f"BlasAccumulator(MM={mm}, suggested={suggested})"
959
+
960
+ @cached_property
961
+ def layout(self) -> BlasLayoutType:
962
+ if self._suggested:
963
+ layout = self._MM._suggest_accumulator_c()
964
+ else:
965
+ layout = self._MM._get_accumulator_c()
966
+
967
+ assert isinstance(layout, _BlasMatmulLayout)
968
+
969
+ return BlasLayoutType(layout)
970
+
971
+
972
+ register_model(BlasAccumulatorType)(OpaqueTensorModel)
973
+
974
+
975
+ def ol_blas_get_accumulator_generic(blas_numba: BlasType, suggested: bool):
976
+ assert isinstance(blas_numba, BlasType)
977
+
978
+ MM = blas_numba.blas
979
+ return_type = BlasAccumulatorType(MM, suggested=suggested)
980
+ opaque_tensor_type = OpaqueTensorType(return_type.layout)
981
+
982
+ @intrinsic
983
+ def _type_cast_ot_acc(typingctx, opaque_tensor):
984
+ def codegen(context: BaseContext, builder: llvmir.IRBuilder, signature, args):
985
+ return args[0]
986
+
987
+ return typing.signature(return_type, opaque_tensor_type), codegen
988
+
989
+ if suggested:
990
+ acc_layout = MM._suggest_accumulator_c()
991
+ else:
992
+ acc_layout = MM._get_accumulator_c()
993
+
994
+ alignment = max(acc_layout.alignment, 8)
995
+
996
+ def impl(mm: Matmul):
997
+ buff = cuda.local.array(acc_layout.cosize, dtype=mm.c_value_type, alignment=alignment)
998
+ tensor = make_tensor(buff, acc_layout)
999
+ clear(tensor)
1000
+ acc = _type_cast_ot_acc(tensor)
1001
+ acc._init()
1002
+ return acc
1003
+
1004
+ return impl
1005
+
1006
+
1007
+ @overload_method(BlasType, "suggest_accumulator", inline="always", strict=False)
1008
+ def ol_blas_suggest_accumulator(blas_numba: BlasType):
1009
+ return ol_blas_get_accumulator_generic(blas_numba, suggested=True)
1010
+
1011
+
1012
+ @overload_method(BlasType, "get_accumulator", inline="always", strict=False)
1013
+ def ol_blas_get_accumulator(blas_numba: BlasType):
1014
+ return ol_blas_get_accumulator_generic(blas_numba, suggested=False)
1015
+
1016
+
1017
+ @overload_method(BlasPartitionerType, "partition_like_C", jit_options={"forceinline": True}, strict=False)
1018
+ def ol_blas_partition_like_C(partitioner: BlasPartitionerType, tensor: OpaqueTensorType):
1019
+ assert isinstance(partitioner, BlasPartitionerType)
1020
+ assert isinstance(tensor, OpaqueTensorType)
1021
+ assert isinstance(tensor.layout, BlasLayoutType)
1022
+ assert tensor.layout.layout.tensor_type == "gmem_c"
1023
+
1024
+ raise NotImplementedError("Blas partition_like_C is not yet implemented, please use map_fragment_index instead")
1025
+
1026
+
1027
+ def get_map_idx2crd_partitioner(symbol: str, lto: cuda.LTOIR):
1028
+ assert isinstance(symbol, str)
1029
+ return_type = types.Tuple((types.int32, types.int32))
1030
+
1031
+ @intrinsic
1032
+ def map_idx2crd_partitioner(typingctx, index):
1033
+ def codegen(context: BaseContext, builder: llvmir.IRBuilder, signature, args):
1034
+ context.active_code_library.add_linking_file(lto)
1035
+ idx: llvmir.AllocaInstr = args[0]
1036
+ i_ptr = cgutils.alloca_once(builder, cgutils.int32_t)
1037
+ j_ptr = cgutils.alloca_once(builder, cgutils.int32_t)
1038
+ idx_ptr = cgutils.alloca_once_value(builder, idx)
1039
+
1040
+ int32_ptr = cgutils.int32_t.as_pointer()
1041
+
1042
+ fnTy = llvmir.FunctionType(cgutils.voidptr_t, [int32_ptr, int32_ptr, int32_ptr])
1043
+ fn = cgutils.get_or_insert_function(builder.module, fnTy, symbol)
1044
+ builder.call(fn, [idx_ptr, i_ptr, j_ptr])
1045
+
1046
+ return context.make_tuple(builder, return_type, (builder.load(i_ptr), builder.load(j_ptr)))
1047
+
1048
+ return typing.signature(return_type, types.int32), codegen
1049
+
1050
+ return map_idx2crd_partitioner
1051
+
1052
+
1053
+ @overload_method(
1054
+ BlasPartitionerType,
1055
+ "map_fragment_index",
1056
+ jit_options={"forceinline": True},
1057
+ strict=False,
1058
+ )
1059
+ def ol_blas_partitioner_map_fragment_index(
1060
+ partitioner: BlasPartitionerType,
1061
+ index: types.Integer,
1062
+ ):
1063
+ if not isinstance(partitioner, BlasPartitionerType):
1064
+ return
1065
+ if not isinstance(index, types.Integer):
1066
+ return
1067
+
1068
+ code, symbol = compile_blas_map_idx2crd_partitioner(partitioner.MM, code_type=get_default_code_type())
1069
+
1070
+ lto = cuda.LTOIR(code.data)
1071
+
1072
+ map_idx2crd_partitioner = get_map_idx2crd_partitioner(symbol, lto=lto)
1073
+
1074
+ def map_fragment_index_impl(obj, idx):
1075
+ i, j = map_idx2crd_partitioner(idx)
1076
+ return (i, j)
1077
+
1078
+ return map_fragment_index_impl
1079
+
1080
+
1081
+ def get_bool_return_intrinsic(symbol: str, index: bool = False, lto=None):
1082
+ return_type = types.bool
1083
+
1084
+ def codegen(context: BaseContext, builder: llvmir.IRBuilder, signature, args: list):
1085
+ if lto is not None:
1086
+ context.active_code_library.add_linking_file(lto)
1087
+ active = cgutils.alloca_once(builder, cgutils.int32_t)
1088
+ int32_ptr = cgutils.int32_t.as_pointer()
1089
+
1090
+ fn_args, fn_args_ty = [], []
1091
+ if index:
1092
+ idx_ptr = cgutils.alloca_once_value(builder, args[0])
1093
+ fn_args += [idx_ptr]
1094
+ fn_args_ty += [int32_ptr]
1095
+ fn_args += [active]
1096
+ fn_args_ty += [int32_ptr]
1097
+
1098
+ fnTy = llvmir.FunctionType(cgutils.voidptr_t, fn_args_ty)
1099
+ fn = cgutils.get_or_insert_function(builder.module, fnTy, symbol)
1100
+ builder.call(fn, fn_args)
1101
+
1102
+ res = builder.icmp_signed("!=", builder.load(active), llvmir.Constant(cgutils.int32_t, 0))
1103
+ return res
1104
+
1105
+ _intrinsic: Callable = lambda typingctx: (typing.signature(return_type), codegen)
1106
+ if index:
1107
+ _intrinsic = lambda typingctx, index: (typing.signature(return_type, types.int32), codegen)
1108
+
1109
+ return intrinsic(_intrinsic)
1110
+
1111
+
1112
+ @overload_method(
1113
+ BlasPartitionerType,
1114
+ "is_thread_active",
1115
+ jit_options={"forceinline": True},
1116
+ strict=False,
1117
+ )
1118
+ def ol_blas_partitioner_is_thread_active(
1119
+ partitioner: BlasPartitionerType,
1120
+ ):
1121
+ if not isinstance(partitioner, BlasPartitionerType):
1122
+ return
1123
+
1124
+ code, symbol = compile_blas_is_thread_active(partitioner.MM, code_type=get_default_code_type())
1125
+ lto = cuda.LTOIR(code.data)
1126
+ is_thread_active = get_bool_return_intrinsic(symbol, lto=lto)
1127
+
1128
+ return lambda partitioner: is_thread_active()
1129
+
1130
+
1131
+ @overload_method(
1132
+ BlasPartitionerType,
1133
+ "is_predicated",
1134
+ jit_options={"forceinline": True},
1135
+ strict=False,
1136
+ )
1137
+ def ol_blas_partitioner_is_predicated(
1138
+ partitioner: BlasPartitionerType,
1139
+ ):
1140
+ if not isinstance(partitioner, BlasPartitionerType):
1141
+ return
1142
+
1143
+ code, symbol = compile_blas_is_predicated(partitioner.MM, code_type=get_default_code_type())
1144
+ lto = cuda.LTOIR(code.data)
1145
+ is_predicated = get_bool_return_intrinsic(symbol, lto=lto)
1146
+
1147
+ return lambda partitioner: is_predicated()
1148
+
1149
+
1150
+ @overload_method(
1151
+ BlasPartitionerType,
1152
+ "is_index_in_bounds",
1153
+ jit_options={"forceinline": True},
1154
+ strict=False,
1155
+ )
1156
+ def ol_blas_partition_is_index_in_bounds(
1157
+ partitioner: BlasPartitionerType,
1158
+ index: types.Integer,
1159
+ ):
1160
+ if not isinstance(partitioner, BlasPartitionerType):
1161
+ return
1162
+ if not isinstance(index, types.Integer):
1163
+ return
1164
+
1165
+ code, symbol = compile_blas_is_index_in_bounds(partitioner.MM, code_type=get_default_code_type())
1166
+ lto = cuda.LTOIR(code.data)
1167
+ is_index_in_bounds = get_bool_return_intrinsic(symbol, index=True, lto=lto)
1168
+
1169
+ return lambda partitioner, idx: is_index_in_bounds(idx)
1170
+
1171
+
1172
+ @overload_method(
1173
+ BlasPartitionerType,
1174
+ "partition_and_copy",
1175
+ inline="always",
1176
+ strict=False,
1177
+ )
1178
+ def ol_blas_partitioner_partition_and_copy(
1179
+ partitioner: BlasPartitionerType,
1180
+ src: OpaqueTensorType,
1181
+ dst: OpaqueTensorType,
1182
+ ):
1183
+ if not isinstance(partitioner, BlasPartitionerType):
1184
+ return
1185
+ if not isinstance(src, OpaqueTensorType):
1186
+ return
1187
+ if not isinstance(dst, OpaqueTensorType):
1188
+ return
1189
+ assert isinstance(src.layout, BlasLayoutType)
1190
+ assert isinstance(dst.layout, BlasLayoutType)
1191
+ src_mem = src.layout.layout.memory_space
1192
+ dst_mem = dst.layout.layout.memory_space
1193
+ assert src_mem == "r" and dst_mem == "g" or src_mem == "g" and dst_mem == "r"
1194
+
1195
+ alignment = max(partitioner.MM.alignment.c, src.layout.layout.alignment, dst.layout.layout.alignment)
1196
+
1197
+ def impl(partitioner: Partitioner, src, dst):
1198
+ if partitioner.is_thread_active():
1199
+ copy_fragment(src, dst, alignment=alignment)
1200
+
1201
+ return impl
1202
+
1203
+
1204
+ @overload_method(
1205
+ BlasPartitionerType,
1206
+ "make_empty_fragment",
1207
+ inline="always",
1208
+ strict=False,
1209
+ )
1210
+ def ol_blas_partitioner_make_empty_fragment(
1211
+ partitioner: BlasPartitionerType,
1212
+ ):
1213
+ MM = partitioner.MM
1214
+ layout = partitioner.fragment_layout.layout
1215
+
1216
+ alignment = max(8, layout.alignment, MM.alignment.c)
1217
+
1218
+ def impl(partitioner):
1219
+ buff = cuda.local.array(layout.cosize, dtype=MM.c_value_type, alignment=alignment)
1220
+ frag = make_tensor(buff, layout)
1221
+ return frag
1222
+
1223
+ return impl
1224
+
1225
+
1226
+ @overload_method(
1227
+ BlasPartitionerType,
1228
+ "make_partition_and_copy",
1229
+ inline="always",
1230
+ strict=False,
1231
+ )
1232
+ def ol_blas_partitioner_make_partition_and_copy(
1233
+ partitioner: BlasPartitionerType,
1234
+ tensor: OpaqueTensorType,
1235
+ ):
1236
+ if not isinstance(tensor, OpaqueTensorType):
1237
+ return
1238
+
1239
+ layout_ty = partitioner.fragment_layout
1240
+ layout = layout_ty.layout
1241
+ if layout_ty.dtype != tensor.layout.dtype:
1242
+ layout = layout_ty.make_layout_like(tensor.layout.layout.dtype).layout
1243
+ assert isinstance(layout, _BlasMatmulLayout)
1244
+
1245
+ MM = partitioner.MM
1246
+ alignment = max(8, layout.alignment, MM.alignment.c)
1247
+ dtype = layout.dtype
1248
+
1249
+ def impl(partitioner, tensor):
1250
+ buff = cuda.local.array(layout.cosize, dtype=dtype, alignment=alignment)
1251
+ frag = make_tensor(buff, layout)
1252
+ partitioner.partition_and_copy(tensor, frag)
1253
+ return frag
1254
+
1255
+ return impl
1256
+
1257
+
1258
+ @overload_method(
1259
+ BlasAccumulatorType,
1260
+ "_init",
1261
+ target="cuda",
1262
+ jit_options={"forceinline": True},
1263
+ strict=False,
1264
+ )
1265
+ def ol_opaque_tensor_init(
1266
+ accumulator: BlasAccumulatorType,
1267
+ ):
1268
+ if not isinstance(accumulator, BlasAccumulatorType):
1269
+ return
1270
+
1271
+ layout = accumulator.layout
1272
+ assert isinstance(layout, BlasLayoutType)
1273
+ code, symbol = compile_blas_accumulator_init(layout.layout, code_type=get_default_code_type())
1274
+ lto = cuda.LTOIR(code.data)
1275
+
1276
+ return_type = types.void
1277
+ mathdx_accumulator = MathdxOpaqueTensorType(layout.layout.dynamic_strides_size, layout.layout.dynamic_shape_size)
1278
+ sig = typing.signature(return_type, mathdx_accumulator)
1279
+
1280
+ cublasdx_init_accumulator = declare_cabi_device(symbol, sig, link=lto)
1281
+
1282
+ def impl(accumulator):
1283
+ cublasdx_init_accumulator(get_mathdx_tensor(accumulator))
1284
+
1285
+ return impl
1286
+
1287
+
1288
+ @overload_method(
1289
+ BlasAccumulatorType,
1290
+ "get_results",
1291
+ inline="always",
1292
+ strict=False,
1293
+ )
1294
+ def ol_blas_accumulator_get_results(
1295
+ accumulator: BlasAccumulatorType,
1296
+ ):
1297
+ if not isinstance(accumulator, BlasAccumulatorType):
1298
+ return
1299
+
1300
+ def impl(accumulator):
1301
+ frag = accumulator.make_empty_fragment()
1302
+ copy_fragment(accumulator, frag)
1303
+
1304
+ return frag
1305
+
1306
+ return impl
1307
+
1308
+
1309
+ @overload_method(BlasAccumulatorType, "clear", jit_options={"forceinline": True}, strict=False)
1310
+ def ol_blas_accumulator_clear(accumulator: BlasAccumulatorType):
1311
+ opaque_tensor_type = OpaqueTensorType(accumulator.layout)
1312
+
1313
+ @intrinsic
1314
+ def _type_cast_ot_tensor(typingctx, opaque_tensor):
1315
+ def codegen(context: BaseContext, builder: llvmir.IRBuilder, signature, args):
1316
+ return args[0]
1317
+
1318
+ return_type = opaque_tensor_type
1319
+ return typing.signature(return_type, accumulator), codegen
1320
+
1321
+ def impl(accumulator: BlasAccumulatorType):
1322
+ tensor = _type_cast_ot_tensor(accumulator)
1323
+ clear(tensor)
1324
+
1325
+ return impl
1326
+
1327
+
1328
+ @overload_method(DevicePipelineType, "get_tile", target="cuda", inline="always", strict=False)
1329
+ def ol_device_pipeline_get_tile(
1330
+ device_pipeline: DevicePipelineType,
1331
+ smem: types.Array,
1332
+ idx: types.Number,
1333
+ idy: types.Number,
1334
+ ):
1335
+ if not isinstance(device_pipeline, DevicePipelineType):
1336
+ return
1337
+ if not isinstance(smem, types.Array):
1338
+ return
1339
+ if not isinstance(idx, types.Number) and not isinstance(idx, types.UniTuple):
1340
+ return
1341
+ if not isinstance(idy, types.Number) and not isinstance(idy, types.UniTuple):
1342
+ return
1343
+
1344
+ assert (
1345
+ isinstance(idx, types.Number)
1346
+ and isinstance(idy, types.Number)
1347
+ or isinstance(idx, types.UniTuple)
1348
+ and isinstance(idy, types.UniTuple)
1349
+ )
1350
+
1351
+ def impl(device_pipeline, smem, idx, idy):
1352
+ tile_pipeline: TilePipeline = _create_tile_pipeline(device_pipeline)
1353
+ tile_pipeline_buffer = cuda.local.array(
1354
+ shape=(tile_pipeline.storage_bytes,), dtype=numpy.byte, alignment=tile_pipeline.storage_alignment
1355
+ )
1356
+ tile_pipeline = _set_tile_pipeline_buffer(tile_pipeline, tile_pipeline_buffer)
1357
+ tile_pipeline._init(device_pipeline, smem, idx, idy)
1358
+
1359
+ return tile_pipeline
1360
+
1361
+ return impl
1362
+
1363
+
1364
+ @overload_method(DevicePipelineType, "reset_tile", target="cuda", inline="always", strict=False)
1365
+ def ol_tile_pipeline_reset_tile(
1366
+ device_pipeline: DevicePipelineType,
1367
+ tile_pipeline: TilePipelineType,
1368
+ idx: types.Number,
1369
+ idy: types.Number,
1370
+ ):
1371
+ if not isinstance(device_pipeline, DevicePipelineType):
1372
+ return
1373
+ if not isinstance(tile_pipeline, TilePipelineType):
1374
+ return
1375
+ if not isinstance(idx, types.Number) and not isinstance(idx, types.UniTuple):
1376
+ return
1377
+ if not isinstance(idy, types.Number) and not isinstance(idy, types.UniTuple):
1378
+ return
1379
+
1380
+ assert tile_pipeline.pipeline.device_pipeline == device_pipeline.pipeline
1381
+
1382
+ code, symbol = compile_blas_device_pipeline_reset_tile(
1383
+ device_pipeline.pipeline, tile_pipeline.pipeline, code_type=get_default_code_type()
1384
+ )
1385
+ lto = cuda.LTOIR(code.data)
1386
+
1387
+ return_type = types.void
1388
+ sig = typing.signature(
1389
+ return_type,
1390
+ MathdxPipelineType(),
1391
+ MathdxPipelineType(),
1392
+ types.CPointer(types.int32),
1393
+ types.CPointer(types.int32),
1394
+ )
1395
+
1396
+ cublasdx_reset_tile = declare_cabi_device(symbol, sig, link=lto)
1397
+
1398
+ if isinstance(idx, types.Number):
1399
+
1400
+ def impl(device_pipeline, tile_pipeline, idx, idy):
1401
+ idx = get_value_ptr(types.int32(idx))
1402
+ idy = get_value_ptr(types.int32(idy))
1403
+ cublasdx_reset_tile(get_mathdx_pipeline(device_pipeline), get_mathdx_pipeline(tile_pipeline), idx, idy)
1404
+
1405
+ return impl
1406
+ else:
1407
+
1408
+ def impl(device_pipeline, tile_pipeline, idx, idy):
1409
+ idx_arr = cuda.local.array(shape=(2,), dtype=numpy.int32)
1410
+ idx_arr[0], idx_arr[1] = idx
1411
+ idy_arr = cuda.local.array(shape=(2,), dtype=numpy.int32)
1412
+ idy_arr[0], idy_arr[1] = idy
1413
+ idx_ptr = get_array_ptr(idx_arr)
1414
+ idy_ptr = get_array_ptr(idy_arr)
1415
+ cublasdx_reset_tile(get_mathdx_pipeline(device_pipeline), get_mathdx_pipeline(tile_pipeline), idx_ptr, idy_ptr)
1416
+
1417
+ return impl
1418
+
1419
+
1420
+ @overload_method(TilePipelineType, "_init", target="cuda", jit_options={"forceinline": True}, strict=False)
1421
+ def ol_tile_pipeline_init(
1422
+ tile_pipeline: TilePipelineType,
1423
+ device_pipeline: DevicePipelineType,
1424
+ smem: types.Array,
1425
+ idx: types.Number,
1426
+ idy: types.Number,
1427
+ ):
1428
+ if not isinstance(tile_pipeline, TilePipelineType):
1429
+ return
1430
+ if not isinstance(device_pipeline, DevicePipelineType):
1431
+ return
1432
+ if not isinstance(smem, types.Array):
1433
+ return
1434
+ if not isinstance(idx, types.Number) and not isinstance(idx, types.UniTuple):
1435
+ return
1436
+ if not isinstance(idy, types.Number) and not isinstance(idy, types.UniTuple):
1437
+ return
1438
+
1439
+ assert tile_pipeline.pipeline.device_pipeline == device_pipeline.pipeline
1440
+
1441
+ code, symbol = compile_blas_tile_pipeline_init(tile_pipeline.pipeline, code_type=get_default_code_type())
1442
+ lto = cuda.LTOIR(code.data)
1443
+
1444
+ return_type = types.void
1445
+ sig = typing.signature(
1446
+ return_type,
1447
+ MathdxPipelineType(),
1448
+ MathdxPipelineType(),
1449
+ types.CPointer(smem.dtype),
1450
+ types.CPointer(types.int32),
1451
+ types.CPointer(types.int32),
1452
+ )
1453
+
1454
+ cublasdx_init_pipeline = declare_cabi_device(symbol, sig, link=lto)
1455
+
1456
+ if isinstance(idx, types.Number):
1457
+
1458
+ def impl(tile_pipeline, device_pipeline, smem, idx, idy):
1459
+ smem_ptr = get_array_ptr(smem)
1460
+ idx = get_value_ptr(types.int32(idx))
1461
+ idy = get_value_ptr(types.int32(idy))
1462
+
1463
+ cublasdx_init_pipeline(get_mathdx_pipeline(device_pipeline), get_mathdx_pipeline(tile_pipeline), smem_ptr, idx, idy)
1464
+
1465
+ return impl
1466
+ else:
1467
+
1468
+ def impl(tile_pipeline, device_pipeline, smem, idx, idy):
1469
+ smem_ptr = get_array_ptr(smem)
1470
+ idx_arr = cuda.local.array(shape=(2,), dtype=numpy.int32)
1471
+ idx_arr[0], idx_arr[1] = idx
1472
+ idy_arr = cuda.local.array(shape=(2,), dtype=numpy.int32)
1473
+ idy_arr[0], idy_arr[1] = idy
1474
+ idx_ptr = get_array_ptr(idx_arr)
1475
+ idy_ptr = get_array_ptr(idy_arr)
1476
+ cublasdx_init_pipeline(
1477
+ get_mathdx_pipeline(device_pipeline), get_mathdx_pipeline(tile_pipeline), smem_ptr, idx_ptr, idy_ptr
1478
+ )
1479
+
1480
+ return impl
1481
+
1482
+
1483
+ @overload_method(TilePipelineType, "_del", target="cuda", jit_options={"forceinline": True}, strict=False)
1484
+ def ol_tile_pipeline_destroy(tile_pipeline: TilePipelineType):
1485
+ if not isinstance(tile_pipeline, TilePipelineType):
1486
+ return
1487
+
1488
+ code, symbol = compile_blas_tile_pipeline_destroy(tile_pipeline.pipeline, code_type=get_default_code_type())
1489
+ lto = cuda.LTOIR(code.data)
1490
+
1491
+ return_type = types.void
1492
+ sig = typing.signature(return_type, tile_pipeline)
1493
+
1494
+ cublasdx_destroy_pipeline = declare_cabi_device(symbol, sig, link=lto)
1495
+
1496
+ def impl(tile_pipeline):
1497
+ cublasdx_destroy_pipeline(tile_pipeline)
1498
+
1499
+ return impl
1500
+
1501
+
1502
+ @overload_method(TilePipelineType, "execute", target="cuda", jit_options={"forceinline": True}, strict=False)
1503
+ def ol_tile_pipeline_execute(
1504
+ tile_pipeline: TilePipelineType,
1505
+ accumulator: BlasAccumulatorType,
1506
+ ):
1507
+ assert isinstance(accumulator, BlasAccumulatorType)
1508
+ acc_layout = accumulator.layout.layout
1509
+ assert acc_layout.accumulator
1510
+
1511
+ code, symbol = compile_blas_tile_pipeline_execute(tile_pipeline.pipeline, acc_layout, code_type=get_default_code_type())
1512
+ lto = cuda.LTOIR(code.data)
1513
+
1514
+ return_type = types.void
1515
+ acc_ty = MathdxOpaqueTensorType(
1516
+ dynamic_strides_size=getattr(getattr(acc_layout, "layout", None), "dynamic_strides_size", 0),
1517
+ dynamic_shape_size=getattr(getattr(acc_layout, "layout", None), "dynamic_shape_size", 0),
1518
+ )
1519
+ sig = typing.signature(return_type, MathdxPipelineType(), acc_ty)
1520
+
1521
+ cublasdx_tile_pipeline_execute = declare_cabi_device(symbol, sig, link=lto)
1522
+
1523
+ def impl(tile_pipeline, accumulator):
1524
+ cublasdx_tile_pipeline_execute(get_mathdx_pipeline(tile_pipeline), get_mathdx_tensor(accumulator))
1525
+
1526
+ return impl
1527
+
1528
+
1529
+ @intrinsic
1530
+ def _get_set_ot_item(typingctx, tensor: OpaqueTensorType, index: types.Integer, val=None):
1531
+ def codegen(context: BaseContext, builder: llvmir.IRBuilder, signature, args):
1532
+ tensor_ty = signature.args[0]
1533
+ tensor, idx = args[0], args[1]
1534
+
1535
+ tensor_struct = cgutils.create_struct_proxy(tensor_ty)(context, builder, tensor)
1536
+ buff_void_ptr = tensor_struct.ptr
1537
+
1538
+ assert isinstance(buff_void_ptr.type, llvmir.PointerType)
1539
+
1540
+ llvm_val_ty = context.get_value_type(tensor_ty.dtype)
1541
+
1542
+ data_ptr_ty = llvmir.PointerType(llvm_val_ty, buff_void_ptr.type.addrspace)
1543
+ buff_ptr = builder.bitcast(buff_void_ptr, data_ptr_ty)
1544
+
1545
+ val_ptr = builder.gep(buff_ptr, [idx], inbounds=True)
1546
+
1547
+ if val is None:
1548
+ return builder.load(val_ptr)
1549
+ else:
1550
+ val_arg = args[2]
1551
+ builder.store(val_arg, val_ptr)
1552
+
1553
+ if val is None:
1554
+ ret_type = tensor.dtype
1555
+ sig = typing.signature(ret_type, tensor, index, types.none)
1556
+ else:
1557
+ ret_type = types.void
1558
+ sig = typing.signature(ret_type, tensor, index, tensor.dtype)
1559
+ return sig, codegen
1560
+
1561
+
1562
+ def _validate_fragment_tensor(tensor: OpaqueTensorType) -> bool:
1563
+ if not isinstance(tensor, OpaqueTensorType):
1564
+ return False
1565
+
1566
+ layout_ty = tensor.layout
1567
+ if not isinstance(layout_ty, BlasLayoutType):
1568
+ return False
1569
+
1570
+ layout = layout_ty.layout
1571
+ if not isinstance(layout, _BlasMatmulLayout):
1572
+ return False
1573
+ return layout.memory_space == "r"
1574
+
1575
+
1576
+ @overload(operator.getitem, jit_options={"forceinline": True}, strict=False)
1577
+ def ol_blas_partition_getitem(tensor: OpaqueTensorType, index: types.Integer):
1578
+ if not _validate_fragment_tensor(tensor):
1579
+ return
1580
+ if not isinstance(index, types.Integer):
1581
+ return
1582
+
1583
+ return lambda tensor, index: _get_set_ot_item(tensor, index)
1584
+
1585
+
1586
+ @overload(operator.setitem, jit_options={"forceinline": True}, strict=False)
1587
+ def ol_blas_partition_setitem(tensor: OpaqueTensorType, index: types.Integer, value):
1588
+ if not _validate_fragment_tensor(tensor):
1589
+ return
1590
+ if not isinstance(index, types.Integer):
1591
+ return
1592
+ if not isinstance(value, types.Number):
1593
+ return
1594
+
1595
+ dtype = tensor.dtype
1596
+
1597
+ return lambda tensor, index, value: _get_set_ot_item(tensor, index, dtype(value))
1598
+
1599
+
1600
+ class _PipelineExtension:
1601
+ def prepare_args(self, ty, val, **kwargs):
1602
+ if isinstance(val, DevicePipeline):
1603
+ assert isinstance(ty, DevicePipelineType)
1604
+ c_ptr = types.CPointer(types.void)
1605
+ return c_ptr, int(val._storage.handle)
1606
+ else:
1607
+ return ty, val
1608
+
1609
+
1610
+ # TODO: make implicit, once numba-cuda supports it
1611
+ # https://github.com/NVIDIA/numba-cuda/pull/504
1612
+ pipeline_extensions = [_PipelineExtension()]