Skip to content

Commit

Permalink
Enable internal use of std::allocator related functionality (#1583)
Browse files Browse the repository at this point in the history
* Move `algin` into its own file

* Move `uses_allocator` to their own file

* Move `allocator_traits` into their own file

* Add `__allocation_guard` helper

* Move `allocator_arg_t` into tis own file

* Move `__allocator_destructor` into its own file

* Implement `allocate_at_least`

* Move `allocator` to its own file
  • Loading branch information
miscco committed Apr 13, 2024
1 parent 1f87d3d commit 4da34c6
Show file tree
Hide file tree
Showing 58 changed files with 4,829 additions and 1,430 deletions.
38 changes: 24 additions & 14 deletions libcudacxx/include/cuda/std/detail/libcxx/include/__config
Original file line number Diff line number Diff line change
Expand Up @@ -1623,23 +1623,24 @@ typedef unsigned int char32_t;
# endif
#endif // defined(__APPLE__)

#if !defined(_LIBCUDACXX_HAS_NO_ALIGNED_ALLOCATION) && \
(defined(_LIBCUDACXX_HAS_NO_LIBRARY_ALIGNED_ALLOCATION) || \
(!defined(__cpp_aligned_new) || __cpp_aligned_new < 201606))
# define _LIBCUDACXX_HAS_NO_ALIGNED_ALLOCATION
#endif
# if !defined(_LIBCUDACXX_HAS_NO_ALIGNED_ALLOCATION) \
&& (defined(_LIBCUDACXX_HAS_NO_LIBRARY_ALIGNED_ALLOCATION) \
|| (!defined(__cpp_aligned_new) || __cpp_aligned_new < 201606)) \
|| defined(__cuda_std__) // FIXME: Properly handle aligned allocations
# define _LIBCUDACXX_HAS_NO_ALIGNED_ALLOCATION
# endif

#if defined(__APPLE__) || defined(__FreeBSD__)
#define _LIBCUDACXX_HAS_DEFAULTRUNELOCALE
#endif
# if defined(__APPLE__) || defined(__FreeBSD__)
# define _LIBCUDACXX_HAS_DEFAULTRUNELOCALE
# endif

#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__sun__)
#define _LIBCUDACXX_WCTYPE_IS_MASK
#endif
# if defined(__APPLE__) || defined(__FreeBSD__) || defined(__sun__)
# define _LIBCUDACXX_WCTYPE_IS_MASK
# endif

#if _CCCL_STD_VER <= 2017 || !defined(__cpp_char8_t)
#define _LIBCUDACXX_NO_HAS_CHAR8_T
#endif
# if _CCCL_STD_VER <= 2017 || !defined(__cpp_char8_t)
# define _LIBCUDACXX_NO_HAS_CHAR8_T
# endif

// Deprecation macros.
//
Expand Down Expand Up @@ -2156,6 +2157,15 @@ extern "C" _LIBCUDACXX_FUNC_VIS void __sanitizer_annotate_contiguous_container(
_CUDA_VSTD::__construct_at(_CUDA_VSTD::addressof(_LOCATION), __VA_ARGS__)
#endif

// We can only expose constexpr allocations if the compiler supports it
# if defined(__cpp_constexpr_dynamic_alloc) && defined(__cpp_lib_constexpr_dynamic_alloc) && _CCCL_STD_VER >= 2020 \
&& !defined(_CCCL_COMPILER_NVRTC)
# define _CCCL_HAS_CONSTEXPR_ALLOCATION
# define _CCCL_CONSTEXPR_CXX20_ALLOCATION constexpr
# else // ^^^ __cpp_constexpr_dynamic_alloc ^^^ / vvv !__cpp_constexpr_dynamic_alloc vvv
# define _CCCL_CONSTEXPR_CXX20_ALLOCATION
# endif

// NVRTC has a bug that prevented the use of delegated constructors, as it did not accept execution space annotations.
// This creates a whole lot of boilerplate that we can avoid through a macro (see nvbug3961621)
# if defined(_CCCL_COMPILER_NVRTC) || (defined(_LIBCUDACXX_CUDACC_BELOW_11_3) && defined(_CCCL_COMPILER_CLANG))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#include <cuda/std/detail/libcxx/include/__functional/reference_wrapper.h>
#include <cuda/std/detail/libcxx/include/__functional/unary_function.h>
#include <cuda/std/detail/libcxx/include/__functional/weak_result_type.h>
#include <cuda/std/detail/libcxx/include/__memory/allocator_arg_t.h>
#include <cuda/std/detail/libcxx/include/__memory/uses_allocator.h>
#include <cuda/std/detail/libcxx/include/__type_traits/integral_constant.h>
#include <cuda/std/detail/libcxx/include/__type_traits/is_constructible.h>
#include <cuda/std/detail/libcxx/include/__type_traits/is_convertible.h>
Expand All @@ -37,93 +39,6 @@

_LIBCUDACXX_BEGIN_NAMESPACE_STD

// allocator_arg_t

struct _LIBCUDACXX_TEMPLATE_VIS allocator_arg_t { explicit allocator_arg_t() = default; };

#if defined(_LIBCUDACXX_BUILDING_LIBRARY)
extern _LIBCUDACXX_EXPORTED_FROM_ABI const allocator_arg_t allocator_arg;
#else
/* _LIBCUDACXX_INLINE_VAR */ constexpr allocator_arg_t allocator_arg = allocator_arg_t();
#endif

// uses_allocator

template <class _Tp>
struct __has_allocator_type
{
private:
struct __two {char __lx; char __lxx;};
template <class _Up> _LIBCUDACXX_INLINE_VISIBILITY static __two __test(...);
template <class _Up> _LIBCUDACXX_INLINE_VISIBILITY static char __test(typename _Up::allocator_type* = 0);
public:
static const bool value = sizeof(__test<_Tp>(0)) == 1;
};

template <class _Tp, class _Alloc, bool = __has_allocator_type<_Tp>::value>
struct __uses_allocator
: public integral_constant<bool,
is_convertible<_Alloc, typename _Tp::allocator_type>::value>
{
};

template <class _Tp, class _Alloc>
struct __uses_allocator<_Tp, _Alloc, false>
: public false_type
{
};

template <class _Tp, class _Alloc>
struct _LIBCUDACXX_TEMPLATE_VIS uses_allocator
: public __uses_allocator<_Tp, _Alloc>
{
};

#if _CCCL_STD_VER > 2014
template <class _Tp, class _Alloc>
_LIBCUDACXX_INLINE_VAR constexpr size_t uses_allocator_v = uses_allocator<_Tp, _Alloc>::value;
#endif

// allocator construction

template <class _Tp, class _Alloc, class ..._Args>
struct __uses_alloc_ctor_imp
{
typedef _LIBCUDACXX_NODEBUG_TYPE __remove_cvref_t<_Alloc> _RawAlloc;
static const bool __ua = uses_allocator<_Tp, _RawAlloc>::value;
static const bool __ic =
is_constructible<_Tp, allocator_arg_t, _Alloc, _Args...>::value;
static const int value = __ua ? 2 - __ic : 0;
};

template <class _Tp, class _Alloc, class ..._Args>
struct __uses_alloc_ctor
: integral_constant<int, __uses_alloc_ctor_imp<_Tp, _Alloc, _Args...>::value>
{};

template <class _Tp, class _Allocator, class... _Args>
inline _LIBCUDACXX_INLINE_VISIBILITY
void __user_alloc_construct_impl (integral_constant<int, 0>, _Tp *__storage, const _Allocator &, _Args &&... __args )
{
new (__storage) _Tp (_CUDA_VSTD::forward<_Args>(__args)...);
}

// FIXME: This should have a version which takes a non-const alloc.
template <class _Tp, class _Allocator, class... _Args>
inline _LIBCUDACXX_INLINE_VISIBILITY
void __user_alloc_construct_impl (integral_constant<int, 1>, _Tp *__storage, const _Allocator &__a, _Args &&... __args )
{
new (__storage) _Tp (allocator_arg, __a, _CUDA_VSTD::forward<_Args>(__args)...);
}

// FIXME: This should have a version which takes a non-const alloc.
template <class _Tp, class _Allocator, class... _Args>
inline _LIBCUDACXX_INLINE_VISIBILITY
void __user_alloc_construct_impl (integral_constant<int, 2>, _Tp *__storage, const _Allocator &__a, _Args &&... __args )
{
new (__storage) _Tp (_CUDA_VSTD::forward<_Args>(__args)..., __a);
}

_LIBCUDACXX_END_NAMESPACE_STD

#include <cuda/std/detail/libcxx/include/__pragma_pop>
Expand Down
55 changes: 55 additions & 0 deletions libcudacxx/include/cuda/std/detail/libcxx/include/__memory/align.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// -*- 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 _LIBCUDACXX___MEMORY_ALIGN_H
#define _LIBCUDACXX___MEMORY_ALIGN_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 <cuda/std/cstdint>

_CCCL_DIAG_PUSH
_CCCL_DIAG_SUPPRESS_MSVC(4146) // unary minus operator applied to unsigned type, result still unsigned

_LIBCUDACXX_BEGIN_NAMESPACE_STD

inline _LIBCUDACXX_INLINE_VISIBILITY void* align(size_t __alignment, size_t __size, void*& __ptr, size_t& __space)
{
if (__space < __size)
{
return nullptr;
}

const auto __intptr = reinterpret_cast<uintptr_t>(__ptr);
const auto __aligned = (__intptr - 1u + __alignment) & -__alignment;
const auto __diff = __aligned - __intptr;
if (__diff > (__space - __size))
{
return nullptr;
}
__space -= __diff;
return __ptr = reinterpret_cast<void*>(__aligned);
}

_LIBCUDACXX_END_NAMESPACE_STD

_CCCL_DIAG_POP

#endif // _LIBCUDACXX___MEMORY_ALIGN_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// -*- 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 _LIBCUDACXX___MEMORY_ALLOCATE_AT_LEAST_H
#define _LIBCUDACXX___MEMORY_ALLOCATE_AT_LEAST_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 <cuda/std/detail/libcxx/include/__memory/allocator_traits.h>

_LIBCUDACXX_BEGIN_NAMESPACE_STD

#if _CCCL_STD_VER >= 2023
template <class _Pointer>
struct allocation_result
{
_Pointer ptr;
size_t count;
};
_LIBCUDACXX_CTAD_SUPPORTED_FOR_TYPE(allocation_result);

template <class _Alloc>
_LIBCUDACXX_NODISCARD_ATTRIBUTE _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr allocation_result<
typename allocator_traits<_Alloc>::pointer>
allocate_at_least(_Alloc& __alloc, size_t __n)
{
if constexpr (requires { __alloc.allocate_at_least(__n); })
{
return __alloc.allocate_at_least(__n);
}
else
{
return {__alloc.allocate(__n), __n};
}
}

template <class _Alloc>
_LIBCUDACXX_NODISCARD_ATTRIBUTE _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr auto
__allocate_at_least(_Alloc& __alloc, size_t __n)
{
return _CUDA_VSTD::allocate_at_least(__alloc, __n);
}
#else // ^^^ _CCCL_STD_VER >= 2023 ^^^ / vvv _CCCL_STD_VER < 2023 vvv
template <class _Pointer>
struct __allocation_result
{
_Pointer ptr;
size_t count;
};

template <class _Alloc>
_LIBCUDACXX_NODISCARD_ATTRIBUTE _LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr __allocation_result<
typename allocator_traits<_Alloc>::pointer>
__allocate_at_least(_Alloc& __alloc, size_t __n)
{
return {__alloc.allocate(__n), __n};
}

#endif // _CCCL_STD_VER >= 2023

_LIBCUDACXX_END_NAMESPACE_STD

#endif // _LIBCUDACXX___MEMORY_ALLOCATE_AT_LEAST_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// -*- 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) 2023 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCUDACXX___MEMORY_ALLOCATION_GUARD_H
#define _LIBCUDACXX___MEMORY_ALLOCATION_GUARD_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 <cuda/std/detail/libcxx/include/__memory/allocator_traits.h>
#include <cuda/std/detail/libcxx/include/__utility/move.h>

_LIBCUDACXX_BEGIN_NAMESPACE_STD

// Helper class to allocate memory using an Allocator in an exception safe
// manner.
//
// The intended usage of this class is as follows:
//
// 0
// 1 __allocation_guard<SomeAllocator> guard(alloc, 10);
// 2 do_some_initialization_that_may_throw(guard.__get());
// 3 save_allocated_pointer_in_a_noexcept_operation(guard.__release_ptr());
// 4
//
// If line (2) throws an exception during initialization of the memory, the
// guard's destructor will be called, and the memory will be released using
// Allocator deallocation. Otherwise, we release the memory from the guard on
// line (3) in an operation that can't throw -- after that, the guard is not
// responsible for the memory anymore.
//
// This is similar to a unique_ptr, except it's easier to use with a
// custom allocator.

_CCCL_NV_DIAG_SUPPRESS(2659) // constexpr non-static member function will not be implicitly 'const' in C++14

template <class _Alloc>
struct __allocation_guard
{
using _Pointer = typename allocator_traits<_Alloc>::pointer;
using _Size = typename allocator_traits<_Alloc>::size_type;

template <class _AllocT> // we perform the allocator conversion inside the constructor
_LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY _CCCL_CONSTEXPR_CXX20 explicit __allocation_guard(
_AllocT __alloc, _Size __n)
: __alloc_(_CUDA_VSTD::move(__alloc))
, __n_(__n)
, __ptr_(allocator_traits<_Alloc>::allocate(__alloc_, __n_)) // initialization order is important
{}

_LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY _CCCL_CONSTEXPR_CXX20 ~__allocation_guard() noexcept
{
if (__ptr_ != nullptr)
{
allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __n_);
}
}

_LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY _CCCL_CONSTEXPR_CXX14 _Pointer __release_ptr() noexcept
{ // not called __release() because it's a keyword in objective-c++
_Pointer __tmp = __ptr_;
__ptr_ = nullptr;
return __tmp;
}

_LIBCUDACXX_HIDE_FROM_ABI _LIBCUDACXX_INLINE_VISIBILITY constexpr _Pointer __get() const noexcept
{
return __ptr_;
}

private:
_Alloc __alloc_;
_Size __n_;
_Pointer __ptr_;
};

_CCCL_NV_DIAG_DEFAULT(2659)

_LIBCUDACXX_END_NAMESPACE_STD

#endif // _LIBCUDACXX___MEMORY_ALLOCATION_GUARD_H
Loading

0 comments on commit 4da34c6

Please sign in to comment.