This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFA: MN10300: Add TLS support


Hi Richard, Hi Jeff, Hi Alex,

  Here is another MN10300 patch.  This ones adds support for TLS.  I
  must confess that I did not actually write this code - DJ did - but I
  have been asked to submit it upstream, so here goes:

  OK to apply ?

Cheers
  Nick

gcc/ChangeLog
2011-05-17  DJ Delorie  <dj@redhat.com>
	    Nick Clifton  <nickc@redhat.com>

	* config/mn10300/mn10300.c (mn10300_unspec_int_label_counter):
	New variable.
	(mn10300_option_override): Disable TLS for the MN10300.
	(tls_symbolic_operand_kind): New function.
	(get_some_local_dynamic_name_1): New function.
	(get_some_local_dynamic_name): New function.
	(mn10300_print_operand): Handle %&.
	(mn10300_legitimize_address): Legitimize TLS addresses.
	(is_legitimate_tls_operand): New function.
	(mn10300_legitimate_pic_operand_p): TLS operands are
	legitimate.
	(mn10300_legitimate_address_p): TLS symbols do not make
	legitimate addresses.
	Allow TLS operands under some circumstances.
	(mn10300_legitimate_constant_p): Handle TLS UNSPECs.
        (mn10300_init_machine_status): New function.
        (mn10300_init_expanders): New function.
        (pic_nonpic_got_ptr): New function.
        (mn10300_tls_get_addr): New function.
        (mn10300_legitimize_tls_address): New function.
        (mn10300_constant_address_p): New function.
        (TARGET_HAVE_TLS): Define.
        * config/mn10300/predicates.md (tls_symbolic_operand): New.
        (nontls_general_operand): New.
        * config/mn10300/mn10300.h (enum reg_class): Add D0_REGS,
	A0_REGS.
        (REG_CLASS_NAMES): Likewise.
        (REG_CLASS_CONTENTS): Likewise.
	(struct machine_function): New structure.
        (INIT_EXPANDERS): Define.
        (mn10300_unspec_int_label_counter): New variable.
        (PRINT_OPERAND_PUNCT_VALID_P): Define.
        (CONSTANT_ADDRESS_P): Define.
        * config/mn10300/constraints (B): New constraint.
        (C): New constraint.
        * config/mn10300/mn10300-protos.h: Alpha sort.
	(mn10300_init_expanders): Prototype.
	(mn10300_tls_get_addr): Prototype.
	(mn10300_legitimize_tls_address): Prototype.
	(mn10300_constant_address_p): Prototype.
        * config/mn10300/mn10300.md (TLS_REG): New constant.
        (UNSPEC_INT_LABEL): New constant.
        (UNSPEC_TLSGD): New constant.
        (UNSPEC_TLSLDM): New constant.
        (UNSPEC_DTPOFF): New constant.
        (UNSPEC_GOTNTPOFF): New constant.
	(UNSPEC_INDNTPOFF): New constant.
	(UNSPEC_TPOFF): New constant.
	(UNSPEC_TLS_GD): New constant.
	(UNSPEC_TLS_LD_BASE): New constant.
        (movsi): Add TLS code.
        (tls_global_dynamic_i): New pattern.
        (tls_global_dynamic): New pattern.
        (tls_local_dynamic_base_i): New pattern.
        (tls_local_dynamic_base): New pattern.
        (tls_initial_exec): New pattern.
        (tls_initial_exec_1): New pattern.
        (tls_initial_exec_2): New pattern.
        (am33_set_got): New pattern.
        (int_label): New pattern.
        (am33_loadPC_anyreg): New pattern.
        (add_GOT_to_any_reg): New pattern.

Index: gcc/config/mn10300/mn10300.c
===================================================================
--- gcc/config/mn10300/mn10300.c	(revision 173815)
+++ gcc/config/mn10300/mn10300.c	(working copy)
@@ -46,7 +46,12 @@
 #include "df.h"
 #include "opts.h"
 #include "cfgloop.h"
+#include "ggc.h"
 
+/* This is used by GOTaddr2picreg to uniquely identify
+   UNSPEC_INT_LABELs.  */
+int mn10300_unspec_int_label_counter;
+
 /* This is used in the am33_2.0-linux-gnu port, in which global symbol
    names are not prefixed by underscores, to tell whether to prefix a
    label with a plus sign or not, so that the assembler can tell
@@ -124,6 +129,9 @@
     target_flags &= ~MASK_MULT_BUG;
   else
     {
+      /* We can't do TLS if we don't have the TLS register.  */
+      targetm.have_tls = false;
+
       /* Disable scheduling for the MN10300 as we do
 	 not have timing information available for it.  */
       flag_schedule_insns = 0;
