aboutsummaryrefslogtreecommitdiff
path: root/debug_tools/WatchYourStep/ptxjitplus/inc/cub/warp/specializations
diff options
context:
space:
mode:
authorJonathan <[email protected]>2018-06-26 13:20:39 -0700
committerJonathan <[email protected]>2018-06-26 13:20:39 -0700
commit584ebaa74a838680e6ed1fa13ac266e88c30c071 (patch)
tree59523a4db9b6b4923611777928818d0bfc8b0ffc /debug_tools/WatchYourStep/ptxjitplus/inc/cub/warp/specializations
parent978730086509050df16b77b9fbb4cc3ef19f3f6a (diff)
exports and imports param data in new debug tool: WatchYourStep
Diffstat (limited to 'debug_tools/WatchYourStep/ptxjitplus/inc/cub/warp/specializations')
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/warp/specializations/warp_reduce_shfl.cuh541
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/warp/specializations/warp_reduce_smem.cuh372
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/warp/specializations/warp_scan_shfl.cuh632
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/warp/specializations/warp_scan_smem.cuh397
4 files changed, 1942 insertions, 0 deletions
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/warp/specializations/warp_reduce_shfl.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/warp/specializations/warp_reduce_shfl.cuh
new file mode 100644
index 0000000..bbbf37e
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/warp/specializations/warp_reduce_shfl.cuh
@@ -0,0 +1,541 @@
+/******************************************************************************
+ * 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::WarpReduceShfl provides SHFL-based variants of parallel reduction of items partitioned across a CUDA thread warp.
+ */
+
+#pragma once
+
+#include "../../thread/thread_operators.cuh"
+#include "../../util_ptx.cuh"
+#include "../../util_type.cuh"
+#include "../../util_macro.cuh"
+#include "../../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+/**
+ * \brief WarpReduceShfl provides SHFL-based variants of parallel reduction of items partitioned across a CUDA thread warp.
+ *
+ * LOGICAL_WARP_THREADS must be a power-of-two
+ */
+template <
+ typename T, ///< Data type being reduced
+ int LOGICAL_WARP_THREADS, ///< Number of threads per logical warp
+ int PTX_ARCH> ///< The PTX compute capability for which to to specialize this collective
+struct WarpReduceShfl
+{
+ //---------------------------------------------------------------------
+ // Constants and type definitions
+ //---------------------------------------------------------------------
+
+ enum
+ {
+ /// Whether the logical warp size and the PTX warp size coincide
+ IS_ARCH_WARP = (LOGICAL_WARP_THREADS == CUB_WARP_THREADS(PTX_ARCH)),
+
+ /// The number of warp reduction steps
+ STEPS = Log2<LOGICAL_WARP_THREADS>::VALUE,
+
+ /// Number of logical warps in a PTX warp
+ LOGICAL_WARPS = CUB_WARP_THREADS(PTX_ARCH) / LOGICAL_WARP_THREADS,
+
+ /// The 5-bit SHFL mask for logically splitting warps into sub-segments starts 8-bits up
+ SHFL_C = (CUB_WARP_THREADS(PTX_ARCH) - LOGICAL_WARP_THREADS) << 8
+
+ };
+
+ template <typename S>
+ struct IsInteger
+ {
+ enum {
+ ///Whether the data type is a small (32b or less) integer for which we can use a single SFHL instruction per exchange
+ IS_SMALL_UNSIGNED = (Traits<S>::CATEGORY == UNSIGNED_INTEGER) && (sizeof(S) <= sizeof(unsigned int))
+ };
+ };
+
+
+ /// Shared memory storage layout type
+ typedef NullType TempStorage;
+
+
+ //---------------------------------------------------------------------
+ // Thread fields
+ //---------------------------------------------------------------------
+
+ /// Lane index in logical warp
+ unsigned int lane_id;
+
+ /// Logical warp index in 32-thread physical warp
+ unsigned int warp_id;
+
+ /// 32-thread physical warp member mask of logical warp
+ unsigned int member_mask;
+
+
+ //---------------------------------------------------------------------
+ // Construction
+ //---------------------------------------------------------------------
+
+ /// Constructor
+ __device__ __forceinline__ WarpReduceShfl(
+ TempStorage &/*temp_storage*/)
+ {
+ lane_id = LaneId();
+ warp_id = 0;
+ member_mask = 0xffffffffu >> (CUB_WARP_THREADS(PTX_ARCH) - LOGICAL_WARP_THREADS);
+
+ if (!IS_ARCH_WARP)
+ {
+ warp_id = lane_id / LOGICAL_WARP_THREADS;
+ lane_id = lane_id % LOGICAL_WARP_THREADS;
+ member_mask = member_mask << (warp_id * LOGICAL_WARP_THREADS);
+ }
+ }
+
+
+ //---------------------------------------------------------------------
+ // Reduction steps
+ //---------------------------------------------------------------------
+
+ /// Reduction (specialized for summation across uint32 types)
+ __device__ __forceinline__ unsigned int ReduceStep(
+ unsigned int input, ///< [in] Calling thread's input item.
+ cub::Sum /*reduction_op*/, ///< [in] Binary reduction operator
+ int last_lane, ///< [in] Index of last lane in segment
+ int offset) ///< [in] Up-offset to pull from
+ {
+ unsigned int output;
+ int shfl_c = last_lane | SHFL_C; // Shuffle control (mask and last_lane)
+
+ // Use predicate set from SHFL to guard against invalid peers
+#ifdef CUB_USE_COOPERATIVE_GROUPS
+ asm volatile(
+ "{"
+ " .reg .u32 r0;"
+ " .reg .pred p;"
+ " shfl.sync.down.b32 r0|p, %1, %2, %3, %5;"
+ " @p add.u32 r0, r0, %4;"
+ " mov.u32 %0, r0;"
+ "}"
+ : "=r"(output) : "r"(input), "r"(offset), "r"(shfl_c), "r"(input), "r"(member_mask));
+#else
+ asm volatile(
+ "{"
+ " .reg .u32 r0;"
+ " .reg .pred p;"
+ " shfl.down.b32 r0|p, %1, %2, %3;"
+ " @p add.u32 r0, r0, %4;"
+ " mov.u32 %0, r0;"
+ "}"
+ : "=r"(output) : "r"(input), "r"(offset), "r"(shfl_c), "r"(input));
+#endif
+
+ return output;
+ }
+
+
+ /// Reduction (specialized for summation across fp32 types)
+ __device__ __forceinline__ float ReduceStep(
+ float input, ///< [in] Calling thread's input item.
+ cub::Sum /*reduction_op*/, ///< [in] Binary reduction operator
+ int last_lane, ///< [in] Index of last lane in segment
+ int offset) ///< [in] Up-offset to pull from
+ {
+ float output;
+ int shfl_c = last_lane | SHFL_C; // Shuffle control (mask and last_lane)
+
+ // Use predicate set from SHFL to guard against invalid peers
+#ifdef CUB_USE_COOPERATIVE_GROUPS
+ asm volatile(
+ "{"
+ " .reg .f32 r0;"
+ " .reg .pred p;"
+ " shfl.sync.down.b32 r0|p, %1, %2, %3, %5;"
+ " @p add.f32 r0, r0, %4;"
+ " mov.f32 %0, r0;"
+ "}"
+ : "=f"(output) : "f"(input), "r"(offset), "r"(shfl_c), "f"(input), "r"(member_mask));
+#else
+ asm volatile(
+ "{"
+ " .reg .f32 r0;"
+ " .reg .pred p;"
+ " shfl.down.b32 r0|p, %1, %2, %3;"
+ " @p add.f32 r0, r0, %4;"
+ " mov.f32 %0, r0;"
+ "}"
+ : "=f"(output) : "f"(input), "r"(offset), "r"(shfl_c), "f"(input));
+#endif
+
+ return output;
+ }
+
+
+ /// Reduction (specialized for summation across unsigned long long types)
+ __device__ __forceinline__ unsigned long long ReduceStep(
+ unsigned long long input, ///< [in] Calling thread's input item.
+ cub::Sum /*reduction_op*/, ///< [in] Binary reduction operator
+ int last_lane, ///< [in] Index of last lane in segment
+ int offset) ///< [in] Up-offset to pull from
+ {
+ unsigned long long output;
+ int shfl_c = last_lane | SHFL_C; // Shuffle control (mask and last_lane)
+
+#ifdef CUB_USE_COOPERATIVE_GROUPS
+ asm volatile(
+ "{"
+ " .reg .u32 lo;"
+ " .reg .u32 hi;"
+ " .reg .pred p;"
+ " mov.b64 {lo, hi}, %1;"
+ " shfl.sync.down.b32 lo|p, lo, %2, %3, %4;"
+ " shfl.sync.down.b32 hi|p, hi, %2, %3, %4;"
+ " mov.b64 %0, {lo, hi};"
+ " @p add.u64 %0, %0, %1;"
+ "}"
+ : "=l"(output) : "l"(input), "r"(offset), "r"(shfl_c), "r"(member_mask));
+#else
+ asm volatile(
+ "{"
+ " .reg .u32 lo;"
+ " .reg .u32 hi;"
+ " .reg .pred p;"
+ " mov.b64 {lo, hi}, %1;"
+ " shfl.down.b32 lo|p, lo, %2, %3;"
+ " shfl.down.b32 hi|p, hi, %2, %3;"
+ " mov.b64 %0, {lo, hi};"
+ " @p add.u64 %0, %0, %1;"
+ "}"
+ : "=l"(output) : "l"(input), "r"(offset), "r"(shfl_c));
+#endif
+
+ return output;
+ }
+
+
+ /// Reduction (specialized for summation across long long types)
+ __device__ __forceinline__ long long ReduceStep(
+ long long input, ///< [in] Calling thread's input item.
+ cub::Sum /*reduction_op*/, ///< [in] Binary reduction operator
+ int last_lane, ///< [in] Index of last lane in segment
+ int offset) ///< [in] Up-offset to pull from
+ {
+ long long output;
+ int shfl_c = last_lane | SHFL_C; // Shuffle control (mask and last_lane)
+
+ // Use predicate set from SHFL to guard against invalid peers
+#ifdef CUB_USE_COOPERATIVE_GROUPS
+ asm volatile(
+ "{"
+ " .reg .u32 lo;"
+ " .reg .u32 hi;"
+ " .reg .pred p;"
+ " mov.b64 {lo, hi}, %1;"
+ " shfl.sync.down.b32 lo|p, lo, %2, %3, %4;"
+ " shfl.sync.down.b32 hi|p, hi, %2, %3, %4;"
+ " mov.b64 %0, {lo, hi};"
+ " @p add.s64 %0, %0, %1;"
+ "}"
+ : "=l"(output) : "l"(input), "r"(offset), "r"(shfl_c), "r"(member_mask));
+#else
+ asm volatile(
+ "{"
+ " .reg .u32 lo;"
+ " .reg .u32 hi;"
+ " .reg .pred p;"
+ " mov.b64 {lo, hi}, %1;"
+ " shfl.down.b32 lo|p, lo, %2, %3;"
+ " shfl.down.b32 hi|p, hi, %2, %3;"
+ " mov.b64 %0, {lo, hi};"
+ " @p add.s64 %0, %0, %1;"
+ "}"
+ : "=l"(output) : "l"(input), "r"(offset), "r"(shfl_c));
+#endif
+
+ return output;
+ }
+
+
+ /// Reduction (specialized for summation across double types)
+ __device__ __forceinline__ double ReduceStep(
+ double input, ///< [in] Calling thread's input item.
+ cub::Sum /*reduction_op*/, ///< [in] Binary reduction operator
+ int last_lane, ///< [in] Index of last lane in segment
+ int offset) ///< [in] Up-offset to pull from
+ {
+ double output;
+ int shfl_c = last_lane | SHFL_C; // Shuffle control (mask and last_lane)
+
+ // Use predicate set from SHFL to guard against invalid peers
+#ifdef CUB_USE_COOPERATIVE_GROUPS
+ asm volatile(
+ "{"
+ " .reg .u32 lo;"
+ " .reg .u32 hi;"
+ " .reg .pred p;"
+ " .reg .f64 r0;"
+ " mov.b64 %0, %1;"
+ " mov.b64 {lo, hi}, %1;"
+ " shfl.sync.down.b32 lo|p, lo, %2, %3, %4;"
+ " shfl.sync.down.b32 hi|p, hi, %2, %3, %4;"
+ " mov.b64 r0, {lo, hi};"
+ " @p add.f64 %0, %0, r0;"
+ "}"
+ : "=d"(output) : "d"(input), "r"(offset), "r"(shfl_c), "r"(member_mask));
+#else
+ asm volatile(
+ "{"
+ " .reg .u32 lo;"
+ " .reg .u32 hi;"
+ " .reg .pred p;"
+ " .reg .f64 r0;"
+ " mov.b64 %0, %1;"
+ " mov.b64 {lo, hi}, %1;"
+ " shfl.down.b32 lo|p, lo, %2, %3;"
+ " shfl.down.b32 hi|p, hi, %2, %3;"
+ " mov.b64 r0, {lo, hi};"
+ " @p add.f64 %0, %0, r0;"
+ "}"
+ : "=d"(output) : "d"(input), "r"(offset), "r"(shfl_c));
+#endif
+
+ return output;
+ }
+
+
+ /// Reduction (specialized for swizzled ReduceByKeyOp<cub::Sum> across KeyValuePair<KeyT, ValueT> types)
+ template <typename ValueT, typename KeyT>
+ __device__ __forceinline__ KeyValuePair<KeyT, ValueT> ReduceStep(
+ KeyValuePair<KeyT, ValueT> input, ///< [in] Calling thread's input item.
+ SwizzleScanOp<ReduceByKeyOp<cub::Sum> > /*reduction_op*/, ///< [in] Binary reduction operator
+ int last_lane, ///< [in] Index of last lane in segment
+ int offset) ///< [in] Up-offset to pull from
+ {
+ KeyValuePair<KeyT, ValueT> output;
+
+ KeyT other_key = ShuffleDown<LOGICAL_WARP_THREADS>(input.key, offset, last_lane, member_mask);
+
+ output.key = input.key;
+ output.value = ReduceStep(
+ input.value,
+ cub::Sum(),
+ last_lane,
+ offset,
+ Int2Type<IsInteger<ValueT>::IS_SMALL_UNSIGNED>());
+
+ if (input.key != other_key)
+ output.value = input.value;
+
+ return output;
+ }
+
+
+
+ /// Reduction (specialized for swizzled ReduceBySegmentOp<cub::Sum> across KeyValuePair<OffsetT, ValueT> types)
+ template <typename ValueT, typename OffsetT>
+ __device__ __forceinline__ KeyValuePair<OffsetT, ValueT> ReduceStep(
+ KeyValuePair<OffsetT, ValueT> input, ///< [in] Calling thread's input item.
+ SwizzleScanOp<ReduceBySegmentOp<cub::Sum> > /*reduction_op*/, ///< [in] Binary reduction operator
+ int last_lane, ///< [in] Index of last lane in segment
+ int offset) ///< [in] Up-offset to pull from
+ {
+ KeyValuePair<OffsetT, ValueT> output;
+
+ output.value = ReduceStep(input.value, cub::Sum(), last_lane, offset, Int2Type<IsInteger<ValueT>::IS_SMALL_UNSIGNED>());
+ output.key = ReduceStep(input.key, cub::Sum(), last_lane, offset, Int2Type<IsInteger<OffsetT>::IS_SMALL_UNSIGNED>());
+
+ if (input.key > 0)
+ output.value = input.value;
+
+ return output;
+ }
+
+
+ /// Reduction step (generic)
+ template <typename _T, typename ReductionOp>
+ __device__ __forceinline__ _T ReduceStep(
+ _T input, ///< [in] Calling thread's input item.
+ ReductionOp reduction_op, ///< [in] Binary reduction operator
+ int last_lane, ///< [in] Index of last lane in segment
+ int offset) ///< [in] Up-offset to pull from
+ {
+ _T output = input;
+
+ _T temp = ShuffleDown<LOGICAL_WARP_THREADS>(output, offset, last_lane, member_mask);
+
+ // Perform reduction op if valid
+ if (offset + lane_id <= last_lane)
+ output = reduction_op(input, temp);
+
+ return output;
+ }
+
+
+ /// Reduction step (specialized for small unsigned integers size 32b or less)
+ template <typename _T, typename ReductionOp>
+ __device__ __forceinline__ _T ReduceStep(
+ _T input, ///< [in] Calling thread's input item.
+ ReductionOp reduction_op, ///< [in] Binary reduction operator
+ int last_lane, ///< [in] Index of last lane in segment
+ int offset, ///< [in] Up-offset to pull from
+ Int2Type<true> /*is_small_unsigned*/) ///< [in] Marker type indicating whether T is a small unsigned integer
+ {
+ return ReduceStep(input, reduction_op, last_lane, offset);
+ }
+
+
+ /// Reduction step (specialized for types other than small unsigned integers size 32b or less)
+ template <typename _T, typename ReductionOp>
+ __device__ __forceinline__ _T ReduceStep(
+ _T input, ///< [in] Calling thread's input item.
+ ReductionOp reduction_op, ///< [in] Binary reduction operator
+ int last_lane, ///< [in] Index of last lane in segment
+ int offset, ///< [in] Up-offset to pull from
+ Int2Type<false> /*is_small_unsigned*/) ///< [in] Marker type indicating whether T is a small unsigned integer
+ {
+ return ReduceStep(input, reduction_op, last_lane, offset);
+ }
+
+
+ //---------------------------------------------------------------------
+ // Templated inclusive scan iteration
+ //---------------------------------------------------------------------
+
+ template <typename ReductionOp, int STEP>
+ __device__ __forceinline__ void ReduceStep(
+ T& input, ///< [in] Calling thread's input item.
+ ReductionOp reduction_op, ///< [in] Binary reduction operator
+ int last_lane, ///< [in] Index of last lane in segment
+ Int2Type<STEP> /*step*/)
+ {
+ input = ReduceStep(input, reduction_op, last_lane, 1 << STEP, Int2Type<IsInteger<T>::IS_SMALL_UNSIGNED>());
+
+ ReduceStep(input, reduction_op, last_lane, Int2Type<STEP + 1>());
+ }
+
+ template <typename ReductionOp>
+ __device__ __forceinline__ void ReduceStep(
+ T& /*input*/, ///< [in] Calling thread's input item.
+ ReductionOp /*reduction_op*/, ///< [in] Binary reduction operator
+ int /*last_lane*/, ///< [in] Index of last lane in segment
+ Int2Type<STEPS> /*step*/)
+ {}
+
+
+ //---------------------------------------------------------------------
+ // Reduction operations
+ //---------------------------------------------------------------------
+
+ /// Reduction
+ template <
+ bool ALL_LANES_VALID, ///< Whether all lanes in each warp are contributing a valid fold of items
+ typename ReductionOp>
+ __device__ __forceinline__ T Reduce(
+ T input, ///< [in] Calling thread's input
+ int valid_items, ///< [in] Total number of valid items across the logical warp
+ ReductionOp reduction_op) ///< [in] Binary reduction operator
+ {
+ int last_lane = (ALL_LANES_VALID) ?
+ LOGICAL_WARP_THREADS - 1 :
+ valid_items - 1;
+
+ T output = input;
+
+// // Iterate reduction steps
+// #pragma unroll
+// for (int STEP = 0; STEP < STEPS; STEP++)
+// {
+// output = ReduceStep(output, reduction_op, last_lane, 1 << STEP, Int2Type<IsInteger<T>::IS_SMALL_UNSIGNED>());
+// }
+
+ // Template-iterate reduction steps
+ ReduceStep(output, reduction_op, last_lane, Int2Type<0>());
+
+ return output;
+ }
+
+
+ /// Segmented reduction
+ template <
+ bool HEAD_SEGMENTED, ///< Whether flags indicate a segment-head or a segment-tail
+ typename FlagT,
+ typename ReductionOp>
+ __device__ __forceinline__ T SegmentedReduce(
+ T input, ///< [in] Calling thread's input
+ FlagT flag, ///< [in] Whether or not the current lane is a segment head/tail
+ ReductionOp reduction_op) ///< [in] Binary reduction operator
+ {
+ // Get the start flags for each thread in the warp.
+ int warp_flags = WARP_BALLOT(flag, member_mask);
+
+ // Convert to tail-segmented
+ if (HEAD_SEGMENTED)
+ warp_flags >>= 1;
+
+ // Mask out the bits below the current thread
+ warp_flags &= LaneMaskGe();
+
+ // Mask of physical lanes outside the logical warp and convert to logical lanemask
+ if (!IS_ARCH_WARP)
+ {
+ warp_flags = (warp_flags & member_mask) >> (warp_id * LOGICAL_WARP_THREADS);
+ }
+
+ // Mask in the last lane of logical warp
+ warp_flags |= 1u << (LOGICAL_WARP_THREADS - 1);
+
+ // Find the next set flag
+ int last_lane = __clz(__brev(warp_flags));
+
+ T output = input;
+
+// // Iterate reduction steps
+// #pragma unroll
+// for (int STEP = 0; STEP < STEPS; STEP++)
+// {
+// output = ReduceStep(output, reduction_op, last_lane, 1 << STEP, Int2Type<IsInteger<T>::IS_SMALL_UNSIGNED>());
+// }
+
+ // Template-iterate reduction steps
+ ReduceStep(output, reduction_op, last_lane, Int2Type<0>());
+
+ return output;
+ }
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/warp/specializations/warp_reduce_smem.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/warp/specializations/warp_reduce_smem.cuh
new file mode 100644
index 0000000..7baa573
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/warp/specializations/warp_reduce_smem.cuh
@@ -0,0 +1,372 @@
+/******************************************************************************
+ * 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::WarpReduceSmem provides smem-based variants of parallel reduction of items partitioned across a CUDA thread warp.
+ */
+
+#pragma once
+
+#include "../../thread/thread_operators.cuh"
+#include "../../thread/thread_load.cuh"
+#include "../../thread/thread_store.cuh"
+#include "../../util_type.cuh"
+#include "../../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+/**
+ * \brief WarpReduceSmem provides smem-based variants of parallel reduction of items partitioned across a CUDA thread warp.
+ */
+template <
+ typename T, ///< Data type being reduced
+ int LOGICAL_WARP_THREADS, ///< Number of threads per logical warp
+ int PTX_ARCH> ///< The PTX compute capability for which to to specialize this collective
+struct WarpReduceSmem
+{
+ /******************************************************************************
+ * Constants and type definitions
+ ******************************************************************************/
+
+ enum
+ {
+ /// Whether the logical warp size and the PTX warp size coincide
+ IS_ARCH_WARP = (LOGICAL_WARP_THREADS == CUB_WARP_THREADS(PTX_ARCH)),
+
+ /// Whether the logical warp size is a power-of-two
+ IS_POW_OF_TWO = PowerOfTwo<LOGICAL_WARP_THREADS>::VALUE,
+
+ /// The number of warp scan steps
+ STEPS = Log2<LOGICAL_WARP_THREADS>::VALUE,
+
+ /// The number of threads in half a warp
+ HALF_WARP_THREADS = 1 << (STEPS - 1),
+
+ /// The number of shared memory elements per warp
+ WARP_SMEM_ELEMENTS = LOGICAL_WARP_THREADS + HALF_WARP_THREADS,
+
+ /// FlagT status (when not using ballot)
+ UNSET = 0x0, // Is initially unset
+ SET = 0x1, // Is initially set
+ SEEN = 0x2, // Has seen another head flag from a successor peer
+ };
+
+ /// Shared memory flag type
+ typedef unsigned char SmemFlag;
+
+ /// Shared memory storage layout type (1.5 warps-worth of elements for each warp)
+ struct _TempStorage
+ {
+ T reduce[WARP_SMEM_ELEMENTS];
+ SmemFlag flags[WARP_SMEM_ELEMENTS];
+ };
+
+ // Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ /******************************************************************************
+ * Thread fields
+ ******************************************************************************/
+
+ _TempStorage &temp_storage;
+ unsigned int lane_id;
+ unsigned int member_mask;
+
+
+ /******************************************************************************
+ * Construction
+ ******************************************************************************/
+
+ /// Constructor
+ __device__ __forceinline__ WarpReduceSmem(
+ TempStorage &temp_storage)
+ :
+ temp_storage(temp_storage.Alias()),
+
+ lane_id(IS_ARCH_WARP ?
+ LaneId() :
+ LaneId() % LOGICAL_WARP_THREADS),
+
+ member_mask((0xffffffff >> (32 - LOGICAL_WARP_THREADS)) << ((IS_ARCH_WARP || !IS_POW_OF_TWO ) ?
+ 0 : // arch-width and non-power-of-two subwarps cannot be tiled with the arch-warp
+ ((LaneId() / LOGICAL_WARP_THREADS) * LOGICAL_WARP_THREADS)))
+ {}
+
+ /******************************************************************************
+ * Utility methods
+ ******************************************************************************/
+
+ //---------------------------------------------------------------------
+ // Regular reduction
+ //---------------------------------------------------------------------
+
+ /**
+ * Reduction step
+ */
+ template <
+ bool ALL_LANES_VALID, ///< Whether all lanes in each warp are contributing a valid fold of items
+ typename ReductionOp,
+ int STEP>
+ __device__ __forceinline__ T ReduceStep(
+ T input, ///< [in] Calling thread's input
+ int valid_items, ///< [in] Total number of valid items across the logical warp
+ ReductionOp reduction_op, ///< [in] Reduction operator
+ Int2Type<STEP> /*step*/)
+ {
+ const int OFFSET = 1 << STEP;
+
+ // Share input through buffer
+ ThreadStore<STORE_VOLATILE>(&temp_storage.reduce[lane_id], input);
+
+ WARP_SYNC(member_mask);
+
+ // Update input if peer_addend is in range
+ if ((ALL_LANES_VALID && IS_POW_OF_TWO) || ((lane_id + OFFSET) < valid_items))
+ {
+ T peer_addend = ThreadLoad<LOAD_VOLATILE>(&temp_storage.reduce[lane_id + OFFSET]);
+ input = reduction_op(input, peer_addend);
+ }
+
+ WARP_SYNC(member_mask);
+
+ return ReduceStep<ALL_LANES_VALID>(input, valid_items, reduction_op, Int2Type<STEP + 1>());
+ }
+
+
+ /**
+ * Reduction step (terminate)
+ */
+ template <
+ bool ALL_LANES_VALID, ///< Whether all lanes in each warp are contributing a valid fold of items
+ typename ReductionOp>
+ __device__ __forceinline__ T ReduceStep(
+ T input, ///< [in] Calling thread's input
+ int valid_items, ///< [in] Total number of valid items across the logical warp
+ ReductionOp /*reduction_op*/, ///< [in] Reduction operator
+ Int2Type<STEPS> /*step*/)
+ {
+ return input;
+ }
+
+
+ //---------------------------------------------------------------------
+ // Segmented reduction
+ //---------------------------------------------------------------------
+
+
+ /**
+ * Ballot-based segmented reduce
+ */
+ template <
+ bool HEAD_SEGMENTED, ///< Whether flags indicate a segment-head or a segment-tail
+ typename FlagT,
+ typename ReductionOp>
+ __device__ __forceinline__ T SegmentedReduce(
+ T input, ///< [in] Calling thread's input
+ FlagT flag, ///< [in] Whether or not the current lane is a segment head/tail
+ ReductionOp reduction_op, ///< [in] Reduction operator
+ Int2Type<true> /*has_ballot*/) ///< [in] Marker type for whether the target arch has ballot functionality
+ {
+ // Get the start flags for each thread in the warp.
+ int warp_flags = WARP_BALLOT(flag, member_mask);
+
+ if (!HEAD_SEGMENTED)
+ warp_flags <<= 1;
+
+ // Keep bits above the current thread.
+ warp_flags &= LaneMaskGt();
+
+ // Accommodate packing of multiple logical warps in a single physical warp
+ if (!IS_ARCH_WARP)
+ {
+ warp_flags >>= (LaneId() / LOGICAL_WARP_THREADS) * LOGICAL_WARP_THREADS;
+ }
+
+ // Find next flag
+ int next_flag = __clz(__brev(warp_flags));
+
+ // Clip the next segment at the warp boundary if necessary
+ if (LOGICAL_WARP_THREADS != 32)
+ next_flag = CUB_MIN(next_flag, LOGICAL_WARP_THREADS);
+
+ #pragma unroll
+ for (int STEP = 0; STEP < STEPS; STEP++)
+ {
+ const int OFFSET = 1 << STEP;
+
+ // Share input into buffer
+ ThreadStore<STORE_VOLATILE>(&temp_storage.reduce[lane_id], input);
+
+ WARP_SYNC(member_mask);
+
+ // Update input if peer_addend is in range
+ if (OFFSET + lane_id < next_flag)
+ {
+ T peer_addend = ThreadLoad<LOAD_VOLATILE>(&temp_storage.reduce[lane_id + OFFSET]);
+ input = reduction_op(input, peer_addend);
+ }
+
+ WARP_SYNC(member_mask);
+ }
+
+ return input;
+ }
+
+
+ /**
+ * Smem-based segmented reduce
+ */
+ template <
+ bool HEAD_SEGMENTED, ///< Whether flags indicate a segment-head or a segment-tail
+ typename FlagT,
+ typename ReductionOp>
+ __device__ __forceinline__ T SegmentedReduce(
+ T input, ///< [in] Calling thread's input
+ FlagT flag, ///< [in] Whether or not the current lane is a segment head/tail
+ ReductionOp reduction_op, ///< [in] Reduction operator
+ Int2Type<false> /*has_ballot*/) ///< [in] Marker type for whether the target arch has ballot functionality
+ {
+ enum
+ {
+ UNSET = 0x0, // Is initially unset
+ SET = 0x1, // Is initially set
+ SEEN = 0x2, // Has seen another head flag from a successor peer
+ };
+
+ // Alias flags onto shared data storage
+ volatile SmemFlag *flag_storage = temp_storage.flags;
+
+ SmemFlag flag_status = (flag) ? SET : UNSET;
+
+ for (int STEP = 0; STEP < STEPS; STEP++)
+ {
+ const int OFFSET = 1 << STEP;
+
+ // Share input through buffer
+ ThreadStore<STORE_VOLATILE>(&temp_storage.reduce[lane_id], input);
+
+ WARP_SYNC(member_mask);
+
+ // Get peer from buffer
+ T peer_addend = ThreadLoad<LOAD_VOLATILE>(&temp_storage.reduce[lane_id + OFFSET]);
+
+ WARP_SYNC(member_mask);
+
+ // Share flag through buffer
+ flag_storage[lane_id] = flag_status;
+
+ // Get peer flag from buffer
+ SmemFlag peer_flag_status = flag_storage[lane_id + OFFSET];
+
+ // Update input if peer was in range
+ if (lane_id < LOGICAL_WARP_THREADS - OFFSET)
+ {
+ if (HEAD_SEGMENTED)
+ {
+ // Head-segmented
+ if ((flag_status & SEEN) == 0)
+ {
+ // Has not seen a more distant head flag
+ if (peer_flag_status & SET)
+ {
+ // Has now seen a head flag
+ flag_status |= SEEN;
+ }
+ else
+ {
+ // Peer is not a head flag: grab its count
+ input = reduction_op(input, peer_addend);
+ }
+
+ // Update seen status to include that of peer
+ flag_status |= (peer_flag_status & SEEN);
+ }
+ }
+ else
+ {
+ // Tail-segmented. Simply propagate flag status
+ if (!flag_status)
+ {
+ input = reduction_op(input, peer_addend);
+ flag_status |= peer_flag_status;
+ }
+
+ }
+ }
+ }
+
+ return input;
+ }
+
+
+ /******************************************************************************
+ * Interface
+ ******************************************************************************/
+
+ /**
+ * Reduction
+ */
+ template <
+ bool ALL_LANES_VALID, ///< Whether all lanes in each warp are contributing a valid fold of items
+ typename ReductionOp>
+ __device__ __forceinline__ T Reduce(
+ T input, ///< [in] Calling thread's input
+ int valid_items, ///< [in] Total number of valid items across the logical warp
+ ReductionOp reduction_op) ///< [in] Reduction operator
+ {
+ return ReduceStep<ALL_LANES_VALID>(input, valid_items, reduction_op, Int2Type<0>());
+ }
+
+
+ /**
+ * Segmented reduction
+ */
+ template <
+ bool HEAD_SEGMENTED, ///< Whether flags indicate a segment-head or a segment-tail
+ typename FlagT,
+ typename ReductionOp>
+ __device__ __forceinline__ T SegmentedReduce(
+ T input, ///< [in] Calling thread's input
+ FlagT flag, ///< [in] Whether or not the current lane is a segment head/tail
+ ReductionOp reduction_op) ///< [in] Reduction operator
+ {
+ return SegmentedReduce<HEAD_SEGMENTED>(input, flag, reduction_op, Int2Type<(PTX_ARCH >= 200)>());
+ }
+
+
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/warp/specializations/warp_scan_shfl.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/warp/specializations/warp_scan_shfl.cuh
new file mode 100644
index 0000000..7f4e1c9
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/warp/specializations/warp_scan_shfl.cuh
@@ -0,0 +1,632 @@
+/******************************************************************************
+ * 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::WarpScanShfl provides SHFL-based variants of parallel prefix scan of items partitioned across a CUDA thread warp.
+ */
+
+#pragma once
+
+#include "../../thread/thread_operators.cuh"
+#include "../../util_type.cuh"
+#include "../../util_ptx.cuh"
+#include "../../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+/**
+ * \brief WarpScanShfl provides SHFL-based variants of parallel prefix scan of items partitioned across a CUDA thread warp.
+ *
+ * LOGICAL_WARP_THREADS must be a power-of-two
+ */
+template <
+ typename T, ///< Data type being scanned
+ int LOGICAL_WARP_THREADS, ///< Number of threads per logical warp
+ int PTX_ARCH> ///< The PTX compute capability for which to to specialize this collective
+struct WarpScanShfl
+{
+ //---------------------------------------------------------------------
+ // Constants and type definitions
+ //---------------------------------------------------------------------
+
+ enum
+ {
+ /// Whether the logical warp size and the PTX warp size coincide
+ IS_ARCH_WARP = (LOGICAL_WARP_THREADS == CUB_WARP_THREADS(PTX_ARCH)),
+
+ /// The number of warp scan steps
+ STEPS = Log2<LOGICAL_WARP_THREADS>::VALUE,
+
+ /// The 5-bit SHFL mask for logically splitting warps into sub-segments starts 8-bits up
+ SHFL_C = (CUB_WARP_THREADS(PTX_ARCH) - LOGICAL_WARP_THREADS) << 8
+ };
+
+ template <typename S>
+ struct IntegerTraits
+ {
+ enum {
+ ///Whether the data type is a small (32b or less) integer for which we can use a single SFHL instruction per exchange
+ IS_SMALL_UNSIGNED = (Traits<S>::CATEGORY == UNSIGNED_INTEGER) && (sizeof(S) <= sizeof(unsigned int))
+ };
+ };
+
+ /// Shared memory storage layout type
+ struct TempStorage {};
+
+
+ //---------------------------------------------------------------------
+ // Thread fields
+ //---------------------------------------------------------------------
+
+ /// Lane index in logical warp
+ unsigned int lane_id;
+
+ /// Logical warp index in 32-thread physical warp
+ unsigned int warp_id;
+
+ /// 32-thread physical warp member mask of logical warp
+ unsigned int member_mask;
+
+ //---------------------------------------------------------------------
+ // Construction
+ //---------------------------------------------------------------------
+
+ /// Constructor
+ __device__ __forceinline__ WarpScanShfl(
+ TempStorage &/*temp_storage*/)
+ {
+ lane_id = LaneId();
+ warp_id = 0;
+ member_mask = 0xffffffffu >> (CUB_WARP_THREADS(PTX_ARCH) - LOGICAL_WARP_THREADS);
+
+ if (!IS_ARCH_WARP)
+ {
+ warp_id = lane_id / LOGICAL_WARP_THREADS;
+ lane_id = lane_id % LOGICAL_WARP_THREADS;
+ member_mask = member_mask << (warp_id * LOGICAL_WARP_THREADS);
+ }
+ }
+
+
+ //---------------------------------------------------------------------
+ // Inclusive scan steps
+ //---------------------------------------------------------------------
+
+ /// Inclusive prefix scan step (specialized for summation across int32 types)
+ __device__ __forceinline__ int InclusiveScanStep(
+ int input, ///< [in] Calling thread's input item.
+ cub::Sum /*scan_op*/, ///< [in] Binary scan operator
+ int first_lane, ///< [in] Index of first lane in segment
+ int offset) ///< [in] Up-offset to pull from
+ {
+ int output;
+ int shfl_c = first_lane | SHFL_C; // Shuffle control (mask and first-lane)
+
+ // Use predicate set from SHFL to guard against invalid peers
+#ifdef CUB_USE_COOPERATIVE_GROUPS
+ asm volatile(
+ "{"
+ " .reg .s32 r0;"
+ " .reg .pred p;"
+ " shfl.sync.up.b32 r0|p, %1, %2, %3, %5;"
+ " @p add.s32 r0, r0, %4;"
+ " mov.s32 %0, r0;"
+ "}"
+ : "=r"(output) : "r"(input), "r"(offset), "r"(shfl_c), "r"(input), "r"(member_mask));
+#else
+ asm volatile(
+ "{"
+ " .reg .s32 r0;"
+ " .reg .pred p;"
+ " shfl.up.b32 r0|p, %1, %2, %3;"
+ " @p add.s32 r0, r0, %4;"
+ " mov.s32 %0, r0;"
+ "}"
+ : "=r"(output) : "r"(input), "r"(offset), "r"(shfl_c), "r"(input));
+#endif
+
+ return output;
+ }
+
+ /// Inclusive prefix scan step (specialized for summation across uint32 types)
+ __device__ __forceinline__ unsigned int InclusiveScanStep(
+ unsigned int input, ///< [in] Calling thread's input item.
+ cub::Sum /*scan_op*/, ///< [in] Binary scan operator
+ int first_lane, ///< [in] Index of first lane in segment
+ int offset) ///< [in] Up-offset to pull from
+ {
+ unsigned int output;
+ int shfl_c = first_lane | SHFL_C; // Shuffle control (mask and first-lane)
+
+ // Use predicate set from SHFL to guard against invalid peers
+#ifdef CUB_USE_COOPERATIVE_GROUPS
+ asm volatile(
+ "{"
+ " .reg .u32 r0;"
+ " .reg .pred p;"
+ " shfl.sync.up.b32 r0|p, %1, %2, %3, %5;"
+ " @p add.u32 r0, r0, %4;"
+ " mov.u32 %0, r0;"
+ "}"
+ : "=r"(output) : "r"(input), "r"(offset), "r"(shfl_c), "r"(input), "r"(member_mask));
+#else
+ asm volatile(
+ "{"
+ " .reg .u32 r0;"
+ " .reg .pred p;"
+ " shfl.up.b32 r0|p, %1, %2, %3;"
+ " @p add.u32 r0, r0, %4;"
+ " mov.u32 %0, r0;"
+ "}"
+ : "=r"(output) : "r"(input), "r"(offset), "r"(shfl_c), "r"(input));
+#endif
+
+ return output;
+ }
+
+
+ /// Inclusive prefix scan step (specialized for summation across fp32 types)
+ __device__ __forceinline__ float InclusiveScanStep(
+ float input, ///< [in] Calling thread's input item.
+ cub::Sum /*scan_op*/, ///< [in] Binary scan operator
+ int first_lane, ///< [in] Index of first lane in segment
+ int offset) ///< [in] Up-offset to pull from
+ {
+ float output;
+ int shfl_c = first_lane | SHFL_C; // Shuffle control (mask and first-lane)
+
+ // Use predicate set from SHFL to guard against invalid peers
+#ifdef CUB_USE_COOPERATIVE_GROUPS
+ asm volatile(
+ "{"
+ " .reg .f32 r0;"
+ " .reg .pred p;"
+ " shfl.sync.up.b32 r0|p, %1, %2, %3, %5;"
+ " @p add.f32 r0, r0, %4;"
+ " mov.f32 %0, r0;"
+ "}"
+ : "=f"(output) : "f"(input), "r"(offset), "r"(shfl_c), "f"(input), "r"(member_mask));
+#else
+ asm volatile(
+ "{"
+ " .reg .f32 r0;"
+ " .reg .pred p;"
+ " shfl.up.b32 r0|p, %1, %2, %3;"
+ " @p add.f32 r0, r0, %4;"
+ " mov.f32 %0, r0;"
+ "}"
+ : "=f"(output) : "f"(input), "r"(offset), "r"(shfl_c), "f"(input));
+#endif
+
+ return output;
+ }
+
+
+ /// Inclusive prefix scan step (specialized for summation across unsigned long long types)
+ __device__ __forceinline__ unsigned long long InclusiveScanStep(
+ unsigned long long input, ///< [in] Calling thread's input item.
+ cub::Sum /*scan_op*/, ///< [in] Binary scan operator
+ int first_lane, ///< [in] Index of first lane in segment
+ int offset) ///< [in] Up-offset to pull from
+ {
+ unsigned long long output;
+ int shfl_c = first_lane | SHFL_C; // Shuffle control (mask and first-lane)
+
+ // Use predicate set from SHFL to guard against invalid peers
+#ifdef CUB_USE_COOPERATIVE_GROUPS
+ asm volatile(
+ "{"
+ " .reg .u64 r0;"
+ " .reg .u32 lo;"
+ " .reg .u32 hi;"
+ " .reg .pred p;"
+ " mov.b64 {lo, hi}, %1;"
+ " shfl.sync.up.b32 lo|p, lo, %2, %3, %5;"
+ " shfl.sync.up.b32 hi|p, hi, %2, %3, %5;"
+ " mov.b64 r0, {lo, hi};"
+ " @p add.u64 r0, r0, %4;"
+ " mov.u64 %0, r0;"
+ "}"
+ : "=l"(output) : "l"(input), "r"(offset), "r"(shfl_c), "l"(input), "r"(member_mask));
+#else
+ asm volatile(
+ "{"
+ " .reg .u64 r0;"
+ " .reg .u32 lo;"
+ " .reg .u32 hi;"
+ " .reg .pred p;"
+ " mov.b64 {lo, hi}, %1;"
+ " shfl.up.b32 lo|p, lo, %2, %3;"
+ " shfl.up.b32 hi|p, hi, %2, %3;"
+ " mov.b64 r0, {lo, hi};"
+ " @p add.u64 r0, r0, %4;"
+ " mov.u64 %0, r0;"
+ "}"
+ : "=l"(output) : "l"(input), "r"(offset), "r"(shfl_c), "l"(input));
+#endif
+
+ return output;
+ }
+
+
+ /// Inclusive prefix scan step (specialized for summation across long long types)
+ __device__ __forceinline__ long long InclusiveScanStep(
+ long long input, ///< [in] Calling thread's input item.
+ cub::Sum /*scan_op*/, ///< [in] Binary scan operator
+ int first_lane, ///< [in] Index of first lane in segment
+ int offset) ///< [in] Up-offset to pull from
+ {
+ long long output;
+ int shfl_c = first_lane | SHFL_C; // Shuffle control (mask and first-lane)
+
+ // Use predicate set from SHFL to guard against invalid peers
+#ifdef CUB_USE_COOPERATIVE_GROUPS
+ asm volatile(
+ "{"
+ " .reg .s64 r0;"
+ " .reg .u32 lo;"
+ " .reg .u32 hi;"
+ " .reg .pred p;"
+ " mov.b64 {lo, hi}, %1;"
+ " shfl.sync.up.b32 lo|p, lo, %2, %3, %5;"
+ " shfl.sync.up.b32 hi|p, hi, %2, %3, %5;"
+ " mov.b64 r0, {lo, hi};"
+ " @p add.s64 r0, r0, %4;"
+ " mov.s64 %0, r0;"
+ "}"
+ : "=l"(output) : "l"(input), "r"(offset), "r"(shfl_c), "l"(input), "r"(member_mask));
+#else
+ asm volatile(
+ "{"
+ " .reg .s64 r0;"
+ " .reg .u32 lo;"
+ " .reg .u32 hi;"
+ " .reg .pred p;"
+ " mov.b64 {lo, hi}, %1;"
+ " shfl.up.b32 lo|p, lo, %2, %3;"
+ " shfl.up.b32 hi|p, hi, %2, %3;"
+ " mov.b64 r0, {lo, hi};"
+ " @p add.s64 r0, r0, %4;"
+ " mov.s64 %0, r0;"
+ "}"
+ : "=l"(output) : "l"(input), "r"(offset), "r"(shfl_c), "l"(input));
+#endif
+
+ return output;
+ }
+
+
+ /// Inclusive prefix scan step (specialized for summation across fp64 types)
+ __device__ __forceinline__ double InclusiveScanStep(
+ double input, ///< [in] Calling thread's input item.
+ cub::Sum /*scan_op*/, ///< [in] Binary scan operator
+ int first_lane, ///< [in] Index of first lane in segment
+ int offset) ///< [in] Up-offset to pull from
+ {
+ double output;
+ int shfl_c = first_lane | SHFL_C; // Shuffle control (mask and first-lane)
+
+ // Use predicate set from SHFL to guard against invalid peers
+#ifdef CUB_USE_COOPERATIVE_GROUPS
+ asm volatile(
+ "{"
+ " .reg .u32 lo;"
+ " .reg .u32 hi;"
+ " .reg .pred p;"
+ " .reg .f64 r0;"
+ " mov.b64 %0, %1;"
+ " mov.b64 {lo, hi}, %1;"
+ " shfl.sync.up.b32 lo|p, lo, %2, %3, %4;"
+ " shfl.sync.up.b32 hi|p, hi, %2, %3, %4;"
+ " mov.b64 r0, {lo, hi};"
+ " @p add.f64 %0, %0, r0;"
+ "}"
+ : "=d"(output) : "d"(input), "r"(offset), "r"(shfl_c), "r"(member_mask));
+#else
+ asm volatile(
+ "{"
+ " .reg .u32 lo;"
+ " .reg .u32 hi;"
+ " .reg .pred p;"
+ " .reg .f64 r0;"
+ " mov.b64 %0, %1;"
+ " mov.b64 {lo, hi}, %1;"
+ " shfl.up.b32 lo|p, lo, %2, %3;"
+ " shfl.up.b32 hi|p, hi, %2, %3;"
+ " mov.b64 r0, {lo, hi};"
+ " @p add.f64 %0, %0, r0;"
+ "}"
+ : "=d"(output) : "d"(input), "r"(offset), "r"(shfl_c));
+#endif
+
+ return output;
+ }
+
+
+/*
+ /// Inclusive prefix scan (specialized for ReduceBySegmentOp<cub::Sum> across KeyValuePair<OffsetT, Value> types)
+ template <typename Value, typename OffsetT>
+ __device__ __forceinline__ KeyValuePair<OffsetT, Value>InclusiveScanStep(
+ KeyValuePair<OffsetT, Value> input, ///< [in] Calling thread's input item.
+ ReduceBySegmentOp<cub::Sum> scan_op, ///< [in] Binary scan operator
+ int first_lane, ///< [in] Index of first lane in segment
+ int offset) ///< [in] Up-offset to pull from
+ {
+ KeyValuePair<OffsetT, Value> output;
+
+ output.value = InclusiveScanStep(input.value, cub::Sum(), first_lane, offset, Int2Type<IntegerTraits<Value>::IS_SMALL_UNSIGNED>());
+ output.key = InclusiveScanStep(input.key, cub::Sum(), first_lane, offset, Int2Type<IntegerTraits<OffsetT>::IS_SMALL_UNSIGNED>());
+
+ if (input.key > 0)
+ output.value = input.value;
+
+ return output;
+ }
+*/
+
+ /// Inclusive prefix scan step (generic)
+ template <typename _T, typename ScanOpT>
+ __device__ __forceinline__ _T InclusiveScanStep(
+ _T input, ///< [in] Calling thread's input item.
+ ScanOpT scan_op, ///< [in] Binary scan operator
+ int first_lane, ///< [in] Index of first lane in segment
+ int offset) ///< [in] Up-offset to pull from
+ {
+ _T temp = ShuffleUp<LOGICAL_WARP_THREADS>(input, offset, first_lane, member_mask);
+
+ // Perform scan op if from a valid peer
+ _T output = scan_op(temp, input);
+ if (static_cast<int>(lane_id) < first_lane + offset)
+ output = input;
+
+ return output;
+ }
+
+
+ /// Inclusive prefix scan step (specialized for small integers size 32b or less)
+ template <typename _T, typename ScanOpT>
+ __device__ __forceinline__ _T InclusiveScanStep(
+ _T input, ///< [in] Calling thread's input item.
+ ScanOpT scan_op, ///< [in] Binary scan operator
+ int first_lane, ///< [in] Index of first lane in segment
+ int offset, ///< [in] Up-offset to pull from
+ Int2Type<true> /*is_small_unsigned*/) ///< [in] Marker type indicating whether T is a small integer
+ {
+ return InclusiveScanStep(input, scan_op, first_lane, offset);
+ }
+
+
+ /// Inclusive prefix scan step (specialized for types other than small integers size 32b or less)
+ template <typename _T, typename ScanOpT>
+ __device__ __forceinline__ _T InclusiveScanStep(
+ _T input, ///< [in] Calling thread's input item.
+ ScanOpT scan_op, ///< [in] Binary scan operator
+ int first_lane, ///< [in] Index of first lane in segment
+ int offset, ///< [in] Up-offset to pull from
+ Int2Type<false> /*is_small_unsigned*/) ///< [in] Marker type indicating whether T is a small integer
+ {
+ return InclusiveScanStep(input, scan_op, first_lane, offset);
+ }
+
+
+ /******************************************************************************
+ * Interface
+ ******************************************************************************/
+
+ //---------------------------------------------------------------------
+ // Broadcast
+ //---------------------------------------------------------------------
+
+ /// Broadcast
+ __device__ __forceinline__ T Broadcast(
+ T input, ///< [in] The value to broadcast
+ int src_lane) ///< [in] Which warp lane is to do the broadcasting
+ {
+ return ShuffleIndex<LOGICAL_WARP_THREADS>(input, src_lane, member_mask);
+ }
+
+
+ //---------------------------------------------------------------------
+ // Inclusive operations
+ //---------------------------------------------------------------------
+
+ /// Inclusive scan
+ template <typename _T, typename ScanOpT>
+ __device__ __forceinline__ void InclusiveScan(
+ _T input, ///< [in] Calling thread's input item.
+ _T &inclusive_output, ///< [out] Calling thread's output item. May be aliased with \p input.
+ ScanOpT scan_op) ///< [in] Binary scan operator
+ {
+ inclusive_output = input;
+
+ // Iterate scan steps
+ int segment_first_lane = 0;
+
+ // Iterate scan steps
+ #pragma unroll
+ for (int STEP = 0; STEP < STEPS; STEP++)
+ {
+ inclusive_output = InclusiveScanStep(
+ inclusive_output,
+ scan_op,
+ segment_first_lane,
+ (1 << STEP),
+ Int2Type<IntegerTraits<T>::IS_SMALL_UNSIGNED>());
+ }
+
+ }
+
+ /// Inclusive scan, specialized for reduce-value-by-key
+ template <typename KeyT, typename ValueT, typename ReductionOpT>
+ __device__ __forceinline__ void InclusiveScan(
+ KeyValuePair<KeyT, ValueT> input, ///< [in] Calling thread's input item.
+ KeyValuePair<KeyT, ValueT> &inclusive_output, ///< [out] Calling thread's output item. May be aliased with \p input.
+ ReduceByKeyOp<ReductionOpT > scan_op) ///< [in] Binary scan operator
+ {
+ inclusive_output = input;
+
+ KeyT pred_key = ShuffleUp<LOGICAL_WARP_THREADS>(inclusive_output.key, 1, 0, member_mask);
+
+ unsigned int ballot = WARP_BALLOT((pred_key != inclusive_output.key), member_mask);
+
+ // Mask away all lanes greater than ours
+ ballot = ballot & LaneMaskLe();
+
+ // Find index of first set bit
+ int segment_first_lane = CUB_MAX(0, 31 - __clz(ballot));
+
+ // Iterate scan steps
+ #pragma unroll
+ for (int STEP = 0; STEP < STEPS; STEP++)
+ {
+ inclusive_output.value = InclusiveScanStep(
+ inclusive_output.value,
+ scan_op.op,
+ segment_first_lane,
+ (1 << STEP),
+ Int2Type<IntegerTraits<T>::IS_SMALL_UNSIGNED>());
+ }
+ }
+
+
+ /// Inclusive scan with aggregate
+ template <typename ScanOpT>
+ __device__ __forceinline__ void InclusiveScan(
+ T input, ///< [in] Calling thread's input item.
+ T &inclusive_output, ///< [out] Calling thread's output item. May be aliased with \p input.
+ ScanOpT scan_op, ///< [in] Binary scan operator
+ T &warp_aggregate) ///< [out] Warp-wide aggregate reduction of input items.
+ {
+ InclusiveScan(input, inclusive_output, scan_op);
+
+ // Grab aggregate from last warp lane
+ warp_aggregate = ShuffleIndex<LOGICAL_WARP_THREADS>(inclusive_output, LOGICAL_WARP_THREADS - 1, member_mask);
+ }
+
+
+ //---------------------------------------------------------------------
+ // Get exclusive from inclusive
+ //---------------------------------------------------------------------
+
+ /// Update inclusive and exclusive using input and inclusive
+ template <typename ScanOpT, typename IsIntegerT>
+ __device__ __forceinline__ void Update(
+ T /*input*/, ///< [in]
+ T &inclusive, ///< [in, out]
+ T &exclusive, ///< [out]
+ ScanOpT /*scan_op*/, ///< [in]
+ IsIntegerT /*is_integer*/) ///< [in]
+ {
+ // initial value unknown
+ exclusive = ShuffleUp<LOGICAL_WARP_THREADS>(inclusive, 1, 0, member_mask);
+ }
+
+ /// Update inclusive and exclusive using input and inclusive (specialized for summation of integer types)
+ __device__ __forceinline__ void Update(
+ T input,
+ T &inclusive,
+ T &exclusive,
+ cub::Sum /*scan_op*/,
+ Int2Type<true> /*is_integer*/)
+ {
+ // initial value presumed 0
+ exclusive = inclusive - input;
+ }
+
+ /// Update inclusive and exclusive using initial value using input, inclusive, and initial value
+ template <typename ScanOpT, typename IsIntegerT>
+ __device__ __forceinline__ void Update (
+ T /*input*/,
+ T &inclusive,
+ T &exclusive,
+ ScanOpT scan_op,
+ T initial_value,
+ IsIntegerT /*is_integer*/)
+ {
+ inclusive = scan_op(initial_value, inclusive);
+ exclusive = ShuffleUp<LOGICAL_WARP_THREADS>(inclusive, 1, 0, member_mask);
+
+ if (lane_id == 0)
+ exclusive = initial_value;
+ }
+
+ /// Update inclusive and exclusive using initial value using input and inclusive (specialized for summation of integer types)
+ __device__ __forceinline__ void Update (
+ T input,
+ T &inclusive,
+ T &exclusive,
+ cub::Sum scan_op,
+ T initial_value,
+ Int2Type<true> /*is_integer*/)
+ {
+ inclusive = scan_op(initial_value, inclusive);
+ exclusive = inclusive - input;
+ }
+
+
+ /// Update inclusive, exclusive, and warp aggregate using input and inclusive
+ template <typename ScanOpT, typename IsIntegerT>
+ __device__ __forceinline__ void Update (
+ T input,
+ T &inclusive,
+ T &exclusive,
+ T &warp_aggregate,
+ ScanOpT scan_op,
+ IsIntegerT is_integer)
+ {
+ warp_aggregate = ShuffleIndex<LOGICAL_WARP_THREADS>(inclusive, LOGICAL_WARP_THREADS - 1, member_mask);
+ Update(input, inclusive, exclusive, scan_op, is_integer);
+ }
+
+ /// Update inclusive, exclusive, and warp aggregate using input, inclusive, and initial value
+ template <typename ScanOpT, typename IsIntegerT>
+ __device__ __forceinline__ void Update (
+ T input,
+ T &inclusive,
+ T &exclusive,
+ T &warp_aggregate,
+ ScanOpT scan_op,
+ T initial_value,
+ IsIntegerT is_integer)
+ {
+ warp_aggregate = ShuffleIndex<LOGICAL_WARP_THREADS>(inclusive, LOGICAL_WARP_THREADS - 1, member_mask);
+ Update(input, inclusive, exclusive, scan_op, initial_value, is_integer);
+ }
+
+
+
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/warp/specializations/warp_scan_smem.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/warp/specializations/warp_scan_smem.cuh
new file mode 100644
index 0000000..3237fcb
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/warp/specializations/warp_scan_smem.cuh
@@ -0,0 +1,397 @@
+/******************************************************************************
+ * 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::WarpScanSmem provides smem-based variants of parallel prefix scan of items partitioned across a CUDA thread warp.
+ */
+
+#pragma once
+
+#include "../../thread/thread_operators.cuh"
+#include "../../thread/thread_load.cuh"
+#include "../../thread/thread_store.cuh"
+#include "../../util_type.cuh"
+#include "../../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+/**
+ * \brief WarpScanSmem provides smem-based variants of parallel prefix scan of items partitioned across a CUDA thread warp.
+ */
+template <
+ typename T, ///< Data type being scanned
+ int LOGICAL_WARP_THREADS, ///< Number of threads per logical warp
+ int PTX_ARCH> ///< The PTX compute capability for which to to specialize this collective
+struct WarpScanSmem
+{
+ /******************************************************************************
+ * Constants and type definitions
+ ******************************************************************************/
+
+ enum
+ {
+ /// Whether the logical warp size and the PTX warp size coincide
+ IS_ARCH_WARP = (LOGICAL_WARP_THREADS == CUB_WARP_THREADS(PTX_ARCH)),
+
+ /// Whether the logical warp size is a power-of-two
+ IS_POW_OF_TWO = PowerOfTwo<LOGICAL_WARP_THREADS>::VALUE,
+
+ /// The number of warp scan steps
+ STEPS = Log2<LOGICAL_WARP_THREADS>::VALUE,
+
+ /// The number of threads in half a warp
+ HALF_WARP_THREADS = 1 << (STEPS - 1),
+
+ /// The number of shared memory elements per warp
+ WARP_SMEM_ELEMENTS = LOGICAL_WARP_THREADS + HALF_WARP_THREADS,
+ };
+
+ /// Storage cell type (workaround for SM1x compiler bugs with custom-ops like Max() on signed chars)
+ typedef typename If<((Equals<T, char>::VALUE || Equals<T, signed char>::VALUE) && (PTX_ARCH < 200)), int, T>::Type CellT;
+
+ /// Shared memory storage layout type (1.5 warps-worth of elements for each warp)
+ typedef CellT _TempStorage[WARP_SMEM_ELEMENTS];
+
+ // Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ /******************************************************************************
+ * Thread fields
+ ******************************************************************************/
+
+ _TempStorage &temp_storage;
+ unsigned int lane_id;
+ unsigned int member_mask;
+
+
+ /******************************************************************************
+ * Construction
+ ******************************************************************************/
+
+ /// Constructor
+ __device__ __forceinline__ WarpScanSmem(
+ TempStorage &temp_storage)
+ :
+ temp_storage(temp_storage.Alias()),
+
+ lane_id(IS_ARCH_WARP ?
+ LaneId() :
+ LaneId() % LOGICAL_WARP_THREADS),
+
+ member_mask((0xffffffff >> (32 - LOGICAL_WARP_THREADS)) << ((IS_ARCH_WARP || !IS_POW_OF_TWO ) ?
+ 0 : // arch-width and non-power-of-two subwarps cannot be tiled with the arch-warp
+ ((LaneId() / LOGICAL_WARP_THREADS) * LOGICAL_WARP_THREADS)))
+ {}
+
+
+ /******************************************************************************
+ * Utility methods
+ ******************************************************************************/
+
+ /// Basic inclusive scan iteration (template unrolled, inductive-case specialization)
+ template <
+ bool HAS_IDENTITY,
+ int STEP,
+ typename ScanOp>
+ __device__ __forceinline__ void ScanStep(
+ T &partial,
+ ScanOp scan_op,
+ Int2Type<STEP> /*step*/)
+ {
+ const int OFFSET = 1 << STEP;
+
+ // Share partial into buffer
+ ThreadStore<STORE_VOLATILE>(&temp_storage[HALF_WARP_THREADS + lane_id], (CellT) partial);
+
+ WARP_SYNC(member_mask);
+
+ // Update partial if addend is in range
+ if (HAS_IDENTITY || (lane_id >= OFFSET))
+ {
+ T addend = (T) ThreadLoad<LOAD_VOLATILE>(&temp_storage[HALF_WARP_THREADS + lane_id - OFFSET]);
+ partial = scan_op(addend, partial);
+ }
+ WARP_SYNC(member_mask);
+
+ ScanStep<HAS_IDENTITY>(partial, scan_op, Int2Type<STEP + 1>());
+ }
+
+
+ /// Basic inclusive scan iteration(template unrolled, base-case specialization)
+ template <
+ bool HAS_IDENTITY,
+ typename ScanOp>
+ __device__ __forceinline__ void ScanStep(
+ T &/*partial*/,
+ ScanOp /*scan_op*/,
+ Int2Type<STEPS> /*step*/)
+ {}
+
+
+ /// Inclusive prefix scan (specialized for summation across primitive types)
+ __device__ __forceinline__ void InclusiveScan(
+ T input, ///< [in] Calling thread's input item.
+ T &output, ///< [out] Calling thread's output item. May be aliased with \p input.
+ Sum scan_op, ///< [in] Binary scan operator
+ Int2Type<true> /*is_primitive*/) ///< [in] Marker type indicating whether T is primitive type
+ {
+ T identity = 0;
+ ThreadStore<STORE_VOLATILE>(&temp_storage[lane_id], (CellT) identity);
+
+ WARP_SYNC(member_mask);
+
+ // Iterate scan steps
+ output = input;
+ ScanStep<true>(output, scan_op, Int2Type<0>());
+ }
+
+
+ /// Inclusive prefix scan
+ template <typename ScanOp, int IS_PRIMITIVE>
+ __device__ __forceinline__ void InclusiveScan(
+ T input, ///< [in] Calling thread's input item.
+ T &output, ///< [out] Calling thread's output item. May be aliased with \p input.
+ ScanOp scan_op, ///< [in] Binary scan operator
+ Int2Type<IS_PRIMITIVE> /*is_primitive*/) ///< [in] Marker type indicating whether T is primitive type
+ {
+ // Iterate scan steps
+ output = input;
+ ScanStep<false>(output, scan_op, Int2Type<0>());
+ }
+
+
+ /******************************************************************************
+ * Interface
+ ******************************************************************************/
+
+ //---------------------------------------------------------------------
+ // Broadcast
+ //---------------------------------------------------------------------
+
+ /// Broadcast
+ __device__ __forceinline__ T Broadcast(
+ T input, ///< [in] The value to broadcast
+ unsigned int src_lane) ///< [in] Which warp lane is to do the broadcasting
+ {
+ if (lane_id == src_lane)
+ {
+ ThreadStore<STORE_VOLATILE>(temp_storage, (CellT) input);
+ }
+
+ WARP_SYNC(member_mask);
+
+ return (T)ThreadLoad<LOAD_VOLATILE>(temp_storage);
+ }
+
+
+ //---------------------------------------------------------------------
+ // Inclusive operations
+ //---------------------------------------------------------------------
+
+ /// Inclusive scan
+ 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 with \p input.
+ ScanOp scan_op) ///< [in] Binary scan operator
+ {
+ InclusiveScan(input, inclusive_output, scan_op, Int2Type<Traits<T>::PRIMITIVE>());
+ }
+
+
+ /// Inclusive scan with aggregate
+ 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 with \p input.
+ ScanOp scan_op, ///< [in] Binary scan operator
+ T &warp_aggregate) ///< [out] Warp-wide aggregate reduction of input items.
+ {
+ InclusiveScan(input, inclusive_output, scan_op);
+
+ // Retrieve aggregate
+ ThreadStore<STORE_VOLATILE>(&temp_storage[HALF_WARP_THREADS + lane_id], (CellT) inclusive_output);
+
+ WARP_SYNC(member_mask);
+
+ warp_aggregate = (T) ThreadLoad<LOAD_VOLATILE>(&temp_storage[WARP_SMEM_ELEMENTS - 1]);
+
+ WARP_SYNC(member_mask);
+ }
+
+
+ //---------------------------------------------------------------------
+ // Get exclusive from inclusive
+ //---------------------------------------------------------------------
+
+ /// Update inclusive and exclusive using input and inclusive
+ template <typename ScanOpT, typename IsIntegerT>
+ __device__ __forceinline__ void Update(
+ T /*input*/, ///< [in]
+ T &inclusive, ///< [in, out]
+ T &exclusive, ///< [out]
+ ScanOpT /*scan_op*/, ///< [in]
+ IsIntegerT /*is_integer*/) ///< [in]
+ {
+ // initial value unknown
+ ThreadStore<STORE_VOLATILE>(&temp_storage[HALF_WARP_THREADS + lane_id], (CellT) inclusive);
+
+ WARP_SYNC(member_mask);
+
+ exclusive = (T) ThreadLoad<LOAD_VOLATILE>(&temp_storage[HALF_WARP_THREADS + lane_id - 1]);
+ }
+
+ /// Update inclusive and exclusive using input and inclusive (specialized for summation of integer types)
+ __device__ __forceinline__ void Update(
+ T input,
+ T &inclusive,
+ T &exclusive,
+ cub::Sum /*scan_op*/,
+ Int2Type<true> /*is_integer*/)
+ {
+ // initial value presumed 0
+ exclusive = inclusive - input;
+ }
+
+ /// Update inclusive and exclusive using initial value using input, inclusive, and initial value
+ template <typename ScanOpT, typename IsIntegerT>
+ __device__ __forceinline__ void Update (
+ T /*input*/,
+ T &inclusive,
+ T &exclusive,
+ ScanOpT scan_op,
+ T initial_value,
+ IsIntegerT /*is_integer*/)
+ {
+ inclusive = scan_op(initial_value, inclusive);
+ ThreadStore<STORE_VOLATILE>(&temp_storage[HALF_WARP_THREADS + lane_id], (CellT) inclusive);
+
+ WARP_SYNC(member_mask);
+
+ exclusive = (T) ThreadLoad<LOAD_VOLATILE>(&temp_storage[HALF_WARP_THREADS + lane_id - 1]);
+ if (lane_id == 0)
+ exclusive = initial_value;
+ }
+
+ /// Update inclusive and exclusive using initial value using input and inclusive (specialized for summation of integer types)
+ __device__ __forceinline__ void Update (
+ T input,
+ T &inclusive,
+ T &exclusive,
+ cub::Sum scan_op,
+ T initial_value,
+ Int2Type<true> /*is_integer*/)
+ {
+ inclusive = scan_op(initial_value, inclusive);
+ exclusive = inclusive - input;
+ }
+
+
+ /// Update inclusive, exclusive, and warp aggregate using input and inclusive
+ template <typename ScanOpT, typename IsIntegerT>
+ __device__ __forceinline__ void Update (
+ T /*input*/,
+ T &inclusive,
+ T &exclusive,
+ T &warp_aggregate,
+ ScanOpT /*scan_op*/,
+ IsIntegerT /*is_integer*/)
+ {
+ // Initial value presumed to be unknown or identity (either way our padding is correct)
+ ThreadStore<STORE_VOLATILE>(&temp_storage[HALF_WARP_THREADS + lane_id], (CellT) inclusive);
+
+ WARP_SYNC(member_mask);
+
+ exclusive = (T) ThreadLoad<LOAD_VOLATILE>(&temp_storage[HALF_WARP_THREADS + lane_id - 1]);
+ warp_aggregate = (T) ThreadLoad<LOAD_VOLATILE>(&temp_storage[WARP_SMEM_ELEMENTS - 1]);
+ }
+
+ /// Update inclusive, exclusive, and warp aggregate using input and inclusive (specialized for summation of integer types)
+ __device__ __forceinline__ void Update (
+ T input,
+ T &inclusive,
+ T &exclusive,
+ T &warp_aggregate,
+ cub::Sum /*scan_o*/,
+ Int2Type<true> /*is_integer*/)
+ {
+ // Initial value presumed to be unknown or identity (either way our padding is correct)
+ ThreadStore<STORE_VOLATILE>(&temp_storage[HALF_WARP_THREADS + lane_id], (CellT) inclusive);
+
+ WARP_SYNC(member_mask);
+
+ warp_aggregate = (T) ThreadLoad<LOAD_VOLATILE>(&temp_storage[WARP_SMEM_ELEMENTS - 1]);
+ exclusive = inclusive - input;
+ }
+
+ /// Update inclusive, exclusive, and warp aggregate using input, inclusive, and initial value
+ template <typename ScanOpT, typename IsIntegerT>
+ __device__ __forceinline__ void Update (
+ T /*input*/,
+ T &inclusive,
+ T &exclusive,
+ T &warp_aggregate,
+ ScanOpT scan_op,
+ T initial_value,
+ IsIntegerT /*is_integer*/)
+ {
+ // Broadcast warp aggregate
+ ThreadStore<STORE_VOLATILE>(&temp_storage[HALF_WARP_THREADS + lane_id], (CellT) inclusive);
+
+ WARP_SYNC(member_mask);
+
+ warp_aggregate = (T) ThreadLoad<LOAD_VOLATILE>(&temp_storage[WARP_SMEM_ELEMENTS - 1]);
+
+ WARP_SYNC(member_mask);
+
+ // Update inclusive with initial value
+ inclusive = scan_op(initial_value, inclusive);
+
+ // Get exclusive from exclusive
+ ThreadStore<STORE_VOLATILE>(&temp_storage[HALF_WARP_THREADS + lane_id - 1], (CellT) inclusive);
+
+ WARP_SYNC(member_mask);
+
+ exclusive = (T) ThreadLoad<LOAD_VOLATILE>(&temp_storage[HALF_WARP_THREADS + lane_id - 2]);
+
+ if (lane_id == 0)
+ exclusive = initial_value;
+ }
+
+
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)