Kernels
danieldk HF Staff commited on
Commit
65bb2f7
·
verified ·
1 Parent(s): 3b163b3

Build uploaded using `kernels` (batch 3/10).

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +1 -0
  2. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/interleaved_epilogue.h +407 -0
  3. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/output_iterator_parameter.h +223 -0
  4. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/output_tile_thread_map.h +628 -0
  5. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator.h +1387 -0
  6. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_affine.h +615 -0
  7. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_affine_layout_params.h +156 -0
  8. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_blas3.h +633 -0
  9. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_conv.h +562 -0
  10. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_direct_conv.h +445 -0
  11. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_params.h +483 -0
  12. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_predicates.h +309 -0
  13. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/predicated_tile_iterator_strided_dgrad.h +479 -0
  14. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/shared_load_iterator.h +223 -0
  15. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/shared_load_iterator_mixed.h +594 -0
  16. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/threadblock/shared_load_iterator_pitch_linear.h +194 -0
  17. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/fragment_iterator_complex_tensor_op.h +187 -0
  18. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/fragment_iterator_gaussian_complex_tensor_op.h +194 -0
  19. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/fragment_iterator_simt.h +164 -0
  20. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/fragment_iterator_tensor_op.h +378 -0
  21. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/fragment_iterator_volta_tensor_op.h +269 -0
  22. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/fragment_iterator_wmma_tensor_op.h +158 -0
  23. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/simt_policy.h +107 -0
  24. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/tensor_op_policy.h +189 -0
  25. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/tile_iterator_simt.h +785 -0
  26. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/tile_iterator_tensor_op.h +671 -0
  27. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/tile_iterator_tensor_op_mixed.h +1089 -0
  28. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/tile_iterator_volta_tensor_op.h +440 -0
  29. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/tile_iterator_wmma_tensor_op.h +224 -0
  30. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/volta_tensor_op_policy.h +195 -0
  31. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/epilogue/warp/wmma_tensor_op_policy.h +101 -0
  32. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/exmy_base.h +1222 -0
  33. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/device/detail.hpp +163 -0
  34. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/device/dist_gemm_universal_wrapper.hpp +717 -0
  35. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/device/full_barrier.hpp +74 -0
  36. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/kernel/detail.hpp +72 -0
  37. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/kernel/dist_gemm_kernel_wrapper.hpp +235 -0
  38. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/kernel/full_barrier.hpp +82 -0
  39. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/schedules/dist_gemm_1d_schedules.hpp +324 -0
  40. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/experimental/distributed/schedules/dist_gemm_base_schedule.hpp +538 -0
  41. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/fast_math.h +1085 -0
  42. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/float8.h +1685 -0
  43. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/float_subbyte.h +797 -0
  44. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/floating_point_nvrtc.h +104 -0
  45. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/functional.h +1106 -0
  46. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/gemm/collective/collective_builder.hpp +62 -0
  47. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/gemm/collective/collective_builder_decl.hpp +100 -0
  48. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/gemm/collective/collective_mma.hpp +84 -0
  49. build/torch210-cxx11-cu128-aarch64-linux/include/third-party/cutlass/include/cutlass/gemm/collective/collective_mma_decl.hpp +64 -0
  50. 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 &quotient, 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 &quotient, 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 &quotient, 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 &quotient, 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