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]

RFA: MIPS TLS support


This patch adds TLS support for MIPS.  I don't have a whole lot to say about
it, except that the MIPS backend symbol classification bits are really neat,
and the mode macros in the md file are also really neat.

The TLS ABI defines the thread pointer access instruction as "rdhwr $3,
$29".  It has to be that particular instruction, because a fast-path
emulation is much more efficient when the destination register is fixed.
So I needed to introduce a new register class for $v1; thank you, Ian,
for sanity checking me while I worked out the reason I couldn't hard code
(reg:P 3) in the instruction.  [Reload won't bother this, but the RTL loop
optimizer will.]

OK for 4.1?

-- 
Daniel Jacobowitz
CodeSourcery, LLC

2005-03-09  Daniel Jacobowitz  <dan@codesourcery.com>

	* configure.ac: Check for MIPS TLS.
	* configure: Regenerated.
	* config/mips/mips-protos.h (enum mips_symbol_type): Add
	SYMBOL_TLS_GD, SYMBOL_TLS_LD, SYMBOL_TLS_IE, SYMBOL_TLS_LE.
	(mips_tls_operand_p): New prototype.
	* config/mips/mips.c (TLS_SYMBOL_TYPE_P): Define.
	(mips_regno_to_class): Handle V1_REG.
	(TARGET_HAVE_TLS, TARGET_CANNOT_FORCE_CONST_MEM): Define.
	(mips_classify_symbol, mips_symbolic_constant_p)
	(mips_symbolic_address_p, mips_symbol_insns): Handle TLS symbols.
	(mips_tls_operand_p, mips_tls_get_addr)
	(mips_legitimize_tls_address): New functions.
	(mips_legitimize_address, mips_legitimize_const_move): Call
	mips_legitimize_tls_address.
	(override_options): Handle V1_REG and TLS symbols.
	* config/mips/mips.h (enum reg_class, REG_CLASS_NAMES)
	(REG_CLASS_CONTENTS, GR_REG_CLASS_P): Include V1_REG.
	(mips_char_to_class): Document V1_REG.
	(LEGITIMATE_CONSTANT_P): Use mips_tls_operand_p.
	(HAVE_AS_TLS): Provide default.
	* config/mips/mips.md (UNSPEC_TLS_GD, UNSPEC_TLS_LD)
	(UNSPEC_TLS_DTPREL_HI16, UNSPEC_TLS_IE)
	(UNSPEC_TLS_TPREL_HI16, UNSPEC_TLS_GET_TP): New constants.
	(tls_gd_<mode>, tls_ld_<mode>, tls_dtprel_hi_<mode>)
	(tls_get_tp_<mode>, tls_ie_<mode>, tls_tprel_hi_<mode>): New
	instructions.
	* config/mips/predicates.md (tls_symbol_ref): New predicate.

Index: gcc/gcc/configure
===================================================================
--- gcc.orig/gcc/configure	2005-03-09 10:03:31.000000000 -0500
+++ gcc/gcc/configure	2005-03-09 10:03:32.000000000 -0500
@@ -13670,6 +13670,19 @@ foo:	data8	25
 	tls_first_minor=13
 	tls_as_opt=--fatal-warnings
 	;;
+  mips*-*-*)
+    conftest_s='
+	.section .tdata,"awT",@progbits
+x:
+	.word 2
+	.text
+	lw $25, %call16(__tls_get_addr)($28)
+	addiu $4, $28, %tlsgd(x)
+	jalr $25'
+	tls_first_major=2
+	tls_first_minor=16
+	tls_as_opt=--fatal-warnings
+	;;
   powerpc-*-*)
     conftest_s='
 	.section ".tdata","awT",@progbits
Index: gcc/gcc/configure.ac
===================================================================
--- gcc.orig/gcc/configure.ac	2005-03-09 10:03:31.000000000 -0500
+++ gcc/gcc/configure.ac	2005-03-09 10:03:32.000000000 -0500
@@ -2353,6 +2353,19 @@ foo:	data8	25
 	tls_first_minor=13
 	tls_as_opt=--fatal-warnings
 	;;
