This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] TLS support for powerpc/powerpc64 (take 2)


This patch adds support for Thread Local Storage (TLS) for powerpc-linux
and powerpc64-linux.  It's been tested with bootstrap and regtest on
powerpc-linux, cross build and regtest on powerpc64-linux.  The powerpc64
testing didn't include Java due to unrelated problems, but earlier
testing showed no problems with Java.

The changes are mostly limited to GNU/Linux targets, but it would be a
good idea for people with access to AIX and Darwin systems to try it out
and report any problems.

2003-05-09  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/rs6000-protos.h: Update.
	* config/rs6000/rs6000.c (rs6000_tls_size): New.
	(rs6000_tls_size_string): New.
	(rs6000_parse_tls_size_option): New.
	(rs6000_legitimize_tls_address): New.
	(rs6000_tls_get_addr): New.
	(rs6000_got_sym): New.
	(rs6000_tls_symbol_ref): New.
	(rs6000_tls_symbol_ref_1): New.
	(rs6000_get_some_local_dynamic_name): New.
	(rs6000_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.
	(print_operand): Handle TLS symbols.
	(uses_TOC): Handle TLS symbols.
	(rs6000_emit_prologue): Use symbol for unspec constant.
	* 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 (load_toc_v4_PIC_1, load_toc_v4_PIC_1b):
	Support TLS.
	(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.

Index: gcc/configure.in
===================================================================
RCS file: /home/janis/gcc_rsync/gcc-cvs/gcc/gcc/configure.in,v
retrieving revision 1.666
diff -u -p -r1.666 configure.in
--- gcc/configure.in	2 May 2003 07:49:26 -0000	1.666
+++ gcc/configure.in	7 May 2003 23:28:39 -0000
@@ -2123,6 +2123,64 @@ 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=14
+	;;
+  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=14
+	;;
   s390-*-*)
     conftest_s='
 	.section ".tdata","awT",@progbits
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.52
diff -u -p -r1.52 rs6000-protos.h
--- gcc/config/rs6000/rs6000-protos.h	4 May 2003 00:33:48 -0000	1.52
+++ gcc/config/rs6000/rs6000-protos.h	7 May 2003 23:28:40 -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.471
diff -u -p -r1.471 rs6000.c
--- gcc/config/rs6000/rs6000.c	5 May 2003 19:33:48 -0000	1.471
+++ gcc/config/rs6000/rs6000.c	7 May 2003 23:28:40 -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
@@ -286,6 +290,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));
@@ -295,6 +300,12 @@ 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 rs6000_legitimize_tls_address PARAMS ((rtx, enum tls_model));
+static rtx rs6000_tls_get_addr PARAMS ((void));
+static rtx rs6000_got_sym PARAMS ((void));
+static inline int rs6000_tls_symbol_ref_1 PARAMS ((rtx *, void *));
+static const char *rs6000_get_some_local_dynamic_name PARAMS ((void));
+static int rs6000_get_some_local_dynamic_name_1 PARAMS ((rtx *, void *));
 
 /* Hash table stuff for keeping track of TOC entries.  */
 
@@ -408,6 +419,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
@@ -727,6 +744,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
@@ -864,6 +884,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;
@@ -2236,7 +2271,9 @@ constant_pool_expr_1 (op, have_sym, have
   switch (GET_CODE(op)) 
     {
     case SYMBOL_REF:
-      if (CONSTANT_POOL_ADDRESS_P (op))
+      if (SYMBOL_REF_TLS_MODEL (op))
+	return 0;
+      else if (CONSTANT_POOL_ADDRESS_P (op))
 	{
 	  if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (op), Pmode))
 	    {
@@ -2462,6 +2499,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 = SYMBOL_REF_TLS_MODEL (x);
+      if (model != 0)
+	return rs6000_legitimize_tls_address (x, model);
+    }
+
   if (GET_CODE (x) == PLUS 
       && GET_CODE (XEXP (x, 0)) == REG
       && GET_CODE (XEXP (x, 1)) == CONST_INT
@@ -2562,6 +2606,250 @@ 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
+rs6000_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;
+}
+
+/* Return 1 if X is a SYMBOL_REF for a TLS symbol.  This is used in
+   instruction definitions.  */
+
+int
+rs6000_tls_symbol_ref (x, mode)
+     rtx x;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  if (GET_CODE (x) != SYMBOL_REF)
+    return 0;
+  return SYMBOL_REF_TLS_MODEL (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 inline int
+rs6000_tls_symbol_ref_1 (x, data)
+     rtx *x;
+     void *data ATTRIBUTE_UNUSED;
+{
+  if (GET_CODE (*x) != SYMBOL_REF)
+    return 0;
+  return SYMBOL_REF_TLS_MODEL (*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.  */
@@ -2730,6 +3018,8 @@ rs6000_legitimate_address (mode, x, reg_
     rtx x;
     int reg_ok_strict;
 {
+  if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (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)
@@ -3051,6 +3341,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 = SYMBOL_REF_TLS_MODEL (operands[1]);
+      if (model != 0)
+	operands[1] = rs6000_legitimize_tls_address (operands[1], model);
+    }
+
   /* Handle the case where reload calls us with an invalid address.  */
   if (reload_in_progress && mode == Pmode
       && (! general_operand (operands[1], mode)
@@ -7825,6 +8124,46 @@ 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 *
+rs6000_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),
+			 rs6000_get_some_local_dynamic_name_1, 0))
+      return cfun->machine->some_ld_name;
+
+  abort ();
+}
+
+static int
+rs6000_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 (SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC)
+	{
+	  cfun->machine->some_ld_name = str;
+	  return 1;
+	}
+    }
+
+  return 0;
+}
+
 /* Print an operand.  Recognize special options, documented below.  */
 
 #if TARGET_ELF
@@ -8439,6 +8778,10 @@ print_operand (file, x, code)
 	output_addr_const (file, x);
       return;
 
+    case '&':
+      assemble_name (file, rs6000_get_some_local_dynamic_name ());
+      return;
+
     default:
       output_operand_lossage ("invalid %%xn code");
     }
