public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [CFT, try 7] Emulated tls rewrite
@ 2010-07-14 23:50 Richard Henderson
  2010-07-15  7:49 ` Richard Guenther
                   ` (2 more replies)
  0 siblings, 3 replies; 28+ messages in thread
From: Richard Henderson @ 2010-07-14 23:50 UTC (permalink / raw)
  To: IainS; +Cc: GCC Patches, richard.guenther

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

This go-around handles phi nodes, as requested by Richi.  This was much more
irritating than it should have been, due to immediate use maintainence.  It
also gets re-arranged to use walk_gimple_ops, which I should have been using
in the first place.

The testsuite is still running here, amd64-linux --disable-tls, but I'm
quitting for today.  I never got around to looking at those non-tls.exp
testsuite failures, Iain.  Hopefully they went away magically.  ;-)


r~

[-- Attachment #2: emutls-7 --]
[-- Type: text/plain, Size: 52360 bytes --]

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 5a45701..893d30d 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1354,6 +1354,7 @@ OBJS-common = \
 	tree-diagnostic.o \
 	tree-dump.o \
 	tree-eh.o \
+	tree-emutls.o \
 	tree-if-conv.o \
 	tree-into-ssa.o \
 	tree-iterator.o \
@@ -3142,6 +3143,9 @@ tree-switch-conversion.o : tree-switch-conversion.c $(CONFIG_H) $(SYSTEM_H) \
 tree-complex.o : tree-complex.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
     $(TM_H) $(FLAGS_H) $(TREE_FLOW_H) $(GIMPLE_H) \
     tree-iterator.h $(TREE_PASS_H) tree-ssa-propagate.h $(DIAGNOSTIC_H)
+tree-emutls.o : tree-emutls.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
+    $(GIMPLE_H) $(TREE_PASS_H) $(TREE_FLOW_H) $(CGRAPH_H) langhooks.h \
+    $(TARGET_H) targhooks.h tree-iterator.h output.h gt-tree-emutls.h
 tree-vect-generic.o : tree-vect-generic.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \
     $(TM_H) $(TREE_FLOW_H) $(GIMPLE_H) tree-iterator.h $(TREE_PASS_H) \
     $(FLAGS_H) $(OPTABS_H) $(MACHMODE_H) $(EXPR_H) \
@@ -3746,6 +3750,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
   $(srcdir)/tree-ssanames.c $(srcdir)/tree-eh.c $(srcdir)/tree-ssa-address.c \
   $(srcdir)/tree-cfg.c \
   $(srcdir)/tree-dfa.c \
+  $(srcdir)/tree-emutls.c \
   $(srcdir)/tree-iterator.c $(srcdir)/gimplify.c \
   $(srcdir)/tree-chrec.h \
   $(srcdir)/tree-scalar-evolution.c \
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index f0d0a97..f9d45ec 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -418,12 +418,17 @@ cgraph_process_new_functions (void)
 	  push_cfun (DECL_STRUCT_FUNCTION (fndecl));
 	  current_function_decl = fndecl;
 	  compute_inline_parameters (node);
-	  if ((cgraph_state == CGRAPH_STATE_IPA_SSA
-	      && !gimple_in_ssa_p (DECL_STRUCT_FUNCTION (fndecl)))
-	      /* When not optimizing, be sure we run early local passes anyway
-		 to expand OMP.  */
-	      || !optimize)
+
+	  /* ??? Honza: what's the real difference between IPA and IPA_SSA?
+	     We seem to be assuming that the "real" ipa passes require SSA
+	     but that the "small" ipa passes do not.  This is false.  Any
+	     new function created by a "small" ipa pass *must* have the
+	     early local passes run so that (at least) init_datastructures
+	     gets executed.  Failure to do so results in an immediate crash
+	     once we get to pass_all_optimizations.  */
+	  if (!gimple_in_ssa_p (DECL_STRUCT_FUNCTION (fndecl)))
 	    execute_pass_list (pass_early_local_passes.pass.sub);
+
 	  free_dominance_info (CDI_POST_DOMINATORS);
 	  free_dominance_info (CDI_DOMINATORS);
 	  pop_cfun ();
@@ -2064,7 +2069,9 @@ cgraph_build_static_cdtor (char which, tree body, int priority)
 
   cgraph_add_new_function (decl, false);
   cgraph_mark_needed_node (cgraph_node (decl));
+
   set_cfun (NULL);
+  current_function_decl = NULL;
 }
 
 void
diff --git a/gcc/expr.c b/gcc/expr.c
index 899d5b8..07e2d7e 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -6819,19 +6819,6 @@ highest_pow2_factor_for_target (const_tree target, const_tree exp)
   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 call = build_call_expr (fn, 1, arg);
-  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
@@ -6934,18 +6921,6 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
       inner = TREE_OPERAND (exp, 0);
       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
@@ -8383,16 +8358,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 	  && (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:
diff --git a/gcc/output.h b/gcc/output.h
index d1e5f24..1756efc 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -165,9 +165,6 @@ extern void merge_weak (tree, tree);
 /* Emit any pending weak declarations.  */
 extern void weak_finish (void);
 
-/* Emit any pending emutls declarations and initializations.  */
-extern void emutls_finish (void);
-
 /* Return the default TLS model for a given variable.  */
 extern enum tls_model decl_default_tls_model (const_tree);
 
diff --git a/gcc/passes.c b/gcc/passes.c
index 72e9b5a..5a4cdc8 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -804,6 +804,7 @@ init_optimization_passes (void)
     }
   NEXT_PASS (pass_ipa_increase_alignment);
   NEXT_PASS (pass_ipa_matrix_reorg);
+  NEXT_PASS (pass_ipa_lower_emutls);
   *p = NULL;
 
   p = &all_regular_ipa_passes;
diff --git a/gcc/testsuite/gcc.dg/tls/thr-init-1.c b/gcc/testsuite/gcc.dg/tls/thr-init-1.c
new file mode 100644
index 0000000..de273d9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tls/thr-init-1.c
@@ -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 } */
diff --git a/gcc/testsuite/gcc.dg/tls/thr-init-2.c b/gcc/testsuite/gcc.dg/tls/thr-init-2.c
new file mode 100644
index 0000000..6d00d8c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tls/thr-init-2.c
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/tls/thr-init-1.c b/gcc/testsuite/gcc.dg/torture/tls/thr-init-1.c
new file mode 100644
index 0000000..89725c3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/tls/thr-init-1.c
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/tls/thr-init-2.c b/gcc/testsuite/gcc.dg/torture/tls/thr-init-2.c
new file mode 100644
index 0000000..9d09319
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/tls/thr-init-2.c
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/tls/tls-test.c b/gcc/testsuite/gcc.dg/torture/tls/tls-test.c
new file mode 100644
index 0000000..a40e15e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/tls/tls-test.c
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/tls/tls.exp b/gcc/testsuite/gcc.dg/torture/tls/tls.exp
new file mode 100644
index 0000000..91c8843
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/tls/tls.exp
@@ -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
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 964669f..60ca5dc 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -992,11 +992,6 @@ compile_file (void)
   if (seen_error ())
     return;
 
-  /* Ensure that emulated TLS control vars are finalized and build 
-     a static constructor for them, when it is required.  */
-  if (!targetm.have_tls)
-    emutls_finish ();
-
   varpool_assemble_pending_decls ();
   finish_aliases_2 ();
 
diff --git a/gcc/tree-emutls.c b/gcc/tree-emutls.c
new file mode 100644
index 0000000..f7eb4cd
--- /dev/null
+++ b/gcc/tree-emutls.c
@@ -0,0 +1,784 @@
+/* Lower TLS operations to emulation functions.
+   Copyright (C) 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any
+later version.
+
+GCC 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/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "tree-flow.h"
+#include "cgraph.h"
+#include "langhooks.h"
+#include "target.h"
+
+/* ??? Should go.  */
+#include "targhooks.h"
+#include "tree-iterator.h"
+#include "output.h"
+
+/* TODO: Get rid of the EMUTLS hooks that no one uses.  */
+
+/* Whenever a target does not support thread-local storage (TLS) natively,
+   we can emulate it with some run-time support in libgcc.  This will in
+   turn rely on "keyed storage" a-la pthread_key_create; essentially all
+   thread libraries provide such functionality.
+
+   In order to coordinate with the libgcc runtime, each TLS variable is
+   described by a "control variable".  This control variable records the
+   required size, alignment, and initial value of the TLS variable for
+   instantiation at runtime.  It also stores an integer token to be used
+   by the runtime to find the address of the variable within each thread.
+
+   On the compiler side, this means that we need to replace all instances
+   of "tls_var" in the code with "*__emutls_get_addr(&control_var)".  We
+   also need to eliminate "tls_var" from the symbol table and introduce
+   "control_var".
+
+   We used to perform all of the transformations during conversion to rtl,
+   and the variable substitutions magically within assemble_variable.
+   However, this late fiddling of the symbol table conflicts with LTO and
+   whole-program compilation.  Therefore we must now make all the changes
+   to the symbol table early in the GIMPLE optimization path, before we
+   write things out to LTO intermediate files.  */
+
+/* These two vectors, once fully populated, are kept in lock-step so that
+   the index of a TLS variable equals the index of its control variable in
+   the other vector.  */
+static GTY (()) varpool_node_set tls_vars;
+static GTY (()) varpool_node_set control_vars;
+
+/* The type of the control structure, shared with the emutls.c runtime.  */
+/* ??? See if we can eliminate the one query via decl_emutls_var_p from
+   varasm.c.  With that gone, this need not be live outside the ipa pass.  */
+static GTY (()) tree emutls_object_type;
+
+/* Emulated TLS objects have the TLS model TLS_MODEL_EMULATED.  This
+   macro can be used on them to distinguish the control variable from
+   the initialization template.  */
+
+bool
+decl_emutls_var_p(const_tree decl)
+{
+  return TREE_TYPE (decl) == emutls_object_type;
+}
+
+#if !defined (NO_DOT_IN_LABEL)
+# define EMUTLS_SEPARATOR	"."
+#elif !defined (NO_DOLLAR_IN_LABEL)
+# define EMUTLS_SEPARATOR	"$"
+#else
+# define EMUTLS_SEPARATOR	"_"
+#endif
+
+/* Create an IDENTIFIER_NODE by prefixing PREFIX to the
+   IDENTIFIER_NODE NAME's name.  */
+
+static tree
+prefix_name (const char *prefix, tree name)
+{
+  unsigned plen = strlen (prefix);
+  unsigned nlen = strlen (IDENTIFIER_POINTER (name));
+  char *toname = (char *) alloca (plen + nlen + 1);
+
+  memcpy (toname, prefix, plen);
+  memcpy (toname + plen, IDENTIFIER_POINTER (name), nlen + 1);
+
+  return get_identifier (toname);
+}
+
+/* Create an identifier for the struct __emutls_object, given an identifier
+   of the DECL_ASSEMBLY_NAME of the original object.  */
+
+static tree
+get_emutls_object_name (tree name)
+{
+  const char *prefix = (targetm.emutls.var_prefix
+			? targetm.emutls.var_prefix
+			: "__emutls_v" EMUTLS_SEPARATOR);
+  return prefix_name (prefix, name);
+}
+
+tree
+default_emutls_var_fields (tree type, tree *name ATTRIBUTE_UNUSED)
+{
+  tree word_type_node, field, next_field;
+
+  field = build_decl (UNKNOWN_LOCATION,
+		      FIELD_DECL, get_identifier ("__templ"), ptr_type_node);
+  DECL_CONTEXT (field) = type;
+  next_field = field;
+
+  field = build_decl (UNKNOWN_LOCATION,
+		      FIELD_DECL, get_identifier ("__offset"),
+		      ptr_type_node);
+  DECL_CONTEXT (field) = type;
+  TREE_CHAIN (field) = next_field;
+  next_field = field;
+
+  word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
+  field = build_decl (UNKNOWN_LOCATION,
+		      FIELD_DECL, get_identifier ("__align"),
+		      word_type_node);
+  DECL_CONTEXT (field) = type;
+  TREE_CHAIN (field) = next_field;
+  next_field = field;
+
+  field = build_decl (UNKNOWN_LOCATION,
+		      FIELD_DECL, get_identifier ("__size"), word_type_node);
+  DECL_CONTEXT (field) = type;
+  TREE_CHAIN (field) = next_field;
+
+  return field;
+}
+
+/* Initialize emulated tls object TO, which refers to TLS variable
+   DECL and is initialized by PROXY.  */
+
+tree
+default_emutls_var_init (tree to, tree decl, tree proxy)
+{
+  VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, 4);
+  constructor_elt *elt;
+  tree type = TREE_TYPE (to);
+  tree field = TYPE_FIELDS (type);
+
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  elt->index = field;
+  elt->value = fold_convert (TREE_TYPE (field), DECL_SIZE_UNIT (decl));
+
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  field = TREE_CHAIN (field);
+  elt->index = field;
+  elt->value = build_int_cst (TREE_TYPE (field),
+			      DECL_ALIGN_UNIT (decl));
+
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  field = TREE_CHAIN (field);
+  elt->index = field;
+  elt->value = null_pointer_node;
+
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  field = TREE_CHAIN (field);
+  elt->index = field;
+  elt->value = proxy;
+
+  return build_constructor (type, v);
+}
+
+/* Create the structure for struct __emutls_object.  This should match the
+   structure at the top of emutls.c, modulo the union there.  */
+
+static tree
+get_emutls_object_type (void)
+{
+  tree type, type_name, field;
+
+  type = emutls_object_type;
+  if (type)
+    return type;
+
+  emutls_object_type = type = lang_hooks.types.make_type (RECORD_TYPE);
+  type_name = NULL;
+  field = targetm.emutls.var_fields (type, &type_name);
+  if (!type_name)
+    type_name = get_identifier ("__emutls_object");
+  type_name = build_decl (UNKNOWN_LOCATION,
+			  TYPE_DECL, type_name, type);
+  TYPE_NAME (type) = type_name;
+  TYPE_FIELDS (type) = field;
+  layout_type (type);
+
+  return type;
+}
+
+/* Create a read-only variable like DECL, with the same DECL_INITIAL.
+   This will be used for initializing the emulated tls data area.  */
+
+static tree
+get_emutls_init_templ_addr (tree decl)
+{
+  tree name, to;
+
+  if (targetm.emutls.register_common && !DECL_INITIAL (decl)
+      && !DECL_SECTION_NAME (decl))
+    return null_pointer_node;
+
+  name = DECL_ASSEMBLER_NAME (decl);
+  if (!targetm.emutls.tmpl_prefix || targetm.emutls.tmpl_prefix[0])
+    {
+      const char *prefix = (targetm.emutls.tmpl_prefix
+			    ? targetm.emutls.tmpl_prefix
+			    : "__emutls_t" EMUTLS_SEPARATOR);
+      name = prefix_name (prefix, name);
+    }
+
+  to = build_decl (DECL_SOURCE_LOCATION (decl),
+		   VAR_DECL, name, TREE_TYPE (decl));
+  SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
+
+  DECL_ARTIFICIAL (to) = 1;
+  TREE_USED (to) = TREE_USED (decl);
+  TREE_READONLY (to) = 1;
+  DECL_IGNORED_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))
+    {
+      make_decl_one_only (to, DECL_ASSEMBLER_NAME (to));
+      TREE_STATIC (to) = TREE_STATIC (decl);
+      TREE_PUBLIC (to) = TREE_PUBLIC (decl);
+      DECL_VISIBILITY (to) = DECL_VISIBILITY (decl);
+    }
+  else
+    TREE_STATIC (to) = 1;
+
+  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);
+}
+
+/* Create and return the control variable for the TLS variable DECL.  */
+
+static tree
+new_emutls_decl (tree decl)
+{
+  tree name, to;
+
+  name = DECL_ASSEMBLER_NAME (decl);
+  to = build_decl (DECL_SOURCE_LOCATION (decl), VAR_DECL,
+                   get_emutls_object_name (name),
+                   get_emutls_object_type ());
+
+  SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
+
+  DECL_TLS_MODEL (to) = TLS_MODEL_EMULATED;
+  DECL_ARTIFICIAL (to) = 1;
+  DECL_IGNORED_P (to) = 1;
+  TREE_READONLY (to) = 0;
+  TREE_STATIC (to) = 1;
+
+  DECL_PRESERVE_P (to) = DECL_PRESERVE_P (decl);
+  DECL_CONTEXT (to) = DECL_CONTEXT (decl);
+  TREE_USED (to) = TREE_USED (decl);
+  TREE_PUBLIC (to) = TREE_PUBLIC (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_RESTRICTED_P (to) = DECL_RESTRICTED_P (decl);
+  DECL_DLLIMPORT_P (to) = DECL_DLLIMPORT_P (decl);
+
+  DECL_ATTRIBUTES (to) = targetm.merge_decl_attributes (decl, to);
+
+  if (DECL_ONE_ONLY (decl))
+    make_decl_one_only (to, DECL_ASSEMBLER_NAME (to));
+
+  /* ??? What in the world is this for?  */
+  if (targetm.emutls.var_align_fixed)
+    /* If we're not allowed to change the proxy object's
+       alignment, pretend it's been set by the user.  */
+    DECL_USER_ALIGN (to) = 1;
+
+  /* If this variable is defined locally, then we need to initialize the
+     control structure with size and alignment information.  Initialization
+     of COMMON block variables happens elsewhere via a constructor.  */
+  if (!DECL_EXTERNAL (to)
+      && (!DECL_COMMON (to)
+          || (DECL_INITIAL (decl)
+              && DECL_INITIAL (decl) != error_mark_node)))
+    {
+      tree tmpl = get_emutls_init_templ_addr (decl);
+      DECL_INITIAL (to) = targetm.emutls.var_init (to, decl, tmpl);
+      record_references_in_initializer (to, false);
+    }
+
+  varpool_finalize_decl (to);
+  return to;
+}
+
+/* Look up the control variable for the TLS variable DECL.  */
+
+static unsigned int
+emutls_index (tree decl)
+{
+  varpool_node_set_iterator i;
+  
+  i = varpool_node_set_find (tls_vars, varpool_get_node (decl));
+  gcc_assert (i.index != ~0u);
+
+  return i.index;
+}
+
+/* ??? The only remaining user is in dwarf2out.c.  Figure out how to
+   eliminate that too.  */
+
+tree
+emutls_decl (tree decl)
+{
+  struct varpool_node *var;
+  unsigned int i;
+
+  i = emutls_index (decl);
+  var = VEC_index (varpool_node_ptr, control_vars->nodes, i);
+  return var->decl;
+}
+
+/* Generate a call statement to initialize CONTROL_DECL for TLS_DECL.
+   This only needs to happen for TLS COMMON variables; non-COMMON
+   variables can be initialized statically.  Insert the generated
+   call statement at the end of PSTMTS.  */
+   
+static void
+emutls_common_1 (tree tls_decl, tree control_decl, tree *pstmts)
+{
+  tree x;
+  tree word_type_node;
+
+  if (! DECL_COMMON (tls_decl)
+      || (DECL_INITIAL (tls_decl)
+	  && DECL_INITIAL (tls_decl) != error_mark_node))
+    return;
+
+  word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
+
+  x = build_call_expr (built_in_decls[BUILT_IN_EMUTLS_REGISTER_COMMON], 4,
+		       build_fold_addr_expr (control_decl),
+		       fold_convert (word_type_node,
+				     DECL_SIZE_UNIT (tls_decl)),
+		       build_int_cst (word_type_node,
+				      DECL_ALIGN_UNIT (tls_decl)),
+		       get_emutls_init_templ_addr (tls_decl));
+
+  append_to_statement_list (x, pstmts);
+}
+
+struct lower_emutls_data
+{
+  VEC(tree,heap) *accessed;
+  struct cgraph_node *cfun_node;
+  struct cgraph_node *builtin_node;
+  tree builtin_decl;
+  basic_block bb;
+  int bb_freq;
+  location_t loc;
+  gimple_seq seq;
+};
+
+/* Given a TLS variable DECL, return an SSA_NAME holding its address.  */
+
+static tree
+gen_emutls_addr (tree decl, struct lower_emutls_data *d)
+{
+  unsigned int index;
+  tree addr;
+
+  /* Compute the address of the TLS variable with help from runtime.  */
+  index = emutls_index (decl);
+  addr = VEC_index (tree, d->accessed, index);
+  if (addr == NULL)
+    {
+      struct varpool_node *cvar;
+      tree cdecl;
+      gimple x;
+
+      cvar = VEC_index (varpool_node_ptr, control_vars->nodes, index);
+      cdecl = cvar->decl;
+      TREE_ADDRESSABLE (cdecl) = 1;
+
+      addr = create_tmp_var (build_pointer_type (TREE_TYPE (decl)), NULL);
+      x = gimple_build_call (d->builtin_decl, 1, build_fold_addr_expr (cdecl));
+      gimple_set_location (x, d->loc);
+
+      addr = make_ssa_name (addr, x);
+      gimple_call_set_lhs (x, addr);
+
+      gimple_seq_add_stmt (&d->seq, x);
+
+      cgraph_create_edge (d->cfun_node, d->builtin_node, x,
+                          d->bb->count, d->bb_freq, d->bb->loop_depth);
+
+      /* We may be adding a new reference to a new variable to the function.
+         This means we have to play with the ipa-reference web.  */
+      ipa_record_reference (d->cfun_node, NULL, NULL, cvar, IPA_REF_ADDR, x);
+
+      /* Record this ssa_name for possible use later in the basic block.  */
+      VEC_replace (tree, d->accessed, index, addr);
+    }
+
+  return addr;
+}
+
+/* Callback for walk_gimple_op.  D = WI->INFO is a struct lower_emutls_data.
+   Given an operand *PTR within D->STMT, if the operand references a TLS
+   variable, then lower the reference to a call to the runtime.  Insert
+   any new statements required into D->SEQ; the caller is responsible for
+   placing those appropriately.  */
+
+static tree
+lower_emutls_1 (tree *ptr, int *walk_subtrees, void *cb_data)
+{
+  struct walk_stmt_info *wi = (struct walk_stmt_info *) cb_data;
+  struct lower_emutls_data *d = (struct lower_emutls_data *) wi->info;
+  tree t = *ptr;
+  bool is_addr = false;
+  tree addr;
+
+  *walk_subtrees = 0;
+
+  switch (TREE_CODE (t))
+    {
+    case ADDR_EXPR:
+      /* If this is not a straight-forward "&var", but rather something
+	 like "&var.a", then we may need special handling.  */
+      if (TREE_CODE (TREE_OPERAND (t, 0)) != VAR_DECL)
+	{
+	  bool save_changed;
+
+	  /* If we're allowed more than just is_gimple_val, continue.  */
+	  if (!wi->val_only)
+	    {
+	      *walk_subtrees = 1;
+	      return NULL_TREE;
+	    }
+
+	  /* See if any substitution would be made.  */
+	  save_changed = wi->changed;
+	  wi->changed = false;
+	  wi->val_only = false;
+	  walk_tree (&TREE_OPERAND (t, 0), lower_emutls_1, wi, NULL);
+	  wi->val_only = true;
+
+	  /* If so, then extract this entire sub-expression "&p->a" into a
+	     new assignment statement, and substitute yet another SSA_NAME.  */
+	  if (wi->changed)
+	    {
+	      gimple x;
+
+	      addr = create_tmp_var (TREE_TYPE (t), NULL);
+	      x = gimple_build_assign (addr, t);
+	      gimple_set_location (x, d->loc);
+
+	      addr = make_ssa_name (addr, x);
+	      gimple_assign_set_lhs (x, addr);
+
+	      gimple_seq_add_stmt (&d->seq, x);
+
+	      *ptr = addr;
+	    }
+	  else
+	    wi->changed = save_changed;
+
+	  return NULL_TREE;
+	}
+
+      t = TREE_OPERAND (t, 0);
+      is_addr = true;
+      /* FALLTHRU */
+
+    case VAR_DECL:
+      if (!DECL_THREAD_LOCAL_P (t))
+	return NULL_TREE;
+      break;
+
+    default:
+      /* We're not interested in other decls or types, only subexpressions.  */
+      if (EXPR_P (t))
+        *walk_subtrees = 1;
+      /* FALLTHRU */
+
+    case SSA_NAME:
+      /* Special-case the return of SSA_NAME, since it's so common.  */
+      return NULL_TREE;
+    }
+
+  addr = gen_emutls_addr (t, d);
+  if (is_addr)
+    {
+      /* Replace "&var" with "addr" in the statement.  */
+      *ptr = addr;
+    }
+  else
+    {
+      /* Replace "var" with "*addr" in the statement.  */
+      t = build2 (MEM_REF, TREE_TYPE (t), addr,
+	          build_int_cst (TREE_TYPE (addr), 0));
+      *ptr = t;
+    }
+
+  wi->changed = true;
+  return NULL_TREE;
+}
+
+/* Lower all of the operands of STMT.  */
+
+static void
+lower_emutls_stmt (gimple stmt, struct lower_emutls_data *d)
+{
+  struct walk_stmt_info wi;
+
+  d->loc = gimple_location (stmt);
+
+  memset (&wi, 0, sizeof (wi));
+  wi.info = d;
+  wi.val_only = true;
+  walk_gimple_op (stmt, lower_emutls_1, &wi);
+
+  if (wi.changed)
+    update_stmt (stmt);
+}
+
+/* Lower the I'th operand of PHI.  */
+
+static void
+lower_emutls_phi_arg (gimple phi, unsigned int i, struct lower_emutls_data *d)
+{
+  struct walk_stmt_info wi;
+  struct phi_arg_d *pd = gimple_phi_arg (phi, i);
+
+  /* Early out for a very common case we don't care about.  */
+  if (TREE_CODE (pd->def) == SSA_NAME)
+    return;
+
+  d->loc = pd->locus;
+
+  memset (&wi, 0, sizeof (wi));
+  wi.info = d;
+  wi.val_only = true;
+  walk_tree (&pd->def, lower_emutls_1, &wi, NULL);
+
+  /* For normal statements, we let update_stmt do its job.  But for phi
+     nodes, we have to manipulate the immediate use list by hand.  */
+  if (wi.changed)
+    {
+      gcc_assert (TREE_CODE (pd->def) == SSA_NAME);
+      link_imm_use_stmt (&pd->imm_use, pd->def, phi);
+    }
+}
+
+/* Lower the entire function NODE.  */
+
+static void
+lower_emutls_function_body (struct cgraph_node *node)
+{
+  struct lower_emutls_data d;
+  bool any_edge_inserts = false;
+  unsigned int n_tls;
+
+  current_function_decl = node->decl;
+  push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+
+  d.cfun_node = node;
+  d.builtin_decl = built_in_decls[BUILT_IN_EMUTLS_GET_ADDRESS];
+  d.builtin_node = cgraph_node (d.builtin_decl);
+
+  n_tls = VEC_length (varpool_node_ptr, tls_vars->nodes);
+  d.accessed = VEC_alloc (tree, heap, n_tls);
+  VEC_safe_grow (tree, heap, d.accessed, n_tls);
+
+  FOR_EACH_BB (d.bb)
+    {
+      gimple_stmt_iterator gsi;
+      unsigned int i, nedge;
+
+      /* ??? This is the frequency of the new block that might be created by
+	 split_edge.  One might have thought EDGE_FREQUENCY.  However, this
+         *must* match split_edge, or we'll fail verify_cgraph.  */
+      d.bb_freq = CGRAPH_FREQ_BASE;
+
+      /* Lower each of the PHI nodes of the block, as we may have 
+	 propagated &tlsvar into a PHI argument.  These loops are
+	 arranged so that we process each edge at once, and each
+	 PHI argument for that edge.  */
+
+      nedge = EDGE_COUNT (d.bb->preds);
+      for (i = 0; i < nedge; ++i)
+	{
+	  edge e = EDGE_PRED (d.bb, i);
+
+          /* We can re-use any SSA_NAME created on this edge.  */
+          memset (VEC_address (tree, d.accessed), 0, n_tls * sizeof(tree));
+	  d.seq = NULL;
+
+	  for (gsi = gsi_start_phis (d.bb); !gsi_end_p (gsi); gsi_next (&gsi))
+	    lower_emutls_phi_arg (gsi_stmt (gsi), i, &d);
+
+	  /* Insert all statements generated by all phi nodes for this
+	     particular edge all at once.  */
+	  if (d.seq)
+	    {
+	      gsi_insert_seq_on_edge (e, d.seq);
+	      any_edge_inserts = true;
+	    }
+	}
+
+      d.bb_freq = compute_call_stmt_bb_frequency (current_function_decl, d.bb);
+
+      /* We can re-use any SSA_NAME created during this basic block.  */
+      memset (VEC_address (tree, d.accessed), 0, n_tls * sizeof(tree));
+
+      /* Lower each of the statements of the block.  */
+      for (gsi = gsi_start_bb (d.bb); !gsi_end_p (gsi); gsi_next (&gsi))
+	{
+          d.seq = NULL;
+	  lower_emutls_stmt (gsi_stmt (gsi), &d);
+
+	  /* If any new statements were created, insert them immediately
+	     before the first use.  This prevents variable lifetimes from
+	     becoming unnecessarily long.  */
+	  if (d.seq)
+	    gsi_insert_seq_before (&gsi, d.seq, GSI_SAME_STMT);
+	}
+    }
+
+  if (any_edge_inserts)
+    gsi_commit_edge_inserts ();
+
+  VEC_free (tree, heap, d.accessed);
+
+  pop_cfun ();
+  current_function_decl = NULL;
+}
+
+static unsigned int
+ipa_lower_emutls (void)
+{
+  struct varpool_node *var;
+  struct cgraph_node *func;
+  bool any_aliases = false;
+  tree ctor_body = NULL;
+  unsigned int i;
+
+  tls_vars = varpool_node_set_new ();
+
+  /* Examine all global variables for TLS variables.  */
+  for (var = varpool_nodes; var ; var = var->next)
+    if (DECL_THREAD_LOCAL_P (var->decl))
+      {
+        /* ??? We really should be more consistent about setting these
+	   sorts of flags.  TREE_STATIC != C "static" keyword, and thus
+	   it should be set *with* DECL_EXTERNAL.  */
+	gcc_checking_assert (TREE_STATIC (var->decl)
+			     || DECL_EXTERNAL (var->decl));
+	varpool_node_set_add (tls_vars, var);
+      }
+
+  /* If we found no TLS variables, then there is no further work to do.  */
+  if (tls_vars->nodes == NULL)
+    {
+      tls_vars = NULL;
+      if (dump_file)
+	fprintf (dump_file, "No TLS variables found.\n");
+      return 0;
+    }
+
+  /* Create the control variables for each TLS variable.  */
+  control_vars = varpool_node_set_new ();
+  for (i = 0; VEC_iterate (varpool_node_ptr, tls_vars->nodes, i, var); ++i)
+    {
+      tree cdecl;
+      struct varpool_node *cvar;
+
+      var = VEC_index (varpool_node_ptr, tls_vars->nodes, i);
+      cdecl = new_emutls_decl (var->decl);
+
+      cvar = varpool_get_node (cdecl);
+      varpool_node_set_add (control_vars, cvar);
+
+      if (var->alias)
+	{
+	  any_aliases = true;
+	  cvar->alias = true;
+	}
+      else
+	{
+	  /* Make sure the COMMON block control variable gets initialized.
+	     Note that there's no point in doing this for aliases; we only
+	     need to do this once for the main variable.  */
+          emutls_common_1 (var->decl, cdecl, &ctor_body);
+	}
+
+      /* Indicate that the value of the TLS variable may be found elsewhere.
+	 This also prevents the variable from re-appearing in the GIMPLE.  */
+      /* ??? Unfortuantely, there's no decent actual value to put here;
+	 there's nothing we can emit for the debugger at the moment.  */
+      SET_DECL_VALUE_EXPR (var->decl, error_mark_node);
+      DECL_HAS_VALUE_EXPR_P (var->decl) = 1;
+    }
+
+  /* If there were any aliases, then frob the alias_pairs vector.  */
+  if (any_aliases)
+    {
+      alias_pair *p;
+      for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ++i)
+	if (DECL_THREAD_LOCAL_P (p->decl))
+	  {
+	    p->decl = emutls_decl (p->decl);
+	    p->target = get_emutls_object_name (p->target);
+	  }
+    }
+
+  /* Adjust all uses of TLS variables within the function bodies.  */
+  for (func = cgraph_nodes; func; func = func->next)
+    if (func->reachable && func->lowered)
+      lower_emutls_function_body (func);
+
+  /* Generate the constructor for any COMMON control variables created.  */
+  if (ctor_body)
+    cgraph_build_static_cdtor ('I', ctor_body, DEFAULT_INIT_PRIORITY);
+
+  return TODO_dump_func | TODO_ggc_collect | TODO_verify_stmts;
+}
+
+/* If the target supports TLS natively, we need do nothing here.  */
+
+static bool
+gate_emutls (void)
+{
+  return !targetm.have_tls;
+}
+
+struct simple_ipa_opt_pass pass_ipa_lower_emutls =
+{
+ {
+  SIMPLE_IPA_PASS,
+  "emutls",				/* name */
+  gate_emutls,				/* gate */
+  ipa_lower_emutls,			/* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_NONE,				/* tv_id */
+  PROP_cfg,				/* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  0,					/* todo_flags_finish */
+ }
+};
+
+#include "gt-tree-emutls.h"
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index c72d7cf..33c898e 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -446,6 +446,7 @@ extern struct gimple_opt_pass pass_warn_unused_result;
 extern struct gimple_opt_pass pass_split_functions;
 
 /* IPA Passes */
+extern struct simple_ipa_opt_pass pass_ipa_lower_emutls;
 extern struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility;
 extern struct simple_ipa_opt_pass pass_ipa_early_inline;
 
diff --git a/gcc/tree.h b/gcc/tree.h
index be70d2b..865c47a 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5258,9 +5258,12 @@ extern void set_user_assembler_name (tree, const char *);
 extern void process_pending_assemble_externals (void);
 extern void finish_aliases_1 (void);
 extern void finish_aliases_2 (void);
