aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/c-family/ChangeLog6
-rw-r--r--gcc/c-family/c-opts.c14
-rw-r--r--gcc/c-family/c.opt3
-rw-r--r--gcc/cp/ChangeLog11
-rw-r--r--gcc/cp/decl2.c78
-rw-r--r--gcc/doc/invoke.texi23
-rw-r--r--gcc/testsuite/g++.dg/gomp/tls-wrap3.C1
-rw-r--r--gcc/testsuite/g++.dg/tls/thread_local-wrap3.C1
-rw-r--r--libgomp/testsuite/libgomp.c++/pr24455.C3
9 files changed, 113 insertions, 27 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 778be4b..d4f989b 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,9 @@
+2013-01-18 Jason Merrill <jason@redhat.com>
+
+ PR target/54908
+ * c.opt (-fextern-tls-init): New.
+ * c-opts.c (c_common_post_options): Handle it.
+
2013-01-09 Jakub Jelinek <jakub@redhat.com>
PR c/48418
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/ChangeLog b/gcc/cp/ChangeLog
index 00bcb7a..6370f7f 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,14 @@
+2013-01-18 Jason Merrill <jason@redhat.com>
+
+ PR target/54908
+ * 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.
+
2013-01-15 Dodji Seketeli <dodji@redhat.com>
PR c++/55663
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 887d31e..d60ac9f 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/gcc/testsuite/g++.dg/gomp/tls-wrap3.C b/gcc/testsuite/g++.dg/gomp/tls-wrap3.C
index 2504d99..abe5cb0 100644
--- a/gcc/testsuite/g++.dg/gomp/tls-wrap3.C
+++ b/gcc/testsuite/g++.dg/gomp/tls-wrap3.C
@@ -1,6 +1,7 @@
// If we can't see the definition at all, we need to assume there might be
// an init function.
+// { dg-require-alias }
// { dg-require-effective-target tls }
// { dg-final { scan-assembler "_ZTW1i" } }
// { dg-final { scan-assembler "_ZTH1i" } }
diff --git a/gcc/testsuite/g++.dg/tls/thread_local-wrap3.C b/gcc/testsuite/g++.dg/tls/thread_local-wrap3.C
index 19e6ab8..6b2fb4f 100644
--- a/gcc/testsuite/g++.dg/tls/thread_local-wrap3.C
+++ b/gcc/testsuite/g++.dg/tls/thread_local-wrap3.C
@@ -1,6 +1,7 @@
// If we can't see the definition at all, we need to assume there might be
// an init function.
+// { dg-require-alias }
// { dg-require-effective-target tls }
// { dg-options "-std=c++11" }
// { dg-final { scan-assembler "_ZTW1i" } }
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);