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? 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