+  mips*-*-*)
+    conftest_s='
+	.section .tdata,"awT",@progbits
+x:
+	.word 2
+	.text
+	lw $25, %call16(__tls_get_addr)($28)
+	addiu $4, $28, %tlsgd(x)
+	jalr $25'
+	tls_first_major=2
+	tls_first_minor=16
+	tls_as_opt=--fatal-warnings
+	;;
   powerpc-*-*)
     conftest_s='
 	.section ".tdata","awT",@progbits
Index: gcc/gcc/config/mips/mips-protos.h
===================================================================
--- gcc.orig/gcc/config/mips/mips-protos.h	2005-02-13 21:49:14.000000000 -0500
+++ gcc/gcc/config/mips/mips-protos.h	2005-03-09 10:03:32.000000000 -0500
@@ -61,6 +61,13 @@ Boston, MA 02111-1307, USA.  */
        An UNSPEC wrapper around a function's address.  It represents the
        offset of _gp from the start of the function.
 
+   SYMBOL_TLS_GD
+   SYMBOL_TLS_LD
+   SYMBOL_TLS_IE
+   SYMBOL_TLS_LE
+       The symbol refers to thread-local data, with GD, LD, IE or LE
+       model respectively.
+
    SYMBOL_64_HIGH
        For a 64-bit symbolic address X, this is the value of
        (%highest(X) << 16) + %higher(X).
