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

Reply via email to