nvmath-python 0.9.0__cp314-cp314-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nvmath/__init__.pxd +0 -0
- nvmath/__init__.py +45 -0
- nvmath/_internal/__init__.py +0 -0
- nvmath/_internal/attribute_ifc_factory.py +330 -0
- nvmath/_internal/layout.py +70 -0
- nvmath/_internal/templates.py +383 -0
- nvmath/_utils.py +150 -0
- nvmath/bindings/__init__.py +51 -0
- nvmath/bindings/_internal/__init__.pxd +0 -0
- nvmath/bindings/_internal/__init__.py +0 -0
- nvmath/bindings/_internal/cublas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublas.pxd +530 -0
- nvmath/bindings/_internal/cublasLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublasLt.pxd +59 -0
- nvmath/bindings/_internal/cublasMp.pxd +52 -0
- nvmath/bindings/_internal/cudss.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cudss.pxd +47 -0
- nvmath/bindings/_internal/cufft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cufft.pxd +70 -0
- nvmath/bindings/_internal/cufftMp.pxd +77 -0
- nvmath/bindings/_internal/curand.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/curand.pxd +42 -0
- nvmath/bindings/_internal/cusolver.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolver.pxd +15 -0
- nvmath/bindings/_internal/cusolverDn.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolverDn.pxd +406 -0
- nvmath/bindings/_internal/cusparse.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusparse.pxd +277 -0
- nvmath/bindings/_internal/cusparseLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusparseLt.pxd +48 -0
- nvmath/bindings/_internal/cutensor.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cutensor.pxd +58 -0
- nvmath/bindings/_internal/mathdx.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/mathdx.pxd +116 -0
- nvmath/bindings/_internal/nvshmem.pxd +29 -0
- nvmath/bindings/_internal/utils.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/utils.pxd +179 -0
- nvmath/bindings/_internal/utils.pyi +10 -0
- nvmath/bindings/cublas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cublas.pxd +558 -0
- nvmath/bindings/cublas.pyi +746 -0
- nvmath/bindings/cublasLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cublasLt.pxd +109 -0
- nvmath/bindings/cublasLt.pyi +1337 -0
- nvmath/bindings/cublasMp.pxd +85 -0
- nvmath/bindings/cublasMp.pyi +219 -0
- nvmath/bindings/cudss.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cudss.pxd +86 -0
- nvmath/bindings/cudss.pyi +282 -0
- nvmath/bindings/cufft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cufft.pxd +118 -0
- nvmath/bindings/cufft.pyi +241 -0
- nvmath/bindings/cufftMp.pxd +124 -0
- nvmath/bindings/cufftMp.pyi +260 -0
- nvmath/bindings/curand.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/curand.pxd +71 -0
- nvmath/bindings/curand.pyi +159 -0
- nvmath/bindings/cusolver.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cusolver.pxd +62 -0
- nvmath/bindings/cusolver.pyi +242 -0
- nvmath/bindings/cusolverDn.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cusolverDn.pxd +430 -0
- nvmath/bindings/cusolverDn.pyi +416 -0
- nvmath/bindings/cusparse.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cusparse.pxd +338 -0
- nvmath/bindings/cusparse.pyi +659 -0
- nvmath/bindings/cusparseLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cusparseLt.pxd +99 -0
- nvmath/bindings/cusparseLt.pyi +198 -0
- nvmath/bindings/cutensor.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cutensor.pxd +98 -0
- nvmath/bindings/cutensor.pyi +294 -0
- nvmath/bindings/cycublas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycublas.pxd +684 -0
- nvmath/bindings/cycublasLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycublasLt.pxd +1055 -0
- nvmath/bindings/cycublasMp.pxd +183 -0
- nvmath/bindings/cycudss.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycudss.pxd +224 -0
- nvmath/bindings/cycufft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycufft.pxd +326 -0
- nvmath/bindings/cycufftMp.pxd +334 -0
- nvmath/bindings/cycurand.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycurand.pxd +146 -0
- nvmath/bindings/cycusolver.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolver.pxd +154 -0
- nvmath/bindings/cycusolverDn.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolverDn.pxd +446 -0
- nvmath/bindings/cycusparse.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycusparse.pxd +470 -0
- nvmath/bindings/cycusparseLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycusparseLt.pxd +150 -0
- nvmath/bindings/cycutensor.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycutensor.pxd +192 -0
- nvmath/bindings/cymathdx.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cymathdx.pxd +552 -0
- nvmath/bindings/cynvshmem.pxd +126 -0
- nvmath/bindings/mathdx.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/mathdx.pxd +182 -0
- nvmath/bindings/mathdx.pyi +1244 -0
- nvmath/bindings/nvpl/__init__.pxd +0 -0
- nvmath/bindings/nvpl/__init__.py +13 -0
- nvmath/bindings/nvpl/_internal/__init__.pxd +0 -0
- nvmath/bindings/nvpl/_internal/__init__.py +0 -0
- nvmath/bindings/nvpl/_internal/blas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/_internal/blas.pxd +125 -0
- nvmath/bindings/nvpl/_internal/fft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/_internal/fft.pxd +36 -0
- nvmath/bindings/nvpl/blas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/blas.pxd +85 -0
- nvmath/bindings/nvpl/blas.pyi +122 -0
- nvmath/bindings/nvpl/cyblas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/cyblas.pxd +166 -0
- nvmath/bindings/nvpl/cyfft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/cyfft.pxd +92 -0
- nvmath/bindings/nvpl/fft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/fft.pxd +100 -0
- nvmath/bindings/nvpl/fft.pyi +100 -0
- nvmath/bindings/nvshmem.pxd +54 -0
- nvmath/bindings/nvshmem.pyi +179 -0
- nvmath/device/__init__.py +21 -0
- nvmath/device/_deprecated.py +33 -0
- nvmath/device/common.py +313 -0
- nvmath/device/common_backend.py +131 -0
- nvmath/device/common_cuda.py +201 -0
- nvmath/device/common_numba.py +310 -0
- nvmath/device/common_opaque_tensor.py +201 -0
- nvmath/device/cublasdx.py +1805 -0
- nvmath/device/cublasdx_backend.py +807 -0
- nvmath/device/cublasdx_numba.py +1612 -0
- nvmath/device/cufftdx.py +510 -0
- nvmath/device/cufftdx_backend.py +196 -0
- nvmath/device/cufftdx_numba.py +196 -0
- nvmath/device/curand_kernel.py +9147 -0
- nvmath/device/cusolverdx.py +2690 -0
- nvmath/device/cusolverdx_backend.py +440 -0
- nvmath/device/cusolverdx_numba.py +1624 -0
- nvmath/device/llvm_array.py +29 -0
- nvmath/device/random.py +445 -0
- nvmath/device/random_helpers.py +23 -0
- nvmath/device/random_states.py +187 -0
- nvmath/device/types.py +147 -0
- nvmath/device/vector_types_numba.py +203 -0
- nvmath/distributed/__init__.py +205 -0
- nvmath/distributed/_internal/__init__.py +0 -0
- nvmath/distributed/_internal/nvshmem.py +302 -0
- nvmath/distributed/_internal/tensor_ifc.py +67 -0
- nvmath/distributed/_internal/tensor_ifc_cupy.py +62 -0
- nvmath/distributed/_internal/tensor_ifc_host_device.py +165 -0
- nvmath/distributed/_internal/tensor_ifc_numpy.py +41 -0
- nvmath/distributed/_internal/tensor_ifc_torch.py +141 -0
- nvmath/distributed/_internal/tensor_wrapper.py +78 -0
- nvmath/distributed/_utils.py +167 -0
- nvmath/distributed/distribution.py +770 -0
- nvmath/distributed/fft/__init__.py +7 -0
- nvmath/distributed/fft/_configuration.py +79 -0
- nvmath/distributed/fft/fft.py +2801 -0
- nvmath/distributed/linalg/__init__.py +12 -0
- nvmath/distributed/linalg/_internal/__init__.py +3 -0
- nvmath/distributed/linalg/_internal/epilog_protocol.py +496 -0
- nvmath/distributed/linalg/_internal/matmul_desc_ifc.py +28 -0
- nvmath/distributed/linalg/advanced/__init__.py +8 -0
- nvmath/distributed/linalg/advanced/_configuration.py +166 -0
- nvmath/distributed/linalg/advanced/matmulmod.py +2908 -0
- nvmath/distributed/process_group.py +408 -0
- nvmath/distributed/reshape/__init__.py +6 -0
- nvmath/distributed/reshape/_configuration.py +39 -0
- nvmath/distributed/reshape/reshape.py +1256 -0
- nvmath/fft/__init__.py +7 -0
- nvmath/fft/_configuration.py +208 -0
- nvmath/fft/_exec_utils.py +109 -0
- nvmath/fft/_helpers.py +237 -0
- nvmath/fft/fft.py +2903 -0
- nvmath/internal/__init__.pxd +3 -0
- nvmath/internal/__init__.py +10 -0
- nvmath/internal/_bindings.cp314-win_amd64.pyd +0 -0
- nvmath/internal/_bindings.pxd +12 -0
- nvmath/internal/_device_utils.py +54 -0
- nvmath/internal/enum_utils.py +142 -0
- nvmath/internal/formatters.py +87 -0
- nvmath/internal/mem_limit.py +51 -0
- nvmath/internal/memory.cp314-win_amd64.pyd +0 -0
- nvmath/internal/memory.pxd +10 -0
- nvmath/internal/memory.pyi +46 -0
- nvmath/internal/ndbuffer/__init__.pxd +3 -0
- nvmath/internal/ndbuffer/__init__.py +7 -0
- nvmath/internal/ndbuffer/copy_kernel/args.h +34 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/array_view.h +52 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/elementwise.h +68 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/grid_indexer.h +69 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/transposed.h +240 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/type_utils.h +39 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/utils.h +132 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/vec.h +159 -0
- nvmath/internal/ndbuffer/copy_kernel/elementwise.h +53 -0
- nvmath/internal/ndbuffer/copy_kernel/transposed.h +58 -0
- nvmath/internal/ndbuffer/copy_kernel.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/copy_kernel.pxd +9 -0
- nvmath/internal/ndbuffer/copy_kernel.pyi +9 -0
- nvmath/internal/ndbuffer/data_layout.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/data_layout.pxd +72 -0
- nvmath/internal/ndbuffer/data_layout.pyi +23 -0
- nvmath/internal/ndbuffer/jit.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/jit.pxd +7 -0
- nvmath/internal/ndbuffer/jit.pyi +6 -0
- nvmath/internal/ndbuffer/ndbuffer.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/ndbuffer.pxd +36 -0
- nvmath/internal/ndbuffer/ndbuffer.pyi +41 -0
- nvmath/internal/ndbuffer/package_utils.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/package_utils.pxd +11 -0
- nvmath/internal/ndbuffer/package_utils.pyi +12 -0
- nvmath/internal/package_ifc.py +147 -0
- nvmath/internal/package_ifc_cuda.py +49 -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 +194 -0
- nvmath/internal/tensor_ifc_cupy.py +241 -0
- nvmath/internal/tensor_ifc_ndbuffer.py +153 -0
- nvmath/internal/tensor_ifc_numpy.py +183 -0
- nvmath/internal/tensor_ifc_torch.py +176 -0
- nvmath/internal/tensor_wrapper.py +157 -0
- nvmath/internal/typemaps.py +162 -0
- nvmath/internal/utils.py +771 -0
- nvmath/linalg/__init__.py +46 -0
- nvmath/linalg/_internal/__init__.py +3 -0
- nvmath/linalg/_internal/algo_cap_ifc.py +82 -0
- nvmath/linalg/_internal/algo_config_ifc.py +43 -0
- nvmath/linalg/_internal/batch.py +217 -0
- nvmath/linalg/_internal/enum_to_tuples.py +64 -0
- nvmath/linalg/_internal/epilog_protocol.py +766 -0
- nvmath/linalg/_internal/layout.py +624 -0
- nvmath/linalg/_internal/matmul_desc_ifc.py +28 -0
- nvmath/linalg/_internal/matmul_pref_ifc.py +27 -0
- nvmath/linalg/_internal/matrix_layout_ifc.py +26 -0
- nvmath/linalg/_internal/typemaps.py +144 -0
- nvmath/linalg/_internal/utils.py +134 -0
- nvmath/linalg/advanced/__init__.py +8 -0
- nvmath/linalg/advanced/_algorithmmod.py +149 -0
- nvmath/linalg/advanced/_configuration.py +349 -0
- nvmath/linalg/advanced/helpers/__init__.py +5 -0
- nvmath/linalg/advanced/helpers/matmul.py +1348 -0
- nvmath/linalg/advanced/matmulmod.py +3937 -0
- nvmath/linalg/generic/__init__.py +43 -0
- nvmath/linalg/generic/_configuration/__init__.py +37 -0
- nvmath/linalg/generic/_configuration/layout.py +263 -0
- nvmath/linalg/generic/_configuration/match.py +609 -0
- nvmath/linalg/generic/_configuration/qualifiers.py +494 -0
- nvmath/linalg/generic/_configuration/wrap.py +217 -0
- nvmath/linalg/generic/_dtype.py +15 -0
- nvmath/linalg/generic/matmulmod.py +1060 -0
- nvmath/memory.py +282 -0
- nvmath/sparse/__init__.py +38 -0
- nvmath/sparse/_internal/__init__.py +21 -0
- nvmath/sparse/_internal/common_utils.py +144 -0
- nvmath/sparse/_internal/cudss_config_ifc.py +741 -0
- nvmath/sparse/_internal/cudss_data_ifc.py +399 -0
- nvmath/sparse/_internal/cudss_utils.py +445 -0
- nvmath/sparse/_internal/cusparse_utils.py +382 -0
- nvmath/sparse/_internal/sparse_bsc_ifc.py +300 -0
- nvmath/sparse/_internal/sparse_bsr_ifc.py +303 -0
- nvmath/sparse/_internal/sparse_coo_ifc.py +254 -0
- nvmath/sparse/_internal/sparse_csc_ifc.py +266 -0
- nvmath/sparse/_internal/sparse_csr_ifc.py +266 -0
- nvmath/sparse/_internal/sparse_dia_ifc.py +239 -0
- nvmath/sparse/_internal/sparse_format_helpers.py +601 -0
- nvmath/sparse/_internal/sparse_tensor_ifc.py +121 -0
- nvmath/sparse/_internal/sparse_ust_ifc.py +146 -0
- nvmath/sparse/_internal/utils.py +56 -0
- nvmath/sparse/advanced/__init__.py +7 -0
- nvmath/sparse/advanced/_configuration.py +230 -0
- nvmath/sparse/advanced/direct_solver.py +1884 -0
- nvmath/sparse/generic/__init__.py +7 -0
- nvmath/sparse/generic/_configuration.py +129 -0
- nvmath/sparse/generic/_helpers.py +137 -0
- nvmath/sparse/generic/_thunks.py +21 -0
- nvmath/sparse/generic/matmulmod.py +2426 -0
- nvmath/sparse/ust/__init__.py +7 -0
- nvmath/sparse/ust/_converters.py +378 -0
- nvmath/sparse/ust/_drawer.py +552 -0
- nvmath/sparse/ust/_emitter.py +553 -0
- nvmath/sparse/ust/_jit.py +212 -0
- nvmath/sparse/ust/_kernel.py +346 -0
- nvmath/sparse/ust/_semiring.py +71 -0
- nvmath/sparse/ust/_utils.py +102 -0
- nvmath/sparse/ust/interfaces/__init__.py +0 -0
- nvmath/sparse/ust/interfaces/torch_interface.py +476 -0
- nvmath/sparse/ust/semiring_ops.py +71 -0
- nvmath/sparse/ust/tensor.py +1027 -0
- nvmath/sparse/ust/tensor_drawer.py +552 -0
- nvmath/sparse/ust/tensor_emitter.py +558 -0
- nvmath/sparse/ust/tensor_format.py +935 -0
- nvmath/sparse/ust/tensor_jit.py +212 -0
- nvmath/sparse/ust/tensor_kernel.py +348 -0
- nvmath/sparse/ust/tensor_utils.py +380 -0
- nvmath/tensor/__init__.py +6 -0
- nvmath/tensor/_configuration.py +95 -0
- nvmath/tensor/_internal/__init__.py +3 -0
- nvmath/tensor/_internal/cutensor_config_ifc.py +247 -0
- nvmath/tensor/_internal/cutensor_utils.py +162 -0
- nvmath/tensor/_internal/data.py +43 -0
- nvmath/tensor/_internal/einsum_parser.py +444 -0
- nvmath/tensor/_internal/typemaps.py +96 -0
- nvmath/tensor/contract.py +1861 -0
- nvmath_python-0.9.0.dist-info/METADATA +127 -0
- nvmath_python-0.9.0.dist-info/RECORD +309 -0
- nvmath_python-0.9.0.dist-info/WHEEL +5 -0
- nvmath_python-0.9.0.dist-info/licenses/LICENSE +177 -0
- nvmath_python-0.9.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"current_device_lto",
|
|
7
|
+
"current_device_sm",
|
|
8
|
+
"ComputeCapability",
|
|
9
|
+
"CodeType",
|
|
10
|
+
"ISAVersion",
|
|
11
|
+
"Code",
|
|
12
|
+
"Dim3",
|
|
13
|
+
"MAX_SUPPORTED_CC",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
import logging
|
|
17
|
+
from collections import namedtuple
|
|
18
|
+
from typing import NamedTuple
|
|
19
|
+
|
|
20
|
+
from cuda.bindings import driver as cudadrv
|
|
21
|
+
from cuda.bindings import runtime as cudart
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# Code = CodeType + ISAVersion + buffer
|
|
25
|
+
class Code(namedtuple("Code", ("code_type", "isa_version", "data"))):
|
|
26
|
+
"""
|
|
27
|
+
A namedtuple class that encapsulates code type, version, and buffer.
|
|
28
|
+
|
|
29
|
+
Attributes:
|
|
30
|
+
code_type (CodeType): The underlying code type.
|
|
31
|
+
isa_version (ISAVersion): The instruction set architecture version for the code.
|
|
32
|
+
data: The buffer pointer.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
__slots__ = ()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# CodeType = type + CC
|
|
39
|
+
class CodeType(namedtuple("CodeType", ("kind", "cc"))):
|
|
40
|
+
"""
|
|
41
|
+
A namedtuple class that encapsulates code kind and compute capability.
|
|
42
|
+
|
|
43
|
+
Attributes:
|
|
44
|
+
kind (str): A string denoting the nature of the code, e.g, ``'lto'``.
|
|
45
|
+
cc (ComputeCapability): The current GPU compute capability.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
__slots__ = ()
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# CC = e.g. SM 9.0 (Hopper)
|
|
52
|
+
class ComputeCapability(NamedTuple):
|
|
53
|
+
"""
|
|
54
|
+
A namedtuple class that encapsulates the major and minor compute capability.
|
|
55
|
+
|
|
56
|
+
Attributes:
|
|
57
|
+
major (int): The major compute capability.
|
|
58
|
+
minor (int): The minor compute capability.
|
|
59
|
+
arch (str): An optional string representing the GPU accelerated
|
|
60
|
+
architecture. Must be either empty or one of 'f' (for Family),
|
|
61
|
+
'a' (for Architecture).
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
major: int
|
|
65
|
+
minor: int
|
|
66
|
+
arch: str = ""
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def integer(self) -> int:
|
|
70
|
+
"""Integer representation of the ISAVersion"""
|
|
71
|
+
return self.major * 100 + self.minor * 10
|
|
72
|
+
|
|
73
|
+
def __str__(self):
|
|
74
|
+
"""String representation of the ComputeCapability"""
|
|
75
|
+
return f"{self.major}.{self.minor}{self.arch}"
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
MIN_SUPPORTED_CC = ComputeCapability(7, 0)
|
|
79
|
+
MAX_SUPPORTED_CC = ComputeCapability(12, 1)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class Dim3(namedtuple("Dim3", ("x", "y", "z"), defaults=(1, 1, 1))):
|
|
83
|
+
"""
|
|
84
|
+
A namedtuple class that encapsulates the dimensions for grids and blocks.
|
|
85
|
+
|
|
86
|
+
Attributes:
|
|
87
|
+
x (int): The dimension in the x direction (default 1).
|
|
88
|
+
y (int): The dimension in the y direction (default 1).
|
|
89
|
+
z (int): The dimension in the z direction (default 1).
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
__slots__ = ()
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# ISAVersion = e.g. 12.3 (from CUDA 12.3)
|
|
96
|
+
class ISAVersion(NamedTuple):
|
|
97
|
+
"""
|
|
98
|
+
A namedtuple class that encapsulates the code version.
|
|
99
|
+
|
|
100
|
+
Attributes:
|
|
101
|
+
major (int): The major code version.
|
|
102
|
+
minor (int): The minor code version.
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
major: int
|
|
106
|
+
minor: int
|
|
107
|
+
|
|
108
|
+
@classmethod
|
|
109
|
+
def from_integer(cls, isa: int):
|
|
110
|
+
major = isa // 1000
|
|
111
|
+
minor = (isa % 1000) // 10
|
|
112
|
+
|
|
113
|
+
return cls(major, minor)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def CHECK_CUDART(err):
|
|
117
|
+
if err != cudart.cudaError_t.cudaSuccess:
|
|
118
|
+
err2, str = cudart.cudaGetErrorString(err)
|
|
119
|
+
raise RuntimeError(f"CUDArt Error: {str} ({err})")
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def CHECK_CUDA(err):
|
|
123
|
+
if err != cudadrv.CUresult.CUDA_SUCCESS:
|
|
124
|
+
err2, str = cudadrv.cuGetErrorName(err)
|
|
125
|
+
raise RuntimeError(f"CUDA Error: {str} ({err})")
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def get_current_device() -> int:
|
|
129
|
+
(err,) = cudadrv.cuInit(0)
|
|
130
|
+
CHECK_CUDA(err)
|
|
131
|
+
# Check if a context exist
|
|
132
|
+
err, pctx = cudadrv.cuCtxGetCurrent()
|
|
133
|
+
CHECK_CUDA(err)
|
|
134
|
+
if int(pctx) == 0:
|
|
135
|
+
# If not, return the CC of device 0
|
|
136
|
+
device = 0
|
|
137
|
+
else:
|
|
138
|
+
err, device = cudart.cudaGetDevice()
|
|
139
|
+
CHECK_CUDART(err)
|
|
140
|
+
|
|
141
|
+
return device
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def get_current_device_cc():
|
|
145
|
+
(err,) = cudadrv.cuInit(0)
|
|
146
|
+
CHECK_CUDA(err)
|
|
147
|
+
# Check if a context exist
|
|
148
|
+
err, pctx = cudadrv.cuCtxGetCurrent()
|
|
149
|
+
CHECK_CUDA(err)
|
|
150
|
+
if int(pctx) == 0:
|
|
151
|
+
# If not, return the CC of device 0
|
|
152
|
+
device = 0
|
|
153
|
+
else:
|
|
154
|
+
err, device = cudart.cudaGetDevice()
|
|
155
|
+
CHECK_CUDART(err)
|
|
156
|
+
err, prop = cudart.cudaGetDeviceProperties(device)
|
|
157
|
+
CHECK_CUDART(err)
|
|
158
|
+
major, minor = prop.major, prop.minor
|
|
159
|
+
if (major, minor) > MAX_SUPPORTED_CC:
|
|
160
|
+
logging.info(
|
|
161
|
+
"The current device supports compute capability "
|
|
162
|
+
f"{prop.major}.{prop.minor}, but the generated LTO version is "
|
|
163
|
+
f"capped at {MAX_SUPPORTED_CC}."
|
|
164
|
+
)
|
|
165
|
+
major, minor = MAX_SUPPORTED_CC
|
|
166
|
+
logging.info(f"Using device {device} for default compute capability, found cc = {prop.major}.{prop.minor}")
|
|
167
|
+
arch = ""
|
|
168
|
+
if (major, minor) >= (9, 0):
|
|
169
|
+
arch = "a"
|
|
170
|
+
return ComputeCapability(major, minor, arch)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def get_default_code_type() -> CodeType:
|
|
174
|
+
try:
|
|
175
|
+
return CodeType("lto", get_current_device_cc())
|
|
176
|
+
except RuntimeError as e:
|
|
177
|
+
raise ValueError(f"Failed to get the current GPU compute capability (got {e}). Set code_type explicitly.") from e
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def current_device_lto():
|
|
181
|
+
"""
|
|
182
|
+
A helper function to get the default code type for link time optimization (LTO) on the
|
|
183
|
+
current device.
|
|
184
|
+
|
|
185
|
+
Returns:
|
|
186
|
+
A :class:`CodeType` object representing the default LTO code type for the current
|
|
187
|
+
device.
|
|
188
|
+
"""
|
|
189
|
+
return get_default_code_type()
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def current_device_sm() -> ComputeCapability:
|
|
193
|
+
"""
|
|
194
|
+
A helper function to get the default SM for mathdx types on the
|
|
195
|
+
current device.
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
A :class:`ComputeCapability` object representing the default SM for
|
|
199
|
+
mathdx types on the current device.
|
|
200
|
+
"""
|
|
201
|
+
return get_current_device_cc()
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
import llvmlite.ir as llvmir
|
|
9
|
+
import numpy as np
|
|
10
|
+
from llvmlite import ir
|
|
11
|
+
from numba import types
|
|
12
|
+
from numba.core import cgutils, typing
|
|
13
|
+
from numba.core.base import BaseContext
|
|
14
|
+
from numba.core.errors import TypingError
|
|
15
|
+
from numba.cuda.cudaimpl import lower_constant
|
|
16
|
+
from numba.cuda.extending import intrinsic, overload, overload_attribute, register_model
|
|
17
|
+
from numba.extending import models, typeof_impl
|
|
18
|
+
|
|
19
|
+
from nvmath.bindings import mathdx
|
|
20
|
+
|
|
21
|
+
from .llvm_array import LLVMArray
|
|
22
|
+
from .types import Complex, Vector, complex32, complex64, complex128, half2, half4, np_float16x2, np_float16x4
|
|
23
|
+
from .vector_types_numba import float16x2_type, float16x4_type, float32x2_type, float64x2_type
|
|
24
|
+
|
|
25
|
+
NP_TYPES_TO_NUMBA_FE_TYPES = {
|
|
26
|
+
np.float16: np.float16,
|
|
27
|
+
np.float32: np.float32,
|
|
28
|
+
np.float64: np.float64,
|
|
29
|
+
np_float16x2: float16x2_type,
|
|
30
|
+
np_float16x4: float16x4_type,
|
|
31
|
+
np.complex64: float32x2_type,
|
|
32
|
+
np.complex128: float64x2_type,
|
|
33
|
+
np.int8: np.int8,
|
|
34
|
+
np.int16: np.int16,
|
|
35
|
+
np.int32: np.int32,
|
|
36
|
+
np.int64: np.int64,
|
|
37
|
+
np.uint8: np.uint8,
|
|
38
|
+
np.uint16: np.uint16,
|
|
39
|
+
np.uint32: np.uint32,
|
|
40
|
+
np.uint64: np.uint64,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
NUMBA_FE_TYPES_TO_NUMBA_IR = {
|
|
44
|
+
np.float16: types.float16,
|
|
45
|
+
np.float32: types.float32,
|
|
46
|
+
np.float64: types.float64,
|
|
47
|
+
complex32: float16x2_type,
|
|
48
|
+
complex64: float32x2_type,
|
|
49
|
+
complex128: float64x2_type,
|
|
50
|
+
half2: float16x2_type,
|
|
51
|
+
half4: float16x4_type,
|
|
52
|
+
float16x2_type: float16x2_type,
|
|
53
|
+
float16x4_type: float16x4_type,
|
|
54
|
+
float32x2_type: float32x2_type,
|
|
55
|
+
float64x2_type: float64x2_type,
|
|
56
|
+
np.int8: types.int8,
|
|
57
|
+
np.int16: types.int16,
|
|
58
|
+
np.int32: types.int32,
|
|
59
|
+
np.int64: types.int64,
|
|
60
|
+
np.uint8: types.uint8,
|
|
61
|
+
np.uint16: types.uint16,
|
|
62
|
+
np.uint32: types.uint32,
|
|
63
|
+
np.uint64: types.uint64,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class EmptyStructModel(models.StructModel):
|
|
68
|
+
"""Data model that does not take space. Intended to be used with types that
|
|
69
|
+
are presented only at typing stage and not represented in memory."""
|
|
70
|
+
|
|
71
|
+
def __init__(self, dmm, fe_type):
|
|
72
|
+
members = []
|
|
73
|
+
super().__init__(dmm, fe_type, members)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def overload_type_attribute(numba_type, attribute_base, attribute):
|
|
77
|
+
"""Make type attribute available inside jitted code."""
|
|
78
|
+
assert issubclass(numba_type, types.Type)
|
|
79
|
+
|
|
80
|
+
@overload_attribute(numba_type, attribute, inline="always")
|
|
81
|
+
def ol_blas_attribute(blas_numba):
|
|
82
|
+
tp = blas_numba
|
|
83
|
+
if attribute_base != "":
|
|
84
|
+
tp = getattr(tp, attribute_base)
|
|
85
|
+
val = getattr(tp, attribute)
|
|
86
|
+
return lambda blas_numba: val
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@typeof_impl.register(Complex)
|
|
90
|
+
def typeof_complex(val: Complex, c: typing.Context) -> Any:
|
|
91
|
+
if val.real_dtype == np.float16:
|
|
92
|
+
return types.NumberClass(float16x2_type)
|
|
93
|
+
elif val.real_dtype == np.float32:
|
|
94
|
+
return types.NumberClass(float32x2_type)
|
|
95
|
+
elif val.real_dtype == np.float64:
|
|
96
|
+
return types.NumberClass(float64x2_type)
|
|
97
|
+
|
|
98
|
+
raise RuntimeError(f"Unsupported complex real dtype {val.real_dtype}")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@typeof_impl.register(Vector)
|
|
102
|
+
def typeof_vector(val: Vector, c: typing.Context) -> Any:
|
|
103
|
+
if val.real_dtype != np.float16 or val.size not in (2, 4):
|
|
104
|
+
raise RuntimeError(f"Unsupported vector type {val.real_dtype}x{val.size}")
|
|
105
|
+
|
|
106
|
+
return types.NumberClass(float16x2_type if val.size == 2 else float16x4_type)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@intrinsic
|
|
110
|
+
def get_array_ptr(typingctx: typing.Context, arr):
|
|
111
|
+
"""Get raw pointer to the data of a Numba array."""
|
|
112
|
+
assert isinstance(arr, types.Array)
|
|
113
|
+
|
|
114
|
+
sig = typing.signature(types.CPointer(arr.dtype), arr)
|
|
115
|
+
|
|
116
|
+
def codegen(context: BaseContext, builder, sig, args):
|
|
117
|
+
arrTy = sig.args[0]
|
|
118
|
+
arr = args[0]
|
|
119
|
+
|
|
120
|
+
dtype = arrTy.dtype
|
|
121
|
+
valueTy = context.get_value_type(dtype)
|
|
122
|
+
ptrTy = ir.PointerType(valueTy)
|
|
123
|
+
if arr is None:
|
|
124
|
+
ptr = ptrTy(None)
|
|
125
|
+
else:
|
|
126
|
+
ptr = cgutils.create_struct_proxy(arrTy)(context, builder, arr).data
|
|
127
|
+
|
|
128
|
+
# Future release of numba-cuda may have support for address spaces.
|
|
129
|
+
# It is not supported to pass a non generic pointer to device function
|
|
130
|
+
# call.
|
|
131
|
+
if ptr.type.addrspace != 0:
|
|
132
|
+
ptr = builder.addrspacecast(ptr, ir.PointerType(ptr.type.pointee), "generic")
|
|
133
|
+
|
|
134
|
+
return ptr
|
|
135
|
+
|
|
136
|
+
return sig, codegen
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def build_get_value_ptr(target_type=None):
|
|
140
|
+
@intrinsic
|
|
141
|
+
def get_value_ptr_impl(typingctx: typing.Context, value):
|
|
142
|
+
"""Get raw pointer to the value."""
|
|
143
|
+
if value not in [float16x2_type, float16x4_type, float32x2_type, float64x2_type] and not isinstance( # noqa: UP038
|
|
144
|
+
value, (types.Float, types.Complex, types.Integer)
|
|
145
|
+
):
|
|
146
|
+
raise TypingError(f"get_value_ptr does not support type {value}")
|
|
147
|
+
|
|
148
|
+
return_type = target_type if target_type is not None else value
|
|
149
|
+
sig = typing.signature(types.CPointer(return_type), value)
|
|
150
|
+
|
|
151
|
+
def codegen(context: BaseContext, builder, sig, args):
|
|
152
|
+
if target_type is not None and sig.args[0] != target_type:
|
|
153
|
+
value = context.cast(builder, args[0], sig.args[0], target_type)
|
|
154
|
+
else:
|
|
155
|
+
value = args[0]
|
|
156
|
+
return cgutils.alloca_once_value(builder, value)
|
|
157
|
+
|
|
158
|
+
return sig, codegen
|
|
159
|
+
|
|
160
|
+
return get_value_ptr_impl
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
get_value_ptr = build_get_value_ptr()
|
|
164
|
+
get_uint32_value_ptr = build_get_value_ptr(target_type=types.uint32)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class MathdxOpaqueTensorType(types.Type):
|
|
168
|
+
def __init__(self, dynamic_strides_size=0, dynamic_shape_size=0):
|
|
169
|
+
self.dynamic_strides_size = dynamic_strides_size
|
|
170
|
+
self.dynamic_shape_size = dynamic_shape_size
|
|
171
|
+
super().__init__(f"MathdxOpaqueTensor({dynamic_strides_size}, {dynamic_shape_size})")
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
@register_model(MathdxOpaqueTensorType)
|
|
175
|
+
class MathdxOpaqueTensorModel(models.StructModel):
|
|
176
|
+
def __init__(self, dmm, fe_type: MathdxOpaqueTensorType):
|
|
177
|
+
members = [("ptr", types.voidptr)]
|
|
178
|
+
|
|
179
|
+
if fe_type.dynamic_strides_size > 0:
|
|
180
|
+
array_type = LLVMArray(types.int64, fe_type.dynamic_strides_size)
|
|
181
|
+
members += [("strides", array_type)]
|
|
182
|
+
|
|
183
|
+
if fe_type.dynamic_shape_size > 0:
|
|
184
|
+
array_type = LLVMArray(types.int64, fe_type.dynamic_shape_size)
|
|
185
|
+
members += [("shape", array_type)]
|
|
186
|
+
|
|
187
|
+
models.StructModel.__init__(self, dmm, fe_type, members)
|
|
188
|
+
|
|
189
|
+
def get_value_type(self):
|
|
190
|
+
if self._value_type is None:
|
|
191
|
+
name = f"struct.libmathdx_tensor_{self._fe_type.dynamic_strides_size}s_{self._fe_type.dynamic_shape_size}s"
|
|
192
|
+
t = llvmir.global_context.get_identified_type(name)
|
|
193
|
+
if t.is_opaque:
|
|
194
|
+
t.set_body(*[m.get_value_type() for m in self._models])
|
|
195
|
+
self._value_type = t
|
|
196
|
+
return self._value_type
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
class MathdxPipelineType(types.Type):
|
|
200
|
+
def __init__(self):
|
|
201
|
+
super().__init__("MathdxPipeline()")
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
@register_model(MathdxPipelineType)
|
|
205
|
+
class MathdxPipelineModel(models.StructModel):
|
|
206
|
+
def __init__(self, dmm, fe_type: MathdxPipelineType):
|
|
207
|
+
members = [("ptr", types.voidptr)]
|
|
208
|
+
models.StructModel.__init__(self, dmm, fe_type, members)
|
|
209
|
+
|
|
210
|
+
def get_value_type(self):
|
|
211
|
+
if self._value_type is None:
|
|
212
|
+
name = "struct.libmathdx_pipeline"
|
|
213
|
+
t = llvmir.global_context.get_identified_type(name)
|
|
214
|
+
if t.is_opaque:
|
|
215
|
+
t.set_body(*[m.get_value_type() for m in self._models])
|
|
216
|
+
self._value_type = t
|
|
217
|
+
return self._value_type
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
@intrinsic
|
|
221
|
+
def cast_to_void_pointer(typingctx: typing.Context, ptr_ty):
|
|
222
|
+
if not isinstance(ptr_ty, types.CPointer):
|
|
223
|
+
raise TypingError("cast_to_void_pointer expects a CPointer type")
|
|
224
|
+
i8_ptr_ty = types.CPointer(types.uint8)
|
|
225
|
+
sig = i8_ptr_ty(ptr_ty)
|
|
226
|
+
|
|
227
|
+
def codegen(context: BaseContext, builder, sig, args):
|
|
228
|
+
return builder.bitcast(args[0], context.get_value_type(i8_ptr_ty))
|
|
229
|
+
|
|
230
|
+
return sig, codegen
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
_cabi_device_registry: dict[str | tuple[str, typing.Signature], Callable] = {}
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def declare_cabi_device(symbol: str, sig: typing.Signature, link=None):
|
|
237
|
+
"""declare_cabi_device is an analog of cuda.declare_device but uses C ABI
|
|
238
|
+
calling convention instead of Numba ABI calling convention. It means that
|
|
239
|
+
the first argument is not a return value pointer."""
|
|
240
|
+
key: str | tuple[str, typing.Signature] = symbol
|
|
241
|
+
if mathdx.get_version_ex() < (0, 3, 0):
|
|
242
|
+
key = (symbol, sig)
|
|
243
|
+
device_func = _cabi_device_registry.get(key)
|
|
244
|
+
if device_func is None:
|
|
245
|
+
device_func = _declare_cabi_device(symbol, sig, link)
|
|
246
|
+
_cabi_device_registry[key] = device_func
|
|
247
|
+
|
|
248
|
+
return device_func
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def _declare_cabi_device(symbol: str, sig: typing.Signature, link=None):
|
|
252
|
+
intrinsic_sig = sig.return_type(types.Tuple(sig.args))
|
|
253
|
+
|
|
254
|
+
@intrinsic
|
|
255
|
+
def call_device(typingctx: typing.Context, args):
|
|
256
|
+
def codegen(context: BaseContext, builder, sig: typing.Signature, args):
|
|
257
|
+
if link is not None:
|
|
258
|
+
context.active_code_library.add_linking_file(link)
|
|
259
|
+
|
|
260
|
+
args = cgutils.unpack_tuple(builder, args[0])
|
|
261
|
+
argTypes = sig.args[0]
|
|
262
|
+
|
|
263
|
+
assert len(args) == len(argTypes)
|
|
264
|
+
|
|
265
|
+
# CUDA target maps types.void to i8*, but we need void for abi correctness.
|
|
266
|
+
if sig.return_type == types.void:
|
|
267
|
+
retTy = ir.VoidType()
|
|
268
|
+
else:
|
|
269
|
+
retTy = context.get_value_type(sig.return_type)
|
|
270
|
+
fnTy = ir.FunctionType(retTy, [context.get_value_type(argTy) for argTy in argTypes])
|
|
271
|
+
fn = cgutils.get_or_insert_function(builder.module, fnTy, symbol)
|
|
272
|
+
builder.call(fn, args)
|
|
273
|
+
|
|
274
|
+
return intrinsic_sig, codegen
|
|
275
|
+
|
|
276
|
+
def device_func():
|
|
277
|
+
pass
|
|
278
|
+
|
|
279
|
+
@overload(device_func, jit_options={"forceinline": True})
|
|
280
|
+
def ol_device_func(*args):
|
|
281
|
+
if len(args) != len(sig.args):
|
|
282
|
+
raise RuntimeError(
|
|
283
|
+
f"Invalid number of arguments for device function {symbol}: expected {len(sig.args)}, got {len(args)}"
|
|
284
|
+
)
|
|
285
|
+
for expected_t, provided_t in zip(sig.args, args, strict=True):
|
|
286
|
+
if expected_t == provided_t:
|
|
287
|
+
continue
|
|
288
|
+
raise RuntimeError(f"Invalid argument type for device function {symbol}: expected {expected_t}, got {provided_t}")
|
|
289
|
+
return lambda *args: call_device(tuple(args))
|
|
290
|
+
|
|
291
|
+
return device_func
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def register_dummy_numba_type(numba_type, base_type, name, attributes):
|
|
295
|
+
"""Register and lower a dummy Numba type that does not take space in memory.
|
|
296
|
+
Intended for types that are present only at typing stage and not represented in memory,
|
|
297
|
+
but are allowed to be accessed inside kernel."""
|
|
298
|
+
for attribute in attributes:
|
|
299
|
+
overload_type_attribute(numba_type, name, attribute)
|
|
300
|
+
|
|
301
|
+
@typeof_impl.register(base_type)
|
|
302
|
+
def typeof_numba(val, context):
|
|
303
|
+
return numba_type(val)
|
|
304
|
+
|
|
305
|
+
register_model(numba_type)(EmptyStructModel)
|
|
306
|
+
|
|
307
|
+
@lower_constant(numba_type)
|
|
308
|
+
def constant_dummy(context, builder, typ, pyval):
|
|
309
|
+
struct_ptr = cgutils.create_struct_proxy(typ)(context, builder)
|
|
310
|
+
return struct_ptr._getvalue()
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from functools import cached_property
|
|
6
|
+
|
|
7
|
+
import numpy
|
|
8
|
+
from llvmlite import ir as llir
|
|
9
|
+
from numba.core import cgutils
|
|
10
|
+
from numba.core.base import BaseContext
|
|
11
|
+
from numba.cuda.extending import lower_builtin, make_attribute_wrapper, type_callable
|
|
12
|
+
from numba.cuda.models import register_model
|
|
13
|
+
from numba.extending import models, types
|
|
14
|
+
|
|
15
|
+
from nvmath.device.common import Layout, OpaqueTensor
|
|
16
|
+
from nvmath.device.common_numba import NUMBA_FE_TYPES_TO_NUMBA_IR, overload_type_attribute
|
|
17
|
+
from nvmath.device.llvm_array import LLVMArray
|
|
18
|
+
|
|
19
|
+
_LIBMATHDX_RUNTIME = -9223372036854775808
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class OpaqueLayout(Layout):
|
|
23
|
+
"""
|
|
24
|
+
A generic tensor layout that can represent arbitrary shapes and strides.
|
|
25
|
+
It is the same as libmathdx opaque tensor, but without the pointer
|
|
26
|
+
to data.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
_dtype: numpy.number
|
|
30
|
+
_shape: tuple[int, ...]
|
|
31
|
+
_strides: tuple[int, ...]
|
|
32
|
+
|
|
33
|
+
def __init__(self, shape: tuple[int, ...], strides: tuple[int, ...], dtype: numpy.number):
|
|
34
|
+
assert len(shape) == len(strides)
|
|
35
|
+
self._shape = shape
|
|
36
|
+
self._strides = strides
|
|
37
|
+
self._dtype = dtype
|
|
38
|
+
|
|
39
|
+
@cached_property
|
|
40
|
+
def dynamic_strides_size(self) -> int:
|
|
41
|
+
return self._strides.count(_LIBMATHDX_RUNTIME)
|
|
42
|
+
|
|
43
|
+
@cached_property
|
|
44
|
+
def dynamic_shape_size(self) -> int:
|
|
45
|
+
return self._shape.count(_LIBMATHDX_RUNTIME)
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def dtype(self) -> numpy.number:
|
|
49
|
+
return self._dtype
|
|
50
|
+
|
|
51
|
+
@cached_property
|
|
52
|
+
def ndim(self) -> int:
|
|
53
|
+
return len(self._shape)
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def shape(self) -> tuple[int, ...]:
|
|
57
|
+
return self._shape
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def strides(self) -> tuple[int, ...]:
|
|
61
|
+
return self._strides
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class LayoutType(types.Type):
|
|
65
|
+
"""
|
|
66
|
+
Type class associated with opaque tensor layouts.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
def __init__(
|
|
70
|
+
self,
|
|
71
|
+
layout: OpaqueLayout,
|
|
72
|
+
):
|
|
73
|
+
self._layout = layout
|
|
74
|
+
super().__init__(
|
|
75
|
+
f"Layout(dynamic_shape_size={layout.dynamic_shape_size}, dynamic_strides_size={layout.dynamic_strides_size})"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def layout(self) -> OpaqueLayout:
|
|
80
|
+
return self._layout
|
|
81
|
+
|
|
82
|
+
@cached_property
|
|
83
|
+
def dtype(self) -> types.Number:
|
|
84
|
+
return NUMBA_FE_TYPES_TO_NUMBA_IR[self._layout.dtype]
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@register_model(LayoutType)
|
|
88
|
+
class LayoutModel(models.StructModel):
|
|
89
|
+
def __init__(self, dmm, fe_type: LayoutType):
|
|
90
|
+
members = []
|
|
91
|
+
|
|
92
|
+
strides_size = fe_type.layout.dynamic_strides_size
|
|
93
|
+
if strides_size > 0:
|
|
94
|
+
array_type = LLVMArray(types.int64, strides_size)
|
|
95
|
+
members += [("strides", array_type)]
|
|
96
|
+
|
|
97
|
+
shape_size = fe_type.layout.dynamic_shape_size
|
|
98
|
+
if shape_size > 0:
|
|
99
|
+
array_type = LLVMArray(types.int64, shape_size)
|
|
100
|
+
members += [("shape", array_type)]
|
|
101
|
+
|
|
102
|
+
models.StructModel.__init__(self, dmm, fe_type, members)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
make_attribute_wrapper(LayoutType, "strides", "strides")
|
|
106
|
+
make_attribute_wrapper(LayoutType, "shape", "shape")
|
|
107
|
+
|
|
108
|
+
for attribute in ("uid", "alignment", "storage_bytes"):
|
|
109
|
+
overload_type_attribute(LayoutType, "", attribute)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class OpaqueTensorType(types.Type):
|
|
113
|
+
def __init__(self, layout: LayoutType):
|
|
114
|
+
super().__init__(f"OpaqueTensor(layout={layout})")
|
|
115
|
+
self._layout = layout
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def uid(self):
|
|
119
|
+
return self._layout.layout.uid
|
|
120
|
+
|
|
121
|
+
@property
|
|
122
|
+
def layout(self) -> LayoutType:
|
|
123
|
+
return self._layout
|
|
124
|
+
|
|
125
|
+
@cached_property
|
|
126
|
+
def ndim(self):
|
|
127
|
+
return 2
|
|
128
|
+
|
|
129
|
+
@cached_property
|
|
130
|
+
def dtype(self):
|
|
131
|
+
return self._layout.dtype
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class OpaqueTensorModel(models.StructModel):
|
|
135
|
+
def __init__(self, dmm, fe_type: OpaqueTensorType):
|
|
136
|
+
members = [
|
|
137
|
+
("ptr", types.voidptr),
|
|
138
|
+
]
|
|
139
|
+
layout = fe_type.layout.layout
|
|
140
|
+
|
|
141
|
+
strides_size = layout.dynamic_strides_size
|
|
142
|
+
if strides_size > 0:
|
|
143
|
+
array_type = LLVMArray(types.int64, strides_size)
|
|
144
|
+
members += [("strides", array_type)]
|
|
145
|
+
|
|
146
|
+
shape_size = layout.dynamic_shape_size
|
|
147
|
+
if shape_size > 0:
|
|
148
|
+
array_type = LLVMArray(types.int64, shape_size)
|
|
149
|
+
members += [("shape", array_type)]
|
|
150
|
+
|
|
151
|
+
models.StructModel.__init__(self, dmm, fe_type, members)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
register_model(OpaqueTensorType)(OpaqueTensorModel)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@type_callable(OpaqueTensor)
|
|
158
|
+
def type_callable_OpaqueTensor(context):
|
|
159
|
+
def typer(buffer_ty, layout_ty):
|
|
160
|
+
if not isinstance(buffer_ty, types.Array):
|
|
161
|
+
return
|
|
162
|
+
if not isinstance(layout_ty, LayoutType):
|
|
163
|
+
return
|
|
164
|
+
assert buffer_ty.dtype == layout_ty.dtype
|
|
165
|
+
return OpaqueTensorType(layout_ty)
|
|
166
|
+
|
|
167
|
+
return typer
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
@lower_builtin(OpaqueTensor, types.Array, LayoutType)
|
|
171
|
+
def impl_opaque_tensor(context: BaseContext, builder: llir.IRBuilder, sig, args):
|
|
172
|
+
tensor_ty: OpaqueTensorType = sig.return_type
|
|
173
|
+
buffer, buffer_ty = args[0], sig.args[0]
|
|
174
|
+
layout, layout_ty = args[1], sig.args[1]
|
|
175
|
+
|
|
176
|
+
ptr = cgutils.create_struct_proxy(buffer_ty)(context, builder, buffer).data
|
|
177
|
+
# Future release of numba-cuda may have support for address spaces.
|
|
178
|
+
# It is not supported to pass a non generic pointer to device function
|
|
179
|
+
# call.
|
|
180
|
+
if ptr.type.addrspace != 0:
|
|
181
|
+
ptr = builder.addrspacecast(ptr, llir.PointerType(ptr.type.pointee), "generic")
|
|
182
|
+
|
|
183
|
+
voidPtrTy = llir.PointerType(llir.IntType(8))
|
|
184
|
+
ptr = builder.bitcast(ptr, voidPtrTy)
|
|
185
|
+
|
|
186
|
+
opaque_tensor = cgutils.create_struct_proxy(tensor_ty)(context, builder)
|
|
187
|
+
opaque_tensor.ptr = ptr
|
|
188
|
+
|
|
189
|
+
layout_struct = cgutils.create_struct_proxy(layout_ty)(context, builder, layout)
|
|
190
|
+
|
|
191
|
+
if tensor_ty.layout.layout.dynamic_shape_size > 0:
|
|
192
|
+
opaque_tensor.shape = layout_struct.shape
|
|
193
|
+
|
|
194
|
+
if tensor_ty.layout.layout.dynamic_strides_size > 0:
|
|
195
|
+
opaque_tensor.strides = layout_struct.strides
|
|
196
|
+
|
|
197
|
+
return opaque_tensor._getvalue()
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
make_attribute_wrapper(OpaqueTensorType, "ptr", "ptr")
|
|
201
|
+
overload_type_attribute(OpaqueTensorType, "layout", "layout")
|