Message ID | 6704f905.170a0220.38d3dc.1276@mx.google.com |
---|---|
State | New |
Headers | show |
Series | libgcc: Use inline variable instead of function-local static | expand |
On Tue, Oct 08, 2024 at 08:18:56PM +1100, Nathaniel Shead wrote: > On Tue, Oct 01, 2024 at 12:36:21PM +0200, Jakub Jelinek wrote: > > On Tue, Oct 01, 2024 at 11:10:03AM +0100, Jonathan Wakely wrote: > > > Let's use an inline variable. A function-local static requires > > > __cxa_guard_acquire, which (for some targets, including the ones > > > affected by this change) uses __gthread_active_p which will > > > recursively re-enter the variable's initialization. > > > > > > So something like: > > > > > > #pragma GCC diagnostic push > > > #pragma GCC diagnostic ignored "-Wc++17-extensions" > > > inline volatile int __gthread_active = -1; > > > #pragma GCC diagnostic pop > > > > Note, only for #ifdef __cplusplus, for C there is no such thing as inline > > variables and in that case it should use > > static volatile int __ghtread_active = -1; > > instead. > > > > Jakub > > > > So something like this maybe; bootstrapped and regtested on > x86_64-pc-linux-gnu and aarch64-unknown-linux-gnu, OK for trunk? > > Or maybe it would be clearer to do the #ifdef __cplusplus here locally > rather than introducing a new __GTHREAD_VAR macro? Actually, had a look again at this and I don't see what this is trying to fix. A function-local static requires __cxa_guard_acquire only if it needs dynamic initialization, which is not the case here (the initializers are = -1). The non-dynamic ones are just initialized that way without any __cxa_guard_acquire. So, the function-local static seems more portable than hoping inline vars will be supported even for older C++ versions. Jakub
On Tue, 8 Oct 2024 at 10:28, Jakub Jelinek <jakub@redhat.com> wrote: > > On Tue, Oct 08, 2024 at 08:18:56PM +1100, Nathaniel Shead wrote: > > On Tue, Oct 01, 2024 at 12:36:21PM +0200, Jakub Jelinek wrote: > > > On Tue, Oct 01, 2024 at 11:10:03AM +0100, Jonathan Wakely wrote: > > > > Let's use an inline variable. A function-local static requires > > > > __cxa_guard_acquire, which (for some targets, including the ones > > > > affected by this change) uses __gthread_active_p which will > > > > recursively re-enter the variable's initialization. > > > > > > > > So something like: > > > > > > > > #pragma GCC diagnostic push > > > > #pragma GCC diagnostic ignored "-Wc++17-extensions" > > > > inline volatile int __gthread_active = -1; > > > > #pragma GCC diagnostic pop > > > > > > Note, only for #ifdef __cplusplus, for C there is no such thing as inline > > > variables and in that case it should use > > > static volatile int __ghtread_active = -1; > > > instead. > > > > > > Jakub > > > > > > > So something like this maybe; bootstrapped and regtested on > > x86_64-pc-linux-gnu and aarch64-unknown-linux-gnu, OK for trunk? > > > > Or maybe it would be clearer to do the #ifdef __cplusplus here locally > > rather than introducing a new __GTHREAD_VAR macro? > > Actually, had a look again at this and I don't see what this is trying to > fix. > A function-local static requires __cxa_guard_acquire only if it needs > dynamic initialization, which is not the case here (the initializers are > = -1). The non-dynamic ones are just initialized that way without any > __cxa_guard_acquire. Whoops, yes of course. Raising the topic of __cxa_guard_acquire was my fault, and doesn't apply here, sorry. But we still want to get rid of the STB_GNU_UNIQUE binding for the static variables, don't we? I've lost track a bit, so please correct me if I've got this wrong: We originally had global static variables, which means a different variable per TU. That causes ODR violations which were silently ignored until we try to use them in modules, where they're diagnosed. So we need to replace them. Currently on trunk we have local statics, which avoid the ODR violations, but emit STB_GNU_UNIQUE symbols, which are not zero-cost. (There are no __cxa_guard_acquire issues, that was just my mistake.) Jason suggested inline variables instead of local statics. That just uses vague linkage for them (comdat), so no STB_GNU_UNIQUE, right? Whether we choose local static or inline globals, these symbols will now be visible across TUs and so become part of the ABI. Previously they weren't, because every TU had its own copy which was manipulated by always_inline static functions. That meant each TU had to initialize its own variable, so we did the pthread_once trigger multiple times (once per TU). But we could change the type of the variable or the body of the always_inline static functions because nothing affected other TUs. Whatever we do now, solving the ODR violations for modules seems to require sharing variables between TUs in one way or another, right? > > So, the function-local static seems more portable than hoping inline vars > will be supported even for older C++ versions. > > Jakub >
On Tue, Oct 08, 2024 at 10:57:06AM +0100, Jonathan Wakely wrote: > Whoops, yes of course. Raising the topic of __cxa_guard_acquire was my > fault, and doesn't apply here, sorry. > > But we still want to get rid of the STB_GNU_UNIQUE binding for the > static variables, don't we? I think it is the other way around. At least when I try: static inline volatile int *foo (void) { static volatile int v = -1; return &v; } inline volatile int z = -1; volatile int *p = foo (); z is STB_GNU_UNIQUE, _ZZL3foovE1v is not. Whether that is a bug or not, I don't know... Jakub
On Tue, 8 Oct 2024 at 11:11, Jakub Jelinek <jakub@redhat.com> wrote: > > On Tue, Oct 08, 2024 at 10:57:06AM +0100, Jonathan Wakely wrote: > > Whoops, yes of course. Raising the topic of __cxa_guard_acquire was my > > fault, and doesn't apply here, sorry. > > > > But we still want to get rid of the STB_GNU_UNIQUE binding for the > > static variables, don't we? > > I think it is the other way around. At least when I try: > static inline volatile int *foo (void) { static volatile int v = -1; return &v; } > inline volatile int z = -1; > volatile int *p = foo (); > > z is STB_GNU_UNIQUE, _ZZL3foovE1v is not. Whether that is a bug or not, I > don't know... But that's because foo() is declared static, which we can't do because of C++ modules. That was the original problem Nathaniel was fixing. If you remove the 'static' from foo() then both z and _ZZ3foovE1v use @gnu_unique_object
On Tue, Oct 08, 2024 at 11:32:16AM +0100, Jonathan Wakely wrote: > But that's because foo() is declared static, which we can't do because > of C++ modules. That was the original problem Nathaniel was fixing. > > If you remove the 'static' from foo() then both z and _ZZ3foovE1v use > @gnu_unique_object Oops, pilot error. Jakub
Hello, On Tue, 8 Oct 2024, Jonathan Wakely wrote: > We originally had global static variables, which means a different > variable per TU. That causes ODR violations which were silently > ignored until we try to use them in modules, where they're diagnosed. > So we need to replace them. Aren't these variables implementation detail? If so violating language rules like ODR should be okay. (Imagine libgcc would be written in some language where such rules doesn't exist). So isn't the actual problem that needs solving rather that c++ modules trip over these here? Ciao, Michael.
On Tue, 8 Oct 2024 at 13:59, Michael Matz <matz@suse.de> wrote: > > Hello, > > On Tue, 8 Oct 2024, Jonathan Wakely wrote: > > > We originally had global static variables, which means a different > > variable per TU. That causes ODR violations which were silently > > ignored until we try to use them in modules, where they're diagnosed. > > So we need to replace them. > > Aren't these variables implementation detail? If so violating language > rules like ODR should be okay. (Imagine libgcc would be written in some > language where such rules doesn't exist). > > So isn't the actual problem that needs solving rather that c++ modules > trip over these here? Yes, I was thinking the same thing. Maybe we need a new attribute that tells the front end not to diagnose the ODR violations for these even in C++ modules.
On 10/8/24 8:58 AM, Michael Matz wrote: > Hello, > > On Tue, 8 Oct 2024, Jonathan Wakely wrote: > >> We originally had global static variables, which means a different >> variable per TU. That causes ODR violations which were silently >> ignored until we try to use them in modules, where they're diagnosed. >> So we need to replace them. > > Aren't these variables implementation detail? If so violating language > rules like ODR should be okay. (Imagine libgcc would be written in some > language where such rules doesn't exist). > > So isn't the actual problem that needs solving rather that c++ modules > trip over these here? That's an interesting point; we need to handle internal variables in header units, I'm not sure how much trouble it would be to provide a way to suppress the exposure diagnostic for particular statics in a named module. Jason
diff --git a/libgcc/gthr-posix.h b/libgcc/gthr-posix.h index 478bcf4cee6..b24992a539f 100644 --- a/libgcc/gthr-posix.h +++ b/libgcc/gthr-posix.h @@ -55,8 +55,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #ifdef __cplusplus # define __GTHREAD_INLINE inline __GTHREAD_ALWAYS_INLINE +# define __GTHREAD_VAR inline #else # define __GTHREAD_INLINE static inline +# define __GTHREAD_VAR static #endif typedef pthread_t __gthread_t; @@ -198,18 +200,16 @@ __gthrw(pthread_setschedparam) #if defined(__FreeBSD__) || (defined(__sun) && defined(__svr4__)) #pragma GCC visibility push(hidden) -__GTHREAD_INLINE volatile int * -__gthread_active (void) -{ - static volatile int __gthread_active_var = -1; - return &__gthread_active_var; -} +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" +__GTHREAD_VAR volatile int * __gthread_active = -1; +#pragma GCC diagnostic pop #pragma GCC visibility pop __GTHREAD_INLINE void __gthread_trigger (void) { - *__gthread_active () = 1; + *__gthread_active = 1; } #pragma GCC visibility push(hidden) @@ -220,7 +220,7 @@ __gthread_active_p (void) static pthread_once_t __gthread_active_once = PTHREAD_ONCE_INIT; /* Avoid reading __gthread_active twice on the main code path. */ - int __gthread_active_latest_value = *__gthread_active (); + int __gthread_active_latest_value = *__gthread_active; /* This test is not protected to avoid taking a lock on the main code path so every update of __gthread_active in a threaded program must @@ -237,10 +237,10 @@ __gthread_active_p (void) } /* Make sure we'll never enter this block again. */ - if (*__gthread_active () < 0) - *__gthread_active () = 0; + if (*__gthread_active < 0) + *__gthread_active = 0; - __gthread_active_latest_value = *__gthread_active (); + __gthread_active_latest_value = *__gthread_active; } return __gthread_active_latest_value != 0; @@ -315,26 +315,24 @@ __gthread_active_p (void) #if defined(__hppa__) && defined(__hpux__) #pragma GCC visibility push(hidden) -__GTHREAD_INLINE volatile int * -__gthread_active (void) -{ - static volatile int __gthread_active_var = -1; - return &__gthread_active_var; -} +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" +__GTHREAD_VAR volatile int * __gthread_active = -1; +#pragma GCC diagnostic pop #pragma GCC visibility pop __GTHREAD_INLINE int __gthread_active_p (void) { /* Avoid reading __gthread_active twice on the main code path. */ - int __gthread_active_latest_value = *__gthread_active (); + int __gthread_active_latest_value = *__gthread_active; size_t __s; if (__builtin_expect (__gthread_active_latest_value < 0, 0)) { pthread_default_stacksize_np (0, &__s); - *__gthread_active () = __s ? 1 : 0; - __gthread_active_latest_value = *__gthread_active (); + *__gthread_active = __s ? 1 : 0; + __gthread_active_latest_value = *__gthread_active; } return __gthread_active_latest_value != 0; @@ -980,6 +978,7 @@ __gthread_rwlock_unlock (__gthread_rwlock_t *__rwlock) #endif /* _LIBOBJC */ +#undef __GTHREAD_VAR #undef __GTHREAD_INLINE #undef __GTHREAD_ALWAYS_INLINE