Skip to content

Commit

Permalink
add _LIBCUDACXX_REQUIRES_EXPR to the concepts emulation macros (NVI…
Browse files Browse the repository at this point in the history
…DIA#2564)

* add `_LIBCUDACXX_REQUIRES_EXPR` to the concepts emulation macros

* work around nvcc pre-12.2 bug and molify nvrtc

* silence warning about an always true condition

* simplify macro substitution with the help of an alias template

* fix the short-circuiting behavior of the `async_resource` concept pre-c++20

* replace C-style casts with C++-style `static_cast`s

* add missing `_LIBCUDACXX_HIDE_FROM_ABI` function annotations

* restore short-circuiting in the `resource` concept
  • Loading branch information
ericniebler authored Oct 16, 2024
1 parent 8ecb3c1 commit 29ecb1e
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 18 deletions.
28 changes: 10 additions & 18 deletions libcudacxx/include/cuda/__memory_resource/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,6 @@

_LIBCUDACXX_BEGIN_NAMESPACE_CUDA_MR

template <class _Resource>
_LIBCUDACXX_CONCEPT_FRAGMENT(
__resource_,
requires(_Resource& __res, void* __ptr, size_t __bytes, size_t __alignment)(
requires(_CUDA_VSTD::same_as<void*, decltype(__res.allocate(__bytes, __alignment))>),
requires(_CUDA_VSTD::same_as<void, decltype(__res.deallocate(__ptr, __bytes, __alignment))>),
requires(_CUDA_VSTD::equality_comparable<_Resource>)));

//! @brief The \c resource concept verifies that a type Resource satisfies the basic requirements of a memory
//! resource
//! @rst
Expand All @@ -57,15 +49,11 @@ _LIBCUDACXX_CONCEPT_FRAGMENT(
//! @endrst
//! @tparam _Resource The type that should implement the resource concept
template <class _Resource>
_LIBCUDACXX_CONCEPT resource = _LIBCUDACXX_FRAGMENT(__resource_, _Resource);

template <class _Resource>
_LIBCUDACXX_CONCEPT_FRAGMENT(
__async_resource_,
requires(_Resource& __res, void* __ptr, size_t __bytes, size_t __alignment, ::cuda::stream_ref __stream)(
requires(resource<_Resource>),
requires(_CUDA_VSTD::same_as<void*, decltype(__res.allocate_async(__bytes, __alignment, __stream))>),
requires(_CUDA_VSTD::same_as<void, decltype(__res.deallocate_async(__ptr, __bytes, __alignment, __stream))>)));
_LIBCUDACXX_CONCEPT resource =
_LIBCUDACXX_REQUIRES_EXPR((_Resource), _Resource& __res, void* __ptr, size_t __bytes, size_t __alignment)(
requires(_CUDA_VSTD::equality_comparable<_Resource>),
_Same_as(void*) __res.allocate(__bytes, __alignment), //
_Same_as(void) __res.deallocate(__ptr, __bytes, __alignment));

//! @brief The \c async_resource concept verifies that a type Resource satisfies the basic requirements of a
//! memory resource and additionally supports stream ordered allocations
Expand All @@ -83,7 +71,11 @@ _LIBCUDACXX_CONCEPT_FRAGMENT(
//! @endrst
//! @tparam _Resource The type that should implement the async resource concept
template <class _Resource>
_LIBCUDACXX_CONCEPT async_resource = _LIBCUDACXX_FRAGMENT(__async_resource_, _Resource);
_LIBCUDACXX_CONCEPT async_resource = _LIBCUDACXX_REQUIRES_EXPR(
(_Resource), _Resource& __res, void* __ptr, size_t __bytes, size_t __alignment, ::cuda::stream_ref __stream)(
requires(resource<_Resource>),
_Same_as(void*) __res.allocate_async(__bytes, __alignment, __stream),
_Same_as(void) __res.deallocate_async(__ptr, __bytes, __alignment, __stream));

//! @brief The \c resource_with concept verifies that a type Resource satisfies the `resource` concept and
//! also satisfies all the provided Properties
Expand Down
107 changes: 107 additions & 0 deletions libcudacxx/include/cuda/std/__concepts/__concept_macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@
# define _LIBCUDACXX_PP_IIF_1(_TRUE, ...) _TRUE

# define _LIBCUDACXX_PP_LPAREN (
# define _LIBCUDACXX_PP_RPAREN )

# define _LIBCUDACXX_PP_NOT(_BIT) _LIBCUDACXX_PP_CAT_(_LIBCUDACXX_PP_NOT_, _BIT)
# define _LIBCUDACXX_PP_NOT_0 1
Expand Down Expand Up @@ -220,11 +221,13 @@
# define _LIBCUDACXX_CONCEPT_FRAGMENT_REQS_SELECT_PROBE_requires _LIBCUDACXX_PP_PROBE_N(~, 1)
# define _LIBCUDACXX_CONCEPT_FRAGMENT_REQS_SELECT_PROBE_noexcept _LIBCUDACXX_PP_PROBE_N(~, 2)
# define _LIBCUDACXX_CONCEPT_FRAGMENT_REQS_SELECT_PROBE_typename _LIBCUDACXX_PP_PROBE_N(~, 3)
# define _LIBCUDACXX_CONCEPT_FRAGMENT_REQS_SELECT_PROBE__Same_as _LIBCUDACXX_PP_PROBE_N(~, 4)

# define _LIBCUDACXX_CONCEPT_FRAGMENT_REQS_SELECT_0 _LIBCUDACXX_PP_EXPAND
# define _LIBCUDACXX_CONCEPT_FRAGMENT_REQS_SELECT_1 _LIBCUDACXX_CONCEPT_FRAGMENT_REQS_REQUIRES_OR_NOEXCEPT
# define _LIBCUDACXX_CONCEPT_FRAGMENT_REQS_SELECT_2 _LIBCUDACXX_CONCEPT_FRAGMENT_REQS_REQUIRES_OR_NOEXCEPT
# define _LIBCUDACXX_CONCEPT_FRAGMENT_REQS_SELECT_3 _LIBCUDACXX_CONCEPT_FRAGMENT_REQS_REQUIRES_OR_NOEXCEPT
# define _LIBCUDACXX_CONCEPT_FRAGMENT_REQS_SELECT_4 _LIBCUDACXX_CONCEPT_FRAGMENT_REQS_SAME_AS
# define _LIBCUDACXX_CONCEPT_FRAGMENT_REQS_REQUIRES_OR_NOEXCEPT(_REQ) \
_LIBCUDACXX_PP_CAT4(_LIBCUDACXX_CONCEPT_FRAGMENT_REQS_REQUIRES_, _REQ)
# define _LIBCUDACXX_PP_EAT_TYPENAME_PROBE_typename _LIBCUDACXX_PP_PROBE(~)
Expand Down Expand Up @@ -255,6 +258,15 @@
{ \
__VA_ARGS__ \
} noexcept
# define _LIBCUDACXX_CONCEPT_FRAGMENT_REQS_SAME_AS(_REQ) \
{ \
_LIBCUDACXX_PP_CAT4(_LIBCUDACXX_PP_EAT_SAME_AS_, _REQ) \
} -> _LIBCUDACXX_CONCEPT_VSTD::same_as<_LIBCUDACXX_PP_EVAL( \
_LIBCUDACXX_CONCEPT_FRAGMENT_REQS_SAME_AS_AUX, \
_LIBCUDACXX_PP_CAT4(_LIBCUDACXX_CONCEPT_FRAGMENT_REQS_SAME_AS_, _REQ))>
# define _LIBCUDACXX_PP_EAT_SAME_AS__Same_as(...)
# define _LIBCUDACXX_CONCEPT_FRAGMENT_REQS_SAME_AS_AUX(_TYPE, ...) _LIBCUDACXX_PP_EXPAND _TYPE
# define _LIBCUDACXX_CONCEPT_FRAGMENT_REQS_SAME_AS__Same_as(...) (__VA_ARGS__),

# define _LIBCUDACXX_FRAGMENT(_NAME, ...) _NAME<__VA_ARGS__>

Expand Down Expand Up @@ -294,6 +306,10 @@
# else
# define _LIBCUDACXX_CONCEPT_FRAGMENT_REQS_REQUIRES_noexcept(...) _Concept::_Requires<noexcept(__VA_ARGS__)>
# endif
# define _LIBCUDACXX_CONCEPT_FRAGMENT_REQS_SAME_AS(_REQ) \
_Concept::_Requires<_CUDA_VSTD::same_as<_LIBCUDACXX_PP_CAT4( \
_LIBCUDACXX_CONCEPT_FRAGMENT_REQS_SAME_AS_, _REQ) _LIBCUDACXX_PP_RPAREN>>
# define _LIBCUDACXX_CONCEPT_FRAGMENT_REQS_SAME_AS__Same_as(...) __VA_ARGS__, decltype _LIBCUDACXX_PP_LPAREN

# define _LIBCUDACXX_FRAGMENT(_NAME, ...) \
(1u == sizeof(_NAME##_LIBCUDACXX_CONCEPT_FRAGMENT_(static_cast<_Concept::_Tag<__VA_ARGS__>*>(nullptr), nullptr)))
Expand Down Expand Up @@ -323,6 +339,74 @@
# define _LIBCUDACXX_TRAILING_REQUIRES(...) ->_Concept::_Requires_t < __VA_ARGS__ _LIBCUDACXX_TRAILING_REQUIRES_AUX_
# endif

////////////////////////////////////////////////////////////////////////////////
// _LIBCUDACXX_REQUIRES_EXPR
// Usage:
// template <typename T>
// _LIBCUDACXX_CONCEPT equality_comparable =
// _LIBCUDACXX_REQUIRES_EXPR((T), T const& lhs, T const& rhs) (
// lhs == rhs,
// lhs != rhs
// );
//
// Can only be used as the last requirement in a concept definition.
# if defined(__cpp_concepts) && _CCCL_STD_VER >= 2020
# define _LIBCUDACXX_REQUIRES_EXPR(_TY, ...) requires(__VA_ARGS__) _LIBCUDACXX_REQUIRES_EXPR_2
# define _LIBCUDACXX_REQUIRES_EXPR_2(...) {_LIBCUDACXX_PP_FOR_EACH(_LIBCUDACXX_CONCEPT_FRAGMENT_REQS_M, __VA_ARGS__)}
# else
# define _LIBCUDACXX_REQUIRES_EXPR_TPARAM_PROBE_variadic _LIBCUDACXX_PP_PROBE(~)
# define _LIBCUDACXX_REQUIRES_EXPR_TPARAM_variadic

# define _LIBCUDACXX_REQUIRES_EXPR_DEF_TPARAM(_TY) \
, _LIBCUDACXX_PP_CAT(_LIBCUDACXX_REQUIRES_EXPR_DEF_TPARAM_, \
_LIBCUDACXX_PP_EVAL(_LIBCUDACXX_PP_CHECK, \
_LIBCUDACXX_PP_CAT(_LIBCUDACXX_REQUIRES_EXPR_TPARAM_PROBE_, _TY)))(_TY)
# define _LIBCUDACXX_REQUIRES_EXPR_DEF_TPARAM_0(_TY) class _TY
# define _LIBCUDACXX_REQUIRES_EXPR_DEF_TPARAM_1(_TY) \
class... _LIBCUDACXX_PP_CAT(_LIBCUDACXX_REQUIRES_EXPR_TPARAM_, _TY)

# define _LIBCUDACXX_REQUIRES_EXPR_EXPAND_TPARAM(_TY) \
, _LIBCUDACXX_PP_CAT(_LIBCUDACXX_REQUIRES_EXPR_EXPAND_TPARAM_, \
_LIBCUDACXX_PP_EVAL(_LIBCUDACXX_PP_CHECK, \
_LIBCUDACXX_PP_CAT(_LIBCUDACXX_REQUIRES_EXPR_TPARAM_PROBE_, _TY)))(_TY)
# define _LIBCUDACXX_REQUIRES_EXPR_EXPAND_TPARAM_0(_TY) _TY
# define _LIBCUDACXX_REQUIRES_EXPR_EXPAND_TPARAM_1(_TY) _LIBCUDACXX_PP_CAT(_LIBCUDACXX_REQUIRES_EXPR_TPARAM_, _TY)...

# define _LIBCUDACXX_REQUIRES_EXPR_TPARAMS(...) \
_LIBCUDACXX_PP_FOR_EACH(_LIBCUDACXX_REQUIRES_EXPR_DEF_TPARAM, __VA_ARGS__)

# define _LIBCUDACXX_REQUIRES_EXPR_EXPAND_TPARAMS(...) \
_LIBCUDACXX_PP_FOR_EACH(_LIBCUDACXX_REQUIRES_EXPR_EXPAND_TPARAM, __VA_ARGS__)

# define _LIBCUDACXX_REQUIRES_EXPR(_TY, ...) \
_Concept::_Requires_expr_impl<struct _LIBCUDACXX_PP_CAT(_Libcudacxx_requires_expr_detail_, __LINE__) \
_LIBCUDACXX_REQUIRES_EXPR_EXPAND_TPARAMS _TY>:: \
_Is_satisfied(static_cast<_Concept::_Tag<void _LIBCUDACXX_REQUIRES_EXPR_EXPAND_TPARAMS _TY>*>(nullptr), \
static_cast<void (*)(__VA_ARGS__)>(nullptr)); \
struct _LIBCUDACXX_PP_CAT(_Libcudacxx_requires_expr_detail_, __LINE__) \
{ \
using _Self_t = _LIBCUDACXX_PP_CAT(_Libcudacxx_requires_expr_detail_, __LINE__); \
template <class _LIBCUDACXX_REQUIRES_EXPR_TPARAMS _TY> \
_LIBCUDACXX_HIDE_FROM_ABI static auto _Well_formed(__VA_ARGS__) _LIBCUDACXX_REQUIRES_EXPR_2

# define _LIBCUDACXX_REQUIRES_EXPR_2(...) \
->decltype(_LIBCUDACXX_PP_FOR_EACH(_LIBCUDACXX_CONCEPT_FRAGMENT_REQS_M, __VA_ARGS__) void()) {} \
template <class... Args, class Sig, class = decltype(static_cast<Sig*>(&_Self_t::_Well_formed<Args...>))> \
_LIBCUDACXX_HIDE_FROM_ABI static constexpr bool _Is_satisfied(_Concept::_Tag<Args...>*, Sig*) \
{ \
return true; \
} \
_LIBCUDACXX_HIDE_FROM_ABI static constexpr bool _Is_satisfied(void*, ...) \
{ \
return false; \
} \
}
# endif

// So that we can refer to the ::cuda::std namespace below
_LIBCUDACXX_BEGIN_NAMESPACE_STD
_LIBCUDACXX_END_NAMESPACE_STD

namespace _Concept
{
template <bool>
Expand All @@ -344,6 +428,7 @@ using _Requires_t = typename _Select<_Bp>::template type<_Tp>;

template <typename...>
struct _Tag;

template <class>
_LIBCUDACXX_HIDE_FROM_ABI constexpr bool _Is_true()
{
Expand All @@ -358,6 +443,28 @@ _LIBCUDACXX_HIDE_FROM_ABI _Concept::_Enable_if_t<_Bp> _Requires()
template <bool _Bp, _Concept::_Enable_if_t<_Bp, int> = 0>
_CCCL_INLINE_VAR constexpr int _Requires = 0;
# endif

template <class _Tp, class... _Args>
_LIBCUDACXX_HIDE_FROM_ABI auto _Make_dependent(_Tp*, _Tag<_Args...>*) -> _Tp;

template <class _Impl, class... _Args>
using _Requires_expr_impl = //
decltype(_Concept::_Make_dependent(static_cast<_Impl*>(nullptr), static_cast<_Tag<void, _Args...>*>(nullptr)));

// We put an alias for _CUDA_VSTD here because of a bug in nvcc <12.2
// where a requirement such as:
//
// { expression } -> ::concept<type>
//
// where ::concept is a fully qualified name, would not compile. The
// _CUDA_VSTD macro is fully qualified.
namespace _Vstd = _CUDA_VSTD; // NOLINT(misc-unused-alias-decls)

# if defined(_CCCL_CUDACC_BELOW_12_2)
# define _LIBCUDACXX_CONCEPT_VSTD _Concept::_Vstd // must not be fully qualified
# else
# define _LIBCUDACXX_CONCEPT_VSTD _CUDA_VSTD
# endif
} // namespace _Concept

#endif // _CCCL_STD_VER > 2011
Expand Down

0 comments on commit 29ecb1e

Please sign in to comment.