[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
This commit is contained in:
EngineX CI
2026-07-30 09:35:51 +00:00
parent b4d01f481e
commit 56fd68e7dd
8871 changed files with 1454674 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
//===----------------------------------------------------------------------===//
//
// Part of libcu++, the C++ Standard Library for your entire system,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#ifndef _CUDA___MEMCPY_ASYNC_CHECK_PRECONDITIONS_H
#define _CUDA___MEMCPY_ASYNC_CHECK_PRECONDITIONS_H
#include <cuda/std/detail/__config>
#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 <cuda/__memory/aligned_size.h>
#include <cuda/std/__algorithm/max.h>
#include <cuda/std/__cstddef/types.h>
#include <cuda/std/__memory/is_sufficiently_aligned.h>
#include <cuda/std/cstdint>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
#ifndef _LIBCUDACXX_MEMCPY_ASYNC_PRE_TESTING
# define _LIBCUDACXX_MEMCPY_ASYNC_PRE_ASSERT(_Cond, _Msg) _CCCL_ASSERT(_Cond, _Msg)
#else // ^^^ _LIBCUDACXX_MEMCPY_ASYNC_PRE_TESTING ^^^ / vvv !_LIBCUDACXX_MEMCPY_ASYNC_PRE_TESTING vvv
# define _LIBCUDACXX_MEMCPY_ASYNC_PRE_ASSERT(_Cond, _Msg) \
do \
{ \
if (!(_Cond)) \
{ \
return false; \
} \
} while (false)
#endif // _LIBCUDACXX_MEMCPY_ASYNC_PRE_TESTING
// Check the memcpy_async preconditions, return value is intended for testing purposes exclusively
template <class _Tp, class _Size>
_CCCL_HOST_DEVICE_API inline bool __memcpy_async_check_pre(_Tp* __dst, const _Tp* __src, _Size __size)
{
constexpr auto __align = ::cuda::std::max(alignof(_Tp), __get_size_align_v<_Size>);
const auto __dst_val = reinterpret_cast<uintptr_t>(__dst);
const auto __src_val = reinterpret_cast<uintptr_t>(__src);
// check src and dst alignment
_LIBCUDACXX_MEMCPY_ASYNC_PRE_ASSERT(::cuda::std::is_sufficiently_aligned<__align>(__dst),
"destination pointer must be aligned to the specified alignment");
_LIBCUDACXX_MEMCPY_ASYNC_PRE_ASSERT(
::cuda::std::is_sufficiently_aligned<__align>(__src), "source pointer must be aligned to the specified alignment");
// check src and dst overlap
_LIBCUDACXX_MEMCPY_ASYNC_PRE_ASSERT(
!((__dst_val <= __src_val && __src_val < __dst_val + __size)
|| (__src_val <= __dst_val && __dst_val < __src_val + __size)),
"destination and source buffers must not overlap");
return true;
}
template <class _Size>
_CCCL_HOST_DEVICE_API inline bool __memcpy_async_check_pre(void* __dst, const void* __src, _Size __size)
{
return ::cuda::__memcpy_async_check_pre(reinterpret_cast<char*>(__dst), reinterpret_cast<const char*>(__src), __size);
}
_CCCL_END_NAMESPACE_CUDA
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___MEMCPY_ASYNC_CHECK_PRECONDITIONS_H

View File

@@ -0,0 +1,47 @@
//===----------------------------------------------------------------------===//
//
// Part of libcu++, the C++ Standard Library for your entire system,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#ifndef _CUDA___MEMCPY_ASYNC_COMPLETION_MECHANISM_H
#define _CUDA___MEMCPY_ASYNC_COMPLETION_MECHANISM_H
#include <cuda/std/detail/__config>
#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 <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
//! @brief __completion_mechanism allows memcpy_async to report back what completion
//! mechanism it used. This is necessary to determine in which way to synchronize
//! the memcpy_async with a sync object (barrier or pipeline).
//
//! In addition, we use this enum to create bit flags so that calling functions
//! can specify which completion mechanisms can be used (__sync is always
//! allowed).
enum class __completion_mechanism
{
__sync = 0,
__mbarrier_complete_tx = 1 << 0, // Use powers of two here to support the
__async_group = 1 << 1, // bit flag use case
__async_bulk_group = 1 << 2,
};
_CCCL_END_NAMESPACE_CUDA
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___MEMCPY_ASYNC_COMPLETION_MECHANISM_H

View File

@@ -0,0 +1,71 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of libcu++, the C++ Standard Library for your entire system,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#ifndef _CUDA___MEMCPY_ASYNC_CP_ASYNC_BULK_SHARED_GLOBAL_H_
#define _CUDA___MEMCPY_ASYNC_CP_ASYNC_BULK_SHARED_GLOBAL_H_
#include <cuda/std/detail/__config>
#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
#if _CCCL_CUDA_COMPILATION()
# if __cccl_ptx_isa >= 800
# include <cuda/__memcpy_async/elect_one.h>
# include <cuda/__ptx/instructions/cp_async_bulk.h>
# include <cuda/__ptx/instructions/mbarrier_expect_tx.h>
# include <cuda/__ptx/ptx_dot_variants.h>
# include <cuda/__ptx/ptx_helper_functions.h>
# include <cuda/std/__type_traits/conditional.h>
# include <cuda/std/cstdint>
# include <nv/target>
# include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
extern "C" _CCCL_DEVICE void __cuda_ptx_cp_async_bulk_shared_global_is_not_supported_before_SM_90__();
template <typename _Group>
_CCCL_DEVICE_API inline void __cp_async_bulk_shared_global_and_expect_tx(
const _Group& __g, char* __dest, const char* __src, ::cuda::std::size_t __size, ::cuda::std::uint64_t* __bar_handle)
{
// https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#data-movement-and-conversion-instructions-cp-async-bulk
NV_IF_ELSE_TARGET(
NV_PROVIDES_SM_90,
(if (::cuda::device::__group_elect_one(__g)) {
::cuda::ptx::cp_async_bulk(
::cuda::std::conditional_t<__cccl_ptx_isa >= 860, ::cuda::ptx::space_shared_t, ::cuda::ptx::space_cluster_t>{},
::cuda::ptx::space_global,
__dest,
__src,
__size,
__bar_handle);
::cuda::ptx::mbarrier_expect_tx(
::cuda::ptx::sem_relaxed, ::cuda::ptx::scope_cta, ::cuda::ptx::space_shared, __bar_handle, __size);
}),
(::cuda::__cuda_ptx_cp_async_bulk_shared_global_is_not_supported_before_SM_90__();));
}
_CCCL_END_NAMESPACE_CUDA
# include <cuda/std/__cccl/epilogue.h>
# endif // __cccl_ptx_isa >= 800
#endif // _CCCL_CUDA_COMPILATION()
#endif // _CUDA___MEMCPY_ASYNC_CP_ASYNC_BULK_SHARED_GLOBAL_H_

View File

@@ -0,0 +1,72 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of libcu++, the C++ Standard Library for your entire system,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#ifndef _CUDA___MEMCPY_ASYNC_CP_ASYNC_FALLBACK_H_
#define _CUDA___MEMCPY_ASYNC_CP_ASYNC_FALLBACK_H_
#include <cuda/std/detail/__config>
#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 <cuda/std/cstddef>
#include <nv/target>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
template <::cuda::std::size_t _Copy_size>
struct __copy_chunk
{
_CCCL_ALIGNAS(_Copy_size) char data[_Copy_size];
};
template <::cuda::std::size_t _Alignment, typename _Group>
_CCCL_HOST_DEVICE_API void
__cp_async_fallback_mechanism(_Group __g, char* __dest, const char* __src, ::cuda::std::size_t __size)
{
// Maximal copy size is 16 bytes
constexpr ::cuda::std::size_t __copy_size = (_Alignment > 16) ? 16 : _Alignment;
using __chunk_t = __copy_chunk<__copy_size>;
// "Group"-strided loop over memory
const ::cuda::std::size_t __stride = __g.size() * __copy_size;
// An unroll factor of 64 ought to be enough for anybody. This unroll pragma
// is mainly intended to place an upper bound on loop unrolling. The number
// is more than high enough for the intended use case: an unroll factor of
// 64 allows moving 4 * 64 * 256 = 64kb in one unrolled loop with 256
// threads (copying ints). On the other hand, in the unfortunate case that
// we have to move 1024 bytes / thread with char width, then we prevent
// fully unrolling the loop to 1024 copy instructions. This prevents the
// compile times from increasing unreasonably, and also has negligible
// impact on runtime performance.
_CCCL_PRAGMA_UNROLL(64)
for (::cuda::std::size_t __offset = __g.thread_rank() * __copy_size; __offset < __size; __offset += __stride)
{
__chunk_t tmp = *reinterpret_cast<const __chunk_t*>(__src + __offset);
*reinterpret_cast<__chunk_t*>(__dest + __offset) = tmp;
}
}
_CCCL_END_NAMESPACE_CUDA
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___MEMCPY_ASYNC_CP_ASYNC_FALLBACK_H_

View File

@@ -0,0 +1,148 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of libcu++, the C++ Standard Library for your entire system,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#ifndef _CUDA___MEMCPY_ASYNC_CP_ASYNC_SHARED_GLOBAL_H_
#define _CUDA___MEMCPY_ASYNC_CP_ASYNC_SHARED_GLOBAL_H_
#include <cuda/std/detail/__config>
#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
#if _CCCL_CUDA_COMPILATION()
# include <cuda/__ptx/ptx_dot_variants.h>
# include <cuda/__ptx/ptx_helper_functions.h>
# include <cuda/std/cstdint>
# include <nv/target>
# include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
extern "C" _CCCL_DEVICE void __cuda_ptx_cp_async_shared_global_is_not_supported_before_SM_80__();
# if _CCCL_CUDA_COMPILER(NVCC, <, 12, 1) // WAR for compiler state space issues
template <size_t _Copy_size>
_CCCL_DEVICE_API void __cp_async_shared_global(char* __dest, const char* __src)
{
// https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#data-movement-and-conversion-instructions-cp-async
// If `if constexpr` is not available, this function gets instantiated even
// if is not called. Do not static_assert in that case.
static_assert(_Copy_size == 4 || _Copy_size == 8 || _Copy_size == 16,
"cp.async.shared.global requires a copy size of 4, 8, or 16.");
NV_IF_ELSE_TARGET(
NV_PROVIDES_SM_80,
(asm volatile(R"XYZ(
{
.reg .b64 tmp;
.reg .b32 dst;
cvta.to.shared.u64 tmp, %0;
cvt.u32.u64 dst, tmp;
cvta.to.global.u64 tmp, %1;
cp.async.ca.shared.global [dst], [tmp], %2, %2;
}
)XYZ" : : "l"(__dest),
"l"(__src),
"n"(_Copy_size) : "memory");),
(::cuda::__cuda_ptx_cp_async_shared_global_is_not_supported_before_SM_80__();));
}
template <>
_CCCL_DEVICE_API inline void __cp_async_shared_global<16>(char* __dest, const char* __src)
{
// https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#data-movement-and-conversion-instructions-cp-async
// When copying 16 bytes, it is possible to skip L1 cache (.cg).
NV_IF_ELSE_TARGET(NV_PROVIDES_SM_80,
(asm volatile(R"XYZ(
{
.reg .u64 tmp;
.reg .u32 dst;
cvta.to.shared.u64 tmp, %0;
cvt.u32.u64 dst, tmp;
cvta.to.global.u64 tmp, %1;
cp.async.cg.shared.global [dst], [tmp], 16, 16;
}
)XYZ" : : "l"(__dest),
"l"(__src) : "memory");),
(::cuda::__cuda_ptx_cp_async_shared_global_is_not_supported_before_SM_80__();));
}
# else // ^^^^ NVCC 12.0 / !NVCC 12.0 vvvvv WAR for compiler state space issues
template <size_t _Copy_size>
_CCCL_DEVICE_API void __cp_async_shared_global(char* __dest, const char* __src)
{
// https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#data-movement-and-conversion-instructions-cp-async
// If `if constexpr` is not available, this function gets instantiated even
// if is not called. Do not static_assert in that case.
static_assert(_Copy_size == 4 || _Copy_size == 8 || _Copy_size == 16,
"cp.async.shared.global requires a copy size of 4, 8, or 16.");
NV_IF_ELSE_TARGET(
NV_PROVIDES_SM_80,
(asm volatile("cp.async.ca.shared.global [%0], [%1], %2, %2;" : : "r"(
static_cast<::cuda::std::uint32_t>(::__cvta_generic_to_shared(__dest))),
"l"(static_cast<::cuda::std::uint64_t>(::__cvta_generic_to_global(__src))),
"n"(_Copy_size) : "memory");),
(::cuda::__cuda_ptx_cp_async_shared_global_is_not_supported_before_SM_80__();));
}
template <>
_CCCL_DEVICE_API inline void __cp_async_shared_global<16>(char* __dest, const char* __src)
{
// https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#data-movement-and-conversion-instructions-cp-async
// When copying 16 bytes, it is possible to skip L1 cache (.cg).
NV_IF_ELSE_TARGET(
NV_PROVIDES_SM_80,
(asm volatile("cp.async.cg.shared.global [%0], [%1], %2, %2;" : : "r"(
static_cast<::cuda::std::uint32_t>(::__cvta_generic_to_shared(__dest))),
"l"(static_cast<::cuda::std::uint64_t>(::__cvta_generic_to_global(__src))),
"n"(16) : "memory");),
(::cuda::__cuda_ptx_cp_async_shared_global_is_not_supported_before_SM_80__();));
}
# endif // _CCCL_CUDA_COMPILER(NVCC, >=, 12, 1)
template <size_t _Alignment, typename _Group>
_CCCL_DEVICE_API void
__cp_async_shared_global_mechanism(_Group __g, char* __dest, const char* __src, ::cuda::std::size_t __size)
{
// If `if constexpr` is not available, this function gets instantiated even
// if is not called. Do not static_assert in that case.
static_assert(4 <= _Alignment, "cp.async requires at least 4-byte alignment");
// Maximal copy size is 16.
constexpr int __copy_size = (_Alignment > 16) ? 16 : _Alignment;
// We use an int offset here, because we are copying to shared memory,
// which is easily addressable using int.
const int __group_size = __g.size();
const int __group_rank = __g.thread_rank();
const int __stride = __group_size * __copy_size;
for (int __offset = __group_rank * __copy_size; __offset < static_cast<int>(__size); __offset += __stride)
{
::cuda::__cp_async_shared_global<__copy_size>(__dest + __offset, __src + __offset);
}
}
_CCCL_END_NAMESPACE_CUDA
# include <cuda/std/__cccl/epilogue.h>
#endif // _CCCL_CUDA_COMPILATION()
#endif // _CUDA___MEMCPY_ASYNC_CP_ASYNC_SHARED_GLOBAL_H_

