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.
- nvmath/__init__.pxd +0 -0
- nvmath/__init__.py +37 -0
- nvmath/_internal/__init__.py +0 -0
- nvmath/_internal/layout.py +58 -0
- nvmath/_utils.py +363 -0
- nvmath/bindings/__init__.pxd +0 -0
- nvmath/bindings/__init__.py +44 -0
- nvmath/bindings/_internal/__init__.pxd +0 -0
- nvmath/bindings/_internal/__init__.py +0 -0
- nvmath/bindings/_internal/cublas.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublas.pxd +518 -0
- nvmath/bindings/_internal/cublasLt.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublasLt.pxd +54 -0
- nvmath/bindings/_internal/cudss.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cudss.pxd +44 -0
- nvmath/bindings/_internal/cufft.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cufft.pxd +69 -0
- nvmath/bindings/_internal/cufftMp.pxd +77 -0
- nvmath/bindings/_internal/curand.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/curand.pxd +42 -0
- nvmath/bindings/_internal/cusolver.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolver.pxd +15 -0
- nvmath/bindings/_internal/cusolverDn.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolverDn.pxd +386 -0
- nvmath/bindings/_internal/cusparse.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusparse.pxd +270 -0
- nvmath/bindings/_internal/mathdx.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/mathdx.pxd +79 -0
- nvmath/bindings/_internal/nvshmem.pxd +29 -0
- nvmath/bindings/_internal/utils.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/utils.pxd +186 -0
- nvmath/bindings/cublas.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cublas.pxd +545 -0
- nvmath/bindings/cublas.pyi +18 -0
- nvmath/bindings/cublasLt.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cublasLt.pxd +99 -0
- nvmath/bindings/cudss.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cudss.pxd +83 -0
- nvmath/bindings/cudss.pyi +249 -0
- nvmath/bindings/cufft.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cufft.pxd +114 -0
- nvmath/bindings/cufftMp.pxd +124 -0
- nvmath/bindings/curand.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/curand.pxd +71 -0
- nvmath/bindings/cusolver.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cusolver.pxd +60 -0
- nvmath/bindings/cusolverDn.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cusolverDn.pxd +410 -0
- nvmath/bindings/cusparse.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cusparse.pxd +329 -0
- nvmath/bindings/cycublas.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cycublas.pxd +657 -0
- nvmath/bindings/cycublasLt.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cycublasLt.pxd +1010 -0
- nvmath/bindings/cycudss.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cycudss.pxd +191 -0
- nvmath/bindings/cycufft.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cycufft.pxd +320 -0
- nvmath/bindings/cycufftMp.pxd +333 -0
- nvmath/bindings/cycurand.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cycurand.pxd +146 -0
- nvmath/bindings/cycusolver.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolver.pxd +143 -0
- nvmath/bindings/cycusolverDn.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolverDn.pxd +414 -0
- nvmath/bindings/cycusparse.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cycusparse.pxd +476 -0
- nvmath/bindings/cymathdx.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/cymathdx.pxd +363 -0
- nvmath/bindings/cynvshmem.pxd +126 -0
- nvmath/bindings/mathdx.cp313-win_amd64.pyd +0 -0
- nvmath/bindings/mathdx.pxd +131 -0
- nvmath/bindings/mathdx.pyi +686 -0
- nvmath/bindings/nvpl/__init__.pxd +0 -0
- nvmath/bindings/nvpl/__init__.py +11 -0
- nvmath/bindings/nvpl/_internal/__init__.pxd +0 -0
- nvmath/bindings/nvpl/_internal/__init__.py +0 -0
- nvmath/bindings/nvpl/_internal/fft.pxd +36 -0
- nvmath/bindings/nvpl/cyfft.pxd +87 -0
- nvmath/bindings/nvpl/fft.pxd +100 -0
- nvmath/bindings/nvshmem.pxd +54 -0
- nvmath/device/__init__.py +23 -0
- nvmath/device/_deprecated.py +33 -0
- nvmath/device/caching.py +51 -0
- nvmath/device/common.py +131 -0
- nvmath/device/common_backend.py +125 -0
- nvmath/device/common_cuda.py +156 -0
- nvmath/device/common_mathdx.py +97 -0
- nvmath/device/common_numba.py +159 -0
- nvmath/device/common_opaque_tensor.py +128 -0
- nvmath/device/cublasdx.py +1085 -0
- nvmath/device/cublasdx_backend.py +552 -0
- nvmath/device/cublasdx_numba.py +528 -0
- nvmath/device/cufftdx.py +551 -0
- nvmath/device/cufftdx_backend.py +194 -0
- nvmath/device/cufftdx_numba.py +123 -0
- nvmath/device/curand_kernel.py +9147 -0
- nvmath/device/nvrtc.py +95 -0
- nvmath/device/patch.py +35 -0
- nvmath/device/random.py +417 -0
- nvmath/device/random_helpers.py +23 -0
- nvmath/device/random_states.py +189 -0
- nvmath/device/types.py +11 -0
- nvmath/device/vector_types_numba.py +203 -0
- nvmath/distributed/__init__.py +117 -0
- nvmath/distributed/_internal/__init__.py +0 -0
- nvmath/distributed/_internal/nvshmem.py +243 -0
- nvmath/distributed/_internal/tensor_ifc_cupy.py +111 -0
- nvmath/distributed/_internal/tensor_ifc_numpy.py +53 -0
- nvmath/distributed/_internal/tensor_ifc_torch.py +108 -0
- nvmath/distributed/_internal/tensor_wrapper.py +59 -0
- nvmath/distributed/_utils.py +152 -0
- nvmath/distributed/fft/__init__.py +6 -0
- nvmath/distributed/fft/_configuration.py +86 -0
- nvmath/distributed/fft/fft.py +1737 -0
- nvmath/distributed/reshape/__init__.py +6 -0
- nvmath/distributed/reshape/_configuration.py +39 -0
- nvmath/distributed/reshape/reshape.py +1249 -0
- nvmath/fft/__init__.py +7 -0
- nvmath/fft/_configuration.py +208 -0
- nvmath/fft/_exec_utils.py +116 -0
- nvmath/fft/_helpers.py +260 -0
- nvmath/fft/fft.py +2346 -0
- nvmath/internal/__init__.py +5 -0
- nvmath/internal/enum_utils.py +142 -0
- nvmath/internal/formatters.py +87 -0
- nvmath/internal/mem_limit.py +51 -0
- nvmath/internal/package_ifc.py +119 -0
- nvmath/internal/package_ifc_cuda.py +43 -0
- nvmath/internal/package_ifc_cupy.py +49 -0
- nvmath/internal/package_ifc_torch.py +31 -0
- nvmath/internal/package_wrapper.py +14 -0
- nvmath/internal/tensor_ifc.py +143 -0
- nvmath/internal/tensor_ifc_cupy.py +185 -0
- nvmath/internal/tensor_ifc_numpy.py +157 -0
- nvmath/internal/tensor_ifc_torch.py +115 -0
- nvmath/internal/tensor_wrapper.py +160 -0
- nvmath/internal/typemaps.py +154 -0
- nvmath/internal/utils.py +634 -0
- nvmath/linalg/__init__.py +11 -0
- nvmath/linalg/_internal/__init__.py +3 -0
- nvmath/linalg/_internal/algo_cap_ifc.py +86 -0
- nvmath/linalg/_internal/algo_config_ifc.py +87 -0
- nvmath/linalg/_internal/enum_to_tuples.py +64 -0
- nvmath/linalg/_internal/epilog_protocol.py +738 -0
- nvmath/linalg/_internal/matmul_desc_ifc.py +72 -0
- nvmath/linalg/_internal/matmul_pref_ifc.py +65 -0
- nvmath/linalg/_internal/matrix_layout_ifc.py +59 -0
- nvmath/linalg/_internal/typemaps.py +135 -0
- nvmath/linalg/_internal/utils.py +96 -0
- nvmath/linalg/advanced/__init__.py +8 -0
- nvmath/linalg/advanced/_algorithmmod.py +142 -0
- nvmath/linalg/advanced/_configuration.py +320 -0
- nvmath/linalg/advanced/helpers/__init__.py +5 -0
- nvmath/linalg/advanced/helpers/matmul.py +173 -0
- nvmath/linalg/advanced/matmulmod.py +2855 -0
- nvmath/memory.py +266 -0
- nvmath/sparse/__init__.py +18 -0
- nvmath/sparse/_internal/__init__.py +21 -0
- nvmath/sparse/_internal/common_utils.py +81 -0
- nvmath/sparse/_internal/cudss_config_ifc.py +584 -0
- nvmath/sparse/_internal/cudss_data_ifc.py +291 -0
- nvmath/sparse/_internal/cudss_utils.py +398 -0
- nvmath/sparse/_internal/sparse_csr_ifc.py +154 -0
- nvmath/sparse/_internal/sparse_format_helpers.py +88 -0
- nvmath/sparse/_internal/sparse_tensor_ifc.py +80 -0
- nvmath/sparse/advanced/__init__.py +7 -0
- nvmath/sparse/advanced/_configuration.py +150 -0
- nvmath/sparse/advanced/direct_solver.py +1705 -0
- nvmath_python-0.5.0.dist-info/METADATA +122 -0
- nvmath_python-0.5.0.dist-info/RECORD +174 -0
- nvmath_python-0.5.0.dist-info/WHEEL +5 -0
- nvmath_python-0.5.0.dist-info/licenses/LICENSE +177 -0
- 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)
|