-extern tree emutls_decl (tree);
 extern void remove_unreachable_alias_pairs (void);
 
+/* tree-emutls.c */
+extern tree emutls_decl (tree);
+extern bool decl_emutls_var_p (const_tree);
+
 /* In stmt.c */
 extern void expand_computed_goto (tree);
 extern bool parse_output_constraint (const char **, int, int, int,
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 55218c4..1f32903 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -186,317 +186,6 @@ static GTY(()) int anchor_labelno;
 /* A pool of constants that can be shared between functions.  */
 static GTY(()) struct rtx_constant_pool *shared_constant_pool;
 
-/* TLS emulation.  */
-
-static GTY ((if_marked ("tree_map_marked_p"), param_is (struct tree_map)))
-     htab_t emutls_htab;
-static GTY (()) tree emutls_object_type;
-/* Emulated TLS objects have the TLS model TLS_MODEL_EMULATED.  This
-   macro can be used on them to distinguish the control variable from
-   the initialization template.  */
-#define DECL_EMUTLS_VAR_P(D)  (TREE_TYPE (D) == emutls_object_type)
-
-#if !defined (NO_DOT_IN_LABEL)
-# define EMUTLS_SEPARATOR	"."
-#elif !defined (NO_DOLLAR_IN_LABEL)
-# define EMUTLS_SEPARATOR	"$"
-#else
-# define EMUTLS_SEPARATOR	"_"
-#endif
-
-/* Create an IDENTIFIER_NODE by prefixing PREFIX to the
-   IDENTIFIER_NODE NAME's name.  */
-
-static tree
-prefix_name (const char *prefix, tree name)
-{
-  unsigned plen = strlen (prefix);
-  unsigned nlen = strlen (IDENTIFIER_POINTER (name));
-  char *toname = (char *) alloca (plen + nlen + 1);
-
-  memcpy (toname, prefix, plen);
-  memcpy (toname + plen, IDENTIFIER_POINTER (name), nlen + 1);
-
-  return get_identifier (toname);
-}
-
-/* Create an identifier for the struct __emutls_object, given an identifier
-   of the DECL_ASSEMBLY_NAME of the original object.  */
-
-static tree
-get_emutls_object_name (tree name)
-{
-  const char *prefix = (targetm.emutls.var_prefix
-			? targetm.emutls.var_prefix
-			: "__emutls_v" EMUTLS_SEPARATOR);
-  return prefix_name (prefix, name);
-}
-
-tree
-default_emutls_var_fields (tree type, tree *name ATTRIBUTE_UNUSED)
-{
-  tree word_type_node, field, next_field;
-
-  field = build_decl (UNKNOWN_LOCATION,
-		      FIELD_DECL, get_identifier ("__templ"), ptr_type_node);
-  DECL_CONTEXT (field) = type;
-  next_field = field;
-
-  field = build_decl (UNKNOWN_LOCATION,
-		      FIELD_DECL, get_identifier ("__offset"),
-		      ptr_type_node);
-  DECL_CONTEXT (field) = type;
-  TREE_CHAIN (field) = next_field;
-  next_field = field;
-
-  word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
-  field = build_decl (UNKNOWN_LOCATION,
-		      FIELD_DECL, get_identifier ("__align"),
-		      word_type_node);
-  DECL_CONTEXT (field) = type;
-  TREE_CHAIN (field) = next_field;
-  next_field = field;
-
-  field = build_decl (UNKNOWN_LOCATION,
-		      FIELD_DECL, get_identifier ("__size"), word_type_node);
-  DECL_CONTEXT (field) = type;
-  TREE_CHAIN (field) = next_field;
-
-  return field;
-}
-
-/* Create the structure for struct __emutls_object.  This should match the
-   structure at the top of emutls.c, modulo the union there.  */
-
-static tree
-get_emutls_object_type (void)
-{
-  tree type, type_name, field;
-
-  type = emutls_object_type;
-  if (type)
-    return type;
-
-  emutls_object_type = type = lang_hooks.types.make_type (RECORD_TYPE);
-  type_name = NULL;
-  field = targetm.emutls.var_fields (type, &type_name);
-  if (!type_name)
-    type_name = get_identifier ("__emutls_object");
-  type_name = build_decl (UNKNOWN_LOCATION,
-			  TYPE_DECL, type_name, type);
-  TYPE_NAME (type) = type_name;
-  TYPE_FIELDS (type) = field;
-  layout_type (type);
-
-  return type;
-}
-
-/* Create a read-only variable like DECL, with the same DECL_INITIAL.
-   This will be used for initializing the emulated tls data area.  */
-
-static tree
-get_emutls_init_templ_addr (tree decl)
-{
-  tree name, to;
-
-  if (targetm.emutls.register_common && !DECL_INITIAL (decl)
-      && !DECL_SECTION_NAME (decl))
-    return null_pointer_node;
-
-  name = DECL_ASSEMBLER_NAME (decl);
-  if (!targetm.emutls.tmpl_prefix || targetm.emutls.tmpl_prefix[0])
-    {
-      const char *prefix = (targetm.emutls.tmpl_prefix
-			    ? targetm.emutls.tmpl_prefix
-			    : "__emutls_t" EMUTLS_SEPARATOR);
-      name = prefix_name (prefix, name);
-    }
-
-  to = build_decl (DECL_SOURCE_LOCATION (decl),
-		   VAR_DECL, name, TREE_TYPE (decl));
-  SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
-
-  DECL_ARTIFICIAL (to) = 1;
-  TREE_USED (to) = TREE_USED (decl);
-  TREE_READONLY (to) = 1;
-  DECL_IGNORED_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))
-    {
-      make_decl_one_only (to, DECL_ASSEMBLER_NAME (to));
-      TREE_STATIC (to) = TREE_STATIC (decl);
-      TREE_PUBLIC (to) = TREE_PUBLIC (decl);
-      DECL_VISIBILITY (to) = DECL_VISIBILITY (decl);
-    }
-  else
-    TREE_STATIC (to) = 1;
-
-  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);
-}
-
-/* When emulating tls, we use a control structure for use by the runtime.
-   Create and return this structure.  */
-
-tree
-emutls_decl (tree decl)
-{
-  tree name, to;
-  struct tree_map *h, in;
-  void **loc;
-
-  if (targetm.have_tls || decl == NULL || decl == error_mark_node
-      || TREE_CODE (decl) != VAR_DECL || ! DECL_THREAD_LOCAL_P (decl))
-    return decl;
-
-  /* Look up the object in the hash; return the control structure if
-     it has already been created.  */
-  if (! emutls_htab)
-    emutls_htab = htab_create_ggc (512, tree_map_hash, tree_map_eq, 0);
-
-  name = DECL_ASSEMBLER_NAME (decl);
-
-  /* Note that we use the hash of the decl's name, rather than a hash
-     of the decl's pointer.  In emutls_finish we iterate through the
-     hash table, and we want this traversal to be predictable.  */
-  in.hash = IDENTIFIER_HASH_VALUE (name);
-  in.base.from = decl;
-  loc = htab_find_slot_with_hash (emutls_htab, &in, in.hash, INSERT);
-  h = (struct tree_map *) *loc;
-  if (h != NULL)
-    to = h->to;
-  else
-    {
-      to = build_decl (DECL_SOURCE_LOCATION (decl),
-		       VAR_DECL, get_emutls_object_name (name),
-		       get_emutls_object_type ());
-
-      h = ggc_alloc_tree_map ();
-      h->hash = in.hash;
-      h->base.from = decl;
-      h->to = to;
-      *(struct tree_map **) loc = h;
-
-      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))
-	make_decl_one_only (to, DECL_ASSEMBLER_NAME (to));
-      DECL_CONTEXT (to) = DECL_CONTEXT (decl);
-      if (targetm.emutls.var_align_fixed)
-	/* If we're not allowed to change the proxy object's
-	   alignment, pretend it's been set by the user.  */
-	DECL_USER_ALIGN (to) = 1;
-    }
-
-  /* Note that these fields may need to be updated from time to time from
-     the original decl.  Consider:
-	extern __thread int i;
-	int foo() { return i; }
-	__thread int i = 1;
-     in which I goes from external to locally defined and initialized.  */
-  DECL_DLLIMPORT_P (to) = DECL_DLLIMPORT_P (decl);
-  DECL_ATTRIBUTES (to) = targetm.merge_decl_attributes (decl, to);
-
-  TREE_STATIC (to) = TREE_STATIC (decl);
-  TREE_USED (to) = TREE_USED (decl);
-  TREE_PUBLIC (to) = TREE_PUBLIC (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);
-  
-  /* Fortran might pass this to us.  */
-  DECL_RESTRICTED_P (to) = DECL_RESTRICTED_P (decl);
-
-  return to;
-}
-
-static int
-emutls_common_1 (void **loc, void *xstmts)
-{
-  struct tree_map *h = *(struct tree_map **) loc;
-  tree 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))
-    return 1;
-
-  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 = built_in_decls[BUILT_IN_EMUTLS_REGISTER_COMMON];
-  x = build_call_expr (x, 4,
-		       build_fold_addr_expr (h->to),
-		       fold_convert (word_type_node,
-				     DECL_SIZE_UNIT (h->base.from)),
-		       build_int_cst (word_type_node,
-				      DECL_ALIGN_UNIT (h->base.from)),
-		       null_pointer_node);
-
-  append_to_statement_list (x, pstmts);
-  return 1;
-}
-
-/* Callback to finalize one emutls control variable.  */
-
-static int
-emutls_finalize_control_var (void **loc, 
-				void *unused ATTRIBUTE_UNUSED)
-{
-  struct tree_map *h = *(struct tree_map **) loc;
-  if (h != NULL) 
-    {
-      struct varpool_node *node = varpool_node (h->to);
-      /* Because varpool_finalize_decl () has side-effects,
-         only apply to un-finalized vars.  */
-      if (node && !node->finalized) 
-	varpool_finalize_decl (h->to);
-    }
-  return 1;
-}
-
-/* Finalize emutls control vars and add a static constructor if
-   required.  */
-
-void
-emutls_finish (void)
-{
-  if (emutls_htab == NULL)
-    return;
-  htab_traverse_noresize (emutls_htab, 
-			  emutls_finalize_control_var, NULL);
-
-  if (targetm.emutls.register_common)
-    {
-      tree body = NULL_TREE;
-
-      htab_traverse_noresize (emutls_htab, emutls_common_1, &body);
-      if (body == NULL_TREE)
-	return;
-
-      cgraph_build_static_cdtor ('I', body, DEFAULT_INIT_PRIORITY);
-    }
-}
-
 /* Helper routines for maintaining section_htab.  */
 
 static int
@@ -1210,11 +899,6 @@ get_variable_section (tree decl, bool prefer_noswitch_p)
 		  && ADDR_SPACE_GENERIC_P (as));
       if (DECL_THREAD_LOCAL_P (decl))
 	return tls_comm_section;
-      /* This cannot be common bss for an emulated TLS object without
-	 a register_common hook.  */
-      else if (DECL_TLS_MODEL (decl) == TLS_MODEL_EMULATED
-	       && !targetm.emutls.register_common)
-	;
       else if (TREE_PUBLIC (decl) && bss_initializer_p (decl))
 	return comm_section;
     }
@@ -2098,40 +1782,6 @@ assemble_variable_contents (tree decl, const char *name,
     }
 }
 
-/* Initialize emulated tls object TO, which refers to TLS variable
-   DECL and is initialized by PROXY.  */
-
-tree
-default_emutls_var_init (tree to, tree decl, tree proxy)
-{
-  VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, 4);
-  constructor_elt *elt;
-  tree type = TREE_TYPE (to);
-  tree field = TYPE_FIELDS (type);
-
-  elt = VEC_quick_push (constructor_elt, v, NULL);
-  elt->index = field;
-  elt->value = fold_convert (TREE_TYPE (field), DECL_SIZE_UNIT (decl));
-
-  elt = VEC_quick_push (constructor_elt, v, NULL);
-  field = TREE_CHAIN (field);
-  elt->index = field;
-  elt->value = build_int_cst (TREE_TYPE (field),
-			      DECL_ALIGN_UNIT (decl));
-
-  elt = VEC_quick_push (constructor_elt, v, NULL);
-  field = TREE_CHAIN (field);
-  elt->index = field;
-  elt->value = null_pointer_node;
-
-  elt = VEC_quick_push (constructor_elt, v, NULL);
-  field = TREE_CHAIN (field);
-  elt->index = field;
-  elt->value = proxy;
-
-  return build_constructor (type, v);
-}
-
 /* Assemble everything that is needed for a variable or function declaration.
    Not used for automatic variables, and not used for function definitions.
    Should not be called for variables of incomplete structure type.
@@ -2153,35 +1803,9 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
   /* This function is supposed to handle VARIABLES.  Ensure we have one.  */
   gcc_assert (TREE_CODE (decl) == VAR_DECL);
 
-  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;
-    }
-
+  /* Emulated TLS had better not get this far.  */
+  gcc_checking_assert (targetm.have_tls || !DECL_THREAD_LOCAL_P (decl));
+              
   last_assemble_variable_decl = 0;
 
   /* Normally no need to say anything here for external references,
@@ -5685,6 +5309,11 @@ find_decl_and_mark_needed (tree decl, tree target)
 static void
 do_assemble_alias (tree decl, tree target)
 {
+  /* Emulated TLS had better not get this var.  */
+  gcc_assert(!(!targetm.have_tls
+	       && TREE_CODE (decl) == VAR_DECL
+	       && DECL_THREAD_LOCAL_P (decl)));
+
   if (TREE_ASM_WRITTEN (decl))
     return;
 
@@ -5699,14 +5328,6 @@ do_assemble_alias (tree decl, tree target)
     {
       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);
 
@@ -5725,14 +5346,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.  */
 
@@ -6404,7 +6017,7 @@ categorize_decl_for_section (const_tree decl, int reloc)
     {
       if (DECL_TLS_MODEL (decl) == TLS_MODEL_EMULATED)
 	{
-	  if (DECL_EMUTLS_VAR_P (decl))
+	  if (decl_emutls_var_p (decl))
 	    {
 	      if (targetm.emutls.var_section)
 		ret = SECCAT_EMUTLS_VAR;
diff --git a/gcc/varpool.c b/gcc/varpool.c
index 94c949e..3843d9c 100644
--- a/gcc/varpool.c
+++ b/gcc/varpool.c
@@ -211,7 +211,9 @@ varpool_remove_node (struct varpool_node *node)
     }
   ipa_remove_all_references (&node->ref_list);
   ipa_remove_all_refering (&node->ref_list);
-  ggc_free (node);
+  /* ??? We need to remove the reference in emutls data structures.  Perhaps
+     it would be better to simply add the xref to the varpool node.  */
+  /* ggc_free (node); */
 }
 
 /* Dump given cgraph node.  */
@@ -346,17 +348,6 @@ decide_is_variable_needed (struct varpool_node *node, tree decl)
       && !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)

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

* Re: [CFT, try 7] Emulated tls rewrite
  2010-07-14 23:50 [CFT, try 7] Emulated tls rewrite Richard Henderson
@ 2010-07-15  7:49 ` Richard Guenther
  2010-07-15  7:59   ` IainS
  2010-07-15 12:00 ` Jack Howarth
  2010-07-19 19:42 ` [CFT, try 8] " Richard Henderson
  2 siblings, 1 reply; 28+ messages in thread
From: Richard Guenther @ 2010-07-15  7:49 UTC (permalink / raw)
  To: Richard Henderson; +Cc: IainS, GCC Patches

On Thu, Jul 15, 2010 at 1:50 AM, Richard Henderson <rth@redhat.com> wrote:
> This go-around handles phi nodes, as requested by Richi.  This was much more
> irritating than it should have been, due to immediate use maintainence.  It

Hm, interesting.  I skimmed around the tree and SET_PHI_ARG_DEF
should do the job.

> also gets re-arranged to use walk_gimple_ops, which I should have been using
> in the first place.
>
> The testsuite is still running here, amd64-linux --disable-tls, but I'm
> quitting for today.  I never got around to looking at those non-tls.exp
> testsuite failures, Iain.  Hopefully they went away magically.  ;-)

Overall it looks reasonable, minus the various ???s.

Richard.

>
> r~
>

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

* Re: [CFT, try 7] Emulated tls rewrite
  2010-07-15  7:49 ` Richard Guenther
@ 2010-07-15  7:59   ` IainS
  2010-07-15 11:39     ` Jack Howarth
  2010-07-15 15:50     ` Richard Henderson
  0 siblings, 2 replies; 28+ messages in thread
From: IainS @ 2010-07-15  7:59 UTC (permalink / raw)
  To: Richard Henderson; +Cc: GCC Patches, Richard Guenther


On 15 Jul 2010, at 08:48, Richard Guenther wrote:

> On Thu, Jul 15, 2010 at 1:50 AM, Richard Henderson <rth@redhat.com>  
> wrote:
>> This go-around handles phi nodes, as requested by Richi.  This was  
>> much more
>> irritating than it should have been, due to immediate use  
>> maintainence.  It
>
> Hm, interesting.  I skimmed around the tree and SET_PHI_ARG_DEF
> should do the job.
>
>> also gets re-arranged to use walk_gimple_ops, which I should have  
>> been using
>> in the first place.
>>
>> The testsuite is still running here, amd64-linux --disable-tls, but  
>> I'm
>> quitting for today.  I never got around to looking at those non- 
>> tls.exp
>> testsuite failures, Iain.  Hopefully they went away magically.  ;-)
>
> Overall it looks reasonable, minus the various ???s.

unfortunately, although it applies cleanly, it doesn't bootstrap for  
me (against either 162180 or 162193).
(fails in building libgomp/parallel.c with 'caller edge frequency 1000  
does not match BB frequency of 61')...
... I will look a little more - but this is uncharted territory for  
me ;)

Iain

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

* Re: [CFT, try 7] Emulated tls rewrite
  2010-07-15  7:59   ` IainS
@ 2010-07-15 11:39     ` Jack Howarth
  2010-07-15 12:00       ` IainS
  2010-07-15 15:50     ` Richard Henderson
  1 sibling, 1 reply; 28+ messages in thread
From: Jack Howarth @ 2010-07-15 11:39 UTC (permalink / raw)
  To: IainS; +Cc: Richard Henderson, GCC Patches, Richard Guenther

On Thu, Jul 15, 2010 at 08:59:35AM +0100, IainS wrote:
>
> On 15 Jul 2010, at 08:48, Richard Guenther wrote:
>
>> On Thu, Jul 15, 2010 at 1:50 AM, Richard Henderson <rth@redhat.com>  
>> wrote:
>>> This go-around handles phi nodes, as requested by Richi.  This was  
>>> much more
>>> irritating than it should have been, due to immediate use  
>>> maintainence.  It
>>
>> Hm, interesting.  I skimmed around the tree and SET_PHI_ARG_DEF
>> should do the job.
>>
>>> also gets re-arranged to use walk_gimple_ops, which I should have  
>>> been using
>>> in the first place.
>>>
>>> The testsuite is still running here, amd64-linux --disable-tls, but  
>>> I'm
>>> quitting for today.  I never got around to looking at those non- 
>>> tls.exp
>>> testsuite failures, Iain.  Hopefully they went away magically.  ;-)
>>
>> Overall it looks reasonable, minus the various ???s.
>
> unfortunately, although it applies cleanly, it doesn't bootstrap for me 
> (against either 162180 or 162193).
> (fails in building libgomp/parallel.c with 'caller edge frequency 1000  
> does not match BB frequency of 61')...
> ... I will look a little more - but this is uncharted territory for me ;)

Bootstraps on x86_64-apple-darwin10 fine here. Regression testresults at...

http://gcc.gnu.org/ml/gcc-testresults/2010-07/msg01432.html

Did you start with a fresh tree before applying the new patch?
                Jack

>
> Iain

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

* Re: [CFT, try 7] Emulated tls rewrite
  2010-07-14 23:50 [CFT, try 7] Emulated tls rewrite Richard Henderson
  2010-07-15  7:49 ` Richard Guenther
@ 2010-07-15 12:00 ` Jack Howarth
  2010-07-19 19:42 ` [CFT, try 8] " Richard Henderson
  2 siblings, 0 replies; 28+ messages in thread
From: Jack Howarth @ 2010-07-15 12:00 UTC (permalink / raw)
  To: Richard Henderson; +Cc: IainS, GCC Patches, richard.guenther

On Wed, Jul 14, 2010 at 04:50:20PM -0700, Richard Henderson wrote:
> This go-around handles phi nodes, as requested by Richi.  This was much more
> irritating than it should have been, due to immediate use maintainence.  It
> also gets re-arranged to use walk_gimple_ops, which I should have been using
> in the first place.
> 
> The testsuite is still running here, amd64-linux --disable-tls, but I'm
> quitting for today.  I never got around to looking at those non-tls.exp
> testsuite failures, Iain.  Hopefully they went away magically.  ;-)
> 
> 
> r~

Richard,
   Test results for x86_64-apple-darwin10 are at...

 http://gcc.gnu.org/ml/gcc-testresults/2010-07/msg01432.html.

We seem to have picked up a couple new failures in the gfortran
testsuite. 

Running target unix/-m32
FAIL: gfortran.dg/char_array_structure_constructor.f90  -O3 -fomit-frame-pointer  execution test
FAIL: gfortran.dg/gomp/appendix-a/a.22.6.f90  -O  (test for excess errors)

Running target unix/-m64
FAIL: gfortran.dg/gomp/appendix-a/a.22.6.f90  -O  (test for excess errors)

The first appears as...

gdb ./char_array_structure_constructor.exe 
(gdb) r
Starting program: /Users/howarth/newbug2/char_array_structure_constructor.exe 
Reading symbols for shared libraries +++. done

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00000000
0x000acc7c in __gfortran_compare_string (len1=4, s1=0x0, len2=4, s2=0x1f40 "wxyzabcdefgh") at intrinsics/string_intrinsics_inc.c:93
93	  res = memcmp (s1, s2, ((len1 < len2) ? len1 : len2) * sizeof (CHARTYPE));
(gdb) bt
#0  0x000acc7c in __gfortran_compare_string (len1=4, s1=0x0, len2=4, s2=0x1f40 "wxyzabcdefgh") at intrinsics/string_intrinsics_inc.c:93
#1  0x00001e31 in main ()
(gdb) 

and the second as...

Executing on host: /sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/gcc/testsuite/gfortran/../../gfortran -B/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/gcc/testsuite/gfortran/../../ /sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100714/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90   -O   -fopenmp -S  -m32 -o a.22.6.s    (timeout = 300)
/sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100714/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90:4:0: sorry, unimplemented: thread-local COMMON data not implemented^M
compiler exited with status 1
output is:
/sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100714/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90:4:0: sorry, unimplemented: thread-local COMMON data not implemented^M

FAIL: gfortran.dg/gomp/appendix-a/a.22.6.f90  -O  (test for excess errors)
Excess errors:
/sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100714/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90:4:0: sorry, unimplemented: thread-local COMMON data not implemented

       Jack

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

* Re: [CFT, try 7] Emulated tls rewrite
  2010-07-15 11:39     ` Jack Howarth
@ 2010-07-15 12:00       ` IainS
  0 siblings, 0 replies; 28+ messages in thread
From: IainS @ 2010-07-15 12:00 UTC (permalink / raw)
  To: Jack Howarth; +Cc: Richard Henderson, GCC Patches, Richard Guenther


On 15 Jul 2010, at 12:39, Jack Howarth wrote:

> On Thu, Jul 15, 2010 at 08:59:35AM +0100, IainS wrote:
>>
>> On 15 Jul 2010, at 08:48, Richard Guenther wrote:
>>
>>> On Thu, Jul 15, 2010 at 1:50 AM, Richard Henderson <rth@redhat.com>
>>> wrote:
>>>> This go-around handles phi nodes, as requested by Richi.  This was
>>>> much more
>>>> irritating than it should have been, due to immediate use
>>>> maintainence.  It
>>>
>>> Hm, interesting.  I skimmed around the tree and SET_PHI_ARG_DEF
>>> should do the job.
>>>
>>>> also gets re-arranged to use walk_gimple_ops, which I should have
>>>> been using
>>>> in the first place.
>>>>
>>>> The testsuite is still running here, amd64-linux --disable-tls, but
>>>> I'm
>>>> quitting for today.  I never got around to looking at those non-
>>>> tls.exp
>>>> testsuite failures, Iain.  Hopefully they went away magically.  ;-)
>>>
>>> Overall it looks reasonable, minus the various ???s.
>>
>> unfortunately, although it applies cleanly, it doesn't bootstrap  
>> for me
>> (against either 162180 or 162193).
>> (fails in building libgomp/parallel.c with 'caller edge frequency  
>> 1000
>> does not match BB frequency of 61')...
>> ... I will look a little more - but this is uncharted territory for  
>> me ;)
>
> Bootstraps on x86_64-apple-darwin10 fine here. Regression  
> testresults at...
>
> http://gcc.gnu.org/ml/gcc-testresults/2010-07/msg01432.html

hm you have checking=release I have checking=yes, and it's failing on  
a cgraph validity check viz:

/GCC/gcc-live-trunk/libgomp/parallel.c:201:1: error: caller edge  
frequency 1000 does not match BB freqency 61
/GCC/gcc-live-trunk/libgomp/parallel.c:201:1: error: caller edge  
frequency 1000 does not match BB freqency 61
__builtin___emutls_get_address/20(-1) @0xeed5e8 (asm:  
__emutls_get_address) availability:not_available
   called by: gomp_resolve_num_threads/24 (0.64 per call)  
gomp_resolve_num_threads/24 (0.80 per call) gomp_resolve_num_threads/ 
24 (1.00 per call) GOMP_parallel_end/26 omp_get_num_threads/27 (1.00  
per call) omp_get_thread_num/28 (1.00 per call) omp_in_parallel/29  
(1.00 per call) omp_get_level/30 (1.00 per call)  
omp_get_ancestor_thread_num/31 (1.00 per call)  
omp_get_ancestor_thread_num/31 (0.06 per call)  
omp_get_ancestor_thread_num/31 (0.10 per call)  
omp_get_ancestor_thread_num/31 (1.00 per call) omp_get_team_size/32  
(1.00 per call) omp_get_team_size/32 (0.06 per call) omp_get_team_size/ 
32 (0.10 per call) omp_get_team_size/32 (1.00 per call)  
omp_get_active_level/33 (1.00 per call)
   calls:
   References:
   Refering this function:
/GCC/gcc-live-trunk/libgomp/parallel.c:201:1: internal compiler error:  
verify_cgraph_node failed

> Did you start with a fresh tree before applying the new patch?

well, erm, yes
(although I do have a patch in an unrelated area - and some test suite  
additions).

Iain.

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

* Re: [CFT, try 7] Emulated tls rewrite
  2010-07-15  7:59   ` IainS
  2010-07-15 11:39     ` Jack Howarth
@ 2010-07-15 15:50     ` Richard Henderson
  2010-07-15 20:29       ` IainS
  2010-07-19 13:18       ` Jack Howarth
  1 sibling, 2 replies; 28+ messages in thread
From: Richard Henderson @ 2010-07-15 15:50 UTC (permalink / raw)
  To: IainS; +Cc: GCC Patches, Richard Guenther

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

On 07/15/2010 12:59 AM, IainS wrote:
> unfortunately, although it applies cleanly, it doesn't bootstrap for me
> (against either 162180 or 162193).
> (fails in building libgomp/parallel.c with 'caller edge frequency 1000
> does not match BB frequency of 61')...
> ... I will look a little more - but this is uncharted territory for me ;)

Incremental patch follows.


r~

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

diff --git a/gcc/tree-emutls.c b/gcc/tree-emutls.c
index f7eb4cd..275e16b 100644
--- a/gcc/tree-emutls.c
+++ b/gcc/tree-emutls.c
@@ -580,6 +580,54 @@ lower_emutls_phi_arg (gimple phi, unsigned int i, struct lower_emutls_data *d)
     }
 }
 
+/* Mirror a portion of the logic from gimple_find_edge_insert_loc.
+   Determine if statements inserted on E will be insertted into the
+   predecessor block.  We *must* match gimple_find_edge_insert_loc
+   in order to pass verify_cgraph. 
+
+   If the destination has one predecessor and no PHI nodes, insert
+   there... Except that we *know* it has PHI nodes or else there's
+   nothing for us to do.  Skip this step.
+
+   If the source has one successor, the edge is not abnormal and the
+   last statement does not end a basic block, insert there.  */
+
+static bool
+will_insert_in_edge_src (edge e)
+{
+  basic_block src = e->src;
+
+  if ((e->flags & EDGE_ABNORMAL) == 0
+      && src != ENTRY_BLOCK_PTR
+      && single_succ_p (src))
+    {
+      gimple_stmt_iterator gsi;
+      gimple last;
+
+      /* If the block is empty, of course we use it.  */
+      gsi = gsi_last_bb (src);
+      if (gsi_end_p (gsi))
+	return true;
+
+      /* If the last stmt does not end the block, we insert after.  */
+      last = gsi_stmt (gsi);
+      if (!stmt_ends_bb_p (last))
+	return true;
+
+      /* If the last stmt is a trivial control, we insert before.  */
+      switch (gimple_code (last))
+	{
+	case GIMPLE_RETURN:
+	case GIMPLE_RESX:
+	  return true;
+	default:
+	  break;
+	}
+    }
+
+  return false;
+}
+
 /* Lower the entire function NODE.  */
 
 static void
@@ -605,34 +653,41 @@ lower_emutls_function_body (struct cgraph_node *node)
       gimple_stmt_iterator gsi;
       unsigned int i, nedge;
 
-      /* ??? This is the frequency of the new block that might be created by
-	 split_edge.  One might have thought EDGE_FREQUENCY.  However, this
-         *must* match split_edge, or we'll fail verify_cgraph.  */
-      d.bb_freq = CGRAPH_FREQ_BASE;
-
       /* Lower each of the PHI nodes of the block, as we may have 
 	 propagated &tlsvar into a PHI argument.  These loops are
 	 arranged so that we process each edge at once, and each
 	 PHI argument for that edge.  */
-
-      nedge = EDGE_COUNT (d.bb->preds);
-      for (i = 0; i < nedge; ++i)
+      if (!gimple_seq_empty_p (phi_nodes (d.bb)))
 	{
-	  edge e = EDGE_PRED (d.bb, i);
-
-          /* We can re-use any SSA_NAME created on this edge.  */
-          memset (VEC_address (tree, d.accessed), 0, n_tls * sizeof(tree));
-	  d.seq = NULL;
-
-	  for (gsi = gsi_start_phis (d.bb); !gsi_end_p (gsi); gsi_next (&gsi))
-	    lower_emutls_phi_arg (gsi_stmt (gsi), i, &d);
-
-	  /* Insert all statements generated by all phi nodes for this
-	     particular edge all at once.  */
-	  if (d.seq)
+	  nedge = EDGE_COUNT (d.bb->preds);
+	  for (i = 0; i < nedge; ++i)
 	    {
-	      gsi_insert_seq_on_edge (e, d.seq);
-	      any_edge_inserts = true;
+	      edge e = EDGE_PRED (d.bb, i);
+
+	      /* Choose the correct frequency for stmts to be
+		 insertted on this edge.  */
+	      if (will_insert_in_edge_src (e))
+		d.bb_freq = (compute_call_stmt_bb_frequency
+			     (current_function_decl, e->src));
+	      else
+		d.bb_freq = EDGE_FREQUENCY (e);
+
+	      /* We can re-use any SSA_NAME created on this edge.  */
+	      memset (VEC_address (tree, d.accessed), 0, n_tls * sizeof(tree));
+	      d.seq = NULL;
+
+	      for (gsi = gsi_start_phis (d.bb);
+		   !gsi_end_p (gsi);
+		   gsi_next (&gsi))
+		lower_emutls_phi_arg (gsi_stmt (gsi), i, &d);
+
+	      /* Insert all statements generated by all phi nodes for this
+		 particular edge all at once.  */
+	      if (d.seq)
+		{
+		  gsi_insert_seq_on_edge (e, d.seq);
+		  any_edge_inserts = true;
+		}
 	    }
 	}
 

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

