diff options
author | Daniel Jacobowitz <dan@codesourcery.com> | 2005-11-04 15:02:51 +0000 |
---|---|---|
committer | Daniel Jacobowitz <drow@gcc.gnu.org> | 2005-11-04 15:02:51 +0000 |
commit | d3585b76d63dd41df119b0118adb37dfe06867c0 (patch) | |
tree | 0b5c365ba47bb21bef0fb99092b7dea429e37aca /gcc/config/arm | |
parent | 802b34612cc1c7176de9de21c4183ce4db22e4cb (diff) | |
download | gcc-d3585b76d63dd41df119b0118adb37dfe06867c0.zip gcc-d3585b76d63dd41df119b0118adb37dfe06867c0.tar.gz gcc-d3585b76d63dd41df119b0118adb37dfe06867c0.tar.bz2 |
configure.ac: Add test for ARM TLS support.
* configure.ac: Add test for ARM TLS support.
* configure: Regenerated.
* config/arm/arm-protos.h (legitimize_tls_address)
(arm_tls_referenced_p, tls_mentioned_p)
(arm_output_addr_const_extra): New prototypes.
(thumb_legitimize_pic_address): Delete.
* config/arm/arm.c: Include "gt-arm.h".
(enum tls_reloc): New.
(arm_cannot_copy_insn_p, arm_tls_symbol_p, load_tls_operand)
(pcrel_constant_p, get_tls_get_addr, arm_load_tp)
(arm_call_tls_get_addr, legitimize_tls_address)
(arm_tls_referenced_p, arm_tls_operand_p_1, tls_mentioned_p)
(arm_init_tls_builtins, arm_emit_tls_decoration)
(arm_output_addr_const_extra): New functions.
(TARGET_CANNOT_COPY_INSN_P, TARGET_CANNOT_FORCE_CONST_MEM)
(TARGET_HAVE_TLS): Define.
(target_thread_pointer): New.
(arm_override_options): Handle -mtp=.
(legitimize_pic_address): Ignore UNSPECs.
(arm_legitimate_address_p, thumb_legitimate_address_p): Handle PC
relative symbols.
(arm_legitimize_address, thumb_legitimize_address): Handle TLS.
(tls_get_addr_libfunc): New variable.
(symbol_mentioned_p, label_mentioned_p): Ignore UNSPEC_TLS.
(arm_init_builtins): Call arm_init_tls_builtins.
(arm_expand_builtin): Handle ARM_BUILTIN_THREAD_POINTER.
(arm_encode_section_info): Call default_encode_section_info.
* config/arm/arm.h (TARGET_HARD_TP, TARGET_SOFT_TP): Define.
(enum arm_tp_type): New.
(target_thread_pointer): Add declaration.
(LEGITIMATE_CONSTANT_P): Handle TLS.
(LEGITIMATE_PIC_OPERAND_P): Handle TLS.
(OUTPUT_ADDR_CONST_EXTRA): Call arm_output_addr_const_extra.
(enum arm_builtins): Add ARM_BUILTIN_THREAD_POINTER.
* config/arm/arm.md: Add UNSPEC_TLS.
(movsi): Handle TLS.
(pic_add_dot_plus_four, pic_add_dot_plus_eight): Allow for
non-PIC.
(tls_load_dot_plus_eight): New insn and a peephole to create it.
(load_tp_hard, load_tp_soft): New insns.
* arm.opt: Add -mtp=.
* doc/invoke.texi (ARM Options): Document -mtp.
Co-Authored-By: Paul Brook <paul@codesourcery.com>
Co-Authored-By: Phil Blundell <pb@reciva.com>
From-SVN: r106489
Diffstat (limited to 'gcc/config/arm')
-rw-r--r-- | gcc/config/arm/arm-protos.h | 6 | ||||
-rw-r--r-- | gcc/config/arm/arm.c | 420 | ||||
-rw-r--r-- | gcc/config/arm/arm.h | 33 | ||||
-rw-r--r-- | gcc/config/arm/arm.md | 100 | ||||
-rw-r--r-- | gcc/config/arm/arm.opt | 4 |
5 files changed, 539 insertions, 24 deletions
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index b8913a1..2bd84ca 100644 --- a/gcc/config/arm/arm-protos.h +++ b/gcc/config/arm/arm-protos.h @@ -56,6 +56,7 @@ extern RTX_CODE arm_canonicalize_comparison (RTX_CODE, enum machine_mode, rtx *); extern int legitimate_pic_operand_p (rtx); extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx); +extern rtx legitimize_tls_address (rtx, rtx); extern int arm_legitimate_address_p (enum machine_mode, rtx, RTX_CODE, int); extern int thumb_legitimate_address_p (enum machine_mode, rtx, int); extern int thumb_legitimate_offset_p (enum machine_mode, HOST_WIDE_INT); @@ -66,6 +67,7 @@ extern rtx thumb_legitimize_reload_address (rtx *, enum machine_mode, int, int, extern int arm_const_double_rtx (rtx); extern int neg_const_double_rtx_ok_for_fpa (rtx); extern enum reg_class vfp_secondary_reload_class (enum machine_mode, rtx); +extern bool arm_tls_referenced_p (rtx); extern int cirrus_memory_offset (rtx); extern int arm_coproc_mem_operand (rtx, bool); @@ -74,6 +76,7 @@ extern int arm_no_early_alu_shift_dep (rtx, rtx); extern int arm_no_early_alu_shift_value_dep (rtx, rtx); extern int arm_no_early_mul_dep (rtx, rtx); +extern int tls_mentioned_p (rtx); extern int symbol_mentioned_p (rtx); extern int label_mentioned_p (rtx); extern RTX_CODE minmax_code (rtx); @@ -122,6 +125,8 @@ extern const char *vfp_output_fstmx (rtx *); extern void arm_set_return_address (rtx, rtx); extern int arm_eliminable_register (rtx); +extern bool arm_output_addr_const_extra (FILE *, rtx); + #if defined TREE_CODE extern rtx arm_function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, int); extern void arm_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree); @@ -161,7 +166,6 @@ extern const char *thumb_load_double_from_address (rtx *); extern const char *thumb_output_move_mem_multiple (int, rtx *); extern const char *thumb_call_via_reg (rtx); extern void thumb_expand_movmemqi (rtx *); -extern rtx *thumb_legitimize_pic_address (rtx, enum machine_mode, rtx); extern int thumb_go_if_legitimate_address (enum machine_mode, rtx); extern rtx arm_return_addr (int, rtx); extern void thumb_reload_out_hi (rtx *); diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 1bb6149..061c33a 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -188,6 +188,9 @@ static bool arm_cxx_use_aeabi_atexit (void); static void arm_init_libfuncs (void); static bool arm_handle_option (size_t, const char *, int); static unsigned HOST_WIDE_INT arm_shift_truncation_mask (enum machine_mode); +static bool arm_cannot_copy_insn_p (rtx); +static bool arm_tls_symbol_p (rtx x); + /* Initialize the GCC target structure. */ #if TARGET_DLLIMPORT_DECL_ATTRIBUTES @@ -353,6 +356,17 @@ static unsigned HOST_WIDE_INT arm_shift_truncation_mask (enum machine_mode); #define TARGET_ARM_EABI_UNWINDER true #endif /* TARGET_UNWIND_INFO */ +#undef TARGET_CANNOT_COPY_INSN_P +#define TARGET_CANNOT_COPY_INSN_P arm_cannot_copy_insn_p + +#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 arm_tls_referenced_p + struct gcc_target targetm = TARGET_INITIALIZER; /* Obstack for minipool constant handling. */ @@ -390,6 +404,9 @@ enum float_abi_type arm_float_abi; /* Which ABI to use. */ enum arm_abi_type arm_abi; +/* Which thread pointer model to use. */ +enum arm_tp_type target_thread_pointer = TP_AUTO; + /* Used to parse -mstructure_size_boundary command line option. */ int arm_structure_size_boundary = DEFAULT_STRUCTURE_SIZE_BOUNDARY; @@ -415,6 +432,7 @@ static int thumb_call_reg_needed; #define FL_VFPV2 (1 << 13) /* Vector Floating Point V2. */ #define FL_WBUF (1 << 14) /* Schedule for write buffer ops. Note: ARM6 & 7 derivatives only. */ +#define FL_ARCH6K (1 << 15) /* Architecture rel 6 K extensions. */ #define FL_IWMMXT (1 << 29) /* XScale v2 or "Intel Wireless MMX technology". */ @@ -430,9 +448,9 @@ static int thumb_call_reg_needed; #define FL_FOR_ARCH5TEJ FL_FOR_ARCH5TE #define FL_FOR_ARCH6 (FL_FOR_ARCH5TE | FL_ARCH6) #define FL_FOR_ARCH6J FL_FOR_ARCH6 -#define FL_FOR_ARCH6K FL_FOR_ARCH6 +#define FL_FOR_ARCH6K (FL_FOR_ARCH6 | FL_ARCH6K) #define FL_FOR_ARCH6Z FL_FOR_ARCH6 -#define FL_FOR_ARCH6ZK FL_FOR_ARCH6 +#define FL_FOR_ARCH6ZK FL_FOR_ARCH6K /* The bits in this mask specify which instructions we are allowed to generate. */ @@ -463,6 +481,9 @@ int arm_arch5e = 0; /* Nonzero if this chip supports the ARM Architecture 6 extensions. */ int arm_arch6 = 0; +/* Nonzero if this chip supports the ARM 6K extensions. */ +int arm_arch6k = 0; + /* Nonzero if this chip can benefit from load scheduling. */ int arm_ld_sched = 0; @@ -677,6 +698,16 @@ static const struct abi_name arm_all_abis[] = {"aapcs-linux", ARM_ABI_AAPCS_LINUX} }; +/* Supported TLS relocations. */ + +enum tls_reloc { + TLS_GD32, + TLS_LDM32, + TLS_LDO32, + TLS_IE32, + TLS_LE32 +}; + /* Return the number of bits set in VALUE. */ static unsigned bit_count (unsigned long value) @@ -1065,6 +1096,7 @@ arm_override_options (void) arm_arch5 = (insn_flags & FL_ARCH5) != 0; arm_arch5e = (insn_flags & FL_ARCH5E) != 0; arm_arch6 = (insn_flags & FL_ARCH6) != 0; + arm_arch6k = (insn_flags & FL_ARCH6K) != 0; arm_arch_xscale = (insn_flags & FL_XSCALE) != 0; arm_arch_cirrus = (insn_flags & FL_CIRRUS) != 0; @@ -1194,6 +1226,30 @@ arm_override_options (void) && (tune_flags & FL_MODE32) == 0) flag_schedule_insns = flag_schedule_insns_after_reload = 0; + if (target_thread_switch) + { + if (strcmp (target_thread_switch, "soft") == 0) + target_thread_pointer = TP_SOFT; + else if (strcmp (target_thread_switch, "auto") == 0) + target_thread_pointer = TP_AUTO; + else if (strcmp (target_thread_switch, "cp15") == 0) + target_thread_pointer = TP_CP15; + else + error ("invalid thread pointer option: -mtp=%s", target_thread_switch); + } + + /* Use the cp15 method if it is available. */ + if (target_thread_pointer == TP_AUTO) + { + if (arm_arch6k && !TARGET_THUMB) + target_thread_pointer = TP_CP15; + else + target_thread_pointer = TP_SOFT; + } + + if (TARGET_HARD_TP && TARGET_THUMB) + error ("can not use -mtp=cp15 with -mthumb"); + /* Override the default structure alignment for AAPCS ABI. */ if (TARGET_AAPCS_BASED) arm_structure_size_boundary = 8; @@ -3182,6 +3238,10 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg) && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx) return orig; + if (GET_CODE (XEXP (orig, 0)) == UNSPEC + && XINT (XEXP (orig, 0), 1) == UNSPEC_TLS) + return orig; + if (reg == 0) { gcc_assert (!no_new_pseudos); @@ -3355,6 +3415,19 @@ arm_address_register_rtx_p (rtx x, int strict_p) || regno == ARG_POINTER_REGNUM); } +/* Return TRUE if this rtx is the difference of a symbol and a label, + and will reduce to a PC-relative relocation in the object file. + Expressions like this can be left alone when generating PIC, rather + than forced through the GOT. */ +static int +pcrel_constant_p (rtx x) +{ + if (GET_CODE (x) == MINUS) + return symbol_mentioned_p (XEXP (x, 0)) && label_mentioned_p (XEXP (x, 1)); + + return FALSE; +} + /* Return nonzero if X is a valid ARM state address operand. */ int arm_legitimate_address_p (enum machine_mode mode, rtx x, RTX_CODE outer, @@ -3433,7 +3506,8 @@ arm_legitimate_address_p (enum machine_mode mode, rtx x, RTX_CODE outer, && code == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x) && ! (flag_pic - && symbol_mentioned_p (get_pool_constant (x)))) + && symbol_mentioned_p (get_pool_constant (x)) + && ! pcrel_constant_p (get_pool_constant (x)))) return 1; return 0; @@ -3658,8 +3732,9 @@ thumb_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p) && GET_MODE_SIZE (mode) == 4 && GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x) - && !(flag_pic - && symbol_mentioned_p (get_pool_constant (x)))) + && ! (flag_pic + && symbol_mentioned_p (get_pool_constant (x)) + && ! pcrel_constant_p (get_pool_constant (x)))) return 1; return 0; @@ -3685,11 +3760,163 @@ thumb_legitimate_offset_p (enum machine_mode mode, HOST_WIDE_INT val) } } +/* Build the SYMBOL_REF for __tls_get_addr. */ + +static GTY(()) rtx tls_get_addr_libfunc; + +static rtx +get_tls_get_addr (void) +{ + if (!tls_get_addr_libfunc) + tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr"); + return tls_get_addr_libfunc; +} + +static rtx +arm_load_tp (rtx target) +{ + if (!target) + target = gen_reg_rtx (SImode); + + if (TARGET_HARD_TP) + { + /* Can return in any reg. */ + emit_insn (gen_load_tp_hard (target)); + } + else + { + /* Always returned in r0. Immediately copy the result into a pseudo, + otherwise other uses of r0 (e.g. setting up function arguments) may + clobber the value. */ + + rtx tmp; + + emit_insn (gen_load_tp_soft ()); + + tmp = gen_rtx_REG (SImode, 0); + emit_move_insn (target, tmp); + } + return target; +} + +static rtx +load_tls_operand (rtx x, rtx reg) +{ + rtx tmp; + + if (reg == NULL_RTX) + reg = gen_reg_rtx (SImode); + + tmp = gen_rtx_CONST (SImode, x); + + emit_move_insn (reg, tmp); + + return reg; +} + +static rtx +arm_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc) +{ + rtx insns, label, sum; + + start_sequence (); + + label = gen_label_rtx (); + sum = gen_rtx_UNSPEC (Pmode, + gen_rtvec (4, x, GEN_INT (reloc), + gen_rtx_LABEL_REF (Pmode, label), + GEN_INT (TARGET_ARM ? 8 : 4)), + UNSPEC_TLS); + reg = load_tls_operand (sum, reg); + + if (TARGET_ARM) + emit_insn (gen_pic_add_dot_plus_eight (reg, label)); + else + emit_insn (gen_pic_add_dot_plus_four (reg, label)); + + *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX, LCT_PURE, /* LCT_CONST? */ + Pmode, 1, reg, Pmode); + + insns = get_insns (); + end_sequence (); + + return insns; +} + +rtx +legitimize_tls_address (rtx x, rtx reg) +{ + rtx dest, tp, label, sum, insns, ret, eqv, addend; + unsigned int model = SYMBOL_REF_TLS_MODEL (x); + + switch (model) + { + case TLS_MODEL_GLOBAL_DYNAMIC: + insns = arm_call_tls_get_addr (x, reg, &ret, TLS_GD32); + dest = gen_reg_rtx (Pmode); + emit_libcall_block (insns, dest, ret, x); + return dest; + + case TLS_MODEL_LOCAL_DYNAMIC: + insns = arm_call_tls_get_addr (x, reg, &ret, TLS_LDM32); + + /* Attach a unique REG_EQUIV, to allow the RTL optimizers to + share the LDM result with other LD model accesses. */ + eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx), + UNSPEC_TLS); + dest = gen_reg_rtx (Pmode); + emit_libcall_block (insns, dest, ret, x); + + /* Load the addend. */ + addend = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (TLS_LDO32)), + UNSPEC_TLS); + addend = force_reg (SImode, gen_rtx_CONST (SImode, addend)); + return gen_rtx_PLUS (Pmode, dest, addend); + + case TLS_MODEL_INITIAL_EXEC: + label = gen_label_rtx (); + sum = gen_rtx_UNSPEC (Pmode, + gen_rtvec (4, x, GEN_INT (TLS_IE32), + gen_rtx_LABEL_REF (Pmode, label), + GEN_INT (TARGET_ARM ? 8 : 4)), + UNSPEC_TLS); + reg = load_tls_operand (sum, reg); + + if (TARGET_ARM) + emit_insn (gen_tls_load_dot_plus_eight (reg, reg, label)); + else + { + emit_insn (gen_pic_add_dot_plus_four (reg, label)); + emit_move_insn (reg, gen_const_mem (SImode, reg)); + } + + tp = arm_load_tp (NULL_RTX); + + return gen_rtx_PLUS (Pmode, tp, reg); + + case TLS_MODEL_LOCAL_EXEC: + tp = arm_load_tp (NULL_RTX); + + reg = gen_rtx_UNSPEC (Pmode, + gen_rtvec (2, x, GEN_INT (TLS_LE32)), + UNSPEC_TLS); + reg = force_reg (SImode, gen_rtx_CONST (SImode, reg)); + + return gen_rtx_PLUS (Pmode, tp, reg); + + default: + abort (); + } +} + /* Try machine-dependent ways of modifying an illegitimate address to be legitimate. If we find one, return the new, valid address. */ rtx arm_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode) { + if (arm_tls_symbol_p (x)) + return legitimize_tls_address (x, NULL_RTX); + if (GET_CODE (x) == PLUS) { rtx xop0 = XEXP (x, 0); @@ -3803,6 +4030,9 @@ arm_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode) rtx thumb_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode) { + if (arm_tls_symbol_p (x)) + return legitimize_tls_address (x, NULL_RTX); + if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT && (INTVAL (XEXP (x, 1)) >= 32 * GET_MODE_SIZE (mode) @@ -3907,6 +4137,50 @@ thumb_legitimize_reload_address (rtx *x_p, return NULL; } + +/* Test for various thread-local symbols. */ + +/* Return TRUE if X is a thread-local symbol. */ + +static bool +arm_tls_symbol_p (rtx x) +{ + if (! TARGET_HAVE_TLS) + return false; + + if (GET_CODE (x) != SYMBOL_REF) + return false; + + return SYMBOL_REF_TLS_MODEL (x) != 0; +} + +/* Helper for arm_tls_referenced_p. */ + +static int +arm_tls_operand_p_1 (rtx *x, void *data ATTRIBUTE_UNUSED) +{ + if (GET_CODE (*x) == SYMBOL_REF) + return SYMBOL_REF_TLS_MODEL (*x) != 0; + + /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are + TLS offsets, not real symbol references. */ + if (GET_CODE (*x) == UNSPEC + && XINT (*x, 1) == UNSPEC_TLS) + return -1; + + return 0; +} + +/* Return TRUE if X contains any TLS symbol references. */ + +bool +arm_tls_referenced_p (rtx x) +{ + if (! TARGET_HAVE_TLS) + return false; + + return for_each_rtx (&x, arm_tls_operand_p_1, NULL); +} #define REG_OR_SUBREG_REG(X) \ (GET_CODE (X) == REG \ @@ -5278,6 +5552,11 @@ symbol_mentioned_p (rtx x) if (GET_CODE (x) == SYMBOL_REF) return 1; + /* UNSPEC_TLS entries for a symbol include the SYMBOL_REF, but they + are constant offsets, not symbols. */ + if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS) + return 0; + fmt = GET_RTX_FORMAT (GET_CODE (x)); for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) @@ -5307,6 +5586,11 @@ label_mentioned_p (rtx x) if (GET_CODE (x) == LABEL_REF) return 1; + /* UNSPEC_TLS entries for a symbol include a LABEL_REF for the referencing + instruction, but they are constant offsets, not symbols. */ + if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS) + return 0; + fmt = GET_RTX_FORMAT (GET_CODE (x)); for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) { @@ -5325,6 +5609,48 @@ label_mentioned_p (rtx x) return 0; } +int +tls_mentioned_p (rtx x) +{ + switch (GET_CODE (x)) + { + case CONST: + return tls_mentioned_p (XEXP (x, 0)); + + case UNSPEC: + if (XINT (x, 1) == UNSPEC_TLS) + return 1; + + default: + return 0; + } +} + +/* Must not copy a SET whose source operand is PC-relative. */ + +static bool +arm_cannot_copy_insn_p (rtx insn) +{ + rtx pat = PATTERN (insn); + + if (GET_CODE (pat) == PARALLEL + && GET_CODE (XVECEXP (pat, 0, 0)) == SET) + { + rtx rhs = SET_SRC (XVECEXP (pat, 0, 0)); + + if (GET_CODE (rhs) == UNSPEC + && XINT (rhs, 1) == UNSPEC_PIC_BASE) + return TRUE; + + if (GET_CODE (rhs) == MEM + && GET_CODE (XEXP (rhs, 0)) == UNSPEC + && XINT (XEXP (rhs, 0), 1) == UNSPEC_PIC_BASE) + return TRUE; + } + + return FALSE; +} + enum rtx_code minmax_code (rtx x) { @@ -5811,7 +6137,6 @@ emit_stm_seq (rtx *operands, int nops) output_asm_insn (buf, operands); return ""; } - /* Routines for use in generating RTL. */ @@ -12119,8 +12444,23 @@ arm_init_iwmmxt_builtins (void) } static void +arm_init_tls_builtins (void) +{ + tree ftype; + tree nothrow = tree_cons (get_identifier ("nothrow"), NULL, NULL); + tree const_nothrow = tree_cons (get_identifier ("const"), NULL, nothrow); + + ftype = build_function_type (ptr_type_node, void_list_node); + lang_hooks.builtin_function ("__builtin_thread_pointer", ftype, + ARM_BUILTIN_THREAD_POINTER, BUILT_IN_MD, + NULL, const_nothrow); +} + +static void arm_init_builtins (void) { + arm_init_tls_builtins (); + if (TARGET_REALLY_IWMMXT) arm_init_iwmmxt_builtins (); } @@ -12425,6 +12765,9 @@ arm_expand_builtin (tree exp, emit_insn (gen_iwmmxt_clrdi (target)); return target; + case ARM_BUILTIN_THREAD_POINTER: + return arm_load_tp (target); + default: break; } @@ -14224,6 +14567,8 @@ arm_encode_section_info (tree decl, rtx rtl, int first) else if (! TREE_PUBLIC (decl)) arm_encode_call_attribute (decl, SHORT_CALL_FLAG_CHAR); } + + default_encode_section_info (decl, rtl, first); } #endif /* !ARM_PE */ @@ -15025,3 +15370,66 @@ arm_output_fn_unwind (FILE * f, bool prologue) else fputs ("\t.fnend\n", f); } + +static bool +arm_emit_tls_decoration (FILE *fp, rtx x) +{ + enum tls_reloc reloc; + rtx val; + + val = XVECEXP (x, 0, 0); + reloc = INTVAL (XVECEXP (x, 0, 1)); + + output_addr_const (fp, val); + + switch (reloc) + { + case TLS_GD32: + fputs ("(tlsgd)", fp); + break; + case TLS_LDM32: + fputs ("(tlsldm)", fp); + break; + case TLS_LDO32: + fputs ("(tlsldo)", fp); + break; + case TLS_IE32: + fputs ("(gottpoff)", fp); + break; + case TLS_LE32: + fputs ("(tpoff)", fp); + break; + default: + gcc_unreachable (); + } + + switch (reloc) + { + case TLS_GD32: + case TLS_LDM32: + case TLS_IE32: + fputs (" + (. - ", fp); + output_addr_const (fp, XVECEXP (x, 0, 2)); + fputs (" - ", fp); + output_addr_const (fp, XVECEXP (x, 0, 3)); + fputc (')', fp); + break; + default: + break; + } + + return TRUE; +} + +bool +arm_output_addr_const_extra (FILE *fp, rtx x) +{ + if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS) + return arm_emit_tls_decoration (fp, x); + else if (GET_CODE (x) == CONST_VECTOR) + return arm_emit_vector_const (fp, x); + + return FALSE; +} + +#include "gt-arm.h" diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index ae13a9d..2bca153 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -192,6 +192,9 @@ extern GTY(()) rtx aof_pic_label; #define TARGET_AAPCS_BASED \ (arm_abi != ARM_ABI_APCS && arm_abi != ARM_ABI_ATPCS) +#define TARGET_HARD_TP (target_thread_pointer == TP_CP15) +#define TARGET_SOFT_TP (target_thread_pointer == TP_SOFT) + /* True iff the full BPABI is being used. If TARGET_BPABI is true, then TARGET_AAPCS_BASED must be true -- but the converse does not hold. TARGET_BPABI implies the use of the BPABI runtime library, @@ -289,6 +292,15 @@ extern enum arm_abi_type arm_abi; #define ARM_DEFAULT_ABI ARM_ABI_APCS #endif +/* Which thread pointer access sequence to use. */ +enum arm_tp_type { + TP_AUTO, + TP_SOFT, + TP_CP15 +}; + +extern enum arm_tp_type target_thread_pointer; + /* Nonzero if this chip supports the ARM Architecture 3M extensions. */ extern int arm_arch3m; @@ -1882,8 +1894,10 @@ typedef struct || CONSTANT_ADDRESS_P (X) \ || flag_pic) -#define LEGITIMATE_CONSTANT_P(X) \ - (TARGET_ARM ? ARM_LEGITIMATE_CONSTANT_P (X) : THUMB_LEGITIMATE_CONSTANT_P (X)) +#define LEGITIMATE_CONSTANT_P(X) \ + (!arm_tls_referenced_p (X) \ + && (TARGET_ARM ? ARM_LEGITIMATE_CONSTANT_P (X) \ + : THUMB_LEGITIMATE_CONSTANT_P (X))) /* Special characters prefixed to function names in order to encode attribute like information. @@ -2199,14 +2213,16 @@ extern int arm_pic_register; #define PIC_OFFSET_TABLE_REGNUM arm_pic_register /* We can't directly access anything that contains a symbol, - nor can we indirect via the constant pool. */ + nor can we indirect via the constant pool. One exception is + UNSPEC_TLS, which is always PIC. */ #define LEGITIMATE_PIC_OPERAND_P(X) \ (!(symbol_mentioned_p (X) \ || label_mentioned_p (X) \ || (GET_CODE (X) == SYMBOL_REF \ && CONSTANT_POOL_ADDRESS_P (X) \ && (symbol_mentioned_p (get_pool_constant (X)) \ - || label_mentioned_p (get_pool_constant (X)))))) + || label_mentioned_p (get_pool_constant (X))))) \ + || tls_mentioned_p (X)) /* We need to know when we are making a constant pool; this determines whether data needs to be in the GOT or can be referenced via a GOT @@ -2487,10 +2503,9 @@ extern int making_const_table; else \ THUMB_PRINT_OPERAND_ADDRESS (STREAM, X) -#define OUTPUT_ADDR_CONST_EXTRA(FILE, X, FAIL) \ - if (GET_CODE (X) != CONST_VECTOR \ - || ! arm_emit_vector_const (FILE, X)) \ - goto FAIL; +#define OUTPUT_ADDR_CONST_EXTRA(file, x, fail) \ + if (arm_output_addr_const_extra (file, x) == FALSE) \ + goto fail /* A C expression whose value is RTL representing the value of the return address for the frame COUNT steps up from the current frame. */ @@ -2682,6 +2697,8 @@ enum arm_builtins ARM_BUILTIN_WUNPCKELUH, ARM_BUILTIN_WUNPCKELUW, + ARM_BUILTIN_THREAD_POINTER, + ARM_BUILTIN_MAX }; #endif /* ! GCC_ARM_H */ diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 76eb12b..478ce86 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -90,6 +90,7 @@ (UNSPEC_CLRDI 17) ; Used by the intrinsic form of the iWMMXt CLRDI instruction. (UNSPEC_WMADDS 18) ; Used by the intrinsic form of the iWMMXt WMADDS instruction. (UNSPEC_WMADDU 19) ; Used by the intrinsic form of the iWMMXt WMADDU instruction. + (UNSPEC_TLS 20) ; A symbol that has been treated properly for TLS usage. ] ) @@ -4280,13 +4281,37 @@ operands[1] = force_reg (SImode, operands[1]); } } - - if (flag_pic - && (CONSTANT_P (operands[1]) - || symbol_mentioned_p (operands[1]) - || label_mentioned_p (operands[1]))) - operands[1] = legitimize_pic_address (operands[1], SImode, - (no_new_pseudos ? operands[0] : 0)); + + /* Recognize the case where operand[1] is a reference to thread-local + data and load its address to a register. */ + if (arm_tls_referenced_p (operands[1])) + { + rtx tmp = operands[1]; + rtx addend = NULL; + + if (GET_CODE (tmp) == CONST && GET_CODE (XEXP (tmp, 0)) == PLUS) + { + addend = XEXP (XEXP (tmp, 0), 1); + tmp = XEXP (XEXP (tmp, 0), 0); + } + + gcc_assert (GET_CODE (tmp) == SYMBOL_REF); + gcc_assert (SYMBOL_REF_TLS_MODEL (tmp) != 0); + + tmp = legitimize_tls_address (tmp, no_new_pseudos ? operands[0] : 0); + if (addend) + { + tmp = gen_rtx_PLUS (SImode, tmp, addend); + tmp = force_operand (tmp, operands[0]); + } + operands[1] = tmp; + } + else if (flag_pic + && (CONSTANT_P (operands[1]) + || symbol_mentioned_p (operands[1]) + || label_mentioned_p (operands[1]))) + operands[1] = legitimize_pic_address (operands[1], SImode, + (no_new_pseudos ? operands[0] : 0)); " ) @@ -4444,7 +4469,7 @@ (const (plus:SI (pc) (const_int 4))))] UNSPEC_PIC_BASE)) (use (label_ref (match_operand 1 "" "")))] - "TARGET_THUMB && flag_pic" + "TARGET_THUMB" "* (*targetm.asm_out.internal_label) (asm_out_file, \"L\", CODE_LABEL_NUMBER (operands[1])); @@ -4459,7 +4484,7 @@ (const (plus:SI (pc) (const_int 8))))] UNSPEC_PIC_BASE)) (use (label_ref (match_operand 1 "" "")))] - "TARGET_ARM && flag_pic" + "TARGET_ARM" "* (*targetm.asm_out.internal_label) (asm_out_file, \"L\", CODE_LABEL_NUMBER (operands[1])); @@ -4468,6 +4493,41 @@ [(set_attr "predicable" "yes")] ) +(define_insn "tls_load_dot_plus_eight" + [(set (match_operand:SI 0 "register_operand" "+r") + (mem:SI (unspec:SI [(plus:SI (match_operand:SI 1 "register_operand" "r") + (const (plus:SI (pc) (const_int 8))))] + UNSPEC_PIC_BASE))) + (use (label_ref (match_operand 2 "" "")))] + "TARGET_ARM" + "* + (*targetm.asm_out.internal_label) (asm_out_file, \"L\", + CODE_LABEL_NUMBER (operands[2])); + return \"ldr%?\\t%0, [%|pc, %1]\t\t@ tls_load_dot_plus_eight\"; + " + [(set_attr "predicable" "yes")] +) + +;; PIC references to local variables can generate pic_add_dot_plus_eight +;; followed by a load. These sequences can be crunched down to +;; tls_load_dot_plus_eight by a peephole. + +(define_peephole2 + [(parallel [(set (match_operand:SI 0 "register_operand" "") + (unspec:SI [(plus:SI (match_dup 0) + (const (plus:SI (pc) (const_int 8))))] + UNSPEC_PIC_BASE)) + (use (label_ref (match_operand 1 "" "")))]) + (set (match_operand:SI 2 "register_operand" "") (mem:SI (match_dup 0)))] + "TARGET_ARM && peep2_reg_dead_p (2, operands[0])" + [(parallel [(set (match_operand:SI 2 "register_operand" "+r") + (mem:SI (unspec:SI [(plus:SI (match_dup 0) + (const (plus:SI (pc) (const_int 8))))] + UNSPEC_PIC_BASE))) + (use (label_ref (match_operand 1 "" "")))])] + "" +) + (define_expand "builtin_setjmp_receiver" [(label_ref (match_operand 0 "" ""))] "flag_pic" @@ -10080,6 +10140,28 @@ }" ) + +;; TLS support + +(define_insn "load_tp_hard" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(const_int 0)] UNSPEC_TLS))] + "TARGET_HARD_TP" + "mrc%?\\tp15, 0, %0, c13, c0, 3\\t@ load_tp_hard" + [(set_attr "predicable" "yes")] +) + +;; Doesn't clobber R1-R3. Must use r0 for the first operand. +(define_insn "load_tp_soft" + [(set (reg:SI 0) (unspec:SI [(const_int 0)] UNSPEC_TLS)) + (clobber (reg:SI LR_REGNUM)) + (clobber (reg:SI IP_REGNUM)) + (clobber (reg:CC CC_REGNUM))] + "TARGET_SOFT_TP" + "bl\\t__aeabi_read_tp\\t@ load_tp_soft" + [(set_attr "conds" "clob")] +) + ;; Load the FPA co-processor patterns (include "fpa.md") ;; Load the Maverick co-processor patterns diff --git a/gcc/config/arm/arm.opt b/gcc/config/arm/arm.opt index a13aa17..ac497d9 100644 --- a/gcc/config/arm/arm.opt +++ b/gcc/config/arm/arm.opt @@ -134,6 +134,10 @@ mthumb-interwork Target Report Mask(INTERWORK) Support calls between Thumb and ARM instruction sets +mtp= +Target RejectNegative Joined Var(target_thread_switch) +Specify how to access the thread pointer + mtpcs-frame Target Report Mask(TPCS_FRAME) Thumb: Generate (non-leaf) stack frames even if not needed |