configure.ac: Add test for ARM TLS support.
authorDaniel Jacobowitz <dan@codesourcery.com>
Fri, 4 Nov 2005 15:02:51 +0000 (15:02 +0000)
committerDaniel Jacobowitz <drow@gcc.gnu.org>
Fri, 4 Nov 2005 15:02:51 +0000 (15:02 +0000)
* 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

gcc/ChangeLog
gcc/config/arm/arm-protos.h
gcc/config/arm/arm.c
gcc/config/arm/arm.h
gcc/config/arm/arm.md
gcc/config/arm/arm.opt
gcc/configure
gcc/configure.ac
gcc/doc/invoke.texi

index f24cb9891958bc6801f6d5b1aa8e4e9c208169b4..cfee75f54c4baa720363e2fbdd67058185bb5514 100644 (file)
@@ -1,3 +1,50 @@
+2005-11-04  Daniel Jacobowitz  <dan@codesourcery.com>
+           Paul Brook  <paul@codesourcery.com>
+           Phil Blundell  <pb@reciva.com>
+
+       * 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.
+
 2005-11-04  Daniel Jacobowitz  <dan@codesourcery.com>
 
        * config/arm/lib1funcs.asm: Don't include "libunwind.S".
index b8913a1cf595b74b837a8cf92bd3d53889325221..2bd84ca6024c7c88fc805c5e9b6e15ac15489541 100644 (file)
@@ -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 *);
index 1bb6149c568bff620dc00bd72c6f5b39c419a602..061c33abfcc0191dc116171d371250c295c47371 100644 (file)
@@ -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);
+
 \f
 /* 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;
 \f
 /* 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);
+}
 \f
 #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 "";
 }
-
 \f
 /* Routines for use in generating RTL.  */
 
@@ -12118,9 +12443,24 @@ arm_init_iwmmxt_builtins (void)
   def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiatt", di_ftype_di_int_int, ARM_BUILTIN_TMIATT);
 }
 
+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"
index ae13a9d92b108c7de083aa8bd435fcf3bbfdc46d..2bca1538dc1a5dd48e2ef9f1ed310d52a999edc2 100644 (file)
@@ -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 */
index 76eb12b5fad51a037df79a529e4f7b3eff61cc0c..478ce866092d734f10eb96cff0a5d00815056d16 100644 (file)
@@ -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.
   ]
 )
 
            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));
   "
 )
 
                             (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]));
                             (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]));
   [(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"
   }"
 )
 
+\f
+;; 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
index a13aa175330acfa8919079af28b5949c3e630215..ac497d96186ebacf3eca96b30adb9602f0c6074c 100644 (file)
@@ -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
index 3e58a337308f958dcff091247c18a0e3f08dd4d1..f9a438bedfe16efe9fabb26c275695c5eff79458 100755 (executable)
@@ -14523,6 +14523,19 @@ foo:   .long   25
        tls_first_minor=15
        tls_as_opt=--fatal-warnings
        ;;
+  arm*-*-*)
+    conftest_s='
+       .section ".tdata","awT",%progbits
+foo:   .long   25
+       .text
+.word foo(gottpoff)
+.word foo(tpoff)
+.word foo(tlsgd)
+.word foo(tlsldm)
+.word foo(tlsldo)'
+       tls_first_major=2
+       tls_first_minor=17
+       ;;
   i[34567]86-*-*)
     conftest_s='
        .section ".tdata","awT",@progbits
index 7070c114fd7a65cff4a3da6f55388c3953abf710..d46fc45fd73a234c234b1caf5b241c4db8bf0fe9 100644 (file)
@@ -1,7 +1,7 @@
 # configure.ac for GCC
 # Process this file with autoconf to generate a configuration script.
 
-# Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+# Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
 # Free Software Foundation, Inc.
 
 #This file is part of GCC.
@@ -2236,6 +2236,19 @@ foo:     .long   25
        tls_first_minor=15
        tls_as_opt=--fatal-warnings
        ;;
+  arm*-*-*)
+    conftest_s='
+       .section ".tdata","awT",%progbits
+foo:   .long   25
+       .text
+.word foo(gottpoff)
+.word foo(tpoff)
+.word foo(tlsgd)
+.word foo(tlsldm)
+.word foo(tlsldo)'
+       tls_first_major=2
+       tls_first_minor=17
+       ;;
   i[34567]86-*-*)
     conftest_s='
        .section ".tdata","awT",@progbits
index 8bbbb04dfb3a996b896ffa297d336b21fd1c5736..eda329a76842ca0a81e72881d419ea52c4819664 100644 (file)
@@ -412,7 +412,8 @@ Objective-C and Objective-C++ Dialects}.
 -mpoke-function-name @gol
 -mthumb  -marm @gol
 -mtpcs-frame  -mtpcs-leaf-frame @gol
--mcaller-super-interworking  -mcallee-super-interworking}
+-mcaller-super-interworking  -mcallee-super-interworking @gol
+-mtp=@var{name}}
 
 @emph{AVR Options}
 @gccoptlist{-mmcu=@var{mcu}  -msize  -minit-stack=@var{n}  -mno-interrupts @gol
@@ -7456,6 +7457,15 @@ execute correctly regardless of whether the target code has been
 compiled for interworking or not.  There is a small overhead in the cost
 of executing a function pointer if this option is enabled.
 
+@item -mtp=@var{name}
+@opindex mtp
+Specify the access model for the thread local storage pointer.  The valid
+models are @option{soft}, which generates calls to @code{__aeabi_read_tp},
+@option{cp15}, which fetches the thread pointer from @code{cp15} directly
+(supported in the arm6k architecture), and @option{auto}, which uses the
+best available method for the selected processor.  The default setting is
+@option{auto}.
+
 @end table
 
 @node AVR Options