* Re: [CFT, try 7] Emulated tls rewrite
  2010-07-15 15:50     ` Richard Henderson
@ 2010-07-15 20:29       ` IainS
  2010-07-19 13:18       ` Jack Howarth
  1 sibling, 0 replies; 28+ messages in thread
From: IainS @ 2010-07-15 20:29 UTC (permalink / raw)
  To: Richard Henderson; +Cc: GCC Patches, Richard Guenther, Jack Howarth

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


On 15 Jul 2010, at 16:50, Richard Henderson wrote:

> On 07/15/2010 12:59 AM, IainS wrote:
>> unfortunately, although it applies cleanly, it doesn't bootstrap  
>> for me
>> (against either 162180 or 162193).
>> (fails in building libgomp/parallel.c with 'caller edge frequency  
>> 1000
>> does not match BB frequency of 61')...
>> ... I will look a little more - but this is uncharted territory for  
>> me ;)
>
> Incremental patch follows.

I applied emutls-7 + the increment to 162222.

It is clean on cris-elf "tls.exp=*"  (emutls target with alias, but no  
libgomp)

also on i686-apple-darwin9 (emutls target without alias but with  
libgomp)

These were done with all the test-suite additions mentioned below.

----
I believe this clears (at least):
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44132
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44137 (together with the  
ObjC LTO patch already applied)
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44276

-----
Note1:

an updated version of this could be applied:

http://gcc.gnu.org/ml/gcc-patches/2010-05/msg01738.html

In fact, it could be applied anyway, the current emutls implementation  
works with these tests.

updated patch for that attached - the changelog should still stand  
(+/- minor adjustments).

----
Note2:

The cse test I sent you only works on darwin (m32) when the branch  
island patch is also applied.
(although, of course, it should be valid for other targets and darwin  
at m64).

---
Note 3:
I've got a set of tls tests for ObjC++, will post those separately (I  
want to trim them a bit).

----
Note 4:
I'll also un-xfail the ObjC tls tests when this goes in.

=====

Thanks very much for working on this....
Iain

==== extended tls test-suite vs 162229.


[-- Attachment #2: 162229-extended-tls --]
[-- Type: application/octet-stream, Size: 21605 bytes --]

Index: gcc/testsuite/gcc.dg/gomp/copyin-1.c
===================================================================
--- gcc/testsuite/gcc.dg/gomp/copyin-1.c	(revision 162229)
+++ gcc/testsuite/gcc.dg/gomp/copyin-1.c	(working copy)
@@ -1,5 +1,5 @@
 // { dg-do compile }
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 
 int i, j;
 
Index: gcc/testsuite/gcc.dg/gomp/tls-1.c
===================================================================
--- gcc/testsuite/gcc.dg/gomp/tls-1.c	(revision 162229)
+++ gcc/testsuite/gcc.dg/gomp/tls-1.c	(working copy)
@@ -1,5 +1,5 @@
 // { dg-do compile }
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 
 int tp1;
 static int tp2;
Index: gcc/testsuite/gcc.dg/gomp/sharing-1.c
===================================================================
--- gcc/testsuite/gcc.dg/gomp/sharing-1.c	(revision 162229)
+++ gcc/testsuite/gcc.dg/gomp/sharing-1.c	(working copy)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 #include <stdlib.h>
 
Index: gcc/testsuite/gcc.dg/gomp/tls-2.c
===================================================================
--- gcc/testsuite/gcc.dg/gomp/tls-2.c	(revision 162229)
+++ gcc/testsuite/gcc.dg/gomp/tls-2.c	(working copy)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 extern char buf[];
 #pragma omp threadprivate (buf)	/* { dg-error "has incomplete type" } */
Index: gcc/testsuite/gcc.dg/gomp/appendix-a/a.22.1.c
===================================================================
--- gcc/testsuite/gcc.dg/gomp/appendix-a/a.22.1.c	(revision 162229)
+++ gcc/testsuite/gcc.dg/gomp/appendix-a/a.22.1.c	(working copy)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 int counter = 0;
 #pragma omp threadprivate(counter)
Index: gcc/testsuite/gcc.dg/gomp/appendix-a/a.22.2.c
===================================================================
--- gcc/testsuite/gcc.dg/gomp/appendix-a/a.22.2.c	(revision 162229)
+++ gcc/testsuite/gcc.dg/gomp/appendix-a/a.22.2.c	(working copy)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 int
 increment_counter_2 ()
Index: gcc/testsuite/gcc.dg/gomp/appendix-a/a.24.1.c
===================================================================
--- gcc/testsuite/gcc.dg/gomp/appendix-a/a.24.1.c	(revision 162229)
+++ gcc/testsuite/gcc.dg/gomp/appendix-a/a.24.1.c	(working copy)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 extern int omp_get_num_threads (void);
 int x, y, t, z[1000];
Index: gcc/testsuite/gcc.dg/gomp/appendix-a/a.32.1.c
===================================================================
--- gcc/testsuite/gcc.dg/gomp/appendix-a/a.32.1.c	(revision 162229)
+++ gcc/testsuite/gcc.dg/gomp/appendix-a/a.32.1.c	(working copy)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 #include <stdlib.h>
 float *work;
Index: gcc/testsuite/gcc.dg/gomp/appendix-a/a.33.1.c
===================================================================
--- gcc/testsuite/gcc.dg/gomp/appendix-a/a.33.1.c	(revision 162229)
+++ gcc/testsuite/gcc.dg/gomp/appendix-a/a.33.1.c	(working copy)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 #include <stdio.h>
 float x, y;
Index: gcc/testsuite/gcc.dg/gomp/clause-1.c
===================================================================
--- gcc/testsuite/gcc.dg/gomp/clause-1.c	(revision 162229)
+++ gcc/testsuite/gcc.dg/gomp/clause-1.c	(working copy)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 #define p parallel
 
Index: gcc/testsuite/gcc.dg/gomp/pr35244.c
===================================================================
--- gcc/testsuite/gcc.dg/gomp/pr35244.c	(revision 162229)
+++ gcc/testsuite/gcc.dg/gomp/pr35244.c	(working copy)
@@ -1,6 +1,6 @@
 /* PR c++/35244 */
 /* { dg-do compile } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 /* { dg-options "-fopenmp" } */
 
 int v1;
Index: gcc/testsuite/gcc.dg/tls/section-1.c
===================================================================
--- gcc/testsuite/gcc.dg/tls/section-1.c	(revision 162229)
+++ gcc/testsuite/gcc.dg/tls/section-1.c	(working copy)
@@ -1,6 +1,6 @@
 /* Verify that we get errors for trying to put TLS data in 
    sections which can't work.  */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 #define A(X)	__attribute__((section(X)))
 
Index: gcc/testsuite/gcc.dg/tls/opt-1.c
===================================================================
--- gcc/testsuite/gcc.dg/tls/opt-1.c	(revision 162229)
+++ gcc/testsuite/gcc.dg/tls/opt-1.c	(working copy)
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fPIC" } */
 /* { dg-options "-O2 -fPIC -mtune=i686" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 /* { dg-require-effective-target fpic } */
 
 extern __thread int thr;
Index: gcc/testsuite/gcc.dg/tls/opt-2.c
===================================================================
--- gcc/testsuite/gcc.dg/tls/opt-2.c	(revision 162229)
+++ gcc/testsuite/gcc.dg/tls/opt-2.c	(working copy)
@@ -5,7 +5,7 @@
 /* { dg-do link } */
 /* { dg-options "-O2 -ftls-model=initial-exec" } */
 /* { dg-options "-O2 -ftls-model=initial-exec -march=i686" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 /* { dg-require-effective-target tls_runtime  } */
 
 __thread int thr;
Index: gcc/testsuite/gcc.dg/tls/opt-3.c
===================================================================
--- gcc/testsuite/gcc.dg/tls/opt-3.c	(revision 162229)
+++ gcc/testsuite/gcc.dg/tls/opt-3.c	(working copy)
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fpic" } */
 /* { dg-options "-O2 -fpic -mregparm=3" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 /* { dg-require-effective-target fpic } */
 
 extern __thread int i, j, k;
Index: gcc/testsuite/gcc.dg/tls/opt-7.c
===================================================================
--- gcc/testsuite/gcc.dg/tls/opt-7.c	(revision 162229)
+++ gcc/testsuite/gcc.dg/tls/opt-7.c	(working copy)
@@ -1,6 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fPIC" } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 /* { dg-require-effective-target fpic } */
 
 static __thread void *baz [4] __attribute__((tls_model ("initial-exec")));
Index: gcc/testsuite/gcc.dg/tls/opt-13.c
===================================================================
--- gcc/testsuite/gcc.dg/tls/opt-13.c	(revision 162229)
+++ gcc/testsuite/gcc.dg/tls/opt-13.c	(working copy)
@@ -1,6 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2" } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 __thread struct
 {
Index: gcc/testsuite/gcc.dg/tls/opt-14.c
===================================================================
--- gcc/testsuite/gcc.dg/tls/opt-14.c	(revision 162229)
+++ gcc/testsuite/gcc.dg/tls/opt-14.c	(working copy)
@@ -3,7 +3,7 @@
    used.  */
 /* { dg-do assemble } */
 /* { dg-options "-O2" } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 struct __res_state
 {
Index: gcc/testsuite/gcc.dg/tls/opt-15.c
===================================================================
--- gcc/testsuite/gcc.dg/tls/opt-15.c	(revision 162229)
+++ gcc/testsuite/gcc.dg/tls/opt-15.c	(working copy)
@@ -3,7 +3,7 @@
 
 /* { dg-do compile } */
 /* { dg-options "-O -fPIC" } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 /* { dg-require-effective-target fpic } */
 
 extern void *memset(void *s, int c, __SIZE_TYPE__ n);
Index: gcc/testsuite/g++.dg/tls/init-1.C
===================================================================
--- gcc/testsuite/g++.dg/tls/init-1.C	(revision 162229)
+++ gcc/testsuite/g++.dg/tls/init-1.C	(working copy)
@@ -1,5 +1,5 @@
 /* Valid initializations.  */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 __thread int i = 42;
 
Index: gcc/testsuite/g++.dg/tls/diag-1.C
===================================================================
--- gcc/testsuite/g++.dg/tls/diag-1.C	(revision 162229)
+++ gcc/testsuite/g++.dg/tls/diag-1.C	(working copy)
@@ -1,5 +1,5 @@
 // Valid __thread specifiers.
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 
 __thread int g1;
 extern __thread int g2;
Index: gcc/testsuite/g++.dg/tls/init-2.C
===================================================================
--- gcc/testsuite/g++.dg/tls/init-2.C	(revision 162229)
+++ gcc/testsuite/g++.dg/tls/init-2.C	(working copy)
@@ -1,5 +1,5 @@
 /* Invalid initializations.  */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 extern __thread int i;
 __thread int *p = &i;	/* { dg-error "dynamically initialized" } */
Index: gcc/testsuite/g++.dg/tls/diag-2.C
===================================================================
--- gcc/testsuite/g++.dg/tls/diag-2.C	(revision 162229)
+++ gcc/testsuite/g++.dg/tls/diag-2.C	(working copy)
@@ -1,5 +1,5 @@
 /* Invalid __thread specifiers.  */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 __thread extern int g1;		/* { dg-error "'__thread' before 'extern'" } */
 __thread static int g2;		/* { dg-error "'__thread' before 'static'" } */
Index: gcc/testsuite/g++.dg/tls/diag-3.C
===================================================================
--- gcc/testsuite/g++.dg/tls/diag-3.C	(revision 162229)
+++ gcc/testsuite/g++.dg/tls/diag-3.C	(working copy)
@@ -1,5 +1,5 @@
 // Report invalid extern and __thread combinations.
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 
 extern int j;		// { dg-error "previously declared here" }
 __thread int j;		// { dg-error "follows non-thread-local" }
Index: gcc/testsuite/g++.dg/tls/diag-4.C
===================================================================
--- gcc/testsuite/g++.dg/tls/diag-4.C	(revision 162229)
+++ gcc/testsuite/g++.dg/tls/diag-4.C	(working copy)
@@ -1,5 +1,5 @@
 /* Invalid __thread specifiers.  */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 __thread typedef int g4;	/* { dg-error "multiple storage classes" } */
 
Index: gcc/testsuite/g++.dg/tls/diag-5.C
===================================================================
--- gcc/testsuite/g++.dg/tls/diag-5.C	(revision 162229)
+++ gcc/testsuite/g++.dg/tls/diag-5.C	(working copy)
@@ -1,5 +1,5 @@
 // PR c++/30536
 // Invalid __thread specifiers.
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 
 struct A { __thread register int i; }; // { dg-error "multiple storage classes|storage class specified" }
Index: gcc/testsuite/g++.dg/tls/trivial.C
===================================================================
--- gcc/testsuite/g++.dg/tls/trivial.C	(revision 162229)
+++ gcc/testsuite/g++.dg/tls/trivial.C	(working copy)
@@ -1,3 +1,3 @@
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 
 __thread int i;
Index: gcc/testsuite/g++.dg/gomp/copyin-1.C
===================================================================
--- gcc/testsuite/g++.dg/gomp/copyin-1.C	(revision 162229)
+++ gcc/testsuite/g++.dg/gomp/copyin-1.C	(working copy)
@@ -1,5 +1,5 @@
 // { dg-do compile }
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 
 int i, j;
 
Index: gcc/testsuite/g++.dg/gomp/tls-1.C
===================================================================
--- gcc/testsuite/g++.dg/gomp/tls-1.C	(revision 162229)
+++ gcc/testsuite/g++.dg/gomp/tls-1.C	(working copy)
@@ -1,5 +1,5 @@
 // { dg-do compile }
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 
 int tp1;
 static int tp2;
Index: gcc/testsuite/g++.dg/gomp/clause-3.C
===================================================================
--- gcc/testsuite/g++.dg/gomp/clause-3.C	(revision 162229)
+++ gcc/testsuite/g++.dg/gomp/clause-3.C	(working copy)
@@ -1,5 +1,5 @@
 // { dg-do compile }
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 
 #define p parallel
 
Index: gcc/testsuite/g++.dg/gomp/sharing-1.C
===================================================================
--- gcc/testsuite/g++.dg/gomp/sharing-1.C	(revision 162229)
+++ gcc/testsuite/g++.dg/gomp/sharing-1.C	(working copy)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 int thrglobalvar;
 #pragma omp threadprivate (thrglobalvar)
Index: gcc/testsuite/g++.dg/gomp/tls-2.C
===================================================================
--- gcc/testsuite/g++.dg/gomp/tls-2.C	(revision 162229)
+++ gcc/testsuite/g++.dg/gomp/tls-2.C	(working copy)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 extern char buf[];
 #pragma omp threadprivate (buf)	/* { dg-error "has incomplete type" } */
Index: gcc/testsuite/g++.dg/gomp/tls-3.C
===================================================================
--- gcc/testsuite/g++.dg/gomp/tls-3.C	(revision 162229)
+++ gcc/testsuite/g++.dg/gomp/tls-3.C	(working copy)
@@ -1,5 +1,5 @@
 // { dg-do compile }
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 
 #define thr threadprivate
 
Index: gcc/testsuite/g++.dg/gomp/pr35244.C
===================================================================
--- gcc/testsuite/g++.dg/gomp/pr35244.C	(revision 162229)
+++ gcc/testsuite/g++.dg/gomp/pr35244.C	(working copy)
@@ -1,6 +1,6 @@
 // PR c++/35244
 // { dg-do compile }
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 // { dg-options "-fopenmp" }
 
 int v1;
Index: gcc/testsuite/g++.dg/gomp/tls-4.C
===================================================================
--- gcc/testsuite/g++.dg/gomp/tls-4.C	(revision 162229)
+++ gcc/testsuite/g++.dg/gomp/tls-4.C	(working copy)
@@ -1,5 +1,5 @@
 // { dg-do compile }
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 
 #define thr threadprivate
 
Index: gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.1.f90
===================================================================
--- gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.1.f90	(revision 162229)
+++ gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.1.f90	(working copy)
@@ -1,5 +1,5 @@
 ! { dg-do compile }
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
 
       INTEGER FUNCTION INCREMENT_COUNTER()
         COMMON/A22_COMMON/COUNTER
Index: gcc/testsuite/gfortran.dg/gomp/appendix-a/a.24.1.f90
===================================================================
--- gcc/testsuite/gfortran.dg/gomp/appendix-a/a.24.1.f90	(revision 162229)
+++ gcc/testsuite/gfortran.dg/gomp/appendix-a/a.24.1.f90	(working copy)
@@ -1,5 +1,5 @@
 ! { dg-do compile }
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
 
       SUBROUTINE A24(A)
       INTEGER A
Index: gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.4.f90
===================================================================
--- gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.4.f90	(revision 162229)
+++ gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.4.f90	(working copy)
@@ -1,5 +1,5 @@
 ! { dg-do compile }
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
 
       MODULE A22_MODULE
       COMMON /T/ A
Index: gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.5.f90
===================================================================
--- gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.5.f90	(revision 162229)
+++ gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.5.f90	(working copy)
@@ -1,5 +1,5 @@
 ! { dg-do compile }
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
 
       SUBROUTINE A22_5_WRONG()
         COMMON /T/ A
Index: gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90
===================================================================
--- gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90	(revision 162229)
+++ gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90	(working copy)
@@ -1,5 +1,5 @@
 ! { dg-do compile }
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
 
        SUBROUTINE A22_6_GOOD()
              COMMON /T/ A
Index: gcc/testsuite/gfortran.dg/gomp/appendix-a/a.32.1.f90
===================================================================
--- gcc/testsuite/gfortran.dg/gomp/appendix-a/a.32.1.f90	(revision 162229)
+++ gcc/testsuite/gfortran.dg/gomp/appendix-a/a.32.1.f90	(working copy)
@@ -1,5 +1,5 @@
 ! { dg-do compile }
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
 
       MODULE M
         REAL, POINTER, SAVE :: WORK(:)
Index: gcc/testsuite/gfortran.dg/gomp/appendix-a/a.33.1.f90
===================================================================
--- gcc/testsuite/gfortran.dg/gomp/appendix-a/a.33.1.f90	(revision 162229)
+++ gcc/testsuite/gfortran.dg/gomp/appendix-a/a.33.1.f90	(working copy)
@@ -1,5 +1,5 @@
 ! { dg-do compile }
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
 
       SUBROUTINE INIT(A,B)
       REAL A, B
Index: gcc/testsuite/gfortran.dg/gomp/sharing-1.f90
===================================================================
--- gcc/testsuite/gfortran.dg/gomp/sharing-1.f90	(revision 162229)
+++ gcc/testsuite/gfortran.dg/gomp/sharing-1.f90	(working copy)
@@ -1,5 +1,5 @@
 ! { dg-do compile }
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
 
   integer :: thrpriv, thr, i, j, s, g1, g2, m
   integer, dimension (6) :: p
Index: gcc/testsuite/gfortran.dg/gomp/omp_threadprivate1.f90
===================================================================
--- gcc/testsuite/gfortran.dg/gomp/omp_threadprivate1.f90	(revision 162229)
+++ gcc/testsuite/gfortran.dg/gomp/omp_threadprivate1.f90	(working copy)
@@ -1,4 +1,4 @@
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
       module omp_threadprivate1
 	common /T/ a
       end module omp_threadprivate1
Index: gcc/testsuite/gfortran.dg/gomp/omp_threadprivate2.f90
===================================================================
--- gcc/testsuite/gfortran.dg/gomp/omp_threadprivate2.f90	(revision 162229)
+++ gcc/testsuite/gfortran.dg/gomp/omp_threadprivate2.f90	(working copy)
@@ -1,5 +1,5 @@
 ! { dg-do compile }
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
       subroutine bad1
 	double precision :: d	! { dg-error "isn't SAVEd" }
 !$omp threadprivate (d)
Index: gcc/testsuite/gfortran.dg/gomp/crayptr2.f90
===================================================================
--- gcc/testsuite/gfortran.dg/gomp/crayptr2.f90	(revision 162229)
+++ gcc/testsuite/gfortran.dg/gomp/crayptr2.f90	(working copy)
@@ -1,6 +1,6 @@
 ! { dg-do compile }
 ! { dg-options "-fopenmp -fcray-pointer" }
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
 
 module crayptr2
   integer :: e		! { dg-error "CRAY POINTEE attribute conflicts with THREADPRIVATE" }
Index: gcc/testsuite/gfortran.dg/gomp/reduction1.f90
===================================================================
--- gcc/testsuite/gfortran.dg/gomp/reduction1.f90	(revision 162229)
+++ gcc/testsuite/gfortran.dg/gomp/reduction1.f90	(working copy)
@@ -1,6 +1,6 @@
 ! { dg-do compile }
 ! { dg-options "-fopenmp -fmax-errors=100" }
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
 
 subroutine foo (ia1)
 integer :: i1, i2, i3
Index: gcc/testsuite/gfortran.dg/gomp/free-1.f90
===================================================================
--- gcc/testsuite/gfortran.dg/gomp/free-1.f90	(revision 162229)
+++ gcc/testsuite/gfortran.dg/gomp/free-1.f90	(working copy)
@@ -1,4 +1,4 @@
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
 
 subroutine foo
 integer, save :: i ! Some comment
Index: gcc/testsuite/gfortran.dg/gomp/fixed-1.f
===================================================================
--- gcc/testsuite/gfortran.dg/gomp/fixed-1.f	(revision 162229)
+++ gcc/testsuite/gfortran.dg/gomp/fixed-1.f	(working copy)
@@ -1,6 +1,6 @@
 C PR fortran/24493
 C { dg-do compile }
-C { dg-require-effective-target tls_native }
+C { dg-require-effective-target tls }
       INTEGER I, J, K, L, M
 C$OMP THREADPRIVATE(I)
 C SOME COMMENT

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



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

* Re: [CFT, try 7] Emulated tls rewrite
  2010-07-15 15:50     ` Richard Henderson
  2010-07-15 20:29       ` IainS
@ 2010-07-19 13:18       ` Jack Howarth
  1 sibling, 0 replies; 28+ messages in thread
From: Jack Howarth @ 2010-07-19 13:18 UTC (permalink / raw)
  To: Richard Henderson; +Cc: IainS, GCC Patches, Richard Guenther

On Thu, Jul 15, 2010 at 08:50:26AM -0700, Richard Henderson wrote:
> On 07/15/2010 12:59 AM, IainS wrote:
> > unfortunately, although it applies cleanly, it doesn't bootstrap for me
> > (against either 162180 or 162193).
> > (fails in building libgomp/parallel.c with 'caller edge frequency 1000
> > does not match BB frequency of 61')...
> > ... I will look a little more - but this is uncharted territory for me ;)
> 
> Incremental patch follows.
> 
> 
> r~

Richard,
   Do you plan to repost the emutls_7 patch combined with this patch
and corrected for bit rot? Also, is there anything left to be done
with the emutls lto patch ? If not, perhaps you can just commit the
current version. Thanks in advance.
           Jack

> diff --git a/gcc/tree-emutls.c b/gcc/tree-emutls.c
> index f7eb4cd..275e16b 100644
> --- a/gcc/tree-emutls.c
> +++ b/gcc/tree-emutls.c
> @@ -580,6 +580,54 @@ lower_emutls_phi_arg (gimple phi, unsigned int i, struct lower_emutls_data *d)
>      }
>  }
>  
> +/* Mirror a portion of the logic from gimple_find_edge_insert_loc.
> +   Determine if statements inserted on E will be insertted into the
> +   predecessor block.  We *must* match gimple_find_edge_insert_loc
> +   in order to pass verify_cgraph. 
> +
> +   If the destination has one predecessor and no PHI nodes, insert
> +   there... Except that we *know* it has PHI nodes or else there's
> +   nothing for us to do.  Skip this step.
> +
> +   If the source has one successor, the edge is not abnormal and the
> +   last statement does not end a basic block, insert there.  */
> +
> +static bool
> +will_insert_in_edge_src (edge e)
> +{
> +  basic_block src = e->src;
> +
> +  if ((e->flags & EDGE_ABNORMAL) == 0
> +      && src != ENTRY_BLOCK_PTR
> +      && single_succ_p (src))
> +    {
> +      gimple_stmt_iterator gsi;
> +      gimple last;
> +
> +      /* If the block is empty, of course we use it.  */
> +      gsi = gsi_last_bb (src);
> +      if (gsi_end_p (gsi))
> +	return true;
> +
> +      /* If the last stmt does not end the block, we insert after.  */
> +      last = gsi_stmt (gsi);
> +      if (!stmt_ends_bb_p (last))
> +	return true;
> +
> +      /* If the last stmt is a trivial control, we insert before.  */
> +      switch (gimple_code (last))
> +	{
> +	case GIMPLE_RETURN:
> +	case GIMPLE_RESX:
> +	  return true;
> +	default:
> +	  break;
> +	}
> +    }
> +
> +  return false;
> +}
> +
>  /* Lower the entire function NODE.  */
>  
>  static void
> @@ -605,34 +653,41 @@ lower_emutls_function_body (struct cgraph_node *node)
>        gimple_stmt_iterator gsi;
>        unsigned int i, nedge;
>  
> -      /* ??? This is the frequency of the new block that might be created by
> -	 split_edge.  One might have thought EDGE_FREQUENCY.  However, this
> -         *must* match split_edge, or we'll fail verify_cgraph.  */
> -      d.bb_freq = CGRAPH_FREQ_BASE;
> -
>        /* Lower each of the PHI nodes of the block, as we may have 
>  	 propagated &tlsvar into a PHI argument.  These loops are
>  	 arranged so that we process each edge at once, and each
>  	 PHI argument for that edge.  */
> -
> -      nedge = EDGE_COUNT (d.bb->preds);
> -      for (i = 0; i < nedge; ++i)
> +      if (!gimple_seq_empty_p (phi_nodes (d.bb)))
>  	{
> -	  edge e = EDGE_PRED (d.bb, i);
> -
> -          /* We can re-use any SSA_NAME created on this edge.  */
> -          memset (VEC_address (tree, d.accessed), 0, n_tls * sizeof(tree));
> -	  d.seq = NULL;
> -
> -	  for (gsi = gsi_start_phis (d.bb); !gsi_end_p (gsi); gsi_next (&gsi))
> -	    lower_emutls_phi_arg (gsi_stmt (gsi), i, &d);
> -
> -	  /* Insert all statements generated by all phi nodes for this
> -	     particular edge all at once.  */
> -	  if (d.seq)
> +	  nedge = EDGE_COUNT (d.bb->preds);
> +	  for (i = 0; i < nedge; ++i)
>  	    {
> -	      gsi_insert_seq_on_edge (e, d.seq);
> -	      any_edge_inserts = true;
> +	      edge e = EDGE_PRED (d.bb, i);
> +
> +	      /* Choose the correct frequency for stmts to be
> +		 insertted on this edge.  */
> +	      if (will_insert_in_edge_src (e))
> +		d.bb_freq = (compute_call_stmt_bb_frequency
> +			     (current_function_decl, e->src));
> +	      else
> +		d.bb_freq = EDGE_FREQUENCY (e);
> +
> +	      /* We can re-use any SSA_NAME created on this edge.  */
> +	      memset (VEC_address (tree, d.accessed), 0, n_tls * sizeof(tree));
> +	      d.seq = NULL;
> +
> +	      for (gsi = gsi_start_phis (d.bb);
> +		   !gsi_end_p (gsi);
> +		   gsi_next (&gsi))
> +		lower_emutls_phi_arg (gsi_stmt (gsi), i, &d);
> +
> +	      /* Insert all statements generated by all phi nodes for this
> +		 particular edge all at once.  */
> +	      if (d.seq)
> +		{
> +		  gsi_insert_seq_on_edge (e, d.seq);
> +		  any_edge_inserts = true;
> +		}
>  	    }
>  	}
>  

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

* [CFT, try 8] Emulated tls rewrite
  2010-07-14 23:50 [CFT, try 7] Emulated tls rewrite Richard Henderson
  2010-07-15  7:49 ` Richard Guenther
  2010-07-15 12:00 ` Jack Howarth
@ 2010-07-19 19:42 ` Richard Henderson
  2010-07-20 15:53   ` Richard Guenther
  2 siblings, 1 reply; 28+ messages in thread
From: Richard Henderson @ 2010-07-19 19:42 UTC (permalink / raw)
  To: IainS; +Cc: GCC Patches, richard.guenther

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

This should be really close to the final version.

I've eliminated a couple of the hacks that remained in v7.  In particular, all of the
GC'd data from v7 is now localized to the IPA pass.  Which means that I no longer have
to have a hack in varpool.c to avoid a ggc_free call.  There are almost no references
to emulated tls remaining outside tree-emutls.c.

The one remaining hack is localized to one line in dwarf2out.c.  If a target arranges
with gdb the meaning of DW_OP_form_tls_address, as vxworks apparently does, then we
need some way to associate the original TLS variable with its control variable.  I
accomplish this by storing the control variable in DECL_VALUE_EXPR.

At first this sounds gross, but I had already been storing a non-null value in
DECL_VALUE_EXPR as a way to indicate to generic verify code that TLS variables should
no longer appear in gimple code.  To a greater or lesser extent DECL_VALUE_EXPR is 
also a way to communicate a complicated storage location for a DECL with the debug
output routines.  The only difference here is that I don't store the entire call
expression and dereference as well.  Given that we're already special-casing TLS
variables, this doesn't seem so bad after all.


r~

[-- Attachment #2: emutls-8 --]
[-- Type: text/plain, Size: 57361 bytes --]

2010-07-19  Richard Henderson  <rth@redhat.com>

	PR target/44132
	* tree-emutls.c: New file.
	* Makefile.in (OBJS-common): Add it.
	* tree-pass.h (pass_ipa_lower_emutls): Declare.
	* passes.c (init_optimization_passes): Add it.

	* dwarf2out.c (loc_list_from_tree): If emutls.debug_form_tls_address,
	pull the control variable from DECL_VALUE_EXPR, not emutls_decl.
	* expr.c (emutls_var_address): Delete.
	(expand_expr_addr_expr_1, expand_expr_real_1): Don't use it.
	* output.h (SECCAT_EMUTLS_VAR, SECCAT_EMUTLS_TMPL): Delete.
	(emutls_finish): Delete.
	* toplev.c (compile_file): Don't call it.
	* tree.h (emutls_decl): Delete.
	* varasm.c (emutls_htab, DECL_EMUTLS_VAR_P): Delete.
	(emutls_finish, emutls_finalize_control_var): Delete.
	(emutls_object_type): Move to tree-emutls.c.
	(EMUTLS_SEPARATOR, prefix_name, get_emutls_object_name,
	default_emutls_var_fields, get_emutls_object_type,
	get_emutls_init_templ_addr, emutls_decl, emutls_common_1
	default_emutls_var_init): Likewise.
	(get_variable_section): Don't special case emutls.
	(assemble_variable, do_assemble_alias, categorize_decl_for_section,
	default_elf_select_section, default_unique_section,
	default_encode_section_info): Likewise.
	* varpool.c (decide_is_variable_needed): Likewise.

	* config/i386/i386.c (x86_64_elf_select_section): Don't handle
	SECCAT_EMUTLS_VAR, SECCAT_EMUTLS_TMPL.
	(x86_64_elf_unique_section): Likewise.

testsuite/
	* gcc.dg/tls/emutls-2.c: New test

2010-07-19  Iain Sandoe  <iains@gcc.gnu.org>

	* 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.


diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 3aeade5..087dbfe 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1354,6 +1354,7 @@ OBJS-common = \
 	tree-diagnostic.o \
 	tree-dump.o \
 	tree-eh.o \
+	tree-emutls.o \
 	tree-if-conv.o \
 	tree-into-ssa.o \
 	tree-iterator.o \
@@ -3142,6 +3143,9 @@ tree-switch-conversion.o : tree-switch-conversion.c $(CONFIG_H) $(SYSTEM_H) \
 tree-complex.o : tree-complex.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
     $(TM_H) $(FLAGS_H) $(TREE_FLOW_H) $(GIMPLE_H) \
     tree-iterator.h $(TREE_PASS_H) tree-ssa-propagate.h $(DIAGNOSTIC_H)
+tree-emutls.o : tree-emutls.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
+    $(GIMPLE_H) $(TREE_PASS_H) $(TREE_FLOW_H) $(CGRAPH_H) langhooks.h \
+    $(TARGET_H) targhooks.h tree-iterator.h
 tree-vect-generic.o : tree-vect-generic.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \
     $(TM_H) $(TREE_FLOW_H) $(GIMPLE_H) tree-iterator.h $(TREE_PASS_H) \
     $(FLAGS_H) $(OPTABS_H) $(MACHMODE_H) $(EXPR_H) \
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index bb0b890..91bc793 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -4355,9 +4355,6 @@ x86_64_elf_select_section (tree decl, int reloc,
 	  /* We don't split these for medium model.  Place them into
 	     default sections and hope for best.  */
 	  break;
-	case SECCAT_EMUTLS_VAR:
-	case SECCAT_EMUTLS_TMPL:
-	  gcc_unreachable ();
 	}
       if (sname)
 	{
@@ -4415,12 +4412,6 @@ x86_64_elf_unique_section (tree decl, int reloc)
 	  /* We don't split these for medium model.  Place them into
 	     default sections and hope for best.  */
 	  break;
-	case SECCAT_EMUTLS_VAR:
-	  prefix = targetm.emutls.var_section;
-	  break;
-	case SECCAT_EMUTLS_TMPL:
-	  prefix = targetm.emutls.tmpl_section;
-	  break;
 	}
       if (prefix)
 	{
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 385d5da..f2bad8a 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -15108,7 +15108,11 @@ loc_list_from_tree (tree loc, int want_address)
 	      if (!targetm.emutls.debug_form_tls_address
 		  || !(dwarf_version >= 3 || !dwarf_strict))
 		return 0;
-	      loc = emutls_decl (loc);
+	      /* We stuffed the control variable into the DECL_VALUE_EXPR
+		 to signal (via DECL_HAS_VALUE_EXPR_P) that the decl should
+		 no longer appear in gimple code.  We used the control
+		 variable in specific so that we could pick it up here.  */
+	      loc = DECL_VALUE_EXPR (loc);
 	      first_op = DW_OP_addr;
 	      second_op = DW_OP_form_tls_address;
 	    }
diff --git a/gcc/expr.c b/gcc/expr.c
index 3e5d18b..57f9eff 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -6818,19 +6818,6 @@ highest_pow2_factor_for_target (const_tree target, const_tree exp)
   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 call = build_call_expr (fn, 1, arg);
-  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
@@ -6933,18 +6920,6 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
       inner = TREE_OPERAND (exp, 0);
       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
@@ -8382,16 +8357,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 	  && (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:
diff --git a/gcc/output.h b/gcc/output.h
index d1e5f24..014ca1c 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -165,9 +165,6 @@ extern void merge_weak (tree, tree);
 /* Emit any pending weak declarations.  */
 extern void weak_finish (void);
 
-/* Emit any pending emutls declarations and initializations.  */
-extern void emutls_finish (void);
-
 /* Return the default TLS model for a given variable.  */
 extern enum tls_model decl_default_tls_model (const_tree);
 
@@ -479,10 +476,7 @@ enum section_category
 
   SECCAT_BSS,
   SECCAT_SBSS,
-  SECCAT_TBSS,
-
-  SECCAT_EMUTLS_VAR,
-  SECCAT_EMUTLS_TMPL
+  SECCAT_TBSS
 };
 
 /* Information that is provided by all instances of the section type.  */
diff --git a/gcc/passes.c b/gcc/passes.c
index 72e9b5a..5a4cdc8 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -804,6 +804,7 @@ init_optimization_passes (void)
     }
   NEXT_PASS (pass_ipa_increase_alignment);
   NEXT_PASS (pass_ipa_matrix_reorg);