@@ -10207,27 +10550,35 @@ get_TOC_alias_set ()
 }   
 
 /* This retuns nonzero if the current function uses the TOC.  This is
-   determined by the presence of (unspec ... UNSPEC_TOC), which is
-   generated by the various load_toc_* patterns.  */
+   determined by the presence of (unspec ... UNSPEC_TOC) or
+   use (unspec ... UNSPEC_TOC), which are 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) == UNSPEC_TOC)
-		  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
@@ -11093,7 +11444,7 @@ rs6000_emit_prologue ()
 	  && regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM]))
   {
     /* If emit_load_toc_table will use the link register, we need to save
-       it.  We use R11 for this purpose because emit_load_toc_table
+       it.  We use R12 for this purpose because emit_load_toc_table
        can use register 0.  This allows us to use a plain 'blr' to return
        from the procedure more often.  */
     int save_LR_around_toc_setup = (TARGET_ELF
@@ -11102,14 +11453,14 @@ rs6000_emit_prologue ()
 				    && ! info->lr_save_p
 				    && EXIT_BLOCK_PTR->pred != NULL);
     if (save_LR_around_toc_setup)
-      emit_move_insn (gen_rtx_REG (Pmode, 11), 
-		      gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
-    
-    rs6000_emit_load_toc_table (TRUE);
-
-    if (save_LR_around_toc_setup)
-      emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM), 
-		      gen_rtx_REG (Pmode, 11));
+      {
+	rtx lr = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
+	rs6000_maybe_dead (emit_move_insn (frame_ptr_rtx, lr));
+	rs6000_emit_load_toc_table (TRUE);
+	rs6000_maybe_dead (emit_move_insn (lr, frame_ptr_rtx));
+      }
+    else
+      rs6000_emit_load_toc_table (TRUE);
   }
 
 #if TARGET_MACHO
@@ -13036,7 +13387,6 @@ rs6000_longcall_ref (call_ref)
 
   return force_reg (Pmode, call_ref);
 }
-
 
 #ifdef USING_ELFOS_H
 
Index: gcc/config/rs6000/rs6000.h
===================================================================
RCS file: /home/janis/gcc_rsync/gcc-cvs/gcc/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.271
diff -u -p -r1.271 rs6000.h
--- gcc/config/rs6000/rs6000.h	5 May 2003 14:33:00 -0000	1.271
+++ gcc/config/rs6000/rs6000.h	7 May 2003 23:28:40 -0000
@@ -211,6 +211,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__)
@@ -1675,6 +1679,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.
@@ -2643,7 +2650,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.  */
 
@@ -2674,6 +2681,7 @@ extern char rs6000_reg_names[][8];	/* re
   {"reg_or_logical_cint_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \
   {"got_operand", {SYMBOL_REF, CONST, LABEL_REF}},			   \
   {"got_no_const_operand", {SYMBOL_REF, LABEL_REF}},			   \
+  {"rs6000_tls_symbol_ref", {SYMBOL_REF}},				   \
   {"easy_fp_constant", {CONST_DOUBLE}},					   \
   {"easy_vector_constant", {CONST_VECTOR}},				   \
   {"easy_vector_constant_add_self", {CONST_VECTOR}},			   \
@@ -2697,6 +2705,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.252
diff -u -p -r1.252 rs6000.md
--- gcc/config/rs6000/rs6000.md	3 May 2003 23:13:57 -0000	1.252
+++ gcc/config/rs6000/rs6000.md	7 May 2003 23:28:40 -0000
@@ -9718,6 +9718,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).
@@ -9895,7 +10075,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)] UNSPEC_TOC)]
+   (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")
@@ -9904,10 +10084,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")]
-   	   UNSPEC_TOCPTR)]
+   (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")])
 
Index: gcc/config/rs6000/sysv4.h
===================================================================
RCS file: /home/janis/gcc_rsync/gcc-cvs/gcc/gcc/config/rs6000/sysv4.h,v
retrieving revision 1.124
diff -u -p -r1.124 sysv4.h
--- gcc/config/rs6000/sysv4.h	5 May 2003 22:57:58 -0000	1.124
+++ gcc/config/rs6000/sysv4.h	7 May 2003 23:28:40 -0000
@@ -79,12 +79,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"), 0},	\
-  { "sdata=", &rs6000_sdata_name, N_("Select method for sdata handling"), 0}
+  { "sdata=", &rs6000_sdata_name, N_("Select method for sdata handling"), 0},	\
+  { "tls-size=", &rs6000_tls_size_string,					\
+   N_("Specify bit size of immediate TLS offsets"), 0 }
 
 /* Max # of bytes for variables to automatically be put into the .sdata
    or .sdata2 sections.  */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]