Instructions to use replicate/deep-gemm with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Kernels
How to use replicate/deep-gemm with Kernels:
# !pip install kernels from kernels import get_kernel # a version (or an explicit revision) is required; see the "Files and versions" tab for the available ones kernel = get_kernel("replicate/deep-gemm", version=1) - Notebooks
- Google Colab
- Kaggle
Build uploaded using `kernels` (batch 3/10).
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +1 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/interleaved_epilogue.h +407 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/output_iterator_parameter.h +223 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/output_tile_thread_map.h +628 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator.h +1387 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_affine.h +615 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_affine_layout_params.h +156 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_blas3.h +633 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_conv.h +562 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_direct_conv.h +445 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_params.h +483 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_predicates.h +309 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_strided_dgrad.h +479 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/shared_load_iterator.h +223 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/shared_load_iterator_mixed.h +594 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/shared_load_iterator_pitch_linear.h +194 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/fragment_iterator_complex_tensor_op.h +187 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/fragment_iterator_gaussian_complex_tensor_op.h +194 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/fragment_iterator_simt.h +164 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/fragment_iterator_tensor_op.h +378 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/fragment_iterator_volta_tensor_op.h +269 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/fragment_iterator_wmma_tensor_op.h +158 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/simt_policy.h +107 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/tensor_op_policy.h +189 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/tile_iterator_simt.h +785 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/tile_iterator_tensor_op.h +671 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/tile_iterator_tensor_op_mixed.h +1089 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/tile_iterator_volta_tensor_op.h +440 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/tile_iterator_wmma_tensor_op.h +224 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/volta_tensor_op_policy.h +195 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/wmma_tensor_op_policy.h +101 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/exmy_base.h +1222 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/device/detail.hpp +163 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/device/dist_gemm_universal_wrapper.hpp +717 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/device/full_barrier.hpp +74 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/kernel/detail.hpp +72 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/kernel/dist_gemm_kernel_wrapper.hpp +235 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/kernel/full_barrier.hpp +82 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/schedules/dist_gemm_1d_schedules.hpp +324 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/schedules/dist_gemm_base_schedule.hpp +538 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/fast_math.h +1085 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/float8.h +1685 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/float_subbyte.h +797 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/floating_point_nvrtc.h +104 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/functional.h +1106 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/gemm/collective/collective_builder.hpp +62 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/gemm/collective/collective_builder_decl.hpp +100 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/gemm/collective/collective_mma.hpp +84 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/gemm/collective/collective_mma_decl.hpp +64 -0
- build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/gemm/collective/fp8_accumulation.hpp +279 -0
.gitattributes
CHANGED
|
@@ -13,3 +13,4 @@ build/torch29-cxx11-cu129-x86_64-linux/_deep_gemm_cuda_a68a39f.abi3.so filter=lf
|
|
| 13 |
build/torch29-cxx11-cu130-x86_64-linux/_deep_gemm_cuda_a68a39f.abi3.so filter=lfs diff=lfs merge=lfs -text
|
| 14 |
build/torch210-cxx11-cu126-aarch64-linux/_deep_gemm_cuda_a68a39f.abi3.so filter=lfs diff=lfs merge=lfs -text
|
| 15 |
build/torch210-cxx11-cu128-aarch64-linux/_deep_gemm_cuda_a68a39f.abi3.so filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 13 |
build/torch29-cxx11-cu130-x86_64-linux/_deep_gemm_cuda_a68a39f.abi3.so filter=lfs diff=lfs merge=lfs -text
|
| 14 |
build/torch210-cxx11-cu126-aarch64-linux/_deep_gemm_cuda_a68a39f.abi3.so filter=lfs diff=lfs merge=lfs -text
|
| 15 |
build/torch210-cxx11-cu128-aarch64-linux/_deep_gemm_cuda_a68a39f.abi3.so filter=lfs diff=lfs merge=lfs -text
|
| 16 |
+
build/torch210-cxx11-cu130-aarch64-linux/_deep_gemm_cuda_a68a39f.abi3.so filter=lfs diff=lfs merge=lfs -text
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/interleaved_epilogue.h
ADDED
|
@@ -0,0 +1,407 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief Epilogue for threadblock scoped GEMMs using Tensor Ops.
|
| 33 |
+
|
| 34 |
+
The epilogue rearranges the result of a matrix product through shared memory to match canonical
|
| 35 |
+
tensor layouts in global memory. Epilogues support conversion and reduction operations.
|
| 36 |
+
|
| 37 |
+
*/
|
| 38 |
+
|
| 39 |
+
#pragma once
|
| 40 |
+
|
| 41 |
+
#include "cutlass/cutlass.h"
|
| 42 |
+
#include "cutlass/numeric_types.h"
|
| 43 |
+
#include "cutlass/array.h"
|
| 44 |
+
#include "cutlass/layout/vector.h"
|
| 45 |
+
#include "cutlass/layout/tensor.h"
|
| 46 |
+
#include "cutlass/tensor_coord.h"
|
| 47 |
+
#include "cutlass/aligned_buffer.h"
|
| 48 |
+
|
| 49 |
+
#include "cutlass/gemm/gemm.h"
|
| 50 |
+
|
| 51 |
+
#include "cutlass/transform/pitch_linear_thread_map.h"
|
| 52 |
+
#include "cutlass/transform/threadblock/regular_tile_iterator.h"
|
| 53 |
+
|
| 54 |
+
#include "cutlass/epilogue/threadblock/epilogue_base_streamk.h"
|
| 55 |
+
#include "cutlass/epilogue/threadblock/predicated_tile_iterator.h"
|
| 56 |
+
|
| 57 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 58 |
+
|
| 59 |
+
namespace cutlass {
|
| 60 |
+
namespace epilogue {
|
| 61 |
+
namespace threadblock {
|
| 62 |
+
|
| 63 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 64 |
+
|
| 65 |
+
/// Epilogue operator without splitk
|
| 66 |
+
template <
|
| 67 |
+
/// Shape of threadblock tile (concept: GemmShape)
|
| 68 |
+
typename Shape_,
|
| 69 |
+
/// Warp-level MMA operator (concept: gemm::warp::MmaTensorOp)
|
| 70 |
+
typename WarpMmaOperator_,
|
| 71 |
+
/// Number of partitions of the K dimension
|
| 72 |
+
int PartitionsK,
|
| 73 |
+
/// Tile iterator reading and writing output tensors
|
| 74 |
+
typename OutputTileIterator_,
|
| 75 |
+
/// Fragment iterator selecting accumulators
|
| 76 |
+
typename AccumulatorFragmentIterator_,
|
| 77 |
+
/// Output operator
|
| 78 |
+
typename OutputOp_,
|
| 79 |
+
/// Number of interleaved k
|
| 80 |
+
int InterleavedK>
|
| 81 |
+
class InterleavedEpilogue :
|
| 82 |
+
public EpilogueBaseStreamK<
|
| 83 |
+
Shape_,
|
| 84 |
+
PartitionsK,
|
| 85 |
+
WarpMmaOperator_,
|
| 86 |
+
AccumulatorFragmentIterator_>
|
| 87 |
+
{
|
| 88 |
+
public:
|
| 89 |
+
|
| 90 |
+
using BaseStreamK = EpilogueBaseStreamK<
|
| 91 |
+
Shape_,
|
| 92 |
+
PartitionsK,
|
| 93 |
+
WarpMmaOperator_,
|
| 94 |
+
AccumulatorFragmentIterator_>;
|
| 95 |
+
|
| 96 |
+
using Shape = Shape_;
|
| 97 |
+
using WarpMmaOperator = WarpMmaOperator_;
|
| 98 |
+
static int const kPartitionsK = PartitionsK;
|
| 99 |
+
using AccumulatorFragmentIterator = AccumulatorFragmentIterator_;
|
| 100 |
+
using OutputTileIterator = OutputTileIterator_;
|
| 101 |
+
using OutputOp = OutputOp_;
|
| 102 |
+
|
| 103 |
+
/// The complete warp-level accumulator tile
|
| 104 |
+
using AccumulatorTile = typename AccumulatorFragmentIterator::AccumulatorTile;
|
| 105 |
+
|
| 106 |
+
/// Fragment type used by the accumulator tile's fragment iterator
|
| 107 |
+
using AccumulatorFragment = typename AccumulatorFragmentIterator::Fragment;
|
| 108 |
+
|
| 109 |
+
/// Accumulator element
|
| 110 |
+
using ElementAccumulator = typename AccumulatorTile::Element;
|
| 111 |
+
|
| 112 |
+
/// Output element
|
| 113 |
+
using ElementOutput = typename OutputTileIterator::Element;
|
| 114 |
+
|
| 115 |
+
/// Output access size
|
| 116 |
+
static int const kElementsPerAccess = OutputTileIterator::kElementsPerAccess;
|
| 117 |
+
|
| 118 |
+
/// Tensor reference to destination tensor
|
| 119 |
+
using TensorRef = typename OutputTileIterator::TensorRef;
|
| 120 |
+
|
| 121 |
+
/// Tensor reference to sync tensor
|
| 122 |
+
using SyncTensorRef =
|
| 123 |
+
typename cutlass::TensorRef<int, cutlass::layout::PackedVectorLayout>;
|
| 124 |
+
|
| 125 |
+
/// Const tensor reference to source tensor
|
| 126 |
+
using ConstTensorRef = typename OutputTileIterator::ConstTensorRef;
|
| 127 |
+
|
| 128 |
+
/// Array type used to output
|
| 129 |
+
using OutputAccessType = Array<typename OutputTileIterator::Element,
|
| 130 |
+
OutputTileIterator::kElementsPerAccess>;
|
| 131 |
+
|
| 132 |
+
/// Array type used by output functor
|
| 133 |
+
using AccumulatorAccessType =
|
| 134 |
+
Array<ElementAccumulator, OutputTileIterator::kElementsPerAccess>;
|
| 135 |
+
|
| 136 |
+
/// Number of warps
|
| 137 |
+
using WarpCount =
|
| 138 |
+
gemm::GemmShape<Shape::kM / WarpMmaOperator::Shape::kM,
|
| 139 |
+
Shape::kN / WarpMmaOperator::Shape::kN, kPartitionsK>;
|
| 140 |
+
|
| 141 |
+
public:
|
| 142 |
+
|
| 143 |
+
static_assert(OutputTileIterator::kElementsPerAccess,
|
| 144 |
+
"This must not be zero.");
|
| 145 |
+
|
| 146 |
+
static_assert(!(OutputTileIterator::Fragment::kElements %
|
| 147 |
+
OutputTileIterator::kElementsPerAccess),
|
| 148 |
+
"Divisibility");
|
| 149 |
+
|
| 150 |
+
public:
|
| 151 |
+
|
| 152 |
+
/// Aspect for when epilogue source is not needed
|
| 153 |
+
struct SourceAspectNotNeeded
|
| 154 |
+
{
|
| 155 |
+
/// Constructor
|
| 156 |
+
CUTLASS_DEVICE
|
| 157 |
+
SourceAspectNotNeeded()
|
| 158 |
+
{}
|
| 159 |
+
|
| 160 |
+
/// Invoke the output functor over each vector of output
|
| 161 |
+
CUTLASS_DEVICE
|
| 162 |
+
void apply_output_operator(
|
| 163 |
+
typename OutputTileIterator::Fragment &output_fragment,
|
| 164 |
+
OutputOp const &output_op,
|
| 165 |
+
typename AccumulatorFragmentIterator::Fragment const &aligned_accum_fragment)
|
| 166 |
+
{
|
| 167 |
+
OutputAccessType *output_frag_ptr =
|
| 168 |
+
reinterpret_cast<OutputAccessType *>(&output_fragment);
|
| 169 |
+
|
| 170 |
+
AccumulatorAccessType const *compute_frag_ptr =
|
| 171 |
+
reinterpret_cast<AccumulatorAccessType const *>(&aligned_accum_fragment);
|
| 172 |
+
|
| 173 |
+
int const kOutputOpIterations =
|
| 174 |
+
OutputTileIterator::Fragment::kElements / OutputTileIterator::kElementsPerAccess;
|
| 175 |
+
|
| 176 |
+
CUTLASS_PRAGMA_UNROLL
|
| 177 |
+
for (int i = 0; i < kOutputOpIterations; ++i)
|
| 178 |
+
{
|
| 179 |
+
// Call the output operator
|
| 180 |
+
output_frag_ptr[i] = output_op(compute_frag_ptr[i]);
|
| 181 |
+
}
|
| 182 |
+
}
|
| 183 |
+
};
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
/// Aspect for when epilogue source is needed
|
| 187 |
+
struct SourceAspectNeeded
|
| 188 |
+
{
|
| 189 |
+
OutputTileIterator source_iterator;
|
| 190 |
+
|
| 191 |
+
typename OutputTileIterator::Fragment source_fragment;
|
| 192 |
+
|
| 193 |
+
/// Invoke the output functor over each vector of output
|
| 194 |
+
CUTLASS_DEVICE
|
| 195 |
+
static void apply_output_operator(
|
| 196 |
+
typename OutputTileIterator::Fragment &output_fragment,
|
| 197 |
+
OutputOp const &output_op,
|
| 198 |
+
typename AccumulatorFragmentIterator::Fragment const &aligned_accum_fragment,
|
| 199 |
+
typename OutputTileIterator::Fragment const &source_fragment)
|
| 200 |
+
{
|
| 201 |
+
OutputAccessType *output_frag_ptr =
|
| 202 |
+
reinterpret_cast<OutputAccessType *>(&output_fragment);
|
| 203 |
+
|
| 204 |
+
AccumulatorAccessType const *compute_frag_ptr =
|
| 205 |
+
reinterpret_cast<AccumulatorAccessType const *>(&aligned_accum_fragment);
|
| 206 |
+
|
| 207 |
+
OutputAccessType const *source_frag_ptr =
|
| 208 |
+
reinterpret_cast<OutputAccessType const *>(&source_fragment);
|
| 209 |
+
|
| 210 |
+
int const kOutputOpIterations =
|
| 211 |
+
OutputTileIterator::Fragment::kElements / OutputTileIterator::kElementsPerAccess;
|
| 212 |
+
|
| 213 |
+
CUTLASS_PRAGMA_UNROLL
|
| 214 |
+
for (int i = 0; i < kOutputOpIterations; ++i)
|
| 215 |
+
{
|
| 216 |
+
// Call the output operator
|
| 217 |
+
output_frag_ptr[i] = output_op(compute_frag_ptr[i], source_frag_ptr[i]);
|
| 218 |
+
}
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
/// Constructor
|
| 222 |
+
CUTLASS_DEVICE
|
| 223 |
+
SourceAspectNeeded(OutputTileIterator source_iterator) :
|
| 224 |
+
source_iterator(source_iterator)
|
| 225 |
+
{
|
| 226 |
+
source_fragment.clear();
|
| 227 |
+
}
|
| 228 |
+
|
| 229 |
+
/// Invoke the output functor over each vector of output
|
| 230 |
+
CUTLASS_DEVICE
|
| 231 |
+
void apply_output_operator(
|
| 232 |
+
typename OutputTileIterator::Fragment &output_fragment,
|
| 233 |
+
OutputOp const &output_op,
|
| 234 |
+
typename AccumulatorFragmentIterator::Fragment const &aligned_accum_fragment)
|
| 235 |
+
{
|
| 236 |
+
// Load addend source fragment from global memory
|
| 237 |
+
source_iterator.load(source_fragment);
|
| 238 |
+
++source_iterator;
|
| 239 |
+
|
| 240 |
+
apply_output_operator(output_fragment, output_op, aligned_accum_fragment, source_fragment);
|
| 241 |
+
}
|
| 242 |
+
};
|
| 243 |
+
|
| 244 |
+
|
| 245 |
+
/// Shared storage allocation needed by the epilogue
|
| 246 |
+
struct SharedStorage {};
|
| 247 |
+
|
| 248 |
+
|
| 249 |
+
public:
|
| 250 |
+
|
| 251 |
+
/// Constructor
|
| 252 |
+
CUTLASS_DEVICE
|
| 253 |
+
InterleavedEpilogue(
|
| 254 |
+
SharedStorage &shared_storage, ///< Shared storage object
|
| 255 |
+
int thread_idx, ///< ID of a thread within the threadblock
|
| 256 |
+
int warp_idx, ///< ID of warp within threadblock
|
| 257 |
+
int lane_idx) ///< Id of thread within warp
|
| 258 |
+
:
|
| 259 |
+
BaseStreamK(thread_idx)
|
| 260 |
+
{}
|
| 261 |
+
|
| 262 |
+
|
| 263 |
+
/// Aggregates the accumulator sets shared by peer blocks in the global workspace,
|
| 264 |
+
/// performing epilogue computations, writing to output
|
| 265 |
+
CUTLASS_DEVICE
|
| 266 |
+
void reduce(
|
| 267 |
+
int peer_idx_begin,
|
| 268 |
+
int peer_idx_end,
|
| 269 |
+
int reduce_fragment_idx,
|
| 270 |
+
void *element_workspace,
|
| 271 |
+
OutputOp const &output_op, ///< Output operator
|
| 272 |
+
OutputTileIterator destination_iterator, ///< Tile iterator for destination
|
| 273 |
+
OutputTileIterator source_iterator) ///< Threadblock tile coordinate in GEMM (in units of threadblock tiles)
|
| 274 |
+
{
|
| 275 |
+
// Redcuce peer accumulator fragments into one fragment
|
| 276 |
+
AccumulatorFragment accum_fragment;
|
| 277 |
+
BaseStreamK::reduce(accum_fragment, peer_idx_begin, peer_idx_end, reduce_fragment_idx, element_workspace);
|
| 278 |
+
|
| 279 |
+
// Source-fragment data (zero-initialized for scenarios where the
|
| 280 |
+
// output operator allows us to skip loading it from global input)
|
| 281 |
+
typename OutputTileIterator::Fragment source_fragment;
|
| 282 |
+
source_fragment.clear();
|
| 283 |
+
|
| 284 |
+
if (output_op.is_source_needed())
|
| 285 |
+
{
|
| 286 |
+
source_iterator += reduce_fragment_idx;
|
| 287 |
+
source_iterator.load(source_fragment);
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
// Compute the output result
|
| 291 |
+
typename OutputTileIterator::Fragment output_fragment;
|
| 292 |
+
|
| 293 |
+
// Apply the output operator
|
| 294 |
+
SourceAspectNeeded::apply_output_operator(output_fragment, output_op, accum_fragment, source_fragment);
|
| 295 |
+
|
| 296 |
+
// Store the final result
|
| 297 |
+
destination_iterator += reduce_fragment_idx;
|
| 298 |
+
destination_iterator.store(output_fragment);
|
| 299 |
+
}
|
| 300 |
+
|
| 301 |
+
|
| 302 |
+
/// Perform the epilogue computations and stream the result to global memory.
|
| 303 |
+
CUTLASS_DEVICE
|
| 304 |
+
void operator()(
|
| 305 |
+
OutputOp const &output_op, ///< Output operator
|
| 306 |
+
OutputTileIterator destination_iterator, ///< Tile iterator for destination
|
| 307 |
+
AccumulatorTile const &accumulators) ///< Complete warp-level accumulator tile
|
| 308 |
+
{
|
| 309 |
+
operator()(output_op, destination_iterator, accumulators, SourceAspectNotNeeded());
|
| 310 |
+
}
|
| 311 |
+
|
| 312 |
+
|
| 313 |
+
/// Perform the epilogue computations and stream the result to global memory. Implements
|
| 314 |
+
/// two alternative codepaths, depending on whether the output op requires addend data to be loaded.
|
| 315 |
+
CUTLASS_DEVICE
|
| 316 |
+
void operator()(
|
| 317 |
+
OutputOp const &output_op, ///< Output operator
|
| 318 |
+
OutputTileIterator destination_iterator, ///< Tile iterator for destination
|
| 319 |
+
AccumulatorTile const &accumulators, ///< Complete warp-level accumulator tile
|
| 320 |
+
OutputTileIterator source_iterator ) ///< Tile iterator for addend source
|
| 321 |
+
{
|
| 322 |
+
if (output_op.is_source_needed())
|
| 323 |
+
{
|
| 324 |
+
operator()(output_op, destination_iterator, accumulators, SourceAspectNeeded(source_iterator));
|
| 325 |
+
}
|
| 326 |
+
else
|
| 327 |
+
{
|
| 328 |
+
operator()(output_op, destination_iterator, accumulators, SourceAspectNotNeeded());
|
| 329 |
+
}
|
| 330 |
+
}
|
| 331 |
+
|
| 332 |
+
|
| 333 |
+
/// Perform the epilogue computations and stream the result to global memory. Implements a
|
| 334 |
+
/// single codepath, regardless of whether the output op requires addend data to be loaded
|
| 335 |
+
CUTLASS_DEVICE
|
| 336 |
+
void unified(
|
| 337 |
+
OutputOp const &output_op, ///< Output operator
|
| 338 |
+
OutputTileIterator destination_iterator, ///< Tile iterator for destination
|
| 339 |
+
AccumulatorTile const &accumulators, ///< Complete warp-level accumulator tile
|
| 340 |
+
OutputTileIterator source_iterator ) ///< Tile iterator for addend source
|
| 341 |
+
{
|
| 342 |
+
if (!output_op.is_source_needed())
|
| 343 |
+
{
|
| 344 |
+
source_iterator.clear_mask();
|
| 345 |
+
__syncthreads(); // Dummy (CUDA 11.0)
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
operator()(output_op, destination_iterator, accumulators, SourceAspectNeeded(source_iterator));
|
| 349 |
+
}
|
| 350 |
+
|
| 351 |
+
|
| 352 |
+
/// Streams the result to global memory
|
| 353 |
+
template <typename SourceAspect>
|
| 354 |
+
CUTLASS_DEVICE
|
| 355 |
+
void operator()(
|
| 356 |
+
OutputOp const &output_op, ///< Output operator
|
| 357 |
+
OutputTileIterator destination_iterator, ///< Tile iterator for destination
|
| 358 |
+
AccumulatorTile const &accumulators, ///< Complete warp-level accumulator tile
|
| 359 |
+
SourceAspect source)
|
| 360 |
+
{
|
| 361 |
+
//
|
| 362 |
+
// Iterator over warp-level accumulator fragment
|
| 363 |
+
//
|
| 364 |
+
|
| 365 |
+
AccumulatorFragmentIterator accum_fragment_iterator(accumulators);
|
| 366 |
+
|
| 367 |
+
//
|
| 368 |
+
// Iterate over accumulator tile
|
| 369 |
+
//
|
| 370 |
+
|
| 371 |
+
CUTLASS_PRAGMA_UNROLL
|
| 372 |
+
for (int iter = 0; iter < OutputTileIterator::kIterations; ++iter) {
|
| 373 |
+
|
| 374 |
+
//
|
| 375 |
+
// Convert fragment
|
| 376 |
+
//
|
| 377 |
+
|
| 378 |
+
typename AccumulatorFragmentIterator::Fragment accum_fragment;
|
| 379 |
+
|
| 380 |
+
accum_fragment_iterator.load(accum_fragment);
|
| 381 |
+
++accum_fragment_iterator;
|
| 382 |
+
|
| 383 |
+
//
|
| 384 |
+
// Compute the output result
|
| 385 |
+
//
|
| 386 |
+
|
| 387 |
+
typename OutputTileIterator::Fragment output_fragment;
|
| 388 |
+
source.apply_output_operator(output_fragment, output_op, accum_fragment);
|
| 389 |
+
|
| 390 |
+
//
|
| 391 |
+
// Store the final result
|
| 392 |
+
//
|
| 393 |
+
|
| 394 |
+
destination_iterator.set_iteration_index(iter);
|
| 395 |
+
destination_iterator.store(output_fragment);
|
| 396 |
+
++destination_iterator;
|
| 397 |
+
}
|
| 398 |
+
}
|
| 399 |
+
};
|
| 400 |
+
|
| 401 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 402 |
+
|
| 403 |
+
} // namespace threadblock
|
| 404 |
+
} // namespace epilogue
|
| 405 |
+
} // namespace cutlass
|
| 406 |
+
|
| 407 |
+
////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/output_iterator_parameter.h
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
|
| 32 |
+
#pragma once
|
| 33 |
+
|
| 34 |
+
#include "cutlass/cutlass.h"
|
| 35 |
+
|
| 36 |
+
#include "cutlass/conv/convolution.h"
|
| 37 |
+
#include "cutlass/conv/conv2d_problem_size.h"
|
| 38 |
+
#include "cutlass/conv/conv3d_problem_size.h"
|
| 39 |
+
#include "cutlass/layout/tensor.h"
|
| 40 |
+
#include "cutlass/layout/matrix.h"
|
| 41 |
+
#include "cutlass/tensor_ref.h"
|
| 42 |
+
|
| 43 |
+
namespace cutlass {
|
| 44 |
+
namespace epilogue {
|
| 45 |
+
namespace threadblock {
|
| 46 |
+
|
| 47 |
+
template<
|
| 48 |
+
typename TensorLayout_, ///! The original output tensor layout
|
| 49 |
+
typename OutputIteratorLayout_, ///! Layout used by epilogue output iterator
|
| 50 |
+
typename TensorRef_, ///! Input tensor to epilogue output iterator
|
| 51 |
+
conv::Operator ConvOperator, ///! Convolutional operator (Fprop, Dgrad, Wgrad)
|
| 52 |
+
typename ConvProblemSize_ ///! Convolutional operator on 2D or 3D problem
|
| 53 |
+
>
|
| 54 |
+
struct ConvOutputIteratorParameter {
|
| 55 |
+
|
| 56 |
+
using TensorLayout = TensorLayout_;
|
| 57 |
+
using OutputIteratorLayout = OutputIteratorLayout_;
|
| 58 |
+
using OutputTensorCoord = typename OutputIteratorLayout::TensorCoord;
|
| 59 |
+
using TensorRef = TensorRef_;
|
| 60 |
+
static conv::Operator const kConvolutionalOperator = ConvOperator;
|
| 61 |
+
using ConvProblemSize = ConvProblemSize_;
|
| 62 |
+
|
| 63 |
+
/// Wgrad stride idx for implicit gemm algorithm
|
| 64 |
+
// Conv2d row-major matrix (KxRSC)
|
| 65 |
+
// Conv3d row-major matrix (KxTRSC)
|
| 66 |
+
static int const kWgradStrideIdx =
|
| 67 |
+
platform::is_same<TensorLayout, layout::TensorNHWC>::value ? 2 : 3;
|
| 68 |
+
|
| 69 |
+
/// This chooses the appropriate stride element of the C tensor.
|
| 70 |
+
static int const kTensorStrideIdx =
|
| 71 |
+
(kConvolutionalOperator == conv::Operator::kWgrad ? kWgradStrideIdx : 0);
|
| 72 |
+
|
| 73 |
+
CUTLASS_HOST_DEVICE
|
| 74 |
+
static OutputIteratorLayout layout(const TensorRef & ref) {
|
| 75 |
+
return ref.stride(kTensorStrideIdx);
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
CUTLASS_HOST_DEVICE
|
| 79 |
+
static OutputTensorCoord extent(ConvProblemSize problem_size) {
|
| 80 |
+
return conv::implicit_gemm_problem_size(kConvolutionalOperator, problem_size).mn();
|
| 81 |
+
}
|
| 82 |
+
};
|
| 83 |
+
|
| 84 |
+
template<
|
| 85 |
+
typename TensorRef_, ///! Input tensor to epilogue output iterator
|
| 86 |
+
typename ConvProblemSize_ ///! Convolutional operator on 2D or 3D problem
|
| 87 |
+
>
|
| 88 |
+
struct ConvOutputIteratorParameter<layout::TensorNHWC, layout::TensorNHWC, TensorRef_, conv::Operator::kFprop, ConvProblemSize_> {
|
| 89 |
+
|
| 90 |
+
using TensorLayout = layout::TensorNHWC;
|
| 91 |
+
using OutputIteratorLayout = layout::TensorNHWC;
|
| 92 |
+
using MappedLayout = layout::RowMajor;
|
| 93 |
+
using OutputTensorCoord = typename OutputIteratorLayout::TensorCoord;
|
| 94 |
+
using MappedTensorCoord = typename MappedLayout::TensorCoord;
|
| 95 |
+
using TensorRef = TensorRef_;
|
| 96 |
+
static conv::Operator const kConvolutionalOperator = conv::Operator::kFprop;
|
| 97 |
+
using ConvProblemSize = ConvProblemSize_;
|
| 98 |
+
|
| 99 |
+
CUTLASS_HOST_DEVICE
|
| 100 |
+
static OutputIteratorLayout layout(const TensorRef & ref) {
|
| 101 |
+
return ref.stride();
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
CUTLASS_HOST_DEVICE
|
| 105 |
+
static MappedTensorCoord extent(ConvProblemSize problem_size) {
|
| 106 |
+
return conv::implicit_gemm_problem_size(kConvolutionalOperator, problem_size).mn();
|
| 107 |
+
}
|
| 108 |
+
};
|
| 109 |
+
|
| 110 |
+
template<
|
| 111 |
+
typename TensorRef_, ///! Input tensor to epilogue output iterator
|
| 112 |
+
typename ConvProblemSize_ ///! Convolutional operator on 2D or 3D problem
|
| 113 |
+
>
|
| 114 |
+
struct ConvOutputIteratorParameter<layout::TensorNHWC, layout::TensorNHWC, TensorRef_, conv::Operator::kDeconv, ConvProblemSize_> {
|
| 115 |
+
|
| 116 |
+
using TensorLayout = layout::TensorNHWC;
|
| 117 |
+
using OutputIteratorLayout = layout::TensorNHWC;
|
| 118 |
+
using MappedLayout = layout::RowMajor;
|
| 119 |
+
using OutputTensorCoord = typename OutputIteratorLayout::TensorCoord;
|
| 120 |
+
using MappedTensorCoord = typename MappedLayout::TensorCoord;
|
| 121 |
+
using TensorRef = TensorRef_;
|
| 122 |
+
static conv::Operator const kConvolutionalOperator = conv::Operator::kDeconv;
|
| 123 |
+
using ConvProblemSize = ConvProblemSize_;
|
| 124 |
+
|
| 125 |
+
CUTLASS_HOST_DEVICE
|
| 126 |
+
static OutputIteratorLayout layout(const TensorRef & ref) {
|
| 127 |
+
return ref.stride();
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
CUTLASS_HOST_DEVICE
|
| 131 |
+
static MappedTensorCoord extent(ConvProblemSize problem_size) {
|
| 132 |
+
return conv::implicit_gemm_problem_size(kConvolutionalOperator, problem_size).mn();
|
| 133 |
+
}
|
| 134 |
+
};
|
| 135 |
+
|
| 136 |
+
template<
|
| 137 |
+
typename TensorRef_, ///! Input tensor to epilogue output iterator
|
| 138 |
+
typename ConvProblemSize_ ///! Convolutional operator on 2D or 3D problem
|
| 139 |
+
>
|
| 140 |
+
struct ConvOutputIteratorParameter<layout::TensorNDHWC, layout::TensorNDHWC, TensorRef_, conv::Operator::kFprop, ConvProblemSize_> {
|
| 141 |
+
|
| 142 |
+
using TensorLayout = layout::TensorNDHWC;
|
| 143 |
+
using OutputIteratorLayout = layout::TensorNDHWC;
|
| 144 |
+
using MappedLayout = layout::RowMajor;
|
| 145 |
+
using OutputTensorCoord = typename OutputIteratorLayout::TensorCoord;
|
| 146 |
+
using MappedTensorCoord = typename MappedLayout::TensorCoord;
|
| 147 |
+
using TensorRef = TensorRef_;
|
| 148 |
+
static conv::Operator const kConvolutionalOperator = conv::Operator::kFprop;
|
| 149 |
+
using ConvProblemSize = ConvProblemSize_;
|
| 150 |
+
|
| 151 |
+
CUTLASS_HOST_DEVICE
|
| 152 |
+
static OutputIteratorLayout layout(const TensorRef & ref) {
|
| 153 |
+
return ref.stride();
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
CUTLASS_HOST_DEVICE
|
| 157 |
+
static MappedTensorCoord extent(ConvProblemSize problem_size) {
|
| 158 |
+
return conv::implicit_gemm_problem_size(kConvolutionalOperator, problem_size).mn();
|
| 159 |
+
}
|
| 160 |
+
};
|
| 161 |
+
|
| 162 |
+
template<
|
| 163 |
+
typename TensorRef_, ///! Input tensor to epilogue output iterator
|
| 164 |
+
typename ConvProblemSize_ ///! Convolutional operator on 2D or 3D problem
|
| 165 |
+
>
|
| 166 |
+
struct ConvOutputIteratorParameter<layout::TensorNDHWC, layout::TensorNDHWC, TensorRef_, conv::Operator::kDeconv, ConvProblemSize_> {
|
| 167 |
+
|
| 168 |
+
using TensorLayout = layout::TensorNDHWC;
|
| 169 |
+
using OutputIteratorLayout = layout::TensorNDHWC;
|
| 170 |
+
using MappedLayout = layout::RowMajor;
|
| 171 |
+
using OutputTensorCoord = typename OutputIteratorLayout::TensorCoord;
|
| 172 |
+
using MappedTensorCoord = typename MappedLayout::TensorCoord;
|
| 173 |
+
using TensorRef = TensorRef_;
|
| 174 |
+
static conv::Operator const kConvolutionalOperator = conv::Operator::kDeconv;
|
| 175 |
+
using ConvProblemSize = ConvProblemSize_;
|
| 176 |
+
|
| 177 |
+
CUTLASS_HOST_DEVICE
|
| 178 |
+
static OutputIteratorLayout layout(const TensorRef & ref) {
|
| 179 |
+
return ref.stride();
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
CUTLASS_HOST_DEVICE
|
| 183 |
+
static MappedTensorCoord extent(ConvProblemSize problem_size) {
|
| 184 |
+
return conv::implicit_gemm_problem_size(kConvolutionalOperator, problem_size).mn();
|
| 185 |
+
}
|
| 186 |
+
};
|
| 187 |
+
|
| 188 |
+
template <
|
| 189 |
+
int InterleavedK,
|
| 190 |
+
typename TensorRef_,
|
| 191 |
+
conv::Operator ConvOperator,
|
| 192 |
+
typename ConvProblemSize_
|
| 193 |
+
>
|
| 194 |
+
struct ConvOutputIteratorParameter<
|
| 195 |
+
layout::TensorNCxHWx<InterleavedK>,
|
| 196 |
+
layout::TensorNCxHWx<InterleavedK>,
|
| 197 |
+
TensorRef_,
|
| 198 |
+
ConvOperator,
|
| 199 |
+
ConvProblemSize_>
|
| 200 |
+
{
|
| 201 |
+
|
| 202 |
+
using TensorLayout = typename layout::TensorNCxHWx<InterleavedK>;
|
| 203 |
+
using OutputIteratorLayout = typename layout::TensorNCxHWx<InterleavedK>;
|
| 204 |
+
using OutputTensorCoord = typename OutputIteratorLayout::TensorCoord;
|
| 205 |
+
using TensorRef = TensorRef_;
|
| 206 |
+
static conv::Operator const kConvolutionalOperator = ConvOperator;
|
| 207 |
+
using ConvProblemSize = ConvProblemSize_;
|
| 208 |
+
|
| 209 |
+
CUTLASS_HOST_DEVICE
|
| 210 |
+
static OutputIteratorLayout layout(const TensorRef & ref) {
|
| 211 |
+
return ref.stride();
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
CUTLASS_HOST_DEVICE
|
| 215 |
+
static OutputTensorCoord extent(ConvProblemSize problem_size) {
|
| 216 |
+
return problem_size.output_extent();
|
| 217 |
+
}
|
| 218 |
+
|
| 219 |
+
};
|
| 220 |
+
|
| 221 |
+
} // namespace threadblock
|
| 222 |
+
} // namespace epilogue
|
| 223 |
+
} // namespace cutlass
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/output_tile_thread_map.h
ADDED
|
@@ -0,0 +1,628 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief Metaprogram for determining the mapping of output elements to threads for epilogue tiles.
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
*/
|
| 36 |
+
|
| 37 |
+
#pragma once
|
| 38 |
+
|
| 39 |
+
#include "cutlass/cutlass.h"
|
| 40 |
+
#include "cutlass/numeric_types.h"
|
| 41 |
+
#include "cutlass/array.h"
|
| 42 |
+
#include "cutlass/layout/matrix.h"
|
| 43 |
+
#include "cutlass/matrix_shape.h"
|
| 44 |
+
#include "cutlass/tensor_ref.h"
|
| 45 |
+
#include "cutlass/fast_math.h"
|
| 46 |
+
|
| 47 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 48 |
+
|
| 49 |
+
namespace cutlass {
|
| 50 |
+
namespace epilogue {
|
| 51 |
+
namespace threadblock {
|
| 52 |
+
|
| 53 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 54 |
+
|
| 55 |
+
/// Tuple defining point in output tile
|
| 56 |
+
template <
|
| 57 |
+
int Column,
|
| 58 |
+
int Row,
|
| 59 |
+
int Group,
|
| 60 |
+
int Cluster,
|
| 61 |
+
int Tile
|
| 62 |
+
>
|
| 63 |
+
struct OutputTileShape {
|
| 64 |
+
static int const kColumn = Column;
|
| 65 |
+
static int const kRow = Row;
|
| 66 |
+
static int const kGroup = Group;
|
| 67 |
+
static int const kCluster = Cluster;
|
| 68 |
+
static int const kTile = Tile;
|
| 69 |
+
|
| 70 |
+
static int const kCount = kColumn * kRow * kGroup * kCluster * kTile;
|
| 71 |
+
};
|
| 72 |
+
|
| 73 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 74 |
+
|
| 75 |
+
template <typename Iterations, typename Delta>
|
| 76 |
+
struct OutputTileThreadMapHelpers {
|
| 77 |
+
|
| 78 |
+
/// Determines the iteration index of a vector access according to the thread map
|
| 79 |
+
CUTLASS_HOST_DEVICE
|
| 80 |
+
static void iteration_index(
|
| 81 |
+
int &column_idx,
|
| 82 |
+
int &row_idx,
|
| 83 |
+
int &group_idx,
|
| 84 |
+
int &cluster_idx,
|
| 85 |
+
int &tile_idx,
|
| 86 |
+
int iter_idx) {
|
| 87 |
+
|
| 88 |
+
column_idx = iter_idx % Iterations::kColumn;
|
| 89 |
+
int residual = iter_idx / Iterations::kColumn;
|
| 90 |
+
|
| 91 |
+
row_idx = residual % Iterations::kRow;
|
| 92 |
+
residual = residual / Iterations::kRow;
|
| 93 |
+
|
| 94 |
+
group_idx = residual % Iterations::kGroup;
|
| 95 |
+
residual = residual / Iterations::kGroup;
|
| 96 |
+
|
| 97 |
+
cluster_idx = residual % Iterations::kCluster;
|
| 98 |
+
tile_idx = residual / Iterations::kCluster;
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
/// Computes the offset of a given vector access
|
| 102 |
+
CUTLASS_HOST_DEVICE
|
| 103 |
+
static MatrixCoord iteration_offset(int iter_idx) {
|
| 104 |
+
|
| 105 |
+
int column_idx;
|
| 106 |
+
int row_idx;
|
| 107 |
+
int group_idx;
|
| 108 |
+
int cluster_idx;
|
| 109 |
+
int tile_idx;
|
| 110 |
+
|
| 111 |
+
iteration_index(column_idx, row_idx, group_idx, cluster_idx, tile_idx, iter_idx);
|
| 112 |
+
|
| 113 |
+
return
|
| 114 |
+
MatrixCoord(
|
| 115 |
+
row_idx * Delta::kRow +
|
| 116 |
+
group_idx * Delta::kGroup +
|
| 117 |
+
cluster_idx * Delta::kCluster +
|
| 118 |
+
tile_idx * Delta::kTile,
|
| 119 |
+
|
| 120 |
+
column_idx * Delta::kColumn);
|
| 121 |
+
}
|
| 122 |
+
};
|
| 123 |
+
|
| 124 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
template <
|
| 128 |
+
typename ThreadMap_,
|
| 129 |
+
typename Shape_,
|
| 130 |
+
typename Iterations_,
|
| 131 |
+
typename Delta_,
|
| 132 |
+
typename Count_
|
| 133 |
+
>
|
| 134 |
+
struct OutputTileThreadMap : public OutputTileThreadMapHelpers<Iterations_, Delta_> {
|
| 135 |
+
|
| 136 |
+
/// Conventional thread map (concept: ThreadMap)
|
| 137 |
+
using ThreadMap = ThreadMap_;
|
| 138 |
+
|
| 139 |
+
/// Number of threads participating in the operation
|
| 140 |
+
static int const kThreads = ThreadMap::kThreads;
|
| 141 |
+
|
| 142 |
+
/// Number of scalar elements per access
|
| 143 |
+
static int const kElementsPerAccess = ThreadMap::kElementsPerAccess;
|
| 144 |
+
|
| 145 |
+
/// Shape of the tile
|
| 146 |
+
using Shape = Shape_;
|
| 147 |
+
|
| 148 |
+
/// Iterations performed by each thread
|
| 149 |
+
using Iterations = Iterations_;
|
| 150 |
+
|
| 151 |
+
/// Delta between accesses
|
| 152 |
+
using Delta = Delta_;
|
| 153 |
+
|
| 154 |
+
/// Number of iterator iterations
|
| 155 |
+
using Count = Count_;
|
| 156 |
+
|
| 157 |
+
/// Initial offset function
|
| 158 |
+
CUTLASS_HOST_DEVICE
|
| 159 |
+
static MatrixCoord initial_offset(int thread_idx) {
|
| 160 |
+
|
| 161 |
+
using Index = typename layout::PitchLinearCoord::Index;
|
| 162 |
+
|
| 163 |
+
layout::PitchLinearCoord coord = ThreadMap::initial_offset(thread_idx);
|
| 164 |
+
|
| 165 |
+
Index cluster = coord.strided() / (Shape::kGroup * Shape::kRow);
|
| 166 |
+
Index cluster_residual = coord.strided() % (Shape::kGroup * Shape::kRow);
|
| 167 |
+
|
| 168 |
+
Index group = cluster_residual / (Shape::kRow);
|
| 169 |
+
Index row = cluster_residual % (Shape::kRow);
|
| 170 |
+
|
| 171 |
+
return MatrixCoord{
|
| 172 |
+
row + group * Shape::kRow * Count::kRow
|
| 173 |
+
+ cluster * Shape::kGroup * Count::kGroup * Shape::kRow * Count::kRow,
|
| 174 |
+
coord.contiguous()
|
| 175 |
+
};
|
| 176 |
+
}
|
| 177 |
+
};
|
| 178 |
+
|
| 179 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 180 |
+
|
| 181 |
+
namespace detail {
|
| 182 |
+
|
| 183 |
+
/// RowArrangement determines how one or more warps cover a region of consecutive rows.
|
| 184 |
+
template <
|
| 185 |
+
typename Shape,
|
| 186 |
+
int WarpsRemaining,
|
| 187 |
+
int ElementsPerAccess,
|
| 188 |
+
int ElementSize,
|
| 189 |
+
bool Is2dTile
|
| 190 |
+
>
|
| 191 |
+
struct RowArrangement;
|
| 192 |
+
|
| 193 |
+
/// RowArrangement in which each warp's access is a 1D tiled arrangement.
|
| 194 |
+
template <
|
| 195 |
+
typename Shape,
|
| 196 |
+
int WarpsRemaining,
|
| 197 |
+
int ElementsPerAccess,
|
| 198 |
+
int ElementSize
|
| 199 |
+
>
|
| 200 |
+
struct RowArrangement<Shape, WarpsRemaining, ElementsPerAccess, ElementSize, false> {
|
| 201 |
+
static int const kWarpSize = 32;
|
| 202 |
+
static int const kElementsPerAccess = ElementsPerAccess;
|
| 203 |
+
static int const kElementSize = ElementSize;
|
| 204 |
+
|
| 205 |
+
static int const kIterationsRow = 1;
|
| 206 |
+
static int const kDeltaRow = 1;
|
| 207 |
+
static int const kIterationsColumn = Shape::kColumn / kElementsPerAccess / kWarpSize;
|
| 208 |
+
static int const kDeltaColumn = kWarpSize * kElementsPerAccess;
|
| 209 |
+
|
| 210 |
+
static int const kAccessWidth = kWarpSize;
|
| 211 |
+
static int const kAccessRows = 1;
|
| 212 |
+
static int const kWarpPartitionsRow = 1;
|
| 213 |
+
static int const kWarpPartitionsColumn = WarpsRemaining;
|
| 214 |
+
};
|
| 215 |
+
|
| 216 |
+
/// RowArrangement in which each warp's access is a 2D tiled arrangement.
|
| 217 |
+
template <
|
| 218 |
+
typename Shape,
|
| 219 |
+
int WarpsRemaining,
|
| 220 |
+
int ElementsPerAccess,
|
| 221 |
+
int ElementSize
|
| 222 |
+
>
|
| 223 |
+
struct RowArrangement<Shape, WarpsRemaining, ElementsPerAccess, ElementSize, true> {
|
| 224 |
+
|
| 225 |
+
static int const kMemoryAccessSize = 256; // Preferred access size
|
| 226 |
+
static int const kWarpSize = 32;
|
| 227 |
+
|
| 228 |
+
static int const kElementsPerAccess = ElementsPerAccess;
|
| 229 |
+
static int const kElementSize = ElementSize;
|
| 230 |
+
|
| 231 |
+
struct Detail {
|
| 232 |
+
static int const kShapeRow = Shape::kRow / WarpsRemaining;
|
| 233 |
+
static int const kShapeWidth = Shape::kColumn / kElementsPerAccess;
|
| 234 |
+
|
| 235 |
+
static int const kTargetMemoryAccessWidth =
|
| 236 |
+
kMemoryAccessSize / (kElementsPerAccess * kElementSize / 8);
|
| 237 |
+
|
| 238 |
+
static int const kTargetAccessRows = kWarpSize / kTargetMemoryAccessWidth;
|
| 239 |
+
};
|
| 240 |
+
|
| 241 |
+
static int const kAccessWidth =
|
| 242 |
+
(Detail::kTargetAccessRows > Detail::kShapeRow ?
|
| 243 |
+
kWarpSize / Detail::kShapeRow
|
| 244 |
+
: const_min(
|
| 245 |
+
Detail::kShapeWidth,
|
| 246 |
+
const_min(kWarpSize, kMemoryAccessSize / (kElementsPerAccess * kElementSize / 8))
|
| 247 |
+
));
|
| 248 |
+
|
| 249 |
+
static int const kAccessRows =
|
| 250 |
+
(Detail::kTargetAccessRows > Detail::kShapeRow ?
|
| 251 |
+
Detail::kShapeRow
|
| 252 |
+
: const_min(Shape::kRow, kWarpSize / kAccessWidth));
|
| 253 |
+
|
| 254 |
+
static int const kIterationsRow = Detail::kShapeRow / kAccessRows;
|
| 255 |
+
static int const kDeltaRow = kAccessRows;
|
| 256 |
+
|
| 257 |
+
static int const kIterationsColumn = Detail::kShapeWidth / kAccessWidth;
|
| 258 |
+
static int const kDeltaColumn = kAccessWidth * kElementsPerAccess;
|
| 259 |
+
|
| 260 |
+
static_assert( kAccessWidth * kElementsPerAccess <= Shape::kColumn, "Accessing too many elements per access");
|
| 261 |
+
static_assert( kIterationsColumn > 0, "Iteration Count Column must be > 0" );
|
| 262 |
+
static_assert( kIterationsRow > 0, "Iteration Count Row must be > 0" );
|
| 263 |
+
|
| 264 |
+
static int const kWarpPartitionsRow = 1;
|
| 265 |
+
static int const kWarpPartitionsColumn = 1;
|
| 266 |
+
};
|
| 267 |
+
|
| 268 |
+
}
|
| 269 |
+
|
| 270 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 271 |
+
|
| 272 |
+
/// Template metaprogram for partitioning a 4D space across warps to achieve several performance
|
| 273 |
+
/// objectives:
|
| 274 |
+
///
|
| 275 |
+
/// - coalesced memory accesses in units of 128 Byte lines
|
| 276 |
+
/// - minimal address arithmetic
|
| 277 |
+
/// - minimal predicate calculations
|
| 278 |
+
///
|
| 279 |
+
template <
|
| 280 |
+
typename Shape_,
|
| 281 |
+
typename Count_,
|
| 282 |
+
int Threads,
|
| 283 |
+
int ElementsPerAccess,
|
| 284 |
+
int ElementSize
|
| 285 |
+
>
|
| 286 |
+
struct OutputTileOptimalThreadMap {
|
| 287 |
+
|
| 288 |
+
using Shape = Shape_;
|
| 289 |
+
using Count = Count_;
|
| 290 |
+
|
| 291 |
+
static int const kWarpSize = 32;
|
| 292 |
+
static int const kThreads = Threads;
|
| 293 |
+
static int const kWarpCount = kThreads / kWarpSize;
|
| 294 |
+
|
| 295 |
+
static int const kElementsPerAccess = ElementsPerAccess;
|
| 296 |
+
static int const kElementSize = ElementSize;
|
| 297 |
+
|
| 298 |
+
//
|
| 299 |
+
// Metaprogram computation
|
| 300 |
+
//
|
| 301 |
+
|
| 302 |
+
struct Detail {
|
| 303 |
+
|
| 304 |
+
// Clusters
|
| 305 |
+
static int const kIterationsCluster =
|
| 306 |
+
((Shape::kCluster > kWarpCount) ?
|
| 307 |
+
Shape::kCluster / kWarpCount
|
| 308 |
+
: 1);
|
| 309 |
+
|
| 310 |
+
static int const kDeltaCluster =
|
| 311 |
+
((Shape::kCluster > kWarpCount) ?
|
| 312 |
+
Shape::kRow * Count::kRow * Shape::kGroup * Count::kGroup * Shape::kCluster / kIterationsCluster
|
| 313 |
+
: 1);
|
| 314 |
+
|
| 315 |
+
static int const kCompactedDeltaCluster =
|
| 316 |
+
((Shape::kCluster > kWarpCount) ?
|
| 317 |
+
Shape::kRow * Shape::kGroup * Shape::kCluster / kIterationsCluster
|
| 318 |
+
: 1);
|
| 319 |
+
|
| 320 |
+
static int const kWarpPartitionsCluster =
|
| 321 |
+
((Shape::kCluster > kWarpCount) ?
|
| 322 |
+
kWarpCount
|
| 323 |
+
: kWarpCount / Shape::kCluster);
|
| 324 |
+
|
| 325 |
+
static int const kWarpsRemainingForGroups =
|
| 326 |
+
((Shape::kCluster > kWarpCount) ? 1 : kWarpCount / Shape::kCluster);
|
| 327 |
+
|
| 328 |
+
// Groups
|
| 329 |
+
static int const kIterationsGroup =
|
| 330 |
+
((Shape::kGroup > kWarpsRemainingForGroups) ?
|
| 331 |
+
Shape::kGroup / kWarpsRemainingForGroups
|
| 332 |
+
: 1);
|
| 333 |
+
|
| 334 |
+
static int const kDeltaGroup =
|
| 335 |
+
((Shape::kGroup > kWarpsRemainingForGroups) ?
|
| 336 |
+
Shape::kRow * Count::kRow * Shape::kGroup / kIterationsGroup
|
| 337 |
+
: 1);
|
| 338 |
+
|
| 339 |
+
static int const kCompactedDeltaGroup =
|
| 340 |
+
((Shape::kGroup > kWarpsRemainingForGroups) ?
|
| 341 |
+
Shape::kRow * Shape::kGroup / kIterationsGroup
|
| 342 |
+
: 1);
|
| 343 |
+
|
| 344 |
+
static int const kWarpPartitionsGroup =
|
| 345 |
+
((Shape::kGroup > kWarpsRemainingForGroups) ?
|
| 346 |
+
1
|
| 347 |
+
: kWarpsRemainingForGroups / Shape::kGroup);
|
| 348 |
+
|
| 349 |
+
static int const kWarpsRemainingForRows =
|
| 350 |
+
((Shape::kGroup > kWarpsRemainingForGroups) ?
|
| 351 |
+
1
|
| 352 |
+
: kWarpsRemainingForGroups / Shape::kGroup);
|
| 353 |
+
|
| 354 |
+
// Rows
|
| 355 |
+
using RowArrangement = detail::RowArrangement<
|
| 356 |
+
Shape,
|
| 357 |
+
kWarpsRemainingForRows,
|
| 358 |
+
kElementsPerAccess,
|
| 359 |
+
kElementSize,
|
| 360 |
+
(Shape::kRow > kWarpsRemainingForRows)
|
| 361 |
+
>;
|
| 362 |
+
|
| 363 |
+
// Warp partitions
|
| 364 |
+
using WarpPartitions = OutputTileShape<
|
| 365 |
+
RowArrangement::kWarpPartitionsColumn,
|
| 366 |
+
RowArrangement::kWarpPartitionsRow,
|
| 367 |
+
kWarpPartitionsGroup,
|
| 368 |
+
kWarpPartitionsCluster,
|
| 369 |
+
1>;
|
| 370 |
+
|
| 371 |
+
static int const kAccessWidth = RowArrangement::kAccessWidth;
|
| 372 |
+
static int const kAccessRows = RowArrangement::kAccessRows;
|
| 373 |
+
};
|
| 374 |
+
|
| 375 |
+
//
|
| 376 |
+
// Output
|
| 377 |
+
//
|
| 378 |
+
|
| 379 |
+
using Iterations = OutputTileShape<
|
| 380 |
+
Detail::RowArrangement::kIterationsColumn,
|
| 381 |
+
Detail::RowArrangement::kIterationsRow,
|
| 382 |
+
Detail::kIterationsGroup,
|
| 383 |
+
Detail::kIterationsCluster,
|
| 384 |
+
1>;
|
| 385 |
+
|
| 386 |
+
using Delta = OutputTileShape<
|
| 387 |
+
Detail::RowArrangement::kDeltaColumn,
|
| 388 |
+
Detail::RowArrangement::kDeltaRow,
|
| 389 |
+
Detail::kDeltaGroup,
|
| 390 |
+
Detail::kDeltaCluster,
|
| 391 |
+
1>;
|
| 392 |
+
|
| 393 |
+
/// Initial offset function
|
| 394 |
+
CUTLASS_HOST_DEVICE
|
| 395 |
+
static MatrixCoord initial_offset(int thread_idx) {
|
| 396 |
+
|
| 397 |
+
// int warp_idx = __shfl_sync(0xffffffff, thread_idx / kWarpSize, 0);
|
| 398 |
+
int warp_idx = thread_idx / kWarpSize;
|
| 399 |
+
int lane_idx = thread_idx % kWarpSize;
|
| 400 |
+
|
| 401 |
+
// Compute warp location
|
| 402 |
+
int cluster_idx = warp_idx / Detail::WarpPartitions::kCluster;
|
| 403 |
+
int residual_cluster = warp_idx % Detail::WarpPartitions::kCluster;
|
| 404 |
+
|
| 405 |
+
int group_idx = residual_cluster / Detail::WarpPartitions::kGroup;
|
| 406 |
+
int residual_group = residual_cluster % Detail::WarpPartitions::kGroup;
|
| 407 |
+
|
| 408 |
+
int row_idx = residual_group / Detail::WarpPartitions::kRow;
|
| 409 |
+
int col_idx = residual_group % Detail::WarpPartitions::kRow;
|
| 410 |
+
|
| 411 |
+
// Compute per-lane offset
|
| 412 |
+
int lane_row_offset = lane_idx / Detail::kAccessWidth;
|
| 413 |
+
int lane_col_offset = lane_idx % Detail::kAccessWidth;
|
| 414 |
+
|
| 415 |
+
// Compute coordinate in output space
|
| 416 |
+
int cluster_offset = cluster_idx * Shape::kRow * Count::kRow * Shape::kGroup * Count::kGroup;
|
| 417 |
+
int group_offset = group_idx * Shape::kRow * Count::kRow;
|
| 418 |
+
int row_offset = row_idx * Iterations::kRow * Detail::kAccessRows;
|
| 419 |
+
int column_offset = col_idx * Iterations::kColumn * Detail::kAccessWidth * kElementsPerAccess;
|
| 420 |
+
|
| 421 |
+
return MatrixCoord(
|
| 422 |
+
cluster_offset + group_offset + row_offset + lane_row_offset,
|
| 423 |
+
column_offset + lane_col_offset * kElementsPerAccess
|
| 424 |
+
);
|
| 425 |
+
}
|
| 426 |
+
|
| 427 |
+
/// Computes the offset of a given vector access
|
| 428 |
+
CUTLASS_HOST_DEVICE
|
| 429 |
+
static MatrixCoord iteration_offset(int iter_idx) {
|
| 430 |
+
return OutputTileThreadMapHelpers<Iterations, Delta>::iteration_offset(iter_idx);
|
| 431 |
+
}
|
| 432 |
+
|
| 433 |
+
/// Compacted thread map in which the 4D region is contiguous
|
| 434 |
+
struct CompactedThreadMap {
|
| 435 |
+
|
| 436 |
+
|
| 437 |
+
using Shape = Shape_;
|
| 438 |
+
|
| 439 |
+
using TileShape = MatrixShape<
|
| 440 |
+
Shape::kTile * Shape::kCluster * Shape::kGroup * Shape::kRow,
|
| 441 |
+
Shape::kColumn
|
| 442 |
+
>;
|
| 443 |
+
|
| 444 |
+
using Iterations = OutputTileShape<
|
| 445 |
+
Detail::RowArrangement::kIterationsColumn,
|
| 446 |
+
Detail::RowArrangement::kIterationsRow,
|
| 447 |
+
Detail::kIterationsGroup,
|
| 448 |
+
Detail::kIterationsCluster,
|
| 449 |
+
1>;
|
| 450 |
+
|
| 451 |
+
using Delta = OutputTileShape<
|
| 452 |
+
Detail::RowArrangement::kDeltaColumn,
|
| 453 |
+
Detail::RowArrangement::kDeltaRow,
|
| 454 |
+
Detail::kCompactedDeltaGroup,
|
| 455 |
+
Detail::kCompactedDeltaCluster,
|
| 456 |
+
1>;
|
| 457 |
+
|
| 458 |
+
/// Number of elements within each vector access
|
| 459 |
+
static int const kElementsPerAccess = ElementsPerAccess;
|
| 460 |
+
|
| 461 |
+
/// Number of threads
|
| 462 |
+
static int const kThreads = Threads;
|
| 463 |
+
|
| 464 |
+
/// Function to compute each thread's initial offset
|
| 465 |
+
CUTLASS_HOST_DEVICE
|
| 466 |
+
static MatrixCoord initial_offset(int thread_idx) {
|
| 467 |
+
|
| 468 |
+
// int warp_idx = __shfl_sync(0xffffffff, thread_idx / kWarpSize, 0);
|
| 469 |
+
int warp_idx = thread_idx / kWarpSize;
|
| 470 |
+
int lane_idx = thread_idx % kWarpSize;
|
| 471 |
+
|
| 472 |
+
// Compute warp location
|
| 473 |
+
int cluster_idx = warp_idx / Detail::WarpPartitions::kCluster;
|
| 474 |
+
int residual_cluster = warp_idx % Detail::WarpPartitions::kCluster;
|
| 475 |
+
|
| 476 |
+
int group_idx = residual_cluster / Detail::WarpPartitions::kGroup;
|
| 477 |
+
int residual_group = residual_cluster % Detail::WarpPartitions::kGroup;
|
| 478 |
+
|
| 479 |
+
int row_idx = residual_group / Detail::WarpPartitions::kRow;
|
| 480 |
+
int col_idx = residual_group % Detail::WarpPartitions::kRow;
|
| 481 |
+
|
| 482 |
+
// Compute per-lane offset
|
| 483 |
+
int lane_row_offset = lane_idx / Detail::kAccessWidth;
|
| 484 |
+
int lane_col_offset = lane_idx % Detail::kAccessWidth;
|
| 485 |
+
|
| 486 |
+
// Compute coordinate in output space
|
| 487 |
+
int cluster_offset = cluster_idx * Shape::kRow * Shape::kGroup;
|
| 488 |
+
int group_offset = group_idx * Shape::kRow;
|
| 489 |
+
int row_offset = row_idx * Iterations::kRow * Detail::kAccessRows;
|
| 490 |
+
int column_offset = col_idx * Iterations::kColumn * Detail::kAccessWidth * kElementsPerAccess;
|
| 491 |
+
|
| 492 |
+
MatrixCoord coord(
|
| 493 |
+
cluster_offset + group_offset + row_offset + lane_row_offset,
|
| 494 |
+
column_offset + lane_col_offset * kElementsPerAccess
|
| 495 |
+
);
|
| 496 |
+
|
| 497 |
+
return coord;
|
| 498 |
+
}
|
| 499 |
+
};
|
| 500 |
+
};
|
| 501 |
+
|
| 502 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 503 |
+
|
| 504 |
+
/// Template metaprogram for partitioning a 3D interleaved layout across warps
|
| 505 |
+
/// to achieve several performance objectives:
|
| 506 |
+
///
|
| 507 |
+
/// - coalesced memory accesses in units of 64 Byte lines
|
| 508 |
+
/// - minimal address arithmetic
|
| 509 |
+
/// - minimal predicate calculations
|
| 510 |
+
///
|
| 511 |
+
template <typename WarpCount_, typename Iterations_, int Threads,
|
| 512 |
+
int ElementsPerAccess, int ElementSize>
|
| 513 |
+
struct InterleavedOutputTileThreadMap {
|
| 514 |
+
using WarpCount = WarpCount_;
|
| 515 |
+
|
| 516 |
+
static int const kWarpSize = 32;
|
| 517 |
+
static int const kThreads = Threads;
|
| 518 |
+
static int const kWarpCount = kThreads / kWarpSize;
|
| 519 |
+
|
| 520 |
+
static int const kElementsPerAccess = ElementsPerAccess;
|
| 521 |
+
static int const kElementSize = ElementSize;
|
| 522 |
+
|
| 523 |
+
//
|
| 524 |
+
// Metaprogram computation
|
| 525 |
+
//
|
| 526 |
+
|
| 527 |
+
struct Detail {};
|
| 528 |
+
|
| 529 |
+
//
|
| 530 |
+
// Output
|
| 531 |
+
//
|
| 532 |
+
|
| 533 |
+
using Iterations = Iterations_;
|
| 534 |
+
|
| 535 |
+
using Delta = layout::PitchLinearShape<kWarpSize * kElementsPerAccess, 1>;
|
| 536 |
+
|
| 537 |
+
/// Initial offset function
|
| 538 |
+
CUTLASS_HOST_DEVICE
|
| 539 |
+
static layout::PitchLinearCoord initial_offset(int thread_idx) {
|
| 540 |
+
int warp_idx = thread_idx / kWarpSize;
|
| 541 |
+
int lane_idx = thread_idx % kWarpSize;
|
| 542 |
+
|
| 543 |
+
// Compute warp location
|
| 544 |
+
layout::PitchLinearCoord warp_footprint{
|
| 545 |
+
Delta::kContiguous * Iterations::kContiguous,
|
| 546 |
+
Delta::kStrided * Iterations::kStrided};
|
| 547 |
+
|
| 548 |
+
layout::PitchLinearCoord warp_offset{warp_idx % WarpCount::kContiguous,
|
| 549 |
+
warp_idx / WarpCount::kContiguous};
|
| 550 |
+
|
| 551 |
+
// Compute per-lane offset
|
| 552 |
+
layout::PitchLinearCoord thread_offset_in_warp{
|
| 553 |
+
lane_idx * kElementsPerAccess, 0};
|
| 554 |
+
|
| 555 |
+
layout::PitchLinearCoord thread_offset_in_threadblock_tile =
|
| 556 |
+
warp_footprint * warp_offset + thread_offset_in_warp;
|
| 557 |
+
|
| 558 |
+
return thread_offset_in_threadblock_tile;
|
| 559 |
+
}
|
| 560 |
+
};
|
| 561 |
+
|
| 562 |
+
|
| 563 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 564 |
+
|
| 565 |
+
/// Template metaprogram for partitioning a 4D interleaved layout across warps
|
| 566 |
+
/// to achieve several performance objectives:
|
| 567 |
+
///
|
| 568 |
+
/// - coalesced memory accesses in units of 64 Byte lines
|
| 569 |
+
/// - minimal address arithmetic
|
| 570 |
+
/// - minimal predicate calculations
|
| 571 |
+
///
|
| 572 |
+
template <typename WarpCount_, typename Iterations_, int Threads,
|
| 573 |
+
int ElementsPerAccess, int ElementSize>
|
| 574 |
+
struct InterleavedConvOutputTileThreadMap {
|
| 575 |
+
using WarpCount = WarpCount_;
|
| 576 |
+
|
| 577 |
+
static int const kWarpSize = 32;
|
| 578 |
+
static int const kThreads = Threads;
|
| 579 |
+
static int const kWarpCount = kThreads / kWarpSize;
|
| 580 |
+
|
| 581 |
+
static int const kElementsPerAccess = ElementsPerAccess;
|
| 582 |
+
static int const kElementSize = ElementSize;
|
| 583 |
+
|
| 584 |
+
//
|
| 585 |
+
// Metaprogram computation
|
| 586 |
+
//
|
| 587 |
+
|
| 588 |
+
struct Detail {};
|
| 589 |
+
|
| 590 |
+
//
|
| 591 |
+
// Output
|
| 592 |
+
//
|
| 593 |
+
|
| 594 |
+
using Iterations = Iterations_;
|
| 595 |
+
|
| 596 |
+
using Delta = MatrixShape<kWarpSize / 4, 4 * kElementsPerAccess>;
|
| 597 |
+
|
| 598 |
+
/// Initial offset function
|
| 599 |
+
CUTLASS_HOST_DEVICE
|
| 600 |
+
static MatrixCoord initial_offset(int thread_idx) {
|
| 601 |
+
int warp_idx = thread_idx / kWarpSize;
|
| 602 |
+
int lane_idx = thread_idx % kWarpSize;
|
| 603 |
+
|
| 604 |
+
// Compute warp location
|
| 605 |
+
MatrixCoord warp_footprint{
|
| 606 |
+
Delta::kRow * Iterations::kRow,
|
| 607 |
+
Delta::kColumn * Iterations::kColumn,
|
| 608 |
+
};
|
| 609 |
+
|
| 610 |
+
MatrixCoord warp_offset{warp_idx % WarpCount::kRow,
|
| 611 |
+
warp_idx / WarpCount::kRow};
|
| 612 |
+
|
| 613 |
+
// Compute per-lane offset
|
| 614 |
+
MatrixCoord thread_offset_in_warp{lane_idx / 4,
|
| 615 |
+
(lane_idx % 4) * kElementsPerAccess};
|
| 616 |
+
|
| 617 |
+
MatrixCoord thread_offset_in_threadblock_tile =
|
| 618 |
+
warp_footprint * warp_offset + thread_offset_in_warp;
|
| 619 |
+
|
| 620 |
+
return thread_offset_in_threadblock_tile;
|
| 621 |
+
}
|
| 622 |
+
};
|
| 623 |
+
|
| 624 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 625 |
+
|
| 626 |
+
} // namespace threadblock
|
| 627 |
+
} // namespace epilogue
|
| 628 |
+
} // namespace cutlass
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator.h
ADDED
|
@@ -0,0 +1,1387 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief Epilogue for threadblock scoped GEMMs using Tensor Ops.
|
| 33 |
+
|
| 34 |
+
The epilogue rearranges the result of a matrix product through shared memory to match canonical
|
| 35 |
+
tensor layouts in global memory. Epilogues support conversion and reduction operations.
|
| 36 |
+
|
| 37 |
+
*/
|
| 38 |
+
|
| 39 |
+
#pragma once
|
| 40 |
+
|
| 41 |
+
#include "cutlass/cutlass.h"
|
| 42 |
+
#include "cutlass/numeric_types.h"
|
| 43 |
+
#include "cutlass/array.h"
|
| 44 |
+
#include "cutlass/layout/matrix.h"
|
| 45 |
+
#include "cutlass/layout/tensor.h"
|
| 46 |
+
#include "cutlass/layout/permute.h"
|
| 47 |
+
#include "cutlass/matrix_shape.h"
|
| 48 |
+
#include "cutlass/tensor_ref.h"
|
| 49 |
+
#include "cutlass/transform/pitch_linear_thread_map.h"
|
| 50 |
+
#include "cutlass/epilogue/threadblock/output_tile_thread_map.h"
|
| 51 |
+
#include "cutlass/arch/arch.h"
|
| 52 |
+
#include "cutlass/arch/memory.h"
|
| 53 |
+
#include "cutlass/epilogue/threadblock/predicated_tile_iterator_params.h"
|
| 54 |
+
#include "cutlass/conv/conv2d_problem_size.h"
|
| 55 |
+
#include "cutlass/conv/conv3d_problem_size.h"
|
| 56 |
+
|
| 57 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 58 |
+
|
| 59 |
+
namespace cutlass {
|
| 60 |
+
|
| 61 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 62 |
+
|
| 63 |
+
namespace epilogue {
|
| 64 |
+
namespace threadblock {
|
| 65 |
+
|
| 66 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 67 |
+
|
| 68 |
+
/// Tile iterator used to load and store output tile from global memory in epilogue.
|
| 69 |
+
///
|
| 70 |
+
/// Satisfies: ReadableTileIterator | PredicatedTileIterator | ForwardTileIterator
|
| 71 |
+
///
|
| 72 |
+
template <
|
| 73 |
+
typename ThreadMap_, ///< Thread map (conept: OutputTileThreadMap)
|
| 74 |
+
typename Element_, ///< Element data type
|
| 75 |
+
bool ScatterD = false, ///< Scatter D operand or not
|
| 76 |
+
typename PermuteDLayout = layout::NoPermute, ///< Permute D operand or not
|
| 77 |
+
bool UseCUDAStore = false
|
| 78 |
+
>
|
| 79 |
+
class PredicatedTileIterator {
|
| 80 |
+
public:
|
| 81 |
+
using ThreadMap = ThreadMap_;
|
| 82 |
+
using Shape = typename ThreadMap::Shape;
|
| 83 |
+
|
| 84 |
+
using Element = Element_;
|
| 85 |
+
|
| 86 |
+
using Layout = layout::RowMajor;
|
| 87 |
+
using TensorRef = TensorRef<Element, Layout>;
|
| 88 |
+
using ConstTensorRef = typename TensorRef::ConstTensorRef;
|
| 89 |
+
|
| 90 |
+
using Index = typename Layout::Index;
|
| 91 |
+
using LongIndex = typename Layout::LongIndex;
|
| 92 |
+
using TensorCoord = MatrixCoord;
|
| 93 |
+
|
| 94 |
+
static int const kElementsPerAccess = ThreadMap::kElementsPerAccess;
|
| 95 |
+
static int const kThreads = ThreadMap::kThreads;
|
| 96 |
+
static int const kIterations = ThreadMap::Count::kTile;
|
| 97 |
+
|
| 98 |
+
static bool constexpr PermuteD = !layout::is_trivial_permute<PermuteDLayout>;
|
| 99 |
+
|
| 100 |
+
static_assert( ThreadMap::Iterations::kRow > 0,"ThreadMap::Iterations::kRow must be > 0");
|
| 101 |
+
static_assert( ThreadMap::Iterations::kGroup > 0,"ThreadMap::Iterations::kGroup must be > 0");
|
| 102 |
+
static_assert( ThreadMap::Iterations::kCluster > 0,"ThreadMap::Iterations::kCluster must be > 0");
|
| 103 |
+
static_assert( ThreadMap::Iterations::kColumn > 0,"ThreadMap::Iterations::kColumn must be > 0");
|
| 104 |
+
|
| 105 |
+
/// Fragment object
|
| 106 |
+
using Fragment = Array<
|
| 107 |
+
Element,
|
| 108 |
+
ThreadMap::Iterations::kColumn *
|
| 109 |
+
ThreadMap::Iterations::kRow *
|
| 110 |
+
ThreadMap::Iterations::kGroup *
|
| 111 |
+
ThreadMap::Iterations::kCluster * ThreadMap::kElementsPerAccess>;
|
| 112 |
+
|
| 113 |
+
/// Memory access size
|
| 114 |
+
using AccessType = AlignedArray<Element, ThreadMap::kElementsPerAccess>;
|
| 115 |
+
|
| 116 |
+
//
|
| 117 |
+
// Parameters struct
|
| 118 |
+
//
|
| 119 |
+
|
| 120 |
+
/// Uses a non-template class
|
| 121 |
+
struct Params : PredicatedTileIteratorParams {
|
| 122 |
+
using Base = PredicatedTileIteratorParams;
|
| 123 |
+
|
| 124 |
+
CUTLASS_HOST_DEVICE
|
| 125 |
+
Params() { }
|
| 126 |
+
|
| 127 |
+
CUTLASS_HOST_DEVICE
|
| 128 |
+
Params(Layout const &layout):
|
| 129 |
+
PredicatedTileIteratorParams(
|
| 130 |
+
layout.stride(0) * int(sizeof(AccessType)) / kElementsPerAccess,
|
| 131 |
+
make_OutputTileThreadMapDesc<ThreadMap>()
|
| 132 |
+
)
|
| 133 |
+
{ }
|
| 134 |
+
|
| 135 |
+
CUTLASS_HOST_DEVICE
|
| 136 |
+
Params(Layout const &layout,
|
| 137 |
+
// Not needed. Added to be compatible with strided conv epilogue.
|
| 138 |
+
cutlass::Tensor4DCoord const &tensor_extent):
|
| 139 |
+
Params(layout)
|
| 140 |
+
{ }
|
| 141 |
+
|
| 142 |
+
CUTLASS_HOST_DEVICE
|
| 143 |
+
Params(Layout const &layout,
|
| 144 |
+
// Not needed. Added to be compatible with strided conv epilogue.
|
| 145 |
+
cutlass::Tensor5DCoord const &tensor_extent):
|
| 146 |
+
Params(layout)
|
| 147 |
+
{ }
|
| 148 |
+
|
| 149 |
+
CUTLASS_HOST_DEVICE
|
| 150 |
+
Params(Base const &base) :
|
| 151 |
+
Base(base) { }
|
| 152 |
+
};
|
| 153 |
+
|
| 154 |
+
/// Mask object
|
| 155 |
+
struct Mask {
|
| 156 |
+
|
| 157 |
+
static int const kCount = ThreadMap::Iterations::kColumn;
|
| 158 |
+
|
| 159 |
+
/// Predicate state
|
| 160 |
+
bool predicates[kCount];
|
| 161 |
+
|
| 162 |
+
//
|
| 163 |
+
// Mask
|
| 164 |
+
//
|
| 165 |
+
CUTLASS_HOST_DEVICE
|
| 166 |
+
Mask() {
|
| 167 |
+
enable();
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
///< Efficiently disables all accesses guarded by mask
|
| 171 |
+
CUTLASS_HOST_DEVICE void clear() {
|
| 172 |
+
CUTLASS_PRAGMA_UNROLL
|
| 173 |
+
for (int i = 0; i < kCount; ++i) {
|
| 174 |
+
predicates[i] = false;
|
| 175 |
+
}
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
///< CUTLASS_HOST_DEVICE enables all accesses guarded by mask
|
| 179 |
+
CUTLASS_DEVICE void enable() {
|
| 180 |
+
CUTLASS_PRAGMA_UNROLL
|
| 181 |
+
for (int i = 0; i < kCount; ++i) {
|
| 182 |
+
predicates[i] = true;
|
| 183 |
+
}
|
| 184 |
+
}
|
| 185 |
+
};
|
| 186 |
+
|
| 187 |
+
private:
|
| 188 |
+
|
| 189 |
+
//
|
| 190 |
+
// Data members
|
| 191 |
+
//
|
| 192 |
+
|
| 193 |
+
/// Parameters structure containing reference and precomputed state.
|
| 194 |
+
PredicatedTileIteratorParams params_;
|
| 195 |
+
|
| 196 |
+
/// Byte-level pointer. This pointer is usually for both load() and store(), unless PermuteD is performed. When having PermuteD, byte_pointer_ is only for load().
|
| 197 |
+
uint8_t *byte_pointer_;
|
| 198 |
+
|
| 199 |
+
/// Byte-level pointer for store(). Due to PermuteD Op, store_byte_pointer_ may be with different address computation compared to byte_pointer_.
|
| 200 |
+
uint8_t *store_byte_pointer_;
|
| 201 |
+
|
| 202 |
+
/// Array of boolean values to contain steady-state predicates
|
| 203 |
+
Mask mask_;
|
| 204 |
+
|
| 205 |
+
/// Extent of the matrix tile in rows
|
| 206 |
+
Index extent_row_;
|
| 207 |
+
|
| 208 |
+
/// Extent of the matrix tile in rows
|
| 209 |
+
Index extent_column_;
|
| 210 |
+
|
| 211 |
+
/// A thread's starting row position (assuming steady-state predicates have been computed)
|
| 212 |
+
Index thread_start_row_;
|
| 213 |
+
|
| 214 |
+
/// A thread's starting column
|
| 215 |
+
Index thread_start_column_;
|
| 216 |
+
|
| 217 |
+
/// Internal state counter
|
| 218 |
+
int state_[3];
|
| 219 |
+
|
| 220 |
+
/// Scatter indices
|
| 221 |
+
int const *indices_;
|
| 222 |
+
|
| 223 |
+
/// PermuteDLayout
|
| 224 |
+
PermuteDLayout permute_layout_;
|
| 225 |
+
|
| 226 |
+
//
|
| 227 |
+
// Static asserts about internal strides
|
| 228 |
+
//
|
| 229 |
+
|
| 230 |
+
static_assert(sizeof(extent_row_) == 4, "Expected 32b extents");
|
| 231 |
+
static_assert(sizeof(thread_start_row_) == 4, "Expected 32b extents");
|
| 232 |
+
static_assert(sizeof(PredicatedTileIteratorParams::stride) == 8, "Expected 64b strides");
|
| 233 |
+
|
| 234 |
+
private:
|
| 235 |
+
|
| 236 |
+
//
|
| 237 |
+
// Methods
|
| 238 |
+
//
|
| 239 |
+
|
| 240 |
+
public:
|
| 241 |
+
|
| 242 |
+
//
|
| 243 |
+
// Methods
|
| 244 |
+
//
|
| 245 |
+
|
| 246 |
+
/// Constructor
|
| 247 |
+
CUTLASS_DEVICE
|
| 248 |
+
PredicatedTileIterator(
|
| 249 |
+
PredicatedTileIteratorParams const & params,
|
| 250 |
+
Element *pointer,
|
| 251 |
+
TensorCoord extent,
|
| 252 |
+
int thread_idx,
|
| 253 |
+
TensorCoord threadblock_offset = TensorCoord(),
|
| 254 |
+
int const *indices = nullptr
|
| 255 |
+
):
|
| 256 |
+
params_(params), indices_(indices),
|
| 257 |
+
permute_layout_(PitchLinearCoord(extent.column(), extent.row()), params_.stride * kElementsPerAccess / sizeof(AccessType))
|
| 258 |
+
{
|
| 259 |
+
|
| 260 |
+
TensorCoord thread_offset = ThreadMap::initial_offset(thread_idx) + threadblock_offset;
|
| 261 |
+
|
| 262 |
+
extent_row_ = extent.row();
|
| 263 |
+
extent_column_ = extent.column();
|
| 264 |
+
|
| 265 |
+
thread_start_row_ = thread_offset.row();
|
| 266 |
+
thread_start_column_ = thread_offset.column();
|
| 267 |
+
|
| 268 |
+
// Initialize predicates
|
| 269 |
+
CUTLASS_PRAGMA_UNROLL
|
| 270 |
+
for (int c = 0; c < ThreadMap::Iterations::kColumn; ++c) {
|
| 271 |
+
|
| 272 |
+
mask_.predicates[c] = ((thread_offset.column()
|
| 273 |
+
+ ThreadMap::Delta::kColumn * c) < extent.column());
|
| 274 |
+
}
|
| 275 |
+
|
| 276 |
+
// Null pointer performs no accesses
|
| 277 |
+
if (!pointer) {
|
| 278 |
+
mask_.clear();
|
| 279 |
+
}
|
| 280 |
+
|
| 281 |
+
if (ScatterD && !indices) {
|
| 282 |
+
mask_.clear();
|
| 283 |
+
}
|
| 284 |
+
|
| 285 |
+
// Initialize byte_pointer_
|
| 286 |
+
byte_pointer_ = reinterpret_cast<uint8_t *>(pointer) +
|
| 287 |
+
LongIndex(thread_offset.row()) * LongIndex(params_.stride) +
|
| 288 |
+
LongIndex(thread_offset.column()) * sizeof(AccessType) / kElementsPerAccess;
|
| 289 |
+
|
| 290 |
+
if (ScatterD) {
|
| 291 |
+
byte_pointer_ = reinterpret_cast<uint8_t *>(pointer) +
|
| 292 |
+
LongIndex(thread_offset.column()) * sizeof(AccessType) / kElementsPerAccess;
|
| 293 |
+
}
|
| 294 |
+
|
| 295 |
+
// store_byte_pointer_ is set to be the same with byte_pointer_ unless PermuteD is used.
|
| 296 |
+
store_byte_pointer_ = PermuteD ? reinterpret_cast<uint8_t *>(pointer) : byte_pointer_;
|
| 297 |
+
|
| 298 |
+
// Initialize internal state counter
|
| 299 |
+
state_[0] = state_[1] = state_[2] = 0;
|
| 300 |
+
}
|
| 301 |
+
|
| 302 |
+
/// Adds a pointer offset in units of Element
|
| 303 |
+
CUTLASS_HOST_DEVICE
|
| 304 |
+
void add_pointer_offset(LongIndex pointer_offset) {
|
| 305 |
+
store_byte_pointer_ += pointer_offset * sizeof_bits<Element>::value / 8;
|
| 306 |
+
byte_pointer_ += pointer_offset * sizeof_bits<Element>::value / 8;
|
| 307 |
+
}
|
| 308 |
+
|
| 309 |
+
/// Loads a fragment from memory
|
| 310 |
+
CUTLASS_DEVICE
|
| 311 |
+
void load_with_byte_offset(Fragment &frag, int64_t byte_offset) const {
|
| 312 |
+
|
| 313 |
+
uint8_t *byte_pointer = byte_pointer_;
|
| 314 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 315 |
+
|
| 316 |
+
CUTLASS_PRAGMA_UNROLL
|
| 317 |
+
for (int cluster = 0; cluster < ThreadMap::Iterations::kCluster; ++cluster) {
|
| 318 |
+
|
| 319 |
+
CUTLASS_PRAGMA_UNROLL
|
| 320 |
+
for (int group = 0; group < ThreadMap::Iterations::kGroup; ++group) {
|
| 321 |
+
|
| 322 |
+
CUTLASS_PRAGMA_UNROLL
|
| 323 |
+
for (int row = 0; row < ThreadMap::Iterations::kRow; ++row) {
|
| 324 |
+
|
| 325 |
+
int frag_row_idx =
|
| 326 |
+
(row + ThreadMap::Iterations::kRow * (group + ThreadMap::Iterations::kGroup * cluster));
|
| 327 |
+
|
| 328 |
+
int row_offset = row * ThreadMap::Delta::kRow
|
| 329 |
+
+ group * ThreadMap::Delta::kGroup
|
| 330 |
+
+ cluster * ThreadMap::Delta::kCluster;
|
| 331 |
+
|
| 332 |
+
bool row_guard = ((row_offset + thread_start_row_) < extent_row_);
|
| 333 |
+
|
| 334 |
+
AccessType *memory_pointer = reinterpret_cast<AccessType *>(byte_pointer + byte_offset);
|
| 335 |
+
|
| 336 |
+
if (ScatterD && row_guard) {
|
| 337 |
+
assert(indices_);
|
| 338 |
+
|
| 339 |
+
memory_pointer = reinterpret_cast<AccessType *>(byte_pointer + byte_offset +
|
| 340 |
+
LongIndex(indices_[row_offset + thread_start_row_]) * LongIndex(params_.stride));
|
| 341 |
+
}
|
| 342 |
+
|
| 343 |
+
CUTLASS_PRAGMA_UNROLL
|
| 344 |
+
for (int column = 0; column < ThreadMap::Iterations::kColumn; ++column) {
|
| 345 |
+
|
| 346 |
+
bool guard = row_guard && mask_.predicates[column];
|
| 347 |
+
|
| 348 |
+
cutlass::arch::global_load<
|
| 349 |
+
AccessType,
|
| 350 |
+
sizeof(AccessType)
|
| 351 |
+
>(
|
| 352 |
+
frag_ptr[frag_row_idx * ThreadMap::Iterations::kColumn +
|
| 353 |
+
column],
|
| 354 |
+
(void *)&memory_pointer[column * ThreadMap::Delta::kColumn /
|
| 355 |
+
kElementsPerAccess],
|
| 356 |
+
guard);
|
| 357 |
+
}
|
| 358 |
+
|
| 359 |
+
if (row + 1 < ThreadMap::Iterations::kRow) {
|
| 360 |
+
if (!ScatterD) {
|
| 361 |
+
byte_pointer += params_.increment_row;
|
| 362 |
+
}
|
| 363 |
+
}
|
| 364 |
+
}
|
| 365 |
+
|
| 366 |
+
if (group + 1 < ThreadMap::Iterations::kGroup) {
|
| 367 |
+
byte_pointer += params_.increment_group;
|
| 368 |
+
}
|
| 369 |
+
}
|
| 370 |
+
|
| 371 |
+
if (cluster + 1 < ThreadMap::Iterations::kCluster) {
|
| 372 |
+
byte_pointer += params_.increment_cluster;
|
| 373 |
+
}
|
| 374 |
+
}
|
| 375 |
+
}
|
| 376 |
+
|
| 377 |
+
/// Loads a fragment from memory
|
| 378 |
+
CUTLASS_DEVICE
|
| 379 |
+
void load(Fragment &frag) const {
|
| 380 |
+
|
| 381 |
+
load_with_byte_offset(frag, 0);
|
| 382 |
+
}
|
| 383 |
+
|
| 384 |
+
/// Stores a fragment to memory
|
| 385 |
+
CUTLASS_DEVICE
|
| 386 |
+
void store_with_byte_offset(Fragment const &frag, int64_t byte_offset) const {
|
| 387 |
+
uint8_t *byte_pointer = store_byte_pointer_;
|
| 388 |
+
AccessType const *frag_ptr = reinterpret_cast<AccessType const *>(&frag);
|
| 389 |
+
|
| 390 |
+
CUTLASS_PRAGMA_UNROLL
|
| 391 |
+
for (int cluster = 0; cluster < ThreadMap::Iterations::kCluster; ++cluster) {
|
| 392 |
+
|
| 393 |
+
CUTLASS_PRAGMA_UNROLL
|
| 394 |
+
for (int group = 0; group < ThreadMap::Iterations::kGroup; ++group) {
|
| 395 |
+
|
| 396 |
+
CUTLASS_PRAGMA_UNROLL
|
| 397 |
+
for (int row = 0; row < ThreadMap::Iterations::kRow; ++row) {
|
| 398 |
+
|
| 399 |
+
int frag_row_idx =
|
| 400 |
+
(row + ThreadMap::Iterations::kRow * (group + ThreadMap::Iterations::kGroup * cluster));
|
| 401 |
+
|
| 402 |
+
int row_offset = row * ThreadMap::Delta::kRow
|
| 403 |
+
+ group * ThreadMap::Delta::kGroup
|
| 404 |
+
+ cluster * ThreadMap::Delta::kCluster;
|
| 405 |
+
|
| 406 |
+
bool row_guard = ((row_offset + thread_start_row_) < extent_row_);
|
| 407 |
+
|
| 408 |
+
AccessType *memory_pointer = reinterpret_cast<AccessType *>(byte_pointer + byte_offset);
|
| 409 |
+
|
| 410 |
+
if (ScatterD && row_guard) {
|
| 411 |
+
assert(indices_);
|
| 412 |
+
|
| 413 |
+
memory_pointer = reinterpret_cast<AccessType *>(byte_pointer + byte_offset +
|
| 414 |
+
LongIndex(indices_[row_offset + thread_start_row_]) * LongIndex(params_.stride));
|
| 415 |
+
}
|
| 416 |
+
|
| 417 |
+
CUTLASS_PRAGMA_UNROLL
|
| 418 |
+
for (int column = 0; column < ThreadMap::Iterations::kColumn; ++column) {
|
| 419 |
+
|
| 420 |
+
bool guard = row_guard && mask_.predicates[column];
|
| 421 |
+
|
| 422 |
+
if (PermuteD) {
|
| 423 |
+
|
| 424 |
+
int col_offset = column * ThreadMap::Delta::kColumn;
|
| 425 |
+
|
| 426 |
+
int col = col_offset + thread_start_column_;
|
| 427 |
+
int row = row_offset + thread_start_row_;
|
| 428 |
+
|
| 429 |
+
// Locate memory_pointer
|
| 430 |
+
memory_pointer = reinterpret_cast<AccessType *>(byte_pointer + byte_offset
|
| 431 |
+
+ permute_layout_(PitchLinearCoord(col, row)) * sizeof(AccessType) / kElementsPerAccess);
|
| 432 |
+
}
|
| 433 |
+
|
| 434 |
+
if (UseCUDAStore) {
|
| 435 |
+
if (guard) {
|
| 436 |
+
memory_pointer[0] =
|
| 437 |
+
frag_ptr[frag_row_idx * ThreadMap::Iterations::kColumn + column];
|
| 438 |
+
}
|
| 439 |
+
} else {
|
| 440 |
+
cutlass::arch::global_store<AccessType, sizeof(AccessType)>(
|
| 441 |
+
frag_ptr[frag_row_idx * ThreadMap::Iterations::kColumn + column],
|
| 442 |
+
(void *)&memory_pointer[0],
|
| 443 |
+
guard);
|
| 444 |
+
}
|
| 445 |
+
|
| 446 |
+
if (!PermuteD) {
|
| 447 |
+
memory_pointer += (ThreadMap::Delta::kColumn / kElementsPerAccess);
|
| 448 |
+
}
|
| 449 |
+
}
|
| 450 |
+
|
| 451 |
+
if (row + 1 < ThreadMap::Iterations::kRow) {
|
| 452 |
+
if (!ScatterD && !PermuteD) {
|
| 453 |
+
byte_pointer += params_.increment_row;
|
| 454 |
+
}
|
| 455 |
+
}
|
| 456 |
+
}
|
| 457 |
+
|
| 458 |
+
if (group + 1 < ThreadMap::Iterations::kGroup) {
|
| 459 |
+
if (!ScatterD && !PermuteD) {
|
| 460 |
+
byte_pointer += params_.increment_group;
|
| 461 |
+
}
|
| 462 |
+
}
|
| 463 |
+
}
|
| 464 |
+
|
| 465 |
+
if (cluster + 1 < ThreadMap::Iterations::kCluster) {
|
| 466 |
+
if (!ScatterD && !PermuteD) {
|
| 467 |
+
byte_pointer += params_.increment_cluster;
|
| 468 |
+
}
|
| 469 |
+
}
|
| 470 |
+
}
|
| 471 |
+
}
|
| 472 |
+
|
| 473 |
+
/// Stores a fragment to memory
|
| 474 |
+
CUTLASS_DEVICE
|
| 475 |
+
void store(Fragment const &frag) const {
|
| 476 |
+
|
| 477 |
+
store_with_byte_offset(frag, 0);
|
| 478 |
+
}
|
| 479 |
+
|
| 480 |
+
/// Loads a fragment from memory
|
| 481 |
+
CUTLASS_DEVICE
|
| 482 |
+
void downsample_load_with_byte_offset(Fragment &frag, int64_t byte_offset, int convolution_P, int convolution_Q, int add_P, int add_Q, int problem_N) const {
|
| 483 |
+
|
| 484 |
+
uint8_t *byte_pointer = byte_pointer_;
|
| 485 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 486 |
+
|
| 487 |
+
CUTLASS_PRAGMA_UNROLL
|
| 488 |
+
for (int cluster = 0; cluster < ThreadMap::Iterations::kCluster; ++cluster) {
|
| 489 |
+
|
| 490 |
+
CUTLASS_PRAGMA_UNROLL
|
| 491 |
+
for (int group = 0; group < ThreadMap::Iterations::kGroup; ++group) {
|
| 492 |
+
|
| 493 |
+
CUTLASS_PRAGMA_UNROLL
|
| 494 |
+
for (int row = 0; row < ThreadMap::Iterations::kRow; ++row) {
|
| 495 |
+
|
| 496 |
+
int frag_row_idx =
|
| 497 |
+
(row + ThreadMap::Iterations::kRow * (group + ThreadMap::Iterations::kGroup * cluster));
|
| 498 |
+
|
| 499 |
+
int row_offset = row * ThreadMap::Delta::kRow
|
| 500 |
+
+ group * ThreadMap::Delta::kGroup
|
| 501 |
+
+ cluster * ThreadMap::Delta::kCluster;
|
| 502 |
+
|
| 503 |
+
bool row_guard = ((row_offset + thread_start_row_) < extent_row_);
|
| 504 |
+
|
| 505 |
+
int output_row = row_offset + thread_start_row_;
|
| 506 |
+
int output_N = output_row / (convolution_P * convolution_Q);
|
| 507 |
+
int output_PQ = output_row % (convolution_P * convolution_Q);
|
| 508 |
+
int output_P = output_PQ / convolution_Q;
|
| 509 |
+
int output_Q = output_PQ % convolution_Q;
|
| 510 |
+
|
| 511 |
+
int input_row = output_N * 2 * convolution_P * 2 * convolution_Q +
|
| 512 |
+
(2 * output_P + add_P) * 2 * convolution_Q + 2 * output_Q + add_Q;
|
| 513 |
+
|
| 514 |
+
int64_t byte_offset = (input_row-output_row)*problem_N*sizeof(float);
|
| 515 |
+
|
| 516 |
+
AccessType *memory_pointer = reinterpret_cast<AccessType *>(byte_pointer + byte_offset);
|
| 517 |
+
|
| 518 |
+
CUTLASS_PRAGMA_UNROLL
|
| 519 |
+
for (int column = 0; column < ThreadMap::Iterations::kColumn; ++column) {
|
| 520 |
+
|
| 521 |
+
bool guard = row_guard && mask_.predicates[column];
|
| 522 |
+
|
| 523 |
+
cutlass::arch::global_load<
|
| 524 |
+
AccessType,
|
| 525 |
+
sizeof(AccessType)
|
| 526 |
+
>(
|
| 527 |
+
frag_ptr[frag_row_idx * ThreadMap::Iterations::kColumn +
|
| 528 |
+
column],
|
| 529 |
+
(void *)&memory_pointer[column * ThreadMap::Delta::kColumn /
|
| 530 |
+
kElementsPerAccess],
|
| 531 |
+
guard);
|
| 532 |
+
}
|
| 533 |
+
|
| 534 |
+
if (row + 1 < ThreadMap::Iterations::kRow) {
|
| 535 |
+
byte_pointer += params_.increment_row;
|
| 536 |
+
}
|
| 537 |
+
}
|
| 538 |
+
|
| 539 |
+
if (group + 1 < ThreadMap::Iterations::kGroup) {
|
| 540 |
+
byte_pointer += params_.increment_group;
|
| 541 |
+
}
|
| 542 |
+
}
|
| 543 |
+
|
| 544 |
+
if (cluster + 1 < ThreadMap::Iterations::kCluster) {
|
| 545 |
+
byte_pointer += params_.increment_cluster;
|
| 546 |
+
}
|
| 547 |
+
}
|
| 548 |
+
}
|
| 549 |
+
|
| 550 |
+
/// Loads a fragment from memory
|
| 551 |
+
CUTLASS_DEVICE
|
| 552 |
+
void upsample_load_with_byte_offset(Fragment &frag, int64_t byte_offset, int convolution_P, int convolution_Q, int add_P, int add_Q, int problem_N) const {
|
| 553 |
+
|
| 554 |
+
uint8_t *byte_pointer = byte_pointer_;
|
| 555 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 556 |
+
|
| 557 |
+
CUTLASS_PRAGMA_UNROLL
|
| 558 |
+
for (int cluster = 0; cluster < ThreadMap::Iterations::kCluster; ++cluster) {
|
| 559 |
+
|
| 560 |
+
CUTLASS_PRAGMA_UNROLL
|
| 561 |
+
for (int group = 0; group < ThreadMap::Iterations::kGroup; ++group) {
|
| 562 |
+
|
| 563 |
+
CUTLASS_PRAGMA_UNROLL
|
| 564 |
+
for (int row = 0; row < ThreadMap::Iterations::kRow; ++row) {
|
| 565 |
+
|
| 566 |
+
int frag_row_idx =
|
| 567 |
+
(row + ThreadMap::Iterations::kRow * (group + ThreadMap::Iterations::kGroup * cluster));
|
| 568 |
+
|
| 569 |
+
int row_offset = row * ThreadMap::Delta::kRow
|
| 570 |
+
+ group * ThreadMap::Delta::kGroup
|
| 571 |
+
+ cluster * ThreadMap::Delta::kCluster;
|
| 572 |
+
|
| 573 |
+
bool row_guard = ((row_offset + thread_start_row_) < extent_row_);
|
| 574 |
+
|
| 575 |
+
int output_row = row_offset + thread_start_row_;
|
| 576 |
+
int output_N = output_row / (convolution_P * convolution_Q);
|
| 577 |
+
int output_PQ = output_row % (convolution_P * convolution_Q);
|
| 578 |
+
int output_P = output_PQ / convolution_Q;
|
| 579 |
+
int output_Q = output_PQ % convolution_Q;
|
| 580 |
+
int row_add_P = add_P;
|
| 581 |
+
int row_add_Q = add_Q;
|
| 582 |
+
if (output_P > convolution_P - 2) row_add_P = 0;
|
| 583 |
+
if (output_Q > convolution_Q - 2) row_add_Q = 0;
|
| 584 |
+
|
| 585 |
+
int input_row = output_N * (convolution_P/2) * (convolution_Q/2) +
|
| 586 |
+
((output_P + row_add_P)/2) * (convolution_Q/2) + (output_Q + row_add_Q)/2;
|
| 587 |
+
|
| 588 |
+
int64_t byte_offset = (input_row-output_row)*problem_N*sizeof(float);
|
| 589 |
+
|
| 590 |
+
AccessType *memory_pointer = reinterpret_cast<AccessType *>(byte_pointer + byte_offset);
|
| 591 |
+
|
| 592 |
+
CUTLASS_PRAGMA_UNROLL
|
| 593 |
+
for (int column = 0; column < ThreadMap::Iterations::kColumn; ++column) {
|
| 594 |
+
|
| 595 |
+
bool guard = row_guard && mask_.predicates[column];
|
| 596 |
+
|
| 597 |
+
cutlass::arch::global_load<
|
| 598 |
+
AccessType,
|
| 599 |
+
sizeof(AccessType)
|
| 600 |
+
>(
|
| 601 |
+
frag_ptr[frag_row_idx * ThreadMap::Iterations::kColumn +
|
| 602 |
+
column],
|
| 603 |
+
(void *)&memory_pointer[column * ThreadMap::Delta::kColumn /
|
| 604 |
+
kElementsPerAccess],
|
| 605 |
+
guard);
|
| 606 |
+
}
|
| 607 |
+
|
| 608 |
+
if (row + 1 < ThreadMap::Iterations::kRow) {
|
| 609 |
+
byte_pointer += params_.increment_row;
|
| 610 |
+
}
|
| 611 |
+
}
|
| 612 |
+
|
| 613 |
+
if (group + 1 < ThreadMap::Iterations::kGroup) {
|
| 614 |
+
byte_pointer += params_.increment_group;
|
| 615 |
+
}
|
| 616 |
+
}
|
| 617 |
+
|
| 618 |
+
if (cluster + 1 < ThreadMap::Iterations::kCluster) {
|
| 619 |
+
byte_pointer += params_.increment_cluster;
|
| 620 |
+
}
|
| 621 |
+
}
|
| 622 |
+
}
|
| 623 |
+
|
| 624 |
+
CUTLASS_DEVICE
|
| 625 |
+
MatrixCoord thread_start() const {
|
| 626 |
+
return MatrixCoord(thread_start_row_, thread_start_column_);
|
| 627 |
+
}
|
| 628 |
+
|
| 629 |
+
/// Need to get the thread start row from the tile iterator
|
| 630 |
+
CUTLASS_DEVICE
|
| 631 |
+
int32_t thread_start_row() const {
|
| 632 |
+
return thread_start_row_;
|
| 633 |
+
}
|
| 634 |
+
|
| 635 |
+
/// Need to get the thread start row from the tile iterator
|
| 636 |
+
CUTLASS_DEVICE
|
| 637 |
+
int32_t thread_start_column() const {
|
| 638 |
+
return thread_start_column_;
|
| 639 |
+
}
|
| 640 |
+
|
| 641 |
+
/// Extent of the matrix in rows
|
| 642 |
+
CUTLASS_DEVICE
|
| 643 |
+
Index extent_row() const {
|
| 644 |
+
return extent_row_;
|
| 645 |
+
}
|
| 646 |
+
|
| 647 |
+
/// Extent of the matrix in columns
|
| 648 |
+
CUTLASS_DEVICE
|
| 649 |
+
Index extent_column() const {
|
| 650 |
+
return extent_column_;
|
| 651 |
+
}
|
| 652 |
+
|
| 653 |
+
/// Advances to the next position to load or store
|
| 654 |
+
CUTLASS_HOST_DEVICE
|
| 655 |
+
PredicatedTileIterator &operator++() {
|
| 656 |
+
|
| 657 |
+
++state_[0];
|
| 658 |
+
|
| 659 |
+
if (!ScatterD) {
|
| 660 |
+
byte_pointer_ += params_.advance_row;
|
| 661 |
+
}
|
| 662 |
+
|
| 663 |
+
if (!ScatterD && !PermuteD) {
|
| 664 |
+
store_byte_pointer_ += params_.advance_row;
|
| 665 |
+
}
|
| 666 |
+
|
| 667 |
+
thread_start_row_ += ThreadMap::Shape::kRow;
|
| 668 |
+
|
| 669 |
+
if (state_[0] == ThreadMap::Count::kRow) {
|
| 670 |
+
|
| 671 |
+
state_[0] = 0;
|
| 672 |
+
++state_[1];
|
| 673 |
+
|
| 674 |
+
if (!ScatterD) {
|
| 675 |
+
byte_pointer_ += params_.advance_group;
|
| 676 |
+
}
|
| 677 |
+
|
| 678 |
+
if (!ScatterD && !PermuteD) {
|
| 679 |
+
store_byte_pointer_ += params_.advance_group;
|
| 680 |
+
}
|
| 681 |
+
|
| 682 |
+
thread_start_row_ += (ThreadMap::Shape::kGroup - 1) *
|
| 683 |
+
ThreadMap::Shape::kRow * ThreadMap::Count::kRow;
|
| 684 |
+
|
| 685 |
+
if (state_[1] == ThreadMap::Count::kGroup) {
|
| 686 |
+
|
| 687 |
+
state_[1] = 0;
|
| 688 |
+
++state_[2];
|
| 689 |
+
|
| 690 |
+
if (!ScatterD) {
|
| 691 |
+
byte_pointer_ += params_.advance_cluster;
|
| 692 |
+
}
|
| 693 |
+
|
| 694 |
+
if (!ScatterD && !PermuteD) {
|
| 695 |
+
store_byte_pointer_ += params_.advance_cluster;
|
| 696 |
+
}
|
| 697 |
+
|
| 698 |
+
thread_start_row_ += ThreadMap::Count::kGroup *
|
| 699 |
+
ThreadMap::Shape::kGroup * ThreadMap::Count::kRow * ThreadMap::Shape::kRow;
|
| 700 |
+
|
| 701 |
+
if (state_[2] == ThreadMap::Count::kCluster) {
|
| 702 |
+
state_[2] = 0;
|
| 703 |
+
|
| 704 |
+
if (!ScatterD) {
|
| 705 |
+
byte_pointer_ += params_.advance_tile;
|
| 706 |
+
}
|
| 707 |
+
|
| 708 |
+
if (!ScatterD && !PermuteD) {
|
| 709 |
+
store_byte_pointer_ += params_.advance_tile;
|
| 710 |
+
}
|
| 711 |
+
|
| 712 |
+
thread_start_row_ += ThreadMap::Shape::kGroup * ThreadMap::Shape::kRow
|
| 713 |
+
* ThreadMap::Shape::kCluster * ThreadMap::Shape::kTile;
|
| 714 |
+
}
|
| 715 |
+
}
|
| 716 |
+
}
|
| 717 |
+
|
| 718 |
+
return *this;
|
| 719 |
+
}
|
| 720 |
+
|
| 721 |
+
/// Advances a number of positions to load or store
|
| 722 |
+
CUTLASS_HOST_DEVICE
|
| 723 |
+
PredicatedTileIterator &operator+=(int increment)
|
| 724 |
+
{
|
| 725 |
+
// Row
|
| 726 |
+
state_[0] += increment;
|
| 727 |
+
int increment_row = state_[0] / ThreadMap::Count::kRow;
|
| 728 |
+
state_[0] = state_[0] % ThreadMap::Count::kRow;
|
| 729 |
+
|
| 730 |
+
byte_pointer_ += (params_.advance_row * increment);
|
| 731 |
+
store_byte_pointer_ += (params_.advance_row * increment);
|
| 732 |
+
thread_start_row_ += (ThreadMap::Shape::kRow * increment);
|
| 733 |
+
|
| 734 |
+
// Group
|
| 735 |
+
state_[1] += increment_row;
|
| 736 |
+
int increment_group = state_[1] / ThreadMap::Count::kGroup;
|
| 737 |
+
state_[1] = state_[1] % ThreadMap::Count::kGroup;
|
| 738 |
+
|
| 739 |
+
byte_pointer_ += (params_.advance_group * increment_row);
|
| 740 |
+
store_byte_pointer_ += (params_.advance_group * increment_row);
|
| 741 |
+
thread_start_row_ +=
|
| 742 |
+
(ThreadMap::Shape::kGroup - 1) *
|
| 743 |
+
ThreadMap::Shape::kRow *
|
| 744 |
+
ThreadMap::Count::kRow *
|
| 745 |
+
increment_row;
|
| 746 |
+
|
| 747 |
+
|
| 748 |
+
// Cluster
|
| 749 |
+
state_[2] += increment_group;
|
| 750 |
+
int increment_cluster = state_[2] / ThreadMap::Count::kCluster;
|
| 751 |
+
state_[2] = state_[2] % ThreadMap::Count::kCluster;
|
| 752 |
+
|
| 753 |
+
byte_pointer_ += (params_.advance_cluster * increment_group);
|
| 754 |
+
store_byte_pointer_ += (params_.advance_cluster * increment_group);
|
| 755 |
+
thread_start_row_ +=
|
| 756 |
+
ThreadMap::Count::kGroup *
|
| 757 |
+
ThreadMap::Shape::kGroup *
|
| 758 |
+
ThreadMap::Count::kRow *
|
| 759 |
+
ThreadMap::Shape::kRow *
|
| 760 |
+
increment_group;
|
| 761 |
+
|
| 762 |
+
// Tile
|
| 763 |
+
byte_pointer_ += (params_.advance_tile * increment_cluster);
|
| 764 |
+
store_byte_pointer_ += (params_.advance_tile * increment_cluster);
|
| 765 |
+
thread_start_row_ +=
|
| 766 |
+
ThreadMap::Shape::kGroup *
|
| 767 |
+
ThreadMap::Shape::kRow *
|
| 768 |
+
ThreadMap::Shape::kCluster *
|
| 769 |
+
ThreadMap::Shape::kTile *
|
| 770 |
+
increment_cluster;
|
| 771 |
+
|
| 772 |
+
return *this;
|
| 773 |
+
}
|
| 774 |
+
|
| 775 |
+
///< Efficiently disables all accesses guarded by mask
|
| 776 |
+
CUTLASS_DEVICE void clear_mask() {
|
| 777 |
+
mask_.clear();
|
| 778 |
+
}
|
| 779 |
+
|
| 780 |
+
///< Efficiently enables all accesses guarded by mask
|
| 781 |
+
CUTLASS_DEVICE void enable_mask() {
|
| 782 |
+
mask_.enable();
|
| 783 |
+
}
|
| 784 |
+
|
| 785 |
+
///< Sets the mask
|
| 786 |
+
CUTLASS_DEVICE void get_mask(Mask &mask) const {
|
| 787 |
+
mask = mask_;
|
| 788 |
+
}
|
| 789 |
+
|
| 790 |
+
///< Sets the mask
|
| 791 |
+
CUTLASS_DEVICE void set_mask(Mask const &mask) {
|
| 792 |
+
mask_ = mask;
|
| 793 |
+
}
|
| 794 |
+
};
|
| 795 |
+
|
| 796 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 797 |
+
|
| 798 |
+
/// Tile iterator used to load output tile from global memory in epilogue.
|
| 799 |
+
///
|
| 800 |
+
/// Satisfies: ReadableTileIterator | InterleavedPredicatedTileIterator | ForwardTileIterator
|
| 801 |
+
///
|
| 802 |
+
template <
|
| 803 |
+
typename ThreadMap_, ///< Thread map (conept: OutputTileThreadMap)
|
| 804 |
+
typename Element_, ///< Element data type
|
| 805 |
+
int InterleavedN ///< Number of Interleaved N
|
| 806 |
+
>
|
| 807 |
+
class InterleavedPredicatedTileIterator {
|
| 808 |
+
public:
|
| 809 |
+
using ThreadMap = ThreadMap_;
|
| 810 |
+
|
| 811 |
+
using Element = Element_;
|
| 812 |
+
|
| 813 |
+
using Layout = layout::ColumnMajorInterleaved<InterleavedN>;
|
| 814 |
+
using TensorRef = TensorRef<Element, Layout>;
|
| 815 |
+
using ConstTensorRef = typename TensorRef::ConstTensorRef;
|
| 816 |
+
|
| 817 |
+
using Index = typename Layout::Index;
|
| 818 |
+
using LongIndex = typename Layout::LongIndex;
|
| 819 |
+
using TensorCoord = layout::PitchLinearCoord;
|
| 820 |
+
|
| 821 |
+
static int const kElementsPerAccess = ThreadMap::kElementsPerAccess;
|
| 822 |
+
static int const kThreads = ThreadMap::kThreads;
|
| 823 |
+
static int const kIterations = ThreadMap::Iterations::kCount;
|
| 824 |
+
|
| 825 |
+
/// Fragment object
|
| 826 |
+
using Fragment = Array<Element, ThreadMap::kElementsPerAccess>;
|
| 827 |
+
|
| 828 |
+
/// Memory access size
|
| 829 |
+
using AccessType = AlignedArray<Element, ThreadMap::kElementsPerAccess>;
|
| 830 |
+
|
| 831 |
+
/// Uses a non-template class
|
| 832 |
+
struct Params : InterleavedPredicatedTileIteratorParams {
|
| 833 |
+
using Base = InterleavedPredicatedTileIteratorParams;
|
| 834 |
+
|
| 835 |
+
CUTLASS_HOST_DEVICE
|
| 836 |
+
Params() { }
|
| 837 |
+
|
| 838 |
+
CUTLASS_HOST_DEVICE
|
| 839 |
+
Params(Layout const &layout):
|
| 840 |
+
Base(
|
| 841 |
+
layout.stride(0) * int(sizeof(AccessType)) / kElementsPerAccess,
|
| 842 |
+
make_InterleavedPredicatedTileIteratorDesc<Element, ThreadMap>()
|
| 843 |
+
) { }
|
| 844 |
+
|
| 845 |
+
CUTLASS_HOST_DEVICE
|
| 846 |
+
Params(Base const &base) :
|
| 847 |
+
Base(base) { }
|
| 848 |
+
};
|
| 849 |
+
|
| 850 |
+
/// Mask object
|
| 851 |
+
struct Mask {
|
| 852 |
+
static int const kCount = (ThreadMap::Iterations::kContiguous < 8)
|
| 853 |
+
? 8
|
| 854 |
+
: ThreadMap::Iterations::kContiguous;
|
| 855 |
+
|
| 856 |
+
/// Predicate state
|
| 857 |
+
bool predicates[kCount];
|
| 858 |
+
|
| 859 |
+
//
|
| 860 |
+
// Mask
|
| 861 |
+
//
|
| 862 |
+
CUTLASS_HOST_DEVICE
|
| 863 |
+
Mask() {
|
| 864 |
+
enable();
|
| 865 |
+
}
|
| 866 |
+
|
| 867 |
+
///< Efficiently disables all accesses guarded by mask
|
| 868 |
+
CUTLASS_HOST_DEVICE void clear() {
|
| 869 |
+
CUTLASS_PRAGMA_UNROLL
|
| 870 |
+
for (int i = 0; i < kCount; ++i) {
|
| 871 |
+
predicates[i] = false;
|
| 872 |
+
}
|
| 873 |
+
}
|
| 874 |
+
|
| 875 |
+
///< CUTLASS_HOST_DEVICE enables all accesses guarded by mask
|
| 876 |
+
CUTLASS_DEVICE void enable() {
|
| 877 |
+
CUTLASS_PRAGMA_UNROLL
|
| 878 |
+
for (int i = 0; i < kCount; ++i) {
|
| 879 |
+
predicates[i] = true;
|
| 880 |
+
}
|
| 881 |
+
}
|
| 882 |
+
};
|
| 883 |
+
|
| 884 |
+
private:
|
| 885 |
+
|
| 886 |
+
//
|
| 887 |
+
// Data members
|
| 888 |
+
//
|
| 889 |
+
|
| 890 |
+
/// Parameters structure containing reference and precomputed state.
|
| 891 |
+
Params params_;
|
| 892 |
+
|
| 893 |
+
/// Byte-level pointer
|
| 894 |
+
uint8_t *byte_pointer_;
|
| 895 |
+
|
| 896 |
+
/// Array of boolean values to contain steady-state predicates
|
| 897 |
+
Mask mask_;
|
| 898 |
+
|
| 899 |
+
/// Extent of the matrix tile in columns
|
| 900 |
+
Index extent_col_;
|
| 901 |
+
|
| 902 |
+
/// A thread's starting column position (assuming steady-state predicates have
|
| 903 |
+
/// been computed)
|
| 904 |
+
Index thread_start_col_;
|
| 905 |
+
|
| 906 |
+
/// Internal iteration counter
|
| 907 |
+
int iteration_contiguous_;
|
| 908 |
+
|
| 909 |
+
int iteration_strided_;
|
| 910 |
+
|
| 911 |
+
private:
|
| 912 |
+
|
| 913 |
+
//
|
| 914 |
+
// Methods
|
| 915 |
+
//
|
| 916 |
+
|
| 917 |
+
public:
|
| 918 |
+
|
| 919 |
+
//
|
| 920 |
+
// Methods
|
| 921 |
+
//
|
| 922 |
+
|
| 923 |
+
/// Constructor
|
| 924 |
+
CUTLASS_DEVICE
|
| 925 |
+
InterleavedPredicatedTileIterator(
|
| 926 |
+
Params const & params,
|
| 927 |
+
Element *pointer,
|
| 928 |
+
TensorCoord extent,
|
| 929 |
+
int thread_idx,
|
| 930 |
+
TensorCoord threadblock_offset,
|
| 931 |
+
int const *indices = nullptr ///< gather/scatter indices, note no support for gather/scatter at this specialization
|
| 932 |
+
):
|
| 933 |
+
params_(params) {
|
| 934 |
+
TensorCoord thread_offset = ThreadMap::initial_offset(thread_idx) +
|
| 935 |
+
TensorCoord(threadblock_offset.contiguous() * InterleavedN,
|
| 936 |
+
threadblock_offset.strided() / InterleavedN);
|
| 937 |
+
|
| 938 |
+
extent_col_ = extent.strided() / InterleavedN;
|
| 939 |
+
thread_start_col_ = thread_offset.strided();
|
| 940 |
+
|
| 941 |
+
// Initialize predicates
|
| 942 |
+
CUTLASS_PRAGMA_UNROLL
|
| 943 |
+
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
|
| 944 |
+
mask_.predicates[c] =
|
| 945 |
+
((thread_offset.contiguous() + ThreadMap::Delta::kContiguous * c) <
|
| 946 |
+
(extent.contiguous() * InterleavedN));
|
| 947 |
+
}
|
| 948 |
+
|
| 949 |
+
// Initialize pointer
|
| 950 |
+
byte_pointer_ = reinterpret_cast<uint8_t *>(pointer) +
|
| 951 |
+
LongIndex(thread_offset.strided()) * LongIndex(params_.stride) +
|
| 952 |
+
LongIndex(thread_offset.contiguous()) * sizeof(AccessType) / kElementsPerAccess;
|
| 953 |
+
|
| 954 |
+
// Initialize internal state counter
|
| 955 |
+
iteration_contiguous_ = iteration_strided_ = 0;
|
| 956 |
+
}
|
| 957 |
+
|
| 958 |
+
/// Adds a pointer offset in units of Element
|
| 959 |
+
CUTLASS_HOST_DEVICE
|
| 960 |
+
void add_pointer_offset(LongIndex pointer_offset) {
|
| 961 |
+
byte_pointer_ += pointer_offset * sizeof_bits<Element>::value / 8;
|
| 962 |
+
}
|
| 963 |
+
|
| 964 |
+
/// Loads a fragment from memory
|
| 965 |
+
CUTLASS_DEVICE
|
| 966 |
+
void load(Fragment &frag) {
|
| 967 |
+
|
| 968 |
+
uint8_t *byte_pointer = byte_pointer_;
|
| 969 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 970 |
+
AccessType *memory_pointer = reinterpret_cast<AccessType *>(byte_pointer);
|
| 971 |
+
|
| 972 |
+
int col_offset = iteration_strided_ * ThreadMap::Delta::kStrided;
|
| 973 |
+
|
| 974 |
+
bool col_guard = ((thread_start_col_ + col_offset) < extent_col_);
|
| 975 |
+
|
| 976 |
+
bool guard = col_guard && mask_.predicates[iteration_contiguous_];
|
| 977 |
+
|
| 978 |
+
cutlass::arch::global_load<
|
| 979 |
+
AccessType,
|
| 980 |
+
sizeof(AccessType)
|
| 981 |
+
>(
|
| 982 |
+
*frag_ptr,
|
| 983 |
+
(void *)memory_pointer,
|
| 984 |
+
guard);
|
| 985 |
+
}
|
| 986 |
+
|
| 987 |
+
/// Stores a fragment to memory
|
| 988 |
+
CUTLASS_DEVICE
|
| 989 |
+
void store(Fragment const &frag) {
|
| 990 |
+
uint8_t *byte_pointer = byte_pointer_;
|
| 991 |
+
AccessType const *frag_ptr = reinterpret_cast<AccessType const *>(&frag);
|
| 992 |
+
AccessType *memory_pointer = reinterpret_cast<AccessType *>(byte_pointer);
|
| 993 |
+
|
| 994 |
+
int col_offset = iteration_strided_ * ThreadMap::Delta::kStrided;
|
| 995 |
+
|
| 996 |
+
bool col_guard = ((thread_start_col_ + col_offset) < extent_col_);
|
| 997 |
+
|
| 998 |
+
bool guard = col_guard && mask_.predicates[iteration_contiguous_];
|
| 999 |
+
|
| 1000 |
+
cutlass::arch::global_store<AccessType, sizeof(AccessType)>(
|
| 1001 |
+
*frag_ptr, (void *)memory_pointer, guard);
|
| 1002 |
+
}
|
| 1003 |
+
|
| 1004 |
+
/// Overrides the internal iteration index
|
| 1005 |
+
CUTLASS_HOST_DEVICE
|
| 1006 |
+
void set_iteration_index(int iteration) {
|
| 1007 |
+
iteration_contiguous_ = iteration % ThreadMap::Iterations::kContiguous;
|
| 1008 |
+
iteration_strided_ = iteration / ThreadMap::Iterations::kContiguous;
|
| 1009 |
+
}
|
| 1010 |
+
|
| 1011 |
+
/// Advances to the next position to load or store
|
| 1012 |
+
CUTLASS_HOST_DEVICE
|
| 1013 |
+
InterleavedPredicatedTileIterator &operator++() {
|
| 1014 |
+
|
| 1015 |
+
++iteration_contiguous_;
|
| 1016 |
+
byte_pointer_ += params_.advance_row;
|
| 1017 |
+
|
| 1018 |
+
if (iteration_contiguous_ == ThreadMap::Iterations::kContiguous) {
|
| 1019 |
+
|
| 1020 |
+
iteration_contiguous_ = 0;
|
| 1021 |
+
++iteration_strided_;
|
| 1022 |
+
byte_pointer_ += params_.advance_column;
|
| 1023 |
+
|
| 1024 |
+
if (iteration_strided_ == ThreadMap::Iterations::kStrided) {
|
| 1025 |
+
iteration_strided_ = 0;
|
| 1026 |
+
}
|
| 1027 |
+
}
|
| 1028 |
+
|
| 1029 |
+
return *this;
|
| 1030 |
+
}
|
| 1031 |
+
|
| 1032 |
+
/// Advances a number of positions to load or store
|
| 1033 |
+
CUTLASS_HOST_DEVICE
|
| 1034 |
+
InterleavedPredicatedTileIterator &operator+=(int increment)
|
| 1035 |
+
{
|
| 1036 |
+
// Contiguous
|
| 1037 |
+
iteration_contiguous_ += increment;
|
| 1038 |
+
int increment_strided = iteration_contiguous_ / ThreadMap::Iterations::kContiguous;
|
| 1039 |
+
iteration_contiguous_ = iteration_contiguous_ % ThreadMap::Iterations::kContiguous;
|
| 1040 |
+
byte_pointer_ += (params_.advance_row * increment);
|
| 1041 |
+
|
| 1042 |
+
// Strided
|
| 1043 |
+
iteration_strided_ += increment_strided;
|
| 1044 |
+
byte_pointer_ += (params_.advance_column * increment_strided);
|
| 1045 |
+
|
| 1046 |
+
return *this;
|
| 1047 |
+
}
|
| 1048 |
+
|
| 1049 |
+
///< Efficiently disables all accesses guarded by mask
|
| 1050 |
+
CUTLASS_DEVICE void clear_mask() {
|
| 1051 |
+
mask_.clear();
|
| 1052 |
+
}
|
| 1053 |
+
|
| 1054 |
+
///< Efficiently enables all accesses guarded by mask
|
| 1055 |
+
CUTLASS_DEVICE void enable_mask() {
|
| 1056 |
+
mask_.enable();
|
| 1057 |
+
}
|
| 1058 |
+
|
| 1059 |
+
///< Sets the mask
|
| 1060 |
+
CUTLASS_DEVICE void get_mask(Mask &mask) {
|
| 1061 |
+
mask = mask_;
|
| 1062 |
+
}
|
| 1063 |
+
|
| 1064 |
+
///< Sets the mask
|
| 1065 |
+
CUTLASS_DEVICE void set_mask(Mask const &mask) {
|
| 1066 |
+
mask_ = mask;
|
| 1067 |
+
}
|
| 1068 |
+
};
|
| 1069 |
+
|
| 1070 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 1071 |
+
|
| 1072 |
+
/// Tile iterator used to load output tile from global memory in epilogue.
|
| 1073 |
+
///
|
| 1074 |
+
/// Satisfies: ReadableTileIterator | InterleavedMaskedTileIterator | ForwardTileIterator
|
| 1075 |
+
///
|
| 1076 |
+
template <
|
| 1077 |
+
typename ThreadMap_, ///< Thread map (conept: OutputTileThreadMap)
|
| 1078 |
+
typename Element_, ///< Element data type
|
| 1079 |
+
int InterleavedN ///< Number of Interleaved N
|
| 1080 |
+
>
|
| 1081 |
+
class InterleavedConvPredicatedTileIterator {
|
| 1082 |
+
public:
|
| 1083 |
+
using ThreadMap = ThreadMap_;
|
| 1084 |
+
|
| 1085 |
+
using Element = Element_;
|
| 1086 |
+
|
| 1087 |
+
using Layout = layout::TensorNCxHWx<InterleavedN>;
|
| 1088 |
+
using TensorRef = TensorRef<Element, Layout>;
|
| 1089 |
+
using ConstTensorRef = typename TensorRef::ConstTensorRef;
|
| 1090 |
+
|
| 1091 |
+
using Index = typename Layout::Index;
|
| 1092 |
+
using LongIndex = typename Layout::LongIndex;
|
| 1093 |
+
using TensorCoord = Tensor4DCoord;
|
| 1094 |
+
|
| 1095 |
+
static int const kElementsPerAccess = ThreadMap::kElementsPerAccess;
|
| 1096 |
+
static int const kThreads = ThreadMap::kThreads;
|
| 1097 |
+
static int const kIterations = ThreadMap::Iterations::kCount;
|
| 1098 |
+
|
| 1099 |
+
/// Fragment object
|
| 1100 |
+
using Fragment = Array<Element, ThreadMap::kElementsPerAccess>;
|
| 1101 |
+
|
| 1102 |
+
/// Memory access size
|
| 1103 |
+
using AccessType = AlignedArray<Element, ThreadMap::kElementsPerAccess>;
|
| 1104 |
+
|
| 1105 |
+
//
|
| 1106 |
+
// Parameters struct
|
| 1107 |
+
//
|
| 1108 |
+
|
| 1109 |
+
struct Params {
|
| 1110 |
+
|
| 1111 |
+
//
|
| 1112 |
+
// Data members
|
| 1113 |
+
//
|
| 1114 |
+
|
| 1115 |
+
LongIndex stride_col; ///< stride in bytes between columns
|
| 1116 |
+
LongIndex stride_row; ///< stride in bytes between rows
|
| 1117 |
+
|
| 1118 |
+
//
|
| 1119 |
+
// Methods
|
| 1120 |
+
//
|
| 1121 |
+
|
| 1122 |
+
CUTLASS_HOST_DEVICE
|
| 1123 |
+
Status initialize(typename Layout::Stride stride_) {
|
| 1124 |
+
stride_col = stride_[1];
|
| 1125 |
+
stride_row = stride_[2];
|
| 1126 |
+
|
| 1127 |
+
return Status::kSuccess;
|
| 1128 |
+
}
|
| 1129 |
+
|
| 1130 |
+
CUTLASS_HOST_DEVICE
|
| 1131 |
+
Params() {
|
| 1132 |
+
initialize(cutlass::make_Coord(0, 0, 0));
|
| 1133 |
+
}
|
| 1134 |
+
|
| 1135 |
+
CUTLASS_HOST_DEVICE
|
| 1136 |
+
Params(Layout const &layout) {
|
| 1137 |
+
|
| 1138 |
+
initialize(layout.stride());
|
| 1139 |
+
}
|
| 1140 |
+
|
| 1141 |
+
CUTLASS_HOST_DEVICE
|
| 1142 |
+
Params(Layout const &layout,
|
| 1143 |
+
// Not needed. Added to be compatible with strided conv epilogue.
|
| 1144 |
+
cutlass::Tensor4DCoord const &tensor_extent):
|
| 1145 |
+
Params(layout)
|
| 1146 |
+
{ }
|
| 1147 |
+
|
| 1148 |
+
};
|
| 1149 |
+
|
| 1150 |
+
/// Mask object
|
| 1151 |
+
struct Mask {
|
| 1152 |
+
static int const kCount =
|
| 1153 |
+
(ThreadMap::Iterations::kRow < 8) ? 8 : ThreadMap::Iterations::kRow;
|
| 1154 |
+
|
| 1155 |
+
/// Predicate state
|
| 1156 |
+
bool predicates[kCount];
|
| 1157 |
+
|
| 1158 |
+
//
|
| 1159 |
+
// Mask
|
| 1160 |
+
//
|
| 1161 |
+
CUTLASS_HOST_DEVICE
|
| 1162 |
+
Mask() {
|
| 1163 |
+
enable();
|
| 1164 |
+
}
|
| 1165 |
+
|
| 1166 |
+
///< Efficiently disables all accesses guarded by mask
|
| 1167 |
+
CUTLASS_HOST_DEVICE void clear() {
|
| 1168 |
+
CUTLASS_PRAGMA_UNROLL
|
| 1169 |
+
for (int i = 0; i < kCount; ++i) {
|
| 1170 |
+
predicates[i] = false;
|
| 1171 |
+
}
|
| 1172 |
+
}
|
| 1173 |
+
|
| 1174 |
+
///< CUTLASS_HOST_DEVICE enables all accesses guarded by mask
|
| 1175 |
+
CUTLASS_DEVICE void enable() {
|
| 1176 |
+
CUTLASS_PRAGMA_UNROLL
|
| 1177 |
+
for (int i = 0; i < kCount; ++i) {
|
| 1178 |
+
predicates[i] = true;
|
| 1179 |
+
}
|
| 1180 |
+
}
|
| 1181 |
+
};
|
| 1182 |
+
|
| 1183 |
+
private:
|
| 1184 |
+
|
| 1185 |
+
//
|
| 1186 |
+
// Data members
|
| 1187 |
+
//
|
| 1188 |
+
|
| 1189 |
+
/// Parameters structure containing reference and precomputed state.
|
| 1190 |
+
Params params_;
|
| 1191 |
+
|
| 1192 |
+
/// Byte-level pointer
|
| 1193 |
+
uint8_t *byte_pointer_;
|
| 1194 |
+
|
| 1195 |
+
/// Array of boolean values to contain steady-state predicates
|
| 1196 |
+
Mask mask_;
|
| 1197 |
+
|
| 1198 |
+
/// Extent of the matrix tile in columns
|
| 1199 |
+
Index extent_col_;
|
| 1200 |
+
|
| 1201 |
+
/// Extent of the matrix tile in rows
|
| 1202 |
+
Index extent_row_;
|
| 1203 |
+
|
| 1204 |
+
/// Extent of the matrix tile in pq
|
| 1205 |
+
Index extent_pq_;
|
| 1206 |
+
|
| 1207 |
+
/// A thread's starting row position (assuming steady-state predicates have
|
| 1208 |
+
/// been computed)
|
| 1209 |
+
Index thread_start_row_;
|
| 1210 |
+
|
| 1211 |
+
/// A thread's starting column position (assuming steady-state predicates have
|
| 1212 |
+
/// been computed)
|
| 1213 |
+
Index thread_start_col_;
|
| 1214 |
+
|
| 1215 |
+
/// Internal iteration counter
|
| 1216 |
+
LongIndex iteration_row_;
|
| 1217 |
+
LongIndex iteration_col_;
|
| 1218 |
+
|
| 1219 |
+
uint32_t pq_mul_;
|
| 1220 |
+
|
| 1221 |
+
uint32_t pq_shr_;
|
| 1222 |
+
|
| 1223 |
+
private:
|
| 1224 |
+
|
| 1225 |
+
//
|
| 1226 |
+
// Methods
|
| 1227 |
+
//
|
| 1228 |
+
|
| 1229 |
+
public:
|
| 1230 |
+
|
| 1231 |
+
//
|
| 1232 |
+
// Methods
|
| 1233 |
+
//
|
| 1234 |
+
|
| 1235 |
+
/// Constructor
|
| 1236 |
+
CUTLASS_DEVICE
|
| 1237 |
+
InterleavedConvPredicatedTileIterator(
|
| 1238 |
+
Params const & params,
|
| 1239 |
+
Element *pointer,
|
| 1240 |
+
TensorCoord extent,
|
| 1241 |
+
int thread_idx,
|
| 1242 |
+
MatrixCoord threadblock_offset
|
| 1243 |
+
):
|
| 1244 |
+
params_(params) {
|
| 1245 |
+
MatrixCoord thread_offset = ThreadMap::initial_offset(thread_idx) + threadblock_offset;
|
| 1246 |
+
|
| 1247 |
+
extent_col_ = extent.c();
|
| 1248 |
+
extent_pq_ = extent.h() * extent.w();
|
| 1249 |
+
extent_row_ = extent.n() * extent_pq_;
|
| 1250 |
+
|
| 1251 |
+
find_divisor(pq_mul_, pq_shr_, extent_pq_);
|
| 1252 |
+
|
| 1253 |
+
thread_start_row_ = thread_offset.row();
|
| 1254 |
+
thread_start_col_ = thread_offset.column();
|
| 1255 |
+
|
| 1256 |
+
// Initialize predicates
|
| 1257 |
+
CUTLASS_PRAGMA_UNROLL
|
| 1258 |
+
for (int r = 0; r < ThreadMap::Iterations::kRow; ++r) {
|
| 1259 |
+
mask_.predicates[r] =
|
| 1260 |
+
((thread_offset.row() + ThreadMap::Delta::kRow * r) < extent_row_);
|
| 1261 |
+
}
|
| 1262 |
+
|
| 1263 |
+
// Initialize pointer
|
| 1264 |
+
byte_pointer_ = reinterpret_cast<uint8_t *>(pointer) +
|
| 1265 |
+
((thread_start_col_ / InterleavedN) * params_.stride_col +
|
| 1266 |
+
(thread_start_col_ % InterleavedN)) *
|
| 1267 |
+
sizeof_bits<Element>::value / 8;
|
| 1268 |
+
|
| 1269 |
+
// Initialize internal state counter
|
| 1270 |
+
iteration_row_ = iteration_col_ = 0;
|
| 1271 |
+
}
|
| 1272 |
+
|
| 1273 |
+
/// Adds a pointer offset in units of Element
|
| 1274 |
+
CUTLASS_HOST_DEVICE
|
| 1275 |
+
void add_pointer_offset(LongIndex pointer_offset) {
|
| 1276 |
+
byte_pointer_ += pointer_offset * sizeof_bits<Element>::value / 8;
|
| 1277 |
+
}
|
| 1278 |
+
|
| 1279 |
+
/// Loads a fragment from memory
|
| 1280 |
+
CUTLASS_DEVICE
|
| 1281 |
+
void load(Fragment &frag) {
|
| 1282 |
+
|
| 1283 |
+
int col_offset = iteration_col_ * ThreadMap::Delta::kColumn;
|
| 1284 |
+
bool col_guard = ((thread_start_col_ + col_offset) < extent_col_);
|
| 1285 |
+
bool guard = col_guard && mask_.predicates[iteration_row_];
|
| 1286 |
+
|
| 1287 |
+
int n, pq_rem;
|
| 1288 |
+
|
| 1289 |
+
fast_divmod(n, pq_rem,
|
| 1290 |
+
thread_start_row_ + iteration_row_ * ThreadMap::Delta::kRow,
|
| 1291 |
+
extent_pq_, pq_mul_, pq_shr_);
|
| 1292 |
+
|
| 1293 |
+
uint8_t *byte_pointer =
|
| 1294 |
+
byte_pointer_ + (n * params_.stride_row + pq_rem * InterleavedN) *
|
| 1295 |
+
sizeof_bits<Element>::value / 8;
|
| 1296 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 1297 |
+
AccessType const *memory_pointer =
|
| 1298 |
+
reinterpret_cast<AccessType const *>(byte_pointer);
|
| 1299 |
+
|
| 1300 |
+
cutlass::arch::global_load<
|
| 1301 |
+
AccessType,
|
| 1302 |
+
sizeof(AccessType)
|
| 1303 |
+
>(
|
| 1304 |
+
*frag_ptr,
|
| 1305 |
+
(void *)memory_pointer,
|
| 1306 |
+
guard);
|
| 1307 |
+
}
|
| 1308 |
+
|
| 1309 |
+
/// Stores a fragment to memory
|
| 1310 |
+
CUTLASS_DEVICE
|
| 1311 |
+
void store(Fragment const &frag) {
|
| 1312 |
+
|
| 1313 |
+
int col_offset = iteration_col_ * ThreadMap::Delta::kColumn;
|
| 1314 |
+
bool col_guard = ((thread_start_col_ + col_offset) < extent_col_);
|
| 1315 |
+
bool guard = col_guard && mask_.predicates[iteration_row_];
|
| 1316 |
+
|
| 1317 |
+
int n, pq_rem;
|
| 1318 |
+
|
| 1319 |
+
fast_divmod(n, pq_rem,
|
| 1320 |
+
thread_start_row_ + iteration_row_ * ThreadMap::Delta::kRow,
|
| 1321 |
+
extent_pq_, pq_mul_, pq_shr_);
|
| 1322 |
+
|
| 1323 |
+
uint8_t *byte_pointer =
|
| 1324 |
+
byte_pointer_ + (n * params_.stride_row + pq_rem * InterleavedN) *
|
| 1325 |
+
sizeof_bits<Element>::value / 8;
|
| 1326 |
+
AccessType const *frag_ptr = reinterpret_cast<AccessType const *>(&frag);
|
| 1327 |
+
AccessType *memory_pointer = reinterpret_cast<AccessType *>(byte_pointer);
|
| 1328 |
+
|
| 1329 |
+
cutlass::arch::global_store<AccessType, sizeof(AccessType)>(
|
| 1330 |
+
*frag_ptr, (void *)memory_pointer, guard);
|
| 1331 |
+
}
|
| 1332 |
+
|
| 1333 |
+
/// Overrides the internal iteration index
|
| 1334 |
+
CUTLASS_HOST_DEVICE
|
| 1335 |
+
void set_iteration_index(int iteration) {
|
| 1336 |
+
iteration_row_ = iteration % ThreadMap::Iterations::kRow;
|
| 1337 |
+
iteration_col_ = iteration / ThreadMap::Iterations::kRow;
|
| 1338 |
+
}
|
| 1339 |
+
|
| 1340 |
+
/// Advances to the next position to load or store
|
| 1341 |
+
CUTLASS_HOST_DEVICE
|
| 1342 |
+
InterleavedConvPredicatedTileIterator &operator++() {
|
| 1343 |
+
|
| 1344 |
+
++iteration_row_;
|
| 1345 |
+
|
| 1346 |
+
if (iteration_row_ == ThreadMap::Iterations::kRow) {
|
| 1347 |
+
|
| 1348 |
+
iteration_row_ = 0;
|
| 1349 |
+
++iteration_col_;
|
| 1350 |
+
byte_pointer_ += params_.stride_col;
|
| 1351 |
+
|
| 1352 |
+
if (iteration_col_ == ThreadMap::Iterations::kColumn) {
|
| 1353 |
+
iteration_col_ = 0;
|
| 1354 |
+
}
|
| 1355 |
+
}
|
| 1356 |
+
|
| 1357 |
+
return *this;
|
| 1358 |
+
}
|
| 1359 |
+
|
| 1360 |
+
///< Efficiently disables all accesses guarded by mask
|
| 1361 |
+
CUTLASS_DEVICE void clear_mask() {
|
| 1362 |
+
mask_.clear();
|
| 1363 |
+
}
|
| 1364 |
+
|
| 1365 |
+
///< Efficiently enables all accesses guarded by mask
|
| 1366 |
+
CUTLASS_DEVICE void enable_mask() {
|
| 1367 |
+
mask_.enable();
|
| 1368 |
+
}
|
| 1369 |
+
|
| 1370 |
+
///< Sets the mask
|
| 1371 |
+
CUTLASS_DEVICE void get_mask(Mask &mask) {
|
| 1372 |
+
mask = mask_;
|
| 1373 |
+
}
|
| 1374 |
+
|
| 1375 |
+
///< Sets the mask
|
| 1376 |
+
CUTLASS_DEVICE void set_mask(Mask const &mask) {
|
| 1377 |
+
mask_ = mask;
|
| 1378 |
+
}
|
| 1379 |
+
};
|
| 1380 |
+
|
| 1381 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 1382 |
+
|
| 1383 |
+
} // namespace threadblock
|
| 1384 |
+
} // namespace epilogue
|
| 1385 |
+
} // namespace cutlass
|
| 1386 |
+
|
| 1387 |
+
////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_affine.h
ADDED
|
@@ -0,0 +1,615 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
|
| 33 |
+
\brief Epilogue for threadblock scoped GEMMs using Tensor Ops.
|
| 34 |
+
|
| 35 |
+
The epilogue rearranges the result of a matrix product through shared memory to match canonical
|
| 36 |
+
tensor layouts in global memory. Epilogues support conversion and reduction operations.
|
| 37 |
+
|
| 38 |
+
*/
|
| 39 |
+
|
| 40 |
+
#pragma once
|
| 41 |
+
|
| 42 |
+
#include "cutlass/cutlass.h"
|
| 43 |
+
#include "cutlass/numeric_types.h"
|
| 44 |
+
#include "cutlass/array.h"
|
| 45 |
+
#include "cutlass/layout/matrix.h"
|
| 46 |
+
#include "cutlass/layout/tensor.h"
|
| 47 |
+
#include "cutlass/matrix_shape.h"
|
| 48 |
+
#include "cutlass/tensor_ref.h"
|
| 49 |
+
#include "cutlass/transform/pitch_linear_thread_map.h"
|
| 50 |
+
#include "cutlass/epilogue/threadblock/output_tile_thread_map.h"
|
| 51 |
+
#include "cutlass/arch/arch.h"
|
| 52 |
+
#include "cutlass/arch/memory.h"
|
| 53 |
+
#include "cutlass/epilogue/threadblock/predicated_tile_iterator_params.h"
|
| 54 |
+
|
| 55 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 56 |
+
|
| 57 |
+
namespace cutlass {
|
| 58 |
+
|
| 59 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 60 |
+
|
| 61 |
+
namespace epilogue {
|
| 62 |
+
namespace threadblock {
|
| 63 |
+
|
| 64 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 65 |
+
|
| 66 |
+
/// Tile iterator used to load and store output tile from global memory in epilogue.
|
| 67 |
+
///
|
| 68 |
+
/// Satisfies: ReadableTileIterator | PredicatedTileIterator | ForwardTileIterator
|
| 69 |
+
///
|
| 70 |
+
/// It provides a fast path for the case Rank = 2 which does not need div/rem to
|
| 71 |
+
/// calculate modes.
|
| 72 |
+
|
| 73 |
+
template <
|
| 74 |
+
typename ThreadMap_, ///< Thread map (conept: OutputTileThreadMap)
|
| 75 |
+
typename Element_, ///< Element data type
|
| 76 |
+
int Rank
|
| 77 |
+
>
|
| 78 |
+
class PredicatedTileIteratorAffineRankN {
|
| 79 |
+
public:
|
| 80 |
+
using ThreadMap = ThreadMap_;
|
| 81 |
+
using Shape = typename ThreadMap::Shape;
|
| 82 |
+
|
| 83 |
+
using Element = Element_;
|
| 84 |
+
|
| 85 |
+
using Layout = layout::AffineRankN<Rank>;
|
| 86 |
+
using TensorRef = TensorRef<Element, Layout>;
|
| 87 |
+
using TensorView = TensorView<Element, Layout>;
|
| 88 |
+
using ConstTensorRef = typename TensorRef::ConstTensorRef;
|
| 89 |
+
|
| 90 |
+
using Index = typename Layout::Index;
|
| 91 |
+
using LongIndex = typename Layout::LongIndex;
|
| 92 |
+
using TensorCoord = typename Layout::TensorCoord;
|
| 93 |
+
|
| 94 |
+
static int const kElementsPerAccess = ThreadMap::kElementsPerAccess;
|
| 95 |
+
static int const kThreads = ThreadMap::kThreads;
|
| 96 |
+
static int const kIterations = ThreadMap::Count::kTile;
|
| 97 |
+
|
| 98 |
+
static_assert( ThreadMap::Iterations::kRow > 0,"ThreadMap::Iterations::kRow must be > 0");
|
| 99 |
+
static_assert( ThreadMap::Iterations::kGroup > 0,"ThreadMap::Iterations::kGroup must be > 0");
|
| 100 |
+
static_assert( ThreadMap::Iterations::kCluster > 0,"ThreadMap::Iterations::kCluster must be > 0");
|
| 101 |
+
static_assert( ThreadMap::Iterations::kColumn > 0,"ThreadMap::Iterations::kColumn must be > 0");
|
| 102 |
+
static_assert( !(Layout::kRank % 2),
|
| 103 |
+
"Layout rank must be even. This assumes the first half of the modes correspond to the 'row' "
|
| 104 |
+
"and the second half of the modes correspond to the 'column'");
|
| 105 |
+
|
| 106 |
+
static bool const kBigEndian = false;
|
| 107 |
+
|
| 108 |
+
/// Fragment object
|
| 109 |
+
using Fragment = Array<
|
| 110 |
+
Element,
|
| 111 |
+
ThreadMap::Iterations::kColumn *
|
| 112 |
+
ThreadMap::Iterations::kRow *
|
| 113 |
+
ThreadMap::Iterations::kGroup *
|
| 114 |
+
ThreadMap::Iterations::kCluster * ThreadMap::kElementsPerAccess>;
|
| 115 |
+
|
| 116 |
+
/// Memory access size
|
| 117 |
+
using AccessType = AlignedArray<Element, ThreadMap::kElementsPerAccess>;
|
| 118 |
+
|
| 119 |
+
//
|
| 120 |
+
// Parameters struct
|
| 121 |
+
//
|
| 122 |
+
|
| 123 |
+
/// Parameters structure
|
| 124 |
+
struct Params {
|
| 125 |
+
|
| 126 |
+
//
|
| 127 |
+
// Data members
|
| 128 |
+
//
|
| 129 |
+
|
| 130 |
+
Layout layout;
|
| 131 |
+
|
| 132 |
+
/// Stride in units of bytes along M modes
|
| 133 |
+
Coord<Layout::kRank/2, typename Layout::LongIndex> stride_m;
|
| 134 |
+
|
| 135 |
+
/// Stride in units of bytes along N modes
|
| 136 |
+
Coord<Layout::kRank/2, typename Layout::LongIndex> stride_n;
|
| 137 |
+
|
| 138 |
+
/// Fast divmod objects divided by tensor extents
|
| 139 |
+
FastDivmod divmod_m[(Layout::kRank == 2) ? 1 : (Layout::kRank/2 - 1)];
|
| 140 |
+
|
| 141 |
+
/// Fast divmod objects divided by tensor extents
|
| 142 |
+
FastDivmod divmod_n[(Layout::kRank == 2) ? 1 : (Layout::kRank/2 - 1)];
|
| 143 |
+
|
| 144 |
+
int64_t rank2_inc_col;
|
| 145 |
+
int64_t rank2_inc_row;
|
| 146 |
+
|
| 147 |
+
//
|
| 148 |
+
// Methods
|
| 149 |
+
//
|
| 150 |
+
CUTLASS_HOST_DEVICE
|
| 151 |
+
Params() { }
|
| 152 |
+
|
| 153 |
+
CUTLASS_HOST_DEVICE
|
| 154 |
+
Params(TensorCoord const &extent, Layout const &layout_): layout(layout_) {
|
| 155 |
+
|
| 156 |
+
CUTLASS_PRAGMA_UNROLL
|
| 157 |
+
for (int i = 0; i < Layout::kRank / 2; ++i) {
|
| 158 |
+
stride_m[i] = OffsetBytes<Element>(layout_.stride()[i]);
|
| 159 |
+
stride_n[i] = OffsetBytes<Element>(layout_.stride()[i + Layout::kRank / 2]);
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
if (kBigEndian) {
|
| 163 |
+
// "Big Endian" scheme
|
| 164 |
+
CUTLASS_PRAGMA_UNROLL
|
| 165 |
+
for (int i = 0; i < Layout::kRank / 2 - 1; ++i) {
|
| 166 |
+
divmod_m[i] = FastDivmod(extent[i + 1]);
|
| 167 |
+
divmod_n[i] = FastDivmod(extent[i + Layout::kRank / 2 + 1]);
|
| 168 |
+
}
|
| 169 |
+
}
|
| 170 |
+
else {
|
| 171 |
+
// "Little Endian" scheme
|
| 172 |
+
CUTLASS_PRAGMA_UNROLL
|
| 173 |
+
for (int i = 0; i < Layout::kRank / 2 - 1; ++i) {
|
| 174 |
+
divmod_m[i] = FastDivmod(extent[i]);
|
| 175 |
+
divmod_n[i] = FastDivmod(extent[i + Layout::kRank / 2]);
|
| 176 |
+
}
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
#if 0
|
| 180 |
+
//
|
| 181 |
+
// Debug print statements to verify extents and strides are passed correctly.
|
| 182 |
+
//
|
| 183 |
+
printf("PredicatedTileIteratorAffine::Params() entered\n");
|
| 184 |
+
|
| 185 |
+
CUTLASS_PRAGMA_UNROLL
|
| 186 |
+
for (int i = 0; i < Layout::kRank; ++i) {
|
| 187 |
+
printf(" extent[%d]: %d\n", i, extent[i]);
|
| 188 |
+
}
|
| 189 |
+
for (int i = 0; i < Layout::kRank; ++i) {
|
| 190 |
+
printf(" stride[%d]: %ld\n", i, layout_.stride()[i]);
|
| 191 |
+
}
|
| 192 |
+
printf("PredicatedTileIteratorAffine::Params() returning\n");
|
| 193 |
+
#endif
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
CUTLASS_HOST_DEVICE
|
| 197 |
+
Params(Layout const &layout_): layout(layout_) {
|
| 198 |
+
|
| 199 |
+
CUTLASS_PRAGMA_UNROLL
|
| 200 |
+
for (int i = 0; i < Layout::kRank / 2; ++i) {
|
| 201 |
+
stride_m[i] = OffsetBytes<Element>(layout_.stride()[i]);
|
| 202 |
+
stride_n[i] = OffsetBytes<Element>(layout_.stride()[i + Layout::kRank / 2]);
|
| 203 |
+
}
|
| 204 |
+
|
| 205 |
+
rank2_inc_col = ThreadMap::Delta::kColumn * stride_n[0];
|
| 206 |
+
rank2_inc_row = ThreadMap::Delta::kRow * stride_m[0];
|
| 207 |
+
}
|
| 208 |
+
};
|
| 209 |
+
|
| 210 |
+
/// Mask object
|
| 211 |
+
struct Mask {
|
| 212 |
+
|
| 213 |
+
static int const kCount = ThreadMap::Iterations::kColumn;
|
| 214 |
+
|
| 215 |
+
/// Predicate state
|
| 216 |
+
bool predicates[kCount];
|
| 217 |
+
|
| 218 |
+
//
|
| 219 |
+
// Mask
|
| 220 |
+
//
|
| 221 |
+
CUTLASS_HOST_DEVICE
|
| 222 |
+
Mask() {
|
| 223 |
+
enable();
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
///< Efficiently disables all accesses guarded by mask
|
| 227 |
+
CUTLASS_HOST_DEVICE void clear() {
|
| 228 |
+
CUTLASS_PRAGMA_UNROLL
|
| 229 |
+
for (int i = 0; i < kCount; ++i) {
|
| 230 |
+
predicates[i] = false;
|
| 231 |
+
}
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
///< CUTLASS_HOST_DEVICE enables all accesses guarded by mask
|
| 235 |
+
CUTLASS_DEVICE void enable() {
|
| 236 |
+
CUTLASS_PRAGMA_UNROLL
|
| 237 |
+
for (int i = 0; i < kCount; ++i) {
|
| 238 |
+
predicates[i] = true;
|
| 239 |
+
}
|
| 240 |
+
}
|
| 241 |
+
};
|
| 242 |
+
|
| 243 |
+
private:
|
| 244 |
+
|
| 245 |
+
//
|
| 246 |
+
// Data members
|
| 247 |
+
//
|
| 248 |
+
|
| 249 |
+
/// Parameters structure containing reference and precomputed state.
|
| 250 |
+
Params params_;
|
| 251 |
+
|
| 252 |
+
/// Byte-level pointer
|
| 253 |
+
uint8_t *byte_pointer_;
|
| 254 |
+
|
| 255 |
+
/// Array of boolean values to contain steady-state predicates
|
| 256 |
+
Mask mask_;
|
| 257 |
+
|
| 258 |
+
/// Extent of the matrix tile in rows
|
| 259 |
+
Index extent_row_;
|
| 260 |
+
|
| 261 |
+
/// Extent of the matrix tile in columns
|
| 262 |
+
Index extent_col_;
|
| 263 |
+
|
| 264 |
+
/// A thread's starting row position (assuming steady-state predicates have been computed)
|
| 265 |
+
Index thread_start_row_;
|
| 266 |
+
|
| 267 |
+
/// A thread's starting column position (assuming steady-state predicates have been computed)
|
| 268 |
+
Index thread_start_column_;
|
| 269 |
+
|
| 270 |
+
/// Internal state counter
|
| 271 |
+
int state_[3];
|
| 272 |
+
|
| 273 |
+
/// Offsets in columns, cached for performance
|
| 274 |
+
int64_t offset_modes_n_[ThreadMap::Iterations::kColumn];
|
| 275 |
+
|
| 276 |
+
//
|
| 277 |
+
// Static asserts about internal strides
|
| 278 |
+
//
|
| 279 |
+
|
| 280 |
+
static_assert(sizeof(extent_row_) == 4, "Expected 32b extents");
|
| 281 |
+
static_assert(sizeof(thread_start_row_) == 4, "Expected 32b extents");
|
| 282 |
+
|
| 283 |
+
private:
|
| 284 |
+
|
| 285 |
+
//
|
| 286 |
+
// Methods
|
| 287 |
+
//
|
| 288 |
+
|
| 289 |
+
public:
|
| 290 |
+
|
| 291 |
+
//
|
| 292 |
+
// Methods
|
| 293 |
+
//
|
| 294 |
+
|
| 295 |
+
/// Constructor
|
| 296 |
+
CUTLASS_DEVICE
|
| 297 |
+
PredicatedTileIteratorAffineRankN(
|
| 298 |
+
Params const & params,
|
| 299 |
+
Element *pointer,
|
| 300 |
+
MatrixCoord extent,
|
| 301 |
+
int thread_idx,
|
| 302 |
+
MatrixCoord threadblock_offset = MatrixCoord(),
|
| 303 |
+
int const *indices = nullptr ///< gather/scatter indices, note no support for gather/scatter at this specialization
|
| 304 |
+
):
|
| 305 |
+
params_(params)
|
| 306 |
+
{
|
| 307 |
+
|
| 308 |
+
MatrixCoord thread_offset = ThreadMap::initial_offset(thread_idx) + threadblock_offset;
|
| 309 |
+
|
| 310 |
+
extent_row_ = extent.row();
|
| 311 |
+
extent_col_ = extent.column();
|
| 312 |
+
|
| 313 |
+
thread_start_row_ = thread_offset.row();
|
| 314 |
+
thread_start_column_ = thread_offset.column();
|
| 315 |
+
|
| 316 |
+
if (Layout::kRank > 2) {
|
| 317 |
+
// Initialize predicates
|
| 318 |
+
CUTLASS_PRAGMA_UNROLL
|
| 319 |
+
for (int c = 0; c < ThreadMap::Iterations::kColumn; ++c) {
|
| 320 |
+
|
| 321 |
+
//
|
| 322 |
+
// Compute coordinate and decompose into N modes
|
| 323 |
+
//
|
| 324 |
+
|
| 325 |
+
int coord_n = thread_start_column_ + c * ThreadMap::Delta::kColumn;
|
| 326 |
+
|
| 327 |
+
mask_.predicates[c] = coord_n < extent.column();
|
| 328 |
+
|
| 329 |
+
Coord<Layout::kRank / 2, Index> modes_n;
|
| 330 |
+
|
| 331 |
+
int64_t offset_modes_n = 0;
|
| 332 |
+
|
| 333 |
+
if (kBigEndian) {
|
| 334 |
+
modes_n = CoordinateDecomposition<Layout::kRank / 2>(coord_n, params_.divmod_n);
|
| 335 |
+
|
| 336 |
+
offset_modes_n = dot(modes_n, params_.stride_n);
|
| 337 |
+
}
|
| 338 |
+
else {
|
| 339 |
+
modes_n = CoordinateDecompositionLittleEndian<Layout::kRank / 2>(coord_n, params_.divmod_n);
|
| 340 |
+
|
| 341 |
+
offset_modes_n = dot(modes_n, params_.stride_n);
|
| 342 |
+
}
|
| 343 |
+
|
| 344 |
+
offset_modes_n_[c] = offset_modes_n;
|
| 345 |
+
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
if (!pointer) {
|
| 349 |
+
mask_.clear();
|
| 350 |
+
}
|
| 351 |
+
}
|
| 352 |
+
|
| 353 |
+
// Initialize pointer
|
| 354 |
+
byte_pointer_ = reinterpret_cast<uint8_t *>(pointer);
|
| 355 |
+
|
| 356 |
+
// Initialize internal state counter
|
| 357 |
+
state_[0] = state_[1] = state_[2] = 0;
|
| 358 |
+
}
|
| 359 |
+
|
| 360 |
+
/// Adds a pointer offset in units of Element
|
| 361 |
+
CUTLASS_HOST_DEVICE
|
| 362 |
+
void add_pointer_offset(LongIndex pointer_offset) {
|
| 363 |
+
byte_pointer_ += pointer_offset * sizeof_bits<Element>::value / 8;
|
| 364 |
+
}
|
| 365 |
+
|
| 366 |
+
/// Loads a fragment from memory
|
| 367 |
+
CUTLASS_DEVICE
|
| 368 |
+
void load_with_byte_offset(Fragment &frag, int64_t byte_offset) {
|
| 369 |
+
uint8_t const *byte_pointer = byte_pointer_;
|
| 370 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 371 |
+
|
| 372 |
+
CUTLASS_PRAGMA_UNROLL
|
| 373 |
+
for (int cluster = 0; cluster < ThreadMap::Iterations::kCluster; ++cluster) {
|
| 374 |
+
|
| 375 |
+
CUTLASS_PRAGMA_UNROLL
|
| 376 |
+
for (int group = 0; group < ThreadMap::Iterations::kGroup; ++group) {
|
| 377 |
+
|
| 378 |
+
int row_begin = thread_start_row_ + group * ThreadMap::Delta::kGroup + cluster * ThreadMap::Delta::kCluster;
|
| 379 |
+
int64_t offset_modes_m = row_begin * params_.stride_m[0];
|
| 380 |
+
|
| 381 |
+
CUTLASS_PRAGMA_UNROLL
|
| 382 |
+
for (int row = 0; row < ThreadMap::Iterations::kRow; ++row) {
|
| 383 |
+
|
| 384 |
+
int frag_row_idx =
|
| 385 |
+
(row + ThreadMap::Iterations::kRow * (group + ThreadMap::Iterations::kGroup * cluster));
|
| 386 |
+
|
| 387 |
+
//
|
| 388 |
+
// Compute coordinate and decompose into M modes
|
| 389 |
+
//
|
| 390 |
+
|
| 391 |
+
int coord_m = row * ThreadMap::Delta::kRow + row_begin;
|
| 392 |
+
|
| 393 |
+
Coord<Layout::kRank / 2, Index> modes_m;
|
| 394 |
+
|
| 395 |
+
if (Layout::kRank > 2) {
|
| 396 |
+
if (kBigEndian) {
|
| 397 |
+
modes_m = CoordinateDecomposition<Layout::kRank / 2>(coord_m, params_.divmod_m);
|
| 398 |
+
} else {
|
| 399 |
+
modes_m = CoordinateDecompositionLittleEndian<Layout::kRank / 2>(coord_m, params_.divmod_m);
|
| 400 |
+
}
|
| 401 |
+
|
| 402 |
+
offset_modes_m = dot(modes_m, params_.stride_m);
|
| 403 |
+
}
|
| 404 |
+
|
| 405 |
+
//
|
| 406 |
+
// Compute the offset due to modes M
|
| 407 |
+
//
|
| 408 |
+
|
| 409 |
+
bool row_guard = (coord_m < extent_row_);
|
| 410 |
+
int64_t offset_modes_n = thread_start_column_ * params_.stride_n[0];
|
| 411 |
+
|
| 412 |
+
CUTLASS_PRAGMA_UNROLL
|
| 413 |
+
for (int column = 0; column < ThreadMap::Iterations::kColumn; ++column) {
|
| 414 |
+
|
| 415 |
+
//
|
| 416 |
+
// Compute coordinate and decompose into N modes
|
| 417 |
+
//
|
| 418 |
+
|
| 419 |
+
if (Layout::kRank > 2) {
|
| 420 |
+
offset_modes_n = offset_modes_n_[column];
|
| 421 |
+
}
|
| 422 |
+
|
| 423 |
+
//
|
| 424 |
+
// Compute the pointer and access
|
| 425 |
+
//
|
| 426 |
+
bool guard;
|
| 427 |
+
|
| 428 |
+
if (Layout::kRank > 2) {
|
| 429 |
+
guard = row_guard && mask_.predicates[column];
|
| 430 |
+
} else {
|
| 431 |
+
guard = (coord_m < extent_row_) &&
|
| 432 |
+
((thread_start_column_ + ThreadMap::Delta::kColumn * column) < extent_col_);
|
| 433 |
+
}
|
| 434 |
+
|
| 435 |
+
cutlass::arch::global_load<
|
| 436 |
+
AccessType,
|
| 437 |
+
sizeof(AccessType)
|
| 438 |
+
>(
|
| 439 |
+
frag_ptr[frag_row_idx * ThreadMap::Iterations::kColumn + column],
|
| 440 |
+
(void *)(byte_pointer + offset_modes_m + offset_modes_n + byte_offset),
|
| 441 |
+
guard
|
| 442 |
+
);
|
| 443 |
+
|
| 444 |
+
if (Layout::kRank == 2) {
|
| 445 |
+
offset_modes_n += params_.rank2_inc_col;
|
| 446 |
+
}
|
| 447 |
+
}
|
| 448 |
+
|
| 449 |
+
if (Layout::kRank == 2) {
|
| 450 |
+
offset_modes_m += params_.rank2_inc_row;
|
| 451 |
+
}
|
| 452 |
+
}
|
| 453 |
+
}
|
| 454 |
+
}
|
| 455 |
+
}
|
| 456 |
+
|
| 457 |
+
/// Loads a fragment from memory
|
| 458 |
+
CUTLASS_DEVICE
|
| 459 |
+
void load(Fragment &frag) {
|
| 460 |
+
|
| 461 |
+
load_with_byte_offset(frag, 0);
|
| 462 |
+
}
|
| 463 |
+
|
| 464 |
+
/// Stores a fragment to memory
|
| 465 |
+
CUTLASS_DEVICE
|
| 466 |
+
void store_with_byte_offset(Fragment const &frag, int64_t byte_offset) {
|
| 467 |
+
uint8_t *byte_pointer = byte_pointer_;
|
| 468 |
+
AccessType const *frag_ptr = reinterpret_cast<AccessType const *>(&frag);
|
| 469 |
+
|
| 470 |
+
CUTLASS_PRAGMA_UNROLL
|
| 471 |
+
for (int cluster = 0; cluster < ThreadMap::Iterations::kCluster; ++cluster) {
|
| 472 |
+
|
| 473 |
+
CUTLASS_PRAGMA_UNROLL
|
| 474 |
+
for (int group = 0; group < ThreadMap::Iterations::kGroup; ++group) {
|
| 475 |
+
|
| 476 |
+
int row_begin = thread_start_row_ + group * ThreadMap::Delta::kGroup + cluster * ThreadMap::Delta::kCluster;
|
| 477 |
+
int64_t offset_modes_m = row_begin * params_.stride_m[0];
|
| 478 |
+
|
| 479 |
+
CUTLASS_PRAGMA_UNROLL
|
| 480 |
+
for (int row = 0; row < ThreadMap::Iterations::kRow; ++row) {
|
| 481 |
+
|
| 482 |
+
int frag_row_idx =
|
| 483 |
+
(row + ThreadMap::Iterations::kRow * (group + ThreadMap::Iterations::kGroup * cluster));
|
| 484 |
+
|
| 485 |
+
//
|
| 486 |
+
// Compute coordinate and decompose into M modes
|
| 487 |
+
//
|
| 488 |
+
|
| 489 |
+
int coord_m = row * ThreadMap::Delta::kRow + row_begin;
|
| 490 |
+
|
| 491 |
+
Coord<Layout::kRank / 2, Index> modes_m;
|
| 492 |
+
|
| 493 |
+
if (Layout::kRank > 2) {
|
| 494 |
+
if (kBigEndian) {
|
| 495 |
+
modes_m = CoordinateDecomposition<Layout::kRank / 2>(coord_m, params_.divmod_m);
|
| 496 |
+
} else {
|
| 497 |
+
modes_m = CoordinateDecompositionLittleEndian<Layout::kRank / 2>(coord_m, params_.divmod_m);
|
| 498 |
+
}
|
| 499 |
+
|
| 500 |
+
offset_modes_m = dot(modes_m, params_.stride_m);
|
| 501 |
+
}
|
| 502 |
+
|
| 503 |
+
//
|
| 504 |
+
// Compute the offset due to modes M
|
| 505 |
+
//
|
| 506 |
+
|
| 507 |
+
bool row_guard = (coord_m < extent_row_);
|
| 508 |
+
int64_t offset_modes_n = thread_start_column_ * params_.stride_n[0];
|
| 509 |
+
|
| 510 |
+
CUTLASS_PRAGMA_UNROLL
|
| 511 |
+
for (int column = 0; column < ThreadMap::Iterations::kColumn; ++column) {
|
| 512 |
+
|
| 513 |
+
//
|
| 514 |
+
// Compute coordinate and decompose into N modes
|
| 515 |
+
//
|
| 516 |
+
|
| 517 |
+
if (Layout::kRank > 2) {
|
| 518 |
+
offset_modes_n = offset_modes_n_[column];
|
| 519 |
+
}
|
| 520 |
+
|
| 521 |
+
//
|
| 522 |
+
// Compute the pointer and access
|
| 523 |
+
//
|
| 524 |
+
bool guard;
|
| 525 |
+
if (Layout::kRank > 2) {
|
| 526 |
+
guard = row_guard && mask_.predicates[column];
|
| 527 |
+
} else {
|
| 528 |
+
guard = (coord_m < extent_row_) && ((thread_start_column_ + ThreadMap::Delta::kColumn * column) < extent_col_);
|
| 529 |
+
}
|
| 530 |
+
|
| 531 |
+
cutlass::arch::global_store<AccessType, sizeof(AccessType)>(
|
| 532 |
+
frag_ptr[frag_row_idx * ThreadMap::Iterations::kColumn + column],
|
| 533 |
+
(void *)(byte_pointer + offset_modes_m + offset_modes_n + byte_offset),
|
| 534 |
+
guard);
|
| 535 |
+
|
| 536 |
+
if (Layout::kRank == 2) {
|
| 537 |
+
offset_modes_n += params_.rank2_inc_col;
|
| 538 |
+
}
|
| 539 |
+
}
|
| 540 |
+
|
| 541 |
+
if (Layout::kRank == 2) {
|
| 542 |
+
offset_modes_m += params_.rank2_inc_row;
|
| 543 |
+
}
|
| 544 |
+
}
|
| 545 |
+
}
|
| 546 |
+
}
|
| 547 |
+
}
|
| 548 |
+
|
| 549 |
+
/// Stores a fragment to memory
|
| 550 |
+
CUTLASS_DEVICE
|
| 551 |
+
void store(Fragment const &frag) {
|
| 552 |
+
|
| 553 |
+
store_with_byte_offset(frag, 0);
|
| 554 |
+
}
|
| 555 |
+
|
| 556 |
+
/// Advances to the next position to load or store
|
| 557 |
+
CUTLASS_HOST_DEVICE
|
| 558 |
+
PredicatedTileIteratorAffineRankN &operator++() {
|
| 559 |
+
|
| 560 |
+
++state_[0];
|
| 561 |
+
thread_start_row_ += ThreadMap::Shape::kRow;
|
| 562 |
+
|
| 563 |
+
if (state_[0] == ThreadMap::Count::kRow) {
|
| 564 |
+
|
| 565 |
+
state_[0] = 0;
|
| 566 |
+
++state_[1];
|
| 567 |
+
|
| 568 |
+
thread_start_row_ += (ThreadMap::Shape::kGroup - 1) *
|
| 569 |
+
ThreadMap::Shape::kRow * ThreadMap::Count::kRow;
|
| 570 |
+
|
| 571 |
+
if (state_[1] == ThreadMap::Count::kGroup) {
|
| 572 |
+
|
| 573 |
+
state_[1] = 0;
|
| 574 |
+
++state_[2];
|
| 575 |
+
|
| 576 |
+
thread_start_row_ += ThreadMap::Count::kGroup *
|
| 577 |
+
ThreadMap::Shape::kGroup * ThreadMap::Count::kRow * ThreadMap::Shape::kRow;
|
| 578 |
+
|
| 579 |
+
if (state_[2] == ThreadMap::Count::kCluster) {
|
| 580 |
+
state_[2] = 0;
|
| 581 |
+
}
|
| 582 |
+
}
|
| 583 |
+
}
|
| 584 |
+
|
| 585 |
+
return *this;
|
| 586 |
+
}
|
| 587 |
+
|
| 588 |
+
///< Efficiently disables all accesses guarded by mask
|
| 589 |
+
CUTLASS_DEVICE void clear_mask() {
|
| 590 |
+
mask_.clear();
|
| 591 |
+
}
|
| 592 |
+
|
| 593 |
+
///< Efficiently enables all accesses guarded by mask
|
| 594 |
+
CUTLASS_DEVICE void enable_mask() {
|
| 595 |
+
mask_.enable();
|
| 596 |
+
}
|
| 597 |
+
|
| 598 |
+
///< Sets the mask
|
| 599 |
+
CUTLASS_DEVICE void get_mask(Mask &mask) {
|
| 600 |
+
mask = mask_;
|
| 601 |
+
}
|
| 602 |
+
|
| 603 |
+
///< Sets the mask
|
| 604 |
+
CUTLASS_DEVICE void set_mask(Mask const &mask) {
|
| 605 |
+
mask_ = mask;
|
| 606 |
+
}
|
| 607 |
+
};
|
| 608 |
+
|
| 609 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 610 |
+
|
| 611 |
+
} // namespace threadblock
|
| 612 |
+
} // namespace epilogue
|
| 613 |
+
} // namespace cutlass
|
| 614 |
+
|
| 615 |
+
////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_affine_layout_params.h
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief
|
| 33 |
+
*/
|
| 34 |
+
|
| 35 |
+
#pragma once
|
| 36 |
+
|
| 37 |
+
#include "cutlass/cutlass.h"
|
| 38 |
+
#include "cutlass/layout/matrix.h"
|
| 39 |
+
#include "cutlass/fast_math.h"
|
| 40 |
+
|
| 41 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 42 |
+
|
| 43 |
+
namespace cutlass {
|
| 44 |
+
namespace epilogue {
|
| 45 |
+
namespace threadblock {
|
| 46 |
+
|
| 47 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 48 |
+
|
| 49 |
+
template <
|
| 50 |
+
int Rank
|
| 51 |
+
>
|
| 52 |
+
struct PredicatedTileIteratorAffineLayoutRankNParams {
|
| 53 |
+
using Layout = layout::AffineRankN<Rank>;
|
| 54 |
+
using TensorCoord = typename Layout::TensorCoord;
|
| 55 |
+
|
| 56 |
+
static bool const kBigEndian = false;
|
| 57 |
+
|
| 58 |
+
//
|
| 59 |
+
// Data members
|
| 60 |
+
//
|
| 61 |
+
|
| 62 |
+
Layout layout;
|
| 63 |
+
|
| 64 |
+
/// Stride in units of bytes along M modes
|
| 65 |
+
Coord<Layout::kRank/2, typename Layout::LongIndex> stride_m;
|
| 66 |
+
|
| 67 |
+
/// Stride in units of bytes along N modes
|
| 68 |
+
Coord<Layout::kRank/2, typename Layout::LongIndex> stride_n;
|
| 69 |
+
|
| 70 |
+
/// Fast divmod objects divided by tensor extents
|
| 71 |
+
FastDivmod divmod_m[(Layout::kRank == 2) ? 1 : (Layout::kRank/2 - 1)];
|
| 72 |
+
|
| 73 |
+
/// Fast divmod objects divided by tensor extents
|
| 74 |
+
FastDivmod divmod_n[(Layout::kRank == 2) ? 1 : (Layout::kRank/2 - 1)];
|
| 75 |
+
|
| 76 |
+
int64_t rank2_inc_col;
|
| 77 |
+
int64_t rank2_inc_row;
|
| 78 |
+
|
| 79 |
+
//
|
| 80 |
+
// Methods
|
| 81 |
+
//
|
| 82 |
+
CUTLASS_HOST_DEVICE
|
| 83 |
+
PredicatedTileIteratorAffineLayoutRankNParams() { }
|
| 84 |
+
|
| 85 |
+
CUTLASS_HOST_DEVICE
|
| 86 |
+
PredicatedTileIteratorAffineLayoutRankNParams(TensorCoord const &extent,
|
| 87 |
+
Layout const &layout_,
|
| 88 |
+
int64_t element_sizeof_bits)
|
| 89 |
+
: layout(layout_)
|
| 90 |
+
{
|
| 91 |
+
|
| 92 |
+
CUTLASS_PRAGMA_UNROLL
|
| 93 |
+
for (int i = 0; i < Layout::kRank / 2; ++i) {
|
| 94 |
+
stride_m[i] = OffsetBytes(layout_.stride()[i], element_sizeof_bits);
|
| 95 |
+
stride_n[i] = OffsetBytes(layout_.stride()[i + Layout::kRank / 2], element_sizeof_bits);
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
if (kBigEndian) {
|
| 99 |
+
// "Big Endian" scheme
|
| 100 |
+
CUTLASS_PRAGMA_UNROLL
|
| 101 |
+
for (int i = 0; i < Layout::kRank / 2 - 1; ++i) {
|
| 102 |
+
divmod_m[i] = FastDivmod(extent[i + 1]);
|
| 103 |
+
divmod_n[i] = FastDivmod(extent[i + Layout::kRank / 2 + 1]);
|
| 104 |
+
}
|
| 105 |
+
}
|
| 106 |
+
else {
|
| 107 |
+
// "Little Endian" scheme
|
| 108 |
+
CUTLASS_PRAGMA_UNROLL
|
| 109 |
+
for (int i = 0; i < Layout::kRank / 2 - 1; ++i) {
|
| 110 |
+
divmod_m[i] = FastDivmod(extent[i]);
|
| 111 |
+
divmod_n[i] = FastDivmod(extent[i + Layout::kRank / 2]);
|
| 112 |
+
}
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
#if 0
|
| 116 |
+
//
|
| 117 |
+
// Debug print statements to verify extents and strides are passed correctly.
|
| 118 |
+
//
|
| 119 |
+
printf("PredicatedTileIteratorAffine::Params() entered\n");
|
| 120 |
+
|
| 121 |
+
CUTLASS_PRAGMA_UNROLL
|
| 122 |
+
for (int i = 0; i < Layout::kRank; ++i) {
|
| 123 |
+
printf(" extent[%d]: %d\n", i, extent[i]);
|
| 124 |
+
}
|
| 125 |
+
for (int i = 0; i < Layout::kRank; ++i) {
|
| 126 |
+
printf(" stride[%d]: %ld\n", i, layout_.stride()[i]);
|
| 127 |
+
}
|
| 128 |
+
printf("PredicatedTileIteratorAffine::Params() returning\n");
|
| 129 |
+
#endif
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
CUTLASS_HOST_DEVICE
|
| 133 |
+
PredicatedTileIteratorAffineLayoutRankNParams(Layout const &layout_,
|
| 134 |
+
int32_t threadmap_delta_kColumn,
|
| 135 |
+
int32_t threadmap_delta_kRow,
|
| 136 |
+
int64_t element_sizeof_bits)
|
| 137 |
+
: layout(layout_)
|
| 138 |
+
{
|
| 139 |
+
|
| 140 |
+
CUTLASS_PRAGMA_UNROLL
|
| 141 |
+
for (int i = 0; i < Layout::kRank / 2; ++i) {
|
| 142 |
+
stride_m[i] = OffsetBytes(layout_.stride()[i], element_sizeof_bits);
|
| 143 |
+
stride_n[i] = OffsetBytes(layout_.stride()[i + Layout::kRank / 2], element_sizeof_bits);
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
rank2_inc_col = threadmap_delta_kColumn * stride_n[0];
|
| 147 |
+
rank2_inc_row = threadmap_delta_kRow * stride_m[0];
|
| 148 |
+
}
|
| 149 |
+
};
|
| 150 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 151 |
+
|
| 152 |
+
} // namespace threadblock
|
| 153 |
+
} // namespace epilogue
|
| 154 |
+
} // namespace cutlass
|
| 155 |
+
|
| 156 |
+
////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_blas3.h
ADDED
|
@@ -0,0 +1,633 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief Epilogue for threadblock scoped GEMMs using Tensor Ops.
|
| 33 |
+
|
| 34 |
+
The epilogue rearranges the result of a matrix product through shared memory to match canonical
|
| 35 |
+
tensor layouts in global memory. Epilogues support conversion and reduction operations.
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
*/
|
| 39 |
+
|
| 40 |
+
#pragma once
|
| 41 |
+
|
| 42 |
+
#include "cutlass/cutlass.h"
|
| 43 |
+
#include "cutlass/numeric_types.h"
|
| 44 |
+
#include "cutlass/array.h"
|
| 45 |
+
#include "cutlass/layout/matrix.h"
|
| 46 |
+
#include "cutlass/layout/tensor.h"
|
| 47 |
+
#include "cutlass/matrix_shape.h"
|
| 48 |
+
#include "cutlass/tensor_ref.h"
|
| 49 |
+
#include "cutlass/transform/pitch_linear_thread_map.h"
|
| 50 |
+
#include "cutlass/epilogue/threadblock/output_tile_thread_map.h"
|
| 51 |
+
#include "cutlass/arch/arch.h"
|
| 52 |
+
#include "cutlass/arch/memory.h"
|
| 53 |
+
#include "cutlass/epilogue/threadblock/predicated_tile_iterator_params.h"
|
| 54 |
+
|
| 55 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 56 |
+
|
| 57 |
+
namespace cutlass {
|
| 58 |
+
|
| 59 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 60 |
+
|
| 61 |
+
namespace epilogue {
|
| 62 |
+
namespace threadblock {
|
| 63 |
+
|
| 64 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 65 |
+
|
| 66 |
+
/// Tile iterator used to load and store output tile from global memory in epilogue.
|
| 67 |
+
///
|
| 68 |
+
/// Satisfies: ReadableTileIterator | PredicatedTileIterator | ForwardTileIterator
|
| 69 |
+
///
|
| 70 |
+
template <
|
| 71 |
+
typename ThreadMap_, ///< Thread map (conept: OutputTileThreadMap)
|
| 72 |
+
typename Element_, ///< Element data type
|
| 73 |
+
BlasMode BlasMode_ = BlasMode::kGemm ///< Tile Iterator for a Symmetric or Hermitian Kernel
|
| 74 |
+
>
|
| 75 |
+
class PredicatedTileIteratorBlas3 {
|
| 76 |
+
public:
|
| 77 |
+
using ThreadMap = ThreadMap_;
|
| 78 |
+
using Shape = typename ThreadMap::Shape;
|
| 79 |
+
|
| 80 |
+
using Element = Element_;
|
| 81 |
+
|
| 82 |
+
using Layout = layout::RowMajor;
|
| 83 |
+
using TensorRef = TensorRef<Element, Layout>;
|
| 84 |
+
using ConstTensorRef = typename TensorRef::ConstTensorRef;
|
| 85 |
+
|
| 86 |
+
using Index = typename Layout::Index;
|
| 87 |
+
using LongIndex = typename Layout::LongIndex;
|
| 88 |
+
using TensorCoord = MatrixCoord;
|
| 89 |
+
|
| 90 |
+
static BlasMode const kBlasMode = BlasMode_;
|
| 91 |
+
|
| 92 |
+
static int const kElementsPerAccess = ThreadMap::kElementsPerAccess;
|
| 93 |
+
static int const kThreads = ThreadMap::kThreads;
|
| 94 |
+
static int const kIterations = ThreadMap::Count::kTile;
|
| 95 |
+
|
| 96 |
+
static_assert( ThreadMap::Iterations::kRow > 0,"ThreadMap::Iterations::kRow must be > 0");
|
| 97 |
+
static_assert( ThreadMap::Iterations::kGroup > 0,"ThreadMap::Iterations::kGroup must be > 0");
|
| 98 |
+
static_assert( ThreadMap::Iterations::kCluster > 0,"ThreadMap::Iterations::kCluster must be > 0");
|
| 99 |
+
static_assert( ThreadMap::Iterations::kColumn > 0,"ThreadMap::Iterations::kColumn must be > 0");
|
| 100 |
+
|
| 101 |
+
/// Fragment object
|
| 102 |
+
using Fragment = Array<
|
| 103 |
+
Element,
|
| 104 |
+
ThreadMap::Iterations::kColumn *
|
| 105 |
+
ThreadMap::Iterations::kRow *
|
| 106 |
+
ThreadMap::Iterations::kGroup *
|
| 107 |
+
ThreadMap::Iterations::kCluster * ThreadMap::kElementsPerAccess>;
|
| 108 |
+
|
| 109 |
+
/// Memory access size
|
| 110 |
+
using AccessType = AlignedArray<Element, ThreadMap::kElementsPerAccess>;
|
| 111 |
+
static_assert( AccessType::kElements == 1, "BLAS3 Epilogue must use AccessType::kElements as 1");
|
| 112 |
+
|
| 113 |
+
//
|
| 114 |
+
// Parameters struct
|
| 115 |
+
//
|
| 116 |
+
|
| 117 |
+
/// Uses a non-template class
|
| 118 |
+
struct Params : PredicatedTileIteratorParams {
|
| 119 |
+
|
| 120 |
+
CUTLASS_HOST_DEVICE
|
| 121 |
+
Params() { }
|
| 122 |
+
|
| 123 |
+
CUTLASS_HOST_DEVICE
|
| 124 |
+
Params(Layout const &layout):
|
| 125 |
+
PredicatedTileIteratorParams(
|
| 126 |
+
layout.stride(0) * int(sizeof(AccessType)) / kElementsPerAccess,
|
| 127 |
+
make_OutputTileThreadMapDesc<ThreadMap>()
|
| 128 |
+
)
|
| 129 |
+
{
|
| 130 |
+
|
| 131 |
+
}
|
| 132 |
+
};
|
| 133 |
+
|
| 134 |
+
/// Mask object
|
| 135 |
+
struct Mask {
|
| 136 |
+
|
| 137 |
+
static int const kCount = ThreadMap::Iterations::kColumn;
|
| 138 |
+
|
| 139 |
+
/// Predicate state
|
| 140 |
+
bool predicates[kCount];
|
| 141 |
+
|
| 142 |
+
//
|
| 143 |
+
// Mask
|
| 144 |
+
//
|
| 145 |
+
CUTLASS_HOST_DEVICE
|
| 146 |
+
Mask() {
|
| 147 |
+
enable();
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
///< Efficiently disables all accesses guarded by mask
|
| 151 |
+
CUTLASS_HOST_DEVICE void clear() {
|
| 152 |
+
CUTLASS_PRAGMA_UNROLL
|
| 153 |
+
for (int i = 0; i < kCount; ++i) {
|
| 154 |
+
predicates[i] = false;
|
| 155 |
+
}
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
///< CUTLASS_HOST_DEVICE enables all accesses guarded by mask
|
| 159 |
+
CUTLASS_DEVICE void enable() {
|
| 160 |
+
CUTLASS_PRAGMA_UNROLL
|
| 161 |
+
for (int i = 0; i < kCount; ++i) {
|
| 162 |
+
predicates[i] = true;
|
| 163 |
+
}
|
| 164 |
+
}
|
| 165 |
+
};
|
| 166 |
+
|
| 167 |
+
private:
|
| 168 |
+
|
| 169 |
+
//
|
| 170 |
+
// Data members
|
| 171 |
+
//
|
| 172 |
+
|
| 173 |
+
/// Parameters structure containing reference and precomputed state.
|
| 174 |
+
PredicatedTileIteratorParams params_;
|
| 175 |
+
|
| 176 |
+
/// Byte-level pointer
|
| 177 |
+
uint8_t *byte_pointer_;
|
| 178 |
+
|
| 179 |
+
/// Fill Mode for a tile on diagonal of a symmetric kernel
|
| 180 |
+
cutlass::FillMode fill_mode;
|
| 181 |
+
|
| 182 |
+
/// Array of boolean values to contain steady-state predicates
|
| 183 |
+
Mask mask_;
|
| 184 |
+
|
| 185 |
+
/// Extent of the matrix tile in rows
|
| 186 |
+
Index extent_row_;
|
| 187 |
+
|
| 188 |
+
/// A thread's starting row position (assuming steady-state predicates have been computed)
|
| 189 |
+
Index thread_start_row_;
|
| 190 |
+
|
| 191 |
+
/// Internal state counter
|
| 192 |
+
int state_[3];
|
| 193 |
+
|
| 194 |
+
/// Starting address of the matrix
|
| 195 |
+
size_t matrix_start_addr;
|
| 196 |
+
|
| 197 |
+
static_assert((kBlasMode == BlasMode::kSymmetric || kBlasMode == BlasMode::kHermitian),
|
| 198 |
+
"Unsupported blas3 mode.");
|
| 199 |
+
|
| 200 |
+
private:
|
| 201 |
+
|
| 202 |
+
//
|
| 203 |
+
// Methods
|
| 204 |
+
//
|
| 205 |
+
|
| 206 |
+
public:
|
| 207 |
+
|
| 208 |
+
//
|
| 209 |
+
// Methods
|
| 210 |
+
//
|
| 211 |
+
|
| 212 |
+
/// Constructor
|
| 213 |
+
CUTLASS_DEVICE
|
| 214 |
+
PredicatedTileIteratorBlas3(
|
| 215 |
+
PredicatedTileIteratorParams const & params,
|
| 216 |
+
Element *pointer,
|
| 217 |
+
TensorCoord extent,
|
| 218 |
+
int thread_idx,
|
| 219 |
+
TensorCoord threadblock_offset
|
| 220 |
+
, cutlass::FillMode fill_mode
|
| 221 |
+
):
|
| 222 |
+
params_(params), fill_mode(fill_mode)
|
| 223 |
+
{
|
| 224 |
+
|
| 225 |
+
TensorCoord thread_offset = ThreadMap::initial_offset(thread_idx) + threadblock_offset;
|
| 226 |
+
|
| 227 |
+
extent_row_ = extent.row();
|
| 228 |
+
thread_start_row_ = thread_offset.row();
|
| 229 |
+
|
| 230 |
+
// Initialize predicates
|
| 231 |
+
CUTLASS_PRAGMA_UNROLL
|
| 232 |
+
for (int c = 0; c < ThreadMap::Iterations::kColumn; ++c) {
|
| 233 |
+
|
| 234 |
+
mask_.predicates[c] = ((thread_offset.column()
|
| 235 |
+
+ ThreadMap::Delta::kColumn * c) < extent.column());
|
| 236 |
+
}
|
| 237 |
+
|
| 238 |
+
// Check Symmetric kernel modes (Lower and Upper - for diagonal CTAs, None for rest CTAs)
|
| 239 |
+
if ((kBlasMode == BlasMode::kSymmetric || kBlasMode == BlasMode::kHermitian) &&
|
| 240 |
+
fill_mode == cutlass::FillMode::kInvalid) {
|
| 241 |
+
arch::device_breakpoint();
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
// Starting address of the matrix
|
| 245 |
+
matrix_start_addr = reinterpret_cast<size_t>(pointer);
|
| 246 |
+
|
| 247 |
+
// Initialize pointer
|
| 248 |
+
byte_pointer_ = reinterpret_cast<uint8_t *>(pointer) +
|
| 249 |
+
LongIndex(thread_offset.row()) * LongIndex(params_.stride) +
|
| 250 |
+
LongIndex(thread_offset.column()) * sizeof(AccessType) / kElementsPerAccess;
|
| 251 |
+
|
| 252 |
+
// Initialize internal state counter
|
| 253 |
+
state_[0] = state_[1] = state_[2] = 0;
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
/// Adds a pointer offset in units of Element
|
| 257 |
+
CUTLASS_HOST_DEVICE
|
| 258 |
+
void add_pointer_offset(LongIndex pointer_offset) {
|
| 259 |
+
byte_pointer_ += pointer_offset * sizeof_bits<Element>::value / 8;
|
| 260 |
+
}
|
| 261 |
+
|
| 262 |
+
/// Loads a fragment from memory
|
| 263 |
+
CUTLASS_DEVICE
|
| 264 |
+
void load_with_byte_offset(Fragment &frag, int64_t byte_offset) {
|
| 265 |
+
|
| 266 |
+
uint8_t *byte_pointer = byte_pointer_;
|
| 267 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 268 |
+
|
| 269 |
+
CUTLASS_PRAGMA_UNROLL
|
| 270 |
+
for (int cluster = 0; cluster < ThreadMap::Iterations::kCluster; ++cluster) {
|
| 271 |
+
|
| 272 |
+
CUTLASS_PRAGMA_UNROLL
|
| 273 |
+
for (int group = 0; group < ThreadMap::Iterations::kGroup; ++group) {
|
| 274 |
+
|
| 275 |
+
CUTLASS_PRAGMA_UNROLL
|
| 276 |
+
for (int row = 0; row < ThreadMap::Iterations::kRow; ++row) {
|
| 277 |
+
|
| 278 |
+
int frag_row_idx =
|
| 279 |
+
(row + ThreadMap::Iterations::kRow * (group + ThreadMap::Iterations::kGroup * cluster));
|
| 280 |
+
|
| 281 |
+
int row_offset = row * ThreadMap::Delta::kRow
|
| 282 |
+
+ group * ThreadMap::Delta::kGroup
|
| 283 |
+
+ cluster * ThreadMap::Delta::kCluster;
|
| 284 |
+
|
| 285 |
+
bool row_guard = ((row_offset + thread_start_row_) < extent_row_);
|
| 286 |
+
|
| 287 |
+
AccessType *memory_pointer = reinterpret_cast<AccessType *>(byte_pointer + byte_offset);
|
| 288 |
+
|
| 289 |
+
CUTLASS_PRAGMA_UNROLL
|
| 290 |
+
for (int column = 0; column < ThreadMap::Iterations::kColumn; ++column) {
|
| 291 |
+
|
| 292 |
+
bool guard = row_guard && mask_.predicates[column];
|
| 293 |
+
|
| 294 |
+
cutlass::arch::global_load<
|
| 295 |
+
AccessType,
|
| 296 |
+
sizeof(AccessType)
|
| 297 |
+
>(
|
| 298 |
+
frag_ptr[frag_row_idx * ThreadMap::Iterations::kColumn +
|
| 299 |
+
column],
|
| 300 |
+
(void *)&memory_pointer[column * ThreadMap::Delta::kColumn /
|
| 301 |
+
kElementsPerAccess],
|
| 302 |
+
guard);
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
if (row + 1 < ThreadMap::Iterations::kRow) {
|
| 306 |
+
byte_pointer += params_.increment_row;
|
| 307 |
+
}
|
| 308 |
+
}
|
| 309 |
+
|
| 310 |
+
if (group + 1 < ThreadMap::Iterations::kGroup) {
|
| 311 |
+
byte_pointer += params_.increment_group;
|
| 312 |
+
}
|
| 313 |
+
}
|
| 314 |
+
|
| 315 |
+
if (cluster + 1 < ThreadMap::Iterations::kCluster) {
|
| 316 |
+
byte_pointer += params_.increment_cluster;
|
| 317 |
+
}
|
| 318 |
+
}
|
| 319 |
+
}
|
| 320 |
+
|
| 321 |
+
/// Loads a fragment on the diagonal of a symmetric kernel to memory
|
| 322 |
+
CUTLASS_DEVICE
|
| 323 |
+
void load_symmetric_with_byte_offset(Fragment &frag, int64_t byte_offset) {
|
| 324 |
+
|
| 325 |
+
uint8_t *byte_pointer = byte_pointer_;
|
| 326 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 327 |
+
|
| 328 |
+
bool isLowerMode = (fill_mode == cutlass::FillMode::kLower) ? true : false;
|
| 329 |
+
|
| 330 |
+
CUTLASS_PRAGMA_UNROLL
|
| 331 |
+
for (int cluster = 0; cluster < ThreadMap::Iterations::kCluster; ++cluster) {
|
| 332 |
+
|
| 333 |
+
CUTLASS_PRAGMA_UNROLL
|
| 334 |
+
for (int group = 0; group < ThreadMap::Iterations::kGroup; ++group) {
|
| 335 |
+
|
| 336 |
+
CUTLASS_PRAGMA_UNROLL
|
| 337 |
+
for (int row = 0; row < ThreadMap::Iterations::kRow; ++row) {
|
| 338 |
+
|
| 339 |
+
int frag_row_idx =
|
| 340 |
+
(row + ThreadMap::Iterations::kRow * (group + ThreadMap::Iterations::kGroup * cluster));
|
| 341 |
+
|
| 342 |
+
int row_offset = row * ThreadMap::Delta::kRow
|
| 343 |
+
+ group * ThreadMap::Delta::kGroup
|
| 344 |
+
+ cluster * ThreadMap::Delta::kCluster;
|
| 345 |
+
|
| 346 |
+
bool row_guard = ((row_offset + thread_start_row_) < extent_row_);
|
| 347 |
+
|
| 348 |
+
AccessType *memory_pointer = reinterpret_cast<AccessType *>(byte_pointer + byte_offset);
|
| 349 |
+
|
| 350 |
+
// Offset of row from beginning of the matrix per thread
|
| 351 |
+
size_t row_start_offset = (size_t)memory_pointer - matrix_start_addr;
|
| 352 |
+
|
| 353 |
+
// Absolute row index
|
| 354 |
+
int row_index = int(row_start_offset/params_.stride);
|
| 355 |
+
|
| 356 |
+
CUTLASS_PRAGMA_UNROLL
|
| 357 |
+
for (int column = 0; column < ThreadMap::Iterations::kColumn; ++column) {
|
| 358 |
+
|
| 359 |
+
bool guard = row_guard && mask_.predicates[column];
|
| 360 |
+
|
| 361 |
+
// Offset of column from beginning of row per thread
|
| 362 |
+
size_t col_start_offset = row_start_offset +
|
| 363 |
+
(column * ThreadMap::Delta::kColumn / kElementsPerAccess) * sizeof(AccessType);
|
| 364 |
+
|
| 365 |
+
// Absolute column index
|
| 366 |
+
size_t col_index = (col_start_offset%params_.stride)/sizeof(AccessType);
|
| 367 |
+
guard = guard && ( (isLowerMode && row_index >= col_index) ||
|
| 368 |
+
(!isLowerMode && row_index <= col_index) );
|
| 369 |
+
|
| 370 |
+
cutlass::arch::global_load<
|
| 371 |
+
AccessType,
|
| 372 |
+
sizeof(AccessType)
|
| 373 |
+
>(
|
| 374 |
+
frag_ptr[frag_row_idx * ThreadMap::Iterations::kColumn +
|
| 375 |
+
column],
|
| 376 |
+
(void *)&memory_pointer[column * ThreadMap::Delta::kColumn /
|
| 377 |
+
kElementsPerAccess],
|
| 378 |
+
guard);
|
| 379 |
+
|
| 380 |
+
// The imaginary parts of the diagonal elements of a complex element are assumed and set to zero
|
| 381 |
+
if (guard && kBlasMode == BlasMode::kHermitian && cutlass::is_complex<Element>::value) {
|
| 382 |
+
Element *scalar_ptr = reinterpret_cast<Element *>(frag_ptr);
|
| 383 |
+
|
| 384 |
+
if (row_index == col_index) {
|
| 385 |
+
scalar_ptr[frag_row_idx * ThreadMap::Iterations::kColumn + column] =
|
| 386 |
+
real(scalar_ptr[frag_row_idx * ThreadMap::Iterations::kColumn + column]);
|
| 387 |
+
}
|
| 388 |
+
}
|
| 389 |
+
}
|
| 390 |
+
|
| 391 |
+
if (row + 1 < ThreadMap::Iterations::kRow) {
|
| 392 |
+
byte_pointer += params_.increment_row;
|
| 393 |
+
}
|
| 394 |
+
}
|
| 395 |
+
|
| 396 |
+
if (group + 1 < ThreadMap::Iterations::kGroup) {
|
| 397 |
+
byte_pointer += params_.increment_group;
|
| 398 |
+
}
|
| 399 |
+
}
|
| 400 |
+
|
| 401 |
+
if (cluster + 1 < ThreadMap::Iterations::kCluster) {
|
| 402 |
+
byte_pointer += params_.increment_cluster;
|
| 403 |
+
}
|
| 404 |
+
}
|
| 405 |
+
}
|
| 406 |
+
|
| 407 |
+
/// Loads a fragment from memory
|
| 408 |
+
CUTLASS_DEVICE
|
| 409 |
+
void load(Fragment &frag) {
|
| 410 |
+
|
| 411 |
+
if (fill_mode == cutlass::FillMode::kNone) {
|
| 412 |
+
load_with_byte_offset(frag, 0);
|
| 413 |
+
}
|
| 414 |
+
else {
|
| 415 |
+
load_symmetric_with_byte_offset(frag, 0);
|
| 416 |
+
}
|
| 417 |
+
}
|
| 418 |
+
|
| 419 |
+
/// Stores a fragment to memory
|
| 420 |
+
CUTLASS_DEVICE
|
| 421 |
+
void store_with_byte_offset(Fragment const &frag, int64_t byte_offset) {
|
| 422 |
+
uint8_t *byte_pointer = byte_pointer_;
|
| 423 |
+
AccessType const *frag_ptr = reinterpret_cast<AccessType const *>(&frag);
|
| 424 |
+
|
| 425 |
+
CUTLASS_PRAGMA_UNROLL
|
| 426 |
+
for (int cluster = 0; cluster < ThreadMap::Iterations::kCluster; ++cluster) {
|
| 427 |
+
|
| 428 |
+
CUTLASS_PRAGMA_UNROLL
|
| 429 |
+
for (int group = 0; group < ThreadMap::Iterations::kGroup; ++group) {
|
| 430 |
+
|
| 431 |
+
CUTLASS_PRAGMA_UNROLL
|
| 432 |
+
for (int row = 0; row < ThreadMap::Iterations::kRow; ++row) {
|
| 433 |
+
|
| 434 |
+
int frag_row_idx =
|
| 435 |
+
(row + ThreadMap::Iterations::kRow * (group + ThreadMap::Iterations::kGroup * cluster));
|
| 436 |
+
|
| 437 |
+
int row_offset = row * ThreadMap::Delta::kRow
|
| 438 |
+
+ group * ThreadMap::Delta::kGroup
|
| 439 |
+
+ cluster * ThreadMap::Delta::kCluster;
|
| 440 |
+
|
| 441 |
+
bool row_guard = ((row_offset + thread_start_row_) < extent_row_);
|
| 442 |
+
|
| 443 |
+
AccessType *memory_pointer = reinterpret_cast<AccessType *>(byte_pointer + byte_offset);
|
| 444 |
+
|
| 445 |
+
CUTLASS_PRAGMA_UNROLL
|
| 446 |
+
for (int column = 0; column < ThreadMap::Iterations::kColumn; ++column) {
|
| 447 |
+
|
| 448 |
+
bool guard = row_guard && mask_.predicates[column];
|
| 449 |
+
|
| 450 |
+
cutlass::arch::global_store<AccessType, sizeof(AccessType)>(
|
| 451 |
+
frag_ptr[frag_row_idx * ThreadMap::Iterations::kColumn + column],
|
| 452 |
+
(void *)&memory_pointer[column * ThreadMap::Delta::kColumn / kElementsPerAccess],
|
| 453 |
+
guard);
|
| 454 |
+
}
|
| 455 |
+
|
| 456 |
+
if (row + 1 < ThreadMap::Iterations::kRow) {
|
| 457 |
+
byte_pointer += params_.increment_row;
|
| 458 |
+
}
|
| 459 |
+
}
|
| 460 |
+
|
| 461 |
+
if (group + 1 < ThreadMap::Iterations::kGroup) {
|
| 462 |
+
byte_pointer += params_.increment_group;
|
| 463 |
+
}
|
| 464 |
+
}
|
| 465 |
+
|
| 466 |
+
if (cluster + 1 < ThreadMap::Iterations::kCluster) {
|
| 467 |
+
byte_pointer += params_.increment_cluster;
|
| 468 |
+
}
|
| 469 |
+
}
|
| 470 |
+
}
|
| 471 |
+
|
| 472 |
+
/// Stores a fragment on the diagonal of a symmetric kernel to memory
|
| 473 |
+
CUTLASS_DEVICE
|
| 474 |
+
void store_symmetric_with_byte_offset(Fragment const &frag, int64_t byte_offset) {
|
| 475 |
+
uint8_t *byte_pointer = byte_pointer_;
|
| 476 |
+
AccessType const *frag_ptr = reinterpret_cast<AccessType const *>(&frag);
|
| 477 |
+
|
| 478 |
+
bool isLowerMode = (fill_mode == cutlass::FillMode::kLower) ? true : false;
|
| 479 |
+
|
| 480 |
+
CUTLASS_PRAGMA_UNROLL
|
| 481 |
+
for (int cluster = 0; cluster < ThreadMap::Iterations::kCluster; ++cluster) {
|
| 482 |
+
|
| 483 |
+
CUTLASS_PRAGMA_UNROLL
|
| 484 |
+
for (int group = 0; group < ThreadMap::Iterations::kGroup; ++group) {
|
| 485 |
+
|
| 486 |
+
CUTLASS_PRAGMA_UNROLL
|
| 487 |
+
for (int row = 0; row < ThreadMap::Iterations::kRow; ++row) {
|
| 488 |
+
|
| 489 |
+
int frag_row_idx =
|
| 490 |
+
(row + ThreadMap::Iterations::kRow * (group + ThreadMap::Iterations::kGroup * cluster));
|
| 491 |
+
|
| 492 |
+
int row_offset = row * ThreadMap::Delta::kRow
|
| 493 |
+
+ group * ThreadMap::Delta::kGroup
|
| 494 |
+
+ cluster * ThreadMap::Delta::kCluster;
|
| 495 |
+
|
| 496 |
+
bool row_guard = ((row_offset + thread_start_row_) < extent_row_);
|
| 497 |
+
|
| 498 |
+
AccessType *memory_pointer = reinterpret_cast<AccessType *>(byte_pointer + byte_offset);
|
| 499 |
+
|
| 500 |
+
// Offset of row from beginning of the matrix per thread
|
| 501 |
+
size_t row_start_offset = (size_t)memory_pointer - matrix_start_addr;
|
| 502 |
+
|
| 503 |
+
// Absolute row index
|
| 504 |
+
int row_index = int(row_start_offset/params_.stride);
|
| 505 |
+
|
| 506 |
+
CUTLASS_PRAGMA_UNROLL
|
| 507 |
+
for (int column = 0; column < ThreadMap::Iterations::kColumn; ++column) {
|
| 508 |
+
|
| 509 |
+
bool guard = row_guard && mask_.predicates[column];
|
| 510 |
+
|
| 511 |
+
// Offset of column from beginning of row per thread
|
| 512 |
+
size_t col_start_offset = row_start_offset +
|
| 513 |
+
(column * ThreadMap::Delta::kColumn / kElementsPerAccess) * sizeof(AccessType);
|
| 514 |
+
|
| 515 |
+
// Absolute column index
|
| 516 |
+
size_t col_index = (col_start_offset%params_.stride)/sizeof(AccessType);
|
| 517 |
+
|
| 518 |
+
guard = guard && ( (isLowerMode && row_index >= col_index) ||
|
| 519 |
+
(!isLowerMode && row_index <= col_index) );
|
| 520 |
+
|
| 521 |
+
// The imaginary parts of the diagonal elements of a complex element are assumed and set to zero
|
| 522 |
+
if (guard && kBlasMode == BlasMode::kHermitian && cutlass::is_complex<Element>::value) {
|
| 523 |
+
|
| 524 |
+
AccessType *frag_ptr_modify = const_cast<AccessType *>(frag_ptr);
|
| 525 |
+
Element *scalar_ptr = reinterpret_cast<Element *>(frag_ptr_modify);
|
| 526 |
+
|
| 527 |
+
if (row_index == col_index) {
|
| 528 |
+
scalar_ptr[frag_row_idx * ThreadMap::Iterations::kColumn + column] =
|
| 529 |
+
real(scalar_ptr[frag_row_idx * ThreadMap::Iterations::kColumn + column]);
|
| 530 |
+
}
|
| 531 |
+
}
|
| 532 |
+
|
| 533 |
+
cutlass::arch::global_store<AccessType, sizeof(AccessType)>(
|
| 534 |
+
frag_ptr[frag_row_idx * ThreadMap::Iterations::kColumn +
|
| 535 |
+
column],
|
| 536 |
+
(void *)&memory_pointer[column * ThreadMap::Delta::kColumn /
|
| 537 |
+
kElementsPerAccess],
|
| 538 |
+
guard);
|
| 539 |
+
}
|
| 540 |
+
|
| 541 |
+
if (row + 1 < ThreadMap::Iterations::kRow) {
|
| 542 |
+
byte_pointer += params_.increment_row;
|
| 543 |
+
}
|
| 544 |
+
}
|
| 545 |
+
|
| 546 |
+
if (group + 1 < ThreadMap::Iterations::kGroup) {
|
| 547 |
+
byte_pointer += params_.increment_group;
|
| 548 |
+
}
|
| 549 |
+
}
|
| 550 |
+
|
| 551 |
+
if (cluster + 1 < ThreadMap::Iterations::kCluster) {
|
| 552 |
+
byte_pointer += params_.increment_cluster;
|
| 553 |
+
}
|
| 554 |
+
}
|
| 555 |
+
}
|
| 556 |
+
|
| 557 |
+
/// Stores a fragment to memory
|
| 558 |
+
CUTLASS_DEVICE
|
| 559 |
+
void store(Fragment const &frag) {
|
| 560 |
+
|
| 561 |
+
if (fill_mode == cutlass::FillMode::kNone) {
|
| 562 |
+
store_with_byte_offset(frag, 0);
|
| 563 |
+
}
|
| 564 |
+
else {
|
| 565 |
+
store_symmetric_with_byte_offset(frag, 0);
|
| 566 |
+
}
|
| 567 |
+
|
| 568 |
+
}
|
| 569 |
+
|
| 570 |
+
/// Advances to the next position to load or store
|
| 571 |
+
CUTLASS_HOST_DEVICE
|
| 572 |
+
PredicatedTileIteratorBlas3 &operator++() {
|
| 573 |
+
|
| 574 |
+
++state_[0];
|
| 575 |
+
byte_pointer_ += params_.advance_row;
|
| 576 |
+
thread_start_row_ += ThreadMap::Shape::kRow;
|
| 577 |
+
|
| 578 |
+
if (state_[0] == ThreadMap::Count::kRow) {
|
| 579 |
+
|
| 580 |
+
state_[0] = 0;
|
| 581 |
+
++state_[1];
|
| 582 |
+
byte_pointer_ += params_.advance_group;
|
| 583 |
+
|
| 584 |
+
thread_start_row_ += (ThreadMap::Shape::kGroup - 1) *
|
| 585 |
+
ThreadMap::Shape::kRow * ThreadMap::Count::kRow;
|
| 586 |
+
|
| 587 |
+
if (state_[1] == ThreadMap::Count::kGroup) {
|
| 588 |
+
|
| 589 |
+
state_[1] = 0;
|
| 590 |
+
++state_[2];
|
| 591 |
+
byte_pointer_ += params_.advance_cluster;
|
| 592 |
+
|
| 593 |
+
thread_start_row_ += ThreadMap::Count::kGroup *
|
| 594 |
+
ThreadMap::Shape::kGroup * ThreadMap::Count::kRow * ThreadMap::Shape::kRow;
|
| 595 |
+
|
| 596 |
+
if (state_[2] == ThreadMap::Count::kCluster) {
|
| 597 |
+
state_[2] = 0;
|
| 598 |
+
byte_pointer_ += params_.advance_tile;
|
| 599 |
+
}
|
| 600 |
+
}
|
| 601 |
+
}
|
| 602 |
+
|
| 603 |
+
return *this;
|
| 604 |
+
}
|
| 605 |
+
|
| 606 |
+
///< Efficiently disables all accesses guarded by mask
|
| 607 |
+
CUTLASS_DEVICE void clear_mask() {
|
| 608 |
+
mask_.clear();
|
| 609 |
+
}
|
| 610 |
+
|
| 611 |
+
///< Efficiently enables all accesses guarded by mask
|
| 612 |
+
CUTLASS_DEVICE void enable_mask() {
|
| 613 |
+
mask_.enable();
|
| 614 |
+
}
|
| 615 |
+
|
| 616 |
+
///< Sets the mask
|
| 617 |
+
CUTLASS_DEVICE void get_mask(Mask &mask) {
|
| 618 |
+
mask = mask_;
|
| 619 |
+
}
|
| 620 |
+
|
| 621 |
+
///< Sets the mask
|
| 622 |
+
CUTLASS_DEVICE void set_mask(Mask const &mask) {
|
| 623 |
+
mask_ = mask;
|
| 624 |
+
}
|
| 625 |
+
};
|
| 626 |
+
|
| 627 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 628 |
+
|
| 629 |
+
} // namespace threadblock
|
| 630 |
+
} // namespace epilogue
|
| 631 |
+
} // namespace cutlass
|
| 632 |
+
|
| 633 |
+
////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_conv.h
ADDED
|
@@ -0,0 +1,562 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief Epilogue for threadblock scoped GEMMs using Tensor Ops.
|
| 33 |
+
|
| 34 |
+
The epilogue rearranges the result of a matrix product through shared memory to match canonical
|
| 35 |
+
tensor layouts in global memory. Epilogues support conversion and reduction operations.
|
| 36 |
+
|
| 37 |
+
*/
|
| 38 |
+
|
| 39 |
+
#pragma once
|
| 40 |
+
|
| 41 |
+
#include "cutlass/cutlass.h"
|
| 42 |
+
#include "cutlass/numeric_types.h"
|
| 43 |
+
#include "cutlass/array.h"
|
| 44 |
+
#include "cutlass/layout/matrix.h"
|
| 45 |
+
#include "cutlass/layout/tensor.h"
|
| 46 |
+
#include "cutlass/layout/permute.h"
|
| 47 |
+
#include "cutlass/matrix_shape.h"
|
| 48 |
+
#include "cutlass/tensor_ref.h"
|
| 49 |
+
#include "cutlass/transform/pitch_linear_thread_map.h"
|
| 50 |
+
#include "cutlass/epilogue/threadblock/output_tile_thread_map.h"
|
| 51 |
+
#include "cutlass/arch/arch.h"
|
| 52 |
+
#include "cutlass/arch/memory.h"
|
| 53 |
+
#include "cutlass/epilogue/threadblock/predicated_tile_iterator_params.h"
|
| 54 |
+
#include "cutlass/conv/conv2d_problem_size.h"
|
| 55 |
+
#include "cutlass/conv/conv3d_problem_size.h"
|
| 56 |
+
|
| 57 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 58 |
+
|
| 59 |
+
namespace cutlass {
|
| 60 |
+
|
| 61 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 62 |
+
|
| 63 |
+
namespace epilogue {
|
| 64 |
+
namespace threadblock {
|
| 65 |
+
|
| 66 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 67 |
+
|
| 68 |
+
/// Tile iterator used to load and store output tile from global memory in epilogue.
|
| 69 |
+
///
|
| 70 |
+
/// Satisfies: ReadableTileIterator | PredicatedTileIteratorConv | ForwardTileIterator
|
| 71 |
+
///
|
| 72 |
+
template <
|
| 73 |
+
typename ThreadMap_, ///< Thread map (conept: OutputTileThreadMap)
|
| 74 |
+
typename Element_, ///< Element data type
|
| 75 |
+
bool ScatterD = false, ///< Scatter D operand or not
|
| 76 |
+
typename PermuteDLayout = layout::NoPermute, ///< Permute D operand or not
|
| 77 |
+
bool UseCUDAStore = false,
|
| 78 |
+
int Rank = 4
|
| 79 |
+
>
|
| 80 |
+
class PredicatedTileIteratorConv {
|
| 81 |
+
public:
|
| 82 |
+
using ThreadMap = ThreadMap_;
|
| 83 |
+
using Shape = typename ThreadMap::Shape;
|
| 84 |
+
|
| 85 |
+
using Element = Element_;
|
| 86 |
+
|
| 87 |
+
static int const kRank = Rank;
|
| 88 |
+
using Layout = typename platform::conditional<kRank == 4,
|
| 89 |
+
layout::TensorNHWC,
|
| 90 |
+
layout::TensorNDHWC>::type;
|
| 91 |
+
|
| 92 |
+
using Stride = typename Layout::Stride;
|
| 93 |
+
static int const kStrideRank = Layout::kStrideRank;
|
| 94 |
+
|
| 95 |
+
using TensorRef = TensorRef<Element, Layout>;
|
| 96 |
+
using ConstTensorRef = typename TensorRef::ConstTensorRef;
|
| 97 |
+
|
| 98 |
+
using MappedLayout = layout::RowMajor;
|
| 99 |
+
using Index = typename MappedLayout::Index;
|
| 100 |
+
using LongIndex = typename MappedLayout::LongIndex;
|
| 101 |
+
using TensorCoord = typename MappedLayout::TensorCoord;
|
| 102 |
+
|
| 103 |
+
static int const kElementsPerAccess = ThreadMap::kElementsPerAccess;
|
| 104 |
+
static int const kThreads = ThreadMap::kThreads;
|
| 105 |
+
static int const kIterations = ThreadMap::Count::kTile;
|
| 106 |
+
|
| 107 |
+
static bool constexpr PermuteD = !layout::is_trivial_permute<PermuteDLayout>;
|
| 108 |
+
|
| 109 |
+
static_assert( ThreadMap::Iterations::kRow > 0,"ThreadMap::Iterations::kRow must be > 0");
|
| 110 |
+
static_assert( ThreadMap::Iterations::kGroup > 0,"ThreadMap::Iterations::kGroup must be > 0");
|
| 111 |
+
static_assert( ThreadMap::Iterations::kCluster > 0,"ThreadMap::Iterations::kCluster must be > 0");
|
| 112 |
+
static_assert( ThreadMap::Iterations::kColumn > 0,"ThreadMap::Iterations::kColumn must be > 0");
|
| 113 |
+
|
| 114 |
+
/// Fragment object
|
| 115 |
+
using Fragment = Array<
|
| 116 |
+
Element,
|
| 117 |
+
ThreadMap::Iterations::kColumn *
|
| 118 |
+
ThreadMap::Iterations::kRow *
|
| 119 |
+
ThreadMap::Iterations::kGroup *
|
| 120 |
+
ThreadMap::Iterations::kCluster * ThreadMap::kElementsPerAccess>;
|
| 121 |
+
|
| 122 |
+
/// Memory access size
|
| 123 |
+
using AccessType = AlignedArray<Element, ThreadMap::kElementsPerAccess>;
|
| 124 |
+
|
| 125 |
+
//
|
| 126 |
+
// Parameters struct
|
| 127 |
+
//
|
| 128 |
+
|
| 129 |
+
/// Uses a non-template class
|
| 130 |
+
struct Params : PredicatedTileIteratorParams {
|
| 131 |
+
using Base = PredicatedTileIteratorParams;
|
| 132 |
+
|
| 133 |
+
/// Fast divmod objects divided by tensor extents
|
| 134 |
+
FastDivmod divmod[kStrideRank - 1];
|
| 135 |
+
Stride tensor_stride;
|
| 136 |
+
|
| 137 |
+
CUTLASS_HOST_DEVICE
|
| 138 |
+
Params() { }
|
| 139 |
+
|
| 140 |
+
CUTLASS_HOST_DEVICE
|
| 141 |
+
Params(Layout const &layout, cutlass::Tensor4DCoord const &tensor_extent):
|
| 142 |
+
PredicatedTileIteratorParams(
|
| 143 |
+
layout.stride()[0] * int(sizeof(AccessType)) / kElementsPerAccess,
|
| 144 |
+
make_OutputTileThreadMapDesc<ThreadMap>()
|
| 145 |
+
) {
|
| 146 |
+
divmod[0] = FastDivmod(tensor_extent[2] /* Q for Fprop & W for Deconv*/);
|
| 147 |
+
divmod[1] = FastDivmod(tensor_extent[1] /* P for Fprop & H for Deconv*/);
|
| 148 |
+
|
| 149 |
+
CUTLASS_PRAGMA_UNROLL
|
| 150 |
+
for (int i = 0; i < kStrideRank; ++i) {
|
| 151 |
+
tensor_stride[i] = layout.stride()[i];
|
| 152 |
+
}
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
CUTLASS_HOST_DEVICE
|
| 156 |
+
Params(Layout const &layout, cutlass::Tensor5DCoord const &tensor_extent):
|
| 157 |
+
PredicatedTileIteratorParams(
|
| 158 |
+
layout.stride()[0] * int(sizeof(AccessType)) / kElementsPerAccess,
|
| 159 |
+
make_OutputTileThreadMapDesc<ThreadMap>()
|
| 160 |
+
) {
|
| 161 |
+
divmod[0] = FastDivmod(tensor_extent[3] /* Q for Fprop & W for Deconv*/);
|
| 162 |
+
divmod[1] = FastDivmod(tensor_extent[2] /* P for Fprop & H for Deconv*/);
|
| 163 |
+
divmod[2] = FastDivmod(tensor_extent[1] /* Z for Fprop & D for Deconv*/);
|
| 164 |
+
|
| 165 |
+
CUTLASS_PRAGMA_UNROLL
|
| 166 |
+
for (int i = 0; i < kStrideRank; ++i) {
|
| 167 |
+
tensor_stride[i] = layout.stride()[i];
|
| 168 |
+
}
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
CUTLASS_HOST_DEVICE
|
| 172 |
+
Params(Base const &base) :
|
| 173 |
+
Base(base) { }
|
| 174 |
+
};
|
| 175 |
+
|
| 176 |
+
/// Mask object
|
| 177 |
+
struct Mask {
|
| 178 |
+
|
| 179 |
+
static int const kCount = ThreadMap::Iterations::kColumn;
|
| 180 |
+
|
| 181 |
+
/// Predicate state
|
| 182 |
+
bool predicates[kCount];
|
| 183 |
+
|
| 184 |
+
//
|
| 185 |
+
// Mask
|
| 186 |
+
//
|
| 187 |
+
CUTLASS_HOST_DEVICE
|
| 188 |
+
Mask() {
|
| 189 |
+
enable();
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
///< Efficiently disables all accesses guarded by mask
|
| 193 |
+
CUTLASS_HOST_DEVICE void clear() {
|
| 194 |
+
CUTLASS_PRAGMA_UNROLL
|
| 195 |
+
for (int i = 0; i < kCount; ++i) {
|
| 196 |
+
predicates[i] = false;
|
| 197 |
+
}
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
///< CUTLASS_HOST_DEVICE enables all accesses guarded by mask
|
| 201 |
+
CUTLASS_DEVICE void enable() {
|
| 202 |
+
CUTLASS_PRAGMA_UNROLL
|
| 203 |
+
for (int i = 0; i < kCount; ++i) {
|
| 204 |
+
predicates[i] = true;
|
| 205 |
+
}
|
| 206 |
+
}
|
| 207 |
+
};
|
| 208 |
+
|
| 209 |
+
private:
|
| 210 |
+
|
| 211 |
+
//
|
| 212 |
+
// Data members
|
| 213 |
+
//
|
| 214 |
+
|
| 215 |
+
/// Parameters structure containing reference and precomputed state.
|
| 216 |
+
Params params_;
|
| 217 |
+
|
| 218 |
+
/// Byte-level pointer. This pointer is usually for both load() and store(), unless PermuteD is performed. When having PermuteD, byte_pointer_ is only for load().
|
| 219 |
+
uint8_t *byte_pointer_;
|
| 220 |
+
|
| 221 |
+
/// Array of boolean values to contain steady-state predicates
|
| 222 |
+
Mask mask_;
|
| 223 |
+
|
| 224 |
+
/// Extent of the matrix tile in rows
|
| 225 |
+
Index extent_row_;
|
| 226 |
+
|
| 227 |
+
/// Extent of the matrix tile in rows
|
| 228 |
+
Index extent_column_;
|
| 229 |
+
|
| 230 |
+
/// A thread's starting row position (assuming steady-state predicates have been computed)
|
| 231 |
+
Index thread_start_row_;
|
| 232 |
+
|
| 233 |
+
/// A thread's starting column
|
| 234 |
+
Index thread_start_column_;
|
| 235 |
+
|
| 236 |
+
/// Internal state counter
|
| 237 |
+
int state_[3];
|
| 238 |
+
|
| 239 |
+
//
|
| 240 |
+
// Static asserts about internal strides
|
| 241 |
+
//
|
| 242 |
+
|
| 243 |
+
static_assert(sizeof(extent_row_) == 4, "Expected 32b extents");
|
| 244 |
+
static_assert(sizeof(thread_start_row_) == 4, "Expected 32b extents");
|
| 245 |
+
static_assert(sizeof(PredicatedTileIteratorParams::stride) == 8, "Expected 64b strides");
|
| 246 |
+
|
| 247 |
+
private:
|
| 248 |
+
|
| 249 |
+
//
|
| 250 |
+
// Methods
|
| 251 |
+
//
|
| 252 |
+
|
| 253 |
+
public:
|
| 254 |
+
|
| 255 |
+
//
|
| 256 |
+
// Methods
|
| 257 |
+
//
|
| 258 |
+
|
| 259 |
+
/// Constructor
|
| 260 |
+
CUTLASS_DEVICE
|
| 261 |
+
PredicatedTileIteratorConv(
|
| 262 |
+
Params const & params,
|
| 263 |
+
Element *pointer,
|
| 264 |
+
TensorCoord extent,
|
| 265 |
+
int thread_idx,
|
| 266 |
+
TensorCoord threadblock_offset = TensorCoord()
|
| 267 |
+
):
|
| 268 |
+
params_(params)
|
| 269 |
+
{
|
| 270 |
+
|
| 271 |
+
TensorCoord thread_offset = ThreadMap::initial_offset(thread_idx) + threadblock_offset;
|
| 272 |
+
|
| 273 |
+
extent_row_ = extent.row();
|
| 274 |
+
extent_column_ = extent.column();
|
| 275 |
+
|
| 276 |
+
thread_start_row_ = thread_offset.row();
|
| 277 |
+
thread_start_column_ = thread_offset.column();
|
| 278 |
+
|
| 279 |
+
// Initialize predicates
|
| 280 |
+
CUTLASS_PRAGMA_UNROLL
|
| 281 |
+
for (int c = 0; c < ThreadMap::Iterations::kColumn; ++c) {
|
| 282 |
+
|
| 283 |
+
mask_.predicates[c] = ((thread_offset.column()
|
| 284 |
+
+ ThreadMap::Delta::kColumn * c) < extent.column());
|
| 285 |
+
}
|
| 286 |
+
|
| 287 |
+
// Null pointer performs no accesses
|
| 288 |
+
if (!pointer) {
|
| 289 |
+
mask_.clear();
|
| 290 |
+
}
|
| 291 |
+
|
| 292 |
+
// Initialize byte_pointer_
|
| 293 |
+
byte_pointer_ = reinterpret_cast<uint8_t *>(pointer) +
|
| 294 |
+
LongIndex(thread_offset.column()) * sizeof(AccessType) / kElementsPerAccess;
|
| 295 |
+
|
| 296 |
+
// Initialize internal state counter
|
| 297 |
+
state_[0] = state_[1] = state_[2] = 0;
|
| 298 |
+
}
|
| 299 |
+
|
| 300 |
+
/// Adds a pointer offset in units of Element
|
| 301 |
+
CUTLASS_HOST_DEVICE
|
| 302 |
+
void add_pointer_offset(LongIndex pointer_offset) {
|
| 303 |
+
byte_pointer_ += pointer_offset * sizeof_bits<Element>::value / 8;
|
| 304 |
+
}
|
| 305 |
+
|
| 306 |
+
/// Loads a fragment from memory
|
| 307 |
+
CUTLASS_DEVICE
|
| 308 |
+
void load_with_byte_offset(Fragment &frag, int64_t byte_offset) const {
|
| 309 |
+
|
| 310 |
+
uint8_t *byte_pointer = byte_pointer_;
|
| 311 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 312 |
+
|
| 313 |
+
CUTLASS_PRAGMA_UNROLL
|
| 314 |
+
for (int cluster = 0; cluster < ThreadMap::Iterations::kCluster; ++cluster) {
|
| 315 |
+
|
| 316 |
+
CUTLASS_PRAGMA_UNROLL
|
| 317 |
+
for (int group = 0; group < ThreadMap::Iterations::kGroup; ++group) {
|
| 318 |
+
|
| 319 |
+
CUTLASS_PRAGMA_UNROLL
|
| 320 |
+
for (int row = 0; row < ThreadMap::Iterations::kRow; ++row) {
|
| 321 |
+
|
| 322 |
+
int frag_row_idx =
|
| 323 |
+
(row + ThreadMap::Iterations::kRow * (group + ThreadMap::Iterations::kGroup * cluster));
|
| 324 |
+
|
| 325 |
+
int row_offset = row * ThreadMap::Delta::kRow
|
| 326 |
+
+ group * ThreadMap::Delta::kGroup
|
| 327 |
+
+ cluster * ThreadMap::Delta::kCluster;
|
| 328 |
+
|
| 329 |
+
bool row_guard = ((row_offset + thread_start_row_) < extent_row_);
|
| 330 |
+
|
| 331 |
+
AccessType *memory_pointer = reinterpret_cast<AccessType *>(byte_pointer + byte_offset);
|
| 332 |
+
|
| 333 |
+
Stride tensor_coord = CoordinateDecompositionLittleEndian<kStrideRank>(row_offset + thread_start_row_, params_.divmod);
|
| 334 |
+
|
| 335 |
+
LongIndex tensor_offset = dot(tensor_coord, params_.tensor_stride);
|
| 336 |
+
|
| 337 |
+
CUTLASS_PRAGMA_UNROLL
|
| 338 |
+
for (int column = 0; column < ThreadMap::Iterations::kColumn; ++column) {
|
| 339 |
+
|
| 340 |
+
bool guard = row_guard && mask_.predicates[column];
|
| 341 |
+
|
| 342 |
+
cutlass::arch::global_load<
|
| 343 |
+
AccessType,
|
| 344 |
+
sizeof(AccessType)
|
| 345 |
+
>(
|
| 346 |
+
frag_ptr[frag_row_idx * ThreadMap::Iterations::kColumn +
|
| 347 |
+
column],
|
| 348 |
+
(void *)&memory_pointer[column * ThreadMap::Delta::kColumn /
|
| 349 |
+
kElementsPerAccess + tensor_offset / kElementsPerAccess],
|
| 350 |
+
guard);
|
| 351 |
+
}
|
| 352 |
+
}
|
| 353 |
+
}
|
| 354 |
+
}
|
| 355 |
+
}
|
| 356 |
+
|
| 357 |
+
/// Loads a fragment from memory
|
| 358 |
+
CUTLASS_DEVICE
|
| 359 |
+
void load(Fragment &frag) const {
|
| 360 |
+
|
| 361 |
+
load_with_byte_offset(frag, 0);
|
| 362 |
+
}
|
| 363 |
+
|
| 364 |
+
/// Stores a fragment to memory
|
| 365 |
+
CUTLASS_DEVICE
|
| 366 |
+
void store_with_byte_offset(Fragment const &frag, int64_t byte_offset) const {
|
| 367 |
+
uint8_t *byte_pointer = byte_pointer_;
|
| 368 |
+
AccessType const *frag_ptr = reinterpret_cast<AccessType const *>(&frag);
|
| 369 |
+
|
| 370 |
+
CUTLASS_PRAGMA_UNROLL
|
| 371 |
+
for (int cluster = 0; cluster < ThreadMap::Iterations::kCluster; ++cluster) {
|
| 372 |
+
|
| 373 |
+
CUTLASS_PRAGMA_UNROLL
|
| 374 |
+
for (int group = 0; group < ThreadMap::Iterations::kGroup; ++group) {
|
| 375 |
+
|
| 376 |
+
CUTLASS_PRAGMA_UNROLL
|
| 377 |
+
for (int row = 0; row < ThreadMap::Iterations::kRow; ++row) {
|
| 378 |
+
|
| 379 |
+
int frag_row_idx =
|
| 380 |
+
(row + ThreadMap::Iterations::kRow * (group + ThreadMap::Iterations::kGroup * cluster));
|
| 381 |
+
|
| 382 |
+
int row_offset = row * ThreadMap::Delta::kRow
|
| 383 |
+
+ group * ThreadMap::Delta::kGroup
|
| 384 |
+
+ cluster * ThreadMap::Delta::kCluster;
|
| 385 |
+
|
| 386 |
+
bool row_guard = ((row_offset + thread_start_row_) < extent_row_);
|
| 387 |
+
|
| 388 |
+
Stride tensor_coord = CoordinateDecompositionLittleEndian<kStrideRank>((row_offset + thread_start_row_), params_.divmod);
|
| 389 |
+
|
| 390 |
+
LongIndex tensor_offset = dot(tensor_coord, params_.tensor_stride);
|
| 391 |
+
|
| 392 |
+
AccessType *memory_pointer = reinterpret_cast<AccessType *>(byte_pointer + byte_offset);
|
| 393 |
+
|
| 394 |
+
CUTLASS_PRAGMA_UNROLL
|
| 395 |
+
for (int column = 0; column < ThreadMap::Iterations::kColumn; ++column) {
|
| 396 |
+
|
| 397 |
+
bool guard = row_guard && mask_.predicates[column];
|
| 398 |
+
|
| 399 |
+
if (UseCUDAStore) {
|
| 400 |
+
if (guard) {
|
| 401 |
+
memory_pointer[tensor_offset / kElementsPerAccess] =
|
| 402 |
+
frag_ptr[frag_row_idx * ThreadMap::Iterations::kColumn + column];
|
| 403 |
+
}
|
| 404 |
+
} else {
|
| 405 |
+
cutlass::arch::global_store<AccessType, sizeof(AccessType)>(
|
| 406 |
+
frag_ptr[frag_row_idx * ThreadMap::Iterations::kColumn + column],
|
| 407 |
+
(void *)&memory_pointer[tensor_offset / kElementsPerAccess],
|
| 408 |
+
guard);
|
| 409 |
+
}
|
| 410 |
+
|
| 411 |
+
memory_pointer += (ThreadMap::Delta::kColumn / kElementsPerAccess);
|
| 412 |
+
}
|
| 413 |
+
}
|
| 414 |
+
}
|
| 415 |
+
}
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
+
/// Stores a fragment to memory
|
| 419 |
+
CUTLASS_DEVICE
|
| 420 |
+
void store(Fragment const &frag) const {
|
| 421 |
+
|
| 422 |
+
store_with_byte_offset(frag, 0);
|
| 423 |
+
}
|
| 424 |
+
|
| 425 |
+
CUTLASS_DEVICE
|
| 426 |
+
MatrixCoord thread_start() const {
|
| 427 |
+
return MatrixCoord(thread_start_row_, thread_start_column_);
|
| 428 |
+
}
|
| 429 |
+
|
| 430 |
+
/// Need to get the thread start row from the tile iterator
|
| 431 |
+
CUTLASS_DEVICE
|
| 432 |
+
int32_t thread_start_row() const {
|
| 433 |
+
return thread_start_row_;
|
| 434 |
+
}
|
| 435 |
+
|
| 436 |
+
/// Need to get the thread start row from the tile iterator
|
| 437 |
+
CUTLASS_DEVICE
|
| 438 |
+
int32_t thread_start_column() const {
|
| 439 |
+
return thread_start_column_;
|
| 440 |
+
}
|
| 441 |
+
|
| 442 |
+
/// Extent of the matrix in rows
|
| 443 |
+
CUTLASS_DEVICE
|
| 444 |
+
Index extent_row() const {
|
| 445 |
+
return extent_row_;
|
| 446 |
+
}
|
| 447 |
+
|
| 448 |
+
/// Extent of the matrix in columns
|
| 449 |
+
CUTLASS_DEVICE
|
| 450 |
+
Index extent_column() const {
|
| 451 |
+
return extent_column_;
|
| 452 |
+
}
|
| 453 |
+
|
| 454 |
+
/// Advances to the next position to load or store
|
| 455 |
+
CUTLASS_HOST_DEVICE
|
| 456 |
+
PredicatedTileIteratorConv &operator++() {
|
| 457 |
+
|
| 458 |
+
++state_[0];
|
| 459 |
+
|
| 460 |
+
thread_start_row_ += ThreadMap::Shape::kRow;
|
| 461 |
+
|
| 462 |
+
if (state_[0] == ThreadMap::Count::kRow) {
|
| 463 |
+
|
| 464 |
+
state_[0] = 0;
|
| 465 |
+
++state_[1];
|
| 466 |
+
|
| 467 |
+
thread_start_row_ += (ThreadMap::Shape::kGroup - 1) *
|
| 468 |
+
ThreadMap::Shape::kRow * ThreadMap::Count::kRow;
|
| 469 |
+
|
| 470 |
+
if (state_[1] == ThreadMap::Count::kGroup) {
|
| 471 |
+
|
| 472 |
+
state_[1] = 0;
|
| 473 |
+
++state_[2];
|
| 474 |
+
|
| 475 |
+
thread_start_row_ += ThreadMap::Count::kGroup *
|
| 476 |
+
ThreadMap::Shape::kGroup * ThreadMap::Count::kRow * ThreadMap::Shape::kRow;
|
| 477 |
+
|
| 478 |
+
if (state_[2] == ThreadMap::Count::kCluster) {
|
| 479 |
+
state_[2] = 0;
|
| 480 |
+
|
| 481 |
+
thread_start_row_ += ThreadMap::Shape::kGroup * ThreadMap::Shape::kRow
|
| 482 |
+
* ThreadMap::Shape::kCluster * ThreadMap::Shape::kTile;
|
| 483 |
+
}
|
| 484 |
+
}
|
| 485 |
+
}
|
| 486 |
+
|
| 487 |
+
return *this;
|
| 488 |
+
}
|
| 489 |
+
|
| 490 |
+
/// Advances a number of positions to load or store
|
| 491 |
+
CUTLASS_HOST_DEVICE
|
| 492 |
+
PredicatedTileIteratorConv &operator+=(int increment)
|
| 493 |
+
{
|
| 494 |
+
// Row
|
| 495 |
+
state_[0] += increment;
|
| 496 |
+
int increment_row = state_[0] / ThreadMap::Count::kRow;
|
| 497 |
+
state_[0] = state_[0] % ThreadMap::Count::kRow;
|
| 498 |
+
|
| 499 |
+
thread_start_row_ += (ThreadMap::Shape::kRow * increment);
|
| 500 |
+
|
| 501 |
+
// Group
|
| 502 |
+
state_[1] += increment_row;
|
| 503 |
+
int increment_group = state_[1] / ThreadMap::Count::kGroup;
|
| 504 |
+
state_[1] = state_[1] % ThreadMap::Count::kGroup;
|
| 505 |
+
|
| 506 |
+
thread_start_row_ +=
|
| 507 |
+
(ThreadMap::Shape::kGroup - 1) *
|
| 508 |
+
ThreadMap::Shape::kRow *
|
| 509 |
+
ThreadMap::Count::kRow *
|
| 510 |
+
increment_row;
|
| 511 |
+
|
| 512 |
+
// Cluster
|
| 513 |
+
state_[2] += increment_group;
|
| 514 |
+
int increment_cluster = state_[2] / ThreadMap::Count::kCluster;
|
| 515 |
+
state_[2] = state_[2] % ThreadMap::Count::kCluster;
|
| 516 |
+
|
| 517 |
+
thread_start_row_ +=
|
| 518 |
+
ThreadMap::Count::kGroup *
|
| 519 |
+
ThreadMap::Shape::kGroup *
|
| 520 |
+
ThreadMap::Count::kRow *
|
| 521 |
+
ThreadMap::Shape::kRow *
|
| 522 |
+
increment_group;
|
| 523 |
+
|
| 524 |
+
// Tile
|
| 525 |
+
thread_start_row_ +=
|
| 526 |
+
ThreadMap::Shape::kGroup *
|
| 527 |
+
ThreadMap::Shape::kRow *
|
| 528 |
+
ThreadMap::Shape::kCluster *
|
| 529 |
+
ThreadMap::Shape::kTile *
|
| 530 |
+
increment_cluster;
|
| 531 |
+
|
| 532 |
+
return *this;
|
| 533 |
+
}
|
| 534 |
+
|
| 535 |
+
///< Efficiently disables all accesses guarded by mask
|
| 536 |
+
CUTLASS_DEVICE void clear_mask() {
|
| 537 |
+
mask_.clear();
|
| 538 |
+
}
|
| 539 |
+
|
| 540 |
+
///< Efficiently enables all accesses guarded by mask
|
| 541 |
+
CUTLASS_DEVICE void enable_mask() {
|
| 542 |
+
mask_.enable();
|
| 543 |
+
}
|
| 544 |
+
|
| 545 |
+
///< Sets the mask
|
| 546 |
+
CUTLASS_DEVICE void get_mask(Mask &mask) const {
|
| 547 |
+
mask = mask_;
|
| 548 |
+
}
|
| 549 |
+
|
| 550 |
+
///< Sets the mask
|
| 551 |
+
CUTLASS_DEVICE void set_mask(Mask const &mask) {
|
| 552 |
+
mask_ = mask;
|
| 553 |
+
}
|
| 554 |
+
};
|
| 555 |
+
|
| 556 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 557 |
+
|
| 558 |
+
} // namespace threadblock
|
| 559 |
+
} // namespace epilogue
|
| 560 |
+
} // namespace cutlass
|
| 561 |
+
|
| 562 |
+
////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_direct_conv.h
ADDED
|
@@ -0,0 +1,445 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief Epilogue for threadblock scoped GEMMs using Tensor Ops.
|
| 33 |
+
|
| 34 |
+
The epilogue rearranges the result of a matrix product through shared memory to match canonical
|
| 35 |
+
tensor layouts in global memory. Epilogues support conversion and reduction operations.
|
| 36 |
+
|
| 37 |
+
*/
|
| 38 |
+
|
| 39 |
+
#pragma once
|
| 40 |
+
|
| 41 |
+
#include "cutlass/cutlass.h"
|
| 42 |
+
#include "cutlass/numeric_types.h"
|
| 43 |
+
#include "cutlass/array.h"
|
| 44 |
+
#include "cutlass/layout/matrix.h"
|
| 45 |
+
#include "cutlass/layout/tensor.h"
|
| 46 |
+
#include "cutlass/layout/permute.h"
|
| 47 |
+
#include "cutlass/matrix_shape.h"
|
| 48 |
+
#include "cutlass/tensor_ref.h"
|
| 49 |
+
#include "cutlass/transform/pitch_linear_thread_map.h"
|
| 50 |
+
#include "cutlass/epilogue/threadblock/output_tile_thread_map.h"
|
| 51 |
+
#include "cutlass/arch/arch.h"
|
| 52 |
+
#include "cutlass/arch/memory.h"
|
| 53 |
+
#include "cutlass/epilogue/threadblock/predicated_tile_iterator_params.h"
|
| 54 |
+
#include "cutlass/conv/conv2d_problem_size.h"
|
| 55 |
+
|
| 56 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 57 |
+
|
| 58 |
+
namespace cutlass {
|
| 59 |
+
|
| 60 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 61 |
+
|
| 62 |
+
namespace epilogue {
|
| 63 |
+
namespace threadblock {
|
| 64 |
+
|
| 65 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 66 |
+
|
| 67 |
+
/// Tile iterator used to load and store output tile from global memory in epilogue.
|
| 68 |
+
///
|
| 69 |
+
/// Satisfies: ReadableTileIterator | PredicatedTileIterator | ForwardTileIterator
|
| 70 |
+
///
|
| 71 |
+
template <
|
| 72 |
+
typename ThreadMap_, ///< Thread map (conept: PitchLinearThreadMap)
|
| 73 |
+
typename Element_, ///< Element data type
|
| 74 |
+
typename ThreadOutputShape_ = cutlass::conv::TensorNHWCShape<1, 1, 1, 1>,
|
| 75 |
+
typename ThreadBlockOutputShape_ = cutlass::conv::TensorNHWCShape<1, 1, 1, 1>
|
| 76 |
+
>
|
| 77 |
+
class PredicatedTileIteratorDirectConv {
|
| 78 |
+
public:
|
| 79 |
+
using ThreadMap = ThreadMap_;
|
| 80 |
+
using Shape = typename ThreadMap::Shape;
|
| 81 |
+
using ThreadOutputShape = ThreadOutputShape_;
|
| 82 |
+
using ThreadBlockOutputShape = ThreadBlockOutputShape_;
|
| 83 |
+
|
| 84 |
+
using Element = Element_;
|
| 85 |
+
|
| 86 |
+
using Layout = layout::RowMajor;
|
| 87 |
+
using TensorRef = TensorRef<Element, Layout>;
|
| 88 |
+
using ConstTensorRef = typename TensorRef::ConstTensorRef;
|
| 89 |
+
|
| 90 |
+
using Index = typename Layout::Index;
|
| 91 |
+
using LongIndex = typename Layout::LongIndex;
|
| 92 |
+
using TensorCoord = MatrixCoord;
|
| 93 |
+
|
| 94 |
+
static int const kElementsPerAccess = ThreadMap::kElementsPerAccess;
|
| 95 |
+
static int const kThreads = ThreadMap::kThreads;
|
| 96 |
+
|
| 97 |
+
using ConvProblemSize = typename cutlass::conv::Conv2dProblemSize;
|
| 98 |
+
|
| 99 |
+
/// Fragment object
|
| 100 |
+
using Fragment = Array<Element, ThreadMap::Iterations::kCount * kElementsPerAccess>;
|
| 101 |
+
|
| 102 |
+
/// Memory access size
|
| 103 |
+
using AccessType = AlignedArray<Element, kElementsPerAccess>;
|
| 104 |
+
|
| 105 |
+
static int const kLoadsPerAccess = AccessType::kElements / AccessType::kElements;
|
| 106 |
+
|
| 107 |
+
using ThreadTileCount = MatrixShape<
|
| 108 |
+
ThreadBlockOutputShape::kH / ThreadOutputShape::kH,
|
| 109 |
+
ThreadBlockOutputShape::kW / ThreadOutputShape::kW
|
| 110 |
+
>;
|
| 111 |
+
|
| 112 |
+
//
|
| 113 |
+
// Parameters struct
|
| 114 |
+
//
|
| 115 |
+
|
| 116 |
+
/// Uses a non-template class
|
| 117 |
+
struct Params : PredicatedTileIteratorDirect2dConvParams {
|
| 118 |
+
using Base = PredicatedTileIteratorDirect2dConvParams;
|
| 119 |
+
|
| 120 |
+
CUTLASS_HOST_DEVICE
|
| 121 |
+
Params() { }
|
| 122 |
+
|
| 123 |
+
CUTLASS_HOST_DEVICE
|
| 124 |
+
Params(Layout const &layout, cutlass::conv::Conv2dProblemSize const &problem_size):
|
| 125 |
+
PredicatedTileIteratorDirect2dConvParams(
|
| 126 |
+
layout.stride(0) * int(sizeof(AccessType)) / kElementsPerAccess,
|
| 127 |
+
problem_size,
|
| 128 |
+
{ThreadBlockOutputShape::kH, ThreadBlockOutputShape::kW}
|
| 129 |
+
)
|
| 130 |
+
{ }
|
| 131 |
+
|
| 132 |
+
CUTLASS_HOST_DEVICE
|
| 133 |
+
Params(Base const &base) :
|
| 134 |
+
Base(base) { }
|
| 135 |
+
};
|
| 136 |
+
|
| 137 |
+
/// Mask object
|
| 138 |
+
struct Mask {
|
| 139 |
+
|
| 140 |
+
static int const kCount = ThreadMap::Iterations::kContiguous;
|
| 141 |
+
|
| 142 |
+
/// Predicate state
|
| 143 |
+
bool predicates[kCount];
|
| 144 |
+
|
| 145 |
+
//
|
| 146 |
+
// Mask
|
| 147 |
+
//
|
| 148 |
+
CUTLASS_HOST_DEVICE
|
| 149 |
+
Mask() {
|
| 150 |
+
enable();
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
///< Efficiently disables all accesses guarded by mask
|
| 154 |
+
CUTLASS_HOST_DEVICE void clear() {
|
| 155 |
+
CUTLASS_PRAGMA_UNROLL
|
| 156 |
+
for (int i = 0; i < kCount; ++i) {
|
| 157 |
+
predicates[i] = false;
|
| 158 |
+
}
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
///< CUTLASS_HOST_DEVICE enables all accesses guarded by mask
|
| 162 |
+
CUTLASS_DEVICE void enable() {
|
| 163 |
+
CUTLASS_PRAGMA_UNROLL
|
| 164 |
+
for (int i = 0; i < kCount; ++i) {
|
| 165 |
+
predicates[i] = true;
|
| 166 |
+
}
|
| 167 |
+
}
|
| 168 |
+
};
|
| 169 |
+
|
| 170 |
+
private:
|
| 171 |
+
|
| 172 |
+
//
|
| 173 |
+
// Data members
|
| 174 |
+
//
|
| 175 |
+
|
| 176 |
+
/// Parameters structure containing reference and precomputed state.
|
| 177 |
+
PredicatedTileIteratorDirect2dConvParams params_;
|
| 178 |
+
|
| 179 |
+
/// Byte-level pointer
|
| 180 |
+
uint8_t *byte_pointer_;
|
| 181 |
+
|
| 182 |
+
///
|
| 183 |
+
Element *pointer_;
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
/// Array of boolean values to contain steady-state predicates
|
| 187 |
+
Mask mask_;
|
| 188 |
+
|
| 189 |
+
/// Extent of the matrix tile in rows
|
| 190 |
+
Index extent_row_;
|
| 191 |
+
|
| 192 |
+
/// Extent of the matrix tile in rows
|
| 193 |
+
Index extent_column_;
|
| 194 |
+
|
| 195 |
+
/// A thread's starting row position (assuming steady-state predicates have been computed)
|
| 196 |
+
Index thread_start_row_;
|
| 197 |
+
|
| 198 |
+
/// A thread's starting column
|
| 199 |
+
Index thread_start_column_;
|
| 200 |
+
|
| 201 |
+
/// Initial thread output location
|
| 202 |
+
int thread_start_n_, thread_start_p_, thread_start_q_;
|
| 203 |
+
|
| 204 |
+
/// Current threadblock tile index
|
| 205 |
+
int tile_index_;
|
| 206 |
+
|
| 207 |
+
//
|
| 208 |
+
// Static asserts about internal strides
|
| 209 |
+
//
|
| 210 |
+
|
| 211 |
+
static_assert(sizeof(extent_row_) == 4, "Expected 32b extents");
|
| 212 |
+
static_assert(sizeof(thread_start_row_) == 4, "Expected 32b extents");
|
| 213 |
+
static_assert(sizeof(PredicatedTileIteratorDirect2dConvParams::stride) == 8, "Expected 64b strides");
|
| 214 |
+
|
| 215 |
+
private:
|
| 216 |
+
|
| 217 |
+
//
|
| 218 |
+
// Methods
|
| 219 |
+
//
|
| 220 |
+
|
| 221 |
+
|
| 222 |
+
|
| 223 |
+
public:
|
| 224 |
+
|
| 225 |
+
//
|
| 226 |
+
// Methods
|
| 227 |
+
//
|
| 228 |
+
|
| 229 |
+
/// Constructor
|
| 230 |
+
CUTLASS_DEVICE
|
| 231 |
+
PredicatedTileIteratorDirectConv(
|
| 232 |
+
PredicatedTileIteratorDirect2dConvParams const & params,
|
| 233 |
+
Element *pointer,
|
| 234 |
+
TensorCoord extent,
|
| 235 |
+
int thread_idx,
|
| 236 |
+
TensorCoord threadblock_offset = TensorCoord()
|
| 237 |
+
):
|
| 238 |
+
params_(params), pointer_(pointer)
|
| 239 |
+
{
|
| 240 |
+
|
| 241 |
+
TensorCoord thread_offset = ThreadMap::initial_offset(thread_idx);
|
| 242 |
+
|
| 243 |
+
extent_row_ = extent.row();
|
| 244 |
+
extent_column_ = extent.column();
|
| 245 |
+
|
| 246 |
+
// stride dim (PQ)
|
| 247 |
+
thread_start_row_ = thread_offset.column();
|
| 248 |
+
// contiguous dim (Channels)
|
| 249 |
+
thread_start_column_ = threadblock_offset.column() + thread_offset.row();
|
| 250 |
+
|
| 251 |
+
tile_index_ = threadblock_offset.row();
|
| 252 |
+
|
| 253 |
+
set_tile_index(0);
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
/// Adds a pointer offset in units of Element
|
| 257 |
+
CUTLASS_HOST_DEVICE
|
| 258 |
+
void set_tile_index(const int index) {
|
| 259 |
+
|
| 260 |
+
int residual;
|
| 261 |
+
params_.pq_divmod(thread_start_n_, residual, tile_index_ + index);
|
| 262 |
+
params_.q_divmod(thread_start_p_, thread_start_q_, residual);
|
| 263 |
+
|
| 264 |
+
// Compute the base output coord of ThreadBlock
|
| 265 |
+
thread_start_p_ *= ThreadBlockOutputShape::kH;
|
| 266 |
+
thread_start_q_ *= ThreadBlockOutputShape::kW;
|
| 267 |
+
|
| 268 |
+
// Initialize predicates
|
| 269 |
+
CUTLASS_PRAGMA_UNROLL
|
| 270 |
+
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
|
| 271 |
+
mask_.predicates[c] = ((thread_start_column_
|
| 272 |
+
+ c * ThreadMap::Delta::kContiguous) < extent_column_);
|
| 273 |
+
}
|
| 274 |
+
|
| 275 |
+
// Null pointer performs no accesses
|
| 276 |
+
if (!pointer_) {
|
| 277 |
+
mask_.clear();
|
| 278 |
+
}
|
| 279 |
+
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
+
/// Adds a pointer offset in units of Element
|
| 283 |
+
CUTLASS_HOST_DEVICE
|
| 284 |
+
void add_pointer_offset(LongIndex pointer_offset) {
|
| 285 |
+
byte_pointer_ += pointer_offset * sizeof_bits<Element>::value / 8;
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
/// Loads a fragment from memory
|
| 289 |
+
CUTLASS_DEVICE
|
| 290 |
+
void load_with_byte_offset(Fragment &frag, int64_t byte_offset) const {
|
| 291 |
+
CUTLASS_PRAGMA_UNROLL
|
| 292 |
+
for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) {
|
| 293 |
+
CUTLASS_PRAGMA_UNROLL
|
| 294 |
+
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
|
| 295 |
+
int frag_base_idx = s * ThreadMap::Iterations::kContiguous + c;
|
| 296 |
+
|
| 297 |
+
int current_row = thread_start_row_ + s * ThreadMap::Delta::kStrided;
|
| 298 |
+
int p = current_row / ThreadBlockOutputShape::kW;
|
| 299 |
+
int q = current_row % ThreadBlockOutputShape::kW;
|
| 300 |
+
|
| 301 |
+
int current_p = thread_start_p_ + p;
|
| 302 |
+
int current_q = thread_start_q_ + q;
|
| 303 |
+
|
| 304 |
+
bool row_guard = (current_p) < params_.P && (current_q) < params_.Q &&
|
| 305 |
+
(thread_start_n_ < params_.N) && current_row < ThreadMap::Shape::kStrided;
|
| 306 |
+
|
| 307 |
+
int output_row_offset =
|
| 308 |
+
thread_start_n_ * params_.stride_n + current_p * params_.stride_p + current_q;
|
| 309 |
+
|
| 310 |
+
uint8_t *byte_pointer =
|
| 311 |
+
reinterpret_cast<uint8_t *>(pointer_) +
|
| 312 |
+
LongIndex(output_row_offset) * LongIndex(params_.stride) +
|
| 313 |
+
LongIndex(thread_start_column_ + c * ThreadMap::Delta::kContiguous) *
|
| 314 |
+
sizeof(AccessType) / kElementsPerAccess;
|
| 315 |
+
|
| 316 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 317 |
+
|
| 318 |
+
AccessType *memory_pointer = reinterpret_cast<AccessType *>(byte_pointer + byte_offset);
|
| 319 |
+
|
| 320 |
+
bool guard = row_guard && mask_.predicates[c];
|
| 321 |
+
|
| 322 |
+
cutlass::arch::global_load<AccessType, sizeof(AccessType)>(
|
| 323 |
+
frag_ptr[frag_base_idx], (void *)&memory_pointer[0], guard);
|
| 324 |
+
}
|
| 325 |
+
}
|
| 326 |
+
}
|
| 327 |
+
|
| 328 |
+
/// Loads a fragment from memory
|
| 329 |
+
CUTLASS_DEVICE
|
| 330 |
+
void load(Fragment &frag) const {
|
| 331 |
+
load_with_byte_offset(frag, 0);
|
| 332 |
+
}
|
| 333 |
+
|
| 334 |
+
/// Stores a fragment to memory
|
| 335 |
+
CUTLASS_DEVICE
|
| 336 |
+
void store_with_byte_offset(Fragment const &frag, int64_t byte_offset) const {
|
| 337 |
+
CUTLASS_PRAGMA_UNROLL
|
| 338 |
+
for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) {
|
| 339 |
+
CUTLASS_PRAGMA_UNROLL
|
| 340 |
+
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
|
| 341 |
+
int frag_base_idx = s * ThreadMap::Iterations::kContiguous + c;
|
| 342 |
+
|
| 343 |
+
int current_row = thread_start_row_ + s * ThreadMap::Delta::kStrided;
|
| 344 |
+
int p = current_row / ThreadBlockOutputShape::kW;
|
| 345 |
+
int q = current_row % ThreadBlockOutputShape::kW;
|
| 346 |
+
|
| 347 |
+
int current_p = thread_start_p_ + p;
|
| 348 |
+
int current_q = thread_start_q_ + q;
|
| 349 |
+
|
| 350 |
+
bool row_guard = (current_p) < params_.P && (current_q) < params_.Q &&
|
| 351 |
+
(thread_start_n_ < params_.N) && current_row < ThreadMap::Shape::kStrided;
|
| 352 |
+
|
| 353 |
+
int output_row_offset =
|
| 354 |
+
thread_start_n_ * params_.stride_n + current_p * params_.stride_p + current_q;
|
| 355 |
+
|
| 356 |
+
uint8_t *byte_pointer =
|
| 357 |
+
reinterpret_cast<uint8_t *>(pointer_) +
|
| 358 |
+
LongIndex(output_row_offset) * LongIndex(params_.stride) +
|
| 359 |
+
LongIndex(thread_start_column_ + c * ThreadMap::Delta::kContiguous) *
|
| 360 |
+
sizeof(AccessType) / kElementsPerAccess;
|
| 361 |
+
|
| 362 |
+
AccessType const *frag_ptr = reinterpret_cast<AccessType const *>(&frag);
|
| 363 |
+
|
| 364 |
+
AccessType *memory_pointer = reinterpret_cast<AccessType *>(byte_pointer + byte_offset);
|
| 365 |
+
|
| 366 |
+
bool guard = row_guard && mask_.predicates[c];
|
| 367 |
+
|
| 368 |
+
cutlass::arch::global_store<AccessType, sizeof(AccessType)>(
|
| 369 |
+
frag_ptr[frag_base_idx], (void *)&memory_pointer[0], guard);
|
| 370 |
+
}
|
| 371 |
+
}
|
| 372 |
+
}
|
| 373 |
+
|
| 374 |
+
/// Stores a fragment to memory
|
| 375 |
+
CUTLASS_DEVICE
|
| 376 |
+
void store(Fragment const &frag) const {
|
| 377 |
+
|
| 378 |
+
store_with_byte_offset(frag, 0);
|
| 379 |
+
}
|
| 380 |
+
|
| 381 |
+
CUTLASS_DEVICE
|
| 382 |
+
MatrixCoord thread_start() const {
|
| 383 |
+
return MatrixCoord(thread_start_row_, thread_start_column_);
|
| 384 |
+
}
|
| 385 |
+
|
| 386 |
+
/// Need to get the thread start row from the tile iterator
|
| 387 |
+
CUTLASS_DEVICE
|
| 388 |
+
int32_t thread_start_row() const {
|
| 389 |
+
return thread_start_row_;
|
| 390 |
+
}
|
| 391 |
+
|
| 392 |
+
/// Need to get the thread start row from the tile iterator
|
| 393 |
+
CUTLASS_DEVICE
|
| 394 |
+
int32_t thread_start_column() const {
|
| 395 |
+
return thread_start_column_;
|
| 396 |
+
}
|
| 397 |
+
|
| 398 |
+
/// Extent of the matrix in rows
|
| 399 |
+
CUTLASS_DEVICE
|
| 400 |
+
Index extent_row() const {
|
| 401 |
+
return extent_row_;
|
| 402 |
+
}
|
| 403 |
+
|
| 404 |
+
/// Extent of the matrix in columns
|
| 405 |
+
CUTLASS_DEVICE
|
| 406 |
+
Index extent_column() const {
|
| 407 |
+
return extent_column_;
|
| 408 |
+
}
|
| 409 |
+
|
| 410 |
+
/// Advances to the next position to load or store
|
| 411 |
+
CUTLASS_HOST_DEVICE
|
| 412 |
+
PredicatedTileIteratorDirectConv &operator++() {
|
| 413 |
+
// do nothing
|
| 414 |
+
|
| 415 |
+
return *this;
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
+
///< Efficiently disables all accesses guarded by mask
|
| 419 |
+
CUTLASS_DEVICE void clear_mask() {
|
| 420 |
+
mask_.clear();
|
| 421 |
+
}
|
| 422 |
+
|
| 423 |
+
///< Efficiently enables all accesses guarded by mask
|
| 424 |
+
CUTLASS_DEVICE void enable_mask() {
|
| 425 |
+
mask_.enable();
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
///< Sets the mask
|
| 429 |
+
CUTLASS_DEVICE void get_mask(Mask &mask) const {
|
| 430 |
+
mask = mask_;
|
| 431 |
+
}
|
| 432 |
+
|
| 433 |
+
///< Sets the mask
|
| 434 |
+
CUTLASS_DEVICE void set_mask(Mask const &mask) {
|
| 435 |
+
mask_ = mask;
|
| 436 |
+
}
|
| 437 |
+
};
|
| 438 |
+
|
| 439 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 440 |
+
|
| 441 |
+
} // namespace threadblock
|
| 442 |
+
} // namespace epilogue
|
| 443 |
+
} // namespace cutlass
|
| 444 |
+
|
| 445 |
+
////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_params.h
ADDED
|
@@ -0,0 +1,483 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief
|
| 33 |
+
*/
|
| 34 |
+
|
| 35 |
+
#pragma once
|
| 36 |
+
|
| 37 |
+
#include "cutlass/cutlass.h"
|
| 38 |
+
|
| 39 |
+
#include "cutlass/layout/pitch_linear.h"
|
| 40 |
+
#include "cutlass/layout/matrix.h"
|
| 41 |
+
|
| 42 |
+
#include "cutlass/conv/conv2d_problem_size.h"
|
| 43 |
+
|
| 44 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 45 |
+
|
| 46 |
+
namespace cutlass {
|
| 47 |
+
namespace epilogue {
|
| 48 |
+
namespace threadblock {
|
| 49 |
+
|
| 50 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 51 |
+
|
| 52 |
+
struct OutputTileShapeDesc {
|
| 53 |
+
|
| 54 |
+
int column;
|
| 55 |
+
int row;
|
| 56 |
+
int group;
|
| 57 |
+
int cluster;
|
| 58 |
+
int tile;
|
| 59 |
+
|
| 60 |
+
//
|
| 61 |
+
// Methods
|
| 62 |
+
//
|
| 63 |
+
|
| 64 |
+
/// Default ctor
|
| 65 |
+
CUTLASS_HOST_DEVICE
|
| 66 |
+
OutputTileShapeDesc(): column(0), row(0), group(0), cluster(0), tile(0) { }
|
| 67 |
+
|
| 68 |
+
/// Ctor
|
| 69 |
+
CUTLASS_HOST_DEVICE
|
| 70 |
+
OutputTileShapeDesc(
|
| 71 |
+
int column_,
|
| 72 |
+
int row_,
|
| 73 |
+
int group_,
|
| 74 |
+
int cluster_,
|
| 75 |
+
int tile_
|
| 76 |
+
):
|
| 77 |
+
column(column_),
|
| 78 |
+
row(row_),
|
| 79 |
+
group(group_),
|
| 80 |
+
cluster(cluster_),
|
| 81 |
+
tile(tile_) { }
|
| 82 |
+
|
| 83 |
+
/// Total number of points in the 5D space
|
| 84 |
+
CUTLASS_HOST_DEVICE
|
| 85 |
+
int count() const {
|
| 86 |
+
return column * row * group * cluster * tile;
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
#if 0
|
| 90 |
+
CUTLASS_HOST_DEVICE
|
| 91 |
+
void print() const {
|
| 92 |
+
printf("{%d, %d, %d, %d, %d}", column, row, group, cluster, tile);
|
| 93 |
+
}
|
| 94 |
+
#endif
|
| 95 |
+
};
|
| 96 |
+
|
| 97 |
+
/// Helper template to construct an OutputTileShapeDesc from a OutputTileShape template.
|
| 98 |
+
template <typename Shape>
|
| 99 |
+
CUTLASS_HOST_DEVICE
|
| 100 |
+
OutputTileShapeDesc make_OutputTileShapeDesc() {
|
| 101 |
+
return OutputTileShapeDesc(
|
| 102 |
+
Shape::kColumn,
|
| 103 |
+
Shape::kRow,
|
| 104 |
+
Shape::kGroup,
|
| 105 |
+
Shape::kCluster,
|
| 106 |
+
Shape::kTile
|
| 107 |
+
);
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 111 |
+
|
| 112 |
+
/// Thread map description
|
| 113 |
+
struct OutputTileThreadMapDesc {
|
| 114 |
+
|
| 115 |
+
int threads;
|
| 116 |
+
int elements_per_access;
|
| 117 |
+
OutputTileShapeDesc shape;
|
| 118 |
+
OutputTileShapeDesc iterations;
|
| 119 |
+
OutputTileShapeDesc delta;
|
| 120 |
+
OutputTileShapeDesc count;
|
| 121 |
+
|
| 122 |
+
//
|
| 123 |
+
// Methods
|
| 124 |
+
//
|
| 125 |
+
|
| 126 |
+
CUTLASS_HOST_DEVICE
|
| 127 |
+
OutputTileThreadMapDesc() { }
|
| 128 |
+
|
| 129 |
+
CUTLASS_HOST_DEVICE
|
| 130 |
+
OutputTileThreadMapDesc(
|
| 131 |
+
int threads_,
|
| 132 |
+
int elements_per_access_,
|
| 133 |
+
OutputTileShapeDesc shape_,
|
| 134 |
+
OutputTileShapeDesc iterations_,
|
| 135 |
+
OutputTileShapeDesc delta_,
|
| 136 |
+
OutputTileShapeDesc count_
|
| 137 |
+
):
|
| 138 |
+
threads(threads_),
|
| 139 |
+
elements_per_access(elements_per_access_),
|
| 140 |
+
shape(shape_),
|
| 141 |
+
iterations(iterations_),
|
| 142 |
+
delta(delta_),
|
| 143 |
+
count(count_)
|
| 144 |
+
{
|
| 145 |
+
|
| 146 |
+
}
|
| 147 |
+
};
|
| 148 |
+
|
| 149 |
+
/// Helper template to construct an OutputTileShapeDesc from a OutputTileThreadMap template.
|
| 150 |
+
template <typename ThreadMap>
|
| 151 |
+
CUTLASS_HOST_DEVICE
|
| 152 |
+
OutputTileThreadMapDesc make_OutputTileThreadMapDesc() {
|
| 153 |
+
return OutputTileThreadMapDesc(
|
| 154 |
+
ThreadMap::kThreads,
|
| 155 |
+
ThreadMap::kElementsPerAccess,
|
| 156 |
+
make_OutputTileShapeDesc<typename ThreadMap::Shape>(),
|
| 157 |
+
make_OutputTileShapeDesc<typename ThreadMap::Iterations>(),
|
| 158 |
+
make_OutputTileShapeDesc<typename ThreadMap::Delta>(),
|
| 159 |
+
make_OutputTileShapeDesc<typename ThreadMap::Count>()
|
| 160 |
+
);
|
| 161 |
+
}
|
| 162 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 163 |
+
|
| 164 |
+
//
|
| 165 |
+
// Parameters struct for PredicatedTileIterator
|
| 166 |
+
//
|
| 167 |
+
|
| 168 |
+
struct PredicatedTileIteratorParams {
|
| 169 |
+
|
| 170 |
+
using Index = int32_t;
|
| 171 |
+
using LongIndex = int64_t;
|
| 172 |
+
|
| 173 |
+
//
|
| 174 |
+
// Data members
|
| 175 |
+
//
|
| 176 |
+
|
| 177 |
+
LongIndex stride; ///< stride in bytes between rows
|
| 178 |
+
|
| 179 |
+
LongIndex increment_row; ///< increment quantity (in bytes) to advance when moving between rows
|
| 180 |
+
LongIndex increment_group; ///< increment quantity (in bytes) to advance when moving to the next group
|
| 181 |
+
LongIndex increment_cluster; ///< increment quantity (in bytes) to advance when moving to the next cluster
|
| 182 |
+
|
| 183 |
+
LongIndex advance_row; ///< amount to add to move to the next 'row' position
|
| 184 |
+
LongIndex advance_group; ///< amount to add to move to the next 'group' position
|
| 185 |
+
LongIndex advance_cluster; ///< amount to add to move to the next 'cluster' position
|
| 186 |
+
LongIndex advance_tile; ///< amount to add to move to the next 'tile'
|
| 187 |
+
|
| 188 |
+
//
|
| 189 |
+
// Methods
|
| 190 |
+
//
|
| 191 |
+
|
| 192 |
+
CUTLASS_HOST_DEVICE
|
| 193 |
+
Status initialize(LongIndex stride_, OutputTileThreadMapDesc thread_map) {
|
| 194 |
+
|
| 195 |
+
stride = stride_;
|
| 196 |
+
|
| 197 |
+
increment_row = stride * thread_map.delta.row;
|
| 198 |
+
|
| 199 |
+
increment_group = stride * thread_map.delta.group
|
| 200 |
+
- stride * thread_map.delta.row * (thread_map.iterations.row - 1);
|
| 201 |
+
|
| 202 |
+
increment_cluster = stride * thread_map.delta.cluster
|
| 203 |
+
- stride * thread_map.delta.group * (thread_map.iterations.group - 1)
|
| 204 |
+
- stride * thread_map.delta.row * (thread_map.iterations.row - 1);
|
| 205 |
+
|
| 206 |
+
advance_row = stride * thread_map.shape.row;
|
| 207 |
+
|
| 208 |
+
advance_group =
|
| 209 |
+
stride *
|
| 210 |
+
(thread_map.shape.group - 1) * thread_map.shape.row * thread_map.count.row;
|
| 211 |
+
|
| 212 |
+
advance_cluster =
|
| 213 |
+
stride *
|
| 214 |
+
thread_map.count.group *
|
| 215 |
+
thread_map.shape.group *
|
| 216 |
+
thread_map.count.row *
|
| 217 |
+
thread_map.shape.row;
|
| 218 |
+
|
| 219 |
+
advance_tile =
|
| 220 |
+
stride *
|
| 221 |
+
thread_map.shape.group *
|
| 222 |
+
thread_map.shape.row *
|
| 223 |
+
thread_map.shape.cluster *
|
| 224 |
+
thread_map.shape.tile;
|
| 225 |
+
|
| 226 |
+
return Status::kSuccess;
|
| 227 |
+
}
|
| 228 |
+
|
| 229 |
+
CUTLASS_HOST_DEVICE
|
| 230 |
+
Status initialize(Index stride_, OutputTileThreadMapDesc thread_map) {
|
| 231 |
+
return initialize(LongIndex(stride_), thread_map);
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
CUTLASS_HOST_DEVICE
|
| 235 |
+
PredicatedTileIteratorParams() {
|
| 236 |
+
initialize(LongIndex(0), OutputTileThreadMapDesc());
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
CUTLASS_HOST_DEVICE
|
| 240 |
+
PredicatedTileIteratorParams(Index stride, OutputTileThreadMapDesc thread_map) {
|
| 241 |
+
initialize(stride, thread_map);
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
CUTLASS_HOST_DEVICE
|
| 245 |
+
PredicatedTileIteratorParams(LongIndex stride, OutputTileThreadMapDesc thread_map) {
|
| 246 |
+
initialize(stride, thread_map);
|
| 247 |
+
}
|
| 248 |
+
};
|
| 249 |
+
|
| 250 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 251 |
+
|
| 252 |
+
//
|
| 253 |
+
// Parameters struct for PredicatedTileIteratorDirect2dConv
|
| 254 |
+
//
|
| 255 |
+
|
| 256 |
+
struct PredicatedTileIteratorDirect2dConvParams{
|
| 257 |
+
using Index = int32_t;
|
| 258 |
+
using LongIndex = int64_t;
|
| 259 |
+
|
| 260 |
+
//
|
| 261 |
+
// Data members
|
| 262 |
+
//
|
| 263 |
+
FastDivmod pq_divmod;
|
| 264 |
+
FastDivmod q_divmod;
|
| 265 |
+
|
| 266 |
+
LongIndex stride;
|
| 267 |
+
LongIndex stride_n;
|
| 268 |
+
LongIndex stride_p;
|
| 269 |
+
|
| 270 |
+
int N;
|
| 271 |
+
int P;
|
| 272 |
+
int Q;
|
| 273 |
+
|
| 274 |
+
//
|
| 275 |
+
// Methods
|
| 276 |
+
//
|
| 277 |
+
|
| 278 |
+
CUTLASS_HOST_DEVICE
|
| 279 |
+
Status initialize(LongIndex stride_,
|
| 280 |
+
cutlass::conv::Conv2dProblemSize const &problem_size,
|
| 281 |
+
MatrixCoord threadblock_output_shape) {
|
| 282 |
+
stride = stride_; // The stride per row of output tensor (bytes)
|
| 283 |
+
stride_n = problem_size.P * problem_size.Q;
|
| 284 |
+
stride_p = problem_size.Q ;
|
| 285 |
+
|
| 286 |
+
N = problem_size.N;
|
| 287 |
+
P = problem_size.P;
|
| 288 |
+
Q = problem_size.Q;
|
| 289 |
+
|
| 290 |
+
// Fastdivmod for output O, P, Q
|
| 291 |
+
if(threadblock_output_shape.row() != 0 && threadblock_output_shape.column() !=0 ){
|
| 292 |
+
// MSVC emits a "potential divide by 0" warning as error
|
| 293 |
+
// if the code just divides without a check and substitution.
|
| 294 |
+
|
| 295 |
+
CUTLASS_ASSERT(threadblock_output_shape.row() != 0);
|
| 296 |
+
const auto row_denom = threadblock_output_shape.row() != 0 ?
|
| 297 |
+
threadblock_output_shape.row() : cutlass::MatrixCoord::Index(1);
|
| 298 |
+
int tiles_p =
|
| 299 |
+
(problem_size.P + (threadblock_output_shape.row() - 1)) / row_denom;
|
| 300 |
+
|
| 301 |
+
CUTLASS_ASSERT(threadblock_output_shape.column() != 0);
|
| 302 |
+
const auto col_denom = threadblock_output_shape.column() != 0 ?
|
| 303 |
+
threadblock_output_shape.column() : cutlass::MatrixCoord::Index(1);
|
| 304 |
+
int tiles_q = (problem_size.Q + (threadblock_output_shape.column() - 1)) /
|
| 305 |
+
col_denom;
|
| 306 |
+
|
| 307 |
+
pq_divmod = FastDivmod(tiles_p * tiles_q);
|
| 308 |
+
q_divmod = FastDivmod(tiles_q);
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
return Status::kSuccess;
|
| 312 |
+
}
|
| 313 |
+
|
| 314 |
+
CUTLASS_HOST_DEVICE
|
| 315 |
+
Status initialize(
|
| 316 |
+
Index stride_,
|
| 317 |
+
cutlass::conv::Conv2dProblemSize const &problem_size = cutlass::conv::Conv2dProblemSize(),
|
| 318 |
+
MatrixCoord threadblock_output_shape = MatrixCoord()) {
|
| 319 |
+
return initialize(LongIndex(stride_), problem_size, threadblock_output_shape);
|
| 320 |
+
}
|
| 321 |
+
|
| 322 |
+
CUTLASS_HOST_DEVICE
|
| 323 |
+
PredicatedTileIteratorDirect2dConvParams() { initialize(LongIndex(0)); }
|
| 324 |
+
|
| 325 |
+
CUTLASS_HOST_DEVICE
|
| 326 |
+
PredicatedTileIteratorDirect2dConvParams(Index stride,
|
| 327 |
+
cutlass::conv::Conv2dProblemSize const &problem_size,
|
| 328 |
+
MatrixCoord threadblock_output_shape) {
|
| 329 |
+
initialize(stride, problem_size, threadblock_output_shape);
|
| 330 |
+
}
|
| 331 |
+
|
| 332 |
+
CUTLASS_HOST_DEVICE
|
| 333 |
+
PredicatedTileIteratorDirect2dConvParams(LongIndex stride,
|
| 334 |
+
cutlass::conv::Conv2dProblemSize const &problem_size,
|
| 335 |
+
MatrixCoord threadblock_output_shape) {
|
| 336 |
+
initialize(stride, problem_size, threadblock_output_shape);
|
| 337 |
+
}
|
| 338 |
+
};
|
| 339 |
+
|
| 340 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 341 |
+
// InterleavedPredicatedTileIterator
|
| 342 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 343 |
+
|
| 344 |
+
|
| 345 |
+
/// Predicated tile access iterator descriptor object containing template dependent state
|
| 346 |
+
struct InterleavedPredicatedTileIteratorDesc {
|
| 347 |
+
|
| 348 |
+
int element_size_bits;
|
| 349 |
+
int elements_per_access;
|
| 350 |
+
int threadmap_warp_size;
|
| 351 |
+
layout::PitchLinearCoord threadmap_iterations;
|
| 352 |
+
layout::PitchLinearCoord threadmap_delta;
|
| 353 |
+
|
| 354 |
+
//
|
| 355 |
+
// Methods
|
| 356 |
+
//
|
| 357 |
+
|
| 358 |
+
CUTLASS_HOST_DEVICE
|
| 359 |
+
InterleavedPredicatedTileIteratorDesc() { }
|
| 360 |
+
|
| 361 |
+
CUTLASS_HOST_DEVICE
|
| 362 |
+
InterleavedPredicatedTileIteratorDesc(
|
| 363 |
+
int element_size_bits_,
|
| 364 |
+
int elements_per_access_,
|
| 365 |
+
int threadmap_warp_size_,
|
| 366 |
+
layout::PitchLinearCoord threadmap_iterations_,
|
| 367 |
+
layout::PitchLinearCoord threadmap_delta_
|
| 368 |
+
):
|
| 369 |
+
element_size_bits(element_size_bits_),
|
| 370 |
+
elements_per_access(elements_per_access_),
|
| 371 |
+
threadmap_warp_size(threadmap_warp_size_),
|
| 372 |
+
threadmap_iterations(threadmap_iterations_),
|
| 373 |
+
threadmap_delta(threadmap_delta_) { }
|
| 374 |
+
};
|
| 375 |
+
|
| 376 |
+
//
|
| 377 |
+
// Parameters struct InterleavedPredicatedTileIterator
|
| 378 |
+
//
|
| 379 |
+
|
| 380 |
+
struct InterleavedPredicatedTileIteratorParams {
|
| 381 |
+
|
| 382 |
+
using Index = int32_t;
|
| 383 |
+
using LongIndex = int64_t;
|
| 384 |
+
|
| 385 |
+
//
|
| 386 |
+
// Data members
|
| 387 |
+
//
|
| 388 |
+
|
| 389 |
+
LongIndex stride; ///< stride in bytes between rows
|
| 390 |
+
LongIndex advance_row; ///< amount to add to move to the next 'row' position
|
| 391 |
+
LongIndex advance_column; ///< amount to add to move to the next 'column' position
|
| 392 |
+
|
| 393 |
+
//
|
| 394 |
+
// Methods
|
| 395 |
+
//
|
| 396 |
+
|
| 397 |
+
CUTLASS_HOST_DEVICE
|
| 398 |
+
Status initialize(LongIndex stride_, InterleavedPredicatedTileIteratorDesc desc) {
|
| 399 |
+
|
| 400 |
+
stride = stride_;
|
| 401 |
+
|
| 402 |
+
advance_row = desc.threadmap_delta.contiguous() * desc.element_size_bits / 8;
|
| 403 |
+
|
| 404 |
+
advance_column = stride_ - desc.threadmap_iterations.contiguous() *
|
| 405 |
+
desc.elements_per_access *
|
| 406 |
+
desc.element_size_bits *
|
| 407 |
+
desc.threadmap_warp_size / 8;
|
| 408 |
+
|
| 409 |
+
return Status::kSuccess;
|
| 410 |
+
}
|
| 411 |
+
|
| 412 |
+
CUTLASS_HOST_DEVICE
|
| 413 |
+
InterleavedPredicatedTileIteratorParams() {
|
| 414 |
+
initialize(LongIndex(0), InterleavedPredicatedTileIteratorDesc());
|
| 415 |
+
}
|
| 416 |
+
|
| 417 |
+
CUTLASS_HOST_DEVICE
|
| 418 |
+
InterleavedPredicatedTileIteratorParams(Index stride, InterleavedPredicatedTileIteratorDesc desc) {
|
| 419 |
+
initialize(stride, desc);
|
| 420 |
+
}
|
| 421 |
+
|
| 422 |
+
CUTLASS_HOST_DEVICE
|
| 423 |
+
InterleavedPredicatedTileIteratorParams(LongIndex stride, InterleavedPredicatedTileIteratorDesc desc) {
|
| 424 |
+
initialize(stride, desc);
|
| 425 |
+
}
|
| 426 |
+
};
|
| 427 |
+
|
| 428 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 429 |
+
/// Helper template to construct an OutputTileShapeDesc from a OutputTileThreadMap template.
|
| 430 |
+
template <typename Element, typename ThreadMap>
|
| 431 |
+
CUTLASS_HOST_DEVICE
|
| 432 |
+
InterleavedPredicatedTileIteratorDesc make_InterleavedPredicatedTileIteratorDesc() {
|
| 433 |
+
return InterleavedPredicatedTileIteratorDesc(
|
| 434 |
+
sizeof_bits<Element>::value,
|
| 435 |
+
ThreadMap::kElementsPerAccess,
|
| 436 |
+
ThreadMap::kWarpSize,
|
| 437 |
+
{ThreadMap::Iterations::kContiguous, ThreadMap::Iterations::kStrided},
|
| 438 |
+
{ThreadMap::Delta::kContiguous, ThreadMap::Delta::kStrided}
|
| 439 |
+
);
|
| 440 |
+
}
|
| 441 |
+
|
| 442 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 443 |
+
/// Helper template to construct an MakePredicatedTileIteratorDesc from a template
|
| 444 |
+
// dependent state
|
| 445 |
+
template <typename Element, typename Layout,
|
| 446 |
+
typename ThreadMap>
|
| 447 |
+
struct MakePredicatedTileIteratorDesc;
|
| 448 |
+
|
| 449 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 450 |
+
|
| 451 |
+
/// Specialization of PredicatedTileAccessIterator for layout::RowMajor output data.
|
| 452 |
+
template <typename Element, typename ThreadMap>
|
| 453 |
+
struct MakePredicatedTileIteratorDesc <
|
| 454 |
+
Element, layout::RowMajor, ThreadMap> {
|
| 455 |
+
|
| 456 |
+
CUTLASS_HOST_DEVICE
|
| 457 |
+
OutputTileThreadMapDesc operator()() {
|
| 458 |
+
|
| 459 |
+
return make_OutputTileThreadMapDesc<ThreadMap>();
|
| 460 |
+
}
|
| 461 |
+
};
|
| 462 |
+
|
| 463 |
+
|
| 464 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 465 |
+
|
| 466 |
+
/// Specialization of PredicatedTileAccessIterator for layout::ColumnMajorInterleaved<InterleavedN> output data.
|
| 467 |
+
template <typename Element, typename ThreadMap, int InterleavedN>
|
| 468 |
+
struct MakePredicatedTileIteratorDesc <
|
| 469 |
+
Element, layout::ColumnMajorInterleaved<InterleavedN>, ThreadMap> {
|
| 470 |
+
|
| 471 |
+
CUTLASS_HOST_DEVICE
|
| 472 |
+
InterleavedPredicatedTileIteratorDesc operator()() {
|
| 473 |
+
|
| 474 |
+
return make_InterleavedPredicatedTileIteratorDesc<Element, ThreadMap>();
|
| 475 |
+
}
|
| 476 |
+
};
|
| 477 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 478 |
+
|
| 479 |
+
} // namespace threadblock
|
| 480 |
+
} // namespace epilogue
|
| 481 |
+
} // namespace cutlass
|
| 482 |
+
|
| 483 |
+
////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_predicates.h
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief PredicatedTileIteratorPredicates.
|
| 33 |
+
|
| 34 |
+
PredicatedTileIteratorPredicates enables both upper and lower bounds for predicates.
|
| 35 |
+
|
| 36 |
+
*/
|
| 37 |
+
|
| 38 |
+
#pragma once
|
| 39 |
+
|
| 40 |
+
#include "cutlass/cutlass.h"
|
| 41 |
+
#include "cutlass/numeric_types.h"
|
| 42 |
+
#include "cutlass/array.h"
|
| 43 |
+
#include "cutlass/layout/matrix.h"
|
| 44 |
+
#include "cutlass/layout/tensor.h"
|
| 45 |
+
#include "cutlass/matrix_shape.h"
|
| 46 |
+
#include "cutlass/tensor_ref.h"
|
| 47 |
+
#include "cutlass/transform/pitch_linear_thread_map.h"
|
| 48 |
+
#include "cutlass/epilogue/threadblock/output_tile_thread_map.h"
|
| 49 |
+
#include "cutlass/arch/arch.h"
|
| 50 |
+
#include "cutlass/arch/memory.h"
|
| 51 |
+
#include "cutlass/epilogue/threadblock/predicated_tile_iterator_params.h"
|
| 52 |
+
|
| 53 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 54 |
+
|
| 55 |
+
namespace cutlass {
|
| 56 |
+
|
| 57 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 58 |
+
|
| 59 |
+
namespace epilogue {
|
| 60 |
+
namespace threadblock {
|
| 61 |
+
|
| 62 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 63 |
+
|
| 64 |
+
/// Tile iterator predicates used to bound computations in epilogue.
|
| 65 |
+
///
|
| 66 |
+
/// Satisfies: ReadableTileIterator | PredicatedTileIterator | ForwardTileIterator
|
| 67 |
+
///
|
| 68 |
+
template <
|
| 69 |
+
typename ThreadMap_, ///< Thread map (conept: OutputTileThreadMap)
|
| 70 |
+
typename Element_ ///< Element data type
|
| 71 |
+
>
|
| 72 |
+
class PredicatedTileIteratorPredicates {
|
| 73 |
+
public:
|
| 74 |
+
using ThreadMap = ThreadMap_;
|
| 75 |
+
using Shape = typename ThreadMap::Shape;
|
| 76 |
+
|
| 77 |
+
using Element = Element_;
|
| 78 |
+
|
| 79 |
+
using Layout = layout::RowMajor;
|
| 80 |
+
using TensorRef = TensorRef<Element, Layout>;
|
| 81 |
+
using ConstTensorRef = typename TensorRef::ConstTensorRef;
|
| 82 |
+
|
| 83 |
+
using Index = typename Layout::Index;
|
| 84 |
+
using LongIndex = typename Layout::LongIndex;
|
| 85 |
+
using TensorCoord = MatrixCoord;
|
| 86 |
+
|
| 87 |
+
static int const kElementsPerAccess = ThreadMap::kElementsPerAccess;
|
| 88 |
+
static int const kThreads = ThreadMap::kThreads;
|
| 89 |
+
static int const kIterations = ThreadMap::Count::kTile;
|
| 90 |
+
|
| 91 |
+
static_assert( ThreadMap::Iterations::kRow > 0,"ThreadMap::Iterations::kRow must be > 0");
|
| 92 |
+
static_assert( ThreadMap::Iterations::kGroup > 0,"ThreadMap::Iterations::kGroup must be > 0");
|
| 93 |
+
static_assert( ThreadMap::Iterations::kCluster > 0,"ThreadMap::Iterations::kCluster must be > 0");
|
| 94 |
+
static_assert( ThreadMap::Iterations::kColumn > 0,"ThreadMap::Iterations::kColumn must be > 0");
|
| 95 |
+
|
| 96 |
+
/// Fragment object
|
| 97 |
+
using Fragment = Array<
|
| 98 |
+
Element,
|
| 99 |
+
ThreadMap::Iterations::kColumn *
|
| 100 |
+
ThreadMap::Iterations::kRow *
|
| 101 |
+
ThreadMap::Iterations::kGroup *
|
| 102 |
+
ThreadMap::Iterations::kCluster * ThreadMap::kElementsPerAccess>;
|
| 103 |
+
|
| 104 |
+
/// Memory access size
|
| 105 |
+
using AccessType = AlignedArray<Element, ThreadMap::kElementsPerAccess>;
|
| 106 |
+
|
| 107 |
+
//
|
| 108 |
+
// Parameters struct
|
| 109 |
+
//
|
| 110 |
+
|
| 111 |
+
/// Uses a non-template class
|
| 112 |
+
struct Params : PredicatedTileIteratorParams {
|
| 113 |
+
|
| 114 |
+
CUTLASS_HOST_DEVICE
|
| 115 |
+
Params() { }
|
| 116 |
+
|
| 117 |
+
CUTLASS_HOST_DEVICE
|
| 118 |
+
Params(Layout const &layout):
|
| 119 |
+
PredicatedTileIteratorParams(
|
| 120 |
+
layout.stride(0) * int(sizeof(AccessType)) / kElementsPerAccess,
|
| 121 |
+
make_OutputTileThreadMapDesc<ThreadMap>()
|
| 122 |
+
)
|
| 123 |
+
{
|
| 124 |
+
|
| 125 |
+
}
|
| 126 |
+
};
|
| 127 |
+
|
| 128 |
+
/// Mask object
|
| 129 |
+
struct Mask {
|
| 130 |
+
|
| 131 |
+
static int const kCount = ThreadMap::Iterations::kColumn;
|
| 132 |
+
|
| 133 |
+
/// Predicate state
|
| 134 |
+
bool predicates[kCount];
|
| 135 |
+
|
| 136 |
+
//
|
| 137 |
+
// Mask
|
| 138 |
+
//
|
| 139 |
+
CUTLASS_HOST_DEVICE
|
| 140 |
+
Mask() {
|
| 141 |
+
enable();
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
///< Efficiently disables all accesses guarded by mask
|
| 145 |
+
CUTLASS_HOST_DEVICE void clear() {
|
| 146 |
+
CUTLASS_PRAGMA_UNROLL
|
| 147 |
+
for (int i = 0; i < kCount; ++i) {
|
| 148 |
+
predicates[i] = false;
|
| 149 |
+
}
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
///< CUTLASS_HOST_DEVICE enables all accesses guarded by mask
|
| 153 |
+
CUTLASS_DEVICE void enable() {
|
| 154 |
+
CUTLASS_PRAGMA_UNROLL
|
| 155 |
+
for (int i = 0; i < kCount; ++i) {
|
| 156 |
+
predicates[i] = true;
|
| 157 |
+
}
|
| 158 |
+
}
|
| 159 |
+
};
|
| 160 |
+
|
| 161 |
+
private:
|
| 162 |
+
|
| 163 |
+
//
|
| 164 |
+
// Data members
|
| 165 |
+
//
|
| 166 |
+
|
| 167 |
+
/// Parameters structure containing reference and precomputed state.
|
| 168 |
+
PredicatedTileIteratorParams params_;
|
| 169 |
+
|
| 170 |
+
/// Array of boolean values to contain steady-state predicates
|
| 171 |
+
Mask mask_;
|
| 172 |
+
|
| 173 |
+
/// Extent of the matrix tile in rows
|
| 174 |
+
Index lower_extent_row_;
|
| 175 |
+
Index upper_extent_row_;
|
| 176 |
+
|
| 177 |
+
/// A thread's starting row position (assuming steady-state predicates have been computed)
|
| 178 |
+
Index thread_start_row_;
|
| 179 |
+
|
| 180 |
+
/// Internal state counter
|
| 181 |
+
int state_[3];
|
| 182 |
+
|
| 183 |
+
//
|
| 184 |
+
// Static asserts about internal strides
|
| 185 |
+
//
|
| 186 |
+
|
| 187 |
+
static_assert(sizeof(lower_extent_row_) == 4, "Expected 32b extents");
|
| 188 |
+
static_assert(sizeof(upper_extent_row_) == 4, "Expected 32b extents");
|
| 189 |
+
static_assert(sizeof(thread_start_row_) == 4, "Expected 32b extents");
|
| 190 |
+
static_assert(sizeof(PredicatedTileIteratorParams::stride) == 8, "Expected 64b strides");
|
| 191 |
+
|
| 192 |
+
private:
|
| 193 |
+
|
| 194 |
+
//
|
| 195 |
+
// Methods
|
| 196 |
+
//
|
| 197 |
+
|
| 198 |
+
public:
|
| 199 |
+
|
| 200 |
+
//
|
| 201 |
+
// Methods
|
| 202 |
+
//
|
| 203 |
+
|
| 204 |
+
/// Constructor
|
| 205 |
+
CUTLASS_DEVICE
|
| 206 |
+
PredicatedTileIteratorPredicates(
|
| 207 |
+
PredicatedTileIteratorParams const & params,
|
| 208 |
+
TensorCoord lower_extent,
|
| 209 |
+
TensorCoord upper_extent,
|
| 210 |
+
int thread_idx,
|
| 211 |
+
TensorCoord threadblock_offset = TensorCoord()
|
| 212 |
+
):
|
| 213 |
+
params_(params)
|
| 214 |
+
{
|
| 215 |
+
|
| 216 |
+
TensorCoord thread_offset = ThreadMap::initial_offset(thread_idx) + threadblock_offset;
|
| 217 |
+
|
| 218 |
+
lower_extent_row_ = lower_extent.row();
|
| 219 |
+
upper_extent_row_ = upper_extent.row();
|
| 220 |
+
thread_start_row_ = thread_offset.row();
|
| 221 |
+
|
| 222 |
+
// Initialize predicates
|
| 223 |
+
CUTLASS_PRAGMA_UNROLL
|
| 224 |
+
for (int c = 0; c < ThreadMap::Iterations::kColumn; ++c) {
|
| 225 |
+
|
| 226 |
+
mask_.predicates[c] = ((thread_offset.column()
|
| 227 |
+
+ ThreadMap::Delta::kColumn * c) < upper_extent.column()) &&
|
| 228 |
+
((thread_offset.column() + ThreadMap::Delta::kColumn * c) >= lower_extent.column());
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
// Initialize internal state counter
|
| 232 |
+
state_[0] = state_[1] = state_[2] = 0;
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
/// Advances to the next position to load or store
|
| 236 |
+
CUTLASS_HOST_DEVICE
|
| 237 |
+
PredicatedTileIteratorPredicates &operator++() {
|
| 238 |
+
|
| 239 |
+
++state_[0];
|
| 240 |
+
thread_start_row_ += ThreadMap::Shape::kRow;
|
| 241 |
+
|
| 242 |
+
if (state_[0] == ThreadMap::Count::kRow) {
|
| 243 |
+
|
| 244 |
+
state_[0] = 0;
|
| 245 |
+
++state_[1];
|
| 246 |
+
|
| 247 |
+
thread_start_row_ += (ThreadMap::Shape::kGroup - 1) *
|
| 248 |
+
ThreadMap::Shape::kRow * ThreadMap::Count::kRow;
|
| 249 |
+
|
| 250 |
+
if (state_[1] == ThreadMap::Count::kGroup) {
|
| 251 |
+
|
| 252 |
+
state_[1] = 0;
|
| 253 |
+
++state_[2];
|
| 254 |
+
|
| 255 |
+
thread_start_row_ += ThreadMap::Count::kGroup *
|
| 256 |
+
ThreadMap::Shape::kGroup * ThreadMap::Count::kRow * ThreadMap::Shape::kRow;
|
| 257 |
+
|
| 258 |
+
if (state_[2] == ThreadMap::Count::kCluster) {
|
| 259 |
+
state_[2] = 0;
|
| 260 |
+
}
|
| 261 |
+
}
|
| 262 |
+
}
|
| 263 |
+
|
| 264 |
+
return *this;
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
///< Efficiently disables all accesses guarded by mask
|
| 268 |
+
CUTLASS_DEVICE void clear_mask() {
|
| 269 |
+
mask_.clear();
|
| 270 |
+
}
|
| 271 |
+
|
| 272 |
+
///< Efficiently enables all accesses guarded by mask
|
| 273 |
+
CUTLASS_DEVICE void enable_mask() {
|
| 274 |
+
mask_.enable();
|
| 275 |
+
}
|
| 276 |
+
|
| 277 |
+
///< Gets the mask
|
| 278 |
+
CUTLASS_DEVICE void get_mask(Mask &mask) {
|
| 279 |
+
mask = mask_;
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
+
///< Sets the mask
|
| 283 |
+
CUTLASS_DEVICE void set_mask(Mask const &mask) {
|
| 284 |
+
mask_ = mask;
|
| 285 |
+
}
|
| 286 |
+
|
| 287 |
+
///< Gets lower_extent_row_
|
| 288 |
+
CUTLASS_DEVICE Index get_lower_extent_row() {
|
| 289 |
+
return lower_extent_row_;
|
| 290 |
+
}
|
| 291 |
+
|
| 292 |
+
///< Gets upper_extent_row_
|
| 293 |
+
CUTLASS_DEVICE Index get_upper_extent_row() {
|
| 294 |
+
return upper_extent_row_;
|
| 295 |
+
}
|
| 296 |
+
|
| 297 |
+
///< Gets thread_start_row_
|
| 298 |
+
CUTLASS_DEVICE Index get_thread_start_row() {
|
| 299 |
+
return thread_start_row_;
|
| 300 |
+
}
|
| 301 |
+
};
|
| 302 |
+
|
| 303 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 304 |
+
|
| 305 |
+
} // namespace threadblock
|
| 306 |
+
} // namespace epilogue
|
| 307 |
+
} // namespace cutlass
|
| 308 |
+
|
| 309 |
+
////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_strided_dgrad.h
ADDED
|
@@ -0,0 +1,479 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief Epilogue for threadblock scoped GEMMs using Tensor Ops.
|
| 33 |
+
|
| 34 |
+
The epilogue rearranges the result of a matrix product through shared memory to match canonical
|
| 35 |
+
tensor layouts in global memory. Epilogues support conversion and reduction operations.
|
| 36 |
+
|
| 37 |
+
*/
|
| 38 |
+
|
| 39 |
+
#pragma once
|
| 40 |
+
|
| 41 |
+
#include "cutlass/cutlass.h"
|
| 42 |
+
#include "cutlass/numeric_types.h"
|
| 43 |
+
#include "cutlass/array.h"
|
| 44 |
+
#include "cutlass/layout/matrix.h"
|
| 45 |
+
#include "cutlass/layout/tensor.h"
|
| 46 |
+
#include "cutlass/matrix_shape.h"
|
| 47 |
+
#include "cutlass/tensor_ref.h"
|
| 48 |
+
#include "cutlass/transform/pitch_linear_thread_map.h"
|
| 49 |
+
#include "cutlass/epilogue/threadblock/output_tile_thread_map.h"
|
| 50 |
+
#include "cutlass/arch/arch.h"
|
| 51 |
+
#include "cutlass/arch/memory.h"
|
| 52 |
+
#include "cutlass/conv/conv2d_problem_size.h"
|
| 53 |
+
#include "cutlass/epilogue/threadblock/predicated_tile_iterator_params.h"
|
| 54 |
+
|
| 55 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 56 |
+
|
| 57 |
+
namespace cutlass {
|
| 58 |
+
|
| 59 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 60 |
+
|
| 61 |
+
namespace epilogue {
|
| 62 |
+
namespace threadblock {
|
| 63 |
+
|
| 64 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 65 |
+
|
| 66 |
+
/// Tile iterator used to load and store output tile from global memory in epilogue.
|
| 67 |
+
///
|
| 68 |
+
/// Satisfies: ReadableTileIterator | PredicatedTileIterator | ForwardTileIterator
|
| 69 |
+
///
|
| 70 |
+
template <
|
| 71 |
+
typename ThreadMap_, ///< Thread map (conept: OutputTileThreadMap)
|
| 72 |
+
typename Element_ ///< Element data type
|
| 73 |
+
>
|
| 74 |
+
class PredicatedTileIteratorStridedDgrad {
|
| 75 |
+
public:
|
| 76 |
+
using ThreadMap = ThreadMap_;
|
| 77 |
+
using Shape = typename ThreadMap::Shape;
|
| 78 |
+
|
| 79 |
+
using Element = Element_;
|
| 80 |
+
|
| 81 |
+
using Layout = layout::RowMajor;
|
| 82 |
+
using TensorRef = TensorRef<Element, Layout>;
|
| 83 |
+
using ConstTensorRef = typename TensorRef::ConstTensorRef;
|
| 84 |
+
|
| 85 |
+
using Index = typename Layout::Index;
|
| 86 |
+
using LongIndex = typename Layout::LongIndex;
|
| 87 |
+
using TensorCoord = MatrixCoord;
|
| 88 |
+
|
| 89 |
+
static int const kElementsPerAccess = ThreadMap::kElementsPerAccess;
|
| 90 |
+
static int const kThreads = ThreadMap::kThreads;
|
| 91 |
+
static int const kIterations = ThreadMap::Count::kTile;
|
| 92 |
+
|
| 93 |
+
static_assert( ThreadMap::Iterations::kRow > 0,"ThreadMap::Iterations::kRow must be > 0");
|
| 94 |
+
static_assert( ThreadMap::Iterations::kGroup > 0,"ThreadMap::Iterations::kGroup must be > 0");
|
| 95 |
+
static_assert( ThreadMap::Iterations::kCluster > 0,"ThreadMap::Iterations::kCluster must be > 0");
|
| 96 |
+
static_assert( ThreadMap::Iterations::kColumn > 0,"ThreadMap::Iterations::kColumn must be > 0");
|
| 97 |
+
|
| 98 |
+
/// Fragment object
|
| 99 |
+
using Fragment = Array<
|
| 100 |
+
Element,
|
| 101 |
+
ThreadMap::Iterations::kColumn *
|
| 102 |
+
ThreadMap::Iterations::kRow *
|
| 103 |
+
ThreadMap::Iterations::kGroup *
|
| 104 |
+
ThreadMap::Iterations::kCluster * ThreadMap::kElementsPerAccess>;
|
| 105 |
+
|
| 106 |
+
/// Memory access size
|
| 107 |
+
using AccessType = AlignedArray<Element, ThreadMap::kElementsPerAccess>;
|
| 108 |
+
|
| 109 |
+
//
|
| 110 |
+
// Parameters struct
|
| 111 |
+
//
|
| 112 |
+
|
| 113 |
+
/// Uses a non-template class
|
| 114 |
+
struct Params : PredicatedTileIteratorParams {
|
| 115 |
+
|
| 116 |
+
/// Convolution problem size
|
| 117 |
+
cutlass::conv::Conv2dProblemSize problem_size;
|
| 118 |
+
int tiled_rows_per_filter;
|
| 119 |
+
|
| 120 |
+
CUTLASS_HOST_DEVICE
|
| 121 |
+
Params() { }
|
| 122 |
+
|
| 123 |
+
CUTLASS_HOST_DEVICE
|
| 124 |
+
Params(Layout const &layout, cutlass::conv::Conv2dProblemSize problem_size_, int threadblock_row):
|
| 125 |
+
problem_size(problem_size_),
|
| 126 |
+
PredicatedTileIteratorParams(
|
| 127 |
+
layout.stride(0) * int(sizeof(AccessType)) / kElementsPerAccess,
|
| 128 |
+
make_OutputTileThreadMapDesc<ThreadMap>()
|
| 129 |
+
)
|
| 130 |
+
{
|
| 131 |
+
|
| 132 |
+
int tile_m_per_filter = strided_dgrad_tile_m_per_filter(problem_size, threadblock_row);
|
| 133 |
+
|
| 134 |
+
tiled_rows_per_filter = tile_m_per_filter * threadblock_row;
|
| 135 |
+
}
|
| 136 |
+
};
|
| 137 |
+
|
| 138 |
+
/// Mask object
|
| 139 |
+
struct Mask {
|
| 140 |
+
|
| 141 |
+
static int const kCount = ThreadMap::Iterations::kColumn;
|
| 142 |
+
|
| 143 |
+
/// Predicate state
|
| 144 |
+
bool predicates[kCount];
|
| 145 |
+
|
| 146 |
+
//
|
| 147 |
+
// Mask
|
| 148 |
+
//
|
| 149 |
+
CUTLASS_HOST_DEVICE
|
| 150 |
+
Mask() {
|
| 151 |
+
enable();
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
///< Efficiently disables all accesses guarded by mask
|
| 155 |
+
CUTLASS_HOST_DEVICE void clear() {
|
| 156 |
+
CUTLASS_PRAGMA_UNROLL
|
| 157 |
+
for (int i = 0; i < kCount; ++i) {
|
| 158 |
+
predicates[i] = false;
|
| 159 |
+
}
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
///< CUTLASS_HOST_DEVICE enables all accesses guarded by mask
|
| 163 |
+
CUTLASS_DEVICE void enable() {
|
| 164 |
+
CUTLASS_PRAGMA_UNROLL
|
| 165 |
+
for (int i = 0; i < kCount; ++i) {
|
| 166 |
+
predicates[i] = true;
|
| 167 |
+
}
|
| 168 |
+
}
|
| 169 |
+
};
|
| 170 |
+
|
| 171 |
+
private:
|
| 172 |
+
|
| 173 |
+
//
|
| 174 |
+
// Data members
|
| 175 |
+
//
|
| 176 |
+
|
| 177 |
+
/// Parameters structure containing reference and precomputed state.
|
| 178 |
+
Params params_;
|
| 179 |
+
|
| 180 |
+
/// Byte-level pointer
|
| 181 |
+
uint8_t *byte_pointer_;
|
| 182 |
+
|
| 183 |
+
/// Array of boolean values to contain steady-state predicates
|
| 184 |
+
Mask mask_;
|
| 185 |
+
|
| 186 |
+
/// Extent of the matrix tile in rows
|
| 187 |
+
Index extent_row_;
|
| 188 |
+
|
| 189 |
+
/// Starting Dx h and w dimension for strided dgrad mapping
|
| 190 |
+
int start_h_, start_w_;
|
| 191 |
+
|
| 192 |
+
/// Effective Dy P and Q dimensions for strided dgrad mapping
|
| 193 |
+
int p_, q_;
|
| 194 |
+
|
| 195 |
+
/// A thread's starting row position (assuming steady-state predicates have been computed)
|
| 196 |
+
Index thread_start_row_;
|
| 197 |
+
|
| 198 |
+
/// A thread's starting column position (assuming steady-state predicates have been computed)
|
| 199 |
+
Index thread_start_column_;
|
| 200 |
+
|
| 201 |
+
/// Internal state counter
|
| 202 |
+
int state_[3];
|
| 203 |
+
|
| 204 |
+
//
|
| 205 |
+
// Static asserts about internal strides
|
| 206 |
+
//
|
| 207 |
+
|
| 208 |
+
static_assert(sizeof(extent_row_) == 4, "Expected 32b extents");
|
| 209 |
+
static_assert(sizeof(thread_start_row_) == 4, "Expected 32b extents");
|
| 210 |
+
static_assert(sizeof(PredicatedTileIteratorParams::stride) == 8, "Expected 64b strides");
|
| 211 |
+
|
| 212 |
+
private:
|
| 213 |
+
|
| 214 |
+
//
|
| 215 |
+
// Methods
|
| 216 |
+
//
|
| 217 |
+
|
| 218 |
+
public:
|
| 219 |
+
|
| 220 |
+
//
|
| 221 |
+
// Methods
|
| 222 |
+
//
|
| 223 |
+
|
| 224 |
+
/// Constructor
|
| 225 |
+
CUTLASS_DEVICE
|
| 226 |
+
PredicatedTileIteratorStridedDgrad(
|
| 227 |
+
Params const & params,
|
| 228 |
+
Element *pointer,
|
| 229 |
+
TensorCoord extent,
|
| 230 |
+
int thread_idx,
|
| 231 |
+
FastDivmod const &stride_h_divmod, FastDivmod const &stride_w_divmod,
|
| 232 |
+
int start_r, int start_s,
|
| 233 |
+
TensorCoord threadblock_offset = TensorCoord()
|
| 234 |
+
):
|
| 235 |
+
params_(params)
|
| 236 |
+
{
|
| 237 |
+
|
| 238 |
+
TensorCoord thread_offset = ThreadMap::initial_offset(thread_idx) + threadblock_offset;
|
| 239 |
+
|
| 240 |
+
int r = start_r;
|
| 241 |
+
int s = start_s;
|
| 242 |
+
|
| 243 |
+
if (params_.problem_size.mode == cutlass::conv::Mode::kConvolution) {
|
| 244 |
+
r = (params_.problem_size.R - 1 - r);
|
| 245 |
+
s = (params_.problem_size.S - 1 - s);
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
// compute starting coordinates in Dx start_h_ and start_w_
|
| 249 |
+
strided_dgrad_starting_coords(
|
| 250 |
+
params_.problem_size,
|
| 251 |
+
stride_h_divmod, stride_w_divmod,
|
| 252 |
+
r, s,
|
| 253 |
+
start_h_, start_w_);
|
| 254 |
+
|
| 255 |
+
p_ = (params_.problem_size.H - start_h_ + params_.problem_size.stride_h - 1) / params_.problem_size.stride_h;
|
| 256 |
+
q_ = (params_.problem_size.W - start_w_ + params_.problem_size.stride_w - 1) / params_.problem_size.stride_w;
|
| 257 |
+
|
| 258 |
+
extent_row_ = extent.row();
|
| 259 |
+
thread_start_row_ = thread_offset.row();
|
| 260 |
+
thread_start_column_ = thread_offset.column();
|
| 261 |
+
|
| 262 |
+
// Initialize predicates
|
| 263 |
+
CUTLASS_PRAGMA_UNROLL
|
| 264 |
+
for (int c = 0; c < ThreadMap::Iterations::kColumn; ++c) {
|
| 265 |
+
|
| 266 |
+
mask_.predicates[c] = ((thread_offset.column()
|
| 267 |
+
+ ThreadMap::Delta::kColumn * c) < extent.column());
|
| 268 |
+
}
|
| 269 |
+
|
| 270 |
+
// Null pointer performs no accesses
|
| 271 |
+
if (!pointer) {
|
| 272 |
+
mask_.clear();
|
| 273 |
+
}
|
| 274 |
+
|
| 275 |
+
// Initialize pointer
|
| 276 |
+
byte_pointer_ = reinterpret_cast<uint8_t *>(pointer);
|
| 277 |
+
|
| 278 |
+
// Initialize internal state counter
|
| 279 |
+
state_[0] = state_[1] = state_[2] = 0;
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
+
/// Adds a pointer offset in units of Element
|
| 283 |
+
CUTLASS_HOST_DEVICE
|
| 284 |
+
void add_pointer_offset(LongIndex pointer_offset) {
|
| 285 |
+
byte_pointer_ += pointer_offset * sizeof_bits<Element>::value / 8;
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
/// Loads a fragment from memory
|
| 289 |
+
CUTLASS_DEVICE
|
| 290 |
+
void load_with_byte_offset(Fragment &frag, int64_t byte_offset) {
|
| 291 |
+
|
| 292 |
+
uint8_t *byte_pointer = byte_pointer_;
|
| 293 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 294 |
+
|
| 295 |
+
CUTLASS_PRAGMA_UNROLL
|
| 296 |
+
for (int cluster = 0; cluster < ThreadMap::Iterations::kCluster; ++cluster) {
|
| 297 |
+
|
| 298 |
+
CUTLASS_PRAGMA_UNROLL
|
| 299 |
+
for (int group = 0; group < ThreadMap::Iterations::kGroup; ++group) {
|
| 300 |
+
|
| 301 |
+
CUTLASS_PRAGMA_UNROLL
|
| 302 |
+
for (int row = 0; row < ThreadMap::Iterations::kRow; ++row) {
|
| 303 |
+
|
| 304 |
+
int frag_row_idx =
|
| 305 |
+
(row + ThreadMap::Iterations::kRow * (group + ThreadMap::Iterations::kGroup * cluster));
|
| 306 |
+
|
| 307 |
+
int row_offset = row * ThreadMap::Delta::kRow
|
| 308 |
+
+ group * ThreadMap::Delta::kGroup
|
| 309 |
+
+ cluster * ThreadMap::Delta::kCluster;
|
| 310 |
+
|
| 311 |
+
// remapping rows to find the mapped_row_offset
|
| 312 |
+
int npq_offset = (row_offset + thread_start_row_) % params_.tiled_rows_per_filter;
|
| 313 |
+
|
| 314 |
+
// (STEP 4.a) [order NHW rows to be loaded and stored in output Dx NHWxC layout]
|
| 315 |
+
int n = npq_offset / (p_ * q_);
|
| 316 |
+
int residual = npq_offset % (p_ * q_);
|
| 317 |
+
int p = residual / q_;
|
| 318 |
+
int q = residual % q_;
|
| 319 |
+
|
| 320 |
+
int mapped_row_offset = n * (params_.problem_size.H * params_.problem_size.W) +
|
| 321 |
+
(start_h_ + p * params_.problem_size.stride_h) * params_.problem_size.W +
|
| 322 |
+
(start_w_ + q * params_.problem_size.stride_w);
|
| 323 |
+
bool row_guard = mapped_row_offset < extent_row_;
|
| 324 |
+
|
| 325 |
+
int64_t row_byte_offset = mapped_row_offset * params_.stride;
|
| 326 |
+
|
| 327 |
+
CUTLASS_PRAGMA_UNROLL
|
| 328 |
+
for (int column = 0; column < ThreadMap::Iterations::kColumn; ++column) {
|
| 329 |
+
|
| 330 |
+
int64_t column_byte_offset = (thread_start_column_ + column * ThreadMap::Delta::kColumn) * (sizeof_bits<Element>::value / 8);
|
| 331 |
+
|
| 332 |
+
bool guard = row_guard && mask_.predicates[column];
|
| 333 |
+
|
| 334 |
+
cutlass::arch::global_load<
|
| 335 |
+
AccessType,
|
| 336 |
+
sizeof(AccessType)
|
| 337 |
+
>(
|
| 338 |
+
frag_ptr[frag_row_idx * ThreadMap::Iterations::kColumn +
|
| 339 |
+
column],
|
| 340 |
+
(void *)(byte_pointer + row_byte_offset + column_byte_offset + byte_offset),
|
| 341 |
+
guard);
|
| 342 |
+
}
|
| 343 |
+
}
|
| 344 |
+
}
|
| 345 |
+
}
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
|
| 349 |
+
/// Loads a fragment from memory
|
| 350 |
+
CUTLASS_DEVICE
|
| 351 |
+
void load(Fragment &frag) {
|
| 352 |
+
|
| 353 |
+
load_with_byte_offset(frag, 0);
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
/// Stores a fragment to memory
|
| 357 |
+
CUTLASS_DEVICE
|
| 358 |
+
void store_with_byte_offset(Fragment const &frag, int64_t byte_offset) {
|
| 359 |
+
uint8_t *byte_pointer = byte_pointer_;
|
| 360 |
+
AccessType const *frag_ptr = reinterpret_cast<AccessType const *>(&frag);
|
| 361 |
+
|
| 362 |
+
CUTLASS_PRAGMA_UNROLL
|
| 363 |
+
for (int cluster = 0; cluster < ThreadMap::Iterations::kCluster; ++cluster) {
|
| 364 |
+
|
| 365 |
+
CUTLASS_PRAGMA_UNROLL
|
| 366 |
+
for (int group = 0; group < ThreadMap::Iterations::kGroup; ++group) {
|
| 367 |
+
|
| 368 |
+
CUTLASS_PRAGMA_UNROLL
|
| 369 |
+
for (int row = 0; row < ThreadMap::Iterations::kRow; ++row) {
|
| 370 |
+
|
| 371 |
+
int frag_row_idx =
|
| 372 |
+
(row + ThreadMap::Iterations::kRow * (group + ThreadMap::Iterations::kGroup * cluster));
|
| 373 |
+
|
| 374 |
+
int row_offset = row * ThreadMap::Delta::kRow
|
| 375 |
+
+ group * ThreadMap::Delta::kGroup
|
| 376 |
+
+ cluster * ThreadMap::Delta::kCluster;
|
| 377 |
+
|
| 378 |
+
// remapping rows to find the mapped_row_offset
|
| 379 |
+
int npq_offset = (row_offset + thread_start_row_) % params_.tiled_rows_per_filter;
|
| 380 |
+
|
| 381 |
+
// (STEP 4.a) [order NHW rows to be loaded and stored in output Dx NHWxC layout]
|
| 382 |
+
int n = npq_offset / (p_ * q_);
|
| 383 |
+
int residual = npq_offset % (p_ * q_);
|
| 384 |
+
int p = residual / q_;
|
| 385 |
+
int q = residual % q_;
|
| 386 |
+
|
| 387 |
+
int mapped_row_offset = n * (params_.problem_size.H * params_.problem_size.W) +
|
| 388 |
+
(start_h_ + p * params_.problem_size.stride_h) * params_.problem_size.W +
|
| 389 |
+
(start_w_ + q * params_.problem_size.stride_w);
|
| 390 |
+
bool row_guard = mapped_row_offset < extent_row_;
|
| 391 |
+
|
| 392 |
+
int64_t row_byte_offset = mapped_row_offset * params_.stride;
|
| 393 |
+
|
| 394 |
+
CUTLASS_PRAGMA_UNROLL
|
| 395 |
+
for (int column = 0; column < ThreadMap::Iterations::kColumn; ++column) {
|
| 396 |
+
|
| 397 |
+
int64_t column_byte_offset = (thread_start_column_ + column * ThreadMap::Delta::kColumn) * (sizeof_bits<Element>::value / 8);
|
| 398 |
+
|
| 399 |
+
bool guard = row_guard && mask_.predicates[column];
|
| 400 |
+
|
| 401 |
+
cutlass::arch::global_store<AccessType, sizeof(AccessType) >(
|
| 402 |
+
frag_ptr[frag_row_idx * ThreadMap::Iterations::kColumn + column],
|
| 403 |
+
(void *)(byte_pointer + row_byte_offset + column_byte_offset + byte_offset),
|
| 404 |
+
guard);
|
| 405 |
+
}
|
| 406 |
+
}
|
| 407 |
+
}
|
| 408 |
+
}
|
| 409 |
+
}
|
| 410 |
+
|
| 411 |
+
|
| 412 |
+
/// Stores a fragment to memory
|
| 413 |
+
CUTLASS_DEVICE
|
| 414 |
+
void store(Fragment const &frag) {
|
| 415 |
+
|
| 416 |
+
store_with_byte_offset(frag, 0);
|
| 417 |
+
}
|
| 418 |
+
|
| 419 |
+
/// Advances to the next position to load or store
|
| 420 |
+
CUTLASS_HOST_DEVICE
|
| 421 |
+
PredicatedTileIteratorStridedDgrad &operator++() {
|
| 422 |
+
|
| 423 |
+
++state_[0];
|
| 424 |
+
|
| 425 |
+
thread_start_row_ += ThreadMap::Shape::kRow;
|
| 426 |
+
|
| 427 |
+
if (state_[0] == ThreadMap::Count::kRow) {
|
| 428 |
+
|
| 429 |
+
state_[0] = 0;
|
| 430 |
+
++state_[1];
|
| 431 |
+
|
| 432 |
+
thread_start_row_ += (ThreadMap::Shape::kGroup - 1) *
|
| 433 |
+
ThreadMap::Shape::kRow * ThreadMap::Count::kRow;
|
| 434 |
+
|
| 435 |
+
if (state_[1] == ThreadMap::Count::kGroup) {
|
| 436 |
+
|
| 437 |
+
state_[1] = 0;
|
| 438 |
+
++state_[2];
|
| 439 |
+
|
| 440 |
+
thread_start_row_ += ThreadMap::Count::kGroup *
|
| 441 |
+
ThreadMap::Shape::kGroup * ThreadMap::Count::kRow * ThreadMap::Shape::kRow;
|
| 442 |
+
|
| 443 |
+
if (state_[2] == ThreadMap::Count::kCluster) {
|
| 444 |
+
state_[2] = 0;
|
| 445 |
+
}
|
| 446 |
+
}
|
| 447 |
+
}
|
| 448 |
+
|
| 449 |
+
return *this;
|
| 450 |
+
}
|
| 451 |
+
|
| 452 |
+
///< Efficiently disables all accesses guarded by mask
|
| 453 |
+
CUTLASS_DEVICE void clear_mask() {
|
| 454 |
+
mask_.clear();
|
| 455 |
+
}
|
| 456 |
+
|
| 457 |
+
///< Efficiently enables all accesses guarded by mask
|
| 458 |
+
CUTLASS_DEVICE void enable_mask() {
|
| 459 |
+
mask_.enable();
|
| 460 |
+
}
|
| 461 |
+
|
| 462 |
+
///< Sets the mask
|
| 463 |
+
CUTLASS_DEVICE void get_mask(Mask &mask) {
|
| 464 |
+
mask = mask_;
|
| 465 |
+
}
|
| 466 |
+
|
| 467 |
+
///< Sets the mask
|
| 468 |
+
CUTLASS_DEVICE void set_mask(Mask const &mask) {
|
| 469 |
+
mask_ = mask;
|
| 470 |
+
}
|
| 471 |
+
};
|
| 472 |
+
|
| 473 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 474 |
+
|
| 475 |
+
} // namespace threadblock
|
| 476 |
+
} // namespace epilogue
|
| 477 |
+
} // namespace cutlass
|
| 478 |
+
|
| 479 |
+
////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/shared_load_iterator.h
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief Epilogue for threadblock scoped GEMMs using Tensor Ops.
|
| 33 |
+
|
| 34 |
+
The epilogue rearranges the result of a matrix product through shared memory to match canonical
|
| 35 |
+
tensor layouts in global memory. Epilogues support conversion and reduction operations.
|
| 36 |
+
|
| 37 |
+
*/
|
| 38 |
+
|
| 39 |
+
#pragma once
|
| 40 |
+
|
| 41 |
+
#include "cutlass/cutlass.h"
|
| 42 |
+
#include "cutlass/numeric_types.h"
|
| 43 |
+
#include "cutlass/array.h"
|
| 44 |
+
#include "cutlass/layout/matrix.h"
|
| 45 |
+
#include "cutlass/matrix_shape.h"
|
| 46 |
+
#include "cutlass/tensor_ref.h"
|
| 47 |
+
|
| 48 |
+
#include "cutlass/epilogue/threadblock/output_tile_thread_map.h"
|
| 49 |
+
|
| 50 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 51 |
+
|
| 52 |
+
namespace cutlass {
|
| 53 |
+
namespace epilogue {
|
| 54 |
+
namespace threadblock {
|
| 55 |
+
|
| 56 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 57 |
+
|
| 58 |
+
/// Tile iterator used to load output tile from shared memory in epilogue.
|
| 59 |
+
///
|
| 60 |
+
/// Satisfies: ReadableTileIterator
|
| 61 |
+
///
|
| 62 |
+
template <
|
| 63 |
+
typename ThreadMap_, ///< Thread map (conept: OutputTileThreadMap)
|
| 64 |
+
typename Element_, ///< Element data type
|
| 65 |
+
int MaxAlignment = ThreadMap_::kElementsPerAccess * sizeof_bits<Element_>::value / 8
|
| 66 |
+
>
|
| 67 |
+
class SharedLoadIterator {
|
| 68 |
+
public:
|
| 69 |
+
using ThreadMap = ThreadMap_;
|
| 70 |
+
using Shape = typename ThreadMap::TileShape;
|
| 71 |
+
|
| 72 |
+
using Element = Element_;
|
| 73 |
+
|
| 74 |
+
using Layout = layout::RowMajor;
|
| 75 |
+
using TensorRef = TensorRef<Element, Layout>;
|
| 76 |
+
using ConstTensorRef = typename TensorRef::ConstTensorRef;
|
| 77 |
+
|
| 78 |
+
using Index = typename Layout::Index;
|
| 79 |
+
using LongIndex = typename Layout::LongIndex;
|
| 80 |
+
using TensorCoord = MatrixCoord;
|
| 81 |
+
|
| 82 |
+
static int const kElementsPerAccess = ThreadMap::kElementsPerAccess;
|
| 83 |
+
|
| 84 |
+
static int const kMinAlignment = ThreadMap_::kElementsPerAccess * sizeof_bits<Element_>::value / 8;
|
| 85 |
+
|
| 86 |
+
static int const kAlignment = (MaxAlignment < kMinAlignment ? MaxAlignment : kMinAlignment);
|
| 87 |
+
|
| 88 |
+
static int const kThreads = ThreadMap::kThreads;
|
| 89 |
+
|
| 90 |
+
/// Fragment object
|
| 91 |
+
using Fragment = Array<
|
| 92 |
+
Element,
|
| 93 |
+
ThreadMap::Iterations::kColumn *
|
| 94 |
+
ThreadMap::Iterations::kRow *
|
| 95 |
+
ThreadMap::Iterations::kGroup *
|
| 96 |
+
ThreadMap::Iterations::kCluster *
|
| 97 |
+
ThreadMap::kElementsPerAccess>;
|
| 98 |
+
|
| 99 |
+
/// Memory access size
|
| 100 |
+
using AccessType = AlignedArray<
|
| 101 |
+
Element,
|
| 102 |
+
ThreadMap::kElementsPerAccess,
|
| 103 |
+
kAlignment>;
|
| 104 |
+
|
| 105 |
+
/// Vector type used for SMEM loads
|
| 106 |
+
using LoadType = AlignedArray<
|
| 107 |
+
Element,
|
| 108 |
+
const_min(128 / sizeof_bits<Element>::value, ThreadMap::kElementsPerAccess),
|
| 109 |
+
const_min(16, kAlignment)
|
| 110 |
+
>;
|
| 111 |
+
|
| 112 |
+
static int const kLoadsPerAccess = AccessType::kElements / LoadType::kElements;
|
| 113 |
+
|
| 114 |
+
private:
|
| 115 |
+
|
| 116 |
+
//
|
| 117 |
+
// Data members
|
| 118 |
+
//
|
| 119 |
+
|
| 120 |
+
/// Byte-level pointer
|
| 121 |
+
uint8_t *byte_pointer_;
|
| 122 |
+
|
| 123 |
+
/// Stride along adjacent rows
|
| 124 |
+
int stride_;
|
| 125 |
+
|
| 126 |
+
public:
|
| 127 |
+
|
| 128 |
+
//
|
| 129 |
+
// Methods
|
| 130 |
+
//
|
| 131 |
+
|
| 132 |
+
/// Constructor
|
| 133 |
+
CUTLASS_DEVICE
|
| 134 |
+
SharedLoadIterator(
|
| 135 |
+
TensorRef ref,
|
| 136 |
+
int thread_idx
|
| 137 |
+
):
|
| 138 |
+
byte_pointer_(reinterpret_cast<uint8_t *>(ref.data())),
|
| 139 |
+
stride_((ref.stride(0) * sizeof_bits<Element>::value) / 8) {
|
| 140 |
+
|
| 141 |
+
TensorCoord thread_offset = ThreadMap::initial_offset(thread_idx);
|
| 142 |
+
|
| 143 |
+
// Initialize pointer
|
| 144 |
+
byte_pointer_ +=
|
| 145 |
+
thread_offset.row() * stride_ +
|
| 146 |
+
thread_offset.column() * sizeof(AccessType) / kElementsPerAccess;
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
/// Adds a pointer offset in units of Element
|
| 150 |
+
CUTLASS_HOST_DEVICE
|
| 151 |
+
void add_pointer_offset(LongIndex pointer_offset) {
|
| 152 |
+
byte_pointer_ += pointer_offset * sizeof_bits<Element>::value / 8;
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
CUTLASS_DEVICE
|
| 156 |
+
void add_tile_offset(TensorCoord const &offset) {
|
| 157 |
+
byte_pointer_ +=
|
| 158 |
+
offset.row() * Shape::kRow * stride_ +
|
| 159 |
+
offset.column() * Shape::kColumn * sizeof_bits<Element>::value / 8;
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
/// Loads a fragment from memory
|
| 163 |
+
CUTLASS_DEVICE
|
| 164 |
+
void load_with_pointer_offset(Fragment &frag, Index pointer_offset) const {
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
CUTLASS_PRAGMA_UNROLL
|
| 168 |
+
for (int cluster = 0; cluster < ThreadMap::Iterations::kCluster; ++cluster) {
|
| 169 |
+
|
| 170 |
+
CUTLASS_PRAGMA_UNROLL
|
| 171 |
+
for (int group = 0; group < ThreadMap::Iterations::kGroup; ++group) {
|
| 172 |
+
|
| 173 |
+
CUTLASS_PRAGMA_UNROLL
|
| 174 |
+
for (int row = 0; row < ThreadMap::Iterations::kRow; ++row) {
|
| 175 |
+
|
| 176 |
+
uint8_t const *byte_pointer = byte_pointer_ +
|
| 177 |
+
row * ThreadMap::Delta::kRow * stride_ +
|
| 178 |
+
group * ThreadMap::Delta::kGroup* stride_ +
|
| 179 |
+
cluster * ThreadMap::Delta::kCluster * stride_ +
|
| 180 |
+
pointer_offset * sizeof_bits<Element>::value / 8;
|
| 181 |
+
|
| 182 |
+
int frag_row_idx =
|
| 183 |
+
(row + ThreadMap::Iterations::kRow * (group + ThreadMap::Iterations::kGroup * cluster));
|
| 184 |
+
|
| 185 |
+
LoadType *frag_ptr = reinterpret_cast<LoadType *>(&frag);
|
| 186 |
+
LoadType const *memory_pointer = reinterpret_cast<LoadType const *>(byte_pointer);
|
| 187 |
+
|
| 188 |
+
CUTLASS_PRAGMA_UNROLL
|
| 189 |
+
for (int column = 0; column < ThreadMap::Iterations::kColumn; ++column) {
|
| 190 |
+
|
| 191 |
+
int frag_idx = frag_row_idx * ThreadMap::Iterations::kColumn + column;
|
| 192 |
+
|
| 193 |
+
CUTLASS_PRAGMA_UNROLL
|
| 194 |
+
for (int v = 0; v < kLoadsPerAccess; ++v) {
|
| 195 |
+
frag_ptr[frag_idx * kLoadsPerAccess + v] =
|
| 196 |
+
memory_pointer[(column * ThreadMap::Delta::kColumn / kElementsPerAccess) * kLoadsPerAccess + v];
|
| 197 |
+
}
|
| 198 |
+
}
|
| 199 |
+
}
|
| 200 |
+
}
|
| 201 |
+
}
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
/// Loads a fragment from memory
|
| 205 |
+
CUTLASS_DEVICE
|
| 206 |
+
void set_smem_base_address(Index address) {
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
/// Loads a fragment
|
| 210 |
+
CUTLASS_DEVICE
|
| 211 |
+
void load(Fragment &frag) const {
|
| 212 |
+
|
| 213 |
+
load_with_pointer_offset(frag, 0);
|
| 214 |
+
}
|
| 215 |
+
};
|
| 216 |
+
|
| 217 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 218 |
+
|
| 219 |
+
} // namespace threadblock
|
| 220 |
+
} // namespace epilogue
|
| 221 |
+
} // namespace cutlass
|
| 222 |
+
|
| 223 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/shared_load_iterator_mixed.h
ADDED
|
@@ -0,0 +1,594 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief Epilogue for threadblock scoped GEMMs using Tensor Ops optimized for mixed-precision.
|
| 33 |
+
|
| 34 |
+
This assumes the shared memory tile is in a permuted layout which avoids bank conflicts on loading.
|
| 35 |
+
|
| 36 |
+
When the fragment is loaded into registers, it matches the row-major thread map assumed by
|
| 37 |
+
the predicated tile iterator writing to global memory.
|
| 38 |
+
|
| 39 |
+
The epilogue rearranges the result of a matrix product through shared memory to match canonical
|
| 40 |
+
tensor layouts in global memory. Epilogues support conversion and reduction operations.
|
| 41 |
+
|
| 42 |
+
*/
|
| 43 |
+
|
| 44 |
+
#pragma once
|
| 45 |
+
|
| 46 |
+
#include "cutlass/cutlass.h"
|
| 47 |
+
#include "cutlass/numeric_types.h"
|
| 48 |
+
#include "cutlass/array.h"
|
| 49 |
+
#include "cutlass/layout/matrix.h"
|
| 50 |
+
#include "cutlass/matrix_shape.h"
|
| 51 |
+
#include "cutlass/tensor_ref.h"
|
| 52 |
+
|
| 53 |
+
#include "cutlass/epilogue/threadblock/output_tile_thread_map.h"
|
| 54 |
+
|
| 55 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 56 |
+
|
| 57 |
+
namespace cutlass {
|
| 58 |
+
namespace epilogue {
|
| 59 |
+
namespace threadblock {
|
| 60 |
+
|
| 61 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 62 |
+
|
| 63 |
+
/// Tile iterator used to load output tile from shared memory in epilogue.
|
| 64 |
+
///
|
| 65 |
+
/// Satisfies: ReadableTileIterator
|
| 66 |
+
///
|
| 67 |
+
template <
|
| 68 |
+
typename ThreadMap_, ///< Thread map (conept: OutputTileThreadMap)
|
| 69 |
+
typename Element_, ///< Accumulator data type
|
| 70 |
+
int ElementSizeBits_, ///< Size of accumulator in bits
|
| 71 |
+
int OutputSizeBits_, ///< Size of output element in bits
|
| 72 |
+
int ElementsPerAccess, ///< Vector length of output vector
|
| 73 |
+
int ContiguousLanes, ///< Number of lanes in the warp writing to contiguous elements
|
| 74 |
+
/// in the global memory tensor
|
| 75 |
+
bool EightBitsOutputOrLess = (OutputSizeBits_ <= 8)
|
| 76 |
+
>
|
| 77 |
+
class SharedLoadIteratorMixed;
|
| 78 |
+
|
| 79 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 80 |
+
|
| 81 |
+
/// Tile iterator used to load output tile from shared memory in epilogue.
|
| 82 |
+
///
|
| 83 |
+
/// Satisfies: ReadableTileIterator
|
| 84 |
+
///
|
| 85 |
+
template <
|
| 86 |
+
typename ThreadMap_, ///< Thread map (conept: OutputTileThreadMap)
|
| 87 |
+
typename Element_ ///< Accumulator data type
|
| 88 |
+
>
|
| 89 |
+
class SharedLoadIteratorMixed<ThreadMap_, Element_, 32, 16, 8, 8, false> {
|
| 90 |
+
public:
|
| 91 |
+
using ThreadMap = ThreadMap_;
|
| 92 |
+
using Shape = typename ThreadMap::Shape;
|
| 93 |
+
|
| 94 |
+
using Element = Element_;
|
| 95 |
+
|
| 96 |
+
using Layout = layout::RowMajor;
|
| 97 |
+
using TensorRef = TensorRef<Element, Layout>;
|
| 98 |
+
using ConstTensorRef = typename TensorRef::ConstTensorRef;
|
| 99 |
+
|
| 100 |
+
using Index = typename Layout::Index;
|
| 101 |
+
using LongIndex = typename Layout::LongIndex;
|
| 102 |
+
using TensorCoord = MatrixCoord;
|
| 103 |
+
|
| 104 |
+
static int const kElementsPerAccess = ThreadMap::kElementsPerAccess;
|
| 105 |
+
|
| 106 |
+
static int const kAlignment = ThreadMap::kElementsPerAccess * sizeof_bits<Element_>::value / 8;
|
| 107 |
+
|
| 108 |
+
static int const kThreads = ThreadMap::kThreads;
|
| 109 |
+
|
| 110 |
+
/// Fragment object
|
| 111 |
+
using Fragment = Array<
|
| 112 |
+
Element,
|
| 113 |
+
ThreadMap::Iterations::kColumn *
|
| 114 |
+
ThreadMap::Iterations::kRow *
|
| 115 |
+
ThreadMap::Iterations::kGroup *
|
| 116 |
+
ThreadMap::Iterations::kCluster *
|
| 117 |
+
ThreadMap::kElementsPerAccess>;
|
| 118 |
+
|
| 119 |
+
/// Memory access size
|
| 120 |
+
using AccessType = AlignedArray<
|
| 121 |
+
Element,
|
| 122 |
+
ThreadMap::kElementsPerAccess,
|
| 123 |
+
kAlignment>;
|
| 124 |
+
|
| 125 |
+
/// Vector type used for SMEM loads
|
| 126 |
+
using LoadType = AlignedArray<
|
| 127 |
+
Element,
|
| 128 |
+
const_min(128 / sizeof_bits<Element>::value, ThreadMap::kElementsPerAccess),
|
| 129 |
+
const_min(16, kAlignment)
|
| 130 |
+
>;
|
| 131 |
+
|
| 132 |
+
static int const kLoadsPerAccess = AccessType::kElements / LoadType::kElements;
|
| 133 |
+
|
| 134 |
+
private:
|
| 135 |
+
|
| 136 |
+
//
|
| 137 |
+
// Data members
|
| 138 |
+
//
|
| 139 |
+
|
| 140 |
+
/// Byte-level pointer
|
| 141 |
+
LoadType const *pointers_[kLoadsPerAccess];
|
| 142 |
+
|
| 143 |
+
/// Stride along adjacent rows in units of LoadType
|
| 144 |
+
int stride_;
|
| 145 |
+
|
| 146 |
+
public:
|
| 147 |
+
|
| 148 |
+
//
|
| 149 |
+
// Methods
|
| 150 |
+
//
|
| 151 |
+
|
| 152 |
+
/// Constructor
|
| 153 |
+
CUTLASS_DEVICE
|
| 154 |
+
SharedLoadIteratorMixed(
|
| 155 |
+
TensorRef ref,
|
| 156 |
+
int thread_idx
|
| 157 |
+
):
|
| 158 |
+
stride_((ref.stride(0) / LoadType::kElements)) {
|
| 159 |
+
|
| 160 |
+
TensorCoord thread_offset = ThreadMap::initial_offset(thread_idx);
|
| 161 |
+
|
| 162 |
+
// Initialize pointers
|
| 163 |
+
CUTLASS_PRAGMA_UNROLL
|
| 164 |
+
for (int i = 0; i < kLoadsPerAccess; ++i) {
|
| 165 |
+
pointers_[i] = reinterpret_cast<LoadType const *>(ref.data());
|
| 166 |
+
|
| 167 |
+
int col_idx = (thread_offset.column() / kElementsPerAccess) * kLoadsPerAccess;
|
| 168 |
+
int bank_offset = (col_idx * int(sizeof(LoadType)) / 128) % kLoadsPerAccess;
|
| 169 |
+
|
| 170 |
+
col_idx += (bank_offset + i) % kLoadsPerAccess;
|
| 171 |
+
|
| 172 |
+
pointers_[i] += thread_offset.row() * stride_ + col_idx;
|
| 173 |
+
}
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
/// Adds a pointer offset in units of Element
|
| 177 |
+
CUTLASS_HOST_DEVICE
|
| 178 |
+
void add_pointer_offset(LongIndex pointer_offset) {
|
| 179 |
+
CUTLASS_PRAGMA_UNROLL
|
| 180 |
+
for (int i = 0; i < kLoadsPerAccess; ++i) {
|
| 181 |
+
pointers_[i] += pointer_offset / LoadType::kElements;
|
| 182 |
+
}
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
+
CUTLASS_DEVICE
|
| 186 |
+
void add_tile_offset(TensorCoord const &offset) {
|
| 187 |
+
CUTLASS_PRAGMA_UNROLL
|
| 188 |
+
for (int i = 0; i < kLoadsPerAccess; ++i) {
|
| 189 |
+
pointers_[i] +=
|
| 190 |
+
offset.row() * Shape::kRow * stride_ +
|
| 191 |
+
offset.column() * Shape::kColumn / LoadType::kElements;
|
| 192 |
+
}
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
/// Loads a fragment from memory
|
| 196 |
+
CUTLASS_DEVICE
|
| 197 |
+
void load_with_pointer_offset(Fragment &frag, Index pointer_offset) const {
|
| 198 |
+
|
| 199 |
+
CUTLASS_PRAGMA_UNROLL
|
| 200 |
+
for (int cluster = 0; cluster < ThreadMap::Iterations::kCluster; ++cluster) {
|
| 201 |
+
|
| 202 |
+
CUTLASS_PRAGMA_UNROLL
|
| 203 |
+
for (int group = 0; group < ThreadMap::Iterations::kGroup; ++group) {
|
| 204 |
+
|
| 205 |
+
CUTLASS_PRAGMA_UNROLL
|
| 206 |
+
for (int row = 0; row < ThreadMap::Iterations::kRow; ++row) {
|
| 207 |
+
|
| 208 |
+
int row_ptr_offset =
|
| 209 |
+
row * ThreadMap::Delta::kRow * stride_ +
|
| 210 |
+
group * ThreadMap::Delta::kGroup* stride_ +
|
| 211 |
+
cluster * ThreadMap::Delta::kCluster * stride_ +
|
| 212 |
+
pointer_offset / LoadType::kElements;
|
| 213 |
+
|
| 214 |
+
int frag_row_idx = (row + ThreadMap::Iterations::kRow * (group + ThreadMap::Iterations::kGroup * cluster));
|
| 215 |
+
|
| 216 |
+
LoadType *frag_ptr = reinterpret_cast<LoadType *>(&frag);
|
| 217 |
+
|
| 218 |
+
CUTLASS_PRAGMA_UNROLL
|
| 219 |
+
for (int column = 0; column < ThreadMap::Iterations::kColumn; ++column) {
|
| 220 |
+
|
| 221 |
+
int frag_idx = frag_row_idx * ThreadMap::Iterations::kColumn + column;
|
| 222 |
+
|
| 223 |
+
CUTLASS_PRAGMA_UNROLL
|
| 224 |
+
for (int v = 0; v < kLoadsPerAccess; ++v) {
|
| 225 |
+
|
| 226 |
+
int vector_idx = (column * ThreadMap::Delta::kColumn / kElementsPerAccess * kLoadsPerAccess);
|
| 227 |
+
|
| 228 |
+
LoadType const *memory_pointer = pointers_[v] + row_ptr_offset;
|
| 229 |
+
|
| 230 |
+
frag_ptr[frag_idx * kLoadsPerAccess + v] = memory_pointer[vector_idx];
|
| 231 |
+
}
|
| 232 |
+
}
|
| 233 |
+
}
|
| 234 |
+
}
|
| 235 |
+
}
|
| 236 |
+
}
|
| 237 |
+
|
| 238 |
+
/// Set base smem address
|
| 239 |
+
CUTLASS_DEVICE
|
| 240 |
+
void set_smem_base_address(Index address) {}
|
| 241 |
+
|
| 242 |
+
/// Loads a fragment
|
| 243 |
+
CUTLASS_DEVICE
|
| 244 |
+
void load(Fragment &frag) const {
|
| 245 |
+
|
| 246 |
+
load_with_pointer_offset(frag, 0);
|
| 247 |
+
}
|
| 248 |
+
};
|
| 249 |
+
|
| 250 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 251 |
+
|
| 252 |
+
/// Partial specialization for
|
| 253 |
+
/// int32_t x 16 => int8_t/int4b_t x 16 and
|
| 254 |
+
/// float x 16 => float_e4m3_t/float_e5m2_t x 16
|
| 255 |
+
template <
|
| 256 |
+
typename ThreadMap_, ///< Thread map (concept: OutputTileThreadMap)
|
| 257 |
+
typename Element_,
|
| 258 |
+
int OutputSizeBits_ ///< Size of output element in bits
|
| 259 |
+
>
|
| 260 |
+
class SharedLoadIteratorMixed<ThreadMap_, Element_, 32, OutputSizeBits_, 16, 8, true> {
|
| 261 |
+
public:
|
| 262 |
+
using ThreadMap = ThreadMap_;
|
| 263 |
+
using Shape = typename ThreadMap::Shape;
|
| 264 |
+
|
| 265 |
+
using Element = Element_;
|
| 266 |
+
static_assert(sizeof_bits<Element>::value == 32, "Element size in bits must be 32.");
|
| 267 |
+
|
| 268 |
+
using Layout = layout::RowMajor;
|
| 269 |
+
using TensorRef = TensorRef<Element, Layout>;
|
| 270 |
+
using ConstTensorRef = typename TensorRef::ConstTensorRef;
|
| 271 |
+
|
| 272 |
+
using Index = typename Layout::Index;
|
| 273 |
+
using LongIndex = typename Layout::LongIndex;
|
| 274 |
+
using TensorCoord = MatrixCoord;
|
| 275 |
+
|
| 276 |
+
static int const kElementsPerAccess = ThreadMap::kElementsPerAccess;
|
| 277 |
+
|
| 278 |
+
static int const kAlignment = 16;
|
| 279 |
+
|
| 280 |
+
static int const kThreads = ThreadMap::kThreads;
|
| 281 |
+
|
| 282 |
+
/// Fragment object
|
| 283 |
+
using Fragment = Array<
|
| 284 |
+
Element,
|
| 285 |
+
ThreadMap::Iterations::kColumn *
|
| 286 |
+
ThreadMap::Iterations::kRow *
|
| 287 |
+
ThreadMap::Iterations::kGroup *
|
| 288 |
+
ThreadMap::Iterations::kCluster *
|
| 289 |
+
ThreadMap::kElementsPerAccess>;
|
| 290 |
+
|
| 291 |
+
/// Memory access size
|
| 292 |
+
using AccessType = AlignedArray<
|
| 293 |
+
Element,
|
| 294 |
+
16,
|
| 295 |
+
kAlignment>;
|
| 296 |
+
|
| 297 |
+
/// Vector type used for SMEM loads
|
| 298 |
+
using LoadType = AlignedArray<
|
| 299 |
+
Element,
|
| 300 |
+
4,
|
| 301 |
+
16
|
| 302 |
+
>;
|
| 303 |
+
|
| 304 |
+
static int const kLoadsPerAccess = 4;
|
| 305 |
+
|
| 306 |
+
private:
|
| 307 |
+
|
| 308 |
+
//
|
| 309 |
+
// Data members
|
| 310 |
+
//
|
| 311 |
+
|
| 312 |
+
/// Byte-level pointer
|
| 313 |
+
LoadType const *pointers_[kLoadsPerAccess];
|
| 314 |
+
|
| 315 |
+
/// Stride along adjacent rows in units of LoadType
|
| 316 |
+
int stride_;
|
| 317 |
+
|
| 318 |
+
public:
|
| 319 |
+
|
| 320 |
+
//
|
| 321 |
+
// Methods
|
| 322 |
+
//
|
| 323 |
+
|
| 324 |
+
/// Constructor
|
| 325 |
+
CUTLASS_DEVICE
|
| 326 |
+
SharedLoadIteratorMixed(
|
| 327 |
+
TensorRef ref,
|
| 328 |
+
int thread_idx
|
| 329 |
+
):
|
| 330 |
+
stride_((ref.stride(0) / LoadType::kElements)) {
|
| 331 |
+
|
| 332 |
+
TensorCoord thread_offset = ThreadMap::initial_offset(thread_idx);
|
| 333 |
+
|
| 334 |
+
// Initialize pointers
|
| 335 |
+
LoadType const *base_ptr = reinterpret_cast<LoadType const *>(ref.data()) + thread_offset.row() * stride_;
|
| 336 |
+
|
| 337 |
+
int lane_col_idx = thread_offset.column() / 16;
|
| 338 |
+
|
| 339 |
+
CUTLASS_PRAGMA_UNROLL
|
| 340 |
+
for (int i = 0; i < kLoadsPerAccess; ++i) {
|
| 341 |
+
int lane_offset = (lane_col_idx % 2) * 4 | ((lane_col_idx / 2) * 8) | ((lane_col_idx / 2) ^ i);
|
| 342 |
+
|
| 343 |
+
pointers_[i] = base_ptr + lane_offset;
|
| 344 |
+
}
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
+
/// Adds a pointer offset in units of Element
|
| 348 |
+
CUTLASS_HOST_DEVICE
|
| 349 |
+
void add_pointer_offset(LongIndex pointer_offset) {
|
| 350 |
+
CUTLASS_PRAGMA_UNROLL
|
| 351 |
+
for (int i = 0; i < kLoadsPerAccess; ++i) {
|
| 352 |
+
pointers_[i] += pointer_offset / LoadType::kElements;
|
| 353 |
+
}
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
CUTLASS_DEVICE
|
| 357 |
+
void add_tile_offset(TensorCoord const &offset) {
|
| 358 |
+
CUTLASS_PRAGMA_UNROLL
|
| 359 |
+
for (int i = 0; i < kLoadsPerAccess; ++i) {
|
| 360 |
+
pointers_[i] +=
|
| 361 |
+
offset.row() * Shape::kRow * stride_ +
|
| 362 |
+
offset.column() * Shape::kColumn / LoadType::kElements;
|
| 363 |
+
}
|
| 364 |
+
}
|
| 365 |
+
|
| 366 |
+
/// Loads a fragment from memory
|
| 367 |
+
CUTLASS_DEVICE
|
| 368 |
+
void load_with_pointer_offset(Fragment &frag, Index pointer_offset) {
|
| 369 |
+
|
| 370 |
+
CUTLASS_PRAGMA_UNROLL
|
| 371 |
+
for (int cluster = 0; cluster < ThreadMap::Iterations::kCluster; ++cluster) {
|
| 372 |
+
|
| 373 |
+
CUTLASS_PRAGMA_UNROLL
|
| 374 |
+
for (int group = 0; group < ThreadMap::Iterations::kGroup; ++group) {
|
| 375 |
+
|
| 376 |
+
CUTLASS_PRAGMA_UNROLL
|
| 377 |
+
for (int row = 0; row < ThreadMap::Iterations::kRow; ++row) {
|
| 378 |
+
|
| 379 |
+
int row_ptr_offset =
|
| 380 |
+
row * ThreadMap::Delta::kRow * stride_ +
|
| 381 |
+
group * ThreadMap::Delta::kGroup* stride_ +
|
| 382 |
+
cluster * ThreadMap::Delta::kCluster * stride_ +
|
| 383 |
+
pointer_offset / LoadType::kElements;
|
| 384 |
+
|
| 385 |
+
int frag_row_idx = (row + ThreadMap::Iterations::kRow * (group + ThreadMap::Iterations::kGroup * cluster));
|
| 386 |
+
|
| 387 |
+
LoadType *frag_ptr = reinterpret_cast<LoadType *>(&frag);
|
| 388 |
+
|
| 389 |
+
CUTLASS_PRAGMA_UNROLL
|
| 390 |
+
for (int column = 0; column < ThreadMap::Iterations::kColumn; ++column) {
|
| 391 |
+
|
| 392 |
+
int frag_idx = frag_row_idx * ThreadMap::Iterations::kColumn + column;
|
| 393 |
+
|
| 394 |
+
CUTLASS_PRAGMA_UNROLL
|
| 395 |
+
for (int v = 0; v < kLoadsPerAccess; ++v) {
|
| 396 |
+
|
| 397 |
+
LoadType const *memory_pointer = pointers_[v];
|
| 398 |
+
|
| 399 |
+
frag_ptr[frag_idx * kLoadsPerAccess + v] = memory_pointer[row_ptr_offset];
|
| 400 |
+
}
|
| 401 |
+
}
|
| 402 |
+
}
|
| 403 |
+
}
|
| 404 |
+
}
|
| 405 |
+
}
|
| 406 |
+
|
| 407 |
+
/// Set base smem address
|
| 408 |
+
CUTLASS_DEVICE
|
| 409 |
+
void set_smem_base_address(Index address) {}
|
| 410 |
+
|
| 411 |
+
/// Loads a fragment
|
| 412 |
+
CUTLASS_DEVICE
|
| 413 |
+
void load(Fragment &frag) {
|
| 414 |
+
|
| 415 |
+
load_with_pointer_offset(frag, 0);
|
| 416 |
+
}
|
| 417 |
+
};
|
| 418 |
+
|
| 419 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 420 |
+
|
| 421 |
+
/// Partial specialization for:
|
| 422 |
+
/// int32_t x 8 => int8_t/int4b_t x 8 and
|
| 423 |
+
/// float x 8 => float_e4m3_t/float_e5m2_t x 8
|
| 424 |
+
template <
|
| 425 |
+
typename ThreadMap_, ///< Thread map (concept: OutputTileThreadMap)
|
| 426 |
+
typename Element_,
|
| 427 |
+
int OutputSizeBits_
|
| 428 |
+
>
|
| 429 |
+
class SharedLoadIteratorMixed<ThreadMap_, Element_, 32, OutputSizeBits_, 8, 8, true> {
|
| 430 |
+
public:
|
| 431 |
+
using ThreadMap = ThreadMap_;
|
| 432 |
+
using Shape = typename ThreadMap::Shape;
|
| 433 |
+
|
| 434 |
+
using Element = Element_;
|
| 435 |
+
static_assert(sizeof_bits<Element>::value == 32, "Element size in bits must be 32.");
|
| 436 |
+
|
| 437 |
+
using Layout = layout::RowMajor;
|
| 438 |
+
using TensorRef = TensorRef<Element, Layout>;
|
| 439 |
+
using ConstTensorRef = typename TensorRef::ConstTensorRef;
|
| 440 |
+
|
| 441 |
+
using Index = typename Layout::Index;
|
| 442 |
+
using LongIndex = typename Layout::LongIndex;
|
| 443 |
+
using TensorCoord = MatrixCoord;
|
| 444 |
+
|
| 445 |
+
static int const kElementsPerAccess = ThreadMap::kElementsPerAccess;
|
| 446 |
+
|
| 447 |
+
static int const kAlignment = 8;
|
| 448 |
+
|
| 449 |
+
static int const kThreads = ThreadMap::kThreads;
|
| 450 |
+
|
| 451 |
+
/// Fragment object
|
| 452 |
+
using Fragment = Array<
|
| 453 |
+
Element,
|
| 454 |
+
ThreadMap::Iterations::kColumn *
|
| 455 |
+
ThreadMap::Iterations::kRow *
|
| 456 |
+
ThreadMap::Iterations::kGroup *
|
| 457 |
+
ThreadMap::Iterations::kCluster *
|
| 458 |
+
ThreadMap::kElementsPerAccess>;
|
| 459 |
+
|
| 460 |
+
/// Memory access size
|
| 461 |
+
using AccessType = AlignedArray<
|
| 462 |
+
Element,
|
| 463 |
+
8,
|
| 464 |
+
kAlignment>;
|
| 465 |
+
|
| 466 |
+
/// Vector type used for SMEM loads
|
| 467 |
+
using LoadType = AlignedArray<
|
| 468 |
+
Element,
|
| 469 |
+
4,
|
| 470 |
+
16
|
| 471 |
+
>;
|
| 472 |
+
|
| 473 |
+
static int const kLoadsPerAccess = 2;
|
| 474 |
+
|
| 475 |
+
private:
|
| 476 |
+
|
| 477 |
+
//
|
| 478 |
+
// Data members
|
| 479 |
+
//
|
| 480 |
+
|
| 481 |
+
/// Byte-level pointer
|
| 482 |
+
LoadType const *pointers_[kLoadsPerAccess];
|
| 483 |
+
|
| 484 |
+
/// Stride along adjacent rows in units of LoadType
|
| 485 |
+
int stride_;
|
| 486 |
+
|
| 487 |
+
public:
|
| 488 |
+
|
| 489 |
+
//
|
| 490 |
+
// Methods
|
| 491 |
+
//
|
| 492 |
+
|
| 493 |
+
/// Constructor
|
| 494 |
+
CUTLASS_DEVICE
|
| 495 |
+
SharedLoadIteratorMixed(
|
| 496 |
+
TensorRef ref,
|
| 497 |
+
int thread_idx
|
| 498 |
+
):
|
| 499 |
+
stride_((ref.stride(0) / LoadType::kElements)) {
|
| 500 |
+
|
| 501 |
+
TensorCoord thread_offset = ThreadMap::initial_offset(thread_idx);
|
| 502 |
+
|
| 503 |
+
// Initialize pointers
|
| 504 |
+
LoadType const *base_ptr = reinterpret_cast<LoadType const *>(ref.data()) + thread_offset.row() * stride_;
|
| 505 |
+
|
| 506 |
+
int lane_col_idx = thread_offset.column() / 8;
|
| 507 |
+
|
| 508 |
+
CUTLASS_PRAGMA_UNROLL
|
| 509 |
+
for (int i = 0; i < kLoadsPerAccess; ++i) {
|
| 510 |
+
int lane_offset = (lane_col_idx % 8) * 2 | ((lane_col_idx / 4) ^ i);
|
| 511 |
+
|
| 512 |
+
pointers_[i] = base_ptr + lane_offset;
|
| 513 |
+
}
|
| 514 |
+
}
|
| 515 |
+
|
| 516 |
+
/// Adds a pointer offset in units of Element
|
| 517 |
+
CUTLASS_HOST_DEVICE
|
| 518 |
+
void add_pointer_offset(LongIndex pointer_offset) {
|
| 519 |
+
CUTLASS_PRAGMA_UNROLL
|
| 520 |
+
for (int i = 0; i < kLoadsPerAccess; ++i) {
|
| 521 |
+
pointers_[i] += pointer_offset / LoadType::kElements;
|
| 522 |
+
}
|
| 523 |
+
}
|
| 524 |
+
|
| 525 |
+
CUTLASS_DEVICE
|
| 526 |
+
void add_tile_offset(TensorCoord const &offset) {
|
| 527 |
+
CUTLASS_PRAGMA_UNROLL
|
| 528 |
+
for (int i = 0; i < kLoadsPerAccess; ++i) {
|
| 529 |
+
pointers_[i] +=
|
| 530 |
+
offset.row() * Shape::kRow * stride_ +
|
| 531 |
+
offset.column() * Shape::kColumn / LoadType::kElements;
|
| 532 |
+
}
|
| 533 |
+
}
|
| 534 |
+
|
| 535 |
+
/// Loads a fragment from memory
|
| 536 |
+
CUTLASS_DEVICE
|
| 537 |
+
void load_with_pointer_offset(Fragment &frag, Index pointer_offset) {
|
| 538 |
+
|
| 539 |
+
CUTLASS_PRAGMA_UNROLL
|
| 540 |
+
for (int cluster = 0; cluster < ThreadMap::Iterations::kCluster; ++cluster) {
|
| 541 |
+
|
| 542 |
+
CUTLASS_PRAGMA_UNROLL
|
| 543 |
+
for (int group = 0; group < ThreadMap::Iterations::kGroup; ++group) {
|
| 544 |
+
|
| 545 |
+
CUTLASS_PRAGMA_UNROLL
|
| 546 |
+
for (int row = 0; row < ThreadMap::Iterations::kRow; ++row) {
|
| 547 |
+
|
| 548 |
+
int row_ptr_offset =
|
| 549 |
+
row * ThreadMap::Delta::kRow * stride_ +
|
| 550 |
+
group * ThreadMap::Delta::kGroup* stride_ +
|
| 551 |
+
cluster * ThreadMap::Delta::kCluster * stride_ +
|
| 552 |
+
pointer_offset / LoadType::kElements;
|
| 553 |
+
|
| 554 |
+
int frag_row_idx = (row + ThreadMap::Iterations::kRow * (group + ThreadMap::Iterations::kGroup * cluster));
|
| 555 |
+
|
| 556 |
+
LoadType *frag_ptr = reinterpret_cast<LoadType *>(&frag);
|
| 557 |
+
|
| 558 |
+
CUTLASS_PRAGMA_UNROLL
|
| 559 |
+
for (int column = 0; column < ThreadMap::Iterations::kColumn; ++column) {
|
| 560 |
+
|
| 561 |
+
int frag_idx = frag_row_idx * ThreadMap::Iterations::kColumn + column;
|
| 562 |
+
|
| 563 |
+
CUTLASS_PRAGMA_UNROLL
|
| 564 |
+
for (int v = 0; v < kLoadsPerAccess; ++v) {
|
| 565 |
+
|
| 566 |
+
LoadType const *memory_pointer = pointers_[v];
|
| 567 |
+
|
| 568 |
+
frag_ptr[frag_idx * kLoadsPerAccess + v] = memory_pointer[row_ptr_offset];
|
| 569 |
+
}
|
| 570 |
+
}
|
| 571 |
+
}
|
| 572 |
+
}
|
| 573 |
+
}
|
| 574 |
+
}
|
| 575 |
+
|
| 576 |
+
/// Set base smem address
|
| 577 |
+
CUTLASS_DEVICE
|
| 578 |
+
void set_smem_base_address(Index address) {}
|
| 579 |
+
|
| 580 |
+
/// Loads a fragment
|
| 581 |
+
CUTLASS_DEVICE
|
| 582 |
+
void load(Fragment &frag) {
|
| 583 |
+
|
| 584 |
+
load_with_pointer_offset(frag, 0);
|
| 585 |
+
}
|
| 586 |
+
};
|
| 587 |
+
|
| 588 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 589 |
+
|
| 590 |
+
} // namespace threadblock
|
| 591 |
+
} // namespace epilogue
|
| 592 |
+
} // namespace cutlass
|
| 593 |
+
|
| 594 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/shared_load_iterator_pitch_linear.h
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief Epilogue for threadblock scoped GEMMs using Tensor Ops.
|
| 33 |
+
|
| 34 |
+
This assumes the shared memory tile is in a permuted layout which avoids bank conflicts on loading.
|
| 35 |
+
|
| 36 |
+
When the fragment is loaded into registers, it matches the row-major thread map assumed by
|
| 37 |
+
the predicated tile iterator writing to global memory.
|
| 38 |
+
|
| 39 |
+
The epilogue rearranges the result of a matrix product through shared memory to match canonical
|
| 40 |
+
tensor layouts in global memory. Epilogues support conversion and reduction operations.
|
| 41 |
+
*/
|
| 42 |
+
|
| 43 |
+
#pragma once
|
| 44 |
+
|
| 45 |
+
#include "cutlass/array.h"
|
| 46 |
+
#include "cutlass/cutlass.h"
|
| 47 |
+
#include "cutlass/epilogue/threadblock/output_tile_thread_map.h"
|
| 48 |
+
#include "cutlass/transform/pitch_linear_thread_map.h"
|
| 49 |
+
#include "cutlass/layout/matrix.h"
|
| 50 |
+
#include "cutlass/matrix_shape.h"
|
| 51 |
+
#include "cutlass/numeric_types.h"
|
| 52 |
+
#include "cutlass/tensor_ref.h"
|
| 53 |
+
|
| 54 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 55 |
+
|
| 56 |
+
namespace cutlass {
|
| 57 |
+
namespace epilogue {
|
| 58 |
+
namespace threadblock {
|
| 59 |
+
|
| 60 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 61 |
+
|
| 62 |
+
/// Tile iterator used to load output tile from shared memory in epilogue.
|
| 63 |
+
///
|
| 64 |
+
/// Satisfies: ReadableTileIterator
|
| 65 |
+
///
|
| 66 |
+
template <typename ThreadMap_, ///< Thread map (conept: PitchLinearThreadMap)
|
| 67 |
+
typename Element_, ///< Element data type
|
| 68 |
+
int MaxAlignment = ThreadMap_::kElementsPerAccess *sizeof_bits<Element_>::value / 8>
|
| 69 |
+
class SharedLoadIteratorPitchLinear {
|
| 70 |
+
public:
|
| 71 |
+
using ThreadMap = ThreadMap_;
|
| 72 |
+
using Element = Element_;
|
| 73 |
+
|
| 74 |
+
using Layout = layout::RowMajor;
|
| 75 |
+
using TensorRef = TensorRef<Element, Layout>;
|
| 76 |
+
using ConstTensorRef = typename TensorRef::ConstTensorRef;
|
| 77 |
+
|
| 78 |
+
using Index = typename Layout::Index;
|
| 79 |
+
using LongIndex = typename Layout::LongIndex;
|
| 80 |
+
using TensorCoord = MatrixCoord;
|
| 81 |
+
|
| 82 |
+
static int const kElementsPerAccess = ThreadMap::kElementsPerAccess;
|
| 83 |
+
|
| 84 |
+
static int const kMinAlignment =
|
| 85 |
+
ThreadMap_::kElementsPerAccess * sizeof_bits<Element_>::value / 8;
|
| 86 |
+
|
| 87 |
+
static int const kAlignment = (MaxAlignment < kMinAlignment ? MaxAlignment : kMinAlignment);
|
| 88 |
+
|
| 89 |
+
static int const kThreads = ThreadMap::kThreads;
|
| 90 |
+
|
| 91 |
+
/// Fragment object
|
| 92 |
+
using Fragment = Array<Element, ThreadMap::Iterations::kCount * kElementsPerAccess>;
|
| 93 |
+
|
| 94 |
+
/// Memory access size
|
| 95 |
+
using AccessType = AlignedArray<Element, kElementsPerAccess, kAlignment>;
|
| 96 |
+
|
| 97 |
+
/// Vector type used for SMEM loads
|
| 98 |
+
using LoadType =
|
| 99 |
+
AlignedArray<Element,
|
| 100 |
+
const_min(128 / sizeof_bits<Element>::value, ThreadMap::kElementsPerAccess),
|
| 101 |
+
const_min(16, kAlignment)>;
|
| 102 |
+
|
| 103 |
+
static int const kLoadsPerAccess = AccessType::kElements / LoadType::kElements;
|
| 104 |
+
|
| 105 |
+
private:
|
| 106 |
+
//
|
| 107 |
+
// Data members
|
| 108 |
+
//
|
| 109 |
+
|
| 110 |
+
/// Byte-level pointer
|
| 111 |
+
uint8_t *byte_pointer_;
|
| 112 |
+
|
| 113 |
+
/// Stride along adjacent rows
|
| 114 |
+
int stride_;
|
| 115 |
+
|
| 116 |
+
/// Base address offset
|
| 117 |
+
Index base_smem_address_;
|
| 118 |
+
|
| 119 |
+
public:
|
| 120 |
+
//
|
| 121 |
+
// Methods
|
| 122 |
+
//
|
| 123 |
+
|
| 124 |
+
/// Constructor
|
| 125 |
+
CUTLASS_DEVICE
|
| 126 |
+
SharedLoadIteratorPitchLinear(TensorRef ref, int thread_idx)
|
| 127 |
+
: byte_pointer_(reinterpret_cast<uint8_t *>(ref.data())),
|
| 128 |
+
stride_((ref.stride(0) * sizeof_bits<Element>::value) / 8),
|
| 129 |
+
base_smem_address_(0) {
|
| 130 |
+
TensorCoord thread_offset = ThreadMap::initial_offset(thread_idx);
|
| 131 |
+
|
| 132 |
+
// Initialize pointer
|
| 133 |
+
// thread_offset.row() is contiguous dim
|
| 134 |
+
// thread_offset.column() is stride dim
|
| 135 |
+
byte_pointer_ += thread_offset.row() * sizeof(AccessType) / kElementsPerAccess+
|
| 136 |
+
thread_offset.column() * stride_ ;
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
/// Adds a pointer offset in units of Element
|
| 140 |
+
CUTLASS_HOST_DEVICE
|
| 141 |
+
void add_pointer_offset(LongIndex pointer_offset) {
|
| 142 |
+
byte_pointer_ += pointer_offset * sizeof_bits<Element>::value / 8;
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
CUTLASS_DEVICE
|
| 146 |
+
void add_tile_offset(TensorCoord const &offset) {
|
| 147 |
+
byte_pointer_ +=
|
| 148 |
+
offset.row() * ThreadMap::StorageShape::kContiguous * sizeof(AccessType) / kElementsPerAccess +
|
| 149 |
+
offset.column() * ThreadMap::StorageShape::kStrided * stride_;
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
/// Loads a fragment from memory
|
| 153 |
+
CUTLASS_DEVICE
|
| 154 |
+
void load_with_pointer_offset(Fragment &frag, Index pointer_offset) const {
|
| 155 |
+
CUTLASS_PRAGMA_UNROLL
|
| 156 |
+
for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) {
|
| 157 |
+
CUTLASS_PRAGMA_UNROLL
|
| 158 |
+
for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) {
|
| 159 |
+
uint8_t const *byte_pointer =
|
| 160 |
+
byte_pointer_ + s * ThreadMap::Delta::kStrided * stride_ +
|
| 161 |
+
c * ThreadMap::Delta::kContiguous * ThreadMap::kElementsPerAccess *
|
| 162 |
+
sizeof_bits<Element>::value / 8 +
|
| 163 |
+
pointer_offset * sizeof_bits<Element>::value / 8 + base_smem_address_;
|
| 164 |
+
|
| 165 |
+
int frag_base_idx = s * ThreadMap::Iterations::kContiguous + c;
|
| 166 |
+
|
| 167 |
+
LoadType *frag_ptr = reinterpret_cast<LoadType *>(&frag);
|
| 168 |
+
|
| 169 |
+
LoadType const *memory_pointer = reinterpret_cast<LoadType const *>(byte_pointer);
|
| 170 |
+
|
| 171 |
+
CUTLASS_PRAGMA_UNROLL
|
| 172 |
+
for (int v = 0; v < kLoadsPerAccess; ++v) {
|
| 173 |
+
frag_ptr[frag_base_idx * kLoadsPerAccess + v] = memory_pointer[v];
|
| 174 |
+
}
|
| 175 |
+
}
|
| 176 |
+
}
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
/// Loads a fragment from memory
|
| 180 |
+
CUTLASS_DEVICE
|
| 181 |
+
void set_smem_base_address(Index address) { base_smem_address_ = address; }
|
| 182 |
+
|
| 183 |
+
/// Loads a fragment
|
| 184 |
+
CUTLASS_DEVICE
|
| 185 |
+
void load(Fragment &frag) const { load_with_pointer_offset(frag, 0); }
|
| 186 |
+
};
|
| 187 |
+
|
| 188 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 189 |
+
|
| 190 |
+
} // namespace threadblock
|
| 191 |
+
} // namespace epilogue
|
| 192 |
+
} // namespace cutlass
|
| 193 |
+
|
| 194 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/fragment_iterator_complex_tensor_op.h
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief This defines a "fragment" iterator for visiting the fragments of an accumulator tile
|
| 33 |
+
that participate in one warp-level store operation.
|
| 34 |
+
|
| 35 |
+
Typically, the accumulator tile is the largest single block of register-backed storage
|
| 36 |
+
within the kernel. Storing it to memory is best accomplished by partitioning it into
|
| 37 |
+
smaller tiles and storing these sequentially.
|
| 38 |
+
|
| 39 |
+
Round trips through shared memory during the Epilogue phase require partitioning, as
|
| 40 |
+
shared memory capacity is typically insufficient for a threadblock's total accumulator
|
| 41 |
+
size.
|
| 42 |
+
*/
|
| 43 |
+
|
| 44 |
+
#pragma once
|
| 45 |
+
|
| 46 |
+
#include "cutlass/array.h"
|
| 47 |
+
#include "cutlass/layout/matrix.h"
|
| 48 |
+
|
| 49 |
+
#include "cutlass/epilogue/warp/tensor_op_policy.h"
|
| 50 |
+
|
| 51 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 52 |
+
|
| 53 |
+
namespace cutlass {
|
| 54 |
+
namespace epilogue {
|
| 55 |
+
namespace warp {
|
| 56 |
+
|
| 57 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 58 |
+
|
| 59 |
+
///
|
| 60 |
+
template <
|
| 61 |
+
typename WarpShape, ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 62 |
+
typename OperatorShape, ///< matrix multiply operation shape (concept: gemm::GemmShape)
|
| 63 |
+
typename OperatorElementC, ///< matrix multiply operation data type (concept: data type)
|
| 64 |
+
typename OperatorFragmentC, ///< matrix multiply operation fragment (concept: Array)
|
| 65 |
+
typename Layout ///< target shared memory layout
|
| 66 |
+
>
|
| 67 |
+
class FragmentIteratorComplexTensorOp;
|
| 68 |
+
|
| 69 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
/// Partial specialization for row-major shared memory
|
| 73 |
+
template <
|
| 74 |
+
typename WarpShape_, ///< shape of the warp-level GEMM tile
|
| 75 |
+
typename OperatorShape_, ///< underlying real-valued matrix multiply operation shape (concept: gemm::GemmShape)
|
| 76 |
+
typename OperatorElementC_, ///< underlying real-valued matrix multiply operation data type
|
| 77 |
+
typename OperatorFragmentC_ ///< underlying real-valued matrix multiply operation fragment (concept: Array)
|
| 78 |
+
>
|
| 79 |
+
class FragmentIteratorComplexTensorOp<WarpShape_, OperatorShape_, OperatorElementC_, OperatorFragmentC_, layout::RowMajor> {
|
| 80 |
+
public:
|
| 81 |
+
|
| 82 |
+
using WarpShape = WarpShape_;
|
| 83 |
+
using OperatorShape = OperatorShape_;
|
| 84 |
+
using OperatorElementC = OperatorElementC_;
|
| 85 |
+
using OperatorFragmentC = OperatorFragmentC_;
|
| 86 |
+
using Layout = layout::RowMajor;
|
| 87 |
+
|
| 88 |
+
using Policy = TensorOpPolicy<WarpShape, OperatorShape, Layout>;
|
| 89 |
+
|
| 90 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 91 |
+
using Fragment = Array<
|
| 92 |
+
complex<OperatorElementC>,
|
| 93 |
+
Policy::OperatorCount::kColumn * Policy::kElementsPerAccess>;
|
| 94 |
+
|
| 95 |
+
static int const kRealIndex = 0;
|
| 96 |
+
|
| 97 |
+
/// Offset into the accumulator fragment
|
| 98 |
+
static int const kImaginaryIndex =
|
| 99 |
+
OperatorFragmentC::kElements * Policy::OperatorCount::kRow * Policy::OperatorCount::kColumn;
|
| 100 |
+
|
| 101 |
+
/// This is the complete warp-level accumulator tile.
|
| 102 |
+
using AccumulatorTile = Array<OperatorElementC, 2 * kImaginaryIndex>;
|
| 103 |
+
|
| 104 |
+
/// This is the complete warp-level accumulator tile.
|
| 105 |
+
using OutputAccumulatorTile = Array<complex<OperatorElementC>, kImaginaryIndex>;
|
| 106 |
+
|
| 107 |
+
/// Number of times this iterator can be incremented
|
| 108 |
+
static int const kIterations = Policy::kIterations;
|
| 109 |
+
|
| 110 |
+
private:
|
| 111 |
+
|
| 112 |
+
/// Internal access type
|
| 113 |
+
using AccessType = Array<OperatorElementC, Policy::kElementsPerAccess>;
|
| 114 |
+
|
| 115 |
+
using FragmentAccessType = Array<complex<OperatorElementC>, Policy::kElementsPerAccess>;
|
| 116 |
+
|
| 117 |
+
private:
|
| 118 |
+
|
| 119 |
+
//
|
| 120 |
+
// Data members
|
| 121 |
+
//
|
| 122 |
+
|
| 123 |
+
/// Accumulator tile
|
| 124 |
+
AccessType const *accumulators_;
|
| 125 |
+
|
| 126 |
+
/// Internal index
|
| 127 |
+
int index_;
|
| 128 |
+
|
| 129 |
+
public:
|
| 130 |
+
|
| 131 |
+
/// Constructs an iterator
|
| 132 |
+
CUTLASS_HOST_DEVICE
|
| 133 |
+
FragmentIteratorComplexTensorOp(AccumulatorTile const &accum):
|
| 134 |
+
accumulators_(reinterpret_cast<AccessType const *>(&accum)),
|
| 135 |
+
index_(0) {
|
| 136 |
+
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
/// Increments
|
| 140 |
+
CUTLASS_HOST_DEVICE
|
| 141 |
+
FragmentIteratorComplexTensorOp &operator++() {
|
| 142 |
+
++index_;
|
| 143 |
+
return *this;
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
/// Decrements
|
| 147 |
+
CUTLASS_HOST_DEVICE
|
| 148 |
+
FragmentIteratorComplexTensorOp &operator--() {
|
| 149 |
+
--index_;
|
| 150 |
+
return *this;
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
/// Loads a fragment from the referenced part of the accumulator tile
|
| 154 |
+
CUTLASS_HOST_DEVICE
|
| 155 |
+
void load(Fragment &frag, int index_offset = 0) const {
|
| 156 |
+
|
| 157 |
+
int index = index_ + index_offset;
|
| 158 |
+
|
| 159 |
+
FragmentAccessType *frag_ptr = reinterpret_cast<FragmentAccessType *>(&frag);
|
| 160 |
+
|
| 161 |
+
CUTLASS_PRAGMA_UNROLL
|
| 162 |
+
for (int n = 0; n < Policy::OperatorCount::kColumn; ++n) {
|
| 163 |
+
|
| 164 |
+
int accumulator_access_offset =
|
| 165 |
+
index + n * Policy::kAccumulatorColumnStride / Policy::kElementsPerAccess;
|
| 166 |
+
|
| 167 |
+
auto const & real_accum_array = accumulators_[accumulator_access_offset + kRealIndex];
|
| 168 |
+
auto const & imag_accum_array = accumulators_[accumulator_access_offset + kImaginaryIndex / Policy::kElementsPerAccess];
|
| 169 |
+
|
| 170 |
+
// Pack real and imaginary parts into a structure. This is likely to result in MOVs
|
| 171 |
+
CUTLASS_PRAGMA_UNROLL
|
| 172 |
+
for (int i = 0; i < Policy::kElementsPerAccess; ++i) {
|
| 173 |
+
|
| 174 |
+
frag_ptr[n][i].real() = real_accum_array[i];
|
| 175 |
+
frag_ptr[n][i].imag() = imag_accum_array[i];
|
| 176 |
+
}
|
| 177 |
+
}
|
| 178 |
+
}
|
| 179 |
+
};
|
| 180 |
+
|
| 181 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 182 |
+
|
| 183 |
+
} // namespace warp
|
| 184 |
+
} // namespace epilogue
|
| 185 |
+
} // namespace cutlass
|
| 186 |
+
|
| 187 |
+
////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/fragment_iterator_gaussian_complex_tensor_op.h
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief This defines a "fragment" iterator for visiting the fragments of an accumulator tile
|
| 33 |
+
that participate in one warp-level store operation.
|
| 34 |
+
|
| 35 |
+
Typically, the accumulator tile is the largest single block of register-backed storage
|
| 36 |
+
within the kernel. Storing it to memory is best accomplished by partitioning it into
|
| 37 |
+
smaller tiles and storing these sequentially.
|
| 38 |
+
|
| 39 |
+
Round trips through shared memory during the Epilogue phase require partitioning, as
|
| 40 |
+
shared memory capacity is typically insufficient for a threadblock's total accumulator
|
| 41 |
+
size.
|
| 42 |
+
*/
|
| 43 |
+
|
| 44 |
+
#pragma once
|
| 45 |
+
|
| 46 |
+
#include "cutlass/array.h"
|
| 47 |
+
#include "cutlass/layout/matrix.h"
|
| 48 |
+
|
| 49 |
+
#include "cutlass/epilogue/warp/tensor_op_policy.h"
|
| 50 |
+
|
| 51 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 52 |
+
|
| 53 |
+
namespace cutlass {
|
| 54 |
+
namespace epilogue {
|
| 55 |
+
namespace warp {
|
| 56 |
+
|
| 57 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 58 |
+
|
| 59 |
+
///
|
| 60 |
+
template <
|
| 61 |
+
typename WarpShape, ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 62 |
+
typename OperatorShape, ///< matrix multiply operation shape (concept: gemm::GemmShape)
|
| 63 |
+
typename OperatorElementC, ///< matrix multiply operation data type (concept: data type)
|
| 64 |
+
typename OperatorFragmentC, ///< matrix multiply operation fragment (concept: Array)
|
| 65 |
+
typename Layout ///< target shared memory layout
|
| 66 |
+
>
|
| 67 |
+
class FragmentIteratorGaussianComplexTensorOp;
|
| 68 |
+
|
| 69 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
/// Partial specialization for row-major shared memory
|
| 73 |
+
template <
|
| 74 |
+
typename WarpShape_, ///< shape of the warp-level GEMM tile
|
| 75 |
+
typename OperatorShape_, ///< underlying real-valued matrix multiply operation shape (concept: gemm::GemmShape)
|
| 76 |
+
typename OperatorElementC_, ///< underlying real-valued matrix multiply operation data type
|
| 77 |
+
typename OperatorFragmentC_ ///< underlying real-valued matrix multiply operation fragment (concept: Array)
|
| 78 |
+
>
|
| 79 |
+
class FragmentIteratorGaussianComplexTensorOp<WarpShape_, OperatorShape_, OperatorElementC_, OperatorFragmentC_, layout::RowMajor> {
|
| 80 |
+
public:
|
| 81 |
+
|
| 82 |
+
using WarpShape = WarpShape_;
|
| 83 |
+
using OperatorShape = OperatorShape_;
|
| 84 |
+
using OperatorElementC = OperatorElementC_;
|
| 85 |
+
using OperatorFragmentC = OperatorFragmentC_;
|
| 86 |
+
using Layout = layout::RowMajor;
|
| 87 |
+
|
| 88 |
+
using Policy = TensorOpPolicy<WarpShape, OperatorShape, Layout>;
|
| 89 |
+
|
| 90 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 91 |
+
using Fragment = Array<
|
| 92 |
+
complex<OperatorElementC>,
|
| 93 |
+
Policy::OperatorCount::kColumn * Policy::kElementsPerAccess>;
|
| 94 |
+
|
| 95 |
+
/// Size of one part of accumulator of 3-part accumulator in units of number of OperatorElementC
|
| 96 |
+
static int const kElementsAccumulatorPerPart =
|
| 97 |
+
OperatorFragmentC::kElements * Policy::OperatorCount::kRow * Policy::OperatorCount::kColumn;
|
| 98 |
+
|
| 99 |
+
/// Offset into the accumulator fragment part 1
|
| 100 |
+
static int const kPart1Index = kElementsAccumulatorPerPart * 0;
|
| 101 |
+
|
| 102 |
+
/// Offset into the accumulator fragment part 2
|
| 103 |
+
static int const kPart2Index = kElementsAccumulatorPerPart * 1;
|
| 104 |
+
|
| 105 |
+
/// Offset into the accumulator fragment part 3
|
| 106 |
+
static int const kPart3Index = kElementsAccumulatorPerPart * 2;
|
| 107 |
+
|
| 108 |
+
/// This is the complete warp-level accumulator tile holding part1, part2, and part3
|
| 109 |
+
using AccumulatorTile = Array<OperatorElementC, kElementsAccumulatorPerPart * 3>;
|
| 110 |
+
|
| 111 |
+
/// This is the complete warp-level accumulator tile holding final output of complex<T> type
|
| 112 |
+
using OutputAccumulatorTile = Array<complex<OperatorElementC>, kElementsAccumulatorPerPart>;
|
| 113 |
+
|
| 114 |
+
/// Number of times this iterator can be incremented
|
| 115 |
+
static int const kIterations = Policy::kIterations;
|
| 116 |
+
|
| 117 |
+
private:
|
| 118 |
+
|
| 119 |
+
/// Internal access type
|
| 120 |
+
using AccessType = Array<OperatorElementC, Policy::kElementsPerAccess>;
|
| 121 |
+
|
| 122 |
+
using FragmentAccessType = Array<complex<OperatorElementC>, Policy::kElementsPerAccess>;
|
| 123 |
+
|
| 124 |
+
private:
|
| 125 |
+
|
| 126 |
+
//
|
| 127 |
+
// Data members
|
| 128 |
+
//
|
| 129 |
+
|
| 130 |
+
/// Accumulator tile
|
| 131 |
+
AccessType const *accumulators_;
|
| 132 |
+
|
| 133 |
+
/// Internal index
|
| 134 |
+
int index_;
|
| 135 |
+
|
| 136 |
+
public:
|
| 137 |
+
|
| 138 |
+
/// Constructs an iterator
|
| 139 |
+
CUTLASS_HOST_DEVICE
|
| 140 |
+
FragmentIteratorGaussianComplexTensorOp(AccumulatorTile const &accum):
|
| 141 |
+
accumulators_(reinterpret_cast<AccessType const *>(&accum)),
|
| 142 |
+
index_(0) {
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
/// Increments
|
| 146 |
+
CUTLASS_HOST_DEVICE
|
| 147 |
+
FragmentIteratorGaussianComplexTensorOp &operator++() {
|
| 148 |
+
++index_;
|
| 149 |
+
return *this;
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
/// Decrements
|
| 153 |
+
CUTLASS_HOST_DEVICE
|
| 154 |
+
FragmentIteratorGaussianComplexTensorOp &operator--() {
|
| 155 |
+
--index_;
|
| 156 |
+
return *this;
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
/// Loads a fragment from the referenced part of the accumulator tile
|
| 160 |
+
CUTLASS_HOST_DEVICE
|
| 161 |
+
void load(Fragment &frag, int index_offset = 0) const {
|
| 162 |
+
|
| 163 |
+
int index = index_ + index_offset;
|
| 164 |
+
|
| 165 |
+
FragmentAccessType *frag_ptr = reinterpret_cast<FragmentAccessType *>(&frag);
|
| 166 |
+
|
| 167 |
+
CUTLASS_PRAGMA_UNROLL
|
| 168 |
+
for (int n = 0; n < Policy::OperatorCount::kColumn; ++n) {
|
| 169 |
+
|
| 170 |
+
int accumulator_access_offset =
|
| 171 |
+
index + n * Policy::kAccumulatorColumnStride / Policy::kElementsPerAccess;
|
| 172 |
+
|
| 173 |
+
auto const & part1_accum_array = accumulators_[accumulator_access_offset + kPart1Index];
|
| 174 |
+
auto const & part2_accum_array = accumulators_[accumulator_access_offset + kPart2Index / Policy::kElementsPerAccess];
|
| 175 |
+
auto const & part3_accum_array = accumulators_[accumulator_access_offset + kPart3Index / Policy::kElementsPerAccess];
|
| 176 |
+
|
| 177 |
+
// Pack parts 1, 2, and 3 into a structure. This is likely to result in MOVs
|
| 178 |
+
CUTLASS_PRAGMA_UNROLL
|
| 179 |
+
for (int i = 0; i < Policy::kElementsPerAccess; ++i) {
|
| 180 |
+
|
| 181 |
+
frag_ptr[n][i].real() = part1_accum_array[i] - part3_accum_array[i];
|
| 182 |
+
frag_ptr[n][i].imag() = part1_accum_array[i] + part2_accum_array[i];
|
| 183 |
+
}
|
| 184 |
+
}
|
| 185 |
+
}
|
| 186 |
+
};
|
| 187 |
+
|
| 188 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 189 |
+
|
| 190 |
+
} // namespace warp
|
| 191 |
+
} // namespace epilogue
|
| 192 |
+
} // namespace cutlass
|
| 193 |
+
|
| 194 |
+
////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/fragment_iterator_simt.h
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief This defines a "fragment" iterator for visiting the fragments of an accumulator tile
|
| 33 |
+
that participate in one warp-level store operation.
|
| 34 |
+
|
| 35 |
+
Typically, the accumulator tile is the largest single block of register-backed storage
|
| 36 |
+
within the kernel. Storing it to memory is best accomplished by partitioning it into
|
| 37 |
+
smaller tiles and storing these sequentially.
|
| 38 |
+
|
| 39 |
+
Round trips through shared memory during the Epilogue phase require partitioning, as
|
| 40 |
+
shared memory capacity is typically insufficient for a threadblock's total accumulator
|
| 41 |
+
size.
|
| 42 |
+
*/
|
| 43 |
+
|
| 44 |
+
#pragma once
|
| 45 |
+
|
| 46 |
+
#include "cutlass/array.h"
|
| 47 |
+
#include "cutlass/layout/matrix.h"
|
| 48 |
+
|
| 49 |
+
#include "cutlass/epilogue/warp/simt_policy.h"
|
| 50 |
+
|
| 51 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 52 |
+
|
| 53 |
+
namespace cutlass {
|
| 54 |
+
namespace epilogue {
|
| 55 |
+
namespace warp {
|
| 56 |
+
|
| 57 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 58 |
+
|
| 59 |
+
/// Fragment iterator for SIMT accumulator arrangements
|
| 60 |
+
template <
|
| 61 |
+
typename WarpShape, ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 62 |
+
typename Operator, ///< matrix multiply operation (concept: arch::Mma)
|
| 63 |
+
typename Layout, ///< target shared memory layout
|
| 64 |
+
typename MmaSimtPolicy ///< policy defining lane arrangement (concept: MmaSimtPolicy)
|
| 65 |
+
>
|
| 66 |
+
class FragmentIteratorSimt;
|
| 67 |
+
|
| 68 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 69 |
+
|
| 70 |
+
/// Partial specialization for row-major shared memory
|
| 71 |
+
template <
|
| 72 |
+
typename WarpShape_, ///< shape of the warp-level GEMM tile
|
| 73 |
+
typename Operator_ , ///< matrix multiply operator (concept: arch::Mma)
|
| 74 |
+
typename MmaSimtPolicy_ ///< policy defining lane arrangement (concept: MmaSimtPolicy)
|
| 75 |
+
>
|
| 76 |
+
class FragmentIteratorSimt<WarpShape_, Operator_, layout::RowMajor, MmaSimtPolicy_> {
|
| 77 |
+
public:
|
| 78 |
+
|
| 79 |
+
using WarpShape = WarpShape_;
|
| 80 |
+
using Operator = Operator_;
|
| 81 |
+
using Layout = layout::RowMajor;
|
| 82 |
+
|
| 83 |
+
/// Policy for warp-level epilogue components
|
| 84 |
+
using Policy = SimtPolicy<WarpShape, Operator, Layout, MmaSimtPolicy_>;
|
| 85 |
+
|
| 86 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 87 |
+
using Fragment = Array<
|
| 88 |
+
typename Operator::ElementC,
|
| 89 |
+
Policy::kElementsPerIteration>;
|
| 90 |
+
|
| 91 |
+
/// This is the complete warp-level accumulator tile.
|
| 92 |
+
using AccumulatorTile = Array<
|
| 93 |
+
typename Operator::ElementC,
|
| 94 |
+
Policy::kAccumulatorElementCount>;
|
| 95 |
+
|
| 96 |
+
using OutputAccumulatorTile = AccumulatorTile;
|
| 97 |
+
|
| 98 |
+
/// Number of times this iterator can be incremented
|
| 99 |
+
static int const kIterations = Policy::kIterations;
|
| 100 |
+
|
| 101 |
+
private:
|
| 102 |
+
|
| 103 |
+
/// Internal access type
|
| 104 |
+
using AccessType = Array<typename Operator::ElementC, Policy::kElementsPerAccess>;
|
| 105 |
+
|
| 106 |
+
private:
|
| 107 |
+
|
| 108 |
+
//
|
| 109 |
+
// Data members
|
| 110 |
+
//
|
| 111 |
+
|
| 112 |
+
/// Accumulator tile
|
| 113 |
+
AccessType const *accumulators_;
|
| 114 |
+
|
| 115 |
+
/// Internal index
|
| 116 |
+
int index_;
|
| 117 |
+
|
| 118 |
+
public:
|
| 119 |
+
|
| 120 |
+
/// Constructs an iterator
|
| 121 |
+
CUTLASS_HOST_DEVICE
|
| 122 |
+
FragmentIteratorSimt(AccumulatorTile const &accum):
|
| 123 |
+
accumulators_(reinterpret_cast<AccessType const *>(&accum)),
|
| 124 |
+
index_(0) {
|
| 125 |
+
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
/// Increments
|
| 129 |
+
CUTLASS_HOST_DEVICE
|
| 130 |
+
FragmentIteratorSimt &operator++() {
|
| 131 |
+
++index_;
|
| 132 |
+
return *this;
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
/// Decrements
|
| 136 |
+
CUTLASS_HOST_DEVICE
|
| 137 |
+
FragmentIteratorSimt &operator--() {
|
| 138 |
+
--index_;
|
| 139 |
+
return *this;
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
/// Loads a fragment from the referenced part of the accumulator tile
|
| 143 |
+
CUTLASS_HOST_DEVICE
|
| 144 |
+
void load(Fragment &frag, int index_offset = 0) const {
|
| 145 |
+
|
| 146 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 147 |
+
|
| 148 |
+
CUTLASS_PRAGMA_UNROLL
|
| 149 |
+
for (int n = 0; n < Policy::kAccessesPerIteration; ++n) {
|
| 150 |
+
|
| 151 |
+
int accumulator_access_offset = index_ * Policy::kAccessesPerIteration + n;
|
| 152 |
+
|
| 153 |
+
frag_ptr[n] = accumulators_[accumulator_access_offset];
|
| 154 |
+
}
|
| 155 |
+
}
|
| 156 |
+
};
|
| 157 |
+
|
| 158 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 159 |
+
|
| 160 |
+
} // namespace warp
|
| 161 |
+
} // namespace epilogue
|
| 162 |
+
} // namespace cutlass
|
| 163 |
+
|
| 164 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/fragment_iterator_tensor_op.h
ADDED
|
@@ -0,0 +1,378 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief This defines a "fragment" iterator for visiting the fragments of an accumulator tile
|
| 33 |
+
that participate in one warp-level store operation.
|
| 34 |
+
|
| 35 |
+
Typically, the accumulator tile is the largest single block of register-backed storage
|
| 36 |
+
within the kernel. Storing it to memory is best accomplished by partitioning it into
|
| 37 |
+
smaller tiles and storing these sequentially.
|
| 38 |
+
|
| 39 |
+
Round trips through shared memory during the Epilogue phase require partitioning, as
|
| 40 |
+
shared memory capacity is typically insufficient for a threadblock's total accumulator
|
| 41 |
+
size.
|
| 42 |
+
*/
|
| 43 |
+
|
| 44 |
+
#pragma once
|
| 45 |
+
|
| 46 |
+
#include "cutlass/array.h"
|
| 47 |
+
#include "cutlass/layout/matrix.h"
|
| 48 |
+
|
| 49 |
+
#include "cutlass/epilogue/warp/tensor_op_policy.h"
|
| 50 |
+
|
| 51 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 52 |
+
|
| 53 |
+
namespace cutlass {
|
| 54 |
+
namespace epilogue {
|
| 55 |
+
namespace warp {
|
| 56 |
+
|
| 57 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 58 |
+
|
| 59 |
+
///
|
| 60 |
+
template <
|
| 61 |
+
typename WarpShape, ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 62 |
+
typename OperatorShape, ///< matrix multiply operation shape (concept: gemm::GemmShape)
|
| 63 |
+
typename OperatorElementC, ///< matrix multiply operation data type (concept: data type)
|
| 64 |
+
typename OperatorFragmentC, ///< matrix multiply operation fragment (concept: Array)
|
| 65 |
+
typename Layout ///< target shared memory layout
|
| 66 |
+
>
|
| 67 |
+
class FragmentIteratorTensorOp;
|
| 68 |
+
|
| 69 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 70 |
+
|
| 71 |
+
/// Partial specialization for row-major shared memory
|
| 72 |
+
template <
|
| 73 |
+
typename WarpShape_, ///< shape of the warp-level GEMM tile
|
| 74 |
+
typename OperatorShape_, ///< matrix multiply operation shape (concept: gemm::GemmShape)
|
| 75 |
+
typename OperatorElementC_, ///< matrix multiply operation data type (concept: data type)
|
| 76 |
+
typename OperatorFragmentC_ ///< matrix multiply operation fragment (concept: Array)
|
| 77 |
+
>
|
| 78 |
+
class FragmentIteratorTensorOp<WarpShape_, OperatorShape_, OperatorElementC_, OperatorFragmentC_, layout::RowMajor> {
|
| 79 |
+
public:
|
| 80 |
+
|
| 81 |
+
using WarpShape = WarpShape_;
|
| 82 |
+
using OperatorShape = OperatorShape_;
|
| 83 |
+
using OperatorElementC = OperatorElementC_;
|
| 84 |
+
using OperatorFragmentC = OperatorFragmentC_;
|
| 85 |
+
using Layout = layout::RowMajor;
|
| 86 |
+
|
| 87 |
+
using Policy = TensorOpPolicy<WarpShape, OperatorShape, Layout>;
|
| 88 |
+
|
| 89 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 90 |
+
using Fragment = Array<
|
| 91 |
+
OperatorElementC,
|
| 92 |
+
Policy::OperatorCount::kColumn * Policy::kElementsPerAccess>;
|
| 93 |
+
|
| 94 |
+
/// This is the complete warp-level accumulator tile.
|
| 95 |
+
using AccumulatorTile = Array<
|
| 96 |
+
OperatorElementC,
|
| 97 |
+
OperatorFragmentC::kElements * Policy::OperatorCount::kRow * Policy::OperatorCount::kColumn>;
|
| 98 |
+
|
| 99 |
+
using OutputAccumulatorTile = AccumulatorTile;
|
| 100 |
+
|
| 101 |
+
/// Number of times this iterator can be incremented
|
| 102 |
+
static int const kIterations = Policy::kIterations;
|
| 103 |
+
using TileIterations = typename Policy::TileIterations;
|
| 104 |
+
static int const kIterationsPerTile = kIterations / TileIterations::kCount;
|
| 105 |
+
|
| 106 |
+
private:
|
| 107 |
+
|
| 108 |
+
/// Internal access type
|
| 109 |
+
using AccessType = Array<OperatorElementC, Policy::kElementsPerAccess>;
|
| 110 |
+
|
| 111 |
+
private:
|
| 112 |
+
|
| 113 |
+
//
|
| 114 |
+
// Data members
|
| 115 |
+
//
|
| 116 |
+
|
| 117 |
+
/// Accumulator tile
|
| 118 |
+
AccessType const *accumulators_;
|
| 119 |
+
|
| 120 |
+
/// Internal index
|
| 121 |
+
int index_;
|
| 122 |
+
|
| 123 |
+
public:
|
| 124 |
+
|
| 125 |
+
/// Constructs an iterator
|
| 126 |
+
CUTLASS_HOST_DEVICE
|
| 127 |
+
FragmentIteratorTensorOp(AccumulatorTile const &accum):
|
| 128 |
+
accumulators_(reinterpret_cast<AccessType const *>(&accum)),
|
| 129 |
+
index_(0) {
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
/// Increments
|
| 133 |
+
CUTLASS_HOST_DEVICE
|
| 134 |
+
FragmentIteratorTensorOp &operator++() {
|
| 135 |
+
++index_;
|
| 136 |
+
return *this;
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
/// Decrements
|
| 140 |
+
CUTLASS_HOST_DEVICE
|
| 141 |
+
FragmentIteratorTensorOp &operator--() {
|
| 142 |
+
--index_;
|
| 143 |
+
return *this;
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
/// Loads a fragment from the referenced part of the accumulator tile
|
| 147 |
+
CUTLASS_HOST_DEVICE
|
| 148 |
+
void load(Fragment &frag, int index_offset = 0) const {
|
| 149 |
+
|
| 150 |
+
int index = index_ + index_offset;
|
| 151 |
+
|
| 152 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 153 |
+
|
| 154 |
+
CUTLASS_PRAGMA_UNROLL
|
| 155 |
+
for (int n = 0; n < Policy::OperatorCount::kColumn; ++n) {
|
| 156 |
+
|
| 157 |
+
int accumulator_access_offset =
|
| 158 |
+
index + n * Policy::kAccumulatorColumnStride / Policy::kElementsPerAccess;
|
| 159 |
+
|
| 160 |
+
frag_ptr[n] = accumulators_[accumulator_access_offset];
|
| 161 |
+
}
|
| 162 |
+
}
|
| 163 |
+
};
|
| 164 |
+
|
| 165 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 166 |
+
|
| 167 |
+
/// Partial specialization for col-major shared memory
|
| 168 |
+
/// Only works for 168x tensor core kernels
|
| 169 |
+
template <
|
| 170 |
+
typename WarpShape_, ///< shape of the warp-level GEMM tile
|
| 171 |
+
typename OperatorShape_, ///< matrix multiply operation shape (concept: gemm::GemmShape)
|
| 172 |
+
typename OperatorElementC_, ///< matrix multiply operation data type (concept: data type)
|
| 173 |
+
typename OperatorFragmentC_ ///< matrix multiply operation fragment (concept: Array)
|
| 174 |
+
>
|
| 175 |
+
class FragmentIteratorTensorOp<WarpShape_, OperatorShape_, OperatorElementC_, OperatorFragmentC_, layout::ColumnMajor> {
|
| 176 |
+
public:
|
| 177 |
+
|
| 178 |
+
using WarpShape = WarpShape_;
|
| 179 |
+
using OperatorShape = OperatorShape_;
|
| 180 |
+
using OperatorElementC = OperatorElementC_;
|
| 181 |
+
using OperatorFragmentC = OperatorFragmentC_;
|
| 182 |
+
using Layout = layout::ColumnMajor;
|
| 183 |
+
|
| 184 |
+
using Policy = TensorOpPolicy<WarpShape, OperatorShape, Layout>;
|
| 185 |
+
|
| 186 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 187 |
+
using Fragment = Array<
|
| 188 |
+
OperatorElementC,
|
| 189 |
+
4 * Policy::OperatorCount::kRow * Policy::kElementsPerAccess>;
|
| 190 |
+
|
| 191 |
+
/// This is the complete warp-level accumulator tile.
|
| 192 |
+
using AccumulatorTile = Array<
|
| 193 |
+
OperatorElementC,
|
| 194 |
+
OperatorFragmentC::kElements * Policy::OperatorCount::kRow * Policy::OperatorCount::kColumn>;
|
| 195 |
+
|
| 196 |
+
using OutputAccumulatorTile = AccumulatorTile;
|
| 197 |
+
|
| 198 |
+
/// Number of times this iterator can be incremented
|
| 199 |
+
static int const kIterations = Policy::kIterations;
|
| 200 |
+
using TileIterations = typename Policy::TileIterations;
|
| 201 |
+
static int const kIterationsPerTile = kIterations / TileIterations::kCount;
|
| 202 |
+
|
| 203 |
+
private:
|
| 204 |
+
|
| 205 |
+
/// Internal access type
|
| 206 |
+
using AccessType = Array<OperatorElementC, Policy::kElementsPerAccess>;
|
| 207 |
+
|
| 208 |
+
private:
|
| 209 |
+
|
| 210 |
+
//
|
| 211 |
+
// Data members
|
| 212 |
+
//
|
| 213 |
+
|
| 214 |
+
/// Accumulator tile
|
| 215 |
+
AccessType const *accumulators_;
|
| 216 |
+
|
| 217 |
+
/// Internal index
|
| 218 |
+
int index_;
|
| 219 |
+
|
| 220 |
+
public:
|
| 221 |
+
|
| 222 |
+
/// Constructs an iterator
|
| 223 |
+
CUTLASS_HOST_DEVICE
|
| 224 |
+
FragmentIteratorTensorOp(AccumulatorTile const &accum):
|
| 225 |
+
accumulators_(reinterpret_cast<AccessType const *>(&accum)),
|
| 226 |
+
index_(0) {
|
| 227 |
+
}
|
| 228 |
+
|
| 229 |
+
/// Increments
|
| 230 |
+
CUTLASS_HOST_DEVICE
|
| 231 |
+
FragmentIteratorTensorOp &operator++() {
|
| 232 |
+
++index_;
|
| 233 |
+
return *this;
|
| 234 |
+
}
|
| 235 |
+
|
| 236 |
+
/// Decrements
|
| 237 |
+
CUTLASS_HOST_DEVICE
|
| 238 |
+
FragmentIteratorTensorOp &operator--() {
|
| 239 |
+
--index_;
|
| 240 |
+
return *this;
|
| 241 |
+
}
|
| 242 |
+
|
| 243 |
+
/// Loads a fragment from the referenced part of the accumulator tile
|
| 244 |
+
CUTLASS_HOST_DEVICE
|
| 245 |
+
void load(Fragment &frag, int index_offset = 0) const {
|
| 246 |
+
|
| 247 |
+
int index = index_ + index_offset;
|
| 248 |
+
|
| 249 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 250 |
+
|
| 251 |
+
CUTLASS_PRAGMA_UNROLL
|
| 252 |
+
for (int i = 0; i < Policy::kAccumulatorRowStride; ++i) {
|
| 253 |
+
|
| 254 |
+
CUTLASS_PRAGMA_UNROLL
|
| 255 |
+
for (int m = 0; m < (Policy::OperatorCount::kRow * 2); ++m) {
|
| 256 |
+
|
| 257 |
+
int accumulator_access_offset =
|
| 258 |
+
index * Policy::kAccumulatorColumnStride + m * Policy::kAccumulatorRowStride / Policy::kElementsPerAccess + i;
|
| 259 |
+
|
| 260 |
+
frag_ptr[m + i * Policy::OperatorCount::kRow * 2] = accumulators_[accumulator_access_offset];
|
| 261 |
+
}
|
| 262 |
+
}
|
| 263 |
+
}
|
| 264 |
+
};
|
| 265 |
+
|
| 266 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 267 |
+
|
| 268 |
+
/// Dedicated to interleaved layout
|
| 269 |
+
template <
|
| 270 |
+
/// shape of the warp-level GEMM tile
|
| 271 |
+
typename WarpShape_,
|
| 272 |
+
/// matrix multiply operator shape (concept: gemm::GemmShape)
|
| 273 |
+
typename OperatorShape_,
|
| 274 |
+
/// matrix multiply operator data type (concept: data type)
|
| 275 |
+
typename OperatorElementC_,
|
| 276 |
+
/// matrix multiply operator fragment (concept: Array)
|
| 277 |
+
typename OperatorFragmentC_,
|
| 278 |
+
/// number of interleaved k
|
| 279 |
+
int InterleavedK>
|
| 280 |
+
class FragmentIteratorTensorOp<WarpShape_, OperatorShape_, OperatorElementC_, OperatorFragmentC_,
|
| 281 |
+
layout::ColumnMajorInterleaved<InterleavedK>> {
|
| 282 |
+
public:
|
| 283 |
+
using WarpShape = WarpShape_;
|
| 284 |
+
using OperatorShape = OperatorShape_;
|
| 285 |
+
using OperatorElementC = OperatorElementC_;
|
| 286 |
+
using OperatorFragmentC = OperatorFragmentC_;
|
| 287 |
+
static int const kInterleavedK = InterleavedK;
|
| 288 |
+
using Layout = layout::ColumnMajorInterleaved<kInterleavedK>;
|
| 289 |
+
|
| 290 |
+
using Policy = TensorOpPolicy<WarpShape, OperatorShape, Layout>;
|
| 291 |
+
|
| 292 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 293 |
+
using Fragment =
|
| 294 |
+
Array<OperatorElementC,
|
| 295 |
+
Policy::kElementsPerAccess * InterleavedK / OperatorShape::kN>;
|
| 296 |
+
|
| 297 |
+
/// This is the complete warp-level accumulator tile.
|
| 298 |
+
using AccumulatorTile =
|
| 299 |
+
Array<OperatorElementC, OperatorFragmentC::kElements *
|
| 300 |
+
Policy::OperatorCount::kRow *
|
| 301 |
+
Policy::OperatorCount::kColumn>;
|
| 302 |
+
|
| 303 |
+
/// Number of times this iterator can be incremented
|
| 304 |
+
static int const kIterations = Policy::kIterations;
|
| 305 |
+
using TileIterations = typename Policy::TileIterations;
|
| 306 |
+
static int const kIterationsPerTile = kIterations / TileIterations::kCount;
|
| 307 |
+
|
| 308 |
+
private:
|
| 309 |
+
/// Internal access type
|
| 310 |
+
using AccessType =
|
| 311 |
+
Array<OperatorElementC, Policy::kElementsPerAccess>;
|
| 312 |
+
|
| 313 |
+
private:
|
| 314 |
+
//
|
| 315 |
+
// Data members
|
| 316 |
+
//
|
| 317 |
+
|
| 318 |
+
/// Accumulator tile
|
| 319 |
+
AccessType const *accumulators_;
|
| 320 |
+
|
| 321 |
+
/// Internal index
|
| 322 |
+
int index_;
|
| 323 |
+
|
| 324 |
+
public:
|
| 325 |
+
/// Constructs an iterator
|
| 326 |
+
CUTLASS_HOST_DEVICE
|
| 327 |
+
FragmentIteratorTensorOp(AccumulatorTile const &accum)
|
| 328 |
+
: accumulators_(reinterpret_cast<AccessType const *>(&accum)),
|
| 329 |
+
index_(0) {}
|
| 330 |
+
|
| 331 |
+
/// Increments
|
| 332 |
+
CUTLASS_HOST_DEVICE
|
| 333 |
+
FragmentIteratorTensorOp &operator++() {
|
| 334 |
+
++index_;
|
| 335 |
+
return *this;
|
| 336 |
+
}
|
| 337 |
+
|
| 338 |
+
/// Decrements
|
| 339 |
+
CUTLASS_HOST_DEVICE
|
| 340 |
+
FragmentIteratorTensorOp &operator--() {
|
| 341 |
+
--index_;
|
| 342 |
+
return *this;
|
| 343 |
+
}
|
| 344 |
+
|
| 345 |
+
/// Loads a fragment from the referenced part of the accumulator tile
|
| 346 |
+
CUTLASS_HOST_DEVICE
|
| 347 |
+
void load(Fragment &frag, int index_offset = 0) const {
|
| 348 |
+
int index = index_ + index_offset;
|
| 349 |
+
|
| 350 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 351 |
+
|
| 352 |
+
CUTLASS_PRAGMA_UNROLL
|
| 353 |
+
for (int n = 0; n < (InterleavedK / OperatorShape::kN); ++n) {
|
| 354 |
+
int index_m = index % (Policy::OperatorCount::kRow *
|
| 355 |
+
Policy::kIterationsPerInstruction);
|
| 356 |
+
int index_n = index / (Policy::OperatorCount::kRow *
|
| 357 |
+
Policy::kIterationsPerInstruction);
|
| 358 |
+
int accumulator_access_offset =
|
| 359 |
+
(index_m / Policy::kIterationsPerInstruction) *
|
| 360 |
+
(Policy::OperatorCount::kColumn *
|
| 361 |
+
Policy::kIterationsPerInstruction) +
|
| 362 |
+
(index_m % Policy::kIterationsPerInstruction) +
|
| 363 |
+
index_n * (InterleavedK / OperatorShape::kN) *
|
| 364 |
+
Policy::kIterationsPerInstruction +
|
| 365 |
+
n * Policy::kIterationsPerInstruction;
|
| 366 |
+
|
| 367 |
+
frag_ptr[n] = accumulators_[accumulator_access_offset];
|
| 368 |
+
}
|
| 369 |
+
}
|
| 370 |
+
};
|
| 371 |
+
|
| 372 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 373 |
+
|
| 374 |
+
} // namespace warp
|
| 375 |
+
} // namespace epilogue
|
| 376 |
+
} // namespace cutlass
|
| 377 |
+
|
| 378 |
+
////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/fragment_iterator_volta_tensor_op.h
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief This defines a "fragment" iterator for visiting the fragments of an accumulator tile
|
| 33 |
+
that participate in one warp-level store operation.
|
| 34 |
+
|
| 35 |
+
Typically, the accumulator tile is the largest single block of register-backed storage
|
| 36 |
+
within the kernel. Storing it to memory is best accomplished by partitioning it into
|
| 37 |
+
smaller tiles and storing these sequentially.
|
| 38 |
+
|
| 39 |
+
Round trips through shared memory during the Epilogue phase require partitioning, as
|
| 40 |
+
shared memory capacity is typically insufficient for a threadblock's total accumulator
|
| 41 |
+
size.
|
| 42 |
+
*/
|
| 43 |
+
|
| 44 |
+
#pragma once
|
| 45 |
+
|
| 46 |
+
#include "cutlass/array.h"
|
| 47 |
+
#include "cutlass/layout/matrix.h"
|
| 48 |
+
#include "cutlass/gemm/gemm.h"
|
| 49 |
+
|
| 50 |
+
#include "cutlass/epilogue/warp/volta_tensor_op_policy.h"
|
| 51 |
+
|
| 52 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 53 |
+
|
| 54 |
+
namespace cutlass {
|
| 55 |
+
namespace epilogue {
|
| 56 |
+
namespace warp {
|
| 57 |
+
|
| 58 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 59 |
+
|
| 60 |
+
///
|
| 61 |
+
template <
|
| 62 |
+
typename WarpShape, ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 63 |
+
typename InterleavedTileShape, ///< shape of indivisible instruction-level arrangement (concept: GemmShape)
|
| 64 |
+
typename ElementC, ///< Accumulator layout
|
| 65 |
+
typename Layout ///< target shared memory layout
|
| 66 |
+
>
|
| 67 |
+
class FragmentIteratorVoltaTensorOp;
|
| 68 |
+
|
| 69 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 70 |
+
|
| 71 |
+
/// Partial specialization for row-major shared memory
|
| 72 |
+
template <
|
| 73 |
+
typename WarpShape_ ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 74 |
+
>
|
| 75 |
+
class FragmentIteratorVoltaTensorOp<WarpShape_, gemm::GemmShape<32, 32, 4>, half_t, layout::RowMajor> {
|
| 76 |
+
public:
|
| 77 |
+
|
| 78 |
+
using WarpShape = WarpShape_;
|
| 79 |
+
using InterleavedTileShape = gemm::GemmShape<32, 32, 4>;
|
| 80 |
+
using ElementC = half_t;
|
| 81 |
+
using Layout = layout::RowMajor;
|
| 82 |
+
|
| 83 |
+
/// Policy operator
|
| 84 |
+
using Policy = VoltaTensorOpPolicy<WarpShape, InterleavedTileShape, ElementC, Layout>;
|
| 85 |
+
|
| 86 |
+
/// Array type for aligned memory accesses
|
| 87 |
+
using AccessType = typename Policy::AccessType;
|
| 88 |
+
|
| 89 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 90 |
+
using Fragment = typename Policy::Fragment;
|
| 91 |
+
|
| 92 |
+
/// This is the complete warp-level accumulator tile.
|
| 93 |
+
using AccumulatorTile = typename Policy::AccumulatorTile;
|
| 94 |
+
|
| 95 |
+
using OutputAccumulatorTile = AccumulatorTile;
|
| 96 |
+
|
| 97 |
+
/// Number of times this iterator can be incremented
|
| 98 |
+
static int const kIterations = Policy::kIterations;
|
| 99 |
+
|
| 100 |
+
private:
|
| 101 |
+
|
| 102 |
+
private:
|
| 103 |
+
|
| 104 |
+
//
|
| 105 |
+
// Data members
|
| 106 |
+
//
|
| 107 |
+
|
| 108 |
+
/// Accumulator tile
|
| 109 |
+
AccessType const *accumulators_;
|
| 110 |
+
|
| 111 |
+
/// Internal index
|
| 112 |
+
int index_;
|
| 113 |
+
|
| 114 |
+
public:
|
| 115 |
+
|
| 116 |
+
/// Constructs an iterator
|
| 117 |
+
CUTLASS_HOST_DEVICE
|
| 118 |
+
FragmentIteratorVoltaTensorOp(AccumulatorTile const &accum):
|
| 119 |
+
accumulators_(reinterpret_cast<AccessType const *>(&accum)),
|
| 120 |
+
index_(0) {
|
| 121 |
+
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
/// Increments
|
| 125 |
+
CUTLASS_HOST_DEVICE
|
| 126 |
+
FragmentIteratorVoltaTensorOp &operator++() {
|
| 127 |
+
++index_;
|
| 128 |
+
return *this;
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
/// Decrements
|
| 132 |
+
CUTLASS_HOST_DEVICE
|
| 133 |
+
FragmentIteratorVoltaTensorOp &operator--() {
|
| 134 |
+
--index_;
|
| 135 |
+
return *this;
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
/// Loads a fragment from the referenced part of the accumulator tile
|
| 139 |
+
CUTLASS_HOST_DEVICE
|
| 140 |
+
void load(Fragment &frag, int index_offset = 0) const {
|
| 141 |
+
|
| 142 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 143 |
+
|
| 144 |
+
static int const kAccessesPerMma = Policy::kElementsPerMma / Policy::kElementsPerAccess;
|
| 145 |
+
|
| 146 |
+
CUTLASS_PRAGMA_UNROLL
|
| 147 |
+
for (int tile_n = 0; tile_n < Policy::TileIterations::kColumn; ++tile_n) {
|
| 148 |
+
|
| 149 |
+
int tile_access_idx =
|
| 150 |
+
(tile_n * Policy::TileIterations::kRow + (index_ & 2) / 2) * Policy::MmaIterations::kCount * kAccessesPerMma;
|
| 151 |
+
|
| 152 |
+
CUTLASS_PRAGMA_UNROLL
|
| 153 |
+
for (int mma_n = 0; mma_n < Policy::MmaIterations::kColumn * kAccessesPerMma; ++mma_n) {
|
| 154 |
+
|
| 155 |
+
int mma_access_idx = ((mma_n & 1) * 2 + (index_ & 1)) * kAccessesPerMma + (mma_n & 2) / 2;
|
| 156 |
+
|
| 157 |
+
frag_ptr[tile_n * Policy::MmaIterations::kColumn * kAccessesPerMma +
|
| 158 |
+
mma_n] = accumulators_[tile_access_idx + mma_access_idx];
|
| 159 |
+
}
|
| 160 |
+
}
|
| 161 |
+
}
|
| 162 |
+
};
|
| 163 |
+
|
| 164 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 165 |
+
|
| 166 |
+
/// Partial specialization for row-major shared memory
|
| 167 |
+
template <
|
| 168 |
+
typename WarpShape_ ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 169 |
+
>
|
| 170 |
+
class FragmentIteratorVoltaTensorOp<WarpShape_, gemm::GemmShape<32, 32, 4>, float, layout::RowMajor> {
|
| 171 |
+
public:
|
| 172 |
+
|
| 173 |
+
using WarpShape = WarpShape_;
|
| 174 |
+
using InterleavedTileShape = gemm::GemmShape<32, 32, 4>;
|
| 175 |
+
using ElementC = float;
|
| 176 |
+
using Layout = layout::RowMajor;
|
| 177 |
+
|
| 178 |
+
/// Policy operator
|
| 179 |
+
using Policy = VoltaTensorOpPolicy<WarpShape, InterleavedTileShape, ElementC, Layout>;
|
| 180 |
+
|
| 181 |
+
/// Array type for aligned memory accesses
|
| 182 |
+
using AccessType = typename Policy::AccessType;
|
| 183 |
+
|
| 184 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 185 |
+
using Fragment = typename Policy::Fragment;
|
| 186 |
+
|
| 187 |
+
/// This is the complete warp-level accumulator tile.
|
| 188 |
+
using AccumulatorTile = typename Policy::AccumulatorTile;
|
| 189 |
+
|
| 190 |
+
/// Number of times this iterator can be incremented
|
| 191 |
+
static int const kIterations = Policy::kIterations;
|
| 192 |
+
|
| 193 |
+
private:
|
| 194 |
+
|
| 195 |
+
private:
|
| 196 |
+
|
| 197 |
+
//
|
| 198 |
+
// Data members
|
| 199 |
+
//
|
| 200 |
+
|
| 201 |
+
/// Accumulator tile
|
| 202 |
+
AccessType const *accumulators_;
|
| 203 |
+
|
| 204 |
+
/// Internal index
|
| 205 |
+
int index_;
|
| 206 |
+
|
| 207 |
+
public:
|
| 208 |
+
|
| 209 |
+
/// Constructs an iterator
|
| 210 |
+
CUTLASS_HOST_DEVICE
|
| 211 |
+
FragmentIteratorVoltaTensorOp(AccumulatorTile const &accum):
|
| 212 |
+
accumulators_(reinterpret_cast<AccessType const *>(&accum)),
|
| 213 |
+
index_(0) {
|
| 214 |
+
}
|
| 215 |
+
|
| 216 |
+
/// Increments
|
| 217 |
+
CUTLASS_HOST_DEVICE
|
| 218 |
+
FragmentIteratorVoltaTensorOp &operator++() {
|
| 219 |
+
++index_;
|
| 220 |
+
return *this;
|
| 221 |
+
}
|
| 222 |
+
|
| 223 |
+
/// Decrements
|
| 224 |
+
CUTLASS_HOST_DEVICE
|
| 225 |
+
FragmentIteratorVoltaTensorOp &operator--() {
|
| 226 |
+
--index_;
|
| 227 |
+
return *this;
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
/// Loads a fragment from the referenced part of the accumulator tile
|
| 231 |
+
CUTLASS_HOST_DEVICE
|
| 232 |
+
void load(Fragment &frag, int index_offset = 0) const {
|
| 233 |
+
|
| 234 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 235 |
+
|
| 236 |
+
int const kRegsPerMmaRow = 2;
|
| 237 |
+
|
| 238 |
+
CUTLASS_PRAGMA_UNROLL
|
| 239 |
+
for (int reg_row = 0; reg_row < Policy::kRowsPerMmaTile; ++reg_row) {
|
| 240 |
+
|
| 241 |
+
CUTLASS_PRAGMA_UNROLL
|
| 242 |
+
for (int tile_n = 0; tile_n < Policy::TileIterations::kColumn; ++tile_n) {
|
| 243 |
+
|
| 244 |
+
CUTLASS_PRAGMA_UNROLL
|
| 245 |
+
for (int mma_n = 0; mma_n < Policy::MmaIterations::kColumn * 2; ++mma_n) {
|
| 246 |
+
|
| 247 |
+
int mma_idx = (index_ & 1) + (index_ & 2) * Policy::MmaIterations::kCount / 2 +
|
| 248 |
+
(tile_n * Policy::TileIterations::kRow) * Policy::MmaIterations::kCount + (mma_n & 1) * 2;
|
| 249 |
+
|
| 250 |
+
int reg_offset = reg_row * kRegsPerMmaRow + (mma_n & 2) * 2;
|
| 251 |
+
int reg_idx = mma_idx * Policy::kElementsPerMma + reg_offset;
|
| 252 |
+
|
| 253 |
+
*frag_ptr = accumulators_[reg_idx / Policy::kElementsPerAccess];
|
| 254 |
+
++frag_ptr;
|
| 255 |
+
}
|
| 256 |
+
}
|
| 257 |
+
}
|
| 258 |
+
}
|
| 259 |
+
};
|
| 260 |
+
|
| 261 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 262 |
+
|
| 263 |
+
|
| 264 |
+
} // namespace warp
|
| 265 |
+
} // namespace epilogue
|
| 266 |
+
} // namespace cutlass
|
| 267 |
+
|
| 268 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 269 |
+
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/fragment_iterator_wmma_tensor_op.h
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief This defines a "fragment" iterator for visiting the fragments of an accumulator tile
|
| 33 |
+
that participate in one warp-level store operation.
|
| 34 |
+
|
| 35 |
+
Typically, the accumulator tile is the largest single block of register-backed storage
|
| 36 |
+
within the kernel. Storing it to memory is best accomplished by partitioning it into
|
| 37 |
+
smaller tiles and storing these sequentially.
|
| 38 |
+
|
| 39 |
+
Round trips through shared memory during the Epilogue phase require partitioning, as
|
| 40 |
+
shared memory capacity is typically insufficient for a threadblock's total accumulator
|
| 41 |
+
size.
|
| 42 |
+
*/
|
| 43 |
+
|
| 44 |
+
#pragma once
|
| 45 |
+
|
| 46 |
+
#include "cutlass/wmma_array.h"
|
| 47 |
+
#include "cutlass/layout/matrix.h"
|
| 48 |
+
|
| 49 |
+
#include "cutlass/epilogue/warp/wmma_tensor_op_policy.h"
|
| 50 |
+
|
| 51 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 52 |
+
|
| 53 |
+
namespace cutlass {
|
| 54 |
+
namespace epilogue {
|
| 55 |
+
namespace warp {
|
| 56 |
+
|
| 57 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 58 |
+
|
| 59 |
+
///
|
| 60 |
+
template <
|
| 61 |
+
typename WarpShape, ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 62 |
+
typename OperatorShape, ///< matrix multiply operation shape (concept: gemm::GemmShape)
|
| 63 |
+
typename OperatorElementC, ///< matrix multiply operation data type (concept: data type)
|
| 64 |
+
typename OperatorFragmentC, ///< matrix multiply operation fragment (concept: nvcuda::cuda::fragment)
|
| 65 |
+
typename Layout ///< target shared memory layout
|
| 66 |
+
>
|
| 67 |
+
class FragmentIteratorWmmaTensorOp;
|
| 68 |
+
|
| 69 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 70 |
+
|
| 71 |
+
/// Partial specialization for row-major shared memory
|
| 72 |
+
template <
|
| 73 |
+
typename WarpShape_, ///< shape of the warp-level GEMM tile
|
| 74 |
+
typename OperatorShape_, ///< matrix multiply operation shape (concept: gemm::GemmShape)
|
| 75 |
+
typename OperatorElementC_, ///< matrix multiply operation data type (concept: data type)
|
| 76 |
+
typename OperatorFragmentC_ ///< matrix multiply operation fragment (concept: nvcuda::cuda::fragment)
|
| 77 |
+
>
|
| 78 |
+
class FragmentIteratorWmmaTensorOp<WarpShape_, OperatorShape_, OperatorElementC_, OperatorFragmentC_, layout::RowMajor> {
|
| 79 |
+
public:
|
| 80 |
+
|
| 81 |
+
using WarpShape = WarpShape_;
|
| 82 |
+
using OperatorShape = OperatorShape_;
|
| 83 |
+
using OperatorElementC = OperatorElementC_;
|
| 84 |
+
using OperatorFragmentC = OperatorFragmentC_;
|
| 85 |
+
using Layout = layout::RowMajor;
|
| 86 |
+
|
| 87 |
+
using Policy = WmmaTensorOpPolicy<WarpShape, OperatorShape, Layout>;
|
| 88 |
+
|
| 89 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 90 |
+
using Fragment = WmmaFragmentArray<OperatorFragmentC, Policy::OperatorCount::kColumn>;
|
| 91 |
+
|
| 92 |
+
/// This is the complete warp-level accumulator tile.
|
| 93 |
+
using AccumulatorTile = WmmaFragmentArray<OperatorFragmentC, Policy::OperatorCount::kCount>;
|
| 94 |
+
|
| 95 |
+
using OutputAccumulatorTile = AccumulatorTile;
|
| 96 |
+
|
| 97 |
+
private:
|
| 98 |
+
|
| 99 |
+
/// Internal access type
|
| 100 |
+
using AccessType = WmmaFragmentArray<OperatorFragmentC, Policy::kWmmaFragmentsPerAccess>;
|
| 101 |
+
|
| 102 |
+
private:
|
| 103 |
+
|
| 104 |
+
//
|
| 105 |
+
// Data members
|
| 106 |
+
//
|
| 107 |
+
|
| 108 |
+
/// Accumulator tile
|
| 109 |
+
AccessType const *accumulators_;
|
| 110 |
+
|
| 111 |
+
/// Internal index
|
| 112 |
+
int index_;
|
| 113 |
+
|
| 114 |
+
public:
|
| 115 |
+
|
| 116 |
+
/// Constructs an iterator
|
| 117 |
+
CUTLASS_HOST_DEVICE
|
| 118 |
+
FragmentIteratorWmmaTensorOp(AccumulatorTile const &accum):
|
| 119 |
+
accumulators_(reinterpret_cast<AccessType const *>(&accum)),
|
| 120 |
+
index_(0) {
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
/// Increments
|
| 124 |
+
CUTLASS_HOST_DEVICE
|
| 125 |
+
FragmentIteratorWmmaTensorOp &operator++() {
|
| 126 |
+
++index_;
|
| 127 |
+
return *this;
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
/// Decrements
|
| 131 |
+
CUTLASS_HOST_DEVICE
|
| 132 |
+
FragmentIteratorWmmaTensorOp &operator--() {
|
| 133 |
+
--index_;
|
| 134 |
+
return *this;
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
/// Loads a fragment from the referenced part of the accumulator tile
|
| 138 |
+
CUTLASS_HOST_DEVICE
|
| 139 |
+
void load(Fragment &frag, int index_offset = 0) const {
|
| 140 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 141 |
+
|
| 142 |
+
CUTLASS_PRAGMA_UNROLL
|
| 143 |
+
for(int n=0; n < Policy::OperatorCount::kColumn; n++) {
|
| 144 |
+
|
| 145 |
+
int accumulator_access_offset = index_ * Policy::OperatorCount::kColumn + n;
|
| 146 |
+
|
| 147 |
+
frag_ptr[n] = accumulators_[accumulator_access_offset];
|
| 148 |
+
}
|
| 149 |
+
}
|
| 150 |
+
};
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
} // namespace warp
|
| 154 |
+
} // namespace epilogue
|
| 155 |
+
} // namespace cutlass
|
| 156 |
+
|
| 157 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 158 |
+
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/simt_policy.h
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief Defines basic structures needed for implementing the warp-scoped phase of the epilogue.
|
| 33 |
+
These quantities assume a 'column-major' arrangement of SimtOp instructions, of which
|
| 34 |
+
a row-oriented slice is visible per iteration.
|
| 35 |
+
*/
|
| 36 |
+
|
| 37 |
+
#pragma once
|
| 38 |
+
|
| 39 |
+
#include "cutlass/matrix_shape.h"
|
| 40 |
+
#include "cutlass/layout/matrix.h"
|
| 41 |
+
|
| 42 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 43 |
+
|
| 44 |
+
namespace cutlass {
|
| 45 |
+
namespace epilogue {
|
| 46 |
+
namespace warp {
|
| 47 |
+
|
| 48 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 49 |
+
|
| 50 |
+
template <
|
| 51 |
+
typename WarpShape, ///< shape of warp-level GEMM (concept: GemmShape)
|
| 52 |
+
typename Operator, ///< matrix multiply operation (concept: arch::Mma)
|
| 53 |
+
typename Layout, ///< destination layout in shared memory
|
| 54 |
+
typename MmaSimtPolicy ///< policy defining lane arrangement (concept: MmaSimtPolicy)
|
| 55 |
+
>
|
| 56 |
+
struct SimtPolicy;
|
| 57 |
+
|
| 58 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 59 |
+
|
| 60 |
+
/// Partial specialization for row-major
|
| 61 |
+
template <
|
| 62 |
+
typename WarpShape_, ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 63 |
+
typename Operator_, ///< matrix multiply operation (concept: arch::Mma)
|
| 64 |
+
typename MmaSimtPolicy_ ///< policy defining lane arrangement (concept: MmaSimtPolicy)
|
| 65 |
+
>
|
| 66 |
+
struct SimtPolicy<WarpShape_, Operator_, layout::RowMajor, MmaSimtPolicy_> {
|
| 67 |
+
|
| 68 |
+
using WarpShape = WarpShape_;
|
| 69 |
+
using Operator = Operator_;
|
| 70 |
+
using MmaSimtPolicy = MmaSimtPolicy_;
|
| 71 |
+
|
| 72 |
+
static_assert(!(WarpShape::kM % MmaSimtPolicy::WarpShape::kRow), "Divisibility");
|
| 73 |
+
static_assert(!(WarpShape::kN % MmaSimtPolicy::WarpShape::kColumn), "Divisibility");
|
| 74 |
+
|
| 75 |
+
/// Number of iterations
|
| 76 |
+
static int const kIterations = WarpShape::kM / MmaSimtPolicy::WarpShape::kRow;
|
| 77 |
+
|
| 78 |
+
/// Number of accumulators written per iteration
|
| 79 |
+
static int const kElementsPerIteration =
|
| 80 |
+
(WarpShape::kN / MmaSimtPolicy::WarpShape::kColumn);
|
| 81 |
+
|
| 82 |
+
/// Total number of accumulators
|
| 83 |
+
static int const kAccumulatorElementCount = kElementsPerIteration * kIterations;
|
| 84 |
+
|
| 85 |
+
/// Number of consecutive elements
|
| 86 |
+
static int const kElementsPerAccess = MmaSimtPolicy::LaneMmaShape::kN;
|
| 87 |
+
|
| 88 |
+
/// Number of rows per epilogue iteration
|
| 89 |
+
static int const kRowsPerIteration = MmaSimtPolicy::WarpShape::kRow;
|
| 90 |
+
|
| 91 |
+
/// Number of accesses made in one iteration
|
| 92 |
+
static int const kAccessesPerIteration = kElementsPerIteration / kElementsPerAccess;
|
| 93 |
+
|
| 94 |
+
/// Number of elements in between accumulator chunks of (LaneMmaShape::kM x LaneMmaShape::kN)
|
| 95 |
+
using Delta = MatrixShape<
|
| 96 |
+
MmaSimtPolicy::WarpShape::kRow * MmaSimtPolicy::LaneMmaShape::kM,
|
| 97 |
+
MmaSimtPolicy::WarpShape::kColumn * MmaSimtPolicy::LaneMmaShape::kN
|
| 98 |
+
>;
|
| 99 |
+
};
|
| 100 |
+
|
| 101 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 102 |
+
|
| 103 |
+
} // namespace warp
|
| 104 |
+
} // namespace epilogue
|
| 105 |
+
} // namespace cutlass
|
| 106 |
+
|
| 107 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/tensor_op_policy.h
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief Defines basic structures needed for implementing the warp-scoped phase of the epilogue.
|
| 33 |
+
These quantities assume a 'column-major' arrangement of TensorOp instructions, of which
|
| 34 |
+
a row-oriented slice is visible per iteration.
|
| 35 |
+
*/
|
| 36 |
+
|
| 37 |
+
#pragma once
|
| 38 |
+
|
| 39 |
+
#include "cutlass/matrix_shape.h"
|
| 40 |
+
#include "cutlass/layout/matrix.h"
|
| 41 |
+
|
| 42 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 43 |
+
|
| 44 |
+
namespace cutlass {
|
| 45 |
+
namespace epilogue {
|
| 46 |
+
namespace warp {
|
| 47 |
+
|
| 48 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 49 |
+
|
| 50 |
+
/// Policy details related to the epilogue
|
| 51 |
+
template <
|
| 52 |
+
typename WarpShape, ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 53 |
+
typename OperatorShape, ///< matrix multiply operation shape (concept: gemm:GemmShape)
|
| 54 |
+
typename Layout ///< target shared memory layout
|
| 55 |
+
>
|
| 56 |
+
struct TensorOpPolicy;
|
| 57 |
+
|
| 58 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 59 |
+
|
| 60 |
+
/// Partial specialization for row-major
|
| 61 |
+
template <
|
| 62 |
+
typename WarpShape, ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 63 |
+
typename OperatorShape ///< matrix multiply operation shape (concept: gemm::GemmShape)
|
| 64 |
+
>
|
| 65 |
+
struct TensorOpPolicy<WarpShape, OperatorShape, layout::RowMajor> {
|
| 66 |
+
|
| 67 |
+
/// Number of operations
|
| 68 |
+
using OperatorCount = MatrixShape<
|
| 69 |
+
(WarpShape::kM + OperatorShape::kM - 1) / OperatorShape::kM,
|
| 70 |
+
(WarpShape::kN + OperatorShape::kN - 1) / OperatorShape::kN
|
| 71 |
+
>;
|
| 72 |
+
|
| 73 |
+
//
|
| 74 |
+
// Hard-coded constants regarding Tensor Operations
|
| 75 |
+
//
|
| 76 |
+
|
| 77 |
+
static int const kElementsPerAccess = 2;
|
| 78 |
+
static int const kRowsPerIteration = 8;
|
| 79 |
+
static bool const kDivisible =
|
| 80 |
+
!(WarpShape::kM % OperatorShape::kM) && !(WarpShape::kN % OperatorShape::kN);
|
| 81 |
+
|
| 82 |
+
//
|
| 83 |
+
// Derived quantities
|
| 84 |
+
//
|
| 85 |
+
|
| 86 |
+
// Number of 'externally visible' iterations per actual instruction
|
| 87 |
+
static int const kIterationsPerInstruction = OperatorShape::kM / kRowsPerIteration;
|
| 88 |
+
|
| 89 |
+
// Number of externally visible iterations
|
| 90 |
+
static int const kIterations = OperatorCount::kRow * kIterationsPerInstruction;
|
| 91 |
+
|
| 92 |
+
using TileIterations = MatrixShape<kIterations, 1>;
|
| 93 |
+
|
| 94 |
+
static int const kAccumulatorRowStride = kElementsPerAccess;
|
| 95 |
+
static int const kAccumulatorColumnStride = kElementsPerAccess * OperatorCount::kRow * kIterationsPerInstruction;
|
| 96 |
+
|
| 97 |
+
};
|
| 98 |
+
|
| 99 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 100 |
+
|
| 101 |
+
/// Partial specialization for row-major
|
| 102 |
+
template <
|
| 103 |
+
typename WarpShape, ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 104 |
+
typename OperatorShape ///< matrix multiply operation shape (concept: gemm::GemmShape)
|
| 105 |
+
>
|
| 106 |
+
struct TensorOpPolicy<WarpShape, OperatorShape, layout::ColumnMajor> {
|
| 107 |
+
|
| 108 |
+
/// Number of operations
|
| 109 |
+
using OperatorCount = MatrixShape<
|
| 110 |
+
(WarpShape::kM + OperatorShape::kM - 1) / OperatorShape::kM,
|
| 111 |
+
(WarpShape::kN + OperatorShape::kN - 1) / OperatorShape::kN
|
| 112 |
+
>;
|
| 113 |
+
|
| 114 |
+
//
|
| 115 |
+
// Hard-coded constants regarding Tensor Operations
|
| 116 |
+
//
|
| 117 |
+
|
| 118 |
+
static int const kElementsPerAccess = 1;
|
| 119 |
+
static int const kColumnsPerIteration = 8;
|
| 120 |
+
static bool const kDivisible =
|
| 121 |
+
!(WarpShape::kM % OperatorShape::kM) && !(WarpShape::kN % OperatorShape::kN);
|
| 122 |
+
|
| 123 |
+
//
|
| 124 |
+
// Derived quantities
|
| 125 |
+
//
|
| 126 |
+
|
| 127 |
+
// Number of 'externally visible' iterations per actual instruction
|
| 128 |
+
static int const kIterationsPerInstruction = OperatorShape::kN / kColumnsPerIteration;
|
| 129 |
+
|
| 130 |
+
// Number of externally visible iterations
|
| 131 |
+
static int const kIterations = OperatorCount::kColumn * kIterationsPerInstruction;
|
| 132 |
+
|
| 133 |
+
using TileIterations = MatrixShape<kIterations, 1>;
|
| 134 |
+
|
| 135 |
+
// Hard code for 16x8
|
| 136 |
+
static int const kAccumulatorRowStride = 2;
|
| 137 |
+
static int const kAccumulatorColumnStride = 4 * OperatorCount::kRow;
|
| 138 |
+
};
|
| 139 |
+
|
| 140 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 141 |
+
|
| 142 |
+
/// Partial specialization for column-major-interleaved
|
| 143 |
+
template <
|
| 144 |
+
typename WarpShape, ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 145 |
+
typename OperatorShape, ///< matrix multiply operation (concept: arch::Mma)
|
| 146 |
+
int InterleavedK ///< number of interleaved k
|
| 147 |
+
>
|
| 148 |
+
struct TensorOpPolicy<WarpShape, OperatorShape,
|
| 149 |
+
layout::ColumnMajorInterleaved<InterleavedK> > {
|
| 150 |
+
/// Number of operations
|
| 151 |
+
using OperatorCount = MatrixShape<WarpShape::kM / OperatorShape::kM,
|
| 152 |
+
WarpShape::kN / OperatorShape::kN>;
|
| 153 |
+
|
| 154 |
+
//
|
| 155 |
+
// Hard-coded constants regarding Tensor Operations
|
| 156 |
+
//
|
| 157 |
+
|
| 158 |
+
static int const kElementsPerAccess = 2;
|
| 159 |
+
static int const kRowsPerIteration = 8;
|
| 160 |
+
|
| 161 |
+
//
|
| 162 |
+
// Derived quantities
|
| 163 |
+
//
|
| 164 |
+
|
| 165 |
+
// Number of 'externally visible' iterations per actual instruction
|
| 166 |
+
static int const kIterationsPerInstruction =
|
| 167 |
+
OperatorShape::kM / kRowsPerIteration;
|
| 168 |
+
|
| 169 |
+
// Number of externally visible iterations
|
| 170 |
+
static int const kIterations = WarpShape::kN / InterleavedK *
|
| 171 |
+
OperatorCount::kRow *
|
| 172 |
+
kIterationsPerInstruction;
|
| 173 |
+
|
| 174 |
+
static int const kElementsPerIteration = InterleavedK / OperatorShape::kN * kElementsPerAccess;
|
| 175 |
+
|
| 176 |
+
static int const kAccessPerIteration = kElementsPerIteration / kElementsPerAccess;
|
| 177 |
+
|
| 178 |
+
// Number of externally visible iterations
|
| 179 |
+
//static int const kTileIterations = OperatorCount::kRow * kIterationsPerInstruction;
|
| 180 |
+
using TileIterations = MatrixShape<1, WarpShape::kN / InterleavedK>;
|
| 181 |
+
};
|
| 182 |
+
|
| 183 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 184 |
+
|
| 185 |
+
} // namespace warp
|
| 186 |
+
} // namespace epilogue
|
| 187 |
+
} // namespace cutlass
|
| 188 |
+
|
| 189 |
+
////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/tile_iterator_simt.h
ADDED
|
@@ -0,0 +1,785 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief
|
| 33 |
+
*/
|
| 34 |
+
|
| 35 |
+
#pragma once
|
| 36 |
+
|
| 37 |
+
#include "cutlass/array.h"
|
| 38 |
+
#include "cutlass/layout/matrix.h"
|
| 39 |
+
#include "cutlass/layout/pitch_linear.h"
|
| 40 |
+
|
| 41 |
+
#include "cutlass/epilogue/warp/simt_policy.h"
|
| 42 |
+
|
| 43 |
+
#define CUTLASS_SIMT_EPILOGUE_USE_SCALAR_STORES 1
|
| 44 |
+
|
| 45 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 46 |
+
|
| 47 |
+
namespace cutlass {
|
| 48 |
+
namespace epilogue {
|
| 49 |
+
namespace warp {
|
| 50 |
+
|
| 51 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 52 |
+
|
| 53 |
+
/// Template for reading and writing tiles of accumulators to shared memory
|
| 54 |
+
template <
|
| 55 |
+
typename WarpShape, ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 56 |
+
typename Operator, ///< matrix multiply operation (concept: arch::Mma)
|
| 57 |
+
typename Element, ///< data type of element to be written
|
| 58 |
+
typename Layout, ///< target shared memory layout
|
| 59 |
+
typename MmaSimtPolicy ///< policy defining lane arrangement (concept: MmaSimtPolicy)
|
| 60 |
+
>
|
| 61 |
+
class TileIteratorSimt;
|
| 62 |
+
|
| 63 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 64 |
+
|
| 65 |
+
/// Template for reading and writing tiles of accumulators to shared memory
|
| 66 |
+
template <
|
| 67 |
+
typename WarpShape_, ///< shape of warp-level GEMM (concept: GemmShape)
|
| 68 |
+
typename Operator_, ///< matrix multiply operation (concept: arch::Mma)
|
| 69 |
+
typename Element_, ///< data type of element to be written
|
| 70 |
+
typename MmaSimtPolicy_ ///< policy defining lane arrangement (concept: MmaSimtPolicy)
|
| 71 |
+
>
|
| 72 |
+
class TileIteratorSimt<WarpShape_, Operator_, Element_, layout::RowMajor, MmaSimtPolicy_> {
|
| 73 |
+
public:
|
| 74 |
+
|
| 75 |
+
using WarpShape = WarpShape_;
|
| 76 |
+
using Operator = Operator_;
|
| 77 |
+
using Element = Element_;
|
| 78 |
+
using Layout = layout::RowMajor;
|
| 79 |
+
|
| 80 |
+
using TensorRef = TensorRef<Element, Layout>; ///< Tensor Reference object
|
| 81 |
+
using TensorCoord = MatrixCoord; ///< Logical coordinate in referenced tensor
|
| 82 |
+
using Index = typename TensorRef::Index;
|
| 83 |
+
using LongIndex = typename TensorRef::LongIndex;
|
| 84 |
+
|
| 85 |
+
using Policy = SimtPolicy<WarpShape, Operator, Layout, MmaSimtPolicy_>;
|
| 86 |
+
|
| 87 |
+
/// Shape of the tile in memory
|
| 88 |
+
using Shape = MatrixShape<
|
| 89 |
+
Policy::kRowsPerIteration,
|
| 90 |
+
WarpShape::kN
|
| 91 |
+
>;
|
| 92 |
+
|
| 93 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 94 |
+
using Fragment = Array<
|
| 95 |
+
typename Operator::ElementC,
|
| 96 |
+
Policy::kElementsPerIteration>;
|
| 97 |
+
|
| 98 |
+
/// This is the complete warp-level accumulator tile.
|
| 99 |
+
using AccumulatorTile = Array<
|
| 100 |
+
typename Operator::ElementC,
|
| 101 |
+
Policy::kAccumulatorElementCount>;
|
| 102 |
+
|
| 103 |
+
/// Number of times this iterator can be incremented
|
| 104 |
+
static int const kIterations = Policy::kIterations;
|
| 105 |
+
|
| 106 |
+
/// Padding quantity
|
| 107 |
+
using Padding = MatrixShape<
|
| 108 |
+
0,
|
| 109 |
+
4 * Policy::kElementsPerAccess
|
| 110 |
+
#if CUTLASS_SIMT_EPILOGUE_USE_SCALAR_STORES
|
| 111 |
+
+ 1
|
| 112 |
+
#endif
|
| 113 |
+
>;
|
| 114 |
+
|
| 115 |
+
private:
|
| 116 |
+
|
| 117 |
+
#if CUTLASS_SIMT_EPILOGUE_USE_SCALAR_STORES
|
| 118 |
+
/// Storage type for accessing memory
|
| 119 |
+
using AccessType = AlignedArray<
|
| 120 |
+
Element,
|
| 121 |
+
1
|
| 122 |
+
>;
|
| 123 |
+
|
| 124 |
+
#else
|
| 125 |
+
/// Storage type for accessing memory
|
| 126 |
+
using AccessType = AlignedArray<
|
| 127 |
+
Element,
|
| 128 |
+
Policy::kElementsPerAccess
|
| 129 |
+
>;
|
| 130 |
+
#endif
|
| 131 |
+
|
| 132 |
+
//
|
| 133 |
+
// Data members
|
| 134 |
+
//
|
| 135 |
+
|
| 136 |
+
/// Internal pointer to memory
|
| 137 |
+
AccessType *pointer_;
|
| 138 |
+
|
| 139 |
+
/// Internal layout object
|
| 140 |
+
Layout layout_;
|
| 141 |
+
|
| 142 |
+
public:
|
| 143 |
+
|
| 144 |
+
/// Default constructor
|
| 145 |
+
CUTLASS_HOST_DEVICE
|
| 146 |
+
TileIteratorSimt(): pointer_(nullptr) { }
|
| 147 |
+
|
| 148 |
+
/// Constructor from TensorRef
|
| 149 |
+
CUTLASS_HOST_DEVICE
|
| 150 |
+
TileIteratorSimt(
|
| 151 |
+
TensorRef const &ref,
|
| 152 |
+
unsigned lane_id
|
| 153 |
+
):
|
| 154 |
+
pointer_(reinterpret_cast<AccessType *>(ref.data())),
|
| 155 |
+
layout_(ref.stride()[0] / AccessType::kElements) {
|
| 156 |
+
|
| 157 |
+
auto lane_layout = Policy::MmaSimtPolicy::get_lane_layout();
|
| 158 |
+
MatrixCoord lane_offset = lane_layout.inverse(lane_id);
|
| 159 |
+
|
| 160 |
+
pointer_ += layout_({
|
| 161 |
+
lane_offset.row(),
|
| 162 |
+
lane_offset.column() * Policy::kElementsPerAccess / int(AccessType::kElements)
|
| 163 |
+
});
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
/// Adds a pointer offset
|
| 167 |
+
CUTLASS_HOST_DEVICE
|
| 168 |
+
TileIteratorSimt & add_pointer_offset(Index pointer_offset) {
|
| 169 |
+
pointer_ += pointer_offset / AccessType::kElements;
|
| 170 |
+
return *this;
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 174 |
+
CUTLASS_HOST_DEVICE
|
| 175 |
+
TileIteratorSimt & add_tile_offset(TensorCoord const &tile_offset) {
|
| 176 |
+
|
| 177 |
+
pointer_ += layout_({
|
| 178 |
+
tile_offset.row() * Shape::kRow,
|
| 179 |
+
(tile_offset.column() * Shape::kColumn / int(AccessType::kElements))
|
| 180 |
+
});
|
| 181 |
+
|
| 182 |
+
return *this;
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 186 |
+
CUTLASS_HOST_DEVICE
|
| 187 |
+
TileIteratorSimt & operator+=(TensorCoord const &tile_offset) {
|
| 188 |
+
|
| 189 |
+
add_tile_offset(tile_offset);
|
| 190 |
+
|
| 191 |
+
return *this;
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
/// Store
|
| 195 |
+
CUTLASS_HOST_DEVICE
|
| 196 |
+
void store_with_pointer_offset(Fragment const &frag, Index pointer_offset) {
|
| 197 |
+
#if CUTLASS_SIMT_EPILOGUE_USE_SCALAR_STORES
|
| 198 |
+
// de-vectorized stores
|
| 199 |
+
using ScalarAccessType = AlignedArray<Element, 1>;
|
| 200 |
+
ScalarAccessType const *scalarFragPtr = reinterpret_cast<ScalarAccessType const *>(&frag);
|
| 201 |
+
ScalarAccessType *scalarPointer = reinterpret_cast<ScalarAccessType *>(pointer_) + pointer_offset;
|
| 202 |
+
|
| 203 |
+
CUTLASS_PRAGMA_UNROLL
|
| 204 |
+
for (int n = 0; n < Policy::kAccessesPerIteration; ++n) {
|
| 205 |
+
CUTLASS_PRAGMA_UNROLL
|
| 206 |
+
for (int s = 0; s < Policy::kElementsPerAccess; s++) {
|
| 207 |
+
scalarPointer[n * Policy::MmaSimtPolicy::WarpShape::kColumn * Policy::kElementsPerAccess + s] = scalarFragPtr[n * Policy::kElementsPerAccess + s];
|
| 208 |
+
}
|
| 209 |
+
}
|
| 210 |
+
#else
|
| 211 |
+
// original vector stores
|
| 212 |
+
AccessType const *frag_ptr = reinterpret_cast<AccessType const *>(&frag);
|
| 213 |
+
CUTLASS_PRAGMA_UNROLL
|
| 214 |
+
for (int n = 0; n < Policy::kAccessesPerIteration; ++n) {
|
| 215 |
+
pointer_[n * Policy::MmaSimtPolicy::WarpShape::kColumn + pointer_offset / int(AccessType::kElements)] = frag_ptr[n];
|
| 216 |
+
}
|
| 217 |
+
#endif
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
/// Store
|
| 221 |
+
CUTLASS_HOST_DEVICE
|
| 222 |
+
void store(Fragment const &frag) {
|
| 223 |
+
store_with_pointer_offset(frag, 0);
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
/// Load
|
| 227 |
+
CUTLASS_HOST_DEVICE
|
| 228 |
+
void load_with_pointer_offset(Fragment &frag, Index pointer_offset) const {
|
| 229 |
+
|
| 230 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 231 |
+
|
| 232 |
+
CUTLASS_PRAGMA_UNROLL
|
| 233 |
+
for (int n = 0; n < Policy::kAccessesPerIteration; ++n) {
|
| 234 |
+
frag_ptr[n] = pointer_[n * Policy::MmaSimtPolicy::WarpShape::kColumn + pointer_offset / int(AccessType::kElements)];
|
| 235 |
+
}
|
| 236 |
+
}
|
| 237 |
+
|
| 238 |
+
/// Load
|
| 239 |
+
CUTLASS_HOST_DEVICE
|
| 240 |
+
void load(Fragment &frag) const {
|
| 241 |
+
load_with_pointer_offset(frag, 0);
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
/// Set smem base address
|
| 245 |
+
CUTLASS_HOST_DEVICE
|
| 246 |
+
void set_smem_base_address(Index address) {
|
| 247 |
+
}
|
| 248 |
+
};
|
| 249 |
+
|
| 250 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 251 |
+
|
| 252 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 253 |
+
|
| 254 |
+
/// Template for reading and writing tiles of accumulators to shared memory
|
| 255 |
+
template <typename WarpShape_, ///< shape of warp-level GEMM (concept: GemmShape)
|
| 256 |
+
typename Operator_, ///< matrix multiply operation (concept: arch::Mma)
|
| 257 |
+
typename Element_, ///< data type of element to be written
|
| 258 |
+
typename Layout_, ///< target shared memory layout
|
| 259 |
+
typename MmaSimtPolicy_ ///< policy defining lane arrangement (concept: MmaSimtPolicy)
|
| 260 |
+
>
|
| 261 |
+
class TileIteratorSimtDirectConv {
|
| 262 |
+
public:
|
| 263 |
+
|
| 264 |
+
using WarpShape = WarpShape_;
|
| 265 |
+
using Operator = Operator_;
|
| 266 |
+
using Element = Element_;
|
| 267 |
+
using Layout = layout::RowMajor;
|
| 268 |
+
|
| 269 |
+
using TensorRef = TensorRef<Element, Layout>; ///< Tensor Reference object
|
| 270 |
+
using TensorCoord = MatrixCoord; ///< Logical coordinate in referenced tensor
|
| 271 |
+
using Index = typename TensorRef::Index;
|
| 272 |
+
using LongIndex = typename TensorRef::LongIndex;
|
| 273 |
+
|
| 274 |
+
using Policy = SimtPolicy<WarpShape, Operator, Layout, MmaSimtPolicy_>;
|
| 275 |
+
|
| 276 |
+
/// Shape of the tile in memory
|
| 277 |
+
using Shape = MatrixShape<Policy::kRowsPerIteration, WarpShape::kN>;
|
| 278 |
+
|
| 279 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 280 |
+
using Fragment = Array<typename Operator::ElementC, Policy::kElementsPerIteration>;
|
| 281 |
+
|
| 282 |
+
/// This is the complete warp-level accumulator tile.
|
| 283 |
+
using AccumulatorTile = Array<typename Operator::ElementC, Policy::kAccumulatorElementCount>;
|
| 284 |
+
|
| 285 |
+
/// Number of times this iterator can be incremented
|
| 286 |
+
static int const kIterations = Policy::kIterations;
|
| 287 |
+
|
| 288 |
+
/// Padding quantity
|
| 289 |
+
using Padding = MatrixShape<0,
|
| 290 |
+
0
|
| 291 |
+
>;
|
| 292 |
+
|
| 293 |
+
private:
|
| 294 |
+
/// Storage type for accessing memory
|
| 295 |
+
using AccessType = AlignedArray<
|
| 296 |
+
Element,
|
| 297 |
+
Policy::kElementsPerAccess
|
| 298 |
+
>;
|
| 299 |
+
|
| 300 |
+
//
|
| 301 |
+
// Data members
|
| 302 |
+
//
|
| 303 |
+
|
| 304 |
+
/// Internal pointer to memory
|
| 305 |
+
AccessType *pointer_;
|
| 306 |
+
|
| 307 |
+
/// Internal layout object
|
| 308 |
+
Layout layout_;
|
| 309 |
+
|
| 310 |
+
/// Base smem offset;
|
| 311 |
+
Index base_smem_address_;
|
| 312 |
+
|
| 313 |
+
public:
|
| 314 |
+
/// Default constructor
|
| 315 |
+
CUTLASS_HOST_DEVICE
|
| 316 |
+
TileIteratorSimtDirectConv() : pointer_(nullptr) {}
|
| 317 |
+
|
| 318 |
+
/// Constructor from TensorRef
|
| 319 |
+
CUTLASS_HOST_DEVICE
|
| 320 |
+
TileIteratorSimtDirectConv(
|
| 321 |
+
TensorRef const &ref,
|
| 322 |
+
unsigned lane_id
|
| 323 |
+
):
|
| 324 |
+
pointer_(reinterpret_cast<AccessType *>(ref.data())),
|
| 325 |
+
layout_(ref.stride()[0] / AccessType::kElements) {
|
| 326 |
+
|
| 327 |
+
auto lane_layout = Policy::MmaSimtPolicy::get_lane_layout();
|
| 328 |
+
MatrixCoord lane_offset = lane_layout.inverse(lane_id);
|
| 329 |
+
|
| 330 |
+
pointer_ += layout_({
|
| 331 |
+
lane_offset.row(),
|
| 332 |
+
lane_offset.column() * Policy::kElementsPerAccess / int(AccessType::kElements)
|
| 333 |
+
});
|
| 334 |
+
}
|
| 335 |
+
|
| 336 |
+
/// Adds a pointer offset
|
| 337 |
+
CUTLASS_HOST_DEVICE
|
| 338 |
+
TileIteratorSimtDirectConv & add_pointer_offset(Index pointer_offset) {
|
| 339 |
+
pointer_ += pointer_offset / AccessType::kElements;
|
| 340 |
+
return *this;
|
| 341 |
+
}
|
| 342 |
+
|
| 343 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 344 |
+
CUTLASS_HOST_DEVICE
|
| 345 |
+
TileIteratorSimtDirectConv & add_tile_offset(TensorCoord const &tile_offset) {
|
| 346 |
+
|
| 347 |
+
pointer_ += layout_({
|
| 348 |
+
tile_offset.row() * Shape::kRow,
|
| 349 |
+
(tile_offset.column() * Shape::kColumn / int(AccessType::kElements))
|
| 350 |
+
});
|
| 351 |
+
|
| 352 |
+
return *this;
|
| 353 |
+
}
|
| 354 |
+
|
| 355 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 356 |
+
CUTLASS_HOST_DEVICE
|
| 357 |
+
TileIteratorSimtDirectConv & operator+=(TensorCoord const &tile_offset) {
|
| 358 |
+
|
| 359 |
+
add_tile_offset(tile_offset);
|
| 360 |
+
|
| 361 |
+
return *this;
|
| 362 |
+
}
|
| 363 |
+
|
| 364 |
+
/// Store
|
| 365 |
+
CUTLASS_HOST_DEVICE
|
| 366 |
+
void store_with_pointer_offset(Fragment const &frag, Index pointer_offset) {
|
| 367 |
+
|
| 368 |
+
// original vector stores
|
| 369 |
+
AccessType const *frag_ptr = reinterpret_cast<AccessType const *>(&frag);
|
| 370 |
+
AccessType * load_pointer_ = reinterpret_cast<AccessType *>(reinterpret_cast<uint8_t *>(pointer_) + base_smem_address_);
|
| 371 |
+
CUTLASS_PRAGMA_UNROLL
|
| 372 |
+
for (int n = 0; n < Policy::kAccessesPerIteration; ++n) {
|
| 373 |
+
load_pointer_[n * Policy::MmaSimtPolicy::WarpShape::kColumn + pointer_offset / int(AccessType::kElements)] = frag_ptr[n];
|
| 374 |
+
}
|
| 375 |
+
}
|
| 376 |
+
|
| 377 |
+
/// Store
|
| 378 |
+
CUTLASS_HOST_DEVICE
|
| 379 |
+
void store(Fragment const &frag) {
|
| 380 |
+
store_with_pointer_offset(frag, 0);
|
| 381 |
+
}
|
| 382 |
+
|
| 383 |
+
/// Load
|
| 384 |
+
CUTLASS_HOST_DEVICE
|
| 385 |
+
void load_with_pointer_offset(Fragment &frag, Index pointer_offset) const {
|
| 386 |
+
|
| 387 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 388 |
+
|
| 389 |
+
CUTLASS_PRAGMA_UNROLL
|
| 390 |
+
for (int n = 0; n < Policy::kAccessesPerIteration; ++n) {
|
| 391 |
+
frag_ptr[n] = pointer_[n * Policy::MmaSimtPolicy::WarpShape::kColumn + pointer_offset / int(AccessType::kElements)];
|
| 392 |
+
}
|
| 393 |
+
}
|
| 394 |
+
|
| 395 |
+
/// Load
|
| 396 |
+
CUTLASS_HOST_DEVICE
|
| 397 |
+
void load(Fragment &frag) const {
|
| 398 |
+
load_with_pointer_offset(frag, 0);
|
| 399 |
+
}
|
| 400 |
+
|
| 401 |
+
/// Set smem base address
|
| 402 |
+
CUTLASS_HOST_DEVICE
|
| 403 |
+
void set_smem_base_address(Index address){
|
| 404 |
+
base_smem_address_ = address;
|
| 405 |
+
}
|
| 406 |
+
|
| 407 |
+
};
|
| 408 |
+
|
| 409 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 410 |
+
/// Template for reading and writing tiles of accumulators to shared memory
|
| 411 |
+
template <typename WarpShape_, ///< shape of warp-level GEMM (concept: GemmShape)
|
| 412 |
+
typename ThreadOutputShape_, /// Size of the matrix to load (concept: TensorNHWC)
|
| 413 |
+
typename ThreadBlockOutputShape_, /// Size of the matrix to load (concept: TensorNHWC)
|
| 414 |
+
typename Operator_, ///< matrix multi ply operation (concept: arch::Mma)
|
| 415 |
+
typename Element_, ///< data type of element to be written
|
| 416 |
+
typename Layout_, ///< target shared memory layout
|
| 417 |
+
typename MmaSimtPolicy_ ///< policy defining lane arrangement (concept: MmaSimtPolicy)
|
| 418 |
+
>
|
| 419 |
+
class TileIteratorSimtDirect2dConv {
|
| 420 |
+
public:
|
| 421 |
+
using WarpShape = WarpShape_;
|
| 422 |
+
using ThreadOutputShape = ThreadOutputShape_;
|
| 423 |
+
using ThreadBlockOutputShape = ThreadBlockOutputShape_;
|
| 424 |
+
using Operator = Operator_;
|
| 425 |
+
using Element = Element_;
|
| 426 |
+
using Layout = layout::RowMajor;
|
| 427 |
+
using MmaSimtPolicy = MmaSimtPolicy_;
|
| 428 |
+
|
| 429 |
+
using TensorRef = TensorRef<Element, Layout>; ///< Tensor Reference object
|
| 430 |
+
using TensorCoord = MatrixCoord; ///< Logical coordinate in referenced tensor
|
| 431 |
+
using Index = typename TensorRef::Index;
|
| 432 |
+
using LongIndex = typename TensorRef::LongIndex;
|
| 433 |
+
|
| 434 |
+
// Thread-level shape of a fragment
|
| 435 |
+
using ThreadShape = MatrixShape<ThreadOutputShape::kNHW, ThreadOutputShape::kC>;
|
| 436 |
+
|
| 437 |
+
static_assert(!(ThreadShape::kColumn % MmaSimtPolicy::LaneMmaShape::kN),
|
| 438 |
+
"Thread-level GEMM must be divisible by Policy::LaneMmaShape.");
|
| 439 |
+
|
| 440 |
+
using ThreadTileCount = MatrixShape<ThreadBlockOutputShape::kH / ThreadOutputShape::kH,
|
| 441 |
+
ThreadBlockOutputShape::kW / ThreadOutputShape::kW>;
|
| 442 |
+
|
| 443 |
+
using Iterations =
|
| 444 |
+
MatrixShape<ThreadShape::kRow, ThreadShape::kColumn / MmaSimtPolicy::LaneMmaShape::kN>;
|
| 445 |
+
|
| 446 |
+
/// This is the complete warp-level accumulator tile.
|
| 447 |
+
using AccumulatorTile = typename Operator::FragmentC;
|
| 448 |
+
|
| 449 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 450 |
+
using Fragment = AccumulatorTile;
|
| 451 |
+
|
| 452 |
+
/// Padding quantity
|
| 453 |
+
using Padding = MatrixShape<0, 0>;
|
| 454 |
+
|
| 455 |
+
private:
|
| 456 |
+
// Storage type for accessing memory
|
| 457 |
+
using AccessType = AlignedArray<Element, MmaSimtPolicy::LaneMmaShape::kN>;
|
| 458 |
+
//
|
| 459 |
+
// Data members
|
| 460 |
+
//
|
| 461 |
+
|
| 462 |
+
/// Internal pointer to memory
|
| 463 |
+
AccessType *pointer_;
|
| 464 |
+
|
| 465 |
+
/// Internal layout object
|
| 466 |
+
Layout layout_;
|
| 467 |
+
|
| 468 |
+
/// Base smem offset;
|
| 469 |
+
Index base_smem_address_;
|
| 470 |
+
|
| 471 |
+
public:
|
| 472 |
+
/// Default constructor
|
| 473 |
+
CUTLASS_HOST_DEVICE
|
| 474 |
+
TileIteratorSimtDirect2dConv() : pointer_(nullptr) {}
|
| 475 |
+
|
| 476 |
+
/// Constructor from TensorRef
|
| 477 |
+
CUTLASS_HOST_DEVICE
|
| 478 |
+
TileIteratorSimtDirect2dConv(TensorRef const &ref, unsigned thread_id, unsigned lane_id)
|
| 479 |
+
: pointer_(reinterpret_cast<AccessType *>(ref.data())),
|
| 480 |
+
layout_(ref.stride()[0] / AccessType::kElements) {
|
| 481 |
+
|
| 482 |
+
auto lane_layout = MmaSimtPolicy::get_lane_layout();
|
| 483 |
+
|
| 484 |
+
MatrixCoord lane_offset = lane_layout.inverse(lane_id);
|
| 485 |
+
|
| 486 |
+
// Get base HW offset of current threads
|
| 487 |
+
const int threadgroup = thread_id / (ThreadBlockOutputShape::kC / ThreadOutputShape::kC);
|
| 488 |
+
const int base_p = (threadgroup / (ThreadTileCount::kColumn)) * ThreadOutputShape::kH;
|
| 489 |
+
const int base_q = (threadgroup % (ThreadTileCount::kColumn)) * ThreadOutputShape::kW;
|
| 490 |
+
|
| 491 |
+
const int row_offset = base_p * ThreadBlockOutputShape::kW + base_q;
|
| 492 |
+
|
| 493 |
+
pointer_ += layout_(
|
| 494 |
+
{row_offset,
|
| 495 |
+
lane_offset.column() * MmaSimtPolicy::LaneMmaShape::kN / int(AccessType::kElements)});
|
| 496 |
+
}
|
| 497 |
+
|
| 498 |
+
/// Adds a pointer offset
|
| 499 |
+
CUTLASS_HOST_DEVICE
|
| 500 |
+
TileIteratorSimtDirect2dConv &add_pointer_offset(Index pointer_offset) {
|
| 501 |
+
pointer_ += pointer_offset / AccessType::kElements;
|
| 502 |
+
return *this;
|
| 503 |
+
}
|
| 504 |
+
|
| 505 |
+
/// Store
|
| 506 |
+
CUTLASS_HOST_DEVICE
|
| 507 |
+
void store_with_pointer_offset(Fragment const &frag, Index pointer_offset) {
|
| 508 |
+
AccessType *storer_pointer_ =
|
| 509 |
+
reinterpret_cast<AccessType *>(reinterpret_cast<uint8_t *>(pointer_) + base_smem_address_);
|
| 510 |
+
AccessType const *frag_ptr = reinterpret_cast<AccessType const *>(&frag);
|
| 511 |
+
|
| 512 |
+
CUTLASS_PRAGMA_UNROLL
|
| 513 |
+
for (int h = 0; h < ThreadOutputShape::kH; ++h) {
|
| 514 |
+
CUTLASS_PRAGMA_UNROLL
|
| 515 |
+
for (int w = 0; w < ThreadOutputShape::kW; ++w) {
|
| 516 |
+
CUTLASS_PRAGMA_UNROLL
|
| 517 |
+
for (int col = 0; col < Iterations::kColumn; ++col) {
|
| 518 |
+
int offset = (w + h * ThreadBlockOutputShape::kW) *
|
| 519 |
+
(ThreadBlockOutputShape::kC / AccessType::kElements) +
|
| 520 |
+
col;
|
| 521 |
+
storer_pointer_[offset + pointer_offset / int(AccessType::kElements)] =
|
| 522 |
+
frag_ptr[w + h * ThreadOutputShape::kW + col];
|
| 523 |
+
}
|
| 524 |
+
}
|
| 525 |
+
}
|
| 526 |
+
}
|
| 527 |
+
|
| 528 |
+
/// Store
|
| 529 |
+
CUTLASS_HOST_DEVICE
|
| 530 |
+
void store(Fragment const &frag) { store_with_pointer_offset(frag, 0); }
|
| 531 |
+
|
| 532 |
+
/// Set smem base address
|
| 533 |
+
CUTLASS_HOST_DEVICE
|
| 534 |
+
void set_smem_base_address(Index address) { base_smem_address_ = address; }
|
| 535 |
+
};
|
| 536 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 537 |
+
|
| 538 |
+
/// Template for reading and writing tiles of accumulators to shared memory
|
| 539 |
+
template <
|
| 540 |
+
typename WarpShape_, ///< shape of warp-level GEMM (concept: GemmShape)
|
| 541 |
+
typename Operator_, ///< matrix multiply operation (concept: arch::Mma)
|
| 542 |
+
typename Element_, ///< data type of element to be written
|
| 543 |
+
typename Layout_, ///< target shared memory layout
|
| 544 |
+
typename MmaSimtPolicy_ ///< policy defining lane arrangement (concept: MmaSimtPolicy)
|
| 545 |
+
>
|
| 546 |
+
class TileIteratorSimtCanonical {
|
| 547 |
+
public:
|
| 548 |
+
|
| 549 |
+
using WarpShape = WarpShape_;
|
| 550 |
+
using Operator = Operator_;
|
| 551 |
+
using Element = Element_;
|
| 552 |
+
using Layout = Layout_;
|
| 553 |
+
|
| 554 |
+
using TensorRef = TensorRef<Element, Layout>; ///< Tensor Reference object
|
| 555 |
+
using TensorCoord = MatrixCoord; ///< Logical coordinate in referenced tensor
|
| 556 |
+
using Index = typename TensorRef::Index;
|
| 557 |
+
using LongIndex = typename TensorRef::LongIndex;
|
| 558 |
+
|
| 559 |
+
using Policy = SimtPolicy<WarpShape, Operator, Layout, MmaSimtPolicy_>;
|
| 560 |
+
|
| 561 |
+
/// Shape of the tile in memory
|
| 562 |
+
using Shape = MatrixShape<
|
| 563 |
+
Policy::kRowsPerIteration,
|
| 564 |
+
WarpShape::kN
|
| 565 |
+
>;
|
| 566 |
+
|
| 567 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 568 |
+
using Fragment = Array<
|
| 569 |
+
typename Operator::ElementC,
|
| 570 |
+
Policy::kElementsPerIteration>;
|
| 571 |
+
|
| 572 |
+
/// This is the complete warp-level accumulator tile.
|
| 573 |
+
using AccumulatorTile = Array<
|
| 574 |
+
typename Operator::ElementC,
|
| 575 |
+
Policy::kAccumulatorElementCount>;
|
| 576 |
+
|
| 577 |
+
/// Number of times this iterator can be incremented
|
| 578 |
+
static int const kIterations = Policy::kIterations;
|
| 579 |
+
|
| 580 |
+
/// Padding quantity
|
| 581 |
+
using Padding = MatrixShape<
|
| 582 |
+
0,
|
| 583 |
+
4 * Policy::kElementsPerAccess + 1
|
| 584 |
+
>;
|
| 585 |
+
|
| 586 |
+
private:
|
| 587 |
+
|
| 588 |
+
/// Storage type for accessing memory
|
| 589 |
+
using AccessType = AlignedArray<
|
| 590 |
+
Element,
|
| 591 |
+
1
|
| 592 |
+
>;
|
| 593 |
+
|
| 594 |
+
//
|
| 595 |
+
// Data members
|
| 596 |
+
//
|
| 597 |
+
|
| 598 |
+
/// Internal pointer to memory
|
| 599 |
+
AccessType *pointer_;
|
| 600 |
+
|
| 601 |
+
/// Internal layout object
|
| 602 |
+
Layout layout_;
|
| 603 |
+
|
| 604 |
+
/// Guard to indicate whether the shape is divisible
|
| 605 |
+
bool divisible_;
|
| 606 |
+
|
| 607 |
+
/// Extent of the output tensor
|
| 608 |
+
MatrixCoord extent_;
|
| 609 |
+
|
| 610 |
+
/// Thread offset
|
| 611 |
+
MatrixCoord thread_offset_;
|
| 612 |
+
|
| 613 |
+
public:
|
| 614 |
+
|
| 615 |
+
/// Default constructor
|
| 616 |
+
CUTLASS_HOST_DEVICE
|
| 617 |
+
TileIteratorSimtCanonical(): pointer_(nullptr) { }
|
| 618 |
+
|
| 619 |
+
/// Constructor from TensorRef
|
| 620 |
+
CUTLASS_HOST_DEVICE
|
| 621 |
+
TileIteratorSimtCanonical(
|
| 622 |
+
TensorRef const &ref,
|
| 623 |
+
unsigned lane_id
|
| 624 |
+
):
|
| 625 |
+
pointer_(reinterpret_cast<AccessType *>(ref.data())),
|
| 626 |
+
layout_(ref.stride()[0] / AccessType::kElements),
|
| 627 |
+
divisible_(true),
|
| 628 |
+
extent_(WarpShape::kM, WarpShape::kN) {
|
| 629 |
+
|
| 630 |
+
auto lane_layout = Policy::MmaSimtPolicy::get_lane_layout();
|
| 631 |
+
MatrixCoord lane_offset = lane_layout.inverse(lane_id);
|
| 632 |
+
|
| 633 |
+
thread_offset_ = {
|
| 634 |
+
lane_offset.row() * Shape::kRow,
|
| 635 |
+
lane_offset.column() * Policy::kElementsPerAccess
|
| 636 |
+
};
|
| 637 |
+
|
| 638 |
+
pointer_ += layout_({
|
| 639 |
+
lane_offset.row() * Shape::kRow,
|
| 640 |
+
lane_offset.column() * Policy::kElementsPerAccess / int(AccessType::kElements)
|
| 641 |
+
});
|
| 642 |
+
}
|
| 643 |
+
|
| 644 |
+
/// Constructor from TensorRef
|
| 645 |
+
CUTLASS_HOST_DEVICE
|
| 646 |
+
TileIteratorSimtCanonical(
|
| 647 |
+
TensorRef const &ref,
|
| 648 |
+
TensorCoord const &extent,
|
| 649 |
+
unsigned lane_id
|
| 650 |
+
):
|
| 651 |
+
pointer_(reinterpret_cast<AccessType *>(ref.data())),
|
| 652 |
+
layout_(ref.stride()[0] / AccessType::kElements),
|
| 653 |
+
divisible_(false),
|
| 654 |
+
extent_(extent) {
|
| 655 |
+
|
| 656 |
+
auto lane_layout = Policy::MmaSimtPolicy::get_lane_layout();
|
| 657 |
+
MatrixCoord lane_offset = lane_layout.inverse(lane_id);
|
| 658 |
+
|
| 659 |
+
thread_offset_ = {
|
| 660 |
+
lane_offset.row() * Shape::kRow,
|
| 661 |
+
lane_offset.column() * Policy::kElementsPerAccess
|
| 662 |
+
};
|
| 663 |
+
|
| 664 |
+
pointer_ += layout_({
|
| 665 |
+
lane_offset.row() * Shape::kRow,
|
| 666 |
+
lane_offset.column() * Policy::kElementsPerAccess / int(AccessType::kElements)
|
| 667 |
+
});
|
| 668 |
+
}
|
| 669 |
+
|
| 670 |
+
/// Adds a pointer offset
|
| 671 |
+
CUTLASS_HOST_DEVICE
|
| 672 |
+
TileIteratorSimtCanonical & add_pointer_offset(Index pointer_offset) {
|
| 673 |
+
pointer_ += pointer_offset / AccessType::kElements;
|
| 674 |
+
return *this;
|
| 675 |
+
}
|
| 676 |
+
|
| 677 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 678 |
+
CUTLASS_HOST_DEVICE
|
| 679 |
+
TileIteratorSimtCanonical & add_tile_offset(TensorCoord const &tile_offset) {
|
| 680 |
+
|
| 681 |
+
MatrixCoord coord_offset(
|
| 682 |
+
tile_offset.row(),
|
| 683 |
+
tile_offset.column() * Shape::kColumn
|
| 684 |
+
);
|
| 685 |
+
|
| 686 |
+
thread_offset_ += coord_offset;
|
| 687 |
+
|
| 688 |
+
pointer_ += layout_({
|
| 689 |
+
coord_offset.row(),
|
| 690 |
+
coord_offset.column()
|
| 691 |
+
});
|
| 692 |
+
|
| 693 |
+
return *this;
|
| 694 |
+
}
|
| 695 |
+
|
| 696 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 697 |
+
CUTLASS_HOST_DEVICE
|
| 698 |
+
TileIteratorSimtCanonical & operator+=(TensorCoord const &tile_offset) {
|
| 699 |
+
|
| 700 |
+
add_tile_offset(tile_offset);
|
| 701 |
+
|
| 702 |
+
return *this;
|
| 703 |
+
}
|
| 704 |
+
|
| 705 |
+
/// Store
|
| 706 |
+
CUTLASS_HOST_DEVICE
|
| 707 |
+
void store_with_pointer_offset(Fragment const &frag, Index pointer_offset) {
|
| 708 |
+
|
| 709 |
+
// de-vectorized stores
|
| 710 |
+
using ScalarAccessType = AlignedArray<Element, 1>;
|
| 711 |
+
ScalarAccessType const *scalarFragPtr = reinterpret_cast<ScalarAccessType const *>(&frag);
|
| 712 |
+
ScalarAccessType *scalarPointer = reinterpret_cast<ScalarAccessType *>(pointer_) + pointer_offset;
|
| 713 |
+
|
| 714 |
+
CUTLASS_PRAGMA_UNROLL
|
| 715 |
+
for (int n = 0; n < Policy::kAccessesPerIteration; ++n) {
|
| 716 |
+
CUTLASS_PRAGMA_UNROLL
|
| 717 |
+
for (int s = 0; s < Policy::kElementsPerAccess; s++) {
|
| 718 |
+
|
| 719 |
+
int ptr_idx = n * Policy::MmaSimtPolicy::WarpShape::kColumn * Policy::kElementsPerAccess + s;
|
| 720 |
+
int frag_idx = n * Policy::kElementsPerAccess + s;
|
| 721 |
+
|
| 722 |
+
int col = thread_offset_.column() + ptr_idx;
|
| 723 |
+
|
| 724 |
+
if (divisible_ || (thread_offset_.row() < extent_.row() && col < extent_.column())) {
|
| 725 |
+
scalarPointer[ptr_idx] = scalarFragPtr[frag_idx];
|
| 726 |
+
}
|
| 727 |
+
}
|
| 728 |
+
}
|
| 729 |
+
}
|
| 730 |
+
|
| 731 |
+
/// Store
|
| 732 |
+
CUTLASS_HOST_DEVICE
|
| 733 |
+
void store(Fragment const &frag) {
|
| 734 |
+
store_with_pointer_offset(frag, 0);
|
| 735 |
+
}
|
| 736 |
+
|
| 737 |
+
/// Load
|
| 738 |
+
CUTLASS_HOST_DEVICE
|
| 739 |
+
void load_with_pointer_offset(Fragment &frag, Index pointer_offset) const {
|
| 740 |
+
|
| 741 |
+
// de-vectorized loads
|
| 742 |
+
using ScalarAccessType = AlignedArray<Element, 1>;
|
| 743 |
+
ScalarAccessType *scalarFragPtr = reinterpret_cast<ScalarAccessType *>(&frag);
|
| 744 |
+
ScalarAccessType const *scalarPointer = reinterpret_cast<ScalarAccessType const*>(pointer_) + pointer_offset;
|
| 745 |
+
|
| 746 |
+
CUTLASS_PRAGMA_UNROLL
|
| 747 |
+
for (int n = 0; n < Policy::kAccessesPerIteration; ++n) {
|
| 748 |
+
CUTLASS_PRAGMA_UNROLL
|
| 749 |
+
for (int s = 0; s < Policy::kElementsPerAccess; s++) {
|
| 750 |
+
|
| 751 |
+
int ptr_idx = n * Policy::MmaSimtPolicy::WarpShape::kColumn * Policy::kElementsPerAccess + s;
|
| 752 |
+
int frag_idx = n * Policy::kElementsPerAccess + s;
|
| 753 |
+
|
| 754 |
+
int col = thread_offset_.column() + ptr_idx;
|
| 755 |
+
|
| 756 |
+
if (divisible_ || (thread_offset_.row() < extent_.row() && col < extent_.column())) {
|
| 757 |
+
scalarFragPtr[frag_idx] = scalarPointer[ptr_idx];
|
| 758 |
+
}
|
| 759 |
+
}
|
| 760 |
+
}
|
| 761 |
+
}
|
| 762 |
+
|
| 763 |
+
/// Load
|
| 764 |
+
CUTLASS_HOST_DEVICE
|
| 765 |
+
void load(Fragment &frag) const {
|
| 766 |
+
load_with_pointer_offset(frag, 0);
|
| 767 |
+
}
|
| 768 |
+
|
| 769 |
+
CUTLASS_HOST_DEVICE
|
| 770 |
+
TileIteratorSimtCanonical & operator++() {
|
| 771 |
+
return add_tile_offset({1, 0});
|
| 772 |
+
}
|
| 773 |
+
|
| 774 |
+
/// Set smem base address
|
| 775 |
+
CUTLASS_HOST_DEVICE
|
| 776 |
+
void set_smem_base_address(Index address) {
|
| 777 |
+
}
|
| 778 |
+
};
|
| 779 |
+
|
| 780 |
+
|
| 781 |
+
} // namespace warp
|
| 782 |
+
} // namespace epilogue
|
| 783 |
+
} // namespace cutlass
|
| 784 |
+
|
| 785 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/tile_iterator_tensor_op.h
ADDED
|
@@ -0,0 +1,671 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief
|
| 33 |
+
*/
|
| 34 |
+
|
| 35 |
+
#pragma once
|
| 36 |
+
|
| 37 |
+
#include "cutlass/array.h"
|
| 38 |
+
#include "cutlass/tensor_ref.h"
|
| 39 |
+
#include "cutlass/layout/matrix.h"
|
| 40 |
+
#include "cutlass/layout/pitch_linear.h"
|
| 41 |
+
|
| 42 |
+
#include "cutlass/epilogue/warp/tensor_op_policy.h"
|
| 43 |
+
|
| 44 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 45 |
+
|
| 46 |
+
namespace cutlass {
|
| 47 |
+
namespace epilogue {
|
| 48 |
+
namespace warp {
|
| 49 |
+
|
| 50 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 51 |
+
|
| 52 |
+
/// Template for reading and writing tiles of accumulators to shared memory
|
| 53 |
+
template <
|
| 54 |
+
typename WarpShape, ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 55 |
+
typename OperatorShape, ///< matrix multiply operation shape (concept: gemm::GemmShape)
|
| 56 |
+
typename Element, ///< data type of element to be written
|
| 57 |
+
typename Layout ///< target shared memory layout
|
| 58 |
+
>
|
| 59 |
+
class TileIteratorTensorOp;
|
| 60 |
+
|
| 61 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 62 |
+
|
| 63 |
+
/// Template for reading and writing tiles of accumulators to shared memory
|
| 64 |
+
template <
|
| 65 |
+
typename WarpShape_, ///< shape of warp-level GEMM (concept: GemmShape)
|
| 66 |
+
typename OperatorShape_, ///< matrix multiply operation shape (concept: gemm::GemmShape)
|
| 67 |
+
typename Element_ ///< data type of element to be written
|
| 68 |
+
>
|
| 69 |
+
class TileIteratorTensorOp<WarpShape_, OperatorShape_, Element_, layout::RowMajor> {
|
| 70 |
+
public:
|
| 71 |
+
|
| 72 |
+
using WarpShape = WarpShape_;
|
| 73 |
+
using OperatorShape = OperatorShape_;
|
| 74 |
+
using Element = Element_;
|
| 75 |
+
using Layout = layout::RowMajor;
|
| 76 |
+
|
| 77 |
+
using TensorLayout = Layout;
|
| 78 |
+
using TensorRef = TensorRef<Element, Layout>; ///< Tensor Reference object
|
| 79 |
+
using TensorCoord = MatrixCoord; ///< Logical coordinate in referenced tensor
|
| 80 |
+
using Index = typename TensorRef::Index;
|
| 81 |
+
using LongIndex = typename TensorRef::LongIndex;
|
| 82 |
+
|
| 83 |
+
using Policy = TensorOpPolicy<WarpShape, OperatorShape, Layout>;
|
| 84 |
+
|
| 85 |
+
/// Shape of the tile in memory
|
| 86 |
+
using Shape = MatrixShape<
|
| 87 |
+
Policy::kRowsPerIteration,
|
| 88 |
+
WarpShape::kN
|
| 89 |
+
>;
|
| 90 |
+
|
| 91 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 92 |
+
using Fragment = Array<
|
| 93 |
+
Element,
|
| 94 |
+
Policy::OperatorCount::kColumn * Policy::kElementsPerAccess>;
|
| 95 |
+
|
| 96 |
+
/// This is the complete warp-level accumulator tile.
|
| 97 |
+
//using AccumulatorTile = typename Operator::FragmentC;
|
| 98 |
+
|
| 99 |
+
/// Number of times this iterator can be incremented
|
| 100 |
+
static int const kIterations = Policy::kIterations;
|
| 101 |
+
|
| 102 |
+
/// Number of times this iterator can be incremented
|
| 103 |
+
using TileIterations = typename Policy::TileIterations;
|
| 104 |
+
|
| 105 |
+
// Internal constants
|
| 106 |
+
struct Detail {
|
| 107 |
+
static int const kLanesInQuad = 4;
|
| 108 |
+
};
|
| 109 |
+
|
| 110 |
+
/// Padding quantity
|
| 111 |
+
using Padding = MatrixShape<
|
| 112 |
+
0,
|
| 113 |
+
Detail::kLanesInQuad * Policy::kElementsPerAccess>;
|
| 114 |
+
|
| 115 |
+
private:
|
| 116 |
+
|
| 117 |
+
/// Storage type for accessing memory
|
| 118 |
+
using AccessType = AlignedArray<Element, Policy::kElementsPerAccess>;
|
| 119 |
+
|
| 120 |
+
//
|
| 121 |
+
// Data members
|
| 122 |
+
//
|
| 123 |
+
|
| 124 |
+
/// Internal pointer to memory
|
| 125 |
+
AccessType *pointer_;
|
| 126 |
+
|
| 127 |
+
/// Internal layout object
|
| 128 |
+
Layout layout_;
|
| 129 |
+
|
| 130 |
+
/// Thread offset
|
| 131 |
+
MatrixCoord thread_offset_;
|
| 132 |
+
|
| 133 |
+
public:
|
| 134 |
+
|
| 135 |
+
/// Default constructor
|
| 136 |
+
CUTLASS_HOST_DEVICE
|
| 137 |
+
TileIteratorTensorOp(): pointer_(nullptr) { }
|
| 138 |
+
|
| 139 |
+
/// Constructor from TensorRef
|
| 140 |
+
CUTLASS_HOST_DEVICE
|
| 141 |
+
TileIteratorTensorOp(
|
| 142 |
+
TensorRef const &ref,
|
| 143 |
+
unsigned lane_id
|
| 144 |
+
):
|
| 145 |
+
pointer_(reinterpret_cast<AccessType *>(ref.data())),
|
| 146 |
+
layout_(ref.stride()[0] / Policy::kElementsPerAccess) {
|
| 147 |
+
|
| 148 |
+
int quad_id = (lane_id / Detail::kLanesInQuad);
|
| 149 |
+
int lane_in_quad = (lane_id % Detail::kLanesInQuad);
|
| 150 |
+
|
| 151 |
+
thread_offset_ = {
|
| 152 |
+
quad_id, lane_in_quad * Policy::kElementsPerAccess
|
| 153 |
+
};
|
| 154 |
+
|
| 155 |
+
pointer_ += layout_({thread_offset_.row(), thread_offset_.column() / Policy::kElementsPerAccess});
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
/// Adds a pointer offset
|
| 159 |
+
CUTLASS_HOST_DEVICE
|
| 160 |
+
TileIteratorTensorOp & add_pointer_offset(Index pointer_offset) {
|
| 161 |
+
pointer_ += pointer_offset / Policy::kElementsPerAccess;
|
| 162 |
+
return *this;
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 166 |
+
CUTLASS_HOST_DEVICE
|
| 167 |
+
TileIteratorTensorOp & add_tile_offset(TensorCoord const &tile_offset) {
|
| 168 |
+
|
| 169 |
+
MatrixCoord coord_offset(
|
| 170 |
+
tile_offset.row() * Shape::kRow,
|
| 171 |
+
tile_offset.column() * Shape::kColumn
|
| 172 |
+
);
|
| 173 |
+
|
| 174 |
+
thread_offset_ += coord_offset;
|
| 175 |
+
|
| 176 |
+
pointer_ += layout_({
|
| 177 |
+
coord_offset.row(),
|
| 178 |
+
coord_offset.column() / Policy::kElementsPerAccess
|
| 179 |
+
});
|
| 180 |
+
|
| 181 |
+
return *this;
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 185 |
+
CUTLASS_HOST_DEVICE
|
| 186 |
+
TileIteratorTensorOp & operator+=(TensorCoord const &tile_offset) {
|
| 187 |
+
add_tile_offset(tile_offset);
|
| 188 |
+
return *this;
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
/// Store
|
| 192 |
+
CUTLASS_HOST_DEVICE
|
| 193 |
+
void store_with_pointer_offset(Fragment const &frag, Index pointer_offset) {
|
| 194 |
+
|
| 195 |
+
AccessType const *frag_ptr = reinterpret_cast<AccessType const *>(&frag);
|
| 196 |
+
|
| 197 |
+
CUTLASS_PRAGMA_UNROLL
|
| 198 |
+
for (int n = 0; n < Policy::OperatorCount::kColumn; ++n) {
|
| 199 |
+
pointer_[n * Detail::kLanesInQuad + pointer_offset / Policy::kElementsPerAccess] = frag_ptr[n];
|
| 200 |
+
}
|
| 201 |
+
}
|
| 202 |
+
|
| 203 |
+
/// Store
|
| 204 |
+
CUTLASS_HOST_DEVICE
|
| 205 |
+
void store(Fragment const &frag) {
|
| 206 |
+
store_with_pointer_offset(frag, 0);
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
/// Load
|
| 210 |
+
CUTLASS_HOST_DEVICE
|
| 211 |
+
void load_with_pointer_offset(Fragment &frag, Index pointer_offset) const {
|
| 212 |
+
|
| 213 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 214 |
+
|
| 215 |
+
CUTLASS_PRAGMA_UNROLL
|
| 216 |
+
for (int n = 0; n < Policy::OperatorCount::kColumn; ++n) {
|
| 217 |
+
frag_ptr[n] = pointer_[n * Detail::kLanesInQuad + pointer_offset / Policy::kElementsPerAccess];
|
| 218 |
+
}
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
/// Load
|
| 222 |
+
CUTLASS_HOST_DEVICE
|
| 223 |
+
void load(Fragment &frag) const {
|
| 224 |
+
load_with_pointer_offset(frag, 0);
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
CUTLASS_HOST_DEVICE
|
| 228 |
+
TileIteratorTensorOp & operator++() {
|
| 229 |
+
return add_tile_offset({1, 0});
|
| 230 |
+
}
|
| 231 |
+
|
| 232 |
+
/// Set smem base address
|
| 233 |
+
CUTLASS_HOST_DEVICE
|
| 234 |
+
void set_smem_base_address(Index address) {
|
| 235 |
+
}
|
| 236 |
+
};
|
| 237 |
+
|
| 238 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 239 |
+
|
| 240 |
+
/// Template for reading and writing tiles of accumulators to shared memory
|
| 241 |
+
template <
|
| 242 |
+
typename WarpShape_, ///< shape of warp-level GEMM (concept: GemmShape)
|
| 243 |
+
typename OperatorShape_, ///< matrix multiply operation shape (concept: gemm::GemmShape)
|
| 244 |
+
typename Element_, ///< data type of element to be written
|
| 245 |
+
int InterleavedK ///< number of interleaved k
|
| 246 |
+
>
|
| 247 |
+
class TileIteratorTensorOp<WarpShape_, OperatorShape_, Element_,
|
| 248 |
+
layout::ColumnMajorInterleaved<InterleavedK> > {
|
| 249 |
+
public:
|
| 250 |
+
|
| 251 |
+
using WarpShape = WarpShape_;
|
| 252 |
+
using OperatorShape = OperatorShape_;
|
| 253 |
+
using Element = Element_;
|
| 254 |
+
using Layout = layout::ColumnMajorInterleaved<InterleavedK>;
|
| 255 |
+
using TensorLayout = Layout; ///< shared memory tensor ref layout
|
| 256 |
+
|
| 257 |
+
using TensorRef = TensorRef<Element, TensorLayout>; ///< Tensor Reference object
|
| 258 |
+
using TensorCoord = MatrixCoord; ///< Logical coordinate in referenced tensor
|
| 259 |
+
using Index = typename TensorRef::Index;
|
| 260 |
+
using LongIndex = typename TensorRef::LongIndex;
|
| 261 |
+
|
| 262 |
+
using Policy = TensorOpPolicy<WarpShape, OperatorShape, Layout>;
|
| 263 |
+
|
| 264 |
+
/// Shape of the tile in memory
|
| 265 |
+
using Shape = MatrixShape<
|
| 266 |
+
// Policy::kRowsPerIteration,
|
| 267 |
+
WarpShape::kM,
|
| 268 |
+
InterleavedK
|
| 269 |
+
>;
|
| 270 |
+
|
| 271 |
+
/// This is the fragment size produced by one tile
|
| 272 |
+
using Fragment = Array<
|
| 273 |
+
Element,
|
| 274 |
+
Policy::OperatorCount::kRow * Policy::kIterationsPerInstruction
|
| 275 |
+
* Policy::kElementsPerIteration>;
|
| 276 |
+
|
| 277 |
+
/// This is the fragment size produced by one iteration
|
| 278 |
+
// using Fragment = Array<
|
| 279 |
+
// Element, Policy::kElementsPerIteration >;
|
| 280 |
+
|
| 281 |
+
/// This is the complete warp-level accumulator tile.
|
| 282 |
+
//using AccumulatorTile = typename Operator::FragmentC;
|
| 283 |
+
|
| 284 |
+
/// Number of times this iterator can be incremented
|
| 285 |
+
using TileIterations = typename Policy::TileIterations;
|
| 286 |
+
|
| 287 |
+
// Internal constants
|
| 288 |
+
struct Detail {
|
| 289 |
+
static int const kLanesInQuad = 4;
|
| 290 |
+
};
|
| 291 |
+
|
| 292 |
+
/// Padding quantity
|
| 293 |
+
using Padding = MatrixShape<
|
| 294 |
+
0,
|
| 295 |
+
Detail::kLanesInQuad * Policy::kElementsPerIteration>;
|
| 296 |
+
|
| 297 |
+
private:
|
| 298 |
+
|
| 299 |
+
/// Storage type for accessing memory
|
| 300 |
+
using AccessType = AlignedArray<Element, Policy::kElementsPerAccess>;
|
| 301 |
+
|
| 302 |
+
//
|
| 303 |
+
// Data members
|
| 304 |
+
//
|
| 305 |
+
|
| 306 |
+
/// Internal pointer to memory
|
| 307 |
+
AccessType *pointer_;
|
| 308 |
+
|
| 309 |
+
/// Internal layout object
|
| 310 |
+
TensorLayout layout_;
|
| 311 |
+
|
| 312 |
+
/// Thread offset
|
| 313 |
+
MatrixCoord thread_offset_;
|
| 314 |
+
|
| 315 |
+
public:
|
| 316 |
+
|
| 317 |
+
/// Default constructor
|
| 318 |
+
CUTLASS_HOST_DEVICE
|
| 319 |
+
TileIteratorTensorOp(): pointer_(nullptr) { }
|
| 320 |
+
|
| 321 |
+
/// Constructor from TensorRef
|
| 322 |
+
CUTLASS_HOST_DEVICE
|
| 323 |
+
TileIteratorTensorOp(
|
| 324 |
+
TensorRef const &ref,
|
| 325 |
+
unsigned lane_id
|
| 326 |
+
):
|
| 327 |
+
pointer_(reinterpret_cast<AccessType *>(ref.data())),
|
| 328 |
+
layout_(ref.stride()[0]) {
|
| 329 |
+
|
| 330 |
+
int quad_id = (lane_id / Detail::kLanesInQuad);
|
| 331 |
+
int lane_in_quad = (lane_id % Detail::kLanesInQuad);
|
| 332 |
+
|
| 333 |
+
thread_offset_ = {
|
| 334 |
+
quad_id, lane_in_quad * Policy::kElementsPerIteration
|
| 335 |
+
};
|
| 336 |
+
|
| 337 |
+
pointer_ += (layout_({thread_offset_.row(), thread_offset_.column()}) / Policy::kElementsPerAccess);
|
| 338 |
+
}
|
| 339 |
+
|
| 340 |
+
/// Adds a pointer offset
|
| 341 |
+
CUTLASS_HOST_DEVICE
|
| 342 |
+
TileIteratorTensorOp & add_pointer_offset(Index pointer_offset) {
|
| 343 |
+
pointer_ += pointer_offset / Policy::kElementsPerAccess;
|
| 344 |
+
return *this;
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 348 |
+
CUTLASS_HOST_DEVICE
|
| 349 |
+
TileIteratorTensorOp & add_tile_offset(TensorCoord const &tile_offset) {
|
| 350 |
+
|
| 351 |
+
MatrixCoord coord_offset(
|
| 352 |
+
tile_offset.row() * Shape::kRow,
|
| 353 |
+
tile_offset.column() * Shape::kColumn
|
| 354 |
+
);
|
| 355 |
+
|
| 356 |
+
thread_offset_ += coord_offset;
|
| 357 |
+
|
| 358 |
+
pointer_ += (layout_({
|
| 359 |
+
coord_offset.row(),
|
| 360 |
+
coord_offset.column()
|
| 361 |
+
}) / Policy::kElementsPerAccess);
|
| 362 |
+
|
| 363 |
+
return *this;
|
| 364 |
+
}
|
| 365 |
+
|
| 366 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 367 |
+
CUTLASS_HOST_DEVICE
|
| 368 |
+
TileIteratorTensorOp & operator+=(TensorCoord const &tile_offset) {
|
| 369 |
+
add_tile_offset(tile_offset);
|
| 370 |
+
return *this;
|
| 371 |
+
}
|
| 372 |
+
|
| 373 |
+
/// Store
|
| 374 |
+
CUTLASS_HOST_DEVICE
|
| 375 |
+
void store_with_pointer_offset(Fragment const &frag, Index pointer_offset) {
|
| 376 |
+
|
| 377 |
+
AccessType const *frag_ptr = reinterpret_cast<AccessType const *>(&frag);
|
| 378 |
+
|
| 379 |
+
CUTLASS_PRAGMA_UNROLL
|
| 380 |
+
for (int n = 0; n < Policy::OperatorCount::kRow * Policy::kIterationsPerInstruction; n++ ) {
|
| 381 |
+
|
| 382 |
+
AccessType *ptr = pointer_ + layout_({n * Policy::kRowsPerIteration, 0}) / Policy::kElementsPerAccess;
|
| 383 |
+
|
| 384 |
+
CUTLASS_PRAGMA_UNROLL
|
| 385 |
+
for (int a = 0; a < Policy::kAccessPerIteration; ++a) {
|
| 386 |
+
ptr[a + pointer_offset / Policy::kElementsPerAccess] = frag_ptr[n * Policy::kAccessPerIteration + a];
|
| 387 |
+
|
| 388 |
+
// printf("store thread %d, address %p, bank %ld\n", threadIdx.x, pointer_+a+n*Detail::kLanesInQuad,
|
| 389 |
+
// ((long long)(pointer_+a+n*Detail::kLanesInQuad)>>2)&0x1f);
|
| 390 |
+
}
|
| 391 |
+
}
|
| 392 |
+
}
|
| 393 |
+
|
| 394 |
+
/// Store
|
| 395 |
+
CUTLASS_HOST_DEVICE
|
| 396 |
+
void store(Fragment const &frag) {
|
| 397 |
+
store_with_pointer_offset(frag, 0);
|
| 398 |
+
}
|
| 399 |
+
|
| 400 |
+
/// Load
|
| 401 |
+
CUTLASS_HOST_DEVICE
|
| 402 |
+
void load_with_pointer_offset(Fragment &frag, Index pointer_offset) const {
|
| 403 |
+
|
| 404 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 405 |
+
|
| 406 |
+
CUTLASS_PRAGMA_UNROLL
|
| 407 |
+
for (int n = 0; n < Policy::OperatorCount::kRow * Policy::kIterationsPerInstruction; n++ ) {
|
| 408 |
+
|
| 409 |
+
AccessType *ptr = pointer_ + layout_({n * Policy::kRowsPerIteration, 0}) / Policy::kElementsPerAccess;
|
| 410 |
+
|
| 411 |
+
CUTLASS_PRAGMA_UNROLL
|
| 412 |
+
for (int a = 0; a < Policy::kAccessPerIteration; ++a) {
|
| 413 |
+
frag_ptr[n * Policy::kAccessPerIteration + a] = ptr[a + pointer_offset / Policy::kElementsPerAccess];
|
| 414 |
+
}
|
| 415 |
+
}
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
+
/// Load
|
| 419 |
+
CUTLASS_HOST_DEVICE
|
| 420 |
+
void load(Fragment &frag) const {
|
| 421 |
+
load_with_pointer_offset(frag, 0);
|
| 422 |
+
}
|
| 423 |
+
|
| 424 |
+
CUTLASS_HOST_DEVICE
|
| 425 |
+
TileIteratorTensorOp & operator++() {
|
| 426 |
+
return add_tile_offset({0, 1});
|
| 427 |
+
}
|
| 428 |
+
|
| 429 |
+
/// Set smem base address
|
| 430 |
+
CUTLASS_HOST_DEVICE
|
| 431 |
+
void set_smem_base_address(Index address) {
|
| 432 |
+
}
|
| 433 |
+
};
|
| 434 |
+
|
| 435 |
+
|
| 436 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 437 |
+
|
| 438 |
+
/// Template for reading and writing tiles of accumulators to shared memory
|
| 439 |
+
template <
|
| 440 |
+
typename WarpShape_, ///< shape of warp-level GEMM (concept: GemmShape)
|
| 441 |
+
typename OperatorShape_, ///< matrix multiply operation shape (concept: gemm::GemmShape)
|
| 442 |
+
typename Element_, ///< data type of element to be written
|
| 443 |
+
typename Layout_
|
| 444 |
+
>
|
| 445 |
+
class TileIteratorTensorOpCanonical {
|
| 446 |
+
public:
|
| 447 |
+
|
| 448 |
+
using WarpShape = WarpShape_;
|
| 449 |
+
using OperatorShape = OperatorShape_;
|
| 450 |
+
using Element = Element_;
|
| 451 |
+
using Layout = Layout_;
|
| 452 |
+
|
| 453 |
+
using TensorRef = TensorRef<Element, Layout>; ///< Tensor Reference object
|
| 454 |
+
using TensorCoord = MatrixCoord; ///< Logical coordinate in referenced tensor
|
| 455 |
+
using Index = typename TensorRef::Index;
|
| 456 |
+
using LongIndex = typename TensorRef::LongIndex;
|
| 457 |
+
|
| 458 |
+
using Policy = TensorOpPolicy<WarpShape, OperatorShape, Layout>;
|
| 459 |
+
|
| 460 |
+
static int const kAccessSize = 1;
|
| 461 |
+
static int const kAccessCount = Policy::kElementsPerAccess / kAccessSize;
|
| 462 |
+
|
| 463 |
+
/// Shape of the tile in memory
|
| 464 |
+
using Shape = MatrixShape<
|
| 465 |
+
Policy::kRowsPerIteration,
|
| 466 |
+
WarpShape::kN
|
| 467 |
+
>;
|
| 468 |
+
|
| 469 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 470 |
+
using Fragment = Array<
|
| 471 |
+
Element,
|
| 472 |
+
Policy::OperatorCount::kColumn * Policy::kElementsPerAccess>;
|
| 473 |
+
|
| 474 |
+
/// This is the complete warp-level accumulator tile.
|
| 475 |
+
//using AccumulatorTile = typename Operator::FragmentC;
|
| 476 |
+
|
| 477 |
+
/// Number of times this iterator can be incremented
|
| 478 |
+
static int const kIterations = Policy::kIterations;
|
| 479 |
+
|
| 480 |
+
// Internal constants
|
| 481 |
+
struct Detail {
|
| 482 |
+
static int const kLanesInQuad = 4;
|
| 483 |
+
};
|
| 484 |
+
|
| 485 |
+
/// Padding quantity
|
| 486 |
+
using Padding = MatrixShape<
|
| 487 |
+
0,
|
| 488 |
+
Detail::kLanesInQuad * Policy::kElementsPerAccess>;
|
| 489 |
+
|
| 490 |
+
private:
|
| 491 |
+
|
| 492 |
+
/// Storage type for accessing memory
|
| 493 |
+
using AccessType = AlignedArray<Element, kAccessSize>;
|
| 494 |
+
|
| 495 |
+
//
|
| 496 |
+
// Data members
|
| 497 |
+
//
|
| 498 |
+
|
| 499 |
+
/// Internal pointer to memory
|
| 500 |
+
AccessType *pointer_;
|
| 501 |
+
|
| 502 |
+
/// Internal layout object
|
| 503 |
+
Layout layout_;
|
| 504 |
+
|
| 505 |
+
/// Guard to indicate whether the shape is divisible
|
| 506 |
+
bool divisible_;
|
| 507 |
+
|
| 508 |
+
/// Extent of the output tensor
|
| 509 |
+
MatrixCoord extent_;
|
| 510 |
+
|
| 511 |
+
/// Thread offset
|
| 512 |
+
MatrixCoord thread_offset_;
|
| 513 |
+
|
| 514 |
+
public:
|
| 515 |
+
|
| 516 |
+
/// Default constructor
|
| 517 |
+
CUTLASS_HOST_DEVICE
|
| 518 |
+
TileIteratorTensorOpCanonical(): pointer_(nullptr) { }
|
| 519 |
+
|
| 520 |
+
/// Constructor from TensorRef
|
| 521 |
+
CUTLASS_HOST_DEVICE
|
| 522 |
+
TileIteratorTensorOpCanonical(
|
| 523 |
+
TensorRef const &ref,
|
| 524 |
+
unsigned lane_id
|
| 525 |
+
):
|
| 526 |
+
pointer_(reinterpret_cast<AccessType *>(ref.data())),
|
| 527 |
+
layout_(ref.stride()[0]),
|
| 528 |
+
divisible_(true),
|
| 529 |
+
extent_(WarpShape::kM, WarpShape::kN) {
|
| 530 |
+
|
| 531 |
+
int quad_id = (lane_id / Detail::kLanesInQuad);
|
| 532 |
+
int lane_in_quad = (lane_id % Detail::kLanesInQuad);
|
| 533 |
+
|
| 534 |
+
thread_offset_ = {
|
| 535 |
+
quad_id, lane_in_quad * Policy::kElementsPerAccess
|
| 536 |
+
};
|
| 537 |
+
|
| 538 |
+
pointer_ += layout_({thread_offset_.row(), thread_offset_.column()});
|
| 539 |
+
}
|
| 540 |
+
|
| 541 |
+
/// Constructor from TensorRef
|
| 542 |
+
CUTLASS_HOST_DEVICE
|
| 543 |
+
TileIteratorTensorOpCanonical(
|
| 544 |
+
TensorRef const &ref,
|
| 545 |
+
TensorCoord const &extent,
|
| 546 |
+
unsigned lane_id
|
| 547 |
+
):
|
| 548 |
+
pointer_(reinterpret_cast<AccessType *>(ref.data())),
|
| 549 |
+
layout_(ref.stride()[0]),
|
| 550 |
+
divisible_(false),
|
| 551 |
+
extent_(extent) {
|
| 552 |
+
|
| 553 |
+
int quad_id = (lane_id / Detail::kLanesInQuad);
|
| 554 |
+
int lane_in_quad = (lane_id % Detail::kLanesInQuad);
|
| 555 |
+
|
| 556 |
+
thread_offset_ = {
|
| 557 |
+
quad_id, lane_in_quad * Policy::kElementsPerAccess
|
| 558 |
+
};
|
| 559 |
+
|
| 560 |
+
pointer_ += layout_({thread_offset_.row(), thread_offset_.column()});
|
| 561 |
+
}
|
| 562 |
+
|
| 563 |
+
/// Adds a pointer offset
|
| 564 |
+
CUTLASS_HOST_DEVICE
|
| 565 |
+
TileIteratorTensorOpCanonical & add_pointer_offset(Index pointer_offset) {
|
| 566 |
+
pointer_ += pointer_offset;
|
| 567 |
+
return *this;
|
| 568 |
+
}
|
| 569 |
+
|
| 570 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 571 |
+
CUTLASS_HOST_DEVICE
|
| 572 |
+
TileIteratorTensorOpCanonical & add_tile_offset(TensorCoord const &tile_offset) {
|
| 573 |
+
|
| 574 |
+
MatrixCoord coord_offset(
|
| 575 |
+
tile_offset.row() * Shape::kRow,
|
| 576 |
+
tile_offset.column() * Shape::kColumn
|
| 577 |
+
);
|
| 578 |
+
|
| 579 |
+
thread_offset_ += coord_offset;
|
| 580 |
+
|
| 581 |
+
pointer_ += layout_({
|
| 582 |
+
coord_offset.row(),
|
| 583 |
+
coord_offset.column()
|
| 584 |
+
});
|
| 585 |
+
|
| 586 |
+
return *this;
|
| 587 |
+
}
|
| 588 |
+
|
| 589 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 590 |
+
CUTLASS_HOST_DEVICE
|
| 591 |
+
TileIteratorTensorOpCanonical & operator+=(TensorCoord const &tile_offset) {
|
| 592 |
+
add_tile_offset(tile_offset);
|
| 593 |
+
return *this;
|
| 594 |
+
}
|
| 595 |
+
|
| 596 |
+
/// Store
|
| 597 |
+
CUTLASS_HOST_DEVICE
|
| 598 |
+
void store_with_pointer_offset(Fragment const &frag, Index pointer_offset) {
|
| 599 |
+
|
| 600 |
+
AccessType const *frag_ptr = reinterpret_cast<AccessType const *>(&frag);
|
| 601 |
+
|
| 602 |
+
CUTLASS_PRAGMA_UNROLL
|
| 603 |
+
for (int n = 0; n < Policy::OperatorCount::kColumn; ++n) {
|
| 604 |
+
CUTLASS_PRAGMA_UNROLL
|
| 605 |
+
for (int a = 0; a < kAccessCount; ++a) {
|
| 606 |
+
|
| 607 |
+
int ptr_idx = n * Detail::kLanesInQuad * kAccessCount + pointer_offset + a;
|
| 608 |
+
int frag_idx = n * kAccessCount + a;
|
| 609 |
+
|
| 610 |
+
int col = thread_offset_.column() + n * Detail::kLanesInQuad * Policy::kElementsPerAccess + a;
|
| 611 |
+
|
| 612 |
+
if (divisible_ || (thread_offset_.row() < extent_.row() && col < extent_.column())) {
|
| 613 |
+
pointer_[ptr_idx] = frag_ptr[frag_idx];
|
| 614 |
+
}
|
| 615 |
+
}
|
| 616 |
+
}
|
| 617 |
+
}
|
| 618 |
+
|
| 619 |
+
/// Store
|
| 620 |
+
CUTLASS_HOST_DEVICE
|
| 621 |
+
void store(Fragment const &frag) {
|
| 622 |
+
store_with_pointer_offset(frag, 0);
|
| 623 |
+
}
|
| 624 |
+
|
| 625 |
+
/// Load
|
| 626 |
+
CUTLASS_HOST_DEVICE
|
| 627 |
+
void load_with_pointer_offset(Fragment &frag, Index pointer_offset) const {
|
| 628 |
+
|
| 629 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 630 |
+
|
| 631 |
+
CUTLASS_PRAGMA_UNROLL
|
| 632 |
+
for (int n = 0; n < Policy::OperatorCount::kColumn; ++n) {
|
| 633 |
+
CUTLASS_PRAGMA_UNROLL
|
| 634 |
+
for (int a = 0; a < kAccessCount; ++a) {
|
| 635 |
+
|
| 636 |
+
int ptr_idx = n * Detail::kLanesInQuad * kAccessCount + pointer_offset + a;
|
| 637 |
+
int frag_idx = n * kAccessCount + a;
|
| 638 |
+
|
| 639 |
+
int col = thread_offset_.column() + n * Detail::kLanesInQuad * Policy::kElementsPerAccess + a;
|
| 640 |
+
|
| 641 |
+
if (divisible_ || (thread_offset_.row() < extent_.row() && col < extent_.column())) {
|
| 642 |
+
frag_ptr[frag_idx] = pointer_[ptr_idx];
|
| 643 |
+
}
|
| 644 |
+
}
|
| 645 |
+
}
|
| 646 |
+
}
|
| 647 |
+
|
| 648 |
+
/// Load
|
| 649 |
+
CUTLASS_HOST_DEVICE
|
| 650 |
+
void load(Fragment &frag) const {
|
| 651 |
+
load_with_pointer_offset(frag, 0);
|
| 652 |
+
}
|
| 653 |
+
|
| 654 |
+
CUTLASS_HOST_DEVICE
|
| 655 |
+
TileIteratorTensorOpCanonical & operator++() {
|
| 656 |
+
return add_tile_offset({1, 0});
|
| 657 |
+
}
|
| 658 |
+
|
| 659 |
+
/// Set smem base address
|
| 660 |
+
CUTLASS_HOST_DEVICE
|
| 661 |
+
void set_smem_base_address(Index address) {
|
| 662 |
+
}
|
| 663 |
+
};
|
| 664 |
+
|
| 665 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 666 |
+
|
| 667 |
+
} // namespace warp
|
| 668 |
+
} // namespace epilogue
|
| 669 |
+
} // namespace cutlass
|
| 670 |
+
|
| 671 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/tile_iterator_tensor_op_mixed.h
ADDED
|
@@ -0,0 +1,1089 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief
|
| 33 |
+
*/
|
| 34 |
+
|
| 35 |
+
#pragma once
|
| 36 |
+
|
| 37 |
+
#include "cutlass/array.h"
|
| 38 |
+
#include "cutlass/layout/matrix.h"
|
| 39 |
+
#include "cutlass/layout/pitch_linear.h"
|
| 40 |
+
|
| 41 |
+
#include "cutlass/arch/memory_sm75.h"
|
| 42 |
+
#include "cutlass/epilogue/warp/tensor_op_policy.h"
|
| 43 |
+
|
| 44 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 45 |
+
|
| 46 |
+
// This is an optimization available on CUDA 11.2 and beyond that eliminates branches in the epilogue.
|
| 47 |
+
#define CUTLASS_EPILOGUE_WARP_TILE_ITERATOR_TENSOR_OP_MIXED_OPTIMIZATION_ENABLED ((__CUDACC_VER_MAJOR__ * 10 + __CUDACC_VER_MINOR__) >= 112)
|
| 48 |
+
|
| 49 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 50 |
+
|
| 51 |
+
namespace cutlass {
|
| 52 |
+
namespace epilogue {
|
| 53 |
+
namespace warp {
|
| 54 |
+
|
| 55 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 56 |
+
|
| 57 |
+
/// Template for reading and writing tiles of accumulators to shared memory. This is optimized
|
| 58 |
+
/// for mixed-precision epilogues in which the accumulators are 32b in width, but the output
|
| 59 |
+
/// data type is smaller.
|
| 60 |
+
template <
|
| 61 |
+
typename WarpShape_, ///< shape of warp-level GEMM (concept: GemmShape)
|
| 62 |
+
typename OperatorShape_, ///< matrix multiply operation shape (concept: gemm::GemmShape)
|
| 63 |
+
typename Element_, ///< data type of accumulator element
|
| 64 |
+
int ElementSizeBits, ///< Size of accumulator element in bits
|
| 65 |
+
int OutputSizeBits, ///< Size of output element in bits
|
| 66 |
+
int OutputElementCount, ///< number of elements in output vector
|
| 67 |
+
int ContiguousLanes, ///< Number of consecutive lanes writing to contiguous memory
|
| 68 |
+
bool EightBitsOutputOrLess = (OutputSizeBits <= 8)
|
| 69 |
+
>
|
| 70 |
+
class TileIteratorTensorOpMixed {
|
| 71 |
+
public:
|
| 72 |
+
|
| 73 |
+
using WarpShape = WarpShape_;
|
| 74 |
+
using OperatorShape = OperatorShape_;
|
| 75 |
+
using Element = Element_;
|
| 76 |
+
using Layout = layout::RowMajor;
|
| 77 |
+
static int const kOutputElementCount = OutputElementCount;
|
| 78 |
+
|
| 79 |
+
using TensorRef = TensorRef<Element, Layout>; ///< Tensor Reference object
|
| 80 |
+
using TensorCoord = MatrixCoord; ///< Logical coordinate in referenced tensor
|
| 81 |
+
using Index = typename TensorRef::Index;
|
| 82 |
+
using LongIndex = typename TensorRef::LongIndex;
|
| 83 |
+
|
| 84 |
+
using Policy = TensorOpPolicy<WarpShape, OperatorShape, Layout>;
|
| 85 |
+
|
| 86 |
+
/// Shape of the tile in memory
|
| 87 |
+
using Shape = MatrixShape<
|
| 88 |
+
Policy::kRowsPerIteration,
|
| 89 |
+
WarpShape::kN
|
| 90 |
+
>;
|
| 91 |
+
|
| 92 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 93 |
+
using Fragment = Array<
|
| 94 |
+
Element,
|
| 95 |
+
Policy::OperatorCount::kColumn * Policy::kElementsPerAccess>;
|
| 96 |
+
|
| 97 |
+
/// This is the complete warp-level accumulator tile.
|
| 98 |
+
//using AccumulatorTile = typename Operator::FragmentC;
|
| 99 |
+
|
| 100 |
+
/// Number of times this iterator can be incremented
|
| 101 |
+
static int const kIterations = Policy::kIterations;
|
| 102 |
+
|
| 103 |
+
// Internal constants
|
| 104 |
+
struct Detail {
|
| 105 |
+
static int const kLanesInQuad = 4;
|
| 106 |
+
|
| 107 |
+
/// Number of pointers needed to write accumulators
|
| 108 |
+
static int const kPointerCount =
|
| 109 |
+
(OutputElementCount * sizeof_bits<Element>::value) / (const_min(128, OutputElementCount * sizeof_bits<Element>::value));
|
| 110 |
+
|
| 111 |
+
// Currently support max 4 ptr
|
| 112 |
+
static constexpr int kMaxPointerCount{4};
|
| 113 |
+
|
| 114 |
+
static_assert(kPointerCount <= kMaxPointerCount, "Can only accommodate four pointers at present.");
|
| 115 |
+
static_assert(sizeof(Element) == 4, "This can only be used with 32b accumulator data types (f32, s32).");
|
| 116 |
+
};
|
| 117 |
+
|
| 118 |
+
/// Padding quantity
|
| 119 |
+
using Padding = MatrixShape<
|
| 120 |
+
0,
|
| 121 |
+
Detail::kLanesInQuad * Policy::kElementsPerAccess>;
|
| 122 |
+
|
| 123 |
+
private:
|
| 124 |
+
|
| 125 |
+
/// Storage type for accessing memory
|
| 126 |
+
using AccessType = AlignedArray<Element, Policy::kElementsPerAccess>;
|
| 127 |
+
|
| 128 |
+
//
|
| 129 |
+
// Data members
|
| 130 |
+
//
|
| 131 |
+
|
| 132 |
+
/// Internal pointer to memory
|
| 133 |
+
AccessType *pointers_[Detail::kPointerCount] = {nullptr};
|
| 134 |
+
|
| 135 |
+
/// Stride in units of AccessType
|
| 136 |
+
int stride_{0};
|
| 137 |
+
|
| 138 |
+
/// Logical column in which warp tile is aligned
|
| 139 |
+
int warp_column_{0};
|
| 140 |
+
|
| 141 |
+
public:
|
| 142 |
+
|
| 143 |
+
/// Default constructor
|
| 144 |
+
TileIteratorTensorOpMixed() = default;
|
| 145 |
+
|
| 146 |
+
/// Constructor from TensorRef
|
| 147 |
+
CUTLASS_HOST_DEVICE
|
| 148 |
+
TileIteratorTensorOpMixed(
|
| 149 |
+
TensorRef const &ref,
|
| 150 |
+
unsigned lane_id
|
| 151 |
+
):
|
| 152 |
+
stride_(ref.stride()[0] / Policy::kElementsPerAccess),
|
| 153 |
+
warp_column_(0) {
|
| 154 |
+
|
| 155 |
+
int quad_id = (lane_id / Detail::kLanesInQuad);
|
| 156 |
+
int lane_in_quad = (lane_id % Detail::kLanesInQuad);
|
| 157 |
+
|
| 158 |
+
CUTLASS_PRAGMA_UNROLL
|
| 159 |
+
for (int64_t i = 0; i < Detail::kPointerCount; ++i) {
|
| 160 |
+
AccessType *ptr = reinterpret_cast<AccessType *>(ref.data()) + quad_id * stride_;
|
| 161 |
+
int column_idx = (lane_in_quad % 2) + (((lane_in_quad / 2) + i) % Detail::kPointerCount) * 2;
|
| 162 |
+
|
| 163 |
+
ptr += column_idx;
|
| 164 |
+
|
| 165 |
+
pointers_[i % Detail::kPointerCount] = ptr;
|
| 166 |
+
}
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
/// Adds a pointer offset
|
| 170 |
+
CUTLASS_HOST_DEVICE
|
| 171 |
+
TileIteratorTensorOpMixed & add_pointer_offset(Index pointer_offset) {
|
| 172 |
+
|
| 173 |
+
CUTLASS_PRAGMA_UNROLL
|
| 174 |
+
for (int64_t i = 0; i < Detail::kPointerCount; ++i) {
|
| 175 |
+
pointers_[i] += pointer_offset / Policy::kElementsPerAccess;
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
return *this;
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 182 |
+
CUTLASS_HOST_DEVICE
|
| 183 |
+
TileIteratorTensorOpMixed & add_tile_offset(TensorCoord const &tile_offset) {
|
| 184 |
+
|
| 185 |
+
CUTLASS_PRAGMA_UNROLL
|
| 186 |
+
for (int64_t i = 0; i < Detail::kPointerCount; ++i) {
|
| 187 |
+
pointers_[i] += tile_offset.row() * Shape::kRow * stride_ +
|
| 188 |
+
tile_offset.column() * Shape::kColumn / Policy::kElementsPerAccess;
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
warp_column_ += tile_offset.column() * Shape::kColumn;
|
| 192 |
+
|
| 193 |
+
return *this;
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 197 |
+
CUTLASS_HOST_DEVICE
|
| 198 |
+
TileIteratorTensorOpMixed & operator+=(TensorCoord const &tile_offset) {
|
| 199 |
+
return add_tile_offset(tile_offset);
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
/// Store
|
| 203 |
+
CUTLASS_DEVICE
|
| 204 |
+
void store_with_pointer_offset(Fragment const &frag, Index pointer_offset) {
|
| 205 |
+
|
| 206 |
+
AccessType const *frag_ptr = reinterpret_cast<AccessType const *>(&frag);
|
| 207 |
+
|
| 208 |
+
AccessType *ptr = pointers_[0];
|
| 209 |
+
|
| 210 |
+
#if CUTLASS_EPILOGUE_WARP_TILE_ITERATOR_TENSOR_OP_MIXED_OPTIMIZATION_ENABLED
|
| 211 |
+
|
| 212 |
+
// When the optimization is enabled, small tiles require separate logic.
|
| 213 |
+
bool kN32_optimization = (WarpShape::kN * Detail::kLanesInQuad * Policy::kElementsPerAccess * sizeof_bits<Element>::value) % 1024 == 0;
|
| 214 |
+
if (kN32_optimization) {
|
| 215 |
+
|
| 216 |
+
int ptr_idx = ((warp_column_ * sizeof_bits<Element>::value) / 1024) % Detail::kPointerCount;
|
| 217 |
+
|
| 218 |
+
if (ptr_idx == 0) {
|
| 219 |
+
ptr = pointers_[0];
|
| 220 |
+
} else if (ptr_idx == 1) {
|
| 221 |
+
if constexpr (AccessType::kElements >= 2) {
|
| 222 |
+
ptr = pointers_[1];
|
| 223 |
+
}
|
| 224 |
+
} else if (ptr_idx == 2) {
|
| 225 |
+
if constexpr (AccessType::kElements >= 3) {
|
| 226 |
+
ptr = pointers_[2];
|
| 227 |
+
}
|
| 228 |
+
} else if (ptr_idx == 3) {
|
| 229 |
+
if constexpr (AccessType::kElements >= 4) {
|
| 230 |
+
ptr = pointers_[3];
|
| 231 |
+
}
|
| 232 |
+
}
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
#endif
|
| 236 |
+
|
| 237 |
+
CUTLASS_PRAGMA_UNROLL
|
| 238 |
+
for (int64_t n = 0; n < Policy::OperatorCount::kColumn; ++n) {
|
| 239 |
+
|
| 240 |
+
#if CUTLASS_EPILOGUE_WARP_TILE_ITERATOR_TENSOR_OP_MIXED_OPTIMIZATION_ENABLED
|
| 241 |
+
|
| 242 |
+
//
|
| 243 |
+
// When the optimization is enabled, this expression suffices to obtain the SMEM pointer.
|
| 244 |
+
//
|
| 245 |
+
if (WarpShape::kN == 64) {
|
| 246 |
+
ptr = pointers_[n / 4];
|
| 247 |
+
}
|
| 248 |
+
else if (!kN32_optimization)
|
| 249 |
+
#endif
|
| 250 |
+
{
|
| 251 |
+
// This is the reference implementation
|
| 252 |
+
int column_idx = warp_column_ + n * Detail::kLanesInQuad * Policy::kElementsPerAccess;
|
| 253 |
+
int ptr_idx = ((column_idx * sizeof_bits<Element>::value) / 1024) % Detail::kPointerCount;
|
| 254 |
+
|
| 255 |
+
if (ptr_idx == 0) {
|
| 256 |
+
ptr = pointers_[0 % Detail::kPointerCount];
|
| 257 |
+
}
|
| 258 |
+
else if (ptr_idx == 1) {
|
| 259 |
+
ptr = pointers_[1 % Detail::kPointerCount];
|
| 260 |
+
}
|
| 261 |
+
else if (ptr_idx == 2) {
|
| 262 |
+
ptr = pointers_[2 % Detail::kPointerCount];
|
| 263 |
+
}
|
| 264 |
+
else if (ptr_idx == 3) {
|
| 265 |
+
ptr = pointers_[3 % Detail::kPointerCount];
|
| 266 |
+
}
|
| 267 |
+
}
|
| 268 |
+
|
| 269 |
+
int offset = n * Detail::kLanesInQuad + pointer_offset / Policy::kElementsPerAccess;
|
| 270 |
+
ptr[offset] = frag_ptr[n];
|
| 271 |
+
}
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
/// Store
|
| 275 |
+
CUTLASS_HOST_DEVICE
|
| 276 |
+
void store(Fragment const &frag) {
|
| 277 |
+
store_with_pointer_offset(frag, 0);
|
| 278 |
+
}
|
| 279 |
+
|
| 280 |
+
/// Load
|
| 281 |
+
CUTLASS_HOST_DEVICE
|
| 282 |
+
void load_with_pointer_offset(Fragment &frag, Index pointer_offset) const {
|
| 283 |
+
|
| 284 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 285 |
+
|
| 286 |
+
CUTLASS_PRAGMA_UNROLL
|
| 287 |
+
for (int64_t n = 0; n < Policy::OperatorCount::kColumn; ++n) {
|
| 288 |
+
|
| 289 |
+
int column_idx = warp_column_ + n * Detail::kLanesInQuad * Policy::kElementsPerAccess;
|
| 290 |
+
int ptr_idx = ((column_idx * sizeof_bits<Element>::value) / 1024) % Detail::kPointerCount;
|
| 291 |
+
|
| 292 |
+
AccessType const *smem_ptr = pointers_[ptr_idx];
|
| 293 |
+
frag_ptr[n] = smem_ptr[n * Detail::kLanesInQuad + pointer_offset / Policy::kElementsPerAccess];
|
| 294 |
+
}
|
| 295 |
+
}
|
| 296 |
+
|
| 297 |
+
/// Load
|
| 298 |
+
CUTLASS_HOST_DEVICE
|
| 299 |
+
void load(Fragment &frag) const {
|
| 300 |
+
load_with_pointer_offset(frag, 0);
|
| 301 |
+
}
|
| 302 |
+
|
| 303 |
+
/// Set smem base address
|
| 304 |
+
CUTLASS_HOST_DEVICE
|
| 305 |
+
void set_smem_base_address(Index address) {
|
| 306 |
+
}
|
| 307 |
+
};
|
| 308 |
+
|
| 309 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 310 |
+
|
| 311 |
+
/// Partial specialization for int32_t x 16 => int8_t/int4b_t x 16
|
| 312 |
+
template <
|
| 313 |
+
typename WarpShape_, ///< shape of warp-level GEMM (concept: GemmShape)
|
| 314 |
+
typename OperatorShape_, ///< matrix multiply operation shape (concept: gemm::GemmShape),
|
| 315 |
+
int OutputSizeBits ///< Size of output element in bits
|
| 316 |
+
>
|
| 317 |
+
class TileIteratorTensorOpMixed<WarpShape_, OperatorShape_, int32_t, 32, OutputSizeBits, 16, 8, true> {
|
| 318 |
+
public:
|
| 319 |
+
|
| 320 |
+
using WarpShape = WarpShape_;
|
| 321 |
+
using OperatorShape = OperatorShape_;
|
| 322 |
+
using Element = int32_t;
|
| 323 |
+
using Layout = layout::RowMajor;
|
| 324 |
+
static int const kOutputElementCount = 16;
|
| 325 |
+
|
| 326 |
+
using TensorRef = TensorRef<Element, Layout>; ///< Tensor Reference object
|
| 327 |
+
using TensorCoord = MatrixCoord; ///< Logical coordinate in referenced tensor
|
| 328 |
+
using Index = typename TensorRef::Index;
|
| 329 |
+
using LongIndex = typename TensorRef::LongIndex;
|
| 330 |
+
|
| 331 |
+
using Policy = TensorOpPolicy<WarpShape, OperatorShape, Layout>;
|
| 332 |
+
|
| 333 |
+
/// Shape of the tile in memory
|
| 334 |
+
using Shape = MatrixShape<
|
| 335 |
+
Policy::kRowsPerIteration,
|
| 336 |
+
WarpShape::kN
|
| 337 |
+
>;
|
| 338 |
+
|
| 339 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 340 |
+
using Fragment = Array<
|
| 341 |
+
Element,
|
| 342 |
+
Policy::OperatorCount::kColumn * Policy::kElementsPerAccess>;
|
| 343 |
+
|
| 344 |
+
/// This is the complete warp-level accumulator tile.
|
| 345 |
+
//using AccumulatorTile = typename Operator::FragmentC;
|
| 346 |
+
|
| 347 |
+
/// Number of times this iterator can be incremented
|
| 348 |
+
static int const kIterations = Policy::kIterations;
|
| 349 |
+
|
| 350 |
+
// Internal constants
|
| 351 |
+
struct Detail {
|
| 352 |
+
static int const kLanesInQuad = 4;
|
| 353 |
+
|
| 354 |
+
/// Number of pointers needed to write accumulators
|
| 355 |
+
static int const kPointerCount = 2;
|
| 356 |
+
|
| 357 |
+
/// Offsets added
|
| 358 |
+
static int const kOffsetCount = 4;
|
| 359 |
+
|
| 360 |
+
static_assert(sizeof(Element) == 4, "This can only be used with 32b accumulator data types (f32, s32).");
|
| 361 |
+
};
|
| 362 |
+
|
| 363 |
+
/// Padding quantity
|
| 364 |
+
using Padding = MatrixShape<0, Detail::kLanesInQuad * 2>;
|
| 365 |
+
|
| 366 |
+
private:
|
| 367 |
+
|
| 368 |
+
/// Storage type for accessing memory
|
| 369 |
+
using AccessType = AlignedArray<Element, 2>;
|
| 370 |
+
|
| 371 |
+
//
|
| 372 |
+
// Data members
|
| 373 |
+
//
|
| 374 |
+
|
| 375 |
+
/// Internal pointer to memory
|
| 376 |
+
AccessType *pointers_[Detail::kPointerCount] = {nullptr};
|
| 377 |
+
|
| 378 |
+
/// Stride in units of AccessType
|
| 379 |
+
int stride_{0};
|
| 380 |
+
|
| 381 |
+
/// Uniform offset in bytes added to warp tile iterator
|
| 382 |
+
int uniform_offset_[Detail::kOffsetCount] = {0};
|
| 383 |
+
|
| 384 |
+
public:
|
| 385 |
+
|
| 386 |
+
/// Default constructor
|
| 387 |
+
TileIteratorTensorOpMixed() = default;
|
| 388 |
+
|
| 389 |
+
/// Constructor from TensorRef
|
| 390 |
+
CUTLASS_HOST_DEVICE
|
| 391 |
+
TileIteratorTensorOpMixed(
|
| 392 |
+
TensorRef const &ref,
|
| 393 |
+
unsigned lane_id
|
| 394 |
+
):
|
| 395 |
+
stride_(ref.stride()[0] / AccessType::kElements) {
|
| 396 |
+
|
| 397 |
+
int quad_id = (lane_id / Detail::kLanesInQuad);
|
| 398 |
+
int lane_in_quad = (lane_id % Detail::kLanesInQuad);
|
| 399 |
+
|
| 400 |
+
CUTLASS_PRAGMA_UNROLL
|
| 401 |
+
for (int i = 0; i < Detail::kPointerCount; ++i) {
|
| 402 |
+
AccessType *ptr = reinterpret_cast<AccessType *>(ref.data()) + quad_id * stride_;
|
| 403 |
+
int column_idx = lane_in_quad ^ (i * 2);
|
| 404 |
+
|
| 405 |
+
ptr += column_idx;
|
| 406 |
+
|
| 407 |
+
if (i == 0) {
|
| 408 |
+
pointers_[0] = ptr;
|
| 409 |
+
}
|
| 410 |
+
else if (i == 1) {
|
| 411 |
+
pointers_[1] = ptr;
|
| 412 |
+
}
|
| 413 |
+
}
|
| 414 |
+
|
| 415 |
+
CUTLASS_PRAGMA_UNROLL
|
| 416 |
+
for (int i = 0; i < Detail::kOffsetCount; ++i) {
|
| 417 |
+
uniform_offset_[i] = (i ^ 0) * 4 * sizeof(AccessType);
|
| 418 |
+
}
|
| 419 |
+
}
|
| 420 |
+
|
| 421 |
+
/// Adds a pointer offset
|
| 422 |
+
CUTLASS_HOST_DEVICE
|
| 423 |
+
TileIteratorTensorOpMixed & add_pointer_offset(Index pointer_offset) {
|
| 424 |
+
|
| 425 |
+
CUTLASS_PRAGMA_UNROLL
|
| 426 |
+
for (int64_t i = 0; i < Detail::kPointerCount; ++i) {
|
| 427 |
+
pointers_[i] += pointer_offset / AccessType::kElements;
|
| 428 |
+
}
|
| 429 |
+
|
| 430 |
+
return *this;
|
| 431 |
+
}
|
| 432 |
+
|
| 433 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 434 |
+
CUTLASS_HOST_DEVICE
|
| 435 |
+
TileIteratorTensorOpMixed & add_tile_offset(TensorCoord const &tile_offset) {
|
| 436 |
+
|
| 437 |
+
int ptr_offset = tile_offset.row() * Shape::kRow * stride_ +
|
| 438 |
+
tile_offset.column() * Shape::kColumn / AccessType::kElements;
|
| 439 |
+
|
| 440 |
+
pointers_[0] += ptr_offset;
|
| 441 |
+
pointers_[1] += ptr_offset;
|
| 442 |
+
|
| 443 |
+
CUTLASS_PRAGMA_UNROLL
|
| 444 |
+
for (int i = 0; i < Detail::kOffsetCount; ++i) {
|
| 445 |
+
uniform_offset_[i] = (i ^ tile_offset.column()) * 4 * sizeof(AccessType);
|
| 446 |
+
}
|
| 447 |
+
|
| 448 |
+
return *this;
|
| 449 |
+
}
|
| 450 |
+
|
| 451 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 452 |
+
CUTLASS_HOST_DEVICE
|
| 453 |
+
TileIteratorTensorOpMixed & operator+=(TensorCoord const &tile_offset) {
|
| 454 |
+
return add_tile_offset(tile_offset);
|
| 455 |
+
}
|
| 456 |
+
|
| 457 |
+
/// Store
|
| 458 |
+
CUTLASS_DEVICE
|
| 459 |
+
void store_with_pointer_offset(Fragment const &frag, Index pointer_offset) {
|
| 460 |
+
|
| 461 |
+
AccessType const *frag_ptr = reinterpret_cast<AccessType const *>(&frag);
|
| 462 |
+
|
| 463 |
+
CUTLASS_PRAGMA_UNROLL
|
| 464 |
+
for (int n = 0; n < Policy::OperatorCount::kColumn; ++n) {
|
| 465 |
+
|
| 466 |
+
int ptr_idx = (n / 4);
|
| 467 |
+
int offset_idx = (n % 4);
|
| 468 |
+
|
| 469 |
+
AccessType *ptr;
|
| 470 |
+
if (ptr_idx == 0) {
|
| 471 |
+
ptr = pointers_[0];
|
| 472 |
+
}
|
| 473 |
+
else if (ptr_idx == 1) {
|
| 474 |
+
ptr = pointers_[1];
|
| 475 |
+
}
|
| 476 |
+
|
| 477 |
+
int offset = (n / 4) * 16 + pointer_offset / AccessType::kElements;
|
| 478 |
+
|
| 479 |
+
#if 0
|
| 480 |
+
//
|
| 481 |
+
// Using inline PTX to avoid generic memory
|
| 482 |
+
//
|
| 483 |
+
AccessType *smem_ptr = pointers_[ptr_idx];
|
| 484 |
+
smem_ptr[offset] = frag_ptr[n];
|
| 485 |
+
#else
|
| 486 |
+
uint32_t smem_addr = arch::cutlass_get_smem_pointer(ptr);
|
| 487 |
+
uint32_t const *data = reinterpret_cast<uint32_t const *>(frag_ptr + n);
|
| 488 |
+
uint32_t offset_in_bytes = offset * sizeof(AccessType) + uniform_offset_[offset_idx];
|
| 489 |
+
|
| 490 |
+
asm volatile(
|
| 491 |
+
"{ .reg .u32 smem_ptr; add.u32 smem_ptr, %0, %1; st.shared.v2.u32 [smem_ptr], {%2, %3}; }\n"
|
| 492 |
+
: : "r"(smem_addr), "r"(offset_in_bytes), "r"(data[0]), "r"(data[1])
|
| 493 |
+
);
|
| 494 |
+
#endif
|
| 495 |
+
}
|
| 496 |
+
}
|
| 497 |
+
|
| 498 |
+
/// Store
|
| 499 |
+
CUTLASS_HOST_DEVICE
|
| 500 |
+
void store(Fragment const &frag) {
|
| 501 |
+
store_with_pointer_offset(frag, 0);
|
| 502 |
+
}
|
| 503 |
+
|
| 504 |
+
/// Set smem base address
|
| 505 |
+
CUTLASS_HOST_DEVICE
|
| 506 |
+
void set_smem_base_address(Index address) {
|
| 507 |
+
}
|
| 508 |
+
};
|
| 509 |
+
|
| 510 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 511 |
+
|
| 512 |
+
/// Partial specialization for int32_t x 8 => int8_t/int4b_t x 8
|
| 513 |
+
template <
|
| 514 |
+
typename WarpShape_, ///< shape of warp-level GEMM (concept: GemmShape)
|
| 515 |
+
typename OperatorShape_, ///< matrix multiply operation shape (concept: gemm::GemmShape)
|
| 516 |
+
int OutputSizeBits ///< Size of output element in bits
|
| 517 |
+
>
|
| 518 |
+
class TileIteratorTensorOpMixed<WarpShape_, OperatorShape_, int32_t, 32, OutputSizeBits, 8, 8, true> {
|
| 519 |
+
public:
|
| 520 |
+
|
| 521 |
+
using WarpShape = WarpShape_;
|
| 522 |
+
using OperatorShape = OperatorShape_;
|
| 523 |
+
using Element = int32_t;
|
| 524 |
+
using Layout = layout::RowMajor;
|
| 525 |
+
static int const kOutputElementCount = 8;
|
| 526 |
+
|
| 527 |
+
using TensorRef = TensorRef<Element, Layout>; ///< Tensor Reference object
|
| 528 |
+
using TensorCoord = MatrixCoord; ///< Logical coordinate in referenced tensor
|
| 529 |
+
using Index = typename TensorRef::Index;
|
| 530 |
+
using LongIndex = typename TensorRef::LongIndex;
|
| 531 |
+
|
| 532 |
+
using Policy = TensorOpPolicy<WarpShape, OperatorShape, Layout>;
|
| 533 |
+
|
| 534 |
+
/// Shape of the tile in memory
|
| 535 |
+
using Shape = MatrixShape<
|
| 536 |
+
Policy::kRowsPerIteration,
|
| 537 |
+
WarpShape::kN
|
| 538 |
+
>;
|
| 539 |
+
|
| 540 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 541 |
+
using Fragment = Array<
|
| 542 |
+
Element,
|
| 543 |
+
Policy::OperatorCount::kColumn * Policy::kElementsPerAccess>;
|
| 544 |
+
|
| 545 |
+
/// This is the complete warp-level accumulator tile.
|
| 546 |
+
//using AccumulatorTile = typename Operator::FragmentC;
|
| 547 |
+
|
| 548 |
+
/// Number of times this iterator can be incremented
|
| 549 |
+
static int const kIterations = Policy::kIterations;
|
| 550 |
+
|
| 551 |
+
// Internal constants
|
| 552 |
+
struct Detail {
|
| 553 |
+
static int const kLanesInQuad = 4;
|
| 554 |
+
|
| 555 |
+
/// Number of pointers needed to write accumulators
|
| 556 |
+
static int const kPointerCount = 2;
|
| 557 |
+
|
| 558 |
+
static_assert(sizeof(Element) == 4, "This can only be used with 32b accumulator data types (f32, s32).");
|
| 559 |
+
};
|
| 560 |
+
|
| 561 |
+
/// Padding quantity
|
| 562 |
+
using Padding = MatrixShape<0, Detail::kLanesInQuad * 2>;
|
| 563 |
+
|
| 564 |
+
private:
|
| 565 |
+
|
| 566 |
+
/// Storage type for accessing memory
|
| 567 |
+
using AccessType = AlignedArray<Element, 2>;
|
| 568 |
+
|
| 569 |
+
//
|
| 570 |
+
// Data members
|
| 571 |
+
//
|
| 572 |
+
|
| 573 |
+
/// Internal pointer to memory
|
| 574 |
+
AccessType *pointers_[Detail::kPointerCount] = {nullptr};
|
| 575 |
+
|
| 576 |
+
/// Stride in units of AccessType
|
| 577 |
+
int stride_{0};
|
| 578 |
+
|
| 579 |
+
public:
|
| 580 |
+
|
| 581 |
+
/// Default constructor
|
| 582 |
+
TileIteratorTensorOpMixed() = default;
|
| 583 |
+
|
| 584 |
+
/// Constructor from TensorRef
|
| 585 |
+
CUTLASS_HOST_DEVICE
|
| 586 |
+
TileIteratorTensorOpMixed(
|
| 587 |
+
TensorRef const &ref,
|
| 588 |
+
unsigned lane_id
|
| 589 |
+
):
|
| 590 |
+
stride_(ref.stride()[0] / AccessType::kElements) {
|
| 591 |
+
|
| 592 |
+
int quad_id = (lane_id / Detail::kLanesInQuad);
|
| 593 |
+
int lane_in_quad = (lane_id % Detail::kLanesInQuad);
|
| 594 |
+
|
| 595 |
+
CUTLASS_PRAGMA_UNROLL
|
| 596 |
+
for (int i = 0; i < Detail::kPointerCount; ++i) {
|
| 597 |
+
AccessType *ptr = reinterpret_cast<AccessType *>(ref.data()) + quad_id * stride_;
|
| 598 |
+
int column_idx = lane_in_quad ^ (i * 2);
|
| 599 |
+
|
| 600 |
+
ptr += column_idx;
|
| 601 |
+
|
| 602 |
+
if (i == 0) {
|
| 603 |
+
pointers_[0] = ptr;
|
| 604 |
+
}
|
| 605 |
+
else if (i == 1) {
|
| 606 |
+
pointers_[1] = ptr;
|
| 607 |
+
}
|
| 608 |
+
}
|
| 609 |
+
}
|
| 610 |
+
|
| 611 |
+
/// Adds a pointer offset
|
| 612 |
+
CUTLASS_HOST_DEVICE
|
| 613 |
+
TileIteratorTensorOpMixed & add_pointer_offset(Index pointer_offset) {
|
| 614 |
+
|
| 615 |
+
CUTLASS_PRAGMA_UNROLL
|
| 616 |
+
for (int64_t i = 0; i < Detail::kPointerCount; ++i) {
|
| 617 |
+
pointers_[i] += pointer_offset / AccessType::kElements;
|
| 618 |
+
}
|
| 619 |
+
|
| 620 |
+
return *this;
|
| 621 |
+
}
|
| 622 |
+
|
| 623 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 624 |
+
CUTLASS_HOST_DEVICE
|
| 625 |
+
TileIteratorTensorOpMixed & add_tile_offset(TensorCoord const &tile_offset) {
|
| 626 |
+
|
| 627 |
+
int ptr_offset = tile_offset.row() * Shape::kRow * stride_ +
|
| 628 |
+
tile_offset.column() * Shape::kColumn / AccessType::kElements;
|
| 629 |
+
|
| 630 |
+
pointers_[0] += ptr_offset;
|
| 631 |
+
pointers_[1] += ptr_offset;
|
| 632 |
+
|
| 633 |
+
if (tile_offset.column() % 2) {
|
| 634 |
+
auto tmp = pointers_[0];
|
| 635 |
+
pointers_[0] = pointers_[1];
|
| 636 |
+
pointers_[1] = tmp;
|
| 637 |
+
}
|
| 638 |
+
|
| 639 |
+
return *this;
|
| 640 |
+
}
|
| 641 |
+
|
| 642 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 643 |
+
CUTLASS_HOST_DEVICE
|
| 644 |
+
TileIteratorTensorOpMixed & operator+=(TensorCoord const &tile_offset) {
|
| 645 |
+
return add_tile_offset(tile_offset);
|
| 646 |
+
}
|
| 647 |
+
|
| 648 |
+
/// Store
|
| 649 |
+
CUTLASS_DEVICE
|
| 650 |
+
void store_with_pointer_offset(Fragment const &frag, Index pointer_offset) {
|
| 651 |
+
|
| 652 |
+
AccessType const *frag_ptr = reinterpret_cast<AccessType const *>(&frag);
|
| 653 |
+
|
| 654 |
+
CUTLASS_PRAGMA_UNROLL
|
| 655 |
+
for (int n = 0; n < Policy::OperatorCount::kColumn; ++n) {
|
| 656 |
+
|
| 657 |
+
int ptr_idx = (n / 4);
|
| 658 |
+
|
| 659 |
+
AccessType *ptr;
|
| 660 |
+
if (ptr_idx == 0) {
|
| 661 |
+
ptr = pointers_[0];
|
| 662 |
+
}
|
| 663 |
+
else if (ptr_idx == 1) {
|
| 664 |
+
ptr = pointers_[1];
|
| 665 |
+
}
|
| 666 |
+
|
| 667 |
+
int offset = (n / 4) * 16 + pointer_offset / AccessType::kElements + (n % 4) * 4;
|
| 668 |
+
|
| 669 |
+
#if 0
|
| 670 |
+
//
|
| 671 |
+
// Using inline PTX to avoid generic memory
|
| 672 |
+
//
|
| 673 |
+
AccessType *smem_ptr = pointers_[ptr_idx];
|
| 674 |
+
smem_ptr[offset] = frag_ptr[n];
|
| 675 |
+
#else
|
| 676 |
+
uint32_t smem_addr = arch::cutlass_get_smem_pointer(ptr);
|
| 677 |
+
uint32_t const *data = reinterpret_cast<uint32_t const *>(frag_ptr + n);
|
| 678 |
+
uint32_t offset_in_bytes = offset * sizeof(AccessType);
|
| 679 |
+
|
| 680 |
+
asm volatile(
|
| 681 |
+
"{ .reg .u32 smem_ptr; add.u32 smem_ptr, %0, %1; st.shared.v2.u32 [smem_ptr], {%2, %3}; }\n"
|
| 682 |
+
: : "r"(smem_addr), "r"(offset_in_bytes), "r"(data[0]), "r"(data[1])
|
| 683 |
+
);
|
| 684 |
+
#endif
|
| 685 |
+
}
|
| 686 |
+
}
|
| 687 |
+
|
| 688 |
+
/// Store
|
| 689 |
+
CUTLASS_HOST_DEVICE
|
| 690 |
+
void store(Fragment const &frag) {
|
| 691 |
+
store_with_pointer_offset(frag, 0);
|
| 692 |
+
}
|
| 693 |
+
|
| 694 |
+
/// Set smem base address
|
| 695 |
+
CUTLASS_HOST_DEVICE
|
| 696 |
+
void set_smem_base_address(Index address) {
|
| 697 |
+
}
|
| 698 |
+
};
|
| 699 |
+
|
| 700 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 701 |
+
|
| 702 |
+
/// Partial specialization for float x 16 => float_e4m3_t/float_e5m2_t x 16
|
| 703 |
+
template <
|
| 704 |
+
typename WarpShape_, ///< shape of warp-level GEMM (concept: GemmShape)
|
| 705 |
+
typename OperatorShape_ ///< matrix multiply operation shape (concept: gemm::GemmShape),
|
| 706 |
+
>
|
| 707 |
+
class TileIteratorTensorOpMixed<WarpShape_, OperatorShape_, float, 32, 8, 16, 8> {
|
| 708 |
+
public:
|
| 709 |
+
|
| 710 |
+
using WarpShape = WarpShape_;
|
| 711 |
+
using OperatorShape = OperatorShape_;
|
| 712 |
+
using Element = float;
|
| 713 |
+
using Layout = layout::RowMajor;
|
| 714 |
+
static int const kOutputElementCount = 16;
|
| 715 |
+
|
| 716 |
+
using TensorRef = TensorRef<Element, Layout>; ///< Tensor Reference object
|
| 717 |
+
using TensorCoord = MatrixCoord; ///< Logical coordinate in referenced tensor
|
| 718 |
+
using Index = typename TensorRef::Index;
|
| 719 |
+
using LongIndex = typename TensorRef::LongIndex;
|
| 720 |
+
|
| 721 |
+
using Policy = TensorOpPolicy<WarpShape, OperatorShape, Layout>;
|
| 722 |
+
|
| 723 |
+
/// Shape of the tile in memory
|
| 724 |
+
using Shape = MatrixShape<
|
| 725 |
+
Policy::kRowsPerIteration,
|
| 726 |
+
WarpShape::kN
|
| 727 |
+
>;
|
| 728 |
+
|
| 729 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 730 |
+
using Fragment = Array<
|
| 731 |
+
Element,
|
| 732 |
+
Policy::OperatorCount::kColumn * Policy::kElementsPerAccess>;
|
| 733 |
+
|
| 734 |
+
/// This is the complete warp-level accumulator tile.
|
| 735 |
+
//using AccumulatorTile = typename Operator::FragmentC;
|
| 736 |
+
|
| 737 |
+
/// Number of times this iterator can be incremented
|
| 738 |
+
static int const kIterations = Policy::kIterations;
|
| 739 |
+
|
| 740 |
+
// Internal constants
|
| 741 |
+
struct Detail {
|
| 742 |
+
static int const kLanesInQuad = 4;
|
| 743 |
+
|
| 744 |
+
/// Number of pointers needed to write accumulators
|
| 745 |
+
static int const kPointerCount = 2;
|
| 746 |
+
|
| 747 |
+
/// Offsets added
|
| 748 |
+
static int const kOffsetCount = 4;
|
| 749 |
+
|
| 750 |
+
static_assert(sizeof(Element) == 4, "This can only be used with 32b accumulator data types (f32, s32).");
|
| 751 |
+
};
|
| 752 |
+
|
| 753 |
+
/// Padding quantity
|
| 754 |
+
using Padding = MatrixShape<0, Detail::kLanesInQuad * 2>;
|
| 755 |
+
|
| 756 |
+
private:
|
| 757 |
+
|
| 758 |
+
/// Storage type for accessing memory
|
| 759 |
+
using AccessType = AlignedArray<Element, 2>;
|
| 760 |
+
|
| 761 |
+
//
|
| 762 |
+
// Data members
|
| 763 |
+
//
|
| 764 |
+
|
| 765 |
+
/// Internal pointer to memory
|
| 766 |
+
AccessType *pointers_[Detail::kPointerCount] = {nullptr};
|
| 767 |
+
|
| 768 |
+
/// Stride in units of AccessType
|
| 769 |
+
int stride_{0};
|
| 770 |
+
|
| 771 |
+
/// Uniform offset in bytes added to warp tile iterator
|
| 772 |
+
int uniform_offset_[Detail::kOffsetCount] = {0};
|
| 773 |
+
|
| 774 |
+
public:
|
| 775 |
+
|
| 776 |
+
/// Default constructor
|
| 777 |
+
TileIteratorTensorOpMixed() = default;
|
| 778 |
+
|
| 779 |
+
/// Constructor from TensorRef
|
| 780 |
+
CUTLASS_HOST_DEVICE
|
| 781 |
+
TileIteratorTensorOpMixed(
|
| 782 |
+
TensorRef const &ref,
|
| 783 |
+
unsigned lane_id
|
| 784 |
+
):
|
| 785 |
+
stride_(ref.stride()[0] / AccessType::kElements) {
|
| 786 |
+
|
| 787 |
+
int quad_id = (lane_id / Detail::kLanesInQuad);
|
| 788 |
+
int lane_in_quad = (lane_id % Detail::kLanesInQuad);
|
| 789 |
+
|
| 790 |
+
CUTLASS_PRAGMA_UNROLL
|
| 791 |
+
for (int i = 0; i < Detail::kPointerCount; ++i) {
|
| 792 |
+
AccessType *ptr = reinterpret_cast<AccessType *>(ref.data()) + quad_id * stride_;
|
| 793 |
+
int column_idx = lane_in_quad ^ (i * 2);
|
| 794 |
+
|
| 795 |
+
ptr += column_idx;
|
| 796 |
+
|
| 797 |
+
if (i == 0) {
|
| 798 |
+
pointers_[0] = ptr;
|
| 799 |
+
}
|
| 800 |
+
else if (i == 1) {
|
| 801 |
+
pointers_[1] = ptr;
|
| 802 |
+
}
|
| 803 |
+
}
|
| 804 |
+
|
| 805 |
+
CUTLASS_PRAGMA_UNROLL
|
| 806 |
+
for (int i = 0; i < Detail::kOffsetCount; ++i) {
|
| 807 |
+
uniform_offset_[i] = (i ^ 0) * 4 * sizeof(AccessType);
|
| 808 |
+
}
|
| 809 |
+
}
|
| 810 |
+
|
| 811 |
+
/// Adds a pointer offset
|
| 812 |
+
CUTLASS_HOST_DEVICE
|
| 813 |
+
TileIteratorTensorOpMixed & add_pointer_offset(Index pointer_offset) {
|
| 814 |
+
|
| 815 |
+
CUTLASS_PRAGMA_UNROLL
|
| 816 |
+
for (int64_t i = 0; i < Detail::kPointerCount; ++i) {
|
| 817 |
+
pointers_[i] += pointer_offset / AccessType::kElements;
|
| 818 |
+
}
|
| 819 |
+
|
| 820 |
+
return *this;
|
| 821 |
+
}
|
| 822 |
+
|
| 823 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 824 |
+
CUTLASS_HOST_DEVICE
|
| 825 |
+
TileIteratorTensorOpMixed & add_tile_offset(TensorCoord const &tile_offset) {
|
| 826 |
+
|
| 827 |
+
int ptr_offset = tile_offset.row() * Shape::kRow * stride_ +
|
| 828 |
+
tile_offset.column() * Shape::kColumn / AccessType::kElements;
|
| 829 |
+
|
| 830 |
+
pointers_[0] += ptr_offset;
|
| 831 |
+
pointers_[1] += ptr_offset;
|
| 832 |
+
|
| 833 |
+
CUTLASS_PRAGMA_UNROLL
|
| 834 |
+
for (int i = 0; i < Detail::kOffsetCount; ++i) {
|
| 835 |
+
uniform_offset_[i] = (i ^ tile_offset.column()) * 4 * sizeof(AccessType);
|
| 836 |
+
}
|
| 837 |
+
|
| 838 |
+
return *this;
|
| 839 |
+
}
|
| 840 |
+
|
| 841 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 842 |
+
CUTLASS_HOST_DEVICE
|
| 843 |
+
TileIteratorTensorOpMixed & operator+=(TensorCoord const &tile_offset) {
|
| 844 |
+
return add_tile_offset(tile_offset);
|
| 845 |
+
}
|
| 846 |
+
|
| 847 |
+
/// Store
|
| 848 |
+
CUTLASS_DEVICE
|
| 849 |
+
void store_with_pointer_offset(Fragment const &frag, Index pointer_offset) {
|
| 850 |
+
|
| 851 |
+
AccessType const *frag_ptr = reinterpret_cast<AccessType const *>(&frag);
|
| 852 |
+
|
| 853 |
+
CUTLASS_PRAGMA_UNROLL
|
| 854 |
+
for (int n = 0; n < Policy::OperatorCount::kColumn; ++n) {
|
| 855 |
+
|
| 856 |
+
int ptr_idx = (n / 4);
|
| 857 |
+
int offset_idx = (n % 4);
|
| 858 |
+
|
| 859 |
+
AccessType *ptr;
|
| 860 |
+
if (ptr_idx == 0) {
|
| 861 |
+
ptr = pointers_[0];
|
| 862 |
+
}
|
| 863 |
+
else if (ptr_idx == 1) {
|
| 864 |
+
ptr = pointers_[1];
|
| 865 |
+
}
|
| 866 |
+
|
| 867 |
+
int offset = (n / 4) * 16 + pointer_offset / AccessType::kElements;
|
| 868 |
+
|
| 869 |
+
#if 0
|
| 870 |
+
//
|
| 871 |
+
// Using inline PTX to avoid generic memory
|
| 872 |
+
//
|
| 873 |
+
AccessType *smem_ptr = pointers_[ptr_idx];
|
| 874 |
+
smem_ptr[offset] = frag_ptr[n];
|
| 875 |
+
#else
|
| 876 |
+
uint32_t smem_addr = arch::cutlass_get_smem_pointer(ptr);
|
| 877 |
+
uint32_t const *data = reinterpret_cast<uint32_t const *>(frag_ptr + n);
|
| 878 |
+
uint32_t offset_in_bytes = offset * sizeof(AccessType) + uniform_offset_[offset_idx];
|
| 879 |
+
|
| 880 |
+
asm volatile(
|
| 881 |
+
"{ .reg .u32 smem_ptr; add.u32 smem_ptr, %0, %1; st.shared.v2.u32 [smem_ptr], {%2, %3}; }\n"
|
| 882 |
+
: : "r"(smem_addr), "r"(offset_in_bytes), "r"(data[0]), "r"(data[1])
|
| 883 |
+
);
|
| 884 |
+
#endif
|
| 885 |
+
}
|
| 886 |
+
}
|
| 887 |
+
|
| 888 |
+
/// Store
|
| 889 |
+
CUTLASS_HOST_DEVICE
|
| 890 |
+
void store(Fragment const &frag) {
|
| 891 |
+
store_with_pointer_offset(frag, 0);
|
| 892 |
+
}
|
| 893 |
+
};
|
| 894 |
+
|
| 895 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 896 |
+
|
| 897 |
+
/// Partial specialization for float x 8 => float_e4m3_t/float_e5m2_t x 8
|
| 898 |
+
template <
|
| 899 |
+
typename WarpShape_, ///< shape of warp-level GEMM (concept: GemmShape)
|
| 900 |
+
typename OperatorShape_ ///< matrix multiply operation shape (concept: gemm::GemmShape)
|
| 901 |
+
>
|
| 902 |
+
class TileIteratorTensorOpMixed<WarpShape_, OperatorShape_, float, 32, 8, 8, 8> {
|
| 903 |
+
public:
|
| 904 |
+
|
| 905 |
+
using WarpShape = WarpShape_;
|
| 906 |
+
using OperatorShape = OperatorShape_;
|
| 907 |
+
using Element = float;
|
| 908 |
+
using Layout = layout::RowMajor;
|
| 909 |
+
static int const kOutputElementCount = 8;
|
| 910 |
+
|
| 911 |
+
using TensorRef = TensorRef<Element, Layout>; ///< Tensor Reference object
|
| 912 |
+
using TensorCoord = MatrixCoord; ///< Logical coordinate in referenced tensor
|
| 913 |
+
using Index = typename TensorRef::Index;
|
| 914 |
+
using LongIndex = typename TensorRef::LongIndex;
|
| 915 |
+
|
| 916 |
+
using Policy = TensorOpPolicy<WarpShape, OperatorShape, Layout>;
|
| 917 |
+
|
| 918 |
+
/// Shape of the tile in memory
|
| 919 |
+
using Shape = MatrixShape<
|
| 920 |
+
Policy::kRowsPerIteration,
|
| 921 |
+
WarpShape::kN
|
| 922 |
+
>;
|
| 923 |
+
|
| 924 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 925 |
+
using Fragment = Array<
|
| 926 |
+
Element,
|
| 927 |
+
Policy::OperatorCount::kColumn * Policy::kElementsPerAccess>;
|
| 928 |
+
|
| 929 |
+
/// This is the complete warp-level accumulator tile.
|
| 930 |
+
//using AccumulatorTile = typename Operator::FragmentC;
|
| 931 |
+
|
| 932 |
+
/// Number of times this iterator can be incremented
|
| 933 |
+
static int const kIterations = Policy::kIterations;
|
| 934 |
+
|
| 935 |
+
// Internal constants
|
| 936 |
+
struct Detail {
|
| 937 |
+
static int const kLanesInQuad = 4;
|
| 938 |
+
|
| 939 |
+
/// Number of pointers needed to write accumulators
|
| 940 |
+
static int const kPointerCount = 2;
|
| 941 |
+
|
| 942 |
+
static_assert(sizeof(Element) == 4, "This can only be used with 32b accumulator data types (f32, s32).");
|
| 943 |
+
};
|
| 944 |
+
|
| 945 |
+
/// Padding quantity
|
| 946 |
+
using Padding = MatrixShape<0, Detail::kLanesInQuad * 2>;
|
| 947 |
+
|
| 948 |
+
private:
|
| 949 |
+
|
| 950 |
+
/// Storage type for accessing memory
|
| 951 |
+
using AccessType = AlignedArray<Element, 2>;
|
| 952 |
+
|
| 953 |
+
//
|
| 954 |
+
// Data members
|
| 955 |
+
//
|
| 956 |
+
|
| 957 |
+
/// Internal pointer to memory
|
| 958 |
+
AccessType *pointers_[Detail::kPointerCount] = {nullptr};
|
| 959 |
+
|
| 960 |
+
/// Stride in units of AccessType
|
| 961 |
+
int stride_{0};
|
| 962 |
+
|
| 963 |
+
public:
|
| 964 |
+
|
| 965 |
+
/// Default constructor
|
| 966 |
+
TileIteratorTensorOpMixed() = default;
|
| 967 |
+
|
| 968 |
+
/// Constructor from TensorRef
|
| 969 |
+
CUTLASS_HOST_DEVICE
|
| 970 |
+
TileIteratorTensorOpMixed(
|
| 971 |
+
TensorRef const &ref,
|
| 972 |
+
unsigned lane_id
|
| 973 |
+
):
|
| 974 |
+
stride_(ref.stride()[0] / AccessType::kElements) {
|
| 975 |
+
|
| 976 |
+
int quad_id = (lane_id / Detail::kLanesInQuad);
|
| 977 |
+
int lane_in_quad = (lane_id % Detail::kLanesInQuad);
|
| 978 |
+
|
| 979 |
+
CUTLASS_PRAGMA_UNROLL
|
| 980 |
+
for (int i = 0; i < Detail::kPointerCount; ++i) {
|
| 981 |
+
AccessType *ptr = reinterpret_cast<AccessType *>(ref.data()) + quad_id * stride_;
|
| 982 |
+
int column_idx = lane_in_quad ^ (i * 2);
|
| 983 |
+
|
| 984 |
+
ptr += column_idx;
|
| 985 |
+
|
| 986 |
+
if (i == 0) {
|
| 987 |
+
pointers_[0] = ptr;
|
| 988 |
+
}
|
| 989 |
+
else if (i == 1) {
|
| 990 |
+
pointers_[1] = ptr;
|
| 991 |
+
}
|
| 992 |
+
}
|
| 993 |
+
}
|
| 994 |
+
|
| 995 |
+
/// Adds a pointer offset
|
| 996 |
+
CUTLASS_HOST_DEVICE
|
| 997 |
+
TileIteratorTensorOpMixed & add_pointer_offset(Index pointer_offset) {
|
| 998 |
+
|
| 999 |
+
CUTLASS_PRAGMA_UNROLL
|
| 1000 |
+
for (int64_t i = 0; i < Detail::kPointerCount; ++i) {
|
| 1001 |
+
pointers_[i] += pointer_offset / AccessType::kElements;
|
| 1002 |
+
}
|
| 1003 |
+
|
| 1004 |
+
return *this;
|
| 1005 |
+
}
|
| 1006 |
+
|
| 1007 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 1008 |
+
CUTLASS_HOST_DEVICE
|
| 1009 |
+
TileIteratorTensorOpMixed & add_tile_offset(TensorCoord const &tile_offset) {
|
| 1010 |
+
|
| 1011 |
+
int ptr_offset = tile_offset.row() * Shape::kRow * stride_ +
|
| 1012 |
+
tile_offset.column() * Shape::kColumn / AccessType::kElements;
|
| 1013 |
+
|
| 1014 |
+
pointers_[0] += ptr_offset;
|
| 1015 |
+
pointers_[1] += ptr_offset;
|
| 1016 |
+
|
| 1017 |
+
if (tile_offset.column() % 2) {
|
| 1018 |
+
auto tmp = pointers_[0];
|
| 1019 |
+
pointers_[0] = pointers_[1];
|
| 1020 |
+
pointers_[1] = tmp;
|
| 1021 |
+
}
|
| 1022 |
+
|
| 1023 |
+
return *this;
|
| 1024 |
+
}
|
| 1025 |
+
|
| 1026 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 1027 |
+
CUTLASS_HOST_DEVICE
|
| 1028 |
+
TileIteratorTensorOpMixed & operator+=(TensorCoord const &tile_offset) {
|
| 1029 |
+
return add_tile_offset(tile_offset);
|
| 1030 |
+
}
|
| 1031 |
+
|
| 1032 |
+
/// Store
|
| 1033 |
+
CUTLASS_DEVICE
|
| 1034 |
+
void store_with_pointer_offset(Fragment const &frag, Index pointer_offset) {
|
| 1035 |
+
|
| 1036 |
+
AccessType const *frag_ptr = reinterpret_cast<AccessType const *>(&frag);
|
| 1037 |
+
|
| 1038 |
+
CUTLASS_PRAGMA_UNROLL
|
| 1039 |
+
for (int n = 0; n < Policy::OperatorCount::kColumn; ++n) {
|
| 1040 |
+
|
| 1041 |
+
int ptr_idx = (n / 4);
|
| 1042 |
+
|
| 1043 |
+
AccessType *ptr;
|
| 1044 |
+
if (ptr_idx == 0) {
|
| 1045 |
+
ptr = pointers_[0];
|
| 1046 |
+
}
|
| 1047 |
+
else if (ptr_idx == 1) {
|
| 1048 |
+
ptr = pointers_[1];
|
| 1049 |
+
}
|
| 1050 |
+
|
| 1051 |
+
int offset = (n / 4) * 16 + pointer_offset / AccessType::kElements + (n % 4) * 4;
|
| 1052 |
+
|
| 1053 |
+
#if 0
|
| 1054 |
+
//
|
| 1055 |
+
// Using inline PTX to avoid generic memory
|
| 1056 |
+
//
|
| 1057 |
+
AccessType *smem_ptr = pointers_[ptr_idx];
|
| 1058 |
+
smem_ptr[offset] = frag_ptr[n];
|
| 1059 |
+
#else
|
| 1060 |
+
uint32_t smem_addr = arch::cutlass_get_smem_pointer(ptr);
|
| 1061 |
+
uint32_t const *data = reinterpret_cast<uint32_t const *>(frag_ptr + n);
|
| 1062 |
+
uint32_t offset_in_bytes = offset * sizeof(AccessType);
|
| 1063 |
+
|
| 1064 |
+
asm volatile(
|
| 1065 |
+
"{ .reg .u32 smem_ptr; add.u32 smem_ptr, %0, %1; st.shared.v2.u32 [smem_ptr], {%2, %3}; }\n"
|
| 1066 |
+
: : "r"(smem_addr), "r"(offset_in_bytes), "r"(data[0]), "r"(data[1])
|
| 1067 |
+
);
|
| 1068 |
+
#endif
|
| 1069 |
+
}
|
| 1070 |
+
}
|
| 1071 |
+
|
| 1072 |
+
/// Store
|
| 1073 |
+
CUTLASS_HOST_DEVICE
|
| 1074 |
+
void store(Fragment const &frag) {
|
| 1075 |
+
store_with_pointer_offset(frag, 0);
|
| 1076 |
+
}
|
| 1077 |
+
};
|
| 1078 |
+
|
| 1079 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1080 |
+
|
| 1081 |
+
} // namespace warp
|
| 1082 |
+
} // namespace epilogue
|
| 1083 |
+
} // namespace cutlass
|
| 1084 |
+
|
| 1085 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1086 |
+
|
| 1087 |
+
#undef CUTLASS_EPILOGUE_WARP_TILE_ITERATOR_TENSOR_OP_MIXED_OPTIMIZATION_ENABLED
|
| 1088 |
+
|
| 1089 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/tile_iterator_volta_tensor_op.h
ADDED
|
@@ -0,0 +1,440 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief
|
| 33 |
+
*/
|
| 34 |
+
|
| 35 |
+
#pragma once
|
| 36 |
+
|
| 37 |
+
#include "cutlass/array.h"
|
| 38 |
+
#include "cutlass/layout/matrix.h"
|
| 39 |
+
#include "cutlass/layout/pitch_linear.h"
|
| 40 |
+
|
| 41 |
+
#include "cutlass/epilogue/warp/tensor_op_policy.h"
|
| 42 |
+
#include "cutlass/epilogue/warp/volta_tensor_op_policy.h"
|
| 43 |
+
|
| 44 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 45 |
+
|
| 46 |
+
namespace cutlass {
|
| 47 |
+
namespace epilogue {
|
| 48 |
+
namespace warp {
|
| 49 |
+
|
| 50 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 51 |
+
|
| 52 |
+
/// Template for reading and writing tiles of accumulators to shared memory
|
| 53 |
+
template <
|
| 54 |
+
typename WarpShape, ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 55 |
+
typename InterleavedTileShape, ///< shape of indivisible instruction-level arrangement (concept: GemmShape)
|
| 56 |
+
typename ElementC, ///< Accumulator layout
|
| 57 |
+
typename Layout ///< target shared memory layout
|
| 58 |
+
>
|
| 59 |
+
struct TileIteratorVoltaTensorOp;
|
| 60 |
+
|
| 61 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 62 |
+
|
| 63 |
+
/// Template for reading and writing tiles of accumulators to shared memory
|
| 64 |
+
template <
|
| 65 |
+
typename WarpShape_ ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 66 |
+
>
|
| 67 |
+
struct TileIteratorVoltaTensorOp<WarpShape_, gemm::GemmShape<32, 32, 4>, half_t, layout::RowMajor> {
|
| 68 |
+
public:
|
| 69 |
+
|
| 70 |
+
using WarpShape = WarpShape_;
|
| 71 |
+
using InterleavedTileShape = gemm::GemmShape<32, 32, 4>;
|
| 72 |
+
using Element = half_t;
|
| 73 |
+
using Layout = layout::RowMajor;
|
| 74 |
+
|
| 75 |
+
using TensorRef = TensorRef<Element, Layout>; ///< Tensor Reference object
|
| 76 |
+
using TensorCoord = MatrixCoord; ///< Logical coordinate in referenced tensor
|
| 77 |
+
using Index = typename TensorRef::Index;
|
| 78 |
+
using LongIndex = typename TensorRef::LongIndex;
|
| 79 |
+
|
| 80 |
+
using Policy = VoltaTensorOpPolicy<WarpShape, InterleavedTileShape, Element, Layout>;
|
| 81 |
+
|
| 82 |
+
/// Shape of the tile in memory
|
| 83 |
+
using Shape = MatrixShape<
|
| 84 |
+
Policy::kRowsPerIteration,
|
| 85 |
+
WarpShape::kN
|
| 86 |
+
>;
|
| 87 |
+
|
| 88 |
+
/// Array type for aligned memory accesses
|
| 89 |
+
using AccessType = typename Policy::AccessType;
|
| 90 |
+
|
| 91 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 92 |
+
using Fragment = typename Policy::Fragment;
|
| 93 |
+
|
| 94 |
+
/// This is the complete warp-level accumulator tile.
|
| 95 |
+
using AccumulatorTile = typename Policy::AccumulatorTile;
|
| 96 |
+
|
| 97 |
+
/// Number of times this iterator can be incremented
|
| 98 |
+
static int const kIterations = Policy::kIterations;
|
| 99 |
+
|
| 100 |
+
/// Number of elements per access
|
| 101 |
+
static int const kElementsPerAccess = Policy::kElementsPerAccess;
|
| 102 |
+
|
| 103 |
+
// Internal constants
|
| 104 |
+
struct Detail {
|
| 105 |
+
static int const kLanesInQuad = 4;
|
| 106 |
+
static int const kRowsPerQuad = 4;
|
| 107 |
+
static int const kColumnsPerQuad = 8;
|
| 108 |
+
static int const kAccessesPerQuad = kColumnsPerQuad / Policy::kElementsPerAccess;
|
| 109 |
+
static int const kAccessQuadDelta = 16;
|
| 110 |
+
};
|
| 111 |
+
|
| 112 |
+
/// Padding quantity
|
| 113 |
+
using Padding = MatrixShape<
|
| 114 |
+
0,
|
| 115 |
+
Policy::kElementsPerAccess>;
|
| 116 |
+
|
| 117 |
+
private:
|
| 118 |
+
|
| 119 |
+
//
|
| 120 |
+
// Data members
|
| 121 |
+
//
|
| 122 |
+
|
| 123 |
+
/// Internal pointer to memory
|
| 124 |
+
AccessType *pointer_;
|
| 125 |
+
|
| 126 |
+
/// Internal layout object
|
| 127 |
+
Layout layout_;
|
| 128 |
+
|
| 129 |
+
public:
|
| 130 |
+
|
| 131 |
+
/// Default constructor
|
| 132 |
+
CUTLASS_HOST_DEVICE
|
| 133 |
+
TileIteratorVoltaTensorOp(): pointer_(nullptr) { }
|
| 134 |
+
|
| 135 |
+
/// Constructor from TensorRef
|
| 136 |
+
CUTLASS_DEVICE
|
| 137 |
+
TileIteratorVoltaTensorOp(
|
| 138 |
+
TensorRef const &ref,
|
| 139 |
+
unsigned lane_id
|
| 140 |
+
):
|
| 141 |
+
pointer_(reinterpret_cast<AccessType *>(ref.data())),
|
| 142 |
+
layout_(ref.stride()[0] / Policy::kElementsPerAccess) {
|
| 143 |
+
|
| 144 |
+
int quad_id = lane_id / Detail::kLanesInQuad;
|
| 145 |
+
int lane_in_quad = (lane_id % Detail::kLanesInQuad);
|
| 146 |
+
|
| 147 |
+
int quad_row_idx = ((quad_id & 4) >> 1) + (quad_id & 1);
|
| 148 |
+
int quad_col_idx = ((quad_id & 2) >> 1);
|
| 149 |
+
|
| 150 |
+
int row = quad_row_idx * Detail::kRowsPerQuad + lane_in_quad;
|
| 151 |
+
int column = quad_col_idx * Detail::kColumnsPerQuad;
|
| 152 |
+
|
| 153 |
+
pointer_ += layout_({row, column / kElementsPerAccess});
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
/// Adds a pointer offset
|
| 157 |
+
CUTLASS_HOST_DEVICE
|
| 158 |
+
TileIteratorVoltaTensorOp & add_pointer_offset(Index pointer_offset) {
|
| 159 |
+
pointer_ += pointer_offset / Policy::kElementsPerAccess;
|
| 160 |
+
return *this;
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 164 |
+
CUTLASS_HOST_DEVICE
|
| 165 |
+
TileIteratorVoltaTensorOp & add_tile_offset(TensorCoord const &tile_offset) {
|
| 166 |
+
|
| 167 |
+
pointer_ += layout_({
|
| 168 |
+
tile_offset.row() * Shape::kRow,
|
| 169 |
+
tile_offset.column() * Shape::kColumn / Policy::kElementsPerAccess});
|
| 170 |
+
|
| 171 |
+
return *this;
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 175 |
+
CUTLASS_HOST_DEVICE
|
| 176 |
+
TileIteratorVoltaTensorOp & operator+=(TensorCoord const &tile_offset) {
|
| 177 |
+
add_tile_offset(tile_offset);
|
| 178 |
+
return *this;
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
/// Store
|
| 182 |
+
CUTLASS_DEVICE
|
| 183 |
+
void store_with_pointer_offset(Fragment const &frag, Index pointer_offset) {
|
| 184 |
+
|
| 185 |
+
AccessType const *frag_ptr = reinterpret_cast<AccessType const *>(&frag);
|
| 186 |
+
|
| 187 |
+
CUTLASS_PRAGMA_UNROLL
|
| 188 |
+
for (int tile_idx = 0; tile_idx < Policy::TileIterations::kColumn; ++tile_idx) {
|
| 189 |
+
|
| 190 |
+
CUTLASS_PRAGMA_UNROLL
|
| 191 |
+
for (int access_idx = 0; access_idx < Policy::kAccessesPerInterleavedTile; ++access_idx) {
|
| 192 |
+
|
| 193 |
+
int access_quad = access_idx / 2;
|
| 194 |
+
int access = access_idx % 2;
|
| 195 |
+
|
| 196 |
+
int ptr_offset = tile_idx * InterleavedTileShape::kN / Policy::kElementsPerAccess +
|
| 197 |
+
access_quad * Detail::kAccessQuadDelta / Policy::kElementsPerAccess +
|
| 198 |
+
access + pointer_offset / Policy::kElementsPerAccess;
|
| 199 |
+
|
| 200 |
+
int frag_idx = tile_idx * Policy::kAccessesPerInterleavedTile + access_idx;
|
| 201 |
+
|
| 202 |
+
AccessType access_vector = frag_ptr[frag_idx];
|
| 203 |
+
|
| 204 |
+
pointer_[ptr_offset] = access_vector;
|
| 205 |
+
}
|
| 206 |
+
}
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
/// Store
|
| 210 |
+
CUTLASS_HOST_DEVICE
|
| 211 |
+
void store(Fragment const &frag) {
|
| 212 |
+
store_with_pointer_offset(frag, 0);
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
/// Load
|
| 216 |
+
CUTLASS_HOST_DEVICE
|
| 217 |
+
void load_with_pointer_offset(Fragment const &frag, Index pointer_offset) {
|
| 218 |
+
|
| 219 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 220 |
+
|
| 221 |
+
CUTLASS_PRAGMA_UNROLL
|
| 222 |
+
for (int tile_idx = 0; tile_idx < Policy::TileIterations::kColumn; ++tile_idx) {
|
| 223 |
+
|
| 224 |
+
CUTLASS_PRAGMA_UNROLL
|
| 225 |
+
for (int access_idx = 0; access_idx < Policy::kAccessesPerInterleavedTile; ++access_idx) {
|
| 226 |
+
|
| 227 |
+
int access_quad = access_idx / 2;
|
| 228 |
+
int access = access_idx % 2;
|
| 229 |
+
|
| 230 |
+
int ptr_offset = tile_idx * Detail::kTileDelta + access_quad * Detail::kAccessQuadDelta +
|
| 231 |
+
access + pointer_offset / Policy::kElementsPerAccess;
|
| 232 |
+
|
| 233 |
+
int frag_idx = tile_idx * Policy::kAccessesPerInterleavedTile + access_idx;
|
| 234 |
+
|
| 235 |
+
frag_ptr[frag_idx] = pointer_[ptr_offset];
|
| 236 |
+
}
|
| 237 |
+
}
|
| 238 |
+
}
|
| 239 |
+
|
| 240 |
+
/// Load
|
| 241 |
+
CUTLASS_HOST_DEVICE
|
| 242 |
+
void load(Fragment const &frag) {
|
| 243 |
+
load_with_pointer_offset(frag, 0);
|
| 244 |
+
}
|
| 245 |
+
|
| 246 |
+
/// Set smem base address
|
| 247 |
+
CUTLASS_HOST_DEVICE
|
| 248 |
+
void set_smem_base_address(Index address) {
|
| 249 |
+
}
|
| 250 |
+
};
|
| 251 |
+
|
| 252 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 253 |
+
|
| 254 |
+
/// Template for reading and writing tiles of accumulators to shared memory
|
| 255 |
+
template <
|
| 256 |
+
typename WarpShape_ ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 257 |
+
>
|
| 258 |
+
struct TileIteratorVoltaTensorOp<WarpShape_, gemm::GemmShape<32, 32, 4>, float, layout::RowMajor> {
|
| 259 |
+
public:
|
| 260 |
+
|
| 261 |
+
using WarpShape = WarpShape_;
|
| 262 |
+
using InterleavedTileShape = gemm::GemmShape<32, 32, 4>;
|
| 263 |
+
using Element = float;
|
| 264 |
+
using Layout = layout::RowMajor;
|
| 265 |
+
|
| 266 |
+
using TensorRef = TensorRef<Element, Layout>; ///< Tensor Reference object
|
| 267 |
+
using TensorCoord = MatrixCoord; ///< Logical coordinate in referenced tensor
|
| 268 |
+
using Index = typename TensorRef::Index;
|
| 269 |
+
using LongIndex = typename TensorRef::LongIndex;
|
| 270 |
+
|
| 271 |
+
using Policy = VoltaTensorOpPolicy<WarpShape, InterleavedTileShape, Element, Layout>;
|
| 272 |
+
|
| 273 |
+
/// Shape of the tile in memory
|
| 274 |
+
using Shape = MatrixShape<
|
| 275 |
+
Policy::kRowsPerIteration,
|
| 276 |
+
WarpShape::kN
|
| 277 |
+
>;
|
| 278 |
+
|
| 279 |
+
/// Array type for aligned memory accesses
|
| 280 |
+
using AccessType = typename Policy::AccessType;
|
| 281 |
+
|
| 282 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 283 |
+
using Fragment = typename Policy::Fragment;
|
| 284 |
+
|
| 285 |
+
/// This is the complete warp-level accumulator tile.
|
| 286 |
+
using AccumulatorTile = typename Policy::AccumulatorTile;
|
| 287 |
+
|
| 288 |
+
/// Number of times this iterator can be incremented
|
| 289 |
+
static int const kIterations = Policy::kIterations;
|
| 290 |
+
|
| 291 |
+
/// Number of elements per access
|
| 292 |
+
static int const kElementsPerAccess = Policy::kElementsPerAccess;
|
| 293 |
+
|
| 294 |
+
// Internal constants
|
| 295 |
+
struct Detail {
|
| 296 |
+
static int const kLanesInQuad = 4;
|
| 297 |
+
static int const kRowsPerQuad = 4;
|
| 298 |
+
static int const kColumnsPerQuad = 8;
|
| 299 |
+
static int const kAccessesPerQuad = kColumnsPerQuad / Policy::kElementsPerAccess;
|
| 300 |
+
static int const kAccessQuadDelta = 16;
|
| 301 |
+
};
|
| 302 |
+
|
| 303 |
+
/// Padding quantity
|
| 304 |
+
using Padding = MatrixShape<
|
| 305 |
+
0,
|
| 306 |
+
Policy::kElementsPerAccess>;
|
| 307 |
+
|
| 308 |
+
private:
|
| 309 |
+
|
| 310 |
+
//
|
| 311 |
+
// Data members
|
| 312 |
+
//
|
| 313 |
+
|
| 314 |
+
/// Internal pointer to memory
|
| 315 |
+
AccessType *pointer_;
|
| 316 |
+
|
| 317 |
+
/// Internal layout object
|
| 318 |
+
Layout layout_;
|
| 319 |
+
|
| 320 |
+
public:
|
| 321 |
+
|
| 322 |
+
/// Default constructor
|
| 323 |
+
CUTLASS_HOST_DEVICE
|
| 324 |
+
TileIteratorVoltaTensorOp(): pointer_(nullptr) { }
|
| 325 |
+
|
| 326 |
+
/// Constructor from TensorRef
|
| 327 |
+
CUTLASS_DEVICE
|
| 328 |
+
TileIteratorVoltaTensorOp(
|
| 329 |
+
TensorRef const &ref,
|
| 330 |
+
unsigned lane_id
|
| 331 |
+
):
|
| 332 |
+
pointer_(reinterpret_cast<AccessType *>(ref.data())),
|
| 333 |
+
layout_(ref.stride()[0] / Policy::kElementsPerAccess) {
|
| 334 |
+
|
| 335 |
+
int quad_id = lane_id / Detail::kLanesInQuad;
|
| 336 |
+
int lane_in_quad = (lane_id % Detail::kLanesInQuad);
|
| 337 |
+
|
| 338 |
+
int const kQuadRowDelta = 4;
|
| 339 |
+
int const kQuadColumnDelta = 2 * Policy::MmaIterations::kColumn;
|
| 340 |
+
|
| 341 |
+
int quad_row_offset = ((quad_id & 4) / 2 + (quad_id & 1)) * kQuadRowDelta;
|
| 342 |
+
int quad_column_offset = (quad_id & 2) / 2 * kQuadColumnDelta;
|
| 343 |
+
|
| 344 |
+
int thread_row_offset = (lane_in_quad & 1);
|
| 345 |
+
int thread_column_offset = (lane_in_quad & 2) / 2;
|
| 346 |
+
|
| 347 |
+
int row = quad_row_offset + thread_row_offset;
|
| 348 |
+
int column = quad_column_offset + thread_column_offset;
|
| 349 |
+
|
| 350 |
+
pointer_ += layout_({row, column});
|
| 351 |
+
}
|
| 352 |
+
|
| 353 |
+
/// Adds a pointer offset
|
| 354 |
+
CUTLASS_HOST_DEVICE
|
| 355 |
+
TileIteratorVoltaTensorOp & add_pointer_offset(Index pointer_offset) {
|
| 356 |
+
pointer_ += pointer_offset / Policy::kElementsPerAccess;
|
| 357 |
+
return *this;
|
| 358 |
+
}
|
| 359 |
+
|
| 360 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 361 |
+
CUTLASS_HOST_DEVICE
|
| 362 |
+
TileIteratorVoltaTensorOp & add_tile_offset(TensorCoord const &tile_offset) {
|
| 363 |
+
|
| 364 |
+
pointer_ += layout_({
|
| 365 |
+
tile_offset.row() * Shape::kRow,
|
| 366 |
+
tile_offset.column() * Shape::kColumn / Policy::kElementsPerAccess});
|
| 367 |
+
|
| 368 |
+
return *this;
|
| 369 |
+
}
|
| 370 |
+
|
| 371 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 372 |
+
CUTLASS_HOST_DEVICE
|
| 373 |
+
TileIteratorVoltaTensorOp & operator+=(TensorCoord const &tile_offset) {
|
| 374 |
+
add_tile_offset(tile_offset);
|
| 375 |
+
return *this;
|
| 376 |
+
}
|
| 377 |
+
|
| 378 |
+
/// Store
|
| 379 |
+
CUTLASS_DEVICE
|
| 380 |
+
void store_with_pointer_offset(Fragment const &frag, Index pointer_offset) {
|
| 381 |
+
|
| 382 |
+
AccessType const *frag_ptr = reinterpret_cast<AccessType const *>(&frag);
|
| 383 |
+
|
| 384 |
+
int const kAccessesPerRow = Policy::TileIterations::kColumn * Policy::MmaIterations::kColumn * 2;
|
| 385 |
+
|
| 386 |
+
CUTLASS_PRAGMA_UNROLL
|
| 387 |
+
for (int row_idx = 0; row_idx < Policy::kRowsPerMmaTile; ++row_idx) {
|
| 388 |
+
|
| 389 |
+
CUTLASS_PRAGMA_UNROLL
|
| 390 |
+
for (int access_idx = 0; access_idx < kAccessesPerRow; ++access_idx) {
|
| 391 |
+
|
| 392 |
+
int frag_idx = row_idx * kAccessesPerRow + access_idx;
|
| 393 |
+
|
| 394 |
+
int ptr_column_offset = (access_idx & 1) * 2 +
|
| 395 |
+
(access_idx & 2) * Policy::MmaIterations::kColumn * 2 +
|
| 396 |
+
(access_idx & 4) * Policy::MmaIterations::kColumn * 2;
|
| 397 |
+
|
| 398 |
+
int ptr_row_offset = row_idx * 2;
|
| 399 |
+
|
| 400 |
+
int ptr_offset = layout_({ptr_row_offset, ptr_column_offset}) + pointer_offset / Policy::kElementsPerAccess;
|
| 401 |
+
|
| 402 |
+
pointer_[ptr_offset] = frag_ptr[frag_idx];
|
| 403 |
+
}
|
| 404 |
+
}
|
| 405 |
+
}
|
| 406 |
+
|
| 407 |
+
/// Store
|
| 408 |
+
CUTLASS_HOST_DEVICE
|
| 409 |
+
void store(Fragment const &frag) {
|
| 410 |
+
store_with_pointer_offset(frag, 0);
|
| 411 |
+
}
|
| 412 |
+
|
| 413 |
+
/// Load
|
| 414 |
+
CUTLASS_HOST_DEVICE
|
| 415 |
+
void load_with_pointer_offset(Fragment const &frag, Index pointer_offset) {
|
| 416 |
+
|
| 417 |
+
AccessType *frag_ptr = reinterpret_cast<AccessType *>(&frag);
|
| 418 |
+
|
| 419 |
+
assert(0);
|
| 420 |
+
}
|
| 421 |
+
|
| 422 |
+
/// Load
|
| 423 |
+
CUTLASS_HOST_DEVICE
|
| 424 |
+
void load(Fragment const &frag) {
|
| 425 |
+
load_with_pointer_offset(frag, 0);
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
/// Set smem base address
|
| 429 |
+
CUTLASS_HOST_DEVICE
|
| 430 |
+
void set_smem_base_address(Index address) {
|
| 431 |
+
}
|
| 432 |
+
};
|
| 433 |
+
|
| 434 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 435 |
+
|
| 436 |
+
} // namespace warp
|
| 437 |
+
} // namespace epilogue
|
| 438 |
+
} // namespace cutlass
|
| 439 |
+
|
| 440 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/tile_iterator_wmma_tensor_op.h
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief
|
| 33 |
+
*/
|
| 34 |
+
|
| 35 |
+
#pragma once
|
| 36 |
+
|
| 37 |
+
#include "cutlass/cutlass.h"
|
| 38 |
+
#include "cutlass/wmma_array.h"
|
| 39 |
+
#include "cutlass/layout/matrix.h"
|
| 40 |
+
#include "cutlass/layout/pitch_linear.h"
|
| 41 |
+
#include "cutlass/tensor_ref.h"
|
| 42 |
+
|
| 43 |
+
#include "cutlass/epilogue/warp/wmma_tensor_op_policy.h"
|
| 44 |
+
|
| 45 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 46 |
+
|
| 47 |
+
namespace cutlass {
|
| 48 |
+
namespace epilogue {
|
| 49 |
+
namespace warp {
|
| 50 |
+
|
| 51 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 52 |
+
|
| 53 |
+
/// Template for reading and writing tiles of accumulators to shared memory
|
| 54 |
+
template <
|
| 55 |
+
typename WarpShape, ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 56 |
+
typename OperatorShape, ///< matrix multiply operation shape (concept: gemm::GemmShape)
|
| 57 |
+
typename OperatorFragment, ///< wmma fragment to be written (concept: nvcuda::wmma::fragment)
|
| 58 |
+
typename Layout ///< target shared memory layout
|
| 59 |
+
>
|
| 60 |
+
class TileIteratorWmmaTensorOp;
|
| 61 |
+
|
| 62 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 63 |
+
|
| 64 |
+
/// Template for reading and writing tiles of accumulators to shared memory
|
| 65 |
+
template <
|
| 66 |
+
typename WarpShape_, ///< shape of warp-level GEMM (concept: GemmShape)
|
| 67 |
+
typename OperatorShape_, ///< matrix multiply operation shape (concept: gemm::GemmShape)
|
| 68 |
+
typename OperatorFragment_ ///< wmma fragment to be written (concept: nvcuda::wmma::fragment)
|
| 69 |
+
>
|
| 70 |
+
class TileIteratorWmmaTensorOp<WarpShape_, OperatorShape_, OperatorFragment_, layout::RowMajor> {
|
| 71 |
+
public:
|
| 72 |
+
|
| 73 |
+
using WarpShape = WarpShape_;
|
| 74 |
+
using OperatorShape = OperatorShape_;
|
| 75 |
+
using OperatorFragment = OperatorFragment_;
|
| 76 |
+
using Layout = layout::RowMajor;
|
| 77 |
+
|
| 78 |
+
//
|
| 79 |
+
// Derived types
|
| 80 |
+
//
|
| 81 |
+
using WmmaDataType = typename OperatorFragment::element_type;
|
| 82 |
+
using Element = typename cutlass::arch::WmmaToCutlassDataType<WmmaDataType>::Type; ///< Data Type of element stored in nvcuda::wmma::frament
|
| 83 |
+
using TensorRef = TensorRef<Element, Layout>; ///< Tensor Reference object
|
| 84 |
+
using TensorCoord = MatrixCoord; ///< Logical coordinate in referenced tensor
|
| 85 |
+
using Index = typename TensorRef::Index;
|
| 86 |
+
using LongIndex = typename TensorRef::LongIndex;
|
| 87 |
+
|
| 88 |
+
using Policy = WmmaTensorOpPolicy<WarpShape, OperatorShape, Layout>;
|
| 89 |
+
|
| 90 |
+
/// Shape of the tile in memory
|
| 91 |
+
using Shape = MatrixShape<
|
| 92 |
+
Policy::kRowsPerIteration,
|
| 93 |
+
WarpShape::kN
|
| 94 |
+
>;
|
| 95 |
+
|
| 96 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 97 |
+
using Fragment = WmmaFragmentArray<OperatorFragment, Policy::OperatorCount::kColumn * Policy::kWmmaFragmentsPerAccess>;
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
/// This is the complete warp-level accumulator tile.
|
| 101 |
+
//using AccumulatorTile = typename Operator::FragmentC;
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
/// Padding quantity
|
| 105 |
+
// (Epilogue shared memory padding for WMMA Gemm kernel is set to run optimaly on Turing)
|
| 106 |
+
using Padding = MatrixShape<
|
| 107 |
+
0,
|
| 108 |
+
4 * Policy::kElementsPerAccess
|
| 109 |
+
>;
|
| 110 |
+
|
| 111 |
+
private:
|
| 112 |
+
|
| 113 |
+
/// Storage type for accessing memory
|
| 114 |
+
//using AccessType = AlignedArray<Element, Policy::kElementsPerAccess>;
|
| 115 |
+
|
| 116 |
+
//
|
| 117 |
+
// Data members
|
| 118 |
+
//
|
| 119 |
+
|
| 120 |
+
/// Internal pointer to shared memory
|
| 121 |
+
TensorRef ref_;
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
public:
|
| 125 |
+
|
| 126 |
+
/// Default constructor
|
| 127 |
+
CUTLASS_HOST_DEVICE
|
| 128 |
+
TileIteratorWmmaTensorOp(): ref_(nullptr) {
|
| 129 |
+
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
/// Constructor from TensorRef
|
| 133 |
+
CUTLASS_HOST_DEVICE
|
| 134 |
+
TileIteratorWmmaTensorOp(
|
| 135 |
+
TensorRef const &ref,
|
| 136 |
+
unsigned lane_id
|
| 137 |
+
): ref_(ref) {
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
/// Adds a pointer offset
|
| 141 |
+
CUTLASS_HOST_DEVICE
|
| 142 |
+
TileIteratorWmmaTensorOp & add_pointer_offset(Index pointer_offset) {
|
| 143 |
+
ref_.add_pointer_offset(pointer_offset);
|
| 144 |
+
return *this;
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 148 |
+
CUTLASS_HOST_DEVICE
|
| 149 |
+
TileIteratorWmmaTensorOp & add_tile_offset(TensorCoord const &tile_offset) {
|
| 150 |
+
ref_.add_coord_offset({tile_offset.row() * OperatorShape::kM, tile_offset.column() * WarpShape::kN});
|
| 151 |
+
return *this;
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
///< advances in units of whole tiles along the logical coordinate space of the tensor
|
| 155 |
+
CUTLASS_HOST_DEVICE
|
| 156 |
+
TileIteratorWmmaTensorOp & operator+=(TensorCoord const &tile_offset) {
|
| 157 |
+
add_tile_offset(tile_offset);
|
| 158 |
+
return *this;
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
/// Store
|
| 162 |
+
CUTLASS_HOST_DEVICE
|
| 163 |
+
void store_with_pointer_offset(Fragment const &frag, Index pointer_offset) {
|
| 164 |
+
|
| 165 |
+
for(int n=0; n < Policy::OperatorCount::kColumn; n++) {
|
| 166 |
+
|
| 167 |
+
WmmaDataType* ptr = reinterpret_cast<WmmaDataType*> (ref_.data() + ref_.offset({0, n * OperatorShape::kN}) + pointer_offset);
|
| 168 |
+
|
| 169 |
+
nvcuda::wmma::store_matrix_sync(
|
| 170 |
+
ptr,
|
| 171 |
+
frag[n],
|
| 172 |
+
ref_.stride()[0],
|
| 173 |
+
nvcuda::wmma::layout_t::mem_row_major
|
| 174 |
+
);
|
| 175 |
+
|
| 176 |
+
}
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
/// Store
|
| 180 |
+
CUTLASS_HOST_DEVICE
|
| 181 |
+
void store(Fragment const &frag) {
|
| 182 |
+
store_with_pointer_offset(frag, 0);
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
+
/// Load
|
| 186 |
+
CUTLASS_HOST_DEVICE
|
| 187 |
+
void load_with_pointer_offset(Fragment &frag, Index pointer_offset) const {
|
| 188 |
+
|
| 189 |
+
for(int n=0; n < Policy::OperatorCount::kColumn; n++) {
|
| 190 |
+
|
| 191 |
+
WmmaDataType* ptr = reinterpret_cast<WmmaDataType*> (ref_.data() + ref_.offset({0, n * OperatorShape::kN}) + pointer_offset);
|
| 192 |
+
|
| 193 |
+
nvcuda::wmma::load_matrix_sync(
|
| 194 |
+
frag[n],
|
| 195 |
+
ptr,
|
| 196 |
+
ref_.stride()[0],
|
| 197 |
+
nvcuda::wmma::layout_t::mem_row_major
|
| 198 |
+
);
|
| 199 |
+
|
| 200 |
+
}
|
| 201 |
+
}
|
| 202 |
+
|
| 203 |
+
/// Load
|
| 204 |
+
CUTLASS_HOST_DEVICE
|
| 205 |
+
void load(Fragment &frag) const {
|
| 206 |
+
load_with_pointer_offset(frag, 0);
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
/// Set smem base address
|
| 211 |
+
CUTLASS_HOST_DEVICE
|
| 212 |
+
void set_smem_base_address(Index address) {
|
| 213 |
+
}
|
| 214 |
+
};
|
| 215 |
+
|
| 216 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 217 |
+
|
| 218 |
+
} // namespace warp
|
| 219 |
+
} // namespace epilogue
|
| 220 |
+
} // namespace cutlass
|
| 221 |
+
|
| 222 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 223 |
+
|
| 224 |
+
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/volta_tensor_op_policy.h
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief Defines basic structures needed for implementing the warp-scoped phase of the epilogue.
|
| 33 |
+
These quantities assume a 'column-major' arrangement of TensorOp instructions, of which
|
| 34 |
+
a row-oriented slice is visible per iteration.
|
| 35 |
+
*/
|
| 36 |
+
|
| 37 |
+
#pragma once
|
| 38 |
+
|
| 39 |
+
#include "cutlass/matrix_shape.h"
|
| 40 |
+
#include "cutlass/layout/matrix.h"
|
| 41 |
+
#include "cutlass/gemm/gemm.h"
|
| 42 |
+
|
| 43 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 44 |
+
|
| 45 |
+
namespace cutlass {
|
| 46 |
+
namespace epilogue {
|
| 47 |
+
namespace warp {
|
| 48 |
+
|
| 49 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 50 |
+
|
| 51 |
+
/// Policy details related to the epilogue
|
| 52 |
+
template <
|
| 53 |
+
typename WarpShape, ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 54 |
+
typename InterleavedTileShape, ///< shape of indivisible instruction-level arrangement (concept: GemmShape)
|
| 55 |
+
typename ElementC, ///< Accumulator layout
|
| 56 |
+
typename Layout ///< target shared memory layout
|
| 57 |
+
>
|
| 58 |
+
struct VoltaTensorOpPolicy;
|
| 59 |
+
|
| 60 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 61 |
+
|
| 62 |
+
/// Partial specialization for row-major
|
| 63 |
+
template <
|
| 64 |
+
typename WarpShape_ ///< shape of warp-level GEMM (concept: GemmShape)
|
| 65 |
+
>
|
| 66 |
+
struct VoltaTensorOpPolicy<WarpShape_, gemm::GemmShape<32, 32, 4>, half_t, layout::RowMajor> {
|
| 67 |
+
|
| 68 |
+
using WarpShape = WarpShape_;
|
| 69 |
+
using InterleavedTileShape = gemm::GemmShape<32, 32, 4>;
|
| 70 |
+
using ElementC = half_t;
|
| 71 |
+
using Layout = layout::RowMajor;
|
| 72 |
+
|
| 73 |
+
/// Shape of one warp-levelinstruction
|
| 74 |
+
using InstructionShape = gemm::GemmShape<16, 16, 4>;
|
| 75 |
+
|
| 76 |
+
/// Number of mma operations performed for one 32x32x4 interleaved tile
|
| 77 |
+
using MmaIterations = MatrixShape<
|
| 78 |
+
InterleavedTileShape::kM / InstructionShape::kM,
|
| 79 |
+
InterleavedTileShape::kN / InstructionShape::kN
|
| 80 |
+
>;
|
| 81 |
+
|
| 82 |
+
/// Number of 32x32x4 interleaved tiles performed to cover the warp-level GEMM shape
|
| 83 |
+
using TileIterations = MatrixShape<
|
| 84 |
+
WarpShape::kM / InterleavedTileShape::kM,
|
| 85 |
+
WarpShape::kN / InterleavedTileShape::kN
|
| 86 |
+
>;
|
| 87 |
+
|
| 88 |
+
/// Number of accumulator elements owned by each thread per Mma
|
| 89 |
+
static int const kElementsPerMma = 8;
|
| 90 |
+
static int const kRowsPerIteration = 16;
|
| 91 |
+
|
| 92 |
+
//
|
| 93 |
+
// Hard-coded constants regarding Tensor Operations
|
| 94 |
+
//
|
| 95 |
+
|
| 96 |
+
/// Number of accumulator elements stored per memory instruction to shared memory
|
| 97 |
+
static int const kElementsPerAccess = 4;
|
| 98 |
+
|
| 99 |
+
/// Number of accesses performed per interleaved tile
|
| 100 |
+
static int const kAccessesPerInterleavedTile = 4;
|
| 101 |
+
|
| 102 |
+
/// Total number of iterations needed to cover the entire tile
|
| 103 |
+
static int const kIterations = TileIterations::kRow * 2;
|
| 104 |
+
|
| 105 |
+
//
|
| 106 |
+
// Derived types
|
| 107 |
+
//
|
| 108 |
+
|
| 109 |
+
/// Array type for aligned memory accesses
|
| 110 |
+
using AccessType = AlignedArray<ElementC, kElementsPerAccess>;
|
| 111 |
+
|
| 112 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 113 |
+
using Fragment = Array<
|
| 114 |
+
ElementC,
|
| 115 |
+
kElementsPerAccess * kAccessesPerInterleavedTile * TileIterations::kColumn>;
|
| 116 |
+
|
| 117 |
+
/// This is the complete warp-level accumulator tile.
|
| 118 |
+
using AccumulatorTile = Array<
|
| 119 |
+
ElementC,
|
| 120 |
+
TileIterations::kCount * MmaIterations::kCount * kElementsPerMma>;
|
| 121 |
+
};
|
| 122 |
+
|
| 123 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 124 |
+
|
| 125 |
+
/// Partial specialization for row-major
|
| 126 |
+
template <
|
| 127 |
+
typename WarpShape_ ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 128 |
+
>
|
| 129 |
+
struct VoltaTensorOpPolicy<WarpShape_, gemm::GemmShape<32, 32, 4>, float, layout::RowMajor> {
|
| 130 |
+
|
| 131 |
+
using WarpShape = WarpShape_;
|
| 132 |
+
using InterleavedTileShape = gemm::GemmShape<32, 32, 4>;
|
| 133 |
+
using ElementC = float;
|
| 134 |
+
using Layout = layout::RowMajor;
|
| 135 |
+
|
| 136 |
+
/// Shape of one warp-levelinstruction
|
| 137 |
+
using InstructionShape = gemm::GemmShape<16, 16, 4>;
|
| 138 |
+
|
| 139 |
+
/// Number of mma operations performed for one 32x32x4 interleaved tile
|
| 140 |
+
using MmaIterations = MatrixShape<
|
| 141 |
+
InterleavedTileShape::kM / InstructionShape::kM,
|
| 142 |
+
InterleavedTileShape::kN / InstructionShape::kN
|
| 143 |
+
>;
|
| 144 |
+
|
| 145 |
+
/// Number of 32x32x4 interleaved tiles performed to cover the warp-level GEMM shape
|
| 146 |
+
using TileIterations = MatrixShape<
|
| 147 |
+
WarpShape::kM / InterleavedTileShape::kM,
|
| 148 |
+
WarpShape::kN / InterleavedTileShape::kN
|
| 149 |
+
>;
|
| 150 |
+
|
| 151 |
+
/// Number of accumulator elements owned by each thread per Mma
|
| 152 |
+
static int const kElementsPerMma = 8;
|
| 153 |
+
static int const kRowsPerIteration = 16;
|
| 154 |
+
|
| 155 |
+
//
|
| 156 |
+
// Hard-coded constants regarding Tensor Operations
|
| 157 |
+
//
|
| 158 |
+
|
| 159 |
+
/// Number of accumulator elements stored per memory instruction to shared memory
|
| 160 |
+
static int const kElementsPerAccess = 2;
|
| 161 |
+
|
| 162 |
+
/// Number of accesses performed per interleaved tile
|
| 163 |
+
static int const kAccessesPerInterleavedTile = 8;
|
| 164 |
+
|
| 165 |
+
/// Number of rows per interleaved tile
|
| 166 |
+
static int const kRowsPerMmaTile = 2;
|
| 167 |
+
|
| 168 |
+
/// Total number of iterations needed to cover the entire tile
|
| 169 |
+
static int const kIterations = TileIterations::kRow * MmaIterations::kRow;
|
| 170 |
+
|
| 171 |
+
//
|
| 172 |
+
// Derived types
|
| 173 |
+
//
|
| 174 |
+
|
| 175 |
+
/// Array type for aligned memory accesses
|
| 176 |
+
using AccessType = AlignedArray<ElementC, kElementsPerAccess>;
|
| 177 |
+
|
| 178 |
+
/// This is the fragment size produced by one access of the iterator.
|
| 179 |
+
using Fragment = Array<
|
| 180 |
+
ElementC,
|
| 181 |
+
kElementsPerAccess * kAccessesPerInterleavedTile * TileIterations::kColumn>;
|
| 182 |
+
|
| 183 |
+
/// This is the complete warp-level accumulator tile.
|
| 184 |
+
using AccumulatorTile = Array<
|
| 185 |
+
ElementC,
|
| 186 |
+
TileIterations::kCount * MmaIterations::kCount * kElementsPerMma>;
|
| 187 |
+
};
|
| 188 |
+
|
| 189 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 190 |
+
|
| 191 |
+
} // namespace warp
|
| 192 |
+
} // namespace epilogue
|
| 193 |
+
} // namespace cutlass
|
| 194 |
+
|
| 195 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/wmma_tensor_op_policy.h
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief Defines basic structures needed for implementing the warp-scoped phase of the epilogue.
|
| 33 |
+
These quantities assume a 'column-major' arrangement of TensorOp instructions, of which
|
| 34 |
+
a row-oriented slice is visible per iteration.
|
| 35 |
+
*/
|
| 36 |
+
|
| 37 |
+
#pragma once
|
| 38 |
+
|
| 39 |
+
#include "cutlass/arch/wmma.h"
|
| 40 |
+
#include "cutlass/matrix_shape.h"
|
| 41 |
+
#include "cutlass/layout/matrix.h"
|
| 42 |
+
|
| 43 |
+
#if defined(CUTLASS_ARCH_WMMA_ENABLED)
|
| 44 |
+
|
| 45 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 46 |
+
|
| 47 |
+
namespace cutlass {
|
| 48 |
+
namespace epilogue {
|
| 49 |
+
namespace warp {
|
| 50 |
+
|
| 51 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 52 |
+
|
| 53 |
+
/// Policy details related to the epilogue
|
| 54 |
+
template <
|
| 55 |
+
typename WarpShape, ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 56 |
+
typename OperatorShape, ///< matrix multiply operation shape (concept: gemm:GemmShape)
|
| 57 |
+
typename Layout ///< target shared memory layout
|
| 58 |
+
>
|
| 59 |
+
struct WmmaTensorOpPolicy;
|
| 60 |
+
|
| 61 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 62 |
+
|
| 63 |
+
/// Partial specialization for row-major
|
| 64 |
+
template <
|
| 65 |
+
typename WarpShape, ///< shape of warp-level GEMM (concept: MatrixShape)
|
| 66 |
+
typename OperatorShape ///< matrix multiply operation shape (concept: gemm::GemmShape)
|
| 67 |
+
>
|
| 68 |
+
struct WmmaTensorOpPolicy<WarpShape, OperatorShape, layout::RowMajor> {
|
| 69 |
+
|
| 70 |
+
/// Number of operations
|
| 71 |
+
using OperatorCount = MatrixShape<
|
| 72 |
+
WarpShape::kM / OperatorShape::kM,
|
| 73 |
+
WarpShape::kN / OperatorShape::kN
|
| 74 |
+
>;
|
| 75 |
+
|
| 76 |
+
//
|
| 77 |
+
// Hard-coded constants regarding Tensor Operations
|
| 78 |
+
//
|
| 79 |
+
static int const kElementsPerAccess = 2;
|
| 80 |
+
static int const kRowsPerIteration = OperatorShape::kM;
|
| 81 |
+
static int const kWmmaFragmentsPerAccess = 1;
|
| 82 |
+
|
| 83 |
+
//
|
| 84 |
+
// Derived quantities
|
| 85 |
+
//
|
| 86 |
+
|
| 87 |
+
// Number of externally visible iterations
|
| 88 |
+
static int const kIterations = OperatorCount::kRow;
|
| 89 |
+
|
| 90 |
+
};
|
| 91 |
+
|
| 92 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 93 |
+
|
| 94 |
+
} // namespace warp
|
| 95 |
+
} // namespace epilogue
|
| 96 |
+
} // namespace cutlass
|
| 97 |
+
|
| 98 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 99 |
+
|
| 100 |
+
#endif
|
| 101 |
+
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/exmy_base.h
ADDED
|
@@ -0,0 +1,1222 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
\file
|
| 36 |
+
\brief Generic floating-point type for ExMy format
|
| 37 |
+
*/
|
| 38 |
+
#pragma once
|
| 39 |
+
|
| 40 |
+
#include "cutlass/cutlass.h"
|
| 41 |
+
#include "cutlass/numeric_size.h"
|
| 42 |
+
#include "cutlass/platform/platform.h"
|
| 43 |
+
|
| 44 |
+
// #define CUTLASS_DEBUG_TRACE_LEVEL 2
|
| 45 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 46 |
+
|
| 47 |
+
namespace cutlass {
|
| 48 |
+
// Helper functions
|
| 49 |
+
namespace detail {
|
| 50 |
+
|
| 51 |
+
template <class Src, class Dst>
|
| 52 |
+
CUTLASS_HOST_DEVICE
|
| 53 |
+
Dst copy_bits(Src src)
|
| 54 |
+
{
|
| 55 |
+
Dst dst;
|
| 56 |
+
static_assert(sizeof(Src) <= sizeof(Dst), "Dst type should be at least the same size as Src type");
|
| 57 |
+
static_assert(cutlass::platform::is_trivially_copyable<Dst>::value, "Dst type should be trivially copyable");
|
| 58 |
+
static_assert(cutlass::platform::is_trivially_copyable<
|
| 59 |
+
/*cutlass::platform::remove_cvref_t< */ Dst /* > */ >::value, "Dst type should be trivially copyable");
|
| 60 |
+
memcpy(&dst, &src, sizeof(src));
|
| 61 |
+
return dst;
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
enum class NanInfEncoding
|
| 65 |
+
{
|
| 66 |
+
// IEEE-754 style NaN. Exponent bits are
|
| 67 |
+
// all ones, and at least one bit of mantissa is one
|
| 68 |
+
IEEE_754,
|
| 69 |
+
// Canonical NaN. There is only one value representing NaN and
|
| 70 |
+
// no Inf is defined.
|
| 71 |
+
CANONICAL_ONLY,
|
| 72 |
+
// No NaN or Inf encoded.
|
| 73 |
+
NONE
|
| 74 |
+
};
|
| 75 |
+
|
| 76 |
+
enum class FpEncoding
|
| 77 |
+
{
|
| 78 |
+
E11M52, // double
|
| 79 |
+
E8M23, // float
|
| 80 |
+
E5M2, // FP8
|
| 81 |
+
E4M3, // FP8
|
| 82 |
+
UE4M3, // FP8
|
| 83 |
+
UE8M0, // FP8
|
| 84 |
+
E3M2, // FP6
|
| 85 |
+
E2M3, // FP6
|
| 86 |
+
E2M1, // FP4
|
| 87 |
+
};
|
| 88 |
+
|
| 89 |
+
//////
|
| 90 |
+
|
| 91 |
+
#if (CUTLASS_CXX17_OR_LATER)
|
| 92 |
+
template<uint32_t NumExpBits, uint32_t NumMantissaBits>
|
| 93 |
+
constexpr int exponent_bias_cxx17() {
|
| 94 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (NumExpBits == 0) {
|
| 95 |
+
static_assert(NumMantissaBits <= static_cast<uint32_t>(cutlass::platform::numeric_limits<int32_t>::max()));
|
| 96 |
+
return -1 * static_cast<int>(NumMantissaBits);
|
| 97 |
+
}
|
| 98 |
+
else {
|
| 99 |
+
return static_cast<int>((1 << (NumExpBits - 1))) - 1;
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
CUTLASS_GCC_UNREACHABLE;
|
| 103 |
+
}
|
| 104 |
+
#endif
|
| 105 |
+
|
| 106 |
+
namespace impl {
|
| 107 |
+
template<uint32_t NumExpBitsMinusOne>
|
| 108 |
+
constexpr int shift_num_bits_expression_cxx11() {
|
| 109 |
+
#if (CUTLASS_CXX17_OR_LATER)
|
| 110 |
+
static_assert(NumExpBitsMinusOne <= 31u);
|
| 111 |
+
#endif
|
| 112 |
+
return NumExpBitsMinusOne > 31u ? 31u : NumExpBitsMinusOne;
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
template<uint32_t NumExpBitsMinusOne>
|
| 116 |
+
constexpr int inner_shift_expression_cxx11() {
|
| 117 |
+
return static_cast<int>((1u << shift_num_bits_expression_cxx11<NumExpBitsMinusOne>()) - 1u);
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
} // namespace impl
|
| 121 |
+
|
| 122 |
+
// C++11 equivalent of exponent_bias_cxx17()
|
| 123 |
+
template<uint32_t NumExpBits, uint32_t NumMantissaBits>
|
| 124 |
+
constexpr int exponent_bias_cxx11() {
|
| 125 |
+
#if (CUTLASS_CXX17_OR_LATER)
|
| 126 |
+
return exponent_bias_cxx17<NumExpBits, NumMantissaBits>();
|
| 127 |
+
#else
|
| 128 |
+
return (NumExpBits == 0) ?
|
| 129 |
+
-1 * static_cast<int>(NumMantissaBits) : impl::inner_shift_expression_cxx11<NumExpBits - 1u>();
|
| 130 |
+
#endif
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
// C++11 equivalent of maximum_exponent_cxx17()
|
| 134 |
+
template<uint32_t NumExpBits, uint32_t NumMantissaBits, NanInfEncoding NaNEncoding>
|
| 135 |
+
constexpr int maximum_exponent_cxx11() {
|
| 136 |
+
return
|
| 137 |
+
((NumExpBits == 0) ?
|
| 138 |
+
(0 - exponent_bias_cxx11<NumExpBits, NumMantissaBits>()) :
|
| 139 |
+
((NaNEncoding == NanInfEncoding::IEEE_754) ?
|
| 140 |
+
((static_cast<int>((1 << NumExpBits)) - 2) - exponent_bias_cxx11<NumExpBits, NumMantissaBits>()) :
|
| 141 |
+
((NaNEncoding == NanInfEncoding::CANONICAL_ONLY) ?
|
| 142 |
+
((NumMantissaBits > 0) ?
|
| 143 |
+
static_cast<int>((1 << NumExpBits)) - 1 - exponent_bias_cxx11<NumExpBits, NumMantissaBits>() :
|
| 144 |
+
static_cast<int>((1 << NumExpBits)) - 2 - exponent_bias_cxx11<NumExpBits, NumMantissaBits>()
|
| 145 |
+
) :
|
| 146 |
+
(static_cast<int>((1 << NumExpBits)) - 1 - exponent_bias_cxx11<NumExpBits, NumMantissaBits>())
|
| 147 |
+
)
|
| 148 |
+
)
|
| 149 |
+
);
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
#if (CUTLASS_CXX17_OR_LATER)
|
| 153 |
+
template<uint32_t NumExpBits, uint32_t NumMantissaBits, NanInfEncoding NaNEncoding>
|
| 154 |
+
constexpr int maximum_exponent_cxx17() {
|
| 155 |
+
constexpr int exp_bias = exponent_bias_cxx17<NumExpBits, NumMantissaBits>();
|
| 156 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (NumExpBits == 0) {
|
| 157 |
+
// If no exponent bits, return fixed hidden bias
|
| 158 |
+
return 0 - exp_bias;
|
| 159 |
+
}
|
| 160 |
+
else {
|
| 161 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (NaNEncoding == NanInfEncoding::IEEE_754) {
|
| 162 |
+
// We have IEEE style NaN and infinity
|
| 163 |
+
// All values when exp_bits = 1...1s are used.
|
| 164 |
+
int max_exp_bits = static_cast<int>((1 << NumExpBits)) - 2;
|
| 165 |
+
return max_exp_bits - exp_bias;
|
| 166 |
+
}
|
| 167 |
+
else {
|
| 168 |
+
// There are no cases where we have Inf without IEEE_754_Nan
|
| 169 |
+
|
| 170 |
+
// If we have a canonical NaN. Only exp=1..1 and mantissa=1..1
|
| 171 |
+
// value has a special meaning. If we also have at least one mantissa
|
| 172 |
+
// bit, then maximum exponent is 1...1 - exponent_bias
|
| 173 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (NaNEncoding == NanInfEncoding::CANONICAL_ONLY) {
|
| 174 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (NumMantissaBits > 0) {
|
| 175 |
+
int max_exp_bits = static_cast<int>((1 << NumExpBits)) - 1;
|
| 176 |
+
return max_exp_bits - exp_bias;
|
| 177 |
+
}
|
| 178 |
+
else { // no mantissa bits
|
| 179 |
+
int max_exp_bits = static_cast<int>((1 << NumExpBits)) - 2;
|
| 180 |
+
return max_exp_bits - exp_bias;
|
| 181 |
+
}
|
| 182 |
+
}
|
| 183 |
+
// No NaNs or infs
|
| 184 |
+
int max_exp_bits = static_cast<int>((1 << NumExpBits)) - 1;
|
| 185 |
+
return max_exp_bits - exp_bias;
|
| 186 |
+
}
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
CUTLASS_GCC_UNREACHABLE;
|
| 190 |
+
}
|
| 191 |
+
#endif
|
| 192 |
+
|
| 193 |
+
template<uint32_t NumExpBits, uint32_t NumMantissaBits>
|
| 194 |
+
constexpr int minimum_exponent_cxx11() {
|
| 195 |
+
return
|
| 196 |
+
((NumExpBits == 0) ?
|
| 197 |
+
0 - exponent_bias_cxx11<NumExpBits, NumMantissaBits>() :
|
| 198 |
+
((NumMantissaBits > 0) ?
|
| 199 |
+
1 - exponent_bias_cxx11<NumExpBits, NumMantissaBits>() :
|
| 200 |
+
0 - exponent_bias_cxx11<NumExpBits, NumMantissaBits>())
|
| 201 |
+
);
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
#if (CUTLASS_CXX17_OR_LATER)
|
| 205 |
+
template<uint32_t NumExpBits, uint32_t NumMantissaBits>
|
| 206 |
+
constexpr int minimum_exponent_cxx17() {
|
| 207 |
+
constexpr int exp_bias = exponent_bias_cxx17<NumExpBits, NumMantissaBits>();
|
| 208 |
+
constexpr bool has_denorm = (NumMantissaBits > 0);
|
| 209 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (NumExpBits == 0) {
|
| 210 |
+
// If no exponent bits, return fixed hidden bias
|
| 211 |
+
// Note that minimum and maximum exponents are the same.
|
| 212 |
+
return 0 - exp_bias;
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (has_denorm) {
|
| 216 |
+
// Exp = 0...0s is reserved for denorm values.
|
| 217 |
+
return 1 - exp_bias;
|
| 218 |
+
}
|
| 219 |
+
return 0 - exp_bias;
|
| 220 |
+
}
|
| 221 |
+
#endif
|
| 222 |
+
|
| 223 |
+
template<class Storage, uint32_t NumExpBits, uint32_t NumMantissaBits, NanInfEncoding NaNEncoding>
|
| 224 |
+
constexpr Storage max_pos_denormal_value_cxx11() {
|
| 225 |
+
static_assert(NumExpBits > 0 || NumMantissaBits > 0, "Both NumExpBits and NumMantissaBits can't be zero");
|
| 226 |
+
return
|
| 227 |
+
(!(NumMantissaBits > 0) ? Storage(0) : Storage((1ull << NumMantissaBits) - 1));
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
#if (CUTLASS_CXX17_OR_LATER)
|
| 231 |
+
template<class Storage, uint32_t NumExpBits, uint32_t NumMantissaBits, NanInfEncoding NaNEncoding>
|
| 232 |
+
constexpr Storage max_pos_denormal_value_cxx17() {
|
| 233 |
+
static_assert(NumExpBits > 0 || NumMantissaBits > 0, "Both NumExpBits and NumMantissaBits can't be zero");
|
| 234 |
+
constexpr bool has_denorm = (NumMantissaBits > 0);
|
| 235 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (!has_denorm) {
|
| 236 |
+
// If we don't have denormal values, return all 0s
|
| 237 |
+
return Storage(0);
|
| 238 |
+
}
|
| 239 |
+
else {
|
| 240 |
+
// Case: (NumExpBits > 0 && NumMantissaBits > 0) or (NumExpBits == 0 && NumMantissaBits > 0)
|
| 241 |
+
return Storage((1ull << NumMantissaBits) - 1);
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
CUTLASS_GCC_UNREACHABLE;
|
| 245 |
+
}
|
| 246 |
+
#endif
|
| 247 |
+
|
| 248 |
+
|
| 249 |
+
template<class Storage, uint32_t NumExpBits, uint32_t NumMantissaBits, NanInfEncoding NaNEncoding>
|
| 250 |
+
constexpr Storage min_pos_denormal_value_cxx11() {
|
| 251 |
+
return (!(NumMantissaBits > 0) ? Storage(0) : Storage(1));
|
| 252 |
+
}
|
| 253 |
+
|
| 254 |
+
#if (CUTLASS_CXX17_OR_LATER)
|
| 255 |
+
template<class Storage, uint32_t NumExpBits, uint32_t NumMantissaBits, NanInfEncoding NaNEncoding>
|
| 256 |
+
constexpr Storage min_pos_denormal_value_cxx17() {
|
| 257 |
+
constexpr bool has_denorm = (NumMantissaBits > 0);
|
| 258 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (!has_denorm) {
|
| 259 |
+
// If we don't have denormal values, return all 0s
|
| 260 |
+
return Storage(0);
|
| 261 |
+
}
|
| 262 |
+
// Case: (NumExpBits > 0 && NumMantissaBits > 0) or (NumExpBits == 0 && NumMantissaBits > 0)
|
| 263 |
+
return Storage(1);
|
| 264 |
+
}
|
| 265 |
+
#endif
|
| 266 |
+
|
| 267 |
+
template<class Storage, uint32_t NumExpBits, uint32_t NumMantissaBits, NanInfEncoding NaNEncoding>
|
| 268 |
+
constexpr Storage max_pos_normal_value_cxx11() {
|
| 269 |
+
return
|
| 270 |
+
((NumExpBits == 0) ?
|
| 271 |
+
Storage(0) :
|
| 272 |
+
((NumMantissaBits == 0) ?
|
| 273 |
+
0 :
|
| 274 |
+
(((NaNEncoding == NanInfEncoding::IEEE_754 || NaNEncoding == NanInfEncoding::NONE) ?
|
| 275 |
+
((1ull << NumMantissaBits) - 1) :
|
| 276 |
+
((1ull << NumMantissaBits) - 2)))
|
| 277 |
+
) | (static_cast<Storage>(
|
| 278 |
+
maximum_exponent_cxx11<NumExpBits, NumMantissaBits, NaNEncoding>() +
|
| 279 |
+
exponent_bias_cxx11<NumExpBits, NumMantissaBits>()
|
| 280 |
+
) << NumMantissaBits)
|
| 281 |
+
);
|
| 282 |
+
}
|
| 283 |
+
|
| 284 |
+
#if (CUTLASS_CXX17_OR_LATER)
|
| 285 |
+
template<class Storage, uint32_t NumExpBits, uint32_t NumMantissaBits, NanInfEncoding NaNEncoding>
|
| 286 |
+
constexpr Storage max_pos_normal_value_cxx17() {
|
| 287 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (NumExpBits == 0) {
|
| 288 |
+
// if there are no exponent bits, we don't have normal values.
|
| 289 |
+
return Storage(0);
|
| 290 |
+
}
|
| 291 |
+
constexpr int exp_bias = exponent_bias_cxx17<NumExpBits, NumMantissaBits>();
|
| 292 |
+
constexpr int max_exp = maximum_exponent_cxx17<NumExpBits, NumMantissaBits, NaNEncoding>();
|
| 293 |
+
constexpr int exp = max_exp + exp_bias;
|
| 294 |
+
|
| 295 |
+
// place the exponent
|
| 296 |
+
Storage val = static_cast<Storage>(exp) << NumMantissaBits;
|
| 297 |
+
// If there are no mantissa bits return the exponent
|
| 298 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (NumMantissaBits == 0) {
|
| 299 |
+
return val;
|
| 300 |
+
}
|
| 301 |
+
else {
|
| 302 |
+
// If the NaN Inf encoding follows IEEE 754 or there is no (NaN and Inf) then mantissa can be all 1..1s
|
| 303 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (NaNEncoding == NanInfEncoding::IEEE_754 ||
|
| 304 |
+
NaNEncoding == NanInfEncoding::NONE ) {
|
| 305 |
+
Storage mantissa = (1ull << NumMantissaBits) - 1;
|
| 306 |
+
val |= mantissa;
|
| 307 |
+
}
|
| 308 |
+
else {
|
| 309 |
+
// If we have a canonical NaN, then the exponent can be the maximum bit value
|
| 310 |
+
// but mantissa=1..1s is reserved for NaN.
|
| 311 |
+
Storage mantissa = (1ull << NumMantissaBits) - 2;
|
| 312 |
+
val |= mantissa;
|
| 313 |
+
}
|
| 314 |
+
return val;
|
| 315 |
+
}
|
| 316 |
+
|
| 317 |
+
CUTLASS_GCC_UNREACHABLE;
|
| 318 |
+
}
|
| 319 |
+
#endif
|
| 320 |
+
|
| 321 |
+
template<class Storage, uint32_t NumExpBits, uint32_t NumMantissaBits, NanInfEncoding NaNEncoding>
|
| 322 |
+
constexpr Storage min_pos_normal_value_cxx11() {
|
| 323 |
+
return
|
| 324 |
+
((NumExpBits == 0) ?
|
| 325 |
+
Storage(0) :
|
| 326 |
+
(Storage((NumMantissaBits > 0) ? 1 : 0) << NumMantissaBits)
|
| 327 |
+
);
|
| 328 |
+
}
|
| 329 |
+
|
| 330 |
+
#if (CUTLASS_CXX17_OR_LATER)
|
| 331 |
+
template<class Storage, uint32_t NumExpBits, uint32_t NumMantissaBits, NanInfEncoding NaNEncoding>
|
| 332 |
+
constexpr Storage min_pos_normal_value_cxx17() {
|
| 333 |
+
constexpr bool has_denorm = (NumMantissaBits > 0);
|
| 334 |
+
|
| 335 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (NumExpBits == 0) {
|
| 336 |
+
// if there are no exponent bits, we don't have normal values.
|
| 337 |
+
return Storage(0);
|
| 338 |
+
}
|
| 339 |
+
Storage exp = 0;
|
| 340 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (has_denorm) {
|
| 341 |
+
exp = 1;
|
| 342 |
+
}
|
| 343 |
+
return static_cast<Storage>(exp << NumMantissaBits);
|
| 344 |
+
}
|
| 345 |
+
#endif
|
| 346 |
+
|
| 347 |
+
template<class Storage, uint32_t NumExpBits, uint32_t NumMantissaBits, NanInfEncoding NaNEncoding>
|
| 348 |
+
constexpr Storage max_value_cxx11() {
|
| 349 |
+
return
|
| 350 |
+
((NumExpBits > 0) ?
|
| 351 |
+
max_pos_normal_value_cxx11<Storage, NumExpBits, NumMantissaBits, NaNEncoding>() :
|
| 352 |
+
max_pos_denormal_value_cxx11<Storage, NumExpBits, NumMantissaBits, NaNEncoding>()
|
| 353 |
+
);
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
#if (CUTLASS_CXX17_OR_LATER)
|
| 357 |
+
template<class Storage, uint32_t NumExpBits, uint32_t NumMantissaBits, NanInfEncoding NaNEncoding>
|
| 358 |
+
constexpr Storage max_value_cxx17() {
|
| 359 |
+
constexpr bool has_normal = (NumExpBits > 0);
|
| 360 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (has_normal) {
|
| 361 |
+
return max_pos_normal_value_cxx17<Storage, NumExpBits, NumMantissaBits, NaNEncoding>();
|
| 362 |
+
}
|
| 363 |
+
else {
|
| 364 |
+
return max_pos_denormal_value_cxx17<Storage, NumExpBits, NumMantissaBits, NaNEncoding>();
|
| 365 |
+
}
|
| 366 |
+
|
| 367 |
+
CUTLASS_GCC_UNREACHABLE;
|
| 368 |
+
}
|
| 369 |
+
#endif
|
| 370 |
+
|
| 371 |
+
template<class Storage, uint32_t NumExpBits, uint32_t NumMantissaBits, NanInfEncoding NaNEncoding, bool IsSigned>
|
| 372 |
+
constexpr Storage min_value_cxx11() {
|
| 373 |
+
return
|
| 374 |
+
(IsSigned ?
|
| 375 |
+
Storage(1ull << (NumExpBits + NumMantissaBits)) | max_value_cxx11<Storage, NumExpBits, NumMantissaBits, NaNEncoding>() :
|
| 376 |
+
Storage(0)
|
| 377 |
+
);
|
| 378 |
+
}
|
| 379 |
+
|
| 380 |
+
#if (CUTLASS_CXX17_OR_LATER)
|
| 381 |
+
template<class Storage, uint32_t NumExpBits, uint32_t NumMantissaBits, NanInfEncoding NaNEncoding, bool IsSigned>
|
| 382 |
+
constexpr Storage min_value_cxx17() {
|
| 383 |
+
if (IsSigned) {
|
| 384 |
+
return Storage(1ull << (NumExpBits + NumMantissaBits)) | max_value_cxx17<Storage, NumExpBits, NumMantissaBits, NaNEncoding>();
|
| 385 |
+
}
|
| 386 |
+
else { // Unsigned number
|
| 387 |
+
return Storage(0);
|
| 388 |
+
}
|
| 389 |
+
|
| 390 |
+
CUTLASS_GCC_UNREACHABLE;
|
| 391 |
+
}
|
| 392 |
+
#endif
|
| 393 |
+
|
| 394 |
+
template <
|
| 395 |
+
class StorageType,
|
| 396 |
+
uint32_t NumBits, uint32_t NumExpBits, uint32_t NumMantissaBits,
|
| 397 |
+
NanInfEncoding Nan = NanInfEncoding::IEEE_754, bool IsSigned = true>
|
| 398 |
+
struct FpBitRepresentation {
|
| 399 |
+
public:
|
| 400 |
+
|
| 401 |
+
using Storage = StorageType;
|
| 402 |
+
|
| 403 |
+
#if (CUTLASS_CXX17_OR_LATER)
|
| 404 |
+
static_assert(cutlass::platform::is_unsigned_v<Storage>, "Use an unsigned integer for StorageType");
|
| 405 |
+
#endif
|
| 406 |
+
static constexpr bool IS_SIGNED = IsSigned;
|
| 407 |
+
// Canonical NaN is always represented as exponent=11...11 and mantissa=11...11, if it exists
|
| 408 |
+
static constexpr NanInfEncoding NAN_TYPE = Nan;
|
| 409 |
+
// Inf is always represented as exponent=11...11 and mantissa=00...00, if it exists
|
| 410 |
+
static constexpr bool HAS_INF = (NAN_TYPE == NanInfEncoding::IEEE_754);
|
| 411 |
+
static constexpr bool HAS_NAN = (NAN_TYPE != NanInfEncoding::NONE);
|
| 412 |
+
|
| 413 |
+
static constexpr bool HAS_DENORM = (NumMantissaBits > 0);
|
| 414 |
+
static constexpr bool HAS_NORMAL = !HAS_DENORM;
|
| 415 |
+
|
| 416 |
+
static constexpr uint32_t NUM_BITS = NumBits;
|
| 417 |
+
static constexpr uint32_t NUM_EXPONENT_BITS = NumExpBits;
|
| 418 |
+
static constexpr uint32_t NUM_MANTISSA_BITS = NumMantissaBits;
|
| 419 |
+
static_assert(NUM_BITS >= (NUM_EXPONENT_BITS + NUM_MANTISSA_BITS + uint32_t(IS_SIGNED)), "Number of bits do not match");
|
| 420 |
+
|
| 421 |
+
static constexpr Storage ONE = Storage(1);
|
| 422 |
+
static constexpr Storage ZERO = Storage(0);
|
| 423 |
+
|
| 424 |
+
// Note: Don't rely on operator precedence. Use parenthesis.
|
| 425 |
+
static constexpr Storage EXPONENT_MASK = (Storage(1) << Storage(NUM_EXPONENT_BITS)) - ONE;
|
| 426 |
+
static constexpr Storage MANTISSA_MASK = (Storage(1) << Storage(NUM_MANTISSA_BITS)) - ONE;
|
| 427 |
+
static constexpr Storage EXPONENT_SHIFT = Storage(NUM_MANTISSA_BITS);
|
| 428 |
+
static constexpr Storage SIGN_SHIFT = (IS_SIGNED) ? Storage(NUM_MANTISSA_BITS + NUM_EXPONENT_BITS) : Storage(0);
|
| 429 |
+
|
| 430 |
+
// Note: All biased/real exponent calculation are done with signed ints
|
| 431 |
+
// Use unsigned to represent data not exponent.
|
| 432 |
+
static constexpr int EXP_BIAS = detail::exponent_bias_cxx11<NUM_EXPONENT_BITS, NUM_MANTISSA_BITS>();
|
| 433 |
+
static constexpr int MAX_EXP = detail::maximum_exponent_cxx11<NUM_EXPONENT_BITS, NUM_MANTISSA_BITS, NAN_TYPE>();
|
| 434 |
+
static constexpr int MIN_EXP = detail::minimum_exponent_cxx11<NUM_EXPONENT_BITS, NUM_MANTISSA_BITS>();
|
| 435 |
+
|
| 436 |
+
// Floating-point Limits
|
| 437 |
+
static constexpr Storage MAX_POS_NORMAL_VAL = detail::max_pos_normal_value_cxx11<Storage, NUM_EXPONENT_BITS, NUM_MANTISSA_BITS, NAN_TYPE>();
|
| 438 |
+
static constexpr Storage MAX_POS_DENORMAL_VAL = detail::max_pos_denormal_value_cxx11<Storage, NUM_EXPONENT_BITS, NUM_MANTISSA_BITS, NAN_TYPE>();
|
| 439 |
+
static constexpr Storage MIN_POS_NORMAL_VAL = detail::min_pos_normal_value_cxx11<Storage, NUM_EXPONENT_BITS, NUM_MANTISSA_BITS, NAN_TYPE>();
|
| 440 |
+
static constexpr Storage MIN_POS_DENORMAL_VAL = detail::min_pos_denormal_value_cxx11<Storage, NUM_EXPONENT_BITS, NUM_MANTISSA_BITS, NAN_TYPE>();
|
| 441 |
+
|
| 442 |
+
static constexpr Storage MAX_VALUE = max_value_cxx11<Storage, NUM_EXPONENT_BITS, NUM_MANTISSA_BITS, NAN_TYPE>();
|
| 443 |
+
static constexpr Storage MIN_VALUE = min_value_cxx11<Storage, NUM_EXPONENT_BITS, NUM_MANTISSA_BITS, NAN_TYPE, IS_SIGNED>();
|
| 444 |
+
|
| 445 |
+
//
|
| 446 |
+
// C++17 Verification
|
| 447 |
+
//
|
| 448 |
+
#if (CUTLASS_CXX17_OR_LATER)
|
| 449 |
+
static_assert(EXP_BIAS == detail::exponent_bias_cxx17<NUM_EXPONENT_BITS, NUM_MANTISSA_BITS>(), "Error");
|
| 450 |
+
static_assert(MAX_EXP == detail::maximum_exponent_cxx17<NUM_EXPONENT_BITS, NUM_MANTISSA_BITS, NAN_TYPE>(), "Error");
|
| 451 |
+
static_assert(MIN_EXP == detail::minimum_exponent_cxx17<NUM_EXPONENT_BITS, NUM_MANTISSA_BITS>(), "Error");
|
| 452 |
+
|
| 453 |
+
static_assert(MAX_POS_NORMAL_VAL == detail::max_pos_normal_value_cxx17<Storage, NUM_EXPONENT_BITS, NUM_MANTISSA_BITS, NAN_TYPE>(), "Error");
|
| 454 |
+
static_assert(MAX_POS_DENORMAL_VAL == detail::max_pos_denormal_value_cxx17<Storage, NUM_EXPONENT_BITS, NUM_MANTISSA_BITS, NAN_TYPE>(), "Error");
|
| 455 |
+
static_assert(MIN_POS_NORMAL_VAL == detail::min_pos_normal_value_cxx17<Storage, NUM_EXPONENT_BITS, NUM_MANTISSA_BITS, NAN_TYPE>(), "Error");
|
| 456 |
+
static_assert(MIN_POS_DENORMAL_VAL == detail::min_pos_denormal_value_cxx17<Storage, NUM_EXPONENT_BITS, NUM_MANTISSA_BITS, NAN_TYPE>(), "Error");
|
| 457 |
+
static_assert(MAX_VALUE == max_value_cxx17<Storage, NUM_EXPONENT_BITS, NUM_MANTISSA_BITS, NAN_TYPE>(), "Error");
|
| 458 |
+
static_assert(MIN_VALUE == min_value_cxx17<Storage, NUM_EXPONENT_BITS, NUM_MANTISSA_BITS, NAN_TYPE, IS_SIGNED>(), "Error");
|
| 459 |
+
#endif
|
| 460 |
+
|
| 461 |
+
// If we don't have INF defined, set the largest number. Gives us .satfinite behavior.
|
| 462 |
+
static constexpr Storage INF_MASK = (HAS_INF) ?
|
| 463 |
+
(Storage(EXPONENT_MASK) << Storage(NUM_MANTISSA_BITS)) : MAX_VALUE;
|
| 464 |
+
static constexpr Storage NAN_MASK = (Storage(EXPONENT_MASK) << Storage(NUM_MANTISSA_BITS)) | MANTISSA_MASK;
|
| 465 |
+
|
| 466 |
+
CUTLASS_HOST_DEVICE
|
| 467 |
+
static CUTLASS_CONSTEXPR_IF_CXX17 bool is_inf(Storage flt) {
|
| 468 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (!HAS_INF) {
|
| 469 |
+
return false;
|
| 470 |
+
}
|
| 471 |
+
bool exp_all_ones = (exponent_bits(flt) ^ EXPONENT_MASK) == 0;
|
| 472 |
+
bool mantissa_all_zeros = mantissa_bits(flt) == 0;
|
| 473 |
+
return exp_all_ones && mantissa_all_zeros;
|
| 474 |
+
}
|
| 475 |
+
|
| 476 |
+
CUTLASS_HOST_DEVICE
|
| 477 |
+
static CUTLASS_CONSTEXPR_IF_CXX17 bool is_canonical_nan(Storage flt) {
|
| 478 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (NAN_TYPE == NanInfEncoding::NONE) {
|
| 479 |
+
return false;
|
| 480 |
+
}
|
| 481 |
+
bool exp_all_ones = (exponent_bits(flt) ^ EXPONENT_MASK) == ZERO;
|
| 482 |
+
bool mantissa_all_ones = (mantissa_bits(flt) ^ MANTISSA_MASK) == ZERO;
|
| 483 |
+
return exp_all_ones && mantissa_all_ones;
|
| 484 |
+
}
|
| 485 |
+
|
| 486 |
+
CUTLASS_HOST_DEVICE
|
| 487 |
+
static CUTLASS_CONSTEXPR_IF_CXX17 bool is_nan(Storage flt) {
|
| 488 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (NAN_TYPE == NanInfEncoding::NONE) {
|
| 489 |
+
return false;
|
| 490 |
+
}
|
| 491 |
+
|
| 492 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (NAN_TYPE == NanInfEncoding::CANONICAL_ONLY) {
|
| 493 |
+
return is_canonical_nan(flt);
|
| 494 |
+
}
|
| 495 |
+
|
| 496 |
+
bool exp_all_ones = (exponent_bits(flt) ^ EXPONENT_MASK) == ZERO;
|
| 497 |
+
bool mantissa_has_ones = mantissa_bits(flt) > ZERO;
|
| 498 |
+
return exp_all_ones && mantissa_has_ones;
|
| 499 |
+
}
|
| 500 |
+
|
| 501 |
+
CUTLASS_HOST_DEVICE
|
| 502 |
+
static CUTLASS_CONSTEXPR_IF_CXX17 bool is_denorm(Storage flt) {
|
| 503 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (!HAS_DENORM) {
|
| 504 |
+
return false;
|
| 505 |
+
}
|
| 506 |
+
else if (exponent_bits(flt) == ZERO) {
|
| 507 |
+
// Exponent bits are all 0s
|
| 508 |
+
return true;
|
| 509 |
+
}
|
| 510 |
+
return false;
|
| 511 |
+
}
|
| 512 |
+
|
| 513 |
+
template<typename T = Storage>
|
| 514 |
+
CUTLASS_HOST_DEVICE
|
| 515 |
+
static CUTLASS_CONSTEXPR_IF_CXX17 T sign_bit(T flt) {
|
| 516 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (!IS_SIGNED) {
|
| 517 |
+
return T(0);
|
| 518 |
+
}
|
| 519 |
+
return static_cast<T>(flt >> T(SIGN_SHIFT));
|
| 520 |
+
}
|
| 521 |
+
|
| 522 |
+
template<typename T = Storage>
|
| 523 |
+
CUTLASS_HOST_DEVICE
|
| 524 |
+
static CUTLASS_CONSTEXPR_IF_CXX17 T set_sign_bit(T flt, T sign) {
|
| 525 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (!IS_SIGNED) {
|
| 526 |
+
return flt;
|
| 527 |
+
}
|
| 528 |
+
return static_cast<T>(flt | (sign << T(SIGN_SHIFT)));
|
| 529 |
+
}
|
| 530 |
+
|
| 531 |
+
CUTLASS_HOST_DEVICE
|
| 532 |
+
static CUTLASS_CONSTEXPR_IF_CXX17 Storage exponent_bits(Storage flt) {
|
| 533 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (NUM_EXPONENT_BITS == ZERO) {
|
| 534 |
+
return ZERO;
|
| 535 |
+
}
|
| 536 |
+
return (flt >> (NUM_MANTISSA_BITS)) & EXPONENT_MASK;
|
| 537 |
+
}
|
| 538 |
+
|
| 539 |
+
CUTLASS_HOST_DEVICE
|
| 540 |
+
static CUTLASS_CONSTEXPR_IF_CXX17 int exponent(Storage flt) {
|
| 541 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (NUM_EXPONENT_BITS == ZERO) {
|
| 542 |
+
return -int(EXP_BIAS);
|
| 543 |
+
}
|
| 544 |
+
|
| 545 |
+
if (HAS_DENORM && (exponent_bits(flt) == ZERO)) {
|
| 546 |
+
return 1 - int(EXP_BIAS);
|
| 547 |
+
}
|
| 548 |
+
|
| 549 |
+
return int(flt >> (NUM_MANTISSA_BITS) & EXPONENT_MASK) - int(EXP_BIAS);
|
| 550 |
+
}
|
| 551 |
+
|
| 552 |
+
CUTLASS_HOST_DEVICE
|
| 553 |
+
static CUTLASS_CONSTEXPR_IF_CXX17 Storage mantissa_bits(Storage flt) {
|
| 554 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (NUM_MANTISSA_BITS == ZERO) {
|
| 555 |
+
return ZERO;
|
| 556 |
+
}
|
| 557 |
+
return (flt & MANTISSA_MASK);
|
| 558 |
+
}
|
| 559 |
+
|
| 560 |
+
template <class FpType>
|
| 561 |
+
CUTLASS_HOST_DEVICE
|
| 562 |
+
static CUTLASS_CONSTEXPR_IF_CXX17 Storage to_bits(FpType flt) {
|
| 563 |
+
return copy_bits<FpType, Storage>(flt);
|
| 564 |
+
}
|
| 565 |
+
|
| 566 |
+
template <class DstFpBits>
|
| 567 |
+
CUTLASS_HOST_DEVICE static typename DstFpBits::Storage convert_to(
|
| 568 |
+
Storage src_val,
|
| 569 |
+
DstFpBits dst_encoding) {
|
| 570 |
+
return convert(FpBitRepresentation{}, src_val, dst_encoding);
|
| 571 |
+
}
|
| 572 |
+
|
| 573 |
+
template <class SrcFpBits>
|
| 574 |
+
CUTLASS_HOST_DEVICE
|
| 575 |
+
static CUTLASS_CONSTEXPR_IF_CXX17 Storage convert_from(
|
| 576 |
+
typename SrcFpBits::Storage src_val,
|
| 577 |
+
SrcFpBits src_encoding) {
|
| 578 |
+
return convert(src_encoding, src_val, FpBitRepresentation{});
|
| 579 |
+
}
|
| 580 |
+
|
| 581 |
+
private:
|
| 582 |
+
|
| 583 |
+
template<typename T = Storage>
|
| 584 |
+
CUTLASS_HOST_DEVICE
|
| 585 |
+
static CUTLASS_CONSTEXPR_IF_CXX17 T make_fp_from_bits(T sign, T exp, T mantissa) {
|
| 586 |
+
T fp_bits = T(ZERO);
|
| 587 |
+
CUTLASS_UNUSED(sign);
|
| 588 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (IS_SIGNED) {
|
| 589 |
+
fp_bits = sign << SIGN_SHIFT;
|
| 590 |
+
}
|
| 591 |
+
fp_bits |= (exp << T(NUM_MANTISSA_BITS));
|
| 592 |
+
fp_bits |= (mantissa);
|
| 593 |
+
return fp_bits;
|
| 594 |
+
}
|
| 595 |
+
|
| 596 |
+
CUTLASS_HOST_DEVICE
|
| 597 |
+
static CUTLASS_CONSTEXPR_IF_CXX17 Storage nan_with_sign(Storage sign) {
|
| 598 |
+
Storage fp_bits = NAN_MASK;
|
| 599 |
+
return set_sign_bit(fp_bits, sign);
|
| 600 |
+
}
|
| 601 |
+
|
| 602 |
+
CUTLASS_HOST_DEVICE
|
| 603 |
+
static CUTLASS_CONSTEXPR_IF_CXX17 Storage inf_with_sign(Storage sign) {
|
| 604 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (HAS_INF) {
|
| 605 |
+
Storage fp_bits = INF_MASK;
|
| 606 |
+
return set_sign_bit(fp_bits, sign);
|
| 607 |
+
}
|
| 608 |
+
else {
|
| 609 |
+
// If INF is not defined assume satfinite behavior
|
| 610 |
+
return (sign == ZERO) ? MAX_VALUE : MIN_VALUE;
|
| 611 |
+
}
|
| 612 |
+
|
| 613 |
+
CUTLASS_GCC_UNREACHABLE;
|
| 614 |
+
}
|
| 615 |
+
|
| 616 |
+
CUTLASS_HOST_DEVICE
|
| 617 |
+
static CUTLASS_CONSTEXPR_IF_CXX17 Storage significand(Storage flt) {
|
| 618 |
+
if (is_denorm(flt)) {
|
| 619 |
+
return mantissa_bits(flt);
|
| 620 |
+
}
|
| 621 |
+
else {
|
| 622 |
+
return (ONE << Storage(NUM_MANTISSA_BITS)) | mantissa_bits(flt);
|
| 623 |
+
}
|
| 624 |
+
|
| 625 |
+
CUTLASS_GCC_UNREACHABLE;
|
| 626 |
+
}
|
| 627 |
+
|
| 628 |
+
template<typename T>
|
| 629 |
+
CUTLASS_HOST_DEVICE
|
| 630 |
+
static CUTLASS_CONSTEXPR_IF_CXX17 T significand_hidden_bits(T significand) {
|
| 631 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (NUM_MANTISSA_BITS == 0) {
|
| 632 |
+
return T(1);
|
| 633 |
+
}
|
| 634 |
+
return ((T(0b11) << T(NUM_MANTISSA_BITS)) & significand) >> T(NUM_MANTISSA_BITS);
|
| 635 |
+
}
|
| 636 |
+
|
| 637 |
+
// Current assumption round to nearest even
|
| 638 |
+
template<class T>
|
| 639 |
+
CUTLASS_HOST_DEVICE
|
| 640 |
+
static CUTLASS_CONSTEXPR_IF_CXX17 T round_significand(T src, int shift_amount) {
|
| 641 |
+
T dst_mantissa = src;
|
| 642 |
+
// If the shift amount is positive, we are shifting left
|
| 643 |
+
// Type with less mantissa bits is rounded to a type with more
|
| 644 |
+
// mantissa bits.
|
| 645 |
+
if (shift_amount > 0) {
|
| 646 |
+
dst_mantissa = (dst_mantissa << (shift_amount));
|
| 647 |
+
}
|
| 648 |
+
else {
|
| 649 |
+
// There are fewer mantissa bits in the target type
|
| 650 |
+
// we need to round the destination number up for all
|
| 651 |
+
// lower precision bits removed.
|
| 652 |
+
// We assume round-to-nearest-even here.
|
| 653 |
+
int pos_shift_amount = -shift_amount;
|
| 654 |
+
|
| 655 |
+
// Too large shift return all zeros to prevent undefined behavior for shift.
|
| 656 |
+
if (pos_shift_amount >= static_cast<int>(sizeof(T) * 8)) {
|
| 657 |
+
return T(0);
|
| 658 |
+
}
|
| 659 |
+
|
| 660 |
+
T guard_bit_mask = (T(1) << T(pos_shift_amount)); // Last bit to remain in mantissa
|
| 661 |
+
T sticky_mask = (T(1) << T(pos_shift_amount - 1)) - T(1); // Remaining bits
|
| 662 |
+
T round_bit_mask = (T(1) << T(pos_shift_amount - 1)); // First bit removed from mantissa
|
| 663 |
+
|
| 664 |
+
bool sticky_bit = (src & sticky_mask) >= T(1); // ORing all sticky bits
|
| 665 |
+
bool round_bit = (src & round_bit_mask) >= T(1);
|
| 666 |
+
bool guard_bit = (src & guard_bit_mask) >= T(1);
|
| 667 |
+
|
| 668 |
+
// Shift mantissa bits to right to remove lowest precision bits
|
| 669 |
+
dst_mantissa = dst_mantissa >> pos_shift_amount;
|
| 670 |
+
|
| 671 |
+
if ((sticky_bit && round_bit) || (guard_bit && round_bit && !sticky_bit)) {
|
| 672 |
+
dst_mantissa += 1;
|
| 673 |
+
}
|
| 674 |
+
}
|
| 675 |
+
return dst_mantissa;
|
| 676 |
+
}
|
| 677 |
+
|
| 678 |
+
template <class SrcFpBits, class DstFpBits>
|
| 679 |
+
CUTLASS_HOST_DEVICE
|
| 680 |
+
static typename DstFpBits::Storage convert(
|
| 681 |
+
SrcFpBits src_encoding,
|
| 682 |
+
typename SrcFpBits::Storage src_val,
|
| 683 |
+
DstFpBits dst_encoding) {
|
| 684 |
+
|
| 685 |
+
using SrcT = typename SrcFpBits::Storage;
|
| 686 |
+
using DstT = typename DstFpBits::Storage;
|
| 687 |
+
using LargeStorage = typename cutlass::platform::conditional<(sizeof(SrcT) > sizeof(DstT)), SrcT, DstT>::type;
|
| 688 |
+
|
| 689 |
+
LargeStorage src_sign_bit = src_encoding.sign_bit(src_val);
|
| 690 |
+
|
| 691 |
+
// If the source is NaN, set the destination to NaN carrying the sign bit
|
| 692 |
+
if (src_encoding.is_nan(src_val)) {
|
| 693 |
+
return dst_encoding.nan_with_sign(DstT(src_sign_bit));
|
| 694 |
+
}
|
| 695 |
+
// If the source is INF, set the destination to INF carrying the sign bit
|
| 696 |
+
else if (src_encoding.is_inf(src_val)) {
|
| 697 |
+
return dst_encoding.set_sign_bit(DstFpBits::INF_MASK, DstT(src_sign_bit));
|
| 698 |
+
}
|
| 699 |
+
// Number is not NaN or INF: Zero and others
|
| 700 |
+
|
| 701 |
+
LargeStorage src_exp_bits = src_encoding.exponent_bits(src_val);
|
| 702 |
+
LargeStorage src_significand = src_encoding.significand(src_val);
|
| 703 |
+
int src_exp = src_encoding.exponent(src_val);
|
| 704 |
+
|
| 705 |
+
// The source value is 0. Return a signed 0.
|
| 706 |
+
if (src_exp_bits == LargeStorage(0) && src_significand == LargeStorage(0)) {
|
| 707 |
+
return dst_encoding.set_sign_bit(DstT(0), DstT(src_sign_bit));
|
| 708 |
+
}
|
| 709 |
+
|
| 710 |
+
#if (CUTLASS_DEBUG_TRACE_LEVEL > 1)
|
| 711 |
+
printf("(1) src_sign: %llu src_exp_bits %llx src_exp %d src_significand %llx\n",
|
| 712 |
+
static_cast<unsigned long long>(src_sign_bit), static_cast<unsigned long long>(src_exp_bits), src_exp, static_cast<unsigned long long>(src_significand));
|
| 713 |
+
#endif
|
| 714 |
+
// Normalize the number: Left shift the significand bits until hidden "1" appears.
|
| 715 |
+
// Only needed if the src value is denormal.
|
| 716 |
+
// Conditions:
|
| 717 |
+
// If the exponent is 0, then the significand can't be 0 (src_val==0 case handled above):
|
| 718 |
+
// there is at least one "1" bit in the significand. Loop executes.
|
| 719 |
+
// If the exponent is not 0, then the number is normal:
|
| 720 |
+
// significand has hidden bit set. Loop doesn't execute.
|
| 721 |
+
// Assumption: Zero is always defined for the floating point types and detected above
|
| 722 |
+
|
| 723 |
+
while (src_encoding.significand_hidden_bits(src_significand) == LargeStorage(0)) {
|
| 724 |
+
src_significand <<= LargeStorage(1);
|
| 725 |
+
src_exp--;
|
| 726 |
+
}
|
| 727 |
+
|
| 728 |
+
#if (CUTLASS_DEBUG_TRACE_LEVEL > 1)
|
| 729 |
+
printf("(2) src_sign: %llu src_exp_bits %llx src_exp %d src_significand %llx\n",
|
| 730 |
+
static_cast<unsigned long long>(src_sign_bit), static_cast<unsigned long long>(src_exp_bits), src_exp, static_cast<unsigned long long>(src_significand));
|
| 731 |
+
#endif
|
| 732 |
+
// The exponent exceeds DstFormat's exponent capacity
|
| 733 |
+
// Return positive/negative infinity.
|
| 734 |
+
// If no INF is defined, return positive/negative largest value.
|
| 735 |
+
if (src_exp > DstFpBits::MAX_EXP) {
|
| 736 |
+
return dst_encoding.set_sign_bit(DstFpBits::INF_MASK, DstT(src_sign_bit));
|
| 737 |
+
}
|
| 738 |
+
else if (src_exp <= DstFpBits::MAX_EXP && src_exp >= DstFpBits::MIN_EXP) {
|
| 739 |
+
#if (CUTLASS_DEBUG_TRACE_LEVEL > 1)
|
| 740 |
+
printf("(3) Exp match: src_sign: %d src_exp_bits: %x src_exp: %d src_significand: %x\n",
|
| 741 |
+
src_sign_bit, src_exp_bits, src_exp, src_significand);
|
| 742 |
+
#endif
|
| 743 |
+
|
| 744 |
+
int shift_amount = int(DstFpBits::NUM_MANTISSA_BITS) - int(SrcFpBits::NUM_MANTISSA_BITS);
|
| 745 |
+
int dst_exponent = src_exp + DstFpBits::EXP_BIAS;
|
| 746 |
+
LargeStorage dst_mantissa = src_significand;
|
| 747 |
+
|
| 748 |
+
// if we have an M0 case, the floating point number is always denormal.
|
| 749 |
+
// Therefore, if exponents are equal, we need to check whether it is inf
|
| 750 |
+
if (DstFpBits::NUM_EXPONENT_BITS == 0) {
|
| 751 |
+
if (dst_mantissa > DstFpBits::INF_MASK) {
|
| 752 |
+
return dst_encoding.inf_with_sign(DstT(src_sign_bit));
|
| 753 |
+
}
|
| 754 |
+
}
|
| 755 |
+
|
| 756 |
+
// Round to nearest even
|
| 757 |
+
dst_mantissa = round_significand(dst_mantissa, shift_amount);
|
| 758 |
+
|
| 759 |
+
#if (CUTLASS_DEBUG_TRACE_LEVEL > 1)
|
| 760 |
+
printf("(4) after rounding src_sign: %d dst_exponent: %d dst_mantissa: %x\n",
|
| 761 |
+
src_sign_bit, dst_exponent, dst_mantissa);
|
| 762 |
+
#endif
|
| 763 |
+
|
| 764 |
+
if (dst_encoding.significand_hidden_bits(dst_mantissa) > 0b1) {
|
| 765 |
+
// Significant became larger than 01.X...X. Divide significand by 2 and multiply exp by 2
|
| 766 |
+
while (dst_exponent < (DstFpBits::MAX_EXP+DstFpBits::EXP_BIAS) &&
|
| 767 |
+
dst_encoding.significand_hidden_bits(dst_mantissa) > LargeStorage(0b1)) {
|
| 768 |
+
dst_mantissa >>= LargeStorage(1);
|
| 769 |
+
dst_exponent++;
|
| 770 |
+
}
|
| 771 |
+
|
| 772 |
+
#if (CUTLASS_DEBUG_TRACE_LEVEL > 1)
|
| 773 |
+
printf("(5) after rounding max_exp: %d src_sign: %d dst_exponent: %d dst_mantissa: %x\n",
|
| 774 |
+
DstFpBits::MAX_EXP,src_sign_bit, dst_exponent, dst_mantissa);
|
| 775 |
+
#endif
|
| 776 |
+
|
| 777 |
+
if (dst_encoding.significand_hidden_bits(dst_mantissa) > LargeStorage(0b1)) {
|
| 778 |
+
return dst_encoding.set_sign_bit(DstFpBits::INF_MASK, DstT(src_sign_bit));
|
| 779 |
+
}
|
| 780 |
+
}
|
| 781 |
+
|
| 782 |
+
dst_mantissa = dst_mantissa & DstFpBits::MANTISSA_MASK;
|
| 783 |
+
static_assert(sizeof(LargeStorage) >= sizeof(decltype(dst_exponent)),
|
| 784 |
+
"sizeof(LargeStorage) must be greater than or equal to sizeof(decltype(dst_exponent))");
|
| 785 |
+
LargeStorage dst_exponent_bits = static_cast<LargeStorage>(dst_exponent);
|
| 786 |
+
|
| 787 |
+
DstT final_val = static_cast<DstT>(dst_encoding.template make_fp_from_bits<LargeStorage>(src_sign_bit, dst_exponent_bits, dst_mantissa));
|
| 788 |
+
|
| 789 |
+
#if (CUTLASS_DEBUG_TRACE_LEVEL > 1)
|
| 790 |
+
printf("(6) Final Value src_sign: %d dst_exp_bits: %x dst_mantissa: %x\n",
|
| 791 |
+
src_sign_bit, dst_exponent_bits, dst_mantissa);
|
| 792 |
+
#endif
|
| 793 |
+
|
| 794 |
+
if (DstFpBits::is_nan(final_val)) {
|
| 795 |
+
// This NAN is generated when:
|
| 796 |
+
// Src is not an Nan
|
| 797 |
+
// the exp of Src == the max_exp of Dst.
|
| 798 |
+
// The mantissa becomes all-1s after rounding.
|
| 799 |
+
// Return max value of Dst (not NAN) as it just couldn't be represented in the range of Dst.
|
| 800 |
+
return dst_encoding.set_sign_bit(DstFpBits::INF_MASK, DstT(src_sign_bit));
|
| 801 |
+
}
|
| 802 |
+
else {
|
| 803 |
+
return final_val;
|
| 804 |
+
}
|
| 805 |
+
}
|
| 806 |
+
else {
|
| 807 |
+
// Result is denormal
|
| 808 |
+
#if (CUTLASS_DEBUG_TRACE_LEVEL > 1)
|
| 809 |
+
printf("(7) Denormal case src_sign: %d src_exp: %d src_significand: %x MIN_EXP: %d\n",
|
| 810 |
+
src_sign_bit, src_exp, src_significand, DstFpBits::MIN_EXP);
|
| 811 |
+
#endif
|
| 812 |
+
|
| 813 |
+
int exp_diff = src_exp - DstFpBits::MIN_EXP;
|
| 814 |
+
int shift_amount = int(DstFpBits::NUM_MANTISSA_BITS) - int(SrcFpBits::NUM_MANTISSA_BITS);
|
| 815 |
+
shift_amount += exp_diff;
|
| 816 |
+
LargeStorage dst_mantissa = src_significand;
|
| 817 |
+
dst_mantissa = round_significand(dst_mantissa, shift_amount);
|
| 818 |
+
|
| 819 |
+
if (dst_encoding.significand_hidden_bits(dst_mantissa) >= LargeStorage(0b1)) {
|
| 820 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (DstFpBits::NUM_EXPONENT_BITS == 0) {
|
| 821 |
+
return dst_encoding.inf_with_sign(DstT(src_sign_bit));
|
| 822 |
+
}
|
| 823 |
+
else {
|
| 824 |
+
LargeStorage dst_exp_bits = 1;
|
| 825 |
+
dst_mantissa &= DstFpBits::MANTISSA_MASK;
|
| 826 |
+
DstT final_val = static_cast<DstT>(dst_encoding.template make_fp_from_bits<LargeStorage>(src_sign_bit, dst_exp_bits, dst_mantissa));
|
| 827 |
+
return final_val;
|
| 828 |
+
}
|
| 829 |
+
}
|
| 830 |
+
#if (CUTLASS_DEBUG_TRACE_LEVEL > 1)
|
| 831 |
+
printf("(7.1) Denormal case exp_diff: %d shift_amount: %d dst_mantissa %d\n", exp_diff, shift_amount, dst_mantissa);
|
| 832 |
+
#endif
|
| 833 |
+
dst_mantissa &= DstFpBits::MANTISSA_MASK;
|
| 834 |
+
|
| 835 |
+
#if (CUTLASS_DEBUG_TRACE_LEVEL > 1)
|
| 836 |
+
printf("(8) Final Value src_sign: %d src_exp: %d dst_mantissa: %x\n",
|
| 837 |
+
src_sign_bit, src_exp, dst_mantissa);
|
| 838 |
+
#endif
|
| 839 |
+
|
| 840 |
+
DstT final_val = static_cast<DstT>(dst_encoding.template make_fp_from_bits<LargeStorage>(src_sign_bit, LargeStorage(0), dst_mantissa));
|
| 841 |
+
return final_val;
|
| 842 |
+
}
|
| 843 |
+
|
| 844 |
+
return DstT(0);
|
| 845 |
+
}
|
| 846 |
+
|
| 847 |
+
template <class StorageType_, uint32_t NumBits_, uint32_t NumExpBits_,
|
| 848 |
+
uint32_t NumMantissaBits_, NanInfEncoding Nan_, bool IsSigned_>
|
| 849 |
+
friend struct FpBitRepresentation;
|
| 850 |
+
};
|
| 851 |
+
|
| 852 |
+
#if (CUTLASS_CXX17_OR_LATER)
|
| 853 |
+
|
| 854 |
+
template<FpEncoding FpExMyCode>
|
| 855 |
+
CUTLASS_CONSTEXPR_IF_CXX17 auto fp_encoding_selector() {
|
| 856 |
+
if CUTLASS_CONSTEXPR_IF_CXX17 (FpExMyCode == FpEncoding::E11M52) { // double
|
| 857 |
+
return cutlass::detail::FpBitRepresentation<uint64_t, 64, 11, 52, cutlass::detail::NanInfEncoding::IEEE_754>{};
|
| 858 |
+
}
|
| 859 |
+
else if CUTLASS_CONSTEXPR_IF_CXX17 (FpExMyCode == FpEncoding::E8M23) { // float
|
| 860 |
+
return cutlass::detail::FpBitRepresentation<uint32_t, 32, 8, 23, cutlass::detail::NanInfEncoding::IEEE_754>{};
|
| 861 |
+
}
|
| 862 |
+
else if CUTLASS_CONSTEXPR_IF_CXX17 (FpExMyCode == FpEncoding::E5M2) { // FP8
|
| 863 |
+
return cutlass::detail::FpBitRepresentation<uint8_t, 8, 5, 2, cutlass::detail::NanInfEncoding::IEEE_754>{};
|
| 864 |
+
}
|
| 865 |
+
else if CUTLASS_CONSTEXPR_IF_CXX17 (FpExMyCode == FpEncoding::E4M3) { // FP8
|
| 866 |
+
return cutlass::detail::FpBitRepresentation<uint8_t, 8, 4, 3, cutlass::detail::NanInfEncoding::CANONICAL_ONLY>{};
|
| 867 |
+
}
|
| 868 |
+
|
| 869 |
+
else if CUTLASS_CONSTEXPR_IF_CXX17 (FpExMyCode == FpEncoding::UE4M3) { // FP8
|
| 870 |
+
return cutlass::detail::FpBitRepresentation<uint8_t, 8, 4, 3, cutlass::detail::NanInfEncoding::CANONICAL_ONLY, false>{};
|
| 871 |
+
}
|
| 872 |
+
|
| 873 |
+
else if CUTLASS_CONSTEXPR_IF_CXX17 (FpExMyCode == FpEncoding::UE8M0) { // FP8
|
| 874 |
+
return cutlass::detail::FpBitRepresentation<uint8_t, 8, 8, 0, cutlass::detail::NanInfEncoding::CANONICAL_ONLY, false>{};
|
| 875 |
+
}
|
| 876 |
+
else if CUTLASS_CONSTEXPR_IF_CXX17 (FpExMyCode == FpEncoding::E3M2) { // FP6
|
| 877 |
+
return cutlass::detail::FpBitRepresentation<uint8_t, 6, 3, 2, cutlass::detail::NanInfEncoding::NONE>{};
|
| 878 |
+
}
|
| 879 |
+
else if CUTLASS_CONSTEXPR_IF_CXX17 (FpExMyCode == FpEncoding::E2M3) { // FP6
|
| 880 |
+
return cutlass::detail::FpBitRepresentation<uint8_t, 6, 2, 3, cutlass::detail::NanInfEncoding::NONE>{};
|
| 881 |
+
}
|
| 882 |
+
else if CUTLASS_CONSTEXPR_IF_CXX17 (FpExMyCode == FpEncoding::E2M1) { // FP4
|
| 883 |
+
return cutlass::detail::FpBitRepresentation<uint8_t, 4, 2, 1, cutlass::detail::NanInfEncoding::NONE>{};
|
| 884 |
+
}
|
| 885 |
+
CUTLASS_GCC_UNREACHABLE;
|
| 886 |
+
}
|
| 887 |
+
|
| 888 |
+
#else
|
| 889 |
+
//
|
| 890 |
+
// Definitions for floating point encodings.
|
| 891 |
+
//
|
| 892 |
+
|
| 893 |
+
template <FpEncoding FpExMyCode> struct FpEncodingSelector {
|
| 894 |
+
using type = void;
|
| 895 |
+
};
|
| 896 |
+
|
| 897 |
+
template <> struct FpEncodingSelector<FpEncoding::E11M52> {
|
| 898 |
+
using type = cutlass::detail::FpBitRepresentation<uint64_t, 64, 11, 52, cutlass::detail::NanInfEncoding::IEEE_754>;
|
| 899 |
+
};
|
| 900 |
+
|
| 901 |
+
template <> struct FpEncodingSelector<FpEncoding::E8M23> {
|
| 902 |
+
using type = cutlass::detail::FpBitRepresentation<uint32_t, 32, 8, 23, cutlass::detail::NanInfEncoding::IEEE_754>;
|
| 903 |
+
};
|
| 904 |
+
template <> struct FpEncodingSelector<FpEncoding::E5M2> {
|
| 905 |
+
using type = cutlass::detail::FpBitRepresentation<uint8_t, 8, 5, 2, cutlass::detail::NanInfEncoding::IEEE_754>;
|
| 906 |
+
};
|
| 907 |
+
|
| 908 |
+
template <> struct FpEncodingSelector<FpEncoding::E4M3> {
|
| 909 |
+
using type = cutlass::detail::FpBitRepresentation<uint8_t, 8, 4, 3, cutlass::detail::NanInfEncoding::CANONICAL_ONLY>;
|
| 910 |
+
};
|
| 911 |
+
|
| 912 |
+
template <> struct FpEncodingSelector<FpEncoding::UE4M3> {
|
| 913 |
+
using type = cutlass::detail::FpBitRepresentation<uint8_t, 8, 4, 3, cutlass::detail::NanInfEncoding::CANONICAL_ONLY, false>;
|
| 914 |
+
};
|
| 915 |
+
|
| 916 |
+
template <> struct FpEncodingSelector<FpEncoding::UE8M0> {
|
| 917 |
+
using type = cutlass::detail::FpBitRepresentation<uint8_t, 8, 8, 0, cutlass::detail::NanInfEncoding::CANONICAL_ONLY, false>;
|
| 918 |
+
};
|
| 919 |
+
|
| 920 |
+
template <> struct FpEncodingSelector<FpEncoding::E3M2> {
|
| 921 |
+
using type = cutlass::detail::FpBitRepresentation<uint8_t, 6, 3, 2, cutlass::detail::NanInfEncoding::NONE>;
|
| 922 |
+
};
|
| 923 |
+
|
| 924 |
+
template <> struct FpEncodingSelector<FpEncoding::E2M3> {
|
| 925 |
+
using type = cutlass::detail::FpBitRepresentation<uint8_t, 6, 2, 3, cutlass::detail::NanInfEncoding::NONE>;
|
| 926 |
+
};
|
| 927 |
+
|
| 928 |
+
template <> struct FpEncodingSelector<FpEncoding::E2M1> {
|
| 929 |
+
using type = cutlass::detail::FpBitRepresentation<uint8_t, 4, 2, 1, cutlass::detail::NanInfEncoding::NONE>;
|
| 930 |
+
};
|
| 931 |
+
#endif
|
| 932 |
+
|
| 933 |
+
} // namespace detail
|
| 934 |
+
|
| 935 |
+
template <detail::FpEncoding T, class Derived>
|
| 936 |
+
struct float_exmy_base
|
| 937 |
+
{
|
| 938 |
+
|
| 939 |
+
static constexpr detail::FpEncoding Encoding = T;
|
| 940 |
+
using BitRepresentation =
|
| 941 |
+
#if (CUTLASS_CXX17_OR_LATER)
|
| 942 |
+
decltype(detail::fp_encoding_selector<T>())
|
| 943 |
+
#else
|
| 944 |
+
typename detail::FpEncodingSelector<T>::type
|
| 945 |
+
#endif
|
| 946 |
+
;
|
| 947 |
+
|
| 948 |
+
using FP32BitRepresentation =
|
| 949 |
+
#if (CUTLASS_CXX17_OR_LATER)
|
| 950 |
+
decltype(cutlass::detail::fp_encoding_selector<cutlass::detail::FpEncoding::E8M23>())
|
| 951 |
+
#else
|
| 952 |
+
typename detail::FpEncodingSelector<cutlass::detail::FpEncoding::E8M23>::type
|
| 953 |
+
#endif
|
| 954 |
+
;
|
| 955 |
+
|
| 956 |
+
using Storage = typename BitRepresentation::Storage;
|
| 957 |
+
|
| 958 |
+
//
|
| 959 |
+
// Data members
|
| 960 |
+
//
|
| 961 |
+
|
| 962 |
+
/// Data container
|
| 963 |
+
Storage storage;
|
| 964 |
+
|
| 965 |
+
/// Ctors.
|
| 966 |
+
float_exmy_base() = default;
|
| 967 |
+
|
| 968 |
+
CUTLASS_HOST_DEVICE
|
| 969 |
+
float_exmy_base(Storage s) : storage(s) {
|
| 970 |
+
}
|
| 971 |
+
|
| 972 |
+
/// Is finite implementation
|
| 973 |
+
CUTLASS_HOST_DEVICE
|
| 974 |
+
static bool isfinite(float_exmy_base flt) {
|
| 975 |
+
return !BitRepresentation::is_inf(flt.storage);
|
| 976 |
+
}
|
| 977 |
+
|
| 978 |
+
/// Is NaN implementation
|
| 979 |
+
CUTLASS_HOST_DEVICE
|
| 980 |
+
static bool isnan(float_exmy_base flt) {
|
| 981 |
+
return BitRepresentation::is_nan(flt.storage);
|
| 982 |
+
}
|
| 983 |
+
|
| 984 |
+
/// Is infinite implementation
|
| 985 |
+
CUTLASS_HOST_DEVICE
|
| 986 |
+
static bool isinf(float_exmy_base flt) {
|
| 987 |
+
return BitRepresentation::is_inf(flt.storage);
|
| 988 |
+
}
|
| 989 |
+
|
| 990 |
+
/// Is infinite implementation
|
| 991 |
+
CUTLASS_HOST_DEVICE
|
| 992 |
+
static bool isnormal(float_exmy_base flt) {
|
| 993 |
+
return !BitRepresentation::is_denorm(flt.storage);
|
| 994 |
+
}
|
| 995 |
+
|
| 996 |
+
CUTLASS_HOST_DEVICE
|
| 997 |
+
static float_exmy_base<T, Derived> bitcast(Storage x) {
|
| 998 |
+
float_exmy_base f;
|
| 999 |
+
f.storage = x;
|
| 1000 |
+
return f;
|
| 1001 |
+
}
|
| 1002 |
+
|
| 1003 |
+
CUTLASS_HOST_DEVICE
|
| 1004 |
+
float_exmy_base convert_from_float(float const &flt) const {
|
| 1005 |
+
FP32BitRepresentation::Storage fp32_bits = FP32BitRepresentation::to_bits(flt);
|
| 1006 |
+
float_exmy_base float_exmy;
|
| 1007 |
+
float_exmy.storage = BitRepresentation::convert_from(fp32_bits, FP32BitRepresentation{});
|
| 1008 |
+
return float_exmy;
|
| 1009 |
+
}
|
| 1010 |
+
|
| 1011 |
+
CUTLASS_HOST_DEVICE
|
| 1012 |
+
float convert_to_float(float_exmy_base<T, Derived> const &x) const {
|
| 1013 |
+
FP32BitRepresentation::Storage fp32_bits;
|
| 1014 |
+
fp32_bits = BitRepresentation::convert_to(x.storage, FP32BitRepresentation{});
|
| 1015 |
+
return detail::copy_bits<FP32BitRepresentation::Storage, float>(fp32_bits);
|
| 1016 |
+
}
|
| 1017 |
+
|
| 1018 |
+
// Note: Only consider float/int conversions in this Base class
|
| 1019 |
+
// Types inheriting from this class should define their own constructors and
|
| 1020 |
+
// specialized type conversions
|
| 1021 |
+
|
| 1022 |
+
/// Floating point conversion
|
| 1023 |
+
CUTLASS_HOST_DEVICE
|
| 1024 |
+
explicit float_exmy_base<T, Derived>(float x) {
|
| 1025 |
+
storage = static_cast<Derived*>(this)->convert_from_float(x).storage;
|
| 1026 |
+
}
|
| 1027 |
+
|
| 1028 |
+
// Integer conversion
|
| 1029 |
+
CUTLASS_HOST_DEVICE
|
| 1030 |
+
explicit float_exmy_base<T, Derived>(int x) {
|
| 1031 |
+
storage = static_cast<Derived*>(this)->convert_from_float(float(x)).storage;
|
| 1032 |
+
}
|
| 1033 |
+
|
| 1034 |
+
CUTLASS_HOST_DEVICE
|
| 1035 |
+
explicit float_exmy_base<T, Derived>(unsigned x) {
|
| 1036 |
+
storage = static_cast<Derived*>(this)->convert_from_float(float(x)).storage;
|
| 1037 |
+
}
|
| 1038 |
+
|
| 1039 |
+
/// Converts to float
|
| 1040 |
+
CUTLASS_HOST_DEVICE
|
| 1041 |
+
operator float() const {
|
| 1042 |
+
return static_cast<const Derived*>(this)->convert_to_float(*this);
|
| 1043 |
+
}
|
| 1044 |
+
|
| 1045 |
+
/// Converts to int
|
| 1046 |
+
CUTLASS_HOST_DEVICE
|
| 1047 |
+
explicit operator int() const {
|
| 1048 |
+
return int(static_cast<const Derived*>(this)->convert_to_float(*this));
|
| 1049 |
+
}
|
| 1050 |
+
|
| 1051 |
+
/// Accesses raw internal state
|
| 1052 |
+
CUTLASS_HOST_DEVICE
|
| 1053 |
+
Storage &raw() {
|
| 1054 |
+
return storage;
|
| 1055 |
+
}
|
| 1056 |
+
|
| 1057 |
+
/// Accesses raw internal state
|
| 1058 |
+
CUTLASS_HOST_DEVICE
|
| 1059 |
+
Storage raw() const {
|
| 1060 |
+
return storage;
|
| 1061 |
+
}
|
| 1062 |
+
|
| 1063 |
+
/// Returns the sign bit
|
| 1064 |
+
CUTLASS_HOST_DEVICE
|
| 1065 |
+
bool signbit() const {
|
| 1066 |
+
return bool(BitRepresentation::sign_bit(storage));
|
| 1067 |
+
}
|
| 1068 |
+
|
| 1069 |
+
/// Returns the biased exponent
|
| 1070 |
+
CUTLASS_HOST_DEVICE
|
| 1071 |
+
int exponent_biased() const {
|
| 1072 |
+
return int(BitRepresentation::exponent_bits(storage));
|
| 1073 |
+
}
|
| 1074 |
+
|
| 1075 |
+
/// Returns the unbiased exponent
|
| 1076 |
+
CUTLASS_HOST_DEVICE
|
| 1077 |
+
int exponent() const {
|
| 1078 |
+
return int(BitRepresentation::exponent(storage));
|
| 1079 |
+
}
|
| 1080 |
+
|
| 1081 |
+
/// Returns the mantissa
|
| 1082 |
+
CUTLASS_HOST_DEVICE
|
| 1083 |
+
int mantissa() const {
|
| 1084 |
+
return int(BitRepresentation::mantissa_bits(storage));
|
| 1085 |
+
}
|
| 1086 |
+
|
| 1087 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1088 |
+
//
|
| 1089 |
+
// Arithmetic operators
|
| 1090 |
+
//
|
| 1091 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1092 |
+
|
| 1093 |
+
// Note: Almost all data types cast to float then do the arithmetic operations
|
| 1094 |
+
// Types inheriting from this class can overload them if specialized instructions are available
|
| 1095 |
+
// in HW (e.g. half_t)
|
| 1096 |
+
|
| 1097 |
+
|
| 1098 |
+
CUTLASS_HOST_DEVICE
|
| 1099 |
+
friend bool operator==(float_exmy_base const &lhs, float_exmy_base const &rhs) {
|
| 1100 |
+
return float(lhs) == float(rhs);
|
| 1101 |
+
}
|
| 1102 |
+
|
| 1103 |
+
CUTLASS_HOST_DEVICE
|
| 1104 |
+
friend bool operator!=(float_exmy_base const &lhs, float_exmy_base const &rhs) {
|
| 1105 |
+
return float(lhs) != float(rhs);
|
| 1106 |
+
}
|
| 1107 |
+
|
| 1108 |
+
CUTLASS_HOST_DEVICE
|
| 1109 |
+
friend bool operator<(float_exmy_base const &lhs, float_exmy_base const &rhs) {
|
| 1110 |
+
return float(lhs) < float(rhs);
|
| 1111 |
+
}
|
| 1112 |
+
|
| 1113 |
+
CUTLASS_HOST_DEVICE
|
| 1114 |
+
friend bool operator<=(float_exmy_base const &lhs, float_exmy_base const &rhs) {
|
| 1115 |
+
return float(lhs) <= float(rhs);
|
| 1116 |
+
}
|
| 1117 |
+
|
| 1118 |
+
CUTLASS_HOST_DEVICE
|
| 1119 |
+
friend bool operator>(float_exmy_base const &lhs, float_exmy_base const &rhs) {
|
| 1120 |
+
return float(lhs) > float(rhs);
|
| 1121 |
+
}
|
| 1122 |
+
|
| 1123 |
+
CUTLASS_HOST_DEVICE
|
| 1124 |
+
friend bool operator>=(float_exmy_base const &lhs, float_exmy_base const &rhs) {
|
| 1125 |
+
return float(lhs) >= float(rhs);
|
| 1126 |
+
}
|
| 1127 |
+
|
| 1128 |
+
CUTLASS_HOST_DEVICE
|
| 1129 |
+
friend float_exmy_base operator+(float_exmy_base const &lhs, float_exmy_base const &rhs) {
|
| 1130 |
+
return float_exmy_base(float(lhs) + float(rhs));
|
| 1131 |
+
}
|
| 1132 |
+
|
| 1133 |
+
CUTLASS_HOST_DEVICE
|
| 1134 |
+
friend float_exmy_base operator-(float_exmy_base const &lhs) {
|
| 1135 |
+
return float_exmy_base(-float(lhs));
|
| 1136 |
+
}
|
| 1137 |
+
|
| 1138 |
+
CUTLASS_HOST_DEVICE
|
| 1139 |
+
friend float_exmy_base operator-(float_exmy_base const &lhs, float_exmy_base const &rhs) {
|
| 1140 |
+
return float_exmy_base(float(lhs) - float(rhs));
|
| 1141 |
+
}
|
| 1142 |
+
|
| 1143 |
+
CUTLASS_HOST_DEVICE
|
| 1144 |
+
friend float_exmy_base operator*(float_exmy_base const &lhs, float_exmy_base const &rhs) {
|
| 1145 |
+
return float_exmy_base(float(lhs) * float(rhs));
|
| 1146 |
+
}
|
| 1147 |
+
|
| 1148 |
+
CUTLASS_HOST_DEVICE
|
| 1149 |
+
friend float_exmy_base operator/(float_exmy_base const &lhs, float_exmy_base const &rhs) {
|
| 1150 |
+
return float_exmy_base(float(lhs) / float(rhs));
|
| 1151 |
+
}
|
| 1152 |
+
|
| 1153 |
+
CUTLASS_HOST_DEVICE
|
| 1154 |
+
friend float_exmy_base &operator+=(float_exmy_base &lhs, float_exmy_base const &rhs) {
|
| 1155 |
+
lhs = float_exmy_base(float(lhs) + float(rhs));
|
| 1156 |
+
return lhs;
|
| 1157 |
+
}
|
| 1158 |
+
|
| 1159 |
+
CUTLASS_HOST_DEVICE
|
| 1160 |
+
friend float_exmy_base &operator-=(float_exmy_base &lhs, float_exmy_base const &rhs) {
|
| 1161 |
+
lhs = float_exmy_base(float(lhs) - float(rhs));
|
| 1162 |
+
return lhs;
|
| 1163 |
+
}
|
| 1164 |
+
|
| 1165 |
+
CUTLASS_HOST_DEVICE
|
| 1166 |
+
friend float_exmy_base &operator*=(float_exmy_base &lhs, float_exmy_base const &rhs) {
|
| 1167 |
+
lhs = float_exmy_base(float(lhs) * float(rhs));
|
| 1168 |
+
return lhs;
|
| 1169 |
+
}
|
| 1170 |
+
|
| 1171 |
+
CUTLASS_HOST_DEVICE
|
| 1172 |
+
friend float_exmy_base &operator/=(float_exmy_base &lhs, float_exmy_base const &rhs) {
|
| 1173 |
+
lhs = float_exmy_base(float(lhs) / float(rhs));
|
| 1174 |
+
return lhs;
|
| 1175 |
+
}
|
| 1176 |
+
|
| 1177 |
+
CUTLASS_HOST_DEVICE
|
| 1178 |
+
friend float_exmy_base &operator++(float_exmy_base &lhs) {
|
| 1179 |
+
float tmp(lhs);
|
| 1180 |
+
++tmp;
|
| 1181 |
+
lhs = float_exmy_base(tmp);
|
| 1182 |
+
return lhs;
|
| 1183 |
+
}
|
| 1184 |
+
|
| 1185 |
+
CUTLASS_HOST_DEVICE
|
| 1186 |
+
friend float_exmy_base &operator--(float_exmy_base &lhs) {
|
| 1187 |
+
float tmp(lhs);
|
| 1188 |
+
--tmp;
|
| 1189 |
+
lhs = float_exmy_base(tmp);
|
| 1190 |
+
return lhs;
|
| 1191 |
+
}
|
| 1192 |
+
|
| 1193 |
+
CUTLASS_HOST_DEVICE
|
| 1194 |
+
friend float_exmy_base operator++(float_exmy_base &lhs, int) {
|
| 1195 |
+
float_exmy_base ret(lhs);
|
| 1196 |
+
float tmp(lhs);
|
| 1197 |
+
tmp++;
|
| 1198 |
+
lhs = float_exmy_base(tmp);
|
| 1199 |
+
return ret;
|
| 1200 |
+
}
|
| 1201 |
+
|
| 1202 |
+
CUTLASS_HOST_DEVICE
|
| 1203 |
+
friend float_exmy_base operator--(float_exmy_base &lhs, int) {
|
| 1204 |
+
float_exmy_base ret(lhs);
|
| 1205 |
+
float tmp(lhs);
|
| 1206 |
+
tmp--;
|
| 1207 |
+
lhs = float_exmy_base(tmp);
|
| 1208 |
+
return ret;
|
| 1209 |
+
}
|
| 1210 |
+
|
| 1211 |
+
};
|
| 1212 |
+
|
| 1213 |
+
template <detail::FpEncoding T, class Derived>
|
| 1214 |
+
CUTLASS_HOST_DEVICE
|
| 1215 |
+
cutlass::float_exmy_base<T, Derived> abs(cutlass::float_exmy_base<T, Derived> const& h) {
|
| 1216 |
+
using BitRepresentation = typename cutlass::float_exmy_base<T, Derived>::BitRepresentation;
|
| 1217 |
+
using Storage = typename cutlass::float_exmy_base<T, Derived>::Storage;
|
| 1218 |
+
return BitRepresentation::IS_SIGNED ?
|
| 1219 |
+
cutlass::float_exmy_base<T, Derived>(Storage(h.raw() & Storage((1<<BitRepresentation::SIGN_SHIFT) - 1))) :
|
| 1220 |
+
cutlass::float_exmy_base<T, Derived>(h.raw());
|
| 1221 |
+
}
|
| 1222 |
+
} // namespace cutlass
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/device/detail.hpp
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief Distributed gemm device layer helpers.
|
| 33 |
+
*/
|
| 34 |
+
|
| 35 |
+
#pragma once
|
| 36 |
+
|
| 37 |
+
#include "cute/layout.hpp"
|
| 38 |
+
#include "cute/tensor.hpp"
|
| 39 |
+
#include "cutlass/cutlass.h"
|
| 40 |
+
|
| 41 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 42 |
+
|
| 43 |
+
namespace cutlass::distributed::device::detail {
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
cutlass::Status check_cuda_status(cudaError_t status) {
|
| 47 |
+
if (status != cudaSuccess) {
|
| 48 |
+
auto result = cudaGetLastError();
|
| 49 |
+
CUTLASS_TRACE_HOST(" error message: " << cudaGetErrorString(result));
|
| 50 |
+
return cutlass::Status::kErrorInternal;
|
| 51 |
+
}
|
| 52 |
+
return cutlass::Status::kSuccess;
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
// DistGemmBufferHelper computes required buffer size and offsets for GEMM operands.
|
| 56 |
+
template <
|
| 57 |
+
typename Tiler_,
|
| 58 |
+
typename ElementA_,
|
| 59 |
+
typename ElementB_,
|
| 60 |
+
typename ElementC_,
|
| 61 |
+
typename ElementD_>
|
| 62 |
+
struct DistGemmBufferHelper {
|
| 63 |
+
|
| 64 |
+
using Tiler = Tiler_;
|
| 65 |
+
|
| 66 |
+
using ElementA = ElementA_;
|
| 67 |
+
using ElementB = ElementB_;
|
| 68 |
+
using ElementC = ElementC_;
|
| 69 |
+
using ElementD = ElementD_;
|
| 70 |
+
|
| 71 |
+
static constexpr int NumBuffersA = Tiler::NumBuffersA;
|
| 72 |
+
static constexpr int NumBuffersB = Tiler::NumBuffersB;
|
| 73 |
+
static constexpr int NumBuffersC = Tiler::NumBuffersC;
|
| 74 |
+
static constexpr int NumBuffersD = Tiler::NumBuffersD;
|
| 75 |
+
|
| 76 |
+
template <typename ProblemShape>
|
| 77 |
+
static auto
|
| 78 |
+
get_buffer_size_a(ProblemShape problem_shape) {
|
| 79 |
+
auto a_buffer_layout = cute::make_layout(
|
| 80 |
+
cute::make_shape(NumBuffersA, Tiler::get_local_a_shape(problem_shape), sizeof(ElementA))
|
| 81 |
+
);
|
| 82 |
+
return size(a_buffer_layout);
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
template <typename ProblemShape>
|
| 86 |
+
static auto
|
| 87 |
+
get_buffer_size_b(ProblemShape problem_shape) {
|
| 88 |
+
auto b_buffer_layout = cute::make_layout(
|
| 89 |
+
cute::make_shape(NumBuffersB, Tiler::get_local_b_shape(problem_shape), sizeof(ElementB))
|
| 90 |
+
);
|
| 91 |
+
return size(b_buffer_layout);
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
template <typename ProblemShape>
|
| 95 |
+
static auto
|
| 96 |
+
get_buffer_size_c(ProblemShape problem_shape) {
|
| 97 |
+
auto c_buffer_layout = cute::make_layout(
|
| 98 |
+
cute::make_shape(NumBuffersC, Tiler::get_local_c_shape(problem_shape), sizeof(ElementC))
|
| 99 |
+
);
|
| 100 |
+
return size(c_buffer_layout);
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
template <typename ProblemShape>
|
| 104 |
+
static auto
|
| 105 |
+
get_buffer_size_d(ProblemShape problem_shape) {
|
| 106 |
+
auto d_buffer_layout = cute::make_layout(
|
| 107 |
+
cute::make_shape(NumBuffersD, Tiler::get_local_d_shape(problem_shape), sizeof(ElementD))
|
| 108 |
+
);
|
| 109 |
+
return size(d_buffer_layout);
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
template <typename ProblemShape>
|
| 113 |
+
static auto
|
| 114 |
+
get_buffer_size(ProblemShape problem_shape) {
|
| 115 |
+
size_t buffer_size = 0;
|
| 116 |
+
|
| 117 |
+
if constexpr (NumBuffersA > 0) {
|
| 118 |
+
buffer_size += get_buffer_size_a(problem_shape);
|
| 119 |
+
}
|
| 120 |
+
if constexpr (NumBuffersB > 0) {
|
| 121 |
+
buffer_size += get_buffer_size_b(problem_shape);
|
| 122 |
+
}
|
| 123 |
+
if constexpr (NumBuffersC > 0) {
|
| 124 |
+
buffer_size += get_buffer_size_c(problem_shape);
|
| 125 |
+
}
|
| 126 |
+
if constexpr (NumBuffersD > 0) {
|
| 127 |
+
buffer_size += get_buffer_size_d(problem_shape);
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
return buffer_size;
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
// Buffer space: | buffer_A | buffer_B | buffer_C | buffer_D |
|
| 134 |
+
// And buffer_{A,B,C,D}: | iter 1 | iter 2 | ... | iter TP - 1 |
|
| 135 |
+
template <typename ProblemShape>
|
| 136 |
+
static size_t
|
| 137 |
+
get_buffer_offset_A(ProblemShape problem_shape) {
|
| 138 |
+
return 0;
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
template <typename ProblemShape>
|
| 142 |
+
static size_t
|
| 143 |
+
get_buffer_offset_B(ProblemShape problem_shape) {
|
| 144 |
+
return get_buffer_size_a(problem_shape);
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
template <typename ProblemShape>
|
| 148 |
+
static size_t
|
| 149 |
+
get_buffer_offset_C(ProblemShape problem_shape) {
|
| 150 |
+
return get_buffer_size_a(problem_shape) + get_buffer_size_b(problem_shape);
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
template <typename ProblemShape>
|
| 154 |
+
static size_t
|
| 155 |
+
get_buffer_offset_D(ProblemShape problem_shape) {
|
| 156 |
+
return get_buffer_size_a(problem_shape) + get_buffer_size_b(problem_shape) + get_buffer_size_c(problem_shape);
|
| 157 |
+
}
|
| 158 |
+
};
|
| 159 |
+
|
| 160 |
+
} // namespace cutlass::distributed::device::detail
|
| 161 |
+
|
| 162 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 163 |
+
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/device/dist_gemm_universal_wrapper.hpp
ADDED
|
@@ -0,0 +1,717 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
\file Distributed GEMM Device Adapter
|
| 33 |
+
|
| 34 |
+
Sets up local GEMM stages, the cuda graph, manages buffer and barrier spaces,
|
| 35 |
+
and maps arguments to per-stage arguments.
|
| 36 |
+
*/
|
| 37 |
+
|
| 38 |
+
#pragma once
|
| 39 |
+
|
| 40 |
+
#include "cutlass/cutlass.h"
|
| 41 |
+
#include "cutlass/device_kernel.h"
|
| 42 |
+
#include "cutlass/gemm/gemm.h"
|
| 43 |
+
#include "cutlass/gemm/device/gemm_universal_adapter.h"
|
| 44 |
+
|
| 45 |
+
#include "cutlass/experimental/distributed/device/full_barrier.hpp"
|
| 46 |
+
#include "cutlass/experimental/distributed/device/detail.hpp"
|
| 47 |
+
|
| 48 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 49 |
+
|
| 50 |
+
namespace cutlass::distributed::device {
|
| 51 |
+
|
| 52 |
+
template <class GemmKernel_>
|
| 53 |
+
class DistributedGemmUniversalAdapter {
|
| 54 |
+
public:
|
| 55 |
+
using DeviceGemm = cutlass::gemm::device::GemmUniversalAdapter<GemmKernel_>;
|
| 56 |
+
using GemmKernel = GemmKernel_;
|
| 57 |
+
using TileShape = typename GemmKernel::TileShape;
|
| 58 |
+
using ElementA = typename GemmKernel::ElementA;
|
| 59 |
+
using ElementB = typename GemmKernel::ElementB;
|
| 60 |
+
using ElementC = typename GemmKernel::ElementC;
|
| 61 |
+
using ElementD = typename GemmKernel::ElementD;
|
| 62 |
+
using ElementAccumulator = typename GemmKernel::ElementAccumulator;
|
| 63 |
+
using DispatchPolicy = typename GemmKernel::DispatchPolicy;
|
| 64 |
+
using CollectiveMainloop = typename GemmKernel::CollectiveMainloop;
|
| 65 |
+
using CollectiveEpilogue = typename GemmKernel::CollectiveEpilogue;
|
| 66 |
+
|
| 67 |
+
// "Inherit" type decls and static values from device GEMM
|
| 68 |
+
using LayoutA = typename DeviceGemm::LayoutA;
|
| 69 |
+
using LayoutB = typename DeviceGemm::LayoutB;
|
| 70 |
+
using LayoutC = typename DeviceGemm::LayoutC;
|
| 71 |
+
using LayoutD = typename DeviceGemm::LayoutD;
|
| 72 |
+
|
| 73 |
+
using StrideA = typename GemmKernel::StrideA;
|
| 74 |
+
using StrideB = typename GemmKernel::StrideB;
|
| 75 |
+
using StrideC = typename GemmKernel::StrideC;
|
| 76 |
+
using StrideD = typename GemmKernel::StrideD;
|
| 77 |
+
|
| 78 |
+
static bool const kEnableCudaHostAdapter = DeviceGemm::kEnableCudaHostAdapter;
|
| 79 |
+
|
| 80 |
+
static ComplexTransform const kTransformA = DeviceGemm::kTransformA;
|
| 81 |
+
static ComplexTransform const kTransformB = DeviceGemm::kTransformB;
|
| 82 |
+
|
| 83 |
+
using MathOperator = typename DeviceGemm::MathOperator;
|
| 84 |
+
using OperatorClass = typename DeviceGemm::OperatorClass;
|
| 85 |
+
using ArchTag = typename DeviceGemm::ArchTag;
|
| 86 |
+
|
| 87 |
+
using ThreadblockSwizzle = typename DeviceGemm::ThreadblockSwizzle;
|
| 88 |
+
using ThreadblockShape = typename DeviceGemm::ThreadblockShape;
|
| 89 |
+
using ClusterShape = typename DeviceGemm::ClusterShape;
|
| 90 |
+
using InstructionShape = typename DeviceGemm::InstructionShape;
|
| 91 |
+
|
| 92 |
+
static int const kThreadCount = DeviceGemm::kThreadCount;
|
| 93 |
+
static constexpr int WarpsInMma = DeviceGemm::WarpsInMma;
|
| 94 |
+
static constexpr int WarpsInMmaM = DeviceGemm::WarpsInMmaM;
|
| 95 |
+
static constexpr int WarpsInMmaN = DeviceGemm::WarpsInMmaN;
|
| 96 |
+
|
| 97 |
+
using WarpCount = typename DeviceGemm::WarpCount;
|
| 98 |
+
using WarpShape = typename DeviceGemm::WarpShape;
|
| 99 |
+
|
| 100 |
+
static int constexpr kStages = DeviceGemm::kStages;
|
| 101 |
+
|
| 102 |
+
static int constexpr kAlignmentA = DeviceGemm::kAlignmentA;
|
| 103 |
+
static int constexpr kAlignmentB = DeviceGemm::kAlignmentB;
|
| 104 |
+
static int constexpr kAlignmentC = DeviceGemm::kAlignmentC;
|
| 105 |
+
static int constexpr kAlignmentD = DeviceGemm::kAlignmentD;
|
| 106 |
+
|
| 107 |
+
using EpilogueOutputOp = typename DeviceGemm::EpilogueOutputOp;
|
| 108 |
+
|
| 109 |
+
static int constexpr kSplitKAlignment = DeviceGemm::kSplitKAlignment;
|
| 110 |
+
|
| 111 |
+
// Distributed GEMM types and defs
|
| 112 |
+
using DistSchedule = typename GemmKernel::DistSchedule;
|
| 113 |
+
static constexpr bool HasMemcpy = DistSchedule::HasMemcpy;
|
| 114 |
+
using TP = typename DistSchedule::TP;
|
| 115 |
+
static constexpr int TP_ = TP{};
|
| 116 |
+
using ElementFlag = typename GemmKernel::ElementFlag;
|
| 117 |
+
using ElementBarrier = uint32_t;
|
| 118 |
+
|
| 119 |
+
using BufferHelper = detail::DistGemmBufferHelper<
|
| 120 |
+
DistSchedule,
|
| 121 |
+
ElementA,
|
| 122 |
+
ElementB,
|
| 123 |
+
ElementC,
|
| 124 |
+
ElementD>;
|
| 125 |
+
|
| 126 |
+
/// Argument structure
|
| 127 |
+
using Arguments = typename GemmKernel::BaseArguments;
|
| 128 |
+
using DistributedArguments = typename GemmKernel::DistributedArguments;
|
| 129 |
+
using PackedArguments = typename GemmKernel::PackedArguments;
|
| 130 |
+
|
| 131 |
+
/// Argument structure: Kernel API
|
| 132 |
+
using Params = typename GemmKernel::PackedParams;
|
| 133 |
+
|
| 134 |
+
struct DistributedGemmState {
|
| 135 |
+
int device_idx;
|
| 136 |
+
|
| 137 |
+
Params params_array[TP_];
|
| 138 |
+
|
| 139 |
+
cudaGraph_t graph;
|
| 140 |
+
cudaGraphExec_t graph_executable;
|
| 141 |
+
|
| 142 |
+
bool graph_created = false;
|
| 143 |
+
bool graph_instantiated = false;
|
| 144 |
+
|
| 145 |
+
void * memcpy_source_ptr_array[TP_];
|
| 146 |
+
void const * memcpy_remote_ptr_array[TP_];
|
| 147 |
+
size_t memcpy_bytes[TP_];
|
| 148 |
+
|
| 149 |
+
cutlass::Array<ElementBarrier*, TP_> device_barrier_ptrs;
|
| 150 |
+
|
| 151 |
+
bool is_initialized = false;
|
| 152 |
+
};
|
| 153 |
+
|
| 154 |
+
private:
|
| 155 |
+
|
| 156 |
+
DistributedGemmState state_;
|
| 157 |
+
|
| 158 |
+
public:
|
| 159 |
+
|
| 160 |
+
bool is_initialized() {
|
| 161 |
+
return state_.is_initialized && state_.graph_created && state_.graph_instantiated;
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
/// Determines whether the GEMM can execute the given problem.
|
| 165 |
+
static Status
|
| 166 |
+
can_implement(Arguments const& args) {
|
| 167 |
+
if (args.epilogue.thread.beta != 0.0 && DistSchedule::RemoteC) {
|
| 168 |
+
CUTLASS_TRACE_HOST(" CAN IMPLEMENT: Selected TP uses Remote C to communicate " <<
|
| 169 |
+
"partial results, which do not support non-zero values for beta yet " <<
|
| 170 |
+
"(epilogue must be sourceless.)\n");
|
| 171 |
+
return Status::kInvalid;
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
if (not DistSchedule::can_implement_global(args.problem_shape)) {
|
| 175 |
+
CUTLASS_TRACE_HOST(" CAN IMPLEMENT: Problem shape not divisible by TP.\n");
|
| 176 |
+
return Status::kInvalid;
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
Arguments args_copy = args;
|
| 180 |
+
args_copy.problem_shape = DistSchedule::get_local_gemm_shape(args.problem_shape);
|
| 181 |
+
for (int iteration = 0; iteration < TP_; ++iteration) {
|
| 182 |
+
if (not GemmKernel::can_implement(args_copy)) {
|
| 183 |
+
return Status::kInvalid;
|
| 184 |
+
}
|
| 185 |
+
}
|
| 186 |
+
return Status::kSuccess;
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
/// Gets buffer space size
|
| 190 |
+
static size_t
|
| 191 |
+
get_buffer_space_size(Arguments const& args) {
|
| 192 |
+
size_t buffer_bytes = 0;
|
| 193 |
+
|
| 194 |
+
buffer_bytes = BufferHelper::get_buffer_size(args.problem_shape);
|
| 195 |
+
buffer_bytes = round_nearest(buffer_bytes, MinWorkspaceAlignment);
|
| 196 |
+
|
| 197 |
+
return buffer_bytes;
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
static auto
|
| 201 |
+
get_tensor_A_for_iter(Arguments const* args_array, void** buffer_space, int device_idx, int iteration) {
|
| 202 |
+
auto args = args_array[device_idx];
|
| 203 |
+
auto tensor_A = make_tensor(args.mainloop.ptr_A, make_layout(
|
| 204 |
+
DistSchedule::get_local_a_shape(args.problem_shape),
|
| 205 |
+
args.mainloop.dA));
|
| 206 |
+
|
| 207 |
+
uint8_t* tensor_buffer = reinterpret_cast<uint8_t*>(buffer_space[device_idx]) +
|
| 208 |
+
BufferHelper::get_buffer_offset_A(args.problem_shape);
|
| 209 |
+
|
| 210 |
+
return DistSchedule::get_tensor_A(tensor_A, tensor_buffer, device_idx, iteration);
|
| 211 |
+
}
|
| 212 |
+
|
| 213 |
+
static auto
|
| 214 |
+
get_tensor_B_for_iter(Arguments const* args_array, void** buffer_space, int device_idx, int iteration) {
|
| 215 |
+
auto args = args_array[device_idx];
|
| 216 |
+
auto tensor_B = make_tensor(args.mainloop.ptr_B, make_layout(
|
| 217 |
+
DistSchedule::get_local_b_shape(args.problem_shape),
|
| 218 |
+
args.mainloop.dB));
|
| 219 |
+
|
| 220 |
+
uint8_t* tensor_buffer = reinterpret_cast<uint8_t*>(buffer_space[device_idx]) +
|
| 221 |
+
BufferHelper::get_buffer_offset_B(args.problem_shape);
|
| 222 |
+
|
| 223 |
+
return DistSchedule::get_tensor_B(tensor_B, tensor_buffer, device_idx, iteration);
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
static auto
|
| 227 |
+
get_tensor_C_for_iter(Arguments const* args_array, void** buffer_space, int device_idx, int iteration) {
|
| 228 |
+
auto args = args_array[device_idx];
|
| 229 |
+
auto tensor_C = make_tensor(args.epilogue.ptr_C, make_layout(
|
| 230 |
+
DistSchedule::get_local_c_shape(args.problem_shape),
|
| 231 |
+
args.epilogue.dC));
|
| 232 |
+
|
| 233 |
+
auto peer_idx_iter = DistSchedule::get_remote_peer_id(device_idx, iteration);
|
| 234 |
+
void* buffer_ptr = DistSchedule::RemoteC ? buffer_space[peer_idx_iter] : buffer_space[device_idx];
|
| 235 |
+
|
| 236 |
+
uint8_t* tensor_buffer = reinterpret_cast<uint8_t*>(buffer_ptr) +
|
| 237 |
+
BufferHelper::get_buffer_offset_C(args.problem_shape);
|
| 238 |
+
|
| 239 |
+
return DistSchedule::get_tensor_C(tensor_C, tensor_buffer, device_idx, iteration);
|
| 240 |
+
}
|
| 241 |
+
|
| 242 |
+
static auto
|
| 243 |
+
get_tensor_D_for_iter(Arguments const* args_array, void** buffer_space, int device_idx, int iteration) {
|
| 244 |
+
auto args = args_array[device_idx];
|
| 245 |
+
auto tensor_D = make_tensor(args.epilogue.ptr_D, make_layout(
|
| 246 |
+
DistSchedule::get_local_d_shape(args.problem_shape),
|
| 247 |
+
args.epilogue.dD));
|
| 248 |
+
|
| 249 |
+
// support remoteD
|
| 250 |
+
uint8_t* tensor_buffer = reinterpret_cast<uint8_t*>(buffer_space[device_idx]) +
|
| 251 |
+
BufferHelper::get_buffer_offset_D(args.problem_shape);
|
| 252 |
+
|
| 253 |
+
return DistSchedule::get_tensor_D(tensor_D, tensor_buffer, device_idx, iteration);
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
static size_t
|
| 257 |
+
get_workspace_size(Arguments const& args) {
|
| 258 |
+
size_t workspace_bytes = 0;
|
| 259 |
+
|
| 260 |
+
workspace_bytes = get_buffer_space_size(args);
|
| 261 |
+
|
| 262 |
+
for (int iteration = 0; iteration < TP_; ++iteration) {
|
| 263 |
+
// NOTE: assumes underlying kernels align up to alignment requirements on their own,
|
| 264 |
+
// and that the alignment requirements of the individual kernels match.
|
| 265 |
+
workspace_bytes += GemmKernel::get_workspace_size(args);
|
| 266 |
+
}
|
| 267 |
+
|
| 268 |
+
return workspace_bytes;
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
static size_t
|
| 272 |
+
get_barrier_bytes() {
|
| 273 |
+
return round_nearest(sizeof(ElementBarrier), 32);
|
| 274 |
+
}
|
| 275 |
+
|
| 276 |
+
static size_t
|
| 277 |
+
get_flag_bytes() {
|
| 278 |
+
return round_nearest(sizeof(ElementFlag) * TP_, 32);
|
| 279 |
+
}
|
| 280 |
+
|
| 281 |
+
static void *
|
| 282 |
+
exclusive_workspace_ptr_to_flag_ptr(void * exclusive_workspace_ptr, int iteration) {
|
| 283 |
+
return static_cast<void*>(
|
| 284 |
+
static_cast<uint8_t*>(exclusive_workspace_ptr) +
|
| 285 |
+
get_barrier_bytes() +
|
| 286 |
+
(sizeof(ElementFlag) * iteration));
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
static size_t
|
| 290 |
+
get_exclusive_workspace_size() {
|
| 291 |
+
return get_barrier_bytes() + get_flag_bytes();
|
| 292 |
+
}
|
| 293 |
+
|
| 294 |
+
/// Initializes GEMM state from arguments.
|
| 295 |
+
Status
|
| 296 |
+
initialize(
|
| 297 |
+
Arguments const* args,
|
| 298 |
+
void** workspace_ptrs,
|
| 299 |
+
void** exclusive_workspace_ptrs,
|
| 300 |
+
int device_idx,
|
| 301 |
+
cudaStream_t stream = nullptr,
|
| 302 |
+
bool launch_with_pdl = false) {
|
| 303 |
+
|
| 304 |
+
CUTLASS_TRACE_HOST("DistributedGemm::initialize() - stream: " << (stream ? "non-null" : "null"));
|
| 305 |
+
|
| 306 |
+
state_.device_idx = device_idx;
|
| 307 |
+
|
| 308 |
+
for (int device = 0; device < TP_; ++device) {
|
| 309 |
+
state_.device_barrier_ptrs[device] = reinterpret_cast<ElementBarrier*>(exclusive_workspace_ptrs[device]);
|
| 310 |
+
}
|
| 311 |
+
|
| 312 |
+
// Zero out exclusive workspace
|
| 313 |
+
zero_workspace(exclusive_workspace_ptrs[device_idx], get_exclusive_workspace_size(), stream, nullptr);
|
| 314 |
+
|
| 315 |
+
for (int iteration = 0; iteration < TP_; ++iteration) {
|
| 316 |
+
|
| 317 |
+
size_t workspace_iteration_offset = GemmKernel::get_workspace_size(args[device_idx]);
|
| 318 |
+
uint8_t* workspace_ptr = reinterpret_cast<uint8_t*>(workspace_ptrs[device_idx]) +
|
| 319 |
+
get_buffer_space_size(args[device_idx]) +
|
| 320 |
+
(iteration * workspace_iteration_offset);
|
| 321 |
+
|
| 322 |
+
void * workspace_iter = reinterpret_cast<void*>(workspace_ptr);
|
| 323 |
+
void** buffer_space = workspace_ptrs;
|
| 324 |
+
|
| 325 |
+
// Set up GEMM arguments for the current stage/iteration
|
| 326 |
+
auto tensor_a_iter = get_tensor_A_for_iter(args, buffer_space, device_idx, iteration);
|
| 327 |
+
auto tensor_b_iter = get_tensor_B_for_iter(args, buffer_space, device_idx, iteration);
|
| 328 |
+
auto tensor_c_iter = get_tensor_C_for_iter(args, buffer_space, device_idx, iteration);
|
| 329 |
+
auto tensor_d_iter = get_tensor_D_for_iter(args, buffer_space, device_idx, iteration);
|
| 330 |
+
|
| 331 |
+
Arguments base_args = args[device_idx];
|
| 332 |
+
base_args.problem_shape = DistSchedule::get_local_gemm_shape(args[device_idx].problem_shape);
|
| 333 |
+
base_args.mainloop = {
|
| 334 |
+
reinterpret_cast<const ElementA*>(tensor_a_iter.data()),
|
| 335 |
+
tensor_a_iter.stride(),
|
| 336 |
+
reinterpret_cast<const ElementB*>(tensor_b_iter.data()),
|
| 337 |
+
tensor_b_iter.stride()
|
| 338 |
+
};
|
| 339 |
+
base_args.epilogue = {
|
| 340 |
+
base_args.epilogue.thread,
|
| 341 |
+
reinterpret_cast<const ElementC*>(tensor_c_iter.data()),
|
| 342 |
+
tensor_c_iter.stride(),
|
| 343 |
+
reinterpret_cast<ElementD*>(tensor_d_iter.data()),
|
| 344 |
+
tensor_d_iter.stride()
|
| 345 |
+
};
|
| 346 |
+
|
| 347 |
+
if constexpr (DistSchedule::RemoteC) {
|
| 348 |
+
if (iteration > 0) {
|
| 349 |
+
base_args.epilogue.thread.beta = 1.0;
|
| 350 |
+
}
|
| 351 |
+
else if (iteration == 0){
|
| 352 |
+
base_args.epilogue.thread.beta = 0.0;
|
| 353 |
+
}
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
auto [left_peer_idx, right_peer_idx] = DistSchedule::get_peers_for_device(device_idx);
|
| 357 |
+
auto flag_peer_idx = DistSchedule::KernelWritesArrivalFlag ? right_peer_idx : device_idx;
|
| 358 |
+
|
| 359 |
+
void * self_flag_ptr = exclusive_workspace_ptr_to_flag_ptr(exclusive_workspace_ptrs[device_idx], iteration);
|
| 360 |
+
void * peer_flag_ptr = exclusive_workspace_ptr_to_flag_ptr(exclusive_workspace_ptrs[flag_peer_idx], iteration);
|
| 361 |
+
|
| 362 |
+
DistributedArguments distributed_args = {
|
| 363 |
+
device_idx,
|
| 364 |
+
iteration,
|
| 365 |
+
self_flag_ptr,
|
| 366 |
+
peer_flag_ptr
|
| 367 |
+
};
|
| 368 |
+
PackedArguments args_iter = {base_args, distributed_args};
|
| 369 |
+
|
| 370 |
+
// Initialize the workspace
|
| 371 |
+
Status status = GemmKernel::initialize_workspace(args_iter, workspace_iter, stream);
|
| 372 |
+
if (status != Status::kSuccess) {
|
| 373 |
+
return status;
|
| 374 |
+
}
|
| 375 |
+
|
| 376 |
+
// Initialize the Params structure
|
| 377 |
+
state_.params_array[iteration] = GemmKernel::to_underlying_arguments(args_iter, workspace_iter);
|
| 378 |
+
|
| 379 |
+
// Set up peer buffer ptrs
|
| 380 |
+
if (iteration > 0 && HasMemcpy) {
|
| 381 |
+
auto peer_idx_iter = DistSchedule::get_remote_peer_id(device_idx, iteration);
|
| 382 |
+
|
| 383 |
+
void * local_ptr_itr = nullptr;
|
| 384 |
+
void const * remote_ptr_itr = nullptr;
|
| 385 |
+
size_t local_size = 0;
|
| 386 |
+
size_t remote_size = 0;
|
| 387 |
+
|
| 388 |
+
static_assert(not DistSchedule::HasMemcpy || (
|
| 389 |
+
DistSchedule::MemcpyA || DistSchedule::MemcpyB),
|
| 390 |
+
"Expected to either memcpy A or B when scheduler requires memcpy.");
|
| 391 |
+
if constexpr (DistSchedule::MemcpyA) {
|
| 392 |
+
local_size = cute::cosize(tensor_a_iter.layout()) * sizeof(ElementA);
|
| 393 |
+
local_ptr_itr = reinterpret_cast<void*>(tensor_a_iter.data());
|
| 394 |
+
|
| 395 |
+
// Copy peer's slice in the first iteration (direct access memcpy instead of logical ring)
|
| 396 |
+
auto remote_tensor_iter = get_tensor_A_for_iter(args, buffer_space, peer_idx_iter, 0);
|
| 397 |
+
remote_ptr_itr = reinterpret_cast<void const*>(remote_tensor_iter.data());
|
| 398 |
+
remote_size = cute::cosize(remote_tensor_iter.layout()) * sizeof(ElementA);
|
| 399 |
+
}
|
| 400 |
+
else if constexpr (DistSchedule::MemcpyB) {
|
| 401 |
+
local_size = cute::cosize(tensor_b_iter.layout()) * sizeof(ElementB);
|
| 402 |
+
local_ptr_itr = reinterpret_cast<void*>(tensor_b_iter.data());
|
| 403 |
+
|
| 404 |
+
// Copy peer's slice in the first iteration (direct access memcpy instead of logical ring)
|
| 405 |
+
auto remote_tensor_iter = get_tensor_B_for_iter(args, buffer_space, peer_idx_iter, 0);
|
| 406 |
+
remote_ptr_itr = reinterpret_cast<void const*>(remote_tensor_iter.data());
|
| 407 |
+
remote_size = cute::cosize(remote_tensor_iter.layout()) * sizeof(ElementB);
|
| 408 |
+
}
|
| 409 |
+
|
| 410 |
+
assert(local_size == remote_size && local_size > 0);
|
| 411 |
+
|
| 412 |
+
state_.memcpy_source_ptr_array[iteration] = local_ptr_itr;
|
| 413 |
+
state_.memcpy_remote_ptr_array[iteration] = remote_ptr_itr;
|
| 414 |
+
state_.memcpy_bytes[iteration] = local_size;
|
| 415 |
+
}
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
+
//
|
| 419 |
+
// Account for dynamic smem capacity if needed
|
| 420 |
+
//
|
| 421 |
+
int smem_size = GemmKernel::SharedStorageSize;
|
| 422 |
+
|
| 423 |
+
if (smem_size >= (48 << 10)) {
|
| 424 |
+
CUTLASS_TRACE_HOST(" Setting smem size to " << smem_size);
|
| 425 |
+
cudaError_t result = cudaFuncSetAttribute(
|
| 426 |
+
device_kernel<GemmKernel>,
|
| 427 |
+
cudaFuncAttributeMaxDynamicSharedMemorySize,
|
| 428 |
+
smem_size);
|
| 429 |
+
if (cudaSuccess != result) {
|
| 430 |
+
result = cudaGetLastError(); // to clear the error bit
|
| 431 |
+
CUTLASS_TRACE_HOST(" cudaFuncSetAttribute() returned error: " << cudaGetErrorString(result));
|
| 432 |
+
return Status::kErrorInternal;
|
| 433 |
+
}
|
| 434 |
+
}
|
| 435 |
+
|
| 436 |
+
state_.is_initialized = true;
|
| 437 |
+
|
| 438 |
+
// Instantiate graph
|
| 439 |
+
Status status = construct_graph(launch_with_pdl);
|
| 440 |
+
if (status != Status::kSuccess) {
|
| 441 |
+
return status;
|
| 442 |
+
}
|
| 443 |
+
|
| 444 |
+
return Status::kSuccess;
|
| 445 |
+
}
|
| 446 |
+
|
| 447 |
+
Status
|
| 448 |
+
construct_graph(bool launch_with_pdl) {
|
| 449 |
+
#if (__CUDACC_VER_MAJOR__ > 12 || (__CUDACC_VER_MAJOR__ == 12 && __CUDACC_VER_MINOR__ >= 6))
|
| 450 |
+
Status status = Status::kSuccess;
|
| 451 |
+
|
| 452 |
+
// Destroy existing graph, if created
|
| 453 |
+
if (state_.graph_created) {
|
| 454 |
+
status = detail::check_cuda_status(cudaGraphDestroy(state_.graph));
|
| 455 |
+
if (status != Status::kSuccess) {
|
| 456 |
+
return status;
|
| 457 |
+
}
|
| 458 |
+
}
|
| 459 |
+
|
| 460 |
+
state_.graph_created = true;
|
| 461 |
+
|
| 462 |
+
cudaGraphNode_t full_barrier_node;
|
| 463 |
+
|
| 464 |
+
// Create dummy stream
|
| 465 |
+
cudaStream_t stream;
|
| 466 |
+
status = detail::check_cuda_status(cudaStreamCreate(&stream));
|
| 467 |
+
if (status != Status::kSuccess) {
|
| 468 |
+
return status;
|
| 469 |
+
}
|
| 470 |
+
|
| 471 |
+
// Create graph
|
| 472 |
+
status = detail::check_cuda_status(cudaGraphCreate(&state_.graph, 0));
|
| 473 |
+
if (status != Status::kSuccess) {
|
| 474 |
+
return status;
|
| 475 |
+
}
|
| 476 |
+
|
| 477 |
+
// 1. Full barrier node
|
| 478 |
+
status = detail::check_cuda_status(cudaStreamBeginCaptureToGraph(
|
| 479 |
+
stream,
|
| 480 |
+
state_.graph,
|
| 481 |
+
nullptr, nullptr, 0,
|
| 482 |
+
cudaStreamCaptureModeRelaxed));
|
| 483 |
+
if (status != Status::kSuccess) {
|
| 484 |
+
return status;
|
| 485 |
+
}
|
| 486 |
+
|
| 487 |
+
cutlass::Array<ElementFlag*, TP_> self_flag_ptrs;
|
| 488 |
+
for (int iteration = 0; iteration < TP_; ++iteration) {
|
| 489 |
+
self_flag_ptrs[iteration] = state_.params_array[iteration].distributed.self_flag_ptr_;
|
| 490 |
+
}
|
| 491 |
+
|
| 492 |
+
launch_full_barrier<TP_, ElementBarrier, TP_, ElementFlag>(
|
| 493 |
+
state_.device_barrier_ptrs, self_flag_ptrs, state_.device_idx, stream, launch_with_pdl);
|
| 494 |
+
|
| 495 |
+
status = detail::check_cuda_status(cudaStreamEndCapture(stream, &state_.graph));
|
| 496 |
+
if (status != Status::kSuccess) {
|
| 497 |
+
return status;
|
| 498 |
+
}
|
| 499 |
+
|
| 500 |
+
size_t num_nodes;
|
| 501 |
+
status = detail::check_cuda_status(cudaGraphGetNodes(state_.graph, nullptr, &num_nodes));
|
| 502 |
+
if (status != Status::kSuccess) {
|
| 503 |
+
return status;
|
| 504 |
+
}
|
| 505 |
+
if (num_nodes != 1) {
|
| 506 |
+
CUTLASS_TRACE_HOST(" construct_graph() failure: expected a single node in the graph, got " << num_nodes << ".");
|
| 507 |
+
return Status::kErrorInternal;
|
| 508 |
+
}
|
| 509 |
+
if (status != Status::kSuccess) {
|
| 510 |
+
return status;
|
| 511 |
+
}
|
| 512 |
+
status = detail::check_cuda_status(cudaGraphGetNodes(state_.graph, &full_barrier_node, &num_nodes));
|
| 513 |
+
if (status != Status::kSuccess) {
|
| 514 |
+
return status;
|
| 515 |
+
}
|
| 516 |
+
|
| 517 |
+
// 2. Optional mem copy branch
|
| 518 |
+
if constexpr (HasMemcpy) {
|
| 519 |
+
|
| 520 |
+
status = detail::check_cuda_status(cudaStreamBeginCaptureToGraph(
|
| 521 |
+
stream,
|
| 522 |
+
state_.graph,
|
| 523 |
+
&full_barrier_node,
|
| 524 |
+
/* dependencyData = */ nullptr,
|
| 525 |
+
1,
|
| 526 |
+
cudaStreamCaptureModeRelaxed));
|
| 527 |
+
|
| 528 |
+
if (status != Status::kSuccess) {
|
| 529 |
+
return status;
|
| 530 |
+
}
|
| 531 |
+
|
| 532 |
+
// No copies for first iter; we assume the data is already there.
|
| 533 |
+
for (int iteration = 1; iteration < TP_; ++iteration) {
|
| 534 |
+
|
| 535 |
+
status = detail::check_cuda_status(cudaMemcpyAsync(
|
| 536 |
+
state_.memcpy_source_ptr_array[iteration],
|
| 537 |
+
state_.memcpy_remote_ptr_array[iteration],
|
| 538 |
+
state_.memcpy_bytes[iteration],
|
| 539 |
+
cudaMemcpyDeviceToDevice, stream));
|
| 540 |
+
|
| 541 |
+
if (status != Status::kSuccess) {
|
| 542 |
+
return status;
|
| 543 |
+
}
|
| 544 |
+
|
| 545 |
+
// Set flag to non zero
|
| 546 |
+
status = detail::check_cuda_status(cudaMemsetAsync(
|
| 547 |
+
reinterpret_cast<void *>(state_.params_array[iteration].distributed.peer_flag_ptr_),
|
| 548 |
+
0b11111111,
|
| 549 |
+
sizeof(ElementFlag),
|
| 550 |
+
stream));
|
| 551 |
+
|
| 552 |
+
if (status != Status::kSuccess) {
|
| 553 |
+
return status;
|
| 554 |
+
}
|
| 555 |
+
}
|
| 556 |
+
|
| 557 |
+
status = detail::check_cuda_status(cudaStreamEndCapture(stream, &state_.graph));
|
| 558 |
+
if (status != Status::kSuccess) {
|
| 559 |
+
return status;
|
| 560 |
+
}
|
| 561 |
+
}
|
| 562 |
+
|
| 563 |
+
// 3. Run local GEMMs
|
| 564 |
+
// 3.1. Create edge between full barrier and the correct gemm stage/iteration
|
| 565 |
+
cudaGraphEdgeData barrier_to_gemm_edge = {};
|
| 566 |
+
barrier_to_gemm_edge.from_port = HasMemcpy ? cudaGraphKernelNodePortLaunchCompletion: cudaGraphKernelNodePortProgrammatic;
|
| 567 |
+
barrier_to_gemm_edge.type = cudaGraphDependencyTypeProgrammatic;
|
| 568 |
+
|
| 569 |
+
status = detail::check_cuda_status(cudaStreamBeginCaptureToGraph(
|
| 570 |
+
stream,
|
| 571 |
+
state_.graph,
|
| 572 |
+
&full_barrier_node,
|
| 573 |
+
/* dependencyData = */ &barrier_to_gemm_edge,
|
| 574 |
+
1,
|
| 575 |
+
cudaStreamCaptureModeRelaxed));
|
| 576 |
+
if (status != Status::kSuccess) {
|
| 577 |
+
return status;
|
| 578 |
+
}
|
| 579 |
+
|
| 580 |
+
for (int iteration = 0; iteration < TP_; ++iteration) {
|
| 581 |
+
status = DeviceGemm::run(
|
| 582 |
+
state_.params_array[iteration],
|
| 583 |
+
stream,
|
| 584 |
+
/* cuda_adapter = */ nullptr,
|
| 585 |
+
/* launch_with_pdl = */ launch_with_pdl);
|
| 586 |
+
|
| 587 |
+
if (status != Status::kSuccess) {
|
| 588 |
+
return status;
|
| 589 |
+
}
|
| 590 |
+
}
|
| 591 |
+
|
| 592 |
+
status = detail::check_cuda_status(cudaStreamEndCapture(stream, &state_.graph));
|
| 593 |
+
if (status != Status::kSuccess) {
|
| 594 |
+
return status;
|
| 595 |
+
}
|
| 596 |
+
|
| 597 |
+
// 4. Cleanup.
|
| 598 |
+
//// Destroy dummy stream
|
| 599 |
+
status = detail::check_cuda_status(cudaStreamDestroy(stream));
|
| 600 |
+
if (status != Status::kSuccess) {
|
| 601 |
+
return status;
|
| 602 |
+
}
|
| 603 |
+
|
| 604 |
+
// 5. Instantiate graph
|
| 605 |
+
status = detail::check_cuda_status(cudaGraphInstantiate(
|
| 606 |
+
&state_.graph_executable,
|
| 607 |
+
state_.graph,
|
| 608 |
+
/* flags = */ 0));
|
| 609 |
+
if (status != Status::kSuccess) {
|
| 610 |
+
return status;
|
| 611 |
+
}
|
| 612 |
+
state_.graph_instantiated = true;
|
| 613 |
+
|
| 614 |
+
return Status::kSuccess;
|
| 615 |
+
#else
|
| 616 |
+
CUTLASS_TRACE_HOST(" construct_graph() failure: target was compiled with an incompatible " <<
|
| 617 |
+
"version of the CUDA toolkit. Please compile Distributed GEMM with CUDA toolkit 12.4 or later.");
|
| 618 |
+
return Status::kErrorInternal;
|
| 619 |
+
#endif
|
| 620 |
+
}
|
| 621 |
+
|
| 622 |
+
Status
|
| 623 |
+
update(Arguments const& args, void* workspace = nullptr) {
|
| 624 |
+
CUTLASS_TRACE_HOST(" DistributedGemm does not support updating arguments yet.");
|
| 625 |
+
return Status::kErrorInternal;
|
| 626 |
+
}
|
| 627 |
+
|
| 628 |
+
// NOTE: the interface for run() is different in Distributed Gemm:
|
| 629 |
+
// 1. launch_with_pdl is specified in `initialize`, where the cuda graph is being constructed,
|
| 630 |
+
// 2. the state of distributed gemm is an array of params for different iterations, and a
|
| 631 |
+
// cuda graph.
|
| 632 |
+
// 3. Custom cuda adapters aren't supported for simplicity.
|
| 633 |
+
static Status
|
| 634 |
+
run(DistributedGemmState& state,
|
| 635 |
+
cudaStream_t stream = nullptr) {
|
| 636 |
+
CUTLASS_TRACE_HOST("DistributedGemm::run()");
|
| 637 |
+
|
| 638 |
+
if (not state.is_initialized) {
|
| 639 |
+
CUTLASS_TRACE_HOST(" Distributed gemm was not initialized. Did you forget to call initialize()?");
|
| 640 |
+
return Status::kErrorInternal;
|
| 641 |
+
}
|
| 642 |
+
|
| 643 |
+
if (not state.graph_instantiated) {
|
| 644 |
+
CUTLASS_TRACE_HOST(" Distributed gemm graph was not instantiated. Did you forget to call initialize()/construct_graph()?");
|
| 645 |
+
return Status::kErrorInternal;
|
| 646 |
+
}
|
| 647 |
+
|
| 648 |
+
cudaError_t result = cudaGraphLaunch(state.graph_executable, stream);
|
| 649 |
+
if (cudaSuccess != result) {
|
| 650 |
+
result = cudaGetLastError(); // to clear the error bit
|
| 651 |
+
CUTLASS_TRACE_HOST(" cudaGraphLaunch() returned error: " << cudaGetErrorString(result));
|
| 652 |
+
return Status::kErrorInternal;
|
| 653 |
+
}
|
| 654 |
+
|
| 655 |
+
return Status::kSuccess;
|
| 656 |
+
}
|
| 657 |
+
|
| 658 |
+
//
|
| 659 |
+
// Non-static launch overloads that first create and set the internal params struct of this kernel handle.
|
| 660 |
+
//
|
| 661 |
+
|
| 662 |
+
/// Overload that allows a user to re-launch the same kernel without updating internal params struct.
|
| 663 |
+
Status
|
| 664 |
+
run(
|
| 665 |
+
cudaStream_t stream = nullptr) {
|
| 666 |
+
return run(state_, stream);
|
| 667 |
+
}
|
| 668 |
+
|
| 669 |
+
/// Overload that allows a user to re-launch the same kernel without updating internal params struct.
|
| 670 |
+
Status
|
| 671 |
+
operator()(cudaStream_t stream = nullptr) {
|
| 672 |
+
return run(state_, stream);
|
| 673 |
+
}
|
| 674 |
+
|
| 675 |
+
/// Launches the kernel after first constructing Params internal state from supplied arguments.
|
| 676 |
+
Status
|
| 677 |
+
run(
|
| 678 |
+
Arguments const* args,
|
| 679 |
+
void** workspace_ptrs,
|
| 680 |
+
void** exclusive_workspace_ptrs,
|
| 681 |
+
int device_idx,
|
| 682 |
+
cudaStream_t stream = nullptr) {
|
| 683 |
+
Status status = initialize(
|
| 684 |
+
args,
|
| 685 |
+
workspace_ptrs,
|
| 686 |
+
exclusive_workspace_ptrs,
|
| 687 |
+
device_idx,
|
| 688 |
+
stream);
|
| 689 |
+
|
| 690 |
+
if (Status::kSuccess == status) {
|
| 691 |
+
status = run(stream);
|
| 692 |
+
}
|
| 693 |
+
return status;
|
| 694 |
+
}
|
| 695 |
+
|
| 696 |
+
/// Launches the kernel after first constructing Params internal state from supplied arguments.
|
| 697 |
+
Status
|
| 698 |
+
operator()(
|
| 699 |
+
Arguments const* args,
|
| 700 |
+
void** workspace_ptrs,
|
| 701 |
+
void** exclusive_workspace_ptrs,
|
| 702 |
+
int device_idx,
|
| 703 |
+
cudaStream_t stream = nullptr) {
|
| 704 |
+
return run(
|
| 705 |
+
args,
|
| 706 |
+
workspace_ptrs,
|
| 707 |
+
exclusive_workspace_ptrs,
|
| 708 |
+
device_idx,
|
| 709 |
+
stream);
|
| 710 |
+
}
|
| 711 |
+
};
|
| 712 |
+
|
| 713 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 714 |
+
|
| 715 |
+
} // namespace cutlass::distributed::device
|
| 716 |
+
|
| 717 |
+
////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/device/full_barrier.hpp
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief Device layer interface for Distributed GEMM barrier kernel.
|
| 33 |
+
*/
|
| 34 |
+
|
| 35 |
+
#pragma once
|
| 36 |
+
|
| 37 |
+
#include "cutlass/cutlass.h"
|
| 38 |
+
#include "cutlass/experimental/distributed/kernel/full_barrier.hpp"
|
| 39 |
+
|
| 40 |
+
namespace cutlass::distributed::device {
|
| 41 |
+
|
| 42 |
+
template <int NP, typename IntType, int Iterations, typename FlagType>
|
| 43 |
+
void launch_full_barrier(
|
| 44 |
+
cutlass::Array<IntType*, NP> device_arrival_ptrs,
|
| 45 |
+
cutlass::Array<FlagType*, Iterations> iteration_flag_ptrs,
|
| 46 |
+
IntType device_idx,
|
| 47 |
+
cudaStream_t stream,
|
| 48 |
+
bool launch_with_pdl) {
|
| 49 |
+
|
| 50 |
+
#if (__CUDACC_VER_MAJOR__ > 12 || (__CUDACC_VER_MAJOR__ == 12 && __CUDACC_VER_MINOR__ >= 6))
|
| 51 |
+
// Legacy (kernel) launch with PDL
|
| 52 |
+
cudaLaunchAttribute attributes[1];
|
| 53 |
+
attributes[0].id = cudaLaunchAttributeProgrammaticStreamSerialization;
|
| 54 |
+
attributes[0].val.programmaticStreamSerializationAllowed = 1;
|
| 55 |
+
|
| 56 |
+
cudaLaunchConfig_t launch_config;
|
| 57 |
+
launch_config.gridDim = 1;
|
| 58 |
+
launch_config.blockDim = 1;
|
| 59 |
+
launch_config.dynamicSmemBytes = 0;
|
| 60 |
+
launch_config.stream = stream;
|
| 61 |
+
launch_config.attrs = attributes;
|
| 62 |
+
launch_config.numAttrs = launch_with_pdl ? 1 : 0;
|
| 63 |
+
|
| 64 |
+
cudaLaunchKernelEx(
|
| 65 |
+
&launch_config,
|
| 66 |
+
cutlass::distributed::kernel::full_barrier_kernel<NP, IntType, Iterations, FlagType>,
|
| 67 |
+
device_arrival_ptrs,
|
| 68 |
+
iteration_flag_ptrs,
|
| 69 |
+
device_idx);
|
| 70 |
+
#endif
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
} // namespace cutlass::distributed::device
|
| 74 |
+
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/kernel/detail.hpp
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief Distributed gemm kernel layer helpers.
|
| 33 |
+
*/
|
| 34 |
+
|
| 35 |
+
#pragma once
|
| 36 |
+
|
| 37 |
+
#include "cutlass/cutlass.h"
|
| 38 |
+
|
| 39 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 40 |
+
|
| 41 |
+
namespace cutlass::distributed::kernel::detail {
|
| 42 |
+
|
| 43 |
+
// Ld with CV cache hint (don’t cache and fetch again)
|
| 44 |
+
// Reference:
|
| 45 |
+
// https://docs.nvidia.com/cuda/parallel-thread-execution/#cache-operators
|
| 46 |
+
// Used for loading arrival counts from peer devices
|
| 47 |
+
|
| 48 |
+
CUTLASS_DEVICE
|
| 49 |
+
void ld_without_cache(uint64_t& val, void const * ptr) {
|
| 50 |
+
asm volatile(
|
| 51 |
+
"{\n"
|
| 52 |
+
" ld.global.cv.u64 %0, [%1];\n"
|
| 53 |
+
"}\n"
|
| 54 |
+
: "=l"(val)
|
| 55 |
+
: "l"(ptr));
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
CUTLASS_DEVICE
|
| 59 |
+
void ld_without_cache(uint32_t& val, void const * ptr) {
|
| 60 |
+
asm volatile(
|
| 61 |
+
"{\n"
|
| 62 |
+
" ld.global.cv.u32 %0, [%1];\n"
|
| 63 |
+
"}\n"
|
| 64 |
+
: "=r"(val)
|
| 65 |
+
: "l"(ptr));
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
} // namespace cutlass::distributed::kernel::detail
|
| 69 |
+
|
| 70 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 71 |
+
|
| 72 |
+
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/kernel/dist_gemm_kernel_wrapper.hpp
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
\file Distributed GEMM Kernel Wrapper
|
| 33 |
+
|
| 34 |
+
Prepends CUTLASS 3 GEMM kernels with barriers and other necessary instructions to exectue
|
| 35 |
+
a Distributed GEMM stage.
|
| 36 |
+
*/
|
| 37 |
+
|
| 38 |
+
#pragma once
|
| 39 |
+
|
| 40 |
+
#include "cutlass/cutlass.h"
|
| 41 |
+
#include "cutlass/arch/grid_dependency_control.h"
|
| 42 |
+
#include "cutlass/gemm/gemm.h"
|
| 43 |
+
|
| 44 |
+
#include "cutlass/experimental/distributed/kernel/detail.hpp"
|
| 45 |
+
|
| 46 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 47 |
+
|
| 48 |
+
namespace cutlass::distributed::kernel {
|
| 49 |
+
|
| 50 |
+
namespace detail {
|
| 51 |
+
|
| 52 |
+
// Allow all CUTLASS 3.X GEMM kernels
|
| 53 |
+
template <typename GemmKernel_>
|
| 54 |
+
struct SupportsDistributedGemm: cutlass::gemm::detail::IsCutlass3GemmKernel<GemmKernel_> {};
|
| 55 |
+
|
| 56 |
+
} // namespace detail
|
| 57 |
+
|
| 58 |
+
/*!
|
| 59 |
+
DistributedGemmKernelWrapper is a wrapper around a GEMM kernel.
|
| 60 |
+
|
| 61 |
+
Depending on the underlying distribution policy/schedule, it prepends the underlying local GEMM
|
| 62 |
+
kernel with a few additional instructions that gate the execution of the GEMM on buffers being
|
| 63 |
+
ready for stages/iterations > 0.
|
| 64 |
+
*/
|
| 65 |
+
|
| 66 |
+
template <class GemmKernel_, class DistSchedule_, class Enable = void>
|
| 67 |
+
struct DistributedGemmKernelWrapper;
|
| 68 |
+
|
| 69 |
+
template <class GemmKernel_, class DistSchedule_>
|
| 70 |
+
struct DistributedGemmKernelWrapper<
|
| 71 |
+
GemmKernel_,
|
| 72 |
+
DistSchedule_,
|
| 73 |
+
cute::enable_if_t<detail::SupportsDistributedGemm<GemmKernel_>::value>
|
| 74 |
+
>: GemmKernel_
|
| 75 |
+
{
|
| 76 |
+
using DistSchedule = DistSchedule_;
|
| 77 |
+
using TP = typename DistSchedule::TP;
|
| 78 |
+
|
| 79 |
+
static constexpr bool KernelWritesArrivalFlag = DistSchedule::KernelWritesArrivalFlag;
|
| 80 |
+
|
| 81 |
+
using BaseKernel = GemmKernel_;
|
| 82 |
+
using BaseArguments = typename BaseKernel::Arguments;
|
| 83 |
+
using BaseParams = typename BaseKernel::Params;
|
| 84 |
+
|
| 85 |
+
//static_assert(BaseKernel::ArchTag::kMinComputeCapability == 90, "DistGEMM only supports Hopper GEMMs for now.");
|
| 86 |
+
static_assert(not cute::is_same_v<typename BaseKernel::ElementC, void>, "DistributedGEMM epilogues must have a source.");
|
| 87 |
+
|
| 88 |
+
using ElementFlag = uint32_t;
|
| 89 |
+
|
| 90 |
+
// Device side arguments
|
| 91 |
+
struct DistributedArguments {
|
| 92 |
+
int device_idx = 0;
|
| 93 |
+
int iteration = 0;
|
| 94 |
+
|
| 95 |
+
void* self_flag_ptr{nullptr};
|
| 96 |
+
void* peer_flag_ptr{nullptr};
|
| 97 |
+
};
|
| 98 |
+
|
| 99 |
+
struct PackedArguments {
|
| 100 |
+
BaseArguments base{};
|
| 101 |
+
DistributedArguments distributed{};
|
| 102 |
+
};
|
| 103 |
+
|
| 104 |
+
struct DistributedParams {
|
| 105 |
+
int device_idx = 0;
|
| 106 |
+
int iteration = 0;
|
| 107 |
+
|
| 108 |
+
ElementFlag* self_flag_ptr_{nullptr};
|
| 109 |
+
ElementFlag* peer_flag_ptr_{nullptr};
|
| 110 |
+
};
|
| 111 |
+
|
| 112 |
+
// Kernel entry point API
|
| 113 |
+
struct PackedParams {
|
| 114 |
+
BaseParams base{};
|
| 115 |
+
DistributedParams distributed{};
|
| 116 |
+
};
|
| 117 |
+
|
| 118 |
+
using Params = PackedParams;
|
| 119 |
+
|
| 120 |
+
// Convert to underlying arguments. In this case, a simple copy for the aliased type.
|
| 121 |
+
static
|
| 122 |
+
PackedParams
|
| 123 |
+
to_underlying_arguments(PackedArguments const& args, void* workspace) {
|
| 124 |
+
CUTLASS_TRACE_HOST("distributed::to_underlying_arguments():");
|
| 125 |
+
|
| 126 |
+
auto kernel_params = BaseKernel::to_underlying_arguments(args.base, workspace);
|
| 127 |
+
|
| 128 |
+
DistributedParams dist_params = {
|
| 129 |
+
args.distributed.device_idx,
|
| 130 |
+
args.distributed.iteration,
|
| 131 |
+
reinterpret_cast<ElementFlag*>(args.distributed.self_flag_ptr),
|
| 132 |
+
reinterpret_cast<ElementFlag*>(args.distributed.peer_flag_ptr)
|
| 133 |
+
};
|
| 134 |
+
|
| 135 |
+
return {kernel_params, dist_params};
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
static bool
|
| 139 |
+
can_implement(BaseArguments const& args) {
|
| 140 |
+
return BaseKernel::can_implement(args);
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
static bool
|
| 144 |
+
can_implement(PackedArguments const& args) {
|
| 145 |
+
return BaseKernel::can_implement(args.base);
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
static size_t
|
| 149 |
+
get_workspace_size(BaseArguments const& args) {
|
| 150 |
+
return BaseKernel::get_workspace_size(args);
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
static size_t
|
| 154 |
+
get_workspace_size(PackedArguments const& args) {
|
| 155 |
+
return BaseKernel::get_workspace_size(args.base);
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
static cutlass::Status
|
| 159 |
+
initialize_workspace(BaseArguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr,
|
| 160 |
+
CudaHostAdapter* cuda_adapter = nullptr) {
|
| 161 |
+
return BaseKernel::initialize_workspace(args, workspace, stream, cuda_adapter);
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
static cutlass::Status
|
| 165 |
+
initialize_workspace(PackedArguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr,
|
| 166 |
+
CudaHostAdapter* cuda_adapter = nullptr) {
|
| 167 |
+
return BaseKernel::initialize_workspace(args.base, workspace, stream, cuda_adapter);
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
/// Computes the grid shape
|
| 171 |
+
static dim3
|
| 172 |
+
get_grid_shape(PackedParams const& params) {
|
| 173 |
+
return BaseKernel::get_grid_shape(params.base);
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
static dim3
|
| 177 |
+
get_grid_shape(BaseParams const& params) {
|
| 178 |
+
return BaseKernel::get_grid_shape(params);
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
CUTLASS_DEVICE
|
| 182 |
+
void
|
| 183 |
+
barrier_buffer(PackedParams const& params) {
|
| 184 |
+
if (params.distributed.iteration > 0) {
|
| 185 |
+
|
| 186 |
+
ElementFlag comm_iter = 0;
|
| 187 |
+
detail::ld_without_cache(comm_iter, params.distributed.self_flag_ptr_);
|
| 188 |
+
while (comm_iter == 0) {
|
| 189 |
+
detail::ld_without_cache(comm_iter, params.distributed.self_flag_ptr_);
|
| 190 |
+
__nanosleep(40);
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
}
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
CUTLASS_DEVICE
|
| 197 |
+
void
|
| 198 |
+
maybe_signal_arrival(PackedParams const& params) {
|
| 199 |
+
if constexpr (KernelWritesArrivalFlag) {
|
| 200 |
+
if (blockIdx.x == 0 && blockIdx.y == 0 && blockIdx.z == 0 &&
|
| 201 |
+
threadIdx.x == 0 && threadIdx.y == 0 && threadIdx.z == 0 &&
|
| 202 |
+
params.distributed.iteration > 0) {
|
| 203 |
+
*reinterpret_cast<ElementFlag*>(params.distributed.peer_flag_ptr_) = 1;
|
| 204 |
+
}
|
| 205 |
+
}
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
CUTLASS_DEVICE
|
| 209 |
+
void
|
| 210 |
+
operator()(PackedParams const& params, char* smem_buf) {
|
| 211 |
+
// Launch next grid as soon as possible
|
| 212 |
+
arch::launch_dependent_grids();
|
| 213 |
+
|
| 214 |
+
// Wait on previous kernels to flush their memory.
|
| 215 |
+
arch::wait_on_dependent_grids();
|
| 216 |
+
|
| 217 |
+
// Optionally write arrivals for the previous stage/iteration.
|
| 218 |
+
maybe_signal_arrival(params);
|
| 219 |
+
|
| 220 |
+
// Spin-wait on an arrival flag, make sure the respective buffers are ready.
|
| 221 |
+
// If the buffered operand is memcpied into, it would wait on its local flag.
|
| 222 |
+
// If it's a remote buffer that is accessed directly, it would wait on its remote flag.
|
| 223 |
+
barrier_buffer(params);
|
| 224 |
+
|
| 225 |
+
// Perform local gemm
|
| 226 |
+
BaseKernel gemm;
|
| 227 |
+
gemm(params.base, smem_buf);
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
};
|
| 231 |
+
|
| 232 |
+
} // namespace cutlass::distributed::kernel
|
| 233 |
+
|
| 234 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 235 |
+
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/kernel/full_barrier.hpp
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief Distributed GEMM barrier kernel.
|
| 33 |
+
|
| 34 |
+
The kernel resets the per-stage arrival flags, performs a full barrier (any-to-any),
|
| 35 |
+
and also atomically resets the local barrier arrival count.
|
| 36 |
+
*/
|
| 37 |
+
|
| 38 |
+
#pragma once
|
| 39 |
+
|
| 40 |
+
#include "cutlass/cutlass.h"
|
| 41 |
+
#include "cutlass/arch/grid_dependency_control.h"
|
| 42 |
+
|
| 43 |
+
#include "cutlass/experimental/distributed/kernel/detail.hpp"
|
| 44 |
+
|
| 45 |
+
namespace cutlass::distributed::kernel {
|
| 46 |
+
|
| 47 |
+
template <int NP, typename IntType, int Iterations, typename FlagType>
|
| 48 |
+
__global__ void full_barrier_kernel(
|
| 49 |
+
cutlass::Array<IntType*, NP> device_arrival_ptrs,
|
| 50 |
+
cutlass::Array<FlagType*, Iterations> iteration_flag_ptrs,
|
| 51 |
+
IntType device_idx) {
|
| 52 |
+
|
| 53 |
+
arch::launch_dependent_grids();
|
| 54 |
+
arch::wait_on_dependent_grids();
|
| 55 |
+
|
| 56 |
+
CUTLASS_PRAGMA_UNROLL
|
| 57 |
+
for (FlagType i = 0; i < Iterations; ++i) {
|
| 58 |
+
iteration_flag_ptrs[i][0] = static_cast<FlagType>(0);
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
IntType val = 1;
|
| 62 |
+
IntType max_val = static_cast<IntType>(NP - 1);
|
| 63 |
+
|
| 64 |
+
CUTLASS_PRAGMA_UNROLL
|
| 65 |
+
for (IntType d = 0; d < NP; ++d) {
|
| 66 |
+
if (d != device_idx) {
|
| 67 |
+
atomicAdd(device_arrival_ptrs[d], val);
|
| 68 |
+
}
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
IntType curr_val = 0;
|
| 72 |
+
detail::ld_without_cache(curr_val, device_arrival_ptrs[device_idx]);
|
| 73 |
+
while (curr_val < max_val) {
|
| 74 |
+
__nanosleep(40);
|
| 75 |
+
detail::ld_without_cache(curr_val, device_arrival_ptrs[device_idx]);
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
atomicSub(device_arrival_ptrs[device_idx], max_val);
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
} // namespace cutlass::distributed::kernel
|
| 82 |
+
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/schedules/dist_gemm_1d_schedules.hpp
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
\file 1-D Distributed GEMM Schedules
|
| 33 |
+
|
| 34 |
+
NOTE: This API is __experimental__ and will change heavily over time. Particularly the use of
|
| 35 |
+
CuTe layouts as integer functions in defining iteration-to-tile mappings is over-expressive and
|
| 36 |
+
leaves plenty of room for incorrect/unexpected behavior.
|
| 37 |
+
Please proceed with caution when modifying these schedules or defining new ones.
|
| 38 |
+
|
| 39 |
+
Device/iteration mappings are defined with CuTe layouts,
|
| 40 |
+
since they are functions from integers to integers as well.
|
| 41 |
+
|
| 42 |
+
Each mapping is defined as a linear function of 2 variables (rank-2 layout):
|
| 43 |
+
First variable (mode) is device index, second variable (mode) is iteration.
|
| 44 |
+
A constant is also added to the final result as an offset value. This is a temporary workaround
|
| 45 |
+
so that identity ownership mappings in the final iteration can be guaranteed for the schedules
|
| 46 |
+
currently implemented.
|
| 47 |
+
How are these mappings defined?
|
| 48 |
+
Each schedule represents a unique parallel matrix multiplication algorithm, which describes how
|
| 49 |
+
matrices/tensors are distributed among TP GPUs.
|
| 50 |
+
|
| 51 |
+
Depending on the algorithm, access patterns (GPU to tile or (GPU, iteration) to tile) mappings)
|
| 52 |
+
are not necessarily going to be the identity function.
|
| 53 |
+
|
| 54 |
+
Pitfalls:
|
| 55 |
+
The current representation uses CuTe layouts as arbitrary linear functions that map
|
| 56 |
+
(GPU, iteration) to tile indices.
|
| 57 |
+
This approach is over-expressive, and therefore makes a lot of assumptions on the part of the
|
| 58 |
+
developer in how these mappings are defined. This can easily lead to incorrect implementations
|
| 59 |
+
if not handled carefully.
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
Assumption made in all schedules: TP == number of iterations (stages)
|
| 63 |
+
*/
|
| 64 |
+
|
| 65 |
+
#pragma once
|
| 66 |
+
|
| 67 |
+
#include "cute/layout.hpp"
|
| 68 |
+
#include "cute/tensor.hpp"
|
| 69 |
+
#include "cutlass/cutlass.h"
|
| 70 |
+
|
| 71 |
+
#include "cutlass/experimental/distributed/schedules/dist_gemm_base_schedule.hpp"
|
| 72 |
+
|
| 73 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 74 |
+
|
| 75 |
+
namespace cutlass::distributed::schedules {
|
| 76 |
+
|
| 77 |
+
// GEMM + Reduce Scatter
|
| 78 |
+
// A and B are tiled along the K mode, which means each GPU gets an [M, K / TP]-shaped slice of A,
|
| 79 |
+
// and an [N, K / TP] slice of B.
|
| 80 |
+
// A is further tiled along the M mode, so that each stage/iteration computes a GEMM of shape
|
| 81 |
+
// [M / TP, N, K / TP], and the epilogue will perform the reduction by reading its C tensor directly
|
| 82 |
+
// from the left peer's previous D buffer.
|
| 83 |
+
//
|
| 84 |
+
// Below is an illustration of the tiling and iteration mappings for this pattern in the TP=4 case:
|
| 85 |
+
//
|
| 86 |
+
// Rows correspond to the M mode, columns correspond to the K mode for A and B and N mode for
|
| 87 |
+
// C and D. Because sharding is done along K, each column of tiles is owned by one GPU.
|
| 88 |
+
// Values in the grid correspond to the iteration/stage accessing the tile.
|
| 89 |
+
// * means the same tile is accessed in all iterations/stages.
|
| 90 |
+
//
|
| 91 |
+
// Tensor A Tensor B
|
| 92 |
+
//
|
| 93 |
+
// GPU0 GPU1 GPU2 GPU3 GPU0 GPU1 GPU2 GPU3
|
| 94 |
+
// |-----|-----|-----|-----| |-----|-----|-----|-----|
|
| 95 |
+
// | | | | | | | | | |
|
| 96 |
+
// | 3 | 0 | 1 | 2 | | | | | |
|
| 97 |
+
// |_____|_____|_____|_____| | | | | |
|
| 98 |
+
// | | | | | | | | | |
|
| 99 |
+
// | 2 | 3 | 0 | 1 | | | | | |
|
| 100 |
+
// |_____|_____|_____|_____| | * | * | * | * |
|
| 101 |
+
// | | | | | | | | | |
|
| 102 |
+
// | 1 | 2 | 3 | 0 | | | | | |
|
| 103 |
+
// |_____|_____|_____|_____| | | | | |
|
| 104 |
+
// | | | | | | | | | |
|
| 105 |
+
// | 0 | 1 | 2 | 3 | | | | | |
|
| 106 |
+
// |_____|_____|_____|_____| |_____|_____|_____|_____|
|
| 107 |
+
//
|
| 108 |
+
// M x K N x K
|
| 109 |
+
//
|
| 110 |
+
//
|
| 111 |
+
// Tensor C Tensor D
|
| 112 |
+
// (Peer's D)
|
| 113 |
+
//
|
| 114 |
+
//
|
| 115 |
+
// |-----------------------| |-----------------------|
|
| 116 |
+
// | | | |
|
| 117 |
+
// GPU0 | 1,2,3 | GPU0 | * |
|
| 118 |
+
// |_______________________| |_______________________|
|
| 119 |
+
// | | | |
|
| 120 |
+
// GPU1 | 1,2,3 | GPU1 | * |
|
| 121 |
+
// |_______________________| |_______________________|
|
| 122 |
+
// | | | |
|
| 123 |
+
// GPU2 | 1,2,3 | GPU2 | * |
|
| 124 |
+
// |_______________________| |_______________________|
|
| 125 |
+
// | | | |
|
| 126 |
+
// GPU3 | 1,2,3 | GPU3 | * |
|
| 127 |
+
// |_______________________| |_______________________|
|
| 128 |
+
//
|
| 129 |
+
// M x N M x N
|
| 130 |
+
//
|
| 131 |
+
//
|
| 132 |
+
// Tensor A's access pattern can be expressed as follows as a function of GPU index and iteration:
|
| 133 |
+
// tile_idx = ((device_idx - 1) - iter + TP) % TP
|
| 134 |
+
//
|
| 135 |
+
// and can be expressed with the following CuTe layout:
|
| 136 |
+
// (TP, TP) : (1, -1)
|
| 137 |
+
// with ProcessorOffset = -1
|
| 138 |
+
//
|
| 139 |
+
//
|
| 140 |
+
// Note: Since this schedule does not expose any communication, iteration 0 has no reduction step,
|
| 141 |
+
// therefore epilogue is sourceless in iteration 0, and in the rest of the iterations the epilogue
|
| 142 |
+
// source is a remote pointer to Tensor D owned by its left peer.
|
| 143 |
+
//
|
| 144 |
+
// Left peer is simply (device_idx - 1 + TP) % TP, which is expressed with the following CuTe layout:
|
| 145 |
+
// (TP, TP) : (1, 0)
|
| 146 |
+
//
|
| 147 |
+
template <class TP_>
|
| 148 |
+
struct ReduceScatter1D_TilingA_RotatingC: BaseSchedule<
|
| 149 |
+
TP_,
|
| 150 |
+
/* ProcessorTiler_ = */ cute::Shape<_1, _1, TP_, _1>,
|
| 151 |
+
/* IterationTiler_ = */ cute::Shape<TP_, _1, _1, _1>,
|
| 152 |
+
/* PeerDeviceMapping_ = */ cute::Layout<cute::Shape<TP_, TP_>, cute::Stride<_1, _0>>, // (left neighbor) = (device_idx + ProcessorOffset + TP) % TP, with ProcessorOffset = -1
|
| 153 |
+
/* IterationMappingM_ = */ cute::Layout<cute::Shape<TP_, TP_>, cute::Stride<_1, _m1>>, // = (device_idx + ProcessorOffset - iter + TP) % TP, with ProcessorOffset = -1
|
| 154 |
+
/* IterationMappingN_ = */ cute::Layout<cute::Shape<TP_, TP_>, cute::Stride<_0, _0>>, // (IterationTiler::N == 1) = 0
|
| 155 |
+
/* IterationMappingK_ = */ cute::Layout<cute::Shape<TP_, TP_>, cute::Stride<_0, _0>>, // (IterationTiler::K == 1) = 0
|
| 156 |
+
/* IterationMappingL_ = */ cute::Layout<cute::Shape<TP_, TP_>, cute::Stride<_0, _0>>, // (IterationTiler::L == 1) = 0
|
| 157 |
+
/* ProcessorOffset_ = */ _m1,
|
| 158 |
+
/* MemcpyA_ = */ false,
|
| 159 |
+
/* MemcpyB_ = */ false,
|
| 160 |
+
/* KernelWritesArrivalFlag_ = */ true,
|
| 161 |
+
/* NumBuffersA_ = */ 0,
|
| 162 |
+
/* NumBuffersB_ = */ 0,
|
| 163 |
+
/* NumBuffersC_ = */ 0,
|
| 164 |
+
/* NumBuffersD_ = */ TP_{} - 1> {};
|
| 165 |
+
|
| 166 |
+
// This schedule is similar to ReduceScatter1D_TilingA_RotatingC, but with the second tiling
|
| 167 |
+
// done along N instead of M. All other details remain unchanged.
|
| 168 |
+
template <class TP_>
|
| 169 |
+
struct ReduceScatter1D_TilingB_RotatingC: BaseSchedule<
|
| 170 |
+
TP_,
|
| 171 |
+
/* ProcessorTiler_ = */ cute::Shape<_1, _1, TP_, _1>,
|
| 172 |
+
/* IterationTiler_ = */ cute::Shape<_1, TP_, _1, _1>,
|
| 173 |
+
/* PeerDeviceMapping_ = */ cute::Layout<cute::Shape<TP_, TP_>, cute::Stride<_1, _0>>, // (left neighbor) = (device_idx + ProcessorOffset + TP) % TP, with ProcessorOffset = -1
|
| 174 |
+
/* IterationMappingM_ = */ cute::Layout<cute::Shape<TP_, TP_>, cute::Stride<_0, _0>>, // (IterationTiler::N == 1) = 0
|
| 175 |
+
/* IterationMappingN_ = */ cute::Layout<cute::Shape<TP_, TP_>, cute::Stride<_1, _m1>>, // = (device_idx + ProcessorOffset - iter + TP) % TP, with ProcessorOffset = -1
|
| 176 |
+
/* IterationMappingK_ = */ cute::Layout<cute::Shape<TP_, TP_>, cute::Stride<_0, _0>>, // (IterationTiler::K == 1) = 0
|
| 177 |
+
/* IterationMappingL_ = */ cute::Layout<cute::Shape<TP_, TP_>, cute::Stride<_0, _0>>, // (IterationTiler::L == 1) = 0
|
| 178 |
+
/* ProcessorOffset_ = */ _m1,
|
| 179 |
+
/* MemcpyA_ = */ false,
|
| 180 |
+
/* MemcpyB_ = */ false,
|
| 181 |
+
/* KernelWritesArrivalFlag_ = */ true,
|
| 182 |
+
/* NumBuffersA_ = */ 0,
|
| 183 |
+
/* NumBuffersB_ = */ 0,
|
| 184 |
+
/* NumBuffersC_ = */ 0,
|
| 185 |
+
/* NumBuffersD_ = */ TP_{} - 1> {};
|
| 186 |
+
|
| 187 |
+
|
| 188 |
+
// AllGather + GEMM
|
| 189 |
+
// A and B are tiled along the N mode, which means each GPU allgathers A,
|
| 190 |
+
// and operates with an [N / TP, K] slice of B.
|
| 191 |
+
// For pipelining, A is further tiled along the M mode, so that each stage/iteration computes a
|
| 192 |
+
// GEMM of shape [M / TP, N / TP, K], and concurrently we copy a peer's A slice into a local buffer
|
| 193 |
+
// for the next stage/iteration.
|
| 194 |
+
//
|
| 195 |
+
// Below is an illustration of the tiling and iteration mappings for this pattern in the TP=4 case:
|
| 196 |
+
//
|
| 197 |
+
// Rows correspond to the M mode, columns correspond to the K mode for A and B and N mode for
|
| 198 |
+
// C and D.
|
| 199 |
+
//
|
| 200 |
+
// Since this is a pipelined schedule without exposed communication, the first iteration starts
|
| 201 |
+
// off immediately and operates on local slices of A and B. In the rest of the iterations, each
|
| 202 |
+
// GPU accesses a slice of A copied from a peer GPU while it was busy with the last stage.
|
| 203 |
+
//
|
| 204 |
+
// Values in the following grids correspond to the peer buffer accessed by each GPU during
|
| 205 |
+
// different iterations:
|
| 206 |
+
//
|
| 207 |
+
// Tensor A Tensor A
|
| 208 |
+
// iter 0 iter 1
|
| 209 |
+
//
|
| 210 |
+
// |-----------------------| |-----------------------|
|
| 211 |
+
// | | | |
|
| 212 |
+
// GPU0 | 0 | | 1 |
|
| 213 |
+
// |_______________________| |_______________________|
|
| 214 |
+
// | | | |
|
| 215 |
+
// GPU1 | 1 | | 2 |
|
| 216 |
+
// |_______________________| |_______________________|
|
| 217 |
+
// | | | |
|
| 218 |
+
// GPU2 | 2 | | 3 |
|
| 219 |
+
// |_______________________| |_______________________|
|
| 220 |
+
// | | | |
|
| 221 |
+
// GPU3 | 3 | | 0 |
|
| 222 |
+
// |_______________________| |_______________________|
|
| 223 |
+
//
|
| 224 |
+
// M x K M x K
|
| 225 |
+
//
|
| 226 |
+
// Tensor A Tensor A
|
| 227 |
+
// iter 2 iter 3
|
| 228 |
+
//
|
| 229 |
+
// |-----------------------| |-----------------------|
|
| 230 |
+
// | | | |
|
| 231 |
+
// GPU0 | 2 | | 3 |
|
| 232 |
+
// |_______________________| |_______________________|
|
| 233 |
+
// | | | |
|
| 234 |
+
// GPU1 | 3 | | 0 |
|
| 235 |
+
// |_______________________| |_______________________|
|
| 236 |
+
// | | | |
|
| 237 |
+
// GPU2 | 0 | | 1 |
|
| 238 |
+
// |_______________________| |_______________________|
|
| 239 |
+
// | | | |
|
| 240 |
+
// GPU3 | 1 | | 2 |
|
| 241 |
+
// |_______________________| |_______________________|
|
| 242 |
+
//
|
| 243 |
+
// M x K M x K
|
| 244 |
+
//
|
| 245 |
+
// Values in the following grids correspond to the tile accessed during each iteration.
|
| 246 |
+
// * means the same tile is accessed in all iterations/stages.
|
| 247 |
+
//
|
| 248 |
+
// Tensor B Tensor C/D
|
| 249 |
+
//
|
| 250 |
+
//
|
| 251 |
+
// |-----------------------| |-----|-----|-----|-----|
|
| 252 |
+
// | | | | | | |
|
| 253 |
+
// GPU0 | * | GPU0 | 0 | 1 | 2 | 3 |
|
| 254 |
+
// |_______________________| |_____|_____|_____|_____|
|
| 255 |
+
// | | | | | | |
|
| 256 |
+
// GPU1 | * | GPU1 | 3 | 0 | 1 | 2 |
|
| 257 |
+
// |_______________________| |_____|_____|_____|_____|
|
| 258 |
+
// | | | | | | |
|
| 259 |
+
// GPU2 | * | GPU2 | 2 | 3 | 0 | 1 |
|
| 260 |
+
// |_______________________| |_____|_____|_____|_____|
|
| 261 |
+
// | | | | | | |
|
| 262 |
+
// GPU3 | * | GPU3 | 1 | 2 | 3 | 0 |
|
| 263 |
+
// |_______________________| |_____|_____|_____|_____|
|
| 264 |
+
//
|
| 265 |
+
// N x K M x N
|
| 266 |
+
//
|
| 267 |
+
//
|
| 268 |
+
// Tensor C/D's access pattern can be expressed as follows as a function of GPU index and iteration:
|
| 269 |
+
// tile_idx = (device_idx + iter) % TP
|
| 270 |
+
//
|
| 271 |
+
// and can be expressed with the following CuTe layout:
|
| 272 |
+
// (TP, TP) : (1, 1)
|
| 273 |
+
//
|
| 274 |
+
// This schedule does not need a ProcessorOffset constant.
|
| 275 |
+
//
|
| 276 |
+
// Peer devices from which A slices are copied is also expressed with the same function and CuTe
|
| 277 |
+
// layout.
|
| 278 |
+
//
|
| 279 |
+
template <class TP_>
|
| 280 |
+
struct AllGather1D_TilingCD_RotatingA: BaseSchedule<
|
| 281 |
+
TP_,
|
| 282 |
+
/* ProcessorTiler_ = */ cute::Shape<_1, TP_, _1, _1>,
|
| 283 |
+
/* IterationTiler_ = */ cute::Shape<TP_, _1, _1, _1>,
|
| 284 |
+
/* PeerDeviceMapping_ = */ cute::Layout<cute::Shape<TP_, TP_>, cute::Stride<_1, _1>>, // = device_idx + iter
|
| 285 |
+
/* IterationMappingM_ = */ cute::Layout<cute::Shape<TP_, TP_>, cute::Stride<_1, _1>>, // = device_idx + iter
|
| 286 |
+
/* IterationMappingN_ = */ cute::Layout<cute::Shape<TP_, TP_>, cute::Stride<_0, _0>>, // (IterationTiler::N == 1) = 0
|
| 287 |
+
/* IterationMappingK_ = */ cute::Layout<cute::Shape<TP_, TP_>, cute::Stride<_0, _0>>, // (IterationTiler::K == 1) = 0
|
| 288 |
+
/* IterationMappingL_ = */ cute::Layout<cute::Shape<TP_, TP_>, cute::Stride<_0, _0>>, // (IterationTiler::L == 1) = 0
|
| 289 |
+
/* ProcessorOffset_ = */ _0,
|
| 290 |
+
/* MemcpyA_ = */ true,
|
| 291 |
+
/* MemcpyB_ = */ false,
|
| 292 |
+
/* KernelWritesArrivalFlag_ = */ false,
|
| 293 |
+
/* NumBuffersA_ = */ TP_{} - 1,
|
| 294 |
+
/* NumBuffersB_ = */ 0,
|
| 295 |
+
/* NumBuffersC_ = */ 0,
|
| 296 |
+
/* NumBuffersD_ = */ 0>{};
|
| 297 |
+
|
| 298 |
+
// This schedule is similar to AllGather1D_TilingCD_RotatingA, but with the order of tiling
|
| 299 |
+
// swapped from N then M to M then N. This means slices of B are rotated around GPUs instead of
|
| 300 |
+
// slices of A. All other details remain unchanged.
|
| 301 |
+
template <class TP_>
|
| 302 |
+
struct AllGather1D_TilingCD_RotatingB: BaseSchedule<
|
| 303 |
+
TP_,
|
| 304 |
+
/* ProcessorTiler_ = */ cute::Shape<TP_, _1, _1, _1>,
|
| 305 |
+
/* IterationTiler_ = */ cute::Shape<_1, TP_, _1, _1>,
|
| 306 |
+
/* PeerDeviceMapping_ = */ cute::Layout<cute::Shape<TP_, TP_>, cute::Stride<_1, _1>>, // = device_idx + iter
|
| 307 |
+
/* IterationMappingM_ = */ cute::Layout<cute::Shape<TP_, TP_>, cute::Stride<_0, _0>>, // (IterationTiler::M == 1) = 0
|
| 308 |
+
/* IterationMappingN_ = */ cute::Layout<cute::Shape<TP_, TP_>, cute::Stride<_1, _1>>, // = device_idx + iter
|
| 309 |
+
/* IterationMappingK_ = */ cute::Layout<cute::Shape<TP_, TP_>, cute::Stride<_0, _0>>, // (IterationTiler::K == 1) = 0
|
| 310 |
+
/* IterationMappingL_ = */ cute::Layout<cute::Shape<TP_, TP_>, cute::Stride<_0, _0>>, // (IterationTiler::L == 1) = 0
|
| 311 |
+
/* ProcessorOffset_ = */ _0,
|
| 312 |
+
/* MemcpyA_ = */ false,
|
| 313 |
+
/* MemcpyB_ = */ true,
|
| 314 |
+
/* KernelWritesArrivalFlag_ = */ false,
|
| 315 |
+
/* NumBuffersA_ = */ 0,
|
| 316 |
+
/* NumBuffersB_ = */ TP_{} - 1,
|
| 317 |
+
/* NumBuffersC_ = */ 0,
|
| 318 |
+
/* NumBuffersD_ = */ 0>{};
|
| 319 |
+
|
| 320 |
+
|
| 321 |
+
} // namespace cutlass::distributed::schedules
|
| 322 |
+
|
| 323 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 324 |
+
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/schedules/dist_gemm_base_schedule.hpp
ADDED
|
@@ -0,0 +1,538 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
\file Base Schedule for Distributed GEMM
|
| 33 |
+
|
| 34 |
+
Templates Distributed GEMM schedules so that they can be expressed as a set of CuTe primitives and
|
| 35 |
+
other static values.
|
| 36 |
+
|
| 37 |
+
NOTE: This API is __experimental__ and will change heavily over time. Particularly the use of
|
| 38 |
+
CuTe layouts as integer functions in defining iteration-to-tile mappings is over-expressive and
|
| 39 |
+
leaves plenty of room for incorrect/unexpected behavior.
|
| 40 |
+
Please proceed with caution when modifying these schedules or defining new ones.
|
| 41 |
+
*/
|
| 42 |
+
|
| 43 |
+
#pragma once
|
| 44 |
+
|
| 45 |
+
#include "cute/layout.hpp"
|
| 46 |
+
#include "cute/tensor.hpp"
|
| 47 |
+
#include "cutlass/cutlass.h"
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 51 |
+
|
| 52 |
+
namespace cutlass::distributed::schedules {
|
| 53 |
+
|
| 54 |
+
/*
|
| 55 |
+
* Distributed GEMM schedules define exactly how operand tensors are tiled and sliced across
|
| 56 |
+
* processors (GPUs) and stages/iterations.
|
| 57 |
+
*
|
| 58 |
+
* BaseSchedule's role is to ease the implementation of arbitrary Distributed GEMM schedules
|
| 59 |
+
* and reduce code repetition, simply by reducing the implementation to CuTe primitives and a few
|
| 60 |
+
* other static values (buffer sizes, whether tensors are rotated using memcpies or not, and the
|
| 61 |
+
* like.)
|
| 62 |
+
*/
|
| 63 |
+
template <
|
| 64 |
+
class TP_, // CuTe constant defining the number of processors / GPUs / TP value
|
| 65 |
+
class ProcessorTiler_, // CuTe tiler defining how fully materialized tensors are sharded across devices
|
| 66 |
+
class IterationTiler_, // CuTe tiler defining how local tensors are tiled across stages/iterations
|
| 67 |
+
class PeerDeviceMapping_, // CuTe layout mapping device index and stage/iteration to the device's peer index for that stage/iteration
|
| 68 |
+
class IterationMappingM_, // CuTe layout mapping device index and stage/iteration to M tile index
|
| 69 |
+
class IterationMappingN_, // CuTe layout mapping device index and stage/iteration to N tile index
|
| 70 |
+
class IterationMappingK_, // CuTe layout mapping device index and stage/iteration to K tile index
|
| 71 |
+
class IterationMappingL_, // CuTe layout mapping device index and stage/iteration to L tile index
|
| 72 |
+
class ProcessorOffset_, // Constant offset for processor / GPU index in iteration mapping
|
| 73 |
+
bool MemcpyA_, // Whether tensor A is memcpied
|
| 74 |
+
bool MemcpyB_, // Whether tensor B is memcpied
|
| 75 |
+
bool KernelWritesArrivalFlag_, // Whether the kernel writes arrival flags (when tensors are directly accessed from peer and not memcpied)
|
| 76 |
+
int NumBuffersA_, // Number of buffers required for tensor A
|
| 77 |
+
int NumBuffersB_, // Number of buffers required for tensor B
|
| 78 |
+
int NumBuffersC_, // Number of buffers required for tensor C
|
| 79 |
+
int NumBuffersD_> // Number of buffers required for tensor D
|
| 80 |
+
struct BaseSchedule {
|
| 81 |
+
|
| 82 |
+
using TP = TP_;
|
| 83 |
+
|
| 84 |
+
static_assert(
|
| 85 |
+
cute::is_static<TP>::value && cute::is_integral<TP>::value && cute::rank(TP{}) == 1 && cute::depth(TP{}) == 0,
|
| 86 |
+
"Only integers allowed for TP at this time.");
|
| 87 |
+
|
| 88 |
+
static_assert(cute::rank(ProcessorTiler_{}) == 4, "Expected rank-4 processor tiler.");
|
| 89 |
+
static_assert(cute::rank(IterationTiler_{}) == 4, "Expected rank-4 iteration tiler.");
|
| 90 |
+
|
| 91 |
+
static_assert(cute::rank(PeerDeviceMapping_{}) == 2,
|
| 92 |
+
"PeerDeviceMapping must be rank-2 (device_idx, iter)");
|
| 93 |
+
|
| 94 |
+
static_assert(cute::rank(IterationMappingM_{}) == 2,
|
| 95 |
+
"IterationMappingM must be rank-2 (device_idx, iter).");
|
| 96 |
+
static_assert(cute::rank(IterationMappingN_{}) == 2,
|
| 97 |
+
"IterationMappingN must be rank-2 (device_idx, iter).");
|
| 98 |
+
static_assert(cute::rank(IterationMappingK_{}) == 2,
|
| 99 |
+
"IterationMappingK must be rank-2 (device_idx, iter).");
|
| 100 |
+
static_assert(cute::rank(IterationMappingL_{}) == 2,
|
| 101 |
+
"IterationMappingL must be rank-2 (device_idx, iter).");
|
| 102 |
+
|
| 103 |
+
using ProcessorTiler = ProcessorTiler_;
|
| 104 |
+
using IterationTiler = IterationTiler_;
|
| 105 |
+
|
| 106 |
+
using PeerDeviceMapping = PeerDeviceMapping_;
|
| 107 |
+
using IterationMappingM = IterationMappingM_;
|
| 108 |
+
using IterationMappingN = IterationMappingN_;
|
| 109 |
+
using IterationMappingK = IterationMappingK_;
|
| 110 |
+
using IterationMappingL = IterationMappingL_;
|
| 111 |
+
|
| 112 |
+
using ProcessorOffset = ProcessorOffset_;
|
| 113 |
+
|
| 114 |
+
static constexpr bool KernelWritesArrivalFlag = KernelWritesArrivalFlag_;
|
| 115 |
+
static constexpr bool MemcpyA = MemcpyA_;
|
| 116 |
+
static constexpr bool MemcpyB = MemcpyB_;
|
| 117 |
+
static constexpr bool HasMemcpy = MemcpyA || MemcpyB;
|
| 118 |
+
|
| 119 |
+
static constexpr int NumBuffersA = NumBuffersA_;
|
| 120 |
+
static constexpr int NumBuffersB = NumBuffersB_;
|
| 121 |
+
static constexpr int NumBuffersC = NumBuffersC_;
|
| 122 |
+
static constexpr int NumBuffersD = NumBuffersD_;
|
| 123 |
+
|
| 124 |
+
static_assert(
|
| 125 |
+
NumBuffersA > 0 ^
|
| 126 |
+
NumBuffersB > 0 ^
|
| 127 |
+
NumBuffersC > 0 ^
|
| 128 |
+
NumBuffersD > 0,
|
| 129 |
+
"Only one of the ABCD tensors can be buffered!");
|
| 130 |
+
|
| 131 |
+
static constexpr bool BufferedOutput = NumBuffersC > 0 || NumBuffersD > 0;
|
| 132 |
+
static constexpr bool RemoteC = NumBuffersC == 0 && NumBuffersD > 0;
|
| 133 |
+
static constexpr bool RemoteD = NumBuffersD == 0 && NumBuffersC > 0;
|
| 134 |
+
|
| 135 |
+
static_assert(not RemoteD, "Remote D is not supported yet.");
|
| 136 |
+
|
| 137 |
+
// Host-side API: can_implement based on the GLOBAL problem shape
|
| 138 |
+
template <typename ProblemShape>
|
| 139 |
+
static bool
|
| 140 |
+
can_implement_global(ProblemShape const& global_problem_shape) {
|
| 141 |
+
auto [M, N, K, L] = append<4>(global_problem_shape, 1);
|
| 142 |
+
|
| 143 |
+
auto [ptileM, ptileN, ptileK, ptileL] = ProcessorTiler{};
|
| 144 |
+
auto [itileM, itileN, itileK, itileL] = IterationTiler{};
|
| 145 |
+
|
| 146 |
+
auto tileM = ptileM * itileM;
|
| 147 |
+
auto tileN = ptileN * itileN;
|
| 148 |
+
auto tileK = ptileK * itileK;
|
| 149 |
+
auto tileL = ptileL * itileL;
|
| 150 |
+
|
| 151 |
+
return M % tileM == 0 && N % tileN == 0 && K % tileK == 0 && L % tileL == 0;
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
template <typename ProblemShape>
|
| 155 |
+
CUTLASS_HOST_DEVICE
|
| 156 |
+
static auto
|
| 157 |
+
get_local_gemm_shape(ProblemShape const& global_problem_shape) {
|
| 158 |
+
auto problem_shape_MNKL = append<4>(global_problem_shape, 1);
|
| 159 |
+
|
| 160 |
+
return shape_div(
|
| 161 |
+
shape_div(
|
| 162 |
+
problem_shape_MNKL,
|
| 163 |
+
ProcessorTiler{}),
|
| 164 |
+
IterationTiler{});
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
// Host-side API: determine peers
|
| 168 |
+
static auto
|
| 169 |
+
get_peers_for_device(int device_idx) {
|
| 170 |
+
auto left_peer_id = device_idx > 0 ? device_idx - 1 : TP{} - 1;
|
| 171 |
+
auto right_peer_id = device_idx < TP{} - 1 ? device_idx + 1 : 0;
|
| 172 |
+
|
| 173 |
+
return cute::make_tuple(left_peer_id, right_peer_id);
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
// Determines peer given device index and iteration
|
| 177 |
+
static int
|
| 178 |
+
get_remote_peer_id(int device_idx, int iteration) {
|
| 179 |
+
auto device_iter_to_peer_idx = PeerDeviceMapping{};
|
| 180 |
+
auto peer_idx = (
|
| 181 |
+
device_iter_to_peer_idx(device_idx + ProcessorOffset{}, iteration) + TP{}
|
| 182 |
+
) % TP{};
|
| 183 |
+
return peer_idx;
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
// Construct tilers and index mappers for sharding across processors
|
| 187 |
+
template <typename Tensor>
|
| 188 |
+
CUTLASS_HOST_DEVICE
|
| 189 |
+
static auto
|
| 190 |
+
get_processor_tiler_a(Tensor tensor) {
|
| 191 |
+
if constexpr (NumBuffersA > 0) {
|
| 192 |
+
return shape_div(tensor.shape(), select<0,2,3>(IterationTiler{}));
|
| 193 |
+
} else {
|
| 194 |
+
return shape_div(tensor.shape(), select<0,2,3>(ProcessorTiler{}));
|
| 195 |
+
}
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
template <typename Tensor>
|
| 199 |
+
CUTLASS_HOST_DEVICE
|
| 200 |
+
static auto
|
| 201 |
+
get_processor_tiler_b(Tensor tensor) {
|
| 202 |
+
if constexpr (NumBuffersB > 0) {
|
| 203 |
+
return shape_div(tensor.shape(), select<1,2,3>(IterationTiler{}));
|
| 204 |
+
} else {
|
| 205 |
+
return shape_div(tensor.shape(), select<1,2,3>(ProcessorTiler{}));
|
| 206 |
+
}
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
template <typename Tensor>
|
| 210 |
+
CUTLASS_HOST_DEVICE
|
| 211 |
+
static auto
|
| 212 |
+
get_processor_tiler_c(Tensor tensor) {
|
| 213 |
+
if constexpr (BufferedOutput) {
|
| 214 |
+
return shape_div(tensor.shape(), select<0,1,3>(IterationTiler{}));
|
| 215 |
+
} else {
|
| 216 |
+
return shape_div(tensor.shape(), select<0,1,3>(ProcessorTiler{}));
|
| 217 |
+
}
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
template <typename Tensor>
|
| 221 |
+
CUTLASS_HOST_DEVICE
|
| 222 |
+
static auto
|
| 223 |
+
get_processor_tiler_d(Tensor tensor) {
|
| 224 |
+
return get_processor_tiler_c(tensor);
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
// Construct tilers and index mappers for tiling and iterating on device
|
| 228 |
+
template <typename Tensor>
|
| 229 |
+
CUTLASS_HOST_DEVICE
|
| 230 |
+
static auto
|
| 231 |
+
get_device_tiler_a(Tensor tensor) {
|
| 232 |
+
static_assert(NumBuffersA == 0, "Buffered tensors don't have device tilers!");
|
| 233 |
+
return shape_div(tensor.shape(), select<0,2,3>(IterationTiler{}));
|
| 234 |
+
}
|
| 235 |
+
|
| 236 |
+
template <typename Tensor>
|
| 237 |
+
CUTLASS_HOST_DEVICE
|
| 238 |
+
static auto
|
| 239 |
+
get_device_tiler_b(Tensor tensor) {
|
| 240 |
+
static_assert(NumBuffersB == 0, "Buffered tensors don't have device tilers!");
|
| 241 |
+
return shape_div(tensor.shape(), select<1,2,3>(IterationTiler{}));
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
template <typename Tensor>
|
| 245 |
+
CUTLASS_HOST_DEVICE
|
| 246 |
+
static auto
|
| 247 |
+
get_device_tiler_c(Tensor tensor) {
|
| 248 |
+
static_assert(NumBuffersC == 0 && NumBuffersD == 0, "Buffered tensors don't have device tilers!");
|
| 249 |
+
return shape_div(tensor.shape(), select<0,1,3>(IterationTiler{}));
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
template <typename Tensor>
|
| 253 |
+
CUTLASS_HOST_DEVICE
|
| 254 |
+
static auto
|
| 255 |
+
get_device_tiler_d(Tensor tensor) {
|
| 256 |
+
static_assert(NumBuffersC == 0 && NumBuffersD == 0, "Buffered tensors don't have device tilers!");
|
| 257 |
+
return shape_div(tensor.shape(), select<0,1,3>(IterationTiler{}));
|
| 258 |
+
}
|
| 259 |
+
|
| 260 |
+
// Map device index and iteration to tile coordinate
|
| 261 |
+
// Must be implemented by children for now.
|
| 262 |
+
CUTLASS_HOST_DEVICE
|
| 263 |
+
static auto
|
| 264 |
+
get_device_tile_idx_a(int device_idx, int iteration) {
|
| 265 |
+
auto mapping_m = IterationMappingM{};
|
| 266 |
+
auto mapping_k = IterationMappingK{};
|
| 267 |
+
auto mapping_l = IterationMappingL{};
|
| 268 |
+
auto crd_m = (mapping_m(device_idx + ProcessorOffset{}, iteration) + TP{}) % TP{};
|
| 269 |
+
auto crd_k = (mapping_k(device_idx + ProcessorOffset{}, iteration) + TP{}) % TP{};
|
| 270 |
+
auto crd_l = (mapping_l(device_idx + ProcessorOffset{}, iteration) + TP{}) % TP{};
|
| 271 |
+
return make_coord(crd_m, crd_k, crd_l);
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
CUTLASS_HOST_DEVICE
|
| 275 |
+
static auto
|
| 276 |
+
get_device_tile_idx_b(int device_idx, int iteration) {
|
| 277 |
+
auto mapping_n = IterationMappingN{};
|
| 278 |
+
auto mapping_k = IterationMappingK{};
|
| 279 |
+
auto mapping_l = IterationMappingL{};
|
| 280 |
+
auto crd_n = (mapping_n(device_idx + ProcessorOffset{}, iteration) + TP{}) % TP{};
|
| 281 |
+
auto crd_k = (mapping_k(device_idx + ProcessorOffset{}, iteration) + TP{}) % TP{};
|
| 282 |
+
auto crd_l = (mapping_l(device_idx + ProcessorOffset{}, iteration) + TP{}) % TP{};
|
| 283 |
+
return make_coord(crd_n, crd_k, crd_l);
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
CUTLASS_HOST_DEVICE
|
| 287 |
+
static auto
|
| 288 |
+
get_device_tile_idx_c(int device_idx, int iteration) {
|
| 289 |
+
auto mapping_m = IterationMappingM{};
|
| 290 |
+
auto mapping_n = IterationMappingN{};
|
| 291 |
+
auto mapping_l = IterationMappingL{};
|
| 292 |
+
auto crd_m = (mapping_m(device_idx + ProcessorOffset{}, iteration) + TP{}) % TP{};
|
| 293 |
+
auto crd_n = (mapping_n(device_idx + ProcessorOffset{}, iteration) + TP{}) % TP{};
|
| 294 |
+
auto crd_l = (mapping_l(device_idx + ProcessorOffset{}, iteration) + TP{}) % TP{};
|
| 295 |
+
return make_coord(crd_m, crd_n, crd_l);
|
| 296 |
+
}
|
| 297 |
+
|
| 298 |
+
CUTLASS_HOST_DEVICE
|
| 299 |
+
static auto
|
| 300 |
+
get_device_tile_idx_d(int device_idx, int iteration) {
|
| 301 |
+
auto mapping_m = IterationMappingM{};
|
| 302 |
+
auto mapping_n = IterationMappingN{};
|
| 303 |
+
auto mapping_l = IterationMappingL{};
|
| 304 |
+
auto crd_m = (mapping_m(device_idx + ProcessorOffset{}, iteration) + TP{}) % TP{};
|
| 305 |
+
auto crd_n = (mapping_n(device_idx + ProcessorOffset{}, iteration) + TP{}) % TP{};
|
| 306 |
+
auto crd_l = (mapping_l(device_idx + ProcessorOffset{}, iteration) + TP{}) % TP{};
|
| 307 |
+
return make_coord(crd_m, crd_n, crd_l);
|
| 308 |
+
}
|
| 309 |
+
|
| 310 |
+
// Device Partitioners: partition non-buffered processor-resident operands.
|
| 311 |
+
// Processor-resident operands fall into two categories: buffered, and not buffered.
|
| 312 |
+
// Those buffered aren't expected to be further partitioned, and those
|
| 313 |
+
template <typename Tensor>
|
| 314 |
+
static auto
|
| 315 |
+
get_tensor_A(Tensor original_tensor, void * tensor_buffer_ptr, int device_idx, int iteration) {
|
| 316 |
+
static_assert(rank(original_tensor) == 3);
|
| 317 |
+
|
| 318 |
+
using Element = typename Tensor::value_type;
|
| 319 |
+
// Recreate tensor without constness. This is to ensure return types match.
|
| 320 |
+
Element* ptr = const_cast<Element*>(original_tensor.data());
|
| 321 |
+
auto shape = original_tensor.shape();
|
| 322 |
+
auto layout = original_tensor.layout();
|
| 323 |
+
auto tensor = make_tensor(ptr, layout);
|
| 324 |
+
|
| 325 |
+
if constexpr (NumBuffersA == 0) {
|
| 326 |
+
auto tiler = get_device_tiler_a(tensor);
|
| 327 |
+
auto idx = get_device_tile_idx_a(device_idx, iteration);
|
| 328 |
+
return inner_partition(tensor, tiler, idx);
|
| 329 |
+
} else {
|
| 330 |
+
Element* ptr_buffer = reinterpret_cast<Element*>(tensor_buffer_ptr);
|
| 331 |
+
if (iteration == 0) {
|
| 332 |
+
return tensor;
|
| 333 |
+
}
|
| 334 |
+
ptr_buffer += size(shape) * (iteration - 1);
|
| 335 |
+
|
| 336 |
+
return make_tensor(ptr_buffer, layout);
|
| 337 |
+
}
|
| 338 |
+
}
|
| 339 |
+
|
| 340 |
+
template <typename Tensor>
|
| 341 |
+
static auto
|
| 342 |
+
get_tensor_B(Tensor original_tensor, void * tensor_buffer_ptr, int device_idx, int iteration) {
|
| 343 |
+
static_assert(rank(original_tensor) == 3);
|
| 344 |
+
|
| 345 |
+
using Element = typename Tensor::value_type;
|
| 346 |
+
// Recreate tensor without constness. This is to ensure return types match.
|
| 347 |
+
Element * ptr = const_cast<Element *>(original_tensor.data());
|
| 348 |
+
auto shape = original_tensor.shape();
|
| 349 |
+
auto layout = original_tensor.layout();
|
| 350 |
+
auto tensor = make_tensor(ptr, layout);
|
| 351 |
+
|
| 352 |
+
if constexpr (NumBuffersB == 0) {
|
| 353 |
+
auto tiler = get_device_tiler_b(tensor);
|
| 354 |
+
auto idx = get_device_tile_idx_b(device_idx, iteration);
|
| 355 |
+
return inner_partition(tensor, tiler, idx);
|
| 356 |
+
} else {
|
| 357 |
+
Element * ptr_buffer = reinterpret_cast<Element *>(tensor_buffer_ptr);
|
| 358 |
+
if (iteration == 0) {
|
| 359 |
+
return tensor;
|
| 360 |
+
}
|
| 361 |
+
ptr_buffer += size(shape) * (iteration - 1);
|
| 362 |
+
|
| 363 |
+
return make_tensor(ptr_buffer, layout);
|
| 364 |
+
}
|
| 365 |
+
}
|
| 366 |
+
|
| 367 |
+
template <typename Tensor>
|
| 368 |
+
static auto
|
| 369 |
+
get_tensor_C(Tensor original_tensor, void * tensor_buffer_ptr, int device_idx, int iteration) {
|
| 370 |
+
static_assert(rank(original_tensor) == 3);
|
| 371 |
+
|
| 372 |
+
using Element = typename Tensor::value_type;
|
| 373 |
+
// Recreate tensor without constness. This is to ensure return types match.
|
| 374 |
+
Element * ptr = const_cast<Element *>(original_tensor.data());
|
| 375 |
+
auto shape = original_tensor.shape();
|
| 376 |
+
auto layout = original_tensor.layout();
|
| 377 |
+
auto tensor = make_tensor(ptr, layout);
|
| 378 |
+
|
| 379 |
+
if constexpr (not BufferedOutput) {
|
| 380 |
+
auto tiler = get_device_tiler_c(tensor);
|
| 381 |
+
auto idx = get_device_tile_idx_c(device_idx, iteration);
|
| 382 |
+
return inner_partition(tensor, tiler, idx);
|
| 383 |
+
} else {
|
| 384 |
+
// implement Remote D
|
| 385 |
+
static_assert(RemoteC, "");
|
| 386 |
+
|
| 387 |
+
Element * ptr_buffer = reinterpret_cast<Element *>(tensor_buffer_ptr);
|
| 388 |
+
if (iteration == 0) {
|
| 389 |
+
return tensor;
|
| 390 |
+
}
|
| 391 |
+
ptr_buffer += size(shape) * (iteration - 1);
|
| 392 |
+
|
| 393 |
+
return make_tensor(ptr_buffer, layout);
|
| 394 |
+
}
|
| 395 |
+
}
|
| 396 |
+
|
| 397 |
+
template <typename Tensor>
|
| 398 |
+
static auto
|
| 399 |
+
get_tensor_D(Tensor original_tensor, void * tensor_buffer_ptr, int device_idx, int iteration) {
|
| 400 |
+
static_assert(rank(original_tensor) == 3);
|
| 401 |
+
|
| 402 |
+
using Element = typename Tensor::value_type;
|
| 403 |
+
// Recreate tensor without constness. This is to ensure return types match.
|
| 404 |
+
Element * ptr = const_cast<Element *>(original_tensor.data());
|
| 405 |
+
auto shape = original_tensor.shape();
|
| 406 |
+
auto layout = original_tensor.layout();
|
| 407 |
+
auto tensor = make_tensor(ptr, layout);
|
| 408 |
+
|
| 409 |
+
if constexpr (not BufferedOutput) {
|
| 410 |
+
auto tiler = get_device_tiler_d(tensor);
|
| 411 |
+
auto idx = get_device_tile_idx_d(device_idx, iteration);
|
| 412 |
+
return inner_partition(tensor, tiler, idx);
|
| 413 |
+
} else {
|
| 414 |
+
// implement Remote D
|
| 415 |
+
static_assert(RemoteC, "");
|
| 416 |
+
|
| 417 |
+
Element * ptr_buffer = reinterpret_cast<Element *>(tensor_buffer_ptr);
|
| 418 |
+
// last iteration is the local tensor, the rest are buffers
|
| 419 |
+
if (iteration == TP{} - 1) {
|
| 420 |
+
return tensor;
|
| 421 |
+
}
|
| 422 |
+
ptr_buffer += size(shape) * iteration; // note: iteration, not iteration - 1
|
| 423 |
+
|
| 424 |
+
return make_tensor(ptr_buffer, layout);
|
| 425 |
+
}
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
template <typename ProblemShape>
|
| 429 |
+
CUTLASS_HOST_DEVICE
|
| 430 |
+
static auto
|
| 431 |
+
get_local_a_shape(ProblemShape problem_shape) {
|
| 432 |
+
auto problem_shape_MNKL = append<4>(problem_shape, 1);
|
| 433 |
+
if constexpr (NumBuffersA == 0) {
|
| 434 |
+
return shape_div(
|
| 435 |
+
select<0,2,3>(problem_shape_MNKL),
|
| 436 |
+
select<0,2,3>(ProcessorTiler{}));
|
| 437 |
+
} else {
|
| 438 |
+
return shape_div(
|
| 439 |
+
shape_div(
|
| 440 |
+
select<0,2,3>(problem_shape_MNKL),
|
| 441 |
+
select<0,2,3>(ProcessorTiler{})),
|
| 442 |
+
select<0,2,3>(IterationTiler{}));
|
| 443 |
+
}
|
| 444 |
+
}
|
| 445 |
+
|
| 446 |
+
template <typename ProblemShape>
|
| 447 |
+
CUTLASS_HOST_DEVICE
|
| 448 |
+
static auto
|
| 449 |
+
get_local_b_shape(ProblemShape problem_shape) {
|
| 450 |
+
auto problem_shape_MNKL = append<4>(problem_shape, 1);
|
| 451 |
+
if constexpr (NumBuffersB == 0) {
|
| 452 |
+
return shape_div(
|
| 453 |
+
select<1,2,3>(problem_shape_MNKL),
|
| 454 |
+
select<1,2,3>(ProcessorTiler{}));
|
| 455 |
+
} else {
|
| 456 |
+
return shape_div(
|
| 457 |
+
shape_div(
|
| 458 |
+
select<1,2,3>(problem_shape_MNKL),
|
| 459 |
+
select<1,2,3>(ProcessorTiler{})),
|
| 460 |
+
select<1,2,3>(IterationTiler{}));
|
| 461 |
+
}
|
| 462 |
+
}
|
| 463 |
+
|
| 464 |
+
template <typename ProblemShape>
|
| 465 |
+
CUTLASS_HOST_DEVICE
|
| 466 |
+
static auto
|
| 467 |
+
get_local_c_shape(ProblemShape problem_shape) {
|
| 468 |
+
auto problem_shape_MNKL = append<4>(problem_shape, 1);
|
| 469 |
+
if constexpr (not BufferedOutput) {
|
| 470 |
+
return shape_div(
|
| 471 |
+
select<0,1,3>(problem_shape_MNKL),
|
| 472 |
+
select<0,1,3>(ProcessorTiler{}));
|
| 473 |
+
} else {
|
| 474 |
+
return shape_div(
|
| 475 |
+
shape_div(
|
| 476 |
+
select<0,1,3>(problem_shape_MNKL),
|
| 477 |
+
select<0,1,3>(ProcessorTiler{})),
|
| 478 |
+
select<0,1,3>(IterationTiler{}));
|
| 479 |
+
}
|
| 480 |
+
}
|
| 481 |
+
|
| 482 |
+
template <typename ProblemShape>
|
| 483 |
+
CUTLASS_HOST_DEVICE
|
| 484 |
+
static auto
|
| 485 |
+
get_local_d_shape(ProblemShape problem_shape) {
|
| 486 |
+
auto problem_shape_MNKL = append<4>(problem_shape, 1);
|
| 487 |
+
if constexpr (not BufferedOutput) {
|
| 488 |
+
return shape_div(
|
| 489 |
+
select<0,1,3>(problem_shape_MNKL),
|
| 490 |
+
select<0,1,3>(ProcessorTiler{}));
|
| 491 |
+
} else {
|
| 492 |
+
return shape_div(
|
| 493 |
+
shape_div(
|
| 494 |
+
select<0,1,3>(problem_shape_MNKL),
|
| 495 |
+
select<0,1,3>(ProcessorTiler{})),
|
| 496 |
+
select<0,1,3>(IterationTiler{}));
|
| 497 |
+
}
|
| 498 |
+
}
|
| 499 |
+
|
| 500 |
+
// Host-side APIs: get_device_slice_{A,B,C,D}
|
| 501 |
+
// Slice off a view of the GLOBAL tensor that corresponds to the shard that
|
| 502 |
+
// is going to be owned by a specific device. This helps with the initial
|
| 503 |
+
// distribution of the GLOBAL operands among devices.
|
| 504 |
+
template <typename Tensor>
|
| 505 |
+
static auto
|
| 506 |
+
get_device_slice_A(Tensor tensor, int device_idx) {
|
| 507 |
+
auto tiler = get_processor_tiler_a(tensor);
|
| 508 |
+
return inner_partition(tensor, tiler, device_idx);
|
| 509 |
+
}
|
| 510 |
+
|
| 511 |
+
template <typename Tensor>
|
| 512 |
+
static auto
|
| 513 |
+
get_device_slice_B(Tensor tensor, int device_idx) {
|
| 514 |
+
auto tiler = get_processor_tiler_b(tensor);
|
| 515 |
+
return inner_partition(tensor, tiler, device_idx);
|
| 516 |
+
}
|
| 517 |
+
|
| 518 |
+
template <typename Tensor>
|
| 519 |
+
static auto
|
| 520 |
+
get_device_slice_C(Tensor tensor, int device_idx) {
|
| 521 |
+
auto tiler = get_processor_tiler_c(tensor);
|
| 522 |
+
return inner_partition(tensor, tiler, device_idx);
|
| 523 |
+
}
|
| 524 |
+
|
| 525 |
+
template <typename Tensor>
|
| 526 |
+
static auto
|
| 527 |
+
get_device_slice_D(Tensor tensor, int device_idx) {
|
| 528 |
+
auto tiler = get_processor_tiler_d(tensor);
|
| 529 |
+
return inner_partition(tensor, tiler, device_idx);
|
| 530 |
+
}
|
| 531 |
+
};
|
| 532 |
+
|
| 533 |
+
|
| 534 |
+
|
| 535 |
+
} // namespace cutlass::gemm::distributed
|
| 536 |
+
|
| 537 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 538 |
+
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/fast_math.h
ADDED
|
@@ -0,0 +1,1085 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
|
| 32 |
+
#pragma once
|
| 33 |
+
#include "cutlass/cutlass.h"
|
| 34 |
+
#if defined(__CUDACC_RTC__)
|
| 35 |
+
#include CUDA_STD_HEADER(cstdint)
|
| 36 |
+
#else
|
| 37 |
+
#include <cstdint>
|
| 38 |
+
#include <cmath>
|
| 39 |
+
#include <type_traits>
|
| 40 |
+
#endif
|
| 41 |
+
#if !defined(__QNX__)
|
| 42 |
+
#include CUDA_STD_HEADER(utility)
|
| 43 |
+
#endif
|
| 44 |
+
#include "cutlass/array.h"
|
| 45 |
+
#include "cutlass/uint128.h"
|
| 46 |
+
#include "cutlass/coord.h"
|
| 47 |
+
#include "cutlass/half.h"
|
| 48 |
+
|
| 49 |
+
/**
|
| 50 |
+
* \file
|
| 51 |
+
* \brief Math utilities
|
| 52 |
+
*/
|
| 53 |
+
|
| 54 |
+
namespace cutlass {
|
| 55 |
+
|
| 56 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 57 |
+
#if !defined(__QNX__)
|
| 58 |
+
using ::cuda::std::swap;
|
| 59 |
+
#else
|
| 60 |
+
template <typename T>
|
| 61 |
+
CUTLASS_HOST_DEVICE void swap(T &lhs, T &rhs) {
|
| 62 |
+
T tmp = lhs;
|
| 63 |
+
lhs = rhs;
|
| 64 |
+
rhs = tmp;
|
| 65 |
+
}
|
| 66 |
+
#endif
|
| 67 |
+
|
| 68 |
+
/******************************************************************************
|
| 69 |
+
* Static math utilities
|
| 70 |
+
******************************************************************************/
|
| 71 |
+
|
| 72 |
+
/// Mixed precision dot product
|
| 73 |
+
template <typename Index, typename LongIndex, int N>
|
| 74 |
+
CUTLASS_HOST_DEVICE LongIndex dot(
|
| 75 |
+
Coord<N, Index> const &coord,
|
| 76 |
+
Coord<N, LongIndex> const &stride,
|
| 77 |
+
LongIndex acc = LongIndex()) {
|
| 78 |
+
|
| 79 |
+
CUTLASS_PRAGMA_UNROLL
|
| 80 |
+
for (int n = 0; n < N; ++n) {
|
| 81 |
+
acc += LongIndex(coord[n]) * stride[n];
|
| 82 |
+
}
|
| 83 |
+
return acc;
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
/**
|
| 87 |
+
* Statically determine if N is a power-of-two
|
| 88 |
+
*/
|
| 89 |
+
template <int N>
|
| 90 |
+
struct is_pow2 {
|
| 91 |
+
static bool const value = ((N & (N - 1)) == 0);
|
| 92 |
+
};
|
| 93 |
+
|
| 94 |
+
/**
|
| 95 |
+
* Statically determine log2(N), rounded down
|
| 96 |
+
*/
|
| 97 |
+
template <int N, int CurrentVal = N, int Count = 0>
|
| 98 |
+
struct log2_down {
|
| 99 |
+
/// Static logarithm value
|
| 100 |
+
enum { value = log2_down<N, (CurrentVal >> 1), Count + 1>::value };
|
| 101 |
+
};
|
| 102 |
+
|
| 103 |
+
// Base case
|
| 104 |
+
template <int N, int Count>
|
| 105 |
+
struct log2_down<N, 1, Count> {
|
| 106 |
+
enum { value = Count };
|
| 107 |
+
};
|
| 108 |
+
|
| 109 |
+
/**
|
| 110 |
+
* Statically determine log2(N), rounded up
|
| 111 |
+
*/
|
| 112 |
+
template <int N, int CurrentVal = N, int Count = 0>
|
| 113 |
+
struct log2_up {
|
| 114 |
+
/// Static logarithm value
|
| 115 |
+
enum { value = log2_up<N, (CurrentVal >> 1), Count + 1>::value };
|
| 116 |
+
};
|
| 117 |
+
|
| 118 |
+
// Base case
|
| 119 |
+
template <int N, int Count>
|
| 120 |
+
struct log2_up<N, 1, Count> {
|
| 121 |
+
enum { value = ((1 << Count) < N) ? Count + 1 : Count };
|
| 122 |
+
};
|
| 123 |
+
|
| 124 |
+
/**
|
| 125 |
+
* Statically estimate sqrt(N) to the nearest power-of-two
|
| 126 |
+
*/
|
| 127 |
+
template <int N>
|
| 128 |
+
struct sqrt_est {
|
| 129 |
+
enum { value = 1 << (log2_up<N>::value / 2) };
|
| 130 |
+
};
|
| 131 |
+
|
| 132 |
+
/**
|
| 133 |
+
* For performing a constant-division with a compile-time assertion that the
|
| 134 |
+
* Divisor evenly-divides the Dividend.
|
| 135 |
+
*/
|
| 136 |
+
template <int Dividend, int Divisor>
|
| 137 |
+
struct divide_assert {
|
| 138 |
+
enum { value = Dividend / Divisor };
|
| 139 |
+
|
| 140 |
+
static_assert((Dividend % Divisor == 0), "Not an even multiple");
|
| 141 |
+
};
|
| 142 |
+
|
| 143 |
+
/******************************************************************************
|
| 144 |
+
* Rounding
|
| 145 |
+
******************************************************************************/
|
| 146 |
+
|
| 147 |
+
/**
|
| 148 |
+
* Round dividend up to the nearest multiple of divisor
|
| 149 |
+
*/
|
| 150 |
+
template <typename dividend_t, typename divisor_t>
|
| 151 |
+
CUTLASS_HOST_DEVICE
|
| 152 |
+
CUTLASS_CONSTEXPR_IF_CXX17
|
| 153 |
+
dividend_t round_nearest(dividend_t dividend, divisor_t divisor) {
|
| 154 |
+
return ((dividend + divisor - 1) / divisor) * divisor;
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
template <typename value_t>
|
| 158 |
+
CUTLASS_HOST_DEVICE
|
| 159 |
+
CUTLASS_CONSTEXPR_IF_CXX17
|
| 160 |
+
value_t abs_for_integer(value_t a) {
|
| 161 |
+
return ((a > value_t{0}) ? a : -a);
|
| 162 |
+
}
|
| 163 |
+
/**
|
| 164 |
+
* Greatest common divisor
|
| 165 |
+
*/
|
| 166 |
+
template <typename value_t>
|
| 167 |
+
CUTLASS_HOST_DEVICE
|
| 168 |
+
CUTLASS_CONSTEXPR_IF_CXX17
|
| 169 |
+
value_t gcd(value_t a, value_t b) {
|
| 170 |
+
for (;;) {
|
| 171 |
+
if (a == value_t{0}) return cutlass::abs_for_integer(b);
|
| 172 |
+
b %= a;
|
| 173 |
+
if (b == value_t{0}) return cutlass::abs_for_integer(a);
|
| 174 |
+
a %= b;
|
| 175 |
+
}
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
/**
|
| 179 |
+
* Least common multiple
|
| 180 |
+
*/
|
| 181 |
+
template <typename value_t>
|
| 182 |
+
CUTLASS_HOST_DEVICE
|
| 183 |
+
CUTLASS_CONSTEXPR_IF_CXX17
|
| 184 |
+
value_t lcm(value_t a, value_t b) {
|
| 185 |
+
value_t temp = cutlass::gcd(a, b);
|
| 186 |
+
return (temp != value_t{0}) ? value_t(cutlass::abs_for_integer(a) / temp * cutlass::abs_for_integer(b)) : value_t{};
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
/**
|
| 190 |
+
* Greatest common divisor
|
| 191 |
+
*/
|
| 192 |
+
template <typename value_t>
|
| 193 |
+
CUTLASS_HOST_DEVICE
|
| 194 |
+
CUTLASS_CONSTEXPR_IF_CXX17
|
| 195 |
+
value_t gcd_cxx11(value_t a, value_t b) {
|
| 196 |
+
return (a == value_t{0} || b == value_t{0}) ? cutlass::abs_for_integer(a | b) : cutlass::gcd_cxx11(b, a % b);
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
/**
|
| 200 |
+
* Least common multiple
|
| 201 |
+
*/
|
| 202 |
+
template <typename value_t>
|
| 203 |
+
CUTLASS_HOST_DEVICE
|
| 204 |
+
CUTLASS_CONSTEXPR_IF_CXX17
|
| 205 |
+
value_t lcm_cxx11(value_t a, value_t b) {
|
| 206 |
+
return cutlass::gcd_cxx11(a, b) ? (cutlass::abs_for_integer(a) / cutlass::gcd_cxx11(a, b) *
|
| 207 |
+
cutlass::abs_for_integer(b))
|
| 208 |
+
: value_t{};
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
/// Returns the smallest value in the half-open range [a, a+b) that is a multiple of b
|
| 212 |
+
CUTLASS_HOST_DEVICE
|
| 213 |
+
CUTLASS_CONSTEXPR_IF_CXX17
|
| 214 |
+
int round_up(int a, int b) {
|
| 215 |
+
return ((a + b - 1) / b) * b;
|
| 216 |
+
}
|
| 217 |
+
|
| 218 |
+
/// Returns the ceiling of (a / b)
|
| 219 |
+
CUTLASS_HOST_DEVICE
|
| 220 |
+
CUTLASS_CONSTEXPR_IF_CXX17
|
| 221 |
+
int ceil_div(int a, int b) {
|
| 222 |
+
return (a + b - 1) / b;
|
| 223 |
+
}
|
| 224 |
+
|
| 225 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 226 |
+
|
| 227 |
+
/**
|
| 228 |
+
* log2 computation, what's the
|
| 229 |
+
* difference between the below codes and
|
| 230 |
+
* log2_up/down codes?
|
| 231 |
+
*/
|
| 232 |
+
template <typename value_t>
|
| 233 |
+
CUTLASS_HOST_DEVICE
|
| 234 |
+
CUTLASS_CONSTEXPR_IF_CXX17
|
| 235 |
+
value_t clz(value_t x) {
|
| 236 |
+
for (int i = 31; i >= 0; --i) {
|
| 237 |
+
if ((1 << i) & x)
|
| 238 |
+
return value_t(31 - i);
|
| 239 |
+
}
|
| 240 |
+
return value_t(32);
|
| 241 |
+
}
|
| 242 |
+
|
| 243 |
+
template <typename value_t>
|
| 244 |
+
CUTLASS_HOST_DEVICE
|
| 245 |
+
CUTLASS_CONSTEXPR_IF_CXX17
|
| 246 |
+
value_t find_log2(value_t x) {
|
| 247 |
+
int a = int(31 - clz(x));
|
| 248 |
+
a += (x & (x - 1)) != 0; // Round up, add 1 if not a power of 2.
|
| 249 |
+
return a;
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
|
| 253 |
+
/**
|
| 254 |
+
* Find divisor, using find_log2
|
| 255 |
+
*/
|
| 256 |
+
CUTLASS_HOST_DEVICE
|
| 257 |
+
CUTLASS_CONSTEXPR_IF_CXX17
|
| 258 |
+
void find_divisor(unsigned int& mul, unsigned int& shr, unsigned int denom) {
|
| 259 |
+
if (denom == 1) {
|
| 260 |
+
mul = 0;
|
| 261 |
+
shr = 0;
|
| 262 |
+
} else {
|
| 263 |
+
unsigned int p = 31 + find_log2(denom);
|
| 264 |
+
unsigned m = unsigned(((1ull << p) + unsigned(denom) - 1) / unsigned(denom));
|
| 265 |
+
|
| 266 |
+
mul = m;
|
| 267 |
+
shr = p - 32;
|
| 268 |
+
}
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
/**
|
| 272 |
+
* Find quotient and remainder using device-side intrinsics
|
| 273 |
+
*/
|
| 274 |
+
CUTLASS_HOST_DEVICE
|
| 275 |
+
CUTLASS_CONSTEXPR_IF_CXX17
|
| 276 |
+
void fast_divmod(int& quo, int& rem, int src, int div, unsigned int mul, unsigned int shr) {
|
| 277 |
+
|
| 278 |
+
#if defined(__CUDA_ARCH__)
|
| 279 |
+
// Use IMUL.HI if div != 1, else simply copy the source.
|
| 280 |
+
quo = (div != 1) ? __umulhi(src, mul) >> shr : src;
|
| 281 |
+
#else
|
| 282 |
+
quo = int((div != 1) ? int(((int64_t)src * mul) >> 32) >> shr : src);
|
| 283 |
+
#endif
|
| 284 |
+
|
| 285 |
+
// The remainder.
|
| 286 |
+
rem = src - (quo * div);
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
// For long int input
|
| 290 |
+
CUTLASS_HOST_DEVICE
|
| 291 |
+
CUTLASS_CONSTEXPR_IF_CXX17
|
| 292 |
+
void fast_divmod(int& quo, int64_t& rem, int64_t src, int div, unsigned int mul, unsigned int shr) {
|
| 293 |
+
|
| 294 |
+
#if defined(__CUDA_ARCH__)
|
| 295 |
+
// Use IMUL.HI if div != 1, else simply copy the source.
|
| 296 |
+
quo = (div != 1) ? __umulhi(src, mul) >> shr : src;
|
| 297 |
+
#else
|
| 298 |
+
quo = int((div != 1) ? ((src * mul) >> 32) >> shr : src);
|
| 299 |
+
#endif
|
| 300 |
+
// The remainder.
|
| 301 |
+
rem = src - (quo * div);
|
| 302 |
+
}
|
| 303 |
+
|
| 304 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 305 |
+
|
| 306 |
+
/// Object to encapsulate the fast division+modulus operation.
|
| 307 |
+
///
|
| 308 |
+
/// This object precomputes two values used to accelerate the computation and is best used
|
| 309 |
+
/// when the divisor is a grid-invariant. In this case, it may be computed in host code and
|
| 310 |
+
/// marshalled along other kernel arguments using the 'Params' pattern.
|
| 311 |
+
///
|
| 312 |
+
/// Example:
|
| 313 |
+
///
|
| 314 |
+
///
|
| 315 |
+
/// int quotient, remainder, dividend, divisor;
|
| 316 |
+
///
|
| 317 |
+
/// FastDivmod divmod(divisor);
|
| 318 |
+
///
|
| 319 |
+
/// divmod(quotient, remainder, dividend);
|
| 320 |
+
///
|
| 321 |
+
/// // quotient = (dividend / divisor)
|
| 322 |
+
/// // remainder = (dividend % divisor)
|
| 323 |
+
///
|
| 324 |
+
struct FastDivmod {
|
| 325 |
+
using value_div_type = int;
|
| 326 |
+
using value_mod_type = int64_t;
|
| 327 |
+
int32_t divisor = 1;
|
| 328 |
+
uint32_t multiplier = 0u;
|
| 329 |
+
uint32_t shift_right = 0u;
|
| 330 |
+
|
| 331 |
+
// Find quotient and remainder using device-side intrinsics
|
| 332 |
+
CUTLASS_HOST_DEVICE
|
| 333 |
+
void fast_divmod(int& quotient, int& remainder, int dividend) const {
|
| 334 |
+
|
| 335 |
+
#if defined(__CUDA_ARCH__)
|
| 336 |
+
// Use IMUL.HI if divisor != 1, else simply copy the source.
|
| 337 |
+
quotient = (divisor != 1) ? __umulhi(dividend, multiplier) >> shift_right : dividend;
|
| 338 |
+
#else
|
| 339 |
+
quotient = int((divisor != 1) ? int(((int64_t)dividend * multiplier) >> 32) >> shift_right : dividend);
|
| 340 |
+
#endif
|
| 341 |
+
|
| 342 |
+
// The remainder.
|
| 343 |
+
remainder = dividend - (quotient * divisor);
|
| 344 |
+
}
|
| 345 |
+
|
| 346 |
+
/// For long int input
|
| 347 |
+
CUTLASS_HOST_DEVICE
|
| 348 |
+
void fast_divmod(int& quotient, int64_t& remainder, int64_t dividend) const {
|
| 349 |
+
|
| 350 |
+
#if defined(__CUDA_ARCH__)
|
| 351 |
+
// Use IMUL.HI if divisor != 1, else simply copy the source.
|
| 352 |
+
quotient = (divisor != 1) ? __umulhi(dividend, multiplier) >> shift_right : dividend;
|
| 353 |
+
#else
|
| 354 |
+
quotient = int((divisor != 1) ? ((dividend * multiplier) >> 32) >> shift_right : dividend);
|
| 355 |
+
#endif
|
| 356 |
+
// The remainder.
|
| 357 |
+
remainder = dividend - (quotient * divisor);
|
| 358 |
+
}
|
| 359 |
+
|
| 360 |
+
|
| 361 |
+
/// Construct the FastDivmod object, in host code ideally.
|
| 362 |
+
///
|
| 363 |
+
/// This precomputes some values based on the divisor and is computationally expensive.
|
| 364 |
+
|
| 365 |
+
constexpr FastDivmod() = default;
|
| 366 |
+
|
| 367 |
+
CUTLASS_HOST_DEVICE
|
| 368 |
+
FastDivmod(int divisor_): divisor(divisor_) {
|
| 369 |
+
assert(divisor_ >= 0);
|
| 370 |
+
if (divisor != 1) {
|
| 371 |
+
unsigned int p = 31 + find_log2(divisor);
|
| 372 |
+
unsigned m = unsigned(((1ull << p) + unsigned(divisor) - 1) / unsigned(divisor));
|
| 373 |
+
|
| 374 |
+
multiplier = m;
|
| 375 |
+
shift_right = p - 32;
|
| 376 |
+
}
|
| 377 |
+
}
|
| 378 |
+
|
| 379 |
+
/// Computes integer division and modulus using precomputed values. This is computationally
|
| 380 |
+
/// inexpensive.
|
| 381 |
+
CUTLASS_HOST_DEVICE
|
| 382 |
+
void operator()(int "ient, int &remainder, int dividend) const {
|
| 383 |
+
fast_divmod(quotient, remainder, dividend);
|
| 384 |
+
}
|
| 385 |
+
|
| 386 |
+
/// Computes integer division using precomputed values. This is computationally
|
| 387 |
+
/// inexpensive.
|
| 388 |
+
CUTLASS_HOST_DEVICE
|
| 389 |
+
int div(int dividend) const {
|
| 390 |
+
int quotient, remainder;
|
| 391 |
+
fast_divmod(quotient, remainder, dividend);
|
| 392 |
+
return quotient;
|
| 393 |
+
}
|
| 394 |
+
|
| 395 |
+
/// Alias for `div` to match the interface of FastDivmodU64
|
| 396 |
+
CUTLASS_HOST_DEVICE
|
| 397 |
+
int divide(int dividend) const {
|
| 398 |
+
return div(dividend);
|
| 399 |
+
}
|
| 400 |
+
|
| 401 |
+
/// Computes integer division remainder using precomputed values.
|
| 402 |
+
CUTLASS_HOST_DEVICE
|
| 403 |
+
int rem(int dividend) const {
|
| 404 |
+
int quotient, remainder;
|
| 405 |
+
fast_divmod(quotient, remainder, dividend);
|
| 406 |
+
return remainder;
|
| 407 |
+
}
|
| 408 |
+
|
| 409 |
+
/// Alias for `rem`
|
| 410 |
+
CUTLASS_HOST_DEVICE
|
| 411 |
+
int remainder(int dividend) const {
|
| 412 |
+
return rem(dividend);
|
| 413 |
+
}
|
| 414 |
+
|
| 415 |
+
/// Computes integer division and modulus using precomputed values. This is computationally
|
| 416 |
+
/// inexpensive.
|
| 417 |
+
///
|
| 418 |
+
/// Simply returns the quotient
|
| 419 |
+
CUTLASS_HOST_DEVICE
|
| 420 |
+
int divmod(int &remainder, int dividend) const {
|
| 421 |
+
int quotient;
|
| 422 |
+
fast_divmod(quotient, remainder, dividend);
|
| 423 |
+
return quotient;
|
| 424 |
+
}
|
| 425 |
+
|
| 426 |
+
/// Computes integer division and modulus using precomputed values. This is computationally
|
| 427 |
+
/// inexpensive.
|
| 428 |
+
CUTLASS_HOST_DEVICE
|
| 429 |
+
void operator()(int "ient, int64_t &remainder, int64_t dividend) const {
|
| 430 |
+
fast_divmod(quotient, remainder, dividend);
|
| 431 |
+
}
|
| 432 |
+
|
| 433 |
+
/// Computes integer division and modulus using precomputed values. This is computationally
|
| 434 |
+
/// inexpensive.
|
| 435 |
+
CUTLASS_HOST_DEVICE
|
| 436 |
+
int divmod(int64_t &remainder, int64_t dividend) const {
|
| 437 |
+
int quotient;
|
| 438 |
+
fast_divmod(quotient, remainder, dividend);
|
| 439 |
+
return quotient;
|
| 440 |
+
}
|
| 441 |
+
|
| 442 |
+
/// Returns the divisor when cast to integer
|
| 443 |
+
CUTLASS_HOST_DEVICE
|
| 444 |
+
operator int() const { return divisor; }
|
| 445 |
+
|
| 446 |
+
};
|
| 447 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 448 |
+
|
| 449 |
+
/// Object to encapsulate the fast division+modulus operation for 64b integer division.
|
| 450 |
+
///
|
| 451 |
+
/// This object precomputes two values used to accelerate the computation and is best used
|
| 452 |
+
/// when the divisor is a grid-invariant. In this case, it may be computed in host code and
|
| 453 |
+
/// marshalled along other kernel arguments using the 'Params' pattern.
|
| 454 |
+
///
|
| 455 |
+
/// Example:
|
| 456 |
+
///
|
| 457 |
+
///
|
| 458 |
+
/// uint64_t quotient, remainder, dividend, divisor;
|
| 459 |
+
///
|
| 460 |
+
/// FastDivmodU64 divmod(divisor);
|
| 461 |
+
///
|
| 462 |
+
/// divmod(quotient, remainder, dividend);
|
| 463 |
+
///
|
| 464 |
+
/// // quotient = (dividend / divisor)
|
| 465 |
+
/// // remainder = (dividend % divisor)
|
| 466 |
+
///
|
| 467 |
+
struct FastDivmodU64 {
|
| 468 |
+
|
| 469 |
+
uint64_t divisor;
|
| 470 |
+
uint64_t multiplier;
|
| 471 |
+
unsigned int shift_right;
|
| 472 |
+
unsigned int round_up;
|
| 473 |
+
|
| 474 |
+
//
|
| 475 |
+
// Static methods
|
| 476 |
+
//
|
| 477 |
+
|
| 478 |
+
/// Computes b, where 2^b is the greatest power of two that is less than or equal to x
|
| 479 |
+
CUTLASS_HOST_DEVICE
|
| 480 |
+
static uint32_t integer_log2(uint64_t x) {
|
| 481 |
+
uint32_t n = 0;
|
| 482 |
+
while (x >>= 1) {
|
| 483 |
+
++n;
|
| 484 |
+
}
|
| 485 |
+
return n;
|
| 486 |
+
}
|
| 487 |
+
|
| 488 |
+
/// Default ctor
|
| 489 |
+
CUTLASS_HOST_DEVICE
|
| 490 |
+
FastDivmodU64(): divisor(0), multiplier(0), shift_right(0), round_up(0) { }
|
| 491 |
+
|
| 492 |
+
/// Construct the FastDivmod object, in host code ideally.
|
| 493 |
+
///
|
| 494 |
+
/// This precomputes some values based on the divisor and is computationally expensive.
|
| 495 |
+
CUTLASS_HOST_DEVICE
|
| 496 |
+
FastDivmodU64(uint64_t divisor_): divisor(divisor_), multiplier(1), shift_right(0), round_up(0) {
|
| 497 |
+
|
| 498 |
+
if (divisor) {
|
| 499 |
+
shift_right = integer_log2(divisor);
|
| 500 |
+
|
| 501 |
+
if ((divisor & (divisor - 1)) == 0) {
|
| 502 |
+
multiplier = 0;
|
| 503 |
+
}
|
| 504 |
+
else {
|
| 505 |
+
uint64_t power_of_two = (uint64_t(1) << shift_right);
|
| 506 |
+
uint64_t multiplier_lo = uint128_t(0, power_of_two) / divisor;
|
| 507 |
+
multiplier = uint128_t(power_of_two, power_of_two) / divisor;
|
| 508 |
+
round_up = (multiplier_lo == multiplier ? 1 : 0);
|
| 509 |
+
}
|
| 510 |
+
}
|
| 511 |
+
}
|
| 512 |
+
|
| 513 |
+
/// Returns the quotient of floor(dividend / divisor)
|
| 514 |
+
CUTLASS_HOST_DEVICE
|
| 515 |
+
uint64_t divide(uint64_t dividend) const {
|
| 516 |
+
uint64_t quotient = 0;
|
| 517 |
+
|
| 518 |
+
#ifdef __CUDA_ARCH__
|
| 519 |
+
uint64_t x = dividend;
|
| 520 |
+
if (multiplier) {
|
| 521 |
+
x = __umul64hi(dividend + round_up, multiplier);
|
| 522 |
+
}
|
| 523 |
+
quotient = (x >> shift_right);
|
| 524 |
+
#else
|
| 525 |
+
quotient = dividend / divisor;
|
| 526 |
+
#endif
|
| 527 |
+
|
| 528 |
+
return quotient;
|
| 529 |
+
}
|
| 530 |
+
|
| 531 |
+
/// Computes the remainder given a computed quotient and dividend
|
| 532 |
+
CUTLASS_HOST_DEVICE
|
| 533 |
+
uint64_t modulus(uint64_t quotient, uint64_t dividend) const {
|
| 534 |
+
return dividend - quotient * divisor;
|
| 535 |
+
}
|
| 536 |
+
|
| 537 |
+
/// Returns the quotient of floor(dividend / divisor) and computes the remainder
|
| 538 |
+
CUTLASS_HOST_DEVICE
|
| 539 |
+
uint64_t divmod(uint64_t &remainder, uint64_t dividend) const {
|
| 540 |
+
uint64_t quotient = divide(dividend);
|
| 541 |
+
remainder = modulus(quotient, dividend);
|
| 542 |
+
return quotient;
|
| 543 |
+
}
|
| 544 |
+
|
| 545 |
+
/// Computes integer division and modulus using precomputed values. This is computationally
|
| 546 |
+
/// inexpensive.
|
| 547 |
+
CUTLASS_HOST_DEVICE
|
| 548 |
+
void operator()(uint64_t "ient, uint64_t &remainder, uint64_t dividend) const {
|
| 549 |
+
quotient = divmod(remainder, dividend);
|
| 550 |
+
}
|
| 551 |
+
};
|
| 552 |
+
|
| 553 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 554 |
+
|
| 555 |
+
/// Object to encapsulate the fast division+modulus operation for 64b integer division
|
| 556 |
+
/// in which the divisor is a power of two.
|
| 557 |
+
struct FastDivmodU64Pow2 {
|
| 558 |
+
|
| 559 |
+
uint64_t divisor;
|
| 560 |
+
unsigned int shift_right;
|
| 561 |
+
|
| 562 |
+
/// Default ctor
|
| 563 |
+
CUTLASS_HOST_DEVICE
|
| 564 |
+
FastDivmodU64Pow2(): divisor(0), shift_right(0) { }
|
| 565 |
+
|
| 566 |
+
/// Construct the FastDivmod object, in host code ideally.
|
| 567 |
+
///
|
| 568 |
+
/// This precomputes some values based on the divisor and is computationally expensive.
|
| 569 |
+
CUTLASS_HOST_DEVICE
|
| 570 |
+
FastDivmodU64Pow2(uint64_t divisor_): divisor(divisor_), shift_right(FastDivmodU64::integer_log2(divisor_)) { }
|
| 571 |
+
|
| 572 |
+
/// Returns the quotient of floor(dividend / divisor)
|
| 573 |
+
CUTLASS_HOST_DEVICE
|
| 574 |
+
uint64_t divide(uint64_t dividend) const {
|
| 575 |
+
return dividend >> shift_right;
|
| 576 |
+
}
|
| 577 |
+
|
| 578 |
+
/// Computes the remainder given a computed quotient and dividend
|
| 579 |
+
CUTLASS_HOST_DEVICE
|
| 580 |
+
uint64_t modulus(uint64_t dividend) const {
|
| 581 |
+
// See https://docs.nvidia.com/cuda/cuda-c-best-practices-guide/index.html#division-modulo-operations
|
| 582 |
+
return dividend & (divisor - 1);
|
| 583 |
+
}
|
| 584 |
+
|
| 585 |
+
/// Returns the quotient of floor(dividend / divisor) and computes the remainder
|
| 586 |
+
CUTLASS_HOST_DEVICE
|
| 587 |
+
uint64_t divmod(uint64_t &remainder, uint64_t dividend) const {
|
| 588 |
+
uint64_t quotient = divide(dividend);
|
| 589 |
+
remainder = modulus(dividend);
|
| 590 |
+
return quotient;
|
| 591 |
+
}
|
| 592 |
+
|
| 593 |
+
/// Computes integer division and modulus using precomputed values. This is computationally
|
| 594 |
+
/// inexpensive.
|
| 595 |
+
CUTLASS_HOST_DEVICE
|
| 596 |
+
void operator()(uint64_t "ient, uint64_t &remainder, uint64_t dividend) const {
|
| 597 |
+
quotient = divmod(remainder, dividend);
|
| 598 |
+
}
|
| 599 |
+
};
|
| 600 |
+
|
| 601 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 602 |
+
|
| 603 |
+
/// Computes the coordinate decomposition from a linear index (64-bit linear index => coord<int32_t>)
|
| 604 |
+
///
|
| 605 |
+
/// This decomposition is accelerated by the FastDivmodU64 object. It is assumed that
|
| 606 |
+
/// a coordinate of <Rank> indices can be decomposed by <Rank - 1> div/mod operations.
|
| 607 |
+
/// Note, is assumed that element divmod[0] divides by extent[1].
|
| 608 |
+
///
|
| 609 |
+
/// For example, assume 4-D coordinate (n, p, q, c) is mapped to a linear index `npqc`. This
|
| 610 |
+
/// can be decomposed via three divide and modulus operations:
|
| 611 |
+
///
|
| 612 |
+
/// c = npqc % C; | divmod[2] = FastDivmodU64(C)
|
| 613 |
+
/// npq = npqc / C; | coord[3] = c
|
| 614 |
+
///
|
| 615 |
+
/// q = npq % Q; | divmod[1] = FastDivmodU64(Q)
|
| 616 |
+
/// np = npq / Q; | coord[2] = q
|
| 617 |
+
///
|
| 618 |
+
/// p = np % P; | divmod[0] = FastDivmodU64(P)
|
| 619 |
+
/// n = np / P; | coord[1] = p
|
| 620 |
+
///
|
| 621 |
+
/// | coord[0] = n
|
| 622 |
+
///
|
| 623 |
+
template <int Rank>
|
| 624 |
+
CUTLASS_HOST_DEVICE Coord<Rank> CoordinateDecomposition(
|
| 625 |
+
uint64_t linear_idx, ///< Linear index to decompose
|
| 626 |
+
FastDivmodU64 const *divmod) { ///< Pointer to array of Rank-1 FastDivmodU64 objects
|
| 627 |
+
|
| 628 |
+
static_assert(Rank > 0, "CoordinateDecomposition requires Rank=1 or greater.");
|
| 629 |
+
|
| 630 |
+
Coord<Rank> coord;
|
| 631 |
+
|
| 632 |
+
CUTLASS_PRAGMA_UNROLL
|
| 633 |
+
for (int i = Rank; i > 1; --i) {
|
| 634 |
+
uint64_t remainder;
|
| 635 |
+
linear_idx = divmod[i - 2].divmod(remainder, linear_idx);
|
| 636 |
+
coord[i - 1] = int(remainder);
|
| 637 |
+
}
|
| 638 |
+
|
| 639 |
+
coord[0] = int(linear_idx);
|
| 640 |
+
|
| 641 |
+
return coord;
|
| 642 |
+
}
|
| 643 |
+
|
| 644 |
+
/// Computes the coordinate decomposition from a linear index (32-bit linear index => coord<int32_t>)
|
| 645 |
+
template <int Rank>
|
| 646 |
+
CUTLASS_HOST_DEVICE Coord<Rank> CoordinateDecomposition(
|
| 647 |
+
int linear_idx, ///< Linear index to decompose
|
| 648 |
+
FastDivmod const *divmod) { ///< Pointer to array of Rank-1 FastDivmodU64 objects
|
| 649 |
+
|
| 650 |
+
static_assert(Rank > 0, "CoordinateDecomposition requires Rank=1 or greater.");
|
| 651 |
+
|
| 652 |
+
Coord<Rank> coord;
|
| 653 |
+
|
| 654 |
+
CUTLASS_PRAGMA_UNROLL
|
| 655 |
+
for (int i = Rank; i > 1; --i) {
|
| 656 |
+
int remainder;
|
| 657 |
+
linear_idx = divmod[i - 2].divmod(remainder, linear_idx);
|
| 658 |
+
coord[i - 1] = int(remainder);
|
| 659 |
+
}
|
| 660 |
+
|
| 661 |
+
coord[0] = int(linear_idx);
|
| 662 |
+
|
| 663 |
+
return coord;
|
| 664 |
+
}
|
| 665 |
+
|
| 666 |
+
template <int Rank>
|
| 667 |
+
CUTLASS_HOST_DEVICE Coord<Rank> CoordinateDecompositionLittleEndian(
|
| 668 |
+
uint64_t linear_idx, ///< Linear index to decompose
|
| 669 |
+
FastDivmodU64 const *divmod) { ///< Pointer to array of Rank-1 FastDivmodU64 objects
|
| 670 |
+
|
| 671 |
+
static_assert(Rank > 0, "CoordinateDecomposition requires Rank=1 or greater.");
|
| 672 |
+
|
| 673 |
+
Coord<Rank> coord;
|
| 674 |
+
|
| 675 |
+
CUTLASS_PRAGMA_UNROLL
|
| 676 |
+
for (int i = 0; i < Rank - 1; ++i) {
|
| 677 |
+
uint64_t remainder;
|
| 678 |
+
linear_idx = divmod[i].divmod(remainder, linear_idx);
|
| 679 |
+
coord[i] = int(remainder);
|
| 680 |
+
}
|
| 681 |
+
|
| 682 |
+
coord[Rank - 1] = int(linear_idx);
|
| 683 |
+
|
| 684 |
+
return coord;
|
| 685 |
+
}
|
| 686 |
+
|
| 687 |
+
/// Computes the coordinate decomposition from a linear index (32-bit linear index => coord<int32_t>)
|
| 688 |
+
template <int Rank>
|
| 689 |
+
CUTLASS_HOST_DEVICE Coord<Rank> CoordinateDecompositionLittleEndian(
|
| 690 |
+
int linear_idx, ///< Linear index to decompose
|
| 691 |
+
FastDivmod const *divmod) { ///< Pointer to array of Rank-1 FastDivmodU64 objects
|
| 692 |
+
|
| 693 |
+
static_assert(Rank > 0, "CoordinateDecomposition requires Rank=1 or greater.");
|
| 694 |
+
|
| 695 |
+
Coord<Rank> coord;
|
| 696 |
+
|
| 697 |
+
CUTLASS_PRAGMA_UNROLL
|
| 698 |
+
for (int i = 0; i < Rank - 1; ++i) {
|
| 699 |
+
int remainder;
|
| 700 |
+
linear_idx = divmod[i].divmod(remainder, linear_idx);
|
| 701 |
+
coord[i] = int(remainder);
|
| 702 |
+
}
|
| 703 |
+
|
| 704 |
+
coord[Rank - 1] = int(linear_idx);
|
| 705 |
+
|
| 706 |
+
return coord;
|
| 707 |
+
}
|
| 708 |
+
|
| 709 |
+
/// Safely computes the offset of a linear index in bytes for all types
|
| 710 |
+
template <typename Element>
|
| 711 |
+
CUTLASS_HOST_DEVICE int64_t OffsetBytes(int64_t index) {
|
| 712 |
+
|
| 713 |
+
static_assert(
|
| 714 |
+
(sizeof_bits<Element>::value >= 8 && !(sizeof_bits<Element>::value % 8)) ||
|
| 715 |
+
(sizeof_bits<Element>::value < 8 && !(8 % sizeof_bits<Element>::value)),
|
| 716 |
+
"Size of numeric type in bits must either be divisible by 8 bits, or 8 bits must be divisible by the size.");
|
| 717 |
+
|
| 718 |
+
if (sizeof_bits<Element>::value >= 8) {
|
| 719 |
+
return index * (sizeof_bits<Element>::value / 8);
|
| 720 |
+
}
|
| 721 |
+
else {
|
| 722 |
+
int const kElementsPerByte = ((8 / sizeof_bits<Element>::value) + ((sizeof_bits<Element>::value >= 8) ? 1 : 0));
|
| 723 |
+
return index / kElementsPerByte;
|
| 724 |
+
}
|
| 725 |
+
}
|
| 726 |
+
|
| 727 |
+
CUTLASS_HOST_DEVICE int64_t OffsetBytes(int64_t index, int64_t element_sizeof_bits) {
|
| 728 |
+
if (element_sizeof_bits >= 8) {
|
| 729 |
+
return index * (element_sizeof_bits / 8);
|
| 730 |
+
}
|
| 731 |
+
else {
|
| 732 |
+
int64_t const kElementsPerByte = ((8 / element_sizeof_bits) + ((element_sizeof_bits >= 8) ? 1 : 0));
|
| 733 |
+
return index / kElementsPerByte;
|
| 734 |
+
}
|
| 735 |
+
}
|
| 736 |
+
|
| 737 |
+
|
| 738 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 739 |
+
// Min/Max
|
| 740 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 741 |
+
|
| 742 |
+
template <int A, int B>
|
| 743 |
+
struct Min {
|
| 744 |
+
static int const kValue = (A < B) ? A : B;
|
| 745 |
+
};
|
| 746 |
+
|
| 747 |
+
template <int A, int B>
|
| 748 |
+
struct Max {
|
| 749 |
+
static int const kValue = (A > B) ? A : B;
|
| 750 |
+
};
|
| 751 |
+
|
| 752 |
+
CUTLASS_HOST_DEVICE
|
| 753 |
+
CUTLASS_CONSTEXPR_IF_CXX17 int const_min(int a, int b) {
|
| 754 |
+
return (b < a ? b : a);
|
| 755 |
+
}
|
| 756 |
+
|
| 757 |
+
CUTLASS_HOST_DEVICE
|
| 758 |
+
CUTLASS_CONSTEXPR_IF_CXX17 int const_max(int a, int b) {
|
| 759 |
+
return (b > a ? b : a);
|
| 760 |
+
}
|
| 761 |
+
|
| 762 |
+
template <typename T>
|
| 763 |
+
CUTLASS_HOST_DEVICE
|
| 764 |
+
T fast_min(T a, T b) {
|
| 765 |
+
return (b < a ? b : a);
|
| 766 |
+
}
|
| 767 |
+
|
| 768 |
+
template <>
|
| 769 |
+
CUTLASS_HOST_DEVICE
|
| 770 |
+
float fast_min(float a, float b) {
|
| 771 |
+
return fminf(a, b);
|
| 772 |
+
}
|
| 773 |
+
|
| 774 |
+
template <typename T>
|
| 775 |
+
CUTLASS_HOST_DEVICE
|
| 776 |
+
T fast_max(T a, T b) {
|
| 777 |
+
return (a < b ? b : a);
|
| 778 |
+
}
|
| 779 |
+
|
| 780 |
+
template <>
|
| 781 |
+
CUTLASS_HOST_DEVICE
|
| 782 |
+
float fast_max(float a, float b) {
|
| 783 |
+
return fmaxf(a, b);
|
| 784 |
+
}
|
| 785 |
+
|
| 786 |
+
CUTLASS_HOST_DEVICE
|
| 787 |
+
float fast_cos(float theta) {
|
| 788 |
+
#if defined(__CUDA_ARCH__)
|
| 789 |
+
return ::cosf(theta);
|
| 790 |
+
#else
|
| 791 |
+
return std::cos(theta);
|
| 792 |
+
#endif
|
| 793 |
+
}
|
| 794 |
+
|
| 795 |
+
CUTLASS_HOST_DEVICE
|
| 796 |
+
double fast_cos(double theta) {
|
| 797 |
+
#if defined(__CUDA_ARCH__)
|
| 798 |
+
return ::cos(theta);
|
| 799 |
+
#else
|
| 800 |
+
return std::cos(theta);
|
| 801 |
+
#endif
|
| 802 |
+
}
|
| 803 |
+
|
| 804 |
+
CUTLASS_HOST_DEVICE
|
| 805 |
+
float fast_sin(float theta) {
|
| 806 |
+
#if defined(__CUDA_ARCH__)
|
| 807 |
+
return ::sinf(theta);
|
| 808 |
+
#else
|
| 809 |
+
return std::sin(theta);
|
| 810 |
+
#endif
|
| 811 |
+
}
|
| 812 |
+
|
| 813 |
+
CUTLASS_HOST_DEVICE
|
| 814 |
+
double fast_sin(double theta) {
|
| 815 |
+
#if defined(__CUDA_ARCH__)
|
| 816 |
+
return ::sin(theta);
|
| 817 |
+
#else
|
| 818 |
+
return std::sin(theta);
|
| 819 |
+
#endif
|
| 820 |
+
}
|
| 821 |
+
|
| 822 |
+
CUTLASS_HOST_DEVICE
|
| 823 |
+
float fast_acos(float theta) {
|
| 824 |
+
#if defined(__CUDA_ARCH__)
|
| 825 |
+
return ::acosf(theta);
|
| 826 |
+
#else
|
| 827 |
+
return std::acos(theta);
|
| 828 |
+
#endif
|
| 829 |
+
}
|
| 830 |
+
|
| 831 |
+
CUTLASS_HOST_DEVICE
|
| 832 |
+
double fast_acos(double theta) {
|
| 833 |
+
#if defined(__CUDA_ARCH__)
|
| 834 |
+
return ::acos(theta);
|
| 835 |
+
#else
|
| 836 |
+
return std::acos(theta);
|
| 837 |
+
#endif
|
| 838 |
+
}
|
| 839 |
+
|
| 840 |
+
CUTLASS_HOST_DEVICE
|
| 841 |
+
float fast_asin(float theta) {
|
| 842 |
+
#if defined(__CUDA_ARCH__)
|
| 843 |
+
return ::asinf(theta);
|
| 844 |
+
#else
|
| 845 |
+
return std::asin(theta);
|
| 846 |
+
#endif
|
| 847 |
+
}
|
| 848 |
+
|
| 849 |
+
CUTLASS_HOST_DEVICE
|
| 850 |
+
double fast_asin(double theta) {
|
| 851 |
+
#if defined(__CUDA_ARCH__)
|
| 852 |
+
return ::asin(theta);
|
| 853 |
+
#else
|
| 854 |
+
return std::asin(theta);
|
| 855 |
+
#endif
|
| 856 |
+
}
|
| 857 |
+
|
| 858 |
+
CUTLASS_HOST_DEVICE
|
| 859 |
+
float fast_sqrt(float theta) {
|
| 860 |
+
#if defined(__CUDA_ARCH__)
|
| 861 |
+
return ::sqrtf(theta);
|
| 862 |
+
#else
|
| 863 |
+
return std::sqrt(theta);
|
| 864 |
+
#endif
|
| 865 |
+
}
|
| 866 |
+
|
| 867 |
+
CUTLASS_HOST_DEVICE
|
| 868 |
+
double fast_sqrt(double theta) {
|
| 869 |
+
#if defined(__CUDA_ARCH__)
|
| 870 |
+
return ::sqrt(theta);
|
| 871 |
+
#else
|
| 872 |
+
return std::sqrt(theta);
|
| 873 |
+
#endif
|
| 874 |
+
}
|
| 875 |
+
|
| 876 |
+
CUTLASS_HOST_DEVICE
|
| 877 |
+
float fast_exp(float x) {
|
| 878 |
+
#if defined(__CUDA_ARCH__)
|
| 879 |
+
return ::expf(x);
|
| 880 |
+
#else
|
| 881 |
+
return std::exp(x);
|
| 882 |
+
#endif
|
| 883 |
+
}
|
| 884 |
+
|
| 885 |
+
CUTLASS_HOST_DEVICE
|
| 886 |
+
double fast_exp(double x) {
|
| 887 |
+
#if defined(__CUDA_ARCH__)
|
| 888 |
+
return ::exp(x);
|
| 889 |
+
#else
|
| 890 |
+
return std::exp(x);
|
| 891 |
+
#endif
|
| 892 |
+
}
|
| 893 |
+
|
| 894 |
+
CUTLASS_HOST_DEVICE
|
| 895 |
+
half_t fast_exp(half_t x) {
|
| 896 |
+
#if defined(__CUDA_ARCH__) && (__CUDACC_VER_MAJOR__ >= 10) && (__CUDA_ARCH__ >= 750)
|
| 897 |
+
return (half_t)(::hexp(x.to_half()));
|
| 898 |
+
#else
|
| 899 |
+
return (half_t)(fast_exp(float(x)));
|
| 900 |
+
#endif
|
| 901 |
+
}
|
| 902 |
+
|
| 903 |
+
CUTLASS_HOST_DEVICE
|
| 904 |
+
float fast_log(float x) {
|
| 905 |
+
#if defined(__CUDA_ARCH__)
|
| 906 |
+
return ::logf(x);
|
| 907 |
+
#else
|
| 908 |
+
return std::log(x);
|
| 909 |
+
#endif
|
| 910 |
+
}
|
| 911 |
+
|
| 912 |
+
CUTLASS_HOST_DEVICE
|
| 913 |
+
double fast_log(double x) {
|
| 914 |
+
#if defined(__CUDA_ARCH__)
|
| 915 |
+
return ::log(x);
|
| 916 |
+
#else
|
| 917 |
+
return std::log(x);
|
| 918 |
+
#endif
|
| 919 |
+
}
|
| 920 |
+
|
| 921 |
+
CUTLASS_HOST_DEVICE
|
| 922 |
+
float fast_tanh(float x) {
|
| 923 |
+
#if defined(__CUDA_ARCH__)
|
| 924 |
+
#if (__CUDACC_VER_MAJOR__ >= 11) && (__CUDA_ARCH__ >= 750)
|
| 925 |
+
float y;
|
| 926 |
+
asm volatile ( "tanh.approx.f32 %0, %1; " : "=f"(y) : "f"(x));
|
| 927 |
+
return y;
|
| 928 |
+
#else
|
| 929 |
+
return ::tanhf(x);
|
| 930 |
+
#endif
|
| 931 |
+
#else
|
| 932 |
+
return std::tanh(x);
|
| 933 |
+
#endif
|
| 934 |
+
}
|
| 935 |
+
|
| 936 |
+
CUTLASS_HOST_DEVICE
|
| 937 |
+
double fast_tanh(double x) {
|
| 938 |
+
#if defined(__CUDA_ARCH__)
|
| 939 |
+
return ::tanh(x);
|
| 940 |
+
#else
|
| 941 |
+
return std::tanh(x);
|
| 942 |
+
#endif
|
| 943 |
+
}
|
| 944 |
+
|
| 945 |
+
CUTLASS_HOST_DEVICE
|
| 946 |
+
half_t fast_tanh(half_t x) {
|
| 947 |
+
#if defined(__CUDA_ARCH__) && (__CUDACC_VER_MAJOR__ >= 11) && (__CUDA_ARCH__ >= 750)
|
| 948 |
+
|
| 949 |
+
asm volatile ( "tanh.approx.f16 %0, %1;" : "=h"(x.raw()) : "h"(x.raw()));
|
| 950 |
+
return x;
|
| 951 |
+
|
| 952 |
+
#else
|
| 953 |
+
return half_t(fast_tanh(float(x)));
|
| 954 |
+
#endif
|
| 955 |
+
}
|
| 956 |
+
|
| 957 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 958 |
+
|
| 959 |
+
template <typename T>
|
| 960 |
+
struct fast_exp_op {
|
| 961 |
+
CUTLASS_HOST_DEVICE
|
| 962 |
+
T operator()(T const &rhs) const {
|
| 963 |
+
return fast_exp(rhs);
|
| 964 |
+
}
|
| 965 |
+
};
|
| 966 |
+
|
| 967 |
+
#if defined(__CUDA_ARCH__) && (__CUDACC_VER_MAJOR__ >= 10) && (__CUDA_ARCH__ >= 750)
|
| 968 |
+
template <int N>
|
| 969 |
+
struct fast_exp_op<Array<half_t, N>> {
|
| 970 |
+
CUTLASS_DEVICE
|
| 971 |
+
Array<half_t, N> operator()(Array<half_t, N> const &rhs) const {
|
| 972 |
+
|
| 973 |
+
Array<half_t, N> result;
|
| 974 |
+
|
| 975 |
+
// use x2 specialization
|
| 976 |
+
__half2 const *in = reinterpret_cast<__half2 const *>(&rhs);
|
| 977 |
+
__half2 *out = reinterpret_cast<__half2 *>(&result);
|
| 978 |
+
|
| 979 |
+
CUTLASS_PRAGMA_UNROLL
|
| 980 |
+
for (int i = 0; i < N / 2; ++i) {
|
| 981 |
+
out[i] = ::h2exp(in[i]);
|
| 982 |
+
}
|
| 983 |
+
|
| 984 |
+
// residual
|
| 985 |
+
if (N % 2) {
|
| 986 |
+
half_t last = rhs[N - 1];
|
| 987 |
+
result[N - 1] = half_t(::hexp(last.to_half()));
|
| 988 |
+
}
|
| 989 |
+
|
| 990 |
+
return result;
|
| 991 |
+
}
|
| 992 |
+
};
|
| 993 |
+
#endif // #if defined(__CUDA_ARCH__)
|
| 994 |
+
|
| 995 |
+
template <typename T, int N>
|
| 996 |
+
struct fast_exp_op<Array<T, N>> {
|
| 997 |
+
CUTLASS_HOST_DEVICE
|
| 998 |
+
Array<T, N> operator()(Array<T, N> const &rhs) const {
|
| 999 |
+
|
| 1000 |
+
fast_exp_op<T> fast_op;
|
| 1001 |
+
Array<T, N> y;
|
| 1002 |
+
|
| 1003 |
+
CUTLASS_PRAGMA_UNROLL
|
| 1004 |
+
for (int i = 0; i < N; ++i) {
|
| 1005 |
+
y[i] = fast_op(rhs[i]);
|
| 1006 |
+
}
|
| 1007 |
+
|
| 1008 |
+
return y;
|
| 1009 |
+
}
|
| 1010 |
+
};
|
| 1011 |
+
|
| 1012 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1013 |
+
|
| 1014 |
+
template <typename T>
|
| 1015 |
+
struct fast_tanh_op {
|
| 1016 |
+
CUTLASS_HOST_DEVICE
|
| 1017 |
+
T operator()(T const &rhs) const {
|
| 1018 |
+
return fast_tanh(rhs);
|
| 1019 |
+
}
|
| 1020 |
+
};
|
| 1021 |
+
|
| 1022 |
+
#if defined(__CUDA_ARCH__) && (__CUDACC_VER_MAJOR__ >= 11) && (__CUDA_ARCH__ >= 750)
|
| 1023 |
+
template <int N>
|
| 1024 |
+
struct fast_tanh_op<Array<half_t, N>> {
|
| 1025 |
+
CUTLASS_DEVICE
|
| 1026 |
+
Array<half_t, N> operator()(Array<half_t, N> const &rhs) const {
|
| 1027 |
+
|
| 1028 |
+
Array<half_t, N> result;
|
| 1029 |
+
|
| 1030 |
+
// use x2 specialization
|
| 1031 |
+
uint32_t const *in = reinterpret_cast<uint32_t const *>(&rhs);
|
| 1032 |
+
uint32_t *out = reinterpret_cast<uint32_t *>(&result);
|
| 1033 |
+
|
| 1034 |
+
CUTLASS_PRAGMA_UNROLL
|
| 1035 |
+
for (int i = 0; i < N / 2; ++i) {
|
| 1036 |
+
asm volatile ("tanh.approx.f16x2 %0, %1;" : "=r"(out[i]) : "r"(in[i]));
|
| 1037 |
+
}
|
| 1038 |
+
|
| 1039 |
+
// residual
|
| 1040 |
+
if (N % 2) {
|
| 1041 |
+
uint16_t const *in = reinterpret_cast<uint16_t const *>(&rhs);
|
| 1042 |
+
uint16_t *out = reinterpret_cast<uint16_t *>(&result);
|
| 1043 |
+
asm volatile ("tanh.approx.f16 %0, %1;" : "=h"(out[N - 1]) : "h"(in[N - 1]));
|
| 1044 |
+
}
|
| 1045 |
+
|
| 1046 |
+
return result;
|
| 1047 |
+
}
|
| 1048 |
+
};
|
| 1049 |
+
#endif // #if defined(__CUDA_ARCH__)
|
| 1050 |
+
|
| 1051 |
+
template <typename T, int N>
|
| 1052 |
+
struct fast_tanh_op<Array<T, N>> {
|
| 1053 |
+
CUTLASS_HOST_DEVICE
|
| 1054 |
+
Array<T, N> operator()(Array<T, N> const &rhs) const {
|
| 1055 |
+
|
| 1056 |
+
fast_tanh_op<T> fast_op;
|
| 1057 |
+
Array<T, N> y;
|
| 1058 |
+
|
| 1059 |
+
CUTLASS_PRAGMA_UNROLL
|
| 1060 |
+
for (int i = 0; i < N; ++i) {
|
| 1061 |
+
y[i] = fast_op(rhs[i]);
|
| 1062 |
+
}
|
| 1063 |
+
|
| 1064 |
+
return y;
|
| 1065 |
+
}
|
| 1066 |
+
};
|
| 1067 |
+
|
| 1068 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1069 |
+
|
| 1070 |
+
/// Absolute value function
|
| 1071 |
+
template <typename T>
|
| 1072 |
+
CUTLASS_HOST_DEVICE
|
| 1073 |
+
T absolute_value(T x) {
|
| 1074 |
+
if (x < T()) {
|
| 1075 |
+
return -x;
|
| 1076 |
+
}
|
| 1077 |
+
return x;
|
| 1078 |
+
}
|
| 1079 |
+
|
| 1080 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1081 |
+
|
| 1082 |
+
} // namespace cutlass
|
| 1083 |
+
|
| 1084 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1085 |
+
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/float8.h
ADDED
|
@@ -0,0 +1,1685 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*!
|
| 32 |
+
\file
|
| 33 |
+
\brief Defines a class for using IEEE half-precision floating-point types in host or
|
| 34 |
+
device code.
|
| 35 |
+
*/
|
| 36 |
+
|
| 37 |
+
#pragma once
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
#include "cutlass/arch/config.h"
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
// FP8 types are available starting CUDA 11.8+
|
| 44 |
+
#if (__CUDACC_VER_MAJOR__ >= 12) || ((__CUDACC_VER_MAJOR__ == 11) && (__CUDACC_VER_MINOR__ >= 8))
|
| 45 |
+
#define CUDA_FP8_ENABLED 1
|
| 46 |
+
#endif
|
| 47 |
+
|
| 48 |
+
#if defined(__CUDA_ARCH__)
|
| 49 |
+
# if (__CUDA_ARCH__ >= 900)
|
| 50 |
+
# if (__CUDACC_VER_MAJOR__ >= 12) || ((__CUDACC_VER_MAJOR__ == 11) && (__CUDACC_VER_MINOR__ >= 8))
|
| 51 |
+
# define CUDA_PTX_FP8_CVT_ENABLED 1
|
| 52 |
+
# endif // (__CUDACC_VER_MAJOR__ >= 12) || ((__CUDACC_VER_MAJOR__ == 11) && (__CUDACC_VER_MINOR__ >= 8))
|
| 53 |
+
# elif (__CUDA_ARCH__ == 890)
|
| 54 |
+
# if (__CUDACC_VER_MAJOR__ > 12) || ((__CUDACC_VER_MAJOR__ == 12) && (__CUDACC_VER_MINOR__ >= 1))
|
| 55 |
+
# define CUDA_PTX_FP8_CVT_ENABLED 1
|
| 56 |
+
# endif // (__CUDACC_VER_MAJOR__ > 12) || ((__CUDACC_VER_MAJOR__ == 12) && (__CUDACC_VER_MINOR__ >= 1))
|
| 57 |
+
# endif // (__CUDA_ARCH__ >= 900)
|
| 58 |
+
#endif // defined(__CUDA_ARCH__)
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
#if (defined(CUTLASS_ARCH_MMA_SM100A_ENABLED) || defined(CUTLASS_ARCH_MMA_SM101A_ENABLED) ||\
|
| 62 |
+
defined(CUTLASS_ARCH_MMA_SM103A_ENABLED) || defined(CUTLASS_ARCH_MMA_SM110A_ENABLED) ||\
|
| 63 |
+
defined(CUTLASS_ARCH_MMA_SM120A_ENABLED) || defined(CUTLASS_ARCH_MMA_SM121A_ENABLED))
|
| 64 |
+
# define CUDA_PTX_UE8M0_CVT_ENABLED 1
|
| 65 |
+
#endif
|
| 66 |
+
|
| 67 |
+
#if (defined(CUTLASS_ARCH_MMA_SM100F_ENABLED) || defined(CUTLASS_ARCH_MMA_SM101F_ENABLED) ||\
|
| 68 |
+
defined(CUTLASS_ARCH_MMA_SM103F_ENABLED) || defined(CUTLASS_ARCH_MMA_SM110F_ENABLED) ||\
|
| 69 |
+
defined(CUTLASS_ARCH_MMA_SM120F_ENABLED) || defined(CUTLASS_ARCH_MMA_SM121F_ENABLED))
|
| 70 |
+
# define CUDA_PTX_UE8M0_CVT_ENABLED 1
|
| 71 |
+
#endif
|
| 72 |
+
|
| 73 |
+
#ifdef __GNUC__
|
| 74 |
+
// Ignore checks on reinterpret-casts that are being used for bitcasts.
|
| 75 |
+
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
| 76 |
+
#endif
|
| 77 |
+
|
| 78 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 79 |
+
|
| 80 |
+
#if defined(__CUDACC_RTC__)
|
| 81 |
+
|
| 82 |
+
#include "cutlass/floating_point_nvrtc.h"
|
| 83 |
+
|
| 84 |
+
#else
|
| 85 |
+
//
|
| 86 |
+
// Standard Library headers belong here to avoid conflicts with NVRTC.
|
| 87 |
+
//
|
| 88 |
+
#include <cmath>
|
| 89 |
+
#include <limits>
|
| 90 |
+
#include <cstdint>
|
| 91 |
+
#include <cstring>
|
| 92 |
+
#endif
|
| 93 |
+
|
| 94 |
+
#ifdef CUDA_FP8_ENABLED
|
| 95 |
+
#include <cuda_fp8.h>
|
| 96 |
+
#endif
|
| 97 |
+
#include <cuda_fp16.h>
|
| 98 |
+
|
| 99 |
+
#include "cutlass/cutlass.h"
|
| 100 |
+
|
| 101 |
+
#include "cutlass/exmy_base.h"
|
| 102 |
+
|
| 103 |
+
#include "cute/util/type_traits.hpp"
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 107 |
+
|
| 108 |
+
namespace cutlass {
|
| 109 |
+
|
| 110 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 111 |
+
//
|
| 112 |
+
// FP8 Has 2 encodings possible : E4M3 and E5M2
|
| 113 |
+
//
|
| 114 |
+
// E4M3 : 7 | 6 5 4 3 | 2 1 0
|
| 115 |
+
// E5M2 : 7 | 6 5 4 3 2 | 1 0
|
| 116 |
+
//
|
| 117 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 118 |
+
|
| 119 |
+
enum class FloatEncoding {
|
| 120 |
+
E4M3,
|
| 121 |
+
E5M2
|
| 122 |
+
};
|
| 123 |
+
|
| 124 |
+
template<FloatEncoding T>
|
| 125 |
+
struct alignas(1) float8_base {
|
| 126 |
+
|
| 127 |
+
static constexpr bool IS_E4M3 = (T == FloatEncoding::E4M3);
|
| 128 |
+
static constexpr bool IS_E5M2 = (T == FloatEncoding::E5M2);
|
| 129 |
+
|
| 130 |
+
// Number of Bits representing mantissa and exponents
|
| 131 |
+
static constexpr int FP32_NUM_BITS = 32;
|
| 132 |
+
static constexpr int FP32_NUM_EXPONENT_BITS = 8;
|
| 133 |
+
static constexpr int FP32_NUM_MANTISSA_BITS = 23;
|
| 134 |
+
static constexpr uint32_t FP32_NAN = 0x7fffffff;
|
| 135 |
+
static constexpr uint32_t FP32_INFINITY_MASK = 0x7f800000;
|
| 136 |
+
static constexpr int FP32_MAX_EXPONENT = 127;
|
| 137 |
+
static constexpr int FP32_MIN_EXPONENT = -126;
|
| 138 |
+
static constexpr int FP32_EXPONENT_BIAS = 127;
|
| 139 |
+
|
| 140 |
+
static constexpr int FP16_NUM_BITS = 16;
|
| 141 |
+
static constexpr int FP16_NUM_EXPONENT_BITS = 5;
|
| 142 |
+
static constexpr int FP16_NUM_MANTISSA_BITS = 10;
|
| 143 |
+
static constexpr uint16_t FP16_NAN = 0x7fff;
|
| 144 |
+
static constexpr uint16_t FP16_INFINITY_MASK = 0x7c00;
|
| 145 |
+
static constexpr int FP16_MAX_EXPONENT = 15;
|
| 146 |
+
static constexpr int FP16_MIN_EXPONENT = -14;
|
| 147 |
+
static constexpr int FP16_EXPONENT_BIAS = 15;
|
| 148 |
+
|
| 149 |
+
static constexpr int FP8_NUM_BITS = 8;
|
| 150 |
+
static constexpr int FP8_NUM_EXPONENT_BITS = IS_E4M3 ? 4 : 5;
|
| 151 |
+
static constexpr int FP8_NUM_MANTISSA_BITS = IS_E4M3 ? 3 : 2;
|
| 152 |
+
static constexpr uint8_t FP8_NAN = 0x7f; // Also F8_INF
|
| 153 |
+
static constexpr uint8_t FP8_INFINITY_MASK = IS_E4M3 ? 0x78 : 0x7c;
|
| 154 |
+
static constexpr int FP8_MAX_EXPONENT = IS_E4M3 ? 7 : 15;
|
| 155 |
+
static constexpr int FP8_MIN_EXPONENT = IS_E4M3 ? -6 : -14;
|
| 156 |
+
static constexpr int FP8_EXPONENT_BIAS = IS_E4M3 ? 7 : 15;
|
| 157 |
+
|
| 158 |
+
static constexpr uint8_t FP8_EXPONENT_MASK = (1 << FP8_NUM_EXPONENT_BITS) - 1;
|
| 159 |
+
static constexpr uint8_t FP8_MANTISSA_MASK = (1 << FP8_NUM_MANTISSA_BITS) - 1;
|
| 160 |
+
|
| 161 |
+
static constexpr uint8_t FP8_MAX_FLT = (IS_E4M3 ? 0x7e : 0x7b);
|
| 162 |
+
|
| 163 |
+
// 256 in float
|
| 164 |
+
static constexpr uint32_t FP8_SAT_VAL_FP32 = 0x43800000;
|
| 165 |
+
|
| 166 |
+
//
|
| 167 |
+
// Data members
|
| 168 |
+
//
|
| 169 |
+
|
| 170 |
+
/// Data container
|
| 171 |
+
uint8_t storage;
|
| 172 |
+
|
| 173 |
+
/// Ctors.
|
| 174 |
+
CUTLASS_HOST_DEVICE
|
| 175 |
+
float8_base() : storage(0) { }
|
| 176 |
+
|
| 177 |
+
/// Is finite implementation
|
| 178 |
+
CUTLASS_HOST_DEVICE
|
| 179 |
+
static bool isfinite(float flt) {
|
| 180 |
+
uint32_t s;
|
| 181 |
+
|
| 182 |
+
#if defined(__CUDA_ARCH__)
|
| 183 |
+
s = reinterpret_cast<uint32_t const &>(flt);
|
| 184 |
+
#else
|
| 185 |
+
std::memcpy(&s, &flt, sizeof(s));
|
| 186 |
+
#endif
|
| 187 |
+
|
| 188 |
+
return (s & 0x7f800000) < 0x7f800000;
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
/// Is NaN implementation
|
| 192 |
+
CUTLASS_HOST_DEVICE
|
| 193 |
+
static bool isnan(float flt) {
|
| 194 |
+
uint32_t s;
|
| 195 |
+
|
| 196 |
+
#if defined(__CUDA_ARCH__)
|
| 197 |
+
s = reinterpret_cast<uint32_t const &>(flt);
|
| 198 |
+
#else
|
| 199 |
+
std::memcpy(&s, &flt, sizeof(s));
|
| 200 |
+
#endif
|
| 201 |
+
|
| 202 |
+
return (s & 0x7fffffff) > 0x7f800000;
|
| 203 |
+
}
|
| 204 |
+
|
| 205 |
+
/// Is infinite implementation
|
| 206 |
+
CUTLASS_HOST_DEVICE
|
| 207 |
+
static bool isinf(float flt) {
|
| 208 |
+
uint32_t s;
|
| 209 |
+
|
| 210 |
+
#if defined(__CUDA_ARCH__)
|
| 211 |
+
s = reinterpret_cast<uint32_t const &>(flt);
|
| 212 |
+
#else
|
| 213 |
+
std::memcpy(&s, &flt, sizeof(s));
|
| 214 |
+
#endif
|
| 215 |
+
|
| 216 |
+
// Sign = 0 for +inf, 1 for -inf
|
| 217 |
+
// Exponent = all ones
|
| 218 |
+
// Mantissa = all zeros
|
| 219 |
+
return (s == 0x7f800000) || (s == 0xff800000);
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
/// FP32 -> FP8 conversion - rounds to nearest even
|
| 223 |
+
CUTLASS_HOST_DEVICE
|
| 224 |
+
static uint8_t convert_float_to_fp8(float const& flt) {
|
| 225 |
+
|
| 226 |
+
// software implementation rounds toward nearest even
|
| 227 |
+
uint32_t s;
|
| 228 |
+
|
| 229 |
+
#if defined(__CUDA_ARCH__)
|
| 230 |
+
s = reinterpret_cast<uint32_t const &>(flt);
|
| 231 |
+
#else
|
| 232 |
+
std::memcpy(&s, &flt, sizeof(s));
|
| 233 |
+
#endif
|
| 234 |
+
|
| 235 |
+
// Extract the bits in the FP32 type
|
| 236 |
+
uint8_t sign = uint8_t((s >> 24 & 0x80));
|
| 237 |
+
int32_t exp = int32_t((s >> FP32_NUM_MANTISSA_BITS) & 0xff) - FP32_EXPONENT_BIAS;
|
| 238 |
+
int mantissa = s & 0x7fffff;
|
| 239 |
+
uint8_t u = 0;
|
| 240 |
+
|
| 241 |
+
uint8_t const kF8_NaN = 0x7f;
|
| 242 |
+
|
| 243 |
+
// NaN => NaN
|
| 244 |
+
if (isnan(flt)) {
|
| 245 |
+
return kF8_NaN;
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
// Inf => MAX_FLT (satfinite)
|
| 249 |
+
if (isinf(flt)) {
|
| 250 |
+
return sign | FP8_MAX_FLT;
|
| 251 |
+
}
|
| 252 |
+
|
| 253 |
+
// Special handling
|
| 254 |
+
if (exp == -128) {
|
| 255 |
+
// int8 range is from -128 to 127
|
| 256 |
+
// So 255(inf) - 127(bias) = 128 - will show up as -128
|
| 257 |
+
|
| 258 |
+
// satfinite
|
| 259 |
+
return (sign | FP8_MAX_FLT);
|
| 260 |
+
}
|
| 261 |
+
|
| 262 |
+
int sticky_bit = 0;
|
| 263 |
+
|
| 264 |
+
bool skip_sign = false;
|
| 265 |
+
bool may_be_nan = false;
|
| 266 |
+
|
| 267 |
+
if ( (exp >= FP8_MIN_EXPONENT) && (exp <= FP8_MAX_EXPONENT) ) {
|
| 268 |
+
// normal fp32 to normal fp8
|
| 269 |
+
exp = exp + FP8_EXPONENT_BIAS;
|
| 270 |
+
u = uint8_t((uint32_t(exp) & FP8_EXPONENT_MASK) << FP8_NUM_MANTISSA_BITS);
|
| 271 |
+
u = uint8_t(u | (mantissa >> (FP32_NUM_MANTISSA_BITS - FP8_NUM_MANTISSA_BITS)));
|
| 272 |
+
} else if(exp < FP8_MIN_EXPONENT) {
|
| 273 |
+
// normal single-precision to subnormal float8-precision representation
|
| 274 |
+
int rshift = (FP8_MIN_EXPONENT - exp);
|
| 275 |
+
if (rshift < FP32_NUM_BITS) {
|
| 276 |
+
mantissa |= (1 << FP32_NUM_MANTISSA_BITS);
|
| 277 |
+
|
| 278 |
+
sticky_bit = ((mantissa & ((1 << rshift) - 1)) != 0);
|
| 279 |
+
|
| 280 |
+
mantissa = (mantissa >> rshift);
|
| 281 |
+
u = (uint8_t(mantissa >> (FP32_NUM_MANTISSA_BITS- FP8_NUM_MANTISSA_BITS)) & FP8_MANTISSA_MASK);
|
| 282 |
+
} else {
|
| 283 |
+
mantissa = 0;
|
| 284 |
+
u = 0;
|
| 285 |
+
}
|
| 286 |
+
// Exponent > FP8_MAX_EXPONENT - this is a special case done to match HW
|
| 287 |
+
// 0x4380_0000 to 0x43e0_0000 - maps from 256 to 448, and does not saturate / inf.
|
| 288 |
+
} else {
|
| 289 |
+
if( exp == (FP8_MAX_EXPONENT + 1) ) {
|
| 290 |
+
uint8_t mantissa_tmp = uint8_t(mantissa >> (FP32_NUM_MANTISSA_BITS - FP8_NUM_MANTISSA_BITS));
|
| 291 |
+
if( mantissa_tmp < FP8_MANTISSA_MASK) {
|
| 292 |
+
exp = exp + FP8_EXPONENT_BIAS;
|
| 293 |
+
u = uint8_t(uint32_t(exp) << FP8_NUM_MANTISSA_BITS) | mantissa_tmp;
|
| 294 |
+
may_be_nan = (mantissa_tmp == (FP8_MANTISSA_MASK-1));
|
| 295 |
+
} else {
|
| 296 |
+
// satfinite
|
| 297 |
+
return (sign | FP8_MAX_FLT);
|
| 298 |
+
}
|
| 299 |
+
} else{
|
| 300 |
+
// satfinite
|
| 301 |
+
return (sign | FP8_MAX_FLT);
|
| 302 |
+
}
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
// round to nearest even
|
| 306 |
+
int NUM_BITS_SHIFT = FP32_NUM_MANTISSA_BITS - (FP8_NUM_MANTISSA_BITS + 1);
|
| 307 |
+
int round_bit = ((mantissa >> NUM_BITS_SHIFT) & 1);
|
| 308 |
+
sticky_bit |= ((mantissa & ((1 << NUM_BITS_SHIFT) - 1)) != 0);
|
| 309 |
+
|
| 310 |
+
if ((round_bit && sticky_bit) || (round_bit && (u & 1))) {
|
| 311 |
+
u = uint8_t(u + 1);
|
| 312 |
+
if( may_be_nan ) {
|
| 313 |
+
skip_sign = true;
|
| 314 |
+
}
|
| 315 |
+
}
|
| 316 |
+
|
| 317 |
+
if (u > FP8_MAX_FLT) {
|
| 318 |
+
// satfinite
|
| 319 |
+
u = (sign | FP8_MAX_FLT);
|
| 320 |
+
}
|
| 321 |
+
|
| 322 |
+
if( ! skip_sign ) {
|
| 323 |
+
u |= sign;
|
| 324 |
+
}
|
| 325 |
+
|
| 326 |
+
return u;
|
| 327 |
+
}
|
| 328 |
+
|
| 329 |
+
|
| 330 |
+
/// Converts a fp8 value stored as a uint8_t to a float
|
| 331 |
+
CUTLASS_HOST_DEVICE
|
| 332 |
+
static float convert_fp8_to_float(uint8_t const& x) {
|
| 333 |
+
|
| 334 |
+
uint32_t constexpr kF32_NaN = 0x7fffffff;
|
| 335 |
+
|
| 336 |
+
uint8_t const &f8 = x;
|
| 337 |
+
uint32_t sign = (f8 >> (FP8_NUM_BITS - 1)) & 1;
|
| 338 |
+
uint32_t exp = (f8 >> FP8_NUM_MANTISSA_BITS) & FP8_EXPONENT_MASK;
|
| 339 |
+
uint32_t mantissa = f8 & FP8_MANTISSA_MASK;
|
| 340 |
+
unsigned f = (sign << (FP32_NUM_BITS-1));
|
| 341 |
+
|
| 342 |
+
if (IS_E4M3 && exp == 15 && mantissa == 0x7) {
|
| 343 |
+
f = kF32_NaN;
|
| 344 |
+
}
|
| 345 |
+
else if (exp > 0 && (IS_E4M3 || exp < (FP8_MAX_EXPONENT + FP8_EXPONENT_BIAS + 1))) {
|
| 346 |
+
// normal
|
| 347 |
+
exp += (FP32_EXPONENT_BIAS - FP8_EXPONENT_BIAS);
|
| 348 |
+
f = f |
|
| 349 |
+
(exp << FP32_NUM_MANTISSA_BITS) |
|
| 350 |
+
(mantissa << (FP32_NUM_MANTISSA_BITS-FP8_NUM_MANTISSA_BITS));
|
| 351 |
+
} else if (exp == 0) {
|
| 352 |
+
if (mantissa) {
|
| 353 |
+
// subnormal
|
| 354 |
+
exp += (FP32_EXPONENT_BIAS - FP8_EXPONENT_BIAS) + 1;
|
| 355 |
+
while ((mantissa & (1 << FP8_NUM_MANTISSA_BITS)) == 0) {
|
| 356 |
+
mantissa <<= 1;
|
| 357 |
+
exp--;
|
| 358 |
+
}
|
| 359 |
+
mantissa &= FP8_MANTISSA_MASK;
|
| 360 |
+
f = f |
|
| 361 |
+
(exp << FP32_NUM_MANTISSA_BITS) |
|
| 362 |
+
(mantissa << (FP32_NUM_MANTISSA_BITS-FP8_NUM_MANTISSA_BITS));
|
| 363 |
+
} else {
|
| 364 |
+
// sign-preserving zero
|
| 365 |
+
}
|
| 366 |
+
} else {
|
| 367 |
+
if(mantissa == 0){
|
| 368 |
+
// Sign-preserving infinity
|
| 369 |
+
f = (f | 0x7f800000);
|
| 370 |
+
} else {
|
| 371 |
+
// Canonical NaN
|
| 372 |
+
f = kF32_NaN;
|
| 373 |
+
}
|
| 374 |
+
}
|
| 375 |
+
|
| 376 |
+
#if defined(__CUDA_ARCH__)
|
| 377 |
+
return reinterpret_cast<float const&>(f);
|
| 378 |
+
#else
|
| 379 |
+
float flt;
|
| 380 |
+
std::memcpy(&flt, &f, sizeof(flt));
|
| 381 |
+
return flt;
|
| 382 |
+
#endif
|
| 383 |
+
}
|
| 384 |
+
};
|
| 385 |
+
|
| 386 |
+
|
| 387 |
+
// Forward declaration of float_e5m2_t to define float_e4m3_t <=> float_e5m2_t
|
| 388 |
+
// conversions in class float_e4m3_t
|
| 389 |
+
struct float_e5m2_t;
|
| 390 |
+
|
| 391 |
+
|
| 392 |
+
///////////////////////////////////////////////////////////////
|
| 393 |
+
///
|
| 394 |
+
/// floating-point 8 type : E4M3
|
| 395 |
+
///
|
| 396 |
+
///////////////////////////////////////////////////////////////
|
| 397 |
+
struct alignas(1) float_e4m3_t : float8_base<FloatEncoding::E4M3> {
|
| 398 |
+
|
| 399 |
+
using Base = float8_base<FloatEncoding::E4M3>;
|
| 400 |
+
|
| 401 |
+
static constexpr int MAX_EXPONENT = Base::FP8_MAX_EXPONENT;
|
| 402 |
+
|
| 403 |
+
//
|
| 404 |
+
// Static conversion operators
|
| 405 |
+
//
|
| 406 |
+
|
| 407 |
+
/// Constructs from an uint8_t
|
| 408 |
+
CUTLASS_HOST_DEVICE
|
| 409 |
+
static float_e4m3_t bitcast(uint8_t x) {
|
| 410 |
+
float_e4m3_t f;
|
| 411 |
+
f.storage = x;
|
| 412 |
+
return f;
|
| 413 |
+
}
|
| 414 |
+
|
| 415 |
+
/// FP32 -> FP8 conversion - rounds to nearest even
|
| 416 |
+
CUTLASS_HOST_DEVICE
|
| 417 |
+
static float_e4m3_t from_float(float const& flt) {
|
| 418 |
+
#if defined(CUDA_PTX_FP8_CVT_ENABLED)
|
| 419 |
+
uint16_t tmp;
|
| 420 |
+
float y = float();
|
| 421 |
+
asm volatile("cvt.rn.satfinite.e4m3x2.f32 %0, %1, %2;" : "=h"(tmp) : "f"(y), "f"(flt));
|
| 422 |
+
|
| 423 |
+
return *reinterpret_cast<float_e4m3_t *>(&tmp);
|
| 424 |
+
#else
|
| 425 |
+
return bitcast(Base::convert_float_to_fp8(flt));
|
| 426 |
+
#endif
|
| 427 |
+
}
|
| 428 |
+
|
| 429 |
+
/// FP16 -> E5M2 conversion - rounds to nearest even
|
| 430 |
+
CUTLASS_HOST_DEVICE
|
| 431 |
+
static float_e4m3_t from_half(half const& flt) {
|
| 432 |
+
#if defined(CUDA_PTX_FP8_CVT_ENABLED)
|
| 433 |
+
uint16_t tmp = 0;
|
| 434 |
+
uint32_t bits = reinterpret_cast<uint16_t const &>(flt);
|
| 435 |
+
asm volatile("cvt.rn.satfinite.e4m3x2.f16x2 %0, %1;" : "=h"(tmp) : "r"(bits));
|
| 436 |
+
|
| 437 |
+
return *reinterpret_cast<float_e4m3_t *>(&tmp);
|
| 438 |
+
#else
|
| 439 |
+
return bitcast(Base::convert_float_to_fp8(__half2float(flt)));
|
| 440 |
+
#endif
|
| 441 |
+
}
|
| 442 |
+
|
| 443 |
+
// E4M3 -> half
|
| 444 |
+
CUTLASS_HOST_DEVICE
|
| 445 |
+
static half to_half(float_e4m3_t const& x) {
|
| 446 |
+
#if defined(CUDA_PTX_FP8_CVT_ENABLED)
|
| 447 |
+
uint16_t bits = x.storage;
|
| 448 |
+
uint32_t packed;
|
| 449 |
+
asm volatile("cvt.rn.f16x2.e4m3x2 %0, %1;\n" : "=r"(packed) : "h"(bits));
|
| 450 |
+
|
| 451 |
+
return reinterpret_cast<half2 const &>(packed).x;
|
| 452 |
+
#else
|
| 453 |
+
return __float2half(Base::convert_fp8_to_float(x.storage));
|
| 454 |
+
#endif
|
| 455 |
+
}
|
| 456 |
+
|
| 457 |
+
// E4M3 -> Float
|
| 458 |
+
CUTLASS_HOST_DEVICE
|
| 459 |
+
static float to_float(float_e4m3_t const& x) {
|
| 460 |
+
#if defined(CUDA_PTX_FP8_CVT_ENABLED)
|
| 461 |
+
uint16_t bits = x.storage;
|
| 462 |
+
uint32_t packed;
|
| 463 |
+
asm volatile("cvt.rn.f16x2.e4m3x2 %0, %1;\n" : "=r"(packed) : "h"(bits));
|
| 464 |
+
|
| 465 |
+
return __half2float(reinterpret_cast<half2 const &>(packed).x);
|
| 466 |
+
#else
|
| 467 |
+
return Base::convert_fp8_to_float(x.storage);
|
| 468 |
+
#endif
|
| 469 |
+
}
|
| 470 |
+
|
| 471 |
+
//
|
| 472 |
+
// Methods
|
| 473 |
+
//
|
| 474 |
+
|
| 475 |
+
/// Constructor inheritance
|
| 476 |
+
using Base::Base;
|
| 477 |
+
|
| 478 |
+
/// Default constructor
|
| 479 |
+
float_e4m3_t() = default;
|
| 480 |
+
|
| 481 |
+
#ifdef CUDA_FP8_ENABLED
|
| 482 |
+
/// Conversion from CUDA's FP8 type
|
| 483 |
+
CUTLASS_HOST_DEVICE
|
| 484 |
+
explicit float_e4m3_t(__nv_fp8_e4m3 x) {
|
| 485 |
+
storage = x.__x;
|
| 486 |
+
}
|
| 487 |
+
#endif
|
| 488 |
+
|
| 489 |
+
/// Floating point conversion
|
| 490 |
+
CUTLASS_HOST_DEVICE
|
| 491 |
+
explicit float_e4m3_t(float x) {
|
| 492 |
+
storage = from_float(x).storage;
|
| 493 |
+
}
|
| 494 |
+
|
| 495 |
+
CUTLASS_HOST_DEVICE
|
| 496 |
+
explicit float_e4m3_t(half x) {
|
| 497 |
+
storage = from_half(x).storage;
|
| 498 |
+
}
|
| 499 |
+
|
| 500 |
+
/// Floating point conversion
|
| 501 |
+
CUTLASS_HOST_DEVICE
|
| 502 |
+
explicit float_e4m3_t(double x): float_e4m3_t(float(x)) {
|
| 503 |
+
}
|
| 504 |
+
|
| 505 |
+
/// Integer conversion
|
| 506 |
+
CUTLASS_HOST_DEVICE
|
| 507 |
+
explicit float_e4m3_t(int x): float_e4m3_t(float(x)) {
|
| 508 |
+
}
|
| 509 |
+
|
| 510 |
+
CUTLASS_HOST_DEVICE
|
| 511 |
+
explicit float_e4m3_t(unsigned x): float_e4m3_t(float(x)) {
|
| 512 |
+
}
|
| 513 |
+
|
| 514 |
+
/// E5M2 conversion. Defined after float_e5m2_t is defined.
|
| 515 |
+
CUTLASS_HOST_DEVICE
|
| 516 |
+
explicit float_e4m3_t(float_e5m2_t x);
|
| 517 |
+
|
| 518 |
+
#ifdef CUDA_FP8_ENABLED
|
| 519 |
+
/// Assignment from CUDA's FP8 type
|
| 520 |
+
CUTLASS_HOST_DEVICE
|
| 521 |
+
float_e4m3_t & operator=(__nv_fp8_e4m3 x) {
|
| 522 |
+
storage = x.__x;
|
| 523 |
+
return *this;
|
| 524 |
+
}
|
| 525 |
+
#endif
|
| 526 |
+
|
| 527 |
+
/// Converts to float
|
| 528 |
+
CUTLASS_HOST_DEVICE
|
| 529 |
+
operator float() const {
|
| 530 |
+
return to_float(*this);
|
| 531 |
+
}
|
| 532 |
+
|
| 533 |
+
/// Converts to half
|
| 534 |
+
CUTLASS_HOST_DEVICE
|
| 535 |
+
operator half() const {
|
| 536 |
+
return to_half(*this);
|
| 537 |
+
}
|
| 538 |
+
|
| 539 |
+
/// Converts to float
|
| 540 |
+
CUTLASS_HOST_DEVICE
|
| 541 |
+
explicit operator double() const {
|
| 542 |
+
return double(to_float(*this));
|
| 543 |
+
}
|
| 544 |
+
|
| 545 |
+
/// Converts to int
|
| 546 |
+
CUTLASS_HOST_DEVICE
|
| 547 |
+
explicit operator int() const {
|
| 548 |
+
#if defined(__CUDA_ARCH__)
|
| 549 |
+
return __half2int_rn(to_half(*this));
|
| 550 |
+
#else
|
| 551 |
+
return int(to_float(*this));
|
| 552 |
+
#endif
|
| 553 |
+
}
|
| 554 |
+
|
| 555 |
+
/// Casts to bool
|
| 556 |
+
CUTLASS_HOST_DEVICE
|
| 557 |
+
explicit operator bool() const {
|
| 558 |
+
#if defined(__CUDA_ARCH__)
|
| 559 |
+
return bool(__half2int_rn(to_half(*this)));
|
| 560 |
+
#else
|
| 561 |
+
return bool(int(to_float(*this)));
|
| 562 |
+
#endif
|
| 563 |
+
}
|
| 564 |
+
|
| 565 |
+
/// Accesses raw internal state
|
| 566 |
+
CUTLASS_HOST_DEVICE
|
| 567 |
+
uint8_t& raw() {
|
| 568 |
+
return storage;
|
| 569 |
+
}
|
| 570 |
+
|
| 571 |
+
/// Accesses raw internal state
|
| 572 |
+
CUTLASS_HOST_DEVICE
|
| 573 |
+
uint8_t raw() const {
|
| 574 |
+
return storage;
|
| 575 |
+
}
|
| 576 |
+
|
| 577 |
+
/// Returns the sign bit
|
| 578 |
+
CUTLASS_HOST_DEVICE
|
| 579 |
+
bool signbit() const {
|
| 580 |
+
return ((storage & (1 << (Base::FP8_NUM_BITS - 1))) != 0);
|
| 581 |
+
}
|
| 582 |
+
|
| 583 |
+
/// Returns the biased exponent
|
| 584 |
+
CUTLASS_HOST_DEVICE
|
| 585 |
+
int exponent_biased() const {
|
| 586 |
+
return int((storage >> FP8_NUM_MANTISSA_BITS) & Base::FP8_EXPONENT_MASK);
|
| 587 |
+
}
|
| 588 |
+
|
| 589 |
+
/// Returns the unbiased exponent
|
| 590 |
+
CUTLASS_HOST_DEVICE
|
| 591 |
+
int exponent() const {
|
| 592 |
+
return exponent_biased() - 15;
|
| 593 |
+
}
|
| 594 |
+
|
| 595 |
+
/// Returns the mantissa
|
| 596 |
+
CUTLASS_HOST_DEVICE
|
| 597 |
+
int mantissa() const {
|
| 598 |
+
return int(storage & Base::FP8_MANTISSA_MASK);
|
| 599 |
+
}
|
| 600 |
+
|
| 601 |
+
CUTLASS_HOST_DEVICE
|
| 602 |
+
friend bool isnan(float_e4m3_t const& x) {
|
| 603 |
+
return x.storage == uint8_t(0x7f);
|
| 604 |
+
}
|
| 605 |
+
|
| 606 |
+
};
|
| 607 |
+
///////////////////////////////////////////////////////////////
|
| 608 |
+
///
|
| 609 |
+
/// floating-point 8 type : E5M2
|
| 610 |
+
///
|
| 611 |
+
///////////////////////////////////////////////////////////////
|
| 612 |
+
struct alignas(1) float_e5m2_t : float8_base<FloatEncoding::E5M2> {
|
| 613 |
+
|
| 614 |
+
using Base = float8_base<FloatEncoding::E5M2>;
|
| 615 |
+
|
| 616 |
+
static constexpr int MAX_EXPONENT = Base::FP8_MAX_EXPONENT;
|
| 617 |
+
|
| 618 |
+
//
|
| 619 |
+
// Static conversion operators
|
| 620 |
+
//
|
| 621 |
+
|
| 622 |
+
/// Constructs from an uint8_t
|
| 623 |
+
CUTLASS_HOST_DEVICE
|
| 624 |
+
static float_e5m2_t bitcast(uint8_t x) {
|
| 625 |
+
float_e5m2_t f;
|
| 626 |
+
f.storage = x;
|
| 627 |
+
return f;
|
| 628 |
+
}
|
| 629 |
+
|
| 630 |
+
/// FP32 -> FP8 conversion - rounds to nearest even
|
| 631 |
+
CUTLASS_HOST_DEVICE
|
| 632 |
+
static float_e5m2_t from_float(float const& flt) {
|
| 633 |
+
#if defined(CUDA_PTX_FP8_CVT_ENABLED)
|
| 634 |
+
uint16_t tmp;
|
| 635 |
+
float y = float();
|
| 636 |
+
asm volatile("cvt.rn.satfinite.e5m2x2.f32 %0, %1, %2;" : "=h"(tmp) : "f"(y), "f"(flt));
|
| 637 |
+
|
| 638 |
+
return *reinterpret_cast<float_e5m2_t *>(&tmp);
|
| 639 |
+
#else
|
| 640 |
+
return bitcast(Base::convert_float_to_fp8(flt));
|
| 641 |
+
#endif
|
| 642 |
+
}
|
| 643 |
+
|
| 644 |
+
/// FP16 -> E5M2 conversion - rounds to nearest even
|
| 645 |
+
CUTLASS_HOST_DEVICE
|
| 646 |
+
static float_e5m2_t from_half(half const& flt) {
|
| 647 |
+
#if defined(CUDA_PTX_FP8_CVT_ENABLED)
|
| 648 |
+
uint16_t tmp = 0;
|
| 649 |
+
uint32_t bits = reinterpret_cast<uint16_t const &>(flt);
|
| 650 |
+
asm volatile("cvt.rn.satfinite.e5m2x2.f16x2 %0, %1;" : "=h"(tmp) : "r"(bits));
|
| 651 |
+
|
| 652 |
+
return *reinterpret_cast<float_e5m2_t *>(&tmp);
|
| 653 |
+
#else
|
| 654 |
+
return bitcast(Base::convert_float_to_fp8(__half2float(flt)));
|
| 655 |
+
#endif
|
| 656 |
+
}
|
| 657 |
+
|
| 658 |
+
// E5M2 -> half
|
| 659 |
+
CUTLASS_HOST_DEVICE
|
| 660 |
+
static half to_half(float_e5m2_t const& x) {
|
| 661 |
+
#if defined(CUDA_PTX_FP8_CVT_ENABLED)
|
| 662 |
+
uint16_t bits = x.storage;
|
| 663 |
+
uint32_t packed;
|
| 664 |
+
asm volatile("cvt.rn.f16x2.e5m2x2 %0, %1;\n" : "=r"(packed) : "h"(bits));
|
| 665 |
+
|
| 666 |
+
return reinterpret_cast<half2 const &>(packed).x;
|
| 667 |
+
#else
|
| 668 |
+
return __float2half(Base::convert_fp8_to_float(x.storage));
|
| 669 |
+
#endif
|
| 670 |
+
}
|
| 671 |
+
|
| 672 |
+
// E5M2 -> Float
|
| 673 |
+
CUTLASS_HOST_DEVICE
|
| 674 |
+
static float to_float(float_e5m2_t const& x) {
|
| 675 |
+
#if defined(CUDA_PTX_FP8_CVT_ENABLED)
|
| 676 |
+
uint16_t bits = x.storage;
|
| 677 |
+
uint32_t packed;
|
| 678 |
+
asm volatile("cvt.rn.f16x2.e5m2x2 %0, %1;\n" : "=r"(packed) : "h"(bits));
|
| 679 |
+
|
| 680 |
+
return __half2float(reinterpret_cast<half2 const &>(packed).x);
|
| 681 |
+
#else
|
| 682 |
+
return Base::convert_fp8_to_float(x.storage);
|
| 683 |
+
#endif
|
| 684 |
+
}
|
| 685 |
+
|
| 686 |
+
//
|
| 687 |
+
// Methods
|
| 688 |
+
//
|
| 689 |
+
|
| 690 |
+
/// Constructor inheritance
|
| 691 |
+
using Base::Base;
|
| 692 |
+
|
| 693 |
+
/// Default constructor
|
| 694 |
+
float_e5m2_t() = default;
|
| 695 |
+
|
| 696 |
+
#ifdef CUDA_FP8_ENABLED
|
| 697 |
+
/// Conversion from CUDA's FP8 type
|
| 698 |
+
CUTLASS_HOST_DEVICE
|
| 699 |
+
explicit float_e5m2_t(__nv_fp8_e5m2 x) {
|
| 700 |
+
storage = x.__x;
|
| 701 |
+
}
|
| 702 |
+
#endif
|
| 703 |
+
|
| 704 |
+
/// Floating point conversion
|
| 705 |
+
CUTLASS_HOST_DEVICE
|
| 706 |
+
explicit float_e5m2_t(float x) {
|
| 707 |
+
storage = from_float(x).storage;
|
| 708 |
+
}
|
| 709 |
+
|
| 710 |
+
CUTLASS_HOST_DEVICE
|
| 711 |
+
explicit float_e5m2_t(half x) {
|
| 712 |
+
storage = from_half(x).storage;
|
| 713 |
+
}
|
| 714 |
+
|
| 715 |
+
/// Floating point conversion
|
| 716 |
+
CUTLASS_HOST_DEVICE
|
| 717 |
+
explicit float_e5m2_t(double x): float_e5m2_t(float(x)) {
|
| 718 |
+
}
|
| 719 |
+
|
| 720 |
+
/// Integer conversion
|
| 721 |
+
CUTLASS_HOST_DEVICE
|
| 722 |
+
explicit float_e5m2_t(int x): float_e5m2_t(float(x)) {
|
| 723 |
+
}
|
| 724 |
+
|
| 725 |
+
CUTLASS_HOST_DEVICE
|
| 726 |
+
explicit float_e5m2_t(unsigned x): float_e5m2_t(float(x)) {
|
| 727 |
+
}
|
| 728 |
+
|
| 729 |
+
/// E4M3 conversion
|
| 730 |
+
CUTLASS_HOST_DEVICE
|
| 731 |
+
explicit float_e5m2_t(float_e4m3_t x);
|
| 732 |
+
|
| 733 |
+
#ifdef CUDA_FP8_ENABLED
|
| 734 |
+
/// Assignment from CUDA's FP8 type
|
| 735 |
+
CUTLASS_HOST_DEVICE
|
| 736 |
+
float_e5m2_t & operator=(__nv_fp8_e5m2 x) {
|
| 737 |
+
storage = x.__x;
|
| 738 |
+
return *this;
|
| 739 |
+
}
|
| 740 |
+
#endif
|
| 741 |
+
|
| 742 |
+
/// Converts to float
|
| 743 |
+
CUTLASS_HOST_DEVICE
|
| 744 |
+
operator float() const {
|
| 745 |
+
return to_float(*this);
|
| 746 |
+
}
|
| 747 |
+
|
| 748 |
+
/// Converts to half
|
| 749 |
+
CUTLASS_HOST_DEVICE
|
| 750 |
+
operator half() const {
|
| 751 |
+
return to_half(*this);
|
| 752 |
+
}
|
| 753 |
+
|
| 754 |
+
/// Converts to float
|
| 755 |
+
CUTLASS_HOST_DEVICE
|
| 756 |
+
explicit operator double() const {
|
| 757 |
+
return double(to_float(*this));
|
| 758 |
+
}
|
| 759 |
+
|
| 760 |
+
/// Converts to int
|
| 761 |
+
CUTLASS_HOST_DEVICE
|
| 762 |
+
explicit operator int() const {
|
| 763 |
+
#if defined(__CUDA_ARCH__)
|
| 764 |
+
return __half2int_rn(to_half(*this));
|
| 765 |
+
#else
|
| 766 |
+
return int(to_float(*this));
|
| 767 |
+
#endif
|
| 768 |
+
}
|
| 769 |
+
|
| 770 |
+
/// Casts to bool
|
| 771 |
+
CUTLASS_HOST_DEVICE
|
| 772 |
+
explicit operator bool() const {
|
| 773 |
+
#if defined(__CUDA_ARCH__)
|
| 774 |
+
return bool(__half2int_rn(to_half(*this)));
|
| 775 |
+
#else
|
| 776 |
+
return bool(int(to_float(*this)));
|
| 777 |
+
#endif
|
| 778 |
+
}
|
| 779 |
+
|
| 780 |
+
/// Accesses raw internal state
|
| 781 |
+
CUTLASS_HOST_DEVICE
|
| 782 |
+
uint8_t& raw() {
|
| 783 |
+
return storage;
|
| 784 |
+
}
|
| 785 |
+
|
| 786 |
+
/// Accesses raw internal state
|
| 787 |
+
CUTLASS_HOST_DEVICE
|
| 788 |
+
uint8_t raw() const {
|
| 789 |
+
return storage;
|
| 790 |
+
}
|
| 791 |
+
|
| 792 |
+
/// Returns the sign bit
|
| 793 |
+
CUTLASS_HOST_DEVICE
|
| 794 |
+
bool signbit() const {
|
| 795 |
+
return ((storage & (1 << (Base::FP8_NUM_BITS - 1))) != 0);
|
| 796 |
+
}
|
| 797 |
+
|
| 798 |
+
/// Returns the biased exponent
|
| 799 |
+
CUTLASS_HOST_DEVICE
|
| 800 |
+
int exponent_biased() const {
|
| 801 |
+
return int((storage >> FP8_NUM_MANTISSA_BITS) & Base::FP8_EXPONENT_MASK);
|
| 802 |
+
}
|
| 803 |
+
|
| 804 |
+
/// Returns the unbiased exponent
|
| 805 |
+
CUTLASS_HOST_DEVICE
|
| 806 |
+
int exponent() const {
|
| 807 |
+
return exponent_biased() - 15;
|
| 808 |
+
}
|
| 809 |
+
|
| 810 |
+
/// Returns the mantissa
|
| 811 |
+
CUTLASS_HOST_DEVICE
|
| 812 |
+
int mantissa() const {
|
| 813 |
+
return int(storage & Base::FP8_MANTISSA_MASK);
|
| 814 |
+
}
|
| 815 |
+
|
| 816 |
+
CUTLASS_HOST_DEVICE
|
| 817 |
+
friend bool isnan(float_e5m2_t const& x) {
|
| 818 |
+
return x.storage == uint8_t(0x7f);
|
| 819 |
+
}
|
| 820 |
+
|
| 821 |
+
};
|
| 822 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 823 |
+
//
|
| 824 |
+
// Arithmetic operators
|
| 825 |
+
//
|
| 826 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 827 |
+
|
| 828 |
+
CUTLASS_HOST_DEVICE
|
| 829 |
+
bool operator==(float_e4m3_t const& lhs, float_e4m3_t const& rhs) {
|
| 830 |
+
return float(lhs) == float(rhs);
|
| 831 |
+
}
|
| 832 |
+
|
| 833 |
+
CUTLASS_HOST_DEVICE
|
| 834 |
+
bool operator!=(float_e4m3_t const& lhs, float_e4m3_t const& rhs) {
|
| 835 |
+
return float(lhs) != float(rhs);
|
| 836 |
+
}
|
| 837 |
+
|
| 838 |
+
CUTLASS_HOST_DEVICE
|
| 839 |
+
bool operator<(float_e4m3_t const& lhs, float_e4m3_t const& rhs) {
|
| 840 |
+
return float(lhs) < float(rhs);
|
| 841 |
+
}
|
| 842 |
+
|
| 843 |
+
CUTLASS_HOST_DEVICE
|
| 844 |
+
bool operator<=(float_e4m3_t const& lhs, float_e4m3_t const& rhs) {
|
| 845 |
+
return float(lhs) <= float(rhs);
|
| 846 |
+
}
|
| 847 |
+
|
| 848 |
+
CUTLASS_HOST_DEVICE
|
| 849 |
+
bool operator>(float_e4m3_t const& lhs, float_e4m3_t const& rhs) {
|
| 850 |
+
return float(lhs) > float(rhs);
|
| 851 |
+
}
|
| 852 |
+
|
| 853 |
+
CUTLASS_HOST_DEVICE
|
| 854 |
+
bool operator>=(float_e4m3_t const& lhs, float_e4m3_t const& rhs) {
|
| 855 |
+
return float(lhs) >= float(rhs);
|
| 856 |
+
}
|
| 857 |
+
|
| 858 |
+
CUTLASS_HOST_DEVICE
|
| 859 |
+
float_e4m3_t operator+(float_e4m3_t const& lhs, float_e4m3_t const& rhs) {
|
| 860 |
+
return float_e4m3_t(float(lhs) + float(rhs));
|
| 861 |
+
}
|
| 862 |
+
|
| 863 |
+
CUTLASS_HOST_DEVICE
|
| 864 |
+
float_e4m3_t operator-(float_e4m3_t const& lhs) {
|
| 865 |
+
return float_e4m3_t(-float(lhs));
|
| 866 |
+
}
|
| 867 |
+
|
| 868 |
+
CUTLASS_HOST_DEVICE
|
| 869 |
+
float_e4m3_t operator-(float_e4m3_t const& lhs, float_e4m3_t const& rhs) {
|
| 870 |
+
return float_e4m3_t(float(lhs) - float(rhs));
|
| 871 |
+
}
|
| 872 |
+
|
| 873 |
+
CUTLASS_HOST_DEVICE
|
| 874 |
+
float_e4m3_t operator*(float_e4m3_t const& lhs, float_e4m3_t const& rhs) {
|
| 875 |
+
return float_e4m3_t(float(lhs) * float(rhs));
|
| 876 |
+
}
|
| 877 |
+
|
| 878 |
+
CUTLASS_HOST_DEVICE
|
| 879 |
+
float_e4m3_t operator/(float_e4m3_t const& lhs, float_e4m3_t const& rhs) {
|
| 880 |
+
return float_e4m3_t(float(lhs) / float(rhs));
|
| 881 |
+
}
|
| 882 |
+
|
| 883 |
+
CUTLASS_HOST_DEVICE
|
| 884 |
+
float_e4m3_t& operator+=(float_e4m3_t & lhs, float_e4m3_t const& rhs) {
|
| 885 |
+
lhs = float_e4m3_t(float(lhs) + float(rhs));
|
| 886 |
+
return lhs;
|
| 887 |
+
}
|
| 888 |
+
|
| 889 |
+
CUTLASS_HOST_DEVICE
|
| 890 |
+
float_e4m3_t& operator-=(float_e4m3_t & lhs, float_e4m3_t const& rhs) {
|
| 891 |
+
lhs = float_e4m3_t(float(lhs) - float(rhs));
|
| 892 |
+
return lhs;
|
| 893 |
+
}
|
| 894 |
+
|
| 895 |
+
CUTLASS_HOST_DEVICE
|
| 896 |
+
float_e4m3_t& operator*=(float_e4m3_t & lhs, float_e4m3_t const& rhs) {
|
| 897 |
+
lhs = float_e4m3_t(float(lhs) * float(rhs));
|
| 898 |
+
return lhs;
|
| 899 |
+
}
|
| 900 |
+
|
| 901 |
+
CUTLASS_HOST_DEVICE
|
| 902 |
+
float_e4m3_t& operator/=(float_e4m3_t & lhs, float_e4m3_t const& rhs) {
|
| 903 |
+
lhs = float_e4m3_t(float(lhs) / float(rhs));
|
| 904 |
+
return lhs;
|
| 905 |
+
}
|
| 906 |
+
|
| 907 |
+
CUTLASS_HOST_DEVICE
|
| 908 |
+
float_e4m3_t& operator++(float_e4m3_t & lhs) {
|
| 909 |
+
float tmp(lhs);
|
| 910 |
+
++tmp;
|
| 911 |
+
lhs = float_e4m3_t(tmp);
|
| 912 |
+
return lhs;
|
| 913 |
+
}
|
| 914 |
+
|
| 915 |
+
CUTLASS_HOST_DEVICE
|
| 916 |
+
float_e4m3_t& operator--(float_e4m3_t & lhs) {
|
| 917 |
+
float tmp(lhs);
|
| 918 |
+
--tmp;
|
| 919 |
+
lhs = float_e4m3_t(tmp);
|
| 920 |
+
return lhs;
|
| 921 |
+
}
|
| 922 |
+
|
| 923 |
+
CUTLASS_HOST_DEVICE
|
| 924 |
+
float_e4m3_t operator++(float_e4m3_t & lhs, int) {
|
| 925 |
+
float_e4m3_t ret(lhs);
|
| 926 |
+
float tmp(lhs);
|
| 927 |
+
tmp++;
|
| 928 |
+
lhs = float_e4m3_t(tmp);
|
| 929 |
+
return ret;
|
| 930 |
+
}
|
| 931 |
+
|
| 932 |
+
CUTLASS_HOST_DEVICE
|
| 933 |
+
float_e4m3_t operator--(float_e4m3_t & lhs, int) {
|
| 934 |
+
float_e4m3_t ret(lhs);
|
| 935 |
+
float tmp(lhs);
|
| 936 |
+
tmp--;
|
| 937 |
+
lhs = float_e4m3_t(tmp);
|
| 938 |
+
return ret;
|
| 939 |
+
}
|
| 940 |
+
|
| 941 |
+
CUTLASS_HOST_DEVICE
|
| 942 |
+
bool operator==(float_e5m2_t const& lhs, float_e5m2_t const& rhs) {
|
| 943 |
+
return float(lhs) == float(rhs);
|
| 944 |
+
}
|
| 945 |
+
|
| 946 |
+
CUTLASS_HOST_DEVICE
|
| 947 |
+
bool operator!=(float_e5m2_t const& lhs, float_e5m2_t const& rhs) {
|
| 948 |
+
return float(lhs) != float(rhs);
|
| 949 |
+
}
|
| 950 |
+
|
| 951 |
+
CUTLASS_HOST_DEVICE
|
| 952 |
+
bool operator<(float_e5m2_t const& lhs, float_e5m2_t const& rhs) {
|
| 953 |
+
return float(lhs) < float(rhs);
|
| 954 |
+
}
|
| 955 |
+
|
| 956 |
+
CUTLASS_HOST_DEVICE
|
| 957 |
+
bool operator<=(float_e5m2_t const& lhs, float_e5m2_t const& rhs) {
|
| 958 |
+
return float(lhs) <= float(rhs);
|
| 959 |
+
}
|
| 960 |
+
|
| 961 |
+
CUTLASS_HOST_DEVICE
|
| 962 |
+
bool operator>(float_e5m2_t const& lhs, float_e5m2_t const& rhs) {
|
| 963 |
+
return float(lhs) > float(rhs);
|
| 964 |
+
}
|
| 965 |
+
|
| 966 |
+
CUTLASS_HOST_DEVICE
|
| 967 |
+
bool operator>=(float_e5m2_t const& lhs, float_e5m2_t const& rhs) {
|
| 968 |
+
return float(lhs) >= float(rhs);
|
| 969 |
+
}
|
| 970 |
+
|
| 971 |
+
CUTLASS_HOST_DEVICE
|
| 972 |
+
float_e5m2_t operator+(float_e5m2_t const& lhs, float_e5m2_t const& rhs) {
|
| 973 |
+
return float_e5m2_t(float(lhs) + float(rhs));
|
| 974 |
+
}
|
| 975 |
+
|
| 976 |
+
CUTLASS_HOST_DEVICE
|
| 977 |
+
float_e5m2_t operator-(float_e5m2_t const& lhs) {
|
| 978 |
+
return float_e5m2_t(-float(lhs));
|
| 979 |
+
}
|
| 980 |
+
|
| 981 |
+
CUTLASS_HOST_DEVICE
|
| 982 |
+
float_e5m2_t operator-(float_e5m2_t const& lhs, float_e5m2_t const& rhs) {
|
| 983 |
+
return float_e5m2_t(float(lhs) - float(rhs));
|
| 984 |
+
}
|
| 985 |
+
|
| 986 |
+
CUTLASS_HOST_DEVICE
|
| 987 |
+
float_e5m2_t operator*(float_e5m2_t const& lhs, float_e5m2_t const& rhs) {
|
| 988 |
+
return float_e5m2_t(float(lhs) * float(rhs));
|
| 989 |
+
}
|
| 990 |
+
|
| 991 |
+
CUTLASS_HOST_DEVICE
|
| 992 |
+
float_e5m2_t operator/(float_e5m2_t const& lhs, float_e5m2_t const& rhs) {
|
| 993 |
+
return float_e5m2_t(float(lhs) / float(rhs));
|
| 994 |
+
}
|
| 995 |
+
|
| 996 |
+
CUTLASS_HOST_DEVICE
|
| 997 |
+
float_e5m2_t& operator+=(float_e5m2_t & lhs, float_e5m2_t const& rhs) {
|
| 998 |
+
lhs = float_e5m2_t(float(lhs) + float(rhs));
|
| 999 |
+
return lhs;
|
| 1000 |
+
}
|
| 1001 |
+
|
| 1002 |
+
CUTLASS_HOST_DEVICE
|
| 1003 |
+
float_e5m2_t& operator-=(float_e5m2_t & lhs, float_e5m2_t const& rhs) {
|
| 1004 |
+
lhs = float_e5m2_t(float(lhs) - float(rhs));
|
| 1005 |
+
return lhs;
|
| 1006 |
+
}
|
| 1007 |
+
|
| 1008 |
+
CUTLASS_HOST_DEVICE
|
| 1009 |
+
float_e5m2_t& operator*=(float_e5m2_t & lhs, float_e5m2_t const& rhs) {
|
| 1010 |
+
lhs = float_e5m2_t(float(lhs) * float(rhs));
|
| 1011 |
+
return lhs;
|
| 1012 |
+
}
|
| 1013 |
+
|
| 1014 |
+
CUTLASS_HOST_DEVICE
|
| 1015 |
+
float_e5m2_t& operator/=(float_e5m2_t & lhs, float_e5m2_t const& rhs) {
|
| 1016 |
+
lhs = float_e5m2_t(float(lhs) / float(rhs));
|
| 1017 |
+
return lhs;
|
| 1018 |
+
}
|
| 1019 |
+
|
| 1020 |
+
CUTLASS_HOST_DEVICE
|
| 1021 |
+
float_e5m2_t& operator++(float_e5m2_t & lhs) {
|
| 1022 |
+
float tmp(lhs);
|
| 1023 |
+
++tmp;
|
| 1024 |
+
lhs = float_e5m2_t(tmp);
|
| 1025 |
+
return lhs;
|
| 1026 |
+
}
|
| 1027 |
+
|
| 1028 |
+
CUTLASS_HOST_DEVICE
|
| 1029 |
+
float_e5m2_t& operator--(float_e5m2_t & lhs) {
|
| 1030 |
+
float tmp(lhs);
|
| 1031 |
+
--tmp;
|
| 1032 |
+
lhs = float_e5m2_t(tmp);
|
| 1033 |
+
return lhs;
|
| 1034 |
+
}
|
| 1035 |
+
|
| 1036 |
+
CUTLASS_HOST_DEVICE
|
| 1037 |
+
float_e5m2_t operator++(float_e5m2_t & lhs, int) {
|
| 1038 |
+
float_e5m2_t ret(lhs);
|
| 1039 |
+
float tmp(lhs);
|
| 1040 |
+
tmp++;
|
| 1041 |
+
lhs = float_e5m2_t(tmp);
|
| 1042 |
+
return ret;
|
| 1043 |
+
}
|
| 1044 |
+
|
| 1045 |
+
CUTLASS_HOST_DEVICE
|
| 1046 |
+
float_e5m2_t operator--(float_e5m2_t & lhs, int) {
|
| 1047 |
+
float_e5m2_t ret(lhs);
|
| 1048 |
+
float tmp(lhs);
|
| 1049 |
+
tmp--;
|
| 1050 |
+
lhs = float_e5m2_t(tmp);
|
| 1051 |
+
return ret;
|
| 1052 |
+
}
|
| 1053 |
+
|
| 1054 |
+
|
| 1055 |
+
///////////////////////////////////////////////////////////////
|
| 1056 |
+
///
|
| 1057 |
+
/// floating-point 8 type : UE4M3
|
| 1058 |
+
///
|
| 1059 |
+
///////////////////////////////////////////////////////////////
|
| 1060 |
+
// UE4M3:
|
| 1061 |
+
// 4 Exponent bits, 3 Mantissa bits
|
| 1062 |
+
// Range: [0:448]
|
| 1063 |
+
// has_inf: false
|
| 1064 |
+
// has_NaN: true
|
| 1065 |
+
// has_denorm: true
|
| 1066 |
+
// Exponent bias (exp_bias): 7
|
| 1067 |
+
struct float_ue4m3_t : public float_exmy_base<cutlass::detail::FpEncoding::UE4M3, float_ue4m3_t> {
|
| 1068 |
+
using Base = float_exmy_base<cutlass::detail::FpEncoding::UE4M3, float_ue4m3_t>;
|
| 1069 |
+
|
| 1070 |
+
float_ue4m3_t() = default;
|
| 1071 |
+
|
| 1072 |
+
CUTLASS_HOST_DEVICE
|
| 1073 |
+
float_ue4m3_t convert_from_float(float const &flt) const {
|
| 1074 |
+
#if defined(CUDA_PTX_FP8_CVT_ENABLED)
|
| 1075 |
+
uint16_t tmp;
|
| 1076 |
+
float y = float();
|
| 1077 |
+
asm volatile("cvt.rn.satfinite.e4m3x2.f32 %0, %1, %2;" : "=h"(tmp) : "f"(y), "f"(flt));
|
| 1078 |
+
return bitcast(*reinterpret_cast<uint8_t *>(&tmp));
|
| 1079 |
+
#else
|
| 1080 |
+
Base::FP32BitRepresentation::Storage fp32_bits = Base::FP32BitRepresentation::to_bits(flt);
|
| 1081 |
+
return bitcast(BitRepresentation::convert_from(fp32_bits, Base::FP32BitRepresentation{}));
|
| 1082 |
+
#endif
|
| 1083 |
+
}
|
| 1084 |
+
|
| 1085 |
+
CUTLASS_HOST_DEVICE
|
| 1086 |
+
float convert_to_float(float_ue4m3_t const &x) const {
|
| 1087 |
+
#if defined(CUDA_PTX_FP8_CVT_ENABLED)
|
| 1088 |
+
uint16_t bits = x.storage;
|
| 1089 |
+
uint32_t packed;
|
| 1090 |
+
asm volatile("cvt.rn.f16x2.e4m3x2 %0, %1;\n" : "=r"(packed) : "h"(bits));
|
| 1091 |
+
return __half2float(reinterpret_cast<half2 const &>(packed).x);
|
| 1092 |
+
#else
|
| 1093 |
+
Base::FP32BitRepresentation::Storage fp32_bits;
|
| 1094 |
+
fp32_bits = Base::BitRepresentation::convert_to(x.storage, Base::FP32BitRepresentation{});
|
| 1095 |
+
return detail::copy_bits<Base::FP32BitRepresentation::Storage, float>(fp32_bits);
|
| 1096 |
+
#endif
|
| 1097 |
+
}
|
| 1098 |
+
|
| 1099 |
+
CUTLASS_HOST_DEVICE
|
| 1100 |
+
explicit float_ue4m3_t(double x) : Base(float(x)) {
|
| 1101 |
+
}
|
| 1102 |
+
|
| 1103 |
+
CUTLASS_HOST_DEVICE
|
| 1104 |
+
explicit float_ue4m3_t(float x) : Base(x) {
|
| 1105 |
+
}
|
| 1106 |
+
|
| 1107 |
+
CUTLASS_HOST_DEVICE
|
| 1108 |
+
explicit float_ue4m3_t(int x) : Base(x) {
|
| 1109 |
+
}
|
| 1110 |
+
|
| 1111 |
+
CUTLASS_HOST_DEVICE
|
| 1112 |
+
explicit float_ue4m3_t(unsigned x) : Base(x) {
|
| 1113 |
+
}
|
| 1114 |
+
|
| 1115 |
+
CUTLASS_HOST_DEVICE
|
| 1116 |
+
float_ue4m3_t(Base x) : Base(x) {
|
| 1117 |
+
}
|
| 1118 |
+
|
| 1119 |
+
CUTLASS_HOST_DEVICE
|
| 1120 |
+
friend bool isnan(float_ue4m3_t const& x) {
|
| 1121 |
+
return x.storage == uint8_t(0x7f);
|
| 1122 |
+
}
|
| 1123 |
+
|
| 1124 |
+
};
|
| 1125 |
+
|
| 1126 |
+
/// Defines the size of an element in bits - specialized for float_ue4m3_t
|
| 1127 |
+
template <>
|
| 1128 |
+
struct sizeof_bits<float_ue4m3_t> {
|
| 1129 |
+
static constexpr int value = sizeof_bits<float_exmy_base<cutlass::detail::FpEncoding::UE4M3, float_ue4m3_t>>::value;
|
| 1130 |
+
};
|
| 1131 |
+
|
| 1132 |
+
|
| 1133 |
+
|
| 1134 |
+
///////////////////////////////////////////////////////////////
|
| 1135 |
+
///
|
| 1136 |
+
/// floating-point 8 type : UE8M0
|
| 1137 |
+
///
|
| 1138 |
+
///////////////////////////////////////////////////////////////
|
| 1139 |
+
// UE8M0:
|
| 1140 |
+
// 8 Exponent bits, 0 Mantissa bits
|
| 1141 |
+
// Range: [2^-127:2^127]
|
| 1142 |
+
// has_inf: false
|
| 1143 |
+
// has_NaN: true (11111111)
|
| 1144 |
+
// has_denorm: true
|
| 1145 |
+
// Exponent bias (exp_bias): 8
|
| 1146 |
+
|
| 1147 |
+
struct float_ue8m0_t : public float_exmy_base<cutlass::detail::FpEncoding::UE8M0, float_ue8m0_t> {
|
| 1148 |
+
using Base = float_exmy_base<cutlass::detail::FpEncoding::UE8M0, float_ue8m0_t>;
|
| 1149 |
+
using FP32Bits = typename Base::FP32BitRepresentation;
|
| 1150 |
+
|
| 1151 |
+
float_ue8m0_t() = default;
|
| 1152 |
+
|
| 1153 |
+
CUTLASS_HOST_DEVICE
|
| 1154 |
+
float_ue8m0_t convert_from_float(float const &flt) const {
|
| 1155 |
+
#if defined(CUDA_PTX_UE8M0_CVT_ENABLED)
|
| 1156 |
+
uint16_t out;
|
| 1157 |
+
asm volatile(
|
| 1158 |
+
"{ cvt.rp.satfinite.ue8m0x2.f32 %0, 0.0, %1; }"
|
| 1159 |
+
: "=h"(out) : "f"(flt));
|
| 1160 |
+
return bitcast(*reinterpret_cast<uint8_t *>(&out));
|
| 1161 |
+
#else
|
| 1162 |
+
if (CUTLASS_CMATH_NAMESPACE::isnan(flt) || CUTLASS_CMATH_NAMESPACE::isinf(flt)) {
|
| 1163 |
+
return bitcast(0xFF);
|
| 1164 |
+
}
|
| 1165 |
+
uint32_t flt_uint32 = cutlass::detail::copy_bits<float, uint32_t>(flt);
|
| 1166 |
+
uint8_t exp = (flt_uint32 >> 23) & 0xff; // Extract the 8 bit exponent
|
| 1167 |
+
uint32_t mant = flt_uint32 & 0x7fffff; // Extract the 23 bit mantissa
|
| 1168 |
+
// Do the round up
|
| 1169 |
+
// Deals w/ satfinite all at once
|
| 1170 |
+
if ((mant > 0) && (exp != 0xFE) && !(exp == 0 && mant <= 0x00400000)) {
|
| 1171 |
+
exp++;
|
| 1172 |
+
}
|
| 1173 |
+
return bitcast(exp);
|
| 1174 |
+
#endif
|
| 1175 |
+
}
|
| 1176 |
+
|
| 1177 |
+
CUTLASS_HOST_DEVICE
|
| 1178 |
+
float convert_to_float(float_ue8m0_t const &x) const {
|
| 1179 |
+
//////////////////////////////////////////////////////////////
|
| 1180 |
+
// The conversion of UE8M0 to FP32 scale can be done simply
|
| 1181 |
+
// with a left shift (No rounding necessary)
|
| 1182 |
+
// Note: The base class implements ue8m0 to FP32 based on the rules of float math conversions.
|
| 1183 |
+
// The result of current implementation and base class are aligned.
|
| 1184 |
+
//////////////////////////////////////////////////////////////
|
| 1185 |
+
#if defined(CUDA_PTX_UE8M0_CVT_ENABLED)
|
| 1186 |
+
uint16_t bits = x.storage;
|
| 1187 |
+
uint32_t bf16x2_val;
|
| 1188 |
+
// E8 -> BF16
|
| 1189 |
+
asm volatile(
|
| 1190 |
+
"{\n"
|
| 1191 |
+
"cvt.rn.bf16x2.ue8m0x2 %0, %1;\n"
|
| 1192 |
+
"}\n" : "=r"(bf16x2_val): "h"(bits));
|
| 1193 |
+
// BF16 -> FP32
|
| 1194 |
+
float f1;
|
| 1195 |
+
asm(
|
| 1196 |
+
"{\n"
|
| 1197 |
+
"prmt.b32 %0, %1, %2, %3;\n"
|
| 1198 |
+
"}\n"
|
| 1199 |
+
: "=f"(f1)
|
| 1200 |
+
: "r"(0), "r"(bf16x2_val), "r"(0x5410));
|
| 1201 |
+
return f1;
|
| 1202 |
+
#else
|
| 1203 |
+
using FP32Bits = cutlass::detail::FpBitRepresentation<uint32_t, 32, 8, 23, cutlass::detail::NanInfEncoding::IEEE_754>;
|
| 1204 |
+
if (x.storage == 0x00) {
|
| 1205 |
+
return cutlass::detail::copy_bits<FP32Bits::Storage, float>(0x00400000);
|
| 1206 |
+
}
|
| 1207 |
+
else if (x.storage == 0xFF) {
|
| 1208 |
+
return cutlass::detail::copy_bits<FP32Bits::Storage, float>(0x7fffffff);
|
| 1209 |
+
}
|
| 1210 |
+
else {
|
| 1211 |
+
auto f8 = static_cast<FP32Bits::Storage>(x.storage);
|
| 1212 |
+
FP32Bits::Storage f = (f8 << FP32Bits::NUM_MANTISSA_BITS);
|
| 1213 |
+
return cutlass::detail::copy_bits<FP32Bits::Storage, float>(f);
|
| 1214 |
+
}
|
| 1215 |
+
#endif
|
| 1216 |
+
}
|
| 1217 |
+
|
| 1218 |
+
CUTLASS_HOST_DEVICE
|
| 1219 |
+
explicit float_ue8m0_t(double x) : Base(float(x)) {
|
| 1220 |
+
}
|
| 1221 |
+
|
| 1222 |
+
CUTLASS_HOST_DEVICE
|
| 1223 |
+
explicit float_ue8m0_t(float x) : Base(x) {
|
| 1224 |
+
}
|
| 1225 |
+
|
| 1226 |
+
CUTLASS_HOST_DEVICE
|
| 1227 |
+
explicit float_ue8m0_t(int x) : Base(x) {
|
| 1228 |
+
}
|
| 1229 |
+
|
| 1230 |
+
CUTLASS_HOST_DEVICE
|
| 1231 |
+
explicit float_ue8m0_t(unsigned x) : Base(x) {
|
| 1232 |
+
}
|
| 1233 |
+
|
| 1234 |
+
CUTLASS_HOST_DEVICE
|
| 1235 |
+
float_ue8m0_t(Base x) : Base(x) {
|
| 1236 |
+
}
|
| 1237 |
+
|
| 1238 |
+
CUTLASS_HOST_DEVICE
|
| 1239 |
+
friend bool isnan(float_ue8m0_t const& x) {
|
| 1240 |
+
return x.storage == uint8_t(0xff);
|
| 1241 |
+
}
|
| 1242 |
+
|
| 1243 |
+
};
|
| 1244 |
+
|
| 1245 |
+
/// Defines the size of an element in bits - specialized for float_ue8m0_t
|
| 1246 |
+
template <>
|
| 1247 |
+
struct sizeof_bits<float_ue8m0_t> {
|
| 1248 |
+
static constexpr int value = sizeof_bits<float_exmy_base<cutlass::detail::FpEncoding::UE8M0, float_ue8m0_t>>::value;
|
| 1249 |
+
};
|
| 1250 |
+
|
| 1251 |
+
|
| 1252 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1253 |
+
//
|
| 1254 |
+
// float_e4m3_t <=> float_e5m2_t conversions
|
| 1255 |
+
//
|
| 1256 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1257 |
+
|
| 1258 |
+
/// float_e4m3_t <= float_e5m2_t
|
| 1259 |
+
CUTLASS_HOST_DEVICE
|
| 1260 |
+
float_e4m3_t::float_e4m3_t(float_e5m2_t x) {
|
| 1261 |
+
storage = from_float(float_e5m2_t::to_float(x)).storage;
|
| 1262 |
+
}
|
| 1263 |
+
|
| 1264 |
+
/// float_e5m2_t <= float_e4m3_t
|
| 1265 |
+
CUTLASS_HOST_DEVICE
|
| 1266 |
+
float_e5m2_t::float_e5m2_t(float_e4m3_t x) {
|
| 1267 |
+
storage = from_float(float_e4m3_t::to_float(x)).storage;
|
| 1268 |
+
}
|
| 1269 |
+
|
| 1270 |
+
///////////////////////////////////////////////////////////////
|
| 1271 |
+
///
|
| 1272 |
+
/// Umbrella floating-point 8-bit data type : type_erased_dynamic_float8_t
|
| 1273 |
+
/// This umbrella datatype can be enabled when a user provides a specific
|
| 1274 |
+
/// datatype in runtime argument list.
|
| 1275 |
+
///
|
| 1276 |
+
/// Currently supported runtime datatypes compatible with type_erased_dynamic_float8_t:
|
| 1277 |
+
/// MXF8F6F4Format::E5M2
|
| 1278 |
+
/// MXF8F6F4Format::E4M3
|
| 1279 |
+
///
|
| 1280 |
+
///////////////////////////////////////////////////////////////
|
| 1281 |
+
|
| 1282 |
+
union type_erased_dynamic_float8_t {
|
| 1283 |
+
uint8_t data;
|
| 1284 |
+
cutlass::float_e5m2_t e5m2;
|
| 1285 |
+
cutlass::float_e4m3_t e4m3;
|
| 1286 |
+
CUTLASS_HOST_DEVICE
|
| 1287 |
+
explicit operator cutlass::float_e5m2_t() const {
|
| 1288 |
+
return e5m2;
|
| 1289 |
+
}
|
| 1290 |
+
|
| 1291 |
+
CUTLASS_HOST_DEVICE
|
| 1292 |
+
explicit operator cutlass::float_e4m3_t() const {
|
| 1293 |
+
return e4m3;
|
| 1294 |
+
}
|
| 1295 |
+
|
| 1296 |
+
};
|
| 1297 |
+
|
| 1298 |
+
|
| 1299 |
+
|
| 1300 |
+
///////////////////////////////////////////////////////////////
|
| 1301 |
+
/// MX type for float8
|
| 1302 |
+
/// Intended to be used in builders
|
| 1303 |
+
///////////////////////////////////////////////////////////////
|
| 1304 |
+
|
| 1305 |
+
template <class F8Type>
|
| 1306 |
+
struct mx_float8_t {
|
| 1307 |
+
static_assert(cute::is_same_v<F8Type,cutlass::float_e5m2_t>
|
| 1308 |
+
|| cute::is_same_v<F8Type,cutlass::float_e4m3_t>
|
| 1309 |
+
|| cute::is_same_v<F8Type,type_erased_dynamic_float8_t>
|
| 1310 |
+
, "Only float_e5m2_t, float_e4m3_t can have scale factors for MXFP8");
|
| 1311 |
+
using ScaleFactorType = cutlass::float_ue8m0_t;
|
| 1312 |
+
using DataType = F8Type;
|
| 1313 |
+
};
|
| 1314 |
+
|
| 1315 |
+
using type_erased_dynamic_mx_float8_t = mx_float8_t<type_erased_dynamic_float8_t>;
|
| 1316 |
+
|
| 1317 |
+
|
| 1318 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1319 |
+
|
| 1320 |
+
} // namespace cutlass
|
| 1321 |
+
|
| 1322 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1323 |
+
//
|
| 1324 |
+
// Standard Library operations and definitions
|
| 1325 |
+
//
|
| 1326 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1327 |
+
|
| 1328 |
+
#if !defined(__CUDACC_RTC__)
|
| 1329 |
+
namespace std {
|
| 1330 |
+
|
| 1331 |
+
/// Numeric limits common to all float8 types
|
| 1332 |
+
template <typename T>
|
| 1333 |
+
struct float8_base_numeric_limits {
|
| 1334 |
+
private:
|
| 1335 |
+
using F8Type = T;
|
| 1336 |
+
public:
|
| 1337 |
+
static bool const is_specialized = true;
|
| 1338 |
+
static bool const is_signed = true;
|
| 1339 |
+
static bool const is_integer = false;
|
| 1340 |
+
static bool const is_exact = false;
|
| 1341 |
+
static bool const has_quiet_NaN = true;
|
| 1342 |
+
static bool const has_signaling_NaN = false;
|
| 1343 |
+
static std::float_denorm_style const has_denorm = std::denorm_present;
|
| 1344 |
+
static bool const has_denorm_loss = true;
|
| 1345 |
+
static std::float_round_style const round_style = std::round_to_nearest;
|
| 1346 |
+
static bool const is_iec559 = false;
|
| 1347 |
+
static bool const is_bounded = true;
|
| 1348 |
+
static bool const is_modulo = false;
|
| 1349 |
+
static int const digits = F8Type::FP8_NUM_MANTISSA_BITS;
|
| 1350 |
+
|
| 1351 |
+
/// Least positive value
|
| 1352 |
+
CUTLASS_HOST_DEVICE
|
| 1353 |
+
static F8Type min() { return F8Type::bitcast(0x01); }
|
| 1354 |
+
|
| 1355 |
+
/// Maximum finite value
|
| 1356 |
+
CUTLASS_HOST_DEVICE
|
| 1357 |
+
static F8Type max() { return F8Type::bitcast(F8Type::FP8_MAX_FLT); }
|
| 1358 |
+
|
| 1359 |
+
/// Returns maximum rounding error
|
| 1360 |
+
CUTLASS_HOST_DEVICE
|
| 1361 |
+
static F8Type round_error() { return F8Type(0.5f); }
|
| 1362 |
+
|
| 1363 |
+
/// Returns positive infinity value
|
| 1364 |
+
CUTLASS_HOST_DEVICE
|
| 1365 |
+
static F8Type infinity() { return F8Type::bitcast(F8Type::FP8_INFINITY_MASK); }
|
| 1366 |
+
|
| 1367 |
+
/// Returns quiet NaN value
|
| 1368 |
+
CUTLASS_HOST_DEVICE
|
| 1369 |
+
static F8Type quiet_NaN() { return F8Type::bitcast(F8Type::FP8_NAN); }
|
| 1370 |
+
|
| 1371 |
+
/// Returns signaling NaN value
|
| 1372 |
+
CUTLASS_HOST_DEVICE
|
| 1373 |
+
static F8Type signaling_NaN() { return F8Type::bitcast(F8Type::FP8_NAN); }
|
| 1374 |
+
|
| 1375 |
+
/// Returns smallest positive subnormal value
|
| 1376 |
+
CUTLASS_HOST_DEVICE
|
| 1377 |
+
static F8Type denorm_min() { return F8Type::bitcast(0x01); }
|
| 1378 |
+
};
|
| 1379 |
+
|
| 1380 |
+
/// Numeric limits for float_e4m3_t
|
| 1381 |
+
template <>
|
| 1382 |
+
struct numeric_limits<cutlass::float_e4m3_t> :
|
| 1383 |
+
public float8_base_numeric_limits<cutlass::float_e4m3_t> {
|
| 1384 |
+
static bool const has_infinity = false;
|
| 1385 |
+
|
| 1386 |
+
/// Minimum finite value
|
| 1387 |
+
static cutlass::float_e4m3_t lowest() { return cutlass::float_e4m3_t::bitcast(0xfe); }
|
| 1388 |
+
|
| 1389 |
+
/// Machine epsilon, that is, the difference between 1.0 and the next representable value
|
| 1390 |
+
static cutlass::float_e4m3_t epsilon() { return cutlass::float_e4m3_t::bitcast(0x20); }
|
| 1391 |
+
};
|
| 1392 |
+
|
| 1393 |
+
/// Numeric limits for float_e5m2_t
|
| 1394 |
+
template <>
|
| 1395 |
+
struct numeric_limits<cutlass::float_e5m2_t> :
|
| 1396 |
+
public float8_base_numeric_limits<cutlass::float_e5m2_t> {
|
| 1397 |
+
static bool const has_infinity = true;
|
| 1398 |
+
|
| 1399 |
+
/// Minimum finite value
|
| 1400 |
+
static cutlass::float_e5m2_t lowest() { return cutlass::float_e5m2_t::bitcast(0xfb); }
|
| 1401 |
+
|
| 1402 |
+
/// Machine epsilon, that is, the difference between 1.0 and the next representable value
|
| 1403 |
+
static cutlass::float_e5m2_t epsilon() { return cutlass::float_e5m2_t::bitcast(0x34); }
|
| 1404 |
+
};
|
| 1405 |
+
|
| 1406 |
+
|
| 1407 |
+
template <typename T>
|
| 1408 |
+
struct float8_exmy_numeric_limits
|
| 1409 |
+
{
|
| 1410 |
+
private:
|
| 1411 |
+
using type = T;
|
| 1412 |
+
|
| 1413 |
+
public:
|
| 1414 |
+
static bool const is_specialized = true;
|
| 1415 |
+
static bool const is_signed = true;
|
| 1416 |
+
static bool const is_integer = false;
|
| 1417 |
+
static bool const is_exact = false;
|
| 1418 |
+
static bool const has_quiet_NaN = true;
|
| 1419 |
+
static bool const has_signaling_NaN = false;
|
| 1420 |
+
static bool const has_denorm_loss = true;
|
| 1421 |
+
static cutlass::platform::float_denorm_style const has_denorm = cutlass::platform::denorm_present;
|
| 1422 |
+
static cutlass::platform::float_round_style const round_style = cutlass::platform::round_to_nearest;
|
| 1423 |
+
static bool const is_iec559 = false;
|
| 1424 |
+
static bool const is_bounded = true;
|
| 1425 |
+
static bool const is_modulo = false;
|
| 1426 |
+
static int const digits = type::Base::BitRepresentation::NUM_MANTISSA_BITS;
|
| 1427 |
+
static bool const has_infinity = false;
|
| 1428 |
+
|
| 1429 |
+
/// Least positive value
|
| 1430 |
+
CUTLASS_HOST_DEVICE
|
| 1431 |
+
static type min() { return type::bitcast(0x01); }
|
| 1432 |
+
|
| 1433 |
+
/// Maximum finite value
|
| 1434 |
+
CUTLASS_HOST_DEVICE
|
| 1435 |
+
static type max() { return type::bitcast(type::Base::BitRepresentation::MAX_VALUE); }
|
| 1436 |
+
|
| 1437 |
+
/// Returns maximum rounding error
|
| 1438 |
+
CUTLASS_HOST_DEVICE
|
| 1439 |
+
static type round_error() { return type(0.5f); }
|
| 1440 |
+
|
| 1441 |
+
/// Returns positive infinity value
|
| 1442 |
+
CUTLASS_HOST_DEVICE
|
| 1443 |
+
static type infinity() { return type::bitcast(type::Base::BitRepresentation::INF_MASK); }
|
| 1444 |
+
|
| 1445 |
+
/// Returns quiet NaN value
|
| 1446 |
+
CUTLASS_HOST_DEVICE
|
| 1447 |
+
static type quiet_NaN() { return type::bitcast(type::Base::BitRepresentation::INF_MASK); }
|
| 1448 |
+
|
| 1449 |
+
/// Returns signaling NaN value
|
| 1450 |
+
CUTLASS_HOST_DEVICE
|
| 1451 |
+
static type signaling_NaN() { return type::bitcast(type::Base::BitRepresentation::INF_MASK); }
|
| 1452 |
+
|
| 1453 |
+
/// Returns smallest positive subnormal value
|
| 1454 |
+
CUTLASS_HOST_DEVICE
|
| 1455 |
+
static type denorm_min() { return type::bitcast(0x01); }
|
| 1456 |
+
};
|
| 1457 |
+
|
| 1458 |
+
/// Numeric limits for float_ue8m0_t
|
| 1459 |
+
template <>
|
| 1460 |
+
struct numeric_limits<cutlass::float_ue8m0_t> :
|
| 1461 |
+
public float8_exmy_numeric_limits<cutlass::float_ue8m0_t> {
|
| 1462 |
+
static bool const has_infinity = false;
|
| 1463 |
+
static bool const is_signed = false;
|
| 1464 |
+
|
| 1465 |
+
/// Minimum finite value
|
| 1466 |
+
static cutlass::float_ue8m0_t lowest() { return cutlass::float_ue8m0_t::bitcast(0xfe); }
|
| 1467 |
+
|
| 1468 |
+
/// Machine epsilon, that is, the difference between 1.0 and the next representable value (2^0)
|
| 1469 |
+
static cutlass::float_ue8m0_t epsilon() { return cutlass::float_ue8m0_t::bitcast(0x7f); }
|
| 1470 |
+
};
|
| 1471 |
+
|
| 1472 |
+
|
| 1473 |
+
} // namespace std
|
| 1474 |
+
#endif
|
| 1475 |
+
|
| 1476 |
+
namespace cutlass {
|
| 1477 |
+
namespace platform {
|
| 1478 |
+
|
| 1479 |
+
/// Numeric limits common to all float8 types
|
| 1480 |
+
template <typename T>
|
| 1481 |
+
struct float8_base_numeric_limits {
|
| 1482 |
+
private:
|
| 1483 |
+
using F8Type = T;
|
| 1484 |
+
public:
|
| 1485 |
+
static bool const is_specialized = true;
|
| 1486 |
+
static bool const is_signed = true;
|
| 1487 |
+
static bool const is_integer = false;
|
| 1488 |
+
static bool const is_exact = false;
|
| 1489 |
+
static bool const has_quiet_NaN = true;
|
| 1490 |
+
static bool const has_signaling_NaN = false;
|
| 1491 |
+
#if !defined(__CUDACC_RTC__)
|
| 1492 |
+
static std::float_denorm_style const has_denorm = std::denorm_present;
|
| 1493 |
+
#endif
|
| 1494 |
+
static bool const has_denorm_loss = true;
|
| 1495 |
+
#if !defined(__CUDACC_RTC__)
|
| 1496 |
+
static std::float_round_style const round_style = std::round_to_nearest;
|
| 1497 |
+
#endif
|
| 1498 |
+
static bool const is_iec559 = false;
|
| 1499 |
+
static bool const is_bounded = true;
|
| 1500 |
+
static bool const is_modulo = false;
|
| 1501 |
+
static int const digits = F8Type::FP8_NUM_MANTISSA_BITS;
|
| 1502 |
+
|
| 1503 |
+
/// Least positive value
|
| 1504 |
+
CUTLASS_HOST_DEVICE
|
| 1505 |
+
static F8Type min() { return F8Type::bitcast(0x01); }
|
| 1506 |
+
|
| 1507 |
+
/// Maximum finite value
|
| 1508 |
+
CUTLASS_HOST_DEVICE
|
| 1509 |
+
static F8Type max() { return F8Type::bitcast(F8Type::FP8_MAX_FLT); }
|
| 1510 |
+
|
| 1511 |
+
/// Returns maximum rounding error
|
| 1512 |
+
CUTLASS_HOST_DEVICE
|
| 1513 |
+
static F8Type round_error() { return F8Type(0.5f); }
|
| 1514 |
+
|
| 1515 |
+
/// Returns positive infinity value
|
| 1516 |
+
CUTLASS_HOST_DEVICE
|
| 1517 |
+
static F8Type infinity() { return F8Type::bitcast(F8Type::FP8_INFINITY_MASK); }
|
| 1518 |
+
|
| 1519 |
+
/// Returns quiet NaN value
|
| 1520 |
+
CUTLASS_HOST_DEVICE
|
| 1521 |
+
static F8Type quiet_NaN() { return F8Type::bitcast(F8Type::FP8_NAN); }
|
| 1522 |
+
|
| 1523 |
+
/// Returns signaling NaN value
|
| 1524 |
+
CUTLASS_HOST_DEVICE
|
| 1525 |
+
static F8Type signaling_NaN() { return F8Type::bitcast(F8Type::FP8_NAN); }
|
| 1526 |
+
|
| 1527 |
+
/// Returns smallest positive subnormal value
|
| 1528 |
+
CUTLASS_HOST_DEVICE
|
| 1529 |
+
static F8Type denorm_min() { return F8Type::bitcast(0x01); }
|
| 1530 |
+
};
|
| 1531 |
+
|
| 1532 |
+
/// Forward Declaration
|
| 1533 |
+
template <class T>
|
| 1534 |
+
struct numeric_limits;
|
| 1535 |
+
|
| 1536 |
+
/// Numeric limits for float_e4m3_t
|
| 1537 |
+
template <>
|
| 1538 |
+
struct numeric_limits<cutlass::float_e4m3_t> :
|
| 1539 |
+
public float8_base_numeric_limits<cutlass::float_e4m3_t> {
|
| 1540 |
+
static bool const has_infinity = false;
|
| 1541 |
+
|
| 1542 |
+
/// Minimum finite value
|
| 1543 |
+
static cutlass::float_e4m3_t lowest() { return cutlass::float_e4m3_t::bitcast(0xfe); }
|
| 1544 |
+
|
| 1545 |
+
/// Machine epsilon, that is, the difference between 1.0 and the next representable value
|
| 1546 |
+
static cutlass::float_e4m3_t epsilon() { return cutlass::float_e4m3_t::bitcast(0x20); }
|
| 1547 |
+
};
|
| 1548 |
+
|
| 1549 |
+
/// Numeric limits for float_e5m2_t
|
| 1550 |
+
template <>
|
| 1551 |
+
struct numeric_limits<cutlass::float_e5m2_t> :
|
| 1552 |
+
public float8_base_numeric_limits<cutlass::float_e5m2_t> {
|
| 1553 |
+
static bool const has_infinity = true;
|
| 1554 |
+
|
| 1555 |
+
/// Minimum finite value
|
| 1556 |
+
static cutlass::float_e5m2_t lowest() { return cutlass::float_e5m2_t::bitcast(0xfb); }
|
| 1557 |
+
|
| 1558 |
+
/// Machine epsilon, that is, the difference between 1.0 and the next representable value
|
| 1559 |
+
static cutlass::float_e5m2_t epsilon() { return cutlass::float_e5m2_t::bitcast(0x34); }
|
| 1560 |
+
};
|
| 1561 |
+
|
| 1562 |
+
|
| 1563 |
+
template <typename T>
|
| 1564 |
+
struct float8_exmy_numeric_limits
|
| 1565 |
+
{
|
| 1566 |
+
private:
|
| 1567 |
+
using type = T;
|
| 1568 |
+
|
| 1569 |
+
public:
|
| 1570 |
+
static bool const is_specialized = true;
|
| 1571 |
+
static bool const is_signed = true;
|
| 1572 |
+
static bool const is_integer = false;
|
| 1573 |
+
static bool const is_exact = false;
|
| 1574 |
+
static bool const has_quiet_NaN = true;
|
| 1575 |
+
static bool const has_signaling_NaN = false;
|
| 1576 |
+
static bool const has_denorm_loss = true;
|
| 1577 |
+
static cutlass::platform::float_denorm_style const has_denorm = cutlass::platform::denorm_present;
|
| 1578 |
+
static cutlass::platform::float_round_style const round_style = cutlass::platform::round_to_nearest;
|
| 1579 |
+
static bool const is_iec559 = false;
|
| 1580 |
+
static bool const is_bounded = true;
|
| 1581 |
+
static bool const is_modulo = false;
|
| 1582 |
+
static int const digits = type::Base::BitRepresentation::NUM_MANTISSA_BITS;
|
| 1583 |
+
static bool const has_infinity = false;
|
| 1584 |
+
|
| 1585 |
+
/// Least positive value
|
| 1586 |
+
CUTLASS_HOST_DEVICE
|
| 1587 |
+
static type min() { return type::bitcast(0x01); }
|
| 1588 |
+
|
| 1589 |
+
/// Maximum finite value
|
| 1590 |
+
CUTLASS_HOST_DEVICE
|
| 1591 |
+
static type max() { return type::bitcast(type::Base::BitRepresentation::MAX_VALUE); }
|
| 1592 |
+
|
| 1593 |
+
/// Returns maximum rounding error
|
| 1594 |
+
CUTLASS_HOST_DEVICE
|
| 1595 |
+
static type round_error() { return type(0.5f); }
|
| 1596 |
+
|
| 1597 |
+
/// Returns positive infinity value
|
| 1598 |
+
CUTLASS_HOST_DEVICE
|
| 1599 |
+
static type infinity() { return type::bitcast(type::Base::BitRepresentation::INF_MASK); }
|
| 1600 |
+
|
| 1601 |
+
/// Returns quiet NaN value
|
| 1602 |
+
CUTLASS_HOST_DEVICE
|
| 1603 |
+
static type quiet_NaN() { return type::bitcast(type::Base::BitRepresentation::INF_MASK); }
|
| 1604 |
+
|
| 1605 |
+
/// Returns signaling NaN value
|
| 1606 |
+
CUTLASS_HOST_DEVICE
|
| 1607 |
+
static type signaling_NaN() { return type::bitcast(type::Base::BitRepresentation::INF_MASK); }
|
| 1608 |
+
|
| 1609 |
+
/// Returns smallest positive subnormal value
|
| 1610 |
+
CUTLASS_HOST_DEVICE
|
| 1611 |
+
static type denorm_min() { return type::bitcast(0x01); }
|
| 1612 |
+
};
|
| 1613 |
+
|
| 1614 |
+
/// Numeric limits for float_ue8m0_t
|
| 1615 |
+
template <>
|
| 1616 |
+
struct numeric_limits<cutlass::float_ue8m0_t> :
|
| 1617 |
+
public float8_exmy_numeric_limits<cutlass::float_ue8m0_t> {
|
| 1618 |
+
static bool const has_infinity = false;
|
| 1619 |
+
static bool const is_signed = false;
|
| 1620 |
+
|
| 1621 |
+
/// Minimum finite value
|
| 1622 |
+
static cutlass::float_ue8m0_t lowest() { return cutlass::float_ue8m0_t::bitcast(0xfe); }
|
| 1623 |
+
|
| 1624 |
+
/// Machine epsilon, that is, the difference between 1.0 and the next representable value (2^0)
|
| 1625 |
+
static cutlass::float_ue8m0_t epsilon() { return cutlass::float_ue8m0_t::bitcast(0x7f); }
|
| 1626 |
+
};
|
| 1627 |
+
|
| 1628 |
+
|
| 1629 |
+
} // namespace platform
|
| 1630 |
+
|
| 1631 |
+
} // namespace cutlass
|
| 1632 |
+
|
| 1633 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1634 |
+
|
| 1635 |
+
//
|
| 1636 |
+
// User-defined literals
|
| 1637 |
+
//
|
| 1638 |
+
|
| 1639 |
+
CUTLASS_HOST_DEVICE
|
| 1640 |
+
cutlass::float_e4m3_t operator "" _fe4m3(long double x) {
|
| 1641 |
+
return cutlass::float_e4m3_t(float(x));
|
| 1642 |
+
}
|
| 1643 |
+
|
| 1644 |
+
CUTLASS_HOST_DEVICE
|
| 1645 |
+
cutlass::float_e4m3_t operator "" _fe4m3(unsigned long long int x) {
|
| 1646 |
+
return cutlass::float_e4m3_t(int(x));
|
| 1647 |
+
}
|
| 1648 |
+
|
| 1649 |
+
|
| 1650 |
+
CUTLASS_HOST_DEVICE
|
| 1651 |
+
cutlass::float_ue4m3_t operator "" _fue4m3(long double x) {
|
| 1652 |
+
return cutlass::float_ue4m3_t(float(x));
|
| 1653 |
+
}
|
| 1654 |
+
|
| 1655 |
+
CUTLASS_HOST_DEVICE
|
| 1656 |
+
cutlass::float_ue4m3_t operator "" _fue4m3(unsigned long long int x) {
|
| 1657 |
+
return cutlass::float_ue4m3_t(int(x));
|
| 1658 |
+
}
|
| 1659 |
+
|
| 1660 |
+
|
| 1661 |
+
CUTLASS_HOST_DEVICE
|
| 1662 |
+
cutlass::float_e5m2_t operator "" _fe5m2(long double x) {
|
| 1663 |
+
return cutlass::float_e5m2_t(float(x));
|
| 1664 |
+
}
|
| 1665 |
+
|
| 1666 |
+
CUTLASS_HOST_DEVICE
|
| 1667 |
+
cutlass::float_e5m2_t operator "" _fe5m2(unsigned long long int x) {
|
| 1668 |
+
return cutlass::float_e5m2_t(int(x));
|
| 1669 |
+
}
|
| 1670 |
+
|
| 1671 |
+
|
| 1672 |
+
CUTLASS_HOST_DEVICE
|
| 1673 |
+
cutlass::float_ue8m0_t operator "" _fue8m0(long double x)
|
| 1674 |
+
{
|
| 1675 |
+
return cutlass::float_ue8m0_t(float(x));
|
| 1676 |
+
}
|
| 1677 |
+
|
| 1678 |
+
CUTLASS_HOST_DEVICE
|
| 1679 |
+
cutlass::float_ue8m0_t operator "" _fue8m0(unsigned long long int x)
|
| 1680 |
+
{
|
| 1681 |
+
return cutlass::float_ue8m0_t(int(x));
|
| 1682 |
+
}
|
| 1683 |
+
|
| 1684 |
+
|
| 1685 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/float_subbyte.h
ADDED
|
@@ -0,0 +1,797 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
\file
|
| 35 |
+
\brief Defines classes for FP4/FP6 datatypes
|
| 36 |
+
*/
|
| 37 |
+
#pragma once
|
| 38 |
+
|
| 39 |
+
#include "cutlass/arch/config.h"
|
| 40 |
+
#include "cutlass/float8.h"
|
| 41 |
+
|
| 42 |
+
// FP4 types are available starting CUDA 12+
|
| 43 |
+
#if (__CUDACC_VER_MAJOR__ >= 12)
|
| 44 |
+
#define CUDA_FP4_ENABLED 1
|
| 45 |
+
#endif
|
| 46 |
+
|
| 47 |
+
#if (defined(CUTLASS_ARCH_MMA_SM100A_ENABLED) || defined(CUTLASS_ARCH_MMA_SM101A_ENABLED) ||\
|
| 48 |
+
defined(CUTLASS_ARCH_MMA_SM103A_ENABLED) || defined(CUTLASS_ARCH_MMA_SM110A_ENABLED) ||\
|
| 49 |
+
defined(CUTLASS_ARCH_MMA_SM120A_ENABLED) || defined(CUTLASS_ARCH_MMA_SM121A_ENABLED))
|
| 50 |
+
# define CUDA_PTX_FP4FP6_CVT_ENABLED 1
|
| 51 |
+
#endif
|
| 52 |
+
|
| 53 |
+
#if (defined(CUTLASS_ARCH_MMA_SM100F_ENABLED) || defined(CUTLASS_ARCH_MMA_SM101F_ENABLED) ||\
|
| 54 |
+
defined(CUTLASS_ARCH_MMA_SM103F_ENABLED) || defined(CUTLASS_ARCH_MMA_SM110F_ENABLED) ||\
|
| 55 |
+
defined(CUTLASS_ARCH_MMA_SM120F_ENABLED) || defined(CUTLASS_ARCH_MMA_SM121F_ENABLED))
|
| 56 |
+
# define CUDA_PTX_FP4FP6_CVT_ENABLED 1
|
| 57 |
+
#endif
|
| 58 |
+
|
| 59 |
+
#include "cutlass/cutlass.h"
|
| 60 |
+
#include "cutlass/exmy_base.h"
|
| 61 |
+
|
| 62 |
+
#include "cute/util/type_traits.hpp"
|
| 63 |
+
|
| 64 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 65 |
+
|
| 66 |
+
namespace cutlass {
|
| 67 |
+
|
| 68 |
+
// FP4 and FP6 types
|
| 69 |
+
struct float_e2m1_t;
|
| 70 |
+
struct float_e3m2_t;
|
| 71 |
+
// E2M1:
|
| 72 |
+
// 2 Exponent bits with 1 Mantissa bit
|
| 73 |
+
// Range: +-[0,0.5,1,1.5,2,3,4,5,6]
|
| 74 |
+
// has_Inf: false
|
| 75 |
+
// has_NaN: false
|
| 76 |
+
// has_denorm: true
|
| 77 |
+
// Exponent bias (exp_bias): 1
|
| 78 |
+
|
| 79 |
+
struct float_e2m1_t : public float_exmy_base<cutlass::detail::FpEncoding::E2M1, float_e2m1_t> {
|
| 80 |
+
|
| 81 |
+
using Base = float_exmy_base<cutlass::detail::FpEncoding::E2M1, float_e2m1_t>;
|
| 82 |
+
|
| 83 |
+
float_e2m1_t() = default;
|
| 84 |
+
|
| 85 |
+
CUTLASS_HOST_DEVICE
|
| 86 |
+
explicit float_e2m1_t(double x) : Base(float(x)) {
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
CUTLASS_HOST_DEVICE
|
| 90 |
+
explicit float_e2m1_t(float x) : Base(x) {
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
CUTLASS_HOST_DEVICE
|
| 94 |
+
explicit float_e2m1_t(int x) : Base(x) {
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
CUTLASS_HOST_DEVICE
|
| 98 |
+
float_e2m1_t(Base x) : Base(x) {
|
| 99 |
+
}
|
| 100 |
+
};
|
| 101 |
+
|
| 102 |
+
namespace detail {
|
| 103 |
+
|
| 104 |
+
// This new type is used to select correct MMA type and TMA type.
|
| 105 |
+
struct float_e2m1_unpacksmem_t : public float_exmy_base<cutlass::detail::FpEncoding::E2M1, float_e2m1_t> {
|
| 106 |
+
|
| 107 |
+
using Base = float_exmy_base<cutlass::detail::FpEncoding::E2M1, float_e2m1_t>;
|
| 108 |
+
|
| 109 |
+
float_e2m1_unpacksmem_t() = default;
|
| 110 |
+
|
| 111 |
+
CUTLASS_HOST_DEVICE
|
| 112 |
+
float_e2m1_unpacksmem_t(float_e2m1_unpacksmem_t const& x) : Base(x) {
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
CUTLASS_HOST_DEVICE
|
| 116 |
+
explicit float_e2m1_unpacksmem_t(double x) : Base(float(x)) {
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
CUTLASS_HOST_DEVICE
|
| 120 |
+
explicit float_e2m1_unpacksmem_t(float x) : Base(x) {
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
CUTLASS_HOST_DEVICE
|
| 124 |
+
explicit float_e2m1_unpacksmem_t(int x) : Base(x) {
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
CUTLASS_HOST_DEVICE
|
| 128 |
+
float_e2m1_unpacksmem_t(Base x) : Base(x) {
|
| 129 |
+
}
|
| 130 |
+
};
|
| 131 |
+
|
| 132 |
+
} // namespace detail
|
| 133 |
+
|
| 134 |
+
/// Defines the size of an element in bits - specialized for float_e2m1_t
|
| 135 |
+
template <>
|
| 136 |
+
struct sizeof_bits<float_e2m1_t> {
|
| 137 |
+
static constexpr int value = 4;
|
| 138 |
+
};
|
| 139 |
+
|
| 140 |
+
template <>
|
| 141 |
+
struct sizeof_bits<detail::float_e2m1_unpacksmem_t> {
|
| 142 |
+
static constexpr int value = 4;
|
| 143 |
+
};
|
| 144 |
+
|
| 145 |
+
CUTLASS_HOST_DEVICE
|
| 146 |
+
float_e2m1_t abs(float_e2m1_t const& val) {
|
| 147 |
+
using BaseType = typename float_e2m1_t::Base;
|
| 148 |
+
return float_e2m1_t(abs(BaseType{val.raw()}));
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
// E2M3:
|
| 153 |
+
// 2 Exponent bits with 3 Mantissa bit
|
| 154 |
+
// Range: [-7.5,+7.5]
|
| 155 |
+
// has_Inf: false
|
| 156 |
+
// has_NaN: false
|
| 157 |
+
// has_denorm: true
|
| 158 |
+
// Exponent bias (exp_bias): 1
|
| 159 |
+
|
| 160 |
+
struct float_e2m3_t : public float_exmy_base<cutlass::detail::FpEncoding::E2M3, float_e2m3_t> {
|
| 161 |
+
|
| 162 |
+
using Base = float_exmy_base<cutlass::detail::FpEncoding::E2M3, float_e2m3_t>;
|
| 163 |
+
|
| 164 |
+
float_e2m3_t() = default;
|
| 165 |
+
|
| 166 |
+
CUTLASS_HOST_DEVICE
|
| 167 |
+
explicit float_e2m3_t(double x) : Base(float(x)) {
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
CUTLASS_HOST_DEVICE
|
| 171 |
+
explicit float_e2m3_t(float x) : Base(x) {
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
CUTLASS_HOST_DEVICE
|
| 175 |
+
explicit float_e2m3_t(int x) : Base(x) {
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
CUTLASS_HOST_DEVICE
|
| 179 |
+
float_e2m3_t(Base x) : Base(x) {
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
CUTLASS_HOST_DEVICE
|
| 183 |
+
explicit float_e2m3_t(float_e3m2_t x);
|
| 184 |
+
};
|
| 185 |
+
|
| 186 |
+
namespace detail {
|
| 187 |
+
|
| 188 |
+
struct float_e2m3_unpack8bits_t: public float_exmy_base<cutlass::detail::FpEncoding::E2M3, float_e2m3_unpack8bits_t> {
|
| 189 |
+
// Used in register.
|
| 190 |
+
using Base = float_exmy_base<cutlass::detail::FpEncoding::E2M3, float_e2m3_unpack8bits_t>;
|
| 191 |
+
|
| 192 |
+
float_e2m3_unpack8bits_t() = default;
|
| 193 |
+
|
| 194 |
+
CUTLASS_HOST_DEVICE
|
| 195 |
+
explicit float_e2m3_unpack8bits_t(double x) : Base(float(x)) {
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
CUTLASS_HOST_DEVICE
|
| 199 |
+
explicit float_e2m3_unpack8bits_t(float x) : Base(x) {
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
CUTLASS_HOST_DEVICE
|
| 203 |
+
explicit float_e2m3_unpack8bits_t(int x) : Base(x) {
|
| 204 |
+
}
|
| 205 |
+
|
| 206 |
+
CUTLASS_HOST_DEVICE
|
| 207 |
+
float_e2m3_unpack8bits_t(Base x) : Base(x) {
|
| 208 |
+
}
|
| 209 |
+
};
|
| 210 |
+
|
| 211 |
+
// This new type is used to select correct MMA type and TMA type.
|
| 212 |
+
struct float_e2m3_unpacksmem_t : public float_exmy_base<cutlass::detail::FpEncoding::E2M3, float_e2m3_t> {
|
| 213 |
+
|
| 214 |
+
using Base = float_exmy_base<cutlass::detail::FpEncoding::E2M3, float_e2m3_t>;
|
| 215 |
+
|
| 216 |
+
float_e2m3_unpacksmem_t() = default;
|
| 217 |
+
|
| 218 |
+
CUTLASS_HOST_DEVICE
|
| 219 |
+
float_e2m3_unpacksmem_t(float_e2m3_unpacksmem_t const& x) : Base(x) {
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
CUTLASS_HOST_DEVICE
|
| 223 |
+
explicit float_e2m3_unpacksmem_t(double x) : Base(float(x)) {
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
CUTLASS_HOST_DEVICE
|
| 227 |
+
explicit float_e2m3_unpacksmem_t(float x) : Base(x) {
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
CUTLASS_HOST_DEVICE
|
| 231 |
+
explicit float_e2m3_unpacksmem_t(int x) : Base(x) {
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
CUTLASS_HOST_DEVICE
|
| 235 |
+
float_e2m3_unpacksmem_t(Base x) : Base(x) {
|
| 236 |
+
}
|
| 237 |
+
};
|
| 238 |
+
|
| 239 |
+
} // namespace detail
|
| 240 |
+
|
| 241 |
+
/// Defines the size of an element in bits - specialized for float_e2m3_t
|
| 242 |
+
template <>
|
| 243 |
+
struct sizeof_bits<float_e2m3_t> {
|
| 244 |
+
static constexpr int value = 6;
|
| 245 |
+
};
|
| 246 |
+
|
| 247 |
+
/// Defines the size of an element in bits - specialized for float_e2m3_unpacksmem_t
|
| 248 |
+
template <>
|
| 249 |
+
struct sizeof_bits<detail::float_e2m3_unpacksmem_t> {
|
| 250 |
+
static constexpr int value = 6;
|
| 251 |
+
};
|
| 252 |
+
|
| 253 |
+
CUTLASS_HOST_DEVICE
|
| 254 |
+
float_e2m3_t abs(float_e2m3_t const& val) {
|
| 255 |
+
using BaseType = typename float_e2m3_t::Base;
|
| 256 |
+
return float_e2m3_t(abs(BaseType{val.raw()}));
|
| 257 |
+
}
|
| 258 |
+
|
| 259 |
+
// E3M2:
|
| 260 |
+
// 3 Exponent bits, 2 Mantissa bits
|
| 261 |
+
// Range: [-28:+28]
|
| 262 |
+
// has_inf: false
|
| 263 |
+
// has_NaN: false
|
| 264 |
+
// has_denorm: true
|
| 265 |
+
// Exponent bias (exp_bias): 3
|
| 266 |
+
|
| 267 |
+
struct float_e3m2_t : public float_exmy_base<cutlass::detail::FpEncoding::E3M2, float_e3m2_t> {
|
| 268 |
+
|
| 269 |
+
using Base = float_exmy_base<cutlass::detail::FpEncoding::E3M2, float_e3m2_t>;
|
| 270 |
+
|
| 271 |
+
float_e3m2_t() = default;
|
| 272 |
+
|
| 273 |
+
CUTLASS_HOST_DEVICE
|
| 274 |
+
explicit float_e3m2_t(double x) : Base(float(x)) {
|
| 275 |
+
}
|
| 276 |
+
|
| 277 |
+
CUTLASS_HOST_DEVICE
|
| 278 |
+
explicit float_e3m2_t(float x) : Base(x) {
|
| 279 |
+
}
|
| 280 |
+
|
| 281 |
+
CUTLASS_HOST_DEVICE
|
| 282 |
+
explicit float_e3m2_t(int x) : Base(x) {
|
| 283 |
+
}
|
| 284 |
+
|
| 285 |
+
CUTLASS_HOST_DEVICE
|
| 286 |
+
float_e3m2_t(Base x) : Base(x) {
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
CUTLASS_HOST_DEVICE
|
| 290 |
+
explicit float_e3m2_t(float_e2m3_t x);
|
| 291 |
+
};
|
| 292 |
+
|
| 293 |
+
namespace detail {
|
| 294 |
+
|
| 295 |
+
struct float_e3m2_unpack8bits_t : public float_exmy_base<cutlass::detail::FpEncoding::E3M2, float_e3m2_unpack8bits_t> {
|
| 296 |
+
|
| 297 |
+
using Base = float_exmy_base<cutlass::detail::FpEncoding::E3M2, float_e3m2_unpack8bits_t>;
|
| 298 |
+
|
| 299 |
+
float_e3m2_unpack8bits_t() = default;
|
| 300 |
+
|
| 301 |
+
CUTLASS_HOST_DEVICE
|
| 302 |
+
explicit float_e3m2_unpack8bits_t(double x) : Base(float(x)) {
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
CUTLASS_HOST_DEVICE
|
| 306 |
+
explicit float_e3m2_unpack8bits_t(float x) : Base(x) {
|
| 307 |
+
}
|
| 308 |
+
|
| 309 |
+
CUTLASS_HOST_DEVICE
|
| 310 |
+
explicit float_e3m2_unpack8bits_t(int x) : Base(x) {
|
| 311 |
+
}
|
| 312 |
+
|
| 313 |
+
CUTLASS_HOST_DEVICE
|
| 314 |
+
float_e3m2_unpack8bits_t(Base x) : Base(x) {
|
| 315 |
+
}
|
| 316 |
+
};
|
| 317 |
+
|
| 318 |
+
// This new type is used to select correct MMA type and TMA type.
|
| 319 |
+
struct float_e3m2_unpacksmem_t : public float_exmy_base<cutlass::detail::FpEncoding::E3M2, float_e3m2_t> {
|
| 320 |
+
|
| 321 |
+
using Base = float_exmy_base<cutlass::detail::FpEncoding::E3M2, float_e3m2_t>;
|
| 322 |
+
|
| 323 |
+
float_e3m2_unpacksmem_t() = default;
|
| 324 |
+
|
| 325 |
+
CUTLASS_HOST_DEVICE
|
| 326 |
+
float_e3m2_unpacksmem_t(float_e3m2_unpacksmem_t const& x) : Base(x) {
|
| 327 |
+
}
|
| 328 |
+
|
| 329 |
+
CUTLASS_HOST_DEVICE
|
| 330 |
+
explicit float_e3m2_unpacksmem_t(double x) : Base(float(x)) {
|
| 331 |
+
}
|
| 332 |
+
|
| 333 |
+
CUTLASS_HOST_DEVICE
|
| 334 |
+
explicit float_e3m2_unpacksmem_t(float x) : Base(x) {
|
| 335 |
+
}
|
| 336 |
+
|
| 337 |
+
CUTLASS_HOST_DEVICE
|
| 338 |
+
explicit float_e3m2_unpacksmem_t(int x) : Base(x) {
|
| 339 |
+
}
|
| 340 |
+
|
| 341 |
+
CUTLASS_HOST_DEVICE
|
| 342 |
+
float_e3m2_unpacksmem_t(Base x) : Base(x) {
|
| 343 |
+
}
|
| 344 |
+
};
|
| 345 |
+
|
| 346 |
+
} // namespace detail
|
| 347 |
+
|
| 348 |
+
/// Defines the size of an element in bits - specialized for float_e3m2_t
|
| 349 |
+
template <>
|
| 350 |
+
struct sizeof_bits<float_e3m2_t> {
|
| 351 |
+
static constexpr int value = 6;
|
| 352 |
+
};
|
| 353 |
+
|
| 354 |
+
/// Defines the size of an element in bits - specialized for float_e3m2_unpacksmem_t
|
| 355 |
+
template <>
|
| 356 |
+
struct sizeof_bits<detail::float_e3m2_unpacksmem_t> {
|
| 357 |
+
static constexpr int value = 6;
|
| 358 |
+
};
|
| 359 |
+
|
| 360 |
+
CUTLASS_HOST_DEVICE
|
| 361 |
+
float_e3m2_t abs(float_e3m2_t const& val) {
|
| 362 |
+
using BaseType = typename float_e3m2_t::Base;
|
| 363 |
+
return float_e3m2_t(abs(BaseType{val.raw()}));
|
| 364 |
+
}
|
| 365 |
+
|
| 366 |
+
/// Defines the size of an element in bits - specialized for float_e3m2_unpack8bits_t
|
| 367 |
+
template <>
|
| 368 |
+
struct sizeof_bits<detail::float_e3m2_unpack8bits_t> {
|
| 369 |
+
static constexpr int value = 8;
|
| 370 |
+
};
|
| 371 |
+
|
| 372 |
+
/// Defines the size of an element in bits - specialized for float_e2m3_unpack8bits_t
|
| 373 |
+
template <>
|
| 374 |
+
struct sizeof_bits<detail::float_e2m3_unpack8bits_t> {
|
| 375 |
+
static constexpr int value = 8;
|
| 376 |
+
};
|
| 377 |
+
|
| 378 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 379 |
+
//
|
| 380 |
+
// Get the register type used in kernel
|
| 381 |
+
//
|
| 382 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 383 |
+
|
| 384 |
+
namespace detail {
|
| 385 |
+
|
| 386 |
+
template<typename T>
|
| 387 |
+
struct get_unpacked_element_type;
|
| 388 |
+
|
| 389 |
+
template <>
|
| 390 |
+
struct get_unpacked_element_type<float_e2m3_t> {
|
| 391 |
+
using type = detail::float_e2m3_unpack8bits_t;
|
| 392 |
+
};
|
| 393 |
+
|
| 394 |
+
template <>
|
| 395 |
+
struct get_unpacked_element_type<float_e3m2_t> {
|
| 396 |
+
using type = detail::float_e3m2_unpack8bits_t;
|
| 397 |
+
};
|
| 398 |
+
} // namespace detail
|
| 399 |
+
// ///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 400 |
+
// //
|
| 401 |
+
// // float_e2m3_t <=> float_e3m2_t conversions
|
| 402 |
+
// //
|
| 403 |
+
// ///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 404 |
+
|
| 405 |
+
CUTLASS_HOST_DEVICE
|
| 406 |
+
float_e2m3_t::float_e2m3_t(float_e3m2_t x)
|
| 407 |
+
{
|
| 408 |
+
storage = convert_from_float(float(x)).storage;
|
| 409 |
+
}
|
| 410 |
+
|
| 411 |
+
CUTLASS_HOST_DEVICE
|
| 412 |
+
float_e3m2_t::float_e3m2_t(float_e2m3_t x)
|
| 413 |
+
{
|
| 414 |
+
storage = convert_from_float(float(x)).storage;
|
| 415 |
+
}
|
| 416 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 417 |
+
|
| 418 |
+
///////////////////////////////////////////////////////////////
|
| 419 |
+
///
|
| 420 |
+
/// Umbrella floating-point 6-bit data type : type_erased_dynamic_float6_t
|
| 421 |
+
/// This umbrella datatype can be enabled when a user provides a specific
|
| 422 |
+
/// datatype in runtime argument list.
|
| 423 |
+
///
|
| 424 |
+
/// Currently supported runtime datatypes compatible with type_erased_dynamic_float6_t:
|
| 425 |
+
/// MXF8F6F4Format::E2M3
|
| 426 |
+
/// MXF8F6F4Format::E3M2
|
| 427 |
+
///
|
| 428 |
+
///////////////////////////////////////////////////////////////
|
| 429 |
+
|
| 430 |
+
union type_erased_dynamic_float6_t {
|
| 431 |
+
cutlass::float_e2m3_t e2m3;
|
| 432 |
+
cutlass::float_e3m2_t e3m2;
|
| 433 |
+
|
| 434 |
+
CUTLASS_HOST_DEVICE
|
| 435 |
+
explicit operator cutlass::float_e2m3_t() const {
|
| 436 |
+
return e2m3;
|
| 437 |
+
}
|
| 438 |
+
|
| 439 |
+
CUTLASS_HOST_DEVICE
|
| 440 |
+
explicit operator cutlass::float_e3m2_t() const {
|
| 441 |
+
return e3m2;
|
| 442 |
+
}
|
| 443 |
+
};
|
| 444 |
+
|
| 445 |
+
template <>
|
| 446 |
+
struct sizeof_bits<type_erased_dynamic_float6_t> {
|
| 447 |
+
static constexpr int value = 6;
|
| 448 |
+
};
|
| 449 |
+
|
| 450 |
+
///////////////////////////////////////////////////////////////
|
| 451 |
+
///
|
| 452 |
+
/// Umbrella floating-point 4-bit data type : type_erased_dynamic_float4_t
|
| 453 |
+
/// This umbrella datatype can be enabled when a user provides a specific
|
| 454 |
+
/// datatype in runtime argument list.
|
| 455 |
+
///
|
| 456 |
+
/// Currently supported runtime datatypes compatible with type_erased_dynamic_float4_t:
|
| 457 |
+
/// MXF8F6F4Format::E2M1
|
| 458 |
+
///
|
| 459 |
+
///////////////////////////////////////////////////////////////
|
| 460 |
+
|
| 461 |
+
union type_erased_dynamic_float4_t {
|
| 462 |
+
cutlass::float_e2m1_t e2m1;
|
| 463 |
+
CUTLASS_HOST_DEVICE
|
| 464 |
+
explicit operator cutlass::float_e2m1_t() const {
|
| 465 |
+
return e2m1;
|
| 466 |
+
}
|
| 467 |
+
};
|
| 468 |
+
|
| 469 |
+
template <>
|
| 470 |
+
struct sizeof_bits<type_erased_dynamic_float4_t> {
|
| 471 |
+
static constexpr int value = 4;
|
| 472 |
+
};
|
| 473 |
+
|
| 474 |
+
|
| 475 |
+
///////////////////////////////////////////////////////////////
|
| 476 |
+
/// MX/NV types for float6 and float4
|
| 477 |
+
/// Intended to be used in builders
|
| 478 |
+
///////////////////////////////////////////////////////////////
|
| 479 |
+
|
| 480 |
+
template <class F6Type>
|
| 481 |
+
struct mx_float6_t
|
| 482 |
+
{
|
| 483 |
+
static_assert(cute::is_same_v<F6Type,cutlass::float_e2m3_t>
|
| 484 |
+
|| cute::is_same_v<F6Type,cutlass::float_e3m2_t>
|
| 485 |
+
|| cute::is_same_v<F6Type,type_erased_dynamic_float6_t>
|
| 486 |
+
, "Only float_e2m3_t, float_e3m2_t can have scale factors for MXFP6");
|
| 487 |
+
using ScaleFactorType = cutlass::float_ue8m0_t;
|
| 488 |
+
using DataType = F6Type;
|
| 489 |
+
};
|
| 490 |
+
|
| 491 |
+
using type_erased_dynamic_mx_float6_t = mx_float6_t<type_erased_dynamic_float6_t>;
|
| 492 |
+
|
| 493 |
+
template <class F4Type>
|
| 494 |
+
struct mx_float4_t
|
| 495 |
+
{
|
| 496 |
+
static_assert(cute::is_same_v<F4Type,cutlass::float_e2m1_t>
|
| 497 |
+
|| cute::is_same_v<F4Type,type_erased_dynamic_float4_t>
|
| 498 |
+
, "Only float_e2m1_t type_erased_dynamic_float4_t can have scale factors for MXFP4");
|
| 499 |
+
using ScaleFactorType = cutlass::float_ue8m0_t;
|
| 500 |
+
using DataType = F4Type;
|
| 501 |
+
};
|
| 502 |
+
|
| 503 |
+
using type_erased_dynamic_mx_float4_t = mx_float4_t<type_erased_dynamic_float4_t>;
|
| 504 |
+
|
| 505 |
+
template <class F4Type>
|
| 506 |
+
struct nv_float4_t
|
| 507 |
+
{
|
| 508 |
+
static_assert(cute::is_same_v<F4Type,cutlass::float_e2m1_t>
|
| 509 |
+
|| cute::is_same_v<F4Type,type_erased_dynamic_float4_t>
|
| 510 |
+
, "Only float_e2m1_t type_erased_dynamic_float4_t can have scale factors for NVFP4");
|
| 511 |
+
using ScaleFactorType = cutlass::float_ue4m3_t;
|
| 512 |
+
using DataType = F4Type;
|
| 513 |
+
};
|
| 514 |
+
|
| 515 |
+
using type_erased_dynamic_nv_float4_t = nv_float4_t<type_erased_dynamic_float4_t>;
|
| 516 |
+
|
| 517 |
+
|
| 518 |
+
namespace detail {
|
| 519 |
+
|
| 520 |
+
union type_erased_dynamic_float6_unpacksmem_t {
|
| 521 |
+
cutlass::detail::float_e2m3_unpacksmem_t e2m3_unpacksmem;
|
| 522 |
+
cutlass::detail::float_e3m2_unpacksmem_t e3m2_unpacksmem;
|
| 523 |
+
|
| 524 |
+
CUTLASS_HOST_DEVICE
|
| 525 |
+
explicit operator cutlass::detail::float_e2m3_unpacksmem_t() const {
|
| 526 |
+
return e2m3_unpacksmem;
|
| 527 |
+
}
|
| 528 |
+
|
| 529 |
+
CUTLASS_HOST_DEVICE
|
| 530 |
+
explicit operator cutlass::detail::float_e3m2_unpacksmem_t() const {
|
| 531 |
+
return e3m2_unpacksmem;
|
| 532 |
+
}
|
| 533 |
+
};
|
| 534 |
+
|
| 535 |
+
union type_erased_dynamic_float4_unpacksmem_t {
|
| 536 |
+
cutlass::detail::float_e2m1_unpacksmem_t e2m1_unpacksmem;
|
| 537 |
+
|
| 538 |
+
CUTLASS_HOST_DEVICE
|
| 539 |
+
explicit operator cutlass::detail::float_e2m1_unpacksmem_t() const {
|
| 540 |
+
return e2m1_unpacksmem;
|
| 541 |
+
}
|
| 542 |
+
};
|
| 543 |
+
|
| 544 |
+
};
|
| 545 |
+
|
| 546 |
+
template <>
|
| 547 |
+
struct sizeof_bits<detail::type_erased_dynamic_float6_unpacksmem_t> {
|
| 548 |
+
static constexpr int value = 6;
|
| 549 |
+
};
|
| 550 |
+
|
| 551 |
+
|
| 552 |
+
template <>
|
| 553 |
+
struct sizeof_bits<detail::type_erased_dynamic_float4_unpacksmem_t> {
|
| 554 |
+
static constexpr int value = 4;
|
| 555 |
+
};
|
| 556 |
+
|
| 557 |
+
} // namespace cutlass
|
| 558 |
+
|
| 559 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 560 |
+
//
|
| 561 |
+
// Standard Library operations and definitions
|
| 562 |
+
//
|
| 563 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 564 |
+
#if !defined(__CUDACC_RTC__)
|
| 565 |
+
namespace std {
|
| 566 |
+
/// Numeric limits common to all float4 types
|
| 567 |
+
template <typename T>
|
| 568 |
+
struct float_subbyte_base_numeric_limits
|
| 569 |
+
{
|
| 570 |
+
private:
|
| 571 |
+
using type = T;
|
| 572 |
+
|
| 573 |
+
public:
|
| 574 |
+
static bool const is_specialized = true;
|
| 575 |
+
static bool const is_signed = true;
|
| 576 |
+
static bool const is_integer = false;
|
| 577 |
+
static bool const is_exact = false;
|
| 578 |
+
static bool const has_quiet_NaN = false;
|
| 579 |
+
static bool const has_signaling_NaN = false;
|
| 580 |
+
static bool const has_denorm_loss = true;
|
| 581 |
+
static cutlass::platform::float_denorm_style const has_denorm = cutlass::platform::denorm_present;
|
| 582 |
+
static cutlass::platform::float_round_style const round_style = cutlass::platform::round_to_nearest;
|
| 583 |
+
static bool const is_iec559 = false;
|
| 584 |
+
static bool const is_bounded = true;
|
| 585 |
+
static bool const is_modulo = false;
|
| 586 |
+
static int const digits = type::Base::BitRepresentation::NUM_MANTISSA_BITS;
|
| 587 |
+
static bool const has_infinity = false;
|
| 588 |
+
|
| 589 |
+
/// Least positive value
|
| 590 |
+
static type min() { return type::bitcast(0x01); }
|
| 591 |
+
|
| 592 |
+
/// Maximum finite value
|
| 593 |
+
static type max() { return type::bitcast(type::Base::BitRepresentation::MAX_VALUE); }
|
| 594 |
+
|
| 595 |
+
/// Returns maximum rounding error
|
| 596 |
+
static type round_error() { return type(0.5f); }
|
| 597 |
+
|
| 598 |
+
/// Returns positive infinity value
|
| 599 |
+
static type infinity() { return type::bitcast(type::Base::BitRepresentation::INF_MASK); }
|
| 600 |
+
|
| 601 |
+
/// Returns quiet NaN value
|
| 602 |
+
static type quiet_NaN() { return type::bitcast(type::Base::BitRepresentation::INF_MASK); }
|
| 603 |
+
|
| 604 |
+
/// Returns signaling NaN value
|
| 605 |
+
static type signaling_NaN() { return type::bitcast(type::Base::BitRepresentation::INF_MASK); }
|
| 606 |
+
|
| 607 |
+
/// Returns smallest positive subnormal value
|
| 608 |
+
static type denorm_min() { return type::bitcast(0x01); }
|
| 609 |
+
};
|
| 610 |
+
/// Numeric limits for float_e2m1_t
|
| 611 |
+
template <>
|
| 612 |
+
struct numeric_limits<cutlass::float_e2m1_t> : public float_subbyte_base_numeric_limits<cutlass::float_e2m1_t>
|
| 613 |
+
{
|
| 614 |
+
/// Minimum finite value
|
| 615 |
+
static cutlass::float_e2m1_t lowest() { return cutlass::float_e2m1_t::bitcast(0xf); }
|
| 616 |
+
|
| 617 |
+
/// Returns machine epsilon, that is, the difference between 1.0 and the next value representable by the floating-point
|
| 618 |
+
static cutlass::float_e2m1_t epsilon() { return cutlass::float_e2m1_t::bitcast(0x1); }
|
| 619 |
+
};
|
| 620 |
+
|
| 621 |
+
/// Numeric limits for float_e2m3_t
|
| 622 |
+
template <>
|
| 623 |
+
struct numeric_limits<cutlass::float_e2m3_t> : public float_subbyte_base_numeric_limits<cutlass::float_e2m3_t>
|
| 624 |
+
{
|
| 625 |
+
/// Minimum finite value
|
| 626 |
+
static cutlass::float_e2m3_t lowest() { return cutlass::float_e2m3_t::bitcast(0x2f); }
|
| 627 |
+
|
| 628 |
+
/// Returns machine epsilon, that is, the difference between 1.0 and the next value representable by the floating-point
|
| 629 |
+
static cutlass::float_e2m3_t epsilon() { return cutlass::float_e2m3_t::bitcast(0x1); }
|
| 630 |
+
};
|
| 631 |
+
|
| 632 |
+
/// Numeric limits for float_e3m2_t
|
| 633 |
+
|
| 634 |
+
template <>
|
| 635 |
+
struct numeric_limits<cutlass::float_e3m2_t> : public float_subbyte_base_numeric_limits<cutlass::float_e3m2_t>
|
| 636 |
+
{
|
| 637 |
+
/// Minimum finite value
|
| 638 |
+
static cutlass::float_e3m2_t lowest() { return cutlass::float_e3m2_t::bitcast(0x2f); }
|
| 639 |
+
|
| 640 |
+
/// Returns machine epsilon, that is, the difference between 1.0 and the next value representable by the floating-point
|
| 641 |
+
static cutlass::float_e3m2_t epsilon() { return cutlass::float_e3m2_t::bitcast(0x4); }
|
| 642 |
+
};
|
| 643 |
+
} // namespace std
|
| 644 |
+
#endif
|
| 645 |
+
|
| 646 |
+
namespace cutlass {
|
| 647 |
+
namespace platform {
|
| 648 |
+
|
| 649 |
+
/// Numeric limits common to all float4 types
|
| 650 |
+
template <typename T>
|
| 651 |
+
struct float_subbyte_base_numeric_limits
|
| 652 |
+
{
|
| 653 |
+
private:
|
| 654 |
+
using type = T;
|
| 655 |
+
|
| 656 |
+
public:
|
| 657 |
+
static bool const is_specialized = true;
|
| 658 |
+
static bool const is_signed = true;
|
| 659 |
+
static bool const is_integer = false;
|
| 660 |
+
static bool const is_exact = false;
|
| 661 |
+
static bool const has_quiet_NaN = false;
|
| 662 |
+
static bool const has_signaling_NaN = false;
|
| 663 |
+
static bool const has_denorm_loss = true;
|
| 664 |
+
static cutlass::platform::float_denorm_style const has_denorm = cutlass::platform::denorm_present;
|
| 665 |
+
static cutlass::platform::float_round_style const round_style = cutlass::platform::round_to_nearest;
|
| 666 |
+
static bool const is_iec559 = false;
|
| 667 |
+
static bool const is_bounded = true;
|
| 668 |
+
static bool const is_modulo = false;
|
| 669 |
+
static int const digits = type::Base::BitRepresentation::NUM_MANTISSA_BITS;
|
| 670 |
+
static bool const has_infinity = false;
|
| 671 |
+
|
| 672 |
+
/// Least positive value
|
| 673 |
+
static type min() { return type::bitcast(0x01); }
|
| 674 |
+
|
| 675 |
+
/// Maximum finite value
|
| 676 |
+
CUTLASS_HOST_DEVICE static type max() { return type::bitcast(type::Base::BitRepresentation::MAX_VALUE); }
|
| 677 |
+
|
| 678 |
+
/// Returns maximum rounding error
|
| 679 |
+
static type round_error() { return type(0.5f); }
|
| 680 |
+
|
| 681 |
+
/// Returns positive infinity value
|
| 682 |
+
static type infinity() { return type::bitcast(type::Base::BitRepresentation::INF_MASK); }
|
| 683 |
+
|
| 684 |
+
/// Returns quiet NaN value
|
| 685 |
+
static type quiet_NaN() { return type::bitcast(type::Base::BitRepresentation::INF_MASK); }
|
| 686 |
+
|
| 687 |
+
/// Returns signaling NaN value
|
| 688 |
+
static type signaling_NaN() { return type::bitcast(type::Base::BitRepresentation::INF_MASK); }
|
| 689 |
+
|
| 690 |
+
/// Returns smallest positive subnormal value
|
| 691 |
+
static type denorm_min() { return type::bitcast(0x01); }
|
| 692 |
+
};
|
| 693 |
+
|
| 694 |
+
/// Forward Declaration
|
| 695 |
+
template <class T>
|
| 696 |
+
struct numeric_limits;
|
| 697 |
+
/// Numeric limits for float_e2m1_t
|
| 698 |
+
template <>
|
| 699 |
+
struct numeric_limits<cutlass::float_e2m1_t> : public float_subbyte_base_numeric_limits<cutlass::float_e2m1_t>
|
| 700 |
+
{
|
| 701 |
+
/// Minimum finite value
|
| 702 |
+
static cutlass::float_e2m1_t lowest() { return cutlass::float_e2m1_t::bitcast(0xf); }
|
| 703 |
+
|
| 704 |
+
/// Returns machine epsilon, that is, the difference between 1.0 and the next value representable by the floating-point
|
| 705 |
+
static cutlass::float_e2m1_t epsilon() { return cutlass::float_e2m1_t::bitcast(0x1); }
|
| 706 |
+
};
|
| 707 |
+
|
| 708 |
+
/// Numeric limits for float_e2m3_t
|
| 709 |
+
template <>
|
| 710 |
+
struct numeric_limits<cutlass::float_e2m3_t> : public float_subbyte_base_numeric_limits<cutlass::float_e2m3_t>
|
| 711 |
+
{
|
| 712 |
+
/// Minimum finite value
|
| 713 |
+
static cutlass::float_e2m3_t lowest() { return cutlass::float_e2m3_t::bitcast(0x2f); }
|
| 714 |
+
|
| 715 |
+
/// Returns machine epsilon, that is, the difference between 1.0 and the next value representable by the floating-point
|
| 716 |
+
static cutlass::float_e2m3_t epsilon() { return cutlass::float_e2m3_t::bitcast(0x1); }
|
| 717 |
+
};
|
| 718 |
+
|
| 719 |
+
/// Numeric limits for float_e3m2_t
|
| 720 |
+
|
| 721 |
+
template <>
|
| 722 |
+
struct numeric_limits<cutlass::float_e3m2_t> : public float_subbyte_base_numeric_limits<cutlass::float_e3m2_t>
|
| 723 |
+
{
|
| 724 |
+
/// Minimum finite value
|
| 725 |
+
static cutlass::float_e3m2_t lowest() { return cutlass::float_e3m2_t::bitcast(0x2f); }
|
| 726 |
+
|
| 727 |
+
/// Returns machine epsilon, that is, the difference between 1.0 and the next value representable by the floating-point
|
| 728 |
+
static cutlass::float_e3m2_t epsilon() { return cutlass::float_e3m2_t::bitcast(0x4); }
|
| 729 |
+
};
|
| 730 |
+
|
| 731 |
+
/// Numeric limits for float_e2m3_unpack8bits_t
|
| 732 |
+
template <>
|
| 733 |
+
struct numeric_limits<cutlass::detail::float_e2m3_unpack8bits_t> : public float_subbyte_base_numeric_limits<cutlass::detail::float_e2m3_unpack8bits_t>
|
| 734 |
+
{
|
| 735 |
+
/// Minimum finite value
|
| 736 |
+
static cutlass::detail::float_e2m3_unpack8bits_t lowest() { return cutlass::detail::float_e2m3_unpack8bits_t::bitcast(0x2f); }
|
| 737 |
+
|
| 738 |
+
/// Returns machine epsilon, that is, the difference between 1.0 and the next value representable by the floating-point
|
| 739 |
+
static cutlass::detail::float_e2m3_unpack8bits_t epsilon() { return cutlass::detail::float_e2m3_unpack8bits_t::bitcast(0x1); }
|
| 740 |
+
};
|
| 741 |
+
|
| 742 |
+
/// Numeric limits for float_e3m2_unpack8bits_t
|
| 743 |
+
|
| 744 |
+
template <>
|
| 745 |
+
struct numeric_limits<cutlass::detail::float_e3m2_unpack8bits_t> : public float_subbyte_base_numeric_limits<cutlass::detail::float_e3m2_unpack8bits_t>
|
| 746 |
+
{
|
| 747 |
+
/// Minimum finite value
|
| 748 |
+
static cutlass::detail::float_e3m2_unpack8bits_t lowest() { return cutlass::detail::float_e3m2_unpack8bits_t::bitcast(0x2f); }
|
| 749 |
+
|
| 750 |
+
/// Returns machine epsilon, that is, the difference between 1.0 and the next value representable by the floating-point
|
| 751 |
+
static cutlass::detail::float_e3m2_unpack8bits_t epsilon() { return cutlass::detail::float_e3m2_unpack8bits_t::bitcast(0x4); }
|
| 752 |
+
};
|
| 753 |
+
} // namespace platform
|
| 754 |
+
|
| 755 |
+
} // namespace cutlass
|
| 756 |
+
|
| 757 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 758 |
+
|
| 759 |
+
//
|
| 760 |
+
// User-defined literals
|
| 761 |
+
//
|
| 762 |
+
CUTLASS_HOST_DEVICE
|
| 763 |
+
cutlass::float_e2m1_t operator"" _fe2m1(long double x)
|
| 764 |
+
{
|
| 765 |
+
return cutlass::float_e2m1_t(float(x));
|
| 766 |
+
}
|
| 767 |
+
|
| 768 |
+
CUTLASS_HOST_DEVICE
|
| 769 |
+
cutlass::float_e2m1_t operator"" _fe2m1(unsigned long long int x)
|
| 770 |
+
{
|
| 771 |
+
return cutlass::float_e2m1_t(int(x));
|
| 772 |
+
}
|
| 773 |
+
CUTLASS_HOST_DEVICE
|
| 774 |
+
cutlass::float_e2m3_t operator"" _fe2m3(long double x)
|
| 775 |
+
{
|
| 776 |
+
return cutlass::float_e2m3_t(float(x));
|
| 777 |
+
}
|
| 778 |
+
|
| 779 |
+
CUTLASS_HOST_DEVICE
|
| 780 |
+
cutlass::float_e2m3_t operator"" _fe2m3(unsigned long long int x)
|
| 781 |
+
{
|
| 782 |
+
return cutlass::float_e2m3_t(int(x));
|
| 783 |
+
}
|
| 784 |
+
|
| 785 |
+
CUTLASS_HOST_DEVICE
|
| 786 |
+
cutlass::float_e3m2_t operator"" _fe3m2(long double x)
|
| 787 |
+
{
|
| 788 |
+
return cutlass::float_e3m2_t(float(x));
|
| 789 |
+
}
|
| 790 |
+
|
| 791 |
+
CUTLASS_HOST_DEVICE
|
| 792 |
+
cutlass::float_e3m2_t operator"" _fe3m2(unsigned long long int x)
|
| 793 |
+
{
|
| 794 |
+
return cutlass::float_e3m2_t(int(x));
|
| 795 |
+
}
|
| 796 |
+
|
| 797 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/floating_point_nvrtc.h
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*!
|
| 32 |
+
\file
|
| 33 |
+
\brief Defines categories for floating point numbers for use in NVRTC-compiled code
|
| 34 |
+
*/
|
| 35 |
+
|
| 36 |
+
#pragma once
|
| 37 |
+
|
| 38 |
+
#include <cutlass/detail/helper_macros.hpp> // CUTLASS_HOST_DEVICE
|
| 39 |
+
#include <cutlass/platform/platform.h> // uint32_t
|
| 40 |
+
#if !defined(__CUDACC_RTC__)
|
| 41 |
+
#include <cstring> // std::memcpy
|
| 42 |
+
#endif
|
| 43 |
+
|
| 44 |
+
namespace cutlass {
|
| 45 |
+
|
| 46 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 47 |
+
|
| 48 |
+
// All floating-point numbers can be put in one of these categories.
|
| 49 |
+
enum {
|
| 50 |
+
FP_NAN =
|
| 51 |
+
# define FP_NAN 0
|
| 52 |
+
FP_NAN,
|
| 53 |
+
FP_INFINITE =
|
| 54 |
+
# define FP_INFINITE 1
|
| 55 |
+
FP_INFINITE,
|
| 56 |
+
FP_ZERO =
|
| 57 |
+
# define FP_ZERO 2
|
| 58 |
+
FP_ZERO,
|
| 59 |
+
FP_SUBNORMAL =
|
| 60 |
+
# define FP_SUBNORMAL 3
|
| 61 |
+
FP_SUBNORMAL,
|
| 62 |
+
FP_NORMAL =
|
| 63 |
+
# define FP_NORMAL 4
|
| 64 |
+
FP_NORMAL
|
| 65 |
+
};
|
| 66 |
+
|
| 67 |
+
CUTLASS_HOST_DEVICE
|
| 68 |
+
int fpclassify(float const& f) {
|
| 69 |
+
|
| 70 |
+
uint32_t s;
|
| 71 |
+
|
| 72 |
+
#if defined(__CUDA_ARCH__)
|
| 73 |
+
s = reinterpret_cast<uint32_t const &>(f);
|
| 74 |
+
#else
|
| 75 |
+
std::memcpy(&s, &f, sizeof(s));
|
| 76 |
+
#endif
|
| 77 |
+
|
| 78 |
+
uint32_t exp = s & 0x7f800000;
|
| 79 |
+
uint32_t mantissa = s & 0x007fffff;
|
| 80 |
+
|
| 81 |
+
if (exp == 0x7f800000) {
|
| 82 |
+
if (mantissa) {
|
| 83 |
+
return FP_NAN;
|
| 84 |
+
}
|
| 85 |
+
else {
|
| 86 |
+
return FP_INFINITE;
|
| 87 |
+
}
|
| 88 |
+
}
|
| 89 |
+
else if (!exp) {
|
| 90 |
+
if (mantissa) {
|
| 91 |
+
return FP_SUBNORMAL;
|
| 92 |
+
}
|
| 93 |
+
else {
|
| 94 |
+
return FP_ZERO;
|
| 95 |
+
}
|
| 96 |
+
}
|
| 97 |
+
return FP_NORMAL;
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
| 101 |
+
|
| 102 |
+
} // namespace cutlass
|
| 103 |
+
|
| 104 |
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/functional.h
ADDED
|
@@ -0,0 +1,1106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/*! \file
|
| 32 |
+
\brief Define basic numeric operators
|
| 33 |
+
|
| 34 |
+
This is inspired by the Standard Library's <functional> header.
|
| 35 |
+
*/
|
| 36 |
+
#pragma once
|
| 37 |
+
|
| 38 |
+
#include "cutlass/cutlass.h"
|
| 39 |
+
#include "cutlass/numeric_types.h"
|
| 40 |
+
#include "cutlass/platform/platform.h"
|
| 41 |
+
#if defined(__CUDACC_RTC__)
|
| 42 |
+
#include "cutlass/floating_point_nvrtc.h"
|
| 43 |
+
#endif
|
| 44 |
+
|
| 45 |
+
#include <cuda_runtime.h>
|
| 46 |
+
|
| 47 |
+
#if defined(CUTLASS_ARCH_WMMA_ENABLED)
|
| 48 |
+
#include <mma.h>
|
| 49 |
+
#endif // defined(CUTLASS_ARCH_WMMA_ENABLED)
|
| 50 |
+
|
| 51 |
+
#ifdef _MSC_VER
|
| 52 |
+
// Provides support for alternate operators such as 'and', 'or', ...
|
| 53 |
+
#include <ciso646>
|
| 54 |
+
#include <intrin.h>
|
| 55 |
+
#endif // _MSC_VER
|
| 56 |
+
|
| 57 |
+
#if defined(CUTLASS_ARCH_MMA_SM100A_ENABLED) || defined(CUTLASS_ARCH_MMA_SM100F_ENABLED) ||\
|
| 58 |
+
defined(CUTLASS_ARCH_MMA_SM103A_ENABLED) || defined(CUTLASS_ARCH_MMA_SM103F_ENABLED)
|
| 59 |
+
# define CUTLASS_ARCH_CREDUX_ENABLED
|
| 60 |
+
#endif
|
| 61 |
+
|
| 62 |
+
namespace cutlass {
|
| 63 |
+
|
| 64 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 65 |
+
|
| 66 |
+
namespace detail {
|
| 67 |
+
|
| 68 |
+
CUTLASS_HOST_DEVICE int32_t popcount(int32_t x) {
|
| 69 |
+
#if defined(__CUDA_ARCH__)
|
| 70 |
+
return __popc(x);
|
| 71 |
+
#elif defined(__GNUC__) || defined(__clang__)
|
| 72 |
+
return __builtin_popcount(x);
|
| 73 |
+
#elif (defined(_MSC_VER) && !defined(_M_ARM64))
|
| 74 |
+
return __popcnt(x);
|
| 75 |
+
#else
|
| 76 |
+
int32_t count = 0;
|
| 77 |
+
while (x) {
|
| 78 |
+
count += x & 1;
|
| 79 |
+
x >>= 1;
|
| 80 |
+
}
|
| 81 |
+
return count;
|
| 82 |
+
#endif
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
CUTLASS_HOST_DEVICE int64_t popcount(int64_t x) {
|
| 86 |
+
#if defined(__CUDA_ARCH__)
|
| 87 |
+
return __popcll(x);
|
| 88 |
+
#elif defined(__GNUC__) || defined(__clang__)
|
| 89 |
+
return __builtin_popcountll(x);
|
| 90 |
+
#elif (defined(_MSC_VER) && !defined(_M_ARM64))
|
| 91 |
+
return __popcnt64(x);
|
| 92 |
+
#else
|
| 93 |
+
int64_t count = 0;
|
| 94 |
+
while (x) {
|
| 95 |
+
count += x & 1;
|
| 96 |
+
x >>= 1;
|
| 97 |
+
}
|
| 98 |
+
return count;
|
| 99 |
+
#endif
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
} // namespace detail
|
| 103 |
+
|
| 104 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 105 |
+
|
| 106 |
+
template <typename T>
|
| 107 |
+
struct absolute_value_op {
|
| 108 |
+
CUTLASS_HOST_DEVICE
|
| 109 |
+
T operator()(T lhs) const {
|
| 110 |
+
return abs(lhs);
|
| 111 |
+
}
|
| 112 |
+
};
|
| 113 |
+
|
| 114 |
+
template <>
|
| 115 |
+
struct absolute_value_op<float> {
|
| 116 |
+
CUTLASS_HOST_DEVICE
|
| 117 |
+
float operator()(float lhs) const { return fabs(lhs); }
|
| 118 |
+
};
|
| 119 |
+
|
| 120 |
+
template <typename T>
|
| 121 |
+
struct plus {
|
| 122 |
+
CUTLASS_HOST_DEVICE
|
| 123 |
+
T operator()(T lhs, T const &rhs) const {
|
| 124 |
+
lhs += rhs;
|
| 125 |
+
return lhs;
|
| 126 |
+
}
|
| 127 |
+
};
|
| 128 |
+
|
| 129 |
+
template <typename T>
|
| 130 |
+
struct minus {
|
| 131 |
+
CUTLASS_HOST_DEVICE
|
| 132 |
+
T operator()(T lhs, T const &rhs) const {
|
| 133 |
+
lhs -= rhs;
|
| 134 |
+
return lhs;
|
| 135 |
+
}
|
| 136 |
+
};
|
| 137 |
+
|
| 138 |
+
template <typename T>
|
| 139 |
+
struct multiplies {
|
| 140 |
+
CUTLASS_HOST_DEVICE
|
| 141 |
+
T operator()(T lhs, T const &rhs) const {
|
| 142 |
+
lhs *= rhs;
|
| 143 |
+
return lhs;
|
| 144 |
+
}
|
| 145 |
+
};
|
| 146 |
+
|
| 147 |
+
template <typename T>
|
| 148 |
+
struct scale {
|
| 149 |
+
T const scaling_factor_;
|
| 150 |
+
|
| 151 |
+
CUTLASS_HOST_DEVICE
|
| 152 |
+
scale(float scaling_factor) : scaling_factor_(scaling_factor) {
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
T operator()(T const &rhs) const {
|
| 156 |
+
T result = rhs * scaling_factor_;
|
| 157 |
+
return result;
|
| 158 |
+
}
|
| 159 |
+
};
|
| 160 |
+
|
| 161 |
+
#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530
|
| 162 |
+
/// Partial specializations needed when __CUDA_NO_HALF2_OPERATORS__ is set
|
| 163 |
+
template<>
|
| 164 |
+
struct plus<__half2> {
|
| 165 |
+
CUTLASS_HOST_DEVICE
|
| 166 |
+
__half2 operator()(__half2 lhs, __half2 const &rhs) const {
|
| 167 |
+
return __hadd2(lhs, rhs);
|
| 168 |
+
}
|
| 169 |
+
};
|
| 170 |
+
|
| 171 |
+
template<>
|
| 172 |
+
struct minus<__half2> {
|
| 173 |
+
CUTLASS_HOST_DEVICE
|
| 174 |
+
__half2 operator()(__half2 lhs, __half2 const &rhs) const {
|
| 175 |
+
return __hsub2(lhs, rhs);
|
| 176 |
+
}
|
| 177 |
+
};
|
| 178 |
+
|
| 179 |
+
template<>
|
| 180 |
+
struct multiplies<__half2> {
|
| 181 |
+
CUTLASS_HOST_DEVICE
|
| 182 |
+
__half2 operator()(__half2 lhs, __half2 const &rhs) const {
|
| 183 |
+
return __hmul2(lhs, rhs);
|
| 184 |
+
}
|
| 185 |
+
};
|
| 186 |
+
|
| 187 |
+
/// Partial specializations needed when __CUDA_NO_HALF_OPERATORS__ is set
|
| 188 |
+
template<>
|
| 189 |
+
struct plus<__half> {
|
| 190 |
+
CUTLASS_HOST_DEVICE
|
| 191 |
+
__half operator()(__half lhs, __half const &rhs) const {
|
| 192 |
+
return __hadd(lhs, rhs);
|
| 193 |
+
}
|
| 194 |
+
};
|
| 195 |
+
|
| 196 |
+
template<>
|
| 197 |
+
struct minus<__half> {
|
| 198 |
+
CUTLASS_HOST_DEVICE
|
| 199 |
+
__half operator()(__half lhs, __half const &rhs) const {
|
| 200 |
+
return __hsub(lhs, rhs);
|
| 201 |
+
}
|
| 202 |
+
};
|
| 203 |
+
|
| 204 |
+
template<>
|
| 205 |
+
struct multiplies<__half> {
|
| 206 |
+
CUTLASS_HOST_DEVICE
|
| 207 |
+
__half operator()(__half lhs, __half const &rhs) const {
|
| 208 |
+
return __hmul(lhs, rhs);
|
| 209 |
+
}
|
| 210 |
+
};
|
| 211 |
+
#endif // defined(__CUDA_ARCH__)
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
/// Squares with optional conversion
|
| 215 |
+
template <typename T, typename Output = T>
|
| 216 |
+
struct square {
|
| 217 |
+
CUTLASS_HOST_DEVICE
|
| 218 |
+
Output operator()(T lhs) const {
|
| 219 |
+
multiplies<Output> mul_op;
|
| 220 |
+
|
| 221 |
+
Output y = Output(lhs);
|
| 222 |
+
return mul_op(y, y);
|
| 223 |
+
}
|
| 224 |
+
};
|
| 225 |
+
|
| 226 |
+
/// Returns the magnitude squared of an element.
|
| 227 |
+
template <typename T, typename Output = T>
|
| 228 |
+
struct magnitude_squared {
|
| 229 |
+
CUTLASS_HOST_DEVICE
|
| 230 |
+
Output operator()(T lhs) const {
|
| 231 |
+
multiplies<Output> mul_op;
|
| 232 |
+
|
| 233 |
+
Output y = Output(lhs);
|
| 234 |
+
return mul_op(y, y);
|
| 235 |
+
}
|
| 236 |
+
};
|
| 237 |
+
|
| 238 |
+
/// Computes the square of a difference with optional conversion
|
| 239 |
+
template <typename T, typename Output = T>
|
| 240 |
+
struct square_difference {
|
| 241 |
+
CUTLASS_HOST_DEVICE
|
| 242 |
+
Output operator()(T lhs, T rhs) const {
|
| 243 |
+
multiplies<Output> mul_op;
|
| 244 |
+
|
| 245 |
+
Output y = Output(lhs) - Output(rhs);
|
| 246 |
+
return mul_op(y, y);
|
| 247 |
+
}
|
| 248 |
+
};
|
| 249 |
+
|
| 250 |
+
/// Computes the square of a difference with optional conversion
|
| 251 |
+
template <typename T, typename Output = T>
|
| 252 |
+
struct magnitude_squared_difference {
|
| 253 |
+
CUTLASS_HOST_DEVICE
|
| 254 |
+
Output operator()(T lhs, T rhs) const {
|
| 255 |
+
multiplies<Output> mul_op;
|
| 256 |
+
|
| 257 |
+
Output y = Output(lhs) - Output(rhs);
|
| 258 |
+
return mul_op(y, y);
|
| 259 |
+
}
|
| 260 |
+
};
|
| 261 |
+
|
| 262 |
+
// Computes the reciprocal square root
|
| 263 |
+
template <typename T>
|
| 264 |
+
struct inverse_square_root;
|
| 265 |
+
|
| 266 |
+
template <>
|
| 267 |
+
struct inverse_square_root<float> {
|
| 268 |
+
CUTLASS_HOST_DEVICE
|
| 269 |
+
float operator()(float const &lhs) const {
|
| 270 |
+
#if defined(__CUDA_ARCH__)
|
| 271 |
+
return rsqrtf(lhs);
|
| 272 |
+
#else
|
| 273 |
+
return 1.f / std::sqrt(lhs);
|
| 274 |
+
#endif
|
| 275 |
+
}
|
| 276 |
+
};
|
| 277 |
+
|
| 278 |
+
template <>
|
| 279 |
+
struct inverse_square_root<half_t> {
|
| 280 |
+
CUTLASS_HOST_DEVICE
|
| 281 |
+
half_t operator()(half_t const &lhs) const {
|
| 282 |
+
#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ > 520)
|
| 283 |
+
auto result = hrsqrt(reinterpret_cast<__half const &>(lhs));
|
| 284 |
+
return reinterpret_cast<half_t const &>(result);
|
| 285 |
+
#else
|
| 286 |
+
return half_t(1.f / std::sqrt(half_t::convert(lhs)));
|
| 287 |
+
#endif
|
| 288 |
+
}
|
| 289 |
+
};
|
| 290 |
+
|
| 291 |
+
/// Divides
|
| 292 |
+
template <typename T>
|
| 293 |
+
struct divides {
|
| 294 |
+
CUTLASS_HOST_DEVICE
|
| 295 |
+
T operator()(T lhs, T const &rhs) const {
|
| 296 |
+
lhs /= rhs;
|
| 297 |
+
return lhs;
|
| 298 |
+
}
|
| 299 |
+
};
|
| 300 |
+
|
| 301 |
+
/// reciprocal_approximate
|
| 302 |
+
template <typename T>
|
| 303 |
+
struct reciprocal_approximate {
|
| 304 |
+
CUTLASS_HOST_DEVICE
|
| 305 |
+
T operator()(T lhs) const {
|
| 306 |
+
return divides<T>{}(T(1), lhs);
|
| 307 |
+
}
|
| 308 |
+
};
|
| 309 |
+
|
| 310 |
+
template <>
|
| 311 |
+
struct reciprocal_approximate <float> {
|
| 312 |
+
CUTLASS_HOST_DEVICE
|
| 313 |
+
float operator()(float lhs) const {
|
| 314 |
+
float ret;
|
| 315 |
+
#if defined(__CUDA_ARCH__)
|
| 316 |
+
asm volatile ("rcp.approx.f32 %0, %1;\n" : "=f"(ret) : "f"(lhs));
|
| 317 |
+
#else
|
| 318 |
+
ret = 1.0f / lhs;
|
| 319 |
+
#endif
|
| 320 |
+
return ret;
|
| 321 |
+
}
|
| 322 |
+
};
|
| 323 |
+
|
| 324 |
+
|
| 325 |
+
template <>
|
| 326 |
+
struct reciprocal_approximate<cutlass::float_ue8m0_t> {
|
| 327 |
+
CUTLASS_HOST_DEVICE
|
| 328 |
+
cutlass::float_ue8m0_t operator()(cutlass::float_ue8m0_t lhs) const {
|
| 329 |
+
return cutlass::float_ue8m0_t::bitcast(static_cast<uint8_t>(static_cast<uint8_t>(254u) - lhs.storage));
|
| 330 |
+
}
|
| 331 |
+
};
|
| 332 |
+
|
| 333 |
+
|
| 334 |
+
/// reciprocal_approximate with ftz
|
| 335 |
+
template<typename T>
|
| 336 |
+
struct reciprocal_approximate_ftz : reciprocal_approximate<T>
|
| 337 |
+
{};
|
| 338 |
+
|
| 339 |
+
template <>
|
| 340 |
+
struct reciprocal_approximate_ftz <float> {
|
| 341 |
+
CUTLASS_HOST_DEVICE
|
| 342 |
+
float operator()(float lhs) const {
|
| 343 |
+
float ret;
|
| 344 |
+
#if defined(__CUDA_ARCH__)
|
| 345 |
+
asm volatile ("rcp.approx.ftz.f32 %0, %1;\n" : "=f"(ret) : "f"(lhs));
|
| 346 |
+
#else
|
| 347 |
+
if (std::fpclassify(lhs) == FP_SUBNORMAL) {
|
| 348 |
+
lhs = 0.0f;
|
| 349 |
+
}
|
| 350 |
+
ret = 1.0f / lhs;
|
| 351 |
+
if (std::fpclassify(ret) == FP_SUBNORMAL) {
|
| 352 |
+
ret = 0.0f;
|
| 353 |
+
}
|
| 354 |
+
#endif
|
| 355 |
+
return ret;
|
| 356 |
+
}
|
| 357 |
+
};
|
| 358 |
+
|
| 359 |
+
/// Negate
|
| 360 |
+
template <typename T>
|
| 361 |
+
struct negate {
|
| 362 |
+
CUTLASS_HOST_DEVICE
|
| 363 |
+
T operator()(T lhs) const {
|
| 364 |
+
return -lhs;
|
| 365 |
+
}
|
| 366 |
+
};
|
| 367 |
+
|
| 368 |
+
/// Greater equal
|
| 369 |
+
template <typename T>
|
| 370 |
+
struct greater_equal {
|
| 371 |
+
CUTLASS_HOST_DEVICE
|
| 372 |
+
bool operator()(T const &lhs, T const &rhs) const {
|
| 373 |
+
return (lhs >= rhs);
|
| 374 |
+
}
|
| 375 |
+
};
|
| 376 |
+
|
| 377 |
+
/// Greater
|
| 378 |
+
template <typename T>
|
| 379 |
+
struct greater {
|
| 380 |
+
CUTLASS_HOST_DEVICE
|
| 381 |
+
bool operator()(T const &lhs, T const &rhs) const {
|
| 382 |
+
return (lhs > rhs);
|
| 383 |
+
}
|
| 384 |
+
};
|
| 385 |
+
|
| 386 |
+
/// Less equal
|
| 387 |
+
template <typename T>
|
| 388 |
+
struct less_equal {
|
| 389 |
+
CUTLASS_HOST_DEVICE
|
| 390 |
+
bool operator()(T const &lhs, T const &rhs) const {
|
| 391 |
+
return (lhs <= rhs);
|
| 392 |
+
}
|
| 393 |
+
};
|
| 394 |
+
|
| 395 |
+
/// Less
|
| 396 |
+
template <typename T>
|
| 397 |
+
struct less {
|
| 398 |
+
CUTLASS_HOST_DEVICE
|
| 399 |
+
bool operator()(T const &lhs, T const &rhs) const {
|
| 400 |
+
return (lhs < rhs);
|
| 401 |
+
}
|
| 402 |
+
};
|
| 403 |
+
|
| 404 |
+
template <typename T, bool PropagateNaN = false>
|
| 405 |
+
struct maximum {
|
| 406 |
+
CUTLASS_HOST_DEVICE
|
| 407 |
+
T operator()(T const &lhs, T const &rhs) const {
|
| 408 |
+
if constexpr (PropagateNaN && cutlass::platform::is_floating_point<T>::value) {
|
| 409 |
+
using CUTLASS_CMATH_NAMESPACE :: isnan;
|
| 410 |
+
|
| 411 |
+
// Call isnan unqualified, so argument-dependent lookup (ADL)
|
| 412 |
+
// will find overloads such as cutlass::isnan(half_t).
|
| 413 |
+
// Calling ::isnan or std::isnan directly would force
|
| 414 |
+
// implicit conversions to float of custom number types
|
| 415 |
+
// in the cutlass namespace (e.g., cutlass::half_t).
|
| 416 |
+
return lhs > rhs || isnan(lhs) ? lhs : rhs;
|
| 417 |
+
}
|
| 418 |
+
else {
|
| 419 |
+
return (lhs < rhs ? rhs : lhs);
|
| 420 |
+
}
|
| 421 |
+
|
| 422 |
+
CUTE_GCC_UNREACHABLE;
|
| 423 |
+
}
|
| 424 |
+
};
|
| 425 |
+
|
| 426 |
+
// This is a subclass and not an alias
|
| 427 |
+
// in order to work around a known Clang issue,
|
| 428 |
+
// where a template template parameter with one template parameter
|
| 429 |
+
// does not match classes that take multiple template parameters
|
| 430 |
+
// but have defaults for all but the first.
|
| 431 |
+
template<typename T>
|
| 432 |
+
struct maximum_with_default_nan_propagation : public maximum<T>
|
| 433 |
+
{};
|
| 434 |
+
|
| 435 |
+
template <>
|
| 436 |
+
struct maximum<float, false> {
|
| 437 |
+
CUTLASS_HOST_DEVICE
|
| 438 |
+
float operator()(float const &lhs, float const &rhs) const {
|
| 439 |
+
return fmaxf(lhs, rhs);
|
| 440 |
+
}
|
| 441 |
+
};
|
| 442 |
+
|
| 443 |
+
template <>
|
| 444 |
+
struct maximum<float, true> {
|
| 445 |
+
CUTLASS_HOST_DEVICE
|
| 446 |
+
float operator()(float lhs, float rhs) const {
|
| 447 |
+
#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 800)
|
| 448 |
+
float res;
|
| 449 |
+
asm volatile("max.NaN.f32 %0, %1, %2;\n" : "=f"(res) : "f"(lhs), "f"(rhs));
|
| 450 |
+
return res;
|
| 451 |
+
#else
|
| 452 |
+
using CUTLASS_CMATH_NAMESPACE :: isnan;
|
| 453 |
+
|
| 454 |
+
return lhs > rhs || isnan(lhs) ? lhs : rhs;
|
| 455 |
+
#endif
|
| 456 |
+
}
|
| 457 |
+
};
|
| 458 |
+
|
| 459 |
+
// This is a subclass and not an alias
|
| 460 |
+
// in order to work around a known Clang issue,
|
| 461 |
+
// where a template template parameter with one template parameter
|
| 462 |
+
// does not match classes that take multiple template parameters
|
| 463 |
+
// but have defaults for all but the first.
|
| 464 |
+
template <typename T>
|
| 465 |
+
struct maximum_with_nan_propagation : maximum<T, true>
|
| 466 |
+
{};
|
| 467 |
+
|
| 468 |
+
// This alias exists for backwards compatibility only.
|
| 469 |
+
// Please use the correctly spelled class template above.
|
| 470 |
+
template <typename T>
|
| 471 |
+
using maximum_with_nan_propogation = maximum_with_nan_propagation<T>;
|
| 472 |
+
|
| 473 |
+
template <typename T, bool PropagateNaN = false>
|
| 474 |
+
struct minimum {
|
| 475 |
+
CUTLASS_HOST_DEVICE
|
| 476 |
+
T operator()(T const &lhs, T const &rhs) const {
|
| 477 |
+
if constexpr (PropagateNaN && cutlass::platform::is_floating_point<T>::value) {
|
| 478 |
+
using CUTLASS_CMATH_NAMESPACE :: isnan;
|
| 479 |
+
|
| 480 |
+
return lhs < rhs || isnan(lhs) ? lhs : rhs;
|
| 481 |
+
}
|
| 482 |
+
else {
|
| 483 |
+
return (rhs < lhs ? rhs : lhs);
|
| 484 |
+
}
|
| 485 |
+
}
|
| 486 |
+
};
|
| 487 |
+
|
| 488 |
+
template <>
|
| 489 |
+
struct minimum<float, false> {
|
| 490 |
+
CUTLASS_HOST_DEVICE
|
| 491 |
+
float operator()(float const &lhs, float const &rhs) const {
|
| 492 |
+
return fminf(lhs, rhs);
|
| 493 |
+
}
|
| 494 |
+
};
|
| 495 |
+
|
| 496 |
+
template <>
|
| 497 |
+
struct minimum<float, true> {
|
| 498 |
+
CUTLASS_HOST_DEVICE
|
| 499 |
+
float operator()(float lhs, float rhs) const {
|
| 500 |
+
#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 800)
|
| 501 |
+
float res;
|
| 502 |
+
asm volatile("min.NaN.f32 %0, %1, %2;\n" : "=f"(res) : "f"(lhs), "f"(rhs));
|
| 503 |
+
return res;
|
| 504 |
+
#else
|
| 505 |
+
// No need for ADL; call std::isnan(float) on host and ::isnan(float) on device.
|
| 506 |
+
return lhs < rhs || (CUTLASS_CMATH_NAMESPACE :: isnan(lhs)) ? lhs : rhs;
|
| 507 |
+
#endif
|
| 508 |
+
}
|
| 509 |
+
};
|
| 510 |
+
|
| 511 |
+
template <typename T>
|
| 512 |
+
struct minimum_with_nan_propagation : minimum<T, true>
|
| 513 |
+
{};
|
| 514 |
+
|
| 515 |
+
template <typename T, bool PropagateNaN = false>
|
| 516 |
+
struct maximum_absolute_value {
|
| 517 |
+
CUTLASS_HOST_DEVICE
|
| 518 |
+
float operator()(T const &lhs, T const &rhs) const {
|
| 519 |
+
absolute_value_op<T> abs_op;
|
| 520 |
+
maximum<T, PropagateNaN> max_op;
|
| 521 |
+
|
| 522 |
+
return max_op(abs_op(lhs), abs_op(rhs));
|
| 523 |
+
}
|
| 524 |
+
};
|
| 525 |
+
|
| 526 |
+
// assumes the left operand is already an absolute value
|
| 527 |
+
template <typename T, bool PropagateNaN = false>
|
| 528 |
+
struct maximum_absolute_value_reduction {
|
| 529 |
+
CUTLASS_HOST_DEVICE
|
| 530 |
+
float operator()(T const &lhs, T const &rhs) const {
|
| 531 |
+
absolute_value_op<T> abs_op;
|
| 532 |
+
maximum<T, PropagateNaN> max_op;
|
| 533 |
+
|
| 534 |
+
return max_op(lhs, abs_op(rhs));
|
| 535 |
+
}
|
| 536 |
+
};
|
| 537 |
+
|
| 538 |
+
/// Fused multiply-add
|
| 539 |
+
template <typename A, typename B = A, typename C = A>
|
| 540 |
+
struct multiply_add {
|
| 541 |
+
CUTLASS_HOST_DEVICE
|
| 542 |
+
C operator()(A const &a, B const &b, C const &c) const {
|
| 543 |
+
return C(a) * C(b) + c;
|
| 544 |
+
}
|
| 545 |
+
};
|
| 546 |
+
|
| 547 |
+
template <typename T>
|
| 548 |
+
struct square_and_plus {
|
| 549 |
+
CUTLASS_HOST_DEVICE
|
| 550 |
+
T operator()(T lhs, T const &rhs) const {
|
| 551 |
+
multiply_add<T> multiply_add_op;
|
| 552 |
+
return multiply_add_op(rhs, rhs, lhs);
|
| 553 |
+
}
|
| 554 |
+
};
|
| 555 |
+
|
| 556 |
+
// Fused multiply-add that takes exactly one template parameter.
|
| 557 |
+
// This is useful for working around a known Clang issue,
|
| 558 |
+
// where a template template parameter with one template parameter
|
| 559 |
+
// does not match classes that take multiple template parameters
|
| 560 |
+
// but have defaults for all but the first.
|
| 561 |
+
template <typename A>
|
| 562 |
+
struct homogeneous_multiply_add : public multiply_add<A, A, A>
|
| 563 |
+
{};
|
| 564 |
+
|
| 565 |
+
/// Fused multiply-add
|
| 566 |
+
template <typename A, typename B = A, typename C = A>
|
| 567 |
+
struct multiply_add_relu0 {
|
| 568 |
+
CUTLASS_HOST_DEVICE
|
| 569 |
+
C operator()(A const &a, B const &b, C const &c) const {
|
| 570 |
+
maximum<C> mx;
|
| 571 |
+
return mx(C(a) * C(b) + c, C(0));
|
| 572 |
+
}
|
| 573 |
+
};
|
| 574 |
+
|
| 575 |
+
/// Guarded-multiply-add
|
| 576 |
+
template <typename A, typename B = A, typename C = A>
|
| 577 |
+
struct guarded_multiply_add {
|
| 578 |
+
CUTLASS_HOST_DEVICE
|
| 579 |
+
C operator()(A const &a, B const &b, C const &c) const {
|
| 580 |
+
using CUTLASS_CMATH_NAMESPACE :: isnan;
|
| 581 |
+
|
| 582 |
+
if (isnan(a) || isnan(b)) {
|
| 583 |
+
return C(0);
|
| 584 |
+
}
|
| 585 |
+
return C(a) * C(b) + c;
|
| 586 |
+
}
|
| 587 |
+
};
|
| 588 |
+
|
| 589 |
+
/// Guarded-multiply-add
|
| 590 |
+
template <>
|
| 591 |
+
struct guarded_multiply_add<half_t, half_t, half_t> {
|
| 592 |
+
CUTLASS_HOST_DEVICE
|
| 593 |
+
half_t operator()(half_t const &a, half_t const &b, half_t const &c) const {
|
| 594 |
+
#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 900
|
| 595 |
+
half_t result;
|
| 596 |
+
asm ("fma.rn.oob.f16 %0, %1, %2, %3;\n"
|
| 597 |
+
: "=h"(*reinterpret_cast<uint16_t*>(&result))
|
| 598 |
+
: "h"(*reinterpret_cast<uint16_t const*>(&a)), "h"(*reinterpret_cast<uint16_t const*>(&b)), "h"(*reinterpret_cast<uint16_t const*>(&c)));
|
| 599 |
+
return result;
|
| 600 |
+
#else
|
| 601 |
+
// Namespace-qualifying isnan as cutlass::isnan saves the compiler
|
| 602 |
+
// the trouble of argument-dependent lookup. Calling std::isnan or
|
| 603 |
+
// ::isnan here would result in unwanted implicit conversion to float.
|
| 604 |
+
if (cutlass::isnan(a) || cutlass::isnan(b)) {
|
| 605 |
+
return half_t(0);
|
| 606 |
+
}
|
| 607 |
+
return a * b + c;
|
| 608 |
+
#endif
|
| 609 |
+
}
|
| 610 |
+
};
|
| 611 |
+
|
| 612 |
+
/// Guarded-multiply-add-relu0
|
| 613 |
+
template <typename A, typename B = A, typename C = A>
|
| 614 |
+
struct guarded_multiply_add_relu0 {
|
| 615 |
+
CUTLASS_HOST_DEVICE
|
| 616 |
+
C operator()(A const &a, B const &b, C const &c) const {
|
| 617 |
+
using CUTLASS_CMATH_NAMESPACE :: isnan;
|
| 618 |
+
|
| 619 |
+
if (isnan(a) || isnan(b)) {
|
| 620 |
+
return C(0);
|
| 621 |
+
}
|
| 622 |
+
maximum<C> mx;
|
| 623 |
+
return mx(C(a) * C(b) + c, C(0));
|
| 624 |
+
}
|
| 625 |
+
};
|
| 626 |
+
|
| 627 |
+
template <>
|
| 628 |
+
struct guarded_multiply_add_relu0<half_t, half_t, half_t> {
|
| 629 |
+
CUTLASS_HOST_DEVICE
|
| 630 |
+
half_t operator()(half_t const &a, half_t const &b, half_t const &c) const {
|
| 631 |
+
#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 900
|
| 632 |
+
half_t result;
|
| 633 |
+
asm ("fma.rn.oob.relu.f16 %0, %1, %2, %3;\n"
|
| 634 |
+
: "=h"(*reinterpret_cast<uint16_t*>(&result))
|
| 635 |
+
: "h"(*reinterpret_cast<uint16_t const*>(&a)), "h"(*reinterpret_cast<uint16_t const*>(&b)), "h"(*reinterpret_cast<uint16_t const*>(&c)));
|
| 636 |
+
return result;
|
| 637 |
+
#else
|
| 638 |
+
if (cutlass::isnan(a) || cutlass::isnan(b)) {
|
| 639 |
+
return half_t(0);
|
| 640 |
+
}
|
| 641 |
+
maximum<half_t> mx;
|
| 642 |
+
return mx(a * b + c, half_t(0));
|
| 643 |
+
#endif
|
| 644 |
+
}
|
| 645 |
+
};
|
| 646 |
+
|
| 647 |
+
|
| 648 |
+
/// Fused and-popc-add
|
| 649 |
+
template <typename A, typename B = A, typename C = A>
|
| 650 |
+
struct and_popc_add {
|
| 651 |
+
CUTLASS_HOST_DEVICE
|
| 652 |
+
C operator()(A const &a, B const &b, C const &c) const {
|
| 653 |
+
A and_result = a & b;
|
| 654 |
+
int32_t popc_result = detail::popcount(and_result);
|
| 655 |
+
return C(popc_result) + c;
|
| 656 |
+
}
|
| 657 |
+
};
|
| 658 |
+
|
| 659 |
+
/// Fused and-add
|
| 660 |
+
template <typename T>
|
| 661 |
+
struct and_add {
|
| 662 |
+
CUTLASS_HOST_DEVICE
|
| 663 |
+
T operator()(T const &a, T const &b, T const &c) const {
|
| 664 |
+
return ((a & b) + c);
|
| 665 |
+
}
|
| 666 |
+
};
|
| 667 |
+
|
| 668 |
+
|
| 669 |
+
|
| 670 |
+
/// Fused xor-popc-add
|
| 671 |
+
template <typename A, typename B = A, typename C = A>
|
| 672 |
+
struct xor_popc_add {
|
| 673 |
+
CUTLASS_HOST_DEVICE
|
| 674 |
+
C operator()(A const &a, B const &b, C const &c) const {
|
| 675 |
+
A xor_result = a ^ b;
|
| 676 |
+
int32_t popc_result = detail::popcount(xor_result);
|
| 677 |
+
return C(popc_result) + c;
|
| 678 |
+
}
|
| 679 |
+
};
|
| 680 |
+
|
| 681 |
+
/// Fused xor-add
|
| 682 |
+
template <typename T>
|
| 683 |
+
struct xor_add {
|
| 684 |
+
CUTLASS_HOST_DEVICE
|
| 685 |
+
T operator()(T const &a, T const &b, T const &c) const {
|
| 686 |
+
return ((a ^ b) + c);
|
| 687 |
+
}
|
| 688 |
+
};
|
| 689 |
+
|
| 690 |
+
|
| 691 |
+
/// Fused or-popc-add
|
| 692 |
+
template <typename A, typename B = A, typename C = A>
|
| 693 |
+
struct or_popc_add {
|
| 694 |
+
CUTLASS_HOST_DEVICE
|
| 695 |
+
C operator()(A const &a, B const &b, C const &c) const {
|
| 696 |
+
A or_result = a | b;
|
| 697 |
+
int32_t popc_result = detail::popcount(or_result);
|
| 698 |
+
return C(popc_result) + c;
|
| 699 |
+
}
|
| 700 |
+
};
|
| 701 |
+
|
| 702 |
+
|
| 703 |
+
/// Fused or-add
|
| 704 |
+
template <typename T>
|
| 705 |
+
struct or_add {
|
| 706 |
+
CUTLASS_HOST_DEVICE
|
| 707 |
+
T operator()(T const &a, T const &b, T const &c) const {
|
| 708 |
+
return ((a | b) + c);
|
| 709 |
+
}
|
| 710 |
+
};
|
| 711 |
+
|
| 712 |
+
namespace detail {
|
| 713 |
+
|
| 714 |
+
// Whether namespace-unqualified conj(t) for t of type T is
|
| 715 |
+
// well-formed. This says whether the compiler can find
|
| 716 |
+
// namespace-unqualified conj(T) via argument-dependent lookup.
|
| 717 |
+
// If so, then CUTLASS assumes that conj(t) returns
|
| 718 |
+
// the complex conjugate of t.
|
| 719 |
+
template <typename T, typename Enable = void>
|
| 720 |
+
struct has_unqualified_conj : cutlass::platform::false_type
|
| 721 |
+
{};
|
| 722 |
+
|
| 723 |
+
template<typename T>
|
| 724 |
+
struct has_unqualified_conj<
|
| 725 |
+
T,
|
| 726 |
+
decltype(static_cast<void>(conj(cutlass::platform::declval<T>())), void())
|
| 727 |
+
> : cutlass::platform::true_type
|
| 728 |
+
{};
|
| 729 |
+
|
| 730 |
+
template <typename T>
|
| 731 |
+
constexpr bool has_unqualified_conj_v = has_unqualified_conj<T>::value;
|
| 732 |
+
|
| 733 |
+
} // namespace detail
|
| 734 |
+
|
| 735 |
+
// forward declaration (needed for conjugate below)
|
| 736 |
+
template<class T>
|
| 737 |
+
CUTLASS_HOST_DEVICE T conj(T const& z);
|
| 738 |
+
|
| 739 |
+
namespace detail {
|
| 740 |
+
|
| 741 |
+
// Whether cutlass::conj(t) for t of type T is well-formed.
|
| 742 |
+
// If so, then CUTLASS assumes that cutlass::conj(t)
|
| 743 |
+
// returns the complex conjugate of t.
|
| 744 |
+
template <typename T, typename Enable = void>
|
| 745 |
+
struct has_cutlass_conj : cutlass::platform::false_type
|
| 746 |
+
{};
|
| 747 |
+
|
| 748 |
+
template<typename T>
|
| 749 |
+
struct has_cutlass_conj<
|
| 750 |
+
T,
|
| 751 |
+
decltype(cutlass::conj(cutlass::platform::declval<T>()), void())
|
| 752 |
+
> : cutlass::platform::true_type
|
| 753 |
+
{};
|
| 754 |
+
|
| 755 |
+
template <typename T>
|
| 756 |
+
constexpr bool has_cutlass_conj_v = has_cutlass_conj<T>::value;
|
| 757 |
+
|
| 758 |
+
} // namespace detail
|
| 759 |
+
|
| 760 |
+
// Return the complex conjugate of the input.
|
| 761 |
+
//
|
| 762 |
+
// If the struct hasn't already been specialized for type T, then
|
| 763 |
+
//
|
| 764 |
+
// 1. for arithmetic types, return z;
|
| 765 |
+
//
|
| 766 |
+
// 2. for types where either (namespace-unqualified) conj(z) or
|
| 767 |
+
// cutlass::conj(z) is well formed, declare "using cutlass::conj;"
|
| 768 |
+
// and return conj(z); and
|
| 769 |
+
//
|
| 770 |
+
// 3. for everything else, return z.
|
| 771 |
+
//
|
| 772 |
+
// Regarding (1), the C++ Standard Library makes std::conj always
|
| 773 |
+
// return std::complex, even for (noncomplex) arithmetic types.
|
| 774 |
+
// cutlass::conj(T t) needs to return type T. This follows the
|
| 775 |
+
// convention of linear algebra software like the BLAS, where
|
| 776 |
+
// "conjugate transpose" means the same thing as "transpose" for a
|
| 777 |
+
// matrix of noncomplex numbers.
|
| 778 |
+
//
|
| 779 |
+
// Case (2) covers std::complex, cuda::std::complex, and non-Standard
|
| 780 |
+
// (including user-defined) complex number types (for which "conj(z)"
|
| 781 |
+
// is findable via argument-dependent lookup). cutlass::conj has a
|
| 782 |
+
// totally generic overload, but a more type-specific overload in any
|
| 783 |
+
// namespace will take precedence.
|
| 784 |
+
//
|
| 785 |
+
// Case (3) covers non-Standard non-complex number types.
|
| 786 |
+
//
|
| 787 |
+
// Users should not generally need to specialize this struct for their
|
| 788 |
+
// own custom complex or noncomplex types. The idiomatic way to
|
| 789 |
+
// identify a type T as "complex" is to make namespace-unqualified
|
| 790 |
+
// calls to conj(T) findable via argument-dependent lookup.
|
| 791 |
+
template <typename T>
|
| 792 |
+
struct conjugate {
|
| 793 |
+
CUTLASS_HOST_DEVICE
|
| 794 |
+
T operator()(T const& z) const {
|
| 795 |
+
if constexpr (cutlass::platform::is_arithmetic_v<T>) {
|
| 796 |
+
return z;
|
| 797 |
+
}
|
| 798 |
+
else if constexpr (detail::has_unqualified_conj_v<T> || detail::has_cutlass_conj_v<T>) {
|
| 799 |
+
using cutlass::conj;
|
| 800 |
+
return conj(z);
|
| 801 |
+
}
|
| 802 |
+
else {
|
| 803 |
+
return z;
|
| 804 |
+
}
|
| 805 |
+
}
|
| 806 |
+
};
|
| 807 |
+
|
| 808 |
+
template <typename T>
|
| 809 |
+
struct first {
|
| 810 |
+
CUTLASS_HOST_DEVICE
|
| 811 |
+
T operator()(T const & first, T const &...) const {
|
| 812 |
+
return first;
|
| 813 |
+
}
|
| 814 |
+
CUTLASS_HOST_DEVICE
|
| 815 |
+
T operator()(T const & first) const {
|
| 816 |
+
return first;
|
| 817 |
+
}
|
| 818 |
+
};
|
| 819 |
+
|
| 820 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 821 |
+
|
| 822 |
+
template <typename T>
|
| 823 |
+
struct logical_and {
|
| 824 |
+
CUTLASS_HOST_DEVICE
|
| 825 |
+
T operator()(T const &a, T const &b) const {
|
| 826 |
+
return ((static_cast<bool>(a) && static_cast<bool>(b)) ? T(1) : T());
|
| 827 |
+
}
|
| 828 |
+
};
|
| 829 |
+
|
| 830 |
+
template <typename T>
|
| 831 |
+
struct logical_or {
|
| 832 |
+
CUTLASS_HOST_DEVICE
|
| 833 |
+
T operator()(T const &a, T const &b) const {
|
| 834 |
+
return ((static_cast<bool>(a) || static_cast<bool>(b)) ? T(1) : T());
|
| 835 |
+
}
|
| 836 |
+
};
|
| 837 |
+
|
| 838 |
+
template <typename T>
|
| 839 |
+
struct logical_not {
|
| 840 |
+
CUTLASS_HOST_DEVICE
|
| 841 |
+
T operator()(T const &a) const {
|
| 842 |
+
return T(!(a));
|
| 843 |
+
}
|
| 844 |
+
};
|
| 845 |
+
|
| 846 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 847 |
+
|
| 848 |
+
template <typename T>
|
| 849 |
+
struct bit_and {
|
| 850 |
+
CUTLASS_HOST_DEVICE
|
| 851 |
+
T operator()(T const &a, T const &b) const {
|
| 852 |
+
return a & b;
|
| 853 |
+
}
|
| 854 |
+
};
|
| 855 |
+
|
| 856 |
+
template <typename T>
|
| 857 |
+
struct bit_or {
|
| 858 |
+
CUTLASS_HOST_DEVICE
|
| 859 |
+
T operator()(T const &a, T const &b) const {
|
| 860 |
+
return a | b;
|
| 861 |
+
}
|
| 862 |
+
};
|
| 863 |
+
|
| 864 |
+
template <typename T>
|
| 865 |
+
struct bit_not {
|
| 866 |
+
CUTLASS_HOST_DEVICE
|
| 867 |
+
T operator()(T const &a) const {
|
| 868 |
+
return ~a;
|
| 869 |
+
}
|
| 870 |
+
};
|
| 871 |
+
|
| 872 |
+
template <typename T>
|
| 873 |
+
struct bit_xor {
|
| 874 |
+
CUTLASS_HOST_DEVICE
|
| 875 |
+
T operator()(T const &a, T const &b) const {
|
| 876 |
+
return a ^ b;
|
| 877 |
+
}
|
| 878 |
+
};
|
| 879 |
+
|
| 880 |
+
//////////////////////////////////////////////////////////////////////////////////////////////////
|
| 881 |
+
/// Atomic reductions
|
| 882 |
+
|
| 883 |
+
template <typename T>
|
| 884 |
+
struct atomic_add
|
| 885 |
+
{
|
| 886 |
+
CUTLASS_DEVICE
|
| 887 |
+
void operator()(T *ptr, const T &data)
|
| 888 |
+
{
|
| 889 |
+
#if defined(__CUDA_ARCH__)
|
| 890 |
+
atomicAdd(ptr, data);
|
| 891 |
+
#else
|
| 892 |
+
CUTLASS_UNUSED(ptr);
|
| 893 |
+
CUTLASS_UNUSED(data);
|
| 894 |
+
CUTLASS_NOT_IMPLEMENTED();
|
| 895 |
+
#endif
|
| 896 |
+
}
|
| 897 |
+
};
|
| 898 |
+
|
| 899 |
+
template<>
|
| 900 |
+
struct atomic_add<double>
|
| 901 |
+
{
|
| 902 |
+
CUTLASS_DEVICE
|
| 903 |
+
void operator()(double *ptr, const double &data)
|
| 904 |
+
{
|
| 905 |
+
#if !defined(__CUDA_ARCH__)
|
| 906 |
+
CUTLASS_UNUSED(ptr);
|
| 907 |
+
CUTLASS_UNUSED(data);
|
| 908 |
+
CUTLASS_NOT_IMPLEMENTED();
|
| 909 |
+
#elif (__CUDA_ARCH__ >= 600)
|
| 910 |
+
atomicAdd(ptr, data);
|
| 911 |
+
#else
|
| 912 |
+
// Use CAS loop
|
| 913 |
+
unsigned long long int* ptr_int = reinterpret_cast<unsigned long long int*>(ptr);
|
| 914 |
+
unsigned long long int old_int = *ptr_int;
|
| 915 |
+
unsigned long long int assumed_int;
|
| 916 |
+
|
| 917 |
+
do {
|
| 918 |
+
double update = data + __longlong_as_double(old_int);
|
| 919 |
+
assumed_int = old_int;
|
| 920 |
+
old_int = atomicCAS(ptr_int, assumed_int, __double_as_longlong(update));
|
| 921 |
+
} while (assumed_int != old_int);
|
| 922 |
+
#endif // (__CUDA_ARCH__ >= 600)
|
| 923 |
+
}
|
| 924 |
+
};
|
| 925 |
+
|
| 926 |
+
template<>
|
| 927 |
+
struct atomic_add<half2>
|
| 928 |
+
{
|
| 929 |
+
CUTLASS_DEVICE
|
| 930 |
+
void operator()(half2 *ptr, const half2 &data)
|
| 931 |
+
{
|
| 932 |
+
#if !defined(__CUDA_ARCH__) || (defined(__CUDA_ARCH__) && (__CUDA_ARCH__ < 600))
|
| 933 |
+
CUTLASS_UNUSED(ptr);
|
| 934 |
+
CUTLASS_UNUSED(data);
|
| 935 |
+
CUTLASS_NOT_IMPLEMENTED();
|
| 936 |
+
#else
|
| 937 |
+
// Vector-2 atomic reduction requires .target sm_60 or higher
|
| 938 |
+
uint32_t word = reinterpret_cast<const uint32_t&>(data);
|
| 939 |
+
asm volatile ("red.gpu.global.add.noftz.f16x2 [%0], %1;\n" : : "l"(ptr), "r"(word));
|
| 940 |
+
#endif // (__CUDA_ARCH__ >= 600)
|
| 941 |
+
}
|
| 942 |
+
};
|
| 943 |
+
|
| 944 |
+
template <typename T>
|
| 945 |
+
using red [[deprecated("use atomic_add instead")]] = atomic_add<T>;
|
| 946 |
+
|
| 947 |
+
template <typename T>
|
| 948 |
+
struct atomic_maximum {
|
| 949 |
+
CUTLASS_DEVICE
|
| 950 |
+
T operator()(T *ptr, T value) const {
|
| 951 |
+
#if defined(__CUDA_ARCH__)
|
| 952 |
+
return atomicMax(ptr, value);
|
| 953 |
+
#else
|
| 954 |
+
CUTLASS_UNUSED(ptr);
|
| 955 |
+
CUTLASS_UNUSED(value);
|
| 956 |
+
CUTLASS_NOT_IMPLEMENTED();
|
| 957 |
+
return 0;
|
| 958 |
+
#endif
|
| 959 |
+
}
|
| 960 |
+
};
|
| 961 |
+
|
| 962 |
+
template <>
|
| 963 |
+
struct atomic_maximum<float> {
|
| 964 |
+
CUTLASS_DEVICE
|
| 965 |
+
float operator()(float *ptr, float value) const {
|
| 966 |
+
#if defined(__CUDA_ARCH__)
|
| 967 |
+
// In device code, make sure that we do NOT try to use
|
| 968 |
+
// std::signbit, as that won't work if building with NVRTC.
|
| 969 |
+
// Instead, prefix "::" to call signbit from the global namespace,
|
| 970 |
+
// which CUDA guarantees to work in device code without including
|
| 971 |
+
// any headers.
|
| 972 |
+
//
|
| 973 |
+
return ! ::signbit(value) ?
|
| 974 |
+
__int_as_float(atomicMax((int*)ptr, __float_as_int(value))) :
|
| 975 |
+
__uint_as_float(atomicMin((unsigned int*)ptr, __float_as_uint(value)));
|
| 976 |
+
#else
|
| 977 |
+
CUTLASS_UNUSED(ptr);
|
| 978 |
+
CUTLASS_UNUSED(value);
|
| 979 |
+
CUTLASS_NOT_IMPLEMENTED();
|
| 980 |
+
return 0;
|
| 981 |
+
#endif
|
| 982 |
+
}
|
| 983 |
+
};
|
| 984 |
+
|
| 985 |
+
// is_atomic
|
| 986 |
+
template <class Fn>
|
| 987 |
+
struct is_atomic : platform::false_type {};
|
| 988 |
+
template <class T>
|
| 989 |
+
struct is_atomic<atomic_add<T>> : platform::true_type {};
|
| 990 |
+
template <class T>
|
| 991 |
+
struct is_atomic<atomic_maximum<T>> : platform::true_type {};
|
| 992 |
+
|
| 993 |
+
|
| 994 |
+
//////////////////////////////////////////////////////////////////////////////////////////////////
|
| 995 |
+
/// Parallel Synchronization and Communication Instructions
|
| 996 |
+
template <typename T>
|
| 997 |
+
struct redux_abs_max_nan_propagation_sync_warp;
|
| 998 |
+
|
| 999 |
+
template <>
|
| 1000 |
+
struct redux_abs_max_nan_propagation_sync_warp <float>{
|
| 1001 |
+
CUTLASS_DEVICE
|
| 1002 |
+
float operator()(float const &lhs) const {
|
| 1003 |
+
#if defined(CUTLASS_ARCH_CREDUX_ENABLED)
|
| 1004 |
+
float result;
|
| 1005 |
+
asm volatile("redux.sync.max.abs.NaN.f32 %0, %1, 0xffffffff;\n" : "=f"(result) : "f"(lhs));
|
| 1006 |
+
return result;
|
| 1007 |
+
#elif defined(__CUDA_ARCH__)
|
| 1008 |
+
cutlass::maximum<float, /*PropagateNaN*/true> max_op;
|
| 1009 |
+
int shuffle_width = 32;
|
| 1010 |
+
float abs_max = cutlass::absolute_value_op<float>{}(lhs);
|
| 1011 |
+
CUTLASS_PRAGMA_UNROLL
|
| 1012 |
+
for(int offset = shuffle_width / 2; offset > 0; offset /= 2) {
|
| 1013 |
+
float value = __shfl_down_sync(0xffffffff, abs_max, offset, shuffle_width);
|
| 1014 |
+
abs_max = max_op(abs_max,value);
|
| 1015 |
+
}
|
| 1016 |
+
// Broadcast the maximum to all threads participating in the reduction.
|
| 1017 |
+
abs_max = __shfl_sync(0xffffffff, abs_max, 0, shuffle_width);
|
| 1018 |
+
return abs_max;
|
| 1019 |
+
#else
|
| 1020 |
+
CUTLASS_UNUSED(lhs);
|
| 1021 |
+
CUTLASS_NOT_IMPLEMENTED();
|
| 1022 |
+
return 0;
|
| 1023 |
+
#endif
|
| 1024 |
+
}
|
| 1025 |
+
};
|
| 1026 |
+
|
| 1027 |
+
template <typename T>
|
| 1028 |
+
struct redux_abs_max_nan_propagation_sync_warp_t0t15_t16t31;
|
| 1029 |
+
|
| 1030 |
+
template <>
|
| 1031 |
+
struct redux_abs_max_nan_propagation_sync_warp_t0t15_t16t31<float>{
|
| 1032 |
+
CUTLASS_DEVICE
|
| 1033 |
+
float operator()(float const &max) const {
|
| 1034 |
+
#if defined(CUTLASS_ARCH_CREDUX_ENABLED)
|
| 1035 |
+
int half_warp_idx = threadIdx.x / (NumThreadsPerWarp / 2);
|
| 1036 |
+
bool first_half_threads = (half_warp_idx % 2) == 0;
|
| 1037 |
+
float value0 = first_half_threads ? max : 0;
|
| 1038 |
+
float v0 = cutlass::redux_abs_max_nan_propagation_sync_warp<float>{}(value0);
|
| 1039 |
+
|
| 1040 |
+
float value1 = !first_half_threads ? max : 0;
|
| 1041 |
+
float v1 = cutlass::redux_abs_max_nan_propagation_sync_warp<float>{}(value1);
|
| 1042 |
+
return first_half_threads ? v0: v1;
|
| 1043 |
+
|
| 1044 |
+
#elif defined(__CUDA_ARCH__)
|
| 1045 |
+
float abs_max = cutlass::absolute_value_op<float>{}(max);
|
| 1046 |
+
cutlass::maximum<float, /*PropagateNaN*/true> max_op;
|
| 1047 |
+
constexpr int shuffle_width = 16;
|
| 1048 |
+
CUTLASS_PRAGMA_UNROLL
|
| 1049 |
+
for(int offset = shuffle_width/2; offset > 0; offset /= 2) {
|
| 1050 |
+
float value = __shfl_down_sync(0xffffffff, abs_max, offset, shuffle_width);
|
| 1051 |
+
abs_max = max_op(abs_max,value);
|
| 1052 |
+
}
|
| 1053 |
+
// Broadcast the maximum to all threads participating in the reduction.
|
| 1054 |
+
abs_max = __shfl_sync(0xffffffff, abs_max, 0, shuffle_width);
|
| 1055 |
+
return abs_max;
|
| 1056 |
+
#else
|
| 1057 |
+
CUTLASS_UNUSED(max);
|
| 1058 |
+
CUTLASS_NOT_IMPLEMENTED();
|
| 1059 |
+
return 0;
|
| 1060 |
+
#endif
|
| 1061 |
+
}
|
| 1062 |
+
};
|
| 1063 |
+
|
| 1064 |
+
|
| 1065 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1066 |
+
//
|
| 1067 |
+
// Partial specializations for nvcuda::wmma::fragment<Use, m, n, k, T, Layout>
|
| 1068 |
+
//
|
| 1069 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1070 |
+
|
| 1071 |
+
#if defined(CUTLASS_ARCH_WMMA_ENABLED)
|
| 1072 |
+
|
| 1073 |
+
template<typename Use, int m, int n, int k, typename T, typename Layout>
|
| 1074 |
+
struct plus<nvcuda::wmma::fragment<Use, m, n, k, T, Layout>>
|
| 1075 |
+
{
|
| 1076 |
+
using Fragment = nvcuda::wmma::fragment<Use, m, n, k, T, Layout>;
|
| 1077 |
+
using ElementType = typename Fragment::element_type;
|
| 1078 |
+
|
| 1079 |
+
CUTLASS_HOST_DEVICE
|
| 1080 |
+
Fragment operator()(Fragment const &lhs, Fragment const &rhs) const
|
| 1081 |
+
{
|
| 1082 |
+
Fragment result;
|
| 1083 |
+
plus<ElementType> scalar_op;
|
| 1084 |
+
|
| 1085 |
+
ElementType *result_elts = reinterpret_cast<ElementType*>(&result);
|
| 1086 |
+
const ElementType *lhs_elts = reinterpret_cast<const ElementType*>(&lhs);
|
| 1087 |
+
const ElementType *rhs_elts = reinterpret_cast<const ElementType*>(&rhs);
|
| 1088 |
+
|
| 1089 |
+
CUTLASS_PRAGMA_UNROLL
|
| 1090 |
+
for (int i = 0; i < Fragment::num_elements; i++) {
|
| 1091 |
+
result_elts[i] = scalar_op(lhs_elts[i], rhs_elts[i]);
|
| 1092 |
+
}
|
| 1093 |
+
|
| 1094 |
+
return result;
|
| 1095 |
+
}
|
| 1096 |
+
};
|
| 1097 |
+
|
| 1098 |
+
#endif // defined(CUTLASS_ARCH_WMMA_ENABLED)
|
| 1099 |
+
|
| 1100 |
+
|
| 1101 |
+
|
| 1102 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 1103 |
+
|
| 1104 |
+
} // namespace cutlass
|
| 1105 |
+
|
| 1106 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/gemm/collective/collective_builder.hpp
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 34 |
+
#include "cutlass/gemm/collective/collective_mma_decl.hpp"
|
| 35 |
+
#include "cutlass/gemm/collective/collective_mma.hpp"
|
| 36 |
+
|
| 37 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 38 |
+
|
| 39 |
+
#include "cutlass/gemm/collective/collective_builder_decl.hpp"
|
| 40 |
+
#include "cutlass/gemm/collective/builders/sm90_gmma_builder.inl"
|
| 41 |
+
#include "cutlass/gemm/collective/builders/sm90_sparse_gmma_builder.inl"
|
| 42 |
+
#if !defined(__CUDACC_RTC__)
|
| 43 |
+
#include "cutlass/gemm/collective/builders/sm100_umma_builder.inl"
|
| 44 |
+
#include "cutlass/gemm/collective/builders/sm100_9xBF16_umma_builder.inl"
|
| 45 |
+
#include "cutlass/gemm/collective/builders/sm100_sparse_umma_builder.inl"
|
| 46 |
+
#include "cutlass/gemm/collective/builders/sm100_blockscaled_umma_builder.inl"
|
| 47 |
+
#include "cutlass/gemm/collective/builders/sm100_blockwise_umma_builder.inl"
|
| 48 |
+
#include "cutlass/gemm/collective/builders/sm100_blockscaled_sparse_umma_builder.inl"
|
| 49 |
+
#include "cutlass/gemm/collective/builders/sm100_simt_builder.inl"
|
| 50 |
+
#include "cutlass/gemm/collective/builders/sm100_mixed_input_umma_builder.inl"
|
| 51 |
+
#include "cutlass/gemm/collective/builders/sm100_cpasync_umma_builder.inl"
|
| 52 |
+
#include "cutlass/gemm/collective/builders/sm100_mixed_tma_cpasync_umma_builder.inl"
|
| 53 |
+
#include "cutlass/gemm/collective/builders/sm100_blockscaled_mixed_tma_cpasync_umma_builder.inl"
|
| 54 |
+
#include "cutlass/gemm/collective/builders/sm103_blockscaled_umma_builder.inl"
|
| 55 |
+
#include "cutlass/gemm/collective/builders/sm120_mma_builder.inl"
|
| 56 |
+
#include "cutlass/gemm/collective/builders/sm120_blockscaled_mma_builder.inl"
|
| 57 |
+
#include "cutlass/gemm/collective/builders/sm120_sparse_mma_builder.inl"
|
| 58 |
+
#include "cutlass/gemm/collective/builders/sm120_blockscaled_sparse_mma_builder.inl"
|
| 59 |
+
#include "cutlass/gemm/collective/builders/sm120_blockwise_mma_builder.inl"
|
| 60 |
+
#endif
|
| 61 |
+
|
| 62 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/gemm/collective/collective_builder_decl.hpp
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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/numeric/integral_constant.hpp>
|
| 34 |
+
#include <cutlass/detail/dependent_false.hpp>
|
| 35 |
+
|
| 36 |
+
namespace cutlass::gemm::collective {
|
| 37 |
+
|
| 38 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 39 |
+
|
| 40 |
+
// Used to specify stage counts or dispatch to automatic computation of stage count
|
| 41 |
+
template<int num_stages>
|
| 42 |
+
struct StageCount {
|
| 43 |
+
static constexpr int value = num_stages;
|
| 44 |
+
|
| 45 |
+
StageCount() = default;
|
| 46 |
+
explicit StageCount(cute::Int<num_stages>) {}
|
| 47 |
+
};
|
| 48 |
+
|
| 49 |
+
template<int carveout_bytes>
|
| 50 |
+
struct StageCountAutoCarveout {
|
| 51 |
+
static constexpr int bytes = carveout_bytes;
|
| 52 |
+
|
| 53 |
+
StageCountAutoCarveout() = default;
|
| 54 |
+
explicit StageCountAutoCarveout(cute::Int<carveout_bytes>) {}
|
| 55 |
+
};
|
| 56 |
+
|
| 57 |
+
namespace detail {
|
| 58 |
+
|
| 59 |
+
// Forward Declaration
|
| 60 |
+
template<class CollectiveEpilogue>
|
| 61 |
+
constexpr int
|
| 62 |
+
compute_carveout_from_epi();
|
| 63 |
+
|
| 64 |
+
} // namespace detail
|
| 65 |
+
|
| 66 |
+
template<class CollectiveEpilogue>
|
| 67 |
+
struct StageCountAutoCarveoutEpi : StageCountAutoCarveout<detail::compute_carveout_from_epi<CollectiveEpilogue>()> {};
|
| 68 |
+
|
| 69 |
+
using StageCountAuto = StageCountAutoCarveout<0>;
|
| 70 |
+
|
| 71 |
+
// Used to automatically let the builder pick the kernel schedule.
|
| 72 |
+
// Can be overridden with kernel schedule tags in cutlass/gemm/dispatch_policy.hpp
|
| 73 |
+
struct KernelScheduleAuto final {};
|
| 74 |
+
|
| 75 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 76 |
+
|
| 77 |
+
template <
|
| 78 |
+
class ArchTag,
|
| 79 |
+
class OpClass,
|
| 80 |
+
class ElementA,
|
| 81 |
+
class GmemLayoutA,
|
| 82 |
+
int AlignmentA,
|
| 83 |
+
class ElementB,
|
| 84 |
+
class GmemLayoutB,
|
| 85 |
+
int AlignmentB,
|
| 86 |
+
class ElementAccumulator,
|
| 87 |
+
class TileShape_MNK,
|
| 88 |
+
class ClusterShape_MNK,
|
| 89 |
+
class StageCountType,
|
| 90 |
+
class KernelScheduleType,
|
| 91 |
+
class Enable = void
|
| 92 |
+
>
|
| 93 |
+
struct CollectiveBuilder {
|
| 94 |
+
static_assert(sizeof(ElementA) == 0, "Could not build a collective for given parameters.");
|
| 95 |
+
};
|
| 96 |
+
|
| 97 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 98 |
+
|
| 99 |
+
} // namespace cutlass::gemm::collective
|
| 100 |
+
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/gemm/collective/collective_mma.hpp
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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/gemm/collective/collective_mma_decl.hpp"
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 37 |
+
|
| 38 |
+
#include "cutlass/gemm/collective/sm70_mma_twostage.hpp"
|
| 39 |
+
#include "cutlass/gemm/collective/sm80_mma_multistage.hpp"
|
| 40 |
+
#include "cutlass/gemm/collective/sm80_mma_array_multistage.hpp"
|
| 41 |
+
#include "cutlass/gemm/collective/sm90_mma_multistage_gmma_ss_warpspecialized.hpp"
|
| 42 |
+
#include "cutlass/gemm/collective/sm90_mma_multistage_gmma_rs_warpspecialized.hpp"
|
| 43 |
+
#include "cutlass/gemm/collective/sm90_mma_tma_gmma_ss.hpp"
|
| 44 |
+
#include "cutlass/gemm/collective/sm90_mma_tma_gmma_rs_warpspecialized.hpp"
|
| 45 |
+
#include "cutlass/gemm/collective/sm90_mma_tma_gmma_rs_warpspecialized_mixed_input.hpp"
|
| 46 |
+
#include "cutlass/gemm/collective/sm90_mma_tma_gmma_ss_warpspecialized.hpp"
|
| 47 |
+
#include "cutlass/gemm/collective/sm90_sparse_mma_tma_gmma_ss_warpspecialized.hpp"
|
| 48 |
+
#include "cutlass/gemm/collective/sm90_sparse_mma_tma_gmma_ss_warpspecialized_fp8.hpp"
|
| 49 |
+
#include "cutlass/gemm/collective/sm90_mma_array_tma_gmma_ss_warpspecialized.hpp"
|
| 50 |
+
#include "cutlass/gemm/collective/sm90_mma_array_tma_gmma_rs_warpspecialized_mixed_input.hpp"
|
| 51 |
+
#include "cutlass/gemm/collective/sm90_mma_tma_gmma_ss_warpspecialized_fp8.hpp"
|
| 52 |
+
#include "cutlass/gemm/collective/sm90_mma_array_tma_gmma_ss_warpspecialized_fp8.hpp"
|
| 53 |
+
#include "cutlass/gemm/collective/sm90_mma_tma_gmma_ss_warpspecialized_fp8_blockwise_scaling.hpp"
|
| 54 |
+
#include "cutlass/gemm/collective/sm90_mma_array_tma_gmma_ss_warpspecialized_fp8_blockwise_scaling.hpp"
|
| 55 |
+
#if !defined(__CUDACC_RTC__)
|
| 56 |
+
#include "cutlass/gemm/collective/sm100_mma_warpspecialized.hpp"
|
| 57 |
+
#include "cutlass/gemm/collective/sm100_mma_array_warpspecialized.hpp"
|
| 58 |
+
#include "cutlass/gemm/collective/sm100_mma_warpspecialized_emulated.hpp"
|
| 59 |
+
#include "cutlass/gemm/collective/sm100_mma_array_warpspecialized_emulated.hpp"
|
| 60 |
+
#include "cutlass/gemm/collective/sm100_sparse_mma_warpspecialized.hpp"
|
| 61 |
+
#include "cutlass/gemm/collective/sm100_blockscaled_sparse_mma_warpspecialized.hpp"
|
| 62 |
+
#include "cutlass/gemm/collective/sm100_blockscaled_mma_warpspecialized.hpp"
|
| 63 |
+
#include "cutlass/gemm/collective/sm100_blockscaled_mma_array_warpspecialized.hpp"
|
| 64 |
+
#include "cutlass/gemm/collective/sm100_mma_warpspecialized_blockwise_scaling.hpp"
|
| 65 |
+
#include "cutlass/gemm/collective/sm100_mma_array_warpspecialized_blockwise_scaling.hpp"
|
| 66 |
+
#include "cutlass/gemm/collective/sm100_mma_warpspecialized_mixed_input.hpp"
|
| 67 |
+
#include "cutlass/gemm/collective/sm100_mma_cpasync_warpspecialized.hpp"
|
| 68 |
+
#include "cutlass/gemm/collective/sm100_mma_mixed_tma_cpasync_warpspecialized.hpp"
|
| 69 |
+
#include "cutlass/gemm/collective/sm100_blockscaled_mma_mixed_tma_cpasync_warpspecialized.hpp"
|
| 70 |
+
#include "cutlass/gemm/collective/sm103_blockscaled_mma_warpspecialized.hpp"
|
| 71 |
+
#include "cutlass/gemm/collective/sm103_blockscaled_mma_array_warpspecialized.hpp"
|
| 72 |
+
#include "cutlass/gemm/collective/sm120_mma_tma.hpp"
|
| 73 |
+
#include "cutlass/gemm/collective/sm120_blockscaled_mma_tma.hpp"
|
| 74 |
+
#include "cutlass/gemm/collective/sm120_blockscaled_mma_array_tma.hpp"
|
| 75 |
+
#include "cutlass/gemm/collective/sm120_sparse_mma_tma.hpp"
|
| 76 |
+
#include "cutlass/gemm/collective/sm120_blockscaled_sparse_mma_tma.hpp"
|
| 77 |
+
#include "cutlass/gemm/collective/sm120_mma_tma_blockwise_scaling.hpp"
|
| 78 |
+
#include "cutlass/gemm/collective/sm120_mma_array_tma_blockwise_scaling.hpp"
|
| 79 |
+
#endif // !defined(__CUDACC_RTC__)
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/gemm/collective/collective_mma_decl.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/numeric/integral_constant.hpp>
|
| 34 |
+
#include <cutlass/detail/dependent_false.hpp>
|
| 35 |
+
|
| 36 |
+
namespace cutlass::gemm::collective {
|
| 37 |
+
|
| 38 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 39 |
+
|
| 40 |
+
template <
|
| 41 |
+
class DispatchPolicy,
|
| 42 |
+
class TileShape,
|
| 43 |
+
class ElementA,
|
| 44 |
+
class StrideA,
|
| 45 |
+
class ElementB,
|
| 46 |
+
class StrideB,
|
| 47 |
+
class TiledMma,
|
| 48 |
+
class GmemTiledCopyA,
|
| 49 |
+
class SmemLayoutAtomA,
|
| 50 |
+
class SmemCopyAtomA,
|
| 51 |
+
class TransformA,
|
| 52 |
+
class GmemTiledCopyB,
|
| 53 |
+
class SmemLayoutAtomB,
|
| 54 |
+
class SmemCopyAtomB,
|
| 55 |
+
class TransformB
|
| 56 |
+
>
|
| 57 |
+
struct CollectiveMma {
|
| 58 |
+
static_assert(cutlass::detail::dependent_false<ElementA>, "Could not find a mainloop specialization.");
|
| 59 |
+
};
|
| 60 |
+
|
| 61 |
+
/////////////////////////////////////////////////////////////////////////////////////////////////
|
| 62 |
+
|
| 63 |
+
} // namespace cutlass::gemm::collective
|
| 64 |
+
|
build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/gemm/collective/fp8_accumulation.hpp
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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/algorithm/clear.hpp"
|
| 35 |
+
#include "cute/tensor.hpp"
|
| 36 |
+
|
| 37 |
+
//////////////////////////////////////////////////////////////////////////////
|
| 38 |
+
///////////////////////////////////FP8 Accumulation///////////////////////////
|
| 39 |
+
//////////////////////////////////////////////////////////////////////////////
|
| 40 |
+
/// This class provides API to promote (add) or scale (multiply_add) the results
|
| 41 |
+
/// from the tensor core accumulators to the main accumulators when the number
|
| 42 |
+
/// of MMAs reaches the max number of MMA interval specified by user, after that
|
| 43 |
+
/// the tensor core accumulators are zeroed.
|
| 44 |
+
//////////////////////////////////////////////////////////////////////////////
|
| 45 |
+
|
| 46 |
+
namespace cutlass::gemm::collective {
|
| 47 |
+
|
| 48 |
+
template <
|
| 49 |
+
class EngineAccum,
|
| 50 |
+
class LayoutAccum>
|
| 51 |
+
struct GmmaFP8Accumulation {
|
| 52 |
+
using TensorAccum = cute::Tensor<EngineAccum, LayoutAccum>;
|
| 53 |
+
using ElementAccumulator = typename EngineAccum::value_type;
|
| 54 |
+
|
| 55 |
+
static_assert(is_static<LayoutAccum>::value, "Accumulator Layout should be static");
|
| 56 |
+
static_assert(is_rmem<TensorAccum>::value , "Accumulator tensor must be rmem resident.");
|
| 57 |
+
|
| 58 |
+
private:
|
| 59 |
+
TensorAccum& accum_;
|
| 60 |
+
TensorAccum accum_temp_;
|
| 61 |
+
|
| 62 |
+
uint32_t accum_promotion_interval_; // defines the max num of executed MMAs after which accum should be promoted.
|
| 63 |
+
uint32_t mma_count_per_mainloop_iteration_; // num of MMAs per k_tile of mainloop
|
| 64 |
+
uint32_t mma_count_; // current executed MMAs
|
| 65 |
+
uint32_t reset_accum_flag_; // accum needs to be zeroed or not.
|
| 66 |
+
|
| 67 |
+
// promote or `add` the partial accumulators to main accumulator (FADD).
|
| 68 |
+
CUTLASS_DEVICE
|
| 69 |
+
void promote_core() {
|
| 70 |
+
warpgroup_wait<0>();
|
| 71 |
+
CUTLASS_PRAGMA_UNROLL
|
| 72 |
+
for (int i = 0; i < size(accum_); ++i) {
|
| 73 |
+
accum_(i) += accum_temp_(i);
|
| 74 |
+
}
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
// `multiply` scale the partial accumulators and `add` to main accumulator (FFMA).
|
| 78 |
+
CUTLASS_DEVICE
|
| 79 |
+
void scale_core(ElementAccumulator const &scale) {
|
| 80 |
+
CUTLASS_PRAGMA_UNROLL
|
| 81 |
+
for (int i = 0; i < size(accum_); ++i) {
|
| 82 |
+
accum_(i) += accum_temp_(i) * scale;
|
| 83 |
+
}
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
template <
|
| 87 |
+
class EngineScale,
|
| 88 |
+
class LayoutScale>
|
| 89 |
+
CUTLASS_DEVICE
|
| 90 |
+
void scale_core(const cute::Tensor<EngineScale, LayoutScale> &scale) {
|
| 91 |
+
using TensorScale = cute::Tensor<EngineScale, LayoutScale>;
|
| 92 |
+
|
| 93 |
+
static_assert(is_static<LayoutScale>::value, "Scale Layout should be static");
|
| 94 |
+
static_assert(is_rmem<TensorScale>::value , "Scale tensor must be rmem resident.");
|
| 95 |
+
|
| 96 |
+
static_assert(LayoutAccum{}.shape() == LayoutScale{}.shape(), "Accumulator and scale must have same shape.");
|
| 97 |
+
|
| 98 |
+
CUTLASS_PRAGMA_UNROLL
|
| 99 |
+
for (int i = 0; i < size(accum_); ++i) {
|
| 100 |
+
accum_(i) += accum_temp_(i) * scale(i);
|
| 101 |
+
}
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
template <
|
| 105 |
+
class EngineScaleA,
|
| 106 |
+
class LayoutScaleA,
|
| 107 |
+
class EngineScaleB,
|
| 108 |
+
class LayoutScaleB>
|
| 109 |
+
CUTLASS_DEVICE
|
| 110 |
+
void scale_core(const cute::Tensor<EngineScaleA, LayoutScaleA> &scaleA, const cute::Tensor<EngineScaleB, LayoutScaleB> &scaleB) {
|
| 111 |
+
using TensorScaleA = cute::Tensor<EngineScaleA, LayoutScaleA>;
|
| 112 |
+
using TensorScaleB = cute::Tensor<EngineScaleB, LayoutScaleB>;
|
| 113 |
+
|
| 114 |
+
static_assert(is_static<LayoutScaleA>::value, "ScaleA Layout should be static");
|
| 115 |
+
static_assert(is_static<LayoutScaleB>::value, "ScaleB Layout should be static");
|
| 116 |
+
static_assert(is_rmem<TensorScaleA>::value, "ScaleA tensor must be rmem resident.");
|
| 117 |
+
static_assert(is_rmem<TensorScaleB>::value, "ScaleB tensor must be rmem resident.");
|
| 118 |
+
|
| 119 |
+
static_assert(LayoutAccum{}.shape() == LayoutScaleA{}.shape(), "Accumulator and scaleA must have same shape.");
|
| 120 |
+
static_assert(LayoutAccum{}.shape() == LayoutScaleB{}.shape(), "Accumulator and scaleB must have same shape.");
|
| 121 |
+
|
| 122 |
+
CUTLASS_PRAGMA_UNROLL
|
| 123 |
+
for (int i = 0; i < size(accum_); ++i) {
|
| 124 |
+
accum_(i) += accum_temp_(i) * scaleA(i) * scaleB(i);
|
| 125 |
+
}
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
public:
|
| 129 |
+
CUTLASS_DEVICE
|
| 130 |
+
GmmaFP8Accumulation(
|
| 131 |
+
TensorAccum &accum,
|
| 132 |
+
uint32_t accum_promotion_interval,
|
| 133 |
+
uint32_t mma_count_per_mainloop_iteration)
|
| 134 |
+
: accum_(accum),
|
| 135 |
+
accum_promotion_interval_(accum_promotion_interval),
|
| 136 |
+
mma_count_per_mainloop_iteration_(mma_count_per_mainloop_iteration),
|
| 137 |
+
mma_count_(0),
|
| 138 |
+
reset_accum_flag_(0)
|
| 139 |
+
{
|
| 140 |
+
accum_temp_ = cute::make_fragment_like(accum);
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
//
|
| 144 |
+
// Methods (Common)
|
| 145 |
+
//
|
| 146 |
+
|
| 147 |
+
CUTLASS_DEVICE
|
| 148 |
+
TensorAccum& operator()() {
|
| 149 |
+
return accum_temp_;
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
/// prepare the MMA accumulators when initialization or zeroing is required.
|
| 153 |
+
CUTLASS_DEVICE
|
| 154 |
+
bool prepare_if_needed() {
|
| 155 |
+
return reset_accum_flag_;
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
//
|
| 159 |
+
// Methods (for FADD version)
|
| 160 |
+
//
|
| 161 |
+
|
| 162 |
+
/// promote (add) the results from the MMA accumulators to main accumulator if needed.
|
| 163 |
+
CUTLASS_DEVICE
|
| 164 |
+
void promote_if_needed() {
|
| 165 |
+
mma_count_ += mma_count_per_mainloop_iteration_;
|
| 166 |
+
reset_accum_flag_ = __shfl_sync(0xffffffff, mma_count_ == accum_promotion_interval_, 0);
|
| 167 |
+
if (reset_accum_flag_) {
|
| 168 |
+
promote_core();
|
| 169 |
+
mma_count_ = 0;
|
| 170 |
+
}
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
/// promote (add) the residue results from the MMA accumulators to main accumulator if needed.
|
| 174 |
+
CUTLASS_DEVICE
|
| 175 |
+
void promote_residue_if_needed() {
|
| 176 |
+
if (__shfl_sync(0xffffffff, mma_count_ > 0, 0)) {
|
| 177 |
+
promote_core();
|
| 178 |
+
}
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
//
|
| 182 |
+
// Methods (for FFMA version)
|
| 183 |
+
//
|
| 184 |
+
|
| 185 |
+
/// scale (multiply_add) the results from the MMA accumulators to main accumulator if needed.
|
| 186 |
+
CUTLASS_DEVICE
|
| 187 |
+
void scale_if_needed(ElementAccumulator const &scale) {
|
| 188 |
+
mma_count_ += mma_count_per_mainloop_iteration_;
|
| 189 |
+
reset_accum_flag_ = __shfl_sync(0xffffffff, mma_count_ == accum_promotion_interval_, 0);
|
| 190 |
+
if (reset_accum_flag_) {
|
| 191 |
+
scale_core(scale);
|
| 192 |
+
mma_count_ = 0;
|
| 193 |
+
}
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
template <
|
| 197 |
+
class EngineScale,
|
| 198 |
+
class LayoutScale>
|
| 199 |
+
CUTLASS_DEVICE
|
| 200 |
+
void scale_if_needed(const cute::Tensor<EngineScale, LayoutScale> &scale) {
|
| 201 |
+
mma_count_ += mma_count_per_mainloop_iteration_;
|
| 202 |
+
reset_accum_flag_ = __shfl_sync(0xffffffff, mma_count_ == accum_promotion_interval_, 0);
|
| 203 |
+
if (reset_accum_flag_) {
|
| 204 |
+
scale_core(scale);
|
| 205 |
+
mma_count_ = 0;
|
| 206 |
+
}
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
template <
|
| 210 |
+
class EngineScaleA,
|
| 211 |
+
class LayoutScaleA,
|
| 212 |
+
class EngineScaleB,
|
| 213 |
+
class LayoutScaleB>
|
| 214 |
+
CUTLASS_DEVICE
|
| 215 |
+
void scale_if_needed(const cute::Tensor<EngineScaleA, LayoutScaleA> &scaleA, const cute::Tensor<EngineScaleB, LayoutScaleB> &scaleB) {
|
| 216 |
+
mma_count_ += mma_count_per_mainloop_iteration_;
|
| 217 |
+
reset_accum_flag_ = __shfl_sync(0xffffffff, mma_count_ == accum_promotion_interval_, 0);
|
| 218 |
+
if (reset_accum_flag_) {
|
| 219 |
+
scale_core(scaleA, scaleB);
|
| 220 |
+
mma_count_ = 0;
|
| 221 |
+
}
|
| 222 |
+
}
|
| 223 |
+
|
| 224 |
+
/// scale (multiply_add) the results from the MMA accumulators to main accumulator without checking the counter.
|
| 225 |
+
CUTLASS_DEVICE
|
| 226 |
+
void scale(ElementAccumulator const &scale) {
|
| 227 |
+
scale_core(scale);
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
template <
|
| 231 |
+
class EngineScale,
|
| 232 |
+
class LayoutScale>
|
| 233 |
+
CUTLASS_DEVICE
|
| 234 |
+
void scale(const cute::Tensor<EngineScale, LayoutScale> &scale) {
|
| 235 |
+
scale_core(scale);
|
| 236 |
+
}
|
| 237 |
+
|
| 238 |
+
template <
|
| 239 |
+
class EngineScaleA,
|
| 240 |
+
class LayoutScaleA,
|
| 241 |
+
class EngineScaleB,
|
| 242 |
+
class LayoutScaleB>
|
| 243 |
+
CUTLASS_DEVICE
|
| 244 |
+
void scale(const cute::Tensor<EngineScaleA, LayoutScaleA> &scaleA, const cute::Tensor<EngineScaleB, LayoutScaleB> &scaleB) {
|
| 245 |
+
scale_core(scaleA, scaleB);
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
/// scale (multiply_add) the residue results from the MMA accumulators to main accumulator if needed.
|
| 249 |
+
CUTLASS_DEVICE
|
| 250 |
+
void scale_residue_if_needed(ElementAccumulator const &scale) {
|
| 251 |
+
if (__shfl_sync(0xffffffff, mma_count_ > 0, 0)) {
|
| 252 |
+
scale_core(scale);
|
| 253 |
+
}
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
template <
|
| 257 |
+
class EngineScale,
|
| 258 |
+
class LayoutScale>
|
| 259 |
+
CUTLASS_DEVICE
|
| 260 |
+
void scale_residue_if_needed(const cute::Tensor<EngineScale, LayoutScale> &scale) {
|
| 261 |
+
if (__shfl_sync(0xffffffff, mma_count_ > 0, 0)) {
|
| 262 |
+
scale_core(scale);
|
| 263 |
+
}
|
| 264 |
+
}
|
| 265 |
+
|
| 266 |
+
template <
|
| 267 |
+
class EngineScaleA,
|
| 268 |
+
class LayoutScaleA,
|
| 269 |
+
class EngineScaleB,
|
| 270 |
+
class LayoutScaleB>
|
| 271 |
+
CUTLASS_DEVICE
|
| 272 |
+
void scale_residue_if_needed(const cute::Tensor<EngineScaleA, LayoutScaleA> &scaleA, const cute::Tensor<EngineScaleB, LayoutScaleB> &scaleB) {
|
| 273 |
+
if (__shfl_sync(0xffffffff, mma_count_ > 0, 0)) {
|
| 274 |
+
scale_core(scaleA, scaleB);
|
| 275 |
+
}
|
| 276 |
+
}
|
| 277 |
+
};
|
| 278 |
+
|
| 279 |
+
} // namespace cutlass::gemm::collective
|