[PATCH 2/3] libstdc++: Optimize __uninitialized_default using memset
Hi, not sure whether I've missed some conditional that would exclude this case, but your change seems to incorrectly handle trivial types that have a non-zero bit pattern of value-initialized object, e.g. pointer to member. Regards, Maciej Cencora
Re: [PATCH 2/3] libstdc++: Optimize __uninitialized_default using memset
You could include some of the bigger classes by checking whether the class type is bit_cast-able to std::array of bytes, and that bitcasted output is equal to value-initialized array. Regards, Maciej czw., 27 cze 2024 o 14:50 Jonathan Wakely napisał(a): > On Thu, 27 Jun 2024 at 13:49, Jonathan Wakely wrote: > > > > On Thu, 27 Jun 2024 at 13:40, Maciej Cencora wrote: > > > > > > Hi, > > > > > > not sure whether I've missed some conditional that would exclude this > case, but your change seems to incorrectly handle trivial types that have a > non-zero bit pattern of value-initialized object, e.g. pointer to member. > > > > Good point. I started working on this optimization after last week's > > https://gcc.gnu.org/r15-1550-g139d65d1f5a60a where is_trivial is > > appropriate, because valarray only supports numeric types, not > > pointers to members. > > > > But the uninitialized memory algos don't have that restriction, so > > need to be more careful. > > > > I think memset is OK for arithmetic types, enums, pointers, nullptr_t, > > and trivial classes ... except when those trivial classes contain > > pointers to members. Which we can't tell. > > > > So maybe we can only do it for is_trivial && ((is_scalar and not > > is_member_pointer) or (is_class and is_empty)). > > I suppose any trivial class type smaller than sizeof(int T::*) would > be OK, because it can't hold a member pointer if it's smaller than > one. > >
Re: [PATCH 2/3] libstdc++: Optimize __uninitialized_default using memset
I think going the bit_cast way would be the best because it enables the optimization for many more classes including common wrappers like optional, variant, pair, tuple and std::array. Regards, Maciej Cencora czw., 27 cze 2024 o 14:57 Maciej Cencora napisał(a): > You could include some of the bigger classes by checking whether the class > type is bit_cast-able to std::array of bytes, and that bitcasted output is > equal to value-initialized array. > > Regards, > Maciej > > czw., 27 cze 2024 o 14:50 Jonathan Wakely napisał(a): > >> On Thu, 27 Jun 2024 at 13:49, Jonathan Wakely wrote: >> > >> > On Thu, 27 Jun 2024 at 13:40, Maciej Cencora wrote: >> > > >> > > Hi, >> > > >> > > not sure whether I've missed some conditional that would exclude this >> case, but your change seems to incorrectly handle trivial types that have a >> non-zero bit pattern of value-initialized object, e.g. pointer to member. >> > >> > Good point. I started working on this optimization after last week's >> > https://gcc.gnu.org/r15-1550-g139d65d1f5a60a where is_trivial is >> > appropriate, because valarray only supports numeric types, not >> > pointers to members. >> > >> > But the uninitialized memory algos don't have that restriction, so >> > need to be more careful. >> > >> > I think memset is OK for arithmetic types, enums, pointers, nullptr_t, >> > and trivial classes ... except when those trivial classes contain >> > pointers to members. Which we can't tell. >> > >> > So maybe we can only do it for is_trivial && ((is_scalar and not >> > is_member_pointer) or (is_class and is_empty)). >> >> I suppose any trivial class type smaller than sizeof(int T::*) would >> be OK, because it can't hold a member pointer if it's smaller than >> one. >> >>
Re: [PATCH 2/3] libstdc++: Optimize __uninitialized_default using memset
But constexpr-ness of bit_cast has additional limitations and e.g. providing an union as _Tp would be a hard-error. So we have two options: - before bitcasting check if type can be bitcast-ed at compile-time, - change the 'if constexpr' to regular 'if'. If we go with the second solution then we will include classes with pointers, and unions. Additionally we could also include types with padding by passing zero-initialized object (like a class-scope static constexpr or global) into bit_cast... but then such a variable would be ODR-used and most-likely won't be optimized out. I guess the best option would be to introduce in C++ language a new compiler-backed type trait like: std::zero_initialized_object_has_all_zeros_object_representation. Regards, Maciej pt., 28 cze 2024 o 00:25 Jonathan Wakely napisał(a): > On Thu, 27 Jun 2024 at 14:27, Maciej Cencora wrote: > > > > I think going the bit_cast way would be the best because it enables the > optimization for many more classes including common wrappers like optional, > variant, pair, tuple and std::array. > > This isn't tested but seems to work on simple cases. But for large > objects the loop hits the constexpr iteration limit and compilation > fails, so it needs a sizeof(_Tp) < 64 or something. > > using _ValueType > = typename iterator_traits<_ForwardIterator>::value_type; > using _Tp = remove_all_extents_t<_ValueType>; > // Need value-init to be equivalent to zero-init. > if constexpr (is_member_pointer<_Tp>::value) > return nullptr; > else if constexpr (!is_scalar<_Tp>::value) > { > using __trivial > = __and_, > is_trivially_constructible<_ValueType>>; > if constexpr (__trivial::value) > { > struct _Bytes > { > unsigned char __b[sizeof(_Tp)]; > > #if __cpp_constexpr >= 201304 > constexpr bool _M_nonzero() const > { > for (auto __c : __b) > if (__c) > return true; > return false; > } > #else > constexpr bool _M_nonzero(size_t __n = 0) const > { > return __n < sizeof(_Tp) > && (__b[__n] || _M_nonzero(__n + 1)); > } > #endif > }; > if constexpr (__builtin_bit_cast(_Bytes, _Tp())._M_nonzero()) > return nullptr; > } > } > using _Ptr = decltype(std::__to_address(__first)); > // Cannot use memset if _Ptr is cv-qualified. > if constexpr (is_convertible<_Ptr, void*>::value) > return std::__to_address(__first); > >
Re: [WIP RFC] libstdc++: add module std
Hi, Thanks for working on this! > stdc++.h also doesn't include the eternally deprecated . There are some other deprecated facilities that I notice are included: and float_denorm_style, at least. It would be nice for L{E,}WG to clarify whether module std is intended to include interfaces that were deprecated in C++23, since ancient code isn't going to be relying on module std. Per P2465r3 Standard Library Modules std and std.compat: Are deprecated features provided by the Standard Library modules? Yes. This is implied by the normative wording. While doing some light testing, one thing that immediately popped up is that we need to export __normal_iterator related operators from __gnu_cxx namespace. Otherwise it is impossible to even use std::vector in range-based for loops. But I think a better solution (than exporting such impl details) is to make these operators hidden friends. Another thing - P2465r3 mentions only lerp, byte and related ops as special w.r.t skipping export from global namespace in std.compat, but for some reason Microsoft's impl treats 3-arg hypot as special as well. Regards, Maciej Cencora
RE: [PATCH 2/2] libstdc++: Implement for C++26 (P3370R1)
Hi, two issues: 1) #include is missing in std.compat.cc.in 2) does the updated std.compat module actually work? When I experimented with implementing the std module in gcc, I couldn't #include standard headers, after they were imported via std module (since GMF merging isn't implemented yet), i.e. following doesn't work: import std; #include And that's exactly the scenario we have right now with your #include added to std.compat.cc.in ( transitively includes and transitively includes and ) Regards, Maciej
RE: [PATCH v2] libstdc++: Implement C++26 features (P2546R5)
Hi, unless I missed it, updates of std and std.compat modules are missing. Regards, Maciej
Re: [PATCH] c++, libstdc++: Implement C++26 P2830R10 - Constexpr Type Ordering
Hi, update of std module is missing. Regards, Maciej
[committed] libstdc++: Fix uses of non-reserved names in headers
Hi, instead of uglyfing all the libstdc++ code wouldn't it be simpler to just ignore all non-reserved macro expansions (+ some special ones like assert) inside system headers on compiler level? Regards, Maciej
Re: [committed] libstdc++: Simplify variant access functions
Hi, variant getter can be implemented in C++17 without using "recursive" calls, but by generating a list of member pointers and applying them with fold expression. Here's an example: https://godbolt.org/z/3vcKjWjPG Regards, Maciej
[PATCH] tree: Fix up tree_code_{length,type}
Hi, you can emulate C++17 inline variables in C++11 with either of the two ways: 1) via a template helper template struct Helper { static constexpr unsigned value[4] = {1, 2, 3, 4}; }; template constexpr unsigned Helper::value[4]; static constexpr auto& arr = Helper<>::value; 2) extern constexpr + weak attribute [[gnu::weak]] extern constexpr unsigned arr[] = {1, 2, 3, 4}; Regards, Maciej