aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Jacobowitz <dan@codesourcery.com>2005-06-15 02:40:07 +0000
committerMark Mitchell <mark@codesourcery.com>2005-06-15 02:40:07 +0000
commita0d788ecb52f6c2425dcff8219efa763e7088beb (patch)
treeb5d3560d211e02bf20089cd6643d2218fcc6ea77
parent8fc626a116887004d791354f44edea4aa5a53d70 (diff)
* gcc/config/mips/linux.h (MD_FALLBACK_REGISTER_OFFSET): Define.
(MD_FALLBACK_FRAME_STATE_FOR): Use it. Backport: 2005-01-25 Daniel Jacobowitz <dan@codesourcery.com> * config/mips/linux.h (LIB_SPEC): Remove -rpath-link. * config/mips/linux64.h (LIB_SPEC): Likewise. Backport: 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. git-svn-id: https://gcc.gnu.org/svn/gcc/branches/csl-3_4_3-linux-branch@100967 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/config/mips/linux.h13
-rw-r--r--gcc/config/mips/linux64.h4
-rw-r--r--gcc/config/mips/mips.c224
-rw-r--r--gcc/config/mips/mips.h11
-rw-r--r--gcc/config/mips/mips.md30
-rwxr-xr-xgcc/configure17
-rw-r--r--gcc/configure.ac17
7 files changed, 303 insertions, 13 deletions
diff --git a/gcc/config/mips/linux.h b/gcc/config/mips/linux.h
index e9dc94bfdec..c1ce52182f6 100644
--- a/gcc/config/mips/linux.h
+++ b/gcc/config/mips/linux.h
@@ -179,7 +179,6 @@ Boston, MA 02111-1307, USA. */
#undef LIB_SPEC
#define LIB_SPEC "\
%{shared: -lc} \
-%{!static:-rpath-link %R/lib:%R/usr/lib} \
%{!shared: %{pthread:-lpthread} \
%{profile:-lc_p} %{!profile: -lc}}"
@@ -200,6 +199,12 @@ typedef struct _sig_ucontext {
sigset_t uc_sigmask;
} _sig_ucontext_t;
+#if defined (__MIPSEB__) && !defined (__mips64)
+# define MD_FALLBACK_REGISTER_OFFSET 4
+#else
+# define MD_FALLBACK_REGISTER_OFFSET 0
+#endif
+
#define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS) \
do { \
u_int32_t *pc_ = (u_int32_t *) (CONTEXT)->ra; \
@@ -242,11 +247,13 @@ typedef struct _sig_ucontext {
for (i_ = 0; i_ < 32; i_++) { \
(FS)->regs.reg[i_].how = REG_SAVED_OFFSET; \
(FS)->regs.reg[i_].loc.offset \
- = (_Unwind_Ptr)&(sc_->sc_regs[i_]) - new_cfa_; \
+ = ((_Unwind_Ptr)&(sc_->sc_regs[i_]) - new_cfa_ \
+ + MD_FALLBACK_REGISTER_OFFSET); \
} \
(FS)->regs.reg[SIGNAL_UNWIND_RETURN_COLUMN].how = REG_SAVED_OFFSET; \
(FS)->regs.reg[SIGNAL_UNWIND_RETURN_COLUMN].loc.offset \
- = (_Unwind_Ptr)&(sc_->sc_pc) - new_cfa_; \
+ = ((_Unwind_Ptr)&(sc_->sc_pc) - new_cfa_ \
+ + MD_FALLBACK_REGISTER_OFFSET); \
(FS)->retaddr_column = SIGNAL_UNWIND_RETURN_COLUMN; \
\
goto SUCCESS; \
diff --git a/gcc/config/mips/linux64.h b/gcc/config/mips/linux64.h
index 58121eb3b8e..f5184ed1d2e 100644
--- a/gcc/config/mips/linux64.h
+++ b/gcc/config/mips/linux64.h
@@ -47,10 +47,6 @@ Boston, MA 02111-1307, USA. */
#undef LIB_SPEC
#define LIB_SPEC "\
%{shared: -lc} \
-%{!static: \
- %{mabi=n32:-rpath-link %R/lib32:%R/usr/lib32} \
- %{mabi=64:-rpath-link %R/lib64:%R/usr/lib64} \
- %{mabi=32:-rpath-link %R/lib:%R/usr/lib}} \
%{!shared: %{pthread:-lpthread} \
%{profile:-lc_p} %{!profile: -lc}}"
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index ceaee531cd2..c0927dc450e 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -145,7 +145,19 @@ enum internal_test {
SYMBOL_GOTOFF_LOADGP
An UNSPEC wrapper around a function's address. It represents the
- offset of _gp from the start of the function. */
+ 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. */
+
enum mips_symbol_type {
SYMBOL_GENERAL,
SYMBOL_SMALL_DATA,
@@ -155,9 +167,15 @@ enum mips_symbol_type {
SYMBOL_GOTOFF_PAGE,
SYMBOL_GOTOFF_GLOBAL,
SYMBOL_GOTOFF_CALL,
- SYMBOL_GOTOFF_LOADGP
+ SYMBOL_GOTOFF_LOADGP,
+ SYMBOL_TLS,
+ SYMBOL_TLSGD,
+ SYMBOL_TLSLDM,
+ SYMBOL_DTPREL,
+ SYMBOL_GOTTPREL,
+ SYMBOL_TPREL
};
-#define NUM_SYMBOL_TYPES (SYMBOL_GOTOFF_LOADGP + 1)
+#define NUM_SYMBOL_TYPES (SYMBOL_TPREL + 1)
/* Classifies an address.
@@ -199,6 +217,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);
@@ -621,7 +640,7 @@ char mips_sw_reg_names[][8] =
/* 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,
@@ -805,6 +824,12 @@ const struct mips_cpu_info mips_cpu_info_table[] = {
#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
+#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. */
@@ -818,6 +843,9 @@ mips_classify_symbol (rtx x)
if (GET_CODE (x) != SYMBOL_REF)
abort ();
+ if (SYMBOL_REF_TLS_MODEL (x))
+ return SYMBOL_TLS;
+
if (CONSTANT_POOL_ADDRESS_P (x))
{
if (TARGET_MIPS16)
@@ -931,7 +959,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;
@@ -970,6 +1002,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;
}
abort ();
@@ -1056,6 +1094,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:
@@ -1117,6 +1163,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
@@ -1183,8 +1256,17 @@ mips_symbol_insns (enum mips_symbol_type type)
case SYMBOL_GOTOFF_GLOBAL:
case SYMBOL_GOTOFF_CALL:
case SYMBOL_GOTOFF_LOADGP:
+ 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;
}
abort ();
}
@@ -1801,6 +1883,109 @@ mips_add_offset (rtx reg, HOST_WIDE_INT offset)
return plus_constant (reg, CONST_LOW_PART (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:
+ if (Pmode == DImode)
+ emit_insn (gen_tls_get_tp_di (v1));
+ else
+ emit_insn (gen_tls_get_tp_si (v1));
+ tmp1 = gen_reg_rtx (Pmode);
+ tmp2 = mips_load_got (pic_offset_table_rtx, loc, SYMBOL_GOTTPREL);
+ emit_move_insn (tmp1, 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,
@@ -1812,6 +1997,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)
@@ -1987,6 +2178,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. */
@@ -4988,6 +5185,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;
@@ -5144,6 +5342,22 @@ override_options (void)
mips_hi_relocs[SYMBOL_GOTOFF_LOADGP] = "%hi(%neg(%gp_rel(";
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;
}
/* Implement CONDITIONAL_REGISTER_USAGE. */
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index d087ed25980..1fb5ae176f0 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -1768,6 +1768,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 */
@@ -1806,6 +1807,7 @@ enum reg_class
"T_REG", \
"M16_T_REGS", \
"PIC_FN_ADDR_REG", \
+ "V1_REG", \
"LEA_REGS", \
"GR_REGS", \
"FP_REGS", \
@@ -1847,7 +1849,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 */ \
@@ -1903,6 +1906,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. */
@@ -1950,6 +1954,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
@@ -3448,3 +3453,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 35f89f0a1b4..7ceb3af333f 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -56,6 +56,8 @@
(UNSPEC_LOADGP 26)
(UNSPEC_LOAD_CALL 27)
(UNSPEC_GP 29)
+ (UNSPEC_TLS_LDM 30)
+ (UNSPEC_TLS_GET_TP 31)
(UNSPEC_ADDRESS_FIRST 100)
@@ -9230,3 +9232,31 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2%/"
"reload_completed"
[(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_si"
+ [(set (match_operand:SI 0 "register_operand" "=v")
+ (unspec:SI [(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" "SI")])
+
+(define_insn "tls_get_tp_di"
+ [(set (match_operand:DI 0 "register_operand" "=v")
+ (unspec:DI [(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" "DI")])
diff --git a/gcc/configure b/gcc/configure
index 3d1407a3120..abbf63fe905 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -10907,6 +10907,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 9a8fa438bf1..dd85d2bf5a5 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -2174,6 +2174,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