Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- lib/python3.12/site-packages/deep_gemm/__init__.py +13 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/axpby.hpp +95 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/clear.hpp +64 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/cooperative_copy.hpp +339 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/cooperative_gemm.hpp +553 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/copy.hpp +527 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/fill.hpp +87 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/functional.hpp +290 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/gemm.hpp +500 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/prefer.hpp +46 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/prefetch.hpp +145 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/tensor_algorithms.hpp +166 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/tuple_algorithms.hpp +1073 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/cluster_sm100.hpp +108 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/cluster_sm90.hpp +245 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/config.hpp +111 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/copy.hpp +107 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/copy_sm100.hpp +0 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/copy_sm100_tma.hpp +664 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/copy_sm50.hpp +98 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/copy_sm75.hpp +236 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/copy_sm80.hpp +198 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/copy_sm90.hpp +219 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/copy_sm90_desc.hpp +475 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/copy_sm90_tma.hpp +1496 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma.hpp +64 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm100.hpp +42 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm100_desc.hpp +651 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm100_umma.hpp +1616 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm120.hpp +0 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm120_sparse.hpp +0 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm61.hpp +87 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm70.hpp +329 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm75.hpp +120 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm80.hpp +2241 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm89.hpp +180 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm90.hpp +0 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm90_desc.hpp +151 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm90_gmma.hpp +0 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm90_gmma_ext.hpp +0 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm90_gmma_sparse.hpp +0 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm90_gmma_sparse_ext.hpp +0 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/simd_sm100.hpp +96 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/tmem_allocator_sm100.hpp +168 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/arch/util.hpp +320 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/atom/copy_atom.hpp +765 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/atom/copy_traits.hpp +162 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/atom/copy_traits_sm100.hpp +0 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/atom/copy_traits_sm100_im2col.hpp +488 -0
- lib/python3.12/site-packages/deep_gemm/include/cute/atom/copy_traits_sm100_tma.hpp +487 -0
lib/python3.12/site-packages/deep_gemm/__init__.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
|
| 3 |
+
from . import jit
|
| 4 |
+
from .jit_kernels import (
|
| 5 |
+
gemm_fp8_fp8_bf16_nt,
|
| 6 |
+
m_grouped_gemm_fp8_fp8_bf16_nt_contiguous,
|
| 7 |
+
m_grouped_gemm_fp8_fp8_bf16_nt_masked,
|
| 8 |
+
ceil_div,
|
| 9 |
+
set_num_sms, get_num_sms,
|
| 10 |
+
get_col_major_tma_aligned_tensor,
|
| 11 |
+
get_m_alignment_for_contiguous_layout
|
| 12 |
+
)
|
| 13 |
+
from .utils import bench, bench_kineto, calc_diff
|
lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/axpby.hpp
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/config.hpp>
|
| 34 |
+
|
| 35 |
+
#include <cute/tensor_impl.hpp>
|
| 36 |
+
#include <cute/tensor_predicate.hpp>
|
| 37 |
+
|
| 38 |
+
namespace cute
|
| 39 |
+
{
|
| 40 |
+
|
| 41 |
+
//
|
| 42 |
+
// Accept mutable temporaries
|
| 43 |
+
//
|
| 44 |
+
template <class Alpha,
|
| 45 |
+
class XEngine, class XLayout,
|
| 46 |
+
class Beta,
|
| 47 |
+
class YEngine, class YLayout,
|
| 48 |
+
class PrdTensor = TrivialPredTensor>
|
| 49 |
+
CUTE_HOST_DEVICE
|
| 50 |
+
void
|
| 51 |
+
axpby(Alpha const& alpha,
|
| 52 |
+
Tensor<XEngine, XLayout> const& x,
|
| 53 |
+
Beta const& beta,
|
| 54 |
+
Tensor<YEngine, YLayout> && y,
|
| 55 |
+
PrdTensor const& p = {})
|
| 56 |
+
{
|
| 57 |
+
return axpby(alpha, x, beta, y, p);
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
//
|
| 61 |
+
// AXPBY
|
| 62 |
+
//
|
| 63 |
+
template <class Alpha,
|
| 64 |
+
class XEngine, class XLayout,
|
| 65 |
+
class Beta,
|
| 66 |
+
class YEngine, class YLayout,
|
| 67 |
+
class PrdTensor = TrivialPredTensor>
|
| 68 |
+
CUTE_HOST_DEVICE
|
| 69 |
+
void
|
| 70 |
+
axpby(Alpha const& alpha,
|
| 71 |
+
Tensor<XEngine, XLayout> const& x,
|
| 72 |
+
Beta const& beta,
|
| 73 |
+
Tensor<YEngine, YLayout> & y,
|
| 74 |
+
PrdTensor const& p = {})
|
| 75 |
+
{
|
| 76 |
+
auto isBetaZero = [&] () {
|
| 77 |
+
if constexpr (is_complex<Beta>::value) {
|
| 78 |
+
return beta.real() == Int<0>{} && beta.imag() == Int<0>{};
|
| 79 |
+
}
|
| 80 |
+
else {
|
| 81 |
+
return beta == Int<0>{};
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
CUTE_GCC_UNREACHABLE;
|
| 85 |
+
} ();
|
| 86 |
+
|
| 87 |
+
CUTE_UNROLL
|
| 88 |
+
for (int i = 0; i < size(x); ++i) {
|
| 89 |
+
if (p(i)) {
|
| 90 |
+
y(i) = (isBetaZero ? alpha * x(i) : alpha * x(i) + beta * y(i));
|
| 91 |
+
}
|
| 92 |
+
}
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/clear.hpp
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/config.hpp> // CUTE_HOST_DEVICE
|
| 34 |
+
#include <cute/tensor_impl.hpp> // cute::Tensor
|
| 35 |
+
#include <cute/algorithm/fill.hpp> // cute::fill
|
| 36 |
+
|
| 37 |
+
namespace cute
|
| 38 |
+
{
|
| 39 |
+
|
| 40 |
+
//
|
| 41 |
+
// Accept mutable temporaries
|
| 42 |
+
//
|
| 43 |
+
template <class Engine, class Layout>
|
| 44 |
+
CUTE_HOST_DEVICE
|
| 45 |
+
void
|
| 46 |
+
clear(Tensor<Engine, Layout>&& tensor)
|
| 47 |
+
{
|
| 48 |
+
return clear(tensor);
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
//
|
| 52 |
+
// Set elements to zero
|
| 53 |
+
//
|
| 54 |
+
template <class Engine, class Layout>
|
| 55 |
+
CUTE_HOST_DEVICE
|
| 56 |
+
void
|
| 57 |
+
clear(Tensor<Engine, Layout>& tensor)
|
| 58 |
+
{
|
| 59 |
+
using T = typename Tensor<Engine,Layout>::value_type;
|
| 60 |
+
|
| 61 |
+
fill(tensor, T{});
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/cooperative_copy.hpp
ADDED
|
@@ -0,0 +1,339 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2017 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/config.hpp>
|
| 34 |
+
#include <cute/layout.hpp>
|
| 35 |
+
#include <cute/layout_composed.hpp> // cute::logical_divide
|
| 36 |
+
#include <cute/swizzle.hpp> // cute::Swizzle
|
| 37 |
+
#include <cute/swizzle_layout.hpp> // cute::get_nonswizzle_portion
|
| 38 |
+
#include <cute/tensor_impl.hpp> // cute::Tensor
|
| 39 |
+
#include <cute/tensor_predicate.hpp>
|
| 40 |
+
#include <cute/algorithm/copy.hpp>
|
| 41 |
+
#include <cute/atom/copy_atom.hpp>
|
| 42 |
+
|
| 43 |
+
namespace cute
|
| 44 |
+
{
|
| 45 |
+
|
| 46 |
+
template <uint32_t NumThreads,
|
| 47 |
+
class SrcEngine, class SrcLayout,
|
| 48 |
+
class DstEngine, class DstLayout>
|
| 49 |
+
CUTE_HOST_DEVICE void
|
| 50 |
+
naive_cooperative_copy(uint32_t const& tid,
|
| 51 |
+
Tensor<SrcEngine, SrcLayout> const& src,
|
| 52 |
+
Tensor<DstEngine, DstLayout> & dst)
|
| 53 |
+
{
|
| 54 |
+
auto N = size(dst);
|
| 55 |
+
auto R = N % Int<NumThreads>{};
|
| 56 |
+
if (R > 0 && tid < R) { // Likely static condition && Residue in-bounds
|
| 57 |
+
dst[tid] = src[tid];
|
| 58 |
+
}
|
| 59 |
+
CUTE_UNROLL
|
| 60 |
+
for (uint32_t i = uint32_t(R); i < uint32_t(N); i += NumThreads) { // All in-bounds
|
| 61 |
+
dst[tid + i] = src[tid + i];
|
| 62 |
+
}
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
// Accept mutable temporaries
|
| 66 |
+
template <uint32_t NumThreads,
|
| 67 |
+
class SrcEngine, class SrcLayout,
|
| 68 |
+
class DstEngine, class DstLayout>
|
| 69 |
+
CUTE_HOST_DEVICE void
|
| 70 |
+
naive_cooperative_copy(uint32_t const& tid,
|
| 71 |
+
Tensor<SrcEngine, SrcLayout> const& src,
|
| 72 |
+
Tensor<DstEngine, DstLayout> && dst)
|
| 73 |
+
{
|
| 74 |
+
return naive_cooperative_copy(tid, src, dst);
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
// A heuristic to determine a "good" permutation of two tensors for later vectorization and thr-assignment
|
| 78 |
+
template <class AEngine, class ALayout,
|
| 79 |
+
class BEngine, class BLayout>
|
| 80 |
+
CUTE_HOST_DEVICE constexpr
|
| 81 |
+
auto
|
| 82 |
+
heuristic_permutation(Tensor<AEngine, ALayout> const& a,
|
| 83 |
+
Tensor<BEngine, BLayout> const& b)
|
| 84 |
+
{
|
| 85 |
+
constexpr bool swizzleA = get_swizzle_t<AEngine>::num_bits != 0 or
|
| 86 |
+
get_swizzle_t<ALayout>::num_bits != 0;
|
| 87 |
+
constexpr bool swizzleB = get_swizzle_t<BEngine>::num_bits != 0 or
|
| 88 |
+
get_swizzle_t<BLayout>::num_bits != 0;
|
| 89 |
+
auto a_inv = right_inverse(get_nonswizzle_portion(a.layout()));
|
| 90 |
+
auto b_inv = right_inverse(get_nonswizzle_portion(b.layout()));
|
| 91 |
+
|
| 92 |
+
constexpr uint8_t scoreA = (uint8_t(swizzleA) << 2) |
|
| 93 |
+
(uint8_t(is_smem<AEngine>::value) << 1) |
|
| 94 |
+
(uint8_t(size(a_inv) > size(b_inv)) << 0);
|
| 95 |
+
|
| 96 |
+
constexpr uint8_t scoreB = (uint8_t(swizzleB) << 2) |
|
| 97 |
+
(uint8_t(is_smem<BEngine>::value) << 1) |
|
| 98 |
+
(uint8_t(size(b_inv) > size(a_inv)) << 0);
|
| 99 |
+
|
| 100 |
+
if constexpr (scoreA >= scoreB) {
|
| 101 |
+
return a_inv;
|
| 102 |
+
} else {
|
| 103 |
+
return b_inv;
|
| 104 |
+
}
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
// cooperative_copy<NumThreads, MaxVecBits>(thr_idx, src, dst)
|
| 108 |
+
// Use NumThreads to copy Tensor src to Tensor dst with element-wise vectorization up to MaxVecBits.
|
| 109 |
+
// @pre 0 <= @a tid < NumThreads
|
| 110 |
+
// @pre Tensors @a src and @a dst are aligned up to MaxVecBits.
|
| 111 |
+
// That is, pointers and dynamic strides are assumed to be aligned up to MaxVecBits.
|
| 112 |
+
//
|
| 113 |
+
template <uint32_t NumThreads, uint32_t MaxVecBits,
|
| 114 |
+
class SrcEngine, class SrcLayout,
|
| 115 |
+
class DstEngine, class DstLayout,
|
| 116 |
+
class CopyPolicy = DefaultCopy>
|
| 117 |
+
CUTE_HOST_DEVICE
|
| 118 |
+
void
|
| 119 |
+
cooperative_copy(uint32_t const& tid,
|
| 120 |
+
Tensor<SrcEngine, SrcLayout> const& src,
|
| 121 |
+
Tensor<DstEngine, DstLayout> & dst,
|
| 122 |
+
CopyPolicy const& cpy = {})
|
| 123 |
+
{
|
| 124 |
+
// Assumes the shapes are static, can generalize/fallback
|
| 125 |
+
CUTE_STATIC_ASSERT_V(is_static<decltype(shape(src))>{} && is_static<decltype(shape(dst))>{});
|
| 126 |
+
CUTE_STATIC_ASSERT_V(size(src) == size(dst));
|
| 127 |
+
// Assumes the types are the same, can generalize/fallback
|
| 128 |
+
static_assert(cute::is_same<typename SrcEngine::value_type, typename DstEngine::value_type>::value);
|
| 129 |
+
static_assert(MaxVecBits == sizeof_bits_v<typename SrcEngine::value_type> ||
|
| 130 |
+
MaxVecBits == 8 || MaxVecBits == 16 || MaxVecBits == 32 || MaxVecBits == 64 || MaxVecBits == 128,
|
| 131 |
+
"Expected MaxVecBits to be value size or 8 or 16 or 32 or 64 or 128 for alignment and performance.");
|
| 132 |
+
// Check that the tensors are likely shared across threads: either gmem or smem
|
| 133 |
+
static_assert((is_gmem<SrcEngine>::value || is_smem<SrcEngine>::value),
|
| 134 |
+
"cooperative_copy expects shared gmem or smem source tensor.");
|
| 135 |
+
static_assert((is_gmem<DstEngine>::value || is_smem<DstEngine>::value),
|
| 136 |
+
"cooperative_copy expects shared gmem or smem destination tensor.");
|
| 137 |
+
// Precondition on tid in DEBUG
|
| 138 |
+
assert(tid < NumThreads);
|
| 139 |
+
// Precondition on pointer alignment in DEBUG
|
| 140 |
+
assert(is_byte_aligned<ceil_div(MaxVecBits,8u)>(raw_pointer_cast(src.data())));
|
| 141 |
+
assert(is_byte_aligned<ceil_div(MaxVecBits,8u)>(raw_pointer_cast(dst.data())));
|
| 142 |
+
|
| 143 |
+
#if 0
|
| 144 |
+
if (thread0()) {
|
| 145 |
+
print(" "); print("cooperative_copy\n");
|
| 146 |
+
print(" "); print("NumThreads: "); print(NumThreads); print("\n");
|
| 147 |
+
print(" "); print("MaxVecBits: "); print(MaxVecBits); print("\n");
|
| 148 |
+
print(" "); print("src: "); print(src); print("\n");
|
| 149 |
+
print(" "); print("dst: "); print(dst); print("\n");
|
| 150 |
+
}
|
| 151 |
+
#ifdef __CUDA_ARCH__
|
| 152 |
+
__syncthreads();
|
| 153 |
+
#endif
|
| 154 |
+
#endif
|
| 155 |
+
|
| 156 |
+
// The common layout of the two tensors that can be vectorized over elements and threads
|
| 157 |
+
// vidx -> coord
|
| 158 |
+
auto common_layout = heuristic_permutation(src, dst);
|
| 159 |
+
|
| 160 |
+
// Apply
|
| 161 |
+
// (V, rest)
|
| 162 |
+
Tensor src_a = coalesce(logical_divide(src, common_layout), Shape<_1,_1>{});
|
| 163 |
+
Tensor dst_a = coalesce(logical_divide(dst, common_layout), Shape<_1,_1>{});
|
| 164 |
+
|
| 165 |
+
//
|
| 166 |
+
// Determine vectorization of elems and thrs based on src/dst size and number of threads
|
| 167 |
+
// NOTE: This heuristic promotes parallelization over vectorization
|
| 168 |
+
//
|
| 169 |
+
|
| 170 |
+
// The number of elements and number of bits
|
| 171 |
+
constexpr int elem_bits = sizeof_bits_v<typename SrcEngine::value_type>;
|
| 172 |
+
constexpr int total_elem = size(SrcLayout{});
|
| 173 |
+
|
| 174 |
+
// The number of elements that can be vectorized in values
|
| 175 |
+
constexpr int common_elem = decltype(max_common_vector(src_a, dst_a))::value;
|
| 176 |
+
|
| 177 |
+
#if 0
|
| 178 |
+
if (thread0()) {
|
| 179 |
+
print(" "); print("common_layout: "); print(common_layout); print("\n");
|
| 180 |
+
print(" "); print("src_a: "); print(src_a); print("\n");
|
| 181 |
+
print(" "); print("dst_a: "); print(dst_a); print("\n");
|
| 182 |
+
}
|
| 183 |
+
#ifdef __CUDA_ARCH__
|
| 184 |
+
__syncthreads();
|
| 185 |
+
#endif
|
| 186 |
+
#endif
|
| 187 |
+
|
| 188 |
+
//
|
| 189 |
+
if constexpr (total_elem % NumThreads != 0) {
|
| 190 |
+
// Not attempting to find a partitioning pattern, fallback to dynamically indexed slowpath
|
| 191 |
+
|
| 192 |
+
if constexpr (common_elem > 1 && MaxVecBits > elem_bits) {
|
| 193 |
+
// If the vectorization is non-trivial and divides the maximum vectorizations, then vectorize
|
| 194 |
+
constexpr auto max_align_src = elem_bits * decltype(max_alignment(src_a.layout()))::value;
|
| 195 |
+
constexpr auto max_align_dst = elem_bits * decltype(max_alignment(dst_a.layout()))::value;
|
| 196 |
+
constexpr auto vec_bits = gcd(max_align_src, max_align_dst, MaxVecBits);
|
| 197 |
+
using VecType = uint_bit_t<vec_bits>;
|
| 198 |
+
|
| 199 |
+
static_assert(vec_bits % elem_bits == 0, "Expected divisibility");
|
| 200 |
+
static_assert((vec_bits >= 8), "No support for subbyte copying");
|
| 201 |
+
|
| 202 |
+
Tensor src_v = recast<VecType const>(src_a);
|
| 203 |
+
Tensor dst_v = recast<VecType >(dst_a);
|
| 204 |
+
|
| 205 |
+
#if 0
|
| 206 |
+
if (thread0()) {
|
| 207 |
+
print(" "); print("cooperative_copy -- naive\n");
|
| 208 |
+
print(" "); print("src_v: "); print(src_v); print("\n");
|
| 209 |
+
print(" "); print("dst_v: "); print(dst_v); print("\n");
|
| 210 |
+
}
|
| 211 |
+
#ifdef __CUDA_ARCH__
|
| 212 |
+
__syncthreads();
|
| 213 |
+
#endif
|
| 214 |
+
#endif
|
| 215 |
+
|
| 216 |
+
naive_cooperative_copy<NumThreads>(tid, src_v, dst_v);
|
| 217 |
+
} else {
|
| 218 |
+
naive_cooperative_copy<NumThreads>(tid, src_a, dst_a);
|
| 219 |
+
}
|
| 220 |
+
} else {
|
| 221 |
+
// If the tensors can be equally partitioned by the threads,
|
| 222 |
+
// compute vectorization widths in elements and threads.
|
| 223 |
+
|
| 224 |
+
// If there are too many threads to allow a full vectorized copy, trunc the vectorization
|
| 225 |
+
constexpr int total_bits = total_elem * elem_bits;
|
| 226 |
+
constexpr int max_bits_per_thr = total_bits / NumThreads;
|
| 227 |
+
// At least elem_bits, at most common_bits
|
| 228 |
+
constexpr int common_bits = common_elem * elem_bits;
|
| 229 |
+
constexpr int vec_bits = cute::max(elem_bits, cute::gcd(common_bits, int(MaxVecBits), max_bits_per_thr));
|
| 230 |
+
|
| 231 |
+
// Should account for vec_bits < 8 and/or vec_elem <= 1
|
| 232 |
+
// And also account for subbyte types, which could cause race conditions
|
| 233 |
+
// Want to ENFORCE sufficient vectorization in those cases
|
| 234 |
+
static_assert(vec_bits % elem_bits == 0, "Expected divisibility");
|
| 235 |
+
static_assert(vec_bits >= 8, "No support for subbyte copying");
|
| 236 |
+
|
| 237 |
+
using VecType = uint_bit_t<vec_bits>;
|
| 238 |
+
constexpr int vec_elem = vec_bits / elem_bits;
|
| 239 |
+
|
| 240 |
+
constexpr int vec_thrs = cute::min(int(NumThreads), total_elem / vec_elem);
|
| 241 |
+
|
| 242 |
+
//
|
| 243 |
+
// Determine the partitioning patterns for the vec_elems and vec_thrs
|
| 244 |
+
//
|
| 245 |
+
|
| 246 |
+
// Distribute the rest of the V*T to some consistent portion outside of the common_layout, if needed
|
| 247 |
+
auto common_domain_src = domain_distribute(shape(src_a), Int<vec_elem*vec_thrs>{});
|
| 248 |
+
auto common_domain_dst = domain_distribute(shape(dst_a), Int<vec_elem*vec_thrs>{});
|
| 249 |
+
|
| 250 |
+
// Make sure for now, could fall back here instead
|
| 251 |
+
CUTE_STATIC_ASSERT_V(size(common_domain_src) == Int<vec_elem*vec_thrs>{});
|
| 252 |
+
CUTE_STATIC_ASSERT_V(compatible(common_domain_src, common_domain_dst) ||
|
| 253 |
+
compatible(common_domain_dst, common_domain_src));
|
| 254 |
+
// Use the "more specific" domain for the extra elements of V*T
|
| 255 |
+
auto common_domain = conditional_return(compatible(common_domain_src, common_domain_dst),
|
| 256 |
+
common_domain_dst, common_domain_src);
|
| 257 |
+
|
| 258 |
+
// Construct the tiler
|
| 259 |
+
auto tiler_vt = common_domain.with_shape(Int<vec_elem>{}, Int<vec_thrs>{});
|
| 260 |
+
|
| 261 |
+
// Apply and slice
|
| 262 |
+
Tensor src_v = logical_divide(src_a, tiler_vt)(make_coord(_,tid),_);
|
| 263 |
+
Tensor dst_v = logical_divide(dst_a, tiler_vt)(make_coord(_,tid),_);
|
| 264 |
+
|
| 265 |
+
#if 0
|
| 266 |
+
if (thread0()) {
|
| 267 |
+
print(" "); print("cooperative_copy -- vec\n");
|
| 268 |
+
print(" "); print("Used vector: "); print(vec_elem); print("\n");
|
| 269 |
+
print(" "); print("Used threads: "); print(vec_thrs); print("\n");
|
| 270 |
+
print(" "); print("tiler_vt: "); print(tiler_vt); print("\n");
|
| 271 |
+
print(" "); print("src_v: "); print(src_v); print("\n");
|
| 272 |
+
print(" "); print("dst_v: "); print(dst_v); print("\n");
|
| 273 |
+
print(" "); print("recast<VecType const>(src_v): "); print(recast<VecType const>(src_v)); print("\n");
|
| 274 |
+
print(" "); print("recast<VecType >(dst_v): "); print(recast<VecType >(dst_v)); print("\n");
|
| 275 |
+
}
|
| 276 |
+
#ifdef __CUDA_ARCH__
|
| 277 |
+
__syncthreads();
|
| 278 |
+
#endif
|
| 279 |
+
#endif
|
| 280 |
+
|
| 281 |
+
// If we're using all threads (static) or the tid is in-range (dynamic)
|
| 282 |
+
if (vec_thrs == NumThreads or tid < vec_thrs) {
|
| 283 |
+
auto src_c = recast<VecType const>(src_v);
|
| 284 |
+
auto dst_c = recast<VecType>(dst_v);
|
| 285 |
+
return copy(cpy, src_c, dst_c);
|
| 286 |
+
}
|
| 287 |
+
}
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
|
| 291 |
+
// Default max-vectorization size to value_type size
|
| 292 |
+
template <uint32_t NumThreads,
|
| 293 |
+
class SrcEngine, class SrcLayout,
|
| 294 |
+
class DstEngine, class DstLayout,
|
| 295 |
+
class CopyPolicy = DefaultCopy>
|
| 296 |
+
CUTE_HOST_DEVICE
|
| 297 |
+
void
|
| 298 |
+
cooperative_copy(uint32_t const& tid,
|
| 299 |
+
Tensor<SrcEngine, SrcLayout> const& src,
|
| 300 |
+
Tensor<DstEngine, DstLayout> & dst,
|
| 301 |
+
CopyPolicy const& cpy = {})
|
| 302 |
+
{
|
| 303 |
+
constexpr uint32_t MaxVecBits = sizeof_bits_v<typename SrcEngine::value_type>;
|
| 304 |
+
return cooperative_copy<NumThreads, MaxVecBits>(tid, src, dst, cpy);
|
| 305 |
+
}
|
| 306 |
+
|
| 307 |
+
//
|
| 308 |
+
// Accept mutable temporaries
|
| 309 |
+
//
|
| 310 |
+
|
| 311 |
+
template <uint32_t NumThreads,
|
| 312 |
+
class SrcEngine, class SrcLayout,
|
| 313 |
+
class DstEngine, class DstLayout,
|
| 314 |
+
class CopyPolicy = DefaultCopy>
|
| 315 |
+
CUTE_HOST_DEVICE
|
| 316 |
+
void
|
| 317 |
+
cooperative_copy(uint32_t const& tid,
|
| 318 |
+
Tensor<SrcEngine, SrcLayout> const& src,
|
| 319 |
+
Tensor<DstEngine, DstLayout> && dst,
|
| 320 |
+
CopyPolicy const& cpy = {})
|
| 321 |
+
{
|
| 322 |
+
return cooperative_copy<NumThreads>(tid, src, dst, cpy);
|
| 323 |
+
}
|
| 324 |
+
|
| 325 |
+
template <uint32_t NumThreads, uint32_t MaxVecBits,
|
| 326 |
+
class SrcEngine, class SrcLayout,
|
| 327 |
+
class DstEngine, class DstLayout,
|
| 328 |
+
class CopyPolicy = DefaultCopy>
|
| 329 |
+
CUTE_HOST_DEVICE
|
| 330 |
+
void
|
| 331 |
+
cooperative_copy(uint32_t const& tid,
|
| 332 |
+
Tensor<SrcEngine, SrcLayout> const& src,
|
| 333 |
+
Tensor<DstEngine, DstLayout> && dst,
|
| 334 |
+
CopyPolicy const& cpy = {})
|
| 335 |
+
{
|
| 336 |
+
return cooperative_copy<NumThreads, MaxVecBits>(tid, src, dst, cpy);
|
| 337 |
+
}
|
| 338 |
+
|
| 339 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/cooperative_gemm.hpp
ADDED
|
@@ -0,0 +1,553 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2017 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/config.hpp>
|
| 34 |
+
#include <cute/util/type_traits.hpp>
|
| 35 |
+
|
| 36 |
+
#include <cute/atom/mma_atom.hpp>
|
| 37 |
+
|
| 38 |
+
#include <cute/algorithm/axpby.hpp>
|
| 39 |
+
#include <cute/algorithm/functional.hpp>
|
| 40 |
+
#include <cute/algorithm/gemm.hpp>
|
| 41 |
+
|
| 42 |
+
#include <cute/tensor_impl.hpp>
|
| 43 |
+
|
| 44 |
+
namespace cute
|
| 45 |
+
{
|
| 46 |
+
|
| 47 |
+
//
|
| 48 |
+
// Cooperative Shared-Memory GEMMs
|
| 49 |
+
//
|
| 50 |
+
|
| 51 |
+
namespace detail {
|
| 52 |
+
|
| 53 |
+
// Slow fallback path:
|
| 54 |
+
template<typename ... Args,
|
| 55 |
+
typename Alpha, typename TRC, typename RCLayout,
|
| 56 |
+
typename Beta, class TSC, typename CLayout, typename SCLayout,
|
| 57 |
+
typename CLoadTransformOp, typename CStoreTransformOp>
|
| 58 |
+
CUTE_HOST_DEVICE
|
| 59 |
+
void
|
| 60 |
+
epilogue_predication(ThrMMA<Args...> const& thr_mma,
|
| 61 |
+
Alpha const& alpha,
|
| 62 |
+
Tensor<TRC, RCLayout> & tCrC,
|
| 63 |
+
Beta const& beta,
|
| 64 |
+
Tensor<TSC, CLayout> & sC,
|
| 65 |
+
Tensor<TSC, SCLayout> & tCsC,
|
| 66 |
+
CLoadTransformOp const& sC_load_op, // transforms C values before use in GEMM
|
| 67 |
+
CStoreTransformOp const& sC_store_op) // transforms results before they are stored to C
|
| 68 |
+
{
|
| 69 |
+
using InputTypeC = typename TSC::value_type;
|
| 70 |
+
using ComputeTypeC = typename ThrMMA<Args...>::ValTypeC;
|
| 71 |
+
CUTE_STATIC_ASSERT(CUTE_STL_NAMESPACE::is_same_v<ComputeTypeC, typename TRC::value_type>);
|
| 72 |
+
|
| 73 |
+
// Create coordinate tensors for the problem
|
| 74 |
+
Tensor cC = make_identity_tensor(shape(sC)); // (M,N) -> (m,n)
|
| 75 |
+
// Repeat partitioning with thr_mma
|
| 76 |
+
Tensor tCcC = thr_mma.partition_C(cC); // (MMA,MMA_M,MMA_N) -> (m,n)
|
| 77 |
+
|
| 78 |
+
const bool isBetaZero = [&] () {
|
| 79 |
+
if constexpr (is_complex<Beta>::value) {
|
| 80 |
+
return beta.real() == Int<0>{} && beta.imag() == Int<0>{};
|
| 81 |
+
}
|
| 82 |
+
else {
|
| 83 |
+
return beta == Int<0>{};
|
| 84 |
+
}
|
| 85 |
+
CUTE_GCC_UNREACHABLE;
|
| 86 |
+
} ();
|
| 87 |
+
|
| 88 |
+
// Custom axpby_if for now
|
| 89 |
+
CUTE_UNROLL
|
| 90 |
+
for (int i = 0; i < size(tCrC); ++i)
|
| 91 |
+
{
|
| 92 |
+
if (elem_less(tCcC(i), shape(sC)))
|
| 93 |
+
{
|
| 94 |
+
tCsC(i) = sC_store_op(isBetaZero ? alpha * tCrC(i)
|
| 95 |
+
: alpha * tCrC(i) +
|
| 96 |
+
beta * static_cast<ComputeTypeC>(sC_load_op(tCsC(i))));
|
| 97 |
+
}
|
| 98 |
+
}
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
template<class ... Args,
|
| 102 |
+
class Alpha, class TRC, class RCLayout,
|
| 103 |
+
class Beta, class TSC, class SCLayout,
|
| 104 |
+
class CLoadTransformOp, class CStoreTransformOp,
|
| 105 |
+
class SmemCopyLdOpC, class SmemCopyStOpC>
|
| 106 |
+
CUTE_HOST_DEVICE
|
| 107 |
+
void
|
| 108 |
+
epilogue_no_predication(uint32_t thread_idx,
|
| 109 |
+
ThrMMA<Args...> const& thr_mma,
|
| 110 |
+
Alpha const& alpha,
|
| 111 |
+
Tensor<TRC, RCLayout> & tCrC,
|
| 112 |
+
Beta const& beta,
|
| 113 |
+
Tensor<TSC, SCLayout> & sC,
|
| 114 |
+
CLoadTransformOp const& sC_load_op, // transforms C values before use in GEMM
|
| 115 |
+
CStoreTransformOp const& sC_store_op, // transforms results before they are stored to C
|
| 116 |
+
SmemCopyLdOpC const& sC_copy_ld_op,
|
| 117 |
+
SmemCopyStOpC const& sC_copy_st_op)
|
| 118 |
+
{
|
| 119 |
+
using InputTypeC = typename TSC::value_type;
|
| 120 |
+
using ComputeTypeC = typename TRC::value_type;
|
| 121 |
+
|
| 122 |
+
const bool isBetaZero = [&] () {
|
| 123 |
+
if constexpr (is_complex<Beta>::value) {
|
| 124 |
+
return beta.real() == Int<0>{} && beta.imag() == Int<0>{};
|
| 125 |
+
}
|
| 126 |
+
else {
|
| 127 |
+
return beta == Int<0>{};
|
| 128 |
+
}
|
| 129 |
+
CUTE_GCC_UNREACHABLE;
|
| 130 |
+
} ();
|
| 131 |
+
|
| 132 |
+
Tensor tCrD = make_fragment_like(tCrC);
|
| 133 |
+
Tensor tCrDi = make_fragment_like<InputTypeC>(tCrD);
|
| 134 |
+
|
| 135 |
+
if(!isBetaZero) {
|
| 136 |
+
auto smem_tiled_copy_C = make_tiled_copy_C(Copy_Atom<SmemCopyLdOpC, InputTypeC>{}, thr_mma);
|
| 137 |
+
auto smem_thr_copy_C = smem_tiled_copy_C.get_thread_slice(thread_idx);
|
| 138 |
+
Tensor tCsC = smem_thr_copy_C.partition_S(sC);
|
| 139 |
+
Tensor tCrDi_copy_view = smem_thr_copy_C.retile_D(tCrDi);
|
| 140 |
+
CUTE_STATIC_ASSERT_V(size<1>(tCsC) == size<1>(tCrDi_copy_view)); // CPY_M
|
| 141 |
+
CUTE_STATIC_ASSERT_V(size<2>(tCsC) == size<2>(tCrDi_copy_view)); // CPY_N
|
| 142 |
+
copy(smem_tiled_copy_C, tCsC, tCrDi_copy_view);
|
| 143 |
+
|
| 144 |
+
// Transform C on/after load
|
| 145 |
+
cute::transform(tCrDi, tCrD, sC_load_op);
|
| 146 |
+
}
|
| 147 |
+
// C = alpha * (A * B) + beta * C
|
| 148 |
+
axpby(alpha, tCrC, beta, tCrD);
|
| 149 |
+
// Transform C before/on store
|
| 150 |
+
cute::transform(tCrD, tCrDi, sC_store_op);
|
| 151 |
+
|
| 152 |
+
auto smem_tiled_copy_C = make_tiled_copy_C(Copy_Atom<SmemCopyStOpC, InputTypeC>{}, thr_mma);
|
| 153 |
+
auto smem_thr_copy_C = smem_tiled_copy_C.get_thread_slice(thread_idx);
|
| 154 |
+
Tensor tCsC = smem_thr_copy_C.partition_D(sC);
|
| 155 |
+
Tensor tCrDi_copy_view = smem_thr_copy_C.retile_S(tCrDi);
|
| 156 |
+
CUTE_STATIC_ASSERT_V(size<1>(tCsC) == size<1>(tCrDi_copy_view)); // CPY_M
|
| 157 |
+
CUTE_STATIC_ASSERT_V(size<2>(tCsC) == size<2>(tCrDi_copy_view)); // CPY_N
|
| 158 |
+
copy(smem_tiled_copy_C, tCrDi_copy_view, tCsC);
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
// Predicated Cooperative GEMM
|
| 162 |
+
template <class... Args,
|
| 163 |
+
class TA, class ALayout, class TB, class BLayout,
|
| 164 |
+
class TC, class RCLayout,
|
| 165 |
+
class ALoadTransformOp, class BLoadTransformOp>
|
| 166 |
+
CUTE_HOST_DEVICE
|
| 167 |
+
void
|
| 168 |
+
cooperative_gemm_predication(ThrMMA<Args...> const& thr_mma,
|
| 169 |
+
Tensor<TA, ALayout> const& sA,
|
| 170 |
+
Tensor<TB, BLayout> const& sB,
|
| 171 |
+
Tensor<TC, RCLayout> & tCrC,
|
| 172 |
+
ALoadTransformOp const& sA_load_op, // transforms A values before use in GEMM
|
| 173 |
+
BLoadTransformOp const& sB_load_op) // transforms B values before use in GEMM
|
| 174 |
+
{
|
| 175 |
+
using InputTypeA = typename TA::value_type;
|
| 176 |
+
using InputTypeB = typename TB::value_type;
|
| 177 |
+
using InputTypeC = typename TC::value_type;
|
| 178 |
+
using ComputeTypeA = typename ThrMMA<Args...>::ValTypeA;
|
| 179 |
+
using ComputeTypeB = typename ThrMMA<Args...>::ValTypeB;
|
| 180 |
+
using ComputeTypeC = typename ThrMMA<Args...>::ValTypeC;
|
| 181 |
+
|
| 182 |
+
//
|
| 183 |
+
// MMA Partitioning
|
| 184 |
+
//
|
| 185 |
+
|
| 186 |
+
// Partition the sA, sB, and sC tiles across the threads for the MMA
|
| 187 |
+
Tensor tCsA = thr_mma.partition_A(sA); // (MMA,MMA_M,MMA_K)
|
| 188 |
+
Tensor tCsB = thr_mma.partition_B(sB); // (MMA,MMA_N,MMA_K)
|
| 189 |
+
|
| 190 |
+
// Create register tensors for the MMA to operate on
|
| 191 |
+
Tensor tCrA = thr_mma.make_fragment_A(tCsA); // (MMA,MMA_M,MMA_K)
|
| 192 |
+
Tensor tCrB = thr_mma.make_fragment_B(tCsB); // (MMA,MMA_N,MMA_K)
|
| 193 |
+
//
|
| 194 |
+
// PREDICATION
|
| 195 |
+
//
|
| 196 |
+
|
| 197 |
+
// Create coordinate tensors for the problem
|
| 198 |
+
Tensor cA = make_identity_tensor(shape(sA)); // (M,K) -> (m,k)
|
| 199 |
+
Tensor cB = make_identity_tensor(shape(sB)); // (N,K) -> (n,k)
|
| 200 |
+
|
| 201 |
+
// Repeat partitioning with thr_mma
|
| 202 |
+
Tensor tCcA = thr_mma.partition_A(cA); // (MMA,MMA_M,MMA_K) -> (m,k)
|
| 203 |
+
Tensor tCcB = thr_mma.partition_B(cB); // (MMA,MMA_N,MMA_K) -> (n,k)
|
| 204 |
+
|
| 205 |
+
// Allocate the preds for MMA- and MMA_MN-modes
|
| 206 |
+
Tensor tCpA = make_tensor<bool>(make_shape(size<0>(tCsA), size<1>(tCsA)));
|
| 207 |
+
Tensor tCpB = make_tensor<bool>(make_shape(size<0>(tCsB), size<1>(tCsB)));
|
| 208 |
+
// Populate the predicates on M and N
|
| 209 |
+
CUTE_UNROLL
|
| 210 |
+
for (int i = 0; i < size(tCpA); ++i) {
|
| 211 |
+
tCpA(i) = elem_less(get<0>(tCcA(_,_,Int<0>{})(i)), shape<0>(sA));
|
| 212 |
+
}
|
| 213 |
+
CUTE_UNROLL
|
| 214 |
+
for (int i = 0; i < size(tCpB); ++i) {
|
| 215 |
+
tCpB(i) = elem_less(get<0>(tCcB(_,_,Int<0>{})(i)), shape<0>(sB));
|
| 216 |
+
}
|
| 217 |
+
//
|
| 218 |
+
// PREFETCH k_block = 0
|
| 219 |
+
// Condition the k-predication on (static) k_block == K_BLOCK_MAX-1, the last k_block
|
| 220 |
+
// Assumes the MMA-tiling in K is trivial
|
| 221 |
+
//
|
| 222 |
+
|
| 223 |
+
constexpr int K_BLOCK_MAX = size<2>(tCrA);
|
| 224 |
+
|
| 225 |
+
CUTE_UNROLL
|
| 226 |
+
for (int m = 0; m < size<1>(tCrA); ++m) { // Copy MMA_M
|
| 227 |
+
CUTE_UNROLL
|
| 228 |
+
for (int i = 0; i < size<0>(tCrA); ++i) { // Copy MMA_I
|
| 229 |
+
tCrA(i,m,0) = (tCpA(i,m) && (0 < K_BLOCK_MAX-1 || elem_less(get<1>(tCcA(i,m,0)), shape<1>(sA)))) ? static_cast<ComputeTypeA>(sA_load_op(tCsA(i,m,0))) : ComputeTypeA{};
|
| 230 |
+
}
|
| 231 |
+
}
|
| 232 |
+
CUTE_UNROLL
|
| 233 |
+
for (int n = 0; n < size<1>(tCrB); ++n) { // Copy MMA_N
|
| 234 |
+
CUTE_UNROLL
|
| 235 |
+
for (int i = 0; i < size<0>(tCrB); ++i) { // Copy MMA_I
|
| 236 |
+
tCrB(i,n,0) = (tCpB(i,n) && (0 < K_BLOCK_MAX-1 || elem_less(get<1>(tCcB(i,n,0)), shape<1>(sB)))) ? static_cast<ComputeTypeB>(sB_load_op(tCsB(i,n,0))) : ComputeTypeB{};
|
| 237 |
+
}
|
| 238 |
+
}
|
| 239 |
+
//
|
| 240 |
+
// MAINLOOP
|
| 241 |
+
//
|
| 242 |
+
|
| 243 |
+
CUTE_UNROLL
|
| 244 |
+
for (int k_block = 0; k_block < K_BLOCK_MAX; ++k_block)
|
| 245 |
+
{
|
| 246 |
+
if (k_block < K_BLOCK_MAX-1) // static-if not the last k_block
|
| 247 |
+
{
|
| 248 |
+
int k_next = k_block + 1; // Load k_next block
|
| 249 |
+
|
| 250 |
+
// Condition the k-predication on (static) k_block == K_BLOCK_MAX-1, the last k_block
|
| 251 |
+
// Assumes the MMA-tiling in K is trivial
|
| 252 |
+
|
| 253 |
+
CUTE_UNROLL
|
| 254 |
+
for (int m = 0; m < size<1>(tCrA); ++m) { // Copy MMA_M
|
| 255 |
+
CUTE_UNROLL
|
| 256 |
+
for (int i = 0; i < size<0>(tCrA); ++i) { // Copy MMA_I
|
| 257 |
+
tCrA(i,m,k_next) = (tCpA(i,m) && (k_next < K_BLOCK_MAX-1 || elem_less(get<1>(tCcA(i,m,k_next)), shape<1>(sA)))) ? static_cast<ComputeTypeA>(sA_load_op(tCsA(i,m,k_next))) : ComputeTypeA{};
|
| 258 |
+
}
|
| 259 |
+
}
|
| 260 |
+
CUTE_UNROLL
|
| 261 |
+
for (int n = 0; n < size<1>(tCrB); ++n) { // Copy MMA_N
|
| 262 |
+
CUTE_UNROLL
|
| 263 |
+
for (int i = 0; i < size<0>(tCrB); ++i) { // Copy MMA_I
|
| 264 |
+
tCrB(i,n,k_next) = (tCpB(i,n) && (k_next < K_BLOCK_MAX-1 || elem_less(get<1>(tCcB(i,n,k_next)), shape<1>(sB)))) ? static_cast<ComputeTypeB>(sB_load_op(tCsB(i,n,k_next))) : ComputeTypeB{};
|
| 265 |
+
}
|
| 266 |
+
}
|
| 267 |
+
}
|
| 268 |
+
// GEMM on k_block in registers
|
| 269 |
+
gemm(thr_mma, tCrA(_,_,k_block), tCrB(_,_,k_block), tCrC);
|
| 270 |
+
}
|
| 271 |
+
}
|
| 272 |
+
|
| 273 |
+
// Unpredicated Cooperative GEMM
|
| 274 |
+
template <class... Args,
|
| 275 |
+
class TA, class ALayout, class TB, class BLayout,
|
| 276 |
+
class TC, class CLayout,
|
| 277 |
+
class ALoadTransformOp, class BLoadTransformOp,
|
| 278 |
+
class SmemCopyOpA, class SmemCopyOpB>
|
| 279 |
+
CUTE_HOST_DEVICE
|
| 280 |
+
void
|
| 281 |
+
cooperative_gemm_no_predication(uint32_t thread_idx,
|
| 282 |
+
ThrMMA<Args...> const& thr_mma,
|
| 283 |
+
Tensor<TA, ALayout> const& sA,
|
| 284 |
+
Tensor<TB, BLayout> const& sB,
|
| 285 |
+
Tensor<TC, CLayout> & tCrC,
|
| 286 |
+
ALoadTransformOp const& sA_load_op, // transforms A values before use in GEMM
|
| 287 |
+
BLoadTransformOp const& sB_load_op, // transforms B values before use in GEMM
|
| 288 |
+
SmemCopyOpA const& sA_copy_op,
|
| 289 |
+
SmemCopyOpB const& sB_copy_op)
|
| 290 |
+
{
|
| 291 |
+
using InputTypeA = typename TA::value_type;
|
| 292 |
+
using InputTypeB = typename TB::value_type;
|
| 293 |
+
using InputTypeC = typename TC::value_type;
|
| 294 |
+
using ComputeTypeA = typename ThrMMA<Args...>::ValTypeA;
|
| 295 |
+
using ComputeTypeB = typename ThrMMA<Args...>::ValTypeB;
|
| 296 |
+
using ComputeTypeC = typename ThrMMA<Args...>::ValTypeC;
|
| 297 |
+
|
| 298 |
+
|
| 299 |
+
//
|
| 300 |
+
// MMA Partitioning
|
| 301 |
+
//
|
| 302 |
+
|
| 303 |
+
// Create register tensors for the MMA to operate on
|
| 304 |
+
Tensor tCrA = thr_mma.partition_fragment_A(sA); // (MMA,MMA_M,MMA_K)
|
| 305 |
+
Tensor tCrAi = make_fragment_like<InputTypeA>(tCrA);
|
| 306 |
+
Tensor tCrB = thr_mma.partition_fragment_B(sB); // (MMA,MMA_N,MMA_K)
|
| 307 |
+
Tensor tCrBi = make_fragment_like<InputTypeB>(tCrB);
|
| 308 |
+
|
| 309 |
+
using CopyOpAType = SmemCopyOpA;
|
| 310 |
+
using CopyOpBType = SmemCopyOpB;
|
| 311 |
+
|
| 312 |
+
auto smem_tiled_copy_A = make_tiled_copy_A(Copy_Atom<CopyOpAType, InputTypeA>{}, thr_mma);
|
| 313 |
+
auto smem_thr_copy_A = smem_tiled_copy_A.get_thread_slice(thread_idx);
|
| 314 |
+
Tensor tCsA = smem_thr_copy_A.partition_S(sA);
|
| 315 |
+
Tensor tCrAi_copy_view = smem_thr_copy_A.retile_D(tCrAi);
|
| 316 |
+
CUTE_STATIC_ASSERT_V(size<1>(tCsA) == size<1>(tCrAi_copy_view)); // CPY_M
|
| 317 |
+
CUTE_STATIC_ASSERT_V(size<2>(tCsA) == size<2>(tCrAi_copy_view)); // CPY_K
|
| 318 |
+
|
| 319 |
+
auto smem_tiled_copy_B = make_tiled_copy_B(Copy_Atom<CopyOpBType, InputTypeB>{}, thr_mma);
|
| 320 |
+
auto smem_thr_copy_B = smem_tiled_copy_B.get_thread_slice(thread_idx);
|
| 321 |
+
Tensor tCsB = smem_thr_copy_B.partition_S(sB);
|
| 322 |
+
Tensor tCrBi_copy_view = smem_thr_copy_B.retile_D(tCrBi);
|
| 323 |
+
CUTE_STATIC_ASSERT_V(size<1>(tCsB) == size<1>(tCrBi_copy_view)); // CPY_N
|
| 324 |
+
CUTE_STATIC_ASSERT_V(size<2>(tCsB) == size<2>(tCrBi_copy_view)); // CPY_K
|
| 325 |
+
//
|
| 326 |
+
// PREFETCH
|
| 327 |
+
//
|
| 328 |
+
|
| 329 |
+
copy(smem_tiled_copy_A, tCsA(_,_,Int<0>{}), tCrAi_copy_view(_,_,Int<0>{}));
|
| 330 |
+
copy(smem_tiled_copy_B, tCsB(_,_,Int<0>{}), tCrBi_copy_view(_,_,Int<0>{}));
|
| 331 |
+
//
|
| 332 |
+
// MAINLOOP
|
| 333 |
+
//
|
| 334 |
+
|
| 335 |
+
constexpr int K_BLOCK_MAX = size<2>(tCrA);
|
| 336 |
+
|
| 337 |
+
CUTE_UNROLL
|
| 338 |
+
for (int k_block = 0; k_block < K_BLOCK_MAX; ++k_block)
|
| 339 |
+
{
|
| 340 |
+
// static-if load the next k_block. No k-predication required on these loads.
|
| 341 |
+
if (k_block < K_BLOCK_MAX-1)
|
| 342 |
+
{
|
| 343 |
+
// Load the next k_block
|
| 344 |
+
int k_next = k_block + 1; // statically unrolled
|
| 345 |
+
copy(smem_tiled_copy_A, tCsA(_,_,k_next), tCrAi_copy_view(_,_,k_next));
|
| 346 |
+
copy(smem_tiled_copy_B, tCsB(_,_,k_next), tCrBi_copy_view(_,_,k_next));
|
| 347 |
+
}
|
| 348 |
+
|
| 349 |
+
// Transform A and B, relying on the compiler to remove in case of identity ops
|
| 350 |
+
cute::transform(tCrAi(_,_,k_block), tCrA(_,_,k_block), sA_load_op);
|
| 351 |
+
cute::transform(tCrBi(_,_,k_block), tCrB(_,_,k_block), sB_load_op);
|
| 352 |
+
|
| 353 |
+
// GEMM on k_block in registers
|
| 354 |
+
gemm(thr_mma, tCrA(_,_,k_block), tCrB(_,_,k_block), tCrC);
|
| 355 |
+
}
|
| 356 |
+
}
|
| 357 |
+
|
| 358 |
+
} // end namespace detail
|
| 359 |
+
|
| 360 |
+
// C passed as a shared memory tensor
|
| 361 |
+
// Epilogue included
|
| 362 |
+
template <class... Args,
|
| 363 |
+
class Alpha, class TA, class ALayout, class TB, class BLayout,
|
| 364 |
+
class Beta, class TC, class CLayout,
|
| 365 |
+
class ALoadTransformOp = cute::identity, class BLoadTransformOp = cute::identity,
|
| 366 |
+
class CLoadTransformOp = cute::identity, class CStoreTransformOp = cute::identity,
|
| 367 |
+
class SmemCopyOpA = DefaultCopy, class SmemCopyOpB = DefaultCopy,
|
| 368 |
+
class SmemCopyLdOpC = DefaultCopy, class SmemCopyStOpC = DefaultCopy>
|
| 369 |
+
CUTE_HOST_DEVICE
|
| 370 |
+
void
|
| 371 |
+
cooperative_gemm(uint32_t thread_idx,
|
| 372 |
+
TiledMMA<Args...> const& tiled_mma,
|
| 373 |
+
Alpha const& alpha,
|
| 374 |
+
Tensor<TA, ALayout> const& sA,
|
| 375 |
+
Tensor<TB, BLayout> const& sB,
|
| 376 |
+
Beta const& beta,
|
| 377 |
+
Tensor<TC, CLayout> & sC,
|
| 378 |
+
ALoadTransformOp const& sA_load_op = {}, // transforms A values before use in GEMM
|
| 379 |
+
BLoadTransformOp const& sB_load_op = {}, // transforms B values before use in GEMM
|
| 380 |
+
CLoadTransformOp const& sC_load_op = {}, // transforms C values before use in GEMM
|
| 381 |
+
CStoreTransformOp const& sC_store_op = {}, // transforms results before they are stored to C
|
| 382 |
+
SmemCopyOpA const& sA_copy_op = {},
|
| 383 |
+
SmemCopyOpB const& sB_copy_op = {},
|
| 384 |
+
SmemCopyLdOpC const& sC_copy_ld_op = {},
|
| 385 |
+
SmemCopyStOpC const& sC_copy_st_op = {})
|
| 386 |
+
{
|
| 387 |
+
CUTE_STATIC_ASSERT_V(rank(sA) == Int<2>{});
|
| 388 |
+
CUTE_STATIC_ASSERT_V(rank(sB) == Int<2>{});
|
| 389 |
+
CUTE_STATIC_ASSERT_V(rank(sC) == Int<2>{});
|
| 390 |
+
|
| 391 |
+
CUTE_STATIC_ASSERT_V(size<0>(sA) == size<0>(sC)); // AM == CM
|
| 392 |
+
CUTE_STATIC_ASSERT_V(size<0>(sB) == size<1>(sC)); // BN == CN
|
| 393 |
+
CUTE_STATIC_ASSERT_V(size<1>(sA) == size<1>(sB)); // AK == BK
|
| 394 |
+
|
| 395 |
+
using InputTypeA = typename TA::value_type;
|
| 396 |
+
using InputTypeB = typename TB::value_type;
|
| 397 |
+
using InputTypeC = typename TC::value_type;
|
| 398 |
+
using ComputeTypeA = typename TiledMMA<Args...>::ValTypeA;
|
| 399 |
+
using ComputeTypeB = typename TiledMMA<Args...>::ValTypeB;
|
| 400 |
+
using ComputeTypeC = typename TiledMMA<Args...>::ValTypeC;
|
| 401 |
+
|
| 402 |
+
auto compat = evenly_divides(make_shape(size<0>(sA), size<0>(sB), size<1>(sA)),
|
| 403 |
+
tile_shape(TiledMMA<Args...>{}));
|
| 404 |
+
|
| 405 |
+
// ThrMMA
|
| 406 |
+
auto thr_mma = tiled_mma.get_thread_slice(thread_idx);
|
| 407 |
+
Tensor tCsC = thr_mma.partition_C(sC); // (MMA,MMA_M,MMA_N) :: InputTypeC
|
| 408 |
+
Tensor tCrC = thr_mma.make_fragment_C(tCsC); // (MMA,MMA_M,MMA_N) :: ComputeTypeC
|
| 409 |
+
|
| 410 |
+
// Clear accumulators
|
| 411 |
+
clear(tCrC);
|
| 412 |
+
if constexpr (is_constant<true, decltype(compat)>::value) {
|
| 413 |
+
detail::cooperative_gemm_no_predication(
|
| 414 |
+
thread_idx, thr_mma, sA, sB, tCrC, sA_load_op, sB_load_op, sA_copy_op, sB_copy_op
|
| 415 |
+
);
|
| 416 |
+
detail::epilogue_no_predication(
|
| 417 |
+
thread_idx, thr_mma,alpha, tCrC, beta, sC, sC_load_op, sC_store_op, sC_copy_ld_op, sC_copy_st_op
|
| 418 |
+
);
|
| 419 |
+
} else {
|
| 420 |
+
detail::cooperative_gemm_predication(
|
| 421 |
+
thr_mma, sA, sB, tCrC, sA_load_op, sB_load_op
|
| 422 |
+
);
|
| 423 |
+
detail::epilogue_predication(
|
| 424 |
+
thr_mma, alpha, tCrC, beta, sC, tCsC, sC_load_op, sC_store_op
|
| 425 |
+
);
|
| 426 |
+
}
|
| 427 |
+
}
|
| 428 |
+
|
| 429 |
+
// C already partitioned into registers on input
|
| 430 |
+
// It can be passed non-empty
|
| 431 |
+
// Epilogue not included
|
| 432 |
+
template <class... Args,
|
| 433 |
+
class TA, class ALayout, class TB, class BLayout,
|
| 434 |
+
class TC, class CLayout,
|
| 435 |
+
class ALoadTransformOp = cute::identity, class BLoadTransformOp = cute::identity,
|
| 436 |
+
class SmemCopyOpA = DefaultCopy, class SmemCopyOpB = DefaultCopy>
|
| 437 |
+
CUTE_HOST_DEVICE
|
| 438 |
+
void
|
| 439 |
+
cooperative_gemm(uint32_t thread_idx,
|
| 440 |
+
TiledMMA<Args...> const& tiled_mma,
|
| 441 |
+
Tensor<TA, ALayout> const& sA,
|
| 442 |
+
Tensor<TB, BLayout> const& sB,
|
| 443 |
+
Tensor<TC, CLayout> & tCrC,
|
| 444 |
+
ALoadTransformOp const& sA_load_op = {}, // transforms A values before use in GEMM
|
| 445 |
+
BLoadTransformOp const& sB_load_op = {}, // transforms B values before use in GEMM
|
| 446 |
+
SmemCopyOpA const& sA_copy_op = {},
|
| 447 |
+
SmemCopyOpB const& sB_copy_op = {})
|
| 448 |
+
{
|
| 449 |
+
CUTE_STATIC_ASSERT_V(rank(sA) == Int<2>{});
|
| 450 |
+
CUTE_STATIC_ASSERT_V(rank(sB) == Int<2>{});
|
| 451 |
+
|
| 452 |
+
CUTE_STATIC_ASSERT_V(size<1>(sA) == size<1>(sB)); // AK == BK
|
| 453 |
+
|
| 454 |
+
using InputTypeA = typename TA::value_type;
|
| 455 |
+
using InputTypeB = typename TB::value_type;
|
| 456 |
+
using InputTypeC = typename TC::value_type;
|
| 457 |
+
using ComputeTypeA = typename TiledMMA<Args...>::ValTypeA;
|
| 458 |
+
using ComputeTypeB = typename TiledMMA<Args...>::ValTypeB;
|
| 459 |
+
using ComputeTypeC = typename TiledMMA<Args...>::ValTypeC;
|
| 460 |
+
|
| 461 |
+
// Check if input C fragment is compatible with thr_mma and problem size
|
| 462 |
+
using ref_c_frag = decltype(partition_shape_C(tiled_mma, make_shape(size<0>(sA), size<0>(sB))));
|
| 463 |
+
CUTE_STATIC_ASSERT_V(compatible(shape(ref_c_frag{}), shape(tCrC)));
|
| 464 |
+
|
| 465 |
+
auto compat = evenly_divides(make_shape(size<0>(sA), size<0>(sB), size<1>(sA)),
|
| 466 |
+
tile_shape(TiledMMA<Args...>{}));
|
| 467 |
+
|
| 468 |
+
// ThrMMA
|
| 469 |
+
auto thr_mma = tiled_mma.get_thread_slice(thread_idx);
|
| 470 |
+
|
| 471 |
+
if constexpr (is_constant<true, decltype(compat)>::value) {
|
| 472 |
+
detail::cooperative_gemm_no_predication(
|
| 473 |
+
thread_idx, thr_mma, sA, sB, tCrC, sA_load_op, sB_load_op, sA_copy_op, sB_copy_op
|
| 474 |
+
);
|
| 475 |
+
} else {
|
| 476 |
+
detail::cooperative_gemm_predication(
|
| 477 |
+
thr_mma, sA, sB, tCrC, sA_load_op, sB_load_op
|
| 478 |
+
);
|
| 479 |
+
}
|
| 480 |
+
}
|
| 481 |
+
|
| 482 |
+
// Accept mutable temporaries
|
| 483 |
+
template <class... Args,
|
| 484 |
+
class Alpha, class TA, class ALayout, class TB, class BLayout,
|
| 485 |
+
class Beta, class TC, class CLayout,
|
| 486 |
+
class ALoadTransformOp = cute::identity, class BLoadTransformOp = cute::identity,
|
| 487 |
+
class CLoadTransformOp = cute::identity, class CStoreTransformOp = cute::identity,
|
| 488 |
+
class SmemCopyOpA = DefaultCopy, class SmemCopyOpB = DefaultCopy,
|
| 489 |
+
class SmemCopyLdOpC = DefaultCopy, class SmemCopyStOpC = DefaultCopy>
|
| 490 |
+
CUTE_HOST_DEVICE
|
| 491 |
+
void
|
| 492 |
+
cooperative_gemm(uint32_t thread_idx,
|
| 493 |
+
TiledMMA<Args...> const& tiled_mma,
|
| 494 |
+
Alpha const& alpha,
|
| 495 |
+
Tensor<TA, ALayout> const& sA,
|
| 496 |
+
Tensor<TB, BLayout> const& sB,
|
| 497 |
+
Beta const& beta,
|
| 498 |
+
Tensor<TC, CLayout> && sC,
|
| 499 |
+
ALoadTransformOp const& sA_load_op = {}, // transforms A values before use in GEMM
|
| 500 |
+
BLoadTransformOp const& sB_load_op = {}, // transforms B values before use in GEMM
|
| 501 |
+
CLoadTransformOp const& sC_load_op = {}, // transforms C values before use in GEMM
|
| 502 |
+
CStoreTransformOp const& sC_store_op = {}, // transforms results before they are stored to C
|
| 503 |
+
SmemCopyOpA const& sA_copy_op = {},
|
| 504 |
+
SmemCopyOpB const& sB_copy_op = {},
|
| 505 |
+
SmemCopyLdOpC const& sC_copy_ld_op = {},
|
| 506 |
+
SmemCopyStOpC const& sC_copy_st_op = {})
|
| 507 |
+
{
|
| 508 |
+
cooperative_gemm(thread_idx, tiled_mma, alpha, sA, sB, beta, sC,
|
| 509 |
+
sA_load_op, sB_load_op, sC_load_op, sC_store_op,
|
| 510 |
+
sA_copy_op, sB_copy_op, sC_copy_ld_op, sC_copy_st_op);
|
| 511 |
+
}
|
| 512 |
+
|
| 513 |
+
// Legacy overload of cute::gemm for backwards-compatibility
|
| 514 |
+
template <class... Args,
|
| 515 |
+
class Alpha, class TA, class ALayout, class TB, class BLayout,
|
| 516 |
+
class Beta, class TC, class CLayout,
|
| 517 |
+
class ALoadTransformOp = cute::identity, class BLoadTransformOp = cute::identity,
|
| 518 |
+
class CLoadTransformOp = cute::identity, class CStoreTransformOp = cute::identity>
|
| 519 |
+
CUTE_HOST_DEVICE
|
| 520 |
+
void
|
| 521 |
+
gemm(ThrMMA<Args...> const& thr_mma,
|
| 522 |
+
Alpha const& alpha,
|
| 523 |
+
Tensor<TA, ALayout> const& sA,
|
| 524 |
+
Tensor<TB, BLayout> const& sB,
|
| 525 |
+
Beta const& beta,
|
| 526 |
+
Tensor<TC, CLayout> & sC,
|
| 527 |
+
ALoadTransformOp const& sA_load_op = {}, // transforms A values before use in GEMM
|
| 528 |
+
BLoadTransformOp const& sB_load_op = {}, // transforms B values before use in GEMM
|
| 529 |
+
CLoadTransformOp const& sC_load_op = {}, // transforms C values before use in GEMM
|
| 530 |
+
CStoreTransformOp const& sC_store_op = {}) // transforms results before they are stored to C
|
| 531 |
+
{
|
| 532 |
+
CUTE_STATIC_ASSERT_V(rank(sA) == Int<2>{});
|
| 533 |
+
CUTE_STATIC_ASSERT_V(rank(sB) == Int<2>{});
|
| 534 |
+
CUTE_STATIC_ASSERT_V(rank(sC) == Int<2>{});
|
| 535 |
+
|
| 536 |
+
CUTE_STATIC_ASSERT_V(size<0>(sA) == size<0>(sC)); // AM == CM
|
| 537 |
+
CUTE_STATIC_ASSERT_V(size<0>(sB) == size<1>(sC)); // BN == CN
|
| 538 |
+
CUTE_STATIC_ASSERT_V(size<1>(sA) == size<1>(sB)); // AK == BK
|
| 539 |
+
|
| 540 |
+
Tensor tCsC = thr_mma.partition_C(sC); // (MMA,MMA_M,MMA_N)
|
| 541 |
+
Tensor tCrC = thr_mma.make_fragment_C(tCsC); // (MMA,MMA_M,MMA_N)
|
| 542 |
+
|
| 543 |
+
// Goes directly to the slow path to avoid getting thread_idx from thr_mma
|
| 544 |
+
detail::cooperative_gemm_predication(
|
| 545 |
+
thr_mma, sA, sB, sC, sA_load_op, sB_load_op
|
| 546 |
+
);
|
| 547 |
+
|
| 548 |
+
detail::epilogue_predication(
|
| 549 |
+
thr_mma, alpha, tCrC, beta, sC, tCsC, sC_load_op, sC_store_op
|
| 550 |
+
);
|
| 551 |
+
}
|
| 552 |
+
|
| 553 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/copy.hpp
ADDED
|
@@ -0,0 +1,527 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/config.hpp> // CUTE_HOST_DEVICE
|
| 34 |
+
#include <cute/tensor_impl.hpp> // cute::Tensor
|
| 35 |
+
#include <cute/tensor_predicate.hpp> // cute::TrivialPredTensor
|
| 36 |
+
#include <cute/atom/copy_atom.hpp> // cute::Copy_Atom
|
| 37 |
+
|
| 38 |
+
namespace cute
|
| 39 |
+
{
|
| 40 |
+
|
| 41 |
+
//
|
| 42 |
+
// copy_if -- Predicated Copy
|
| 43 |
+
//
|
| 44 |
+
|
| 45 |
+
template <class PrdTensor,
|
| 46 |
+
class SrcEngine, class SrcLayout,
|
| 47 |
+
class DstEngine, class DstLayout>
|
| 48 |
+
CUTE_HOST_DEVICE
|
| 49 |
+
void
|
| 50 |
+
copy_if(PrdTensor const& pred,
|
| 51 |
+
Tensor<SrcEngine, SrcLayout> const& src,
|
| 52 |
+
Tensor<DstEngine, DstLayout> & dst)
|
| 53 |
+
{
|
| 54 |
+
using SrcType = typename SrcEngine::value_type;
|
| 55 |
+
using DstType = typename DstEngine::value_type;
|
| 56 |
+
|
| 57 |
+
CUTE_UNROLL
|
| 58 |
+
for (int i = 0; i < size(dst); ++i) {
|
| 59 |
+
if (pred(i)) {
|
| 60 |
+
dst(i) = static_cast<DstType>(static_cast<SrcType>(src(i)));
|
| 61 |
+
}
|
| 62 |
+
}
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
//
|
| 66 |
+
// copy_if -- Predicated CopyAtom
|
| 67 |
+
//
|
| 68 |
+
|
| 69 |
+
template <class... CopyArgs,
|
| 70 |
+
class PredTensor,
|
| 71 |
+
class SrcEngine, class SrcLayout,
|
| 72 |
+
class DstEngine, class DstLayout>
|
| 73 |
+
CUTE_HOST_DEVICE
|
| 74 |
+
void
|
| 75 |
+
copy_if(Copy_Atom<CopyArgs...> const& copy_atom,
|
| 76 |
+
PredTensor const& pred, // (Rest...)
|
| 77 |
+
Tensor<SrcEngine, SrcLayout> const& src, // (V,Rest...)
|
| 78 |
+
Tensor<DstEngine, DstLayout> & dst) // (V,Rest...)
|
| 79 |
+
{
|
| 80 |
+
static_assert(SrcLayout::rank == DstLayout::rank, "CopyAtom rank-mismatch.");
|
| 81 |
+
auto has_with_bool = cute::is_valid([](auto t)->void_t<decltype(declval<typename decltype(t)::Traits>().with(true))>{}, copy_atom);
|
| 82 |
+
|
| 83 |
+
if constexpr (SrcLayout::rank == 1) { // Dispatch the copy
|
| 84 |
+
if constexpr (has_with_bool) {
|
| 85 |
+
copy_atom.with(pred()).call(src, dst);
|
| 86 |
+
} else {
|
| 87 |
+
if (pred()) { copy_atom.call(src, dst); }
|
| 88 |
+
}
|
| 89 |
+
} else { // Loop over all but the first mode
|
| 90 |
+
constexpr int R = SrcLayout::rank;
|
| 91 |
+
Tensor src_v = group_modes<1,R>(src);
|
| 92 |
+
Tensor dst_v = group_modes<1,R>(dst);
|
| 93 |
+
CUTE_UNROLL
|
| 94 |
+
for (int i = 0; i < size<1>(dst_v); ++i) {
|
| 95 |
+
if constexpr (has_with_bool) {
|
| 96 |
+
copy_atom.with(pred(i)).call(src_v(_,i), dst_v(_,i));
|
| 97 |
+
} else {
|
| 98 |
+
if (pred(i)) { copy_atom.call(src_v(_,i), dst_v(_,i)); }
|
| 99 |
+
}
|
| 100 |
+
}
|
| 101 |
+
}
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
//
|
| 105 |
+
// copy_if -- AutoCopyAsync
|
| 106 |
+
//
|
| 107 |
+
template <class PrdTensor,
|
| 108 |
+
class SrcEngine, class SrcLayout,
|
| 109 |
+
class DstEngine, class DstLayout>
|
| 110 |
+
CUTE_HOST_DEVICE
|
| 111 |
+
void
|
| 112 |
+
copy_if(AutoCopyAsync const& cpy,
|
| 113 |
+
PrdTensor const& pred,
|
| 114 |
+
Tensor<SrcEngine, SrcLayout> const& src,
|
| 115 |
+
Tensor<DstEngine, DstLayout> & dst)
|
| 116 |
+
{
|
| 117 |
+
using SrcElemWithConst = remove_reference_t<typename SrcEngine::reference>;
|
| 118 |
+
using SrcType = typename SrcEngine::value_type;
|
| 119 |
+
using DstType = typename DstEngine::value_type;
|
| 120 |
+
|
| 121 |
+
auto copy_op = []() {
|
| 122 |
+
#if defined(CUTE_ARCH_CP_ASYNC_SM80_ENABLED)
|
| 123 |
+
if constexpr (is_gmem<SrcEngine>::value && is_smem<DstEngine>::value &&
|
| 124 |
+
sizeof(SrcType) == sizeof(DstType)) {
|
| 125 |
+
if constexpr (is_const_v<SrcElemWithConst> && sizeof(SrcType) == 16) {
|
| 126 |
+
return SM80_CP_ASYNC_CACHEGLOBAL<SrcType,DstType>{};
|
| 127 |
+
} else if constexpr (sizeof(SrcType) == 4 || sizeof(SrcType) == 8 || sizeof(SrcType) == 16) {
|
| 128 |
+
return SM80_CP_ASYNC_CACHEALWAYS<SrcType,DstType>{};
|
| 129 |
+
} else {
|
| 130 |
+
return UniversalCopy<SrcType,DstType>{};
|
| 131 |
+
}
|
| 132 |
+
} else {
|
| 133 |
+
return UniversalCopy<SrcType,DstType>{};
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
CUTE_GCC_UNREACHABLE;
|
| 137 |
+
#else
|
| 138 |
+
return UniversalCopy<SrcType,DstType>{};
|
| 139 |
+
#endif
|
| 140 |
+
}();
|
| 141 |
+
|
| 142 |
+
CUTE_UNROLL
|
| 143 |
+
for (int i = 0; i < size(dst); ++i) {
|
| 144 |
+
if (pred(i)) {
|
| 145 |
+
copy_op.copy(src(i), dst(i));
|
| 146 |
+
}
|
| 147 |
+
}
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
//
|
| 151 |
+
// copy -- AutoCopyAsync
|
| 152 |
+
//
|
| 153 |
+
|
| 154 |
+
template <class SrcEngine, class SrcLayout,
|
| 155 |
+
class DstEngine, class DstLayout>
|
| 156 |
+
CUTE_HOST_DEVICE
|
| 157 |
+
void
|
| 158 |
+
copy(AutoCopyAsync const& cpy,
|
| 159 |
+
Tensor<SrcEngine, SrcLayout> const& src, // (V,Rest...)
|
| 160 |
+
Tensor<DstEngine, DstLayout> & dst) // (V,Rest...)
|
| 161 |
+
{
|
| 162 |
+
copy_if(cpy, TrivialPredTensor{}, src, dst);
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
//
|
| 166 |
+
// copy -- CopyAtom
|
| 167 |
+
//
|
| 168 |
+
|
| 169 |
+
template <class... CopyArgs,
|
| 170 |
+
class SrcEngine, class SrcLayout,
|
| 171 |
+
class DstEngine, class DstLayout>
|
| 172 |
+
CUTE_HOST_DEVICE
|
| 173 |
+
void
|
| 174 |
+
copy(Copy_Atom<CopyArgs...> const& copy_atom,
|
| 175 |
+
Tensor<SrcEngine, SrcLayout> const& src, // (V,Rest...)
|
| 176 |
+
Tensor<DstEngine, DstLayout> & dst) // (V,Rest...)
|
| 177 |
+
{
|
| 178 |
+
static_assert(SrcLayout::rank == DstLayout::rank, "CopyAtom rank-mismatch.");
|
| 179 |
+
|
| 180 |
+
if constexpr (SrcLayout::rank == 1) { // Dispatch the copy
|
| 181 |
+
copy_atom.call(src, dst);
|
| 182 |
+
} else { // Loop over all but the first mode
|
| 183 |
+
constexpr int R = SrcLayout::rank;
|
| 184 |
+
Tensor src_v = group_modes<1,R>(src);
|
| 185 |
+
Tensor dst_v = group_modes<1,R>(dst);
|
| 186 |
+
|
| 187 |
+
if constexpr (is_static<decltype(shape(src_v))>::value && is_static<decltype(shape(dst_v))>::value) {
|
| 188 |
+
CUTE_STATIC_ASSERT_V(size<1>(src_v) == size<1>(dst_v));
|
| 189 |
+
|
| 190 |
+
// AutoFilter on the Rest-mode
|
| 191 |
+
auto dst_null = nullspace(layout<1>(dst_v));
|
| 192 |
+
|
| 193 |
+
Tensor dst_n = zipped_divide(dst_v, make_tile(shape<0>(dst_v), dst_null)); // ((V, NLL), (_1, Rest))
|
| 194 |
+
Tensor src_n = zipped_divide(src_v, make_tile(shape<0>(src_v), dst_null)); // ((V, NLL), (_1, Rest))
|
| 195 |
+
|
| 196 |
+
CUTE_STATIC_ASSERT_V(size<1>(src_n) == size<1>(dst_n));
|
| 197 |
+
CUTE_STATIC_ASSERT_V((cosize<0,1>(dst_n.layout()) == Int<1>{}), "Nullspace definition error");
|
| 198 |
+
CUTE_STATIC_ASSERT_V((cosize<0,1>(src_n.layout()) == Int<1>{}), "Error: Ambiguous scatter detected in copy");
|
| 199 |
+
CUTE_STATIC_ASSERT_V((size<1,0>(dst_n) == Int<1>{}));
|
| 200 |
+
CUTE_STATIC_ASSERT_V((size<1,0>(src_n) == Int<1>{}));
|
| 201 |
+
|
| 202 |
+
Tensor dst_c = dst_n(make_coord(_,Int<0>{}),make_coord(Int<0>{},_)); // (V, Rest)
|
| 203 |
+
Tensor src_c = src_n(make_coord(_,Int<0>{}),make_coord(Int<0>{},_)); // (V, Rest)
|
| 204 |
+
|
| 205 |
+
CUTE_STATIC_ASSERT_V(size<1>(src_c) == size<1>(dst_c));
|
| 206 |
+
CUTE_STATIC_ASSERT_V(shape<0>(dst_c) == shape<0>(dst));
|
| 207 |
+
CUTE_STATIC_ASSERT_V(shape<0>(src_c) == shape<0>(src));
|
| 208 |
+
|
| 209 |
+
CUTE_UNROLL
|
| 210 |
+
for (int i = 0; i < size<1>(dst_c); ++i) {
|
| 211 |
+
copy_atom.call(src_c(_,i), dst_c(_,i));
|
| 212 |
+
}
|
| 213 |
+
} else {
|
| 214 |
+
CUTE_UNROLL
|
| 215 |
+
for (int i = 0; i < size<1>(dst_v); ++i) {
|
| 216 |
+
copy_atom.call(src_v(_,i), dst_v(_,i));
|
| 217 |
+
}
|
| 218 |
+
}
|
| 219 |
+
}
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
////////////////////////////////////////////////////////
|
| 223 |
+
// Special Auto-Vectorizing, Auto-Filtering Overloads //
|
| 224 |
+
////////////////////////////////////////////////////////
|
| 225 |
+
|
| 226 |
+
// Specialization for AutoVectorizingCopyAssumedAlignment<MaxVecBits>
|
| 227 |
+
template <int MaxVecBits, class... Args,
|
| 228 |
+
class SrcEngine, class SrcLayout,
|
| 229 |
+
class DstEngine, class DstLayout>
|
| 230 |
+
CUTE_HOST_DEVICE
|
| 231 |
+
void
|
| 232 |
+
copy(AutoVectorizingCopyWithAssumedAlignment<MaxVecBits> const&,
|
| 233 |
+
Tensor<SrcEngine, SrcLayout> const& src,
|
| 234 |
+
Tensor<DstEngine, DstLayout> & dst)
|
| 235 |
+
{
|
| 236 |
+
constexpr int common_elem = CUTE_STATIC_V(max_common_vector(src, dst));
|
| 237 |
+
constexpr int align_bits = CUTE_STATIC_V(gcd(max_alignment(src), max_alignment(dst), Int<MaxVecBits>{}));
|
| 238 |
+
static_assert(is_integral<decltype(Int<common_elem>{} * sizeof_bits_v<typename SrcEngine::value_type>)>::value, "Error: Attempting a subbit copy!");
|
| 239 |
+
constexpr int vec_bits = gcd(common_elem * sizeof_bits_v<typename SrcEngine::value_type>, align_bits);
|
| 240 |
+
|
| 241 |
+
if constexpr (common_elem > 1 && ((vec_bits % 8) == 0)) {
|
| 242 |
+
// If more than one element vectorizes to 8bits or more, then recast and copy
|
| 243 |
+
using VecType = uint_bit_t<vec_bits>;
|
| 244 |
+
// Preserve volatility
|
| 245 |
+
using SrcVecType = conditional_t<is_volatile_v<typename SrcEngine::element_type>, VecType const volatile, VecType const>;
|
| 246 |
+
using DstVecType = conditional_t<is_volatile_v<typename DstEngine::element_type>, VecType volatile, VecType >;
|
| 247 |
+
|
| 248 |
+
// Recast
|
| 249 |
+
Tensor src_v = recast<SrcVecType>(src);
|
| 250 |
+
Tensor dst_v = recast<DstVecType>(dst);
|
| 251 |
+
return copy_if(TrivialPredTensor{}, src_v, dst_v);
|
| 252 |
+
} else {
|
| 253 |
+
return copy_if(TrivialPredTensor{}, src, dst);
|
| 254 |
+
}
|
| 255 |
+
}
|
| 256 |
+
|
| 257 |
+
template <class Base>
|
| 258 |
+
struct AutoFilter {
|
| 259 |
+
Base const& base;
|
| 260 |
+
CUTE_HOST_DEVICE AutoFilter(Base const& b) : base(b) {}
|
| 261 |
+
};
|
| 262 |
+
|
| 263 |
+
// Specialization for AutoFilter
|
| 264 |
+
template <class CopyOp,
|
| 265 |
+
class SrcEngine, class SrcLayout,
|
| 266 |
+
class DstEngine, class DstLayout>
|
| 267 |
+
CUTE_HOST_DEVICE
|
| 268 |
+
void
|
| 269 |
+
copy(AutoFilter<CopyOp> const& copy_op,
|
| 270 |
+
Tensor<SrcEngine, SrcLayout> const& src,
|
| 271 |
+
Tensor<DstEngine, DstLayout> & dst)
|
| 272 |
+
{
|
| 273 |
+
if constexpr (is_constant<true, decltype(size(src) == size(dst))>::value) {
|
| 274 |
+
auto dst_null = nullspace(dst.layout());
|
| 275 |
+
|
| 276 |
+
Tensor dst_n = zipped_divide(dst, dst_null);
|
| 277 |
+
Tensor src_n = zipped_divide(src, dst_null);
|
| 278 |
+
|
| 279 |
+
CUTE_STATIC_ASSERT_V(cosize<0>(dst_n.layout()) == Int<1>{}, "Nullspace definition error");
|
| 280 |
+
CUTE_STATIC_ASSERT_V(cosize<0>(src_n.layout()) == Int<1>{}, "Error: Ambiguous scatter detected in copy");
|
| 281 |
+
|
| 282 |
+
copy(copy_op.base, src_n(Int<0>{},_), dst_n(Int<0>{},_));
|
| 283 |
+
} else {
|
| 284 |
+
copy(copy_op.base, src, dst);
|
| 285 |
+
}
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
// Auto-vectorizing copy for static layouts
|
| 289 |
+
template <class SrcEngine, class SrcLayout,
|
| 290 |
+
class DstEngine, class DstLayout>
|
| 291 |
+
CUTE_HOST_DEVICE
|
| 292 |
+
void
|
| 293 |
+
copy(Tensor<SrcEngine, SrcLayout> const& src,
|
| 294 |
+
Tensor<DstEngine, DstLayout> & dst)
|
| 295 |
+
{
|
| 296 |
+
if constexpr (is_static<SrcLayout>::value && is_static<DstLayout>::value) {
|
| 297 |
+
// Assume Tensors with static layouts (e.g. registers) have pointers that are 128b aligned
|
| 298 |
+
return copy(AutoFilter(AutoVectorizingCopyWithAssumedAlignment<128>{}), src, dst);
|
| 299 |
+
} else
|
| 300 |
+
if constexpr (is_static<decltype(shape(src))>::value && is_static<decltype(shape(dst))>::value) {
|
| 301 |
+
// Tensors with static shapes can be filtered, but do not assume that dynamic layouts are aligned.
|
| 302 |
+
return copy(AutoFilter(AutoVectorizingCopyWithAssumedAlignment<8>{}), src, dst);
|
| 303 |
+
} else {
|
| 304 |
+
// Do not assume that dynamic layouts are aligned.
|
| 305 |
+
return copy(AutoVectorizingCopyWithAssumedAlignment<8>{}, src, dst);
|
| 306 |
+
}
|
| 307 |
+
}
|
| 308 |
+
|
| 309 |
+
// Auto-vectorizing copy with assumed alignment up to 128bit.
|
| 310 |
+
template <class SrcEngine, class SrcLayout,
|
| 311 |
+
class DstEngine, class DstLayout>
|
| 312 |
+
CUTE_HOST_DEVICE
|
| 313 |
+
void
|
| 314 |
+
copy_aligned(Tensor<SrcEngine, SrcLayout> const& src,
|
| 315 |
+
Tensor<DstEngine, DstLayout> & dst)
|
| 316 |
+
{
|
| 317 |
+
if constexpr (is_static<decltype(shape(src))>::value && is_static<decltype(shape(dst))>::value) {
|
| 318 |
+
// Tensors with static shapes can be filtered
|
| 319 |
+
return copy(AutoFilter(AutoVectorizingCopyWithAssumedAlignment<128>{}), src, dst);
|
| 320 |
+
} else {
|
| 321 |
+
return copy(AutoVectorizingCopyWithAssumedAlignment<128>{}, src, dst);
|
| 322 |
+
}
|
| 323 |
+
}
|
| 324 |
+
|
| 325 |
+
// Specializaton for Atom AutoVectorizingCopyAssumedAlignment
|
| 326 |
+
template <int MaxVecBits, class... Args,
|
| 327 |
+
class SrcEngine, class SrcLayout,
|
| 328 |
+
class DstEngine, class DstLayout>
|
| 329 |
+
CUTE_HOST_DEVICE
|
| 330 |
+
void
|
| 331 |
+
copy(Copy_Atom<AutoVectorizingCopyWithAssumedAlignment<MaxVecBits>, Args...> const&,
|
| 332 |
+
Tensor<SrcEngine, SrcLayout> const& src,
|
| 333 |
+
Tensor<DstEngine, DstLayout> & dst)
|
| 334 |
+
{
|
| 335 |
+
return copy(AutoVectorizingCopyWithAssumedAlignment<MaxVecBits>{}, src, dst);
|
| 336 |
+
}
|
| 337 |
+
|
| 338 |
+
#if defined(CUTE_COPY_ATOM_TMA_SM90_ENABLED)
|
| 339 |
+
template <class... CT_Args,
|
| 340 |
+
class SrcEngine, class SrcLayout,
|
| 341 |
+
class DstEngine, class DstLayout>
|
| 342 |
+
CUTE_HOST_DEVICE
|
| 343 |
+
void
|
| 344 |
+
copy(Copy_Traits<SM90_BULK_COPY_AUTO, CT_Args...> const& atom, // Copy_Traits may or may not have the memory barrier in it already
|
| 345 |
+
Tensor<SrcEngine, SrcLayout> const& src,
|
| 346 |
+
Tensor<DstEngine, DstLayout> & dst)
|
| 347 |
+
{
|
| 348 |
+
using SrcType = typename SrcEngine::value_type;
|
| 349 |
+
using DstType = typename DstEngine::value_type;
|
| 350 |
+
static_assert(cute::is_same<SrcType, DstType>::value);
|
| 351 |
+
static_assert((is_gmem<SrcEngine>::value && is_smem<DstEngine>::value) ||
|
| 352 |
+
(is_smem<SrcEngine>::value && is_gmem<DstEngine>::value),
|
| 353 |
+
"Bulk Copy only supports gmem -> smem or smem -> gmem movement.");
|
| 354 |
+
// G2S or S2G dispatch
|
| 355 |
+
using BULK_COPY_OP = conditional_t<is_gmem<SrcEngine>::value,
|
| 356 |
+
SM90_BULK_COPY_G2S,
|
| 357 |
+
SM90_BULK_COPY_S2G>;
|
| 358 |
+
|
| 359 |
+
// Find the common subtensor of src and dst
|
| 360 |
+
auto tiler = max_common_layout(src, dst);
|
| 361 |
+
constexpr int vec_elem = decltype(size(tiler))::value;
|
| 362 |
+
constexpr int vec_bits = vec_elem * sizeof_bits_v<SrcType>;
|
| 363 |
+
static_assert(vec_bits >= 128, "Expected at least 128-bits for BLKCP");
|
| 364 |
+
|
| 365 |
+
// Construct a new concrete Atom of the vector size
|
| 366 |
+
using BulkAtom = Copy_Atom<Copy_Traits<BULK_COPY_OP, Int<vec_bits>, CT_Args...>, SrcType>;
|
| 367 |
+
auto bulk_atom = apply(atom.opargs_, [](auto const&... args) { return BulkAtom{args...}; });
|
| 368 |
+
return copy(bulk_atom, logical_divide(src, tiler), logical_divide(dst, tiler));
|
| 369 |
+
}
|
| 370 |
+
|
| 371 |
+
// Backwards-compat. Throw out any extra Copy_Atom args.
|
| 372 |
+
template <class... CT_Args, class... CA_Args,
|
| 373 |
+
class SrcEngine, class SrcLayout,
|
| 374 |
+
class DstEngine, class DstLayout>
|
| 375 |
+
CUTE_HOST_DEVICE
|
| 376 |
+
void
|
| 377 |
+
copy(Copy_Atom<Copy_Traits<SM90_BULK_COPY_AUTO, CT_Args...>, CA_Args...> const& atom,
|
| 378 |
+
Tensor<SrcEngine, SrcLayout> const& src,
|
| 379 |
+
Tensor<DstEngine, DstLayout> & dst)
|
| 380 |
+
{
|
| 381 |
+
return copy(static_cast<Copy_Traits<SM90_BULK_COPY_AUTO, CT_Args...> const&>(atom), src, dst);
|
| 382 |
+
}
|
| 383 |
+
#endif // #if defined(CUTE_COPY_ATOM_TMA_SM90_ENABLED)
|
| 384 |
+
|
| 385 |
+
//
|
| 386 |
+
// Decay TiledCopy to CopyAtom
|
| 387 |
+
//
|
| 388 |
+
|
| 389 |
+
template <class CopyAtom, class TV, class Tiler,
|
| 390 |
+
class PrdTensor,
|
| 391 |
+
class SrcEngine, class SrcLayout,
|
| 392 |
+
class DstEngine, class DstLayout>
|
| 393 |
+
CUTE_HOST_DEVICE
|
| 394 |
+
void
|
| 395 |
+
copy_if(TiledCopy<CopyAtom, TV, Tiler> const& tiled_copy,
|
| 396 |
+
PrdTensor const& pred,
|
| 397 |
+
Tensor<SrcEngine, SrcLayout> const& src,
|
| 398 |
+
Tensor<DstEngine, DstLayout> & dst)
|
| 399 |
+
{
|
| 400 |
+
return copy_if(static_cast<CopyAtom const&>(tiled_copy), pred, src, dst);
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
template <class CopyAtom, class TV, class Tiler,
|
| 404 |
+
class SrcEngine, class SrcLayout,
|
| 405 |
+
class DstEngine, class DstLayout>
|
| 406 |
+
CUTE_HOST_DEVICE
|
| 407 |
+
void
|
| 408 |
+
copy(TiledCopy<CopyAtom, TV, Tiler> const& tiled_copy,
|
| 409 |
+
Tensor<SrcEngine, SrcLayout> const& src,
|
| 410 |
+
Tensor<DstEngine, DstLayout> & dst)
|
| 411 |
+
{
|
| 412 |
+
return copy(static_cast<CopyAtom const&>(tiled_copy), src, dst);
|
| 413 |
+
}
|
| 414 |
+
|
| 415 |
+
template <class TiledCopy, class ThrIdx,
|
| 416 |
+
class PrdTensor,
|
| 417 |
+
class SrcEngine, class SrcLayout,
|
| 418 |
+
class DstEngine, class DstLayout>
|
| 419 |
+
CUTE_HOST_DEVICE
|
| 420 |
+
void
|
| 421 |
+
copy_if(ThrCopy<TiledCopy, ThrIdx> const& thr_copy,
|
| 422 |
+
PrdTensor const& pred,
|
| 423 |
+
Tensor<SrcEngine, SrcLayout> const& src,
|
| 424 |
+
Tensor<DstEngine, DstLayout> & dst) = delete;
|
| 425 |
+
|
| 426 |
+
template <class TiledCopy, class ThrIdx,
|
| 427 |
+
class SrcEngine, class SrcLayout,
|
| 428 |
+
class DstEngine, class DstLayout>
|
| 429 |
+
CUTE_HOST_DEVICE
|
| 430 |
+
void
|
| 431 |
+
copy(ThrCopy<TiledCopy, ThrIdx> const& thr_copy,
|
| 432 |
+
Tensor<SrcEngine, SrcLayout> const& src,
|
| 433 |
+
Tensor<DstEngine, DstLayout> & dst) = delete;
|
| 434 |
+
|
| 435 |
+
//
|
| 436 |
+
// Catch uncaught policies
|
| 437 |
+
//
|
| 438 |
+
|
| 439 |
+
template <class CopyPolicy,
|
| 440 |
+
class PredTensor,
|
| 441 |
+
class SrcEngine, class SrcLayout,
|
| 442 |
+
class DstEngine, class DstLayout>
|
| 443 |
+
CUTE_HOST_DEVICE
|
| 444 |
+
void
|
| 445 |
+
copy_if(CopyPolicy const& cpy,
|
| 446 |
+
PredTensor const& prd,
|
| 447 |
+
Tensor<SrcEngine, SrcLayout> const& src,
|
| 448 |
+
Tensor<DstEngine, DstLayout> & dst)
|
| 449 |
+
{
|
| 450 |
+
static_assert(dependent_false<CopyPolicy>, "Unrecognized CopyPolicy.");
|
| 451 |
+
}
|
| 452 |
+
|
| 453 |
+
template <class CopyPolicy,
|
| 454 |
+
class SrcEngine, class SrcLayout,
|
| 455 |
+
class DstEngine, class DstLayout>
|
| 456 |
+
CUTE_HOST_DEVICE
|
| 457 |
+
void
|
| 458 |
+
copy(CopyPolicy const& cpy,
|
| 459 |
+
Tensor<SrcEngine, SrcLayout> const& src,
|
| 460 |
+
Tensor<DstEngine, DstLayout> & dst)
|
| 461 |
+
{
|
| 462 |
+
static_assert(dependent_false<CopyPolicy>, "Unrecognized CopyPolicy.");
|
| 463 |
+
}
|
| 464 |
+
|
| 465 |
+
//
|
| 466 |
+
// Accept mutable temporaries
|
| 467 |
+
//
|
| 468 |
+
|
| 469 |
+
template <class PrdTensor,
|
| 470 |
+
class SrcEngine, class SrcLayout,
|
| 471 |
+
class DstEngine, class DstLayout>
|
| 472 |
+
CUTE_HOST_DEVICE
|
| 473 |
+
void
|
| 474 |
+
copy_if(PrdTensor const& pred,
|
| 475 |
+
Tensor<SrcEngine, SrcLayout> const& src,
|
| 476 |
+
Tensor<DstEngine, DstLayout> && dst)
|
| 477 |
+
{
|
| 478 |
+
return copy_if(pred, src, dst);
|
| 479 |
+
}
|
| 480 |
+
|
| 481 |
+
template <class CopyPolicy,
|
| 482 |
+
class PrdTensor,
|
| 483 |
+
class SrcEngine, class SrcLayout,
|
| 484 |
+
class DstEngine, class DstLayout>
|
| 485 |
+
CUTE_HOST_DEVICE
|
| 486 |
+
void
|
| 487 |
+
copy_if(CopyPolicy const& copy_policy,
|
| 488 |
+
PrdTensor const& pred,
|
| 489 |
+
Tensor<SrcEngine, SrcLayout> const& src,
|
| 490 |
+
Tensor<DstEngine, DstLayout> && dst)
|
| 491 |
+
{
|
| 492 |
+
return copy_if(copy_policy, pred, src, dst);
|
| 493 |
+
}
|
| 494 |
+
|
| 495 |
+
template <class SrcEngine, class SrcLayout,
|
| 496 |
+
class DstEngine, class DstLayout>
|
| 497 |
+
CUTE_HOST_DEVICE
|
| 498 |
+
void
|
| 499 |
+
copy(Tensor<SrcEngine, SrcLayout> const& src,
|
| 500 |
+
Tensor<DstEngine, DstLayout> && dst)
|
| 501 |
+
{
|
| 502 |
+
return copy(src, dst);
|
| 503 |
+
}
|
| 504 |
+
|
| 505 |
+
template <class CopyPolicy,
|
| 506 |
+
class SrcEngine, class SrcLayout,
|
| 507 |
+
class DstEngine, class DstLayout>
|
| 508 |
+
CUTE_HOST_DEVICE
|
| 509 |
+
void
|
| 510 |
+
copy(CopyPolicy const& copy_policy,
|
| 511 |
+
Tensor<SrcEngine, SrcLayout> const& src,
|
| 512 |
+
Tensor<DstEngine, DstLayout> && dst)
|
| 513 |
+
{
|
| 514 |
+
return copy(copy_policy, src, dst);
|
| 515 |
+
}
|
| 516 |
+
|
| 517 |
+
template <class SrcEngine, class SrcLayout,
|
| 518 |
+
class DstEngine, class DstLayout>
|
| 519 |
+
CUTE_HOST_DEVICE
|
| 520 |
+
void
|
| 521 |
+
copy_aligned(Tensor<SrcEngine, SrcLayout> const& src,
|
| 522 |
+
Tensor<DstEngine, DstLayout> && dst)
|
| 523 |
+
{
|
| 524 |
+
return copy_aligned(src, dst);
|
| 525 |
+
}
|
| 526 |
+
|
| 527 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/fill.hpp
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/config.hpp>
|
| 34 |
+
|
| 35 |
+
#include <cute/tensor_impl.hpp>
|
| 36 |
+
#include <cute/algorithm/prefer.hpp>
|
| 37 |
+
|
| 38 |
+
namespace cute
|
| 39 |
+
{
|
| 40 |
+
|
| 41 |
+
//
|
| 42 |
+
// Accept mutable temporaries
|
| 43 |
+
//
|
| 44 |
+
template <class Engine, class Layout, class T>
|
| 45 |
+
CUTE_HOST_DEVICE
|
| 46 |
+
void
|
| 47 |
+
fill(Tensor<Engine, Layout>&& tensor, T const& value)
|
| 48 |
+
{
|
| 49 |
+
return fill(tensor, value);
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
namespace detail
|
| 53 |
+
{
|
| 54 |
+
|
| 55 |
+
// Prefer fill(tensor.data(), value), if possible
|
| 56 |
+
template <class Engine, class Layout, class T>
|
| 57 |
+
CUTE_HOST_DEVICE
|
| 58 |
+
auto
|
| 59 |
+
fill(Tensor<Engine, Layout>& tensor, T const& value, prefer<1>)
|
| 60 |
+
-> decltype(fill(tensor.data(), value))
|
| 61 |
+
{
|
| 62 |
+
fill(tensor.data(), value);
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
// Default implementation
|
| 66 |
+
template <class Engine, class Layout, class T>
|
| 67 |
+
CUTE_HOST_DEVICE
|
| 68 |
+
void
|
| 69 |
+
fill(Tensor<Engine, Layout>& tensor, T const& value, prefer<0>)
|
| 70 |
+
{
|
| 71 |
+
CUTE_UNROLL
|
| 72 |
+
for (int i = 0; i < size(tensor); ++i) {
|
| 73 |
+
tensor(i) = value;
|
| 74 |
+
}
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
} // end namespace detail
|
| 78 |
+
|
| 79 |
+
template <class Engine, class Layout, class T>
|
| 80 |
+
CUTE_HOST_DEVICE
|
| 81 |
+
void
|
| 82 |
+
fill(Tensor<Engine, Layout>& tensor, T const& value)
|
| 83 |
+
{
|
| 84 |
+
return detail::fill(tensor, value, prefer<1>{});
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/functional.hpp
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/config.hpp> // CUTE_HOST_DEVICE
|
| 34 |
+
#include <cute/numeric/math.hpp> // cute::max, cute::min
|
| 35 |
+
#include <cute/numeric/complex.hpp> // cute::conj
|
| 36 |
+
|
| 37 |
+
/** C++14 <functional> extensions */
|
| 38 |
+
|
| 39 |
+
namespace cute {
|
| 40 |
+
|
| 41 |
+
/**************/
|
| 42 |
+
/** Identity **/
|
| 43 |
+
/**************/
|
| 44 |
+
|
| 45 |
+
struct identity {
|
| 46 |
+
template <class T>
|
| 47 |
+
CUTE_HOST_DEVICE constexpr
|
| 48 |
+
decltype(auto) operator()(T&& arg) const {
|
| 49 |
+
return static_cast<T&&>(arg);
|
| 50 |
+
}
|
| 51 |
+
};
|
| 52 |
+
|
| 53 |
+
template <class R>
|
| 54 |
+
struct constant_fn {
|
| 55 |
+
template <class... T>
|
| 56 |
+
CUTE_HOST_DEVICE constexpr
|
| 57 |
+
decltype(auto) operator()(T&&...) const {
|
| 58 |
+
return r_;
|
| 59 |
+
}
|
| 60 |
+
R r_;
|
| 61 |
+
};
|
| 62 |
+
|
| 63 |
+
/***********/
|
| 64 |
+
/** Unary **/
|
| 65 |
+
/***********/
|
| 66 |
+
|
| 67 |
+
#define CUTE_LEFT_UNARY_OP(NAME,OP) \
|
| 68 |
+
struct NAME { \
|
| 69 |
+
template <class T> \
|
| 70 |
+
CUTE_HOST_DEVICE constexpr \
|
| 71 |
+
decltype(auto) operator()(T&& arg) const { \
|
| 72 |
+
return OP static_cast<T&&>(arg); \
|
| 73 |
+
} \
|
| 74 |
+
}
|
| 75 |
+
#define CUTE_RIGHT_UNARY_OP(NAME,OP) \
|
| 76 |
+
struct NAME { \
|
| 77 |
+
template <class T> \
|
| 78 |
+
CUTE_HOST_DEVICE constexpr \
|
| 79 |
+
decltype(auto) operator()(T&& arg) const { \
|
| 80 |
+
return static_cast<T&&>(arg) OP ; \
|
| 81 |
+
} \
|
| 82 |
+
}
|
| 83 |
+
#define CUTE_NAMED_UNARY_OP(NAME,OP) \
|
| 84 |
+
struct NAME { \
|
| 85 |
+
template <class T> \
|
| 86 |
+
CUTE_HOST_DEVICE constexpr \
|
| 87 |
+
decltype(auto) operator()(T&& arg) const { \
|
| 88 |
+
return OP (static_cast<T&&>(arg)); \
|
| 89 |
+
} \
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
CUTE_LEFT_UNARY_OP(unary_plus, +);
|
| 93 |
+
CUTE_LEFT_UNARY_OP(negate, -);
|
| 94 |
+
CUTE_LEFT_UNARY_OP(bit_not, ~);
|
| 95 |
+
CUTE_LEFT_UNARY_OP(logical_not, !);
|
| 96 |
+
CUTE_LEFT_UNARY_OP(dereference, *);
|
| 97 |
+
CUTE_LEFT_UNARY_OP(address_of, &);
|
| 98 |
+
CUTE_LEFT_UNARY_OP(pre_increment, ++);
|
| 99 |
+
CUTE_LEFT_UNARY_OP(pre_decrement, --);
|
| 100 |
+
|
| 101 |
+
CUTE_RIGHT_UNARY_OP(post_increment, ++);
|
| 102 |
+
CUTE_RIGHT_UNARY_OP(post_decrement, --);
|
| 103 |
+
|
| 104 |
+
CUTE_NAMED_UNARY_OP(abs_fn, abs);
|
| 105 |
+
CUTE_NAMED_UNARY_OP(conjugate, cute::conj);
|
| 106 |
+
|
| 107 |
+
#undef CUTE_LEFT_UNARY_OP
|
| 108 |
+
#undef CUTE_RIGHT_UNARY_OP
|
| 109 |
+
#undef CUTE_NAMED_UNARY_OP
|
| 110 |
+
|
| 111 |
+
template <int Shift_>
|
| 112 |
+
struct shift_right_const {
|
| 113 |
+
static constexpr int Shift = Shift_;
|
| 114 |
+
|
| 115 |
+
template <class T>
|
| 116 |
+
CUTE_HOST_DEVICE constexpr
|
| 117 |
+
decltype(auto) operator()(T&& arg) const {
|
| 118 |
+
return static_cast<T&&>(arg) >> Shift;
|
| 119 |
+
}
|
| 120 |
+
};
|
| 121 |
+
|
| 122 |
+
template <int Shift_>
|
| 123 |
+
struct shift_left_const {
|
| 124 |
+
static constexpr int Shift = Shift_;
|
| 125 |
+
|
| 126 |
+
template <class T>
|
| 127 |
+
CUTE_HOST_DEVICE constexpr
|
| 128 |
+
decltype(auto) operator()(T&& arg) const {
|
| 129 |
+
return static_cast<T&&>(arg) << Shift;
|
| 130 |
+
}
|
| 131 |
+
};
|
| 132 |
+
|
| 133 |
+
/************/
|
| 134 |
+
/** Binary **/
|
| 135 |
+
/************/
|
| 136 |
+
|
| 137 |
+
#define CUTE_BINARY_OP(NAME,OP) \
|
| 138 |
+
struct NAME { \
|
| 139 |
+
template <class T, class U> \
|
| 140 |
+
CUTE_HOST_DEVICE constexpr \
|
| 141 |
+
decltype(auto) operator()(T&& lhs, U&& rhs) const { \
|
| 142 |
+
return static_cast<T&&>(lhs) OP static_cast<U&&>(rhs); \
|
| 143 |
+
} \
|
| 144 |
+
}
|
| 145 |
+
#define CUTE_NAMED_BINARY_OP(NAME,OP) \
|
| 146 |
+
struct NAME { \
|
| 147 |
+
template <class T, class U> \
|
| 148 |
+
CUTE_HOST_DEVICE constexpr \
|
| 149 |
+
decltype(auto) operator()(T&& lhs, U&& rhs) const { \
|
| 150 |
+
return OP (static_cast<T&&>(lhs), static_cast<U&&>(rhs)); \
|
| 151 |
+
} \
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
CUTE_BINARY_OP(plus, +);
|
| 156 |
+
CUTE_BINARY_OP(minus, -);
|
| 157 |
+
CUTE_BINARY_OP(multiplies, *);
|
| 158 |
+
CUTE_BINARY_OP(divides, /);
|
| 159 |
+
CUTE_BINARY_OP(modulus, %);
|
| 160 |
+
|
| 161 |
+
CUTE_BINARY_OP(plus_assign, +=);
|
| 162 |
+
CUTE_BINARY_OP(minus_assign, -=);
|
| 163 |
+
CUTE_BINARY_OP(multiplies_assign, *=);
|
| 164 |
+
CUTE_BINARY_OP(divides_assign, /=);
|
| 165 |
+
CUTE_BINARY_OP(modulus_assign, %=);
|
| 166 |
+
|
| 167 |
+
CUTE_BINARY_OP(bit_and, &);
|
| 168 |
+
CUTE_BINARY_OP(bit_or, |);
|
| 169 |
+
CUTE_BINARY_OP(bit_xor, ^);
|
| 170 |
+
CUTE_BINARY_OP(left_shift, <<);
|
| 171 |
+
CUTE_BINARY_OP(right_shift, >>);
|
| 172 |
+
|
| 173 |
+
CUTE_BINARY_OP(bit_and_assign, &=);
|
| 174 |
+
CUTE_BINARY_OP(bit_or_assign, |=);
|
| 175 |
+
CUTE_BINARY_OP(bit_xor_assign, ^=);
|
| 176 |
+
CUTE_BINARY_OP(left_shift_assign, <<=);
|
| 177 |
+
CUTE_BINARY_OP(right_shift_assign, >>=);
|
| 178 |
+
|
| 179 |
+
CUTE_BINARY_OP(logical_and, &&);
|
| 180 |
+
CUTE_BINARY_OP(logical_or, ||);
|
| 181 |
+
|
| 182 |
+
CUTE_BINARY_OP(equal_to, ==);
|
| 183 |
+
CUTE_BINARY_OP(not_equal_to, !=);
|
| 184 |
+
CUTE_BINARY_OP(greater, >);
|
| 185 |
+
CUTE_BINARY_OP(less, <);
|
| 186 |
+
CUTE_BINARY_OP(greater_equal, >=);
|
| 187 |
+
CUTE_BINARY_OP(less_equal, <=);
|
| 188 |
+
|
| 189 |
+
CUTE_NAMED_BINARY_OP(max_fn, cute::max);
|
| 190 |
+
CUTE_NAMED_BINARY_OP(min_fn, cute::min);
|
| 191 |
+
|
| 192 |
+
#undef CUTE_BINARY_OP
|
| 193 |
+
#undef CUTE_NAMED_BINARY_OP
|
| 194 |
+
|
| 195 |
+
/**********/
|
| 196 |
+
/** Fold **/
|
| 197 |
+
/**********/
|
| 198 |
+
|
| 199 |
+
#define CUTE_FOLD_OP(NAME,OP) \
|
| 200 |
+
struct NAME##_unary_rfold { \
|
| 201 |
+
template <class... T> \
|
| 202 |
+
CUTE_HOST_DEVICE constexpr \
|
| 203 |
+
auto operator()(T&&... t) const { \
|
| 204 |
+
return (t OP ...); \
|
| 205 |
+
} \
|
| 206 |
+
}; \
|
| 207 |
+
struct NAME##_unary_lfold { \
|
| 208 |
+
template <class... T> \
|
| 209 |
+
CUTE_HOST_DEVICE constexpr \
|
| 210 |
+
auto operator()(T&&... t) const { \
|
| 211 |
+
return (... OP t); \
|
| 212 |
+
} \
|
| 213 |
+
}; \
|
| 214 |
+
struct NAME##_binary_rfold { \
|
| 215 |
+
template <class U, class... T> \
|
| 216 |
+
CUTE_HOST_DEVICE constexpr \
|
| 217 |
+
auto operator()(U&& u, T&&... t) const { \
|
| 218 |
+
return (t OP ... OP u); \
|
| 219 |
+
} \
|
| 220 |
+
}; \
|
| 221 |
+
struct NAME##_binary_lfold { \
|
| 222 |
+
template <class U, class... T> \
|
| 223 |
+
CUTE_HOST_DEVICE constexpr \
|
| 224 |
+
auto operator()(U&& u, T&&... t) const { \
|
| 225 |
+
return (u OP ... OP t); \
|
| 226 |
+
} \
|
| 227 |
+
}
|
| 228 |
+
|
| 229 |
+
CUTE_FOLD_OP(plus, +);
|
| 230 |
+
CUTE_FOLD_OP(minus, -);
|
| 231 |
+
CUTE_FOLD_OP(multiplies, *);
|
| 232 |
+
CUTE_FOLD_OP(divides, /);
|
| 233 |
+
CUTE_FOLD_OP(modulus, %);
|
| 234 |
+
|
| 235 |
+
CUTE_FOLD_OP(plus_assign, +=);
|
| 236 |
+
CUTE_FOLD_OP(minus_assign, -=);
|
| 237 |
+
CUTE_FOLD_OP(multiplies_assign, *=);
|
| 238 |
+
CUTE_FOLD_OP(divides_assign, /=);
|
| 239 |
+
CUTE_FOLD_OP(modulus_assign, %=);
|
| 240 |
+
|
| 241 |
+
CUTE_FOLD_OP(bit_and, &);
|
| 242 |
+
CUTE_FOLD_OP(bit_or, |);
|
| 243 |
+
CUTE_FOLD_OP(bit_xor, ^);
|
| 244 |
+
CUTE_FOLD_OP(left_shift, <<);
|
| 245 |
+
CUTE_FOLD_OP(right_shift, >>);
|
| 246 |
+
|
| 247 |
+
CUTE_FOLD_OP(bit_and_assign, &=);
|
| 248 |
+
CUTE_FOLD_OP(bit_or_assign, |=);
|
| 249 |
+
CUTE_FOLD_OP(bit_xor_assign, ^=);
|
| 250 |
+
CUTE_FOLD_OP(left_shift_assign, <<=);
|
| 251 |
+
CUTE_FOLD_OP(right_shift_assign, >>=);
|
| 252 |
+
|
| 253 |
+
CUTE_FOLD_OP(logical_and, &&);
|
| 254 |
+
CUTE_FOLD_OP(logical_or, ||);
|
| 255 |
+
|
| 256 |
+
CUTE_FOLD_OP(equal_to, ==);
|
| 257 |
+
CUTE_FOLD_OP(not_equal_to, !=);
|
| 258 |
+
CUTE_FOLD_OP(greater, >);
|
| 259 |
+
CUTE_FOLD_OP(less, <);
|
| 260 |
+
CUTE_FOLD_OP(greater_equal, >=);
|
| 261 |
+
CUTE_FOLD_OP(less_equal, <=);
|
| 262 |
+
|
| 263 |
+
#undef CUTE_FOLD_OP
|
| 264 |
+
|
| 265 |
+
/**********/
|
| 266 |
+
/** Meta **/
|
| 267 |
+
/**********/
|
| 268 |
+
|
| 269 |
+
template <class Fn, class Arg>
|
| 270 |
+
struct bound_fn {
|
| 271 |
+
|
| 272 |
+
template <class T>
|
| 273 |
+
CUTE_HOST_DEVICE constexpr
|
| 274 |
+
decltype(auto)
|
| 275 |
+
operator()(T&& arg) {
|
| 276 |
+
return fn_(arg_, static_cast<T&&>(arg));
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
Fn fn_;
|
| 280 |
+
Arg arg_;
|
| 281 |
+
};
|
| 282 |
+
|
| 283 |
+
template <class Fn, class Arg>
|
| 284 |
+
CUTE_HOST_DEVICE constexpr
|
| 285 |
+
auto
|
| 286 |
+
bind(Fn const& fn, Arg const& arg) {
|
| 287 |
+
return bound_fn<Fn,Arg>{fn, arg};
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/gemm.hpp
ADDED
|
@@ -0,0 +1,500 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/config.hpp>
|
| 34 |
+
|
| 35 |
+
#include <cute/util/type_traits.hpp>
|
| 36 |
+
#include <cute/algorithm/functional.hpp>
|
| 37 |
+
|
| 38 |
+
#include <cute/tensor_impl.hpp>
|
| 39 |
+
|
| 40 |
+
#include <cute/atom/mma_atom.hpp>
|
| 41 |
+
|
| 42 |
+
/** The gemm algorithm takes four (or three) tensors and computes
|
| 43 |
+
* D = A * B + C
|
| 44 |
+
* It dispatches based on the number of modes each tensor has:
|
| 45 |
+
*
|
| 46 |
+
* 1. `(V) x (V) => (V)`.
|
| 47 |
+
* The element-wise product of vectors. Dispatches to FMA or MMA.
|
| 48 |
+
* 2. `(M) x (N) => (M,N)`.
|
| 49 |
+
* The outer product of vectors. Dispatches to [3] with new mode K=(1).
|
| 50 |
+
* 3. `(M,K) x (N,K) => (M,N)`.
|
| 51 |
+
* The product of matrices. Dispatches to [5] with MMA vector-mode V.
|
| 52 |
+
* 4. `(V,M) x (V,N) => (V,M,N)`.
|
| 53 |
+
* The batched outer product of vectors. Accounts for register reuse and dispatches to [1] for each (m,n).
|
| 54 |
+
* 5. `(V,M,K) x (V,N,K) => (V,M,N)`.
|
| 55 |
+
* The batched product of matrices. Dispatches to [4] for each (k).
|
| 56 |
+
*/
|
| 57 |
+
|
| 58 |
+
namespace cute
|
| 59 |
+
{
|
| 60 |
+
|
| 61 |
+
//
|
| 62 |
+
// Three arguments to four
|
| 63 |
+
//
|
| 64 |
+
|
| 65 |
+
template <class TA, class ALayout,
|
| 66 |
+
class TB, class BLayout,
|
| 67 |
+
class TC, class CLayout>
|
| 68 |
+
CUTE_HOST_DEVICE
|
| 69 |
+
void
|
| 70 |
+
gemm(Tensor<TA, ALayout> const& A,
|
| 71 |
+
Tensor<TB, BLayout> const& B,
|
| 72 |
+
Tensor<TC, CLayout> & C)
|
| 73 |
+
{
|
| 74 |
+
return gemm(C, A, B, C);
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
template <class MMA,
|
| 78 |
+
class TA, class ALayout,
|
| 79 |
+
class TB, class BLayout,
|
| 80 |
+
class TC, class CLayout>
|
| 81 |
+
CUTE_HOST_DEVICE
|
| 82 |
+
void
|
| 83 |
+
gemm(MMA_Atom<MMA> const& mma,
|
| 84 |
+
Tensor<TA, ALayout> const& A,
|
| 85 |
+
Tensor<TB, BLayout> const& B,
|
| 86 |
+
Tensor<TC, CLayout> & C)
|
| 87 |
+
{
|
| 88 |
+
return gemm(mma, C, A, B, C);
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
//
|
| 92 |
+
// Accept mutable temporaries
|
| 93 |
+
//
|
| 94 |
+
|
| 95 |
+
template <class TA, class ALayout,
|
| 96 |
+
class TB, class BLayout,
|
| 97 |
+
class TC, class CLayout>
|
| 98 |
+
CUTE_HOST_DEVICE
|
| 99 |
+
void
|
| 100 |
+
gemm(Tensor<TA, ALayout> const& A,
|
| 101 |
+
Tensor<TB, BLayout> const& B,
|
| 102 |
+
Tensor<TC, CLayout> && C)
|
| 103 |
+
{
|
| 104 |
+
return gemm(C, A, B, C);
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
template <class TD, class DLayout,
|
| 108 |
+
class TA, class ALayout,
|
| 109 |
+
class TB, class BLayout,
|
| 110 |
+
class TC, class CLayout>
|
| 111 |
+
CUTE_HOST_DEVICE
|
| 112 |
+
void
|
| 113 |
+
gemm(Tensor<TD, DLayout> && D,
|
| 114 |
+
Tensor<TA, ALayout> const& A,
|
| 115 |
+
Tensor<TB, BLayout> const& B,
|
| 116 |
+
Tensor<TC, CLayout> const& C)
|
| 117 |
+
{
|
| 118 |
+
return gemm(D, A, B, C);
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
template <class MMA,
|
| 122 |
+
class TA, class ALayout,
|
| 123 |
+
class TB, class BLayout,
|
| 124 |
+
class TC, class CLayout>
|
| 125 |
+
CUTE_HOST_DEVICE
|
| 126 |
+
void
|
| 127 |
+
gemm(MMA_Atom<MMA> const& mma,
|
| 128 |
+
Tensor<TA, ALayout> const& A,
|
| 129 |
+
Tensor<TB, BLayout> const& B,
|
| 130 |
+
Tensor<TC, CLayout> && C)
|
| 131 |
+
{
|
| 132 |
+
return gemm(mma, C, A, B, C);
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
template <class MMA,
|
| 136 |
+
class TD, class DLayout,
|
| 137 |
+
class TA, class ALayout,
|
| 138 |
+
class TB, class BLayout,
|
| 139 |
+
class TC, class CLayout>
|
| 140 |
+
CUTE_HOST_DEVICE
|
| 141 |
+
void
|
| 142 |
+
gemm(MMA_Atom<MMA> const& mma,
|
| 143 |
+
Tensor<TD, DLayout> && D,
|
| 144 |
+
Tensor<TA, ALayout> const& A,
|
| 145 |
+
Tensor<TB, BLayout> const& B,
|
| 146 |
+
Tensor<TC, CLayout> const& C)
|
| 147 |
+
{
|
| 148 |
+
return gemm(mma, D, A, B, C);
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
//
|
| 152 |
+
// Default MMA is UniversalFMA
|
| 153 |
+
//
|
| 154 |
+
|
| 155 |
+
template <class TD, class DLayout,
|
| 156 |
+
class TA, class ALayout,
|
| 157 |
+
class TB, class BLayout,
|
| 158 |
+
class TC, class CLayout>
|
| 159 |
+
CUTE_HOST_DEVICE
|
| 160 |
+
void
|
| 161 |
+
gemm(Tensor<TD, DLayout> & D,
|
| 162 |
+
Tensor<TA, ALayout> const& A,
|
| 163 |
+
Tensor<TB, BLayout> const& B,
|
| 164 |
+
Tensor<TC, CLayout> const& C)
|
| 165 |
+
{
|
| 166 |
+
using MMA = MMA_Atom<UniversalFMA<typename Tensor<TD,DLayout>::value_type,
|
| 167 |
+
typename Tensor<TA,ALayout>::value_type,
|
| 168 |
+
typename Tensor<TB,BLayout>::value_type,
|
| 169 |
+
typename Tensor<TC,CLayout>::value_type>>;
|
| 170 |
+
|
| 171 |
+
return gemm(MMA{}, D, A, B, C);
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
//
|
| 175 |
+
// Thread-Local Register-Memory GEMMs
|
| 176 |
+
//
|
| 177 |
+
|
| 178 |
+
// Dispatch [1]: (V) x (V) => (V)
|
| 179 |
+
template <class MMA,
|
| 180 |
+
class TD, class DLayout,
|
| 181 |
+
class TA, class ALayout,
|
| 182 |
+
class TB, class BLayout,
|
| 183 |
+
class TC, class CLayout,
|
| 184 |
+
__CUTE_REQUIRES(DLayout::rank == 1 && is_rmem<TD>::value &&
|
| 185 |
+
ALayout::rank == 1 && is_rmem<TA>::value &&
|
| 186 |
+
BLayout::rank == 1 && is_rmem<TB>::value &&
|
| 187 |
+
CLayout::rank == 1 && is_rmem<TC>::value)>
|
| 188 |
+
CUTE_HOST_DEVICE
|
| 189 |
+
void
|
| 190 |
+
gemm(MMA_Atom<MMA> const& mma,
|
| 191 |
+
Tensor<TD, DLayout> & D, // (V) Logical data
|
| 192 |
+
Tensor<TA, ALayout> const& A, // (V) Logical data
|
| 193 |
+
Tensor<TB, BLayout> const& B, // (V) Logical data
|
| 194 |
+
Tensor<TC, CLayout> const& C) // (V) Logical data
|
| 195 |
+
{
|
| 196 |
+
// No static assertions on (V), MMA checks compatibility
|
| 197 |
+
mma.call(D, A, B, C);
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
// Dispatch [2]: (M) x (N) => (M,N)
|
| 201 |
+
template <class MMA,
|
| 202 |
+
class TD, class DLayout,
|
| 203 |
+
class TA, class ALayout,
|
| 204 |
+
class TB, class BLayout,
|
| 205 |
+
class TC, class CLayout,
|
| 206 |
+
__CUTE_REQUIRES(DLayout::rank == 2 && is_rmem<TD>::value &&
|
| 207 |
+
ALayout::rank == 1 && is_rmem<TA>::value &&
|
| 208 |
+
BLayout::rank == 1 && is_rmem<TB>::value &&
|
| 209 |
+
CLayout::rank == 2 && is_rmem<TC>::value)>
|
| 210 |
+
CUTE_HOST_DEVICE
|
| 211 |
+
void
|
| 212 |
+
gemm(MMA_Atom<MMA> const& mma,
|
| 213 |
+
Tensor<TD, DLayout> & D, // (M,N) Logical data
|
| 214 |
+
Tensor<TA, ALayout> const& A, // (M) Logical data
|
| 215 |
+
Tensor<TB, BLayout> const& B, // (N) Logical data
|
| 216 |
+
Tensor<TC, CLayout> const& C) // (M,N) Logical data
|
| 217 |
+
{
|
| 218 |
+
CUTE_STATIC_ASSERT_V(size<0>(A) == size<0>(C)); // AM == CM
|
| 219 |
+
CUTE_STATIC_ASSERT_V(size<0>(B) == size<1>(C)); // BN == CN
|
| 220 |
+
CUTE_STATIC_ASSERT_V(size<0>(C) == size<0>(D) && size<1>(C) == size<1>(D));
|
| 221 |
+
gemm(mma,
|
| 222 |
+
D, // (M,N)
|
| 223 |
+
make_tensor(A.data(), append<2>(A.layout())), // (M,1)
|
| 224 |
+
make_tensor(B.data(), append<2>(B.layout())), // (N,1)
|
| 225 |
+
C); // (M,N)
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
// Dispatch [3]: (M,K) x (N,K) => (M,N)
|
| 229 |
+
template <class MMA,
|
| 230 |
+
class TD, class DLayout,
|
| 231 |
+
class TA, class ALayout,
|
| 232 |
+
class TB, class BLayout,
|
| 233 |
+
class TC, class CLayout,
|
| 234 |
+
__CUTE_REQUIRES(DLayout::rank == 2 && is_rmem<TD>::value &&
|
| 235 |
+
ALayout::rank == 2 && is_rmem<TA>::value &&
|
| 236 |
+
BLayout::rank == 2 && is_rmem<TB>::value &&
|
| 237 |
+
CLayout::rank == 2 && is_rmem<TC>::value)>
|
| 238 |
+
CUTE_HOST_DEVICE
|
| 239 |
+
void
|
| 240 |
+
gemm(MMA_Atom<MMA> const& mma,
|
| 241 |
+
Tensor<TD, DLayout> & D, // (M,N) Logical data
|
| 242 |
+
Tensor<TA, ALayout> const& A, // (M,K) Logical data
|
| 243 |
+
Tensor<TB, BLayout> const& B, // (N,K) Logical data
|
| 244 |
+
Tensor<TC, CLayout> const& C) // (M,N) Logical data
|
| 245 |
+
{
|
| 246 |
+
CUTE_STATIC_ASSERT_V(size<0>(A) == size<0>(C)); // AM == CM
|
| 247 |
+
CUTE_STATIC_ASSERT_V(size<0>(B) == size<1>(C)); // BN == CN
|
| 248 |
+
CUTE_STATIC_ASSERT_V(size<1>(A) == size<1>(B)); // AK == BK
|
| 249 |
+
CUTE_STATIC_ASSERT_V(size<0>(C) == size<0>(D) && size<1>(C) == size<1>(D));
|
| 250 |
+
|
| 251 |
+
// Assert this is a 1-value MMA
|
| 252 |
+
CUTE_STATIC_ASSERT_V(size<1>(typename MMA_Atom<MMA>::LayoutC_TV{}) == Int<1>{});
|
| 253 |
+
CUTE_STATIC_ASSERT_V(size<1>(typename MMA_Atom<MMA>::LayoutA_TV{}) == Int<1>{});
|
| 254 |
+
CUTE_STATIC_ASSERT_V(size<1>(typename MMA_Atom<MMA>::LayoutB_TV{}) == Int<1>{});
|
| 255 |
+
|
| 256 |
+
gemm(mma,
|
| 257 |
+
make_tensor(D.data(), prepend<3>(D.layout())), // (1,M,N)
|
| 258 |
+
make_tensor(A.data(), prepend<3>(A.layout())), // (1,M,K)
|
| 259 |
+
make_tensor(B.data(), prepend<3>(B.layout())), // (1,N,K)
|
| 260 |
+
make_tensor(C.data(), prepend<3>(C.layout()))); // (1,M,N)
|
| 261 |
+
}
|
| 262 |
+
|
| 263 |
+
// Dispatch [4]: (V,M) x (V,N) => (V,M,N)
|
| 264 |
+
template <class MMA,
|
| 265 |
+
class TD, class DLayout,
|
| 266 |
+
class TA, class ALayout,
|
| 267 |
+
class TB, class BLayout,
|
| 268 |
+
class TC, class CLayout,
|
| 269 |
+
__CUTE_REQUIRES(DLayout::rank == 3 && is_rmem<TD>::value &&
|
| 270 |
+
ALayout::rank == 2 && is_rmem<TA>::value &&
|
| 271 |
+
BLayout::rank == 2 && is_rmem<TB>::value &&
|
| 272 |
+
CLayout::rank == 3 && is_rmem<TC>::value)>
|
| 273 |
+
CUTE_HOST_DEVICE
|
| 274 |
+
void
|
| 275 |
+
gemm(MMA_Atom<MMA> const& mma,
|
| 276 |
+
Tensor<TD, DLayout> & D, // (V,M,N) Logical data
|
| 277 |
+
Tensor<TA, ALayout> const& A, // (V,M) Logical data
|
| 278 |
+
Tensor<TB, BLayout> const& B, // (V,N) Logical data
|
| 279 |
+
Tensor<TC, CLayout> const& C) // (V,M,N) Logical data
|
| 280 |
+
{
|
| 281 |
+
CUTE_STATIC_ASSERT_V(size<1>(A) == size<1>(C)); // AM == CM
|
| 282 |
+
CUTE_STATIC_ASSERT_V(size<1>(B) == size<2>(C)); // BN == CN
|
| 283 |
+
CUTE_STATIC_ASSERT_V(size<0>(C) == size<0>(D) && size<1>(C) == size<1>(D) && size<2>(C) == size<2>(D));
|
| 284 |
+
auto M = size<1>(A);
|
| 285 |
+
auto N = size<1>(B);
|
| 286 |
+
// REGISTER .reuse OPTIMIZATIONS
|
| 287 |
+
// 64-bit traversal specialization -- serpentine path
|
| 288 |
+
if constexpr (decltype(size<0>(A))::value * sizeof(typename TA::value_type) == 8 &&
|
| 289 |
+
decltype(size<0>(B))::value * sizeof(typename TB::value_type) == 8)
|
| 290 |
+
{
|
| 291 |
+
#if 1 // NOTE: Row- vs Col- major could depend on the C-matrix order... (which we can test)
|
| 292 |
+
// Row-major serpentine iteration
|
| 293 |
+
CUTE_UNROLL
|
| 294 |
+
for (int m = 0; m < M; ++m) {
|
| 295 |
+
CUTE_UNROLL
|
| 296 |
+
for (int n = 0; n < N; ++n) {
|
| 297 |
+
int ns = (m & 1) ? N-1-n : n; // Serpentine coordinate
|
| 298 |
+
gemm(mma, D(_,m,ns), A(_,m), B(_,ns), C(_,m,ns));
|
| 299 |
+
}
|
| 300 |
+
}
|
| 301 |
+
#else
|
| 302 |
+
// Col-major serpentine iteration
|
| 303 |
+
CUTE_UNROLL
|
| 304 |
+
for (int n = 0; n < N; ++n) {
|
| 305 |
+
CUTE_UNROLL
|
| 306 |
+
for (int m = 0; m < M; ++m) {
|
| 307 |
+
int ms = (n & 1) ? M-1-m : m; // Serpentine coordinate
|
| 308 |
+
gemm(mma, D(_,ms,n), A(_,ms), B(_,n), C(_,ms,n));
|
| 309 |
+
}
|
| 310 |
+
}
|
| 311 |
+
#endif
|
| 312 |
+
} else
|
| 313 |
+
// 32-bit traversal specialization -- kinked serpentine path
|
| 314 |
+
if constexpr (decltype(size<0>(A))::value * sizeof(typename TA::value_type) == 4 &&
|
| 315 |
+
decltype(size<0>(B))::value * sizeof(typename TB::value_type) == 4)
|
| 316 |
+
{
|
| 317 |
+
#if 1 // NOTE: Row- vs Col- major could depend on the C-matrix order... (which we can test)
|
| 318 |
+
// Row-major kinked serpentine iteration
|
| 319 |
+
CUTE_UNROLL
|
| 320 |
+
for (int m = 0; m < M; m += 2) {
|
| 321 |
+
CUTE_UNROLL
|
| 322 |
+
for (int n = 0; n < N; ++n) {
|
| 323 |
+
int ns = (m & 2) ? N-1-n : n;
|
| 324 |
+
gemm(mma, D(_,m+0,ns), A(_,m+0), B(_,ns), C(_,m+0,ns));
|
| 325 |
+
|
| 326 |
+
if (m+1 < M) {
|
| 327 |
+
gemm(mma, D(_,m+1,ns), A(_,m+1), B(_,ns), C(_,m+1,ns));
|
| 328 |
+
}
|
| 329 |
+
}
|
| 330 |
+
}
|
| 331 |
+
#else
|
| 332 |
+
// Col-major kinked serpentine iteration
|
| 333 |
+
CUTE_UNROLL
|
| 334 |
+
for (int n = 0; n < N; n += 2) {
|
| 335 |
+
CUTE_UNROLL
|
| 336 |
+
for (int m = 0; m < M; ++m) {
|
| 337 |
+
// Kinked serpentine traversal for maximum register reuse
|
| 338 |
+
int ms = (n & 2) ? M-1-m : m;
|
| 339 |
+
gemm(mma, D(_,ms,n+0), A(_,ms), B(_,n+0), C(_,ms,n+0));
|
| 340 |
+
|
| 341 |
+
if (n+1 < N) {
|
| 342 |
+
gemm(mma, D(_,ms,n+1), A(_,ms), B(_,n+1), C(_,ms,n+1));
|
| 343 |
+
}
|
| 344 |
+
}
|
| 345 |
+
}
|
| 346 |
+
#endif
|
| 347 |
+
} else
|
| 348 |
+
// 64-bit + 32-bit traversal order -- keep A (64-bit) in the outer loop and serpentine B
|
| 349 |
+
if constexpr (decltype(size<0>(A))::value * sizeof(typename TA::value_type) == 8 &&
|
| 350 |
+
decltype(size<0>(B))::value * sizeof(typename TB::value_type) == 4) {
|
| 351 |
+
// Row-major serpentine iteration
|
| 352 |
+
CUTE_UNROLL
|
| 353 |
+
for (int m = 0; m < M; ++m) {
|
| 354 |
+
CUTE_UNROLL
|
| 355 |
+
for (int n = 0; n < N; ++n) {
|
| 356 |
+
int ns = (m & 1) ? N-1-n : n; // Serpentine coordinate
|
| 357 |
+
gemm(mma, D(_,m,ns), A(_,m), B(_,ns), C(_,m,ns));
|
| 358 |
+
}
|
| 359 |
+
}
|
| 360 |
+
} else
|
| 361 |
+
// 32-bit + 64-bit traversal order -- keep B (64-bit) in the outer loop and serpentine A
|
| 362 |
+
if constexpr (decltype(size<0>(A))::value * sizeof(typename TA::value_type) == 4 &&
|
| 363 |
+
decltype(size<0>(B))::value * sizeof(typename TB::value_type) == 8) {
|
| 364 |
+
// Col-major serpentine iteration
|
| 365 |
+
CUTE_UNROLL
|
| 366 |
+
for (int n = 0; n < N; ++n) {
|
| 367 |
+
CUTE_UNROLL
|
| 368 |
+
for (int m = 0; m < M; ++m) {
|
| 369 |
+
int ms = (n & 1) ? M-1-m : m; // Serpentine coordinate
|
| 370 |
+
gemm(mma, D(_,ms,n), A(_,ms), B(_,n), C(_,ms,n));
|
| 371 |
+
}
|
| 372 |
+
}
|
| 373 |
+
} else
|
| 374 |
+
// Fallback to serpentine loop
|
| 375 |
+
{
|
| 376 |
+
// Col-major serpentine iteration
|
| 377 |
+
CUTE_UNROLL
|
| 378 |
+
for (int n = 0; n < N; ++n) {
|
| 379 |
+
CUTE_UNROLL
|
| 380 |
+
for (int m = 0; m < M; ++m) {
|
| 381 |
+
int ms = (n & 1) ? M-1-m : m; // Serpentine coordinate
|
| 382 |
+
gemm(mma, D(_,ms,n), A(_,ms), B(_,n), C(_,ms,n));
|
| 383 |
+
}
|
| 384 |
+
}
|
| 385 |
+
}
|
| 386 |
+
}
|
| 387 |
+
|
| 388 |
+
// Dispatch [5]: (V,M,K) x (V,N,K) => (V,M,N)
|
| 389 |
+
template <class MMA,
|
| 390 |
+
class TD, class DLayout,
|
| 391 |
+
class TA, class ALayout,
|
| 392 |
+
class TB, class BLayout,
|
| 393 |
+
class TC, class CLayout,
|
| 394 |
+
__CUTE_REQUIRES(DLayout::rank == 3 && is_rmem<TD>::value &&
|
| 395 |
+
ALayout::rank == 3 && is_rmem<TA>::value &&
|
| 396 |
+
BLayout::rank == 3 && is_rmem<TB>::value &&
|
| 397 |
+
CLayout::rank == 3 && is_rmem<TC>::value)>
|
| 398 |
+
CUTE_HOST_DEVICE
|
| 399 |
+
void
|
| 400 |
+
gemm(MMA_Atom<MMA> const& mma,
|
| 401 |
+
Tensor<TD, DLayout> & D, // (V,M,N) Logical data
|
| 402 |
+
Tensor<TA, ALayout> const& A, // (V,M,K) Logical data
|
| 403 |
+
Tensor<TB, BLayout> const& B, // (V,N,K) Logical data
|
| 404 |
+
Tensor<TC, CLayout> const& C) // (V,M,N) Logical data
|
| 405 |
+
{
|
| 406 |
+
CUTE_STATIC_ASSERT_V(size<1>(A) == size<1>(C)); // AM == CM
|
| 407 |
+
CUTE_STATIC_ASSERT_V(size<1>(B) == size<2>(C)); // BN == CN
|
| 408 |
+
CUTE_STATIC_ASSERT_V(size<2>(A) == size<2>(B)); // AK == BK
|
| 409 |
+
CUTE_STATIC_ASSERT_V(size<0>(C) == size<0>(D) && size<1>(C) == size<1>(D) && size<2>(C) == size<2>(D));
|
| 410 |
+
auto K = size<2>(A);
|
| 411 |
+
|
| 412 |
+
CUTE_UNROLL
|
| 413 |
+
for (int k = 0; k < K; ++k) {
|
| 414 |
+
gemm(mma, D, A(_,_,k), B(_,_,k), C);
|
| 415 |
+
}
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
+
//
|
| 419 |
+
// Thread-Local Shared-Memory GEMMs
|
| 420 |
+
//
|
| 421 |
+
|
| 422 |
+
// Dispatch [1]: (V) x (V) => (V)
|
| 423 |
+
// Dispatch [2]: (M) x (N) => (M,N)
|
| 424 |
+
// Dispatch [3]: (M,K) x (N,K) => (M,N)
|
| 425 |
+
// Dispatch [4]: (V,M) x (V,N) => (V,M,N)
|
| 426 |
+
// Dispatch [5]: (V,M,K) x (V,N,K) => (V,M,N)
|
| 427 |
+
// Dispatch [3]: (M,K) x (N,K) => (M,N)
|
| 428 |
+
template <class MMA,
|
| 429 |
+
class TD, class DLayout,
|
| 430 |
+
class TA, class ALayout,
|
| 431 |
+
class TB, class BLayout,
|
| 432 |
+
class TC, class CLayout,
|
| 433 |
+
__CUTE_REQUIRES(DLayout::rank == 2 && is_rmem<TD>::value &&
|
| 434 |
+
ALayout::rank == 2 && is_smem<TA>::value &&
|
| 435 |
+
BLayout::rank == 2 && is_smem<TB>::value &&
|
| 436 |
+
CLayout::rank == 2 && is_rmem<TC>::value)>
|
| 437 |
+
CUTE_HOST_DEVICE
|
| 438 |
+
void
|
| 439 |
+
gemm(MMA_Atom<MMA> const& mma,
|
| 440 |
+
Tensor<TD, DLayout> & D, // (M,N) Logical data
|
| 441 |
+
Tensor<TA, ALayout> const& A, // (M,K) Logical data
|
| 442 |
+
Tensor<TB, BLayout> const& B, // (N,K) Logical data
|
| 443 |
+
Tensor<TC, CLayout> const& C) // (M,N) Logical data
|
| 444 |
+
{
|
| 445 |
+
CUTE_STATIC_ASSERT_V(size<0>(A) == size<0>(C)); // AM == CM
|
| 446 |
+
CUTE_STATIC_ASSERT_V(size<0>(B) == size<1>(C)); // BN == CN
|
| 447 |
+
CUTE_STATIC_ASSERT_V(size<1>(A) == size<1>(B)); // AK == BK
|
| 448 |
+
CUTE_STATIC_ASSERT_V(size<0>(C) == size<0>(D) && size<1>(C) == size<1>(D));
|
| 449 |
+
|
| 450 |
+
// Assert this is a 1-value MMA
|
| 451 |
+
CUTE_STATIC_ASSERT_V(size<1>(typename MMA_Atom<MMA>::LayoutC_TV{}) == Int<1>{});
|
| 452 |
+
CUTE_STATIC_ASSERT_V(size<1>(typename MMA_Atom<MMA>::LayoutA_TV{}) == Int<1>{});
|
| 453 |
+
CUTE_STATIC_ASSERT_V(size<1>(typename MMA_Atom<MMA>::LayoutB_TV{}) == Int<1>{});
|
| 454 |
+
|
| 455 |
+
gemm(mma,
|
| 456 |
+
make_tensor(D.data(), prepend<3>(D.layout())), // (1,M,N)
|
| 457 |
+
make_tensor(A.data(), prepend<3>(A.layout())), // (1,M,K)
|
| 458 |
+
make_tensor(B.data(), prepend<3>(B.layout())), // (1,N,K)
|
| 459 |
+
make_tensor(C.data(), prepend<3>(C.layout()))); // (1,M,N)
|
| 460 |
+
}
|
| 461 |
+
|
| 462 |
+
// Dispatch [5]: (V,M,K) x (V,N,K) => (V,M,N)
|
| 463 |
+
template <class MMA,
|
| 464 |
+
class TD, class DLayout,
|
| 465 |
+
class TA, class ALayout,
|
| 466 |
+
class TB, class BLayout,
|
| 467 |
+
class TC, class CLayout,
|
| 468 |
+
__CUTE_REQUIRES(DLayout::rank == 3 && is_rmem<TD>::value &&
|
| 469 |
+
ALayout::rank == 3 && is_smem<TA>::value &&
|
| 470 |
+
BLayout::rank == 3 && is_smem<TB>::value &&
|
| 471 |
+
CLayout::rank == 3 && is_rmem<TC>::value)>
|
| 472 |
+
CUTE_HOST_DEVICE
|
| 473 |
+
void
|
| 474 |
+
gemm(MMA_Atom<MMA> const& mma,
|
| 475 |
+
Tensor<TD, DLayout> & D, // (V,M,N) Logical data
|
| 476 |
+
Tensor<TA, ALayout> const& A, // (V,M,K) Logical data
|
| 477 |
+
Tensor<TB, BLayout> const& B, // (V,N,K) Logical data
|
| 478 |
+
Tensor<TC, CLayout> const& C) // (V,M,N) Logical data
|
| 479 |
+
{
|
| 480 |
+
CUTE_STATIC_ASSERT_V(size<1>(A) == size<1>(C)); // AM == CM
|
| 481 |
+
CUTE_STATIC_ASSERT_V(size<1>(B) == size<2>(C)); // BN == CN
|
| 482 |
+
CUTE_STATIC_ASSERT_V(size<2>(A) == size<2>(B)); // AK == BK
|
| 483 |
+
CUTE_STATIC_ASSERT_V(size<0>(C) == size<0>(D) && size<1>(C) == size<1>(D) && size<2>(C) == size<2>(D));
|
| 484 |
+
|
| 485 |
+
auto rA = MMA_Atom<MMA>::make_fragment_A(A);
|
| 486 |
+
auto rB = MMA_Atom<MMA>::make_fragment_B(B);
|
| 487 |
+
|
| 488 |
+
auto K = size<2>(A);
|
| 489 |
+
|
| 490 |
+
CUTE_UNROLL
|
| 491 |
+
for (int k = 0; k < K; ++k)
|
| 492 |
+
{
|
| 493 |
+
copy(A(_,_,k), rA(_,_,k));
|
| 494 |
+
copy(B(_,_,k), rB(_,_,k));
|
| 495 |
+
// Thread-level register gemm for k
|
| 496 |
+
gemm(mma, D, rA(_,_,k), rB(_,_,k), C);
|
| 497 |
+
}
|
| 498 |
+
}
|
| 499 |
+
|
| 500 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/prefer.hpp
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
namespace cute
|
| 34 |
+
{
|
| 35 |
+
|
| 36 |
+
// Infinite types that inherit from each other
|
| 37 |
+
template <size_t N>
|
| 38 |
+
struct prefer : prefer<N-1> {};
|
| 39 |
+
|
| 40 |
+
template <>
|
| 41 |
+
struct prefer<0> {};
|
| 42 |
+
|
| 43 |
+
// Can be used to preferencially overload implementations
|
| 44 |
+
// Higher N in prefer<N> have higher priority.
|
| 45 |
+
|
| 46 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/prefetch.hpp
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2024 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/config.hpp> // CUTE_HOST_DEVICE
|
| 34 |
+
#include <cute/tensor_impl.hpp> // cute::Tensor
|
| 35 |
+
#include <cute/atom/copy_atom.hpp> // cute::Copy_Atom
|
| 36 |
+
|
| 37 |
+
namespace cute
|
| 38 |
+
{
|
| 39 |
+
|
| 40 |
+
//
|
| 41 |
+
// Prefetch global tensors into L2
|
| 42 |
+
//
|
| 43 |
+
|
| 44 |
+
template <uint32_t NumThreads, uint32_t FetchBytes = 64,
|
| 45 |
+
class GEngine, class GLayout>
|
| 46 |
+
CUTE_HOST_DEVICE
|
| 47 |
+
void
|
| 48 |
+
cooperative_prefetch(uint32_t const& tid,
|
| 49 |
+
Tensor<GEngine, GLayout> const& src)
|
| 50 |
+
{
|
| 51 |
+
static_assert(is_gmem<GEngine>::value, "Expected global tensor for prefetch");
|
| 52 |
+
|
| 53 |
+
constexpr int V = decltype(max_common_vector(src, src))::value;
|
| 54 |
+
|
| 55 |
+
if constexpr (V > 1) {
|
| 56 |
+
// L2 sector is 32B, default fetch granularity is 64B
|
| 57 |
+
using VecType = conditional_t<(V * sizeof_bits_v<typename GEngine::value_type>) < (FetchBytes * 8),
|
| 58 |
+
ArrayEngine<typename GEngine::value_type, V>,
|
| 59 |
+
uint8_t[FetchBytes] >;
|
| 60 |
+
|
| 61 |
+
Tensor src_v = recast<VecType const>(src);
|
| 62 |
+
CUTE_UNROLL
|
| 63 |
+
for (int i = tid; i < size(src_v); i += NumThreads) {
|
| 64 |
+
prefetch(raw_pointer_cast(&src_v(i)));
|
| 65 |
+
}
|
| 66 |
+
} else {
|
| 67 |
+
CUTE_UNROLL
|
| 68 |
+
for (int i = tid; i < size(src); i += NumThreads) {
|
| 69 |
+
prefetch(raw_pointer_cast(&src(i)));
|
| 70 |
+
}
|
| 71 |
+
}
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
template <class GEngine, class GLayout>
|
| 75 |
+
CUTE_HOST_DEVICE
|
| 76 |
+
void
|
| 77 |
+
prefetch(Tensor<GEngine, GLayout> const& src)
|
| 78 |
+
{
|
| 79 |
+
return cooperative_prefetch<1>(0, src);
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
// Prefetch with copy atom
|
| 83 |
+
namespace detail {
|
| 84 |
+
|
| 85 |
+
template <class CopyOp, class = void>
|
| 86 |
+
constexpr bool has_prefetch = false;
|
| 87 |
+
|
| 88 |
+
template <class CopyOp>
|
| 89 |
+
constexpr bool has_prefetch<CopyOp, void_t<typename CopyOp::PREFETCH>> = true;
|
| 90 |
+
|
| 91 |
+
} // end namespace detail
|
| 92 |
+
|
| 93 |
+
template <class CopyOp, class... CT_Args, class... CA_Args,
|
| 94 |
+
class GEngine, class GLayout>
|
| 95 |
+
CUTE_HOST_DEVICE
|
| 96 |
+
void
|
| 97 |
+
prefetch(Copy_Atom<Copy_Traits<CopyOp, CT_Args...>, CA_Args...> const& atom,
|
| 98 |
+
Tensor<GEngine, GLayout> const& src)
|
| 99 |
+
{
|
| 100 |
+
if constexpr (detail::has_prefetch<CopyOp>) {
|
| 101 |
+
using Prefetch_Traits = Copy_Traits<typename CopyOp::PREFETCH, CT_Args...>;
|
| 102 |
+
using Prefetch_Atom = Copy_Atom<Prefetch_Traits, CA_Args...>;
|
| 103 |
+
Prefetch_Atom prefetch_atom{atom};
|
| 104 |
+
auto& dst = const_cast<Tensor<GEngine, GLayout>&>(src); // dst is ignored for prefetch atoms
|
| 105 |
+
return copy(prefetch_atom, src, dst);
|
| 106 |
+
} else {
|
| 107 |
+
return prefetch(src);
|
| 108 |
+
}
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
#if defined(CUTE_COPY_ATOM_TMA_SM90_ENABLED)
|
| 112 |
+
template <class... CT_Args,
|
| 113 |
+
class SrcEngine, class SrcLayout>
|
| 114 |
+
CUTE_HOST_DEVICE
|
| 115 |
+
void
|
| 116 |
+
prefetch(Copy_Traits<SM90_BULK_COPY_AUTO, CT_Args...> const& atom,
|
| 117 |
+
Tensor<SrcEngine, SrcLayout> const& src)
|
| 118 |
+
{
|
| 119 |
+
using SrcType = typename SrcEngine::value_type;
|
| 120 |
+
static_assert(is_gmem<SrcEngine>::value, "Expected global tensor for L2 prefetch");
|
| 121 |
+
|
| 122 |
+
auto tiler = max_common_layout(src, src);
|
| 123 |
+
constexpr int vec_elem = decltype(size(tiler))::value;
|
| 124 |
+
constexpr int vec_bits = vec_elem * sizeof_bits_v<SrcType>;
|
| 125 |
+
static_assert(vec_bits >= 128, "Expected at least 128-bits for BLKCP");
|
| 126 |
+
|
| 127 |
+
// Construct a new concrete Atom of the vector size
|
| 128 |
+
auto bulk_atom = Copy_Atom<Copy_Traits<SM90_BULK_COPY_G2S, Int<vec_bits>>, SrcType>{};
|
| 129 |
+
|
| 130 |
+
return prefetch(bulk_atom, logical_divide(src, tiler));
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
// Backwards-compat. Throw out any extra Copy_Atom args.
|
| 134 |
+
template <class... CT_Args, class... CA_Args,
|
| 135 |
+
class SrcEngine, class SrcLayout>
|
| 136 |
+
CUTE_HOST_DEVICE
|
| 137 |
+
void
|
| 138 |
+
prefetch(Copy_Atom<Copy_Traits<SM90_BULK_COPY_AUTO, CT_Args...>, CA_Args...> const& atom,
|
| 139 |
+
Tensor<SrcEngine, SrcLayout> const& src)
|
| 140 |
+
{
|
| 141 |
+
return prefetch(static_cast<Copy_Traits<SM90_BULK_COPY_AUTO, CT_Args...> const&>(atom), src);
|
| 142 |
+
}
|
| 143 |
+
#endif // #if defined(CUTE_COPY_ATOM_TMA_SM90_ENABLED)
|
| 144 |
+
|
| 145 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/tensor_algorithms.hpp
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
/** Common algorithms on (hierarchical) tensors */
|
| 32 |
+
|
| 33 |
+
#pragma once
|
| 34 |
+
|
| 35 |
+
#include <cute/config.hpp>
|
| 36 |
+
#include <cute/tensor_impl.hpp>
|
| 37 |
+
|
| 38 |
+
namespace cute
|
| 39 |
+
{
|
| 40 |
+
|
| 41 |
+
//
|
| 42 |
+
// for_each
|
| 43 |
+
//
|
| 44 |
+
|
| 45 |
+
template <class Engine, class Layout, class UnaryOp>
|
| 46 |
+
CUTE_HOST_DEVICE constexpr
|
| 47 |
+
void
|
| 48 |
+
for_each(Tensor<Engine,Layout> const& tensor, UnaryOp&& op)
|
| 49 |
+
{
|
| 50 |
+
CUTE_UNROLL
|
| 51 |
+
for (int i = 0; i < size(tensor); ++i) {
|
| 52 |
+
op(tensor(i));
|
| 53 |
+
}
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
template <class Engine, class Layout, class UnaryOp>
|
| 57 |
+
CUTE_HOST_DEVICE constexpr
|
| 58 |
+
void
|
| 59 |
+
for_each(Tensor<Engine,Layout>& tensor, UnaryOp&& op)
|
| 60 |
+
{
|
| 61 |
+
CUTE_UNROLL
|
| 62 |
+
for (int i = 0; i < size(tensor); ++i) {
|
| 63 |
+
op(tensor(i));
|
| 64 |
+
}
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
// Accept mutable temporaries
|
| 68 |
+
template <class Engine, class Layout, class UnaryOp>
|
| 69 |
+
CUTE_HOST_DEVICE constexpr
|
| 70 |
+
void
|
| 71 |
+
for_each(Tensor<Engine,Layout>&& tensor, UnaryOp&& op)
|
| 72 |
+
{
|
| 73 |
+
return for_each(tensor, op);
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
//
|
| 77 |
+
// transform
|
| 78 |
+
//
|
| 79 |
+
|
| 80 |
+
// Similar to std::transform but does not return number of elements affected
|
| 81 |
+
template <class Engine, class Layout, class UnaryOp>
|
| 82 |
+
CUTE_HOST_DEVICE constexpr
|
| 83 |
+
void
|
| 84 |
+
transform(Tensor<Engine,Layout>& tensor, UnaryOp&& op)
|
| 85 |
+
{
|
| 86 |
+
CUTE_UNROLL
|
| 87 |
+
for (int i = 0; i < size(tensor); ++i) {
|
| 88 |
+
tensor(i) = op(tensor(i));
|
| 89 |
+
}
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
// Accept mutable temporaries
|
| 93 |
+
template <class Engine, class Layout, class UnaryOp>
|
| 94 |
+
CUTE_HOST_DEVICE constexpr
|
| 95 |
+
void
|
| 96 |
+
transform(Tensor<Engine,Layout>&& tensor, UnaryOp&& op)
|
| 97 |
+
{
|
| 98 |
+
return transform(tensor, op);
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
// Similar to std::transform transforms one tensors and assigns it to another
|
| 102 |
+
template <class EngineIn, class LayoutIn,
|
| 103 |
+
class EngineOut, class LayoutOut,
|
| 104 |
+
class UnaryOp>
|
| 105 |
+
CUTE_HOST_DEVICE constexpr
|
| 106 |
+
void
|
| 107 |
+
transform(Tensor<EngineIn, LayoutIn > const& tensor_in,
|
| 108 |
+
Tensor<EngineOut,LayoutOut> & tensor_out,
|
| 109 |
+
UnaryOp&& op)
|
| 110 |
+
{
|
| 111 |
+
CUTE_UNROLL
|
| 112 |
+
for (int i = 0; i < size(tensor_in); ++i) {
|
| 113 |
+
tensor_out(i) = op(tensor_in(i));
|
| 114 |
+
}
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
// Accept mutable temporaries
|
| 118 |
+
template <class EngineIn, class LayoutIn,
|
| 119 |
+
class EngineOut, class LayoutOut,
|
| 120 |
+
class UnaryOp>
|
| 121 |
+
CUTE_HOST_DEVICE constexpr
|
| 122 |
+
void
|
| 123 |
+
transform(Tensor<EngineIn, LayoutIn > const& tensor_in,
|
| 124 |
+
Tensor<EngineOut,LayoutOut> && tensor_out,
|
| 125 |
+
UnaryOp&& op)
|
| 126 |
+
{
|
| 127 |
+
return transform(tensor_in, tensor_out, op);
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
// Similar to std::transform with a binary operation
|
| 131 |
+
// Takes two tensors as input and one tensor as output.
|
| 132 |
+
// Applies the binary_op to tensor_in1 and tensor_in2 and
|
| 133 |
+
// assigns it to tensor_out
|
| 134 |
+
template <class EngineIn1, class LayoutIn1,
|
| 135 |
+
class EngineIn2, class LayoutIn2,
|
| 136 |
+
class EngineOut, class LayoutOut,
|
| 137 |
+
class BinaryOp>
|
| 138 |
+
CUTE_HOST_DEVICE constexpr
|
| 139 |
+
void
|
| 140 |
+
transform(Tensor<EngineIn1,LayoutIn1> const& tensor_in1,
|
| 141 |
+
Tensor<EngineIn2,LayoutIn2> const& tensor_in2,
|
| 142 |
+
Tensor<EngineOut,LayoutOut> & tensor_out,
|
| 143 |
+
BinaryOp&& op)
|
| 144 |
+
{
|
| 145 |
+
CUTE_UNROLL
|
| 146 |
+
for (int i = 0; i < size(tensor_in1); ++i) {
|
| 147 |
+
tensor_out(i) = op(tensor_in1(i), tensor_in2(i));
|
| 148 |
+
}
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
// Accept mutable temporaries
|
| 152 |
+
template <class EngineIn1, class LayoutIn1,
|
| 153 |
+
class EngineIn2, class LayoutIn2,
|
| 154 |
+
class EngineOut, class LayoutOut,
|
| 155 |
+
class BinaryOp>
|
| 156 |
+
CUTE_HOST_DEVICE constexpr
|
| 157 |
+
void
|
| 158 |
+
transform(Tensor<EngineIn1,LayoutIn1> const& tensor_in1,
|
| 159 |
+
Tensor<EngineIn2,LayoutIn2> const& tensor_in2,
|
| 160 |
+
Tensor<EngineOut,LayoutOut> && tensor_out,
|
| 161 |
+
BinaryOp&& op)
|
| 162 |
+
{
|
| 163 |
+
return transform(tensor_in1, tensor_in2, tensor_out, op);
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/algorithm/tuple_algorithms.hpp
ADDED
|
@@ -0,0 +1,1073 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/config.hpp>
|
| 34 |
+
|
| 35 |
+
#include <cute/util/type_traits.hpp>
|
| 36 |
+
#include <cute/container/tuple.hpp>
|
| 37 |
+
#include <cute/algorithm/functional.hpp>
|
| 38 |
+
#include <cute/numeric/integer_sequence.hpp>
|
| 39 |
+
#include <cute/numeric/integral_constant.hpp>
|
| 40 |
+
|
| 41 |
+
/// @file tuple_algorithms.hpp
|
| 42 |
+
/// @brief Common algorithms on (hierarchical) tuples
|
| 43 |
+
///
|
| 44 |
+
/// Code guidelines and style preferences:
|
| 45 |
+
///
|
| 46 |
+
/// For perfect forwarding, don't use std::forward, because it may not
|
| 47 |
+
/// be defined in device code when compiling with NVRTC. Instead, use
|
| 48 |
+
/// `static_cast<ParameterType&&>(parameter_name)`.
|
| 49 |
+
///
|
| 50 |
+
/// CuTe generally does not bother forwarding functions, as
|
| 51 |
+
/// reference-qualified member functions are rare in this code base.
|
| 52 |
+
///
|
| 53 |
+
/// Throughout CUTLASS, cute::make_tuple always needs to be called
|
| 54 |
+
/// namespace-qualified, EVEN If inside the cute namespace and/or in
|
| 55 |
+
/// scope of a "using namespace cute" declaration. Otherwise, the
|
| 56 |
+
/// compiler may select std::make_tuple instead of cute::make_tuple,
|
| 57 |
+
/// due to argument-dependent lookup.
|
| 58 |
+
|
| 59 |
+
namespace cute
|
| 60 |
+
{
|
| 61 |
+
|
| 62 |
+
//
|
| 63 |
+
// Apply (Unpack)
|
| 64 |
+
// (t, f) => f(t_0,t_1,...,t_n)
|
| 65 |
+
//
|
| 66 |
+
|
| 67 |
+
namespace detail {
|
| 68 |
+
|
| 69 |
+
template <class T, class F, int... I>
|
| 70 |
+
CUTE_HOST_DEVICE constexpr
|
| 71 |
+
auto
|
| 72 |
+
apply(T&& t, F&& f, seq<I...>)
|
| 73 |
+
{
|
| 74 |
+
return f(get<I>(static_cast<T&&>(t))...);
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
} // end namespace detail
|
| 78 |
+
|
| 79 |
+
template <class T, class F>
|
| 80 |
+
CUTE_HOST_DEVICE constexpr
|
| 81 |
+
auto
|
| 82 |
+
apply(T&& t, F&& f)
|
| 83 |
+
{
|
| 84 |
+
return detail::apply(static_cast<T&&>(t), f, tuple_seq<T>{});
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
//
|
| 88 |
+
// Transform Apply
|
| 89 |
+
// (t, f, g) => g(f(t_0),f(t_1),...)
|
| 90 |
+
//
|
| 91 |
+
|
| 92 |
+
namespace detail {
|
| 93 |
+
|
| 94 |
+
template <class T, class F, class G, int... I>
|
| 95 |
+
CUTE_HOST_DEVICE constexpr
|
| 96 |
+
auto
|
| 97 |
+
tapply(T&& t, F&& f, G&& g, seq<I...>)
|
| 98 |
+
{
|
| 99 |
+
return g(f(get<I>(static_cast<T&&>(t)))...);
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
template <class T0, class T1, class F, class G, int... I>
|
| 103 |
+
CUTE_HOST_DEVICE constexpr
|
| 104 |
+
auto
|
| 105 |
+
tapply(T0&& t0, T1&& t1, F&& f, G&& g, seq<I...>)
|
| 106 |
+
{
|
| 107 |
+
return g(f(get<I>(static_cast<T0&&>(t0)),
|
| 108 |
+
get<I>(static_cast<T1&&>(t1)))...);
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
template <class T0, class T1, class T2, class F, class G, int... I>
|
| 112 |
+
CUTE_HOST_DEVICE constexpr
|
| 113 |
+
auto
|
| 114 |
+
tapply(T0&& t0, T1&& t1, T2&& t2, F&& f, G&& g, seq<I...>)
|
| 115 |
+
{
|
| 116 |
+
return g(f(get<I>(static_cast<T0&&>(t0)),
|
| 117 |
+
get<I>(static_cast<T1&&>(t1)),
|
| 118 |
+
get<I>(static_cast<T2&&>(t2)))...);
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
} // end namespace detail
|
| 122 |
+
|
| 123 |
+
template <class T, class F, class G>
|
| 124 |
+
CUTE_HOST_DEVICE constexpr
|
| 125 |
+
auto
|
| 126 |
+
transform_apply(T&& t, F&& f, G&& g)
|
| 127 |
+
{
|
| 128 |
+
if constexpr (is_tuple<remove_cvref_t<T>>::value) {
|
| 129 |
+
return detail::tapply(static_cast<T&&>(t), f, g, tuple_seq<T>{});
|
| 130 |
+
} else {
|
| 131 |
+
return g(f(static_cast<T&&>(t)));
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
CUTE_GCC_UNREACHABLE;
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
template <class T0, class T1, class F, class G>
|
| 138 |
+
CUTE_HOST_DEVICE constexpr
|
| 139 |
+
auto
|
| 140 |
+
transform_apply(T0&& t0, T1&& t1, F&& f, G&& g)
|
| 141 |
+
{
|
| 142 |
+
if constexpr (is_tuple<remove_cvref_t<T0>>::value) {
|
| 143 |
+
return detail::tapply(static_cast<T0&&>(t0), static_cast<T1&&>(t1), f, g, tuple_seq<T0>{});
|
| 144 |
+
} else {
|
| 145 |
+
return g(f(static_cast<T0&&>(t0), static_cast<T1&&>(t1)));
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
CUTE_GCC_UNREACHABLE;
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
template <class T0, class T1, class T2, class F, class G>
|
| 152 |
+
CUTE_HOST_DEVICE constexpr
|
| 153 |
+
auto
|
| 154 |
+
transform_apply(T0&& t0, T1&& t1, T2&& t2, F&& f, G&& g)
|
| 155 |
+
{
|
| 156 |
+
if constexpr (is_tuple<remove_cvref_t<T0>>::value) {
|
| 157 |
+
return detail::tapply(static_cast<T0&&>(t0), static_cast<T1&&>(t1), static_cast<T2&&>(t2), f, g, tuple_seq<T0>{});
|
| 158 |
+
} else {
|
| 159 |
+
return g(f(static_cast<T0&&>(t0), static_cast<T1&&>(t1), static_cast<T2&&>(t2)));
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
CUTE_GCC_UNREACHABLE;
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
//
|
| 166 |
+
// For Each
|
| 167 |
+
// (t, f) => f(t_0),f(t_1),...,f(t_n)
|
| 168 |
+
//
|
| 169 |
+
|
| 170 |
+
template <class T, class F>
|
| 171 |
+
CUTE_HOST_DEVICE constexpr
|
| 172 |
+
void
|
| 173 |
+
for_each(T&& t, F&& f)
|
| 174 |
+
{
|
| 175 |
+
if constexpr (is_tuple<remove_cvref_t<T>>::value) {
|
| 176 |
+
return detail::apply(t, [&](auto&&... a) { (f(static_cast<decltype(a)&&>(a)), ...); }, tuple_seq<T>{});
|
| 177 |
+
} else {
|
| 178 |
+
return f(static_cast<T&&>(t));
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
CUTE_GCC_UNREACHABLE;
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
template <class T, class F>
|
| 185 |
+
CUTE_HOST_DEVICE constexpr
|
| 186 |
+
auto
|
| 187 |
+
for_each_leaf(T&& t, F&& f)
|
| 188 |
+
{
|
| 189 |
+
if constexpr (is_tuple<remove_cvref_t<T>>::value) {
|
| 190 |
+
return detail::apply(static_cast<T&&>(t), [&](auto&&... a){ return (for_each_leaf(static_cast<decltype(a)&&>(a), f), ...); }, tuple_seq<T>{});
|
| 191 |
+
} else {
|
| 192 |
+
return f(static_cast<T&&>(t));
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
CUTE_GCC_UNREACHABLE;
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
//
|
| 199 |
+
// Transform
|
| 200 |
+
// (t, f) => (f(t_0),f(t_1),...,f(t_n))
|
| 201 |
+
//
|
| 202 |
+
|
| 203 |
+
template <class T, class F>
|
| 204 |
+
CUTE_HOST_DEVICE constexpr
|
| 205 |
+
auto
|
| 206 |
+
transform(T const& t, F&& f)
|
| 207 |
+
{
|
| 208 |
+
if constexpr (is_tuple<T>::value) {
|
| 209 |
+
return detail::tapply(t, f, [](auto const&... a){ return cute::make_tuple(a...); }, tuple_seq<T>{});
|
| 210 |
+
} else {
|
| 211 |
+
return f(t);
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
CUTE_GCC_UNREACHABLE;
|
| 215 |
+
}
|
| 216 |
+
|
| 217 |
+
template <class T0, class T1, class F>
|
| 218 |
+
CUTE_HOST_DEVICE constexpr
|
| 219 |
+
auto
|
| 220 |
+
transform(T0 const& t0, T1 const& t1, F&& f)
|
| 221 |
+
{
|
| 222 |
+
if constexpr (is_tuple<T0>::value) {
|
| 223 |
+
static_assert(tuple_size<T0>::value == tuple_size<T1>::value, "Mismatched tuple_size");
|
| 224 |
+
return detail::tapply(t0, t1, f, [](auto const&... a){ return cute::make_tuple(a...); }, tuple_seq<T0>{});
|
| 225 |
+
} else {
|
| 226 |
+
return f(t0, t1);
|
| 227 |
+
}
|
| 228 |
+
|
| 229 |
+
CUTE_GCC_UNREACHABLE;
|
| 230 |
+
}
|
| 231 |
+
|
| 232 |
+
template <class T0, class T1, class T2, class F>
|
| 233 |
+
CUTE_HOST_DEVICE constexpr
|
| 234 |
+
auto
|
| 235 |
+
transform(T0 const& t0, T1 const& t1, T2 const& t2, F&& f)
|
| 236 |
+
{
|
| 237 |
+
if constexpr (is_tuple<T0>::value) {
|
| 238 |
+
static_assert(tuple_size<T0>::value == tuple_size<T1>::value, "Mismatched tuple_size");
|
| 239 |
+
static_assert(tuple_size<T0>::value == tuple_size<T2>::value, "Mismatched tuple_size");
|
| 240 |
+
return detail::tapply(t0, t1, t2, f, [](auto const&... a){ return cute::make_tuple(a...); }, tuple_seq<T0>{});
|
| 241 |
+
} else {
|
| 242 |
+
return f(t0, t1, t2);
|
| 243 |
+
}
|
| 244 |
+
|
| 245 |
+
CUTE_GCC_UNREACHABLE;
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
template <class T, class F>
|
| 249 |
+
CUTE_HOST_DEVICE constexpr
|
| 250 |
+
auto
|
| 251 |
+
transform_leaf(T const& t, F&& f)
|
| 252 |
+
{
|
| 253 |
+
if constexpr (is_tuple<T>::value) {
|
| 254 |
+
return transform(t, [&](auto const& a) { return transform_leaf(a, f); });
|
| 255 |
+
} else {
|
| 256 |
+
return f(t);
|
| 257 |
+
}
|
| 258 |
+
|
| 259 |
+
CUTE_GCC_UNREACHABLE;
|
| 260 |
+
}
|
| 261 |
+
|
| 262 |
+
template <class T0, class T1, class F>
|
| 263 |
+
CUTE_HOST_DEVICE constexpr
|
| 264 |
+
auto
|
| 265 |
+
transform_leaf(T0 const& t0, T1 const& t1, F&& f)
|
| 266 |
+
{
|
| 267 |
+
if constexpr (is_tuple<T0>::value) {
|
| 268 |
+
return transform(t0, t1, [&](auto const& a, auto const& b) { return transform_leaf(a, b, f); });
|
| 269 |
+
} else {
|
| 270 |
+
return f(t0, t1);
|
| 271 |
+
}
|
| 272 |
+
|
| 273 |
+
CUTE_GCC_UNREACHABLE;
|
| 274 |
+
}
|
| 275 |
+
|
| 276 |
+
//
|
| 277 |
+
// find and find_if
|
| 278 |
+
//
|
| 279 |
+
|
| 280 |
+
namespace detail {
|
| 281 |
+
|
| 282 |
+
template <class T, class F, int I, int... Is>
|
| 283 |
+
CUTE_HOST_DEVICE constexpr
|
| 284 |
+
auto
|
| 285 |
+
find_if(T const& t, F&& f, seq<I,Is...>)
|
| 286 |
+
{
|
| 287 |
+
if constexpr (decltype(f(get<I>(t)))::value) {
|
| 288 |
+
return cute::C<I>{};
|
| 289 |
+
} else
|
| 290 |
+
if constexpr (sizeof...(Is) == 0) {
|
| 291 |
+
return cute::C<I+1>{};
|
| 292 |
+
} else {
|
| 293 |
+
return find_if(t, f, seq<Is...>{});
|
| 294 |
+
}
|
| 295 |
+
|
| 296 |
+
CUTE_GCC_UNREACHABLE;
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
} // end namespace detail
|
| 300 |
+
|
| 301 |
+
template <class T, class F>
|
| 302 |
+
CUTE_HOST_DEVICE constexpr
|
| 303 |
+
auto
|
| 304 |
+
find_if(T const& t, F&& f)
|
| 305 |
+
{
|
| 306 |
+
if constexpr (is_tuple<T>::value) {
|
| 307 |
+
return detail::find_if(t, f, tuple_seq<T>{});
|
| 308 |
+
} else {
|
| 309 |
+
return cute::C<decltype(f(t))::value ? 0 : 1>{};
|
| 310 |
+
}
|
| 311 |
+
|
| 312 |
+
CUTE_GCC_UNREACHABLE;
|
| 313 |
+
}
|
| 314 |
+
|
| 315 |
+
template <class T, class X>
|
| 316 |
+
CUTE_HOST_DEVICE constexpr
|
| 317 |
+
auto
|
| 318 |
+
find(T const& t, X const& x)
|
| 319 |
+
{
|
| 320 |
+
return find_if(t, [&](auto const& v) { return v == x; }); // This should always return a static true/false
|
| 321 |
+
}
|
| 322 |
+
|
| 323 |
+
template <class T, class F>
|
| 324 |
+
CUTE_HOST_DEVICE constexpr
|
| 325 |
+
auto
|
| 326 |
+
any_of(T const& t, F&& f)
|
| 327 |
+
{
|
| 328 |
+
if constexpr (is_tuple<T>::value) {
|
| 329 |
+
return detail::apply(cute::transform(t, f), [&] (auto const&... a) { return (false_type{} || ... || a); }, tuple_seq<T>{});
|
| 330 |
+
} else {
|
| 331 |
+
return f(t);
|
| 332 |
+
}
|
| 333 |
+
|
| 334 |
+
CUTE_GCC_UNREACHABLE;
|
| 335 |
+
}
|
| 336 |
+
|
| 337 |
+
template <class T, class F>
|
| 338 |
+
CUTE_HOST_DEVICE constexpr
|
| 339 |
+
auto
|
| 340 |
+
all_of(T const& t, F&& f)
|
| 341 |
+
{
|
| 342 |
+
if constexpr (is_tuple<T>::value) {
|
| 343 |
+
return detail::apply(cute::transform(t, f), [&] (auto const&... a) { return (true_type{} && ... && a); }, tuple_seq<T>{});
|
| 344 |
+
} else {
|
| 345 |
+
return f(t);
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
CUTE_GCC_UNREACHABLE;
|
| 349 |
+
}
|
| 350 |
+
|
| 351 |
+
template <class T, class F>
|
| 352 |
+
CUTE_HOST_DEVICE constexpr
|
| 353 |
+
auto
|
| 354 |
+
none_of(T const& t, F&& f)
|
| 355 |
+
{
|
| 356 |
+
return not any_of(t, f);
|
| 357 |
+
}
|
| 358 |
+
|
| 359 |
+
//
|
| 360 |
+
// Filter
|
| 361 |
+
// (t, f) => <f(t_0),f(t_1),...,f(t_n)>
|
| 362 |
+
//
|
| 363 |
+
|
| 364 |
+
template <class T, class F>
|
| 365 |
+
CUTE_HOST_DEVICE constexpr
|
| 366 |
+
auto
|
| 367 |
+
filter_tuple(T const& t, F&& f)
|
| 368 |
+
{
|
| 369 |
+
return transform_apply(t, f, [](auto const&... a) { return cute::tuple_cat(a...); });
|
| 370 |
+
}
|
| 371 |
+
|
| 372 |
+
template <class T0, class T1, class F>
|
| 373 |
+
CUTE_HOST_DEVICE constexpr
|
| 374 |
+
auto
|
| 375 |
+
filter_tuple(T0 const& t0, T1 const& t1, F&& f)
|
| 376 |
+
{
|
| 377 |
+
return transform_apply(t0, t1, f, [](auto const&... a) { return cute::tuple_cat(a...); });
|
| 378 |
+
}
|
| 379 |
+
|
| 380 |
+
template <class T0, class T1, class T2, class F>
|
| 381 |
+
CUTE_HOST_DEVICE constexpr
|
| 382 |
+
auto
|
| 383 |
+
filter_tuple(T0 const& t0, T1 const& t1, T2 const& t2, F&& f)
|
| 384 |
+
{
|
| 385 |
+
return transform_apply(t0, t1, t2, f, [](auto const&... a) { return cute::tuple_cat(a...); });
|
| 386 |
+
}
|
| 387 |
+
|
| 388 |
+
//
|
| 389 |
+
// Fold (Reduce, Accumulate)
|
| 390 |
+
// (t, v, f) => f(...f(f(v,t_0),t_1),...,t_n)
|
| 391 |
+
//
|
| 392 |
+
|
| 393 |
+
namespace detail {
|
| 394 |
+
|
| 395 |
+
template <class Fn, class Val>
|
| 396 |
+
struct FoldAdaptor {
|
| 397 |
+
template <class X>
|
| 398 |
+
CUTE_HOST_DEVICE constexpr auto operator|(X&& x) {
|
| 399 |
+
auto r = fn_(val_, static_cast<X&&>(x));
|
| 400 |
+
return FoldAdaptor<Fn, decltype(r)>{fn_, r};
|
| 401 |
+
}
|
| 402 |
+
Fn fn_;
|
| 403 |
+
Val val_;
|
| 404 |
+
};
|
| 405 |
+
|
| 406 |
+
template <class T, class V, class F, int... Is>
|
| 407 |
+
CUTE_HOST_DEVICE constexpr
|
| 408 |
+
auto
|
| 409 |
+
fold(T&& t, V const& v, F&& f, seq<Is...>)
|
| 410 |
+
{
|
| 411 |
+
return (FoldAdaptor<F,V>{f,v} | ... | get<Is>(static_cast<T&&>(t))).val_;
|
| 412 |
+
}
|
| 413 |
+
|
| 414 |
+
} // end namespace detail
|
| 415 |
+
|
| 416 |
+
template <class T, class V, class F>
|
| 417 |
+
CUTE_HOST_DEVICE constexpr
|
| 418 |
+
auto
|
| 419 |
+
fold(T&& t, V const& v, F&& f)
|
| 420 |
+
{
|
| 421 |
+
if constexpr (is_tuple<remove_cvref_t<T>>::value) {
|
| 422 |
+
return detail::fold(static_cast<T&&>(t), v, f, tuple_seq<T>{});
|
| 423 |
+
} else {
|
| 424 |
+
return f(v, static_cast<T&&>(t));
|
| 425 |
+
}
|
| 426 |
+
|
| 427 |
+
CUTE_GCC_UNREACHABLE;
|
| 428 |
+
}
|
| 429 |
+
|
| 430 |
+
template <class T, class F>
|
| 431 |
+
CUTE_HOST_DEVICE constexpr
|
| 432 |
+
auto
|
| 433 |
+
fold_first(T&& t, F&& f)
|
| 434 |
+
{
|
| 435 |
+
if constexpr (is_tuple<remove_cvref_t<T>>::value) {
|
| 436 |
+
return detail::fold(static_cast<T&&>(t), get<0>(t), f, make_range<1,tuple_size<remove_cvref_t<T>>::value>{});
|
| 437 |
+
} else {
|
| 438 |
+
return t;
|
| 439 |
+
}
|
| 440 |
+
|
| 441 |
+
CUTE_GCC_UNREACHABLE;
|
| 442 |
+
}
|
| 443 |
+
|
| 444 |
+
//
|
| 445 |
+
// front, back, take, select, unwrap
|
| 446 |
+
//
|
| 447 |
+
|
| 448 |
+
// Get the first non-tuple element in a hierarchical tuple
|
| 449 |
+
template <class T>
|
| 450 |
+
CUTE_HOST_DEVICE constexpr
|
| 451 |
+
decltype(auto)
|
| 452 |
+
front(T&& t)
|
| 453 |
+
{
|
| 454 |
+
if constexpr (is_tuple<remove_cvref_t<T>>::value) {
|
| 455 |
+
return front(get<0>(static_cast<T&&>(t)));
|
| 456 |
+
} else {
|
| 457 |
+
return static_cast<T&&>(t);
|
| 458 |
+
}
|
| 459 |
+
|
| 460 |
+
CUTE_GCC_UNREACHABLE;
|
| 461 |
+
}
|
| 462 |
+
|
| 463 |
+
// Get the last non-tuple element in a hierarchical tuple
|
| 464 |
+
template <class T>
|
| 465 |
+
CUTE_HOST_DEVICE constexpr
|
| 466 |
+
decltype(auto)
|
| 467 |
+
back(T&& t)
|
| 468 |
+
{
|
| 469 |
+
if constexpr (is_tuple<remove_cvref_t<T>>::value) {
|
| 470 |
+
constexpr int N = tuple_size<remove_cvref_t<T>>::value;
|
| 471 |
+
|
| 472 |
+
// MSVC needs a bit of extra help here deducing return types.
|
| 473 |
+
// We help it by peeling off the nonrecursive case a level "early."
|
| 474 |
+
if constexpr (! is_tuple<remove_cvref_t<decltype(get<N - 1>(static_cast<T&&>(t)))>>::value) {
|
| 475 |
+
return get<N - 1>(static_cast<T&&>(t));
|
| 476 |
+
} else {
|
| 477 |
+
return back(get<N - 1>(static_cast<T&&>(t)));
|
| 478 |
+
}
|
| 479 |
+
} else {
|
| 480 |
+
return static_cast<T&&>(t);
|
| 481 |
+
}
|
| 482 |
+
|
| 483 |
+
CUTE_GCC_UNREACHABLE;
|
| 484 |
+
}
|
| 485 |
+
|
| 486 |
+
// Takes the elements in the range [B,E)
|
| 487 |
+
template <int B, int E, class T>
|
| 488 |
+
CUTE_HOST_DEVICE constexpr
|
| 489 |
+
auto
|
| 490 |
+
take(T const& t)
|
| 491 |
+
{
|
| 492 |
+
if constexpr (E == -1) {
|
| 493 |
+
if constexpr (is_tuple<T>::value) {
|
| 494 |
+
return take<B,tuple_size<T>::value>(t);
|
| 495 |
+
} else {
|
| 496 |
+
return take<B,1>(t);
|
| 497 |
+
}
|
| 498 |
+
} else
|
| 499 |
+
if constexpr (B <= E) {
|
| 500 |
+
return detail::apply(t, [](auto const&... a) { return cute::make_tuple(a...); }, make_range<B,E>{});
|
| 501 |
+
} else {
|
| 502 |
+
static_assert(B <= E);
|
| 503 |
+
}
|
| 504 |
+
|
| 505 |
+
CUTE_GCC_UNREACHABLE;
|
| 506 |
+
}
|
| 507 |
+
|
| 508 |
+
// Select tuple elements with given indices.
|
| 509 |
+
template <int... I, class T>
|
| 510 |
+
CUTE_HOST_DEVICE constexpr
|
| 511 |
+
auto
|
| 512 |
+
select(T const& t)
|
| 513 |
+
{
|
| 514 |
+
return cute::make_tuple(get<I>(t)...);
|
| 515 |
+
}
|
| 516 |
+
|
| 517 |
+
// Wrap non-tuples into rank-1 tuples or forward
|
| 518 |
+
template <class T>
|
| 519 |
+
CUTE_HOST_DEVICE constexpr
|
| 520 |
+
auto
|
| 521 |
+
wrap(T const& t)
|
| 522 |
+
{
|
| 523 |
+
if constexpr (is_tuple<T>::value) {
|
| 524 |
+
return t;
|
| 525 |
+
} else {
|
| 526 |
+
return cute::make_tuple(t);
|
| 527 |
+
}
|
| 528 |
+
|
| 529 |
+
CUTE_GCC_UNREACHABLE;
|
| 530 |
+
}
|
| 531 |
+
|
| 532 |
+
// Unwrap rank-1 tuples until we're left with a rank>1 tuple or a non-tuple
|
| 533 |
+
template <class T>
|
| 534 |
+
CUTE_HOST_DEVICE constexpr
|
| 535 |
+
auto
|
| 536 |
+
unwrap(T const& t)
|
| 537 |
+
{
|
| 538 |
+
if constexpr (is_tuple<T>::value) {
|
| 539 |
+
if constexpr (tuple_size<T>::value == 1) {
|
| 540 |
+
return unwrap(get<0>(t));
|
| 541 |
+
} else {
|
| 542 |
+
return t;
|
| 543 |
+
}
|
| 544 |
+
} else {
|
| 545 |
+
return t;
|
| 546 |
+
}
|
| 547 |
+
|
| 548 |
+
CUTE_GCC_UNREACHABLE;
|
| 549 |
+
}
|
| 550 |
+
|
| 551 |
+
//
|
| 552 |
+
// Flatten and Unflatten
|
| 553 |
+
//
|
| 554 |
+
|
| 555 |
+
template <class T>
|
| 556 |
+
struct is_flat : true_type {};
|
| 557 |
+
|
| 558 |
+
template <class... Ts>
|
| 559 |
+
struct is_flat<tuple<Ts...>> : bool_constant<(true && ... && (not is_tuple<Ts>::value))> {};
|
| 560 |
+
|
| 561 |
+
// Flatten a hierarchical tuple to a tuple of depth one
|
| 562 |
+
// and wrap non-tuples into a rank-1 tuple.
|
| 563 |
+
template <class T>
|
| 564 |
+
CUTE_HOST_DEVICE constexpr
|
| 565 |
+
auto
|
| 566 |
+
flatten_to_tuple(T const& t)
|
| 567 |
+
{
|
| 568 |
+
if constexpr (is_tuple<T>::value) {
|
| 569 |
+
if constexpr (is_flat<T>::value) { // Shortcut for perf
|
| 570 |
+
return t;
|
| 571 |
+
} else {
|
| 572 |
+
return filter_tuple(t, [](auto const& a) { return flatten_to_tuple(a); });
|
| 573 |
+
}
|
| 574 |
+
} else {
|
| 575 |
+
return cute::make_tuple(t);
|
| 576 |
+
}
|
| 577 |
+
|
| 578 |
+
CUTE_GCC_UNREACHABLE;
|
| 579 |
+
}
|
| 580 |
+
|
| 581 |
+
// Flatten a hierarchical tuple to a tuple of depth one
|
| 582 |
+
// and leave non-tuple untouched.
|
| 583 |
+
template <class T>
|
| 584 |
+
CUTE_HOST_DEVICE constexpr
|
| 585 |
+
auto
|
| 586 |
+
flatten(T const& t)
|
| 587 |
+
{
|
| 588 |
+
if constexpr (is_tuple<T>::value) {
|
| 589 |
+
if constexpr (is_flat<T>::value) { // Shortcut for perf
|
| 590 |
+
return t;
|
| 591 |
+
} else {
|
| 592 |
+
return filter_tuple(t, [](auto const& a) { return flatten_to_tuple(a); });
|
| 593 |
+
}
|
| 594 |
+
} else {
|
| 595 |
+
return t;
|
| 596 |
+
}
|
| 597 |
+
|
| 598 |
+
CUTE_GCC_UNREACHABLE;
|
| 599 |
+
}
|
| 600 |
+
|
| 601 |
+
namespace detail {
|
| 602 |
+
|
| 603 |
+
template <class FlatTuple, class TargetProfile>
|
| 604 |
+
CUTE_HOST_DEVICE constexpr
|
| 605 |
+
auto
|
| 606 |
+
unflatten_impl(FlatTuple const& flat_tuple, TargetProfile const& target_profile)
|
| 607 |
+
{
|
| 608 |
+
if constexpr (is_tuple<TargetProfile>::value) {
|
| 609 |
+
return fold(target_profile, cute::make_tuple(cute::make_tuple(), flat_tuple), [](auto const& v, auto const& t) {
|
| 610 |
+
auto [result, remaining_tuple] = v;
|
| 611 |
+
auto [sub_result, sub_tuple] = unflatten_impl(remaining_tuple, t);
|
| 612 |
+
return cute::make_tuple(append(result, sub_result), sub_tuple);
|
| 613 |
+
});
|
| 614 |
+
} else {
|
| 615 |
+
return cute::make_tuple(get<0>(flat_tuple), take<1, decltype(rank(flat_tuple))::value>(flat_tuple));
|
| 616 |
+
}
|
| 617 |
+
|
| 618 |
+
CUTE_GCC_UNREACHABLE;
|
| 619 |
+
}
|
| 620 |
+
|
| 621 |
+
} // end namespace detail
|
| 622 |
+
|
| 623 |
+
// Unflatten a flat tuple into a hierarchical tuple
|
| 624 |
+
// @pre flatten(@a flat_tuple) == @a flat_tuple
|
| 625 |
+
// @pre rank(flatten(@a target_profile)) == rank(@a flat_tuple)
|
| 626 |
+
// @post congruent(@a result, @a target_profile)
|
| 627 |
+
// @post flatten(@a result) == @a flat_tuple
|
| 628 |
+
template <class FlatTuple, class TargetProfile>
|
| 629 |
+
CUTE_HOST_DEVICE constexpr
|
| 630 |
+
auto
|
| 631 |
+
unflatten(FlatTuple const& flat_tuple, TargetProfile const& target_profile)
|
| 632 |
+
{
|
| 633 |
+
auto [unflatten_tuple, flat_remainder] = detail::unflatten_impl(flat_tuple, target_profile);
|
| 634 |
+
CUTE_STATIC_ASSERT_V(rank(flat_remainder) == Int<0>{});
|
| 635 |
+
return unflatten_tuple;
|
| 636 |
+
}
|
| 637 |
+
|
| 638 |
+
//
|
| 639 |
+
// insert and remove and replace
|
| 640 |
+
//
|
| 641 |
+
|
| 642 |
+
namespace detail {
|
| 643 |
+
|
| 644 |
+
// Shortcut around cute::tuple_cat for common insert/remove/repeat cases
|
| 645 |
+
template <class T, class X, int... I, int... J, int... K>
|
| 646 |
+
CUTE_HOST_DEVICE constexpr
|
| 647 |
+
auto
|
| 648 |
+
construct(T const& t, X const& x, seq<I...>, seq<J...>, seq<K...>)
|
| 649 |
+
{
|
| 650 |
+
return cute::make_tuple(get<I>(t)..., (void(J),x)..., get<K>(t)...);
|
| 651 |
+
}
|
| 652 |
+
|
| 653 |
+
} // end namespace detail
|
| 654 |
+
|
| 655 |
+
// Insert x into the Nth position of the tuple
|
| 656 |
+
template <int N, class T, class X>
|
| 657 |
+
CUTE_HOST_DEVICE constexpr
|
| 658 |
+
auto
|
| 659 |
+
insert(T const& t, X const& x)
|
| 660 |
+
{
|
| 661 |
+
return detail::construct(t, x, make_seq<N>{}, seq<0>{}, make_range<N,tuple_size<T>::value>{});
|
| 662 |
+
}
|
| 663 |
+
|
| 664 |
+
// Remove the Nth element of the tuple
|
| 665 |
+
template <int N, class T>
|
| 666 |
+
CUTE_HOST_DEVICE constexpr
|
| 667 |
+
auto
|
| 668 |
+
remove(T const& t)
|
| 669 |
+
{
|
| 670 |
+
return detail::construct(t, 0, make_seq<N>{}, seq<>{}, make_range<N+1,tuple_size<T>::value>{});
|
| 671 |
+
}
|
| 672 |
+
|
| 673 |
+
// Replace the Nth element of the tuple with x
|
| 674 |
+
template <int N, class T, class X>
|
| 675 |
+
CUTE_HOST_DEVICE constexpr
|
| 676 |
+
auto
|
| 677 |
+
replace(T const& t, X const& x)
|
| 678 |
+
{
|
| 679 |
+
if constexpr (is_tuple<T>::value) {
|
| 680 |
+
return detail::construct(t, x, make_seq<N>{}, seq<0>{}, make_range<N+1,tuple_size<T>::value>{});
|
| 681 |
+
} else {
|
| 682 |
+
static_assert(N == 0);
|
| 683 |
+
return x;
|
| 684 |
+
}
|
| 685 |
+
|
| 686 |
+
CUTE_GCC_UNREACHABLE;
|
| 687 |
+
}
|
| 688 |
+
|
| 689 |
+
// Replace the first element of the tuple with x
|
| 690 |
+
template <class T, class X>
|
| 691 |
+
CUTE_HOST_DEVICE constexpr
|
| 692 |
+
auto
|
| 693 |
+
replace_front(T const& t, X const& x)
|
| 694 |
+
{
|
| 695 |
+
if constexpr (is_tuple<T>::value) {
|
| 696 |
+
return detail::construct(t, x, seq<>{}, seq<0>{}, make_range<1,tuple_size<T>::value>{});
|
| 697 |
+
} else {
|
| 698 |
+
return x;
|
| 699 |
+
}
|
| 700 |
+
|
| 701 |
+
CUTE_GCC_UNREACHABLE;
|
| 702 |
+
}
|
| 703 |
+
|
| 704 |
+
// Replace the last element of the tuple with x
|
| 705 |
+
template <class T, class X>
|
| 706 |
+
CUTE_HOST_DEVICE constexpr
|
| 707 |
+
auto
|
| 708 |
+
replace_back(T const& t, X const& x)
|
| 709 |
+
{
|
| 710 |
+
if constexpr (is_tuple<T>::value) {
|
| 711 |
+
return detail::construct(t, x, make_seq<tuple_size<T>::value-1>{}, seq<0>{}, seq<>{});
|
| 712 |
+
} else {
|
| 713 |
+
return x;
|
| 714 |
+
}
|
| 715 |
+
|
| 716 |
+
CUTE_GCC_UNREACHABLE;
|
| 717 |
+
}
|
| 718 |
+
|
| 719 |
+
//
|
| 720 |
+
// Make a tuple of Xs of tuple_size N
|
| 721 |
+
//
|
| 722 |
+
|
| 723 |
+
template <int N, class X>
|
| 724 |
+
CUTE_HOST_DEVICE constexpr
|
| 725 |
+
auto
|
| 726 |
+
tuple_repeat(X const& x)
|
| 727 |
+
{
|
| 728 |
+
return detail::construct(0, x, seq<>{}, make_seq<N>{}, seq<>{});
|
| 729 |
+
}
|
| 730 |
+
|
| 731 |
+
//
|
| 732 |
+
// Make repeated Xs of rank N
|
| 733 |
+
//
|
| 734 |
+
|
| 735 |
+
template <int N, class X>
|
| 736 |
+
CUTE_HOST_DEVICE constexpr
|
| 737 |
+
auto
|
| 738 |
+
repeat(X const& x)
|
| 739 |
+
{
|
| 740 |
+
if constexpr (N == 1) {
|
| 741 |
+
return x;
|
| 742 |
+
} else {
|
| 743 |
+
return detail::construct(0, x, seq<>{}, make_seq<N>{}, seq<>{});
|
| 744 |
+
}
|
| 745 |
+
|
| 746 |
+
CUTE_GCC_UNREACHABLE;
|
| 747 |
+
}
|
| 748 |
+
|
| 749 |
+
//
|
| 750 |
+
// Make a tuple of Xs the same profile as tuple T
|
| 751 |
+
//
|
| 752 |
+
|
| 753 |
+
template <class T, class X>
|
| 754 |
+
CUTE_HOST_DEVICE constexpr
|
| 755 |
+
auto
|
| 756 |
+
repeat_like(T const& t, X const& x)
|
| 757 |
+
{
|
| 758 |
+
if constexpr (is_tuple<T>::value) {
|
| 759 |
+
return transform(t, [&](auto const& a) { return repeat_like(a,x); });
|
| 760 |
+
} else {
|
| 761 |
+
return x;
|
| 762 |
+
}
|
| 763 |
+
|
| 764 |
+
CUTE_GCC_UNREACHABLE;
|
| 765 |
+
}
|
| 766 |
+
|
| 767 |
+
// Group the elements [B,E) of a T into a single element
|
| 768 |
+
// e.g. group<2,4>(T<_1,_2,_3,_4,_5,_6>{})
|
| 769 |
+
// => T<_1,_2,T<_3,_4>,_5,_6>{}
|
| 770 |
+
template <int B, int E, class T>
|
| 771 |
+
CUTE_HOST_DEVICE constexpr
|
| 772 |
+
auto
|
| 773 |
+
group(T const& t)
|
| 774 |
+
{
|
| 775 |
+
if constexpr (not is_tuple<T>::value) {
|
| 776 |
+
if constexpr (E == -1) {
|
| 777 |
+
return group<B,1>(t);
|
| 778 |
+
} else {
|
| 779 |
+
return detail::construct(t, take<B,E>(t), make_seq<B>{}, make_seq<(B < E)>{}, make_range<E,1>{});
|
| 780 |
+
}
|
| 781 |
+
} else
|
| 782 |
+
if constexpr (E == -1) {
|
| 783 |
+
return group<B,tuple_size<T>::value>(t);
|
| 784 |
+
} else
|
| 785 |
+
if constexpr (B <= E) {
|
| 786 |
+
return detail::construct(t, take<B,E>(t), make_seq<B>{}, make_seq<(B < E)>{}, make_range<E,tuple_size<T>::value>{});
|
| 787 |
+
} else {
|
| 788 |
+
static_assert(B <= E);
|
| 789 |
+
}
|
| 790 |
+
|
| 791 |
+
CUTE_GCC_UNREACHABLE;
|
| 792 |
+
}
|
| 793 |
+
|
| 794 |
+
//
|
| 795 |
+
// Extend a T to rank N by appending/prepending an element
|
| 796 |
+
//
|
| 797 |
+
|
| 798 |
+
template <int N, class T, class X>
|
| 799 |
+
CUTE_HOST_DEVICE constexpr
|
| 800 |
+
auto
|
| 801 |
+
append(T const& a, X const& x)
|
| 802 |
+
{
|
| 803 |
+
if constexpr (is_tuple<T>::value) {
|
| 804 |
+
if constexpr (N == tuple_size<T>::value) {
|
| 805 |
+
return a;
|
| 806 |
+
} else {
|
| 807 |
+
static_assert(N > tuple_size<T>::value);
|
| 808 |
+
return detail::construct(a, x, make_seq<tuple_size<T>::value>{}, make_seq<N-tuple_size<T>::value>{}, seq<>{});
|
| 809 |
+
}
|
| 810 |
+
} else {
|
| 811 |
+
if constexpr (N == 1) {
|
| 812 |
+
return a;
|
| 813 |
+
} else {
|
| 814 |
+
return detail::construct(cute::make_tuple(a), x, seq<0>{}, make_seq<N-1>{}, seq<>{});
|
| 815 |
+
}
|
| 816 |
+
}
|
| 817 |
+
|
| 818 |
+
CUTE_GCC_UNREACHABLE;
|
| 819 |
+
}
|
| 820 |
+
|
| 821 |
+
template <class T, class X>
|
| 822 |
+
CUTE_HOST_DEVICE constexpr
|
| 823 |
+
auto
|
| 824 |
+
append(T const& a, X const& x)
|
| 825 |
+
{
|
| 826 |
+
if constexpr (is_tuple<T>::value) {
|
| 827 |
+
return detail::construct(a, x, make_seq<tuple_size<T>::value>{}, seq<0>{}, seq<>{});
|
| 828 |
+
} else {
|
| 829 |
+
return cute::make_tuple(a, x);
|
| 830 |
+
}
|
| 831 |
+
|
| 832 |
+
CUTE_GCC_UNREACHABLE;
|
| 833 |
+
}
|
| 834 |
+
|
| 835 |
+
template <int N, class T, class X>
|
| 836 |
+
CUTE_HOST_DEVICE constexpr
|
| 837 |
+
auto
|
| 838 |
+
prepend(T const& a, X const& x)
|
| 839 |
+
{
|
| 840 |
+
if constexpr (is_tuple<T>::value) {
|
| 841 |
+
if constexpr (N == tuple_size<T>::value) {
|
| 842 |
+
return a;
|
| 843 |
+
} else {
|
| 844 |
+
static_assert(N > tuple_size<T>::value);
|
| 845 |
+
return detail::construct(a, x, seq<>{}, make_seq<N-tuple_size<T>::value>{}, make_seq<tuple_size<T>::value>{});
|
| 846 |
+
}
|
| 847 |
+
} else {
|
| 848 |
+
if constexpr (N == 1) {
|
| 849 |
+
return a;
|
| 850 |
+
} else {
|
| 851 |
+
static_assert(N > 1);
|
| 852 |
+
return detail::construct(cute::make_tuple(a), x, seq<>{}, make_seq<N-1>{}, seq<0>{});
|
| 853 |
+
}
|
| 854 |
+
}
|
| 855 |
+
|
| 856 |
+
CUTE_GCC_UNREACHABLE;
|
| 857 |
+
}
|
| 858 |
+
|
| 859 |
+
template <class T, class X>
|
| 860 |
+
CUTE_HOST_DEVICE constexpr
|
| 861 |
+
auto
|
| 862 |
+
prepend(T const& a, X const& x)
|
| 863 |
+
{
|
| 864 |
+
if constexpr (is_tuple<T>::value) {
|
| 865 |
+
return detail::construct(a, x, seq<>{}, seq<0>{}, make_seq<tuple_size<T>::value>{});
|
| 866 |
+
} else {
|
| 867 |
+
return cute::make_tuple(x, a);
|
| 868 |
+
}
|
| 869 |
+
|
| 870 |
+
CUTE_GCC_UNREACHABLE;
|
| 871 |
+
}
|
| 872 |
+
|
| 873 |
+
//
|
| 874 |
+
// Inclusive scan (prefix sum)
|
| 875 |
+
//
|
| 876 |
+
|
| 877 |
+
namespace detail {
|
| 878 |
+
|
| 879 |
+
template <class T, class V, class F, int I, int... Is>
|
| 880 |
+
CUTE_HOST_DEVICE constexpr
|
| 881 |
+
auto
|
| 882 |
+
iscan(T const& t, V const& v, F&& f, seq<I,Is...>)
|
| 883 |
+
{
|
| 884 |
+
// Apply the function to v and the element at I
|
| 885 |
+
auto v_next = f(v, get<I>(t));
|
| 886 |
+
// Replace I with v_next
|
| 887 |
+
auto t_next = replace<I>(t, v_next);
|
| 888 |
+
|
| 889 |
+
#if 0
|
| 890 |
+
std::cout << "ISCAN i" << I << std::endl;
|
| 891 |
+
std::cout << " t " << t << std::endl;
|
| 892 |
+
std::cout << " i " << v << std::endl;
|
| 893 |
+
std::cout << " f(i,t) " << v_next << std::endl;
|
| 894 |
+
std::cout << " t_n " << t_next << std::endl;
|
| 895 |
+
#endif
|
| 896 |
+
|
| 897 |
+
if constexpr (sizeof...(Is) == 0) {
|
| 898 |
+
return t_next;
|
| 899 |
+
} else {
|
| 900 |
+
return iscan(t_next, v_next, f, seq<Is...>{});
|
| 901 |
+
}
|
| 902 |
+
|
| 903 |
+
CUTE_GCC_UNREACHABLE;
|
| 904 |
+
}
|
| 905 |
+
|
| 906 |
+
} // end namespace detail
|
| 907 |
+
|
| 908 |
+
template <class T, class V, class F>
|
| 909 |
+
CUTE_HOST_DEVICE constexpr
|
| 910 |
+
auto
|
| 911 |
+
iscan(T const& t, V const& v, F&& f)
|
| 912 |
+
{
|
| 913 |
+
return detail::iscan(t, v, f, tuple_seq<T>{});
|
| 914 |
+
}
|
| 915 |
+
|
| 916 |
+
//
|
| 917 |
+
// Exclusive scan (prefix sum)
|
| 918 |
+
//
|
| 919 |
+
|
| 920 |
+
namespace detail {
|
| 921 |
+
|
| 922 |
+
template <class T, class V, class F, int I, int... Is>
|
| 923 |
+
CUTE_HOST_DEVICE constexpr
|
| 924 |
+
auto
|
| 925 |
+
escan(T const& t, V const& v, F&& f, seq<I,Is...>)
|
| 926 |
+
{
|
| 927 |
+
if constexpr (sizeof...(Is) == 0) {
|
| 928 |
+
// Replace I with v
|
| 929 |
+
return replace<I>(t, v);
|
| 930 |
+
} else {
|
| 931 |
+
// Apply the function to v and the element at I
|
| 932 |
+
auto v_next = f(v, get<I>(t));
|
| 933 |
+
// Replace I with v
|
| 934 |
+
auto t_next = replace<I>(t, v);
|
| 935 |
+
|
| 936 |
+
#if 0
|
| 937 |
+
std::cout << "ESCAN i" << I << std::endl;
|
| 938 |
+
std::cout << " t " << t << std::endl;
|
| 939 |
+
std::cout << " i " << v << std::endl;
|
| 940 |
+
std::cout << " f(i,t) " << v_next << std::endl;
|
| 941 |
+
std::cout << " t_n " << t_next << std::endl;
|
| 942 |
+
#endif
|
| 943 |
+
|
| 944 |
+
// Recurse
|
| 945 |
+
return escan(t_next, v_next, f, seq<Is...>{});
|
| 946 |
+
}
|
| 947 |
+
|
| 948 |
+
CUTE_GCC_UNREACHABLE;
|
| 949 |
+
}
|
| 950 |
+
|
| 951 |
+
} // end namespace detail
|
| 952 |
+
|
| 953 |
+
template <class T, class V, class F>
|
| 954 |
+
CUTE_HOST_DEVICE constexpr
|
| 955 |
+
auto
|
| 956 |
+
escan(T const& t, V const& v, F&& f)
|
| 957 |
+
{
|
| 958 |
+
return detail::escan(t, v, f, tuple_seq<T>{});
|
| 959 |
+
}
|
| 960 |
+
|
| 961 |
+
//
|
| 962 |
+
// Zip (Transpose)
|
| 963 |
+
//
|
| 964 |
+
|
| 965 |
+
// Take ((a,b,c,...),(x,y,z,...),...) rank-R0 x rank-R1 input
|
| 966 |
+
// to produce ((a,x,...),(b,y,...),(c,z,...),...) rank-R1 x rank-R0 output
|
| 967 |
+
|
| 968 |
+
namespace detail {
|
| 969 |
+
|
| 970 |
+
template <int J, class... Ts>
|
| 971 |
+
CUTE_HOST_DEVICE constexpr
|
| 972 |
+
auto
|
| 973 |
+
zip_(Ts const&... ts)
|
| 974 |
+
{
|
| 975 |
+
return cute::make_tuple(get<J>(ts)...);
|
| 976 |
+
}
|
| 977 |
+
|
| 978 |
+
template <class T, int... Is, int... Js>
|
| 979 |
+
CUTE_HOST_DEVICE constexpr
|
| 980 |
+
auto
|
| 981 |
+
zip(T const& t, seq<Is...>, seq<Js...>)
|
| 982 |
+
{
|
| 983 |
+
static_assert(conjunction<bool_constant<tuple_size<tuple_element_t<0,T>>::value == tuple_size<tuple_element_t<Is,T>>::value>...>::value, "Mismatched Ranks");
|
| 984 |
+
return cute::make_tuple(zip_<Js>(get<Is>(t)...)...);
|
| 985 |
+
}
|
| 986 |
+
|
| 987 |
+
} // end namespace detail
|
| 988 |
+
|
| 989 |
+
template <class T>
|
| 990 |
+
CUTE_HOST_DEVICE constexpr
|
| 991 |
+
auto
|
| 992 |
+
zip(T const& t)
|
| 993 |
+
{
|
| 994 |
+
if constexpr (is_tuple<T>::value) {
|
| 995 |
+
if constexpr (is_tuple<tuple_element_t<0,T>>::value) {
|
| 996 |
+
return detail::zip(t, tuple_seq<T>{}, tuple_seq<tuple_element_t<0,T>>{});
|
| 997 |
+
} else {
|
| 998 |
+
return cute::make_tuple(t);
|
| 999 |
+
}
|
| 1000 |
+
} else {
|
| 1001 |
+
return t;
|
| 1002 |
+
}
|
| 1003 |
+
|
| 1004 |
+
CUTE_GCC_UNREACHABLE;
|
| 1005 |
+
}
|
| 1006 |
+
|
| 1007 |
+
// Convenient to pass them in separately
|
| 1008 |
+
template <class T0, class T1, class... Ts>
|
| 1009 |
+
CUTE_HOST_DEVICE constexpr
|
| 1010 |
+
auto
|
| 1011 |
+
zip(T0 const& t0, T1 const& t1, Ts const&... ts)
|
| 1012 |
+
{
|
| 1013 |
+
return zip(cute::make_tuple(t0, t1, ts...));
|
| 1014 |
+
}
|
| 1015 |
+
|
| 1016 |
+
//
|
| 1017 |
+
// zip2_by -- A guided zip for rank-2 tuples
|
| 1018 |
+
// Take a tuple like ((A,a),((B,b),(C,c)),d)
|
| 1019 |
+
// and produce a tuple ((A,(B,C)),(a,(b,c),d))
|
| 1020 |
+
// where the rank-2 modes are selected by the terminals of the guide (X,(X,X))
|
| 1021 |
+
//
|
| 1022 |
+
|
| 1023 |
+
namespace detail {
|
| 1024 |
+
|
| 1025 |
+
template <class T, class TG, int... Is, int... Js>
|
| 1026 |
+
CUTE_HOST_DEVICE constexpr
|
| 1027 |
+
auto
|
| 1028 |
+
zip2_by(T const& t, TG const& guide, seq<Is...>, seq<Js...>)
|
| 1029 |
+
{
|
| 1030 |
+
// zip2_by produces the modes like ((A,a),(B,b),...)
|
| 1031 |
+
auto split = cute::make_tuple(zip2_by(get<Is>(t), get<Is>(guide))...);
|
| 1032 |
+
|
| 1033 |
+
// Rearrange and append missing modes from t to make ((A,B,...),(a,b,...,x,y))
|
| 1034 |
+
return cute::make_tuple(cute::make_tuple(get<0>(get<Is>(split))...),
|
| 1035 |
+
cute::make_tuple(get<1>(get<Is>(split))..., get<Js>(t)...));
|
| 1036 |
+
}
|
| 1037 |
+
|
| 1038 |
+
} // end namespace detail
|
| 1039 |
+
|
| 1040 |
+
template <class T, class TG>
|
| 1041 |
+
CUTE_HOST_DEVICE constexpr
|
| 1042 |
+
auto
|
| 1043 |
+
zip2_by(T const& t, TG const& guide)
|
| 1044 |
+
{
|
| 1045 |
+
if constexpr (is_tuple<TG>::value) {
|
| 1046 |
+
constexpr int TR = tuple_size<T>::value;
|
| 1047 |
+
constexpr int GR = tuple_size<TG>::value;
|
| 1048 |
+
static_assert(TR >= GR, "Mismatched ranks");
|
| 1049 |
+
return detail::zip2_by(t, guide,
|
| 1050 |
+
make_range< 0, GR>{},
|
| 1051 |
+
make_range<GR, TR>{});
|
| 1052 |
+
} else {
|
| 1053 |
+
static_assert(tuple_size<T>::value == 2, "Mismatched ranks");
|
| 1054 |
+
return t;
|
| 1055 |
+
}
|
| 1056 |
+
|
| 1057 |
+
CUTE_GCC_UNREACHABLE;
|
| 1058 |
+
}
|
| 1059 |
+
|
| 1060 |
+
/// @return A tuple of the elements of @c t in reverse order.
|
| 1061 |
+
template <class T>
|
| 1062 |
+
CUTE_HOST_DEVICE constexpr
|
| 1063 |
+
auto
|
| 1064 |
+
reverse(T const& t)
|
| 1065 |
+
{
|
| 1066 |
+
if constexpr (is_tuple<T>::value) {
|
| 1067 |
+
return detail::apply(t, [](auto const&... a){ return cute::make_tuple(a...); }, tuple_rseq<T>{});
|
| 1068 |
+
} else {
|
| 1069 |
+
return t;
|
| 1070 |
+
}
|
| 1071 |
+
}
|
| 1072 |
+
|
| 1073 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/cluster_sm100.hpp
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
|
| 32 |
+
//
|
| 33 |
+
|
| 34 |
+
//
|
| 35 |
+
|
| 36 |
+
#pragma once
|
| 37 |
+
|
| 38 |
+
#include <cute/config.hpp>
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
namespace cute {
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
//
|
| 45 |
+
// Cluster launch utility
|
| 46 |
+
//
|
| 47 |
+
CUTE_HOST
|
| 48 |
+
bool
|
| 49 |
+
initialize_preferred_cluster_launch(void const* const kernel_function,
|
| 50 |
+
dim3 const& grid_dims,
|
| 51 |
+
dim3 const& cluster_dims_preferred,
|
| 52 |
+
dim3 const& cluster_dims_fallback)
|
| 53 |
+
{
|
| 54 |
+
//
|
| 55 |
+
// Validate cluster_dims
|
| 56 |
+
//
|
| 57 |
+
|
| 58 |
+
// Total number of cluster cannot be greater than 32 (hardware requirement)
|
| 59 |
+
if (cluster_dims_preferred.x * cluster_dims_preferred.y * cluster_dims_preferred.z <= 0 ||
|
| 60 |
+
cluster_dims_preferred.x * cluster_dims_preferred.y * cluster_dims_preferred.z > 32) {
|
| 61 |
+
std::cout << "Invalid preferred cluster dimensions: Attempting to init preferred cluster (" << cluster_dims_preferred.x << "," << cluster_dims_preferred.y << "," << cluster_dims_preferred.z
|
| 62 |
+
<< ") [" << (cluster_dims_preferred.x * cluster_dims_preferred.y * cluster_dims_preferred.z) << "] which must be within (0,32]." << std::endl;
|
| 63 |
+
return false;
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
// Total number of cluster cannot be greater than 32 (hardware requirement)
|
| 67 |
+
if (cluster_dims_fallback.x * cluster_dims_fallback.y * cluster_dims_fallback.z <= 0 ||
|
| 68 |
+
cluster_dims_fallback.x * cluster_dims_fallback.y * cluster_dims_fallback.z > 32) {
|
| 69 |
+
std::cout << "Invalid cluster dimensions: Attempting to init fallback cluster (" << cluster_dims_fallback.x << "," << cluster_dims_fallback.y << "," << cluster_dims_fallback.z
|
| 70 |
+
<< ") [" << (cluster_dims_fallback.x * cluster_dims_fallback.y * cluster_dims_fallback.z) << "] which must be within (0,32]." << std::endl;
|
| 71 |
+
return false;
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
// Total grid dimensions must be within (2^32, 2^16, 2^16)
|
| 75 |
+
if (grid_dims.y > (1 << 16) || grid_dims.z > (1 << 16)) {
|
| 76 |
+
std::cout << "Invalid grid dimensions: Attempting to init grid dimensions (" << grid_dims.x << "," << grid_dims.y << "," << grid_dims.z
|
| 77 |
+
<< ") which must be within (2^32, 2^16, 2^16)." << std::endl;
|
| 78 |
+
return false;
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
// grid_dims should be divisible by cluster_dims_preferred
|
| 82 |
+
if (grid_dims.x % cluster_dims_preferred.x != 0 ||
|
| 83 |
+
grid_dims.y % cluster_dims_preferred.y != 0 ||
|
| 84 |
+
grid_dims.z % cluster_dims_preferred.z != 0) {
|
| 85 |
+
std::cout << "Invalid grid dimensions: Preferred cluster (" << cluster_dims_preferred.x << "," << cluster_dims_preferred.y << "," << cluster_dims_preferred.z
|
| 86 |
+
<< ") does not divide Grid (" << grid_dims.x << "," << grid_dims.y << "," << grid_dims.z << ")." << std::endl;
|
| 87 |
+
return false;
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
// cluster_dims_preferred should be divisible by cluster_dims_fallback
|
| 91 |
+
if (cluster_dims_preferred.x % cluster_dims_fallback.x != 0 ||
|
| 92 |
+
cluster_dims_preferred.y % cluster_dims_fallback.y != 0 ||
|
| 93 |
+
cluster_dims_preferred.z % cluster_dims_fallback.z != 0) {
|
| 94 |
+
std::cout << "Invalid cluster dimensions: Fallback cluster (" << cluster_dims_fallback.x << "," << cluster_dims_fallback.y << "," << cluster_dims_fallback.z
|
| 95 |
+
<< ") does not divide Preferred cluster (" << cluster_dims_preferred.x << "," << cluster_dims_preferred.y << "," << cluster_dims_preferred.z << ")." << std::endl;
|
| 96 |
+
return false;
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
// Both cluster dimenions should have the same depth
|
| 100 |
+
if (cluster_dims_preferred.z != cluster_dims_fallback.z) {
|
| 101 |
+
std::cout << "Invalid cluster dimensions: Fallback cluster (" << cluster_dims_fallback.x << "," << cluster_dims_fallback.y << "," << cluster_dims_fallback.z
|
| 102 |
+
<< ") and Preferred cluster (" << cluster_dims_preferred.x << "," << cluster_dims_preferred.y << "," << cluster_dims_preferred.z << ") does not have the same depth." << std::endl;
|
| 103 |
+
return false;
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
return true;
|
| 107 |
+
}
|
| 108 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/cluster_sm90.hpp
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/config.hpp>
|
| 34 |
+
|
| 35 |
+
// Config
|
| 36 |
+
#if (defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 900) && \
|
| 37 |
+
((__CUDACC_VER_MAJOR__ >= 12) || ((__CUDACC_VER_MAJOR__ == 11) && (__CUDACC_VER_MINOR__ >= 8))))
|
| 38 |
+
# define CUTE_ARCH_CLUSTER_SM90_ENABLED
|
| 39 |
+
#endif
|
| 40 |
+
|
| 41 |
+
#if (defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 900) && (__CUDACC_VER_MAJOR__ >= 12))
|
| 42 |
+
# define CUTE_ARCH_ELECT_ONE_SM90_ENABLED
|
| 43 |
+
#endif
|
| 44 |
+
|
| 45 |
+
namespace cute {
|
| 46 |
+
|
| 47 |
+
CUTE_DEVICE void cluster_arrive_relaxed()
|
| 48 |
+
{
|
| 49 |
+
#if defined(CUTE_ARCH_CLUSTER_SM90_ENABLED)
|
| 50 |
+
asm volatile("barrier.cluster.arrive.relaxed.aligned;\n" : : );
|
| 51 |
+
#else
|
| 52 |
+
CUTE_INVALID_CONTROL_PATH("CUTE_ARCH_CLUSTER_SM90_ENABLED is not defined");
|
| 53 |
+
#endif
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
CUTE_DEVICE void cluster_arrive()
|
| 57 |
+
{
|
| 58 |
+
#if defined(CUTE_ARCH_CLUSTER_SM90_ENABLED)
|
| 59 |
+
asm volatile("barrier.cluster.arrive.aligned;\n" : : );
|
| 60 |
+
#else
|
| 61 |
+
CUTE_INVALID_CONTROL_PATH("CUTE_ARCH_CLUSTER_SM90_ENABLED is not defined");
|
| 62 |
+
#endif
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
CUTE_DEVICE void cluster_wait()
|
| 66 |
+
{
|
| 67 |
+
#if defined(CUTE_ARCH_CLUSTER_SM90_ENABLED)
|
| 68 |
+
asm volatile("barrier.cluster.wait.aligned;\n" : : );
|
| 69 |
+
#else
|
| 70 |
+
CUTE_INVALID_CONTROL_PATH("CUTE_ARCH_CLUSTER_SM90_ENABLED is not defined");
|
| 71 |
+
#endif
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
CUTE_DEVICE void cluster_sync()
|
| 75 |
+
{
|
| 76 |
+
#if defined(CUTE_ARCH_CLUSTER_SM90_ENABLED)
|
| 77 |
+
cluster_arrive();
|
| 78 |
+
cluster_wait();
|
| 79 |
+
#else
|
| 80 |
+
CUTE_INVALID_CONTROL_PATH("CUTE_ARCH_CLUSTER_SM90_ENABLED is not defined");
|
| 81 |
+
#endif
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
// Returns the dim3 grid size in terms of number of clusters.
|
| 85 |
+
CUTE_DEVICE dim3 cluster_grid_dims()
|
| 86 |
+
{
|
| 87 |
+
#if defined(CUTE_ARCH_CLUSTER_SM90_ENABLED)
|
| 88 |
+
uint32_t x, y, z;
|
| 89 |
+
asm volatile("mov.u32 %0, %%nclusterid.x;\n" : "=r"(x) : );
|
| 90 |
+
asm volatile("mov.u32 %0, %%nclusterid.y;\n" : "=r"(y) : );
|
| 91 |
+
asm volatile("mov.u32 %0, %%nclusterid.z;\n" : "=r"(z) : );
|
| 92 |
+
return {x, y, z};
|
| 93 |
+
#elif defined(__CUDA_ARCH__)
|
| 94 |
+
// MSVC requires protecting use of gridDim with __CUDA_ARCH__.
|
| 95 |
+
return gridDim;
|
| 96 |
+
#elif defined(_MSC_VER)
|
| 97 |
+
CUTE_INVALID_CONTROL_PATH("cluster_grid_dims() can only be called on device");
|
| 98 |
+
return {0, 0, 0};
|
| 99 |
+
#else
|
| 100 |
+
return {0, 0, 0};
|
| 101 |
+
#endif
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
// Returns the dim3 cluster rank in the grid.
|
| 105 |
+
CUTE_DEVICE dim3 cluster_id_in_grid()
|
| 106 |
+
{
|
| 107 |
+
#if defined(CUTE_ARCH_CLUSTER_SM90_ENABLED)
|
| 108 |
+
uint32_t x, y, z;
|
| 109 |
+
asm volatile("mov.u32 %0, %%clusterid.x;\n" : "=r"(x) : );
|
| 110 |
+
asm volatile("mov.u32 %0, %%clusterid.y;\n" : "=r"(y) : );
|
| 111 |
+
asm volatile("mov.u32 %0, %%clusterid.z;\n" : "=r"(z) : );
|
| 112 |
+
return {x, y, z};
|
| 113 |
+
#elif defined(__CUDA_ARCH__)
|
| 114 |
+
// MSVC requires protecting use of blockIdx with __CUDA_ARCH__.
|
| 115 |
+
return blockIdx;
|
| 116 |
+
#elif defined(_MSC_VER)
|
| 117 |
+
CUTE_INVALID_CONTROL_PATH("cluster_id_in_grid() can only be called on device");
|
| 118 |
+
return {0, 0, 0};
|
| 119 |
+
#else
|
| 120 |
+
return {0, 0, 0};
|
| 121 |
+
#endif
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
// Returns the relative dim3 block rank local to the cluster.
|
| 125 |
+
CUTE_DEVICE dim3 block_id_in_cluster()
|
| 126 |
+
{
|
| 127 |
+
#if defined(CUTE_ARCH_CLUSTER_SM90_ENABLED)
|
| 128 |
+
uint32_t x, y, z;
|
| 129 |
+
asm volatile("mov.u32 %0, %%cluster_ctaid.x;\n" : "=r"(x) : );
|
| 130 |
+
asm volatile("mov.u32 %0, %%cluster_ctaid.y;\n" : "=r"(y) : );
|
| 131 |
+
asm volatile("mov.u32 %0, %%cluster_ctaid.z;\n" : "=r"(z) : );
|
| 132 |
+
return {x, y, z};
|
| 133 |
+
#else
|
| 134 |
+
return {0,0,0};
|
| 135 |
+
#endif
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
// Returns the dim3 cluster shape.
|
| 139 |
+
CUTE_DEVICE dim3 cluster_shape()
|
| 140 |
+
{
|
| 141 |
+
#if defined(CUTE_ARCH_CLUSTER_SM90_ENABLED)
|
| 142 |
+
uint32_t x, y, z;
|
| 143 |
+
asm volatile("mov.u32 %0, %%cluster_nctaid.x;\n" : "=r"(x) : );
|
| 144 |
+
asm volatile("mov.u32 %0, %%cluster_nctaid.y;\n" : "=r"(y) : );
|
| 145 |
+
asm volatile("mov.u32 %0, %%cluster_nctaid.z;\n" : "=r"(z) : );
|
| 146 |
+
return {x, y, z};
|
| 147 |
+
#else
|
| 148 |
+
return {1,1,1};
|
| 149 |
+
#endif
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
// Get 1D ctaid in a cluster.
|
| 153 |
+
CUTE_DEVICE uint32_t block_rank_in_cluster()
|
| 154 |
+
{
|
| 155 |
+
#if defined(CUTE_ARCH_CLUSTER_SM90_ENABLED)
|
| 156 |
+
uint32_t rank;
|
| 157 |
+
asm volatile("mov.u32 %0, %%cluster_ctarank;\n" : "=r"(rank) :);
|
| 158 |
+
return rank;
|
| 159 |
+
#else
|
| 160 |
+
return 0;
|
| 161 |
+
#endif
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
// Set the destination block-ID in cluster for a given SMEM Address
|
| 165 |
+
CUTE_DEVICE uint32_t set_block_rank(uint32_t smemAddr, uint32_t rank)
|
| 166 |
+
{
|
| 167 |
+
#if defined(CUTE_ARCH_CLUSTER_SM90_ENABLED)
|
| 168 |
+
uint32_t result;
|
| 169 |
+
asm volatile("mapa.shared::cluster.u32 %0, %1, %2;\n"
|
| 170 |
+
: "=r"(result)
|
| 171 |
+
: "r"(smemAddr), "r"(rank));
|
| 172 |
+
return result;
|
| 173 |
+
#else
|
| 174 |
+
return smemAddr;
|
| 175 |
+
#endif
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
// Elect one thread in the warp. The elected thread gets its predicate set to true, all others obtain false.
|
| 179 |
+
CUTE_HOST_DEVICE uint32_t elect_one_sync()
|
| 180 |
+
{
|
| 181 |
+
#if defined(CUTE_ARCH_ELECT_ONE_SM90_ENABLED)
|
| 182 |
+
uint32_t pred = 0;
|
| 183 |
+
uint32_t laneid = 0;
|
| 184 |
+
asm volatile(
|
| 185 |
+
"{\n"
|
| 186 |
+
".reg .b32 %%rx;\n"
|
| 187 |
+
".reg .pred %%px;\n"
|
| 188 |
+
" elect.sync %%rx|%%px, %2;\n"
|
| 189 |
+
"@%%px mov.s32 %1, 1;\n"
|
| 190 |
+
" mov.s32 %0, %%rx;\n"
|
| 191 |
+
"}\n"
|
| 192 |
+
: "+r"(laneid), "+r"(pred)
|
| 193 |
+
: "r"(0xFFFFFFFF));
|
| 194 |
+
return pred;
|
| 195 |
+
#elif defined(__CUDA_ARCH__)
|
| 196 |
+
return (threadIdx.x % 32) == 0;
|
| 197 |
+
#else
|
| 198 |
+
return true;
|
| 199 |
+
#endif
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
struct ElectOneLaneIdReturnType {
|
| 203 |
+
uint32_t is_leader;
|
| 204 |
+
uint32_t leader_lane_id;
|
| 205 |
+
};
|
| 206 |
+
|
| 207 |
+
CUTE_HOST_DEVICE
|
| 208 |
+
ElectOneLaneIdReturnType
|
| 209 |
+
elect_one_leader_sync()
|
| 210 |
+
{
|
| 211 |
+
#if defined(CUTE_ARCH_ELECT_ONE_SM90_ENABLED)
|
| 212 |
+
uint32_t pred = 0;
|
| 213 |
+
uint32_t laneid = 0;
|
| 214 |
+
asm volatile(
|
| 215 |
+
"{\n"
|
| 216 |
+
".reg .b32 %%rx;\n"
|
| 217 |
+
".reg .pred %%px;\n"
|
| 218 |
+
" elect.sync %%rx|%%px, %2;\n"
|
| 219 |
+
"@%%px mov.s32 %1, 1;\n"
|
| 220 |
+
" mov.s32 %0, %%rx;\n"
|
| 221 |
+
"}\n"
|
| 222 |
+
: "+r"(laneid), "+r"(pred)
|
| 223 |
+
: "r"(0xFFFFFFFF));
|
| 224 |
+
return {pred, laneid};
|
| 225 |
+
#elif defined(__CUDA_ARCH__)
|
| 226 |
+
return {(threadIdx.x % 32) == 0, 0};
|
| 227 |
+
#else
|
| 228 |
+
return {true, 0};
|
| 229 |
+
#endif
|
| 230 |
+
}
|
| 231 |
+
|
| 232 |
+
// Store value to remote shared memory in the cluster
|
| 233 |
+
CUTE_DEVICE
|
| 234 |
+
void
|
| 235 |
+
store_shared_remote(uint32_t value, uint32_t smem_addr, uint32_t mbarrier_addr, uint32_t dst_cta_rank)
|
| 236 |
+
{
|
| 237 |
+
#if defined(CUTE_ARCH_CLUSTER_SM90_ENABLED)
|
| 238 |
+
uint32_t dsmem_addr = set_block_rank(smem_addr, dst_cta_rank);
|
| 239 |
+
uint32_t remote_barrier_addr = set_block_rank(mbarrier_addr, dst_cta_rank);
|
| 240 |
+
asm volatile("st.async.shared::cluster.mbarrier::complete_tx::bytes.u32 [%0], %1, [%2];"
|
| 241 |
+
: : "r"(dsmem_addr), "r"(value), "r"(remote_barrier_addr));
|
| 242 |
+
#endif
|
| 243 |
+
}
|
| 244 |
+
|
| 245 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/config.hpp
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2024 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cutlass/arch/config.h> // CUTLASS_ARCH_MMA_SMxx_ENABLED
|
| 34 |
+
|
| 35 |
+
// MMA SM90A
|
| 36 |
+
#if defined(CUTLASS_ARCH_MMA_SM90A_ENABLED)
|
| 37 |
+
# define CUTE_ARCH_MMA_SM90A_ENABLED
|
| 38 |
+
#endif
|
| 39 |
+
|
| 40 |
+
// TMA instructions
|
| 41 |
+
#if defined(CUTLASS_ARCH_MMA_SM90_ENABLED)
|
| 42 |
+
# define CUTE_ARCH_TMA_SM90_ENABLED
|
| 43 |
+
#endif
|
| 44 |
+
|
| 45 |
+
#if defined(CUTLASS_ARCH_MMA_MODIFIABLE_TMA_SM90_ENABLED)
|
| 46 |
+
# define CUTE_ARCH_DEVICE_MODIFIABLE_TMA_SM90_ENABLED
|
| 47 |
+
#endif
|
| 48 |
+
|
| 49 |
+
// STSM
|
| 50 |
+
#if defined(CUTLASS_ARCH_MMA_SM90_ENABLED)
|
| 51 |
+
# define CUTE_ARCH_STSM_SM90_ENABLED
|
| 52 |
+
#endif
|
| 53 |
+
|
| 54 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 55 |
+
|
| 56 |
+
#if (defined(CUTLASS_ARCH_MMA_SM100A_ENABLED) || defined(CUTLASS_ARCH_MMA_SM101A_ENABLED) ||\
|
| 57 |
+
defined(CUTLASS_ARCH_MMA_SM120A_ENABLED))
|
| 58 |
+
# define CUTE_ARCH_TMA_SM90_ENABLED
|
| 59 |
+
# define CUTE_ARCH_DEVICE_MODIFIABLE_TMA_SM90_ENABLED
|
| 60 |
+
# define CUTE_ARCH_STSM_SM90_ENABLED
|
| 61 |
+
#endif
|
| 62 |
+
|
| 63 |
+
#if (defined(CUTLASS_ARCH_MMA_SM100A_ENABLED) || defined(CUTLASS_ARCH_MMA_SM101A_ENABLED))
|
| 64 |
+
# define CUTE_ARCH_TCGEN05_TF32_MMA_ENABLED
|
| 65 |
+
# define CUTE_ARCH_TCGEN05_F16F32_MMA_ENABLED
|
| 66 |
+
# define CUTE_ARCH_TCGEN05_MXF8F6F4_MMA_ENABLED
|
| 67 |
+
# define CUTE_ARCH_TCGEN05_MXF4_MMA_ENABLED
|
| 68 |
+
# define CUTE_ARCH_TCGEN05_MXF4NVF4_MMA_ENABLED
|
| 69 |
+
#endif
|
| 70 |
+
|
| 71 |
+
#if defined(CUTLASS_ARCH_MMA_SM100A_ENABLED)
|
| 72 |
+
# define CUTE_ARCH_TCGEN05_F16BF16_MMA_SCALED_ENABLED
|
| 73 |
+
#endif
|
| 74 |
+
|
| 75 |
+
#if (defined(CUTLASS_ARCH_MMA_SM100A_ENABLED) || defined(CUTLASS_ARCH_MMA_SM101A_ENABLED))
|
| 76 |
+
# define CUTE_ARCH_TCGEN05_S8_MMA_ENABLED
|
| 77 |
+
#endif
|
| 78 |
+
|
| 79 |
+
#if (defined(CUTLASS_ARCH_MMA_SM100A_ENABLED) || defined(CUTLASS_ARCH_MMA_SM101A_ENABLED) ||\
|
| 80 |
+
defined(CUTLASS_ARCH_MMA_SM120A_ENABLED))
|
| 81 |
+
# define CUTE_ARCH_LDSM_SM100A_ENABLED
|
| 82 |
+
# define CUTE_ARCH_STSM_SM100A_ENABLED
|
| 83 |
+
#endif
|
| 84 |
+
|
| 85 |
+
#if (defined(CUTLASS_ARCH_MMA_SM100A_ENABLED) || defined(CUTLASS_ARCH_MMA_SM101A_ENABLED))
|
| 86 |
+
# define CUTE_ARCH_TCGEN05_TMEM_ENABLED
|
| 87 |
+
#endif
|
| 88 |
+
|
| 89 |
+
#if (defined(CUTLASS_ARCH_MMA_SM100A_ENABLED) || defined(CUTLASS_ARCH_MMA_SM101A_ENABLED))
|
| 90 |
+
# define CUTE_ARCH_TMA_SM100_ENABLED
|
| 91 |
+
#endif
|
| 92 |
+
|
| 93 |
+
// {add, mul, fma}.f32x2 PTX
|
| 94 |
+
#if (defined(CUTLASS_ARCH_MMA_SM100A_ENABLED))
|
| 95 |
+
#define CUTE_ARCH_FLOAT2_MATH_ENABLED
|
| 96 |
+
#endif
|
| 97 |
+
|
| 98 |
+
#if defined(CUTLASS_ARCH_MMA_SM120_ENABLED) || defined(CUTLASS_ARCH_MMA_SM120A_ENABLED)
|
| 99 |
+
# define CUTE_ARCH_MMA_SM120_ENABLED
|
| 100 |
+
# define CUTE_ARCH_TMA_SM120_ENABLED
|
| 101 |
+
#endif
|
| 102 |
+
|
| 103 |
+
#if defined(CUTLASS_ARCH_MMA_SM120_ENABLED) || defined(CUTLASS_ARCH_MMA_SM120A_ENABLED)
|
| 104 |
+
# if (__CUDACC_VER_MAJOR__ > 12 || (__CUDACC_VER_MAJOR__ == 12 && __CUDACC_VER_MINOR__ >= 8))
|
| 105 |
+
# define CUTE_ARCH_F8F6F4_MMA_ENABLED
|
| 106 |
+
# define CUTE_ARCH_MXF8F6F4_MMA_ENABLED
|
| 107 |
+
# define CUTE_ARCH_MXF4NVF4_2X_UE8M0_MMA_ENABLED
|
| 108 |
+
# define CUTE_ARCH_MXF4NVF4_4X_UE4M3_MMA_ENABLED
|
| 109 |
+
# endif
|
| 110 |
+
#endif
|
| 111 |
+
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/copy.hpp
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/config.hpp>
|
| 34 |
+
|
| 35 |
+
#include <cute/arch/util.hpp>
|
| 36 |
+
#include <cute/numeric/numeric_types.hpp>
|
| 37 |
+
|
| 38 |
+
namespace cute
|
| 39 |
+
{
|
| 40 |
+
|
| 41 |
+
//
|
| 42 |
+
// Direct Copy for any specific types
|
| 43 |
+
//
|
| 44 |
+
|
| 45 |
+
template <class S, class D = S>
|
| 46 |
+
struct UniversalCopy
|
| 47 |
+
{
|
| 48 |
+
using SRegisters = S[1];
|
| 49 |
+
using DRegisters = D[1];
|
| 50 |
+
|
| 51 |
+
// Sanity
|
| 52 |
+
static_assert(sizeof_bits_v<S> >= 8);
|
| 53 |
+
static_assert(sizeof_bits_v<D> >= 8);
|
| 54 |
+
|
| 55 |
+
CUTE_HOST_DEVICE static constexpr void
|
| 56 |
+
copy(S const& src,
|
| 57 |
+
D & dst)
|
| 58 |
+
{
|
| 59 |
+
dst = src;
|
| 60 |
+
}
|
| 61 |
+
};
|
| 62 |
+
|
| 63 |
+
//
|
| 64 |
+
// Placeholder for the copy algorithm's stronger auto-vectorizing behavior
|
| 65 |
+
// that assumes alignment of pointers and dynamic layouts up to MaxVecBits
|
| 66 |
+
//
|
| 67 |
+
|
| 68 |
+
template <int MaxVecBits = 128>
|
| 69 |
+
struct AutoVectorizingCopyWithAssumedAlignment
|
| 70 |
+
: UniversalCopy<uint_bit_t<MaxVecBits>>
|
| 71 |
+
{
|
| 72 |
+
static_assert(MaxVecBits == 8 || MaxVecBits == 16 || MaxVecBits == 32 || MaxVecBits == 64 || MaxVecBits == 128,
|
| 73 |
+
"Expected MaxVecBits to be 8 or 16 or 32 or 64 or 128 for alignment and performance.");
|
| 74 |
+
};
|
| 75 |
+
|
| 76 |
+
//
|
| 77 |
+
// AutoVectorizingCopy alias assumes maximal alignment of pointers and dynamic strides.
|
| 78 |
+
// If this is not the case then AutoVectorizingCopyWithAssumedAlignment should be used instead
|
| 79 |
+
//
|
| 80 |
+
|
| 81 |
+
using AutoVectorizingCopy = AutoVectorizingCopyWithAssumedAlignment<128>;
|
| 82 |
+
|
| 83 |
+
//
|
| 84 |
+
// DefaultCopy alias does not assume alignment of pointers or dynamic strides.
|
| 85 |
+
//
|
| 86 |
+
|
| 87 |
+
using DefaultCopy = AutoVectorizingCopyWithAssumedAlignment<8>;
|
| 88 |
+
|
| 89 |
+
//
|
| 90 |
+
// Copy policy automatically selecting between
|
| 91 |
+
// UniversalCopy and cp.async , based on type and memory space.
|
| 92 |
+
//
|
| 93 |
+
struct AutoCopyAsync {};
|
| 94 |
+
|
| 95 |
+
//
|
| 96 |
+
// Global memory prefetch into L2
|
| 97 |
+
//
|
| 98 |
+
|
| 99 |
+
CUTE_HOST_DEVICE static void
|
| 100 |
+
prefetch(void const* gmem_ptr)
|
| 101 |
+
{
|
| 102 |
+
#if defined(__CUDA_ARCH__)
|
| 103 |
+
asm volatile("prefetch.global.L2 [%0];\n" : : "l"(gmem_ptr) : "memory");
|
| 104 |
+
#endif
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/copy_sm100.hpp
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/copy_sm100_tma.hpp
ADDED
|
@@ -0,0 +1,664 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2020 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
#pragma once
|
| 35 |
+
|
| 36 |
+
#include <cute/arch/config.hpp>
|
| 37 |
+
|
| 38 |
+
#include <cute/arch/copy.hpp>
|
| 39 |
+
#include <cute/arch/copy_sm90.hpp>
|
| 40 |
+
namespace cute
|
| 41 |
+
{
|
| 42 |
+
|
| 43 |
+
constexpr uint32_t Sm100MmaPeerBitMask = 0xFEFFFFFF;
|
| 44 |
+
constexpr uint64_t Sm100MemDescDefault = uint64_t(0x1000000000000000);
|
| 45 |
+
|
| 46 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 47 |
+
/// UTMA_LOAD : Initiates a TMA copy from global memory to shared memory
|
| 48 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 49 |
+
|
| 50 |
+
struct SM100_TMA_2SM_LOAD_1D
|
| 51 |
+
{
|
| 52 |
+
CUTE_HOST_DEVICE static void
|
| 53 |
+
copy([[maybe_unused]] void const* desc_ptr, [[maybe_unused]] uint64_t* mbar_ptr, [[maybe_unused]] uint64_t cache_hint,
|
| 54 |
+
[[maybe_unused]] void * smem_ptr,
|
| 55 |
+
[[maybe_unused]] int32_t const& crd0)
|
| 56 |
+
{
|
| 57 |
+
#if defined(CUTE_ARCH_TMA_SM100_ENABLED)
|
| 58 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 59 |
+
// Executed by both CTAs. Set peer bit to 0 so that the
|
| 60 |
+
// transaction bytes will update CTA0's barrier.
|
| 61 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr) & Sm100MmaPeerBitMask;
|
| 62 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 63 |
+
asm volatile (
|
| 64 |
+
"cp.async.bulk.tensor.1d.cta_group::2.shared::cluster.global.mbarrier::complete_tx::bytes.L2::cache_hint"
|
| 65 |
+
" [%0], [%1, {%3}], [%2], %4;"
|
| 66 |
+
:
|
| 67 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 68 |
+
"r"(crd0), "l"(cache_hint)
|
| 69 |
+
: "memory");
|
| 70 |
+
#else
|
| 71 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM100_ENABLED.");
|
| 72 |
+
#endif
|
| 73 |
+
}
|
| 74 |
+
};
|
| 75 |
+
|
| 76 |
+
struct SM100_TMA_2SM_LOAD_2D
|
| 77 |
+
{
|
| 78 |
+
CUTE_HOST_DEVICE static void
|
| 79 |
+
copy([[maybe_unused]] void const* desc_ptr, [[maybe_unused]] uint64_t* mbar_ptr, [[maybe_unused]] uint64_t cache_hint,
|
| 80 |
+
[[maybe_unused]] void * smem_ptr,
|
| 81 |
+
[[maybe_unused]] int32_t const& crd0, int32_t const& crd1)
|
| 82 |
+
{
|
| 83 |
+
#if defined(CUTE_ARCH_TMA_SM100_ENABLED)
|
| 84 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 85 |
+
// Executed by both CTAs. Set peer bit to 0 so that the
|
| 86 |
+
// transaction bytes will update CTA0's barrier.
|
| 87 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr) & Sm100MmaPeerBitMask;
|
| 88 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 89 |
+
asm volatile (
|
| 90 |
+
"cp.async.bulk.tensor.2d.cta_group::2.shared::cluster.global.mbarrier::complete_tx::bytes.L2::cache_hint"
|
| 91 |
+
" [%0], [%1, {%3, %4}], [%2], %5;"
|
| 92 |
+
:
|
| 93 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 94 |
+
"r"(crd0), "r"(crd1), "l"(cache_hint)
|
| 95 |
+
: "memory");
|
| 96 |
+
#else
|
| 97 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM100_ENABLED.");
|
| 98 |
+
#endif
|
| 99 |
+
}
|
| 100 |
+
};
|
| 101 |
+
|
| 102 |
+
struct SM100_TMA_2SM_LOAD_3D
|
| 103 |
+
{
|
| 104 |
+
CUTE_HOST_DEVICE static void
|
| 105 |
+
copy([[maybe_unused]] void const* desc_ptr, [[maybe_unused]] uint64_t* mbar_ptr, [[maybe_unused]] uint64_t cache_hint,
|
| 106 |
+
[[maybe_unused]] void * smem_ptr,
|
| 107 |
+
[[maybe_unused]] int32_t const& crd0, int32_t const& crd1, int32_t const& crd2)
|
| 108 |
+
{
|
| 109 |
+
#if defined(CUTE_ARCH_TMA_SM100_ENABLED)
|
| 110 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 111 |
+
// Executed by both CTAs. Set peer bit to 0 so that the
|
| 112 |
+
// transaction bytes will update CTA0's barrier.
|
| 113 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr) & Sm100MmaPeerBitMask;
|
| 114 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 115 |
+
asm volatile (
|
| 116 |
+
"cp.async.bulk.tensor.3d.cta_group::2.shared::cluster.global.mbarrier::complete_tx::bytes.L2::cache_hint"
|
| 117 |
+
" [%0], [%1, {%3, %4, %5}], [%2], %6;"
|
| 118 |
+
:
|
| 119 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 120 |
+
"r"(crd0), "r"(crd1), "r"(crd2), "l"(cache_hint)
|
| 121 |
+
: "memory");
|
| 122 |
+
#else
|
| 123 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM100_ENABLED.");
|
| 124 |
+
#endif
|
| 125 |
+
}
|
| 126 |
+
};
|
| 127 |
+
|
| 128 |
+
struct SM100_TMA_2SM_LOAD_4D
|
| 129 |
+
{
|
| 130 |
+
CUTE_HOST_DEVICE static void
|
| 131 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint64_t cache_hint,
|
| 132 |
+
void * smem_ptr,
|
| 133 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3)
|
| 134 |
+
{
|
| 135 |
+
#if defined(CUTE_ARCH_TMA_SM100_ENABLED)
|
| 136 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 137 |
+
// Executed by both CTAs. Set peer bit to 0 so that the
|
| 138 |
+
// transaction bytes will update CTA0's barrier.
|
| 139 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr) & Sm100MmaPeerBitMask;
|
| 140 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 141 |
+
asm volatile (
|
| 142 |
+
"cp.async.bulk.tensor.4d.cta_group::2.shared::cluster.global.mbarrier::complete_tx::bytes.L2::cache_hint"
|
| 143 |
+
" [%0], [%1, {%3, %4, %5, %6}], [%2], %7;"
|
| 144 |
+
:
|
| 145 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 146 |
+
"r"(crd0), "r"(crd1), "r"(crd2), "r"(crd3), "l"(cache_hint)
|
| 147 |
+
: "memory");
|
| 148 |
+
#else
|
| 149 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM100_ENABLED.");
|
| 150 |
+
#endif
|
| 151 |
+
}
|
| 152 |
+
};
|
| 153 |
+
|
| 154 |
+
struct SM100_TMA_2SM_LOAD_5D
|
| 155 |
+
{
|
| 156 |
+
CUTE_HOST_DEVICE static void
|
| 157 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint64_t cache_hint,
|
| 158 |
+
void * smem_ptr,
|
| 159 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3, int32_t const& crd4)
|
| 160 |
+
{
|
| 161 |
+
#if defined(CUTE_ARCH_TMA_SM100_ENABLED)
|
| 162 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 163 |
+
// Executed by both CTAs. Set peer bit to 0 so that the
|
| 164 |
+
// transaction bytes will update CTA0's barrier.
|
| 165 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr) & Sm100MmaPeerBitMask;
|
| 166 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 167 |
+
asm volatile (
|
| 168 |
+
"cp.async.bulk.tensor.5d.cta_group::2.shared::cluster.global.mbarrier::complete_tx::bytes.L2::cache_hint"
|
| 169 |
+
" [%0], [%1, {%3, %4, %5, %6, %7}], [%2], %8;"
|
| 170 |
+
:
|
| 171 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 172 |
+
"r"(crd0), "r"(crd1), "r"(crd2), "r"(crd3), "r"(crd4), "l"(cache_hint)
|
| 173 |
+
: "memory");
|
| 174 |
+
#else
|
| 175 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM100_ENABLED.");
|
| 176 |
+
#endif
|
| 177 |
+
}
|
| 178 |
+
};
|
| 179 |
+
|
| 180 |
+
struct SM100_TMA_2SM_LOAD
|
| 181 |
+
{
|
| 182 |
+
CUTE_HOST_DEVICE static void
|
| 183 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint64_t cache_hint,
|
| 184 |
+
void * smem_ptr,
|
| 185 |
+
int32_t const& crd0)
|
| 186 |
+
{
|
| 187 |
+
return SM100_TMA_2SM_LOAD_1D::copy(desc_ptr, mbar_ptr, cache_hint, smem_ptr, crd0);
|
| 188 |
+
}
|
| 189 |
+
CUTE_HOST_DEVICE static void
|
| 190 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint64_t cache_hint,
|
| 191 |
+
void * smem_ptr,
|
| 192 |
+
int32_t const& crd0, int32_t const& crd1)
|
| 193 |
+
{
|
| 194 |
+
return SM100_TMA_2SM_LOAD_2D::copy(desc_ptr, mbar_ptr, cache_hint, smem_ptr, crd0, crd1);
|
| 195 |
+
}
|
| 196 |
+
CUTE_HOST_DEVICE static void
|
| 197 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint64_t cache_hint,
|
| 198 |
+
void * smem_ptr,
|
| 199 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2)
|
| 200 |
+
{
|
| 201 |
+
return SM100_TMA_2SM_LOAD_3D::copy(desc_ptr, mbar_ptr, cache_hint, smem_ptr, crd0, crd1, crd2);
|
| 202 |
+
}
|
| 203 |
+
CUTE_HOST_DEVICE static void
|
| 204 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint64_t cache_hint,
|
| 205 |
+
void * smem_ptr,
|
| 206 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3)
|
| 207 |
+
{
|
| 208 |
+
return SM100_TMA_2SM_LOAD_4D::copy(desc_ptr, mbar_ptr, cache_hint, smem_ptr, crd0, crd1, crd2, crd3);
|
| 209 |
+
}
|
| 210 |
+
CUTE_HOST_DEVICE static void
|
| 211 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint64_t cache_hint,
|
| 212 |
+
void * smem_ptr,
|
| 213 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3, int32_t const& crd4)
|
| 214 |
+
{
|
| 215 |
+
return SM100_TMA_2SM_LOAD_5D::copy(desc_ptr, mbar_ptr, cache_hint, smem_ptr, crd0, crd1, crd2, crd3, crd4);
|
| 216 |
+
}
|
| 217 |
+
|
| 218 |
+
using PREFETCH = typename SM90_TMA_LOAD::PREFETCH;
|
| 219 |
+
};
|
| 220 |
+
|
| 221 |
+
|
| 222 |
+
|
| 223 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 224 |
+
/// TMA_LOAD_MULTICAST: Initiates a TMA copy from global memory to shared memory
|
| 225 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 226 |
+
|
| 227 |
+
struct SM100_TMA_2SM_LOAD_MULTICAST_1D
|
| 228 |
+
{
|
| 229 |
+
CUTE_HOST_DEVICE static void
|
| 230 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask, uint64_t cache_hint,
|
| 231 |
+
void * smem_ptr,
|
| 232 |
+
int32_t const& crd0)
|
| 233 |
+
{
|
| 234 |
+
#if defined(CUTE_ARCH_TMA_SM100_ENABLED)
|
| 235 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 236 |
+
// Executed by both CTAs. Set peer bit to 0 so that the
|
| 237 |
+
// transaction bytes will update CTA0's barrier.
|
| 238 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr) & Sm100MmaPeerBitMask;
|
| 239 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 240 |
+
asm volatile (
|
| 241 |
+
"cp.async.bulk.tensor.1d.cta_group::2.shared::cluster.global.mbarrier::complete_tx::bytes.multicast::cluster.L2::cache_hint"
|
| 242 |
+
" [%0], [%1, {%4}], [%2], %3, %5;"
|
| 243 |
+
:
|
| 244 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar), "h"(multicast_mask),
|
| 245 |
+
"r"(crd0), "l"(cache_hint)
|
| 246 |
+
: "memory");
|
| 247 |
+
#else
|
| 248 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM100_ENABLED.");
|
| 249 |
+
#endif
|
| 250 |
+
}
|
| 251 |
+
};
|
| 252 |
+
|
| 253 |
+
struct SM100_TMA_2SM_LOAD_MULTICAST_2D
|
| 254 |
+
{
|
| 255 |
+
CUTE_HOST_DEVICE static void
|
| 256 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask, uint64_t cache_hint,
|
| 257 |
+
void * smem_ptr,
|
| 258 |
+
int32_t const& crd0, int32_t const& crd1)
|
| 259 |
+
{
|
| 260 |
+
#if defined(CUTE_ARCH_TMA_SM100_ENABLED)
|
| 261 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 262 |
+
// Executed by both CTAs. Set peer bit to 0 so that the
|
| 263 |
+
// transaction bytes will update CTA0's barrier.
|
| 264 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr) & Sm100MmaPeerBitMask;
|
| 265 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 266 |
+
asm volatile (
|
| 267 |
+
"cp.async.bulk.tensor.2d.cta_group::2.shared::cluster.global.mbarrier::complete_tx::bytes.multicast::cluster.L2::cache_hint"
|
| 268 |
+
" [%0], [%1, {%4, %5}], [%2], %3, %6;"
|
| 269 |
+
:
|
| 270 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar), "h"(multicast_mask),
|
| 271 |
+
"r"(crd0), "r"(crd1), "l"(cache_hint)
|
| 272 |
+
: "memory");
|
| 273 |
+
#else
|
| 274 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM100_ENABLED.");
|
| 275 |
+
#endif
|
| 276 |
+
}
|
| 277 |
+
};
|
| 278 |
+
|
| 279 |
+
struct SM100_TMA_2SM_LOAD_MULTICAST_3D
|
| 280 |
+
{
|
| 281 |
+
CUTE_HOST_DEVICE static void
|
| 282 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask, uint64_t cache_hint,
|
| 283 |
+
void * smem_ptr,
|
| 284 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2)
|
| 285 |
+
{
|
| 286 |
+
#if defined(CUTE_ARCH_TMA_SM100_ENABLED)
|
| 287 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 288 |
+
// Executed by both CTAs. Set peer bit to 0 so that the
|
| 289 |
+
// transaction bytes will update CTA0's barrier.
|
| 290 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr) & Sm100MmaPeerBitMask;
|
| 291 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 292 |
+
asm volatile (
|
| 293 |
+
"cp.async.bulk.tensor.3d.cta_group::2.shared::cluster.global.mbarrier::complete_tx::bytes.multicast::cluster.L2::cache_hint"
|
| 294 |
+
" [%0], [%1, {%4, %5, %6}], [%2], %3, %7;"
|
| 295 |
+
:
|
| 296 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar), "h"(multicast_mask),
|
| 297 |
+
"r"(crd0), "r"(crd1), "r"(crd2), "l"(cache_hint)
|
| 298 |
+
: "memory");
|
| 299 |
+
#else
|
| 300 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM100_ENABLED.");
|
| 301 |
+
#endif
|
| 302 |
+
}
|
| 303 |
+
};
|
| 304 |
+
|
| 305 |
+
struct SM100_TMA_2SM_LOAD_MULTICAST_4D
|
| 306 |
+
{
|
| 307 |
+
CUTE_HOST_DEVICE static void
|
| 308 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask, uint64_t cache_hint,
|
| 309 |
+
void * smem_ptr,
|
| 310 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3)
|
| 311 |
+
{
|
| 312 |
+
#if defined(CUTE_ARCH_TMA_SM100_ENABLED)
|
| 313 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 314 |
+
// Executed by both CTAs. Set peer bit to 0 so that the
|
| 315 |
+
// transaction bytes will update CTA0's barrier.
|
| 316 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr) & Sm100MmaPeerBitMask;
|
| 317 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 318 |
+
asm volatile (
|
| 319 |
+
"cp.async.bulk.tensor.4d.cta_group::2.shared::cluster.global.mbarrier::complete_tx::bytes.multicast::cluster.L2::cache_hint"
|
| 320 |
+
" [%0], [%1, {%4, %5, %6, %7}], [%2], %3, %8;"
|
| 321 |
+
:
|
| 322 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar), "h"(multicast_mask),
|
| 323 |
+
"r"(crd0), "r"(crd1), "r"(crd2), "r"(crd3), "l"(cache_hint)
|
| 324 |
+
: "memory");
|
| 325 |
+
#else
|
| 326 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM100_ENABLED.");
|
| 327 |
+
#endif
|
| 328 |
+
}
|
| 329 |
+
};
|
| 330 |
+
|
| 331 |
+
struct SM100_TMA_2SM_LOAD_MULTICAST_5D
|
| 332 |
+
{
|
| 333 |
+
CUTE_HOST_DEVICE static void
|
| 334 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask, uint64_t cache_hint,
|
| 335 |
+
void * smem_ptr,
|
| 336 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3, int32_t const& crd4)
|
| 337 |
+
{
|
| 338 |
+
#if defined(CUTE_ARCH_TMA_SM100_ENABLED)
|
| 339 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 340 |
+
// Executed by both CTAs. Set peer bit to 0 so that the
|
| 341 |
+
// transaction bytes will update CTA0's barrier.
|
| 342 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr) & Sm100MmaPeerBitMask;
|
| 343 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 344 |
+
asm volatile (
|
| 345 |
+
"cp.async.bulk.tensor.5d.cta_group::2.shared::cluster.global.mbarrier::complete_tx::bytes.multicast::cluster.L2::cache_hint"
|
| 346 |
+
" [%0], [%1, {%4, %5, %6, %7, %8}], [%2], %3, %9;"
|
| 347 |
+
:
|
| 348 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar), "h"(multicast_mask),
|
| 349 |
+
"r"(crd0), "r"(crd1), "r"(crd2), "r"(crd3), "r"(crd4), "l"(cache_hint)
|
| 350 |
+
: "memory");
|
| 351 |
+
#else
|
| 352 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM0_ENABLED.");
|
| 353 |
+
#endif
|
| 354 |
+
}
|
| 355 |
+
};
|
| 356 |
+
|
| 357 |
+
struct SM100_TMA_2SM_LOAD_MULTICAST
|
| 358 |
+
{
|
| 359 |
+
CUTE_HOST_DEVICE static void
|
| 360 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask, uint64_t cache_hint,
|
| 361 |
+
void * smem_ptr,
|
| 362 |
+
int32_t const& crd0)
|
| 363 |
+
{
|
| 364 |
+
return SM100_TMA_2SM_LOAD_MULTICAST_1D::copy(desc_ptr, mbar_ptr, multicast_mask, cache_hint, smem_ptr, crd0);
|
| 365 |
+
}
|
| 366 |
+
CUTE_HOST_DEVICE static void
|
| 367 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask, uint64_t cache_hint,
|
| 368 |
+
void * smem_ptr,
|
| 369 |
+
int32_t const& crd0, int32_t const& crd1)
|
| 370 |
+
{
|
| 371 |
+
return SM100_TMA_2SM_LOAD_MULTICAST_2D::copy(desc_ptr, mbar_ptr, multicast_mask, cache_hint, smem_ptr, crd0, crd1);
|
| 372 |
+
}
|
| 373 |
+
CUTE_HOST_DEVICE static void
|
| 374 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask, uint64_t cache_hint,
|
| 375 |
+
void * smem_ptr,
|
| 376 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2)
|
| 377 |
+
{
|
| 378 |
+
return SM100_TMA_2SM_LOAD_MULTICAST_3D::copy(desc_ptr, mbar_ptr, multicast_mask, cache_hint, smem_ptr, crd0, crd1, crd2);
|
| 379 |
+
}
|
| 380 |
+
CUTE_HOST_DEVICE static void
|
| 381 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask, uint64_t cache_hint,
|
| 382 |
+
void * smem_ptr,
|
| 383 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3)
|
| 384 |
+
{
|
| 385 |
+
return SM100_TMA_2SM_LOAD_MULTICAST_4D::copy(desc_ptr, mbar_ptr, multicast_mask, cache_hint, smem_ptr, crd0, crd1, crd2, crd3);
|
| 386 |
+
}
|
| 387 |
+
CUTE_HOST_DEVICE static void
|
| 388 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask, uint64_t cache_hint,
|
| 389 |
+
void * smem_ptr,
|
| 390 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3, int32_t const& crd4)
|
| 391 |
+
{
|
| 392 |
+
return SM100_TMA_2SM_LOAD_MULTICAST_5D::copy(desc_ptr, mbar_ptr, multicast_mask, cache_hint, smem_ptr, crd0, crd1, crd2, crd3, crd4);
|
| 393 |
+
}
|
| 394 |
+
|
| 395 |
+
using PREFETCH = typename SM90_TMA_LOAD::PREFETCH;
|
| 396 |
+
};
|
| 397 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 398 |
+
|
| 399 |
+
|
| 400 |
+
struct SM100_TMA_2SM_LOAD_IM2COL_3D
|
| 401 |
+
{
|
| 402 |
+
CUTE_HOST_DEVICE static void
|
| 403 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr,
|
| 404 |
+
void * smem_ptr,
|
| 405 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_n,
|
| 406 |
+
uint16_t const& offset_w)
|
| 407 |
+
{
|
| 408 |
+
#if defined(CUTE_ARCH_TMA_SM100_ENABLED)
|
| 409 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 410 |
+
// Executed by both CTAs. Set peer bit to 0 so that the
|
| 411 |
+
// transaction bytes will update CTA0's barrier.
|
| 412 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr) & Sm100MmaPeerBitMask;
|
| 413 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 414 |
+
asm volatile (
|
| 415 |
+
"cp.async.bulk.tensor.3d.im2col.cta_group::2.shared::cluster.global.mbarrier::complete_tx::bytes.L2::cache_hint"
|
| 416 |
+
" [%0], [%1, {%3, %4, %5}], [%2], {%6}, %7;"
|
| 417 |
+
:
|
| 418 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 419 |
+
"r"(coord_c), "r"(coord_w), "r"(coord_n),
|
| 420 |
+
"h"(offset_w), "l"(Sm100MemDescDefault)
|
| 421 |
+
: "memory");
|
| 422 |
+
#else
|
| 423 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM100_ENABLED.");
|
| 424 |
+
#endif
|
| 425 |
+
}
|
| 426 |
+
};
|
| 427 |
+
|
| 428 |
+
struct SM100_TMA_2SM_LOAD_IM2COL_4D
|
| 429 |
+
{
|
| 430 |
+
CUTE_HOST_DEVICE static void
|
| 431 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr,
|
| 432 |
+
void * smem_ptr,
|
| 433 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_n,
|
| 434 |
+
uint16_t const& offset_w,
|
| 435 |
+
uint16_t const& offset_h)
|
| 436 |
+
{
|
| 437 |
+
#if defined(CUTE_ARCH_TMA_SM100_ENABLED)
|
| 438 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 439 |
+
// Executed by both CTAs. Set peer bit to 0 so that the
|
| 440 |
+
// transaction bytes will update CTA0's barrier.
|
| 441 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr) & Sm100MmaPeerBitMask;
|
| 442 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 443 |
+
asm volatile (
|
| 444 |
+
"cp.async.bulk.tensor.4d.im2col.cta_group::2.shared::cluster.global.mbarrier::complete_tx::bytes.L2::cache_hint"
|
| 445 |
+
" [%0], [%1, {%3, %4, %5, %6}], [%2], {%7, %8}, %9;"
|
| 446 |
+
:
|
| 447 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 448 |
+
"r"(coord_c), "r"(coord_w), "r"(coord_h), "r"(coord_n),
|
| 449 |
+
"h"(offset_w), "h"(offset_h), "l"(Sm100MemDescDefault)
|
| 450 |
+
: "memory");
|
| 451 |
+
#else
|
| 452 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM100_ENABLED.");
|
| 453 |
+
#endif
|
| 454 |
+
}
|
| 455 |
+
};
|
| 456 |
+
|
| 457 |
+
struct SM100_TMA_2SM_LOAD_IM2COL_5D
|
| 458 |
+
{
|
| 459 |
+
CUTE_HOST_DEVICE static void
|
| 460 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr,
|
| 461 |
+
void * smem_ptr,
|
| 462 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_d, int32_t const& coord_n,
|
| 463 |
+
uint16_t const& offset_w,
|
| 464 |
+
uint16_t const& offset_h,
|
| 465 |
+
uint16_t const& offset_d)
|
| 466 |
+
{
|
| 467 |
+
#if defined(CUTE_ARCH_TMA_SM100_ENABLED)
|
| 468 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 469 |
+
// Executed by both CTAs. Set peer bit to 0 so that the
|
| 470 |
+
// transaction bytes will update CTA0's barrier.
|
| 471 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr) & Sm100MmaPeerBitMask;
|
| 472 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 473 |
+
asm volatile (
|
| 474 |
+
"cp.async.bulk.tensor.5d.im2col.cta_group::2.shared::cluster.global.mbarrier::complete_tx::bytes.L2::cache_hint"
|
| 475 |
+
" [%0], [%1, {%3, %4, %5, %6, %7}], [%2], {%8, %9, %10}, %11;"
|
| 476 |
+
:
|
| 477 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 478 |
+
"r"(coord_c), "r"(coord_w), "r"(coord_h), "r"(coord_d), "r"(coord_n),
|
| 479 |
+
"h"(offset_w), "h"(offset_h), "h"(offset_d), "l"(Sm100MemDescDefault)
|
| 480 |
+
: "memory");
|
| 481 |
+
#else
|
| 482 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM100_ENABLED.");
|
| 483 |
+
#endif
|
| 484 |
+
}
|
| 485 |
+
};
|
| 486 |
+
|
| 487 |
+
struct SM100_TMA_2SM_LOAD_IM2COL
|
| 488 |
+
{
|
| 489 |
+
CUTE_HOST_DEVICE static void
|
| 490 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr,
|
| 491 |
+
void * smem_ptr,
|
| 492 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_n,
|
| 493 |
+
uint16_t const& offset_w)
|
| 494 |
+
{
|
| 495 |
+
return SM100_TMA_2SM_LOAD_IM2COL_3D::copy(desc_ptr, mbar_ptr, smem_ptr,
|
| 496 |
+
coord_c, coord_w, coord_n,
|
| 497 |
+
offset_w);
|
| 498 |
+
}
|
| 499 |
+
CUTE_HOST_DEVICE static void
|
| 500 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr,
|
| 501 |
+
void * smem_ptr,
|
| 502 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_n,
|
| 503 |
+
uint16_t const& offset_w,
|
| 504 |
+
uint16_t const& offset_h)
|
| 505 |
+
{
|
| 506 |
+
return SM100_TMA_2SM_LOAD_IM2COL_4D::copy(desc_ptr, mbar_ptr, smem_ptr,
|
| 507 |
+
coord_c, coord_w, coord_h, coord_n,
|
| 508 |
+
offset_w, offset_h);
|
| 509 |
+
}
|
| 510 |
+
CUTE_HOST_DEVICE static void
|
| 511 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr,
|
| 512 |
+
void * smem_ptr,
|
| 513 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_d, int32_t const& coord_n,
|
| 514 |
+
uint16_t const& offset_w,
|
| 515 |
+
uint16_t const& offset_h,
|
| 516 |
+
uint16_t const& offset_d)
|
| 517 |
+
{
|
| 518 |
+
return SM100_TMA_2SM_LOAD_IM2COL_5D::copy(desc_ptr, mbar_ptr, smem_ptr,
|
| 519 |
+
coord_c, coord_w, coord_h, coord_d, coord_n,
|
| 520 |
+
offset_w, offset_h, offset_d);
|
| 521 |
+
}
|
| 522 |
+
|
| 523 |
+
using PREFETCH = typename SM90_TMA_LOAD_IM2COL::PREFETCH;
|
| 524 |
+
};
|
| 525 |
+
|
| 526 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 527 |
+
|
| 528 |
+
struct SM100_TMA_2SM_LOAD_IM2COL_MULTICAST_3D
|
| 529 |
+
{
|
| 530 |
+
CUTE_HOST_DEVICE static void
|
| 531 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask,
|
| 532 |
+
void * smem_ptr,
|
| 533 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_n,
|
| 534 |
+
uint16_t const& offset_w)
|
| 535 |
+
{
|
| 536 |
+
#if defined(CUTE_ARCH_TMA_SM100_ENABLED)
|
| 537 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 538 |
+
// Executed by both CTAs. Set peer bit to 0 so that the
|
| 539 |
+
// transaction bytes will update CTA0's barrier.
|
| 540 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr) & Sm100MmaPeerBitMask;
|
| 541 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 542 |
+
asm volatile (
|
| 543 |
+
"cp.async.bulk.tensor.3d.im2col.cta_group::2.shared::cluster.global.mbarrier::complete_tx::bytes.multicast::cluster.L2::cache_hint"
|
| 544 |
+
" [%0], [%1, {%3, %4, %5}], [%2], {%6}, %7, %8;"
|
| 545 |
+
:
|
| 546 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 547 |
+
"r"(coord_c), "r"(coord_w), "r"(coord_n),
|
| 548 |
+
"h"(offset_w),
|
| 549 |
+
"h"(multicast_mask),
|
| 550 |
+
"l"(Sm100MemDescDefault)
|
| 551 |
+
: "memory");
|
| 552 |
+
#else
|
| 553 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM100_ENABLED.");
|
| 554 |
+
#endif
|
| 555 |
+
}
|
| 556 |
+
};
|
| 557 |
+
|
| 558 |
+
struct SM100_TMA_2SM_LOAD_IM2COL_MULTICAST_4D
|
| 559 |
+
{
|
| 560 |
+
CUTE_HOST_DEVICE static void
|
| 561 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask,
|
| 562 |
+
void * smem_ptr,
|
| 563 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_n,
|
| 564 |
+
uint16_t const& offset_w,
|
| 565 |
+
uint16_t const& offset_h)
|
| 566 |
+
{
|
| 567 |
+
#if defined(CUTE_ARCH_TMA_SM100_ENABLED)
|
| 568 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 569 |
+
// Executed by both CTAs. Set peer bit to 0 so that the
|
| 570 |
+
// transaction bytes will update CTA0's barrier.
|
| 571 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr) & Sm100MmaPeerBitMask;
|
| 572 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 573 |
+
asm volatile (
|
| 574 |
+
"cp.async.bulk.tensor.4d.im2col.cta_group::2.shared::cluster.global.mbarrier::complete_tx::bytes.multicast::cluster.L2::cache_hint"
|
| 575 |
+
" [%0], [%1, {%3, %4, %5, %6}], [%2], {%7, %8}, %9, %10;"
|
| 576 |
+
:
|
| 577 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 578 |
+
"r"(coord_c), "r"(coord_w), "r"(coord_h), "r"(coord_n),
|
| 579 |
+
"h"(offset_w), "h"(offset_h),
|
| 580 |
+
"h"(multicast_mask),
|
| 581 |
+
"l"(Sm100MemDescDefault)
|
| 582 |
+
: "memory");
|
| 583 |
+
#else
|
| 584 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM100_ENABLED.");
|
| 585 |
+
#endif
|
| 586 |
+
}
|
| 587 |
+
};
|
| 588 |
+
|
| 589 |
+
struct SM100_TMA_2SM_LOAD_IM2COL_MULTICAST_5D
|
| 590 |
+
{
|
| 591 |
+
CUTE_HOST_DEVICE static void
|
| 592 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask,
|
| 593 |
+
void * smem_ptr,
|
| 594 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_d, int32_t const& coord_n,
|
| 595 |
+
uint16_t const& offset_w,
|
| 596 |
+
uint16_t const& offset_h,
|
| 597 |
+
uint16_t const& offset_d)
|
| 598 |
+
{
|
| 599 |
+
#if defined(CUTE_ARCH_TMA_SM100_ENABLED)
|
| 600 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 601 |
+
// Executed by both CTAs. Set peer bit to 0 so that the
|
| 602 |
+
// transaction bytes will update CTA0's barrier.
|
| 603 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr) & Sm100MmaPeerBitMask;
|
| 604 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 605 |
+
asm volatile (
|
| 606 |
+
"cp.async.bulk.tensor.5d.im2col.cta_group::2.shared::cluster.global.mbarrier::complete_tx::bytes.multicast::cluster.L2::cache_hint"
|
| 607 |
+
" [%0], [%1, {%3, %4, %5, %6, %7}], [%2], {%8, %9, %10}, %11, %12;"
|
| 608 |
+
:
|
| 609 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 610 |
+
"r"(coord_c), "r"(coord_w), "r"(coord_h), "r"(coord_d), "r"(coord_n),
|
| 611 |
+
"h"(offset_w), "h"(offset_h), "h"(offset_d),
|
| 612 |
+
"h"(multicast_mask),
|
| 613 |
+
"l"(Sm100MemDescDefault)
|
| 614 |
+
: "memory");
|
| 615 |
+
#else
|
| 616 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM100_ENABLED.");
|
| 617 |
+
#endif
|
| 618 |
+
}
|
| 619 |
+
};
|
| 620 |
+
|
| 621 |
+
struct SM100_TMA_2SM_LOAD_IM2COL_MULTICAST
|
| 622 |
+
{
|
| 623 |
+
CUTE_HOST_DEVICE static void
|
| 624 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask,
|
| 625 |
+
void * smem_ptr,
|
| 626 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_n,
|
| 627 |
+
uint16_t const& offset_w)
|
| 628 |
+
{
|
| 629 |
+
return SM100_TMA_2SM_LOAD_IM2COL_MULTICAST_3D::copy(desc_ptr, mbar_ptr, multicast_mask,
|
| 630 |
+
smem_ptr,
|
| 631 |
+
coord_c, coord_w, coord_n,
|
| 632 |
+
offset_w);
|
| 633 |
+
}
|
| 634 |
+
CUTE_HOST_DEVICE static void
|
| 635 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask,
|
| 636 |
+
void * smem_ptr,
|
| 637 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_n,
|
| 638 |
+
uint16_t const& offset_w, uint16_t const& offset_h)
|
| 639 |
+
{
|
| 640 |
+
return SM100_TMA_2SM_LOAD_IM2COL_MULTICAST_4D::copy(desc_ptr, mbar_ptr, multicast_mask,
|
| 641 |
+
smem_ptr,
|
| 642 |
+
coord_c, coord_w, coord_h, coord_n,
|
| 643 |
+
offset_w, offset_h);
|
| 644 |
+
}
|
| 645 |
+
CUTE_HOST_DEVICE static void
|
| 646 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask,
|
| 647 |
+
void * smem_ptr,
|
| 648 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_d, int32_t const& coord_n,
|
| 649 |
+
uint16_t const& offset_w, uint16_t const& offset_h, uint16_t const& offset_d)
|
| 650 |
+
{
|
| 651 |
+
return SM100_TMA_2SM_LOAD_IM2COL_MULTICAST_5D::copy(desc_ptr, mbar_ptr, multicast_mask,
|
| 652 |
+
smem_ptr,
|
| 653 |
+
coord_c, coord_w, coord_h, coord_d, coord_n,
|
| 654 |
+
offset_w, offset_h, offset_d);
|
| 655 |
+
}
|
| 656 |
+
|
| 657 |
+
using PREFETCH = typename SM90_TMA_LOAD_IM2COL::PREFETCH;
|
| 658 |
+
};
|
| 659 |
+
|
| 660 |
+
|
| 661 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 662 |
+
|
| 663 |
+
|
| 664 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/copy_sm50.hpp
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2024 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/config.hpp>
|
| 34 |
+
|
| 35 |
+
#include <cute/arch/copy.hpp>
|
| 36 |
+
|
| 37 |
+
#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 500
|
| 38 |
+
#define CUTE_ARCH_WARP_SHUFFLE_ENABLED 1
|
| 39 |
+
#endif
|
| 40 |
+
|
| 41 |
+
namespace cute
|
| 42 |
+
{
|
| 43 |
+
// Shuffle data between thread pair (0, 1), (2, 3), etc.
|
| 44 |
+
struct SM50_Shuffle_U32_2x2Trans_XOR1
|
| 45 |
+
{
|
| 46 |
+
using SRegisters = uint32_t[2];
|
| 47 |
+
using DRegisters = uint32_t[2];
|
| 48 |
+
|
| 49 |
+
CUTE_HOST_DEVICE static void
|
| 50 |
+
copy(uint32_t const& src0, uint32_t const& src1, uint32_t& dst0, uint32_t& dst1)
|
| 51 |
+
{
|
| 52 |
+
#if defined(CUTE_ARCH_WARP_SHUFFLE_ENABLED)
|
| 53 |
+
uint32_t x0 = src0;
|
| 54 |
+
uint32_t y0 = __shfl_xor_sync(0xffffffff, x0, 1);
|
| 55 |
+
|
| 56 |
+
uint32_t x1 = src1;
|
| 57 |
+
uint32_t y1 = __shfl_xor_sync(0xffffffff, x1, 1);
|
| 58 |
+
|
| 59 |
+
if (threadIdx.x % 2 == 0) {
|
| 60 |
+
dst1 = y0;
|
| 61 |
+
}
|
| 62 |
+
else {
|
| 63 |
+
dst0 = y1;
|
| 64 |
+
}
|
| 65 |
+
#else
|
| 66 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use __shfl_xor_sync without CUTE_ARCH_WARP_SHUFFLE_ENABLED.");
|
| 67 |
+
#endif
|
| 68 |
+
}
|
| 69 |
+
};
|
| 70 |
+
|
| 71 |
+
// Shuffle data between thread pair (0, 4), (1, 5), etc.
|
| 72 |
+
struct SM50_Shuffle_U32_2x2Trans_XOR4
|
| 73 |
+
{
|
| 74 |
+
using SRegisters = uint32_t[2];
|
| 75 |
+
using DRegisters = uint32_t[2];
|
| 76 |
+
|
| 77 |
+
CUTE_HOST_DEVICE static void
|
| 78 |
+
copy(uint32_t const& src0, uint32_t const& src1, uint32_t& dst0, uint32_t& dst1)
|
| 79 |
+
{
|
| 80 |
+
#if defined(CUTE_ARCH_WARP_SHUFFLE_ENABLED)
|
| 81 |
+
uint32_t x0 = threadIdx.x & 4 ? src0 : src1;
|
| 82 |
+
uint32_t y0 = __shfl_xor_sync(0xffffffff, x0, 4);
|
| 83 |
+
|
| 84 |
+
// Replace detination register with shuffle result.
|
| 85 |
+
if (threadIdx.x & 0x4) {
|
| 86 |
+
dst0 = y0;
|
| 87 |
+
}
|
| 88 |
+
else {
|
| 89 |
+
dst1 = y0;
|
| 90 |
+
}
|
| 91 |
+
#else
|
| 92 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use __shfl_xor_sync without CUTE_ARCH_WARP_SHUFFLE_ENABLED.");
|
| 93 |
+
#endif
|
| 94 |
+
}
|
| 95 |
+
};
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/copy_sm75.hpp
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/config.hpp>
|
| 34 |
+
|
| 35 |
+
#include <cute/arch/copy.hpp>
|
| 36 |
+
|
| 37 |
+
// Config
|
| 38 |
+
#if defined(__clang__) && defined(__CUDA__)
|
| 39 |
+
// ldmatrix PTX instructions added in Clang 14: https://reviews.llvm.org/D107046
|
| 40 |
+
// ... but will not work until Clang 15:
|
| 41 |
+
// * https://reviews.llvm.org/D121666
|
| 42 |
+
// * https://reviews.llvm.org/D126846
|
| 43 |
+
#define CUTE_ARCH_CLANG_SUPPORTS_LDSM_SM75 (__clang_major__ >= 15)
|
| 44 |
+
#endif
|
| 45 |
+
|
| 46 |
+
#if defined(__NVCC__) || defined(__CUDACC_RTC__)
|
| 47 |
+
// ldmatrix PTX instruction added in CUDA 10.2+
|
| 48 |
+
#define CUTE_ARCH_NVCC_SUPPORTS_LDSM_SM75 ((__CUDACC_VER_MAJOR__ == 10 && __CUDACC_VER_MINOR__ >= 2) || __CUDACC_VER_MAJOR__ >= 11)
|
| 49 |
+
#endif
|
| 50 |
+
|
| 51 |
+
#if ! defined(CUTE_ARCH_LDSM_SM75_SUPPORTED)
|
| 52 |
+
#define CUTE_ARCH_LDSM_SM75_SUPPORTED (CUTE_ARCH_NVCC_SUPPORTS_LDSM_SM75 || CUTE_ARCH_CLANG_SUPPORTS_LDSM_SM75)
|
| 53 |
+
#endif
|
| 54 |
+
|
| 55 |
+
#if ! defined(CUTE_ARCH_LDSM_SM75_ENABLED)
|
| 56 |
+
#define CUTE_ARCH_LDSM_SM75_ENABLED (CUTE_ARCH_LDSM_SM75_SUPPORTED)
|
| 57 |
+
#endif
|
| 58 |
+
|
| 59 |
+
#if (CUTE_ARCH_LDSM_SM75_ENABLED) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 750
|
| 60 |
+
#define CUTE_ARCH_LDSM_SM75_ACTIVATED 1
|
| 61 |
+
#endif
|
| 62 |
+
|
| 63 |
+
namespace cute
|
| 64 |
+
{
|
| 65 |
+
|
| 66 |
+
struct SM75_U32x1_LDSM_N
|
| 67 |
+
{
|
| 68 |
+
using SRegisters = uint128_t[1];
|
| 69 |
+
using DRegisters = uint32_t[1];
|
| 70 |
+
|
| 71 |
+
CUTE_HOST_DEVICE static void
|
| 72 |
+
copy(uint128_t const& smem_src,
|
| 73 |
+
uint32_t& dst)
|
| 74 |
+
{
|
| 75 |
+
#if defined(CUTE_ARCH_LDSM_SM75_ACTIVATED)
|
| 76 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(&smem_src);
|
| 77 |
+
asm volatile ("ldmatrix.sync.aligned.x1.m8n8.shared.b16 {%0}, [%1];\n"
|
| 78 |
+
: "=r"(dst)
|
| 79 |
+
: "r"(smem_int_ptr));
|
| 80 |
+
#else
|
| 81 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use ldmatrix without CUTE_ARCH_LDSM_SM75_ACTIVATED.");
|
| 82 |
+
#endif
|
| 83 |
+
}
|
| 84 |
+
};
|
| 85 |
+
|
| 86 |
+
struct SM75_U32x2_LDSM_N
|
| 87 |
+
{
|
| 88 |
+
using SRegisters = uint128_t[1];
|
| 89 |
+
using DRegisters = uint32_t[2];
|
| 90 |
+
|
| 91 |
+
CUTE_HOST_DEVICE static void
|
| 92 |
+
copy(uint128_t const& smem_src,
|
| 93 |
+
uint32_t& dst0, uint32_t& dst1)
|
| 94 |
+
{
|
| 95 |
+
#if defined(CUTE_ARCH_LDSM_SM75_ACTIVATED)
|
| 96 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(&smem_src);
|
| 97 |
+
asm volatile ("ldmatrix.sync.aligned.x2.m8n8.shared.b16 {%0, %1}, [%2];\n"
|
| 98 |
+
: "=r"(dst0), "=r"(dst1)
|
| 99 |
+
: "r"(smem_int_ptr));
|
| 100 |
+
#else
|
| 101 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use ldmatrix without CUTE_ARCH_LDSM_SM75_ACTIVATED.");
|
| 102 |
+
#endif
|
| 103 |
+
}
|
| 104 |
+
};
|
| 105 |
+
|
| 106 |
+
struct SM75_U32x4_LDSM_N
|
| 107 |
+
{
|
| 108 |
+
using SRegisters = uint128_t[1];
|
| 109 |
+
using DRegisters = uint32_t[4];
|
| 110 |
+
|
| 111 |
+
CUTE_HOST_DEVICE static void
|
| 112 |
+
copy(uint128_t const& smem_src,
|
| 113 |
+
uint32_t& dst0, uint32_t& dst1, uint32_t& dst2, uint32_t& dst3)
|
| 114 |
+
{
|
| 115 |
+
#if defined(CUTE_ARCH_LDSM_SM75_ACTIVATED)
|
| 116 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(&smem_src);
|
| 117 |
+
asm volatile ("ldmatrix.sync.aligned.x4.m8n8.shared.b16 {%0, %1, %2, %3}, [%4];\n"
|
| 118 |
+
: "=r"(dst0), "=r"(dst1), "=r"(dst2), "=r"(dst3)
|
| 119 |
+
: "r"(smem_int_ptr));
|
| 120 |
+
#else
|
| 121 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use ldmatrix without CUTE_ARCH_LDSM_SM75_ACTIVATED.");
|
| 122 |
+
#endif
|
| 123 |
+
}
|
| 124 |
+
};
|
| 125 |
+
|
| 126 |
+
struct SM75_U16x2_LDSM_T
|
| 127 |
+
{
|
| 128 |
+
using SRegisters = uint128_t[1];
|
| 129 |
+
using DRegisters = uint32_t[1];
|
| 130 |
+
|
| 131 |
+
CUTE_HOST_DEVICE static void
|
| 132 |
+
copy(uint128_t const& smem_src,
|
| 133 |
+
uint32_t& dst)
|
| 134 |
+
{
|
| 135 |
+
#if defined(CUTE_ARCH_LDSM_SM75_ACTIVATED)
|
| 136 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(&smem_src);
|
| 137 |
+
asm volatile ("ldmatrix.sync.aligned.x1.trans.m8n8.shared.b16 {%0}, [%1];\n"
|
| 138 |
+
: "=r"(dst)
|
| 139 |
+
: "r"(smem_int_ptr));
|
| 140 |
+
#else
|
| 141 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use ldmatrix without CUTE_ARCH_LDSM_SM75_ACTIVATED.");
|
| 142 |
+
#endif
|
| 143 |
+
}
|
| 144 |
+
};
|
| 145 |
+
|
| 146 |
+
struct SM75_U16x4_LDSM_T
|
| 147 |
+
{
|
| 148 |
+
using SRegisters = uint128_t[1];
|
| 149 |
+
using DRegisters = uint32_t[2];
|
| 150 |
+
|
| 151 |
+
CUTE_HOST_DEVICE static void
|
| 152 |
+
copy(uint128_t const& smem_src,
|
| 153 |
+
uint32_t& dst0, uint32_t& dst1)
|
| 154 |
+
{
|
| 155 |
+
#if defined(CUTE_ARCH_LDSM_SM75_ACTIVATED)
|
| 156 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(&smem_src);
|
| 157 |
+
asm volatile ("ldmatrix.sync.aligned.x2.trans.m8n8.shared.b16 {%0, %1}, [%2];\n"
|
| 158 |
+
: "=r"(dst0), "=r"(dst1)
|
| 159 |
+
: "r"(smem_int_ptr));
|
| 160 |
+
#else
|
| 161 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use ldmatrix without CUTE_ARCH_LDSM_SM75_ACTIVATED.");
|
| 162 |
+
#endif
|
| 163 |
+
}
|
| 164 |
+
};
|
| 165 |
+
|
| 166 |
+
struct SM75_U16x8_LDSM_T
|
| 167 |
+
{
|
| 168 |
+
using SRegisters = uint128_t[1];
|
| 169 |
+
using DRegisters = uint32_t[4];
|
| 170 |
+
|
| 171 |
+
CUTE_HOST_DEVICE static void
|
| 172 |
+
copy(uint128_t const& smem_src,
|
| 173 |
+
uint32_t& dst0, uint32_t& dst1, uint32_t& dst2, uint32_t& dst3)
|
| 174 |
+
{
|
| 175 |
+
#if defined(CUTE_ARCH_LDSM_SM75_ACTIVATED)
|
| 176 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(&smem_src);
|
| 177 |
+
asm volatile ("ldmatrix.sync.aligned.x4.trans.m8n8.shared.b16 {%0, %1, %2, %3}, [%4];\n"
|
| 178 |
+
: "=r"(dst0), "=r"(dst1), "=r"(dst2), "=r"(dst3)
|
| 179 |
+
: "r"(smem_int_ptr));
|
| 180 |
+
#else
|
| 181 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use ldmatrix without CUTE_ARCH_LDSM_SM75_ACTIVATED.");
|
| 182 |
+
#endif
|
| 183 |
+
}
|
| 184 |
+
};
|
| 185 |
+
|
| 186 |
+
//
|
| 187 |
+
// Legacy LDSM interfaces that aren't very useful
|
| 188 |
+
//
|
| 189 |
+
|
| 190 |
+
template <class T>
|
| 191 |
+
CUTE_HOST_DEVICE
|
| 192 |
+
void
|
| 193 |
+
copy_ldsm(uint128_t const* const smem_ptr,
|
| 194 |
+
T* rmem_ptr)
|
| 195 |
+
{
|
| 196 |
+
uint32_t* reg_ptr = reinterpret_cast<uint32_t*>(rmem_ptr);
|
| 197 |
+
|
| 198 |
+
// if constexpr
|
| 199 |
+
if (sizeof(T) == 4) {
|
| 200 |
+
SM75_U32x1_LDSM_N::copy(smem_ptr[0], reg_ptr[0]);
|
| 201 |
+
}
|
| 202 |
+
else if (sizeof(T) == 8) {
|
| 203 |
+
SM75_U32x2_LDSM_N::copy(smem_ptr[0], reg_ptr[0], reg_ptr[1]);
|
| 204 |
+
}
|
| 205 |
+
else if (sizeof(T) == 16) {
|
| 206 |
+
SM75_U32x4_LDSM_N::copy(smem_ptr[0], reg_ptr[0], reg_ptr[1], reg_ptr[2], reg_ptr[3]);
|
| 207 |
+
}
|
| 208 |
+
else {
|
| 209 |
+
static_assert(sizeof(T) == 4 || sizeof(T) == 8 || sizeof(T) == 16, "sizeof(T) is not supported");
|
| 210 |
+
}
|
| 211 |
+
}
|
| 212 |
+
|
| 213 |
+
template <class T>
|
| 214 |
+
CUTE_HOST_DEVICE
|
| 215 |
+
void
|
| 216 |
+
copy_ldsm_trans(uint128_t const* const smem_ptr,
|
| 217 |
+
T* rmem_ptr)
|
| 218 |
+
{
|
| 219 |
+
uint32_t* reg_ptr = reinterpret_cast<uint32_t*>(rmem_ptr);
|
| 220 |
+
|
| 221 |
+
// if constexpr
|
| 222 |
+
if (sizeof(T) == 4) {
|
| 223 |
+
SM75_U16x2_LDSM_T::copy(smem_ptr[0], reg_ptr[0]);
|
| 224 |
+
}
|
| 225 |
+
else if (sizeof(T) == 8) {
|
| 226 |
+
SM75_U16x4_LDSM_T::copy(smem_ptr[0], reg_ptr[0], reg_ptr[1]);
|
| 227 |
+
}
|
| 228 |
+
else if (sizeof(T) == 16) {
|
| 229 |
+
SM75_U16x8_LDSM_T::copy(smem_ptr[0], reg_ptr[0], reg_ptr[1], reg_ptr[2], reg_ptr[3]);
|
| 230 |
+
}
|
| 231 |
+
else {
|
| 232 |
+
static_assert(sizeof(T) == 4 || sizeof(T) == 8 || sizeof(T) == 16, "sizeof(T) is not supported");
|
| 233 |
+
}
|
| 234 |
+
}
|
| 235 |
+
|
| 236 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/copy_sm80.hpp
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/config.hpp>
|
| 34 |
+
|
| 35 |
+
#include <cute/arch/copy.hpp>
|
| 36 |
+
|
| 37 |
+
// Config
|
| 38 |
+
#if (defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 800))
|
| 39 |
+
# define CUTE_ARCH_CP_ASYNC_SM80_ENABLED
|
| 40 |
+
#endif
|
| 41 |
+
|
| 42 |
+
namespace cute
|
| 43 |
+
{
|
| 44 |
+
|
| 45 |
+
/// Copy via cp.async with caching at all levels
|
| 46 |
+
template <class TS, class TD = TS>
|
| 47 |
+
struct SM80_CP_ASYNC_CACHEALWAYS
|
| 48 |
+
{
|
| 49 |
+
using SRegisters = TS[1];
|
| 50 |
+
using DRegisters = TD[1];
|
| 51 |
+
|
| 52 |
+
static_assert(sizeof(TS) == sizeof(TD), "cp.async requires sizeof(src_value_type) == sizeof(dst_value_type)");
|
| 53 |
+
static_assert(sizeof(TS) == 4 || sizeof(TS) == 8 || sizeof(TS) == 16, "cp.async sizeof(TS) is not supported");
|
| 54 |
+
|
| 55 |
+
CUTE_HOST_DEVICE static void
|
| 56 |
+
copy(TS const& gmem_src,
|
| 57 |
+
TD & smem_dst)
|
| 58 |
+
{
|
| 59 |
+
#if defined(CUTE_ARCH_CP_ASYNC_SM80_ENABLED)
|
| 60 |
+
TS const* gmem_ptr = &gmem_src;
|
| 61 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(&smem_dst);
|
| 62 |
+
asm volatile("cp.async.ca.shared.global.L2::128B [%0], [%1], %2;\n"
|
| 63 |
+
:: "r"(smem_int_ptr),
|
| 64 |
+
"l"(gmem_ptr),
|
| 65 |
+
"n"(sizeof(TS)));
|
| 66 |
+
#else
|
| 67 |
+
CUTE_INVALID_CONTROL_PATH("Support for cp.async instructions has not been enabled");
|
| 68 |
+
#endif
|
| 69 |
+
}
|
| 70 |
+
};
|
| 71 |
+
|
| 72 |
+
/// Copy via cp.async with caching at global level
|
| 73 |
+
template <class TS, class TD = TS>
|
| 74 |
+
struct SM80_CP_ASYNC_CACHEGLOBAL
|
| 75 |
+
{
|
| 76 |
+
using SRegisters = TS[1];
|
| 77 |
+
using DRegisters = TD[1];
|
| 78 |
+
|
| 79 |
+
static_assert(sizeof(TS) == sizeof(TD), "cp.async requires sizeof(src_value_type) == sizeof(dst_value_type)");
|
| 80 |
+
static_assert(sizeof(TS) == 16, "cp.async sizeof(TS) is not supported");
|
| 81 |
+
|
| 82 |
+
CUTE_HOST_DEVICE static void
|
| 83 |
+
copy(TS const& gmem_src,
|
| 84 |
+
TD & smem_dst)
|
| 85 |
+
{
|
| 86 |
+
#if defined(CUTE_ARCH_CP_ASYNC_SM80_ENABLED)
|
| 87 |
+
TS const* gmem_ptr = &gmem_src;
|
| 88 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(&smem_dst);
|
| 89 |
+
asm volatile("cp.async.cg.shared.global.L2::128B [%0], [%1], %2;\n"
|
| 90 |
+
:: "r"(smem_int_ptr),
|
| 91 |
+
"l"(gmem_ptr),
|
| 92 |
+
"n"(sizeof(TS)));
|
| 93 |
+
#else
|
| 94 |
+
CUTE_INVALID_CONTROL_PATH("Support for cp.async instructions has not been enabled");
|
| 95 |
+
#endif
|
| 96 |
+
}
|
| 97 |
+
};
|
| 98 |
+
|
| 99 |
+
/// Copy via cp.async with caching at all levels
|
| 100 |
+
template <class TS, class TD = TS>
|
| 101 |
+
struct SM80_CP_ASYNC_CACHEALWAYS_ZFILL
|
| 102 |
+
{
|
| 103 |
+
using SRegisters = TS[1];
|
| 104 |
+
using DRegisters = TD[1];
|
| 105 |
+
|
| 106 |
+
static_assert(sizeof(TS) == sizeof(TD), "cp.async requires sizeof(src_value_type) == sizeof(dst_value_type)");
|
| 107 |
+
static_assert(sizeof(TS) == 4 || sizeof(TS) == 8 || sizeof(TS) == 16, "cp.async sizeof(TS) is not supported");
|
| 108 |
+
|
| 109 |
+
CUTE_HOST_DEVICE static void
|
| 110 |
+
copy(TS const& gmem_src,
|
| 111 |
+
TD & smem_dst,
|
| 112 |
+
bool pred)
|
| 113 |
+
{
|
| 114 |
+
#if defined(CUTE_ARCH_CP_ASYNC_SM80_ENABLED)
|
| 115 |
+
TS const* gmem_ptr = &gmem_src;
|
| 116 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(&smem_dst);
|
| 117 |
+
int src_size = pred ? sizeof(TS) : 0;
|
| 118 |
+
asm volatile("cp.async.ca.shared.global.L2::128B [%0], [%1], %2, %3;\n"
|
| 119 |
+
:: "r"(smem_int_ptr),
|
| 120 |
+
"l"(gmem_ptr),
|
| 121 |
+
"n"(sizeof(TS)),
|
| 122 |
+
"r"(src_size));
|
| 123 |
+
#else
|
| 124 |
+
CUTE_INVALID_CONTROL_PATH("Support for cp.async instructions has not been enabled");
|
| 125 |
+
#endif
|
| 126 |
+
}
|
| 127 |
+
};
|
| 128 |
+
|
| 129 |
+
/// Copy via cp.async with caching at global level
|
| 130 |
+
template <class TS, class TD = TS>
|
| 131 |
+
struct SM80_CP_ASYNC_CACHEGLOBAL_ZFILL
|
| 132 |
+
{
|
| 133 |
+
using SRegisters = TS[1];
|
| 134 |
+
using DRegisters = TD[1];
|
| 135 |
+
|
| 136 |
+
static_assert(sizeof(TS) == sizeof(TD), "cp.async requires sizeof(src_value_type) == sizeof(dst_value_type)");
|
| 137 |
+
static_assert(sizeof(TS) == 16, "cp.async sizeof(TS) is not supported");
|
| 138 |
+
|
| 139 |
+
CUTE_HOST_DEVICE static void
|
| 140 |
+
copy(TS const& gmem_src,
|
| 141 |
+
TD & smem_dst,
|
| 142 |
+
bool pred)
|
| 143 |
+
{
|
| 144 |
+
#if defined(CUTE_ARCH_CP_ASYNC_SM80_ENABLED)
|
| 145 |
+
TS const* gmem_ptr = &gmem_src;
|
| 146 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(&smem_dst);
|
| 147 |
+
int src_size = pred ? sizeof(TS) : 0;
|
| 148 |
+
asm volatile("cp.async.cg.shared.global.L2::128B [%0], [%1], %2, %3;\n"
|
| 149 |
+
:: "r"(smem_int_ptr),
|
| 150 |
+
"l"(gmem_ptr),
|
| 151 |
+
"n"(sizeof(TS)),
|
| 152 |
+
"r"(src_size));
|
| 153 |
+
#else
|
| 154 |
+
CUTE_INVALID_CONTROL_PATH("Support for cp.async instructions has not been enabled");
|
| 155 |
+
#endif
|
| 156 |
+
}
|
| 157 |
+
};
|
| 158 |
+
|
| 159 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 160 |
+
|
| 161 |
+
/// Establishes an ordering w.r.t previously issued cp.async instructions. Does not block.
|
| 162 |
+
CUTE_HOST_DEVICE
|
| 163 |
+
void
|
| 164 |
+
cp_async_fence()
|
| 165 |
+
{
|
| 166 |
+
#if defined(CUTE_ARCH_CP_ASYNC_SM80_ENABLED)
|
| 167 |
+
asm volatile("cp.async.commit_group;\n" ::);
|
| 168 |
+
#endif
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 172 |
+
|
| 173 |
+
/// Blocks until all but N previous cp.async.commit_group operations have committed.
|
| 174 |
+
template <int N>
|
| 175 |
+
CUTE_HOST_DEVICE
|
| 176 |
+
void
|
| 177 |
+
cp_async_wait()
|
| 178 |
+
{
|
| 179 |
+
#if defined(CUTE_ARCH_CP_ASYNC_SM80_ENABLED)
|
| 180 |
+
if constexpr (N == 0) {
|
| 181 |
+
asm volatile("cp.async.wait_all;\n" ::);
|
| 182 |
+
} else {
|
| 183 |
+
asm volatile("cp.async.wait_group %0;\n" :: "n"(N));
|
| 184 |
+
}
|
| 185 |
+
#endif
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
template <int N>
|
| 189 |
+
CUTE_HOST_DEVICE
|
| 190 |
+
void
|
| 191 |
+
cp_async_wait(Int<N>)
|
| 192 |
+
{
|
| 193 |
+
return cp_async_wait<N>();
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 197 |
+
|
| 198 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/copy_sm90.hpp
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/config.hpp> // CUTE_HOST_DEVICE
|
| 34 |
+
#include <cute/arch/config.hpp> // CUTE_ARCH_TMA_SMxx_ENABLED
|
| 35 |
+
#include <cute/arch/copy.hpp>
|
| 36 |
+
|
| 37 |
+
namespace cute
|
| 38 |
+
{
|
| 39 |
+
|
| 40 |
+
struct SM90_U32x1_STSM_N
|
| 41 |
+
{
|
| 42 |
+
using SRegisters = uint32_t[1];
|
| 43 |
+
using DRegisters = uint128_t[1];
|
| 44 |
+
|
| 45 |
+
CUTE_HOST_DEVICE static void
|
| 46 |
+
copy(uint32_t const& src,
|
| 47 |
+
uint128_t & smem_dst)
|
| 48 |
+
{
|
| 49 |
+
#if defined(CUTE_ARCH_STSM_SM90_ENABLED)
|
| 50 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(&smem_dst);
|
| 51 |
+
asm volatile ("stmatrix.sync.aligned.x1.m8n8.shared.b16 [%0], {%1};\n"
|
| 52 |
+
:: "r"(smem_int_ptr),
|
| 53 |
+
"r"(src));
|
| 54 |
+
#else
|
| 55 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use stmatrix without CUTE_ARCH_STSM_SM90_ENABLED.");
|
| 56 |
+
#endif
|
| 57 |
+
}
|
| 58 |
+
};
|
| 59 |
+
|
| 60 |
+
struct SM90_U32x2_STSM_N
|
| 61 |
+
{
|
| 62 |
+
using SRegisters = uint32_t[2];
|
| 63 |
+
using DRegisters = uint128_t[1];
|
| 64 |
+
|
| 65 |
+
CUTE_HOST_DEVICE static void
|
| 66 |
+
copy(uint32_t const& src0, uint32_t const& src1,
|
| 67 |
+
uint128_t& smem_dst)
|
| 68 |
+
{
|
| 69 |
+
#if defined(CUTE_ARCH_STSM_SM90_ENABLED)
|
| 70 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(&smem_dst);
|
| 71 |
+
asm volatile ("stmatrix.sync.aligned.x2.m8n8.shared.b16 [%0], {%1, %2};\n"
|
| 72 |
+
:: "r"(smem_int_ptr),
|
| 73 |
+
"r"(src0), "r"(src1));
|
| 74 |
+
#else
|
| 75 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use stmatrix without CUTE_ARCH_STSM_SM90_ENABLED.");
|
| 76 |
+
#endif
|
| 77 |
+
}
|
| 78 |
+
};
|
| 79 |
+
|
| 80 |
+
struct SM90_U32x4_STSM_N
|
| 81 |
+
{
|
| 82 |
+
using SRegisters = uint32_t[4];
|
| 83 |
+
using DRegisters = uint128_t[1];
|
| 84 |
+
|
| 85 |
+
CUTE_HOST_DEVICE static void
|
| 86 |
+
copy(uint32_t const& src0, uint32_t const& src1, uint32_t const& src2, uint32_t const& src3,
|
| 87 |
+
uint128_t& smem_dst)
|
| 88 |
+
{
|
| 89 |
+
#if defined(CUTE_ARCH_STSM_SM90_ENABLED)
|
| 90 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(&smem_dst);
|
| 91 |
+
asm volatile ("stmatrix.sync.aligned.x4.m8n8.shared.b16 [%0], {%1, %2, %3, %4};\n"
|
| 92 |
+
:: "r"(smem_int_ptr),
|
| 93 |
+
"r"(src0), "r"(src1), "r"(src2), "r"(src3));
|
| 94 |
+
#else
|
| 95 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use stmatrix without CUTE_ARCH_STSM_SM90_ENABLED.");
|
| 96 |
+
#endif
|
| 97 |
+
}
|
| 98 |
+
};
|
| 99 |
+
|
| 100 |
+
struct SM90_U16x2_STSM_T
|
| 101 |
+
{
|
| 102 |
+
using SRegisters = uint32_t[1];
|
| 103 |
+
using DRegisters = uint128_t[1];
|
| 104 |
+
|
| 105 |
+
CUTE_HOST_DEVICE static void
|
| 106 |
+
copy(uint32_t const& src,
|
| 107 |
+
uint128_t& smem_dst)
|
| 108 |
+
{
|
| 109 |
+
#if defined(CUTE_ARCH_STSM_SM90_ENABLED)
|
| 110 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(&smem_dst);
|
| 111 |
+
asm volatile ("stmatrix.sync.aligned.x1.trans.m8n8.shared.b16 [%0], {%1};\n"
|
| 112 |
+
:: "r"(smem_int_ptr),
|
| 113 |
+
"r"(src));
|
| 114 |
+
#else
|
| 115 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use stmatrix without CUTE_ARCH_STSM_SM90_ENABLED.");
|
| 116 |
+
#endif
|
| 117 |
+
}
|
| 118 |
+
};
|
| 119 |
+
|
| 120 |
+
struct SM90_U16x4_STSM_T
|
| 121 |
+
{
|
| 122 |
+
using SRegisters = uint32_t[2];
|
| 123 |
+
using DRegisters = uint128_t[1];
|
| 124 |
+
|
| 125 |
+
CUTE_HOST_DEVICE static void
|
| 126 |
+
copy(uint32_t const& src0, uint32_t const& src1,
|
| 127 |
+
uint128_t& smem_dst)
|
| 128 |
+
{
|
| 129 |
+
#if defined(CUTE_ARCH_STSM_SM90_ENABLED)
|
| 130 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(&smem_dst);
|
| 131 |
+
asm volatile ("stmatrix.sync.aligned.x2.trans.m8n8.shared.b16 [%0], {%1, %2};\n"
|
| 132 |
+
:: "r"(smem_int_ptr),
|
| 133 |
+
"r"(src0), "r"(src1));
|
| 134 |
+
#else
|
| 135 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use stmatrix without CUTE_ARCH_STSM_SM90_ENABLED.");
|
| 136 |
+
#endif
|
| 137 |
+
}
|
| 138 |
+
};
|
| 139 |
+
|
| 140 |
+
struct SM90_U16x8_STSM_T
|
| 141 |
+
{
|
| 142 |
+
using SRegisters = uint32_t[4];
|
| 143 |
+
using DRegisters = uint128_t[1];
|
| 144 |
+
|
| 145 |
+
CUTE_HOST_DEVICE static void
|
| 146 |
+
copy(uint32_t const& src0, uint32_t const& src1, uint32_t const& src2, uint32_t const& src3,
|
| 147 |
+
uint128_t& smem_dst)
|
| 148 |
+
{
|
| 149 |
+
#if defined(CUTE_ARCH_STSM_SM90_ENABLED)
|
| 150 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(&smem_dst);
|
| 151 |
+
asm volatile ("stmatrix.sync.aligned.x4.trans.m8n8.shared.b16 [%0], {%1, %2, %3, %4};\n"
|
| 152 |
+
:: "r"(smem_int_ptr),
|
| 153 |
+
"r"(src0), "r"(src1), "r"(src2), "r"(src3));
|
| 154 |
+
#else
|
| 155 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use stmatrix without CUTE_ARCH_STSM_SM90_ENABLED.");
|
| 156 |
+
#endif
|
| 157 |
+
}
|
| 158 |
+
};
|
| 159 |
+
|
| 160 |
+
//
|
| 161 |
+
// Legacy STSM interfaces that aren't very useful
|
| 162 |
+
//
|
| 163 |
+
|
| 164 |
+
template <class T>
|
| 165 |
+
CUTE_HOST_DEVICE
|
| 166 |
+
void
|
| 167 |
+
copy_stsm(T const* const rmem_ptr,
|
| 168 |
+
uint128_t* const smem_ptr)
|
| 169 |
+
{
|
| 170 |
+
uint32_t const* reg_ptr = reinterpret_cast<uint32_t const*>(rmem_ptr);
|
| 171 |
+
|
| 172 |
+
// if constexpr
|
| 173 |
+
if (sizeof(T) == 4) {
|
| 174 |
+
SM90_U32x1_STSM_N::copy(reg_ptr[0], smem_ptr[0]);
|
| 175 |
+
}
|
| 176 |
+
else if (sizeof(T) == 8) {
|
| 177 |
+
SM90_U32x2_STSM_N::copy(reg_ptr[0], reg_ptr[1], smem_ptr[0]);
|
| 178 |
+
}
|
| 179 |
+
else if (sizeof(T) == 16) {
|
| 180 |
+
SM90_U32x4_STSM_N::copy(reg_ptr[0], reg_ptr[1], reg_ptr[2], reg_ptr[3], smem_ptr[0]);
|
| 181 |
+
}
|
| 182 |
+
else {
|
| 183 |
+
static_assert(sizeof(T) == 4 || sizeof(T) == 8 || sizeof(T) == 16, "sizeof(T) is not supported");
|
| 184 |
+
}
|
| 185 |
+
}
|
| 186 |
+
|
| 187 |
+
template <class T>
|
| 188 |
+
CUTE_HOST_DEVICE
|
| 189 |
+
void
|
| 190 |
+
copy_stsm_trans(T const* const rmem_ptr,
|
| 191 |
+
uint128_t* const smem_ptr)
|
| 192 |
+
{
|
| 193 |
+
uint32_t const* reg_ptr = reinterpret_cast<uint32_t const*>(rmem_ptr);
|
| 194 |
+
|
| 195 |
+
// if constexpr
|
| 196 |
+
if (sizeof(T) == 4) {
|
| 197 |
+
SM90_U16x2_STSM_T::copy(reg_ptr[0], smem_ptr[0]);
|
| 198 |
+
}
|
| 199 |
+
else if (sizeof(T) == 8) {
|
| 200 |
+
SM90_U16x4_STSM_T::copy(reg_ptr[0], reg_ptr[1], smem_ptr[0]);
|
| 201 |
+
}
|
| 202 |
+
else if (sizeof(T) == 16) {
|
| 203 |
+
SM90_U16x8_STSM_T::copy(reg_ptr[0], reg_ptr[1], reg_ptr[2], reg_ptr[3], smem_ptr[0]);
|
| 204 |
+
}
|
| 205 |
+
else {
|
| 206 |
+
static_assert(sizeof(T) == 4 || sizeof(T) == 8 || sizeof(T) == 16, "sizeof(T) is not supported");
|
| 207 |
+
}
|
| 208 |
+
}
|
| 209 |
+
|
| 210 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 211 |
+
|
| 212 |
+
} // end namespace cute
|
| 213 |
+
|
| 214 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 215 |
+
|
| 216 |
+
#include <cute/arch/copy_sm90_desc.hpp>
|
| 217 |
+
#include <cute/arch/copy_sm90_tma.hpp>
|
| 218 |
+
|
| 219 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/copy_sm90_desc.hpp
ADDED
|
@@ -0,0 +1,475 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include "cutlass/numeric_types.h"
|
| 34 |
+
|
| 35 |
+
#if !defined(__CUDACC_RTC__)
|
| 36 |
+
#include <cuda.h>
|
| 37 |
+
#include <cinttypes>
|
| 38 |
+
#endif
|
| 39 |
+
|
| 40 |
+
#include <cute/config.hpp>
|
| 41 |
+
|
| 42 |
+
#include <cute/arch/util.hpp> // cute::cast_smem_ptr_to_uint
|
| 43 |
+
#include <cute/arch/config.hpp> // CUTE_ARCH_TMA_SMxx_ENABLED
|
| 44 |
+
#include <cute/arch/copy.hpp>
|
| 45 |
+
#include <cute/arch/copy_sm90.hpp>
|
| 46 |
+
|
| 47 |
+
#include <cute/container/alignment.hpp>
|
| 48 |
+
#include <cute/container/bit_field.hpp>
|
| 49 |
+
#include <cute/container/array.hpp>
|
| 50 |
+
#include <cute/numeric/numeric_types.hpp>
|
| 51 |
+
|
| 52 |
+
namespace cute
|
| 53 |
+
{
|
| 54 |
+
|
| 55 |
+
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 56 |
+
/// Barriers are 64-bit of user-managed information used in broadly two types syncronization patterns
|
| 57 |
+
/// 1) arrive/wait on threads (usage: cp.async and warp-specialized kernels)
|
| 58 |
+
/// 2) transaction-based (usage: TMA transaction where a CTA issues one transaction)
|
| 59 |
+
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 60 |
+
|
| 61 |
+
// Initialize barrier present in shared memory
|
| 62 |
+
CUTE_HOST_DEVICE
|
| 63 |
+
void
|
| 64 |
+
initialize_barrier(uint64_t& smem_barrier, // 64 bits user-manged barrier in smem
|
| 65 |
+
int thread_count = 1) // Thread count expected to arrive/wait on this barrier
|
| 66 |
+
{
|
| 67 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 68 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(&smem_barrier);
|
| 69 |
+
asm volatile ("mbarrier.init.shared::cta.b64 [%0], %1;\n"
|
| 70 |
+
:: "r"(smem_int_ptr),
|
| 71 |
+
"r"(thread_count));
|
| 72 |
+
#endif
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
// Set the number of bytes transfered per transaction and perform an arrive operation as well
|
| 76 |
+
CUTE_HOST_DEVICE
|
| 77 |
+
void
|
| 78 |
+
set_barrier_transaction_bytes(uint64_t& smem_barrier, // 64 bits user-manged barrier in smem
|
| 79 |
+
uint32_t bytes) // Number of bytes transfered by per TMA transaction
|
| 80 |
+
{
|
| 81 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 82 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(&smem_barrier);
|
| 83 |
+
asm volatile ("mbarrier.arrive.expect_tx.shared::cta.b64 _, [%0], %1;\n"
|
| 84 |
+
:: "r"(smem_int_ptr),
|
| 85 |
+
"r"(bytes));
|
| 86 |
+
#endif
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
// Barrier wait
|
| 90 |
+
CUTE_HOST_DEVICE
|
| 91 |
+
void
|
| 92 |
+
wait_barrier(uint64_t& smem_barrier, // 64 bits user-manged barrier in smem
|
| 93 |
+
int phase_bit) // Current phase bit the barrier waiting to flip
|
| 94 |
+
{
|
| 95 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 96 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(&smem_barrier);
|
| 97 |
+
asm volatile(
|
| 98 |
+
"{\n"
|
| 99 |
+
".reg .pred P1;\n"
|
| 100 |
+
"LAB_WAIT:\n"
|
| 101 |
+
"mbarrier.try_wait.parity.shared::cta.b64 P1, [%0], %1;\n"
|
| 102 |
+
"@P1 bra DONE;\n"
|
| 103 |
+
"bra LAB_WAIT;\n"
|
| 104 |
+
"DONE:\n"
|
| 105 |
+
"}\n"
|
| 106 |
+
:: "r"(smem_int_ptr),
|
| 107 |
+
"r"(phase_bit));
|
| 108 |
+
|
| 109 |
+
#endif
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
// Barrier arrive
|
| 113 |
+
CUTE_HOST_DEVICE
|
| 114 |
+
void
|
| 115 |
+
arrive_barrier(uint64_t& smem_barrier) // 64 bits user-manged barrier in smem
|
| 116 |
+
{
|
| 117 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 118 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(&smem_barrier);
|
| 119 |
+
asm volatile(
|
| 120 |
+
"{\n"
|
| 121 |
+
".reg .b64 state; \n"
|
| 122 |
+
"mbarrier.arrive.shared::cta.b64 state, [%0];\n"
|
| 123 |
+
"}\n"
|
| 124 |
+
:: "r"(smem_int_ptr));
|
| 125 |
+
#endif
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 129 |
+
// TMA Descriptor and utilities
|
| 130 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 131 |
+
|
| 132 |
+
namespace TMA {
|
| 133 |
+
|
| 134 |
+
enum class SmemSwizzleBits : uint8_t {
|
| 135 |
+
DISABLE = 0,
|
| 136 |
+
B32 = 1,
|
| 137 |
+
B64 = 2,
|
| 138 |
+
B128 = 3,
|
| 139 |
+
};
|
| 140 |
+
|
| 141 |
+
enum class SmemSwizzleBase : uint8_t {
|
| 142 |
+
SWIZZLE_BASE_16B = 0,
|
| 143 |
+
|
| 144 |
+
SWIZZLE_BASE_32B = 1,
|
| 145 |
+
SWIZZLE_BASE_32B_FLIP_8B = 2,
|
| 146 |
+
SWIZZLE_BASE_64B = 3,
|
| 147 |
+
|
| 148 |
+
};
|
| 149 |
+
|
| 150 |
+
enum class OOBFill : uint8_t {
|
| 151 |
+
ZERO = 0,
|
| 152 |
+
CONSTANT = 1,
|
| 153 |
+
};
|
| 154 |
+
|
| 155 |
+
CUTE_HOST_DEVICE char const* to_string(OOBFill const& t) {
|
| 156 |
+
switch (t) {
|
| 157 |
+
case OOBFill::ZERO: return "ZERO";
|
| 158 |
+
case OOBFill::CONSTANT: return "CONSTANT";
|
| 159 |
+
}
|
| 160 |
+
return nullptr;
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
enum class L2Promotion : uint8_t {
|
| 164 |
+
DISABLE = 0,
|
| 165 |
+
B64 = 1,
|
| 166 |
+
B128 = 2,
|
| 167 |
+
B256 = 3,
|
| 168 |
+
};
|
| 169 |
+
|
| 170 |
+
CUTE_HOST_DEVICE char const* to_string(L2Promotion const& t) {
|
| 171 |
+
switch (t) {
|
| 172 |
+
case L2Promotion::DISABLE: return "DISABLE";
|
| 173 |
+
case L2Promotion::B64: return "B64";
|
| 174 |
+
case L2Promotion::B128: return "B128";
|
| 175 |
+
case L2Promotion::B256: return "B256";
|
| 176 |
+
}
|
| 177 |
+
return nullptr;
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
// Aux parameters which are independent with the problem size
|
| 181 |
+
struct DescriptorAuxParams {
|
| 182 |
+
OOBFill oobfill_ = OOBFill::ZERO;
|
| 183 |
+
L2Promotion l2promo_ = L2Promotion::DISABLE;
|
| 184 |
+
};
|
| 185 |
+
|
| 186 |
+
enum class CacheHintSm90 : uint64_t {
|
| 187 |
+
EVICT_NORMAL = 0x1000000000000000,
|
| 188 |
+
EVICT_FIRST = 0x12F0000000000000,
|
| 189 |
+
EVICT_LAST = 0x14F0000000000000,
|
| 190 |
+
};
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
enum class CacheHintSm100 : uint64_t {
|
| 194 |
+
EVICT_NORMAL = 0x1000000000000000,
|
| 195 |
+
EVICT_FIRST = 0x12F0000000000000,
|
| 196 |
+
EVICT_LAST = 0x14F0000000000000,
|
| 197 |
+
};
|
| 198 |
+
|
| 199 |
+
|
| 200 |
+
#if (__CUDACC_VER_MAJOR__ >= 12)
|
| 201 |
+
|
| 202 |
+
#if !defined(__CUDACC_RTC__)
|
| 203 |
+
/// @return The TMA descriptor datatype enum corresponding to T.
|
| 204 |
+
template <class T>
|
| 205 |
+
inline CUtensorMapDataType
|
| 206 |
+
to_CUtensorMapDataType() {
|
| 207 |
+
if constexpr (is_same_v<T, int8_t>) { return CU_TENSOR_MAP_DATA_TYPE_UINT8; } else
|
| 208 |
+
if constexpr (is_same_v<T, uint8_t>) { return CU_TENSOR_MAP_DATA_TYPE_UINT8; } else
|
| 209 |
+
if constexpr (is_same_v<T, float_e4m3_t>) { return CU_TENSOR_MAP_DATA_TYPE_UINT8; } else
|
| 210 |
+
if constexpr (is_same_v<T, float_e5m2_t>) { return CU_TENSOR_MAP_DATA_TYPE_UINT8; } else
|
| 211 |
+
if constexpr (is_same_v<T, float_ue8m0_t>) { return CU_TENSOR_MAP_DATA_TYPE_UINT8; } else
|
| 212 |
+
if constexpr (is_same_v<T, type_erased_dynamic_float8_t>) { return CU_TENSOR_MAP_DATA_TYPE_UINT8;} else
|
| 213 |
+
if constexpr (is_same_v<T, uint16_t>) { return CU_TENSOR_MAP_DATA_TYPE_UINT16; } else
|
| 214 |
+
if constexpr (is_same_v<T, uint32_t>) { return CU_TENSOR_MAP_DATA_TYPE_UINT32; } else
|
| 215 |
+
if constexpr (is_same_v<T, uint64_t>) { return CU_TENSOR_MAP_DATA_TYPE_UINT64; } else
|
| 216 |
+
if constexpr (is_same_v<T, int32_t>) { return CU_TENSOR_MAP_DATA_TYPE_INT32; } else
|
| 217 |
+
if constexpr (is_same_v<T, int64_t>) { return CU_TENSOR_MAP_DATA_TYPE_INT64; } else
|
| 218 |
+
if constexpr (is_same_v<T, half_t>) { return CU_TENSOR_MAP_DATA_TYPE_FLOAT16; } else
|
| 219 |
+
if constexpr (is_same_v<T, float>) { return CU_TENSOR_MAP_DATA_TYPE_FLOAT32; } else
|
| 220 |
+
if constexpr (is_same_v<T, double>) { return CU_TENSOR_MAP_DATA_TYPE_FLOAT64; } else
|
| 221 |
+
if constexpr (is_same_v<T, bfloat16_t>) { return CU_TENSOR_MAP_DATA_TYPE_BFLOAT16; } else
|
| 222 |
+
if constexpr (is_same_v<T, tfloat32_t>) { return CU_TENSOR_MAP_DATA_TYPE_TFLOAT32; } else
|
| 223 |
+
#if ((__CUDACC_VER_MAJOR__ > 12) || ((__CUDACC_VER_MAJOR__ == 12) && (__CUDACC_VER_MINOR__ > 6)))
|
| 224 |
+
if constexpr (is_same_v<T, float_e2m1_t>) { return CU_TENSOR_MAP_DATA_TYPE_16U4_ALIGN8B; } else
|
| 225 |
+
if constexpr (is_same_v<T, float_e2m3_t>) { return CU_TENSOR_MAP_DATA_TYPE_16U6_ALIGN16B; } else
|
| 226 |
+
if constexpr (is_same_v<T, float_e3m2_t>) { return CU_TENSOR_MAP_DATA_TYPE_16U6_ALIGN16B; } else
|
| 227 |
+
if constexpr (is_same_v<T, type_erased_dynamic_float4_t>) { return CU_TENSOR_MAP_DATA_TYPE_16U4_ALIGN8B; } else
|
| 228 |
+
if constexpr (is_same_v<T, type_erased_dynamic_float6_t>) { return CU_TENSOR_MAP_DATA_TYPE_16U6_ALIGN16B; } else
|
| 229 |
+
if constexpr (is_same_v<T, detail::float_e2m1_unpacksmem_t>) { return CU_TENSOR_MAP_DATA_TYPE_16U4_ALIGN16B; } else
|
| 230 |
+
if constexpr (is_same_v<T, detail::float_e2m3_unpacksmem_t>) { return CU_TENSOR_MAP_DATA_TYPE_16U6_ALIGN16B; } else
|
| 231 |
+
if constexpr (is_same_v<T, detail::float_e3m2_unpacksmem_t>) { return CU_TENSOR_MAP_DATA_TYPE_16U6_ALIGN16B; } else
|
| 232 |
+
if constexpr (is_same_v<T, detail::type_erased_dynamic_float4_unpacksmem_t>) { return CU_TENSOR_MAP_DATA_TYPE_16U4_ALIGN16B; } else
|
| 233 |
+
if constexpr (is_same_v<T, detail::type_erased_dynamic_float6_unpacksmem_t>) { return CU_TENSOR_MAP_DATA_TYPE_16U6_ALIGN16B; } else
|
| 234 |
+
#endif
|
| 235 |
+
|
| 236 |
+
{ static_assert(sizeof(T) < 0, "Unknown TMA Format!"); }
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
inline CUtensorMapSwizzle
|
| 240 |
+
to_CUtensorMapSwizzle(SmemSwizzleBits const& t, SmemSwizzleBase const& b) {
|
| 241 |
+
switch (t) {
|
| 242 |
+
default: assert(false && "Unsupported pair of SmemSwizzleBits and SmemSwizzleBase!");
|
| 243 |
+
case SmemSwizzleBits::DISABLE:
|
| 244 |
+
assert((b == SmemSwizzleBase::SWIZZLE_BASE_16B) && "Expected 16B swizzle base for 0B swizzle bits.");
|
| 245 |
+
return CU_TENSOR_MAP_SWIZZLE_NONE;
|
| 246 |
+
case SmemSwizzleBits::B32:
|
| 247 |
+
assert((b == SmemSwizzleBase::SWIZZLE_BASE_16B) && "Expected 16B swizzle base for 32B swizzle bits.");
|
| 248 |
+
return CU_TENSOR_MAP_SWIZZLE_32B;
|
| 249 |
+
case SmemSwizzleBits::B64:
|
| 250 |
+
assert((b == SmemSwizzleBase::SWIZZLE_BASE_16B) && "Expected 16B swizzle base for 64B swizzle bits.");
|
| 251 |
+
return CU_TENSOR_MAP_SWIZZLE_64B;
|
| 252 |
+
case SmemSwizzleBits::B128:
|
| 253 |
+
switch (b) {
|
| 254 |
+
default: assert(false && "Unsupported pair of SmemSwizzleBits and SmemSwizzleBase!");
|
| 255 |
+
case SmemSwizzleBase::SWIZZLE_BASE_16B: return CU_TENSOR_MAP_SWIZZLE_128B;
|
| 256 |
+
|
| 257 |
+
#if ((__CUDACC_VER_MAJOR__ > 12) || ((__CUDACC_VER_MAJOR__ == 12) && (__CUDACC_VER_MINOR__ > 6)))
|
| 258 |
+
case SmemSwizzleBase::SWIZZLE_BASE_32B: return CU_TENSOR_MAP_SWIZZLE_128B_ATOM_32B;
|
| 259 |
+
case SmemSwizzleBase::SWIZZLE_BASE_64B: return CU_TENSOR_MAP_SWIZZLE_128B_ATOM_64B;
|
| 260 |
+
#endif
|
| 261 |
+
}
|
| 262 |
+
}
|
| 263 |
+
}
|
| 264 |
+
|
| 265 |
+
inline CUtensorMapFloatOOBfill
|
| 266 |
+
to_CUtensorMapFloatOOBfill(OOBFill const& t) {
|
| 267 |
+
switch(t) {
|
| 268 |
+
default: assert(false && "Unknown OOBFill!");
|
| 269 |
+
case OOBFill::ZERO: return CU_TENSOR_MAP_FLOAT_OOB_FILL_NONE;
|
| 270 |
+
case OOBFill::CONSTANT: return CU_TENSOR_MAP_FLOAT_OOB_FILL_NAN_REQUEST_ZERO_FMA;
|
| 271 |
+
}
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
inline CUtensorMapL2promotion
|
| 275 |
+
to_CUtensorMapL2promotion(L2Promotion const& t) {
|
| 276 |
+
switch(t) {
|
| 277 |
+
default: assert(false && "Unknown L2Promotion!");
|
| 278 |
+
case L2Promotion::DISABLE: return CU_TENSOR_MAP_L2_PROMOTION_NONE;
|
| 279 |
+
case L2Promotion::B64: return CU_TENSOR_MAP_L2_PROMOTION_L2_64B;
|
| 280 |
+
case L2Promotion::B128: return CU_TENSOR_MAP_L2_PROMOTION_L2_128B;
|
| 281 |
+
case L2Promotion::B256: return CU_TENSOR_MAP_L2_PROMOTION_L2_256B;
|
| 282 |
+
}
|
| 283 |
+
}
|
| 284 |
+
|
| 285 |
+
#endif // !defined(__CUDACC_RTC__)
|
| 286 |
+
|
| 287 |
+
#endif // (__CUDACC_VER_MAJOR__ >= 12)
|
| 288 |
+
|
| 289 |
+
} // end namespace TMA
|
| 290 |
+
|
| 291 |
+
#if (__CUDACC_VER_MAJOR__ >= 12) && !defined(__CUDACC_RTC__)
|
| 292 |
+
using TmaDescriptor = CUtensorMap;
|
| 293 |
+
using Im2ColTmaDescriptor = CUtensorMap;
|
| 294 |
+
#else
|
| 295 |
+
using TmaDescriptor = struct alignas(64) { char bytes[128]; };
|
| 296 |
+
using Im2ColTmaDescriptor = struct alignas(64) { char bytes[128]; };
|
| 297 |
+
#endif
|
| 298 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 299 |
+
/// Initiates a TensorMap Prefetch
|
| 300 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 301 |
+
|
| 302 |
+
CUTE_HOST_DEVICE
|
| 303 |
+
void
|
| 304 |
+
prefetch_tma_descriptor(TmaDescriptor const* desc_ptr)
|
| 305 |
+
{
|
| 306 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 307 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 308 |
+
// Prefetch TMA Descriptor using generic addressing (i.e. no specific state space: const or param)
|
| 309 |
+
asm volatile (
|
| 310 |
+
"prefetch.tensormap [%0];"
|
| 311 |
+
:
|
| 312 |
+
: "l"(gmem_int_desc)
|
| 313 |
+
: "memory");
|
| 314 |
+
#else
|
| 315 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use TMA Descriptor Prefetch without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 316 |
+
#endif
|
| 317 |
+
}
|
| 318 |
+
|
| 319 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 320 |
+
/// Perform a TensorMap modification (by each field)
|
| 321 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 322 |
+
|
| 323 |
+
// Replace tensor pointer directly in GMEM
|
| 324 |
+
CUTE_HOST_DEVICE
|
| 325 |
+
void
|
| 326 |
+
tma_descriptor_replace_addr_in_global_mem(TmaDescriptor const* desc_ptr,
|
| 327 |
+
void const* const new_tensor_ptr)
|
| 328 |
+
{
|
| 329 |
+
#if defined(CUTE_ARCH_DEVICE_MODIFIABLE_TMA_SM90_ENABLED)
|
| 330 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 331 |
+
uint64_t const new_desc_addr = reinterpret_cast<uint64_t>(new_tensor_ptr);
|
| 332 |
+
asm volatile (
|
| 333 |
+
"tensormap.replace.tile.global_address.global.b1024.b64 [%0], %1;"
|
| 334 |
+
:: "l"(gmem_int_desc), "l"(new_desc_addr));
|
| 335 |
+
#else
|
| 336 |
+
CUTE_INVALID_CONTROL_PATH("Using TMA Descriptor modification without CUTE_ARCH_DEVICE_MODIFIABLE_TMA_SM90_ENABLED and CUDA 12.3");
|
| 337 |
+
#endif
|
| 338 |
+
}
|
| 339 |
+
|
| 340 |
+
// Replace tensor pointer by bringing the tensormap from GMEM into the shared memory
|
| 341 |
+
CUTE_HOST_DEVICE
|
| 342 |
+
void
|
| 343 |
+
tma_descriptor_replace_addr_in_shared_mem(TmaDescriptor& smem_desc,
|
| 344 |
+
void const* const new_tensor_ptr)
|
| 345 |
+
{
|
| 346 |
+
#if defined(CUTE_ARCH_DEVICE_MODIFIABLE_TMA_SM90_ENABLED)
|
| 347 |
+
uint32_t smem_int_desc = cast_smem_ptr_to_uint(&smem_desc);
|
| 348 |
+
uint64_t const new_desc_addr = reinterpret_cast<uint64_t>(new_tensor_ptr);
|
| 349 |
+
asm volatile (
|
| 350 |
+
"tensormap.replace.tile.global_address.shared::cta.b1024.b64 [%0], %1;"
|
| 351 |
+
:: "r"(smem_int_desc), "l"(new_desc_addr));
|
| 352 |
+
#else
|
| 353 |
+
CUTE_INVALID_CONTROL_PATH("Using TMA Descriptor modification without CUTE_ARCH_DEVICE_MODIFIABLE_TMA_SM90_ENABLED and CUDA 12.3");
|
| 354 |
+
#endif
|
| 355 |
+
}
|
| 356 |
+
|
| 357 |
+
// Replace tensor dims and strides for GEMMs by bringing the tensormap from GMEM into the shared memory
|
| 358 |
+
CUTE_HOST_DEVICE
|
| 359 |
+
void
|
| 360 |
+
tma_descriptor_replace_dims_strides_in_shared_mem(TmaDescriptor & smem_desc,
|
| 361 |
+
cute::array<uint32_t, 5> const& prob_shape,
|
| 362 |
+
cute::array<uint64_t, 5> const& prob_stride)
|
| 363 |
+
{
|
| 364 |
+
#if defined(CUTE_ARCH_DEVICE_MODIFIABLE_TMA_SM90_ENABLED)
|
| 365 |
+
uint32_t smem_int_desc = cast_smem_ptr_to_uint(&smem_desc);
|
| 366 |
+
uint64_t const smem_int64_desc = 0;
|
| 367 |
+
asm volatile (
|
| 368 |
+
"cvt.u64.u32 %0, %1;"
|
| 369 |
+
:: "l"(smem_int64_desc), "r"(smem_int_desc));
|
| 370 |
+
asm volatile (
|
| 371 |
+
"tensormap.replace.tile.global_dim.shared::cta.b1024.b32 [%0], 0, %1;"
|
| 372 |
+
:: "l"(smem_int64_desc), "r"(prob_shape[0]));
|
| 373 |
+
asm volatile (
|
| 374 |
+
"tensormap.replace.tile.global_dim.shared::cta.b1024.b32 [%0], 1, %1;"
|
| 375 |
+
:: "l"(smem_int64_desc), "r"(prob_shape[1]));
|
| 376 |
+
asm volatile (
|
| 377 |
+
"tensormap.replace.tile.global_dim.shared::cta.b1024.b32 [%0], 2, %1;"
|
| 378 |
+
:: "l"(smem_int64_desc), "r"(prob_shape[2]));
|
| 379 |
+
asm volatile (
|
| 380 |
+
"tensormap.replace.tile.global_dim.shared::cta.b1024.b32 [%0], 3, %1;"
|
| 381 |
+
:: "l"(smem_int64_desc), "r"(prob_shape[3]));
|
| 382 |
+
asm volatile (
|
| 383 |
+
"tensormap.replace.tile.global_dim.shared::cta.b1024.b32 [%0], 4, %1;"
|
| 384 |
+
:: "l"(smem_int64_desc), "r"(prob_shape[4]));
|
| 385 |
+
// Strides must be a multiple of 16. Also, stride for the intermost dimension is implicitly 1
|
| 386 |
+
#if ((__CUDACC_VER_MAJOR__ > 12) || ((__CUDACC_VER_MAJOR__ == 12) && (__CUDACC_VER_MINOR__ >= 5)))
|
| 387 |
+
asm volatile (
|
| 388 |
+
"tensormap.replace.tile.global_stride.shared::cta.b1024.b64 [%0], 0, %1;"
|
| 389 |
+
:: "l"(smem_int64_desc), "l"(prob_stride[1]));
|
| 390 |
+
asm volatile (
|
| 391 |
+
"tensormap.replace.tile.global_stride.shared::cta.b1024.b64 [%0], 1, %1;"
|
| 392 |
+
:: "l"(smem_int64_desc), "l"(prob_stride[2]));
|
| 393 |
+
asm volatile (
|
| 394 |
+
"tensormap.replace.tile.global_stride.shared::cta.b1024.b64 [%0], 2, %1;"
|
| 395 |
+
:: "l"(smem_int64_desc), "l"(prob_stride[3]));
|
| 396 |
+
asm volatile (
|
| 397 |
+
"tensormap.replace.tile.global_stride.shared::cta.b1024.b64 [%0], 3, %1;"
|
| 398 |
+
:: "l"(smem_int64_desc), "l"(prob_stride[4]));
|
| 399 |
+
#else
|
| 400 |
+
// 4 LSBs are not included
|
| 401 |
+
asm volatile (
|
| 402 |
+
"tensormap.replace.tile.global_stride.shared::cta.b1024.b64 [%0], 0, %1;"
|
| 403 |
+
:: "l"(smem_int64_desc), "l"(prob_stride[1] >> 4));
|
| 404 |
+
asm volatile (
|
| 405 |
+
"tensormap.replace.tile.global_stride.shared::cta.b1024.b64 [%0], 1, %1;"
|
| 406 |
+
:: "l"(smem_int64_desc), "l"(prob_stride[2] >> 4));
|
| 407 |
+
asm volatile (
|
| 408 |
+
"tensormap.replace.tile.global_stride.shared::cta.b1024.b64 [%0], 2, %1;"
|
| 409 |
+
:: "l"(smem_int64_desc), "l"(prob_stride[3] >> 4));
|
| 410 |
+
asm volatile (
|
| 411 |
+
"tensormap.replace.tile.global_stride.shared::cta.b1024.b64 [%0], 3, %1;"
|
| 412 |
+
:: "l"(smem_int64_desc), "l"(prob_stride[4] >> 4));
|
| 413 |
+
#endif
|
| 414 |
+
#else
|
| 415 |
+
CUTE_INVALID_CONTROL_PATH("Using TMA Descriptor modification without CUTE_ARCH_DEVICE_MODIFIABLE_TMA_SM90_ENABLED and CUDA 12.3");
|
| 416 |
+
#endif
|
| 417 |
+
}
|
| 418 |
+
|
| 419 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 420 |
+
/// Perform a fused copy and fence operation (needed when modifying tensormap in shared memory)
|
| 421 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 422 |
+
|
| 423 |
+
CUTE_HOST_DEVICE
|
| 424 |
+
void
|
| 425 |
+
tma_descriptor_cp_fence_release(TmaDescriptor const* gmem_desc_ptr, TmaDescriptor& smem_desc)
|
| 426 |
+
{
|
| 427 |
+
#if defined(CUTE_ARCH_DEVICE_MODIFIABLE_TMA_SM90_ENABLED)
|
| 428 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(gmem_desc_ptr);
|
| 429 |
+
uint32_t smem_int_desc = cast_smem_ptr_to_uint(&smem_desc);
|
| 430 |
+
asm volatile (
|
| 431 |
+
"tensormap.cp_fenceproxy.global.shared::cta.tensormap::generic.release.gpu.sync.aligned [%0], [%1], 128;"
|
| 432 |
+
:: "l"(gmem_int_desc), "r"(smem_int_desc));
|
| 433 |
+
#else
|
| 434 |
+
CUTE_INVALID_CONTROL_PATH("Using TMA Descriptor modification without CUTE_ARCH_DEVICE_MODIFIABLE_TMA_SM90_ENABLED and CUDA 12.3");
|
| 435 |
+
#endif
|
| 436 |
+
}
|
| 437 |
+
|
| 438 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 439 |
+
/// Perform a release fence operation (needed when modifying tensormap directly in GMEM)
|
| 440 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 441 |
+
|
| 442 |
+
CUTE_HOST_DEVICE
|
| 443 |
+
void
|
| 444 |
+
tma_descriptor_fence_release()
|
| 445 |
+
{
|
| 446 |
+
#if defined(CUTE_ARCH_DEVICE_MODIFIABLE_TMA_SM90_ENABLED)
|
| 447 |
+
asm volatile ("fence.proxy.tensormap::generic.release.gpu;");
|
| 448 |
+
#else
|
| 449 |
+
CUTE_INVALID_CONTROL_PATH("Using TMA Descriptor modification without CUTE_ARCH_DEVICE_MODIFIABLE_TMA_SM90_ENABLED and CUDA 12.3");
|
| 450 |
+
#endif
|
| 451 |
+
}
|
| 452 |
+
|
| 453 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 454 |
+
/// Perform a acquire fence operation
|
| 455 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 456 |
+
|
| 457 |
+
CUTE_HOST_DEVICE
|
| 458 |
+
void
|
| 459 |
+
tma_descriptor_fence_acquire(TmaDescriptor const* desc_ptr)
|
| 460 |
+
{
|
| 461 |
+
#if defined(CUTE_ARCH_DEVICE_MODIFIABLE_TMA_SM90_ENABLED)
|
| 462 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 463 |
+
asm volatile (
|
| 464 |
+
"fence.proxy.tensormap::generic.acquire.gpu [%0], 128;"
|
| 465 |
+
:
|
| 466 |
+
: "l"(gmem_int_desc)
|
| 467 |
+
: "memory");
|
| 468 |
+
#else
|
| 469 |
+
CUTE_INVALID_CONTROL_PATH("Using TMA Descriptor modification without CUTE_ARCH_DEVICE_MODIFIABLE_TMA_SM90_ENABLED and CUDA 12.3");
|
| 470 |
+
#endif
|
| 471 |
+
}
|
| 472 |
+
|
| 473 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 474 |
+
|
| 475 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/copy_sm90_tma.hpp
ADDED
|
@@ -0,0 +1,1496 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/config.hpp>
|
| 34 |
+
|
| 35 |
+
#include <cute/arch/config.hpp> // CUTE_ARCH_TMA_SMxx_ENABLED
|
| 36 |
+
#include <cute/arch/copy.hpp>
|
| 37 |
+
#include <cute/arch/copy_sm90.hpp>
|
| 38 |
+
#include "cutlass/arch/synclog.hpp"
|
| 39 |
+
|
| 40 |
+
namespace cute
|
| 41 |
+
{
|
| 42 |
+
|
| 43 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 44 |
+
/// TMA_LOAD : Initiates a TMA copy from global memory to shared memory
|
| 45 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 46 |
+
|
| 47 |
+
struct SM90_TMA_LOAD_1D
|
| 48 |
+
{
|
| 49 |
+
CUTE_HOST_DEVICE static void
|
| 50 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint64_t cache_hint,
|
| 51 |
+
void * smem_ptr,
|
| 52 |
+
int32_t const& crd0)
|
| 53 |
+
{
|
| 54 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 55 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 56 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr);
|
| 57 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 58 |
+
cutlass::arch::synclog_emit_tma_load(__LINE__, gmem_int_desc, smem_int_mbar, smem_int_ptr);
|
| 59 |
+
#if defined(CUTE_ARCH_TMA_SM120_ENABLED)
|
| 60 |
+
asm volatile (
|
| 61 |
+
"cp.async.bulk.tensor.1d.shared::cta.global.mbarrier::complete_tx::bytes.L2::cache_hint"
|
| 62 |
+
" [%0], [%1, {%3}], [%2], %4;"
|
| 63 |
+
:
|
| 64 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 65 |
+
"r"(crd0), "l"(cache_hint)
|
| 66 |
+
: "memory");
|
| 67 |
+
#else
|
| 68 |
+
asm volatile (
|
| 69 |
+
"cp.async.bulk.tensor.1d.shared::cluster.global.mbarrier::complete_tx::bytes.L2::cache_hint"
|
| 70 |
+
" [%0], [%1, {%3}], [%2], %4;"
|
| 71 |
+
:
|
| 72 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 73 |
+
"r"(crd0), "l"(cache_hint)
|
| 74 |
+
: "memory");
|
| 75 |
+
#endif
|
| 76 |
+
#else
|
| 77 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 78 |
+
#endif
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
struct PREFETCH
|
| 82 |
+
{
|
| 83 |
+
CUTE_HOST_DEVICE static void
|
| 84 |
+
copy(void const* desc_ptr,
|
| 85 |
+
int32_t const& crd0)
|
| 86 |
+
{
|
| 87 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 88 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 89 |
+
asm volatile (
|
| 90 |
+
"cp.async.bulk.prefetch.tensor.1d.L2.global"
|
| 91 |
+
" [%0, {%1}];"
|
| 92 |
+
:
|
| 93 |
+
: "l"(gmem_int_desc),
|
| 94 |
+
"r"(crd0)
|
| 95 |
+
: "memory");
|
| 96 |
+
#else
|
| 97 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 98 |
+
#endif
|
| 99 |
+
}
|
| 100 |
+
};
|
| 101 |
+
};
|
| 102 |
+
|
| 103 |
+
struct SM90_TMA_LOAD_2D
|
| 104 |
+
{
|
| 105 |
+
CUTE_HOST_DEVICE static void
|
| 106 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint64_t cache_hint,
|
| 107 |
+
void * smem_ptr,
|
| 108 |
+
int32_t const& crd0, int32_t const& crd1)
|
| 109 |
+
{
|
| 110 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 111 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 112 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr);
|
| 113 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 114 |
+
cutlass::arch::synclog_emit_tma_load(__LINE__, gmem_int_desc, smem_int_mbar, smem_int_ptr);
|
| 115 |
+
#if defined(CUTE_ARCH_TMA_SM120_ENABLED)
|
| 116 |
+
asm volatile (
|
| 117 |
+
"cp.async.bulk.tensor.2d.shared::cta.global.mbarrier::complete_tx::bytes.L2::cache_hint"
|
| 118 |
+
" [%0], [%1, {%3, %4}], [%2], %5;"
|
| 119 |
+
:
|
| 120 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 121 |
+
"r"(crd0), "r"(crd1), "l"(cache_hint)
|
| 122 |
+
: "memory");
|
| 123 |
+
#else
|
| 124 |
+
asm volatile (
|
| 125 |
+
"cp.async.bulk.tensor.2d.shared::cluster.global.mbarrier::complete_tx::bytes.L2::cache_hint"
|
| 126 |
+
" [%0], [%1, {%3, %4}], [%2], %5;"
|
| 127 |
+
:
|
| 128 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 129 |
+
"r"(crd0), "r"(crd1), "l"(cache_hint)
|
| 130 |
+
: "memory");
|
| 131 |
+
#endif
|
| 132 |
+
#else
|
| 133 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 134 |
+
#endif
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
struct PREFETCH
|
| 138 |
+
{
|
| 139 |
+
CUTE_HOST_DEVICE static void
|
| 140 |
+
copy(void const* desc_ptr,
|
| 141 |
+
int32_t const& crd0, int32_t const& crd1)
|
| 142 |
+
{
|
| 143 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 144 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 145 |
+
asm volatile (
|
| 146 |
+
"cp.async.bulk.prefetch.tensor.2d.L2.global"
|
| 147 |
+
" [%0, {%1, %2}];"
|
| 148 |
+
:
|
| 149 |
+
: "l"(gmem_int_desc),
|
| 150 |
+
"r"(crd0), "r"(crd1)
|
| 151 |
+
: "memory");
|
| 152 |
+
#else
|
| 153 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 154 |
+
#endif
|
| 155 |
+
}
|
| 156 |
+
};
|
| 157 |
+
};
|
| 158 |
+
|
| 159 |
+
struct SM90_TMA_LOAD_3D
|
| 160 |
+
{
|
| 161 |
+
CUTE_HOST_DEVICE static void
|
| 162 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint64_t cache_hint,
|
| 163 |
+
void * smem_ptr,
|
| 164 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2)
|
| 165 |
+
{
|
| 166 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 167 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 168 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr);
|
| 169 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 170 |
+
cutlass::arch::synclog_emit_tma_load(__LINE__, gmem_int_desc, smem_int_mbar, smem_int_ptr);
|
| 171 |
+
#if defined(CUTE_ARCH_TMA_SM120_ENABLED)
|
| 172 |
+
asm volatile (
|
| 173 |
+
"cp.async.bulk.tensor.3d.shared::cta.global.mbarrier::complete_tx::bytes.L2::cache_hint"
|
| 174 |
+
" [%0], [%1, {%3, %4, %5}], [%2], %6;"
|
| 175 |
+
:
|
| 176 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 177 |
+
"r"(crd0), "r"(crd1), "r"(crd2), "l"(cache_hint)
|
| 178 |
+
: "memory");
|
| 179 |
+
#else
|
| 180 |
+
asm volatile (
|
| 181 |
+
"cp.async.bulk.tensor.3d.shared::cluster.global.mbarrier::complete_tx::bytes.L2::cache_hint"
|
| 182 |
+
" [%0], [%1, {%3, %4, %5}], [%2], %6;"
|
| 183 |
+
:
|
| 184 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 185 |
+
"r"(crd0), "r"(crd1), "r"(crd2), "l"(cache_hint)
|
| 186 |
+
: "memory");
|
| 187 |
+
#endif
|
| 188 |
+
#else
|
| 189 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 190 |
+
#endif
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
struct PREFETCH
|
| 194 |
+
{
|
| 195 |
+
CUTE_HOST_DEVICE static void
|
| 196 |
+
copy(void const* desc_ptr,
|
| 197 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2)
|
| 198 |
+
{
|
| 199 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 200 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 201 |
+
asm volatile (
|
| 202 |
+
"cp.async.bulk.prefetch.tensor.3d.L2.global"
|
| 203 |
+
" [%0, {%1, %2, %3}];"
|
| 204 |
+
:
|
| 205 |
+
: "l"(gmem_int_desc),
|
| 206 |
+
"r"(crd0), "r"(crd1), "r"(crd2)
|
| 207 |
+
: "memory");
|
| 208 |
+
#else
|
| 209 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 210 |
+
#endif
|
| 211 |
+
}
|
| 212 |
+
};
|
| 213 |
+
};
|
| 214 |
+
|
| 215 |
+
struct SM90_TMA_LOAD_4D
|
| 216 |
+
{
|
| 217 |
+
CUTE_HOST_DEVICE static void
|
| 218 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint64_t cache_hint,
|
| 219 |
+
void * smem_ptr,
|
| 220 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3)
|
| 221 |
+
{
|
| 222 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 223 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 224 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr);
|
| 225 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 226 |
+
cutlass::arch::synclog_emit_tma_load(__LINE__, gmem_int_desc, smem_int_mbar, smem_int_ptr);
|
| 227 |
+
#if defined(CUTE_ARCH_TMA_SM120_ENABLED)
|
| 228 |
+
asm volatile (
|
| 229 |
+
"cp.async.bulk.tensor.4d.shared::cta.global.mbarrier::complete_tx::bytes.L2::cache_hint"
|
| 230 |
+
" [%0], [%1, {%3, %4, %5, %6}], [%2], %7;"
|
| 231 |
+
:
|
| 232 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 233 |
+
"r"(crd0), "r"(crd1), "r"(crd2), "r"(crd3), "l"(cache_hint)
|
| 234 |
+
: "memory");
|
| 235 |
+
#else
|
| 236 |
+
asm volatile (
|
| 237 |
+
"cp.async.bulk.tensor.4d.shared::cluster.global.mbarrier::complete_tx::bytes.L2::cache_hint"
|
| 238 |
+
" [%0], [%1, {%3, %4, %5, %6}], [%2], %7;"
|
| 239 |
+
:
|
| 240 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 241 |
+
"r"(crd0), "r"(crd1), "r"(crd2), "r"(crd3), "l"(cache_hint)
|
| 242 |
+
: "memory");
|
| 243 |
+
#endif
|
| 244 |
+
#else
|
| 245 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 246 |
+
#endif
|
| 247 |
+
}
|
| 248 |
+
|
| 249 |
+
struct PREFETCH
|
| 250 |
+
{
|
| 251 |
+
CUTE_HOST_DEVICE static void
|
| 252 |
+
copy(void const* desc_ptr,
|
| 253 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3)
|
| 254 |
+
{
|
| 255 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 256 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 257 |
+
asm volatile (
|
| 258 |
+
"cp.async.bulk.prefetch.tensor.4d.L2.global"
|
| 259 |
+
" [%0, {%1, %2, %3, %4}];"
|
| 260 |
+
:
|
| 261 |
+
: "l"(gmem_int_desc),
|
| 262 |
+
"r"(crd0), "r"(crd1), "r"(crd2), "r"(crd3)
|
| 263 |
+
: "memory");
|
| 264 |
+
#else
|
| 265 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 266 |
+
#endif
|
| 267 |
+
}
|
| 268 |
+
};
|
| 269 |
+
};
|
| 270 |
+
|
| 271 |
+
struct SM90_TMA_LOAD_5D
|
| 272 |
+
{
|
| 273 |
+
CUTE_HOST_DEVICE static void
|
| 274 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint64_t cache_hint,
|
| 275 |
+
void * smem_ptr,
|
| 276 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3, int32_t const& crd4)
|
| 277 |
+
{
|
| 278 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 279 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 280 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr);
|
| 281 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 282 |
+
cutlass::arch::synclog_emit_tma_load(__LINE__, gmem_int_desc, smem_int_mbar, smem_int_ptr);
|
| 283 |
+
#if defined(CUTE_ARCH_TMA_SM120_ENABLED)
|
| 284 |
+
asm volatile (
|
| 285 |
+
"cp.async.bulk.tensor.5d.shared::cta.global.mbarrier::complete_tx::bytes.L2::cache_hint"
|
| 286 |
+
" [%0], [%1, {%3, %4, %5, %6, %7}], [%2], %8;"
|
| 287 |
+
:
|
| 288 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 289 |
+
"r"(crd0), "r"(crd1), "r"(crd2), "r"(crd3), "r"(crd4), "l"(cache_hint)
|
| 290 |
+
: "memory");
|
| 291 |
+
#else
|
| 292 |
+
asm volatile (
|
| 293 |
+
"cp.async.bulk.tensor.5d.shared::cluster.global.mbarrier::complete_tx::bytes.L2::cache_hint"
|
| 294 |
+
" [%0], [%1, {%3, %4, %5, %6, %7}], [%2], %8;"
|
| 295 |
+
:
|
| 296 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 297 |
+
"r"(crd0), "r"(crd1), "r"(crd2), "r"(crd3), "r"(crd4), "l"(cache_hint)
|
| 298 |
+
: "memory");
|
| 299 |
+
#endif
|
| 300 |
+
#else
|
| 301 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 302 |
+
#endif
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
struct PREFETCH
|
| 306 |
+
{
|
| 307 |
+
CUTE_HOST_DEVICE static void
|
| 308 |
+
copy(void const* desc_ptr,
|
| 309 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3, int32_t const& crd4)
|
| 310 |
+
{
|
| 311 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 312 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 313 |
+
asm volatile (
|
| 314 |
+
"cp.async.bulk.prefetch.tensor.5d.L2.global"
|
| 315 |
+
" [%0, {%1, %2, %3, %4, %5}];"
|
| 316 |
+
:
|
| 317 |
+
: "l"(gmem_int_desc),
|
| 318 |
+
"r"(crd0), "r"(crd1), "r"(crd2), "r"(crd3), "r"(crd4)
|
| 319 |
+
: "memory");
|
| 320 |
+
#else
|
| 321 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 322 |
+
#endif
|
| 323 |
+
}
|
| 324 |
+
};
|
| 325 |
+
};
|
| 326 |
+
|
| 327 |
+
struct SM90_TMA_LOAD
|
| 328 |
+
{
|
| 329 |
+
CUTE_HOST_DEVICE static void
|
| 330 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint64_t cache_hint,
|
| 331 |
+
void * smem_ptr,
|
| 332 |
+
int32_t const& crd0)
|
| 333 |
+
{
|
| 334 |
+
return SM90_TMA_LOAD_1D::copy(desc_ptr, mbar_ptr, cache_hint, smem_ptr, crd0);
|
| 335 |
+
}
|
| 336 |
+
CUTE_HOST_DEVICE static void
|
| 337 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint64_t cache_hint,
|
| 338 |
+
void * smem_ptr,
|
| 339 |
+
int32_t const& crd0, int32_t const& crd1)
|
| 340 |
+
{
|
| 341 |
+
return SM90_TMA_LOAD_2D::copy(desc_ptr, mbar_ptr, cache_hint, smem_ptr, crd0, crd1);
|
| 342 |
+
}
|
| 343 |
+
CUTE_HOST_DEVICE static void
|
| 344 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint64_t cache_hint,
|
| 345 |
+
void * smem_ptr,
|
| 346 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2)
|
| 347 |
+
{
|
| 348 |
+
return SM90_TMA_LOAD_3D::copy(desc_ptr, mbar_ptr, cache_hint, smem_ptr, crd0, crd1, crd2);
|
| 349 |
+
}
|
| 350 |
+
CUTE_HOST_DEVICE static void
|
| 351 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint64_t cache_hint,
|
| 352 |
+
void * smem_ptr,
|
| 353 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3)
|
| 354 |
+
{
|
| 355 |
+
return SM90_TMA_LOAD_4D::copy(desc_ptr, mbar_ptr, cache_hint, smem_ptr, crd0, crd1, crd2, crd3);
|
| 356 |
+
}
|
| 357 |
+
CUTE_HOST_DEVICE static void
|
| 358 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint64_t cache_hint,
|
| 359 |
+
void * smem_ptr,
|
| 360 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3, int32_t const& crd4)
|
| 361 |
+
{
|
| 362 |
+
return SM90_TMA_LOAD_5D::copy(desc_ptr, mbar_ptr, cache_hint, smem_ptr, crd0, crd1, crd2, crd3, crd4);
|
| 363 |
+
}
|
| 364 |
+
|
| 365 |
+
struct PREFETCH
|
| 366 |
+
{
|
| 367 |
+
CUTE_HOST_DEVICE static void
|
| 368 |
+
copy(void const* desc_ptr,
|
| 369 |
+
int32_t const& crd0)
|
| 370 |
+
{
|
| 371 |
+
return SM90_TMA_LOAD_1D::PREFETCH::copy(desc_ptr, crd0);
|
| 372 |
+
}
|
| 373 |
+
CUTE_HOST_DEVICE static void
|
| 374 |
+
copy(void const* desc_ptr,
|
| 375 |
+
int32_t const& crd0, int32_t const& crd1)
|
| 376 |
+
{
|
| 377 |
+
return SM90_TMA_LOAD_2D::PREFETCH::copy(desc_ptr, crd0, crd1);
|
| 378 |
+
}
|
| 379 |
+
CUTE_HOST_DEVICE static void
|
| 380 |
+
copy(void const* desc_ptr,
|
| 381 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2)
|
| 382 |
+
{
|
| 383 |
+
return SM90_TMA_LOAD_3D::PREFETCH::copy(desc_ptr, crd0, crd1, crd2);
|
| 384 |
+
}
|
| 385 |
+
CUTE_HOST_DEVICE static void
|
| 386 |
+
copy(void const* desc_ptr,
|
| 387 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3)
|
| 388 |
+
{
|
| 389 |
+
return SM90_TMA_LOAD_4D::PREFETCH::copy(desc_ptr, crd0, crd1, crd2, crd3);
|
| 390 |
+
}
|
| 391 |
+
CUTE_HOST_DEVICE static void
|
| 392 |
+
copy(void const* desc_ptr,
|
| 393 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3, int32_t const& crd4)
|
| 394 |
+
{
|
| 395 |
+
return SM90_TMA_LOAD_5D::PREFETCH::copy(desc_ptr, crd0, crd1, crd2, crd3, crd4);
|
| 396 |
+
}
|
| 397 |
+
};
|
| 398 |
+
};
|
| 399 |
+
|
| 400 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 401 |
+
/// TMA_LOAD im2col: Initiates a TMA copy, in im2col mode, from global memory to shared memory
|
| 402 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 403 |
+
|
| 404 |
+
struct SM90_TMA_LOAD_IM2COL_3D
|
| 405 |
+
{
|
| 406 |
+
CUTE_HOST_DEVICE static void
|
| 407 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr,
|
| 408 |
+
void * smem_ptr,
|
| 409 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_n,
|
| 410 |
+
uint16_t const& offset_w)
|
| 411 |
+
{
|
| 412 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 413 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 414 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr);
|
| 415 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 416 |
+
cutlass::arch::synclog_emit_tma_load(__LINE__, gmem_int_desc, smem_int_mbar, smem_int_ptr);
|
| 417 |
+
// Copy from global to shared::cluster.
|
| 418 |
+
asm volatile (
|
| 419 |
+
"cp.async.bulk.tensor.3d.shared::cluster.global.im2col.mbarrier::complete_tx::bytes"
|
| 420 |
+
" [%0], [%1, {%3, %4, %5}], [%2], {%6};"
|
| 421 |
+
:
|
| 422 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 423 |
+
"r"(coord_c), "r"(coord_w), "r"(coord_n),
|
| 424 |
+
"h"(offset_w)
|
| 425 |
+
: "memory");
|
| 426 |
+
#else
|
| 427 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 428 |
+
#endif
|
| 429 |
+
}
|
| 430 |
+
|
| 431 |
+
struct PREFETCH
|
| 432 |
+
{
|
| 433 |
+
CUTE_HOST_DEVICE static void
|
| 434 |
+
copy(void const* desc_ptr,
|
| 435 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_n,
|
| 436 |
+
uint16_t const& offset_w)
|
| 437 |
+
{
|
| 438 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 439 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 440 |
+
asm volatile (
|
| 441 |
+
"cp.async.bulk.prefetch.tensor.3d.L2.global.im2col"
|
| 442 |
+
" [%0, {%1, %2, %3}], {%4};"
|
| 443 |
+
:
|
| 444 |
+
: "l"(gmem_int_desc),
|
| 445 |
+
"r"(coord_c), "r"(coord_w), "r"(coord_n),
|
| 446 |
+
"h"(offset_w)
|
| 447 |
+
: "memory");
|
| 448 |
+
#else
|
| 449 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 450 |
+
#endif
|
| 451 |
+
}
|
| 452 |
+
};
|
| 453 |
+
};
|
| 454 |
+
|
| 455 |
+
struct SM90_TMA_LOAD_IM2COL_4D
|
| 456 |
+
{
|
| 457 |
+
CUTE_HOST_DEVICE static void
|
| 458 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr,
|
| 459 |
+
void * smem_ptr,
|
| 460 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_n,
|
| 461 |
+
uint16_t const& offset_w, uint16_t const& offset_h)
|
| 462 |
+
{
|
| 463 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 464 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 465 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr);
|
| 466 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 467 |
+
cutlass::arch::synclog_emit_tma_load(__LINE__, gmem_int_desc, smem_int_mbar, smem_int_ptr);
|
| 468 |
+
// Copy from global to shared::cluster.
|
| 469 |
+
asm volatile (
|
| 470 |
+
"cp.async.bulk.tensor.4d.shared::cluster.global.im2col.mbarrier::complete_tx::bytes"
|
| 471 |
+
" [%0], [%1, {%3, %4, %5, %6}], [%2], {%7, %8};"
|
| 472 |
+
:
|
| 473 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 474 |
+
"r"(coord_c), "r"(coord_w), "r"(coord_h), "r"(coord_n),
|
| 475 |
+
"h"(offset_w), "h"(offset_h)
|
| 476 |
+
: "memory");
|
| 477 |
+
#else
|
| 478 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 479 |
+
#endif
|
| 480 |
+
}
|
| 481 |
+
|
| 482 |
+
struct PREFETCH
|
| 483 |
+
{
|
| 484 |
+
CUTE_HOST_DEVICE static void
|
| 485 |
+
copy(void const* desc_ptr,
|
| 486 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_n,
|
| 487 |
+
uint16_t const& offset_w, uint16_t const& offset_h)
|
| 488 |
+
{
|
| 489 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 490 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 491 |
+
asm volatile (
|
| 492 |
+
"cp.async.bulk.prefetch.tensor.4d.L2.global.im2col"
|
| 493 |
+
" [%0, {%1, %2, %3, %4}], {%5, %6};"
|
| 494 |
+
:
|
| 495 |
+
: "l"(gmem_int_desc),
|
| 496 |
+
"r"(coord_c), "r"(coord_w), "r"(coord_h), "r"(coord_n),
|
| 497 |
+
"h"(offset_w), "h"(offset_h)
|
| 498 |
+
: "memory");
|
| 499 |
+
#else
|
| 500 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 501 |
+
#endif
|
| 502 |
+
}
|
| 503 |
+
};
|
| 504 |
+
};
|
| 505 |
+
|
| 506 |
+
struct SM90_TMA_LOAD_IM2COL_5D
|
| 507 |
+
{
|
| 508 |
+
CUTE_HOST_DEVICE static void
|
| 509 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr,
|
| 510 |
+
void * smem_ptr,
|
| 511 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_d, int32_t const& coord_n,
|
| 512 |
+
uint16_t const& offset_w, uint16_t const& offset_h, uint16_t const& offset_d)
|
| 513 |
+
{
|
| 514 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 515 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 516 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr);
|
| 517 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 518 |
+
cutlass::arch::synclog_emit_tma_load(__LINE__, gmem_int_desc, smem_int_mbar, smem_int_ptr);
|
| 519 |
+
// Copy from global to shared::cluster.
|
| 520 |
+
asm volatile (
|
| 521 |
+
"cp.async.bulk.tensor.5d.shared::cluster.global.im2col.mbarrier::complete_tx::bytes"
|
| 522 |
+
" [%0], [%1, {%3, %4, %5, %6, %7}], [%2], {%8, %9, %10};"
|
| 523 |
+
:
|
| 524 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 525 |
+
"r"(coord_c), "r"(coord_w), "r"(coord_h), "r"(coord_d), "r"(coord_n),
|
| 526 |
+
"h"(offset_w), "h"(offset_h), "h"(offset_d)
|
| 527 |
+
: "memory");
|
| 528 |
+
#else
|
| 529 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 530 |
+
#endif
|
| 531 |
+
}
|
| 532 |
+
|
| 533 |
+
struct PREFETCH
|
| 534 |
+
{
|
| 535 |
+
CUTE_HOST_DEVICE static void
|
| 536 |
+
copy(void const* desc_ptr,
|
| 537 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_d, int32_t const& coord_n,
|
| 538 |
+
uint16_t const& offset_w, uint16_t const& offset_h, uint16_t const& offset_d)
|
| 539 |
+
{
|
| 540 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 541 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 542 |
+
asm volatile (
|
| 543 |
+
"cp.async.bulk.prefetch.tensor.5d.L2.global.im2col"
|
| 544 |
+
" [%0, {%1, %2, %3, %4, %5}], {%6, %7, %8};"
|
| 545 |
+
:
|
| 546 |
+
: "l"(gmem_int_desc),
|
| 547 |
+
"r"(coord_c), "r"(coord_w), "r"(coord_h), "r"(coord_d), "r"(coord_n),
|
| 548 |
+
"h"(offset_w), "h"(offset_h), "h"(offset_d)
|
| 549 |
+
: "memory");
|
| 550 |
+
#else
|
| 551 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 552 |
+
#endif
|
| 553 |
+
}
|
| 554 |
+
};
|
| 555 |
+
};
|
| 556 |
+
|
| 557 |
+
struct SM90_TMA_LOAD_IM2COL
|
| 558 |
+
{
|
| 559 |
+
CUTE_HOST_DEVICE static void
|
| 560 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr,
|
| 561 |
+
void * smem_ptr,
|
| 562 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_n,
|
| 563 |
+
uint16_t const& offset_w)
|
| 564 |
+
{
|
| 565 |
+
return SM90_TMA_LOAD_IM2COL_3D::copy(desc_ptr, mbar_ptr, smem_ptr,
|
| 566 |
+
coord_c, coord_w, coord_n,
|
| 567 |
+
offset_w);
|
| 568 |
+
}
|
| 569 |
+
CUTE_HOST_DEVICE static void
|
| 570 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr,
|
| 571 |
+
void * smem_ptr,
|
| 572 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_n,
|
| 573 |
+
uint16_t const& offset_w, uint16_t const& offset_h)
|
| 574 |
+
{
|
| 575 |
+
return SM90_TMA_LOAD_IM2COL_4D::copy(desc_ptr, mbar_ptr, smem_ptr,
|
| 576 |
+
coord_c, coord_w, coord_h, coord_n,
|
| 577 |
+
offset_w, offset_h);
|
| 578 |
+
}
|
| 579 |
+
CUTE_HOST_DEVICE static void
|
| 580 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr,
|
| 581 |
+
void * smem_ptr,
|
| 582 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_d, int32_t const& coord_n,
|
| 583 |
+
uint16_t const& offset_w, uint16_t const& offset_h, uint16_t const& offset_d)
|
| 584 |
+
{
|
| 585 |
+
return SM90_TMA_LOAD_IM2COL_5D::copy(desc_ptr, mbar_ptr, smem_ptr,
|
| 586 |
+
coord_c, coord_w, coord_h, coord_d, coord_n,
|
| 587 |
+
offset_w, offset_h, offset_d);
|
| 588 |
+
}
|
| 589 |
+
|
| 590 |
+
struct PREFETCH
|
| 591 |
+
{
|
| 592 |
+
CUTE_HOST_DEVICE static void
|
| 593 |
+
copy(void const* desc_ptr,
|
| 594 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_n,
|
| 595 |
+
uint16_t const& offset_w)
|
| 596 |
+
{
|
| 597 |
+
return SM90_TMA_LOAD_IM2COL_3D::PREFETCH::copy(desc_ptr,
|
| 598 |
+
coord_c, coord_w, coord_n,
|
| 599 |
+
offset_w);
|
| 600 |
+
}
|
| 601 |
+
CUTE_HOST_DEVICE static void
|
| 602 |
+
copy(void const* desc_ptr,
|
| 603 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_n,
|
| 604 |
+
uint16_t const& offset_w, uint16_t const& offset_h)
|
| 605 |
+
{
|
| 606 |
+
return SM90_TMA_LOAD_IM2COL_4D::PREFETCH::copy(desc_ptr,
|
| 607 |
+
coord_c, coord_w, coord_h, coord_n,
|
| 608 |
+
offset_w, offset_h);
|
| 609 |
+
}
|
| 610 |
+
CUTE_HOST_DEVICE static void
|
| 611 |
+
copy(void const* desc_ptr,
|
| 612 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_d, int32_t const& coord_n,
|
| 613 |
+
uint16_t const& offset_w, uint16_t const& offset_h, uint16_t const& offset_d)
|
| 614 |
+
{
|
| 615 |
+
return SM90_TMA_LOAD_IM2COL_5D::PREFETCH::copy(desc_ptr,
|
| 616 |
+
coord_c, coord_w, coord_h, coord_d, coord_n,
|
| 617 |
+
offset_w, offset_h, offset_d);
|
| 618 |
+
}
|
| 619 |
+
};
|
| 620 |
+
};
|
| 621 |
+
|
| 622 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 623 |
+
/// TMA_LOAD_MULTICAST: Initiates a TMA copy from global memory to shared memory
|
| 624 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 625 |
+
|
| 626 |
+
struct SM90_TMA_LOAD_MULTICAST_1D
|
| 627 |
+
{
|
| 628 |
+
CUTE_HOST_DEVICE static void
|
| 629 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask, uint64_t cache_hint,
|
| 630 |
+
void * smem_ptr,
|
| 631 |
+
int32_t const& crd0)
|
| 632 |
+
{
|
| 633 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 634 |
+
#if defined(CUTE_ARCH_TMA_SM120_ENABLED)
|
| 635 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 636 |
+
#endif
|
| 637 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 638 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr);
|
| 639 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 640 |
+
cutlass::arch::synclog_emit_tma_load(__LINE__, gmem_int_desc, smem_int_mbar, smem_int_ptr);
|
| 641 |
+
asm volatile (
|
| 642 |
+
"cp.async.bulk.tensor.1d.shared::cluster.global.mbarrier::complete_tx::bytes.multicast::cluster.L2::cache_hint"
|
| 643 |
+
" [%0], [%1, {%4}], [%2], %3, %5;"
|
| 644 |
+
:
|
| 645 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 646 |
+
"h"(multicast_mask),
|
| 647 |
+
"r"(crd0), "l"(cache_hint)
|
| 648 |
+
: "memory");
|
| 649 |
+
#else
|
| 650 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 651 |
+
#endif
|
| 652 |
+
}
|
| 653 |
+
};
|
| 654 |
+
|
| 655 |
+
struct SM90_TMA_LOAD_MULTICAST_2D
|
| 656 |
+
{
|
| 657 |
+
CUTE_HOST_DEVICE static void
|
| 658 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask, uint64_t cache_hint,
|
| 659 |
+
void * smem_ptr,
|
| 660 |
+
int32_t const& crd0, int32_t const& crd1)
|
| 661 |
+
{
|
| 662 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 663 |
+
#if defined(CUTE_ARCH_TMA_SM120_ENABLED)
|
| 664 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 665 |
+
#endif
|
| 666 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 667 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr);
|
| 668 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 669 |
+
cutlass::arch::synclog_emit_tma_load(__LINE__, gmem_int_desc, smem_int_mbar, smem_int_ptr);
|
| 670 |
+
asm volatile (
|
| 671 |
+
"cp.async.bulk.tensor.2d.shared::cluster.global.mbarrier::complete_tx::bytes.multicast::cluster.L2::cache_hint"
|
| 672 |
+
" [%0], [%1, {%4, %5}], [%2], %3, %6;"
|
| 673 |
+
:
|
| 674 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 675 |
+
"h"(multicast_mask),
|
| 676 |
+
"r"(crd0), "r"(crd1), "l"(cache_hint)
|
| 677 |
+
: "memory");
|
| 678 |
+
#else
|
| 679 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 680 |
+
#endif
|
| 681 |
+
}
|
| 682 |
+
};
|
| 683 |
+
|
| 684 |
+
struct SM90_TMA_LOAD_MULTICAST_3D
|
| 685 |
+
{
|
| 686 |
+
CUTE_HOST_DEVICE static void
|
| 687 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask, uint64_t cache_hint,
|
| 688 |
+
void * smem_ptr,
|
| 689 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2)
|
| 690 |
+
{
|
| 691 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 692 |
+
#if defined(CUTE_ARCH_TMA_SM120_ENABLED)
|
| 693 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 694 |
+
#endif
|
| 695 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 696 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr);
|
| 697 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 698 |
+
cutlass::arch::synclog_emit_tma_load(__LINE__, gmem_int_desc, smem_int_mbar, smem_int_ptr);
|
| 699 |
+
asm volatile (
|
| 700 |
+
"cp.async.bulk.tensor.3d.shared::cluster.global.mbarrier::complete_tx::bytes.multicast::cluster.L2::cache_hint"
|
| 701 |
+
" [%0], [%1, {%4, %5, %6}], [%2], %3, %7;"
|
| 702 |
+
:
|
| 703 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 704 |
+
"h"(multicast_mask),
|
| 705 |
+
"r"(crd0), "r"(crd1), "r"(crd2), "l"(cache_hint)
|
| 706 |
+
: "memory");
|
| 707 |
+
#else
|
| 708 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 709 |
+
#endif
|
| 710 |
+
}
|
| 711 |
+
};
|
| 712 |
+
|
| 713 |
+
struct SM90_TMA_LOAD_MULTICAST_4D
|
| 714 |
+
{
|
| 715 |
+
CUTE_HOST_DEVICE static void
|
| 716 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask, uint64_t cache_hint,
|
| 717 |
+
void * smem_ptr,
|
| 718 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3)
|
| 719 |
+
{
|
| 720 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 721 |
+
#if defined(CUTE_ARCH_TMA_SM120_ENABLED)
|
| 722 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 723 |
+
#endif
|
| 724 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 725 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr);
|
| 726 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 727 |
+
cutlass::arch::synclog_emit_tma_load(__LINE__, gmem_int_desc, smem_int_mbar, smem_int_ptr);
|
| 728 |
+
asm volatile (
|
| 729 |
+
"cp.async.bulk.tensor.4d.shared::cluster.global.mbarrier::complete_tx::bytes.multicast::cluster.L2::cache_hint"
|
| 730 |
+
" [%0], [%1, {%4, %5, %6, %7}], [%2], %3, %8;"
|
| 731 |
+
:
|
| 732 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 733 |
+
"h"(multicast_mask),
|
| 734 |
+
"r"(crd0), "r"(crd1), "r"(crd2), "r"(crd3), "l"(cache_hint)
|
| 735 |
+
: "memory");
|
| 736 |
+
#else
|
| 737 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 738 |
+
#endif
|
| 739 |
+
}
|
| 740 |
+
};
|
| 741 |
+
|
| 742 |
+
struct SM90_TMA_LOAD_MULTICAST_5D
|
| 743 |
+
{
|
| 744 |
+
CUTE_HOST_DEVICE static void
|
| 745 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask, uint64_t cache_hint,
|
| 746 |
+
void * smem_ptr,
|
| 747 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3, int32_t const& crd4)
|
| 748 |
+
{
|
| 749 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 750 |
+
#if defined(CUTE_ARCH_TMA_SM120_ENABLED)
|
| 751 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 752 |
+
#endif
|
| 753 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 754 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr);
|
| 755 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 756 |
+
cutlass::arch::synclog_emit_tma_load(__LINE__, gmem_int_desc, smem_int_mbar, smem_int_ptr);
|
| 757 |
+
asm volatile (
|
| 758 |
+
"cp.async.bulk.tensor.5d.shared::cluster.global.mbarrier::complete_tx::bytes.multicast::cluster.L2::cache_hint"
|
| 759 |
+
" [%0], [%1, {%4, %5, %6, %7, %8}], [%2], %3, %9;"
|
| 760 |
+
:
|
| 761 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 762 |
+
"h"(multicast_mask),
|
| 763 |
+
"r"(crd0), "r"(crd1), "r"(crd2), "r"(crd3), "r"(crd4), "l"(cache_hint)
|
| 764 |
+
: "memory");
|
| 765 |
+
#else
|
| 766 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 767 |
+
#endif
|
| 768 |
+
}
|
| 769 |
+
};
|
| 770 |
+
|
| 771 |
+
struct SM90_TMA_LOAD_MULTICAST
|
| 772 |
+
{
|
| 773 |
+
CUTE_HOST_DEVICE static void
|
| 774 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask, uint64_t cache_hint,
|
| 775 |
+
void * smem_ptr,
|
| 776 |
+
int32_t const& crd0)
|
| 777 |
+
{
|
| 778 |
+
return SM90_TMA_LOAD_MULTICAST_1D::copy(desc_ptr, mbar_ptr, multicast_mask, cache_hint, smem_ptr, crd0);
|
| 779 |
+
}
|
| 780 |
+
CUTE_HOST_DEVICE static void
|
| 781 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask, uint64_t cache_hint,
|
| 782 |
+
void * smem_ptr,
|
| 783 |
+
int32_t const& crd0, int32_t const& crd1)
|
| 784 |
+
{
|
| 785 |
+
return SM90_TMA_LOAD_MULTICAST_2D::copy(desc_ptr, mbar_ptr, multicast_mask, cache_hint, smem_ptr, crd0, crd1);
|
| 786 |
+
}
|
| 787 |
+
CUTE_HOST_DEVICE static void
|
| 788 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask, uint64_t cache_hint,
|
| 789 |
+
void * smem_ptr,
|
| 790 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2)
|
| 791 |
+
{
|
| 792 |
+
return SM90_TMA_LOAD_MULTICAST_3D::copy(desc_ptr, mbar_ptr, multicast_mask, cache_hint, smem_ptr, crd0, crd1, crd2);
|
| 793 |
+
}
|
| 794 |
+
CUTE_HOST_DEVICE static void
|
| 795 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask, uint64_t cache_hint,
|
| 796 |
+
void * smem_ptr,
|
| 797 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3)
|
| 798 |
+
{
|
| 799 |
+
return SM90_TMA_LOAD_MULTICAST_4D::copy(desc_ptr, mbar_ptr, multicast_mask, cache_hint, smem_ptr, crd0, crd1, crd2, crd3);
|
| 800 |
+
}
|
| 801 |
+
CUTE_HOST_DEVICE static void
|
| 802 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask, uint64_t cache_hint,
|
| 803 |
+
void * smem_ptr,
|
| 804 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3, int32_t const& crd4)
|
| 805 |
+
{
|
| 806 |
+
return SM90_TMA_LOAD_MULTICAST_5D::copy(desc_ptr, mbar_ptr, multicast_mask, cache_hint, smem_ptr, crd0, crd1, crd2, crd3, crd4);
|
| 807 |
+
}
|
| 808 |
+
|
| 809 |
+
using PREFETCH = typename SM90_TMA_LOAD::PREFETCH;
|
| 810 |
+
};
|
| 811 |
+
|
| 812 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 813 |
+
/// TMA_LOAD_MULTICAST im2col: Initiates a TMA copy, in im2col mode, from global memory to shared memory
|
| 814 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 815 |
+
|
| 816 |
+
struct SM90_TMA_LOAD_IM2COL_MULTICAST_3D
|
| 817 |
+
{
|
| 818 |
+
CUTE_HOST_DEVICE static void
|
| 819 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask,
|
| 820 |
+
void * smem_ptr,
|
| 821 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_n,
|
| 822 |
+
uint16_t const& offset_w)
|
| 823 |
+
{
|
| 824 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 825 |
+
#if defined(CUTE_ARCH_TMA_SM120_ENABLED)
|
| 826 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 827 |
+
#endif
|
| 828 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 829 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr);
|
| 830 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 831 |
+
cutlass::arch::synclog_emit_tma_load(__LINE__, gmem_int_desc, smem_int_mbar, smem_int_ptr);
|
| 832 |
+
// Copy from global to shared::cluster.
|
| 833 |
+
asm volatile (
|
| 834 |
+
"cp.async.bulk.tensor.3d.shared::cluster.global.im2col.mbarrier::complete_tx::bytes.multicast::cluster"
|
| 835 |
+
" [%0], [%1, {%3, %4, %5}], [%2], {%6}, %7;"
|
| 836 |
+
:
|
| 837 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 838 |
+
"r"(coord_c), "r"(coord_w), "r"(coord_n),
|
| 839 |
+
"h"(offset_w),
|
| 840 |
+
"h"(multicast_mask)
|
| 841 |
+
: "memory");
|
| 842 |
+
#else
|
| 843 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 844 |
+
#endif
|
| 845 |
+
}
|
| 846 |
+
};
|
| 847 |
+
|
| 848 |
+
struct SM90_TMA_LOAD_IM2COL_MULTICAST_4D
|
| 849 |
+
{
|
| 850 |
+
CUTE_HOST_DEVICE static void
|
| 851 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask,
|
| 852 |
+
void * smem_ptr,
|
| 853 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_n,
|
| 854 |
+
uint16_t const& offset_w, uint16_t const& offset_h)
|
| 855 |
+
{
|
| 856 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 857 |
+
#if defined(CUTE_ARCH_TMA_SM120_ENABLED)
|
| 858 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 859 |
+
#endif
|
| 860 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 861 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr);
|
| 862 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 863 |
+
cutlass::arch::synclog_emit_tma_load(__LINE__, gmem_int_desc, smem_int_mbar, smem_int_ptr);
|
| 864 |
+
// Copy from global to shared::cluster.
|
| 865 |
+
asm volatile (
|
| 866 |
+
"cp.async.bulk.tensor.4d.shared::cluster.global.im2col.mbarrier::complete_tx::bytes.multicast::cluster"
|
| 867 |
+
" [%0], [%1, {%3, %4, %5, %6}], [%2], {%7, %8}, %9;"
|
| 868 |
+
:
|
| 869 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 870 |
+
"r"(coord_c), "r"(coord_w), "r"(coord_h), "r"(coord_n),
|
| 871 |
+
"h"(offset_w), "h"(offset_h),
|
| 872 |
+
"h"(multicast_mask)
|
| 873 |
+
: "memory");
|
| 874 |
+
#else
|
| 875 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 876 |
+
#endif
|
| 877 |
+
}
|
| 878 |
+
};
|
| 879 |
+
|
| 880 |
+
struct SM90_TMA_LOAD_IM2COL_MULTICAST_5D
|
| 881 |
+
{
|
| 882 |
+
CUTE_HOST_DEVICE static void
|
| 883 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask,
|
| 884 |
+
void * smem_ptr,
|
| 885 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_d, int32_t const& coord_n,
|
| 886 |
+
uint16_t const& offset_w, uint16_t const& offset_h, uint16_t const& offset_d)
|
| 887 |
+
{
|
| 888 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 889 |
+
#if defined(CUTE_ARCH_TMA_SM120_ENABLED)
|
| 890 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 891 |
+
#endif
|
| 892 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 893 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr);
|
| 894 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 895 |
+
cutlass::arch::synclog_emit_tma_load(__LINE__, gmem_int_desc, smem_int_mbar, smem_int_ptr);
|
| 896 |
+
// Copy from global to shared::cluster.
|
| 897 |
+
asm volatile (
|
| 898 |
+
"cp.async.bulk.tensor.5d.shared::cluster.global.im2col.mbarrier::complete_tx::bytes.multicast::cluster"
|
| 899 |
+
" [%0], [%1, {%3, %4, %5, %6, %7}], [%2], {%8, %9, %10}, %11;"
|
| 900 |
+
:
|
| 901 |
+
: "r"(smem_int_ptr), "l"(gmem_int_desc), "r"(smem_int_mbar),
|
| 902 |
+
"r"(coord_c), "r"(coord_w), "r"(coord_h), "r"(coord_d), "r"(coord_n),
|
| 903 |
+
"h"(offset_w), "h"(offset_h), "h"(offset_d),
|
| 904 |
+
"h"(multicast_mask)
|
| 905 |
+
: "memory");
|
| 906 |
+
#else
|
| 907 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 908 |
+
#endif
|
| 909 |
+
}
|
| 910 |
+
};
|
| 911 |
+
|
| 912 |
+
struct SM90_TMA_LOAD_IM2COL_MULTICAST
|
| 913 |
+
{
|
| 914 |
+
CUTE_HOST_DEVICE static void
|
| 915 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask,
|
| 916 |
+
void * smem_ptr,
|
| 917 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_n,
|
| 918 |
+
uint16_t const& offset_w)
|
| 919 |
+
{
|
| 920 |
+
return SM90_TMA_LOAD_IM2COL_MULTICAST_3D::copy(desc_ptr, mbar_ptr, multicast_mask,
|
| 921 |
+
smem_ptr,
|
| 922 |
+
coord_c, coord_w, coord_n,
|
| 923 |
+
offset_w);
|
| 924 |
+
}
|
| 925 |
+
|
| 926 |
+
CUTE_HOST_DEVICE static void
|
| 927 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask,
|
| 928 |
+
void * smem_ptr,
|
| 929 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_n,
|
| 930 |
+
uint16_t const& offset_w, uint16_t const& offset_h)
|
| 931 |
+
{
|
| 932 |
+
return SM90_TMA_LOAD_IM2COL_MULTICAST_4D::copy(desc_ptr, mbar_ptr, multicast_mask,
|
| 933 |
+
smem_ptr,
|
| 934 |
+
coord_c, coord_w, coord_h, coord_n,
|
| 935 |
+
offset_w, offset_h);
|
| 936 |
+
}
|
| 937 |
+
|
| 938 |
+
CUTE_HOST_DEVICE static void
|
| 939 |
+
copy(void const* desc_ptr, uint64_t* mbar_ptr, uint16_t multicast_mask,
|
| 940 |
+
void * smem_ptr,
|
| 941 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_d, int32_t const& coord_n,
|
| 942 |
+
uint16_t const& offset_w, uint16_t const& offset_h, uint16_t const& offset_d)
|
| 943 |
+
{
|
| 944 |
+
return SM90_TMA_LOAD_IM2COL_MULTICAST_5D::copy(desc_ptr, mbar_ptr, multicast_mask,
|
| 945 |
+
smem_ptr,
|
| 946 |
+
coord_c, coord_w, coord_h, coord_d, coord_n,
|
| 947 |
+
offset_w, offset_h, offset_d);
|
| 948 |
+
}
|
| 949 |
+
|
| 950 |
+
using PREFETCH = typename SM90_TMA_LOAD_IM2COL::PREFETCH;
|
| 951 |
+
};
|
| 952 |
+
|
| 953 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 954 |
+
/// TMA_STORE : Initiates a TMA copy from shared memory to global memory
|
| 955 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 956 |
+
|
| 957 |
+
struct SM90_TMA_STORE_1D
|
| 958 |
+
{
|
| 959 |
+
CUTE_HOST_DEVICE static void
|
| 960 |
+
copy(void const* desc_ptr,
|
| 961 |
+
void const* smem_ptr,
|
| 962 |
+
int32_t const& crd0)
|
| 963 |
+
{
|
| 964 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 965 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 966 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 967 |
+
cutlass::arch::synclog_emit_tma_store(__LINE__, gmem_int_desc, smem_int_ptr);
|
| 968 |
+
asm volatile (
|
| 969 |
+
"cp.async.bulk.tensor.1d.global.shared::cta.bulk_group [%0, {%2}], [%1];"
|
| 970 |
+
:
|
| 971 |
+
: "l"(gmem_int_desc), "r"(smem_int_ptr),
|
| 972 |
+
"r"(crd0)
|
| 973 |
+
: "memory");
|
| 974 |
+
#else
|
| 975 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 976 |
+
#endif
|
| 977 |
+
}
|
| 978 |
+
};
|
| 979 |
+
|
| 980 |
+
struct SM90_TMA_STORE_2D
|
| 981 |
+
{
|
| 982 |
+
CUTE_HOST_DEVICE static void
|
| 983 |
+
copy(void const* desc_ptr,
|
| 984 |
+
void const* smem_ptr,
|
| 985 |
+
int32_t const& crd0, int32_t const& crd1)
|
| 986 |
+
{
|
| 987 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 988 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 989 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 990 |
+
cutlass::arch::synclog_emit_tma_store(__LINE__, gmem_int_desc, smem_int_ptr);
|
| 991 |
+
asm volatile (
|
| 992 |
+
"cp.async.bulk.tensor.2d.global.shared::cta.bulk_group [%0, {%2, %3}], [%1];"
|
| 993 |
+
:
|
| 994 |
+
: "l"(gmem_int_desc), "r"(smem_int_ptr),
|
| 995 |
+
"r"(crd0), "r"(crd1)
|
| 996 |
+
: "memory");
|
| 997 |
+
#else
|
| 998 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 999 |
+
#endif
|
| 1000 |
+
}
|
| 1001 |
+
};
|
| 1002 |
+
|
| 1003 |
+
struct SM90_TMA_STORE_3D
|
| 1004 |
+
{
|
| 1005 |
+
CUTE_HOST_DEVICE static void
|
| 1006 |
+
copy(void const* desc_ptr,
|
| 1007 |
+
void const* smem_ptr,
|
| 1008 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2)
|
| 1009 |
+
{
|
| 1010 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 1011 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 1012 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 1013 |
+
cutlass::arch::synclog_emit_tma_store(__LINE__, gmem_int_desc, smem_int_ptr);
|
| 1014 |
+
asm volatile (
|
| 1015 |
+
"cp.async.bulk.tensor.3d.global.shared::cta.bulk_group [%0, {%2, %3, %4}], [%1];"
|
| 1016 |
+
:
|
| 1017 |
+
: "l"(gmem_int_desc), "r"(smem_int_ptr),
|
| 1018 |
+
"r"(crd0), "r"(crd1), "r"(crd2)
|
| 1019 |
+
: "memory");
|
| 1020 |
+
#else
|
| 1021 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 1022 |
+
#endif
|
| 1023 |
+
}
|
| 1024 |
+
};
|
| 1025 |
+
|
| 1026 |
+
struct SM90_TMA_STORE_4D
|
| 1027 |
+
{
|
| 1028 |
+
CUTE_HOST_DEVICE static void
|
| 1029 |
+
copy(void const* desc_ptr,
|
| 1030 |
+
void const* smem_ptr,
|
| 1031 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3)
|
| 1032 |
+
{
|
| 1033 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 1034 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 1035 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 1036 |
+
cutlass::arch::synclog_emit_tma_store(__LINE__, gmem_int_desc, smem_int_ptr);
|
| 1037 |
+
asm volatile (
|
| 1038 |
+
"cp.async.bulk.tensor.4d.global.shared::cta.bulk_group [%0, {%2, %3, %4, %5}], [%1];"
|
| 1039 |
+
:
|
| 1040 |
+
: "l"(gmem_int_desc), "r"(smem_int_ptr),
|
| 1041 |
+
"r"(crd0), "r"(crd1), "r"(crd2), "r"(crd3)
|
| 1042 |
+
: "memory");
|
| 1043 |
+
#else
|
| 1044 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 1045 |
+
#endif
|
| 1046 |
+
}
|
| 1047 |
+
};
|
| 1048 |
+
|
| 1049 |
+
struct SM90_TMA_STORE_5D
|
| 1050 |
+
{
|
| 1051 |
+
CUTE_HOST_DEVICE static void
|
| 1052 |
+
copy(void const* desc_ptr,
|
| 1053 |
+
void const* smem_ptr,
|
| 1054 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3, int32_t const& crd4)
|
| 1055 |
+
{
|
| 1056 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 1057 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 1058 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 1059 |
+
cutlass::arch::synclog_emit_tma_store(__LINE__, gmem_int_desc, smem_int_ptr);
|
| 1060 |
+
asm volatile (
|
| 1061 |
+
"cp.async.bulk.tensor.5d.global.shared::cta.bulk_group [%0, {%2, %3, %4, %5, %6}], [%1];"
|
| 1062 |
+
:
|
| 1063 |
+
: "l"(gmem_int_desc), "r"(smem_int_ptr),
|
| 1064 |
+
"r"(crd0), "r"(crd1), "r"(crd2), "r"(crd3), "r"(crd4)
|
| 1065 |
+
: "memory");
|
| 1066 |
+
#else
|
| 1067 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 1068 |
+
#endif
|
| 1069 |
+
}
|
| 1070 |
+
};
|
| 1071 |
+
|
| 1072 |
+
struct SM90_TMA_STORE
|
| 1073 |
+
{
|
| 1074 |
+
CUTE_HOST_DEVICE static void
|
| 1075 |
+
copy(void const* desc_ptr,
|
| 1076 |
+
void const* smem_ptr,
|
| 1077 |
+
int32_t const& crd0)
|
| 1078 |
+
{
|
| 1079 |
+
return SM90_TMA_STORE_1D::copy(desc_ptr, smem_ptr, crd0);
|
| 1080 |
+
}
|
| 1081 |
+
CUTE_HOST_DEVICE static void
|
| 1082 |
+
copy(void const* desc_ptr,
|
| 1083 |
+
void const* smem_ptr,
|
| 1084 |
+
int32_t const& crd0, int32_t const& crd1)
|
| 1085 |
+
{
|
| 1086 |
+
return SM90_TMA_STORE_2D::copy(desc_ptr, smem_ptr, crd0, crd1);
|
| 1087 |
+
}
|
| 1088 |
+
CUTE_HOST_DEVICE static void
|
| 1089 |
+
copy(void const* desc_ptr,
|
| 1090 |
+
void const* smem_ptr,
|
| 1091 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2)
|
| 1092 |
+
{
|
| 1093 |
+
return SM90_TMA_STORE_3D::copy(desc_ptr, smem_ptr, crd0, crd1, crd2);
|
| 1094 |
+
}
|
| 1095 |
+
CUTE_HOST_DEVICE static void
|
| 1096 |
+
copy(void const* desc_ptr,
|
| 1097 |
+
void const* smem_ptr,
|
| 1098 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3)
|
| 1099 |
+
{
|
| 1100 |
+
return SM90_TMA_STORE_4D::copy(desc_ptr, smem_ptr, crd0, crd1, crd2, crd3);
|
| 1101 |
+
}
|
| 1102 |
+
CUTE_HOST_DEVICE static void
|
| 1103 |
+
copy(void const* desc_ptr,
|
| 1104 |
+
void const* smem_ptr,
|
| 1105 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3, int32_t const& crd4)
|
| 1106 |
+
{
|
| 1107 |
+
return SM90_TMA_STORE_5D::copy(desc_ptr, smem_ptr, crd0, crd1, crd2, crd3, crd4);
|
| 1108 |
+
}
|
| 1109 |
+
};
|
| 1110 |
+
|
| 1111 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1112 |
+
/// TMA_STORE im2col: Initiates a TMA copy, in im2col mode, from shared memory to global memory
|
| 1113 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1114 |
+
|
| 1115 |
+
struct SM90_TMA_STORE_IM2COL_3D
|
| 1116 |
+
{
|
| 1117 |
+
CUTE_HOST_DEVICE static void
|
| 1118 |
+
copy(void const* desc_ptr,
|
| 1119 |
+
void const* smem_ptr,
|
| 1120 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_n)
|
| 1121 |
+
{
|
| 1122 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 1123 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 1124 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 1125 |
+
cutlass::arch::synclog_emit_tma_store(__LINE__, gmem_int_desc, smem_int_ptr);
|
| 1126 |
+
asm volatile (
|
| 1127 |
+
"cp.async.bulk.tensor.3d.global.shared::cta.im2col_no_offs.bulk_group"
|
| 1128 |
+
" [%0, {%2, %3, %4}], [%1];"
|
| 1129 |
+
:
|
| 1130 |
+
: "l"(gmem_int_desc), "r"(smem_int_ptr),
|
| 1131 |
+
"r"(coord_c), "r"(coord_w), "r"(coord_n)
|
| 1132 |
+
: "memory");
|
| 1133 |
+
#else
|
| 1134 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 1135 |
+
#endif
|
| 1136 |
+
}
|
| 1137 |
+
};
|
| 1138 |
+
|
| 1139 |
+
struct SM90_TMA_STORE_IM2COL_4D
|
| 1140 |
+
{
|
| 1141 |
+
CUTE_HOST_DEVICE static void
|
| 1142 |
+
copy(void const* desc_ptr,
|
| 1143 |
+
void const* smem_ptr,
|
| 1144 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_n)
|
| 1145 |
+
{
|
| 1146 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 1147 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 1148 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 1149 |
+
cutlass::arch::synclog_emit_tma_store(__LINE__, gmem_int_desc, smem_int_ptr);
|
| 1150 |
+
asm volatile (
|
| 1151 |
+
"cp.async.bulk.tensor.4d.global.shared::cta.im2col_no_offs.bulk_group"
|
| 1152 |
+
" [%0, {%2, %3, %4, %5}], [%1];"
|
| 1153 |
+
:
|
| 1154 |
+
: "l"(gmem_int_desc), "r"(smem_int_ptr),
|
| 1155 |
+
"r"(coord_c), "r"(coord_w), "r"(coord_h), "r"(coord_n)
|
| 1156 |
+
: "memory");
|
| 1157 |
+
#else
|
| 1158 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 1159 |
+
#endif
|
| 1160 |
+
}
|
| 1161 |
+
};
|
| 1162 |
+
|
| 1163 |
+
struct SM90_TMA_STORE_IM2COL_5D
|
| 1164 |
+
{
|
| 1165 |
+
CUTE_HOST_DEVICE static void
|
| 1166 |
+
copy(void const* desc_ptr,
|
| 1167 |
+
void const* smem_ptr,
|
| 1168 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_d, int32_t const& coord_n)
|
| 1169 |
+
{
|
| 1170 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 1171 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 1172 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 1173 |
+
cutlass::arch::synclog_emit_tma_store(__LINE__, gmem_int_desc, smem_int_ptr);
|
| 1174 |
+
asm volatile (
|
| 1175 |
+
"cp.async.bulk.tensor.5d.global.shared::cta.im2col_no_offs.bulk_group"
|
| 1176 |
+
" [%0, {%2, %3, %4, %5, %6}], [%1];"
|
| 1177 |
+
:
|
| 1178 |
+
: "l"(gmem_int_desc), "r"(smem_int_ptr),
|
| 1179 |
+
"r"(coord_c), "r"(coord_w), "r"(coord_h), "r"(coord_d), "r"(coord_n)
|
| 1180 |
+
: "memory");
|
| 1181 |
+
#else
|
| 1182 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 1183 |
+
#endif
|
| 1184 |
+
}
|
| 1185 |
+
};
|
| 1186 |
+
|
| 1187 |
+
struct SM90_TMA_STORE_IM2COL
|
| 1188 |
+
{
|
| 1189 |
+
CUTE_HOST_DEVICE static void
|
| 1190 |
+
copy(void const* desc_ptr,
|
| 1191 |
+
void const* smem_ptr,
|
| 1192 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_n)
|
| 1193 |
+
{
|
| 1194 |
+
return SM90_TMA_STORE_IM2COL_3D::copy(desc_ptr, smem_ptr, coord_c, coord_w, coord_n);
|
| 1195 |
+
}
|
| 1196 |
+
CUTE_HOST_DEVICE static void
|
| 1197 |
+
copy(void const* desc_ptr,
|
| 1198 |
+
void const* smem_ptr,
|
| 1199 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_n)
|
| 1200 |
+
{
|
| 1201 |
+
return SM90_TMA_STORE_IM2COL_4D::copy(desc_ptr, smem_ptr, coord_c, coord_w, coord_h, coord_n);
|
| 1202 |
+
}
|
| 1203 |
+
CUTE_HOST_DEVICE static void
|
| 1204 |
+
copy(void const* desc_ptr,
|
| 1205 |
+
void const* smem_ptr,
|
| 1206 |
+
int32_t const& coord_c, int32_t const& coord_w, int32_t const& coord_h, int32_t const& coord_d, int32_t const& coord_n)
|
| 1207 |
+
{
|
| 1208 |
+
return SM90_TMA_STORE_IM2COL_5D::copy(desc_ptr, smem_ptr, coord_c, coord_w, coord_h, coord_d, coord_n);
|
| 1209 |
+
}
|
| 1210 |
+
};
|
| 1211 |
+
|
| 1212 |
+
// Fence for smem stores for subsequent TMA_STORE
|
| 1213 |
+
CUTE_HOST_DEVICE static void
|
| 1214 |
+
tma_store_fence() {
|
| 1215 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 1216 |
+
cutlass::arch::synclog_emit_fence_view_async_shared(__LINE__);
|
| 1217 |
+
asm volatile ("fence.proxy.async.shared::cta;");
|
| 1218 |
+
#elif defined(__CUDA_ARCH__)
|
| 1219 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 1220 |
+
#endif
|
| 1221 |
+
}
|
| 1222 |
+
|
| 1223 |
+
// Indicate arrival of warp issuing TMA_STORE
|
| 1224 |
+
CUTE_HOST_DEVICE static void
|
| 1225 |
+
tma_store_arrive() {
|
| 1226 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 1227 |
+
cutlass::arch::synclog_emit_tma_store_arrive(__LINE__);
|
| 1228 |
+
asm volatile("cp.async.bulk.commit_group;");
|
| 1229 |
+
#else
|
| 1230 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 1231 |
+
#endif
|
| 1232 |
+
}
|
| 1233 |
+
|
| 1234 |
+
|
| 1235 |
+
CUTE_HOST_DEVICE static void
|
| 1236 |
+
tma_desc_commit_group() {
|
| 1237 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 1238 |
+
asm volatile("cp.async.bulk.commit_group;");
|
| 1239 |
+
#else
|
| 1240 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 1241 |
+
#endif
|
| 1242 |
+
}
|
| 1243 |
+
|
| 1244 |
+
|
| 1245 |
+
// Wait until at most Count committed TMA_STOREs are pending and all prior commits are complete
|
| 1246 |
+
template <int Count>
|
| 1247 |
+
CUTE_HOST_DEVICE static void
|
| 1248 |
+
tma_store_wait() {
|
| 1249 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 1250 |
+
asm volatile(
|
| 1251 |
+
"cp.async.bulk.wait_group.read %0;"
|
| 1252 |
+
:
|
| 1253 |
+
: "n"(Count)
|
| 1254 |
+
: "memory");
|
| 1255 |
+
cutlass::arch::synclog_emit_tma_store_wait(__LINE__, Count);
|
| 1256 |
+
#else
|
| 1257 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 1258 |
+
#endif
|
| 1259 |
+
}
|
| 1260 |
+
|
| 1261 |
+
|
| 1262 |
+
// Wait until all TMA descriptor previously issued are safe to be modified after tma_desc_commit_group()
|
| 1263 |
+
CUTE_HOST_DEVICE static void
|
| 1264 |
+
tma_desc_wait_group() {
|
| 1265 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 1266 |
+
asm volatile(
|
| 1267 |
+
"cp.async.bulk.wait_group.read %0;"
|
| 1268 |
+
:
|
| 1269 |
+
: "n"(0)
|
| 1270 |
+
: "memory");
|
| 1271 |
+
#else
|
| 1272 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 1273 |
+
#endif
|
| 1274 |
+
}
|
| 1275 |
+
|
| 1276 |
+
|
| 1277 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1278 |
+
/// TMA_REDUCE_ADD : Initiates a TMA reduce-add from shared memory to global memory
|
| 1279 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1280 |
+
|
| 1281 |
+
struct SM90_TMA_REDUCE_ADD_1D
|
| 1282 |
+
{
|
| 1283 |
+
CUTE_HOST_DEVICE static void
|
| 1284 |
+
copy(void const* const desc_ptr,
|
| 1285 |
+
void const* const smem_ptr,
|
| 1286 |
+
int32_t const& crd0)
|
| 1287 |
+
{
|
| 1288 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 1289 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 1290 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 1291 |
+
cutlass::arch::synclog_emit_tma_store(__LINE__, gmem_int_desc, smem_int_ptr);
|
| 1292 |
+
asm volatile (
|
| 1293 |
+
"cp.reduce.async.bulk.tensor.1d.global.shared::cta.add.bulk_group [%0, {%2}], [%1];"
|
| 1294 |
+
:
|
| 1295 |
+
: "l"(gmem_int_desc), "r"(smem_int_ptr),
|
| 1296 |
+
"r"(crd0)
|
| 1297 |
+
: "memory");
|
| 1298 |
+
#else
|
| 1299 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 1300 |
+
#endif
|
| 1301 |
+
}
|
| 1302 |
+
};
|
| 1303 |
+
|
| 1304 |
+
struct SM90_TMA_REDUCE_ADD_2D
|
| 1305 |
+
{
|
| 1306 |
+
CUTE_HOST_DEVICE static void
|
| 1307 |
+
copy(void const* const desc_ptr,
|
| 1308 |
+
void const* const smem_ptr,
|
| 1309 |
+
int32_t const& crd0, int32_t const& crd1)
|
| 1310 |
+
{
|
| 1311 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 1312 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 1313 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 1314 |
+
cutlass::arch::synclog_emit_tma_store(__LINE__, gmem_int_desc, smem_int_ptr);
|
| 1315 |
+
asm volatile (
|
| 1316 |
+
"cp.reduce.async.bulk.tensor.2d.global.shared::cta.add.bulk_group [%0, {%2, %3}], [%1];"
|
| 1317 |
+
:
|
| 1318 |
+
: "l"(gmem_int_desc), "r"(smem_int_ptr),
|
| 1319 |
+
"r"(crd0), "r"(crd1)
|
| 1320 |
+
: "memory");
|
| 1321 |
+
#else
|
| 1322 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 1323 |
+
#endif
|
| 1324 |
+
}
|
| 1325 |
+
};
|
| 1326 |
+
|
| 1327 |
+
struct SM90_TMA_REDUCE_ADD_3D
|
| 1328 |
+
{
|
| 1329 |
+
CUTE_HOST_DEVICE static void
|
| 1330 |
+
copy(void const* const desc_ptr,
|
| 1331 |
+
void const* const smem_ptr,
|
| 1332 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2)
|
| 1333 |
+
{
|
| 1334 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 1335 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 1336 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 1337 |
+
cutlass::arch::synclog_emit_tma_store(__LINE__, gmem_int_desc, smem_int_ptr);
|
| 1338 |
+
asm volatile (
|
| 1339 |
+
"cp.reduce.async.bulk.tensor.3d.global.shared::cta.add.bulk_group [%0, {%2, %3, %4}], [%1];"
|
| 1340 |
+
:
|
| 1341 |
+
: "l"(gmem_int_desc), "r"(smem_int_ptr),
|
| 1342 |
+
"r"(crd0), "r"(crd1), "r"(crd2)
|
| 1343 |
+
: "memory");
|
| 1344 |
+
#else
|
| 1345 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 1346 |
+
#endif
|
| 1347 |
+
}
|
| 1348 |
+
};
|
| 1349 |
+
|
| 1350 |
+
struct SM90_TMA_REDUCE_ADD_4D
|
| 1351 |
+
{
|
| 1352 |
+
CUTE_HOST_DEVICE static void
|
| 1353 |
+
copy(void const* const desc_ptr,
|
| 1354 |
+
void const* const smem_ptr,
|
| 1355 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3)
|
| 1356 |
+
{
|
| 1357 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 1358 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 1359 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 1360 |
+
cutlass::arch::synclog_emit_tma_store(__LINE__, gmem_int_desc, smem_int_ptr);
|
| 1361 |
+
asm volatile (
|
| 1362 |
+
"cp.reduce.async.bulk.tensor.4d.global.shared::cta.add.bulk_group [%0, {%2, %3, %4, %5}], [%1];"
|
| 1363 |
+
:
|
| 1364 |
+
: "l"(gmem_int_desc), "r"(smem_int_ptr),
|
| 1365 |
+
"r"(crd0), "r"(crd1), "r"(crd2), "r"(crd3)
|
| 1366 |
+
: "memory");
|
| 1367 |
+
#else
|
| 1368 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 1369 |
+
#endif
|
| 1370 |
+
}
|
| 1371 |
+
};
|
| 1372 |
+
|
| 1373 |
+
struct SM90_TMA_REDUCE_ADD_5D
|
| 1374 |
+
{
|
| 1375 |
+
CUTE_HOST_DEVICE static void
|
| 1376 |
+
copy(void const* const desc_ptr,
|
| 1377 |
+
void const* const smem_ptr,
|
| 1378 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3, int32_t const& crd4)
|
| 1379 |
+
{
|
| 1380 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 1381 |
+
uint64_t gmem_int_desc = reinterpret_cast<uint64_t>(desc_ptr);
|
| 1382 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 1383 |
+
cutlass::arch::synclog_emit_tma_store(__LINE__, gmem_int_desc, smem_int_ptr);
|
| 1384 |
+
asm volatile (
|
| 1385 |
+
"cp.reduce.async.bulk.tensor.5d.global.shared::cta.add.bulk_group [%0, {%2, %3, %4, %5, %6}], [%1];"
|
| 1386 |
+
:
|
| 1387 |
+
: "l"(gmem_int_desc), "r"(smem_int_ptr),
|
| 1388 |
+
"r"(crd0), "r"(crd1), "r"(crd2), "r"(crd3), "r"(crd4)
|
| 1389 |
+
: "memory");
|
| 1390 |
+
#else
|
| 1391 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use tma without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 1392 |
+
#endif
|
| 1393 |
+
}
|
| 1394 |
+
};
|
| 1395 |
+
|
| 1396 |
+
struct SM90_TMA_REDUCE_ADD
|
| 1397 |
+
{
|
| 1398 |
+
CUTE_HOST_DEVICE static void
|
| 1399 |
+
copy(void const* const desc_ptr,
|
| 1400 |
+
void const* const smem_ptr,
|
| 1401 |
+
int32_t const& crd0)
|
| 1402 |
+
{
|
| 1403 |
+
return SM90_TMA_REDUCE_ADD_1D::copy(desc_ptr, smem_ptr, crd0);
|
| 1404 |
+
}
|
| 1405 |
+
CUTE_HOST_DEVICE static void
|
| 1406 |
+
copy(void const* const desc_ptr,
|
| 1407 |
+
void const* const smem_ptr,
|
| 1408 |
+
int32_t const& crd0, int32_t const& crd1)
|
| 1409 |
+
{
|
| 1410 |
+
return SM90_TMA_REDUCE_ADD_2D::copy(desc_ptr, smem_ptr, crd0, crd1);
|
| 1411 |
+
}
|
| 1412 |
+
CUTE_HOST_DEVICE static void
|
| 1413 |
+
copy(void const* const desc_ptr,
|
| 1414 |
+
void const* const smem_ptr,
|
| 1415 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2)
|
| 1416 |
+
{
|
| 1417 |
+
return SM90_TMA_REDUCE_ADD_3D::copy(desc_ptr, smem_ptr, crd0, crd1, crd2);
|
| 1418 |
+
}
|
| 1419 |
+
CUTE_HOST_DEVICE static void
|
| 1420 |
+
copy(void const* const desc_ptr,
|
| 1421 |
+
void const* const smem_ptr,
|
| 1422 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3)
|
| 1423 |
+
{
|
| 1424 |
+
return SM90_TMA_REDUCE_ADD_4D::copy(desc_ptr, smem_ptr, crd0, crd1, crd2, crd3);
|
| 1425 |
+
}
|
| 1426 |
+
CUTE_HOST_DEVICE static void
|
| 1427 |
+
copy(void const* const desc_ptr,
|
| 1428 |
+
void const* const smem_ptr,
|
| 1429 |
+
int32_t const& crd0, int32_t const& crd1, int32_t const& crd2, int32_t const& crd3, int32_t const& crd4)
|
| 1430 |
+
{
|
| 1431 |
+
return SM90_TMA_REDUCE_ADD_5D::copy(desc_ptr, smem_ptr, crd0, crd1, crd2, crd3, crd4);
|
| 1432 |
+
}
|
| 1433 |
+
};
|
| 1434 |
+
|
| 1435 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1436 |
+
/// BULK_COPY : Copy a bulk of memory between shared memory and global memory
|
| 1437 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1438 |
+
|
| 1439 |
+
struct SM90_BULK_COPY_G2S
|
| 1440 |
+
{
|
| 1441 |
+
CUTE_HOST_DEVICE static void
|
| 1442 |
+
copy(void const* gmem_ptr, uint64_t* mbar_ptr,
|
| 1443 |
+
void * smem_ptr, int32_t load_bytes)
|
| 1444 |
+
{
|
| 1445 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 1446 |
+
uint32_t smem_int_mbar = cast_smem_ptr_to_uint(mbar_ptr);
|
| 1447 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 1448 |
+
asm volatile("cp.async.bulk.shared::cluster.global.mbarrier::complete_tx::bytes [%0], [%1], %2, [%3];\n"
|
| 1449 |
+
:
|
| 1450 |
+
: "r"(smem_int_ptr), "l"(gmem_ptr), "r"(load_bytes), "r"(smem_int_mbar)
|
| 1451 |
+
: "memory");
|
| 1452 |
+
#else
|
| 1453 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use BULK_COPY without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 1454 |
+
#endif
|
| 1455 |
+
}
|
| 1456 |
+
|
| 1457 |
+
struct PREFETCH
|
| 1458 |
+
{
|
| 1459 |
+
CUTE_HOST_DEVICE static void
|
| 1460 |
+
copy(void const* gmem_ptr, int32_t load_bytes)
|
| 1461 |
+
{
|
| 1462 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 1463 |
+
asm volatile("cp.async.bulk.prefetch.L2.global [%0], %1;\n"
|
| 1464 |
+
:
|
| 1465 |
+
: "l"(gmem_ptr), "r"(load_bytes)
|
| 1466 |
+
: "memory");
|
| 1467 |
+
#else
|
| 1468 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use BULK_COPY without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 1469 |
+
#endif
|
| 1470 |
+
}
|
| 1471 |
+
};
|
| 1472 |
+
};
|
| 1473 |
+
|
| 1474 |
+
struct SM90_BULK_COPY_S2G
|
| 1475 |
+
{
|
| 1476 |
+
CUTE_HOST_DEVICE static void
|
| 1477 |
+
copy(void const* smem_ptr,
|
| 1478 |
+
void * gmem_ptr, int32_t store_bytes)
|
| 1479 |
+
{
|
| 1480 |
+
#if defined(CUTE_ARCH_TMA_SM90_ENABLED)
|
| 1481 |
+
uint32_t smem_int_ptr = cast_smem_ptr_to_uint(smem_ptr);
|
| 1482 |
+
asm volatile("cp.async.bulk.global.shared::cta.bulk_group [%0], [%1], %2;\n"
|
| 1483 |
+
:
|
| 1484 |
+
: "l"(gmem_ptr), "r"(smem_int_ptr), "r"(store_bytes)
|
| 1485 |
+
: "memory");
|
| 1486 |
+
#else
|
| 1487 |
+
CUTE_INVALID_CONTROL_PATH("Trying to use BULK_COPY without CUTE_ARCH_TMA_SM90_ENABLED.");
|
| 1488 |
+
#endif
|
| 1489 |
+
}
|
| 1490 |
+
};
|
| 1491 |
+
|
| 1492 |
+
struct SM90_BULK_COPY_AUTO {};
|
| 1493 |
+
|
| 1494 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1495 |
+
|
| 1496 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma.hpp
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/config.hpp> // CUTE_HOST_DEVICE
|
| 34 |
+
#include <cute/numeric/complex.hpp> // cute::fma
|
| 35 |
+
#include <cute/numeric/real.hpp> // cute::fma
|
| 36 |
+
|
| 37 |
+
namespace cute
|
| 38 |
+
{
|
| 39 |
+
|
| 40 |
+
//
|
| 41 |
+
// Direct FMA for any type
|
| 42 |
+
//
|
| 43 |
+
|
| 44 |
+
template <class D, class A = D, class B = A, class C = D>
|
| 45 |
+
struct UniversalFMA
|
| 46 |
+
{
|
| 47 |
+
using DRegisters = D[1];
|
| 48 |
+
using ARegisters = A[1];
|
| 49 |
+
using BRegisters = B[1];
|
| 50 |
+
using CRegisters = C[1];
|
| 51 |
+
|
| 52 |
+
CUTE_HOST_DEVICE static constexpr void
|
| 53 |
+
fma(D & d,
|
| 54 |
+
A const& a,
|
| 55 |
+
B const& b,
|
| 56 |
+
C const& c)
|
| 57 |
+
{
|
| 58 |
+
// Forward to an ADL/cute free function for these types
|
| 59 |
+
using cute::fma;
|
| 60 |
+
fma(d, a, b, c);
|
| 61 |
+
}
|
| 62 |
+
};
|
| 63 |
+
|
| 64 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm100.hpp
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
//
|
| 32 |
+
|
| 33 |
+
//
|
| 34 |
+
|
| 35 |
+
#pragma once
|
| 36 |
+
|
| 37 |
+
#include <cute/arch/config.hpp>
|
| 38 |
+
#include <cute/arch/mma.hpp>
|
| 39 |
+
|
| 40 |
+
namespace cute {
|
| 41 |
+
|
| 42 |
+
} // namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm100_desc.hpp
ADDED
|
@@ -0,0 +1,651 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
//
|
| 32 |
+
|
| 33 |
+
//
|
| 34 |
+
|
| 35 |
+
#pragma once
|
| 36 |
+
|
| 37 |
+
#if !defined(__CUDACC_RTC__)
|
| 38 |
+
#include <cinttypes>
|
| 39 |
+
#endif
|
| 40 |
+
|
| 41 |
+
#include <cute/arch/config.hpp>
|
| 42 |
+
|
| 43 |
+
#include <cute/arch/mma.hpp>
|
| 44 |
+
|
| 45 |
+
#include <cute/container/bit_field.hpp>
|
| 46 |
+
#include <cute/container/array.hpp> // cute::array
|
| 47 |
+
|
| 48 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 49 |
+
|
| 50 |
+
namespace cute {
|
| 51 |
+
|
| 52 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 53 |
+
// UMMA Descriptor and utilities
|
| 54 |
+
|
| 55 |
+
// UMMA enums and utilities
|
| 56 |
+
namespace UMMA
|
| 57 |
+
{
|
| 58 |
+
|
| 59 |
+
enum class Major : uint8_t {
|
| 60 |
+
K = 0,
|
| 61 |
+
MN = 1
|
| 62 |
+
};
|
| 63 |
+
|
| 64 |
+
enum class ScaleIn : uint8_t {
|
| 65 |
+
One = 0,
|
| 66 |
+
Neg = 1
|
| 67 |
+
};
|
| 68 |
+
|
| 69 |
+
enum class ScaleOut : uint8_t {
|
| 70 |
+
Zero = 0,
|
| 71 |
+
One = 1
|
| 72 |
+
};
|
| 73 |
+
|
| 74 |
+
enum class Saturate : uint8_t {
|
| 75 |
+
False = 0,
|
| 76 |
+
True = 1
|
| 77 |
+
};
|
| 78 |
+
|
| 79 |
+
enum class LayoutType : uint8_t {
|
| 80 |
+
SWIZZLE_NONE = 0,
|
| 81 |
+
SWIZZLE_128B_BASE32B = 1,
|
| 82 |
+
SWIZZLE_128B = 2,
|
| 83 |
+
SWIZZLE_64B = 4,
|
| 84 |
+
SWIZZLE_32B = 6
|
| 85 |
+
};
|
| 86 |
+
|
| 87 |
+
CUTE_HOST_DEVICE char const* to_string(LayoutType const& t) {
|
| 88 |
+
switch (t) {
|
| 89 |
+
case LayoutType::SWIZZLE_NONE: return "SWIZZLE_NONE";
|
| 90 |
+
case LayoutType::SWIZZLE_128B_BASE32B: return "SWIZZLE_128B_BASE32B";
|
| 91 |
+
case LayoutType::SWIZZLE_128B: return "SWIZZLE_128B";
|
| 92 |
+
case LayoutType::SWIZZLE_64B: return "SWIZZLE_64B";
|
| 93 |
+
case LayoutType::SWIZZLE_32B: return "SWIZZLE_32B";
|
| 94 |
+
}
|
| 95 |
+
return nullptr;
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
union SmemDescriptor
|
| 99 |
+
{
|
| 100 |
+
uint64_t desc_ = 0;
|
| 101 |
+
// Bitfield implementation avoids the need for shifts in assignment
|
| 102 |
+
struct {
|
| 103 |
+
// start_address, bit [0,14), 4LSB not included
|
| 104 |
+
uint16_t start_address_ : 14, : 2; // 14 bits [0,14), 2 bits unused
|
| 105 |
+
// leading dimension byte offset, bit [16,30), 4LSB not included
|
| 106 |
+
uint16_t leading_byte_offset_ : 14, : 2; // 14 bits [0,14), 2 bits unused
|
| 107 |
+
// stride dimension byte offset, bit [32,46), 4LSB not included
|
| 108 |
+
uint16_t stride_byte_offset_ : 14, version_ : 2; // 14 bits [0,14), 2 bits [14,16)
|
| 109 |
+
// base_offset, bit [49,52). leading_byte_offset_mode, bit [52,53).
|
| 110 |
+
uint8_t : 1, base_offset_ : 3, lbo_mode_ : 1, : 3; // 1 bit unused, 3 bits [1,4), 1 bit [4,5), 3 bits unused
|
| 111 |
+
// layout type, bit [61,64), SWIZZLE_NONE matrix descriptor = 0, SWIZZLE_128B matrix descriptor = 2, SWIZZLE_64B descriptor = 4, SWIZZLE_32B descriptor = 6, SWIZZLE_128B_BASE32B = 1, N/A = 3, N/A = 5, N/A = 7
|
| 112 |
+
uint8_t : 5, layout_type_ : 3; // 6 bits unused, 3 bits [5,8)
|
| 113 |
+
};
|
| 114 |
+
// Seperate the field, as we may only update one part of desc
|
| 115 |
+
struct {
|
| 116 |
+
uint32_t lo;
|
| 117 |
+
uint32_t hi;
|
| 118 |
+
};
|
| 119 |
+
|
| 120 |
+
// Decay to a uint64_t
|
| 121 |
+
CUTE_HOST_DEVICE constexpr
|
| 122 |
+
operator uint64_t() const noexcept { return desc_; }
|
| 123 |
+
};
|
| 124 |
+
|
| 125 |
+
enum class F16F32Format : uint8_t {
|
| 126 |
+
F16 = 0,
|
| 127 |
+
BF16 = 1,
|
| 128 |
+
TF32 = 2,
|
| 129 |
+
};
|
| 130 |
+
|
| 131 |
+
CUTE_HOST_DEVICE char const* to_string(F16F32Format const& t) {
|
| 132 |
+
switch (t) {
|
| 133 |
+
case F16F32Format::F16: return "F16";
|
| 134 |
+
case F16F32Format::BF16: return "BF16";
|
| 135 |
+
case F16F32Format::TF32: return "TF32";
|
| 136 |
+
}
|
| 137 |
+
return nullptr;
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
template <class T>
|
| 141 |
+
CUTE_HOST_DEVICE constexpr F16F32Format to_F16F32Format() {
|
| 142 |
+
if constexpr (is_same_v<T, half_t>) { return F16F32Format::F16; } else
|
| 143 |
+
if constexpr (is_same_v<T, bfloat16_t>) { return F16F32Format::BF16; } else
|
| 144 |
+
if constexpr (is_same_v<T, tfloat32_t>) { return F16F32Format::TF32; } else
|
| 145 |
+
{ static_assert(sizeof(T) == 0, "Unknown type for F16F32Format"); }
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
enum class S8Format : uint8_t {
|
| 149 |
+
UINT8 = 0,
|
| 150 |
+
INT8 = 1,
|
| 151 |
+
};
|
| 152 |
+
|
| 153 |
+
CUTE_HOST_DEVICE char const* to_string(S8Format const& t) {
|
| 154 |
+
switch (t) {
|
| 155 |
+
case S8Format::UINT8: return "UINT8";
|
| 156 |
+
case S8Format::INT8: return "INT8";
|
| 157 |
+
}
|
| 158 |
+
return nullptr;
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
template <class T>
|
| 162 |
+
CUTE_HOST_DEVICE constexpr S8Format to_S8Format() {
|
| 163 |
+
if constexpr (is_same_v<T, uint8_t>) { return S8Format::UINT8; } else
|
| 164 |
+
if constexpr (is_same_v<T, int8_t>) { return S8Format::INT8; } else
|
| 165 |
+
{ static_assert(sizeof(T) == 0, "Unknown type for S8Format"); }
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
enum class MXF8F6F4Format : uint8_t {
|
| 169 |
+
E4M3 = 0,
|
| 170 |
+
E5M2 = 1,
|
| 171 |
+
E2M3 = 3,
|
| 172 |
+
E3M2 = 4,
|
| 173 |
+
E2M1 = 5,
|
| 174 |
+
INVALID = 7 // an invalid datatype for runtime proxy type
|
| 175 |
+
};
|
| 176 |
+
|
| 177 |
+
CUTE_HOST_DEVICE char const* to_string(MXF8F6F4Format const& t) {
|
| 178 |
+
switch (t) {
|
| 179 |
+
case MXF8F6F4Format::E4M3: return "E4M3";
|
| 180 |
+
case MXF8F6F4Format::E5M2: return "E5M2";
|
| 181 |
+
case MXF8F6F4Format::E2M3: return "E2M3";
|
| 182 |
+
case MXF8F6F4Format::E3M2: return "E3M2";
|
| 183 |
+
case MXF8F6F4Format::E2M1: return "E2M1";
|
| 184 |
+
case MXF8F6F4Format::INVALID: return "INVALID";
|
| 185 |
+
}
|
| 186 |
+
return nullptr;
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
template <class T>
|
| 190 |
+
CUTE_HOST_DEVICE constexpr MXF8F6F4Format to_MXF8F6F4Format() {
|
| 191 |
+
if constexpr (is_same_v<T, float_e4m3_t>) { return MXF8F6F4Format::E4M3; } else
|
| 192 |
+
if constexpr (is_same_v<T, float_e5m2_t>) { return MXF8F6F4Format::E5M2; } else
|
| 193 |
+
if constexpr (is_same_v<T, detail::float_e2m3_unpacksmem_t>) { return MXF8F6F4Format::E2M3; } else
|
| 194 |
+
if constexpr (is_same_v<T, detail::float_e3m2_unpacksmem_t>) { return MXF8F6F4Format::E3M2; } else
|
| 195 |
+
if constexpr (is_same_v<T, detail::float_e2m1_unpacksmem_t>) { return MXF8F6F4Format::E2M1; } else
|
| 196 |
+
{ static_assert(sizeof(T) == 0, "Unknown type for MXF8F6F4Format"); }
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
enum class MXF4Format : uint8_t {
|
| 200 |
+
E2M1 = 1,
|
| 201 |
+
};
|
| 202 |
+
|
| 203 |
+
CUTE_HOST_DEVICE char const* to_string(MXF4Format const& t) {
|
| 204 |
+
switch (t) {
|
| 205 |
+
case MXF4Format::E2M1: return "E2M1";
|
| 206 |
+
}
|
| 207 |
+
return nullptr;
|
| 208 |
+
}
|
| 209 |
+
|
| 210 |
+
template <class T>
|
| 211 |
+
CUTE_HOST_DEVICE constexpr MXF4Format to_MXF4Format() {
|
| 212 |
+
if constexpr (is_same_v<T, float_e2m1_t>) { return MXF4Format::E2M1; } else
|
| 213 |
+
{ static_assert(sizeof(T) == 0, "Unknown type for MXF4Format"); }
|
| 214 |
+
}
|
| 215 |
+
|
| 216 |
+
enum class ScaleFormat : uint8_t {
|
| 217 |
+
UE4M3 = 0,
|
| 218 |
+
UE8M0 = 1,
|
| 219 |
+
};
|
| 220 |
+
|
| 221 |
+
CUTE_HOST_DEVICE char const* to_string(ScaleFormat const& t) {
|
| 222 |
+
switch (t) {
|
| 223 |
+
case ScaleFormat::UE4M3: return "UE4M3";
|
| 224 |
+
case ScaleFormat::UE8M0: return "UE8M0";
|
| 225 |
+
}
|
| 226 |
+
return nullptr;
|
| 227 |
+
}
|
| 228 |
+
|
| 229 |
+
template <class T>
|
| 230 |
+
CUTE_HOST_DEVICE constexpr ScaleFormat to_ScaleFormat() {
|
| 231 |
+
if constexpr (is_same_v<T, float_ue4m3_t>) { return ScaleFormat::UE4M3; } else
|
| 232 |
+
if constexpr (is_same_v<T, float_ue8m0_t>) { return ScaleFormat::UE8M0; } else
|
| 233 |
+
{ static_assert(sizeof(T) == 0, "Unknown type for ScaleFormat"); }
|
| 234 |
+
}
|
| 235 |
+
|
| 236 |
+
enum class CFormat : uint8_t {
|
| 237 |
+
F16 = 0,
|
| 238 |
+
F32 = 1,
|
| 239 |
+
S32 = 2,
|
| 240 |
+
};
|
| 241 |
+
|
| 242 |
+
CUTE_HOST_DEVICE char const* to_string(CFormat const& t) {
|
| 243 |
+
switch (t) {
|
| 244 |
+
case CFormat::F16: return "F16";
|
| 245 |
+
case CFormat::F32: return "F32";
|
| 246 |
+
case CFormat::S32: return "S32";
|
| 247 |
+
}
|
| 248 |
+
return nullptr;
|
| 249 |
+
}
|
| 250 |
+
|
| 251 |
+
enum class MaxShift : uint8_t {
|
| 252 |
+
NoShift = 0,
|
| 253 |
+
MaxShift8 = 1,
|
| 254 |
+
MaxShift16 = 2,
|
| 255 |
+
MaxShift32 = 3
|
| 256 |
+
};
|
| 257 |
+
|
| 258 |
+
enum class BMatrixBufferId : uint8_t {
|
| 259 |
+
Zero = 0u,
|
| 260 |
+
One = 1u,
|
| 261 |
+
Two = 2u,
|
| 262 |
+
Three = 3u
|
| 263 |
+
};
|
| 264 |
+
|
| 265 |
+
enum class BMatrixBufferReuse : uint8_t {
|
| 266 |
+
Keep = 1u,
|
| 267 |
+
Reuse = 2u,
|
| 268 |
+
ReuseAndKeep = 3u
|
| 269 |
+
};
|
| 270 |
+
|
| 271 |
+
// using MaskAndShiftB = uint32_t[2];
|
| 272 |
+
union MaskAndShiftB
|
| 273 |
+
{
|
| 274 |
+
uint32_t uri[2];
|
| 275 |
+
|
| 276 |
+
struct {
|
| 277 |
+
// Bitfield implementation avoids the need for shifts in assignment
|
| 278 |
+
uint8_t start_count_ [4]; // bit [ 0:32) : 8 bits each. Specifies the start count for mask generation.
|
| 279 |
+
uint32_t first_span_ : 4, // bit [32:36) : 1 bit each. 0 = start where B is used. 1 = start with where B is skipped(0 value is used).
|
| 280 |
+
: 3, //
|
| 281 |
+
nzm_ : 1, // bit [39:40) : 0 = Enable the mask. 1 = Disable the mask.
|
| 282 |
+
skip_span_ : 8, // bit [40:48) : Count-1 (zero encoded in this field specifies use span of 1) of consecutive columns where 0 value is used.
|
| 283 |
+
use_span_ : 8, // bit [48:55) : Count-1 (zero encoded in this field specifies use span of 1) of consecutive columns where B matrix data is used.
|
| 284 |
+
shift_ : 6, // bit [56:62) : Shift value for B matrix data.
|
| 285 |
+
: 2;
|
| 286 |
+
};
|
| 287 |
+
};
|
| 288 |
+
|
| 289 |
+
template <typename ShapeType, int FLT_S, int CTA_M, int CTA_N>
|
| 290 |
+
CUTE_HOST_DEVICE constexpr auto
|
| 291 |
+
make_column_zero_mask(ShapeType conv_q, int32_t cta_coord_q, int32_t num_pixels_skip_left) {
|
| 292 |
+
|
| 293 |
+
static_assert(cute::is_same_v<ShapeType, cutlass::FastDivmod> || cute::is_integral<ShapeType>::value);
|
| 294 |
+
|
| 295 |
+
cute::array<MaskAndShiftB, FLT_S> column_zero_masks{};
|
| 296 |
+
|
| 297 |
+
static_assert(FLT_S == 3, "Filter size not supported.");
|
| 298 |
+
constexpr int MAX_USE_SPAN_COUNT = 256;
|
| 299 |
+
constexpr int MAX_SKIP_SPAN_COUNT = 256;
|
| 300 |
+
|
| 301 |
+
// conv_q_int used for non-divmod case (add/minus/..)
|
| 302 |
+
// conv_q used for divmod case (div/mod/...)
|
| 303 |
+
int32_t conv_q_int = int(conv_q);
|
| 304 |
+
auto [_, cta_q] = divmod(cta_coord_q * CTA_N, conv_q);
|
| 305 |
+
|
| 306 |
+
int step_q = CTA_M == 128 ? CTA_N / 1
|
| 307 |
+
: CTA_M == 64 ? CTA_N / 2
|
| 308 |
+
: CTA_M == 32 ? CTA_N / 4
|
| 309 |
+
: 0;
|
| 310 |
+
|
| 311 |
+
for (int mask_iter = 0; mask_iter < int(CTA_N / step_q); ++mask_iter) {
|
| 312 |
+
|
| 313 |
+
for (int s_iter = 0; s_iter < FLT_S; s_iter += 1) {
|
| 314 |
+
|
| 315 |
+
int32_t skip_span{0}, use_span{0}, nzm{1}, first_span{0}, start_count{0}, shift{0};
|
| 316 |
+
|
| 317 |
+
shift = s_iter;
|
| 318 |
+
|
| 319 |
+
// Examples for CZM setting
|
| 320 |
+
// CASE0: (skip_span_ < 0)
|
| 321 |
+
// | padding |<- conv_q ->|
|
| 322 |
+
// |skip_span_|<- use_span ->|skip_span_|
|
| 323 |
+
// -skip_span 0 ^cta_q conv_q-1
|
| 324 |
+
// 0 ^index
|
| 325 |
+
//
|
| 326 |
+
// CASE1: (skip_span_ > 0)
|
| 327 |
+
// |<- conv_q ->|
|
| 328 |
+
// |skip_span_|<- use_span ->|skip_span_|
|
| 329 |
+
// 0 ^cta_q conv_q-1
|
| 330 |
+
// 0 ^index
|
| 331 |
+
//
|
| 332 |
+
// line 0 an input vector from 0 to conv_q with the padding
|
| 333 |
+
// line 1 shows the different spans we need to skip or load
|
| 334 |
+
// lines 2-3 show the different coordinates of different boundaries.
|
| 335 |
+
// CTQ_q is the coordinate of the present cta.
|
| 336 |
+
|
| 337 |
+
int32_t skip_span_ = num_pixels_skip_left - shift;
|
| 338 |
+
int32_t index{0};
|
| 339 |
+
if (skip_span_ > 0) {
|
| 340 |
+
auto [_, index_mod] = divmod(cta_q, conv_q);
|
| 341 |
+
index = index_mod;
|
| 342 |
+
} else if (skip_span_ < 0) {
|
| 343 |
+
auto [_, index_mod] = divmod((cta_q - skip_span_), conv_q);
|
| 344 |
+
index = index_mod;
|
| 345 |
+
} else {
|
| 346 |
+
nzm = 0;
|
| 347 |
+
}
|
| 348 |
+
skip_span = cute::max(cute::abs(skip_span_), 1);
|
| 349 |
+
use_span = cute::min(conv_q_int - static_cast<int32_t>(skip_span), MAX_USE_SPAN_COUNT);
|
| 350 |
+
if (use_span > 0) {
|
| 351 |
+
first_span = index >= skip_span ? 0 : 1;
|
| 352 |
+
if ((first_span == 0) && (index + CTA_N < conv_q_int + skip_span)) {
|
| 353 |
+
nzm = 0;
|
| 354 |
+
} else {
|
| 355 |
+
start_count = first_span == 0 ? (use_span - (conv_q_int - index)) : index;
|
| 356 |
+
}
|
| 357 |
+
} else {
|
| 358 |
+
skip_span = MAX_SKIP_SPAN_COUNT;
|
| 359 |
+
use_span = 1;
|
| 360 |
+
first_span = 1;
|
| 361 |
+
start_count = 0;
|
| 362 |
+
}
|
| 363 |
+
|
| 364 |
+
column_zero_masks[s_iter].start_count_[mask_iter] = start_count;
|
| 365 |
+
column_zero_masks[s_iter].first_span_ |= first_span << mask_iter;
|
| 366 |
+
column_zero_masks[s_iter].nzm_ |= nzm;
|
| 367 |
+
column_zero_masks[s_iter].skip_span_ = skip_span - 1;
|
| 368 |
+
column_zero_masks[s_iter].use_span_ = use_span - 1;
|
| 369 |
+
column_zero_masks[s_iter].shift_ = shift;
|
| 370 |
+
|
| 371 |
+
}
|
| 372 |
+
|
| 373 |
+
cta_q += step_q;
|
| 374 |
+
}
|
| 375 |
+
|
| 376 |
+
return column_zero_masks;
|
| 377 |
+
}
|
| 378 |
+
|
| 379 |
+
template <class T>
|
| 380 |
+
CUTE_HOST_DEVICE constexpr auto to_UMMAFormat() {
|
| 381 |
+
if constexpr (is_same_v<T, half_t>) { return F16F32Format::F16; } else
|
| 382 |
+
if constexpr (is_same_v<T, bfloat16_t>) { return F16F32Format::BF16; } else
|
| 383 |
+
if constexpr (is_same_v<T, tfloat32_t>) { return F16F32Format::TF32; } else
|
| 384 |
+
if constexpr (is_same_v<T, uint8_t>) { return S8Format::UINT8; } else
|
| 385 |
+
if constexpr (is_same_v<T, int8_t>) { return S8Format::INT8; } else
|
| 386 |
+
if constexpr (is_same_v<T, type_erased_dynamic_float8_t>) {return MXF8F6F4Format::INVALID; } else
|
| 387 |
+
|
| 388 |
+
if constexpr (is_same_v<T, type_erased_dynamic_float6_t>) {return MXF8F6F4Format::INVALID; } else
|
| 389 |
+
if constexpr (is_same_v<T, type_erased_dynamic_float4_t>) {return MXF8F6F4Format::INVALID; } else
|
| 390 |
+
if constexpr (is_same_v<T, detail::type_erased_dynamic_float4_unpacksmem_t>) {return MXF8F6F4Format::INVALID; } else
|
| 391 |
+
|
| 392 |
+
if constexpr (is_same_v<T, float_e4m3_t>) { return MXF8F6F4Format::E4M3; } else
|
| 393 |
+
if constexpr (is_same_v<T, float_e5m2_t>) { return MXF8F6F4Format::E5M2; } else
|
| 394 |
+
if constexpr (is_same_v<T, detail::type_erased_dynamic_float6_unpacksmem_t>) {return MXF8F6F4Format::INVALID; } else
|
| 395 |
+
if constexpr (is_same_v<T, detail::float_e2m3_unpacksmem_t>) { return MXF8F6F4Format::E2M3; } else
|
| 396 |
+
if constexpr (is_same_v<T, detail::float_e3m2_unpacksmem_t>) { return MXF8F6F4Format::E3M2; } else
|
| 397 |
+
if constexpr (is_same_v<T, float_e2m3_t>) { return MXF8F6F4Format::E2M3; } else
|
| 398 |
+
if constexpr (is_same_v<T, float_e3m2_t>) { return MXF8F6F4Format::E3M2; } else
|
| 399 |
+
if constexpr (is_same_v<T, detail::float_e2m1_unpacksmem_t>) { return MXF8F6F4Format::E2M1; } else
|
| 400 |
+
if constexpr (is_same_v<T, float_e2m1_t>) { return MXF4Format::E2M1; } else
|
| 401 |
+
{ static_assert(sizeof(T) == 0, "Unknown type for UMMAFormat"); }
|
| 402 |
+
}
|
| 403 |
+
|
| 404 |
+
template <class T>
|
| 405 |
+
CUTE_HOST_DEVICE constexpr CFormat to_CFormat() {
|
| 406 |
+
if constexpr (is_same_v<T, half_t>) { return CFormat::F16; } else
|
| 407 |
+
if constexpr (is_same_v<T, float>) { return CFormat::F32; } else
|
| 408 |
+
if constexpr (is_same_v<T, int32_t>) { return CFormat::S32; } else
|
| 409 |
+
{ static_assert(sizeof(T) == 0, "Unknown type for CFormat"); }
|
| 410 |
+
}
|
| 411 |
+
|
| 412 |
+
union InstrDescriptor
|
| 413 |
+
{
|
| 414 |
+
uint32_t desc_;
|
| 415 |
+
|
| 416 |
+
struct {
|
| 417 |
+
// Bitfield implementation avoids the need for shifts in assignment
|
| 418 |
+
uint16_t sparse_id2_ : 2, // bit [ 0, 2) : Sparse meta data id2
|
| 419 |
+
sparse_flag_ : 1, // bit [ 2, 3) : 0 = dense. 1 = sparse. 1 value valid only for F32F16/S8/MXF8F6F4
|
| 420 |
+
saturate_ : 1, // bit [ 3, 4) : 0 = no saturate. 1 = saturate. 1 value valid only for S8
|
| 421 |
+
c_format_ : 2, // bit [ 4, 6) : 0 = F16. 1 = F32, 2 = S32
|
| 422 |
+
: 1, //
|
| 423 |
+
a_format_ : 3, // bit [ 7,10) : MXF8F6F4Format:0 = E4M3, 1 = E5M2, 3 = E2M3, 4 = E3M2, 5 = E2M1. F32F16Format: 0 = F16, 1 = BF16, 2 = TF32. S8: 0 unsigned 8 bit, 1 signed 8 bit. Boolean MMA: 0 Boolean
|
| 424 |
+
b_format_ : 3, // bit [10,13) : MXF8F6F4Format:0 = E4M3, 1 = E5M2, 3 = E2M3, 4 = E3M2, 5 = E2M1. F32F16Format: 0 = F16, 1 = BF16, 2 = TF32. S8: 0 unsigned 8 bit, 1 signed 8 bit. Boolean MMA: 0 Boolean
|
| 425 |
+
a_negate_ : 1, // bit [13,14) : 0 = no negate. 1 = negate. 1 value valid only for F32F16Format and MXF8F6F4Format
|
| 426 |
+
b_negate_ : 1, // bit [14,15) : 0 = no negate. 1 = negate. 1 value valid only for F32F16Format and MXF8F6F4Format
|
| 427 |
+
a_major_ : 1; // bit [15,16) : 0 = K-major. 1 = MN-major. Major value of 1 is only valid for E4M3, E5M2, INT8 (signed and unsigned), F16, BF16 and TF32 source formats
|
| 428 |
+
uint16_t b_major_ : 1, // bit [16,17) : 0 = K-major. 1 = MN-major. Major value of 1 is only valid for E4M3, E5M2, INT8 (signed and unsigned), F16, BF16 and TF32 source formats
|
| 429 |
+
n_dim_ : 6, // bit [17,23) : 3 LSBs not included. Valid values range from 1 (N=8) to 32 (N=256). All values are not valid for all instruction formats
|
| 430 |
+
: 1, //
|
| 431 |
+
m_dim_ : 5, // bit [24,29) : 4 LSBs not included. Valid values are: 4 (M=64), 8 (M=128), 16 (M=256)
|
| 432 |
+
: 1, //
|
| 433 |
+
max_shift_ : 2; // bit [30,32) : Maximum shift for WS instruction. Encoded as follows: 0 = no shift, 1 = maximum shift of 8, 2 = maximum shift of 16, 3 = maximum shift of 32.
|
| 434 |
+
};
|
| 435 |
+
|
| 436 |
+
// Decay to a uint32_t
|
| 437 |
+
CUTE_HOST_DEVICE constexpr explicit
|
| 438 |
+
operator uint32_t() const noexcept { return desc_; }
|
| 439 |
+
};
|
| 440 |
+
|
| 441 |
+
union InstrDescriptorBlockScaled
|
| 442 |
+
{
|
| 443 |
+
uint32_t desc_;
|
| 444 |
+
|
| 445 |
+
struct {
|
| 446 |
+
// Bitfield implementation avoids the need for shifts in assignment
|
| 447 |
+
uint16_t sparse_id2_ : 2, // bit [ 0, 2) : Sparse meta data id2
|
| 448 |
+
sparse_flag_ : 1, // bit [ 2, 3) : 0 = dense. 1 = sparse. 1 value valid only for F32F16/S8/MXF8F6F4
|
| 449 |
+
: 1, //
|
| 450 |
+
b_sf_id_ : 2, // bit [ 4, 6) : Matrix B Scale Factor ID
|
| 451 |
+
: 1, //
|
| 452 |
+
a_format_ : 3, // bit [ 7, 9) : MXF8F6F4Format:0 = E4M3, 1 = E5M2, 3 = E2M3, 4 = E3M2, 5 = E2M1. F32F16Format: 0 = F16, 1 = BF16, 2 = TF32. S8: 0 unsigned 8 bit, 1 signed 8 bit. BMMA: 0 Boolean
|
| 453 |
+
b_format_ : 3, // bit [10,12) : MXF8F6F4Format:0 = E4M3, 1 = E5M2, 3 = E2M3, 4 = E3M2, 5 = E2M1. F32F16Format: 0 = F16, 1 = BF16, 2 = TF32. S8: 0 unsigned 8 bit, 1 signed 8 bit. BMMA: 0 Boolean
|
| 454 |
+
a_negate_ : 1, // bit [13,14) : 0 = no negate. 1 = negate. 1 value valid only for F32F16Format and MXF8F6F4Format
|
| 455 |
+
b_negate_ : 1, // bit [14,15) : 0 = no negate. 1 = negate. 1 value valid only for F32F16Format and MXF8F6F4Format
|
| 456 |
+
a_major_ : 1; // bit [15,16) : 0 = K-major. 1 = MN-major. Major value of 1 is only valid for E4M3, E5M2, INT8 (signed and unsigned), F16, BF16 and TF32 source formats
|
| 457 |
+
uint16_t b_major_ : 1, // bit [16,17) : 0 = K-major. 1 = MN-major. Major value of 1 is only valid for E4M3, E5M2, INT8 (signed and unsigned), F16, BF16 and TF32 source formats
|
| 458 |
+
n_dim_ : 6, // bit [17,23) : 3 LSBs not included. Valid values range from 1 (N=8) to 32 (N=256). All values are not valid for all instruction formats
|
| 459 |
+
scale_format_ : 1, // bit [23,24) : 0=E4M3, 1=E8M0
|
| 460 |
+
m_dim_ : 5, // bit [24,29) : 4 LSBs not included. Valid values are: 4 (M=64), 8 (M=128), 16 (M=256)
|
| 461 |
+
a_sf_id_ : 2, // bit [29,31) : Matrix A Scale Factor ID
|
| 462 |
+
: 1; //
|
| 463 |
+
};
|
| 464 |
+
|
| 465 |
+
// Decay to a uint32_t
|
| 466 |
+
CUTE_HOST_DEVICE constexpr
|
| 467 |
+
operator uint32_t() const noexcept { return desc_; }
|
| 468 |
+
};
|
| 469 |
+
|
| 470 |
+
template <class a_type, class b_type, class c_type,
|
| 471 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 472 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One,
|
| 473 |
+
UMMA::Saturate c_sat = UMMA::Saturate::False,
|
| 474 |
+
bool is_sparse = false,
|
| 475 |
+
UMMA::MaxShift max_shift = UMMA::MaxShift::NoShift>
|
| 476 |
+
CUTE_HOST_DEVICE constexpr
|
| 477 |
+
UMMA::InstrDescriptor
|
| 478 |
+
make_instr_desc()
|
| 479 |
+
{
|
| 480 |
+
UMMA::InstrDescriptor desc_i = {};
|
| 481 |
+
|
| 482 |
+
desc_i.a_format_ = uint8_t(UMMA::to_UMMAFormat<a_type>());
|
| 483 |
+
desc_i.b_format_ = uint8_t(UMMA::to_UMMAFormat<b_type>());
|
| 484 |
+
desc_i.c_format_ = uint8_t(UMMA::to_CFormat<c_type>());
|
| 485 |
+
|
| 486 |
+
desc_i.m_dim_ = (M >> 4);
|
| 487 |
+
desc_i.n_dim_ = (N >> 3);
|
| 488 |
+
|
| 489 |
+
desc_i.a_major_ = uint8_t(a_major);
|
| 490 |
+
desc_i.b_major_ = uint8_t(b_major);
|
| 491 |
+
|
| 492 |
+
desc_i.a_negate_ = uint8_t(a_neg);
|
| 493 |
+
desc_i.b_negate_ = uint8_t(b_neg);
|
| 494 |
+
desc_i.saturate_ = uint8_t(c_sat);
|
| 495 |
+
|
| 496 |
+
desc_i.sparse_flag_ = is_sparse; // 1 = Sparse
|
| 497 |
+
desc_i.sparse_id2_ = 0;
|
| 498 |
+
|
| 499 |
+
desc_i.max_shift_ = uint8_t(max_shift);
|
| 500 |
+
|
| 501 |
+
return desc_i;
|
| 502 |
+
}
|
| 503 |
+
|
| 504 |
+
template <class a_type, class b_type, class c_type,
|
| 505 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 506 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One,
|
| 507 |
+
UMMA::Saturate c_sat = UMMA::Saturate::False,
|
| 508 |
+
bool is_sparse = false,
|
| 509 |
+
UMMA::MaxShift max_shift = UMMA::MaxShift::NoShift>
|
| 510 |
+
CUTE_HOST_DEVICE
|
| 511 |
+
constexpr uint64_t
|
| 512 |
+
make_runtime_instr_desc(uint16_t sparse_id2 = 0u, uint32_t tmem_e = 0u) {
|
| 513 |
+
UMMA::InstrDescriptor desc_i = UMMA::make_instr_desc<
|
| 514 |
+
a_type, b_type, c_type, M, N, a_major, b_major, a_neg, b_neg, c_sat, is_sparse,
|
| 515 |
+
max_shift>();
|
| 516 |
+
|
| 517 |
+
if constexpr (is_sparse) {
|
| 518 |
+
desc_i.sparse_id2_ = sparse_id2;
|
| 519 |
+
}
|
| 520 |
+
else {
|
| 521 |
+
assert(sparse_id2 == 0u);
|
| 522 |
+
}
|
| 523 |
+
// In current compiler exposure, idescE is a uint64_t. It should contain:
|
| 524 |
+
// - Lower 32b URe: Specifies the tmem address that stores the sparse metadata.
|
| 525 |
+
// Only needed for Sparse MMA instructions. Otherwise, ignored.
|
| 526 |
+
// - Upper 32b URh: Specifies the instruction descriptor.
|
| 527 |
+
uint64_t idescE = (static_cast<uint64_t>(static_cast<uint32_t>(desc_i)) << 32);
|
| 528 |
+
|
| 529 |
+
return idescE;
|
| 530 |
+
}
|
| 531 |
+
|
| 532 |
+
template <bool is_sparse = false>
|
| 533 |
+
CUTE_HOST_DEVICE
|
| 534 |
+
constexpr uint64_t
|
| 535 |
+
make_runtime_instr_desc(UMMA::InstrDescriptor desc_i, uint16_t sparse_id2 = 0u, uint32_t tmem_e = 0u)
|
| 536 |
+
{
|
| 537 |
+
if constexpr (is_sparse) {
|
| 538 |
+
desc_i.sparse_id2_ = sparse_id2;
|
| 539 |
+
}
|
| 540 |
+
else {
|
| 541 |
+
assert(sparse_id2 == 0u);
|
| 542 |
+
}
|
| 543 |
+
// In current compiler exposure, idescE is a uint64_t. It should contain:
|
| 544 |
+
// - Lower 32b URe: Specifies the tmem address that stores the sparse metadata.
|
| 545 |
+
// Only needed for Sparse MMA instructions. Otherwise, ignored.
|
| 546 |
+
// - Upper 32b URh: Specifies the instruction descriptor.
|
| 547 |
+
uint64_t idescE = (static_cast<uint64_t>(static_cast<uint32_t>(desc_i)) << 32);
|
| 548 |
+
|
| 549 |
+
return idescE;
|
| 550 |
+
}
|
| 551 |
+
|
| 552 |
+
template <class a_type, class b_type, class c_type, class sf_type,
|
| 553 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 554 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One,
|
| 555 |
+
bool is_sparse = false
|
| 556 |
+
>
|
| 557 |
+
CUTE_HOST_DEVICE constexpr
|
| 558 |
+
UMMA::InstrDescriptorBlockScaled
|
| 559 |
+
make_instr_desc_block_scaled()
|
| 560 |
+
{
|
| 561 |
+
UMMA::InstrDescriptorBlockScaled desc_i = {};
|
| 562 |
+
|
| 563 |
+
desc_i.a_format_ = uint8_t(UMMA::to_UMMAFormat<a_type>());
|
| 564 |
+
desc_i.b_format_ = uint8_t(UMMA::to_UMMAFormat<b_type>());
|
| 565 |
+
|
| 566 |
+
desc_i.scale_format_ = uint8_t(UMMA::to_ScaleFormat<sf_type>());
|
| 567 |
+
desc_i.a_sf_id_ = 0;
|
| 568 |
+
desc_i.b_sf_id_ = 0;
|
| 569 |
+
|
| 570 |
+
desc_i.m_dim_ = (M >> 4);
|
| 571 |
+
desc_i.n_dim_ = (N >> 3);
|
| 572 |
+
|
| 573 |
+
desc_i.a_major_ = uint8_t(a_major);
|
| 574 |
+
desc_i.b_major_ = uint8_t(b_major);
|
| 575 |
+
|
| 576 |
+
desc_i.a_negate_ = uint8_t(a_neg);
|
| 577 |
+
desc_i.b_negate_ = uint8_t(b_neg);
|
| 578 |
+
desc_i.sparse_flag_ = is_sparse; // 1 = Sparse
|
| 579 |
+
desc_i.sparse_id2_ = 0;
|
| 580 |
+
|
| 581 |
+
// Below would bring some warnings.
|
| 582 |
+
#if defined(__GNUC__)
|
| 583 |
+
# pragma GCC diagnostic ignored "-Wconversion"
|
| 584 |
+
#endif
|
| 585 |
+
return desc_i;
|
| 586 |
+
}
|
| 587 |
+
|
| 588 |
+
template <class a_type, class b_type, class c_type, class sf_type,
|
| 589 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 590 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One,
|
| 591 |
+
bool is_sparse = false>
|
| 592 |
+
CUTE_HOST_DEVICE
|
| 593 |
+
constexpr uint64_t
|
| 594 |
+
make_runtime_instr_desc_block_scaled(uint32_t const tmem_sfa_addr, uint32_t const tmem_sfb_addr,
|
| 595 |
+
uint16_t const sparse_id2 = 0u, uint32_t const tmem_e = 0u)
|
| 596 |
+
{
|
| 597 |
+
UMMA::InstrDescriptorBlockScaled desc_i = UMMA::make_instr_desc_block_scaled<
|
| 598 |
+
a_type, b_type, c_type, sf_type, M, N,
|
| 599 |
+
a_major, b_major,
|
| 600 |
+
a_neg, b_neg,
|
| 601 |
+
is_sparse>();
|
| 602 |
+
|
| 603 |
+
// The first 2-bits of TMEM address includes byte address.
|
| 604 |
+
desc_i.a_sf_id_ = (tmem_sfa_addr & 0xC0000000) >> 30;
|
| 605 |
+
desc_i.b_sf_id_ = (tmem_sfb_addr & 0xC0000000) >> 30;
|
| 606 |
+
|
| 607 |
+
if constexpr (is_sparse) {
|
| 608 |
+
desc_i.sparse_id2_ = sparse_id2;
|
| 609 |
+
}
|
| 610 |
+
else {
|
| 611 |
+
assert(sparse_id2 == 0u);
|
| 612 |
+
}
|
| 613 |
+
|
| 614 |
+
// In current compiler exposure, idescE is a uint64_t. It should contain:
|
| 615 |
+
// - Lower 32b URe: Specifies the tmem address that stores the sparse metadata.
|
| 616 |
+
// Only needed for Sparse MMA instructions. Otherwise, ignored.
|
| 617 |
+
// - Upper 32b URh: Specifies the instruction descriptor.
|
| 618 |
+
uint64_t idescE = (static_cast<uint64_t>(static_cast<uint32_t>(desc_i)) << 32);
|
| 619 |
+
|
| 620 |
+
return idescE;
|
| 621 |
+
}
|
| 622 |
+
|
| 623 |
+
template <bool is_sparse = false>
|
| 624 |
+
CUTE_HOST_DEVICE
|
| 625 |
+
constexpr uint64_t
|
| 626 |
+
make_runtime_instr_desc_block_scaled(UMMA::InstrDescriptorBlockScaled desc_i,
|
| 627 |
+
uint32_t const tmem_sfa_addr, uint32_t const tmem_sfb_addr,
|
| 628 |
+
uint16_t const sparse_id2 = 0u, uint32_t const tmem_e = 0u)
|
| 629 |
+
{
|
| 630 |
+
// The first 2-bits of TMEM address includes byte address.
|
| 631 |
+
desc_i.a_sf_id_ = (tmem_sfa_addr & 0xC0000000) >> 30;
|
| 632 |
+
desc_i.b_sf_id_ = (tmem_sfb_addr & 0xC0000000) >> 30;
|
| 633 |
+
|
| 634 |
+
if constexpr (is_sparse) {
|
| 635 |
+
desc_i.sparse_id2_ = sparse_id2;
|
| 636 |
+
}
|
| 637 |
+
else {
|
| 638 |
+
assert(sparse_id2 == 0u);
|
| 639 |
+
}
|
| 640 |
+
|
| 641 |
+
// In current compiler exposure, idescE is a uint64_t. It should contain:
|
| 642 |
+
// - Lower 32b URe: Specifies the tmem address that stores the sparse metadata.
|
| 643 |
+
// Only needed for Sparse MMA instructions. Otherwise, ignored.
|
| 644 |
+
// - Upper 32b URh: Specifies the instruction descriptor.
|
| 645 |
+
uint64_t idescE = (static_cast<uint64_t>(static_cast<uint32_t>(desc_i)) << 32);
|
| 646 |
+
|
| 647 |
+
return idescE;
|
| 648 |
+
}
|
| 649 |
+
|
| 650 |
+
} // end namespace UMMA
|
| 651 |
+
} // namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm100_umma.hpp
ADDED
|
@@ -0,0 +1,1616 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
|
| 32 |
+
#pragma once
|
| 33 |
+
|
| 34 |
+
#include <cute/arch/config.hpp>
|
| 35 |
+
#include <cute/arch/mma.hpp>
|
| 36 |
+
#include <cute/arch/mma_sm100.hpp>
|
| 37 |
+
#include <cute/arch/mma_sm100_desc.hpp>
|
| 38 |
+
#include <cute/arch/cluster_sm90.hpp>
|
| 39 |
+
|
| 40 |
+
namespace cute
|
| 41 |
+
{
|
| 42 |
+
|
| 43 |
+
template <class a_type, class b_type, class c_type,
|
| 44 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 45 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One>
|
| 46 |
+
struct SM100_MMA_TF32_SS
|
| 47 |
+
{
|
| 48 |
+
static_assert(M == 64 || M == 128, "SM100_MMA_TF32 M-mode size should be 64 or 128 for 1 CTA cluster MMA.");
|
| 49 |
+
static_assert((M == 64 && (N % 8 == 0) && (8 <= N) && (N <= 256)) ||
|
| 50 |
+
(M == 128 && (N % 16 == 0) && (16 <= N) && (N <= 256)),
|
| 51 |
+
"SM100_MMA_TF32 N-mode size should be a multiple of 8 between 8 and 256 for M=64,\
|
| 52 |
+
or a multiple of 16 between 16 and 256 for M=128.");
|
| 53 |
+
|
| 54 |
+
using DRegisters = void;
|
| 55 |
+
using ARegisters = uint64_t[1];
|
| 56 |
+
using BRegisters = uint64_t[1];
|
| 57 |
+
using CRegisters = uint32_t[1];
|
| 58 |
+
|
| 59 |
+
CUTE_HOST_DEVICE static void
|
| 60 |
+
fma(uint64_t const& desc_a,
|
| 61 |
+
uint64_t const& desc_b,
|
| 62 |
+
uint32_t const& tmem_c,
|
| 63 |
+
uint32_t const& scaleC,
|
| 64 |
+
uint64_t const& idescE)
|
| 65 |
+
{
|
| 66 |
+
#if defined(CUTE_ARCH_TCGEN05_TF32_MMA_ENABLED)
|
| 67 |
+
if (cute::elect_one_sync()) {
|
| 68 |
+
uint32_t mask[4] = {0, 0, 0, 0};
|
| 69 |
+
asm volatile(
|
| 70 |
+
"{\n\t"
|
| 71 |
+
".reg .pred p;\n\t"
|
| 72 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 73 |
+
"tcgen05.mma.cta_group::1.kind::tf32 [%0], %1, %2, %3, {%5, %6, %7, %8}, p; \n\t"
|
| 74 |
+
"}\n"
|
| 75 |
+
:
|
| 76 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 77 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]));
|
| 78 |
+
}
|
| 79 |
+
#else
|
| 80 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_TF32_SS without CUTE_ARCH_TCGEN05_TF32_MMA_ENABLED");
|
| 81 |
+
#endif
|
| 82 |
+
}
|
| 83 |
+
};
|
| 84 |
+
|
| 85 |
+
template <class a_type, class b_type, class c_type,
|
| 86 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 87 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One>
|
| 88 |
+
struct SM100_MMA_F16BF16_SS
|
| 89 |
+
{
|
| 90 |
+
static_assert(M == 64 || M == 128, "SM100_MMA_F16BF16 M-mode size should be 64 or 128 for 1 CTA cluster MMA.");
|
| 91 |
+
static_assert((M == 64 && (N % 8 == 0) && (8 <= N) && (N <= 256)) ||
|
| 92 |
+
(M == 128 && (N % 16 == 0) && (16 <= N) && (N <= 256)),
|
| 93 |
+
"SM100_MMA_F16BF16 N-mode size should be a multiple of 8 between 8 and 256 for M=64,\
|
| 94 |
+
or a multiple of 16 between 16 and 256 for M=128.");
|
| 95 |
+
|
| 96 |
+
using DRegisters = void;
|
| 97 |
+
using ARegisters = uint64_t[1];
|
| 98 |
+
using BRegisters = uint64_t[1];
|
| 99 |
+
using CRegisters = uint32_t[1];
|
| 100 |
+
|
| 101 |
+
CUTE_HOST_DEVICE static void
|
| 102 |
+
fma(uint64_t const& desc_a,
|
| 103 |
+
uint64_t const& desc_b,
|
| 104 |
+
uint32_t const& tmem_c,
|
| 105 |
+
uint32_t const& scaleC,
|
| 106 |
+
uint64_t const& idescE)
|
| 107 |
+
{
|
| 108 |
+
#if defined(CUTE_ARCH_TCGEN05_F16F32_MMA_ENABLED)
|
| 109 |
+
if (cute::elect_one_sync()) {
|
| 110 |
+
uint32_t mask[4] = {0, 0, 0, 0};
|
| 111 |
+
asm volatile(
|
| 112 |
+
"{\n\t"
|
| 113 |
+
".reg .pred p;\n\t"
|
| 114 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 115 |
+
"tcgen05.mma.cta_group::1.kind::f16 [%0], %1, %2, %3, {%5, %6, %7, %8}, p; \n\t"
|
| 116 |
+
"}\n"
|
| 117 |
+
:
|
| 118 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 119 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]));
|
| 120 |
+
}
|
| 121 |
+
#else
|
| 122 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_F16BF16_SS without CUTE_ARCH_MMA_SM100A_ENABLED");
|
| 123 |
+
#endif
|
| 124 |
+
}
|
| 125 |
+
};
|
| 126 |
+
|
| 127 |
+
template <class a_type, class b_type, class c_type,
|
| 128 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 129 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One,
|
| 130 |
+
UMMA::Saturate c_sat = UMMA::Saturate::False>
|
| 131 |
+
struct SM100_MMA_TF32_TS
|
| 132 |
+
{
|
| 133 |
+
static_assert(M == 64 || M == 128, "SM100_MMA_TF32 M-mode size should be 64 or 128 for 1 CTA cluster MMA.");
|
| 134 |
+
static_assert((M == 64 && (N % 8 == 0) && (8 <= N) && (N <= 256)) ||
|
| 135 |
+
(M == 128 && (N % 16 == 0) && (16 <= N) && (N <= 256)),
|
| 136 |
+
"SM100_MMA_TF32 N-mode size should be a multiple of 8 between 8 and 256 for M=64,\
|
| 137 |
+
or a multiple of 16 between 16 and 256 for M=128.");
|
| 138 |
+
static_assert(a_major == UMMA::Major::K, "SM100_MMA_TF32 A from TMEM can't be transposed");
|
| 139 |
+
|
| 140 |
+
using DRegisters = void;
|
| 141 |
+
using ARegisters = uint32_t[1];
|
| 142 |
+
using BRegisters = uint64_t[1];
|
| 143 |
+
using CRegisters = uint32_t[1];
|
| 144 |
+
|
| 145 |
+
CUTE_HOST_DEVICE static void
|
| 146 |
+
fma(uint32_t const& tmem_a,
|
| 147 |
+
uint64_t const& desc_b,
|
| 148 |
+
uint32_t const& tmem_c,
|
| 149 |
+
uint32_t const& scaleC,
|
| 150 |
+
uint64_t const& idescE)
|
| 151 |
+
{
|
| 152 |
+
#if defined(CUTE_ARCH_TCGEN05_TF32_MMA_ENABLED)
|
| 153 |
+
uint32_t mask[4] = {0, 0, 0, 0};
|
| 154 |
+
if (cute::elect_one_sync()) {
|
| 155 |
+
asm volatile(
|
| 156 |
+
"{\n\t"
|
| 157 |
+
".reg .pred p;\n\t"
|
| 158 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 159 |
+
"tcgen05.mma.cta_group::1.kind::tf32 [%0], [%1], %2, %3, {%5, %6, %7, %8}, p; \n\t"
|
| 160 |
+
"}\n"
|
| 161 |
+
:
|
| 162 |
+
: "r"(tmem_c), "r"(tmem_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 163 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]));
|
| 164 |
+
}
|
| 165 |
+
#else
|
| 166 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_TF32_TS without CUTE_ARCH_TCGEN05_TF32_MMA_ENABLED");
|
| 167 |
+
#endif
|
| 168 |
+
}
|
| 169 |
+
};
|
| 170 |
+
|
| 171 |
+
template <class a_type, class b_type, class c_type,
|
| 172 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 173 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One,
|
| 174 |
+
UMMA::Saturate c_sat = UMMA::Saturate::False>
|
| 175 |
+
struct SM100_MMA_F16BF16_TS
|
| 176 |
+
{
|
| 177 |
+
static_assert(M == 64 || M == 128, "SM100_MMA_F16BF16 M-mode size should be 64 or 128 for 1 CTA cluster MMA.");
|
| 178 |
+
static_assert((M == 64 && (N % 8 == 0) && (8 <= N) && (N <= 256)) ||
|
| 179 |
+
(M == 128 && (N % 16 == 0) && (16 <= N) && (N <= 256)),
|
| 180 |
+
"SM100_MMA_F16BF16 N-mode size should be a multiple of 8 between 8 and 256 for M=64,\
|
| 181 |
+
or a multiple of 16 between 16 and 256 for M=128.");
|
| 182 |
+
static_assert(a_major == UMMA::Major::K, "SM100_MMA_F16BF16 A from TMEM can't be transposed");
|
| 183 |
+
|
| 184 |
+
using DRegisters = void;
|
| 185 |
+
using ARegisters = uint32_t[1];
|
| 186 |
+
using BRegisters = uint64_t[1];
|
| 187 |
+
using CRegisters = uint32_t[1];
|
| 188 |
+
|
| 189 |
+
CUTE_HOST_DEVICE static void
|
| 190 |
+
fma(uint32_t const& tmem_a,
|
| 191 |
+
uint64_t const& desc_b,
|
| 192 |
+
uint32_t const& tmem_c,
|
| 193 |
+
uint32_t const& scaleC,
|
| 194 |
+
uint64_t const& idescE)
|
| 195 |
+
{
|
| 196 |
+
#if defined(CUTE_ARCH_TCGEN05_F16F32_MMA_ENABLED)
|
| 197 |
+
uint32_t mask[4] = {0, 0, 0, 0};
|
| 198 |
+
if (cute::elect_one_sync()) {
|
| 199 |
+
asm volatile(
|
| 200 |
+
"{\n\t"
|
| 201 |
+
".reg .pred p;\n\t"
|
| 202 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 203 |
+
"tcgen05.mma.cta_group::1.kind::f16 [%0], [%1], %2, %3, {%5, %6, %7, %8}, p; \n\t"
|
| 204 |
+
"}\n"
|
| 205 |
+
:
|
| 206 |
+
: "r"(tmem_c), "r"(tmem_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 207 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]));
|
| 208 |
+
}
|
| 209 |
+
#else
|
| 210 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_F16BF16_TS without CUTE_ARCH_MMA_SM100A_ENABLED");
|
| 211 |
+
#endif
|
| 212 |
+
}
|
| 213 |
+
};
|
| 214 |
+
|
| 215 |
+
template <class a_type, class b_type, class c_type,
|
| 216 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major, uint32_t ScaleC,
|
| 217 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One>
|
| 218 |
+
struct SM100_MMA_F16BF16_SS_SCALED
|
| 219 |
+
{
|
| 220 |
+
static_assert(M == 64 || M == 128, "SM100_MMA_F16BF16_SS_SCALED M-mode size should be 64 or 128 for 1 CTA cluster MMA.");
|
| 221 |
+
static_assert((M == 64 && (N % 8 == 0) && (8 <= N) && (N <= 256)) ||
|
| 222 |
+
(M == 128 && (N % 16 == 0) && (16 <= N) && (N <= 256)),
|
| 223 |
+
"SM100_MMA_F16BF16_SS_SCALED N-mode size should be a multiple of 8 between 8 and 256 for M=64,\
|
| 224 |
+
or a multiple of 16 between 16 and 256 for M=128.");
|
| 225 |
+
|
| 226 |
+
using DRegisters = void;
|
| 227 |
+
using ARegisters = uint64_t[1];
|
| 228 |
+
using BRegisters = uint64_t[1];
|
| 229 |
+
using CRegisters = uint32_t[1];
|
| 230 |
+
|
| 231 |
+
CUTE_HOST_DEVICE static void
|
| 232 |
+
fma(uint64_t const& desc_a,
|
| 233 |
+
uint64_t const& desc_b,
|
| 234 |
+
uint32_t const& tmem_c,
|
| 235 |
+
uint32_t const& accumulate,
|
| 236 |
+
uint64_t const& idescE)
|
| 237 |
+
{
|
| 238 |
+
#if defined(CUTE_ARCH_TCGEN05_F16BF16_MMA_SCALED_ENABLED)
|
| 239 |
+
if (cute::elect_one_sync()) {
|
| 240 |
+
// ScaleC input should be a literal or compile time constant
|
| 241 |
+
uint32_t mask[4] = {0, 0, 0, 0};
|
| 242 |
+
asm volatile(
|
| 243 |
+
"{\n\t"
|
| 244 |
+
".reg .pred p;\n\t"
|
| 245 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 246 |
+
"tcgen05.mma.cta_group::1.kind::f16 [%0], %1, %2, %3, {%5, %6, %7, %8}, p, %9; \n\t"
|
| 247 |
+
"}\n"
|
| 248 |
+
:
|
| 249 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(accumulate),
|
| 250 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]), "n"(ScaleC));
|
| 251 |
+
}
|
| 252 |
+
#else
|
| 253 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_F16BF16_SS without CUTE_ARCH_TCGEN05_F16BF16_MMA_SCALED_ENABLED");
|
| 254 |
+
#endif
|
| 255 |
+
}
|
| 256 |
+
};
|
| 257 |
+
|
| 258 |
+
template <class a_type, class b_type, class c_type,
|
| 259 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major, uint32_t ScaleC,
|
| 260 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One,
|
| 261 |
+
UMMA::Saturate c_sat = UMMA::Saturate::False>
|
| 262 |
+
struct SM100_MMA_F16BF16_TS_SCALED
|
| 263 |
+
{
|
| 264 |
+
static_assert(M == 64 || M == 128, "SM100_MMA_F16BF16_TS_SCALED M-mode size should be 64 or 128 for 1 CTA cluster MMA.");
|
| 265 |
+
static_assert((M == 64 && (N % 8 == 0) && (8 <= N) && (N <= 256)) ||
|
| 266 |
+
(M == 128 && (N % 16 == 0) && (16 <= N) && (N <= 256)),
|
| 267 |
+
"SM100_MMA_F16BF16_TS_SCALED N-mode size should be a multiple of 8 between 8 and 256 for M=64,\
|
| 268 |
+
or a multiple of 16 between 16 and 256 for M=128.");
|
| 269 |
+
static_assert(a_major == UMMA::Major::K, "SM100_MMA_F16BF16_TS_SCALED A from TMEM can't be transposed");
|
| 270 |
+
|
| 271 |
+
using DRegisters = void;
|
| 272 |
+
using ARegisters = uint32_t[1];
|
| 273 |
+
using BRegisters = uint64_t[1];
|
| 274 |
+
using CRegisters = uint32_t[1];
|
| 275 |
+
|
| 276 |
+
CUTE_HOST_DEVICE static void
|
| 277 |
+
fma(uint32_t const& tmem_a,
|
| 278 |
+
uint64_t const& desc_b,
|
| 279 |
+
uint32_t const& tmem_c,
|
| 280 |
+
uint32_t const& accumulate,
|
| 281 |
+
uint64_t const& idescE)
|
| 282 |
+
{
|
| 283 |
+
#if defined(CUTE_ARCH_TCGEN05_F16BF16_MMA_SCALED_ENABLED)
|
| 284 |
+
if (cute::elect_one_sync()) {
|
| 285 |
+
// ScaleC input should be a literal or compile time constant
|
| 286 |
+
uint32_t mask[4] = {0, 0, 0, 0};
|
| 287 |
+
asm volatile(
|
| 288 |
+
"{\n\t"
|
| 289 |
+
".reg .pred p;\n\t"
|
| 290 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 291 |
+
"tcgen05.mma.cta_group::1.kind::f16 [%0], [%1], %2, %3, {%5, %6, %7, %8}, p, %9; \n\t"
|
| 292 |
+
"}\n"
|
| 293 |
+
:
|
| 294 |
+
: "r"(tmem_c), "r"(tmem_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(accumulate),
|
| 295 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]), "n"(ScaleC));
|
| 296 |
+
}
|
| 297 |
+
#else
|
| 298 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_F16BF16_TS_SCALED without CUTE_ARCH_TCGEN05_F16BF16_MMA_SCALED_ENABLED");
|
| 299 |
+
#endif
|
| 300 |
+
}
|
| 301 |
+
};
|
| 302 |
+
|
| 303 |
+
template <class a_type, class b_type, class c_type,
|
| 304 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 305 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One>
|
| 306 |
+
struct SM100_MMA_TF32_SS_SPARSE
|
| 307 |
+
{
|
| 308 |
+
static_assert(M == 64 || M == 128, "SM100_MMA_TF32_SS_SPARSE M-mode size should be 64 or 128 for 1 CTA cluster MMA.");
|
| 309 |
+
static_assert((M == 64 && (N % 8 == 0) && (8 <= N) && (N <= 256)) ||
|
| 310 |
+
(M == 128 && (N % 16 == 0) && (16 <= N) && (N <= 256)),
|
| 311 |
+
"SM100_MMA_TF32_SS_SPARSE N-mode size should be a multiple of 8 between 8 and 256 for M=64,\
|
| 312 |
+
or a multiple of 16 between 16 and 256 for M=128.");
|
| 313 |
+
|
| 314 |
+
using DRegisters = void;
|
| 315 |
+
using ARegisters = uint64_t[1];
|
| 316 |
+
using BRegisters = uint64_t[1];
|
| 317 |
+
using CRegisters = uint32_t[1];
|
| 318 |
+
|
| 319 |
+
CUTE_HOST_DEVICE static void
|
| 320 |
+
fma(uint64_t const& desc_a,
|
| 321 |
+
uint64_t const& desc_b,
|
| 322 |
+
uint32_t const& tmem_c,
|
| 323 |
+
uint32_t const& scaleC,
|
| 324 |
+
uint64_t const& idescE,
|
| 325 |
+
uint32_t const& tmem_e)
|
| 326 |
+
{
|
| 327 |
+
#if defined(CUTE_ARCH_TCGEN05_TF32_MMA_ENABLED)
|
| 328 |
+
if (cute::elect_one_sync()) {
|
| 329 |
+
uint32_t mask[4] = {0, 0, 0, 0};
|
| 330 |
+
asm volatile(
|
| 331 |
+
"{\n\t"
|
| 332 |
+
".reg .pred p;\n\t"
|
| 333 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 334 |
+
"tcgen05.mma.sp.cta_group::1.kind::tf32 [%0], %1, %2, [%9], %3, {%5, %6, %7, %8}, p; \n\t"
|
| 335 |
+
"}\n"
|
| 336 |
+
:
|
| 337 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 338 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]), "r"(tmem_e));
|
| 339 |
+
}
|
| 340 |
+
#else
|
| 341 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_TF32_SS_SPARSE without CUTE_ARCH_TCGEN05_TF32_MMA_ENABLED");
|
| 342 |
+
#endif
|
| 343 |
+
}
|
| 344 |
+
};
|
| 345 |
+
|
| 346 |
+
template <class a_type, class b_type, class c_type,
|
| 347 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 348 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One>
|
| 349 |
+
struct SM100_MMA_F16BF16_SS_SPARSE
|
| 350 |
+
{
|
| 351 |
+
static_assert(M == 64 || M == 128, "SM100_MMA_F16BF16_SS_SPARSE M-mode size should be 64 or 128 for 1 CTA cluster MMA.");
|
| 352 |
+
static_assert((M == 64 && (N % 8 == 0) && (8 <= N) && (N <= 256)) ||
|
| 353 |
+
(M == 128 && (N % 16 == 0) && (16 <= N) && (N <= 256)),
|
| 354 |
+
"SM100_MMA_F16BF16_SS_SPARSE N-mode size should be a multiple of 8 between 8 and 256 for M=64,\
|
| 355 |
+
or a multiple of 16 between 16 and 256 for M=128.");
|
| 356 |
+
|
| 357 |
+
using DRegisters = void;
|
| 358 |
+
using ARegisters = uint64_t[1];
|
| 359 |
+
using BRegisters = uint64_t[1];
|
| 360 |
+
using CRegisters = uint32_t[1];
|
| 361 |
+
|
| 362 |
+
CUTE_HOST_DEVICE static void
|
| 363 |
+
fma(uint64_t const& desc_a,
|
| 364 |
+
uint64_t const& desc_b,
|
| 365 |
+
uint32_t const& tmem_c,
|
| 366 |
+
uint32_t const& scaleC,
|
| 367 |
+
uint64_t const& idescE,
|
| 368 |
+
uint32_t const& tmem_e)
|
| 369 |
+
{
|
| 370 |
+
#if defined(CUTE_ARCH_TCGEN05_F16F32_MMA_ENABLED)
|
| 371 |
+
if (cute::elect_one_sync()) {
|
| 372 |
+
uint32_t mask[4] = {0, 0, 0, 0};
|
| 373 |
+
asm volatile(
|
| 374 |
+
"{\n\t"
|
| 375 |
+
".reg .pred p;\n\t"
|
| 376 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 377 |
+
"tcgen05.mma.sp.cta_group::1.kind::f16 [%0], %1, %2, [%9], %3, {%5, %6, %7, %8}, p; \n\t"
|
| 378 |
+
"}\n"
|
| 379 |
+
:
|
| 380 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 381 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]), "r"(tmem_e));
|
| 382 |
+
}
|
| 383 |
+
#else
|
| 384 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_F16BF16_SS_SPARSE without CUTE_ARCH_TCGEN05_F16F32_MMA_ENABLED");
|
| 385 |
+
#endif
|
| 386 |
+
}
|
| 387 |
+
};
|
| 388 |
+
|
| 389 |
+
template <class a_type, class b_type, class c_type,
|
| 390 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 391 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One>
|
| 392 |
+
struct SM100_MMA_TF32_2x1SM_SS
|
| 393 |
+
{
|
| 394 |
+
static_assert(M == 128 || M == 256, "SM100_MMA_TF32_2x1SM_SS M-mode size should be 128 or 256 for 2 CTA cluster MMA.");
|
| 395 |
+
static_assert((N % 32 == 0) && (32 <= N) && (N <= 256), "SM100_MMA_TF32_2x1SM_SS N-mode size should be a multiple of 32 between 32 and 256.");
|
| 396 |
+
|
| 397 |
+
using DRegisters = void;
|
| 398 |
+
using ARegisters = uint64_t[1];
|
| 399 |
+
using BRegisters = uint64_t[1];
|
| 400 |
+
using CRegisters = uint32_t[1];
|
| 401 |
+
|
| 402 |
+
CUTE_HOST_DEVICE static void
|
| 403 |
+
fma(uint64_t const& desc_a,
|
| 404 |
+
uint64_t const& desc_b,
|
| 405 |
+
uint32_t const& tmem_c,
|
| 406 |
+
uint32_t const& scaleC,
|
| 407 |
+
uint64_t const& idescE)
|
| 408 |
+
{
|
| 409 |
+
#if defined(CUTE_ARCH_TCGEN05_TF32_MMA_ENABLED)
|
| 410 |
+
if (cute::elect_one_sync()) {
|
| 411 |
+
uint32_t mask[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
| 412 |
+
asm volatile(
|
| 413 |
+
"{\n\t"
|
| 414 |
+
".reg .pred p;\n\t"
|
| 415 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 416 |
+
"tcgen05.mma.cta_group::2.kind::tf32 [%0], %1, %2, %3, {%5, %6, %7, %8, %9, %10, %11, %12}, p; \n\t"
|
| 417 |
+
"}\n"
|
| 418 |
+
:
|
| 419 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 420 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]),
|
| 421 |
+
"r"(mask[4]), "r"(mask[5]), "r"(mask[6]), "r"(mask[7]));
|
| 422 |
+
}
|
| 423 |
+
#else
|
| 424 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_TF32_2x1SM_SS without CUTE_ARCH_TCGEN05_TF32_MMA_ENABLED");
|
| 425 |
+
#endif
|
| 426 |
+
}
|
| 427 |
+
};
|
| 428 |
+
|
| 429 |
+
template <class a_type, class b_type, class c_type,
|
| 430 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 431 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One>
|
| 432 |
+
struct SM100_MMA_F16BF16_2x1SM_SS
|
| 433 |
+
{
|
| 434 |
+
static_assert(M == 128 || M == 256, "SM100_MMA_F16BF16_2x1SM_SS M-mode size should be 128 or 256 for 2 CTA cluster MMA.");
|
| 435 |
+
static_assert((N % 32 == 0) && (32 <= N) && (N <= 256), "SM100_MMA_F16BF16_2x1SM_SS N-mode size should be a multiple of 32 between 32 and 256.");
|
| 436 |
+
|
| 437 |
+
using DRegisters = void;
|
| 438 |
+
using ARegisters = uint64_t[1];
|
| 439 |
+
using BRegisters = uint64_t[1];
|
| 440 |
+
using CRegisters = uint32_t[1];
|
| 441 |
+
|
| 442 |
+
CUTE_HOST_DEVICE static void
|
| 443 |
+
fma(uint64_t const& desc_a,
|
| 444 |
+
uint64_t const& desc_b,
|
| 445 |
+
uint32_t const& tmem_c,
|
| 446 |
+
uint32_t const& scaleC,
|
| 447 |
+
uint64_t const& idescE)
|
| 448 |
+
{
|
| 449 |
+
#if defined(CUTE_ARCH_TCGEN05_F16F32_MMA_ENABLED)
|
| 450 |
+
if (cute::elect_one_sync()) {
|
| 451 |
+
uint32_t mask[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
| 452 |
+
asm volatile(
|
| 453 |
+
"{\n\t"
|
| 454 |
+
".reg .pred p;\n\t"
|
| 455 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 456 |
+
"tcgen05.mma.cta_group::2.kind::f16 [%0], %1, %2, %3, {%5, %6, %7, %8, %9, %10, %11, %12}, p; \n\t"
|
| 457 |
+
"}\n"
|
| 458 |
+
:
|
| 459 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 460 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]),
|
| 461 |
+
"r"(mask[4]), "r"(mask[5]), "r"(mask[6]), "r"(mask[7]));
|
| 462 |
+
}
|
| 463 |
+
#else
|
| 464 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_F16BF16_2x1SM_SS without CUTE_ARCH_TCGEN05_F16F32_MMA_ENABLED");
|
| 465 |
+
#endif
|
| 466 |
+
}
|
| 467 |
+
};
|
| 468 |
+
|
| 469 |
+
template <class a_type, class b_type, class c_type,
|
| 470 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 471 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One,
|
| 472 |
+
UMMA::Saturate c_sat = UMMA::Saturate::False>
|
| 473 |
+
struct SM100_MMA_TF32_2x1SM_TS
|
| 474 |
+
{
|
| 475 |
+
static_assert(M == 128 || M == 256, "SM100_MMA_TF32_2x1SM_TS M-mode size should be 128 or 256 for 2 CTA cluster MMA.");
|
| 476 |
+
static_assert((N % 32 == 0) && (32 <= N) && (N <= 256), "SM100_MMA_TF32_2x1SM_TS N-mode size should be a multiple of 32 between 32 and 256.");
|
| 477 |
+
static_assert(a_major == UMMA::Major::K, "SM100_MMA_TF32_2x1SM_TS A from TMEM can't be transposed");
|
| 478 |
+
|
| 479 |
+
using DRegisters = void;
|
| 480 |
+
using ARegisters = uint32_t[1];
|
| 481 |
+
using BRegisters = uint64_t[1];
|
| 482 |
+
using CRegisters = uint32_t[1];
|
| 483 |
+
|
| 484 |
+
CUTE_HOST_DEVICE static void
|
| 485 |
+
fma(uint32_t const& tmem_a,
|
| 486 |
+
uint64_t const& desc_b,
|
| 487 |
+
uint32_t const& tmem_c,
|
| 488 |
+
uint32_t const& scaleC,
|
| 489 |
+
uint64_t const& idescE)
|
| 490 |
+
{
|
| 491 |
+
#if defined(CUTE_ARCH_TCGEN05_TF32_MMA_ENABLED)
|
| 492 |
+
if (cute::elect_one_sync()) {
|
| 493 |
+
uint32_t mask[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
| 494 |
+
asm volatile(
|
| 495 |
+
"{\n\t"
|
| 496 |
+
".reg .pred p;\n\t"
|
| 497 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 498 |
+
"tcgen05.mma.cta_group::2.kind::tf32 [%0], [%1], %2, %3, {%5, %6, %7, %8, %9, %10, %11, %12}, p; \n\t"
|
| 499 |
+
"}\n"
|
| 500 |
+
:
|
| 501 |
+
: "r"(tmem_c), "r"(tmem_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 502 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]),
|
| 503 |
+
"r"(mask[4]), "r"(mask[5]), "r"(mask[6]), "r"(mask[7]));
|
| 504 |
+
}
|
| 505 |
+
#else
|
| 506 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_TF32_2x1SM_TS without CUTE_ARCH_TCGEN05_TF32_MMA_ENABLED");
|
| 507 |
+
#endif
|
| 508 |
+
}
|
| 509 |
+
};
|
| 510 |
+
|
| 511 |
+
template <class a_type, class b_type, class c_type,
|
| 512 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 513 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One,
|
| 514 |
+
UMMA::Saturate c_sat = UMMA::Saturate::False>
|
| 515 |
+
struct SM100_MMA_F16BF16_2x1SM_TS
|
| 516 |
+
{
|
| 517 |
+
static_assert(M == 128 || M == 256, "SM100_MMA_F16BF16_2x1SM_TS M-mode size should be 128 or 256 for 2 CTA cluster MMA.");
|
| 518 |
+
static_assert((N % 32 == 0) && (32 <= N) && (N <= 256), "SM100_MMA_F16BF16_2x1SM_TS N-mode size should be a multiple of 32 between 32 and 256.");
|
| 519 |
+
static_assert(a_major == UMMA::Major::K, "SM100_MMA_F16BF16_2x1SM_TS A from TMEM can't be transposed");
|
| 520 |
+
|
| 521 |
+
using DRegisters = void;
|
| 522 |
+
using ARegisters = uint32_t[1];
|
| 523 |
+
using BRegisters = uint64_t[1];
|
| 524 |
+
using CRegisters = uint32_t[1];
|
| 525 |
+
|
| 526 |
+
CUTE_HOST_DEVICE static void
|
| 527 |
+
fma(uint32_t const& tmem_a,
|
| 528 |
+
uint64_t const& desc_b,
|
| 529 |
+
uint32_t const& tmem_c,
|
| 530 |
+
uint32_t const& scaleC,
|
| 531 |
+
uint64_t const& idescE)
|
| 532 |
+
{
|
| 533 |
+
#if defined(CUTE_ARCH_TCGEN05_F16F32_MMA_ENABLED)
|
| 534 |
+
if (cute::elect_one_sync()) {
|
| 535 |
+
uint32_t mask[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
| 536 |
+
asm volatile(
|
| 537 |
+
"{\n\t"
|
| 538 |
+
".reg .pred p;\n\t"
|
| 539 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 540 |
+
"tcgen05.mma.cta_group::2.kind::f16 [%0], [%1], %2, %3, {%5, %6, %7, %8, %9, %10, %11, %12}, p; \n\t"
|
| 541 |
+
"}\n"
|
| 542 |
+
:
|
| 543 |
+
: "r"(tmem_c), "r"(tmem_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 544 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]),
|
| 545 |
+
"r"(mask[4]), "r"(mask[5]), "r"(mask[6]), "r"(mask[7]));
|
| 546 |
+
}
|
| 547 |
+
#else
|
| 548 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_F16BF16_2x1SM_TS without CUTE_ARCH_TCGEN05_F16F32_MMA_ENABLED");
|
| 549 |
+
#endif
|
| 550 |
+
}
|
| 551 |
+
};
|
| 552 |
+
|
| 553 |
+
template <class a_type, class b_type, class c_type,
|
| 554 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major, uint32_t ScaleC,
|
| 555 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One>
|
| 556 |
+
struct SM100_MMA_F16BF16_2x1SM_SS_SCALED
|
| 557 |
+
{
|
| 558 |
+
static_assert(M == 128 || M == 256, "SM100_MMA_F16BF16_2x1SM_SS_SCALED M-mode size should be 128 or 256 for 2 CTA cluster MMA.");
|
| 559 |
+
static_assert((N % 32 == 0) && (32 <= N) && (N <= 256), "SM100_MMA_F16BF16_2x1SM_SS_SCALED N-mode size should be a multiple of 32 between 32 and 256.");
|
| 560 |
+
|
| 561 |
+
using DRegisters = void;
|
| 562 |
+
using ARegisters = uint64_t[1];
|
| 563 |
+
using BRegisters = uint64_t[1];
|
| 564 |
+
using CRegisters = uint32_t[1];
|
| 565 |
+
|
| 566 |
+
CUTE_HOST_DEVICE static void
|
| 567 |
+
fma(uint64_t const& desc_a,
|
| 568 |
+
uint64_t const& desc_b,
|
| 569 |
+
uint32_t const& tmem_c,
|
| 570 |
+
uint32_t const& accumulate,
|
| 571 |
+
uint64_t const& idescE)
|
| 572 |
+
{
|
| 573 |
+
#if defined(CUTE_ARCH_TCGEN05_F16BF16_MMA_SCALED_ENABLED)
|
| 574 |
+
if (cute::elect_one_sync()) {
|
| 575 |
+
// ScaleC input should be a literal or compile time constant
|
| 576 |
+
uint32_t mask[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
| 577 |
+
asm volatile(
|
| 578 |
+
"{\n\t"
|
| 579 |
+
".reg .pred p;\n\t"
|
| 580 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 581 |
+
"tcgen05.mma.cta_group::2.kind::f16 [%0], %1, %2, %3, {%5, %6, %7, %8, %9, %10, %11, %12}, p, %13; \n\t"
|
| 582 |
+
"}\n"
|
| 583 |
+
:
|
| 584 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(accumulate),
|
| 585 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]),
|
| 586 |
+
"r"(mask[4]), "r"(mask[5]), "r"(mask[6]), "r"(mask[7]), "n"(ScaleC));
|
| 587 |
+
}
|
| 588 |
+
#else
|
| 589 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_F16BF16_2x1SM_SS_SCALED without CUTE_ARCH_TCGEN05_F16BF16_MMA_SCALED_ENABLED");
|
| 590 |
+
#endif
|
| 591 |
+
}
|
| 592 |
+
};
|
| 593 |
+
|
| 594 |
+
template <class a_type, class b_type, class c_type,
|
| 595 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major, uint32_t ScaleC,
|
| 596 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One,
|
| 597 |
+
UMMA::Saturate c_sat = UMMA::Saturate::False>
|
| 598 |
+
struct SM100_MMA_F16BF16_2x1SM_TS_SCALED
|
| 599 |
+
{
|
| 600 |
+
static_assert(M == 128 || M == 256, "SM100_MMA_F16BF16_2x1SM_TS_SCALED M-mode size should be 128 or 256 for 2 CTA cluster MMA.");
|
| 601 |
+
static_assert((N % 32 == 0) && (32 <= N) && (N <= 256), "SM100_MMA_F16BF16_2x1SM_TS_SCALED N-mode size should be a multiple of 32 between 32 and 256.");
|
| 602 |
+
static_assert(a_major == UMMA::Major::K, "SM100_MMA_F16BF16_2x1SM_TS_SCALED A from TMEM can't be transposed");
|
| 603 |
+
|
| 604 |
+
using DRegisters = void;
|
| 605 |
+
using ARegisters = uint32_t[1];
|
| 606 |
+
using BRegisters = uint64_t[1];
|
| 607 |
+
using CRegisters = uint32_t[1];
|
| 608 |
+
|
| 609 |
+
CUTE_HOST_DEVICE static void
|
| 610 |
+
fma(uint32_t const& tmem_a,
|
| 611 |
+
uint64_t const& desc_b,
|
| 612 |
+
uint32_t const& tmem_c,
|
| 613 |
+
uint32_t const& accumulate,
|
| 614 |
+
uint64_t idescE)
|
| 615 |
+
{
|
| 616 |
+
#if defined(CUTE_ARCH_TCGEN05_F16BF16_MMA_SCALED_ENABLED)
|
| 617 |
+
if (cute::elect_one_sync()) {
|
| 618 |
+
// ScaleC input should be a literal or compile time constant
|
| 619 |
+
uint32_t mask[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
| 620 |
+
asm volatile(
|
| 621 |
+
"{\n\t"
|
| 622 |
+
".reg .pred p;\n\t"
|
| 623 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 624 |
+
"tcgen05.mma.cta_group::2.kind::f16 [%0], [%1], %2, %3, {%5, %6, %7, %8, %9, %10, %11, %12}, p, %13; \n\t"
|
| 625 |
+
"}\n"
|
| 626 |
+
:
|
| 627 |
+
: "r"(tmem_c), "r"(tmem_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(accumulate),
|
| 628 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]),
|
| 629 |
+
"r"(mask[4]), "r"(mask[5]), "r"(mask[6]), "r"(mask[7]), "n"(ScaleC));
|
| 630 |
+
}
|
| 631 |
+
#else
|
| 632 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_F16BF16_2x1SM_TS_SCALED without CUTE_ARCH_TCGEN05_F16BF16_MMA_SCALED_ENABLED");
|
| 633 |
+
#endif
|
| 634 |
+
}
|
| 635 |
+
};
|
| 636 |
+
|
| 637 |
+
template <class a_type, class b_type, class c_type,
|
| 638 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 639 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One>
|
| 640 |
+
struct SM100_MMA_TF32_2x1SM_SS_SPARSE
|
| 641 |
+
{
|
| 642 |
+
static_assert(M == 128 || M == 256, "SM100_MMA_TF32_2x1SM_SS_SPARSE M-mode size should be 128 or 256 for 2 CTA cluster MMA.");
|
| 643 |
+
static_assert((N % 32 == 0) && (32 <= N) && (N <= 256), "SM100_MMA_TF32_2x1SM_SS_SPARSE N-mode size should be a multiple of 32 between 32 and 256.");
|
| 644 |
+
|
| 645 |
+
using DRegisters = void;
|
| 646 |
+
using ARegisters = uint64_t[1];
|
| 647 |
+
using BRegisters = uint64_t[1];
|
| 648 |
+
using CRegisters = uint32_t[1];
|
| 649 |
+
|
| 650 |
+
CUTE_HOST_DEVICE static void
|
| 651 |
+
fma(uint64_t const& desc_a,
|
| 652 |
+
uint64_t const& desc_b,
|
| 653 |
+
uint32_t const& tmem_c,
|
| 654 |
+
uint32_t const& scaleC,
|
| 655 |
+
uint64_t const& idescE,
|
| 656 |
+
uint32_t const& tmem_e)
|
| 657 |
+
{
|
| 658 |
+
#if defined(CUTE_ARCH_TCGEN05_TF32_MMA_ENABLED)
|
| 659 |
+
if (cute::elect_one_sync()) {
|
| 660 |
+
uint32_t mask[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
| 661 |
+
asm volatile(
|
| 662 |
+
"{\n\t"
|
| 663 |
+
".reg .pred p;\n\t"
|
| 664 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 665 |
+
"tcgen05.mma.sp.cta_group::2.kind::tf32 [%0], %1, %2, [%13], %3, {%5, %6, %7, %8, %9, %10, %11, %12}, p; \n\t"
|
| 666 |
+
"}\n"
|
| 667 |
+
:
|
| 668 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 669 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]),
|
| 670 |
+
"r"(mask[4]), "r"(mask[5]), "r"(mask[6]), "r"(mask[7]), "r"(tmem_e));
|
| 671 |
+
}
|
| 672 |
+
#else
|
| 673 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_TF32_2x1SM_SS_SPARSE without CUTE_ARCH_TCGEN05_TF32_MMA_ENABLED");
|
| 674 |
+
#endif
|
| 675 |
+
}
|
| 676 |
+
};
|
| 677 |
+
|
| 678 |
+
template <class a_type, class b_type, class c_type,
|
| 679 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 680 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One>
|
| 681 |
+
struct SM100_MMA_F16BF16_2x1SM_SS_SPARSE
|
| 682 |
+
{
|
| 683 |
+
static_assert(M == 128 || M == 256, "SM100_MMA_F16BF16_2x1SM_SS_SPARSE M-mode size should be 128 or 256 for 2 CTA cluster MMA.");
|
| 684 |
+
static_assert((N % 32 == 0) && (32 <= N) && (N <= 256), "SM100_MMA_F16BF16_2x1SM_SS_SPARSE N-mode size should be a multiple of 32 between 32 and 256.");
|
| 685 |
+
|
| 686 |
+
using DRegisters = void;
|
| 687 |
+
using ARegisters = uint64_t[1];
|
| 688 |
+
using BRegisters = uint64_t[1];
|
| 689 |
+
using CRegisters = uint32_t[1];
|
| 690 |
+
|
| 691 |
+
CUTE_HOST_DEVICE static void
|
| 692 |
+
fma(uint64_t const& desc_a,
|
| 693 |
+
uint64_t const& desc_b,
|
| 694 |
+
uint32_t const& tmem_c,
|
| 695 |
+
uint32_t const& scaleC,
|
| 696 |
+
uint64_t const& idescE,
|
| 697 |
+
uint32_t const& tmem_e)
|
| 698 |
+
{
|
| 699 |
+
#if defined(CUTE_ARCH_TCGEN05_F16F32_MMA_ENABLED)
|
| 700 |
+
if (cute::elect_one_sync()) {
|
| 701 |
+
uint32_t mask[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
| 702 |
+
asm volatile(
|
| 703 |
+
"{\n\t"
|
| 704 |
+
".reg .pred p;\n\t"
|
| 705 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 706 |
+
"tcgen05.mma.sp.cta_group::2.kind::f16 [%0], %1, %2, [%13], %3, {%5, %6, %7, %8, %9, %10, %11, %12}, p; \n\t"
|
| 707 |
+
"}\n"
|
| 708 |
+
:
|
| 709 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 710 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]),
|
| 711 |
+
"r"(mask[4]), "r"(mask[5]), "r"(mask[6]), "r"(mask[7]), "r"(tmem_e));
|
| 712 |
+
}
|
| 713 |
+
#else
|
| 714 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_F16BF16_2x1SM_SS_SPARSE without CUTE_ARCH_TCGEN05_F16F32_MMA_ENABLED");
|
| 715 |
+
#endif
|
| 716 |
+
}
|
| 717 |
+
};
|
| 718 |
+
|
| 719 |
+
template <class a_type, class b_type, class c_type,
|
| 720 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 721 |
+
UMMA::Saturate c_sat = UMMA::Saturate::False>
|
| 722 |
+
struct SM100_MMA_S8_SS
|
| 723 |
+
{
|
| 724 |
+
static_assert(is_same_v<c_type, int32_t>, "SM100_MMA_S8_SS result type can only be int32_t.");
|
| 725 |
+
static_assert(M == 64 || M == 128, "SM100_MMA_S8_SS M-mode size should be 64 or 128 for 1 CTA cluster MMA.");
|
| 726 |
+
static_assert(N == 8 || ((N % 16 == 0) && (16 <= N) && (N <= 256)), "SM100_MMA_S8_SS N-mode size should be 8 or a multiple of 16 between 16 and 256.");
|
| 727 |
+
|
| 728 |
+
using DRegisters = void;
|
| 729 |
+
using ARegisters = uint64_t[1];
|
| 730 |
+
using BRegisters = uint64_t[1];
|
| 731 |
+
using CRegisters = uint32_t[1];
|
| 732 |
+
|
| 733 |
+
CUTE_HOST_DEVICE static void
|
| 734 |
+
fma(uint64_t const& desc_a,
|
| 735 |
+
uint64_t const& desc_b,
|
| 736 |
+
uint32_t const& tmem_c,
|
| 737 |
+
uint32_t const& scaleC,
|
| 738 |
+
uint64_t const& idescE)
|
| 739 |
+
{
|
| 740 |
+
#if defined(CUTE_ARCH_TCGEN05_S8_MMA_ENABLED)
|
| 741 |
+
if (cute::elect_one_sync()) {
|
| 742 |
+
uint32_t mask[4] = {0, 0, 0, 0};
|
| 743 |
+
asm volatile(
|
| 744 |
+
"{\n\t"
|
| 745 |
+
".reg .pred p;\n\t"
|
| 746 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 747 |
+
"tcgen05.mma.cta_group::1.kind::i8 [%0], %1, %2, %3, {%5, %6, %7, %8}, p; \n\t"
|
| 748 |
+
"}\n"
|
| 749 |
+
:
|
| 750 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 751 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]));
|
| 752 |
+
}
|
| 753 |
+
#else
|
| 754 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_S8_SS without CUTE_ARCH_TCGEN05_S8_MMA_ENABLED");
|
| 755 |
+
#endif
|
| 756 |
+
}
|
| 757 |
+
};
|
| 758 |
+
|
| 759 |
+
template <class a_type, class b_type, class c_type,
|
| 760 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 761 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One,
|
| 762 |
+
UMMA::Saturate c_sat = UMMA::Saturate::False>
|
| 763 |
+
struct SM100_MMA_S8_TS
|
| 764 |
+
{
|
| 765 |
+
static_assert(M == 64 || M == 128, "SM100_MMA_S8_TS M-mode size should be 64 or 128 for 1 CTA cluster MMA.");
|
| 766 |
+
static_assert(N == 8 || ((N % 16 == 0) && (16 <= N) && (N <= 256)), "SM100_MMA_S8_TS N-mode size should be 8 or a multiple of 16 between 16 and 256.");
|
| 767 |
+
static_assert(a_major == UMMA::Major::K, "SM100_MMA_S8_TS A from TMEM can't be transposed");
|
| 768 |
+
|
| 769 |
+
using DRegisters = void;
|
| 770 |
+
using ARegisters = uint32_t[1];
|
| 771 |
+
using BRegisters = uint64_t[1];
|
| 772 |
+
using CRegisters = uint32_t[1];
|
| 773 |
+
|
| 774 |
+
CUTE_HOST_DEVICE static void
|
| 775 |
+
fma(uint32_t const& tmem_a,
|
| 776 |
+
uint64_t const& desc_b,
|
| 777 |
+
uint32_t const& tmem_c,
|
| 778 |
+
uint32_t const& scaleC,
|
| 779 |
+
uint64_t const& idescE)
|
| 780 |
+
{
|
| 781 |
+
#if defined(CUTE_ARCH_TCGEN05_S8_MMA_ENABLED)
|
| 782 |
+
if (cute::elect_one_sync()) {
|
| 783 |
+
uint32_t mask[4] = {0, 0, 0, 0};
|
| 784 |
+
asm volatile(
|
| 785 |
+
"{\n\t"
|
| 786 |
+
".reg .pred p;\n\t"
|
| 787 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 788 |
+
"tcgen05.mma.cta_group::1.kind::i8 [%0], [%1], %2, %3, {%5, %6, %7, %8}, p; \n\t"
|
| 789 |
+
"}\n"
|
| 790 |
+
:
|
| 791 |
+
: "r"(tmem_c), "r"(tmem_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 792 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]));
|
| 793 |
+
}
|
| 794 |
+
#else
|
| 795 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_S8_TS without CUTE_ARCH_TCGEN05_S8_MMA_ENABLED");
|
| 796 |
+
#endif
|
| 797 |
+
}
|
| 798 |
+
};
|
| 799 |
+
|
| 800 |
+
template <class a_type, class b_type, class c_type,
|
| 801 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 802 |
+
UMMA::Saturate c_sat = UMMA::Saturate::False>
|
| 803 |
+
struct SM100_MMA_S8_SS_SPARSE
|
| 804 |
+
{
|
| 805 |
+
static_assert(is_same_v<c_type, int32_t>, "SM100_MMA_S8_SS_SPARSE result type can only be int32_t.");
|
| 806 |
+
static_assert(M == 64 || M == 128, "SM100_MMA_S8_SS_SPARSE M-mode size should be 64 or 128 for 1 CTA cluster MMA.");
|
| 807 |
+
static_assert(N == 8 || ((N % 16 == 0) && (16 <= N) && (N <= 256)), "SM100_MMA_S8_SS_SPARSE N-mode size should be 8 or a multiple of 16 between 16 and 256.");
|
| 808 |
+
|
| 809 |
+
using DRegisters = void;
|
| 810 |
+
using ARegisters = uint64_t[1];
|
| 811 |
+
using BRegisters = uint64_t[1];
|
| 812 |
+
using CRegisters = uint32_t[1];
|
| 813 |
+
|
| 814 |
+
CUTE_HOST_DEVICE static void
|
| 815 |
+
fma(uint64_t const& desc_a,
|
| 816 |
+
uint64_t const& desc_b,
|
| 817 |
+
uint32_t const& tmem_c,
|
| 818 |
+
uint32_t const& scaleC,
|
| 819 |
+
uint64_t const& idescE,
|
| 820 |
+
uint32_t const& tmem_e)
|
| 821 |
+
{
|
| 822 |
+
#if defined(CUTE_ARCH_TCGEN05_S8_MMA_ENABLED)
|
| 823 |
+
if (cute::elect_one_sync()) {
|
| 824 |
+
uint32_t mask[4] = {0, 0, 0, 0};
|
| 825 |
+
asm volatile(
|
| 826 |
+
"{\n\t"
|
| 827 |
+
".reg .pred p;\n\t"
|
| 828 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 829 |
+
"tcgen05.mma.sp.cta_group::1.kind::i8 [%0], %1, %2, [%9], %3, {%5, %6, %7, %8}, p; \n\t"
|
| 830 |
+
"}\n"
|
| 831 |
+
:
|
| 832 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 833 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]), "r"(tmem_e));
|
| 834 |
+
}
|
| 835 |
+
#else
|
| 836 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_S8_SS_SPARSE without CUTE_ARCH_TCGEN05_S8_MMA_ENABLED");
|
| 837 |
+
#endif
|
| 838 |
+
}
|
| 839 |
+
};
|
| 840 |
+
|
| 841 |
+
template <class a_type, class b_type, class c_type,
|
| 842 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 843 |
+
UMMA::Saturate c_sat = UMMA::Saturate::False>
|
| 844 |
+
struct SM100_MMA_S8_2x1SM_SS
|
| 845 |
+
{
|
| 846 |
+
static_assert(M == 128 || M == 256, "SM100_MMA_S8_2x1SM_SS M-mode size should be 128 or 256 for 2 CTA cluster MMA.");
|
| 847 |
+
static_assert((N % 32 == 0) && (32 <= N) && (N <= 256), "SM100_MMA_S8_2x1SM_SS N-mode size should be a multiple of 32 between 32 and 256.");
|
| 848 |
+
|
| 849 |
+
using DRegisters = void;
|
| 850 |
+
using ARegisters = uint64_t[1];
|
| 851 |
+
using BRegisters = uint64_t[1];
|
| 852 |
+
using CRegisters = uint32_t[1];
|
| 853 |
+
|
| 854 |
+
CUTE_HOST_DEVICE static void
|
| 855 |
+
fma(uint64_t const& desc_a,
|
| 856 |
+
uint64_t const& desc_b,
|
| 857 |
+
uint32_t const& tmem_c,
|
| 858 |
+
uint32_t const& scaleC,
|
| 859 |
+
uint64_t const& idescE)
|
| 860 |
+
{
|
| 861 |
+
#if defined(CUTE_ARCH_TCGEN05_S8_MMA_ENABLED)
|
| 862 |
+
if (cute::elect_one_sync()) {
|
| 863 |
+
uint32_t mask[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
| 864 |
+
asm volatile(
|
| 865 |
+
"{\n\t"
|
| 866 |
+
".reg .pred p;\n\t"
|
| 867 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 868 |
+
"tcgen05.mma.cta_group::2.kind::i8 [%0], %1, %2, %3, {%5, %6, %7, %8, %9, %10, %11, %12}, p; \n\t"
|
| 869 |
+
"}\n"
|
| 870 |
+
:
|
| 871 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 872 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]),
|
| 873 |
+
"r"(mask[4]), "r"(mask[5]), "r"(mask[6]), "r"(mask[7]));
|
| 874 |
+
}
|
| 875 |
+
#else
|
| 876 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_S8_2x1SM_SS without CUTE_ARCH_TCGEN05_S8_MMA_ENABLED");
|
| 877 |
+
#endif
|
| 878 |
+
}
|
| 879 |
+
};
|
| 880 |
+
|
| 881 |
+
template <class a_type, class b_type, class c_type,
|
| 882 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 883 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One,
|
| 884 |
+
UMMA::Saturate c_sat = UMMA::Saturate::False>
|
| 885 |
+
struct SM100_MMA_S8_2x1SM_TS
|
| 886 |
+
{
|
| 887 |
+
static_assert(M == 128 || M == 256, "SM100_MMA_S8_2x1SM_TS M-mode size should be 128 or 256 for 2 CTA cluster MMA.");
|
| 888 |
+
static_assert((N % 32 == 0) && (32 <= N) && (N <= 256), "SM100_MMA_S8_2x1SM_TS N-mode size should be a multiple of 32 between 32 and 256.");
|
| 889 |
+
static_assert(a_major == UMMA::Major::K, "SM100_MMA_S8_2x1SM_TS A from TMEM can't be transposed");
|
| 890 |
+
|
| 891 |
+
using DRegisters = void;
|
| 892 |
+
using ARegisters = uint32_t[1];
|
| 893 |
+
using BRegisters = uint64_t[1];
|
| 894 |
+
using CRegisters = uint32_t[1];
|
| 895 |
+
|
| 896 |
+
CUTE_HOST_DEVICE static void
|
| 897 |
+
fma(uint32_t const& tmem_a,
|
| 898 |
+
uint64_t const& desc_b,
|
| 899 |
+
uint32_t const& tmem_c,
|
| 900 |
+
uint32_t const& scaleC,
|
| 901 |
+
uint64_t const& idescE)
|
| 902 |
+
{
|
| 903 |
+
#if defined(CUTE_ARCH_TCGEN05_S8_MMA_ENABLED)
|
| 904 |
+
if (cute::elect_one_sync()) {
|
| 905 |
+
uint32_t mask[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
| 906 |
+
asm volatile(
|
| 907 |
+
"{\n\t"
|
| 908 |
+
".reg .pred p;\n\t"
|
| 909 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 910 |
+
"tcgen05.mma.cta_group::2.kind::i8 [%0], [%1], %2, %3, {%5, %6, %7, %8, %9, %10, %11, %12}, p; \n\t"
|
| 911 |
+
"}\n"
|
| 912 |
+
:
|
| 913 |
+
: "r"(tmem_c), "r"(tmem_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 914 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]),
|
| 915 |
+
"r"(mask[4]), "r"(mask[5]), "r"(mask[6]), "r"(mask[7]));
|
| 916 |
+
}
|
| 917 |
+
#else
|
| 918 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_S8_2x1SM_TS without CUTE_ARCH_TCGEN05_S8_MMA_ENABLED");
|
| 919 |
+
#endif
|
| 920 |
+
}
|
| 921 |
+
};
|
| 922 |
+
|
| 923 |
+
template <class a_type, class b_type, class c_type,
|
| 924 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 925 |
+
UMMA::Saturate c_sat = UMMA::Saturate::False>
|
| 926 |
+
struct SM100_MMA_S8_2x1SM_SS_SPARSE
|
| 927 |
+
{
|
| 928 |
+
static_assert(M == 128 || M == 256, "SM100_MMA_S8 M-mode size should be 128 or 256 for 2 CTA cluster MMA.");
|
| 929 |
+
static_assert((N % 32 == 0) && (32 <= N) && (N <= 256), "SM100_MMA_S8 N-mode size should be a multiple of 32 between 32 and 256.");
|
| 930 |
+
|
| 931 |
+
using DRegisters = void;
|
| 932 |
+
using ARegisters = uint64_t[1];
|
| 933 |
+
using BRegisters = uint64_t[1];
|
| 934 |
+
using CRegisters = uint32_t[1];
|
| 935 |
+
|
| 936 |
+
CUTE_HOST_DEVICE static void
|
| 937 |
+
fma(uint64_t const& desc_a,
|
| 938 |
+
uint64_t const& desc_b,
|
| 939 |
+
uint32_t const& tmem_c,
|
| 940 |
+
uint32_t const& scaleC,
|
| 941 |
+
uint64_t const& idescE,
|
| 942 |
+
uint32_t const& tmem_e)
|
| 943 |
+
{
|
| 944 |
+
#if defined(CUTE_ARCH_TCGEN05_S8_MMA_ENABLED)
|
| 945 |
+
if (cute::elect_one_sync()) {
|
| 946 |
+
uint32_t mask[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
| 947 |
+
asm volatile(
|
| 948 |
+
"{\n\t"
|
| 949 |
+
".reg .pred p;\n\t"
|
| 950 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 951 |
+
"tcgen05.mma.sp.cta_group::2.kind::i8 [%0], %1, %2, [%13], %3, {%5, %6, %7, %8, %9, %10, %11, %12}, p; \n\t"
|
| 952 |
+
"}\n"
|
| 953 |
+
:
|
| 954 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 955 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]),
|
| 956 |
+
"r"(mask[4]), "r"(mask[5]), "r"(mask[6]), "r"(mask[7]), "r"(tmem_e));
|
| 957 |
+
}
|
| 958 |
+
#else
|
| 959 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_S8_2x1SM_SS_SPARSE without CUTE_ARCH_TCGEN05_S8_MMA_ENABLED");
|
| 960 |
+
#endif
|
| 961 |
+
}
|
| 962 |
+
};
|
| 963 |
+
|
| 964 |
+
struct SM100_MMA_F8F6F4_SS
|
| 965 |
+
{
|
| 966 |
+
using DRegisters = void;
|
| 967 |
+
using ARegisters = uint64_t[1];
|
| 968 |
+
using BRegisters = uint64_t[1];
|
| 969 |
+
using CRegisters = uint32_t[1];
|
| 970 |
+
|
| 971 |
+
CUTE_HOST_DEVICE static void
|
| 972 |
+
fma(uint64_t const& desc_a,
|
| 973 |
+
uint64_t const& desc_b,
|
| 974 |
+
uint32_t const& tmem_c,
|
| 975 |
+
uint32_t const& scaleC,
|
| 976 |
+
uint64_t const& idescE)
|
| 977 |
+
{
|
| 978 |
+
#if defined(CUTE_ARCH_TCGEN05_MXF8F6F4_MMA_ENABLED)
|
| 979 |
+
if (cute::elect_one_sync()) {
|
| 980 |
+
uint32_t mask[4] = {0, 0, 0, 0};
|
| 981 |
+
asm volatile(
|
| 982 |
+
"{\n\t"
|
| 983 |
+
".reg .pred p;\n\t"
|
| 984 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 985 |
+
"tcgen05.mma.cta_group::1.kind::f8f6f4 [%0], %1, %2, %3, {%5, %6, %7, %8}, p; \n\t"
|
| 986 |
+
"}\n"
|
| 987 |
+
:
|
| 988 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 989 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]));
|
| 990 |
+
}
|
| 991 |
+
#else
|
| 992 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_F8F6F4_SS without CUTE_ARCH_TCGEN05_MXF8F6F4_MMA_ENABLED");
|
| 993 |
+
#endif
|
| 994 |
+
}
|
| 995 |
+
};
|
| 996 |
+
|
| 997 |
+
template <class a_type, class b_type, class c_type, class sf_type,
|
| 998 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 999 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One>
|
| 1000 |
+
struct SM100_MMA_MXF8F6F4_SS
|
| 1001 |
+
{
|
| 1002 |
+
static_assert(M == 128, "SM100_MMA_MXF8F6F4_SS M-mode size should be 64 or 128 for 1 CTA cluster MMA.");
|
| 1003 |
+
static_assert((N % 8 == 0) && (8 <= N) && (N <= 256), "SM100_MMA_MXF8F6F4_SS N-mode size should be a multiple of 8 between 8 and 256.");
|
| 1004 |
+
|
| 1005 |
+
using DRegisters = void;
|
| 1006 |
+
using ARegisters = uint64_t[1];
|
| 1007 |
+
using BRegisters = uint64_t[1];
|
| 1008 |
+
using CRegisters = uint32_t[1];
|
| 1009 |
+
using SFARegisters = uint32_t[1];
|
| 1010 |
+
using SFBRegisters = uint32_t[1];
|
| 1011 |
+
|
| 1012 |
+
CUTE_HOST_DEVICE static void
|
| 1013 |
+
fma(uint64_t const& desc_a,
|
| 1014 |
+
uint64_t const& desc_b,
|
| 1015 |
+
uint32_t const& tmem_c,
|
| 1016 |
+
uint32_t const& scaleC,
|
| 1017 |
+
uint64_t const& idescE,
|
| 1018 |
+
uint32_t const& tsfa_addr,
|
| 1019 |
+
uint32_t const& tsfb_addr)
|
| 1020 |
+
{
|
| 1021 |
+
#if defined(CUTE_ARCH_TCGEN05_MXF8F6F4_MMA_ENABLED)
|
| 1022 |
+
if (cute::elect_one_sync()) {
|
| 1023 |
+
asm volatile(
|
| 1024 |
+
"{\n\t"
|
| 1025 |
+
".reg .pred p;\n\t"
|
| 1026 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 1027 |
+
"tcgen05.mma.cta_group::1.kind::mxf8f6f4.block_scale [%0], %1, %2, %3, [%5], [%6], p; \n\t"
|
| 1028 |
+
"}\n"
|
| 1029 |
+
:
|
| 1030 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC), "r"(tsfa_addr), "r"(tsfb_addr));
|
| 1031 |
+
}
|
| 1032 |
+
#else
|
| 1033 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_F8F6F4_SS without CUTE_ARCH_TCGEN05_MXF8F6F4_MMA_ENABLED");
|
| 1034 |
+
#endif
|
| 1035 |
+
}
|
| 1036 |
+
};
|
| 1037 |
+
|
| 1038 |
+
template <class a_type, class b_type, class c_type,
|
| 1039 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 1040 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One,
|
| 1041 |
+
UMMA::Saturate c_sat = UMMA::Saturate::False>
|
| 1042 |
+
struct SM100_MMA_F8F6F4_TS
|
| 1043 |
+
{
|
| 1044 |
+
static_assert(M == 64 || M == 128, "SM100_MMA_F8F6F4_TS M-mode size should be 64 or 128 for 1 CTA cluster MMA.");
|
| 1045 |
+
static_assert((M == 64 && (N % 8 == 0) && (8 <= N) && (N <= 256)) ||
|
| 1046 |
+
(M == 128 && (N % 16 == 0) && (16 <= N) && (N <= 256)),
|
| 1047 |
+
"SM100_MMA_F8F6F4_TS N-mode size should be a multiple of 8 between 8 and 256 for M=64,\
|
| 1048 |
+
or a multiple of 16 between 16 and 256 for M=128.");
|
| 1049 |
+
static_assert(a_major == UMMA::Major::K, "SM100_MMA_F8F6F4_TS A from TMEM can't be transposed");
|
| 1050 |
+
|
| 1051 |
+
using DRegisters = void;
|
| 1052 |
+
using ARegisters = uint32_t[1];
|
| 1053 |
+
using BRegisters = uint64_t[1];
|
| 1054 |
+
using CRegisters = uint32_t[1];
|
| 1055 |
+
|
| 1056 |
+
CUTE_HOST_DEVICE static void
|
| 1057 |
+
fma(uint32_t const& tmem_a,
|
| 1058 |
+
uint64_t const& desc_b,
|
| 1059 |
+
uint32_t const& tmem_c,
|
| 1060 |
+
uint32_t const& scaleC,
|
| 1061 |
+
uint64_t const& idescE)
|
| 1062 |
+
{
|
| 1063 |
+
#if defined(CUTE_ARCH_TCGEN05_MXF8F6F4_MMA_ENABLED)
|
| 1064 |
+
if (cute::elect_one_sync()) {
|
| 1065 |
+
uint32_t mask[4] = {0, 0, 0, 0};
|
| 1066 |
+
asm volatile(
|
| 1067 |
+
"{\n\t"
|
| 1068 |
+
".reg .pred p;\n\t"
|
| 1069 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 1070 |
+
"tcgen05.mma.cta_group::1.kind::f8f6f4 [%0], [%1], %2, %3, {%5, %6, %7, %8}, p; \n\t"
|
| 1071 |
+
"}\n"
|
| 1072 |
+
:
|
| 1073 |
+
: "r"(tmem_c), "r"(tmem_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 1074 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]));
|
| 1075 |
+
}
|
| 1076 |
+
#else
|
| 1077 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_F8F6F4_TS without CUTE_ARCH_TCGEN05_MXF8F6F4_MMA_ENABLED");
|
| 1078 |
+
#endif
|
| 1079 |
+
}
|
| 1080 |
+
};
|
| 1081 |
+
|
| 1082 |
+
template <class a_type, class b_type, class c_type,
|
| 1083 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 1084 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One,
|
| 1085 |
+
UMMA::Saturate c_sat = UMMA::Saturate::False>
|
| 1086 |
+
struct SM100_MMA_F8F6F4_2x1SM_TS
|
| 1087 |
+
{
|
| 1088 |
+
static_assert(M == 128 || M == 256, "SM100_MMA_F8F6F4_2x1SM_TS M-mode size should be 64 or 128 for 1 CTA cluster MMA.");
|
| 1089 |
+
static_assert((N % 32 == 0) && (32 <= N) && (N <= 256), "SM100_MMA_F8F6F4_2x1SM_TS N-mode size should be a multiple of 32 between 32 and 256.");
|
| 1090 |
+
static_assert(a_major == UMMA::Major::K, "SM100_MMA_F8F6F4_2x1SM_TS A from TMEM can't be transposed");
|
| 1091 |
+
|
| 1092 |
+
using DRegisters = void;
|
| 1093 |
+
using ARegisters = uint32_t[1];
|
| 1094 |
+
using BRegisters = uint64_t[1];
|
| 1095 |
+
using CRegisters = uint32_t[1];
|
| 1096 |
+
|
| 1097 |
+
CUTE_HOST_DEVICE static void
|
| 1098 |
+
fma(uint32_t const& tmem_a,
|
| 1099 |
+
uint64_t const& desc_b,
|
| 1100 |
+
uint32_t const& tmem_c,
|
| 1101 |
+
uint32_t const& scaleC,
|
| 1102 |
+
uint64_t const& idescE)
|
| 1103 |
+
{
|
| 1104 |
+
#if defined(CUTE_ARCH_TCGEN05_MXF8F6F4_MMA_ENABLED)
|
| 1105 |
+
if (cute::elect_one_sync()) {
|
| 1106 |
+
uint32_t mask[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
| 1107 |
+
asm volatile(
|
| 1108 |
+
"{\n\t"
|
| 1109 |
+
".reg .pred p;\n\t"
|
| 1110 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 1111 |
+
"tcgen05.mma.cta_group::2.kind::f8f6f4 [%0], [%1], %2, %3, {%5, %6, %7, %8, %9, %10, %11, %12}, p; \n\t"
|
| 1112 |
+
"}\n"
|
| 1113 |
+
:
|
| 1114 |
+
: "r"(tmem_c), "r"(tmem_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 1115 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]),
|
| 1116 |
+
"r"(mask[4]), "r"(mask[5]), "r"(mask[6]), "r"(mask[7]));
|
| 1117 |
+
}
|
| 1118 |
+
#else
|
| 1119 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_F8F6F4_TS without CUTE_ARCH_TCGEN05_MXF8F6F4_MMA_ENABLED");
|
| 1120 |
+
#endif
|
| 1121 |
+
}
|
| 1122 |
+
};
|
| 1123 |
+
|
| 1124 |
+
template <class a_type, class b_type, class c_type,
|
| 1125 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 1126 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One>
|
| 1127 |
+
struct SM100_MMA_F8F6F4_SS_SPARSE
|
| 1128 |
+
{
|
| 1129 |
+
static_assert(M == 64 || M == 128, "SM100_MMA_F8F6F4_SS_SPARSE M-mode size should be 64 or 128 for 1 CTA cluster MMA.");
|
| 1130 |
+
static_assert((M == 64 && (N % 8 == 0) && (8 <= N) && (N <= 256)) ||
|
| 1131 |
+
(M == 128 && (N % 16 == 0) && (16 <= N) && (N <= 256)),
|
| 1132 |
+
"SM100_MMA_F8F6F4_SS_SPARSE N-mode size should be a multiple of 8 between 8 and 256 for M=64,\
|
| 1133 |
+
or a multiple of 16 between 16 and 256 for M=128.");
|
| 1134 |
+
|
| 1135 |
+
using DRegisters = void;
|
| 1136 |
+
using ARegisters = uint64_t[1];
|
| 1137 |
+
using BRegisters = uint64_t[1];
|
| 1138 |
+
using CRegisters = uint32_t[1];
|
| 1139 |
+
|
| 1140 |
+
CUTE_HOST_DEVICE static void
|
| 1141 |
+
fma(uint64_t const& desc_a,
|
| 1142 |
+
uint64_t const& desc_b,
|
| 1143 |
+
uint32_t const& tmem_c,
|
| 1144 |
+
uint32_t const& scaleC,
|
| 1145 |
+
uint64_t const& idescE,
|
| 1146 |
+
uint32_t const& tmem_e)
|
| 1147 |
+
{
|
| 1148 |
+
#if defined(CUTE_ARCH_TCGEN05_MXF8F6F4_MMA_ENABLED)
|
| 1149 |
+
if (cute::elect_one_sync()) {
|
| 1150 |
+
uint32_t mask[4] = {0, 0, 0, 0}; // %5, %6, %7, %8
|
| 1151 |
+
asm volatile(
|
| 1152 |
+
"{\n\t"
|
| 1153 |
+
".reg .pred p;\n\t"
|
| 1154 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 1155 |
+
"tcgen05.mma.sp.cta_group::1.kind::f8f6f4 [%0], %1, %2, [%9], %3, {%5, %6, %7, %8}, p; \n\t"
|
| 1156 |
+
"}\n"
|
| 1157 |
+
:
|
| 1158 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 1159 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]), "r"(tmem_e));
|
| 1160 |
+
}
|
| 1161 |
+
#else
|
| 1162 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_F8F6F4_SS_SPARSE without CUTE_ARCH_TCGEN05_MXF8F6F4_MMA_ENABLED");
|
| 1163 |
+
#endif
|
| 1164 |
+
}
|
| 1165 |
+
};
|
| 1166 |
+
|
| 1167 |
+
template <class a_type, class b_type, class c_type, class sf_type,
|
| 1168 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 1169 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One>
|
| 1170 |
+
struct SM100_MMA_MXF8F6F4_SS_SPARSE
|
| 1171 |
+
{
|
| 1172 |
+
static_assert(M == 128, "SM100_MMA_MXF8F6F4_SS_SPARSE M-mode size should be 128 for 1 CTA cluster MMA.");
|
| 1173 |
+
static_assert((N % 8 == 0) && (8 <= N) && (N <= 256), "SM100_MMA_MXF8F6F4_SS_SPARSE N-mode size should be a multiple of 8 between 8 and 256.");
|
| 1174 |
+
|
| 1175 |
+
using DRegisters = void;
|
| 1176 |
+
using ARegisters = uint64_t[1];
|
| 1177 |
+
using BRegisters = uint64_t[1];
|
| 1178 |
+
using CRegisters = uint32_t[1];
|
| 1179 |
+
using SFARegisters = uint32_t[1];
|
| 1180 |
+
using SFBRegisters = uint32_t[1];
|
| 1181 |
+
|
| 1182 |
+
CUTE_HOST_DEVICE static void
|
| 1183 |
+
fma(uint64_t const& desc_a,
|
| 1184 |
+
uint64_t const& desc_b,
|
| 1185 |
+
uint32_t const& tmem_c,
|
| 1186 |
+
uint32_t const& scaleC,
|
| 1187 |
+
uint64_t const& idescE,
|
| 1188 |
+
uint32_t const& tsfa_addr,
|
| 1189 |
+
uint32_t const& tsfb_addr,
|
| 1190 |
+
uint32_t const& tmem_e)
|
| 1191 |
+
{
|
| 1192 |
+
#if defined(CUTE_ARCH_TCGEN05_MXF8F6F4_MMA_ENABLED)
|
| 1193 |
+
if (cute::elect_one_sync()) {
|
| 1194 |
+
asm volatile(
|
| 1195 |
+
"{\n\t"
|
| 1196 |
+
".reg .pred p;\n\t"
|
| 1197 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 1198 |
+
"tcgen05.mma.sp.cta_group::1.kind::mxf8f6f4.block_scale [%0], %1, %2, [%7], %3, [%5], [%6], p; \n\t"
|
| 1199 |
+
"}\n"
|
| 1200 |
+
:
|
| 1201 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC), "r"(tsfa_addr), "r"(tsfb_addr), "r"(tmem_e));
|
| 1202 |
+
}
|
| 1203 |
+
#else
|
| 1204 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_MXF8F6F4_SS_SPARSE without CUTE_ARCH_TCGEN05_MXF8F6F4_MMA_ENABLED");
|
| 1205 |
+
#endif
|
| 1206 |
+
}
|
| 1207 |
+
};
|
| 1208 |
+
|
| 1209 |
+
struct SM100_MMA_F8F6F4_2x1SM_SS
|
| 1210 |
+
{
|
| 1211 |
+
using DRegisters = void;
|
| 1212 |
+
using ARegisters = uint64_t[1];
|
| 1213 |
+
using BRegisters = uint64_t[1];
|
| 1214 |
+
using CRegisters = uint32_t[1];
|
| 1215 |
+
|
| 1216 |
+
CUTE_HOST_DEVICE static void
|
| 1217 |
+
fma(uint64_t const& desc_a,
|
| 1218 |
+
uint64_t const& desc_b,
|
| 1219 |
+
uint32_t const& tmem_c,
|
| 1220 |
+
uint32_t const& scaleC,
|
| 1221 |
+
uint64_t const& idescE)
|
| 1222 |
+
{
|
| 1223 |
+
#if defined(CUTE_ARCH_TCGEN05_MXF8F6F4_MMA_ENABLED)
|
| 1224 |
+
if (cute::elect_one_sync()) {
|
| 1225 |
+
uint32_t mask[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
| 1226 |
+
asm volatile(
|
| 1227 |
+
"{\n\t"
|
| 1228 |
+
".reg .pred p;\n\t"
|
| 1229 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 1230 |
+
"tcgen05.mma.cta_group::2.kind::f8f6f4 [%0], %1, %2, %3, {%5, %6, %7, %8, %9, %10, %11, %12}, p; \n\t"
|
| 1231 |
+
"}\n"
|
| 1232 |
+
:
|
| 1233 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 1234 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]),
|
| 1235 |
+
"r"(mask[4]), "r"(mask[5]), "r"(mask[6]), "r"(mask[7]));
|
| 1236 |
+
}
|
| 1237 |
+
#else
|
| 1238 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_F8F6F4_2x1SM_SS without CUTE_ARCH_TCGEN05_MXF8F6F4_MMA_ENABLED");
|
| 1239 |
+
#endif
|
| 1240 |
+
}
|
| 1241 |
+
};
|
| 1242 |
+
|
| 1243 |
+
template <class a_type, class b_type, class c_type, class sf_type,
|
| 1244 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 1245 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One>
|
| 1246 |
+
struct SM100_MMA_MXF8F6F4_2x1SM_SS_SPARSE
|
| 1247 |
+
{
|
| 1248 |
+
static_assert(M == 256, "SM100_MMA_MXF8F6F4_2x1SM_SS_SPARSE M-mode size should be 256 for 2 CTA cluster MMA.");
|
| 1249 |
+
static_assert((N % 16 == 0) && (16 <= N) && (N <= 256), "SM100_MMA_MXF8F6F4_2x1SM_SS_SPARSE N-mode size should be a multiple of 16 between 16 and 256.");
|
| 1250 |
+
|
| 1251 |
+
using DRegisters = void;
|
| 1252 |
+
using ARegisters = uint64_t[1];
|
| 1253 |
+
using BRegisters = uint64_t[1];
|
| 1254 |
+
using CRegisters = uint32_t[1];
|
| 1255 |
+
|
| 1256 |
+
CUTE_HOST_DEVICE static void
|
| 1257 |
+
fma(uint64_t const& desc_a,
|
| 1258 |
+
uint64_t const& desc_b,
|
| 1259 |
+
uint32_t const& tmem_c,
|
| 1260 |
+
uint32_t const& scaleC,
|
| 1261 |
+
uint64_t const& idescE,
|
| 1262 |
+
uint32_t const& tsfa_addr,
|
| 1263 |
+
uint32_t const& tsfb_addr,
|
| 1264 |
+
uint32_t const& tmem_e)
|
| 1265 |
+
{
|
| 1266 |
+
#if defined(CUTE_ARCH_TCGEN05_MXF8F6F4_MMA_ENABLED)
|
| 1267 |
+
if (cute::elect_one_sync()) {
|
| 1268 |
+
asm volatile(
|
| 1269 |
+
"{\n\t"
|
| 1270 |
+
".reg .pred p;\n\t"
|
| 1271 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 1272 |
+
"tcgen05.mma.sp.cta_group::2.kind::mxf8f6f4.block_scale [%0], %1, %2, [%7], %3, [%5], [%6], p; \n\t"
|
| 1273 |
+
"}\n"
|
| 1274 |
+
:
|
| 1275 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 1276 |
+
"r"(tsfa_addr), "r"(tsfb_addr), "r"(tmem_e));
|
| 1277 |
+
}
|
| 1278 |
+
#else
|
| 1279 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_MXF8F6F4_2x1SM_SS_SPARSE without CUTE_ARCH_TCGEN05_MXF8F6F4_MMA_ENABLED");
|
| 1280 |
+
#endif
|
| 1281 |
+
}
|
| 1282 |
+
};
|
| 1283 |
+
|
| 1284 |
+
template <class a_type, class b_type, class c_type, class sf_type,
|
| 1285 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 1286 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One>
|
| 1287 |
+
struct SM100_MMA_MXF8F6F4_2x1SM_SS
|
| 1288 |
+
{
|
| 1289 |
+
static_assert(M == 256, "SM100_MMA_MXF8F6F4_2x1SM_SS M-mode size should be 128 or 256 for 2 CTA cluster MMA.");
|
| 1290 |
+
static_assert((N % 16 == 0) && (16 <= N) && (N <= 256), "SM100_MMA_MXF8F6F4_2x1SM_SS N-mode size should be a multiple of 16 between 16 and 256.");
|
| 1291 |
+
|
| 1292 |
+
using DRegisters = void;
|
| 1293 |
+
using ARegisters = uint64_t[1];
|
| 1294 |
+
using BRegisters = uint64_t[1];
|
| 1295 |
+
using CRegisters = uint32_t[1];
|
| 1296 |
+
|
| 1297 |
+
CUTE_HOST_DEVICE static void
|
| 1298 |
+
fma(uint64_t const& desc_a,
|
| 1299 |
+
uint64_t const& desc_b,
|
| 1300 |
+
uint32_t const& tmem_c,
|
| 1301 |
+
uint32_t const& scaleC,
|
| 1302 |
+
uint64_t const& idescE,
|
| 1303 |
+
uint32_t const& tsfa_addr,
|
| 1304 |
+
uint32_t const& tsfb_addr)
|
| 1305 |
+
{
|
| 1306 |
+
#if defined(CUTE_ARCH_TCGEN05_MXF8F6F4_MMA_ENABLED)
|
| 1307 |
+
if (cute::elect_one_sync()) {
|
| 1308 |
+
asm volatile(
|
| 1309 |
+
"{\n\t"
|
| 1310 |
+
".reg .pred p;\n\t"
|
| 1311 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 1312 |
+
"tcgen05.mma.cta_group::2.kind::mxf8f6f4.block_scale [%0], %1, %2, %3, [%5], [%6], p; \n\t"
|
| 1313 |
+
"}\n"
|
| 1314 |
+
:
|
| 1315 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 1316 |
+
"r"(tsfa_addr), "r"(tsfb_addr));
|
| 1317 |
+
}
|
| 1318 |
+
#else
|
| 1319 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_MXF8F6F4_2x1SM_SS without CUTE_ARCH_TCGEN05_MXF8F6F4_MMA_ENABLED");
|
| 1320 |
+
#endif
|
| 1321 |
+
}
|
| 1322 |
+
};
|
| 1323 |
+
|
| 1324 |
+
template <class a_type, class b_type, class c_type,
|
| 1325 |
+
int M, int N, UMMA::Major a_major, UMMA::Major b_major,
|
| 1326 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One>
|
| 1327 |
+
struct SM100_MMA_F8F6F4_2x1SM_SS_SPARSE
|
| 1328 |
+
{
|
| 1329 |
+
static_assert(M == 128 || M == 256, "SM100_MMA_F8F6F4_2x1SM_SS_SPARSE M-mode size should be 128 or 256 for 2 CTA cluster MMA.");
|
| 1330 |
+
static_assert((N % 32 == 0) && (32 <= N) && (N <= 256), "SM100_MMA_F8F6F4_2x1SM_SS_SPARSE N-mode size should be a multiple of 32 between 32 and 256.");
|
| 1331 |
+
|
| 1332 |
+
using DRegisters = void;
|
| 1333 |
+
using ARegisters = uint64_t[1];
|
| 1334 |
+
using BRegisters = uint64_t[1];
|
| 1335 |
+
using CRegisters = uint32_t[1];
|
| 1336 |
+
|
| 1337 |
+
CUTE_HOST_DEVICE static void
|
| 1338 |
+
fma(uint64_t const& desc_a,
|
| 1339 |
+
uint64_t const& desc_b,
|
| 1340 |
+
uint32_t const& tmem_c,
|
| 1341 |
+
uint32_t const& scaleC,
|
| 1342 |
+
uint64_t const& idescE,
|
| 1343 |
+
uint32_t const& tmem_e)
|
| 1344 |
+
{
|
| 1345 |
+
#if defined(CUTE_ARCH_TCGEN05_MXF8F6F4_MMA_ENABLED)
|
| 1346 |
+
if (cute::elect_one_sync()) {
|
| 1347 |
+
uint32_t mask[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
| 1348 |
+
asm volatile(
|
| 1349 |
+
"{\n\t"
|
| 1350 |
+
".reg .pred p;\n\t"
|
| 1351 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 1352 |
+
"tcgen05.mma.sp.cta_group::2.kind::f8f6f4 [%0], %1, %2, [%13], %3, {%5, %6, %7, %8, %9, %10, %11, %12}, p; \n\t"
|
| 1353 |
+
"}\n"
|
| 1354 |
+
:
|
| 1355 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 1356 |
+
"r"(mask[0]), "r"(mask[1]), "r"(mask[2]), "r"(mask[3]),
|
| 1357 |
+
"r"(mask[4]), "r"(mask[5]), "r"(mask[6]), "r"(mask[7]), "r"(tmem_e));
|
| 1358 |
+
}
|
| 1359 |
+
#else
|
| 1360 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_F8F6F4_2x1SM_SS_SPARSE without CUTE_ARCH_TCGEN05_MXF8F6F4_MMA_ENABLED");
|
| 1361 |
+
#endif
|
| 1362 |
+
}
|
| 1363 |
+
};
|
| 1364 |
+
|
| 1365 |
+
template <class a_type, class b_type, class c_type, class sf_type,
|
| 1366 |
+
int M, int N, int VS, UMMA::Major a_major, UMMA::Major b_major,
|
| 1367 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One>
|
| 1368 |
+
struct SM100_MMA_MXF4_SS
|
| 1369 |
+
{
|
| 1370 |
+
static_assert(M == 128, "SM100_MMA_MXF4_SS M-mode size should be 128 for 1 CTA cluster MMA.");
|
| 1371 |
+
static_assert((N % 8 == 0) && (8 <= N) && (N <= 256), "SM100_MMA_MXF4_SS N-mode size should be a multiple of 8 between 8 and 256.");
|
| 1372 |
+
static_assert((VS == 16) || (VS == 32), "SM100_MMA_MXF4_SS Vector size can only be 16 or 32.");
|
| 1373 |
+
|
| 1374 |
+
using DRegisters = void;
|
| 1375 |
+
using ARegisters = uint64_t[1];
|
| 1376 |
+
using BRegisters = uint64_t[1];
|
| 1377 |
+
using CRegisters = uint32_t[1];
|
| 1378 |
+
using SFARegisters = uint32_t[1];
|
| 1379 |
+
using SFBRegisters = uint32_t[1];
|
| 1380 |
+
|
| 1381 |
+
CUTE_HOST_DEVICE static void
|
| 1382 |
+
fma(uint64_t const& desc_a,
|
| 1383 |
+
uint64_t const& desc_b,
|
| 1384 |
+
uint32_t const& tmem_c,
|
| 1385 |
+
uint32_t const& scaleC,
|
| 1386 |
+
uint64_t const& idescE,
|
| 1387 |
+
uint32_t const& tsfa_addr,
|
| 1388 |
+
uint32_t const& tsfb_addr)
|
| 1389 |
+
{
|
| 1390 |
+
if constexpr (VS == 16) {
|
| 1391 |
+
#if defined(CUTE_ARCH_TCGEN05_MXF4NVF4_MMA_ENABLED)
|
| 1392 |
+
if (cute::elect_one_sync()) {
|
| 1393 |
+
asm volatile(
|
| 1394 |
+
"{\n\t"
|
| 1395 |
+
".reg .pred p;\n\t"
|
| 1396 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 1397 |
+
"tcgen05.mma.cta_group::1.kind::mxf4nvf4.block_scale.scale_vec::4X [%0], %1, %2, %3, [%5], [%6], p; \n\t"
|
| 1398 |
+
"}\n"
|
| 1399 |
+
:
|
| 1400 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 1401 |
+
"r"(tsfa_addr), "r"(tsfb_addr));
|
| 1402 |
+
}
|
| 1403 |
+
#else
|
| 1404 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_MXF4_SS (VS = 16) without CUTE_ARCH_TCGEN05_MXF4NVF4_MMA_ENABLED");
|
| 1405 |
+
#endif
|
| 1406 |
+
}
|
| 1407 |
+
if constexpr (VS == 32) {
|
| 1408 |
+
#if defined(CUTE_ARCH_TCGEN05_MXF4_MMA_ENABLED)
|
| 1409 |
+
if (cute::elect_one_sync()) {
|
| 1410 |
+
asm volatile(
|
| 1411 |
+
"{\n\t"
|
| 1412 |
+
".reg .pred p;\n\t"
|
| 1413 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 1414 |
+
"tcgen05.mma.cta_group::1.kind::mxf4.block_scale.scale_vec::2X [%0], %1, %2, %3, [%5], [%6], p; \n\t"
|
| 1415 |
+
"}\n"
|
| 1416 |
+
:
|
| 1417 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 1418 |
+
"r"(tsfa_addr), "r"(tsfb_addr));
|
| 1419 |
+
}
|
| 1420 |
+
#else
|
| 1421 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_MXF4_SS (VS = 32) without CUTE_ARCH_TCGEN05_MXF4_MMA_ENABLED");
|
| 1422 |
+
#endif
|
| 1423 |
+
}
|
| 1424 |
+
}
|
| 1425 |
+
|
| 1426 |
+
};
|
| 1427 |
+
|
| 1428 |
+
template <class a_type, class b_type, class c_type, class sf_type,
|
| 1429 |
+
int M, int N, int VS, UMMA::Major a_major, UMMA::Major b_major,
|
| 1430 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One>
|
| 1431 |
+
struct SM100_MMA_MXF4NVF4_SS_SPARSE
|
| 1432 |
+
{
|
| 1433 |
+
static_assert(M == 128, "SM100_MMA_MXF4NVF4_SS_SPARSE M-mode size should be 128 for 1 CTA cluster MMA.");
|
| 1434 |
+
static_assert((N % 8 == 0) && (8 <= N) && (N <= 256), "SM100_MMA_MXF4NVF4_SS_SPARSE N-mode size should be a multiple of 8 between 8 and 256.");
|
| 1435 |
+
|
| 1436 |
+
using DRegisters = void;
|
| 1437 |
+
using ARegisters = uint64_t[1];
|
| 1438 |
+
using BRegisters = uint64_t[1];
|
| 1439 |
+
using CRegisters = uint32_t[1];
|
| 1440 |
+
using SFARegisters = uint32_t[1];
|
| 1441 |
+
using SFBRegisters = uint32_t[1];
|
| 1442 |
+
|
| 1443 |
+
CUTE_HOST_DEVICE static void
|
| 1444 |
+
fma(uint64_t const& desc_a,
|
| 1445 |
+
uint64_t const& desc_b,
|
| 1446 |
+
uint32_t const& tmem_c,
|
| 1447 |
+
uint32_t const& scaleC,
|
| 1448 |
+
uint64_t const& idescE,
|
| 1449 |
+
uint32_t const& tsfa_addr,
|
| 1450 |
+
uint32_t const& tsfb_addr,
|
| 1451 |
+
uint32_t const& tmem_e)
|
| 1452 |
+
{
|
| 1453 |
+
if constexpr (VS == 32) {
|
| 1454 |
+
#if defined(CUTE_ARCH_TCGEN05_MXF4NVF4_MMA_ENABLED)
|
| 1455 |
+
if (cute::elect_one_sync()) {
|
| 1456 |
+
asm volatile(
|
| 1457 |
+
"{\n\t"
|
| 1458 |
+
".reg .pred p;\n\t"
|
| 1459 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 1460 |
+
"tcgen05.mma.sp.cta_group::1.kind::mxf4nvf4.block_scale.scale_vec::4X [%0], %1, %2, [%7], %3, [%5], [%6], p; \n\t"
|
| 1461 |
+
"}\n"
|
| 1462 |
+
:
|
| 1463 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 1464 |
+
"r"(tsfa_addr), "r"(tsfb_addr), "r"(tmem_e));
|
| 1465 |
+
}
|
| 1466 |
+
#else
|
| 1467 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_MXF4NVF4_SS_SPARSE (VS = 32) without CUTE_ARCH_TCGEN05_MXF4NVF4_MMA_ENABLED");
|
| 1468 |
+
#endif
|
| 1469 |
+
}
|
| 1470 |
+
|
| 1471 |
+
if constexpr (VS == 64) {
|
| 1472 |
+
#if defined(CUTE_ARCH_TCGEN05_MXF4_MMA_ENABLED)
|
| 1473 |
+
if (cute::elect_one_sync()) {
|
| 1474 |
+
asm volatile(
|
| 1475 |
+
"{\n\t"
|
| 1476 |
+
".reg .pred p;\n\t"
|
| 1477 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 1478 |
+
"tcgen05.mma.sp.cta_group::1.kind::mxf4.block_scale.scale_vec::2X [%0], %1, %2, [%7], %3, [%5], [%6], p; \n\t"
|
| 1479 |
+
"}\n"
|
| 1480 |
+
:
|
| 1481 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 1482 |
+
"r"(tsfa_addr), "r"(tsfb_addr), "r"(tmem_e));
|
| 1483 |
+
}
|
| 1484 |
+
#else
|
| 1485 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_MXF4NVF4_SS_SPARSE (VS = 64) without CUTE_ARCH_TCGEN05_MXF4_MMA_ENABLED");
|
| 1486 |
+
#endif
|
| 1487 |
+
}
|
| 1488 |
+
}
|
| 1489 |
+
};
|
| 1490 |
+
|
| 1491 |
+
template <class a_type, class b_type, class c_type, class sf_type,
|
| 1492 |
+
int M, int N, int VS, UMMA::Major a_major, UMMA::Major b_major,
|
| 1493 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One>
|
| 1494 |
+
struct SM100_MMA_MXF4_2x1SM_SS
|
| 1495 |
+
{
|
| 1496 |
+
static_assert(M == 128 || M == 256, "SM100_MMA_MXF4_2x1SM_SS M-mode size should be 128 or 256 for 2 CTA cluster MMA.");
|
| 1497 |
+
static_assert((N % 16 == 0) && (16 <= N) && (N <= 256), "SM100_MMA_MXF4_2x1SM_SS N-mode size should be a multiple of 16 between 16 and 256.");
|
| 1498 |
+
static_assert((VS == 16) || (VS == 32), "SM100_MMA_MXF4_2x1SM_SS Vector size can only be 16 or 32.");
|
| 1499 |
+
|
| 1500 |
+
using DRegisters = void;
|
| 1501 |
+
using ARegisters = uint64_t[1];
|
| 1502 |
+
using BRegisters = uint64_t[1];
|
| 1503 |
+
using CRegisters = uint32_t[1];
|
| 1504 |
+
using SFARegisters = uint32_t[1];
|
| 1505 |
+
using SFBRegisters = uint32_t[1];
|
| 1506 |
+
|
| 1507 |
+
CUTE_HOST_DEVICE static void
|
| 1508 |
+
fma(uint64_t const& desc_a,
|
| 1509 |
+
uint64_t const& desc_b,
|
| 1510 |
+
uint32_t const& tmem_c,
|
| 1511 |
+
uint32_t const& scaleC,
|
| 1512 |
+
uint64_t const& idescE,
|
| 1513 |
+
uint32_t const& tsfa_addr,
|
| 1514 |
+
uint32_t const& tsfb_addr)
|
| 1515 |
+
{
|
| 1516 |
+
if constexpr (VS == 16) {
|
| 1517 |
+
#if defined(CUTE_ARCH_TCGEN05_MXF4NVF4_MMA_ENABLED)
|
| 1518 |
+
if (cute::elect_one_sync()) {
|
| 1519 |
+
asm volatile(
|
| 1520 |
+
"{\n\t"
|
| 1521 |
+
".reg .pred p;\n\t"
|
| 1522 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 1523 |
+
"tcgen05.mma.cta_group::2.kind::mxf4nvf4.block_scale.scale_vec::4X [%0], %1, %2, %3, [%5], [%6], p; \n\t"
|
| 1524 |
+
"}\n"
|
| 1525 |
+
:
|
| 1526 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 1527 |
+
"r"(tsfa_addr), "r"(tsfb_addr));
|
| 1528 |
+
}
|
| 1529 |
+
#else
|
| 1530 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_MXF4_2x1SM_SS (VS = 16) without CUTE_ARCH_TCGEN05_MXF4NVF4_MMA_ENABLED");
|
| 1531 |
+
#endif
|
| 1532 |
+
}
|
| 1533 |
+
if constexpr (VS == 32) {
|
| 1534 |
+
#if defined(CUTE_ARCH_TCGEN05_MXF4_MMA_ENABLED)
|
| 1535 |
+
if (cute::elect_one_sync()) {
|
| 1536 |
+
asm volatile(
|
| 1537 |
+
"{\n\t"
|
| 1538 |
+
".reg .pred p;\n\t"
|
| 1539 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 1540 |
+
"tcgen05.mma.cta_group::2.kind::mxf4.block_scale.scale_vec::2X [%0], %1, %2, %3, [%5], [%6], p; \n\t"
|
| 1541 |
+
"}\n"
|
| 1542 |
+
:
|
| 1543 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 1544 |
+
"r"(tsfa_addr), "r"(tsfb_addr));
|
| 1545 |
+
}
|
| 1546 |
+
#else
|
| 1547 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_MXF4_2x1SM_SS (VS = 32) without CUTE_ARCH_TCGEN05_MXF4_MMA_ENABLED");
|
| 1548 |
+
#endif
|
| 1549 |
+
}
|
| 1550 |
+
}
|
| 1551 |
+
};
|
| 1552 |
+
|
| 1553 |
+
template <class a_type, class b_type, class c_type, class sf_type,
|
| 1554 |
+
int M, int N, int VS, UMMA::Major a_major, UMMA::Major b_major,
|
| 1555 |
+
UMMA::ScaleIn a_neg = UMMA::ScaleIn::One, UMMA::ScaleIn b_neg = UMMA::ScaleIn::One>
|
| 1556 |
+
struct SM100_MMA_MXF4NVF4_2x1SM_SS_SPARSE
|
| 1557 |
+
{
|
| 1558 |
+
static_assert((N % 16 == 0) && (16 <= N) && (N <= 256), "SM100_MMA_MXF4NVF4_2x1SM_SS_SPARSE N-mode size should be a multiple of 16 between 16 and 256.");
|
| 1559 |
+
static_assert((VS == 32) || (VS == 64), "SM100_MMA_MXF4NVF4_2x1SM_SS_SPARSE Vector size can only be 32 or 64.");
|
| 1560 |
+
|
| 1561 |
+
using DRegisters = void;
|
| 1562 |
+
using ARegisters = uint64_t[1];
|
| 1563 |
+
using BRegisters = uint64_t[1];
|
| 1564 |
+
using CRegisters = uint32_t[1];
|
| 1565 |
+
using SFARegisters = uint32_t[1];
|
| 1566 |
+
using SFBRegisters = uint32_t[1];
|
| 1567 |
+
|
| 1568 |
+
CUTE_HOST_DEVICE static void
|
| 1569 |
+
fma(uint64_t const& desc_a,
|
| 1570 |
+
uint64_t const& desc_b,
|
| 1571 |
+
uint32_t const& tmem_c,
|
| 1572 |
+
uint32_t const& scaleC,
|
| 1573 |
+
uint64_t const& idescE,
|
| 1574 |
+
uint32_t const& tsfa_addr,
|
| 1575 |
+
uint32_t const& tsfb_addr,
|
| 1576 |
+
uint32_t const& tmem_e)
|
| 1577 |
+
{
|
| 1578 |
+
if constexpr (VS == 32) {
|
| 1579 |
+
#if defined(CUTE_ARCH_TCGEN05_MXF4NVF4_MMA_ENABLED)
|
| 1580 |
+
if (cute::elect_one_sync()) {
|
| 1581 |
+
asm volatile(
|
| 1582 |
+
"{\n\t"
|
| 1583 |
+
".reg .pred p;\n\t"
|
| 1584 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 1585 |
+
"tcgen05.mma.sp.cta_group::2.kind::mxf4nvf4.block_scale.scale_vec::4X [%0], %1, %2, [%7], %3, [%5], [%6], p; \n\t"
|
| 1586 |
+
"}\n"
|
| 1587 |
+
:
|
| 1588 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 1589 |
+
"r"(tsfa_addr), "r"(tsfb_addr), "r"(tmem_e));
|
| 1590 |
+
}
|
| 1591 |
+
#else
|
| 1592 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_MXF4NVF4_2x1SM_SS_SPARSE (VS = 32) without CUTE_ARCH_TCGEN05_MXF4NVF4_MMA_ENABLED");
|
| 1593 |
+
#endif
|
| 1594 |
+
}
|
| 1595 |
+
|
| 1596 |
+
if constexpr (VS == 64) {
|
| 1597 |
+
#if defined(CUTE_ARCH_TCGEN05_MXF4_MMA_ENABLED)
|
| 1598 |
+
if (cute::elect_one_sync()) {
|
| 1599 |
+
asm volatile(
|
| 1600 |
+
"{\n\t"
|
| 1601 |
+
".reg .pred p;\n\t"
|
| 1602 |
+
"setp.ne.b32 p, %4, 0;\n\t"
|
| 1603 |
+
"tcgen05.mma.sp.cta_group::2.kind::mxf4.block_scale.scale_vec::2X [%0], %1, %2, [%7], %3, [%5], [%6], p; \n\t"
|
| 1604 |
+
"}\n"
|
| 1605 |
+
:
|
| 1606 |
+
: "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(uint32_t(idescE>>32)), "r"(scaleC),
|
| 1607 |
+
"r"(tsfa_addr), "r"(tsfb_addr), "r"(tmem_e));
|
| 1608 |
+
}
|
| 1609 |
+
#else
|
| 1610 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM100_MMA_MXF4NVF4_2x1SM_SS_SPARSE (VS = 64) without CUTE_ARCH_TCGEN05_MXF4_MMA_ENABLED");
|
| 1611 |
+
#endif
|
| 1612 |
+
}
|
| 1613 |
+
}
|
| 1614 |
+
};
|
| 1615 |
+
|
| 1616 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm120.hpp
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm120_sparse.hpp
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm61.hpp
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
|
| 32 |
+
#pragma once
|
| 33 |
+
|
| 34 |
+
#include <cute/config.hpp>
|
| 35 |
+
#include <cute/arch/mma.hpp>
|
| 36 |
+
|
| 37 |
+
// Config
|
| 38 |
+
#if (defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 610))
|
| 39 |
+
# define CUTE_ARCH_MMA_SM61_ENABLED
|
| 40 |
+
#endif
|
| 41 |
+
|
| 42 |
+
namespace cute
|
| 43 |
+
{
|
| 44 |
+
|
| 45 |
+
struct SM61_DP4A
|
| 46 |
+
{
|
| 47 |
+
using DRegisters = int32_t[1];
|
| 48 |
+
using ARegisters = uint32_t[1];
|
| 49 |
+
using BRegisters = uint32_t[1];
|
| 50 |
+
using CRegisters = int32_t[1];
|
| 51 |
+
|
| 52 |
+
// Register asm fma
|
| 53 |
+
CUTE_HOST_DEVICE static void
|
| 54 |
+
fma(int32_t& d, uint32_t const& a, uint32_t const& b, int32_t const& c)
|
| 55 |
+
{
|
| 56 |
+
#if defined(CUTE_ARCH_MMA_SM61_ENABLED)
|
| 57 |
+
asm volatile("dp4a.s32.s32 %0, %1, %2, %3;"
|
| 58 |
+
: "=r"(d)
|
| 59 |
+
: "r"(a), "r"(b), "r"(c));
|
| 60 |
+
#else
|
| 61 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM61_DP4A without CUTE_ARCH_MMA_SM61_ENABLED");
|
| 62 |
+
#endif
|
| 63 |
+
}
|
| 64 |
+
};
|
| 65 |
+
|
| 66 |
+
struct SM61_DP2A
|
| 67 |
+
{
|
| 68 |
+
using DRegisters = int32_t[1];
|
| 69 |
+
using ARegisters = uint32_t[1];
|
| 70 |
+
using BRegisters = uint32_t[1];
|
| 71 |
+
using CRegisters = int32_t[1];
|
| 72 |
+
|
| 73 |
+
// Register asm fma
|
| 74 |
+
CUTE_HOST_DEVICE static void
|
| 75 |
+
fma(int32_t& d, uint32_t const& a, uint32_t const& b, int32_t const& c)
|
| 76 |
+
{
|
| 77 |
+
#if defined(CUTE_ARCH_MMA_SM61_ENABLED)
|
| 78 |
+
asm volatile("dp2a.s32.s32 %0, %1, %2, %3;"
|
| 79 |
+
: "=r"(d)
|
| 80 |
+
: "r"(a), "r"(b), "r"(c));
|
| 81 |
+
#else
|
| 82 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM61_DP2A without CUTE_ARCH_MMA_SM61_ENABLED");
|
| 83 |
+
#endif
|
| 84 |
+
}
|
| 85 |
+
};
|
| 86 |
+
|
| 87 |
+
} // namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm70.hpp
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/config.hpp>
|
| 34 |
+
|
| 35 |
+
#include <cute/arch/mma.hpp>
|
| 36 |
+
|
| 37 |
+
// Config
|
| 38 |
+
#if ((__CUDACC_VER_MAJOR__ > 10) || (__CUDACC_VER_MAJOR__ == 10 && __CUDACC_VER_MINOR__ >= 1))
|
| 39 |
+
# define CUTE_ARCH_MMA_SM70_SUPPORTED
|
| 40 |
+
# if (defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 700))
|
| 41 |
+
# define CUTE_ARCH_MMA_SM70_ENABLED
|
| 42 |
+
# endif
|
| 43 |
+
#endif
|
| 44 |
+
|
| 45 |
+
namespace cute
|
| 46 |
+
{
|
| 47 |
+
|
| 48 |
+
//
|
| 49 |
+
// SM70 MMA 884 F16F16F16
|
| 50 |
+
//
|
| 51 |
+
|
| 52 |
+
struct SM70_8x8x4_F16F16F16F16_TN
|
| 53 |
+
{
|
| 54 |
+
using DRegisters = uint32_t[4];
|
| 55 |
+
using ARegisters = uint32_t[2];
|
| 56 |
+
using BRegisters = uint32_t[2];
|
| 57 |
+
using CRegisters = uint32_t[4];
|
| 58 |
+
|
| 59 |
+
// Register asm fma
|
| 60 |
+
CUTE_HOST_DEVICE static void
|
| 61 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 62 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 63 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 64 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 65 |
+
{
|
| 66 |
+
#if defined(CUTE_ARCH_MMA_SM70_ENABLED)
|
| 67 |
+
asm volatile("mma.sync.aligned.m8n8k4.row.col.f16.f16.f16.f16"
|
| 68 |
+
"{%0, %1, %2, %3},"
|
| 69 |
+
"{%4, %5},"
|
| 70 |
+
"{%6, %7},"
|
| 71 |
+
"{%8, %9, %10, %11};\n"
|
| 72 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 73 |
+
: "r"(a0), "r"(a1),
|
| 74 |
+
"r"(b0), "r"(b1),
|
| 75 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 76 |
+
#else
|
| 77 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM70_8x8x4_F16F16F16F16_TN without CUTE_ARCH_MMA_SM70_ENABLED");
|
| 78 |
+
#endif
|
| 79 |
+
}
|
| 80 |
+
};
|
| 81 |
+
|
| 82 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 83 |
+
|
| 84 |
+
struct SM70_8x8x4_F16F16F16F16_NT
|
| 85 |
+
{
|
| 86 |
+
using DRegisters = uint32_t[4];
|
| 87 |
+
using ARegisters = uint32_t[2];
|
| 88 |
+
using BRegisters = uint32_t[2];
|
| 89 |
+
using CRegisters = uint32_t[4];
|
| 90 |
+
|
| 91 |
+
// Register asm fma
|
| 92 |
+
CUTE_HOST_DEVICE static void
|
| 93 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 94 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 95 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 96 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 97 |
+
{
|
| 98 |
+
#if defined(CUTE_ARCH_MMA_SM70_ENABLED)
|
| 99 |
+
asm volatile("mma.sync.aligned.m8n8k4.col.row.f16.f16.f16.f16"
|
| 100 |
+
"{%0, %1, %2, %3},"
|
| 101 |
+
"{%4, %5},"
|
| 102 |
+
"{%6, %7},"
|
| 103 |
+
"{%8, %9, %10, %11};\n"
|
| 104 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 105 |
+
: "r"(a0), "r"(a1),
|
| 106 |
+
"r"(b0), "r"(b1),
|
| 107 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 108 |
+
#else
|
| 109 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM70_8x8x4_F16F16F16F16_NT without CUTE_ARCH_MMA_SM70_ENABLED");
|
| 110 |
+
#endif
|
| 111 |
+
}
|
| 112 |
+
};
|
| 113 |
+
|
| 114 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 115 |
+
|
| 116 |
+
struct SM70_8x8x4_F16F16F16F16_NN
|
| 117 |
+
{
|
| 118 |
+
using DRegisters = uint32_t[4];
|
| 119 |
+
using ARegisters = uint32_t[2];
|
| 120 |
+
using BRegisters = uint32_t[2];
|
| 121 |
+
using CRegisters = uint32_t[4];
|
| 122 |
+
|
| 123 |
+
// Register asm fma
|
| 124 |
+
CUTE_HOST_DEVICE static void
|
| 125 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 126 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 127 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 128 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 129 |
+
{
|
| 130 |
+
#if defined(CUTE_ARCH_MMA_SM70_ENABLED)
|
| 131 |
+
asm volatile("mma.sync.aligned.m8n8k4.col.col.f16.f16.f16.f16"
|
| 132 |
+
"{%0, %1, %2, %3},"
|
| 133 |
+
"{%4, %5},"
|
| 134 |
+
"{%6, %7},"
|
| 135 |
+
"{%8, %9, %10, %11};\n"
|
| 136 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 137 |
+
: "r"(a0), "r"(a1),
|
| 138 |
+
"r"(b0), "r"(b1),
|
| 139 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 140 |
+
#else
|
| 141 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM70_8x8x4_F16F16F16F16_NN without CUTE_ARCH_MMA_SM70_ENABLED");
|
| 142 |
+
#endif
|
| 143 |
+
}
|
| 144 |
+
};
|
| 145 |
+
|
| 146 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 147 |
+
|
| 148 |
+
struct SM70_8x8x4_F16F16F16F16_TT
|
| 149 |
+
{
|
| 150 |
+
using DRegisters = uint32_t[4];
|
| 151 |
+
using ARegisters = uint32_t[2];
|
| 152 |
+
using BRegisters = uint32_t[2];
|
| 153 |
+
using CRegisters = uint32_t[4];
|
| 154 |
+
|
| 155 |
+
// Register asm fma
|
| 156 |
+
CUTE_HOST_DEVICE static void
|
| 157 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 158 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 159 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 160 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 161 |
+
{
|
| 162 |
+
#if defined(CUTE_ARCH_MMA_SM70_ENABLED)
|
| 163 |
+
asm volatile("mma.sync.aligned.m8n8k4.row.row.f16.f16.f16.f16"
|
| 164 |
+
"{%0, %1, %2, %3},"
|
| 165 |
+
"{%4, %5},"
|
| 166 |
+
"{%6, %7},"
|
| 167 |
+
"{%8, %9, %10, %11};\n"
|
| 168 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 169 |
+
: "r"(a0), "r"(a1),
|
| 170 |
+
"r"(b0), "r"(b1),
|
| 171 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 172 |
+
#else
|
| 173 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM70_8x8x4_F16F16F16F16_TT without CUTE_ARCH_MMA_SM70_ENABLED");
|
| 174 |
+
#endif
|
| 175 |
+
}
|
| 176 |
+
};
|
| 177 |
+
|
| 178 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 179 |
+
|
| 180 |
+
//
|
| 181 |
+
// SM70 MMA 884 F16F16F32
|
| 182 |
+
//
|
| 183 |
+
|
| 184 |
+
struct SM70_8x8x4_F32F16F16F32_TN
|
| 185 |
+
{
|
| 186 |
+
using DRegisters = float[8];
|
| 187 |
+
using ARegisters = uint32_t[2];
|
| 188 |
+
using BRegisters = uint32_t[2];
|
| 189 |
+
using CRegisters = float[8];
|
| 190 |
+
|
| 191 |
+
// Register asm fma
|
| 192 |
+
CUTE_HOST_DEVICE static void
|
| 193 |
+
fma(float & d0, float & d1, float & d2, float & d3,
|
| 194 |
+
float & d4, float & d5, float & d6, float & d7,
|
| 195 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 196 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 197 |
+
float const& c0, float const& c1, float const& c2, float const& c3,
|
| 198 |
+
float const& c4, float const& c5, float const& c6, float const& c7)
|
| 199 |
+
{
|
| 200 |
+
#if defined(CUTE_ARCH_MMA_SM70_ENABLED)
|
| 201 |
+
asm volatile("mma.sync.aligned.m8n8k4.row.col.f32.f16.f16.f32"
|
| 202 |
+
"{%0, %1, %2, %3, %4, %5, %6, %7},"
|
| 203 |
+
"{%8, %9},"
|
| 204 |
+
"{%10, %11},"
|
| 205 |
+
"{%12, %13, %14, %15, %16, %17, %18, %19};\n"
|
| 206 |
+
: "=f"(d0), "=f"(d1), "=f"(d2), "=f"(d3),
|
| 207 |
+
"=f"(d4), "=f"(d5), "=f"(d6), "=f"(d7)
|
| 208 |
+
: "r"(a0), "r"(a1),
|
| 209 |
+
"r"(b0), "r"(b1),
|
| 210 |
+
"f"(c0), "f"(c1), "f"(c2), "f"(c3),
|
| 211 |
+
"f"(c4), "f"(c5), "f"(c6), "f"(c7));
|
| 212 |
+
#else
|
| 213 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM70_8x8x4_F32F16F16F32_TN without CUTE_ARCH_MMA_SM70_ENABLED");
|
| 214 |
+
#endif
|
| 215 |
+
}
|
| 216 |
+
};
|
| 217 |
+
|
| 218 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 219 |
+
|
| 220 |
+
struct SM70_8x8x4_F32F16F16F32_NT
|
| 221 |
+
{
|
| 222 |
+
using DRegisters = float[8];
|
| 223 |
+
using ARegisters = uint32_t[2];
|
| 224 |
+
using BRegisters = uint32_t[2];
|
| 225 |
+
using CRegisters = float[8];
|
| 226 |
+
|
| 227 |
+
// Register asm fma
|
| 228 |
+
CUTE_HOST_DEVICE static void
|
| 229 |
+
fma(float & d0, float & d1, float & d2, float & d3,
|
| 230 |
+
float & d4, float & d5, float & d6, float & d7,
|
| 231 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 232 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 233 |
+
float const& c0, float const& c1, float const& c2, float const& c3,
|
| 234 |
+
float const& c4, float const& c5, float const& c6, float const& c7)
|
| 235 |
+
{
|
| 236 |
+
#if defined(CUTE_ARCH_MMA_SM70_ENABLED)
|
| 237 |
+
asm volatile("mma.sync.aligned.m8n8k4.col.row.f32.f16.f16.f32"
|
| 238 |
+
"{%0, %1, %2, %3, %4, %5, %6, %7},"
|
| 239 |
+
"{%8, %9},"
|
| 240 |
+
"{%10, %11},"
|
| 241 |
+
"{%12, %13, %14, %15, %16, %17, %18, %19};"
|
| 242 |
+
: "=f"(d0), "=f"(d1), "=f"(d2), "=f"(d3),
|
| 243 |
+
"=f"(d4), "=f"(d5), "=f"(d6), "=f"(d7)
|
| 244 |
+
: "r"(a0), "r"(a1),
|
| 245 |
+
"r"(b0), "r"(b1),
|
| 246 |
+
"f"(c0), "f"(c1), "f"(c2), "f"(c3),
|
| 247 |
+
"f"(c4), "f"(c5), "f"(c6), "f"(c7));
|
| 248 |
+
#else
|
| 249 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM70_8x8x4_F32F16F16F32_NT without CUTE_ARCH_MMA_SM70_ENABLED");
|
| 250 |
+
#endif
|
| 251 |
+
}
|
| 252 |
+
};
|
| 253 |
+
|
| 254 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 255 |
+
|
| 256 |
+
struct SM70_8x8x4_F32F16F16F32_NN
|
| 257 |
+
{
|
| 258 |
+
using DRegisters = float[8];
|
| 259 |
+
using ARegisters = uint32_t[2];
|
| 260 |
+
using BRegisters = uint32_t[2];
|
| 261 |
+
using CRegisters = float[8];
|
| 262 |
+
|
| 263 |
+
// Register asm fma
|
| 264 |
+
CUTE_HOST_DEVICE static void
|
| 265 |
+
fma(float & d0, float & d1, float & d2, float & d3,
|
| 266 |
+
float & d4, float & d5, float & d6, float & d7,
|
| 267 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 268 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 269 |
+
float const& c0, float const& c1, float const& c2, float const& c3,
|
| 270 |
+
float const& c4, float const& c5, float const& c6, float const& c7)
|
| 271 |
+
{
|
| 272 |
+
#if defined(CUTE_ARCH_MMA_SM70_ENABLED)
|
| 273 |
+
asm volatile("mma.sync.aligned.m8n8k4.col.col.f32.f16.f16.f32"
|
| 274 |
+
"{%0, %1, %2, %3, %4, %5, %6, %7},"
|
| 275 |
+
"{%8, %9},"
|
| 276 |
+
"{%10, %11},"
|
| 277 |
+
"{%12, %13, %14, %15, %16, %17, %18, %19};"
|
| 278 |
+
: "=f"(d0), "=f"(d1), "=f"(d2), "=f"(d3),
|
| 279 |
+
"=f"(d4), "=f"(d5), "=f"(d6), "=f"(d7)
|
| 280 |
+
: "r"(a0), "r"(a1),
|
| 281 |
+
"r"(b0), "r"(b1),
|
| 282 |
+
"f"(c0), "f"(c1), "f"(c2), "f"(c3),
|
| 283 |
+
"f"(c4), "f"(c5), "f"(c6), "f"(c7));
|
| 284 |
+
#else
|
| 285 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM70_8x8x4_F32F16F16F32_NN without CUTE_ARCH_MMA_SM70_ENABLED");
|
| 286 |
+
#endif
|
| 287 |
+
}
|
| 288 |
+
};
|
| 289 |
+
|
| 290 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 291 |
+
|
| 292 |
+
struct SM70_8x8x4_F32F16F16F32_TT
|
| 293 |
+
{
|
| 294 |
+
using DRegisters = float[8];
|
| 295 |
+
using ARegisters = uint32_t[2];
|
| 296 |
+
using BRegisters = uint32_t[2];
|
| 297 |
+
using CRegisters = float[8];
|
| 298 |
+
|
| 299 |
+
// Register asm fma
|
| 300 |
+
CUTE_HOST_DEVICE static void
|
| 301 |
+
fma(float & d0, float & d1, float & d2, float & d3,
|
| 302 |
+
float & d4, float & d5, float & d6, float & d7,
|
| 303 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 304 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 305 |
+
float const& c0, float const& c1, float const& c2, float const& c3,
|
| 306 |
+
float const& c4, float const& c5, float const& c6, float const& c7)
|
| 307 |
+
{
|
| 308 |
+
#if defined(CUTE_ARCH_MMA_SM70_ENABLED)
|
| 309 |
+
asm volatile("mma.sync.aligned.m8n8k4.row.row.f32.f16.f16.f32"
|
| 310 |
+
"{%0, %1, %2, %3, %4, %5, %6, %7},"
|
| 311 |
+
"{%8, %9},"
|
| 312 |
+
"{%10, %11},"
|
| 313 |
+
"{%12, %13, %14, %15, %16, %17, %18, %19};"
|
| 314 |
+
: "=f"(d0), "=f"(d1), "=f"(d2), "=f"(d3),
|
| 315 |
+
"=f"(d4), "=f"(d5), "=f"(d6), "=f"(d7)
|
| 316 |
+
: "r"(a0), "r"(a1),
|
| 317 |
+
"r"(b0), "r"(b1),
|
| 318 |
+
"f"(c0), "f"(c1), "f"(c2), "f"(c3),
|
| 319 |
+
"f"(c4), "f"(c5), "f"(c6), "f"(c7));
|
| 320 |
+
#else
|
| 321 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM70_8x8x4_F32F16F16F32_TT without CUTE_ARCH_MMA_SM70_ENABLED");
|
| 322 |
+
#endif
|
| 323 |
+
}
|
| 324 |
+
|
| 325 |
+
};
|
| 326 |
+
|
| 327 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 328 |
+
|
| 329 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm75.hpp
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/config.hpp>
|
| 34 |
+
|
| 35 |
+
#include <cute/arch/mma.hpp>
|
| 36 |
+
|
| 37 |
+
// Config
|
| 38 |
+
#if ((__CUDACC_VER_MAJOR__ > 10) || (__CUDACC_VER_MAJOR__ == 10 && __CUDACC_VER_MINOR__ >= 2))
|
| 39 |
+
# define CUTE_ARCH_MMA_SM75_SUPPORTED
|
| 40 |
+
# if (defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 750))
|
| 41 |
+
# define CUTE_ARCH_MMA_SM75_ENABLED
|
| 42 |
+
# endif
|
| 43 |
+
#endif
|
| 44 |
+
|
| 45 |
+
namespace cute
|
| 46 |
+
{
|
| 47 |
+
|
| 48 |
+
//
|
| 49 |
+
// SM75 MMA 1688 F16F16F32
|
| 50 |
+
//
|
| 51 |
+
|
| 52 |
+
struct SM75_16x8x8_F32F16F16F32_TN
|
| 53 |
+
{
|
| 54 |
+
using DRegisters = float[4];
|
| 55 |
+
using ARegisters = uint32_t[2];
|
| 56 |
+
using BRegisters = uint32_t[1];
|
| 57 |
+
using CRegisters = float[4];
|
| 58 |
+
|
| 59 |
+
// Register asm fma
|
| 60 |
+
CUTE_HOST_DEVICE static void
|
| 61 |
+
fma(float & d0, float & d1, float & d2, float & d3,
|
| 62 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 63 |
+
uint32_t const& b0,
|
| 64 |
+
float const& c0, float const& c1, float const& c2, float const& c3)
|
| 65 |
+
{
|
| 66 |
+
#if defined(CUTE_ARCH_MMA_SM75_ENABLED)
|
| 67 |
+
asm volatile("mma.sync.aligned.m16n8k8.row.col.f32.f16.f16.f32"
|
| 68 |
+
"{%0, %1, %2, %3},"
|
| 69 |
+
"{%4, %5},"
|
| 70 |
+
"{%6},"
|
| 71 |
+
"{%7, %8, %9, %10};\n"
|
| 72 |
+
: "=f"(d0), "=f"(d1), "=f"(d2), "=f"(d3)
|
| 73 |
+
: "r"(a0), "r"(a1),
|
| 74 |
+
"r"(b0),
|
| 75 |
+
"f"(c0), "f"(c1), "f"(c2), "f"(c3));
|
| 76 |
+
#else
|
| 77 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM75_16x8x8_F32F16F16F32_TN without CUTE_ARCH_MMA_SM75_ENABLED");
|
| 78 |
+
#endif
|
| 79 |
+
}
|
| 80 |
+
};
|
| 81 |
+
|
| 82 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 83 |
+
|
| 84 |
+
//
|
| 85 |
+
// SM75 MMA 8816 S8S8S32
|
| 86 |
+
//
|
| 87 |
+
|
| 88 |
+
struct SM75_8x8x16_S32S8S8S32_TN
|
| 89 |
+
{
|
| 90 |
+
using DRegisters = uint32_t[2];
|
| 91 |
+
using ARegisters = uint32_t[1];
|
| 92 |
+
using BRegisters = uint32_t[1];
|
| 93 |
+
using CRegisters = uint32_t[2];
|
| 94 |
+
|
| 95 |
+
// Register asm fma
|
| 96 |
+
CUTE_HOST_DEVICE static void
|
| 97 |
+
fma(uint32_t & d0, uint32_t & d1,
|
| 98 |
+
uint32_t const& a0,
|
| 99 |
+
uint32_t const& b0,
|
| 100 |
+
uint32_t const& c0, uint32_t const& c1)
|
| 101 |
+
{
|
| 102 |
+
#if defined(CUTE_ARCH_MMA_SM75_ENABLED)
|
| 103 |
+
asm volatile("mma.sync.aligned.m8n8k16.row.col.s32.s8.s8.s32"
|
| 104 |
+
"{%0, %1},"
|
| 105 |
+
"{%2},"
|
| 106 |
+
"{%3},"
|
| 107 |
+
"{%4, %5};\n"
|
| 108 |
+
: "=r"(d0), "=r"(d1)
|
| 109 |
+
: "r"(a0),
|
| 110 |
+
"r"(b0),
|
| 111 |
+
"r"(c0), "r"(c1));
|
| 112 |
+
#else
|
| 113 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM75_8x8x16_S32S8S8S32_TN without CUTE_ARCH_MMA_SM75_ENABLED");
|
| 114 |
+
#endif
|
| 115 |
+
}
|
| 116 |
+
};
|
| 117 |
+
|
| 118 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 119 |
+
|
| 120 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm80.hpp
ADDED
|
@@ -0,0 +1,2241 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
|
| 32 |
+
#pragma once
|
| 33 |
+
|
| 34 |
+
#include <cute/config.hpp>
|
| 35 |
+
#include <cute/arch/mma.hpp>
|
| 36 |
+
#include <cute/numeric/complex.hpp>
|
| 37 |
+
|
| 38 |
+
// Config
|
| 39 |
+
#if (defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 800))
|
| 40 |
+
# define CUTE_ARCH_MMA_SM80_ENABLED
|
| 41 |
+
|
| 42 |
+
#if (__CUDA_ARCH__ <= 900)
|
| 43 |
+
#define CUTE_ARCH_MMA_B1_AND_SM80_ENABLED
|
| 44 |
+
#endif
|
| 45 |
+
|
| 46 |
+
#if (__CUDA_ARCH__ <= 890)
|
| 47 |
+
#define CUTE_ARCH_MMA_B1_XOR_SM80_ENABLED
|
| 48 |
+
#endif
|
| 49 |
+
|
| 50 |
+
#endif
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
namespace cute {
|
| 55 |
+
|
| 56 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 57 |
+
|
| 58 |
+
// MMA 16x8x8 TN
|
| 59 |
+
struct SM80_16x8x8_F16F16F16F16_TN
|
| 60 |
+
{
|
| 61 |
+
using DRegisters = uint32_t[2];
|
| 62 |
+
using ARegisters = uint32_t[2];
|
| 63 |
+
using BRegisters = uint32_t[1];
|
| 64 |
+
using CRegisters = uint32_t[2];
|
| 65 |
+
|
| 66 |
+
CUTE_HOST_DEVICE static void
|
| 67 |
+
fma(uint32_t & d0, uint32_t & d1,
|
| 68 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 69 |
+
uint32_t const& b0,
|
| 70 |
+
uint32_t const& c0, uint32_t const& c1)
|
| 71 |
+
{
|
| 72 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 73 |
+
asm volatile(
|
| 74 |
+
"mma.sync.aligned.m16n8k8.row.col.f16.f16.f16.f16 "
|
| 75 |
+
"{%0, %1},"
|
| 76 |
+
"{%2, %3},"
|
| 77 |
+
"{%4},"
|
| 78 |
+
"{%5, %6};\n"
|
| 79 |
+
: "=r"(d0), "=r"(d1)
|
| 80 |
+
: "r"(a0), "r"(a1),
|
| 81 |
+
"r"(b0),
|
| 82 |
+
"r"(c0), "r"(c1));
|
| 83 |
+
#else
|
| 84 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x8_F16F16F16F16_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 85 |
+
#endif
|
| 86 |
+
}
|
| 87 |
+
};
|
| 88 |
+
|
| 89 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 90 |
+
|
| 91 |
+
// MMA 16x8x16 TN
|
| 92 |
+
struct SM80_16x8x16_F16F16F16F16_TN
|
| 93 |
+
{
|
| 94 |
+
using DRegisters = uint32_t[2];
|
| 95 |
+
using ARegisters = uint32_t[4];
|
| 96 |
+
using BRegisters = uint32_t[2];
|
| 97 |
+
using CRegisters = uint32_t[2];
|
| 98 |
+
|
| 99 |
+
CUTE_HOST_DEVICE static void
|
| 100 |
+
fma(uint32_t & d0, uint32_t & d1,
|
| 101 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 102 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 103 |
+
uint32_t const& c0, uint32_t const& c1)
|
| 104 |
+
{
|
| 105 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 106 |
+
asm volatile(
|
| 107 |
+
"mma.sync.aligned.m16n8k16.row.col.f16.f16.f16.f16 "
|
| 108 |
+
"{%0, %1},"
|
| 109 |
+
"{%2, %3, %4, %5},"
|
| 110 |
+
"{%6, %7},"
|
| 111 |
+
"{%8, %9};\n"
|
| 112 |
+
: "=r"(d0), "=r"(d1)
|
| 113 |
+
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 114 |
+
"r"(b0), "r"(b1),
|
| 115 |
+
"r"(c0), "r"(c1));
|
| 116 |
+
#else
|
| 117 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x16_F16F16F16F16_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 118 |
+
#endif
|
| 119 |
+
}
|
| 120 |
+
};
|
| 121 |
+
|
| 122 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 123 |
+
|
| 124 |
+
// MMA 16x8x8 TN
|
| 125 |
+
struct SM80_16x8x8_F32F16F16F32_TN
|
| 126 |
+
{
|
| 127 |
+
using DRegisters = float[4];
|
| 128 |
+
using ARegisters = uint32_t[2];
|
| 129 |
+
using BRegisters = uint32_t[1];
|
| 130 |
+
using CRegisters = float[4];
|
| 131 |
+
|
| 132 |
+
CUTE_HOST_DEVICE static void
|
| 133 |
+
fma(float & d0, float & d1, float & d2, float & d3,
|
| 134 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 135 |
+
uint32_t const& b0,
|
| 136 |
+
float const & c0, float const & c1, float const & c2, float const & c3)
|
| 137 |
+
{
|
| 138 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 139 |
+
asm volatile(
|
| 140 |
+
"mma.sync.aligned.m16n8k8.row.col.f32.f16.f16.f32 "
|
| 141 |
+
"{%0, %1, %2, %3},"
|
| 142 |
+
"{%4, %5},"
|
| 143 |
+
"{%6},"
|
| 144 |
+
"{%7, %8, %9, %10};\n"
|
| 145 |
+
: "=f"(d0), "=f"(d1), "=f"(d2), "=f"(d3)
|
| 146 |
+
: "r"(a0), "r"(a1),
|
| 147 |
+
"r"(b0),
|
| 148 |
+
"f"(c0), "f"(c1), "f"(c2), "f"(c3));
|
| 149 |
+
#else
|
| 150 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x8_F32F16F16F32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 151 |
+
#endif
|
| 152 |
+
}
|
| 153 |
+
};
|
| 154 |
+
|
| 155 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 156 |
+
|
| 157 |
+
// MMA 16x8x16 TN
|
| 158 |
+
struct SM80_16x8x16_F32F16F16F32_TN
|
| 159 |
+
{
|
| 160 |
+
using DRegisters = float[4];
|
| 161 |
+
using ARegisters = uint32_t[4];
|
| 162 |
+
using BRegisters = uint32_t[2];
|
| 163 |
+
using CRegisters = float[4];
|
| 164 |
+
|
| 165 |
+
CUTE_HOST_DEVICE static void
|
| 166 |
+
fma(float & d0, float & d1, float & d2, float & d3,
|
| 167 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 168 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 169 |
+
float const & c0, float const & c1, float const & c2, float const & c3)
|
| 170 |
+
{
|
| 171 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 172 |
+
asm volatile(
|
| 173 |
+
"mma.sync.aligned.m16n8k16.row.col.f32.f16.f16.f32 "
|
| 174 |
+
"{%0, %1, %2, %3},"
|
| 175 |
+
"{%4, %5, %6, %7},"
|
| 176 |
+
"{%8, %9},"
|
| 177 |
+
"{%10, %11, %12, %13};\n"
|
| 178 |
+
: "=f"(d0), "=f"(d1), "=f"(d2), "=f"(d3)
|
| 179 |
+
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 180 |
+
"r"(b0), "r"(b1),
|
| 181 |
+
"f"(c0), "f"(c1), "f"(c2), "f"(c3));
|
| 182 |
+
#else
|
| 183 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x16_F32F16F16F32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 184 |
+
#endif
|
| 185 |
+
}
|
| 186 |
+
};
|
| 187 |
+
|
| 188 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 189 |
+
|
| 190 |
+
// MMA 16x8x8 TN
|
| 191 |
+
struct SM80_16x8x8_F32BF16BF16F32_TN
|
| 192 |
+
{
|
| 193 |
+
using DRegisters = float[4];
|
| 194 |
+
using ARegisters = uint32_t[2];
|
| 195 |
+
using BRegisters = uint32_t[1];
|
| 196 |
+
using CRegisters = float[4];
|
| 197 |
+
|
| 198 |
+
CUTE_HOST_DEVICE static void
|
| 199 |
+
fma(float & d0, float & d1, float & d2, float & d3,
|
| 200 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 201 |
+
uint32_t const& b0,
|
| 202 |
+
float const & c0, float const & c1, float const & c2, float const & c3)
|
| 203 |
+
{
|
| 204 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 205 |
+
asm volatile(
|
| 206 |
+
"mma.sync.aligned.m16n8k8.row.col.f32.bf16.bf16.f32 "
|
| 207 |
+
"{%0, %1, %2, %3},"
|
| 208 |
+
"{%4, %5},"
|
| 209 |
+
"{%6},"
|
| 210 |
+
"{%7, %8, %9, %10};\n"
|
| 211 |
+
: "=f"(d0), "=f"(d1), "=f"(d2), "=f"(d3)
|
| 212 |
+
: "r"(a0), "r"(a1),
|
| 213 |
+
"r"(b0),
|
| 214 |
+
"f"(c0), "f"(c1), "f"(c2), "f"(c3));
|
| 215 |
+
#else
|
| 216 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x8_F32BF16BF16F32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 217 |
+
#endif
|
| 218 |
+
}
|
| 219 |
+
};
|
| 220 |
+
|
| 221 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 222 |
+
|
| 223 |
+
// MMA 16x8x16 TN
|
| 224 |
+
struct SM80_16x8x16_F32BF16BF16F32_TN
|
| 225 |
+
{
|
| 226 |
+
using DRegisters = float[4];
|
| 227 |
+
using ARegisters = uint32_t[4];
|
| 228 |
+
using BRegisters = uint32_t[2];
|
| 229 |
+
using CRegisters = float[4];
|
| 230 |
+
|
| 231 |
+
CUTE_HOST_DEVICE static void
|
| 232 |
+
fma(float & d0, float & d1, float & d2, float & d3,
|
| 233 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 234 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 235 |
+
float const & c0, float const & c1, float const & c2, float const & c3)
|
| 236 |
+
{
|
| 237 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 238 |
+
asm volatile(
|
| 239 |
+
"mma.sync.aligned.m16n8k16.row.col.f32.bf16.bf16.f32 "
|
| 240 |
+
"{%0, %1, %2, %3},"
|
| 241 |
+
"{%4, %5, %6, %7},"
|
| 242 |
+
"{%8, %9},"
|
| 243 |
+
"{%10, %11, %12, %13};\n"
|
| 244 |
+
: "=f"(d0), "=f"(d1), "=f"(d2), "=f"(d3)
|
| 245 |
+
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 246 |
+
"r"(b0), "r"(b1),
|
| 247 |
+
"f"(c0), "f"(c1), "f"(c2), "f"(c3));
|
| 248 |
+
#else
|
| 249 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x16_F32BF16BF16F32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 250 |
+
#endif
|
| 251 |
+
}
|
| 252 |
+
};
|
| 253 |
+
|
| 254 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 255 |
+
|
| 256 |
+
// MMA 16x8x4 TN
|
| 257 |
+
struct SM80_16x8x4_F32TF32TF32F32_TN
|
| 258 |
+
{
|
| 259 |
+
using DRegisters = float[4];
|
| 260 |
+
using ARegisters = uint32_t[2];
|
| 261 |
+
using BRegisters = uint32_t[1];
|
| 262 |
+
using CRegisters = float[4];
|
| 263 |
+
|
| 264 |
+
CUTE_HOST_DEVICE static void
|
| 265 |
+
fma(float & d0, float & d1, float & d2, float & d3,
|
| 266 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 267 |
+
uint32_t const& b0,
|
| 268 |
+
float const & c0, float const & c1, float const & c2, float const & c3)
|
| 269 |
+
{
|
| 270 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 271 |
+
asm volatile(
|
| 272 |
+
"mma.sync.aligned.m16n8k4.row.col.f32.tf32.tf32.f32 "
|
| 273 |
+
"{%0, %1, %2, %3},"
|
| 274 |
+
"{%4, %5},"
|
| 275 |
+
"{%6},"
|
| 276 |
+
"{%7, %8, %9, %10};\n"
|
| 277 |
+
: "=f"(d0), "=f"(d1), "=f"(d2), "=f"(d3)
|
| 278 |
+
: "r"(a0), "r"(a1),
|
| 279 |
+
"r"(b0),
|
| 280 |
+
"f"(c0), "f"(c1), "f"(c2), "f"(c3));
|
| 281 |
+
#else
|
| 282 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x4_F32TF32TF32F32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 283 |
+
#endif
|
| 284 |
+
}
|
| 285 |
+
};
|
| 286 |
+
|
| 287 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 288 |
+
|
| 289 |
+
// MMA 16x8x8 TN
|
| 290 |
+
struct SM80_16x8x8_F32TF32TF32F32_TN
|
| 291 |
+
{
|
| 292 |
+
using DRegisters = float[4];
|
| 293 |
+
using ARegisters = uint32_t[4];
|
| 294 |
+
using BRegisters = uint32_t[2];
|
| 295 |
+
using CRegisters = float[4];
|
| 296 |
+
|
| 297 |
+
CUTE_HOST_DEVICE static void
|
| 298 |
+
fma(float & d0, float & d1, float & d2, float & d3,
|
| 299 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 300 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 301 |
+
float const & c0, float const & c1, float const & c2, float const & c3)
|
| 302 |
+
{
|
| 303 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 304 |
+
asm volatile(
|
| 305 |
+
"mma.sync.aligned.m16n8k8.row.col.f32.tf32.tf32.f32 "
|
| 306 |
+
"{%0, %1, %2, %3},"
|
| 307 |
+
"{%4, %5, %6, %7},"
|
| 308 |
+
"{%8, %9},"
|
| 309 |
+
"{%10, %11, %12, %13};\n"
|
| 310 |
+
: "=f"(d0), "=f"(d1), "=f"(d2), "=f"(d3)
|
| 311 |
+
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 312 |
+
"r"(b0), "r"(b1),
|
| 313 |
+
"f"(c0), "f"(c1), "f"(c2), "f"(c3));
|
| 314 |
+
#else
|
| 315 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x8_F32TF32TF32F32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 316 |
+
#endif
|
| 317 |
+
}
|
| 318 |
+
};
|
| 319 |
+
|
| 320 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 321 |
+
|
| 322 |
+
// MMA 8x8x4 TN
|
| 323 |
+
struct SM80_8x8x4_F64F64F64F64_TN
|
| 324 |
+
{
|
| 325 |
+
using DRegisters = double[2];
|
| 326 |
+
using ARegisters = double[1];
|
| 327 |
+
using BRegisters = double[1];
|
| 328 |
+
using CRegisters = double[2];
|
| 329 |
+
|
| 330 |
+
CUTE_HOST_DEVICE static void
|
| 331 |
+
fma(double & d0, double & d1,
|
| 332 |
+
double const& a0,
|
| 333 |
+
double const& b0,
|
| 334 |
+
double const& c0, double const& c1)
|
| 335 |
+
{
|
| 336 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 337 |
+
asm volatile(
|
| 338 |
+
"mma.sync.aligned.m8n8k4.row.col.f64.f64.f64.f64 "
|
| 339 |
+
"{%0, %1},"
|
| 340 |
+
"{%2},"
|
| 341 |
+
"{%3},"
|
| 342 |
+
"{%4, %5};\n"
|
| 343 |
+
: "=d"(d0), "=d"(d1)
|
| 344 |
+
: "d"(a0),
|
| 345 |
+
"d"(b0),
|
| 346 |
+
"d"(c0), "d"(c1));
|
| 347 |
+
#else
|
| 348 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_8x8x4_F64F64F64F64_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 349 |
+
#endif
|
| 350 |
+
}
|
| 351 |
+
};
|
| 352 |
+
|
| 353 |
+
// MMA 8x8x4 TN with Planar Complex multiplication
|
| 354 |
+
struct SM80_8x8x4_C64C64C64C64_TN
|
| 355 |
+
{
|
| 356 |
+
using DRegisters = complex<double>[2];
|
| 357 |
+
using ARegisters = complex<double>[1];
|
| 358 |
+
using BRegisters = complex<double>[1];
|
| 359 |
+
using CRegisters = complex<double>[2];
|
| 360 |
+
|
| 361 |
+
CUTE_HOST_DEVICE static void
|
| 362 |
+
fma(complex<double> & d0, complex<double> & d1,
|
| 363 |
+
complex<double> const& a0,
|
| 364 |
+
complex<double> const& b0,
|
| 365 |
+
complex<double> const& c0, complex<double> const& c1)
|
| 366 |
+
{
|
| 367 |
+
// Because thrust::complex does not provide a mutable ref
|
| 368 |
+
double& rd0 = reinterpret_cast<double(&)[2]>(d0)[0];
|
| 369 |
+
double& id0 = reinterpret_cast<double(&)[2]>(d0)[1];
|
| 370 |
+
double& rd1 = reinterpret_cast<double(&)[2]>(d1)[0];
|
| 371 |
+
double& id1 = reinterpret_cast<double(&)[2]>(d1)[1];
|
| 372 |
+
|
| 373 |
+
// d.real() = a.real() * b.real() + c.real();
|
| 374 |
+
SM80_8x8x4_F64F64F64F64_TN::fma(
|
| 375 |
+
rd0, rd1,
|
| 376 |
+
a0.real(),
|
| 377 |
+
b0.real(),
|
| 378 |
+
c0.real(), c1.real());
|
| 379 |
+
|
| 380 |
+
// d.imag() = a.imag() * b.real() + c.imag();
|
| 381 |
+
SM80_8x8x4_F64F64F64F64_TN::fma(
|
| 382 |
+
id0, id1,
|
| 383 |
+
a0.imag(),
|
| 384 |
+
b0.real(),
|
| 385 |
+
c0.imag(), c1.imag());
|
| 386 |
+
|
| 387 |
+
// d.real() = -a.imag() * b.imag() + d.real();
|
| 388 |
+
SM80_8x8x4_F64F64F64F64_TN::fma(
|
| 389 |
+
rd0, rd1,
|
| 390 |
+
-a0.imag(),
|
| 391 |
+
b0.imag(),
|
| 392 |
+
d0.real(), d1.real());
|
| 393 |
+
|
| 394 |
+
// d.imag() = a.real() * b.imag() + d.imag();
|
| 395 |
+
SM80_8x8x4_F64F64F64F64_TN::fma(
|
| 396 |
+
id0, id1,
|
| 397 |
+
a0.real(),
|
| 398 |
+
b0.imag(),
|
| 399 |
+
d0.imag(), d1.imag());
|
| 400 |
+
}
|
| 401 |
+
};
|
| 402 |
+
|
| 403 |
+
// MMA 8x8x4 TN with Gaussian Complex multiplication:
|
| 404 |
+
// (a + bi)*(c + di)
|
| 405 |
+
// yields
|
| 406 |
+
// t0 += a*c
|
| 407 |
+
// t1 += b*d
|
| 408 |
+
// t2 += (a+b)*(c+d)
|
| 409 |
+
// then
|
| 410 |
+
// re = t0 - t1
|
| 411 |
+
// im = t2 - t0 - t1
|
| 412 |
+
struct SM80_8x8x4_GC64C64C64GC64_TN
|
| 413 |
+
{
|
| 414 |
+
struct GaussComplex {
|
| 415 |
+
double t0, t1, t2;
|
| 416 |
+
|
| 417 |
+
CUTE_HOST_DEVICE //constexpr
|
| 418 |
+
operator complex<double>() const { return complex<double>(t0 - t1, t2 - t0 - t1); }
|
| 419 |
+
|
| 420 |
+
CUTE_HOST_DEVICE friend //constexpr
|
| 421 |
+
complex<double> operator*(GaussComplex const& a, complex<double> const& b) { return static_cast<complex<double>>(a) * b; }
|
| 422 |
+
CUTE_HOST_DEVICE friend //constexpr
|
| 423 |
+
complex<double> operator*(complex<double> const& a, GaussComplex const& b) { return b * a; }
|
| 424 |
+
|
| 425 |
+
CUTE_HOST_DEVICE friend //constexpr
|
| 426 |
+
complex<double> operator+(GaussComplex const& a, complex<double> const& b) { return static_cast<complex<double>>(a) + b; }
|
| 427 |
+
CUTE_HOST_DEVICE friend //constexpr
|
| 428 |
+
complex<double> operator+(complex<double> const& a, GaussComplex const& b) { return b + a; }
|
| 429 |
+
};
|
| 430 |
+
|
| 431 |
+
using DRegisters = GaussComplex[2];
|
| 432 |
+
using ARegisters = complex<double>[1];
|
| 433 |
+
using BRegisters = complex<double>[1];
|
| 434 |
+
using CRegisters = GaussComplex[2];
|
| 435 |
+
|
| 436 |
+
CUTE_HOST_DEVICE static void
|
| 437 |
+
fma(GaussComplex & d0, GaussComplex & d1,
|
| 438 |
+
complex<double> const& a0,
|
| 439 |
+
complex<double> const& b0,
|
| 440 |
+
GaussComplex const& c0, GaussComplex const& c1)
|
| 441 |
+
{
|
| 442 |
+
SM80_8x8x4_F64F64F64F64_TN::fma(d0.t0, d1.t0,
|
| 443 |
+
a0.real(),
|
| 444 |
+
b0.real(),
|
| 445 |
+
c0.t0, c1.t0);
|
| 446 |
+
SM80_8x8x4_F64F64F64F64_TN::fma(d0.t1, d1.t1,
|
| 447 |
+
a0.imag(),
|
| 448 |
+
b0.imag(),
|
| 449 |
+
c0.t1, c1.t1);
|
| 450 |
+
SM80_8x8x4_F64F64F64F64_TN::fma(d0.t2, d1.t2,
|
| 451 |
+
a0.real() + a0.imag(),
|
| 452 |
+
b0.real() + b0.imag(),
|
| 453 |
+
c0.t2, c1.t2);
|
| 454 |
+
}
|
| 455 |
+
};
|
| 456 |
+
|
| 457 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 458 |
+
|
| 459 |
+
// MMA 8x8x16 TN
|
| 460 |
+
struct SM80_8x8x16_S32S8S8S32_TN
|
| 461 |
+
{
|
| 462 |
+
using DRegisters = uint32_t[2];
|
| 463 |
+
using ARegisters = uint32_t[1];
|
| 464 |
+
using BRegisters = uint32_t[1];
|
| 465 |
+
using CRegisters = uint32_t[2];
|
| 466 |
+
|
| 467 |
+
CUTE_HOST_DEVICE static void
|
| 468 |
+
fma(uint32_t & d0, uint32_t & d1,
|
| 469 |
+
uint32_t const& a0,
|
| 470 |
+
uint32_t const& b0,
|
| 471 |
+
uint32_t const& c0, uint32_t const& c1)
|
| 472 |
+
{
|
| 473 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 474 |
+
asm volatile(
|
| 475 |
+
"mma.sync.aligned.m8n8k16.row.col.s32.s8.s8.s32 "
|
| 476 |
+
"{%0, %1},"
|
| 477 |
+
"{%2},"
|
| 478 |
+
"{%3},"
|
| 479 |
+
"{%4, %5};\n"
|
| 480 |
+
: "=r"(d0), "=r"(d1)
|
| 481 |
+
: "r"(a0),
|
| 482 |
+
"r"(b0),
|
| 483 |
+
"r"(c0), "r"(c1));
|
| 484 |
+
#else
|
| 485 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_8x8x16_S32S8S8S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 486 |
+
#endif
|
| 487 |
+
}
|
| 488 |
+
};
|
| 489 |
+
|
| 490 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 491 |
+
|
| 492 |
+
// MMA 8x8x16 TN
|
| 493 |
+
struct SM80_8x8x16_S32S8S8S32_TN_SATURATE
|
| 494 |
+
{
|
| 495 |
+
using DRegisters = uint32_t[2];
|
| 496 |
+
using ARegisters = uint32_t[1];
|
| 497 |
+
using BRegisters = uint32_t[1];
|
| 498 |
+
using CRegisters = uint32_t[2];
|
| 499 |
+
|
| 500 |
+
CUTE_HOST_DEVICE static void
|
| 501 |
+
fma(uint32_t & d0, uint32_t & d1,
|
| 502 |
+
uint32_t const& a0,
|
| 503 |
+
uint32_t const& b0,
|
| 504 |
+
uint32_t const& c0, uint32_t const& c1)
|
| 505 |
+
{
|
| 506 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 507 |
+
asm volatile(
|
| 508 |
+
"mma.sync.aligned.m8n8k16.row.col.s32.s8.s8.s32.satfinite "
|
| 509 |
+
"{%0, %1},"
|
| 510 |
+
"{%2},"
|
| 511 |
+
"{%3},"
|
| 512 |
+
"{%4, %5};\n"
|
| 513 |
+
: "=r"(d0), "=r"(d1)
|
| 514 |
+
: "r"(a0),
|
| 515 |
+
"r"(b0),
|
| 516 |
+
"r"(c0), "r"(c1));
|
| 517 |
+
#else
|
| 518 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_8x8x16_S32S8S8S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 519 |
+
#endif
|
| 520 |
+
}
|
| 521 |
+
};
|
| 522 |
+
|
| 523 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 524 |
+
|
| 525 |
+
// MMA 16x8x16 TN
|
| 526 |
+
struct SM80_16x8x16_S32S8S8S32_TN
|
| 527 |
+
{
|
| 528 |
+
using DRegisters = uint32_t[4];
|
| 529 |
+
using ARegisters = uint32_t[2];
|
| 530 |
+
using BRegisters = uint32_t[1];
|
| 531 |
+
using CRegisters = uint32_t[4];
|
| 532 |
+
|
| 533 |
+
CUTE_HOST_DEVICE static void
|
| 534 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 535 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 536 |
+
uint32_t const& b0,
|
| 537 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 538 |
+
{
|
| 539 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 540 |
+
asm volatile(
|
| 541 |
+
"mma.sync.aligned.m16n8k16.row.col.s32.s8.s8.s32 "
|
| 542 |
+
"{%0, %1, %2, %3},"
|
| 543 |
+
"{%4, %5},"
|
| 544 |
+
"{%6},"
|
| 545 |
+
"{%7, %8, %9, %10};\n"
|
| 546 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 547 |
+
: "r"(a0), "r"(a1),
|
| 548 |
+
"r"(b0),
|
| 549 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 550 |
+
#else
|
| 551 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x16_S32S8S8S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 552 |
+
#endif
|
| 553 |
+
}
|
| 554 |
+
};
|
| 555 |
+
|
| 556 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 557 |
+
|
| 558 |
+
// MMA 16x8x16 TN
|
| 559 |
+
struct SM80_16x8x16_S32S8S8S32_TN_SATURATE
|
| 560 |
+
{
|
| 561 |
+
using DRegisters = uint32_t[4];
|
| 562 |
+
using ARegisters = uint32_t[2];
|
| 563 |
+
using BRegisters = uint32_t[1];
|
| 564 |
+
using CRegisters = uint32_t[4];
|
| 565 |
+
|
| 566 |
+
CUTE_HOST_DEVICE static void
|
| 567 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 568 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 569 |
+
uint32_t const& b0,
|
| 570 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 571 |
+
{
|
| 572 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 573 |
+
asm volatile(
|
| 574 |
+
"mma.sync.aligned.m16n8k16.row.col.s32.s8.s8.s32.satfinite "
|
| 575 |
+
"{%0, %1, %2, %3},"
|
| 576 |
+
"{%4, %5},"
|
| 577 |
+
"{%6},"
|
| 578 |
+
"{%7, %8, %9, %10};\n"
|
| 579 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 580 |
+
: "r"(a0), "r"(a1),
|
| 581 |
+
"r"(b0),
|
| 582 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 583 |
+
#else
|
| 584 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x16_S32S8S8S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 585 |
+
#endif
|
| 586 |
+
}
|
| 587 |
+
};
|
| 588 |
+
|
| 589 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 590 |
+
|
| 591 |
+
// MMA 16x8x32 TN
|
| 592 |
+
struct SM80_16x8x32_S32S8S8S32_TN
|
| 593 |
+
{
|
| 594 |
+
using DRegisters = uint32_t[4];
|
| 595 |
+
using ARegisters = uint32_t[4];
|
| 596 |
+
using BRegisters = uint32_t[2];
|
| 597 |
+
using CRegisters = uint32_t[4];
|
| 598 |
+
|
| 599 |
+
CUTE_HOST_DEVICE static void
|
| 600 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 601 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 602 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 603 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 604 |
+
{
|
| 605 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 606 |
+
asm volatile(
|
| 607 |
+
"mma.sync.aligned.m16n8k32.row.col.s32.s8.s8.s32 "
|
| 608 |
+
"{%0, %1, %2, %3},"
|
| 609 |
+
"{%4, %5, %6, %7},"
|
| 610 |
+
"{%8, %9},"
|
| 611 |
+
"{%10, %11, %12, %13};\n"
|
| 612 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 613 |
+
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 614 |
+
"r"(b0), "r"(b1),
|
| 615 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 616 |
+
#else
|
| 617 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x32_S32S8S8S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 618 |
+
#endif
|
| 619 |
+
}
|
| 620 |
+
};
|
| 621 |
+
|
| 622 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 623 |
+
|
| 624 |
+
// MMA 16x8x32 TN
|
| 625 |
+
struct SM80_16x8x32_S32S8S8S32_TN_SATURATE
|
| 626 |
+
{
|
| 627 |
+
using DRegisters = uint32_t[4];
|
| 628 |
+
using ARegisters = uint32_t[4];
|
| 629 |
+
using BRegisters = uint32_t[2];
|
| 630 |
+
using CRegisters = uint32_t[4];
|
| 631 |
+
|
| 632 |
+
CUTE_HOST_DEVICE static void
|
| 633 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 634 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 635 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 636 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 637 |
+
{
|
| 638 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 639 |
+
asm volatile(
|
| 640 |
+
"mma.sync.aligned.m16n8k32.row.col.s32.s8.s8.s32.satfinite "
|
| 641 |
+
"{%0, %1, %2, %3},"
|
| 642 |
+
"{%4, %5, %6, %7},"
|
| 643 |
+
"{%8, %9},"
|
| 644 |
+
"{%10, %11, %12, %13};\n"
|
| 645 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 646 |
+
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 647 |
+
"r"(b0), "r"(b1),
|
| 648 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 649 |
+
#else
|
| 650 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x32_S32S8S8S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 651 |
+
#endif
|
| 652 |
+
}
|
| 653 |
+
};
|
| 654 |
+
|
| 655 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 656 |
+
|
| 657 |
+
// MMA 8x8x16 TN
|
| 658 |
+
struct SM80_8x8x16_S32S8U8S32_TN
|
| 659 |
+
{
|
| 660 |
+
using DRegisters = uint32_t[2];
|
| 661 |
+
using ARegisters = uint32_t[1];
|
| 662 |
+
using BRegisters = uint32_t[1];
|
| 663 |
+
using CRegisters = uint32_t[2];
|
| 664 |
+
|
| 665 |
+
CUTE_HOST_DEVICE static void
|
| 666 |
+
fma(uint32_t & d0, uint32_t & d1,
|
| 667 |
+
uint32_t const& a0,
|
| 668 |
+
uint32_t const& b0,
|
| 669 |
+
uint32_t const& c0, uint32_t const& c1)
|
| 670 |
+
{
|
| 671 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 672 |
+
asm volatile(
|
| 673 |
+
"mma.sync.aligned.m8n8k16.row.col.s32.s8.u8.s32 "
|
| 674 |
+
"{%0, %1},"
|
| 675 |
+
"{%2},"
|
| 676 |
+
"{%3},"
|
| 677 |
+
"{%4, %5};\n"
|
| 678 |
+
: "=r"(d0), "=r"(d1)
|
| 679 |
+
: "r"(a0),
|
| 680 |
+
"r"(b0),
|
| 681 |
+
"r"(c0), "r"(c1));
|
| 682 |
+
#else
|
| 683 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_8x8x16_S32S8U8S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 684 |
+
#endif
|
| 685 |
+
}
|
| 686 |
+
};
|
| 687 |
+
|
| 688 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 689 |
+
|
| 690 |
+
// MMA 8x8x16 TN
|
| 691 |
+
struct SM80_8x8x16_S32S8U8S32_TN_SATURATE
|
| 692 |
+
{
|
| 693 |
+
using DRegisters = uint32_t[2];
|
| 694 |
+
using ARegisters = uint32_t[1];
|
| 695 |
+
using BRegisters = uint32_t[1];
|
| 696 |
+
using CRegisters = uint32_t[2];
|
| 697 |
+
|
| 698 |
+
CUTE_HOST_DEVICE static void
|
| 699 |
+
fma(uint32_t & d0, uint32_t & d1,
|
| 700 |
+
uint32_t const& a0,
|
| 701 |
+
uint32_t const& b0,
|
| 702 |
+
uint32_t const& c0, uint32_t const& c1)
|
| 703 |
+
{
|
| 704 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 705 |
+
asm volatile(
|
| 706 |
+
"mma.sync.aligned.m8n8k16.row.col.s32.s8.u8.s32.satfinite "
|
| 707 |
+
"{%0, %1},"
|
| 708 |
+
"{%2},"
|
| 709 |
+
"{%3},"
|
| 710 |
+
"{%4, %5};\n"
|
| 711 |
+
: "=r"(d0), "=r"(d1)
|
| 712 |
+
: "r"(a0),
|
| 713 |
+
"r"(b0),
|
| 714 |
+
"r"(c0), "r"(c1));
|
| 715 |
+
#else
|
| 716 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_8x8x16_S32S8U8S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 717 |
+
#endif
|
| 718 |
+
}
|
| 719 |
+
};
|
| 720 |
+
|
| 721 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 722 |
+
|
| 723 |
+
// MMA 16x8x16 TN
|
| 724 |
+
struct SM80_16x8x16_S32S8U8S32_TN
|
| 725 |
+
{
|
| 726 |
+
using DRegisters = uint32_t[4];
|
| 727 |
+
using ARegisters = uint32_t[2];
|
| 728 |
+
using BRegisters = uint32_t[1];
|
| 729 |
+
using CRegisters = uint32_t[4];
|
| 730 |
+
|
| 731 |
+
CUTE_HOST_DEVICE static void
|
| 732 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 733 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 734 |
+
uint32_t const& b0,
|
| 735 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 736 |
+
{
|
| 737 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 738 |
+
asm volatile(
|
| 739 |
+
"mma.sync.aligned.m16n8k16.row.col.s32.s8.u8.s32 "
|
| 740 |
+
"{%0, %1, %2, %3},"
|
| 741 |
+
"{%4, %5},"
|
| 742 |
+
"{%6},"
|
| 743 |
+
"{%7, %8, %9, %10};\n"
|
| 744 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 745 |
+
: "r"(a0), "r"(a1),
|
| 746 |
+
"r"(b0),
|
| 747 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 748 |
+
#else
|
| 749 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x16_S32S8U8S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 750 |
+
#endif
|
| 751 |
+
}
|
| 752 |
+
};
|
| 753 |
+
|
| 754 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 755 |
+
|
| 756 |
+
// MMA 16x8x16 TN
|
| 757 |
+
struct SM80_16x8x16_S32S8U8S32_TN_SATURATE
|
| 758 |
+
{
|
| 759 |
+
using DRegisters = uint32_t[4];
|
| 760 |
+
using ARegisters = uint32_t[2];
|
| 761 |
+
using BRegisters = uint32_t[1];
|
| 762 |
+
using CRegisters = uint32_t[4];
|
| 763 |
+
|
| 764 |
+
CUTE_HOST_DEVICE static void
|
| 765 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 766 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 767 |
+
uint32_t const& b0,
|
| 768 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 769 |
+
{
|
| 770 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 771 |
+
asm volatile(
|
| 772 |
+
"mma.sync.aligned.m16n8k16.row.col.s32.s8.u8.s32.satfinite "
|
| 773 |
+
"{%0, %1, %2, %3},"
|
| 774 |
+
"{%4, %5},"
|
| 775 |
+
"{%6},"
|
| 776 |
+
"{%7, %8, %9, %10};\n"
|
| 777 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 778 |
+
: "r"(a0), "r"(a1),
|
| 779 |
+
"r"(b0),
|
| 780 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 781 |
+
#else
|
| 782 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x16_S32S8U8S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 783 |
+
#endif
|
| 784 |
+
}
|
| 785 |
+
};
|
| 786 |
+
|
| 787 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 788 |
+
|
| 789 |
+
// MMA 16x8x32 TN
|
| 790 |
+
struct SM80_16x8x32_S32S8U8S32_TN
|
| 791 |
+
{
|
| 792 |
+
using DRegisters = uint32_t[4];
|
| 793 |
+
using ARegisters = uint32_t[4];
|
| 794 |
+
using BRegisters = uint32_t[2];
|
| 795 |
+
using CRegisters = uint32_t[4];
|
| 796 |
+
|
| 797 |
+
CUTE_HOST_DEVICE static void
|
| 798 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 799 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 800 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 801 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 802 |
+
{
|
| 803 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 804 |
+
asm volatile(
|
| 805 |
+
"mma.sync.aligned.m16n8k32.row.col.s32.s8.u8.s32 "
|
| 806 |
+
"{%0, %1, %2, %3},"
|
| 807 |
+
"{%4, %5, %6, %7},"
|
| 808 |
+
"{%8, %9},"
|
| 809 |
+
"{%10, %11, %12, %13};\n"
|
| 810 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 811 |
+
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 812 |
+
"r"(b0), "r"(b1),
|
| 813 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 814 |
+
#else
|
| 815 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x32_S32S8U8S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 816 |
+
#endif
|
| 817 |
+
}
|
| 818 |
+
};
|
| 819 |
+
|
| 820 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 821 |
+
|
| 822 |
+
// MMA 16x8x32 TN
|
| 823 |
+
struct SM80_16x8x32_S32S8U8S32_TN_SATURATE
|
| 824 |
+
{
|
| 825 |
+
using DRegisters = uint32_t[4];
|
| 826 |
+
using ARegisters = uint32_t[4];
|
| 827 |
+
using BRegisters = uint32_t[2];
|
| 828 |
+
using CRegisters = uint32_t[4];
|
| 829 |
+
|
| 830 |
+
CUTE_HOST_DEVICE static void
|
| 831 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 832 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 833 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 834 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 835 |
+
{
|
| 836 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 837 |
+
asm volatile(
|
| 838 |
+
"mma.sync.aligned.m16n8k32.row.col.s32.s8.u8.s32.satfinite "
|
| 839 |
+
"{%0, %1, %2, %3},"
|
| 840 |
+
"{%4, %5, %6, %7},"
|
| 841 |
+
"{%8, %9},"
|
| 842 |
+
"{%10, %11, %12, %13};\n"
|
| 843 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 844 |
+
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 845 |
+
"r"(b0), "r"(b1),
|
| 846 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 847 |
+
#else
|
| 848 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x32_S32S8U8S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 849 |
+
#endif
|
| 850 |
+
}
|
| 851 |
+
};
|
| 852 |
+
|
| 853 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 854 |
+
|
| 855 |
+
// MMA 8x8x16 TN
|
| 856 |
+
struct SM80_8x8x16_S32U8S8S32_TN
|
| 857 |
+
{
|
| 858 |
+
using DRegisters = uint32_t[2];
|
| 859 |
+
using ARegisters = uint32_t[1];
|
| 860 |
+
using BRegisters = uint32_t[1];
|
| 861 |
+
using CRegisters = uint32_t[2];
|
| 862 |
+
|
| 863 |
+
CUTE_HOST_DEVICE static void
|
| 864 |
+
fma(uint32_t & d0, uint32_t & d1,
|
| 865 |
+
uint32_t const& a0,
|
| 866 |
+
uint32_t const& b0,
|
| 867 |
+
uint32_t const& c0, uint32_t const& c1)
|
| 868 |
+
{
|
| 869 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 870 |
+
asm volatile(
|
| 871 |
+
"mma.sync.aligned.m8n8k16.row.col.s32.u8.s8.s32 "
|
| 872 |
+
"{%0, %1},"
|
| 873 |
+
"{%2},"
|
| 874 |
+
"{%3},"
|
| 875 |
+
"{%4, %5};\n"
|
| 876 |
+
: "=r"(d0), "=r"(d1)
|
| 877 |
+
: "r"(a0),
|
| 878 |
+
"r"(b0),
|
| 879 |
+
"r"(c0), "r"(c1));
|
| 880 |
+
#else
|
| 881 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_8x8x16_S32U8S8S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 882 |
+
#endif
|
| 883 |
+
}
|
| 884 |
+
};
|
| 885 |
+
|
| 886 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 887 |
+
|
| 888 |
+
// MMA 8x8x16 TN
|
| 889 |
+
struct SM80_8x8x16_S32U8S8S32_TN_SATURATE
|
| 890 |
+
{
|
| 891 |
+
using DRegisters = uint32_t[2];
|
| 892 |
+
using ARegisters = uint32_t[1];
|
| 893 |
+
using BRegisters = uint32_t[1];
|
| 894 |
+
using CRegisters = uint32_t[2];
|
| 895 |
+
|
| 896 |
+
CUTE_HOST_DEVICE static void
|
| 897 |
+
fma(uint32_t & d0, uint32_t & d1,
|
| 898 |
+
uint32_t const& a0,
|
| 899 |
+
uint32_t const& b0,
|
| 900 |
+
uint32_t const& c0, uint32_t const& c1)
|
| 901 |
+
{
|
| 902 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 903 |
+
asm volatile(
|
| 904 |
+
"mma.sync.aligned.m8n8k16.row.col.s32.u8.s8.s32.satfinite "
|
| 905 |
+
"{%0, %1},"
|
| 906 |
+
"{%2},"
|
| 907 |
+
"{%3},"
|
| 908 |
+
"{%4, %5};\n"
|
| 909 |
+
: "=r"(d0), "=r"(d1)
|
| 910 |
+
: "r"(a0),
|
| 911 |
+
"r"(b0),
|
| 912 |
+
"r"(c0), "r"(c1));
|
| 913 |
+
#else
|
| 914 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_8x8x16_S32U8S8S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 915 |
+
#endif
|
| 916 |
+
}
|
| 917 |
+
};
|
| 918 |
+
|
| 919 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 920 |
+
|
| 921 |
+
// MMA 16x8x16 TN
|
| 922 |
+
struct SM80_16x8x16_S32U8S8S32_TN
|
| 923 |
+
{
|
| 924 |
+
using DRegisters = uint32_t[4];
|
| 925 |
+
using ARegisters = uint32_t[2];
|
| 926 |
+
using BRegisters = uint32_t[1];
|
| 927 |
+
using CRegisters = uint32_t[4];
|
| 928 |
+
|
| 929 |
+
CUTE_HOST_DEVICE static void
|
| 930 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 931 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 932 |
+
uint32_t const& b0,
|
| 933 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 934 |
+
{
|
| 935 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 936 |
+
asm volatile(
|
| 937 |
+
"mma.sync.aligned.m16n8k16.row.col.s32.u8.s8.s32 "
|
| 938 |
+
"{%0, %1, %2, %3},"
|
| 939 |
+
"{%4, %5},"
|
| 940 |
+
"{%6},"
|
| 941 |
+
"{%7, %8, %9, %10};\n"
|
| 942 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 943 |
+
: "r"(a0), "r"(a1),
|
| 944 |
+
"r"(b0),
|
| 945 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 946 |
+
#else
|
| 947 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x16_S32U8S8S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 948 |
+
#endif
|
| 949 |
+
}
|
| 950 |
+
};
|
| 951 |
+
|
| 952 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 953 |
+
|
| 954 |
+
// MMA 16x8x16 TN
|
| 955 |
+
struct SM80_16x8x16_S32U8S8S32_TN_SATURATE
|
| 956 |
+
{
|
| 957 |
+
using DRegisters = uint32_t[4];
|
| 958 |
+
using ARegisters = uint32_t[2];
|
| 959 |
+
using BRegisters = uint32_t[1];
|
| 960 |
+
using CRegisters = uint32_t[4];
|
| 961 |
+
|
| 962 |
+
CUTE_HOST_DEVICE static void
|
| 963 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 964 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 965 |
+
uint32_t const& b0,
|
| 966 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 967 |
+
{
|
| 968 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 969 |
+
asm volatile(
|
| 970 |
+
"mma.sync.aligned.m16n8k16.row.col.s32.u8.s8.s32.satfinite "
|
| 971 |
+
"{%0, %1, %2, %3},"
|
| 972 |
+
"{%4, %5},"
|
| 973 |
+
"{%6},"
|
| 974 |
+
"{%7, %8, %9, %10};\n"
|
| 975 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 976 |
+
: "r"(a0), "r"(a1),
|
| 977 |
+
"r"(b0),
|
| 978 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 979 |
+
#else
|
| 980 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x16_S32U8S8S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 981 |
+
#endif
|
| 982 |
+
}
|
| 983 |
+
};
|
| 984 |
+
|
| 985 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 986 |
+
|
| 987 |
+
// MMA 16x8x32 TN
|
| 988 |
+
struct SM80_16x8x32_S32U8S8S32_TN
|
| 989 |
+
{
|
| 990 |
+
using DRegisters = uint32_t[4];
|
| 991 |
+
using ARegisters = uint32_t[4];
|
| 992 |
+
using BRegisters = uint32_t[2];
|
| 993 |
+
using CRegisters = uint32_t[4];
|
| 994 |
+
|
| 995 |
+
CUTE_HOST_DEVICE static void
|
| 996 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 997 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 998 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 999 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 1000 |
+
{
|
| 1001 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1002 |
+
asm volatile(
|
| 1003 |
+
"mma.sync.aligned.m16n8k32.row.col.s32.u8.s8.s32 "
|
| 1004 |
+
"{%0, %1, %2, %3},"
|
| 1005 |
+
"{%4, %5, %6, %7},"
|
| 1006 |
+
"{%8, %9},"
|
| 1007 |
+
"{%10, %11, %12, %13};\n"
|
| 1008 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 1009 |
+
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 1010 |
+
"r"(b0), "r"(b1),
|
| 1011 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 1012 |
+
#else
|
| 1013 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x32_S32U8S8S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1014 |
+
#endif
|
| 1015 |
+
}
|
| 1016 |
+
};
|
| 1017 |
+
|
| 1018 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1019 |
+
|
| 1020 |
+
// MMA 16x8x32 TN
|
| 1021 |
+
struct SM80_16x8x32_S32U8S8S32_TN_SATURATE
|
| 1022 |
+
{
|
| 1023 |
+
using DRegisters = uint32_t[4];
|
| 1024 |
+
using ARegisters = uint32_t[4];
|
| 1025 |
+
using BRegisters = uint32_t[2];
|
| 1026 |
+
using CRegisters = uint32_t[4];
|
| 1027 |
+
|
| 1028 |
+
CUTE_HOST_DEVICE static void
|
| 1029 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 1030 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 1031 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 1032 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 1033 |
+
{
|
| 1034 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1035 |
+
asm volatile(
|
| 1036 |
+
"mma.sync.aligned.m16n8k32.row.col.s32.u8.s8.s32.satfinite "
|
| 1037 |
+
"{%0, %1, %2, %3},"
|
| 1038 |
+
"{%4, %5, %6, %7},"
|
| 1039 |
+
"{%8, %9},"
|
| 1040 |
+
"{%10, %11, %12, %13};\n"
|
| 1041 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 1042 |
+
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 1043 |
+
"r"(b0), "r"(b1),
|
| 1044 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 1045 |
+
#else
|
| 1046 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x32_S32U8S8S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1047 |
+
#endif
|
| 1048 |
+
}
|
| 1049 |
+
};
|
| 1050 |
+
|
| 1051 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1052 |
+
|
| 1053 |
+
// MMA 8x8x16 TN
|
| 1054 |
+
struct SM80_8x8x16_S32U8U8S32_TN
|
| 1055 |
+
{
|
| 1056 |
+
using DRegisters = uint32_t[2];
|
| 1057 |
+
using ARegisters = uint32_t[1];
|
| 1058 |
+
using BRegisters = uint32_t[1];
|
| 1059 |
+
using CRegisters = uint32_t[2];
|
| 1060 |
+
|
| 1061 |
+
CUTE_HOST_DEVICE static void
|
| 1062 |
+
fma(uint32_t & d0, uint32_t & d1,
|
| 1063 |
+
uint32_t const& a0,
|
| 1064 |
+
uint32_t const& b0,
|
| 1065 |
+
uint32_t const& c0, uint32_t const& c1)
|
| 1066 |
+
{
|
| 1067 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1068 |
+
asm volatile(
|
| 1069 |
+
"mma.sync.aligned.m8n8k16.row.col.s32.u8.u8.s32 "
|
| 1070 |
+
"{%0, %1},"
|
| 1071 |
+
"{%2},"
|
| 1072 |
+
"{%3},"
|
| 1073 |
+
"{%4, %5};\n"
|
| 1074 |
+
: "=r"(d0), "=r"(d1)
|
| 1075 |
+
: "r"(a0),
|
| 1076 |
+
"r"(b0),
|
| 1077 |
+
"r"(c0), "r"(c1));
|
| 1078 |
+
#else
|
| 1079 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_8x8x16_S32U8U8S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1080 |
+
#endif
|
| 1081 |
+
}
|
| 1082 |
+
};
|
| 1083 |
+
|
| 1084 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1085 |
+
|
| 1086 |
+
// MMA 8x8x16 TN
|
| 1087 |
+
struct SM80_8x8x16_S32U8U8S32_TN_SATURATE
|
| 1088 |
+
{
|
| 1089 |
+
using DRegisters = uint32_t[2];
|
| 1090 |
+
using ARegisters = uint32_t[1];
|
| 1091 |
+
using BRegisters = uint32_t[1];
|
| 1092 |
+
using CRegisters = uint32_t[2];
|
| 1093 |
+
|
| 1094 |
+
CUTE_HOST_DEVICE static void
|
| 1095 |
+
fma(uint32_t & d0, uint32_t & d1,
|
| 1096 |
+
uint32_t const& a0,
|
| 1097 |
+
uint32_t const& b0,
|
| 1098 |
+
uint32_t const& c0, uint32_t const& c1)
|
| 1099 |
+
{
|
| 1100 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1101 |
+
asm volatile(
|
| 1102 |
+
"mma.sync.aligned.m8n8k16.row.col.s32.u8.u8.s32.satfinite "
|
| 1103 |
+
"{%0, %1},"
|
| 1104 |
+
"{%2},"
|
| 1105 |
+
"{%3},"
|
| 1106 |
+
"{%4, %5};\n"
|
| 1107 |
+
: "=r"(d0), "=r"(d1)
|
| 1108 |
+
: "r"(a0),
|
| 1109 |
+
"r"(b0),
|
| 1110 |
+
"r"(c0), "r"(c1));
|
| 1111 |
+
#else
|
| 1112 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_8x8x16_S32U8U8S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1113 |
+
#endif
|
| 1114 |
+
}
|
| 1115 |
+
};
|
| 1116 |
+
|
| 1117 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1118 |
+
|
| 1119 |
+
// MMA 16x8x16 TN
|
| 1120 |
+
struct SM80_16x8x16_S32U8U8S32_TN
|
| 1121 |
+
{
|
| 1122 |
+
using DRegisters = uint32_t[4];
|
| 1123 |
+
using ARegisters = uint32_t[2];
|
| 1124 |
+
using BRegisters = uint32_t[1];
|
| 1125 |
+
using CRegisters = uint32_t[4];
|
| 1126 |
+
|
| 1127 |
+
CUTE_HOST_DEVICE static void
|
| 1128 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 1129 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 1130 |
+
uint32_t const& b0,
|
| 1131 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 1132 |
+
{
|
| 1133 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1134 |
+
asm volatile(
|
| 1135 |
+
"mma.sync.aligned.m16n8k16.row.col.s32.u8.u8.s32 "
|
| 1136 |
+
"{%0, %1, %2, %3},"
|
| 1137 |
+
"{%4, %5},"
|
| 1138 |
+
"{%6},"
|
| 1139 |
+
"{%7, %8, %9, %10};\n"
|
| 1140 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 1141 |
+
: "r"(a0), "r"(a1),
|
| 1142 |
+
"r"(b0),
|
| 1143 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 1144 |
+
#else
|
| 1145 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x16_S32U8U8S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1146 |
+
#endif
|
| 1147 |
+
}
|
| 1148 |
+
};
|
| 1149 |
+
|
| 1150 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1151 |
+
|
| 1152 |
+
// MMA 16x8x16 TN
|
| 1153 |
+
struct SM80_16x8x16_S32U8U8S32_TN_SATURATE
|
| 1154 |
+
{
|
| 1155 |
+
using DRegisters = uint32_t[4];
|
| 1156 |
+
using ARegisters = uint32_t[2];
|
| 1157 |
+
using BRegisters = uint32_t[1];
|
| 1158 |
+
using CRegisters = uint32_t[4];
|
| 1159 |
+
|
| 1160 |
+
CUTE_HOST_DEVICE static void
|
| 1161 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 1162 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 1163 |
+
uint32_t const& b0,
|
| 1164 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 1165 |
+
{
|
| 1166 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1167 |
+
asm volatile(
|
| 1168 |
+
"mma.sync.aligned.m16n8k16.row.col.s32.u8.u8.s32.satfinite "
|
| 1169 |
+
"{%0, %1, %2, %3},"
|
| 1170 |
+
"{%4, %5},"
|
| 1171 |
+
"{%6},"
|
| 1172 |
+
"{%7, %8, %9, %10};\n"
|
| 1173 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 1174 |
+
: "r"(a0), "r"(a1),
|
| 1175 |
+
"r"(b0),
|
| 1176 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 1177 |
+
#else
|
| 1178 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x16_S32U8U8S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1179 |
+
#endif
|
| 1180 |
+
}
|
| 1181 |
+
};
|
| 1182 |
+
|
| 1183 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1184 |
+
|
| 1185 |
+
// MMA 16x8x32 TN
|
| 1186 |
+
struct SM80_16x8x32_S32U8U8S32_TN
|
| 1187 |
+
{
|
| 1188 |
+
using DRegisters = uint32_t[4];
|
| 1189 |
+
using ARegisters = uint32_t[4];
|
| 1190 |
+
using BRegisters = uint32_t[2];
|
| 1191 |
+
using CRegisters = uint32_t[4];
|
| 1192 |
+
|
| 1193 |
+
CUTE_HOST_DEVICE static void
|
| 1194 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 1195 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 1196 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 1197 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 1198 |
+
{
|
| 1199 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1200 |
+
asm volatile(
|
| 1201 |
+
"mma.sync.aligned.m16n8k32.row.col.s32.u8.u8.s32 "
|
| 1202 |
+
"{%0, %1, %2, %3},"
|
| 1203 |
+
"{%4, %5, %6, %7},"
|
| 1204 |
+
"{%8, %9},"
|
| 1205 |
+
"{%10, %11, %12, %13};\n"
|
| 1206 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 1207 |
+
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 1208 |
+
"r"(b0), "r"(b1),
|
| 1209 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 1210 |
+
#else
|
| 1211 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x32_S32U8U8S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1212 |
+
#endif
|
| 1213 |
+
}
|
| 1214 |
+
};
|
| 1215 |
+
|
| 1216 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1217 |
+
|
| 1218 |
+
// MMA 16x8x32 TN
|
| 1219 |
+
struct SM80_16x8x32_S32U8U8S32_TN_SATURATE
|
| 1220 |
+
{
|
| 1221 |
+
using DRegisters = uint32_t[4];
|
| 1222 |
+
using ARegisters = uint32_t[4];
|
| 1223 |
+
using BRegisters = uint32_t[2];
|
| 1224 |
+
using CRegisters = uint32_t[4];
|
| 1225 |
+
|
| 1226 |
+
CUTE_HOST_DEVICE static void
|
| 1227 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 1228 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 1229 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 1230 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 1231 |
+
{
|
| 1232 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1233 |
+
asm volatile(
|
| 1234 |
+
"mma.sync.aligned.m16n8k32.row.col.s32.u8.u8.s32.satfinite "
|
| 1235 |
+
"{%0, %1, %2, %3},"
|
| 1236 |
+
"{%4, %5, %6, %7},"
|
| 1237 |
+
"{%8, %9},"
|
| 1238 |
+
"{%10, %11, %12, %13};\n"
|
| 1239 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 1240 |
+
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 1241 |
+
"r"(b0), "r"(b1),
|
| 1242 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 1243 |
+
#else
|
| 1244 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x32_S32U8U8S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1245 |
+
#endif
|
| 1246 |
+
}
|
| 1247 |
+
};
|
| 1248 |
+
|
| 1249 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1250 |
+
|
| 1251 |
+
// MMA 8x8x32 TN
|
| 1252 |
+
struct SM80_8x8x32_S32S4S4S32_TN
|
| 1253 |
+
{
|
| 1254 |
+
using DRegisters = uint32_t[2];
|
| 1255 |
+
using ARegisters = uint32_t[1];
|
| 1256 |
+
using BRegisters = uint32_t[1];
|
| 1257 |
+
using CRegisters = uint32_t[2];
|
| 1258 |
+
|
| 1259 |
+
CUTE_HOST_DEVICE static void
|
| 1260 |
+
fma(uint32_t & d0, uint32_t & d1,
|
| 1261 |
+
uint32_t const& a0,
|
| 1262 |
+
uint32_t const& b0,
|
| 1263 |
+
uint32_t const& c0, uint32_t const& c1)
|
| 1264 |
+
{
|
| 1265 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1266 |
+
asm volatile(
|
| 1267 |
+
"mma.sync.aligned.m8n8k32.row.col.s32.s4.s4.s32 "
|
| 1268 |
+
"{%0, %1},"
|
| 1269 |
+
"{%2},"
|
| 1270 |
+
"{%3},"
|
| 1271 |
+
"{%4, %5};\n"
|
| 1272 |
+
: "=r"(d0), "=r"(d1)
|
| 1273 |
+
: "r"(a0),
|
| 1274 |
+
"r"(b0),
|
| 1275 |
+
"r"(c0), "r"(c1));
|
| 1276 |
+
#else
|
| 1277 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_8x8x32_S32S4S4S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1278 |
+
#endif
|
| 1279 |
+
}
|
| 1280 |
+
};
|
| 1281 |
+
|
| 1282 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1283 |
+
|
| 1284 |
+
// MMA 8x8x32 TN
|
| 1285 |
+
struct SM80_8x8x32_S32S4S4S32_TN_SATURATE
|
| 1286 |
+
{
|
| 1287 |
+
using DRegisters = uint32_t[2];
|
| 1288 |
+
using ARegisters = uint32_t[1];
|
| 1289 |
+
using BRegisters = uint32_t[1];
|
| 1290 |
+
using CRegisters = uint32_t[2];
|
| 1291 |
+
|
| 1292 |
+
CUTE_HOST_DEVICE static void
|
| 1293 |
+
fma(uint32_t & d0, uint32_t & d1,
|
| 1294 |
+
uint32_t const& a0,
|
| 1295 |
+
uint32_t const& b0,
|
| 1296 |
+
uint32_t const& c0, uint32_t const& c1)
|
| 1297 |
+
{
|
| 1298 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1299 |
+
asm volatile(
|
| 1300 |
+
"mma.sync.aligned.m8n8k32.row.col.s32.s4.s4.s32.satfinite "
|
| 1301 |
+
"{%0, %1},"
|
| 1302 |
+
"{%2},"
|
| 1303 |
+
"{%3},"
|
| 1304 |
+
"{%4, %5};\n"
|
| 1305 |
+
: "=r"(d0), "=r"(d1)
|
| 1306 |
+
: "r"(a0),
|
| 1307 |
+
"r"(b0),
|
| 1308 |
+
"r"(c0), "r"(c1));
|
| 1309 |
+
#else
|
| 1310 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_8x8x32_S32S4S4S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1311 |
+
#endif
|
| 1312 |
+
}
|
| 1313 |
+
};
|
| 1314 |
+
|
| 1315 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1316 |
+
|
| 1317 |
+
// MMA 16x8x32 TN
|
| 1318 |
+
struct SM80_16x8x32_S32S4S4S32_TN
|
| 1319 |
+
{
|
| 1320 |
+
using DRegisters = uint32_t[4];
|
| 1321 |
+
using ARegisters = uint32_t[2];
|
| 1322 |
+
using BRegisters = uint32_t[1];
|
| 1323 |
+
using CRegisters = uint32_t[4];
|
| 1324 |
+
|
| 1325 |
+
CUTE_HOST_DEVICE static void
|
| 1326 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 1327 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 1328 |
+
uint32_t const& b0,
|
| 1329 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 1330 |
+
{
|
| 1331 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1332 |
+
asm volatile(
|
| 1333 |
+
"mma.sync.aligned.m16n8k32.row.col.s32.s4.s4.s32 "
|
| 1334 |
+
"{%0, %1, %2, %3},"
|
| 1335 |
+
"{%4, %5},"
|
| 1336 |
+
"{%6},"
|
| 1337 |
+
"{%7, %8, %9, %10};\n"
|
| 1338 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 1339 |
+
: "r"(a0), "r"(a1),
|
| 1340 |
+
"r"(b0),
|
| 1341 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 1342 |
+
#else
|
| 1343 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x32_S32S4S4S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1344 |
+
#endif
|
| 1345 |
+
}
|
| 1346 |
+
};
|
| 1347 |
+
|
| 1348 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1349 |
+
|
| 1350 |
+
// MMA 16x8x32 TN
|
| 1351 |
+
struct SM80_16x8x32_S32S4S4S32_TN_SATURATE
|
| 1352 |
+
{
|
| 1353 |
+
using DRegisters = uint32_t[4];
|
| 1354 |
+
using ARegisters = uint32_t[2];
|
| 1355 |
+
using BRegisters = uint32_t[1];
|
| 1356 |
+
using CRegisters = uint32_t[4];
|
| 1357 |
+
|
| 1358 |
+
CUTE_HOST_DEVICE static void
|
| 1359 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 1360 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 1361 |
+
uint32_t const& b0,
|
| 1362 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 1363 |
+
{
|
| 1364 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1365 |
+
asm volatile(
|
| 1366 |
+
"mma.sync.aligned.m16n8k32.row.col.s32.s4.s4.s32.satfinite "
|
| 1367 |
+
"{%0, %1, %2, %3},"
|
| 1368 |
+
"{%4, %5},"
|
| 1369 |
+
"{%6},"
|
| 1370 |
+
"{%7, %8, %9, %10};\n"
|
| 1371 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 1372 |
+
: "r"(a0), "r"(a1),
|
| 1373 |
+
"r"(b0),
|
| 1374 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 1375 |
+
#else
|
| 1376 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x32_S32S4S4S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1377 |
+
#endif
|
| 1378 |
+
}
|
| 1379 |
+
};
|
| 1380 |
+
|
| 1381 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1382 |
+
|
| 1383 |
+
// MMA 16x8x64 TN
|
| 1384 |
+
struct SM80_16x8x64_S32S4S4S32_TN
|
| 1385 |
+
{
|
| 1386 |
+
using DRegisters = uint32_t[4];
|
| 1387 |
+
using ARegisters = uint32_t[4];
|
| 1388 |
+
using BRegisters = uint32_t[2];
|
| 1389 |
+
using CRegisters = uint32_t[4];
|
| 1390 |
+
|
| 1391 |
+
CUTE_HOST_DEVICE static void
|
| 1392 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 1393 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 1394 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 1395 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 1396 |
+
{
|
| 1397 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1398 |
+
asm volatile(
|
| 1399 |
+
"mma.sync.aligned.m16n8k64.row.col.s32.s4.s4.s32 "
|
| 1400 |
+
"{%0, %1, %2, %3},"
|
| 1401 |
+
"{%4, %5, %6, %7},"
|
| 1402 |
+
"{%8, %9},"
|
| 1403 |
+
"{%10, %11, %12, %13};\n"
|
| 1404 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 1405 |
+
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 1406 |
+
"r"(b0), "r"(b1),
|
| 1407 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 1408 |
+
#else
|
| 1409 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x64_S32S4S4S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1410 |
+
#endif
|
| 1411 |
+
}
|
| 1412 |
+
};
|
| 1413 |
+
|
| 1414 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1415 |
+
|
| 1416 |
+
// MMA 16x8x64 TN
|
| 1417 |
+
struct SM80_16x8x64_S32S4S4S32_TN_SATURATE
|
| 1418 |
+
{
|
| 1419 |
+
using DRegisters = uint32_t[4];
|
| 1420 |
+
using ARegisters = uint32_t[4];
|
| 1421 |
+
using BRegisters = uint32_t[2];
|
| 1422 |
+
using CRegisters = uint32_t[4];
|
| 1423 |
+
|
| 1424 |
+
CUTE_HOST_DEVICE static void
|
| 1425 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 1426 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 1427 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 1428 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 1429 |
+
{
|
| 1430 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1431 |
+
asm volatile(
|
| 1432 |
+
"mma.sync.aligned.m16n8k64.row.col.s32.s4.s4.s32.satfinite "
|
| 1433 |
+
"{%0, %1, %2, %3},"
|
| 1434 |
+
"{%4, %5, %6, %7},"
|
| 1435 |
+
"{%8, %9},"
|
| 1436 |
+
"{%10, %11, %12, %13};\n"
|
| 1437 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 1438 |
+
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 1439 |
+
"r"(b0), "r"(b1),
|
| 1440 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 1441 |
+
#else
|
| 1442 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x64_S32S4S4S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1443 |
+
#endif
|
| 1444 |
+
}
|
| 1445 |
+
};
|
| 1446 |
+
|
| 1447 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1448 |
+
|
| 1449 |
+
// MMA 8x8x32 TN
|
| 1450 |
+
struct SM80_8x8x32_S32S4U4S32_TN
|
| 1451 |
+
{
|
| 1452 |
+
using DRegisters = uint32_t[2];
|
| 1453 |
+
using ARegisters = uint32_t[1];
|
| 1454 |
+
using BRegisters = uint32_t[1];
|
| 1455 |
+
using CRegisters = uint32_t[2];
|
| 1456 |
+
|
| 1457 |
+
CUTE_HOST_DEVICE static void
|
| 1458 |
+
fma(uint32_t & d0, uint32_t & d1,
|
| 1459 |
+
uint32_t const& a0,
|
| 1460 |
+
uint32_t const& b0,
|
| 1461 |
+
uint32_t const& c0, uint32_t const& c1)
|
| 1462 |
+
{
|
| 1463 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1464 |
+
asm volatile(
|
| 1465 |
+
"mma.sync.aligned.m8n8k32.row.col.s32.s4.u4.s32 "
|
| 1466 |
+
"{%0, %1},"
|
| 1467 |
+
"{%2},"
|
| 1468 |
+
"{%3},"
|
| 1469 |
+
"{%4, %5};\n"
|
| 1470 |
+
: "=r"(d0), "=r"(d1)
|
| 1471 |
+
: "r"(a0),
|
| 1472 |
+
"r"(b0),
|
| 1473 |
+
"r"(c0), "r"(c1));
|
| 1474 |
+
#else
|
| 1475 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_8x8x32_S32S4U4S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1476 |
+
#endif
|
| 1477 |
+
}
|
| 1478 |
+
};
|
| 1479 |
+
|
| 1480 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1481 |
+
|
| 1482 |
+
// MMA 8x8x32 TN
|
| 1483 |
+
struct SM80_8x8x32_S32S4U4S32_TN_SATURATE
|
| 1484 |
+
{
|
| 1485 |
+
using DRegisters = uint32_t[2];
|
| 1486 |
+
using ARegisters = uint32_t[1];
|
| 1487 |
+
using BRegisters = uint32_t[1];
|
| 1488 |
+
using CRegisters = uint32_t[2];
|
| 1489 |
+
|
| 1490 |
+
CUTE_HOST_DEVICE static void
|
| 1491 |
+
fma(uint32_t & d0, uint32_t & d1,
|
| 1492 |
+
uint32_t const& a0,
|
| 1493 |
+
uint32_t const& b0,
|
| 1494 |
+
uint32_t const& c0, uint32_t const& c1)
|
| 1495 |
+
{
|
| 1496 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1497 |
+
asm volatile(
|
| 1498 |
+
"mma.sync.aligned.m8n8k32.row.col.s32.s4.u4.s32.satfinite "
|
| 1499 |
+
"{%0, %1},"
|
| 1500 |
+
"{%2},"
|
| 1501 |
+
"{%3},"
|
| 1502 |
+
"{%4, %5};\n"
|
| 1503 |
+
: "=r"(d0), "=r"(d1)
|
| 1504 |
+
: "r"(a0),
|
| 1505 |
+
"r"(b0),
|
| 1506 |
+
"r"(c0), "r"(c1));
|
| 1507 |
+
#else
|
| 1508 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_8x8x32_S32S4U4S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1509 |
+
#endif
|
| 1510 |
+
}
|
| 1511 |
+
};
|
| 1512 |
+
|
| 1513 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1514 |
+
|
| 1515 |
+
// MMA 16x8x32 TN
|
| 1516 |
+
struct SM80_16x8x32_S32S4U4S32_TN
|
| 1517 |
+
{
|
| 1518 |
+
using DRegisters = uint32_t[4];
|
| 1519 |
+
using ARegisters = uint32_t[2];
|
| 1520 |
+
using BRegisters = uint32_t[1];
|
| 1521 |
+
using CRegisters = uint32_t[4];
|
| 1522 |
+
|
| 1523 |
+
CUTE_HOST_DEVICE static void
|
| 1524 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 1525 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 1526 |
+
uint32_t const& b0,
|
| 1527 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 1528 |
+
{
|
| 1529 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1530 |
+
asm volatile(
|
| 1531 |
+
"mma.sync.aligned.m16n8k32.row.col.s32.s4.u4.s32 "
|
| 1532 |
+
"{%0, %1, %2, %3},"
|
| 1533 |
+
"{%4, %5},"
|
| 1534 |
+
"{%6},"
|
| 1535 |
+
"{%7, %8, %9, %10};\n"
|
| 1536 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 1537 |
+
: "r"(a0), "r"(a1),
|
| 1538 |
+
"r"(b0),
|
| 1539 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 1540 |
+
#else
|
| 1541 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x32_S32S4U4S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1542 |
+
#endif
|
| 1543 |
+
}
|
| 1544 |
+
};
|
| 1545 |
+
|
| 1546 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1547 |
+
|
| 1548 |
+
// MMA 16x8x32 TN
|
| 1549 |
+
struct SM80_16x8x32_S32S4U4S32_TN_SATURATE
|
| 1550 |
+
{
|
| 1551 |
+
using DRegisters = uint32_t[4];
|
| 1552 |
+
using ARegisters = uint32_t[2];
|
| 1553 |
+
using BRegisters = uint32_t[1];
|
| 1554 |
+
using CRegisters = uint32_t[4];
|
| 1555 |
+
|
| 1556 |
+
CUTE_HOST_DEVICE static void
|
| 1557 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 1558 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 1559 |
+
uint32_t const& b0,
|
| 1560 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 1561 |
+
{
|
| 1562 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1563 |
+
asm volatile(
|
| 1564 |
+
"mma.sync.aligned.m16n8k32.row.col.s32.s4.u4.s32.satfinite "
|
| 1565 |
+
"{%0, %1, %2, %3},"
|
| 1566 |
+
"{%4, %5},"
|
| 1567 |
+
"{%6},"
|
| 1568 |
+
"{%7, %8, %9, %10};\n"
|
| 1569 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 1570 |
+
: "r"(a0), "r"(a1),
|
| 1571 |
+
"r"(b0),
|
| 1572 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 1573 |
+
#else
|
| 1574 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x32_S32S4U4S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1575 |
+
#endif
|
| 1576 |
+
}
|
| 1577 |
+
};
|
| 1578 |
+
|
| 1579 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1580 |
+
|
| 1581 |
+
// MMA 16x8x64 TN
|
| 1582 |
+
struct SM80_16x8x64_S32S4U4S32_TN
|
| 1583 |
+
{
|
| 1584 |
+
using DRegisters = uint32_t[4];
|
| 1585 |
+
using ARegisters = uint32_t[4];
|
| 1586 |
+
using BRegisters = uint32_t[2];
|
| 1587 |
+
using CRegisters = uint32_t[4];
|
| 1588 |
+
|
| 1589 |
+
CUTE_HOST_DEVICE static void
|
| 1590 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 1591 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 1592 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 1593 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 1594 |
+
{
|
| 1595 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1596 |
+
asm volatile(
|
| 1597 |
+
"mma.sync.aligned.m16n8k64.row.col.s32.s4.u4.s32 "
|
| 1598 |
+
"{%0, %1, %2, %3},"
|
| 1599 |
+
"{%4, %5, %6, %7},"
|
| 1600 |
+
"{%8, %9},"
|
| 1601 |
+
"{%10, %11, %12, %13};\n"
|
| 1602 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 1603 |
+
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 1604 |
+
"r"(b0), "r"(b1),
|
| 1605 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 1606 |
+
#else
|
| 1607 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x64_S32S4U4S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1608 |
+
#endif
|
| 1609 |
+
}
|
| 1610 |
+
};
|
| 1611 |
+
|
| 1612 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1613 |
+
|
| 1614 |
+
// MMA 16x8x64 TN
|
| 1615 |
+
struct SM80_16x8x64_S32S4U4S32_TN_SATURATE
|
| 1616 |
+
{
|
| 1617 |
+
using DRegisters = uint32_t[4];
|
| 1618 |
+
using ARegisters = uint32_t[4];
|
| 1619 |
+
using BRegisters = uint32_t[2];
|
| 1620 |
+
using CRegisters = uint32_t[4];
|
| 1621 |
+
|
| 1622 |
+
CUTE_HOST_DEVICE static void
|
| 1623 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 1624 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 1625 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 1626 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 1627 |
+
{
|
| 1628 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1629 |
+
asm volatile(
|
| 1630 |
+
"mma.sync.aligned.m16n8k64.row.col.s32.s4.u4.s32.satfinite "
|
| 1631 |
+
"{%0, %1, %2, %3},"
|
| 1632 |
+
"{%4, %5, %6, %7},"
|
| 1633 |
+
"{%8, %9},"
|
| 1634 |
+
"{%10, %11, %12, %13};\n"
|
| 1635 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 1636 |
+
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 1637 |
+
"r"(b0), "r"(b1),
|
| 1638 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 1639 |
+
#else
|
| 1640 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x64_S32S4U4S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1641 |
+
#endif
|
| 1642 |
+
}
|
| 1643 |
+
};
|
| 1644 |
+
|
| 1645 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1646 |
+
|
| 1647 |
+
// MMA 8x8x32 TN
|
| 1648 |
+
struct SM80_8x8x32_S32U4S4S32_TN
|
| 1649 |
+
{
|
| 1650 |
+
using DRegisters = uint32_t[2];
|
| 1651 |
+
using ARegisters = uint32_t[1];
|
| 1652 |
+
using BRegisters = uint32_t[1];
|
| 1653 |
+
using CRegisters = uint32_t[2];
|
| 1654 |
+
|
| 1655 |
+
CUTE_HOST_DEVICE static void
|
| 1656 |
+
fma(uint32_t & d0, uint32_t & d1,
|
| 1657 |
+
uint32_t const& a0,
|
| 1658 |
+
uint32_t const& b0,
|
| 1659 |
+
uint32_t const& c0, uint32_t const& c1)
|
| 1660 |
+
{
|
| 1661 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1662 |
+
asm volatile(
|
| 1663 |
+
"mma.sync.aligned.m8n8k32.row.col.s32.u4.s4.s32 "
|
| 1664 |
+
"{%0, %1},"
|
| 1665 |
+
"{%2},"
|
| 1666 |
+
"{%3},"
|
| 1667 |
+
"{%4, %5};\n"
|
| 1668 |
+
: "=r"(d0), "=r"(d1)
|
| 1669 |
+
: "r"(a0),
|
| 1670 |
+
"r"(b0),
|
| 1671 |
+
"r"(c0), "r"(c1));
|
| 1672 |
+
#else
|
| 1673 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_8x8x32_S32U4S4S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1674 |
+
#endif
|
| 1675 |
+
}
|
| 1676 |
+
};
|
| 1677 |
+
|
| 1678 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1679 |
+
|
| 1680 |
+
// MMA 8x8x32 TN
|
| 1681 |
+
struct SM80_8x8x32_S32U4S4S32_TN_SATURATE
|
| 1682 |
+
{
|
| 1683 |
+
using DRegisters = uint32_t[2];
|
| 1684 |
+
using ARegisters = uint32_t[1];
|
| 1685 |
+
using BRegisters = uint32_t[1];
|
| 1686 |
+
using CRegisters = uint32_t[2];
|
| 1687 |
+
|
| 1688 |
+
CUTE_HOST_DEVICE static void
|
| 1689 |
+
fma(uint32_t & d0, uint32_t & d1,
|
| 1690 |
+
uint32_t const& a0,
|
| 1691 |
+
uint32_t const& b0,
|
| 1692 |
+
uint32_t const& c0, uint32_t const& c1)
|
| 1693 |
+
{
|
| 1694 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1695 |
+
asm volatile(
|
| 1696 |
+
"mma.sync.aligned.m8n8k32.row.col.s32.u4.s4.s32.satfinite "
|
| 1697 |
+
"{%0, %1},"
|
| 1698 |
+
"{%2},"
|
| 1699 |
+
"{%3},"
|
| 1700 |
+
"{%4, %5};\n"
|
| 1701 |
+
: "=r"(d0), "=r"(d1)
|
| 1702 |
+
: "r"(a0),
|
| 1703 |
+
"r"(b0),
|
| 1704 |
+
"r"(c0), "r"(c1));
|
| 1705 |
+
#else
|
| 1706 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_8x8x32_S32U4S4S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1707 |
+
#endif
|
| 1708 |
+
}
|
| 1709 |
+
};
|
| 1710 |
+
|
| 1711 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1712 |
+
|
| 1713 |
+
// MMA 16x8x32 TN
|
| 1714 |
+
struct SM80_16x8x32_S32U4S4S32_TN
|
| 1715 |
+
{
|
| 1716 |
+
using DRegisters = uint32_t[4];
|
| 1717 |
+
using ARegisters = uint32_t[2];
|
| 1718 |
+
using BRegisters = uint32_t[1];
|
| 1719 |
+
using CRegisters = uint32_t[4];
|
| 1720 |
+
|
| 1721 |
+
CUTE_HOST_DEVICE static void
|
| 1722 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 1723 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 1724 |
+
uint32_t const& b0,
|
| 1725 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 1726 |
+
{
|
| 1727 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1728 |
+
asm volatile(
|
| 1729 |
+
"mma.sync.aligned.m16n8k32.row.col.s32.u4.s4.s32 "
|
| 1730 |
+
"{%0, %1, %2, %3},"
|
| 1731 |
+
"{%4, %5},"
|
| 1732 |
+
"{%6},"
|
| 1733 |
+
"{%7, %8, %9, %10};\n"
|
| 1734 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 1735 |
+
: "r"(a0), "r"(a1),
|
| 1736 |
+
"r"(b0),
|
| 1737 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 1738 |
+
#else
|
| 1739 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x32_S32U4S4S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1740 |
+
#endif
|
| 1741 |
+
}
|
| 1742 |
+
};
|
| 1743 |
+
|
| 1744 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1745 |
+
|
| 1746 |
+
// MMA 16x8x32 TN
|
| 1747 |
+
struct SM80_16x8x32_S32U4S4S32_TN_SATURATE
|
| 1748 |
+
{
|
| 1749 |
+
using DRegisters = uint32_t[4];
|
| 1750 |
+
using ARegisters = uint32_t[2];
|
| 1751 |
+
using BRegisters = uint32_t[1];
|
| 1752 |
+
using CRegisters = uint32_t[4];
|
| 1753 |
+
|
| 1754 |
+
CUTE_HOST_DEVICE static void
|
| 1755 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 1756 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 1757 |
+
uint32_t const& b0,
|
| 1758 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 1759 |
+
{
|
| 1760 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1761 |
+
asm volatile(
|
| 1762 |
+
"mma.sync.aligned.m16n8k32.row.col.s32.u4.s4.s32.satfinite "
|
| 1763 |
+
"{%0, %1, %2, %3},"
|
| 1764 |
+
"{%4, %5},"
|
| 1765 |
+
"{%6},"
|
| 1766 |
+
"{%7, %8, %9, %10};\n"
|
| 1767 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 1768 |
+
: "r"(a0), "r"(a1),
|
| 1769 |
+
"r"(b0),
|
| 1770 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 1771 |
+
#else
|
| 1772 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x32_S32U4S4S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1773 |
+
#endif
|
| 1774 |
+
}
|
| 1775 |
+
};
|
| 1776 |
+
|
| 1777 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1778 |
+
|
| 1779 |
+
// MMA 16x8x64 TN
|
| 1780 |
+
struct SM80_16x8x64_S32U4S4S32_TN
|
| 1781 |
+
{
|
| 1782 |
+
using DRegisters = uint32_t[4];
|
| 1783 |
+
using ARegisters = uint32_t[4];
|
| 1784 |
+
using BRegisters = uint32_t[2];
|
| 1785 |
+
using CRegisters = uint32_t[4];
|
| 1786 |
+
|
| 1787 |
+
CUTE_HOST_DEVICE static void
|
| 1788 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 1789 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 1790 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 1791 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 1792 |
+
{
|
| 1793 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1794 |
+
asm volatile(
|
| 1795 |
+
"mma.sync.aligned.m16n8k64.row.col.s32.u4.s4.s32 "
|
| 1796 |
+
"{%0, %1, %2, %3},"
|
| 1797 |
+
"{%4, %5, %6, %7},"
|
| 1798 |
+
"{%8, %9},"
|
| 1799 |
+
"{%10, %11, %12, %13};\n"
|
| 1800 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 1801 |
+
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 1802 |
+
"r"(b0), "r"(b1),
|
| 1803 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 1804 |
+
#else
|
| 1805 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x64_S32U4S4S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1806 |
+
#endif
|
| 1807 |
+
}
|
| 1808 |
+
};
|
| 1809 |
+
|
| 1810 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1811 |
+
|
| 1812 |
+
// MMA 16x8x64 TN
|
| 1813 |
+
struct SM80_16x8x64_S32U4S4S32_TN_SATURATE
|
| 1814 |
+
{
|
| 1815 |
+
using DRegisters = uint32_t[4];
|
| 1816 |
+
using ARegisters = uint32_t[4];
|
| 1817 |
+
using BRegisters = uint32_t[2];
|
| 1818 |
+
using CRegisters = uint32_t[4];
|
| 1819 |
+
|
| 1820 |
+
CUTE_HOST_DEVICE static void
|
| 1821 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 1822 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 1823 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 1824 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 1825 |
+
{
|
| 1826 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1827 |
+
asm volatile(
|
| 1828 |
+
"mma.sync.aligned.m16n8k64.row.col.s32.u4.s4.s32.satfinite "
|
| 1829 |
+
"{%0, %1, %2, %3},"
|
| 1830 |
+
"{%4, %5, %6, %7},"
|
| 1831 |
+
"{%8, %9},"
|
| 1832 |
+
"{%10, %11, %12, %13};\n"
|
| 1833 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 1834 |
+
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 1835 |
+
"r"(b0), "r"(b1),
|
| 1836 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 1837 |
+
#else
|
| 1838 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x64_S32U4S4S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1839 |
+
#endif
|
| 1840 |
+
}
|
| 1841 |
+
};
|
| 1842 |
+
|
| 1843 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1844 |
+
|
| 1845 |
+
// MMA 8x8x32 TN
|
| 1846 |
+
struct SM80_8x8x32_S32U4U4S32_TN
|
| 1847 |
+
{
|
| 1848 |
+
using DRegisters = uint32_t[2];
|
| 1849 |
+
using ARegisters = uint32_t[1];
|
| 1850 |
+
using BRegisters = uint32_t[1];
|
| 1851 |
+
using CRegisters = uint32_t[2];
|
| 1852 |
+
|
| 1853 |
+
CUTE_HOST_DEVICE static void
|
| 1854 |
+
fma(uint32_t & d0, uint32_t & d1,
|
| 1855 |
+
uint32_t const& a0,
|
| 1856 |
+
uint32_t const& b0,
|
| 1857 |
+
uint32_t const& c0, uint32_t const& c1)
|
| 1858 |
+
{
|
| 1859 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1860 |
+
asm volatile(
|
| 1861 |
+
"mma.sync.aligned.m8n8k32.row.col.s32.u4.u4.s32 "
|
| 1862 |
+
"{%0, %1},"
|
| 1863 |
+
"{%2},"
|
| 1864 |
+
"{%3},"
|
| 1865 |
+
"{%4, %5};\n"
|
| 1866 |
+
: "=r"(d0), "=r"(d1)
|
| 1867 |
+
: "r"(a0),
|
| 1868 |
+
"r"(b0),
|
| 1869 |
+
"r"(c0), "r"(c1));
|
| 1870 |
+
#else
|
| 1871 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_8x8x32_S32U4U4S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1872 |
+
#endif
|
| 1873 |
+
}
|
| 1874 |
+
};
|
| 1875 |
+
|
| 1876 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1877 |
+
|
| 1878 |
+
// MMA 8x8x32 TN
|
| 1879 |
+
struct SM80_8x8x32_S32U4U4S32_TN_SATURATE
|
| 1880 |
+
{
|
| 1881 |
+
using DRegisters = uint32_t[2];
|
| 1882 |
+
using ARegisters = uint32_t[1];
|
| 1883 |
+
using BRegisters = uint32_t[1];
|
| 1884 |
+
using CRegisters = uint32_t[2];
|
| 1885 |
+
|
| 1886 |
+
CUTE_HOST_DEVICE static void
|
| 1887 |
+
fma(uint32_t & d0, uint32_t & d1,
|
| 1888 |
+
uint32_t const& a0,
|
| 1889 |
+
uint32_t const& b0,
|
| 1890 |
+
uint32_t const& c0, uint32_t const& c1)
|
| 1891 |
+
{
|
| 1892 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1893 |
+
asm volatile(
|
| 1894 |
+
"mma.sync.aligned.m8n8k32.row.col.s32.u4.u4.s32.satfinite "
|
| 1895 |
+
"{%0, %1},"
|
| 1896 |
+
"{%2},"
|
| 1897 |
+
"{%3},"
|
| 1898 |
+
"{%4, %5};\n"
|
| 1899 |
+
: "=r"(d0), "=r"(d1)
|
| 1900 |
+
: "r"(a0),
|
| 1901 |
+
"r"(b0),
|
| 1902 |
+
"r"(c0), "r"(c1));
|
| 1903 |
+
#else
|
| 1904 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_8x8x32_S32U4U4S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1905 |
+
#endif
|
| 1906 |
+
}
|
| 1907 |
+
};
|
| 1908 |
+
|
| 1909 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1910 |
+
|
| 1911 |
+
// MMA 16x8x32 TN
|
| 1912 |
+
struct SM80_16x8x32_S32U4U4S32_TN
|
| 1913 |
+
{
|
| 1914 |
+
using DRegisters = uint32_t[4];
|
| 1915 |
+
using ARegisters = uint32_t[2];
|
| 1916 |
+
using BRegisters = uint32_t[1];
|
| 1917 |
+
using CRegisters = uint32_t[4];
|
| 1918 |
+
|
| 1919 |
+
CUTE_HOST_DEVICE static void
|
| 1920 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 1921 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 1922 |
+
uint32_t const& b0,
|
| 1923 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 1924 |
+
{
|
| 1925 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1926 |
+
asm volatile(
|
| 1927 |
+
"mma.sync.aligned.m16n8k32.row.col.s32.u4.u4.s32 "
|
| 1928 |
+
"{%0, %1, %2, %3},"
|
| 1929 |
+
"{%4, %5},"
|
| 1930 |
+
"{%6},"
|
| 1931 |
+
"{%7, %8, %9, %10};\n"
|
| 1932 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 1933 |
+
: "r"(a0), "r"(a1),
|
| 1934 |
+
"r"(b0),
|
| 1935 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 1936 |
+
#else
|
| 1937 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x32_S32U4U4S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1938 |
+
#endif
|
| 1939 |
+
}
|
| 1940 |
+
};
|
| 1941 |
+
|
| 1942 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1943 |
+
|
| 1944 |
+
// MMA 16x8x32 TN
|
| 1945 |
+
struct SM80_16x8x32_S32U4U4S32_TN_SATURATE
|
| 1946 |
+
{
|
| 1947 |
+
using DRegisters = uint32_t[4];
|
| 1948 |
+
using ARegisters = uint32_t[2];
|
| 1949 |
+
using BRegisters = uint32_t[1];
|
| 1950 |
+
using CRegisters = uint32_t[4];
|
| 1951 |
+
|
| 1952 |
+
CUTE_HOST_DEVICE static void
|
| 1953 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 1954 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 1955 |
+
uint32_t const& b0,
|
| 1956 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 1957 |
+
{
|
| 1958 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1959 |
+
asm volatile(
|
| 1960 |
+
"mma.sync.aligned.m16n8k32.row.col.s32.u4.u4.s32.satfinite "
|
| 1961 |
+
"{%0, %1, %2, %3},"
|
| 1962 |
+
"{%4, %5},"
|
| 1963 |
+
"{%6},"
|
| 1964 |
+
"{%7, %8, %9, %10};\n"
|
| 1965 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 1966 |
+
: "r"(a0), "r"(a1),
|
| 1967 |
+
"r"(b0),
|
| 1968 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 1969 |
+
#else
|
| 1970 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x32_S32U4U4S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 1971 |
+
#endif
|
| 1972 |
+
}
|
| 1973 |
+
};
|
| 1974 |
+
|
| 1975 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1976 |
+
|
| 1977 |
+
// MMA 16x8x64 TN
|
| 1978 |
+
struct SM80_16x8x64_S32U4U4S32_TN
|
| 1979 |
+
{
|
| 1980 |
+
using DRegisters = uint32_t[4];
|
| 1981 |
+
using ARegisters = uint32_t[4];
|
| 1982 |
+
using BRegisters = uint32_t[2];
|
| 1983 |
+
using CRegisters = uint32_t[4];
|
| 1984 |
+
|
| 1985 |
+
CUTE_HOST_DEVICE static void
|
| 1986 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 1987 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 1988 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 1989 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 1990 |
+
{
|
| 1991 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 1992 |
+
asm volatile(
|
| 1993 |
+
"mma.sync.aligned.m16n8k64.row.col.s32.u4.u4.s32 "
|
| 1994 |
+
"{%0, %1, %2, %3},"
|
| 1995 |
+
"{%4, %5, %6, %7},"
|
| 1996 |
+
"{%8, %9},"
|
| 1997 |
+
"{%10, %11, %12, %13};\n"
|
| 1998 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 1999 |
+
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 2000 |
+
"r"(b0), "r"(b1),
|
| 2001 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 2002 |
+
#else
|
| 2003 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x64_S32U4U4S32_TN without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 2004 |
+
#endif
|
| 2005 |
+
}
|
| 2006 |
+
};
|
| 2007 |
+
|
| 2008 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 2009 |
+
|
| 2010 |
+
// MMA 16x8x64 TN
|
| 2011 |
+
struct SM80_16x8x64_S32U4U4S32_TN_SATURATE
|
| 2012 |
+
{
|
| 2013 |
+
using DRegisters = uint32_t[4];
|
| 2014 |
+
using ARegisters = uint32_t[4];
|
| 2015 |
+
using BRegisters = uint32_t[2];
|
| 2016 |
+
using CRegisters = uint32_t[4];
|
| 2017 |
+
|
| 2018 |
+
CUTE_HOST_DEVICE static void
|
| 2019 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 2020 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 2021 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 2022 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 2023 |
+
{
|
| 2024 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 2025 |
+
asm volatile(
|
| 2026 |
+
"mma.sync.aligned.m16n8k64.row.col.s32.u4.u4.s32.satfinite "
|
| 2027 |
+
"{%0, %1, %2, %3},"
|
| 2028 |
+
"{%4, %5, %6, %7},"
|
| 2029 |
+
"{%8, %9},"
|
| 2030 |
+
"{%10, %11, %12, %13};\n"
|
| 2031 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 2032 |
+
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 2033 |
+
"r"(b0), "r"(b1),
|
| 2034 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 2035 |
+
#else
|
| 2036 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x64_S32U4U4S32_TN_SATURATE without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 2037 |
+
#endif
|
| 2038 |
+
}
|
| 2039 |
+
};
|
| 2040 |
+
|
| 2041 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 2042 |
+
|
| 2043 |
+
// MMA 8x8x128 TN
|
| 2044 |
+
struct SM80_8x8x128_S32U1U1S32_TN_ANDPOPC
|
| 2045 |
+
{
|
| 2046 |
+
using DRegisters = uint32_t[2];
|
| 2047 |
+
using ARegisters = uint32_t[1];
|
| 2048 |
+
using BRegisters = uint32_t[1];
|
| 2049 |
+
using CRegisters = uint32_t[2];
|
| 2050 |
+
|
| 2051 |
+
CUTE_HOST_DEVICE static void
|
| 2052 |
+
fma(uint32_t & d0, uint32_t & d1,
|
| 2053 |
+
uint32_t const& a0,
|
| 2054 |
+
uint32_t const& b0,
|
| 2055 |
+
uint32_t const& c0, uint32_t const& c1)
|
| 2056 |
+
{
|
| 2057 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 2058 |
+
asm volatile(
|
| 2059 |
+
"mma.sync.aligned.m8n8k128.row.col.s32.b1.b1.s32.and.popc "
|
| 2060 |
+
"{%0, %1},"
|
| 2061 |
+
"{%2},"
|
| 2062 |
+
"{%3},"
|
| 2063 |
+
"{%4, %5};\n"
|
| 2064 |
+
: "=r"(d0), "=r"(d1)
|
| 2065 |
+
: "r"(a0),
|
| 2066 |
+
"r"(b0),
|
| 2067 |
+
"r"(c0), "r"(c1));
|
| 2068 |
+
#else
|
| 2069 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_8x8x128_S32U1U1S32_TN_ANDPOPC without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 2070 |
+
#endif
|
| 2071 |
+
}
|
| 2072 |
+
};
|
| 2073 |
+
|
| 2074 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 2075 |
+
|
| 2076 |
+
// MMA 16x8x128 TN
|
| 2077 |
+
struct SM80_16x8x128_S32U1U1S32_TN_ANDPOPC
|
| 2078 |
+
{
|
| 2079 |
+
using DRegisters = uint32_t[4];
|
| 2080 |
+
using ARegisters = uint32_t[2];
|
| 2081 |
+
using BRegisters = uint32_t[1];
|
| 2082 |
+
using CRegisters = uint32_t[4];
|
| 2083 |
+
|
| 2084 |
+
CUTE_HOST_DEVICE static void
|
| 2085 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 2086 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 2087 |
+
uint32_t const& b0,
|
| 2088 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 2089 |
+
{
|
| 2090 |
+
#if defined(CUTE_ARCH_MMA_SM80_ENABLED)
|
| 2091 |
+
asm volatile(
|
| 2092 |
+
"mma.sync.aligned.m16n8k128.row.col.s32.b1.b1.s32.and.popc "
|
| 2093 |
+
"{%0, %1, %2, %3},"
|
| 2094 |
+
"{%4, %5},"
|
| 2095 |
+
"{%6},"
|
| 2096 |
+
"{%7, %8, %9, %10};\n"
|
| 2097 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 2098 |
+
: "r"(a0), "r"(a1),
|
| 2099 |
+
"r"(b0),
|
| 2100 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 2101 |
+
#else
|
| 2102 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x128_S32U1U1S32_TN_ANDPOPC without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 2103 |
+
#endif
|
| 2104 |
+
}
|
| 2105 |
+
};
|
| 2106 |
+
|
| 2107 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 2108 |
+
|
| 2109 |
+
// MMA 16x8x256 TN
|
| 2110 |
+
struct SM80_16x8x256_S32U1U1S32_TN_ANDPOPC
|
| 2111 |
+
{
|
| 2112 |
+
using DRegisters = uint32_t[4];
|
| 2113 |
+
using ARegisters = uint32_t[4];
|
| 2114 |
+
using BRegisters = uint32_t[2];
|
| 2115 |
+
using CRegisters = uint32_t[4];
|
| 2116 |
+
|
| 2117 |
+
CUTE_HOST_DEVICE static void
|
| 2118 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 2119 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 2120 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 2121 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 2122 |
+
{
|
| 2123 |
+
#if defined(CUTE_ARCH_MMA_B1_AND_SM80_ENABLED)
|
| 2124 |
+
asm volatile(
|
| 2125 |
+
"mma.sync.aligned.m16n8k256.row.col.s32.b1.b1.s32.and.popc "
|
| 2126 |
+
"{%0, %1, %2, %3},"
|
| 2127 |
+
"{%4, %5, %6, %7},"
|
| 2128 |
+
"{%8, %9},"
|
| 2129 |
+
"{%10, %11, %12, %13};\n"
|
| 2130 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 2131 |
+
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 2132 |
+
"r"(b0), "r"(b1),
|
| 2133 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 2134 |
+
#else
|
| 2135 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x256_S32U1U1S32_TN_ANDPOPC without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 2136 |
+
#endif
|
| 2137 |
+
}
|
| 2138 |
+
};
|
| 2139 |
+
|
| 2140 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 2141 |
+
|
| 2142 |
+
// MMA 8x8x128 TN
|
| 2143 |
+
struct SM80_8x8x128_S32U1U1S32_TN_XORPOPC
|
| 2144 |
+
{
|
| 2145 |
+
using DRegisters = uint32_t[2];
|
| 2146 |
+
using ARegisters = uint32_t[1];
|
| 2147 |
+
using BRegisters = uint32_t[1];
|
| 2148 |
+
using CRegisters = uint32_t[2];
|
| 2149 |
+
|
| 2150 |
+
CUTE_HOST_DEVICE static void
|
| 2151 |
+
fma(uint32_t & d0, uint32_t & d1,
|
| 2152 |
+
uint32_t const& a0,
|
| 2153 |
+
uint32_t const& b0,
|
| 2154 |
+
uint32_t const& c0, uint32_t const& c1)
|
| 2155 |
+
{
|
| 2156 |
+
#if defined(CUTE_ARCH_MMA_B1_XOR_SM80_ENABLED)
|
| 2157 |
+
asm volatile(
|
| 2158 |
+
"mma.sync.aligned.m8n8k128.row.col.s32.b1.b1.s32.xor.popc "
|
| 2159 |
+
"{%0, %1},"
|
| 2160 |
+
"{%2},"
|
| 2161 |
+
"{%3},"
|
| 2162 |
+
"{%4, %5};\n"
|
| 2163 |
+
: "=r"(d0), "=r"(d1)
|
| 2164 |
+
: "r"(a0),
|
| 2165 |
+
"r"(b0),
|
| 2166 |
+
"r"(c0), "r"(c1));
|
| 2167 |
+
#else
|
| 2168 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_8x8x128_S32U1U1S32_TN_XORPOPC without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 2169 |
+
#endif
|
| 2170 |
+
}
|
| 2171 |
+
};
|
| 2172 |
+
|
| 2173 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 2174 |
+
|
| 2175 |
+
// MMA 16x8x128 TN
|
| 2176 |
+
struct SM80_16x8x128_S32U1U1S32_TN_XORPOPC
|
| 2177 |
+
{
|
| 2178 |
+
using DRegisters = uint32_t[4];
|
| 2179 |
+
using ARegisters = uint32_t[2];
|
| 2180 |
+
using BRegisters = uint32_t[1];
|
| 2181 |
+
using CRegisters = uint32_t[4];
|
| 2182 |
+
|
| 2183 |
+
CUTE_HOST_DEVICE static void
|
| 2184 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 2185 |
+
uint32_t const& a0, uint32_t const& a1,
|
| 2186 |
+
uint32_t const& b0,
|
| 2187 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 2188 |
+
{
|
| 2189 |
+
#if defined(CUTE_ARCH_MMA_B1_XOR_SM80_ENABLED)
|
| 2190 |
+
asm volatile(
|
| 2191 |
+
"mma.sync.aligned.m16n8k128.row.col.s32.b1.b1.s32.xor.popc "
|
| 2192 |
+
"{%0, %1, %2, %3},"
|
| 2193 |
+
"{%4, %5},"
|
| 2194 |
+
"{%6},"
|
| 2195 |
+
"{%7, %8, %9, %10};\n"
|
| 2196 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 2197 |
+
: "r"(a0), "r"(a1),
|
| 2198 |
+
"r"(b0),
|
| 2199 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 2200 |
+
#else
|
| 2201 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x128_S32U1U1S32_TN_XORPOPC without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 2202 |
+
#endif
|
| 2203 |
+
}
|
| 2204 |
+
};
|
| 2205 |
+
|
| 2206 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 2207 |
+
|
| 2208 |
+
// MMA 16x8x256 TN
|
| 2209 |
+
struct SM80_16x8x256_S32U1U1S32_TN_XORPOPC
|
| 2210 |
+
{
|
| 2211 |
+
using DRegisters = uint32_t[4];
|
| 2212 |
+
using ARegisters = uint32_t[4];
|
| 2213 |
+
using BRegisters = uint32_t[2];
|
| 2214 |
+
using CRegisters = uint32_t[4];
|
| 2215 |
+
|
| 2216 |
+
CUTE_HOST_DEVICE static void
|
| 2217 |
+
fma(uint32_t & d0, uint32_t & d1, uint32_t & d2, uint32_t & d3,
|
| 2218 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 2219 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 2220 |
+
uint32_t const& c0, uint32_t const& c1, uint32_t const& c2, uint32_t const& c3)
|
| 2221 |
+
{
|
| 2222 |
+
#if defined(CUTE_ARCH_MMA_B1_XOR_SM80_ENABLED)
|
| 2223 |
+
asm volatile(
|
| 2224 |
+
"mma.sync.aligned.m16n8k256.row.col.s32.b1.b1.s32.xor.popc "
|
| 2225 |
+
"{%0, %1, %2, %3},"
|
| 2226 |
+
"{%4, %5, %6, %7},"
|
| 2227 |
+
"{%8, %9},"
|
| 2228 |
+
"{%10, %11, %12, %13};\n"
|
| 2229 |
+
: "=r"(d0), "=r"(d1), "=r"(d2), "=r"(d3)
|
| 2230 |
+
: "r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 2231 |
+
"r"(b0), "r"(b1),
|
| 2232 |
+
"r"(c0), "r"(c1), "r"(c2), "r"(c3));
|
| 2233 |
+
#else
|
| 2234 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM80_16x8x256_S32U1U1S32_TN_XORPOPC without CUTE_ARCH_MMA_SM80_ENABLED");
|
| 2235 |
+
#endif
|
| 2236 |
+
}
|
| 2237 |
+
};
|
| 2238 |
+
|
| 2239 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 2240 |
+
|
| 2241 |
+
} // namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm89.hpp
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
|
| 32 |
+
//
|
| 33 |
+
|
| 34 |
+
//
|
| 35 |
+
#pragma once
|
| 36 |
+
|
| 37 |
+
#include <cute/config.hpp>
|
| 38 |
+
#include <cute/arch/mma.hpp>
|
| 39 |
+
|
| 40 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 41 |
+
|
| 42 |
+
#if (__CUDACC_VER_MAJOR__ > 12) || (__CUDACC_VER_MAJOR__ == 12 && __CUDACC_VER_MINOR__ >= 4)
|
| 43 |
+
# define CUTE_ARCH_MMA_F32_SM89_SUPPORTED
|
| 44 |
+
#endif
|
| 45 |
+
|
| 46 |
+
#if (__CUDACC_VER_MAJOR__ > 12) || (__CUDACC_VER_MAJOR__ == 12 && __CUDACC_VER_MINOR__ >= 8)
|
| 47 |
+
# define CUTE_ARCH_MMA_F16_SM89_SUPPORTED
|
| 48 |
+
#endif
|
| 49 |
+
|
| 50 |
+
#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 890)
|
| 51 |
+
# if defined(CUTE_ARCH_MMA_F32_SM89_SUPPORTED)
|
| 52 |
+
# define CUTE_ARCH_MMA_F32_SM89_ENABLED
|
| 53 |
+
# endif
|
| 54 |
+
|
| 55 |
+
# if defined(CUTE_ARCH_MMA_F16_SM89_SUPPORTED)
|
| 56 |
+
# define CUTE_ARCH_MMA_F16_SM89_ENABLED
|
| 57 |
+
# endif
|
| 58 |
+
#endif
|
| 59 |
+
|
| 60 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 61 |
+
|
| 62 |
+
namespace cute {
|
| 63 |
+
// MMA 16x8x32 TN
|
| 64 |
+
struct SM89_16x8x32_F32E4M3E4M3F32_TN
|
| 65 |
+
{
|
| 66 |
+
using DRegisters = float[4];
|
| 67 |
+
using ARegisters = uint32_t[4];
|
| 68 |
+
using BRegisters = uint32_t[2];
|
| 69 |
+
using CRegisters = float[4];
|
| 70 |
+
|
| 71 |
+
CUTE_HOST_DEVICE static void
|
| 72 |
+
fma(float & d0, float & d1, float & d2, float & d3,
|
| 73 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 74 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 75 |
+
float const& c0, float const& c1, float const& c2, float const& c3)
|
| 76 |
+
{
|
| 77 |
+
#if defined(CUTE_ARCH_MMA_F32_SM89_ENABLED)
|
| 78 |
+
asm(
|
| 79 |
+
"mma.sync.aligned.m16n8k32.row.col.f32.e4m3.e4m3.f32 "
|
| 80 |
+
"{%0,%1,%2,%3}, {%4,%5,%6,%7}, {%8,%9}, {%10,%11,%12,%13};\n"
|
| 81 |
+
: "=f"(d0), "=f"(d1), "=f"(d2), "=f"(d3)
|
| 82 |
+
:
|
| 83 |
+
"r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 84 |
+
"r"(b0), "r"(b1),
|
| 85 |
+
"f"(c0), "f"(c1), "f"(c2), "f"(c3)
|
| 86 |
+
);
|
| 87 |
+
#else
|
| 88 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM89_16x8x32_F32E4M3E4M3F32_TN without CUTE_ARCH_MMA_F32_SM89_ENABLED");
|
| 89 |
+
#endif
|
| 90 |
+
}
|
| 91 |
+
};
|
| 92 |
+
|
| 93 |
+
struct SM89_16x8x32_F32E4M3E5M2F32_TN
|
| 94 |
+
{
|
| 95 |
+
using DRegisters = float[4];
|
| 96 |
+
using ARegisters = uint32_t[4];
|
| 97 |
+
using BRegisters = uint32_t[2];
|
| 98 |
+
using CRegisters = float[4];
|
| 99 |
+
|
| 100 |
+
CUTE_HOST_DEVICE static void
|
| 101 |
+
fma(float & d0, float & d1, float & d2, float & d3,
|
| 102 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 103 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 104 |
+
float const& c0, float const& c1, float const& c2, float const& c3)
|
| 105 |
+
{
|
| 106 |
+
#if defined(CUTE_ARCH_MMA_F32_SM89_ENABLED)
|
| 107 |
+
asm(
|
| 108 |
+
"mma.sync.aligned.m16n8k32.row.col.f32.e4m3.e5m2.f32 "
|
| 109 |
+
"{%0,%1,%2,%3}, {%4,%5,%6,%7}, {%8,%9}, {%10,%11,%12,%13};\n"
|
| 110 |
+
: "=f"(d0), "=f"(d1), "=f"(d2), "=f"(d3)
|
| 111 |
+
:
|
| 112 |
+
"r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 113 |
+
"r"(b0), "r"(b1),
|
| 114 |
+
"f"(c0), "f"(c1), "f"(c2), "f"(c3)
|
| 115 |
+
);
|
| 116 |
+
#else
|
| 117 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM89_16x8x32_F32E4M3E5M2F32_TN without CUTE_ARCH_MMA_F32_SM89_ENABLED");
|
| 118 |
+
#endif
|
| 119 |
+
}
|
| 120 |
+
};
|
| 121 |
+
|
| 122 |
+
struct SM89_16x8x32_F32E5M2E5M2F32_TN
|
| 123 |
+
{
|
| 124 |
+
using DRegisters = float[4];
|
| 125 |
+
using ARegisters = uint32_t[4];
|
| 126 |
+
using BRegisters = uint32_t[2];
|
| 127 |
+
using CRegisters = float[4];
|
| 128 |
+
|
| 129 |
+
CUTE_HOST_DEVICE static void
|
| 130 |
+
fma(float & d0, float & d1, float & d2, float & d3,
|
| 131 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 132 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 133 |
+
float const& c0, float const& c1, float const& c2, float const& c3)
|
| 134 |
+
{
|
| 135 |
+
#if defined(CUTE_ARCH_MMA_F32_SM89_ENABLED)
|
| 136 |
+
asm(
|
| 137 |
+
"mma.sync.aligned.m16n8k32.row.col.f32.e5m2.e5m2.f32 "
|
| 138 |
+
"{%0,%1,%2,%3}, {%4,%5,%6,%7}, {%8,%9}, {%10,%11,%12,%13};\n"
|
| 139 |
+
: "=f"(d0), "=f"(d1), "=f"(d2), "=f"(d3)
|
| 140 |
+
:
|
| 141 |
+
"r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 142 |
+
"r"(b0), "r"(b1),
|
| 143 |
+
"f"(c0), "f"(c1), "f"(c2), "f"(c3)
|
| 144 |
+
);
|
| 145 |
+
#else
|
| 146 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM89_16x8x32_F32E5M2E5M2F32_TN without CUTE_ARCH_MMA_F32_SM89_ENABLED");
|
| 147 |
+
#endif
|
| 148 |
+
}
|
| 149 |
+
};
|
| 150 |
+
|
| 151 |
+
struct SM89_16x8x32_F32E5M2E4M3F32_TN
|
| 152 |
+
{
|
| 153 |
+
using DRegisters = float[4];
|
| 154 |
+
using ARegisters = uint32_t[4];
|
| 155 |
+
using BRegisters = uint32_t[2];
|
| 156 |
+
using CRegisters = float[4];
|
| 157 |
+
|
| 158 |
+
CUTE_HOST_DEVICE static void
|
| 159 |
+
fma(float & d0, float & d1, float & d2, float & d3,
|
| 160 |
+
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
| 161 |
+
uint32_t const& b0, uint32_t const& b1,
|
| 162 |
+
float const& c0, float const& c1, float const& c2, float const& c3)
|
| 163 |
+
{
|
| 164 |
+
#if defined(CUTE_ARCH_MMA_F32_SM89_ENABLED)
|
| 165 |
+
asm(
|
| 166 |
+
"mma.sync.aligned.m16n8k32.row.col.f32.e5m2.e4m3.f32 "
|
| 167 |
+
"{%0,%1,%2,%3}, {%4,%5,%6,%7}, {%8,%9}, {%10,%11,%12,%13};\n"
|
| 168 |
+
: "=f"(d0), "=f"(d1), "=f"(d2), "=f"(d3)
|
| 169 |
+
:
|
| 170 |
+
"r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
| 171 |
+
"r"(b0), "r"(b1),
|
| 172 |
+
"f"(c0), "f"(c1), "f"(c2), "f"(c3)
|
| 173 |
+
);
|
| 174 |
+
#else
|
| 175 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use SM89_16x8x32_F32E5M2E4M3F32_TN without CUTE_ARCH_MMA_F32_SM89_ENABLED");
|
| 176 |
+
#endif
|
| 177 |
+
}
|
| 178 |
+
};
|
| 179 |
+
|
| 180 |
+
} // namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm90.hpp
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm90_desc.hpp
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
|
| 32 |
+
#pragma once
|
| 33 |
+
|
| 34 |
+
#include <cute/arch/config.hpp>
|
| 35 |
+
|
| 36 |
+
#include <cute/arch/mma.hpp>
|
| 37 |
+
|
| 38 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 39 |
+
|
| 40 |
+
namespace cute {
|
| 41 |
+
|
| 42 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 43 |
+
// GMMA Descriptor and utilities
|
| 44 |
+
|
| 45 |
+
// GMMA enums and utilities
|
| 46 |
+
namespace SM90::GMMA {
|
| 47 |
+
|
| 48 |
+
enum class LayoutType : uint8_t {
|
| 49 |
+
INTERLEAVE = 0,
|
| 50 |
+
B128 = 1,
|
| 51 |
+
B64 = 2,
|
| 52 |
+
B32 = 3,
|
| 53 |
+
};
|
| 54 |
+
|
| 55 |
+
CUTE_HOST_DEVICE char const* to_string(LayoutType const& t) {
|
| 56 |
+
switch (t) {
|
| 57 |
+
case LayoutType::INTERLEAVE: return "INTERLEAVE";
|
| 58 |
+
case LayoutType::B128: return "B128";
|
| 59 |
+
case LayoutType::B64: return "B64";
|
| 60 |
+
case LayoutType::B32: return "B32";
|
| 61 |
+
}
|
| 62 |
+
return nullptr;
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
#if !defined(__CUDACC_RTC__)
|
| 66 |
+
// Output operator for all enums in this namespace
|
| 67 |
+
CUTE_HOST std::ostream& operator<<(std::ostream& os, LayoutType const& t) {
|
| 68 |
+
char const* s = to_string(t);
|
| 69 |
+
if (s) {
|
| 70 |
+
std::operator<<(os, s); // Explicit call to avoid ambiguity
|
| 71 |
+
} else {
|
| 72 |
+
os.setstate(std::ios_base::failbit);
|
| 73 |
+
}
|
| 74 |
+
return os;
|
| 75 |
+
}
|
| 76 |
+
#endif // !defined(__CUDACC_RTC__)
|
| 77 |
+
|
| 78 |
+
} // end namespace SM90::GMMA
|
| 79 |
+
|
| 80 |
+
union GmmaDescriptor
|
| 81 |
+
{
|
| 82 |
+
CUTE_HOST_DEVICE constexpr
|
| 83 |
+
GmmaDescriptor() noexcept : desc_(0) {}
|
| 84 |
+
CUTE_HOST_DEVICE constexpr
|
| 85 |
+
GmmaDescriptor(uint64_t desc) noexcept : desc_(desc) {}
|
| 86 |
+
CUTE_HOST_DEVICE constexpr
|
| 87 |
+
GmmaDescriptor(GmmaDescriptor const& t) noexcept : desc_(t.desc_) {}
|
| 88 |
+
CUTE_HOST_DEVICE constexpr
|
| 89 |
+
GmmaDescriptor(GmmaDescriptor && t) noexcept : desc_(t.desc_) {}
|
| 90 |
+
|
| 91 |
+
CUTE_HOST_DEVICE constexpr
|
| 92 |
+
GmmaDescriptor& operator=(GmmaDescriptor const& t) noexcept {
|
| 93 |
+
desc_ = t.desc_;
|
| 94 |
+
return *this;
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
CUTE_HOST_DEVICE constexpr
|
| 98 |
+
GmmaDescriptor& operator=(GmmaDescriptor && t) noexcept {
|
| 99 |
+
desc_ = t.desc_;
|
| 100 |
+
return *this;
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
uint64_t desc_;
|
| 104 |
+
uint32_t reg32_[2];
|
| 105 |
+
uint16_t reg16_[4];
|
| 106 |
+
|
| 107 |
+
// Bitfield implementation avoids the need for shifts in assignment
|
| 108 |
+
struct {
|
| 109 |
+
// start_address, bit [0,14), 4LSB not included
|
| 110 |
+
uint16_t start_address_ : 14, : 2; // 14 bits [0,14), 2 bits unused
|
| 111 |
+
// leading dimension byte offset, bit [16,30), 4LSB not included
|
| 112 |
+
// For N: This is the stride from the first col to the second col of the 8x2 brick in INTERLEAVED
|
| 113 |
+
// Unused for all SWIZZLE_* layouts (and assumed to be 1)
|
| 114 |
+
// For T: This is the stride from the first 8 rows to the next 8 rows.
|
| 115 |
+
uint16_t leading_byte_offset_ : 14, : 2; // 14 bits [0,14), 2 bits unused
|
| 116 |
+
// stride dimension byte offset, bit [32,46), 4LSB not included
|
| 117 |
+
// For N: This is the stride from the first 8 rows to the next 8 rows.
|
| 118 |
+
// For T: This is the stride fro mthe first 8 cols to the next 8 cols.
|
| 119 |
+
uint16_t stride_byte_offset_ : 14, : 2; // 14 bits [0,14), 2 bits unused
|
| 120 |
+
// base_offset, bit [49,52)
|
| 121 |
+
// Valid only for SWIZZLE_128B and SWIZZLE_64B
|
| 122 |
+
uint8_t : 1, base_offset_ : 3, : 4; // 1 bit unused, 3 bits [1,4), 4 bits unused
|
| 123 |
+
// layout type, bit [62,64)
|
| 124 |
+
// SWIZZLE_NONE = 0, SWIZZLE_32B = 3, SWIZZLE_64B = 2, SWIZZLE_128B = 1
|
| 125 |
+
uint8_t : 6, layout_type_ : 2; // 6 bits unused, 2 bits [6,8)
|
| 126 |
+
} bitfield;
|
| 127 |
+
|
| 128 |
+
// Decay to a uint64_t
|
| 129 |
+
CUTE_HOST_DEVICE constexpr
|
| 130 |
+
operator uint64_t() const noexcept { return desc_; }
|
| 131 |
+
};
|
| 132 |
+
|
| 133 |
+
// Printer
|
| 134 |
+
CUTE_HOST_DEVICE void
|
| 135 |
+
print(GmmaDescriptor const& t)
|
| 136 |
+
{
|
| 137 |
+
#if !defined(__CUDACC_RTC__)
|
| 138 |
+
printf("GmmaDescriptor: 0x%016llx\n", static_cast<unsigned long long>(t.desc_));
|
| 139 |
+
printf(" start_addr : 0x%04x\n", t.bitfield.start_address_);
|
| 140 |
+
printf(" leading_off: 0x%04x (%d)\n", t.bitfield.leading_byte_offset_, t.bitfield.leading_byte_offset_);
|
| 141 |
+
printf(" stride_off : 0x%04x (%d)\n", t.bitfield.stride_byte_offset_, t.bitfield.stride_byte_offset_);
|
| 142 |
+
printf(" base_offset: 0x%01x\n", t.bitfield.base_offset_);
|
| 143 |
+
printf(" layout_type: 0x%01x (%s)\n", t.bitfield.layout_type_, to_string(static_cast<SM90::GMMA::LayoutType>(t.bitfield.layout_type_)));
|
| 144 |
+
#endif // !defined(__CUDACC_RTC__)
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 148 |
+
|
| 149 |
+
} // namespace cute
|
| 150 |
+
|
| 151 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm90_gmma.hpp
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm90_gmma_ext.hpp
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm90_gmma_sparse.hpp
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/mma_sm90_gmma_sparse_ext.hpp
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/simd_sm100.hpp
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2024 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
//
|
| 32 |
+
|
| 33 |
+
//
|
| 34 |
+
|
| 35 |
+
#pragma once
|
| 36 |
+
|
| 37 |
+
#include <cute/config.hpp>
|
| 38 |
+
#include <cute/arch/config.hpp>
|
| 39 |
+
#include <cute/numeric/real.hpp>
|
| 40 |
+
|
| 41 |
+
namespace cute {
|
| 42 |
+
|
| 43 |
+
CUTE_HOST_DEVICE
|
| 44 |
+
void
|
| 45 |
+
add(float2 & c,
|
| 46 |
+
float2 const& a,
|
| 47 |
+
float2 const& b)
|
| 48 |
+
{
|
| 49 |
+
#if defined(CUTE_ARCH_FLOAT2_MATH_ENABLED)
|
| 50 |
+
asm volatile("add.f32x2 %0, %1, %2;\n"
|
| 51 |
+
: "=l"(reinterpret_cast<uint64_t &>(c))
|
| 52 |
+
: "l"(reinterpret_cast<uint64_t const&>(a)),
|
| 53 |
+
"l"(reinterpret_cast<uint64_t const&>(b)));
|
| 54 |
+
#else
|
| 55 |
+
add(c.x, a.x, b.x);
|
| 56 |
+
add(c.y, a.y, b.y);
|
| 57 |
+
#endif
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
CUTE_HOST_DEVICE
|
| 61 |
+
void
|
| 62 |
+
mul(float2 & c,
|
| 63 |
+
float2 const& a,
|
| 64 |
+
float2 const& b)
|
| 65 |
+
{
|
| 66 |
+
#if defined(CUTE_ARCH_FLOAT2_MATH_ENABLED)
|
| 67 |
+
asm volatile("mul.f32x2 %0, %1, %2;\n"
|
| 68 |
+
: "=l"(reinterpret_cast<uint64_t &>(c))
|
| 69 |
+
: "l"(reinterpret_cast<uint64_t const&>(a)),
|
| 70 |
+
"l"(reinterpret_cast<uint64_t const&>(b)));
|
| 71 |
+
#else
|
| 72 |
+
mul(c.x, a.x, b.x);
|
| 73 |
+
mul(c.y, a.y, b.y);
|
| 74 |
+
#endif
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
CUTE_HOST_DEVICE
|
| 78 |
+
void
|
| 79 |
+
fma(float2 & d,
|
| 80 |
+
float2 const& a,
|
| 81 |
+
float2 const& b,
|
| 82 |
+
float2 const& c)
|
| 83 |
+
{
|
| 84 |
+
#if defined(CUTE_ARCH_FLOAT2_MATH_ENABLED)
|
| 85 |
+
asm volatile("fma.rn.f32x2 %0, %1, %2, %3;\n"
|
| 86 |
+
: "=l"(reinterpret_cast<uint64_t &>(d))
|
| 87 |
+
: "l"(reinterpret_cast<uint64_t const&>(a)),
|
| 88 |
+
"l"(reinterpret_cast<uint64_t const&>(b)),
|
| 89 |
+
"l"(reinterpret_cast<uint64_t const&>(c)));
|
| 90 |
+
#else
|
| 91 |
+
fma(d.x, a.x, b.x, c.x);
|
| 92 |
+
fma(d.y, a.y, b.y, c.y);
|
| 93 |
+
#endif
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
} // namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/tmem_allocator_sm100.hpp
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
//
|
| 32 |
+
|
| 33 |
+
//
|
| 34 |
+
#pragma once
|
| 35 |
+
|
| 36 |
+
#include <cute/arch/config.hpp>
|
| 37 |
+
#include <cute/arch/cluster_sm90.hpp>
|
| 38 |
+
#include <cute/atom/copy_traits_sm100.hpp>
|
| 39 |
+
|
| 40 |
+
#include <cutlass/pipeline/sm90_pipeline.hpp>
|
| 41 |
+
|
| 42 |
+
namespace cute::TMEM {
|
| 43 |
+
|
| 44 |
+
// All operations of this class require that only a single warp uniformly participates
|
| 45 |
+
class Allocator1Sm {
|
| 46 |
+
public:
|
| 47 |
+
static constexpr int ColumnsPerAllocationSlice = 32;
|
| 48 |
+
static constexpr int Sm100TmemCapacityColumns = 512;
|
| 49 |
+
|
| 50 |
+
__device__ Allocator1Sm() { }
|
| 51 |
+
|
| 52 |
+
/**
|
| 53 |
+
* Performs a non-blocking allocation of TMEM.
|
| 54 |
+
* @param num_columns Number of columns being freed. Must be 32 <= num_columns <= 512 and power of 2.
|
| 55 |
+
* @param dst_ptr Pointer to shared memory to which to write the result tmem pointer to.
|
| 56 |
+
* @pre Must be issued by a single fully active warp of the CTA.
|
| 57 |
+
* @pre Must never be issued by more than one warp at the same time.
|
| 58 |
+
* @pre For repeated allocations, the same warp must be used to issue all allocations.
|
| 59 |
+
**/
|
| 60 |
+
CUTE_HOST_DEVICE void
|
| 61 |
+
allocate(int num_columns, uint32_t* dst_ptr) {
|
| 62 |
+
#if defined(CUTE_ARCH_TCGEN05_TMEM_ENABLED)
|
| 63 |
+
uint32_t dst_intptr = cute::cast_smem_ptr_to_uint(dst_ptr);
|
| 64 |
+
asm volatile(
|
| 65 |
+
"tcgen05.alloc.cta_group::1.sync.aligned.shared::cta.b32 [%0], %1;"
|
| 66 |
+
:
|
| 67 |
+
: "r"(dst_intptr), "r"(num_columns));
|
| 68 |
+
#else
|
| 69 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use TMEM allocation PTX without CUTE_ARCH_TCGEN05_TMEM_ENABLED");
|
| 70 |
+
#endif
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
__device__
|
| 74 |
+
void
|
| 75 |
+
free(uint32_t tmem_ptr, int num_columns) {
|
| 76 |
+
#if defined(CUTE_ARCH_TCGEN05_TMEM_ENABLED)
|
| 77 |
+
asm volatile(
|
| 78 |
+
"{\n\t"
|
| 79 |
+
"tcgen05.dealloc.cta_group::1.sync.aligned.b32 %0, %1; \n\t"
|
| 80 |
+
"}"
|
| 81 |
+
:
|
| 82 |
+
: "r"(tmem_ptr), "r"(num_columns));
|
| 83 |
+
#else
|
| 84 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use TMEM allocation PTX without CUTE_ARCH_TCGEN05_TMEM_ENABLED");
|
| 85 |
+
#endif
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
__device__ void
|
| 89 |
+
release_allocation_lock() {
|
| 90 |
+
#if defined(CUTE_ARCH_TCGEN05_TMEM_ENABLED)
|
| 91 |
+
asm volatile("tcgen05.relinquish_alloc_permit.cta_group::1.sync.aligned;" ::);
|
| 92 |
+
#else
|
| 93 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use TMEM allocation PTX without CUTE_ARCH_TCGEN05_TMEM_ENABLED");
|
| 94 |
+
#endif
|
| 95 |
+
}
|
| 96 |
+
};
|
| 97 |
+
|
| 98 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 99 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 100 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 101 |
+
|
| 102 |
+
class Allocator2Sm {
|
| 103 |
+
public:
|
| 104 |
+
static constexpr int ColumnsPerAllocationSlice = 32;
|
| 105 |
+
static constexpr int Sm100TmemCapacityColumns = 512;
|
| 106 |
+
|
| 107 |
+
__device__ Allocator2Sm() { }
|
| 108 |
+
|
| 109 |
+
/**
|
| 110 |
+
* Performs a non-blocking allocation of TMEM.
|
| 111 |
+
* @param num_columns Number of columns being freed. Must be 32 <= num_columns <= 512 and power of 2.
|
| 112 |
+
* @param dst_ptr Pointer to shared memory to which to write the result tmem pointer to.
|
| 113 |
+
* Both CTAs _must_ provide the exact same dst_ptr for correctness.
|
| 114 |
+
* @pre Must be issued by a single fully active warp of the CTA.
|
| 115 |
+
* @pre Must never be issued by more than one warp at the same time.
|
| 116 |
+
* @pre For repeated allocations, the same warp must be used to issue all allocations.
|
| 117 |
+
* @pre The 2 warps from participating CTAs have the same logical warp ID.
|
| 118 |
+
**/
|
| 119 |
+
CUTE_HOST_DEVICE void
|
| 120 |
+
allocate(int num_columns, uint32_t* dst_ptr) {
|
| 121 |
+
#if defined(CUTE_ARCH_TCGEN05_TMEM_ENABLED)
|
| 122 |
+
uint32_t dst_intptr = cute::cast_smem_ptr_to_uint(dst_ptr);
|
| 123 |
+
asm volatile(
|
| 124 |
+
"tcgen05.alloc.cta_group::2.sync.aligned.shared::cta.b32 [%0], %1;"
|
| 125 |
+
:
|
| 126 |
+
: "r"(dst_intptr), "r"(num_columns));
|
| 127 |
+
#else
|
| 128 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use TMEM allocation PTX without CUTE_ARCH_TCGEN05_TMEM_ENABLED");
|
| 129 |
+
#endif
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
/**
|
| 133 |
+
* Frees the TMEM corresponding to the pointer and slice count provided.
|
| 134 |
+
* Release the TMEM after checking that the CTA issuing the free does indeed own the corresponding slices.
|
| 135 |
+
* @param tmem_ptr Base address of the TMEM address space being freed.
|
| 136 |
+
* @param num_columns Number of columns being freed. Must be 32 <= num_columns <= 512 and power of 2.
|
| 137 |
+
* @pre Must be issued by a single fully active warp of the CTA.
|
| 138 |
+
* @pre Must never be issued by more than one warp at the same time.
|
| 139 |
+
* @pre The 2 warps from participating CTAs have the same logical warp ID.
|
| 140 |
+
* @returns true
|
| 141 |
+
**/
|
| 142 |
+
__device__
|
| 143 |
+
void
|
| 144 |
+
free(uint32_t tmem_ptr, int num_columns) {
|
| 145 |
+
#if defined(CUTE_ARCH_TCGEN05_TMEM_ENABLED)
|
| 146 |
+
asm volatile(
|
| 147 |
+
"{\n\t"
|
| 148 |
+
"tcgen05.dealloc.cta_group::2.sync.aligned.b32 %0, %1; \n\t"
|
| 149 |
+
"}"
|
| 150 |
+
:
|
| 151 |
+
: "r"(tmem_ptr), "r"(num_columns));
|
| 152 |
+
#else
|
| 153 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use TMEM allocation PTX without CUTE_ARCH_TCGEN05_TMEM_ENABLED");
|
| 154 |
+
#endif
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
__device__
|
| 158 |
+
void
|
| 159 |
+
release_allocation_lock() {
|
| 160 |
+
#if defined(CUTE_ARCH_TCGEN05_TMEM_ENABLED)
|
| 161 |
+
asm volatile("tcgen05.relinquish_alloc_permit.cta_group::2.sync.aligned;" ::);
|
| 162 |
+
#else
|
| 163 |
+
CUTE_INVALID_CONTROL_PATH("Attempting to use TMEM allocation PTX without CUTE_ARCH_TCGEN05_TMEM_ENABLED");
|
| 164 |
+
#endif
|
| 165 |
+
}
|
| 166 |
+
};
|
| 167 |
+
|
| 168 |
+
} // namespace cute::TMEM
|
lib/python3.12/site-packages/deep_gemm/include/cute/arch/util.hpp
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/config.hpp>
|
| 34 |
+
#include <cute/numeric/integer_sequence.hpp>
|
| 35 |
+
|
| 36 |
+
#if defined(__clang__) && defined(__CUDA__)
|
| 37 |
+
// __cvta_generic_to_shared was added in Clang 14: https://reviews.llvm.org/D111665
|
| 38 |
+
#if __clang_major__ >= 14
|
| 39 |
+
#define CUTE_CLANG_SUPPORTS_CVTA_GENERIC_TO_SHARED 1
|
| 40 |
+
#endif
|
| 41 |
+
|
| 42 |
+
// __nvvm_get_smem_pointer added in Clang 14: https://reviews.llvm.org/D111665
|
| 43 |
+
// ... but will not work on Windows until Clang 15: https://reviews.llvm.org/D122897
|
| 44 |
+
#if (!defined(_WIN32) && __clang_major__ >= 14) || __clang_major__ >= 15
|
| 45 |
+
#define CUTE_CLANG_SUPPORTS_NVVM_GET_SMEM_POINTER 1
|
| 46 |
+
#endif
|
| 47 |
+
#endif
|
| 48 |
+
|
| 49 |
+
#if defined(__NVCC__) || defined(__CUDACC_RTC__)
|
| 50 |
+
// __cvta_generic_to_shared added in CUDA 11+
|
| 51 |
+
#if __CUDACC_VER_MAJOR__ >= 11
|
| 52 |
+
#define CUTE_NVCC_SUPPORTS_CVTA_GENERIC_TO_SHARED 1
|
| 53 |
+
#endif
|
| 54 |
+
|
| 55 |
+
// __nvvm_get_smem_pointer added in CUDA 10.2
|
| 56 |
+
#if __CUDACC_VER_MAJOR__ == 10 && __CUDACC_VER_MINOR__ >= 2
|
| 57 |
+
#define CUTE_NVCC_SUPPORTS_NVVM_GET_SMEM_POINTER 1
|
| 58 |
+
#endif
|
| 59 |
+
#endif
|
| 60 |
+
|
| 61 |
+
#if CUTE_NVCC_SUPPORTS_CVTA_GENERIC_TO_SHARED || CUTE_CLANG_SUPPORTS_CVTA_GENERIC_TO_SHARED
|
| 62 |
+
#define CUTE_CVTA_GENERIC_TO_SHARED_SUPPORTED 1
|
| 63 |
+
#endif
|
| 64 |
+
|
| 65 |
+
#if !defined(CUTE_CVTA_GENERIC_TO_SHARED_ACTIVATED) && CUTE_CVTA_GENERIC_TO_SHARED_SUPPORTED && defined(__CUDA_ARCH__)
|
| 66 |
+
#define CUTE_CVTA_GENERIC_TO_SHARED_ACTIVATED 1
|
| 67 |
+
#endif
|
| 68 |
+
|
| 69 |
+
#if CUTE_NVCC_SUPPORTS_NVVM_GET_SMEM_POINTER || CUTE_CLANG_SUPPORTS_NVVM_GET_SMEM_POINTER
|
| 70 |
+
#define CUTE_NVVM_GET_SMEM_POINTER_SUPPORTED 1
|
| 71 |
+
#endif
|
| 72 |
+
|
| 73 |
+
#if !defined(CUTE_NVVM_GET_SMEM_POINTER_ACTIVATED) && CUTE_NVVM_GET_SMEM_POINTER_SUPPORTED && defined(__CUDA_ARCH__)
|
| 74 |
+
#define CUTE_NVVM_GET_SMEM_POINTER_ACTIVATED 1
|
| 75 |
+
#endif
|
| 76 |
+
|
| 77 |
+
// Clang 14+ provides a declaration of __nvvm_get_smem_pointer, so we only need
|
| 78 |
+
// to provide one for NVCC
|
| 79 |
+
#if CUTE_NVCC_SUPPORTS_NVVM_GET_SMEM_POINTER
|
| 80 |
+
extern "C" {
|
| 81 |
+
// This NVVM intrinsic is subject to change in future versions of CUDA.
|
| 82 |
+
// Clients should not call it directly.
|
| 83 |
+
CUTE_DEVICE uint32_t __nvvm_get_smem_pointer(void*);
|
| 84 |
+
}
|
| 85 |
+
#endif
|
| 86 |
+
|
| 87 |
+
namespace cute
|
| 88 |
+
{
|
| 89 |
+
|
| 90 |
+
/// CUTE helper to cast SMEM pointer to unsigned
|
| 91 |
+
CUTE_HOST_DEVICE
|
| 92 |
+
uint32_t
|
| 93 |
+
cast_smem_ptr_to_uint(void const* const ptr)
|
| 94 |
+
{
|
| 95 |
+
// We prefer to use the new CVTA intrinsics if they are available, otherwise we will fall back to
|
| 96 |
+
// the previous internal intrinsics if they are available.
|
| 97 |
+
#if CUTE_CVTA_GENERIC_TO_SHARED_ACTIVATED
|
| 98 |
+
//
|
| 99 |
+
// This NVVM intrinsic converts an address in shared memory to a plain
|
| 100 |
+
// unsigned integer. This is necessary to pass to shared memory instructions
|
| 101 |
+
// in inline PTX.
|
| 102 |
+
//
|
| 103 |
+
// In CUDA 11 and beyond, this replaces __nvvm_get_smem_pointer() [only available in 10.2].
|
| 104 |
+
//
|
| 105 |
+
//__device__ size_t __cvta_generic_to_shared(void* ptr);
|
| 106 |
+
|
| 107 |
+
/// CUTE helper to get SMEM pointer
|
| 108 |
+
return static_cast<uint32_t>(__cvta_generic_to_shared(ptr));
|
| 109 |
+
|
| 110 |
+
#elif CUTE_NVVM_GET_SMEM_POINTER_ACTIVATED
|
| 111 |
+
|
| 112 |
+
return __nvvm_get_smem_pointer(ptr);
|
| 113 |
+
|
| 114 |
+
#elif defined(__CUDA_ARCH__)
|
| 115 |
+
|
| 116 |
+
uint32_t smem_ptr;
|
| 117 |
+
|
| 118 |
+
asm(
|
| 119 |
+
"{ .reg .u64 smem_ptr; cvta.to.shared.u64 smem_ptr, %1; cvt.u32.u64 %0, smem_ptr; }\n"
|
| 120 |
+
: "=r"(smem_ptr) : "l"(ptr));
|
| 121 |
+
|
| 122 |
+
return smem_ptr;
|
| 123 |
+
|
| 124 |
+
#else
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
(void) ptr;
|
| 128 |
+
printf("ERROR: cast_smem_ptr_to_uint not supported but used.\n");
|
| 129 |
+
return 0;
|
| 130 |
+
|
| 131 |
+
#endif
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
namespace detail {
|
| 135 |
+
|
| 136 |
+
//
|
| 137 |
+
// Wrapper for MMAOp::fma
|
| 138 |
+
//
|
| 139 |
+
|
| 140 |
+
template <class MmaOp>
|
| 141 |
+
struct CallFMA {
|
| 142 |
+
template <class... Args>
|
| 143 |
+
CUTE_HOST_DEVICE constexpr void
|
| 144 |
+
operator()(Args&&... args) const {
|
| 145 |
+
return MmaOp::fma(static_cast<Args&&>(args)...);
|
| 146 |
+
}
|
| 147 |
+
};
|
| 148 |
+
|
| 149 |
+
//
|
| 150 |
+
// Wrapper for CopyOp::copy
|
| 151 |
+
//
|
| 152 |
+
|
| 153 |
+
template <class CopyOp>
|
| 154 |
+
struct CallCOPY {
|
| 155 |
+
template <class... Args>
|
| 156 |
+
CUTE_HOST_DEVICE constexpr void
|
| 157 |
+
operator()(Args&&... args) const {
|
| 158 |
+
return CopyOp::copy(static_cast<Args&&>(args)...);
|
| 159 |
+
}
|
| 160 |
+
};
|
| 161 |
+
|
| 162 |
+
//
|
| 163 |
+
// Utility for exploding pointers/arrays/tensors into functions
|
| 164 |
+
//
|
| 165 |
+
|
| 166 |
+
template <class Fn,
|
| 167 |
+
class PtrA, int... I>
|
| 168 |
+
CUTE_HOST_DEVICE constexpr
|
| 169 |
+
void
|
| 170 |
+
explode(Fn fn,
|
| 171 |
+
PtrA&& a, int_sequence<I...>)
|
| 172 |
+
{
|
| 173 |
+
return fn(a[I]...);
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
template <class Fn,
|
| 177 |
+
class PtrS, int... Is,
|
| 178 |
+
class PtrD, int... Id>
|
| 179 |
+
CUTE_HOST_DEVICE constexpr
|
| 180 |
+
void
|
| 181 |
+
explode(Fn fn,
|
| 182 |
+
PtrS&& s, int_sequence<Is...>,
|
| 183 |
+
PtrD&& d, int_sequence<Id...>)
|
| 184 |
+
{
|
| 185 |
+
return fn(s[Is]..., d[Id]...);
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
template <class Fn,
|
| 189 |
+
class PtrA, int... Ia,
|
| 190 |
+
class PtrB, int... Ib,
|
| 191 |
+
class PtrC, int... Ic>
|
| 192 |
+
CUTE_HOST_DEVICE constexpr
|
| 193 |
+
void
|
| 194 |
+
explode(Fn fn,
|
| 195 |
+
PtrA&& a, int_sequence<Ia...>,
|
| 196 |
+
PtrB&& b, int_sequence<Ib...>,
|
| 197 |
+
PtrC&& c, int_sequence<Ic...>)
|
| 198 |
+
{
|
| 199 |
+
return fn(a[Ia]..., b[Ib]..., c[Ic]...);
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
template <class Fn,
|
| 203 |
+
class PtrD, int... Id,
|
| 204 |
+
class PtrA, int... Ia,
|
| 205 |
+
class PtrB, int... Ib,
|
| 206 |
+
class PtrC, int... Ic>
|
| 207 |
+
CUTE_HOST_DEVICE constexpr
|
| 208 |
+
void
|
| 209 |
+
explode(Fn fn,
|
| 210 |
+
PtrD&& d, int_sequence<Id...>,
|
| 211 |
+
PtrA&& a, int_sequence<Ia...>,
|
| 212 |
+
PtrB&& b, int_sequence<Ib...>,
|
| 213 |
+
PtrC&& c, int_sequence<Ic...>)
|
| 214 |
+
{
|
| 215 |
+
return fn(d[Id]..., a[Ia]..., b[Ib]..., c[Ic]...);
|
| 216 |
+
}
|
| 217 |
+
|
| 218 |
+
template <class Fn,
|
| 219 |
+
class PtrD, int... Id,
|
| 220 |
+
class PtrA, int... Ia,
|
| 221 |
+
class PtrB, int... Ib,
|
| 222 |
+
class PtrC, int... Ic,
|
| 223 |
+
class PtrE, int... Ie>
|
| 224 |
+
CUTE_HOST_DEVICE constexpr
|
| 225 |
+
void
|
| 226 |
+
explode(Fn fn,
|
| 227 |
+
PtrD&& d, int_sequence<Id...>,
|
| 228 |
+
PtrA&& a, int_sequence<Ia...>,
|
| 229 |
+
PtrB&& b, int_sequence<Ib...>,
|
| 230 |
+
PtrC&& c, int_sequence<Ic...>,
|
| 231 |
+
PtrE&& e, int_sequence<Ie...>)
|
| 232 |
+
{
|
| 233 |
+
return fn(d[Id]..., a[Ia]..., b[Ib]..., c[Ic]..., e[Ie]...);
|
| 234 |
+
}
|
| 235 |
+
|
| 236 |
+
template <class Fn,
|
| 237 |
+
class PtrD, int... Id,
|
| 238 |
+
class PtrA, int... Ia,
|
| 239 |
+
class PtrB, int... Ib,
|
| 240 |
+
class PtrC, int... Ic,
|
| 241 |
+
class PtrE, int... Ie,
|
| 242 |
+
class PtrF, int... If>
|
| 243 |
+
CUTE_HOST_DEVICE constexpr
|
| 244 |
+
void
|
| 245 |
+
explode(Fn fn,
|
| 246 |
+
PtrD&& d, int_sequence<Id...>,
|
| 247 |
+
PtrA&& a, int_sequence<Ia...>,
|
| 248 |
+
PtrB&& b, int_sequence<Ib...>,
|
| 249 |
+
PtrC&& c, int_sequence<Ic...>,
|
| 250 |
+
PtrE&& e, int_sequence<Ie...>,
|
| 251 |
+
PtrF&& f, int_sequence<If...>)
|
| 252 |
+
{
|
| 253 |
+
return fn(d[Id]..., a[Ia]..., b[Ib]..., c[Ic]..., e[Ie]..., f[If]...);
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
template <class Fn,
|
| 257 |
+
class PtrD, int... Id,
|
| 258 |
+
class PtrA, int... Ia,
|
| 259 |
+
class PtrB, int... Ib,
|
| 260 |
+
class PtrC, int... Ic,
|
| 261 |
+
class PtrE, int... Ie,
|
| 262 |
+
class PtrF, int... If,
|
| 263 |
+
class PtrG, int... Ig>
|
| 264 |
+
CUTE_HOST_DEVICE constexpr
|
| 265 |
+
void
|
| 266 |
+
explode(Fn fn,
|
| 267 |
+
PtrD&& d, int_sequence<Id...>,
|
| 268 |
+
PtrA&& a, int_sequence<Ia...>,
|
| 269 |
+
PtrB&& b, int_sequence<Ib...>,
|
| 270 |
+
PtrC&& c, int_sequence<Ic...>,
|
| 271 |
+
PtrE&& e, int_sequence<Ie...>,
|
| 272 |
+
PtrF&& f, int_sequence<If...>,
|
| 273 |
+
PtrG&& g, int_sequence<Ig...>)
|
| 274 |
+
{
|
| 275 |
+
return fn(d[Id]..., a[Ia]..., b[Ib]..., c[Ic]..., e[Ie]..., f[If]..., g[Ig]...);
|
| 276 |
+
}
|
| 277 |
+
|
| 278 |
+
//
|
| 279 |
+
// Utility for exploding tuples into functions
|
| 280 |
+
//
|
| 281 |
+
|
| 282 |
+
template <class Fn,
|
| 283 |
+
class TupleA, int... I>
|
| 284 |
+
CUTE_HOST_DEVICE constexpr
|
| 285 |
+
void
|
| 286 |
+
explode_tuple(Fn fn,
|
| 287 |
+
TupleA&& a, int_sequence<I...>)
|
| 288 |
+
{
|
| 289 |
+
return fn(get<I>(a)...);
|
| 290 |
+
}
|
| 291 |
+
|
| 292 |
+
template <class Fn,
|
| 293 |
+
class TupleA, int... Ia,
|
| 294 |
+
class TupleB, int... Ib>
|
| 295 |
+
CUTE_HOST_DEVICE constexpr
|
| 296 |
+
void
|
| 297 |
+
explode_tuple(Fn fn,
|
| 298 |
+
TupleA&& a, int_sequence<Ia...>,
|
| 299 |
+
TupleB&& b, int_sequence<Ib...>)
|
| 300 |
+
{
|
| 301 |
+
return fn(get<Ia>(a)..., get<Ib>(b)...);
|
| 302 |
+
}
|
| 303 |
+
|
| 304 |
+
template <class Fn,
|
| 305 |
+
class TupleA, int... Ia,
|
| 306 |
+
class TupleB, int... Ib,
|
| 307 |
+
class TupleC, int... Ic>
|
| 308 |
+
CUTE_HOST_DEVICE constexpr
|
| 309 |
+
void
|
| 310 |
+
explode_tuple(Fn fn,
|
| 311 |
+
TupleA&& a, int_sequence<Ia...>,
|
| 312 |
+
TupleB&& b, int_sequence<Ib...>,
|
| 313 |
+
TupleC&& c, int_sequence<Ic...>)
|
| 314 |
+
{
|
| 315 |
+
return fn(get<Ia>(a)..., get<Ib>(b)..., get<Ic>(c)...);
|
| 316 |
+
}
|
| 317 |
+
|
| 318 |
+
} // end namespace detail
|
| 319 |
+
|
| 320 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/atom/copy_atom.hpp
ADDED
|
@@ -0,0 +1,765 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/config.hpp> // CUTE_HOST_DEVICE
|
| 34 |
+
#include <cute/tensor_impl.hpp> // cute::Tensor
|
| 35 |
+
#include <cute/util/type_traits.hpp> // cute::__CUTE_REQUIRES
|
| 36 |
+
#include <cute/container/tuple.hpp> // cute::is_tuple
|
| 37 |
+
#include <cute/numeric/integral_constant.hpp> // cute::is_constant, cute::is_integral
|
| 38 |
+
#include <cute/atom/copy_traits.hpp> // cute::Copy_Traits
|
| 39 |
+
#include <cute/atom/mma_atom.hpp> // cute::TiledMMA
|
| 40 |
+
|
| 41 |
+
namespace cute
|
| 42 |
+
{
|
| 43 |
+
|
| 44 |
+
template <class... Args>
|
| 45 |
+
struct Copy_Atom;
|
| 46 |
+
|
| 47 |
+
template <class CopyOperation, class CopyInternalType>
|
| 48 |
+
struct Copy_Atom<CopyOperation, CopyInternalType> : Copy_Atom<Copy_Traits<CopyOperation>, CopyInternalType>
|
| 49 |
+
{};
|
| 50 |
+
|
| 51 |
+
template <class... Args, class CopyInternalType>
|
| 52 |
+
struct Copy_Atom<Copy_Traits<Args...>, CopyInternalType>
|
| 53 |
+
: Copy_Traits<Args...>
|
| 54 |
+
{
|
| 55 |
+
using Traits = Copy_Traits<Args...>;
|
| 56 |
+
|
| 57 |
+
// Bit and Thr layouts from the Copy_Traits
|
| 58 |
+
using ThrID = typename Traits::ThrID;
|
| 59 |
+
using BitLayoutSrc = typename Traits::SrcLayout;
|
| 60 |
+
using BitLayoutDst = typename Traits::DstLayout;
|
| 61 |
+
using BitLayoutRef = typename Traits::RefLayout;
|
| 62 |
+
|
| 63 |
+
using ValType = CopyInternalType;
|
| 64 |
+
|
| 65 |
+
using ValLayoutSrc = decltype(recast_layout<uint1_t, ValType>(BitLayoutSrc{}));
|
| 66 |
+
using ValLayoutDst = decltype(recast_layout<uint1_t, ValType>(BitLayoutDst{}));
|
| 67 |
+
using ValLayoutRef = decltype(recast_layout<uint1_t, ValType>(BitLayoutRef{}));
|
| 68 |
+
|
| 69 |
+
CUTE_STATIC_ASSERT_V(size<0>(ValLayoutSrc{}) == size(ThrID{}), "CopyOperation is not valid for Src of ValType.");
|
| 70 |
+
CUTE_STATIC_ASSERT_V(size<0>(ValLayoutDst{}) == size(ThrID{}), "CopyOperation is not valid for Dst of ValType.");
|
| 71 |
+
CUTE_STATIC_ASSERT_V(size<0>(ValLayoutRef{}) == size(ThrID{}), "CopyOperation is not valid for Ref of ValType.");
|
| 72 |
+
|
| 73 |
+
static constexpr int NumValSrc = size<1>(ValLayoutSrc{});
|
| 74 |
+
static constexpr int NumValDst = size<1>(ValLayoutDst{});
|
| 75 |
+
|
| 76 |
+
// Additional Trait parameters/transformations
|
| 77 |
+
template <class... TraitsArgs>
|
| 78 |
+
CUTE_HOST_DEVICE
|
| 79 |
+
auto
|
| 80 |
+
with(TraitsArgs&&... args) const {
|
| 81 |
+
auto traits = Traits::with(static_cast<TraitsArgs&&>(args)...);
|
| 82 |
+
return Copy_Atom<decltype(traits), CopyInternalType>{traits};
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
//
|
| 86 |
+
// Tensor call interfaces
|
| 87 |
+
//
|
| 88 |
+
|
| 89 |
+
// Check and call instruction, or recurse
|
| 90 |
+
template <class SEngine, class SLayout,
|
| 91 |
+
class DEngine, class DLayout>
|
| 92 |
+
CUTE_HOST_DEVICE
|
| 93 |
+
void
|
| 94 |
+
call(Tensor<SEngine,SLayout> const& src,
|
| 95 |
+
Tensor<DEngine,DLayout> & dst) const
|
| 96 |
+
{
|
| 97 |
+
static_assert(SLayout::rank == 1, "Expected rank-1 src tensor");
|
| 98 |
+
static_assert(DLayout::rank == 1, "Expected rank-1 dst tensor");
|
| 99 |
+
|
| 100 |
+
if constexpr (is_constant<NumValSrc, decltype(size(src))>::value ||
|
| 101 |
+
is_constant<NumValDst, decltype(size(dst))>::value) {
|
| 102 |
+
// Dispatch to unpack to execute instruction
|
| 103 |
+
return copy_unpack(static_cast<Traits const&>(*this), src, dst);
|
| 104 |
+
} else if constexpr (is_tuple<decltype(shape(src))>::value &&
|
| 105 |
+
is_tuple<decltype(shape(dst))>::value) {
|
| 106 |
+
// If the size of the src/dst doesn't match the instruction,
|
| 107 |
+
// recurse this rank-1 layout by peeling off the mode
|
| 108 |
+
// ((A,B,C,...)) -> (A,B,C,...)
|
| 109 |
+
return copy(*this, tensor<0>(src), tensor<0>(dst));
|
| 110 |
+
} else {
|
| 111 |
+
static_assert(dependent_false<SEngine>,
|
| 112 |
+
"CopyAtom: Src/Dst partitioning does not match the instruction requirement.");
|
| 113 |
+
}
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
// Accept mutable temporaries
|
| 117 |
+
template <class SEngine, class SLayout,
|
| 118 |
+
class DEngine, class DLayout>
|
| 119 |
+
CUTE_HOST_DEVICE
|
| 120 |
+
void
|
| 121 |
+
call(Tensor<SEngine,SLayout> const& src,
|
| 122 |
+
Tensor<DEngine,DLayout> && dst) const
|
| 123 |
+
{
|
| 124 |
+
return call(src, dst);
|
| 125 |
+
}
|
| 126 |
+
};
|
| 127 |
+
|
| 128 |
+
//
|
| 129 |
+
// A tiling of copy atoms
|
| 130 |
+
//
|
| 131 |
+
|
| 132 |
+
template <class TiledCopy, class ThrIdx>
|
| 133 |
+
struct ThrCopy;
|
| 134 |
+
|
| 135 |
+
template <class Copy_Atom,
|
| 136 |
+
class LayoutCopy_TV, // (tid,vid) -> coord [Need not be 2D...]
|
| 137 |
+
class ShapeTiler_MN> // coord space
|
| 138 |
+
struct TiledCopy : Copy_Atom
|
| 139 |
+
{
|
| 140 |
+
// Layout information from the CopyAtom
|
| 141 |
+
using AtomThrID = typename Copy_Atom::ThrID; // thrid -> thr_idx
|
| 142 |
+
using AtomLayoutSrc = typename Copy_Atom::ValLayoutSrc; // (thr,val) -> offset
|
| 143 |
+
using AtomLayoutDst = typename Copy_Atom::ValLayoutDst; // (thr,val) -> offset
|
| 144 |
+
using AtomLayoutRef = typename Copy_Atom::ValLayoutRef; // (thr,val) -> offset
|
| 145 |
+
|
| 146 |
+
using AtomNumThr = decltype(size<0>(AtomLayoutRef{}));
|
| 147 |
+
using AtomNumVal = decltype(size<1>(AtomLayoutRef{}));
|
| 148 |
+
|
| 149 |
+
// Layout information for the TiledCopy
|
| 150 |
+
using Tiler_MN = ShapeTiler_MN;
|
| 151 |
+
using TiledLayout_TV = LayoutCopy_TV;
|
| 152 |
+
using TiledNumThr = decltype(size<0>(TiledLayout_TV{}));
|
| 153 |
+
using TiledNumVal = decltype(size<1>(TiledLayout_TV{}));
|
| 154 |
+
|
| 155 |
+
CUTE_STATIC_ASSERT_V(TiledNumThr{} % AtomNumThr{} == Int<0>{}, "TiledCopy uses too few thrs for selected CopyAtom");
|
| 156 |
+
CUTE_STATIC_ASSERT_V(TiledNumVal{} % AtomNumVal{} == Int<0>{}, "TiledCopy uses too few vals for selected CopyAtom");
|
| 157 |
+
|
| 158 |
+
// Tile a tensor or a layout from shape
|
| 159 |
+
// (M,N,...)
|
| 160 |
+
// to shape
|
| 161 |
+
// ((ThrV,ThrX),FrgV,(RestM,RestN,...))
|
| 162 |
+
// where
|
| 163 |
+
// ThrV: The threads local to a COPY_ATOM Src.
|
| 164 |
+
// ThrX: The threads tiled across COPY_ATOMs Src.
|
| 165 |
+
// FrgV: The values local to a COPY_ATOM Src.
|
| 166 |
+
// RestM: The values tiled in M.
|
| 167 |
+
// RestN: The values tiled in N.
|
| 168 |
+
template <class STensor>
|
| 169 |
+
CUTE_HOST_DEVICE constexpr static
|
| 170 |
+
auto
|
| 171 |
+
tidfrg_S(STensor&& stensor)
|
| 172 |
+
{
|
| 173 |
+
CUTE_STATIC_ASSERT_V(rank(stensor) >= rank(Tiler_MN{}), "Rank of tensor to be partitioned too small.");
|
| 174 |
+
|
| 175 |
+
// Tile the stensor and compute the (src-thr, src-val) -> (ref-thr, ref-val) layout
|
| 176 |
+
return tile2thrfrg(zipped_divide(stensor,Tiler_MN{}), right_inverse(AtomLayoutRef{}).compose(AtomLayoutSrc{}));
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
// Tile a tensor or a layout from shape
|
| 180 |
+
// (M,N,...)
|
| 181 |
+
// to shape
|
| 182 |
+
// ((ThrV,ThrX),FrgV,(RestM,RestN,...))
|
| 183 |
+
// where
|
| 184 |
+
// ThrV: The threads local to a COPY_ATOM Dst.
|
| 185 |
+
// ThrX: The threads tiled across COPY_ATOMs Dst.
|
| 186 |
+
// FrgV: The values local to a COPY_ATOM Dst.
|
| 187 |
+
// RestM: The values tiled in M.
|
| 188 |
+
// RestN: The values tiled in N.
|
| 189 |
+
template <class DTensor>
|
| 190 |
+
CUTE_HOST_DEVICE constexpr static
|
| 191 |
+
auto
|
| 192 |
+
tidfrg_D(DTensor&& dtensor)
|
| 193 |
+
{
|
| 194 |
+
CUTE_STATIC_ASSERT_V(rank(dtensor) >= rank(Tiler_MN{}), "Rank of tensor to be partitioned too small.");
|
| 195 |
+
|
| 196 |
+
// Tile the dtensor and compute the (dst-thr, dst-val) -> (ref-thr, ref-val) layout
|
| 197 |
+
return tile2thrfrg(zipped_divide(dtensor,Tiler_MN{}), right_inverse(AtomLayoutRef{}).compose(AtomLayoutDst{}));
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
// Tile a tensor or a layout from shape
|
| 201 |
+
// ((TileM,TileN,...), (RestM,RestN,...))
|
| 202 |
+
// to shape
|
| 203 |
+
// ((ThrV,ThrX),FrgV,(RestM,RestN,...))
|
| 204 |
+
template <class Tensor, class Ref2TrgLayout>
|
| 205 |
+
CUTE_HOST_DEVICE constexpr static
|
| 206 |
+
auto
|
| 207 |
+
tile2thrfrg(Tensor&& tensor, Ref2TrgLayout const& ref2trg)
|
| 208 |
+
{
|
| 209 |
+
// Take the thrs/vals that the atom is interested in
|
| 210 |
+
// NOTE: Assumes the AtomNumThr are contiguous and identity within TiledThrID
|
| 211 |
+
auto atom_layout_TV = zipped_divide(TiledLayout_TV{}, make_shape(AtomNumThr{}, AtomNumVal{}));
|
| 212 |
+
// ((atom_tid,atom_val),(rest_tid,rest_val)) -> (m,n)
|
| 213 |
+
|
| 214 |
+
// Transform to the trg layout
|
| 215 |
+
auto trg_layout_TV = atom_layout_TV.compose(ref2trg, _);
|
| 216 |
+
// ((trg_tid,trg_val),(rest_tid,rest_val)) -> (m,n)
|
| 217 |
+
|
| 218 |
+
// Transform the thrs mode from thrid to thr_idx
|
| 219 |
+
// NOTE: Assumes the AtomNumThr are contiguous and identity within TiledThrID
|
| 220 |
+
auto thrval2mn = coalesce(zip(trg_layout_TV), Shape<_1,Shape<_1,_1>>{});
|
| 221 |
+
// ((trg_tid,rest_tid),(trg_val,rest_val)) -> (m,n)
|
| 222 |
+
|
| 223 |
+
/// ==================
|
| 224 |
+
|
| 225 |
+
// Transform the tile mode
|
| 226 |
+
auto tv_tensor = tensor.compose(thrval2mn, _);
|
| 227 |
+
// ((thrid,val),(RestM,RestN,...))
|
| 228 |
+
|
| 229 |
+
// Unfold and return
|
| 230 |
+
return tv_tensor(make_coord(_,_), _);
|
| 231 |
+
}
|
| 232 |
+
|
| 233 |
+
// retile_S and retile_D assume they are working with the reference layout -- they are the same
|
| 234 |
+
template <class Tensor>
|
| 235 |
+
CUTE_HOST_DEVICE constexpr static
|
| 236 |
+
auto
|
| 237 |
+
retile(Tensor&& tensor)
|
| 238 |
+
{
|
| 239 |
+
constexpr int R = remove_cvref_t<Tensor>::rank;
|
| 240 |
+
// Assert that AtomLayoutSrc|Dst is identity so we can skip the Ref transformation
|
| 241 |
+
|
| 242 |
+
// Assume the first size<0>(tensor) elements are the first val_ids in TiledLayout_TV.
|
| 243 |
+
// Then, we only need the shape+layout of those size<0>(tensor) elements in TiledLayout_TV
|
| 244 |
+
// and that shape is what we gather from the other modes of tensor
|
| 245 |
+
|
| 246 |
+
auto V = size<0>(tensor);
|
| 247 |
+
|
| 248 |
+
auto frg_layout_mn = upcast<TiledNumThr{} * V>(right_inverse(TiledLayout_TV{}).with_shape(shape(Tiler_MN{})));
|
| 249 |
+
// (m,n) -> v_idx -- The shape and order of the V inside of TiledLayout_TV
|
| 250 |
+
|
| 251 |
+
auto frg_layout_v = zipped_divide(logical_product(make_layout(V), right_inverse(frg_layout_mn)), make_layout(AtomNumVal{}));
|
| 252 |
+
// (atom_vals,rest_vals) -> (v,m,n)
|
| 253 |
+
|
| 254 |
+
/// =======
|
| 255 |
+
|
| 256 |
+
// Tile the tensor for TileFrg
|
| 257 |
+
auto t_tensor = zipped_divide(tensor, prepend(product_each(shape(frg_layout_mn)), V));
|
| 258 |
+
// ((TileV,TileM,TileN,...),(1,RestM,RestN,...))
|
| 259 |
+
|
| 260 |
+
// Transform the tile mode
|
| 261 |
+
auto v_tensor = t_tensor.compose(frg_layout_v, _);
|
| 262 |
+
// ((atom_vals,rest_vals),(1,RM,RN,...))
|
| 263 |
+
|
| 264 |
+
// Unfold and return
|
| 265 |
+
return v_tensor(_, append<R>(Int<0>{},_));
|
| 266 |
+
}
|
| 267 |
+
|
| 268 |
+
CUTE_HOST_DEVICE constexpr static
|
| 269 |
+
auto
|
| 270 |
+
get_layoutS_TV()
|
| 271 |
+
{
|
| 272 |
+
// (M,N) -> (M,N)
|
| 273 |
+
auto ref_S = make_layout(make_shape(shape(Tiler_MN{}), Int<1>{}));
|
| 274 |
+
// (thr_idx,val_idx) -> (M,N)
|
| 275 |
+
return tile2thrfrg(ref_S, right_inverse(AtomLayoutRef{}).compose(AtomLayoutSrc{}))(_,_,Int<0>{});
|
| 276 |
+
}
|
| 277 |
+
|
| 278 |
+
CUTE_HOST_DEVICE constexpr static
|
| 279 |
+
auto
|
| 280 |
+
get_layoutS_MN()
|
| 281 |
+
{
|
| 282 |
+
// (thr_idx,val_idx) -> (M,N)
|
| 283 |
+
auto layoutS_TV = get_layoutS_TV();
|
| 284 |
+
// (M,K) -> (thr_idx,val_idx)
|
| 285 |
+
auto layoutS_MK = right_inverse(layoutS_TV).with_shape(shape(Tiler_MN{}));
|
| 286 |
+
|
| 287 |
+
// athrid = (v,m,k) -> thr_idx
|
| 288 |
+
auto thrID_S = make_layout(size<0>(TiledLayout_TV{}));
|
| 289 |
+
|
| 290 |
+
return cute::make_tuple(layoutS_MK, thrID_S);
|
| 291 |
+
}
|
| 292 |
+
|
| 293 |
+
CUTE_HOST_DEVICE constexpr static
|
| 294 |
+
auto
|
| 295 |
+
get_layoutD_TV()
|
| 296 |
+
{
|
| 297 |
+
// (M,N) -> (M,N)
|
| 298 |
+
auto ref_D = make_layout(make_shape(shape(Tiler_MN{}), Int<1>{}));
|
| 299 |
+
// (thr_idx,val_idx) -> (M,N)
|
| 300 |
+
return tile2thrfrg(ref_D, right_inverse(AtomLayoutRef{}).compose(AtomLayoutDst{}))(_,_,Int<0>{});
|
| 301 |
+
}
|
| 302 |
+
|
| 303 |
+
CUTE_HOST_DEVICE constexpr static
|
| 304 |
+
auto
|
| 305 |
+
get_layoutD_MN()
|
| 306 |
+
{
|
| 307 |
+
// (thr_idx,val_idx) -> (M,N)
|
| 308 |
+
auto layoutD_TV = get_layoutD_TV();
|
| 309 |
+
// (M,K) -> (thr_idx,val_idx)
|
| 310 |
+
auto layoutD_MK = right_inverse(layoutD_TV).with_shape(shape(Tiler_MN{}));
|
| 311 |
+
|
| 312 |
+
// athrid = (v,m,k) -> thr_idx
|
| 313 |
+
auto thrID_D = make_layout(size<0>(TiledLayout_TV{}));
|
| 314 |
+
|
| 315 |
+
return cute::make_tuple(layoutD_MK, thrID_D);
|
| 316 |
+
}
|
| 317 |
+
|
| 318 |
+
template <class ThrIdx,
|
| 319 |
+
__CUTE_REQUIRES(is_integral<ThrIdx>::value)>
|
| 320 |
+
CUTE_HOST_DEVICE static
|
| 321 |
+
auto
|
| 322 |
+
get_slice(ThrIdx const& thr_idx)
|
| 323 |
+
{
|
| 324 |
+
return ThrCopy<TiledCopy, ThrIdx>(thr_idx);
|
| 325 |
+
}
|
| 326 |
+
|
| 327 |
+
template <class ThrIdx,
|
| 328 |
+
__CUTE_REQUIRES(is_integral<ThrIdx>::value)>
|
| 329 |
+
CUTE_HOST_DEVICE static
|
| 330 |
+
auto
|
| 331 |
+
get_thread_slice(ThrIdx const& thr_idx)
|
| 332 |
+
{
|
| 333 |
+
return get_slice(thr_idx);
|
| 334 |
+
}
|
| 335 |
+
};
|
| 336 |
+
|
| 337 |
+
template <class TiledCopy, class ThrIdx>
|
| 338 |
+
struct ThrCopy
|
| 339 |
+
{
|
| 340 |
+
ThrIdx thr_idx_;
|
| 341 |
+
|
| 342 |
+
CUTE_HOST_DEVICE
|
| 343 |
+
ThrCopy(ThrIdx const& thr_idx) : thr_idx_(thr_idx) {}
|
| 344 |
+
|
| 345 |
+
template <class STensor>
|
| 346 |
+
CUTE_HOST_DEVICE
|
| 347 |
+
auto
|
| 348 |
+
partition_S(STensor&& stensor) const {
|
| 349 |
+
//static_assert(sizeof(typename remove_cvref_t<STensor>::value_type) == sizeof(typename TiledCopy::ValType),
|
| 350 |
+
// "Expected ValType for tiling SrcTensor.");
|
| 351 |
+
auto thr_tensor = make_tensor(static_cast<STensor&&>(stensor).data(), TiledCopy::tidfrg_S(stensor.layout()));
|
| 352 |
+
return thr_tensor(thr_idx_, _, repeat<rank_v<STensor>>(_));
|
| 353 |
+
}
|
| 354 |
+
|
| 355 |
+
template <class DTensor>
|
| 356 |
+
CUTE_HOST_DEVICE
|
| 357 |
+
auto
|
| 358 |
+
partition_D(DTensor&& dtensor) const {
|
| 359 |
+
//static_assert(sizeof(typename remove_cvref_t<DTensor>::value_type) == sizeof(typename TiledCopy::ValType),
|
| 360 |
+
// "Expected ValType for tiling DstTensor.");
|
| 361 |
+
auto thr_tensor = make_tensor(static_cast<DTensor&&>(dtensor).data(), TiledCopy::tidfrg_D(dtensor.layout()));
|
| 362 |
+
return thr_tensor(thr_idx_, _, repeat<rank_v<DTensor>>(_));
|
| 363 |
+
}
|
| 364 |
+
|
| 365 |
+
template <class STensor>
|
| 366 |
+
CUTE_HOST_DEVICE static
|
| 367 |
+
auto
|
| 368 |
+
retile_S(STensor&& stensor) {
|
| 369 |
+
// static_assert(sizeof(typename remove_cvref_t<STensor>::value_type) == sizeof(typename TiledCopy::ValType),
|
| 370 |
+
// "Expected ValType for tiling SrcTensor.");
|
| 371 |
+
return make_tensor(static_cast<STensor&&>(stensor).data(), TiledCopy::retile(stensor.layout()));
|
| 372 |
+
}
|
| 373 |
+
|
| 374 |
+
template <class DTensor>
|
| 375 |
+
CUTE_HOST_DEVICE static
|
| 376 |
+
auto
|
| 377 |
+
retile_D(DTensor&& dtensor) {
|
| 378 |
+
// static_assert(sizeof(typename remove_cvref_t<DTensor>::value_type) == sizeof(typename TiledCopy::ValType),
|
| 379 |
+
// "Expected ValType for tiling DstTensor.");
|
| 380 |
+
return make_tensor(static_cast<DTensor&&>(dtensor).data(), TiledCopy::retile(dtensor.layout()));
|
| 381 |
+
}
|
| 382 |
+
};
|
| 383 |
+
|
| 384 |
+
|
| 385 |
+
template <class... Args,
|
| 386 |
+
class LayoutCopy_TV,
|
| 387 |
+
class Tiler>
|
| 388 |
+
CUTE_HOST_DEVICE
|
| 389 |
+
auto
|
| 390 |
+
make_tiled_copy_impl(Copy_Atom<Args...> const& atom,
|
| 391 |
+
LayoutCopy_TV const&,
|
| 392 |
+
Tiler const&)
|
| 393 |
+
{
|
| 394 |
+
return TiledCopy<Copy_Atom<Args...>, LayoutCopy_TV, Tiler>{atom};
|
| 395 |
+
}
|
| 396 |
+
|
| 397 |
+
//
|
| 398 |
+
// These tile the Copy_Atom as a whole
|
| 399 |
+
//
|
| 400 |
+
|
| 401 |
+
template <class... CArgs, class... MArgs>
|
| 402 |
+
CUTE_HOST_DEVICE
|
| 403 |
+
auto
|
| 404 |
+
make_tiled_copy_A(Copy_Atom<CArgs...> const& copy_atom,
|
| 405 |
+
TiledMMA<MArgs...> const& mma)
|
| 406 |
+
{
|
| 407 |
+
return make_tiled_copy_impl(copy_atom, mma.get_layoutA_TV(), make_shape(tile_size<0>(mma),tile_size<2>(mma)));
|
| 408 |
+
}
|
| 409 |
+
|
| 410 |
+
template <class... CArgs, class... MArgs>
|
| 411 |
+
CUTE_HOST_DEVICE
|
| 412 |
+
auto
|
| 413 |
+
make_tiled_copy_B(Copy_Atom<CArgs...> const& copy_atom,
|
| 414 |
+
TiledMMA<MArgs...> const& mma)
|
| 415 |
+
{
|
| 416 |
+
return make_tiled_copy_impl(copy_atom, mma.get_layoutB_TV(), make_shape(tile_size<1>(mma),tile_size<2>(mma)));
|
| 417 |
+
}
|
| 418 |
+
|
| 419 |
+
template <class... CArgs, class... MArgs>
|
| 420 |
+
CUTE_HOST_DEVICE
|
| 421 |
+
auto
|
| 422 |
+
make_tiled_copy_C(Copy_Atom<CArgs...> const& copy_atom,
|
| 423 |
+
TiledMMA<MArgs...> const& mma)
|
| 424 |
+
{
|
| 425 |
+
return make_tiled_copy_impl(copy_atom, mma.get_layoutC_TV(), make_shape(tile_size<0>(mma),tile_size<1>(mma)));
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
// returns the smallest tiled copy that can retile LayoutC_TV
|
| 429 |
+
// for use with pipelined epilogues with subtiled stores
|
| 430 |
+
template <class... CArgs, class... MArgs>
|
| 431 |
+
CUTE_HOST_DEVICE
|
| 432 |
+
auto
|
| 433 |
+
make_tiled_copy_C_atom(Copy_Atom<CArgs...> const& copy_atom,
|
| 434 |
+
TiledMMA<MArgs...> const& mma)
|
| 435 |
+
{
|
| 436 |
+
// Truncate the V-layout to just the Copy_Atom, keep the V-order
|
| 437 |
+
auto layoutC_TV = mma.get_layoutC_TV();
|
| 438 |
+
auto copy_V = Int<Copy_Atom<CArgs...>::NumValSrc>{};
|
| 439 |
+
CUTE_STATIC_ASSERT_V(copy_V <= size<1>(layoutC_TV));
|
| 440 |
+
auto layout_TV = composition(layoutC_TV, make_layout(make_shape(size<0>(layoutC_TV), copy_V)));
|
| 441 |
+
|
| 442 |
+
// Recompute tiler and restride the TV layout for the new tiler
|
| 443 |
+
|
| 444 |
+
// Tiler -- Find the active elements in the MMA tensor and generate a tiler to extract them
|
| 445 |
+
// Convert to the awkward by-mode tiler to preserve the modes of the tiled MMA
|
| 446 |
+
auto mma_tiler = make_shape(tile_size<0>(mma),tile_size<1>(mma));
|
| 447 |
+
auto mma_zeros = repeat_like(mma_tiler, Int<0>{});
|
| 448 |
+
|
| 449 |
+
auto tiler = transform(make_seq<rank(mma_tiler)>{}, [&](auto i) {
|
| 450 |
+
return filter(composition(make_layout(mma_tiler, replace<i>(mma_zeros, Int<1>{})), layout_TV));
|
| 451 |
+
});
|
| 452 |
+
|
| 453 |
+
// Layout_TV -- Find the (tid,vid) -> tile coord transformation
|
| 454 |
+
// Apply the tiler to a reference and transform the codomain
|
| 455 |
+
// tile_coord -> mma_coord
|
| 456 |
+
auto tile2mma = composition(make_layout(mma_tiler), tiler);
|
| 457 |
+
|
| 458 |
+
// (tid,vid) -> tile_coord
|
| 459 |
+
auto layout_tv = composition(left_inverse(tile2mma), layout_TV);
|
| 460 |
+
|
| 461 |
+
return make_tiled_copy_impl(copy_atom, layout_tv, tiler);
|
| 462 |
+
}
|
| 463 |
+
|
| 464 |
+
/** Produce a TiledCopy from logical thread and values layouts.
|
| 465 |
+
* The thread and value layouts map coordinates to thr_idx and val_idx.
|
| 466 |
+
* The product of these layouts is taken to produce the TV layout and the Tiler.
|
| 467 |
+
* Useful when threads and values need very specific mappings onto coordinates
|
| 468 |
+
* in the target tensors.
|
| 469 |
+
*/
|
| 470 |
+
template <class... Args,
|
| 471 |
+
class ThrLayout,
|
| 472 |
+
class ValLayout = Layout<_1>>
|
| 473 |
+
CUTE_HOST_DEVICE
|
| 474 |
+
auto
|
| 475 |
+
make_tiled_copy(Copy_Atom<Args...> const& copy_atom,
|
| 476 |
+
ThrLayout const& thr_layout = {}, // (m,n) -> thr_idx
|
| 477 |
+
ValLayout const& val_layout = {}) // (m,n) -> val_idx
|
| 478 |
+
{
|
| 479 |
+
// Take the raked_products to compute the Layout_MN
|
| 480 |
+
// (M,N) -> (thr_idx, val_idx)
|
| 481 |
+
auto layout_mn = raked_product(thr_layout, val_layout);
|
| 482 |
+
// (thr_idx, val_idx) -> (M,N)
|
| 483 |
+
auto layout_tv = right_inverse(layout_mn).with_shape(make_shape(size(thr_layout), size(val_layout)));
|
| 484 |
+
// Tiler for extracting relevant elements
|
| 485 |
+
// (M,N) -> tensor coord
|
| 486 |
+
auto tiler = product_each(shape(layout_mn));
|
| 487 |
+
|
| 488 |
+
#if 0
|
| 489 |
+
print("thr_layout: "); print(thr_layout); print("\n");
|
| 490 |
+
print("val_layout: "); print(val_layout); print("\n");
|
| 491 |
+
print("layout_mn : "); print(layout_mn); print("\n");
|
| 492 |
+
print("layout_tv : "); print(layout_tv); print("\n");
|
| 493 |
+
print("tiler : "); print(tiler); print("\n");
|
| 494 |
+
#endif
|
| 495 |
+
|
| 496 |
+
return make_tiled_copy_impl(copy_atom, layout_tv, tiler);
|
| 497 |
+
}
|
| 498 |
+
|
| 499 |
+
/** Produce a TiledCopy from thread and value offset maps.
|
| 500 |
+
* The TV Layout maps threads and values to the codomain of the data_layout.
|
| 501 |
+
* It is verified that the intended codomain is valid within data_layout.
|
| 502 |
+
* Useful when threads and values don't care about owning specific coordinates, but
|
| 503 |
+
* care more about the vector-width and offsets between them.
|
| 504 |
+
*/
|
| 505 |
+
template <class... Args, class AtomTVLayout, class DataLayout>
|
| 506 |
+
CUTE_HOST_DEVICE constexpr
|
| 507 |
+
auto
|
| 508 |
+
make_cotiled_copy(Copy_Atom<Args...> const& copy_atom,
|
| 509 |
+
AtomTVLayout const& atom_tv_layout, // atom (thr,val) -> data addr
|
| 510 |
+
DataLayout const& data_layout) // coord -> data addr The target layout
|
| 511 |
+
{
|
| 512 |
+
static_assert(is_static<AtomTVLayout>::value);
|
| 513 |
+
static_assert(is_static<DataLayout>::value);
|
| 514 |
+
|
| 515 |
+
// data addr -> data coord Append 1:0 so off-the-ends get the stride-0
|
| 516 |
+
auto inv_data_layout = make_layout(left_inverse(data_layout), Layout<_1,_0>{});
|
| 517 |
+
|
| 518 |
+
// (tid,vid) -> data_coord
|
| 519 |
+
auto layout_tv_data = composition(inv_data_layout, atom_tv_layout);
|
| 520 |
+
|
| 521 |
+
// Check validity
|
| 522 |
+
CUTE_STATIC_ASSERT_V(coalesce(composition(data_layout, layout<1>(layout_tv_data))) == coalesce(layout<1>(atom_tv_layout)),
|
| 523 |
+
"The memory pointed to by AtomTVLayout does not exist in the DataLayout.");
|
| 524 |
+
//
|
| 525 |
+
// Tiler -- Find the active elements in the DATA tensor and generate a tiler to extract them
|
| 526 |
+
//
|
| 527 |
+
|
| 528 |
+
// Convert to the awkward by-mode tiler to preserve the modes of the tiled DATA
|
| 529 |
+
auto flat_data_shape = product_each(shape(data_layout));
|
| 530 |
+
auto flat_data_zeros = repeat<rank(flat_data_shape)>(Int<0>{});
|
| 531 |
+
|
| 532 |
+
auto tiler = transform(make_seq<rank(flat_data_shape)>{}, [&](auto i) {
|
| 533 |
+
return filter(composition(make_layout(flat_data_shape, replace<i>(flat_data_zeros, Int<1>{})), layout_tv_data));
|
| 534 |
+
});
|
| 535 |
+
|
| 536 |
+
//
|
| 537 |
+
// Layout_TV -- Find the (tid,vid) -> tile coord transformation
|
| 538 |
+
//
|
| 539 |
+
|
| 540 |
+
// Apply the tiler to a reference and transform the codomain
|
| 541 |
+
// tile_coord -> data_coord
|
| 542 |
+
auto tile2data = composition(make_layout(flat_data_shape), tiler);
|
| 543 |
+
|
| 544 |
+
// (tid,vid) -> tile_coord
|
| 545 |
+
auto layout_tv = composition(left_inverse(tile2data), layout_tv_data);
|
| 546 |
+
return make_tiled_copy_impl(copy_atom, layout_tv, tiler);
|
| 547 |
+
}
|
| 548 |
+
|
| 549 |
+
// Make a TiledCopy out of the copy_atom that matches the Src-Layout of tiled_copy
|
| 550 |
+
template <class... Args,
|
| 551 |
+
class TiledCopy>
|
| 552 |
+
CUTE_HOST_DEVICE
|
| 553 |
+
auto
|
| 554 |
+
make_tiled_copy_S(Copy_Atom<Args...> const& copy_atom,
|
| 555 |
+
TiledCopy const& tiled_copy)
|
| 556 |
+
{
|
| 557 |
+
return make_tiled_copy_impl(copy_atom, tiled_copy.get_layoutS_TV(), typename TiledCopy::Tiler_MN{});
|
| 558 |
+
}
|
| 559 |
+
|
| 560 |
+
// Make a TiledCopy out of the copy_atom that matches the Dst-Layout of tiled_copy
|
| 561 |
+
template <class... Args,
|
| 562 |
+
class TiledCopy>
|
| 563 |
+
CUTE_HOST_DEVICE
|
| 564 |
+
auto
|
| 565 |
+
make_tiled_copy_D(Copy_Atom<Args...> const& copy_atom,
|
| 566 |
+
TiledCopy const& tiled_copy)
|
| 567 |
+
{
|
| 568 |
+
return make_tiled_copy_impl(copy_atom, tiled_copy.get_layoutD_TV(), typename TiledCopy::Tiler_MN{});
|
| 569 |
+
}
|
| 570 |
+
|
| 571 |
+
//
|
| 572 |
+
// Size
|
| 573 |
+
//
|
| 574 |
+
|
| 575 |
+
// The logical size of a TileCopy
|
| 576 |
+
template <int... I, class... Args>
|
| 577 |
+
CUTE_HOST_DEVICE constexpr
|
| 578 |
+
auto
|
| 579 |
+
tile_size(TiledCopy<Args...> const&)
|
| 580 |
+
{
|
| 581 |
+
return size<I...>(typename TiledCopy<Args...>::Tiler_MN{});
|
| 582 |
+
}
|
| 583 |
+
|
| 584 |
+
// The number of threads involved in a TiledCopy
|
| 585 |
+
template <class... Args>
|
| 586 |
+
CUTE_HOST_DEVICE constexpr
|
| 587 |
+
auto
|
| 588 |
+
size(TiledCopy<Args...> const&)
|
| 589 |
+
{
|
| 590 |
+
return typename TiledCopy<Args...>::TiledNumThr{};
|
| 591 |
+
}
|
| 592 |
+
|
| 593 |
+
//
|
| 594 |
+
// Display utilities
|
| 595 |
+
//
|
| 596 |
+
|
| 597 |
+
template <class... Args, class T>
|
| 598 |
+
CUTE_HOST_DEVICE
|
| 599 |
+
void
|
| 600 |
+
print(Copy_Atom<Copy_Traits<Args...>, T> const&)
|
| 601 |
+
{
|
| 602 |
+
using Atom = Copy_Atom<Copy_Traits<Args...>, T>;
|
| 603 |
+
print("Copy_Atom\n");
|
| 604 |
+
print(" ThrID: "); print(typename Atom::ThrID{}); print("\n");
|
| 605 |
+
print(" ValLayoutSrc: "); print(typename Atom::ValLayoutSrc{}); print("\n");
|
| 606 |
+
print(" ValLayoutDst: "); print(typename Atom::ValLayoutDst{}); print("\n");
|
| 607 |
+
print(" ValLayoutRef: "); print(typename Atom::ValLayoutRef{}); print("\n");
|
| 608 |
+
print(" ValueType: "); print(sizeof_bits<typename Atom::ValType>::value); print("b\n");
|
| 609 |
+
}
|
| 610 |
+
|
| 611 |
+
template <class Atom, class... Args>
|
| 612 |
+
CUTE_HOST_DEVICE
|
| 613 |
+
void
|
| 614 |
+
print(TiledCopy<Atom, Args...> const& copy, char const* pad = "")
|
| 615 |
+
{
|
| 616 |
+
using Copy = TiledCopy<Atom, Args...>;
|
| 617 |
+
print("TiledCopy\n");
|
| 618 |
+
print(" Tiler_MN: "); print(typename Copy::Tiler_MN{}); print("\n");
|
| 619 |
+
print(" TiledLayout_TV: "); print(typename Copy::TiledLayout_TV{}); print("\n");
|
| 620 |
+
print(static_cast<Atom const&>(copy));
|
| 621 |
+
}
|
| 622 |
+
|
| 623 |
+
template <class TiledCopy, class ThrIdx>
|
| 624 |
+
CUTE_HOST_DEVICE
|
| 625 |
+
void
|
| 626 |
+
print(ThrCopy<TiledCopy, ThrIdx> const& thr_copy)
|
| 627 |
+
{
|
| 628 |
+
print("ThrCopy\n");
|
| 629 |
+
print(" ThrIdx: "); print(thr_copy.thr_idx_); print("\n");
|
| 630 |
+
print(TiledCopy{});
|
| 631 |
+
}
|
| 632 |
+
|
| 633 |
+
// TiledCopy to LaTeX TikZ
|
| 634 |
+
template <class... Args, class TikzColorFn = TikzColor_TV>
|
| 635 |
+
CUTE_HOST_DEVICE
|
| 636 |
+
auto
|
| 637 |
+
print_latex(TiledCopy<Args...> const& copy,
|
| 638 |
+
TikzColorFn color = {}) // lambda(thr_idx,val_idx) -> tikz color string
|
| 639 |
+
{
|
| 640 |
+
auto [layoutS_MN, thrID_S] = copy.get_layoutS_MN();
|
| 641 |
+
auto [layoutD_MN, thrID_D] = copy.get_layoutD_MN();
|
| 642 |
+
|
| 643 |
+
print_latex_copy(layoutS_MN, thrID_S,
|
| 644 |
+
layoutD_MN, thrID_D);
|
| 645 |
+
}
|
| 646 |
+
|
| 647 |
+
// MNK Copy Layout to LaTeX TikZ
|
| 648 |
+
template <class LayoutS, class ThrIDS,
|
| 649 |
+
class LayoutD, class ThrIDD,
|
| 650 |
+
class TikzColorFn = TikzColor_TV>
|
| 651 |
+
CUTE_HOST_DEVICE
|
| 652 |
+
void
|
| 653 |
+
print_latex_copy(LayoutS const& S, ThrIDS const& TS, // (m,n) -> (tid,vid) and tid -> thr_idx
|
| 654 |
+
LayoutD const& D, ThrIDD const& TD, // (m,n) -> (tid,vid) and tid -> thr_idx
|
| 655 |
+
TikzColorFn color = {}) // lambda(thr_idx,val_idx) -> tikz color string
|
| 656 |
+
{
|
| 657 |
+
CUTE_STATIC_ASSERT_V(rank(S) == Int<2>{});
|
| 658 |
+
CUTE_STATIC_ASSERT_V(rank(D) == Int<2>{});
|
| 659 |
+
|
| 660 |
+
assert(size<0>(S) == size<0>(D));
|
| 661 |
+
assert(size<1>(S) == size<1>(D));
|
| 662 |
+
|
| 663 |
+
// Commented prints
|
| 664 |
+
printf("%% LayoutS: "); print(S); printf("\n");
|
| 665 |
+
printf("%% ThrIDS : "); print(TS); printf("\n");
|
| 666 |
+
printf("%% LayoutD: "); print(D); printf("\n");
|
| 667 |
+
printf("%% ThrIDD : "); print(TD); printf("\n\n");
|
| 668 |
+
|
| 669 |
+
// Header
|
| 670 |
+
printf("\\documentclass[convert]{standalone}\n"
|
| 671 |
+
"\\usepackage{tikz}\n\n"
|
| 672 |
+
"\\begin{document}\n"
|
| 673 |
+
"\\begin{tikzpicture}[x={(0cm,-1cm)},y={(1cm,0cm)},every node/.style={minimum size=1cm, outer sep=0pt}]\n\n");
|
| 674 |
+
|
| 675 |
+
// S starting at 0,0
|
| 676 |
+
for (int i = 0; i < size<0>(S); ++i) {
|
| 677 |
+
for (int j = 0; j < size<1>(S); ++j) {
|
| 678 |
+
int thrid = S(i,j) % size(TS);
|
| 679 |
+
int val_idx = S(i,j) / size(TS);
|
| 680 |
+
int thr_idx = TS(thrid);
|
| 681 |
+
|
| 682 |
+
printf("\\node[fill=%s] at (%d,%d) {\\shortstack{T%d \\\\ V%d}};\n",
|
| 683 |
+
color(thr_idx, val_idx),
|
| 684 |
+
i, j,
|
| 685 |
+
thr_idx, val_idx);
|
| 686 |
+
}
|
| 687 |
+
}
|
| 688 |
+
// Grid
|
| 689 |
+
printf("\\draw[color=black,thick,shift={(-0.5,-0.5)}] (%d,%d) grid (%d,%d);\n\n",
|
| 690 |
+
0, 0, int(size<0>(S)), int(size<1>(S)));
|
| 691 |
+
// S Labels
|
| 692 |
+
for (int i = 0, j = -1; i < size<0>(S); ++i) {
|
| 693 |
+
printf("\\node at (%d,%d) {\\Large{\\texttt{%d}}};\n", i, j, i);
|
| 694 |
+
}
|
| 695 |
+
for (int i = -1, j = 0; j < size<1>(S); ++j) {
|
| 696 |
+
printf("\\node at (%d,%d) {\\Large{\\texttt{%d}}};\n", i, j, j);
|
| 697 |
+
}
|
| 698 |
+
|
| 699 |
+
// D starting at 0,size<1>(S)+3
|
| 700 |
+
for (int i = 0; i < size<0>(D); ++i) {
|
| 701 |
+
for (int j = 0; j < size<1>(D); ++j) {
|
| 702 |
+
int thrid = D(i,j) % size(TD);
|
| 703 |
+
int val_idx = D(i,j) / size(TD);
|
| 704 |
+
int thr_idx = TD(thrid);
|
| 705 |
+
|
| 706 |
+
printf("\\node[fill=%s] at (%d,%d) {\\shortstack{T%d \\\\ V%d}};\n",
|
| 707 |
+
color(thr_idx, val_idx),
|
| 708 |
+
i, j + size<1>(S) + 3,
|
| 709 |
+
thr_idx, val_idx);
|
| 710 |
+
}
|
| 711 |
+
}
|
| 712 |
+
// Grid
|
| 713 |
+
printf("\\draw[color=black,thick,shift={(-0.5,-0.5)}] (%d,%d) grid (%d,%d);\n\n",
|
| 714 |
+
0, int(size<1>(S)+3), int(size<0>(D)), int(size<1>(D)+size<1>(S)+3));
|
| 715 |
+
// D Labels
|
| 716 |
+
for (int i = 0, j = size<1>(D); i < size<0>(D); ++i) {
|
| 717 |
+
printf("\\node at (%d,%d) {\\Large{\\texttt{%d}}};\n", i, j + size<1>(S) + 3, i);
|
| 718 |
+
}
|
| 719 |
+
for (int i = -1, j = 0; j < size<1>(D); ++j) {
|
| 720 |
+
printf("\\node at (%d,%d) {\\Large{\\texttt{%d}}};\n", i, j + size<1>(S) + 3, j);
|
| 721 |
+
}
|
| 722 |
+
|
| 723 |
+
// Footer
|
| 724 |
+
printf("\\end{tikzpicture}\n"
|
| 725 |
+
"\\end{document}\n");
|
| 726 |
+
}
|
| 727 |
+
|
| 728 |
+
} // end namespace cute
|
| 729 |
+
|
| 730 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
| 731 |
+
|
| 732 |
+
#include <cute/atom/copy_traits_sm50.hpp>
|
| 733 |
+
#include <cute/atom/copy_traits_sm75.hpp>
|
| 734 |
+
#include <cute/atom/copy_traits_sm80.hpp>
|
| 735 |
+
#include <cute/atom/copy_traits_sm90.hpp>
|
| 736 |
+
#include <cute/atom/copy_traits_sm100.hpp>
|
| 737 |
+
|
| 738 |
+
|
| 739 |
+
// Config
|
| 740 |
+
#if (__CUDACC_VER_MAJOR__ >= 12)
|
| 741 |
+
# define CUTE_COPY_ATOM_TMA_SM90_ENABLED
|
| 742 |
+
# define CUTE_COPY_ATOM_TMA_SM100_ENABLED
|
| 743 |
+
#endif
|
| 744 |
+
|
| 745 |
+
|
| 746 |
+
#if (!defined(CUTE_COPY_ATOM_TMA_SM90_ENABLED))
|
| 747 |
+
# define CUTE_COPY_ATOM_TMA_SM90_ENABLED
|
| 748 |
+
#endif
|
| 749 |
+
|
| 750 |
+
#if (!defined(CUTE_COPY_ATOM_TMA_SM100_ENABLED))
|
| 751 |
+
# define CUTE_COPY_ATOM_TMA_SM100_ENABLED
|
| 752 |
+
#endif
|
| 753 |
+
|
| 754 |
+
|
| 755 |
+
#if defined(CUTE_COPY_ATOM_TMA_SM90_ENABLED)
|
| 756 |
+
#include <cute/atom/copy_traits_sm90_tma.hpp>
|
| 757 |
+
#endif
|
| 758 |
+
|
| 759 |
+
|
| 760 |
+
#if defined(CUTE_COPY_ATOM_TMA_SM100_ENABLED)
|
| 761 |
+
#include <cute/atom/copy_traits_sm100_tma.hpp>
|
| 762 |
+
#endif
|
| 763 |
+
|
| 764 |
+
|
| 765 |
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
lib/python3.12/site-packages/deep_gemm/include/cute/atom/copy_traits.hpp
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
#include <cute/arch/copy.hpp>
|
| 34 |
+
|
| 35 |
+
#include <cute/tensor_impl.hpp>
|
| 36 |
+
|
| 37 |
+
namespace cute
|
| 38 |
+
{
|
| 39 |
+
|
| 40 |
+
/**
|
| 41 |
+
* concept Copy_Traits
|
| 42 |
+
* {
|
| 43 |
+
* using ThrID = // Logical thread id (tid) -> tidx
|
| 44 |
+
*
|
| 45 |
+
* using SrcLayout = // (Logical src thread id (tid), Logical src value id (vid)) -> bit
|
| 46 |
+
* using DstLayout = // (Logical dst thread id (tid), Logical dst value id (vid)) -> bit
|
| 47 |
+
* using RefLayout = // (Logical ref thread id (tid), Logical ref value id (vid)) -> bit
|
| 48 |
+
* };
|
| 49 |
+
*
|
| 50 |
+
* The abstract bit ordering of the Copy_Traits (the codomain of SrcLayout, DstLayout, and RefLayout)
|
| 51 |
+
* is arbitrary and only used to construct maps
|
| 52 |
+
* (ref-tid,ref-vid) -> (src-tid,src-vid)
|
| 53 |
+
* (ref-tid,ref-vid) -> (dst-tid,dst-vid)
|
| 54 |
+
* in TiledCopy. The Layout_TV in TiledCopy is in accordance with the RefLayout of a Traits, then mapped to
|
| 55 |
+
* the Src or Dst (tid,vid) representation on demand.
|
| 56 |
+
*
|
| 57 |
+
*/
|
| 58 |
+
|
| 59 |
+
template <class CopyOperation, class... CopyOpArgs>
|
| 60 |
+
struct Copy_Traits
|
| 61 |
+
{
|
| 62 |
+
static_assert(dependent_false<CopyOperation>, "Copy_Traits not implemented for this CopyOperation.");
|
| 63 |
+
};
|
| 64 |
+
|
| 65 |
+
template <class S, class D>
|
| 66 |
+
struct Copy_Traits<UniversalCopy<S,D>>
|
| 67 |
+
{
|
| 68 |
+
// Logical thread id to thread idx (one-thread)
|
| 69 |
+
using ThrID = Layout<_1>;
|
| 70 |
+
|
| 71 |
+
// Map from (src-thr,src-val) to bit
|
| 72 |
+
using SrcLayout = Layout<Shape<_1,Int<sizeof_bits<S>::value>>>;
|
| 73 |
+
// Map from (dst-thr,dst-val) to bit
|
| 74 |
+
using DstLayout = Layout<Shape<_1,Int<sizeof_bits<D>::value>>>;
|
| 75 |
+
|
| 76 |
+
// Reference map from (thr,val) to bit
|
| 77 |
+
using RefLayout = SrcLayout;
|
| 78 |
+
};
|
| 79 |
+
|
| 80 |
+
template <int MaxVecBits>
|
| 81 |
+
struct Copy_Traits<AutoVectorizingCopyWithAssumedAlignment<MaxVecBits>>
|
| 82 |
+
{
|
| 83 |
+
// Logical thread id to thread idx (one-thread)
|
| 84 |
+
using ThrID = Layout<_1>;
|
| 85 |
+
|
| 86 |
+
// Map from (src-thr,src-val) to bit
|
| 87 |
+
using SrcLayout = Layout<Shape<_1,_1>, Stride<_0,_0>>;
|
| 88 |
+
// Map from (dst-thr,dst-val) to bit
|
| 89 |
+
using DstLayout = Layout<Shape<_1,_1>, Stride<_0,_0>>;
|
| 90 |
+
|
| 91 |
+
// Reference map from (thr,val) to bit
|
| 92 |
+
using RefLayout = SrcLayout;
|
| 93 |
+
};
|
| 94 |
+
|
| 95 |
+
// Extract a CPY_Op from a CPY_Traits
|
| 96 |
+
template <class CPY_Traits>
|
| 97 |
+
struct CPY_Op {};
|
| 98 |
+
|
| 99 |
+
template <class CPY_Op_Arg, class... Args>
|
| 100 |
+
struct CPY_Op<Copy_Traits<CPY_Op_Arg, Args...>> {
|
| 101 |
+
using type = CPY_Op_Arg;
|
| 102 |
+
};
|
| 103 |
+
|
| 104 |
+
//
|
| 105 |
+
// Generic copy_unpack for common argument-based Copy_Traits
|
| 106 |
+
//
|
| 107 |
+
|
| 108 |
+
template <class AnyCPYTraits,
|
| 109 |
+
class SEngine, class SLayout,
|
| 110 |
+
class DEngine, class DLayout>
|
| 111 |
+
CUTE_HOST_DEVICE constexpr
|
| 112 |
+
void
|
| 113 |
+
copy_unpack(AnyCPYTraits const&,
|
| 114 |
+
Tensor<SEngine,SLayout> const& src,
|
| 115 |
+
Tensor<DEngine,DLayout> & dst)
|
| 116 |
+
{
|
| 117 |
+
using CopyOp = typename CPY_Op<AnyCPYTraits>::type;
|
| 118 |
+
using RegistersSrc = typename CopyOp::SRegisters;
|
| 119 |
+
using RegistersDst = typename CopyOp::DRegisters;
|
| 120 |
+
using RegTypeSrc = typename remove_extent<RegistersSrc>::type;
|
| 121 |
+
using RegTypeDst = typename remove_extent<RegistersDst>::type;
|
| 122 |
+
constexpr int RegNumSrc = extent<RegistersSrc>::value;
|
| 123 |
+
constexpr int RegNumDst = extent<RegistersDst>::value;
|
| 124 |
+
|
| 125 |
+
Tensor rS = recast<RegTypeSrc>(src);
|
| 126 |
+
Tensor rD = recast<RegTypeDst>(dst);
|
| 127 |
+
|
| 128 |
+
CUTE_STATIC_ASSERT_V(size(rS) == Int<RegNumSrc>{},
|
| 129 |
+
"Copy_Traits: src failed to vectorize into registers. Layout is incompatible with this CopyOp.");
|
| 130 |
+
CUTE_STATIC_ASSERT_V(size(rD) == Int<RegNumDst>{},
|
| 131 |
+
"Copy_Traits: dst failed to vectorize into registers. Layout is incompatible with this CopyOp.");
|
| 132 |
+
|
| 133 |
+
detail::explode(detail::CallCOPY<CopyOp>{},
|
| 134 |
+
rS, make_int_sequence<RegNumSrc>{},
|
| 135 |
+
rD, make_int_sequence<RegNumDst>{});
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
// Accept mutable temporaries
|
| 139 |
+
template <class AnyCPYTraits,
|
| 140 |
+
class SEngine, class SLayout,
|
| 141 |
+
class DEngine, class DLayout>
|
| 142 |
+
CUTE_HOST_DEVICE constexpr
|
| 143 |
+
void
|
| 144 |
+
copy_unpack(AnyCPYTraits const& traits,
|
| 145 |
+
Tensor<SEngine,SLayout> const& src,
|
| 146 |
+
Tensor<DEngine,DLayout> && dst)
|
| 147 |
+
{
|
| 148 |
+
copy_unpack(traits, src, dst);
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
namespace detail {
|
| 152 |
+
|
| 153 |
+
template <class CopyOp, class = void>
|
| 154 |
+
constexpr bool is_prefetch = false;
|
| 155 |
+
|
| 156 |
+
template <class CopyOp>
|
| 157 |
+
constexpr bool is_prefetch<CopyOp, void_t<typename CopyOp::PREFETCH>> = is_same_v<CopyOp, typename CopyOp::PREFETCH>;
|
| 158 |
+
|
| 159 |
+
} // end namespace detail
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/atom/copy_traits_sm100.hpp
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
lib/python3.12/site-packages/deep_gemm/include/cute/atom/copy_traits_sm100_im2col.hpp
ADDED
|
@@ -0,0 +1,488 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2023 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
#pragma once
|
| 32 |
+
|
| 33 |
+
/*! \file
|
| 34 |
+
\brief im2col make_tma_copy
|
| 35 |
+
|
| 36 |
+
*/
|
| 37 |
+
|
| 38 |
+
#include "cute/arch/copy_sm90.hpp"
|
| 39 |
+
#include "cute/arch/copy_sm90_desc.hpp"
|
| 40 |
+
#include "cute/atom/copy_traits_sm90_im2col.hpp"
|
| 41 |
+
#include "cute/tensor.hpp"
|
| 42 |
+
|
| 43 |
+
namespace cute {
|
| 44 |
+
|
| 45 |
+
struct SM100_TMA_2SM_LOAD_IM2COL_OP : SM100_TMA_2SM_LOAD_IM2COL {};
|
| 46 |
+
|
| 47 |
+
/// @brief Non-executable specialization of Copy_Traits for SM100
|
| 48 |
+
/// im2col TMA load, with TMA descriptor but no barrier.
|
| 49 |
+
///
|
| 50 |
+
/// Use `.with(memory_barrier)` to construct an executable version.
|
| 51 |
+
template <class NumBitsPerTMA, class TMATensor>
|
| 52 |
+
struct Copy_Traits<SM100_TMA_2SM_LOAD_IM2COL, NumBitsPerTMA, TMATensor>
|
| 53 |
+
{
|
| 54 |
+
using ThrID = Layout<_2>;
|
| 55 |
+
// Map from (src-thr,src-val) to bit
|
| 56 |
+
using SrcLayout = Layout<Shape<_2, NumBitsPerTMA>, Stride<NumBitsPerTMA,_1>>;
|
| 57 |
+
// Map from (dst-thr,dst-val) to bit
|
| 58 |
+
using DstLayout = Layout<Shape<_2, NumBitsPerTMA>, Stride<NumBitsPerTMA,_1>>;
|
| 59 |
+
// Reference map from (thr,val) to bit
|
| 60 |
+
using RefLayout = SrcLayout;
|
| 61 |
+
|
| 62 |
+
Im2ColTmaDescriptor tma_desc_;
|
| 63 |
+
TMATensor tma_tensor_;
|
| 64 |
+
|
| 65 |
+
CUTE_HOST_DEVICE constexpr
|
| 66 |
+
Im2ColTmaDescriptor const*
|
| 67 |
+
get_tma_descriptor() const
|
| 68 |
+
{
|
| 69 |
+
return &tma_desc_;
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
template <class GShape>
|
| 73 |
+
CUTE_HOST_DEVICE constexpr
|
| 74 |
+
TMATensor const
|
| 75 |
+
get_tma_tensor(GShape const&) const
|
| 76 |
+
{
|
| 77 |
+
return tma_tensor_;
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
/// @brief Get an executable specialization.
|
| 81 |
+
///
|
| 82 |
+
/// Copy_Traits specializations with SM100_TMA_2SM_LOAD_IM2COL are not
|
| 83 |
+
/// directly executable. Instead, call this "with" member function
|
| 84 |
+
/// to get an executable specialization. "Executable" means that
|
| 85 |
+
/// @c copy_unpack works.
|
| 86 |
+
///
|
| 87 |
+
/// @param tma_mbar Memory barrier for synchronization
|
| 88 |
+
///
|
| 89 |
+
/// @param multicast_mask Multicast mask (unused; only exists
|
| 90 |
+
/// for consistency with the actual multicast Copy_Traits
|
| 91 |
+
/// specialization)
|
| 92 |
+
///
|
| 93 |
+
/// @return Executable specialization of @c Copy_Traits
|
| 94 |
+
CUTE_HOST_DEVICE constexpr
|
| 95 |
+
Copy_Traits<SM100_TMA_2SM_LOAD_IM2COL_OP, NumBitsPerTMA>
|
| 96 |
+
with(uint64_t& tma_mbar, [[maybe_unused]] uint16_t const& multicast_mask = 0) const
|
| 97 |
+
{
|
| 98 |
+
return {{}, {&tma_desc_, &tma_mbar}};
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
// Copy_Traits specializations with SM100_TMA_2SM_LOAD_IM2COL
|
| 102 |
+
// are not directly executable. Instead, call .with
|
| 103 |
+
// to get an executable specialization.
|
| 104 |
+
template <class TS, class SLayout,
|
| 105 |
+
class TD, class DLayout>
|
| 106 |
+
CUTE_HOST_DEVICE friend constexpr void
|
| 107 |
+
copy_unpack(Copy_Traits const& traits,
|
| 108 |
+
Tensor<TS,SLayout> const& src,
|
| 109 |
+
Tensor<TD,DLayout> & dst) = delete;
|
| 110 |
+
};
|
| 111 |
+
|
| 112 |
+
/// TMA load, with TMA descriptor and barrier.
|
| 113 |
+
template <class NumBitsPerTMA>
|
| 114 |
+
struct Copy_Traits<SM100_TMA_2SM_LOAD_IM2COL_OP, NumBitsPerTMA>
|
| 115 |
+
: TMA_LOAD_IM2COL_Unpack<SM100_TMA_2SM_LOAD_IM2COL_OP>
|
| 116 |
+
{
|
| 117 |
+
using ThrID = Layout<_2>;
|
| 118 |
+
// Map from (src-thr,src-val) to bit
|
| 119 |
+
using SrcLayout = Layout<Shape<_2, NumBitsPerTMA>, Stride<NumBitsPerTMA,_1>>;
|
| 120 |
+
// Map from (dst-thr,dst-val) to bit
|
| 121 |
+
using DstLayout = Layout<Shape<_2, NumBitsPerTMA>, Stride<NumBitsPerTMA,_1>>;
|
| 122 |
+
// Reference map from (thr,val) to bit
|
| 123 |
+
using RefLayout = SrcLayout;
|
| 124 |
+
|
| 125 |
+
// SM100_TMA_2SM_LOAD_IM2COL arguments
|
| 126 |
+
tuple<
|
| 127 |
+
Im2ColTmaDescriptor const*,
|
| 128 |
+
uint64_t* // smem mbarrier
|
| 129 |
+
> const opargs_;
|
| 130 |
+
};
|
| 131 |
+
|
| 132 |
+
//////////////////////////////////////////////////////////////////////////////
|
| 133 |
+
///////////////////////////// TMA_LOAD_MULTICAST /////////////////////////////
|
| 134 |
+
//////////////////////////////////////////////////////////////////////////////
|
| 135 |
+
|
| 136 |
+
struct SM100_TMA_2SM_LOAD_IM2COL_MULTICAST_OP : SM100_TMA_2SM_LOAD_IM2COL_MULTICAST {};
|
| 137 |
+
|
| 138 |
+
/// @brief Non-executable specialization of Copy_Traits for SM100
|
| 139 |
+
/// im2col TMA load, with TMA descriptor but no barrier or multicast
|
| 140 |
+
/// mask.
|
| 141 |
+
///
|
| 142 |
+
/// Use `.with(memory_barrier)` to construct an executable version.
|
| 143 |
+
template <class NumBitsPerTMA, class TMATensor>
|
| 144 |
+
struct Copy_Traits<SM100_TMA_2SM_LOAD_IM2COL_MULTICAST, NumBitsPerTMA, TMATensor>
|
| 145 |
+
{
|
| 146 |
+
using ThrID = Layout<_2>;
|
| 147 |
+
// Map from (src-thr,src-val) to bit
|
| 148 |
+
using SrcLayout = Layout<Shape<_2, NumBitsPerTMA>, Stride<NumBitsPerTMA,_1>>;
|
| 149 |
+
// Map from (dst-thr,dst-val) to bit
|
| 150 |
+
using DstLayout = Layout<Shape<_2, NumBitsPerTMA>, Stride<NumBitsPerTMA,_1>>;
|
| 151 |
+
// Reference map from (thr,val) to bit
|
| 152 |
+
using RefLayout = SrcLayout;
|
| 153 |
+
|
| 154 |
+
Im2ColTmaDescriptor tma_desc_;
|
| 155 |
+
TMATensor tma_tensor_;
|
| 156 |
+
|
| 157 |
+
CUTE_HOST_DEVICE constexpr
|
| 158 |
+
Im2ColTmaDescriptor const*
|
| 159 |
+
get_tma_descriptor() const
|
| 160 |
+
{
|
| 161 |
+
return &tma_desc_;
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
template <class GShape>
|
| 165 |
+
CUTE_HOST_DEVICE constexpr
|
| 166 |
+
TMATensor const
|
| 167 |
+
get_tma_tensor(GShape const&) const
|
| 168 |
+
{
|
| 169 |
+
return tma_tensor_;
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
/// @brief Get an executable specialization.
|
| 173 |
+
///
|
| 174 |
+
/// Copy_Traits specializations with SM100_TMA_2SM_LOAD_IM2COL_MULTICAST
|
| 175 |
+
/// are not directly executable. Instead, call this "with" member
|
| 176 |
+
/// function to get an executable specialization. "Executable"
|
| 177 |
+
/// means that @c copy_unpack works.
|
| 178 |
+
///
|
| 179 |
+
/// @param tma_mbar Memory barrier for synchronization
|
| 180 |
+
///
|
| 181 |
+
/// @param multicast_mask Multicast mask (defaults to a single CTA)
|
| 182 |
+
///
|
| 183 |
+
/// @return Executable specialization of @c Copy_Traits
|
| 184 |
+
CUTE_HOST_DEVICE constexpr
|
| 185 |
+
Copy_Traits<SM100_TMA_2SM_LOAD_IM2COL_MULTICAST_OP, NumBitsPerTMA>
|
| 186 |
+
with(uint64_t& tma_mbar, uint16_t const& multicast_mask) const
|
| 187 |
+
{
|
| 188 |
+
return {{}, {&tma_desc_, &tma_mbar, multicast_mask}};
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
// Copy_Traits specializations with SM100_TMA_LOAD_IM2COL_MULTICAST
|
| 192 |
+
// are not directly executable. Instead, call .with to get an
|
| 193 |
+
// executable specialization.
|
| 194 |
+
template <class TS, class SLayout,
|
| 195 |
+
class TD, class DLayout>
|
| 196 |
+
CUTE_HOST_DEVICE friend constexpr void
|
| 197 |
+
copy_unpack(Copy_Traits const& traits,
|
| 198 |
+
Tensor<TS,SLayout> const& src,
|
| 199 |
+
Tensor<TD,DLayout> & dst) = delete;
|
| 200 |
+
};
|
| 201 |
+
|
| 202 |
+
/// @brief Executable specialization of Copy_Traits for SM100 multicast
|
| 203 |
+
/// im2col TMA load, with TMA descriptor, barrier, and multicast mask.
|
| 204 |
+
template <class NumBitsPerTMA>
|
| 205 |
+
struct Copy_Traits<SM100_TMA_2SM_LOAD_IM2COL_MULTICAST_OP, NumBitsPerTMA>
|
| 206 |
+
: TMA_LOAD_IM2COL_Unpack<SM100_TMA_2SM_LOAD_IM2COL_MULTICAST_OP>
|
| 207 |
+
{
|
| 208 |
+
using ThrID = Layout<_2>;
|
| 209 |
+
// Map from (src-thr,src-val) to bit.
|
| 210 |
+
using SrcLayout = Layout<Shape<_2, NumBitsPerTMA>, Stride<NumBitsPerTMA,_1>>;
|
| 211 |
+
// Map from (dst-thr,dst-val) to bit
|
| 212 |
+
using DstLayout = Layout<Shape<_2, NumBitsPerTMA>, Stride<NumBitsPerTMA,_1>>;
|
| 213 |
+
// Reference map from (thr,val) to bit
|
| 214 |
+
using RefLayout = SrcLayout;
|
| 215 |
+
|
| 216 |
+
// SM100_TMA_2SM_LOAD_IM2COL_MULTICAST arguments
|
| 217 |
+
tuple<
|
| 218 |
+
Im2ColTmaDescriptor const*,
|
| 219 |
+
uint64_t*, // smem mbarrier
|
| 220 |
+
uint16_t // multicast mask
|
| 221 |
+
> const opargs_;
|
| 222 |
+
};
|
| 223 |
+
|
| 224 |
+
////////////////////////////////////
|
| 225 |
+
// Make TMA
|
| 226 |
+
///////////////////////////////////
|
| 227 |
+
|
| 228 |
+
#if !defined(__CUDACC_RTC__)
|
| 229 |
+
/** Make a CuTe CTA-collective TiledCopy for a TMA operation.
|
| 230 |
+
*
|
| 231 |
+
* @param CopyOp The target copy operation: SM100_TMA_2SM_LOAD
|
| 232 |
+
* @param gtensor The GMEM Tensor to be involved in the TMA.
|
| 233 |
+
* @param slayout The SMEM Layout to be involved in the TMA.
|
| 234 |
+
* @param cluster_tile The Cluster-local tile that each Cluster will be tiling GMEM with.
|
| 235 |
+
* This is often the cluster_tile_shape that is used to tile the GMEM:
|
| 236 |
+
* local_tile(gtensor, cluster_tile_shape, cluster_coord)
|
| 237 |
+
* -> Cluster-local tile of GMEM
|
| 238 |
+
* @param mma The TiledMMA that defines the Cluster-Tile to Block-Tile partitioning.
|
| 239 |
+
*
|
| 240 |
+
* This code attempts to maximize the TMA box size. It does this by tracing
|
| 241 |
+
* the SMEM "vector" -- the inverse of the smem layout -- to find the largest
|
| 242 |
+
* contiguous array of smem that can be written to/from global memory given
|
| 243 |
+
* the constraints that the TMA instruction imposes.
|
| 244 |
+
*
|
| 245 |
+
* This is accomplished by assigning "basis" strides to the GMEM to track which
|
| 246 |
+
* modes of SMEM map to which modes of GMEM, then reordering the modes of GMEM according
|
| 247 |
+
* to the SMEM vector, and then using those GMEM/SMEM modes to fill in the desc.
|
| 248 |
+
*
|
| 249 |
+
* Examples:
|
| 250 |
+
*/
|
| 251 |
+
template <class CopyOp,
|
| 252 |
+
class GEngine, class GLayout,
|
| 253 |
+
class SLayout,
|
| 254 |
+
class Cluster_Tile,
|
| 255 |
+
class... Args,
|
| 256 |
+
class LowerCornerStride,
|
| 257 |
+
class UpperCornerStride,
|
| 258 |
+
class LowerPaddingStride,
|
| 259 |
+
class UpperPaddingStride,
|
| 260 |
+
class TraversalStride,
|
| 261 |
+
class LowerSRTStride,
|
| 262 |
+
class DilationStride>
|
| 263 |
+
CUTE_HOST
|
| 264 |
+
auto
|
| 265 |
+
make_im2col_tma_copy_A_sm100(CopyOp const& copy_op,
|
| 266 |
+
Tensor<GEngine,GLayout> const& gtensor, // (M,K,...)
|
| 267 |
+
SLayout const& slayout, // (MMA, MMA_M, MMA_K)
|
| 268 |
+
Cluster_Tile const& cluster_tile, // (TILE_M,TILE_N,TILE_K)
|
| 269 |
+
TiledMMA<Args...> const& mma,
|
| 270 |
+
LowerCornerStride const& lower_corner_whd,
|
| 271 |
+
UpperCornerStride const& upper_corner_whd,
|
| 272 |
+
LowerPaddingStride const& lower_padding_whd,
|
| 273 |
+
UpperPaddingStride const& upper_padding_whd,
|
| 274 |
+
TraversalStride const& stride_whd,
|
| 275 |
+
LowerSRTStride const& lower_srt,
|
| 276 |
+
DilationStride const& stride_srt,
|
| 277 |
+
TMA::DescriptorAuxParams const& aux_params = {})
|
| 278 |
+
{
|
| 279 |
+
constexpr int R = GLayout::rank;
|
| 280 |
+
// Keep only MK modes from MNK
|
| 281 |
+
auto cluster_tile_shape = append<R>(make_shape(get<0>(cluster_tile), get<2>(cluster_tile)), Int<1>{});
|
| 282 |
+
auto cluster_layout = make_identity_layout(cluster_tile_shape);
|
| 283 |
+
// cta val idx -> gmem mode
|
| 284 |
+
auto cta_v_tile = layout<1>(mma.thrfrg_A(cluster_layout))(_, repeat<R>(_));
|
| 285 |
+
|
| 286 |
+
auto cta_t_vmnk_strides = [](){
|
| 287 |
+
if constexpr (is_same_v<CopyOp, SM90_TMA_LOAD_IM2COL_MULTICAST> ||
|
| 288 |
+
is_same_v<CopyOp, SM100_TMA_2SM_LOAD_IM2COL_MULTICAST>) {
|
| 289 |
+
return Stride<_0,_0,_1,_0>{}; // VMNK: Use only the N-CTAs in the Multicast
|
| 290 |
+
} else
|
| 291 |
+
if constexpr (is_same_v<CopyOp, SM90_TMA_LOAD_IM2COL> ||
|
| 292 |
+
is_same_v<CopyOp, SM100_TMA_2SM_LOAD_IM2COL>) {
|
| 293 |
+
return Stride<_0,_0,_0,_0>{}; // VMNK: Use no CTAs in Non-Multicast
|
| 294 |
+
} else {
|
| 295 |
+
static_assert(dependent_false<CopyOp>, "Unsupported TMA");
|
| 296 |
+
}
|
| 297 |
+
}();
|
| 298 |
+
|
| 299 |
+
auto cta_t_shape = shape(mma.get_thr_layout_vmnk());
|
| 300 |
+
// cta rank -> logical cta idx
|
| 301 |
+
auto cta_t_map = make_layout(cta_t_shape, compact_col_major(cta_t_shape, cta_t_vmnk_strides));
|
| 302 |
+
|
| 303 |
+
return detail::make_tma_copy_im2col(copy_op, gtensor, slayout,
|
| 304 |
+
cta_t_map, cta_v_tile,
|
| 305 |
+
lower_corner_whd, upper_corner_whd, lower_padding_whd, upper_padding_whd, stride_whd,
|
| 306 |
+
lower_srt, stride_srt, aux_params);
|
| 307 |
+
}
|
| 308 |
+
|
| 309 |
+
template <class CopyOp,
|
| 310 |
+
class GEngine, class GLayout,
|
| 311 |
+
class SLayout,
|
| 312 |
+
class Cluster_Tile,
|
| 313 |
+
class... Args,
|
| 314 |
+
class LowerCornerStride,
|
| 315 |
+
class UpperCornerStride,
|
| 316 |
+
class LowerPaddingStride,
|
| 317 |
+
class UpperPaddingStride,
|
| 318 |
+
class TraversalStride,
|
| 319 |
+
class LowerSRTStride,
|
| 320 |
+
class DilationStride>
|
| 321 |
+
CUTE_HOST
|
| 322 |
+
auto
|
| 323 |
+
make_im2col_tma_copy_B_sm100(CopyOp const& copy_op,
|
| 324 |
+
Tensor<GEngine,GLayout> const& gtensor, // (N,K,...)
|
| 325 |
+
SLayout const& slayout, // (MMA, MMA_N, MMA_K)
|
| 326 |
+
Cluster_Tile const& cluster_tile, // (TILE_M,TILE_N,TILE_K)
|
| 327 |
+
TiledMMA<Args...> const& mma,
|
| 328 |
+
LowerCornerStride const& lower_corner_whd,
|
| 329 |
+
UpperCornerStride const& upper_corner_whd,
|
| 330 |
+
LowerPaddingStride const& lower_padding_whd,
|
| 331 |
+
UpperPaddingStride const& upper_padding_whd,
|
| 332 |
+
TraversalStride const& stride_whd,
|
| 333 |
+
LowerSRTStride const& lower_srt,
|
| 334 |
+
DilationStride const& stride_srt,
|
| 335 |
+
TMA::DescriptorAuxParams const& aux_params = {})
|
| 336 |
+
{
|
| 337 |
+
constexpr int R = GLayout::rank;
|
| 338 |
+
// Keep only NK modes from MNK
|
| 339 |
+
auto cluster_tile_shape = append<R>(make_shape(get<1>(cluster_tile), get<2>(cluster_tile)), Int<1>{});
|
| 340 |
+
auto cluster_layout = make_identity_layout(cluster_tile_shape);
|
| 341 |
+
// cta val idx -> gmem mode
|
| 342 |
+
auto cta_v_tile = layout<1>(mma.thrfrg_B(cluster_layout))(_, repeat<R>(_));
|
| 343 |
+
|
| 344 |
+
auto cta_t_vmnk_strides = [](){
|
| 345 |
+
if constexpr (is_same_v<CopyOp, SM90_TMA_LOAD_IM2COL_MULTICAST> ||
|
| 346 |
+
is_same_v<CopyOp, SM100_TMA_2SM_LOAD_IM2COL_MULTICAST>) {
|
| 347 |
+
return Stride<_0,_1,_0,_0>{}; // VMNK: Use only the M-CTAs in the Multicast
|
| 348 |
+
} else
|
| 349 |
+
if constexpr (is_same_v<CopyOp, SM90_TMA_LOAD_IM2COL> ||
|
| 350 |
+
is_same_v<CopyOp, SM100_TMA_2SM_LOAD_IM2COL>) {
|
| 351 |
+
return Stride<_0,_0,_0,_0>{}; // VMNK: Use no CTAs in Non-Multicast
|
| 352 |
+
} else {
|
| 353 |
+
static_assert(dependent_false<CopyOp>, "Unsupported TMA");
|
| 354 |
+
}
|
| 355 |
+
}();
|
| 356 |
+
|
| 357 |
+
auto cta_t_shape = shape(mma.get_thr_layout_vmnk());
|
| 358 |
+
// cta rank -> logical cta idx
|
| 359 |
+
auto cta_t_map = make_layout(cta_t_shape, compact_col_major(cta_t_shape, cta_t_vmnk_strides));
|
| 360 |
+
|
| 361 |
+
return detail::make_tma_copy_im2col(copy_op, gtensor, slayout,
|
| 362 |
+
cta_t_map, cta_v_tile,
|
| 363 |
+
lower_corner_whd, upper_corner_whd, lower_padding_whd, upper_padding_whd, stride_whd,
|
| 364 |
+
lower_srt, stride_srt, aux_params);
|
| 365 |
+
}
|
| 366 |
+
|
| 367 |
+
/////////////////////////////////////
|
| 368 |
+
// Experimental Make Im2col TMA Atom
|
| 369 |
+
/////////////////////////////////////
|
| 370 |
+
|
| 371 |
+
template <class TmaInternalType = void,
|
| 372 |
+
class CopyOp,
|
| 373 |
+
class GEngine, class GLayout,
|
| 374 |
+
class SLayout,
|
| 375 |
+
class MMA_Tiler,
|
| 376 |
+
class... Args,
|
| 377 |
+
class ClusterShapeVMNK,
|
| 378 |
+
class LowerCornerStride,
|
| 379 |
+
class UpperCornerStride,
|
| 380 |
+
class LowerPaddingStride,
|
| 381 |
+
class UpperPaddingStride,
|
| 382 |
+
class TraversalStride,
|
| 383 |
+
class LowerSRTStride,
|
| 384 |
+
class DilationStride>
|
| 385 |
+
CUTE_HOST
|
| 386 |
+
auto
|
| 387 |
+
make_im2col_tma_atom_A_sm100(CopyOp const& copy_op,
|
| 388 |
+
Tensor<GEngine,GLayout> const& gtensor, // (M, K, ...)
|
| 389 |
+
SLayout const& slayout, // (MMA, MMA_M, MMA_K, ...)
|
| 390 |
+
MMA_Tiler const& mma_tiler, // (TILE_M, TILE_N, TILE_K, ...)
|
| 391 |
+
TiledMMA<Args...> const& mma,
|
| 392 |
+
ClusterShapeVMNK const& cluster_shape, // (CTA_V, CTA_M, CTA_N, CTA_K)
|
| 393 |
+
LowerCornerStride const& lower_corner_whd,
|
| 394 |
+
UpperCornerStride const& upper_corner_whd,
|
| 395 |
+
LowerPaddingStride const& lower_padding_whd,
|
| 396 |
+
UpperPaddingStride const& upper_padding_whd,
|
| 397 |
+
TraversalStride const& stride_whd,
|
| 398 |
+
LowerSRTStride const& lower_srt,
|
| 399 |
+
DilationStride const& stride_srt,
|
| 400 |
+
TMA::DescriptorAuxParams const& aux_params = {})
|
| 401 |
+
{
|
| 402 |
+
constexpr int R = GLayout::rank;
|
| 403 |
+
// Keep only MK modes from MNK
|
| 404 |
+
auto cluster_tile_shape = append<R>(make_shape(get<0>(mma_tiler), get<2>(mma_tiler)), Int<1>{});
|
| 405 |
+
auto cluster_layout = make_identity_layout(cluster_tile_shape);
|
| 406 |
+
// cta val idx -> gmem mode
|
| 407 |
+
auto cta_v_tile = layout<1>(mma.thrfrg_A(cluster_layout))(_, repeat<R>(_));
|
| 408 |
+
|
| 409 |
+
// The size of the multicasting
|
| 410 |
+
auto num_multicast = [&](){
|
| 411 |
+
if constexpr (is_same_v<CopyOp, SM90_TMA_LOAD_IM2COL_MULTICAST> ||
|
| 412 |
+
is_same_v<CopyOp, SM100_TMA_2SM_LOAD_IM2COL_MULTICAST>) {
|
| 413 |
+
return size<2>(cluster_shape); // VMNK: Use only the N-CTAs in the Multicast
|
| 414 |
+
} else
|
| 415 |
+
if constexpr (is_same_v<CopyOp, SM90_TMA_LOAD_IM2COL> ||
|
| 416 |
+
is_same_v<CopyOp, SM90_TMA_STORE_IM2COL> ||
|
| 417 |
+
is_same_v<CopyOp, SM100_TMA_2SM_LOAD_IM2COL>) {
|
| 418 |
+
return Int<1>{}; // VMNK: Use no CTAs in Non-Multicast
|
| 419 |
+
} else {
|
| 420 |
+
static_assert(dependent_false<CopyOp>, "Unsupported TMA");
|
| 421 |
+
}
|
| 422 |
+
}();
|
| 423 |
+
|
| 424 |
+
return detail::make_tma_atom_im2col(copy_op, gtensor, slayout, num_multicast, cta_v_tile,
|
| 425 |
+
lower_corner_whd, upper_corner_whd, lower_padding_whd, upper_padding_whd,
|
| 426 |
+
stride_whd, lower_srt, stride_srt, aux_params);
|
| 427 |
+
}
|
| 428 |
+
|
| 429 |
+
template <class TmaInternalType = void,
|
| 430 |
+
class CopyOp,
|
| 431 |
+
class GEngine, class GLayout,
|
| 432 |
+
class SLayout,
|
| 433 |
+
class MMA_Tiler,
|
| 434 |
+
class... Args,
|
| 435 |
+
class ClusterShapeVMNK,
|
| 436 |
+
class LowerCornerStride,
|
| 437 |
+
class UpperCornerStride,
|
| 438 |
+
class LowerPaddingStride,
|
| 439 |
+
class UpperPaddingStride,
|
| 440 |
+
class TraversalStride,
|
| 441 |
+
class LowerSRTStride,
|
| 442 |
+
class DilationStride>
|
| 443 |
+
CUTE_HOST
|
| 444 |
+
auto
|
| 445 |
+
make_im2col_tma_atom_B_sm100(CopyOp const& copy_op,
|
| 446 |
+
Tensor<GEngine,GLayout> const& gtensor, // (N, K, ...)
|
| 447 |
+
SLayout const& slayout, // (MMA, MMA_N, MMA_K, ...)
|
| 448 |
+
MMA_Tiler const& mma_tiler, // (TILE_M, TILE_N, TILE_K, ...)
|
| 449 |
+
TiledMMA<Args...> const& mma,
|
| 450 |
+
ClusterShapeVMNK const& cluster_shape, // (CTA_V, CTA_M, CTA_N, CTA_K)
|
| 451 |
+
LowerCornerStride const& lower_corner_whd,
|
| 452 |
+
UpperCornerStride const& upper_corner_whd,
|
| 453 |
+
LowerPaddingStride const& lower_padding_whd,
|
| 454 |
+
UpperPaddingStride const& upper_padding_whd,
|
| 455 |
+
TraversalStride const& stride_whd,
|
| 456 |
+
LowerSRTStride const& lower_srt,
|
| 457 |
+
DilationStride const& stride_srt,
|
| 458 |
+
TMA::DescriptorAuxParams const& aux_params = {})
|
| 459 |
+
{
|
| 460 |
+
constexpr int R = GLayout::rank;
|
| 461 |
+
// Keep only NK modes from MNK
|
| 462 |
+
auto cluster_tile_shape = append<R>(make_shape(get<1>(mma_tiler), get<2>(mma_tiler)), Int<1>{});
|
| 463 |
+
auto cluster_layout = make_identity_layout(cluster_tile_shape);
|
| 464 |
+
// cta val idx -> gmem mode
|
| 465 |
+
auto cta_v_tile = layout<1>(mma.thrfrg_B(cluster_layout))(_, repeat<R>(_));
|
| 466 |
+
|
| 467 |
+
// The size of the multicasting
|
| 468 |
+
auto num_multicast = [&](){
|
| 469 |
+
if constexpr (is_same_v<CopyOp, SM90_TMA_LOAD_IM2COL_MULTICAST> ||
|
| 470 |
+
is_same_v<CopyOp, SM100_TMA_2SM_LOAD_IM2COL_MULTICAST>) {
|
| 471 |
+
return size<1>(cluster_shape); // VMNK: Use only the M-CTAs in the Multicast
|
| 472 |
+
} else
|
| 473 |
+
if constexpr (is_same_v<CopyOp, SM90_TMA_LOAD_IM2COL> ||
|
| 474 |
+
is_same_v<CopyOp, SM90_TMA_STORE_IM2COL> ||
|
| 475 |
+
is_same_v<CopyOp, SM100_TMA_2SM_LOAD_IM2COL>) {
|
| 476 |
+
return Int<1>{}; // VMNK: Use no CTAs in Non-Multicast
|
| 477 |
+
} else {
|
| 478 |
+
static_assert(dependent_false<CopyOp>, "Unsupported TMA");
|
| 479 |
+
}
|
| 480 |
+
}();
|
| 481 |
+
|
| 482 |
+
return detail::make_tma_atom_im2col(copy_op, gtensor, slayout, num_multicast, cta_v_tile,
|
| 483 |
+
lower_corner_whd, upper_corner_whd, lower_padding_whd, upper_padding_whd,
|
| 484 |
+
stride_whd, lower_srt, stride_srt, aux_params);
|
| 485 |
+
}
|
| 486 |
+
#endif // !defined(__CUDACC_RTC__)
|
| 487 |
+
|
| 488 |
+
} // end namespace cute
|
lib/python3.12/site-packages/deep_gemm/include/cute/atom/copy_traits_sm100_tma.hpp
ADDED
|
@@ -0,0 +1,487 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/***************************************************************************************************
|
| 2 |
+
* Copyright (c) 2021 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 3 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
* list of conditions and the following disclaimer.
|
| 10 |
+
*
|
| 11 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
* and/or other materials provided with the distribution.
|
| 14 |
+
*
|
| 15 |
+
* 3. Neither the name of the copyright holder nor the names of its
|
| 16 |
+
* contributors may be used to endorse or promote products derived from
|
| 17 |
+
* this software without specific prior written permission.
|
| 18 |
+
*
|
| 19 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 20 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 21 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 22 |
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 23 |
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 24 |
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 25 |
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 26 |
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 27 |
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 28 |
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
*
|
| 30 |
+
**************************************************************************************************/
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
#pragma once
|
| 35 |
+
|
| 36 |
+
#if !defined(__CUDACC_RTC__)
|
| 37 |
+
#include <cuda.h>
|
| 38 |
+
#endif
|
| 39 |
+
|
| 40 |
+
#include <cute/tensor.hpp>
|
| 41 |
+
#include <cute/atom/copy_traits_sm90_tma.hpp>
|
| 42 |
+
#include <cute/arch/copy_sm100_tma.hpp>
|
| 43 |
+
#include <cute/atom/copy_traits.hpp>
|
| 44 |
+
|
| 45 |
+
namespace cute
|
| 46 |
+
{
|
| 47 |
+
|
| 48 |
+
//////////////////////////////////////////////////////////////////////////////
|
| 49 |
+
////////////////////////////// TMA_LOAD ////////////////////////////////////////
|
| 50 |
+
//////////////////////////////////////////////////////////////////////////////
|
| 51 |
+
|
| 52 |
+
struct SM100_TMA_2SM_LOAD_OP : SM100_TMA_2SM_LOAD {};
|
| 53 |
+
|
| 54 |
+
// The non-executable SM100_TMA_2SM_LOAD with tma_desc and no tma_mbar
|
| 55 |
+
// Use .with(tma_mbar) to construct an executable version
|
| 56 |
+
template <class NumBitsPerTMA, class AuxParams_>
|
| 57 |
+
struct Copy_Traits<SM100_TMA_2SM_LOAD, NumBitsPerTMA, AuxParams_>
|
| 58 |
+
{
|
| 59 |
+
using ThrID = Layout<_2>;
|
| 60 |
+
// Map from (src-thr,src-val) to bit
|
| 61 |
+
using SrcLayout = Layout<Shape<_2,NumBitsPerTMA>, Stride<NumBitsPerTMA,_1>>;
|
| 62 |
+
// Map from (dst-thr,dst-val) to bit
|
| 63 |
+
using DstLayout = Layout<Shape<_2,NumBitsPerTMA>, Stride<NumBitsPerTMA,_1>>;
|
| 64 |
+
// Reference map from (thr,val) to bit
|
| 65 |
+
using RefLayout = SrcLayout;
|
| 66 |
+
|
| 67 |
+
// SM100_TMA_2SM_LOAD arguments
|
| 68 |
+
TmaDescriptor tma_desc_;
|
| 69 |
+
using AuxParams = AuxParams_;
|
| 70 |
+
AuxParams aux_params_;
|
| 71 |
+
|
| 72 |
+
// Return TmaDescriptor/TensorMap
|
| 73 |
+
CUTE_HOST_DEVICE constexpr
|
| 74 |
+
TmaDescriptor const*
|
| 75 |
+
get_tma_descriptor() const {
|
| 76 |
+
return &tma_desc_;
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
// Construct an executable SM100_TMA_2SM_LOAD with tma_mbar
|
| 80 |
+
CUTE_HOST_DEVICE constexpr
|
| 81 |
+
Copy_Traits<SM100_TMA_2SM_LOAD_OP, NumBitsPerTMA>
|
| 82 |
+
with(
|
| 83 |
+
uint64_t& tma_mbar,
|
| 84 |
+
[[maybe_unused]] uint16_t const& multicast_mask = 0,
|
| 85 |
+
TMA::CacheHintSm100 const& cache_hint = TMA::CacheHintSm100::EVICT_NORMAL) const {
|
| 86 |
+
// We accept multicast_mask here to keep the API for both atoms consistent
|
| 87 |
+
return {{}, {&tma_desc_, &tma_mbar, static_cast<uint64_t>(cache_hint)}};
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
// Construct an executable SM100_TMA_2SM_LOAD with tma_mbar (temp. overloaded for grouped gemm/ptr array gemm)
|
| 91 |
+
CUTE_HOST_DEVICE constexpr
|
| 92 |
+
Copy_Traits<SM100_TMA_2SM_LOAD_OP, NumBitsPerTMA>
|
| 93 |
+
with(
|
| 94 |
+
TmaDescriptor const* new_tma_desc,
|
| 95 |
+
uint64_t& tma_mbar,
|
| 96 |
+
[[maybe_unused]] uint16_t const& multicast_mask = 0,
|
| 97 |
+
TMA::CacheHintSm100 const& cache_hint = TMA::CacheHintSm100::EVICT_NORMAL) const {
|
| 98 |
+
// We accept multicast_mask here to keep the API for both atoms consistent
|
| 99 |
+
return {{}, {new_tma_desc, &tma_mbar, static_cast<uint64_t>(cache_hint)}};
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
template <class GShape>
|
| 103 |
+
CUTE_HOST_DEVICE constexpr
|
| 104 |
+
auto
|
| 105 |
+
get_tma_tensor(GShape const& g_shape) const {
|
| 106 |
+
static_assert(is_congruent<decltype(g_shape), decltype(aux_params_.g_stride_)>::value);
|
| 107 |
+
return make_counting_tensor(make_layout(g_shape, aux_params_.g_stride_));
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
// Don't try to execute a copy with SM100_TMA_2SM_LOAD before calling .with()
|
| 111 |
+
template <class TS, class SLayout,
|
| 112 |
+
class TD, class DLayout>
|
| 113 |
+
CUTE_HOST_DEVICE friend constexpr void
|
| 114 |
+
copy_unpack(Copy_Traits const& traits,
|
| 115 |
+
Tensor<TS,SLayout> const& src,
|
| 116 |
+
Tensor<TD,DLayout> & dst) = delete;
|
| 117 |
+
};
|
| 118 |
+
|
| 119 |
+
// The executable SM100_TMA_2SM_LOAD with tma_desc and tma_mbar
|
| 120 |
+
template <class NumBitsPerTMA>
|
| 121 |
+
struct Copy_Traits<SM100_TMA_2SM_LOAD_OP, NumBitsPerTMA>
|
| 122 |
+
: TMA_LOAD_Unpack<SM100_TMA_2SM_LOAD_OP, NumBitsPerTMA>
|
| 123 |
+
{
|
| 124 |
+
using ThrID = Layout<_2>;
|
| 125 |
+
// Map from (src-thr,src-val) to bit
|
| 126 |
+
using SrcLayout = Layout<Shape<_2,NumBitsPerTMA>, Stride<NumBitsPerTMA,_1>>;
|
| 127 |
+
// Map from (dst-thr,dst-val) to bit
|
| 128 |
+
using DstLayout = Layout<Shape<_2,NumBitsPerTMA>, Stride<NumBitsPerTMA,_1>>;
|
| 129 |
+
// Reference map from (thr,val) to bit
|
| 130 |
+
using RefLayout = SrcLayout;
|
| 131 |
+
|
| 132 |
+
// SM100_TMA_2SM_LOAD arguments
|
| 133 |
+
tuple<
|
| 134 |
+
TmaDescriptor const*,
|
| 135 |
+
uint64_t*, // smem mbarrier
|
| 136 |
+
uint64_t // cache hint
|
| 137 |
+
> const opargs_;
|
| 138 |
+
};
|
| 139 |
+
|
| 140 |
+
//////////////////////////////////////////////////////////////////////////////
|
| 141 |
+
///////////////////////////// TMA_LOAD_MULTICAST /////////////////////////////
|
| 142 |
+
//////////////////////////////////////////////////////////////////////////////
|
| 143 |
+
|
| 144 |
+
struct SM100_TMA_2SM_LOAD_MULTICAST_OP : SM100_TMA_2SM_LOAD_MULTICAST {};
|
| 145 |
+
|
| 146 |
+
template <class NumBitsPerTMA, class AuxParams_>
|
| 147 |
+
struct Copy_Traits<SM100_TMA_2SM_LOAD_MULTICAST, NumBitsPerTMA, AuxParams_>
|
| 148 |
+
{
|
| 149 |
+
using ThrID = Layout<_2>;
|
| 150 |
+
// Map from (src-thr,src-val) to bit
|
| 151 |
+
using SrcLayout = Layout<Shape<_2,NumBitsPerTMA>, Stride<NumBitsPerTMA,_1>>;
|
| 152 |
+
// Map from (dst-thr,dst-val) to bit
|
| 153 |
+
using DstLayout = Layout<Shape<_2,NumBitsPerTMA>, Stride<NumBitsPerTMA,_1>>;
|
| 154 |
+
// Reference map from (thr,val) to bit
|
| 155 |
+
using RefLayout = SrcLayout;
|
| 156 |
+
|
| 157 |
+
// SM100_TMA_2SM_LOAD_MULTICAST_OP arguments
|
| 158 |
+
TmaDescriptor tma_desc_;
|
| 159 |
+
using AuxParams = AuxParams_;
|
| 160 |
+
AuxParams aux_params_;
|
| 161 |
+
|
| 162 |
+
// Return TmaDescriptor/TensorMap
|
| 163 |
+
CUTE_HOST_DEVICE constexpr
|
| 164 |
+
TmaDescriptor const*
|
| 165 |
+
get_tma_descriptor() const {
|
| 166 |
+
return &tma_desc_;
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
// Construct an executable SM100_TMA_2SM_LOAD_MULTICAST_OP with tma_mbar
|
| 170 |
+
CUTE_HOST_DEVICE constexpr
|
| 171 |
+
Copy_Traits<SM100_TMA_2SM_LOAD_MULTICAST_OP, NumBitsPerTMA>
|
| 172 |
+
with(
|
| 173 |
+
uint64_t& tma_load_mbar,
|
| 174 |
+
uint16_t const& multicast_mask,
|
| 175 |
+
TMA::CacheHintSm100 const& cache_hint = TMA::CacheHintSm100::EVICT_NORMAL) const {
|
| 176 |
+
return {{}, {&tma_desc_, &tma_load_mbar, multicast_mask, static_cast<uint64_t>(cache_hint)}};
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
// Construct an executable SM100_TMA_2SM_LOAD_MULTICAST_OP with tma_mbar (temp. overloaded for grouped gemm/ptr array gemm)
|
| 180 |
+
CUTE_HOST_DEVICE constexpr
|
| 181 |
+
Copy_Traits<SM100_TMA_2SM_LOAD_MULTICAST_OP, NumBitsPerTMA>
|
| 182 |
+
with(
|
| 183 |
+
TmaDescriptor const* new_tma_desc,
|
| 184 |
+
uint64_t& tma_load_mbar,
|
| 185 |
+
uint16_t const& multicast_mask,
|
| 186 |
+
TMA::CacheHintSm100 const& cache_hint = TMA::CacheHintSm100::EVICT_NORMAL) const {
|
| 187 |
+
return {{}, {new_tma_desc, &tma_load_mbar, multicast_mask, static_cast<uint64_t>(cache_hint)}};
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
template <class GShape>
|
| 191 |
+
CUTE_HOST_DEVICE constexpr
|
| 192 |
+
auto
|
| 193 |
+
get_tma_tensor(GShape const& g_shape) const {
|
| 194 |
+
static_assert(is_congruent<decltype(g_shape), decltype(aux_params_.g_stride_)>::value);
|
| 195 |
+
return make_counting_tensor(make_layout(g_shape, aux_params_.g_stride_));
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
// Don't try to execute a copy with SM100_TMA_2SM_LOAD_MULTICAST_OP before calling .with()
|
| 199 |
+
template <class TS, class SLayout,
|
| 200 |
+
class TD, class DLayout>
|
| 201 |
+
CUTE_HOST_DEVICE friend constexpr void
|
| 202 |
+
copy_unpack(Copy_Traits const& traits,
|
| 203 |
+
Tensor<TS,SLayout> const& src,
|
| 204 |
+
Tensor<TD,DLayout> & dst) = delete;
|
| 205 |
+
};
|
| 206 |
+
|
| 207 |
+
template <class NumBitsPerTMA>
|
| 208 |
+
struct Copy_Traits<SM100_TMA_2SM_LOAD_MULTICAST_OP, NumBitsPerTMA>
|
| 209 |
+
: TMA_LOAD_Unpack<SM100_TMA_2SM_LOAD_MULTICAST_OP, NumBitsPerTMA>
|
| 210 |
+
{
|
| 211 |
+
using ThrID = Layout<_2>;
|
| 212 |
+
// Map from (src-thr,src-val) to bit
|
| 213 |
+
using SrcLayout = Layout<Shape<_2,NumBitsPerTMA>, Stride<NumBitsPerTMA,_1>>;
|
| 214 |
+
// Map from (dst-thr,dst-val) to bit
|
| 215 |
+
using DstLayout = Layout<Shape<_2,NumBitsPerTMA>, Stride<NumBitsPerTMA,_1>>;
|
| 216 |
+
// Reference map from (thr,val) to bit
|
| 217 |
+
using RefLayout = SrcLayout;
|
| 218 |
+
|
| 219 |
+
// SM100_TMA_2SM_LOAD_MULTICAST_OP arguments
|
| 220 |
+
tuple<
|
| 221 |
+
TmaDescriptor const*,
|
| 222 |
+
uint64_t*, // smem mbarrier
|
| 223 |
+
uint16_t, // multicast mask
|
| 224 |
+
uint64_t // cache hint
|
| 225 |
+
> const opargs_;
|
| 226 |
+
};
|
| 227 |
+
|
| 228 |
+
////////////////////////////////////
|
| 229 |
+
// Make TMA
|
| 230 |
+
///////////////////////////////////
|
| 231 |
+
|
| 232 |
+
#if !defined(__CUDACC_RTC__)
|
| 233 |
+
/** Make a CuTe CTA-collective TiledCopy for a TMA operation.
|
| 234 |
+
*
|
| 235 |
+
* @param CopyOp The target copy operation: SM100_TMA_2SM_LOAD
|
| 236 |
+
* @param gtensor The GMEM Tensor to be involved in the TMA.
|
| 237 |
+
* @param slayout The SMEM Layout to be involved in the TMA.
|
| 238 |
+
* @param cluster_tile The Cluster-local tile that each Cluster will be tiling GMEM with.
|
| 239 |
+
* This is often the cluster_tile_shape that is used to tile the GMEM:
|
| 240 |
+
* local_tile(gtensor, cluster_tile_shape, cluster_coord)
|
| 241 |
+
* -> Cluster-local tile of GMEM
|
| 242 |
+
* @param mma The TiledMMA that defines the Cluster-Tile to Block-Tile partitioning.
|
| 243 |
+
*
|
| 244 |
+
* This code attempts to maximize the TMA box size. It does this by tracing
|
| 245 |
+
* the SMEM "vector" -- the inverse of the smem layout -- to find the largest
|
| 246 |
+
* contiguous array of smem that can be written to/from global memory given
|
| 247 |
+
* the constraints that the TMA instruction imposes.
|
| 248 |
+
*
|
| 249 |
+
* This is accomplished by assigning "basis" strides to the GMEM to track which
|
| 250 |
+
* modes of SMEM map to which modes of GMEM, then reordering the modes of GMEM according
|
| 251 |
+
* to the SMEM vector, and then using those GMEM/SMEM modes to fill in the desc.
|
| 252 |
+
*
|
| 253 |
+
* Examples:
|
| 254 |
+
*/
|
| 255 |
+
template <class TmaInternalType = void,
|
| 256 |
+
class CopyOp,
|
| 257 |
+
class GEngine, class GLayout,
|
| 258 |
+
class SLayout,
|
| 259 |
+
class Cluster_Tiler,
|
| 260 |
+
class... Args>
|
| 261 |
+
CUTE_HOST
|
| 262 |
+
auto
|
| 263 |
+
make_tma_copy_A_sm100(CopyOp const& copy_op,
|
| 264 |
+
Tensor<GEngine,GLayout> const& gtensor, // (M, K, ...)
|
| 265 |
+
SLayout const& slayout, // (MMA, MMA_M, MMA_K, ...)
|
| 266 |
+
Cluster_Tiler const& cluster_tiler, // (TILER_M, TILER_N, TILER_K, ...)
|
| 267 |
+
TiledMMA<Args...> const& mma)
|
| 268 |
+
{
|
| 269 |
+
// Keep only MK modes from MNK
|
| 270 |
+
auto cluster_tiler_mk = remove<1>(cluster_tiler);
|
| 271 |
+
// cluster tile coord -> gtensor coord
|
| 272 |
+
auto g_tile = make_identity_layout(shape(gtensor)).compose(cluster_tiler_mk); // (TILE_M, TILE_K, ...)
|
| 273 |
+
// cta val idx -> gmem mode
|
| 274 |
+
auto cta_v_tile = layout<1>(mma.thrfrg_A(g_tile))(_, repeat<rank(g_tile)>(_)); // (MMA, MMA_M, MMA_K, ...)
|
| 275 |
+
|
| 276 |
+
auto cta_t_vmnk_strides = [](){
|
| 277 |
+
if constexpr (is_same_v<CopyOp, SM90_TMA_LOAD_MULTICAST> ||
|
| 278 |
+
is_same_v<CopyOp, SM100_TMA_2SM_LOAD_MULTICAST>) {
|
| 279 |
+
return Stride<_0,_0,_1,_0>{}; // VMNK: Use only the N-CTAs in the Multicast
|
| 280 |
+
} else
|
| 281 |
+
if constexpr (is_same_v<CopyOp, SM90_TMA_LOAD> ||
|
| 282 |
+
is_same_v<CopyOp, SM90_TMA_STORE> ||
|
| 283 |
+
is_same_v<CopyOp, SM100_TMA_2SM_LOAD>) {
|
| 284 |
+
return Stride<_0,_0,_0,_0>{}; // VMNK: Use no CTAs in Non-Multicast
|
| 285 |
+
} else {
|
| 286 |
+
static_assert(dependent_false<CopyOp>, "Unsupported TMA");
|
| 287 |
+
}
|
| 288 |
+
}();
|
| 289 |
+
|
| 290 |
+
auto cta_t_shape = shape(mma.get_thr_layout_vmnk());
|
| 291 |
+
// cta rank -> logical cta idx
|
| 292 |
+
auto cta_t_map = coalesce(make_layout(cta_t_shape, compact_col_major(cta_t_shape, cta_t_vmnk_strides)));
|
| 293 |
+
|
| 294 |
+
// Prefer TmaInternalType if specified. Fallback to GEngine::value_type
|
| 295 |
+
using TmaType = conditional_t<is_same<void, TmaInternalType>::value, typename GEngine::value_type, TmaInternalType>;
|
| 296 |
+
return detail::make_tma_copy_tiled<TmaType>(copy_op, gtensor, slayout, cta_t_map, cta_v_tile);
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
template <class TmaInternalType = void,
|
| 300 |
+
class CopyOp,
|
| 301 |
+
class GEngine, class GLayout,
|
| 302 |
+
class SLayout,
|
| 303 |
+
class Cluster_Tiler,
|
| 304 |
+
class... Args>
|
| 305 |
+
CUTE_HOST
|
| 306 |
+
auto
|
| 307 |
+
make_tma_copy_B_sm100(CopyOp const& copy_op,
|
| 308 |
+
Tensor<GEngine,GLayout> const& gtensor, // (N, K, ...)
|
| 309 |
+
SLayout const& slayout, // (MMA, MMA_N, MMA_K, ...)
|
| 310 |
+
Cluster_Tiler const& cluster_tiler, // (TILE_M, TILE_N, TILE_K, ...)
|
| 311 |
+
TiledMMA<Args...> const& mma)
|
| 312 |
+
{
|
| 313 |
+
// Keep only NK modes from MNK
|
| 314 |
+
auto cluster_tiler_nk = remove<0>(cluster_tiler);
|
| 315 |
+
// cluster tile coord -> gtensor coord
|
| 316 |
+
auto g_tile = make_identity_layout(shape(gtensor)).compose(cluster_tiler_nk); // (TILE_N, TILE_K, ...)
|
| 317 |
+
// cta val idx -> gmem mode
|
| 318 |
+
auto cta_v_tile = layout<1>(mma.thrfrg_B(g_tile))(_, repeat<rank(g_tile)>(_)); // (MMA, MMA_N, MMA_K, ...)
|
| 319 |
+
|
| 320 |
+
auto cta_t_vmnk_strides = [](){
|
| 321 |
+
if constexpr (is_same_v<CopyOp, SM90_TMA_LOAD_MULTICAST> ||
|
| 322 |
+
is_same_v<CopyOp, SM100_TMA_2SM_LOAD_MULTICAST>) {
|
| 323 |
+
return Stride<_0,_1,_0,_0>{}; // VMNK: Use only the M-CTAs in the Multicast
|
| 324 |
+
} else
|
| 325 |
+
if constexpr (is_same_v<CopyOp, SM90_TMA_LOAD> ||
|
| 326 |
+
is_same_v<CopyOp, SM90_TMA_STORE> ||
|
| 327 |
+
is_same_v<CopyOp, SM100_TMA_2SM_LOAD>) {
|
| 328 |
+
return Stride<_0,_0,_0,_0>{}; // VMNK: Use no CTAs in Non-Multicast
|
| 329 |
+
} else {
|
| 330 |
+
static_assert(dependent_false<CopyOp>, "Unsupported TMA");
|
| 331 |
+
}
|
| 332 |
+
}();
|
| 333 |
+
|
| 334 |
+
auto cta_t_shape = shape(mma.get_thr_layout_vmnk());
|
| 335 |
+
// cta rank -> logical cta idx
|
| 336 |
+
auto cta_t_map = coalesce(make_layout(cta_t_shape, compact_col_major(cta_t_shape, cta_t_vmnk_strides)));
|
| 337 |
+
|
| 338 |
+
// Prefer TmaInternalType if specified. Fallback to GEngine::value_type
|
| 339 |
+
using TmaType = conditional_t<is_same<void, TmaInternalType>::value, typename GEngine::value_type, TmaInternalType>;
|
| 340 |
+
return detail::make_tma_copy_tiled<TmaType>(copy_op, gtensor, slayout, cta_t_map, cta_v_tile);
|
| 341 |
+
}
|
| 342 |
+
|
| 343 |
+
template <class TmaInternalType = void,
|
| 344 |
+
class CopyOp,
|
| 345 |
+
class GEngine, class GLayout,
|
| 346 |
+
class SLayout,
|
| 347 |
+
class Cluster_Tiler,
|
| 348 |
+
class... Args>
|
| 349 |
+
CUTE_HOST
|
| 350 |
+
auto
|
| 351 |
+
make_tma_copy_C_sm100(CopyOp const& copy_op,
|
| 352 |
+
Tensor<GEngine,GLayout> const& gtensor, // (M, N, ...)
|
| 353 |
+
SLayout const& slayout, // (MMA, MMA_M, MMA_N, ...)
|
| 354 |
+
Cluster_Tiler const& cluster_tiler, // (TILE_M, TILE_N, TILE_K, ...)
|
| 355 |
+
TiledMMA<Args...> const& mma)
|
| 356 |
+
{
|
| 357 |
+
// Keep only MN modes from MNK
|
| 358 |
+
auto cluster_tiler_mn = remove<2>(cluster_tiler);
|
| 359 |
+
// cluster tile coord -> gtensor coord
|
| 360 |
+
auto g_tile = make_identity_layout(shape(gtensor)).compose(cluster_tiler_mn); // (TILE_M, TILE_N, ...)
|
| 361 |
+
// cta val idx -> gmem mode
|
| 362 |
+
auto cta_v_tile = layout<1>(mma.thrfrg_C(g_tile))(_, repeat<rank(g_tile)>(_)); // (MMA, MMA_M, MMA_N, ...)
|
| 363 |
+
|
| 364 |
+
static_assert(is_same_v<CopyOp, SM90_TMA_LOAD> ||
|
| 365 |
+
is_same_v<CopyOp, SM90_TMA_STORE> ||
|
| 366 |
+
is_same_v<CopyOp, SM100_TMA_2SM_LOAD>,
|
| 367 |
+
"Unsupported TMA Op, expected a non-multicast TMA");
|
| 368 |
+
|
| 369 |
+
// No multicast, so only 1 CTA involved
|
| 370 |
+
auto cta_t_map = Layout<_1,_0>{};
|
| 371 |
+
|
| 372 |
+
// Prefer TmaInternalType if specified. Fallback to GEngine::value_type
|
| 373 |
+
using TmaType = conditional_t<is_same<void, TmaInternalType>::value, typename GEngine::value_type, TmaInternalType>;
|
| 374 |
+
return detail::make_tma_copy_tiled<TmaType>(copy_op, gtensor, slayout, cta_t_map, cta_v_tile);
|
| 375 |
+
}
|
| 376 |
+
|
| 377 |
+
////////////////////////////////////
|
| 378 |
+
// Experimental Make TMA Atom
|
| 379 |
+
///////////////////////////////////
|
| 380 |
+
|
| 381 |
+
template <class TmaInternalType = void,
|
| 382 |
+
class CopyOp,
|
| 383 |
+
class GEngine, class GLayout,
|
| 384 |
+
class SLayout,
|
| 385 |
+
class MMA_Tiler,
|
| 386 |
+
class... Args,
|
| 387 |
+
class ClusterShapeVMNK>
|
| 388 |
+
CUTE_HOST
|
| 389 |
+
auto
|
| 390 |
+
make_tma_atom_A_sm100(CopyOp const& copy_op,
|
| 391 |
+
Tensor<GEngine,GLayout> const& gtensor, // (M, K, ...)
|
| 392 |
+
SLayout const& slayout, // (MMA, MMA_M, MMA_K, ...)
|
| 393 |
+
MMA_Tiler const& mma_tiler, // (TILE_M, TILE_N, TILE_K, ...)
|
| 394 |
+
TiledMMA<Args...> const& mma,
|
| 395 |
+
ClusterShapeVMNK const& cluster_shape) // (CTA_V, CTA_M, CTA_N, CTA_K)
|
| 396 |
+
{
|
| 397 |
+
// Keep only MK modes from MNK
|
| 398 |
+
auto mma_tiler_mk = remove<1>(mma_tiler);
|
| 399 |
+
|
| 400 |
+
// cluster tile coord -> gtensor coord
|
| 401 |
+
auto g_tile = make_identity_layout(shape(gtensor)).compose(mma_tiler_mk); // (TILE_M, TILE_K, ...)
|
| 402 |
+
|
| 403 |
+
// cta val idx -> gmem mode
|
| 404 |
+
auto cta_v_tile = layout<1>(mma.thrfrg_A(g_tile))(_, repeat<rank(g_tile)>(_)); // (MMA, MMA_M, MMA_K, ...)
|
| 405 |
+
|
| 406 |
+
#if 0
|
| 407 |
+
print("(tma_a) slayout: "); print(slayout); print("\n");
|
| 408 |
+
print("(tma_a) mma_tiler_nk: "); print(mma_tiler_nk); print("\n");
|
| 409 |
+
print("(tma_a) g_tile: "); print(g_tile); print("\n");
|
| 410 |
+
print("(tma_a) mma_tiler: "); print(mma_tiler); print("\n");
|
| 411 |
+
print("(tma_a) cta_v_tile: "); print(cta_v_tile); print("\n");
|
| 412 |
+
#endif
|
| 413 |
+
|
| 414 |
+
// The size of the multicasting
|
| 415 |
+
auto num_multicast = [&](){
|
| 416 |
+
if constexpr (is_same_v<CopyOp, SM90_TMA_LOAD_MULTICAST> ||
|
| 417 |
+
is_same_v<CopyOp, SM100_TMA_2SM_LOAD_MULTICAST>) {
|
| 418 |
+
return size<2>(cluster_shape); // VMNK: Use only the N-CTAs in the Multicast
|
| 419 |
+
} else
|
| 420 |
+
if constexpr (is_same_v<CopyOp, SM90_TMA_LOAD> ||
|
| 421 |
+
is_same_v<CopyOp, SM90_TMA_STORE> ||
|
| 422 |
+
is_same_v<CopyOp, SM100_TMA_2SM_LOAD>) {
|
| 423 |
+
return Int<1>{}; // VMNK: Use no CTAs in Non-Multicast
|
| 424 |
+
} else {
|
| 425 |
+
static_assert(dependent_false<CopyOp>, "Unsupported TMA");
|
| 426 |
+
}
|
| 427 |
+
}();
|
| 428 |
+
|
| 429 |
+
// Prefer TmaInternalType if specified. Fallback to GEngine::value_type
|
| 430 |
+
using TmaType = conditional_t<is_same<void, TmaInternalType>::value, typename GEngine::value_type, TmaInternalType>;
|
| 431 |
+
return detail::make_tma_copy_atom<TmaType>(copy_op, gtensor, slayout, num_multicast, cta_v_tile);
|
| 432 |
+
}
|
| 433 |
+
|
| 434 |
+
template <class TmaInternalType = void,
|
| 435 |
+
class CopyOp,
|
| 436 |
+
class GEngine, class GLayout,
|
| 437 |
+
class SLayout,
|
| 438 |
+
class MMA_Tiler,
|
| 439 |
+
class... Args,
|
| 440 |
+
class ClusterShapeVMNK>
|
| 441 |
+
CUTE_HOST
|
| 442 |
+
auto
|
| 443 |
+
make_tma_atom_B_sm100(CopyOp const& copy_op,
|
| 444 |
+
Tensor<GEngine,GLayout> const& gtensor, // (N, K, ...)
|
| 445 |
+
SLayout const& slayout, // (MMA, MMA_N, MMA_K, ...)
|
| 446 |
+
MMA_Tiler const& mma_tiler, // (TILE_M, TILE_N, TILE_K, ...)
|
| 447 |
+
TiledMMA<Args...> const& mma,
|
| 448 |
+
ClusterShapeVMNK const& cluster_shape) // (CTA_V, CTA_M, CTA_N, CTA_K)
|
| 449 |
+
{
|
| 450 |
+
// Keep only NK modes from MNK
|
| 451 |
+
auto mma_tiler_nk = remove<0>(mma_tiler);
|
| 452 |
+
// cluster tile coord -> gtensor coord
|
| 453 |
+
auto g_tile = make_identity_layout(shape(gtensor)).compose(mma_tiler_nk); // (TILE_N, TILE_K, ...)
|
| 454 |
+
// cta val idx -> gmem mode
|
| 455 |
+
auto cta_v_tile = layout<1>(mma.thrfrg_B(g_tile))(_, repeat<rank(g_tile)>(_)); // (MMA, MMA_N, MMA_K, ...)
|
| 456 |
+
|
| 457 |
+
#if 0
|
| 458 |
+
print("(tma_b) slayout: "); print(slayout); print("\n");
|
| 459 |
+
print("(tma_b) mma_tiler_nk: "); print(mma_tiler_nk); print("\n");
|
| 460 |
+
print("(tma_b) g_tile: "); print(g_tile); print("\n");
|
| 461 |
+
print("(tma_b) mma_tiler: "); print(mma_tiler); print("\n");
|
| 462 |
+
print("(tma_b) cta_v_tile: "); print(cta_v_tile); print("\n");
|
| 463 |
+
#endif
|
| 464 |
+
|
| 465 |
+
// The size of the multicasting
|
| 466 |
+
auto num_multicast = [&](){
|
| 467 |
+
if constexpr (is_same_v<CopyOp, SM90_TMA_LOAD_MULTICAST> ||
|
| 468 |
+
is_same_v<CopyOp, SM100_TMA_2SM_LOAD_MULTICAST>) {
|
| 469 |
+
return size<1>(cluster_shape); // VMNK: Use only the M-CTAs in the Multicast
|
| 470 |
+
} else
|
| 471 |
+
if constexpr (is_same_v<CopyOp, SM90_TMA_LOAD> ||
|
| 472 |
+
is_same_v<CopyOp, SM90_TMA_STORE> ||
|
| 473 |
+
is_same_v<CopyOp, SM100_TMA_2SM_LOAD>) {
|
| 474 |
+
return Int<1>{}; // VMNK: Use no CTAs in Non-Multicast
|
| 475 |
+
} else {
|
| 476 |
+
static_assert(dependent_false<CopyOp>, "Unsupported TMA");
|
| 477 |
+
}
|
| 478 |
+
}();
|
| 479 |
+
|
| 480 |
+
// Prefer TmaInternalType if specified. Fallback to GEngine::value_type
|
| 481 |
+
using TmaType = conditional_t<is_same<void, TmaInternalType>::value, typename GEngine::value_type, TmaInternalType>;
|
| 482 |
+
return detail::make_tma_copy_atom<TmaType>(copy_op, gtensor, slayout, num_multicast, cta_v_tile);
|
| 483 |
+
}
|
| 484 |
+
|
| 485 |
+
#endif // !defined(__CUDACC_RTC__)
|
| 486 |
+
|
| 487 |
+
} // end namespace cute
|