@@ -82,6 +89,10 @@ enum mips_symbol_type {
   SYMBOL_GOTOFF_GLOBAL,
   SYMBOL_GOTOFF_CALL,
   SYMBOL_GOTOFF_LOADGP,
+  SYMBOL_TLS_GD,
+  SYMBOL_TLS_LD,
+  SYMBOL_TLS_IE,
+  SYMBOL_TLS_LE,
   SYMBOL_64_HIGH,
   SYMBOL_64_MID,
   SYMBOL_64_LOW
@@ -102,6 +113,7 @@ extern bool mips_legitimate_address_p (e
 extern rtx mips_unspec_address (rtx, enum mips_symbol_type);
 extern bool mips_legitimize_address (rtx *, enum machine_mode);
 extern bool mips_legitimize_move (enum machine_mode, rtx, rtx);
+extern bool mips_tls_operand_p (rtx);
 
 extern int m16_uimm3_b (rtx, enum machine_mode);
 extern int m16_simm4_1 (rtx, enum machine_mode);
Index: gcc/gcc/config/mips/mips.c
===================================================================
--- gcc.orig/gcc/config/mips/mips.c	2005-03-08 17:18:48.000000000 -0500
+++ gcc/gcc/config/mips/mips.c	2005-03-09 10:03:32.000000000 -0500
@@ -71,6 +71,11 @@ Boston, MA 02111-1307, USA.  */
 #define UNSPEC_ADDRESS_TYPE(X) \
   ((enum mips_symbol_type) (XINT (X, 1) - UNSPEC_ADDRESS_FIRST))
 
+/* True if X is a TLS symbol type.  */
+#define TLS_SYMBOL_TYPE_P(X) \
+  ((X) == SYMBOL_TLS_GD || (X) == SYMBOL_TLS_LD			\
+   || (X) == SYMBOL_TLS_IE || (X) == SYMBOL_TLS_LE)
+
 /* The maximum distance between the top of the stack frame and the
    value $sp has when we save & restore registers.
 
@@ -598,7 +603,7 @@ static const char *mips_hi_relocs[NUM_SY
 /* Map hard register number to register class */
 const enum reg_class mips_regno_to_class[] =
 {
-  LEA_REGS,	LEA_REGS,	M16_NA_REGS,	M16_NA_REGS,
+  LEA_REGS,	LEA_REGS,	M16_NA_REGS,	V1_REG,
   M16_REGS,	M16_REGS,	M16_REGS,	M16_REGS,
   LEA_REGS,	LEA_REGS,	LEA_REGS,	LEA_REGS,
   LEA_REGS,	LEA_REGS,	LEA_REGS,	LEA_REGS,
@@ -814,6 +819,12 @@ const struct mips_cpu_info mips_cpu_info
 #undef TARGET_EXPAND_BUILTIN
 #define TARGET_EXPAND_BUILTIN mips_expand_builtin
 
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS HAVE_AS_TLS
+
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM mips_tls_operand_p
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF.  */
@@ -832,6 +843,22 @@ mips_classify_symbol (rtx x)
 
   gcc_assert (GET_CODE (x) == SYMBOL_REF);
 
+  switch (SYMBOL_REF_TLS_MODEL (x))
+    {
+    case 0:
+      break;
+    case TLS_MODEL_GLOBAL_DYNAMIC:
+      return SYMBOL_TLS_GD;
+    case TLS_MODEL_LOCAL_DYNAMIC:
+      return SYMBOL_TLS_LD;
+    case TLS_MODEL_INITIAL_EXEC:
+      return SYMBOL_TLS_IE;
+    case TLS_MODEL_LOCAL_EXEC:
+      return SYMBOL_TLS_LE;
+    default:
+      abort ();
+    }
+
   if (CONSTANT_POOL_ADDRESS_P (x))
     {
       if (TARGET_MIPS16)
@@ -990,6 +1017,10 @@ mips_symbolic_constant_p (rtx x, enum mi
     case SYMBOL_GOTOFF_GLOBAL:
     case SYMBOL_GOTOFF_CALL:
     case SYMBOL_GOTOFF_LOADGP:
+    case SYMBOL_TLS_GD:
+    case SYMBOL_TLS_LD:
+    case SYMBOL_TLS_IE:
+    case SYMBOL_TLS_LE:
       return false;
     }
   gcc_unreachable ();
@@ -1094,6 +1125,10 @@ mips_symbolic_address_p (enum mips_symbo
     case SYMBOL_64_HIGH:
     case SYMBOL_64_MID:
     case SYMBOL_64_LOW:
+    case SYMBOL_TLS_GD:
+    case SYMBOL_TLS_LD:
+    case SYMBOL_TLS_IE:
+    case SYMBOL_TLS_LE:
       return true;
     }
   gcc_unreachable ();
@@ -1151,6 +1186,17 @@ mips_classify_address (struct mips_addre
       return false;
     }
 }
+
+/* Return true if X is a thread-local symbol.  */
+
+bool
+mips_tls_operand_p (rtx x)
+{
+  if (GET_CODE (x) != SYMBOL_REF)
+    return false;
+
+  return !!SYMBOL_REF_TLS_MODEL (x);
+}
 
 /* Return the number of instructions needed to load a symbol of the
    given type into a register.  If valid in an address, the same number
@@ -1222,6 +1268,16 @@ mips_symbol_insns (enum mips_symbol_type
     case SYMBOL_64_LOW:
       /* Check whether the offset is a 16- or 32-bit value.  */
       return mips_split_p[type] ? 2 : 1;
+
+    case SYMBOL_TLS_GD:
+    case SYMBOL_TLS_IE:
+      return 3;
+
+    case SYMBOL_TLS_LE:
+      return 4;
+
+    case SYMBOL_TLS_LD:
+      return 6;
     }
   gcc_unreachable ();
 }
@@ -1518,6 +1574,131 @@ mips_add_offset (rtx temp, rtx reg, HOST
   return plus_constant (reg, offset);
 }
 
+/* Construct the SYMBOL_REF for the tls_get_addr function.  */
+
+static GTY(()) rtx mips_tls_symbol;
+static rtx
+mips_tls_get_addr (void)
+{
+  if (!mips_tls_symbol)
+    mips_tls_symbol = init_one_libfunc ("__tls_get_addr");
+
+  return mips_tls_symbol;
+}
+
+/* Generate the code to access a TLS SYMBOL_REF.  */
+
+static rtx
+mips_legitimize_tls_address (rtx loc)
+{
+  rtx dest, insn, v0, v1, a0, gp, tga, tmp1, tmp2, eqv;
+
+  if (TARGET_MIPS16)
+    sorry ("mips16 TLS");
+
+  dest = gen_reg_rtx (Pmode);
+  v0 = gen_rtx_REG (Pmode, GP_RETURN);
+  v1 = gen_rtx_REG (Pmode, GP_RETURN + 1);
+  a0 = gen_rtx_REG (Pmode, GP_ARG_FIRST);
+  gp = gen_rtx_REG (Pmode, GLOBAL_POINTER_REGNUM);
+
+  switch (SYMBOL_REF_TLS_MODEL (loc))
+    {
+    case TLS_MODEL_GLOBAL_DYNAMIC:
+      start_sequence ();
+      if (Pmode == DImode)
+	emit_insn (gen_tls_gd_di (a0, gp, loc));
+      else
+	emit_insn (gen_tls_gd_si (a0, gp, loc));
+      tga = gen_rtx_MEM (Pmode, mips_tls_get_addr ());
+      insn = gen_call_value (v0, tga, const0_rtx, const0_rtx);
+      insn = emit_call_insn (insn);
+      CONST_OR_PURE_CALL_P (insn) = 1;
+      use_reg (&CALL_INSN_FUNCTION_USAGE (insn), v0);
+      use_reg (&CALL_INSN_FUNCTION_USAGE (insn), a0);
+      insn = get_insns ();
+      end_sequence ();
+      emit_libcall_block (insn, dest, v0, loc);
+      break;
+
+    case TLS_MODEL_LOCAL_DYNAMIC:
+      start_sequence ();
+      if (Pmode == DImode)
+	emit_insn (gen_tls_ld_di (a0, gp, loc));
+      else
+	emit_insn (gen_tls_ld_si (a0, gp, loc));
+      tga = gen_rtx_MEM (Pmode, mips_tls_get_addr ());
+      insn = gen_call_value (v0, tga, const0_rtx, const0_rtx);
+      insn = emit_call_insn (insn);
+      CONST_OR_PURE_CALL_P (insn) = 1;
+      use_reg (&CALL_INSN_FUNCTION_USAGE (insn), v0);
+      use_reg (&CALL_INSN_FUNCTION_USAGE (insn), a0);
+      insn = get_insns ();
+      end_sequence ();
+      tmp1 = gen_reg_rtx (Pmode);
+      eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
+			    UNSPEC_TLS_LD);
+      emit_libcall_block (insn, tmp1, v0, eqv);
+
+      tmp2 = gen_reg_rtx (Pmode);
+      if (Pmode == DImode)
+	{
+	  emit_insn (gen_tls_dtprel_hi_di (tmp2, loc));
+	  emit_insn (gen_adddi3 (dest, tmp2, tmp1));
+	}
+      else
+	{
+	  emit_insn (gen_tls_dtprel_hi_si (tmp2, loc));
+	  emit_insn (gen_addsi3 (dest, tmp2, tmp1));
+	}
+      eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, loc),
+			    UNSPEC_ADDRESS_FIRST + SYMBOL_TLS_LD);
+      eqv = gen_rtx_CONST (Pmode, eqv);
+      dest = gen_rtx_LO_SUM (Pmode, dest, eqv);
+      break;
+
+    case TLS_MODEL_INITIAL_EXEC:
+      tmp1 = gen_reg_rtx (Pmode);
+      if (Pmode == DImode)
+	{
+	  emit_insn (gen_tls_get_tp_di (v1));
+	  emit_insn (gen_tls_ie_di (tmp1, gp, loc));
+	  emit_insn (gen_adddi3 (dest, tmp1, v1));
+	}
+      else
+	{
+	  emit_insn (gen_tls_get_tp_si (v1));
+	  emit_insn (gen_tls_ie_si (tmp1, gp, loc));
+	  emit_insn (gen_addsi3 (dest, tmp1, v1));
+	}
+      break;
+
+    case TLS_MODEL_LOCAL_EXEC:
+      tmp1 = gen_reg_rtx (Pmode);
+      if (Pmode == DImode)
+	{
+	  emit_insn (gen_tls_get_tp_di (v1));
+	  emit_insn (gen_tls_tprel_hi_di (tmp1, loc));
+	  emit_insn (gen_adddi3 (dest, tmp1, v1));
+	}
+      else
+	{
+	  emit_insn (gen_tls_get_tp_si (v1));
+	  emit_insn (gen_tls_tprel_hi_si (tmp1, loc));
+	  emit_insn (gen_addsi3 (dest, tmp1, v1));
+	}
+      eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, loc),
+			    UNSPEC_ADDRESS_FIRST + SYMBOL_TLS_LE);
+      eqv = gen_rtx_CONST (Pmode, eqv);
+      dest = gen_rtx_LO_SUM (Pmode, dest, eqv);
+      break;
+
+    default:
+      abort ();
+    }
+
+  return dest;
+}
 
 /* This function is used to implement LEGITIMIZE_ADDRESS.  If *XLOC can
    be legitimized in a way that the generic machinery might not expect,
@@ -1534,7 +1715,10 @@ mips_legitimize_address (rtx *xloc, enum
       && mips_symbolic_address_p (symbol_type, mode)
       && mips_split_p[symbol_type])
     {
-      *xloc = mips_split_symbol (0, *xloc);
+      if (TLS_SYMBOL_TYPE_P (symbol_type))
+	*xloc = mips_legitimize_tls_address (*xloc);
+      else
+	*xloc = mips_split_symbol (0, *xloc);
       return true;
     }
 
@@ -1707,12 +1891,20 @@ mips_legitimize_const_move (enum machine
   /* See if the symbol can be split.  For mips16, this is often worse than
      forcing it in the constant pool since it needs the single-register form
      of addiu or daddiu.  */