View File

@@ -0,0 +1,165 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of libcu++, the C++ Standard Library for your entire system,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#ifndef _CUDA___MEMCPY_ASYNC_DISPATCH_MEMCPY_ASYNC_H_
#define _CUDA___MEMCPY_ASYNC_DISPATCH_MEMCPY_ASYNC_H_
#include <cuda/std/detail/__config>
#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 <cuda/__memcpy_async/completion_mechanism.h>
#include <cuda/__memcpy_async/cp_async_bulk_shared_global.h>
#include <cuda/__memcpy_async/cp_async_fallback.h>
#include <cuda/__memcpy_async/cp_async_shared_global.h>
#include <cuda/__memory/address_space.h>
#include <cuda/std/cstddef>
#include <cuda/std/cstdint>
#include <cuda/std/cstring>
#include <nv/target>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
/***********************************************************************
* cuda::memcpy_async dispatch
*
* The dispatch mechanism takes all the arguments and dispatches to the
* fastest asynchronous copy mechanism available.
*
* It returns a __completion_mechanism that indicates which completion mechanism
* was used by the copy mechanism. This value can be used by the sync object to
* further synchronize if necessary.
*
***********************************************************************/
template <::cuda::std::size_t _Align, typename _Group>
[[nodiscard]] _CCCL_DEVICE_API __completion_mechanism __dispatch_memcpy_async_any_to_any(
_Group const& __group,
char* __dest_char,
char const* __src_char,
::cuda::std::size_t __size,
[[maybe_unused]] ::cuda::std::uint32_t __allowed_completions,
[[maybe_unused]] ::cuda::std::uint64_t* __bar_handle)
{
::cuda::__cp_async_fallback_mechanism<_Align>(__group, __dest_char, __src_char, __size);
return __completion_mechanism::__sync;
}
template <::cuda::std::size_t _Align, typename _Group>
[[nodiscard]] _CCCL_DEVICE_API __completion_mechanism __dispatch_memcpy_async_global_to_shared(
_Group const& __group,
char* __dest_char,
char const* __src_char,
::cuda::std::size_t __size,
[[maybe_unused]] ::cuda::std::uint32_t __allowed_completions,
[[maybe_unused]] ::cuda::std::uint64_t* __bar_handle)
{
#if __cccl_ptx_isa >= 800
NV_IF_TARGET(
NV_PROVIDES_SM_90,
([[maybe_unused]] const bool __can_use_complete_tx =
__allowed_completions & uint32_t(__completion_mechanism::__mbarrier_complete_tx);
_CCCL_ASSERT(__can_use_complete_tx == (nullptr != __bar_handle),
"Pass non-null bar_handle if and only if can_use_complete_tx.");
if constexpr (_Align >= 16) {
if (__can_use_complete_tx
&& ::cuda::device::is_address_from(__bar_handle, ::cuda::device::address_space::shared))
{
::cuda::__cp_async_bulk_shared_global_and_expect_tx(__group, __dest_char, __src_char, __size, __bar_handle);
return __completion_mechanism::__mbarrier_complete_tx;
}
}
// Fallthrough to SM 80..
));
#endif // __cccl_ptx_isa >= 800
NV_IF_TARGET(
NV_PROVIDES_SM_80,
(if constexpr (_Align >= 4) {
const bool __can_use_async_group = __allowed_completions & uint32_t(__completion_mechanism::__async_group);
if (__can_use_async_group)
{
::cuda::__cp_async_shared_global_mechanism<_Align>(__group, __dest_char, __src_char, __size);
return __completion_mechanism::__async_group;
}
}
// Fallthrough..
));
::cuda::__cp_async_fallback_mechanism<_Align>(__group, __dest_char, __src_char, __size);
return __completion_mechanism::__sync;
}
// __dispatch_memcpy_async is the internal entry point for dispatching to the correct memcpy_async implementation.
template <::cuda::std::size_t _Align, typename _Group>
[[nodiscard]] _CCCL_HOST_DEVICE_API __completion_mechanism __dispatch_memcpy_async(
_Group const& __group,
char* __dest_char,
char const* __src_char,
::cuda::std::size_t __size,
[[maybe_unused]] ::cuda::std::uint32_t __allowed_completions,
[[maybe_unused]] ::cuda::std::uint64_t* __bar_handle)
{
NV_IF_ELSE_TARGET(
NV_IS_DEVICE,
(
// Dispatch based on direction of the copy: global to shared, shared to
// global, etc.
// CUDA compilers <= 12.2 may not propagate assumptions about the state space
// of pointers correctly. Therefore, we
// 1) put the code for each copy direction in a separate function, and
// 2) make sure none of the code paths can reach each other by "falling through".
//
// See nvbug 4074679 and also PR #478.
if (::cuda::device::is_address_from(__src_char, ::cuda::device::address_space::global)
&& ::cuda::device::is_address_from(__dest_char, ::cuda::device::address_space::shared)) {
return ::cuda::__dispatch_memcpy_async_global_to_shared<_Align>(
__group, __dest_char, __src_char, __size, __allowed_completions, __bar_handle);
} else {
return ::cuda::__dispatch_memcpy_async_any_to_any<_Align>(
__group, __dest_char, __src_char, __size, __allowed_completions, __bar_handle);
}),
(
// Host code path:
if (__group.thread_rank() == 0) {
::cuda::std::memcpy(__dest_char, __src_char, __size);
} return __completion_mechanism::__sync;));
}
template <::cuda::std::size_t _Align, typename _Group>
[[nodiscard]] _CCCL_HOST_DEVICE_API __completion_mechanism __dispatch_memcpy_async(
_Group const& __group,
char* __dest_char,
char const* __src_char,
[[maybe_unused]] ::cuda::std::size_t __size,
[[maybe_unused]] ::cuda::std::uint32_t __allowed_completions)
{
_CCCL_ASSERT(!(__allowed_completions & uint32_t(__completion_mechanism::__mbarrier_complete_tx)),
"Cannot allow mbarrier_complete_tx completion mechanism when not passing a barrier. ");
return ::cuda::__dispatch_memcpy_async<_Align>(
__group, __dest_char, __src_char, __size, __allowed_completions, nullptr);
}
_CCCL_END_NAMESPACE_CUDA
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___MEMCPY_ASYNC_DISPATCH_MEMCPY_ASYNC_H_

