sparc.c (struct machine_function): New type.
authorJakub Jelinek <jakub@redhat.com>
Mon, 8 Sep 2003 06:57:05 +0000 (08:57 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Mon, 8 Sep 2003 06:57:05 +0000 (08:57 +0200)
* 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
gcc/config/sparc/linux.h
gcc/config/sparc/linux64.h
gcc/config/sparc/sparc-protos.h
gcc/config/sparc/sparc.c
gcc/config/sparc/sparc.h
gcc/config/sparc/sparc.md
gcc/configure
gcc/configure.in

index 06f8a05..f5cb771 100644 (file)
@@ -1,3 +1,61 @@
+2003-09-08  Jakub Jelinek  <jakub@redhat.com>
+
+       * config/sparc/sparc.c (struct machine_function): New type.
+       (TARGET_HAVE_TLS, TARGET_CANNOT_FORCE_CONST_MEM): Define.
+       (sparc_override_options): Initialize init_machine_status.
+       (tls_symbolic_operand, tgd_symbolic_operand, tld_symbolic_operand,
+       tie_symbolic_operand, tle_symbolic_operand): New functions.
+       (symbolic_operand): Disallow tls_symbolic_operand.
+       (symbolic_memory_operand): Likewise.
+       (tls_call_delay, sparc_cannot_force_const_mem, legitimate_constant_p,
+       constant_address_p, legitimate_pic_operand_p, legitimate_address_p):
+       New functions.
+       (sparc_tls_symbol): New variable.
+       (sparc_tls_get_addr, sparc_tls_got, legitimize_tls_address,
+       legitimize_address): New functions.
+       (print_operand): Handle %&.
+       (sparc_init_machine_status, get_some_local_dynamic_name,
+       get_some_local_dynamic_name_1): New functions.
+       (sparc_output_dwarf_dtprel): New function.
+       * config/sparc/sparc.h (CONSTANT_ADDRESS_P): Moved into
+       constant_address_p.
+       (LEGITIMATE_PIC_OPERAND_P): Moved into legitimate_pic_operand_p.
+       (LEGITIMATE_CONSTANT_P): Moved into legitimate_constant_p.
+       (GO_IF_LEGITIMATE_ADDRESS): Moved into legitimate_address_p.
+       (LEGITIMIZE_ADDRESS): Moved into legitimize_address.
+       (PRINT_OPERAND_PUNCT_VALID_P): Add '&'.
+       (TARGET_TLS, TARGET_SUN_TLS, TARGET_GNU_TLS): Define.
+       (ASM_OUTPUT_DWARF_DTPREL): Define.
+       (PREDICATE_CODES): Add tgd_symbolic_operand, tld_symbolic_operand,
+       tie_symbolic_operand, tle_symbolic_operand.
+       * config/sparc/sparc.md (UNSPEC_TLSGD, UNSPEC_TLSLDM, UNSPEC_TLSLDO,
+       UNSPEC_TLSIE, UNSPEC_TLSLE, UNSPEC_TLSLD_BASE): New constants.
+       (tls_call_delay): New attribute.
+       (in_call_delay): Use it.
+       (movqi, movhi, movsi, movdi): Call legitimize_tls_address if needed.
+       (tgd_hi22, tgd_lo10, tgd_add32, tgd_add64, tgd_call32, tgd_call64,
+       tldm_hi22, tldm_lo10, tldm_add32, tldm_add64, tldm_call32, tldm_call64,
+       tldo_hix22, tldo_lox10, tldo_add32, tldo_add64, tie_hi22, tie_lo10,
+       tie_ld32, tie_ld64, tie_add32, tie_add64, tle_hix22_sp32,
+       tle_lox10_sp32, tle_hix22_sp64, tle_lox10_sp64): New insns.
+       (tldo_ldub_sp32, tldo_ldub1_sp32, tldo_ldub2_sp32, tldo_ldsb1_sp32,
+       tldo_ldsb2_sp32, tldo_ldub_sp64, tldo_ldub1_sp64, tldo_ldub2_sp64,
+       tldo_ldub3_sp64, tldo_ldsb1_sp64, tldo_ldsb2_sp64, tldo_ldsb3_sp64,
+       tldo_lduh_sp32, tldo_lduh1_sp32, tldo_ldsh1_sp32, tldo_lduh_sp64,
+       tldo_lduh1_sp64, tldo_lduh2_sp64, tldo_ldsh1_sp64, tldo_ldsh2_sp64,
+       tldo_lduw_sp32, tldo_lduw_sp64, tldo_lduw1_sp64, tldo_ldsw1_sp64,
+       tldo_ldx_sp64, tldo_stb_sp32, tldo_stb_sp64, tldo_sth_sp32,
+       tldo_sth_sp64, tldo_stw_sp32, tldo_stw_sp64, tldo_stx_sp64): New
+       insns.
+       * config/sparc/sparc-protos.h (legitimate_constant_p,
+       constant_address_p, legitimate_pic_operand_p, legitimate_address_p,
+       legitimize_tls_address, legitimize_address, tls_symbolic_operand,
+       tls_call_delay, sparc_output_dwarf_dtprel): New prototypes.
+       * config/sparc/linux.h (TARGET_GNU_TLS, TARGET_SUN_TLS): Define.
+       * config/sparc/linux64.h (TARGET_GNU_TLS, TARGET_SUN_TLS): Likewise.
+       * configure.in (sparc*-*-*): Add TLS check.
+       * configure: Rebuilt.
+
 2003-09-07  Eric Botcazou  <ebotcazou@libertysurf.fr>
 
        PR target/11689
 2003-09-07  Eric Botcazou  <ebotcazou@libertysurf.fr>
 
        PR target/11689
index 87d3a70..a53e796 100644 (file)
@@ -232,6 +232,13 @@ do {                                                                       \
 #define LINK_EH_SPEC "%{!static:--eh-frame-hdr} "
 #endif
 \f
 #define LINK_EH_SPEC "%{!static:--eh-frame-hdr} "
 #endif
 \f
+#ifdef HAVE_AS_TLS
+#undef TARGET_SUN_TLS
+#undef TARGET_GNU_TLS
+#define TARGET_SUN_TLS 0
+#define TARGET_GNU_TLS 1
+#endif
+\f
 /* Don't be different from other Linux platforms in this regard.  */
 #define HANDLE_PRAGMA_PACK_PUSH_POP
 
 /* Don't be different from other Linux platforms in this regard.  */
 #define HANDLE_PRAGMA_PACK_PUSH_POP
 
index f85d4aa..fe7470a 100644 (file)
@@ -315,6 +315,13 @@ do {                                                                       \
 #define LINK_EH_SPEC "%{!static:--eh-frame-hdr} "
 #endif
 \f
 #define LINK_EH_SPEC "%{!static:--eh-frame-hdr} "
 #endif
 \f
+#ifdef HAVE_AS_TLS
+#undef TARGET_SUN_TLS
+#undef TARGET_GNU_TLS
+#define TARGET_SUN_TLS 0
+#define TARGET_GNU_TLS 1
+#endif
+\f
 /* Don't be different from other Linux platforms in this regard.  */
 #define HANDLE_PRAGMA_PACK_PUSH_POP
 
 /* Don't be different from other Linux platforms in this regard.  */
 #define HANDLE_PRAGMA_PACK_PUSH_POP
 
index 1b5af30..4b9582d 100644 (file)
@@ -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 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_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);
 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 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 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);
 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 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__ */
 #endif /* RTX_CODE */
 
 #endif /* __SPARC_PROTOS_H__ */
index 84d27d2..9e65136 100644 (file)
@@ -120,6 +120,12 @@ char sparc_leaf_regs[] =
   1, 1, 1, 1, 1, 1, 1, 1,
   1, 1, 1, 1, 1};
 
   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
 /* 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 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 *);
 \f
 /* Option handling.  */
 static bool sparc_rtx_costs (rtx, int, int, int *);
 \f
 /* 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
 
 #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
 #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 ();
 
   /* Do various machine dependent initializations.  */
   sparc_init_modes ();