@@ -162,6 +170,51 @@
     fprintf (asm_out_file, "\t.am33\n");
 }
 
+/* Returns non-zero if OP has the KIND tls model.  */
+
+static inline bool
+tls_symbolic_operand_kind (rtx op, enum tls_model kind)
+{
+  if (GET_CODE (op) != SYMBOL_REF)
+    return false;
+  return SYMBOL_REF_TLS_MODEL (op) == kind;
+}
+
+/* Locate some local-dynamic symbol still in use by this function
+   so that we can print its name in some tls_local_dynamic_base
+   pattern.  This is used by "%&" in print_operand().  */
+
+static int
+get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
+{
+  rtx x = *px;
+
+  if (GET_CODE (x) == SYMBOL_REF
+      && tls_symbolic_operand_kind (x, TLS_MODEL_LOCAL_DYNAMIC))
+    {
+      cfun->machine->some_ld_name = XSTR (x, 0);
+      return 1;
+    }
+
+  return 0;
+}
+
+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 (NONDEBUG_INSN_P (insn)
+	&& for_each_rtx (&PATTERN (insn), get_some_local_dynamic_name_1, 0))
+      return cfun->machine->some_ld_name;
+
+  gcc_unreachable ();
+}
+
 /* Note: This list must match the liw_op attribute in mn10300.md.  */
 
 static const char *liw_op_names[] =
@@ -435,6 +488,10 @@
       fprintf (file, "%d", (int)(INTVAL (x) & 0xff));
       break;
 
+    case '&':
+      assemble_name (file, get_some_local_dynamic_name ());
+      return;
+
       /* For shift counts.  The hardware ignores the upper bits of
 	 any immediate, but the assembler will flag an out of range
 	 shift count as an error.  So we mask off the high bits
@@ -1824,7 +1881,9 @@
 mn10300_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
 			    enum machine_mode mode ATTRIBUTE_UNUSED)
 {
-  if (flag_pic && ! mn10300_legitimate_pic_operand_p (x))
+  if (tls_symbolic_operand (x, Pmode))
+    x = mn10300_legitimize_tls_address (oldx);
+  else if (flag_pic && ! mn10300_legitimate_pic_operand_p (x))
     x = mn10300_legitimize_pic_address (oldx, NULL_RTX);
 
   /* Uh-oh.  We might have an address for x[n-100000].  This needs
@@ -1899,6 +1958,46 @@
   return reg;
 }
 
+/* Return zero if X references a SYMBOL_REF or LABEL_REF whose
+   symbol isn't protected by a TLS unspec; nonzero otherwise.  */
+
+static bool
+is_legitimate_tls_operand (rtx x)
+{
+  const char *fmt;
+  int i;
+
+  if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
+    return false;
+
+  if (GET_CODE (x) == UNSPEC
+      && (XINT (x, 1) == UNSPEC_TLSGD
+	  || XINT (x, 1) == UNSPEC_TLSLDM
+	  || XINT (x, 1) == UNSPEC_DTPOFF
+	  || XINT (x, 1) == UNSPEC_GOTNTPOFF
+	  || XINT (x, 1) == UNSPEC_INDNTPOFF
+	  || XINT (x, 1) == UNSPEC_TPOFF
+	  ))
+    return true;
+
+  fmt = GET_RTX_FORMAT (GET_CODE (x));
+  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'E')
+	{
+	  int j;
+
+	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+	    if (! is_legitimate_tls_operand (XVECEXP (x, i, j)))
+	      return false;
+	}
+      else if (fmt[i] == 'e' && ! is_legitimate_tls_operand (XEXP (x, i)))
+	return false;
+    }
+
+  return true;
+}
+
 /* Return zero if X references a SYMBOL_REF or LABEL_REF whose symbol
    isn't protected by a PIC unspec; nonzero otherwise.  */
 
@@ -1908,6 +2007,9 @@
   const char *fmt;
   int i;
 
+  if (is_legitimate_tls_operand (x))
+    return 1;
+
   if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
     return 0;
 
