summaryrefslogtreecommitdiff
path: root/cutlass-example/cutlass/tile_iterator.h
diff options
context:
space:
mode:
authoraamir <[email protected]>2018-07-21 19:30:40 -0700
committeraamir <[email protected]>2018-07-21 19:30:40 -0700
commitfcf40649feb6046fb9b1ed984fb9b19422cd5463 (patch)
tree92b28621af353598ad3a49df70ebb596d1205609 /cutlass-example/cutlass/tile_iterator.h
parentb3ad8abea43b7d1e8887f57d6e30c5a40cf752a6 (diff)
adding the cutlass examples
Diffstat (limited to 'cutlass-example/cutlass/tile_iterator.h')
-rw-r--r--cutlass-example/cutlass/tile_iterator.h899
1 files changed, 899 insertions, 0 deletions
diff --git a/cutlass-example/cutlass/tile_iterator.h b/cutlass-example/cutlass/tile_iterator.h
new file mode 100644
index 0000000..5d39c4f
--- /dev/null
+++ b/cutlass-example/cutlass/tile_iterator.h
@@ -0,0 +1,899 @@
+/***************************************************************************************************
+ * Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted
+ * provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ **************************************************************************************************/
+/*! \file
+ \brief Defines the Tile Traits concept and iterators for loading and storing to tiles
+ efficiently.
+*/
+#pragma once
+
+#include <cutlass/fragment.h>
+#include <cutlass/load_store.h>
+#include <cutlass/predicate_vector.h>
+#include <cutlass/vector.h>
+
+namespace cutlass {
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+/*!@defgroup tile_traits_concept Tile Traits Concept
+@{
+
+\ref tile_traits_concept is a type definining the shape of a tile and the distribution of accesses
+by individual entities, either threads or other.
+
+@par Tile Traits Concept
+ Types satisfying \ref tile_traits_concept define the following members
+ - <b>Tile</b> - a type satisfying \ref layout_concept describing the dimensions of the tile
+ - <b>Delta</b> - a type satisfying \ref layout_concept describing the increments between accesses
+along each dimension
+ - <b>Iterations</b> - a type satisfying \ref layout_concept describing the number of accesses
+along each dimension
+ - <b>Offset</b> - the type of a <i>functor</i> computing the offset of each participating entity
+as a Coord<4>.
+@}
+*/
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+/// Specifies dimension in which post-increment accesses advance
+struct IteratorAdvance {
+ enum Kind { kD, kH, kW };
+};
+
+/// Specifies whether iterator storage fragment consists of Scalar values or WMMA matrix
+struct IteratorFragment {
+ enum Kind { kScalar, kWmmaMatrix };
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+* @brief A template defining \ref tile_traits_concept
+* @concept{tile_traits_concept}
+*/
+template <typename Tile_,
+ typename Delta_,
+ typename Iterations_,
+ typename ThreadOffset_,
+ int kAccessSize>
+struct TileTraits {
+ /// Shape of the tile
+ typedef Tile_ Tile;
+
+ /// Number of steps between accesses along each dimension
+ typedef Delta_ Delta;
+
+ /// Number of accesses performed
+ typedef Iterations_ Iterations;
+
+ /// Functor that returns the logical coordinate of each entity's initial offset in the tile
+ typedef ThreadOffset_ ThreadOffset;
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+/// Iterator for accessing a stripmined tile in memory
+template <typename Traits_,
+ typename Scalar_,
+ IteratorAdvance::Kind Advance_ = IteratorAdvance::kH,
+ MemorySpace::Kind MemorySpace = MemorySpace::kGeneric,
+ typename Index_ = int,
+ typename FragmentElement_ = Scalar_,
+ IteratorFragment::Kind IteratorFragment_ = IteratorFragment::kScalar,
+ typename Skew_ = Shape<0, 0, 0, 0> >
+struct TileIteratorBase {
+ /// concept TileTraits
+ typedef Traits_ Traits;
+
+ /// Scalar element
+ typedef Scalar_ Scalar;
+
+ /// Fragment element
+ typedef FragmentElement_ FragmentElement;
+
+ /// Specifies dimension in which post-increment accesses advance.
+ static IteratorAdvance::Kind const kAdvance = Advance_;
+
+ /// Specifies iterator storage fragment type (Scalar or WmmaMatrix)
+ static IteratorFragment::Kind const kIteratorFragment = IteratorFragment_;
+
+ /// Source or destination memory space
+ static MemorySpace::Kind const kMemorySpace = MemorySpace;
+
+ /// Index type
+ typedef Index_ Index;
+
+ /// Skew quantity
+ typedef Skew_ Skew;
+
+ /// Tile shape
+ typedef typename Traits::Tile Tile;
+
+ /// Distance along each dimension
+ typedef typename Traits::Delta Delta;
+
+ /// The strides in each dimension between different loads/stores.
+ typedef typename Traits::ImmediateOffsetStrides ImmediateOffsetStrides;
+
+ /// Iterations
+ typedef typename Traits::Iterations Iterations;
+
+ /// Thread offset
+ typedef typename Traits::ThreadOffset ThreadOffset;
+
+ /// The number of scalars accessed per load/store.
+ static int const kAccessSize = Tile::kC;
+
+ /// The elements loaded/store by one instruction.
+ typedef typename Vectorize<FragmentElement, kAccessSize>::Type AccessType;
+
+ /// The size of storage needed per fragment
+ static int const kFragmentSize =
+ (kIteratorFragment == IteratorFragment::kWmmaMatrix ? 16 : sizeof(AccessType));
+ /// The storage.
+ typedef Fragment<Scalar, ShapeCount<Tile>::kCount, kFragmentSize> Storage;
+ /// The fragment.
+ typedef Fragment<FragmentElement, ShapeCount<Iterations>::kCount * kAccessSize> Fragment;
+ /// The fragment iterator.
+ typedef FragmentIterator<Fragment, Iterations, AccessType> FragmentIterator;
+ /// The fragment const iterator.
+ typedef FragmentConstIterator<Fragment, Iterations, AccessType> FragmentConstIterator;
+ /// The shape of the fragment.
+ typedef typename FragmentIterator::FragmentShape FragmentShape;
+
+ /// Default predicate mask type
+ typedef PredicateVector<ShapeCount<Iterations>::kCount> PredicateVector;
+
+ //
+ // Params struct
+ //
+
+ /// Parameters to the iterator
+ struct Params {
+ Index stride_d;
+ Index stride_h;
+ Index stride_w;
+
+ Index inc_d;
+ Index inc_h;
+ Index inc_w;
+
+ Index inc_advance;
+
+ /// Initializes params
+ CUTLASS_HOST_DEVICE
+ int initialize(Index _stride_d,
+ Index _stride_h,
+ Index _stride_w,
+ Index _inc_d,
+ Index _inc_h,
+ Index _inc_w,
+ Index _inc_advance) {
+ stride_d = _stride_d;
+ stride_h = _stride_h;
+ stride_w = _stride_w;
+
+ inc_d = _inc_d;
+ inc_h = _inc_h;
+ inc_w = _inc_w;
+ inc_advance = _inc_advance;
+
+ return 0;
+ }
+
+ CUTLASS_HOST_DEVICE
+ int initialize(Index _stride_d, Index _stride_h, Index _stride_w) {
+ stride_d = _stride_d;
+ stride_h = _stride_h;
+ stride_w = _stride_w;
+
+ inc_w = stride_w * Delta::kW;
+ inc_h = stride_h * Delta::kH - stride_w * Delta::kW * (Iterations::kW - 1);
+
+ if (kAdvance == IteratorAdvance::kH) {
+ // Advance in the H dimension.
+ inc_d = 0;
+ } else if (kAdvance == IteratorAdvance::kW) {
+ // Advance in the W dimension.
+ inc_d = stride_w * Tile::kW - stride_h * Tile::kH;
+ } else {
+ // Advance in the D dimension.
+ inc_d = stride_d;
+ }
+
+ inc_advance = 0;
+
+ return 0;
+ }
+
+ CUTLASS_HOST_DEVICE int initialize() {
+ stride_d = 0;
+ stride_h = 0;
+ stride_w = 1;
+
+ inc_d = inc_h = inc_w = inc_advance = 0;
+
+ return 0;
+ }
+ };
+
+ /// Is the iterator valid?
+ CUTLASS_DEVICE bool valid(int d, int h, int w, int c) const { return true; }
+
+ //
+ // Static function members
+ //
+
+ /// Initializes a predicate vector
+ template <typename PredicateIterator>
+ CUTLASS_DEVICE static void initialize_predicates(PredicateIterator predicate_it,
+ Coord<3> const &bounds,
+ Coord<3> const &offset = make_Coord(0, 0, 0)) {
+ for (int d = 0; d < Iterations::kD; ++d) {
+ bool enable_d = (d * Delta::kD + offset[0] < bounds[0]);
+ for (int h = 0; h < Iterations::kH; ++h) {
+ bool enable_h = (h * Delta::kH + offset[1] < bounds[1]);
+ for (int w = 0; w < Iterations::kW; ++w) {
+ bool enable_w = (w * Tile::kC * Delta::kW + offset[2] < bounds[2]);
+ predicate_it.set(d, h, w, 0, enable_d && enable_h && enable_w);
+ }
+ }
+ }
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+/*!@defgroup tile_load_iterator_concept Tile Load Iterator Concept
+@{
+
+\ref tile_load_iterator_concept enables loading a tile from addressable memory into a fragment
+
+@par Tile Load Iterator Concept
+ Types satisfying \ref tile_load_iterator_concept define the following members
+ - <b>PredicateVector</b> - a \ref predicate_vector_concept with sufficient predicate storage for
+each access implied by the tile traits
+ - <b>Fragment</b> - the destination fragment type satisfying \ref fragment_concept
+ - <b>initialize_predicates(pred_it, bounds, block_offset)</b> - function initializing a predicate
+vector according to externally specified bounds
+ - <b>load_post_increment(fragment, pred_it)</b> - a method that loads a fragment and increments
+the iterator to the next tile, guarded by a \ref predicate_iterator_concept
+ - <b>load_post_increment(fragment)</b> - a method that loads a fragment and increments the
+iterator to the next tile
+ - <b>load(fragment, pred_it)</b> - a const method that loads a fragment, guarded by a \ref
+predicate_iterator_concept
+ - <b>load(fragment)</b> - a method that loads a fragment
+
+@}
+*/
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+* @brief An iterator implementing \ref tile_load_iterator_concept for loading a tile from memory
+* @concept{tile_load_iterator_concept}
+*/
+template <typename Traits_,
+ typename Scalar_,
+ IteratorAdvance::Kind Advance_ = IteratorAdvance::kH,
+ MemorySpace::Kind MemorySpace = MemorySpace::kGeneric,
+ typename Index_ = int,
+ typename FragmentElement_ = Scalar_,
+ IteratorFragment::Kind IteratorFragment_ = IteratorFragment::kScalar,
+ typename Skew_ = Shape<0, 0, 0, 0> >
+struct TileLoadIterator : public TileIteratorBase<Traits_,
+ Scalar_,
+ Advance_,
+ MemorySpace,
+ Index_,
+ FragmentElement_,
+ IteratorFragment_,
+ Skew_> {
+ /// Base class
+ typedef TileIteratorBase<Traits_,
+ Scalar_,
+ Advance_,
+ MemorySpace,
+ Index_,
+ FragmentElement_,
+ IteratorFragment_,
+ Skew_>
+ Base;
+
+ /// concept TileTraits
+ typedef typename Base::Traits Traits;
+
+ /// Scalar element
+ typedef typename Base::Scalar Scalar;
+
+ /// Fragment element
+ typedef typename Base::FragmentElement FragmentElement;
+
+ /// Specifies in which dimension post-increment accesses advance.
+ static IteratorAdvance::Kind const kAdvance = Base::kAdvance;
+
+ /// Specifies type of iterator fragment storage (Salar or WmmaMatrix)
+ static IteratorFragment::Kind const kIteratorFragment = Base::kIteratorFragment;
+
+ /// Source or destination memory space
+ static MemorySpace::Kind const kMemorySpace = Base::kMemorySpace;
+
+ /// Index type
+ typedef typename Base::Index Index;
+
+ /// Skew quantity
+ typedef typename Base::Skew Skew;
+
+ /// Tile shape
+ typedef typename Base::Tile Tile;
+
+ /// Delta
+ typedef typename Base::Delta Delta;
+
+ /// Iterations
+ typedef typename Base::Iterations Iterations;
+
+ /// ThreadOffset functor
+ typedef typename Base::ThreadOffset ThreadOffset;
+
+ /// Fragment type
+ typedef typename Base::FragmentShape FragmentShape;
+
+ /// Memory access type
+ typedef typename Base::AccessType AccessType;
+
+ /// Fragment definition
+ typedef typename Base::Fragment Fragment;
+
+ /// Fragment iterator definition
+ typedef typename Base::FragmentIterator FragmentIterator;
+
+ /// Fragment const iterator definition
+ typedef typename Base::FragmentConstIterator FragmentConstIterator;
+
+ /// Default predicate mask type
+ typedef typename Base::PredicateVector PredicateVector;
+
+ /// Storage object that may be loaded from
+ typedef typename Base::Storage SharedStorage;
+
+ /// IteratorBase parameters
+ typedef typename Base::Params BaseParams;
+
+ /// Do we require a fence?
+ enum { kRequiresLoadFence = Tile::kD == 1 };
+
+ /// The pointer type
+ typedef Scalar const *Pointer;
+
+ /// Parameters
+ struct Params : public BaseParams {
+ /// Pointer to memory
+ Scalar const *pointer;
+
+ /// Initialize params to access storage object
+ CUTLASS_HOST_DEVICE
+ int initialize(SharedStorage const &storage) {
+ pointer = &storage[0];
+ return 0;
+ }
+
+ /// Initializes params to access a raw pointer
+ CUTLASS_HOST_DEVICE
+ int initialize(Scalar const *ptr, Index stride_d, Index stride_h, Index stride_w) {
+ Base::Params::initialize(stride_d, stride_h, stride_w);
+ pointer = ptr;
+ return 0;
+ }
+
+ /// Initializes params
+ CUTLASS_HOST_DEVICE
+ int initialize(Scalar const *ptr,
+ Index _stride_d,
+ Index _stride_h,
+ Index _stride_w,
+ Index _inc_d,
+ Index _inc_h,
+ Index _inc_w,
+ Index _inc_advance) {
+ pointer = ptr;
+ Base::Params::initialize(
+ _stride_d, _stride_h, _stride_w, _inc_d, _inc_h, _inc_w, _inc_advance);
+ return 0;
+ }
+
+ // Initializes params to default values
+ CUTLASS_HOST_DEVICE
+ int initialize() { return Base::Params::initialize(); }
+ };
+
+ //
+ // Data members
+ //
+
+ /// Parameters structure
+ Params params;
+
+ /// Offset of an individual lane from the start of the tile
+ Coord<4> thread_offset;
+
+ /// Stage argument enables wrapping after some number of tiles have been loaded.
+ int stage;
+
+ //
+ // Static member functions
+ //
+
+ /// Initializes a predicate vector
+ template <typename PredicateIterator>
+ CUTLASS_HOST_DEVICE void initialize_predicates(PredicateIterator predicate_it,
+ Coord<3> const &bounds,
+ Coord<3> const &block_offset = make_Coord(0,
+ 0,
+ 0)) {
+ Base::initialize_predicates(
+ predicate_it,
+ bounds,
+ block_offset + make_Coord(0, thread_offset[1], thread_offset[2] * Tile::kC));
+ }
+
+ //
+ // Methods
+ //
+
+ /// Default constructor
+ CUTLASS_HOST_DEVICE
+ TileLoadIterator() {}
+
+ /// Constructs a tile load iterator
+ CUTLASS_HOST_DEVICE
+ TileLoadIterator(Params const &_params,
+ Coord<3> const &block_offset = make_Coord(0, 0, 0),
+ ThreadOffset thread_offset_func = ThreadOffset())
+ : params(_params), stage(0) {
+ thread_offset = thread_offset_func();
+
+ Index block_offset_h = 0;
+ Index block_offset_w = 0;
+ if (kAdvance == IteratorAdvance::kH) {
+ block_offset_h = block_offset[1];
+ block_offset_w = block_offset[2];
+ } else {
+ block_offset_h = block_offset[2];
+ block_offset_w = block_offset[1];
+ }
+
+ params.pointer += block_offset[0] * params.stride_d +
+ (block_offset_h + thread_offset[1]) * params.stride_h +
+ (block_offset_w + thread_offset[2] * Tile::kC) / Tile::kC * params.stride_w;
+ }
+
+ /// Constructs a tile load iterator
+ CUTLASS_HOST_DEVICE
+ TileLoadIterator(Params const &,
+ SharedStorage &shared_storage,
+ Coord<3> const &block_offset = make_Coord(0, 0, 0),
+ ThreadOffset thread_offset_func = ThreadOffset())
+ : stage(0) {
+ int const offset = thread_offset_func()[2];
+ params.pointer = &shared_storage[offset];
+ }
+
+ /// Returns the current pointer
+ CUTLASS_HOST_DEVICE
+ Scalar const *data() const { return params.pointer; }
+
+ /// The accessor.
+ CUTLASS_DEVICE void get(AccessType &value, int d, int h, int w, int c) const {
+ int const imm =
+ ComputeOffsetFromStrides<typename Base::ImmediateOffsetStrides>::get(d, h, w, c);
+ Load<Scalar, Base::kAccessSize, kMemorySpace>::load(value, params.pointer, imm);
+ }
+
+ /// Increment in the D dimension
+ CUTLASS_HOST_DEVICE void inc_d() { params.pointer += params.inc_d; }
+
+ /// Increment in the H dimension
+ CUTLASS_HOST_DEVICE void inc_h() { params.pointer += params.inc_h; }
+
+ /// Increment in the W dimension
+ CUTLASS_HOST_DEVICE void inc_w() { params.pointer += params.inc_w; }
+
+ /// Increment in the next dimension
+ CUTLASS_HOST_DEVICE void inc_advance() { params.pointer += params.inc_advance; }
+
+ /// Increment the stage.
+ CUTLASS_DEVICE void inc_stage() {
+ if (Tile::kD > 1) {
+ int const kStageSize = Tile::kH * Tile::kW * Tile::kC;
+ if (stage == Tile::kD - 1) {
+ params.pointer -= (Tile::kD - 1) * kStageSize;
+ stage = 0;
+ } else {
+ params.pointer += kStageSize;
+ stage = stage + 1;
+ }
+ }
+ }
+
+ public:
+ /// Loads a fragment and advances the iterator to the next tile.
+ template <typename Fragment, typename PredicateIterator>
+ CUTLASS_HOST_DEVICE void load_post_increment(Fragment &fragment, PredicateIterator pred_it) {
+ FragmentIterator frag_iterator(fragment);
+
+ for (int d = 0; d < Iterations::kD; ++d) {
+ for (int h = 0; h < Iterations::kH; ++h) {
+ for (int w = 0; w < Iterations::kW; ++w, ++pred_it) {
+ if (*pred_it) {
+ Load<typename Fragment::Element, Tile::kC, kMemorySpace>::load(
+ reinterpret_cast<AccessType &>(frag_iterator.at(d, h, w, 0)), data(), 0);
+ }
+
+ if (w < Iterations::kW - 1) {
+ inc_w();
+ }
+ }
+ if (h < Iterations::kH - 1) {
+ inc_h();
+ }
+ }
+ if (d < Iterations::kD - 1) {
+ inc_d();
+ }
+ }
+ inc_advance();
+ }
+
+ /// Loads a fragment and advances the iterator to the next tile.
+ template <typename Fragment>
+ CUTLASS_HOST_DEVICE void load_post_increment(Fragment &fragment) {
+ typename PredicateVector::TrivialIterator pred_it;
+ load_post_increment(fragment, pred_it);
+ }
+
+ /// Loads a fragment without advancing the iterator..
+ template <typename Fragment, typename PredicateIterator>
+ CUTLASS_HOST_DEVICE void load(Fragment &fragment, PredicateIterator pred_it) const {
+ TileLoadIterator _load_it(*this);
+ _load_it.load_post_increment(fragment, pred_it);
+ }
+
+ /// Loads a fragment without advancing the iterator..
+ template <typename Fragment>
+ CUTLASS_HOST_DEVICE void load(Fragment &fragment) const {
+ typename PredicateVector::TrivialIterator pred_it;
+ load(fragment, pred_it);
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+/*!@defgroup tile_store_iterator_concept Tile Store Iterator Concept
+@{
+
+\ref tile_store_iterator_concept enables storing a tile to addressable memory
+
+@par Tile Store Iterator Concept
+ Types satisfying \ref tile_load_iterator_concept define the following members
+ - <b>PredicateVector</b> - a \ref predicate_vector_concept with sufficient predicate storage for
+each access implied by the tile traits
+ - <b>Fragment</b> - the destination fragment type satisfying \ref fragment_concept
+ - <b>initialize_predicates(pred_it, bounds, block_offset)</b> - function initializing a predicate
+vector according to externally specified bounds
+ - <b>store_post_increment(fragment, pred_it)</b> - a method that stores a fragment and increments
+the iterator to the next tile, guarded by a \ref predicate_iterator_concept
+ - <b>store_post_increment(fragment)</b> - a method that stores a fragment and increments the
+iterator to the next tile
+ - <b>store(fragment, pred_it)</b> - a const method that stores a fragment, guarded by a \ref
+predicate_iterator_concept
+ - <b>store(fragment)</b> - a method that loads a fragment
+
+@}
+*/
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+* @brief An iterator implementing \ref tile_store_iterator_concept for storing a tile to memory
+* @concept{tile_store_iterator_concept}
+*/
+template <typename Traits_,
+ typename Scalar_,
+ IteratorAdvance::Kind Advance_ = IteratorAdvance::kH,
+ MemorySpace::Kind MemorySpace = MemorySpace::kGeneric,
+ typename Index_ = int,
+ typename FragmentElement_ = Scalar_,
+ IteratorFragment::Kind IteratorFragment_ = IteratorFragment::kScalar,
+ typename Skew_ = Shape<0, 0, 0, 0> >
+struct TileStoreIterator : public TileIteratorBase<Traits_,
+ Scalar_,
+ Advance_,
+ MemorySpace,
+ Index_,
+ FragmentElement_,
+ IteratorFragment_,
+ Skew_> {
+ /// Base class
+ typedef TileIteratorBase<Traits_,
+ Scalar_,
+ Advance_,
+ MemorySpace,
+ Index_,
+ FragmentElement_,
+ IteratorFragment_,
+ Skew_>
+ Base;
+
+ /// concept TileTraits
+ typedef typename Base::Traits Traits;
+
+ /// Scalar element
+ typedef typename Base::Scalar Scalar;
+
+ /// Fragment element
+ typedef typename Base::FragmentElement FragmentElement;
+
+ /// Specifies in which dimension post-increment accesses advance.
+ static IteratorAdvance::Kind const kAdvance = Base::kAdvance;
+
+ /// Specifies type of iterator fragment storage (Salar or WmmaMatrix)
+ static IteratorFragment::Kind const kIteratorFragment = Base::kIteratorFragment;
+
+ /// Source or destination memory space
+ static MemorySpace::Kind const kMemorySpace = Base::kMemorySpace;
+
+ /// Index type
+ typedef typename Base::Index Index;
+
+ /// Skew quantity
+ typedef typename Base::Skew Skew;
+
+ /// Tile shape
+ typedef typename Base::Tile Tile;
+
+ /// Delta
+ typedef typename Base::Delta Delta;
+
+ /// Iterations
+ typedef typename Base::Iterations Iterations;
+
+ /// ThreadOffset functor
+ typedef typename Base::ThreadOffset ThreadOffset;
+
+ /// Fragment type
+ typedef typename Base::FragmentShape FragmentShape;
+
+ /// Memory access type
+ typedef typename Base::AccessType AccessType;
+
+ /// Fragment definition
+ typedef typename Base::Fragment Fragment;
+
+ /// Fragment iterator definition
+ typedef typename Base::FragmentIterator FragmentIterator;
+
+ /// Fragment const iterator definition
+ typedef typename Base::FragmentConstIterator FragmentConstIterator;
+
+ /// Default predicate mask type
+ typedef typename Base::PredicateVector PredicateVector;
+
+ /// Storage object which may be stored to
+ typedef typename Base::Storage SharedStorage;
+
+ /// IteratorBase parameters
+ typedef typename Base::Params BaseParams;
+
+ /// Parameters
+ struct Params : public BaseParams {
+ /// Pointer to memory
+ Scalar *pointer;
+
+ /// Initialize params to access storage object
+ CUTLASS_HOST_DEVICE
+ int initialize(SharedStorage &storage) {
+ pointer = &storage[0];
+ return 0;
+ }
+
+ /// Initializes params to access a raw pointer
+ CUTLASS_HOST_DEVICE
+ int initialize(Scalar *ptr, Index stride_d, Index stride_h, Index stride_w) {
+ Base::Params::initialize(stride_d, stride_h, stride_w);
+ pointer = ptr;
+ return 0;
+ }
+
+ /// Initializes params
+ CUTLASS_HOST_DEVICE
+ int initialize(Scalar *ptr,
+ Index _stride_d,
+ Index _stride_h,
+ Index _stride_w,
+ Index _inc_d,
+ Index _inc_h,
+ Index _inc_w,
+ Index _inc_advance) {
+ pointer = ptr;
+ Base::Params::initialize(
+ _stride_d, _stride_h, _stride_w, _inc_d, _inc_h, _inc_w, _inc_advance);
+ return 0;
+ }
+
+ /// Initializes params to default values
+ CUTLASS_HOST_DEVICE
+ int initialize() { return Base::Params::initialize(); }
+ };
+
+ //
+ // Data members
+ //
+
+ /// Parameters structure
+ Params params;
+
+ /// Offset of an individual lane from the start of the tile
+ Coord<4> thread_offset;
+
+ /// The stage.
+ int stage;
+
+ //
+ // Static member functions
+ //
+
+ /// Initializes a predicate vector
+ template <typename PredicateIterator>
+ CUTLASS_HOST_DEVICE void initialize_predicates(PredicateIterator predicate_it,
+ Coord<3> const &bounds,
+ Coord<3> const &block_offset = make_Coord(0,
+ 0,
+ 0)) {
+ Base::initialize_predicates(
+ predicate_it,
+ bounds,
+ block_offset + make_Coord(0, thread_offset[1], thread_offset[2] * Tile::kC));
+ }
+
+ //
+ // Methods
+ //
+
+ /// Default constructor
+ CUTLASS_HOST_DEVICE
+ TileStoreIterator() {}
+
+ /// Constructs a tile store iterator
+ CUTLASS_HOST_DEVICE
+ TileStoreIterator(Params const &_params,
+ Coord<3> const &block_offset = make_Coord(0, 0, 0),
+ ThreadOffset thread_offset_func = ThreadOffset())
+ : params(_params), stage(0) {
+ thread_offset = thread_offset_func();
+
+ params.pointer += block_offset[0] * params.stride_d +
+ (block_offset[1] + thread_offset[1]) * params.stride_h +
+ (block_offset[2] + thread_offset[2] * Tile::kC) / Tile::kC * params.stride_w;
+ }
+
+ /// Constructs a tile store iterator
+ CUTLASS_HOST_DEVICE
+ TileStoreIterator(Params const &,
+ SharedStorage &shared_storage,
+ Coord<3> const &block_offset = make_Coord(0, 0, 0),
+ ThreadOffset thread_offset_func = ThreadOffset())
+ : stage(0) {
+ int const offset = thread_offset_func()[2];
+ params.pointer = &shared_storage[offset];
+ }
+
+ /// Returns the current pointer
+ CUTLASS_HOST_DEVICE
+ Scalar *data() const { return params.pointer; }
+
+ /// Increment in the D dimension
+ CUTLASS_HOST_DEVICE void inc_d() { params.pointer += params.inc_d; }
+
+ /// Increment in the H dimension
+ CUTLASS_HOST_DEVICE void inc_h() { params.pointer += params.inc_h; }
+
+ /// Increment in the W dimension
+ CUTLASS_HOST_DEVICE void inc_w() { params.pointer += params.inc_w; }
+
+ /// Increment in the next dimension
+ CUTLASS_HOST_DEVICE void inc_advance() {}
+
+ /// Increment the stage.
+ CUTLASS_DEVICE void inc_stage() {
+ if (Tile::kD > 1) {
+ int const kStageSize = Tile::kH * Tile::kW * Tile::kC;
+ if (stage == Tile::kD - 1) {
+ params.pointer -= (Tile::kD - 1) * kStageSize;
+ stage = 0;
+ } else {
+ params.pointer += kStageSize;
+ stage = stage + 1;
+ }
+ }
+ }
+
+ /// The accessor.
+ CUTLASS_DEVICE void set(AccessType const &value, int d, int h, int w, int c) {
+ int const imm =
+ ComputeOffsetFromStrides<typename Base::ImmediateOffsetStrides>::get(d, h, w, c);
+ Store<Scalar, Base::kAccessSize, kMemorySpace>::store(value, params.pointer, imm);
+ }
+
+ public:
+ /// Stores a fragment and advances to the next tile.
+ template <typename Fragment, typename PredicateIterator>
+ CUTLASS_HOST_DEVICE void store_post_increment(Fragment &fragment, PredicateIterator pred_it) {
+ FragmentIterator frag_iterator(fragment);
+
+ for (int d = 0; d < Iterations::kD; ++d) {
+ for (int h = 0; h < Iterations::kH; ++h) {
+ for (int w = 0; w < Iterations::kW; ++w, ++pred_it) {
+ if (*pred_it) {
+ Store<typename Fragment::Element, Tile::kC, kMemorySpace>::store(
+ reinterpret_cast<AccessType &>(frag_iterator.at(d, h, w, 0)), data(), 0);
+ }
+ if (w < Iterations::kW - 1) {
+ inc_w();
+ }
+ }
+ if (h < Iterations::kH - 1) {
+ inc_h();
+ }
+ }
+ if (d < Iterations::kD - 1) {
+ inc_d();
+ }
+ }
+ inc_advance();
+ }
+
+ /// Stores a fragment and advances to the next tile.
+ template <typename Fragment>
+ CUTLASS_HOST_DEVICE void store_post_increment(Fragment &fragment) {
+ typename PredicateVector::TrivialIterator pred_it;
+ store_post_increment(fragment, pred_it);
+ }
+
+ /// Stores a fragment without advancing the iterator.
+ template <typename Fragment, typename PredicateIterator>
+ CUTLASS_HOST_DEVICE void store(Fragment &fragment, PredicateIterator pred_it) const {
+ TileStoreIterator _store_it(*this);
+ _store_it.store_post_increment(fragment, pred_it);
+ }
+
+ /// Stores a fragment without advancing the iterator.
+ template <typename Fragment>
+ CUTLASS_HOST_DEVICE void store(Fragment &fragment) const {
+ typename PredicateVector::TrivialIterator pred_it;
+ store(fragment, pred_it);
+ }
+};
+}