+  NEXT_PASS (pass_ipa_lower_emutls);
   *p = NULL;
 
   p = &all_regular_ipa_passes;
diff --git a/gcc/testsuite/gcc.dg/tls/emutls-2.c b/gcc/testsuite/gcc.dg/tls/emutls-2.c
new file mode 100644
index 0000000..1e26d5f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tls/emutls-2.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target tls } */
+/* { dg-options "-O2" } */
+
+/* With emulated TLS, the constructor generated during IPA
+   was not properly lowered to SSA form.  */
+
+__thread int i __attribute__((common));
diff --git a/gcc/testsuite/gcc.dg/tls/thr-init-1.c b/gcc/testsuite/gcc.dg/tls/thr-init-1.c
new file mode 100644
index 0000000..de273d9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tls/thr-init-1.c
@@ -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 } */
diff --git a/gcc/testsuite/gcc.dg/tls/thr-init-2.c b/gcc/testsuite/gcc.dg/tls/thr-init-2.c
new file mode 100644
index 0000000..6d00d8c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tls/thr-init-2.c
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/tls/thr-init-1.c b/gcc/testsuite/gcc.dg/torture/tls/thr-init-1.c
new file mode 100644
index 0000000..89725c3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/tls/thr-init-1.c
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/tls/thr-init-2.c b/gcc/testsuite/gcc.dg/torture/tls/thr-init-2.c
new file mode 100644
index 0000000..9d09319
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/tls/thr-init-2.c
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/tls/tls-test.c b/gcc/testsuite/gcc.dg/torture/tls/tls-test.c
new file mode 100644
index 0000000..8a23e77
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/tls/tls-test.c
@@ -0,0 +1,52 @@
+/* { dg-do run }  */
+/* { dg-require-effective-target tls  }  */
+/* { dg-require-effective-target pthread } */
+/* { dg-options "-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;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/tls/tls.exp b/gcc/testsuite/gcc.dg/torture/tls/tls.exp
new file mode 100644
index 0000000..91c8843
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/tls/tls.exp
@@ -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
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 964669f..60ca5dc 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -992,11 +992,6 @@ compile_file (void)
   if (seen_error ())
     return;
 
-  /* Ensure that emulated TLS control vars are finalized and build 
-     a static constructor for them, when it is required.  */
-  if (!targetm.have_tls)
-    emutls_finish ();
-
   varpool_assemble_pending_decls ();
   finish_aliases_2 ();
 
diff --git a/gcc/tree-emutls.c b/gcc/tree-emutls.c
new file mode 100644
index 0000000..d67cd2f
--- /dev/null
+++ b/gcc/tree-emutls.c
@@ -0,0 +1,846 @@
+/* Lower TLS operations to emulation functions.
+   Copyright (C) 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any
+later version.
+
+GCC 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/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "tree-flow.h"
+#include "cgraph.h"
+#include "langhooks.h"
+#include "target.h"
+#include "targhooks.h"
+#include "tree-iterator.h"
+
+
+/* Whenever a target does not support thread-local storage (TLS) natively,
+   we can emulate it with some run-time support in libgcc.  This will in
+   turn rely on "keyed storage" a-la pthread_key_create; essentially all
+   thread libraries provide such functionality.
+
+   In order to coordinate with the libgcc runtime, each TLS variable is
+   described by a "control variable".  This control variable records the
+   required size, alignment, and initial value of the TLS variable for
+   instantiation at runtime.  It also stores an integer token to be used
+   by the runtime to find the address of the variable within each thread.
+
+   On the compiler side, this means that we need to replace all instances
+   of "tls_var" in the code with "*__emutls_get_addr(&control_var)".  We
+   also need to eliminate "tls_var" from the symbol table and introduce
+   "control_var".
+
+   We used to perform all of the transformations during conversion to rtl,
+   and the variable substitutions magically within assemble_variable.
+   However, this late fiddling of the symbol table conflicts with LTO and
+   whole-program compilation.  Therefore we must now make all the changes
+   to the symbol table early in the GIMPLE optimization path, before we
+   write things out to LTO intermediate files.  */
+
+/* These two vectors, once fully populated, are kept in lock-step so that
+   the index of a TLS variable equals the index of its control variable in
+   the other vector.  */
+static varpool_node_set tls_vars;
+static VEC(varpool_node_ptr, heap) *control_vars;
+
+/* For the current basic block, an SSA_NAME that has computed the address 
+   of the TLS variable at the corresponding index.  */
+static VEC(tree, heap) *access_vars;
+
+/* The type of the control structure, shared with the emutls.c runtime.  */
+static tree emutls_object_type;
+
+#if !defined (NO_DOT_IN_LABEL)
+# define EMUTLS_SEPARATOR	"."
+#elif !defined (NO_DOLLAR_IN_LABEL)
+# define EMUTLS_SEPARATOR	"$"
+#else
+# define EMUTLS_SEPARATOR	"_"
+#endif
+
+/* Create an IDENTIFIER_NODE by prefixing PREFIX to the
+   IDENTIFIER_NODE NAME's name.  */
+
+static tree
+prefix_name (const char *prefix, tree name)
+{
+  unsigned plen = strlen (prefix);
+  unsigned nlen = strlen (IDENTIFIER_POINTER (name));
+  char *toname = (char *) alloca (plen + nlen + 1);
+
+  memcpy (toname, prefix, plen);
+  memcpy (toname + plen, IDENTIFIER_POINTER (name), nlen + 1);
+
+  return get_identifier (toname);
+}
+
+/* Create an identifier for the struct __emutls_object, given an identifier
+   of the DECL_ASSEMBLY_NAME of the original object.  */
+
+static tree
+get_emutls_object_name (tree name)
+{
+  const char *prefix = (targetm.emutls.var_prefix
+			? targetm.emutls.var_prefix
+			: "__emutls_v" EMUTLS_SEPARATOR);
+  return prefix_name (prefix, name);
+}
+
+tree
+default_emutls_var_fields (tree type, tree *name ATTRIBUTE_UNUSED)
+{
+  tree word_type_node, field, next_field;
+
+  field = build_decl (UNKNOWN_LOCATION,
+		      FIELD_DECL, get_identifier ("__templ"), ptr_type_node);
+  DECL_CONTEXT (field) = type;
+  next_field = field;
+
+  field = build_decl (UNKNOWN_LOCATION,
+		      FIELD_DECL, get_identifier ("__offset"),
+		      ptr_type_node);
+  DECL_CONTEXT (field) = type;
+  DECL_CHAIN (field) = next_field;
+  next_field = field;
+
+  word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
+  field = build_decl (UNKNOWN_LOCATION,
+		      FIELD_DECL, get_identifier ("__align"),
+		      word_type_node);
+  DECL_CONTEXT (field) = type;
+  DECL_CHAIN (field) = next_field;
+  next_field = field;
+
+  field = build_decl (UNKNOWN_LOCATION,
+		      FIELD_DECL, get_identifier ("__size"), word_type_node);
+  DECL_CONTEXT (field) = type;
+  DECL_CHAIN (field) = next_field;
+
+  return field;
+}
+
+/* Initialize emulated tls object TO, which refers to TLS variable
+   DECL and is initialized by PROXY.  */
+
+tree
+default_emutls_var_init (tree to, tree decl, tree proxy)
+{
+  VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, 4);
+  constructor_elt *elt;
+  tree type = TREE_TYPE (to);
+  tree field = TYPE_FIELDS (type);
+
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  elt->index = field;
+  elt->value = fold_convert (TREE_TYPE (field), DECL_SIZE_UNIT (decl));
+
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  field = DECL_CHAIN (field);
+  elt->index = field;
+  elt->value = build_int_cst (TREE_TYPE (field),
+			      DECL_ALIGN_UNIT (decl));
+
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  field = DECL_CHAIN (field);
+  elt->index = field;
+  elt->value = null_pointer_node;
+
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  field = DECL_CHAIN (field);
+  elt->index = field;
+  elt->value = proxy;
+
+  return build_constructor (type, v);
+}
+
+/* Create the structure for struct __emutls_object.  This should match the
+   structure at the top of emutls.c, modulo the union there.  */
+
+static tree
+get_emutls_object_type (void)
+{
+  tree type, type_name, field;
+
+  type = emutls_object_type;
+  if (type)
+    return type;
+
+  emutls_object_type = type = lang_hooks.types.make_type (RECORD_TYPE);
+  type_name = NULL;
+  field = targetm.emutls.var_fields (type, &type_name);
+  if (!type_name)
+    type_name = get_identifier ("__emutls_object");
+  type_name = build_decl (UNKNOWN_LOCATION,
+			  TYPE_DECL, type_name, type);
+  TYPE_NAME (type) = type_name;
+  TYPE_FIELDS (type) = field;
+  layout_type (type);
+
+  return type;
+}
+
+/* Create a read-only variable like DECL, with the same DECL_INITIAL.
+   This will be used for initializing the emulated tls data area.  */
+
+static tree
+get_emutls_init_templ_addr (tree decl)
+{
+  tree name, to;
+
+  if (targetm.emutls.register_common && !DECL_INITIAL (decl)
+      && !DECL_SECTION_NAME (decl))
+    return null_pointer_node;
+
+  name = DECL_ASSEMBLER_NAME (decl);
+  if (!targetm.emutls.tmpl_prefix || targetm.emutls.tmpl_prefix[0])
+    {
+      const char *prefix = (targetm.emutls.tmpl_prefix
+			    ? targetm.emutls.tmpl_prefix
+			    : "__emutls_t" EMUTLS_SEPARATOR);
+      name = prefix_name (prefix, name);
+    }
+
+  to = build_decl (DECL_SOURCE_LOCATION (decl),
+		   VAR_DECL, name, TREE_TYPE (decl));
+  SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
+
+  DECL_ARTIFICIAL (to) = 1;
+  TREE_USED (to) = TREE_USED (decl);
+  TREE_READONLY (to) = 1;
+  DECL_IGNORED_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))
+    {
+      make_decl_one_only (to, DECL_ASSEMBLER_NAME (to));
+      TREE_STATIC (to) = TREE_STATIC (decl);
+      TREE_PUBLIC (to) = TREE_PUBLIC (decl);
+      DECL_VISIBILITY (to) = DECL_VISIBILITY (decl);
+    }
+  else
+    TREE_STATIC (to) = 1;
+
+  DECL_VISIBILITY_SPECIFIED (to) = DECL_VISIBILITY_SPECIFIED (decl);
+  DECL_INITIAL (to) = DECL_INITIAL (decl);
+  DECL_INITIAL (decl) = NULL;
+
+  if (targetm.emutls.tmpl_section)
+    {
+      DECL_SECTION_NAME (to)
+        = build_string (strlen (targetm.emutls.tmpl_section),
+			targetm.emutls.tmpl_section);
+    }
+
+  varpool_finalize_decl (to);
+  return build_fold_addr_expr (to);
+}
+
+/* Create and return the control variable for the TLS variable DECL.  */
+
+static tree
+new_emutls_decl (tree decl)
+{
+  tree name, to;
+
+  name = DECL_ASSEMBLER_NAME (decl);
+  to = build_decl (DECL_SOURCE_LOCATION (decl), VAR_DECL,
+                   get_emutls_object_name (name),
+                   get_emutls_object_type ());
+
+  SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
+
+  DECL_TLS_MODEL (to) = TLS_MODEL_EMULATED;
+  DECL_ARTIFICIAL (to) = 1;
+  DECL_IGNORED_P (to) = 1;
+  TREE_READONLY (to) = 0;
+  TREE_STATIC (to) = 1;
+
+  DECL_PRESERVE_P (to) = DECL_PRESERVE_P (decl);
+  DECL_CONTEXT (to) = DECL_CONTEXT (decl);
+  TREE_USED (to) = TREE_USED (decl);
+  TREE_PUBLIC (to) = TREE_PUBLIC (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_RESTRICTED_P (to) = DECL_RESTRICTED_P (decl);
+  DECL_DLLIMPORT_P (to) = DECL_DLLIMPORT_P (decl);
+
+  DECL_ATTRIBUTES (to) = targetm.merge_decl_attributes (decl, to);
+
+  if (DECL_ONE_ONLY (decl))
+    make_decl_one_only (to, DECL_ASSEMBLER_NAME (to));
+
+  /* If we're not allowed to change the proxy object's alignment,
+     pretend it has been set by the user.  */
+  if (targetm.emutls.var_align_fixed)
+    DECL_USER_ALIGN (to) = 1;
+
+  /* If the target wants the control variables grouped, do so.  */
+  if (!DECL_COMMON (to) && targetm.emutls.var_section)
+    {
+      DECL_SECTION_NAME (to)
+        = build_string (strlen (targetm.emutls.tmpl_section),
+			targetm.emutls.tmpl_section);
+    }
+
+  /* If this variable is defined locally, then we need to initialize the
+     control structure with size and alignment information.  Initialization
+     of COMMON block variables happens elsewhere via a constructor.  */
+  if (!DECL_EXTERNAL (to)
+      && (!DECL_COMMON (to)
+          || (DECL_INITIAL (decl)
+              && DECL_INITIAL (decl) != error_mark_node)))
+    {
+      tree tmpl = get_emutls_init_templ_addr (decl);
+      DECL_INITIAL (to) = targetm.emutls.var_init (to, decl, tmpl);
+      record_references_in_initializer (to, false);
+    }
+
+  varpool_finalize_decl (to);
+  return to;
+}
+
+/* Look up the control variable for the TLS variable DECL.  */
+
+static unsigned int
+emutls_index (tree decl)
+{
+  varpool_node_set_iterator i;
+  
+  i = varpool_node_set_find (tls_vars, varpool_get_node (decl));
+  gcc_assert (i.index != ~0u);
+
+  return i.index;
+}
+
+static tree
+emutls_decl (tree decl)
+{
+  struct varpool_node *var;
+  unsigned int i;
+
+  i = emutls_index (decl);
+  var = VEC_index (varpool_node_ptr, control_vars, i);
+  return var->decl;
+}
+
+/* Generate a call statement to initialize CONTROL_DECL for TLS_DECL.
+   This only needs to happen for TLS COMMON variables; non-COMMON
+   variables can be initialized statically.  Insert the generated
+   call statement at the end of PSTMTS.  */
+   
+static void
+emutls_common_1 (tree tls_decl, tree control_decl, tree *pstmts)
+{
+  tree x;
+  tree word_type_node;
+
+  if (! DECL_COMMON (tls_decl)
+      || (DECL_INITIAL (tls_decl)
+	  && DECL_INITIAL (tls_decl) != error_mark_node))
+    return;
+
+  word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
+
+  x = build_call_expr (built_in_decls[BUILT_IN_EMUTLS_REGISTER_COMMON], 4,
+		       build_fold_addr_expr (control_decl),
+		       fold_convert (word_type_node,
+				     DECL_SIZE_UNIT (tls_decl)),
+		       build_int_cst (word_type_node,
+				      DECL_ALIGN_UNIT (tls_decl)),
+		       get_emutls_init_templ_addr (tls_decl));
+
+  append_to_statement_list (x, pstmts);
+}
+
+struct lower_emutls_data
+{
+  struct cgraph_node *cfun_node;
+  struct cgraph_node *builtin_node;
+  tree builtin_decl;
+  basic_block bb;
+  int bb_freq;
+  location_t loc;
+  gimple_seq seq;
+};
+
+/* Given a TLS variable DECL, return an SSA_NAME holding its address.  */
+
+static tree
+gen_emutls_addr (tree decl, struct lower_emutls_data *d)
+{
+  unsigned int index;
+  tree addr;
+
+  /* Compute the address of the TLS variable with help from runtime.  */
+  index = emutls_index (decl);
+  addr = VEC_index (tree, access_vars, index);
+  if (addr == NULL)
+    {
+      struct varpool_node *cvar;
+      tree cdecl;
+      gimple x;
+
+      cvar = VEC_index (varpool_node_ptr, control_vars, index);
+      cdecl = cvar->decl;
+      TREE_ADDRESSABLE (cdecl) = 1;
+
+      addr = create_tmp_var (build_pointer_type (TREE_TYPE (decl)), NULL);
+      x = gimple_build_call (d->builtin_decl, 1, build_fold_addr_expr (cdecl));
+      gimple_set_location (x, d->loc);
+
+      addr = make_ssa_name (addr, x);
+      gimple_call_set_lhs (x, addr);
+
+      gimple_seq_add_stmt (&d->seq, x);
+
+      cgraph_create_edge (d->cfun_node, d->builtin_node, x,
+                          d->bb->count, d->bb_freq, d->bb->loop_depth);
+
+      /* We may be adding a new reference to a new variable to the function.
+         This means we have to play with the ipa-reference web.  */
+      ipa_record_reference (d->cfun_node, NULL, NULL, cvar, IPA_REF_ADDR, x);
+
+      /* Record this ssa_name for possible use later in the basic block.  */
+      VEC_replace (tree, access_vars, index, addr);
+    }
+
+  return addr;
+}
+
+/* Callback for walk_gimple_op.  D = WI->INFO is a struct lower_emutls_data.
+   Given an operand *PTR within D->STMT, if the operand references a TLS
+   variable, then lower the reference to a call to the runtime.  Insert
+   any new statements required into D->SEQ; the caller is responsible for
+   placing those appropriately.  */
+
+static tree
+lower_emutls_1 (tree *ptr, int *walk_subtrees, void *cb_data)
+{
+  struct walk_stmt_info *wi = (struct walk_stmt_info *) cb_data;
+  struct lower_emutls_data *d = (struct lower_emutls_data *) wi->info;
+  tree t = *ptr;
+  bool is_addr = false;
+  tree addr;
+
+  *walk_subtrees = 0;
+
+  switch (TREE_CODE (t))
+    {
+    case ADDR_EXPR:
+      /* If this is not a straight-forward "&var", but rather something
+	 like "&var.a", then we may need special handling.  */
+      if (TREE_CODE (TREE_OPERAND (t, 0)) != VAR_DECL)
+	{
+	  bool save_changed;
+
+	  /* If we're allowed more than just is_gimple_val, continue.  */
+	  if (!wi->val_only)
+	    {
+	      *walk_subtrees = 1;
+	      return NULL_TREE;
+	    }
+
+	  /* See if any substitution would be made.  */
+	  save_changed = wi->changed;
+	  wi->changed = false;
+	  wi->val_only = false;
+	  walk_tree (&TREE_OPERAND (t, 0), lower_emutls_1, wi, NULL);
+	  wi->val_only = true;
+
+	  /* If so, then extract this entire sub-expression "&p->a" into a
+	     new assignment statement, and substitute yet another SSA_NAME.  */
+	  if (wi->changed)
+	    {
+	      gimple x;
+
+	      addr = create_tmp_var (TREE_TYPE (t), NULL);
+	      x = gimple_build_assign (addr, t);
+	      gimple_set_location (x, d->loc);
+
+	      addr = make_ssa_name (addr, x);
+	      gimple_assign_set_lhs (x, addr);
+
+	      gimple_seq_add_stmt (&d->seq, x);
+
+	      *ptr = addr;
+	    }
+	  else
+	    wi->changed = save_changed;
+
+	  return NULL_TREE;
+	}
+
+      t = TREE_OPERAND (t, 0);
+      is_addr = true;
+      /* FALLTHRU */
+
+    case VAR_DECL:
+      if (!DECL_THREAD_LOCAL_P (t))
+	return NULL_TREE;
+      break;
+
+    default:
+      /* We're not interested in other decls or types, only subexpressions.  */
+      if (EXPR_P (t))
+        *walk_subtrees = 1;
+      /* FALLTHRU */
+
+    case SSA_NAME:
+      /* Special-case the return of SSA_NAME, since it's so common.  */
+      return NULL_TREE;
+    }
+
+  addr = gen_emutls_addr (t, d);
+  if (is_addr)
+    {
+      /* Replace "&var" with "addr" in the statement.  */
+      *ptr = addr;
+    }
+  else
+    {
+      /* Replace "var" with "*addr" in the statement.  */
+      t = build2 (MEM_REF, TREE_TYPE (t), addr,
+	          build_int_cst (TREE_TYPE (addr), 0));
+      *ptr = t;
+    }
+
+  wi->changed = true;
+  return NULL_TREE;
+}
+
+/* Lower all of the operands of STMT.  */
+
+static void
+lower_emutls_stmt (gimple stmt, struct lower_emutls_data *d)
+{
+  struct walk_stmt_info wi;
+
+  d->loc = gimple_location (stmt);
+
+  memset (&wi, 0, sizeof (wi));
+  wi.info = d;
+  wi.val_only = true;
+  walk_gimple_op (stmt, lower_emutls_1, &wi);
+
+  if (wi.changed)
+    update_stmt (stmt);
+}
+
+/* Lower the I'th operand of PHI.  */
+
+static void
+lower_emutls_phi_arg (gimple phi, unsigned int i, struct lower_emutls_data *d)
+{
+  struct walk_stmt_info wi;
+  struct phi_arg_d *pd = gimple_phi_arg (phi, i);
+
+  /* Early out for a very common case we don't care about.  */
+  if (TREE_CODE (pd->def) == SSA_NAME)
+    return;
+
+  d->loc = pd->locus;
+
+  memset (&wi, 0, sizeof (wi));
+  wi.info = d;
+  wi.val_only = true;
+  walk_tree (&pd->def, lower_emutls_1, &wi, NULL);
+
+  /* For normal statements, we let update_stmt do its job.  But for phi
+     nodes, we have to manipulate the immediate use list by hand.  */
+  if (wi.changed)
+    {
+      gcc_assert (TREE_CODE (pd->def) == SSA_NAME);
+      link_imm_use_stmt (&pd->imm_use, pd->def, phi);
+    }
+}
+
+/* Clear the ACCESS_VARS array, in order to begin a new block.  */
+
+static inline void
+clear_access_vars (void)
+{
+  memset (VEC_address (tree, access_vars), 0,
+          VEC_length (tree, access_vars) * sizeof(tree));
+}
+
+/* Compute the frequency of instructions to be insertted on an edge E.
+
+   Mirror a portion of the logic from gimple_find_edge_insert_loc to
+   do this.  Determine if statements inserted on E will be insertted
+   into the predecessor block.  We must choose the correct block,
+   and thus frequency, in order to pass verify_cgraph.  */
+
+static int
+compute_edge_bb_frequency (edge e)
+{
+  basic_block src = e->src;
+
+  /* If the destination has one predecessor and no PHI nodes, insert
+     there... Except that we *know* it has PHI nodes or else there's
+     nothing for us to do.  Skip this step.  */
+
+  /* If the source has one successor, the edge is not abnormal and the
+     last statement does not end a basic block, insert there.  */
+  if ((e->flags & EDGE_ABNORMAL) == 0
+      && src != ENTRY_BLOCK_PTR
+      && single_succ_p (src))
+    {
+      gimple_stmt_iterator gsi;
+      gimple last;
+
+      /* If the block is empty, of course we use it.  */
+      gsi = gsi_last_bb (src);
+      if (gsi_end_p (gsi))
+	goto return_pred;
+
+      /* If the last stmt does not end the block, we insert after.  */
+      last = gsi_stmt (gsi);
+      if (!stmt_ends_bb_p (last))
+	goto return_pred;
+
+      /* If the last stmt is a trivial control, we insert before.  */
+      switch (gimple_code (last))
+	{
+	case GIMPLE_RETURN:
+	case GIMPLE_RESX:
+	  goto return_pred;
+	default:
+	  break;
+	}
+    }
+
+  /* We will be splitting the edge and insertting there.  */
+  return EDGE_FREQUENCY (e);
+
+  /* If we get here, we will not be splitting the edge and instead
+     insertting any code into the predecessor block.  */
+ return_pred:
+  return compute_call_stmt_bb_frequency (current_function_decl, e->src);
+}
+
+/* Lower the entire function NODE.  */
+
+static void
+lower_emutls_function_body (struct cgraph_node *node)
+{
+  struct lower_emutls_data d;
+  bool any_edge_inserts = false;
+
+  current_function_decl = node->decl;
+  push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+
+  d.cfun_node = node;
+  d.builtin_decl = built_in_decls[BUILT_IN_EMUTLS_GET_ADDRESS];
+  d.builtin_node = cgraph_node (d.builtin_decl);
+
+  FOR_EACH_BB (d.bb)
+    {
+      gimple_stmt_iterator gsi;
+      unsigned int i, nedge;
+
+      /* Lower each of the PHI nodes of the block, as we may have 
+	 propagated &tlsvar into a PHI argument.  These loops are
+	 arranged so that we process each edge at once, and each
+	 PHI argument for that edge.  */
+      if (!gimple_seq_empty_p (phi_nodes (d.bb)))
+	{
+	  nedge = EDGE_COUNT (d.bb->preds);
+	  for (i = 0; i < nedge; ++i)
+	    {
+	      edge e = EDGE_PRED (d.bb, i);
+
+	      d.bb_freq = compute_edge_bb_frequency (e);
+
+	      /* We can re-use any SSA_NAME created on this edge.  */
+	      clear_access_vars ();
+	      d.seq = NULL;
+
+	      for (gsi = gsi_start_phis (d.bb);
+		   !gsi_end_p (gsi);
+		   gsi_next (&gsi))
+		lower_emutls_phi_arg (gsi_stmt (gsi), i, &d);
+
+	      /* Insert all statements generated by all phi nodes for this
+		 particular edge all at once.  */
+	      if (d.seq)
+		{
+		  gsi_insert_seq_on_edge (e, d.seq);
+		  any_edge_inserts = true;
+		}
+	    }
+	}
+
+      d.bb_freq = compute_call_stmt_bb_frequency (current_function_decl, d.bb);
+
+      /* We can re-use any SSA_NAME created during this basic block.  */
+      clear_access_vars ();
+
+      /* Lower each of the statements of the block.  */
+      for (gsi = gsi_start_bb (d.bb); !gsi_end_p (gsi); gsi_next (&gsi))
+	{
+          d.seq = NULL;
+	  lower_emutls_stmt (gsi_stmt (gsi), &d);
+
+	  /* If any new statements were created, insert them immediately
+	     before the first use.  This prevents variable lifetimes from
+	     becoming unnecessarily long.  */
+	  if (d.seq)
+	    gsi_insert_seq_before (&gsi, d.seq, GSI_SAME_STMT);
+	}
+    }
+
+  if (any_edge_inserts)
+    gsi_commit_edge_inserts ();
+
+  pop_cfun ();
+  current_function_decl = NULL;
+}
+
+/* Main entry point to the tls lowering pass.  */
+
+static unsigned int
+ipa_lower_emutls (void)
+{
+  struct varpool_node *var;
+  struct cgraph_node *func;
+  bool any_aliases = false;
+  tree ctor_body = NULL;
+  unsigned int i, n_tls;
+
+  tls_vars = varpool_node_set_new ();
+
+  /* Examine all global variables for TLS variables.  */
+  for (var = varpool_nodes; var ; var = var->next)
+    if (DECL_THREAD_LOCAL_P (var->decl))
+      {
+	gcc_checking_assert (TREE_STATIC (var->decl)
+			     || DECL_EXTERNAL (var->decl));
+	varpool_node_set_add (tls_vars, var);
+      }
+
+  /* If we found no TLS variables, then there is no further work to do.  */
+  if (tls_vars->nodes == NULL)
+    {
+      tls_vars = NULL;
+      if (dump_file)
+	fprintf (dump_file, "No TLS variables found.\n");
+      return 0;
+    }
+
+  /* Allocate the on-the-side arrays that share indicies with the TLS vars.  */
+  n_tls = VEC_length (varpool_node_ptr, tls_vars->nodes);
+  control_vars = VEC_alloc (varpool_node_ptr, heap, n_tls);
+  access_vars = VEC_alloc (tree, heap, n_tls);
+  VEC_safe_grow (tree, heap, access_vars, n_tls);
+
+  /* Create the control variables for each TLS variable.  */
+  for (i = 0; VEC_iterate (varpool_node_ptr, tls_vars->nodes, i, var); ++i)
+    {
+      tree cdecl;
+      struct varpool_node *cvar;
+
+      var = VEC_index (varpool_node_ptr, tls_vars->nodes, i);
+      cdecl = new_emutls_decl (var->decl);
+
+      cvar = varpool_get_node (cdecl);
+      VEC_quick_push (varpool_node_ptr, control_vars, cvar);
+
+      if (var->alias)
+	{
+	  any_aliases = true;
+	  cvar->alias = true;
+	}
+      else
+	{
+	  /* Make sure the COMMON block control variable gets initialized.
+	     Note that there's no point in doing this for aliases; we only
+	     need to do this once for the main variable.  */
+          emutls_common_1 (var->decl, cdecl, &ctor_body);
+	}
+
+      /* Indicate that the value of the TLS variable may be found elsewhere,
+	 preventing the variable from re-appearing in the GIMPLE.  We cheat
+	 and use the control variable here (rather than a full call_expr),
+	 which is special-cased inside the DWARF2 output routines.  */
+      SET_DECL_VALUE_EXPR (var->decl, cdecl);
+      DECL_HAS_VALUE_EXPR_P (var->decl) = 1;
+    }
+
+  /* If there were any aliases, then frob the alias_pairs vector.  */
+  if (any_aliases)
+    {
+      alias_pair *p;
+      for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ++i)
+	if (DECL_THREAD_LOCAL_P (p->decl))
+	  {
+	    p->decl = emutls_decl (p->decl);
+	    p->target = get_emutls_object_name (p->target);
+	  }
+    }
+
+  /* Adjust all uses of TLS variables within the function bodies.  */
+  for (func = cgraph_nodes; func; func = func->next)
+    if (func->reachable && func->lowered)
+      lower_emutls_function_body (func);
+
+  /* Generate the constructor for any COMMON control variables created.  */
+  if (ctor_body)
+    cgraph_build_static_cdtor ('I', ctor_body, DEFAULT_INIT_PRIORITY);
+
+  VEC_free (varpool_node_ptr, heap, control_vars);
+  VEC_free (tree, heap, access_vars);
+  tls_vars = NULL;
+
+  return TODO_dump_func | TODO_ggc_collect | TODO_verify_stmts;
+}
+
+/* If the target supports TLS natively, we need do nothing here.  */
+
+static bool
+gate_emutls (void)
+{
+  return !targetm.have_tls;
+}
+
+struct simple_ipa_opt_pass pass_ipa_lower_emutls =
+{
+ {
+  SIMPLE_IPA_PASS,
+  "emutls",				/* name */
+  gate_emutls,				/* gate */
+  ipa_lower_emutls,			/* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_NONE,				/* tv_id */
+  PROP_cfg,				/* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  0,					/* todo_flags_finish */
+ }
+};
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index c72d7cf..33c898e 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -446,6 +446,7 @@ extern struct gimple_opt_pass pass_warn_unused_result;
 extern struct gimple_opt_pass pass_split_functions;
 
 /* IPA Passes */
+extern struct simple_ipa_opt_pass pass_ipa_lower_emutls;
 extern struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility;
 extern struct simple_ipa_opt_pass pass_ipa_early_inline;
 
diff --git a/gcc/tree.h b/gcc/tree.h
index 3c0806e..5aa5a89 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5249,7 +5249,6 @@ extern void set_user_assembler_name (tree, const char *);
 extern void process_pending_assemble_externals (void);
 extern void finish_aliases_1 (void);
 extern void finish_aliases_2 (void);
-extern tree emutls_decl (tree);
 extern void remove_unreachable_alias_pairs (void);
 
 /* In stmt.c */
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 9a4c193..58c9a1b 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -186,317 +186,6 @@ static GTY(()) int anchor_labelno;
 /* A pool of constants that can be shared between functions.  */
 static GTY(()) struct rtx_constant_pool *shared_constant_pool;
 
