This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] SPARC TLS support
- From: Jakub Jelinek <jakub at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 8 Sep 2003 07:10:14 +0200
- Subject: [PATCH] SPARC TLS support
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
Hi!
I've commited following patch to add TLS support for sparc*.
Bootstrapped/regtested on sparc64-*-linux* (with Christian's
PR 12168 patch for strstream.cc ICE), no regressions.
2003-09-08 Jakub Jelinek <jakub@redhat.com>
* config/sparc/sparc.c (struct machine_function): New type.
(TARGET_HAVE_TLS, TARGET_CANNOT_FORCE_CONST_MEM): Define.
(sparc_override_options): Initialize init_machine_status.
(tls_symbolic_operand, tgd_symbolic_operand, tld_symbolic_operand,
tie_symbolic_operand, tle_symbolic_operand): New functions.
(symbolic_operand): Disallow tls_symbolic_operand.
(symbolic_memory_operand): Likewise.
(tls_call_delay, sparc_cannot_force_const_mem, legitimate_constant_p,
constant_address_p, legitimate_pic_operand_p, legitimate_address_p):
New functions.
(sparc_tls_symbol): New variable.
(sparc_tls_get_addr, sparc_tls_got, legitimize_tls_address,
legitimize_address): New functions.
(print_operand): Handle %&.
(sparc_init_machine_status, get_some_local_dynamic_name,
get_some_local_dynamic_name_1): New functions.
(sparc_output_dwarf_dtprel): New function.
* config/sparc/sparc.h (CONSTANT_ADDRESS_P): Moved into
constant_address_p.
(LEGITIMATE_PIC_OPERAND_P): Moved into legitimate_pic_operand_p.
(LEGITIMATE_CONSTANT_P): Moved into legitimate_constant_p.
(GO_IF_LEGITIMATE_ADDRESS): Moved into legitimate_address_p.
(LEGITIMIZE_ADDRESS): Moved into legitimize_address.
(PRINT_OPERAND_PUNCT_VALID_P): Add '&'.
(TARGET_TLS, TARGET_SUN_TLS, TARGET_GNU_TLS): Define.
(ASM_OUTPUT_DWARF_DTPREL): Define.
(PREDICATE_CODES): Add tgd_symbolic_operand, tld_symbolic_operand,
tie_symbolic_operand, tle_symbolic_operand.
* config/sparc/sparc.md (UNSPEC_TLSGD, UNSPEC_TLSLDM, UNSPEC_TLSLDO,
UNSPEC_TLSIE, UNSPEC_TLSLE, UNSPEC_TLSLD_BASE): New constants.
(tls_call_delay): New attribute.
(in_call_delay): Use it.
(movqi, movhi, movsi, movdi): Call legitimize_tls_address if needed.
(tgd_hi22, tgd_lo10, tgd_add32, tgd_add64, tgd_call32, tgd_call64,
tldm_hi22, tldm_lo10, tldm_add32, tldm_add64, tldm_call32, tldm_call64,
tldo_hix22, tldo_lox10, tldo_add32, tldo_add64, tie_hi22, tie_lo10,
tie_ld32, tie_ld64, tie_add32, tie_add64, tle_hix22_sp32,
tle_lox10_sp32, tle_hix22_sp64, tle_lox10_sp64): New insns.
(tldo_ldub_sp32, tldo_ldub1_sp32, tldo_ldub2_sp32, tldo_ldsb1_sp32,
tldo_ldsb2_sp32, tldo_ldub_sp64, tldo_ldub1_sp64, tldo_ldub2_sp64,
tldo_ldub3_sp64, tldo_ldsb1_sp64, tldo_ldsb2_sp64, tldo_ldsb3_sp64,
tldo_lduh_sp32, tldo_lduh1_sp32, tldo_ldsh1_sp32, tldo_lduh_sp64,
tldo_lduh1_sp64, tldo_lduh2_sp64, tldo_ldsh1_sp64, tldo_ldsh2_sp64,
tldo_lduw_sp32, tldo_lduw_sp64, tldo_lduw1_sp64, tldo_ldsw1_sp64,
tldo_ldx_sp64, tldo_stb_sp32, tldo_stb_sp64, tldo_sth_sp32,
tldo_sth_sp64, tldo_stw_sp32, tldo_stw_sp64, tldo_stx_sp64): New
insns.
* config/sparc/sparc-protos.h (legitimate_constant_p,
constant_address_p, legitimate_pic_operand_p, legitimate_address_p,
legitimize_tls_address, legitimize_address, tls_symbolic_operand,
tls_call_delay, sparc_output_dwarf_dtprel): New prototypes.
* config/sparc/linux.h (TARGET_GNU_TLS, TARGET_SUN_TLS): Define.
* config/sparc/linux64.h (TARGET_GNU_TLS, TARGET_SUN_TLS): Likewise.
* configure.in (sparc*-*-*): Add TLS check.
* configure: Rebuilt.
--- gcc/config/sparc/sparc.c.jj 2003-09-04 06:02:08.000000000 -0400
+++ gcc/config/sparc/sparc.c 2003-09-05 11:31:44.000000000 -0400
@@ -120,6 +120,12 @@ char sparc_leaf_regs[] =
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1};
+struct machine_function GTY(())
+{
+ /* Some local-dynamic TLS symbol name. */
+ const char *some_ld_name;
+};
+
/* Name of where we pretend to think the frame pointer points.
Normally, this is "%fp", but if we are in a leaf procedure,
this is "%sp+something". We record "something" separately as it may be
@@ -176,6 +182,12 @@ static void emit_hard_tfmode_operation (
static bool sparc_function_ok_for_sibcall (tree, tree);
static void sparc_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
HOST_WIDE_INT, tree);
+static struct machine_function * sparc_init_machine_status (void);
+static bool sparc_cannot_force_const_mem (rtx);
+static rtx sparc_tls_get_addr (void);
+static rtx sparc_tls_got (void);
+static const char *get_some_local_dynamic_name (void);
+static int get_some_local_dynamic_name_1 (rtx *, void *);
static bool sparc_rtx_costs (rtx, int, int, int *);
/* Option handling. */
@@ -240,6 +252,13 @@ enum processor_type sparc_cpu;
#undef TARGET_FUNCTION_OK_FOR_SIBCALL
#define TARGET_FUNCTION_OK_FOR_SIBCALL sparc_function_ok_for_sibcall
+#ifdef HAVE_AS_TLS
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS true
+#endif
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM sparc_cannot_force_const_mem
+
#undef TARGET_ASM_OUTPUT_MI_THUNK
#define TARGET_ASM_OUTPUT_MI_THUNK sparc_output_mi_thunk
#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
@@ -448,6 +467,9 @@ sparc_override_options (void)
/* Do various machine dependent initializations. */
sparc_init_modes ();
+
+ /* Set up function hooks. */
+ init_machine_status = sparc_init_machine_status;
}
/* Miscellaneous utilities. */
@@ -687,6 +709,41 @@ call_operand_address (rtx op, enum machi
return (symbolic_operand (op, mode) || memory_address_p (Pmode, op));
}
+/* If OP is a SYMBOL_REF of a thread-local symbol, return its TLS mode,
+ otherwise return 0. */
+
+int
+tls_symbolic_operand (rtx op)
+{
+ if (GET_CODE (op) != SYMBOL_REF)
+ return 0;
+ return SYMBOL_REF_TLS_MODEL (op);
+}
+
+int
+tgd_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ return tls_symbolic_operand (op) == TLS_MODEL_GLOBAL_DYNAMIC;
+}
+
+int
+tld_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ return tls_symbolic_operand (op) == TLS_MODEL_LOCAL_DYNAMIC;
+}
+
+int
+tie_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ return tls_symbolic_operand (op) == TLS_MODEL_INITIAL_EXEC;
+}
+
+int
+tle_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ return tls_symbolic_operand (op) == TLS_MODEL_LOCAL_EXEC;
+}
+
/* Returns 1 if OP is either a symbol reference or a sum of a symbol
reference and a constant. */
@@ -701,12 +758,15 @@ symbolic_operand (register rtx op, enum
switch (GET_CODE (op))
{
case SYMBOL_REF:
+ return !SYMBOL_REF_TLS_MODEL (op);
+
case LABEL_REF:
return 1;
case CONST:
op = XEXP (op, 0);
- return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
+ return (((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
+ && !SYMBOL_REF_TLS_MODEL (XEXP (op, 0)))
|| GET_CODE (XEXP (op, 0)) == LABEL_REF)
&& GET_CODE (XEXP (op, 1)) == CONST_INT);
@@ -726,8 +786,9 @@ symbolic_memory_operand (rtx op, enum ma
if (GET_CODE (op) != MEM)
return 0;
op = XEXP (op, 0);
- return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST
- || GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF);
+ return ((GET_CODE (op) == SYMBOL_REF && !SYMBOL_REF_TLS_MODEL (op))
+ || GET_CODE (op) == CONST || GET_CODE (op) == HIGH
+ || GET_CODE (op) == LABEL_REF);
}
/* Return truth value of statement that OP is a LABEL_REF of mode MODE. */
@@ -2793,6 +2854,32 @@ eligible_for_epilogue_delay (rtx trial,
return 0;
}
+/* Return nonzero if TRIAL can go into the call delay slot. */
+int
+tls_call_delay (rtx trial)
+{
+ rtx pat, unspec;
+
+ /* Binutils allows
+ call __tls_get_addr, %tgd_call (foo)
+ add %l7, %o0, %o0, %tgd_add (foo)
+ while Sun as/ld does not. */
+ if (TARGET_GNU_TLS || !TARGET_TLS)
+ return 1;
+
+ pat = PATTERN (trial);
+ if (GET_CODE (pat) != SET || GET_CODE (SET_DEST (pat)) != PLUS)
+ return 1;
+
+ unspec = XEXP (SET_DEST (pat), 1);
+ if (GET_CODE (unspec) != UNSPEC
+ || (XINT (unspec, 1) != UNSPEC_TLSGD
+ && XINT (unspec, 1) != UNSPEC_TLSLDM))
+ return 1;
+
+ return 0;
+}
+
/* Return nonzero if TRIAL can go into the sibling call
delay slot. */
@@ -2965,6 +3052,45 @@ reg_unused_after (rtx reg, rtx insn)
return 1;
}
+/* Determine if it's legal to put X into the constant pool. This
+ is not possible if X contains the address of a symbol that is
+ not constant (TLS) or not known at final link time (PIC). */
+
+static bool
+sparc_cannot_force_const_mem (rtx x)
+{
+ switch (GET_CODE (x))
+ {
+ case CONST_INT:
+ case CONST_DOUBLE:
+ /* Accept all non-symbolic constants. */
+ return false;
+
+ case LABEL_REF:
+ /* Labels are OK iff we are non-PIC. */
+ return flag_pic != 0;
+
+ case SYMBOL_REF:
+ /* 'Naked' TLS symbol references are never OK,
+ non-TLS symbols are OK iff we are non-PIC. */
+ if (SYMBOL_REF_TLS_MODEL (x))
+ return true;
+ else
+ return flag_pic != 0;
+
+ case CONST:
+ return sparc_cannot_force_const_mem (XEXP (x, 0));
+ case PLUS:
+ case MINUS:
+ return sparc_cannot_force_const_mem (XEXP (x, 0))
+ || sparc_cannot_force_const_mem (XEXP (x, 1));
+ case UNSPEC:
+ return true;
+ default:
+ abort ();
+ }
+}
+
/* The table we use to reference PIC data. */
static GTY(()) rtx global_offset_table;
@@ -3010,6 +3136,391 @@ pic_address_needs_scratch (rtx x)
return 0;
}
+/* Determine if a given RTX is a valid constant. We already know this
+ satisfies CONSTANT_P. */
+
+bool
+legitimate_constant_p (rtx x)
+{
+ rtx inner;
+
+ switch (GET_CODE (x))
+ {
+ case SYMBOL_REF:
+ /* TLS symbols are not constant. */
+ if (SYMBOL_REF_TLS_MODEL (x))
+ return false;
+ break;
+
+ case CONST:
+ inner = XEXP (x, 0);
+
+ /* Offsets of TLS symbols are never valid.
+ Discourage CSE from creating them. */
+ if (GET_CODE (inner) == PLUS
+ && tls_symbolic_operand (XEXP (inner, 0)))
+ return false;
+ break;
+
+ case CONST_DOUBLE:
+ if (GET_MODE (x) == VOIDmode)
+ return true;
+
+ /* Floating point constants are generally not ok.
+ The only exception is 0.0 in VIS. */
+ if (TARGET_VIS
+ && (GET_MODE (x) == SFmode
+ || GET_MODE (x) == DFmode
+ || GET_MODE (x) == TFmode)
+ && fp_zero_operand (x, GET_MODE (x)))
+ return true;
+
+ return false;
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+/* Determine if a given RTX is a valid constant address. */
+
+bool
+constant_address_p (rtx x)
+{
+ switch (GET_CODE (x))
+ {
+ case LABEL_REF:
+ case CONST_INT:
+ case HIGH:
+ return true;
+
+ case CONST:
+ if (flag_pic && pic_address_needs_scratch (x))
+ return false;
+ return legitimate_constant_p (x);
+
+ case SYMBOL_REF:
+ return !flag_pic && legitimate_constant_p (x);
+
+ default:
+ return false;
+ }
+}
+
+/* Nonzero if the constant value X is a legitimate general operand
+ when generating PIC code. It is given that flag_pic is on and
+ that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
+
+bool
+legitimate_pic_operand_p (rtx x)
+{
+ if (pic_address_needs_scratch (x))
+ return false;
+ if (tls_symbolic_operand (x)
+ || (GET_CODE (x) == CONST
+ && GET_CODE (XEXP (x, 0)) == PLUS
+ && tls_symbolic_operand (XEXP (XEXP (x, 0), 0))))
+ return false;
+ return true;
+}
+
+/* Return nonzero if ADDR is a valid memory address.
+ STRICT specifies whether strict register checking applies. */
+
+int
+legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
+{
+ rtx rs1 = NULL, rs2 = NULL, imm1 = NULL, imm2;
+
+ if (REG_P (addr) || GET_CODE (addr) == SUBREG)
+ rs1 = addr;
+ else if (GET_CODE (addr) == PLUS)
+ {
+ rs1 = XEXP (addr, 0);
+ rs2 = XEXP (addr, 1);
+
+ /* Canonicalize. REG comes first, if there are no regs,
+ LO_SUM comes first. */
+ if (!REG_P (rs1)
+ && GET_CODE (rs1) != SUBREG
+ && (REG_P (rs2)
+ || GET_CODE (rs2) == SUBREG
+ || (GET_CODE (rs2) == LO_SUM && GET_CODE (rs1) != LO_SUM)))
+ {
+ rs1 = XEXP (addr, 1);
+ rs2 = XEXP (addr, 0);
+ }
+
+ if ((flag_pic == 1
+ && rs1 == pic_offset_table_rtx
+ && !REG_P (rs2)
+ && GET_CODE (rs2) != SUBREG
+ && GET_CODE (rs2) != LO_SUM
+ && GET_CODE (rs2) != MEM
+ && !tls_symbolic_operand (rs2)
+ && (! symbolic_operand (rs2, VOIDmode) || mode == Pmode)
+ && (GET_CODE (rs2) != CONST_INT || SMALL_INT (rs2)))
+ || ((REG_P (rs1)
+ || GET_CODE (rs1) == SUBREG)
+ && RTX_OK_FOR_OFFSET_P (rs2)))
+ {
+ imm1 = rs2;
+ rs2 = NULL;
+ }
+ else if ((REG_P (rs1) || GET_CODE (rs1) == SUBREG)
+ && (REG_P (rs2) || GET_CODE (rs2) == SUBREG))
+ {
+ /* We prohibit REG + REG for TFmode when there are no instructions
+ which accept REG+REG instructions. We do this because REG+REG
+ is not an offsetable address. If we get the situation in reload
+ where source and destination of a movtf pattern are both MEMs with
+ REG+REG address, then only one of them gets converted to an
+ offsetable address. */
+ if (mode == TFmode
+ && !(TARGET_FPU && TARGET_ARCH64 && TARGET_V9
+ && TARGET_HARD_QUAD))
+ return 0;
+
+ /* We prohibit REG + REG on ARCH32 if not optimizing for
+ DFmode/DImode because then mem_min_alignment is likely to be zero
+ after reload and the forced split would lack a matching splitter
+ pattern. */
+ if (TARGET_ARCH32 && !optimize
+ && (mode == DFmode || mode == DImode))
+ return 0;
+ }
+ else if (USE_AS_OFFSETABLE_LO10
+ && GET_CODE (rs1) == LO_SUM
+ && TARGET_ARCH64
+ && ! TARGET_CM_MEDMID
+ && RTX_OK_FOR_OLO10_P (rs2))
+ {
+ imm2 = rs2;
+ rs2 = NULL;
+ imm1 = XEXP (rs1, 1);
+ rs1 = XEXP (rs1, 0);
+ if (! CONSTANT_P (imm1) || tls_symbolic_operand (rs1))
+ return 0;
+ }
+ }
+ else if (GET_CODE (addr) == LO_SUM)
+ {
+ rs1 = XEXP (addr, 0);
+ imm1 = XEXP (addr, 1);
+
+ if (! CONSTANT_P (imm1) || tls_symbolic_operand (rs1))
+ return 0;
+
+ /* We can't allow TFmode, because an offset greater than or equal to the
+ alignment (8) may cause the LO_SUM to overflow if !v9. */
+ if (mode == TFmode && !TARGET_V9)
+ return 0;
+ }
+ else if (GET_CODE (addr) == CONST_INT && SMALL_INT (addr))
+ return 1;
+ else
+ return 0;
+
+ if (GET_CODE (rs1) == SUBREG)
+ rs1 = SUBREG_REG (rs1);
+ if (!REG_P (rs1))
+ return 0;
+
+ if (rs2)
+ {
+ if (GET_CODE (rs2) == SUBREG)
+ rs2 = SUBREG_REG (rs2);
+ if (!REG_P (rs2))
+ return 0;
+ }
+
+ if (strict)
+ {
+ if (!REGNO_OK_FOR_BASE_P (REGNO (rs1))
+ || (rs2 && !REGNO_OK_FOR_BASE_P (REGNO (rs2))))
+ return 0;
+ }
+ else
+ {
+ if ((REGNO (rs1) >= 32
+ && REGNO (rs1) != FRAME_POINTER_REGNUM
+ && REGNO (rs1) < FIRST_PSEUDO_REGISTER)
+ || (rs2
+ && (REGNO (rs2) >= 32
+ && REGNO (rs2) != FRAME_POINTER_REGNUM
+ && REGNO (rs2) < FIRST_PSEUDO_REGISTER)))
+ return 0;
+ }
+ return 1;
+}
+
+/* Construct the SYMBOL_REF for the tls_get_offset function. */
+
+static GTY(()) rtx sparc_tls_symbol;
+static rtx
+sparc_tls_get_addr (void)
+{
+ if (!sparc_tls_symbol)
+ sparc_tls_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tls_get_addr");
+
+ return sparc_tls_symbol;
+}
+
+static rtx
+sparc_tls_got (void)
+{
+ rtx temp;
+ if (flag_pic)
+ {
+ current_function_uses_pic_offset_table = 1;
+ return pic_offset_table_rtx;
+ }
+
+ if (!global_offset_table)
+ global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
+ temp = gen_reg_rtx (Pmode);
+ emit_move_insn (temp, global_offset_table);
+ return temp;
+}
+
+
+/* ADDR contains a thread-local SYMBOL_REF. Generate code to compute
+ this (thread-local) address. */
+
+rtx
+legitimize_tls_address (rtx addr)
+{
+ rtx temp1, temp2, temp3, ret, o0, got, insn;
+
+ if (no_new_pseudos)
+ abort ();
+
+ if (GET_CODE (addr) == SYMBOL_REF)
+ switch (SYMBOL_REF_TLS_MODEL (addr))
+ {
+ case TLS_MODEL_GLOBAL_DYNAMIC:
+ start_sequence ();
+ temp1 = gen_reg_rtx (SImode);
+ temp2 = gen_reg_rtx (SImode);
+ ret = gen_reg_rtx (Pmode);
+ o0 = gen_rtx_REG (Pmode, 8);
+ got = sparc_tls_got ();
+ emit_insn (gen_tgd_hi22 (temp1, addr));
+ emit_insn (gen_tgd_lo10 (temp2, temp1, addr));
+ if (TARGET_ARCH32)
+ {
+ emit_insn (gen_tgd_add32 (o0, got, temp2, addr));
+ insn = emit_call_insn (gen_tgd_call32 (o0, sparc_tls_get_addr (),
+ addr, const1_rtx));
+ }
+ else
+ {
+ emit_insn (gen_tgd_add64 (o0, got, temp2, addr));
+ insn = emit_call_insn (gen_tgd_call64 (o0, sparc_tls_get_addr (),
+ addr, const1_rtx));
+ }
+ CALL_INSN_FUNCTION_USAGE (insn)
+ = gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_USE (VOIDmode, o0),
+ CALL_INSN_FUNCTION_USAGE (insn));
+ insn = get_insns ();
+ end_sequence ();
+ emit_libcall_block (insn, ret, o0, addr);
+ break;
+
+ case TLS_MODEL_LOCAL_DYNAMIC:
+ start_sequence ();
+ temp1 = gen_reg_rtx (SImode);
+ temp2 = gen_reg_rtx (SImode);
+ temp3 = gen_reg_rtx (Pmode);
+ ret = gen_reg_rtx (Pmode);
+ o0 = gen_rtx_REG (Pmode, 8);
+ got = sparc_tls_got ();
+ emit_insn (gen_tldm_hi22 (temp1));
+ emit_insn (gen_tldm_lo10 (temp2, temp1));
+ if (TARGET_ARCH32)
+ {
+ emit_insn (gen_tldm_add32 (o0, got, temp2));
+ insn = emit_call_insn (gen_tldm_call32 (o0, sparc_tls_get_addr (),
+ const1_rtx));
+ }
+ else
+ {
+ emit_insn (gen_tldm_add64 (o0, got, temp2));
+ insn = emit_call_insn (gen_tldm_call64 (o0, sparc_tls_get_addr (),
+ const1_rtx));
+ }
+ CALL_INSN_FUNCTION_USAGE (insn)
+ = gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_USE (VOIDmode, o0),
+ CALL_INSN_FUNCTION_USAGE (insn));
+ insn = get_insns ();
+ end_sequence ();
+ emit_libcall_block (insn, temp3, o0,
+ gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
+ UNSPEC_TLSLD_BASE));
+ temp1 = gen_reg_rtx (SImode);
+ temp2 = gen_reg_rtx (SImode);
+ emit_insn (gen_tldo_hix22 (temp1, addr));
+ emit_insn (gen_tldo_lox10 (temp2, temp1, addr));
+ if (TARGET_ARCH32)
+ emit_insn (gen_tldo_add32 (ret, temp3, temp2, addr));
+ else
+ emit_insn (gen_tldo_add64 (ret, temp3, temp2, addr));
+ break;
+
+ case TLS_MODEL_INITIAL_EXEC:
+ temp1 = gen_reg_rtx (SImode);
+ temp2 = gen_reg_rtx (SImode);
+ temp3 = gen_reg_rtx (Pmode);
+ got = sparc_tls_got ();
+ emit_insn (gen_tie_hi22 (temp1, addr));
+ emit_insn (gen_tie_lo10 (temp2, temp1, addr));
+ if (TARGET_ARCH32)
+ emit_insn (gen_tie_ld32 (temp3, got, temp2, addr));
+ else
+ emit_insn (gen_tie_ld64 (temp3, got, temp2, addr));
+ if (TARGET_SUN_TLS)
+ {
+ ret = gen_reg_rtx (Pmode);
+ if (TARGET_ARCH32)
+ emit_insn (gen_tie_add32 (ret, gen_rtx_REG (Pmode, 7),
+ temp3, addr));
+ else
+ emit_insn (gen_tie_add64 (ret, gen_rtx_REG (Pmode, 7),
+ temp3, addr));
+ }
+ else
+ ret = gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, 7), temp3);
+ break;
+
+ case TLS_MODEL_LOCAL_EXEC:
+ temp1 = gen_reg_rtx (Pmode);
+ temp2 = gen_reg_rtx (Pmode);
+ if (TARGET_ARCH32)
+ {
+ emit_insn (gen_tle_hix22_sp32 (temp1, addr));
+ emit_insn (gen_tle_lox10_sp32 (temp2, temp1, addr));
+ }
+ else
+ {
+ emit_insn (gen_tle_hix22_sp64 (temp1, addr));
+ emit_insn (gen_tle_lox10_sp64 (temp2, temp1, addr));
+ }
+ ret = gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, 7), temp2);
+ break;
+
+ default:
+ abort ();
+ }
+
+ else
+ abort (); /* for now ... */
+
+ return ret;
+}
+
+
/* Legitimize PIC addresses. If the address is already position-independent,
we return ORIG. Newly generated position-independent addresses go into a
reg. This is REG if nonzero, otherwise we allocate register(s) as
@@ -3117,6 +3628,52 @@ legitimize_pic_address (rtx orig, enum m
return orig;
}
+/* Try machine-dependent ways of modifying an illegitimate address X
+ to be legitimate. If we find one, return the new, valid address.
+
+ OLDX is the address as it was before break_out_memory_refs was called.
+ In some cases it is useful to look at this to decide what needs to be done.
+
+ MODE is the mode of the operand pointed to by X. */
+
+rtx
+legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode)
+{
+ rtx orig_x = x;
+
+ if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == MULT)
+ x = gen_rtx_PLUS (Pmode, XEXP (x, 1),
+ force_operand (XEXP (x, 0), NULL_RTX));
+ if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == MULT)
+ x = gen_rtx_PLUS (Pmode, XEXP (x, 0),
+ force_operand (XEXP (x, 1), NULL_RTX));
+ if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == PLUS)
+ x = gen_rtx_PLUS (Pmode, force_operand (XEXP (x, 0), NULL_RTX),
+ XEXP (x, 1));
+ if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == PLUS)
+ x = gen_rtx_PLUS (Pmode, XEXP (x, 0),
+ force_operand (XEXP (x, 1), NULL_RTX));
+
+ if (x != orig_x && legitimate_address_p (mode, x, FALSE))
+ return x;
+
+ if (tls_symbolic_operand (x))
+ x = legitimize_tls_address (x);
+ else if (flag_pic)
+ x = legitimize_pic_address (x, mode, 0);
+ else if (GET_CODE (x) == PLUS && CONSTANT_ADDRESS_P (XEXP (x, 1)))
+ x = gen_rtx_PLUS (Pmode, XEXP (x, 0),
+ copy_to_mode_reg (Pmode, XEXP (x, 1)));
+ else if (GET_CODE (x) == PLUS && CONSTANT_ADDRESS_P (XEXP (x, 0)))
+ x = gen_rtx_PLUS (Pmode, XEXP (x, 1),
+ copy_to_mode_reg (Pmode, XEXP (x, 0)));
+ else if (GET_CODE (x) == SYMBOL_REF
+ || GET_CODE (x) == CONST
+ || GET_CODE (x) == LABEL_REF)
+ x = copy_to_suggested_reg (x, NULL_RTX, Pmode);
+ return x;
+}
+
/* Emit special PIC prologues. */
void
@@ -6095,6 +6652,10 @@ print_operand (FILE *file, rtx x, int co
/* ??? What if offset is too big? Perhaps the caller knows it isn't? */
fprintf (file, "%s+%d", frame_base_name, frame_base_offset);
return;
+ case '&':
+ /* Print some local dynamic TLS name. */
+ assemble_name (file, get_some_local_dynamic_name ());
+ return;
case 'Y':
/* Adjust the operand to take into account a RESTORE operation. */
if (GET_CODE (x) == CONST_INT)
@@ -8350,4 +8911,68 @@ sparc_output_mi_thunk (FILE *file, tree
no_new_pseudos = 0;
}
+/* How to allocate a 'struct machine_function'. */
+
+static struct machine_function *
+sparc_init_machine_status (void)
+{
+ return ggc_alloc_cleared (sizeof (struct machine_function));
+}
+
+/* Locate some local-dynamic symbol still in use by this function
+ so that we can print its name in local-dynamic base patterns. */
+
+static const char *
+get_some_local_dynamic_name (void)
+{
+ 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), get_some_local_dynamic_name_1, 0))
+ return cfun->machine->some_ld_name;
+
+ abort ();
+}
+
+static int
+get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
+{
+ rtx x = *px;
+
+ if (x
+ && GET_CODE (x) == SYMBOL_REF
+ && SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC)
+ {
+ cfun->machine->some_ld_name = XSTR (x, 0);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* This is called from dwarf2out.c via ASM_OUTPUT_DWARF_DTPREL.
+ We need to emit DTP-relative relocations. */
+
+void
+sparc_output_dwarf_dtprel (FILE *file, int size, rtx x)
+{
+ switch (size)
+ {
+ case 4:
+ fputs ("\t.word\t%r_tls_dtpoff32(", file);
+ break;
+ case 8:
+ fputs ("\t.xword\t%r_tls_dtpoff64(", file);
+ break;
+ default:
+ abort ();
+ }
+ output_addr_const (file, x);
+ fputs (")", file);
+}
+
#include "gt-sparc.h"
--- gcc/config/sparc/sparc.h.jj 2003-07-11 04:27:13.000000000 -0400
+++ gcc/config/sparc/sparc.h 2003-09-04 16:40:40.000000000 -0400
@@ -2099,27 +2099,18 @@ do { \
When PIC, we do not accept an address that would require a scratch reg
to load into a register. */
-#define CONSTANT_ADDRESS_P(X) \
- (GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \
- || GET_CODE (X) == CONST_INT || GET_CODE (X) == HIGH \
- || (GET_CODE (X) == CONST \
- && ! (flag_pic && pic_address_needs_scratch (X))))
+#define CONSTANT_ADDRESS_P(X) constant_address_p (X)
/* Define this, so that when PIC, reload won't try to reload invalid
addresses which require two reload registers. */
-#define LEGITIMATE_PIC_OPERAND_P(X) (! pic_address_needs_scratch (X))
+#define LEGITIMATE_PIC_OPERAND_P(X) legitimate_pic_operand_p (X)
/* Nonzero if the constant value X is a legitimate general operand.
Anything can be made to work except floating point constants.
If TARGET_VIS, 0.0 can be made to work as well. */
-#define LEGITIMATE_CONSTANT_P(X) \
- (GET_CODE (X) != CONST_DOUBLE || GET_MODE (X) == VOIDmode || \
- (TARGET_VIS && \
- (GET_MODE (X) == SFmode || GET_MODE (X) == DFmode || \
- GET_MODE (X) == TFmode) && \
- fp_zero_operand (X, GET_MODE (X))))
+#define LEGITIMATE_CONSTANT_P(X) legitimate_constant_p (X)
/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
and check its validity for a certain class.
@@ -2226,110 +2217,19 @@ do { \
#define RTX_OK_FOR_OLO10_P(X) \
(GET_CODE (X) == CONST_INT && INTVAL (X) >= -0x1000 && INTVAL (X) < 0xc00 - 8)
+#ifdef REG_OK_STRICT
#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
-{ if (RTX_OK_FOR_BASE_P (X)) \
+{ \
+ if (legitimate_address_p (MODE, X, 1)) \
goto ADDR; \
- else if (GET_CODE (X) == PLUS) \
- { \
- register rtx op0 = XEXP (X, 0); \
- register rtx op1 = XEXP (X, 1); \
- if (flag_pic && op0 == pic_offset_table_rtx) \
- { \
- if (RTX_OK_FOR_BASE_P (op1)) \
- goto ADDR; \
- else if (flag_pic == 1 \
- && GET_CODE (op1) != REG \
- && GET_CODE (op1) != LO_SUM \
- && GET_CODE (op1) != MEM \
- && (! SYMBOLIC_CONST (op1) \
- || MODE == Pmode) \
- && (GET_CODE (op1) != CONST_INT \
- || SMALL_INT (op1))) \
- goto ADDR; \
- } \
- else if (RTX_OK_FOR_BASE_P (op0)) \
- { \
- if ((RTX_OK_FOR_INDEX_P (op1) \
- /* We prohibit REG + REG for TFmode when \
- there are no instructions which accept \
- REG+REG instructions. We do this \
- because REG+REG is not an offsetable \
- address. If we get the situation \
- in reload where source and destination \
- of a movtf pattern are both MEMs with \
- REG+REG address, then only one of them \
- gets converted to an offsetable \
- address. */ \
- && (MODE != TFmode \
- || (TARGET_FPU && TARGET_ARCH64 \
- && TARGET_V9 \
- && TARGET_HARD_QUAD)) \
- /* We prohibit REG + REG on ARCH32 if \
- not optimizing for DFmode/DImode \
- because then mem_min_alignment is \
- likely to be zero after reload and the \
- forced split would lack a matching \
- splitter pattern. */ \
- && (TARGET_ARCH64 || optimize \
- || (MODE != DFmode \
- && MODE != DImode))) \
- || RTX_OK_FOR_OFFSET_P (op1)) \
- goto ADDR; \
- } \
- else if (RTX_OK_FOR_BASE_P (op1)) \
- { \
- if ((RTX_OK_FOR_INDEX_P (op0) \
- /* See the previous comment. */ \
- && (MODE != TFmode \
- || (TARGET_FPU && TARGET_ARCH64 \
- && TARGET_V9 \
- && TARGET_HARD_QUAD)) \
- && (TARGET_ARCH64 || optimize \
- || (MODE != DFmode \
- && MODE != DImode))) \
- || RTX_OK_FOR_OFFSET_P (op0)) \
- goto ADDR; \
- } \
- else if (USE_AS_OFFSETABLE_LO10 \
- && GET_CODE (op0) == LO_SUM \
- && TARGET_ARCH64 \
- && ! TARGET_CM_MEDMID \
- && RTX_OK_FOR_OLO10_P (op1)) \
- { \
- register rtx op00 = XEXP (op0, 0); \
- register rtx op01 = XEXP (op0, 1); \
- if (RTX_OK_FOR_BASE_P (op00) \
- && CONSTANT_P (op01)) \
- goto ADDR; \
- } \
- else if (USE_AS_OFFSETABLE_LO10 \
- && GET_CODE (op1) == LO_SUM \
- && TARGET_ARCH64 \
- && ! TARGET_CM_MEDMID \
- && RTX_OK_FOR_OLO10_P (op0)) \
- { \
- register rtx op10 = XEXP (op1, 0); \
- register rtx op11 = XEXP (op1, 1); \
- if (RTX_OK_FOR_BASE_P (op10) \
- && CONSTANT_P (op11)) \
- goto ADDR; \
- } \
- } \
- else if (GET_CODE (X) == LO_SUM) \
- { \
- register rtx op0 = XEXP (X, 0); \
- register rtx op1 = XEXP (X, 1); \
- if (RTX_OK_FOR_BASE_P (op0) \
- && CONSTANT_P (op1) \
- /* We can't allow TFmode, because an offset \
- greater than or equal to the alignment (8) \
- may cause the LO_SUM to overflow if !v9. */\
- && (MODE != TFmode || TARGET_V9)) \
- goto ADDR; \
- } \
- else if (GET_CODE (X) == CONST_INT && SMALL_INT (X)) \
+}
+#else
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
+{ \
+ if (legitimate_address_p (MODE, X, 0)) \
goto ADDR; \
}
+#endif
/* Go to LABEL if ADDR (a legitimate address expression)
has an effect that depends on the machine mode it is used for.
@@ -2374,33 +2274,11 @@ do { \
/* On SPARC, change REG+N into REG+REG, and REG+(X*Y) into REG+REG. */
#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \
-{ rtx sparc_x = (X); \
- if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == MULT) \
- (X) = gen_rtx_PLUS (Pmode, XEXP (X, 1), \
- force_operand (XEXP (X, 0), NULL_RTX)); \
- if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == MULT) \
- (X) = gen_rtx_PLUS (Pmode, XEXP (X, 0), \
- force_operand (XEXP (X, 1), NULL_RTX)); \
- if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == PLUS) \
- (X) = gen_rtx_PLUS (Pmode, force_operand (XEXP (X, 0), NULL_RTX),\
- XEXP (X, 1)); \
- if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == PLUS) \
- (X) = gen_rtx_PLUS (Pmode, XEXP (X, 0), \
- force_operand (XEXP (X, 1), NULL_RTX)); \
- if (sparc_x != (X) && memory_address_p (MODE, X)) \
- goto WIN; \
- if (flag_pic) (X) = legitimize_pic_address (X, MODE, 0); \
- else if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 1))) \
- (X) = gen_rtx_PLUS (Pmode, XEXP (X, 0), \
- copy_to_mode_reg (Pmode, XEXP (X, 1))); \
- else if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 0))) \
- (X) = gen_rtx_PLUS (Pmode, XEXP (X, 1), \
- copy_to_mode_reg (Pmode, XEXP (X, 0))); \
- else if (GET_CODE (X) == SYMBOL_REF || GET_CODE (X) == CONST \
- || GET_CODE (X) == LABEL_REF) \
- (X) = copy_to_suggested_reg (X, NULL_RTX, Pmode); \
- if (memory_address_p (MODE, X)) \
- goto WIN; }
+{ \
+ (X) = legitimize_address (X, OLDX, MODE); \
+ if (memory_address_p (MODE, X)) \
+ goto WIN; \
+}
/* Try a machine-dependent way of reloading an illegitimate address
operand. If we find one, push the reload and jump to WIN. This
@@ -2845,8 +2723,16 @@ do { \
#define ASM_OUTPUT_IDENT(FILE, NAME) \
fprintf (FILE, "%s\"%s\"\n", IDENT_ASM_OP, NAME);
+/* Emit a dtp-relative reference to a TLS variable. */
+
+#ifdef HAVE_AS_TLS
+#define ASM_OUTPUT_DWARF_DTPREL(FILE, SIZE, X) \
+ sparc_output_dwarf_dtprel (FILE, SIZE, X)
+#endif
+
#define PRINT_OPERAND_PUNCT_VALID_P(CHAR) \
- ((CHAR) == '#' || (CHAR) == '*' || (CHAR) == '^' || (CHAR) == '(' || (CHAR) == '_')
+ ((CHAR) == '#' || (CHAR) == '*' || (CHAR) == '^' \
+ || (CHAR) == '(' || (CHAR) == '_' || (CHAR) == '&')
/* Print operand X (an rtx) in assembler syntax to file FILE.
CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
@@ -2933,6 +2819,14 @@ do { \
} \
}
+#ifdef HAVE_AS_TLS
+#define TARGET_TLS 1
+#else
+#define TARGET_TLS 0
+#endif
+#define TARGET_SUN_TLS TARGET_TLS
+#define TARGET_GNU_TLS 0
+
/* Define the codes that are matched by predicates in sparc.c. */
#define PREDICATE_CODES \
@@ -2980,7 +2874,11 @@ do { \
{"clobbered_register", {REG}}, \
{"input_operand", {SUBREG, REG, CONST_INT, MEM, CONST}}, \
{"const64_operand", {CONST_INT, CONST_DOUBLE}}, \
-{"const64_high_operand", {CONST_INT, CONST_DOUBLE}},
+{"const64_high_operand", {CONST_INT, CONST_DOUBLE}}, \
+{"tgd_symbolic_operand", {SYMBOL_REF}}, \
+{"tld_symbolic_operand", {SYMBOL_REF}}, \
+{"tie_symbolic_operand", {SYMBOL_REF}}, \
+{"tle_symbolic_operand", {SYMBOL_REF}},
/* The number of Pmode words for the setjmp buffer. */
#define JMP_BUF_SIZE 12
--- gcc/config/sparc/sparc.md.jj 2003-07-11 04:27:13.000000000 -0400
+++ gcc/config/sparc/sparc.md 2003-09-04 16:40:40.000000000 -0400
@@ -38,6 +38,13 @@
(UNSPEC_EMB_TEXTHI 14)
(UNSPEC_EMB_TEXTULO 15)
(UNSPEC_EMB_SETHM 18)
+
+ (UNSPEC_TLSGD 30)
+ (UNSPEC_TLSLDM 31)
+ (UNSPEC_TLSLDO 32)
+ (UNSPEC_TLSIE 33)
+ (UNSPEC_TLSLE 34)
+ (UNSPEC_TLSLD_BASE 35)
])
(define_constants
@@ -195,6 +202,9 @@
;; Attributes for instruction and branch scheduling
+(define_attr "tls_call_delay" "false,true"
+ (symbol_ref "tls_call_delay (insn)"))
+
(define_attr "in_call_delay" "false,true"
(cond [(eq_attr "type" "uncond_branch,branch,call,sibcall,call_no_delay_slot,multi")
(const_string "false")
@@ -202,7 +212,8 @@
(if_then_else (eq_attr "length" "1")
(const_string "true")
(const_string "false"))]
- (if_then_else (eq_attr "length" "1")
+ (if_then_else (and (eq_attr "length" "1")
+ (eq_attr "tls_call_delay" "true"))
(const_string "true")
(const_string "false"))))
@@ -1681,6 +1692,10 @@
}
}
+ /* Fixup TLS cases. */
+ if (tls_symbolic_operand (operands [1]))
+ operands[1] = legitimize_tls_address (operands[1]);
+
/* Fixup PIC cases. */
if (flag_pic)
{
@@ -1740,6 +1755,10 @@
}
}
+ /* Fixup TLS cases. */
+ if (tls_symbolic_operand (operands [1]))
+ operands[1] = legitimize_tls_address (operands[1]);
+
/* Fixup PIC cases. */
if (flag_pic)
{
@@ -1822,6 +1841,10 @@
}
}
+ /* Fixup TLS cases. */
+ if (tls_symbolic_operand (operands [1]))
+ operands[1] = legitimize_tls_address (operands[1]);
+
/* Fixup PIC cases. */
if (flag_pic)
{
@@ -1998,6 +2021,10 @@
}
}
+ /* Fixup TLS cases. */
+ if (tls_symbolic_operand (operands [1]))
+ operands[1] = legitimize_tls_address (operands[1]);
+
if (flag_pic)
{
if (CONSTANT_P (operands[1])
@@ -8366,3 +8393,566 @@
"TARGET_V9"
"t%C0\t%%xcc, %1"
[(set_attr "type" "trap")])
+
+;; TLS support
+(define_insn "tgd_hi22"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (high:SI (unspec:SI [(match_operand 1 "tgd_symbolic_operand" "")]
+ UNSPEC_TLSGD)))]
+ "TARGET_TLS"
+ "sethi\\t%%tgd_hi22(%a1), %0")
+
+(define_insn "tgd_lo10"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lo_sum:SI (match_operand:SI 1 "register_operand" "r")
+ (unspec:SI [(match_operand 2 "tgd_symbolic_operand" "")]
+ UNSPEC_TLSGD)))]
+ "TARGET_TLS"
+ "add\\t%1, %%tgd_lo10(%a2), %0")
+
+(define_insn "tgd_add32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (match_operand:SI 1 "register_operand" "r")
+ (unspec:SI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tgd_symbolic_operand" "")]
+ UNSPEC_TLSGD)))]
+ "TARGET_TLS && TARGET_ARCH32"
+ "add\\t%1, %2, %0, %%tgd_add(%a3)")
+
+(define_insn "tgd_add64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (match_operand:DI 1 "register_operand" "r")
+ (unspec:DI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tgd_symbolic_operand" "")]
+ UNSPEC_TLSGD)))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "add\\t%1, %2, %0, %%tgd_add(%a3)")
+
+(define_insn "tgd_call32"
+ [(set (match_operand 0 "register_operand" "=r")
+ (call (mem:SI (unspec:SI [(match_operand:SI 1 "symbolic_operand" "s")
+ (match_operand 2 "tgd_symbolic_operand" "")]
+ UNSPEC_TLSGD))
+ (match_operand 3 "" "")))
+ (clobber (reg:SI 15))]
+ "TARGET_TLS && TARGET_ARCH32"
+ "call\t%a1, %%tgd_call(%a2)%#"
+ [(set_attr "type" "call")])
+
+(define_insn "tgd_call64"
+ [(set (match_operand 0 "register_operand" "=r")
+ (call (mem:DI (unspec:DI [(match_operand:DI 1 "symbolic_operand" "s")
+ (match_operand 2 "tgd_symbolic_operand" "")]
+ UNSPEC_TLSGD))
+ (match_operand 3 "" "")))
+ (clobber (reg:DI 15))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "call\t%a1, %%tgd_call(%a2)%#"
+ [(set_attr "type" "call")])
+
+(define_insn "tldm_hi22"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (high:SI (unspec:SI [(const_int 0)] UNSPEC_TLSLDM)))]
+ "TARGET_TLS"
+ "sethi\\t%%tldm_hi22(%&), %0")
+
+(define_insn "tldm_lo10"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lo_sum:SI (match_operand:SI 1 "register_operand" "r")
+ (unspec:SI [(const_int 0)] UNSPEC_TLSLDM)))]
+ "TARGET_TLS"
+ "add\\t%1, %%tldm_lo10(%&), %0")
+
+(define_insn "tldm_add32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (match_operand:SI 1 "register_operand" "r")
+ (unspec:SI [(match_operand:SI 2 "register_operand" "r")]
+ UNSPEC_TLSLDM)))]
+ "TARGET_TLS && TARGET_ARCH32"
+ "add\\t%1, %2, %0, %%tldm_add(%&)")
+
+(define_insn "tldm_add64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (match_operand:DI 1 "register_operand" "r")
+ (unspec:DI [(match_operand:SI 2 "register_operand" "r")]
+ UNSPEC_TLSLDM)))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "add\\t%1, %2, %0, %%tldm_add(%&)")
+
+(define_insn "tldm_call32"
+ [(set (match_operand 0 "register_operand" "=r")
+ (call (mem:SI (unspec:SI [(match_operand:SI 1 "symbolic_operand" "s")]
+ UNSPEC_TLSLDM))
+ (match_operand 2 "" "")))
+ (clobber (reg:SI 15))]
+ "TARGET_TLS && TARGET_ARCH32"
+ "call\t%a1, %%tldm_call(%&)%#"
+ [(set_attr "type" "call")])
+
+(define_insn "tldm_call64"
+ [(set (match_operand 0 "register_operand" "=r")
+ (call (mem:DI (unspec:DI [(match_operand:DI 1 "symbolic_operand" "s")]
+ UNSPEC_TLSLDM))
+ (match_operand 2 "" "")))
+ (clobber (reg:DI 15))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "call\t%a1, %%tldm_call(%&)%#"
+ [(set_attr "type" "call")])
+
+(define_insn "tldo_hix22"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (high:SI (unspec:SI [(match_operand 1 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)))]
+ "TARGET_TLS"
+ "sethi\\t%%tldo_hix22(%a1), %0")
+
+(define_insn "tldo_lox10"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lo_sum:SI (match_operand:SI 1 "register_operand" "r")
+ (unspec:SI [(match_operand 2 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)))]
+ "TARGET_TLS"
+ "xor\\t%1, %%tldo_lox10(%a2), %0")
+
+(define_insn "tldo_add32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (match_operand:SI 1 "register_operand" "r")
+ (unspec:SI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)))]
+ "TARGET_TLS && TARGET_ARCH32"
+ "add\\t%1, %2, %0, %%tldo_add(%a3)")
+
+(define_insn "tldo_add64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (match_operand:DI 1 "register_operand" "r")
+ (unspec:DI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "add\\t%1, %2, %0, %%tldo_add(%a3)")
+
+(define_insn "tie_hi22"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (high:SI (unspec:SI [(match_operand 1 "tie_symbolic_operand" "")]
+ UNSPEC_TLSIE)))]
+ "TARGET_TLS"
+ "sethi\\t%%tie_hi22(%a1), %0")
+
+(define_insn "tie_lo10"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lo_sum:SI (match_operand:SI 1 "register_operand" "r")
+ (unspec:SI [(match_operand 2 "tie_symbolic_operand" "")]
+ UNSPEC_TLSIE)))]
+ "TARGET_TLS"
+ "add\\t%1, %%tie_lo10(%a2), %0")
+
+(define_insn "tie_ld32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tie_symbolic_operand" "")]
+ UNSPEC_TLSIE))]
+ "TARGET_TLS && TARGET_ARCH32"
+ "ld\\t[%1 + %2], %0, %%tie_ld(%a3)"
+ [(set_attr "type" "load")])
+
+(define_insn "tie_ld64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec:DI [(match_operand:DI 1 "register_operand" "r")
+ (match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tie_symbolic_operand" "")]
+ UNSPEC_TLSIE))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "ldx\\t[%1 + %2], %0, %%tie_ldx(%a3)"
+ [(set_attr "type" "load")])
+
+(define_insn "tie_add32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (match_operand:SI 1 "register_operand" "r")
+ (unspec:SI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSIE)))]
+ "TARGET_SUN_TLS && TARGET_ARCH32"
+ "add\\t%1, %2, %0, %%tie_add(%a3)")
+
+(define_insn "tie_add64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (match_operand:DI 1 "register_operand" "r")
+ (unspec:DI [(match_operand:DI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSIE)))]
+ "TARGET_SUN_TLS && TARGET_ARCH64"
+ "add\\t%1, %2, %0, %%tie_add(%a3)")
+
+(define_insn "tle_hix22_sp32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (high:SI (unspec:SI [(match_operand 1 "tle_symbolic_operand" "")]
+ UNSPEC_TLSLE)))]
+ "TARGET_TLS && TARGET_ARCH32"
+ "sethi\\t%%tle_hix22(%a1), %0")
+
+(define_insn "tle_lox10_sp32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lo_sum:SI (match_operand:SI 1 "register_operand" "r")
+ (unspec:SI [(match_operand 2 "tle_symbolic_operand" "")]
+ UNSPEC_TLSLE)))]
+ "TARGET_TLS && TARGET_ARCH32"
+ "xor\\t%1, %%tle_lox10(%a2), %0")
+
+(define_insn "tle_hix22_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (high:DI (unspec:DI [(match_operand 1 "tle_symbolic_operand" "")]
+ UNSPEC_TLSLE)))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "sethi\\t%%tle_hix22(%a1), %0")
+
+(define_insn "tle_lox10_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (lo_sum:DI (match_operand:DI 1 "register_operand" "r")
+ (unspec:DI [(match_operand 2 "tle_symbolic_operand" "")]
+ UNSPEC_TLSLE)))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "xor\\t%1, %%tle_lox10(%a2), %0")
+
+;; Now patterns combinding tldo_add{32,64} with some integer loads or stores
+(define_insn "*tldo_ldub_sp32"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (mem:QI (plus:SI (unspec:SI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:SI 1 "register_operand" "r"))))]
+ "TARGET_TLS && TARGET_ARCH32"
+ "ldub\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "load")
+ (set_attr "us3load_type" "3cycle")])
+
+(define_insn "*tldo_ldub1_sp32"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (zero_extend:HI (mem:QI (plus:SI (unspec:SI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:SI 1 "register_operand" "r")))))]
+ "TARGET_TLS && TARGET_ARCH32"
+ "ldub\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "load")
+ (set_attr "us3load_type" "3cycle")])
+
+(define_insn "*tldo_ldub2_sp32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI (mem:QI (plus:SI (unspec:SI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:SI 1 "register_operand" "r")))))]
+ "TARGET_TLS && TARGET_ARCH32"
+ "ldub\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "load")
+ (set_attr "us3load_type" "3cycle")])
+
+(define_insn "*tldo_ldsb1_sp32"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (sign_extend:HI (mem:QI (plus:SI (unspec:SI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:SI 1 "register_operand" "r")))))]
+ "TARGET_TLS && TARGET_ARCH32"
+ "ldsb\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "sload")
+ (set_attr "us3load_type" "3cycle")])
+
+(define_insn "*tldo_ldsb2_sp32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (mem:QI (plus:SI (unspec:SI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:SI 1 "register_operand" "r")))))]
+ "TARGET_TLS && TARGET_ARCH32"
+ "ldsb\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "sload")
+ (set_attr "us3load_type" "3cycle")])
+
+(define_insn "*tldo_ldub_sp64"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (mem:QI (plus:DI (unspec:DI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:DI 1 "register_operand" "r"))))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "ldub\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "load")
+ (set_attr "us3load_type" "3cycle")])
+
+(define_insn "*tldo_ldub1_sp64"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (zero_extend:HI (mem:QI (plus:DI (unspec:DI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:DI 1 "register_operand" "r")))))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "ldub\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "load")
+ (set_attr "us3load_type" "3cycle")])
+
+(define_insn "*tldo_ldub2_sp64"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI (mem:QI (plus:DI (unspec:DI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:DI 1 "register_operand" "r")))))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "ldub\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "load")
+ (set_attr "us3load_type" "3cycle")])
+
+(define_insn "*tldo_ldub3_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extend:DI (mem:QI (plus:DI (unspec:DI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:DI 1 "register_operand" "r")))))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "ldub\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "load")
+ (set_attr "us3load_type" "3cycle")])
+
+(define_insn "*tldo_ldsb1_sp64"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (sign_extend:HI (mem:QI (plus:DI (unspec:DI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:DI 1 "register_operand" "r")))))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "ldsb\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "sload")
+ (set_attr "us3load_type" "3cycle")])
+
+(define_insn "*tldo_ldsb2_sp64"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (mem:QI (plus:DI (unspec:DI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:DI 1 "register_operand" "r")))))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "ldsb\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "sload")
+ (set_attr "us3load_type" "3cycle")])
+
+(define_insn "*tldo_ldsb3_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (sign_extend:DI (mem:QI (plus:DI (unspec:DI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:DI 1 "register_operand" "r")))))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "ldsb\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "sload")
+ (set_attr "us3load_type" "3cycle")])
+
+(define_insn "*tldo_lduh_sp32"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (mem:HI (plus:SI (unspec:SI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:SI 1 "register_operand" "r"))))]
+ "TARGET_TLS && TARGET_ARCH32"
+ "lduh\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "load")
+ (set_attr "us3load_type" "3cycle")])
+
+(define_insn "*tldo_lduh1_sp32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI (mem:HI (plus:SI (unspec:SI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:SI 1 "register_operand" "r")))))]
+ "TARGET_TLS && TARGET_ARCH32"
+ "lduh\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "load")
+ (set_attr "us3load_type" "3cycle")])
+
+(define_insn "*tldo_ldsh1_sp32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (mem:HI (plus:SI (unspec:SI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:SI 1 "register_operand" "r")))))]
+ "TARGET_TLS && TARGET_ARCH32"
+ "ldsh\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "sload")
+ (set_attr "us3load_type" "3cycle")])
+
+(define_insn "*tldo_lduh_sp64"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (mem:HI (plus:DI (unspec:DI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:DI 1 "register_operand" "r"))))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "lduh\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "load")
+ (set_attr "us3load_type" "3cycle")])
+
+(define_insn "*tldo_lduh1_sp64"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI (mem:HI (plus:DI (unspec:DI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:DI 1 "register_operand" "r")))))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "lduh\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "load")
+ (set_attr "us3load_type" "3cycle")])
+
+(define_insn "*tldo_lduh2_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extend:DI (mem:HI (plus:DI (unspec:DI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:DI 1 "register_operand" "r")))))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "lduh\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "load")
+ (set_attr "us3load_type" "3cycle")])
+
+(define_insn "*tldo_ldsh1_sp64"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (mem:HI (plus:DI (unspec:DI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:DI 1 "register_operand" "r")))))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "ldsh\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "sload")
+ (set_attr "us3load_type" "3cycle")])
+
+(define_insn "*tldo_ldsh2_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (sign_extend:DI (mem:HI (plus:DI (unspec:DI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:DI 1 "register_operand" "r")))))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "ldsh\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "sload")
+ (set_attr "us3load_type" "3cycle")])
+
+(define_insn "*tldo_lduw_sp32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (mem:SI (plus:SI (unspec:SI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:SI 1 "register_operand" "r"))))]
+ "TARGET_TLS && TARGET_ARCH32"
+ "ld\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "load")])
+
+(define_insn "*tldo_lduw_sp64"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (mem:SI (plus:DI (unspec:DI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:DI 1 "register_operand" "r"))))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "lduw\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "load")])
+
+(define_insn "*tldo_lduw1_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extend:DI (mem:SI (plus:DI (unspec:DI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:DI 1 "register_operand" "r")))))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "lduw\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "load")])
+
+(define_insn "*tldo_ldsw1_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (sign_extend:DI (mem:SI (plus:DI (unspec:DI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:DI 1 "register_operand" "r")))))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "ldsw\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "sload")
+ (set_attr "us3load_type" "3cycle")])
+
+(define_insn "*tldo_ldx_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (mem:DI (plus:DI (unspec:DI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:DI 1 "register_operand" "r"))))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "ldx\t[%1 + %2], %0, %%tldo_add(%3)"
+ [(set_attr "type" "load")])
+
+(define_insn "*tldo_stb_sp32"
+ [(set (mem:QI (plus:SI (unspec:SI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:SI 1 "register_operand" "r")))
+ (match_operand:QI 0 "register_operand" "=r"))]
+ "TARGET_TLS && TARGET_ARCH32"
+ "stb\t%0, [%1 + %2], %%tldo_add(%3)"
+ [(set_attr "type" "store")])
+
+(define_insn "*tldo_stb_sp64"
+ [(set (mem:QI (plus:DI (unspec:DI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:DI 1 "register_operand" "r")))
+ (match_operand:QI 0 "register_operand" "=r"))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "stb\t%0, [%1 + %2], %%tldo_add(%3)"
+ [(set_attr "type" "store")])
+
+(define_insn "*tldo_sth_sp32"
+ [(set (mem:HI (plus:SI (unspec:SI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:SI 1 "register_operand" "r")))
+ (match_operand:HI 0 "register_operand" "=r"))]
+ "TARGET_TLS && TARGET_ARCH32"
+ "sth\t%0, [%1 + %2], %%tldo_add(%3)"
+ [(set_attr "type" "store")])
+
+(define_insn "*tldo_sth_sp64"
+ [(set (mem:HI (plus:DI (unspec:DI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:DI 1 "register_operand" "r")))
+ (match_operand:HI 0 "register_operand" "=r"))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "sth\t%0, [%1 + %2], %%tldo_add(%3)"
+ [(set_attr "type" "store")])
+
+(define_insn "*tldo_stw_sp32"
+ [(set (mem:SI (plus:SI (unspec:SI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:SI 1 "register_operand" "r")))
+ (match_operand:SI 0 "register_operand" "=r"))]
+ "TARGET_TLS && TARGET_ARCH32"
+ "st\t%0, [%1 + %2], %%tldo_add(%3)"
+ [(set_attr "type" "store")])
+
+(define_insn "*tldo_stw_sp64"
+ [(set (mem:SI (plus:DI (unspec:DI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:DI 1 "register_operand" "r")))
+ (match_operand:SI 0 "register_operand" "=r"))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "stw\t%0, [%1 + %2], %%tldo_add(%3)"
+ [(set_attr "type" "store")])
+
+(define_insn "*tldo_stx_sp64"
+ [(set (mem:DI (plus:DI (unspec:DI [(match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:DI 1 "register_operand" "r")))
+ (match_operand:DI 0 "register_operand" "=r"))]
+ "TARGET_TLS && TARGET_ARCH64"
+ "stx\t%0, [%1 + %2], %%tldo_add(%3)"
+ [(set_attr "type" "store")])
--- gcc/config/sparc/linux.h.jj 2003-09-04 06:02:07.000000000 -0400
+++ gcc/config/sparc/linux.h 2003-09-04 16:40:40.000000000 -0400
@@ -232,6 +232,13 @@ do { \
#define LINK_EH_SPEC "%{!static:--eh-frame-hdr} "
#endif
+#ifdef HAVE_AS_TLS
+#undef TARGET_SUN_TLS
+#undef TARGET_GNU_TLS
+#define TARGET_SUN_TLS 0
+#define TARGET_GNU_TLS 1
+#endif
+
/* Don't be different from other Linux platforms in this regard. */
#define HANDLE_PRAGMA_PACK_PUSH_POP
--- gcc/config/sparc/sparc-protos.h.jj 2003-08-26 10:53:14.000000000 -0400
+++ gcc/config/sparc/sparc-protos.h 2003-09-05 11:36:05.000000000 -0400
@@ -78,7 +78,13 @@ extern void emit_tfmode_cvt (enum rtx_co
extern int gen_v9_scc (enum rtx_code, rtx *);
extern void sparc_initialize_trampoline (rtx, rtx, rtx);
extern void sparc64_initialize_trampoline (rtx, rtx, rtx);
+extern bool legitimate_constant_p (rtx);
+extern bool constant_address_p (rtx);
+extern bool legitimate_pic_operand_p (rtx);
+extern int legitimate_address_p (enum machine_mode, rtx, int);
extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx);
+extern rtx legitimize_tls_address (rtx);
+extern rtx legitimize_address (rtx, rtx, enum machine_mode);
extern void sparc_defer_case_vector (rtx, rtx, int);
extern void sparc_emit_set_const32 (rtx, rtx);
extern void sparc_emit_set_const64 (rtx, rtx);
@@ -96,9 +102,11 @@ extern int arith_4096_operand (rtx, enum
extern int zero_operand (rtx, enum machine_mode);
extern int fp_zero_operand (rtx, enum machine_mode);
extern int reg_or_0_operand (rtx, enum machine_mode);
+extern int tls_symbolic_operand (rtx);
extern int empty_delay_slot (rtx);
extern int eligible_for_epilogue_delay (rtx, int);
extern int eligible_for_sibcall_delay (rtx);
+extern int tls_call_delay (rtx);
extern int emit_move_sequence (rtx, enum machine_mode);
extern int fp_sethi_p (rtx);
extern int fp_mov_p (rtx);
@@ -116,6 +124,7 @@ extern char *sparc_v8plus_shift (rtx *,
extern int sparc_check_64 (rtx, rtx);
extern rtx gen_df_reg (rtx, int);
extern int sparc_extra_constraint_check (rtx, int, int);
+extern void sparc_output_dwarf_dtprel (FILE*, int, rtx);
#endif /* RTX_CODE */
#endif /* __SPARC_PROTOS_H__ */
--- gcc/config/sparc/linux64.h.jj 2003-09-04 06:02:07.000000000 -0400
+++ gcc/config/sparc/linux64.h 2003-09-04 16:40:40.000000000 -0400
@@ -315,6 +315,13 @@ do { \
#define LINK_EH_SPEC "%{!static:--eh-frame-hdr} "
#endif
+#ifdef HAVE_AS_TLS
+#undef TARGET_SUN_TLS
+#undef TARGET_GNU_TLS
+#define TARGET_SUN_TLS 0
+#define TARGET_GNU_TLS 1
+#endif
+
/* Don't be different from other Linux platforms in this regard. */
#define HANDLE_PRAGMA_PACK_PUSH_POP
--- gcc/configure.in.jj 2003-09-04 06:01:50.000000000 -0400
+++ gcc/configure.in 2003-09-04 16:40:40.000000000 -0400
@@ -2000,7 +2000,6 @@ foo: .long 25
tls_first_minor=13
;;
i[34567]86-*-*)
-changequote([,])dnl
conftest_s='
.section ".tdata","awT",@progbits
foo: .long 25
@@ -2147,6 +2146,34 @@ foo: .long 25
tls_first_minor=14
tls_as_opt="-m64 -Aesame"
;;
+ sparc*-*-*)
+ conftest_s='
+ .section ".tdata","awT",@progbits
+foo: .long 25
+ .text
+ sethi %tgd_hi22(foo), %o0
+ add %o0, %tgd_lo10(foo), %o1
+ add %l7, %o1, %o0, %tgd_add(foo)
+ call __tls_get_addr, %tgd_call(foo)
+ sethi %tldm_hi22(foo), %l1
+ add %l1, %tldm_lo10(foo), %l2
+ add %l7, %l2, %o0, %tldm_add(foo)
+ call __tls_get_addr, %tldm_call(foo)
+ sethi %tldo_hix22(foo), %l3
+ xor %l3, %tldo_lox10(foo), %l4
+ add %o0, %l4, %l5, %tldo_add(foo)
+ sethi %tie_hi22(foo), %o3
+ add %o3, %tie_lo10(foo), %o3
+ ld [%l7 + %o3], %o2, %tie_ld(foo)
+ add %g7, %o2, %o4, %tie_add(foo)
+ sethi %tle_hix22(foo), %l1
+ xor %l1, %tle_lox10(foo), %o5
+ ld [%g7 + %o5], %o1'
+ tls_first_major=2
+ tls_first_minor=14
+ tls_as_opt=-32
+ ;;
+changequote([,])dnl
esac
if test -z "$tls_first_major"; then
: # If we don't have a check, assume no support.
--- gcc/configure.jj 2003-09-04 06:01:49.000000000 -0400
+++ gcc/configure 2003-09-04 16:40:40.000000000 -0400
@@ -6661,6 +6661,33 @@ foo: .long 25
tls_first_minor=14
tls_as_opt="-m64 -Aesame"
;;
+ sparc*-*-*)
+ conftest_s='
+ .section ".tdata","awT",@progbits
+foo: .long 25
+ .text
+ sethi %tgd_hi22(foo), %o0
+ add %o0, %tgd_lo10(foo), %o1
+ add %l7, %o1, %o0, %tgd_add(foo)
+ call __tls_get_addr, %tgd_call(foo)
+ sethi %tldm_hi22(foo), %l1
+ add %l1, %tldm_lo10(foo), %l2
+ add %l7, %l2, %o0, %tldm_add(foo)
+ call __tls_get_addr, %tldm_call(foo)
+ sethi %tldo_hix22(foo), %l3
+ xor %l3, %tldo_lox10(foo), %l4
+ add %o0, %l4, %l5, %tldo_add(foo)
+ sethi %tie_hi22(foo), %o3
+ add %o3, %tie_lo10(foo), %o3
+ ld [%l7 + %o3], %o2, %tie_ld(foo)
+ add %g7, %o2, %o4, %tie_add(foo)
+ sethi %tle_hix22(foo), %l1
+ xor %l1, %tle_lox10(foo), %o5
+ ld [%g7 + %o5], %o1'
+ tls_first_major=2
+ tls_first_minor=14
+ tls_as_opt=-32
+ ;;
esac
if test -z "$tls_first_major"; then
: # If we don't have a check, assume no support.
Jakub