[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