summaryrefslogtreecommitdiff
path: root/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block
diff options
context:
space:
mode:
Diffstat (limited to 'debug_tools/WatchYourStep/ptxjitplus/inc/cub/block')
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_adjacent_difference.cuh596
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_discontinuity.cuh1148
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_exchange.cuh1248
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_histogram.cuh415
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_load.cuh1241
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_radix_rank.cuh696
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_radix_sort.cuh863
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_raking_layout.cuh152
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_reduce.cuh607
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_scan.cuh2126
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_shuffle.cuh305
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_store.cuh1000
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_histogram_atomic.cuh82
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_histogram_sort.cuh226
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_reduce_raking.cuh226
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_reduce_raking_commutative_only.cuh199
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_reduce_warp_reductions.cuh218
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_scan_raking.cuh666
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_scan_warp_scans.cuh392
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_scan_warp_scans2.cuh436
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_scan_warp_scans3.cuh418
21 files changed, 13260 insertions, 0 deletions
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_adjacent_difference.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_adjacent_difference.cuh
new file mode 100644
index 0000000..acef9f0
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_adjacent_difference.cuh
@@ -0,0 +1,596 @@
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-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 TORT
+ * (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
+ * The cub::BlockDiscontinuity class provides [<em>collective</em>](index.html#sec0) methods for flagging discontinuities within an ordered set of items partitioned across a CUDA thread block.
+ */
+
+#pragma once
+
+#include "../util_type.cuh"
+#include "../util_ptx.cuh"
+#include "../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+template <
+ typename T,
+ int BLOCK_DIM_X,
+ int BLOCK_DIM_Y = 1,
+ int BLOCK_DIM_Z = 1,
+ int PTX_ARCH = CUB_PTX_ARCH>
+class BlockAdjacentDifference
+{
+private:
+
+ /******************************************************************************
+ * Constants and type definitions
+ ******************************************************************************/
+
+ /// Constants
+ enum
+ {
+ /// The thread block size in threads
+ BLOCK_THREADS = BLOCK_DIM_X * BLOCK_DIM_Y * BLOCK_DIM_Z,
+ };
+
+
+ /// Shared memory storage layout type (last element from each thread's input)
+ struct _TempStorage
+ {
+ T first_items[BLOCK_THREADS];
+ T last_items[BLOCK_THREADS];
+ };
+
+
+ /******************************************************************************
+ * Utility methods
+ ******************************************************************************/
+
+ /// Internal storage allocator
+ __device__ __forceinline__ _TempStorage& PrivateStorage()
+ {
+ __shared__ _TempStorage private_storage;
+ return private_storage;
+ }
+
+
+ /// Specialization for when FlagOp has third index param
+ template <typename FlagOp, bool HAS_PARAM = BinaryOpHasIdxParam<T, FlagOp>::HAS_PARAM>
+ struct ApplyOp
+ {
+ // Apply flag operator
+ static __device__ __forceinline__ T FlagT(FlagOp flag_op, const T &a, const T &b, int idx)
+ {
+ return flag_op(b, a, idx);
+ }
+ };
+
+ /// Specialization for when FlagOp does not have a third index param
+ template <typename FlagOp>
+ struct ApplyOp<FlagOp, false>
+ {
+ // Apply flag operator
+ static __device__ __forceinline__ T FlagT(FlagOp flag_op, const T &a, const T &b, int /*idx*/)
+ {
+ return flag_op(b, a);
+ }
+ };
+
+ /// Templated unrolling of item comparison (inductive case)
+ template <int ITERATION, int MAX_ITERATIONS>
+ struct Iterate
+ {
+ // Head flags
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ static __device__ __forceinline__ void FlagHeads(
+ int linear_tid,
+ FlagT (&flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ T (&preds)[ITEMS_PER_THREAD], ///< [out] Calling thread's predecessor items
+ FlagOp flag_op) ///< [in] Binary boolean flag predicate
+ {
+ preds[ITERATION] = input[ITERATION - 1];
+
+ flags[ITERATION] = ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ preds[ITERATION],
+ input[ITERATION],
+ (linear_tid * ITEMS_PER_THREAD) + ITERATION);
+
+ Iterate<ITERATION + 1, MAX_ITERATIONS>::FlagHeads(linear_tid, flags, input, preds, flag_op);
+ }
+
+ // Tail flags
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ static __device__ __forceinline__ void FlagTails(
+ int linear_tid,
+ FlagT (&flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ FlagOp flag_op) ///< [in] Binary boolean flag predicate
+ {
+ flags[ITERATION] = ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ input[ITERATION],
+ input[ITERATION + 1],
+ (linear_tid * ITEMS_PER_THREAD) + ITERATION + 1);
+
+ Iterate<ITERATION + 1, MAX_ITERATIONS>::FlagTails(linear_tid, flags, input, flag_op);
+ }
+
+ };
+
+ /// Templated unrolling of item comparison (termination case)
+ template <int MAX_ITERATIONS>
+ struct Iterate<MAX_ITERATIONS, MAX_ITERATIONS>
+ {
+ // Head flags
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ static __device__ __forceinline__ void FlagHeads(
+ int /*linear_tid*/,
+ FlagT (&/*flags*/)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ T (&/*input*/)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ T (&/*preds*/)[ITEMS_PER_THREAD], ///< [out] Calling thread's predecessor items
+ FlagOp /*flag_op*/) ///< [in] Binary boolean flag predicate
+ {}
+
+ // Tail flags
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ static __device__ __forceinline__ void FlagTails(
+ int /*linear_tid*/,
+ FlagT (&/*flags*/)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ T (&/*input*/)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ FlagOp /*flag_op*/) ///< [in] Binary boolean flag predicate
+ {}
+ };
+
+
+ /******************************************************************************
+ * Thread fields
+ ******************************************************************************/
+
+ /// Shared storage reference
+ _TempStorage &temp_storage;
+
+ /// Linear thread-id
+ unsigned int linear_tid;
+
+
+public:
+
+ /// \smemstorage{BlockDiscontinuity}
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ /******************************************************************//**
+ * \name Collective constructors
+ *********************************************************************/
+ //@{
+
+ /**
+ * \brief Collective constructor using a private static allocation of shared memory as temporary storage.
+ */
+ __device__ __forceinline__ BlockAdjacentDifference()
+ :
+ temp_storage(PrivateStorage()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ /**
+ * \brief Collective constructor using the specified memory allocation as temporary storage.
+ */
+ __device__ __forceinline__ BlockAdjacentDifference(
+ TempStorage &temp_storage) ///< [in] Reference to memory allocation having layout type TempStorage
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ //@} end member group
+ /******************************************************************//**
+ * \name Head flag operations
+ *********************************************************************/
+ //@{
+
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS // Do not document
+
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ __device__ __forceinline__ void FlagHeads(
+ FlagT (&head_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ T (&preds)[ITEMS_PER_THREAD], ///< [out] Calling thread's predecessor items
+ FlagOp flag_op) ///< [in] Binary boolean flag predicate
+ {
+ // Share last item
+ temp_storage.last_items[linear_tid] = input[ITEMS_PER_THREAD - 1];
+
+ CTA_SYNC();
+
+ if (linear_tid == 0)
+ {
+ // Set flag for first thread-item (preds[0] is undefined)
+ head_flags[0] = 1;
+ }
+ else
+ {
+ preds[0] = temp_storage.last_items[linear_tid - 1];
+ head_flags[0] = ApplyOp<FlagOp>::FlagT(flag_op, preds[0], input[0], linear_tid * ITEMS_PER_THREAD);
+ }
+
+ // Set head_flags for remaining items
+ Iterate<1, ITEMS_PER_THREAD>::FlagHeads(linear_tid, head_flags, input, preds, flag_op);
+ }
+
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ __device__ __forceinline__ void FlagHeads(
+ FlagT (&head_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ T (&preds)[ITEMS_PER_THREAD], ///< [out] Calling thread's predecessor items
+ FlagOp flag_op, ///< [in] Binary boolean flag predicate
+ T tile_predecessor_item) ///< [in] <b>[<em>thread</em><sub>0</sub> only]</b> Item with which to compare the first tile item (<tt>input<sub>0</sub></tt> from <em>thread</em><sub>0</sub>).
+ {
+ // Share last item
+ temp_storage.last_items[linear_tid] = input[ITEMS_PER_THREAD - 1];
+
+ CTA_SYNC();
+
+ // Set flag for first thread-item
+ preds[0] = (linear_tid == 0) ?
+ tile_predecessor_item : // First thread
+ temp_storage.last_items[linear_tid - 1];
+
+ head_flags[0] = ApplyOp<FlagOp>::FlagT(flag_op, preds[0], input[0], linear_tid * ITEMS_PER_THREAD);
+
+ // Set head_flags for remaining items
+ Iterate<1, ITEMS_PER_THREAD>::FlagHeads(linear_tid, head_flags, input, preds, flag_op);
+ }
+
+#endif // DOXYGEN_SHOULD_SKIP_THIS
+
+
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ __device__ __forceinline__ void FlagHeads(
+ FlagT (&head_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ FlagOp flag_op) ///< [in] Binary boolean flag predicate
+ {
+ T preds[ITEMS_PER_THREAD];
+ FlagHeads(head_flags, input, preds, flag_op);
+ }
+
+
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ __device__ __forceinline__ void FlagHeads(
+ FlagT (&head_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ FlagOp flag_op, ///< [in] Binary boolean flag predicate
+ T tile_predecessor_item) ///< [in] <b>[<em>thread</em><sub>0</sub> only]</b> Item with which to compare the first tile item (<tt>input<sub>0</sub></tt> from <em>thread</em><sub>0</sub>).
+ {
+ T preds[ITEMS_PER_THREAD];
+ FlagHeads(head_flags, input, preds, flag_op, tile_predecessor_item);
+ }
+
+
+
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ __device__ __forceinline__ void FlagTails(
+ FlagT (&tail_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity tail_flags
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ FlagOp flag_op) ///< [in] Binary boolean flag predicate
+ {
+ // Share first item
+ temp_storage.first_items[linear_tid] = input[0];
+
+ CTA_SYNC();
+
+ // Set flag for last thread-item
+ tail_flags[ITEMS_PER_THREAD - 1] = (linear_tid == BLOCK_THREADS - 1) ?
+ 1 : // Last thread
+ ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ input[ITEMS_PER_THREAD - 1],
+ temp_storage.first_items[linear_tid + 1],
+ (linear_tid * ITEMS_PER_THREAD) + ITEMS_PER_THREAD);
+
+ // Set tail_flags for remaining items
+ Iterate<0, ITEMS_PER_THREAD - 1>::FlagTails(linear_tid, tail_flags, input, flag_op);
+ }
+
+
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ __device__ __forceinline__ void FlagTails(
+ FlagT (&tail_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity tail_flags
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ FlagOp flag_op, ///< [in] Binary boolean flag predicate
+ T tile_successor_item) ///< [in] <b>[<em>thread</em><sub><tt>BLOCK_THREADS</tt>-1</sub> only]</b> Item with which to compare the last tile item (<tt>input</tt><sub><em>ITEMS_PER_THREAD</em>-1</sub> from <em>thread</em><sub><em>BLOCK_THREADS</em>-1</sub>).
+ {
+ // Share first item
+ temp_storage.first_items[linear_tid] = input[0];
+
+ CTA_SYNC();
+
+ // Set flag for last thread-item
+ T successor_item = (linear_tid == BLOCK_THREADS - 1) ?
+ tile_successor_item : // Last thread
+ temp_storage.first_items[linear_tid + 1];
+
+ tail_flags[ITEMS_PER_THREAD - 1] = ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ input[ITEMS_PER_THREAD - 1],
+ successor_item,
+ (linear_tid * ITEMS_PER_THREAD) + ITEMS_PER_THREAD);
+
+ // Set tail_flags for remaining items
+ Iterate<0, ITEMS_PER_THREAD - 1>::FlagTails(linear_tid, tail_flags, input, flag_op);
+ }
+
+
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ __device__ __forceinline__ void FlagHeadsAndTails(
+ FlagT (&head_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ FlagT (&tail_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity tail_flags
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ FlagOp flag_op) ///< [in] Binary boolean flag predicate
+ {
+ // Share first and last items
+ temp_storage.first_items[linear_tid] = input[0];
+ temp_storage.last_items[linear_tid] = input[ITEMS_PER_THREAD - 1];
+
+ CTA_SYNC();
+
+ T preds[ITEMS_PER_THREAD];
+
+ // Set flag for first thread-item
+ preds[0] = temp_storage.last_items[linear_tid - 1];
+ if (linear_tid == 0)
+ {
+ head_flags[0] = 1;
+ }
+ else
+ {
+ head_flags[0] = ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ preds[0],
+ input[0],
+ linear_tid * ITEMS_PER_THREAD);
+ }
+
+
+ // Set flag for last thread-item
+ tail_flags[ITEMS_PER_THREAD - 1] = (linear_tid == BLOCK_THREADS - 1) ?
+ 1 : // Last thread
+ ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ input[ITEMS_PER_THREAD - 1],
+ temp_storage.first_items[linear_tid + 1],
+ (linear_tid * ITEMS_PER_THREAD) + ITEMS_PER_THREAD);
+
+ // Set head_flags for remaining items
+ Iterate<1, ITEMS_PER_THREAD>::FlagHeads(linear_tid, head_flags, input, preds, flag_op);
+
+ // Set tail_flags for remaining items
+ Iterate<0, ITEMS_PER_THREAD - 1>::FlagTails(linear_tid, tail_flags, input, flag_op);
+ }
+
+
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ __device__ __forceinline__ void FlagHeadsAndTails(
+ FlagT (&head_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ FlagT (&tail_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity tail_flags
+ T tile_successor_item, ///< [in] <b>[<em>thread</em><sub><tt>BLOCK_THREADS</tt>-1</sub> only]</b> Item with which to compare the last tile item (<tt>input</tt><sub><em>ITEMS_PER_THREAD</em>-1</sub> from <em>thread</em><sub><em>BLOCK_THREADS</em>-1</sub>).
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ FlagOp flag_op) ///< [in] Binary boolean flag predicate
+ {
+ // Share first and last items
+ temp_storage.first_items[linear_tid] = input[0];
+ temp_storage.last_items[linear_tid] = input[ITEMS_PER_THREAD - 1];
+
+ CTA_SYNC();
+
+ T preds[ITEMS_PER_THREAD];
+
+ // Set flag for first thread-item
+ if (linear_tid == 0)
+ {
+ head_flags[0] = 1;
+ }
+ else
+ {
+ preds[0] = temp_storage.last_items[linear_tid - 1];
+ head_flags[0] = ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ preds[0],
+ input[0],
+ linear_tid * ITEMS_PER_THREAD);
+ }
+
+ // Set flag for last thread-item
+ T successor_item = (linear_tid == BLOCK_THREADS - 1) ?
+ tile_successor_item : // Last thread
+ temp_storage.first_items[linear_tid + 1];
+
+ tail_flags[ITEMS_PER_THREAD - 1] = ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ input[ITEMS_PER_THREAD - 1],
+ successor_item,
+ (linear_tid * ITEMS_PER_THREAD) + ITEMS_PER_THREAD);
+
+ // Set head_flags for remaining items
+ Iterate<1, ITEMS_PER_THREAD>::FlagHeads(linear_tid, head_flags, input, preds, flag_op);
+
+ // Set tail_flags for remaining items
+ Iterate<0, ITEMS_PER_THREAD - 1>::FlagTails(linear_tid, tail_flags, input, flag_op);
+ }
+
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ __device__ __forceinline__ void FlagHeadsAndTails(
+ FlagT (&head_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ T tile_predecessor_item, ///< [in] <b>[<em>thread</em><sub>0</sub> only]</b> Item with which to compare the first tile item (<tt>input<sub>0</sub></tt> from <em>thread</em><sub>0</sub>).
+ FlagT (&tail_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity tail_flags
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ FlagOp flag_op) ///< [in] Binary boolean flag predicate
+ {
+ // Share first and last items
+ temp_storage.first_items[linear_tid] = input[0];
+ temp_storage.last_items[linear_tid] = input[ITEMS_PER_THREAD - 1];
+
+ CTA_SYNC();
+
+ T preds[ITEMS_PER_THREAD];
+
+ // Set flag for first thread-item
+ preds[0] = (linear_tid == 0) ?
+ tile_predecessor_item : // First thread
+ temp_storage.last_items[linear_tid - 1];
+
+ head_flags[0] = ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ preds[0],
+ input[0],
+ linear_tid * ITEMS_PER_THREAD);
+
+ // Set flag for last thread-item
+ tail_flags[ITEMS_PER_THREAD - 1] = (linear_tid == BLOCK_THREADS - 1) ?
+ 1 : // Last thread
+ ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ input[ITEMS_PER_THREAD - 1],
+ temp_storage.first_items[linear_tid + 1],
+ (linear_tid * ITEMS_PER_THREAD) + ITEMS_PER_THREAD);
+
+ // Set head_flags for remaining items
+ Iterate<1, ITEMS_PER_THREAD>::FlagHeads(linear_tid, head_flags, input, preds, flag_op);
+
+ // Set tail_flags for remaining items
+ Iterate<0, ITEMS_PER_THREAD - 1>::FlagTails(linear_tid, tail_flags, input, flag_op);
+ }
+
+
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ __device__ __forceinline__ void FlagHeadsAndTails(
+ FlagT (&head_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ T tile_predecessor_item, ///< [in] <b>[<em>thread</em><sub>0</sub> only]</b> Item with which to compare the first tile item (<tt>input<sub>0</sub></tt> from <em>thread</em><sub>0</sub>).
+ FlagT (&tail_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity tail_flags
+ T tile_successor_item, ///< [in] <b>[<em>thread</em><sub><tt>BLOCK_THREADS</tt>-1</sub> only]</b> Item with which to compare the last tile item (<tt>input</tt><sub><em>ITEMS_PER_THREAD</em>-1</sub> from <em>thread</em><sub><em>BLOCK_THREADS</em>-1</sub>).
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ FlagOp flag_op) ///< [in] Binary boolean flag predicate
+ {
+ // Share first and last items
+ temp_storage.first_items[linear_tid] = input[0];
+ temp_storage.last_items[linear_tid] = input[ITEMS_PER_THREAD - 1];
+
+ CTA_SYNC();
+
+ T preds[ITEMS_PER_THREAD];
+
+ // Set flag for first thread-item
+ preds[0] = (linear_tid == 0) ?
+ tile_predecessor_item : // First thread
+ temp_storage.last_items[linear_tid - 1];
+
+ head_flags[0] = ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ preds[0],
+ input[0],
+ linear_tid * ITEMS_PER_THREAD);
+
+ // Set flag for last thread-item
+ T successor_item = (linear_tid == BLOCK_THREADS - 1) ?
+ tile_successor_item : // Last thread
+ temp_storage.first_items[linear_tid + 1];
+
+ tail_flags[ITEMS_PER_THREAD - 1] = ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ input[ITEMS_PER_THREAD - 1],
+ successor_item,
+ (linear_tid * ITEMS_PER_THREAD) + ITEMS_PER_THREAD);
+
+ // Set head_flags for remaining items
+ Iterate<1, ITEMS_PER_THREAD>::FlagHeads(linear_tid, head_flags, input, preds, flag_op);
+
+ // Set tail_flags for remaining items
+ Iterate<0, ITEMS_PER_THREAD - 1>::FlagTails(linear_tid, tail_flags, input, flag_op);
+ }
+
+
+
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_discontinuity.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_discontinuity.cuh
new file mode 100644
index 0000000..503e3e0
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_discontinuity.cuh
@@ -0,0 +1,1148 @@
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-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 TORT
+ * (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
+ * The cub::BlockDiscontinuity class provides [<em>collective</em>](index.html#sec0) methods for flagging discontinuities within an ordered set of items partitioned across a CUDA thread block.
+ */
+
+#pragma once
+
+#include "../util_type.cuh"
+#include "../util_ptx.cuh"
+#include "../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+/**
+ * \brief The BlockDiscontinuity class provides [<em>collective</em>](index.html#sec0) methods for flagging discontinuities within an ordered set of items partitioned across a CUDA thread block. ![](discont_logo.png)
+ * \ingroup BlockModule
+ *
+ * \tparam T The data type to be flagged.
+ * \tparam BLOCK_DIM_X The thread block length in threads along the X dimension
+ * \tparam BLOCK_DIM_Y <b>[optional]</b> The thread block length in threads along the Y dimension (default: 1)
+ * \tparam BLOCK_DIM_Z <b>[optional]</b> The thread block length in threads along the Z dimension (default: 1)
+ * \tparam PTX_ARCH <b>[optional]</b> \ptxversion
+ *
+ * \par Overview
+ * - A set of "head flags" (or "tail flags") is often used to indicate corresponding items
+ * that differ from their predecessors (or successors). For example, head flags are convenient
+ * for demarcating disjoint data segments as part of a segmented scan or reduction.
+ * - \blocked
+ *
+ * \par Performance Considerations
+ * - \granularity
+ *
+ * \par A Simple Example
+ * \blockcollective{BlockDiscontinuity}
+ * \par
+ * The code snippet below illustrates the head flagging of 512 integer items that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_discontinuity.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockDiscontinuity for a 1D block of 128 threads on type int
+ * typedef cub::BlockDiscontinuity<int, 128> BlockDiscontinuity;
+ *
+ * // Allocate shared memory for BlockDiscontinuity
+ * __shared__ typename BlockDiscontinuity::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Collectively compute head flags for discontinuities in the segment
+ * int head_flags[4];
+ * BlockDiscontinuity(temp_storage).FlagHeads(head_flags, thread_data, cub::Inequality());
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is
+ * <tt>{ [0,0,1,1], [1,1,1,1], [2,3,3,3], [3,4,4,4], ... }</tt>.
+ * The corresponding output \p head_flags in those threads will be
+ * <tt>{ [1,0,1,0], [0,0,0,0], [1,1,0,0], [0,1,0,0], ... }</tt>.
+ *
+ * \par Performance Considerations
+ * - Incurs zero bank conflicts for most types
+ *
+ */
+template <
+ typename T,
+ int BLOCK_DIM_X,
+ int BLOCK_DIM_Y = 1,
+ int BLOCK_DIM_Z = 1,
+ int PTX_ARCH = CUB_PTX_ARCH>
+class BlockDiscontinuity
+{
+private:
+
+ /******************************************************************************
+ * Constants and type definitions
+ ******************************************************************************/
+
+ /// Constants
+ enum
+ {
+ /// The thread block size in threads
+ BLOCK_THREADS = BLOCK_DIM_X * BLOCK_DIM_Y * BLOCK_DIM_Z,
+ };
+
+
+ /// Shared memory storage layout type (last element from each thread's input)
+ struct _TempStorage
+ {
+ T first_items[BLOCK_THREADS];
+ T last_items[BLOCK_THREADS];
+ };
+
+
+ /******************************************************************************
+ * Utility methods
+ ******************************************************************************/
+
+ /// Internal storage allocator
+ __device__ __forceinline__ _TempStorage& PrivateStorage()
+ {
+ __shared__ _TempStorage private_storage;
+ return private_storage;
+ }
+
+
+ /// Specialization for when FlagOp has third index param
+ template <typename FlagOp, bool HAS_PARAM = BinaryOpHasIdxParam<T, FlagOp>::HAS_PARAM>
+ struct ApplyOp
+ {
+ // Apply flag operator
+ static __device__ __forceinline__ bool FlagT(FlagOp flag_op, const T &a, const T &b, int idx)
+ {
+ return flag_op(a, b, idx);
+ }
+ };
+
+ /// Specialization for when FlagOp does not have a third index param
+ template <typename FlagOp>
+ struct ApplyOp<FlagOp, false>
+ {
+ // Apply flag operator
+ static __device__ __forceinline__ bool FlagT(FlagOp flag_op, const T &a, const T &b, int /*idx*/)
+ {
+ return flag_op(a, b);
+ }
+ };
+
+ /// Templated unrolling of item comparison (inductive case)
+ template <int ITERATION, int MAX_ITERATIONS>
+ struct Iterate
+ {
+ // Head flags
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ static __device__ __forceinline__ void FlagHeads(
+ int linear_tid,
+ FlagT (&flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ T (&preds)[ITEMS_PER_THREAD], ///< [out] Calling thread's predecessor items
+ FlagOp flag_op) ///< [in] Binary boolean flag predicate
+ {
+ preds[ITERATION] = input[ITERATION - 1];
+
+ flags[ITERATION] = ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ preds[ITERATION],
+ input[ITERATION],
+ (linear_tid * ITEMS_PER_THREAD) + ITERATION);
+
+ Iterate<ITERATION + 1, MAX_ITERATIONS>::FlagHeads(linear_tid, flags, input, preds, flag_op);
+ }
+
+ // Tail flags
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ static __device__ __forceinline__ void FlagTails(
+ int linear_tid,
+ FlagT (&flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ FlagOp flag_op) ///< [in] Binary boolean flag predicate
+ {
+ flags[ITERATION] = ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ input[ITERATION],
+ input[ITERATION + 1],
+ (linear_tid * ITEMS_PER_THREAD) + ITERATION + 1);
+
+ Iterate<ITERATION + 1, MAX_ITERATIONS>::FlagTails(linear_tid, flags, input, flag_op);
+ }
+
+ };
+
+ /// Templated unrolling of item comparison (termination case)
+ template <int MAX_ITERATIONS>
+ struct Iterate<MAX_ITERATIONS, MAX_ITERATIONS>
+ {
+ // Head flags
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ static __device__ __forceinline__ void FlagHeads(
+ int /*linear_tid*/,
+ FlagT (&/*flags*/)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ T (&/*input*/)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ T (&/*preds*/)[ITEMS_PER_THREAD], ///< [out] Calling thread's predecessor items
+ FlagOp /*flag_op*/) ///< [in] Binary boolean flag predicate
+ {}
+
+ // Tail flags
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ static __device__ __forceinline__ void FlagTails(
+ int /*linear_tid*/,
+ FlagT (&/*flags*/)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ T (&/*input*/)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ FlagOp /*flag_op*/) ///< [in] Binary boolean flag predicate
+ {}
+ };
+
+
+ /******************************************************************************
+ * Thread fields
+ ******************************************************************************/
+
+ /// Shared storage reference
+ _TempStorage &temp_storage;
+
+ /// Linear thread-id
+ unsigned int linear_tid;
+
+
+public:
+
+ /// \smemstorage{BlockDiscontinuity}
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ /******************************************************************//**
+ * \name Collective constructors
+ *********************************************************************/
+ //@{
+
+ /**
+ * \brief Collective constructor using a private static allocation of shared memory as temporary storage.
+ */
+ __device__ __forceinline__ BlockDiscontinuity()
+ :
+ temp_storage(PrivateStorage()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ /**
+ * \brief Collective constructor using the specified memory allocation as temporary storage.
+ */
+ __device__ __forceinline__ BlockDiscontinuity(
+ TempStorage &temp_storage) ///< [in] Reference to memory allocation having layout type TempStorage
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ //@} end member group
+ /******************************************************************//**
+ * \name Head flag operations
+ *********************************************************************/
+ //@{
+
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS // Do not document
+
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ __device__ __forceinline__ void FlagHeads(
+ FlagT (&head_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ T (&preds)[ITEMS_PER_THREAD], ///< [out] Calling thread's predecessor items
+ FlagOp flag_op) ///< [in] Binary boolean flag predicate
+ {
+ // Share last item
+ temp_storage.last_items[linear_tid] = input[ITEMS_PER_THREAD - 1];
+
+ CTA_SYNC();
+
+ if (linear_tid == 0)
+ {
+ // Set flag for first thread-item (preds[0] is undefined)
+ head_flags[0] = 1;
+ }
+ else
+ {
+ preds[0] = temp_storage.last_items[linear_tid - 1];
+ head_flags[0] = ApplyOp<FlagOp>::FlagT(flag_op, preds[0], input[0], linear_tid * ITEMS_PER_THREAD);
+ }
+
+ // Set head_flags for remaining items
+ Iterate<1, ITEMS_PER_THREAD>::FlagHeads(linear_tid, head_flags, input, preds, flag_op);
+ }
+
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ __device__ __forceinline__ void FlagHeads(
+ FlagT (&head_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ T (&preds)[ITEMS_PER_THREAD], ///< [out] Calling thread's predecessor items
+ FlagOp flag_op, ///< [in] Binary boolean flag predicate
+ T tile_predecessor_item) ///< [in] <b>[<em>thread</em><sub>0</sub> only]</b> Item with which to compare the first tile item (<tt>input<sub>0</sub></tt> from <em>thread</em><sub>0</sub>).
+ {
+ // Share last item
+ temp_storage.last_items[linear_tid] = input[ITEMS_PER_THREAD - 1];
+
+ CTA_SYNC();
+
+ // Set flag for first thread-item
+ preds[0] = (linear_tid == 0) ?
+ tile_predecessor_item : // First thread
+ temp_storage.last_items[linear_tid - 1];
+
+ head_flags[0] = ApplyOp<FlagOp>::FlagT(flag_op, preds[0], input[0], linear_tid * ITEMS_PER_THREAD);
+
+ // Set head_flags for remaining items
+ Iterate<1, ITEMS_PER_THREAD>::FlagHeads(linear_tid, head_flags, input, preds, flag_op);
+ }
+
+#endif // DOXYGEN_SHOULD_SKIP_THIS
+
+
+ /**
+ * \brief Sets head flags indicating discontinuities between items partitioned across the thread block, for which the first item has no reference and is always flagged.
+ *
+ * \par
+ * - The flag <tt>head_flags<sub><em>i</em></sub></tt> is set for item
+ * <tt>input<sub><em>i</em></sub></tt> when
+ * <tt>flag_op(</tt><em>previous-item</em><tt>, input<sub><em>i</em></sub>)</tt>
+ * returns \p true (where <em>previous-item</em> is either the preceding item
+ * in the same thread or the last item in the previous thread).
+ * - For <em>thread</em><sub>0</sub>, item <tt>input<sub>0</sub></tt> is always flagged.
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates the head-flagging of 512 integer items that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_discontinuity.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockDiscontinuity for a 1D block of 128 threads on type int
+ * typedef cub::BlockDiscontinuity<int, 128> BlockDiscontinuity;
+ *
+ * // Allocate shared memory for BlockDiscontinuity
+ * __shared__ typename BlockDiscontinuity::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Collectively compute head flags for discontinuities in the segment
+ * int head_flags[4];
+ * BlockDiscontinuity(temp_storage).FlagHeads(head_flags, thread_data, cub::Inequality());
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is
+ * <tt>{ [0,0,1,1], [1,1,1,1], [2,3,3,3], [3,4,4,4], ... }</tt>.
+ * The corresponding output \p head_flags in those threads will be
+ * <tt>{ [1,0,1,0], [0,0,0,0], [1,1,0,0], [0,1,0,0], ... }</tt>.
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam FlagT <b>[inferred]</b> The flag type (must be an integer type)
+ * \tparam FlagOp <b>[inferred]</b> Binary predicate functor type having member <tt>T operator()(const T &a, const T &b)</tt> or member <tt>T operator()(const T &a, const T &b, unsigned int b_index)</tt>, and returning \p true if a discontinuity exists between \p a and \p b, otherwise \p false. \p b_index is the rank of b in the aggregate tile of data.
+ */
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ __device__ __forceinline__ void FlagHeads(
+ FlagT (&head_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ FlagOp flag_op) ///< [in] Binary boolean flag predicate
+ {
+ T preds[ITEMS_PER_THREAD];
+ FlagHeads(head_flags, input, preds, flag_op);
+ }
+
+
+ /**
+ * \brief Sets head flags indicating discontinuities between items partitioned across the thread block.
+ *
+ * \par
+ * - The flag <tt>head_flags<sub><em>i</em></sub></tt> is set for item
+ * <tt>input<sub><em>i</em></sub></tt> when
+ * <tt>flag_op(</tt><em>previous-item</em><tt>, input<sub><em>i</em></sub>)</tt>
+ * returns \p true (where <em>previous-item</em> is either the preceding item
+ * in the same thread or the last item in the previous thread).
+ * - For <em>thread</em><sub>0</sub>, item <tt>input<sub>0</sub></tt> is compared
+ * against \p tile_predecessor_item.
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates the head-flagging of 512 integer items that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_discontinuity.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockDiscontinuity for a 1D block of 128 threads on type int
+ * typedef cub::BlockDiscontinuity<int, 128> BlockDiscontinuity;
+ *
+ * // Allocate shared memory for BlockDiscontinuity
+ * __shared__ typename BlockDiscontinuity::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Have thread0 obtain the predecessor item for the entire tile
+ * int tile_predecessor_item;
+ * if (threadIdx.x == 0) tile_predecessor_item == ...
+ *
+ * // Collectively compute head flags for discontinuities in the segment
+ * int head_flags[4];
+ * BlockDiscontinuity(temp_storage).FlagHeads(
+ * head_flags, thread_data, cub::Inequality(), tile_predecessor_item);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is
+ * <tt>{ [0,0,1,1], [1,1,1,1], [2,3,3,3], [3,4,4,4], ... }</tt>,
+ * and that \p tile_predecessor_item is \p 0. The corresponding output \p head_flags in those threads will be
+ * <tt>{ [0,0,1,0], [0,0,0,0], [1,1,0,0], [0,1,0,0], ... }</tt>.
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam FlagT <b>[inferred]</b> The flag type (must be an integer type)
+ * \tparam FlagOp <b>[inferred]</b> Binary predicate functor type having member <tt>T operator()(const T &a, const T &b)</tt> or member <tt>T operator()(const T &a, const T &b, unsigned int b_index)</tt>, and returning \p true if a discontinuity exists between \p a and \p b, otherwise \p false. \p b_index is the rank of b in the aggregate tile of data.
+ */
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ __device__ __forceinline__ void FlagHeads(
+ FlagT (&head_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ FlagOp flag_op, ///< [in] Binary boolean flag predicate
+ T tile_predecessor_item) ///< [in] <b>[<em>thread</em><sub>0</sub> only]</b> Item with which to compare the first tile item (<tt>input<sub>0</sub></tt> from <em>thread</em><sub>0</sub>).
+ {
+ T preds[ITEMS_PER_THREAD];
+ FlagHeads(head_flags, input, preds, flag_op, tile_predecessor_item);
+ }
+
+
+
+ //@} end member group
+ /******************************************************************//**
+ * \name Tail flag operations
+ *********************************************************************/
+ //@{
+
+
+ /**
+ * \brief Sets tail flags indicating discontinuities between items partitioned across the thread block, for which the last item has no reference and is always flagged.
+ *
+ * \par
+ * - The flag <tt>tail_flags<sub><em>i</em></sub></tt> is set for item
+ * <tt>input<sub><em>i</em></sub></tt> when
+ * <tt>flag_op(input<sub><em>i</em></sub>, </tt><em>next-item</em><tt>)</tt>
+ * returns \p true (where <em>next-item</em> is either the next item
+ * in the same thread or the first item in the next thread).
+ * - For <em>thread</em><sub><em>BLOCK_THREADS</em>-1</sub>, item
+ * <tt>input</tt><sub><em>ITEMS_PER_THREAD</em>-1</sub> is always flagged.
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates the tail-flagging of 512 integer items that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_discontinuity.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockDiscontinuity for a 1D block of 128 threads on type int
+ * typedef cub::BlockDiscontinuity<int, 128> BlockDiscontinuity;
+ *
+ * // Allocate shared memory for BlockDiscontinuity
+ * __shared__ typename BlockDiscontinuity::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Collectively compute tail flags for discontinuities in the segment
+ * int tail_flags[4];
+ * BlockDiscontinuity(temp_storage).FlagTails(tail_flags, thread_data, cub::Inequality());
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is
+ * <tt>{ [0,0,1,1], [1,1,1,1], [2,3,3,3], ..., [124,125,125,125] }</tt>.
+ * The corresponding output \p tail_flags in those threads will be
+ * <tt>{ [0,1,0,0], [0,0,0,1], [1,0,0,...], ..., [1,0,0,1] }</tt>.
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam FlagT <b>[inferred]</b> The flag type (must be an integer type)
+ * \tparam FlagOp <b>[inferred]</b> Binary predicate functor type having member <tt>T operator()(const T &a, const T &b)</tt> or member <tt>T operator()(const T &a, const T &b, unsigned int b_index)</tt>, and returning \p true if a discontinuity exists between \p a and \p b, otherwise \p false. \p b_index is the rank of b in the aggregate tile of data.
+ */
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ __device__ __forceinline__ void FlagTails(
+ FlagT (&tail_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity tail_flags
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ FlagOp flag_op) ///< [in] Binary boolean flag predicate
+ {
+ // Share first item
+ temp_storage.first_items[linear_tid] = input[0];
+
+ CTA_SYNC();
+
+ // Set flag for last thread-item
+ tail_flags[ITEMS_PER_THREAD - 1] = (linear_tid == BLOCK_THREADS - 1) ?
+ 1 : // Last thread
+ ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ input[ITEMS_PER_THREAD - 1],
+ temp_storage.first_items[linear_tid + 1],
+ (linear_tid * ITEMS_PER_THREAD) + ITEMS_PER_THREAD);
+
+ // Set tail_flags for remaining items
+ Iterate<0, ITEMS_PER_THREAD - 1>::FlagTails(linear_tid, tail_flags, input, flag_op);
+ }
+
+
+ /**
+ * \brief Sets tail flags indicating discontinuities between items partitioned across the thread block.
+ *
+ * \par
+ * - The flag <tt>tail_flags<sub><em>i</em></sub></tt> is set for item
+ * <tt>input<sub><em>i</em></sub></tt> when
+ * <tt>flag_op(input<sub><em>i</em></sub>, </tt><em>next-item</em><tt>)</tt>
+ * returns \p true (where <em>next-item</em> is either the next item
+ * in the same thread or the first item in the next thread).
+ * - For <em>thread</em><sub><em>BLOCK_THREADS</em>-1</sub>, item
+ * <tt>input</tt><sub><em>ITEMS_PER_THREAD</em>-1</sub> is compared
+ * against \p tile_successor_item.
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates the tail-flagging of 512 integer items that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_discontinuity.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockDiscontinuity for a 1D block of 128 threads on type int
+ * typedef cub::BlockDiscontinuity<int, 128> BlockDiscontinuity;
+ *
+ * // Allocate shared memory for BlockDiscontinuity
+ * __shared__ typename BlockDiscontinuity::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Have thread127 obtain the successor item for the entire tile
+ * int tile_successor_item;
+ * if (threadIdx.x == 127) tile_successor_item == ...
+ *
+ * // Collectively compute tail flags for discontinuities in the segment
+ * int tail_flags[4];
+ * BlockDiscontinuity(temp_storage).FlagTails(
+ * tail_flags, thread_data, cub::Inequality(), tile_successor_item);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is
+ * <tt>{ [0,0,1,1], [1,1,1,1], [2,3,3,3], ..., [124,125,125,125] }</tt>
+ * and that \p tile_successor_item is \p 125. The corresponding output \p tail_flags in those threads will be
+ * <tt>{ [0,1,0,0], [0,0,0,1], [1,0,0,...], ..., [1,0,0,0] }</tt>.
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam FlagT <b>[inferred]</b> The flag type (must be an integer type)
+ * \tparam FlagOp <b>[inferred]</b> Binary predicate functor type having member <tt>T operator()(const T &a, const T &b)</tt> or member <tt>T operator()(const T &a, const T &b, unsigned int b_index)</tt>, and returning \p true if a discontinuity exists between \p a and \p b, otherwise \p false. \p b_index is the rank of b in the aggregate tile of data.
+ */
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ __device__ __forceinline__ void FlagTails(
+ FlagT (&tail_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity tail_flags
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ FlagOp flag_op, ///< [in] Binary boolean flag predicate
+ T tile_successor_item) ///< [in] <b>[<em>thread</em><sub><tt>BLOCK_THREADS</tt>-1</sub> only]</b> Item with which to compare the last tile item (<tt>input</tt><sub><em>ITEMS_PER_THREAD</em>-1</sub> from <em>thread</em><sub><em>BLOCK_THREADS</em>-1</sub>).
+ {
+ // Share first item
+ temp_storage.first_items[linear_tid] = input[0];
+
+ CTA_SYNC();
+
+ // Set flag for last thread-item
+ T successor_item = (linear_tid == BLOCK_THREADS - 1) ?
+ tile_successor_item : // Last thread
+ temp_storage.first_items[linear_tid + 1];
+
+ tail_flags[ITEMS_PER_THREAD - 1] = ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ input[ITEMS_PER_THREAD - 1],
+ successor_item,
+ (linear_tid * ITEMS_PER_THREAD) + ITEMS_PER_THREAD);
+
+ // Set tail_flags for remaining items
+ Iterate<0, ITEMS_PER_THREAD - 1>::FlagTails(linear_tid, tail_flags, input, flag_op);
+ }
+
+
+ //@} end member group
+ /******************************************************************//**
+ * \name Head & tail flag operations
+ *********************************************************************/
+ //@{
+
+
+ /**
+ * \brief Sets both head and tail flags indicating discontinuities between items partitioned across the thread block.
+ *
+ * \par
+ * - The flag <tt>head_flags<sub><em>i</em></sub></tt> is set for item
+ * <tt>input<sub><em>i</em></sub></tt> when
+ * <tt>flag_op(</tt><em>previous-item</em><tt>, input<sub><em>i</em></sub>)</tt>
+ * returns \p true (where <em>previous-item</em> is either the preceding item
+ * in the same thread or the last item in the previous thread).
+ * - For <em>thread</em><sub>0</sub>, item <tt>input<sub>0</sub></tt> is always flagged.
+ * - The flag <tt>tail_flags<sub><em>i</em></sub></tt> is set for item
+ * <tt>input<sub><em>i</em></sub></tt> when
+ * <tt>flag_op(input<sub><em>i</em></sub>, </tt><em>next-item</em><tt>)</tt>
+ * returns \p true (where <em>next-item</em> is either the next item
+ * in the same thread or the first item in the next thread).
+ * - For <em>thread</em><sub><em>BLOCK_THREADS</em>-1</sub>, item
+ * <tt>input</tt><sub><em>ITEMS_PER_THREAD</em>-1</sub> is always flagged.
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates the head- and tail-flagging of 512 integer items that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_discontinuity.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockDiscontinuity for a 1D block of 128 threads on type int
+ * typedef cub::BlockDiscontinuity<int, 128> BlockDiscontinuity;
+ *
+ * // Allocate shared memory for BlockDiscontinuity
+ * __shared__ typename BlockDiscontinuity::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Collectively compute head and flags for discontinuities in the segment
+ * int head_flags[4];
+ * int tail_flags[4];
+ * BlockDiscontinuity(temp_storage).FlagTails(
+ * head_flags, tail_flags, thread_data, cub::Inequality());
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is
+ * <tt>{ [0,0,1,1], [1,1,1,1], [2,3,3,3], ..., [124,125,125,125] }</tt>
+ * and that the tile_successor_item is \p 125. The corresponding output \p head_flags
+ * in those threads will be <tt>{ [1,0,1,0], [0,0,0,0], [1,1,0,0], [0,1,0,0], ... }</tt>.
+ * and the corresponding output \p tail_flags in those threads will be
+ * <tt>{ [0,1,0,0], [0,0,0,1], [1,0,0,...], ..., [1,0,0,1] }</tt>.
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam FlagT <b>[inferred]</b> The flag type (must be an integer type)
+ * \tparam FlagOp <b>[inferred]</b> Binary predicate functor type having member <tt>T operator()(const T &a, const T &b)</tt> or member <tt>T operator()(const T &a, const T &b, unsigned int b_index)</tt>, and returning \p true if a discontinuity exists between \p a and \p b, otherwise \p false. \p b_index is the rank of b in the aggregate tile of data.
+ */
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ __device__ __forceinline__ void FlagHeadsAndTails(
+ FlagT (&head_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ FlagT (&tail_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity tail_flags
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ FlagOp flag_op) ///< [in] Binary boolean flag predicate
+ {
+ // Share first and last items
+ temp_storage.first_items[linear_tid] = input[0];
+ temp_storage.last_items[linear_tid] = input[ITEMS_PER_THREAD - 1];
+
+ CTA_SYNC();
+
+ T preds[ITEMS_PER_THREAD];
+
+ // Set flag for first thread-item
+ preds[0] = temp_storage.last_items[linear_tid - 1];
+ if (linear_tid == 0)
+ {
+ head_flags[0] = 1;
+ }
+ else
+ {
+ head_flags[0] = ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ preds[0],
+ input[0],
+ linear_tid * ITEMS_PER_THREAD);
+ }
+
+
+ // Set flag for last thread-item
+ tail_flags[ITEMS_PER_THREAD - 1] = (linear_tid == BLOCK_THREADS - 1) ?
+ 1 : // Last thread
+ ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ input[ITEMS_PER_THREAD - 1],
+ temp_storage.first_items[linear_tid + 1],
+ (linear_tid * ITEMS_PER_THREAD) + ITEMS_PER_THREAD);
+
+ // Set head_flags for remaining items
+ Iterate<1, ITEMS_PER_THREAD>::FlagHeads(linear_tid, head_flags, input, preds, flag_op);
+
+ // Set tail_flags for remaining items
+ Iterate<0, ITEMS_PER_THREAD - 1>::FlagTails(linear_tid, tail_flags, input, flag_op);
+ }
+
+
+ /**
+ * \brief Sets both head and tail flags indicating discontinuities between items partitioned across the thread block.
+ *
+ * \par
+ * - The flag <tt>head_flags<sub><em>i</em></sub></tt> is set for item
+ * <tt>input<sub><em>i</em></sub></tt> when
+ * <tt>flag_op(</tt><em>previous-item</em><tt>, input<sub><em>i</em></sub>)</tt>
+ * returns \p true (where <em>previous-item</em> is either the preceding item
+ * in the same thread or the last item in the previous thread).
+ * - For <em>thread</em><sub>0</sub>, item <tt>input<sub>0</sub></tt> is always flagged.
+ * - The flag <tt>tail_flags<sub><em>i</em></sub></tt> is set for item
+ * <tt>input<sub><em>i</em></sub></tt> when
+ * <tt>flag_op(input<sub><em>i</em></sub>, </tt><em>next-item</em><tt>)</tt>
+ * returns \p true (where <em>next-item</em> is either the next item
+ * in the same thread or the first item in the next thread).
+ * - For <em>thread</em><sub><em>BLOCK_THREADS</em>-1</sub>, item
+ * <tt>input</tt><sub><em>ITEMS_PER_THREAD</em>-1</sub> is compared
+ * against \p tile_predecessor_item.
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates the head- and tail-flagging of 512 integer items that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_discontinuity.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockDiscontinuity for a 1D block of 128 threads on type int
+ * typedef cub::BlockDiscontinuity<int, 128> BlockDiscontinuity;
+ *
+ * // Allocate shared memory for BlockDiscontinuity
+ * __shared__ typename BlockDiscontinuity::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Have thread127 obtain the successor item for the entire tile
+ * int tile_successor_item;
+ * if (threadIdx.x == 127) tile_successor_item == ...
+ *
+ * // Collectively compute head and flags for discontinuities in the segment
+ * int head_flags[4];
+ * int tail_flags[4];
+ * BlockDiscontinuity(temp_storage).FlagTails(
+ * head_flags, tail_flags, tile_successor_item, thread_data, cub::Inequality());
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is
+ * <tt>{ [0,0,1,1], [1,1,1,1], [2,3,3,3], ..., [124,125,125,125] }</tt>
+ * and that the tile_successor_item is \p 125. The corresponding output \p head_flags
+ * in those threads will be <tt>{ [1,0,1,0], [0,0,0,0], [1,1,0,0], [0,1,0,0], ... }</tt>.
+ * and the corresponding output \p tail_flags in those threads will be
+ * <tt>{ [0,1,0,0], [0,0,0,1], [1,0,0,...], ..., [1,0,0,0] }</tt>.
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam FlagT <b>[inferred]</b> The flag type (must be an integer type)
+ * \tparam FlagOp <b>[inferred]</b> Binary predicate functor type having member <tt>T operator()(const T &a, const T &b)</tt> or member <tt>T operator()(const T &a, const T &b, unsigned int b_index)</tt>, and returning \p true if a discontinuity exists between \p a and \p b, otherwise \p false. \p b_index is the rank of b in the aggregate tile of data.
+ */
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ __device__ __forceinline__ void FlagHeadsAndTails(
+ FlagT (&head_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ FlagT (&tail_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity tail_flags
+ T tile_successor_item, ///< [in] <b>[<em>thread</em><sub><tt>BLOCK_THREADS</tt>-1</sub> only]</b> Item with which to compare the last tile item (<tt>input</tt><sub><em>ITEMS_PER_THREAD</em>-1</sub> from <em>thread</em><sub><em>BLOCK_THREADS</em>-1</sub>).
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ FlagOp flag_op) ///< [in] Binary boolean flag predicate
+ {
+ // Share first and last items
+ temp_storage.first_items[linear_tid] = input[0];
+ temp_storage.last_items[linear_tid] = input[ITEMS_PER_THREAD - 1];
+
+ CTA_SYNC();
+
+ T preds[ITEMS_PER_THREAD];
+
+ // Set flag for first thread-item
+ if (linear_tid == 0)
+ {
+ head_flags[0] = 1;
+ }
+ else
+ {
+ preds[0] = temp_storage.last_items[linear_tid - 1];
+ head_flags[0] = ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ preds[0],
+ input[0],
+ linear_tid * ITEMS_PER_THREAD);
+ }
+
+ // Set flag for last thread-item
+ T successor_item = (linear_tid == BLOCK_THREADS - 1) ?
+ tile_successor_item : // Last thread
+ temp_storage.first_items[linear_tid + 1];
+
+ tail_flags[ITEMS_PER_THREAD - 1] = ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ input[ITEMS_PER_THREAD - 1],
+ successor_item,
+ (linear_tid * ITEMS_PER_THREAD) + ITEMS_PER_THREAD);
+
+ // Set head_flags for remaining items
+ Iterate<1, ITEMS_PER_THREAD>::FlagHeads(linear_tid, head_flags, input, preds, flag_op);
+
+ // Set tail_flags for remaining items
+ Iterate<0, ITEMS_PER_THREAD - 1>::FlagTails(linear_tid, tail_flags, input, flag_op);
+ }
+
+
+ /**
+ * \brief Sets both head and tail flags indicating discontinuities between items partitioned across the thread block.
+ *
+ * \par
+ * - The flag <tt>head_flags<sub><em>i</em></sub></tt> is set for item
+ * <tt>input<sub><em>i</em></sub></tt> when
+ * <tt>flag_op(</tt><em>previous-item</em><tt>, input<sub><em>i</em></sub>)</tt>
+ * returns \p true (where <em>previous-item</em> is either the preceding item
+ * in the same thread or the last item in the previous thread).
+ * - For <em>thread</em><sub>0</sub>, item <tt>input<sub>0</sub></tt> is compared
+ * against \p tile_predecessor_item.
+ * - The flag <tt>tail_flags<sub><em>i</em></sub></tt> is set for item
+ * <tt>input<sub><em>i</em></sub></tt> when
+ * <tt>flag_op(input<sub><em>i</em></sub>, </tt><em>next-item</em><tt>)</tt>
+ * returns \p true (where <em>next-item</em> is either the next item
+ * in the same thread or the first item in the next thread).
+ * - For <em>thread</em><sub><em>BLOCK_THREADS</em>-1</sub>, item
+ * <tt>input</tt><sub><em>ITEMS_PER_THREAD</em>-1</sub> is always flagged.
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates the head- and tail-flagging of 512 integer items that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_discontinuity.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockDiscontinuity for a 1D block of 128 threads on type int
+ * typedef cub::BlockDiscontinuity<int, 128> BlockDiscontinuity;
+ *
+ * // Allocate shared memory for BlockDiscontinuity
+ * __shared__ typename BlockDiscontinuity::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Have thread0 obtain the predecessor item for the entire tile
+ * int tile_predecessor_item;
+ * if (threadIdx.x == 0) tile_predecessor_item == ...
+ *
+ * // Have thread127 obtain the successor item for the entire tile
+ * int tile_successor_item;
+ * if (threadIdx.x == 127) tile_successor_item == ...
+ *
+ * // Collectively compute head and flags for discontinuities in the segment
+ * int head_flags[4];
+ * int tail_flags[4];
+ * BlockDiscontinuity(temp_storage).FlagTails(
+ * head_flags, tile_predecessor_item, tail_flags, tile_successor_item,
+ * thread_data, cub::Inequality());
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is
+ * <tt>{ [0,0,1,1], [1,1,1,1], [2,3,3,3], ..., [124,125,125,125] }</tt>,
+ * that the \p tile_predecessor_item is \p 0, and that the
+ * \p tile_successor_item is \p 125. The corresponding output \p head_flags
+ * in those threads will be <tt>{ [0,0,1,0], [0,0,0,0], [1,1,0,0], [0,1,0,0], ... }</tt>.
+ * and the corresponding output \p tail_flags in those threads will be
+ * <tt>{ [0,1,0,0], [0,0,0,1], [1,0,0,...], ..., [1,0,0,1] }</tt>.
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam FlagT <b>[inferred]</b> The flag type (must be an integer type)
+ * \tparam FlagOp <b>[inferred]</b> Binary predicate functor type having member <tt>T operator()(const T &a, const T &b)</tt> or member <tt>T operator()(const T &a, const T &b, unsigned int b_index)</tt>, and returning \p true if a discontinuity exists between \p a and \p b, otherwise \p false. \p b_index is the rank of b in the aggregate tile of data.
+ */
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ __device__ __forceinline__ void FlagHeadsAndTails(
+ FlagT (&head_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ T tile_predecessor_item, ///< [in] <b>[<em>thread</em><sub>0</sub> only]</b> Item with which to compare the first tile item (<tt>input<sub>0</sub></tt> from <em>thread</em><sub>0</sub>).
+ FlagT (&tail_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity tail_flags
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ FlagOp flag_op) ///< [in] Binary boolean flag predicate
+ {
+ // Share first and last items
+ temp_storage.first_items[linear_tid] = input[0];
+ temp_storage.last_items[linear_tid] = input[ITEMS_PER_THREAD - 1];
+
+ CTA_SYNC();
+
+ T preds[ITEMS_PER_THREAD];
+
+ // Set flag for first thread-item
+ preds[0] = (linear_tid == 0) ?
+ tile_predecessor_item : // First thread
+ temp_storage.last_items[linear_tid - 1];
+
+ head_flags[0] = ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ preds[0],
+ input[0],
+ linear_tid * ITEMS_PER_THREAD);
+
+ // Set flag for last thread-item
+ tail_flags[ITEMS_PER_THREAD - 1] = (linear_tid == BLOCK_THREADS - 1) ?
+ 1 : // Last thread
+ ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ input[ITEMS_PER_THREAD - 1],
+ temp_storage.first_items[linear_tid + 1],
+ (linear_tid * ITEMS_PER_THREAD) + ITEMS_PER_THREAD);
+
+ // Set head_flags for remaining items
+ Iterate<1, ITEMS_PER_THREAD>::FlagHeads(linear_tid, head_flags, input, preds, flag_op);
+
+ // Set tail_flags for remaining items
+ Iterate<0, ITEMS_PER_THREAD - 1>::FlagTails(linear_tid, tail_flags, input, flag_op);
+ }
+
+
+ /**
+ * \brief Sets both head and tail flags indicating discontinuities between items partitioned across the thread block.
+ *
+ * \par
+ * - The flag <tt>head_flags<sub><em>i</em></sub></tt> is set for item
+ * <tt>input<sub><em>i</em></sub></tt> when
+ * <tt>flag_op(</tt><em>previous-item</em><tt>, input<sub><em>i</em></sub>)</tt>
+ * returns \p true (where <em>previous-item</em> is either the preceding item
+ * in the same thread or the last item in the previous thread).
+ * - For <em>thread</em><sub>0</sub>, item <tt>input<sub>0</sub></tt> is compared
+ * against \p tile_predecessor_item.
+ * - The flag <tt>tail_flags<sub><em>i</em></sub></tt> is set for item
+ * <tt>input<sub><em>i</em></sub></tt> when
+ * <tt>flag_op(input<sub><em>i</em></sub>, </tt><em>next-item</em><tt>)</tt>
+ * returns \p true (where <em>next-item</em> is either the next item
+ * in the same thread or the first item in the next thread).
+ * - For <em>thread</em><sub><em>BLOCK_THREADS</em>-1</sub>, item
+ * <tt>input</tt><sub><em>ITEMS_PER_THREAD</em>-1</sub> is compared
+ * against \p tile_successor_item.
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates the head- and tail-flagging of 512 integer items that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_discontinuity.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockDiscontinuity for a 1D block of 128 threads on type int
+ * typedef cub::BlockDiscontinuity<int, 128> BlockDiscontinuity;
+ *
+ * // Allocate shared memory for BlockDiscontinuity
+ * __shared__ typename BlockDiscontinuity::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Have thread0 obtain the predecessor item for the entire tile
+ * int tile_predecessor_item;
+ * if (threadIdx.x == 0) tile_predecessor_item == ...
+ *
+ * // Have thread127 obtain the successor item for the entire tile
+ * int tile_successor_item;
+ * if (threadIdx.x == 127) tile_successor_item == ...
+ *
+ * // Collectively compute head and flags for discontinuities in the segment
+ * int head_flags[4];
+ * int tail_flags[4];
+ * BlockDiscontinuity(temp_storage).FlagTails(
+ * head_flags, tile_predecessor_item, tail_flags, tile_successor_item,
+ * thread_data, cub::Inequality());
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is
+ * <tt>{ [0,0,1,1], [1,1,1,1], [2,3,3,3], ..., [124,125,125,125] }</tt>,
+ * that the \p tile_predecessor_item is \p 0, and that the
+ * \p tile_successor_item is \p 125. The corresponding output \p head_flags
+ * in those threads will be <tt>{ [0,0,1,0], [0,0,0,0], [1,1,0,0], [0,1,0,0], ... }</tt>.
+ * and the corresponding output \p tail_flags in those threads will be
+ * <tt>{ [0,1,0,0], [0,0,0,1], [1,0,0,...], ..., [1,0,0,0] }</tt>.
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam FlagT <b>[inferred]</b> The flag type (must be an integer type)
+ * \tparam FlagOp <b>[inferred]</b> Binary predicate functor type having member <tt>T operator()(const T &a, const T &b)</tt> or member <tt>T operator()(const T &a, const T &b, unsigned int b_index)</tt>, and returning \p true if a discontinuity exists between \p a and \p b, otherwise \p false. \p b_index is the rank of b in the aggregate tile of data.
+ */
+ template <
+ int ITEMS_PER_THREAD,
+ typename FlagT,
+ typename FlagOp>
+ __device__ __forceinline__ void FlagHeadsAndTails(
+ FlagT (&head_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity head_flags
+ T tile_predecessor_item, ///< [in] <b>[<em>thread</em><sub>0</sub> only]</b> Item with which to compare the first tile item (<tt>input<sub>0</sub></tt> from <em>thread</em><sub>0</sub>).
+ FlagT (&tail_flags)[ITEMS_PER_THREAD], ///< [out] Calling thread's discontinuity tail_flags
+ T tile_successor_item, ///< [in] <b>[<em>thread</em><sub><tt>BLOCK_THREADS</tt>-1</sub> only]</b> Item with which to compare the last tile item (<tt>input</tt><sub><em>ITEMS_PER_THREAD</em>-1</sub> from <em>thread</em><sub><em>BLOCK_THREADS</em>-1</sub>).
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ FlagOp flag_op) ///< [in] Binary boolean flag predicate
+ {
+ // Share first and last items
+ temp_storage.first_items[linear_tid] = input[0];
+ temp_storage.last_items[linear_tid] = input[ITEMS_PER_THREAD - 1];
+
+ CTA_SYNC();
+
+ T preds[ITEMS_PER_THREAD];
+
+ // Set flag for first thread-item
+ preds[0] = (linear_tid == 0) ?
+ tile_predecessor_item : // First thread
+ temp_storage.last_items[linear_tid - 1];
+
+ head_flags[0] = ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ preds[0],
+ input[0],
+ linear_tid * ITEMS_PER_THREAD);
+
+ // Set flag for last thread-item
+ T successor_item = (linear_tid == BLOCK_THREADS - 1) ?
+ tile_successor_item : // Last thread
+ temp_storage.first_items[linear_tid + 1];
+
+ tail_flags[ITEMS_PER_THREAD - 1] = ApplyOp<FlagOp>::FlagT(
+ flag_op,
+ input[ITEMS_PER_THREAD - 1],
+ successor_item,
+ (linear_tid * ITEMS_PER_THREAD) + ITEMS_PER_THREAD);
+
+ // Set head_flags for remaining items
+ Iterate<1, ITEMS_PER_THREAD>::FlagHeads(linear_tid, head_flags, input, preds, flag_op);
+
+ // Set tail_flags for remaining items
+ Iterate<0, ITEMS_PER_THREAD - 1>::FlagTails(linear_tid, tail_flags, input, flag_op);
+ }
+
+
+
+
+ //@} end member group
+
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_exchange.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_exchange.cuh
new file mode 100644
index 0000000..3ae9934
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_exchange.cuh
@@ -0,0 +1,1248 @@
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-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 TORT
+ * (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
+ * The cub::BlockExchange class provides [<em>collective</em>](index.html#sec0) methods for rearranging data partitioned across a CUDA thread block.
+ */
+
+#pragma once
+
+#include "../util_ptx.cuh"
+#include "../util_arch.cuh"
+#include "../util_macro.cuh"
+#include "../util_type.cuh"
+#include "../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+/**
+ * \brief The BlockExchange class provides [<em>collective</em>](index.html#sec0) methods for rearranging data partitioned across a CUDA thread block. ![](transpose_logo.png)
+ * \ingroup BlockModule
+ *
+ * \tparam T The data type to be exchanged.
+ * \tparam BLOCK_DIM_X The thread block length in threads along the X dimension
+ * \tparam ITEMS_PER_THREAD The number of items partitioned onto each thread.
+ * \tparam WARP_TIME_SLICING <b>[optional]</b> When \p true, only use enough shared memory for a single warp's worth of tile data, time-slicing the block-wide exchange over multiple synchronized rounds. Yields a smaller memory footprint at the expense of decreased parallelism. (Default: false)
+ * \tparam BLOCK_DIM_Y <b>[optional]</b> The thread block length in threads along the Y dimension (default: 1)
+ * \tparam BLOCK_DIM_Z <b>[optional]</b> The thread block length in threads along the Z dimension (default: 1)
+ * \tparam PTX_ARCH <b>[optional]</b> \ptxversion
+ *
+ * \par Overview
+ * - It is commonplace for blocks of threads to rearrange data items between
+ * threads. For example, the device-accessible memory subsystem prefers access patterns
+ * where data items are "striped" across threads (where consecutive threads access consecutive items),
+ * yet most block-wide operations prefer a "blocked" partitioning of items across threads
+ * (where consecutive items belong to a single thread).
+ * - BlockExchange supports the following types of data exchanges:
+ * - Transposing between [<em>blocked</em>](index.html#sec5sec3) and [<em>striped</em>](index.html#sec5sec3) arrangements
+ * - Transposing between [<em>blocked</em>](index.html#sec5sec3) and [<em>warp-striped</em>](index.html#sec5sec3) arrangements
+ * - Scattering ranked items to a [<em>blocked arrangement</em>](index.html#sec5sec3)
+ * - Scattering ranked items to a [<em>striped arrangement</em>](index.html#sec5sec3)
+ * - \rowmajor
+ *
+ * \par A Simple Example
+ * \blockcollective{BlockExchange}
+ * \par
+ * The code snippet below illustrates the conversion from a "blocked" to a "striped" arrangement
+ * of 512 integer items partitioned across 128 threads where each thread owns 4 items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_exchange.cuh>
+ *
+ * __global__ void ExampleKernel(int *d_data, ...)
+ * {
+ * // Specialize BlockExchange for a 1D block of 128 threads owning 4 integer items each
+ * typedef cub::BlockExchange<int, 128, 4> BlockExchange;
+ *
+ * // Allocate shared memory for BlockExchange
+ * __shared__ typename BlockExchange::TempStorage temp_storage;
+ *
+ * // Load a tile of data striped across threads
+ * int thread_data[4];
+ * cub::LoadDirectStriped<128>(threadIdx.x, d_data, thread_data);
+ *
+ * // Collectively exchange data into a blocked arrangement across threads
+ * BlockExchange(temp_storage).StripedToBlocked(thread_data);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of striped input \p thread_data across the block of threads is
+ * <tt>{ [0,128,256,384], [1,129,257,385], ..., [127,255,383,511] }</tt>.
+ * The corresponding output \p thread_data in those threads will be
+ * <tt>{ [0,1,2,3], [4,5,6,7], [8,9,10,11], ..., [508,509,510,511] }</tt>.
+ *
+ * \par Performance Considerations
+ * - Proper device-specific padding ensures zero bank conflicts for most types.
+ *
+ */
+template <
+ typename InputT,
+ int BLOCK_DIM_X,
+ int ITEMS_PER_THREAD,
+ bool WARP_TIME_SLICING = false,
+ int BLOCK_DIM_Y = 1,
+ int BLOCK_DIM_Z = 1,
+ int PTX_ARCH = CUB_PTX_ARCH>
+class BlockExchange
+{
+private:
+
+ /******************************************************************************
+ * Constants
+ ******************************************************************************/
+
+ /// Constants
+ enum
+ {
+ /// The thread block size in threads
+ BLOCK_THREADS = BLOCK_DIM_X * BLOCK_DIM_Y * BLOCK_DIM_Z,
+
+ LOG_WARP_THREADS = CUB_LOG_WARP_THREADS(PTX_ARCH),
+ WARP_THREADS = 1 << LOG_WARP_THREADS,
+ WARPS = (BLOCK_THREADS + WARP_THREADS - 1) / WARP_THREADS,
+
+ LOG_SMEM_BANKS = CUB_LOG_SMEM_BANKS(PTX_ARCH),
+ SMEM_BANKS = 1 << LOG_SMEM_BANKS,
+
+ TILE_ITEMS = BLOCK_THREADS * ITEMS_PER_THREAD,
+
+ TIME_SLICES = (WARP_TIME_SLICING) ? WARPS : 1,
+
+ TIME_SLICED_THREADS = (WARP_TIME_SLICING) ? CUB_MIN(BLOCK_THREADS, WARP_THREADS) : BLOCK_THREADS,
+ TIME_SLICED_ITEMS = TIME_SLICED_THREADS * ITEMS_PER_THREAD,
+
+ WARP_TIME_SLICED_THREADS = CUB_MIN(BLOCK_THREADS, WARP_THREADS),
+ WARP_TIME_SLICED_ITEMS = WARP_TIME_SLICED_THREADS * ITEMS_PER_THREAD,
+
+ // Insert padding to avoid bank conflicts during raking when items per thread is a power of two and > 4 (otherwise we can typically use 128b loads)
+ INSERT_PADDING = (ITEMS_PER_THREAD > 4) && (PowerOfTwo<ITEMS_PER_THREAD>::VALUE),
+ PADDING_ITEMS = (INSERT_PADDING) ? (TIME_SLICED_ITEMS >> LOG_SMEM_BANKS) : 0,
+ };
+
+ /******************************************************************************
+ * Type definitions
+ ******************************************************************************/
+
+ /// Shared memory storage layout type
+ struct __align__(16) _TempStorage
+ {
+ InputT buff[TIME_SLICED_ITEMS + PADDING_ITEMS];
+ };
+
+public:
+
+ /// \smemstorage{BlockExchange}
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+private:
+
+
+ /******************************************************************************
+ * Thread fields
+ ******************************************************************************/
+
+ /// Shared storage reference
+ _TempStorage &temp_storage;
+
+ /// Linear thread-id
+ unsigned int linear_tid;
+ unsigned int lane_id;
+ unsigned int warp_id;
+ unsigned int warp_offset;
+
+
+ /******************************************************************************
+ * Utility methods
+ ******************************************************************************/
+
+ /// Internal storage allocator
+ __device__ __forceinline__ _TempStorage& PrivateStorage()
+ {
+ __shared__ _TempStorage private_storage;
+ return private_storage;
+ }
+
+
+ /**
+ * Transposes data items from <em>blocked</em> arrangement to <em>striped</em> arrangement. Specialized for no timeslicing.
+ */
+ template <typename OutputT>
+ __device__ __forceinline__ void BlockedToStriped(
+ InputT input_items[ITEMS_PER_THREAD], ///< [in] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ OutputT output_items[ITEMS_PER_THREAD], ///< [out] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ Int2Type<false> /*time_slicing*/)
+ {
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = (linear_tid * ITEMS_PER_THREAD) + ITEM;
+ if (INSERT_PADDING) item_offset += item_offset >> LOG_SMEM_BANKS;
+ temp_storage.buff[item_offset] = input_items[ITEM];
+ }
+
+ CTA_SYNC();
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = int(ITEM * BLOCK_THREADS) + linear_tid;
+ if (INSERT_PADDING) item_offset += item_offset >> LOG_SMEM_BANKS;
+ output_items[ITEM] = temp_storage.buff[item_offset];
+ }
+ }
+
+
+ /**
+ * Transposes data items from <em>blocked</em> arrangement to <em>striped</em> arrangement. Specialized for warp-timeslicing.
+ */
+ template <typename OutputT>
+ __device__ __forceinline__ void BlockedToStriped(
+ InputT input_items[ITEMS_PER_THREAD], ///< [in] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ OutputT output_items[ITEMS_PER_THREAD], ///< [out] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ Int2Type<true> /*time_slicing*/)
+ {
+ InputT temp_items[ITEMS_PER_THREAD];
+
+ #pragma unroll
+ for (int SLICE = 0; SLICE < TIME_SLICES; SLICE++)
+ {
+ const int SLICE_OFFSET = SLICE * TIME_SLICED_ITEMS;
+ const int SLICE_OOB = SLICE_OFFSET + TIME_SLICED_ITEMS;
+
+ CTA_SYNC();
+
+ if (warp_id == SLICE)
+ {
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = (lane_id * ITEMS_PER_THREAD) + ITEM;
+ if (INSERT_PADDING) item_offset += item_offset >> LOG_SMEM_BANKS;
+ temp_storage.buff[item_offset] = input_items[ITEM];
+ }
+ }
+
+ CTA_SYNC();
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ // Read a strip of items
+ const int STRIP_OFFSET = ITEM * BLOCK_THREADS;
+ const int STRIP_OOB = STRIP_OFFSET + BLOCK_THREADS;
+
+ if ((SLICE_OFFSET < STRIP_OOB) && (SLICE_OOB > STRIP_OFFSET))
+ {
+ int item_offset = STRIP_OFFSET + linear_tid - SLICE_OFFSET;
+ if ((item_offset >= 0) && (item_offset < TIME_SLICED_ITEMS))
+ {
+ if (INSERT_PADDING) item_offset += item_offset >> LOG_SMEM_BANKS;
+ temp_items[ITEM] = temp_storage.buff[item_offset];
+ }
+ }
+ }
+ }
+
+ // Copy
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ output_items[ITEM] = temp_items[ITEM];
+ }
+ }
+
+
+ /**
+ * Transposes data items from <em>blocked</em> arrangement to <em>warp-striped</em> arrangement. Specialized for no timeslicing
+ */
+ template <typename OutputT>
+ __device__ __forceinline__ void BlockedToWarpStriped(
+ InputT input_items[ITEMS_PER_THREAD], ///< [in] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ OutputT output_items[ITEMS_PER_THREAD], ///< [out] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ Int2Type<false> /*time_slicing*/)
+ {
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = warp_offset + ITEM + (lane_id * ITEMS_PER_THREAD);
+ if (INSERT_PADDING) item_offset += item_offset >> LOG_SMEM_BANKS;
+ temp_storage.buff[item_offset] = input_items[ITEM];
+ }
+
+ WARP_SYNC(0xffffffff);
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = warp_offset + (ITEM * WARP_TIME_SLICED_THREADS) + lane_id;
+ if (INSERT_PADDING) item_offset += item_offset >> LOG_SMEM_BANKS;
+ output_items[ITEM] = temp_storage.buff[item_offset];
+ }
+ }
+
+ /**
+ * Transposes data items from <em>blocked</em> arrangement to <em>warp-striped</em> arrangement. Specialized for warp-timeslicing
+ */
+ template <typename OutputT>
+ __device__ __forceinline__ void BlockedToWarpStriped(
+ InputT input_items[ITEMS_PER_THREAD], ///< [in] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ OutputT output_items[ITEMS_PER_THREAD], ///< [out] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ Int2Type<true> /*time_slicing*/)
+ {
+ if (warp_id == 0)
+ {
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = ITEM + (lane_id * ITEMS_PER_THREAD);
+ if (INSERT_PADDING) item_offset += item_offset >> LOG_SMEM_BANKS;
+ temp_storage.buff[item_offset] = input_items[ITEM];
+ }
+
+ WARP_SYNC(0xffffffff);
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = (ITEM * WARP_TIME_SLICED_THREADS) + lane_id;
+ if (INSERT_PADDING) item_offset += item_offset >> LOG_SMEM_BANKS;
+ output_items[ITEM] = temp_storage.buff[item_offset];
+ }
+ }
+
+ #pragma unroll
+ for (unsigned int SLICE = 1; SLICE < TIME_SLICES; ++SLICE)
+ {
+ CTA_SYNC();
+
+ if (warp_id == SLICE)
+ {
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = ITEM + (lane_id * ITEMS_PER_THREAD);
+ if (INSERT_PADDING) item_offset += item_offset >> LOG_SMEM_BANKS;
+ temp_storage.buff[item_offset] = input_items[ITEM];
+ }
+
+ WARP_SYNC(0xffffffff);
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = (ITEM * WARP_TIME_SLICED_THREADS) + lane_id;
+ if (INSERT_PADDING) item_offset += item_offset >> LOG_SMEM_BANKS;
+ output_items[ITEM] = temp_storage.buff[item_offset];
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Transposes data items from <em>striped</em> arrangement to <em>blocked</em> arrangement. Specialized for no timeslicing.
+ */
+ template <typename OutputT>
+ __device__ __forceinline__ void StripedToBlocked(
+ InputT input_items[ITEMS_PER_THREAD], ///< [in] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ OutputT output_items[ITEMS_PER_THREAD], ///< [out] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ Int2Type<false> /*time_slicing*/)
+ {
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = int(ITEM * BLOCK_THREADS) + linear_tid;
+ if (INSERT_PADDING) item_offset += item_offset >> LOG_SMEM_BANKS;
+ temp_storage.buff[item_offset] = input_items[ITEM];
+ }
+
+ CTA_SYNC();
+
+ // No timeslicing
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = (linear_tid * ITEMS_PER_THREAD) + ITEM;
+ if (INSERT_PADDING) item_offset += item_offset >> LOG_SMEM_BANKS;
+ output_items[ITEM] = temp_storage.buff[item_offset];
+ }
+ }
+
+
+ /**
+ * Transposes data items from <em>striped</em> arrangement to <em>blocked</em> arrangement. Specialized for warp-timeslicing.
+ */
+ template <typename OutputT>
+ __device__ __forceinline__ void StripedToBlocked(
+ InputT input_items[ITEMS_PER_THREAD], ///< [in] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ OutputT output_items[ITEMS_PER_THREAD], ///< [out] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ Int2Type<true> /*time_slicing*/)
+ {
+ // Warp time-slicing
+ InputT temp_items[ITEMS_PER_THREAD];
+
+ #pragma unroll
+ for (int SLICE = 0; SLICE < TIME_SLICES; SLICE++)
+ {
+ const int SLICE_OFFSET = SLICE * TIME_SLICED_ITEMS;
+ const int SLICE_OOB = SLICE_OFFSET + TIME_SLICED_ITEMS;
+
+ CTA_SYNC();
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ // Write a strip of items
+ const int STRIP_OFFSET = ITEM * BLOCK_THREADS;
+ const int STRIP_OOB = STRIP_OFFSET + BLOCK_THREADS;
+
+ if ((SLICE_OFFSET < STRIP_OOB) && (SLICE_OOB > STRIP_OFFSET))
+ {
+ int item_offset = STRIP_OFFSET + linear_tid - SLICE_OFFSET;
+ if ((item_offset >= 0) && (item_offset < TIME_SLICED_ITEMS))
+ {
+ if (INSERT_PADDING) item_offset += item_offset >> LOG_SMEM_BANKS;
+ temp_storage.buff[item_offset] = input_items[ITEM];
+ }
+ }
+ }
+
+ CTA_SYNC();
+
+ if (warp_id == SLICE)
+ {
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = (lane_id * ITEMS_PER_THREAD) + ITEM;
+ if (INSERT_PADDING) item_offset += item_offset >> LOG_SMEM_BANKS;
+ temp_items[ITEM] = temp_storage.buff[item_offset];
+ }
+ }
+ }
+
+ // Copy
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ output_items[ITEM] = temp_items[ITEM];
+ }
+ }
+
+
+ /**
+ * Transposes data items from <em>warp-striped</em> arrangement to <em>blocked</em> arrangement. Specialized for no timeslicing
+ */
+ template <typename OutputT>
+ __device__ __forceinline__ void WarpStripedToBlocked(
+ InputT input_items[ITEMS_PER_THREAD], ///< [in] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ OutputT output_items[ITEMS_PER_THREAD], ///< [out] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ Int2Type<false> /*time_slicing*/)
+ {
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = warp_offset + (ITEM * WARP_TIME_SLICED_THREADS) + lane_id;
+ if (INSERT_PADDING) item_offset += item_offset >> LOG_SMEM_BANKS;
+ temp_storage.buff[item_offset] = input_items[ITEM];
+ }
+
+ WARP_SYNC(0xffffffff);
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = warp_offset + ITEM + (lane_id * ITEMS_PER_THREAD);
+ if (INSERT_PADDING) item_offset += item_offset >> LOG_SMEM_BANKS;
+ output_items[ITEM] = temp_storage.buff[item_offset];
+ }
+ }
+
+
+ /**
+ * Transposes data items from <em>warp-striped</em> arrangement to <em>blocked</em> arrangement. Specialized for warp-timeslicing
+ */
+ template <typename OutputT>
+ __device__ __forceinline__ void WarpStripedToBlocked(
+ InputT input_items[ITEMS_PER_THREAD], ///< [in] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ OutputT output_items[ITEMS_PER_THREAD], ///< [out] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ Int2Type<true> /*time_slicing*/)
+ {
+ #pragma unroll
+ for (unsigned int SLICE = 0; SLICE < TIME_SLICES; ++SLICE)
+ {
+ CTA_SYNC();
+
+ if (warp_id == SLICE)
+ {
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = (ITEM * WARP_TIME_SLICED_THREADS) + lane_id;
+ if (INSERT_PADDING) item_offset += item_offset >> LOG_SMEM_BANKS;
+ temp_storage.buff[item_offset] = input_items[ITEM];
+ }
+
+ WARP_SYNC(0xffffffff);
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = ITEM + (lane_id * ITEMS_PER_THREAD);
+ if (INSERT_PADDING) item_offset += item_offset >> LOG_SMEM_BANKS;
+ output_items[ITEM] = temp_storage.buff[item_offset];
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Exchanges data items annotated by rank into <em>blocked</em> arrangement. Specialized for no timeslicing.
+ */
+ template <typename OutputT, typename OffsetT>
+ __device__ __forceinline__ void ScatterToBlocked(
+ InputT input_items[ITEMS_PER_THREAD], ///< [in] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ OutputT output_items[ITEMS_PER_THREAD], ///< [out] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ OffsetT ranks[ITEMS_PER_THREAD], ///< [in] Corresponding scatter ranks
+ Int2Type<false> /*time_slicing*/)
+ {
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = ranks[ITEM];
+ if (INSERT_PADDING) item_offset = SHR_ADD(item_offset, LOG_SMEM_BANKS, item_offset);
+ temp_storage.buff[item_offset] = input_items[ITEM];
+ }
+
+ CTA_SYNC();
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = (linear_tid * ITEMS_PER_THREAD) + ITEM;
+ if (INSERT_PADDING) item_offset = SHR_ADD(item_offset, LOG_SMEM_BANKS, item_offset);
+ output_items[ITEM] = temp_storage.buff[item_offset];
+ }
+ }
+
+ /**
+ * Exchanges data items annotated by rank into <em>blocked</em> arrangement. Specialized for warp-timeslicing.
+ */
+ template <typename OutputT, typename OffsetT>
+ __device__ __forceinline__ void ScatterToBlocked(
+ InputT input_items[ITEMS_PER_THREAD], ///< [in] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ OutputT output_items[ITEMS_PER_THREAD], ///< [out] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ OffsetT ranks[ITEMS_PER_THREAD], ///< [in] Corresponding scatter ranks
+ Int2Type<true> /*time_slicing*/)
+ {
+ InputT temp_items[ITEMS_PER_THREAD];
+
+ #pragma unroll
+ for (int SLICE = 0; SLICE < TIME_SLICES; SLICE++)
+ {
+ CTA_SYNC();
+
+ const int SLICE_OFFSET = TIME_SLICED_ITEMS * SLICE;
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = ranks[ITEM] - SLICE_OFFSET;
+ if ((item_offset >= 0) && (item_offset < WARP_TIME_SLICED_ITEMS))
+ {
+ if (INSERT_PADDING) item_offset = SHR_ADD(item_offset, LOG_SMEM_BANKS, item_offset);
+ temp_storage.buff[item_offset] = input_items[ITEM];
+ }
+ }
+
+ CTA_SYNC();
+
+ if (warp_id == SLICE)
+ {
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = (lane_id * ITEMS_PER_THREAD) + ITEM;
+ if (INSERT_PADDING) item_offset = SHR_ADD(item_offset, LOG_SMEM_BANKS, item_offset);
+ temp_items[ITEM] = temp_storage.buff[item_offset];
+ }
+ }
+ }
+
+ // Copy
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ output_items[ITEM] = temp_items[ITEM];
+ }
+ }
+
+
+ /**
+ * Exchanges data items annotated by rank into <em>striped</em> arrangement. Specialized for no timeslicing.
+ */
+ template <typename OutputT, typename OffsetT>
+ __device__ __forceinline__ void ScatterToStriped(
+ InputT input_items[ITEMS_PER_THREAD], ///< [in] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ OutputT output_items[ITEMS_PER_THREAD], ///< [out] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ OffsetT ranks[ITEMS_PER_THREAD], ///< [in] Corresponding scatter ranks
+ Int2Type<false> /*time_slicing*/)
+ {
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = ranks[ITEM];
+ if (INSERT_PADDING) item_offset = SHR_ADD(item_offset, LOG_SMEM_BANKS, item_offset);
+ temp_storage.buff[item_offset] = input_items[ITEM];
+ }
+
+ CTA_SYNC();
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = int(ITEM * BLOCK_THREADS) + linear_tid;
+ if (INSERT_PADDING) item_offset = SHR_ADD(item_offset, LOG_SMEM_BANKS, item_offset);
+ output_items[ITEM] = temp_storage.buff[item_offset];
+ }
+ }
+
+
+ /**
+ * Exchanges data items annotated by rank into <em>striped</em> arrangement. Specialized for warp-timeslicing.
+ */
+ template <typename OutputT, typename OffsetT>
+ __device__ __forceinline__ void ScatterToStriped(
+ InputT input_items[ITEMS_PER_THREAD], ///< [in] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ OutputT output_items[ITEMS_PER_THREAD], ///< [out] Items to exchange, converting between <em>blocked</em> and <em>striped</em> arrangements.
+ OffsetT ranks[ITEMS_PER_THREAD], ///< [in] Corresponding scatter ranks
+ Int2Type<true> /*time_slicing*/)
+ {
+ InputT temp_items[ITEMS_PER_THREAD];
+
+ #pragma unroll
+ for (int SLICE = 0; SLICE < TIME_SLICES; SLICE++)
+ {
+ const int SLICE_OFFSET = SLICE * TIME_SLICED_ITEMS;
+ const int SLICE_OOB = SLICE_OFFSET + TIME_SLICED_ITEMS;
+
+ CTA_SYNC();
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = ranks[ITEM] - SLICE_OFFSET;
+ if ((item_offset >= 0) && (item_offset < WARP_TIME_SLICED_ITEMS))
+ {
+ if (INSERT_PADDING) item_offset = SHR_ADD(item_offset, LOG_SMEM_BANKS, item_offset);
+ temp_storage.buff[item_offset] = input_items[ITEM];
+ }
+ }
+
+ CTA_SYNC();
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ // Read a strip of items
+ const int STRIP_OFFSET = ITEM * BLOCK_THREADS;
+ const int STRIP_OOB = STRIP_OFFSET + BLOCK_THREADS;
+
+ if ((SLICE_OFFSET < STRIP_OOB) && (SLICE_OOB > STRIP_OFFSET))
+ {
+ int item_offset = STRIP_OFFSET + linear_tid - SLICE_OFFSET;
+ if ((item_offset >= 0) && (item_offset < TIME_SLICED_ITEMS))
+ {
+ if (INSERT_PADDING) item_offset += item_offset >> LOG_SMEM_BANKS;
+ temp_items[ITEM] = temp_storage.buff[item_offset];
+ }
+ }
+ }
+ }
+
+ // Copy
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ output_items[ITEM] = temp_items[ITEM];
+ }
+ }
+
+
+public:
+
+ /******************************************************************//**
+ * \name Collective constructors
+ *********************************************************************/
+ //@{
+
+ /**
+ * \brief Collective constructor using a private static allocation of shared memory as temporary storage.
+ */
+ __device__ __forceinline__ BlockExchange()
+ :
+ temp_storage(PrivateStorage()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z)),
+ warp_id((WARPS == 1) ? 0 : linear_tid / WARP_THREADS),
+ lane_id(LaneId()),
+ warp_offset(warp_id * WARP_TIME_SLICED_ITEMS)
+ {}
+
+
+ /**
+ * \brief Collective constructor using the specified memory allocation as temporary storage.
+ */
+ __device__ __forceinline__ BlockExchange(
+ TempStorage &temp_storage) ///< [in] Reference to memory allocation having layout type TempStorage
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z)),
+ lane_id(LaneId()),
+ warp_id((WARPS == 1) ? 0 : linear_tid / WARP_THREADS),
+ warp_offset(warp_id * WARP_TIME_SLICED_ITEMS)
+ {}
+
+
+ //@} end member group
+ /******************************************************************//**
+ * \name Structured exchanges
+ *********************************************************************/
+ //@{
+
+ /**
+ * \brief Transposes data items from <em>striped</em> arrangement to <em>blocked</em> arrangement.
+ *
+ * \par
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates the conversion from a "striped" to a "blocked" arrangement
+ * of 512 integer items partitioned across 128 threads where each thread owns 4 items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_exchange.cuh>
+ *
+ * __global__ void ExampleKernel(int *d_data, ...)
+ * {
+ * // Specialize BlockExchange for a 1D block of 128 threads owning 4 integer items each
+ * typedef cub::BlockExchange<int, 128, 4> BlockExchange;
+ *
+ * // Allocate shared memory for BlockExchange
+ * __shared__ typename BlockExchange::TempStorage temp_storage;
+ *
+ * // Load a tile of ordered data into a striped arrangement across block threads
+ * int thread_data[4];
+ * cub::LoadDirectStriped<128>(threadIdx.x, d_data, thread_data);
+ *
+ * // Collectively exchange data into a blocked arrangement across threads
+ * BlockExchange(temp_storage).StripedToBlocked(thread_data, thread_data);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of striped input \p thread_data across the block of threads is
+ * <tt>{ [0,128,256,384], [1,129,257,385], ..., [127,255,383,511] }</tt> after loading from device-accessible memory.
+ * The corresponding output \p thread_data in those threads will be
+ * <tt>{ [0,1,2,3], [4,5,6,7], [8,9,10,11], ..., [508,509,510,511] }</tt>.
+ *
+ */
+ template <typename OutputT>
+ __device__ __forceinline__ void StripedToBlocked(
+ InputT input_items[ITEMS_PER_THREAD], ///< [in] Items to exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ OutputT output_items[ITEMS_PER_THREAD]) ///< [out] Items from exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ {
+ StripedToBlocked(input_items, output_items, Int2Type<WARP_TIME_SLICING>());
+ }
+
+
+ /**
+ * \brief Transposes data items from <em>blocked</em> arrangement to <em>striped</em> arrangement.
+ *
+ * \par
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates the conversion from a "blocked" to a "striped" arrangement
+ * of 512 integer items partitioned across 128 threads where each thread owns 4 items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_exchange.cuh>
+ *
+ * __global__ void ExampleKernel(int *d_data, ...)
+ * {
+ * // Specialize BlockExchange for a 1D block of 128 threads owning 4 integer items each
+ * typedef cub::BlockExchange<int, 128, 4> BlockExchange;
+ *
+ * // Allocate shared memory for BlockExchange
+ * __shared__ typename BlockExchange::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Collectively exchange data into a striped arrangement across threads
+ * BlockExchange(temp_storage).BlockedToStriped(thread_data, thread_data);
+ *
+ * // Store data striped across block threads into an ordered tile
+ * cub::StoreDirectStriped<STORE_DEFAULT, 128>(threadIdx.x, d_data, thread_data);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of blocked input \p thread_data across the block of threads is
+ * <tt>{ [0,1,2,3], [4,5,6,7], [8,9,10,11], ..., [508,509,510,511] }</tt>.
+ * The corresponding output \p thread_data in those threads will be
+ * <tt>{ [0,128,256,384], [1,129,257,385], ..., [127,255,383,511] }</tt> in
+ * preparation for storing to device-accessible memory.
+ *
+ */
+ template <typename OutputT>
+ __device__ __forceinline__ void BlockedToStriped(
+ InputT input_items[ITEMS_PER_THREAD], ///< [in] Items to exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ OutputT output_items[ITEMS_PER_THREAD]) ///< [out] Items from exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ {
+ BlockedToStriped(input_items, output_items, Int2Type<WARP_TIME_SLICING>());
+ }
+
+
+
+ /**
+ * \brief Transposes data items from <em>warp-striped</em> arrangement to <em>blocked</em> arrangement.
+ *
+ * \par
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates the conversion from a "warp-striped" to a "blocked" arrangement
+ * of 512 integer items partitioned across 128 threads where each thread owns 4 items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_exchange.cuh>
+ *
+ * __global__ void ExampleKernel(int *d_data, ...)
+ * {
+ * // Specialize BlockExchange for a 1D block of 128 threads owning 4 integer items each
+ * typedef cub::BlockExchange<int, 128, 4> BlockExchange;
+ *
+ * // Allocate shared memory for BlockExchange
+ * __shared__ typename BlockExchange::TempStorage temp_storage;
+ *
+ * // Load a tile of ordered data into a warp-striped arrangement across warp threads
+ * int thread_data[4];
+ * cub::LoadSWarptriped<LOAD_DEFAULT>(threadIdx.x, d_data, thread_data);
+ *
+ * // Collectively exchange data into a blocked arrangement across threads
+ * BlockExchange(temp_storage).WarpStripedToBlocked(thread_data);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of warp-striped input \p thread_data across the block of threads is
+ * <tt>{ [0,32,64,96], [1,33,65,97], [2,34,66,98], ..., [415,447,479,511] }</tt>
+ * after loading from device-accessible memory. (The first 128 items are striped across
+ * the first warp of 32 threads, the second 128 items are striped across the second warp, etc.)
+ * The corresponding output \p thread_data in those threads will be
+ * <tt>{ [0,1,2,3], [4,5,6,7], [8,9,10,11], ..., [508,509,510,511] }</tt>.
+ *
+ */
+ template <typename OutputT>
+ __device__ __forceinline__ void WarpStripedToBlocked(
+ InputT input_items[ITEMS_PER_THREAD], ///< [in] Items to exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ OutputT output_items[ITEMS_PER_THREAD]) ///< [out] Items from exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ {
+ WarpStripedToBlocked(input_items, output_items, Int2Type<WARP_TIME_SLICING>());
+ }
+
+
+
+ /**
+ * \brief Transposes data items from <em>blocked</em> arrangement to <em>warp-striped</em> arrangement.
+ *
+ * \par
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates the conversion from a "blocked" to a "warp-striped" arrangement
+ * of 512 integer items partitioned across 128 threads where each thread owns 4 items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_exchange.cuh>
+ *
+ * __global__ void ExampleKernel(int *d_data, ...)
+ * {
+ * // Specialize BlockExchange for a 1D block of 128 threads owning 4 integer items each
+ * typedef cub::BlockExchange<int, 128, 4> BlockExchange;
+ *
+ * // Allocate shared memory for BlockExchange
+ * __shared__ typename BlockExchange::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Collectively exchange data into a warp-striped arrangement across threads
+ * BlockExchange(temp_storage).BlockedToWarpStriped(thread_data, thread_data);
+ *
+ * // Store data striped across warp threads into an ordered tile
+ * cub::StoreDirectStriped<STORE_DEFAULT, 128>(threadIdx.x, d_data, thread_data);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of blocked input \p thread_data across the block of threads is
+ * <tt>{ [0,1,2,3], [4,5,6,7], [8,9,10,11], ..., [508,509,510,511] }</tt>.
+ * The corresponding output \p thread_data in those threads will be
+ * <tt>{ [0,32,64,96], [1,33,65,97], [2,34,66,98], ..., [415,447,479,511] }</tt>
+ * in preparation for storing to device-accessible memory. (The first 128 items are striped across
+ * the first warp of 32 threads, the second 128 items are striped across the second warp, etc.)
+ *
+ */
+ template <typename OutputT>
+ __device__ __forceinline__ void BlockedToWarpStriped(
+ InputT input_items[ITEMS_PER_THREAD], ///< [in] Items to exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ OutputT output_items[ITEMS_PER_THREAD]) ///< [out] Items from exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ {
+ BlockedToWarpStriped(input_items, output_items, Int2Type<WARP_TIME_SLICING>());
+ }
+
+
+
+ //@} end member group
+ /******************************************************************//**
+ * \name Scatter exchanges
+ *********************************************************************/
+ //@{
+
+
+ /**
+ * \brief Exchanges data items annotated by rank into <em>blocked</em> arrangement.
+ *
+ * \par
+ * - \smemreuse
+ *
+ * \tparam OffsetT <b>[inferred]</b> Signed integer type for local offsets
+ */
+ template <typename OutputT, typename OffsetT>
+ __device__ __forceinline__ void ScatterToBlocked(
+ InputT input_items[ITEMS_PER_THREAD], ///< [in] Items to exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ OutputT output_items[ITEMS_PER_THREAD], ///< [out] Items from exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ OffsetT ranks[ITEMS_PER_THREAD]) ///< [in] Corresponding scatter ranks
+ {
+ ScatterToBlocked(input_items, output_items, ranks, Int2Type<WARP_TIME_SLICING>());
+ }
+
+
+
+ /**
+ * \brief Exchanges data items annotated by rank into <em>striped</em> arrangement.
+ *
+ * \par
+ * - \smemreuse
+ *
+ * \tparam OffsetT <b>[inferred]</b> Signed integer type for local offsets
+ */
+ template <typename OutputT, typename OffsetT>
+ __device__ __forceinline__ void ScatterToStriped(
+ InputT input_items[ITEMS_PER_THREAD], ///< [in] Items to exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ OutputT output_items[ITEMS_PER_THREAD], ///< [out] Items from exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ OffsetT ranks[ITEMS_PER_THREAD]) ///< [in] Corresponding scatter ranks
+ {
+ ScatterToStriped(input_items, output_items, ranks, Int2Type<WARP_TIME_SLICING>());
+ }
+
+
+
+ /**
+ * \brief Exchanges data items annotated by rank into <em>striped</em> arrangement. Items with rank -1 are not exchanged.
+ *
+ * \par
+ * - \smemreuse
+ *
+ * \tparam OffsetT <b>[inferred]</b> Signed integer type for local offsets
+ */
+ template <typename OutputT, typename OffsetT>
+ __device__ __forceinline__ void ScatterToStripedGuarded(
+ InputT input_items[ITEMS_PER_THREAD], ///< [in] Items to exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ OutputT output_items[ITEMS_PER_THREAD], ///< [out] Items from exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ OffsetT ranks[ITEMS_PER_THREAD]) ///< [in] Corresponding scatter ranks
+ {
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = ranks[ITEM];
+ if (INSERT_PADDING) item_offset = SHR_ADD(item_offset, LOG_SMEM_BANKS, item_offset);
+ if (ranks[ITEM] >= 0)
+ temp_storage.buff[item_offset] = input_items[ITEM];
+ }
+
+ CTA_SYNC();
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = int(ITEM * BLOCK_THREADS) + linear_tid;
+ if (INSERT_PADDING) item_offset = SHR_ADD(item_offset, LOG_SMEM_BANKS, item_offset);
+ output_items[ITEM] = temp_storage.buff[item_offset];
+ }
+ }
+
+
+
+
+ /**
+ * \brief Exchanges valid data items annotated by rank into <em>striped</em> arrangement.
+ *
+ * \par
+ * - \smemreuse
+ *
+ * \tparam OffsetT <b>[inferred]</b> Signed integer type for local offsets
+ * \tparam ValidFlag <b>[inferred]</b> FlagT type denoting which items are valid
+ */
+ template <typename OutputT, typename OffsetT, typename ValidFlag>
+ __device__ __forceinline__ void ScatterToStripedFlagged(
+ InputT input_items[ITEMS_PER_THREAD], ///< [in] Items to exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ OutputT output_items[ITEMS_PER_THREAD], ///< [out] Items from exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ OffsetT ranks[ITEMS_PER_THREAD], ///< [in] Corresponding scatter ranks
+ ValidFlag is_valid[ITEMS_PER_THREAD]) ///< [in] Corresponding flag denoting item validity
+ {
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = ranks[ITEM];
+ if (INSERT_PADDING) item_offset = SHR_ADD(item_offset, LOG_SMEM_BANKS, item_offset);
+ if (is_valid[ITEM])
+ temp_storage.buff[item_offset] = input_items[ITEM];
+ }
+
+ CTA_SYNC();
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = int(ITEM * BLOCK_THREADS) + linear_tid;
+ if (INSERT_PADDING) item_offset = SHR_ADD(item_offset, LOG_SMEM_BANKS, item_offset);
+ output_items[ITEM] = temp_storage.buff[item_offset];
+ }
+ }
+
+
+ //@} end member group
+
+
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS // Do not document
+
+
+ __device__ __forceinline__ void StripedToBlocked(
+ InputT items[ITEMS_PER_THREAD]) ///< [in-out] Items to exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ {
+ StripedToBlocked(items, items);
+ }
+
+ __device__ __forceinline__ void BlockedToStriped(
+ InputT items[ITEMS_PER_THREAD]) ///< [in-out] Items to exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ {
+ BlockedToStriped(items, items);
+ }
+
+ __device__ __forceinline__ void WarpStripedToBlocked(
+ InputT items[ITEMS_PER_THREAD]) ///< [in-out] Items to exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ {
+ WarpStripedToBlocked(items, items);
+ }
+
+ __device__ __forceinline__ void BlockedToWarpStriped(
+ InputT items[ITEMS_PER_THREAD]) ///< [in-out] Items to exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ {
+ BlockedToWarpStriped(items, items);
+ }
+
+ template <typename OffsetT>
+ __device__ __forceinline__ void ScatterToBlocked(
+ InputT items[ITEMS_PER_THREAD], ///< [in-out] Items to exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ OffsetT ranks[ITEMS_PER_THREAD]) ///< [in] Corresponding scatter ranks
+ {
+ ScatterToBlocked(items, items, ranks);
+ }
+
+ template <typename OffsetT>
+ __device__ __forceinline__ void ScatterToStriped(
+ InputT items[ITEMS_PER_THREAD], ///< [in-out] Items to exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ OffsetT ranks[ITEMS_PER_THREAD]) ///< [in] Corresponding scatter ranks
+ {
+ ScatterToStriped(items, items, ranks);
+ }
+
+ template <typename OffsetT>
+ __device__ __forceinline__ void ScatterToStripedGuarded(
+ InputT items[ITEMS_PER_THREAD], ///< [in-out] Items to exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ OffsetT ranks[ITEMS_PER_THREAD]) ///< [in] Corresponding scatter ranks
+ {
+ ScatterToStripedGuarded(items, items, ranks);
+ }
+
+ template <typename OffsetT, typename ValidFlag>
+ __device__ __forceinline__ void ScatterToStripedFlagged(
+ InputT items[ITEMS_PER_THREAD], ///< [in-out] Items to exchange, converting between <em>striped</em> and <em>blocked</em> arrangements.
+ OffsetT ranks[ITEMS_PER_THREAD], ///< [in] Corresponding scatter ranks
+ ValidFlag is_valid[ITEMS_PER_THREAD]) ///< [in] Corresponding flag denoting item validity
+ {
+ ScatterToStriped(items, items, ranks, is_valid);
+ }
+
+#endif // DOXYGEN_SHOULD_SKIP_THIS
+
+
+};
+
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS // Do not document
+
+
+template <
+ typename T,
+ int ITEMS_PER_THREAD,
+ int LOGICAL_WARP_THREADS = CUB_PTX_WARP_THREADS,
+ int PTX_ARCH = CUB_PTX_ARCH>
+class WarpExchange
+{
+private:
+
+ /******************************************************************************
+ * Constants
+ ******************************************************************************/
+
+ /// Constants
+ enum
+ {
+ // Whether the logical warp size and the PTX warp size coincide
+ IS_ARCH_WARP = (LOGICAL_WARP_THREADS == CUB_WARP_THREADS(PTX_ARCH)),
+
+ WARP_ITEMS = (ITEMS_PER_THREAD * LOGICAL_WARP_THREADS) + 1,
+
+ LOG_SMEM_BANKS = CUB_LOG_SMEM_BANKS(PTX_ARCH),
+ SMEM_BANKS = 1 << LOG_SMEM_BANKS,
+
+ // Insert padding if the number of items per thread is a power of two and > 4 (otherwise we can typically use 128b loads)
+ INSERT_PADDING = (ITEMS_PER_THREAD > 4) && (PowerOfTwo<ITEMS_PER_THREAD>::VALUE),
+ PADDING_ITEMS = (INSERT_PADDING) ? (WARP_ITEMS >> LOG_SMEM_BANKS) : 0,
+ };
+
+ /******************************************************************************
+ * Type definitions
+ ******************************************************************************/
+
+ /// Shared memory storage layout type
+ struct _TempStorage
+ {
+ T buff[WARP_ITEMS + PADDING_ITEMS];
+ };
+
+public:
+
+ /// \smemstorage{WarpExchange}
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+private:
+
+
+ /******************************************************************************
+ * Thread fields
+ ******************************************************************************/
+
+ _TempStorage &temp_storage;
+ int lane_id;
+
+public:
+
+ /******************************************************************************
+ * Construction
+ ******************************************************************************/
+
+ /// Constructor
+ __device__ __forceinline__ WarpExchange(
+ TempStorage &temp_storage)
+ :
+ temp_storage(temp_storage.Alias()),
+ lane_id(IS_ARCH_WARP ?
+ LaneId() :
+ LaneId() % LOGICAL_WARP_THREADS)
+ {}
+
+
+ /******************************************************************************
+ * Interface
+ ******************************************************************************/
+
+ /**
+ * \brief Exchanges valid data items annotated by rank into <em>striped</em> arrangement.
+ *
+ * \par
+ * - \smemreuse
+ *
+ * \tparam OffsetT <b>[inferred]</b> Signed integer type for local offsets
+ */
+ template <typename OffsetT>
+ __device__ __forceinline__ void ScatterToStriped(
+ T items[ITEMS_PER_THREAD], ///< [in-out] Items to exchange
+ OffsetT ranks[ITEMS_PER_THREAD]) ///< [in] Corresponding scatter ranks
+ {
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ if (INSERT_PADDING) ranks[ITEM] = SHR_ADD(ranks[ITEM], LOG_SMEM_BANKS, ranks[ITEM]);
+ temp_storage.buff[ranks[ITEM]] = items[ITEM];
+ }
+
+ WARP_SYNC(0xffffffff);
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ int item_offset = (ITEM * LOGICAL_WARP_THREADS) + lane_id;
+ if (INSERT_PADDING) item_offset = SHR_ADD(item_offset, LOG_SMEM_BANKS, item_offset);
+ items[ITEM] = temp_storage.buff[item_offset];
+ }
+ }
+
+};
+
+
+
+
+#endif // DOXYGEN_SHOULD_SKIP_THIS
+
+
+
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_histogram.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_histogram.cuh
new file mode 100644
index 0000000..b7cb970
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_histogram.cuh
@@ -0,0 +1,415 @@
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-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 TORT
+ * (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
+ * The cub::BlockHistogram class provides [<em>collective</em>](index.html#sec0) methods for constructing block-wide histograms from data samples partitioned across a CUDA thread block.
+ */
+
+#pragma once
+
+#include "specializations/block_histogram_sort.cuh"
+#include "specializations/block_histogram_atomic.cuh"
+#include "../util_ptx.cuh"
+#include "../util_arch.cuh"
+#include "../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+/******************************************************************************
+ * Algorithmic variants
+ ******************************************************************************/
+
+/**
+ * \brief BlockHistogramAlgorithm enumerates alternative algorithms for the parallel construction of block-wide histograms.
+ */
+enum BlockHistogramAlgorithm
+{
+
+ /**
+ * \par Overview
+ * Sorting followed by differentiation. Execution is comprised of two phases:
+ * -# Sort the data using efficient radix sort
+ * -# Look for "runs" of same-valued keys by detecting discontinuities; the run-lengths are histogram bin counts.
+ *
+ * \par Performance Considerations
+ * Delivers consistent throughput regardless of sample bin distribution.
+ */
+ BLOCK_HISTO_SORT,
+
+
+ /**
+ * \par Overview
+ * Use atomic addition to update byte counts directly
+ *
+ * \par Performance Considerations
+ * Performance is strongly tied to the hardware implementation of atomic
+ * addition, and may be significantly degraded for non uniformly-random
+ * input distributions where many concurrent updates are likely to be
+ * made to the same bin counter.
+ */
+ BLOCK_HISTO_ATOMIC,
+};
+
+
+
+/******************************************************************************
+ * Block histogram
+ ******************************************************************************/
+
+
+/**
+ * \brief The BlockHistogram class provides [<em>collective</em>](index.html#sec0) methods for constructing block-wide histograms from data samples partitioned across a CUDA thread block. ![](histogram_logo.png)
+ * \ingroup BlockModule
+ *
+ * \tparam T The sample type being histogrammed (must be castable to an integer bin identifier)
+ * \tparam BLOCK_DIM_X The thread block length in threads along the X dimension
+ * \tparam ITEMS_PER_THREAD The number of items per thread
+ * \tparam BINS The number bins within the histogram
+ * \tparam ALGORITHM <b>[optional]</b> cub::BlockHistogramAlgorithm enumerator specifying the underlying algorithm to use (default: cub::BLOCK_HISTO_SORT)
+ * \tparam BLOCK_DIM_Y <b>[optional]</b> The thread block length in threads along the Y dimension (default: 1)
+ * \tparam BLOCK_DIM_Z <b>[optional]</b> The thread block length in threads along the Z dimension (default: 1)
+ * \tparam PTX_ARCH <b>[optional]</b> \ptxversion
+ *
+ * \par Overview
+ * - A <a href="http://en.wikipedia.org/wiki/Histogram"><em>histogram</em></a>
+ * counts the number of observations that fall into each of the disjoint categories (known as <em>bins</em>).
+ * - BlockHistogram can be optionally specialized to use different algorithms:
+ * -# <b>cub::BLOCK_HISTO_SORT</b>. Sorting followed by differentiation. [More...](\ref cub::BlockHistogramAlgorithm)
+ * -# <b>cub::BLOCK_HISTO_ATOMIC</b>. Use atomic addition to update byte counts directly. [More...](\ref cub::BlockHistogramAlgorithm)
+ *
+ * \par Performance Considerations
+ * - \granularity
+ *
+ * \par A Simple Example
+ * \blockcollective{BlockHistogram}
+ * \par
+ * The code snippet below illustrates a 256-bin histogram of 512 integer samples that
+ * are partitioned across 128 threads where each thread owns 4 samples.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_histogram.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize a 256-bin BlockHistogram type for a 1D block of 128 threads having 4 character samples each
+ * typedef cub::BlockHistogram<unsigned char, 128, 4, 256> BlockHistogram;
+ *
+ * // Allocate shared memory for BlockHistogram
+ * __shared__ typename BlockHistogram::TempStorage temp_storage;
+ *
+ * // Allocate shared memory for block-wide histogram bin counts
+ * __shared__ unsigned int smem_histogram[256];
+ *
+ * // Obtain input samples per thread
+ * unsigned char data[4];
+ * ...
+ *
+ * // Compute the block-wide histogram
+ * BlockHistogram(temp_storage).Histogram(data, smem_histogram);
+ *
+ * \endcode
+ *
+ * \par Performance and Usage Considerations
+ * - The histogram output can be constructed in shared or device-accessible memory
+ * - See cub::BlockHistogramAlgorithm for performance details regarding algorithmic alternatives
+ *
+ */
+template <
+ typename T,
+ int BLOCK_DIM_X,
+ int ITEMS_PER_THREAD,
+ int BINS,
+ BlockHistogramAlgorithm ALGORITHM = BLOCK_HISTO_SORT,
+ int BLOCK_DIM_Y = 1,
+ int BLOCK_DIM_Z = 1,
+ int PTX_ARCH = CUB_PTX_ARCH>
+class BlockHistogram
+{
+private:
+
+ /******************************************************************************
+ * Constants and type definitions
+ ******************************************************************************/
+
+ /// Constants
+ enum
+ {
+ /// The thread block size in threads
+ BLOCK_THREADS = BLOCK_DIM_X * BLOCK_DIM_Y * BLOCK_DIM_Z,
+ };
+
+ /**
+ * Ensure the template parameterization meets the requirements of the
+ * targeted device architecture. BLOCK_HISTO_ATOMIC can only be used
+ * on version SM120 or later. Otherwise BLOCK_HISTO_SORT is used
+ * regardless.
+ */
+ static const BlockHistogramAlgorithm SAFE_ALGORITHM =
+ ((ALGORITHM == BLOCK_HISTO_ATOMIC) && (PTX_ARCH < 120)) ?
+ BLOCK_HISTO_SORT :
+ ALGORITHM;
+
+ /// Internal specialization.
+ typedef typename If<(SAFE_ALGORITHM == BLOCK_HISTO_SORT),
+ BlockHistogramSort<T, BLOCK_DIM_X, ITEMS_PER_THREAD, BINS, BLOCK_DIM_Y, BLOCK_DIM_Z, PTX_ARCH>,
+ BlockHistogramAtomic<BINS> >::Type InternalBlockHistogram;
+
+ /// Shared memory storage layout type for BlockHistogram
+ typedef typename InternalBlockHistogram::TempStorage _TempStorage;
+
+
+ /******************************************************************************
+ * Thread fields
+ ******************************************************************************/
+
+ /// Shared storage reference
+ _TempStorage &temp_storage;
+
+ /// Linear thread-id
+ unsigned int linear_tid;
+
+
+ /******************************************************************************
+ * Utility methods
+ ******************************************************************************/
+
+ /// Internal storage allocator
+ __device__ __forceinline__ _TempStorage& PrivateStorage()
+ {
+ __shared__ _TempStorage private_storage;
+ return private_storage;
+ }
+
+
+public:
+
+ /// \smemstorage{BlockHistogram}
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ /******************************************************************//**
+ * \name Collective constructors
+ *********************************************************************/
+ //@{
+
+ /**
+ * \brief Collective constructor using a private static allocation of shared memory as temporary storage.
+ */
+ __device__ __forceinline__ BlockHistogram()
+ :
+ temp_storage(PrivateStorage()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ /**
+ * \brief Collective constructor using the specified memory allocation as temporary storage.
+ */
+ __device__ __forceinline__ BlockHistogram(
+ TempStorage &temp_storage) ///< [in] Reference to memory allocation having layout type TempStorage
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ //@} end member group
+ /******************************************************************//**
+ * \name Histogram operations
+ *********************************************************************/
+ //@{
+
+
+ /**
+ * \brief Initialize the shared histogram counters to zero.
+ *
+ * \par Snippet
+ * The code snippet below illustrates a the initialization and update of a
+ * histogram of 512 integer samples that are partitioned across 128 threads
+ * where each thread owns 4 samples.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_histogram.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize a 256-bin BlockHistogram type for a 1D block of 128 threads having 4 character samples each
+ * typedef cub::BlockHistogram<unsigned char, 128, 4, 256> BlockHistogram;
+ *
+ * // Allocate shared memory for BlockHistogram
+ * __shared__ typename BlockHistogram::TempStorage temp_storage;
+ *
+ * // Allocate shared memory for block-wide histogram bin counts
+ * __shared__ unsigned int smem_histogram[256];
+ *
+ * // Obtain input samples per thread
+ * unsigned char thread_samples[4];
+ * ...
+ *
+ * // Initialize the block-wide histogram
+ * BlockHistogram(temp_storage).InitHistogram(smem_histogram);
+ *
+ * // Update the block-wide histogram
+ * BlockHistogram(temp_storage).Composite(thread_samples, smem_histogram);
+ *
+ * \endcode
+ *
+ * \tparam CounterT <b>[inferred]</b> Histogram counter type
+ */
+ template <typename CounterT >
+ __device__ __forceinline__ void InitHistogram(CounterT histogram[BINS])
+ {
+ // Initialize histogram bin counts to zeros
+ int histo_offset = 0;
+
+ #pragma unroll
+ for(; histo_offset + BLOCK_THREADS <= BINS; histo_offset += BLOCK_THREADS)
+ {
+ histogram[histo_offset + linear_tid] = 0;
+ }
+ // Finish up with guarded initialization if necessary
+ if ((BINS % BLOCK_THREADS != 0) && (histo_offset + linear_tid < BINS))
+ {
+ histogram[histo_offset + linear_tid] = 0;
+ }
+ }
+
+
+ /**
+ * \brief Constructs a block-wide histogram in shared/device-accessible memory. Each thread contributes an array of input elements.
+ *
+ * \par
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a 256-bin histogram of 512 integer samples that
+ * are partitioned across 128 threads where each thread owns 4 samples.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_histogram.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize a 256-bin BlockHistogram type for a 1D block of 128 threads having 4 character samples each
+ * typedef cub::BlockHistogram<unsigned char, 128, 4, 256> BlockHistogram;
+ *
+ * // Allocate shared memory for BlockHistogram
+ * __shared__ typename BlockHistogram::TempStorage temp_storage;
+ *
+ * // Allocate shared memory for block-wide histogram bin counts
+ * __shared__ unsigned int smem_histogram[256];
+ *
+ * // Obtain input samples per thread
+ * unsigned char thread_samples[4];
+ * ...
+ *
+ * // Compute the block-wide histogram
+ * BlockHistogram(temp_storage).Histogram(thread_samples, smem_histogram);
+ *
+ * \endcode
+ *
+ * \tparam CounterT <b>[inferred]</b> Histogram counter type
+ */
+ template <
+ typename CounterT >
+ __device__ __forceinline__ void Histogram(
+ T (&items)[ITEMS_PER_THREAD], ///< [in] Calling thread's input values to histogram
+ CounterT histogram[BINS]) ///< [out] Reference to shared/device-accessible memory histogram
+ {
+ // Initialize histogram bin counts to zeros
+ InitHistogram(histogram);
+
+ CTA_SYNC();
+
+ // Composite the histogram
+ InternalBlockHistogram(temp_storage).Composite(items, histogram);
+ }
+
+
+
+ /**
+ * \brief Updates an existing block-wide histogram in shared/device-accessible memory. Each thread composites an array of input elements.
+ *
+ * \par
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a the initialization and update of a
+ * histogram of 512 integer samples that are partitioned across 128 threads
+ * where each thread owns 4 samples.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_histogram.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize a 256-bin BlockHistogram type for a 1D block of 128 threads having 4 character samples each
+ * typedef cub::BlockHistogram<unsigned char, 128, 4, 256> BlockHistogram;
+ *
+ * // Allocate shared memory for BlockHistogram
+ * __shared__ typename BlockHistogram::TempStorage temp_storage;
+ *
+ * // Allocate shared memory for block-wide histogram bin counts
+ * __shared__ unsigned int smem_histogram[256];
+ *
+ * // Obtain input samples per thread
+ * unsigned char thread_samples[4];
+ * ...
+ *
+ * // Initialize the block-wide histogram
+ * BlockHistogram(temp_storage).InitHistogram(smem_histogram);
+ *
+ * // Update the block-wide histogram
+ * BlockHistogram(temp_storage).Composite(thread_samples, smem_histogram);
+ *
+ * \endcode
+ *
+ * \tparam CounterT <b>[inferred]</b> Histogram counter type
+ */
+ template <
+ typename CounterT >
+ __device__ __forceinline__ void Composite(
+ T (&items)[ITEMS_PER_THREAD], ///< [in] Calling thread's input values to histogram
+ CounterT histogram[BINS]) ///< [out] Reference to shared/device-accessible memory histogram
+ {
+ InternalBlockHistogram(temp_storage).Composite(items, histogram);
+ }
+
+};
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_load.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_load.cuh
new file mode 100644
index 0000000..217f521
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_load.cuh
@@ -0,0 +1,1241 @@
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-2016, 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 TORT
+ * (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
+ * Operations for reading linear tiles of data into the CUDA thread block.
+ */
+
+#pragma once
+
+#include <iterator>
+
+#include "block_exchange.cuh"
+#include "../iterator/cache_modified_input_iterator.cuh"
+#include "../util_ptx.cuh"
+#include "../util_macro.cuh"
+#include "../util_type.cuh"
+#include "../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+/**
+ * \addtogroup UtilIo
+ * @{
+ */
+
+
+/******************************************************************//**
+ * \name Blocked arrangement I/O (direct)
+ *********************************************************************/
+//@{
+
+
+/**
+ * \brief Load a linear segment of items into a blocked arrangement across the thread block.
+ *
+ * \blocked
+ *
+ * \tparam T <b>[inferred]</b> The data type to load.
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam InputIteratorT <b>[inferred]</b> The random-access iterator type for input \iterator.
+ */
+template <
+ typename InputT,
+ int ITEMS_PER_THREAD,
+ typename InputIteratorT>
+__device__ __forceinline__ void LoadDirectBlocked(
+ int linear_tid, ///< [in] A suitable 1D thread-identifier for the calling thread (e.g., <tt>(threadIdx.y * blockDim.x) + linear_tid</tt> for 2D thread blocks)
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD]) ///< [out] Data to load
+{
+ InputIteratorT thread_itr = block_itr + (linear_tid * ITEMS_PER_THREAD);
+
+ // Load directly in thread-blocked order
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ items[ITEM] = thread_itr[ITEM];
+ }
+}
+
+
+/**
+ * \brief Load a linear segment of items into a blocked arrangement across the thread block, guarded by range.
+ *
+ * \blocked
+ *
+ * \tparam T <b>[inferred]</b> The data type to load.
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam InputIteratorT <b>[inferred]</b> The random-access iterator type for input \iterator.
+ */
+template <
+ typename InputT,
+ int ITEMS_PER_THREAD,
+ typename InputIteratorT>
+__device__ __forceinline__ void LoadDirectBlocked(
+ int linear_tid, ///< [in] A suitable 1D thread-identifier for the calling thread (e.g., <tt>(threadIdx.y * blockDim.x) + linear_tid</tt> for 2D thread blocks)
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD], ///< [out] Data to load
+ int valid_items) ///< [in] Number of valid items to load
+{
+ InputIteratorT thread_itr = block_itr + (linear_tid * ITEMS_PER_THREAD);
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ if ((linear_tid * ITEMS_PER_THREAD) + ITEM < valid_items)
+ {
+ items[ITEM] = thread_itr[ITEM];
+ }
+ }
+}
+
+
+/**
+ * \brief Load a linear segment of items into a blocked arrangement across the thread block, guarded by range, with a fall-back assignment of out-of-bound elements..
+ *
+ * \blocked
+ *
+ * \tparam T <b>[inferred]</b> The data type to load.
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam InputIteratorT <b>[inferred]</b> The random-access iterator type for input \iterator.
+ */
+template <
+ typename InputT,
+ typename DefaultT,
+ int ITEMS_PER_THREAD,
+ typename InputIteratorT>
+__device__ __forceinline__ void LoadDirectBlocked(
+ int linear_tid, ///< [in] A suitable 1D thread-identifier for the calling thread (e.g., <tt>(threadIdx.y * blockDim.x) + linear_tid</tt> for 2D thread blocks)
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD], ///< [out] Data to load
+ int valid_items, ///< [in] Number of valid items to load
+ DefaultT oob_default) ///< [in] Default value to assign out-of-bound items
+{
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ items[ITEM] = oob_default;
+
+ LoadDirectBlocked(linear_tid, block_itr, items, valid_items);
+}
+
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS // Do not document
+
+/**
+ * Internal implementation for load vectorization
+ */
+template <
+ CacheLoadModifier MODIFIER,
+ typename T,
+ int ITEMS_PER_THREAD>
+__device__ __forceinline__ void InternalLoadDirectBlockedVectorized(
+ int linear_tid, ///< [in] A suitable 1D thread-identifier for the calling thread (e.g., <tt>(threadIdx.y * blockDim.x) + linear_tid</tt> for 2D thread blocks)
+ T *block_ptr, ///< [in] Input pointer for loading from
+ T (&items)[ITEMS_PER_THREAD]) ///< [out] Data to load
+{
+ // Biggest memory access word that T is a whole multiple of
+ typedef typename UnitWord<T>::DeviceWord DeviceWord;
+
+ enum
+ {
+ TOTAL_WORDS = sizeof(items) / sizeof(DeviceWord),
+
+ VECTOR_SIZE = (TOTAL_WORDS % 4 == 0) ?
+ 4 :
+ (TOTAL_WORDS % 2 == 0) ?
+ 2 :
+ 1,
+
+ VECTORS_PER_THREAD = TOTAL_WORDS / VECTOR_SIZE,
+ };
+
+ // Vector type
+ typedef typename CubVector<DeviceWord, VECTOR_SIZE>::Type Vector;
+
+ // Vector items
+ Vector vec_items[VECTORS_PER_THREAD];
+
+ // Aliased input ptr
+ Vector* vec_ptr = reinterpret_cast<Vector*>(block_ptr) + (linear_tid * VECTORS_PER_THREAD);
+
+ // Load directly in thread-blocked order
+ #pragma unroll
+ for (int ITEM = 0; ITEM < VECTORS_PER_THREAD; ITEM++)
+ {
+ vec_items[ITEM] = ThreadLoad<MODIFIER>(vec_ptr + ITEM);
+ }
+
+ // Copy
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ items[ITEM] = *(reinterpret_cast<T*>(vec_items) + ITEM);
+ }
+}
+
+#endif // DOXYGEN_SHOULD_SKIP_THIS
+
+
+/**
+ * \brief Load a linear segment of items into a blocked arrangement across the thread block.
+ *
+ * \blocked
+ *
+ * The input offset (\p block_ptr + \p block_offset) must be quad-item aligned
+ *
+ * The following conditions will prevent vectorization and loading will fall back to cub::BLOCK_LOAD_DIRECT:
+ * - \p ITEMS_PER_THREAD is odd
+ * - The data type \p T is not a built-in primitive or CUDA vector type (e.g., \p short, \p int2, \p double, \p float2, etc.)
+ *
+ * \tparam T <b>[inferred]</b> The data type to load.
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ */
+template <
+ typename T,
+ int ITEMS_PER_THREAD>
+__device__ __forceinline__ void LoadDirectBlockedVectorized(
+ int linear_tid, ///< [in] A suitable 1D thread-identifier for the calling thread (e.g., <tt>(threadIdx.y * blockDim.x) + linear_tid</tt> for 2D thread blocks)
+ T *block_ptr, ///< [in] Input pointer for loading from
+ T (&items)[ITEMS_PER_THREAD]) ///< [out] Data to load
+{
+ InternalLoadDirectBlockedVectorized<LOAD_DEFAULT>(linear_tid, block_ptr, items);
+}
+
+
+//@} end member group
+/******************************************************************//**
+ * \name Striped arrangement I/O (direct)
+ *********************************************************************/
+//@{
+
+
+/**
+ * \brief Load a linear segment of items into a striped arrangement across the thread block.
+ *
+ * \striped
+ *
+ * \tparam BLOCK_THREADS The thread block size in threads
+ * \tparam T <b>[inferred]</b> The data type to load.
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam InputIteratorT <b>[inferred]</b> The random-access iterator type for input \iterator.
+ */
+template <
+ int BLOCK_THREADS,
+ typename InputT,
+ int ITEMS_PER_THREAD,
+ typename InputIteratorT>
+__device__ __forceinline__ void LoadDirectStriped(
+ int linear_tid, ///< [in] A suitable 1D thread-identifier for the calling thread (e.g., <tt>(threadIdx.y * blockDim.x) + linear_tid</tt> for 2D thread blocks)
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD]) ///< [out] Data to load
+{
+ InputIteratorT thread_itr = block_itr + linear_tid;
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ items[ITEM] = thread_itr[ITEM * BLOCK_THREADS];
+ }
+}
+
+
+/**
+ * \brief Load a linear segment of items into a striped arrangement across the thread block, guarded by range
+ *
+ * \striped
+ *
+ * \tparam BLOCK_THREADS The thread block size in threads
+ * \tparam T <b>[inferred]</b> The data type to load.
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam InputIteratorT <b>[inferred]</b> The random-access iterator type for input \iterator.
+ */
+template <
+ int BLOCK_THREADS,
+ typename InputT,
+ int ITEMS_PER_THREAD,
+ typename InputIteratorT>
+__device__ __forceinline__ void LoadDirectStriped(
+ int linear_tid, ///< [in] A suitable 1D thread-identifier for the calling thread (e.g., <tt>(threadIdx.y * blockDim.x) + linear_tid</tt> for 2D thread blocks)
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD], ///< [out] Data to load
+ int valid_items) ///< [in] Number of valid items to load
+{
+ InputIteratorT thread_itr = block_itr + linear_tid;
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ if (linear_tid + (ITEM * BLOCK_THREADS) < valid_items)
+ {
+ items[ITEM] = thread_itr[ITEM * BLOCK_THREADS];
+ }
+ }
+}
+
+
+/**
+ * \brief Load a linear segment of items into a striped arrangement across the thread block, guarded by range, with a fall-back assignment of out-of-bound elements.
+ *
+ * \striped
+ *
+ * \tparam BLOCK_THREADS The thread block size in threads
+ * \tparam T <b>[inferred]</b> The data type to load.
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam InputIteratorT <b>[inferred]</b> The random-access iterator type for input \iterator.
+ */
+template <
+ int BLOCK_THREADS,
+ typename InputT,
+ typename DefaultT,
+ int ITEMS_PER_THREAD,
+ typename InputIteratorT>
+__device__ __forceinline__ void LoadDirectStriped(
+ int linear_tid, ///< [in] A suitable 1D thread-identifier for the calling thread (e.g., <tt>(threadIdx.y * blockDim.x) + linear_tid</tt> for 2D thread blocks)
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD], ///< [out] Data to load
+ int valid_items, ///< [in] Number of valid items to load
+ DefaultT oob_default) ///< [in] Default value to assign out-of-bound items
+{
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ items[ITEM] = oob_default;
+
+ LoadDirectStriped<BLOCK_THREADS>(linear_tid, block_itr, items, valid_items);
+}
+
+
+
+//@} end member group
+/******************************************************************//**
+ * \name Warp-striped arrangement I/O (direct)
+ *********************************************************************/
+//@{
+
+
+/**
+ * \brief Load a linear segment of items into a warp-striped arrangement across the thread block.
+ *
+ * \warpstriped
+ *
+ * \par Usage Considerations
+ * The number of threads in the thread block must be a multiple of the architecture's warp size.
+ *
+ * \tparam T <b>[inferred]</b> The data type to load.
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam InputIteratorT <b>[inferred]</b> The random-access iterator type for input \iterator.
+ */
+template <
+ typename InputT,
+ int ITEMS_PER_THREAD,
+ typename InputIteratorT>
+__device__ __forceinline__ void LoadDirectWarpStriped(
+ int linear_tid, ///< [in] A suitable 1D thread-identifier for the calling thread (e.g., <tt>(threadIdx.y * blockDim.x) + linear_tid</tt> for 2D thread blocks)
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD]) ///< [out] Data to load
+{
+ int tid = linear_tid & (CUB_PTX_WARP_THREADS - 1);
+ int wid = linear_tid >> CUB_PTX_LOG_WARP_THREADS;
+ int warp_offset = wid * CUB_PTX_WARP_THREADS * ITEMS_PER_THREAD;
+
+ InputIteratorT thread_itr = block_itr + warp_offset + tid ;
+
+ // Load directly in warp-striped order
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ items[ITEM] = thread_itr[(ITEM * CUB_PTX_WARP_THREADS)];
+ }
+}
+
+
+/**
+ * \brief Load a linear segment of items into a warp-striped arrangement across the thread block, guarded by range
+ *
+ * \warpstriped
+ *
+ * \par Usage Considerations
+ * The number of threads in the thread block must be a multiple of the architecture's warp size.
+ *
+ * \tparam T <b>[inferred]</b> The data type to load.
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam InputIteratorT <b>[inferred]</b> The random-access iterator type for input \iterator.
+ */
+template <
+ typename InputT,
+ int ITEMS_PER_THREAD,
+ typename InputIteratorT>
+__device__ __forceinline__ void LoadDirectWarpStriped(
+ int linear_tid, ///< [in] A suitable 1D thread-identifier for the calling thread (e.g., <tt>(threadIdx.y * blockDim.x) + linear_tid</tt> for 2D thread blocks)
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD], ///< [out] Data to load
+ int valid_items) ///< [in] Number of valid items to load
+{
+ int tid = linear_tid & (CUB_PTX_WARP_THREADS - 1);
+ int wid = linear_tid >> CUB_PTX_LOG_WARP_THREADS;
+ int warp_offset = wid * CUB_PTX_WARP_THREADS * ITEMS_PER_THREAD;
+
+ InputIteratorT thread_itr = block_itr + warp_offset + tid ;
+
+ // Load directly in warp-striped order
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ if (warp_offset + tid + (ITEM * CUB_PTX_WARP_THREADS) < valid_items)
+ {
+ items[ITEM] = thread_itr[(ITEM * CUB_PTX_WARP_THREADS)];
+ }
+ }
+}
+
+
+/**
+ * \brief Load a linear segment of items into a warp-striped arrangement across the thread block, guarded by range, with a fall-back assignment of out-of-bound elements.
+ *
+ * \warpstriped
+ *
+ * \par Usage Considerations
+ * The number of threads in the thread block must be a multiple of the architecture's warp size.
+ *
+ * \tparam T <b>[inferred]</b> The data type to load.
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam InputIteratorT <b>[inferred]</b> The random-access iterator type for input \iterator.
+ */
+template <
+ typename InputT,
+ typename DefaultT,
+ int ITEMS_PER_THREAD,
+ typename InputIteratorT>
+__device__ __forceinline__ void LoadDirectWarpStriped(
+ int linear_tid, ///< [in] A suitable 1D thread-identifier for the calling thread (e.g., <tt>(threadIdx.y * blockDim.x) + linear_tid</tt> for 2D thread blocks)
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD], ///< [out] Data to load
+ int valid_items, ///< [in] Number of valid items to load
+ DefaultT oob_default) ///< [in] Default value to assign out-of-bound items
+{
+ // Load directly in warp-striped order
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ items[ITEM] = oob_default;
+
+ LoadDirectWarpStriped(linear_tid, block_itr, items, valid_items);
+}
+
+
+
+//@} end member group
+
+/** @} */ // end group UtilIo
+
+
+
+//-----------------------------------------------------------------------------
+// Generic BlockLoad abstraction
+//-----------------------------------------------------------------------------
+
+/**
+ * \brief cub::BlockLoadAlgorithm enumerates alternative algorithms for cub::BlockLoad to read a linear segment of data from memory into a blocked arrangement across a CUDA thread block.
+ */
+
+/**
+ * \brief cub::BlockLoadAlgorithm enumerates alternative algorithms for cub::BlockLoad to read a linear segment of data from memory into a blocked arrangement across a CUDA thread block.
+ */
+enum BlockLoadAlgorithm
+{
+ /**
+ * \par Overview
+ *
+ * A [<em>blocked arrangement</em>](index.html#sec5sec3) of data is read
+ * directly from memory.
+ *
+ * \par Performance Considerations
+ * - The utilization of memory transactions (coalescing) decreases as the
+ * access stride between threads increases (i.e., the number items per thread).
+ */
+ BLOCK_LOAD_DIRECT,
+
+ /**
+ * \par Overview
+ *
+ * A [<em>blocked arrangement</em>](index.html#sec5sec3) of data is read
+ * from memory using CUDA's built-in vectorized loads as a coalescing optimization.
+ * For example, <tt>ld.global.v4.s32</tt> instructions will be generated
+ * when \p T = \p int and \p ITEMS_PER_THREAD % 4 == 0.
+ *
+ * \par Performance Considerations
+ * - The utilization of memory transactions (coalescing) remains high until the the
+ * access stride between threads (i.e., the number items per thread) exceeds the
+ * maximum vector load width (typically 4 items or 64B, whichever is lower).
+ * - The following conditions will prevent vectorization and loading will fall back to cub::BLOCK_LOAD_DIRECT:
+ * - \p ITEMS_PER_THREAD is odd
+ * - The \p InputIteratorTis not a simple pointer type
+ * - The block input offset is not quadword-aligned
+ * - The data type \p T is not a built-in primitive or CUDA vector type (e.g., \p short, \p int2, \p double, \p float2, etc.)
+ */
+ BLOCK_LOAD_VECTORIZE,
+
+ /**
+ * \par Overview
+ *
+ * A [<em>striped arrangement</em>](index.html#sec5sec3) of data is read
+ * efficiently from memory and then locally transposed into a
+ * [<em>blocked arrangement</em>](index.html#sec5sec3).
+ *
+ * \par Performance Considerations
+ * - The utilization of memory transactions (coalescing) remains high regardless
+ * of items loaded per thread.
+ * - The local reordering incurs slightly longer latencies and throughput than the
+ * direct cub::BLOCK_LOAD_DIRECT and cub::BLOCK_LOAD_VECTORIZE alternatives.
+ */
+ BLOCK_LOAD_TRANSPOSE,
+
+
+ /**
+ * \par Overview
+ *
+ * A [<em>warp-striped arrangement</em>](index.html#sec5sec3) of data is
+ * read efficiently from memory and then locally transposed into a
+ * [<em>blocked arrangement</em>](index.html#sec5sec3).
+ *
+ * \par Usage Considerations
+ * - BLOCK_THREADS must be a multiple of WARP_THREADS
+ *
+ * \par Performance Considerations
+ * - The utilization of memory transactions (coalescing) remains high regardless
+ * of items loaded per thread.
+ * - The local reordering incurs slightly larger latencies than the
+ * direct cub::BLOCK_LOAD_DIRECT and cub::BLOCK_LOAD_VECTORIZE alternatives.
+ * - Provisions more shared storage, but incurs smaller latencies than the
+ * BLOCK_LOAD_WARP_TRANSPOSE_TIMESLICED alternative.
+ */
+ BLOCK_LOAD_WARP_TRANSPOSE,
+
+
+ /**
+ * \par Overview
+ *
+ * Like \p BLOCK_LOAD_WARP_TRANSPOSE, a [<em>warp-striped arrangement</em>](index.html#sec5sec3)
+ * of data is read directly from memory and then is locally transposed into a
+ * [<em>blocked arrangement</em>](index.html#sec5sec3). To reduce the shared memory
+ * requirement, only one warp's worth of shared memory is provisioned and is
+ * subsequently time-sliced among warps.
+ *
+ * \par Usage Considerations
+ * - BLOCK_THREADS must be a multiple of WARP_THREADS
+ *
+ * \par Performance Considerations
+ * - The utilization of memory transactions (coalescing) remains high regardless
+ * of items loaded per thread.
+ * - Provisions less shared memory temporary storage, but incurs larger
+ * latencies than the BLOCK_LOAD_WARP_TRANSPOSE alternative.
+ */
+ BLOCK_LOAD_WARP_TRANSPOSE_TIMESLICED,
+};
+
+
+/**
+ * \brief The BlockLoad class provides [<em>collective</em>](index.html#sec0) data movement methods for loading a linear segment of items from memory into a [<em>blocked arrangement</em>](index.html#sec5sec3) across a CUDA thread block. ![](block_load_logo.png)
+ * \ingroup BlockModule
+ * \ingroup UtilIo
+ *
+ * \tparam InputT The data type to read into (which must be convertible from the input iterator's value type).
+ * \tparam BLOCK_DIM_X The thread block length in threads along the X dimension
+ * \tparam ITEMS_PER_THREAD The number of consecutive items partitioned onto each thread.
+ * \tparam ALGORITHM <b>[optional]</b> cub::BlockLoadAlgorithm tuning policy. default: cub::BLOCK_LOAD_DIRECT.
+ * \tparam WARP_TIME_SLICING <b>[optional]</b> Whether or not only one warp's worth of shared memory should be allocated and time-sliced among block-warps during any load-related data transpositions (versus each warp having its own storage). (default: false)
+ * \tparam BLOCK_DIM_Y <b>[optional]</b> The thread block length in threads along the Y dimension (default: 1)
+ * \tparam BLOCK_DIM_Z <b>[optional]</b> The thread block length in threads along the Z dimension (default: 1)
+ * \tparam PTX_ARCH <b>[optional]</b> \ptxversion
+ *
+ * \par Overview
+ * - The BlockLoad class provides a single data movement abstraction that can be specialized
+ * to implement different cub::BlockLoadAlgorithm strategies. This facilitates different
+ * performance policies for different architectures, data types, granularity sizes, etc.
+ * - BlockLoad can be optionally specialized by different data movement strategies:
+ * -# <b>cub::BLOCK_LOAD_DIRECT</b>. A [<em>blocked arrangement</em>](index.html#sec5sec3)
+ * of data is read directly from memory. [More...](\ref cub::BlockLoadAlgorithm)
+ * -# <b>cub::BLOCK_LOAD_VECTORIZE</b>. A [<em>blocked arrangement</em>](index.html#sec5sec3)
+ * of data is read directly from memory using CUDA's built-in vectorized loads as a
+ * coalescing optimization. [More...](\ref cub::BlockLoadAlgorithm)
+ * -# <b>cub::BLOCK_LOAD_TRANSPOSE</b>. A [<em>striped arrangement</em>](index.html#sec5sec3)
+ * of data is read directly from memory and is then locally transposed into a
+ * [<em>blocked arrangement</em>](index.html#sec5sec3). [More...](\ref cub::BlockLoadAlgorithm)
+ * -# <b>cub::BLOCK_LOAD_WARP_TRANSPOSE</b>. A [<em>warp-striped arrangement</em>](index.html#sec5sec3)
+ * of data is read directly from memory and is then locally transposed into a
+ * [<em>blocked arrangement</em>](index.html#sec5sec3). [More...](\ref cub::BlockLoadAlgorithm)
+ * -# <b>cub::BLOCK_LOAD_WARP_TRANSPOSE_TIMESLICED,</b>. A [<em>warp-striped arrangement</em>](index.html#sec5sec3)
+ * of data is read directly from memory and is then locally transposed into a
+ * [<em>blocked arrangement</em>](index.html#sec5sec3) one warp at a time. [More...](\ref cub::BlockLoadAlgorithm)
+ * - \rowmajor
+ *
+ * \par A Simple Example
+ * \blockcollective{BlockLoad}
+ * \par
+ * The code snippet below illustrates the loading of a linear
+ * segment of 512 integers into a "blocked" arrangement across 128 threads where each
+ * thread owns 4 consecutive items. The load is specialized for \p BLOCK_LOAD_WARP_TRANSPOSE,
+ * meaning memory references are efficiently coalesced using a warp-striped access
+ * pattern (after which items are locally reordered among threads).
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_load.cuh>
+ *
+ * __global__ void ExampleKernel(int *d_data, ...)
+ * {
+ * // Specialize BlockLoad for a 1D block of 128 threads owning 4 integer items each
+ * typedef cub::BlockLoad<int, 128, 4, BLOCK_LOAD_WARP_TRANSPOSE> BlockLoad;
+ *
+ * // Allocate shared memory for BlockLoad
+ * __shared__ typename BlockLoad::TempStorage temp_storage;
+ *
+ * // Load a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * BlockLoad(temp_storage).Load(d_data, thread_data);
+ *
+ * \endcode
+ * \par
+ * Suppose the input \p d_data is <tt>0, 1, 2, 3, 4, 5, ...</tt>.
+ * The set of \p thread_data across the block of threads in those threads will be
+ * <tt>{ [0,1,2,3], [4,5,6,7], ..., [508,509,510,511] }</tt>.
+ *
+ */
+template <
+ typename InputT,
+ int BLOCK_DIM_X,
+ int ITEMS_PER_THREAD,
+ BlockLoadAlgorithm ALGORITHM = BLOCK_LOAD_DIRECT,
+ int BLOCK_DIM_Y = 1,
+ int BLOCK_DIM_Z = 1,
+ int PTX_ARCH = CUB_PTX_ARCH>
+class BlockLoad
+{
+private:
+
+ /******************************************************************************
+ * Constants and typed definitions
+ ******************************************************************************/
+
+ /// Constants
+ enum
+ {
+ /// The thread block size in threads
+ BLOCK_THREADS = BLOCK_DIM_X * BLOCK_DIM_Y * BLOCK_DIM_Z,
+ };
+
+
+ /******************************************************************************
+ * Algorithmic variants
+ ******************************************************************************/
+
+ /// Load helper
+ template <BlockLoadAlgorithm _POLICY, int DUMMY>
+ struct LoadInternal;
+
+
+ /**
+ * BLOCK_LOAD_DIRECT specialization of load helper
+ */
+ template <int DUMMY>
+ struct LoadInternal<BLOCK_LOAD_DIRECT, DUMMY>
+ {
+ /// Shared memory storage layout type
+ typedef NullType TempStorage;
+
+ /// Linear thread-id
+ int linear_tid;
+
+ /// Constructor
+ __device__ __forceinline__ LoadInternal(
+ TempStorage &/*temp_storage*/,
+ int linear_tid)
+ :
+ linear_tid(linear_tid)
+ {}
+
+ /// Load a linear segment of items from memory
+ template <typename InputIteratorT>
+ __device__ __forceinline__ void Load(
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD]) ///< [out] Data to load
+ {
+ LoadDirectBlocked(linear_tid, block_itr, items);
+ }
+
+ /// Load a linear segment of items from memory, guarded by range
+ template <typename InputIteratorT>
+ __device__ __forceinline__ void Load(
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD], ///< [out] Data to load
+ int valid_items) ///< [in] Number of valid items to load
+ {
+ LoadDirectBlocked(linear_tid, block_itr, items, valid_items);
+ }
+
+ /// Load a linear segment of items from memory, guarded by range, with a fall-back assignment of out-of-bound elements
+ template <typename InputIteratorT, typename DefaultT>
+ __device__ __forceinline__ void Load(
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD], ///< [out] Data to load
+ int valid_items, ///< [in] Number of valid items to load
+ DefaultT oob_default) ///< [in] Default value to assign out-of-bound items
+ {
+ LoadDirectBlocked(linear_tid, block_itr, items, valid_items, oob_default);
+ }
+
+ };
+
+
+ /**
+ * BLOCK_LOAD_VECTORIZE specialization of load helper
+ */
+ template <int DUMMY>
+ struct LoadInternal<BLOCK_LOAD_VECTORIZE, DUMMY>
+ {
+ /// Shared memory storage layout type
+ typedef NullType TempStorage;
+
+ /// Linear thread-id
+ int linear_tid;
+
+ /// Constructor
+ __device__ __forceinline__ LoadInternal(
+ TempStorage &/*temp_storage*/,
+ int linear_tid)
+ :
+ linear_tid(linear_tid)
+ {}
+
+ /// Load a linear segment of items from memory, specialized for native pointer types (attempts vectorization)
+ template <typename InputIteratorT>
+ __device__ __forceinline__ void Load(
+ InputT *block_ptr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD]) ///< [out] Data to load
+ {
+ InternalLoadDirectBlockedVectorized<LOAD_DEFAULT>(linear_tid, block_ptr, items);
+ }
+
+ /// Load a linear segment of items from memory, specialized for native pointer types (attempts vectorization)
+ template <typename InputIteratorT>
+ __device__ __forceinline__ void Load(
+ const InputT *block_ptr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD]) ///< [out] Data to load
+ {
+ InternalLoadDirectBlockedVectorized<LOAD_DEFAULT>(linear_tid, block_ptr, items);
+ }
+
+ /// Load a linear segment of items from memory, specialized for native pointer types (attempts vectorization)
+ template <
+ CacheLoadModifier MODIFIER,
+ typename ValueType,
+ typename OffsetT>
+ __device__ __forceinline__ void Load(
+ CacheModifiedInputIterator<MODIFIER, ValueType, OffsetT> block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD]) ///< [out] Data to load
+ {
+ InternalLoadDirectBlockedVectorized<MODIFIER>(linear_tid, block_itr.ptr, items);
+ }
+
+ /// Load a linear segment of items from memory, specialized for opaque input iterators (skips vectorization)
+ template <typename _InputIteratorT>
+ __device__ __forceinline__ void Load(
+ _InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD]) ///< [out] Data to load
+ {
+ LoadDirectBlocked(linear_tid, block_itr, items);
+ }
+
+ /// Load a linear segment of items from memory, guarded by range (skips vectorization)
+ template <typename InputIteratorT>
+ __device__ __forceinline__ void Load(
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD], ///< [out] Data to load
+ int valid_items) ///< [in] Number of valid items to load
+ {
+ LoadDirectBlocked(linear_tid, block_itr, items, valid_items);
+ }
+
+ /// Load a linear segment of items from memory, guarded by range, with a fall-back assignment of out-of-bound elements (skips vectorization)
+ template <typename InputIteratorT, typename DefaultT>
+ __device__ __forceinline__ void Load(
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD], ///< [out] Data to load
+ int valid_items, ///< [in] Number of valid items to load
+ DefaultT oob_default) ///< [in] Default value to assign out-of-bound items
+ {
+ LoadDirectBlocked(linear_tid, block_itr, items, valid_items, oob_default);
+ }
+
+ };
+
+
+ /**
+ * BLOCK_LOAD_TRANSPOSE specialization of load helper
+ */
+ template <int DUMMY>
+ struct LoadInternal<BLOCK_LOAD_TRANSPOSE, DUMMY>
+ {
+ // BlockExchange utility type for keys
+ typedef BlockExchange<InputT, BLOCK_DIM_X, ITEMS_PER_THREAD, false, BLOCK_DIM_Y, BLOCK_DIM_Z, PTX_ARCH> BlockExchange;
+
+ /// Shared memory storage layout type
+ struct _TempStorage : BlockExchange::TempStorage
+ {};
+
+ /// Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+ /// Thread reference to shared storage
+ _TempStorage &temp_storage;
+
+ /// Linear thread-id
+ int linear_tid;
+
+ /// Constructor
+ __device__ __forceinline__ LoadInternal(
+ TempStorage &temp_storage,
+ int linear_tid)
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(linear_tid)
+ {}
+
+ /// Load a linear segment of items from memory
+ template <typename InputIteratorT>
+ __device__ __forceinline__ void Load(
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD]) ///< [out] Data to load{
+ {
+ LoadDirectStriped<BLOCK_THREADS>(linear_tid, block_itr, items);
+ BlockExchange(temp_storage).StripedToBlocked(items, items);
+ }
+
+ /// Load a linear segment of items from memory, guarded by range
+ template <typename InputIteratorT>
+ __device__ __forceinline__ void Load(
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD], ///< [out] Data to load
+ int valid_items) ///< [in] Number of valid items to load
+ {
+ LoadDirectStriped<BLOCK_THREADS>(linear_tid, block_itr, items, valid_items);
+ BlockExchange(temp_storage).StripedToBlocked(items, items);
+ }
+
+ /// Load a linear segment of items from memory, guarded by range, with a fall-back assignment of out-of-bound elements
+ template <typename InputIteratorT, typename DefaultT>
+ __device__ __forceinline__ void Load(
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD], ///< [out] Data to load
+ int valid_items, ///< [in] Number of valid items to load
+ DefaultT oob_default) ///< [in] Default value to assign out-of-bound items
+ {
+ LoadDirectStriped<BLOCK_THREADS>(linear_tid, block_itr, items, valid_items, oob_default);
+ BlockExchange(temp_storage).StripedToBlocked(items, items);
+ }
+
+ };
+
+
+ /**
+ * BLOCK_LOAD_WARP_TRANSPOSE specialization of load helper
+ */
+ template <int DUMMY>
+ struct LoadInternal<BLOCK_LOAD_WARP_TRANSPOSE, DUMMY>
+ {
+ enum
+ {
+ WARP_THREADS = CUB_WARP_THREADS(PTX_ARCH)
+ };
+
+ // Assert BLOCK_THREADS must be a multiple of WARP_THREADS
+ CUB_STATIC_ASSERT((BLOCK_THREADS % WARP_THREADS == 0), "BLOCK_THREADS must be a multiple of WARP_THREADS");
+
+ // BlockExchange utility type for keys
+ typedef BlockExchange<InputT, BLOCK_DIM_X, ITEMS_PER_THREAD, false, BLOCK_DIM_Y, BLOCK_DIM_Z, PTX_ARCH> BlockExchange;
+
+ /// Shared memory storage layout type
+ struct _TempStorage : BlockExchange::TempStorage
+ {};
+
+ /// Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+ /// Thread reference to shared storage
+ _TempStorage &temp_storage;
+
+ /// Linear thread-id
+ int linear_tid;
+
+ /// Constructor
+ __device__ __forceinline__ LoadInternal(
+ TempStorage &temp_storage,
+ int linear_tid)
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(linear_tid)
+ {}
+
+ /// Load a linear segment of items from memory
+ template <typename InputIteratorT>
+ __device__ __forceinline__ void Load(
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD]) ///< [out] Data to load{
+ {
+ LoadDirectWarpStriped(linear_tid, block_itr, items);
+ BlockExchange(temp_storage).WarpStripedToBlocked(items, items);
+ }
+
+ /// Load a linear segment of items from memory, guarded by range
+ template <typename InputIteratorT>
+ __device__ __forceinline__ void Load(
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD], ///< [out] Data to load
+ int valid_items) ///< [in] Number of valid items to load
+ {
+ LoadDirectWarpStriped(linear_tid, block_itr, items, valid_items);
+ BlockExchange(temp_storage).WarpStripedToBlocked(items, items);
+ }
+
+
+ /// Load a linear segment of items from memory, guarded by range, with a fall-back assignment of out-of-bound elements
+ template <typename InputIteratorT, typename DefaultT>
+ __device__ __forceinline__ void Load(
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD], ///< [out] Data to load
+ int valid_items, ///< [in] Number of valid items to load
+ DefaultT oob_default) ///< [in] Default value to assign out-of-bound items
+ {
+ LoadDirectWarpStriped(linear_tid, block_itr, items, valid_items, oob_default);
+ BlockExchange(temp_storage).WarpStripedToBlocked(items, items);
+ }
+ };
+
+
+ /**
+ * BLOCK_LOAD_WARP_TRANSPOSE_TIMESLICED specialization of load helper
+ */
+ template <int DUMMY>
+ struct LoadInternal<BLOCK_LOAD_WARP_TRANSPOSE_TIMESLICED, DUMMY>
+ {
+ enum
+ {
+ WARP_THREADS = CUB_WARP_THREADS(PTX_ARCH)
+ };
+
+ // Assert BLOCK_THREADS must be a multiple of WARP_THREADS
+ CUB_STATIC_ASSERT((BLOCK_THREADS % WARP_THREADS == 0), "BLOCK_THREADS must be a multiple of WARP_THREADS");
+
+ // BlockExchange utility type for keys
+ typedef BlockExchange<InputT, BLOCK_DIM_X, ITEMS_PER_THREAD, true, BLOCK_DIM_Y, BLOCK_DIM_Z, PTX_ARCH> BlockExchange;
+
+ /// Shared memory storage layout type
+ struct _TempStorage : BlockExchange::TempStorage
+ {};
+
+ /// Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+ /// Thread reference to shared storage
+ _TempStorage &temp_storage;
+
+ /// Linear thread-id
+ int linear_tid;
+
+ /// Constructor
+ __device__ __forceinline__ LoadInternal(
+ TempStorage &temp_storage,
+ int linear_tid)
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(linear_tid)
+ {}
+
+ /// Load a linear segment of items from memory
+ template <typename InputIteratorT>
+ __device__ __forceinline__ void Load(
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD]) ///< [out] Data to load{
+ {
+ LoadDirectWarpStriped(linear_tid, block_itr, items);
+ BlockExchange(temp_storage).WarpStripedToBlocked(items, items);
+ }
+
+ /// Load a linear segment of items from memory, guarded by range
+ template <typename InputIteratorT>
+ __device__ __forceinline__ void Load(
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD], ///< [out] Data to load
+ int valid_items) ///< [in] Number of valid items to load
+ {
+ LoadDirectWarpStriped(linear_tid, block_itr, items, valid_items);
+ BlockExchange(temp_storage).WarpStripedToBlocked(items, items);
+ }
+
+
+ /// Load a linear segment of items from memory, guarded by range, with a fall-back assignment of out-of-bound elements
+ template <typename InputIteratorT, typename DefaultT>
+ __device__ __forceinline__ void Load(
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD], ///< [out] Data to load
+ int valid_items, ///< [in] Number of valid items to load
+ DefaultT oob_default) ///< [in] Default value to assign out-of-bound items
+ {
+ LoadDirectWarpStriped(linear_tid, block_itr, items, valid_items, oob_default);
+ BlockExchange(temp_storage).WarpStripedToBlocked(items, items);
+ }
+ };
+
+
+ /******************************************************************************
+ * Type definitions
+ ******************************************************************************/
+
+ /// Internal load implementation to use
+ typedef LoadInternal<ALGORITHM, 0> InternalLoad;
+
+
+ /// Shared memory storage layout type
+ typedef typename InternalLoad::TempStorage _TempStorage;
+
+
+ /******************************************************************************
+ * Utility methods
+ ******************************************************************************/
+
+ /// Internal storage allocator
+ __device__ __forceinline__ _TempStorage& PrivateStorage()
+ {
+ __shared__ _TempStorage private_storage;
+ return private_storage;
+ }
+
+
+ /******************************************************************************
+ * Thread fields
+ ******************************************************************************/
+
+ /// Thread reference to shared storage
+ _TempStorage &temp_storage;
+
+ /// Linear thread-id
+ int linear_tid;
+
+public:
+
+ /// \smemstorage{BlockLoad}
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ /******************************************************************//**
+ * \name Collective constructors
+ *********************************************************************/
+ //@{
+
+ /**
+ * \brief Collective constructor using a private static allocation of shared memory as temporary storage.
+ */
+ __device__ __forceinline__ BlockLoad()
+ :
+ temp_storage(PrivateStorage()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ /**
+ * \brief Collective constructor using the specified memory allocation as temporary storage.
+ */
+ __device__ __forceinline__ BlockLoad(
+ TempStorage &temp_storage) ///< [in] Reference to memory allocation having layout type TempStorage
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+
+
+ //@} end member group
+ /******************************************************************//**
+ * \name Data movement
+ *********************************************************************/
+ //@{
+
+
+ /**
+ * \brief Load a linear segment of items from memory.
+ *
+ * \par
+ * - \blocked
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates the loading of a linear
+ * segment of 512 integers into a "blocked" arrangement across 128 threads where each
+ * thread owns 4 consecutive items. The load is specialized for \p BLOCK_LOAD_WARP_TRANSPOSE,
+ * meaning memory references are efficiently coalesced using a warp-striped access
+ * pattern (after which items are locally reordered among threads).
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_load.cuh>
+ *
+ * __global__ void ExampleKernel(int *d_data, ...)
+ * {
+ * // Specialize BlockLoad for a 1D block of 128 threads owning 4 integer items each
+ * typedef cub::BlockLoad<int, 128, 4, BLOCK_LOAD_WARP_TRANSPOSE> BlockLoad;
+ *
+ * // Allocate shared memory for BlockLoad
+ * __shared__ typename BlockLoad::TempStorage temp_storage;
+ *
+ * // Load a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * BlockLoad(temp_storage).Load(d_data, thread_data);
+ *
+ * \endcode
+ * \par
+ * Suppose the input \p d_data is <tt>0, 1, 2, 3, 4, 5, ...</tt>.
+ * The set of \p thread_data across the block of threads in those threads will be
+ * <tt>{ [0,1,2,3], [4,5,6,7], ..., [508,509,510,511] }</tt>.
+ *
+ */
+ template <typename InputIteratorT>
+ __device__ __forceinline__ void Load(
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD]) ///< [out] Data to load
+ {
+ InternalLoad(temp_storage, linear_tid).Load(block_itr, items);
+ }
+
+
+ /**
+ * \brief Load a linear segment of items from memory, guarded by range.
+ *
+ * \par
+ * - \blocked
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates the guarded loading of a linear
+ * segment of 512 integers into a "blocked" arrangement across 128 threads where each
+ * thread owns 4 consecutive items. The load is specialized for \p BLOCK_LOAD_WARP_TRANSPOSE,
+ * meaning memory references are efficiently coalesced using a warp-striped access
+ * pattern (after which items are locally reordered among threads).
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_load.cuh>
+ *
+ * __global__ void ExampleKernel(int *d_data, int valid_items, ...)
+ * {
+ * // Specialize BlockLoad for a 1D block of 128 threads owning 4 integer items each
+ * typedef cub::BlockLoad<int, 128, 4, BLOCK_LOAD_WARP_TRANSPOSE> BlockLoad;
+ *
+ * // Allocate shared memory for BlockLoad
+ * __shared__ typename BlockLoad::TempStorage temp_storage;
+ *
+ * // Load a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * BlockLoad(temp_storage).Load(d_data, thread_data, valid_items);
+ *
+ * \endcode
+ * \par
+ * Suppose the input \p d_data is <tt>0, 1, 2, 3, 4, 5, 6...</tt> and \p valid_items is \p 5.
+ * The set of \p thread_data across the block of threads in those threads will be
+ * <tt>{ [0,1,2,3], [4,?,?,?], ..., [?,?,?,?] }</tt>, with only the first two threads
+ * being unmasked to load portions of valid data (and other items remaining unassigned).
+ *
+ */
+ template <typename InputIteratorT>
+ __device__ __forceinline__ void Load(
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD], ///< [out] Data to load
+ int valid_items) ///< [in] Number of valid items to load
+ {
+ InternalLoad(temp_storage, linear_tid).Load(block_itr, items, valid_items);
+ }
+
+
+ /**
+ * \brief Load a linear segment of items from memory, guarded by range, with a fall-back assignment of out-of-bound elements
+ *
+ * \par
+ * - \blocked
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates the guarded loading of a linear
+ * segment of 512 integers into a "blocked" arrangement across 128 threads where each
+ * thread owns 4 consecutive items. The load is specialized for \p BLOCK_LOAD_WARP_TRANSPOSE,
+ * meaning memory references are efficiently coalesced using a warp-striped access
+ * pattern (after which items are locally reordered among threads).
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_load.cuh>
+ *
+ * __global__ void ExampleKernel(int *d_data, int valid_items, ...)
+ * {
+ * // Specialize BlockLoad for a 1D block of 128 threads owning 4 integer items each
+ * typedef cub::BlockLoad<int, 128, 4, BLOCK_LOAD_WARP_TRANSPOSE> BlockLoad;
+ *
+ * // Allocate shared memory for BlockLoad
+ * __shared__ typename BlockLoad::TempStorage temp_storage;
+ *
+ * // Load a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * BlockLoad(temp_storage).Load(d_data, thread_data, valid_items, -1);
+ *
+ * \endcode
+ * \par
+ * Suppose the input \p d_data is <tt>0, 1, 2, 3, 4, 5, 6...</tt>,
+ * \p valid_items is \p 5, and the out-of-bounds default is \p -1.
+ * The set of \p thread_data across the block of threads in those threads will be
+ * <tt>{ [0,1,2,3], [4,-1,-1,-1], ..., [-1,-1,-1,-1] }</tt>, with only the first two threads
+ * being unmasked to load portions of valid data (and other items are assigned \p -1)
+ *
+ */
+ template <typename InputIteratorT, typename DefaultT>
+ __device__ __forceinline__ void Load(
+ InputIteratorT block_itr, ///< [in] The thread block's base input iterator for loading from
+ InputT (&items)[ITEMS_PER_THREAD], ///< [out] Data to load
+ int valid_items, ///< [in] Number of valid items to load
+ DefaultT oob_default) ///< [in] Default value to assign out-of-bound items
+ {
+ InternalLoad(temp_storage, linear_tid).Load(block_itr, items, valid_items, oob_default);
+ }
+
+
+ //@} end member group
+
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_radix_rank.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_radix_rank.cuh
new file mode 100644
index 0000000..c26451c
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_radix_rank.cuh
@@ -0,0 +1,696 @@
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-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 TORT
+ * (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
+ * cub::BlockRadixRank provides operations for ranking unsigned integer types within a CUDA thread block
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include "../thread/thread_reduce.cuh"
+#include "../thread/thread_scan.cuh"
+#include "../block/block_scan.cuh"
+#include "../util_ptx.cuh"
+#include "../util_arch.cuh"
+#include "../util_type.cuh"
+#include "../util_namespace.cuh"
+
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+/**
+ * \brief BlockRadixRank provides operations for ranking unsigned integer types within a CUDA thread block.
+ * \ingroup BlockModule
+ *
+ * \tparam BLOCK_DIM_X The thread block length in threads along the X dimension
+ * \tparam RADIX_BITS The number of radix bits per digit place
+ * \tparam IS_DESCENDING Whether or not the sorted-order is high-to-low
+ * \tparam MEMOIZE_OUTER_SCAN <b>[optional]</b> Whether or not to buffer outer raking scan partials to incur fewer shared memory reads at the expense of higher register pressure (default: true for architectures SM35 and newer, false otherwise). See BlockScanAlgorithm::BLOCK_SCAN_RAKING_MEMOIZE for more details.
+ * \tparam INNER_SCAN_ALGORITHM <b>[optional]</b> The cub::BlockScanAlgorithm algorithm to use (default: cub::BLOCK_SCAN_WARP_SCANS)
+ * \tparam SMEM_CONFIG <b>[optional]</b> Shared memory bank mode (default: \p cudaSharedMemBankSizeFourByte)
+ * \tparam BLOCK_DIM_Y <b>[optional]</b> The thread block length in threads along the Y dimension (default: 1)
+ * \tparam BLOCK_DIM_Z <b>[optional]</b> The thread block length in threads along the Z dimension (default: 1)
+ * \tparam PTX_ARCH <b>[optional]</b> \ptxversion
+ *
+ * \par Overview
+ * Blah...
+ * - Keys must be in a form suitable for radix ranking (i.e., unsigned bits).
+ * - \blocked
+ *
+ * \par Performance Considerations
+ * - \granularity
+ *
+ * \par Examples
+ * \par
+ * - <b>Example 1:</b> Simple radix rank of 32-bit integer keys
+ * \code
+ * #include <cub/cub.cuh>
+ *
+ * template <int BLOCK_THREADS>
+ * __global__ void ExampleKernel(...)
+ * {
+ *
+ * \endcode
+ */
+template <
+ int BLOCK_DIM_X,
+ int RADIX_BITS,
+ bool IS_DESCENDING,
+ bool MEMOIZE_OUTER_SCAN = (CUB_PTX_ARCH >= 350) ? true : false,
+ BlockScanAlgorithm INNER_SCAN_ALGORITHM = BLOCK_SCAN_WARP_SCANS,
+ cudaSharedMemConfig SMEM_CONFIG = cudaSharedMemBankSizeFourByte,
+ int BLOCK_DIM_Y = 1,
+ int BLOCK_DIM_Z = 1,
+ int PTX_ARCH = CUB_PTX_ARCH>
+class BlockRadixRank
+{
+private:
+
+ /******************************************************************************
+ * Type definitions and constants
+ ******************************************************************************/
+
+ // Integer type for digit counters (to be packed into words of type PackedCounters)
+ typedef unsigned short DigitCounter;
+
+ // Integer type for packing DigitCounters into columns of shared memory banks
+ typedef typename If<(SMEM_CONFIG == cudaSharedMemBankSizeEightByte),
+ unsigned long long,
+ unsigned int>::Type PackedCounter;
+
+ enum
+ {
+ // The thread block size in threads
+ BLOCK_THREADS = BLOCK_DIM_X * BLOCK_DIM_Y * BLOCK_DIM_Z,
+
+ RADIX_DIGITS = 1 << RADIX_BITS,
+
+ LOG_WARP_THREADS = CUB_LOG_WARP_THREADS(PTX_ARCH),
+ WARP_THREADS = 1 << LOG_WARP_THREADS,
+ WARPS = (BLOCK_THREADS + WARP_THREADS - 1) / WARP_THREADS,
+
+ BYTES_PER_COUNTER = sizeof(DigitCounter),
+ LOG_BYTES_PER_COUNTER = Log2<BYTES_PER_COUNTER>::VALUE,
+
+ PACKING_RATIO = sizeof(PackedCounter) / sizeof(DigitCounter),
+ LOG_PACKING_RATIO = Log2<PACKING_RATIO>::VALUE,
+
+ LOG_COUNTER_LANES = CUB_MAX((RADIX_BITS - LOG_PACKING_RATIO), 0), // Always at least one lane
+ COUNTER_LANES = 1 << LOG_COUNTER_LANES,
+
+ // The number of packed counters per thread (plus one for padding)
+ PADDED_COUNTER_LANES = COUNTER_LANES + 1,
+ RAKING_SEGMENT = PADDED_COUNTER_LANES,
+ };
+
+public:
+
+ enum
+ {
+ /// Number of bin-starting offsets tracked per thread
+ BINS_TRACKED_PER_THREAD = CUB_MAX(1, (RADIX_DIGITS + BLOCK_THREADS - 1) / BLOCK_THREADS),
+ };
+
+private:
+
+
+ /// BlockScan type
+ typedef BlockScan<
+ PackedCounter,
+ BLOCK_DIM_X,
+ INNER_SCAN_ALGORITHM,
+ BLOCK_DIM_Y,
+ BLOCK_DIM_Z,
+ PTX_ARCH>
+ BlockScan;
+
+
+ /// Shared memory storage layout type for BlockRadixRank
+ struct __align__(16) _TempStorage
+ {
+ union Aliasable
+ {
+ DigitCounter digit_counters[PADDED_COUNTER_LANES][BLOCK_THREADS][PACKING_RATIO];
+ PackedCounter raking_grid[BLOCK_THREADS][RAKING_SEGMENT];
+
+ } aliasable;
+
+ // Storage for scanning local ranks
+ typename BlockScan::TempStorage block_scan;
+ };
+
+
+ /******************************************************************************
+ * Thread fields
+ ******************************************************************************/
+
+ /// Shared storage reference
+ _TempStorage &temp_storage;
+
+ /// Linear thread-id
+ unsigned int linear_tid;
+
+ /// Copy of raking segment, promoted to registers
+ PackedCounter cached_segment[RAKING_SEGMENT];
+
+
+ /******************************************************************************
+ * Utility methods
+ ******************************************************************************/
+
+ /**
+ * Internal storage allocator
+ */
+ __device__ __forceinline__ _TempStorage& PrivateStorage()
+ {
+ __shared__ _TempStorage private_storage;
+ return private_storage;
+ }
+
+
+ /**
+ * Performs upsweep raking reduction, returning the aggregate
+ */
+ __device__ __forceinline__ PackedCounter Upsweep()
+ {
+ PackedCounter *smem_raking_ptr = temp_storage.aliasable.raking_grid[linear_tid];
+ PackedCounter *raking_ptr;
+
+ if (MEMOIZE_OUTER_SCAN)
+ {
+ // Copy data into registers
+ #pragma unroll
+ for (int i = 0; i < RAKING_SEGMENT; i++)
+ {
+ cached_segment[i] = smem_raking_ptr[i];
+ }
+ raking_ptr = cached_segment;
+ }
+ else
+ {
+ raking_ptr = smem_raking_ptr;
+ }
+
+ return internal::ThreadReduce<RAKING_SEGMENT>(raking_ptr, Sum());
+ }
+
+
+ /// Performs exclusive downsweep raking scan
+ __device__ __forceinline__ void ExclusiveDownsweep(
+ PackedCounter raking_partial)
+ {
+ PackedCounter *smem_raking_ptr = temp_storage.aliasable.raking_grid[linear_tid];
+
+ PackedCounter *raking_ptr = (MEMOIZE_OUTER_SCAN) ?
+ cached_segment :
+ smem_raking_ptr;
+
+ // Exclusive raking downsweep scan
+ internal::ThreadScanExclusive<RAKING_SEGMENT>(raking_ptr, raking_ptr, Sum(), raking_partial);
+
+ if (MEMOIZE_OUTER_SCAN)
+ {
+ // Copy data back to smem
+ #pragma unroll
+ for (int i = 0; i < RAKING_SEGMENT; i++)
+ {
+ smem_raking_ptr[i] = cached_segment[i];
+ }
+ }
+ }
+
+
+ /**
+ * Reset shared memory digit counters
+ */
+ __device__ __forceinline__ void ResetCounters()
+ {
+ // Reset shared memory digit counters
+ #pragma unroll
+ for (int LANE = 0; LANE < PADDED_COUNTER_LANES; LANE++)
+ {
+ *((PackedCounter*) temp_storage.aliasable.digit_counters[LANE][linear_tid]) = 0;
+ }
+ }
+
+
+ /**
+ * Block-scan prefix callback
+ */
+ struct PrefixCallBack
+ {
+ __device__ __forceinline__ PackedCounter operator()(PackedCounter block_aggregate)
+ {
+ PackedCounter block_prefix = 0;
+
+ // Propagate totals in packed fields
+ #pragma unroll
+ for (int PACKED = 1; PACKED < PACKING_RATIO; PACKED++)
+ {
+ block_prefix += block_aggregate << (sizeof(DigitCounter) * 8 * PACKED);
+ }
+
+ return block_prefix;
+ }
+ };
+
+
+ /**
+ * Scan shared memory digit counters.
+ */
+ __device__ __forceinline__ void ScanCounters()
+ {
+ // Upsweep scan
+ PackedCounter raking_partial = Upsweep();
+
+ // Compute exclusive sum
+ PackedCounter exclusive_partial;
+ PrefixCallBack prefix_call_back;
+ BlockScan(temp_storage.block_scan).ExclusiveSum(raking_partial, exclusive_partial, prefix_call_back);
+
+ // Downsweep scan with exclusive partial
+ ExclusiveDownsweep(exclusive_partial);
+ }
+
+public:
+
+ /// \smemstorage{BlockScan}
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ /******************************************************************//**
+ * \name Collective constructors
+ *********************************************************************/
+ //@{
+
+ /**
+ * \brief Collective constructor using a private static allocation of shared memory as temporary storage.
+ */
+ __device__ __forceinline__ BlockRadixRank()
+ :
+ temp_storage(PrivateStorage()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ /**
+ * \brief Collective constructor using the specified memory allocation as temporary storage.
+ */
+ __device__ __forceinline__ BlockRadixRank(
+ TempStorage &temp_storage) ///< [in] Reference to memory allocation having layout type TempStorage
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ //@} end member group
+ /******************************************************************//**
+ * \name Raking
+ *********************************************************************/
+ //@{
+
+ /**
+ * \brief Rank keys.
+ */
+ template <
+ typename UnsignedBits,
+ int KEYS_PER_THREAD>
+ __device__ __forceinline__ void RankKeys(
+ UnsignedBits (&keys)[KEYS_PER_THREAD], ///< [in] Keys for this tile
+ int (&ranks)[KEYS_PER_THREAD], ///< [out] For each key, the local rank within the tile
+ int current_bit, ///< [in] The least-significant bit position of the current digit to extract
+ int num_bits) ///< [in] The number of bits in the current digit
+ {
+ DigitCounter thread_prefixes[KEYS_PER_THREAD]; // For each key, the count of previous keys in this tile having the same digit
+ DigitCounter* digit_counters[KEYS_PER_THREAD]; // For each key, the byte-offset of its corresponding digit counter in smem
+
+ // Reset shared memory digit counters
+ ResetCounters();
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < KEYS_PER_THREAD; ++ITEM)
+ {
+ // Get digit
+ unsigned int digit = BFE(keys[ITEM], current_bit, num_bits);
+
+ // Get sub-counter
+ unsigned int sub_counter = digit >> LOG_COUNTER_LANES;
+
+ // Get counter lane
+ unsigned int counter_lane = digit & (COUNTER_LANES - 1);
+
+ if (IS_DESCENDING)
+ {
+ sub_counter = PACKING_RATIO - 1 - sub_counter;
+ counter_lane = COUNTER_LANES - 1 - counter_lane;
+ }
+
+ // Pointer to smem digit counter
+ digit_counters[ITEM] = &temp_storage.aliasable.digit_counters[counter_lane][linear_tid][sub_counter];
+
+ // Load thread-exclusive prefix
+ thread_prefixes[ITEM] = *digit_counters[ITEM];
+
+ // Store inclusive prefix
+ *digit_counters[ITEM] = thread_prefixes[ITEM] + 1;
+ }
+
+ CTA_SYNC();
+
+ // Scan shared memory counters
+ ScanCounters();
+
+ CTA_SYNC();
+
+ // Extract the local ranks of each key
+ for (int ITEM = 0; ITEM < KEYS_PER_THREAD; ++ITEM)
+ {
+ // Add in thread block exclusive prefix
+ ranks[ITEM] = thread_prefixes[ITEM] + *digit_counters[ITEM];
+ }
+ }
+
+
+ /**
+ * \brief Rank keys. For the lower \p RADIX_DIGITS threads, digit counts for each digit are provided for the corresponding thread.
+ */
+ template <
+ typename UnsignedBits,
+ int KEYS_PER_THREAD>
+ __device__ __forceinline__ void RankKeys(
+ UnsignedBits (&keys)[KEYS_PER_THREAD], ///< [in] Keys for this tile
+ int (&ranks)[KEYS_PER_THREAD], ///< [out] For each key, the local rank within the tile (out parameter)
+ int current_bit, ///< [in] The least-significant bit position of the current digit to extract
+ int num_bits, ///< [in] The number of bits in the current digit
+ int (&exclusive_digit_prefix)[BINS_TRACKED_PER_THREAD]) ///< [out] The exclusive prefix sum for the digits [(threadIdx.x * BINS_TRACKED_PER_THREAD) ... (threadIdx.x * BINS_TRACKED_PER_THREAD) + BINS_TRACKED_PER_THREAD - 1]
+ {
+ // Rank keys
+ RankKeys(keys, ranks, current_bit, num_bits);
+
+ // Get the inclusive and exclusive digit totals corresponding to the calling thread.
+ #pragma unroll
+ for (int track = 0; track < BINS_TRACKED_PER_THREAD; ++track)
+ {
+ int bin_idx = (linear_tid * BINS_TRACKED_PER_THREAD) + track;
+
+ if ((BLOCK_THREADS == RADIX_DIGITS) || (bin_idx < RADIX_DIGITS))
+ {
+ if (IS_DESCENDING)
+ bin_idx = RADIX_DIGITS - bin_idx - 1;
+
+ // Obtain ex/inclusive digit counts. (Unfortunately these all reside in the
+ // first counter column, resulting in unavoidable bank conflicts.)
+ unsigned int counter_lane = (bin_idx & (COUNTER_LANES - 1));
+ unsigned int sub_counter = bin_idx >> (LOG_COUNTER_LANES);
+
+ exclusive_digit_prefix[track] = temp_storage.aliasable.digit_counters[counter_lane][0][sub_counter];
+ }
+ }
+ }
+};
+
+
+
+
+
+/**
+ * Radix-rank using match.any
+ */
+template <
+ int BLOCK_DIM_X,
+ int RADIX_BITS,
+ bool IS_DESCENDING,
+ BlockScanAlgorithm INNER_SCAN_ALGORITHM = BLOCK_SCAN_WARP_SCANS,
+ int BLOCK_DIM_Y = 1,
+ int BLOCK_DIM_Z = 1,
+ int PTX_ARCH = CUB_PTX_ARCH>
+class BlockRadixRankMatch
+{
+private:
+
+ /******************************************************************************
+ * Type definitions and constants
+ ******************************************************************************/
+
+ typedef int32_t RankT;
+ typedef int32_t DigitCounterT;
+
+ enum
+ {
+ // The thread block size in threads
+ BLOCK_THREADS = BLOCK_DIM_X * BLOCK_DIM_Y * BLOCK_DIM_Z,
+
+ RADIX_DIGITS = 1 << RADIX_BITS,
+
+ LOG_WARP_THREADS = CUB_LOG_WARP_THREADS(PTX_ARCH),
+ WARP_THREADS = 1 << LOG_WARP_THREADS,
+ WARPS = (BLOCK_THREADS + WARP_THREADS - 1) / WARP_THREADS,
+
+ PADDED_WARPS = ((WARPS & 0x1) == 0) ?
+ WARPS + 1 :
+ WARPS,
+
+ COUNTERS = PADDED_WARPS * RADIX_DIGITS,
+ RAKING_SEGMENT = (COUNTERS + BLOCK_THREADS - 1) / BLOCK_THREADS,
+ PADDED_RAKING_SEGMENT = ((RAKING_SEGMENT & 0x1) == 0) ?
+ RAKING_SEGMENT + 1 :
+ RAKING_SEGMENT,
+ };
+
+public:
+
+ enum
+ {
+ /// Number of bin-starting offsets tracked per thread
+ BINS_TRACKED_PER_THREAD = CUB_MAX(1, (RADIX_DIGITS + BLOCK_THREADS - 1) / BLOCK_THREADS),
+ };
+
+private:
+
+ /// BlockScan type
+ typedef BlockScan<
+ DigitCounterT,
+ BLOCK_THREADS,
+ INNER_SCAN_ALGORITHM,
+ BLOCK_DIM_Y,
+ BLOCK_DIM_Z,
+ PTX_ARCH>
+ BlockScanT;
+
+
+ /// Shared memory storage layout type for BlockRadixRank
+ struct __align__(16) _TempStorage
+ {
+ typename BlockScanT::TempStorage block_scan;
+
+ union __align__(16) Aliasable
+ {
+ volatile DigitCounterT warp_digit_counters[RADIX_DIGITS][PADDED_WARPS];
+ DigitCounterT raking_grid[BLOCK_THREADS][PADDED_RAKING_SEGMENT];
+
+ } aliasable;
+ };
+
+
+ /******************************************************************************
+ * Thread fields
+ ******************************************************************************/
+
+ /// Shared storage reference
+ _TempStorage &temp_storage;
+
+ /// Linear thread-id
+ unsigned int linear_tid;
+
+
+
+public:
+
+ /// \smemstorage{BlockScan}
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ /******************************************************************//**
+ * \name Collective constructors
+ *********************************************************************/
+ //@{
+
+
+ /**
+ * \brief Collective constructor using the specified memory allocation as temporary storage.
+ */
+ __device__ __forceinline__ BlockRadixRankMatch(
+ TempStorage &temp_storage) ///< [in] Reference to memory allocation having layout type TempStorage
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ //@} end member group
+ /******************************************************************//**
+ * \name Raking
+ *********************************************************************/
+ //@{
+
+ /**
+ * \brief Rank keys.
+ */
+ template <
+ typename UnsignedBits,
+ int KEYS_PER_THREAD>
+ __device__ __forceinline__ void RankKeys(
+ UnsignedBits (&keys)[KEYS_PER_THREAD], ///< [in] Keys for this tile
+ int (&ranks)[KEYS_PER_THREAD], ///< [out] For each key, the local rank within the tile
+ int current_bit, ///< [in] The least-significant bit position of the current digit to extract
+ int num_bits) ///< [in] The number of bits in the current digit
+ {
+ // Initialize shared digit counters
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < PADDED_RAKING_SEGMENT; ++ITEM)
+ temp_storage.aliasable.raking_grid[linear_tid][ITEM] = 0;
+
+ CTA_SYNC();
+
+ // Each warp will strip-mine its section of input, one strip at a time
+
+ volatile DigitCounterT *digit_counters[KEYS_PER_THREAD];
+ uint32_t warp_id = linear_tid >> LOG_WARP_THREADS;
+ uint32_t lane_mask_lt = LaneMaskLt();
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < KEYS_PER_THREAD; ++ITEM)
+ {
+ // My digit
+ uint32_t digit = BFE(keys[ITEM], current_bit, num_bits);
+
+ if (IS_DESCENDING)
+ digit = RADIX_DIGITS - digit - 1;
+
+ // Mask of peers who have same digit as me
+ uint32_t peer_mask = MatchAny<RADIX_BITS>(digit);
+
+ // Pointer to smem digit counter for this key
+ digit_counters[ITEM] = &temp_storage.aliasable.warp_digit_counters[digit][warp_id];
+
+ // Number of occurrences in previous strips
+ DigitCounterT warp_digit_prefix = *digit_counters[ITEM];
+
+ // Warp-sync
+ WARP_SYNC(0xFFFFFFFF);
+
+ // Number of peers having same digit as me
+ int32_t digit_count = __popc(peer_mask);
+
+ // Number of lower-ranked peers having same digit seen so far
+ int32_t peer_digit_prefix = __popc(peer_mask & lane_mask_lt);
+
+ if (peer_digit_prefix == 0)
+ {
+ // First thread for each digit updates the shared warp counter
+ *digit_counters[ITEM] = DigitCounterT(warp_digit_prefix + digit_count);
+ }
+
+ // Warp-sync
+ WARP_SYNC(0xFFFFFFFF);
+
+ // Number of prior keys having same digit
+ ranks[ITEM] = warp_digit_prefix + DigitCounterT(peer_digit_prefix);
+ }
+
+ CTA_SYNC();
+
+ // Scan warp counters
+
+ DigitCounterT scan_counters[PADDED_RAKING_SEGMENT];
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < PADDED_RAKING_SEGMENT; ++ITEM)
+ scan_counters[ITEM] = temp_storage.aliasable.raking_grid[linear_tid][ITEM];
+
+ BlockScanT(temp_storage.block_scan).ExclusiveSum(scan_counters, scan_counters);
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < PADDED_RAKING_SEGMENT; ++ITEM)
+ temp_storage.aliasable.raking_grid[linear_tid][ITEM] = scan_counters[ITEM];
+
+ CTA_SYNC();
+
+ // Seed ranks with counter values from previous warps
+ #pragma unroll
+ for (int ITEM = 0; ITEM < KEYS_PER_THREAD; ++ITEM)
+ ranks[ITEM] += *digit_counters[ITEM];
+ }
+
+
+ /**
+ * \brief Rank keys. For the lower \p RADIX_DIGITS threads, digit counts for each digit are provided for the corresponding thread.
+ */
+ template <
+ typename UnsignedBits,
+ int KEYS_PER_THREAD>
+ __device__ __forceinline__ void RankKeys(
+ UnsignedBits (&keys)[KEYS_PER_THREAD], ///< [in] Keys for this tile
+ int (&ranks)[KEYS_PER_THREAD], ///< [out] For each key, the local rank within the tile (out parameter)
+ int current_bit, ///< [in] The least-significant bit position of the current digit to extract
+ int num_bits, ///< [in] The number of bits in the current digit
+ int (&exclusive_digit_prefix)[BINS_TRACKED_PER_THREAD]) ///< [out] The exclusive prefix sum for the digits [(threadIdx.x * BINS_TRACKED_PER_THREAD) ... (threadIdx.x * BINS_TRACKED_PER_THREAD) + BINS_TRACKED_PER_THREAD - 1]
+ {
+ RankKeys(keys, ranks, current_bit, num_bits);
+
+ // Get exclusive count for each digit
+ #pragma unroll
+ for (int track = 0; track < BINS_TRACKED_PER_THREAD; ++track)
+ {
+ int bin_idx = (linear_tid * BINS_TRACKED_PER_THREAD) + track;
+
+ if ((BLOCK_THREADS == RADIX_DIGITS) || (bin_idx < RADIX_DIGITS))
+ {
+ if (IS_DESCENDING)
+ bin_idx = RADIX_DIGITS - bin_idx - 1;
+
+ exclusive_digit_prefix[track] = temp_storage.aliasable.warp_digit_counters[bin_idx][0];
+ }
+ }
+ }
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_radix_sort.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_radix_sort.cuh
new file mode 100644
index 0000000..ac0c9f8
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_radix_sort.cuh
@@ -0,0 +1,863 @@
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-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 TORT
+ * (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
+ * The cub::BlockRadixSort class provides [<em>collective</em>](index.html#sec0) methods for radix sorting of items partitioned across a CUDA thread block.
+ */
+
+
+#pragma once
+
+#include "block_exchange.cuh"
+#include "block_radix_rank.cuh"
+#include "../util_ptx.cuh"
+#include "../util_arch.cuh"
+#include "../util_type.cuh"
+#include "../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+/**
+ * \brief The BlockRadixSort class provides [<em>collective</em>](index.html#sec0) methods for sorting items partitioned across a CUDA thread block using a radix sorting method. ![](sorting_logo.png)
+ * \ingroup BlockModule
+ *
+ * \tparam KeyT KeyT type
+ * \tparam BLOCK_DIM_X The thread block length in threads along the X dimension
+ * \tparam ITEMS_PER_THREAD The number of items per thread
+ * \tparam ValueT <b>[optional]</b> ValueT type (default: cub::NullType, which indicates a keys-only sort)
+ * \tparam RADIX_BITS <b>[optional]</b> The number of radix bits per digit place (default: 4 bits)
+ * \tparam MEMOIZE_OUTER_SCAN <b>[optional]</b> Whether or not to buffer outer raking scan partials to incur fewer shared memory reads at the expense of higher register pressure (default: true for architectures SM35 and newer, false otherwise).
+ * \tparam INNER_SCAN_ALGORITHM <b>[optional]</b> The cub::BlockScanAlgorithm algorithm to use (default: cub::BLOCK_SCAN_WARP_SCANS)
+ * \tparam SMEM_CONFIG <b>[optional]</b> Shared memory bank mode (default: \p cudaSharedMemBankSizeFourByte)
+ * \tparam BLOCK_DIM_Y <b>[optional]</b> The thread block length in threads along the Y dimension (default: 1)
+ * \tparam BLOCK_DIM_Z <b>[optional]</b> The thread block length in threads along the Z dimension (default: 1)
+ * \tparam PTX_ARCH <b>[optional]</b> \ptxversion
+ *
+ * \par Overview
+ * - The [<em>radix sorting method</em>](http://en.wikipedia.org/wiki/Radix_sort) arranges
+ * items into ascending order. It relies upon a positional representation for
+ * keys, i.e., each key is comprised of an ordered sequence of symbols (e.g., digits,
+ * characters, etc.) specified from least-significant to most-significant. For a
+ * given input sequence of keys and a set of rules specifying a total ordering
+ * of the symbolic alphabet, the radix sorting method produces a lexicographic
+ * ordering of those keys.
+ * - BlockRadixSort can sort all of the built-in C++ numeric primitive types
+ * (<tt>unsigned char</tt>, \p int, \p double, etc.) as well as CUDA's \p __half
+ * half-precision floating-point type. Within each key, the implementation treats fixed-length
+ * bit-sequences of \p RADIX_BITS as radix digit places. Although the direct radix sorting
+ * method can only be applied to unsigned integral types, BlockRadixSort
+ * is able to sort signed and floating-point types via simple bit-wise transformations
+ * that ensure lexicographic key ordering.
+ * - \rowmajor
+ *
+ * \par Performance Considerations
+ * - \granularity
+ *
+ * \par A Simple Example
+ * \blockcollective{BlockRadixSort}
+ * \par
+ * The code snippet below illustrates a sort of 512 integer keys that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_radix_sort.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockRadixSort for a 1D block of 128 threads owning 4 integer items each
+ * typedef cub::BlockRadixSort<int, 128, 4> BlockRadixSort;
+ *
+ * // Allocate shared memory for BlockRadixSort
+ * __shared__ typename BlockRadixSort::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_keys[4];
+ * ...
+ *
+ * // Collectively sort the keys
+ * BlockRadixSort(temp_storage).Sort(thread_keys);
+ *
+ * ...
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_keys across the block of threads is
+ * <tt>{ [0,511,1,510], [2,509,3,508], [4,507,5,506], ..., [254,257,255,256] }</tt>. The
+ * corresponding output \p thread_keys in those threads will be
+ * <tt>{ [0,1,2,3], [4,5,6,7], [8,9,10,11], ..., [508,509,510,511] }</tt>.
+ *
+ */
+template <
+ typename KeyT,
+ int BLOCK_DIM_X,
+ int ITEMS_PER_THREAD,
+ typename ValueT = NullType,
+ int RADIX_BITS = 4,
+ bool MEMOIZE_OUTER_SCAN = (CUB_PTX_ARCH >= 350) ? true : false,
+ BlockScanAlgorithm INNER_SCAN_ALGORITHM = BLOCK_SCAN_WARP_SCANS,
+ cudaSharedMemConfig SMEM_CONFIG = cudaSharedMemBankSizeFourByte,
+ int BLOCK_DIM_Y = 1,
+ int BLOCK_DIM_Z = 1,
+ int PTX_ARCH = CUB_PTX_ARCH>
+class BlockRadixSort
+{
+private:
+
+ /******************************************************************************
+ * Constants and type definitions
+ ******************************************************************************/
+
+ enum
+ {
+ // The thread block size in threads
+ BLOCK_THREADS = BLOCK_DIM_X * BLOCK_DIM_Y * BLOCK_DIM_Z,
+
+ // Whether or not there are values to be trucked along with keys
+ KEYS_ONLY = Equals<ValueT, NullType>::VALUE,
+ };
+
+ // KeyT traits and unsigned bits type
+ typedef Traits<KeyT> KeyTraits;
+ typedef typename KeyTraits::UnsignedBits UnsignedBits;
+
+ /// Ascending BlockRadixRank utility type
+ typedef BlockRadixRank<
+ BLOCK_DIM_X,
+ RADIX_BITS,
+ false,
+ MEMOIZE_OUTER_SCAN,
+ INNER_SCAN_ALGORITHM,
+ SMEM_CONFIG,
+ BLOCK_DIM_Y,
+ BLOCK_DIM_Z,
+ PTX_ARCH>
+ AscendingBlockRadixRank;
+
+ /// Descending BlockRadixRank utility type
+ typedef BlockRadixRank<
+ BLOCK_DIM_X,
+ RADIX_BITS,
+ true,
+ MEMOIZE_OUTER_SCAN,
+ INNER_SCAN_ALGORITHM,
+ SMEM_CONFIG,
+ BLOCK_DIM_Y,
+ BLOCK_DIM_Z,
+ PTX_ARCH>
+ DescendingBlockRadixRank;
+
+ /// BlockExchange utility type for keys
+ typedef BlockExchange<KeyT, BLOCK_DIM_X, ITEMS_PER_THREAD, false, BLOCK_DIM_Y, BLOCK_DIM_Z, PTX_ARCH> BlockExchangeKeys;
+
+ /// BlockExchange utility type for values
+ typedef BlockExchange<ValueT, BLOCK_DIM_X, ITEMS_PER_THREAD, false, BLOCK_DIM_Y, BLOCK_DIM_Z, PTX_ARCH> BlockExchangeValues;
+
+ /// Shared memory storage layout type
+ union _TempStorage
+ {
+ typename AscendingBlockRadixRank::TempStorage asending_ranking_storage;
+ typename DescendingBlockRadixRank::TempStorage descending_ranking_storage;
+ typename BlockExchangeKeys::TempStorage exchange_keys;
+ typename BlockExchangeValues::TempStorage exchange_values;
+ };
+
+
+ /******************************************************************************
+ * Thread fields
+ ******************************************************************************/
+
+ /// Shared storage reference
+ _TempStorage &temp_storage;
+
+ /// Linear thread-id
+ unsigned int linear_tid;
+
+ /******************************************************************************
+ * Utility methods
+ ******************************************************************************/
+
+ /// Internal storage allocator
+ __device__ __forceinline__ _TempStorage& PrivateStorage()
+ {
+ __shared__ _TempStorage private_storage;
+ return private_storage;
+ }
+
+ /// Rank keys (specialized for ascending sort)
+ __device__ __forceinline__ void RankKeys(
+ UnsignedBits (&unsigned_keys)[ITEMS_PER_THREAD],
+ int (&ranks)[ITEMS_PER_THREAD],
+ int begin_bit,
+ int pass_bits,
+ Int2Type<false> /*is_descending*/)
+ {
+ AscendingBlockRadixRank(temp_storage.asending_ranking_storage).RankKeys(
+ unsigned_keys,
+ ranks,
+ begin_bit,
+ pass_bits);
+ }
+
+ /// Rank keys (specialized for descending sort)
+ __device__ __forceinline__ void RankKeys(
+ UnsignedBits (&unsigned_keys)[ITEMS_PER_THREAD],
+ int (&ranks)[ITEMS_PER_THREAD],
+ int begin_bit,
+ int pass_bits,
+ Int2Type<true> /*is_descending*/)
+ {
+ DescendingBlockRadixRank(temp_storage.descending_ranking_storage).RankKeys(
+ unsigned_keys,
+ ranks,
+ begin_bit,
+ pass_bits);
+ }
+
+ /// ExchangeValues (specialized for key-value sort, to-blocked arrangement)
+ __device__ __forceinline__ void ExchangeValues(
+ ValueT (&values)[ITEMS_PER_THREAD],
+ int (&ranks)[ITEMS_PER_THREAD],
+ Int2Type<false> /*is_keys_only*/,
+ Int2Type<true> /*is_blocked*/)
+ {
+ CTA_SYNC();
+
+ // Exchange values through shared memory in blocked arrangement
+ BlockExchangeValues(temp_storage.exchange_values).ScatterToBlocked(values, ranks);
+ }
+
+ /// ExchangeValues (specialized for key-value sort, to-striped arrangement)
+ __device__ __forceinline__ void ExchangeValues(
+ ValueT (&values)[ITEMS_PER_THREAD],
+ int (&ranks)[ITEMS_PER_THREAD],
+ Int2Type<false> /*is_keys_only*/,
+ Int2Type<false> /*is_blocked*/)
+ {
+ CTA_SYNC();
+
+ // Exchange values through shared memory in blocked arrangement
+ BlockExchangeValues(temp_storage.exchange_values).ScatterToStriped(values, ranks);
+ }
+
+ /// ExchangeValues (specialized for keys-only sort)
+ template <int IS_BLOCKED>
+ __device__ __forceinline__ void ExchangeValues(
+ ValueT (&/*values*/)[ITEMS_PER_THREAD],
+ int (&/*ranks*/)[ITEMS_PER_THREAD],
+ Int2Type<true> /*is_keys_only*/,
+ Int2Type<IS_BLOCKED> /*is_blocked*/)
+ {}
+
+ /// Sort blocked arrangement
+ template <int DESCENDING, int KEYS_ONLY>
+ __device__ __forceinline__ void SortBlocked(
+ KeyT (&keys)[ITEMS_PER_THREAD], ///< Keys to sort
+ ValueT (&values)[ITEMS_PER_THREAD], ///< Values to sort
+ int begin_bit, ///< The beginning (least-significant) bit index needed for key comparison
+ int end_bit, ///< The past-the-end (most-significant) bit index needed for key comparison
+ Int2Type<DESCENDING> is_descending, ///< Tag whether is a descending-order sort
+ Int2Type<KEYS_ONLY> is_keys_only) ///< Tag whether is keys-only sort
+ {
+ UnsignedBits (&unsigned_keys)[ITEMS_PER_THREAD] =
+ reinterpret_cast<UnsignedBits (&)[ITEMS_PER_THREAD]>(keys);
+
+ // Twiddle bits if necessary
+ #pragma unroll
+ for (int KEY = 0; KEY < ITEMS_PER_THREAD; KEY++)
+ {
+ unsigned_keys[KEY] = KeyTraits::TwiddleIn(unsigned_keys[KEY]);
+ }
+
+ // Radix sorting passes
+ while (true)
+ {
+ int pass_bits = CUB_MIN(RADIX_BITS, end_bit - begin_bit);
+
+ // Rank the blocked keys
+ int ranks[ITEMS_PER_THREAD];
+ RankKeys(unsigned_keys, ranks, begin_bit, pass_bits, is_descending);
+ begin_bit += RADIX_BITS;
+
+ CTA_SYNC();
+
+ // Exchange keys through shared memory in blocked arrangement
+ BlockExchangeKeys(temp_storage.exchange_keys).ScatterToBlocked(keys, ranks);
+
+ // Exchange values through shared memory in blocked arrangement
+ ExchangeValues(values, ranks, is_keys_only, Int2Type<true>());
+
+ // Quit if done
+ if (begin_bit >= end_bit) break;
+
+ CTA_SYNC();
+ }
+
+ // Untwiddle bits if necessary
+ #pragma unroll
+ for (int KEY = 0; KEY < ITEMS_PER_THREAD; KEY++)
+ {
+ unsigned_keys[KEY] = KeyTraits::TwiddleOut(unsigned_keys[KEY]);
+ }
+ }
+
+public:
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS // Do not document
+
+ /// Sort blocked -> striped arrangement
+ template <int DESCENDING, int KEYS_ONLY>
+ __device__ __forceinline__ void SortBlockedToStriped(
+ KeyT (&keys)[ITEMS_PER_THREAD], ///< Keys to sort
+ ValueT (&values)[ITEMS_PER_THREAD], ///< Values to sort
+ int begin_bit, ///< The beginning (least-significant) bit index needed for key comparison
+ int end_bit, ///< The past-the-end (most-significant) bit index needed for key comparison
+ Int2Type<DESCENDING> is_descending, ///< Tag whether is a descending-order sort
+ Int2Type<KEYS_ONLY> is_keys_only) ///< Tag whether is keys-only sort
+ {
+ UnsignedBits (&unsigned_keys)[ITEMS_PER_THREAD] =
+ reinterpret_cast<UnsignedBits (&)[ITEMS_PER_THREAD]>(keys);
+
+ // Twiddle bits if necessary
+ #pragma unroll
+ for (int KEY = 0; KEY < ITEMS_PER_THREAD; KEY++)
+ {
+ unsigned_keys[KEY] = KeyTraits::TwiddleIn(unsigned_keys[KEY]);
+ }
+
+ // Radix sorting passes
+ while (true)
+ {
+ int pass_bits = CUB_MIN(RADIX_BITS, end_bit - begin_bit);
+
+ // Rank the blocked keys
+ int ranks[ITEMS_PER_THREAD];
+ RankKeys(unsigned_keys, ranks, begin_bit, pass_bits, is_descending);
+ begin_bit += RADIX_BITS;
+
+ CTA_SYNC();
+
+ // Check if this is the last pass
+ if (begin_bit >= end_bit)
+ {
+ // Last pass exchanges keys through shared memory in striped arrangement
+ BlockExchangeKeys(temp_storage.exchange_keys).ScatterToStriped(keys, ranks);
+
+ // Last pass exchanges through shared memory in striped arrangement
+ ExchangeValues(values, ranks, is_keys_only, Int2Type<false>());
+
+ // Quit
+ break;
+ }
+
+ // Exchange keys through shared memory in blocked arrangement
+ BlockExchangeKeys(temp_storage.exchange_keys).ScatterToBlocked(keys, ranks);
+
+ // Exchange values through shared memory in blocked arrangement
+ ExchangeValues(values, ranks, is_keys_only, Int2Type<true>());
+
+ CTA_SYNC();
+ }
+
+ // Untwiddle bits if necessary
+ #pragma unroll
+ for (int KEY = 0; KEY < ITEMS_PER_THREAD; KEY++)
+ {
+ unsigned_keys[KEY] = KeyTraits::TwiddleOut(unsigned_keys[KEY]);
+ }
+ }
+
+#endif // DOXYGEN_SHOULD_SKIP_THIS
+
+ /// \smemstorage{BlockRadixSort}
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ /******************************************************************//**
+ * \name Collective constructors
+ *********************************************************************/
+ //@{
+
+ /**
+ * \brief Collective constructor using a private static allocation of shared memory as temporary storage.
+ */
+ __device__ __forceinline__ BlockRadixSort()
+ :
+ temp_storage(PrivateStorage()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ /**
+ * \brief Collective constructor using the specified memory allocation as temporary storage.
+ */
+ __device__ __forceinline__ BlockRadixSort(
+ TempStorage &temp_storage) ///< [in] Reference to memory allocation having layout type TempStorage
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ //@} end member group
+ /******************************************************************//**
+ * \name Sorting (blocked arrangements)
+ *********************************************************************/
+ //@{
+
+ /**
+ * \brief Performs an ascending block-wide radix sort over a [<em>blocked arrangement</em>](index.html#sec5sec3) of keys.
+ *
+ * \par
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a sort of 512 integer keys that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive keys.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_radix_sort.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockRadixSort for a 1D block of 128 threads owning 4 integer keys each
+ * typedef cub::BlockRadixSort<int, 128, 4> BlockRadixSort;
+ *
+ * // Allocate shared memory for BlockRadixSort
+ * __shared__ typename BlockRadixSort::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_keys[4];
+ * ...
+ *
+ * // Collectively sort the keys
+ * BlockRadixSort(temp_storage).Sort(thread_keys);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_keys across the block of threads is
+ * <tt>{ [0,511,1,510], [2,509,3,508], [4,507,5,506], ..., [254,257,255,256] }</tt>.
+ * The corresponding output \p thread_keys in those threads will be
+ * <tt>{ [0,1,2,3], [4,5,6,7], [8,9,10,11], ..., [508,509,510,511] }</tt>.
+ */
+ __device__ __forceinline__ void Sort(
+ KeyT (&keys)[ITEMS_PER_THREAD], ///< [in-out] Keys to sort
+ int begin_bit = 0, ///< [in] <b>[optional]</b> The beginning (least-significant) bit index needed for key comparison
+ int end_bit = sizeof(KeyT) * 8) ///< [in] <b>[optional]</b> The past-the-end (most-significant) bit index needed for key comparison
+ {
+ NullType values[ITEMS_PER_THREAD];
+
+ SortBlocked(keys, values, begin_bit, end_bit, Int2Type<false>(), Int2Type<KEYS_ONLY>());
+ }
+
+
+ /**
+ * \brief Performs an ascending block-wide radix sort across a [<em>blocked arrangement</em>](index.html#sec5sec3) of keys and values.
+ *
+ * \par
+ * - BlockRadixSort can only accommodate one associated tile of values. To "truck along"
+ * more than one tile of values, simply perform a key-value sort of the keys paired
+ * with a temporary value array that enumerates the key indices. The reordered indices
+ * can then be used as a gather-vector for exchanging other associated tile data through
+ * shared memory.
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a sort of 512 integer keys and values that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive pairs.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_radix_sort.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockRadixSort for a 1D block of 128 threads owning 4 integer keys and values each
+ * typedef cub::BlockRadixSort<int, 128, 4, int> BlockRadixSort;
+ *
+ * // Allocate shared memory for BlockRadixSort
+ * __shared__ typename BlockRadixSort::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_keys[4];
+ * int thread_values[4];
+ * ...
+ *
+ * // Collectively sort the keys and values among block threads
+ * BlockRadixSort(temp_storage).Sort(thread_keys, thread_values);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_keys across the block of threads is
+ * <tt>{ [0,511,1,510], [2,509,3,508], [4,507,5,506], ..., [254,257,255,256] }</tt>. The
+ * corresponding output \p thread_keys in those threads will be
+ * <tt>{ [0,1,2,3], [4,5,6,7], [8,9,10,11], ..., [508,509,510,511] }</tt>.
+ *
+ */
+ __device__ __forceinline__ void Sort(
+ KeyT (&keys)[ITEMS_PER_THREAD], ///< [in-out] Keys to sort
+ ValueT (&values)[ITEMS_PER_THREAD], ///< [in-out] Values to sort
+ int begin_bit = 0, ///< [in] <b>[optional]</b> The beginning (least-significant) bit index needed for key comparison
+ int end_bit = sizeof(KeyT) * 8) ///< [in] <b>[optional]</b> The past-the-end (most-significant) bit index needed for key comparison
+ {
+ SortBlocked(keys, values, begin_bit, end_bit, Int2Type<false>(), Int2Type<KEYS_ONLY>());
+ }
+
+ /**
+ * \brief Performs a descending block-wide radix sort over a [<em>blocked arrangement</em>](index.html#sec5sec3) of keys.
+ *
+ * \par
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a sort of 512 integer keys that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive keys.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_radix_sort.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockRadixSort for a 1D block of 128 threads owning 4 integer keys each
+ * typedef cub::BlockRadixSort<int, 128, 4> BlockRadixSort;
+ *
+ * // Allocate shared memory for BlockRadixSort
+ * __shared__ typename BlockRadixSort::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_keys[4];
+ * ...
+ *
+ * // Collectively sort the keys
+ * BlockRadixSort(temp_storage).Sort(thread_keys);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_keys across the block of threads is
+ * <tt>{ [0,511,1,510], [2,509,3,508], [4,507,5,506], ..., [254,257,255,256] }</tt>.
+ * The corresponding output \p thread_keys in those threads will be
+ * <tt>{ [511,510,509,508], [11,10,9,8], [7,6,5,4], ..., [3,2,1,0] }</tt>.
+ */
+ __device__ __forceinline__ void SortDescending(
+ KeyT (&keys)[ITEMS_PER_THREAD], ///< [in-out] Keys to sort
+ int begin_bit = 0, ///< [in] <b>[optional]</b> The beginning (least-significant) bit index needed for key comparison
+ int end_bit = sizeof(KeyT) * 8) ///< [in] <b>[optional]</b> The past-the-end (most-significant) bit index needed for key comparison
+ {
+ NullType values[ITEMS_PER_THREAD];
+
+ SortBlocked(keys, values, begin_bit, end_bit, Int2Type<true>(), Int2Type<KEYS_ONLY>());
+ }
+
+
+ /**
+ * \brief Performs a descending block-wide radix sort across a [<em>blocked arrangement</em>](index.html#sec5sec3) of keys and values.
+ *
+ * \par
+ * - BlockRadixSort can only accommodate one associated tile of values. To "truck along"
+ * more than one tile of values, simply perform a key-value sort of the keys paired
+ * with a temporary value array that enumerates the key indices. The reordered indices
+ * can then be used as a gather-vector for exchanging other associated tile data through
+ * shared memory.
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a sort of 512 integer keys and values that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive pairs.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_radix_sort.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockRadixSort for a 1D block of 128 threads owning 4 integer keys and values each
+ * typedef cub::BlockRadixSort<int, 128, 4, int> BlockRadixSort;
+ *
+ * // Allocate shared memory for BlockRadixSort
+ * __shared__ typename BlockRadixSort::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_keys[4];
+ * int thread_values[4];
+ * ...
+ *
+ * // Collectively sort the keys and values among block threads
+ * BlockRadixSort(temp_storage).Sort(thread_keys, thread_values);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_keys across the block of threads is
+ * <tt>{ [0,511,1,510], [2,509,3,508], [4,507,5,506], ..., [254,257,255,256] }</tt>. The
+ * corresponding output \p thread_keys in those threads will be
+ * <tt>{ [511,510,509,508], [11,10,9,8], [7,6,5,4], ..., [3,2,1,0] }</tt>.
+ *
+ */
+ __device__ __forceinline__ void SortDescending(
+ KeyT (&keys)[ITEMS_PER_THREAD], ///< [in-out] Keys to sort
+ ValueT (&values)[ITEMS_PER_THREAD], ///< [in-out] Values to sort
+ int begin_bit = 0, ///< [in] <b>[optional]</b> The beginning (least-significant) bit index needed for key comparison
+ int end_bit = sizeof(KeyT) * 8) ///< [in] <b>[optional]</b> The past-the-end (most-significant) bit index needed for key comparison
+ {
+ SortBlocked(keys, values, begin_bit, end_bit, Int2Type<true>(), Int2Type<KEYS_ONLY>());
+ }
+
+
+ //@} end member group
+ /******************************************************************//**
+ * \name Sorting (blocked arrangement -> striped arrangement)
+ *********************************************************************/
+ //@{
+
+
+ /**
+ * \brief Performs an ascending radix sort across a [<em>blocked arrangement</em>](index.html#sec5sec3) of keys, leaving them in a [<em>striped arrangement</em>](index.html#sec5sec3).
+ *
+ * \par
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a sort of 512 integer keys that
+ * are initially partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive keys. The final partitioning is striped.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_radix_sort.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockRadixSort for a 1D block of 128 threads owning 4 integer keys each
+ * typedef cub::BlockRadixSort<int, 128, 4> BlockRadixSort;
+ *
+ * // Allocate shared memory for BlockRadixSort
+ * __shared__ typename BlockRadixSort::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_keys[4];
+ * ...
+ *
+ * // Collectively sort the keys
+ * BlockRadixSort(temp_storage).SortBlockedToStriped(thread_keys);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_keys across the block of threads is
+ * <tt>{ [0,511,1,510], [2,509,3,508], [4,507,5,506], ..., [254,257,255,256] }</tt>. The
+ * corresponding output \p thread_keys in those threads will be
+ * <tt>{ [0,128,256,384], [1,129,257,385], [2,130,258,386], ..., [127,255,383,511] }</tt>.
+ *
+ */
+ __device__ __forceinline__ void SortBlockedToStriped(
+ KeyT (&keys)[ITEMS_PER_THREAD], ///< [in-out] Keys to sort
+ int begin_bit = 0, ///< [in] <b>[optional]</b> The beginning (least-significant) bit index needed for key comparison
+ int end_bit = sizeof(KeyT) * 8) ///< [in] <b>[optional]</b> The past-the-end (most-significant) bit index needed for key comparison
+ {
+ NullType values[ITEMS_PER_THREAD];
+
+ SortBlockedToStriped(keys, values, begin_bit, end_bit, Int2Type<false>(), Int2Type<KEYS_ONLY>());
+ }
+
+
+ /**
+ * \brief Performs an ascending radix sort across a [<em>blocked arrangement</em>](index.html#sec5sec3) of keys and values, leaving them in a [<em>striped arrangement</em>](index.html#sec5sec3).
+ *
+ * \par
+ * - BlockRadixSort can only accommodate one associated tile of values. To "truck along"
+ * more than one tile of values, simply perform a key-value sort of the keys paired
+ * with a temporary value array that enumerates the key indices. The reordered indices
+ * can then be used as a gather-vector for exchanging other associated tile data through
+ * shared memory.
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a sort of 512 integer keys and values that
+ * are initially partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive pairs. The final partitioning is striped.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_radix_sort.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockRadixSort for a 1D block of 128 threads owning 4 integer keys and values each
+ * typedef cub::BlockRadixSort<int, 128, 4, int> BlockRadixSort;
+ *
+ * // Allocate shared memory for BlockRadixSort
+ * __shared__ typename BlockRadixSort::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_keys[4];
+ * int thread_values[4];
+ * ...
+ *
+ * // Collectively sort the keys and values among block threads
+ * BlockRadixSort(temp_storage).SortBlockedToStriped(thread_keys, thread_values);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_keys across the block of threads is
+ * <tt>{ [0,511,1,510], [2,509,3,508], [4,507,5,506], ..., [254,257,255,256] }</tt>. The
+ * corresponding output \p thread_keys in those threads will be
+ * <tt>{ [0,128,256,384], [1,129,257,385], [2,130,258,386], ..., [127,255,383,511] }</tt>.
+ *
+ */
+ __device__ __forceinline__ void SortBlockedToStriped(
+ KeyT (&keys)[ITEMS_PER_THREAD], ///< [in-out] Keys to sort
+ ValueT (&values)[ITEMS_PER_THREAD], ///< [in-out] Values to sort
+ int begin_bit = 0, ///< [in] <b>[optional]</b> The beginning (least-significant) bit index needed for key comparison
+ int end_bit = sizeof(KeyT) * 8) ///< [in] <b>[optional]</b> The past-the-end (most-significant) bit index needed for key comparison
+ {
+ SortBlockedToStriped(keys, values, begin_bit, end_bit, Int2Type<false>(), Int2Type<KEYS_ONLY>());
+ }
+
+
+ /**
+ * \brief Performs a descending radix sort across a [<em>blocked arrangement</em>](index.html#sec5sec3) of keys, leaving them in a [<em>striped arrangement</em>](index.html#sec5sec3).
+ *
+ * \par
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a sort of 512 integer keys that
+ * are initially partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive keys. The final partitioning is striped.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_radix_sort.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockRadixSort for a 1D block of 128 threads owning 4 integer keys each
+ * typedef cub::BlockRadixSort<int, 128, 4> BlockRadixSort;
+ *
+ * // Allocate shared memory for BlockRadixSort
+ * __shared__ typename BlockRadixSort::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_keys[4];
+ * ...
+ *
+ * // Collectively sort the keys
+ * BlockRadixSort(temp_storage).SortBlockedToStriped(thread_keys);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_keys across the block of threads is
+ * <tt>{ [0,511,1,510], [2,509,3,508], [4,507,5,506], ..., [254,257,255,256] }</tt>. The
+ * corresponding output \p thread_keys in those threads will be
+ * <tt>{ [511,383,255,127], [386,258,130,2], [385,257,128,1], ..., [384,256,128,0] }</tt>.
+ *
+ */
+ __device__ __forceinline__ void SortDescendingBlockedToStriped(
+ KeyT (&keys)[ITEMS_PER_THREAD], ///< [in-out] Keys to sort
+ int begin_bit = 0, ///< [in] <b>[optional]</b> The beginning (least-significant) bit index needed for key comparison
+ int end_bit = sizeof(KeyT) * 8) ///< [in] <b>[optional]</b> The past-the-end (most-significant) bit index needed for key comparison
+ {
+ NullType values[ITEMS_PER_THREAD];
+
+ SortBlockedToStriped(keys, values, begin_bit, end_bit, Int2Type<true>(), Int2Type<KEYS_ONLY>());
+ }
+
+
+ /**
+ * \brief Performs a descending radix sort across a [<em>blocked arrangement</em>](index.html#sec5sec3) of keys and values, leaving them in a [<em>striped arrangement</em>](index.html#sec5sec3).
+ *
+ * \par
+ * - BlockRadixSort can only accommodate one associated tile of values. To "truck along"
+ * more than one tile of values, simply perform a key-value sort of the keys paired
+ * with a temporary value array that enumerates the key indices. The reordered indices
+ * can then be used as a gather-vector for exchanging other associated tile data through
+ * shared memory.
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a sort of 512 integer keys and values that
+ * are initially partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive pairs. The final partitioning is striped.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_radix_sort.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockRadixSort for a 1D block of 128 threads owning 4 integer keys and values each
+ * typedef cub::BlockRadixSort<int, 128, 4, int> BlockRadixSort;
+ *
+ * // Allocate shared memory for BlockRadixSort
+ * __shared__ typename BlockRadixSort::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_keys[4];
+ * int thread_values[4];
+ * ...
+ *
+ * // Collectively sort the keys and values among block threads
+ * BlockRadixSort(temp_storage).SortBlockedToStriped(thread_keys, thread_values);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_keys across the block of threads is
+ * <tt>{ [0,511,1,510], [2,509,3,508], [4,507,5,506], ..., [254,257,255,256] }</tt>. The
+ * corresponding output \p thread_keys in those threads will be
+ * <tt>{ [511,383,255,127], [386,258,130,2], [385,257,128,1], ..., [384,256,128,0] }</tt>.
+ *
+ */
+ __device__ __forceinline__ void SortDescendingBlockedToStriped(
+ KeyT (&keys)[ITEMS_PER_THREAD], ///< [in-out] Keys to sort
+ ValueT (&values)[ITEMS_PER_THREAD], ///< [in-out] Values to sort
+ int begin_bit = 0, ///< [in] <b>[optional]</b> The beginning (least-significant) bit index needed for key comparison
+ int end_bit = sizeof(KeyT) * 8) ///< [in] <b>[optional]</b> The past-the-end (most-significant) bit index needed for key comparison
+ {
+ SortBlockedToStriped(keys, values, begin_bit, end_bit, Int2Type<true>(), Int2Type<KEYS_ONLY>());
+ }
+
+
+ //@} end member group
+
+};
+
+/**
+ * \example example_block_radix_sort.cu
+ */
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_raking_layout.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_raking_layout.cuh
new file mode 100644
index 0000000..3500616
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_raking_layout.cuh
@@ -0,0 +1,152 @@
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-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 TORT
+ * (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
+ * cub::BlockRakingLayout provides a conflict-free shared memory layout abstraction for warp-raking across thread block data.
+ */
+
+
+#pragma once
+
+#include "../util_macro.cuh"
+#include "../util_arch.cuh"
+#include "../util_type.cuh"
+#include "../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+/**
+ * \brief BlockRakingLayout provides a conflict-free shared memory layout abstraction for 1D raking across thread block data. ![](raking.png)
+ * \ingroup BlockModule
+ *
+ * \par Overview
+ * This type facilitates a shared memory usage pattern where a block of CUDA
+ * threads places elements into shared memory and then reduces the active
+ * parallelism to one "raking" warp of threads for serially aggregating consecutive
+ * sequences of shared items. Padding is inserted to eliminate bank conflicts
+ * (for most data types).
+ *
+ * \tparam T The data type to be exchanged.
+ * \tparam BLOCK_THREADS The thread block size in threads.
+ * \tparam PTX_ARCH <b>[optional]</b> \ptxversion
+ */
+template <
+ typename T,
+ int BLOCK_THREADS,
+ int PTX_ARCH = CUB_PTX_ARCH>
+struct BlockRakingLayout
+{
+ //---------------------------------------------------------------------
+ // Constants and type definitions
+ //---------------------------------------------------------------------
+
+ enum
+ {
+ /// The total number of elements that need to be cooperatively reduced
+ SHARED_ELEMENTS = BLOCK_THREADS,
+
+ /// Maximum number of warp-synchronous raking threads
+ MAX_RAKING_THREADS = CUB_MIN(BLOCK_THREADS, CUB_WARP_THREADS(PTX_ARCH)),
+
+ /// Number of raking elements per warp-synchronous raking thread (rounded up)
+ SEGMENT_LENGTH = (SHARED_ELEMENTS + MAX_RAKING_THREADS - 1) / MAX_RAKING_THREADS,
+
+ /// Never use a raking thread that will have no valid data (e.g., when BLOCK_THREADS is 62 and SEGMENT_LENGTH is 2, we should only use 31 raking threads)
+ RAKING_THREADS = (SHARED_ELEMENTS + SEGMENT_LENGTH - 1) / SEGMENT_LENGTH,
+
+ /// Whether we will have bank conflicts (technically we should find out if the GCD is > 1)
+ HAS_CONFLICTS = (CUB_SMEM_BANKS(PTX_ARCH) % SEGMENT_LENGTH == 0),
+
+ /// Degree of bank conflicts (e.g., 4-way)
+ CONFLICT_DEGREE = (HAS_CONFLICTS) ?
+ (MAX_RAKING_THREADS * SEGMENT_LENGTH) / CUB_SMEM_BANKS(PTX_ARCH) :
+ 1,
+
+ /// Pad each segment length with one element if segment length is not relatively prime to warp size and can't be optimized as a vector load
+ USE_SEGMENT_PADDING = ((SEGMENT_LENGTH & 1) == 0) && (SEGMENT_LENGTH > 2),
+
+ /// Total number of elements in the raking grid
+ GRID_ELEMENTS = RAKING_THREADS * (SEGMENT_LENGTH + USE_SEGMENT_PADDING),
+
+ /// Whether or not we need bounds checking during raking (the number of reduction elements is not a multiple of the number of raking threads)
+ UNGUARDED = (SHARED_ELEMENTS % RAKING_THREADS == 0),
+ };
+
+
+ /**
+ * \brief Shared memory storage type
+ */
+ struct __align__(16) _TempStorage
+ {
+ T buff[BlockRakingLayout::GRID_ELEMENTS];
+ };
+
+ /// Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ /**
+ * \brief Returns the location for the calling thread to place data into the grid
+ */
+ static __device__ __forceinline__ T* PlacementPtr(
+ TempStorage &temp_storage,
+ unsigned int linear_tid)
+ {
+ // Offset for partial
+ unsigned int offset = linear_tid;
+
+ // Add in one padding element for every segment
+ if (USE_SEGMENT_PADDING > 0)
+ {
+ offset += offset / SEGMENT_LENGTH;
+ }
+
+ // Incorporating a block of padding partials every shared memory segment
+ return temp_storage.Alias().buff + offset;
+ }
+
+
+ /**
+ * \brief Returns the location for the calling thread to begin sequential raking
+ */
+ static __device__ __forceinline__ T* RakingPtr(
+ TempStorage &temp_storage,
+ unsigned int linear_tid)
+ {
+ return temp_storage.Alias().buff + (linear_tid * (SEGMENT_LENGTH + USE_SEGMENT_PADDING));
+ }
+};
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_reduce.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_reduce.cuh
new file mode 100644
index 0000000..261f2ea
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_reduce.cuh
@@ -0,0 +1,607 @@
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-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 TORT
+ * (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
+ * The cub::BlockReduce class provides [<em>collective</em>](index.html#sec0) methods for computing a parallel reduction of items partitioned across a CUDA thread block.
+ */
+
+#pragma once
+
+#include "specializations/block_reduce_raking.cuh"
+#include "specializations/block_reduce_raking_commutative_only.cuh"
+#include "specializations/block_reduce_warp_reductions.cuh"
+#include "../util_ptx.cuh"
+#include "../util_type.cuh"
+#include "../thread/thread_operators.cuh"
+#include "../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+
+/******************************************************************************
+ * Algorithmic variants
+ ******************************************************************************/
+
+/**
+ * BlockReduceAlgorithm enumerates alternative algorithms for parallel
+ * reduction across a CUDA thread block.
+ */
+enum BlockReduceAlgorithm
+{
+
+ /**
+ * \par Overview
+ * An efficient "raking" reduction algorithm that only supports commutative
+ * reduction operators (true for most operations, e.g., addition).
+ *
+ * \par
+ * Execution is comprised of three phases:
+ * -# Upsweep sequential reduction in registers (if threads contribute more
+ * than one input each). Threads in warps other than the first warp place
+ * their partial reductions into shared memory.
+ * -# Upsweep sequential reduction in shared memory. Threads within the first
+ * warp continue to accumulate by raking across segments of shared partial reductions
+ * -# A warp-synchronous Kogge-Stone style reduction within the raking warp.
+ *
+ * \par
+ * \image html block_reduce.png
+ * <div class="centercaption">\p BLOCK_REDUCE_RAKING data flow for a hypothetical 16-thread thread block and 4-thread raking warp.</div>
+ *
+ * \par Performance Considerations
+ * - This variant performs less communication than BLOCK_REDUCE_RAKING_NON_COMMUTATIVE
+ * and is preferable when the reduction operator is commutative. This variant
+ * applies fewer reduction operators than BLOCK_REDUCE_WARP_REDUCTIONS, and can provide higher overall
+ * throughput across the GPU when suitably occupied. However, turn-around latency may be
+ * higher than to BLOCK_REDUCE_WARP_REDUCTIONS and thus less-desirable
+ * when the GPU is under-occupied.
+ */
+ BLOCK_REDUCE_RAKING_COMMUTATIVE_ONLY,
+
+
+ /**
+ * \par Overview
+ * An efficient "raking" reduction algorithm that supports commutative
+ * (e.g., addition) and non-commutative (e.g., string concatenation) reduction
+ * operators. \blocked.
+ *
+ * \par
+ * Execution is comprised of three phases:
+ * -# Upsweep sequential reduction in registers (if threads contribute more
+ * than one input each). Each thread then places the partial reduction
+ * of its item(s) into shared memory.
+ * -# Upsweep sequential reduction in shared memory. Threads within a
+ * single warp rake across segments of shared partial reductions.
+ * -# A warp-synchronous Kogge-Stone style reduction within the raking warp.
+ *
+ * \par
+ * \image html block_reduce.png
+ * <div class="centercaption">\p BLOCK_REDUCE_RAKING data flow for a hypothetical 16-thread thread block and 4-thread raking warp.</div>
+ *
+ * \par Performance Considerations
+ * - This variant performs more communication than BLOCK_REDUCE_RAKING
+ * and is only preferable when the reduction operator is non-commutative. This variant
+ * applies fewer reduction operators than BLOCK_REDUCE_WARP_REDUCTIONS, and can provide higher overall
+ * throughput across the GPU when suitably occupied. However, turn-around latency may be
+ * higher than to BLOCK_REDUCE_WARP_REDUCTIONS and thus less-desirable
+ * when the GPU is under-occupied.
+ */
+ BLOCK_REDUCE_RAKING,
+
+
+ /**
+ * \par Overview
+ * A quick "tiled warp-reductions" reduction algorithm that supports commutative
+ * (e.g., addition) and non-commutative (e.g., string concatenation) reduction
+ * operators.
+ *
+ * \par
+ * Execution is comprised of four phases:
+ * -# Upsweep sequential reduction in registers (if threads contribute more
+ * than one input each). Each thread then places the partial reduction
+ * of its item(s) into shared memory.
+ * -# Compute a shallow, but inefficient warp-synchronous Kogge-Stone style
+ * reduction within each warp.
+ * -# A propagation phase where the warp reduction outputs in each warp are
+ * updated with the aggregate from each preceding warp.
+ *
+ * \par
+ * \image html block_scan_warpscans.png
+ * <div class="centercaption">\p BLOCK_REDUCE_WARP_REDUCTIONS data flow for a hypothetical 16-thread thread block and 4-thread raking warp.</div>
+ *
+ * \par Performance Considerations
+ * - This variant applies more reduction operators than BLOCK_REDUCE_RAKING
+ * or BLOCK_REDUCE_RAKING_NON_COMMUTATIVE, which may result in lower overall
+ * throughput across the GPU. However turn-around latency may be lower and
+ * thus useful when the GPU is under-occupied.
+ */
+ BLOCK_REDUCE_WARP_REDUCTIONS,
+};
+
+
+/******************************************************************************
+ * Block reduce
+ ******************************************************************************/
+
+/**
+ * \brief The BlockReduce class provides [<em>collective</em>](index.html#sec0) methods for computing a parallel reduction of items partitioned across a CUDA thread block. ![](reduce_logo.png)
+ * \ingroup BlockModule
+ *
+ * \tparam T Data type being reduced
+ * \tparam BLOCK_DIM_X The thread block length in threads along the X dimension
+ * \tparam ALGORITHM <b>[optional]</b> cub::BlockReduceAlgorithm enumerator specifying the underlying algorithm to use (default: cub::BLOCK_REDUCE_WARP_REDUCTIONS)
+ * \tparam BLOCK_DIM_Y <b>[optional]</b> The thread block length in threads along the Y dimension (default: 1)
+ * \tparam BLOCK_DIM_Z <b>[optional]</b> The thread block length in threads along the Z dimension (default: 1)
+ * \tparam PTX_ARCH <b>[optional]</b> \ptxversion
+ *
+ * \par Overview
+ * - A <a href="http://en.wikipedia.org/wiki/Reduce_(higher-order_function)"><em>reduction</em></a> (or <em>fold</em>)
+ * uses a binary combining operator to compute a single aggregate from a list of input elements.
+ * - \rowmajor
+ * - BlockReduce can be optionally specialized by algorithm to accommodate different latency/throughput workload profiles:
+ * -# <b>cub::BLOCK_REDUCE_RAKING_COMMUTATIVE_ONLY</b>. An efficient "raking" reduction algorithm that only supports commutative reduction operators. [More...](\ref cub::BlockReduceAlgorithm)
+ * -# <b>cub::BLOCK_REDUCE_RAKING</b>. An efficient "raking" reduction algorithm that supports commutative and non-commutative reduction operators. [More...](\ref cub::BlockReduceAlgorithm)
+ * -# <b>cub::BLOCK_REDUCE_WARP_REDUCTIONS</b>. A quick "tiled warp-reductions" reduction algorithm that supports commutative and non-commutative reduction operators. [More...](\ref cub::BlockReduceAlgorithm)
+ *
+ * \par Performance Considerations
+ * - \granularity
+ * - Very efficient (only one synchronization barrier).
+ * - Incurs zero bank conflicts for most types
+ * - Computation is slightly more efficient (i.e., having lower instruction overhead) for:
+ * - Summation (<b><em>vs.</em></b> generic reduction)
+ * - \p BLOCK_THREADS is a multiple of the architecture's warp size
+ * - Every thread has a valid input (i.e., full <b><em>vs.</em></b> partial-tiles)
+ * - See cub::BlockReduceAlgorithm for performance details regarding algorithmic alternatives
+ *
+ * \par A Simple Example
+ * \blockcollective{BlockReduce}
+ * \par
+ * The code snippet below illustrates a sum reduction of 512 integer items that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_reduce.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockReduce for a 1D block of 128 threads on type int
+ * typedef cub::BlockReduce<int, 128> BlockReduce;
+ *
+ * // Allocate shared memory for BlockReduce
+ * __shared__ typename BlockReduce::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Compute the block-wide sum for thread0
+ * int aggregate = BlockReduce(temp_storage).Sum(thread_data);
+ *
+ * \endcode
+ *
+ */
+template <
+ typename T,
+ int BLOCK_DIM_X,
+ BlockReduceAlgorithm ALGORITHM = BLOCK_REDUCE_WARP_REDUCTIONS,
+ int BLOCK_DIM_Y = 1,
+ int BLOCK_DIM_Z = 1,
+ int PTX_ARCH = CUB_PTX_ARCH>
+class BlockReduce
+{
+private:
+
+ /******************************************************************************
+ * Constants and type definitions
+ ******************************************************************************/
+
+ /// Constants
+ enum
+ {
+ /// The thread block size in threads
+ BLOCK_THREADS = BLOCK_DIM_X * BLOCK_DIM_Y * BLOCK_DIM_Z,
+ };
+
+ typedef BlockReduceWarpReductions<T, BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z, PTX_ARCH> WarpReductions;
+ typedef BlockReduceRakingCommutativeOnly<T, BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z, PTX_ARCH> RakingCommutativeOnly;
+ typedef BlockReduceRaking<T, BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z, PTX_ARCH> Raking;
+
+ /// Internal specialization type
+ typedef typename If<(ALGORITHM == BLOCK_REDUCE_WARP_REDUCTIONS),
+ WarpReductions,
+ typename If<(ALGORITHM == BLOCK_REDUCE_RAKING_COMMUTATIVE_ONLY),
+ RakingCommutativeOnly,
+ Raking>::Type>::Type InternalBlockReduce; // BlockReduceRaking
+
+ /// Shared memory storage layout type for BlockReduce
+ typedef typename InternalBlockReduce::TempStorage _TempStorage;
+
+
+ /******************************************************************************
+ * Utility methods
+ ******************************************************************************/
+
+ /// Internal storage allocator
+ __device__ __forceinline__ _TempStorage& PrivateStorage()
+ {
+ __shared__ _TempStorage private_storage;
+ return private_storage;
+ }
+
+
+ /******************************************************************************
+ * Thread fields
+ ******************************************************************************/
+
+ /// Shared storage reference
+ _TempStorage &temp_storage;
+
+ /// Linear thread-id
+ unsigned int linear_tid;
+
+
+public:
+
+ /// \smemstorage{BlockReduce}
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ /******************************************************************//**
+ * \name Collective constructors
+ *********************************************************************/
+ //@{
+
+ /**
+ * \brief Collective constructor using a private static allocation of shared memory as temporary storage.
+ */
+ __device__ __forceinline__ BlockReduce()
+ :
+ temp_storage(PrivateStorage()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ /**
+ * \brief Collective constructor using the specified memory allocation as temporary storage.
+ */
+ __device__ __forceinline__ BlockReduce(
+ TempStorage &temp_storage) ///< [in] Reference to memory allocation having layout type TempStorage
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ //@} end member group
+ /******************************************************************//**
+ * \name Generic reductions
+ *********************************************************************/
+ //@{
+
+
+ /**
+ * \brief Computes a block-wide reduction for thread<sub>0</sub> using the specified binary reduction functor. Each thread contributes one input element.
+ *
+ * \par
+ * - The return value is undefined in threads other than thread<sub>0</sub>.
+ * - \rowmajor
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a max reduction of 128 integer items that
+ * are partitioned across 128 threads.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_reduce.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockReduce for a 1D block of 128 threads on type int
+ * typedef cub::BlockReduce<int, 128> BlockReduce;
+ *
+ * // Allocate shared memory for BlockReduce
+ * __shared__ typename BlockReduce::TempStorage temp_storage;
+ *
+ * // Each thread obtains an input item
+ * int thread_data;
+ * ...
+ *
+ * // Compute the block-wide max for thread0
+ * int aggregate = BlockReduce(temp_storage).Reduce(thread_data, cub::Max());
+ *
+ * \endcode
+ *
+ * \tparam ReductionOp <b>[inferred]</b> Binary reduction functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ */
+ template <typename ReductionOp>
+ __device__ __forceinline__ T Reduce(
+ T input, ///< [in] Calling thread's input
+ ReductionOp reduction_op) ///< [in] Binary reduction functor
+ {
+ return InternalBlockReduce(temp_storage).template Reduce<true>(input, BLOCK_THREADS, reduction_op);
+ }
+
+
+ /**
+ * \brief Computes a block-wide reduction for thread<sub>0</sub> using the specified binary reduction functor. Each thread contributes an array of consecutive input elements.
+ *
+ * \par
+ * - The return value is undefined in threads other than thread<sub>0</sub>.
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a max reduction of 512 integer items that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_reduce.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockReduce for a 1D block of 128 threads on type int
+ * typedef cub::BlockReduce<int, 128> BlockReduce;
+ *
+ * // Allocate shared memory for BlockReduce
+ * __shared__ typename BlockReduce::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Compute the block-wide max for thread0
+ * int aggregate = BlockReduce(temp_storage).Reduce(thread_data, cub::Max());
+ *
+ * \endcode
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam ReductionOp <b>[inferred]</b> Binary reduction functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ */
+ template <
+ int ITEMS_PER_THREAD,
+ typename ReductionOp>
+ __device__ __forceinline__ T Reduce(
+ T (&inputs)[ITEMS_PER_THREAD], ///< [in] Calling thread's input segment
+ ReductionOp reduction_op) ///< [in] Binary reduction functor
+ {
+ // Reduce partials
+ T partial = internal::ThreadReduce(inputs, reduction_op);
+ return Reduce(partial, reduction_op);
+ }
+
+
+ /**
+ * \brief Computes a block-wide reduction for thread<sub>0</sub> using the specified binary reduction functor. The first \p num_valid threads each contribute one input element.
+ *
+ * \par
+ * - The return value is undefined in threads other than thread<sub>0</sub>.
+ * - \rowmajor
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a max reduction of a partially-full tile of integer items that
+ * are partitioned across 128 threads.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_reduce.cuh>
+ *
+ * __global__ void ExampleKernel(int num_valid, ...)
+ * {
+ * // Specialize BlockReduce for a 1D block of 128 threads on type int
+ * typedef cub::BlockReduce<int, 128> BlockReduce;
+ *
+ * // Allocate shared memory for BlockReduce
+ * __shared__ typename BlockReduce::TempStorage temp_storage;
+ *
+ * // Each thread obtains an input item
+ * int thread_data;
+ * if (threadIdx.x < num_valid) thread_data = ...
+ *
+ * // Compute the block-wide max for thread0
+ * int aggregate = BlockReduce(temp_storage).Reduce(thread_data, cub::Max(), num_valid);
+ *
+ * \endcode
+ *
+ * \tparam ReductionOp <b>[inferred]</b> Binary reduction functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ */
+ template <typename ReductionOp>
+ __device__ __forceinline__ T Reduce(
+ T input, ///< [in] Calling thread's input
+ ReductionOp reduction_op, ///< [in] Binary reduction functor
+ int num_valid) ///< [in] Number of threads containing valid elements (may be less than BLOCK_THREADS)
+ {
+ // Determine if we scan skip bounds checking
+ if (num_valid >= BLOCK_THREADS)
+ {
+ return InternalBlockReduce(temp_storage).template Reduce<true>(input, num_valid, reduction_op);
+ }
+ else
+ {
+ return InternalBlockReduce(temp_storage).template Reduce<false>(input, num_valid, reduction_op);
+ }
+ }
+
+
+ //@} end member group
+ /******************************************************************//**
+ * \name Summation reductions
+ *********************************************************************/
+ //@{
+
+
+ /**
+ * \brief Computes a block-wide reduction for thread<sub>0</sub> using addition (+) as the reduction operator. Each thread contributes one input element.
+ *
+ * \par
+ * - The return value is undefined in threads other than thread<sub>0</sub>.
+ * - \rowmajor
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a sum reduction of 128 integer items that
+ * are partitioned across 128 threads.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_reduce.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockReduce for a 1D block of 128 threads on type int
+ * typedef cub::BlockReduce<int, 128> BlockReduce;
+ *
+ * // Allocate shared memory for BlockReduce
+ * __shared__ typename BlockReduce::TempStorage temp_storage;
+ *
+ * // Each thread obtains an input item
+ * int thread_data;
+ * ...
+ *
+ * // Compute the block-wide sum for thread0
+ * int aggregate = BlockReduce(temp_storage).Sum(thread_data);
+ *
+ * \endcode
+ *
+ */
+ __device__ __forceinline__ T Sum(
+ T input) ///< [in] Calling thread's input
+ {
+ return InternalBlockReduce(temp_storage).template Sum<true>(input, BLOCK_THREADS);
+ }
+
+ /**
+ * \brief Computes a block-wide reduction for thread<sub>0</sub> using addition (+) as the reduction operator. Each thread contributes an array of consecutive input elements.
+ *
+ * \par
+ * - The return value is undefined in threads other than thread<sub>0</sub>.
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a sum reduction of 512 integer items that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_reduce.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockReduce for a 1D block of 128 threads on type int
+ * typedef cub::BlockReduce<int, 128> BlockReduce;
+ *
+ * // Allocate shared memory for BlockReduce
+ * __shared__ typename BlockReduce::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Compute the block-wide sum for thread0
+ * int aggregate = BlockReduce(temp_storage).Sum(thread_data);
+ *
+ * \endcode
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ */
+ template <int ITEMS_PER_THREAD>
+ __device__ __forceinline__ T Sum(
+ T (&inputs)[ITEMS_PER_THREAD]) ///< [in] Calling thread's input segment
+ {
+ // Reduce partials
+ T partial = internal::ThreadReduce(inputs, cub::Sum());
+ return Sum(partial);
+ }
+
+
+ /**
+ * \brief Computes a block-wide reduction for thread<sub>0</sub> using addition (+) as the reduction operator. The first \p num_valid threads each contribute one input element.
+ *
+ * \par
+ * - The return value is undefined in threads other than thread<sub>0</sub>.
+ * - \rowmajor
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a sum reduction of a partially-full tile of integer items that
+ * are partitioned across 128 threads.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_reduce.cuh>
+ *
+ * __global__ void ExampleKernel(int num_valid, ...)
+ * {
+ * // Specialize BlockReduce for a 1D block of 128 threads on type int
+ * typedef cub::BlockReduce<int, 128> BlockReduce;
+ *
+ * // Allocate shared memory for BlockReduce
+ * __shared__ typename BlockReduce::TempStorage temp_storage;
+ *
+ * // Each thread obtains an input item (up to num_items)
+ * int thread_data;
+ * if (threadIdx.x < num_valid)
+ * thread_data = ...
+ *
+ * // Compute the block-wide sum for thread0
+ * int aggregate = BlockReduce(temp_storage).Sum(thread_data, num_valid);
+ *
+ * \endcode
+ *
+ */
+ __device__ __forceinline__ T Sum(
+ T input, ///< [in] Calling thread's input
+ int num_valid) ///< [in] Number of threads containing valid elements (may be less than BLOCK_THREADS)
+ {
+ // Determine if we scan skip bounds checking
+ if (num_valid >= BLOCK_THREADS)
+ {
+ return InternalBlockReduce(temp_storage).template Sum<true>(input, num_valid);
+ }
+ else
+ {
+ return InternalBlockReduce(temp_storage).template Sum<false>(input, num_valid);
+ }
+ }
+
+
+ //@} end member group
+};
+
+/**
+ * \example example_block_reduce.cu
+ */
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_scan.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_scan.cuh
new file mode 100644
index 0000000..27ea7ed
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_scan.cuh
@@ -0,0 +1,2126 @@
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-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 TORT
+ * (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
+ * The cub::BlockScan class provides [<em>collective</em>](index.html#sec0) methods for computing a parallel prefix sum/scan of items partitioned across a CUDA thread block.
+ */
+
+#pragma once
+
+#include "specializations/block_scan_raking.cuh"
+#include "specializations/block_scan_warp_scans.cuh"
+#include "../util_arch.cuh"
+#include "../util_type.cuh"
+#include "../util_ptx.cuh"
+#include "../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+/******************************************************************************
+ * Algorithmic variants
+ ******************************************************************************/
+
+/**
+ * \brief BlockScanAlgorithm enumerates alternative algorithms for cub::BlockScan to compute a parallel prefix scan across a CUDA thread block.
+ */
+enum BlockScanAlgorithm
+{
+
+ /**
+ * \par Overview
+ * An efficient "raking reduce-then-scan" prefix scan algorithm. Execution is comprised of five phases:
+ * -# Upsweep sequential reduction in registers (if threads contribute more than one input each). Each thread then places the partial reduction of its item(s) into shared memory.
+ * -# Upsweep sequential reduction in shared memory. Threads within a single warp rake across segments of shared partial reductions.
+ * -# A warp-synchronous Kogge-Stone style exclusive scan within the raking warp.
+ * -# Downsweep sequential exclusive scan in shared memory. Threads within a single warp rake across segments of shared partial reductions, seeded with the warp-scan output.
+ * -# Downsweep sequential scan in registers (if threads contribute more than one input), seeded with the raking scan output.
+ *
+ * \par
+ * \image html block_scan_raking.png
+ * <div class="centercaption">\p BLOCK_SCAN_RAKING data flow for a hypothetical 16-thread thread block and 4-thread raking warp.</div>
+ *
+ * \par Performance Considerations
+ * - Although this variant may suffer longer turnaround latencies when the
+ * GPU is under-occupied, it can often provide higher overall throughput
+ * across the GPU when suitably occupied.
+ */
+ BLOCK_SCAN_RAKING,
+
+
+ /**
+ * \par Overview
+ * Similar to cub::BLOCK_SCAN_RAKING, but with fewer shared memory reads at
+ * the expense of higher register pressure. Raking threads preserve their
+ * "upsweep" segment of values in registers while performing warp-synchronous
+ * scan, allowing the "downsweep" not to re-read them from shared memory.
+ */
+ BLOCK_SCAN_RAKING_MEMOIZE,
+
+
+ /**
+ * \par Overview
+ * A quick "tiled warpscans" prefix scan algorithm. Execution is comprised of four phases:
+ * -# Upsweep sequential reduction in registers (if threads contribute more than one input each). Each thread then places the partial reduction of its item(s) into shared memory.
+ * -# Compute a shallow, but inefficient warp-synchronous Kogge-Stone style scan within each warp.
+ * -# A propagation phase where the warp scan outputs in each warp are updated with the aggregate from each preceding warp.
+ * -# Downsweep sequential scan in registers (if threads contribute more than one input), seeded with the raking scan output.
+ *
+ * \par
+ * \image html block_scan_warpscans.png
+ * <div class="centercaption">\p BLOCK_SCAN_WARP_SCANS data flow for a hypothetical 16-thread thread block and 4-thread raking warp.</div>
+ *
+ * \par Performance Considerations
+ * - Although this variant may suffer lower overall throughput across the
+ * GPU because due to a heavy reliance on inefficient warpscans, it can
+ * often provide lower turnaround latencies when the GPU is under-occupied.
+ */
+ BLOCK_SCAN_WARP_SCANS,
+};
+
+
+/******************************************************************************
+ * Block scan
+ ******************************************************************************/
+
+/**
+ * \brief The BlockScan class provides [<em>collective</em>](index.html#sec0) methods for computing a parallel prefix sum/scan of items partitioned across a CUDA thread block. ![](block_scan_logo.png)
+ * \ingroup BlockModule
+ *
+ * \tparam T Data type being scanned
+ * \tparam BLOCK_DIM_X The thread block length in threads along the X dimension
+ * \tparam ALGORITHM <b>[optional]</b> cub::BlockScanAlgorithm enumerator specifying the underlying algorithm to use (default: cub::BLOCK_SCAN_RAKING)
+ * \tparam BLOCK_DIM_Y <b>[optional]</b> The thread block length in threads along the Y dimension (default: 1)
+ * \tparam BLOCK_DIM_Z <b>[optional]</b> The thread block length in threads along the Z dimension (default: 1)
+ * \tparam PTX_ARCH <b>[optional]</b> \ptxversion
+ *
+ * \par Overview
+ * - Given a list of input elements and a binary reduction operator, a [<em>prefix scan</em>](http://en.wikipedia.org/wiki/Prefix_sum)
+ * produces an output list where each element is computed to be the reduction
+ * of the elements occurring earlier in the input list. <em>Prefix sum</em>
+ * connotes a prefix scan with the addition operator. The term \em inclusive indicates
+ * that the <em>i</em><sup>th</sup> output reduction incorporates the <em>i</em><sup>th</sup> input.
+ * The term \em exclusive indicates the <em>i</em><sup>th</sup> input is not incorporated into
+ * the <em>i</em><sup>th</sup> output reduction.
+ * - \rowmajor
+ * - BlockScan can be optionally specialized by algorithm to accommodate different workload profiles:
+ * -# <b>cub::BLOCK_SCAN_RAKING</b>. An efficient (high throughput) "raking reduce-then-scan" prefix scan algorithm. [More...](\ref cub::BlockScanAlgorithm)
+ * -# <b>cub::BLOCK_SCAN_RAKING_MEMOIZE</b>. Similar to cub::BLOCK_SCAN_RAKING, but having higher throughput at the expense of additional register pressure for intermediate storage. [More...](\ref cub::BlockScanAlgorithm)
+ * -# <b>cub::BLOCK_SCAN_WARP_SCANS</b>. A quick (low latency) "tiled warpscans" prefix scan algorithm. [More...](\ref cub::BlockScanAlgorithm)
+ *
+ * \par Performance Considerations
+ * - \granularity
+ * - Uses special instructions when applicable (e.g., warp \p SHFL)
+ * - Uses synchronization-free communication between warp lanes when applicable
+ * - Invokes a minimal number of minimal block-wide synchronization barriers (only
+ * one or two depending on algorithm selection)
+ * - Incurs zero bank conflicts for most types
+ * - Computation is slightly more efficient (i.e., having lower instruction overhead) for:
+ * - Prefix sum variants (<b><em>vs.</em></b> generic scan)
+ * - \blocksize
+ * - See cub::BlockScanAlgorithm for performance details regarding algorithmic alternatives
+ *
+ * \par A Simple Example
+ * \blockcollective{BlockScan}
+ * \par
+ * The code snippet below illustrates an exclusive prefix sum of 512 integer items that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockScan for a 1D block of 128 threads on type int
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate shared memory for BlockScan
+ * __shared__ typename BlockScan::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Collectively compute the block-wide exclusive prefix sum
+ * BlockScan(temp_storage).ExclusiveSum(thread_data, thread_data);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is
+ * <tt>{[1,1,1,1], [1,1,1,1], ..., [1,1,1,1]}</tt>.
+ * The corresponding output \p thread_data in those threads will be
+ * <tt>{[0,1,2,3], [4,5,6,7], ..., [508,509,510,511]}</tt>.
+ *
+ */
+template <
+ typename T,
+ int BLOCK_DIM_X,
+ BlockScanAlgorithm ALGORITHM = BLOCK_SCAN_RAKING,
+ int BLOCK_DIM_Y = 1,
+ int BLOCK_DIM_Z = 1,
+ int PTX_ARCH = CUB_PTX_ARCH>
+class BlockScan
+{
+private:
+
+ /******************************************************************************
+ * Constants and type definitions
+ ******************************************************************************/
+
+ /// Constants
+ enum
+ {
+ /// The thread block size in threads
+ BLOCK_THREADS = BLOCK_DIM_X * BLOCK_DIM_Y * BLOCK_DIM_Z,
+ };
+
+ /**
+ * Ensure the template parameterization meets the requirements of the
+ * specified algorithm. Currently, the BLOCK_SCAN_WARP_SCANS policy
+ * cannot be used with thread block sizes not a multiple of the
+ * architectural warp size.
+ */
+ static const BlockScanAlgorithm SAFE_ALGORITHM =
+ ((ALGORITHM == BLOCK_SCAN_WARP_SCANS) && (BLOCK_THREADS % CUB_WARP_THREADS(PTX_ARCH) != 0)) ?
+ BLOCK_SCAN_RAKING :
+ ALGORITHM;
+
+ typedef BlockScanWarpScans<T, BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z, PTX_ARCH> WarpScans;
+ typedef BlockScanRaking<T, BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z, (SAFE_ALGORITHM == BLOCK_SCAN_RAKING_MEMOIZE), PTX_ARCH> Raking;
+
+ /// Define the delegate type for the desired algorithm
+ typedef typename If<(SAFE_ALGORITHM == BLOCK_SCAN_WARP_SCANS),
+ WarpScans,
+ Raking>::Type InternalBlockScan;
+
+ /// Shared memory storage layout type for BlockScan
+ typedef typename InternalBlockScan::TempStorage _TempStorage;
+
+
+ /******************************************************************************
+ * Thread fields
+ ******************************************************************************/
+
+ /// Shared storage reference
+ _TempStorage &temp_storage;
+
+ /// Linear thread-id
+ unsigned int linear_tid;
+
+
+ /******************************************************************************
+ * Utility methods
+ ******************************************************************************/
+
+ /// Internal storage allocator
+ __device__ __forceinline__ _TempStorage& PrivateStorage()
+ {
+ __shared__ _TempStorage private_storage;
+ return private_storage;
+ }
+
+
+ /******************************************************************************
+ * Public types
+ ******************************************************************************/
+public:
+
+ /// \smemstorage{BlockScan}
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ /******************************************************************//**
+ * \name Collective constructors
+ *********************************************************************/
+ //@{
+
+ /**
+ * \brief Collective constructor using a private static allocation of shared memory as temporary storage.
+ */
+ __device__ __forceinline__ BlockScan()
+ :
+ temp_storage(PrivateStorage()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ /**
+ * \brief Collective constructor using the specified memory allocation as temporary storage.
+ */
+ __device__ __forceinline__ BlockScan(
+ TempStorage &temp_storage) ///< [in] Reference to memory allocation having layout type TempStorage
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+
+ //@} end member group
+ /******************************************************************//**
+ * \name Exclusive prefix sum operations
+ *********************************************************************/
+ //@{
+
+
+ /**
+ * \brief Computes an exclusive block-wide prefix scan using addition (+) as the scan operator. Each thread contributes one input element. The value of 0 is applied as the initial value, and is assigned to \p output in <em>thread</em><sub>0</sub>.
+ *
+ * \par
+ * - \identityzero
+ * - \rowmajor
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates an exclusive prefix sum of 128 integer items that
+ * are partitioned across 128 threads.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockScan for a 1D block of 128 threads on type int
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate shared memory for BlockScan
+ * __shared__ typename BlockScan::TempStorage temp_storage;
+ *
+ * // Obtain input item for each thread
+ * int thread_data;
+ * ...
+ *
+ * // Collectively compute the block-wide exclusive prefix sum
+ * BlockScan(temp_storage).ExclusiveSum(thread_data, thread_data);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is <tt>1, 1, ..., 1</tt>. The
+ * corresponding output \p thread_data in those threads will be <tt>0, 1, ..., 127</tt>.
+ *
+ */
+ __device__ __forceinline__ void ExclusiveSum(
+ T input, ///< [in] Calling thread's input item
+ T &output) ///< [out] Calling thread's output item (may be aliased to \p input)
+ {
+ T initial_value = 0;
+ ExclusiveScan(input, output, initial_value, cub::Sum());
+ }
+
+
+ /**
+ * \brief Computes an exclusive block-wide prefix scan using addition (+) as the scan operator. Each thread contributes one input element. The value of 0 is applied as the initial value, and is assigned to \p output in <em>thread</em><sub>0</sub>. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ *
+ * \par
+ * - \identityzero
+ * - \rowmajor
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates an exclusive prefix sum of 128 integer items that
+ * are partitioned across 128 threads.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockScan for a 1D block of 128 threads on type int
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate shared memory for BlockScan
+ * __shared__ typename BlockScan::TempStorage temp_storage;
+ *
+ * // Obtain input item for each thread
+ * int thread_data;
+ * ...
+ *
+ * // Collectively compute the block-wide exclusive prefix sum
+ * int block_aggregate;
+ * BlockScan(temp_storage).ExclusiveSum(thread_data, thread_data, block_aggregate);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is <tt>1, 1, ..., 1</tt>. The
+ * corresponding output \p thread_data in those threads will be <tt>0, 1, ..., 127</tt>.
+ * Furthermore the value \p 128 will be stored in \p block_aggregate for all threads.
+ *
+ */
+ __device__ __forceinline__ void ExclusiveSum(
+ T input, ///< [in] Calling thread's input item
+ T &output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ T &block_aggregate) ///< [out] block-wide aggregate reduction of input items
+ {
+ T initial_value = 0;
+ ExclusiveScan(input, output, initial_value, cub::Sum(), block_aggregate);
+ }
+
+
+ /**
+ * \brief Computes an exclusive block-wide prefix scan using addition (+) as the scan operator. Each thread contributes one input element. Instead of using 0 as the block-wide prefix, the call-back functor \p block_prefix_callback_op is invoked by the first warp in the block, and the value returned by <em>lane</em><sub>0</sub> in that warp is used as the "seed" value that logically prefixes the thread block's scan inputs. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ *
+ * \par
+ * - \identityzero
+ * - The \p block_prefix_callback_op functor must implement a member function <tt>T operator()(T block_aggregate)</tt>.
+ * The functor's input parameter \p block_aggregate is the same value also returned by the scan operation.
+ * The functor will be invoked by the first warp of threads in the block, however only the return value from
+ * <em>lane</em><sub>0</sub> is applied as the block-wide prefix. Can be stateful.
+ * - \rowmajor
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a single thread block that progressively
+ * computes an exclusive prefix sum over multiple "tiles" of input using a
+ * prefix functor to maintain a running total between block-wide scans. Each tile consists
+ * of 128 integer items that are partitioned across 128 threads.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * // A stateful callback functor that maintains a running prefix to be applied
+ * // during consecutive scan operations.
+ * struct BlockPrefixCallbackOp
+ * {
+ * // Running prefix
+ * int running_total;
+ *
+ * // Constructor
+ * __device__ BlockPrefixCallbackOp(int running_total) : running_total(running_total) {}
+ *
+ * // Callback operator to be entered by the first warp of threads in the block.
+ * // Thread-0 is responsible for returning a value for seeding the block-wide scan.
+ * __device__ int operator()(int block_aggregate)
+ * {
+ * int old_prefix = running_total;
+ * running_total += block_aggregate;
+ * return old_prefix;
+ * }
+ * };
+ *
+ * __global__ void ExampleKernel(int *d_data, int num_items, ...)
+ * {
+ * // Specialize BlockScan for a 1D block of 128 threads
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate shared memory for BlockScan
+ * __shared__ typename BlockScan::TempStorage temp_storage;
+ *
+ * // Initialize running total
+ * BlockPrefixCallbackOp prefix_op(0);
+ *
+ * // Have the block iterate over segments of items
+ * for (int block_offset = 0; block_offset < num_items; block_offset += 128)
+ * {
+ * // Load a segment of consecutive items that are blocked across threads
+ * int thread_data = d_data[block_offset];
+ *
+ * // Collectively compute the block-wide exclusive prefix sum
+ * BlockScan(temp_storage).ExclusiveSum(
+ * thread_data, thread_data, prefix_op);
+ * CTA_SYNC();
+ *
+ * // Store scanned items to output segment
+ * d_data[block_offset] = thread_data;
+ * }
+ * \endcode
+ * \par
+ * Suppose the input \p d_data is <tt>1, 1, 1, 1, 1, 1, 1, 1, ...</tt>.
+ * The corresponding output for the first segment will be <tt>0, 1, ..., 127</tt>.
+ * The output for the second segment will be <tt>128, 129, ..., 255</tt>.
+ *
+ * \tparam BlockPrefixCallbackOp <b>[inferred]</b> Call-back functor type having member <tt>T operator()(T block_aggregate)</tt>
+ */
+ template <typename BlockPrefixCallbackOp>
+ __device__ __forceinline__ void ExclusiveSum(
+ T input, ///< [in] Calling thread's input item
+ T &output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ BlockPrefixCallbackOp &block_prefix_callback_op) ///< [in-out] <b>[<em>warp</em><sub>0</sub> only]</b> Call-back functor for specifying a block-wide prefix to be applied to the logical input sequence.
+ {
+ ExclusiveScan(input, output, cub::Sum(), block_prefix_callback_op);
+ }
+
+
+ //@} end member group
+ /******************************************************************//**
+ * \name Exclusive prefix sum operations (multiple data per thread)
+ *********************************************************************/
+ //@{
+
+
+ /**
+ * \brief Computes an exclusive block-wide prefix scan using addition (+) as the scan operator. Each thread contributes an array of consecutive input elements. The value of 0 is applied as the initial value, and is assigned to \p output[0] in <em>thread</em><sub>0</sub>.
+ *
+ * \par
+ * - \identityzero
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates an exclusive prefix sum of 512 integer items that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockScan for a 1D block of 128 threads on type int
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate shared memory for BlockScan
+ * __shared__ typename BlockScan::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Collectively compute the block-wide exclusive prefix sum
+ * BlockScan(temp_storage).ExclusiveSum(thread_data, thread_data);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is <tt>{ [1,1,1,1], [1,1,1,1], ..., [1,1,1,1] }</tt>. The
+ * corresponding output \p thread_data in those threads will be <tt>{ [0,1,2,3], [4,5,6,7], ..., [508,509,510,511] }</tt>.
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ */
+ template <int ITEMS_PER_THREAD>
+ __device__ __forceinline__ void ExclusiveSum(
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ T (&output)[ITEMS_PER_THREAD]) ///< [out] Calling thread's output items (may be aliased to \p input)
+ {
+ T initial_value = 0;
+ ExclusiveScan(input, output, initial_value, cub::Sum());
+ }
+
+
+ /**
+ * \brief Computes an exclusive block-wide prefix scan using addition (+) as the scan operator. Each thread contributes an array of consecutive input elements. The value of 0 is applied as the initial value, and is assigned to \p output[0] in <em>thread</em><sub>0</sub>. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ *
+ * \par
+ * - \identityzero
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates an exclusive prefix sum of 512 integer items that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockScan for a 1D block of 128 threads on type int
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate shared memory for BlockScan
+ * __shared__ typename BlockScan::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Collectively compute the block-wide exclusive prefix sum
+ * int block_aggregate;
+ * BlockScan(temp_storage).ExclusiveSum(thread_data, thread_data, block_aggregate);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is <tt>{ [1,1,1,1], [1,1,1,1], ..., [1,1,1,1] }</tt>. The
+ * corresponding output \p thread_data in those threads will be <tt>{ [0,1,2,3], [4,5,6,7], ..., [508,509,510,511] }</tt>.
+ * Furthermore the value \p 512 will be stored in \p block_aggregate for all threads.
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ */
+ template <int ITEMS_PER_THREAD>
+ __device__ __forceinline__ void ExclusiveSum(
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ T (&output)[ITEMS_PER_THREAD], ///< [out] Calling thread's output items (may be aliased to \p input)
+ T &block_aggregate) ///< [out] block-wide aggregate reduction of input items
+ {
+ // Reduce consecutive thread items in registers
+ T initial_value = 0;
+ ExclusiveScan(input, output, initial_value, cub::Sum(), block_aggregate);
+ }
+
+
+ /**
+ * \brief Computes an exclusive block-wide prefix scan using addition (+) as the scan operator. Each thread contributes an array of consecutive input elements. Instead of using 0 as the block-wide prefix, the call-back functor \p block_prefix_callback_op is invoked by the first warp in the block, and the value returned by <em>lane</em><sub>0</sub> in that warp is used as the "seed" value that logically prefixes the thread block's scan inputs. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ *
+ * \par
+ * - \identityzero
+ * - The \p block_prefix_callback_op functor must implement a member function <tt>T operator()(T block_aggregate)</tt>.
+ * The functor's input parameter \p block_aggregate is the same value also returned by the scan operation.
+ * The functor will be invoked by the first warp of threads in the block, however only the return value from
+ * <em>lane</em><sub>0</sub> is applied as the block-wide prefix. Can be stateful.
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a single thread block that progressively
+ * computes an exclusive prefix sum over multiple "tiles" of input using a
+ * prefix functor to maintain a running total between block-wide scans. Each tile consists
+ * of 512 integer items that are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3)
+ * across 128 threads where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * // A stateful callback functor that maintains a running prefix to be applied
+ * // during consecutive scan operations.
+ * struct BlockPrefixCallbackOp
+ * {
+ * // Running prefix
+ * int running_total;
+ *
+ * // Constructor
+ * __device__ BlockPrefixCallbackOp(int running_total) : running_total(running_total) {}
+ *
+ * // Callback operator to be entered by the first warp of threads in the block.
+ * // Thread-0 is responsible for returning a value for seeding the block-wide scan.
+ * __device__ int operator()(int block_aggregate)
+ * {
+ * int old_prefix = running_total;
+ * running_total += block_aggregate;
+ * return old_prefix;
+ * }
+ * };
+ *
+ * __global__ void ExampleKernel(int *d_data, int num_items, ...)
+ * {
+ * // Specialize BlockLoad, BlockStore, and BlockScan for a 1D block of 128 threads, 4 ints per thread
+ * typedef cub::BlockLoad<int*, 128, 4, BLOCK_LOAD_TRANSPOSE> BlockLoad;
+ * typedef cub::BlockStore<int, 128, 4, BLOCK_STORE_TRANSPOSE> BlockStore;
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate aliased shared memory for BlockLoad, BlockStore, and BlockScan
+ * __shared__ union {
+ * typename BlockLoad::TempStorage load;
+ * typename BlockScan::TempStorage scan;
+ * typename BlockStore::TempStorage store;
+ * } temp_storage;
+ *
+ * // Initialize running total
+ * BlockPrefixCallbackOp prefix_op(0);
+ *
+ * // Have the block iterate over segments of items
+ * for (int block_offset = 0; block_offset < num_items; block_offset += 128 * 4)
+ * {
+ * // Load a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * BlockLoad(temp_storage.load).Load(d_data + block_offset, thread_data);
+ * CTA_SYNC();
+ *
+ * // Collectively compute the block-wide exclusive prefix sum
+ * int block_aggregate;
+ * BlockScan(temp_storage.scan).ExclusiveSum(
+ * thread_data, thread_data, prefix_op);
+ * CTA_SYNC();
+ *
+ * // Store scanned items to output segment
+ * BlockStore(temp_storage.store).Store(d_data + block_offset, thread_data);
+ * CTA_SYNC();
+ * }
+ * \endcode
+ * \par
+ * Suppose the input \p d_data is <tt>1, 1, 1, 1, 1, 1, 1, 1, ...</tt>.
+ * The corresponding output for the first segment will be <tt>0, 1, 2, 3, ..., 510, 511</tt>.
+ * The output for the second segment will be <tt>512, 513, 514, 515, ..., 1022, 1023</tt>.
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam BlockPrefixCallbackOp <b>[inferred]</b> Call-back functor type having member <tt>T operator()(T block_aggregate)</tt>
+ */
+ template <
+ int ITEMS_PER_THREAD,
+ typename BlockPrefixCallbackOp>
+ __device__ __forceinline__ void ExclusiveSum(
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ T (&output)[ITEMS_PER_THREAD], ///< [out] Calling thread's output items (may be aliased to \p input)
+ BlockPrefixCallbackOp &block_prefix_callback_op) ///< [in-out] <b>[<em>warp</em><sub>0</sub> only]</b> Call-back functor for specifying a block-wide prefix to be applied to the logical input sequence.
+ {
+ ExclusiveScan(input, output, cub::Sum(), block_prefix_callback_op);
+ }
+
+
+
+ //@} end member group // Exclusive prefix sums
+ /******************************************************************//**
+ * \name Exclusive prefix scan operations
+ *********************************************************************/
+ //@{
+
+
+ /**
+ * \brief Computes an exclusive block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element.
+ *
+ * \par
+ * - Supports non-commutative scan operators.
+ * - \rowmajor
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates an exclusive prefix max scan of 128 integer items that
+ * are partitioned across 128 threads.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockScan for a 1D block of 128 threads on type int
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate shared memory for BlockScan
+ * __shared__ typename BlockScan::TempStorage temp_storage;
+ *
+ * // Obtain input item for each thread
+ * int thread_data;
+ * ...
+ *
+ * // Collectively compute the block-wide exclusive prefix max scan
+ * BlockScan(temp_storage).ExclusiveScan(thread_data, thread_data, INT_MIN, cub::Max());
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is <tt>0, -1, 2, -3, ..., 126, -127</tt>. The
+ * corresponding output \p thread_data in those threads will be <tt>INT_MIN, 0, 0, 2, ..., 124, 126</tt>.
+ *
+ * \tparam ScanOp <b>[inferred]</b> Binary scan functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ */
+ template <typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ T initial_value, ///< [in] Initial value to seed the exclusive scan (and is assigned to \p output[0] in <em>thread</em><sub>0</sub>)
+ ScanOp scan_op) ///< [in] Binary scan functor
+ {
+ InternalBlockScan(temp_storage).ExclusiveScan(input, output, initial_value, scan_op);
+ }
+
+
+ /**
+ * \brief Computes an exclusive block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ *
+ * \par
+ * - Supports non-commutative scan operators.
+ * - \rowmajor
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates an exclusive prefix max scan of 128 integer items that
+ * are partitioned across 128 threads.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockScan for a 1D block of 128 threads on type int
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate shared memory for BlockScan
+ * __shared__ typename BlockScan::TempStorage temp_storage;
+ *
+ * // Obtain input item for each thread
+ * int thread_data;
+ * ...
+ *
+ * // Collectively compute the block-wide exclusive prefix max scan
+ * int block_aggregate;
+ * BlockScan(temp_storage).ExclusiveScan(thread_data, thread_data, INT_MIN, cub::Max(), block_aggregate);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is <tt>0, -1, 2, -3, ..., 126, -127</tt>. The
+ * corresponding output \p thread_data in those threads will be <tt>INT_MIN, 0, 0, 2, ..., 124, 126</tt>.
+ * Furthermore the value \p 126 will be stored in \p block_aggregate for all threads.
+ *
+ * \tparam ScanOp <b>[inferred]</b> Binary scan functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ */
+ template <typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input items
+ T &output, ///< [out] Calling thread's output items (may be aliased to \p input)
+ T initial_value, ///< [in] Initial value to seed the exclusive scan (and is assigned to \p output[0] in <em>thread</em><sub>0</sub>)
+ ScanOp scan_op, ///< [in] Binary scan functor
+ T &block_aggregate) ///< [out] block-wide aggregate reduction of input items
+ {
+ InternalBlockScan(temp_storage).ExclusiveScan(input, output, initial_value, scan_op, block_aggregate);
+ }
+
+
+ /**
+ * \brief Computes an exclusive block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. the call-back functor \p block_prefix_callback_op is invoked by the first warp in the block, and the value returned by <em>lane</em><sub>0</sub> in that warp is used as the "seed" value that logically prefixes the thread block's scan inputs. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ *
+ * \par
+ * - The \p block_prefix_callback_op functor must implement a member function <tt>T operator()(T block_aggregate)</tt>.
+ * The functor's input parameter \p block_aggregate is the same value also returned by the scan operation.
+ * The functor will be invoked by the first warp of threads in the block, however only the return value from
+ * <em>lane</em><sub>0</sub> is applied as the block-wide prefix. Can be stateful.
+ * - Supports non-commutative scan operators.
+ * - \rowmajor
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a single thread block that progressively
+ * computes an exclusive prefix max scan over multiple "tiles" of input using a
+ * prefix functor to maintain a running total between block-wide scans. Each tile consists
+ * of 128 integer items that are partitioned across 128 threads.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * // A stateful callback functor that maintains a running prefix to be applied
+ * // during consecutive scan operations.
+ * struct BlockPrefixCallbackOp
+ * {
+ * // Running prefix
+ * int running_total;
+ *
+ * // Constructor
+ * __device__ BlockPrefixCallbackOp(int running_total) : running_total(running_total) {}
+ *
+ * // Callback operator to be entered by the first warp of threads in the block.
+ * // Thread-0 is responsible for returning a value for seeding the block-wide scan.
+ * __device__ int operator()(int block_aggregate)
+ * {
+ * int old_prefix = running_total;
+ * running_total = (block_aggregate > old_prefix) ? block_aggregate : old_prefix;
+ * return old_prefix;
+ * }
+ * };
+ *
+ * __global__ void ExampleKernel(int *d_data, int num_items, ...)
+ * {
+ * // Specialize BlockScan for a 1D block of 128 threads
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate shared memory for BlockScan
+ * __shared__ typename BlockScan::TempStorage temp_storage;
+ *
+ * // Initialize running total
+ * BlockPrefixCallbackOp prefix_op(INT_MIN);
+ *
+ * // Have the block iterate over segments of items
+ * for (int block_offset = 0; block_offset < num_items; block_offset += 128)
+ * {
+ * // Load a segment of consecutive items that are blocked across threads
+ * int thread_data = d_data[block_offset];
+ *
+ * // Collectively compute the block-wide exclusive prefix max scan
+ * BlockScan(temp_storage).ExclusiveScan(
+ * thread_data, thread_data, INT_MIN, cub::Max(), prefix_op);
+ * CTA_SYNC();
+ *
+ * // Store scanned items to output segment
+ * d_data[block_offset] = thread_data;
+ * }
+ * \endcode
+ * \par
+ * Suppose the input \p d_data is <tt>0, -1, 2, -3, 4, -5, ...</tt>.
+ * The corresponding output for the first segment will be <tt>INT_MIN, 0, 0, 2, ..., 124, 126</tt>.
+ * The output for the second segment will be <tt>126, 128, 128, 130, ..., 252, 254</tt>.
+ *
+ * \tparam ScanOp <b>[inferred]</b> Binary scan functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ * \tparam BlockPrefixCallbackOp <b>[inferred]</b> Call-back functor type having member <tt>T operator()(T block_aggregate)</tt>
+ */
+ template <
+ typename ScanOp,
+ typename BlockPrefixCallbackOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan functor
+ BlockPrefixCallbackOp &block_prefix_callback_op) ///< [in-out] <b>[<em>warp</em><sub>0</sub> only]</b> Call-back functor for specifying a block-wide prefix to be applied to the logical input sequence.
+ {
+ InternalBlockScan(temp_storage).ExclusiveScan(input, output, scan_op, block_prefix_callback_op);
+ }
+
+
+ //@} end member group // Inclusive prefix sums
+ /******************************************************************//**
+ * \name Exclusive prefix scan operations (multiple data per thread)
+ *********************************************************************/
+ //@{
+
+
+ /**
+ * \brief Computes an exclusive block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes an array of consecutive input elements.
+ *
+ * \par
+ * - Supports non-commutative scan operators.
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates an exclusive prefix max scan of 512 integer items that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockScan for a 1D block of 128 threads on type int
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate shared memory for BlockScan
+ * __shared__ typename BlockScan::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Collectively compute the block-wide exclusive prefix max scan
+ * BlockScan(temp_storage).ExclusiveScan(thread_data, thread_data, INT_MIN, cub::Max());
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is
+ * <tt>{ [0,-1,2,-3], [4,-5,6,-7], ..., [508,-509,510,-511] }</tt>.
+ * The corresponding output \p thread_data in those threads will be
+ * <tt>{ [INT_MIN,0,0,2], [2,4,4,6], ..., [506,508,508,510] }</tt>.
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam ScanOp <b>[inferred]</b> Binary scan functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ */
+ template <
+ int ITEMS_PER_THREAD,
+ typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ T (&output)[ITEMS_PER_THREAD], ///< [out] Calling thread's output items (may be aliased to \p input)
+ T initial_value, ///< [in] Initial value to seed the exclusive scan (and is assigned to \p output[0] in <em>thread</em><sub>0</sub>)
+ ScanOp scan_op) ///< [in] Binary scan functor
+ {
+ // Reduce consecutive thread items in registers
+ T thread_prefix = internal::ThreadReduce(input, scan_op);
+
+ // Exclusive thread block-scan
+ ExclusiveScan(thread_prefix, thread_prefix, initial_value, scan_op);
+
+ // Exclusive scan in registers with prefix as seed
+ internal::ThreadScanExclusive(input, output, scan_op, thread_prefix);
+ }
+
+
+ /**
+ * \brief Computes an exclusive block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes an array of consecutive input elements. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ *
+ * \par
+ * - Supports non-commutative scan operators.
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates an exclusive prefix max scan of 512 integer items that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockScan for a 1D block of 128 threads on type int
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate shared memory for BlockScan
+ * __shared__ typename BlockScan::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Collectively compute the block-wide exclusive prefix max scan
+ * int block_aggregate;
+ * BlockScan(temp_storage).ExclusiveScan(thread_data, thread_data, INT_MIN, cub::Max(), block_aggregate);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is <tt>{ [0,-1,2,-3], [4,-5,6,-7], ..., [508,-509,510,-511] }</tt>. The
+ * corresponding output \p thread_data in those threads will be <tt>{ [INT_MIN,0,0,2], [2,4,4,6], ..., [506,508,508,510] }</tt>.
+ * Furthermore the value \p 510 will be stored in \p block_aggregate for all threads.
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam ScanOp <b>[inferred]</b> Binary scan functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ */
+ template <
+ int ITEMS_PER_THREAD,
+ typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ T (&output)[ITEMS_PER_THREAD], ///< [out] Calling thread's output items (may be aliased to \p input)
+ T initial_value, ///< [in] Initial value to seed the exclusive scan (and is assigned to \p output[0] in <em>thread</em><sub>0</sub>)
+ ScanOp scan_op, ///< [in] Binary scan functor
+ T &block_aggregate) ///< [out] block-wide aggregate reduction of input items
+ {
+ // Reduce consecutive thread items in registers
+ T thread_prefix = internal::ThreadReduce(input, scan_op);
+
+ // Exclusive thread block-scan
+ ExclusiveScan(thread_prefix, thread_prefix, initial_value, scan_op, block_aggregate);
+
+ // Exclusive scan in registers with prefix as seed
+ internal::ThreadScanExclusive(input, output, scan_op, thread_prefix);
+ }
+
+
+ /**
+ * \brief Computes an exclusive block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes an array of consecutive input elements. the call-back functor \p block_prefix_callback_op is invoked by the first warp in the block, and the value returned by <em>lane</em><sub>0</sub> in that warp is used as the "seed" value that logically prefixes the thread block's scan inputs. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ *
+ * \par
+ * - The \p block_prefix_callback_op functor must implement a member function <tt>T operator()(T block_aggregate)</tt>.
+ * The functor's input parameter \p block_aggregate is the same value also returned by the scan operation.
+ * The functor will be invoked by the first warp of threads in the block, however only the return value from
+ * <em>lane</em><sub>0</sub> is applied as the block-wide prefix. Can be stateful.
+ * - Supports non-commutative scan operators.
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a single thread block that progressively
+ * computes an exclusive prefix max scan over multiple "tiles" of input using a
+ * prefix functor to maintain a running total between block-wide scans. Each tile consists
+ * of 128 integer items that are partitioned across 128 threads.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * // A stateful callback functor that maintains a running prefix to be applied
+ * // during consecutive scan operations.
+ * struct BlockPrefixCallbackOp
+ * {
+ * // Running prefix
+ * int running_total;
+ *
+ * // Constructor
+ * __device__ BlockPrefixCallbackOp(int running_total) : running_total(running_total) {}
+ *
+ * // Callback operator to be entered by the first warp of threads in the block.
+ * // Thread-0 is responsible for returning a value for seeding the block-wide scan.
+ * __device__ int operator()(int block_aggregate)
+ * {
+ * int old_prefix = running_total;
+ * running_total = (block_aggregate > old_prefix) ? block_aggregate : old_prefix;
+ * return old_prefix;
+ * }
+ * };
+ *
+ * __global__ void ExampleKernel(int *d_data, int num_items, ...)
+ * {
+ * // Specialize BlockLoad, BlockStore, and BlockScan for a 1D block of 128 threads, 4 ints per thread
+ * typedef cub::BlockLoad<int*, 128, 4, BLOCK_LOAD_TRANSPOSE> BlockLoad;
+ * typedef cub::BlockStore<int, 128, 4, BLOCK_STORE_TRANSPOSE> BlockStore;
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate aliased shared memory for BlockLoad, BlockStore, and BlockScan
+ * __shared__ union {
+ * typename BlockLoad::TempStorage load;
+ * typename BlockScan::TempStorage scan;
+ * typename BlockStore::TempStorage store;
+ * } temp_storage;
+ *
+ * // Initialize running total
+ * BlockPrefixCallbackOp prefix_op(0);
+ *
+ * // Have the block iterate over segments of items
+ * for (int block_offset = 0; block_offset < num_items; block_offset += 128 * 4)
+ * {
+ * // Load a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * BlockLoad(temp_storage.load).Load(d_data + block_offset, thread_data);
+ * CTA_SYNC();
+ *
+ * // Collectively compute the block-wide exclusive prefix max scan
+ * BlockScan(temp_storage.scan).ExclusiveScan(
+ * thread_data, thread_data, INT_MIN, cub::Max(), prefix_op);
+ * CTA_SYNC();
+ *
+ * // Store scanned items to output segment
+ * BlockStore(temp_storage.store).Store(d_data + block_offset, thread_data);
+ * CTA_SYNC();
+ * }
+ * \endcode
+ * \par
+ * Suppose the input \p d_data is <tt>0, -1, 2, -3, 4, -5, ...</tt>.
+ * The corresponding output for the first segment will be <tt>INT_MIN, 0, 0, 2, 2, 4, ..., 508, 510</tt>.
+ * The output for the second segment will be <tt>510, 512, 512, 514, 514, 516, ..., 1020, 1022</tt>.
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam ScanOp <b>[inferred]</b> Binary scan functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ * \tparam BlockPrefixCallbackOp <b>[inferred]</b> Call-back functor type having member <tt>T operator()(T block_aggregate)</tt>
+ */
+ template <
+ int ITEMS_PER_THREAD,
+ typename ScanOp,
+ typename BlockPrefixCallbackOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ T (&output)[ITEMS_PER_THREAD], ///< [out] Calling thread's output items (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan functor
+ BlockPrefixCallbackOp &block_prefix_callback_op) ///< [in-out] <b>[<em>warp</em><sub>0</sub> only]</b> Call-back functor for specifying a block-wide prefix to be applied to the logical input sequence.
+ {
+ // Reduce consecutive thread items in registers
+ T thread_prefix = internal::ThreadReduce(input, scan_op);
+
+ // Exclusive thread block-scan
+ ExclusiveScan(thread_prefix, thread_prefix, scan_op, block_prefix_callback_op);
+
+ // Exclusive scan in registers with prefix as seed
+ internal::ThreadScanExclusive(input, output, scan_op, thread_prefix);
+ }
+
+
+ //@} end member group
+#ifndef DOXYGEN_SHOULD_SKIP_THIS // Do not document no-initial-value scans
+
+ /******************************************************************//**
+ * \name Exclusive prefix scan operations (no initial value, single datum per thread)
+ *********************************************************************/
+ //@{
+
+
+ /**
+ * \brief Computes an exclusive block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. With no initial value, the output computed for <em>thread</em><sub>0</sub> is undefined.
+ *
+ * \par
+ * - Supports non-commutative scan operators.
+ * - \rowmajor
+ * - \smemreuse
+ *
+ * \tparam ScanOp <b>[inferred]</b> Binary scan functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ */
+ template <typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op) ///< [in] Binary scan functor
+ {
+ InternalBlockScan(temp_storage).ExclusiveScan(input, output, scan_op);
+ }
+
+
+ /**
+ * \brief Computes an exclusive block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. Also provides every thread with the block-wide \p block_aggregate of all inputs. With no initial value, the output computed for <em>thread</em><sub>0</sub> is undefined.
+ *
+ * \par
+ * - Supports non-commutative scan operators.
+ * - \rowmajor
+ * - \smemreuse
+ *
+ * \tparam ScanOp <b>[inferred]</b> Binary scan functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ */
+ template <typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan functor
+ T &block_aggregate) ///< [out] block-wide aggregate reduction of input items
+ {
+ InternalBlockScan(temp_storage).ExclusiveScan(input, output, scan_op, block_aggregate);
+ }
+
+ //@} end member group
+ /******************************************************************//**
+ * \name Exclusive prefix scan operations (no initial value, multiple data per thread)
+ *********************************************************************/
+ //@{
+
+
+ /**
+ * \brief Computes an exclusive block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes an array of consecutive input elements. With no initial value, the output computed for <em>thread</em><sub>0</sub> is undefined.
+ *
+ * \par
+ * - Supports non-commutative scan operators.
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam ScanOp <b>[inferred]</b> Binary scan functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ */
+ template <
+ int ITEMS_PER_THREAD,
+ typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ T (&output)[ITEMS_PER_THREAD], ///< [out] Calling thread's output items (may be aliased to \p input)
+ ScanOp scan_op) ///< [in] Binary scan functor
+ {
+ // Reduce consecutive thread items in registers
+ T thread_partial = internal::ThreadReduce(input, scan_op);
+
+ // Exclusive thread block-scan
+ ExclusiveScan(thread_partial, thread_partial, scan_op);
+
+ // Exclusive scan in registers with prefix
+ internal::ThreadScanExclusive(input, output, scan_op, thread_partial, (linear_tid != 0));
+ }
+
+
+ /**
+ * \brief Computes an exclusive block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes an array of consecutive input elements. Also provides every thread with the block-wide \p block_aggregate of all inputs. With no initial value, the output computed for <em>thread</em><sub>0</sub> is undefined.
+ *
+ * \par
+ * - Supports non-commutative scan operators.
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam ScanOp <b>[inferred]</b> Binary scan functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ */
+ template <
+ int ITEMS_PER_THREAD,
+ typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ T (&output)[ITEMS_PER_THREAD], ///< [out] Calling thread's output items (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan functor
+ T &block_aggregate) ///< [out] block-wide aggregate reduction of input items
+ {
+ // Reduce consecutive thread items in registers
+ T thread_partial = internal::ThreadReduce(input, scan_op);
+
+ // Exclusive thread block-scan
+ ExclusiveScan(thread_partial, thread_partial, scan_op, block_aggregate);
+
+ // Exclusive scan in registers with prefix
+ internal::ThreadScanExclusive(input, output, scan_op, thread_partial, (linear_tid != 0));
+ }
+
+
+ //@} end member group
+#endif // DOXYGEN_SHOULD_SKIP_THIS // Do not document no-initial-value scans
+
+ /******************************************************************//**
+ * \name Inclusive prefix sum operations
+ *********************************************************************/
+ //@{
+
+
+ /**
+ * \brief Computes an inclusive block-wide prefix scan using addition (+) as the scan operator. Each thread contributes one input element.
+ *
+ * \par
+ * - \rowmajor
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates an inclusive prefix sum of 128 integer items that
+ * are partitioned across 128 threads.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockScan for a 1D block of 128 threads on type int
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate shared memory for BlockScan
+ * __shared__ typename BlockScan::TempStorage temp_storage;
+ *
+ * // Obtain input item for each thread
+ * int thread_data;
+ * ...
+ *
+ * // Collectively compute the block-wide inclusive prefix sum
+ * BlockScan(temp_storage).InclusiveSum(thread_data, thread_data);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is <tt>1, 1, ..., 1</tt>. The
+ * corresponding output \p thread_data in those threads will be <tt>1, 2, ..., 128</tt>.
+ *
+ */
+ __device__ __forceinline__ void InclusiveSum(
+ T input, ///< [in] Calling thread's input item
+ T &output) ///< [out] Calling thread's output item (may be aliased to \p input)
+ {
+ InclusiveScan(input, output, cub::Sum());
+ }
+
+
+ /**
+ * \brief Computes an inclusive block-wide prefix scan using addition (+) as the scan operator. Each thread contributes one input element. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ *
+ * \par
+ * - \rowmajor
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates an inclusive prefix sum of 128 integer items that
+ * are partitioned across 128 threads.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockScan for a 1D block of 128 threads on type int
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate shared memory for BlockScan
+ * __shared__ typename BlockScan::TempStorage temp_storage;
+ *
+ * // Obtain input item for each thread
+ * int thread_data;
+ * ...
+ *
+ * // Collectively compute the block-wide inclusive prefix sum
+ * int block_aggregate;
+ * BlockScan(temp_storage).InclusiveSum(thread_data, thread_data, block_aggregate);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is <tt>1, 1, ..., 1</tt>. The
+ * corresponding output \p thread_data in those threads will be <tt>1, 2, ..., 128</tt>.
+ * Furthermore the value \p 128 will be stored in \p block_aggregate for all threads.
+ *
+ */
+ __device__ __forceinline__ void InclusiveSum(
+ T input, ///< [in] Calling thread's input item
+ T &output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ T &block_aggregate) ///< [out] block-wide aggregate reduction of input items
+ {
+ InclusiveScan(input, output, cub::Sum(), block_aggregate);
+ }
+
+
+
+ /**
+ * \brief Computes an inclusive block-wide prefix scan using addition (+) as the scan operator. Each thread contributes one input element. Instead of using 0 as the block-wide prefix, the call-back functor \p block_prefix_callback_op is invoked by the first warp in the block, and the value returned by <em>lane</em><sub>0</sub> in that warp is used as the "seed" value that logically prefixes the thread block's scan inputs. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ *
+ * \par
+ * - The \p block_prefix_callback_op functor must implement a member function <tt>T operator()(T block_aggregate)</tt>.
+ * The functor's input parameter \p block_aggregate is the same value also returned by the scan operation.
+ * The functor will be invoked by the first warp of threads in the block, however only the return value from
+ * <em>lane</em><sub>0</sub> is applied as the block-wide prefix. Can be stateful.
+ * - \rowmajor
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a single thread block that progressively
+ * computes an inclusive prefix sum over multiple "tiles" of input using a
+ * prefix functor to maintain a running total between block-wide scans. Each tile consists
+ * of 128 integer items that are partitioned across 128 threads.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * // A stateful callback functor that maintains a running prefix to be applied
+ * // during consecutive scan operations.
+ * struct BlockPrefixCallbackOp
+ * {
+ * // Running prefix
+ * int running_total;
+ *
+ * // Constructor
+ * __device__ BlockPrefixCallbackOp(int running_total) : running_total(running_total) {}
+ *
+ * // Callback operator to be entered by the first warp of threads in the block.
+ * // Thread-0 is responsible for returning a value for seeding the block-wide scan.
+ * __device__ int operator()(int block_aggregate)
+ * {
+ * int old_prefix = running_total;
+ * running_total += block_aggregate;
+ * return old_prefix;
+ * }
+ * };
+ *
+ * __global__ void ExampleKernel(int *d_data, int num_items, ...)
+ * {
+ * // Specialize BlockScan for a 1D block of 128 threads
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate shared memory for BlockScan
+ * __shared__ typename BlockScan::TempStorage temp_storage;
+ *
+ * // Initialize running total
+ * BlockPrefixCallbackOp prefix_op(0);
+ *
+ * // Have the block iterate over segments of items
+ * for (int block_offset = 0; block_offset < num_items; block_offset += 128)
+ * {
+ * // Load a segment of consecutive items that are blocked across threads
+ * int thread_data = d_data[block_offset];
+ *
+ * // Collectively compute the block-wide inclusive prefix sum
+ * BlockScan(temp_storage).InclusiveSum(
+ * thread_data, thread_data, prefix_op);
+ * CTA_SYNC();
+ *
+ * // Store scanned items to output segment
+ * d_data[block_offset] = thread_data;
+ * }
+ * \endcode
+ * \par
+ * Suppose the input \p d_data is <tt>1, 1, 1, 1, 1, 1, 1, 1, ...</tt>.
+ * The corresponding output for the first segment will be <tt>1, 2, ..., 128</tt>.
+ * The output for the second segment will be <tt>129, 130, ..., 256</tt>.
+ *
+ * \tparam BlockPrefixCallbackOp <b>[inferred]</b> Call-back functor type having member <tt>T operator()(T block_aggregate)</tt>
+ */
+ template <typename BlockPrefixCallbackOp>
+ __device__ __forceinline__ void InclusiveSum(
+ T input, ///< [in] Calling thread's input item
+ T &output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ BlockPrefixCallbackOp &block_prefix_callback_op) ///< [in-out] <b>[<em>warp</em><sub>0</sub> only]</b> Call-back functor for specifying a block-wide prefix to be applied to the logical input sequence.
+ {
+ InclusiveScan(input, output, cub::Sum(), block_prefix_callback_op);
+ }
+
+
+ //@} end member group
+ /******************************************************************//**
+ * \name Inclusive prefix sum operations (multiple data per thread)
+ *********************************************************************/
+ //@{
+
+
+ /**
+ * \brief Computes an inclusive block-wide prefix scan using addition (+) as the scan operator. Each thread contributes an array of consecutive input elements.
+ *
+ * \par
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates an inclusive prefix sum of 512 integer items that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockScan for a 1D block of 128 threads on type int
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate shared memory for BlockScan
+ * __shared__ typename BlockScan::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Collectively compute the block-wide inclusive prefix sum
+ * BlockScan(temp_storage).InclusiveSum(thread_data, thread_data);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is <tt>{ [1,1,1,1], [1,1,1,1], ..., [1,1,1,1] }</tt>. The
+ * corresponding output \p thread_data in those threads will be <tt>{ [1,2,3,4], [5,6,7,8], ..., [509,510,511,512] }</tt>.
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ */
+ template <int ITEMS_PER_THREAD>
+ __device__ __forceinline__ void InclusiveSum(
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ T (&output)[ITEMS_PER_THREAD]) ///< [out] Calling thread's output items (may be aliased to \p input)
+ {
+ if (ITEMS_PER_THREAD == 1)
+ {
+ InclusiveSum(input[0], output[0]);
+ }
+ else
+ {
+ // Reduce consecutive thread items in registers
+ Sum scan_op;
+ T thread_prefix = internal::ThreadReduce(input, scan_op);
+
+ // Exclusive thread block-scan
+ ExclusiveSum(thread_prefix, thread_prefix);
+
+ // Inclusive scan in registers with prefix as seed
+ internal::ThreadScanInclusive(input, output, scan_op, thread_prefix, (linear_tid != 0));
+ }
+ }
+
+
+ /**
+ * \brief Computes an inclusive block-wide prefix scan using addition (+) as the scan operator. Each thread contributes an array of consecutive input elements. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ *
+ * \par
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates an inclusive prefix sum of 512 integer items that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockScan for a 1D block of 128 threads on type int
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate shared memory for BlockScan
+ * __shared__ typename BlockScan::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Collectively compute the block-wide inclusive prefix sum
+ * int block_aggregate;
+ * BlockScan(temp_storage).InclusiveSum(thread_data, thread_data, block_aggregate);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is
+ * <tt>{ [1,1,1,1], [1,1,1,1], ..., [1,1,1,1] }</tt>. The
+ * corresponding output \p thread_data in those threads will be
+ * <tt>{ [1,2,3,4], [5,6,7,8], ..., [509,510,511,512] }</tt>.
+ * Furthermore the value \p 512 will be stored in \p block_aggregate for all threads.
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam ScanOp <b>[inferred]</b> Binary scan functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ */
+ template <int ITEMS_PER_THREAD>
+ __device__ __forceinline__ void InclusiveSum(
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ T (&output)[ITEMS_PER_THREAD], ///< [out] Calling thread's output items (may be aliased to \p input)
+ T &block_aggregate) ///< [out] block-wide aggregate reduction of input items
+ {
+ if (ITEMS_PER_THREAD == 1)
+ {
+ InclusiveSum(input[0], output[0], block_aggregate);
+ }
+ else
+ {
+ // Reduce consecutive thread items in registers
+ Sum scan_op;
+ T thread_prefix = internal::ThreadReduce(input, scan_op);
+
+ // Exclusive thread block-scan
+ ExclusiveSum(thread_prefix, thread_prefix, block_aggregate);
+
+ // Inclusive scan in registers with prefix as seed
+ internal::ThreadScanInclusive(input, output, scan_op, thread_prefix, (linear_tid != 0));
+ }
+ }
+
+
+ /**
+ * \brief Computes an inclusive block-wide prefix scan using addition (+) as the scan operator. Each thread contributes an array of consecutive input elements. Instead of using 0 as the block-wide prefix, the call-back functor \p block_prefix_callback_op is invoked by the first warp in the block, and the value returned by <em>lane</em><sub>0</sub> in that warp is used as the "seed" value that logically prefixes the thread block's scan inputs. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ *
+ * \par
+ * - The \p block_prefix_callback_op functor must implement a member function <tt>T operator()(T block_aggregate)</tt>.
+ * The functor's input parameter \p block_aggregate is the same value also returned by the scan operation.
+ * The functor will be invoked by the first warp of threads in the block, however only the return value from
+ * <em>lane</em><sub>0</sub> is applied as the block-wide prefix. Can be stateful.
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a single thread block that progressively
+ * computes an inclusive prefix sum over multiple "tiles" of input using a
+ * prefix functor to maintain a running total between block-wide scans. Each tile consists
+ * of 512 integer items that are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3)
+ * across 128 threads where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * // A stateful callback functor that maintains a running prefix to be applied
+ * // during consecutive scan operations.
+ * struct BlockPrefixCallbackOp
+ * {
+ * // Running prefix
+ * int running_total;
+ *
+ * // Constructor
+ * __device__ BlockPrefixCallbackOp(int running_total) : running_total(running_total) {}
+ *
+ * // Callback operator to be entered by the first warp of threads in the block.
+ * // Thread-0 is responsible for returning a value for seeding the block-wide scan.
+ * __device__ int operator()(int block_aggregate)
+ * {
+ * int old_prefix = running_total;
+ * running_total += block_aggregate;
+ * return old_prefix;
+ * }
+ * };
+ *
+ * __global__ void ExampleKernel(int *d_data, int num_items, ...)
+ * {
+ * // Specialize BlockLoad, BlockStore, and BlockScan for a 1D block of 128 threads, 4 ints per thread
+ * typedef cub::BlockLoad<int*, 128, 4, BLOCK_LOAD_TRANSPOSE> BlockLoad;
+ * typedef cub::BlockStore<int, 128, 4, BLOCK_STORE_TRANSPOSE> BlockStore;
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate aliased shared memory for BlockLoad, BlockStore, and BlockScan
+ * __shared__ union {
+ * typename BlockLoad::TempStorage load;
+ * typename BlockScan::TempStorage scan;
+ * typename BlockStore::TempStorage store;
+ * } temp_storage;
+ *
+ * // Initialize running total
+ * BlockPrefixCallbackOp prefix_op(0);
+ *
+ * // Have the block iterate over segments of items
+ * for (int block_offset = 0; block_offset < num_items; block_offset += 128 * 4)
+ * {
+ * // Load a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * BlockLoad(temp_storage.load).Load(d_data + block_offset, thread_data);
+ * CTA_SYNC();
+ *
+ * // Collectively compute the block-wide inclusive prefix sum
+ * BlockScan(temp_storage.scan).IncluisveSum(
+ * thread_data, thread_data, prefix_op);
+ * CTA_SYNC();
+ *
+ * // Store scanned items to output segment
+ * BlockStore(temp_storage.store).Store(d_data + block_offset, thread_data);
+ * CTA_SYNC();
+ * }
+ * \endcode
+ * \par
+ * Suppose the input \p d_data is <tt>1, 1, 1, 1, 1, 1, 1, 1, ...</tt>.
+ * The corresponding output for the first segment will be <tt>1, 2, 3, 4, ..., 511, 512</tt>.
+ * The output for the second segment will be <tt>513, 514, 515, 516, ..., 1023, 1024</tt>.
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam BlockPrefixCallbackOp <b>[inferred]</b> Call-back functor type having member <tt>T operator()(T block_aggregate)</tt>
+ */
+ template <
+ int ITEMS_PER_THREAD,
+ typename BlockPrefixCallbackOp>
+ __device__ __forceinline__ void InclusiveSum(
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ T (&output)[ITEMS_PER_THREAD], ///< [out] Calling thread's output items (may be aliased to \p input)
+ BlockPrefixCallbackOp &block_prefix_callback_op) ///< [in-out] <b>[<em>warp</em><sub>0</sub> only]</b> Call-back functor for specifying a block-wide prefix to be applied to the logical input sequence.
+ {
+ if (ITEMS_PER_THREAD == 1)
+ {
+ InclusiveSum(input[0], output[0], block_prefix_callback_op);
+ }
+ else
+ {
+ // Reduce consecutive thread items in registers
+ Sum scan_op;
+ T thread_prefix = internal::ThreadReduce(input, scan_op);
+
+ // Exclusive thread block-scan
+ ExclusiveSum(thread_prefix, thread_prefix, block_prefix_callback_op);
+
+ // Inclusive scan in registers with prefix as seed
+ internal::ThreadScanInclusive(input, output, scan_op, thread_prefix);
+ }
+ }
+
+
+ //@} end member group
+ /******************************************************************//**
+ * \name Inclusive prefix scan operations
+ *********************************************************************/
+ //@{
+
+
+ /**
+ * \brief Computes an inclusive block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element.
+ *
+ * \par
+ * - Supports non-commutative scan operators.
+ * - \rowmajor
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates an inclusive prefix max scan of 128 integer items that
+ * are partitioned across 128 threads.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockScan for a 1D block of 128 threads on type int
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate shared memory for BlockScan
+ * __shared__ typename BlockScan::TempStorage temp_storage;
+ *
+ * // Obtain input item for each thread
+ * int thread_data;
+ * ...
+ *
+ * // Collectively compute the block-wide inclusive prefix max scan
+ * BlockScan(temp_storage).InclusiveScan(thread_data, thread_data, cub::Max());
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is <tt>0, -1, 2, -3, ..., 126, -127</tt>. The
+ * corresponding output \p thread_data in those threads will be <tt>0, 0, 2, 2, ..., 126, 126</tt>.
+ *
+ * \tparam ScanOp <b>[inferred]</b> Binary scan functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ */
+ template <typename ScanOp>
+ __device__ __forceinline__ void InclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op) ///< [in] Binary scan functor
+ {
+ InternalBlockScan(temp_storage).InclusiveScan(input, output, scan_op);
+ }
+
+
+ /**
+ * \brief Computes an inclusive block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ *
+ * \par
+ * - Supports non-commutative scan operators.
+ * - \rowmajor
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates an inclusive prefix max scan of 128 integer items that
+ * are partitioned across 128 threads.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockScan for a 1D block of 128 threads on type int
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate shared memory for BlockScan
+ * __shared__ typename BlockScan::TempStorage temp_storage;
+ *
+ * // Obtain input item for each thread
+ * int thread_data;
+ * ...
+ *
+ * // Collectively compute the block-wide inclusive prefix max scan
+ * int block_aggregate;
+ * BlockScan(temp_storage).InclusiveScan(thread_data, thread_data, cub::Max(), block_aggregate);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is <tt>0, -1, 2, -3, ..., 126, -127</tt>. The
+ * corresponding output \p thread_data in those threads will be <tt>0, 0, 2, 2, ..., 126, 126</tt>.
+ * Furthermore the value \p 126 will be stored in \p block_aggregate for all threads.
+ *
+ * \tparam ScanOp <b>[inferred]</b> Binary scan functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ */
+ template <typename ScanOp>
+ __device__ __forceinline__ void InclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan functor
+ T &block_aggregate) ///< [out] block-wide aggregate reduction of input items
+ {
+ InternalBlockScan(temp_storage).InclusiveScan(input, output, scan_op, block_aggregate);
+ }
+
+
+ /**
+ * \brief Computes an inclusive block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. the call-back functor \p block_prefix_callback_op is invoked by the first warp in the block, and the value returned by <em>lane</em><sub>0</sub> in that warp is used as the "seed" value that logically prefixes the thread block's scan inputs. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ *
+ * \par
+ * - The \p block_prefix_callback_op functor must implement a member function <tt>T operator()(T block_aggregate)</tt>.
+ * The functor's input parameter \p block_aggregate is the same value also returned by the scan operation.
+ * The functor will be invoked by the first warp of threads in the block, however only the return value from
+ * <em>lane</em><sub>0</sub> is applied as the block-wide prefix. Can be stateful.
+ * - Supports non-commutative scan operators.
+ * - \rowmajor
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a single thread block that progressively
+ * computes an inclusive prefix max scan over multiple "tiles" of input using a
+ * prefix functor to maintain a running total between block-wide scans. Each tile consists
+ * of 128 integer items that are partitioned across 128 threads.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * // A stateful callback functor that maintains a running prefix to be applied
+ * // during consecutive scan operations.
+ * struct BlockPrefixCallbackOp
+ * {
+ * // Running prefix
+ * int running_total;
+ *
+ * // Constructor
+ * __device__ BlockPrefixCallbackOp(int running_total) : running_total(running_total) {}
+ *
+ * // Callback operator to be entered by the first warp of threads in the block.
+ * // Thread-0 is responsible for returning a value for seeding the block-wide scan.
+ * __device__ int operator()(int block_aggregate)
+ * {
+ * int old_prefix = running_total;
+ * running_total = (block_aggregate > old_prefix) ? block_aggregate : old_prefix;
+ * return old_prefix;
+ * }
+ * };
+ *
+ * __global__ void ExampleKernel(int *d_data, int num_items, ...)
+ * {
+ * // Specialize BlockScan for a 1D block of 128 threads
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate shared memory for BlockScan
+ * __shared__ typename BlockScan::TempStorage temp_storage;
+ *
+ * // Initialize running total
+ * BlockPrefixCallbackOp prefix_op(INT_MIN);
+ *
+ * // Have the block iterate over segments of items
+ * for (int block_offset = 0; block_offset < num_items; block_offset += 128)
+ * {
+ * // Load a segment of consecutive items that are blocked across threads
+ * int thread_data = d_data[block_offset];
+ *
+ * // Collectively compute the block-wide inclusive prefix max scan
+ * BlockScan(temp_storage).InclusiveScan(
+ * thread_data, thread_data, cub::Max(), prefix_op);
+ * CTA_SYNC();
+ *
+ * // Store scanned items to output segment
+ * d_data[block_offset] = thread_data;
+ * }
+ * \endcode
+ * \par
+ * Suppose the input \p d_data is <tt>0, -1, 2, -3, 4, -5, ...</tt>.
+ * The corresponding output for the first segment will be <tt>0, 0, 2, 2, ..., 126, 126</tt>.
+ * The output for the second segment will be <tt>128, 128, 130, 130, ..., 254, 254</tt>.
+ *
+ * \tparam ScanOp <b>[inferred]</b> Binary scan functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ * \tparam BlockPrefixCallbackOp <b>[inferred]</b> Call-back functor type having member <tt>T operator()(T block_aggregate)</tt>
+ */
+ template <
+ typename ScanOp,
+ typename BlockPrefixCallbackOp>
+ __device__ __forceinline__ void InclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan functor
+ BlockPrefixCallbackOp &block_prefix_callback_op) ///< [in-out] <b>[<em>warp</em><sub>0</sub> only]</b> Call-back functor for specifying a block-wide prefix to be applied to the logical input sequence.
+ {
+ InternalBlockScan(temp_storage).InclusiveScan(input, output, scan_op, block_prefix_callback_op);
+ }
+
+
+ //@} end member group
+ /******************************************************************//**
+ * \name Inclusive prefix scan operations (multiple data per thread)
+ *********************************************************************/
+ //@{
+
+
+ /**
+ * \brief Computes an inclusive block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes an array of consecutive input elements.
+ *
+ * \par
+ * - Supports non-commutative scan operators.
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates an inclusive prefix max scan of 512 integer items that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockScan for a 1D block of 128 threads on type int
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate shared memory for BlockScan
+ * __shared__ typename BlockScan::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Collectively compute the block-wide inclusive prefix max scan
+ * BlockScan(temp_storage).InclusiveScan(thread_data, thread_data, cub::Max());
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is <tt>{ [0,-1,2,-3], [4,-5,6,-7], ..., [508,-509,510,-511] }</tt>. The
+ * corresponding output \p thread_data in those threads will be <tt>{ [0,0,2,2], [4,4,6,6], ..., [508,508,510,510] }</tt>.
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam ScanOp <b>[inferred]</b> Binary scan functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ */
+ template <
+ int ITEMS_PER_THREAD,
+ typename ScanOp>
+ __device__ __forceinline__ void InclusiveScan(
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ T (&output)[ITEMS_PER_THREAD], ///< [out] Calling thread's output items (may be aliased to \p input)
+ ScanOp scan_op) ///< [in] Binary scan functor
+ {
+ if (ITEMS_PER_THREAD == 1)
+ {
+ InclusiveScan(input[0], output[0], scan_op);
+ }
+ else
+ {
+ // Reduce consecutive thread items in registers
+ T thread_prefix = internal::ThreadReduce(input, scan_op);
+
+ // Exclusive thread block-scan
+ ExclusiveScan(thread_prefix, thread_prefix, scan_op);
+
+ // Inclusive scan in registers with prefix as seed (first thread does not seed)
+ internal::ThreadScanInclusive(input, output, scan_op, thread_prefix, (linear_tid != 0));
+ }
+ }
+
+
+ /**
+ * \brief Computes an inclusive block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes an array of consecutive input elements. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ *
+ * \par
+ * - Supports non-commutative scan operators.
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates an inclusive prefix max scan of 512 integer items that
+ * are partitioned in a [<em>blocked arrangement</em>](index.html#sec5sec3) across 128 threads
+ * where each thread owns 4 consecutive items.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * __global__ void ExampleKernel(...)
+ * {
+ * // Specialize BlockScan for a 1D block of 128 threads on type int
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate shared memory for BlockScan
+ * __shared__ typename BlockScan::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Collectively compute the block-wide inclusive prefix max scan
+ * int block_aggregate;
+ * BlockScan(temp_storage).InclusiveScan(thread_data, thread_data, cub::Max(), block_aggregate);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of input \p thread_data across the block of threads is
+ * <tt>{ [0,-1,2,-3], [4,-5,6,-7], ..., [508,-509,510,-511] }</tt>.
+ * The corresponding output \p thread_data in those threads will be
+ * <tt>{ [0,0,2,2], [4,4,6,6], ..., [508,508,510,510] }</tt>.
+ * Furthermore the value \p 510 will be stored in \p block_aggregate for all threads.
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam ScanOp <b>[inferred]</b> Binary scan functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ */
+ template <
+ int ITEMS_PER_THREAD,
+ typename ScanOp>
+ __device__ __forceinline__ void InclusiveScan(
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ T (&output)[ITEMS_PER_THREAD], ///< [out] Calling thread's output items (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan functor
+ T &block_aggregate) ///< [out] block-wide aggregate reduction of input items
+ {
+ if (ITEMS_PER_THREAD == 1)
+ {
+ InclusiveScan(input[0], output[0], scan_op, block_aggregate);
+ }
+ else
+ {
+ // Reduce consecutive thread items in registers
+ T thread_prefix = internal::ThreadReduce(input, scan_op);
+
+ // Exclusive thread block-scan (with no initial value)
+ ExclusiveScan(thread_prefix, thread_prefix, scan_op, block_aggregate);
+
+ // Inclusive scan in registers with prefix as seed (first thread does not seed)
+ internal::ThreadScanInclusive(input, output, scan_op, thread_prefix, (linear_tid != 0));
+ }
+ }
+
+
+ /**
+ * \brief Computes an inclusive block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes an array of consecutive input elements. the call-back functor \p block_prefix_callback_op is invoked by the first warp in the block, and the value returned by <em>lane</em><sub>0</sub> in that warp is used as the "seed" value that logically prefixes the thread block's scan inputs. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ *
+ * \par
+ * - The \p block_prefix_callback_op functor must implement a member function <tt>T operator()(T block_aggregate)</tt>.
+ * The functor's input parameter \p block_aggregate is the same value also returned by the scan operation.
+ * The functor will be invoked by the first warp of threads in the block, however only the return value from
+ * <em>lane</em><sub>0</sub> is applied as the block-wide prefix. Can be stateful.
+ * - Supports non-commutative scan operators.
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates a single thread block that progressively
+ * computes an inclusive prefix max scan over multiple "tiles" of input using a
+ * prefix functor to maintain a running total between block-wide scans. Each tile consists
+ * of 128 integer items that are partitioned across 128 threads.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
+ *
+ * // A stateful callback functor that maintains a running prefix to be applied
+ * // during consecutive scan operations.
+ * struct BlockPrefixCallbackOp
+ * {
+ * // Running prefix
+ * int running_total;
+ *
+ * // Constructor
+ * __device__ BlockPrefixCallbackOp(int running_total) : running_total(running_total) {}
+ *
+ * // Callback operator to be entered by the first warp of threads in the block.
+ * // Thread-0 is responsible for returning a value for seeding the block-wide scan.
+ * __device__ int operator()(int block_aggregate)
+ * {
+ * int old_prefix = running_total;
+ * running_total = (block_aggregate > old_prefix) ? block_aggregate : old_prefix;
+ * return old_prefix;
+ * }
+ * };
+ *
+ * __global__ void ExampleKernel(int *d_data, int num_items, ...)
+ * {
+ * // Specialize BlockLoad, BlockStore, and BlockScan for a 1D block of 128 threads, 4 ints per thread
+ * typedef cub::BlockLoad<int*, 128, 4, BLOCK_LOAD_TRANSPOSE> BlockLoad;
+ * typedef cub::BlockStore<int, 128, 4, BLOCK_STORE_TRANSPOSE> BlockStore;
+ * typedef cub::BlockScan<int, 128> BlockScan;
+ *
+ * // Allocate aliased shared memory for BlockLoad, BlockStore, and BlockScan
+ * __shared__ union {
+ * typename BlockLoad::TempStorage load;
+ * typename BlockScan::TempStorage scan;
+ * typename BlockStore::TempStorage store;
+ * } temp_storage;
+ *
+ * // Initialize running total
+ * BlockPrefixCallbackOp prefix_op(0);
+ *
+ * // Have the block iterate over segments of items
+ * for (int block_offset = 0; block_offset < num_items; block_offset += 128 * 4)
+ * {
+ * // Load a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * BlockLoad(temp_storage.load).Load(d_data + block_offset, thread_data);
+ * CTA_SYNC();
+ *
+ * // Collectively compute the block-wide inclusive prefix max scan
+ * BlockScan(temp_storage.scan).InclusiveScan(
+ * thread_data, thread_data, cub::Max(), prefix_op);
+ * CTA_SYNC();
+ *
+ * // Store scanned items to output segment
+ * BlockStore(temp_storage.store).Store(d_data + block_offset, thread_data);
+ * CTA_SYNC();
+ * }
+ * \endcode
+ * \par
+ * Suppose the input \p d_data is <tt>0, -1, 2, -3, 4, -5, ...</tt>.
+ * The corresponding output for the first segment will be <tt>0, 0, 2, 2, 4, 4, ..., 510, 510</tt>.
+ * The output for the second segment will be <tt>512, 512, 514, 514, 516, 516, ..., 1022, 1022</tt>.
+ *
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam ScanOp <b>[inferred]</b> Binary scan functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ * \tparam BlockPrefixCallbackOp <b>[inferred]</b> Call-back functor type having member <tt>T operator()(T block_aggregate)</tt>
+ */
+ template <
+ int ITEMS_PER_THREAD,
+ typename ScanOp,
+ typename BlockPrefixCallbackOp>
+ __device__ __forceinline__ void InclusiveScan(
+ T (&input)[ITEMS_PER_THREAD], ///< [in] Calling thread's input items
+ T (&output)[ITEMS_PER_THREAD], ///< [out] Calling thread's output items (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan functor
+ BlockPrefixCallbackOp &block_prefix_callback_op) ///< [in-out] <b>[<em>warp</em><sub>0</sub> only]</b> Call-back functor for specifying a block-wide prefix to be applied to the logical input sequence.
+ {
+ if (ITEMS_PER_THREAD == 1)
+ {
+ InclusiveScan(input[0], output[0], scan_op, block_prefix_callback_op);
+ }
+ else
+ {
+ // Reduce consecutive thread items in registers
+ T thread_prefix = internal::ThreadReduce(input, scan_op);
+
+ // Exclusive thread block-scan
+ ExclusiveScan(thread_prefix, thread_prefix, scan_op, block_prefix_callback_op);
+
+ // Inclusive scan in registers with prefix as seed
+ internal::ThreadScanInclusive(input, output, scan_op, thread_prefix);
+ }
+ }
+
+ //@} end member group
+
+
+};
+
+/**
+ * \example example_block_scan.cu
+ */
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_shuffle.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_shuffle.cuh
new file mode 100644
index 0000000..a0cc71d
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_shuffle.cuh
@@ -0,0 +1,305 @@
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-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 TORT
+ * (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
+ * The cub::BlockShuffle class provides [<em>collective</em>](index.html#sec0) methods for shuffling data partitioned across a CUDA thread block.
+ */
+
+#pragma once
+
+#include "../util_arch.cuh"
+#include "../util_ptx.cuh"
+#include "../util_macro.cuh"
+#include "../util_type.cuh"
+#include "../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+/**
+ * \brief The BlockShuffle class provides [<em>collective</em>](index.html#sec0) methods for shuffling data partitioned across a CUDA thread block.
+ * \ingroup BlockModule
+ *
+ * \tparam T The data type to be exchanged.
+ * \tparam BLOCK_DIM_X The thread block length in threads along the X dimension
+ * \tparam BLOCK_DIM_Y <b>[optional]</b> The thread block length in threads along the Y dimension (default: 1)
+ * \tparam BLOCK_DIM_Z <b>[optional]</b> The thread block length in threads along the Z dimension (default: 1)
+ * \tparam PTX_ARCH <b>[optional]</b> \ptxversion
+ *
+ * \par Overview
+ * It is commonplace for blocks of threads to rearrange data items between
+ * threads. The BlockShuffle abstraction allows threads to efficiently shift items
+ * either (a) up to their successor or (b) down to their predecessor.
+ *
+ */
+template <
+ typename T,
+ int BLOCK_DIM_X,
+ int BLOCK_DIM_Y = 1,
+ int BLOCK_DIM_Z = 1,
+ int PTX_ARCH = CUB_PTX_ARCH>
+class BlockShuffle
+{
+private:
+
+ /******************************************************************************
+ * Constants
+ ******************************************************************************/
+
+ enum
+ {
+ BLOCK_THREADS = BLOCK_DIM_X * BLOCK_DIM_Y * BLOCK_DIM_Z,
+
+ LOG_WARP_THREADS = CUB_LOG_WARP_THREADS(PTX_ARCH),
+ WARP_THREADS = 1 << LOG_WARP_THREADS,
+ WARPS = (BLOCK_THREADS + WARP_THREADS - 1) / WARP_THREADS,
+ };
+
+ /******************************************************************************
+ * Type definitions
+ ******************************************************************************/
+
+ /// Shared memory storage layout type (last element from each thread's input)
+ struct _TempStorage
+ {
+ T prev[BLOCK_THREADS];
+ T next[BLOCK_THREADS];
+ };
+
+
+public:
+
+ /// \smemstorage{BlockShuffle}
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+private:
+
+
+ /******************************************************************************
+ * Thread fields
+ ******************************************************************************/
+
+ /// Shared storage reference
+ _TempStorage &temp_storage;
+
+ /// Linear thread-id
+ unsigned int linear_tid;
+
+
+ /******************************************************************************
+ * Utility methods
+ ******************************************************************************/
+
+ /// Internal storage allocator
+ __device__ __forceinline__ _TempStorage& PrivateStorage()
+ {
+ __shared__ _TempStorage private_storage;
+ return private_storage;
+ }
+
+
+public:
+
+ /******************************************************************//**
+ * \name Collective constructors
+ *********************************************************************/
+ //@{
+
+ /**
+ * \brief Collective constructor using a private static allocation of shared memory as temporary storage.
+ */
+ __device__ __forceinline__ BlockShuffle()
+ :
+ temp_storage(PrivateStorage()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ /**
+ * \brief Collective constructor using the specified memory allocation as temporary storage.
+ */
+ __device__ __forceinline__ BlockShuffle(
+ TempStorage &temp_storage) ///< [in] Reference to memory allocation having layout type TempStorage
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ //@} end member group
+ /******************************************************************//**
+ * \name Shuffle movement
+ *********************************************************************/
+ //@{
+
+
+ /**
+ * \brief Each <em>thread<sub>i</sub></em> obtains the \p input provided by <em>thread</em><sub><em>i</em>+<tt>distance</tt></sub>. The offset \p distance may be negative.
+ *
+ * \par
+ * - \smemreuse
+ */
+ __device__ __forceinline__ void Offset(
+ T input, ///< [in] The input item from the calling thread (<em>thread<sub>i</sub></em>)
+ T& output, ///< [out] The \p input item from the successor (or predecessor) thread <em>thread</em><sub><em>i</em>+<tt>distance</tt></sub> (may be aliased to \p input). This value is only updated for for <em>thread<sub>i</sub></em> when 0 <= (<em>i</em> + \p distance) < <tt>BLOCK_THREADS-1</tt>
+ int distance = 1) ///< [in] Offset distance (may be negative)
+ {
+ temp_storage[linear_tid].prev = input;
+
+ CTA_SYNC();
+
+ if ((linear_tid + distance >= 0) && (linear_tid + distance < BLOCK_THREADS))
+ output = temp_storage[linear_tid + distance].prev;
+ }
+
+
+ /**
+ * \brief Each <em>thread<sub>i</sub></em> obtains the \p input provided by <em>thread</em><sub><em>i</em>+<tt>distance</tt></sub>.
+ *
+ * \par
+ * - \smemreuse
+ */
+ __device__ __forceinline__ void Rotate(
+ T input, ///< [in] The calling thread's input item
+ T& output, ///< [out] The \p input item from thread <em>thread</em><sub>(<em>i</em>+<tt>distance></tt>)%<tt><BLOCK_THREADS></tt></sub> (may be aliased to \p input). This value is not updated for <em>thread</em><sub>BLOCK_THREADS-1</sub>
+ unsigned int distance = 1) ///< [in] Offset distance (0 < \p distance < <tt>BLOCK_THREADS</tt>)
+ {
+ temp_storage[linear_tid].prev = input;
+
+ CTA_SYNC();
+
+ unsigned int offset = threadIdx.x + distance;
+ if (offset >= BLOCK_THREADS)
+ offset -= BLOCK_THREADS;
+
+ output = temp_storage[offset].prev;
+ }
+
+
+ /**
+ * \brief The thread block rotates its [<em>blocked arrangement</em>](index.html#sec5sec3) of \p input items, shifting it up by one item
+ *
+ * \par
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ */
+ template <int ITEMS_PER_THREAD>
+ __device__ __forceinline__ void Up(
+ T (&input)[ITEMS_PER_THREAD], ///< [in] The calling thread's input items
+ T (&prev)[ITEMS_PER_THREAD]) ///< [out] The corresponding predecessor items (may be aliased to \p input). The item \p prev[0] is not updated for <em>thread</em><sub>0</sub>.
+ {
+ temp_storage[linear_tid].prev = input[ITEMS_PER_THREAD - 1];
+
+ CTA_SYNC();
+
+ #pragma unroll
+ for (int ITEM = ITEMS_PER_THREAD - 1; ITEM > 0; --ITEM)
+ prev[ITEM] = input[ITEM - 1];
+
+
+ if (linear_tid > 0)
+ prev[0] = temp_storage[linear_tid - 1].prev;
+ }
+
+
+ /**
+ * \brief The thread block rotates its [<em>blocked arrangement</em>](index.html#sec5sec3) of \p input items, shifting it up by one item. All threads receive the \p input provided by <em>thread</em><sub><tt>BLOCK_THREADS-1</tt></sub>.
+ *
+ * \par
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ */
+ template <int ITEMS_PER_THREAD>
+ __device__ __forceinline__ void Up(
+ T (&input)[ITEMS_PER_THREAD], ///< [in] The calling thread's input items
+ T (&prev)[ITEMS_PER_THREAD], ///< [out] The corresponding predecessor items (may be aliased to \p input). The item \p prev[0] is not updated for <em>thread</em><sub>0</sub>.
+ T &block_suffix) ///< [out] The item \p input[ITEMS_PER_THREAD-1] from <em>thread</em><sub><tt>BLOCK_THREADS-1</tt></sub>, provided to all threads
+ {
+ Up(input, prev);
+ block_suffix = temp_storage[BLOCK_THREADS - 1].prev;
+ }
+
+
+ /**
+ * \brief The thread block rotates its [<em>blocked arrangement</em>](index.html#sec5sec3) of \p input items, shifting it down by one item
+ *
+ * \par
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ */
+ template <int ITEMS_PER_THREAD>
+ __device__ __forceinline__ void Down(
+ T (&input)[ITEMS_PER_THREAD], ///< [in] The calling thread's input items
+ T (&prev)[ITEMS_PER_THREAD]) ///< [out] The corresponding predecessor items (may be aliased to \p input). The value \p prev[0] is not updated for <em>thread</em><sub>BLOCK_THREADS-1</sub>.
+ {
+ temp_storage[linear_tid].prev = input[ITEMS_PER_THREAD - 1];
+
+ CTA_SYNC();
+
+ #pragma unroll
+ for (int ITEM = ITEMS_PER_THREAD - 1; ITEM > 0; --ITEM)
+ prev[ITEM] = input[ITEM - 1];
+
+ if (linear_tid > 0)
+ prev[0] = temp_storage[linear_tid - 1].prev;
+ }
+
+
+ /**
+ * \brief The thread block rotates its [<em>blocked arrangement</em>](index.html#sec5sec3) of input items, shifting it down by one item. All threads receive \p input[0] provided by <em>thread</em><sub><tt>0</tt></sub>.
+ *
+ * \par
+ * - \blocked
+ * - \granularity
+ * - \smemreuse
+ */
+ template <int ITEMS_PER_THREAD>
+ __device__ __forceinline__ void Down(
+ T (&input)[ITEMS_PER_THREAD], ///< [in] The calling thread's input items
+ T (&prev)[ITEMS_PER_THREAD], ///< [out] The corresponding predecessor items (may be aliased to \p input). The value \p prev[0] is not updated for <em>thread</em><sub>BLOCK_THREADS-1</sub>.
+ T &block_prefix) ///< [out] The item \p input[0] from <em>thread</em><sub><tt>0</tt></sub>, provided to all threads
+ {
+ Up(input, prev);
+ block_prefix = temp_storage[BLOCK_THREADS - 1].prev;
+ }
+
+ //@} end member group
+
+
+};
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_store.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_store.cuh
new file mode 100644
index 0000000..648bf9f
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/block_store.cuh
@@ -0,0 +1,1000 @@
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-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 TORT
+ * (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
+ * Operations for writing linear segments of data from the CUDA thread block
+ */
+
+#pragma once
+
+#include <iterator>
+
+#include "block_exchange.cuh"
+#include "../util_ptx.cuh"
+#include "../util_macro.cuh"
+#include "../util_type.cuh"
+#include "../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+/**
+ * \addtogroup UtilIo
+ * @{
+ */
+
+
+/******************************************************************//**
+ * \name Blocked arrangement I/O (direct)
+ *********************************************************************/
+//@{
+
+/**
+ * \brief Store a blocked arrangement of items across a thread block into a linear segment of items.
+ *
+ * \blocked
+ *
+ * \tparam T <b>[inferred]</b> The data type to store.
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam OutputIteratorT <b>[inferred]</b> The random-access iterator type for output \iterator.
+ */
+template <
+ typename T,
+ int ITEMS_PER_THREAD,
+ typename OutputIteratorT>
+__device__ __forceinline__ void StoreDirectBlocked(
+ int linear_tid, ///< [in] A suitable 1D thread-identifier for the calling thread (e.g., <tt>(threadIdx.y * blockDim.x) + linear_tid</tt> for 2D thread blocks)
+ OutputIteratorT block_itr, ///< [in] The thread block's base output iterator for storing to
+ T (&items)[ITEMS_PER_THREAD]) ///< [in] Data to store
+{
+ OutputIteratorT thread_itr = block_itr + (linear_tid * ITEMS_PER_THREAD);
+
+ // Store directly in thread-blocked order
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ thread_itr[ITEM] = items[ITEM];
+ }
+}
+
+
+/**
+ * \brief Store a blocked arrangement of items across a thread block into a linear segment of items, guarded by range
+ *
+ * \blocked
+ *
+ * \tparam T <b>[inferred]</b> The data type to store.
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam OutputIteratorT <b>[inferred]</b> The random-access iterator type for output \iterator.
+ */
+template <
+ typename T,
+ int ITEMS_PER_THREAD,
+ typename OutputIteratorT>
+__device__ __forceinline__ void StoreDirectBlocked(
+ int linear_tid, ///< [in] A suitable 1D thread-identifier for the calling thread (e.g., <tt>(threadIdx.y * blockDim.x) + linear_tid</tt> for 2D thread blocks)
+ OutputIteratorT block_itr, ///< [in] The thread block's base output iterator for storing to
+ T (&items)[ITEMS_PER_THREAD], ///< [in] Data to store
+ int valid_items) ///< [in] Number of valid items to write
+{
+ OutputIteratorT thread_itr = block_itr + (linear_tid * ITEMS_PER_THREAD);
+
+ // Store directly in thread-blocked order
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ if (ITEM + (linear_tid * ITEMS_PER_THREAD) < valid_items)
+ {
+ thread_itr[ITEM] = items[ITEM];
+ }
+ }
+}
+
+
+/**
+ * \brief Store a blocked arrangement of items across a thread block into a linear segment of items.
+ *
+ * \blocked
+ *
+ * The output offset (\p block_ptr + \p block_offset) must be quad-item aligned,
+ * which is the default starting offset returned by \p cudaMalloc()
+ *
+ * \par
+ * The following conditions will prevent vectorization and storing will fall back to cub::BLOCK_STORE_DIRECT:
+ * - \p ITEMS_PER_THREAD is odd
+ * - The data type \p T is not a built-in primitive or CUDA vector type (e.g., \p short, \p int2, \p double, \p float2, etc.)
+ *
+ * \tparam T <b>[inferred]</b> The data type to store.
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ *
+ */
+template <
+ typename T,
+ int ITEMS_PER_THREAD>
+__device__ __forceinline__ void StoreDirectBlockedVectorized(
+ int linear_tid, ///< [in] A suitable 1D thread-identifier for the calling thread (e.g., <tt>(threadIdx.y * blockDim.x) + linear_tid</tt> for 2D thread blocks)
+ T *block_ptr, ///< [in] Input pointer for storing from
+ T (&items)[ITEMS_PER_THREAD]) ///< [in] Data to store
+{
+ enum
+ {
+ // Maximum CUDA vector size is 4 elements
+ MAX_VEC_SIZE = CUB_MIN(4, ITEMS_PER_THREAD),
+
+ // Vector size must be a power of two and an even divisor of the items per thread
+ VEC_SIZE = ((((MAX_VEC_SIZE - 1) & MAX_VEC_SIZE) == 0) && ((ITEMS_PER_THREAD % MAX_VEC_SIZE) == 0)) ?
+ MAX_VEC_SIZE :
+ 1,
+
+ VECTORS_PER_THREAD = ITEMS_PER_THREAD / VEC_SIZE,
+ };
+
+ // Vector type
+ typedef typename CubVector<T, VEC_SIZE>::Type Vector;
+
+ // Alias global pointer
+ Vector *block_ptr_vectors = reinterpret_cast<Vector*>(const_cast<T*>(block_ptr));
+
+ // Alias pointers (use "raw" array here which should get optimized away to prevent conservative PTXAS lmem spilling)
+ Vector raw_vector[VECTORS_PER_THREAD];
+ T *raw_items = reinterpret_cast<T*>(raw_vector);
+
+ // Copy
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ raw_items[ITEM] = items[ITEM];
+ }
+
+ // Direct-store using vector types
+ StoreDirectBlocked(linear_tid, block_ptr_vectors, raw_vector);
+}
+
+
+
+//@} end member group
+/******************************************************************//**
+ * \name Striped arrangement I/O (direct)
+ *********************************************************************/
+//@{
+
+
+/**
+ * \brief Store a striped arrangement of data across the thread block into a linear segment of items.
+ *
+ * \striped
+ *
+ * \tparam BLOCK_THREADS The thread block size in threads
+ * \tparam T <b>[inferred]</b> The data type to store.
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam OutputIteratorT <b>[inferred]</b> The random-access iterator type for output \iterator.
+ */
+template <
+ int BLOCK_THREADS,
+ typename T,
+ int ITEMS_PER_THREAD,
+ typename OutputIteratorT>
+__device__ __forceinline__ void StoreDirectStriped(
+ int linear_tid, ///< [in] A suitable 1D thread-identifier for the calling thread (e.g., <tt>(threadIdx.y * blockDim.x) + linear_tid</tt> for 2D thread blocks)
+ OutputIteratorT block_itr, ///< [in] The thread block's base output iterator for storing to
+ T (&items)[ITEMS_PER_THREAD]) ///< [in] Data to store
+{
+ OutputIteratorT thread_itr = block_itr + linear_tid;
+
+ // Store directly in striped order
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ thread_itr[(ITEM * BLOCK_THREADS)] = items[ITEM];
+ }
+}
+
+
+/**
+ * \brief Store a striped arrangement of data across the thread block into a linear segment of items, guarded by range
+ *
+ * \striped
+ *
+ * \tparam BLOCK_THREADS The thread block size in threads
+ * \tparam T <b>[inferred]</b> The data type to store.
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam OutputIteratorT <b>[inferred]</b> The random-access iterator type for output \iterator.
+ */
+template <
+ int BLOCK_THREADS,
+ typename T,
+ int ITEMS_PER_THREAD,
+ typename OutputIteratorT>
+__device__ __forceinline__ void StoreDirectStriped(
+ int linear_tid, ///< [in] A suitable 1D thread-identifier for the calling thread (e.g., <tt>(threadIdx.y * blockDim.x) + linear_tid</tt> for 2D thread blocks)
+ OutputIteratorT block_itr, ///< [in] The thread block's base output iterator for storing to
+ T (&items)[ITEMS_PER_THREAD], ///< [in] Data to store
+ int valid_items) ///< [in] Number of valid items to write
+{
+ OutputIteratorT thread_itr = block_itr + linear_tid;
+
+ // Store directly in striped order
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ if ((ITEM * BLOCK_THREADS) + linear_tid < valid_items)
+ {
+ thread_itr[(ITEM * BLOCK_THREADS)] = items[ITEM];
+ }
+ }
+}
+
+
+
+//@} end member group
+/******************************************************************//**
+ * \name Warp-striped arrangement I/O (direct)
+ *********************************************************************/
+//@{
+
+
+/**
+ * \brief Store a warp-striped arrangement of data across the thread block into a linear segment of items.
+ *
+ * \warpstriped
+ *
+ * \par Usage Considerations
+ * The number of threads in the thread block must be a multiple of the architecture's warp size.
+ *
+ * \tparam T <b>[inferred]</b> The data type to store.
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam OutputIteratorT <b>[inferred]</b> The random-access iterator type for output \iterator.
+ */
+template <
+ typename T,
+ int ITEMS_PER_THREAD,
+ typename OutputIteratorT>
+__device__ __forceinline__ void StoreDirectWarpStriped(
+ int linear_tid, ///< [in] A suitable 1D thread-identifier for the calling thread (e.g., <tt>(threadIdx.y * blockDim.x) + linear_tid</tt> for 2D thread blocks)
+ OutputIteratorT block_itr, ///< [in] The thread block's base output iterator for storing to
+ T (&items)[ITEMS_PER_THREAD]) ///< [out] Data to load
+{
+ int tid = linear_tid & (CUB_PTX_WARP_THREADS - 1);
+ int wid = linear_tid >> CUB_PTX_LOG_WARP_THREADS;
+ int warp_offset = wid * CUB_PTX_WARP_THREADS * ITEMS_PER_THREAD;
+
+ OutputIteratorT thread_itr = block_itr + warp_offset + tid;
+
+ // Store directly in warp-striped order
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ thread_itr[(ITEM * CUB_PTX_WARP_THREADS)] = items[ITEM];
+ }
+}
+
+
+/**
+ * \brief Store a warp-striped arrangement of data across the thread block into a linear segment of items, guarded by range
+ *
+ * \warpstriped
+ *
+ * \par Usage Considerations
+ * The number of threads in the thread block must be a multiple of the architecture's warp size.
+ *
+ * \tparam T <b>[inferred]</b> The data type to store.
+ * \tparam ITEMS_PER_THREAD <b>[inferred]</b> The number of consecutive items partitioned onto each thread.
+ * \tparam OutputIteratorT <b>[inferred]</b> The random-access iterator type for output \iterator.
+ */
+template <
+ typename T,
+ int ITEMS_PER_THREAD,
+ typename OutputIteratorT>
+__device__ __forceinline__ void StoreDirectWarpStriped(
+ int linear_tid, ///< [in] A suitable 1D thread-identifier for the calling thread (e.g., <tt>(threadIdx.y * blockDim.x) + linear_tid</tt> for 2D thread blocks)
+ OutputIteratorT block_itr, ///< [in] The thread block's base output iterator for storing to
+ T (&items)[ITEMS_PER_THREAD], ///< [in] Data to store
+ int valid_items) ///< [in] Number of valid items to write
+{
+ int tid = linear_tid & (CUB_PTX_WARP_THREADS - 1);
+ int wid = linear_tid >> CUB_PTX_LOG_WARP_THREADS;
+ int warp_offset = wid * CUB_PTX_WARP_THREADS * ITEMS_PER_THREAD;
+
+ OutputIteratorT thread_itr = block_itr + warp_offset + tid;
+
+ // Store directly in warp-striped order
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ if (warp_offset + tid + (ITEM * CUB_PTX_WARP_THREADS) < valid_items)
+ {
+ thread_itr[(ITEM * CUB_PTX_WARP_THREADS)] = items[ITEM];
+ }
+ }
+}
+
+
+//@} end member group
+
+
+/** @} */ // end group UtilIo
+
+
+//-----------------------------------------------------------------------------
+// Generic BlockStore abstraction
+//-----------------------------------------------------------------------------
+
+/**
+ * \brief cub::BlockStoreAlgorithm enumerates alternative algorithms for cub::BlockStore to write a blocked arrangement of items across a CUDA thread block to a linear segment of memory.
+ */
+enum BlockStoreAlgorithm
+{
+ /**
+ * \par Overview
+ *
+ * A [<em>blocked arrangement</em>](index.html#sec5sec3) of data is written
+ * directly to memory.
+ *
+ * \par Performance Considerations
+ * - The utilization of memory transactions (coalescing) decreases as the
+ * access stride between threads increases (i.e., the number items per thread).
+ */
+ BLOCK_STORE_DIRECT,
+
+ /**
+ * \par Overview
+ *
+ * A [<em>blocked arrangement</em>](index.html#sec5sec3) of data is written directly
+ * to memory using CUDA's built-in vectorized stores as a coalescing optimization.
+ * For example, <tt>st.global.v4.s32</tt> instructions will be generated
+ * when \p T = \p int and \p ITEMS_PER_THREAD % 4 == 0.
+ *
+ * \par Performance Considerations
+ * - The utilization of memory transactions (coalescing) remains high until the the
+ * access stride between threads (i.e., the number items per thread) exceeds the
+ * maximum vector store width (typically 4 items or 64B, whichever is lower).
+ * - The following conditions will prevent vectorization and writing will fall back to cub::BLOCK_STORE_DIRECT:
+ * - \p ITEMS_PER_THREAD is odd
+ * - The \p OutputIteratorT is not a simple pointer type
+ * - The block output offset is not quadword-aligned
+ * - The data type \p T is not a built-in primitive or CUDA vector type (e.g., \p short, \p int2, \p double, \p float2, etc.)
+ */
+ BLOCK_STORE_VECTORIZE,
+
+ /**
+ * \par Overview
+ * A [<em>blocked arrangement</em>](index.html#sec5sec3) is locally
+ * transposed and then efficiently written to memory as a [<em>striped arrangement</em>](index.html#sec5sec3).
+ *
+ * \par Performance Considerations
+ * - The utilization of memory transactions (coalescing) remains high regardless
+ * of items written per thread.
+ * - The local reordering incurs slightly longer latencies and throughput than the
+ * direct cub::BLOCK_STORE_DIRECT and cub::BLOCK_STORE_VECTORIZE alternatives.
+ */
+ BLOCK_STORE_TRANSPOSE,
+
+ /**
+ * \par Overview
+ * A [<em>blocked arrangement</em>](index.html#sec5sec3) is locally
+ * transposed and then efficiently written to memory as a
+ * [<em>warp-striped arrangement</em>](index.html#sec5sec3)
+ *
+ * \par Usage Considerations
+ * - BLOCK_THREADS must be a multiple of WARP_THREADS
+ *
+ * \par Performance Considerations
+ * - The utilization of memory transactions (coalescing) remains high regardless
+ * of items written per thread.
+ * - The local reordering incurs slightly longer latencies and throughput than the
+ * direct cub::BLOCK_STORE_DIRECT and cub::BLOCK_STORE_VECTORIZE alternatives.
+ */
+ BLOCK_STORE_WARP_TRANSPOSE,
+
+ /**
+ * \par Overview
+ * A [<em>blocked arrangement</em>](index.html#sec5sec3) is locally
+ * transposed and then efficiently written to memory as a
+ * [<em>warp-striped arrangement</em>](index.html#sec5sec3)
+ * To reduce the shared memory requirement, only one warp's worth of shared
+ * memory is provisioned and is subsequently time-sliced among warps.
+ *
+ * \par Usage Considerations
+ * - BLOCK_THREADS must be a multiple of WARP_THREADS
+ *
+ * \par Performance Considerations
+ * - The utilization of memory transactions (coalescing) remains high regardless
+ * of items written per thread.
+ * - Provisions less shared memory temporary storage, but incurs larger
+ * latencies than the BLOCK_STORE_WARP_TRANSPOSE alternative.
+ */
+ BLOCK_STORE_WARP_TRANSPOSE_TIMESLICED,
+
+};
+
+
+/**
+ * \brief The BlockStore class provides [<em>collective</em>](index.html#sec0) data movement methods for writing a [<em>blocked arrangement</em>](index.html#sec5sec3) of items partitioned across a CUDA thread block to a linear segment of memory. ![](block_store_logo.png)
+ * \ingroup BlockModule
+ * \ingroup UtilIo
+ *
+ * \tparam T The type of data to be written.
+ * \tparam BLOCK_DIM_X The thread block length in threads along the X dimension
+ * \tparam ITEMS_PER_THREAD The number of consecutive items partitioned onto each thread.
+ * \tparam ALGORITHM <b>[optional]</b> cub::BlockStoreAlgorithm tuning policy enumeration. default: cub::BLOCK_STORE_DIRECT.
+ * \tparam WARP_TIME_SLICING <b>[optional]</b> Whether or not only one warp's worth of shared memory should be allocated and time-sliced among block-warps during any load-related data transpositions (versus each warp having its own storage). (default: false)
+ * \tparam BLOCK_DIM_Y <b>[optional]</b> The thread block length in threads along the Y dimension (default: 1)
+ * \tparam BLOCK_DIM_Z <b>[optional]</b> The thread block length in threads along the Z dimension (default: 1)
+ * \tparam PTX_ARCH <b>[optional]</b> \ptxversion
+ *
+ * \par Overview
+ * - The BlockStore class provides a single data movement abstraction that can be specialized
+ * to implement different cub::BlockStoreAlgorithm strategies. This facilitates different
+ * performance policies for different architectures, data types, granularity sizes, etc.
+ * - BlockStore can be optionally specialized by different data movement strategies:
+ * -# <b>cub::BLOCK_STORE_DIRECT</b>. A [<em>blocked arrangement</em>](index.html#sec5sec3) of data is written
+ * directly to memory. [More...](\ref cub::BlockStoreAlgorithm)
+ * -# <b>cub::BLOCK_STORE_VECTORIZE</b>. A [<em>blocked arrangement</em>](index.html#sec5sec3)
+ * of data is written directly to memory using CUDA's built-in vectorized stores as a
+ * coalescing optimization. [More...](\ref cub::BlockStoreAlgorithm)
+ * -# <b>cub::BLOCK_STORE_TRANSPOSE</b>. A [<em>blocked arrangement</em>](index.html#sec5sec3)
+ * is locally transposed into a [<em>striped arrangement</em>](index.html#sec5sec3) which is
+ * then written to memory. [More...](\ref cub::BlockStoreAlgorithm)
+ * -# <b>cub::BLOCK_STORE_WARP_TRANSPOSE</b>. A [<em>blocked arrangement</em>](index.html#sec5sec3)
+ * is locally transposed into a [<em>warp-striped arrangement</em>](index.html#sec5sec3) which is
+ * then written to memory. [More...](\ref cub::BlockStoreAlgorithm)
+ * - \rowmajor
+ *
+ * \par A Simple Example
+ * \blockcollective{BlockStore}
+ * \par
+ * The code snippet below illustrates the storing of a "blocked" arrangement
+ * of 512 integers across 128 threads (where each thread owns 4 consecutive items)
+ * into a linear segment of memory. The store is specialized for \p BLOCK_STORE_WARP_TRANSPOSE,
+ * meaning items are locally reordered among threads so that memory references will be
+ * efficiently coalesced using a warp-striped access pattern.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_store.cuh>
+ *
+ * __global__ void ExampleKernel(int *d_data, ...)
+ * {
+ * // Specialize BlockStore for a 1D block of 128 threads owning 4 integer items each
+ * typedef cub::BlockStore<int, 128, 4, BLOCK_STORE_WARP_TRANSPOSE> BlockStore;
+ *
+ * // Allocate shared memory for BlockStore
+ * __shared__ typename BlockStore::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Store items to linear memory
+ * int thread_data[4];
+ * BlockStore(temp_storage).Store(d_data, thread_data);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of \p thread_data across the block of threads is
+ * <tt>{ [0,1,2,3], [4,5,6,7], ..., [508,509,510,511] }</tt>.
+ * The output \p d_data will be <tt>0, 1, 2, 3, 4, 5, ...</tt>.
+ *
+ */
+template <
+ typename T,
+ int BLOCK_DIM_X,
+ int ITEMS_PER_THREAD,
+ BlockStoreAlgorithm ALGORITHM = BLOCK_STORE_DIRECT,
+ int BLOCK_DIM_Y = 1,
+ int BLOCK_DIM_Z = 1,
+ int PTX_ARCH = CUB_PTX_ARCH>
+class BlockStore
+{
+private:
+ /******************************************************************************
+ * Constants and typed definitions
+ ******************************************************************************/
+
+ /// Constants
+ enum
+ {
+ /// The thread block size in threads
+ BLOCK_THREADS = BLOCK_DIM_X * BLOCK_DIM_Y * BLOCK_DIM_Z,
+ };
+
+
+ /******************************************************************************
+ * Algorithmic variants
+ ******************************************************************************/
+
+ /// Store helper
+ template <BlockStoreAlgorithm _POLICY, int DUMMY>
+ struct StoreInternal;
+
+
+ /**
+ * BLOCK_STORE_DIRECT specialization of store helper
+ */
+ template <int DUMMY>
+ struct StoreInternal<BLOCK_STORE_DIRECT, DUMMY>
+ {
+ /// Shared memory storage layout type
+ typedef NullType TempStorage;
+
+ /// Linear thread-id
+ int linear_tid;
+
+ /// Constructor
+ __device__ __forceinline__ StoreInternal(
+ TempStorage &/*temp_storage*/,
+ int linear_tid)
+ :
+ linear_tid(linear_tid)
+ {}
+
+ /// Store items into a linear segment of memory
+ template <typename OutputIteratorT>
+ __device__ __forceinline__ void Store(
+ OutputIteratorT block_itr, ///< [in] The thread block's base output iterator for storing to
+ T (&items)[ITEMS_PER_THREAD]) ///< [in] Data to store
+ {
+ StoreDirectBlocked(linear_tid, block_itr, items);
+ }
+
+ /// Store items into a linear segment of memory, guarded by range
+ template <typename OutputIteratorT>
+ __device__ __forceinline__ void Store(
+ OutputIteratorT block_itr, ///< [in] The thread block's base output iterator for storing to
+ T (&items)[ITEMS_PER_THREAD], ///< [in] Data to store
+ int valid_items) ///< [in] Number of valid items to write
+ {
+ StoreDirectBlocked(linear_tid, block_itr, items, valid_items);
+ }
+ };
+
+
+ /**
+ * BLOCK_STORE_VECTORIZE specialization of store helper
+ */
+ template <int DUMMY>
+ struct StoreInternal<BLOCK_STORE_VECTORIZE, DUMMY>
+ {
+ /// Shared memory storage layout type
+ typedef NullType TempStorage;
+
+ /// Linear thread-id
+ int linear_tid;
+
+ /// Constructor
+ __device__ __forceinline__ StoreInternal(
+ TempStorage &/*temp_storage*/,
+ int linear_tid)
+ :
+ linear_tid(linear_tid)
+ {}
+
+ /// Store items into a linear segment of memory, specialized for native pointer types (attempts vectorization)
+ __device__ __forceinline__ void Store(
+ T *block_ptr, ///< [in] The thread block's base output iterator for storing to
+ T (&items)[ITEMS_PER_THREAD]) ///< [in] Data to store
+ {
+ StoreDirectBlockedVectorized(linear_tid, block_ptr, items);
+ }
+
+ /// Store items into a linear segment of memory, specialized for opaque input iterators (skips vectorization)
+ template <typename OutputIteratorT>
+ __device__ __forceinline__ void Store(
+ OutputIteratorT block_itr, ///< [in] The thread block's base output iterator for storing to
+ T (&items)[ITEMS_PER_THREAD]) ///< [in] Data to store
+ {
+ StoreDirectBlocked(linear_tid, block_itr, items);
+ }
+
+ /// Store items into a linear segment of memory, guarded by range
+ template <typename OutputIteratorT>
+ __device__ __forceinline__ void Store(
+ OutputIteratorT block_itr, ///< [in] The thread block's base output iterator for storing to
+ T (&items)[ITEMS_PER_THREAD], ///< [in] Data to store
+ int valid_items) ///< [in] Number of valid items to write
+ {
+ StoreDirectBlocked(linear_tid, block_itr, items, valid_items);
+ }
+ };
+
+
+ /**
+ * BLOCK_STORE_TRANSPOSE specialization of store helper
+ */
+ template <int DUMMY>
+ struct StoreInternal<BLOCK_STORE_TRANSPOSE, DUMMY>
+ {
+ // BlockExchange utility type for keys
+ typedef BlockExchange<T, BLOCK_DIM_X, ITEMS_PER_THREAD, false, BLOCK_DIM_Y, BLOCK_DIM_Z, PTX_ARCH> BlockExchange;
+
+ /// Shared memory storage layout type
+ struct _TempStorage : BlockExchange::TempStorage
+ {
+ /// Temporary storage for partially-full block guard
+ volatile int valid_items;
+ };
+
+ /// Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+ /// Thread reference to shared storage
+ _TempStorage &temp_storage;
+
+ /// Linear thread-id
+ int linear_tid;
+
+ /// Constructor
+ __device__ __forceinline__ StoreInternal(
+ TempStorage &temp_storage,
+ int linear_tid)
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(linear_tid)
+ {}
+
+ /// Store items into a linear segment of memory
+ template <typename OutputIteratorT>
+ __device__ __forceinline__ void Store(
+ OutputIteratorT block_itr, ///< [in] The thread block's base output iterator for storing to
+ T (&items)[ITEMS_PER_THREAD]) ///< [in] Data to store
+ {
+ BlockExchange(temp_storage).BlockedToStriped(items);
+ StoreDirectStriped<BLOCK_THREADS>(linear_tid, block_itr, items);
+ }
+
+ /// Store items into a linear segment of memory, guarded by range
+ template <typename OutputIteratorT>
+ __device__ __forceinline__ void Store(
+ OutputIteratorT block_itr, ///< [in] The thread block's base output iterator for storing to
+ T (&items)[ITEMS_PER_THREAD], ///< [in] Data to store
+ int valid_items) ///< [in] Number of valid items to write
+ {
+ BlockExchange(temp_storage).BlockedToStriped(items);
+ if (linear_tid == 0)
+ temp_storage.valid_items = valid_items; // Move through volatile smem as a workaround to prevent RF spilling on subsequent loads
+ CTA_SYNC();
+ StoreDirectStriped<BLOCK_THREADS>(linear_tid, block_itr, items, temp_storage.valid_items);
+ }
+ };
+
+
+ /**
+ * BLOCK_STORE_WARP_TRANSPOSE specialization of store helper
+ */
+ template <int DUMMY>
+ struct StoreInternal<BLOCK_STORE_WARP_TRANSPOSE, DUMMY>
+ {
+ enum
+ {
+ WARP_THREADS = CUB_WARP_THREADS(PTX_ARCH)
+ };
+
+ // Assert BLOCK_THREADS must be a multiple of WARP_THREADS
+ CUB_STATIC_ASSERT((BLOCK_THREADS % WARP_THREADS == 0), "BLOCK_THREADS must be a multiple of WARP_THREADS");
+
+ // BlockExchange utility type for keys
+ typedef BlockExchange<T, BLOCK_DIM_X, ITEMS_PER_THREAD, false, BLOCK_DIM_Y, BLOCK_DIM_Z, PTX_ARCH> BlockExchange;
+
+ /// Shared memory storage layout type
+ struct _TempStorage : BlockExchange::TempStorage
+ {
+ /// Temporary storage for partially-full block guard
+ volatile int valid_items;
+ };
+
+ /// Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+ /// Thread reference to shared storage
+ _TempStorage &temp_storage;
+
+ /// Linear thread-id
+ int linear_tid;
+
+ /// Constructor
+ __device__ __forceinline__ StoreInternal(
+ TempStorage &temp_storage,
+ int linear_tid)
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(linear_tid)
+ {}
+
+ /// Store items into a linear segment of memory
+ template <typename OutputIteratorT>
+ __device__ __forceinline__ void Store(
+ OutputIteratorT block_itr, ///< [in] The thread block's base output iterator for storing to
+ T (&items)[ITEMS_PER_THREAD]) ///< [in] Data to store
+ {
+ BlockExchange(temp_storage).BlockedToWarpStriped(items);
+ StoreDirectWarpStriped(linear_tid, block_itr, items);
+ }
+
+ /// Store items into a linear segment of memory, guarded by range
+ template <typename OutputIteratorT>
+ __device__ __forceinline__ void Store(
+ OutputIteratorT block_itr, ///< [in] The thread block's base output iterator for storing to
+ T (&items)[ITEMS_PER_THREAD], ///< [in] Data to store
+ int valid_items) ///< [in] Number of valid items to write
+ {
+ BlockExchange(temp_storage).BlockedToWarpStriped(items);
+ if (linear_tid == 0)
+ temp_storage.valid_items = valid_items; // Move through volatile smem as a workaround to prevent RF spilling on subsequent loads
+ CTA_SYNC();
+ StoreDirectWarpStriped(linear_tid, block_itr, items, temp_storage.valid_items);
+ }
+ };
+
+
+ /**
+ * BLOCK_STORE_WARP_TRANSPOSE_TIMESLICED specialization of store helper
+ */
+ template <int DUMMY>
+ struct StoreInternal<BLOCK_STORE_WARP_TRANSPOSE_TIMESLICED, DUMMY>
+ {
+ enum
+ {
+ WARP_THREADS = CUB_WARP_THREADS(PTX_ARCH)
+ };
+
+ // Assert BLOCK_THREADS must be a multiple of WARP_THREADS
+ CUB_STATIC_ASSERT((BLOCK_THREADS % WARP_THREADS == 0), "BLOCK_THREADS must be a multiple of WARP_THREADS");
+
+ // BlockExchange utility type for keys
+ typedef BlockExchange<T, BLOCK_DIM_X, ITEMS_PER_THREAD, true, BLOCK_DIM_Y, BLOCK_DIM_Z, PTX_ARCH> BlockExchange;
+
+ /// Shared memory storage layout type
+ struct _TempStorage : BlockExchange::TempStorage
+ {
+ /// Temporary storage for partially-full block guard
+ volatile int valid_items;
+ };
+
+ /// Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+ /// Thread reference to shared storage
+ _TempStorage &temp_storage;
+
+ /// Linear thread-id
+ int linear_tid;
+
+ /// Constructor
+ __device__ __forceinline__ StoreInternal(
+ TempStorage &temp_storage,
+ int linear_tid)
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(linear_tid)
+ {}
+
+ /// Store items into a linear segment of memory
+ template <typename OutputIteratorT>
+ __device__ __forceinline__ void Store(
+ OutputIteratorT block_itr, ///< [in] The thread block's base output iterator for storing to
+ T (&items)[ITEMS_PER_THREAD]) ///< [in] Data to store
+ {
+ BlockExchange(temp_storage).BlockedToWarpStriped(items);
+ StoreDirectWarpStriped(linear_tid, block_itr, items);
+ }
+
+ /// Store items into a linear segment of memory, guarded by range
+ template <typename OutputIteratorT>
+ __device__ __forceinline__ void Store(
+ OutputIteratorT block_itr, ///< [in] The thread block's base output iterator for storing to
+ T (&items)[ITEMS_PER_THREAD], ///< [in] Data to store
+ int valid_items) ///< [in] Number of valid items to write
+ {
+ BlockExchange(temp_storage).BlockedToWarpStriped(items);
+ if (linear_tid == 0)
+ temp_storage.valid_items = valid_items; // Move through volatile smem as a workaround to prevent RF spilling on subsequent loads
+ CTA_SYNC();
+ StoreDirectWarpStriped(linear_tid, block_itr, items, temp_storage.valid_items);
+ }
+ };
+
+ /******************************************************************************
+ * Type definitions
+ ******************************************************************************/
+
+ /// Internal load implementation to use
+ typedef StoreInternal<ALGORITHM, 0> InternalStore;
+
+
+ /// Shared memory storage layout type
+ typedef typename InternalStore::TempStorage _TempStorage;
+
+
+ /******************************************************************************
+ * Utility methods
+ ******************************************************************************/
+
+ /// Internal storage allocator
+ __device__ __forceinline__ _TempStorage& PrivateStorage()
+ {
+ __shared__ _TempStorage private_storage;
+ return private_storage;
+ }
+
+
+ /******************************************************************************
+ * Thread fields
+ ******************************************************************************/
+
+ /// Thread reference to shared storage
+ _TempStorage &temp_storage;
+
+ /// Linear thread-id
+ int linear_tid;
+
+public:
+
+
+ /// \smemstorage{BlockStore}
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ /******************************************************************//**
+ * \name Collective constructors
+ *********************************************************************/
+ //@{
+
+ /**
+ * \brief Collective constructor using a private static allocation of shared memory as temporary storage.
+ */
+ __device__ __forceinline__ BlockStore()
+ :
+ temp_storage(PrivateStorage()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ /**
+ * \brief Collective constructor using the specified memory allocation as temporary storage.
+ */
+ __device__ __forceinline__ BlockStore(
+ TempStorage &temp_storage) ///< [in] Reference to memory allocation having layout type TempStorage
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ //@} end member group
+ /******************************************************************//**
+ * \name Data movement
+ *********************************************************************/
+ //@{
+
+
+ /**
+ * \brief Store items into a linear segment of memory.
+ *
+ * \par
+ * - \blocked
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates the storing of a "blocked" arrangement
+ * of 512 integers across 128 threads (where each thread owns 4 consecutive items)
+ * into a linear segment of memory. The store is specialized for \p BLOCK_STORE_WARP_TRANSPOSE,
+ * meaning items are locally reordered among threads so that memory references will be
+ * efficiently coalesced using a warp-striped access pattern.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_store.cuh>
+ *
+ * __global__ void ExampleKernel(int *d_data, ...)
+ * {
+ * // Specialize BlockStore for a 1D block of 128 threads owning 4 integer items each
+ * typedef cub::BlockStore<int, 128, 4, BLOCK_STORE_WARP_TRANSPOSE> BlockStore;
+ *
+ * // Allocate shared memory for BlockStore
+ * __shared__ typename BlockStore::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Store items to linear memory
+ * int thread_data[4];
+ * BlockStore(temp_storage).Store(d_data, thread_data);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of \p thread_data across the block of threads is
+ * <tt>{ [0,1,2,3], [4,5,6,7], ..., [508,509,510,511] }</tt>.
+ * The output \p d_data will be <tt>0, 1, 2, 3, 4, 5, ...</tt>.
+ *
+ */
+ template <typename OutputIteratorT>
+ __device__ __forceinline__ void Store(
+ OutputIteratorT block_itr, ///< [in] The thread block's base output iterator for storing to
+ T (&items)[ITEMS_PER_THREAD]) ///< [in] Data to store
+ {
+ InternalStore(temp_storage, linear_tid).Store(block_itr, items);
+ }
+
+ /**
+ * \brief Store items into a linear segment of memory, guarded by range.
+ *
+ * \par
+ * - \blocked
+ * - \smemreuse
+ *
+ * \par Snippet
+ * The code snippet below illustrates the guarded storing of a "blocked" arrangement
+ * of 512 integers across 128 threads (where each thread owns 4 consecutive items)
+ * into a linear segment of memory. The store is specialized for \p BLOCK_STORE_WARP_TRANSPOSE,
+ * meaning items are locally reordered among threads so that memory references will be
+ * efficiently coalesced using a warp-striped access pattern.
+ * \par
+ * \code
+ * #include <cub/cub.cuh> // or equivalently <cub/block/block_store.cuh>
+ *
+ * __global__ void ExampleKernel(int *d_data, int valid_items, ...)
+ * {
+ * // Specialize BlockStore for a 1D block of 128 threads owning 4 integer items each
+ * typedef cub::BlockStore<int, 128, 4, BLOCK_STORE_WARP_TRANSPOSE> BlockStore;
+ *
+ * // Allocate shared memory for BlockStore
+ * __shared__ typename BlockStore::TempStorage temp_storage;
+ *
+ * // Obtain a segment of consecutive items that are blocked across threads
+ * int thread_data[4];
+ * ...
+ *
+ * // Store items to linear memory
+ * int thread_data[4];
+ * BlockStore(temp_storage).Store(d_data, thread_data, valid_items);
+ *
+ * \endcode
+ * \par
+ * Suppose the set of \p thread_data across the block of threads is
+ * <tt>{ [0,1,2,3], [4,5,6,7], ..., [508,509,510,511] }</tt> and \p valid_items is \p 5.
+ * The output \p d_data will be <tt>0, 1, 2, 3, 4, ?, ?, ?, ...</tt>, with
+ * only the first two threads being unmasked to store portions of valid data.
+ *
+ */
+ template <typename OutputIteratorT>
+ __device__ __forceinline__ void Store(
+ OutputIteratorT block_itr, ///< [in] The thread block's base output iterator for storing to
+ T (&items)[ITEMS_PER_THREAD], ///< [in] Data to store
+ int valid_items) ///< [in] Number of valid items to write
+ {
+ InternalStore(temp_storage, linear_tid).Store(block_itr, items, valid_items);
+ }
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_histogram_atomic.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_histogram_atomic.cuh
new file mode 100644
index 0000000..29db0df
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_histogram_atomic.cuh
@@ -0,0 +1,82 @@
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-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 TORT
+ * (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
+ * The cub::BlockHistogramAtomic class provides atomic-based methods for constructing block-wide histograms from data samples partitioned across a CUDA thread block.
+ */
+
+#pragma once
+
+#include "../../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+/**
+ * \brief The BlockHistogramAtomic class provides atomic-based methods for constructing block-wide histograms from data samples partitioned across a CUDA thread block.
+ */
+template <int BINS>
+struct BlockHistogramAtomic
+{
+ /// Shared memory storage layout type
+ struct TempStorage {};
+
+
+ /// Constructor
+ __device__ __forceinline__ BlockHistogramAtomic(
+ TempStorage &temp_storage)
+ {}
+
+
+ /// Composite data onto an existing histogram
+ template <
+ typename T,
+ typename CounterT,
+ int ITEMS_PER_THREAD>
+ __device__ __forceinline__ void Composite(
+ T (&items)[ITEMS_PER_THREAD], ///< [in] Calling thread's input values to histogram
+ CounterT histogram[BINS]) ///< [out] Reference to shared/device-accessible memory histogram
+ {
+ // Update histogram
+ #pragma unroll
+ for (int i = 0; i < ITEMS_PER_THREAD; ++i)
+ {
+ atomicAdd(histogram + items[i], 1);
+ }
+ }
+
+};
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_histogram_sort.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_histogram_sort.cuh
new file mode 100644
index 0000000..9ef417a
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_histogram_sort.cuh
@@ -0,0 +1,226 @@
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-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 TORT
+ * (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
+ * The cub::BlockHistogramSort class provides sorting-based methods for constructing block-wide histograms from data samples partitioned across a CUDA thread block.
+ */
+
+#pragma once
+
+#include "../../block/block_radix_sort.cuh"
+#include "../../block/block_discontinuity.cuh"
+#include "../../util_ptx.cuh"
+#include "../../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+
+/**
+ * \brief The BlockHistogramSort class provides sorting-based methods for constructing block-wide histograms from data samples partitioned across a CUDA thread block.
+ */
+template <
+ typename T, ///< Sample type
+ int BLOCK_DIM_X, ///< The thread block length in threads along the X dimension
+ int ITEMS_PER_THREAD, ///< The number of samples per thread
+ int BINS, ///< The number of bins into which histogram samples may fall
+ int BLOCK_DIM_Y, ///< The thread block length in threads along the Y dimension
+ int BLOCK_DIM_Z, ///< The thread block length in threads along the Z dimension
+ int PTX_ARCH> ///< The PTX compute capability for which to to specialize this collective
+struct BlockHistogramSort
+{
+ /// Constants
+ enum
+ {
+ /// The thread block size in threads
+ BLOCK_THREADS = BLOCK_DIM_X * BLOCK_DIM_Y * BLOCK_DIM_Z,
+ };
+
+ // Parameterize BlockRadixSort type for our thread block
+ typedef BlockRadixSort<
+ T,
+ BLOCK_DIM_X,
+ ITEMS_PER_THREAD,
+ NullType,
+ 4,
+ (PTX_ARCH >= 350) ? true : false,
+ BLOCK_SCAN_WARP_SCANS,
+ cudaSharedMemBankSizeFourByte,
+ BLOCK_DIM_Y,
+ BLOCK_DIM_Z,
+ PTX_ARCH>
+ BlockRadixSortT;
+
+ // Parameterize BlockDiscontinuity type for our thread block
+ typedef BlockDiscontinuity<
+ T,
+ BLOCK_DIM_X,
+ BLOCK_DIM_Y,
+ BLOCK_DIM_Z,
+ PTX_ARCH>
+ BlockDiscontinuityT;
+
+ /// Shared memory
+ union _TempStorage
+ {
+ // Storage for sorting bin values
+ typename BlockRadixSortT::TempStorage sort;
+
+ struct
+ {
+ // Storage for detecting discontinuities in the tile of sorted bin values
+ typename BlockDiscontinuityT::TempStorage flag;
+
+ // Storage for noting begin/end offsets of bin runs in the tile of sorted bin values
+ unsigned int run_begin[BINS];
+ unsigned int run_end[BINS];
+ };
+ };
+
+
+ /// Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ // Thread fields
+ _TempStorage &temp_storage;
+ unsigned int linear_tid;
+
+
+ /// Constructor
+ __device__ __forceinline__ BlockHistogramSort(
+ TempStorage &temp_storage)
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ // Discontinuity functor
+ struct DiscontinuityOp
+ {
+ // Reference to temp_storage
+ _TempStorage &temp_storage;
+
+ // Constructor
+ __device__ __forceinline__ DiscontinuityOp(_TempStorage &temp_storage) :
+ temp_storage(temp_storage)
+ {}
+
+ // Discontinuity predicate
+ __device__ __forceinline__ bool operator()(const T &a, const T &b, int b_index)
+ {
+ if (a != b)
+ {
+ // Note the begin/end offsets in shared storage
+ temp_storage.run_begin[b] = b_index;
+ temp_storage.run_end[a] = b_index;
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ };
+
+
+ // Composite data onto an existing histogram
+ template <
+ typename CounterT >
+ __device__ __forceinline__ void Composite(
+ T (&items)[ITEMS_PER_THREAD], ///< [in] Calling thread's input values to histogram
+ CounterT histogram[BINS]) ///< [out] Reference to shared/device-accessible memory histogram
+ {
+ enum { TILE_SIZE = BLOCK_THREADS * ITEMS_PER_THREAD };
+
+ // Sort bytes in blocked arrangement
+ BlockRadixSortT(temp_storage.sort).Sort(items);
+
+ CTA_SYNC();
+
+ // Initialize the shared memory's run_begin and run_end for each bin
+ int histo_offset = 0;
+
+ #pragma unroll
+ for(; histo_offset + BLOCK_THREADS <= BINS; histo_offset += BLOCK_THREADS)
+ {
+ temp_storage.run_begin[histo_offset + linear_tid] = TILE_SIZE;
+ temp_storage.run_end[histo_offset + linear_tid] = TILE_SIZE;
+ }
+ // Finish up with guarded initialization if necessary
+ if ((BINS % BLOCK_THREADS != 0) && (histo_offset + linear_tid < BINS))
+ {
+ temp_storage.run_begin[histo_offset + linear_tid] = TILE_SIZE;
+ temp_storage.run_end[histo_offset + linear_tid] = TILE_SIZE;
+ }
+
+ CTA_SYNC();
+
+ int flags[ITEMS_PER_THREAD]; // unused
+
+ // Compute head flags to demarcate contiguous runs of the same bin in the sorted tile
+ DiscontinuityOp flag_op(temp_storage);
+ BlockDiscontinuityT(temp_storage.flag).FlagHeads(flags, items, flag_op);
+
+ // Update begin for first item
+ if (linear_tid == 0) temp_storage.run_begin[items[0]] = 0;
+
+ CTA_SYNC();
+
+ // Composite into histogram
+ histo_offset = 0;
+
+ #pragma unroll
+ for(; histo_offset + BLOCK_THREADS <= BINS; histo_offset += BLOCK_THREADS)
+ {
+ int thread_offset = histo_offset + linear_tid;
+ CounterT count = temp_storage.run_end[thread_offset] - temp_storage.run_begin[thread_offset];
+ histogram[thread_offset] += count;
+ }
+
+ // Finish up with guarded composition if necessary
+ if ((BINS % BLOCK_THREADS != 0) && (histo_offset + linear_tid < BINS))
+ {
+ int thread_offset = histo_offset + linear_tid;
+ CounterT count = temp_storage.run_end[thread_offset] - temp_storage.run_begin[thread_offset];
+ histogram[thread_offset] += count;
+ }
+ }
+
+};
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_reduce_raking.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_reduce_raking.cuh
new file mode 100644
index 0000000..aff97fc
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_reduce_raking.cuh
@@ -0,0 +1,226 @@
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-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 TORT
+ * (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
+ * cub::BlockReduceRaking provides raking-based methods of parallel reduction across a CUDA thread block. Supports non-commutative reduction operators.
+ */
+
+#pragma once
+
+#include "../../block/block_raking_layout.cuh"
+#include "../../warp/warp_reduce.cuh"
+#include "../../thread/thread_reduce.cuh"
+#include "../../util_ptx.cuh"
+#include "../../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+/**
+ * \brief BlockReduceRaking provides raking-based methods of parallel reduction across a CUDA thread block. Supports non-commutative reduction operators.
+ *
+ * Supports non-commutative binary reduction operators. Unlike commutative
+ * reduction operators (e.g., addition), the application of a non-commutative
+ * reduction operator (e.g, string concatenation) across a sequence of inputs must
+ * honor the relative ordering of items and partial reductions when applying the
+ * reduction operator.
+ *
+ * Compared to the implementation of BlockReduceRaking (which does not support
+ * non-commutative operators), this implementation requires a few extra
+ * rounds of inter-thread communication.
+ */
+template <
+ typename T, ///< Data type being reduced
+ int BLOCK_DIM_X, ///< The thread block length in threads along the X dimension
+ int BLOCK_DIM_Y, ///< The thread block length in threads along the Y dimension
+ int BLOCK_DIM_Z, ///< The thread block length in threads along the Z dimension
+ int PTX_ARCH> ///< The PTX compute capability for which to to specialize this collective
+struct BlockReduceRaking
+{
+ /// Constants
+ enum
+ {
+ /// The thread block size in threads
+ BLOCK_THREADS = BLOCK_DIM_X * BLOCK_DIM_Y * BLOCK_DIM_Z,
+ };
+
+ /// Layout type for padded thread block raking grid
+ typedef BlockRakingLayout<T, BLOCK_THREADS, PTX_ARCH> BlockRakingLayout;
+
+ /// WarpReduce utility type
+ typedef typename WarpReduce<T, BlockRakingLayout::RAKING_THREADS, PTX_ARCH>::InternalWarpReduce WarpReduce;
+
+ /// Constants
+ enum
+ {
+ /// Number of raking threads
+ RAKING_THREADS = BlockRakingLayout::RAKING_THREADS,
+
+ /// Number of raking elements per warp synchronous raking thread
+ SEGMENT_LENGTH = BlockRakingLayout::SEGMENT_LENGTH,
+
+ /// Cooperative work can be entirely warp synchronous
+ WARP_SYNCHRONOUS = (RAKING_THREADS == BLOCK_THREADS),
+
+ /// Whether or not warp-synchronous reduction should be unguarded (i.e., the warp-reduction elements is a power of two
+ WARP_SYNCHRONOUS_UNGUARDED = PowerOfTwo<RAKING_THREADS>::VALUE,
+
+ /// Whether or not accesses into smem are unguarded
+ RAKING_UNGUARDED = BlockRakingLayout::UNGUARDED,
+
+ };
+
+
+ /// Shared memory storage layout type
+ union _TempStorage
+ {
+ typename WarpReduce::TempStorage warp_storage; ///< Storage for warp-synchronous reduction
+ typename BlockRakingLayout::TempStorage raking_grid; ///< Padded thread block raking grid
+ };
+
+
+ /// Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ // Thread fields
+ _TempStorage &temp_storage;
+ unsigned int linear_tid;
+
+
+ /// Constructor
+ __device__ __forceinline__ BlockReduceRaking(
+ TempStorage &temp_storage)
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ template <bool IS_FULL_TILE, typename ReductionOp, int ITERATION>
+ __device__ __forceinline__ T RakingReduction(
+ ReductionOp reduction_op, ///< [in] Binary scan operator
+ T *raking_segment,
+ T partial, ///< [in] <b>[<em>lane</em><sub>0</sub> only]</b> Warp-wide aggregate reduction of input items
+ int num_valid, ///< [in] Number of valid elements (may be less than BLOCK_THREADS)
+ Int2Type<ITERATION> /*iteration*/)
+ {
+ // Update partial if addend is in range
+ if ((IS_FULL_TILE && RAKING_UNGUARDED) || ((linear_tid * SEGMENT_LENGTH) + ITERATION < num_valid))
+ {
+ T addend = raking_segment[ITERATION];
+ partial = reduction_op(partial, addend);
+ }
+ return RakingReduction<IS_FULL_TILE>(reduction_op, raking_segment, partial, num_valid, Int2Type<ITERATION + 1>());
+ }
+
+ template <bool IS_FULL_TILE, typename ReductionOp>
+ __device__ __forceinline__ T RakingReduction(
+ ReductionOp /*reduction_op*/, ///< [in] Binary scan operator
+ T * /*raking_segment*/,
+ T partial, ///< [in] <b>[<em>lane</em><sub>0</sub> only]</b> Warp-wide aggregate reduction of input items
+ int /*num_valid*/, ///< [in] Number of valid elements (may be less than BLOCK_THREADS)
+ Int2Type<SEGMENT_LENGTH> /*iteration*/)
+ {
+ return partial;
+ }
+
+
+
+ /// Computes a thread block-wide reduction using the specified reduction operator. The first num_valid threads each contribute one reduction partial. The return value is only valid for thread<sub>0</sub>.
+ template <
+ bool IS_FULL_TILE,
+ typename ReductionOp>
+ __device__ __forceinline__ T Reduce(
+ T partial, ///< [in] Calling thread's input partial reductions
+ int num_valid, ///< [in] Number of valid elements (may be less than BLOCK_THREADS)
+ ReductionOp reduction_op) ///< [in] Binary reduction operator
+ {
+ if (WARP_SYNCHRONOUS)
+ {
+ // Short-circuit directly to warp synchronous reduction (unguarded if active threads is a power-of-two)
+ partial = WarpReduce(temp_storage.warp_storage).template Reduce<IS_FULL_TILE>(
+ partial,
+ num_valid,
+ reduction_op);
+ }
+ else
+ {
+ // Place partial into shared memory grid.
+ *BlockRakingLayout::PlacementPtr(temp_storage.raking_grid, linear_tid) = partial;
+
+ CTA_SYNC();
+
+ // Reduce parallelism to one warp
+ if (linear_tid < RAKING_THREADS)
+ {
+ // Raking reduction in grid
+ T *raking_segment = BlockRakingLayout::RakingPtr(temp_storage.raking_grid, linear_tid);
+ partial = raking_segment[0];
+
+ partial = RakingReduction<IS_FULL_TILE>(reduction_op, raking_segment, partial, num_valid, Int2Type<1>());
+
+ int valid_raking_threads = (IS_FULL_TILE) ?
+ RAKING_THREADS :
+ (num_valid + SEGMENT_LENGTH - 1) / SEGMENT_LENGTH;
+
+ partial = WarpReduce(temp_storage.warp_storage).template Reduce<IS_FULL_TILE && RAKING_UNGUARDED>(
+ partial,
+ valid_raking_threads,
+ reduction_op);
+
+ }
+ }
+
+ return partial;
+ }
+
+
+ /// Computes a thread block-wide reduction using addition (+) as the reduction operator. The first num_valid threads each contribute one reduction partial. The return value is only valid for thread<sub>0</sub>.
+ template <bool IS_FULL_TILE>
+ __device__ __forceinline__ T Sum(
+ T partial, ///< [in] Calling thread's input partial reductions
+ int num_valid) ///< [in] Number of valid elements (may be less than BLOCK_THREADS)
+ {
+ cub::Sum reduction_op;
+
+ return Reduce<IS_FULL_TILE>(partial, num_valid, reduction_op);
+ }
+
+
+
+};
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_reduce_raking_commutative_only.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_reduce_raking_commutative_only.cuh
new file mode 100644
index 0000000..454fdaf
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_reduce_raking_commutative_only.cuh
@@ -0,0 +1,199 @@
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-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 TORT
+ * (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
+ * cub::BlockReduceRakingCommutativeOnly provides raking-based methods of parallel reduction across a CUDA thread block. Does not support non-commutative reduction operators.
+ */
+
+#pragma once
+
+#include "block_reduce_raking.cuh"
+#include "../../warp/warp_reduce.cuh"
+#include "../../thread/thread_reduce.cuh"
+#include "../../util_ptx.cuh"
+#include "../../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+/**
+ * \brief BlockReduceRakingCommutativeOnly provides raking-based methods of parallel reduction across a CUDA thread block. Does not support non-commutative reduction operators. Does not support block sizes that are not a multiple of the warp size.
+ */
+template <
+ typename T, ///< Data type being reduced
+ int BLOCK_DIM_X, ///< The thread block length in threads along the X dimension
+ int BLOCK_DIM_Y, ///< The thread block length in threads along the Y dimension
+ int BLOCK_DIM_Z, ///< The thread block length in threads along the Z dimension
+ int PTX_ARCH> ///< The PTX compute capability for which to to specialize this collective
+struct BlockReduceRakingCommutativeOnly
+{
+ /// Constants
+ enum
+ {
+ /// The thread block size in threads
+ BLOCK_THREADS = BLOCK_DIM_X * BLOCK_DIM_Y * BLOCK_DIM_Z,
+ };
+
+ // The fall-back implementation to use when BLOCK_THREADS is not a multiple of the warp size or not all threads have valid values
+ typedef BlockReduceRaking<T, BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z, PTX_ARCH> FallBack;
+
+ /// Constants
+ enum
+ {
+ /// Number of warp threads
+ WARP_THREADS = CUB_WARP_THREADS(PTX_ARCH),
+
+ /// Whether or not to use fall-back
+ USE_FALLBACK = ((BLOCK_THREADS % WARP_THREADS != 0) || (BLOCK_THREADS <= WARP_THREADS)),
+
+ /// Number of raking threads
+ RAKING_THREADS = WARP_THREADS,
+
+ /// Number of threads actually sharing items with the raking threads
+ SHARING_THREADS = CUB_MAX(1, BLOCK_THREADS - RAKING_THREADS),
+
+ /// Number of raking elements per warp synchronous raking thread
+ SEGMENT_LENGTH = SHARING_THREADS / WARP_THREADS,
+ };
+
+ /// WarpReduce utility type
+ typedef WarpReduce<T, RAKING_THREADS, PTX_ARCH> WarpReduce;
+
+ /// Layout type for padded thread block raking grid
+ typedef BlockRakingLayout<T, SHARING_THREADS, PTX_ARCH> BlockRakingLayout;
+
+ /// Shared memory storage layout type
+ union _TempStorage
+ {
+ struct
+ {
+ typename WarpReduce::TempStorage warp_storage; ///< Storage for warp-synchronous reduction
+ typename BlockRakingLayout::TempStorage raking_grid; ///< Padded thread block raking grid
+ };
+ typename FallBack::TempStorage fallback_storage; ///< Fall-back storage for non-commutative block scan
+ };
+
+
+ /// Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ // Thread fields
+ _TempStorage &temp_storage;
+ unsigned int linear_tid;
+
+
+ /// Constructor
+ __device__ __forceinline__ BlockReduceRakingCommutativeOnly(
+ TempStorage &temp_storage)
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ /// Computes a thread block-wide reduction using addition (+) as the reduction operator. The first num_valid threads each contribute one reduction partial. The return value is only valid for thread<sub>0</sub>.
+ template <bool FULL_TILE>
+ __device__ __forceinline__ T Sum(
+ T partial, ///< [in] Calling thread's input partial reductions
+ int num_valid) ///< [in] Number of valid elements (may be less than BLOCK_THREADS)
+ {
+ if (USE_FALLBACK || !FULL_TILE)
+ {
+ return FallBack(temp_storage.fallback_storage).template Sum<FULL_TILE>(partial, num_valid);
+ }
+ else
+ {
+ // Place partial into shared memory grid
+ if (linear_tid >= RAKING_THREADS)
+ *BlockRakingLayout::PlacementPtr(temp_storage.raking_grid, linear_tid - RAKING_THREADS) = partial;
+
+ CTA_SYNC();
+
+ // Reduce parallelism to one warp
+ if (linear_tid < RAKING_THREADS)
+ {
+ // Raking reduction in grid
+ T *raking_segment = BlockRakingLayout::RakingPtr(temp_storage.raking_grid, linear_tid);
+ partial = internal::ThreadReduce<SEGMENT_LENGTH>(raking_segment, cub::Sum(), partial);
+
+ // Warpscan
+ partial = WarpReduce(temp_storage.warp_storage).Sum(partial);
+ }
+ }
+
+ return partial;
+ }
+
+
+ /// Computes a thread block-wide reduction using the specified reduction operator. The first num_valid threads each contribute one reduction partial. The return value is only valid for thread<sub>0</sub>.
+ template <
+ bool FULL_TILE,
+ typename ReductionOp>
+ __device__ __forceinline__ T Reduce(
+ T partial, ///< [in] Calling thread's input partial reductions
+ int num_valid, ///< [in] Number of valid elements (may be less than BLOCK_THREADS)
+ ReductionOp reduction_op) ///< [in] Binary reduction operator
+ {
+ if (USE_FALLBACK || !FULL_TILE)
+ {
+ return FallBack(temp_storage.fallback_storage).template Reduce<FULL_TILE>(partial, num_valid, reduction_op);
+ }
+ else
+ {
+ // Place partial into shared memory grid
+ if (linear_tid >= RAKING_THREADS)
+ *BlockRakingLayout::PlacementPtr(temp_storage.raking_grid, linear_tid - RAKING_THREADS) = partial;
+
+ CTA_SYNC();
+
+ // Reduce parallelism to one warp
+ if (linear_tid < RAKING_THREADS)
+ {
+ // Raking reduction in grid
+ T *raking_segment = BlockRakingLayout::RakingPtr(temp_storage.raking_grid, linear_tid);
+ partial = internal::ThreadReduce<SEGMENT_LENGTH>(raking_segment, reduction_op, partial);
+
+ // Warpscan
+ partial = WarpReduce(temp_storage.warp_storage).Reduce(partial, reduction_op);
+ }
+ }
+
+ return partial;
+ }
+
+};
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_reduce_warp_reductions.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_reduce_warp_reductions.cuh
new file mode 100644
index 0000000..10ba303
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_reduce_warp_reductions.cuh
@@ -0,0 +1,218 @@
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-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 TORT
+ * (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
+ * cub::BlockReduceWarpReductions provides variants of warp-reduction-based parallel reduction across a CUDA thread block. Supports non-commutative reduction operators.
+ */
+
+#pragma once
+
+#include "../../warp/warp_reduce.cuh"
+#include "../../util_ptx.cuh"
+#include "../../util_arch.cuh"
+#include "../../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+/**
+ * \brief BlockReduceWarpReductions provides variants of warp-reduction-based parallel reduction across a CUDA thread block. Supports non-commutative reduction operators.
+ */
+template <
+ typename T, ///< Data type being reduced
+ int BLOCK_DIM_X, ///< The thread block length in threads along the X dimension
+ int BLOCK_DIM_Y, ///< The thread block length in threads along the Y dimension
+ int BLOCK_DIM_Z, ///< The thread block length in threads along the Z dimension
+ int PTX_ARCH> ///< The PTX compute capability for which to to specialize this collective
+struct BlockReduceWarpReductions
+{
+ /// Constants
+ enum
+ {
+ /// The thread block size in threads
+ BLOCK_THREADS = BLOCK_DIM_X * BLOCK_DIM_Y * BLOCK_DIM_Z,
+
+ /// Number of warp threads
+ WARP_THREADS = CUB_WARP_THREADS(PTX_ARCH),
+
+ /// Number of active warps
+ WARPS = (BLOCK_THREADS + WARP_THREADS - 1) / WARP_THREADS,
+
+ /// The logical warp size for warp reductions
+ LOGICAL_WARP_SIZE = CUB_MIN(BLOCK_THREADS, WARP_THREADS),
+
+ /// Whether or not the logical warp size evenly divides the thread block size
+ EVEN_WARP_MULTIPLE = (BLOCK_THREADS % LOGICAL_WARP_SIZE == 0)
+ };
+
+
+ /// WarpReduce utility type
+ typedef typename WarpReduce<T, LOGICAL_WARP_SIZE, PTX_ARCH>::InternalWarpReduce WarpReduce;
+
+
+ /// Shared memory storage layout type
+ struct _TempStorage
+ {
+ typename WarpReduce::TempStorage warp_reduce[WARPS]; ///< Buffer for warp-synchronous scan
+ T warp_aggregates[WARPS]; ///< Shared totals from each warp-synchronous scan
+ T block_prefix; ///< Shared prefix for the entire thread block
+ };
+
+ /// Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ // Thread fields
+ _TempStorage &temp_storage;
+ int linear_tid;
+ int warp_id;
+ int lane_id;
+
+
+ /// Constructor
+ __device__ __forceinline__ BlockReduceWarpReductions(
+ TempStorage &temp_storage)
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z)),
+ warp_id((WARPS == 1) ? 0 : linear_tid / WARP_THREADS),
+ lane_id(LaneId())
+ {}
+
+
+ template <bool FULL_TILE, typename ReductionOp, int SUCCESSOR_WARP>
+ __device__ __forceinline__ T ApplyWarpAggregates(
+ ReductionOp reduction_op, ///< [in] Binary scan operator
+ T warp_aggregate, ///< [in] <b>[<em>lane</em><sub>0</sub> only]</b> Warp-wide aggregate reduction of input items
+ int num_valid, ///< [in] Number of valid elements (may be less than BLOCK_THREADS)
+ Int2Type<SUCCESSOR_WARP> /*successor_warp*/)
+ {
+ if (FULL_TILE || (SUCCESSOR_WARP * LOGICAL_WARP_SIZE < num_valid))
+ {
+ T addend = temp_storage.warp_aggregates[SUCCESSOR_WARP];
+ warp_aggregate = reduction_op(warp_aggregate, addend);
+ }
+ return ApplyWarpAggregates<FULL_TILE>(reduction_op, warp_aggregate, num_valid, Int2Type<SUCCESSOR_WARP + 1>());
+ }
+
+ template <bool FULL_TILE, typename ReductionOp>
+ __device__ __forceinline__ T ApplyWarpAggregates(
+ ReductionOp /*reduction_op*/, ///< [in] Binary scan operator
+ T warp_aggregate, ///< [in] <b>[<em>lane</em><sub>0</sub> only]</b> Warp-wide aggregate reduction of input items
+ int /*num_valid*/, ///< [in] Number of valid elements (may be less than BLOCK_THREADS)
+ Int2Type<WARPS> /*successor_warp*/)
+ {
+ return warp_aggregate;
+ }
+
+
+ /// Returns block-wide aggregate in <em>thread</em><sub>0</sub>.
+ template <
+ bool FULL_TILE,
+ typename ReductionOp>
+ __device__ __forceinline__ T ApplyWarpAggregates(
+ ReductionOp reduction_op, ///< [in] Binary scan operator
+ T warp_aggregate, ///< [in] <b>[<em>lane</em><sub>0</sub> only]</b> Warp-wide aggregate reduction of input items
+ int num_valid) ///< [in] Number of valid elements (may be less than BLOCK_THREADS)
+ {
+ // Share lane aggregates
+ if (lane_id == 0)
+ {
+ temp_storage.warp_aggregates[warp_id] = warp_aggregate;
+ }
+
+ CTA_SYNC();
+
+ // Update total aggregate in warp 0, lane 0
+ if (linear_tid == 0)
+ {
+ warp_aggregate = ApplyWarpAggregates<FULL_TILE>(reduction_op, warp_aggregate, num_valid, Int2Type<1>());
+ }
+
+ return warp_aggregate;
+ }
+
+
+ /// Computes a thread block-wide reduction using addition (+) as the reduction operator. The first num_valid threads each contribute one reduction partial. The return value is only valid for thread<sub>0</sub>.
+ template <bool FULL_TILE>
+ __device__ __forceinline__ T Sum(
+ T input, ///< [in] Calling thread's input partial reductions
+ int num_valid) ///< [in] Number of valid elements (may be less than BLOCK_THREADS)
+ {
+ cub::Sum reduction_op;
+ int warp_offset = (warp_id * LOGICAL_WARP_SIZE);
+ int warp_num_valid = ((FULL_TILE && EVEN_WARP_MULTIPLE) || (warp_offset + LOGICAL_WARP_SIZE <= num_valid)) ?
+ LOGICAL_WARP_SIZE :
+ num_valid - warp_offset;
+
+ // Warp reduction in every warp
+ T warp_aggregate = WarpReduce(temp_storage.warp_reduce[warp_id]).template Reduce<(FULL_TILE && EVEN_WARP_MULTIPLE)>(
+ input,
+ warp_num_valid,
+ cub::Sum());
+
+ // Update outputs and block_aggregate with warp-wide aggregates from lane-0s
+ return ApplyWarpAggregates<FULL_TILE>(reduction_op, warp_aggregate, num_valid);
+ }
+
+
+ /// Computes a thread block-wide reduction using the specified reduction operator. The first num_valid threads each contribute one reduction partial. The return value is only valid for thread<sub>0</sub>.
+ template <
+ bool FULL_TILE,
+ typename ReductionOp>
+ __device__ __forceinline__ T Reduce(
+ T input, ///< [in] Calling thread's input partial reductions
+ int num_valid, ///< [in] Number of valid elements (may be less than BLOCK_THREADS)
+ ReductionOp reduction_op) ///< [in] Binary reduction operator
+ {
+ int warp_offset = warp_id * LOGICAL_WARP_SIZE;
+ int warp_num_valid = ((FULL_TILE && EVEN_WARP_MULTIPLE) || (warp_offset + LOGICAL_WARP_SIZE <= num_valid)) ?
+ LOGICAL_WARP_SIZE :
+ num_valid - warp_offset;
+
+ // Warp reduction in every warp
+ T warp_aggregate = WarpReduce(temp_storage.warp_reduce[warp_id]).template Reduce<(FULL_TILE && EVEN_WARP_MULTIPLE)>(
+ input,
+ warp_num_valid,
+ reduction_op);
+
+ // Update outputs and block_aggregate with warp-wide aggregates from lane-0s
+ return ApplyWarpAggregates<FULL_TILE>(reduction_op, warp_aggregate, num_valid);
+ }
+
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_scan_raking.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_scan_raking.cuh
new file mode 100644
index 0000000..a855cda
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_scan_raking.cuh
@@ -0,0 +1,666 @@
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-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 TORT
+ * (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
+ * cub::BlockScanRaking provides variants of raking-based parallel prefix scan across a CUDA thread block.
+ */
+
+#pragma once
+
+#include "../../util_ptx.cuh"
+#include "../../util_arch.cuh"
+#include "../../block/block_raking_layout.cuh"
+#include "../../thread/thread_reduce.cuh"
+#include "../../thread/thread_scan.cuh"
+#include "../../warp/warp_scan.cuh"
+#include "../../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+/**
+ * \brief BlockScanRaking provides variants of raking-based parallel prefix scan across a CUDA thread block.
+ */
+template <
+ typename T, ///< Data type being scanned
+ int BLOCK_DIM_X, ///< The thread block length in threads along the X dimension
+ int BLOCK_DIM_Y, ///< The thread block length in threads along the Y dimension
+ int BLOCK_DIM_Z, ///< The thread block length in threads along the Z dimension
+ bool MEMOIZE, ///< Whether or not to buffer outer raking scan partials to incur fewer shared memory reads at the expense of higher register pressure
+ int PTX_ARCH> ///< The PTX compute capability for which to to specialize this collective
+struct BlockScanRaking
+{
+ //---------------------------------------------------------------------
+ // Types and constants
+ //---------------------------------------------------------------------
+
+ /// Constants
+ enum
+ {
+ /// The thread block size in threads
+ BLOCK_THREADS = BLOCK_DIM_X * BLOCK_DIM_Y * BLOCK_DIM_Z,
+ };
+
+ /// Layout type for padded thread block raking grid
+ typedef BlockRakingLayout<T, BLOCK_THREADS, PTX_ARCH> BlockRakingLayout;
+
+ /// Constants
+ enum
+ {
+ /// Number of raking threads
+ RAKING_THREADS = BlockRakingLayout::RAKING_THREADS,
+
+ /// Number of raking elements per warp synchronous raking thread
+ SEGMENT_LENGTH = BlockRakingLayout::SEGMENT_LENGTH,
+
+ /// Cooperative work can be entirely warp synchronous
+ WARP_SYNCHRONOUS = (BLOCK_THREADS == RAKING_THREADS),
+ };
+
+ /// WarpScan utility type
+ typedef WarpScan<T, RAKING_THREADS, PTX_ARCH> WarpScan;
+
+ /// Shared memory storage layout type
+ struct _TempStorage
+ {
+ typename WarpScan::TempStorage warp_scan; ///< Buffer for warp-synchronous scan
+ typename BlockRakingLayout::TempStorage raking_grid; ///< Padded thread block raking grid
+ T block_aggregate; ///< Block aggregate
+ };
+
+
+ /// Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ //---------------------------------------------------------------------
+ // Per-thread fields
+ //---------------------------------------------------------------------
+
+ // Thread fields
+ _TempStorage &temp_storage;
+ unsigned int linear_tid;
+ T cached_segment[SEGMENT_LENGTH];
+
+
+ //---------------------------------------------------------------------
+ // Utility methods
+ //---------------------------------------------------------------------
+
+ /// Templated reduction
+ template <int ITERATION, typename ScanOp>
+ __device__ __forceinline__ T GuardedReduce(
+ T* raking_ptr, ///< [in] Input array
+ ScanOp scan_op, ///< [in] Binary reduction operator
+ T raking_partial, ///< [in] Prefix to seed reduction with
+ Int2Type<ITERATION> /*iteration*/)
+ {
+ if ((BlockRakingLayout::UNGUARDED) || (((linear_tid * SEGMENT_LENGTH) + ITERATION) < BLOCK_THREADS))
+ {
+ T addend = raking_ptr[ITERATION];
+ raking_partial = scan_op(raking_partial, addend);
+ }
+
+ return GuardedReduce(raking_ptr, scan_op, raking_partial, Int2Type<ITERATION + 1>());
+ }
+
+
+ /// Templated reduction (base case)
+ template <typename ScanOp>
+ __device__ __forceinline__ T GuardedReduce(
+ T* /*raking_ptr*/, ///< [in] Input array
+ ScanOp /*scan_op*/, ///< [in] Binary reduction operator
+ T raking_partial, ///< [in] Prefix to seed reduction with
+ Int2Type<SEGMENT_LENGTH> /*iteration*/)
+ {
+ return raking_partial;
+ }
+
+
+ /// Templated copy
+ template <int ITERATION>
+ __device__ __forceinline__ void CopySegment(
+ T* out, ///< [out] Out array
+ T* in, ///< [in] Input array
+ Int2Type<ITERATION> /*iteration*/)
+ {
+ out[ITERATION] = in[ITERATION];
+ CopySegment(out, in, Int2Type<ITERATION + 1>());
+ }
+
+
+ /// Templated copy (base case)
+ __device__ __forceinline__ void CopySegment(
+ T* /*out*/, ///< [out] Out array
+ T* /*in*/, ///< [in] Input array
+ Int2Type<SEGMENT_LENGTH> /*iteration*/)
+ {}
+
+
+ /// Performs upsweep raking reduction, returning the aggregate
+ template <typename ScanOp>
+ __device__ __forceinline__ T Upsweep(
+ ScanOp scan_op)
+ {
+ T *smem_raking_ptr = BlockRakingLayout::RakingPtr(temp_storage.raking_grid, linear_tid);
+
+ // Read data into registers
+ CopySegment(cached_segment, smem_raking_ptr, Int2Type<0>());
+
+ T raking_partial = cached_segment[0];
+
+ return GuardedReduce(cached_segment, scan_op, raking_partial, Int2Type<1>());
+ }
+
+
+ /// Performs exclusive downsweep raking scan
+ template <typename ScanOp>
+ __device__ __forceinline__ void ExclusiveDownsweep(
+ ScanOp scan_op,
+ T raking_partial,
+ bool apply_prefix = true)
+ {
+ T *smem_raking_ptr = BlockRakingLayout::RakingPtr(temp_storage.raking_grid, linear_tid);
+
+ // Read data back into registers
+ if (!MEMOIZE)
+ {
+ CopySegment(cached_segment, smem_raking_ptr, Int2Type<0>());
+ }
+
+ internal::ThreadScanExclusive(cached_segment, cached_segment, scan_op, raking_partial, apply_prefix);
+
+ // Write data back to smem
+ CopySegment(smem_raking_ptr, cached_segment, Int2Type<0>());
+ }
+
+
+ /// Performs inclusive downsweep raking scan
+ template <typename ScanOp>
+ __device__ __forceinline__ void InclusiveDownsweep(
+ ScanOp scan_op,
+ T raking_partial,
+ bool apply_prefix = true)
+ {
+ T *smem_raking_ptr = BlockRakingLayout::RakingPtr(temp_storage.raking_grid, linear_tid);
+
+ // Read data back into registers
+ if (!MEMOIZE)
+ {
+ CopySegment(cached_segment, smem_raking_ptr, Int2Type<0>());
+ }
+
+ internal::ThreadScanInclusive(cached_segment, cached_segment, scan_op, raking_partial, apply_prefix);
+
+ // Write data back to smem
+ CopySegment(smem_raking_ptr, cached_segment, Int2Type<0>());
+ }
+
+
+ //---------------------------------------------------------------------
+ // Constructors
+ //---------------------------------------------------------------------
+
+ /// Constructor
+ __device__ __forceinline__ BlockScanRaking(
+ TempStorage &temp_storage)
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z))
+ {}
+
+
+ //---------------------------------------------------------------------
+ // Exclusive scans
+ //---------------------------------------------------------------------
+
+ /// Computes an exclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. With no initial value, the output computed for <em>thread</em><sub>0</sub> is undefined.
+ template <typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &exclusive_output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op) ///< [in] Binary scan operator
+ {
+ if (WARP_SYNCHRONOUS)
+ {
+ // Short-circuit directly to warp-synchronous scan
+ WarpScan(temp_storage.warp_scan).ExclusiveScan(input, exclusive_output, scan_op);
+ }
+ else
+ {
+ // Place thread partial into shared memory raking grid
+ T *placement_ptr = BlockRakingLayout::PlacementPtr(temp_storage.raking_grid, linear_tid);
+ *placement_ptr = input;
+
+ CTA_SYNC();
+
+ // Reduce parallelism down to just raking threads
+ if (linear_tid < RAKING_THREADS)
+ {
+ // Raking upsweep reduction across shared partials
+ T upsweep_partial = Upsweep(scan_op);
+
+ // Warp-synchronous scan
+ T exclusive_partial;
+ WarpScan(temp_storage.warp_scan).ExclusiveScan(upsweep_partial, exclusive_partial, scan_op);
+
+ // Exclusive raking downsweep scan
+ ExclusiveDownsweep(scan_op, exclusive_partial, (linear_tid != 0));
+ }
+
+ CTA_SYNC();
+
+ // Grab thread prefix from shared memory
+ exclusive_output = *placement_ptr;
+ }
+ }
+
+ /// Computes an exclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element.
+ template <typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input items
+ T &output, ///< [out] Calling thread's output items (may be aliased to \p input)
+ const T &initial_value, ///< [in] Initial value to seed the exclusive scan
+ ScanOp scan_op) ///< [in] Binary scan operator
+ {
+ if (WARP_SYNCHRONOUS)
+ {
+ // Short-circuit directly to warp-synchronous scan
+ WarpScan(temp_storage.warp_scan).ExclusiveScan(input, output, initial_value, scan_op);
+ }
+ else
+ {
+ // Place thread partial into shared memory raking grid
+ T *placement_ptr = BlockRakingLayout::PlacementPtr(temp_storage.raking_grid, linear_tid);
+ *placement_ptr = input;
+
+ CTA_SYNC();
+
+ // Reduce parallelism down to just raking threads
+ if (linear_tid < RAKING_THREADS)
+ {
+ // Raking upsweep reduction across shared partials
+ T upsweep_partial = Upsweep(scan_op);
+
+ // Exclusive Warp-synchronous scan
+ T exclusive_partial;
+ WarpScan(temp_storage.warp_scan).ExclusiveScan(upsweep_partial, exclusive_partial, initial_value, scan_op);
+
+ // Exclusive raking downsweep scan
+ ExclusiveDownsweep(scan_op, exclusive_partial);
+ }
+
+ CTA_SYNC();
+
+ // Grab exclusive partial from shared memory
+ output = *placement_ptr;
+ }
+ }
+
+
+ /// Computes an exclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. Also provides every thread with the block-wide \p block_aggregate of all inputs. With no initial value, the output computed for <em>thread</em><sub>0</sub> is undefined.
+ template <typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan operator
+ T &block_aggregate) ///< [out] Threadblock-wide aggregate reduction of input items
+ {
+ if (WARP_SYNCHRONOUS)
+ {
+ // Short-circuit directly to warp-synchronous scan
+ WarpScan(temp_storage.warp_scan).ExclusiveScan(input, output, scan_op, block_aggregate);
+ }
+ else
+ {
+ // Place thread partial into shared memory raking grid
+ T *placement_ptr = BlockRakingLayout::PlacementPtr(temp_storage.raking_grid, linear_tid);
+ *placement_ptr = input;
+
+ CTA_SYNC();
+
+ // Reduce parallelism down to just raking threads
+ if (linear_tid < RAKING_THREADS)
+ {
+ // Raking upsweep reduction across shared partials
+ T upsweep_partial= Upsweep(scan_op);
+
+ // Warp-synchronous scan
+ T inclusive_partial;
+ T exclusive_partial;
+ WarpScan(temp_storage.warp_scan).Scan(upsweep_partial, inclusive_partial, exclusive_partial, scan_op);
+
+ // Exclusive raking downsweep scan
+ ExclusiveDownsweep(scan_op, exclusive_partial, (linear_tid != 0));
+
+ // Broadcast aggregate to all threads
+ if (linear_tid == RAKING_THREADS - 1)
+ temp_storage.block_aggregate = inclusive_partial;
+ }
+
+ CTA_SYNC();
+
+ // Grab thread prefix from shared memory
+ output = *placement_ptr;
+
+ // Retrieve block aggregate
+ block_aggregate = temp_storage.block_aggregate;
+ }
+ }
+
+
+ /// Computes an exclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ template <typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input items
+ T &output, ///< [out] Calling thread's output items (may be aliased to \p input)
+ const T &initial_value, ///< [in] Initial value to seed the exclusive scan
+ ScanOp scan_op, ///< [in] Binary scan operator
+ T &block_aggregate) ///< [out] Threadblock-wide aggregate reduction of input items
+ {
+ if (WARP_SYNCHRONOUS)
+ {
+ // Short-circuit directly to warp-synchronous scan
+ WarpScan(temp_storage.warp_scan).ExclusiveScan(input, output, initial_value, scan_op, block_aggregate);
+ }
+ else
+ {
+ // Place thread partial into shared memory raking grid
+ T *placement_ptr = BlockRakingLayout::PlacementPtr(temp_storage.raking_grid, linear_tid);
+ *placement_ptr = input;
+
+ CTA_SYNC();
+
+ // Reduce parallelism down to just raking threads
+ if (linear_tid < RAKING_THREADS)
+ {
+ // Raking upsweep reduction across shared partials
+ T upsweep_partial = Upsweep(scan_op);
+
+ // Warp-synchronous scan
+ T exclusive_partial;
+ WarpScan(temp_storage.warp_scan).ExclusiveScan(upsweep_partial, exclusive_partial, initial_value, scan_op, block_aggregate);
+
+ // Exclusive raking downsweep scan
+ ExclusiveDownsweep(scan_op, exclusive_partial);
+
+ // Broadcast aggregate to other threads
+ if (linear_tid == 0)
+ temp_storage.block_aggregate = block_aggregate;
+ }
+
+ CTA_SYNC();
+
+ // Grab exclusive partial from shared memory
+ output = *placement_ptr;
+
+ // Retrieve block aggregate
+ block_aggregate = temp_storage.block_aggregate;
+ }
+ }
+
+
+ /// Computes an exclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. the call-back functor \p block_prefix_callback_op is invoked by the first warp in the block, and the value returned by <em>lane</em><sub>0</sub> in that warp is used as the "seed" value that logically prefixes the thread block's scan inputs. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ template <
+ typename ScanOp,
+ typename BlockPrefixCallbackOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan operator
+ BlockPrefixCallbackOp &block_prefix_callback_op) ///< [in-out] <b>[<em>warp</em><sub>0</sub> only]</b> Call-back functor for specifying a thread block-wide prefix to be applied to all inputs.
+ {
+ if (WARP_SYNCHRONOUS)
+ {
+ // Short-circuit directly to warp-synchronous scan
+ T block_aggregate;
+ WarpScan warp_scan(temp_storage.warp_scan);
+ warp_scan.ExclusiveScan(input, output, scan_op, block_aggregate);
+
+ // Obtain warp-wide prefix in lane0, then broadcast to other lanes
+ T block_prefix = block_prefix_callback_op(block_aggregate);
+ block_prefix = warp_scan.Broadcast(block_prefix, 0);
+
+ output = scan_op(block_prefix, output);
+ if (linear_tid == 0)
+ output = block_prefix;
+ }
+ else
+ {
+ // Place thread partial into shared memory raking grid
+ T *placement_ptr = BlockRakingLayout::PlacementPtr(temp_storage.raking_grid, linear_tid);
+ *placement_ptr = input;
+
+ CTA_SYNC();
+
+ // Reduce parallelism down to just raking threads
+ if (linear_tid < RAKING_THREADS)
+ {
+ WarpScan warp_scan(temp_storage.warp_scan);
+
+ // Raking upsweep reduction across shared partials
+ T upsweep_partial = Upsweep(scan_op);
+
+ // Warp-synchronous scan
+ T exclusive_partial, block_aggregate;
+ warp_scan.ExclusiveScan(upsweep_partial, exclusive_partial, scan_op, block_aggregate);
+
+ // Obtain block-wide prefix in lane0, then broadcast to other lanes
+ T block_prefix = block_prefix_callback_op(block_aggregate);
+ block_prefix = warp_scan.Broadcast(block_prefix, 0);
+
+ // Update prefix with warpscan exclusive partial
+ T downsweep_prefix = scan_op(block_prefix, exclusive_partial);
+ if (linear_tid == 0)
+ downsweep_prefix = block_prefix;
+
+ // Exclusive raking downsweep scan
+ ExclusiveDownsweep(scan_op, downsweep_prefix);
+ }
+
+ CTA_SYNC();
+
+ // Grab thread prefix from shared memory
+ output = *placement_ptr;
+ }
+ }
+
+
+ //---------------------------------------------------------------------
+ // Inclusive scans
+ //---------------------------------------------------------------------
+
+ /// Computes an inclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element.
+ template <typename ScanOp>
+ __device__ __forceinline__ void InclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op) ///< [in] Binary scan operator
+ {
+ if (WARP_SYNCHRONOUS)
+ {
+ // Short-circuit directly to warp-synchronous scan
+ WarpScan(temp_storage.warp_scan).InclusiveScan(input, output, scan_op);
+ }
+ else
+ {
+ // Place thread partial into shared memory raking grid
+ T *placement_ptr = BlockRakingLayout::PlacementPtr(temp_storage.raking_grid, linear_tid);
+ *placement_ptr = input;
+
+ CTA_SYNC();
+
+ // Reduce parallelism down to just raking threads
+ if (linear_tid < RAKING_THREADS)
+ {
+ // Raking upsweep reduction across shared partials
+ T upsweep_partial = Upsweep(scan_op);
+
+ // Exclusive Warp-synchronous scan
+ T exclusive_partial;
+ WarpScan(temp_storage.warp_scan).ExclusiveScan(upsweep_partial, exclusive_partial, scan_op);
+
+ // Inclusive raking downsweep scan
+ InclusiveDownsweep(scan_op, exclusive_partial, (linear_tid != 0));
+ }
+
+ CTA_SYNC();
+
+ // Grab thread prefix from shared memory
+ output = *placement_ptr;
+ }
+ }
+
+
+ /// Computes an inclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ template <typename ScanOp>
+ __device__ __forceinline__ void InclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan operator
+ T &block_aggregate) ///< [out] Threadblock-wide aggregate reduction of input items
+ {
+ if (WARP_SYNCHRONOUS)
+ {
+ // Short-circuit directly to warp-synchronous scan
+ WarpScan(temp_storage.warp_scan).InclusiveScan(input, output, scan_op, block_aggregate);
+ }
+ else
+ {
+ // Place thread partial into shared memory raking grid
+ T *placement_ptr = BlockRakingLayout::PlacementPtr(temp_storage.raking_grid, linear_tid);
+ *placement_ptr = input;
+
+ CTA_SYNC();
+
+ // Reduce parallelism down to just raking threads
+ if (linear_tid < RAKING_THREADS)
+ {
+ // Raking upsweep reduction across shared partials
+ T upsweep_partial = Upsweep(scan_op);
+
+ // Warp-synchronous scan
+ T inclusive_partial;
+ T exclusive_partial;
+ WarpScan(temp_storage.warp_scan).Scan(upsweep_partial, inclusive_partial, exclusive_partial, scan_op);
+
+ // Inclusive raking downsweep scan
+ InclusiveDownsweep(scan_op, exclusive_partial, (linear_tid != 0));
+
+ // Broadcast aggregate to all threads
+ if (linear_tid == RAKING_THREADS - 1)
+ temp_storage.block_aggregate = inclusive_partial;
+ }
+
+ CTA_SYNC();
+
+ // Grab thread prefix from shared memory
+ output = *placement_ptr;
+
+ // Retrieve block aggregate
+ block_aggregate = temp_storage.block_aggregate;
+ }
+ }
+
+
+ /// Computes an inclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. the call-back functor \p block_prefix_callback_op is invoked by the first warp in the block, and the value returned by <em>lane</em><sub>0</sub> in that warp is used as the "seed" value that logically prefixes the thread block's scan inputs. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ template <
+ typename ScanOp,
+ typename BlockPrefixCallbackOp>
+ __device__ __forceinline__ void InclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan operator
+ BlockPrefixCallbackOp &block_prefix_callback_op) ///< [in-out] <b>[<em>warp</em><sub>0</sub> only]</b> Call-back functor for specifying a thread block-wide prefix to be applied to all inputs.
+ {
+ if (WARP_SYNCHRONOUS)
+ {
+ // Short-circuit directly to warp-synchronous scan
+ T block_aggregate;
+ WarpScan warp_scan(temp_storage.warp_scan);
+ warp_scan.InclusiveScan(input, output, scan_op, block_aggregate);
+
+ // Obtain warp-wide prefix in lane0, then broadcast to other lanes
+ T block_prefix = block_prefix_callback_op(block_aggregate);
+ block_prefix = warp_scan.Broadcast(block_prefix, 0);
+
+ // Update prefix with exclusive warpscan partial
+ output = scan_op(block_prefix, output);
+ }
+ else
+ {
+ // Place thread partial into shared memory raking grid
+ T *placement_ptr = BlockRakingLayout::PlacementPtr(temp_storage.raking_grid, linear_tid);
+ *placement_ptr = input;
+
+ CTA_SYNC();
+
+ // Reduce parallelism down to just raking threads
+ if (linear_tid < RAKING_THREADS)
+ {
+ WarpScan warp_scan(temp_storage.warp_scan);
+
+ // Raking upsweep reduction across shared partials
+ T upsweep_partial = Upsweep(scan_op);
+
+ // Warp-synchronous scan
+ T exclusive_partial, block_aggregate;
+ warp_scan.ExclusiveScan(upsweep_partial, exclusive_partial, scan_op, block_aggregate);
+
+ // Obtain block-wide prefix in lane0, then broadcast to other lanes
+ T block_prefix = block_prefix_callback_op(block_aggregate);
+ block_prefix = warp_scan.Broadcast(block_prefix, 0);
+
+ // Update prefix with warpscan exclusive partial
+ T downsweep_prefix = scan_op(block_prefix, exclusive_partial);
+ if (linear_tid == 0)
+ downsweep_prefix = block_prefix;
+
+ // Inclusive raking downsweep scan
+ InclusiveDownsweep(scan_op, downsweep_prefix);
+ }
+
+ CTA_SYNC();
+
+ // Grab thread prefix from shared memory
+ output = *placement_ptr;
+ }
+ }
+
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_scan_warp_scans.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_scan_warp_scans.cuh
new file mode 100644
index 0000000..85e4d61
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_scan_warp_scans.cuh
@@ -0,0 +1,392 @@
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-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 TORT
+ * (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
+ * cub::BlockScanWarpscans provides warpscan-based variants of parallel prefix scan across a CUDA thread block.
+ */
+
+#pragma once
+
+#include "../../util_arch.cuh"
+#include "../../util_ptx.cuh"
+#include "../../warp/warp_scan.cuh"
+#include "../../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+/**
+ * \brief BlockScanWarpScans provides warpscan-based variants of parallel prefix scan across a CUDA thread block.
+ */
+template <
+ typename T,
+ int BLOCK_DIM_X, ///< The thread block length in threads along the X dimension
+ int BLOCK_DIM_Y, ///< The thread block length in threads along the Y dimension
+ int BLOCK_DIM_Z, ///< The thread block length in threads along the Z dimension
+ int PTX_ARCH> ///< The PTX compute capability for which to to specialize this collective
+struct BlockScanWarpScans
+{
+ //---------------------------------------------------------------------
+ // Types and constants
+ //---------------------------------------------------------------------
+
+ /// Constants
+ enum
+ {
+ /// Number of warp threads
+ WARP_THREADS = CUB_WARP_THREADS(PTX_ARCH),
+
+ /// The thread block size in threads
+ BLOCK_THREADS = BLOCK_DIM_X * BLOCK_DIM_Y * BLOCK_DIM_Z,
+
+ /// Number of active warps
+ WARPS = (BLOCK_THREADS + WARP_THREADS - 1) / WARP_THREADS,
+ };
+
+ /// WarpScan utility type
+ typedef WarpScan<T, WARP_THREADS, PTX_ARCH> WarpScanT;
+
+ /// WarpScan utility type
+ typedef WarpScan<T, WARPS, PTX_ARCH> WarpAggregateScan;
+
+ /// Shared memory storage layout type
+
+ struct __align__(32) _TempStorage
+ {
+ T warp_aggregates[WARPS];
+ typename WarpScanT::TempStorage warp_scan[WARPS]; ///< Buffer for warp-synchronous scans
+ T block_prefix; ///< Shared prefix for the entire thread block
+ };
+
+
+ /// Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ //---------------------------------------------------------------------
+ // Per-thread fields
+ //---------------------------------------------------------------------
+
+ // Thread fields
+ _TempStorage &temp_storage;
+ unsigned int linear_tid;
+ unsigned int warp_id;
+ unsigned int lane_id;
+
+
+ //---------------------------------------------------------------------
+ // Constructors
+ //---------------------------------------------------------------------
+
+ /// Constructor
+ __device__ __forceinline__ BlockScanWarpScans(
+ TempStorage &temp_storage)
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z)),
+ warp_id((WARPS == 1) ? 0 : linear_tid / WARP_THREADS),
+ lane_id(LaneId())
+ {}
+
+
+ //---------------------------------------------------------------------
+ // Utility methods
+ //---------------------------------------------------------------------
+
+ template <typename ScanOp, int WARP>
+ __device__ __forceinline__ void ApplyWarpAggregates(
+ T &warp_prefix, ///< [out] The calling thread's partial reduction
+ ScanOp scan_op, ///< [in] Binary scan operator
+ T &block_aggregate, ///< [out] Threadblock-wide aggregate reduction of input items
+ Int2Type<WARP> /*addend_warp*/)
+ {
+ if (warp_id == WARP)
+ warp_prefix = block_aggregate;
+
+ T addend = temp_storage.warp_aggregates[WARP];
+ block_aggregate = scan_op(block_aggregate, addend);
+
+ ApplyWarpAggregates(warp_prefix, scan_op, block_aggregate, Int2Type<WARP + 1>());
+ }
+
+ template <typename ScanOp>
+ __device__ __forceinline__ void ApplyWarpAggregates(
+ T &/*warp_prefix*/, ///< [out] The calling thread's partial reduction
+ ScanOp /*scan_op*/, ///< [in] Binary scan operator
+ T &/*block_aggregate*/, ///< [out] Threadblock-wide aggregate reduction of input items
+ Int2Type<WARPS> /*addend_warp*/)
+ {}
+
+
+ /// Use the warp-wide aggregates to compute the calling warp's prefix. Also returns block-wide aggregate in all threads.
+ template <typename ScanOp>
+ __device__ __forceinline__ T ComputeWarpPrefix(
+ ScanOp scan_op, ///< [in] Binary scan operator
+ T warp_aggregate, ///< [in] <b>[<em>lane</em><sub>WARP_THREADS - 1</sub> only]</b> Warp-wide aggregate reduction of input items
+ T &block_aggregate) ///< [out] Threadblock-wide aggregate reduction of input items
+ {
+ // Last lane in each warp shares its warp-aggregate
+ if (lane_id == WARP_THREADS - 1)
+ temp_storage.warp_aggregates[warp_id] = warp_aggregate;
+
+ CTA_SYNC();
+
+ // Accumulate block aggregates and save the one that is our warp's prefix
+ T warp_prefix;
+ block_aggregate = temp_storage.warp_aggregates[0];
+
+ // Use template unrolling (since the PTX backend can't handle unrolling it for SM1x)
+ ApplyWarpAggregates(warp_prefix, scan_op, block_aggregate, Int2Type<1>());
+/*
+ #pragma unroll
+ for (int WARP = 1; WARP < WARPS; ++WARP)
+ {
+ if (warp_id == WARP)
+ warp_prefix = block_aggregate;
+
+ T addend = temp_storage.warp_aggregates[WARP];
+ block_aggregate = scan_op(block_aggregate, addend);
+ }
+*/
+
+ return warp_prefix;
+ }
+
+
+ /// Use the warp-wide aggregates and initial-value to compute the calling warp's prefix. Also returns block-wide aggregate in all threads.
+ template <typename ScanOp>
+ __device__ __forceinline__ T ComputeWarpPrefix(
+ ScanOp scan_op, ///< [in] Binary scan operator
+ T warp_aggregate, ///< [in] <b>[<em>lane</em><sub>WARP_THREADS - 1</sub> only]</b> Warp-wide aggregate reduction of input items
+ T &block_aggregate, ///< [out] Threadblock-wide aggregate reduction of input items
+ const T &initial_value) ///< [in] Initial value to seed the exclusive scan
+ {
+ T warp_prefix = ComputeWarpPrefix(scan_op, warp_aggregate, block_aggregate);
+
+ warp_prefix = scan_op(initial_value, warp_prefix);
+
+ if (warp_id == 0)
+ warp_prefix = initial_value;
+
+ return warp_prefix;
+ }
+
+ //---------------------------------------------------------------------
+ // Exclusive scans
+ //---------------------------------------------------------------------
+
+ /// Computes an exclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. With no initial value, the output computed for <em>thread</em><sub>0</sub> is undefined.
+ template <typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &exclusive_output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op) ///< [in] Binary scan operator
+ {
+ // Compute block-wide exclusive scan. The exclusive output from tid0 is invalid.
+ T block_aggregate;
+ ExclusiveScan(input, exclusive_output, scan_op, block_aggregate);
+ }
+
+
+ /// Computes an exclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element.
+ template <typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input items
+ T &exclusive_output, ///< [out] Calling thread's output items (may be aliased to \p input)
+ const T &initial_value, ///< [in] Initial value to seed the exclusive scan
+ ScanOp scan_op) ///< [in] Binary scan operator
+ {
+ T block_aggregate;
+ ExclusiveScan(input, exclusive_output, initial_value, scan_op, block_aggregate);
+ }
+
+
+ /// Computes an exclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. Also provides every thread with the block-wide \p block_aggregate of all inputs. With no initial value, the output computed for <em>thread</em><sub>0</sub> is undefined.
+ template <typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &exclusive_output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan operator
+ T &block_aggregate) ///< [out] Threadblock-wide aggregate reduction of input items
+ {
+ // Compute warp scan in each warp. The exclusive output from each lane0 is invalid.
+ T inclusive_output;
+ WarpScanT(temp_storage.warp_scan[warp_id]).Scan(input, inclusive_output, exclusive_output, scan_op);
+
+ // Compute the warp-wide prefix and block-wide aggregate for each warp. Warp prefix for warp0 is invalid.
+ T warp_prefix = ComputeWarpPrefix(scan_op, inclusive_output, block_aggregate);
+
+ // Apply warp prefix to our lane's partial
+ if (warp_id != 0)
+ {
+ exclusive_output = scan_op(warp_prefix, exclusive_output);
+ if (lane_id == 0)
+ exclusive_output = warp_prefix;
+ }
+ }
+
+
+ /// Computes an exclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ template <typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input items
+ T &exclusive_output, ///< [out] Calling thread's output items (may be aliased to \p input)
+ const T &initial_value, ///< [in] Initial value to seed the exclusive scan
+ ScanOp scan_op, ///< [in] Binary scan operator
+ T &block_aggregate) ///< [out] Threadblock-wide aggregate reduction of input items
+ {
+ // Compute warp scan in each warp. The exclusive output from each lane0 is invalid.
+ T inclusive_output;
+ WarpScanT(temp_storage.warp_scan[warp_id]).Scan(input, inclusive_output, exclusive_output, scan_op);
+
+ // Compute the warp-wide prefix and block-wide aggregate for each warp
+ T warp_prefix = ComputeWarpPrefix(scan_op, inclusive_output, block_aggregate, initial_value);
+
+ // Apply warp prefix to our lane's partial
+ exclusive_output = scan_op(warp_prefix, exclusive_output);
+ if (lane_id == 0)
+ exclusive_output = warp_prefix;
+ }
+
+
+ /// Computes an exclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. the call-back functor \p block_prefix_callback_op is invoked by the first warp in the block, and the value returned by <em>lane</em><sub>0</sub> in that warp is used as the "seed" value that logically prefixes the thread block's scan inputs. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ template <
+ typename ScanOp,
+ typename BlockPrefixCallbackOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &exclusive_output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan operator
+ BlockPrefixCallbackOp &block_prefix_callback_op) ///< [in-out] <b>[<em>warp</em><sub>0</sub> only]</b> Call-back functor for specifying a thread block-wide prefix to be applied to all inputs.
+ {
+ // Compute block-wide exclusive scan. The exclusive output from tid0 is invalid.
+ T block_aggregate;
+ ExclusiveScan(input, exclusive_output, scan_op, block_aggregate);
+
+ // Use the first warp to determine the thread block prefix, returning the result in lane0
+ if (warp_id == 0)
+ {
+ T block_prefix = block_prefix_callback_op(block_aggregate);
+ if (lane_id == 0)
+ {
+ // Share the prefix with all threads
+ temp_storage.block_prefix = block_prefix;
+ exclusive_output = block_prefix; // The block prefix is the exclusive output for tid0
+ }
+ }
+
+ CTA_SYNC();
+
+ // Incorporate thread block prefix into outputs
+ T block_prefix = temp_storage.block_prefix;
+ if (linear_tid > 0)
+ {
+ exclusive_output = scan_op(block_prefix, exclusive_output);
+ }
+ }
+
+
+ //---------------------------------------------------------------------
+ // Inclusive scans
+ //---------------------------------------------------------------------
+
+ /// Computes an inclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element.
+ template <typename ScanOp>
+ __device__ __forceinline__ void InclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &inclusive_output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op) ///< [in] Binary scan operator
+ {
+ T block_aggregate;
+ InclusiveScan(input, inclusive_output, scan_op, block_aggregate);
+ }
+
+
+ /// Computes an inclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ template <typename ScanOp>
+ __device__ __forceinline__ void InclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &inclusive_output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan operator
+ T &block_aggregate) ///< [out] Threadblock-wide aggregate reduction of input items
+ {
+ WarpScanT(temp_storage.warp_scan[warp_id]).InclusiveScan(input, inclusive_output, scan_op);
+
+ // Compute the warp-wide prefix and block-wide aggregate for each warp. Warp prefix for warp0 is invalid.
+ T warp_prefix = ComputeWarpPrefix(scan_op, inclusive_output, block_aggregate);
+
+ // Apply warp prefix to our lane's partial
+ if (warp_id != 0)
+ {
+ inclusive_output = scan_op(warp_prefix, inclusive_output);
+ }
+ }
+
+
+ /// Computes an inclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. the call-back functor \p block_prefix_callback_op is invoked by the first warp in the block, and the value returned by <em>lane</em><sub>0</sub> in that warp is used as the "seed" value that logically prefixes the thread block's scan inputs. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ template <
+ typename ScanOp,
+ typename BlockPrefixCallbackOp>
+ __device__ __forceinline__ void InclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &exclusive_output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan operator
+ BlockPrefixCallbackOp &block_prefix_callback_op) ///< [in-out] <b>[<em>warp</em><sub>0</sub> only]</b> Call-back functor for specifying a thread block-wide prefix to be applied to all inputs.
+ {
+ T block_aggregate;
+ InclusiveScan(input, exclusive_output, scan_op, block_aggregate);
+
+ // Use the first warp to determine the thread block prefix, returning the result in lane0
+ if (warp_id == 0)
+ {
+ T block_prefix = block_prefix_callback_op(block_aggregate);
+ if (lane_id == 0)
+ {
+ // Share the prefix with all threads
+ temp_storage.block_prefix = block_prefix;
+ }
+ }
+
+ CTA_SYNC();
+
+ // Incorporate thread block prefix into outputs
+ T block_prefix = temp_storage.block_prefix;
+ exclusive_output = scan_op(block_prefix, exclusive_output);
+ }
+
+
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_scan_warp_scans2.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_scan_warp_scans2.cuh
new file mode 100644
index 0000000..4de7c69
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_scan_warp_scans2.cuh
@@ -0,0 +1,436 @@
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-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 TORT
+ * (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
+ * cub::BlockScanWarpscans provides warpscan-based variants of parallel prefix scan across a CUDA thread block.
+ */
+
+#pragma once
+
+#include "../../util_arch.cuh"
+#include "../../util_ptx.cuh"
+#include "../../warp/warp_scan.cuh"
+#include "../../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+/**
+ * \brief BlockScanWarpScans provides warpscan-based variants of parallel prefix scan across a CUDA thread block.
+ */
+template <
+ typename T,
+ int BLOCK_DIM_X, ///< The thread block length in threads along the X dimension
+ int BLOCK_DIM_Y, ///< The thread block length in threads along the Y dimension
+ int BLOCK_DIM_Z, ///< The thread block length in threads along the Z dimension
+ int PTX_ARCH> ///< The PTX compute capability for which to to specialize this collective
+struct BlockScanWarpScans
+{
+ //---------------------------------------------------------------------
+ // Types and constants
+ //---------------------------------------------------------------------
+
+ /// Constants
+ enum
+ {
+ /// Number of warp threads
+ WARP_THREADS = CUB_WARP_THREADS(PTX_ARCH),
+
+ /// The thread block size in threads
+ BLOCK_THREADS = BLOCK_DIM_X * BLOCK_DIM_Y * BLOCK_DIM_Z,
+
+ /// Number of active warps
+ WARPS = (BLOCK_THREADS + WARP_THREADS - 1) / WARP_THREADS,
+ };
+
+ /// WarpScan utility type
+ typedef WarpScan<T, WARP_THREADS, PTX_ARCH> WarpScanT;
+
+ /// WarpScan utility type
+ typedef WarpScan<T, WARPS, PTX_ARCH> WarpAggregateScanT;
+
+ /// Shared memory storage layout type
+ struct _TempStorage
+ {
+ typename WarpAggregateScanT::TempStorage inner_scan[WARPS]; ///< Buffer for warp-synchronous scans
+ typename WarpScanT::TempStorage warp_scan[WARPS]; ///< Buffer for warp-synchronous scans
+ T warp_aggregates[WARPS];
+ T block_prefix; ///< Shared prefix for the entire thread block
+ };
+
+
+ /// Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ //---------------------------------------------------------------------
+ // Per-thread fields
+ //---------------------------------------------------------------------
+
+ // Thread fields
+ _TempStorage &temp_storage;
+ unsigned int linear_tid;
+ unsigned int warp_id;
+ unsigned int lane_id;
+
+
+ //---------------------------------------------------------------------
+ // Constructors
+ //---------------------------------------------------------------------
+
+ /// Constructor
+ __device__ __forceinline__ BlockScanWarpScans(
+ TempStorage &temp_storage)
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z)),
+ warp_id((WARPS == 1) ? 0 : linear_tid / WARP_THREADS),
+ lane_id(LaneId())
+ {}
+
+
+ //---------------------------------------------------------------------
+ // Utility methods
+ //---------------------------------------------------------------------
+
+ template <typename ScanOp, int WARP>
+ __device__ __forceinline__ void ApplyWarpAggregates(
+ T &warp_prefix, ///< [out] The calling thread's partial reduction
+ ScanOp scan_op, ///< [in] Binary scan operator
+ T &block_aggregate, ///< [out] Threadblock-wide aggregate reduction of input items
+ Int2Type<WARP> addend_warp)
+ {
+ if (warp_id == WARP)
+ warp_prefix = block_aggregate;
+
+ T addend = temp_storage.warp_aggregates[WARP];
+ block_aggregate = scan_op(block_aggregate, addend);
+
+ ApplyWarpAggregates(warp_prefix, scan_op, block_aggregate, Int2Type<WARP + 1>());
+ }
+
+ template <typename ScanOp>
+ __device__ __forceinline__ void ApplyWarpAggregates(
+ T &warp_prefix, ///< [out] The calling thread's partial reduction
+ ScanOp scan_op, ///< [in] Binary scan operator
+ T &block_aggregate, ///< [out] Threadblock-wide aggregate reduction of input items
+ Int2Type<WARPS> addend_warp)
+ {}
+
+
+ /// Use the warp-wide aggregates to compute the calling warp's prefix. Also returns block-wide aggregate in all threads.
+ template <typename ScanOp>
+ __device__ __forceinline__ T ComputeWarpPrefix(
+ ScanOp scan_op, ///< [in] Binary scan operator
+ T warp_aggregate, ///< [in] <b>[<em>lane</em><sub>WARP_THREADS - 1</sub> only]</b> Warp-wide aggregate reduction of input items
+ T &block_aggregate) ///< [out] Threadblock-wide aggregate reduction of input items
+ {
+ // Last lane in each warp shares its warp-aggregate
+ if (lane_id == WARP_THREADS - 1)
+ temp_storage.warp_aggregates[warp_id] = warp_aggregate;
+
+ CTA_SYNC();
+
+ // Accumulate block aggregates and save the one that is our warp's prefix
+ T warp_prefix;
+ block_aggregate = temp_storage.warp_aggregates[0];
+
+ // Use template unrolling (since the PTX backend can't handle unrolling it for SM1x)
+ ApplyWarpAggregates(warp_prefix, scan_op, block_aggregate, Int2Type<1>());
+/*
+ #pragma unroll
+ for (int WARP = 1; WARP < WARPS; ++WARP)
+ {
+ if (warp_id == WARP)
+ warp_prefix = block_aggregate;
+
+ T addend = temp_storage.warp_aggregates[WARP];
+ block_aggregate = scan_op(block_aggregate, addend);
+ }
+*/
+
+ return warp_prefix;
+ }
+
+
+ /// Use the warp-wide aggregates and initial-value to compute the calling warp's prefix. Also returns block-wide aggregate in all threads.
+ template <typename ScanOp>
+ __device__ __forceinline__ T ComputeWarpPrefix(
+ ScanOp scan_op, ///< [in] Binary scan operator
+ T warp_aggregate, ///< [in] <b>[<em>lane</em><sub>WARP_THREADS - 1</sub> only]</b> Warp-wide aggregate reduction of input items
+ T &block_aggregate, ///< [out] Threadblock-wide aggregate reduction of input items
+ const T &initial_value) ///< [in] Initial value to seed the exclusive scan
+ {
+ T warp_prefix = ComputeWarpPrefix(scan_op, warp_aggregate, block_aggregate);
+
+ warp_prefix = scan_op(initial_value, warp_prefix);
+
+ if (warp_id == 0)
+ warp_prefix = initial_value;
+
+ return warp_prefix;
+ }
+
+ //---------------------------------------------------------------------
+ // Exclusive scans
+ //---------------------------------------------------------------------
+
+ /// Computes an exclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. With no initial value, the output computed for <em>thread</em><sub>0</sub> is undefined.
+ template <typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &exclusive_output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op) ///< [in] Binary scan operator
+ {
+ // Compute block-wide exclusive scan. The exclusive output from tid0 is invalid.
+ T block_aggregate;
+ ExclusiveScan(input, exclusive_output, scan_op, block_aggregate);
+ }
+
+
+ /// Computes an exclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element.
+ template <typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input items
+ T &exclusive_output, ///< [out] Calling thread's output items (may be aliased to \p input)
+ const T &initial_value, ///< [in] Initial value to seed the exclusive scan
+ ScanOp scan_op) ///< [in] Binary scan operator
+ {
+ T block_aggregate;
+ ExclusiveScan(input, exclusive_output, initial_value, scan_op, block_aggregate);
+ }
+
+
+ /// Computes an exclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. Also provides every thread with the block-wide \p block_aggregate of all inputs. With no initial value, the output computed for <em>thread</em><sub>0</sub> is undefined.
+ template <typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &exclusive_output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan operator
+ T &block_aggregate) ///< [out] Threadblock-wide aggregate reduction of input items
+ {
+ WarpScanT my_warp_scan(temp_storage.warp_scan[warp_id]);
+
+ // Compute warp scan in each warp. The exclusive output from each lane0 is invalid.
+ T inclusive_output;
+ my_warp_scan.Scan(input, inclusive_output, exclusive_output, scan_op);
+
+ // Compute the warp-wide prefix and block-wide aggregate for each warp. Warp prefix for warp0 is invalid.
+// T warp_prefix = ComputeWarpPrefix(scan_op, inclusive_output, block_aggregate);
+
+//--------------------------------------------------
+ // Last lane in each warp shares its warp-aggregate
+ if (lane_id == WARP_THREADS - 1)
+ temp_storage.warp_aggregates[warp_id] = inclusive_output;
+
+ CTA_SYNC();
+
+ // Get the warp scan partial
+ T warp_inclusive, warp_prefix;
+ if (lane_id < WARPS)
+ {
+ // Scan the warpscan partials
+ T warp_val = temp_storage.warp_aggregates[lane_id];
+ WarpAggregateScanT(temp_storage.inner_scan[warp_id]).Scan(warp_val, warp_inclusive, warp_prefix, scan_op);
+ }
+
+ warp_prefix = my_warp_scan.Broadcast(warp_prefix, warp_id);
+ block_aggregate = my_warp_scan.Broadcast(warp_inclusive, WARPS - 1);
+//--------------------------------------------------
+
+ // Apply warp prefix to our lane's partial
+ if (warp_id != 0)
+ {
+ exclusive_output = scan_op(warp_prefix, exclusive_output);
+ if (lane_id == 0)
+ exclusive_output = warp_prefix;
+ }
+ }
+
+
+ /// Computes an exclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ template <typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input items
+ T &exclusive_output, ///< [out] Calling thread's output items (may be aliased to \p input)
+ const T &initial_value, ///< [in] Initial value to seed the exclusive scan
+ ScanOp scan_op, ///< [in] Binary scan operator
+ T &block_aggregate) ///< [out] Threadblock-wide aggregate reduction of input items
+ {
+ WarpScanT my_warp_scan(temp_storage.warp_scan[warp_id]);
+
+ // Compute warp scan in each warp. The exclusive output from each lane0 is invalid.
+ T inclusive_output;
+ my_warp_scan.Scan(input, inclusive_output, exclusive_output, scan_op);
+
+ // Compute the warp-wide prefix and block-wide aggregate for each warp
+// T warp_prefix = ComputeWarpPrefix(scan_op, inclusive_output, block_aggregate, initial_value);
+
+//--------------------------------------------------
+ // Last lane in each warp shares its warp-aggregate
+ if (lane_id == WARP_THREADS - 1)
+ temp_storage.warp_aggregates[warp_id] = inclusive_output;
+
+ CTA_SYNC();
+
+ // Get the warp scan partial
+ T warp_inclusive, warp_prefix;
+ if (lane_id < WARPS)
+ {
+ // Scan the warpscan partials
+ T warp_val = temp_storage.warp_aggregates[lane_id];
+ WarpAggregateScanT(temp_storage.inner_scan[warp_id]).Scan(warp_val, warp_inclusive, warp_prefix, initial_value, scan_op);
+ }
+
+ warp_prefix = my_warp_scan.Broadcast(warp_prefix, warp_id);
+ block_aggregate = my_warp_scan.Broadcast(warp_inclusive, WARPS - 1);
+//--------------------------------------------------
+
+ // Apply warp prefix to our lane's partial
+ exclusive_output = scan_op(warp_prefix, exclusive_output);
+ if (lane_id == 0)
+ exclusive_output = warp_prefix;
+ }
+
+
+ /// Computes an exclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. the call-back functor \p block_prefix_callback_op is invoked by the first warp in the block, and the value returned by <em>lane</em><sub>0</sub> in that warp is used as the "seed" value that logically prefixes the thread block's scan inputs. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ template <
+ typename ScanOp,
+ typename BlockPrefixCallbackOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &exclusive_output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan operator
+ BlockPrefixCallbackOp &block_prefix_callback_op) ///< [in-out] <b>[<em>warp</em><sub>0</sub> only]</b> Call-back functor for specifying a thread block-wide prefix to be applied to all inputs.
+ {
+ // Compute block-wide exclusive scan. The exclusive output from tid0 is invalid.
+ T block_aggregate;
+ ExclusiveScan(input, exclusive_output, scan_op, block_aggregate);
+
+ // Use the first warp to determine the thread block prefix, returning the result in lane0
+ if (warp_id == 0)
+ {
+ T block_prefix = block_prefix_callback_op(block_aggregate);
+ if (lane_id == 0)
+ {
+ // Share the prefix with all threads
+ temp_storage.block_prefix = block_prefix;
+ exclusive_output = block_prefix; // The block prefix is the exclusive output for tid0
+ }
+ }
+
+ CTA_SYNC();
+
+ // Incorporate thread block prefix into outputs
+ T block_prefix = temp_storage.block_prefix;
+ if (linear_tid > 0)
+ {
+ exclusive_output = scan_op(block_prefix, exclusive_output);
+ }
+ }
+
+
+ //---------------------------------------------------------------------
+ // Inclusive scans
+ //---------------------------------------------------------------------
+
+ /// Computes an inclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element.
+ template <typename ScanOp>
+ __device__ __forceinline__ void InclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &inclusive_output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op) ///< [in] Binary scan operator
+ {
+ T block_aggregate;
+ InclusiveScan(input, inclusive_output, scan_op, block_aggregate);
+ }
+
+
+ /// Computes an inclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ template <typename ScanOp>
+ __device__ __forceinline__ void InclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &inclusive_output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan operator
+ T &block_aggregate) ///< [out] Threadblock-wide aggregate reduction of input items
+ {
+ WarpScanT(temp_storage.warp_scan[warp_id]).InclusiveScan(input, inclusive_output, scan_op);
+
+ // Compute the warp-wide prefix and block-wide aggregate for each warp. Warp prefix for warp0 is invalid.
+ T warp_prefix = ComputeWarpPrefix(scan_op, inclusive_output, block_aggregate);
+
+ // Apply warp prefix to our lane's partial
+ if (warp_id != 0)
+ {
+ inclusive_output = scan_op(warp_prefix, inclusive_output);
+ }
+ }
+
+
+ /// Computes an inclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. the call-back functor \p block_prefix_callback_op is invoked by the first warp in the block, and the value returned by <em>lane</em><sub>0</sub> in that warp is used as the "seed" value that logically prefixes the thread block's scan inputs. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ template <
+ typename ScanOp,
+ typename BlockPrefixCallbackOp>
+ __device__ __forceinline__ void InclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &exclusive_output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan operator
+ BlockPrefixCallbackOp &block_prefix_callback_op) ///< [in-out] <b>[<em>warp</em><sub>0</sub> only]</b> Call-back functor for specifying a thread block-wide prefix to be applied to all inputs.
+ {
+ T block_aggregate;
+ InclusiveScan(input, exclusive_output, scan_op, block_aggregate);
+
+ // Use the first warp to determine the thread block prefix, returning the result in lane0
+ if (warp_id == 0)
+ {
+ T block_prefix = block_prefix_callback_op(block_aggregate);
+ if (lane_id == 0)
+ {
+ // Share the prefix with all threads
+ temp_storage.block_prefix = block_prefix;
+ }
+ }
+
+ CTA_SYNC();
+
+ // Incorporate thread block prefix into outputs
+ T block_prefix = temp_storage.block_prefix;
+ exclusive_output = scan_op(block_prefix, exclusive_output);
+ }
+
+
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_scan_warp_scans3.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_scan_warp_scans3.cuh
new file mode 100644
index 0000000..147ca4c
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/block/specializations/block_scan_warp_scans3.cuh
@@ -0,0 +1,418 @@
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-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 TORT
+ * (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
+ * cub::BlockScanWarpscans provides warpscan-based variants of parallel prefix scan across a CUDA thread block.
+ */
+
+#pragma once
+
+#include "../../util_arch.cuh"
+#include "../../util_ptx.cuh"
+#include "../../warp/warp_scan.cuh"
+#include "../../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+/**
+ * \brief BlockScanWarpScans provides warpscan-based variants of parallel prefix scan across a CUDA thread block.
+ */
+template <
+ typename T,
+ int BLOCK_DIM_X, ///< The thread block length in threads along the X dimension
+ int BLOCK_DIM_Y, ///< The thread block length in threads along the Y dimension
+ int BLOCK_DIM_Z, ///< The thread block length in threads along the Z dimension
+ int PTX_ARCH> ///< The PTX compute capability for which to to specialize this collective
+struct BlockScanWarpScans
+{
+ //---------------------------------------------------------------------
+ // Types and constants
+ //---------------------------------------------------------------------
+
+ /// Constants
+ enum
+ {
+ /// The thread block size in threads
+ BLOCK_THREADS = BLOCK_DIM_X * BLOCK_DIM_Y * BLOCK_DIM_Z,
+
+ /// Number of warp threads
+ INNER_WARP_THREADS = CUB_WARP_THREADS(PTX_ARCH),
+ OUTER_WARP_THREADS = BLOCK_THREADS / INNER_WARP_THREADS,
+
+ /// Number of outer scan warps
+ OUTER_WARPS = INNER_WARP_THREADS
+ };
+
+ /// Outer WarpScan utility type
+ typedef WarpScan<T, OUTER_WARP_THREADS, PTX_ARCH> OuterWarpScanT;
+
+ /// Inner WarpScan utility type
+ typedef WarpScan<T, INNER_WARP_THREADS, PTX_ARCH> InnerWarpScanT;
+
+ typedef typename OuterWarpScanT::TempStorage OuterScanArray[OUTER_WARPS];
+
+
+ /// Shared memory storage layout type
+ struct _TempStorage
+ {
+ union Aliasable
+ {
+ Uninitialized<OuterScanArray> outer_warp_scan; ///< Buffer for warp-synchronous outer scans
+ typename InnerWarpScanT::TempStorage inner_warp_scan; ///< Buffer for warp-synchronous inner scan
+
+ } aliasable;
+
+ T warp_aggregates[OUTER_WARPS];
+
+ T block_aggregate; ///< Shared prefix for the entire thread block
+ };
+
+
+ /// Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ //---------------------------------------------------------------------
+ // Per-thread fields
+ //---------------------------------------------------------------------
+
+ // Thread fields
+ _TempStorage &temp_storage;
+ unsigned int linear_tid;
+ unsigned int warp_id;
+ unsigned int lane_id;
+
+
+ //---------------------------------------------------------------------
+ // Constructors
+ //---------------------------------------------------------------------
+
+ /// Constructor
+ __device__ __forceinline__ BlockScanWarpScans(
+ TempStorage &temp_storage)
+ :
+ temp_storage(temp_storage.Alias()),
+ linear_tid(RowMajorTid(BLOCK_DIM_X, BLOCK_DIM_Y, BLOCK_DIM_Z)),
+ warp_id((OUTER_WARPS == 1) ? 0 : linear_tid / OUTER_WARP_THREADS),
+ lane_id((OUTER_WARPS == 1) ? linear_tid : linear_tid % OUTER_WARP_THREADS)
+ {}
+
+
+ //---------------------------------------------------------------------
+ // Exclusive scans
+ //---------------------------------------------------------------------
+
+ /// Computes an exclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. With no initial value, the output computed for <em>thread</em><sub>0</sub> is undefined.
+ template <typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &exclusive_output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op) ///< [in] Binary scan operator
+ {
+ // Compute block-wide exclusive scan. The exclusive output from tid0 is invalid.
+ T block_aggregate;
+ ExclusiveScan(input, exclusive_output, scan_op, block_aggregate);
+ }
+
+
+ /// Computes an exclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element.
+ template <typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input items
+ T &exclusive_output, ///< [out] Calling thread's output items (may be aliased to \p input)
+ const T &initial_value, ///< [in] Initial value to seed the exclusive scan
+ ScanOp scan_op) ///< [in] Binary scan operator
+ {
+ T block_aggregate;
+ ExclusiveScan(input, exclusive_output, initial_value, scan_op, block_aggregate);
+ }
+
+
+ /// Computes an exclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. Also provides every thread with the block-wide \p block_aggregate of all inputs. With no initial value, the output computed for <em>thread</em><sub>0</sub> is undefined.
+ template <typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &exclusive_output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan operator
+ T &block_aggregate) ///< [out] Threadblock-wide aggregate reduction of input items
+ {
+ // Compute warp scan in each warp. The exclusive output from each lane0 is invalid.
+ T inclusive_output;
+ OuterWarpScanT(temp_storage.aliasable.outer_warp_scan.Alias()[warp_id]).Scan(
+ input, inclusive_output, exclusive_output, scan_op);
+
+ // Share outer warp total
+ if (lane_id == OUTER_WARP_THREADS - 1)
+ temp_storage.warp_aggregates[warp_id] = inclusive_output;
+
+ CTA_SYNC();
+
+ if (linear_tid < INNER_WARP_THREADS)
+ {
+ T outer_warp_input = temp_storage.warp_aggregates[linear_tid];
+ T outer_warp_exclusive;
+
+ InnerWarpScanT(temp_storage.aliasable.inner_warp_scan).ExclusiveScan(
+ outer_warp_input, outer_warp_exclusive, scan_op, block_aggregate);
+
+ temp_storage.block_aggregate = block_aggregate;
+ temp_storage.warp_aggregates[linear_tid] = outer_warp_exclusive;
+ }
+
+ CTA_SYNC();
+
+ if (warp_id != 0)
+ {
+ // Retrieve block aggregate
+ block_aggregate = temp_storage.block_aggregate;
+
+ // Apply warp prefix to our lane's partial
+ T outer_warp_exclusive = temp_storage.warp_aggregates[warp_id];
+ exclusive_output = scan_op(outer_warp_exclusive, exclusive_output);
+ if (lane_id == 0)
+ exclusive_output = outer_warp_exclusive;
+ }
+ }
+
+
+ /// Computes an exclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ template <typename ScanOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input items
+ T &exclusive_output, ///< [out] Calling thread's output items (may be aliased to \p input)
+ const T &initial_value, ///< [in] Initial value to seed the exclusive scan
+ ScanOp scan_op, ///< [in] Binary scan operator
+ T &block_aggregate) ///< [out] Threadblock-wide aggregate reduction of input items
+ {
+ // Compute warp scan in each warp. The exclusive output from each lane0 is invalid.
+ T inclusive_output;
+ OuterWarpScanT(temp_storage.aliasable.outer_warp_scan.Alias()[warp_id]).Scan(
+ input, inclusive_output, exclusive_output, scan_op);
+
+ // Share outer warp total
+ if (lane_id == OUTER_WARP_THREADS - 1)
+ {
+ temp_storage.warp_aggregates[warp_id] = inclusive_output;
+ }
+
+ CTA_SYNC();
+
+ if (linear_tid < INNER_WARP_THREADS)
+ {
+ T outer_warp_input = temp_storage.warp_aggregates[linear_tid];
+ T outer_warp_exclusive;
+
+ InnerWarpScanT(temp_storage.aliasable.inner_warp_scan).ExclusiveScan(
+ outer_warp_input, outer_warp_exclusive, initial_value, scan_op, block_aggregate);
+
+ temp_storage.block_aggregate = block_aggregate;
+ temp_storage.warp_aggregates[linear_tid] = outer_warp_exclusive;
+ }
+
+ CTA_SYNC();
+
+ // Retrieve block aggregate
+ block_aggregate = temp_storage.block_aggregate;
+
+ // Apply warp prefix to our lane's partial
+ T outer_warp_exclusive = temp_storage.warp_aggregates[warp_id];
+ exclusive_output = scan_op(outer_warp_exclusive, exclusive_output);
+ if (lane_id == 0)
+ exclusive_output = outer_warp_exclusive;
+ }
+
+
+ /// Computes an exclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. The call-back functor \p block_prefix_callback_op is invoked by the first warp in the block, and the value returned by <em>lane</em><sub>0</sub> in that warp is used as the "seed" value that logically prefixes the thread block's scan inputs.
+ template <
+ typename ScanOp,
+ typename BlockPrefixCallbackOp>
+ __device__ __forceinline__ void ExclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &exclusive_output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan operator
+ BlockPrefixCallbackOp &block_prefix_callback_op) ///< [in-out] <b>[<em>warp</em><sub>0</sub> only]</b> Call-back functor for specifying a thread block-wide prefix to be applied to all inputs.
+ {
+ // Compute warp scan in each warp. The exclusive output from each lane0 is invalid.
+ T inclusive_output;
+ OuterWarpScanT(temp_storage.aliasable.outer_warp_scan.Alias()[warp_id]).Scan(
+ input, inclusive_output, exclusive_output, scan_op);
+
+ // Share outer warp total
+ if (lane_id == OUTER_WARP_THREADS - 1)
+ temp_storage.warp_aggregates[warp_id] = inclusive_output;
+
+ CTA_SYNC();
+
+ if (linear_tid < INNER_WARP_THREADS)
+ {
+ InnerWarpScanT inner_scan(temp_storage.aliasable.inner_warp_scan);
+
+ T upsweep = temp_storage.warp_aggregates[linear_tid];
+ T downsweep_prefix, block_aggregate;
+
+ inner_scan.ExclusiveScan(upsweep, downsweep_prefix, scan_op, block_aggregate);
+
+ // Use callback functor to get block prefix in lane0 and then broadcast to other lanes
+ T block_prefix = block_prefix_callback_op(block_aggregate);
+ block_prefix = inner_scan.Broadcast(block_prefix, 0);
+
+ downsweep_prefix = scan_op(block_prefix, downsweep_prefix);
+ if (linear_tid == 0)
+ downsweep_prefix = block_prefix;
+
+ temp_storage.warp_aggregates[linear_tid] = downsweep_prefix;
+ }
+
+ CTA_SYNC();
+
+ // Apply warp prefix to our lane's partial (or assign it if partial is invalid)
+ T outer_warp_exclusive = temp_storage.warp_aggregates[warp_id];
+ exclusive_output = scan_op(outer_warp_exclusive, exclusive_output);
+ if (lane_id == 0)
+ exclusive_output = outer_warp_exclusive;
+ }
+
+
+ //---------------------------------------------------------------------
+ // Inclusive scans
+ //---------------------------------------------------------------------
+
+ /// Computes an inclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element.
+ template <typename ScanOp>
+ __device__ __forceinline__ void InclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &inclusive_output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op) ///< [in] Binary scan operator
+ {
+ T block_aggregate;
+ InclusiveScan(input, inclusive_output, scan_op, block_aggregate);
+ }
+
+
+ /// Computes an inclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. Also provides every thread with the block-wide \p block_aggregate of all inputs.
+ template <typename ScanOp>
+ __device__ __forceinline__ void InclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &inclusive_output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan operator
+ T &block_aggregate) ///< [out] Threadblock-wide aggregate reduction of input items
+ {
+ // Compute warp scan in each warp. The exclusive output from each lane0 is invalid.
+ OuterWarpScanT(temp_storage.aliasable.outer_warp_scan.Alias()[warp_id]).InclusiveScan(
+ input, inclusive_output, scan_op);
+
+ // Share outer warp total
+ if (lane_id == OUTER_WARP_THREADS - 1)
+ temp_storage.warp_aggregates[warp_id] = inclusive_output;
+
+ CTA_SYNC();
+
+ if (linear_tid < INNER_WARP_THREADS)
+ {
+ T outer_warp_input = temp_storage.warp_aggregates[linear_tid];
+ T outer_warp_exclusive;
+
+ InnerWarpScanT(temp_storage.aliasable.inner_warp_scan).ExclusiveScan(
+ outer_warp_input, outer_warp_exclusive, scan_op, block_aggregate);
+
+ temp_storage.block_aggregate = block_aggregate;
+ temp_storage.warp_aggregates[linear_tid] = outer_warp_exclusive;
+ }
+
+ CTA_SYNC();
+
+ if (warp_id != 0)
+ {
+ // Retrieve block aggregate
+ block_aggregate = temp_storage.block_aggregate;
+
+ // Apply warp prefix to our lane's partial
+ T outer_warp_exclusive = temp_storage.warp_aggregates[warp_id];
+ inclusive_output = scan_op(outer_warp_exclusive, inclusive_output);
+ }
+ }
+
+
+ /// Computes an inclusive thread block-wide prefix scan using the specified binary \p scan_op functor. Each thread contributes one input element. the call-back functor \p block_prefix_callback_op is invoked by the first warp in the block, and the value returned by <em>lane</em><sub>0</sub> in that warp is used as the "seed" value that logically prefixes the thread block's scan inputs.
+ template <
+ typename ScanOp,
+ typename BlockPrefixCallbackOp>
+ __device__ __forceinline__ void InclusiveScan(
+ T input, ///< [in] Calling thread's input item
+ T &inclusive_output, ///< [out] Calling thread's output item (may be aliased to \p input)
+ ScanOp scan_op, ///< [in] Binary scan operator
+ BlockPrefixCallbackOp &block_prefix_callback_op) ///< [in-out] <b>[<em>warp</em><sub>0</sub> only]</b> Call-back functor for specifying a thread block-wide prefix to be applied to all inputs.
+ {
+ // Compute warp scan in each warp. The exclusive output from each lane0 is invalid.
+ OuterWarpScanT(temp_storage.aliasable.outer_warp_scan.Alias()[warp_id]).InclusiveScan(
+ input, inclusive_output, scan_op);
+
+ // Share outer warp total
+ if (lane_id == OUTER_WARP_THREADS - 1)
+ temp_storage.warp_aggregates[warp_id] = inclusive_output;
+
+ CTA_SYNC();
+
+ if (linear_tid < INNER_WARP_THREADS)
+ {
+ InnerWarpScanT inner_scan(temp_storage.aliasable.inner_warp_scan);
+
+ T upsweep = temp_storage.warp_aggregates[linear_tid];
+ T downsweep_prefix, block_aggregate;
+ inner_scan.ExclusiveScan(upsweep, downsweep_prefix, scan_op, block_aggregate);
+
+ // Use callback functor to get block prefix in lane0 and then broadcast to other lanes
+ T block_prefix = block_prefix_callback_op(block_aggregate);
+ block_prefix = inner_scan.Broadcast(block_prefix, 0);
+
+ downsweep_prefix = scan_op(block_prefix, downsweep_prefix);
+ if (linear_tid == 0)
+ downsweep_prefix = block_prefix;
+
+ temp_storage.warp_aggregates[linear_tid] = downsweep_prefix;
+ }
+
+ CTA_SYNC();
+
+ // Apply warp prefix to our lane's partial
+ T outer_warp_exclusive = temp_storage.warp_aggregates[warp_id];
+ inclusive_output = scan_op(outer_warp_exclusive, inclusive_output);
+ }
+
+
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+