Files
project_6/cccl_upstream/cub/cub/block/block_adjacent_difference.cuh
EngineX CI 56fd68e7dd [INFRA] Import NVIDIA/CCCL upstream as optimization reference library
CCCL (CUDA C++ Core Libraries) provides:
- CUB: device/block/warp-level GPU primitives (reduce, scan, sort, topk)
- Thrust: high-level parallel algorithms (transform_reduce, sort, scan)
- libcudacxx: CUDA C++ standard library (atomics, barriers, memory)
- cudax: experimental features (memory resources, allocators)
- Tuning policies: per-SM hardware-specific algorithm parameters

Competition optimization vectors mapped to CCCL:
- Output TPS (83% weight): warp_reduce, block_reduce, device_topk
- Input TPS (14% weight): device_scan, block_load, prefetch
- Cache TPS (3% weight): prefix caching strategy patterns
- Memory (0.9 util): pooled/cached/buddy allocators

Source: https://github.com/NVIDIA/cccl (shallow clone, HEAD only)
License: Apache-2.0
2026-07-30 09:35:51 +00:00

972 lines
31 KiB
Plaintext

// SPDX-FileCopyrightText: Copyright (c) 2011, Duane Merrill. All rights reserved.
// SPDX-FileCopyrightText: Copyright (c) 2011-2021, NVIDIA CORPORATION. All rights reserved.
// SPDX-License-Identifier: BSD-3
//! @file
//! The cub::BlockAdjacentDifference class provides collective methods for computing the differences of adjacent
//! elements partitioned across a CUDA thread block.
#pragma once
#include <cub/config.cuh>
#if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC)
# pragma GCC system_header
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG)
# pragma clang system_header
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC)
# pragma system_header
#endif // no system header
#include <cub/util_ptx.cuh>
#include <cub/util_type.cuh>
CUB_NAMESPACE_BEGIN
//! @rst
//! BlockAdjacentDifference provides :ref:`collective <collective-primitives>` methods for computing the
//! differences of adjacent elements partitioned across a CUDA thread block.
//!
//! Overview
//! ++++++++++++++++
//!
//! BlockAdjacentDifference calculates the differences of adjacent elements in the elements partitioned across a CUDA
//! thread block. Because the binary operation could be noncommutative, there are two sets of methods.
//! Methods named SubtractLeft subtract left element ``i - 1`` of input sequence from current element ``i``.
//! Methods named SubtractRight subtract the right element ``i + 1`` from the current one ``i``:
//!
//! .. code-block:: c++
//!
//! int values[4]; // [1, 2, 3, 4]
//! //...
//! int subtract_left_result[4]; <-- [ 1, 1, 1, 1 ]
//! int subtract_right_result[4]; <-- [ -1, -1, -1, 4 ]
//!
//! - For SubtractLeft, if the left element is out of bounds, the input value is assigned to ``output[0]``
//! without modification.
//! - For SubtractRight, if the right element is out of bounds, the input value is assigned to the current output value
//! without modification.
//! - The block/example_block_reduce_dyn_smem.cu example under the examples/block folder illustrates usage of
//! dynamically shared memory with BlockReduce and how to re-purpose the same memory region.
//! This example can be easily adapted to the storage required by BlockAdjacentDifference.
//!
//! A Simple Example
//! ++++++++++++++++
//!
//! The code snippet below illustrates how to use BlockAdjacentDifference to
//! compute the left difference between adjacent elements.
//!
//! .. code-block:: c++
//!
//! #include <cub/cub.cuh>
//! // or equivalently <cub/block/block_adjacent_difference.cuh>
//!
//! struct CustomDifference
//! {
//! template <typename DataType>
//! __host__ DataType operator()(DataType &lhs, DataType &rhs)
//! {
//! return lhs - rhs;
//! }
//! };
//!
//! __global__ void ExampleKernel(...)
//! {
//! // Specialize BlockAdjacentDifference for a 1D block of
//! // 128 threads of type int
//! using BlockAdjacentDifferenceT =
//! cub::BlockAdjacentDifference<int, 128>;
//!
//! // Allocate shared memory for BlockAdjacentDifference
//! __shared__ typename BlockAdjacentDifferenceT::TempStorage temp_storage;
//!
//! // Obtain a segment of consecutive items that are blocked across threads
//! int thread_data[4];
//! ...
//!
//! // Collectively compute adjacent_difference
//! int result[4];
//!
//! BlockAdjacentDifferenceT(temp_storage).SubtractLeft(thread_data, result,
//! CustomDifference());
//! }
//!
//! Suppose the set of input `thread_data` across the block of threads is
//! ``{ [4,2,1,1], [1,1,1,1], [2,3,3,3], [3,4,1,4], ... }``.
//! The corresponding output ``result`` in those threads will be
//! ``{ [4,-2,-1,0], [0,0,0,0], [1,1,0,0], [0,1,-3,3], ... }``.
//!
//! @endrst
template <typename T, int BlockDimX, int BlockDimY = 1, int BlockDimZ = 1>
class BlockAdjacentDifference
{
private:
/// The thread block size in threads
static constexpr int BLOCK_THREADS = BlockDimX * BlockDimY * BlockDimZ;
/// Shared memory storage layout type (last element from each thread's input)
struct _TempStorage
{
T first_items[BLOCK_THREADS];
T last_items[BLOCK_THREADS];
};
/// Internal storage allocator
_CCCL_DEVICE _CCCL_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>::value>
struct ApplyOp
{
// Apply flag operator
static _CCCL_DEVICE _CCCL_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 _CCCL_DEVICE _CCCL_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)
struct Iterate
{
/**
* Head flags
*
* @param[out] flags Calling thread's discontinuity head_flags
* @param[in] input Calling thread's input items
* @param[out] preds Calling thread's predecessor items
* @param[in] flag_op Binary boolean flag predicate
*/
template <int ITEMS_PER_THREAD, typename FlagT, typename FlagOp>
static _CCCL_DEVICE _CCCL_FORCEINLINE void FlagHeads(
int linear_tid,
FlagT (&flags)[ITEMS_PER_THREAD],
T (&input)[ITEMS_PER_THREAD],
T (&preds)[ITEMS_PER_THREAD],
FlagOp flag_op)
{
_CCCL_PRAGMA_UNROLL_FULL()
for (int i = 1; i < ITEMS_PER_THREAD; ++i)
{
preds[i] = input[i - 1];
flags[i] = ApplyOp<FlagOp>::FlagT(flag_op, preds[i], input[i], (linear_tid * ITEMS_PER_THREAD) + i);
}
}
/**
* Tail flags
*
* @param[out] flags Calling thread's discontinuity head_flags
* @param[in] input Calling thread's input items
* @param[in] flag_op Binary boolean flag predicate
*/
template <int ITEMS_PER_THREAD, typename FlagT, typename FlagOp>
static _CCCL_DEVICE _CCCL_FORCEINLINE void
FlagTails(int linear_tid, FlagT (&flags)[ITEMS_PER_THREAD], T (&input)[ITEMS_PER_THREAD], FlagOp flag_op)
{
_CCCL_PRAGMA_UNROLL_FULL()
for (int i = 0; i < ITEMS_PER_THREAD - 1; ++i)
{
flags[i] = ApplyOp<FlagOp>::FlagT(flag_op, input[i], input[i + 1], (linear_tid * ITEMS_PER_THREAD) + i + 1);
}
}
};
/// Shared storage reference
_TempStorage& temp_storage;
/// Linear thread-id
unsigned int linear_tid;
public:
/// @smemstorage{BlockAdjacentDifference}
struct TempStorage : Uninitialized<_TempStorage>
{};
//! @name Collective constructors
//! @{
//! @brief Collective constructor using a private static allocation of shared memory as temporary storage
//!
//! @rst
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//! @endrst
_CCCL_DEVICE _CCCL_FORCEINLINE BlockAdjacentDifference()
: temp_storage(PrivateStorage())
, linear_tid(RowMajorTid(BlockDimX, BlockDimY, BlockDimZ))
{}
//! @brief Collective constructor using the specified memory allocation as temporary storage
//!
//! @rst
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//! @endrst
//!
//! @param[in] temp_storage Reference to memory allocation having layout type TempStorage
_CCCL_DEVICE _CCCL_FORCEINLINE BlockAdjacentDifference(TempStorage& temp_storage)
: temp_storage(temp_storage.Alias())
, linear_tid(RowMajorTid(BlockDimX, BlockDimY, BlockDimZ))
{}
//! @}
//! @name Read left operations
//! @{
//! @rst
//! Subtracts the left element of each adjacent pair of elements partitioned across a CUDA thread block.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! - @rowmajor
//! - @smemreuse
//!
//! Snippet
//! +++++++
//!
//! The code snippet below illustrates how to use BlockAdjacentDifference to compute the left difference between
//! adjacent elements.
//!
//! .. code-block:: c++
//!
//! #include <cub/cub.cuh>
//! // or equivalently <cub/block/block_adjacent_difference.cuh>
//!
//! struct CustomDifference
//! {
//! template <typename DataType>
//! __host__ DataType operator()(DataType &lhs, DataType &rhs)
//! {
//! return lhs - rhs;
//! }
//! };
//!
//! __global__ void ExampleKernel(...)
//! {
//! // Specialize BlockAdjacentDifference for a 1D block
//! // of 128 threads of type int
//! using BlockAdjacentDifferenceT =
//! cub::BlockAdjacentDifference<int, 128>;
//!
//! // Allocate shared memory for BlockAdjacentDifference
//! __shared__ typename BlockAdjacentDifferenceT::TempStorage temp_storage;
//!
//! // Obtain a segment of consecutive items that are blocked across threads
//! int thread_data[4];
//! ...
//!
//! // Collectively compute adjacent_difference
//! BlockAdjacentDifferenceT(temp_storage).SubtractLeft(thread_data, thread_data,
//! CustomDifference());
//! }
//!
//! Suppose the set of input ``thread_data`` across the block of threads is
//! ``{ [4,2,1,1], [1,1,1,1], [2,3,3,3], [3,4,1,4], ... }``.
//! The corresponding output ``result`` in those threads will be
//! ``{ [4,-2,-1,0], [0,0,0,0], [1,1,0,0], [0,1,-3,3], ... }``.
//! @endrst
//!
//! @param[out] output
//! Calling thread's adjacent difference result
//!
//! @param[in] input
//! Calling thread's input items (may be aliased to `output`)
//!
//! @param[in] difference_op
//! Binary difference operator
template <int ITEMS_PER_THREAD, typename OutputType, typename DifferenceOpT>
_CCCL_DEVICE _CCCL_FORCEINLINE void
SubtractLeft(T (&input)[ITEMS_PER_THREAD], OutputType (&output)[ITEMS_PER_THREAD], DifferenceOpT difference_op)
{
// Share last item
temp_storage.last_items[linear_tid] = input[ITEMS_PER_THREAD - 1];
__syncthreads();
_CCCL_PRAGMA_UNROLL_FULL()
for (int item = ITEMS_PER_THREAD - 1; item > 0; item--)
{
output[item] = difference_op(input[item], input[item - 1]);
}
if (linear_tid == 0)
{
output[0] = input[0];
}
else
{
output[0] = difference_op(input[0], temp_storage.last_items[linear_tid - 1]);
}
}
//! @rst
//! Subtracts the left element of each adjacent pair of elements partitioned across a CUDA thread block.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! - @rowmajor
//! - @smemreuse
//!
//! Snippet
//! +++++++
//!
//! The code snippet below illustrates how to use BlockAdjacentDifference to compute the left difference between
//! adjacent elements.
//!
//! .. code-block:: c++
//!
//! #include <cub/cub.cuh>
//! // or equivalently <cub/block/block_adjacent_difference.cuh>
//!
//! struct CustomDifference
//! {
//! template <typename DataType>
//! __host__ DataType operator()(DataType &lhs, DataType &rhs)
//! {
//! return lhs - rhs;
//! }
//! };
//!
//! __global__ void ExampleKernel(...)
//! {
//! // Specialize BlockAdjacentDifference for a 1D block of
//! // 128 threads of type int
//! using BlockAdjacentDifferenceT =
//! cub::BlockAdjacentDifference<int, 128>;
//!
//! // Allocate shared memory for BlockAdjacentDifference
//! __shared__ typename BlockAdjacentDifferenceT::TempStorage temp_storage;
//!
//! // Obtain a segment of consecutive items that are blocked across threads
//! int thread_data[4];
//! ...
//!
//! // The last item in the previous tile:
//! int tile_predecessor_item = ...;
//!
//! // Collectively compute adjacent_difference
//! BlockAdjacentDifferenceT(temp_storage).SubtractLeft(
//! thread_data,
//! thread_data,
//! CustomDifference(),
//! tile_predecessor_item);
//!
//! Suppose the set of input ``thread_data`` across the block of threads is
//! ``{ [4,2,1,1], [1,1,1,1], [2,3,3,3], [3,4,1,4], ... }``.
//! and that `tile_predecessor_item` is `3`. The corresponding output
//! ``result`` in those threads will be
//! ``{ [1,-2,-1,0], [0,0,0,0], [1,1,0,0], [0,1,-3,3], ... }``.
//! @endrst
//!
//! @param[out] output
//! Calling thread's adjacent difference result
//!
//! @param[in] input
//! Calling thread's input items (may be aliased to `output`)
//!
//! @param[in] difference_op
//! Binary difference operator
//!
//! @param[in] tile_predecessor_item
//! @rst
//! *thread*\ :sub:`0` only item which is going to be subtracted from the first tile item
//! (*input*\ :sub:`0` from *thread*\ :sub:`0`).
//! @endrst
template <int ITEMS_PER_THREAD, typename OutputT, typename DifferenceOpT>
_CCCL_DEVICE _CCCL_FORCEINLINE void SubtractLeft(
T (&input)[ITEMS_PER_THREAD],
OutputT (&output)[ITEMS_PER_THREAD],
DifferenceOpT difference_op,
T tile_predecessor_item)
{
// Share last item
temp_storage.last_items[linear_tid] = input[ITEMS_PER_THREAD - 1];
__syncthreads();
_CCCL_PRAGMA_UNROLL_FULL()
for (int item = ITEMS_PER_THREAD - 1; item > 0; item--)
{
output[item] = difference_op(input[item], input[item - 1]);
}
// Set flag for first thread-item
if (linear_tid == 0)
{
output[0] = difference_op(input[0], tile_predecessor_item);
}
else
{
output[0] = difference_op(input[0], temp_storage.last_items[linear_tid - 1]);
}
}
//! @rst
//! Subtracts the left element of each adjacent pair of elements partitioned across a CUDA thread block.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! - @rowmajor
//! - @smemreuse
//!
//! Snippet
//! +++++++
//!
//! The code snippet below illustrates how to use BlockAdjacentDifference to compute the left difference between
//! adjacent elements.
//!
//! .. code-block:: c++
//!
//! #include <cub/cub.cuh>
//! // or equivalently <cub/block/block_adjacent_difference.cuh>
//!
//! struct CustomDifference
//! {
//! template <typename DataType>
//! __host__ DataType operator()(DataType &lhs, DataType &rhs)
//! {
//! return lhs - rhs;
//! }
//! };
//!
//! __global__ void ExampleKernel(...)
//! {
//! // Specialize BlockAdjacentDifference for a 1D block of
//! // 128 threads of type int
//! using BlockAdjacentDifferenceT =
//! cub::BlockAdjacentDifference<int, 128>;
//!
//! // Allocate shared memory for BlockAdjacentDifference
//! __shared__ typename BlockAdjacentDifferenceT::TempStorage temp_storage;
//!
//! // Obtain a segment of consecutive items that are blocked across threads
//! int thread_data[4];
//! ...
//! int valid_items = 9;
//!
//! // Collectively compute adjacent_difference
//! BlockAdjacentDifferenceT(temp_storage).SubtractLeftPartialTile(
//! thread_data,
//! thread_data,
//! CustomDifference(),
//! valid_items);
//!
//! Suppose the set of input ``thread_data`` across the block of threads is
//! ``{ [4,2,1,1], [1,1,1,1], [2,3,3,3], [3,4,1,4], ... }``.
//! The corresponding output ``result`` in those threads will be
//! ``{ [4,-2,-1,0], [0,0,0,0], [1,3,3,3], [3,4,1,4], ... }``.
//! @endrst
//!
//! @param[out] output
//! Calling thread's adjacent difference result
//!
//! @param[in] input
//! Calling thread's input items (may be aliased to `output`)
//!
//! @param[in] difference_op
//! Binary difference operator
//!
//! @param[in] valid_items
//! Number of valid items in thread block
template <int ITEMS_PER_THREAD, typename OutputType, typename DifferenceOpT>
_CCCL_DEVICE _CCCL_FORCEINLINE void SubtractLeftPartialTile(
T (&input)[ITEMS_PER_THREAD], OutputType (&output)[ITEMS_PER_THREAD], DifferenceOpT difference_op, int valid_items)
{
// Share last item
temp_storage.last_items[linear_tid] = input[ITEMS_PER_THREAD - 1];
__syncthreads();
if ((linear_tid + 1) * ITEMS_PER_THREAD <= valid_items)
{
_CCCL_PRAGMA_UNROLL_FULL()
for (int item = ITEMS_PER_THREAD - 1; item > 0; item--)
{
output[item] = difference_op(input[item], input[item - 1]);
}
}
else
{
_CCCL_PRAGMA_UNROLL_FULL()
for (int item = ITEMS_PER_THREAD - 1; item > 0; item--)
{
const int idx = linear_tid * ITEMS_PER_THREAD + item;
if (idx < valid_items)
{
output[item] = difference_op(input[item], input[item - 1]);
}
else
{
output[item] = input[item];
}
}
}
if (linear_tid == 0 || valid_items <= linear_tid * ITEMS_PER_THREAD)
{
output[0] = input[0];
}
else
{
output[0] = difference_op(input[0], temp_storage.last_items[linear_tid - 1]);
}
}
//! @rst
//! Subtracts the left element of each adjacent pair of elements partitioned across a CUDA thread block.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! - @rowmajor
//! - @smemreuse
//!
//!
//! Snippet
//! +++++++
//!
//! The code snippet below illustrates how to use BlockAdjacentDifference to compute the left difference between
//! adjacent elements.
//!
//! .. code-block:: c++
//!
//! #include <cub/cub.cuh>
//! // or equivalently <cub/block/block_adjacent_difference.cuh>
//!
//! struct CustomDifference
//! {
//! template <typename DataType>
//! __host__ DataType operator()(DataType &lhs, DataType &rhs)
//! {
//! return lhs - rhs;
//! }
//! };
//!
//! __global__ void ExampleKernel(...)
//! {
//! // Specialize BlockAdjacentDifference for a 1D block of
//! // 128 threads of type int
//! using BlockAdjacentDifferenceT =
//! cub::BlockAdjacentDifference<int, 128>;
//!
//! // Allocate shared memory for BlockAdjacentDifference
//! __shared__ typename BlockAdjacentDifferenceT::TempStorage temp_storage;
//!
//! // Obtain a segment of consecutive items that are blocked across threads
//! int thread_data[4];
//! ...
//! int valid_items = 9;
//! int tile_predecessor_item = 4;
//!
//! // Collectively compute adjacent_difference
//! BlockAdjacentDifferenceT(temp_storage).SubtractLeftPartialTile(
//! thread_data,
//! thread_data,
//! CustomDifference(),
//! valid_items,
//! tile_predecessor_item);
//!
//! Suppose the set of input ``thread_data`` across the block of threads is
//! ``{ [4,2,1,1], [1,1,1,1], [2,3,3,3], [3,4,1,4], ... }``.
//! The corresponding output ``result`` in those threads will be
//! ``{ [0,-2,-1,0], [0,0,0,0], [1,3,3,3], [3,4,1,4], ... }``.
//! @endrst
//!
//! @param[out] output
//! Calling thread's adjacent difference result
//!
//! @param[in] input
//! Calling thread's input items (may be aliased to `output`)
//!
//! @param[in] difference_op
//! Binary difference operator
//!
//! @param[in] valid_items
//! Number of valid items in thread block
//!
//! @param[in] tile_predecessor_item
//! @rst
//! *thread*\ :sub:`0` only item which is going to be subtracted from the first tile item
//! (*input*\ :sub:`0` from *thread*\ :sub:`0`).
//! @endrst
template <int ITEMS_PER_THREAD, typename OutputType, typename DifferenceOpT>
_CCCL_DEVICE _CCCL_FORCEINLINE void SubtractLeftPartialTile(
T (&input)[ITEMS_PER_THREAD],
OutputType (&output)[ITEMS_PER_THREAD],
DifferenceOpT difference_op,
int valid_items,
T tile_predecessor_item)
{
// Share last item
temp_storage.last_items[linear_tid] = input[ITEMS_PER_THREAD - 1];
__syncthreads();
if ((linear_tid + 1) * ITEMS_PER_THREAD <= valid_items)
{
_CCCL_PRAGMA_UNROLL_FULL()
for (int item = ITEMS_PER_THREAD - 1; item > 0; item--)
{
output[item] = difference_op(input[item], input[item - 1]);
}
}
else
{
_CCCL_PRAGMA_UNROLL_FULL()
for (int item = ITEMS_PER_THREAD - 1; item > 0; item--)
{
const int idx = linear_tid * ITEMS_PER_THREAD + item;
if (idx < valid_items)
{
output[item] = difference_op(input[item], input[item - 1]);
}
else
{
output[item] = input[item];
}
}
}
if (valid_items <= linear_tid * ITEMS_PER_THREAD)
{
output[0] = input[0];
}
else if (linear_tid == 0)
{
output[0] = difference_op(input[0], tile_predecessor_item);
}
else
{
output[0] = difference_op(input[0], temp_storage.last_items[linear_tid - 1]);
}
}
//! @}
//! @name Read right operations
//! @{
//!
//! @rst
//!
//! Subtracts the right element of each adjacent pair of elements partitioned across a CUDA thread block.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! - @rowmajor
//! - @smemreuse
//!
//! Snippet
//! +++++++
//!
//! The code snippet below illustrates how to use BlockAdjacentDifference to compute the right difference between
//! adjacent elements.
//!
//! .. code-block:: c++
//!
//! #include <cub/cub.cuh>
//! // or equivalently <cub/block/block_adjacent_difference.cuh>
//!
//! struct CustomDifference
//! {
//! template <typename DataType>
//! __host__ DataType operator()(DataType &lhs, DataType &rhs)
//! {
//! return lhs - rhs;
//! }
//! };
//!
//! __global__ void ExampleKernel(...)
//! {
//! // Specialize BlockAdjacentDifference for a 1D block of
//! // 128 threads of type int
//! using BlockAdjacentDifferenceT =
//! cub::BlockAdjacentDifference<int, 128>;
//!
//! // Allocate shared memory for BlockAdjacentDifference
//! __shared__ typename BlockAdjacentDifferenceT::TempStorage temp_storage;
//!
//! // Obtain a segment of consecutive items that are blocked across threads
//! int thread_data[4];
//! ...
//!
//! // Collectively compute adjacent_difference
//! BlockAdjacentDifferenceT(temp_storage).SubtractRight(
//! thread_data,
//! thread_data,
//! CustomDifference());
//!
//! Suppose the set of input ``thread_data`` across the block of threads is
//! ``{ ...3], [4,2,1,1], [1,1,1,1], [2,3,3,3], [3,4,1,4] }``.
//! The corresponding output ``result`` in those threads will be
//! ``{ ...-1, [2,1,0,0], [0,0,0,-1], [-1,0,0,0], [-1,3,-3,4] }``.
//! @endrst
//!
//! @param[out] output
//! Calling thread's adjacent difference result
//!
//! @param[in] input
//! Calling thread's input items (may be aliased to `output`)
//!
//! @param[in] difference_op
//! Binary difference operator
template <int ITEMS_PER_THREAD, typename OutputT, typename DifferenceOpT>
_CCCL_DEVICE _CCCL_FORCEINLINE void
SubtractRight(T (&input)[ITEMS_PER_THREAD], OutputT (&output)[ITEMS_PER_THREAD], DifferenceOpT difference_op)
{
// Share first item
temp_storage.first_items[linear_tid] = input[0];
__syncthreads();
_CCCL_PRAGMA_UNROLL_FULL()
for (int item = 0; item < ITEMS_PER_THREAD - 1; item++)
{
output[item] = difference_op(input[item], input[item + 1]);
}
if (linear_tid == BLOCK_THREADS - 1)
{
output[ITEMS_PER_THREAD - 1] = input[ITEMS_PER_THREAD - 1];
}
else
{
output[ITEMS_PER_THREAD - 1] =
difference_op(input[ITEMS_PER_THREAD - 1], temp_storage.first_items[linear_tid + 1]);
}
}
//! @rst
//! Subtracts the right element of each adjacent pair of elements partitioned across a CUDA thread block.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! - @rowmajor
//! - @smemreuse
//!
//! Snippet
//! +++++++
//!
//! The code snippet below illustrates how to use BlockAdjacentDifference to compute the right difference between
//! adjacent elements.
//!
//!
//! .. code-block:: c++
//!
//! #include <cub/cub.cuh>
//! // or equivalently <cub/block/block_adjacent_difference.cuh>
//!
//! struct CustomDifference
//! {
//! template <typename DataType>
//! __host__ DataType operator()(DataType &lhs, DataType &rhs)
//! {
//! return lhs - rhs;
//! }
//! };
//!
//! __global__ void ExampleKernel(...)
//! {
//! // Specialize BlockAdjacentDifference for a 1D block of
//! // 128 threads of type int
//! using BlockAdjacentDifferenceT =
//! cub::BlockAdjacentDifference<int, 128>;
//!
//! // Allocate shared memory for BlockAdjacentDifference
//! __shared__ typename BlockAdjacentDifferenceT::TempStorage temp_storage;
//!
//! // Obtain a segment of consecutive items that are blocked across threads
//! int thread_data[4];
//! ...
//!
//! // The first item in the next tile:
//! int tile_successor_item = ...;
//!
//! // Collectively compute adjacent_difference
//! BlockAdjacentDifferenceT(temp_storage).SubtractRight(
//! thread_data,
//! thread_data,
//! CustomDifference(),
//! tile_successor_item);
//!
//! Suppose the set of input ``thread_data`` across the block of threads is
//! ``{ ...3], [4,2,1,1], [1,1,1,1], [2,3,3,3], [3,4,1,4] }``,
//! and that ``tile_successor_item`` is ``3``. The corresponding output ``result``
//! in those threads will be
//! ``{ ...-1, [2,1,0,0], [0,0,0,-1], [-1,0,0,0], [-1,3,-3,1] }``.
//! @endrst
//!
//! @param[out] output
//! Calling thread's adjacent difference result
//!
//! @param[in] input
//! Calling thread's input items (may be aliased to `output`)
//!
//! @param[in] difference_op
//! Binary difference operator
//!
//! @param[in] tile_successor_item
//! @rst
//! *thread*\ :sub:`BLOCK_THREADS` only item which is going to be subtracted from the last tile item
//! (*input*\ :sub:`ITEMS_PER_THREAD` from *thread*\ :sub:`BLOCK_THREADS`).
//! @endrst
template <int ITEMS_PER_THREAD, typename OutputT, typename DifferenceOpT>
_CCCL_DEVICE _CCCL_FORCEINLINE void SubtractRight(
T (&input)[ITEMS_PER_THREAD],
OutputT (&output)[ITEMS_PER_THREAD],
DifferenceOpT difference_op,
T tile_successor_item)
{
// Share first item
temp_storage.first_items[linear_tid] = input[0];
__syncthreads();
// 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];
_CCCL_PRAGMA_UNROLL_FULL()
for (int item = 0; item < ITEMS_PER_THREAD - 1; item++)
{
output[item] = difference_op(input[item], input[item + 1]);
}
output[ITEMS_PER_THREAD - 1] = difference_op(input[ITEMS_PER_THREAD - 1], successor_item);
}
//! @rst
//! Subtracts the right element of each adjacent pair in range of elements partitioned across a CUDA thread block.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! - @rowmajor
//! - @smemreuse
//!
//! Snippet
//! +++++++
//!
//! The code snippet below illustrates how to use BlockAdjacentDifference to compute the right difference between
//! adjacent elements.
//!
//!
//! .. code-block:: c++
//!
//! #include <cub/cub.cuh>
//! // or equivalently <cub/block/block_adjacent_difference.cuh>
//!
//! struct CustomDifference
//! {
//! template <typename DataType>
//! __host__ DataType operator()(DataType &lhs, DataType &rhs)
//! {
//! return lhs - rhs;
//! }
//! };
//!
//! __global__ void ExampleKernel(...)
//! {
//! // Specialize BlockAdjacentDifference for a 1D block of
//! // 128 threads of type int
//! using BlockAdjacentDifferenceT =
//! cub::BlockAdjacentDifference<int, 128>;
//!
//! // Allocate shared memory for BlockAdjacentDifference
//! __shared__ typename BlockAdjacentDifferenceT::TempStorage temp_storage;
//!
//! // Obtain a segment of consecutive items that are blocked across threads
//! int thread_data[4];
//! ...
//!
//! // Collectively compute adjacent_difference
//! BlockAdjacentDifferenceT(temp_storage).SubtractRightPartialTile(
//! thread_data,
//! thread_data,
//! CustomDifference(),
//! valid_items);
//!
//! Suppose the set of input ``thread_data`` across the block of threads is
//! ``{ ...3], [4,2,1,1], [1,1,1,1], [2,3,3,3], [3,4,1,4] }``.
//! and that ``valid_items`` is ``507``. The corresponding output ``result`` in
//! those threads will be
//! ``{ ...-1, [2,1,0,0], [0,0,0,-1], [-1,0,3,3], [3,4,1,4] }``.
//! @endrst
//!
//! @param[out] output
//! Calling thread's adjacent difference result
//!
//! @param[in] input
//! Calling thread's input items (may be aliased to `output`)
//!
//! @param[in] difference_op
//! Binary difference operator
//!
//! @param[in] valid_items
//! Number of valid items in thread block
template <int ITEMS_PER_THREAD, typename OutputT, typename DifferenceOpT>
_CCCL_DEVICE _CCCL_FORCEINLINE void SubtractRightPartialTile(
T (&input)[ITEMS_PER_THREAD], OutputT (&output)[ITEMS_PER_THREAD], DifferenceOpT difference_op, int valid_items)
{
// Share first item
temp_storage.first_items[linear_tid] = input[0];
__syncthreads();
if ((linear_tid + 1) * ITEMS_PER_THREAD < valid_items)
{
_CCCL_PRAGMA_UNROLL_FULL()
for (int item = 0; item < ITEMS_PER_THREAD - 1; item++)
{
output[item] = difference_op(input[item], input[item + 1]);
}
output[ITEMS_PER_THREAD - 1] =
difference_op(input[ITEMS_PER_THREAD - 1], temp_storage.first_items[linear_tid + 1]);
}
else
{
_CCCL_PRAGMA_UNROLL_FULL()
for (int item = 0; item < ITEMS_PER_THREAD; item++)
{
const int idx = linear_tid * ITEMS_PER_THREAD + item;
// Right element of input[valid_items - 1] is out of bounds.
// According to the API it's copied into output array
// without modification.
if (idx < valid_items - 1)
{
output[item] = difference_op(input[item], input[item + 1]);
}
else
{
output[item] = input[item];
}
}
}
}
};
CUB_NAMESPACE_END