sh.c (TARGET_HAVE_TLS): Conditionally define.
authorKaz Kojima <kkojima@gcc.gnu.org>
Mon, 24 Feb 2003 02:44:02 +0000 (02:44 +0000)
committerKaz Kojima <kkojima@gcc.gnu.org>
Mon, 24 Feb 2003 02:44:02 +0000 (02:44 +0000)
* config/sh/sh.c (TARGET_HAVE_TLS): Conditionally define.
(prepare_move_operands): Handle TLS operands.
(tls_symbolic_operand): New.
(nonpic_symbol_mentioned_p): Handle TLS UNSPECs.
(legitimize_pic_address): Do nothing for the TLS symbol.
(sh_encode_section_info): Handle TLS case.
(sh_strip_name_encoding): Drop TLS encoding.
* config/sh/sh-protos.h (tls_symbolic_operand): Add prototype.
* config/sh/sh.h (SH_TLS_ENCODING): Define.
(TLS_SYMNAME_P, STRIP_TLS_ENCODING): Likewise.
(ASM_OUTPUT_LABELREF): Drop TLS encoding.
(OUTPUT_ADDR_CONST_EXTRA): Handle TLS UNSPECs.
* config/sh/sh.md: Define TLS UNSPEC constants.
(type): Add tls_load.
("tls_global_dynamic", "tls_local_dynamic"): New insns.
("sym2DTPOFF", "symDTPOFF2reg", "sym2GOTTPOFF"): New expanders.
("tls_initial_exec"): New insn.
("sym2TPOFF", "symTPOFF2reg"): New expanders.
("load_gbr"): New insn.

* configure.in (HAVE_AS_TLS): Add sh-*-* and sh[34]*-*-* cases.
        * configure: Regenerate.

From-SVN: r63353

gcc/ChangeLog
gcc/config/sh/sh-protos.h
gcc/config/sh/sh.c
gcc/config/sh/sh.h
gcc/config/sh/sh.md

index 0e92c85ee9ba98c2dbb1ed056aba9d99092eee08..2efa9116bd18c2fc5f2da6b952aeef093eb0d4a2 100644 (file)
@@ -1,3 +1,28 @@
+2003-02-24  Kaz Kojima  <kkojima@gcc.gnu.org>
+
+       * config/sh/sh.c (TARGET_HAVE_TLS): Conditionally define.
+       (prepare_move_operands): Handle TLS operands.
+       (tls_symbolic_operand): New.
+       (nonpic_symbol_mentioned_p): Handle TLS UNSPECs.
+       (legitimize_pic_address): Do nothing for the TLS symbol.
+       (sh_encode_section_info): Handle TLS case.
+       (sh_strip_name_encoding): Drop TLS encoding.
+       * config/sh/sh-protos.h (tls_symbolic_operand): Add prototype.
+       * config/sh/sh.h (SH_TLS_ENCODING): Define.
+       (TLS_SYMNAME_P, STRIP_TLS_ENCODING): Likewise.
+       (ASM_OUTPUT_LABELREF): Drop TLS encoding.
+       (OUTPUT_ADDR_CONST_EXTRA): Handle TLS UNSPECs.
+       * config/sh/sh.md: Define TLS UNSPEC constants.
+       (type): Add tls_load.
+       ("tls_global_dynamic", "tls_local_dynamic"): New insns.
+       ("sym2DTPOFF", "symDTPOFF2reg", "sym2GOTTPOFF"): New expanders.
+       ("tls_initial_exec"): New insn.
+       ("sym2TPOFF", "symTPOFF2reg"): New expanders.
+       ("load_gbr"): New insn.
+
+       * configure.in (HAVE_AS_TLS): Add sh-*-* and sh[34]*-*-* cases.
+        * configure: Regenerate.
+
 2003-02-24  Alan Modra  <amodra@bigpond.net.au>
 
        * calls.c (store_one_arg): Revert 1999-02-16 change.  Revert