-  if (!TARGET_MIPS16
-      && mips_symbolic_constant_p (src, &symbol_type)
+  if (mips_symbolic_constant_p (src, &symbol_type)
       && mips_split_p[symbol_type])
     {
-      emit_move_insn (dest, mips_split_symbol (dest, src));
-      return;
+      if (TLS_SYMBOL_TYPE_P (symbol_type))
+	{
+	  emit_move_insn (dest, mips_legitimize_tls_address (src));
+	  return;
+	}
+
+      if (!TARGET_MIPS16)
+	{
+	  emit_move_insn (dest, mips_split_symbol (dest, src));
+	  return;
+	}
     }
 
   /* If we have (const (plus symbol offset)), load the symbol first
@@ -4317,6 +4509,7 @@ override_options (void)
 			     GR_REGS);
   mips_char_to_class['e'] = LEA_REGS;
   mips_char_to_class['j'] = PIC_FN_ADDR_REG;
+  mips_char_to_class['v'] = V1_REG;
   mips_char_to_class['y'] = GR_REGS;
   mips_char_to_class['z'] = ST_REGS;
   mips_char_to_class['B'] = COP0_REGS;
@@ -4505,6 +4698,15 @@ override_options (void)
       mips_lo_relocs[SYMBOL_GOTOFF_LOADGP] = "%lo(%neg(%gp_rel(";
     }
 
+  /* Thread-local symbols must be split.  Only LD and LE have useful
+     LO_SUMs though.  */
+  mips_split_p[SYMBOL_TLS_GD] = true;
+  mips_split_p[SYMBOL_TLS_LD] = true;
+  mips_lo_relocs[SYMBOL_TLS_LD] = "%dtprel_lo(";
+  mips_split_p[SYMBOL_TLS_IE] = true;
+  mips_split_p[SYMBOL_TLS_LE] = true;
+  mips_lo_relocs[SYMBOL_TLS_LE] = "%tprel_lo(";
+  
   /* Default to working around R4000 errata only if the processor
      was selected explicitly.  */
   if ((target_flags_explicit & MASK_FIX_R4000) == 0
Index: gcc/gcc/config/mips/mips.h
===================================================================
--- gcc.orig/gcc/config/mips/mips.h	2005-03-08 17:18:48.000000000 -0500
+++ gcc/gcc/config/mips/mips.h	2005-03-09 10:03:32.000000000 -0500
@@ -1705,6 +1705,7 @@ enum reg_class
   T_REG,			/* mips16 T register ($24) */
   M16_T_REGS,			/* mips16 registers plus T register */
   PIC_FN_ADDR_REG,		/* SVR4 PIC function address register */
+  V1_REG,			/* Register $v1 ($3) used for TLS access.  */
   LEA_REGS,			/* Every GPR except $25 */
   GR_REGS,			/* integer registers */
   FP_REGS,			/* floating point registers */
@@ -1743,6 +1744,7 @@ enum reg_class
   "T_REG",								\
   "M16_T_REGS",								\
   "PIC_FN_ADDR_REG",							\
+  "V1_REG",								\
   "LEA_REGS",								\
   "GR_REGS",								\
   "FP_REGS",								\
@@ -1784,7 +1786,8 @@ enum reg_class
   { 0x01000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },	/* mips16 T register */	\
   { 0x010300fc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },	/* mips16 and T regs */ \
   { 0x02000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },	/* SVR4 PIC function address register */ \
-  { 0xfdffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },	/* Every other GPR */   \
+  { 0x00000008, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },	/* only $v1 */ \
+  { 0xfdffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },	/* Every other GPR except $25 */   \
   { 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },	/* integer registers */	\
   { 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },	/* floating registers*/	\
   { 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000 },	/* hi register */	\
@@ -1840,6 +1843,7 @@ extern const enum reg_class mips_regno_t
 #define GR_REG_CLASS_P(CLASS)						\
   ((CLASS) == GR_REGS || (CLASS) == M16_REGS || (CLASS) == T_REG	\
    || (CLASS) == M16_T_REGS || (CLASS) == M16_NA_REGS			\
+   || (CLASS) == V1_REG							\
    || (CLASS) == PIC_FN_ADDR_REG || (CLASS) == LEA_REGS)
 
 /* This macro is also used later on in the file.  */
@@ -1887,6 +1891,7 @@ extern const enum reg_class mips_regno_t
    'f'	Floating point registers
    'h'	Hi register
    'l'	Lo register
+   'v'	$v1 only
    'x'	Multiply/divide registers
    'z'	FP Status register
    'B'  Cop0 register
@@ -2486,7 +2491,7 @@ typedef struct mips_args {
 #define CONSTANT_ADDRESS_P(X) \
   (CONSTANT_P (X) && mips_legitimate_address_p (SImode, X, 0))
 
-#define LEGITIMATE_CONSTANT_P(X) (mips_const_insns (X) > 0)
+#define LEGITIMATE_CONSTANT_P(X) (!mips_tls_operand_p (X) && mips_const_insns (X) > 0)
 
 #define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN)			\
   do {								\
@@ -3022,3 +3027,7 @@ while (0)
 	" TEXT_SECTION_ASM_OP);
 #endif
 #endif
+
+#ifndef HAVE_AS_TLS
+#define HAVE_AS_TLS 0
+#endif
Index: gcc/gcc/config/mips/mips.md
===================================================================
--- gcc.orig/gcc/config/mips/mips.md	2005-03-08 17:18:48.000000000 -0500
+++ gcc/gcc/config/mips/mips.md	2005-03-09 10:03:32.000000000 -0500
@@ -45,6 +45,12 @@
    (UNSPEC_LOAD_GOT		24)
    (UNSPEC_GP			25)
    (UNSPEC_MFHILO		26)
+   (UNSPEC_TLS_GD		27)
+   (UNSPEC_TLS_LD		28)
+   (UNSPEC_TLS_DTPREL_HI16	29)
+   (UNSPEC_TLS_IE		30)
+   (UNSPEC_TLS_TPREL_HI16	31)
+   (UNSPEC_TLS_GET_TP		32)
 
    (UNSPEC_ADDRESS_FIRST	100)
 
@@ -5270,6 +5276,65 @@ beq\t%2,%.,1b\;\
   [(match_dup 0)]
   { operands[0] = mips_rewrite_small_data (operands[0]); })
 
+; Thread-Local Storage
+(define_insn "tls_gd_<mode>"
+  [(set (match_operand:P 0 "register_operand" "=d")
+	(unspec:P [(match_operand:P 1 "register_operand" "d")
+		    (match_operand:P 2 "tls_symbol_ref" "")]
+		  UNSPEC_TLS_GD))]
+  "HAVE_AS_TLS && !TARGET_MIPS16"
+  "<d>addiu\t%0,%1,%%tlsgd(%2)"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "tls_ld_<mode>"
+  [(set (match_operand:P 0 "register_operand" "=d")
+	(unspec:P [(match_operand:P 1 "register_operand" "d")
+		    (match_operand:P 2 "tls_symbol_ref" "")]
+		  UNSPEC_TLS_LD))]
+  "HAVE_AS_TLS && !TARGET_MIPS16"
+  "<d>addiu\t%0,%1,%%tlsldm(%2)"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "tls_dtprel_hi_<mode>"
+  [(set (match_operand:P 0 "register_operand" "=d")
+	(unspec:P [(match_operand:P 1 "tls_symbol_ref" "")]
+		  UNSPEC_TLS_DTPREL_HI16))]
+  "HAVE_AS_TLS && !TARGET_MIPS16"
+  "lui\t%0,%%dtprel_hi(%1)"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "tls_get_tp_<mode>"
+  [(set (match_operand:P 0 "register_operand" "=v")
+	(unspec:P [(const_int 0)]
+		  UNSPEC_TLS_GET_TP))]
+  "HAVE_AS_TLS && !TARGET_MIPS16"
+  ".set\tpush\;.set\tmips32r2\t\;rdhwr\t%0,$29\;.set\tpop"
+  [(set_attr "type" "unknown")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "tls_ie_<mode>"
+  [(set (match_operand:P 0 "register_operand" "=d")
+	(unspec:P [(match_operand:P 1 "register_operand" "d")
+		   (match_operand:P 2 "tls_symbol_ref" "")]
+		  UNSPEC_TLS_TPREL_HI16))]
+  "HAVE_AS_TLS && !TARGET_MIPS16"
+  "lw\t%0,%%gottprel(%2)(%1)"
+  [(set_attr "type" "load")
+   (set_attr "length" "4")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "tls_tprel_hi_<mode>"
+  [(set (match_operand:P 0 "register_operand" "=d")
+	(unspec:P [(match_operand:P 1 "tls_symbol_ref" "")]
+		  UNSPEC_TLS_TPREL_HI16))]
+  "HAVE_AS_TLS && !TARGET_MIPS16"
+  "lui\t%0,%%tprel_hi(%1)"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "<MODE>")])
+
 ; The MIPS Paired-Single Floating Point and MIPS-3D Instructions.
 
 (include "mips-ps-3d.md")
Index: gcc/gcc/config/mips/predicates.md
===================================================================
--- gcc.orig/gcc/config/mips/predicates.md	2005-02-13 21:49:14.000000000 -0500
+++ gcc/gcc/config/mips/predicates.md	2005-03-09 10:03:32.000000000 -0500
@@ -206,3 +206,23 @@
 (define_predicate "small_data_pattern"
   (and (match_code "set,parallel,unspec,unspec_volatile,prefetch")
        (match_test "mips_small_data_pattern_p (op)")))
+
+(define_predicate "tls_symbol_ref"
+  (match_code "symbol_ref")
+{
+  enum mips_symbol_type symbol_type;
+
+  if (!mips_symbolic_constant_p (op, &symbol_type))
+    return false;
+
+  switch (symbol_type)
+    {
+    case SYMBOL_TLS_GD:
+    case SYMBOL_TLS_LD:
+    case SYMBOL_TLS_IE:
+    case SYMBOL_TLS_LE:
+      return true;
+    default:
+      return false;
+    }
+})


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