@@ -1957,6 +2059,9 @@
 {
   rtx base, index;
 
+  if (tls_symbolic_operand (x, Pmode))
+    return false;
+
   if (CONSTANT_ADDRESS_P (x))
     return !flag_pic || mn10300_legitimate_pic_operand_p (x);
 
@@ -1980,6 +2085,7 @@
 
   if (!REG_P (base))
     return false;
+
   if (REG_P (index))
     {
       /* ??? Without AM33 generalized (Ri,Rn) addressing, reg+reg
@@ -1997,6 +2103,11 @@
   if (CONST_INT_P (index))
     return IN_RANGE (INTVAL (index), -1 - 0x7fffffff, 0x7fffffff);
 
+  if (GET_MODE_SIZE (mode) == 4
+      && GET_CODE (index) != MEM
+      && is_legitimate_tls_operand (index))
+    return true;
+
   if (CONSTANT_ADDRESS_P (index))
     return !flag_pic || mn10300_legitimate_pic_operand_p (index);
 
@@ -2075,13 +2186,25 @@
       /* Only some unspecs are valid as "constants".  */
       if (GET_CODE (x) == UNSPEC)
 	{
+	  rtx sym = XVECEXP (x, 0, 0);
+
 	  switch (XINT (x, 1))
 	    {
+	    case UNSPEC_DTPOFF:
+	      return tls_symbolic_operand_kind (sym, TLS_MODEL_LOCAL_DYNAMIC);
+	    case UNSPEC_GOTNTPOFF:
+	    case UNSPEC_INDNTPOFF:
+	      return tls_symbolic_operand_kind (sym, TLS_MODEL_INITIAL_EXEC);
+	    case UNSPEC_TPOFF:
+	      return tls_symbolic_operand_kind (sym, TLS_MODEL_LOCAL_EXEC);
+
+	    case UNSPEC_INT_LABEL:
 	    case UNSPEC_PIC:
 	    case UNSPEC_GOT:
 	    case UNSPEC_GOTOFF:
 	    case UNSPEC_PLT:
 	      return true;
+
 	    default:
 	      return false;
 	    }
@@ -2092,6 +2215,11 @@
 	return false;
       break;
 
+    case SYMBOL_REF:
+      if (tls_symbolic_operand (x, Pmode))
+	return false;
+      break;
+
     default:
       break;
     }
@@ -3315,8 +3443,148 @@
     }
 }
 
