From 5751a10b97f8607b89325cecdac246d9ef758592 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Mon, 8 Sep 2003 08:57:05 +0200 Subject: [PATCH] sparc.c (struct machine_function): New type. * 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. From-SVN: r71202 --- gcc/ChangeLog | 58 ++++ gcc/config/sparc/linux.h | 7 + gcc/config/sparc/linux64.h | 7 + gcc/config/sparc/sparc-protos.h | 9 + gcc/config/sparc/sparc.c | 631 +++++++++++++++++++++++++++++++++++++++- gcc/config/sparc/sparc.h | 180 +++--------- gcc/config/sparc/sparc.md | 592 ++++++++++++++++++++++++++++++++++++- gcc/configure | 27 ++ gcc/configure.in | 29 +- 9 files changed, 1394 insertions(+), 146 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 06f8a05..f5cb771 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,61 @@ +2003-09-08 Jakub Jelinek + + * 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. + 2003-09-07 Eric Botcazou PR target/11689 diff --git a/gcc/config/sparc/linux.h b/gcc/config/sparc/linux.h index 87d3a70..a53e796 100644 --- a/gcc/config/sparc/linux.h +++ b/gcc/config/sparc/linux.h @@ -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 diff --git a/gcc/config/sparc/linux64.h b/gcc/config/sparc/linux64.h index f85d4aa..fe7470a 100644 --- a/gcc/config/sparc/linux64.h +++ b/gcc/config/sparc/linux64.h @@ -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 diff --git a/gcc/config/sparc/sparc-protos.h b/gcc/config/sparc/sparc-protos.h index 1b5af30..4b9582d 100644 --- a/gcc/config/sparc/sparc-protos.h +++ b/gcc/config/sparc/sparc-protos.h @@ -78,7 +78,13 @@ extern void emit_tfmode_cvt (enum rtx_code, rtx *); 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 machine_mode); 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 *, rtx, const char *); 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__ */ diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 84d27d2..9e651365 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -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 (enum rtx_code, rtx *); 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 machine_mode mode) 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 machine_mode mode) 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 machine_mode mode ATTRIBUTE_UNUSED) 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, int slot) 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 machine_mode mode ATTRIBUTE_UNUSED, 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 code) /* ??? 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 thunk_fndecl ATTRIBUTE_UNUSED, 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" diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h index 9235f66..a997602 100644 --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -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 diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index 07ce718..954e89d 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -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")]) diff --git a/gcc/configure b/gcc/configure index 0b47a0b..05dec41 100755 --- a/gcc/configure +++ b/gcc/configure @@ -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. diff --git a/gcc/configure.in b/gcc/configure.in index c6c6bae..b0926a7 100644 --- a/gcc/configure.in +++ b/gcc/configure.in @@ -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. -- 2.7.4