public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [Patch, updated] Make emulated TLS lto-friendly.
@ 2010-07-03 14:11 IainS
  2010-07-07 23:22 ` Richard Henderson
  0 siblings, 1 reply; 35+ messages in thread
From: IainS @ 2010-07-03 14:11 UTC (permalink / raw)
  To: GCC Patches; +Cc: Diego Novillo, Jan Hubicka, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 3419 bytes --]

This is an update of a patch originally posted and discussed in this  
thread:
http://gcc.gnu.org/ml/gcc-patches/2010-06/threads.html#00995

I guess it needs a global approver - so cc-ing Diego who, IIRC,  
approved the previous EMUTLS changes.

changes from the previous thread.
(a) emutls.c is no longer modified in any way.
(b) I have taken on board the comments about not rearranging code.
(c) the cases where we should not have emutls variables are now asserts.

tested on {i686,powerpc*}-apple-darwin{8,9},  x86_64-apple-darwin10 -  
EMUTLS target without aliases.
    {i686,x86_64}unknown-linux-gnu - native TLS targets (i.e. for a  
null response)
   cris-elf(sim)  - EMUTLS target with aliases
  + armel-linux-eabi(compile-only), mipsabi64-elf(sim), s390x(sompile  
only).

The test-suite additions are motivated by:
(a) the fact that initialization of the emults vars was a weakness  
w.r.t. optimization,
(b) to include the test that is used as the configury check for TLS  
compliance.


OK for trunk now? (and eventually 4.5)?

Iain

gcc/Changelog (email addresses omitted)
	
	Iain Sandoe
	Jan Hubika

	PR target/44132
	* expr.c (emutls_var_address): Remove.
	(expand_expr_addr_expr_1): Remove TLS emulation hook.
	(expand_expr_real_1): Ditto.

	* gimplify.c (emutls_var_address): Add proc.
	(gimplify_decl_expr): expand TLS vars.
	(gimplify_var_or_parm_decl): Ditto.
	(omp_notice_variable): Recognize TLS_MODEL_EMULATED.

	* passes.c (rest_of_decl_compilation): Substitute TLS control vars  
for the master.

	* varasm.c (get_emutls_init_templ_addr): Do not reset the caller's  
DECL_INITIAL.
	(emutls_decl): copy DECL_PRESERVE_P instead of setting it, copy
	TREE_ADDRESSABLE.  Create the init template as soon as we see a valid  
initializer.
	 Mark the original var with error_mark_node so that re- 
initializations will be diagnosed
	properly.  Mark the original var as not to be output.
	(emutls_common_1): Do not rely on DECL_COMMON as a decision on  
whether a constructor
	is needed, it is also required for lcomm.   Ensure that the var is  
laid out before the constructor
	is built.
	(emutls_finalize_control_var): Assert on incorrect type, copy USED.
	(asm_output_bss): Assert on DECL_THREAD_LOCAL_P for EMUTLS targets.
	(asm_output_aligned_bss): Likewise.
	(assemble_variable): Remove TLS var. substitution.  Back up  
TREE_ASM_WRITTEN so that
	assemble_variable() has no side-effects for unwritten vars.  Assert  
on DECL_THREAD_LOCAL_P
	for EMUTLS targets.
	(do_assemble_alias): Assert on DECL_THREAD_LOCAL_P for EMUTLS targets.
	(var_decl_for_asm): New.
	(finish_aliases_1): Walk alias pairs substituting tls controls for  
originals.

	* passes.c (rest_of_decl_compilation): Substitute TLS control vars  
for the master.

	* varpool.c (varpool_mark_needed_node): Do not handle TLS  
substitution here.
	(decide_is_variable_needed): Or here.
	(varpool_finalize_decl): Handle TLS substitution.
	Remove early calls to varpool_assemble_pending_decls().
	Check enqueuing of vars after all tests for need are complete.
	(varpool_analyze_pending_decls): Do not record references if the  
initializer is error_mark.

testsuite:
	
	PR target/44132
	* gcc.dg/tls/thr-init-1.c: New.
	* gcc.dg/tls/thr-init-2.c: New.
	* gcc.dg/torture/tls New.
	* gcc.dg/torture/tls/tls-test.c: New.
	* gcc.dg/torture/tls/thr-init-1.c: New.
	* gcc.dg/torture/tls/tls.exp: New.
	* gcc.dg/torture/tls/thr-init-2.c: New.


[-- Attachment #2: 161773-emutls-lto.txt --]
[-- Type: text/plain, Size: 21739 bytes --]

Index: gcc/expr.c
===================================================================
--- gcc/expr.c	(revision 161773)
+++ gcc/expr.c	(working copy)
@@ -6862,21 +6862,7 @@ highest_pow2_factor_for_target (const_tree target,
 
   return MAX (factor, talign);
 }
-\f
-/* Return &VAR expression for emulated thread local VAR.  */
 
-static tree
-emutls_var_address (tree var)
-{
-  tree emuvar = emutls_decl (var);
-  tree fn = built_in_decls [BUILT_IN_EMUTLS_GET_ADDRESS];
-  tree arg = build_fold_addr_expr_with_type (emuvar, ptr_type_node);
-  tree arglist = build_tree_list (NULL_TREE, arg);
-  tree call = build_function_call_expr (UNKNOWN_LOCATION, fn, arglist);
-  return fold_convert (build_pointer_type (TREE_TYPE (var)), call);
-}
-\f
-
 /* Subroutine of expand_expr.  Expand the two operands of a binary
    expression EXP0 and EXP1 placing the results in OP0 and OP1.
    The value may be stored in TARGET if TARGET is nonzero.  The
@@ -6980,17 +6966,6 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enu
       break;
 
     case VAR_DECL:
-      /* TLS emulation hook - replace __thread VAR's &VAR with
-	 __emutls_get_address (&_emutls.VAR).  */
-      if (! targetm.have_tls
-	  && TREE_CODE (exp) == VAR_DECL
-	  && DECL_THREAD_LOCAL_P (exp))
-	{
-	  exp = emutls_var_address (exp);
-	  return expand_expr (exp, target, tmode, modifier);
-	}
-      /* Fall through.  */
-
     default:
       /* If the object is a DECL, then expand it for its rtl.  Don't bypass
 	 expand_expr, as that can have various side effects; LABEL_DECLs for
@@ -8428,16 +8403,6 @@ expand_expr_real_1 (tree exp, rtx target, enum mac
 	  && (TREE_STATIC (exp) || DECL_EXTERNAL (exp)))
 	layout_decl (exp, 0);
 
-      /* TLS emulation hook - replace __thread vars with
-	 *__emutls_get_address (&_emutls.var).  */
-      if (! targetm.have_tls
-	  && TREE_CODE (exp) == VAR_DECL
-	  && DECL_THREAD_LOCAL_P (exp))
-	{
-	  exp = build_fold_indirect_ref_loc (loc, emutls_var_address (exp));
-	  return expand_expr_real_1 (exp, target, tmode, modifier, NULL);
-	}
-
       /* ... fall through ...  */
 
     case FUNCTION_DECL:
Index: gcc/gimplify.c
===================================================================
--- gcc/gimplify.c	(revision 161773)
+++ gcc/gimplify.c	(working copy)
@@ -1341,7 +1341,19 @@ gimplify_vla_decl (tree decl, gimple_seq *seq_p)
   gimplify_ctxp->save_stack = true;
 }
 
+/* Return &VAR expression for emulated thread local VAR.  */
 
+static tree
+emutls_var_address (tree var)
+{
+  tree emuvar = emutls_decl (var);
+  tree fn = built_in_decls [BUILT_IN_EMUTLS_GET_ADDRESS];
+  tree arg = build_fold_addr_expr_with_type (emuvar, ptr_type_node);
+  tree arglist = build_tree_list (NULL_TREE, arg);
+  tree call = build_function_call_expr (UNKNOWN_LOCATION, fn, arglist);
+  return fold_convert (build_pointer_type (TREE_TYPE (var)), call);
+}
+
 /* Gimplifies a DECL_EXPR node *STMT_P by making any necessary allocation
    and initialization explicit.  */
 
@@ -1356,6 +1368,18 @@ gimplify_decl_expr (tree *stmt_p, gimple_seq *seq_
   if (TREE_TYPE (decl) == error_mark_node)
     return GS_ERROR;
 
+  /* TLS emulation hook - replace __thread VAR's &VAR with
+     __emutls_get_address (&_emutls.VAR). We then ignore the original
+     var.  */
+  if (! targetm.have_tls
+      && TREE_CODE (decl) == VAR_DECL
+      && DECL_THREAD_LOCAL_P (decl))
+    {
+      stmt = build_fold_indirect_ref (emutls_var_address (decl));
+      gimplify_and_add (stmt, seq_p);
+      return GS_ALL_DONE;
+    }
+
   if ((TREE_CODE (decl) == TYPE_DECL
        || TREE_CODE (decl) == VAR_DECL)
       && !TYPE_SIZES_GIMPLIFIED (TREE_TYPE (decl)))
@@ -1875,6 +1899,17 @@ gimplify_var_or_parm_decl (tree *expr_p)
       return GS_ERROR;
     }
 
+  /* TLS emulation hook - replace __thread VAR's &VAR with
+     __emutls_get_address (&_emutls.VAR).  */
+  if (! targetm.have_tls
+      && TREE_CODE (decl) == VAR_DECL
+      && DECL_THREAD_LOCAL_P (decl))
+    {
+      gcc_assert (!DECL_HAS_VALUE_EXPR_P (decl)) ;
+      *expr_p = build_fold_indirect_ref (emutls_var_address (decl));
+      return GS_OK ;
+    }
+
   /* When within an OpenMP context, notice uses of variables.  */
   if (gimplify_omp_ctxp && omp_notice_variable (gimplify_omp_ctxp, decl, true))
     return GS_ALL_DONE;
@@ -5555,14 +5590,15 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx,
   /* Threadprivate variables are predetermined.  */
   if (is_global_var (decl))
     {
-      if (DECL_THREAD_LOCAL_P (decl))
+      if ((DECL_TLS_MODEL (decl) >= TLS_MODEL_EMULATED))
 	return omp_notice_threadprivate_variable (ctx, decl, NULL_TREE);
 
       if (DECL_HAS_VALUE_EXPR_P (decl))
 	{
 	  tree value = get_base_address (DECL_VALUE_EXPR (decl));
 
-	  if (value && DECL_P (value) && DECL_THREAD_LOCAL_P (value))
+	  if (value && DECL_P (value) && 
+	      (DECL_TLS_MODEL (value) >= TLS_MODEL_EMULATED))
 	    return omp_notice_threadprivate_variable (ctx, decl, value);
 	}
     }
Index: gcc/varasm.c
===================================================================
--- gcc/varasm.c	(revision 161773)
+++ gcc/varasm.c	(working copy)
@@ -319,9 +319,11 @@ get_emutls_init_templ_addr (tree decl)
   TREE_USED (to) = TREE_USED (decl);
   TREE_READONLY (to) = 1;
   DECL_IGNORED_P (to) = 1;
+
+  DECL_PRESERVE_P (to) = 1;
+  
   DECL_CONTEXT (to) = DECL_CONTEXT (decl);
   DECL_SECTION_NAME (to) = DECL_SECTION_NAME (decl);
-  DECL_PRESERVE_P (to) = DECL_PRESERVE_P (decl);
 
   DECL_WEAK (to) = DECL_WEAK (decl);
   if (DECL_ONE_ONLY (decl))
@@ -336,7 +338,6 @@ get_emutls_init_templ_addr (tree decl)
 
   DECL_VISIBILITY_SPECIFIED (to) = DECL_VISIBILITY_SPECIFIED (decl);
   DECL_INITIAL (to) = DECL_INITIAL (decl);
-  DECL_INITIAL (decl) = NULL;
 
   varpool_finalize_decl (to);
   return build_fold_addr_expr (to);
@@ -361,6 +362,8 @@ emutls_decl (tree decl)
   if (! emutls_htab)
     emutls_htab = htab_create_ggc (512, tree_map_hash, tree_map_eq, 0);
 
+  gcc_assert (DECL_NAME (decl)) ;
+  
   name = DECL_ASSEMBLER_NAME (decl);
 
   /* Note that we use the hash of the decl's name, rather than a hash
@@ -387,8 +390,7 @@ emutls_decl (tree decl)
       DECL_TLS_MODEL (to) = TLS_MODEL_EMULATED;
       DECL_ARTIFICIAL (to) = 1;
       DECL_IGNORED_P (to) = 1;
-      /* FIXME: work around PR44132.  */
-      DECL_PRESERVE_P (to) = 1;
+
       TREE_READONLY (to) = 0;
       SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
       if (DECL_ONE_ONLY (decl))
@@ -412,18 +414,42 @@ emutls_decl (tree decl)
   TREE_STATIC (to) = TREE_STATIC (decl);
   TREE_USED (to) = TREE_USED (decl);
   TREE_PUBLIC (to) = TREE_PUBLIC (decl);
+  TREE_ADDRESSABLE (to) = TREE_ADDRESSABLE (decl);
   DECL_EXTERNAL (to) = DECL_EXTERNAL (decl);
   DECL_COMMON (to) = DECL_COMMON (decl);
   DECL_WEAK (to) = DECL_WEAK (decl);
   DECL_VISIBILITY (to) = DECL_VISIBILITY (decl);
   DECL_VISIBILITY_SPECIFIED (to) = DECL_VISIBILITY_SPECIFIED (decl);
+  DECL_PRESERVE_P (to) = DECL_PRESERVE_P (decl);
   
   /* Fortran might pass this to us.  */
   DECL_RESTRICTED_P (to) = DECL_RESTRICTED_P (decl);
+  
+  /* As soon as we see an initializer (and providing one is not already
+     present) we can setup the init. template.  */
+  if (!DECL_INITIAL (to) && 
+      DECL_INITIAL (decl) && (DECL_INITIAL (decl) != error_mark_node)) 
+    if (! DECL_EXTERNAL (to) && ! DECL_COMMON (to))
+      {
+	DECL_INITIAL (to) = targetm.emutls.var_init
+		(to, decl, get_emutls_init_templ_addr (decl));
 
+	/* Make sure the template is marked as needed early enough.
+	   Without this, if the variable is placed in a
+	   section-anchored block, the template will only be marked
+	   when it's too late.*/
+	record_references_in_initializer (to, false);
+	/* We leave this marked, so that any attempt at duplicate
+	   or re-initialization will give the appropriate error.  */
+	DECL_INITIAL (decl) = error_mark_node ;
+      }
+  /* Say we are not interested in emitting this Var.  */
+  TREE_ASM_WRITTEN (decl) = 1;
   return to;
 }
 
+/* Add static constructors for emutls vars, where required.  */
+
 static int
 emutls_common_1 (void **loc, void *xstmts)
 {
@@ -431,17 +457,21 @@ emutls_common_1 (void **loc, void *xstmts)
   tree args, x, *pstmts = (tree *) xstmts;
   tree word_type_node;
 
-  if (! DECL_COMMON (h->base.from)
-      || (DECL_INITIAL (h->base.from)
-	  && DECL_INITIAL (h->base.from) != error_mark_node))
+  /* ??? It is not enough to check DECL_COMMON because variables might be 
+     allocated in other uninitialized sections.  However, this might still
+     not be an adequate test.  */
+  if (DECL_INITIAL (h->to))
     return 1;
+  
+  /* Refuse to build a zero-sized item, first make sure there's
+     a valid layout.  */
+  if (DECL_SIZE (h->base.from) == 0)
+    layout_decl (h->base.from, 0);
+	
+  gcc_assert (DECL_SIZE (h->base.from) != 0);
 
   word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
 
-  /* The idea was to call get_emutls_init_templ_addr here, but if we
-     do this and there is an initializer, -fanchor_section loses,
-     because it would be too late to ensure the template is
-     output.  */
   x = null_pointer_node;
   args = tree_cons (NULL, x, NULL);
   x = build_int_cst (word_type_node, DECL_ALIGN_UNIT (h->base.from));
@@ -468,6 +498,9 @@ emutls_finalize_control_var (void **loc,
   if (h != NULL) 
     {
       struct varpool_node *node = varpool_node (h->to);
+      gcc_assert (! DECL_THREAD_LOCAL_P (h->to));
+      if (TREE_USED (h->base.from)) 
+	TREE_USED (h->to) = 1;
       /* Because varpool_finalize_decl () has side-effects,
          only apply to un-finalized vars.  */
       if (node && !node->finalized) 
@@ -791,6 +824,10 @@ asm_output_bss (FILE *file, tree decl ATTRIBUTE_UN
   gcc_assert (strcmp (XSTR (XEXP (DECL_RTL (decl), 0), 0), name) == 0);
   targetm.asm_out.globalize_decl_name (file, decl);
   switch_to_section (bss_section);
+  /* We don't emit the userland vars for emulated TLS, just the control.  */
+  gcc_assert (targetm.have_tls  
+	      || (TREE_CODE (decl) != VAR_DECL)
+	      || !DECL_THREAD_LOCAL_P (decl));
 #ifdef ASM_DECLARE_OBJECT_NAME
   last_assemble_variable_decl = decl;
   ASM_DECLARE_OBJECT_NAME (file, name, decl);
@@ -817,6 +854,10 @@ asm_output_aligned_bss (FILE *file, tree decl ATTR
 {
   switch_to_section (bss_section);
   ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
+  /* We don't emit the userland vars for emulated TLS, just the control.  */
+  gcc_assert (targetm.have_tls  
+	      || (TREE_CODE (decl) != VAR_DECL)
+	      || !DECL_THREAD_LOCAL_P (decl));
 #ifdef ASM_DECLARE_OBJECT_NAME
   last_assemble_variable_decl = decl;
   ASM_DECLARE_OBJECT_NAME (file, name, decl);
@@ -1232,7 +1273,12 @@ get_variable_section (tree decl, bool prefer_noswi
   if (IN_NAMED_SECTION (decl))
     return get_named_section (decl, NULL, reloc);
 
-  if (ADDR_SPACE_GENERIC_P (as)
+  /* This cannot be lcomm for an emulated TLS object, without
+     a register_common hook.  */
+  if (DECL_TLS_MODEL (decl) == TLS_MODEL_EMULATED
+      && !targetm.emutls.register_common)
+    ;
+  else if (ADDR_SPACE_GENERIC_P (as)
       && !DECL_THREAD_LOCAL_P (decl)
       && !(prefer_noswitch_p && targetm.have_switchable_bss_sections)
       && bss_initializer_p (decl))
@@ -2152,35 +2198,6 @@ assemble_variable (tree decl, int top_level ATTRIB
   rtx decl_rtl, symbol;
   section *sect;
 
-  if (! targetm.have_tls
-      && TREE_CODE (decl) == VAR_DECL
-      && DECL_THREAD_LOCAL_P (decl))
-    {
-      tree to = emutls_decl (decl);
-
-      /* If this variable is defined locally, then we need to initialize the
-         control structure with size and alignment information.  We do this
-	 at the last moment because tentative definitions can take a locally
-	 defined but uninitialized variable and initialize it later, which
-	 would result in incorrect contents.  */
-      if (! DECL_EXTERNAL (to)
-	  && (! DECL_COMMON (to)
-	      || (DECL_INITIAL (decl)
-		  && DECL_INITIAL (decl) != error_mark_node)))
-	{
-	  DECL_INITIAL (to) = targetm.emutls.var_init
-	    (to, decl, get_emutls_init_templ_addr (decl));
-
-	  /* Make sure the template is marked as needed early enough.
-	     Without this, if the variable is placed in a
-	     section-anchored block, the template will only be marked
-	     when it's too late.  */
-	  record_references_in_initializer (to, false);
-	}
-
-      decl = to;
-    }
-
   last_assemble_variable_decl = 0;
 
   /* Normally no need to say anything here for external references,
@@ -2196,6 +2213,14 @@ assemble_variable (tree decl, int top_level ATTRIB
   if (TREE_CODE (decl) == FUNCTION_DECL)
     return;
 
+  /* The first declaration of a variable that comes through this function
+     decides whether it is global (in C, has external linkage)
+     or local (in C, has internal linkage).  So do nothing more
+     if this function has already run.  */
+
+  if (TREE_ASM_WRITTEN (decl))
+    return;
+
   /* Do nothing for global register variables.  */
   if (DECL_RTL_SET_P (decl) && REG_P (DECL_RTL (decl)))
     {
@@ -2219,14 +2244,6 @@ assemble_variable (tree decl, int top_level ATTRIB
       return;
     }
 
-  /* The first declaration of a variable that comes through this function
-     decides whether it is global (in C, has external linkage)
-     or local (in C, has internal linkage).  So do nothing more
-     if this function has already run.  */
-
-  if (TREE_ASM_WRITTEN (decl))
-    return;
-
   /* Make sure targetm.encode_section_info is invoked before we set
      ASM_WRITTEN.  */
   decl_rtl = DECL_RTL (decl);
@@ -2237,6 +2254,12 @@ assemble_variable (tree decl, int top_level ATTRIB
   if (flag_syntax_only)
     return;
 
+  /* We don't emit the userland vars for emulated TLS - they should never
+     get to here, only the control vars should be emitted.  */
+  gcc_assert (targetm.have_tls  
+	      || (TREE_CODE (decl) != VAR_DECL)
+	      || !DECL_THREAD_LOCAL_P (decl));
+
   if (! dont_output_data
       && ! host_integerp (DECL_SIZE_UNIT (decl), 1))
     {
@@ -5700,18 +5723,14 @@ do_assemble_alias (tree decl, tree target)
   TREE_ASM_WRITTEN (decl) = 1;
   TREE_ASM_WRITTEN (DECL_ASSEMBLER_NAME (decl)) = 1;
 
+  gcc_assert (targetm.have_tls  
+	      || (TREE_CODE (decl) != VAR_DECL)
+	      || !DECL_THREAD_LOCAL_P (decl));
+
   if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
     {
       ultimate_transparent_alias_target (&target);
 
-      if (!targetm.have_tls
-	  && TREE_CODE (decl) == VAR_DECL
-	  && DECL_THREAD_LOCAL_P (decl))
-	{
-	  decl = emutls_decl (decl);
-	  target = get_emutls_object_name (target);
-	}
-
       if (!TREE_SYMBOL_REFERENCED (target))
 	weakref_targets = tree_cons (decl, target, weakref_targets);
 
@@ -5730,14 +5749,6 @@ do_assemble_alias (tree decl, tree target)
       return;
     }
 
-  if (!targetm.have_tls
-      && TREE_CODE (decl) == VAR_DECL
-      && DECL_THREAD_LOCAL_P (decl))
-    {
-      decl = emutls_decl (decl);
-      target = get_emutls_object_name (target);
-    }
-
 #ifdef ASM_OUTPUT_DEF
   /* Make name accessible from other files, if appropriate.  */
 
@@ -5819,6 +5830,15 @@ remove_unreachable_alias_pairs (void)
     }
 }
 
+/* Lookup the decl for a symbol in the varpool.  */
+static tree
+var_decl_for_asm (tree symbol)
+{
+  struct varpool_node *vnode = varpool_node_for_asm  (symbol);
+  if (vnode) 
+    return vnode->decl;
+  return NULL;
+}
 
 /* First pass of completing pending aliases.  Make sure that cgraph knows
    which symbols will be required.  */
@@ -5831,8 +5851,55 @@ finish_aliases_1 (void)
 
   for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); i++)
     {
-      tree target_decl;
+      tree target_decl=NULL;
 
+      /* When emulated TLS is in effect, redirect aliases so that they 
+         are registered between the control vars.  */
+      if (!targetm.have_tls 
+          && TREE_CODE (p->decl) == VAR_DECL
+          && (DECL_TLS_MODEL (p->decl) >= TLS_MODEL_EMULATED))
+	{
+	  tree tsym = p->target ;
+	  target_decl = var_decl_for_asm (tsym) ;
+	  if (!target_decl) 
+	    {
+	      /* If we didn't find the user's symbol, it could
+	         be because the alias really refers to a control 
+	         var.  */
+	      tsym = get_emutls_object_name (p->target);
+	      target_decl = var_decl_for_asm (tsym);
+	    }
+	  if (target_decl) 
+	    {
+	      struct varpool_node *vnode;
+	      /* If it hasn't been done already, substitute the control
+	         var for the original.  */
+	      if (DECL_THREAD_LOCAL_P (p->decl))
+		p->decl = emutls_decl (p->decl);
+	      /* If not TLS target, we've made a mistake.  */
+	      if (DECL_TLS_MODEL (target_decl) < TLS_MODEL_EMULATED)
+		error ("TLS symbol %q+D aliased to non-TLS symbol %qE",
+			p->decl, p->target);
+	      /* If it's the original we need to substitute the contol.  */
+	      else if (DECL_THREAD_LOCAL_P (target_decl))
+		{
+		  target_decl = emutls_decl (target_decl);
+		  tsym = get_emutls_object_name (p->target);
+		}
+	      /* else it's already the emulation control.  */
+	      /* Mark the var needed.  */
+	      vnode = varpool_node (target_decl);
+	      if (vnode) 
+	        {
+		  varpool_mark_needed_node (vnode);
+		  vnode->force_output = 1;
+	        }
+	      p->target = tsym;
+	    }
+	  /* Else we didn't find a decl for the symbol, which is an error
+	     unless there's a weak ref.  */
+	} 
+      else
       target_decl = find_decl_and_mark_needed (p->decl, p->target);
       if (target_decl == NULL)
 	{
Index: gcc/passes.c
===================================================================
--- gcc/passes.c	(revision 161773)
+++ gcc/passes.c	(working copy)
@@ -152,6 +152,16 @@ rest_of_decl_compilation (tree decl,
 			  int top_level,
 			  int at_end)
 {
+  if (! targetm.have_tls 
+	&& !in_lto_p 
+	&& TREE_CODE (decl) == VAR_DECL
+	&& DECL_THREAD_LOCAL_P (decl))
+    {
+      /* Substitute the control var. for the user one.  */
+      rest_of_decl_compilation (emutls_decl (decl), top_level, at_end);
+      return;
+    }
+
   /* We deferred calling assemble_alias so that we could collect
      other attributes such as visibility.  Emit the alias now.  */
   {
Index: gcc/varpool.c
===================================================================
--- gcc/varpool.c	(revision 161773)
+++ gcc/varpool.c	(working copy)
@@ -312,6 +312,14 @@ varpool_mark_needed_node (struct varpool_node *nod
       && !TREE_ASM_WRITTEN (node->decl))
     varpool_enqueue_needed_node (node);
   node->needed = 1;
+  /* If we need the var, and it's an emulated TLS entity, that
+     means we need the control var.  */
+  if (!targetm.have_tls && DECL_THREAD_LOCAL_P (node->decl))
+    {
+      struct varpool_node *cv_node;
+      cv_node = varpool_node (emutls_decl (node->decl)) ;
+      varpool_mark_needed_node (cv_node);
+    }
 }
 
 /* Reset the queue of needed nodes.  */
@@ -346,17 +354,6 @@ decide_is_variable_needed (struct varpool_node *no
       && !DECL_EXTERNAL (decl))
     return true;
 
-  /* When emulating tls, we actually see references to the control
-     variable, rather than the user-level variable.  */
-  if (!targetm.have_tls
-      && TREE_CODE (decl) == VAR_DECL
-      && DECL_THREAD_LOCAL_P (decl))
-    {
-      tree control = emutls_decl (decl);
-      if (decide_is_variable_needed (varpool_node (control), control))
-	return true;
-    }
-
   /* When not reordering top level variables, we have to assume that
      we are going to keep everything.  */
   if (flag_toplevel_reorder)
@@ -381,14 +378,19 @@ varpool_finalize_decl (tree decl)
      or local (in C, has internal linkage).  So do nothing more
      if this function has already run.  */
   if (node->finalized)
+      return;
+
+  /* For emulated TLS vars, if we are in a position to finalize the userland
+     var, then we should be able to finalize the control var too.  */
+  if (!targetm.have_tls && decl 
+      && TREE_CODE (decl) == VAR_DECL
+      && DECL_THREAD_LOCAL_P (decl))
     {
-      if (cgraph_global_info_ready)
-	varpool_assemble_pending_decls ();
+      varpool_finalize_decl (emutls_decl (decl)) ;
+      node->finalized = true;    
       return;
     }
-  if (node->needed)
-    varpool_enqueue_needed_node (node);
-  node->finalized = true;
+
   if (TREE_THIS_VOLATILE (decl) || DECL_PRESERVE_P (decl))
     node->force_output = true;
 
@@ -399,8 +401,11 @@ varpool_finalize_decl (tree decl)
      there.  */
   else if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
     varpool_mark_needed_node (node);
-  if (cgraph_global_info_ready)
-    varpool_assemble_pending_decls ();
+
+  if (node->needed)
+    varpool_enqueue_needed_node (node);
+
+  node->finalized = true;
 }
 
 /* Return variable availability.  See cgraph.h for description of individual
@@ -449,7 +454,7 @@ varpool_analyze_pending_decls (void)
 	     already informed about increased alignment.  */
           align_variable (decl, 0);
 	}
-      if (DECL_INITIAL (decl))
+      if (DECL_INITIAL (decl) && (DECL_INITIAL (decl) != error_mark_node))
 	record_references_in_initializer (decl, analyzed);
       if (node->same_comdat_group)
 	{

[-- Attachment #3: Type: text/plain, Size: 2 bytes --]




[-- Attachment #4: 161773-tls-testsuite-additions.txt --]
[-- Type: text/plain, Size: 5294 bytes --]

Index: gcc/testsuite/gcc.dg/tls/thr-init-1.c
===================================================================
--- gcc/testsuite/gcc.dg/tls/thr-init-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/tls/thr-init-1.c	(revision 0)
@@ -0,0 +1,8 @@
+/* { dg-require-effective-target tls } */
+/* { dg-do compile } */
+
+static __thread int fstat ;
+static __thread int fstat = 1 ;
+static __thread int fstat ;
+static __thread int fstat = 2; /* { dg-error "redefinition of 'fstat'" } */
+				/* { dg-message "note: previous definition of 'fstat' was here" "" { target *-*-* } 5 } */
Index: gcc/testsuite/gcc.dg/tls/thr-init-2.c
===================================================================
--- gcc/testsuite/gcc.dg/tls/thr-init-2.c	(revision 0)
+++ gcc/testsuite/gcc.dg/tls/thr-init-2.c	(revision 0)
@@ -0,0 +1,23 @@
+/* { dg-require-effective-target tls } */
+/* { dg-do run } */
+
+extern void abort() ;
+
+static __thread int fstat ;
+static __thread int fstat = 1;
+
+int test_code(int b)
+{
+  fstat += b ;
+  return fstat;
+}
+
+int main (int ac, char *av[])
+{
+  int a = test_code(1);
+  
+  if ((a != 2) || (fstat != 2))
+    abort () ;
+  
+  return 0;
+}
Index: gcc/testsuite/gcc.dg/torture/tls/tls-test.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/tls/tls-test.c	(revision 0)
+++ gcc/testsuite/gcc.dg/torture/tls/tls-test.c	(revision 0)
@@ -0,0 +1,51 @@
+/* { dg-do run }  */
+/* { dg-require-effective-target tls  }  */
+/* { dg-require-effective-target pthread } */
+
+#include <pthread.h>
+extern int printf (char *,...);
+__thread int a = 5; 
+int *volatile a_in_other_thread = (int *) 12345;
+
+static void *
+thread_func (void *arg)
+{
+  a_in_other_thread = &a;
+  a+=5;
+  *((int *) arg) = a;
+  return (void *)0;
+}
+
+int
+main ()
+{
+  pthread_t thread;
+  void *thread_retval;
+  int *volatile a_in_main_thread;
+  int *volatile again ;
+  int thr_a;
+
+  a_in_main_thread = &a;
+
+  if (pthread_create (&thread, (pthread_attr_t *)0, thread_func, &thr_a))
+    return 0;
+
+  if (pthread_join (thread, &thread_retval))
+    return 0;
+
+  again = &a;
+  if (again != a_in_main_thread)
+    {
+      printf ("FAIL: main thread addy changed from 0x%0x to 0x%0x\n", 
+		a_in_other_thread, again);
+      return 1;
+    }
+
+  if (a != 5 || thr_a != 10 || (a_in_other_thread == a_in_main_thread))
+    {
+      printf ("FAIL: a= %d, thr_a = %d Addr = 0x%0x\n", 
+		a, thr_a, a_in_other_thread);
+      return 1;
+    }
+  return 0;
+}
Index: gcc/testsuite/gcc.dg/torture/tls/thr-init-1.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/tls/thr-init-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/torture/tls/thr-init-1.c	(revision 0)
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-require-effective-target tls } */
+
+extern int printf (char *,...);
+extern void abort() ;
+
+int test_code(int b)
+{
+static __thread int fstat = 1;
+  fstat += b ;
+  return fstat;
+}
+
+int main (int ac, char *av[])
+{
+  int a = test_code(1);
+  
+  if ( a != 2 )
+    {
+      printf ("a=%d\n", a) ;
+      abort ();
+    }
+  
+  return 0;
+}
Index: gcc/testsuite/gcc.dg/torture/tls/tls.exp
===================================================================
--- gcc/testsuite/gcc.dg/torture/tls/tls.exp	(revision 0)
+++ gcc/testsuite/gcc.dg/torture/tls/tls.exp	(revision 0)
@@ -0,0 +1,36 @@
+#   Copyright (C) 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+    set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] \
+        $DEFAULT_CFLAGS
+
+# All done.
+dg-finish
Index: gcc/testsuite/gcc.dg/torture/tls/thr-init-2.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/tls/thr-init-2.c	(revision 0)
+++ gcc/testsuite/gcc.dg/torture/tls/thr-init-2.c	(revision 0)
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-require-effective-target tls } */
+
+extern int printf (char *,...);
+extern void abort() ;
+
+static __thread int fstat ;
+static __thread int fstat = 1;
+static __thread int fstat ;
+
+int test_code(int b)
+{
+  fstat += b ;
+  return fstat;
+}
+
+int main (int ac, char *av[])
+{
+  int a = test_code(1);
+  
+  if ( a != 2 || fstat != 2 )
+    {
+    printf ("a=%d fstat=%d\n", a, fstat) ;
+    abort ();
+    }
+  
+  return 0;
+}

[-- Attachment #5: Type: text/plain, Size: 1 bytes --]



^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2010-07-14 16:25 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-07-03 14:11 [Patch, updated] Make emulated TLS lto-friendly IainS
2010-07-07 23:22 ` Richard Henderson
2010-07-08  8:42   ` IainS
2010-07-08  9:32     ` Jakub Jelinek
2010-07-08 12:01       ` IainS
2010-07-08 17:10         ` Richard Henderson
2010-07-08 17:21           ` Jan Hubicka
2010-07-08 17:34             ` Richard Henderson
2010-07-08 16:14     ` Richard Henderson
2010-07-08 16:21       ` IainS
2010-07-08 17:04         ` Richard Henderson
2010-07-08  9:25   ` Richard Guenther
2010-07-08 11:59     ` [Patch, testsuite] " IainS
2010-07-08 12:05       ` IainS
2010-07-08 19:07   ` IainS
2010-07-08 19:19     ` Richard Henderson
2010-07-09 12:11       ` IainS
2010-07-12 14:48         ` Jack Howarth
2010-07-12 15:18         ` Richard Henderson
2010-07-12 17:04           ` Richard Henderson
2010-07-12 20:08             ` Richard Henderson
2010-07-13 15:47               ` Richard Henderson
2010-07-13 18:56                 ` Richard Henderson
2010-07-13 20:01                   ` Richard Henderson
2010-07-13 20:04                     ` Nathan Froyd
2010-07-13 21:20                       ` Richard Henderson
2010-07-13 21:23                         ` Nathan Froyd
2010-07-13 20:46                     ` Richard Guenther
2010-07-13 21:19                       ` Richard Henderson
2010-07-13 21:39                         ` Andrew Pinski
2010-07-13 21:48                           ` Richard Henderson
2010-07-14  8:26                             ` Richard Guenther
2010-07-14 16:00                               ` Richard Henderson
2010-07-14 16:25                                 ` Richard Guenther
2010-07-14  8:11                         ` Richard Guenther

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).