diff options
-rw-r--r-- | gcc/c-family/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/c-family/c-opts.c | 14 | ||||
-rw-r--r-- | gcc/c-family/c.opt | 3 | ||||
-rw-r--r-- | gcc/cp/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/cp/decl2.c | 78 | ||||
-rw-r--r-- | gcc/doc/invoke.texi | 23 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/gomp/tls-wrap3.C | 1 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/tls/thread_local-wrap3.C | 1 | ||||
-rw-r--r-- | libgomp/testsuite/libgomp.c++/pr24455.C | 3 |
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); |