From 69229b8198e11bbbc5962d3e4ce8ce77ebf737b7 Mon Sep 17 00:00:00 2001
From: Daniel Jacobowitz <dan@codesourcery.com>
Date: Sun, 13 Mar 2005 18:03:25 +0000
Subject: [PATCH] configure.ac: Check for MIPS TLS.

	* configure.ac: Check for MIPS TLS.
	* configure: Regenerated.
	* config/mips/mips-protos.h (enum mips_symbol_type): Add
	SYMBOL_TLS, SYMBOL_TLSGD, SYMBOL_TLSLDM, SYMBOL_DTPREL,
	SYMBOL_GOTTPREL, and SYMBOL_TPREL.
	* config/mips/mips.c (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_call_tls_get_addr)
	(mips_legitimize_tls_address, mips_cannot_force_const_mem)
	(mips_tls_symbol_ref_1): New functions.
	(mips_legitimize_address, mips_legitimize_const_move): Call
	mips_legitimize_tls_address.
	(override_options): Handle V1_REG and TLS symbols.  Disable TLS
	for MIPS16.
	* 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.
	(HAVE_AS_TLS): Provide default.
	* config/mips/mips.md (UNSPEC_TLS_LDM, UNSPEC_TLS_GET_TP): New
	constants.
	(load_got<mode>): Renamed from *load_got<mode>.  Allow when
	!TARGET_ABICALLS.
	(tls_get_tp_<mode>): New instruction.

Co-Authored-By: Joseph Myers <joseph@codesourcery.com>

From-SVN: r96380
---
 gcc/ChangeLog                 |  29 +++++
 gcc/config/mips/mips-protos.h |  17 +++
 gcc/config/mips/mips.c        | 205 +++++++++++++++++++++++++++++++++-
 gcc/config/mips/mips.h        |  11 +-
 gcc/config/mips/mips.md       |  25 ++++-
 gcc/configure                 |  17 +++
 gcc/configure.ac              |  17 +++
 7 files changed, 316 insertions(+), 5 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 78cdd8968e1c..6489c3c438fb 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,32 @@
+2005-03-13  Daniel Jacobowitz  <dan@codesourcery.com>
+	    Joseph S. Myers  <joseph@codesourcery.com>
+
+	* configure.ac: Check for MIPS TLS.
+	* configure: Regenerated.
+	* config/mips/mips-protos.h (enum mips_symbol_type): Add
+	SYMBOL_TLS, SYMBOL_TLSGD, SYMBOL_TLSLDM, SYMBOL_DTPREL,
+	SYMBOL_GOTTPREL, and SYMBOL_TPREL.
+	* config/mips/mips.c (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_call_tls_get_addr)
+	(mips_legitimize_tls_address, mips_cannot_force_const_mem)
+	(mips_tls_symbol_ref_1): New functions.
+	(mips_legitimize_address, mips_legitimize_const_move): Call
+	mips_legitimize_tls_address.
+	(override_options): Handle V1_REG and TLS symbols.  Disable TLS
+	for MIPS16.
+	* 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.
+	(HAVE_AS_TLS): Provide default.
+	* config/mips/mips.md (UNSPEC_TLS_LDM, UNSPEC_TLS_GET_TP): New
+	constants.
+	(load_got<mode>): Renamed from *load_got<mode>.  Allow when
+	!TARGET_ABICALLS.
+	(tls_get_tp_<mode>): New instruction.
+
 2005-03-13  Daniel Jacobowitz  <dan@codesourcery.com>
 
 	* configure.ac: Update checks for target tools.
diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h
index 8569d429959b..4b0b53d10918 100644
--- a/gcc/config/mips/mips-protos.h
+++ b/gcc/config/mips/mips-protos.h
@@ -61,6 +61,17 @@ 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
+       A thread-local symbol.
+
+   SYMBOL_TLSGD
+   SYMBOL_TLSLDM
+   SYMBOL_DTPREL
+   SYMBOL_GOTTPREL
+   SYMBOL_TPREL
+       UNSPEC wrappers around SYMBOL_TLS, corresponding to the
+       thread-local storage relocation operators.
+
    SYMBOL_64_HIGH
        For a 64-bit symbolic address X, this is the value of
        (%highest(X) << 16) + %higher(X).