+static struct machine_function *
+mn10300_init_machine_status (void)
+{
+  return ggc_alloc_cleared_machine_function ();
+}
+
+/* Implements INIT_EXPANDERS.  We just set up to call the above
+   function.  */
+
+void
+mn10300_init_expanders (void)
+{
+  init_machine_status = mn10300_init_machine_status;
+}
+
+/* Regardless of whether we're in PIC mode or not, return an RTX that
+   refers to the GOT base.  In PIC mode, we return the PIC register.
+   In non-PIC mode, we calculate the GOT base into a pseudo and cache
+   it.  */
+
+static rtx
+pic_nonpic_got_ptr (void)
+{
+  if (flag_pic)
+    return gen_rtx_REG (SImode, PIC_REG);
+
+  if (cfun->machine->got_ptr == NULL_RTX)
+    {
+      rtx uns, insns, note, got, tmp;
+
+      tmp = gen_reg_rtx (SImode);
+      got = gen_reg_rtx (SImode);
+      start_sequence ();
+      emit_insn (gen_am33_set_got (tmp));
+      insns = get_insns ();
+      end_sequence ();
+      note = gen_rtx_EXPR_LIST (VOIDmode, const0_rtx, NULL);
+      uns = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);
+      note = gen_rtx_EXPR_LIST (VOIDmode, uns, note);
+      emit_libcall_block (insns, got, tmp, note);
+      cfun->machine->got_ptr = got;
+    }
+
+  return cfun->machine->got_ptr;
+}
+
+/* Encapsulates the chosen TLS base register.  */
+
+rtx
+mn10300_tls_get_addr (void)
+{
+  return gen_rtx_REG (Pmode, TLS_REG);
+}
+
+/* Given a symbol X that has TLS linkage, convert it into a (usually)
+   unspec pattern that reflects the appropriate TLS access type.  */
+
+rtx
+mn10300_legitimize_tls_address (rtx x)
+{
+  rtx dest, base, off, uns, a0, insns, note, got;
+
+  switch (SYMBOL_REF_TLS_MODEL (x))
+    {
+    case TLS_MODEL_GLOBAL_DYNAMIC:
+      got = pic_nonpic_got_ptr ();
+      a0 = gen_rtx_REG (Pmode, FIRST_ADDRESS_REGNUM);
+      start_sequence ();
+      dest = gen_reg_rtx (Pmode);
+      emit_call_insn (gen_tls_global_dynamic (a0, x, got));
+      insns = get_insns ();
+      end_sequence ();
+      note = gen_rtx_EXPR_LIST (VOIDmode, const0_rtx, NULL);
+      uns = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_TLS_GD);
+      note = gen_rtx_EXPR_LIST (VOIDmode, uns, note);
+      emit_libcall_block (insns, dest, a0, note);
+      if (crtl->outgoing_args_size == 0)
+	crtl->outgoing_args_size = 8;
+      break;
+
+    case TLS_MODEL_LOCAL_DYNAMIC:
+      got = pic_nonpic_got_ptr ();
+      a0 = gen_rtx_REG (Pmode, FIRST_ADDRESS_REGNUM);
+      start_sequence ();
+      dest = gen_reg_rtx (Pmode);
+      base = gen_reg_rtx (Pmode);
+      emit_call_insn (gen_tls_local_dynamic_base (a0, x, got));
+      emit_move_insn (base, a0);
+      insns = get_insns ();
+      end_sequence ();
+      note = gen_rtx_EXPR_LIST (VOIDmode, const0_rtx, NULL);
+      note = gen_rtx_EXPR_LIST (VOIDmode, GEN_INT (UNSPEC_TLS_LD_BASE), note);
+      emit_libcall_block (insns, base, a0, note);
+
+      uns = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_DTPOFF);
+      uns = gen_rtx_CONST (Pmode, uns);
+      off = gen_reg_rtx (Pmode);
+      emit_move_insn (off, uns);
+      emit_insn (gen_addsi3 (dest, off, base));
+      if (crtl->outgoing_args_size == 0)
+	crtl->outgoing_args_size = 8;
+      break;
+
+    case TLS_MODEL_INITIAL_EXEC:
+      dest = gen_reg_rtx (Pmode);
+      emit_insn (gen_tls_initial_exec (dest, x));
+      insns = emit_insn (gen_addsi3 (dest, dest, mn10300_tls_get_addr ()));
+      break;
+
+    case TLS_MODEL_LOCAL_EXEC:
+      uns = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_TPOFF);
+      uns = gen_rtx_CONST (Pmode, uns);
+      off = gen_reg_rtx (Pmode);
+      emit_move_insn (off, uns);
+      dest = gen_reg_rtx (Pmode);
+      emit_insn (gen_addsi3 (dest, off, mn10300_tls_get_addr ()));
+      break;
+
+    default:
+      abort ();
+    }
+
+  return dest;
+}
+
+/* Returns TRUE if X is a valid constant address.  Used by
+   CONSTANT_ADDRESS_P().  This definition makes sure we don't put TLS
+   symbols in initializers and such.  */
+
+bool
+mn10300_constant_address_p (rtx x)
+{
+  if (tls_symbolic_operand (x, Pmode))
+    return false;
+  return CONSTANT_P (x) && GET_CODE (x) != CONST_DOUBLE;
+}
+
 /* Initialize the GCC target structure.  */
 
+#undef  TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS true
+
 #undef  TARGET_MACHINE_DEPENDENT_REORG
 #define TARGET_MACHINE_DEPENDENT_REORG mn10300_reorg
 
@@ -3422,3 +3690,4 @@
 #define TARGET_FLAGS_REGNUM  CC_REG
 
 struct gcc_target targetm = TARGET_INITIALIZER;
+
Index: gcc/config/mn10300/predicates.md
===================================================================
--- gcc/config/mn10300/predicates.md	(revision 173815)
+++ gcc/config/mn10300/predicates.md	(working copy)
@@ -67,3 +67,18 @@
 (define_predicate "liw_operand"
   (ior (match_operand 0 "register_operand")
        (match_test "satisfies_constraint_O (op)")))
