* C++ PATCH for target/54908 (thread_local vs emutls) @ 2012-10-15 7:38 Jason Merrill 2013-01-18 22:29 ` Jason Merrill 0 siblings, 1 reply; 6+ messages in thread From: Jason Merrill @ 2012-10-15 7:38 UTC (permalink / raw) To: gcc-patches List; +Cc: Jack Howarth, Dominique Dhumieres [-- Attachment #1: Type: text/plain, Size: 379 bytes --] This patch completely rewrites atexit_thread.cc to use __gthread_getspecific/setspecific rather than a thread_local variable to store the cleanup list, so that the list won't vanish if emutls_destroy runs first. With this patch all the TLS tests pass on i686-pc-linux-gnu configured with --disable-tls to force use of emutls. Tested x86_64-pc-linux-gnu, applying to trunk. [-- Attachment #2: atexit-setspecific.patch --] [-- Type: text/x-patch, Size: 5351 bytes --] commit 8735583f399914e92f126d98c120aba317f6626a Author: Jason Merrill <jason@redhat.com> Date: Mon Oct 8 10:50:20 2012 -0400 PR target/54908 * libsupc++/atexit_thread.cc: Rewrite to keep the cleanup list with get/setspecific. Destroy the key on dlclose. diff --git a/gcc/testsuite/g++.dg/tls/thread_local7g.C b/gcc/testsuite/g++.dg/tls/thread_local7g.C index 6960598..3479aeb 100644 --- a/gcc/testsuite/g++.dg/tls/thread_local7g.C +++ b/gcc/testsuite/g++.dg/tls/thread_local7g.C @@ -3,7 +3,7 @@ // { dg-require-alias } // The reference temp should be TLS, not normal data. -// { dg-final { scan-assembler-not "\\.data" } } +// { dg-final { scan-assembler-not "\\.data" { target tls_native } } } thread_local int&& ir = 42; diff --git a/libstdc++-v3/libsupc++/atexit_thread.cc b/libstdc++-v3/libsupc++/atexit_thread.cc index 5e47708..95bdcf0 100644 --- a/libstdc++-v3/libsupc++/atexit_thread.cc +++ b/libstdc++-v3/libsupc++/atexit_thread.cc @@ -27,109 +27,92 @@ #include "bits/gthr.h" namespace { - // Data structure for the list of destructors: Singly-linked list - // of arrays. - class list + // One element in a singly-linked stack of cleanups. + struct elt { - struct elt - { - void *object; - void (*destructor)(void *); - }; - - static const int max_nelts = 32; - - list *next; - int nelts; - elt array[max_nelts]; - - elt *allocate_elt(); - public: - void run(); - static void run(void *p); - int add_elt(void (*)(void *), void *); + void (*destructor)(void *); + void *object; + elt *next; }; - // Return the address of an open slot. - list::elt * - list::allocate_elt() - { - if (nelts < max_nelts) - return &array[nelts++]; - if (!next) - next = new (std::nothrow) list(); - if (!next) - return 0; - return next->allocate_elt(); - } - - // Run all the cleanups in the list. - void - list::run() - { - for (int i = nelts - 1; i >= 0; --i) - array[i].destructor (array[i].object); - if (next) - next->run(); - } - - // Static version to use as a callback to __gthread_key_create. - void - list::run(void *p) - { - static_cast<list *>(p)->run(); - } - - // The list of cleanups is per-thread. - thread_local list first; - - // The pthread data structures for actually running the destructors at - // thread exit are shared. The constructor of the thread-local sentinel - // object in add_elt performs the initialization. + // Keep a per-thread list of cleanups in gthread_key storage. __gthread_key_t key; - __gthread_once_t once = __GTHREAD_ONCE_INIT; - void run_current () { first.run(); } + // But also support non-threaded mode. + elt *single_thread; + + // Run the specified stack of cleanups. + void run (void *p) + { + elt *e = static_cast<elt*>(p); + for (; e; e = e->next) + e->destructor (e->object); + } + + // Run the stack of cleanups for the current thread. + void run () + { + void *e; + if (__gthread_active_p ()) + e = __gthread_getspecific (key); + else + e = single_thread; + run (e); + } + + // Initialize the key for the cleanup stack. We use a static local for + // key init/delete rather than atexit so that delete is run on dlclose. void key_init() { - __gthread_key_create (&key, list::run); + struct key_s { + key_s() { __gthread_key_create (&key, run); } + ~key_s() { __gthread_key_delete (key); } + }; + static key_s ks; // Also make sure the destructors are run by std::exit. // FIXME TLS cleanups should run before static cleanups and atexit // cleanups. - std::atexit (run_current); + std::atexit (run); } - struct sentinel - { - sentinel() +} + +extern "C" int +__cxxabiv1::__cxa_thread_atexit (void (*dtor)(void *), void *obj, void */*dso_handle*/) + _GLIBCXX_NOTHROW +{ + // Do this initialization once. + if (__gthread_active_p ()) { - if (__gthread_active_p ()) + // When threads are active use __gthread_once. + static __gthread_once_t once = __GTHREAD_ONCE_INIT; + __gthread_once (&once, key_init); + } + else + { + // And when threads aren't active use a static local guard. + static bool queued; + if (!queued) { - __gthread_once (&once, key_init); - __gthread_setspecific (key, &first); + queued = true; + std::atexit (run); } - else - std::atexit (run_current); } - }; - // Actually insert an element. - int - list::add_elt(void (*dtor)(void *), void *obj) - { - thread_local sentinel s; - elt *e = allocate_elt (); - if (!e) - return -1; - e->object = obj; - e->destructor = dtor; - return 0; - } -} + elt *first; + if (__gthread_active_p ()) + first = static_cast<elt*>(__gthread_getspecific (key)); + else + first = single_thread; + + elt *new_elt = new (std::nothrow) elt; + if (!new_elt) + return -1; + new_elt->destructor = dtor; + new_elt->object = obj; + new_elt->next = first; + + if (__gthread_active_p ()) + __gthread_setspecific (key, new_elt); + else + single_thread = new_elt; -namespace __cxxabiv1 -{ - extern "C" int - __cxa_thread_atexit (void (*dtor)(void *), void *obj, void */*dso_handle*/) - _GLIBCXX_NOTHROW - { - return first.add_elt (dtor, obj); - } + return 0; } ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: C++ PATCH for target/54908 (thread_local vs emutls) 2012-10-15 7:38 C++ PATCH for target/54908 (thread_local vs emutls) Jason Merrill @ 2013-01-18 22:29 ` Jason Merrill 2013-01-19 2:20 ` Jack Howarth 0 siblings, 1 reply; 6+ messages in thread From: Jason Merrill @ 2013-01-18 22:29 UTC (permalink / raw) To: gcc-patches List; +Cc: Jack Howarth, Dominique Dhumieres [-- Attachment #1: Type: text/plain, Size: 631 bytes --] I've been thinking about how to deal with the problems with calling initialization functions in another translation unit; namely, that it's significant overhead even for cases where it isn't useful, and that it requires alias and weak reference support. This patch introduces a new flag -fno-extern-tls-init that allows the user to disable support for calling a lazy initialization function in a different translation unit to avoid the overhead. It also disables it by default for targets without support for aliases or weak references. Tested x86_64-pc-linux-gnu. Jack, does this fix the thread_local tests on Darwin? [-- Attachment #2: 54908.patch --] [-- Type: text/x-patch, Size: 8629 bytes --] commit b3cf0f73d853bb9f0d5bfde22995eafc244210d3 Author: Jason Merrill <jason@redhat.com> Date: Thu Jan 17 06:15:22 2013 -0500 PR target/54908 c-family/ * c.opt (-fextern-tls-init): New. * c-opts.c (c_common_post_options): Handle it. cp/ * decl2.c (get_local_tls_init_fn): New. (get_tls_init_fn): Handle flag_extern_tls_init. Don't bother with aliases for internal variables. Don't use weakrefs if the variable needs destruction. (generate_tls_wrapper): Mark the wrapper as const if no initialization is needed. (handle_tls_init): Don't require aliases. diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c index 3fabb36..1a922a8 100644 --- a/gcc/c-family/c-opts.c +++ b/gcc/c-family/c-opts.c @@ -901,6 +901,20 @@ c_common_post_options (const char **pfilename) else if (warn_narrowing == -1) warn_narrowing = 0; + if (flag_extern_tls_init) + { +#if !defined (ASM_OUTPUT_DEF) || !SUPPORTS_WEAK + /* Lazy TLS initialization for a variable in another TU requires + alias and weak reference support. */ + if (flag_extern_tls_init > 0) + sorry ("external TLS initialization functions not supported " + "on this target"); + flag_extern_tls_init = 0; +#else + flag_extern_tls_init = 1; +#endif + } + if (flag_preprocess_only) { /* Open the output now. We must do so even if flag_no_output is diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 187f3be..10ae84d 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -913,6 +913,9 @@ finput-charset= C ObjC C++ ObjC++ Joined RejectNegative -finput-charset=<cset> Specify the default character set for source files +fextern-tls-init +C++ ObjC++ Var(flag_extern_tls_init) Init(-1) +Support dynamic initialization of thread-local variables in a different translation unit fexternal-templates C++ ObjC++ Ignore Warn(switch %qs is no longer supported) diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 619d30d..4496395 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -2812,6 +2812,28 @@ var_needs_tls_wrapper (tree var) && !var_defined_without_dynamic_init (var)); } +/* Get the FUNCTION_DECL for the shared TLS init function for this + translation unit. */ + +static tree +get_local_tls_init_fn (void) +{ + tree sname = get_identifier ("__tls_init"); + tree fn = IDENTIFIER_GLOBAL_VALUE (sname); + if (!fn) + { + fn = build_lang_decl (FUNCTION_DECL, sname, + build_function_type (void_type_node, + void_list_node)); + SET_DECL_LANGUAGE (fn, lang_c); + TREE_PUBLIC (fn) = false; + DECL_ARTIFICIAL (fn) = true; + mark_used (fn); + SET_IDENTIFIER_GLOBAL_VALUE (sname, fn); + } + return fn; +} + /* Get a FUNCTION_DECL for the init function for the thread_local variable VAR. The init function will be an alias to the function that initializes all the non-local TLS variables in the translation @@ -2824,6 +2846,18 @@ get_tls_init_fn (tree var) if (!var_needs_tls_wrapper (var)) return NULL_TREE; + /* If -fno-extern-tls-init, assume that we don't need to call + a tls init function for a variable defined in another TU. */ + if (!flag_extern_tls_init && DECL_EXTERNAL (var)) + return NULL_TREE; + +#ifdef ASM_OUTPUT_DEF + /* If the variable is internal, or if we can't generate aliases, + call the local init function directly. */ + if (!TREE_PUBLIC (var)) +#endif + return get_local_tls_init_fn (); + tree sname = mangle_tls_init_fn (var); tree fn = IDENTIFIER_GLOBAL_VALUE (sname); if (!fn) @@ -2841,11 +2875,12 @@ get_tls_init_fn (tree var) if (TREE_PUBLIC (var)) { tree obtype = strip_array_types (non_reference (TREE_TYPE (var))); - /* If the variable might have static initialization, make the - init function a weak reference. */ + /* If the variable is defined somewhere else and might have static + initialization, make the init function a weak reference. */ if ((!TYPE_NEEDS_CONSTRUCTING (obtype) || TYPE_HAS_CONSTEXPR_CTOR (obtype)) - && TARGET_SUPPORTS_WEAK) + && TYPE_HAS_TRIVIAL_DESTRUCTOR (obtype) + && DECL_EXTERNAL (var)) declare_weak (fn); else DECL_WEAK (fn) = DECL_WEAK (var); @@ -2956,6 +2991,9 @@ generate_tls_wrapper (tree fn) finish_if_stmt (if_stmt); } } + else + /* If there's no initialization, the wrapper is a constant function. */ + TREE_READONLY (fn) = true; finish_return_stmt (convert_from_reference (var)); finish_function_body (body); expand_or_defer_fn (finish_function (0)); @@ -3861,15 +3899,6 @@ handle_tls_init (void) location_t loc = DECL_SOURCE_LOCATION (TREE_VALUE (vars)); - #ifndef ASM_OUTPUT_DEF - /* This currently requires alias support. FIXME other targets could use - small thunks instead of aliases. */ - input_location = loc; - sorry ("dynamic initialization of non-function-local thread_local " - "variables not supported on this target"); - return; - #endif - write_out_vars (vars); tree guard = build_decl (loc, VAR_DECL, get_identifier ("__tls_guard"), @@ -3882,14 +3911,7 @@ handle_tls_init (void) DECL_TLS_MODEL (guard) = decl_default_tls_model (guard); pushdecl_top_level_and_finish (guard, NULL_TREE); - tree fn = build_lang_decl (FUNCTION_DECL, - get_identifier ("__tls_init"), - build_function_type (void_type_node, - void_list_node)); - SET_DECL_LANGUAGE (fn, lang_c); - TREE_PUBLIC (fn) = false; - DECL_ARTIFICIAL (fn) = true; - mark_used (fn); + tree fn = get_local_tls_init_fn (); start_preparsed_function (fn, NULL_TREE, SF_PRE_PARSED); tree body = begin_function_body (); tree if_stmt = begin_if_stmt (); @@ -3904,11 +3926,17 @@ handle_tls_init (void) tree init = TREE_PURPOSE (vars); one_static_initialization_or_destruction (var, init, true); - tree single_init_fn = get_tls_init_fn (var); - cgraph_node *alias - = cgraph_same_body_alias (cgraph_get_create_node (fn), - single_init_fn, fn); - gcc_assert (alias != NULL); +#ifdef ASM_OUTPUT_DEF + /* Output init aliases even with -fno-extern-tls-init. */ + if (TREE_PUBLIC (var)) + { + tree single_init_fn = get_tls_init_fn (var); + cgraph_node *alias + = cgraph_same_body_alias (cgraph_get_create_node (fn), + single_init_fn, fn); + gcc_assert (alias != NULL); + } +#endif } finish_then_clause (if_stmt); diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 9ef6c93..48ee779 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -2029,6 +2029,29 @@ exceptions in violation of the exception specifications; the compiler still optimizes based on the specifications, so throwing an unexpected exception results in undefined behavior at run time. +@item -fextern-tls-init +@itemx -fno-extern-tls-init +@opindex fextern-tls-init +@opindex fno-extern-tls-init +The C++11 and OpenMP standards allow @samp{thread_local} and +@samp{threadprivate} variables to have dynamic (runtime) +initialization. To support this, any use of such a variable goes +through a wrapper function that performs any necessary initialization. +When the use and definition of the variable are in the same +translation unit, this overhead can be optimized away, but when the +use is in a different translation unit there is significant overhead +even if the variable doesn't actually need dynamic initialization. If +the programmer can be sure that no use of the variable in a +non-defining TU needs to trigger dynamic initialization (either +because the variable is statically initialized, or a use of the +variable in the defining TU will be executed before any uses in +another TU), they can avoid this overhead with the +@option{-fno-extern-tls-init} option. + +On targets that support symbol aliases, the default is +@option{-fextern-tls-init}. On targets that do not support symbol +aliases, the default is @option{-fno-extern-tls-init}. + @item -ffor-scope @itemx -fno-for-scope @opindex ffor-scope diff --git a/libgomp/testsuite/libgomp.c++/pr24455.C b/libgomp/testsuite/libgomp.c++/pr24455.C index 3185ca5..8256b66 100644 --- a/libgomp/testsuite/libgomp.c++/pr24455.C +++ b/libgomp/testsuite/libgomp.c++/pr24455.C @@ -1,8 +1,7 @@ // { dg-do run } // { dg-additional-sources pr24455-1.C } // { dg-require-effective-target tls_runtime } -// { dg-options "-Wl,-G" { target powerpc-ibm-aix* } } -// { dg-options "-Wl,-undefined,dynamic_lookup" { target *-*-darwin* } } +// { dg-options "-fno-extern-tls-init" } extern "C" void abort (void); ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: C++ PATCH for target/54908 (thread_local vs emutls) 2013-01-18 22:29 ` Jason Merrill @ 2013-01-19 2:20 ` Jack Howarth 2013-01-19 5:16 ` Jason Merrill 0 siblings, 1 reply; 6+ messages in thread From: Jack Howarth @ 2013-01-19 2:20 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches List, Dominique Dhumieres [-- Attachment #1: Type: text/plain, Size: 11254 bytes --] On Fri, Jan 18, 2013 at 05:29:02PM -0500, Jason Merrill wrote: > I've been thinking about how to deal with the problems with calling > initialization functions in another translation unit; namely, that it's > significant overhead even for cases where it isn't useful, and that it > requires alias and weak reference support. This patch introduces a new > flag -fno-extern-tls-init that allows the user to disable support for > calling a lazy initialization function in a different translation unit > to avoid the overhead. It also disables it by default for targets > without support for aliases or weak references. > > Tested x86_64-pc-linux-gnu. Jack, does this fix the thread_local tests > on Darwin? Jason, The proposed patch eliminates all of the previous failures from PR54908 at both -m32/-m64 on x86_64-apple-darwin12 but seems to introduce a new set of failures... FAIL: g++.dg/tls/thread_local-wrap3.C scan-assembler _ZTH1i FAIL: g++.dg/gomp/tls-wrap3.C -std=c++98 scan-assembler _ZTH1i FAIL: g++.dg/gomp/tls-wrap3.C -std=c++11 scan-assembler _ZTH1i at both -m32 and -m64. The thread_local-wrap3.s generated with... /sw/src/fink.build/gcc48-4.8.0-1000/darwin_objdir/gcc/testsuite/g++/../../xg++ -B/sw/src/fink.build/gcc48-4.8.0-1000/darwin_objdir/gcc/testsuite/g++/../../ /sw/src/fink.build/gcc48-4.8.0-1000/gcc-4.8-20130118/gcc/testsuite/g++.dg/tls/thread_local-wrap3.C -fno-diagnostics-show-caret -nostdinc++ -I/sw/src/fink.build/gcc48-4.8.0-1000/darwin_objdir/x86_64-apple-darwin12.2.0/libstdc++-v3/include/x86_64-apple-darwin12.2.0 -I/sw/src/fink.build/gcc48-4.8.0-1000/darwin_objdir/x86_64-apple-darwin12.2.0/libstdc++-v3/include -I/sw/src/fink.build/gcc48-4.8.0-1000/gcc-4.8-20130118/libstdc++-v3/libsupc++ -I/sw/src/fink.build/gcc48-4.8.0-1000/gcc-4.8-20130118/libstdc++-v3/include/backward -I/sw/src/fink.build/gcc48-4.8.0-1000/gcc-4.8-20130118/libstdc++-v3/testsuite/util -fmessage-length=0 -std=c++11 -S -m64 -o thread_local-wrap3.s is attached. Recompiling the testcase with -fextern-tls-init doesn't produce the missing _ZTH1i. Jack ps I'll post full regression results tomorrow. > commit b3cf0f73d853bb9f0d5bfde22995eafc244210d3 > Author: Jason Merrill <jason@redhat.com> > Date: Thu Jan 17 06:15:22 2013 -0500 > > PR target/54908 > c-family/ > * c.opt (-fextern-tls-init): New. > * c-opts.c (c_common_post_options): Handle it. > cp/ > * decl2.c (get_local_tls_init_fn): New. > (get_tls_init_fn): Handle flag_extern_tls_init. Don't bother > with aliases for internal variables. Don't use weakrefs if > the variable needs destruction. > (generate_tls_wrapper): Mark the wrapper as const if no > initialization is needed. > (handle_tls_init): Don't require aliases. > > diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c > index 3fabb36..1a922a8 100644 > --- a/gcc/c-family/c-opts.c > +++ b/gcc/c-family/c-opts.c > @@ -901,6 +901,20 @@ c_common_post_options (const char **pfilename) > else if (warn_narrowing == -1) > warn_narrowing = 0; > > + if (flag_extern_tls_init) > + { > +#if !defined (ASM_OUTPUT_DEF) || !SUPPORTS_WEAK > + /* Lazy TLS initialization for a variable in another TU requires > + alias and weak reference support. */ > + if (flag_extern_tls_init > 0) > + sorry ("external TLS initialization functions not supported " > + "on this target"); > + flag_extern_tls_init = 0; > +#else > + flag_extern_tls_init = 1; > +#endif > + } > + > if (flag_preprocess_only) > { > /* Open the output now. We must do so even if flag_no_output is > diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt > index 187f3be..10ae84d 100644 > --- a/gcc/c-family/c.opt > +++ b/gcc/c-family/c.opt > @@ -913,6 +913,9 @@ finput-charset= > C ObjC C++ ObjC++ Joined RejectNegative > -finput-charset=<cset> Specify the default character set for source files > > +fextern-tls-init > +C++ ObjC++ Var(flag_extern_tls_init) Init(-1) > +Support dynamic initialization of thread-local variables in a different translation unit > > fexternal-templates > C++ ObjC++ Ignore Warn(switch %qs is no longer supported) > diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c > index 619d30d..4496395 100644 > --- a/gcc/cp/decl2.c > +++ b/gcc/cp/decl2.c > @@ -2812,6 +2812,28 @@ var_needs_tls_wrapper (tree var) > && !var_defined_without_dynamic_init (var)); > } > > +/* Get the FUNCTION_DECL for the shared TLS init function for this > + translation unit. */ > + > +static tree > +get_local_tls_init_fn (void) > +{ > + tree sname = get_identifier ("__tls_init"); > + tree fn = IDENTIFIER_GLOBAL_VALUE (sname); > + if (!fn) > + { > + fn = build_lang_decl (FUNCTION_DECL, sname, > + build_function_type (void_type_node, > + void_list_node)); > + SET_DECL_LANGUAGE (fn, lang_c); > + TREE_PUBLIC (fn) = false; > + DECL_ARTIFICIAL (fn) = true; > + mark_used (fn); > + SET_IDENTIFIER_GLOBAL_VALUE (sname, fn); > + } > + return fn; > +} > + > /* Get a FUNCTION_DECL for the init function for the thread_local > variable VAR. The init function will be an alias to the function > that initializes all the non-local TLS variables in the translation > @@ -2824,6 +2846,18 @@ get_tls_init_fn (tree var) > if (!var_needs_tls_wrapper (var)) > return NULL_TREE; > > + /* If -fno-extern-tls-init, assume that we don't need to call > + a tls init function for a variable defined in another TU. */ > + if (!flag_extern_tls_init && DECL_EXTERNAL (var)) > + return NULL_TREE; > + > +#ifdef ASM_OUTPUT_DEF > + /* If the variable is internal, or if we can't generate aliases, > + call the local init function directly. */ > + if (!TREE_PUBLIC (var)) > +#endif > + return get_local_tls_init_fn (); > + > tree sname = mangle_tls_init_fn (var); > tree fn = IDENTIFIER_GLOBAL_VALUE (sname); > if (!fn) > @@ -2841,11 +2875,12 @@ get_tls_init_fn (tree var) > if (TREE_PUBLIC (var)) > { > tree obtype = strip_array_types (non_reference (TREE_TYPE (var))); > - /* If the variable might have static initialization, make the > - init function a weak reference. */ > + /* If the variable is defined somewhere else and might have static > + initialization, make the init function a weak reference. */ > if ((!TYPE_NEEDS_CONSTRUCTING (obtype) > || TYPE_HAS_CONSTEXPR_CTOR (obtype)) > - && TARGET_SUPPORTS_WEAK) > + && TYPE_HAS_TRIVIAL_DESTRUCTOR (obtype) > + && DECL_EXTERNAL (var)) > declare_weak (fn); > else > DECL_WEAK (fn) = DECL_WEAK (var); > @@ -2956,6 +2991,9 @@ generate_tls_wrapper (tree fn) > finish_if_stmt (if_stmt); > } > } > + else > + /* If there's no initialization, the wrapper is a constant function. */ > + TREE_READONLY (fn) = true; > finish_return_stmt (convert_from_reference (var)); > finish_function_body (body); > expand_or_defer_fn (finish_function (0)); > @@ -3861,15 +3899,6 @@ handle_tls_init (void) > > location_t loc = DECL_SOURCE_LOCATION (TREE_VALUE (vars)); > > - #ifndef ASM_OUTPUT_DEF > - /* This currently requires alias support. FIXME other targets could use > - small thunks instead of aliases. */ > - input_location = loc; > - sorry ("dynamic initialization of non-function-local thread_local " > - "variables not supported on this target"); > - return; > - #endif > - > write_out_vars (vars); > > tree guard = build_decl (loc, VAR_DECL, get_identifier ("__tls_guard"), > @@ -3882,14 +3911,7 @@ handle_tls_init (void) > DECL_TLS_MODEL (guard) = decl_default_tls_model (guard); > pushdecl_top_level_and_finish (guard, NULL_TREE); > > - tree fn = build_lang_decl (FUNCTION_DECL, > - get_identifier ("__tls_init"), > - build_function_type (void_type_node, > - void_list_node)); > - SET_DECL_LANGUAGE (fn, lang_c); > - TREE_PUBLIC (fn) = false; > - DECL_ARTIFICIAL (fn) = true; > - mark_used (fn); > + tree fn = get_local_tls_init_fn (); > start_preparsed_function (fn, NULL_TREE, SF_PRE_PARSED); > tree body = begin_function_body (); > tree if_stmt = begin_if_stmt (); > @@ -3904,11 +3926,17 @@ handle_tls_init (void) > tree init = TREE_PURPOSE (vars); > one_static_initialization_or_destruction (var, init, true); > > - tree single_init_fn = get_tls_init_fn (var); > - cgraph_node *alias > - = cgraph_same_body_alias (cgraph_get_create_node (fn), > - single_init_fn, fn); > - gcc_assert (alias != NULL); > +#ifdef ASM_OUTPUT_DEF > + /* Output init aliases even with -fno-extern-tls-init. */ > + if (TREE_PUBLIC (var)) > + { > + tree single_init_fn = get_tls_init_fn (var); > + cgraph_node *alias > + = cgraph_same_body_alias (cgraph_get_create_node (fn), > + single_init_fn, fn); > + gcc_assert (alias != NULL); > + } > +#endif > } > > finish_then_clause (if_stmt); > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > index 9ef6c93..48ee779 100644 > --- a/gcc/doc/invoke.texi > +++ b/gcc/doc/invoke.texi > @@ -2029,6 +2029,29 @@ exceptions in violation of the exception specifications; the compiler > still optimizes based on the specifications, so throwing an > unexpected exception results in undefined behavior at run time. > > +@item -fextern-tls-init > +@itemx -fno-extern-tls-init > +@opindex fextern-tls-init > +@opindex fno-extern-tls-init > +The C++11 and OpenMP standards allow @samp{thread_local} and > +@samp{threadprivate} variables to have dynamic (runtime) > +initialization. To support this, any use of such a variable goes > +through a wrapper function that performs any necessary initialization. > +When the use and definition of the variable are in the same > +translation unit, this overhead can be optimized away, but when the > +use is in a different translation unit there is significant overhead > +even if the variable doesn't actually need dynamic initialization. If > +the programmer can be sure that no use of the variable in a > +non-defining TU needs to trigger dynamic initialization (either > +because the variable is statically initialized, or a use of the > +variable in the defining TU will be executed before any uses in > +another TU), they can avoid this overhead with the > +@option{-fno-extern-tls-init} option. > + > +On targets that support symbol aliases, the default is > +@option{-fextern-tls-init}. On targets that do not support symbol > +aliases, the default is @option{-fno-extern-tls-init}. > + > @item -ffor-scope > @itemx -fno-for-scope > @opindex ffor-scope > diff --git a/libgomp/testsuite/libgomp.c++/pr24455.C b/libgomp/testsuite/libgomp.c++/pr24455.C > index 3185ca5..8256b66 100644 > --- a/libgomp/testsuite/libgomp.c++/pr24455.C > +++ b/libgomp/testsuite/libgomp.c++/pr24455.C > @@ -1,8 +1,7 @@ > // { dg-do run } > // { dg-additional-sources pr24455-1.C } > // { dg-require-effective-target tls_runtime } > -// { dg-options "-Wl,-G" { target powerpc-ibm-aix* } } > -// { dg-options "-Wl,-undefined,dynamic_lookup" { target *-*-darwin* } } > +// { dg-options "-fno-extern-tls-init" } > > extern "C" void abort (void); > [-- Attachment #2: thread_local-wrap3.s --] [-- Type: text/plain, Size: 1668 bytes --] .text .globl _main _main: LFB0: pushq %rbp LCFI0: movq %rsp, %rbp LCFI1: call __ZTW1i movl (%rax), %eax subl $42, %eax popq %rbp LCFI2: ret LFE0: .section __TEXT,__textcoal_nt,coalesced,pure_instructions .globl __ZTW1i .weak_definition __ZTW1i .private_extern __ZTW1i __ZTW1i: LFB1: pushq %rbp LCFI3: movq %rsp, %rbp LCFI4: movq ___emutls_v.i@GOTPCREL(%rip), %rax movq %rax, %rdi call ___emutls_get_address popq %rbp LCFI5: ret LFE1: .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support EH_frame1: .set L$set$0,LECIE1-LSCIE1 .long L$set$0 LSCIE1: .long 0 .byte 0x1 .ascii "zR\0" .byte 0x1 .byte 0x78 .byte 0x10 .byte 0x1 .byte 0x10 .byte 0xc .byte 0x7 .byte 0x8 .byte 0x90 .byte 0x1 .align 3 LECIE1: LSFDE1: .set L$set$1,LEFDE1-LASFDE1 .long L$set$1 LASFDE1: .long LASFDE1-EH_frame1 .quad LFB0-. .set L$set$2,LFE0-LFB0 .quad L$set$2 .byte 0 .byte 0x4 .set L$set$3,LCFI0-LFB0 .long L$set$3 .byte 0xe .byte 0x10 .byte 0x86 .byte 0x2 .byte 0x4 .set L$set$4,LCFI1-LCFI0 .long L$set$4 .byte 0xd .byte 0x6 .byte 0x4 .set L$set$5,LCFI2-LCFI1 .long L$set$5 .byte 0xc .byte 0x7 .byte 0x8 .align 3 LEFDE1: LSFDE3: .set L$set$6,LEFDE3-LASFDE3 .long L$set$6 LASFDE3: .long LASFDE3-EH_frame1 .quad LFB1-. .set L$set$7,LFE1-LFB1 .quad L$set$7 .byte 0 .byte 0x4 .set L$set$8,LCFI3-LFB1 .long L$set$8 .byte 0xe .byte 0x10 .byte 0x86 .byte 0x2 .byte 0x4 .set L$set$9,LCFI4-LCFI3 .long L$set$9 .byte 0xd .byte 0x6 .byte 0x4 .set L$set$10,LCFI5-LCFI4 .long L$set$10 .byte 0xc .byte 0x7 .byte 0x8 .align 3 LEFDE3: .constructor .destructor .align 1 .subsections_via_symbols ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: C++ PATCH for target/54908 (thread_local vs emutls) 2013-01-19 2:20 ` Jack Howarth @ 2013-01-19 5:16 ` Jason Merrill 0 siblings, 0 replies; 6+ messages in thread From: Jason Merrill @ 2013-01-19 5:16 UTC (permalink / raw) To: Jack Howarth; +Cc: gcc-patches List, Dominique Dhumieres On 01/18/2013 09:20 PM, Jack Howarth wrote: > The proposed patch eliminates all of the previous failures from PR54908 > at both -m32/-m64 on x86_64-apple-darwin12 but seems to introduce a new set of > failures... > > FAIL: g++.dg/tls/thread_local-wrap3.C scan-assembler _ZTH1i > FAIL: g++.dg/gomp/tls-wrap3.C -std=c++98 scan-assembler _ZTH1i > FAIL: g++.dg/gomp/tls-wrap3.C -std=c++11 scan-assembler _ZTH1i Ah, yes; those are specifically testing for the aliases that we can't generate on darwin. I'll add dg-require-alias to those tests. Thanks for the testing. > Recompiling the testcase with -fextern-tls-init doesn't produce the missing _ZTH1i. Hmm, compiling with -fextern-tls-init should give an error for you. Doesn't it? Jason ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: C++ PATCH for target/54908 (thread_local vs emutls)
@ 2013-01-19 13:25 Dominique Dhumieres
2013-01-19 15:35 ` Jason Merrill
0 siblings, 1 reply; 6+ messages in thread
From: Dominique Dhumieres @ 2013-01-19 13:25 UTC (permalink / raw)
To: gcc-patches; +Cc: howarth, jason
> > FAIL: g++.dg/tls/thread_local-wrap3.C scan-assembler _ZTH1i
> > FAIL: g++.dg/gomp/tls-wrap3.C -std=c++98 scan-assembler _ZTH1i
> > FAIL: g++.dg/gomp/tls-wrap3.C -std=c++11 scan-assembler _ZTH1i
>
> Ah, yes; those are specifically testing for the aliases that we can't
> generate on darwin. I'll add dg-require-alias to those tests. ...
These tests still fail on x86_64-apple-darwin10 after bootstrapping
a clean revision 195310.
Dominique
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: C++ PATCH for target/54908 (thread_local vs emutls) 2013-01-19 13:25 Dominique Dhumieres @ 2013-01-19 15:35 ` Jason Merrill 0 siblings, 0 replies; 6+ messages in thread From: Jason Merrill @ 2013-01-19 15:35 UTC (permalink / raw) To: Dominique Dhumieres; +Cc: gcc-patches, howarth On 01/19/2013 08:25 AM, Dominique Dhumieres wrote: >>> FAIL: g++.dg/tls/thread_local-wrap3.C scan-assembler _ZTH1i >>> FAIL: g++.dg/gomp/tls-wrap3.C -std=c++98 scan-assembler _ZTH1i >>> FAIL: g++.dg/gomp/tls-wrap3.C -std=c++11 scan-assembler _ZTH1i >> >> Ah, yes; those are specifically testing for the aliases that we can't >> generate on darwin. I'll add dg-require-alias to those tests. ... > > These tests still fail on x86_64-apple-darwin10 after bootstrapping > a clean revision 195310. Ah, apparently I need a "" after the dg-require-alias. Will fix. Jason ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2013-01-19 15:35 UTC | newest] Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2012-10-15 7:38 C++ PATCH for target/54908 (thread_local vs emutls) Jason Merrill 2013-01-18 22:29 ` Jason Merrill 2013-01-19 2:20 ` Jack Howarth 2013-01-19 5:16 ` Jason Merrill 2013-01-19 13:25 Dominique Dhumieres 2013-01-19 15:35 ` Jason Merrill
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).