-/* TLS emulation.  */
-
-static GTY ((if_marked ("tree_map_marked_p"), param_is (struct tree_map)))
-     htab_t emutls_htab;
-static GTY (()) tree emutls_object_type;
-/* Emulated TLS objects have the TLS model TLS_MODEL_EMULATED.  This
-   macro can be used on them to distinguish the control variable from
-   the initialization template.  */
-#define DECL_EMUTLS_VAR_P(D)  (TREE_TYPE (D) == emutls_object_type)
-
-#if !defined (NO_DOT_IN_LABEL)
-# define EMUTLS_SEPARATOR	"."
-#elif !defined (NO_DOLLAR_IN_LABEL)
-# define EMUTLS_SEPARATOR	"$"
-#else
-# define EMUTLS_SEPARATOR	"_"
-#endif
-
-/* Create an IDENTIFIER_NODE by prefixing PREFIX to the
-   IDENTIFIER_NODE NAME's name.  */
-
-static tree
-prefix_name (const char *prefix, tree name)
-{
-  unsigned plen = strlen (prefix);
-  unsigned nlen = strlen (IDENTIFIER_POINTER (name));
-  char *toname = (char *) alloca (plen + nlen + 1);
-
-  memcpy (toname, prefix, plen);
-  memcpy (toname + plen, IDENTIFIER_POINTER (name), nlen + 1);
-
-  return get_identifier (toname);
-}
-
-/* Create an identifier for the struct __emutls_object, given an identifier
-   of the DECL_ASSEMBLY_NAME of the original object.  */
-
-static tree
-get_emutls_object_name (tree name)
-{
-  const char *prefix = (targetm.emutls.var_prefix
-			? targetm.emutls.var_prefix
-			: "__emutls_v" EMUTLS_SEPARATOR);
-  return prefix_name (prefix, name);
-}
-
-tree
-default_emutls_var_fields (tree type, tree *name ATTRIBUTE_UNUSED)
-{
-  tree word_type_node, field, next_field;
-
-  field = build_decl (UNKNOWN_LOCATION,
-		      FIELD_DECL, get_identifier ("__templ"), ptr_type_node);
-  DECL_CONTEXT (field) = type;
-  next_field = field;
-
-  field = build_decl (UNKNOWN_LOCATION,
-		      FIELD_DECL, get_identifier ("__offset"),
-		      ptr_type_node);
-  DECL_CONTEXT (field) = type;
-  DECL_CHAIN (field) = next_field;
-  next_field = field;
-
-  word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
-  field = build_decl (UNKNOWN_LOCATION,
-		      FIELD_DECL, get_identifier ("__align"),
-		      word_type_node);
-  DECL_CONTEXT (field) = type;
-  DECL_CHAIN (field) = next_field;
-  next_field = field;
-
-  field = build_decl (UNKNOWN_LOCATION,
-		      FIELD_DECL, get_identifier ("__size"), word_type_node);
-  DECL_CONTEXT (field) = type;
-  DECL_CHAIN (field) = next_field;
-
-  return field;
-}
-
-/* Create the structure for struct __emutls_object.  This should match the
-   structure at the top of emutls.c, modulo the union there.  */
-
-static tree
-get_emutls_object_type (void)
-{
-  tree type, type_name, field;
-
-  type = emutls_object_type;
-  if (type)
-    return type;
-
-  emutls_object_type = type = lang_hooks.types.make_type (RECORD_TYPE);
-  type_name = NULL;
-  field = targetm.emutls.var_fields (type, &type_name);
-  if (!type_name)
-    type_name = get_identifier ("__emutls_object");
-  type_name = build_decl (UNKNOWN_LOCATION,
-			  TYPE_DECL, type_name, type);
-  TYPE_NAME (type) = type_name;
-  TYPE_FIELDS (type) = field;
-  layout_type (type);
-
-  return type;
-}
-
-/* Create a read-only variable like DECL, with the same DECL_INITIAL.
-   This will be used for initializing the emulated tls data area.  */
-
-static tree
-get_emutls_init_templ_addr (tree decl)
-{
-  tree name, to;
-
-  if (targetm.emutls.register_common && !DECL_INITIAL (decl)
-      && !DECL_SECTION_NAME (decl))
-    return null_pointer_node;
-
-  name = DECL_ASSEMBLER_NAME (decl);
-  if (!targetm.emutls.tmpl_prefix || targetm.emutls.tmpl_prefix[0])
-    {
-      const char *prefix = (targetm.emutls.tmpl_prefix
-			    ? targetm.emutls.tmpl_prefix
-			    : "__emutls_t" EMUTLS_SEPARATOR);
-      name = prefix_name (prefix, name);
-    }
-
-  to = build_decl (DECL_SOURCE_LOCATION (decl),
-		   VAR_DECL, name, TREE_TYPE (decl));
-  SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
-
-  DECL_ARTIFICIAL (to) = 1;
-  TREE_USED (to) = TREE_USED (decl);
-  TREE_READONLY (to) = 1;
-  DECL_IGNORED_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))
-    {
-      make_decl_one_only (to, DECL_ASSEMBLER_NAME (to));
-      TREE_STATIC (to) = TREE_STATIC (decl);
-      TREE_PUBLIC (to) = TREE_PUBLIC (decl);
-      DECL_VISIBILITY (to) = DECL_VISIBILITY (decl);
-    }
-  else
-    TREE_STATIC (to) = 1;
-
-  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);
-}
-
-/* When emulating tls, we use a control structure for use by the runtime.
-   Create and return this structure.  */
-
-tree
-emutls_decl (tree decl)
-{
-  tree name, to;
-  struct tree_map *h, in;
-  void **loc;
-
-  if (targetm.have_tls || decl == NULL || decl == error_mark_node
-      || TREE_CODE (decl) != VAR_DECL || ! DECL_THREAD_LOCAL_P (decl))
-    return decl;
-
-  /* Look up the object in the hash; return the control structure if
-     it has already been created.  */
-  if (! emutls_htab)
-    emutls_htab = htab_create_ggc (512, tree_map_hash, tree_map_eq, 0);
-
-  name = DECL_ASSEMBLER_NAME (decl);
-
-  /* Note that we use the hash of the decl's name, rather than a hash
-     of the decl's pointer.  In emutls_finish we iterate through the
-     hash table, and we want this traversal to be predictable.  */
-  in.hash = IDENTIFIER_HASH_VALUE (name);
-  in.base.from = decl;
-  loc = htab_find_slot_with_hash (emutls_htab, &in, in.hash, INSERT);
-  h = (struct tree_map *) *loc;
-  if (h != NULL)
-    to = h->to;
-  else
-    {
-      to = build_decl (DECL_SOURCE_LOCATION (decl),
-		       VAR_DECL, get_emutls_object_name (name),
-		       get_emutls_object_type ());
-
-      h = ggc_alloc_tree_map ();
-      h->hash = in.hash;
-      h->base.from = decl;
-      h->to = to;
-      *(struct tree_map **) loc = h;
-
-      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))
-	make_decl_one_only (to, DECL_ASSEMBLER_NAME (to));
-      DECL_CONTEXT (to) = DECL_CONTEXT (decl);
-      if (targetm.emutls.var_align_fixed)
-	/* If we're not allowed to change the proxy object's
-	   alignment, pretend it's been set by the user.  */
-	DECL_USER_ALIGN (to) = 1;
-    }
-
-  /* Note that these fields may need to be updated from time to time from
-     the original decl.  Consider:
-	extern __thread int i;
-	int foo() { return i; }
-	__thread int i = 1;
-     in which I goes from external to locally defined and initialized.  */
-  DECL_DLLIMPORT_P (to) = DECL_DLLIMPORT_P (decl);
-  DECL_ATTRIBUTES (to) = targetm.merge_decl_attributes (decl, to);
-
-  TREE_STATIC (to) = TREE_STATIC (decl);
-  TREE_USED (to) = TREE_USED (decl);
-  TREE_PUBLIC (to) = TREE_PUBLIC (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);
-  
-  /* Fortran might pass this to us.  */
-  DECL_RESTRICTED_P (to) = DECL_RESTRICTED_P (decl);
-
-  return to;
-}
-
-static int
-emutls_common_1 (void **loc, void *xstmts)
-{
-  struct tree_map *h = *(struct tree_map **) loc;
-  tree 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))
-    return 1;
-
-  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 = built_in_decls[BUILT_IN_EMUTLS_REGISTER_COMMON];
-  x = build_call_expr (x, 4,
-		       build_fold_addr_expr (h->to),
-		       fold_convert (word_type_node,
-				     DECL_SIZE_UNIT (h->base.from)),
-		       build_int_cst (word_type_node,
-				      DECL_ALIGN_UNIT (h->base.from)),
-		       null_pointer_node);
-
-  append_to_statement_list (x, pstmts);
-  return 1;
-}
-
-/* Callback to finalize one emutls control variable.  */
-
-static int
-emutls_finalize_control_var (void **loc, 
-				void *unused ATTRIBUTE_UNUSED)
-{
-  struct tree_map *h = *(struct tree_map **) loc;
-  if (h != NULL) 
-    {
-      struct varpool_node *node = varpool_node (h->to);
-      /* Because varpool_finalize_decl () has side-effects,
-         only apply to un-finalized vars.  */
-      if (node && !node->finalized) 
-	varpool_finalize_decl (h->to);
-    }
-  return 1;
-}
-
-/* Finalize emutls control vars and add a static constructor if
-   required.  */
-
-void
-emutls_finish (void)
-{
-  if (emutls_htab == NULL)
-    return;
-  htab_traverse_noresize (emutls_htab, 
-			  emutls_finalize_control_var, NULL);
-
-  if (targetm.emutls.register_common)
-    {
-      tree body = NULL_TREE;
-
-      htab_traverse_noresize (emutls_htab, emutls_common_1, &body);
-      if (body == NULL_TREE)
-	return;
-
-      cgraph_build_static_cdtor ('I', body, DEFAULT_INIT_PRIORITY);
-    }
-}
-
 /* Helper routines for maintaining section_htab.  */
 
 static int
@@ -1210,11 +899,6 @@ get_variable_section (tree decl, bool prefer_noswitch_p)
 		  && ADDR_SPACE_GENERIC_P (as));
       if (DECL_THREAD_LOCAL_P (decl))
 	return tls_comm_section;
-      /* This cannot be common bss for an emulated TLS object without
-	 a register_common hook.  */
-      else if (DECL_TLS_MODEL (decl) == TLS_MODEL_EMULATED
-	       && !targetm.emutls.register_common)
-	;
       else if (TREE_PUBLIC (decl) && bss_initializer_p (decl))
 	return comm_section;
     }
@@ -2098,40 +1782,6 @@ assemble_variable_contents (tree decl, const char *name,
     }
 }
 
-/* Initialize emulated tls object TO, which refers to TLS variable
-   DECL and is initialized by PROXY.  */
-
-tree
-default_emutls_var_init (tree to, tree decl, tree proxy)
-{
-  VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, 4);
-  constructor_elt *elt;
-  tree type = TREE_TYPE (to);
-  tree field = TYPE_FIELDS (type);
-
-  elt = VEC_quick_push (constructor_elt, v, NULL);
-  elt->index = field;
-  elt->value = fold_convert (TREE_TYPE (field), DECL_SIZE_UNIT (decl));
-
-  elt = VEC_quick_push (constructor_elt, v, NULL);
-  field = DECL_CHAIN (field);
-  elt->index = field;
-  elt->value = build_int_cst (TREE_TYPE (field),
-			      DECL_ALIGN_UNIT (decl));
-
-  elt = VEC_quick_push (constructor_elt, v, NULL);
-  field = DECL_CHAIN (field);
-  elt->index = field;
-  elt->value = null_pointer_node;
-
-  elt = VEC_quick_push (constructor_elt, v, NULL);
-  field = DECL_CHAIN (field);
-  elt->index = field;
-  elt->value = proxy;
-
-  return build_constructor (type, v);
-}
-
 /* Assemble everything that is needed for a variable or function declaration.
    Not used for automatic variables, and not used for function definitions.
    Should not be called for variables of incomplete structure type.
@@ -2153,35 +1803,9 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
   /* This function is supposed to handle VARIABLES.  Ensure we have one.  */
   gcc_assert (TREE_CODE (decl) == VAR_DECL);
 
-  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;
-    }
-
+  /* Emulated TLS had better not get this far.  */
+  gcc_checking_assert (targetm.have_tls || !DECL_THREAD_LOCAL_P (decl));
+              
   last_assemble_variable_decl = 0;
 
   /* Normally no need to say anything here for external references,
@@ -5685,6 +5309,11 @@ find_decl_and_mark_needed (tree decl, tree target)
 static void
 do_assemble_alias (tree decl, tree target)
 {
+  /* Emulated TLS had better not get this var.  */
+  gcc_assert(!(!targetm.have_tls
+	       && TREE_CODE (decl) == VAR_DECL
+	       && DECL_THREAD_LOCAL_P (decl)));
+
   if (TREE_ASM_WRITTEN (decl))
     return;
 
@@ -5699,14 +5328,6 @@ do_assemble_alias (tree decl, tree target)
     {
       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);
 
@@ -5725,14 +5346,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.  */
 
@@ -6400,24 +6013,11 @@ categorize_decl_for_section (const_tree decl, int reloc)
     ret = SECCAT_RODATA;
 
   /* There are no read-only thread-local sections.  */
-  if (TREE_CODE (decl) == VAR_DECL && DECL_TLS_MODEL (decl))
+  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
     {
-      if (DECL_TLS_MODEL (decl) == TLS_MODEL_EMULATED)
-	{
-	  if (DECL_EMUTLS_VAR_P (decl))
-	    {
-	      if (targetm.emutls.var_section)
-		ret = SECCAT_EMUTLS_VAR;
-	    }
-	  else
-	    {
-	      if (targetm.emutls.tmpl_prefix)
-		ret = SECCAT_EMUTLS_TMPL;
-	    }
-	}
       /* Note that this would be *just* SECCAT_BSS, except that there's
 	 no concept of a read-only thread-local-data section.  */
-      else if (ret == SECCAT_BSS
+      if (ret == SECCAT_BSS
 	       || (flag_zero_initialized_in_bss
 		   && initializer_zerop (DECL_INITIAL (decl))))
 	ret = SECCAT_TBSS;
@@ -6511,12 +6111,6 @@ default_elf_select_section (tree decl, int reloc,
     case SECCAT_TBSS:
       sname = ".tbss";
       break;
-    case SECCAT_EMUTLS_VAR:
-      sname = targetm.emutls.var_section;
-      break;
-    case SECCAT_EMUTLS_TMPL:
-      sname = targetm.emutls.tmpl_section;
-      break;
     default:
       gcc_unreachable ();
     }
@@ -6581,12 +6175,6 @@ default_unique_section (tree decl, int reloc)
     case SECCAT_TBSS:
       prefix = one_only ? ".tb" : ".tbss";
       break;
-    case SECCAT_EMUTLS_VAR:
-      prefix = targetm.emutls.var_section;
-      break;
-    case SECCAT_EMUTLS_TMPL:
-      prefix = targetm.emutls.tmpl_section;
-      break;
     default:
       gcc_unreachable ();
     }
@@ -6697,8 +6285,7 @@ default_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
     flags |= SYMBOL_FLAG_FUNCTION;
   if (targetm.binds_local_p (decl))
     flags |= SYMBOL_FLAG_LOCAL;
-  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl)
-      && DECL_TLS_MODEL (decl) != TLS_MODEL_EMULATED)
+  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
     flags |= DECL_TLS_MODEL (decl) << SYMBOL_FLAG_TLS_SHIFT;
   else if (targetm.in_small_data_p (decl))
     flags |= SYMBOL_FLAG_SMALL;
diff --git a/gcc/varpool.c b/gcc/varpool.c
index 94c949e..dcf3518 100644
--- a/gcc/varpool.c
+++ b/gcc/varpool.c
@@ -346,17 +346,6 @@ decide_is_variable_needed (struct varpool_node *node, tree decl)
       && !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)

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

* Re: [CFT, try 8] Emulated tls rewrite
  2010-07-19 19:42 ` [CFT, try 8] " Richard Henderson
@ 2010-07-20 15:53   ` Richard Guenther
  2010-07-20 16:16     ` Richard Henderson
  0 siblings, 1 reply; 28+ messages in thread
From: Richard Guenther @ 2010-07-20 15:53 UTC (permalink / raw)
  To: Richard Henderson; +Cc: IainS, GCC Patches

On Mon, Jul 19, 2010 at 9:42 PM, Richard Henderson <rth@redhat.com> wrote:
> This should be really close to the final version.
>
> I've eliminated a couple of the hacks that remained in v7.  In particular, all of the
> GC'd data from v7 is now localized to the IPA pass.  Which means that I no longer have
> to have a hack in varpool.c to avoid a ggc_free call.  There are almost no references
> to emulated tls remaining outside tree-emutls.c.
>
> The one remaining hack is localized to one line in dwarf2out.c.  If a target arranges
> with gdb the meaning of DW_OP_form_tls_address, as vxworks apparently does, then we
> need some way to associate the original TLS variable with its control variable.  I
> accomplish this by storing the control variable in DECL_VALUE_EXPR.
>
> At first this sounds gross, but I had already been storing a non-null value in
> DECL_VALUE_EXPR as a way to indicate to generic verify code that TLS variables should
> no longer appear in gimple code.  To a greater or lesser extent DECL_VALUE_EXPR is
> also a way to communicate a complicated storage location for a DECL with the debug
> output routines.  The only difference here is that I don't store the entire call
> expression and dereference as well.  Given that we're already special-casing TLS
> variables, this doesn't seem so bad after all.

Some functions in the new pass lack function comments.

+  /* For normal statements, we let update_stmt do its job.  But for phi
+     nodes, we have to manipulate the immediate use list by hand.  */
+  if (wi.changed)
+    {
+      gcc_assert (TREE_CODE (pd->def) == SSA_NAME);
+      link_imm_use_stmt (&pd->imm_use, pd->def, phi);
+    }

if you can use SET_USE here it will do the immediate-use handling
for you.  Might not be very convenient here, so probably the above
is ok.

+      /* If the block is empty, of course we use it.  */
+      gsi = gsi_last_bb (src);
+      if (gsi_end_p (gsi))
+	goto return_pred;

it looks like this might cause -g vs. -g0 issues, so better use
gsi_last_nondebug_bb here.

Which makes me wonder how we lower emultls accesses inside
debug stmts?

Otherwise the patch looks good to me.

Thanks,
Richard.

>
> r~
>

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

* Re: [CFT, try 8] Emulated tls rewrite
  2010-07-20 15:53   ` Richard Guenther
@ 2010-07-20 16:16     ` Richard Henderson
  2010-07-21  8:24       ` Richard Guenther
  0 siblings, 1 reply; 28+ messages in thread
From: Richard Henderson @ 2010-07-20 16:16 UTC (permalink / raw)
  To: Richard Guenther; +Cc: IainS, GCC Patches, Jakub Jelinek, jh

On 07/20/2010 08:53 AM, Richard Guenther wrote:
> +  /* For normal statements, we let update_stmt do its job.  But for phi
> +     nodes, we have to manipulate the immediate use list by hand.  */
> +  if (wi.changed)
> +    {
> +      gcc_assert (TREE_CODE (pd->def) == SSA_NAME);
> +      link_imm_use_stmt (&pd->imm_use, pd->def, phi);
> +    }
> 
> if you can use SET_USE here it will do the immediate-use handling
> for you.  Might not be very convenient here, so probably the above
> is ok.

Yeah, I looked at that after you mentioned it the other day,
but since I already pulled out the phi_arg_t to make the 
scanning a bit easier it's just as easy to go ahead with
the one line to perform the link here.

> 
> +      /* If the block is empty, of course we use it.  */
> +      gsi = gsi_last_bb (src);
> +      if (gsi_end_p (gsi))
> +	goto return_pred;
> 
> it looks like this might cause -g vs. -g0 issues, so better use
> gsi_last_nondebug_bb here.

[Sanity check here, Jakub:]

I don't *think* this is necessary.  The reason for that check
is to avoid a null-pointer dereference in the immediately
following gsi_stmt.  At which point a debug stmt should not
be stmt_ends_bb_p and we also accept the predecessor block.

But in any case if we made the change here, we also have to
change gimple_find_edge_insert_loc.  The functions really do
have to match.

<rant>

Which brings me to a point of irritation.  Why do cgraph edges
have to duplicate something as complex as the frequency?  Why
can't we get the edge frequency from the basic block?

My problem here is that when I create the call stmt I have all
of the data handy to create the cgraph edge.  What I do not
have is the location at which the call stmt will be inserted.
In the case of insertting on an edge, the block will be created
later by gsi_commit_edge_inserts.  So instead I have to guess
what gsi_commit_edge_inserts is going to do and guess what
frequency the chosen block will have.

My problem is that I have to duplicate code from gsi_commit_edge_inserts
one way or the other.  Either the duplication above, or I have to
split the edges myself ahead of time (possibly unnecessarily, since
I don't yet know that there is something that needs insertting).

</rant>

> Which makes me wonder how we lower emultls accesses inside
> debug stmts?

Debug stmts track registers; TLS variables live in static memory.


r~

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

* Re: [CFT, try 8] Emulated tls rewrite
  2010-07-20 16:16     ` Richard Henderson
@ 2010-07-21  8:24       ` Richard Guenther
  2010-07-21 17:11         ` Richard Henderson
  0 siblings, 1 reply; 28+ messages in thread
From: Richard Guenther @ 2010-07-21  8:24 UTC (permalink / raw)
  To: Richard Henderson; +Cc: IainS, GCC Patches, Jakub Jelinek, jh

On Tue, Jul 20, 2010 at 6:16 PM, Richard Henderson <rth@redhat.com> wrote:
> On 07/20/2010 08:53 AM, Richard Guenther wrote:
>> +  /* For normal statements, we let update_stmt do its job.  But for phi
>> +     nodes, we have to manipulate the immediate use list by hand.  */
>> +  if (wi.changed)
>> +    {
>> +      gcc_assert (TREE_CODE (pd->def) == SSA_NAME);
>> +      link_imm_use_stmt (&pd->imm_use, pd->def, phi);
>> +    }
>>
>> if you can use SET_USE here it will do the immediate-use handling
>> for you.  Might not be very convenient here, so probably the above
>> is ok.
>
> Yeah, I looked at that after you mentioned it the other day,
> but since I already pulled out the phi_arg_t to make the
> scanning a bit easier it's just as easy to go ahead with
> the one line to perform the link here.
>
>>
>> +      /* If the block is empty, of course we use it.  */
>> +      gsi = gsi_last_bb (src);
>> +      if (gsi_end_p (gsi))
>> +     goto return_pred;
>>
>> it looks like this might cause -g vs. -g0 issues, so better use
>> gsi_last_nondebug_bb here.
>
> [Sanity check here, Jakub:]
>
> I don't *think* this is necessary.  The reason for that check
> is to avoid a null-pointer dereference in the immediately
> following gsi_stmt.  At which point a debug stmt should not
> be stmt_ends_bb_p and we also accept the predecessor block.
>
> But in any case if we made the change here, we also have to
> change gimple_find_edge_insert_loc.  The functions really do
> have to match.
>
> <rant>
>
> Which brings me to a point of irritation.  Why do cgraph edges
> have to duplicate something as complex as the frequency?  Why
> can't we get the edge frequency from the basic block?

Because we need the frequencies during WPA stage where we
do not have basic-blocks.

> My problem here is that when I create the call stmt I have all
> of the data handy to create the cgraph edge.  What I do not
> have is the location at which the call stmt will be inserted.
> In the case of insertting on an edge, the block will be created
> later by gsi_commit_edge_inserts.  So instead I have to guess
> what gsi_commit_edge_inserts is going to do and guess what
> frequency the chosen block will have.

Couldn't you do gsi_insert_on_edge_immediate?  Btw, edge
frequencies for calls that call to external functions are not used
for anything I think.

> My problem is that I have to duplicate code from gsi_commit_edge_inserts
> one way or the other.  Either the duplication above, or I have to
> split the edges myself ahead of time (possibly unnecessarily, since
> I don't yet know that there is something that needs insertting).
>
> </rant>
>
>> Which makes me wonder how we lower emultls accesses inside
>> debug stmts?
>
> Debug stmts track registers; TLS variables live in static memory.

Oh, indeed.

Richard.

>
> r~
>

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

* Re: [CFT, try 8] Emulated tls rewrite
  2010-07-21  8:24       ` Richard Guenther
@ 2010-07-21 17:11         ` Richard Henderson
  2010-07-21 19:38           ` [CFT, try 9] " Richard Henderson
  0 siblings, 1 reply; 28+ messages in thread
From: Richard Henderson @ 2010-07-21 17:11 UTC (permalink / raw)
  To: Richard Guenther; +Cc: IainS, GCC Patches, Jakub Jelinek, jh

On 07/21/2010 01:23 AM, Richard Guenther wrote:
> Couldn't you do gsi_insert_on_edge_immediate?

I could.  It doesn't really help though, since the location at which
the call statement and the call edge are created is shared between
the normal statements and the phi statements.  It gets ugly either way.

> Btw, edge
> frequencies for calls that call to external functions are not used
> for anything I think.

Tell that to verify_cgraph.


r~

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

* [CFT, try 9] Emulated tls rewrite
  2010-07-21 17:11         ` Richard Henderson
@ 2010-07-21 19:38           ` Richard Henderson
  2010-07-21 19:44             ` Jakub Jelinek
  2010-07-22  2:32             ` Jack Howarth
  0 siblings, 2 replies; 28+ messages in thread
From: Richard Henderson @ 2010-07-21 19:38 UTC (permalink / raw)
  To: Richard Guenther; +Cc: IainS, GCC Patches, Jakub Jelinek, jh

On 07/21/2010 09:32 AM, Richard Henderson wrote:
> On 07/21/2010 01:23 AM, Richard Guenther wrote:
>> Couldn't you do gsi_insert_on_edge_immediate?
> 
> I could.  It doesn't really help though, since the location at which
> the call statement and the call edge are created is shared between
> the normal statements and the phi statements.  It gets ugly either way.

As discussed on IRC, what do you think of this incremental patch?

I've tested it on tls.exp and see no failures.  I'll start a proper
bootstrap and test in a moment to see that there are no other 
unexpected consequences.



r~


diff --git a/gcc/gimple-iterator.c b/gcc/gimple-iterator.c
index 1402c0d..291e4d9 100644
--- a/gcc/gimple-iterator.c
+++ b/gcc/gimple-iterator.c
@@ -65,6 +65,25 @@ update_bb_for_stmts (gimple_seq_node first, basic_block bb)
     gimple_set_bb (n->stmt, bb);
 }
 
+/* Set the frequencies for the cgraph_edges for each of the calls
+   starting at FIRST for their new position within BB.  */
+
+static void
+update_call_edge_frequencies (gimple_seq_node first, basic_block bb)
+{
+  int bb_freq = compute_call_stmt_bb_frequency (current_function_decl, bb);
+  struct cgraph_node *cfun_node = cgraph_node (current_function_decl);
+  gimple_seq_node n;
+
+  for (n = first; n ; n = n->next)
+    if (is_gimple_call (n->stmt))
+      {
+	struct cgraph_edge *e = cgraph_edge (cfun_node, n->stmt);
+	if (e != NULL)
+	  e->frequency = bb_freq;
+      }
+}
+
 
 /* Insert the sequence delimited by nodes FIRST and LAST before
    iterator I.  M specifies how to update iterator I after insertion
@@ -696,11 +715,19 @@ basic_block
 gsi_insert_on_edge_immediate (edge e, gimple stmt)
 {
   gimple_stmt_iterator gsi;
+  struct gimple_seq_node_d node;
   basic_block new_bb = NULL;
+  bool ins_after;
 
   gcc_assert (!PENDING_STMT (e));
 
-  if (gimple_find_edge_insert_loc (e, &gsi, &new_bb))
+  ins_after = gimple_find_edge_insert_loc (e, &gsi, &new_bb);
+
+  node.stmt = stmt;
+  node.prev = node.next = NULL;
+  update_call_edge_frequencies (&node, gsi.bb);
+
+  if (ins_after)
     gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
   else
     gsi_insert_before (&gsi, stmt, GSI_NEW_STMT);
@@ -716,10 +743,14 @@ gsi_insert_seq_on_edge_immediate (edge e, gimple_seq stmts)
 {
   gimple_stmt_iterator gsi;
   basic_block new_bb = NULL;
+  bool ins_after;
 
   gcc_assert (!PENDING_STMT (e));
 
-  if (gimple_find_edge_insert_loc (e, &gsi, &new_bb))
+  ins_after = gimple_find_edge_insert_loc (e, &gsi, &new_bb);
+  update_call_edge_frequencies (gimple_seq_first (stmts), gsi.bb);
+
+  if (ins_after)
     gsi_insert_seq_after (&gsi, stmts, GSI_NEW_STMT);
   else
     gsi_insert_seq_before (&gsi, stmts, GSI_NEW_STMT);
@@ -744,7 +775,6 @@ gsi_commit_edge_inserts (void)
       gsi_commit_one_edge_insert (e, NULL);
 }
 
-
 /* Commit insertions pending at edge E. If a new block is created, set NEW_BB
    to this block, otherwise set it to NULL.  */
 
@@ -758,10 +788,14 @@ gsi_commit_one_edge_insert (edge e, basic_block *new_bb)
     {
       gimple_stmt_iterator gsi;
       gimple_seq seq = PENDING_STMT (e);
+      bool ins_after;
 
       PENDING_STMT (e) = NULL;
 
-      if (gimple_find_edge_insert_loc (e, &gsi, new_bb))
+      ins_after = gimple_find_edge_insert_loc (e, &gsi, new_bb);
+      update_call_edge_frequencies (gimple_seq_first (seq), gsi.bb);
+
+      if (ins_after)
 	gsi_insert_seq_after (&gsi, seq, GSI_NEW_STMT);
       else
 	gsi_insert_seq_before (&gsi, seq, GSI_NEW_STMT);
diff --git a/gcc/tree-emutls.c b/gcc/tree-emutls.c
index 8b7c7d8..17f97be 100644
--- a/gcc/tree-emutls.c
+++ b/gcc/tree-emutls.c
@@ -596,61 +596,6 @@ clear_access_vars (void)
           VEC_length (tree, access_vars) * sizeof(tree));
 }
 
-/* Compute the frequency of instructions to be insertted on an edge E.
-
-   Mirror a portion of the logic from gimple_find_edge_insert_loc to
-   do this.  Determine if statements inserted on E will be insertted
-   into the predecessor block.  We must choose the correct block,
-   and thus frequency, in order to pass verify_cgraph.  */
-
-static int
-compute_edge_bb_frequency (edge e)
-{
-  basic_block src = e->src;
-
-  /* If the destination has one predecessor and no PHI nodes, insert
-     there... Except that we *know* it has PHI nodes or else there's
-     nothing for us to do.  Skip this step.  */
-
-  /* If the source has one successor, the edge is not abnormal and the
-     last statement does not end a basic block, insert there.  */
-  if ((e->flags & EDGE_ABNORMAL) == 0
-      && src != ENTRY_BLOCK_PTR
-      && single_succ_p (src))
-    {
-      gimple_stmt_iterator gsi;
-      gimple last;
-
-      /* If the block is empty, of course we use it.  */
-      gsi = gsi_last_bb (src);
-      if (gsi_end_p (gsi))
-	goto return_pred;
-
-      /* If the last stmt does not end the block, we insert after.  */
-      last = gsi_stmt (gsi);
-      if (!stmt_ends_bb_p (last))
-	goto return_pred;
-
-      /* If the last stmt is a trivial control, we insert before.  */
-      switch (gimple_code (last))
-	{
-	case GIMPLE_RETURN:
-	case GIMPLE_RESX:
-	  goto return_pred;
-	default:
-	  break;
-	}
-    }
-
-  /* We will be splitting the edge and insertting there.  */
-  return EDGE_FREQUENCY (e);
-
-  /* If we get here, we will not be splitting the edge and instead
-     insertting any code into the predecessor block.  */
- return_pred:
-  return compute_call_stmt_bb_frequency (current_function_decl, e->src);
-}
-
 /* Lower the entire function NODE.  */
 
 static void