index f04ab01670925ee1c943efd832fffddb8b9628c0..f7758a15992c6a5441ef05dd3bb8190c22fe2142 100644 (file)
@@ -75,6 +75,7 @@ extern void fixup_addr_diff_vecs PARAMS ((rtx));
 extern int get_dest_uid PARAMS ((rtx, int));
 extern void final_prescan_insn PARAMS ((rtx, rtx *, int));
 extern int symbol_ref_operand PARAMS ((rtx, enum machine_mode));
+extern int tls_symbolic_operand PARAMS ((rtx, enum machine_mode));
 extern int system_reg_operand PARAMS ((rtx, enum machine_mode));
 extern int general_movsrc_operand PARAMS ((rtx, enum machine_mode));
 extern int general_movdst_operand PARAMS ((rtx, enum machine_mode));
index a0b7a92765e4f8ba2c5b79c106532ea4f39531cc..3c7549b29b51a0c52afc41be0926332ecd8d0b4d 100644 (file)
@@ -280,6 +280,11 @@ static int sh_address_cost PARAMS ((rtx));
 #undef TARGET_ADDRESS_COST
 #define TARGET_ADDRESS_COST sh_address_cost
 
+#ifdef HAVE_AS_TLS
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS true
+#endif
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Print the operand address in x to the stream.  */
@@ -708,7 +713,10 @@ prepare_move_operands (operands, mode)
      rtx operands[];
      enum machine_mode mode;
 {
-  if ((mode == SImode || mode == DImode) && flag_pic)
+  if ((mode == SImode || mode == DImode)
+      && flag_pic
+      && ! ((mode == Pmode || mode == ptr_mode)
+           && tls_symbolic_operand (operands[1], Pmode) != 0))
     {
       rtx temp;
       if (SYMBOLIC_CONST_P (operands[1]))
@@ -758,6 +766,73 @@ prepare_move_operands (operands, mode)
        operands[1] = copy_to_mode_reg (mode, operands[1]);
     }
 
+  if (mode == Pmode || mode == ptr_mode)
+    {
+      rtx op0, op1;
+      enum tls_model tls_kind;
+
+      op0 = operands[0];
+      op1 = operands[1];
+      if ((tls_kind = tls_symbolic_operand (op1, Pmode)))
+       {
+         rtx tga_op1, tga_ret, tmp, tmp2;
+
+         
+         switch (tls_kind)
+           {
+           case TLS_MODEL_GLOBAL_DYNAMIC:
+             tga_ret = gen_rtx_REG (Pmode, R0_REG);
+             emit_insn (gen_tls_global_dynamic (tga_ret, op1));
+             op1 = tga_ret;
+             break;
+
+           case TLS_MODEL_LOCAL_DYNAMIC:
+             tga_ret = gen_rtx_REG (Pmode, R0_REG);
+             emit_insn (gen_tls_local_dynamic (tga_ret, op1));
+
+             tmp = gen_reg_rtx (Pmode);
+             emit_move_insn (tmp, tga_ret);
+
+             if (register_operand (op0, Pmode))
+               tmp2 = op0;
+             else
+               tmp2 = gen_reg_rtx (Pmode);
+
+             emit_insn (gen_symDTPOFF2reg (tmp2, op1, tmp));
+             op1 = tmp2;
+             break;
+
+           case TLS_MODEL_INITIAL_EXEC:
+             if (! flag_pic)
+               emit_insn (gen_GOTaddr2picreg ());
+             tga_op1 = gen_reg_rtx (Pmode);
+             tmp = gen_sym2GOTTPOFF (op1);
+             emit_insn (gen_tls_initial_exec (tga_op1, tmp));
+             op1 = tga_op1;
+             break;
+
+           case TLS_MODEL_LOCAL_EXEC:
+             tmp2 = gen_reg_rtx (Pmode);
+             emit_insn (gen_load_gbr (tmp2));
+             tmp = gen_reg_rtx (Pmode);
+             emit_insn (gen_symTPOFF2reg (tmp, op1));
+             RTX_UNCHANGING_P (tmp) = 1;
+
+             if (register_operand (op0, Pmode))
+               op1 = op0;
+             else
+               op1 = gen_reg_rtx (Pmode);
+
+             emit_insn (gen_addsi3 (op1, tmp, tmp2));
+             break;
+
+           default:
+             abort ();
+           }
+         operands[1] = op1;
+       }
+    }
+
   return 0;
 }
 