View File

@@ -0,0 +1,73 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of libcu++, the C++ Standard Library for your entire system,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#ifndef _CUDA___MEMCPY_ASYNC_ELECT_ONE_H_
#define _CUDA___MEMCPY_ASYNC_ELECT_ONE_H_
#include <cuda/std/detail/__config>
#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 <cuda/__memcpy_async/group_traits.h>
#include <cuda/__ptx/instructions/elect_sync.h>
#include <cuda/std/__cccl/prologue.h>
#if _CCCL_CUDA_COMPILATION()
_CCCL_BEGIN_NAMESPACE_CUDA_DEVICE
//! Elects a single leader thread from a one dimensional thread block. For SM90+ will use ptx::elect_sync() etc.,
//! otherwise just selects the thread with ID 0. If the returned value is used as condition for an if statement, the
//! compiler will emit a uniform data path for the branch.
[[nodiscard]] _CCCL_DEVICE_API _CCCL_FORCEINLINE bool __block_elect_one() noexcept
{
_CCCL_ASSERT(blockDim.y == 1 && blockDim.z == 1, "The block must by one dimensional");
NV_IF_ELSE_TARGET(
NV_PROVIDES_SM_90,
(const auto tid = threadIdx.x; //
const auto warp_id = tid / 32;
const auto uniform_warp_id = ::__shfl_sync(~0, warp_id, 0); // broadcast from lane 0
return uniform_warp_id == 0 && ::cuda::ptx::elect_sync(~0); // elect a leader thread among warp 0
),
(return threadIdx.x == 0;));
}
template <typename _Group>
[[nodiscard]] _CCCL_DEVICE_API _CCCL_FORCEINLINE bool __group_elect_one(const _Group& __g) noexcept
{
NV_IF_TARGET(NV_PROVIDES_SM_90,
(
if constexpr (is_thread_block_group_v<_Group>) {
// cooperative groups maps a multidimensional thread id into the thread rank the same way as warps do
const unsigned __tid = __g.thread_rank();
const unsigned __warp_id = __tid / 32;
const unsigned __uniform_warp_id = ::__shfl_sync(~0, __warp_id, 0); // broadcast from lane 0
return __uniform_warp_id == 0 && ::cuda::ptx::elect_sync(~0); // elect a leader thread among warp 0
} else if constexpr (is_warp_group_v<_Group>) { return ::cuda::ptx::elect_sync(~0); }));
return __g.thread_rank() == 0;
}
#endif // _CCCL_CUDA_COMPILATION()
_CCCL_END_NAMESPACE_CUDA_DEVICE
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___MEMCPY_ASYNC_ELECT_ONE_H_