@@ -677,13 +622,15 @@ lower_emutls_function_body (struct cgraph_node *node)
 	 PHI argument for that edge.  */
       if (!gimple_seq_empty_p (phi_nodes (d.bb)))
 	{
+	  /* The calls will be inserted on the edges, and the frequencies
+	     will be computed during the commit process.  */
+	  d.bb_freq = 0;
+
 	  nedge = EDGE_COUNT (d.bb->preds);
 	  for (i = 0; i < nedge; ++i)
 	    {
 	      edge e = EDGE_PRED (d.bb, i);
 
-	      d.bb_freq = compute_edge_bb_frequency (e);
-
 	      /* We can re-use any SSA_NAME created on this edge.  */
 	      clear_access_vars ();
 	      d.seq = NULL;

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

* Re: [CFT, try 9] Emulated tls rewrite
  2010-07-21 19:38           ` [CFT, try 9] " Richard Henderson
@ 2010-07-21 19:44             ` Jakub Jelinek
  2010-07-21 19:54               ` Richard Henderson
  2010-07-22  2:32             ` Jack Howarth
  1 sibling, 1 reply; 28+ messages in thread
From: Jakub Jelinek @ 2010-07-21 19:44 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Richard Guenther, IainS, GCC Patches, jh

On Wed, Jul 21, 2010 at 12:38:30PM -0700, Richard Henderson wrote:
> On 07/21/2010 09:32 AM, Richard Henderson wrote:
> > On 07/21/2010 01:23 AM, Richard Guenther wrote:
> >> Couldn't you do gsi_insert_on_edge_immediate?
> > 
> > I could.  It doesn't really help though, since the location at which
> > the call statement and the call edge are created is shared between
> > the normal statements and the phi statements.  It gets ugly either way.
> 
> As discussed on IRC, what do you think of this incremental patch?
> 
> I've tested it on tls.exp and see no failures.  I'll start a proper
> bootstrap and test in a moment to see that there are no other 
> unexpected consequences.

> --- a/gcc/gimple-iterator.c
> +++ b/gcc/gimple-iterator.c
> @@ -65,6 +65,25 @@ update_bb_for_stmts (gimple_seq_node first, basic_block bb)
>      gimple_set_bb (n->stmt, bb);
>  }
>  
> +/* Set the frequencies for the cgraph_edges for each of the calls
> +   starting at FIRST for their new position within BB.  */
> +
> +static void
> +update_call_edge_frequencies (gimple_seq_node first, basic_block bb)
> +{
> +  int bb_freq = compute_call_stmt_bb_frequency (current_function_decl, bb);
> +  struct cgraph_node *cfun_node = cgraph_node (current_function_decl);

Aren't the above two calls expensive enough that it would be better to
only call them after seeing first is_gimple_call?
Many bbs don't contain any calls...

> +  gimple_seq_node n;
> +
> +  for (n = first; n ; n = n->next)
> +    if (is_gimple_call (n->stmt))
> +      {
> +	struct cgraph_edge *e = cgraph_edge (cfun_node, n->stmt);
> +	if (e != NULL)
> +	  e->frequency = bb_freq;
> +      }
> +}
> +

	Jakub

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

* Re: [CFT, try 9] Emulated tls rewrite
  2010-07-21 19:44             ` Jakub Jelinek
@ 2010-07-21 19:54               ` Richard Henderson
  0 siblings, 0 replies; 28+ messages in thread
From: Richard Henderson @ 2010-07-21 19:54 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Richard Guenther, IainS, GCC Patches, jh

On 07/21/2010 12:46 PM, Jakub Jelinek wrote:
>> +  int bb_freq = compute_call_stmt_bb_frequency (current_function_decl, bb);
>> +  struct cgraph_node *cfun_node = cgraph_node (current_function_decl);
> 
> Aren't the above two calls expensive enough that it would be better to
> only call them after seeing first is_gimple_call?
> Many bbs don't contain any calls...

You're probably right.  Consider the patch adjusted.


r~

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

* Re: [CFT, try 9] Emulated tls rewrite
  2010-07-21 19:38           ` [CFT, try 9] " Richard Henderson
  2010-07-21 19:44             ` Jakub Jelinek
@ 2010-07-22  2:32             ` Jack Howarth
  2010-07-22 10:13               ` IainS
                                 ` (2 more replies)
  1 sibling, 3 replies; 28+ messages in thread
From: Jack Howarth @ 2010-07-22  2:32 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Richard Guenther, IainS, GCC Patches, Jakub Jelinek, jh

On Wed, Jul 21, 2010 at 12:38:30PM -0700, Richard Henderson wrote:
> On 07/21/2010 09:32 AM, Richard Henderson wrote:
> > On 07/21/2010 01:23 AM, Richard Guenther wrote:
> >> Couldn't you do gsi_insert_on_edge_immediate?
> > 
> > I could.  It doesn't really help though, since the location@which
> > the call statement and the call edge are created is shared between
> > the normal statements and the phi statements.  It gets ugly either way.
> 
> As discussed on IRC, what do you think of this incremental patch?
> 
> I've tested it on tls.exp and see no failures.  I'll start a proper
> bootstrap and test in a moment to see that there are no other 
> unexpected consequences.
> 
> 
> 
> r~
> 

Richard,
   I am still seeing one additional failure in the gfortran testsuite
(with the expanded tls test set) under your emutls patch that wasn't
present with Iain's original version. For the gfortran.dg/gomp/appendix-a/a.22.6.f90
testcase with...

! { dg-require-effective-target tls }

I get the failure...

Executing on host: /sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/gcc/testsuite/gfortran/../../gfortran -B/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/gcc/testsuite/gfortran/../../ /sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100721/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90   -O   -fopenmp -S  -o a.22.6.s    (timeout = 300)
/sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100721/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90:4:0: sorry, unimplemented: thread-local COMMON data not implemented^M
compiler exited with status 1
output is:
/sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100721/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90:4:0: sorry, unimplemented: thread-local COMMON data not implemented^M

FAIL: gfortran.dg/gomp/appendix-a/a.22.6.f90  -O  (test for excess errors)
Excess errors:
/sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100721/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90:4:0: sorry, unimplemented: thread-local COMMON data not implemented


Any idea why your version (with the emutls code as a pass) fails gfortran.dg/gomp/appendix-a/a.22.6.f90
and Iain's version didn't?
        Jack

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

* Re: [CFT, try 9] Emulated tls rewrite
  2010-07-22  2:32             ` Jack Howarth
@ 2010-07-22 10:13               ` IainS
  2010-07-22 16:15                 ` Jack Howarth
  2010-07-22 16:13               ` Richard Henderson
  2010-07-23 23:12               ` [RFA, Fortran, try 11] " Richard Henderson
  2 siblings, 1 reply; 28+ messages in thread
From: IainS @ 2010-07-22 10:13 UTC (permalink / raw)
  To: Jack Howarth; +Cc: Richard Henderson, GCC Patches

Hi Jack, Richard,

On 22 Jul 2010, at 03:32, Jack Howarth wrote:
>   I am still seeing one additional failure in the gfortran testsuite
> (with the expanded tls test set) under your emutls patch

8b or...
... 8b + http://gcc.gnu.org/ml/gcc-patches/2010-07/msg01671.html ?

> Executing on host: /sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/ 
> gcc/testsuite/gfortran/../../gfortran -B/sw/src/fink.build/ 
> gcc46-4.6.0-1000/darwin_objdir/gcc/testsuite/gfortran/../../ /sw/src/ 
> fink.build/gcc46-4.6.0-1000/gcc-4.6-20100721/gcc/testsuite/ 
> gfortran.dg/gomp/appendix-a/a.22.6.f90   -O   -fopenmp -S  -o a. 
> 22.6.s    (timeout = 300)
> /sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100721/gcc/testsuite/ 
> gfortran.dg/gomp/appendix-a/a.22.6.f90:4:0: sorry, unimplemented:  
> thread-local COMMON data not implemented^M

I do _not_ see this on either i686-darwin9 or x86_64-darwin10

with r162403 + emutls-8b.

.. . sorry, I haven't tried the increment, been busy with bootstrap  
issues..
...  (although the increment  looks to be still in flux)..

Iain

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

* Re: [CFT, try 9] Emulated tls rewrite
  2010-07-22  2:32             ` Jack Howarth
  2010-07-22 10:13               ` IainS
@ 2010-07-22 16:13               ` Richard Henderson
  2010-07-23 23:12               ` [RFA, Fortran, try 11] " Richard Henderson
  2 siblings, 0 replies; 28+ messages in thread
From: Richard Henderson @ 2010-07-22 16:13 UTC (permalink / raw)
  To: Jack Howarth; +Cc: Richard Guenther, IainS, GCC Patches, Jakub Jelinek, jh

On 07/21/2010 07:32 PM, Jack Howarth wrote:
> /sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100721/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90:4:0:
> sorry, unimplemented: thread-local COMMON data not implemented
> 
> Any idea why your version (with the emutls code as a pass) fails
> gfortran.dg/gomp/appendix-a/a.22.6.f90 and Iain's version didn't?

I have absolutely no idea how you can get that message.

Suppose that a TLS variable did slip past the IPA pass and didn't get
lowered.  Then you *should* have failed the gcc_checking_assert right
at the top of assemble_variable.



r~

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

* Re: [CFT, try 9] Emulated tls rewrite
  2010-07-22 10:13               ` IainS
@ 2010-07-22 16:15                 ` Jack Howarth
  0 siblings, 0 replies; 28+ messages in thread
From: Jack Howarth @ 2010-07-22 16:15 UTC (permalink / raw)
  To: IainS; +Cc: Richard Henderson, GCC Patches

On Thu, Jul 22, 2010 at 11:12:53AM +0100, IainS wrote:
> Hi Jack, Richard,
>
> On 22 Jul 2010, at 03:32, Jack Howarth wrote:
>>   I am still seeing one additional failure in the gfortran testsuite
>> (with the expanded tls test set) under your emutls patch
>
> 8b or...
> ... 8b + http://gcc.gnu.org/ml/gcc-patches/2010-07/msg01671.html ?
>
>> Executing on host: /sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/ 
>> gcc/testsuite/gfortran/../../gfortran -B/sw/src/fink.build/ 
>> gcc46-4.6.0-1000/darwin_objdir/gcc/testsuite/gfortran/../../ /sw/src/ 
>> fink.build/gcc46-4.6.0-1000/gcc-4.6-20100721/gcc/testsuite/ 
>> gfortran.dg/gomp/appendix-a/a.22.6.f90   -O   -fopenmp -S  -o a.22.6.s  
>>   (timeout = 300)
>> /sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100721/gcc/testsuite/ 
>> gfortran.dg/gomp/appendix-a/a.22.6.f90:4:0: sorry, unimplemented:  
>> thread-local COMMON data not implemented^M
>
> I do _not_ see this on either i686-darwin9 or x86_64-darwin10

Iain,
   Apparently this must have been fixed with http://gcc.gnu.org/ml/gcc-patches/2010-07/msg01671.html.
I don't see the problem with that and http://gcc.gnu.org/ml/gcc-patches/2010-07/msg01528.html
applied to r162414 on x86_64-apple-darwin10.
                     Jack
>
> with r162403 + emutls-8b.
>
> .. . sorry, I haven't tried the increment, been busy with bootstrap  
> issues..
> ...  (although the increment  looks to be still in flux)..
>
> Iain

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

* [RFA, Fortran, try 11] Emulated tls rewrite
  2010-07-22  2:32             ` Jack Howarth
  2010-07-22 10:13               ` IainS
  2010-07-22 16:13               ` Richard Henderson
@ 2010-07-23 23:12               ` Richard Henderson
  2010-07-24  9:54                 ` Jan Hubicka
  2010-07-26 23:09                 ` Richard Henderson
  2 siblings, 2 replies; 28+ messages in thread
From: Richard Henderson @ 2010-07-23 23:12 UTC (permalink / raw)
  To: Jack Howarth; +Cc: Richard Guenther, IainS, GCC Patches, Jakub Jelinek, jh

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

On 07/21/2010 07:32 PM, Jack Howarth wrote:
> FAIL: gfortran.dg/gomp/appendix-a/a.22.6.f90  -O  (test for excess errors)
> Excess errors:
> .../testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90:4:0: sorry, unimplemented: thread-local COMMON data not implemented

I managed to reproduce this problem reliably.  It has to do with the Fortran
front end (indirectly) invoking varpool_finalize_decl much later than the C
front ends do.  Without the decls being finalized, the IPA pass doesn't get
to see them and they don't get lowered.

I talked to Richi about this ordering problem on IRC, and changing the 
generic ordering of decls vs compilation unit finalization appears to run
into problems with C++ and Java and their aliases.  An acceptable solution
appears to be to hack the Fortran front end to do it by hand.

An incremental diff, excluding the testsuite, from #9 is below and the
full patch from HEAD is attached.

Ok?


r~



diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c
index 5b67621..9d0bf44 100644
--- a/gcc/fortran/f95-lang.c
+++ b/gcc/fortran/f95-lang.c
@@ -88,6 +88,7 @@ static void gfc_init_builtin_functions (void);
 /* Each front end provides its own.  */
 static bool gfc_init (void);
 static void gfc_finish (void);
+static void gfc_write_global_declarations (void);
 static void gfc_print_identifier (FILE *, tree, int);
 void do_function_end (void);
 int global_bindings_p (void);
@@ -99,6 +100,7 @@ static void gfc_init_ts (void);
 #undef LANG_HOOKS_NAME
 #undef LANG_HOOKS_INIT
 #undef LANG_HOOKS_FINISH
+#undef LANG_HOOKS_WRITE_GLOBALS
 #undef LANG_HOOKS_INIT_OPTIONS
 #undef LANG_HOOKS_HANDLE_OPTION
 #undef LANG_HOOKS_POST_OPTIONS
@@ -127,6 +129,7 @@ static void gfc_init_ts (void);
 #define LANG_HOOKS_NAME                 "GNU Fortran"
 #define LANG_HOOKS_INIT                 gfc_init
 #define LANG_HOOKS_FINISH               gfc_finish
+#define LANG_HOOKS_WRITE_GLOBALS	gfc_write_global_declarations
 #define LANG_HOOKS_INIT_OPTIONS         gfc_init_options
 #define LANG_HOOKS_HANDLE_OPTION        gfc_handle_option
 #define LANG_HOOKS_POST_OPTIONS		gfc_post_options
@@ -282,6 +285,33 @@ gfc_finish (void)
   return;
 }
 
+/* ??? This is something of a hack.
+
+   Emulated tls lowering needs to see all TLS variables before we call
+   cgraph_finalize_compilation_unit.  The C/C++ front ends manage this
+   by calling decl_rest_of_compilation on each global and static variable
+   as they are seen.  The Fortran front end waits until this hook.
+
+   A Correct solution is for cgraph_finalize_compilation_unit not to be
+   called during the WRITE_GLOBALS langhook, and have that hook only do what
+   its name suggests and write out globals.  But the C++ and Java front ends
+   have (unspecified) problems with aliases that gets in the way.  It has
+   been suggested that these problems would be solved by completing the
+   conversion to cgraph-based aliases.  */
+
+static void
+gfc_write_global_declarations (void)
+{
+  tree decl;
+
+  /* Finalize all of the globals.  */
+  for (decl = getdecls(); decl ; decl = DECL_CHAIN (decl))
+    rest_of_decl_compilation (decl, true, true);
+
+  write_global_declarations ();
+}
+
+
 static void
 gfc_print_identifier (FILE * file ATTRIBUTE_UNUSED,
 		      tree node ATTRIBUTE_UNUSED,

[-- Attachment #2: emutls-11 --]
[-- Type: text/plain, Size: 80387 bytes --]

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 22e4ee8..e4b6452 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1354,6 +1354,7 @@ OBJS-common = \
 	tree-diagnostic.o \
 	tree-dump.o \
 	tree-eh.o \
+	tree-emutls.o \
 	tree-if-conv.o \
 	tree-into-ssa.o \
 	tree-iterator.o \
@@ -3142,6 +3143,9 @@ tree-switch-conversion.o : tree-switch-conversion.c $(CONFIG_H) $(SYSTEM_H) \
 tree-complex.o : tree-complex.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
     $(TM_H) $(FLAGS_H) $(TREE_FLOW_H) $(GIMPLE_H) \
     tree-iterator.h $(TREE_PASS_H) tree-ssa-propagate.h $(DIAGNOSTIC_H)
+tree-emutls.o : tree-emutls.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
+    $(GIMPLE_H) $(TREE_PASS_H) $(TREE_FLOW_H) $(CGRAPH_H) langhooks.h \
+    $(TARGET_H) targhooks.h tree-iterator.h
 tree-vect-generic.o : tree-vect-generic.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \
     $(TM_H) $(TREE_FLOW_H) $(GIMPLE_H) tree-iterator.h $(TREE_PASS_H) \
     $(FLAGS_H) $(OPTABS_H) $(MACHMODE_H) $(EXPR_H) \
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index d9dc571..8b6fe51 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -4355,9 +4355,6 @@ x86_64_elf_select_section (tree decl, int reloc,
 	  /* We don't split these for medium model.  Place them into
 	     default sections and hope for best.  */
 	  break;
-	case SECCAT_EMUTLS_VAR:
-	case SECCAT_EMUTLS_TMPL:
-	  gcc_unreachable ();
 	}
       if (sname)
 	{
@@ -4415,12 +4412,6 @@ x86_64_elf_unique_section (tree decl, int reloc)
 	  /* We don't split these for medium model.  Place them into
 	     default sections and hope for best.  */
 	  break;
-	case SECCAT_EMUTLS_VAR:
-	  prefix = targetm.emutls.var_section;
-	  break;
-	case SECCAT_EMUTLS_TMPL:
-	  prefix = targetm.emutls.tmpl_section;
-	  break;
 	}
       if (prefix)
 	{
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 183bbd3..6abeb9c 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -15103,7 +15103,11 @@ loc_list_from_tree (tree loc, int want_address)
 	      if (!targetm.emutls.debug_form_tls_address
 		  || !(dwarf_version >= 3 || !dwarf_strict))
 		return 0;
-	      loc = emutls_decl (loc);
+	      /* We stuffed the control variable into the DECL_VALUE_EXPR
+		 to signal (via DECL_HAS_VALUE_EXPR_P) that the decl should
+		 no longer appear in gimple code.  We used the control
+		 variable in specific so that we could pick it up here.  */
+	      loc = DECL_VALUE_EXPR (loc);
 	      first_op = DW_OP_addr;
 	      second_op = DW_OP_form_tls_address;
 	    }
diff --git a/gcc/expr.c b/gcc/expr.c
index 3e5d18b..57f9eff 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -6818,19 +6818,6 @@ highest_pow2_factor_for_target (const_tree target, const_tree exp)
   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 call = build_call_expr (fn, 1, arg);
-  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
@@ -6933,18 +6920,6 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
       inner = TREE_OPERAND (exp, 0);
       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
@@ -8382,16 +8357,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 	  && (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:
diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c
index 5b67621..9d0bf44 100644
--- a/gcc/fortran/f95-lang.c
+++ b/gcc/fortran/f95-lang.c
@@ -88,6 +88,7 @@ static void gfc_init_builtin_functions (void);
 /* Each front end provides its own.  */
 static bool gfc_init (void);
 static void gfc_finish (void);
+static void gfc_write_global_declarations (void);
 static void gfc_print_identifier (FILE *, tree, int);
 void do_function_end (void);
 int global_bindings_p (void);
@@ -99,6 +100,7 @@ static void gfc_init_ts (void);
 #undef LANG_HOOKS_NAME
 #undef LANG_HOOKS_INIT
 #undef LANG_HOOKS_FINISH
+#undef LANG_HOOKS_WRITE_GLOBALS
 #undef LANG_HOOKS_INIT_OPTIONS
 #undef LANG_HOOKS_HANDLE_OPTION
 #undef LANG_HOOKS_POST_OPTIONS
@@ -127,6 +129,7 @@ static void gfc_init_ts (void);
 #define LANG_HOOKS_NAME                 "GNU Fortran"
 #define LANG_HOOKS_INIT                 gfc_init
 #define LANG_HOOKS_FINISH               gfc_finish
+#define LANG_HOOKS_WRITE_GLOBALS	gfc_write_global_declarations
 #define LANG_HOOKS_INIT_OPTIONS         gfc_init_options
 #define LANG_HOOKS_HANDLE_OPTION        gfc_handle_option
 #define LANG_HOOKS_POST_OPTIONS		gfc_post_options
@@ -282,6 +285,33 @@ gfc_finish (void)
   return;
 }
 
+/* ??? This is something of a hack.
+
+   Emulated tls lowering needs to see all TLS variables before we call
+   cgraph_finalize_compilation_unit.  The C/C++ front ends manage this
+   by calling decl_rest_of_compilation on each global and static variable
+   as they are seen.  The Fortran front end waits until this hook.
+
+   A Correct solution is for cgraph_finalize_compilation_unit not to be
+   called during the WRITE_GLOBALS langhook, and have that hook only do what
+   its name suggests and write out globals.  But the C++ and Java front ends
+   have (unspecified) problems with aliases that gets in the way.  It has
+   been suggested that these problems would be solved by completing the
+   conversion to cgraph-based aliases.  */
+
+static void
+gfc_write_global_declarations (void)
+{
+  tree decl;
+
+  /* Finalize all of the globals.  */
+  for (decl = getdecls(); decl ; decl = DECL_CHAIN (decl))
+    rest_of_decl_compilation (decl, true, true);
+
+  write_global_declarations ();
+}
+
+
 static void
 gfc_print_identifier (FILE * file ATTRIBUTE_UNUSED,
 		      tree node ATTRIBUTE_UNUSED,
diff --git a/gcc/gimple-iterator.c b/gcc/gimple-iterator.c
index 1402c0d..064b7fe 100644
--- a/gcc/gimple-iterator.c
+++ b/gcc/gimple-iterator.c
@@ -65,6 +65,35 @@ update_bb_for_stmts (gimple_seq_node first, basic_block bb)
     gimple_set_bb (n->stmt, bb);
 }
 
+/* Set the frequencies for the cgraph_edges for each of the calls
+   starting at FIRST for their new position within BB.  */
+
+static void
+update_call_edge_frequencies (gimple_seq_node first, basic_block bb)
+{
+  struct cgraph_node *cfun_node = NULL;
+  int bb_freq = 0;
+  gimple_seq_node n;
+
+  for (n = first; n ; n = n->next)
+    if (is_gimple_call (n->stmt))
+      {
+	struct cgraph_edge *e;
+
+	/* These function calls are expensive enough that we want
+	   to avoid calling them if we never see any calls.  */
+	if (cfun_node == NULL)
+	  {
+	    cfun_node = cgraph_node (current_function_decl);
+	    bb_freq = (compute_call_stmt_bb_frequency
+		       (current_function_decl, bb));
+	  }
+
+	e = cgraph_edge (cfun_node, n->stmt);
+	if (e != NULL)
+	  e->frequency = bb_freq;
+      }
+}
 
 /* Insert the sequence delimited by nodes FIRST and LAST before
    iterator I.  M specifies how to update iterator I after insertion
@@ -696,11 +725,19 @@ basic_block
 gsi_insert_on_edge_immediate (edge e, gimple stmt)
 {
   gimple_stmt_iterator gsi;
+  struct gimple_seq_node_d node;
   basic_block new_bb = NULL;
+  bool ins_after;
 
   gcc_assert (!PENDING_STMT (e));
 
-  if (gimple_find_edge_insert_loc (e, &gsi, &new_bb))
+  ins_after = gimple_find_edge_insert_loc (e, &gsi, &new_bb);
+
+  node.stmt = stmt;
+  node.prev = node.next = NULL;
+  update_call_edge_frequencies (&node, gsi.bb);
+
+  if (ins_after)
     gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
   else
     gsi_insert_before (&gsi, stmt, GSI_NEW_STMT);
@@ -716,10 +753,14 @@ gsi_insert_seq_on_edge_immediate (edge e, gimple_seq stmts)
 {
   gimple_stmt_iterator gsi;
   basic_block new_bb = NULL;
+  bool ins_after;
 
   gcc_assert (!PENDING_STMT (e));
 
-  if (gimple_find_edge_insert_loc (e, &gsi, &new_bb))
+  ins_after = gimple_find_edge_insert_loc (e, &gsi, &new_bb);
+  update_call_edge_frequencies (gimple_seq_first (stmts), gsi.bb);
+
+  if (ins_after)
     gsi_insert_seq_after (&gsi, stmts, GSI_NEW_STMT);
   else
     gsi_insert_seq_before (&gsi, stmts, GSI_NEW_STMT);
@@ -758,10 +799,14 @@ gsi_commit_one_edge_insert (edge e, basic_block *new_bb)
     {
       gimple_stmt_iterator gsi;
       gimple_seq seq = PENDING_STMT (e);
+      bool ins_after;
 
       PENDING_STMT (e) = NULL;
 
-      if (gimple_find_edge_insert_loc (e, &gsi, new_bb))
+      ins_after = gimple_find_edge_insert_loc (e, &gsi, new_bb);
+      update_call_edge_frequencies (gimple_seq_first (seq), gsi.bb);
+
+      if (ins_after)
 	gsi_insert_seq_after (&gsi, seq, GSI_NEW_STMT);
       else
 	gsi_insert_seq_before (&gsi, seq, GSI_NEW_STMT);
diff --git a/gcc/output.h b/gcc/output.h
index d1e5f24..014ca1c 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -165,9 +165,6 @@ extern void merge_weak (tree, tree);
 /* Emit any pending weak declarations.  */
 extern void weak_finish (void);
 
-/* Emit any pending emutls declarations and initializations.  */
-extern void emutls_finish (void);
-
 /* Return the default TLS model for a given variable.  */
 extern enum tls_model decl_default_tls_model (const_tree);
 
@@ -479,10 +476,7 @@ enum section_category
 
   SECCAT_BSS,
   SECCAT_SBSS,
-  SECCAT_TBSS,
-
-  SECCAT_EMUTLS_VAR,
-  SECCAT_EMUTLS_TMPL
+  SECCAT_TBSS
 };
 
 /* Information that is provided by all instances of the section type.  */
diff --git a/gcc/passes.c b/gcc/passes.c
index 72e9b5a..5a4cdc8 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -804,6 +804,7 @@ init_optimization_passes (void)
     }
   NEXT_PASS (pass_ipa_increase_alignment);
   NEXT_PASS (pass_ipa_matrix_reorg);
+  NEXT_PASS (pass_ipa_lower_emutls);
   *p = NULL;
 
   p = &all_regular_ipa_passes;
diff --git a/gcc/testsuite/g++.dg/gomp/clause-3.C b/gcc/testsuite/g++.dg/gomp/clause-3.C
index 055c189..6b3d410 100644
--- a/gcc/testsuite/g++.dg/gomp/clause-3.C
+++ b/gcc/testsuite/g++.dg/gomp/clause-3.C
@@ -1,5 +1,5 @@
 // { dg-do compile }
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 
 #define p parallel
 
diff --git a/gcc/testsuite/g++.dg/gomp/copyin-1.C b/gcc/testsuite/g++.dg/gomp/copyin-1.C
index f984d10..117f82f 100644
--- a/gcc/testsuite/g++.dg/gomp/copyin-1.C
+++ b/gcc/testsuite/g++.dg/gomp/copyin-1.C
@@ -1,5 +1,5 @@
 // { dg-do compile }
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 
 int i, j;
 
diff --git a/gcc/testsuite/g++.dg/gomp/pr35244.C b/gcc/testsuite/g++.dg/gomp/pr35244.C
index 189df1e..022f9d0 100644
--- a/gcc/testsuite/g++.dg/gomp/pr35244.C
+++ b/gcc/testsuite/g++.dg/gomp/pr35244.C
@@ -1,6 +1,6 @@
 // PR c++/35244
 // { dg-do compile }
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 // { dg-options "-fopenmp" }
 
 int v1;
diff --git a/gcc/testsuite/g++.dg/gomp/sharing-1.C b/gcc/testsuite/g++.dg/gomp/sharing-1.C
index 25626ff..83b8180 100644
--- a/gcc/testsuite/g++.dg/gomp/sharing-1.C
+++ b/gcc/testsuite/g++.dg/gomp/sharing-1.C
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 int thrglobalvar;
 #pragma omp threadprivate (thrglobalvar)
diff --git a/gcc/testsuite/g++.dg/gomp/tls-1.C b/gcc/testsuite/g++.dg/gomp/tls-1.C
index 13d2c0d..bfe62cb 100644
--- a/gcc/testsuite/g++.dg/gomp/tls-1.C
+++ b/gcc/testsuite/g++.dg/gomp/tls-1.C
@@ -1,5 +1,5 @@
 // { dg-do compile }
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 
 int tp1;
 static int tp2;
diff --git a/gcc/testsuite/g++.dg/gomp/tls-2.C b/gcc/testsuite/g++.dg/gomp/tls-2.C
index 26dbc53..80275f9 100644
--- a/gcc/testsuite/g++.dg/gomp/tls-2.C
+++ b/gcc/testsuite/g++.dg/gomp/tls-2.C
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 extern char buf[];
 #pragma omp threadprivate (buf)	/* { dg-error "has incomplete type" } */
diff --git a/gcc/testsuite/g++.dg/gomp/tls-3.C b/gcc/testsuite/g++.dg/gomp/tls-3.C
index 04f6bbe..c710b6d 100644
--- a/gcc/testsuite/g++.dg/gomp/tls-3.C
+++ b/gcc/testsuite/g++.dg/gomp/tls-3.C
@@ -1,5 +1,5 @@
 // { dg-do compile }
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 
 #define thr threadprivate
 
diff --git a/gcc/testsuite/g++.dg/gomp/tls-4.C b/gcc/testsuite/g++.dg/gomp/tls-4.C
index e4377c5..f6c039e 100644
--- a/gcc/testsuite/g++.dg/gomp/tls-4.C
+++ b/gcc/testsuite/g++.dg/gomp/tls-4.C
@@ -1,5 +1,5 @@
 // { dg-do compile }
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 
 #define thr threadprivate
 
diff --git a/gcc/testsuite/g++.dg/tls/diag-1.C b/gcc/testsuite/g++.dg/tls/diag-1.C
index beeeccb..af53871 100644
--- a/gcc/testsuite/g++.dg/tls/diag-1.C
+++ b/gcc/testsuite/g++.dg/tls/diag-1.C
@@ -1,5 +1,5 @@
 // Valid __thread specifiers.
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 
 __thread int g1;
 extern __thread int g2;
diff --git a/gcc/testsuite/g++.dg/tls/diag-2.C b/gcc/testsuite/g++.dg/tls/diag-2.C
index b48b7d7..484b188 100644
--- a/gcc/testsuite/g++.dg/tls/diag-2.C
+++ b/gcc/testsuite/g++.dg/tls/diag-2.C
@@ -1,5 +1,5 @@
 /* Invalid __thread specifiers.  */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 __thread extern int g1;		/* { dg-error "'__thread' before 'extern'" } */
 __thread static int g2;		/* { dg-error "'__thread' before 'static'" } */
diff --git a/gcc/testsuite/g++.dg/tls/diag-3.C b/gcc/testsuite/g++.dg/tls/diag-3.C
index 0a05cff..ea5158b 100644
--- a/gcc/testsuite/g++.dg/tls/diag-3.C
+++ b/gcc/testsuite/g++.dg/tls/diag-3.C
@@ -1,5 +1,5 @@
 // Report invalid extern and __thread combinations.
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 
 extern int j;		// { dg-error "previously declared here" }
 __thread int j;		// { dg-error "follows non-thread-local" }
diff --git a/gcc/testsuite/g++.dg/tls/diag-4.C b/gcc/testsuite/g++.dg/tls/diag-4.C
index 6fb9215..55e985e 100644
--- a/gcc/testsuite/g++.dg/tls/diag-4.C
+++ b/gcc/testsuite/g++.dg/tls/diag-4.C
@@ -1,5 +1,5 @@
 /* Invalid __thread specifiers.  */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 __thread typedef int g4;	/* { dg-error "multiple storage classes" } */
 
diff --git a/gcc/testsuite/g++.dg/tls/diag-5.C b/gcc/testsuite/g++.dg/tls/diag-5.C
index 5859a3d..ca92b30 100644
--- a/gcc/testsuite/g++.dg/tls/diag-5.C
+++ b/gcc/testsuite/g++.dg/tls/diag-5.C
@@ -1,5 +1,5 @@
 // PR c++/30536
 // Invalid __thread specifiers.
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 
 struct A { __thread register int i; }; // { dg-error "multiple storage classes|storage class specified" }
diff --git a/gcc/testsuite/g++.dg/tls/init-1.C b/gcc/testsuite/g++.dg/tls/init-1.C
index 91a3afe..9786712 100644
--- a/gcc/testsuite/g++.dg/tls/init-1.C
+++ b/gcc/testsuite/g++.dg/tls/init-1.C
@@ -1,5 +1,5 @@
 /* Valid initializations.  */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 __thread int i = 42;
 
diff --git a/gcc/testsuite/g++.dg/tls/init-2.C b/gcc/testsuite/g++.dg/tls/init-2.C
index b4407d3..c9f646d 100644
--- a/gcc/testsuite/g++.dg/tls/init-2.C
+++ b/gcc/testsuite/g++.dg/tls/init-2.C
@@ -1,5 +1,5 @@
 /* Invalid initializations.  */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 extern __thread int i;
 __thread int *p = &i;	/* { dg-error "dynamically initialized" } */
diff --git a/gcc/testsuite/g++.dg/tls/trivial.C b/gcc/testsuite/g++.dg/tls/trivial.C
index 6c30da7..e2b8f45 100644
--- a/gcc/testsuite/g++.dg/tls/trivial.C
+++ b/gcc/testsuite/g++.dg/tls/trivial.C
@@ -1,3 +1,3 @@
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 
 __thread int i;
diff --git a/gcc/testsuite/gcc.dg/gomp/appendix-a/a.22.1.c b/gcc/testsuite/gcc.dg/gomp/appendix-a/a.22.1.c
index 2cc1488..e358683 100644
--- a/gcc/testsuite/gcc.dg/gomp/appendix-a/a.22.1.c
+++ b/gcc/testsuite/gcc.dg/gomp/appendix-a/a.22.1.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 int counter = 0;
 #pragma omp threadprivate(counter)
diff --git a/gcc/testsuite/gcc.dg/gomp/appendix-a/a.22.2.c b/gcc/testsuite/gcc.dg/gomp/appendix-a/a.22.2.c
index 171bc20..7a6e901 100644
--- a/gcc/testsuite/gcc.dg/gomp/appendix-a/a.22.2.c
+++ b/gcc/testsuite/gcc.dg/gomp/appendix-a/a.22.2.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 int
 increment_counter_2 ()
diff --git a/gcc/testsuite/gcc.dg/gomp/appendix-a/a.24.1.c b/gcc/testsuite/gcc.dg/gomp/appendix-a/a.24.1.c
index 5662e70..9d8baa3 100644
--- a/gcc/testsuite/gcc.dg/gomp/appendix-a/a.24.1.c
+++ b/gcc/testsuite/gcc.dg/gomp/appendix-a/a.24.1.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 extern int omp_get_num_threads (void);
 int x, y, t, z[1000];
diff --git a/gcc/testsuite/gcc.dg/gomp/appendix-a/a.32.1.c b/gcc/testsuite/gcc.dg/gomp/appendix-a/a.32.1.c
index 89d841c..d2cb316 100644
--- a/gcc/testsuite/gcc.dg/gomp/appendix-a/a.32.1.c
+++ b/gcc/testsuite/gcc.dg/gomp/appendix-a/a.32.1.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 #include <stdlib.h>
 float *work;
diff --git a/gcc/testsuite/gcc.dg/gomp/appendix-a/a.33.1.c b/gcc/testsuite/gcc.dg/gomp/appendix-a/a.33.1.c
index 364a71e..99c06da 100644
--- a/gcc/testsuite/gcc.dg/gomp/appendix-a/a.33.1.c
+++ b/gcc/testsuite/gcc.dg/gomp/appendix-a/a.33.1.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 #include <stdio.h>
 float x, y;
diff --git a/gcc/testsuite/gcc.dg/gomp/clause-1.c b/gcc/testsuite/gcc.dg/gomp/clause-1.c
index cfab168..ace9738 100644
--- a/gcc/testsuite/gcc.dg/gomp/clause-1.c
+++ b/gcc/testsuite/gcc.dg/gomp/clause-1.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 #define p parallel
 
diff --git a/gcc/testsuite/gcc.dg/gomp/copyin-1.c b/gcc/testsuite/gcc.dg/gomp/copyin-1.c
index f984d10..117f82f 100644
--- a/gcc/testsuite/gcc.dg/gomp/copyin-1.c
+++ b/gcc/testsuite/gcc.dg/gomp/copyin-1.c
@@ -1,5 +1,5 @@
 // { dg-do compile }
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 
 int i, j;
 
diff --git a/gcc/testsuite/gcc.dg/gomp/pr35244.c b/gcc/testsuite/gcc.dg/gomp/pr35244.c
index aa19a18..92d6a1c 100644
--- a/gcc/testsuite/gcc.dg/gomp/pr35244.c
+++ b/gcc/testsuite/gcc.dg/gomp/pr35244.c
@@ -1,6 +1,6 @@
 /* PR c++/35244 */
 /* { dg-do compile } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 /* { dg-options "-fopenmp" } */
 
 int v1;
diff --git a/gcc/testsuite/gcc.dg/gomp/sharing-1.c b/gcc/testsuite/gcc.dg/gomp/sharing-1.c
index 6b53efe..90d389b 100644
--- a/gcc/testsuite/gcc.dg/gomp/sharing-1.c
+++ b/gcc/testsuite/gcc.dg/gomp/sharing-1.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 #include <stdlib.h>
 