@@ -82,6 +93,12 @@ enum mips_symbol_type {
   SYMBOL_GOTOFF_GLOBAL,
   SYMBOL_GOTOFF_CALL,
   SYMBOL_GOTOFF_LOADGP,
+  SYMBOL_TLS,
+  SYMBOL_TLSGD,
+  SYMBOL_TLSLDM,
+  SYMBOL_DTPREL,
+  SYMBOL_GOTTPREL,
+  SYMBOL_TPREL,
   SYMBOL_64_HIGH,
   SYMBOL_64_MID,
   SYMBOL_64_LOW
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 6748eae02c5a..59fd616b7f50 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -236,6 +236,7 @@ static bool mips_valid_base_register_p (rtx, enum machine_mode, int);
 static bool mips_symbolic_address_p (enum mips_symbol_type, enum machine_mode);
 static bool mips_classify_address (struct mips_address_info *, rtx,
 				   enum machine_mode, int);
+static bool mips_cannot_force_const_mem (rtx);
 static int mips_symbol_insns (enum mips_symbol_type);
 static bool mips16_unextended_reference_p (enum machine_mode mode, rtx, rtx);
 static rtx mips_force_temporary (rtx, rtx);
@@ -601,7 +602,7 @@ static const char *mips_hi_relocs[NUM_SYMBOL_TYPES];
 /* 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,
@@ -817,6 +818,12 @@ const struct mips_cpu_info mips_cpu_info_table[] = {
 #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_cannot_force_const_mem
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF.  */
@@ -835,6 +842,9 @@ mips_classify_symbol (rtx x)
 
   gcc_assert (GET_CODE (x) == SYMBOL_REF);
 
+  if (SYMBOL_REF_TLS_MODEL (x))
+    return SYMBOL_TLS;
+
   if (CONSTANT_POOL_ADDRESS_P (x))
     {
       if (TARGET_MIPS16)
@@ -943,7 +953,11 @@ mips_symbolic_constant_p (rtx x, enum mips_symbol_type *symbol_type)
   if (UNSPEC_ADDRESS_P (x))
     *symbol_type = UNSPEC_ADDRESS_TYPE (x);
   else if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
-    *symbol_type = mips_classify_symbol (x);
+    {
+      *symbol_type = mips_classify_symbol (x);
+      if (*symbol_type == SYMBOL_TLS)
+	return false;
+    }
   else
     return false;
 
@@ -993,6 +1007,12 @@ mips_symbolic_constant_p (rtx x, enum mips_symbol_type *symbol_type)
     case SYMBOL_GOTOFF_GLOBAL:
     case SYMBOL_GOTOFF_CALL:
     case SYMBOL_GOTOFF_LOADGP:
+    case SYMBOL_TLSGD:
+    case SYMBOL_TLSLDM:
+    case SYMBOL_DTPREL:
+    case SYMBOL_TPREL:
+    case SYMBOL_GOTTPREL:
+    case SYMBOL_TLS:
       return false;
     }
   gcc_unreachable ();
@@ -1090,6 +1110,14 @@ mips_symbolic_address_p (enum mips_symbol_type symbol_type,
       /* The address will have to be loaded from the GOT first.  */
       return false;
 
+    case SYMBOL_TLSGD:
+    case SYMBOL_TLSLDM:
+    case SYMBOL_DTPREL:
+    case SYMBOL_TPREL:
+    case SYMBOL_GOTTPREL:
+    case SYMBOL_TLS:
+      return false;
+
     case SYMBOL_GOTOFF_PAGE:
     case SYMBOL_GOTOFF_GLOBAL:
     case SYMBOL_GOTOFF_CALL:
@@ -1154,6 +1182,33 @@ mips_classify_address (struct mips_address_info *info, rtx x,
       return false;
     }
 }
+
+/* Return true if X is a thread-local symbol.  */
+
+static bool
+mips_tls_operand_p (rtx x)
+{
+  return GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) != 0;
+}
+
+/* Return true if X can not be forced into a constant pool.  */
+
+static int
+mips_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
+{
+  return mips_tls_operand_p (*x);
+}
+
+/* Return true if X can not be forced into a constant pool.  */
+
+static bool
+mips_cannot_force_const_mem (rtx x)
+{
+  if (! TARGET_HAVE_TLS)
+    return false;
+
+  return for_each_rtx (&x, &mips_tls_symbol_ref_1, 0);
+}
 
 /* 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
@@ -1223,8 +1278,17 @@ mips_symbol_insns (enum mips_symbol_type type)
     case SYMBOL_64_HIGH:
     case SYMBOL_64_MID:
     case SYMBOL_64_LOW:
+    case SYMBOL_TLSGD:
+    case SYMBOL_TLSLDM:
+    case SYMBOL_DTPREL:
+    case SYMBOL_GOTTPREL:
+    case SYMBOL_TPREL:
       /* Check whether the offset is a 16- or 32-bit value.  */
       return mips_split_p[type] ? 2 : 1;
