Hi Richard,
here are the patches for MIPS16 TLS. Some highlights of the implementation:
1) For the common -mcode-readable=yes case, TP/DTP offset constants are
loaded pc-relative (this saves insn count and size). HI16/LO16
constructing is used only as a fall-back when text is not readable.
2) To support the Initial/Local-Exec TLS access models, direct access to
the TP is needed. However, MIPS16 mode cannot access the 'rdhwr $3,$29'
instruction used to do that, thus a new __mips16_rdhwr() helper routine
is added to libgcc.a
3) Uses of this __mips16_rdhwr() routine are only generated by by (a)
IE/LE accesses, and (b) calls to the (new added)
__builtin_thread_pointer() builtin function. To facilitate lower
overhead, such calls are represented as UNSPECs instead of actual
function calls, and doesn't really follow the standard ABI (e.g. value
returned in $3). The __mips16_rdhwr() function is not intended for
general use, just tightly coupled compiler runtime support; therefore,
it is only linked statically from libgcc.a, not exported from shared libgcc.
4) Due to containing such a static only support routine, mips*-linux*
targets have been adjusted to use config/t-slibgcc-libgcc in
libgcc/config.host (or else static -lgcc would not be included when
linking with -shared -shared-libgcc)
5) The libgomp MIPS futex.h header has been adjusted; sys_futex0() has
been modified to be static, non-inlined, nomips16 under MIPS16 mode (for
sake of using 'syscall'). The inline assembly has also been fixed, as
Maciej noticed a possible violation of the MIPS syscall restart
convention; the 'li $2, #syscall_number' must be right before the
syscall insn.
Only O32 support has been attempted right now, though the code should
not have anything really old-ABI specific. We were able to build glibc
as MIPS16 code with this TLS implementation, so I believe things should
be fairly stable.
Anyways, I believe this will be going in only after 4.8-stage1 opens, so
you should have plenty time to review it :)
Thanks, and Happy New Year
Chung-Lin
2012-01-06 Chung-Lin Tang <[email protected]>
gcc/
* config/mips/mips.h (CRT_CALL_STATIC_FUNCTION): Define versions
for MIPS16 O32.
* config/mips/mips-protos.h (mips_symbol_type): Add
SYMBOL_DTPREL_HI,SYMBOL_TPREL_HI. Update in comments.
(mips_output_tls_reloc_directive): New prototype.
* config/mips/mips-ftypes.def: Add (0, (POINTER)) entry.
* config/mips/predicates.md (tls_reloc_operand): New predicate.
* config/mips/mips.md (V0_REGNUM,PIC_JUMP_REGNUM): New constant.
(MIPS16 %dtprel_hi,%tprel_hi split pattern): New.
(consttable_tls_reloc): New.
(tls_get_tp_<mode>_mips16): New insn and split pattern.
(*tls_get_tp_<mode>_mips16_rdhwr): New insn pattern.
libgcc/
* config.host
(mips64*-*-linux*,mipsisa64*-*-linux*,mips*-*-linux*):
Use config/t-slibgcc-libgcc.
* config/mips/t-mips16 (LIB1ASMFUNCS): Add _m16rdhwr.
* config/mips/crtfastmath.c (set_fast_math): Add 'nomips16'
attribute.
* config/mips/mips16.S (__mips16_rdhwr): New.
libgomp/
* config/linux/mips/futex.h (sys_futex0): Change to static
function with noinline, nomips16 attributes under MIPS16. Adjust
asm statement to place 'li v0,SYS_futex' immediately before
syscall insn.
Index: gcc/config/mips/mips-ftypes.def
===================================================================
--- gcc/config/mips/mips-ftypes.def (revision 182952)
+++ gcc/config/mips/mips-ftypes.def (working copy)
@@ -51,6 +51,8 @@ DEF_MIPS_FTYPE (2, (INT, SF, SF))
DEF_MIPS_FTYPE (2, (INT, V2SF, V2SF))
DEF_MIPS_FTYPE (4, (INT, V2SF, V2SF, V2SF, V2SF))
+DEF_MIPS_FTYPE (0, (POINTER))
+
DEF_MIPS_FTYPE (2, (SI, DI, SI))
DEF_MIPS_FTYPE (2, (SI, POINTER, SI))
DEF_MIPS_FTYPE (2, (DI, POINTER, SI))
Index: gcc/config/mips/predicates.md
===================================================================
--- gcc/config/mips/predicates.md (revision 182952)
+++ gcc/config/mips/predicates.md (working copy)
@@ -312,6 +312,14 @@
&& type == SYMBOL_GOT_PAGE_OFST);
})
+(define_predicate "tls_reloc_operand"
+ (match_code "const,symbol_ref,label_ref")
+{
+ enum mips_symbol_type type;
+ return (mips_symbolic_constant_p (op, SYMBOL_CONTEXT_LEA, &type)
+ && (type == SYMBOL_DTPREL || type == SYMBOL_TPREL));
+})
+
(define_predicate "symbol_ref_operand"
(match_code "symbol_ref"))
Index: gcc/config/mips/mips.md
===================================================================
--- gcc/config/mips/mips.md (revision 182952)
+++ gcc/config/mips/mips.md (working copy)
@@ -134,7 +134,9 @@
])
(define_constants
- [(TLS_GET_TP_REGNUM 3)
+ [(V0_REGNUM 2)
+ (TLS_GET_TP_REGNUM 3)
+ (PIC_JUMP_REGNUM 25)
(RETURN_ADDR_REGNUM 31)
(CPRESTORE_SLOT_REGNUM 76)
(GOT_VERSION_REGNUM 79)
@@ -3933,6 +3935,23 @@
operands[2] = mips_unspec_address (operands[1], SYMBOL_32_HIGH);
})
+;; MIPS16 %dtprel_hi,%tprel_hi split pattern. Similar transform
+;; as above, for supporting MIPS16 TLS.
+(define_split
+ [(set (match_operand:SI 0 "d_operand")
+ (high:SI (match_operand:SI 1 "tls_reloc_operand")))]
+ "TARGET_MIPS16 && reload_completed"
+ [(set (match_dup 0) (match_dup 2))
+ (set (match_dup 0) (ashift:SI (match_dup 0) (const_int 16)))]
+{
+ /* SYMBOL_DTPREL_HI/TPREL_HI are ordered immediately after
+ SYMBOL_DTPREL/TPREL respectively, so use unspec_type + 1. */
+ rtx unspec = XEXP (operands[1], 0);
+ int unspec_type = XINT (unspec, 1);
+ operands[2] = mips_unspec_address (XVECEXP (unspec, 0, 0),
+ unspec_type + 1 - UNSPEC_ADDRESS_FIRST);
+})
+
;; Insns to fetch a symbol from a big GOT.
(define_insn_and_split "*xgot_hi<mode>"
@@ -6492,6 +6511,17 @@
;; ....................
;;
+(define_insn "consttable_tls_reloc"
+ [(unspec_volatile [(match_operand 0 "tls_reloc_operand" "")
+ (match_operand 1 "const_int_operand" "")]
+ UNSPEC_CONSTTABLE_INT)]
+ "TARGET_MIPS16_PCREL_LOADS"
+{
+ mips_output_tls_reloc_directive (operands[0], operands[1]);
+ return "";
+}
+ [(set (attr "length") (symbol_ref "INTVAL (operands[1])"))])
+
(define_insn "consttable_int"
[(unspec_volatile [(match_operand 0 "consttable_operand" "")
(match_operand 1 "const_int_operand" "")]
@@ -6593,6 +6623,60 @@
; See tls_get_tp_<mode>
(set_attr "can_delay" "no")
(set_attr "mode" "<MODE>")])
+
+;; In MIPS16 mode, the TLS base pointer is accessed by a
+;; libgcc helper function __mips16_rdhwr(), as 'rdhwr' is not
+;; accessible in MIPS16.
+;;
+;; This is not represented as a call insn, to avoid the
+;; unnecesarry clobbering of caller-save registers by a
+;; function consisting only of: "rdhwr $3,$29; j $31; nop;"
+;;
+;; A $25 clobber is added to cater for a $25 load stub added by the
+;; linker to __mips16_rdhwr when the call is made from non-PIC code.
+
+(define_insn_and_split "tls_get_tp_<mode>_mips16"
+ [(set (match_operand:P 0 "register_operand" "=d")
+ (unspec:P [(const_int 0)] UNSPEC_TLS_GET_TP))
+ (clobber (reg:P TLS_GET_TP_REGNUM))
+ (clobber (reg:P PIC_JUMP_REGNUM))
+ (clobber (reg:P RETURN_ADDR_REGNUM))]
+ "HAVE_AS_TLS && TARGET_MIPS16"
+ "#"
+ "&& reload_completed"
+ [(parallel [(set (reg:P TLS_GET_TP_REGNUM)
+ (unspec:P [(match_dup 1)] UNSPEC_TLS_GET_TP))
+ (clobber (reg:P PIC_JUMP_REGNUM))
+ (clobber (reg:P RETURN_ADDR_REGNUM))])
+ (set (match_dup 0) (reg:P TLS_GET_TP_REGNUM)) ]
+ {
+ /* UNSPEC operand decides on direct/indirect pattern below. */
+ rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__mips16_rdhwr");
+ if (TARGET_ABSOLUTE_JUMPS)
+ operands[1] = sym;
+ else
+ {
+ operands[1] = gen_rtx_REG (Pmode, TLS_GET_TP_REGNUM);
+ mips_emit_move (operands[1], sym);
+ }
+ }
+ [(set_attr "type" "unknown")
+ (set_attr "can_delay" "no")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "*tls_get_tp_<mode>_mips16_rdhwr"
+ [(set (reg:P TLS_GET_TP_REGNUM)
+ (unspec:P [(match_operand:P 0 "")] UNSPEC_TLS_GET_TP))
+ (clobber (reg:P PIC_JUMP_REGNUM))
+ (clobber (reg:P RETURN_ADDR_REGNUM))]
+ "HAVE_AS_TLS && TARGET_MIPS16"
+ {
+ return MIPS_CALL ("jal", operands, 0, -1);
+ }
+ [(set_attr "type" "call")
+ (set_attr "can_delay" "no")
+ (set_attr "mode" "<MODE>")])
+
;; Synchronization instructions.
Index: gcc/config/mips/mips-protos.h
===================================================================
--- gcc/config/mips/mips-protos.h (revision 182952)
+++ gcc/config/mips/mips-protos.h (working copy)
@@ -89,8 +89,10 @@ enum mips_symbol_context {
SYMBOL_TLSGD
SYMBOL_TLSLDM
SYMBOL_DTPREL
+ SYMBOL_DTPREL_HI
SYMBOL_GOTTPREL
SYMBOL_TPREL
+ SYMBOL_TPREL_HI
UNSPEC wrappers around SYMBOL_TLS, corresponding to the
thread-local storage relocation operators.
@@ -127,8 +129,10 @@ enum mips_symbol_type {
SYMBOL_TLSGD,
SYMBOL_TLSLDM,
SYMBOL_DTPREL,
+ SYMBOL_DTPREL_HI,
SYMBOL_GOTTPREL,
SYMBOL_TPREL,
+ SYMBOL_TPREL_HI,
SYMBOL_32_HIGH,
SYMBOL_64_HIGH,
SYMBOL_64_MID,
@@ -341,6 +345,7 @@ extern bool mips_epilogue_uses (unsigned int);
extern void mips_final_prescan_insn (rtx, rtx *, int);
extern int mips_trampoline_code_size (void);
extern void mips_function_profiler (FILE *);
+extern void mips_output_tls_reloc_directive (rtx, rtx);
typedef rtx (*mulsidi3_gen_fn) (rtx, rtx, rtx);
#ifdef RTX_CODE
Index: gcc/config/mips/mips.c
===================================================================
--- gcc/config/mips/mips.c (revision 182952)
+++ gcc/config/mips/mips.c (working copy)
@@ -183,6 +183,7 @@ enum mips_address_type {
};
/* Macros to create an enumeration identifier for a function prototype. */
+#define MIPS_FTYPE_NAME0(A) MIPS_##A##_FTYPE_VOID
#define MIPS_FTYPE_NAME1(A, B) MIPS_##A##_FTYPE_##B
#define MIPS_FTYPE_NAME2(A, B, C) MIPS_##A##_FTYPE_##B##_##C
#define MIPS_FTYPE_NAME3(A, B, C, D) MIPS_##A##_FTYPE_##B##_##C##_##D
@@ -233,7 +234,10 @@ enum mips_builtin_type {
MIPS_BUILTIN_CMP_SINGLE,
/* For generating bposge32 branch instructions in MIPS32 DSP ASE. */
- MIPS_BUILTIN_BPOSGE32
+ MIPS_BUILTIN_BPOSGE32,
+
+ /* For generating accesses to the TLS thread pointer. */
+ MIPS_BUILTIN_THREAD_POINTER
};
/* Invoke MACRO (COND) for each C.cond.fmt condition. */
@@ -1763,6 +1767,8 @@ mips_symbolic_constant_p (rtx x, enum mips_symbol_
case SYMBOL_GOTTPREL:
case SYMBOL_TLS:
case SYMBOL_HALF:
+ case SYMBOL_TPREL_HI:
+ case SYMBOL_DTPREL_HI:
return false;
}
gcc_unreachable ();
@@ -1857,8 +1863,10 @@ mips_symbol_insns_1 (enum mips_symbol_type type, e
case SYMBOL_TLSGD:
case SYMBOL_TLSLDM:
case SYMBOL_DTPREL:
+ case SYMBOL_DTPREL_HI:
case SYMBOL_GOTTPREL:
case SYMBOL_TPREL:
+ case SYMBOL_TPREL_HI:
case SYMBOL_HALF:
/* A 16-bit constant formed by a single relocation, or a 32-bit
constant formed from a high 16-bit relocation and a low 16-bit
@@ -1928,14 +1936,23 @@ mips_cannot_force_const_mem (enum machine_mode mod
if (mips_symbolic_constant_p (base, SYMBOL_CONTEXT_LEA, &type)
&& type != SYMBOL_FORCE_TO_MEM)
{
+ if (TARGET_MIPS16_PCREL_LOADS)
+ {
+ /* Under MIPS16, TLS DTP/TP-relative offsets are loaded from the
+ constant pool, as this saves some code size compared to hi/lo
+ constructing. */
+ if (type == SYMBOL_DTPREL || type == SYMBOL_TPREL)
+ return false;
+
+ /* If MIPS16 constant pools live in the text section, they should
+ not refer to anything that might need run-time relocation. */
+ if (mips_got_symbol_type_p (type))
+ return true;
+ }
+
/* The same optimization as for CONST_INT. */
if (SMALL_INT (offset) && mips_symbol_insns (type, MAX_MACHINE_MODE) > 0)
return true;
-
- /* If MIPS16 constant pools live in the text section, they should
- not refer to anything that might need run-time relocation. */
- if (TARGET_MIPS16_PCREL_LOADS && mips_got_symbol_type_p (type))
- return true;
}
/* TLS symbols must be computed by mips_legitimize_move. */
@@ -2820,11 +2837,20 @@ mips_call_tls_get_addr (rtx sym, enum mips_symbol_
/* Return a pseudo register that contains the current thread pointer. */
static rtx
-mips_get_tp (void)
+mips_get_tp (rtx target)
{
- rtx tp;
+ rtx tp = (target != NULL_RTX && REG_P (target)
+ ? target : gen_reg_rtx (Pmode));
- tp = gen_reg_rtx (Pmode);
+ if (TARGET_MIPS16)
+ {
+ if (Pmode == DImode)
+ emit_insn (gen_tls_get_tp_di_mips16 (tp));
+ else
+ emit_insn (gen_tls_get_tp_si_mips16 (tp));
+ return tp;
+ }
+
if (Pmode == DImode)
emit_insn (gen_tls_get_tp_di (tp));
else
@@ -2842,12 +2868,6 @@ mips_legitimize_tls_address (rtx loc)
rtx dest, insn, v0, tp, tmp1, tmp2, eqv;
enum tls_model model;
- if (TARGET_MIPS16)
- {
- sorry ("MIPS16 TLS");
- return gen_reg_rtx (Pmode);
- }
-
model = SYMBOL_REF_TLS_MODEL (loc);
/* Only TARGET_ABICALLS code can have more than one module; other
code must be be static and should not use a GOT. All TLS models
@@ -2875,13 +2895,23 @@ mips_legitimize_tls_address (rtx loc)
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));
+ if (TARGET_MIPS16_PCREL_LOADS)
+ {
+ tmp2 = mips_force_temporary (NULL,
+ mips_unspec_address (loc,
+ SYMBOL_DTPREL));
+ dest = gen_rtx_PLUS (Pmode, tmp1, tmp2);
+ }
+ else
+ {
+ 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:
- tp = mips_get_tp ();
+ tp = mips_get_tp (NULL_RTX);
tmp1 = gen_reg_rtx (Pmode);
tmp2 = mips_unspec_address (loc, SYMBOL_GOTTPREL);
if (Pmode == DImode)
@@ -2893,10 +2923,20 @@ mips_legitimize_tls_address (rtx loc)
break;
case TLS_MODEL_LOCAL_EXEC:
- tp = mips_get_tp ();
- tmp1 = mips_unspec_offset_high (NULL, tp, loc, SYMBOL_TPREL);
- dest = gen_rtx_LO_SUM (Pmode, tmp1,
- mips_unspec_address (loc, SYMBOL_TPREL));
+ tp = mips_get_tp (NULL_RTX);
+ if (TARGET_MIPS16_PCREL_LOADS)
+ {
+ tmp1 = mips_force_temporary (NULL,
+ mips_unspec_address (loc,
+ SYMBOL_TPREL));
+ dest = gen_rtx_PLUS (Pmode, tp, tmp1);
+ }
+ else
+ {
+ tmp1 = mips_unspec_offset_high (NULL, tp, loc, SYMBOL_TPREL);
+ dest = gen_rtx_LO_SUM (Pmode, tmp1,
+ mips_unspec_address (loc, SYMBOL_TPREL));
+ }
break;
default:
@@ -7291,16 +7331,24 @@ mips_init_relocs (void)
mips_lo_relocs[SYMBOL_TLSGD] = "%tlsgd(";
mips_lo_relocs[SYMBOL_TLSLDM] = "%tlsldm(";
- mips_split_p[SYMBOL_DTPREL] = true;
- mips_hi_relocs[SYMBOL_DTPREL] = "%dtprel_hi(";
- mips_lo_relocs[SYMBOL_DTPREL] = "%dtprel_lo(";
+ if (! TARGET_MIPS16_PCREL_LOADS)
+ {
+ mips_split_p[SYMBOL_DTPREL] = true;
+ 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] = true;
+ mips_hi_relocs[SYMBOL_TPREL] = "%tprel_hi(";
+ mips_lo_relocs[SYMBOL_TPREL] = "%tprel_lo(";
- mips_split_p[SYMBOL_TPREL] = true;
- mips_hi_relocs[SYMBOL_TPREL] = "%tprel_hi(";
- mips_lo_relocs[SYMBOL_TPREL] = "%tprel_lo(";
+ if (TARGET_MIPS16)
+ {
+ mips_lo_relocs[SYMBOL_TPREL_HI] = "%tprel_hi(";
+ mips_lo_relocs[SYMBOL_DTPREL_HI] = "%dtprel_hi(";
+ }
+ }
+ mips_lo_relocs[SYMBOL_GOTTPREL] = "%gottprel(";
mips_lo_relocs[SYMBOL_HALF] = "%half(";
}
@@ -12734,7 +12782,8 @@ struct mips_builtin_description {
/* The function's prototype. */
enum mips_function_type function_type;
- /* Whether the function is available. */
+ /* Whether the function is available. A NULL pointer value here
+ means the builtin is always available. */
unsigned int (*avail) (void);
};
@@ -12904,6 +12953,12 @@ AVAIL_NON_MIPS16 (cache, TARGET_CACHE_BUILTIN)
#define CODE_FOR_loongson_psubush CODE_FOR_ussubv4hi3
#define CODE_FOR_loongson_psubusb CODE_FOR_ussubv8qi3
+/* Define a MIPS_BUILTIN_THREAD_POINTER builtin. The parameters are fixed,
+ but we allow both __builtin* and __builtin_mips* prefixes below. */
+#define THREAD_POINTER_BUILTIN(NAME) \
+ { CODE_FOR_nothing, MIPS_FP_COND_f, #NAME, \
+ MIPS_BUILTIN_THREAD_POINTER, MIPS_POINTER_FTYPE_VOID, NULL }
+
static const struct mips_builtin_description mips_builtins[] = {
DIRECT_BUILTIN (pll_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, paired_single),
DIRECT_BUILTIN (pul_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, paired_single),
@@ -13187,7 +13242,11 @@ static const struct mips_builtin_description mips_
LOONGSON_BUILTIN_SUFFIX (punpcklwd, s, MIPS_V2SI_FTYPE_V2SI_V2SI),
/* Sundry other built-in functions. */
- DIRECT_NO_TARGET_BUILTIN (cache, MIPS_VOID_FTYPE_SI_CVPOINTER, cache)
+ DIRECT_NO_TARGET_BUILTIN (cache, MIPS_VOID_FTYPE_SI_CVPOINTER, cache),
+
+ /* TLS thread pointer built-in functions. */
+ THREAD_POINTER_BUILTIN (__builtin_mips_thread_pointer),
+ THREAD_POINTER_BUILTIN (__builtin_thread_pointer)
};
/* Index I is the function declaration for mips_builtins[I], or null if the
@@ -13258,6 +13317,8 @@ mips_build_cvpointer_type (void)
/* MIPS_FTYPE_ATYPESN takes N MIPS_FTYPES-like type codes and lists
their associated MIPS_ATYPEs. */
+#define MIPS_FTYPE_ATYPES0(A) MIPS_ATYPE_##A
+
#define MIPS_FTYPE_ATYPES1(A, B) \
MIPS_ATYPE_##A, MIPS_ATYPE_##B
@@ -13309,11 +13370,19 @@ mips_init_builtins (void)
for (i = 0; i < ARRAY_SIZE (mips_builtins); i++)
{
d = &mips_builtins[i];
- if (d->avail ())
- mips_builtin_decls[i]
- = add_builtin_function (d->name,
- mips_build_function_type (d->function_type),
- i, BUILT_IN_MD, NULL, NULL);
+ if (d->avail && !d->avail ())
+ continue;
+
+ mips_builtin_decls[i]
+ = add_builtin_function (d->name,
+ mips_build_function_type (d->function_type),
+ i, BUILT_IN_MD, NULL, NULL);
+
+ if (d->builtin_type == MIPS_BUILTIN_THREAD_POINTER)
+ {
+ TREE_NOTHROW (mips_builtin_decls[i]) = 1;
+ TREE_READONLY (mips_builtin_decls[i]) = 1;
+ }
}
}
@@ -13544,20 +13613,21 @@ mips_expand_builtin (tree exp, rtx target, rtx sub
enum machine_mode mode, int ignore)
{
tree fndecl;
- unsigned int fcode, avail;
+ unsigned int fcode;
const struct mips_builtin_description *d;
fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
fcode = DECL_FUNCTION_CODE (fndecl);
gcc_assert (fcode < ARRAY_SIZE (mips_builtins));
d = &mips_builtins[fcode];
- avail = d->avail ();
- gcc_assert (avail != 0);
- if (TARGET_MIPS16)
+ if (d->avail && !d->avail ())
{
- error ("built-in function %qE not supported for MIPS16",
- DECL_NAME (fndecl));
- return ignore ? const0_rtx : CONST0_RTX (mode);
+ if (TARGET_MIPS16)
+ {
+ error ("built-in function %qE not supported for MIPS16",
+ DECL_NAME (fndecl));
+ return ignore ? const0_rtx : CONST0_RTX (mode);
+ }
}
switch (d->builtin_type)
{
@@ -13582,6 +13652,9 @@ mips_expand_builtin (tree exp, rtx target, rtx sub
case MIPS_BUILTIN_BPOSGE32:
return mips_expand_builtin_bposge (d->builtin_type, target);
+
+ case MIPS_BUILTIN_THREAD_POINTER:
+ return mips_get_tp (target);
}
gcc_unreachable ();
}
@@ -13771,7 +13844,7 @@ mips16_rewrite_pool_refs (rtx *x, void *data)
struct mips16_rewrite_pool_refs_info *info =
(struct mips16_rewrite_pool_refs_info *) data;
- if (force_to_mem_operand (*x, Pmode))
+ if (force_to_mem_operand (*x, Pmode) || tls_reloc_operand (*x, Pmode))
{
rtx mem = force_const_mem (GET_MODE (*x), *x);
validate_change (info->insn, x, mem, false);
@@ -13783,6 +13856,11 @@ mips16_rewrite_pool_refs (rtx *x, void *data)
return -1;
}
+ if (GET_CODE (*x) == UNSPEC
+ && XINT (*x, 1) == UNSPEC_TLS_GET_TP
+ && GET_CODE (XVECEXP (*x, 0, 0)) == SYMBOL_REF)
+ return -1;
+
if (TARGET_MIPS16_TEXT_LOADS)
mips16_rewrite_pool_constant (info->pool, x);
@@ -17108,6 +17186,28 @@ mips_expand_vec_minmax (rtx target, rtx op0, rtx o
x = gen_rtx_IOR (vmode, t0, t1);
emit_insn (gen_rtx_SET (VOIDmode, target, x));
}
+
+/* Output a DTP/TP-relative relocation, used in MIPS16 TLS. */
+
+void
+mips_output_tls_reloc_directive (rtx x, rtx size)
+{
+ const char *dir = NULL;
+ if (GET_CODE (x) == CONST)
+ x = XEXP (x, 0);
+ switch (UNSPEC_ADDRESS_TYPE (x))
+ {
+ case SYMBOL_DTPREL:
+ dir = INTVAL (size) == 4 ? ".dtprelword" : ".dtpreldword";
+ break;
+ case SYMBOL_TPREL:
+ dir = INTVAL (size) == 4 ? ".tprelword" : ".tpreldword";
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ fprintf (asm_out_file, "\t%s\t%s\n", dir, XSTR (UNSPEC_ADDRESS (x), 0));
+}
/* Initialize the GCC target structure. */
#undef TARGET_ASM_ALIGNED_HI_OP
Index: gcc/config/mips/mips.h
===================================================================
--- gcc/config/mips/mips.h (revision 182952)
+++ gcc/config/mips/mips.h (working copy)
@@ -2841,8 +2841,32 @@ while (0)
jal " USER_LABEL_PREFIX #FUNC "\n\
" TEXT_SECTION_ASM_OP);
#endif
+
+#else
+#if (defined _ABIO32 && _MIPS_SIM == _ABIO32)
+#ifdef __PIC__
+/* For MIPS16 PIC, construct the GP-value in $2 using PC-relative insns. */
+#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC) \
+ asm (SECTION_OP "\n\
+ li $2,%hi(_gp_disp)\n\
+ addiu $3,$pc,%lo(_gp_disp)\n\
+ sll $2,16\n\
+ addu $2,$3\n\
+ lw $2,%got(" USER_LABEL_PREFIX #FUNC ")($2)\n\
+ addiu $2,%lo(" USER_LABEL_PREFIX #FUNC ")\n\
+ move $25,$2\n\
+ jalr $2\n\
+ " TEXT_SECTION_ASM_OP);
+#else
+#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC) \
+ asm (SECTION_OP "\n\
+ jal " USER_LABEL_PREFIX #FUNC "\n\
+ " TEXT_SECTION_ASM_OP);
#endif
+#endif
+#endif /* __mips16 */
+
#ifndef HAVE_AS_TLS
#define HAVE_AS_TLS 0
#endif
Index: libgcc/config.host
===================================================================
--- libgcc/config.host (revision 182952)
+++ libgcc/config.host (working copy)
@@ -740,12 +740,12 @@ mips*-*-netbsd*) # NetBSD/mips, either
endian.
;;
mips64*-*-linux* | mipsisa64*-*-linux*)
extra_parts="$extra_parts crtfastmath.o"
- tmake_file="${tmake_file} t-crtfm mips/t-mips16 mips/t-tpbit"
+ tmake_file="${tmake_file} t-crtfm mips/t-mips16 mips/t-tpbit
t-slibgcc-libgcc"
md_unwind_header=mips/linux-unwind.h
;;
mips*-*-linux*) # Linux MIPS, either endian.
extra_parts="$extra_parts crtfastmath.o"
- tmake_file="${tmake_file} t-crtfm mips/t-mips16"
+ tmake_file="${tmake_file} t-crtfm mips/t-mips16 t-slibgcc-libgcc"
md_unwind_header=mips/linux-unwind.h
;;
mips*-*-openbsd*)
Index: libgcc/config/mips/t-mips16
===================================================================
--- libgcc/config/mips/t-mips16 (revision 182952)
+++ libgcc/config/mips/t-mips16 (working copy)
@@ -36,7 +36,8 @@ LIB1ASMFUNCS = _m16addsf3 _m16subsf3 _m16mulsf3 _m
_m16stubsc0 _m16stubsc1 _m16stubsc2 _m16stubsc5 _m16stubsc6 \
_m16stubsc9 _m16stubsc10 \
_m16stubdc0 _m16stubdc1 _m16stubdc2 _m16stubdc5 _m16stubdc6 \
- _m16stubdc9 _m16stubdc10
+ _m16stubdc9 _m16stubdc10 \
+ _m16rdhwr
SYNC = yes
SYNC_CFLAGS = -mno-mips16
Index: libgcc/config/mips/mips16.S
===================================================================
--- libgcc/config/mips/mips16.S (revision 182952)
+++ libgcc/config/mips/mips16.S (working copy)
@@ -709,4 +709,18 @@ CALL_STUB_RET (__mips16_call_stub_dc_9, 9, DC)
CALL_STUB_RET (__mips16_call_stub_dc_10, 10, DC)
#endif
#endif /* !__mips_single_float */
+
+#ifdef L_m16rdhwr
+STARTFN (__mips16_rdhwr)
+ /* Forced always hidden, to avoid exporting from shared libgcc. */
+ .hidden __mips16_rdhwr
+ .set push
+ .set mips32r2
+ .set noreorder
+ rdhwr $3,$29
+ .set pop
+ j $31
+ ENDFN (__mips16_rdhwr)
#endif
+
+#endif
Index: libgcc/config/mips/crtfastmath.c
===================================================================
--- libgcc/config/mips/crtfastmath.c (revision 182952)
+++ libgcc/config/mips/crtfastmath.c (working copy)
@@ -39,7 +39,7 @@
#define _FPU_GETCW(cw) __asm__ ("cfc1 %0,$31" : "=r" (cw))
#define _FPU_SETCW(cw) __asm__ ("ctc1 %0,$31" : : "r" (cw))
-static void __attribute__((constructor))
+static void __attribute__ ((constructor,nomips16))
set_fast_math (void)
{
unsigned int fcr;
Index: libgomp/config/linux/mips/futex.h
===================================================================
--- libgomp/config/linux/mips/futex.h (revision 182952)
+++ libgomp/config/linux/mips/futex.h (working copy)
@@ -28,20 +28,26 @@
#define FUTEX_WAIT 0
#define FUTEX_WAKE 1
+#ifdef __mips16
+static void __attribute__((noinline,nomips16))
+#else
static inline void
+#endif
sys_futex0 (int *addr, int op, int val)
{
- register unsigned long __v0 asm("$2") = (unsigned long) SYS_futex;
+ register unsigned long __v0 asm("$2");
register unsigned long __a0 asm("$4") = (unsigned long) addr;
register unsigned long __a1 asm("$5") = (unsigned long) op;
register unsigned long __a2 asm("$6") = (unsigned long) val;
register unsigned long __a3 asm("$7") = 0;
- __asm volatile ("syscall"
+ __asm volatile ("li $2, %6\n\t"
+ "syscall"
/* returns $a3 (errno), $v0 (return value) */
: "=r" (__v0), "=r" (__a3)
- /* arguments in v0 (syscall) a0-a3 */
- : "r" (__v0), "r" (__a0), "r" (__a1), "r" (__a2), "r" (__a3)
+ /* arguments in a0-a3, and syscall number */
+ : "r" (__a0), "r" (__a1), "r" (__a2), "r" (__a3),
+ "IK" (SYS_futex)
/* clobbers at, v1, t0-t9, memory */
: "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", "$14",
"$15", "$24", "$25", "memory");