@@ -6429,6 +6504,36 @@ symbol_ref_operand (op, mode)
   return (GET_CODE (op) == SYMBOL_REF);
 }
 
+/* Return the TLS type for TLS symbols, 0 for otherwise.  */
+int
+tls_symbolic_operand (op, mode)
+     rtx op;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  const char *str;
+
+  if (GET_CODE (op) != SYMBOL_REF)
+    return 0;
+
+  str = XSTR (op, 0);
+  STRIP_DATALABEL_ENCODING(str, str);  
+  if (! TLS_SYMNAME_P (str))
+    return 0;
+
+  switch (str[1])
+    {
+    case 'G':
+      return TLS_MODEL_GLOBAL_DYNAMIC;
+    case 'L':
+      return TLS_MODEL_LOCAL_DYNAMIC;
+    case 'i':
+      return TLS_MODEL_INITIAL_EXEC;
+    case 'l':
+      return TLS_MODEL_LOCAL_EXEC;
+    }
+  return 0;
+}
+
 int
 commutative_float_operator (op, mode)
      rtx op;
@@ -7174,6 +7279,8 @@ nonpic_symbol_mentioned_p (x)
          || XINT (x, 1) == UNSPEC_GOT
          || XINT (x, 1) == UNSPEC_GOTOFF
          || XINT (x, 1) == UNSPEC_GOTPLT
+         || XINT (x, 1) == UNSPEC_GOTTPOFF
+         || XINT (x, 1) == UNSPEC_DTPOFF
          || XINT (x, 1) == UNSPEC_PLT))
       return 0;
 
