&& !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
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)
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);
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));
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"),
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 ();
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);
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