mirror of git://gcc.gnu.org/git/gcc.git
re PR target/54908 (misc regressions on emutls targets remain from dynamic initialization of non-function-local TLS variables)
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. From-SVN: r195310
This commit is contained in:
parent
fd36469e79
commit
5af057d8bd
|
|
@ -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>
|
2013-01-09 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
|
||||||
PR c/48418
|
PR c/48418
|
||||||
|
|
|
||||||
|
|
@ -901,6 +901,20 @@ c_common_post_options (const char **pfilename)
|
||||||
else if (warn_narrowing == -1)
|
else if (warn_narrowing == -1)
|
||||||
warn_narrowing = 0;
|
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)
|
if (flag_preprocess_only)
|
||||||
{
|
{
|
||||||
/* Open the output now. We must do so even if flag_no_output is
|
/* Open the output now. We must do so even if flag_no_output is
|
||||||
|
|
|
||||||
|
|
@ -913,6 +913,9 @@ finput-charset=
|
||||||
C ObjC C++ ObjC++ Joined RejectNegative
|
C ObjC C++ ObjC++ Joined RejectNegative
|
||||||
-finput-charset=<cset> Specify the default character set for source files
|
-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
|
fexternal-templates
|
||||||
C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
|
C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
|
||||||
|
|
|
||||||
|
|
@ -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>
|
2013-01-15 Dodji Seketeli <dodji@redhat.com>
|
||||||
|
|
||||||
PR c++/55663
|
PR c++/55663
|
||||||
|
|
|
||||||
|
|
@ -2812,6 +2812,28 @@ var_needs_tls_wrapper (tree var)
|
||||||
&& !var_defined_without_dynamic_init (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
|
/* Get a FUNCTION_DECL for the init function for the thread_local
|
||||||
variable VAR. The init function will be an alias to the function
|
variable VAR. The init function will be an alias to the function
|
||||||
that initializes all the non-local TLS variables in the translation
|
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))
|
if (!var_needs_tls_wrapper (var))
|
||||||
return NULL_TREE;
|
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 sname = mangle_tls_init_fn (var);
|
||||||
tree fn = IDENTIFIER_GLOBAL_VALUE (sname);
|
tree fn = IDENTIFIER_GLOBAL_VALUE (sname);
|
||||||
if (!fn)
|
if (!fn)
|
||||||
|
|
@ -2841,11 +2875,12 @@ get_tls_init_fn (tree var)
|
||||||
if (TREE_PUBLIC (var))
|
if (TREE_PUBLIC (var))
|
||||||
{
|
{
|
||||||
tree obtype = strip_array_types (non_reference (TREE_TYPE (var)));
|
tree obtype = strip_array_types (non_reference (TREE_TYPE (var)));
|
||||||
/* If the variable might have static initialization, make the
|
/* If the variable is defined somewhere else and might have static
|
||||||
init function a weak reference. */
|
initialization, make the init function a weak reference. */
|
||||||
if ((!TYPE_NEEDS_CONSTRUCTING (obtype)
|
if ((!TYPE_NEEDS_CONSTRUCTING (obtype)
|
||||||
|| TYPE_HAS_CONSTEXPR_CTOR (obtype))
|
|| TYPE_HAS_CONSTEXPR_CTOR (obtype))
|
||||||
&& TARGET_SUPPORTS_WEAK)
|
&& TYPE_HAS_TRIVIAL_DESTRUCTOR (obtype)
|
||||||
|
&& DECL_EXTERNAL (var))
|
||||||
declare_weak (fn);
|
declare_weak (fn);
|
||||||
else
|
else
|
||||||
DECL_WEAK (fn) = DECL_WEAK (var);
|
DECL_WEAK (fn) = DECL_WEAK (var);
|
||||||
|
|
@ -2956,6 +2991,9 @@ generate_tls_wrapper (tree fn)
|
||||||
finish_if_stmt (if_stmt);
|
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_return_stmt (convert_from_reference (var));
|
||||||
finish_function_body (body);
|
finish_function_body (body);
|
||||||
expand_or_defer_fn (finish_function (0));
|
expand_or_defer_fn (finish_function (0));
|
||||||
|
|
@ -3861,15 +3899,6 @@ handle_tls_init (void)
|
||||||
|
|
||||||
location_t loc = DECL_SOURCE_LOCATION (TREE_VALUE (vars));
|
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);
|
write_out_vars (vars);
|
||||||
|
|
||||||
tree guard = build_decl (loc, VAR_DECL, get_identifier ("__tls_guard"),
|
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);
|
DECL_TLS_MODEL (guard) = decl_default_tls_model (guard);
|
||||||
pushdecl_top_level_and_finish (guard, NULL_TREE);
|
pushdecl_top_level_and_finish (guard, NULL_TREE);
|
||||||
|
|
||||||
tree fn = build_lang_decl (FUNCTION_DECL,
|
tree fn = get_local_tls_init_fn ();
|
||||||
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);
|
|
||||||
start_preparsed_function (fn, NULL_TREE, SF_PRE_PARSED);
|
start_preparsed_function (fn, NULL_TREE, SF_PRE_PARSED);
|
||||||
tree body = begin_function_body ();
|
tree body = begin_function_body ();
|
||||||
tree if_stmt = begin_if_stmt ();
|
tree if_stmt = begin_if_stmt ();
|
||||||
|
|
@ -3904,11 +3926,17 @@ handle_tls_init (void)
|
||||||
tree init = TREE_PURPOSE (vars);
|
tree init = TREE_PURPOSE (vars);
|
||||||
one_static_initialization_or_destruction (var, init, true);
|
one_static_initialization_or_destruction (var, init, true);
|
||||||
|
|
||||||
tree single_init_fn = get_tls_init_fn (var);
|
#ifdef ASM_OUTPUT_DEF
|
||||||
cgraph_node *alias
|
/* Output init aliases even with -fno-extern-tls-init. */
|
||||||
= cgraph_same_body_alias (cgraph_get_create_node (fn),
|
if (TREE_PUBLIC (var))
|
||||||
single_init_fn, fn);
|
{
|
||||||
gcc_assert (alias != NULL);
|
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);
|
finish_then_clause (if_stmt);
|
||||||
|
|
|
||||||
|
|
@ -2029,6 +2029,29 @@ exceptions in violation of the exception specifications; the compiler
|
||||||
still optimizes based on the specifications, so throwing an
|
still optimizes based on the specifications, so throwing an
|
||||||
unexpected exception results in undefined behavior at run time.
|
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
|
@item -ffor-scope
|
||||||
@itemx -fno-for-scope
|
@itemx -fno-for-scope
|
||||||
@opindex ffor-scope
|
@opindex ffor-scope
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// If we can't see the definition at all, we need to assume there might be
|
// If we can't see the definition at all, we need to assume there might be
|
||||||
// an init function.
|
// an init function.
|
||||||
|
|
||||||
|
// { dg-require-alias }
|
||||||
// { dg-require-effective-target tls }
|
// { dg-require-effective-target tls }
|
||||||
// { dg-final { scan-assembler "_ZTW1i" } }
|
// { dg-final { scan-assembler "_ZTW1i" } }
|
||||||
// { dg-final { scan-assembler "_ZTH1i" } }
|
// { dg-final { scan-assembler "_ZTH1i" } }
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// If we can't see the definition at all, we need to assume there might be
|
// If we can't see the definition at all, we need to assume there might be
|
||||||
// an init function.
|
// an init function.
|
||||||
|
|
||||||
|
// { dg-require-alias }
|
||||||
// { dg-require-effective-target tls }
|
// { dg-require-effective-target tls }
|
||||||
// { dg-options "-std=c++11" }
|
// { dg-options "-std=c++11" }
|
||||||
// { dg-final { scan-assembler "_ZTW1i" } }
|
// { dg-final { scan-assembler "_ZTW1i" } }
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
// { dg-do run }
|
// { dg-do run }
|
||||||
// { dg-additional-sources pr24455-1.C }
|
// { dg-additional-sources pr24455-1.C }
|
||||||
// { dg-require-effective-target tls_runtime }
|
// { dg-require-effective-target tls_runtime }
|
||||||
// { dg-options "-Wl,-G" { target powerpc-ibm-aix* } }
|
// { dg-options "-fno-extern-tls-init" }
|
||||||
// { dg-options "-Wl,-undefined,dynamic_lookup" { target *-*-darwin* } }
|
|
||||||
|
|
||||||
extern "C" void abort (void);
|
extern "C" void abort (void);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue