[PATCH] TLS support for powerpc and powerpc64

Janis Johnson janis187@us.ibm.com
Fri Apr 11 23:35:00 GMT 2003


This patch adds thread local storage support for powerpc-linux and
powerpc64-linux.  Bootstrapped and regression tested on
powerpc-unknown-linux-gnu.  Regression tests for cross compiler are
still running on powerpc64-unknown-linux-gnu, but they've had no
problems for recent versions of this patch.

OK for mainline, assuming powerpc64 test results are good?

2003-04-11  Janis Johnson  <janis187@us.ibm.com>
	    Alan Modra  <amodra@bigpond.net.au>
	    Jakub Jelinek  <jakub@redhat.com>

	* configure.in (HAVE_AS_TLS): Add powerpc and powerpc64 tests.
	* configure: Rebuild.
	* config/rs6000/linux64.h (ASM_OUTPUT_LABELREF): Handle TLS symbols.
	* config/rs6000/rs6000-protos.h: Update.
	* config/rs6000/rs6000.c (rs6000_tls_size): New.
	(rs6000_tls_size_string): New.
	(rs6000_parse_tls_size_option): New.
	(legitimize_tls_address): New.
	(rs6000_tls_get_addr): New.
	(rs6000_got_sym): New.
	(encode_tls_info): New.
	(tls_model tls_symbolic_operand_type): New.
	(rs6000_tls_symbol_ref_1): New.
	(get_some_local_dynamic_name): New.
	(get_some_local_dynamic_name_1): New.
	(TARGET_HAVE_TLS): New.
	(TARGET_CANNOT_FORCE_CONST_MEM): New.
	(rs6000_override_options): Handle -mtls-size option.
	(constant_pool_expr_1): Handle TLS symbols.
	(rs6000_legitimize_address): Handle TLS symbols.
	(rs6000_tls_referenced_p): New.
	(rs6000_legitimate_address): Handle TLS symbols.
	(rs6000_emit_move): Handle TLS symbols.
	(mtcrf_operation): Use symbol for unspec constant.
	(print_operand): Handle TLS symbols.
	(uses_TOC): Handle TLS symbols.
	(rs6000_emit_prologue): Use symbol for unspec constant.
	(rs6000_elf_encode_section_info): Handle TLS symbols.
	(rs6000_elf_strip_name_encoding): Handle TLS symbols.
	* config/rs6000/rs6000.h (HAVE_AS_TLS): New.
	(some_ld_name): New.
	(LEGITIMATE_CONSTANT_P): Handle TLS symbols.
	(PRINT_OPERAND_PUNCT_VALID_P): Handle TLS symbols.
	(PREDICATE_CODES): Add rs6000_tls_symbol_ref.
	* config/rs6000/rs6000.md (define_constants): Define constants for
	all UNSPEC usage, including new values for TLS support.
	(aux_truncdfsf2, gpc_reg_operand, movsi_got, movsi_got_internal,
	load_toc_aix_si, load_toc_aix_di, load_toc_v4_pic_si,
	load_toc_v4_PIC_1, load_toc_v4_PIC_1b, load_macho_picbase,
	macho_correct_pic, blockage, gpc_reg_operand, movesi_from_cr,
	stack_tie, movsi_to_cr_one, movsi_to_cr, mtcrfsi, eh_set_lr_si,
	eh_set_lr_di): Use symbol for unspec constant.
	(gpc_reg_operand): Use symbol for unspec constant.
	(tls_gd_32, tls_gd_64, tls_ld_32, tls_ld_64, tls_dtprel_32,
	tls_dtprel_64, tls_dtprel_ha_32, tls_dtprel_ha_64, tls_dtprel_lo_32,
	tls_dtprel_lo_64, tls_got_dtprel_32, tls_got_dtprel_64, tls_tprel_32,
	tls_tprel_64, tls_tprel_ha_32, tls_tprel_ha_64, tls_tprel_lo_32,
	tls_tprel_lo_64, tls_got_tprel_32, tls_got_tprel_64, tls_tls_32,
	tls_tls_64): New.
	* config/rs6000/sysv4.h (SUBTARGET_OPTIONS): Add tls_size.
	(ASM_OUTPUT_LABELREF): Handle TLS symbols.

Index: gcc/configure.in
===================================================================
RCS file: /home/janis/gcc_rsync/gcc-cvs/gcc/gcc/configure.in,v
retrieving revision 1.656
diff -u -p -r1.656 configure.in
--- gcc/configure.in	28 Mar 2003 23:15:41 -0000	1.656
+++ gcc/configure.in	11 Apr 2003 15:48:55 -0000
@@ -1991,6 +1991,7 @@ gcc_cv_as_tls=no
 conftest_s=
 tls_first_major=
 tls_first_minor=
+tls_as_opt=
 case "$target" in
 changequote(,)dnl
   alpha*-*-*)
@@ -2066,6 +2067,66 @@ foo:	data8	25
 	tls_first_major=2
 	tls_first_minor=13
 	;;
+  powerpc-*-*)
+    conftest_s='
+	.section ".tdata","awT",@progbits
+	.align 2
+ld0:	.space 4
+ld1:	.space 4
+x1:	.space 4
+x2:	.space 4
+x3:	.space 4
+	.text
+	addi 3,31,ld0@got@tlsgd
+	bl __tls_get_addr
+	addi 3,31,x1@got@tlsld
+	bl __tls_get_addr
+	addi 9,3,x1@dtprel
+	addis 9,3,x2@dtprel@ha
+	addi 9,9,x2@dtprel@l
+	lwz 9,x3@got@tprel(31)
+	add 9,9,x@tls
+	addi 9,2,x1@tprel
+	addis 9,2,x2@tprel@ha
+	addi 9,9,x2@tprel@l'
+	tls_first_major=2
+	tls_first_minor=13
+	tls_as_opt=-a32
+	;;
+  powerpc64-*-*)
+    conftest_s='
+	.section ".tdata","awT",@progbits
+	.align 3
+ld0:	.space 8
+ld1:	.space 8
+x1:	.space 8
+x2:	.space 8
+x3:	.space 8
+	.text
+	addi 3,2,ld0@got@tlsgd
+	bl .__tls_get_addr
+	nop
+	addi 3,2,ld1@toc
+	bl .__tls_get_addr
+	nop
+	addi 3,2,x1@got@tlsld
+	bl .__tls_get_addr
+	nop
+	addi 9,3,x1@dtprel
+	bl .__tls_get_addr
+	nop
+	addis 9,3,x2@dtprel@ha
+	addi 9,9,x2@dtprel@l
+	bl .__tls_get_addr
+	nop
+	ld 9,x3@got@dtprel(2)
+	add 9,9,3
+	bl .__tls_get_addr
+	nop'
+	tls_first_major=2
+	tls_first_minor=13
+	tls_as_opt=-a64
+	;;
   s390-*-*)
     conftest_s='
 	.section ".tdata","awT",@progbits
@@ -2083,6 +2144,7 @@ foo:	.long	25
 	bas	%r14,0(%r1,%r13):tls_ldcall:foo'
 	tls_first_major=2
 	tls_first_minor=14
+	tls_as_opt=-m31
 	;;
   s390x-*-*)
     conftest_s='
@@ -2100,6 +2162,7 @@ foo:	.long	25
 	brasl	%r14,__tls_get_offset@PLT:tls_ldcall:foo'
 	tls_first_major=2
 	tls_first_minor=14
+	tls_as_opt=-m64
 	;;
 esac
 if test -z "$tls_first_major"; then
@@ -2110,7 +2173,7 @@ elif test $in_tree_gas = yes ; then
   ])
 elif test x$gcc_cv_as != x; then
   echo "$conftest_s" > conftest.s
-  if $gcc_cv_as --fatal-warnings -o conftest.o conftest.s > /dev/null 2>&1
+  if $gcc_cv_as $tls_as_opt --fatal-warnings -o conftest.o conftest.s > /dev/null 2>&1
   then
     gcc_cv_as_tls=yes
   fi
Index: gcc/config/rs6000/linux64.h
===================================================================
RCS file: /home/janis/gcc_rsync/gcc-cvs/gcc/gcc/config/rs6000/linux64.h,v
retrieving revision 1.35
diff -u -p -r1.35 linux64.h
--- gcc/config/rs6000/linux64.h	18 Mar 2003 02:28:46 -0000	1.35
+++ gcc/config/rs6000/linux64.h	11 Apr 2003 15:48:55 -0000
@@ -282,6 +282,8 @@ do {						\
   const char *_name = NAME;			\
   if (*_name == '@')				\
     _name++;					\
+  else if (*_name == '%')			\
+    _name += 2;					\
  						\
   if (*_name == '*')				\
     fprintf (FILE, "%s", _name + 1);		\
Index: gcc/config/rs6000/rs6000-protos.h
===================================================================
RCS file: /home/janis/gcc_rsync/gcc-cvs/gcc/gcc/config/rs6000/rs6000-protos.h,v
retrieving revision 1.50
diff -u -p -r1.50 rs6000-protos.h
--- gcc/config/rs6000/rs6000-protos.h	1 Apr 2003 13:40:11 -0000	1.50
+++ gcc/config/rs6000/rs6000-protos.h	11 Apr 2003 15:48:55 -0000
@@ -195,6 +195,8 @@ extern int rs6000_register_move_cost PAR
 					      enum reg_class, enum reg_class));
 extern int rs6000_memory_move_cost PARAMS ((enum machine_mode,
 					    enum reg_class, int));
+extern bool rs6000_tls_referenced_p PARAMS ((rtx));
+extern int rs6000_tls_symbol_ref PARAMS ((rtx, enum machine_mode));
 
 /* Declare functions in rs6000-c.c */
 
Index: gcc/config/rs6000/rs6000.c
===================================================================
RCS file: /home/janis/gcc_rsync/gcc-cvs/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.454
diff -u -p -r1.454 rs6000.c
--- gcc/config/rs6000/rs6000.c	8 Apr 2003 14:01:58 -0000	1.454
+++ gcc/config/rs6000/rs6000.c	11 Apr 2003 15:48:55 -0000
@@ -132,6 +132,10 @@ enum rs6000_sdata_type rs6000_sdata = SD
 /* Which small data model to use */
 const char *rs6000_sdata_name = (char *)0;
 
+/* Bit size of immediate TLS offsets and string from which it is decoded.  */
+int rs6000_tls_size = 32;
+const char *rs6000_tls_size_string;
+
 /* Counter for labels which are to be placed in .fixup.  */
 int fixuplabelno = 0;
 #endif
@@ -283,6 +287,7 @@ static rtx altivec_expand_abs_builtin PA
 static rtx altivec_expand_predicate_builtin PARAMS ((enum insn_code, const char *, tree, rtx));
 static rtx altivec_expand_stv_builtin PARAMS ((enum insn_code, tree));
 static void rs6000_parse_abi_options PARAMS ((void));
+static void rs6000_parse_tls_size_option PARAMS ((void));
 static void rs6000_parse_yes_no_option (const char *, const char *, int *);
 static int first_altivec_reg_to_save PARAMS ((void));
 static unsigned int compute_vrsave_mask PARAMS ((void));
@@ -292,6 +297,14 @@ int easy_vector_constant PARAMS ((rtx, e
 static int easy_vector_same PARAMS ((rtx, enum machine_mode));
 static bool is_ev64_opaque_type PARAMS ((tree));
 static rtx rs6000_dwarf_register_span PARAMS ((rtx));
+static rtx legitimize_tls_address PARAMS ((rtx, enum tls_model));
+static rtx rs6000_tls_get_addr PARAMS ((void));
+static rtx rs6000_got_sym PARAMS ((void));
+static void encode_tls_info PARAMS ((tree));
+static enum tls_model tls_symbolic_operand_type PARAMS ((rtx));
+static int rs6000_tls_symbol_ref_1 PARAMS ((rtx *, void *));
+static const char *get_some_local_dynamic_name PARAMS ((void));
+static int get_some_local_dynamic_name_1 PARAMS ((rtx *, void *));
 
 /* Hash table stuff for keeping track of TOC entries.  */
 
@@ -405,6 +418,12 @@ static const char alt_reg_names[][8] =
 #define TARGET_ASM_ASSEMBLE_VISIBILITY rs6000_assemble_visibility
 #endif
 
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS HAVE_AS_TLS
+
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM rs6000_tls_referenced_p
+
 #undef TARGET_ASM_FUNCTION_PROLOGUE
 #define TARGET_ASM_FUNCTION_PROLOGUE rs6000_output_function_prologue
 #undef TARGET_ASM_FUNCTION_EPILOGUE
@@ -718,6 +737,9 @@ rs6000_override_options (default_cpu)
   rs6000_parse_yes_no_option ("float-gprs", rs6000_float_gprs_string,
 			      &rs6000_float_gprs);
 
+  /* Handle -mtls-size option.  */
+  rs6000_parse_tls_size_option ();
+
 #ifdef SUBTARGET_OVERRIDE_OPTIONS
   SUBTARGET_OVERRIDE_OPTIONS;
 #endif
@@ -848,6 +870,21 @@ rs6000_parse_abi_options ()
     error ("unknown ABI specified: '%s'", rs6000_abi_string);
 }
 
+static void
+rs6000_parse_tls_size_option ()
+{
+  if (rs6000_tls_size_string == 0)
+    return;
+  else if (strcmp (rs6000_tls_size_string, "16") == 0)
+    rs6000_tls_size = 16;
+  else if (strcmp (rs6000_tls_size_string, "32") == 0)
+    rs6000_tls_size = 32;
+  else if (strcmp (rs6000_tls_size_string, "64") == 0)
+    rs6000_tls_size = 64;
+  else
+    error ("bad value `%s' for -mtls-size-switch", rs6000_tls_size_string);
+}
+
 void
 optimization_options (level, size)
      int level ATTRIBUTE_UNUSED;
@@ -2218,7 +2255,9 @@ constant_pool_expr_1 (op, have_sym, have
   switch (GET_CODE(op)) 
     {
     case SYMBOL_REF:
-      if (CONSTANT_POOL_ADDRESS_P (op))
+      if (tls_symbolic_operand_type (op))
+	return 0;
+      else if (CONSTANT_POOL_ADDRESS_P (op))
 	{
 	  if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (op), Pmode))
 	    {
@@ -2294,6 +2333,13 @@ rs6000_legitimize_address (x, oldx, mode
      rtx oldx ATTRIBUTE_UNUSED;
      enum machine_mode mode;
 {
+  if (GET_CODE (x) == SYMBOL_REF)
+    {
+      enum tls_model model = tls_symbolic_operand_type (x);
+      if (model != 0)
+	return legitimize_tls_address (x, model);
+    }
+
   if (GET_CODE (x) == PLUS 
       && GET_CODE (XEXP (x, 0)) == REG
       && GET_CODE (XEXP (x, 1)) == CONST_INT
@@ -2394,6 +2440,284 @@ rs6000_legitimize_address (x, oldx, mode
     return NULL_RTX;
 }
 
+/* Construct the SYMBOL_REF for the tls_get_addr function.  */
+
+static GTY(()) rtx rs6000_tls_symbol;
+static rtx
+rs6000_tls_get_addr ()
+{
+  if (!rs6000_tls_symbol)
+    rs6000_tls_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tls_get_addr");
+
+  return rs6000_tls_symbol;
+}
+
+/* Construct the SYMBOL_REF for TLS GOT references.  */
+
+static GTY(()) rtx rs6000_got_symbol;
+static rtx
+rs6000_got_sym ()
+{
+  if (!rs6000_got_symbol)
+    rs6000_got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
+
+  return rs6000_got_symbol;
+}
+
+/* ADDR contains a thread-local SYMBOL_REF.  Generate code to compute
+   this (thread-local) address.  */
+
+static rtx
+legitimize_tls_address (addr, model)
+     rtx addr;
+     enum tls_model model;
+{
+  rtx dest, insn;
+
+  dest = gen_reg_rtx (Pmode);
+  if (model == TLS_MODEL_LOCAL_EXEC && rs6000_tls_size == 16)
+    {
+      rtx tlsreg;
+
+      if (TARGET_64BIT)
+	{
+	  tlsreg = gen_rtx_REG (Pmode, 13);
+	  insn = gen_tls_tprel_64 (dest, tlsreg, addr);
+	}
+      else
+	{
+	  tlsreg = gen_rtx_REG (Pmode, 2);
+	  insn = gen_tls_tprel_32 (dest, tlsreg, addr);
+	}
+      emit_insn (insn);
+    }
+  else if (model == TLS_MODEL_LOCAL_EXEC && rs6000_tls_size == 32)
+    {
+      rtx tlsreg, tmp;
+
+      tmp = gen_reg_rtx (Pmode);
+      if (TARGET_64BIT)
+	{
+	  tlsreg = gen_rtx_REG (Pmode, 13);
+	  insn = gen_tls_tprel_ha_64 (tmp, tlsreg, addr);
+	}
+      else
+	{
+	  tlsreg = gen_rtx_REG (Pmode, 2);
+	  insn = gen_tls_tprel_ha_32 (tmp, tlsreg, addr);
+	}
+      emit_insn (insn);
+      if (TARGET_64BIT)
+	insn = gen_tls_tprel_lo_64 (dest, tmp, addr);
+      else
+	insn = gen_tls_tprel_lo_32 (dest, tmp, addr);
+      emit_insn (insn);
+    }
+  else
+    {
+      rtx r3, got, tga, tmp1, tmp2, eqv;
+
+      if (TARGET_64BIT)
+	got = gen_rtx_REG (Pmode, TOC_REGISTER);
+      else
+	{
+	  if (flag_pic == 1)
+	    got = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
+	  else
+	    {
+	      rtx gsym = rs6000_got_sym ();
+	      got = gen_reg_rtx (Pmode);
+	      if (flag_pic == 0)
+		rs6000_emit_move (got, gsym, Pmode);
+	      else
+		{
+		  char buf[30];
+		  static int tls_got_labelno = 0;
+		  rtx tempLR, lab, tmp3, mem;
+		  rtx first, last;
+
+		  ASM_GENERATE_INTERNAL_LABEL (buf, "LTLS", tls_got_labelno++);
+		  lab = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
+		  tempLR = gen_reg_rtx (Pmode);
+		  tmp1 = gen_reg_rtx (Pmode);
+		  tmp2 = gen_reg_rtx (Pmode);
+		  tmp3 = gen_reg_rtx (Pmode);
+		  mem = gen_rtx_MEM (Pmode, tmp1);
+		  RTX_UNCHANGING_P (mem) = 1;
+
+		  first = emit_insn (gen_load_toc_v4_PIC_1b (tempLR, lab,
+							     gsym));
+		  emit_move_insn (tmp1, tempLR);
+		  emit_move_insn (tmp2, mem);
+		  emit_insn (gen_addsi3 (tmp3, tmp1, tmp2));
+		  last = emit_move_insn (got, tmp3);
+		  REG_NOTES (last) = gen_rtx_EXPR_LIST (REG_EQUAL, gsym,
+							REG_NOTES (last));
+		  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
+							 REG_NOTES (first));
+		  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first,
+							REG_NOTES (last));
+		}
+	    }
+	}
+
+      if (model == TLS_MODEL_GLOBAL_DYNAMIC)
+	{
+	  r3 = gen_rtx_REG (Pmode, 3);
+	  if (TARGET_64BIT)
+	    insn = gen_tls_gd_64 (r3, got, addr);
+	  else
+	    insn = gen_tls_gd_32 (r3, got, addr);
+	  start_sequence ();
+	  emit_insn (insn);
+	  tga = gen_rtx_MEM (Pmode, rs6000_tls_get_addr ());
+	  insn = gen_call_value (r3, tga, const0_rtx, const0_rtx);
+	  insn = emit_call_insn (insn);
+	  CONST_OR_PURE_CALL_P (insn) = 1;
+	  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r3);
+	  insn = get_insns ();
+	  end_sequence ();
+	  emit_libcall_block (insn, dest, r3, addr);
+	}
+      else if (model == TLS_MODEL_LOCAL_DYNAMIC)
+	{
+	  r3 = gen_rtx_REG (Pmode, 3);
+	  if (TARGET_64BIT)
+	    insn = gen_tls_ld_64 (r3, got);
+	  else
+	    insn = gen_tls_ld_32 (r3, got);
+	  start_sequence ();
+	  emit_insn (insn);
+	  tga = gen_rtx_MEM (Pmode, rs6000_tls_get_addr ());
+	  insn = gen_call_value (r3, tga, const0_rtx, const0_rtx);
+	  insn = emit_call_insn (insn);
+	  CONST_OR_PURE_CALL_P (insn) = 1;
+	  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r3);
+	  insn = get_insns ();
+	  end_sequence ();
+	  tmp1 = gen_reg_rtx (Pmode);
+	  eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
+				UNSPEC_TLSLD);
+	  emit_libcall_block (insn, tmp1, r3, eqv);
+	  if (rs6000_tls_size == 16)
+	    {
+	      if (TARGET_64BIT)
+		insn = gen_tls_dtprel_64 (dest, tmp1, addr);
+	      else
+		insn = gen_tls_dtprel_32 (dest, tmp1, addr);
+	    }
+	  else if (rs6000_tls_size == 32)
+	    {
+	      tmp2 = gen_reg_rtx (Pmode);
+	      if (TARGET_64BIT)
+		insn = gen_tls_dtprel_ha_64 (tmp2, tmp1, addr);
+	      else
+		insn = gen_tls_dtprel_ha_32 (tmp2, tmp1, addr);
+	      emit_insn (insn);
+	      if (TARGET_64BIT)
+		insn = gen_tls_dtprel_lo_64 (dest, tmp2, addr);
+	      else
+		insn = gen_tls_dtprel_lo_32 (dest, tmp2, addr);
+	    }
+	  else
+	    {
+	      tmp2 = gen_reg_rtx (Pmode);
+	      if (TARGET_64BIT)
+		insn = gen_tls_got_dtprel_64 (tmp2, got, addr);
+	      else
+		insn = gen_tls_got_dtprel_32 (tmp2, got, addr);
+	      emit_insn (insn);
+	      insn = gen_rtx_SET (Pmode, dest,
+				  gen_rtx_PLUS (Pmode, tmp2, tmp1));
+	    }
+	  emit_insn (insn);
+	}
+      else
+	{
+	  /* IE, or 64 bit offset LE.  */
+	  tmp2 = gen_reg_rtx (Pmode);
+	  if (TARGET_64BIT)
+	    insn = gen_tls_got_tprel_64 (tmp2, got, addr);
+	  else
+	    insn = gen_tls_got_tprel_32 (tmp2, got, addr);
+	  emit_insn (insn);
+	  if (TARGET_64BIT)
+	    insn = gen_tls_tls_64 (dest, tmp2, addr);
+	  else
+	    insn = gen_tls_tls_32 (dest, tmp2, addr);
+	  emit_insn (insn);
+	}
+    }
+
+  return dest;
+}
+
+/* If OP is a SYMBOL_REF of a thread-local symbol, return its TLS type,
+   otherwise return 0.  */
+
+static enum tls_model
+tls_symbolic_operand_type (op)
+    rtx op;
+{
+  const char *str;
+
+  if (GET_CODE (op) != SYMBOL_REF)
+    return 0;
+
+  str = XSTR (op, 0);
+  if (str[0] != '%')
+    return 0;
+
+  switch (str[1])
+    {
+    case 'G':
+      return TLS_MODEL_GLOBAL_DYNAMIC;
+    case 'L':
+      /* Local dynamic is a waste if we're not going to combine
+	 the __tls_get_addr calls.  So avoid it if not optimizing.  */
+      if (optimize)
+	return TLS_MODEL_LOCAL_DYNAMIC;
+      else
+	return TLS_MODEL_GLOBAL_DYNAMIC;
+    case 'i':
+      return TLS_MODEL_INITIAL_EXEC;
+    case 'l':
+      return TLS_MODEL_LOCAL_EXEC;
+    }
+  return 0;
+}
+
+/* Return 1 if X is a SYMBOL_REF for a TLS symbol.  */
+
+int
+rs6000_tls_symbol_ref (x, mode)
+     rtx x;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  if (GET_CODE (x) != SYMBOL_REF)
+    return 0;
+  return tls_symbolic_operand_type (x) != 0;
+}
+
+/* Determine if X contains a thread-local symbol.  */
+
+bool
+rs6000_tls_referenced_p (x)
+     rtx x;
+{
+  return for_each_rtx (&x, &rs6000_tls_symbol_ref_1, 0);
+}
+
+static int
+rs6000_tls_symbol_ref_1 (x, data)
+     rtx *x;
+     void *data ATTRIBUTE_UNUSED;
+{
+  if (GET_CODE (*x) != SYMBOL_REF)
+    return 0;
+  return tls_symbolic_operand_type (*x);
+}
+
 /* The convention appears to be to define this wherever it is used.
    With legitimize_reload_address now defined here, REG_MODE_OK_FOR_BASE_P
    is now used here.  */
@@ -2562,6 +2886,8 @@ rs6000_legitimate_address (mode, x, reg_
     rtx x;
     int reg_ok_strict;
 {
+  if (GET_CODE (x) == SYMBOL_REF && tls_symbolic_operand_type (x) != 0)
+    return 0;
   if (LEGITIMATE_INDIRECT_ADDRESS_P (x, reg_ok_strict))
     return 1;
   if ((GET_CODE (x) == PRE_INC || GET_CODE (x) == PRE_DEC)
@@ -2844,6 +3170,15 @@ rs6000_emit_move (dest, source, mode)
 	}
     }
 
+  /* Recognize the case where operand[1] is a reference to thread-local
+     data and load its address to a register.  */
+  if (GET_CODE (operands[1]) == SYMBOL_REF)
+    {
+      enum tls_model model = tls_symbolic_operand_type (operands[1]);
+      if (model != 0)
+	operands[1] = legitimize_tls_address (operands[1], model);
+    }
+
   /* Handle the case where reload calls us with an invalid address;
      and the case of CONSTANT_P_RTX.  */
   if (!ALTIVEC_VECTOR_MODE (mode)
@@ -6789,7 +7124,7 @@ mtcrf_operation (op, mode)
       maskval = 1 << (MAX_CR_REGNO - REGNO (SET_DEST (exp)));
       
       if (GET_CODE (unspec) != UNSPEC
-	  || XINT (unspec, 1) != 20
+	  || XINT (unspec, 1) != UNSPEC_MOVESI_TO_CR
 	  || XVECLEN (unspec, 0) != 2
 	  || XVECEXP (unspec, 0, 0) != src_reg
 	  || GET_CODE (XVECEXP (unspec, 0, 1)) != CONST_INT
@@ -7633,6 +7968,45 @@ extract_ME (op)
   return i;
 }
 
+/* Locate some local-dynamic symbol still in use by this function
+   so that we can print its name in some tls_ld pattern.  */
+
+static const char *
+get_some_local_dynamic_name ()
+{
+  rtx insn;
+
+  if (cfun->machine->some_ld_name)
+    return cfun->machine->some_ld_name;
+
+  for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
+    if (INSN_P (insn)
+	&& for_each_rtx (&PATTERN (insn), get_some_local_dynamic_name_1, 0))
+      return cfun->machine->some_ld_name;
+
+  abort ();
+}
+
+static int
+get_some_local_dynamic_name_1 (px, data)
+     rtx *px;
+     void *data ATTRIBUTE_UNUSED;
+{
+  rtx x = *px;
+
+  if (GET_CODE (x) == SYMBOL_REF)
+    {
+      const char *str = XSTR (x, 0);
+      if (str[0] == '%' && str[1] == 'L')
+	{
+	  cfun->machine->some_ld_name = str;
+	  return 1;
+	}
+    }
+
+  return 0;
+}
+
 /* Print an operand.  Recognize special options, documented below.  */
 
 #if TARGET_ELF
@@ -8284,6 +8658,10 @@ print_operand (file, x, code)
 	output_addr_const (file, x);
       return;
 
+    case '&':
+      assemble_name (file, get_some_local_dynamic_name ());
+      return;
+
     default:
       output_operand_lossage ("invalid %%xn code");
     }
@@ -10030,27 +10408,34 @@ get_TOC_alias_set ()
 }   
 
 /* This retuns nonzero if the current function uses the TOC.  This is
-   determined by the presence of (unspec ... 7), which is generated by
-   the various load_toc_* patterns.  */
+   determined by the presence of (unspec ... UNSPEC_TOC), which is
+   generated by the various load_toc_* patterns.  */
 
 int
 uses_TOC () 
 {
-    rtx insn;
+  rtx insn;
 
-    for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-      if (INSN_P (insn))
-	{
-	  rtx pat = PATTERN (insn);
-	  int i;
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    if (INSN_P (insn))
+      {
+	rtx pat = PATTERN (insn);
+	int i;
 
-	  if (GET_CODE (pat) == PARALLEL) 
-	    for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
-	      if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == UNSPEC 
-		 && XINT (XVECEXP (PATTERN (insn), 0, i), 1) == 7)
-		  return 1;
-	}
-    return 0;
+	if (GET_CODE (pat) == PARALLEL) 
+	  for (i = 0; i < XVECLEN (pat, 0); i++)
+	    {
+	      rtx sub = XVECEXP (pat, 0, i);
+	      if (GET_CODE (sub) == USE)
+		{
+		  sub = XEXP (sub, 0);
+		  if (GET_CODE (sub) == UNSPEC
+		      && XINT (sub, 1) == UNSPEC_TOC)
+		    return 1;
+		}
+	    }
+      }
+  return 0;
 }
 
 rtx
@@ -10888,9 +11273,9 @@ rs6000_emit_prologue ()
       insn = emit_move_insn (mem, cr_save_rtx);
 
       /* Now, there's no way that dwarf2out_frame_debug_expr is going
-	 to understand '(unspec:SI [(reg:CC 68) ...] 19)'.  But that's
-	 OK.  All we have to do is specify that _one_ condition code
-	 register is saved in this stack slot.  The thrower's epilogue
+	 to understand '(unspec:SI [(reg:CC 68) ...] UNSPEC_MOVESI_FROM_CR)'.
+	 But that's OK.  All we have to do is specify that _one_ condition
+	 code register is saved in this stack slot.  The thrower's epilogue
 	 will then restore all the call-saved registers.
 	 We use CR2_REGNO (70) to be compatible with gcc-2.95 on Linux.  */
       rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, 
@@ -11291,7 +11676,7 @@ rs6000_emit_epilogue (sibcall)
 		RTVEC_ELT (r, 1) = GEN_INT (1 << (7-i));
 		RTVEC_ELT (p, ndx) =
 		  gen_rtx_SET (VOIDmode, gen_rtx_REG (CCmode, CR0_REGNO+i), 
-			       gen_rtx_UNSPEC (CCmode, r, 20));
+			       gen_rtx_UNSPEC (CCmode, r, UNSPEC_MOVESI_TO_CR));
 		ndx++;
 	      }
 	  emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
@@ -12882,6 +13267,53 @@ rs6000_longcall_ref (call_ref)
   return force_reg (Pmode, call_ref);
 }
 
+/* Encode the TLS model into the name of a thread-local variable.  */
+
+static void
+encode_tls_info (decl)
+     tree decl;
+{
+  /* Encode thread-local data with %[GLil] for the TLS model.  */
+  rtx sym_ref = XEXP (DECL_RTL (decl), 0);
+  const char *symbol_str = XSTR (sym_ref, 0);
+  char *newstr;
+  size_t len;
+  char encoding = 0;
+
+  switch (decl_tls_model (decl))
+    {
+    case TLS_MODEL_GLOBAL_DYNAMIC:
+      encoding = 'G';
+      break;
+    case TLS_MODEL_LOCAL_DYNAMIC:
+      encoding = 'L';
+      break;
+    case TLS_MODEL_INITIAL_EXEC:
+      encoding = 'i';
+      break;
+    case TLS_MODEL_LOCAL_EXEC:
+      encoding = 'l';
+      break;
+    }
+
+  /* Strip an existing TLS encoding, which might be there for aliases.  */
+  if (symbol_str[0] == '%')
+    {
+      if (symbol_str[1] == encoding)
+	return;
+      symbol_str += 2;
+    }
+
+  len = strlen (symbol_str) + 1;
+  newstr = alloca (len + 2);
+
+  newstr[0] = '%';
+  newstr[1] = encoding;      
+  memcpy (newstr + 2, symbol_str, len);
+
+  XSTR (sym_ref, 0) = ggc_alloc_string (newstr, len + 2 - 1);
+}
+
 
 #ifdef USING_ELFOS_H
 
@@ -12944,13 +13376,18 @@ rs6000_elf_unique_section (decl, reloc)
 			    flag_pic || DEFAULT_ABI == ABI_AIX);
 }
 
-/* If we are referencing a function that is static or is known to be
+/* Encode symbol attributes of a SYMBOL_REF into its name and
+   SYMBOL_REF_FLAG.
+
+   If we are referencing a function that is static or is known to be
    in this file, make the SYMBOL_REF special.  We can use this to indicate
    that we can branch to this function without emitting a no-op after the
    call.  For real AIX calling sequences, we also replace the
    function name with the real name (1 or 2 leading .'s), rather than
    the function descriptor name.  This saves a lot of overriding code
-   to read the prefixes.  */
+   to read the prefixes.
+
+   For a TLS symbol we encode the TLS model.  */
 
 static void
 rs6000_elf_encode_section_info (decl, first)
@@ -12978,6 +13415,8 @@ rs6000_elf_encode_section_info (decl, fi
 	  XSTR (sym_ref, 0) = ggc_alloc_string (str, len1 + len2);
 	}
     }
+  else if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
+    encode_tls_info (decl);
   else if (rs6000_sdata != SDATA_NONE
 	   && DEFAULT_ABI == ABI_V4
 	   && TREE_CODE (decl) == VAR_DECL)
@@ -13027,11 +13466,17 @@ rs6000_elf_encode_section_info (decl, fi
     }
 }
 
+/* Undo the effects of the above for printing symbol names.  */
+
 static const char *
 rs6000_elf_strip_name_encoding (str)
      const char *str;
 {
-  while (*str == '*' || *str == '@')
+  if (*str == '@')
+    str++;
+  else if (*str == '%')
+    str += 2;
+  if (*str == '*')
     str++;
   return str;
 }
Index: gcc/config/rs6000/rs6000.h
===================================================================
RCS file: /home/janis/gcc_rsync/gcc-cvs/gcc/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.263
diff -u -p -r1.263 rs6000.h
--- gcc/config/rs6000/rs6000.h	7 Apr 2003 18:49:10 -0000	1.263
+++ gcc/config/rs6000/rs6000.h	11 Apr 2003 15:48:55 -0000
@@ -210,6 +210,10 @@ extern int target_flags;
 #define TARGET_UPDATE		(! TARGET_NO_UPDATE)
 #define TARGET_FUSED_MADD	(! TARGET_NO_FUSED_MADD)
 
+#ifndef HAVE_AS_TLS
+#define HAVE_AS_TLS 0
+#endif
+
 #ifdef IN_LIBGCC2
 /* For libgcc2 we make sure this is a compile time constant */
 #if defined (__64BIT__) || defined (__powerpc64__)
@@ -1674,6 +1678,8 @@ typedef struct machine_function GTY(())
   int sysv_varargs_p;
   /* Flags if __builtin_return_address (n) with n >= 1 was used.  */
   int ra_needs_full_frame;
+  /* Some local-dynamic symbol.  */
+  const char *some_ld_name;
   /* Whether the instruction chain has been scanned already.  */
   int insn_chain_scanned_p;
 } machine_function;
@@ -2012,9 +2018,10 @@ typedef struct rs6000_args
    acceptable.  */
 
 #define LEGITIMATE_CONSTANT_P(X)				\
-  (GET_CODE (X) != CONST_DOUBLE || GET_MODE (X) == VOIDmode	\
-   || (TARGET_POWERPC64 && GET_MODE (X) == DImode)		\
-   || easy_fp_constant (X, GET_MODE (X)))
+  ((GET_CODE (X) != CONST_DOUBLE || GET_MODE (X) == VOIDmode	\
+    || (TARGET_POWERPC64 && GET_MODE (X) == DImode)		\
+    || easy_fp_constant (X, GET_MODE (X)))			\
+   && !rs6000_tls_referenced_p (X))
 
 /* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
    and check its validity for a certain class.
@@ -2718,7 +2725,7 @@ extern char rs6000_reg_names[][8];	/* re
 /* Define which CODE values are valid.  */
 
 #define PRINT_OPERAND_PUNCT_VALID_P(CODE)  \
-  ((CODE) == '.')
+  ((CODE) == '.' || (CODE) == '&')
 
 /* Print a memory address as an operand to reference that memory location.  */
 