+
+(define_predicate "tls_symbolic_operand"
+  (match_code "symbol_ref")
+{
+  return SYMBOL_REF_TLS_MODEL (op);
+})
+
+(define_predicate "nontls_general_operand"
+  (match_code "const_int,const_double,const,symbol_ref,label_ref,subreg,reg,mem")
+{
+  if (tls_symbolic_operand (op, mode))
+    return false;
+  return general_operand (op, mode);
+})
+
Index: gcc/config/mn10300/mn10300.h
===================================================================
--- gcc/config/mn10300/mn10300.h	(revision 173815)
+++ gcc/config/mn10300/mn10300.h	(working copy)
@@ -272,7 +272,7 @@
 
 enum reg_class
 {
-  NO_REGS, DATA_REGS, ADDRESS_REGS, SP_REGS, SP_OR_ADDRESS_REGS,
+  NO_REGS, D0_REGS, DATA_REGS, A0_REGS, ADDRESS_REGS, SP_REGS, SP_OR_ADDRESS_REGS,
   EXTENDED_REGS, FP_REGS, FP_ACC_REGS, CC_REGS, MDR_REGS,
   GENERAL_REGS, SP_OR_GENERAL_REGS, ALL_REGS, LIM_REG_CLASSES
 };
@@ -282,7 +282,7 @@
 /* Give names of register classes as strings for dump file.  */
 
 #define REG_CLASS_NAMES					   		\