View File

@@ -0,0 +1,61 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of libcu++, the C++ Standard Library for your entire system,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#ifndef _CUDA___MEMCPY_ASYNC_GROUP_TRAITS_H_
#define _CUDA___MEMCPY_ASYNC_GROUP_TRAITS_H_
#include <cuda/std/detail/__config>
#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 <cuda/std/__cccl/prologue.h>
// forward declare cooperative groups types. we cannot include <cooperative_groups.h> since it does not work with NVHPC
namespace cooperative_groups
{
namespace __v1
{
class thread_block;
template <unsigned int Size, typename ParentT>
class thread_block_tile;
} // namespace __v1
using namespace __v1;
} // namespace cooperative_groups
_CCCL_BEGIN_NAMESPACE_CUDA
//! Trait to detect whether a group represents a CUDA thread block, for example: ``cooperative_groups::thread_block``.
template <typename _Group>
inline constexpr bool is_thread_block_group_v = false;
template <>
inline constexpr bool is_thread_block_group_v<::cooperative_groups::thread_block> = true;
//! Trait to detect whether a group represents a CUDA warp, for example:
//! ``cooperative_groups::thread_block_tile<32, ...>``.
template <typename _Group>
inline constexpr bool is_warp_group_v = false;
template <typename _Parent>
inline constexpr bool is_warp_group_v<::cooperative_groups::thread_block_tile<32, _Parent>> = true;
_CCCL_END_NAMESPACE_CUDA
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___MEMCPY_ASYNC_GROUP_TRAITS_H_

