nvmath-python 0.5.0__cp313-cp313-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 (174) hide show
  1. nvmath/__init__.pxd +0 -0
  2. nvmath/__init__.py +37 -0
  3. nvmath/_internal/__init__.py +0 -0
  4. nvmath/_internal/layout.py +58 -0
  5. nvmath/_utils.py +363 -0
  6. nvmath/bindings/__init__.pxd +0 -0
  7. nvmath/bindings/__init__.py +44 -0
  8. nvmath/bindings/_internal/__init__.pxd +0 -0
  9. nvmath/bindings/_internal/__init__.py +0 -0
  10. nvmath/bindings/_internal/cublas.cp313-win_amd64.pyd +0 -0
  11. nvmath/bindings/_internal/cublas.pxd +518 -0
  12. nvmath/bindings/_internal/cublasLt.cp313-win_amd64.pyd +0 -0
  13. nvmath/bindings/_internal/cublasLt.pxd +54 -0
  14. nvmath/bindings/_internal/cudss.cp313-win_amd64.pyd +0 -0
  15. nvmath/bindings/_internal/cudss.pxd +44 -0
  16. nvmath/bindings/_internal/cufft.cp313-win_amd64.pyd +0 -0
  17. nvmath/bindings/_internal/cufft.pxd +69 -0
  18. nvmath/bindings/_internal/cufftMp.pxd +77 -0
  19. nvmath/bindings/_internal/curand.cp313-win_amd64.pyd +0 -0
  20. nvmath/bindings/_internal/curand.pxd +42 -0
  21. nvmath/bindings/_internal/cusolver.cp313-win_amd64.pyd +0 -0
  22. nvmath/bindings/_internal/cusolver.pxd +15 -0
  23. nvmath/bindings/_internal/cusolverDn.cp313-win_amd64.pyd +0 -0
  24. nvmath/bindings/_internal/cusolverDn.pxd +386 -0
  25. nvmath/bindings/_internal/cusparse.cp313-win_amd64.pyd +0 -0
  26. nvmath/bindings/_internal/cusparse.pxd +270 -0
  27. nvmath/bindings/_internal/mathdx.cp313-win_amd64.pyd +0 -0
  28. nvmath/bindings/_internal/mathdx.pxd +79 -0
  29. nvmath/bindings/_internal/nvshmem.pxd +29 -0
  30. nvmath/bindings/_internal/utils.cp313-win_amd64.pyd +0 -0
  31. nvmath/bindings/_internal/utils.pxd +186 -0
  32. nvmath/bindings/cublas.cp313-win_amd64.pyd +0 -0
  33. nvmath/bindings/cublas.pxd +545 -0
  34. nvmath/bindings/cublas.pyi +18 -0
  35. nvmath/bindings/cublasLt.cp313-win_amd64.pyd +0 -0
  36. nvmath/bindings/cublasLt.pxd +99 -0
  37. nvmath/bindings/cudss.cp313-win_amd64.pyd +0 -0
  38. nvmath/bindings/cudss.pxd +83 -0
  39. nvmath/bindings/cudss.pyi +249 -0
  40. nvmath/bindings/cufft.cp313-win_amd64.pyd +0 -0
  41. nvmath/bindings/cufft.pxd +114 -0
  42. nvmath/bindings/cufftMp.pxd +124 -0
  43. nvmath/bindings/curand.cp313-win_amd64.pyd +0 -0
  44. nvmath/bindings/curand.pxd +71 -0
  45. nvmath/bindings/cusolver.cp313-win_amd64.pyd +0 -0
  46. nvmath/bindings/cusolver.pxd +60 -0
  47. nvmath/bindings/cusolverDn.cp313-win_amd64.pyd +0 -0
  48. nvmath/bindings/cusolverDn.pxd +410 -0
  49. nvmath/bindings/cusparse.cp313-win_amd64.pyd +0 -0
  50. nvmath/bindings/cusparse.pxd +329 -0
  51. nvmath/bindings/cycublas.cp313-win_amd64.pyd +0 -0
  52. nvmath/bindings/cycublas.pxd +657 -0
  53. nvmath/bindings/cycublasLt.cp313-win_amd64.pyd +0 -0
  54. nvmath/bindings/cycublasLt.pxd +1010 -0
  55. nvmath/bindings/cycudss.cp313-win_amd64.pyd +0 -0
  56. nvmath/bindings/cycudss.pxd +191 -0
  57. nvmath/bindings/cycufft.cp313-win_amd64.pyd +0 -0
  58. nvmath/bindings/cycufft.pxd +320 -0
  59. nvmath/bindings/cycufftMp.pxd +333 -0
  60. nvmath/bindings/cycurand.cp313-win_amd64.pyd +0 -0
  61. nvmath/bindings/cycurand.pxd +146 -0
  62. nvmath/bindings/cycusolver.cp313-win_amd64.pyd +0 -0
  63. nvmath/bindings/cycusolver.pxd +143 -0
  64. nvmath/bindings/cycusolverDn.cp313-win_amd64.pyd +0 -0
  65. nvmath/bindings/cycusolverDn.pxd +414 -0
  66. nvmath/bindings/cycusparse.cp313-win_amd64.pyd +0 -0
  67. nvmath/bindings/cycusparse.pxd +476 -0
  68. nvmath/bindings/cymathdx.cp313-win_amd64.pyd +0 -0
  69. nvmath/bindings/cymathdx.pxd +363 -0
  70. nvmath/bindings/cynvshmem.pxd +126 -0
  71. nvmath/bindings/mathdx.cp313-win_amd64.pyd +0 -0
  72. nvmath/bindings/mathdx.pxd +131 -0
  73. nvmath/bindings/mathdx.pyi +686 -0
  74. nvmath/bindings/nvpl/__init__.pxd +0 -0
  75. nvmath/bindings/nvpl/__init__.py +11 -0
  76. nvmath/bindings/nvpl/_internal/__init__.pxd +0 -0
  77. nvmath/bindings/nvpl/_internal/__init__.py +0 -0
  78. nvmath/bindings/nvpl/_internal/fft.pxd +36 -0
  79. nvmath/bindings/nvpl/cyfft.pxd +87 -0
  80. nvmath/bindings/nvpl/fft.pxd +100 -0
  81. nvmath/bindings/nvshmem.pxd +54 -0
  82. nvmath/device/__init__.py +23 -0
  83. nvmath/device/_deprecated.py +33 -0
  84. nvmath/device/caching.py +51 -0
  85. nvmath/device/common.py +131 -0
  86. nvmath/device/common_backend.py +125 -0
  87. nvmath/device/common_cuda.py +156 -0
  88. nvmath/device/common_mathdx.py +97 -0
  89. nvmath/device/common_numba.py +159 -0
  90. nvmath/device/common_opaque_tensor.py +128 -0
  91. nvmath/device/cublasdx.py +1085 -0
  92. nvmath/device/cublasdx_backend.py +552 -0
  93. nvmath/device/cublasdx_numba.py +528 -0
  94. nvmath/device/cufftdx.py +551 -0
  95. nvmath/device/cufftdx_backend.py +194 -0
  96. nvmath/device/cufftdx_numba.py +123 -0
  97. nvmath/device/curand_kernel.py +9147 -0
  98. nvmath/device/nvrtc.py +95 -0
  99. nvmath/device/patch.py +35 -0
  100. nvmath/device/random.py +417 -0
  101. nvmath/device/random_helpers.py +23 -0
  102. nvmath/device/random_states.py +189 -0
  103. nvmath/device/types.py +11 -0
  104. nvmath/device/vector_types_numba.py +203 -0
  105. nvmath/distributed/__init__.py +117 -0
  106. nvmath/distributed/_internal/__init__.py +0 -0
  107. nvmath/distributed/_internal/nvshmem.py +243 -0
  108. nvmath/distributed/_internal/tensor_ifc_cupy.py +111 -0
  109. nvmath/distributed/_internal/tensor_ifc_numpy.py +53 -0
  110. nvmath/distributed/_internal/tensor_ifc_torch.py +108 -0
  111. nvmath/distributed/_internal/tensor_wrapper.py +59 -0
  112. nvmath/distributed/_utils.py +152 -0
  113. nvmath/distributed/fft/__init__.py +6 -0
  114. nvmath/distributed/fft/_configuration.py +86 -0
  115. nvmath/distributed/fft/fft.py +1737 -0
  116. nvmath/distributed/reshape/__init__.py +6 -0
  117. nvmath/distributed/reshape/_configuration.py +39 -0
  118. nvmath/distributed/reshape/reshape.py +1249 -0
  119. nvmath/fft/__init__.py +7 -0
  120. nvmath/fft/_configuration.py +208 -0
  121. nvmath/fft/_exec_utils.py +116 -0
  122. nvmath/fft/_helpers.py +260 -0
  123. nvmath/fft/fft.py +2346 -0
  124. nvmath/internal/__init__.py +5 -0
  125. nvmath/internal/enum_utils.py +142 -0
  126. nvmath/internal/formatters.py +87 -0
  127. nvmath/internal/mem_limit.py +51 -0
  128. nvmath/internal/package_ifc.py +119 -0
  129. nvmath/internal/package_ifc_cuda.py +43 -0
  130. nvmath/internal/package_ifc_cupy.py +49 -0
  131. nvmath/internal/package_ifc_torch.py +31 -0
  132. nvmath/internal/package_wrapper.py +14 -0
  133. nvmath/internal/tensor_ifc.py +143 -0
  134. nvmath/internal/tensor_ifc_cupy.py +185 -0
  135. nvmath/internal/tensor_ifc_numpy.py +157 -0
  136. nvmath/internal/tensor_ifc_torch.py +115 -0
  137. nvmath/internal/tensor_wrapper.py +160 -0
  138. nvmath/internal/typemaps.py +154 -0
  139. nvmath/internal/utils.py +634 -0
  140. nvmath/linalg/__init__.py +11 -0
  141. nvmath/linalg/_internal/__init__.py +3 -0
  142. nvmath/linalg/_internal/algo_cap_ifc.py +86 -0
  143. nvmath/linalg/_internal/algo_config_ifc.py +87 -0
  144. nvmath/linalg/_internal/enum_to_tuples.py +64 -0
  145. nvmath/linalg/_internal/epilog_protocol.py +738 -0
  146. nvmath/linalg/_internal/matmul_desc_ifc.py +72 -0
  147. nvmath/linalg/_internal/matmul_pref_ifc.py +65 -0
  148. nvmath/linalg/_internal/matrix_layout_ifc.py +59 -0
  149. nvmath/linalg/_internal/typemaps.py +135 -0
  150. nvmath/linalg/_internal/utils.py +96 -0
  151. nvmath/linalg/advanced/__init__.py +8 -0
  152. nvmath/linalg/advanced/_algorithmmod.py +142 -0
  153. nvmath/linalg/advanced/_configuration.py +320 -0
  154. nvmath/linalg/advanced/helpers/__init__.py +5 -0
  155. nvmath/linalg/advanced/helpers/matmul.py +173 -0
  156. nvmath/linalg/advanced/matmulmod.py +2855 -0
  157. nvmath/memory.py +266 -0
  158. nvmath/sparse/__init__.py +18 -0
  159. nvmath/sparse/_internal/__init__.py +21 -0
  160. nvmath/sparse/_internal/common_utils.py +81 -0
  161. nvmath/sparse/_internal/cudss_config_ifc.py +584 -0
  162. nvmath/sparse/_internal/cudss_data_ifc.py +291 -0
  163. nvmath/sparse/_internal/cudss_utils.py +398 -0
  164. nvmath/sparse/_internal/sparse_csr_ifc.py +154 -0
  165. nvmath/sparse/_internal/sparse_format_helpers.py +88 -0
  166. nvmath/sparse/_internal/sparse_tensor_ifc.py +80 -0
  167. nvmath/sparse/advanced/__init__.py +7 -0
  168. nvmath/sparse/advanced/_configuration.py +150 -0
  169. nvmath/sparse/advanced/direct_solver.py +1705 -0
  170. nvmath_python-0.5.0.dist-info/METADATA +122 -0
  171. nvmath_python-0.5.0.dist-info/RECORD +174 -0
  172. nvmath_python-0.5.0.dist-info/WHEEL +5 -0
  173. nvmath_python-0.5.0.dist-info/licenses/LICENSE +177 -0
  174. nvmath_python-0.5.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,528 @@
