* 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, 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
* 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
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).