View File

@@ -0,0 +1,53 @@
//===----------------------------------------------------------------------===//
//
// Part of libcu++, the C++ Standard Library for your entire system,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#ifndef _CUDA___MEMCPY_ASYNC_IS_LOCAL_SMEM_BARRIER_H
#define _CUDA___MEMCPY_ASYNC_IS_LOCAL_SMEM_BARRIER_H
#include <cuda/std/detail/__config>
#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 <cuda/__barrier/barrier.h>
#include <cuda/__memory/address_space.h>
#include <cuda/std/__atomic/scopes.h>
#include <cuda/std/__barrier/empty_completion.h>
#include <cuda/std/__type_traits/is_same.h>
#include <nv/target>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
//! @brief __is_local_smem_barrier returns true if barrier is (1) block-scoped and (2) located in shared memory.
template <thread_scope _Sco,
typename _CompF,
bool _Is_mbarrier = (_Sco == thread_scope_block)
&& ::cuda::std::is_same_v<_CompF, ::cuda::std::__empty_completion>>
_CCCL_HOST_DEVICE_API inline bool __is_local_smem_barrier([[maybe_unused]] barrier<_Sco, _CompF>& __barrier)
{
NV_IF_ELSE_TARGET(
NV_IS_DEVICE,
(return _Is_mbarrier && ::cuda::device::is_object_from(__barrier, ::cuda::device::address_space::shared);),
(return false;));
}
_CCCL_END_NAMESPACE_CUDA
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___MEMCPY_ASYNC_IS_LOCAL_SMEM_BARRIER_H

View File

@@ -0,0 +1,179 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of libcu++, the C++ Standard Library for your entire system,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#ifndef _CUDA___MEMCPY_ASYNC_MEMCPY_ASYNC_H_
#define _CUDA___MEMCPY_ASYNC_MEMCPY_ASYNC_H_
#include <cuda/std/detail/__config>
#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
#if _CCCL_CUDA_COMPILATION()
# include <cuda/__barrier/async_contract_fulfillment.h>
# include <cuda/__barrier/barrier.h>
# include <cuda/__barrier/barrier_block_scope.h>
# include <cuda/__barrier/barrier_thread_scope.h>
# include <cuda/__memcpy_async/check_preconditions.h>
# include <cuda/__memcpy_async/memcpy_async_barrier.h>
# include <cuda/__memory/aligned_size.h>
# include <cuda/std/__atomic/scopes.h>
# include <cuda/std/__type_traits/void_t.h>
# include <cuda/std/cstddef>
# include <cuda/std/cstdint>
# include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
/***********************************************************************
* memcpy_async code:
*
* A call to cuda::memcpy_async(dest, src, size, barrier) can dispatch to any of
* these PTX instructions:
*
* 1. normal synchronous copy (fallback)
* 2. cp.async: shared <- global
* 3. cp.async.bulk: shared <- global
* 4. TODO: cp.async.bulk: global <- shared
* 5. TODO: cp.async.bulk: cluster <- shared
*
* Which of these options is chosen, depends on:
*
* 1. The alignment of dest, src, and size;
* 2. The direction of the copy
* 3. The current compute capability
* 4. The requested completion mechanism
*
* PTX has 3 asynchronous completion mechanisms:
*
* 1. Async group - local to a thread. Used by cp.async
* 2. Bulk async group - local to a thread. Used by cp.async.bulk (shared -> global)
* 3. mbarrier::complete_tx - shared memory barier. Used by cp.async.bulk (other directions)
*
* The code is organized as follows:
*
* 1. Asynchronous copy mechanisms that wrap the PTX instructions
*
* 2. Device memcpy_async implementation per copy direction (global to shared,
* shared to global, etc). Dispatches to fastest mechanism based on requested
* completion mechanism(s), pointer alignment, and architecture.
*
* 3. Host and device memcpy_async implementations. Host implementation is
* basically a memcpy wrapper; device implementation dispatches based on the
* direction of the copy.
*
* 4. __memcpy_async_barrier:
* a) Sets the allowed completion mechanisms based on the barrier location
* b) Calls the host or device memcpy_async implementation
* c) If necessary, synchronizes with the barrier based on the returned
* completion mechanism.
*
* 5. The public memcpy_async function overloads. Call into
* __memcpy_async_barrier.
*
***********************************************************************/
/***********************************************************************
* Asynchronous copy mechanisms:
*
* 1. cp.async.bulk: shared <- global
* 2. TODO: cp.async.bulk: cluster <- shared
* 3. TODO: cp.async.bulk: global <- shared
* 4. cp.async: shared <- global
* 5. normal synchronous copy (fallback)
***********************************************************************/
template <typename _Group, class _Tp, ::cuda::std::size_t _Alignment, thread_scope _Sco, typename _CompF>
_CCCL_HOST_DEVICE_API inline async_contract_fulfillment memcpy_async(
_Group const& __group,
_Tp* __destination,
_Tp const* __source,
aligned_size_t<_Alignment> __size,
barrier<_Sco, _CompF>& __barrier)
{
static_assert(_Alignment >= alignof(_Tp), "alignment must be at least the alignof(T)");
_CCCL_ASSERT(::cuda::__memcpy_async_check_pre(__destination, __source, __size), "memcpy_async preconditions unmet");
return ::cuda::__memcpy_async_barrier(__group, __destination, __source, __size, __barrier);
}
template <class _Tp, typename _Size, thread_scope _Sco, typename _CompF>
_CCCL_HOST_DEVICE_API inline async_contract_fulfillment
memcpy_async(_Tp* __destination, _Tp const* __source, _Size __size, barrier<_Sco, _CompF>& __barrier)
{
_CCCL_ASSERT(::cuda::__memcpy_async_check_pre(__destination, __source, __size), "memcpy_async preconditions unmet");
return ::cuda::__memcpy_async_barrier(__single_thread_group{}, __destination, __source, __size, __barrier);
}
template <typename _Group, class _Tp, thread_scope _Sco, typename _CompF>
_CCCL_HOST_DEVICE_API inline async_contract_fulfillment memcpy_async(
_Group const& __group,
_Tp* __destination,
_Tp const* __source,
::cuda::std::size_t __size,
barrier<_Sco, _CompF>& __barrier)
{
_CCCL_ASSERT(::cuda::__memcpy_async_check_pre(__destination, __source, __size), "memcpy_async preconditions unmet");
return ::cuda::__memcpy_async_barrier(__group, __destination, __source, __size, __barrier);
}
template <typename _Group, thread_scope _Sco, typename _CompF>
_CCCL_HOST_DEVICE_API inline async_contract_fulfillment memcpy_async(
_Group const& __group,
void* __destination,
void const* __source,
::cuda::std::size_t __size,
barrier<_Sco, _CompF>& __barrier)
{
_CCCL_ASSERT(::cuda::__memcpy_async_check_pre(__destination, __source, __size), "memcpy_async preconditions unmet");
return ::cuda::__memcpy_async_barrier(
__group, reinterpret_cast<char*>(__destination), reinterpret_cast<char const*>(__source), __size, __barrier);
}
template <typename _Group, ::cuda::std::size_t _Alignment, thread_scope _Sco, typename _CompF>
_CCCL_HOST_DEVICE_API inline async_contract_fulfillment memcpy_async(
_Group const& __group,
void* __destination,
void const* __source,
aligned_size_t<_Alignment> __size,
barrier<_Sco, _CompF>& __barrier)
{
_CCCL_ASSERT(::cuda::__memcpy_async_check_pre(__destination, __source, __size), "memcpy_async preconditions unmet");
return ::cuda::__memcpy_async_barrier(
__group, reinterpret_cast<char*>(__destination), reinterpret_cast<char const*>(__source), __size, __barrier);
}
template <typename _Size, thread_scope _Sco, typename _CompF>
_CCCL_HOST_DEVICE_API inline async_contract_fulfillment
memcpy_async(void* __destination, void const* __source, _Size __size, barrier<_Sco, _CompF>& __barrier)
{
_CCCL_ASSERT(::cuda::__memcpy_async_check_pre(__destination, __source, __size), "memcpy_async preconditions unmet");
return ::cuda::__memcpy_async_barrier(
__single_thread_group{},
reinterpret_cast<char*>(__destination),
reinterpret_cast<char const*>(__source),
__size,
__barrier);
}
_CCCL_END_NAMESPACE_CUDA
# include <cuda/std/__cccl/epilogue.h>
#endif // _CCCL_CUDA_COMPILATION()
#endif // _CUDA___MEMCPY_ASYNC_MEMCPY_ASYNC_H_