1
+ # Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ from numba.core import typing, cgutils
6
+ from numba.extending import typeof_impl, overload_method, intrinsic, types, utils, overload
7
+ from numba.cuda.cudaimpl import lower_constant, registry as cuda_registry
8
+ from numba.cuda.models import register_model
9
+
10
+ from nvmath.device.common_cuda import get_default_code_type
11
+ from nvmath.device.cublasdx_backend import generate_copy_wait_lto
12
+
13
+ from .common import axpby, copy, copy_fragment, clear, copy_wait, make_tensor, OpaqueTensor
14
+ from .common_numba import NUMBA_FE_TYPES_TO_NUMBA_IR, make_function_call, overload_type_attribute, EmptyStructModel
15
+ from .cublasdx import BlasNumba, _BlasLayout
16
+ from .common_opaque_tensor import LayoutModel, LayoutType, OpaqueTensorType
17
+
18
+ import llvmlite.ir as llvmir
19
+ from numba.core.base import BaseContext
20
+
21
+ _BLAS_DEFINITION_ARGS = [
22
+ "size",
23
+ "precision",
24
+ "data_type",
25
+ "code_type",
26
+ "block_size",
27
+ "block_dim",
28
+ "leading_dimension",
29
+ "transpose_mode",
30
+ "arrangement",
31
+ "function",
32
+ "execution",
33
+ "execute_api",
34
+ ]
35
+
36
+ _BLAS_COMPILED_ARGS = [
37
+ "a_value_type",
38
+ "b_value_type",
39
+ "c_value_type",
40
+ # value_type, input_type, and output_type not included intentionally,
41
+ # because they are deprecated.
42
+ "a_dim",
43
+ "b_dim",
44
+ "c_dim",
45
+ "a_size",
46
+ "b_size",
47
+ "c_size",
48
+ "leading_dimension",
49
+ "shared_memory_size",
50
+ "max_threads_per_block",
51
+ ]
52
+
53
+
54
+ class BlasType(types.Type):
55
+ """
56
+ Type class associated with the `cublasdx.BlasNumba`.
57
+ """
58
+
59
+ def __init__(self, blas: BlasNumba):
60
+ assert isinstance(blas, BlasNumba)
61
+ self._blas = blas
62
+ attributes = [f"{attr}={getattr(blas, attr)}" for attr in _BLAS_DEFINITION_ARGS if getattr(blas, attr)]
63
+ if blas._tensor_types:
64
+ attributes += [f"tensor_types={blas._tensor_types}"]
65
+ attributes.sort()
66
+
67
+ self.name = "BlasNumba(" + ",".join(attributes) + ")"
68
+
69
+ @property
70
+ def blas(self) -> BlasNumba:
71
+ return self._blas
72
+
73
+
74
+ register_model(BlasType)(EmptyStructModel)
75
+
76
+
77
+ @lower_constant(BlasType)
78
+ def constant_dummy(context, builder, typ, pyval):
79
+ struct_ptr = cgutils.create_struct_proxy(typ)(context, builder)
80
+ return struct_ptr._getvalue()
81
+
82
+
83
+ @typeof_impl.register(BlasNumba)
84
+ def typeof_blas_numba(val: BlasNumba, c: typing.Context) -> BlasType:
85
+ return BlasType(val)
86
+
87
+
88
+ for attribute in _BLAS_COMPILED_ARGS + _BLAS_DEFINITION_ARGS:
89
+ overload_type_attribute(BlasType, "blas", attribute)
90
+
91
+
92
+ # Numba does not support method overload or variadic arguments, so we using
93
+ # default values as a workaround
94
+ # https://github.com/numba/numba/issues/9980
95
+ # https://github.com/numba/numba/issues/9979
96
+ @overload_method(BlasType, "execute", target="cuda", inline="always", strict=False)
97
+ def ol_blas_numba_execute(*args):
98
+ return ol_blas_numba(*args)
99
+
100
+
101
+ @overload_method(BlasType, "__call__", target="cuda", strict=False)
102
+ def ol_blas_numba_call(blas_numba: BlasType, _arg1, _arg2, _arg3, _arg4=None, _arg5=None, _arg6=None, _arg7=None, _arg8=None):
103
+ return ol_blas_numba(blas_numba, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8)
104
+
105
+
106
+ def ol_blas_numba(blas_numba: BlasType, _arg1, _arg2, _arg3, _arg4=None, _arg5=None, _arg6=None, _arg7=None, _arg8=None):
107
+ if blas_numba.blas.execute_api == "tensors" and blas_numba.blas._tensor_types[2] == "suggested_rmem_c":
108
+ assert _arg4 in {None, types.Omitted(None)}
109
+ assert _arg5 in {None, types.Omitted(None)}
110
+ assert _arg6 in {None, types.Omitted(None)}
111
+ assert _arg7 in {None, types.Omitted(None)}
112
+ assert _arg8 in {None, types.Omitted(None)}
113
+
114
+ return lambda _, a, b, c, _arg4=None, _arg5=None, _arg6=None, _arg7=None, _arg8=None: _bals_type___call__(_, a, b, c)
115
+ elif (
116
+ blas_numba.blas.execute_api == "static_leading_dimensions"
117
+ or blas_numba.blas.execute_api == "tensors"
118
+ and blas_numba.blas._tensor_types[2] != "suggested_rmem_c"
119
+ ):
120
+ assert _arg6 in {None, types.Omitted(None)}
121
+ assert _arg7 in {None, types.Omitted(None)}
122
+ assert _arg8 in {None, types.Omitted(None)}
123
+
124
+ return lambda _, alpha, a, b, beta, c, _arg6=None, _arg7=None, _arg8=None: _bals_type___call__(_, alpha, a, b, beta, c)
125
+ elif blas_numba.blas.execute_api == "dynamic_leading_dimensions":
126
+ return lambda _, alpha, a, lda, b, ldb, beta, c, ldc: _bals_type___call__(_, alpha, a, lda, b, ldb, beta, c, ldc)
127
+ else:
128
+ return # no implementation
129
+
130
+
131
+ # TODO: use overload_method when supported
132
+ def _bals_type___call__(*args):
133
+ raise Exception("Stub for overloads")
134
+
135
+
136
+ @overload(_bals_type___call__, inline="always", strict=False)
137
+ def ol_blas_type___call___tensors_rmem(
138
+ blas_numba: BlasType,
139
+ a: OpaqueTensorType,
140
+ b: OpaqueTensorType,
141
+ c: OpaqueTensorType,
142
+ ):
143
+ if not isinstance(blas_numba, BlasType):
144
+ return
145
+ MM = blas_numba.blas
146
+ if not all(isinstance(t, OpaqueTensorType) for t in (a, b, c)):
147
+ return
148
+ if (a.uid, b.uid, c.uid) != MM._target_tensor_uids:
149
+ return
150
+
151
+ @intrinsic
152
+ def sym_call(typingctx, a, b, c):
153
+ return_type = types.void
154
+ sig = typing.signature(return_type, a, b, c)
155
+ return sig, make_function_call(MM._tensor_api_symbols.gemm)
156
+
157
+ return lambda _, a, b, c: sym_call(a, b, c)
158
+
159
+
160
+ @overload(_bals_type___call__, inline="always", strict=False)
161
+ def ol_blas_type___call___tensors_smem(
162
+ blas_numba: BlasType,
163
+ alpha: types.Number,
164
+ a: OpaqueTensorType,
165
+ b: OpaqueTensorType,
166
+ beta: types.Number,
167
+ c: OpaqueTensorType,
168
+ ):
169
+ if not isinstance(blas_numba, BlasType):
170
+ return
171
+ MM = blas_numba.blas
172
+ if not all(isinstance(a, types.Number) for a in (alpha, beta)):
173
+ return
174
+ if not all(isinstance(a, OpaqueTensorType) for a in (a, b, c)):
175
+ return
176
+ if (a.uid, b.uid, c.uid) != MM._target_tensor_uids:
177
+ return
178
+
179
+ @intrinsic
180
+ def sym_call(typingctx, alpha, a, b, beta, c):
181
+ return_type = types.void
182
+ sig = typing.signature(return_type, c.dtype, a, b, c.dtype, c)
183
+ return sig, make_function_call(MM._tensor_api_symbols.gemm)
184
+
185
+ return lambda _, alpha, a, b, beta, c: sym_call(alpha, a, b, beta, c)
186
+
187
+
188
+ @overload(_bals_type___call__, inline="always", strict=False)
189
+ def ol_blas_type___call___basic(
190
+ blas_numba: BlasType,
191
+ alpha: types.Number,
192
+ a: types.Array,
193
+ b: types.Array,
194
+ beta: types.Number,
195
+ c: types.Array,
196
+ ):
197
+ if not isinstance(blas_numba, BlasType):
198
+ return
199
+ MM = blas_numba.blas
200
+ if not all(isinstance(a, types.Number) for a in (alpha, beta)):
201
+ return
202
+ if not all(isinstance(a, types.Array) for a in (a, b, c)):
203
+ return
204
+ if (a.dtype, b.dtype, c.dtype) != tuple(NUMBA_FE_TYPES_TO_NUMBA_IR[vt] for vt in MM._numba_value_types):
205
+ return
206
+
207
+ # setting signature for intrinsic to much calling conventions. Numba will
208
+ # automatically cast to desired values.
209
+ return_type = types.void
210
+ sig = typing.signature(return_type, c.dtype, a, b, c.dtype, c)
211
+
212
+ symbol = MM.symbol
213
+
214
+ @intrinsic
215
+ def sym_call(typingctx, alpha, a, b, beta, c):
216
+ return sig, make_function_call(symbol)
217
+
218
+ return lambda _, alpha, a, b, beta, c: sym_call(alpha, a, b, beta, c)
219
+
220
+
221
+ @overload(_bals_type___call__, inline="always", strict=False)
222
+ def ol_blas_type___call___ldabc(
223
+ blas_numba: BlasType,
224
+ alpha: types.Number,
225
+ a: types.Array,
226
+ lda: types.Integer,
227
+ b: types.Array,
228
+ ldb: types.Integer,
229
+ beta: types.Number,
230
+ c: types.Array,
231
+ ldc: types.Integer,
232
+ ):
233
+ if not isinstance(blas_numba, BlasType):
234
+ return
235
+ MM = blas_numba.blas
236
+ if not all(isinstance(a, types.Number) for a in (alpha, beta)):
237
+ return
238
+ if not all(isinstance(a, types.Array) for a in (a, b, c)):
239
+ return
240
+ if (a.dtype, b.dtype, c.dtype) != tuple(NUMBA_FE_TYPES_TO_NUMBA_IR[vt] for vt in MM._numba_value_types):
241
+ return
242
+ if not all(isinstance(a, types.Integer) for a in (lda, ldb, ldc)):
243
+ return
244
+
245
+ # setting signature for intrinsic to much calling conventions. Numba will
246
+ # automatically cast to desired values.
247
+ ld_type = types.uint32
248
+ return_type = types.void
249
+ sig = typing.signature(return_type, c.dtype, a, ld_type, b, ld_type, c.dtype, c, ld_type)
250
+
251
+ @intrinsic
252
+ def sym_call(typingctx, alpha, a, lda, b, ldb, beta, c, ldc):
253
+ return sig, make_function_call(MM.symbol)
254
+
255
+ return lambda _, alpha, a, lda, b, ldb, beta, c, ldc: sym_call(alpha, a, lda, b, ldb, beta, c, ldc)
256
+
257
+
258
+ # __call__ overload is not supported by numba, however adding this overload
259
+ # kind of activates proper behaviour and works like magic.
260
+ # Issue reference: https://github.com/numba/numba/issues/5885
261
+ # TODO: remove once supported
262
+ @cuda_registry.lower(BlasType, BlasType, types.VarArg(types.Any))
263
+ def method_impl(context, builder, sig, args):
264
+ typing_context = context.typing_context
265
+ fnty = typing_context.resolve_value_type(ol_blas_numba_call)
266
+ sig = fnty.get_call_type(typing_context, sig.args, {})
267
+ sig = sig.replace(pysig=utils.pysignature(ol_blas_numba_call))
268
+
269
+ call = context.get_function(fnty, sig)
270
+ # Link dependent library
271
+ context.add_linking_libs(getattr(call, "libs", ()))
272
+ return call(builder, args)
273
+
274
+
275
+ @overload(copy, target="cuda", inline="always", strict=False)
276
+ def ol_blas_copy(src: OpaqueTensorType, dst: OpaqueTensorType):
277
+ return ol_blas_copy_generic(src, dst, "copy")
278
+
279
+
280
+ @overload(copy_fragment, target="cuda", inline="always", strict=False)
281
+ def ol_blas_copy_fragment(src: OpaqueTensorType, dst: OpaqueTensorType):
282
+ return ol_blas_copy_generic(src, dst, "copy_fragment")
283
+
284
+
285
+ def ol_blas_copy_generic(src: OpaqueTensorType, dst: OpaqueTensorType, func: str):
286
+ assert isinstance(src, OpaqueTensorType)
287
+ assert isinstance(src.layout, BlasLayoutType)
288
+ assert isinstance(dst, OpaqueTensorType)
289
+ assert isinstance(dst.layout, BlasLayoutType)
290
+
291
+ rmem = "rmem" in dst.layout.layout or "rmem" in src.layout.layout
292
+
293
+ if func == "copy_fragment":
294
+ assert rmem
295
+ else:
296
+ assert func == "copy"
297
+ assert not rmem
298
+
299
+ symbol = src.layout.copy_to_symbol(dst.layout)
300
+
301
+ @intrinsic
302
+ def _intrinsic(typingctx, src, dst):
303
+ assert isinstance(src, OpaqueTensorType)
304
+ assert isinstance(dst, OpaqueTensorType)
305
+ assert src.dtype == dst.dtype
306
+
307
+ return_type = types.void
308
+ return typing.signature(return_type, src, dst), make_function_call(symbol)
309
+
310
+ def impl(src, dst):
311
+ return _intrinsic(src, dst)
312
+
313
+ return impl
314
+
315
+
316
+ @overload(clear, target="cuda", inline="always", strict=False)
317
+ def ol_blas_clear(arr: OpaqueTensorType):
318
+ assert isinstance(arr, OpaqueTensorType)
319
+ assert isinstance(arr.layout, BlasLayoutType)
320
+ assert arr.buffer_type
321
+
322
+ symbol = arr.layout.clear_symbol
323
+
324
+ assert symbol
325
+
326
+ @intrinsic
327
+ def _intrinsic(typingctx, arr):
328
+ return_type = types.void
329
+ return typing.signature(return_type, arr), make_function_call(symbol)
330
+
331
+ def impl(arr):
332
+ return _intrinsic(arr)
333
+
334
+ return impl
335
+
336
+
337
+ class BlasLayoutType(LayoutType):
338
+ """
339
+ Type class associated with opaque tensor layouts.
340
+ """
341
+
342
+ def __init__(self, MM: BlasNumba, layout: str):
343
+ assert isinstance(MM, BlasNumba)
344
+ assert isinstance(layout, str)
345
+
346
+ blas_layout = _BlasLayout(MM, layout)
347
+
348
+ self._uid = blas_layout._uid
349
+ self._size = blas_layout._size
350
+ self._cosize = blas_layout._cosize
351
+ self._tensor_index = blas_layout._tensor_index
352
+ self._dynamic_ld = blas_layout._dynamic_ld
353
+ self._dtype = NUMBA_FE_TYPES_TO_NUMBA_IR[MM._value_types[self._tensor_index]]
354
+ self._layout = layout
355
+
356
+ self._copy_symbols_map = MM._copy_symbols_map
357
+ self._clear_symbol = MM._tensor_api_symbols.clear_c if blas_layout._is_register else None
358
+ self._axpby_symbol = MM._tensor_api_symbols.axpby if blas_layout._is_register else None
359
+
360
+ # Using handle descriptor in the type name to avoid symbol copy caching
361
+ # by numba.
362
+ self.name = f"Layout(uid={self._uid},layout={self._layout},handle={MM._handle.descriptor})"
363
+
364
+ @property
365
+ def layout(self) -> str:
366
+ return self._layout
367
+
368
+ @property
369
+ def uid(self) -> int:
370
+ return self._uid
371
+
372
+ @property
373
+ def tensor_index(self) -> int:
374
+ """Tensor index is 0 for A, 1 for B and 2 for C."""
375
+ return self._tensor_index
376
+
377
+ @property
378
+ def dtype(self) -> str:
379
+ return self._dtype
380
+
381
+ @property
382
+ def size(self) -> int:
383
+ return self._size
384
+
385
+ @property
386
+ def cosize(self) -> int:
387
+ return self._cosize
388
+
389
+ @property
390
+ def dynamic_ld(self) -> bool:
391
+ return self._dynamic_ld
392
+
393
+ def copy_to_symbol(self, dst: "BlasLayoutType") -> str:
394
+ return self._copy_symbols_map[(self.uid, dst.uid)]
395
+
396
+ @property
397
+ def clear_symbol(self) -> str | None:
398
+ return self._clear_symbol
399
+
400
+ @property
401
+ def axpby_symbol(self) -> str | None:
402
+ return self._axpby_symbol
403
+
404
+
405
+ register_model(BlasLayoutType)(LayoutModel)
406
+
407
+
408
+ @lower_constant(BlasLayoutType)
409
+ def constant_blas_layout(context, builder, typ, pyval):
410
+ struct_ptr = cgutils.create_struct_proxy(typ)(context, builder)
411
+ return struct_ptr._getvalue()
412
+
413
+
414
+ @typeof_impl.register(_BlasLayout)
415
+ def typeof_blas_layout(val: _BlasLayout, c: typing.Context) -> BlasLayoutType:
416
+ assert val._MM is not None
417
+ return BlasLayoutType(val._MM, val._layout)
418
+
419
+
420
+ for attribute in ["size", "cosize"]:
421
+ overload_type_attribute(BlasLayoutType, "", attribute)
422
+
423
+
424
+ def ol_blas_layout(blas_numba: BlasType, method: str, leading_dimension: types.Number | None = None):
425
+ # leading_dimension is available only for global memory
426
+ if ("gmem" not in method) and (leading_dimension not in {None, types.Omitted(None)}):
427
+ return
428
+ MM = blas_numba.blas
429
+ if not MM._tensor_types:
430
+ return
431
+
432
+ return_type = BlasLayoutType(MM, method)
433
+
434
+ @intrinsic
435
+ def _intrinsic(typingctx, leading_dimension=None):
436
+ def codegen(context: BaseContext, builder: llvmir.IRBuilder, signature, args):
437
+ # Create empty struct to avoid runtime memory usage
438
+ layout = cgutils.create_struct_proxy(return_type)(context, builder)
439
+ if return_type.dynamic_ld:
440
+ if isinstance(leading_dimension, types.NoneType):
441
+ default_ld = MM.leading_dimension[return_type.tensor_index]
442
+ ld = context.get_constant(types.int64, default_ld)
443
+ else:
444
+ ld = args[0]
445
+ ld_ty = signature.args[0]
446
+ ld = context.cast(builder, ld, ld_ty, types.int64)
447
+ layout.leading_dimension = ld
448
+ return layout._getvalue()
449
+
450
+ return typing.signature(return_type, leading_dimension), codegen
451
+
452
+ return lambda blas_numba, leading_dimension=None: _intrinsic(leading_dimension)
453
+
454
+
455
+ def overload_blas_layout_method(method: str):
456
+ overload_method(
457
+ BlasType,
458
+ method,
459
+ target="cuda",
460
+ inline="always",
461
+ strict=False,
462
+ )(lambda blas_numba, leading_dimension=None: ol_blas_layout(blas_numba, method, leading_dimension))
463
+
464
+
465
+ for method in [
466
+ "get_layout_smem_a",
467
+ "get_layout_smem_b",
468
+ "get_layout_smem_c",
469
+ "get_layout_gmem_a",
470
+ "get_layout_gmem_b",
471
+ "get_layout_gmem_c",
472
+ "suggest_layout_smem_a",
473
+ "suggest_layout_smem_b",
474
+ "suggest_layout_smem_c",
475
+ "suggest_layout_rmem_c",
476
+ ]:
477
+ overload_blas_layout_method(method)
478
+
479
+
480
+ @overload(make_tensor, target="cuda", inline="always", strict=False)
481
+ def ol_make_tensor(array, layout):
482
+ assert isinstance(array, types.Array)
483
+ assert isinstance(layout, BlasLayoutType)
484
+ assert array.dtype == layout.dtype
485
+
486
+ return lambda array, layout: OpaqueTensor(array, layout)
487
+
488
+
489
+ @overload(copy_wait, target="cuda", inline="always", strict=False)
490
+ def ol_copy_wait():
491
+ # numba has cache per compute capability, so the function won't end up
492
+ # cached for the wrong compute capability.
493
+ ct = get_default_code_type()
494
+ symbol, _ = generate_copy_wait_lto(ct.cc)
495
+
496
+ @intrinsic
497
+ def _intrinsic(typingctx):
498
+ return_type = types.void
499
+ return typing.signature(return_type), make_function_call(symbol)
500
+
501
+ return lambda: _intrinsic()
502
+
503
+
504
+ @overload(axpby, target="cuda", inline="always", strict=False)
505
+ def ol_axpby(a, x, b, y):
506
+ if not isinstance(a, types.Number):
507
+ return
508
+ if not isinstance(x, OpaqueTensorType):
509
+ return
510
+ if not isinstance(b, types.Number):
511
+ return
512
+ if not isinstance(y, OpaqueTensorType):
513
+ return
514
+ if x != y:
515
+ raise TypeError("x and y must be the same tensor type")
516
+ if "rmem" not in x.layout.layout:
517
+ raise TypeError("axpby is only supported for rmem tensors")
518
+
519
+ symbol = x.layout.axpby_symbol
520
+
521
+ assert symbol is not None
522
+
523
+ @intrinsic
524
+ def _intrinsic(typingctx, a, x, b, y):
525
+ return_type = types.void
526
+ return typing.signature(return_type, x.dtype, x, y.dtype, y), make_function_call(symbol)
527
+
528
+ return lambda a, x, b, y: _intrinsic(a, x, b, y)