On Mon, 8 Sep 2025, H.J. Lu wrote:
> Don't check tls_model attribute when optimizing TLS access since > > 1. -ftls-model=initial-exec also can specify tls_model without tls_model > attribute. There's a difference: -ftls-model is usable only for upgrading the model; if you pass -ftls-model=global-dynamic without -fpic, you still get local-exec or initial-exec. Just a correction in case you missed it. > 2. Linker can optimize TLS access at link-time. > 3. LTO should perform the similar optimization. I generally agree that GCC should perform this optimization. That said, with this patch we arrive at a situation with both a) ld.bfd does not obey --no-relax to switch off TLS relaxation, and b) gcc unconditionally performs TLS access optimization which makes investigation of TLS-related toolchain bugs difficult. Would you consider adding a GCC flag to control this optimization? And using the flag in the testcases? > Since C, C++, and Fortran front-ends now set the TLS access model after > a variable has been fully processed, not in the middle of processing it, > partially revert > > commit 82e629c26647313be406c41a01e6868cfad0f289 > Author: Alexander Monakov <amona...@ispras.ru> > Date: Wed Oct 26 16:37:34 2022 +0300 > > ipa-visibility: remove assert in TLS optimization [PR107353] > > to restore assert if not compiling for shared library. When compiling > for shared library, the recomputed model may be weaker. I don't understand why (for shared libraries), can you explain? > Linker may > issue an error if the front-end assigned model isn't supported in shared > library. But compiler doesn't know if the generated code will be linked > into executable or shared library. > > gcc/ > > PR other/107353 > PR middle-end/121352 > * ipa-visibility.cc (function_and_variable_visibility): Don't > check tls_model attribute. Restore assert if not compiling for > shared library. > * doc/extend.texi: Update the tls_model attribute. > > gcc/testsuite/ > > PR middle-end/121352 > * gcc.dg/tls/vis-attr-hidden-gd.c: Scan for tls-local-dynamic. > * gcc.dg/tls/vis-flag-hidden-gd.c: Likewise. > * gcc.dg/tls/vis-pragma-hidden-gd.c: Likewise. > > Signed-off-by: H.J. Lu <hjl.to...@gmail.com> > --- > gcc/doc/extend.texi | 5 ++++- > gcc/ipa-visibility.cc | 19 ++++++++++++------- > gcc/testsuite/gcc.dg/tls/vis-attr-hidden-gd.c | 4 ++-- > gcc/testsuite/gcc.dg/tls/vis-flag-hidden-gd.c | 4 ++-- > .../gcc.dg/tls/vis-pragma-hidden-gd.c | 4 ++-- > 5 files changed, 22 insertions(+), 14 deletions(-) > > diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi > index 2922d9e9839..879a759714b 100644 > --- a/gcc/doc/extend.texi > +++ b/gcc/doc/extend.texi > @@ -7563,7 +7563,10 @@ The @code{tls_model} attribute sets thread-local > storage model > overriding @option{-ftls-model=} command-line switch on a per-variable > basis. > The @var{tls_model} argument should be one of @code{global-dynamic}, > -@code{local-dynamic}, @code{initial-exec} or @code{local-exec}. > +@code{local-dynamic}, @code{initial-exec} or @code{local-exec}. The > +@code{tls_model} attribute specifies the weakest @acronym{TLS} access > +model. GCC may optimize @acronym{TLS} access to a stronger @acronym{TLS} > +access model. I think with this patch the attribute does not fully override the -ftls-model option. If so, the 'overriding' claim in the previous paragraph should be changed. If you add a command-line flag to control the optimization, this section will have to be reworded. > > Not all targets support this attribute. > > diff --git a/gcc/ipa-visibility.cc b/gcc/ipa-visibility.cc > index 8097a03e240..d2283507a31 100644 > --- a/gcc/ipa-visibility.cc > +++ b/gcc/ipa-visibility.cc > @@ -883,17 +883,22 @@ function_and_variable_visibility (bool whole_program) > tree decl = vnode->decl; > > /* Upgrade TLS access model based on optimized visibility status, > - unless it was specified explicitly or no references remain. */ > + unless no references remain. */ > if (DECL_THREAD_LOCAL_P (decl) > - && !lookup_attribute ("tls_model", DECL_ATTRIBUTES (decl)) > && vnode->ref_list.referring.length ()) > { > enum tls_model new_model = decl_default_tls_model (decl); > - STATIC_ASSERT (TLS_MODEL_GLOBAL_DYNAMIC < > TLS_MODEL_LOCAL_DYNAMIC); > - STATIC_ASSERT (TLS_MODEL_INITIAL_EXEC < TLS_MODEL_LOCAL_EXEC); > - /* We'd prefer to assert that recomputed model is not weaker than > - what the front-end assigned, but cannot: see PR 107353. */ > - if (new_model >= decl_tls_model (decl)) > + /* Assert that the recomputed model is not weaker than > + what the front-end assigned if not comping for shared > + library. When compiling for shared library, the > + recomputed model may be weaker. Linker may issue an > + error if the front-end assigned model isn't supported > + in shared library. But compiler doesn't know if the > + generated code will be linked into executable or shared > + library. */ > + tls_model model = decl_tls_model (decl); > + gcc_checking_assert (flag_shlib || new_model >= model); I think this can trip if a variable is redeclared such that initial declaration implies a stronger model: // compile with gcc -O2 -std=c11 -fno-common __thread int x; __attribute__((common)) __thread int x; int *f() { return &x; } Can you check? Thanks. Alexander > + if (new_model > model) > set_decl_tls_model (decl, new_model); > } > } > diff --git a/gcc/testsuite/gcc.dg/tls/vis-attr-hidden-gd.c > b/gcc/testsuite/gcc.dg/tls/vis-attr-hidden-gd.c > index e32565588c8..4512bff04ad 100644 > --- a/gcc/testsuite/gcc.dg/tls/vis-attr-hidden-gd.c > +++ b/gcc/testsuite/gcc.dg/tls/vis-attr-hidden-gd.c > @@ -3,11 +3,11 @@ > /* { dg-require-effective-target tls } */ > /* { dg-options "-O2 -fPIC -fdump-ipa-whole-program" } */ > > -// tls_model should be global-dynamic due to explicitly specified attribute > __attribute__((visibility("hidden"))) > __attribute__((tls_model("global-dynamic"))) > __thread int x; > > void reference() { x++; } > > -/* { dg-final { scan-ipa-dump "Varpool flags: tls-global-dynamic" > "whole-program" } } */ > +// tls_model should be local-dynamic due to hidden visibility. > +/* { dg-final { scan-ipa-dump "Varpool flags: tls-local-dynamic" > "whole-program" } } */ > diff --git a/gcc/testsuite/gcc.dg/tls/vis-flag-hidden-gd.c > b/gcc/testsuite/gcc.dg/tls/vis-flag-hidden-gd.c > index cad41e0c8e6..fba79cfd75a 100644 > --- a/gcc/testsuite/gcc.dg/tls/vis-flag-hidden-gd.c > +++ b/gcc/testsuite/gcc.dg/tls/vis-flag-hidden-gd.c > @@ -4,10 +4,10 @@ > /* { dg-options "-O2 -fPIC -fdump-ipa-whole-program -fvisibility=hidden" } */ > > > -// tls_model should be global-dynamic due to explicitly specified attribute > __attribute__((tls_model("global-dynamic"))) > __thread int x; > > void reference() { x++; } > > -/* { dg-final { scan-ipa-dump "Varpool flags: tls-global-dynamic" > "whole-program" } } */ > +// tls_model should be local-dynamic due to hidden visibility. > +/* { dg-final { scan-ipa-dump "Varpool flags: tls-local-dynamic" > "whole-program" } } */ > diff --git a/gcc/testsuite/gcc.dg/tls/vis-pragma-hidden-gd.c > b/gcc/testsuite/gcc.dg/tls/vis-pragma-hidden-gd.c > index 3b3598134fe..3649b6f7272 100644 > --- a/gcc/testsuite/gcc.dg/tls/vis-pragma-hidden-gd.c > +++ b/gcc/testsuite/gcc.dg/tls/vis-pragma-hidden-gd.c > @@ -6,7 +6,6 @@ > > #pragma GCC visibility push(hidden) > > -// tls_model should be global-dynamic due to explicitly specified attribute > __attribute__((tls_model("global-dynamic"))) > __thread int x; > > @@ -14,4 +13,5 @@ __thread int x; > > void reference() { x++; } > > -/* { dg-final { scan-ipa-dump "Varpool flags: tls-global-dynamic" > "whole-program" } } */ > +// tls_model should be local-dynamic due to hidden visibility. > +/* { dg-final { scan-ipa-dump "Varpool flags: tls-local-dynamic" > "whole-program" } } */ >