View File

@@ -0,0 +1,99 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of libcu++, the C++ Standard Library for your entire system,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#ifndef _CUDA___MEMCPY_ASYNC_MEMCPY_ASYNC_BARRIER_H_
#define _CUDA___MEMCPY_ASYNC_MEMCPY_ASYNC_BARRIER_H_
#include <cuda/std/detail/__config>
#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 <cuda/__barrier/barrier.h>
#include <cuda/__barrier/barrier_block_scope.h>
#include <cuda/__barrier/barrier_thread_scope.h>
#include <cuda/__memcpy_async/completion_mechanism.h>
#include <cuda/__memcpy_async/dispatch_memcpy_async.h>
#include <cuda/__memcpy_async/is_local_smem_barrier.h>
#include <cuda/__memcpy_async/memcpy_completion.h>
#include <cuda/__memcpy_async/try_get_barrier_handle.h>
#include <cuda/__memory/aligned_size.h>
#include <cuda/__type_traits/is_trivially_copyable.h>
#include <cuda/std/__algorithm/max.h>
#include <cuda/std/__atomic/scopes.h>
#include <cuda/std/cstddef>
#include <cuda/std/cstdint>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
struct __single_thread_group
{
_CCCL_HOST_DEVICE_API inline void sync() const {}
[[nodiscard]] _CCCL_HOST_DEVICE_API constexpr ::cuda::std::size_t size() const
{
return 1;
};
[[nodiscard]] _CCCL_HOST_DEVICE_API constexpr ::cuda::std::size_t thread_rank() const
{
return 0;
};
};
template <typename _Group, class _Tp, typename _Size, thread_scope _Sco, typename _CompF>
_CCCL_HOST_DEVICE_API inline async_contract_fulfillment __memcpy_async_barrier(
_Group const& __group, _Tp* __destination, _Tp const* __source, _Size __size, barrier<_Sco, _CompF>& __barrier)
{
static_assert(::cuda::is_trivially_copyable_v<_Tp>, "memcpy_async requires a trivially copyable type");
// 1. Determine which completion mechanisms can be used with the current
// barrier. A local shared memory barrier, i.e., block-scope barrier in local
// shared memory, supports the mbarrier_complete_tx mechanism in addition to
// the async group mechanism.
::cuda::std::uint32_t __allowed_completions =
::cuda::__is_local_smem_barrier(__barrier)
? (::cuda::std::uint32_t(__completion_mechanism::__async_group)
| ::cuda::std::uint32_t(__completion_mechanism::__mbarrier_complete_tx))
: ::cuda::std::uint32_t(__completion_mechanism::__async_group);
// Alignment: Use the maximum of the alignment of _Tp and that of a possible cuda::aligned_size_t.
constexpr auto __align = ::cuda::std::max(alignof(_Tp), __get_size_align_v<_Size>);
// Cast to char pointers. We don't need the type for alignment anymore and
// erasing the types reduces the number of instantiations of down-stream
// functions.
char* __dest_char = reinterpret_cast<char*>(__destination);
char const* __src_char = reinterpret_cast<char const*>(__source);
// 2. Issue actual copy instructions.
::cuda::std::uint64_t* __bh = nullptr;
#if __cccl_ptx_isa >= 800
NV_IF_TARGET(
NV_PROVIDES_SM_90,
(__bh = ::cuda::__is_local_smem_barrier(__barrier) ? ::cuda::__try_get_barrier_handle(__barrier) : nullptr;))
#endif // __cccl_ptx_isa >= 800
auto __cm =
::cuda::__dispatch_memcpy_async<__align>(__group, __dest_char, __src_char, __size, __allowed_completions, __bh);
// 3. Synchronize barrier with copy instructions.
return __memcpy_completion_impl::__defer(__cm, __group, __size, __barrier);
}
_CCCL_END_NAMESPACE_CUDA
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___MEMCPY_ASYNC_MEMCPY_ASYNC_BARRIER_H_