diff --git a/gcc/testsuite/gcc.dg/gomp/tls-1.c b/gcc/testsuite/gcc.dg/gomp/tls-1.c
index 7a36c2d..9dc102e 100644
--- a/gcc/testsuite/gcc.dg/gomp/tls-1.c
+++ b/gcc/testsuite/gcc.dg/gomp/tls-1.c
@@ -1,5 +1,5 @@
 // { dg-do compile }
-// { dg-require-effective-target tls_native }
+// { dg-require-effective-target tls }
 
 int tp1;
 static int tp2;
diff --git a/gcc/testsuite/gcc.dg/gomp/tls-2.c b/gcc/testsuite/gcc.dg/gomp/tls-2.c
index 26dbc53..80275f9 100644
--- a/gcc/testsuite/gcc.dg/gomp/tls-2.c
+++ b/gcc/testsuite/gcc.dg/gomp/tls-2.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 extern char buf[];
 #pragma omp threadprivate (buf)	/* { dg-error "has incomplete type" } */
diff --git a/gcc/testsuite/gcc.dg/tls/emutls-2.c b/gcc/testsuite/gcc.dg/tls/emutls-2.c
new file mode 100644
index 0000000..1e26d5f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tls/emutls-2.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target tls } */
+/* { dg-options "-O2" } */
+
+/* With emulated TLS, the constructor generated during IPA
+   was not properly lowered to SSA form.  */
+
+__thread int i __attribute__((common));
diff --git a/gcc/testsuite/gcc.dg/tls/opt-1.c b/gcc/testsuite/gcc.dg/tls/opt-1.c
index f96bb67..f9399e0 100644
--- a/gcc/testsuite/gcc.dg/tls/opt-1.c
+++ b/gcc/testsuite/gcc.dg/tls/opt-1.c
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fPIC" } */
 /* { dg-options "-O2 -fPIC -mtune=i686" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 /* { dg-require-effective-target fpic } */
 
 extern __thread int thr;
diff --git a/gcc/testsuite/gcc.dg/tls/opt-13.c b/gcc/testsuite/gcc.dg/tls/opt-13.c
index aadfb28..8eea76b 100644
--- a/gcc/testsuite/gcc.dg/tls/opt-13.c
+++ b/gcc/testsuite/gcc.dg/tls/opt-13.c
@@ -1,6 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2" } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 __thread struct
 {
diff --git a/gcc/testsuite/gcc.dg/tls/opt-14.c b/gcc/testsuite/gcc.dg/tls/opt-14.c
index 2549c89..5abeace 100644
--- a/gcc/testsuite/gcc.dg/tls/opt-14.c
+++ b/gcc/testsuite/gcc.dg/tls/opt-14.c
@@ -3,7 +3,7 @@
    used.  */
 /* { dg-do assemble } */
 /* { dg-options "-O2" } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 struct __res_state
 {
diff --git a/gcc/testsuite/gcc.dg/tls/opt-15.c b/gcc/testsuite/gcc.dg/tls/opt-15.c
index bebee8a..a6cc721 100644
--- a/gcc/testsuite/gcc.dg/tls/opt-15.c
+++ b/gcc/testsuite/gcc.dg/tls/opt-15.c
@@ -3,7 +3,7 @@
 
 /* { dg-do compile } */
 /* { dg-options "-O -fPIC" } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 /* { dg-require-effective-target fpic } */
 
 extern void *memset(void *s, int c, __SIZE_TYPE__ n);
diff --git a/gcc/testsuite/gcc.dg/tls/opt-2.c b/gcc/testsuite/gcc.dg/tls/opt-2.c
index 0980fab..3ede352 100644
--- a/gcc/testsuite/gcc.dg/tls/opt-2.c
+++ b/gcc/testsuite/gcc.dg/tls/opt-2.c
@@ -5,7 +5,7 @@
 /* { dg-do link } */
 /* { dg-options "-O2 -ftls-model=initial-exec" } */
 /* { dg-options "-O2 -ftls-model=initial-exec -march=i686" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 /* { dg-require-effective-target tls_runtime  } */
 
 __thread int thr;
diff --git a/gcc/testsuite/gcc.dg/tls/opt-3.c b/gcc/testsuite/gcc.dg/tls/opt-3.c
index 61f5bdb..dd37dbc 100644
--- a/gcc/testsuite/gcc.dg/tls/opt-3.c
+++ b/gcc/testsuite/gcc.dg/tls/opt-3.c
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fpic" } */
 /* { dg-options "-O2 -fpic -mregparm=3" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 /* { dg-require-effective-target fpic } */
 
 extern __thread int i, j, k;
diff --git a/gcc/testsuite/gcc.dg/tls/opt-7.c b/gcc/testsuite/gcc.dg/tls/opt-7.c
index d3e81f4..44b900f 100644
--- a/gcc/testsuite/gcc.dg/tls/opt-7.c
+++ b/gcc/testsuite/gcc.dg/tls/opt-7.c
@@ -1,6 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fPIC" } */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 /* { dg-require-effective-target fpic } */
 
 static __thread void *baz [4] __attribute__((tls_model ("initial-exec")));
diff --git a/gcc/testsuite/gcc.dg/tls/section-1.c b/gcc/testsuite/gcc.dg/tls/section-1.c
index 1ca2ffb..4fc5066 100644
--- a/gcc/testsuite/gcc.dg/tls/section-1.c
+++ b/gcc/testsuite/gcc.dg/tls/section-1.c
@@ -1,6 +1,6 @@
 /* Verify that we get errors for trying to put TLS data in 
    sections which can't work.  */
-/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target tls } */
 
 #define A(X)	__attribute__((section(X)))
 
diff --git a/gcc/testsuite/gcc.dg/tls/thr-init-1.c b/gcc/testsuite/gcc.dg/tls/thr-init-1.c
new file mode 100644
index 0000000..de273d9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tls/thr-init-1.c
@@ -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 } */
diff --git a/gcc/testsuite/gcc.dg/tls/thr-init-2.c b/gcc/testsuite/gcc.dg/tls/thr-init-2.c
new file mode 100644
index 0000000..6d00d8c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tls/thr-init-2.c
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/tls/thr-init-1.c b/gcc/testsuite/gcc.dg/torture/tls/thr-init-1.c
new file mode 100644
index 0000000..89725c3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/tls/thr-init-1.c
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/tls/thr-init-2.c b/gcc/testsuite/gcc.dg/torture/tls/thr-init-2.c
new file mode 100644
index 0000000..9d09319
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/tls/thr-init-2.c
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/tls/tls-test.c b/gcc/testsuite/gcc.dg/torture/tls/tls-test.c
new file mode 100644
index 0000000..8a23e77
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/tls/tls-test.c
@@ -0,0 +1,52 @@
+/* { dg-do run }  */
+/* { dg-require-effective-target tls  }  */
+/* { dg-require-effective-target pthread } */
+/* { dg-options "-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;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/tls/tls.exp b/gcc/testsuite/gcc.dg/torture/tls/tls.exp
new file mode 100644
index 0000000..91c8843
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/tls/tls.exp
@@ -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
diff --git a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.1.f90 b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.1.f90
index 96b6abc..cc94b14 100644
--- a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.1.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.1.f90
@@ -1,5 +1,5 @@
 ! { dg-do compile }
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
 
       INTEGER FUNCTION INCREMENT_COUNTER()
         COMMON/A22_COMMON/COUNTER
diff --git a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.4.f90 b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.4.f90
index a272af5..2a63758 100644
--- a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.4.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.4.f90
@@ -1,5 +1,5 @@
 ! { dg-do compile }
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
 
       MODULE A22_MODULE
       COMMON /T/ A
diff --git a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.5.f90 b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.5.f90
index abd911f..6531d82 100644
--- a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.5.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.5.f90
@@ -1,5 +1,5 @@
 ! { dg-do compile }
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
 
       SUBROUTINE A22_5_WRONG()
         COMMON /T/ A
diff --git a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90 b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90
index 1d74593..0a2e6a6 100644
--- a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90
@@ -1,5 +1,5 @@
 ! { dg-do compile }
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
 
        SUBROUTINE A22_6_GOOD()
              COMMON /T/ A
diff --git a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.24.1.f90 b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.24.1.f90
index 87388e3..e5b9545 100644
--- a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.24.1.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.24.1.f90
@@ -1,5 +1,5 @@
 ! { dg-do compile }
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
 
       SUBROUTINE A24(A)
       INTEGER A
diff --git a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.32.1.f90 b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.32.1.f90
index 8bf2010..498a6d3 100644
--- a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.32.1.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.32.1.f90
@@ -1,5 +1,5 @@
 ! { dg-do compile }
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
 
       MODULE M
         REAL, POINTER, SAVE :: WORK(:)
diff --git a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.33.1.f90 b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.33.1.f90
index a161d54..05145b1 100644
--- a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.33.1.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.33.1.f90
@@ -1,5 +1,5 @@
 ! { dg-do compile }
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
 
       SUBROUTINE INIT(A,B)
       REAL A, B
diff --git a/gcc/testsuite/gfortran.dg/gomp/crayptr2.f90 b/gcc/testsuite/gfortran.dg/gomp/crayptr2.f90
index 0032080..476d7b9 100644
--- a/gcc/testsuite/gfortran.dg/gomp/crayptr2.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/crayptr2.f90
@@ -1,6 +1,6 @@
 ! { dg-do compile }
 ! { dg-options "-fopenmp -fcray-pointer" }
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
 
 module crayptr2
   integer :: e		! { dg-error "CRAY POINTEE attribute conflicts with THREADPRIVATE" }
diff --git a/gcc/testsuite/gfortran.dg/gomp/fixed-1.f b/gcc/testsuite/gfortran.dg/gomp/fixed-1.f
index 8323356..d61f2ba 100644
--- a/gcc/testsuite/gfortran.dg/gomp/fixed-1.f
+++ b/gcc/testsuite/gfortran.dg/gomp/fixed-1.f
@@ -1,6 +1,6 @@
 C PR fortran/24493
 C { dg-do compile }
-C { dg-require-effective-target tls_native }
+C { dg-require-effective-target tls }
       INTEGER I, J, K, L, M
 C$OMP THREADPRIVATE(I)
 C SOME COMMENT
diff --git a/gcc/testsuite/gfortran.dg/gomp/free-1.f90 b/gcc/testsuite/gfortran.dg/gomp/free-1.f90
index 3503389..f6f9de4 100644
--- a/gcc/testsuite/gfortran.dg/gomp/free-1.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/free-1.f90
@@ -1,4 +1,4 @@
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
 
 subroutine foo
 integer, save :: i ! Some comment
diff --git a/gcc/testsuite/gfortran.dg/gomp/omp_threadprivate1.f90 b/gcc/testsuite/gfortran.dg/gomp/omp_threadprivate1.f90
index 2380e3b..2ccf93c 100644
--- a/gcc/testsuite/gfortran.dg/gomp/omp_threadprivate1.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/omp_threadprivate1.f90
@@ -1,4 +1,4 @@
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
       module omp_threadprivate1
 	common /T/ a
       end module omp_threadprivate1
diff --git a/gcc/testsuite/gfortran.dg/gomp/omp_threadprivate2.f90 b/gcc/testsuite/gfortran.dg/gomp/omp_threadprivate2.f90
index 3112afd..cd1ab5c 100644
--- a/gcc/testsuite/gfortran.dg/gomp/omp_threadprivate2.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/omp_threadprivate2.f90
@@ -1,5 +1,5 @@
 ! { dg-do compile }
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
       subroutine bad1
 	double precision :: d	! { dg-error "isn't SAVEd" }
 !$omp threadprivate (d)
diff --git a/gcc/testsuite/gfortran.dg/gomp/reduction1.f90 b/gcc/testsuite/gfortran.dg/gomp/reduction1.f90
index 9c55d17..4912f71 100644
--- a/gcc/testsuite/gfortran.dg/gomp/reduction1.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/reduction1.f90
@@ -1,6 +1,6 @@
 ! { dg-do compile }
 ! { dg-options "-fopenmp -fmax-errors=100" }
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
 
 subroutine foo (ia1)
 integer :: i1, i2, i3
diff --git a/gcc/testsuite/gfortran.dg/gomp/sharing-1.f90 b/gcc/testsuite/gfortran.dg/gomp/sharing-1.f90
index 89bc6a8..7a107ff 100644
--- a/gcc/testsuite/gfortran.dg/gomp/sharing-1.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/sharing-1.f90
@@ -1,5 +1,5 @@
 ! { dg-do compile }
-! { dg-require-effective-target tls_native }
+! { dg-require-effective-target tls }
 
   integer :: thrpriv, thr, i, j, s, g1, g2, m
   integer, dimension (6) :: p
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 964669f..60ca5dc 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -992,11 +992,6 @@ compile_file (void)
   if (seen_error ())
     return;
 
-  /* Ensure that emulated TLS control vars are finalized and build 
-     a static constructor for them, when it is required.  */
-  if (!targetm.have_tls)
-    emutls_finish ();
-
   varpool_assemble_pending_decls ();
   finish_aliases_2 ();
 
diff --git a/gcc/tree-emutls.c b/gcc/tree-emutls.c
new file mode 100644
index 0000000..17f97be
--- /dev/null
+++ b/gcc/tree-emutls.c
@@ -0,0 +1,802 @@
+/* Lower TLS operations to emulation functions.
+   Copyright (C) 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any
+later version.
+
+GCC 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/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "tree-flow.h"
+#include "cgraph.h"
+#include "langhooks.h"
+#include "target.h"
+#include "targhooks.h"
+#include "tree-iterator.h"
+
+
+/* Whenever a target does not support thread-local storage (TLS) natively,
+   we can emulate it with some run-time support in libgcc.  This will in
+   turn rely on "keyed storage" a-la pthread_key_create; essentially all
+   thread libraries provide such functionality.
+
+   In order to coordinate with the libgcc runtime, each TLS variable is
+   described by a "control variable".  This control variable records the
+   required size, alignment, and initial value of the TLS variable for
+   instantiation at runtime.  It also stores an integer token to be used
+   by the runtime to find the address of the variable within each thread.
+
+   On the compiler side, this means that we need to replace all instances
+   of "tls_var" in the code with "*__emutls_get_addr(&control_var)".  We
+   also need to eliminate "tls_var" from the symbol table and introduce
+   "control_var".
+
+   We used to perform all of the transformations during conversion to rtl,
+   and the variable substitutions magically within assemble_variable.
+   However, this late fiddling of the symbol table conflicts with LTO and
+   whole-program compilation.  Therefore we must now make all the changes
+   to the symbol table early in the GIMPLE optimization path, before we
+   write things out to LTO intermediate files.  */
+
+/* These two vectors, once fully populated, are kept in lock-step so that
+   the index of a TLS variable equals the index of its control variable in
+   the other vector.  */
+static varpool_node_set tls_vars;
+static VEC(varpool_node_ptr, heap) *control_vars;
+
+/* For the current basic block, an SSA_NAME that has computed the address 
+   of the TLS variable at the corresponding index.  */
+static VEC(tree, heap) *access_vars;
+
+/* The type of the control structure, shared with the emutls.c runtime.  */
+static tree emutls_object_type;
+
+#if !defined (NO_DOT_IN_LABEL)
+# define EMUTLS_SEPARATOR	"."
+#elif !defined (NO_DOLLAR_IN_LABEL)
+# define EMUTLS_SEPARATOR	"$"
+#else
+# define EMUTLS_SEPARATOR	"_"
+#endif
+
+/* Create an IDENTIFIER_NODE by prefixing PREFIX to the
+   IDENTIFIER_NODE NAME's name.  */
+
+static tree
+prefix_name (const char *prefix, tree name)
+{
+  unsigned plen = strlen (prefix);
+  unsigned nlen = strlen (IDENTIFIER_POINTER (name));
+  char *toname = (char *) alloca (plen + nlen + 1);
+
+  memcpy (toname, prefix, plen);
+  memcpy (toname + plen, IDENTIFIER_POINTER (name), nlen + 1);
+
+  return get_identifier (toname);
+}
+
+/* Create an identifier for the struct __emutls_object, given an identifier
+   of the DECL_ASSEMBLY_NAME of the original object.  */
+
+static tree
+get_emutls_object_name (tree name)
+{
+  const char *prefix = (targetm.emutls.var_prefix
+			? targetm.emutls.var_prefix
+			: "__emutls_v" EMUTLS_SEPARATOR);
+  return prefix_name (prefix, name);
+}
+
+/* Create the fields of the type for the control variables.  Ordinarily
+   this must match struct __emutls_object defined in emutls.c.  However
+   this is a target hook so that VxWorks can define its own layout.  */
+
+tree
+default_emutls_var_fields (tree type, tree *name ATTRIBUTE_UNUSED)
+{
+  tree word_type_node, field, next_field;
+
+  field = build_decl (UNKNOWN_LOCATION,
+		      FIELD_DECL, get_identifier ("__templ"), ptr_type_node);
+  DECL_CONTEXT (field) = type;
+  next_field = field;
+
+  field = build_decl (UNKNOWN_LOCATION,
+		      FIELD_DECL, get_identifier ("__offset"),
+		      ptr_type_node);
+  DECL_CONTEXT (field) = type;
+  DECL_CHAIN (field) = next_field;
+  next_field = field;
+
+  word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
+  field = build_decl (UNKNOWN_LOCATION,
+		      FIELD_DECL, get_identifier ("__align"),
+		      word_type_node);
+  DECL_CONTEXT (field) = type;
+  DECL_CHAIN (field) = next_field;
+  next_field = field;
+
+  field = build_decl (UNKNOWN_LOCATION,
+		      FIELD_DECL, get_identifier ("__size"), word_type_node);
+  DECL_CONTEXT (field) = type;
+  DECL_CHAIN (field) = next_field;
+
+  return field;
+}
+
+/* Initialize emulated tls object TO, which refers to TLS variable DECL and
+   is initialized by PROXY.  As above, this is the default implementation of
+   a target hook overridden by VxWorks.  */
+
+tree
+default_emutls_var_init (tree to, tree decl, tree proxy)
+{
+  VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, 4);
+  constructor_elt *elt;
+  tree type = TREE_TYPE (to);
+  tree field = TYPE_FIELDS (type);
+
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  elt->index = field;
+  elt->value = fold_convert (TREE_TYPE (field), DECL_SIZE_UNIT (decl));
+
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  field = DECL_CHAIN (field);
+  elt->index = field;
+  elt->value = build_int_cst (TREE_TYPE (field),
+			      DECL_ALIGN_UNIT (decl));
+
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  field = DECL_CHAIN (field);
+  elt->index = field;
+  elt->value = null_pointer_node;
+
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  field = DECL_CHAIN (field);
+  elt->index = field;
+  elt->value = proxy;
+
+  return build_constructor (type, v);
+}
+
+/* Create the structure for struct __emutls_object.  This should match the
+   structure at the top of emutls.c, modulo the union there.  */
+
+static tree
+get_emutls_object_type (void)
+{
+  tree type, type_name, field;
+
+  type = emutls_object_type;
+  if (type)
+    return type;
+
+  emutls_object_type = type = lang_hooks.types.make_type (RECORD_TYPE);
+  type_name = NULL;
+  field = targetm.emutls.var_fields (type, &type_name);
+  if (!type_name)
+    type_name = get_identifier ("__emutls_object");
+  type_name = build_decl (UNKNOWN_LOCATION,
+			  TYPE_DECL, type_name, type);
+  TYPE_NAME (type) = type_name;
+  TYPE_FIELDS (type) = field;
+  layout_type (type);
+
+  return type;
+}
+
+/* Create a read-only variable like DECL, with the same DECL_INITIAL.
+   This will be used for initializing the emulated tls data area.  */
+
+static tree
+get_emutls_init_templ_addr (tree decl)
+{
+  tree name, to;
+
+  if (targetm.emutls.register_common && !DECL_INITIAL (decl)
+      && !DECL_SECTION_NAME (decl))
+    return null_pointer_node;
+
+  name = DECL_ASSEMBLER_NAME (decl);
+  if (!targetm.emutls.tmpl_prefix || targetm.emutls.tmpl_prefix[0])
+    {
+      const char *prefix = (targetm.emutls.tmpl_prefix
+			    ? targetm.emutls.tmpl_prefix
+			    : "__emutls_t" EMUTLS_SEPARATOR);
+      name = prefix_name (prefix, name);
+    }
+
+  to = build_decl (DECL_SOURCE_LOCATION (decl),
+		   VAR_DECL, name, TREE_TYPE (decl));
+  SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
+
+  DECL_ARTIFICIAL (to) = 1;
+  TREE_USED (to) = TREE_USED (decl);
+  TREE_READONLY (to) = 1;
+  DECL_IGNORED_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))
+    {
+      make_decl_one_only (to, DECL_ASSEMBLER_NAME (to));
+      TREE_STATIC (to) = TREE_STATIC (decl);
+      TREE_PUBLIC (to) = TREE_PUBLIC (decl);
+      DECL_VISIBILITY (to) = DECL_VISIBILITY (decl);
+    }
+  else
+    TREE_STATIC (to) = 1;
+
+  DECL_VISIBILITY_SPECIFIED (to) = DECL_VISIBILITY_SPECIFIED (decl);
+  DECL_INITIAL (to) = DECL_INITIAL (decl);
+  DECL_INITIAL (decl) = NULL;
+
+  if (targetm.emutls.tmpl_section)
+    {
+      DECL_SECTION_NAME (to)
+        = build_string (strlen (targetm.emutls.tmpl_section),
+			targetm.emutls.tmpl_section);
+    }
+
+  varpool_finalize_decl (to);
+  return build_fold_addr_expr (to);
+}
+
+/* Create and return the control variable for the TLS variable DECL.  */
+
+static tree
+new_emutls_decl (tree decl)
+{
+  tree name, to;
+
+  name = DECL_ASSEMBLER_NAME (decl);
+  to = build_decl (DECL_SOURCE_LOCATION (decl), VAR_DECL,
+                   get_emutls_object_name (name),
+                   get_emutls_object_type ());
+
+  SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
+
+  DECL_TLS_MODEL (to) = TLS_MODEL_EMULATED;
+  DECL_ARTIFICIAL (to) = 1;
+  DECL_IGNORED_P (to) = 1;
+  TREE_READONLY (to) = 0;
+  TREE_STATIC (to) = 1;
+
+  DECL_PRESERVE_P (to) = DECL_PRESERVE_P (decl);
+  DECL_CONTEXT (to) = DECL_CONTEXT (decl);
+  TREE_USED (to) = TREE_USED (decl);
+  TREE_PUBLIC (to) = TREE_PUBLIC (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_RESTRICTED_P (to) = DECL_RESTRICTED_P (decl);
+  DECL_DLLIMPORT_P (to) = DECL_DLLIMPORT_P (decl);
+
+  DECL_ATTRIBUTES (to) = targetm.merge_decl_attributes (decl, to);
+
+  if (DECL_ONE_ONLY (decl))
+    make_decl_one_only (to, DECL_ASSEMBLER_NAME (to));
+
+  /* If we're not allowed to change the proxy object's alignment,
+     pretend it has been set by the user.  */
+  if (targetm.emutls.var_align_fixed)
+    DECL_USER_ALIGN (to) = 1;
+
+  /* If the target wants the control variables grouped, do so.  */
+  if (!DECL_COMMON (to) && targetm.emutls.var_section)
+    {
+      DECL_SECTION_NAME (to)
+        = build_string (strlen (targetm.emutls.tmpl_section),
+			targetm.emutls.tmpl_section);
+    }
+
+  /* If this variable is defined locally, then we need to initialize the
+     control structure with size and alignment information.  Initialization
+     of COMMON block variables happens elsewhere via a constructor.  */
+  if (!DECL_EXTERNAL (to)
+      && (!DECL_COMMON (to)
+          || (DECL_INITIAL (decl)
+              && DECL_INITIAL (decl) != error_mark_node)))
+    {
+      tree tmpl = get_emutls_init_templ_addr (decl);
+      DECL_INITIAL (to) = targetm.emutls.var_init (to, decl, tmpl);
+      record_references_in_initializer (to, false);
+    }
+
+  varpool_finalize_decl (to);
+  return to;
+}
+
+/* Look up the index of the TLS variable DECL.  This index can then be
+   used in both the control_vars and access_vars arrays.  */
+
+static unsigned int
+emutls_index (tree decl)
+{
+  varpool_node_set_iterator i;
+  
+  i = varpool_node_set_find (tls_vars, varpool_get_node (decl));
+  gcc_assert (i.index != ~0u);
+
+  return i.index;
+}
+
+/* Look up the control variable for the TLS variable DECL.  */
+
+static tree
+emutls_decl (tree decl)
+{
+  struct varpool_node *var;
+  unsigned int i;
+
+  i = emutls_index (decl);
+  var = VEC_index (varpool_node_ptr, control_vars, i);
+  return var->decl;
+}
+
+/* Generate a call statement to initialize CONTROL_DECL for TLS_DECL.
+   This only needs to happen for TLS COMMON variables; non-COMMON
+   variables can be initialized statically.  Insert the generated
+   call statement at the end of PSTMTS.  */
+   
+static void
+emutls_common_1 (tree tls_decl, tree control_decl, tree *pstmts)
+{
+  tree x;
+  tree word_type_node;
+
+  if (! DECL_COMMON (tls_decl)
+      || (DECL_INITIAL (tls_decl)
+	  && DECL_INITIAL (tls_decl) != error_mark_node))
+    return;
+
+  word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
+
+  x = build_call_expr (built_in_decls[BUILT_IN_EMUTLS_REGISTER_COMMON], 4,
+		       build_fold_addr_expr (control_decl),
+		       fold_convert (word_type_node,
+				     DECL_SIZE_UNIT (tls_decl)),
+		       build_int_cst (word_type_node,
+				      DECL_ALIGN_UNIT (tls_decl)),
+		       get_emutls_init_templ_addr (tls_decl));
+
+  append_to_statement_list (x, pstmts);
+}
+
+struct lower_emutls_data
+{
+  struct cgraph_node *cfun_node;
+  struct cgraph_node *builtin_node;
+  tree builtin_decl;
+  basic_block bb;
+  int bb_freq;
+  location_t loc;
+  gimple_seq seq;
+};
+
+/* Given a TLS variable DECL, return an SSA_NAME holding its address.
+   Append any new computation statements required to D->SEQ.  */
+
+static tree
+gen_emutls_addr (tree decl, struct lower_emutls_data *d)
+{
+  unsigned int index;
+  tree addr;
+
+  /* Compute the address of the TLS variable with help from runtime.  */
+  index = emutls_index (decl);
+  addr = VEC_index (tree, access_vars, index);
+  if (addr == NULL)
+    {
+      struct varpool_node *cvar;
+      tree cdecl;
+      gimple x;
+
+      cvar = VEC_index (varpool_node_ptr, control_vars, index);
+      cdecl = cvar->decl;
+      TREE_ADDRESSABLE (cdecl) = 1;
+
+      addr = create_tmp_var (build_pointer_type (TREE_TYPE (decl)), NULL);
+      x = gimple_build_call (d->builtin_decl, 1, build_fold_addr_expr (cdecl));
+      gimple_set_location (x, d->loc);
+
+      addr = make_ssa_name (addr, x);
+      gimple_call_set_lhs (x, addr);
+
+      gimple_seq_add_stmt (&d->seq, x);
+
+      cgraph_create_edge (d->cfun_node, d->builtin_node, x,
+                          d->bb->count, d->bb_freq, d->bb->loop_depth);
+
+      /* We may be adding a new reference to a new variable to the function.
+         This means we have to play with the ipa-reference web.  */
+      ipa_record_reference (d->cfun_node, NULL, NULL, cvar, IPA_REF_ADDR, x);
+
+      /* Record this ssa_name for possible use later in the basic block.  */
+      VEC_replace (tree, access_vars, index, addr);
+    }
+
+  return addr;
+}
+
+/* Callback for walk_gimple_op.  D = WI->INFO is a struct lower_emutls_data.
+   Given an operand *PTR within D->STMT, if the operand references a TLS
+   variable, then lower the reference to a call to the runtime.  Insert
+   any new statements required into D->SEQ; the caller is responsible for
+   placing those appropriately.  */
+
+static tree
+lower_emutls_1 (tree *ptr, int *walk_subtrees, void *cb_data)
+{
+  struct walk_stmt_info *wi = (struct walk_stmt_info *) cb_data;
+  struct lower_emutls_data *d = (struct lower_emutls_data *) wi->info;
+  tree t = *ptr;
+  bool is_addr = false;
+  tree addr;
+
+  *walk_subtrees = 0;
+
+  switch (TREE_CODE (t))
+    {
+    case ADDR_EXPR:
+      /* If this is not a straight-forward "&var", but rather something
+	 like "&var.a", then we may need special handling.  */
+      if (TREE_CODE (TREE_OPERAND (t, 0)) != VAR_DECL)
+	{
+	  bool save_changed;
+
+	  /* If we're allowed more than just is_gimple_val, continue.  */
+	  if (!wi->val_only)
+	    {
+	      *walk_subtrees = 1;
+	      return NULL_TREE;
+	    }
+
+	  /* See if any substitution would be made.  */
+	  save_changed = wi->changed;
+	  wi->changed = false;
+	  wi->val_only = false;
+	  walk_tree (&TREE_OPERAND (t, 0), lower_emutls_1, wi, NULL);
+	  wi->val_only = true;
+
+	  /* If so, then extract this entire sub-expression "&p->a" into a
+	     new assignment statement, and substitute yet another SSA_NAME.  */
+	  if (wi->changed)
+	    {
+	      gimple x;
+
+	      addr = create_tmp_var (TREE_TYPE (t), NULL);
+	      x = gimple_build_assign (addr, t);
+	      gimple_set_location (x, d->loc);
+
+	      addr = make_ssa_name (addr, x);
+	      gimple_assign_set_lhs (x, addr);
+
+	      gimple_seq_add_stmt (&d->seq, x);
+
+	      *ptr = addr;
+	    }
+	  else
+	    wi->changed = save_changed;
+
+	  return NULL_TREE;
+	}
+
+      t = TREE_OPERAND (t, 0);
+      is_addr = true;
+      /* FALLTHRU */
+
+    case VAR_DECL:
+      if (!DECL_THREAD_LOCAL_P (t))
+	return NULL_TREE;
+      break;
+
+    default:
+      /* We're not interested in other decls or types, only subexpressions.  */
+      if (EXPR_P (t))
+        *walk_subtrees = 1;
+      /* FALLTHRU */
+
+    case SSA_NAME:
+      /* Special-case the return of SSA_NAME, since it's so common.  */
+      return NULL_TREE;
+    }
+
+  addr = gen_emutls_addr (t, d);
+  if (is_addr)
+    {
+      /* Replace "&var" with "addr" in the statement.  */
+      *ptr = addr;
+    }
+  else
+    {
+      /* Replace "var" with "*addr" in the statement.  */
+      t = build2 (MEM_REF, TREE_TYPE (t), addr,
+	          build_int_cst (TREE_TYPE (addr), 0));
+      *ptr = t;
+    }
+
+  wi->changed = true;
+  return NULL_TREE;
+}
+
+/* Lower all of the operands of STMT.  */
+
+static void
+lower_emutls_stmt (gimple stmt, struct lower_emutls_data *d)
+{
+  struct walk_stmt_info wi;
+
+  d->loc = gimple_location (stmt);
+
+  memset (&wi, 0, sizeof (wi));
+  wi.info = d;
+  wi.val_only = true;
+  walk_gimple_op (stmt, lower_emutls_1, &wi);
+
+  if (wi.changed)
+    update_stmt (stmt);
+}
+
+/* Lower the I'th operand of PHI.  */
+
+static void
+lower_emutls_phi_arg (gimple phi, unsigned int i, struct lower_emutls_data *d)
+{
+  struct walk_stmt_info wi;
+  struct phi_arg_d *pd = gimple_phi_arg (phi, i);
+
+  /* Early out for a very common case we don't care about.  */
+  if (TREE_CODE (pd->def) == SSA_NAME)
+    return;
+
+  d->loc = pd->locus;
+
+  memset (&wi, 0, sizeof (wi));
+  wi.info = d;
+  wi.val_only = true;
+  walk_tree (&pd->def, lower_emutls_1, &wi, NULL);
+
+  /* For normal statements, we let update_stmt do its job.  But for phi
+     nodes, we have to manipulate the immediate use list by hand.  */
+  if (wi.changed)
+    {
+      gcc_assert (TREE_CODE (pd->def) == SSA_NAME);
+      link_imm_use_stmt (&pd->imm_use, pd->def, phi);
+    }
+}
+
+/* Clear the ACCESS_VARS array, in order to begin a new block.  */
+
+static inline void
+clear_access_vars (void)
+{
+  memset (VEC_address (tree, access_vars), 0,
+          VEC_length (tree, access_vars) * sizeof(tree));
+}
+
+/* Lower the entire function NODE.  */
+
+static void
+lower_emutls_function_body (struct cgraph_node *node)
+{
+  struct lower_emutls_data d;
+  bool any_edge_inserts = false;
+
+  current_function_decl = node->decl;
+  push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+
+  d.cfun_node = node;
+  d.builtin_decl = built_in_decls[BUILT_IN_EMUTLS_GET_ADDRESS];
+  d.builtin_node = cgraph_node (d.builtin_decl);
+
+  FOR_EACH_BB (d.bb)
+    {
+      gimple_stmt_iterator gsi;
+      unsigned int i, nedge;
+
+      /* Lower each of the PHI nodes of the block, as we may have 
+	 propagated &tlsvar into a PHI argument.  These loops are
+	 arranged so that we process each edge at once, and each
+	 PHI argument for that edge.  */
+      if (!gimple_seq_empty_p (phi_nodes (d.bb)))
+	{
+	  /* The calls will be inserted on the edges, and the frequencies
+	     will be computed during the commit process.  */
+	  d.bb_freq = 0;
+
+	  nedge = EDGE_COUNT (d.bb->preds);
+	  for (i = 0; i < nedge; ++i)
+	    {
+	      edge e = EDGE_PRED (d.bb, i);
+
+	      /* We can re-use any SSA_NAME created on this edge.  */
+	      clear_access_vars ();
+	      d.seq = NULL;
+
+	      for (gsi = gsi_start_phis (d.bb);
+		   !gsi_end_p (gsi);
+		   gsi_next (&gsi))
+		lower_emutls_phi_arg (gsi_stmt (gsi), i, &d);
+
+	      /* Insert all statements generated by all phi nodes for this
+		 particular edge all at once.  */
+	      if (d.seq)
+		{
+		  gsi_insert_seq_on_edge (e, d.seq);
+		  any_edge_inserts = true;
+		}
+	    }
+	}
+
+      d.bb_freq = compute_call_stmt_bb_frequency (current_function_decl, d.bb);
+
+      /* We can re-use any SSA_NAME created during this basic block.  */
+      clear_access_vars ();
+
+      /* Lower each of the statements of the block.  */
+      for (gsi = gsi_start_bb (d.bb); !gsi_end_p (gsi); gsi_next (&gsi))
+	{
+          d.seq = NULL;
+	  lower_emutls_stmt (gsi_stmt (gsi), &d);
+
+	  /* If any new statements were created, insert them immediately
+	     before the first use.  This prevents variable lifetimes from
+	     becoming unnecessarily long.  */
+	  if (d.seq)
+	    gsi_insert_seq_before (&gsi, d.seq, GSI_SAME_STMT);
+	}
+    }
+
+  if (any_edge_inserts)
+    gsi_commit_edge_inserts ();
+
+  pop_cfun ();
+  current_function_decl = NULL;
+}
+
+/* Main entry point to the tls lowering pass.  */
+
+static unsigned int
+ipa_lower_emutls (void)
+{
+  struct varpool_node *var;
+  struct cgraph_node *func;
+  bool any_aliases = false;
+  tree ctor_body = NULL;
+  unsigned int i, n_tls;
+
+  tls_vars = varpool_node_set_new ();
+
+  /* Examine all global variables for TLS variables.  */
+  for (var = varpool_nodes; var ; var = var->next)
+    if (DECL_THREAD_LOCAL_P (var->decl))
+      {
+	gcc_checking_assert (TREE_STATIC (var->decl)
+			     || DECL_EXTERNAL (var->decl));
+	varpool_node_set_add (tls_vars, var);
+      }
+
+  /* If we found no TLS variables, then there is no further work to do.  */
+  if (tls_vars->nodes == NULL)
+    {
+      tls_vars = NULL;
+      if (dump_file)
+	fprintf (dump_file, "No TLS variables found.\n");
+      return 0;
+    }
+
+  /* Allocate the on-the-side arrays that share indicies with the TLS vars.  */
+  n_tls = VEC_length (varpool_node_ptr, tls_vars->nodes);
+  control_vars = VEC_alloc (varpool_node_ptr, heap, n_tls);
+  access_vars = VEC_alloc (tree, heap, n_tls);
+  VEC_safe_grow (tree, heap, access_vars, n_tls);
+
+  /* Create the control variables for each TLS variable.  */
+  for (i = 0; VEC_iterate (varpool_node_ptr, tls_vars->nodes, i, var); ++i)
+    {
+      tree cdecl;
+      struct varpool_node *cvar;
+
+      var = VEC_index (varpool_node_ptr, tls_vars->nodes, i);
+      cdecl = new_emutls_decl (var->decl);
+
+      cvar = varpool_get_node (cdecl);
+      VEC_quick_push (varpool_node_ptr, control_vars, cvar);
+
+      if (var->alias)
+	{
+	  any_aliases = true;
+	  cvar->alias = true;
+	}
+      else
+	{
+	  /* Make sure the COMMON block control variable gets initialized.
+	     Note that there's no point in doing this for aliases; we only
+	     need to do this once for the main variable.  */
+          emutls_common_1 (var->decl, cdecl, &ctor_body);
+	}
+
+      /* Indicate that the value of the TLS variable may be found elsewhere,
+	 preventing the variable from re-appearing in the GIMPLE.  We cheat
+	 and use the control variable here (rather than a full call_expr),
+	 which is special-cased inside the DWARF2 output routines.  */
+      SET_DECL_VALUE_EXPR (var->decl, cdecl);
+      DECL_HAS_VALUE_EXPR_P (var->decl) = 1;
+    }
+
+  /* If there were any aliases, then frob the alias_pairs vector.  */
+  if (any_aliases)
+    {
+      alias_pair *p;
+      for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ++i)
+	if (DECL_THREAD_LOCAL_P (p->decl))
+	  {
+	    p->decl = emutls_decl (p->decl);
+	    p->target = get_emutls_object_name (p->target);
+	  }
+    }
+
+  /* Adjust all uses of TLS variables within the function bodies.  */
+  for (func = cgraph_nodes; func; func = func->next)
+    if (func->reachable && func->lowered)
+      lower_emutls_function_body (func);
+
+  /* Generate the constructor for any COMMON control variables created.  */
+  if (ctor_body)
+    cgraph_build_static_cdtor ('I', ctor_body, DEFAULT_INIT_PRIORITY);
+
+  VEC_free (varpool_node_ptr, heap, control_vars);
+  VEC_free (tree, heap, access_vars);
+  tls_vars = NULL;
+
+  return TODO_dump_func | TODO_ggc_collect | TODO_verify_all;
+}
+
+/* If the target supports TLS natively, we need do nothing here.  */
+
+static bool
+gate_emutls (void)
+{
+  return !targetm.have_tls;
+}
+
+struct simple_ipa_opt_pass pass_ipa_lower_emutls =
+{
+ {
+  SIMPLE_IPA_PASS,
+  "emutls",				/* name */
+  gate_emutls,				/* gate */
+  ipa_lower_emutls,			/* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_NONE,				/* tv_id */
+  PROP_cfg | PROP_ssa,			/* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  0,					/* todo_flags_finish */
+ }
+};
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index c72d7cf..33c898e 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -446,6 +446,7 @@ extern struct gimple_opt_pass pass_warn_unused_result;
 extern struct gimple_opt_pass pass_split_functions;
 
 /* IPA Passes */
