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