View File

@@ -0,0 +1,102 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of libcu++, the C++ Standard Library for your entire system,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#ifndef _CUDA___MEMCPY_ASYNC_MEMCPY_ASYNC_TX_H_
#define _CUDA___MEMCPY_ASYNC_MEMCPY_ASYNC_TX_H_
#include <cuda/std/detail/__config>
#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
#if _CCCL_CUDA_COMPILATION()
# if __cccl_ptx_isa >= 800
# include <cuda/__barrier/async_contract_fulfillment.h>
# include <cuda/__barrier/barrier_block_scope.h>
# include <cuda/__memcpy_async/check_preconditions.h>
# include <cuda/__memory/address_space.h>
# include <cuda/__memory/aligned_size.h>
# include <cuda/__ptx/instructions/cp_async_bulk.h>
# include <cuda/__ptx/ptx_dot_variants.h>
# include <cuda/__ptx/ptx_helper_functions.h>
# include <cuda/__type_traits/is_trivially_copyable.h>
# include <cuda/std/__atomic/scopes.h>
# include <cuda/std/__type_traits/conditional.h>
# include <cuda/std/cstdint>
# include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA_DEVICE
extern "C" _CCCL_DEVICE void __cuda_ptx_memcpy_async_tx_is_not_supported_before_SM_90__();
template <typename _Tp, ::cuda::std::size_t _Alignment>
_CCCL_DEVICE_API async_contract_fulfillment memcpy_async_tx(
_Tp* __dest,
const _Tp* __src,
::cuda::aligned_size_t<_Alignment> __size,
::cuda::barrier<::cuda::thread_scope_block>& __b)
{
// When compiling with NVCC and GCC 4.8, certain user defined types that _are_ trivially copyable are
// incorrectly classified as not trivially copyable. Remove this assertion to allow for their usage with
// memcpy_async when compiling with GCC 4.8.
// FIXME: remove the #if once GCC 4.8 is no longer supported.
# if !_CCCL_COMPILER(GCC) || _CCCL_COMPILER(GCC, >, 4, 8)
static_assert(::cuda::is_trivially_copyable_v<_Tp>, "memcpy_async_tx requires a trivially copyable type");
# endif
static_assert(16 <= _Alignment, "mempcy_async_tx expects arguments to be at least 16 byte aligned.");
static_assert(_Alignment >= alignof(_Tp), "alignment must be at least the alignof(T)");
_CCCL_ASSERT(::cuda::__memcpy_async_check_pre(__dest, __src, __size), "memcpy_async_tx preconditions unmet");
_CCCL_ASSERT(
::cuda::device::is_address_from(::cuda::device::barrier_native_handle(__b), ::cuda::device::address_space::shared),
"Barrier must be located in local shared memory.");
_CCCL_ASSERT(::cuda::device::is_address_from(__dest, ::cuda::device::address_space::shared),
"dest must point to shared memory.");
_CCCL_ASSERT(::cuda::device::is_address_from(__src, ::cuda::device::address_space::global),
"src must point to global memory.");
NV_IF_ELSE_TARGET(
NV_PROVIDES_SM_90,
(
if (::cuda::device::is_address_from(__dest, ::cuda::device::address_space::shared)
&& ::cuda::device::is_address_from(__src, ::cuda::device::address_space::global)) {
::cuda::ptx::cp_async_bulk(
::cuda::std::conditional_t<__cccl_ptx_isa >= 860, ::cuda::ptx::space_shared_t, ::cuda::ptx::space_cluster_t>{},
::cuda::ptx::space_global,
__dest,
__src,
static_cast<uint32_t>(__size),
::cuda::device::barrier_native_handle(__b));
} else {
_CCCL_VERIFY(false,
"memcpy_async_tx only supports copying from global to shared or from shared to remote cluster "
"dsmem. To copy to remote is not yet implemented.");
}),
(::cuda::device::__cuda_ptx_memcpy_async_tx_is_not_supported_before_SM_90__();));
return async_contract_fulfillment::async;
}
_CCCL_END_NAMESPACE_CUDA_DEVICE
# include <cuda/std/__cccl/epilogue.h>
# endif // __cccl_ptx_isa >= 800
#endif // _CCCL_CUDA_COMPILATION()
#endif // _CUDA___MEMCPY_ASYNC_MEMCPY_ASYNC_TX_H_

View File