+
+  /* Set up function hooks.  */
+  init_machine_status = sparc_init_machine_status;
 }
 \f
 /* Miscellaneous utilities.  */
 }
 \f
 /* 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));
 }
 
   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.  */
 
 /* 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:
   switch (GET_CODE (op))
     {
     case SYMBOL_REF:
+      return !SYMBOL_REF_TLS_MODEL (op);
+
     case LABEL_REF:
       return 1;
 
     case CONST:
       op = XEXP (op, 0);
     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);
 
               || 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);
   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.  */
 }
 
 /* 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 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.  */
 
 /* 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;
 }
 \f
   return 1;
 }
 \f
+/* 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 ();
+    }
+}
+\f
 /* The table we use to reference PIC data.  */
 static GTY(()) rtx global_offset_table;
 
 /* 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;
 }
 
   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
 /* 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;
 }
 
   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
 /* 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;
       /* ??? 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)
     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;
 }
 
   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"
 #include "gt-sparc.h"
index 9235f66..a997602 100644 (file)
@@ -2099,27 +2099,18 @@ do {                                                                    \
    When PIC, we do not accept an address that would require a scratch reg
    to load into a register.  */
 
    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 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.  */
 
 
 /* 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.
 
 /* 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)
 
 #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)                \
 #define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR)                \
-{ if (RTX_OK_FOR_BASE_P (X))                           \
+{                                                      \
+  if (legitimate_address_p (MODE, X, 1))               \
     goto ADDR;                                         \
     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;                                         \
 }
     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.
 
 /* 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)    \
 
 /* 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
 
 /* 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);
 
 #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) \
 #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.
 
 /* 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                                                        \
 /* 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}},                                \
 {"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
 
 /* The number of Pmode words for the setjmp buffer.  */
 #define JMP_BUF_SIZE 12
