[PATCH] Teach libc++ to use __builtin_operator_new/__builtin_operator_delete when available
Richard Smith
richard at metafoo.co.uk
Tue Jun 3 15:15:05 PDT 2014
On Tue, Jun 3, 2014 at 3:14 PM, Richard Smith <richard at metafoo.co.uk> wrote:
> Hi!
>
> This patch causes libc++ to use Clang's new __builtin_operator_new and
> __builtin_operator_delete builtins when possible. These builtins allow
> optimizations that the standard builtins do not: in particular, if we can
> remove all uses of an allocation, this permits removing the allocation
> itself too.
>
> In particular, this allows code using std::vector and its kin to be
> optimized away to nothing. Previously it would get optimized to the point
> where only the allocation and deallocation remained.
>
> This change has been applied to most calls to ::operator new and
> ::operator delete in libc++; I believe such optimizations are permitted by
> the specification of all affected library components.
>
> The exceptions are:
> * get_temporary_buffer wants to call nothrow new, and we don't support
> that with the builtins (that would require teaching Clang about
> std::nothrow_t)
> * __refstring is not affected; this doesn't seem particularly worthwhile
> since the only purpose for it is ABI interoperability with GCC
>
> One other caveat: the patch adds an include of <new> to <valarray>. <new>
> is extremely light, so I doubt this is a problem, but I thought it was
> worth calling out.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140603/28664745/attachment.html>
-------------- next part --------------
Index: valarray
===================================================================
--- valarray (revision 208949)
+++ valarray (working copy)
@@ -345,6 +345,7 @@
#include <initializer_list>
#include <algorithm>
#include <functional>
+#include <new>
#include <__undef_min_max>
@@ -2636,7 +2637,7 @@
{
__r.__begin_ =
__r.__end_ =
- static_cast<result_type*>(::operator new(__n * sizeof(result_type)));
+ static_cast<result_type*>(_VSTD::__allocate(__n * sizeof(result_type)));
for (size_t __i = 0; __i != __n; ++__r.__end_, ++__i)
::new (__r.__end_) result_type(__expr_[__i]);
}
@@ -2670,7 +2671,7 @@
{
if (__n)
{
- __begin_ = __end_ = static_cast<value_type*>(::operator new(__n * sizeof(value_type)));
+ __begin_ = __end_ = static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type)));
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
@@ -2695,7 +2696,7 @@
{
if (__v.size())
{
- __begin_ = __end_ = static_cast<value_type*>(::operator new(__v.size() * sizeof(value_type)));
+ __begin_ = __end_ = static_cast<value_type*>(_VSTD::__allocate(__v.size() * sizeof(value_type)));
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
@@ -2736,7 +2737,7 @@
size_t __n = __il.size();
if (__n)
{
- __begin_ = __end_ = static_cast<value_type*>(::operator new(__n * sizeof(value_type)));
+ __begin_ = __end_ = static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type)));
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
@@ -2764,7 +2765,7 @@
size_t __n = __sa.__size_;
if (__n)
{
- __begin_ = __end_ = static_cast<value_type*>(::operator new(__n * sizeof(value_type)));
+ __begin_ = __end_ = static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type)));
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
@@ -2790,7 +2791,7 @@
size_t __n = __ga.__1d_.size();
if (__n)
{
- __begin_ = __end_ = static_cast<value_type*>(::operator new(__n * sizeof(value_type)));
+ __begin_ = __end_ = static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type)));
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
@@ -2819,7 +2820,7 @@
size_t __n = __ma.__1d_.size();
if (__n)
{
- __begin_ = __end_ = static_cast<value_type*>(::operator new(__n * sizeof(value_type)));
+ __begin_ = __end_ = static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type)));
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
@@ -2848,7 +2849,7 @@
size_t __n = __ia.__1d_.size();
if (__n)
{
- __begin_ = __end_ = static_cast<value_type*>(::operator new(__n * sizeof(value_type)));
+ __begin_ = __end_ = static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type)));
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
@@ -3133,7 +3134,7 @@
{
__r.__begin_ =
__r.__end_ =
- static_cast<value_type*>(::operator new(__n * sizeof(value_type)));
+ static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type)));
for (const value_type* __p = __begin_; __n; ++__r.__end_, ++__p, --__n)
::new (__r.__end_) value_type(+*__p);
}
@@ -3150,7 +3151,7 @@
{
__r.__begin_ =
__r.__end_ =
- static_cast<value_type*>(::operator new(__n * sizeof(value_type)));
+ static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type)));
for (const value_type* __p = __begin_; __n; ++__r.__end_, ++__p, --__n)
::new (__r.__end_) value_type(-*__p);
}
@@ -3167,7 +3168,7 @@
{
__r.__begin_ =
__r.__end_ =
- static_cast<value_type*>(::operator new(__n * sizeof(value_type)));
+ static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type)));
for (const value_type* __p = __begin_; __n; ++__r.__end_, ++__p, --__n)
::new (__r.__end_) value_type(~*__p);
}
@@ -3184,7 +3185,7 @@
{
__r.__begin_ =
__r.__end_ =
- static_cast<bool*>(::operator new(__n * sizeof(bool)));
+ static_cast<bool*>(_VSTD::__allocate(__n * sizeof(bool)));
for (const value_type* __p = __begin_; __n; ++__r.__end_, ++__p, --__n)
::new (__r.__end_) bool(!*__p);
}
@@ -3504,7 +3505,7 @@
{
__r.__begin_ =
__r.__end_ =
- static_cast<value_type*>(::operator new(__n * sizeof(value_type)));
+ static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type)));
const value_type* __sb;
value_type* __tb;
value_type* __te;
@@ -3542,7 +3543,7 @@
{
__r.__begin_ =
__r.__end_ =
- static_cast<value_type*>(::operator new(__n * sizeof(value_type)));
+ static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type)));
__i %= static_cast<int>(__n);
const value_type* __m = __i >= 0 ? __begin_ + __i : __end_ + __i;
for (const value_type* __s = __m; __s != __end_; ++__r.__end_, ++__s)
@@ -3563,7 +3564,7 @@
{
__r.__begin_ =
__r.__end_ =
- static_cast<value_type*>(::operator new(__n * sizeof(value_type)));
+ static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type)));
for (const value_type* __p = __begin_; __n; ++__r.__end_, ++__p, --__n)
::new (__r.__end_) value_type(__f(*__p));
}
@@ -3580,7 +3581,7 @@
{
__r.__begin_ =
__r.__end_ =
- static_cast<value_type*>(::operator new(__n * sizeof(value_type)));
+ static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type)));
for (const value_type* __p = __begin_; __n; ++__r.__end_, ++__p, --__n)
::new (__r.__end_) value_type(__f(*__p));
}
@@ -3595,12 +3596,12 @@
{
while (__end_ != __begin_)
(--__end_)->~value_type();
- ::operator delete(__begin_);
+ _VSTD::__deallocate(__begin_);
__begin_ = __end_ = nullptr;
}
if (__n)
{
- __begin_ = __end_ = static_cast<value_type*>(::operator new(__n * sizeof(value_type)));
+ __begin_ = __end_ = static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type)));
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
Index: __config
===================================================================
--- __config (revision 208949)
+++ __config (working copy)
@@ -543,12 +543,20 @@
#define __has_feature(__x) 0
#endif
+#ifndef __has_builtin
+#define __has_builtin(__x) 0
+#endif
+
#if __has_feature(cxx_explicit_conversions) || defined(__IBMCPP__)
# define _LIBCPP_EXPLICIT explicit
#else
# define _LIBCPP_EXPLICIT
#endif
+#if !__has_builtin(__builtin_operator_new) || !__has_builtin(__builtin_operator_delete)
+# define _LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE
+#endif
+
#ifdef _LIBCPP_HAS_NO_STRONG_ENUMS
#define _LIBCPP_DECLARE_STRONG_ENUM(x) struct _LIBCPP_TYPE_VIS x { enum __lx
#define _LIBCPP_DECLARE_STRONG_ENUM_EPILOG(x) \
Index: new
===================================================================
--- new (revision 208949)
+++ new (working copy)
@@ -147,4 +147,24 @@
inline _LIBCPP_INLINE_VISIBILITY void operator delete (void*, void*) _NOEXCEPT {}
inline _LIBCPP_INLINE_VISIBILITY void operator delete[](void*, void*) _NOEXCEPT {}
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+inline _LIBCPP_INLINE_VISIBILITY void *__allocate(size_t __size) {
+#ifdef _LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE
+ return ::operator new(__size);
+#else
+ return __builtin_operator_new(__size);
+#endif
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void __deallocate(void *__ptr) {
+#ifdef _LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE
+ ::operator delete(__ptr);
+#else
+ __builtin_operator_delete(__ptr);
+#endif
+}
+
+_LIBCPP_END_NAMESPACE_STD
+
#endif // _LIBCPP_NEW
Index: experimental/dynarray
===================================================================
--- experimental/dynarray (revision 208949)
+++ experimental/dynarray (working copy)
@@ -147,12 +147,12 @@
assert(!"dynarray::allocation");
#endif
}
- return static_cast<value_type *> (::operator new (sizeof(value_type) * count));
+ return static_cast<value_type *> (_VSTD::__allocate (sizeof(value_type) * count));
}
static inline _LIBCPP_INLINE_VISIBILITY void __deallocate ( value_type* __ptr ) noexcept
{
- ::operator delete (static_cast<void *> (__ptr));
+ _VSTD::__deallocate (static_cast<void *> (__ptr));
}
public:
Index: memory
===================================================================
--- memory (revision 208949)
+++ memory (working copy)
@@ -1631,9 +1631,9 @@
_LIBCPP_INLINE_VISIBILITY const_pointer address(const_reference __x) const _NOEXCEPT
{return _VSTD::addressof(__x);}
_LIBCPP_INLINE_VISIBILITY pointer allocate(size_type __n, allocator<void>::const_pointer = 0)
- {return static_cast<pointer>(::operator new(__n * sizeof(_Tp)));}
+ {return static_cast<pointer>(_VSTD::__allocate(__n * sizeof(_Tp)));}
_LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type) _NOEXCEPT
- {::operator delete((void*)__p);}
+ {_VSTD::__deallocate((void*)__p);}
_LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT
{return size_type(~0) / sizeof(_Tp);}
#if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS)
@@ -1721,9 +1721,9 @@
_LIBCPP_INLINE_VISIBILITY const_pointer address(const_reference __x) const _NOEXCEPT
{return _VSTD::addressof(__x);}
_LIBCPP_INLINE_VISIBILITY pointer allocate(size_type __n, allocator<void>::const_pointer = 0)
- {return static_cast<pointer>(::operator new(__n * sizeof(_Tp)));}
+ {return static_cast<pointer>(_VSTD::__allocate(__n * sizeof(_Tp)));}
_LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type) _NOEXCEPT
- {::operator delete((void*)__p);}
+ {_VSTD::__deallocate((void*)__p);}
_LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT
{return size_type(~0) / sizeof(_Tp);}
#if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS)
Index: __sso_allocator
===================================================================
--- __sso_allocator (revision 208949)
+++ __sso_allocator (working copy)
@@ -55,14 +55,14 @@
__allocated_ = true;
return (pointer)&buf_;
}
- return static_cast<pointer>(::operator new(__n * sizeof(_Tp)));
+ return static_cast<pointer>(_VSTD::__allocate(__n * sizeof(_Tp)));
}
_LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type)
{
if (__p == (pointer)&buf_)
__allocated_ = false;
else
- ::operator delete(__p);
+ _VSTD::deallocate(__p);
}
_LIBCPP_INLINE_VISIBILITY size_type max_size() const throw() {return size_type(~0) / sizeof(_Tp);}
More information about the cfe-commits
mailing list