Patchwork [CFT,try,8] Emulated tls rewrite

login
register
mail settings
Submitter Richard Henderson
Date July 19, 2010, 7:42 p.m.
Message ID <4C44AA95.9000505@redhat.com>
Download mbox | patch
Permalink /patch/59221/
State New
Headers show

Comments

Richard Henderson - July 19, 2010, 7:42 p.m.
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~
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.
Richard Guenther - July 20, 2010, 3:53 p.m.
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~
>
Richard Henderson - July 20, 2010, 4:16 p.m.
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~
Richard Guenther - July 21, 2010, 8:23 a.m.
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~
>
Richard Henderson - July 21, 2010, 4:32 p.m.
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~

Patch

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);
 }
 
-/* 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);
-}
-
-
 /* 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)