mirror of git://gcc.gnu.org/git/gcc.git
PR libstdc++/70940 make pmr::resource_adaptor return aligned memory
PR libstdc++/70940 * include/experimental/memory_resource (__resource_adaptor_common): New base class. (__resource_adaptor_common::_AlignMgr): Helper for obtaining aligned pointer from unaligned, and vice versa. (__resource_adaptor_imp::do_allocate): Use _AlignMgr to adjust allocated pointer to meet alignment request. (__resource_adaptor_imp::do_deallocate): Use _AlignMgr to retrieve original pointer for deallocation. (__resource_adaptor_imp::do_is_equal): Reformat. (__resource_adaptor_imp::_S_aligned_size): Remove. (__resource_adaptor_imp::_S_supported): Remove. (new_delete_resource): Use __gnu_cxx::new_allocator. * testsuite/experimental/memory_resource/resource_adaptor.cc: Test extended alignments and use debug_allocator to check for matching allocate/deallocate pairs. From-SVN: r261849
This commit is contained in:
parent
67b3b8feb3
commit
7956c508dd
|
|
@ -1,3 +1,22 @@
|
||||||
|
2018-06-21 Jonathan Wakely <jwakely@redhat.com>
|
||||||
|
|
||||||
|
PR libstdc++/70940
|
||||||
|
* include/experimental/memory_resource (__resource_adaptor_common):
|
||||||
|
New base class.
|
||||||
|
(__resource_adaptor_common::_AlignMgr): Helper for obtaining aligned
|
||||||
|
pointer from unaligned, and vice versa.
|
||||||
|
(__resource_adaptor_imp::do_allocate): Use _AlignMgr to adjust
|
||||||
|
allocated pointer to meet alignment request.
|
||||||
|
(__resource_adaptor_imp::do_deallocate): Use _AlignMgr to retrieve
|
||||||
|
original pointer for deallocation.
|
||||||
|
(__resource_adaptor_imp::do_is_equal): Reformat.
|
||||||
|
(__resource_adaptor_imp::_S_aligned_size): Remove.
|
||||||
|
(__resource_adaptor_imp::_S_supported): Remove.
|
||||||
|
(new_delete_resource): Use __gnu_cxx::new_allocator.
|
||||||
|
* testsuite/experimental/memory_resource/resource_adaptor.cc: Test
|
||||||
|
extended alignments and use debug_allocator to check for matching
|
||||||
|
allocate/deallocate pairs.
|
||||||
|
|
||||||
2018-06-21 François Dumont <fdumont@gcc.gnu.org>
|
2018-06-21 François Dumont <fdumont@gcc.gnu.org>
|
||||||
|
|
||||||
* include/debug/debug.h
|
* include/debug/debug.h
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
#include <new>
|
#include <new>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <ext/new_allocator.h>
|
||||||
#include <experimental/bits/lfts_config.h>
|
#include <experimental/bits/lfts_config.h>
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
|
|
@ -253,9 +254,103 @@ namespace pmr {
|
||||||
const polymorphic_allocator<_Tp2>& __b) noexcept
|
const polymorphic_allocator<_Tp2>& __b) noexcept
|
||||||
{ return !(__a == __b); }
|
{ return !(__a == __b); }
|
||||||
|
|
||||||
|
class __resource_adaptor_common
|
||||||
|
{
|
||||||
|
template<typename> friend class __resource_adaptor_imp;
|
||||||
|
|
||||||
|
struct _AlignMgr
|
||||||
|
{
|
||||||
|
_AlignMgr(size_t __nbytes, size_t __align)
|
||||||
|
: _M_nbytes(__nbytes), _M_align(__align)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
// Total size that needs to be allocated.
|
||||||
|
size_t
|
||||||
|
_M_alloc_size() const { return _M_buf_size() + _M_token_size(); }
|
||||||
|
|
||||||
|
void*
|
||||||
|
_M_adjust(void* __ptr) const
|
||||||
|
{
|
||||||
|
const auto __orig_ptr = static_cast<char*>(__ptr);
|
||||||
|
size_t __space = _M_buf_size();
|
||||||
|
// Align the pointer within the buffer:
|
||||||
|
std::align(_M_align, _M_nbytes, __ptr, __space);
|
||||||
|
const auto __aligned_ptr = static_cast<char*>(__ptr);
|
||||||
|
const auto __token_size = _M_token_size();
|
||||||
|
// Store token immediately after the aligned block:
|
||||||
|
char* const __end = __aligned_ptr + _M_nbytes;
|
||||||
|
if (__token_size == 1)
|
||||||
|
_S_write<unsigned char>(__end, __aligned_ptr - __orig_ptr);
|
||||||
|
else if (__token_size == sizeof(short))
|
||||||
|
_S_write<unsigned short>(__end, __aligned_ptr - __orig_ptr);
|
||||||
|
else if (__token_size == sizeof(int) && sizeof(int) < sizeof(char*))
|
||||||
|
_S_write<unsigned int>(__end, __aligned_ptr - __orig_ptr);
|
||||||
|
else // (__token_size == sizeof(char*))
|
||||||
|
// Just store the original pointer:
|
||||||
|
_S_write<char*>(__end, __orig_ptr);
|
||||||
|
return __aligned_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
_M_unadjust(char* __ptr) const
|
||||||
|
{
|
||||||
|
const char* const __end = __ptr + _M_nbytes;
|
||||||
|
char* __orig_ptr;
|
||||||
|
const auto __token_size = _M_token_size();
|
||||||
|
// Read the token and restore the original pointer:
|
||||||
|
if (__token_size == 1)
|
||||||
|
__orig_ptr = __ptr - _S_read<unsigned char>(__end);
|
||||||
|
else if (__token_size == sizeof(short))
|
||||||
|
__orig_ptr = __ptr - _S_read<unsigned short>(__end);
|
||||||
|
else if (__token_size == sizeof(int)
|
||||||
|
&& sizeof(int) < sizeof(char*))
|
||||||
|
__orig_ptr = __ptr - _S_read<unsigned int>(__end);
|
||||||
|
else // (__token_size == sizeof(char*))
|
||||||
|
__orig_ptr = _S_read<char*>(__end);
|
||||||
|
return __orig_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t _M_nbytes;
|
||||||
|
size_t _M_align;
|
||||||
|
|
||||||
|
// Number of bytes needed to fit block of given size and alignment.
|
||||||
|
size_t
|
||||||
|
_M_buf_size() const { return _M_nbytes + _M_align - 1; }
|
||||||
|
|
||||||
|
// Number of additional bytes needed to write the token.
|
||||||
|
int
|
||||||
|
_M_token_size() const
|
||||||
|
{
|
||||||
|
if (_M_align <= (1ul << __CHAR_BIT__))
|
||||||
|
return 1;
|
||||||
|
if (_M_align <= (1ul << (sizeof(short) * __CHAR_BIT__)))
|
||||||
|
return sizeof(short);
|
||||||
|
if (_M_align <= (1ul << (sizeof(int) * __CHAR_BIT__)))
|
||||||
|
return sizeof(int);
|
||||||
|
return sizeof(char*);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename _Tp>
|
||||||
|
static void
|
||||||
|
_S_write(void* __to, _Tp __val)
|
||||||
|
{ __builtin_memcpy(__to, &__val, sizeof(_Tp)); }
|
||||||
|
|
||||||
|
template<typename _Tp>
|
||||||
|
static _Tp
|
||||||
|
_S_read(const void* __from)
|
||||||
|
{
|
||||||
|
_Tp __val;
|
||||||
|
__builtin_memcpy(&__val, __from, sizeof(_Tp));
|
||||||
|
return __val;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// 8.7.1 __resource_adaptor_imp
|
// 8.7.1 __resource_adaptor_imp
|
||||||
template <typename _Alloc>
|
template <typename _Alloc>
|
||||||
class __resource_adaptor_imp : public memory_resource
|
class __resource_adaptor_imp
|
||||||
|
: public memory_resource, private __resource_adaptor_common
|
||||||
{
|
{
|
||||||
static_assert(is_same<char,
|
static_assert(is_same<char,
|
||||||
typename allocator_traits<_Alloc>::value_type>::value,
|
typename allocator_traits<_Alloc>::value_type>::value,
|
||||||
|
|
@ -295,50 +390,41 @@ namespace pmr {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void*
|
virtual void*
|
||||||
do_allocate(size_t __bytes, size_t __alignment)
|
do_allocate(size_t __bytes, size_t __alignment) override
|
||||||
{
|
{
|
||||||
using _Aligned_alloc = std::__alloc_rebind<_Alloc, char>;
|
if (__alignment == 1)
|
||||||
size_t __new_size = _S_aligned_size(__bytes,
|
return _M_alloc.allocate(__bytes);
|
||||||
_S_supported(__alignment) ?
|
|
||||||
__alignment : _S_max_align);
|
const _AlignMgr __mgr(__bytes, __alignment);
|
||||||
return _Aligned_alloc(_M_alloc).allocate(__new_size);
|
// Assume _M_alloc returns 1-byte aligned memory, so allocate enough
|
||||||
|
// space to fit a block of the right size and alignment, plus some
|
||||||
|
// extra bytes to store a token for retrieving the original pointer.
|
||||||
|
return __mgr._M_adjust(_M_alloc.allocate(__mgr._M_alloc_size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void
|
virtual void
|
||||||
do_deallocate(void* __p, size_t __bytes, size_t __alignment)
|
do_deallocate(void* __p, size_t __bytes, size_t __alignment) noexcept
|
||||||
|
override
|
||||||
{
|
{
|
||||||
using _Aligned_alloc = std::__alloc_rebind<_Alloc, char>;
|
auto __ptr = static_cast<char*>(__p);
|
||||||
size_t __new_size = _S_aligned_size(__bytes,
|
if (__alignment == 1)
|
||||||
_S_supported(__alignment) ?
|
_M_alloc.deallocate(__ptr, __bytes);
|
||||||
__alignment : _S_max_align);
|
|
||||||
using _Ptr = typename allocator_traits<_Aligned_alloc>::pointer;
|
const _AlignMgr __mgr(__bytes, __alignment);
|
||||||
_Aligned_alloc(_M_alloc).deallocate(static_cast<_Ptr>(__p),
|
// Use the stored token to retrieve the original pointer to deallocate.
|
||||||
__new_size);
|
_M_alloc.deallocate(__mgr._M_unadjust(__ptr), __mgr._M_alloc_size());
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool
|
virtual bool
|
||||||
do_is_equal(const memory_resource& __other) const noexcept
|
do_is_equal(const memory_resource& __other) const noexcept override
|
||||||
{
|
{
|
||||||
auto __p = dynamic_cast<const __resource_adaptor_imp*>(&__other);
|
if (auto __p = dynamic_cast<const __resource_adaptor_imp*>(&__other))
|
||||||
return __p ? (_M_alloc == __p->_M_alloc) : false;
|
return _M_alloc == __p->_M_alloc;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Calculate Aligned Size
|
_Alloc _M_alloc{};
|
||||||
// Returns a size that is larger than or equal to __size and divisible
|
|
||||||
// by __alignment, where __alignment is required to be a power of 2.
|
|
||||||
static size_t
|
|
||||||
_S_aligned_size(size_t __size, size_t __alignment)
|
|
||||||
{ return ((__size - 1)|(__alignment - 1)) + 1; }
|
|
||||||
|
|
||||||
// Determine whether alignment meets one of those preconditions:
|
|
||||||
// 1. Equal to Zero
|
|
||||||
// 2. Is power of two
|
|
||||||
static bool
|
|
||||||
_S_supported (size_t __x)
|
|
||||||
{ return ((__x != 0) && !(__x & (__x - 1))); }
|
|
||||||
|
|
||||||
_Alloc _M_alloc;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Global memory resources
|
// Global memory resources
|
||||||
|
|
@ -352,7 +438,7 @@ namespace pmr {
|
||||||
inline memory_resource*
|
inline memory_resource*
|
||||||
new_delete_resource() noexcept
|
new_delete_resource() noexcept
|
||||||
{
|
{
|
||||||
using type = resource_adaptor<std::allocator<char>>;
|
using type = resource_adaptor<__gnu_cxx::new_allocator<char>>;
|
||||||
alignas(type) static unsigned char __buf[sizeof(type)];
|
alignas(type) static unsigned char __buf[sizeof(type)];
|
||||||
static type* __r = new(__buf) type;
|
static type* __r = new(__buf) type;
|
||||||
return __r;
|
return __r;
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
// <http://www.gnu.org/licenses/>.
|
// <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include <experimental/memory_resource>
|
#include <experimental/memory_resource>
|
||||||
|
#include <ext/debug_allocator.h>
|
||||||
#include <testsuite_hooks.h>
|
#include <testsuite_hooks.h>
|
||||||
#include <testsuite_allocator.h>
|
#include <testsuite_allocator.h>
|
||||||
|
|
||||||
|
|
@ -34,18 +35,22 @@ template<typename T>
|
||||||
Allocator(const Allocator<U>&) { }
|
Allocator(const Allocator<U>&) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<std::size_t A>
|
||||||
bool aligned(void* p)
|
bool aligned(void* p)
|
||||||
{
|
{
|
||||||
return (reinterpret_cast<std::uintptr_t>(p) % alignof(T)) == 0;
|
return (reinterpret_cast<std::uintptr_t>(p) % A) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool aligned(void* p)
|
||||||
|
{ return aligned<alignof(T)>(p); }
|
||||||
|
|
||||||
// resource_adaptor
|
// resource_adaptor
|
||||||
void
|
void
|
||||||
test05()
|
test05()
|
||||||
{
|
{
|
||||||
using std::max_align_t;
|
using std::max_align_t;
|
||||||
using std::uintptr_t;
|
using std::size_t;
|
||||||
void* p = nullptr;
|
void* p = nullptr;
|
||||||
|
|
||||||
Allocator<int> a1(1), a2(2); // minimal interface allocators
|
Allocator<int> a1(1), a2(2); // minimal interface allocators
|
||||||
|
|
@ -61,12 +66,18 @@ test05()
|
||||||
p = r1.allocate(1, alignof(long));
|
p = r1.allocate(1, alignof(long));
|
||||||
VERIFY( aligned<long>(p) );
|
VERIFY( aligned<long>(p) );
|
||||||
r1.deallocate(p, 1, alignof(long));
|
r1.deallocate(p, 1, alignof(long));
|
||||||
|
constexpr size_t big_al = alignof(max_align_t) * 8;
|
||||||
|
p = r1.allocate(1, big_al);
|
||||||
|
VERIFY( aligned<big_al>(p) );
|
||||||
|
r1.deallocate(p, 1, big_al);
|
||||||
|
|
||||||
__gnu_test::uneq_allocator<double> a3(3), a4(4); // non-equal allocators
|
__gnu_test::uneq_allocator<double> a3(3), a4(4); // non-equal allocators
|
||||||
resource_adaptor<decltype(a3)> r3(a3), r4(a4);
|
resource_adaptor<decltype(a3)> r3(a3), r4(a4);
|
||||||
VERIFY( r3 == r3 );
|
VERIFY( r3 == r3 );
|
||||||
VERIFY( r4 == r4 );
|
VERIFY( r4 == r4 );
|
||||||
VERIFY( r3 != r4 );
|
VERIFY( r3 != r4 );
|
||||||
|
VERIFY( r3 != r1 );
|
||||||
|
VERIFY( r3 != r2 );
|
||||||
p = r3.allocate(1);
|
p = r3.allocate(1);
|
||||||
VERIFY( aligned<max_align_t>(p) );
|
VERIFY( aligned<max_align_t>(p) );
|
||||||
r3.deallocate(p, 1);
|
r3.deallocate(p, 1);
|
||||||
|
|
@ -76,9 +87,40 @@ test05()
|
||||||
p = r3.allocate(1, alignof(long));
|
p = r3.allocate(1, alignof(long));
|
||||||
VERIFY( aligned<long>(p) );
|
VERIFY( aligned<long>(p) );
|
||||||
r3.deallocate(p, 1, alignof(long));
|
r3.deallocate(p, 1, alignof(long));
|
||||||
|
p = r3.allocate(1, big_al);
|
||||||
|
VERIFY( aligned<big_al>(p) );
|
||||||
|
r3.deallocate(p, 1, big_al);
|
||||||
|
|
||||||
// TODO test with an allocator that doesn't use new or malloc, so
|
__gnu_cxx::debug_allocator<std::allocator<short>> a5;
|
||||||
// returns pointers that are not suitably aligned for any type.
|
resource_adaptor<decltype(a5)> r5(a5), r6(a5);
|
||||||
|
VERIFY( r5 == r5 );
|
||||||
|
VERIFY( r5 == r6 );
|
||||||
|
VERIFY( r5 != r1 );
|
||||||
|
VERIFY( r5 != r3 );
|
||||||
|
p = r5.allocate(1);
|
||||||
|
VERIFY( aligned<max_align_t>(p) );
|
||||||
|
r5.deallocate(p, 1);
|
||||||
|
p = r5.allocate(1, alignof(short));
|
||||||
|
VERIFY( aligned<short>(p) );
|
||||||
|
r5.deallocate(p, 1, alignof(short));
|
||||||
|
p = r5.allocate(1, alignof(long));
|
||||||
|
VERIFY( aligned<long>(p) );
|
||||||
|
r5.deallocate(p, 1, alignof(long));
|
||||||
|
p = r5.allocate(1, big_al);
|
||||||
|
VERIFY( aligned<big_al>(p) );
|
||||||
|
r5.deallocate(p, 1, big_al);
|
||||||
|
|
||||||
|
// Test extended alignments
|
||||||
|
constexpr size_t al6 = (1ul << 6), al12 = (1ul << 12), al18 = (1ul << 18);
|
||||||
|
p = r5.allocate(1024, al6);
|
||||||
|
VERIFY( aligned<al6>(p) );
|
||||||
|
r5.deallocate(p, 1024, al6);
|
||||||
|
p = r5.allocate(1024, al12);
|
||||||
|
VERIFY( aligned<al12>(p) );
|
||||||
|
r5.deallocate(p, 1024, al12);
|
||||||
|
p = r5.allocate(1024, al18);
|
||||||
|
VERIFY( aligned<al18>(p) );
|
||||||
|
r5.deallocate(p, 1024, al18);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue