On Fri, 29 Aug 2025, Richard Biener wrote: > On Fri, 29 Aug 2025, Jakub Jelinek wrote: > > > Hi! > > > > Here is a variant of the patch which pretends there are also stores > > in the inline asms. > > Plus the forgotten std.cc exports. > > Can you add a testcase on actual constant objects? I wonder why > we do not diagnose asm outputs on such?
In particular I wonder about void foo(int n) { const short a[8] = { 1,2,3,4,5,6,7,8 }; int sum = 0; for (int i = 0; i < n; ++i) { const int *p = std::start_lifetime_as<int> (a); sum += ((int *)a)[2]; } return sum; } I'd expect RTL LIM to hoist the ((int *)a)[2] load across the asm() as 'a' is readonly. GIMPLE alias analysis of course treats all asm()s with a VDEF as black-boxes. The hoisting would be a TBAA violation, possibly wrong-code if 'a' is put on the stack. Richard. > > 2025-08-29 Jakub Jelinek <ja...@redhat.com> > > > > * include/bits/version.def: Implement C++23 P2590R2 - Explicit > > lifetime management. > > (start_lifetime_as): New. > > * include/bits/version.h: Regenerate. > > * include/std/memory (std::start_lifetime_as, > > std::start_lifetime_as_array): New function templates. > > * src/c++23/std.cc.in (std::start_lifetime_as, > > std::start_lifetime_as_array): Export. > > * testsuite/std/memory/start_lifetime_as/start_lifetime_as.cc: New test. > > > > --- libstdc++-v3/include/bits/version.def.jj 2025-08-28 > > 17:06:44.190031458 +0200 > > +++ libstdc++-v3/include/bits/version.def 2025-08-28 18:44:00.947678928 > > +0200 > > @@ -2100,6 +2100,14 @@ ftms = { > > }; > > }; > > > > +ftms = { > > + name = start_lifetime_as; > > + values = { > > + v = 202207; > > + cxxmin = 23; > > + }; > > +}; > > + > > // Standard test specifications. > > stds[97] = ">= 199711L"; > > stds[03] = ">= 199711L"; > > --- libstdc++-v3/include/bits/version.h.jj 2025-08-28 17:06:49.160883915 > > +0200 > > +++ libstdc++-v3/include/bits/version.h 2025-08-28 18:44:08.431550790 > > +0200 > > @@ -2353,4 +2353,14 @@ > > #endif /* !defined(__cpp_lib_is_implicit_lifetime) && > > defined(__glibcxx_want_is_implicit_lifetime) */ > > #undef __glibcxx_want_is_implicit_lifetime > > > > +#if !defined(__cpp_lib_start_lifetime_as) > > +# if (__cplusplus >= 202100L) > > +# define __glibcxx_start_lifetime_as 202207L > > +# if defined(__glibcxx_want_all) || > > defined(__glibcxx_want_start_lifetime_as) > > +# define __cpp_lib_start_lifetime_as 202207L > > +# endif > > +# endif > > +#endif /* !defined(__cpp_lib_start_lifetime_as) && > > defined(__glibcxx_want_start_lifetime_as) */ > > +#undef __glibcxx_want_start_lifetime_as > > + > > #undef __glibcxx_want_all > > --- libstdc++-v3/include/std/memory.jj 2025-08-23 15:00:05.208775420 > > +0200 > > +++ libstdc++-v3/include/std/memory 2025-08-29 09:21:59.402103595 +0200 > > @@ -120,6 +120,7 @@ > > #define __glibcxx_want_shared_ptr_arrays > > #define __glibcxx_want_shared_ptr_weak_type > > #define __glibcxx_want_smart_ptr_for_overwrite > > +#define __glibcxx_want_start_lifetime_as > > #define __glibcxx_want_to_address > > #define __glibcxx_want_transparent_operators > > #define __glibcxx_want_smart_ptr_owner_equality > > @@ -172,6 +173,134 @@ _GLIBCXX_END_NAMESPACE_VERSION > > } // namespace > > #endif // C++11 to C++20 > > > > +#if __cpp_lib_start_lifetime_as >= 202207L // C++ >= 23 > > +namespace std _GLIBCXX_VISIBILITY(default) > > +{ > > +_GLIBCXX_BEGIN_NAMESPACE_VERSION > > + template<typename _Tp> > > + [[__gnu__::__always_inline__]] > > + inline _Tp* > > + start_lifetime_as(void* __p) noexcept > > + { > > +#if __cpp_lib_is_implicit_lifetime >= 202302L > > + static_assert(is_implicit_lifetime_v<_Tp>); > > +#endif > > + auto __q = reinterpret_cast<_Tp*>(__p); > > + __asm__ __volatile__("" : "=g" (__q), "=m" (*__q) > > + : "0" (__q), "m" (*__q)); > > + return __q; > > + } > > + > > + template<typename _Tp> > > + [[__gnu__::__always_inline__]] > > + inline const _Tp* > > + start_lifetime_as(const void* __p) noexcept > > + { > > +#if __cpp_lib_is_implicit_lifetime >= 202302L > > + static_assert(is_implicit_lifetime_v<_Tp>); > > +#endif > > + auto __q = reinterpret_cast<const _Tp*>(__p); > > + auto __r = reinterpret_cast<_Tp*>(const_cast<void*>(__p)); > > + __asm__ __volatile__("" : "=g" (__q), "=m" (*__r) > > + : "0" (__q), "m" (*__q)); > > + return __q; > > + } > > + > > + template<typename _Tp> > > + [[__gnu__::__always_inline__]] > > + inline volatile _Tp* > > + start_lifetime_as(volatile void* __p) noexcept > > + { > > +#if __cpp_lib_is_implicit_lifetime >= 202302L > > + static_assert(is_implicit_lifetime_v<_Tp>); > > +#endif > > + auto __q = reinterpret_cast<volatile _Tp*>(__p); > > + auto __r = reinterpret_cast<_Tp*>(const_cast<void*>(__p)); > > + __asm__ __volatile__("" : "=g" (__q), "=m" (*__r) > > + : "0" (__q), "m" (*__q)); > > + return __q; > > + } > > + > > + template<typename _Tp> > > + [[__gnu__::__always_inline__]] > > + inline const volatile _Tp* > > + start_lifetime_as(const volatile void* __p) noexcept > > + { > > +#if __cpp_lib_is_implicit_lifetime >= 202302L > > + static_assert(is_implicit_lifetime_v<_Tp>); > > +#endif > > + auto __q = reinterpret_cast<const volatile _Tp*>(__p); > > + auto __r = reinterpret_cast<_Tp*>(const_cast<void*>(__p)); > > + __asm__ __volatile__("" : "=g" (__q), "=m" (*__r) > > + : "0" (__q), "m" (*__q)); > > + return __q; > > + } > > + > > + template<typename _Tp> > > + [[__gnu__::__always_inline__]] > > + inline _Tp* > > + start_lifetime_as_array(void* __p, size_t __n) noexcept > > + { > > + auto __q = reinterpret_cast<_Tp*>(__p); > > + if (!__n) > > + return __q; > > + auto __r = (__extension__ reinterpret_cast<_Tp(*)[__n]>(__p)); > > + __asm__ __volatile__("" : "=g" (__q), "=m" (*__r) > > + : "0" (__q), "m" (*__r)); > > + return __q; > > + } > > + > > + template<typename _Tp> > > + [[__gnu__::__always_inline__]] > > + inline const _Tp* > > + start_lifetime_as_array(const void* __p, size_t __n) noexcept > > + { > > + auto __q = reinterpret_cast<const _Tp*>(__p); > > + if (!__n) > > + return __q; > > + auto __r = (__extension__ reinterpret_cast<const _Tp(*)[__n]>(__p)); > > + auto __s = (__extension__ > > + reinterpret_cast<_Tp(*)[__n]>(const_cast<void*>(__p))); > > + __asm__ __volatile__("" : "=g" (__q), "=m" (*__s) > > + : "0" (__q), "m" (*__r)); > > + return __q; > > + } > > + > > + template<typename _Tp> > > + [[__gnu__::__always_inline__]] > > + inline volatile _Tp* > > + start_lifetime_as_array(volatile void* __p, size_t __n) noexcept > > + { > > + auto __q = reinterpret_cast<volatile _Tp*>(__p); > > + if (!__n) > > + return __q; > > + auto __r = (__extension__ reinterpret_cast<volatile > > _Tp(*)[__n]>(__p)); > > + auto __s = (__extension__ > > + reinterpret_cast<_Tp(*)[__n]>(const_cast<void*>(__p))); > > + __asm__ __volatile__("" : "=g" (__q), "=m" (*__s) > > + : "0" (__q), "m" (*__r)); > > + return __q; > > + } > > + > > + template<typename _Tp> > > + [[__gnu__::__always_inline__]] > > + inline const volatile _Tp* > > + start_lifetime_as_array(const volatile void* __p, size_t __n) noexcept > > + { > > + auto __q = reinterpret_cast<const volatile _Tp*>(__p); > > + if (!__n) > > + return __q; > > + auto __r = (__extension__ reinterpret_cast<const volatile > > _Tp(*)[__n]>(__p)); > > + auto __s = (__extension__ > > + reinterpret_cast<_Tp(*)[__n]>(const_cast<void*>(__p))); > > + __asm__ __volatile__("" : "=g" (__q), "=m" (*__s) > > + : "0" (__q), "m" (*__r)); > > + return __q; > > + } > > +_GLIBCXX_END_NAMESPACE_VERSION > > +} // namespace > > +#endif > > + > > #ifdef __cpp_lib_parallel_algorithm // C++ >= 17 && HOSTED > > // Parallel STL algorithms > > # if _PSTL_EXECUTION_POLICIES_DEFINED > > --- libstdc++-v3/src/c++23/std.cc.in.jj 2025-08-28 17:10:43.784942152 > > +0200 > > +++ libstdc++-v3/src/c++23/std.cc.in 2025-08-29 09:55:46.164636222 > > +0200 > > @@ -2004,6 +2004,10 @@ export namespace std > > using std::owner_equal; > > using std::owner_hash; > > #endif > > +#if __cpp_lib_start_lifetime_as > > + using std::start_lifetime_as; > > + using std::start_lifetime_as_array; > > +#endif > > } > > > > // 20.4 <memory_resource> > > --- > > libstdc++-v3/testsuite/std/memory/start_lifetime_as/start_lifetime_as.cc.jj > > 2025-08-28 19:29:12.865001523 +0200 > > +++ > > libstdc++-v3/testsuite/std/memory/start_lifetime_as/start_lifetime_as.cc > > 2025-08-28 19:56:44.975864728 +0200 > > @@ -0,0 +1,68 @@ > > +// { dg-do run { target c++23 } } > > + > > +#include <bit> > > +#include <memory> > > + > > +#include <testsuite_hooks.h> > > +#include <testsuite_allocator.h> > > + > > +struct S { int a; int b; }; > > +struct T { long long c; }; > > + > > +void > > +test01() > > +{ > > + if (sizeof(S) != sizeof(T)) > > + return; > > + > > + union U { unsigned char a[sizeof(S)]; S b; T c; } u; > > + u.a[0] = 1; > > + T v = std::bit_cast<T> (S{1, 2}); > > + union V { unsigned char a[3 * sizeof(S)]; S b[3]; T c[3]; } w; > > + T x = std::bit_cast<T> (S{3, 4}); > > + T y = std::bit_cast<T> (S{5, 6}); > > + S* d = std::start_lifetime_as<S>(reinterpret_cast<void*>(&u.a)); > > + d->a = 1; > > + d->b = 2; > > + T* e = std::start_lifetime_as<T>(reinterpret_cast<void*>(d)); > > + VERIFY( e->c == v.c ); > > + const T* f = std::start_lifetime_as<T>(reinterpret_cast<const void*>(d)); > > + VERIFY( f->c == v.c ); > > + volatile T* g = std::start_lifetime_as<T>(reinterpret_cast<volatile > > void*>(d)); > > + VERIFY( g->c == v.c ); > > + const volatile T* h = std::start_lifetime_as<T>(reinterpret_cast<const > > volatile void*>(d)); > > + VERIFY( h->c == v.c ); > > + S* i = std::start_lifetime_as_array<S>(reinterpret_cast<void*>(&w.a), 3); > > + i[0].a = 1; > > + i[0].b = 2; > > + i[1].a = 3; > > + i[1].b = 4; > > + i[2].a = 5; > > + i[2].b = 6; > > + T* j = std::start_lifetime_as_array<T>(reinterpret_cast<void*>(i), 3); > > + VERIFY( j[0].c == v.c && j[1].c == x.c && j[2].c == y.c ); > > + const T* k = std::start_lifetime_as_array<T>(reinterpret_cast<const > > void*>(i), 3); > > + VERIFY( k[0].c == v.c && k[1].c == x.c && k[2].c == y.c ); > > + volatile T* l = > > std::start_lifetime_as_array<T>(reinterpret_cast<volatile void*>(i), 3); > > + VERIFY( l[0].c == v.c && l[1].c == x.c && l[2].c == y.c ); > > + const volatile T* m = > > std::start_lifetime_as_array<T>(reinterpret_cast<const volatile void*>(i), > > 3); > > + VERIFY( m[0].c == v.c && m[1].c == x.c && m[2].c == y.c ); > > + T* n = std::start_lifetime_as_array<T>(static_cast<void*>(nullptr), 0); > > + VERIFY( n == nullptr ); > > + const T* o = std::start_lifetime_as_array<T>(static_cast<const > > void*>(nullptr), 0); > > + VERIFY( o == nullptr ); > > + volatile T* p = std::start_lifetime_as_array<T>(static_cast<volatile > > void*>(nullptr), 0); > > + VERIFY( p == nullptr ); > > + const volatile T* q = std::start_lifetime_as_array<T>(static_cast<const > > volatile void*>(nullptr), 0); > > + VERIFY( q == nullptr ); > > + VERIFY( std::start_lifetime_as_array<T>(reinterpret_cast<void*>(&w.a), > > 0) == &w.c[0] ); > > + VERIFY( std::start_lifetime_as_array<T>(reinterpret_cast<const > > void*>(&w.a), 0) == static_cast<const T*>(&w.c[0]) ); > > + VERIFY( std::start_lifetime_as_array<T>(reinterpret_cast<volatile > > void*>(&w.a), 0) == static_cast<volatile T*>(&w.c[0]) ); > > + VERIFY( std::start_lifetime_as_array<T>(reinterpret_cast<const volatile > > void*>(&w.a), 0) == static_cast<const volatile T*>(&w.c[0]) ); > > +} > > + > > +int > > +main() > > +{ > > + test01(); > > +} > > > > Jakub > > > > > > -- Richard Biener <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)