ok thanks. David
On Fri, Mar 20, 2015 at 1:40 PM, Teresa Johnson <tejohn...@google.com> wrote: > After offline discussions with David, I changed to the approach of > generating __tls_init for the aux module, but then modifying the LIPO > code to allow it to be statically promoted and treated as an aux > function as a special case of an artificial decl. That works well. New > patch below. Fixed the tests to validate rather than print the > expected output. > > Ok for google branches? > > 2015-03-20 Teresa Johnson <tejohn...@google.com> > > gcc/ > Google ref b/19618364. > * cp/decl2.c (get_local_tls_init_fn): Mark static, > record new global at module scope. > (get_tls_init_fn): Record new global at module scope. > (get_tls_wrapper_fn): Ditto. > (handle_tls_init): Suppress alias in aux module. > * l-ipo.c (decl_artificial_nopromote): New function. > (cgraph_is_aux_decl_external): Call new function. > (process_module_scope_static_func): Ditto. > > testsuite/ > Google ref b/19618364. > * testsuite/g++.dg/tree-prof/lipo/tls.h: New test. > * testsuite/g++.dg/tree-prof/lipo/tls2.h: Ditto. > * testsuite/g++.dg/tree-prof/lipo/tls2_0.C: Ditto. > * testsuite/g++.dg/tree-prof/lipo/tls2_1.C: Ditto. > * testsuite/g++.dg/tree-prof/lipo/tls_0.C: Ditto. > * testsuite/g++.dg/tree-prof/lipo/tls_1.C: Ditto. > > Index: cp/decl2.c > =================================================================== > --- cp/decl2.c (revision 221425) > +++ cp/decl2.c (working copy) > @@ -3033,9 +3033,15 @@ get_local_tls_init_fn (void) > void_list_node)); > SET_DECL_LANGUAGE (fn, lang_c); > TREE_PUBLIC (fn) = false; > + TREE_STATIC (fn) = true; > DECL_ARTIFICIAL (fn) = true; > mark_used (fn); > SET_IDENTIFIER_GLOBAL_VALUE (sname, fn); > + /* In LIPO mode make sure we record the new global value so that it > + is cleared before parsing the next aux module. */ > + if (L_IPO_COMP_MODE && !is_parsing_done_p ()) > + add_decl_to_current_module_scope (fn, > + NAMESPACE_LEVEL > (global_namespace)); > } > return fn; > } > @@ -3100,6 +3106,11 @@ get_tls_init_fn (tree var) > DECL_BEFRIENDING_CLASSES (fn) = var; > > SET_IDENTIFIER_GLOBAL_VALUE (sname, fn); > + /* In LIPO mode make sure we record the new global value so that it > + is cleared before parsing the next aux module. */ > + if (L_IPO_COMP_MODE && !is_parsing_done_p ()) > + add_decl_to_current_module_scope (fn, > + NAMESPACE_LEVEL > (global_namespace)); > } > return fn; > } > @@ -3157,6 +3168,11 @@ get_tls_wrapper_fn (tree var) > DECL_BEFRIENDING_CLASSES (fn) = var; > > SET_IDENTIFIER_GLOBAL_VALUE (sname, fn); > + /* In LIPO mode make sure we record the new global value so that it > + is cleared before parsing the next aux module. */ > + if (L_IPO_COMP_MODE && !is_parsing_done_p ()) > + add_decl_to_current_module_scope (fn, > + NAMESPACE_LEVEL > (global_namespace)); > } > return fn; > } > @@ -4213,8 +4229,12 @@ handle_tls_init (void) > one_static_initialization_or_destruction (var, init, true); > > #ifdef ASM_OUTPUT_DEF > - /* Output init aliases even with -fno-extern-tls-init. */ > - if (TREE_PUBLIC (var)) > + /* Output init aliases even with -fno-extern-tls-init. Don't emit > + aliases in LIPO aux modules, since the corresponding __tls_init > + will be static promoted and deleted, so the variable's tls init > + function will be resolved by its own primary module. An alias > + would prevent the promoted aux __tls_init from being deleted. */ > + if (TREE_PUBLIC (var) && !L_IPO_IS_AUXILIARY_MODULE) > { > tree single_init_fn = get_tls_init_fn (var); > if (single_init_fn == NULL_TREE) > Index: l-ipo.c > =================================================================== > --- l-ipo.c (revision 221425) > +++ l-ipo.c (working copy) > @@ -1120,6 +1120,27 @@ cgraph_unify_type_alias_sets (void) > htab_delete (type_hash_tab); > } > > +/* Return true if DECL is an artificial function that we do not want > + to promote and which may not be available in the primary module. > + The sole exception is currently __tls_init. */ > + > +static bool > +decl_artificial_nopromote (tree decl) > +{ > + if (!DECL_ARTIFICIAL (decl)) > + return false; > + > + /* Handle the __tls_init function specially as we do want to promote it and > + allow the aux module to be resolved to the version in the primary > module. > + We check if it is prefixed by __tls_init to catch it after promotion > + as well from cgraph_is_aux_decl_external. */ > + if (!strncmp (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), > "__tls_init", > + 10)) > + return false; > + > + return true; > +} > + > /* Return true if NODE->decl from an auxiliary module has external > definition (and therefore is not needed for expansion). */ > > @@ -1144,7 +1165,7 @@ cgraph_is_aux_decl_external (struct cgraph_node *n > Functions marked artificial (e.g. an implicitly instantiated virtual > destructor) are also not guaranteed to be available in the primary > module, > as they are not promoted by process_module_scope_static_func. */ > - if (DECL_COMDAT (decl) || DECL_WEAK (decl) || DECL_ARTIFICIAL (decl)) > + if (DECL_COMDAT (decl) || DECL_WEAK (decl) || > decl_artificial_nopromote (decl)) > return false; > > /* virtual functions won't be deleted in the primary module. */ > @@ -2022,7 +2043,7 @@ process_module_scope_static_func (struct cgraph_no > if (TREE_PUBLIC (decl) > || !TREE_STATIC (decl) > || DECL_EXTERNAL (decl) > - || DECL_ARTIFICIAL (decl)) > + || decl_artificial_nopromote (decl)) > return; > > if (flag_ripa_no_promote_always_inline > Index: testsuite/g++.dg/tree-prof/lipo/tls.h > =================================================================== > --- testsuite/g++.dg/tree-prof/lipo/tls.h (revision 0) > +++ testsuite/g++.dg/tree-prof/lipo/tls.h (working copy) > @@ -0,0 +1,16 @@ > +extern int NextId(); > + > +class TLSClass { > + public: > + TLSClass() { > + id = NextId(); > + bar = 1; > + } > + ~TLSClass() {} > + int id; > + int bar; > +}; > +extern TLSClass* NextTLSClass(); > +extern void *SetTLSClass(TLSClass *a); > +extern TLSClass *GetTLSClass(); > +extern thread_local TLSClass* current_tls_; > Index: testsuite/g++.dg/tree-prof/lipo/tls2.h > =================================================================== > --- testsuite/g++.dg/tree-prof/lipo/tls2.h (revision 0) > +++ testsuite/g++.dg/tree-prof/lipo/tls2.h (working copy) > @@ -0,0 +1,15 @@ > +extern int NextId(); > + > +class TLSClass { > + public: > + TLSClass() { > + id = NextId(); > + bar = 1; > + } > + ~TLSClass() {} > + int id; > + int bar; > +}; > +extern TLSClass* NextTLSClass(); > +extern void *SetTLSClass(TLSClass *a); > +extern TLSClass *GetTLSClass(); > Index: testsuite/g++.dg/tree-prof/lipo/tls2_0.C > =================================================================== > --- testsuite/g++.dg/tree-prof/lipo/tls2_0.C (revision 0) > +++ testsuite/g++.dg/tree-prof/lipo/tls2_0.C (working copy) > @@ -0,0 +1,10 @@ > +// { dg-options "-std=c++11 -O2 --param=lipo-sampling-period=1" } > +#include "tls2.h" > + > +static thread_local TLSClass* current_tls_ = NextTLSClass(); > +void *SetTLSClass(TLSClass *a) { > + current_tls_ = a; > +} > +TLSClass *GetTLSClass() { > + return current_tls_; > +} > Index: testsuite/g++.dg/tree-prof/lipo/tls2_1.C > =================================================================== > --- testsuite/g++.dg/tree-prof/lipo/tls2_1.C (revision 0) > +++ testsuite/g++.dg/tree-prof/lipo/tls2_1.C (working copy) > @@ -0,0 +1,31 @@ > +// { dg-options "-std=c++11 -O2 --param=lipo-sampling-period=1" } > +#include <stdio.h> > +#include <stdlib.h> > +#include <new> > +#include "tls2.h" > +TLSClass* NextTLSClass() { > + return new TLSClass(); > +} > +int NextId() { > + static int id = 0; > + return id++; > +} > +static thread_local TLSClass* current_tls2_ = NextTLSClass(); > +void *SetTLSClass2(TLSClass *a) { > + current_tls2_ = a; > +} > +int main() { > + int i = 0; > + if (GetTLSClass()->id != i++) > + abort(); > + TLSClass *A = NextTLSClass(); > + SetTLSClass(A); > + if (GetTLSClass()->id != i++) > + abort(); > + if (current_tls2_->id != i++) > + abort(); > + A = NextTLSClass(); > + SetTLSClass2(A); > + if (current_tls2_->id != i++) > + abort(); > +} > Index: testsuite/g++.dg/tree-prof/lipo/tls_0.C > =================================================================== > --- testsuite/g++.dg/tree-prof/lipo/tls_0.C (revision 0) > +++ testsuite/g++.dg/tree-prof/lipo/tls_0.C (working copy) > @@ -0,0 +1,10 @@ > +// { dg-options "-std=c++11 -O2 --param=lipo-sampling-period=1" } > +#include "tls.h" > + > +thread_local TLSClass* current_tls_ = NextTLSClass(); > +void *SetTLSClass(TLSClass *a) { > + current_tls_ = a; > +} > +TLSClass *GetTLSClass() { > + return current_tls_; > +} > Index: testsuite/g++.dg/tree-prof/lipo/tls_1.C > =================================================================== > --- testsuite/g++.dg/tree-prof/lipo/tls_1.C (revision 0) > +++ testsuite/g++.dg/tree-prof/lipo/tls_1.C (working copy) > @@ -0,0 +1,38 @@ > +// { dg-options "-std=c++11 -O2 --param=lipo-sampling-period=1" } > +#include <stdio.h> > +#include <stdlib.h> > +#include <new> > +#include "tls.h" > +TLSClass* NextTLSClass() { > + return new TLSClass(); > +} > +int NextId() { > + static int id = 0; > + return id++; > +} > +void *SetTLSClassHere(TLSClass *a) { > + current_tls_ = a; > +} > +thread_local TLSClass* current_tls2_ = NextTLSClass(); > +void *SetTLSClass2(TLSClass *a) { > + current_tls2_ = a; > +} > +int main() { > + int i = 0; > + if (GetTLSClass()->id != i++) > + abort(); > + TLSClass *A = NextTLSClass(); > + SetTLSClass(A); > + if (GetTLSClass()->id != i++) > + abort(); > + A = NextTLSClass(); > + SetTLSClassHere(A); > + if (GetTLSClass()->id != i++) > + abort(); > + if (current_tls2_->id != i++) > + abort(); > + A = NextTLSClass(); > + SetTLSClass2(A); > + if (current_tls2_->id != i++) > + abort(); > +} > > On Fri, Mar 20, 2015 at 8:15 AM, Teresa Johnson <tejohn...@google.com> wrote: >> On Thu, Mar 19, 2015 at 10:38 PM, Xinliang David Li <davi...@google.com> >> wrote: >>> On Thu, Mar 19, 2015 at 9:57 PM, Teresa Johnson <tejohn...@google.com> >>> wrote: >>>> On Thu, Mar 19, 2015 at 8:00 PM, Xinliang David Li <davi...@google.com> >>>> wrote: >>>>> ok -- then there is an over assertion in get_local_tls_init_fn. The >>>>> method can be called for aux module -- the decl created will also be >>>>> promoted. >>>> >>>> No, it won't ever be called for an aux module. Both callsites are >>>> guarded (handle_tls_init has an early return at the top, and the >>>> callsite is guarded in get_tls_iniit_fn). >>>> >>>>> >>>>> Also can we rely on late promotion (special case of artificial >>>>> function __tls_init? This can avoid duplicated logic here. >>>> >>>> We don't need to promote __tls_init, but rather the init functions for >>>> each TLS variable (which are each aliased to __tls_init). >>> >>>> I thought >>>> about both approaches, but promoting it as it was created seemed more >>>> straightforward. I can give that approach a try though if you prefer >>>> it (special casing DECL_ARTIFICIAL functions that start with _ZTH). >>>> Incidentally they are not marked static, so that would also need to be >>>> done to get them promoted. >>> >>> For public tls symbols in aux module, tls wrappers will reference >>> _ZTHxx init functions which are aliases to __tls_init. If __tls_init >>> is not created for aux modules, what symbol will those _ZTHxx >>> funcitons aliased to? >>> >>> Is it better just let _tls_init function to be created as usual, but >>> let the standard promotion kick in later? The ZTHxx functions can >>> still be marked as alias to the promoted __tls_init? >> >> So there are 3 function decls being generated for TLS variables: >> >> 1) A single __tls_init function per module >> This initializes *all* TLS variables in the module, guarded by a >> single __tls_guard variable to ensure it is only done once. >> >> 2) One _ZTHxx init function per TLS variable >> Each of these is aliased to the module's __tls_init >> >> 3) One _ZTWxx wrapper function per TLS variable >> This is called in place of accesses to that TLS variable. It invokes >> the _ZTHxx init function for the variable to initialize it if >> necessary. >> >> I am concerned about generating the aux module __tls_init functions >> and then promoting them as they contain initializations for all TLS >> variables from the aux module - generating it each time the module is >> included as an aux module seems inefficient at best. >> >> What happens in the case where the TLS variable is declared extern and >> accessed by a separate module (and essentially is what happens with my >> patch when it is file static, promoted and accessed via an aux module) >> is this: The _ZTHxx init functions are aliased to __tls_init in the >> module containing the definition, and are externally-visible (after >> promoting in the file-static exported primary module case). The >> external module containing the reference (or the primary module that >> imported the defining module as an aux module in the LIPO case) >> generates a _ZTWxx wrapper for the TLS variable, which references its >> _ZTHxx init function. This ends up resolved to the exported/promoted >> _ZTHxx symbol in the defining module, which in turn is aliased to the >> defining module's __tls_init function. >> >> Teresa >> >>> >>> David >>> >>> >>> >>> >>>> >>>> Teresa >>>> >>>>> >>>>> David >>>>> >>>>> On Thu, Mar 19, 2015 at 5:51 PM, Teresa Johnson <tejohn...@google.com> >>>>> wrote: >>>>>> On Thu, Mar 19, 2015 at 4:45 PM, Xinliang David Li <davi...@google.com> >>>>>> wrote: >>>>>>> does generate_tls_wrapper also need to be suppressed for aux module? >>>>>> >>>>>> No, we generate the wrapper in the aux module and use it to access the >>>>>> TLS variable and invoke it's init function (which is defined in the >>>>>> variable's own module). Presumably we could generate that only in the >>>>>> original module and promote it if necessary, but generating it in the >>>>>> aux module does allow it to be inlined. This is essentially how the >>>>>> TLS accesses are handled for extern TLS variables defined elsewhere >>>>>> (wrapper generated in referring module). >>>>>> >>>>>> Teresa >>>>>> >>>>>>> >>>>>>> David >>>>>>> >>>>>>> On Thu, Mar 19, 2015 at 4:11 PM, Teresa Johnson <tejohn...@google.com> >>>>>>> wrote: >>>>>>>> New patch below. Passes regression tests plus internal application >>>>>>>> build. >>>>>>>> >>>>>>>> 2015-03-19 Teresa Johnson <tejohn...@google.com> >>>>>>>> >>>>>>>> gcc/ >>>>>>>> Google ref b/19618364. >>>>>>>> * cp/decl2.c (get_local_tls_init_fn): Assert on aux module. >>>>>>>> (get_tls_init_fn): Promote non-public init functions if >>>>>>>> necessary >>>>>>>> in LIPO mode, record new global at module scope. >>>>>>>> (get_tls_wrapper_fn): Record new global at module scope. >>>>>>>> (handle_tls_init): Skip in aux module, setup alias in exported >>>>>>>> primary module. >>>>>>>> >>>>>>>> testsuite/ >>>>>>>> Google ref b/19618364. >>>>>>>> * testsuite/g++.dg/tree-prof/lipo/tls.h: New test. >>>>>>>> * testsuite/g++.dg/tree-prof/lipo/tls2.h: Ditto. >>>>>>>> * testsuite/g++.dg/tree-prof/lipo/tls2_0.C: Ditto. >>>>>>>> * testsuite/g++.dg/tree-prof/lipo/tls2_1.C: Ditto. >>>>>>>> * testsuite/g++.dg/tree-prof/lipo/tls_0.C: Ditto. >>>>>>>> * testsuite/g++.dg/tree-prof/lipo/tls_1.C: Ditto. >>>>>>>> >>>>>>>> Index: cp/decl2.c >>>>>>>> =================================================================== >>>>>>>> --- cp/decl2.c (revision 221425) >>>>>>>> +++ cp/decl2.c (working copy) >>>>>>>> @@ -55,6 +55,7 @@ along with GCC; see the file COPYING3. If not see >>>>>>>> #include "langhooks.h" >>>>>>>> #include "c-family/c-ada-spec.h" >>>>>>>> #include "asan.h" >>>>>>>> +#include "gcov-io.h" >>>>>>>> >>>>>>>> extern cpp_reader *parse_in; >>>>>>>> >>>>>>>> @@ -3024,6 +3025,9 @@ var_needs_tls_wrapper (tree var) >>>>>>>> static tree >>>>>>>> get_local_tls_init_fn (void) >>>>>>>> { >>>>>>>> + /* In LIPO mode we should not generate local init functions for >>>>>>>> + the aux modules (see handle_tls_init). */ >>>>>>>> + gcc_assert (!L_IPO_IS_AUXILIARY_MODULE); >>>>>>>> tree sname = get_identifier ("__tls_init"); >>>>>>>> tree fn = IDENTIFIER_GLOBAL_VALUE (sname); >>>>>>>> if (!fn) >>>>>>>> @@ -3057,14 +3061,39 @@ get_tls_init_fn (tree var) >>>>>>>> if (!flag_extern_tls_init && DECL_EXTERNAL (var)) >>>>>>>> return NULL_TREE; >>>>>>>> >>>>>>>> + /* In LIPO mode we should not generate local init functions for >>>>>>>> + aux modules. The wrapper will reference the variable's init >>>>>>>> function >>>>>>>> + that is defined in its own primary module. Otherwise there is >>>>>>>> + a name conflict between the primary and aux __tls_init functions, >>>>>>>> + and difficulty ensuring each TLS variable is initialized exactly >>>>>>>> once. >>>>>>>> + Therefore, if this is an aux module or an exported primary >>>>>>>> module, we >>>>>>>> + need to ensure that the init function is available externally by >>>>>>>> + promoting it if it is not already public. This is similar to the >>>>>>>> + handling in promote_static_var_func, but we do it as the init >>>>>>>> function >>>>>>>> + is created to avoid the need to detect and properly promote this >>>>>>>> + artificial decl later on. */ >>>>>>>> + bool promote = L_IPO_IS_AUXILIARY_MODULE || >>>>>>>> + (L_IPO_COMP_MODE && PRIMARY_MODULE_EXPORTED); >>>>>>>> + >>>>>>>> #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)) >>>>>>>> + call the local init function directly. Don't do this if we >>>>>>>> + are in LIPO mode an may need to export the init function. Note >>>>>>>> + that get_local_tls_init_fn will assert if it is called on an aux >>>>>>>> + module. */ >>>>>>>> + if (!TREE_PUBLIC (var) && !promote) >>>>>>>> #endif >>>>>>>> return get_local_tls_init_fn (); >>>>>>>> >>>>>>>> tree sname = mangle_tls_init_fn (var); >>>>>>>> + if (promote) >>>>>>>> + { >>>>>>>> + const char *name = IDENTIFIER_POINTER (sname); >>>>>>>> + char *assembler_name = (char*) alloca (strlen (name) + 30); >>>>>>>> + sprintf (assembler_name, "%s.cmo.%u", name, current_module_id); >>>>>>>> + sname = get_identifier (assembler_name); >>>>>>>> + } >>>>>>>> + >>>>>>>> tree fn = IDENTIFIER_GLOBAL_VALUE (sname); >>>>>>>> if (!fn) >>>>>>>> { >>>>>>>> @@ -3072,7 +3101,18 @@ get_tls_init_fn (tree var) >>>>>>>> build_function_type (void_type_node, >>>>>>>> void_list_node)); >>>>>>>> SET_DECL_LANGUAGE (fn, lang_c); >>>>>>>> - TREE_PUBLIC (fn) = TREE_PUBLIC (var); >>>>>>>> + if (promote) >>>>>>>> + { >>>>>>>> + TREE_PUBLIC (fn) = 1; >>>>>>>> + DECL_VISIBILITY (fn) = VISIBILITY_HIDDEN; >>>>>>>> + DECL_VISIBILITY_SPECIFIED (fn) = 1; >>>>>>>> + } >>>>>>>> + else >>>>>>>> + { >>>>>>>> + TREE_PUBLIC (fn) = TREE_PUBLIC (var); >>>>>>>> + DECL_VISIBILITY (fn) = DECL_VISIBILITY (var); >>>>>>>> + DECL_VISIBILITY_SPECIFIED (fn) = DECL_VISIBILITY_SPECIFIED >>>>>>>> (var); >>>>>>>> + } >>>>>>>> DECL_ARTIFICIAL (fn) = true; >>>>>>>> DECL_COMDAT (fn) = DECL_COMDAT (var); >>>>>>>> DECL_EXTERNAL (fn) = DECL_EXTERNAL (var); >>>>>>>> @@ -3091,8 +3131,6 @@ get_tls_init_fn (tree var) >>>>>>>> else >>>>>>>> DECL_WEAK (fn) = DECL_WEAK (var); >>>>>>>> } >>>>>>>> - DECL_VISIBILITY (fn) = DECL_VISIBILITY (var); >>>>>>>> - DECL_VISIBILITY_SPECIFIED (fn) = DECL_VISIBILITY_SPECIFIED >>>>>>>> (var); >>>>>>>> DECL_DLLIMPORT_P (fn) = DECL_DLLIMPORT_P (var); >>>>>>>> DECL_IGNORED_P (fn) = 1; >>>>>>>> mark_used (fn); >>>>>>>> @@ -3100,6 +3138,11 @@ get_tls_init_fn (tree var) >>>>>>>> DECL_BEFRIENDING_CLASSES (fn) = var; >>>>>>>> >>>>>>>> SET_IDENTIFIER_GLOBAL_VALUE (sname, fn); >>>>>>>> + /* In LIPO mode make sure we record the new global value so >>>>>>>> that it >>>>>>>> + is cleared before parsing the next aux module. */ >>>>>>>> + if (L_IPO_COMP_MODE && !is_parsing_done_p ()) >>>>>>>> + add_decl_to_current_module_scope (fn, >>>>>>>> + NAMESPACE_LEVEL >>>>>>>> (global_namespace)); >>>>>>>> } >>>>>>>> return fn; >>>>>>>> } >>>>>>>> @@ -3157,6 +3200,11 @@ get_tls_wrapper_fn (tree var) >>>>>>>> DECL_BEFRIENDING_CLASSES (fn) = var; >>>>>>>> >>>>>>>> SET_IDENTIFIER_GLOBAL_VALUE (sname, fn); >>>>>>>> + /* In LIPO mode make sure we record the new global value so >>>>>>>> that it >>>>>>>> + is cleared before parsing the next aux module. */ >>>>>>>> + if (L_IPO_COMP_MODE && !is_parsing_done_p ()) >>>>>>>> + add_decl_to_current_module_scope (fn, >>>>>>>> + NAMESPACE_LEVEL >>>>>>>> (global_namespace)); >>>>>>>> } >>>>>>>> return fn; >>>>>>>> } >>>>>>>> @@ -4179,6 +4227,14 @@ clear_decl_external (struct cgraph_node *node, >>>>>>>> voi >>>>>>>> static void >>>>>>>> handle_tls_init (void) >>>>>>>> { >>>>>>>> + /* In LIPO mode we should not generate local init functions for >>>>>>>> + aux modules. The wrapper will reference the variable's init >>>>>>>> function >>>>>>>> + that is defined in its own primary module. Otherwise there is >>>>>>>> + a name conflict between the primary and aux __tls_init functions, >>>>>>>> + and difficulty ensuring each TLS variable is initialized exactly >>>>>>>> once. */ >>>>>>>> + if (L_IPO_IS_AUXILIARY_MODULE) >>>>>>>> + return; >>>>>>>> + >>>>>>>> tree vars = prune_vars_needing_no_initialization (&tls_aggregates); >>>>>>>> if (vars == NULL_TREE) >>>>>>>> return; >>>>>>>> @@ -4213,8 +4269,12 @@ handle_tls_init (void) >>>>>>>> one_static_initialization_or_destruction (var, init, true); >>>>>>>> >>>>>>>> #ifdef ASM_OUTPUT_DEF >>>>>>>> - /* Output init aliases even with -fno-extern-tls-init. */ >>>>>>>> - if (TREE_PUBLIC (var)) >>>>>>>> + /* Output init aliases even with -fno-extern-tls-init. Also >>>>>>>> + export in LIPO mode if the primary module may be exported, >>>>>>>> + in which case the init function may be referenced externally >>>>>>>> + (see comments in get_tls_init_fn). */ >>>>>>>> + if (TREE_PUBLIC (var) || >>>>>>>> + (L_IPO_COMP_MODE && PRIMARY_MODULE_EXPORTED)) >>>>>>>> { >>>>>>>> tree single_init_fn = get_tls_init_fn (var); >>>>>>>> if (single_init_fn == NULL_TREE) >>>>>>>> Index: testsuite/g++.dg/tree-prof/lipo/tls.h >>>>>>>> =================================================================== >>>>>>>> --- testsuite/g++.dg/tree-prof/lipo/tls.h (revision 0) >>>>>>>> +++ testsuite/g++.dg/tree-prof/lipo/tls.h (working copy) >>>>>>>> @@ -0,0 +1,16 @@ >>>>>>>> +extern int NextId(); >>>>>>>> + >>>>>>>> +class TLSClass { >>>>>>>> + public: >>>>>>>> + TLSClass() { >>>>>>>> + id = NextId(); >>>>>>>> + bar = 1; >>>>>>>> + } >>>>>>>> + ~TLSClass() {} >>>>>>>> + int id; >>>>>>>> + int bar; >>>>>>>> +}; >>>>>>>> +extern TLSClass* NextTLSClass(); >>>>>>>> +extern void *SetTLSClass(TLSClass *a); >>>>>>>> +extern TLSClass *GetTLSClass(); >>>>>>>> +extern thread_local TLSClass* current_tls_; >>>>>>>> Index: testsuite/g++.dg/tree-prof/lipo/tls2.h >>>>>>>> =================================================================== >>>>>>>> --- testsuite/g++.dg/tree-prof/lipo/tls2.h (revision 0) >>>>>>>> +++ testsuite/g++.dg/tree-prof/lipo/tls2.h (working copy) >>>>>>>> @@ -0,0 +1,15 @@ >>>>>>>> +extern int NextId(); >>>>>>>> + >>>>>>>> +class TLSClass { >>>>>>>> + public: >>>>>>>> + TLSClass() { >>>>>>>> + id = NextId(); >>>>>>>> + bar = 1; >>>>>>>> + } >>>>>>>> + ~TLSClass() {} >>>>>>>> + int id; >>>>>>>> + int bar; >>>>>>>> +}; >>>>>>>> +extern TLSClass* NextTLSClass(); >>>>>>>> +extern void *SetTLSClass(TLSClass *a); >>>>>>>> +extern TLSClass *GetTLSClass(); >>>>>>>> Index: testsuite/g++.dg/tree-prof/lipo/tls2_0.C >>>>>>>> =================================================================== >>>>>>>> --- testsuite/g++.dg/tree-prof/lipo/tls2_0.C (revision 0) >>>>>>>> +++ testsuite/g++.dg/tree-prof/lipo/tls2_0.C (working copy) >>>>>>>> @@ -0,0 +1,10 @@ >>>>>>>> +// { dg-options "-std=c++11 -O2 --param=lipo-sampling-period=1" } >>>>>>>> +#include "tls2.h" >>>>>>>> + >>>>>>>> +static thread_local TLSClass* current_tls_ = NextTLSClass(); >>>>>>>> +void *SetTLSClass(TLSClass *a) { >>>>>>>> + current_tls_ = a; >>>>>>>> +} >>>>>>>> +TLSClass *GetTLSClass() { >>>>>>>> + return current_tls_; >>>>>>>> +} >>>>>>>> Index: testsuite/g++.dg/tree-prof/lipo/tls2_1.C >>>>>>>> =================================================================== >>>>>>>> --- testsuite/g++.dg/tree-prof/lipo/tls2_1.C (revision 0) >>>>>>>> +++ testsuite/g++.dg/tree-prof/lipo/tls2_1.C (working copy) >>>>>>>> @@ -0,0 +1,26 @@ >>>>>>>> +// { dg-options "-std=c++11 -O2 --param=lipo-sampling-period=1" } >>>>>>>> +#include <stdio.h> >>>>>>>> +#include <stdlib.h> >>>>>>>> +#include <new> >>>>>>>> +#include "tls2.h" >>>>>>>> +TLSClass* NextTLSClass() { >>>>>>>> + return new TLSClass(); >>>>>>>> +} >>>>>>>> +int NextId() { >>>>>>>> + static int id = 0; >>>>>>>> + return id++; >>>>>>>> +} >>>>>>>> +static thread_local TLSClass* current_tls2_ = NextTLSClass(); >>>>>>>> +void *SetTLSClass2(TLSClass *a) { >>>>>>>> + current_tls2_ = a; >>>>>>>> +} >>>>>>>> +int main() { >>>>>>>> + printf ("Id %d\n", GetTLSClass()->id); >>>>>>>> + TLSClass *A = NextTLSClass(); >>>>>>>> + SetTLSClass(A); >>>>>>>> + printf ("Id %d\n", GetTLSClass()->id); >>>>>>>> + printf ("Id %d\n", current_tls2_->id); >>>>>>>> + A = NextTLSClass(); >>>>>>>> + SetTLSClass2(A); >>>>>>>> + printf ("Id %d\n", current_tls2_->id); >>>>>>>> +} >>>>>>>> Index: testsuite/g++.dg/tree-prof/lipo/tls_0.C >>>>>>>> =================================================================== >>>>>>>> --- testsuite/g++.dg/tree-prof/lipo/tls_0.C (revision 0) >>>>>>>> +++ testsuite/g++.dg/tree-prof/lipo/tls_0.C (working copy) >>>>>>>> @@ -0,0 +1,10 @@ >>>>>>>> +// { dg-options "-std=c++11 -O2 --param=lipo-sampling-period=1" } >>>>>>>> +#include "tls.h" >>>>>>>> + >>>>>>>> +thread_local TLSClass* current_tls_ = NextTLSClass(); >>>>>>>> +void *SetTLSClass(TLSClass *a) { >>>>>>>> + current_tls_ = a; >>>>>>>> +} >>>>>>>> +TLSClass *GetTLSClass() { >>>>>>>> + return current_tls_; >>>>>>>> +} >>>>>>>> Index: testsuite/g++.dg/tree-prof/lipo/tls_1.C >>>>>>>> =================================================================== >>>>>>>> --- testsuite/g++.dg/tree-prof/lipo/tls_1.C (revision 0) >>>>>>>> +++ testsuite/g++.dg/tree-prof/lipo/tls_1.C (working copy) >>>>>>>> @@ -0,0 +1,32 @@ >>>>>>>> +// { dg-options "-std=c++11 -O2 --param=lipo-sampling-period=1" } >>>>>>>> +#include <stdio.h> >>>>>>>> +#include <stdlib.h> >>>>>>>> +#include <new> >>>>>>>> +#include "tls.h" >>>>>>>> +TLSClass* NextTLSClass() { >>>>>>>> + return new TLSClass(); >>>>>>>> +} >>>>>>>> +int NextId() { >>>>>>>> + static int id = 0; >>>>>>>> + return id++; >>>>>>>> +} >>>>>>>> +void *SetTLSClassHere(TLSClass *a) { >>>>>>>> + current_tls_ = a; >>>>>>>> +} >>>>>>>> +thread_local TLSClass* current_tls2_ = NextTLSClass(); >>>>>>>> +void *SetTLSClass2(TLSClass *a) { >>>>>>>> + current_tls2_ = a; >>>>>>>> +} >>>>>>>> +int main() { >>>>>>>> + printf ("Id %d\n", GetTLSClass()->id); >>>>>>>> + TLSClass *A = NextTLSClass(); >>>>>>>> + SetTLSClass(A); >>>>>>>> + printf ("Id %d\n", GetTLSClass()->id); >>>>>>>> + A = NextTLSClass(); >>>>>>>> + SetTLSClassHere(A); >>>>>>>> + printf ("Id %d\n", GetTLSClass()->id); >>>>>>>> + printf ("Id %d\n", current_tls2_->id); >>>>>>>> + A = NextTLSClass(); >>>>>>>> + SetTLSClass2(A); >>>>>>>> + printf ("Id %d\n", current_tls2_->id); >>>>>>>> +} >>>>>>>> >>>>>>>> On Thu, Mar 19, 2015 at 6:09 AM, Teresa Johnson <tejohn...@google.com> >>>>>>>> wrote: >>>>>>>>> On Wed, Mar 18, 2015 at 9:25 PM, Xinliang David Li >>>>>>>>> <davi...@google.com> wrote: >>>>>>>>>> get_local_tls_init_fn can be called from other contexts other than >>>>>>>>>> 'handle_tls_init' -- is the added new assertion safe ? >>>>>>>>> >>>>>>>>> In fact there is still an issue here, for file static TLS vars. Will >>>>>>>>> work on a fix and send the original test case (forgot to include in >>>>>>>>> first patch) and the new one with the fixed patch. >>>>>>>>> >>>>>>>>> Teresa >>>>>>>>> >>>>>>>>>> >>>>>>>>>> David >>>>>>>>>> >>>>>>>>>> On Wed, Mar 18, 2015 at 9:18 PM, Teresa Johnson >>>>>>>>>> <tejohn...@google.com> >>>>>>>>>> wrote: >>>>>>>>>>> >>>>>>>>>>> Ensure TLS variable wrapper and init functions are recorded at >>>>>>>>>>> the module scope upon creation so that they are cleared when >>>>>>>>>>> popping the module scope in between modules in LIPO mode. >>>>>>>>>>> >>>>>>>>>>> Also, do not generate a local TLS init function (__tls_init) >>>>>>>>>>> for aux functions, only in the primary modules. >>>>>>>>>>> >>>>>>>>>>> Passes regression tests. Ok for Google branches? >>>>>>>>>>> Teresa >>>>>>>>>>> >>>>>>>>>>> 2015-03-18 Teresa Johnson <tejohn...@google.com> >>>>>>>>>>> >>>>>>>>>>> Google ref b/19618364. >>>>>>>>>>> * cp/decl2.c (get_local_tls_init_fn): Assert on aux module. >>>>>>>>>>> (get_tls_init_fn): Record new global decl. >>>>>>>>>>> (get_tls_wrapper_fn): Ditto. >>>>>>>>>>> (handle_tls_init): Skip aux modules. >>>>>>>>>>> >>>>>>>>>>> Index: cp/decl2.c >>>>>>>>>>> =================================================================== >>>>>>>>>>> --- cp/decl2.c (revision 221425) >>>>>>>>>>> +++ cp/decl2.c (working copy) >>>>>>>>>>> @@ -3036,6 +3036,9 @@ get_local_tls_init_fn (void) >>>>>>>>>>> DECL_ARTIFICIAL (fn) = true; >>>>>>>>>>> mark_used (fn); >>>>>>>>>>> SET_IDENTIFIER_GLOBAL_VALUE (sname, fn); >>>>>>>>>>> + /* In LIPO mode we should not generate local init functions >>>>>>>>>>> for >>>>>>>>>>> + the aux modules (see handle_tls_init). */ >>>>>>>>>>> + gcc_assert (!L_IPO_IS_AUXILIARY_MODULE); >>>>>>>>>>> } >>>>>>>>>>> return fn; >>>>>>>>>>> } >>>>>>>>>>> @@ -3100,6 +3103,11 @@ get_tls_init_fn (tree var) >>>>>>>>>>> DECL_BEFRIENDING_CLASSES (fn) = var; >>>>>>>>>>> >>>>>>>>>>> SET_IDENTIFIER_GLOBAL_VALUE (sname, fn); >>>>>>>>>>> + /* In LIPO mode make sure we record the new global value so >>>>>>>>>>> that it >>>>>>>>>>> + is cleared before parsing the next aux module. */ >>>>>>>>>>> + if (L_IPO_COMP_MODE && !is_parsing_done_p ()) >>>>>>>>>>> + add_decl_to_current_module_scope (fn, >>>>>>>>>>> + NAMESPACE_LEVEL >>>>>>>>>>> (global_namespace)); >>>>>>>>>>> } >>>>>>>>>>> return fn; >>>>>>>>>>> } >>>>>>>>>>> @@ -3157,6 +3165,11 @@ get_tls_wrapper_fn (tree var) >>>>>>>>>>> DECL_BEFRIENDING_CLASSES (fn) = var; >>>>>>>>>>> >>>>>>>>>>> SET_IDENTIFIER_GLOBAL_VALUE (sname, fn); >>>>>>>>>>> + /* In LIPO mode make sure we record the new global value so >>>>>>>>>>> that it >>>>>>>>>>> + is cleared before parsing the next aux module. */ >>>>>>>>>>> + if (L_IPO_COMP_MODE && !is_parsing_done_p ()) >>>>>>>>>>> + add_decl_to_current_module_scope (fn, >>>>>>>>>>> + NAMESPACE_LEVEL >>>>>>>>>>> (global_namespace)); >>>>>>>>>>> } >>>>>>>>>>> return fn; >>>>>>>>>>> } >>>>>>>>>>> @@ -4179,6 +4192,14 @@ clear_decl_external (struct cgraph_node >>>>>>>>>>> *node, voi >>>>>>>>>>> static void >>>>>>>>>>> handle_tls_init (void) >>>>>>>>>>> { >>>>>>>>>>> + /* In LIPO mode we should not generate local init functions for >>>>>>>>>>> + aux modules. The wrapper will reference the variable's init >>>>>>>>>>> function >>>>>>>>>>> + that is defined in its own primary module. Otherwise there is >>>>>>>>>>> + a name conflict between the primary and aux __tls_init >>>>>>>>>>> functions, >>>>>>>>>>> + and difficulty ensuring each TLS variable is initialized >>>>>>>>>>> exactly >>>>>>>>>>> once. */ >>>>>>>>>>> + if (L_IPO_IS_AUXILIARY_MODULE) >>>>>>>>>>> + return; >>>>>>>>>>> + >>>>>>>>>>> tree vars = prune_vars_needing_no_initialization >>>>>>>>>>> (&tls_aggregates); >>>>>>>>>>> if (vars == NULL_TREE) >>>>>>>>>>> return; >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> -- >>>>>>>>>>> Teresa Johnson | Software Engineer | tejohn...@google.com | >>>>>>>>>>> 408-460-2413 >>>>>>>>>> >>>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> -- >>>>>>>>> Teresa Johnson | Software Engineer | tejohn...@google.com | >>>>>>>>> 408-460-2413 >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> -- >>>>>>>> Teresa Johnson | Software Engineer | tejohn...@google.com | >>>>>>>> 408-460-2413 >>>>>> >>>>>> >>>>>> >>>>>> -- >>>>>> Teresa Johnson | Software Engineer | tejohn...@google.com | 408-460-2413 >>>> >>>> >>>> >>>> -- >>>> Teresa Johnson | Software Engineer | tejohn...@google.com | 408-460-2413 >> >> >> >> -- >> Teresa Johnson | Software Engineer | tejohn...@google.com | 408-460-2413 > > > > -- > Teresa Johnson | Software Engineer | tejohn...@google.com | 408-460-2413