-{ "NO_REGS", "DATA_REGS", "ADDRESS_REGS", "SP_REGS", "SP_OR_ADDRESS_REGS", \
+{ "NO_REGS", "D0_REGS", "DATA_REGS", "A0_REGS", "ADDRESS_REGS", "SP_REGS", "SP_OR_ADDRESS_REGS", \
   "EXTENDED_REGS", "FP_REGS", "FP_ACC_REGS", "CC_REGS", "MDR_REGS",	\
   "GENERAL_REGS", "SP_OR_GENERAL_REGS", "ALL_REGS", "LIM_REGS"		\
 }
@@ -293,7 +293,9 @@
 
 #define REG_CLASS_CONTENTS					\
 { { 0,	        0 },	  /* No regs */				\
+  { 0x00000001, 0 },	  /* D0_REGS */				\
   { 0x0000000f, 0 },	  /* DATA_REGS */			\
+  { 0x00000010, 0 },	  /* A0_REGS */				\
   { 0x000001f0, 0 },	  /* ADDRESS_REGS */			\
   { 0x00000200, 0 },	  /* SP_REGS */				\
   { 0x000003f0, 0 },	  /* SP_OR_ADDRESS_REGS */		\
@@ -740,3 +742,26 @@
 
 #define FILE_ASM_OP "\t.file\n"
 
+#ifndef GENERATOR_FILE
+/* A data structure for per-function information.  */
+typedef struct GTY(()) machine_function
+{
+  /* For non-pic use.  */
+  rtx got_ptr;
+  /* For TLS local dynamic.  */
+  const char * some_ld_name;
+}
+machine_function;
+#endif
+
+#define INIT_EXPANDERS mn10300_init_expanders ()
+
+extern GTY(()) int mn10300_unspec_int_label_counter;
+
+/* %& prints some local dynamic TLS symbol.  */
+
+#define PRINT_OPERAND_PUNCT_VALID_P(CODE)  ((CODE) == '&')
+
+/* 1 if X is an rtx for a constant that is a valid address.  */
+
+#define CONSTANT_ADDRESS_P(X)   mn10300_constant_address_p (X)
Index: gcc/config/mn10300/constraints.md
===================================================================
--- gcc/config/mn10300/constraints.md	(revision 173815)
+++ gcc/config/mn10300/constraints.md	(working copy)
@@ -47,6 +47,9 @@
 (define_register_constraint "c" "TARGET_AM33_2 ? FP_ACC_REGS : NO_REGS"
   "A floating point accumulator register.")
 
+(define_register_constraint "B" "D0_REGS" "The d0 register.")
+(define_register_constraint "C" "A0_REGS" "The a0 register.")
+
 (define_memory_constraint "Q"
   "@internal"
   (and (match_code "mem")
Index: gcc/config/mn10300/mn10300-protos.h
===================================================================
--- gcc/config/mn10300/mn10300-protos.h	(revision 173815)
+++ gcc/config/mn10300/mn10300-protos.h	(working copy)
@@ -20,30 +20,33 @@
    <http://www.gnu.org/licenses/>.  */
 
 #ifdef RTX_CODE
-extern rtx   mn10300_legitimize_pic_address (rtx, rtx);
-extern int   mn10300_legitimate_pic_operand_p (rtx);
-extern rtx   mn10300_legitimize_reload_address (rtx, enum machine_mode,
-						int, int, int);
-extern bool  mn10300_function_value_regno_p (const unsigned int);
-extern int   mn10300_get_live_callee_saved_regs (void);
-extern bool  mn10300_hard_regno_mode_ok (unsigned int, enum machine_mode);
-extern bool  mn10300_modes_tieable (enum machine_mode, enum machine_mode);
-extern const char *mn10300_output_add (rtx[3], bool);
-extern void  mn10300_print_operand (FILE *, rtx, int);
-extern void  mn10300_print_operand_address (FILE *, rtx);
-extern void  mn10300_print_reg_list (FILE *, int);
+extern bool         mn10300_constant_address_p (rtx);
+extern bool         mn10300_function_value_regno_p (const unsigned int);
+extern int          mn10300_get_live_callee_saved_regs (void);
+extern bool         mn10300_hard_regno_mode_ok (unsigned int, enum machine_mode);
+extern rtx          mn10300_legitimize_pic_address (rtx, rtx);
+extern int          mn10300_legitimate_pic_operand_p (rtx);
+extern rtx          mn10300_legitimize_reload_address (rtx, enum machine_mode, int, int, int);
+extern rtx          mn10300_legitimize_tls_address (rtx);
+extern bool         mn10300_match_ccmode (rtx, enum machine_mode);
+extern bool         mn10300_modes_tieable (enum machine_mode, enum machine_mode);
+extern const char * mn10300_output_add (rtx[3], bool);
+extern void         mn10300_print_operand (FILE *, rtx, int);
+extern void         mn10300_print_operand_address (FILE *, rtx);
+extern void         mn10300_print_reg_list (FILE *, int);
 extern enum machine_mode mn10300_select_cc_mode (enum rtx_code, rtx, rtx);
-extern int   mn10300_store_multiple_operation (rtx, enum machine_mode);
-extern int   mn10300_symbolic_operand (rtx, enum machine_mode);
-extern void  mn10300_split_cbranch (enum machine_mode, rtx, rtx);
-extern int   mn10300_split_and_operand_count (rtx);
-extern bool  mn10300_match_ccmode (rtx, enum machine_mode);
+extern void         mn10300_split_cbranch (enum machine_mode, rtx, rtx);
+extern int          mn10300_split_and_operand_count (rtx);
+extern int          mn10300_store_multiple_operation (rtx, enum machine_mode);
+extern int          mn10300_symbolic_operand (rtx, enum machine_mode);
+extern rtx          mn10300_tls_get_addr (void);
 #endif /* RTX_CODE */
 
-extern bool  mn10300_regno_in_class_p (unsigned, int, bool);
+extern bool  mn10300_can_use_retf_insn (void);
 extern bool  mn10300_can_use_rets_insn (void);
-extern bool  mn10300_can_use_retf_insn (void);
+extern void  mn10300_expand_epilogue (void);
 extern void  mn10300_expand_prologue (void);
-extern void  mn10300_expand_epilogue (void);
+extern int   mn10300_frame_size (void);
+extern void  mn10300_init_expanders (void);
 extern int   mn10300_initial_offset (int, int);
-extern int   mn10300_frame_size (void);
+extern bool  mn10300_regno_in_class_p (unsigned, int, bool);
Index: gcc/config/mn10300/mn10300.md
===================================================================
--- gcc/config/mn10300/mn10300.md	(revision 173815)
+++ gcc/config/mn10300/mn10300.md	(working copy)
@@ -28,9 +28,11 @@
 (define_constants [
   (PIC_REG   6)
   (SP_REG    9)
+  (TLS_REG  12)
   (MDR_REG  50)
   (CC_REG   51)
 
+  (UNSPEC_INT_LABEL	0)
   (UNSPEC_PIC		1)
   (UNSPEC_GOT		2)
   (UNSPEC_GOTOFF	3)
@@ -44,6 +46,18 @@
   (UNSPEC_LIW		8)
   ;; This is for the low overhead loop instructions.
   (UNSPEC_SETLB         9)
+
+  ;; These put the corresponding @op suffix on TLS variables.
+  (UNSPEC_TLSGD		100)
+  (UNSPEC_TLSLDM	101)
+  (UNSPEC_DTPOFF	102)
+  (UNSPEC_GOTNTPOFF	103)
+  (UNSPEC_INDNTPOFF	104)
+  (UNSPEC_TPOFF		105)
+
+  ;; These are used to differentiate tls-specific insns.
+  (UNSPEC_TLS_GD	110)
+  (UNSPEC_TLS_LD_BASE	111)
 ])
 
 (include "predicates.md")
@@ -393,10 +407,33 @@
 	(match_operand:SI 1 "general_operand"))]
   ""
 {
+  if (tls_symbolic_operand (operands[1], Pmode))
+    {
+      operands[1] = mn10300_legitimize_tls_address (operands[1]);
+      operands[1] = force_operand (operands[1], operands[0]);
+      if (operands[1] == operands[0])
+        DONE;
+    }
+
+  if (GET_CODE (operands[1]) == CONST
+      && GET_CODE (XEXP (operands[1], 0)) == PLUS
+      && tls_symbolic_operand (XEXP (XEXP (operands[1], 0), 0), Pmode))
+    {
+      rtx plus = XEXP (XEXP (operands[1], 0), 1);
+      rtx tls  = XEXP (XEXP (operands[1], 0), 0);
+
+      operands[1] = mn10300_legitimize_tls_address (tls);
+      operands[1] = gen_rtx_PLUS (SImode, operands[1], plus);
+      operands[1] = force_operand (operands[1], operands[0]);
+      if (operands[1] == operands[0])
+        DONE;
+    }
+
   /* One of the ops has to be in a register.  */
   if (!register_operand (operand1, SImode)
       && !register_operand (operand0, SImode))
     operands[1] = force_reg (SImode, operand1);
+
   if (flag_pic)
     {
       rtx temp;
@@ -432,7 +469,7 @@
 (define_insn "*movsi_internal"
   [(set (match_operand:SI 0 "nonimmediate_operand"
 			  "=r,r,r,r,m,r, A,*y,*y,*z,*d")
-	(match_operand:SI 1 "general_operand"
+	(match_operand:SI 1 "nontls_general_operand"
 			  " 0,O,i,r,r,m,*y, A, i,*d,*z"))]
   "register_operand (operands[0], SImode)
    || register_operand (operands[1], SImode)"
@@ -2204,3 +2241,188 @@
   "FL%b0 # loop back to: %1"
   [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34") (const_int 44) (const_int 11)))]
 )
+
+; We clobber d0 instead of passing it as a parameter so that gcc will
+; know that it doesn't have to set a value in it.  We use constraints
+; to specify it as reload avoids regs that are mentioned explicitly.
+; Whoever emits this is responsible for moving the result out of a0
+; into a pseudo, else reload complains sometimes.  We use PIC_REG so
+; that gcc won't delete the prologue insns that set it.  We don't
+; split the insns because relaxation requires this specific insn
+; sequence.
+
+(define_insn "tls_global_dynamic_i"
+  [(parallel
+    [(set (match_operand:SI         0 "register_operand" "=C")
+	  (call (unspec:SI
+		 [(match_operand:SI 1 "tls_symbolic_operand" "")
+		  (match_operand:SI 2 "register_operand" "a")
+		  (match_operand    4 "register_operand" "")]
+		 UNSPEC_TLS_GD)
+		(const_int 0)))
+     (clobber (match_operand        3 "register_operand" "=B"))])
+   ]
+  ""
+  {
+    if (flag_pic)
+      return "mov %1@tlsgd, %3\;add %2, %3\;call __tls_get_addr@PLT,[],0";
+    return   "mov %1@tlsgd, %3\;add %2, %3\;call __tls_get_addr,[],0";
+  }
+  ;; Timings: AM33  AM34
+  ;; MOV        4     3    (latency invoked because ADD uses %3)
+  ;; ADD        1     1
+  ;; CALL       3     5
+  ;; -------------------
+  ;; total      8     9
+  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34") (const_int 99) (const_int 88)))]
+)
+
+(define_expand "tls_global_dynamic"
+  [(parallel
+    [(set (match_operand:SI 0 "register_operand" "")
+	  (call (unspec:SI
+		 [(match_operand:SI 1 "tls_symbolic_operand" "")
+		  (match_operand:SI 2 "register_operand" "")
+		  (match_dup 4)]
+		 UNSPEC_TLS_GD)
+		(const_int 0)))
+     (clobber (match_dup 3))])
+   ]
+  ""
+  {
+    operands[3] = gen_reg_rtx (SImode);
+    operands[4] = mn10300_tls_get_addr ();
+  }
+)
+
+(define_insn "tls_local_dynamic_base_i"
+  [(parallel
+    [(set (match_operand:SI 0 "register_operand" "=C")
+	  (call (unspec:SI
+		 [(match_operand:SI 1 "tls_symbolic_operand" "")
+		  (match_operand:SI 2 "register_operand" "a")
+		  (match_operand 4 "register_operand" "")]
+		 UNSPEC_TLS_LD_BASE)
+		(const_int 0)))
+     (clobber (match_operand 3 "register_operand" "=B"))])
+   ]
+  ""
+  {
+    if (flag_pic)
+      return "mov %&@tlsldm, %3\;add %2, %3\;call __tls_get_addr@PLT,[],0";
+    return   "mov %&@tlsldm, %3\;add %2, %3\;call __tls_get_addr,[],0";
+  }
+  ;; Timings: AM33  AM34
+  ;; MOV        4     3    (latency invoked because ADD uses %3)
+  ;; ADD        1     1
+  ;; CALL       3     5
+  ;; -------------------
+  ;; total      8     9
+  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34") (const_int 99) (const_int 88)))]
+)
+
+(define_expand "tls_local_dynamic_base"
+  [(parallel
+    [(set (match_operand:SI 0 "register_operand" "")
+	  (call (unspec:SI
+		 [(match_operand:SI 1 "tls_symbolic_operand" "")
+		  (match_operand:SI 2 "register_operand" "")
+		  (match_dup 4)]
+		 UNSPEC_TLS_LD_BASE)
+		(const_int 0)))
+     (clobber (match_dup 3))])
+   ]
+  ""
+  {
+    operands[3] = gen_reg_rtx (SImode);
+    operands[4] = mn10300_tls_get_addr ();
+  }
+)
+
+(define_expand "tls_initial_exec"
+  [(match_operand:SI 0 "" "")
+   (match_operand:SI 1 "" "")]
+  ""
+  "
+  {
+    rtx insn;
+
+    if (flag_pic)
+      insn = emit_insn (gen_tls_initial_exec_1 (operands[0], operands[1]));
+    else
+      insn = emit_insn (gen_tls_initial_exec_2 (operands[0], operands[1]));
+
+    MEM_READONLY_P (SET_SRC (PATTERN (insn))) = 1;
+
+    DONE;
+  }"
+)
+
+(define_expand "tls_initial_exec_1"
+  [(set (match_operand:SI 0 "" "")
+	(mem:SI (plus:SI (reg:SI PIC_REG)
+			 (const (unspec [(match_operand:SI 1 "" "")]
+					UNSPEC_GOTNTPOFF)))))
+  ]
+  ""
+  ""
+)
+
+(define_expand "tls_initial_exec_2"
+  [(set (match_operand:SI 0 "" "")
+	(mem:SI (const (unspec [(match_operand:SI 1 "" "")]
+				UNSPEC_INDNTPOFF))))
+  ]
+  ""
+  ""
+)
+
+;; Used for non-pic code; will store in any register.
+(define_expand "am33_set_got"
+  [(match_operand:SI 0 "" "")
+   (match_dup 1)
+  ]
+  "TARGET_AM33"
+  "
+  {
+    rtx tmp = gen_reg_rtx (SImode);
+
+    operands[1] = gen_int_label (GEN_INT (mn10300_unspec_int_label_counter++));
+    emit_insn (gen_am33_loadPC_anyreg (tmp, operands[1]));
+    emit_insn (gen_add_GOT_to_any_reg (operands[0], tmp, operands[1]));
+    DONE;
+  }"
+)
+
+(define_expand "int_label"
+  [(unspec [(match_operand:SI 0 "" "")] UNSPEC_INT_LABEL)]
+  ""
+  ""
+)
+
+(define_insn "am33_loadPC_anyreg"
+  [(parallel
+    [(set (match_operand 0 "register_operand" "=a") (pc))
+     (use (match_operand 1 "" ""))])]
+  "TARGET_AM33"
+  "%1:\;mov pc, %0"
+  ;; [(set_attr "timings" "11")]
+)
+
+(define_expand "add_GOT_to_any_reg"
+  [(parallel [(set (match_operand:SI 0 "" "")
+		   (plus:SI
+		    (match_operand:SI 1 "" "")
+		    (const
+		     (unspec [(minus:SI
+			       (match_dup 3)
+			       (const (minus:SI
+				       (const (match_operand:SI 2 "" ""))
+				       (pc))))
+			      ] UNSPEC_PIC))))
+	      (clobber (reg:CC CC_REG))
+	     ])
+  ]
+  ""
+  "operands[3] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);"
+)

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]