index 07ce718..954e89d 100644 (file)
    (UNSPEC_EMB_TEXTHI          14)
    (UNSPEC_EMB_TEXTULO         15)
    (UNSPEC_EMB_SETHM           18)
    (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
   ])
 
 (define_constants
 
 ;; Attributes for instruction and branch scheduling
 
 
 ;; 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")
 (define_attr "in_call_delay" "false,true"
   (cond [(eq_attr "type" "uncond_branch,branch,call,sibcall,call_no_delay_slot,multi")
                (const_string "false")
                (if_then_else (eq_attr "length" "1")
                              (const_string "true")
                              (const_string "false"))]
                (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"))))
 
                      (const_string "true")
                      (const_string "false"))))
 
        }
     }
 
        }
     }
 
+  /* Fixup TLS cases.  */
+  if (tls_symbolic_operand (operands [1]))
+    operands[1] = legitimize_tls_address (operands[1]);
+
   /* Fixup PIC cases.  */
   if (flag_pic)
     {
   /* Fixup PIC cases.  */
   if (flag_pic)
     {
        }
     }
 
        }
     }
 
+  /* Fixup TLS cases.  */
+  if (tls_symbolic_operand (operands [1]))
+    operands[1] = legitimize_tls_address (operands[1]);
+
   /* Fixup PIC cases.  */
   if (flag_pic)
     {
   /* Fixup PIC cases.  */
   if (flag_pic)
     {
        }
     }
 
        }
     }
 
+  /* Fixup TLS cases.  */
+  if (tls_symbolic_operand (operands [1]))
+    operands[1] = legitimize_tls_address (operands[1]);
+
   /* Fixup PIC cases.  */
   if (flag_pic)
     {
   /* Fixup PIC cases.  */
   if (flag_pic)
     {
        }
     }
 
        }
     }
 
+  /* Fixup TLS cases.  */
+  if (tls_symbolic_operand (operands [1]))
+    operands[1] = legitimize_tls_address (operands[1]);
+
   if (flag_pic)
     {
       if (CONSTANT_P (operands[1])
   if (flag_pic)
     {
       if (CONSTANT_P (operands[1])
   "TARGET_V9"
   "t%C0\t%%xcc, %1"
   [(set_attr "type" "trap")])
   "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")])
index 0b47a0b..05dec41 100755 (executable)
@@ -6661,6 +6661,33 @@ foo:     .long   25
        tls_first_minor=14
        tls_as_opt="-m64 -Aesame"
        ;;
        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.
 esac
 if test -z "$tls_first_major"; then
   : # If we don't have a check, assume no support.
index c6c6bae..b0926a7 100644 (file)
@@ -2000,7 +2000,6 @@ foo:      .long   25
        tls_first_minor=13
        ;;
   i[34567]86-*-*)
        tls_first_minor=13
        ;;
   i[34567]86-*-*)
-changequote([,])dnl
     conftest_s='
        .section ".tdata","awT",@progbits
 foo:   .long   25
     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"
        ;;
        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.
 esac
 if test -z "$tls_first_major"; then
   : # If we don't have a check, assume no support.