@@ -0,0 +1,164 @@
//===----------------------------------------------------------------------===//
//
// Part of libcu++, the C++ Standard Library for your entire system,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#ifndef _CUDA___MEMCPY_ASYNC_MEMCPY_COMPLETION_H
#define _CUDA___MEMCPY_ASYNC_MEMCPY_COMPLETION_H
#include <cuda/std/detail/__config>
#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 <cuda/__barrier/async_contract_fulfillment.h>
#include <cuda/__barrier/barrier_block_scope.h>
#include <cuda/__barrier/barrier_expect_tx.h>
#include <cuda/__fwd/pipeline.h>
#include <cuda/__memcpy_async/completion_mechanism.h>
#include <cuda/__memcpy_async/is_local_smem_barrier.h>
#include <cuda/__memcpy_async/try_get_barrier_handle.h>
#include <cuda/std/__atomic/scopes.h>
#include <cuda/std/cstdint>
#if _CCCL_CUDA_COMPILATION()
# include <cuda/__ptx/ptx_dot_variants.h>
# include <cuda/__ptx/ptx_helper_functions.h>
#endif // _CCCL_CUDA_COMPILATION()
#include <nv/target>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
// This struct contains functions to defer the completion of a barrier phase
// or pipeline stage until a specific memcpy_async operation *initiated by
// this thread* has completed.
// The user is still responsible for arriving and waiting on (or otherwise
// synchronizing with) the barrier or pipeline barrier to see the results of
// copies from other threads participating in the synchronization object.
struct __memcpy_completion_impl
{
template <typename _Group>
[[nodiscard]] _CCCL_HOST_DEVICE_API inline static async_contract_fulfillment
__defer(__completion_mechanism __cm,
_Group const& __group,
::cuda::std::size_t __size,
barrier<::cuda::thread_scope_block>& __barrier)
{
// In principle, this is the overload for shared memory barriers. However, a
// block-scope barrier may also be located in global memory. Therefore, we
// check if the barrier is a non-smem barrier and handle that separately.
if (!::cuda::__is_local_smem_barrier(__barrier))
{
return __defer_non_smem_barrier(__cm, __group, __size, __barrier);
}
switch (__cm)
{
case __completion_mechanism::__async_group:
// Pre-SM80, the async_group mechanism is not available.
NV_IF_TARGET(
NV_PROVIDES_SM_80,
(
// Non-Blocking: unbalance barrier by 1, barrier will be
// rebalanced when all thread-local cp.async instructions
// have completed writing to shared memory.
::cuda::std::uint64_t* __bh = ::cuda::__try_get_barrier_handle(__barrier);
asm volatile("cp.async.mbarrier.arrive.shared.b64 [%0];" ::"r"(
static_cast<::cuda::std::uint32_t>(::__cvta_generic_to_shared(__bh))) : "memory");));
return async_contract_fulfillment::async;
case __completion_mechanism::__async_bulk_group:
// This completion mechanism should not be used with a shared
// memory barrier. Or at least, we do not currently envision
// bulk group to be used with shared memory barriers.
_CCCL_UNREACHABLE();
case __completion_mechanism::__mbarrier_complete_tx:
// we already updated the mbarrier's tx count when we issued the bulk copy
return async_contract_fulfillment::async;
case __completion_mechanism::__sync:
// sync: In this case, we do not need to do anything. The user will have
// to issue `bar.arrive_wait();` to see the effect of the transaction.
return async_contract_fulfillment::none;
default:
// Get rid of "control reaches end of non-void function":
_CCCL_UNREACHABLE();
}
}
template <typename _Group, thread_scope _Sco, typename _CompF>
[[nodiscard]] _CCCL_HOST_DEVICE_API inline static async_contract_fulfillment __defer(
__completion_mechanism __cm, _Group const& __group, ::cuda::std::size_t __size, barrier<_Sco, _CompF>& __barrier)
{
return __defer_non_smem_barrier(__cm, __group, __size, __barrier);
}
template <typename _Group, thread_scope _Sco, typename _CompF>
[[nodiscard]] _CCCL_HOST_DEVICE_API inline static async_contract_fulfillment
__defer_non_smem_barrier(__completion_mechanism __cm, _Group const&, ::cuda::std::size_t, barrier<_Sco, _CompF>&)
{
// Overload for non-smem barriers.
switch (__cm)
{
case __completion_mechanism::__async_group:
// Pre-SM80, the async_group mechanism is not available.
NV_IF_TARGET(NV_PROVIDES_SM_80,
(
// Blocking: wait for all thread-local cp.async instructions to have
// completed writing to shared memory.
asm volatile("cp.async.wait_all;" :: : "memory");));
return async_contract_fulfillment::async;
case __completion_mechanism::__async_bulk_group:
[[fallthrough]];
// This completion mechanism is currently not expected to be used with barriers.
case __completion_mechanism::__mbarrier_complete_tx:
// Non-smem barriers do not have an mbarrier_complete_tx mechanism.
_CCCL_UNREACHABLE();
case __completion_mechanism::__sync:
// sync: In this case, we do not need to do anything.
return async_contract_fulfillment::none;
default:
// Get rid of "control reaches end of non-void function":
_CCCL_UNREACHABLE();
}
}
template <typename _Group, thread_scope _Sco>
[[nodiscard]] _CCCL_HOST_DEVICE_API inline static async_contract_fulfillment
__defer(__completion_mechanism __cm, _Group const&, ::cuda::std::size_t, pipeline<_Sco>&)
{
switch (__cm)
{
case __completion_mechanism::__async_group:
[[fallthrough]];
case __completion_mechanism::__async_bulk_group:
[[fallthrough]];
case __completion_mechanism::__mbarrier_complete_tx:
return async_contract_fulfillment::async;
case __completion_mechanism::__sync:
return async_contract_fulfillment::none;
default:
// Get rid of "control reaches end of non-void function":
_CCCL_UNREACHABLE();
}
}
};
_CCCL_END_NAMESPACE_CUDA
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___MEMCPY_ASYNC_MEMCPY_COMPLETION_H

View File

@@ -0,0 +1,57 @@
//===----------------------------------------------------------------------===//
//
// Part of libcu++, the C++ Standard Library for your entire system,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#ifndef _CUDA___MEMCPY_ASYNC_TRY_GET_BARRIER_HANDLE_H
#define _CUDA___MEMCPY_ASYNC_TRY_GET_BARRIER_HANDLE_H
#include <cuda/std/detail/__config>
#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 <cuda/__barrier/barrier_block_scope.h>
#include <cuda/std/__atomic/scopes.h>
#include <cuda/std/__barrier/barrier.h>
#include <cuda/std/__barrier/empty_completion.h>
#include <cuda/std/__type_traits/is_same.h>
#include <cuda/std/cstdint>
#include <nv/target>
#include <cuda/std/__cccl/prologue.h>
_CCCL_BEGIN_NAMESPACE_CUDA
//! @brief __try_get_barrier_handle returns barrier handle of block-scoped barriers and a nullptr otherwise.
template <thread_scope _Sco, typename _CompF>
_CCCL_HOST_DEVICE_API inline ::cuda::std::uint64_t* __try_get_barrier_handle(barrier<_Sco, _CompF>&)
{
return nullptr;
}
template <>
_CCCL_HOST_DEVICE_API inline ::cuda::std::uint64_t*
__try_get_barrier_handle<::cuda::thread_scope_block, ::cuda::std::__empty_completion>(
[[maybe_unused]] barrier<thread_scope_block>& __barrier)
{
NV_DISPATCH_TARGET(
NV_IS_DEVICE, (return ::cuda::device::barrier_native_handle(__barrier);), NV_ANY_TARGET, (return nullptr;));
}
_CCCL_END_NAMESPACE_CUDA
#include <cuda/std/__cccl/epilogue.h>
#endif // _CUDA___MEMCPY_ASYNC_TRY_GET_BARRIER_HANDLE_H