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