+extern struct simple_ipa_opt_pass pass_ipa_lower_emutls;
 extern struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility;
 extern struct simple_ipa_opt_pass pass_ipa_early_inline;
 
diff --git a/gcc/tree.h b/gcc/tree.h
index 3c0806e..5aa5a89 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5249,7 +5249,6 @@ extern void set_user_assembler_name (tree, const char *);
 extern void process_pending_assemble_externals (void);
 extern void finish_aliases_1 (void);
 extern void finish_aliases_2 (void);
-extern tree emutls_decl (tree);
 extern void remove_unreachable_alias_pairs (void);
 
 /* In stmt.c */
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 9a4c193..58c9a1b 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -186,317 +186,6 @@ static GTY(()) int anchor_labelno;
 /* A pool of constants that can be shared between functions.  */
 static GTY(()) struct rtx_constant_pool *shared_constant_pool;
 
-/* TLS emulation.  */
-
-static GTY ((if_marked ("tree_map_marked_p"), param_is (struct tree_map)))
-     htab_t emutls_htab;
-static GTY (()) tree emutls_object_type;
-/* Emulated TLS objects have the TLS model TLS_MODEL_EMULATED.  This
-   macro can be used on them to distinguish the control variable from
-   the initialization template.  */
-#define DECL_EMUTLS_VAR_P(D)  (TREE_TYPE (D) == emutls_object_type)
-
-#if !defined (NO_DOT_IN_LABEL)
-# define EMUTLS_SEPARATOR	"."
-#elif !defined (NO_DOLLAR_IN_LABEL)
-# define EMUTLS_SEPARATOR	"$"
-#else
-# define EMUTLS_SEPARATOR	"_"
-#endif
-
-/* Create an IDENTIFIER_NODE by prefixing PREFIX to the
-   IDENTIFIER_NODE NAME's name.  */
-
-static tree
-prefix_name (const char *prefix, tree name)
-{
-  unsigned plen = strlen (prefix);
-  unsigned nlen = strlen (IDENTIFIER_POINTER (name));
-  char *toname = (char *) alloca (plen + nlen + 1);
-
-  memcpy (toname, prefix, plen);
-  memcpy (toname + plen, IDENTIFIER_POINTER (name), nlen + 1);
-
-  return get_identifier (toname);
-}
-
-/* Create an identifier for the struct __emutls_object, given an identifier
-   of the DECL_ASSEMBLY_NAME of the original object.  */
-
-static tree
-get_emutls_object_name (tree name)
-{
-  const char *prefix = (targetm.emutls.var_prefix
-			? targetm.emutls.var_prefix
-			: "__emutls_v" EMUTLS_SEPARATOR);
-  return prefix_name (prefix, name);
-}
-
-tree
-default_emutls_var_fields (tree type, tree *name ATTRIBUTE_UNUSED)
-{
-  tree word_type_node, field, next_field;
-
-  field = build_decl (UNKNOWN_LOCATION,
-		      FIELD_DECL, get_identifier ("__templ"), ptr_type_node);
-  DECL_CONTEXT (field) = type;
-  next_field = field;
-
-  field = build_decl (UNKNOWN_LOCATION,
-		      FIELD_DECL, get_identifier ("__offset"),
-		      ptr_type_node);
-  DECL_CONTEXT (field) = type;
-  DECL_CHAIN (field) = next_field;
-  next_field = field;
-
-  word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
-  field = build_decl (UNKNOWN_LOCATION,
-		      FIELD_DECL, get_identifier ("__align"),
-		      word_type_node);
-  DECL_CONTEXT (field) = type;
-  DECL_CHAIN (field) = next_field;
-  next_field = field;
-
-  field = build_decl (UNKNOWN_LOCATION,
-		      FIELD_DECL, get_identifier ("__size"), word_type_node);
-  DECL_CONTEXT (field) = type;
-  DECL_CHAIN (field) = next_field;
-
-  return field;
-}
-
-/* Create the structure for struct __emutls_object.  This should match the
-   structure at the top of emutls.c, modulo the union there.  */
-
-static tree
-get_emutls_object_type (void)
-{
-  tree type, type_name, field;
-
-  type = emutls_object_type;
-  if (type)
-    return type;
-
-  emutls_object_type = type = lang_hooks.types.make_type (RECORD_TYPE);
-  type_name = NULL;
-  field = targetm.emutls.var_fields (type, &type_name);
-  if (!type_name)
-    type_name = get_identifier ("__emutls_object");
-  type_name = build_decl (UNKNOWN_LOCATION,
-			  TYPE_DECL, type_name, type);
-  TYPE_NAME (type) = type_name;
-  TYPE_FIELDS (type) = field;
-  layout_type (type);
-
-  return type;
-}
-
-/* Create a read-only variable like DECL, with the same DECL_INITIAL.
-   This will be used for initializing the emulated tls data area.  */
-
-static tree
-get_emutls_init_templ_addr (tree decl)
-{
-  tree name, to;
-
-  if (targetm.emutls.register_common && !DECL_INITIAL (decl)
-      && !DECL_SECTION_NAME (decl))
-    return null_pointer_node;
-
-  name = DECL_ASSEMBLER_NAME (decl);
-  if (!targetm.emutls.tmpl_prefix || targetm.emutls.tmpl_prefix[0])
-    {
-      const char *prefix = (targetm.emutls.tmpl_prefix
-			    ? targetm.emutls.tmpl_prefix
-			    : "__emutls_t" EMUTLS_SEPARATOR);
-      name = prefix_name (prefix, name);
-    }
-
-  to = build_decl (DECL_SOURCE_LOCATION (decl),
-		   VAR_DECL, name, TREE_TYPE (decl));
-  SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
-
-  DECL_ARTIFICIAL (to) = 1;
-  TREE_USED (to) = TREE_USED (decl);
-  TREE_READONLY (to) = 1;
-  DECL_IGNORED_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))
-    {
-      make_decl_one_only (to, DECL_ASSEMBLER_NAME (to));
-      TREE_STATIC (to) = TREE_STATIC (decl);
-      TREE_PUBLIC (to) = TREE_PUBLIC (decl);
-      DECL_VISIBILITY (to) = DECL_VISIBILITY (decl);
-    }
-  else
-    TREE_STATIC (to) = 1;
-
-  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);
-}
-
-/* When emulating tls, we use a control structure for use by the runtime.
-   Create and return this structure.  */
-
-tree
-emutls_decl (tree decl)
-{
-  tree name, to;
-  struct tree_map *h, in;
-  void **loc;
-
-  if (targetm.have_tls || decl == NULL || decl == error_mark_node
-      || TREE_CODE (decl) != VAR_DECL || ! DECL_THREAD_LOCAL_P (decl))
-    return decl;
-
-  /* Look up the object in the hash; return the control structure if
-     it has already been created.  */
-  if (! emutls_htab)
-    emutls_htab = htab_create_ggc (512, tree_map_hash, tree_map_eq, 0);
-
-  name = DECL_ASSEMBLER_NAME (decl);
-
-  /* Note that we use the hash of the decl's name, rather than a hash
-     of the decl's pointer.  In emutls_finish we iterate through the
-     hash table, and we want this traversal to be predictable.  */
-  in.hash = IDENTIFIER_HASH_VALUE (name);
-  in.base.from = decl;
-  loc = htab_find_slot_with_hash (emutls_htab, &in, in.hash, INSERT);
-  h = (struct tree_map *) *loc;
-  if (h != NULL)
-    to = h->to;
-  else
-    {
-      to = build_decl (DECL_SOURCE_LOCATION (decl),
-		       VAR_DECL, get_emutls_object_name (name),
-		       get_emutls_object_type ());
-
-      h = ggc_alloc_tree_map ();
-      h->hash = in.hash;
-      h->base.from = decl;
-      h->to = to;
-      *(struct tree_map **) loc = h;
-
-      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))
-	make_decl_one_only (to, DECL_ASSEMBLER_NAME (to));
-      DECL_CONTEXT (to) = DECL_CONTEXT (decl);
-      if (targetm.emutls.var_align_fixed)
-	/* If we're not allowed to change the proxy object's
-	   alignment, pretend it's been set by the user.  */
-	DECL_USER_ALIGN (to) = 1;
-    }
-
-  /* Note that these fields may need to be updated from time to time from
-     the original decl.  Consider:
-	extern __thread int i;
-	int foo() { return i; }
-	__thread int i = 1;
-     in which I goes from external to locally defined and initialized.  */
-  DECL_DLLIMPORT_P (to) = DECL_DLLIMPORT_P (decl);
-  DECL_ATTRIBUTES (to) = targetm.merge_decl_attributes (decl, to);
-
-  TREE_STATIC (to) = TREE_STATIC (decl);
-  TREE_USED (to) = TREE_USED (decl);
-  TREE_PUBLIC (to) = TREE_PUBLIC (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);
-  
-  /* Fortran might pass this to us.  */
-  DECL_RESTRICTED_P (to) = DECL_RESTRICTED_P (decl);
-
-  return to;
-}
-
-static int
-emutls_common_1 (void **loc, void *xstmts)
-{
-  struct tree_map *h = *(struct tree_map **) loc;
-  tree 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))
-    return 1;
-
-  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 = built_in_decls[BUILT_IN_EMUTLS_REGISTER_COMMON];
-  x = build_call_expr (x, 4,
-		       build_fold_addr_expr (h->to),
-		       fold_convert (word_type_node,
-				     DECL_SIZE_UNIT (h->base.from)),
-		       build_int_cst (word_type_node,
-				      DECL_ALIGN_UNIT (h->base.from)),
-		       null_pointer_node);
-
-  append_to_statement_list (x, pstmts);
-  return 1;
-}
-
-/* Callback to finalize one emutls control variable.  */
-
-static int
-emutls_finalize_control_var (void **loc, 
-				void *unused ATTRIBUTE_UNUSED)
-{
-  struct tree_map *h = *(struct tree_map **) loc;
-  if (h != NULL) 
-    {
-      struct varpool_node *node = varpool_node (h->to);
-      /* Because varpool_finalize_decl () has side-effects,
-         only apply to un-finalized vars.  */
-      if (node && !node->finalized) 
-	varpool_finalize_decl (h->to);
-    }
-  return 1;
-}
-
-/* Finalize emutls control vars and add a static constructor if
-   required.  */
-
-void
-emutls_finish (void)
-{
-  if (emutls_htab == NULL)
-    return;
-  htab_traverse_noresize (emutls_htab, 
-			  emutls_finalize_control_var, NULL);
-
-  if (targetm.emutls.register_common)
-    {
-      tree body = NULL_TREE;
-
-      htab_traverse_noresize (emutls_htab, emutls_common_1, &body);
-      if (body == NULL_TREE)
-	return;
-
-      cgraph_build_static_cdtor ('I', body, DEFAULT_INIT_PRIORITY);
-    }
-}
-
 /* Helper routines for maintaining section_htab.  */
 
 static int
@@ -1210,11 +899,6 @@ get_variable_section (tree decl, bool prefer_noswitch_p)
 		  && ADDR_SPACE_GENERIC_P (as));
       if (DECL_THREAD_LOCAL_P (decl))
 	return tls_comm_section;
-      /* This cannot be common bss for an emulated TLS object without
-	 a register_common hook.  */
-      else if (DECL_TLS_MODEL (decl) == TLS_MODEL_EMULATED
-	       && !targetm.emutls.register_common)
-	;
       else if (TREE_PUBLIC (decl) && bss_initializer_p (decl))
 	return comm_section;
     }
@@ -2098,40 +1782,6 @@ assemble_variable_contents (tree decl, const char *name,
     }
 }
 
-/* Initialize emulated tls object TO, which refers to TLS variable
-   DECL and is initialized by PROXY.  */
-
-tree
-default_emutls_var_init (tree to, tree decl, tree proxy)
-{
-  VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, 4);
-  constructor_elt *elt;
-  tree type = TREE_TYPE (to);
-  tree field = TYPE_FIELDS (type);
-
-  elt = VEC_quick_push (constructor_elt, v, NULL);
-  elt->index = field;
-  elt->value = fold_convert (TREE_TYPE (field), DECL_SIZE_UNIT (decl));
-
-  elt = VEC_quick_push (constructor_elt, v, NULL);
-  field = DECL_CHAIN (field);
-  elt->index = field;
-  elt->value = build_int_cst (TREE_TYPE (field),
-			      DECL_ALIGN_UNIT (decl));
-
-  elt = VEC_quick_push (constructor_elt, v, NULL);
-  field = DECL_CHAIN (field);
-  elt->index = field;
-  elt->value = null_pointer_node;
-
-  elt = VEC_quick_push (constructor_elt, v, NULL);
-  field = DECL_CHAIN (field);
-  elt->index = field;
-  elt->value = proxy;
-
-  return build_constructor (type, v);
-}
-
 /* Assemble everything that is needed for a variable or function declaration.
    Not used for automatic variables, and not used for function definitions.
    Should not be called for variables of incomplete structure type.
@@ -2153,35 +1803,9 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
   /* This function is supposed to handle VARIABLES.  Ensure we have one.  */
   gcc_assert (TREE_CODE (decl) == VAR_DECL);
 
-  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;
-    }
-
+  /* Emulated TLS had better not get this far.  */
+  gcc_checking_assert (targetm.have_tls || !DECL_THREAD_LOCAL_P (decl));
+              
   last_assemble_variable_decl = 0;
 
   /* Normally no need to say anything here for external references,
@@ -5685,6 +5309,11 @@ find_decl_and_mark_needed (tree decl, tree target)
 static void
 do_assemble_alias (tree decl, tree target)
 {
+  /* Emulated TLS had better not get this var.  */
+  gcc_assert(!(!targetm.have_tls
+	       && TREE_CODE (decl) == VAR_DECL
+	       && DECL_THREAD_LOCAL_P (decl)));
+
   if (TREE_ASM_WRITTEN (decl))
     return;
 
@@ -5699,14 +5328,6 @@ do_assemble_alias (tree decl, tree target)
     {
       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);
 
@@ -5725,14 +5346,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.  */
 
@@ -6400,24 +6013,11 @@ categorize_decl_for_section (const_tree decl, int reloc)
     ret = SECCAT_RODATA;
 
   /* There are no read-only thread-local sections.  */
-  if (TREE_CODE (decl) == VAR_DECL && DECL_TLS_MODEL (decl))
+  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
     {
-      if (DECL_TLS_MODEL (decl) == TLS_MODEL_EMULATED)
-	{
-	  if (DECL_EMUTLS_VAR_P (decl))
-	    {
-	      if (targetm.emutls.var_section)
-		ret = SECCAT_EMUTLS_VAR;
-	    }
-	  else
-	    {
-	      if (targetm.emutls.tmpl_prefix)
-		ret = SECCAT_EMUTLS_TMPL;
-	    }
-	}
       /* Note that this would be *just* SECCAT_BSS, except that there's
 	 no concept of a read-only thread-local-data section.  */
-      else if (ret == SECCAT_BSS
+      if (ret == SECCAT_BSS
 	       || (flag_zero_initialized_in_bss
 		   && initializer_zerop (DECL_INITIAL (decl))))
 	ret = SECCAT_TBSS;
@@ -6511,12 +6111,6 @@ default_elf_select_section (tree decl, int reloc,
     case SECCAT_TBSS:
       sname = ".tbss";
       break;
-    case SECCAT_EMUTLS_VAR:
-      sname = targetm.emutls.var_section;
-      break;
-    case SECCAT_EMUTLS_TMPL:
-      sname = targetm.emutls.tmpl_section;
-      break;
     default:
       gcc_unreachable ();
     }
@@ -6581,12 +6175,6 @@ default_unique_section (tree decl, int reloc)
     case SECCAT_TBSS:
       prefix = one_only ? ".tb" : ".tbss";
       break;
-    case SECCAT_EMUTLS_VAR:
-      prefix = targetm.emutls.var_section;
-      break;
-    case SECCAT_EMUTLS_TMPL:
-      prefix = targetm.emutls.tmpl_section;
-      break;
     default:
       gcc_unreachable ();
     }
@@ -6697,8 +6285,7 @@ default_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
     flags |= SYMBOL_FLAG_FUNCTION;
   if (targetm.binds_local_p (decl))
     flags |= SYMBOL_FLAG_LOCAL;
-  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl)
-      && DECL_TLS_MODEL (decl) != TLS_MODEL_EMULATED)
+  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
     flags |= DECL_TLS_MODEL (decl) << SYMBOL_FLAG_TLS_SHIFT;
   else if (targetm.in_small_data_p (decl))
     flags |= SYMBOL_FLAG_SMALL;
diff --git a/gcc/varpool.c b/gcc/varpool.c
index 94c949e..dcf3518 100644
--- a/gcc/varpool.c
+++ b/gcc/varpool.c
@@ -346,17 +346,6 @@ decide_is_variable_needed (struct varpool_node *node, tree decl)
       && !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)

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

* Re: [RFA, Fortran, try 11] Emulated tls rewrite
  2010-07-23 23:12               ` [RFA, Fortran, try 11] " Richard Henderson
@ 2010-07-24  9:54                 ` Jan Hubicka
  2010-07-24 13:52                   ` Richard Guenther
  2010-07-26 23:09                 ` Richard Henderson
  1 sibling, 1 reply; 28+ messages in thread
From: Jan Hubicka @ 2010-07-24  9:54 UTC (permalink / raw)
  To: Richard Henderson
  Cc: Jack Howarth, Richard Guenther, IainS, GCC Patches, Jakub Jelinek, jh

Am Sat 24 Jul 2010 01:11:31 AM CEST schrieb Richard Henderson  
<rth@redhat.com>:

> On 07/21/2010 07:32 PM, Jack Howarth wrote:
>> FAIL: gfortran.dg/gomp/appendix-a/a.22.6.f90  -O  (test for excess errors)
>> Excess errors:
>> .../testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90:4:0: sorry,   
>> unimplemented: thread-local COMMON data not implemented
>
> I managed to reproduce this problem reliably.  It has to do with the Fortran
> front end (indirectly) invoking varpool_finalize_decl much later than the C
> front ends do.  Without the decls being finalized, the IPA pass doesn't get
> to see them and they don't get lowered.
>
> I talked to Richi about this ordering problem on IRC, and changing the
> generic ordering of decls vs compilation unit finalization appears to run
> into problems with C++ and Java and their aliases.  An acceptable solution
> appears to be to hack the Fortran front end to do it by hand.

Hmm, I wanted to get decl finalization out of wrapup_global_decls for  
a while but never got around it.  What are those problems with aliases?

Honza

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

* Re: [RFA, Fortran, try 11] Emulated tls rewrite
  2010-07-24  9:54                 ` Jan Hubicka
@ 2010-07-24 13:52                   ` Richard Guenther
  0 siblings, 0 replies; 28+ messages in thread
From: Richard Guenther @ 2010-07-24 13:52 UTC (permalink / raw)
  To: Jan Hubicka
  Cc: Richard Henderson, Jack Howarth, IainS, GCC Patches, Jakub Jelinek, jh

On Sat, Jul 24, 2010 at 11:54 AM, Jan Hubicka <jh@suse.de> wrote:
> Am Sat 24 Jul 2010 01:11:31 AM CEST schrieb Richard Henderson
> <rth@redhat.com>:
>
>> On 07/21/2010 07:32 PM, Jack Howarth wrote:
>>>
>>> FAIL: gfortran.dg/gomp/appendix-a/a.22.6.f90  -O  (test for excess
>>> errors)
>>> Excess errors:
>>> .../testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90:4:0: sorry,
>>>  unimplemented: thread-local COMMON data not implemented
>>
>> I managed to reproduce this problem reliably.  It has to do with the
>> Fortran
>> front end (indirectly) invoking varpool_finalize_decl much later than the
>> C
>> front ends do.  Without the decls being finalized, the IPA pass doesn't
>> get
>> to see them and they don't get lowered.
>>
>> I talked to Richi about this ordering problem on IRC, and changing the
>> generic ordering of decls vs compilation unit finalization appears to run
>> into problems with C++ and Java and their aliases.  An acceptable solution
>> appears to be to hack the Fortran front end to do it by hand.
>
> Hmm, I wanted to get decl finalization out of wrapup_global_decls for a
> while but never got around it.  What are those problems with aliases?

Apply

Index: decl2.c
===================================================================
--- decl2.c	(revision 162499)
+++ decl2.c	(working copy)
@@ -3921,8 +3921,6 @@ cp_write_global_declarations (void)
   /* Collect candidates for Java hidden aliases.  */
   candidates = collect_candidates_for_java_method_aliases ();

-  cgraph_finalize_compilation_unit ();
-
   /* Now, issue warnings about static, but not defined, functions,
      etc., and emit debugging information.  */
   walk_namespaces (wrapup_globals_for_namespace, /*data=*/&reconsider);
@@ -3968,6 +3966,8 @@ cp_write_global_declarations (void)
 #ifdef ENABLE_CHECKING
   validate_conversion_obstack ();
 #endif /* ENABLE_CHECKING */
+
+  cgraph_finalize_compilation_unit ();
 }

 /* FN is an OFFSET_REF, DOTSTAR_EXPR or MEMBER_REF indicating the

(basically move it after /* Generate hidden aliases for Java.  */) and enjoy
libjava exploding.

Richard.

> Honza
>
>

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

* Re: [RFA, Fortran, try 11] Emulated tls rewrite
  2010-07-23 23:12               ` [RFA, Fortran, try 11] " Richard Henderson
  2010-07-24  9:54                 ` Jan Hubicka
@ 2010-07-26 23:09                 ` Richard Henderson
  2010-07-27 12:14                   ` IainS
  1 sibling, 1 reply; 28+ messages in thread
From: Richard Henderson @ 2010-07-26 23:09 UTC (permalink / raw)
  To: Jack Howarth; +Cc: Richard Guenther, IainS, GCC Patches, Jakub Jelinek, jh

I've committed v11 of this patch.


r~

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

* Re: [RFA, Fortran, try 11] Emulated tls rewrite
  2010-07-26 23:09                 ` Richard Henderson
@ 2010-07-27 12:14                   ` IainS
  2010-07-27 16:08                     ` Richard Henderson
  0 siblings, 1 reply; 28+ messages in thread
From: IainS @ 2010-07-27 12:14 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc patches

Richard,

Thanks very much for working on this.

On 26 Jul 2010, at 23:55, Richard Henderson wrote:

> I've committed v11 of this patch.

1
Since LTO and emutls issues are now resolved I've re-enabled the  
relevant tests for ObjC/C++
(after re-checking on i686-darwin{8,9} and x86_64-unknown-linux-gnu.)  
that is r162563.

2
I  noticed that the cse test is not in the set.
If that was an intentional omission (i.e. no longer needed) then fine.
Otherwise, updated version below
If OK, I'll do a changelog and apply it.

thanks again,
Iain



Index: gcc/testsuite/lib/target-supports.exp
===================================================================
--- gcc/testsuite/lib/target-supports.exp	(revision 162562)
+++ gcc/testsuite/lib/target-supports.exp	(working copy)
@@ -614,6 +614,23 @@ proc check_effective_target_tls_native {} {
      }]
  }

+# Return 1 if *emulated* thread local storage (TLS) is supported, 0  
otherwise.
+
+proc check_effective_target_tls_emulated {} {
+    # VxWorks uses emulated TLS machinery, but with non-standard helper
+    # functions, so we fail to automatically detect it.
+    global target_triplet
+    if { [regexp ".*-.*-vxworks.*" $target_triplet] } {
+	return 1
+    }
+
+    return [check_no_messages_and_pattern tls_emulated "emutls"  
assembly {
+	__thread int i;
+	int f (void) { return i; }
+	void g (int j) { i = j; }
+    }]
+}
+
  # Return 1 if TLS executables can run correctly, 0 otherwise.

  proc check_effective_target_tls_runtime {} {
Index: gcc/testsuite/gcc.dg/tls/thr-cse-1.c
===================================================================
--- gcc/testsuite/gcc.dg/tls/thr-cse-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/tls/thr-cse-1.c	(revision 0)
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O1" } */
+/* { dg-require-effective-target tls_emulated } */
+
+/* Test that we only get one call to emutls_get_address when CSE is
+   active.  Note that the var _must_ be initialized for the scan asm
+   to work, since otherwise there will be an initializer which will,
+   correctly, call emutls_get_address.  */
+int foo (int b, int c, int d)
+{
+  static __thread int a=1;
+  a += b;
+  a -= c;
+  a += d;
+  return a;
+}
+
+/* { dg-final { scan-assembler-not  
"emutls_get_address.*emutls_get_address.*" { target { { ! "*-wrs- 
vxworks" } && { ! "*-*-darwin8" } } } } } */
+/* { dg-final { scan-assembler-not "call 
\tL___emutls_get_address.stub.*call 
\tL___emutls_get_address.stub.*" { target "*-*-darwin8" } } } */
+/* { dg-final { scan-assembler-not  
"tls_lookup.*tls_lookup.*" { target *-wrs-vxworks } } } */
+

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

* Re: [RFA, Fortran, try 11] Emulated tls rewrite
  2010-07-27 12:14                   ` IainS
@ 2010-07-27 16:08                     ` Richard Henderson
  2010-08-18  9:19                       ` IainS
  0 siblings, 1 reply; 28+ messages in thread
From: Richard Henderson @ 2010-07-27 16:08 UTC (permalink / raw)
  To: IainS; +Cc: gcc patches

On 07/27/2010 05:11 AM, IainS wrote:
> I  noticed that the cse test is not in the set.
> If that was an intentional omission (i.e. no longer needed) then fine.
> Otherwise, updated version below
> If OK, I'll do a changelog and apply it.

Not an intentional omission.  The test is ok.


r~

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

* Re: [RFA, Fortran, try 11] Emulated tls rewrite
  2010-07-27 16:08                     ` Richard Henderson
@ 2010-08-18  9:19                       ` IainS
  0 siblings, 0 replies; 28+ messages in thread
From: IainS @ 2010-08-18  9:19 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc patches


On 27 Jul 2010, at 16:54, Richard Henderson wrote:

> On 07/27/2010 05:11 AM, IainS wrote:
>> I  noticed that the cse test is not in the set.
>> If that was an intentional omission (i.e. no longer needed) then  
>> fine.
>> Otherwise, updated version below
>> If OK, I'll do a changelog and apply it.
>
> Not an intentional omission.  The test is ok.

better late than never:

test cse for emulated TLS targets.

testsuite:

         * lib/target-supports.exp  
(check_effective_target_tls_emulated): New.
         * gcc.dg/tls/thr-cse-1.c: New.

r163330
cheers,
Iain

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

end of thread, other threads:[~2010-08-18  9:05 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-07-14 23:50 [CFT, try 7] Emulated tls rewrite Richard Henderson
2010-07-15  7:49 ` Richard Guenther
2010-07-15  7:59   ` IainS
2010-07-15 11:39     ` Jack Howarth
2010-07-15 12:00       ` IainS
2010-07-15 15:50     ` Richard Henderson
2010-07-15 20:29       ` IainS
2010-07-19 13:18       ` Jack Howarth
2010-07-15 12:00 ` Jack Howarth
2010-07-19 19:42 ` [CFT, try 8] " Richard Henderson
2010-07-20 15:53   ` Richard Guenther
2010-07-20 16:16     ` Richard Henderson
2010-07-21  8:24       ` Richard Guenther
2010-07-21 17:11         ` Richard Henderson
2010-07-21 19:38           ` [CFT, try 9] " Richard Henderson
2010-07-21 19:44             ` Jakub Jelinek
2010-07-21 19:54               ` Richard Henderson
2010-07-22  2:32             ` Jack Howarth
2010-07-22 10:13               ` IainS
2010-07-22 16:15                 ` Jack Howarth
2010-07-22 16:13               ` Richard Henderson
2010-07-23 23:12               ` [RFA, Fortran, try 11] " Richard Henderson
2010-07-24  9:54                 ` Jan Hubicka
2010-07-24 13:52                   ` Richard Guenther
2010-07-26 23:09                 ` Richard Henderson
2010-07-27 12:14                   ` IainS
2010-07-27 16:08                     ` Richard Henderson
2010-08-18  9:19                       ` IainS

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).