Message ID | 20230715045519.50684-3-kmatsui@gcc.gnu.org |
---|---|
State | New |
Headers | show |
Series | [v2,1/3] c++, libstdc++: Implement __is_arithmetic built-in trait | expand |
Hi, Here are the benchmarks for this change: * is_fundamental https://github.com/ken-matsui/gcc-benches/blob/main/is_fundamental.md#fri-jul-14-091146-pm-pdt-2023 Time: -37.1619% Peak Memory Usage: -29.4294% Total Memory Usage: -29.4783% * is_fundamental_v https://github.com/ken-matsui/gcc-benches/blob/main/is_fundamental_v.md#fri-jul-14-091757-pm-pdt-2023 Time: -35.5446% Peak Memory Usage: -30.0096% Total Memory Usage: -30.6021% * is_fundamental with bool_constant (on trunk [18dac101678b8c0aed4bd995351e47f26cd54dec]) https://github.com/ken-matsui/gcc-benches/blob/main/is_fundamental-bool_constant.md#fri-jul-14-094237-pm-pdt-2023 Time: -28.3908% Peak Memory Usage: -18.5403% Total Memory Usage: -19.9045% --- It appears using bool_constant is better than disjunction. If my understanding is correct, disjunction can avoid later instantiations when short-circuiting, but might the evaluation of disjunction be more expensive than evaluating is_void and is_null_pointer? Or my benchmark might be just incorrect. Sincerely, Ken Matsui On Fri, Jul 14, 2023 at 9:57 PM Ken Matsui <kmatsui@gcc.gnu.org> wrote: > > This patch optimizes the performance of the is_fundamental trait by > dispatching to the new __is_arithmetic built-in trait. > > libstdc++-v3/ChangeLog: > > * include/std/type_traits (is_fundamental_v): Use __is_arithmetic > built-in trait. > (is_fundamental): Likewise. Optimize the original implementation. > > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org> > --- > libstdc++-v3/include/std/type_traits | 21 +++++++++++++++++---- > 1 file changed, 17 insertions(+), 4 deletions(-) > > diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits > index 7ebbe04c77b..cf24de2fcac 100644 > --- a/libstdc++-v3/include/std/type_traits > +++ b/libstdc++-v3/include/std/type_traits > @@ -668,11 +668,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > #endif > > /// is_fundamental > +#if __has_builtin(__is_arithmetic) > + template<typename _Tp> > + struct is_fundamental > + : public __bool_constant<__is_arithmetic(_Tp) > + || is_void<_Tp>::value > + || is_null_pointer<_Tp>::value> > + { }; > +#else > template<typename _Tp> > struct is_fundamental > - : public __or_<is_arithmetic<_Tp>, is_void<_Tp>, > - is_null_pointer<_Tp>>::type > + : public __bool_constant<is_arithmetic<_Tp>::value > + || is_void<_Tp>::value > + || is_null_pointer<_Tp>::value> > { }; > +#endif > > /// is_object > template<typename _Tp> > @@ -3209,13 +3219,16 @@ template <typename _Tp> > #if __has_builtin(__is_arithmetic) > template <typename _Tp> > inline constexpr bool is_arithmetic_v = __is_arithmetic(_Tp); > +template <typename _Tp> > + inline constexpr bool is_fundamental_v > + = __is_arithmetic(_Tp) || is_void_v<_Tp> || is_null_pointer_v<_Tp>; > #else > template <typename _Tp> > inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value; > -#endif > - > template <typename _Tp> > inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value; > +#endif > + > template <typename _Tp> > inline constexpr bool is_object_v = is_object<_Tp>::value; > template <typename _Tp> > -- > 2.41.0 >
On 15/07/2023 06:55, Ken Matsui via Libstdc++ wrote: > This patch optimizes the performance of the is_fundamental trait by > dispatching to the new __is_arithmetic built-in trait. > > libstdc++-v3/ChangeLog: > > * include/std/type_traits (is_fundamental_v): Use __is_arithmetic > built-in trait. > (is_fundamental): Likewise. Optimize the original implementation. > > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org> > --- > libstdc++-v3/include/std/type_traits | 21 +++++++++++++++++---- > 1 file changed, 17 insertions(+), 4 deletions(-) > > diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits > index 7ebbe04c77b..cf24de2fcac 100644 > --- a/libstdc++-v3/include/std/type_traits > +++ b/libstdc++-v3/include/std/type_traits > @@ -668,11 +668,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > #endif > > /// is_fundamental > +#if __has_builtin(__is_arithmetic) > + template<typename _Tp> > + struct is_fundamental > + : public __bool_constant<__is_arithmetic(_Tp) > + || is_void<_Tp>::value > + || is_null_pointer<_Tp>::value> > + { }; What about doing this ? template<typename _Tp> struct is_fundamental : public __bool_constant<__is_arithmetic(_Tp) || __or_<is_void<_Tp>, is_null_pointer<_Tp>>::value> { }; Based on your benches it seems that builtin __is_arithmetic is much better that std::is_arithmetic. But __or_ could still avoid instantiation of is_null_pointer.
On Sun, Jul 16, 2023 at 5:41 AM François Dumont <frs.dumont@gmail.com> wrote: > > > On 15/07/2023 06:55, Ken Matsui via Libstdc++ wrote: > > This patch optimizes the performance of the is_fundamental trait by > > dispatching to the new __is_arithmetic built-in trait. > > > > libstdc++-v3/ChangeLog: > > > > * include/std/type_traits (is_fundamental_v): Use __is_arithmetic > > built-in trait. > > (is_fundamental): Likewise. Optimize the original implementation. > > > > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org> > > --- > > libstdc++-v3/include/std/type_traits | 21 +++++++++++++++++---- > > 1 file changed, 17 insertions(+), 4 deletions(-) > > > > diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits > > index 7ebbe04c77b..cf24de2fcac 100644 > > --- a/libstdc++-v3/include/std/type_traits > > +++ b/libstdc++-v3/include/std/type_traits > > @@ -668,11 +668,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > #endif > > > > /// is_fundamental > > +#if __has_builtin(__is_arithmetic) > > + template<typename _Tp> > > + struct is_fundamental > > + : public __bool_constant<__is_arithmetic(_Tp) > > + || is_void<_Tp>::value > > + || is_null_pointer<_Tp>::value> > > + { }; > > What about doing this ? > > template<typename _Tp> > struct is_fundamental > : public __bool_constant<__is_arithmetic(_Tp) > || __or_<is_void<_Tp>, > is_null_pointer<_Tp>>::value> > { }; > > Based on your benches it seems that builtin __is_arithmetic is much better that std::is_arithmetic. But __or_ could still avoid instantiation of is_null_pointer. > Let me take a benchmark for this later.
Hi, I took a benchmark for this. https://github.com/ken-matsui/gcc-benches/blob/main/is_fundamental-disjunction.md#mon-jul-17-105937-pm-pdt-2023 template<typename _Tp> struct is_fundamental : public std::bool_constant<__is_arithmetic(_Tp) || std::is_void<_Tp>::value || std::is_null_pointer<_Tp>::value> { }; is faster than: template<typename _Tp> struct is_fundamental : public std::bool_constant<__is_arithmetic(_Tp) || std::disjunction<std::is_void<_Tp>, std::is_null_pointer<_Tp> >::value> { }; Time: -32.2871% Peak Memory: -18.5071% Total Memory: -20.1991% Sincerely, Ken Matsui On Sun, Jul 16, 2023 at 9:49 PM Ken Matsui <kmatsui@cs.washington.edu> wrote: > > On Sun, Jul 16, 2023 at 5:41 AM François Dumont <frs.dumont@gmail.com> wrote: > > > > > > On 15/07/2023 06:55, Ken Matsui via Libstdc++ wrote: > > > This patch optimizes the performance of the is_fundamental trait by > > > dispatching to the new __is_arithmetic built-in trait. > > > > > > libstdc++-v3/ChangeLog: > > > > > > * include/std/type_traits (is_fundamental_v): Use __is_arithmetic > > > built-in trait. > > > (is_fundamental): Likewise. Optimize the original implementation. > > > > > > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org> > > > --- > > > libstdc++-v3/include/std/type_traits | 21 +++++++++++++++++---- > > > 1 file changed, 17 insertions(+), 4 deletions(-) > > > > > > diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits > > > index 7ebbe04c77b..cf24de2fcac 100644 > > > --- a/libstdc++-v3/include/std/type_traits > > > +++ b/libstdc++-v3/include/std/type_traits > > > @@ -668,11 +668,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > > #endif > > > > > > /// is_fundamental > > > +#if __has_builtin(__is_arithmetic) > > > + template<typename _Tp> > > > + struct is_fundamental > > > + : public __bool_constant<__is_arithmetic(_Tp) > > > + || is_void<_Tp>::value > > > + || is_null_pointer<_Tp>::value> > > > + { }; > > > > What about doing this ? > > > > template<typename _Tp> > > struct is_fundamental > > : public __bool_constant<__is_arithmetic(_Tp) > > || __or_<is_void<_Tp>, > > is_null_pointer<_Tp>>::value> > > { }; > > > > Based on your benches it seems that builtin __is_arithmetic is much better that std::is_arithmetic. But __or_ could still avoid instantiation of is_null_pointer. > > > Let me take a benchmark for this later.
I will eventually work on disjunction to somehow optimize, but in the meantime, this might be a better implementation. Of course, my benchmark could be wrong. On Mon, Jul 17, 2023 at 11:24 PM Ken Matsui <kmatsui@cs.washington.edu> wrote: > > Hi, > > I took a benchmark for this. > > https://github.com/ken-matsui/gcc-benches/blob/main/is_fundamental-disjunction.md#mon-jul-17-105937-pm-pdt-2023 > > template<typename _Tp> > struct is_fundamental > : public std::bool_constant<__is_arithmetic(_Tp) > || std::is_void<_Tp>::value > || std::is_null_pointer<_Tp>::value> > { }; > > is faster than: > > template<typename _Tp> > struct is_fundamental > : public std::bool_constant<__is_arithmetic(_Tp) > || std::disjunction<std::is_void<_Tp>, > std::is_null_pointer<_Tp> > >::value> > { }; > > Time: -32.2871% > Peak Memory: -18.5071% > Total Memory: -20.1991% > > Sincerely, > Ken Matsui > > On Sun, Jul 16, 2023 at 9:49 PM Ken Matsui <kmatsui@cs.washington.edu> wrote: > > > > On Sun, Jul 16, 2023 at 5:41 AM François Dumont <frs.dumont@gmail.com> wrote: > > > > > > > > > On 15/07/2023 06:55, Ken Matsui via Libstdc++ wrote: > > > > This patch optimizes the performance of the is_fundamental trait by > > > > dispatching to the new __is_arithmetic built-in trait. > > > > > > > > libstdc++-v3/ChangeLog: > > > > > > > > * include/std/type_traits (is_fundamental_v): Use __is_arithmetic > > > > built-in trait. > > > > (is_fundamental): Likewise. Optimize the original implementation. > > > > > > > > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org> > > > > --- > > > > libstdc++-v3/include/std/type_traits | 21 +++++++++++++++++---- > > > > 1 file changed, 17 insertions(+), 4 deletions(-) > > > > > > > > diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits > > > > index 7ebbe04c77b..cf24de2fcac 100644 > > > > --- a/libstdc++-v3/include/std/type_traits > > > > +++ b/libstdc++-v3/include/std/type_traits > > > > @@ -668,11 +668,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > > > #endif > > > > > > > > /// is_fundamental > > > > +#if __has_builtin(__is_arithmetic) > > > > + template<typename _Tp> > > > > + struct is_fundamental > > > > + : public __bool_constant<__is_arithmetic(_Tp) > > > > + || is_void<_Tp>::value > > > > + || is_null_pointer<_Tp>::value> > > > > + { }; > > > > > > What about doing this ? > > > > > > template<typename _Tp> > > > struct is_fundamental > > > : public __bool_constant<__is_arithmetic(_Tp) > > > || __or_<is_void<_Tp>, > > > is_null_pointer<_Tp>>::value> > > > { }; > > > > > > Based on your benches it seems that builtin __is_arithmetic is much better that std::is_arithmetic. But __or_ could still avoid instantiation of is_null_pointer. > > > > > Let me take a benchmark for this later.
It seems rather logical cause std::disjunction is supposed to avoid instantiations but in case of: std::disjunction<std::is_void<_Tp>, std::is_null_pointer<_Tp>> you'll avoid std::is_null_pointer instantiation only for 'void' type and at the price of instantiating std::disjunction so 2 instantiations at best but most of the time 3, clearly useless here. On 18/07/2023 08:24, Ken Matsui wrote: > Hi, > > I took a benchmark for this. > > https://github.com/ken-matsui/gcc-benches/blob/main/is_fundamental-disjunction.md#mon-jul-17-105937-pm-pdt-2023 > > template<typename _Tp> > struct is_fundamental > : public std::bool_constant<__is_arithmetic(_Tp) > || std::is_void<_Tp>::value > || std::is_null_pointer<_Tp>::value> > { }; > > is faster than: > > template<typename _Tp> > struct is_fundamental > : public std::bool_constant<__is_arithmetic(_Tp) > || std::disjunction<std::is_void<_Tp>, > std::is_null_pointer<_Tp> > >::value> > { }; > > Time: -32.2871% > Peak Memory: -18.5071% > Total Memory: -20.1991% > > Sincerely, > Ken Matsui > > On Sun, Jul 16, 2023 at 9:49 PM Ken Matsui <kmatsui@cs.washington.edu> wrote: >> On Sun, Jul 16, 2023 at 5:41 AM François Dumont <frs.dumont@gmail.com> wrote: >>> >>> On 15/07/2023 06:55, Ken Matsui via Libstdc++ wrote: >>>> This patch optimizes the performance of the is_fundamental trait by >>>> dispatching to the new __is_arithmetic built-in trait. >>>> >>>> libstdc++-v3/ChangeLog: >>>> >>>> * include/std/type_traits (is_fundamental_v): Use __is_arithmetic >>>> built-in trait. >>>> (is_fundamental): Likewise. Optimize the original implementation. >>>> >>>> Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org> >>>> --- >>>> libstdc++-v3/include/std/type_traits | 21 +++++++++++++++++---- >>>> 1 file changed, 17 insertions(+), 4 deletions(-) >>>> >>>> diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits >>>> index 7ebbe04c77b..cf24de2fcac 100644 >>>> --- a/libstdc++-v3/include/std/type_traits >>>> +++ b/libstdc++-v3/include/std/type_traits >>>> @@ -668,11 +668,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION >>>> #endif >>>> >>>> /// is_fundamental >>>> +#if __has_builtin(__is_arithmetic) >>>> + template<typename _Tp> >>>> + struct is_fundamental >>>> + : public __bool_constant<__is_arithmetic(_Tp) >>>> + || is_void<_Tp>::value >>>> + || is_null_pointer<_Tp>::value> >>>> + { }; >>> What about doing this ? >>> >>> template<typename _Tp> >>> struct is_fundamental >>> : public __bool_constant<__is_arithmetic(_Tp) >>> || __or_<is_void<_Tp>, >>> is_null_pointer<_Tp>>::value> >>> { }; >>> >>> Based on your benches it seems that builtin __is_arithmetic is much better that std::is_arithmetic. But __or_ could still avoid instantiation of is_null_pointer. >>> >> Let me take a benchmark for this later.
On Tue, 18 Jul 2023 at 07:28, Ken Matsui via Libstdc++ < libstdc++@gcc.gnu.org> wrote: > I will eventually work on disjunction to somehow optimize, but in the > meantime, this might be a better implementation. Of course, my > benchmark could be wrong. > You should use __or_ internally in libstdc++ code, not std::disjunction. Patrick already optimized both of those, and __or_ is slightly faster (because it doesn't have to conform to the full requirements of std::disjunction). A compiler built-in for __or_ / __disjunction might perform better. But eventually if we're going to have built-ins for all of __is_arithmetic, __is_void, and __is_null_pointer, then we would want simply: __is_arithmetic(T) || __is_void(T) || __is_null_pointer(T) and so we wouldn't need to avoid instantiating any class templates at all. > > On Mon, Jul 17, 2023 at 11:24 PM Ken Matsui <kmatsui@cs.washington.edu> > wrote: > > > > Hi, > > > > I took a benchmark for this. > > > > > https://github.com/ken-matsui/gcc-benches/blob/main/is_fundamental-disjunction.md#mon-jul-17-105937-pm-pdt-2023 > > > > template<typename _Tp> > > struct is_fundamental > > : public std::bool_constant<__is_arithmetic(_Tp) > > || std::is_void<_Tp>::value > > || std::is_null_pointer<_Tp>::value> > > { }; > > > > is faster than: > > > > template<typename _Tp> > > struct is_fundamental > > : public std::bool_constant<__is_arithmetic(_Tp) > > || std::disjunction<std::is_void<_Tp>, > > std::is_null_pointer<_Tp> > > >::value> > > { }; > > > > Time: -32.2871% > > Peak Memory: -18.5071% > > Total Memory: -20.1991% > > > > Sincerely, > > Ken Matsui > > > > On Sun, Jul 16, 2023 at 9:49 PM Ken Matsui <kmatsui@cs.washington.edu> > wrote: > > > > > > On Sun, Jul 16, 2023 at 5:41 AM François Dumont <frs.dumont@gmail.com> > wrote: > > > > > > > > > > > > On 15/07/2023 06:55, Ken Matsui via Libstdc++ wrote: > > > > > This patch optimizes the performance of the is_fundamental trait by > > > > > dispatching to the new __is_arithmetic built-in trait. > > > > > > > > > > libstdc++-v3/ChangeLog: > > > > > > > > > > * include/std/type_traits (is_fundamental_v): Use > __is_arithmetic > > > > > built-in trait. > > > > > (is_fundamental): Likewise. Optimize the original > implementation. > > > > > > > > > > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org> > > > > > --- > > > > > libstdc++-v3/include/std/type_traits | 21 +++++++++++++++++---- > > > > > 1 file changed, 17 insertions(+), 4 deletions(-) > > > > > > > > > > diff --git a/libstdc++-v3/include/std/type_traits > b/libstdc++-v3/include/std/type_traits > > > > > index 7ebbe04c77b..cf24de2fcac 100644 > > > > > --- a/libstdc++-v3/include/std/type_traits > > > > > +++ b/libstdc++-v3/include/std/type_traits > > > > > @@ -668,11 +668,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > > > > #endif > > > > > > > > > > /// is_fundamental > > > > > +#if __has_builtin(__is_arithmetic) > > > > > + template<typename _Tp> > > > > > + struct is_fundamental > > > > > + : public __bool_constant<__is_arithmetic(_Tp) > > > > > + || is_void<_Tp>::value > > > > > + || is_null_pointer<_Tp>::value> > > > > > + { }; > > > > > > > > What about doing this ? > > > > > > > > template<typename _Tp> > > > > struct is_fundamental > > > > : public __bool_constant<__is_arithmetic(_Tp) > > > > || __or_<is_void<_Tp>, > > > > is_null_pointer<_Tp>>::value> > > > > { }; > > > > > > > > Based on your benches it seems that builtin __is_arithmetic is much > better that std::is_arithmetic. But __or_ could still avoid instantiation > of is_null_pointer. > > > > > > > Let me take a benchmark for this later. > >
On Tue, 18 Jul 2023 at 07:25, Ken Matsui via Libstdc++ < libstdc++@gcc.gnu.org> wrote: > Hi, > > I took a benchmark for this. > > > https://github.com/ken-matsui/gcc-benches/blob/main/is_fundamental-disjunction.md#mon-jul-17-105937-pm-pdt-2023 > > template<typename _Tp> > struct is_fundamental > : public std::bool_constant<__is_arithmetic(_Tp) > || std::is_void<_Tp>::value > || std::is_null_pointer<_Tp>::value> > { }; > > is faster than: > > template<typename _Tp> > struct is_fundamental > : public std::bool_constant<__is_arithmetic(_Tp) > || std::disjunction<std::is_void<_Tp>, > std::is_null_pointer<_Tp> > >::value> > { }; > > Time: -32.2871% > Peak Memory: -18.5071% > Total Memory: -20.1991% > But what about the fallback implementation of is_fundamental where we don't have the __is_arithmetic built-in? - : public __or_<is_arithmetic<_Tp>, is_void<_Tp>, - is_null_pointer<_Tp>>::type + : public __bool_constant<is_arithmetic<_Tp>::value + || is_void<_Tp>::value + || is_null_pointer<_Tp>::value> Here the use of __or_ means that for is_fundamental<int> we don't instantiate is_void<int> and is_null_pointer<int>. Isn't that still worthwhile? > > Sincerely, > Ken Matsui > > On Sun, Jul 16, 2023 at 9:49 PM Ken Matsui <kmatsui@cs.washington.edu> > wrote: > > > > On Sun, Jul 16, 2023 at 5:41 AM François Dumont <frs.dumont@gmail.com> > wrote: > > > > > > > > > On 15/07/2023 06:55, Ken Matsui via Libstdc++ wrote: > > > > This patch optimizes the performance of the is_fundamental trait by > > > > dispatching to the new __is_arithmetic built-in trait. > > > > > > > > libstdc++-v3/ChangeLog: > > > > > > > > * include/std/type_traits (is_fundamental_v): Use > __is_arithmetic > > > > built-in trait. > > > > (is_fundamental): Likewise. Optimize the original > implementation. > > > > > > > > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org> > > > > --- > > > > libstdc++-v3/include/std/type_traits | 21 +++++++++++++++++---- > > > > 1 file changed, 17 insertions(+), 4 deletions(-) > > > > > > > > diff --git a/libstdc++-v3/include/std/type_traits > b/libstdc++-v3/include/std/type_traits > > > > index 7ebbe04c77b..cf24de2fcac 100644 > > > > --- a/libstdc++-v3/include/std/type_traits > > > > +++ b/libstdc++-v3/include/std/type_traits > > > > @@ -668,11 +668,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > > > #endif > > > > > > > > /// is_fundamental > > > > +#if __has_builtin(__is_arithmetic) > > > > + template<typename _Tp> > > > > + struct is_fundamental > > > > + : public __bool_constant<__is_arithmetic(_Tp) > > > > + || is_void<_Tp>::value > > > > + || is_null_pointer<_Tp>::value> > > > > + { }; > > > > > > What about doing this ? > > > > > > template<typename _Tp> > > > struct is_fundamental > > > : public __bool_constant<__is_arithmetic(_Tp) > > > || __or_<is_void<_Tp>, > > > is_null_pointer<_Tp>>::value> > > > { }; > > > > > > Based on your benches it seems that builtin __is_arithmetic is much > better that std::is_arithmetic. But __or_ could still avoid instantiation > of is_null_pointer. > > > > > Let me take a benchmark for this later. > >
On Tue, Aug 8, 2023 at 1:14 PM Jonathan Wakely <jwakely@redhat.com> wrote: > > > > On Tue, 18 Jul 2023 at 07:28, Ken Matsui via Libstdc++ <libstdc++@gcc.gnu.org> wrote: >> >> I will eventually work on disjunction to somehow optimize, but in the >> meantime, this might be a better implementation. Of course, my >> benchmark could be wrong. > > > You should use __or_ internally in libstdc++ code, not std::disjunction. > > Patrick already optimized both of those, and __or_ is slightly faster (because it doesn't have to conform to the full requirements of std::disjunction). > I will! Thank you! > A compiler built-in for __or_ / __disjunction might perform better. But eventually if we're going to have built-ins for all of __is_arithmetic, __is_void, and __is_null_pointer, then we would want simply: > > __is_arithmetic(T) || __is_void(T) || __is_null_pointer(T) > > and so we wouldn't need to avoid instantiating any class templates at all. > I think we are not going to define built-ins for is_void and is_null_pointer as their type trait implementations are already optimal. > >> >> >> On Mon, Jul 17, 2023 at 11:24 PM Ken Matsui <kmatsui@cs.washington.edu> wrote: >> > >> > Hi, >> > >> > I took a benchmark for this. >> > >> > https://github.com/ken-matsui/gcc-benches/blob/main/is_fundamental-disjunction.md#mon-jul-17-105937-pm-pdt-2023 >> > >> > template<typename _Tp> >> > struct is_fundamental >> > : public std::bool_constant<__is_arithmetic(_Tp) >> > || std::is_void<_Tp>::value >> > || std::is_null_pointer<_Tp>::value> >> > { }; >> > >> > is faster than: >> > >> > template<typename _Tp> >> > struct is_fundamental >> > : public std::bool_constant<__is_arithmetic(_Tp) >> > || std::disjunction<std::is_void<_Tp>, >> > std::is_null_pointer<_Tp> >> > >::value> >> > { }; >> > >> > Time: -32.2871% >> > Peak Memory: -18.5071% >> > Total Memory: -20.1991% >> > >> > Sincerely, >> > Ken Matsui >> > >> > On Sun, Jul 16, 2023 at 9:49 PM Ken Matsui <kmatsui@cs.washington.edu> wrote: >> > > >> > > On Sun, Jul 16, 2023 at 5:41 AM François Dumont <frs.dumont@gmail.com> wrote: >> > > > >> > > > >> > > > On 15/07/2023 06:55, Ken Matsui via Libstdc++ wrote: >> > > > > This patch optimizes the performance of the is_fundamental trait by >> > > > > dispatching to the new __is_arithmetic built-in trait. >> > > > > >> > > > > libstdc++-v3/ChangeLog: >> > > > > >> > > > > * include/std/type_traits (is_fundamental_v): Use __is_arithmetic >> > > > > built-in trait. >> > > > > (is_fundamental): Likewise. Optimize the original implementation. >> > > > > >> > > > > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org> >> > > > > --- >> > > > > libstdc++-v3/include/std/type_traits | 21 +++++++++++++++++---- >> > > > > 1 file changed, 17 insertions(+), 4 deletions(-) >> > > > > >> > > > > diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits >> > > > > index 7ebbe04c77b..cf24de2fcac 100644 >> > > > > --- a/libstdc++-v3/include/std/type_traits >> > > > > +++ b/libstdc++-v3/include/std/type_traits >> > > > > @@ -668,11 +668,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION >> > > > > #endif >> > > > > >> > > > > /// is_fundamental >> > > > > +#if __has_builtin(__is_arithmetic) >> > > > > + template<typename _Tp> >> > > > > + struct is_fundamental >> > > > > + : public __bool_constant<__is_arithmetic(_Tp) >> > > > > + || is_void<_Tp>::value >> > > > > + || is_null_pointer<_Tp>::value> >> > > > > + { }; >> > > > >> > > > What about doing this ? >> > > > >> > > > template<typename _Tp> >> > > > struct is_fundamental >> > > > : public __bool_constant<__is_arithmetic(_Tp) >> > > > || __or_<is_void<_Tp>, >> > > > is_null_pointer<_Tp>>::value> >> > > > { }; >> > > > >> > > > Based on your benches it seems that builtin __is_arithmetic is much better that std::is_arithmetic. But __or_ could still avoid instantiation of is_null_pointer. >> > > > >> > > Let me take a benchmark for this later. >>
On Tue, Aug 8, 2023 at 1:19 PM Jonathan Wakely <jwakely@redhat.com> wrote: > > > > On Tue, 18 Jul 2023 at 07:25, Ken Matsui via Libstdc++ <libstdc++@gcc.gnu.org> wrote: >> >> Hi, >> >> I took a benchmark for this. >> >> https://github.com/ken-matsui/gcc-benches/blob/main/is_fundamental-disjunction.md#mon-jul-17-105937-pm-pdt-2023 >> >> template<typename _Tp> >> struct is_fundamental >> : public std::bool_constant<__is_arithmetic(_Tp) >> || std::is_void<_Tp>::value >> || std::is_null_pointer<_Tp>::value> >> { }; >> >> is faster than: >> >> template<typename _Tp> >> struct is_fundamental >> : public std::bool_constant<__is_arithmetic(_Tp) >> || std::disjunction<std::is_void<_Tp>, >> std::is_null_pointer<_Tp> >> >::value> >> { }; >> >> Time: -32.2871% >> Peak Memory: -18.5071% >> Total Memory: -20.1991% > > > But what about the fallback implementation of is_fundamental where we don't have the __is_arithmetic built-in? That fallback implementation would be this: https://github.com/ken-matsui/gsoc23/blob/967e20770599f2a8925c9794669111faef11beb7/is_fundamental.cc#L11-L15. The is_fundamental-disjunction.cc benchmark used the USE_BUILTIN macro, but in this benchmark, I used it to just switch two different implementations that use the __is_arithmetic built-in. > - : public __or_<is_arithmetic<_Tp>, is_void<_Tp>, > - is_null_pointer<_Tp>>::type > + : public __bool_constant<is_arithmetic<_Tp>::value > + || is_void<_Tp>::value > + || is_null_pointer<_Tp>::value> > > Here the use of __or_ means that for is_fundamental<int> we don't instantiate is_void<int> and is_null_pointer<int>. Isn't that still worthwhile? > Let me take a benchmark with __or_ later! We may see a difference. > > > >> >> >> Sincerely, >> Ken Matsui >> >> On Sun, Jul 16, 2023 at 9:49 PM Ken Matsui <kmatsui@cs.washington.edu> wrote: >> > >> > On Sun, Jul 16, 2023 at 5:41 AM François Dumont <frs.dumont@gmail.com> wrote: >> > > >> > > >> > > On 15/07/2023 06:55, Ken Matsui via Libstdc++ wrote: >> > > > This patch optimizes the performance of the is_fundamental trait by >> > > > dispatching to the new __is_arithmetic built-in trait. >> > > > >> > > > libstdc++-v3/ChangeLog: >> > > > >> > > > * include/std/type_traits (is_fundamental_v): Use __is_arithmetic >> > > > built-in trait. >> > > > (is_fundamental): Likewise. Optimize the original implementation. >> > > > >> > > > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org> >> > > > --- >> > > > libstdc++-v3/include/std/type_traits | 21 +++++++++++++++++---- >> > > > 1 file changed, 17 insertions(+), 4 deletions(-) >> > > > >> > > > diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits >> > > > index 7ebbe04c77b..cf24de2fcac 100644 >> > > > --- a/libstdc++-v3/include/std/type_traits >> > > > +++ b/libstdc++-v3/include/std/type_traits >> > > > @@ -668,11 +668,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION >> > > > #endif >> > > > >> > > > /// is_fundamental >> > > > +#if __has_builtin(__is_arithmetic) >> > > > + template<typename _Tp> >> > > > + struct is_fundamental >> > > > + : public __bool_constant<__is_arithmetic(_Tp) >> > > > + || is_void<_Tp>::value >> > > > + || is_null_pointer<_Tp>::value> >> > > > + { }; >> > > >> > > What about doing this ? >> > > >> > > template<typename _Tp> >> > > struct is_fundamental >> > > : public __bool_constant<__is_arithmetic(_Tp) >> > > || __or_<is_void<_Tp>, >> > > is_null_pointer<_Tp>>::value> >> > > { }; >> > > >> > > Based on your benches it seems that builtin __is_arithmetic is much better that std::is_arithmetic. But __or_ could still avoid instantiation of is_null_pointer. >> > > >> > Let me take a benchmark for this later. >>
On Thu, Aug 31, 2023 at 6:57 AM Ken Matsui <kmatsui@cs.washington.edu> wrote: > > On Tue, Aug 8, 2023 at 1:19 PM Jonathan Wakely <jwakely@redhat.com> wrote: > > > > > > > > On Tue, 18 Jul 2023 at 07:25, Ken Matsui via Libstdc++ <libstdc++@gcc.gnu.org> wrote: > >> > >> Hi, > >> > >> I took a benchmark for this. > >> > >> https://github.com/ken-matsui/gcc-benches/blob/main/is_fundamental-disjunction.md#mon-jul-17-105937-pm-pdt-2023 > >> > >> template<typename _Tp> > >> struct is_fundamental > >> : public std::bool_constant<__is_arithmetic(_Tp) > >> || std::is_void<_Tp>::value > >> || std::is_null_pointer<_Tp>::value> > >> { }; > >> > >> is faster than: > >> > >> template<typename _Tp> > >> struct is_fundamental > >> : public std::bool_constant<__is_arithmetic(_Tp) > >> || std::disjunction<std::is_void<_Tp>, > >> std::is_null_pointer<_Tp> > >> >::value> > >> { }; > >> > >> Time: -32.2871% > >> Peak Memory: -18.5071% > >> Total Memory: -20.1991% > > > > > > But what about the fallback implementation of is_fundamental where we don't have the __is_arithmetic built-in? > > That fallback implementation would be this: > https://github.com/ken-matsui/gsoc23/blob/967e20770599f2a8925c9794669111faef11beb7/is_fundamental.cc#L11-L15. > > The is_fundamental-disjunction.cc benchmark used the USE_BUILTIN > macro, but in this benchmark, I used it to just switch two different > implementations that use the __is_arithmetic built-in. > > > - : public __or_<is_arithmetic<_Tp>, is_void<_Tp>, > > - is_null_pointer<_Tp>>::type > > + : public __bool_constant<is_arithmetic<_Tp>::value > > + || is_void<_Tp>::value > > + || is_null_pointer<_Tp>::value> > > > > Here the use of __or_ means that for is_fundamental<int> we don't instantiate is_void<int> and is_null_pointer<int>. Isn't that still worthwhile? > > > Let me take a benchmark with __or_ later! We may see a difference. > Here is the benchmark result with __or_: https://github.com/ken-matsui/gsoc23/blob/main/is_fundamental-disjunction.md#thu-aug-31-075127-am-pdt-2023 Time: -23.3935% Peak Memory: -10.2915% Total Memory: -14.4165% Considering the following was with disjunction, __or_ is faster than disjunction, but still just || seems much faster. Time: -32.2871% Peak Memory: -18.5071% Total Memory: -20.1991% > > > > > > > >> > >> > >> Sincerely, > >> Ken Matsui > >> > >> On Sun, Jul 16, 2023 at 9:49 PM Ken Matsui <kmatsui@cs.washington.edu> wrote: > >> > > >> > On Sun, Jul 16, 2023 at 5:41 AM François Dumont <frs.dumont@gmail.com> wrote: > >> > > > >> > > > >> > > On 15/07/2023 06:55, Ken Matsui via Libstdc++ wrote: > >> > > > This patch optimizes the performance of the is_fundamental trait by > >> > > > dispatching to the new __is_arithmetic built-in trait. > >> > > > > >> > > > libstdc++-v3/ChangeLog: > >> > > > > >> > > > * include/std/type_traits (is_fundamental_v): Use __is_arithmetic > >> > > > built-in trait. > >> > > > (is_fundamental): Likewise. Optimize the original implementation. > >> > > > > >> > > > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org> > >> > > > --- > >> > > > libstdc++-v3/include/std/type_traits | 21 +++++++++++++++++---- > >> > > > 1 file changed, 17 insertions(+), 4 deletions(-) > >> > > > > >> > > > diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits > >> > > > index 7ebbe04c77b..cf24de2fcac 100644 > >> > > > --- a/libstdc++-v3/include/std/type_traits > >> > > > +++ b/libstdc++-v3/include/std/type_traits > >> > > > @@ -668,11 +668,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > >> > > > #endif > >> > > > > >> > > > /// is_fundamental > >> > > > +#if __has_builtin(__is_arithmetic) > >> > > > + template<typename _Tp> > >> > > > + struct is_fundamental > >> > > > + : public __bool_constant<__is_arithmetic(_Tp) > >> > > > + || is_void<_Tp>::value > >> > > > + || is_null_pointer<_Tp>::value> > >> > > > + { }; > >> > > > >> > > What about doing this ? > >> > > > >> > > template<typename _Tp> > >> > > struct is_fundamental > >> > > : public __bool_constant<__is_arithmetic(_Tp) > >> > > || __or_<is_void<_Tp>, > >> > > is_null_pointer<_Tp>>::value> > >> > > { }; > >> > > > >> > > Based on your benches it seems that builtin __is_arithmetic is much better that std::is_arithmetic. But __or_ could still avoid instantiation of is_null_pointer. > >> > > > >> > Let me take a benchmark for this later. > >>
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index 7ebbe04c77b..cf24de2fcac 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -668,11 +668,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif /// is_fundamental +#if __has_builtin(__is_arithmetic) + template<typename _Tp> + struct is_fundamental + : public __bool_constant<__is_arithmetic(_Tp) + || is_void<_Tp>::value + || is_null_pointer<_Tp>::value> + { }; +#else template<typename _Tp> struct is_fundamental - : public __or_<is_arithmetic<_Tp>, is_void<_Tp>, - is_null_pointer<_Tp>>::type + : public __bool_constant<is_arithmetic<_Tp>::value + || is_void<_Tp>::value + || is_null_pointer<_Tp>::value> { }; +#endif /// is_object template<typename _Tp> @@ -3209,13 +3219,16 @@ template <typename _Tp> #if __has_builtin(__is_arithmetic) template <typename _Tp> inline constexpr bool is_arithmetic_v = __is_arithmetic(_Tp); +template <typename _Tp> + inline constexpr bool is_fundamental_v + = __is_arithmetic(_Tp) || is_void_v<_Tp> || is_null_pointer_v<_Tp>; #else template <typename _Tp> inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value; -#endif - template <typename _Tp> inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value; +#endif + template <typename _Tp> inline constexpr bool is_object_v = is_object<_Tp>::value; template <typename _Tp>
This patch optimizes the performance of the is_fundamental trait by dispatching to the new __is_arithmetic built-in trait. libstdc++-v3/ChangeLog: * include/std/type_traits (is_fundamental_v): Use __is_arithmetic built-in trait. (is_fundamental): Likewise. Optimize the original implementation. Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org> --- libstdc++-v3/include/std/type_traits | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-)