@@ -2772,6 +2779,7 @@ extern char rs6000_reg_names[][8];	/* re
   {"count_register_operand", {REG}},					   \
   {"xer_operand", {REG}},						   \
   {"symbol_ref_operand", {SYMBOL_REF}},					   \
+  {"rs6000_tls_symbol_ref", {SYMBOL_REF}},				   \
   {"call_operand", {SYMBOL_REF, REG}},					   \
   {"current_file_function_operand", {SYMBOL_REF}},			   \
   {"input_operand", {SUBREG, MEM, REG, CONST_INT,			   \
Index: gcc/config/rs6000/rs6000.md
===================================================================
RCS file: /home/janis/gcc_rsync/gcc-cvs/gcc/gcc/config/rs6000/rs6000.md,v
retrieving revision 1.245
diff -u -p -r1.245 rs6000.md
--- gcc/config/rs6000/rs6000.md	1 Apr 2003 18:05:46 -0000	1.245
+++ gcc/config/rs6000/rs6000.md	11 Apr 2003 15:48:55 -0000
@@ -22,20 +22,43 @@
 
 ;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
 
-;; `unspec' values used in rs6000.md:
-;; Number	Use
-;; 0		frsp for POWER machines
-;; 0/v		blockage
-;; 5		used to tie the stack contents and the stack pointer
-;; 6		address of a word pointing to the TOC
-;; 7		address of the TOC (more-or-less)
-;; 8		movsi_got
-;; 9/v		eh_reg_restore
-;; 10		fctiwz
-;; 15		load_macho_picbase
-;; 16		macho_correct_pic
-;; 19		movesi_from_cr
-;; 20		movsi_to_cr
+;;
+;; UNSPEC usage
+;;
+
+(define_constants
+  [(UNSPEC_FRSP			0)	; frsp for POWER machines
+   (UNSPEC_TIE			5)	; tie stack contents and stack pointer
+   (UNSPEC_TOCPTR		6)	; address of a word pointing to the TOC
+   (UNSPEC_TOC			7)	; address of the TOC (more-or-less)
+   (UNSPEC_MOVSI_GOT		8)
+   (UNSPEC_MV_CR_OV		9)	; move_from_CR_ov_bit
+   (UNSPEC_FCTIWZ		10)
+   (UNSPEC_LD_MPIC		15)	; load_macho_picbase
+   (UNSPEC_MPIC_CORRECT		16)	; macho_correct_pic
+   (UNSPEC_TLSGD		17)
+   (UNSPEC_TLSLD		18)
+   (UNSPEC_MOVESI_FROM_CR	19)
+   (UNSPEC_MOVESI_TO_CR		20)
+   (UNSPEC_TLSDTPREL		21)
+   (UNSPEC_TLSDTPRELHA		22)
+   (UNSPEC_TLSDTPRELLO		23)
+   (UNSPEC_TLSGOTDTPREL		24)
+   (UNSPEC_TLSTPREL		25)
+   (UNSPEC_TLSTPRELHA		26)
+   (UNSPEC_TLSTPRELLO		27)
+   (UNSPEC_TLSGOTTPREL		28)
+   (UNSPEC_TLSTLS		29)
+  ])
+
+;;
+;; UNSPEC_VOLATILE usage
+;;
+
+(define_constants
+  [(UNSPECV_BLOCK		0)
+   (UNSPECV_EH_RR		9)	; eh_reg_restore
+  ])
 
 ;; Define an insn type attribute.  This is used in function unit delay
 ;; computations.
@@ -4362,7 +4385,7 @@
 
 (define_insn "aux_truncdfsf2"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-	(unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")] 0))]
+	(unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")] UNSPEC_FRSP))]
   "! TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS"
   "frsp %0,%1"
   [(set_attr "type" "fp")])
@@ -5148,13 +5171,14 @@
   DONE;
 }")
 
-; Here, we use (set (reg) (unspec:DI [(fix:SI ...)] 10))
+; Here, we use (set (reg) (unspec:DI [(fix:SI ...)] UNSPEC_FCTIWZ))
 ; rather than (set (subreg:SI (reg)) (fix:SI ...))
 ; because the first makes it clear that operand 0 is not live
 ; before the instruction.
 (define_insn "fctiwz"
   [(set (match_operand:DI 0 "gpc_reg_operand" "=*f")
-	(unspec:DI [(fix:SI (match_operand:DF 1 "gpc_reg_operand" "f"))] 10))]
+	(unspec:DI [(fix:SI (match_operand:DF 1 "gpc_reg_operand" "f"))]
+		   UNSPEC_FCTIWZ))]
   "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT && TARGET_FPRS"
   "{fcirz|fctiwz} %0,%1"
   [(set_attr "type" "fp")])
@@ -7497,7 +7521,7 @@
 (define_expand "movsi_got"
   [(set (match_operand:SI 0 "gpc_reg_operand" "")
 	(unspec:SI [(match_operand:SI 1 "got_operand" "")
-		    (match_dup 2)] 8))]
+		    (match_dup 2)] UNSPEC_MOVSI_GOT))]
   "DEFAULT_ABI == ABI_V4 && flag_pic == 1"
   "
 {
@@ -7523,7 +7547,8 @@
 (define_insn "*movsi_got_internal"
   [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
 	(unspec:SI [(match_operand:SI 1 "got_no_const_operand" "")
-		    (match_operand:SI 2 "gpc_reg_operand" "b")] 8))]
+		    (match_operand:SI 2 "gpc_reg_operand" "b")]
+		   UNSPEC_MOVSI_GOT))]
   "DEFAULT_ABI == ABI_V4 && flag_pic == 1"
   "{l|lwz} %0,%a1@got(%2)"
   [(set_attr "type" "load")])
@@ -7533,12 +7558,14 @@
 (define_split 
   [(set (match_operand:SI 0 "gpc_reg_operand" "")
 	(unspec:SI [(match_operand:SI 1 "got_no_const_operand" "")
-		    (match_operand:SI 2 "memory_operand" "")] 8))]
+		    (match_operand:SI 2 "memory_operand" "")]
+		   UNSPEC_MOVSI_GOT))]
   "DEFAULT_ABI == ABI_V4
     && flag_pic == 1
     && (reload_in_progress || reload_completed)"
   [(set (match_dup 0) (match_dup 2))
-   (set (match_dup 0) (unspec:SI [(match_dup 1)(match_dup 0)] 8))]
+   (set (match_dup 0) (unspec:SI [(match_dup 1)(match_dup 0)]
+				 UNSPEC_MOVSI_GOT))]
   "")
 
 ;; For SI, we special-case integers that can't be loaded in one insn.  We
@@ -9689,6 +9716,186 @@
    && addrs_ok_for_quad_peep (XEXP (operands[0], 0), XEXP (operands[2], 0))"
   "stfq%U0%X0 %1,%0")
 
+;; TLS support.
+
+;; "b" output constraint here and on tls_ld to support tls linker optimization.
+(define_insn "tls_gd_32"
+  [(set (match_operand:SI 0 "register_operand" "=b")
+	(unspec:SI [(match_operand:SI 1 "register_operand" "b")
+		    (match_operand:SI 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSGD))]
+  "HAVE_AS_TLS && !TARGET_64BIT"
+  "addi %0,%1,%2@got@tlsgd")
+
+(define_insn "tls_gd_64"
+  [(set (match_operand:DI 0 "register_operand" "=b")
+	(unspec:DI [(match_operand:DI 1 "register_operand" "b")
+		    (match_operand:DI 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSGD))]
+  "HAVE_AS_TLS && TARGET_64BIT"
+  "addi %0,%1,%2@got@tlsgd")
+
+(define_insn "tls_ld_32"
+  [(set (match_operand:SI 0 "register_operand" "=b")
+	(unspec:SI [(match_operand:SI 1 "register_operand" "b")]
+		   UNSPEC_TLSLD))]
+  "HAVE_AS_TLS && !TARGET_64BIT"
+  "addi %0,%1,%&@got@tlsld")
+
+(define_insn "tls_ld_64"
+  [(set (match_operand:DI 0 "register_operand" "=b")
+	(unspec:DI [(match_operand:DI 1 "register_operand" "b")]
+		   UNSPEC_TLSLD))]
+  "HAVE_AS_TLS && TARGET_64BIT"
+  "addi %0,%1,%&@got@tlsld")
+
+(define_insn "tls_dtprel_32"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(unspec:SI [(match_operand:SI 1 "register_operand" "b")
+		    (match_operand:SI 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSDTPREL))]
+  "HAVE_AS_TLS && !TARGET_64BIT"
+  "addi %0,%1,%2@dtprel")
+
+(define_insn "tls_dtprel_64"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(unspec:DI [(match_operand:DI 1 "register_operand" "b")
+		    (match_operand:DI 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSDTPREL))]
+  "HAVE_AS_TLS && TARGET_64BIT"
+  "addi %0,%1,%2@dtprel")
+
+(define_insn "tls_dtprel_ha_32"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(unspec:SI [(match_operand:SI 1 "register_operand" "b")
+		    (match_operand:SI 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSDTPRELHA))]
+  "HAVE_AS_TLS && !TARGET_64BIT"
+  "addis %0,%1,%2@dtprel@ha")
+
+(define_insn "tls_dtprel_ha_64"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(unspec:DI [(match_operand:DI 1 "register_operand" "b")
+		    (match_operand:DI 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSDTPRELHA))]
+  "HAVE_AS_TLS && TARGET_64BIT"
+  "addis %0,%1,%2@dtprel@ha")
+
+(define_insn "tls_dtprel_lo_32"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(unspec:SI [(match_operand:SI 1 "register_operand" "b")
+		    (match_operand:SI 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSDTPRELLO))]
+  "HAVE_AS_TLS && !TARGET_64BIT"
+  "addi %0,%1,%2@dtprel@l")
+
+(define_insn "tls_dtprel_lo_64"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(unspec:DI [(match_operand:DI 1 "register_operand" "b")
+		    (match_operand:DI 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSDTPRELLO))]
+  "HAVE_AS_TLS && TARGET_64BIT"
+  "addi %0,%1,%2@dtprel@l")
+
+(define_insn "tls_got_dtprel_32"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(unspec:SI [(match_operand:SI 1 "register_operand" "b")
+		    (match_operand:SI 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSGOTDTPREL))]
+  "HAVE_AS_TLS && !TARGET_64BIT"
+  "lwz %0,%2@got@dtprel(%1)")
+
+(define_insn "tls_got_dtprel_64"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(unspec:DI [(match_operand:DI 1 "register_operand" "b")
+		    (match_operand:DI 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSGOTDTPREL))]
+  "HAVE_AS_TLS && TARGET_64BIT"
+  "ld %0,%2@got@dtprel(%1)")
+
+(define_insn "tls_tprel_32"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(unspec:SI [(match_operand:SI 1 "register_operand" "b")
+		    (match_operand:SI 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSTPREL))]
+  "HAVE_AS_TLS && !TARGET_64BIT"
+  "addi %0,%1,%2@tprel")
+
+(define_insn "tls_tprel_64"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(unspec:DI [(match_operand:DI 1 "register_operand" "b")
+		    (match_operand:DI 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSTPREL))]
+  "HAVE_AS_TLS && TARGET_64BIT"
+  "addi %0,%1,%2@tprel")
+
+(define_insn "tls_tprel_ha_32"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(unspec:SI [(match_operand:SI 1 "register_operand" "b")
+		    (match_operand:SI 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSTPRELHA))]
+  "HAVE_AS_TLS && !TARGET_64BIT"
+  "addis %0,%1,%2@tprel@ha")
+
+(define_insn "tls_tprel_ha_64"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(unspec:DI [(match_operand:DI 1 "register_operand" "b")
+		    (match_operand:DI 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSTPRELHA))]
+  "HAVE_AS_TLS && TARGET_64BIT"
+  "addis %0,%1,%2@tprel@ha")
+
+(define_insn "tls_tprel_lo_32"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(unspec:SI [(match_operand:SI 1 "register_operand" "b")
+		    (match_operand:SI 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSTPRELLO))]
+  "HAVE_AS_TLS && !TARGET_64BIT"
+  "addi %0,%1,%2@tprel@l")
+
+(define_insn "tls_tprel_lo_64"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(unspec:DI [(match_operand:DI 1 "register_operand" "b")
+		    (match_operand:DI 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSTPRELLO))]
+  "HAVE_AS_TLS && TARGET_64BIT"
+  "addi %0,%1,%2@tprel@l")
+
+;; "b" output contraint here and on tls_tls input to support linker tls
+;; optimization.  The linker may edit the instructions emitted by a
+;; tls_got_tprel/tls_tls pair to addis,addi.
+(define_insn "tls_got_tprel_32"
+  [(set (match_operand:SI 0 "register_operand" "=b")
+	(unspec:SI [(match_operand:SI 1 "register_operand" "b")
+		    (match_operand:SI 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSGOTTPREL))]
+  "HAVE_AS_TLS && !TARGET_64BIT"
+  "lwz %0,%2@got@tprel(%1)")
+
+(define_insn "tls_got_tprel_64"
+  [(set (match_operand:DI 0 "register_operand" "=b")
+	(unspec:DI [(match_operand:DI 1 "register_operand" "b")
+		    (match_operand:DI 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSGOTTPREL))]
+  "HAVE_AS_TLS && TARGET_64BIT"
+  "ld %0,%2@got@tprel(%1)")
+
+(define_insn "tls_tls_32"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(unspec:SI [(match_operand:SI 1 "register_operand" "b")
+		    (match_operand:SI 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSTLS))]
+  "HAVE_AS_TLS && !TARGET_64BIT"
+  "add %0,%1,%2@tls")
+
+(define_insn "tls_tls_64"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(unspec:DI [(match_operand:DI 1 "register_operand" "b")
+		    (match_operand:DI 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSTLS))]
+  "HAVE_AS_TLS && TARGET_64BIT"
+  "add %0,%1,%2@tls")
+
 ;; Next come insns related to the calling sequence.
 ;;
 ;; First, an insn to allocate new stack space for dynamic use (e.g., alloca).
@@ -9820,7 +10027,7 @@
 
 (define_insn "load_toc_aix_si"
   [(parallel [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
-		   (unspec:SI [(const_int 0)] 7))
+		   (unspec:SI [(const_int 0)] UNSPEC_TOC))
 	      (use (reg:SI 2))])]
   "DEFAULT_ABI == ABI_AIX && TARGET_32BIT"
   "*
@@ -9835,7 +10042,7 @@
 
 (define_insn "load_toc_aix_di"
   [(parallel [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
-		   (unspec:DI [(const_int 0)] 7))
+		   (unspec:DI [(const_int 0)] UNSPEC_TOC))
 	      (use (reg:DI 2))])]
   "DEFAULT_ABI == ABI_AIX && TARGET_64BIT"
   "*
@@ -9857,7 +10064,7 @@
 
 (define_insn "load_toc_v4_pic_si"
   [(set (match_operand:SI 0 "register_operand" "=l")
-	(unspec:SI [(const_int 0)] 7))]
+	(unspec:SI [(const_int 0)] UNSPEC_TOC))]
   "DEFAULT_ABI == ABI_V4 && flag_pic == 1 && TARGET_32BIT"
   "bl _GLOBAL_OFFSET_TABLE_@local-4"
   [(set_attr "type" "branch")
@@ -9866,7 +10073,7 @@
 (define_insn "load_toc_v4_PIC_1"
   [(set (match_operand:SI 0 "register_operand" "=l")
 	(match_operand:SI 1 "immediate_operand" "s"))
-   (unspec [(match_dup 1)] 7)]
+   (use (unspec [(match_dup 1)] UNSPEC_TOC))]
   "TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2"
   "bcl 20,31,%1\\n%1:"
   [(set_attr "type" "branch")
@@ -9875,9 +10082,10 @@
 (define_insn "load_toc_v4_PIC_1b"
   [(set (match_operand:SI 0 "register_operand" "=l")
 	(match_operand:SI 1 "immediate_operand" "s"))
-   (unspec [(match_dup 1) (match_operand 2 "immediate_operand" "s")] 6)]
+   (use (unspec [(match_dup 1) (match_operand 2 "immediate_operand" "s")]
+		UNSPEC_TOCPTR))]
   "TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2"
-  "bcl 20,31,%1\\n\\t.long %2-%1+4\\n%1:"
+  "bcl 20,31,%1+4\\n%1:\\n\\t.long %2-%1"
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
 
@@ -9892,7 +10100,8 @@
 
 (define_insn "load_macho_picbase"
   [(set (match_operand:SI 0 "register_operand" "=l")
-	(unspec:SI [(match_operand:SI 1 "immediate_operand" "s")] 15))]
+	(unspec:SI [(match_operand:SI 1 "immediate_operand" "s")]
+		   UNSPEC_LD_MPIC))]
   "(DEFAULT_ABI == ABI_DARWIN) && flag_pic"
   "bcl 20,31,%1\\n%1:"
   [(set_attr "type" "branch")
@@ -9903,7 +10112,7 @@
 	(plus:SI (match_operand:SI 1 "gpc_reg_operand" "r")
 		 (unspec:SI [(match_operand:SI 2 "immediate_operand" "s")
 			     (match_operand:SI 3 "immediate_operand" "s")]
-			    16)))]
+			    UNSPEC_MPIC_CORRECT)))]
   "DEFAULT_ABI == ABI_DARWIN"
   "addis %0,%1,ha16(%2-%3)\n\taddi %0,%0,lo16(%2-%3)"
   [(set_attr "length" "8")])
@@ -10697,7 +10906,7 @@
 ;; all of memory.  This blocks insns from being moved across this point.
 
 (define_insn "blockage"
-  [(unspec_volatile [(const_int 0)] 0)]
+  [(unspec_volatile [(const_int 0)] UNSPECV_BLOCK)]
   ""
   "")
 
@@ -11123,7 +11332,7 @@
 ;; Same as above, but get the OV/ORDERED bit.
 (define_insn "move_from_CR_ov_bit"
   [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
-	(unspec:SI [(match_operand 1 "cc_reg_operand" "y")] 724))]
+	(unspec:SI [(match_operand 1 "cc_reg_operand" "y")] UNSPEC_MV_CR_OV))]
   "TARGET_ISEL"
   "%D1mfcr %0\;{rlinm|rlwinm} %0,%0,%t1,1"
   [(set_attr "type" "mfcr")
@@ -14185,7 +14394,8 @@
 (define_insn "movesi_from_cr"
   [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
         (unspec:SI [(reg:CC 68) (reg:CC 69) (reg:CC 70) (reg:CC 71) 
-		    (reg:CC 72)	(reg:CC 73) (reg:CC 74) (reg:CC 75)] 19))]
+		    (reg:CC 72)	(reg:CC 73) (reg:CC 74) (reg:CC 75)]
+		   UNSPEC_MOVESI_FROM_CR))]
   ""
   "mfcr %0"
   [(set_attr "type" "mfcr")])
@@ -14219,7 +14429,7 @@
 ; not be moved over stores to stack memory.
 (define_insn "stack_tie"
   [(set (match_operand:BLK 0 "memory_operand" "+m")
-        (unspec:BLK [(match_dup 0)] 5))]
+        (unspec:BLK [(match_dup 0)] UNSPEC_TIE))]
   ""
   ""
   [(set_attr "length" "0")])
@@ -14241,7 +14451,7 @@
 (define_expand "movsi_to_cr_one"
   [(set (match_operand:CC 0 "cc_reg_operand" "=y")
         (unspec:CC [(match_operand:SI 1 "gpc_reg_operand" "r")
-		    (match_dup 2)] 20))]
+		    (match_dup 2)] UNSPEC_MOVESI_TO_CR))]
   ""
   "operands[2] = GEN_INT (1 << (75 - REGNO (operands[0])));")
 
@@ -14250,7 +14460,7 @@
 		   [(set (match_operand:CC 1 "cc_reg_operand" "=y")
 			 (unspec:CC [(match_operand:SI 2 "gpc_reg_operand" "r")
 				     (match_operand 3 "immediate_operand" "n")]
-			 20))])]
+			 	    UNSPEC_MOVESI_TO_CR))])]
  ""
  "*
 {
@@ -14266,7 +14476,8 @@
 (define_insn "*mtcrfsi"
   [(set (match_operand:CC 0 "cc_reg_operand" "=y")
         (unspec:CC [(match_operand:SI 1 "gpc_reg_operand" "r")
-		    (match_operand 2 "immediate_operand" "n")] 20))]
+		    (match_operand 2 "immediate_operand" "n")]
+		   UNSPEC_MOVESI_TO_CR))]
   "GET_CODE (operands[0]) == REG 
    && CR_REGNO_P (REGNO (operands[0]))
    && GET_CODE (operands[2]) == CONST_INT
@@ -14342,19 +14553,22 @@
 
 ; We can't expand this before we know where the link register is stored.
 (define_insn "eh_set_lr_si"
-  [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")] 9)
+  [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")]
+		    UNSPECV_EH_RR)
    (clobber (match_scratch:SI 1 "=&b"))]
   "TARGET_32BIT"
   "#")
 
 (define_insn "eh_set_lr_di"
-  [(unspec_volatile [(match_operand:DI 0 "register_operand" "r")] 9)
+  [(unspec_volatile [(match_operand:DI 0 "register_operand" "r")]
+		    UNSPECV_EH_RR)
    (clobber (match_scratch:DI 1 "=&b"))]
   "TARGET_64BIT"
   "#")
 
 (define_split
-  [(unspec_volatile [(match_operand 0 "register_operand" "")] 9)
+  [(unspec_volatile [(match_operand 0 "register_operand" "")]
+		    UNSPECV_EH_RR)
    (clobber (match_scratch 1 ""))]
   "reload_completed"
   [(const_int 0)]
Index: gcc/config/rs6000/sysv4.h
===================================================================
RCS file: /home/janis/gcc_rsync/gcc-cvs/gcc/gcc/config/rs6000/sysv4.h,v
retrieving revision 1.118
diff -u -p -r1.118 sysv4.h
--- gcc/config/rs6000/sysv4.h	23 Mar 2003 22:44:04 -0000	1.118
+++ gcc/config/rs6000/sysv4.h	11 Apr 2003 15:48:55 -0000
@@ -80,12 +80,15 @@ extern enum rs6000_sdata_type rs6000_sda
 /* Strings provided by SUBTARGET_OPTIONS */
 extern const char *rs6000_abi_name;
 extern const char *rs6000_sdata_name;
+extern const char *rs6000_tls_size_string; /* For -mtls-size= */
 
 /* Override rs6000.h definition.  */
 #undef	SUBTARGET_OPTIONS
-#define	SUBTARGET_OPTIONS						\
-  { "call-",  &rs6000_abi_name, N_("Select ABI calling convention") },	\
-  { "sdata=", &rs6000_sdata_name, N_("Select method for sdata handling") }
+#define	SUBTARGET_OPTIONS						    \
+  { "call-",  &rs6000_abi_name, N_("Select ABI calling convention") },      \
+  { "sdata=", &rs6000_sdata_name, N_("Select method for sdata handling") }, \
+  { "tls-size=", &rs6000_tls_size_string,				    \
+   N_("Specify bit size of immediate TLS offsets") }
 
 /* Max # of bytes for variables to automatically be put into the .sdata
    or .sdata2 sections.  */
@@ -791,6 +794,8 @@ do {						\
   const char *_name = NAME;			\
   if (*_name == '@')				\
     _name++;					\
+  else if (*_name == '%')			\
+    _name += 2;					\
  						\
   if (*_name == '*')				\
     fprintf (FILE, "%s", _name + 1);		\



More information about the Gcc-patches mailing list