cuda::simd::add_min and cuda::simd::add_max#
Defined in the <cuda/simd> header.
namespace cuda::simd {
template <class T, class Abi>
[[nodiscard]] __host__ __device__ constexpr
cuda::std::simd::basic_vec<T, Abi> add_max(
const cuda::std::simd::basic_vec<T, Abi>& a,
const cuda::std::simd::basic_vec<T, Abi>& b,
const cuda::std::simd::basic_vec<T, Abi>& c) noexcept;
template <class T, class Abi>
[[nodiscard]] __host__ __device__ constexpr
cuda::std::simd::basic_vec<T, Abi> add_min(
const cuda::std::simd::basic_vec<T, Abi>& a,
const cuda::std::simd::basic_vec<T, Abi>& b,
const cuda::std::simd::basic_vec<T, Abi>& c) noexcept;
} // namespace cuda::simd
The functions perform an element-wise addition followed by a minimum or maximum.
For each element i, the functions are equivalent to:
add_max(a, b, c)[i] == cuda::std::max(a[i] + b[i], c[i])
add_min(a, b, c)[i] == cuda::std::min(a[i] + b[i], c[i])
A ReLU form can be obtained by composing the addition with cuda::simd::min_relu and cuda::simd::max_relu:
auto maximum_relu = cuda::simd::max_relu(a + b, c);
auto minimum_relu = cuda::simd::min_relu(a + b, c);
On supported GPU architectures, the optimized device paths map to Dynamic Programming eXtension (DPX) instructions.
Parameters
a,b: The vectors whose corresponding elements are added.c: The vector compared with the element-wise sum.
Return value
Returns a cuda::std::simd::basic_vec<T, Abi> containing the element-wise result.
Constraints
Tmust be an integer type.The composed ReLU forms require
Tto be a signed integer type.
Performance considerations
On SM90, SM100, and SM103:
Signed and unsigned 16-bit elements use one
VIADDMNMX.S16x2orVIADDMNMX.U16x2instruction per two elements.Signed and unsigned 32-bit elements use one
VIADDMNMXinstruction per element.The composed signed 16-bit and 32-bit ReLU
cuda::simd::max_relu(a + b, c)andcuda::simd::min_relu(a + b, c)forms use the correspondingVIADDMNMX.RELUinstruction.
On SM107 and SM120:
Signed and unsigned 16-bit elements use one
VIADD.16x2and oneVIMNMX.S16x2orVIMNMX.U16x2instruction.Signed and unsigned 32-bit elements use one
IADDand oneVIMNMXinstruction.The composed signed 16-bit and 32-bit ReLU
cuda::simd::max_relu(a + b, c)andcuda::simd::min_relu(a + b, c)forms use one addition and one of the correspondingVIMNMX.RELUinstruction.
Other element types use the portable element-wise implementation.
Example#
#include <cuda/simd>
#include <cuda/std/array>
#include <cuda/std/cassert>
#include <cuda/std/cstdint>
#include <cuda_runtime_api.h>
namespace simd = cuda::std::simd;
__global__ void kernel()
{
using vec_t = simd::basic_vec<int16_t, simd::fixed_size<2>>;
vec_t a(cuda::std::array<int16_t, 2>{-4, 8});
vec_t b(cuda::std::array<int16_t, 2>{1, -3});
vec_t c(cuda::std::array<int16_t, 2>{-2, 10});
vec_t maximum = cuda::simd::add_max(a, b, c);
vec_t minimum = cuda::simd::add_min(a, b, c);
vec_t maximum_relu = cuda::simd::max_relu(a + b, c);
vec_t minimum_relu = cuda::simd::min_relu(a + b, c);
assert(maximum[0] == -2);
assert(maximum[1] == 10);
assert(minimum[0] == -3);
assert(minimum[1] == 5);
assert(maximum_relu[0] == 0);
assert(maximum_relu[1] == 10);
assert(minimum_relu[0] == 0);
assert(minimum_relu[1] == 5);
}
int main()
{
kernel<<<1, 1>>>();
cudaDeviceSynchronize();
}