+
+    case SYMBOL_TLS:
+      /* We don't treat a bare TLS symbol as a constant.  */
+      return 0;
     }
   gcc_unreachable ();
 }
@@ -1521,6 +1585,114 @@ mips_add_offset (rtx temp, rtx reg, HOST_WIDE_INT offset)
   return plus_constant (reg, offset);
 }
 
+/* Emit a call to __tls_get_addr.  SYM is the TLS symbol we are
+   referencing, and TYPE is the symbol type to use (either global
+   dynamic or local dynamic).  V0 is an RTX for the return value
+   location.  The entire insn sequence is returned.  */
+
+static GTY(()) rtx mips_tls_symbol;
+
+static rtx
+mips_call_tls_get_addr (rtx sym, enum mips_symbol_type type, rtx v0)
+{
+  rtx insn, loc, tga, a0;
+
+  a0 = gen_rtx_REG (Pmode, GP_ARG_FIRST);
+
+  if (!mips_tls_symbol)
+    mips_tls_symbol = init_one_libfunc ("__tls_get_addr");
+
+  loc = mips_unspec_address (sym, type);
+
+  start_sequence ();
+
+  emit_insn (gen_rtx_SET (Pmode, a0,
+			  gen_rtx_LO_SUM (Pmode, pic_offset_table_rtx, loc)));
+  tga = gen_rtx_MEM (Pmode, mips_tls_symbol);
+  insn = emit_call_insn (gen_call_value (v0, tga, const0_rtx, const0_rtx));
+  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 ();
+
+  return insn;
+}
+
+/* Generate the code to access LOC, a thread local SYMBOL_REF.  The
+   return value will be a valid address and move_operand (either a REG
+   or a LO_SUM).  */
+
+static rtx
+mips_legitimize_tls_address (rtx loc)
+{
+  rtx dest, insn, v0, v1, tmp1, tmp2, eqv;
+  enum tls_model model;
+
+  v0 = gen_rtx_REG (Pmode, GP_RETURN);
+  v1 = gen_rtx_REG (Pmode, GP_RETURN + 1);
+
+  model = SYMBOL_REF_TLS_MODEL (loc);
+
+  switch (model)
+    {
+    case TLS_MODEL_GLOBAL_DYNAMIC:
+      insn = mips_call_tls_get_addr (loc, SYMBOL_TLSGD, v0);
+      dest = gen_reg_rtx (Pmode);
+      emit_libcall_block (insn, dest, v0, loc);
+      break;
+
+    case TLS_MODEL_LOCAL_DYNAMIC:
+      insn = mips_call_tls_get_addr (loc, SYMBOL_TLSLDM, v0);
+      tmp1 = gen_reg_rtx (Pmode);
+
+      /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
+	 share the LDM result with other LD model accesses.  */
+      eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
+			    UNSPEC_TLS_LDM);
+      emit_libcall_block (insn, tmp1, v0, eqv);
+
+      tmp2 = mips_unspec_offset_high (NULL, tmp1, loc, SYMBOL_DTPREL);
+      dest = gen_rtx_LO_SUM (Pmode, tmp2,
+			     mips_unspec_address (loc, SYMBOL_DTPREL));
+      break;
+
+    case TLS_MODEL_INITIAL_EXEC:
+      tmp1 = gen_reg_rtx (Pmode);
+      tmp2 = mips_unspec_address (loc, SYMBOL_GOTTPREL);
+      if (Pmode == DImode)
+	{
+	  emit_insn (gen_tls_get_tp_di (v1));
+	  emit_insn (gen_load_gotdi (tmp1, pic_offset_table_rtx, tmp2));
+	}
+      else
+	{
+	  emit_insn (gen_tls_get_tp_si (v1));
+	  emit_insn (gen_load_gotsi (tmp1, pic_offset_table_rtx, tmp2));
+	}
+      dest = gen_reg_rtx (Pmode);
+      emit_insn (gen_add3_insn (dest, tmp1, v1));
+      break;
+
+    case TLS_MODEL_LOCAL_EXEC:
+
+      if (Pmode == DImode)
+	emit_insn (gen_tls_get_tp_di (v1));
+      else
+	emit_insn (gen_tls_get_tp_si (v1));
+
+      tmp1 = mips_unspec_offset_high (NULL, v1, loc, SYMBOL_TPREL);
+      dest = gen_rtx_LO_SUM (Pmode, tmp1,
+			     mips_unspec_address (loc, SYMBOL_TPREL));
+      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,
@@ -1532,6 +1704,12 @@ mips_legitimize_address (rtx *xloc, enum machine_mode mode)
 {
   enum mips_symbol_type symbol_type;
 
+  if (mips_tls_operand_p (*xloc))
+    {
+      *xloc = mips_legitimize_tls_address (*xloc);
+      return true;
+    }
+
   /* See if the address can split into a high part and a LO_SUM.  */
   if (mips_symbolic_constant_p (*xloc, &symbol_type)
       && mips_symbolic_address_p (symbol_type, mode)
@@ -1707,6 +1885,12 @@ mips_legitimize_const_move (enum machine_mode mode, rtx dest, rtx src)
       return;
     }
 
+  if (mips_tls_operand_p (src))
+    {
+      emit_move_insn (dest, mips_legitimize_tls_address (src));
+      return;
+    }
+
   /* 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.  */
@@ -4323,6 +4507,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;
@@ -4511,6 +4696,22 @@ override_options (void)
       mips_lo_relocs[SYMBOL_GOTOFF_LOADGP] = "%lo(%neg(%gp_rel(";
     }
 
+  /* Thread-local relocation operators.  */
+  mips_lo_relocs[SYMBOL_TLSGD] = "%tlsgd(";
+  mips_lo_relocs[SYMBOL_TLSLDM] = "%tlsldm(";
+  mips_split_p[SYMBOL_DTPREL] = 1;
+  mips_hi_relocs[SYMBOL_DTPREL] = "%dtprel_hi(";
+  mips_lo_relocs[SYMBOL_DTPREL] = "%dtprel_lo(";
+  mips_lo_relocs[SYMBOL_GOTTPREL] = "%gottprel(";
+  mips_split_p[SYMBOL_TPREL] = 1;
+  mips_hi_relocs[SYMBOL_TPREL] = "%tprel_hi(";
+  mips_lo_relocs[SYMBOL_TPREL] = "%tprel_lo(";
+
+  /* We don't have a thread pointer access instruction on MIPS16, or
+     appropriate TLS relocations.  */
+  if (TARGET_MIPS16)
+    targetm.have_tls = false;
+
   /* Default to working around R4000 errata only if the processor
      was selected explicitly.  */
   if ((target_flags_explicit & MASK_FIX_R4000) == 0
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index 0417adda368d..2d8695e2e578 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -1714,6 +1714,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 */
@@ -1752,6 +1753,7 @@ enum reg_class
   "T_REG",								\
   "M16_T_REGS",								\
   "PIC_FN_ADDR_REG",							\
+  "V1_REG",								\
   "LEA_REGS",								\
   "GR_REGS",								\
   "FP_REGS",								\
@@ -1793,7 +1795,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 */	\
@@ -1849,6 +1852,7 @@ extern const enum reg_class mips_regno_to_class[];
 #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.  */
@@ -1896,6 +1900,7 @@ extern const enum reg_class mips_regno_to_class[];
    'f'	Floating point registers
    'h'	Hi register
    'l'	Lo register
+   'v'	$v1 only
    'x'	Multiply/divide registers
    'z'	FP Status register
    'B'  Cop0 register
@@ -3031,3 +3036,7 @@ while (0)
 	" TEXT_SECTION_ASM_OP);
 #endif
 #endif
+
+#ifndef HAVE_AS_TLS
+#define HAVE_AS_TLS 0
+#endif
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index 0a63df09c1ae..9948e0627cd7 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -45,6 +45,8 @@
    (UNSPEC_LOAD_GOT		24)
    (UNSPEC_GP			25)
    (UNSPEC_MFHILO		26)
+   (UNSPEC_TLS_LDM		27)
+   (UNSPEC_TLS_GET_TP		28)
 
    (UNSPEC_ADDRESS_FIRST	100)
 
@@ -3017,12 +3019,12 @@ beq\t%2,%.,1b\;\
 ;; We could use MEMs, but an unspec gives more optimization
 ;; opportunities.
 
-(define_insn "*load_got<mode>"
+(define_insn "load_got<mode>"
   [(set (match_operand:P 0 "register_operand" "=d")
 	(unspec:P [(match_operand:P 1 "register_operand" "d")
 		   (match_operand:P 2 "immediate_operand" "")]
 		  UNSPEC_LOAD_GOT))]
-  "TARGET_ABICALLS"
+  ""
   "<load>\t%0,%R2(%1)"
   [(set_attr "type" "load")
    (set_attr "mode" "<MODE>")
@@ -5295,6 +5297,25 @@ beq\t%2,%.,1b\;\
   [(match_dup 0)]
   { operands[0] = mips_rewrite_small_data (operands[0]); })
 
+; Thread-Local Storage
+
+; The TLS base pointer is acessed via "rdhwr $v1, $29".  No current
+; MIPS architecture defines this register, and no current
+; implementation provides it; instead, any OS which supports TLS is
+; expected to trap and emulate this instruction.  rdhwr is part of the
+; MIPS 32r2 specification, but we use it on any architecture because
+; we expect it to be emulated.  Use .set to force the assembler to
+; accept it.
+
+(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>")])
+
 ; The MIPS Paired-Single Floating Point and MIPS-3D Instructions.
 
 (include "mips-ps-3d.md")
diff --git a/gcc/configure b/gcc/configure
index d69aa44ebcb6..10ff30583bee 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -13670,6 +13670,23 @@ foo:	data8	25
 	tls_first_minor=13
 	tls_as_opt=--fatal-warnings
 	;;
+  mips*-*-*)
+    conftest_s='
+	.section .tdata,"awT",@progbits
+x:
+	.word 2
+	.text
+	addiu $4, $28, %tlsgd(x)
+	addiu $4, $28, %tlsldm(x)
+	lui $4, %dtprel_hi(x)
+	addiu $4, $4, %dtprel_lo(x)
+	lw $4, %gottprel(x)($28)
+	lui $4, %tprel_hi(x)
+	addiu $4, $4, %tprel_lo(x)'
+	tls_first_major=2
+	tls_first_minor=16
+	tls_as_opt='-32 --fatal-warnings'
+	;;
   powerpc-*-*)
     conftest_s='
 	.section ".tdata","awT",@progbits
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 07e2c2f9043d..b076ad201295 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -2353,6 +2353,23 @@ foo:	data8	25
 	tls_first_minor=13
 	tls_as_opt=--fatal-warnings
 	;;
+  mips*-*-*)
+    conftest_s='
+	.section .tdata,"awT",@progbits
+x:
+	.word 2
+	.text
+	addiu $4, $28, %tlsgd(x)
+	addiu $4, $28, %tlsldm(x)
+	lui $4, %dtprel_hi(x)
+	addiu $4, $4, %dtprel_lo(x)
+	lw $4, %gottprel(x)($28)
+	lui $4, %tprel_hi(x)
+	addiu $4, $4, %tprel_lo(x)'
+	tls_first_major=2
+	tls_first_minor=16
+	tls_as_opt='-32 --fatal-warnings'
+	;;
   powerpc-*-*)
     conftest_s='
 	.section ".tdata","awT",@progbits
-- 
GitLab