@@ -7203,6 +7310,9 @@ legitimize_pic_address (orig, mode, reg)
      enum machine_mode mode ATTRIBUTE_UNUSED;
      rtx reg;
 {
+  if (tls_symbolic_operand (orig, Pmode))
+    return orig;
+
   if (GET_CODE (orig) == LABEL_REF
       || (GET_CODE (orig) == SYMBOL_REF
          && (CONSTANT_POOL_ADDRESS_P (orig)
@@ -7555,6 +7665,60 @@ sh_encode_section_info (decl, first)
   if (flag_pic)
     SYMBOL_REF_FLAG (symbol) = (*targetm.binds_local_p) (decl);
 
+  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
+    {
+      const char *symbol_str, *orig_str;
+      bool is_local;
+      enum tls_model kind;
+      char encoding;
+      char *newstr;
+      size_t len, dlen;
+
+      orig_str = XSTR (symbol, 0);
+      is_local = (*targetm.binds_local_p) (decl);
+
+      if (! flag_pic)
+       {
+         if (is_local)
+           kind = TLS_MODEL_LOCAL_EXEC;
+         else
+           kind = TLS_MODEL_INITIAL_EXEC;
+       }
+      else if (is_local)
+       kind = TLS_MODEL_LOCAL_DYNAMIC;
+      else
+       kind = TLS_MODEL_GLOBAL_DYNAMIC;
+      if (kind < flag_tls_default)
+       kind = flag_tls_default;
+
+      STRIP_DATALABEL_ENCODING (symbol_str, orig_str);
+      dlen = symbol_str - orig_str;
+
+      encoding = " GLil"[kind];
+      if (TLS_SYMNAME_P (symbol_str))
+       {
+         if (encoding == symbol_str[1])
+           return;
+         /* Handle the changes from initial-exec to local-exec and
+            from global-dynamic to local-dynamic.  */
+         if ((encoding == 'l' && symbol_str[1] == 'i')
+             || (encoding == 'L' && symbol_str[1] == 'G'))
+           symbol_str += 2;
+         else
+           abort ();
+       }
+
+      len = strlen (symbol_str);
+      newstr = alloca (dlen + len + 3);
+      if (dlen)
+       memcpy (newstr, orig_str, dlen);
+      newstr[dlen + 0] = SH_TLS_ENCODING[0];
+      newstr[dlen + 1] = encoding;
+      memcpy (newstr + dlen + 2, symbol_str, len + 1);
+
+      XSTR (symbol, 0) = ggc_alloc_string (newstr, dlen + len + 2);
+    }
+
   if (TARGET_SH5 && first && TREE_CODE (decl) != FUNCTION_DECL)
     XEXP (rtl, 0) = gen_datalabel_ref (symbol);
 }
@@ -7566,6 +7730,7 @@ sh_strip_name_encoding (str)
      const char *str;
 {
   STRIP_DATALABEL_ENCODING (str, str);
+  STRIP_TLS_ENCODING (str, str);
   str += *str == '*';
   return str;
 }
index f99ed78d1ed7bd06eb73da99bab59a2cb9156ebd..82325b89d81dd37013ab0f33031ec7432d939999 100644 (file)
@@ -2752,6 +2752,20 @@ while (0)
 ((GET_CODE (X) == SYMBOL_REF || GET_CODE (X) == LABEL_REF)     \
   && nonpic_symbol_mentioned_p (X))
 \f
+/* TLS.  */
+
+/* The prefix used to mark SYMBOL_REFs that refer to TLS symbols.  */
+#define SH_TLS_ENCODING "@"
+
+/* Return true if SYM_NAME starts with SH_TLS_ENCODING.  */
+#define TLS_SYMNAME_P(SYM_NAME) \
+  ((SYM_NAME)[0] == SH_TLS_ENCODING[0])
+
+/* Skip an optional SH_TLS_ENCODING in the beginning of SYM_NAME.  */
+#define STRIP_TLS_ENCODING(VAR, SYM_NAME) \
+  (VAR) = (SYM_NAME) + (TLS_SYMNAME_P (SYM_NAME) \
+                       ? strlen (SH_TLS_ENCODING) + 1 : 0)
+\f
 /* Compute extra cost of moving data between one register class
    and another.  */
 
@@ -2915,6 +2929,7 @@ while (0)
       const char * lname;                              \
                                                        \
       STRIP_DATALABEL_ENCODING (lname, (NAME));                \
+      STRIP_TLS_ENCODING (lname, lname);               \
       if (lname[0] == '*')                             \
        fputs (lname + 1, (FILE));                      \
       else                                             \
@@ -3053,6 +3068,18 @@ while (0)
            output_addr_const ((STREAM), XVECEXP ((X), 0, 0));          \
            fputs ("@GOTPLT", (STREAM));                                \
            break;                                                      \
+         case UNSPEC_DTPOFF:                                           \
+           output_addr_const ((STREAM), XVECEXP ((X), 0, 0));          \
+           fputs ("@DTPOFF", (STREAM));                                \
+           break;                                                      \
+         case UNSPEC_GOTTPOFF:                                         \
+           output_addr_const ((STREAM), XVECEXP ((X), 0, 0));          \
+           fputs ("@GOTTPOFF", (STREAM));                              \
+           break;                                                      \
+         case UNSPEC_TPOFF:                                            \
+           output_addr_const ((STREAM), XVECEXP ((X), 0, 0));          \
+           fputs ("@TPOFF", (STREAM));                                 \
+           break;                                                      \
          case UNSPEC_CALLER:                                           \
            {                                                           \
              char name[32];                                            \
index e32d30a49a4d70ec076d8d93b9a4639659830381..f26d2b37e50af2aa4e835274a512e8660078eb26 100644 (file)
   (UNSPEC_NSB          17)
   (UNSPEC_ALLOCO       18)
   (UNSPEC_EH_RETURN    19)
+  (UNSPEC_TLSGD                20)
+  (UNSPEC_TLSLDM       21)
+  (UNSPEC_TLSIE                22)
+  (UNSPEC_DTPOFF       23)
+  (UNSPEC_GOTTPOFF     24)
+  (UNSPEC_TPOFF                25)
 
   ;; These are used with unspec_volatile.
   (UNSPECV_BLOCKAGE    0)
 ;; ftrc_s      fix_truncsfsi2_i4
 ;; dfdiv       double precision floating point divide (or square root)
 ;; cwb         ic_invalidate_line_i
+;; tls_load     load TLS related address 
 ;; arith_media SHmedia arithmetic, logical, and shift instructions
 ;; cbranch_media SHmedia conditional branch instructions
 ;; cmp_media   SHmedia compare instructions
 ;; nil         no-op move, will be deleted.
 
 (define_attr "type"
- "mt_group,cbranch,jump,jump_ind,arith,arith3,arith3b,dyn_shift,load,load_si,fload,store,move,fmove,smpy,dmpy,return,pload,prset,pstore,prget,pcload,pcload_si,pcfload,rte,sfunc,call,fp,fdiv,ftrc_s,dfp_arith,dfp_cmp,dfp_conv,dfdiv,gp_fpul,fpul_gp,mac_gp,mem_fpscr,gp_fpscr,cwb,arith_media,cbranch_media,cmp_media,dfdiv_media,dfmul_media,dfparith_media,dfpconv_media,dmpy_media,fcmp_media,fdiv_media,fload_media,fmove_media,fparith_media,fpconv_media,fstore_media,gettr_media,invalidate_line_media,jump_media,load_media,pt_media,ptabs_media,store_media,mcmp_media,mac_media,d2mpy_media,atrans_media,ustore_media,nil,other"
+ "mt_group,cbranch,jump,jump_ind,arith,arith3,arith3b,dyn_shift,load,load_si,fload,store,move,fmove,smpy,dmpy,return,pload,prset,pstore,prget,pcload,pcload_si,pcfload,rte,sfunc,call,fp,fdiv,ftrc_s,dfp_arith,dfp_cmp,dfp_conv,dfdiv,gp_fpul,fpul_gp,mac_gp,mem_fpscr,gp_fpscr,cwb,tls_load,arith_media,cbranch_media,cmp_media,dfdiv_media,dfmul_media,dfparith_media,dfpconv_media,dmpy_media,fcmp_media,fdiv_media,fload_media,fmove_media,fparith_media,fpconv_media,fstore_media,gettr_media,invalidate_line_media,jump_media,load_media,pt_media,ptabs_media,store_media,mcmp_media,mac_media,d2mpy_media,atrans_media,ustore_media,nil,other"
   (const_string "other"))
 
 ;; We define a new attribute namely "insn_class".We use
   ""
   "")
 
+;; TLS code generation.
+;; ??? this should be a define_insn_and_split
+;; See the thread [PATCH/RFA] SH TLS support on gcc-patches
+;; <http://gcc.gnu.org/ml/gcc-patches/2003-02/msg01898.html>
+;; for details.
+
+(define_insn "tls_global_dynamic"
+  [(set (match_operand:SI 0 "register_operand" "=&z")
+       (unspec:SI [(match_operand:SI 1 "" "")]
+                   UNSPEC_TLSGD))
+   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI PIC_REG))
+   (clobber (reg:SI PR_REG))
+   (clobber (scratch:SI))]
+  "TARGET_SH1"
+  "*
+{
+  return \"\\
+mov.l\\t1f,r4\\n\\
+\\tmova\\t2f,r0\\n\\
+\\tmov.l\\t2f,r1\\n\\
+\\tadd\\tr0,r1\\n\\
+\\tjsr\\t@r1\\n\\
+\\tadd\\tr12,r4\\n\\
+\\tbra\\t3f\\n\\
+\\tnop\\n\\
+\\t.align\\t2\\n\\
+1:\\t.long\\t%a1@TLSGD\\n\\
+2:\\t.long\\t__tls_get_addr@PLT\\n\\
+3:\";
+}"
+  [(set_attr "type" "tls_load")
+   (set_attr "length" "26")])
+
+(define_insn "tls_local_dynamic"
+  [(set (match_operand:SI 0 "register_operand" "=&z")
+       (unspec:SI [(match_operand:SI 1 "" "")]
+                   UNSPEC_TLSLDM))
+   (use (reg:PSI FPSCR_REG))
+   (use (reg:SI PIC_REG))
+   (clobber (reg:SI PR_REG))
+   (clobber (scratch:SI))]
+  "TARGET_SH1"
+  "*
+{
+  return \"\\
+mov.l\\t1f,r4\\n\\
+\\tmova\\t2f,r0\\n\\
+\\tmov.l\\t2f,r1\\n\\
+\\tadd\\tr0,r1\\n\\
+\\tjsr\\t@r1\\n\\
+\\tadd\\tr12,r4\\n\\
+\\tbra\\t3f\\n\\
+\\tnop\\n\\
+\\t.align\\t2\\n\\
+1:\\t.long\\t%a1@TLSLDM\\n\\
+2:\\t.long\\t__tls_get_addr@PLT\\n\\
+3:\";
+}"
+  [(set_attr "type" "tls_load")
+   (set_attr "length" "26")])
+
+(define_expand "sym2DTPOFF"
+  [(const (unspec [(match_operand 0 "" "")] UNSPEC_DTPOFF))]
+  ""
+  "")
+
+(define_expand "symDTPOFF2reg"
+  [(match_operand 0 "" "") (match_operand 1 "" "") (match_operand 2 "" "")]
+  ""
+  "
+{
+  rtx dtpoffsym, insn;
+  rtx t = no_new_pseudos ? operands[0] : gen_reg_rtx (GET_MODE (operands[0]));
+
+  dtpoffsym = gen_sym2DTPOFF (operands[1]);
+  PUT_MODE (dtpoffsym, Pmode);
+  emit_move_insn (t, dtpoffsym);
+  insn = emit_move_insn (operands[0],
+                        gen_rtx_PLUS (Pmode, t, operands[2]));
+  DONE;
+}")
+
+(define_expand "sym2GOTTPOFF"
+  [(const (unspec [(match_operand 0 "" "")] UNSPEC_GOTTPOFF))]
+  ""
+  "")
+
+(define_insn "tls_initial_exec"
+  [(set (match_operand:SI 0 "register_operand" "=&r")
+       (unspec:SI [(match_operand:SI 1 "" "")]
+                   UNSPEC_TLSIE))
+   (use (reg:SI GBR_REG))
+   (use (reg:SI PIC_REG))
+   (clobber (reg:SI R0_REG))]
+  ""
+  "*
+{
+  return \"\\
+mov.l\\t1f,r0\\n\\
+\\tstc\\tgbr,%0\\n\\
+\\tmov.l\\t@(r0,r12),r0\\n\\
+\\tbra\\t2f\\n\\
+\\tadd\\tr0,%0\\n\\
+\\t.align\\t2\\n\\
+1:\\t.long\\t%a1\\n\\
+2:\";
+}"
+  [(set_attr "type" "tls_load")
+   (set_attr "length" "16")])
+
+(define_expand "sym2TPOFF"
+  [(const (unspec [(match_operand 0 "" "")] UNSPEC_TPOFF))]
+  ""
+  "")
+
+(define_expand "symTPOFF2reg"
+  [(match_operand 0 "" "") (match_operand 1 "" "")]
+  ""
+  "
+{
+  rtx tpoffsym, insn;
+
+  tpoffsym = gen_sym2TPOFF (operands[1]);
+  PUT_MODE (tpoffsym, Pmode);
+  insn = emit_move_insn (operands[0], tpoffsym);
+  DONE;
+}")
+
+(define_insn "load_gbr"
+  [(set (match_operand:SI 0 "register_operand" "") (reg:SI GBR_REG))
+   (use (reg:SI GBR_REG))]
+  ""
+  "stc gbr,%0"
+  [(set_attr "type" "tls_load")])
+
 ;; case instruction for switch statements.
 
 ;; Operand 0 is index