diff options
author | Kaz Kojima <kkojima@gcc.gnu.org> | 2003-02-24 02:44:02 +0000 |
---|---|---|
committer | Kaz Kojima <kkojima@gcc.gnu.org> | 2003-02-24 02:44:02 +0000 |
commit | 463f02cd037fbf3af66cdbfff526fcb48d2ba746 (patch) | |
tree | 553894bde43b663f56ac150a268af18125866500 | |
parent | cf88ede3d283f7ccab57c921204f855bb5b283a4 (diff) | |
download | gcc-463f02cd037fbf3af66cdbfff526fcb48d2ba746.zip gcc-463f02cd037fbf3af66cdbfff526fcb48d2ba746.tar.gz gcc-463f02cd037fbf3af66cdbfff526fcb48d2ba746.tar.bz2 |
sh.c (TARGET_HAVE_TLS): Conditionally define.
* 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
-rw-r--r-- | gcc/ChangeLog | 25 | ||||
-rw-r--r-- | gcc/config/sh/sh-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/sh/sh.c | 167 | ||||
-rw-r--r-- | gcc/config/sh/sh.h | 27 | ||||
-rw-r--r-- | gcc/config/sh/sh.md | 145 |
5 files changed, 363 insertions, 2 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0e92c85..2efa911 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h index f04ab01..f7758a1 100644 --- a/gcc/config/sh/sh-protos.h +++ b/gcc/config/sh/sh-protos.h @@ -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)); diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index a0b7a92..3c7549b 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -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; /* 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; } diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h index f99ed78..82325b8 100644 --- a/gcc/config/sh/sh.h +++ b/gcc/config/sh/sh.h @@ -2752,6 +2752,20 @@ while (0) ((GET_CODE (X) == SYMBOL_REF || GET_CODE (X) == LABEL_REF) \ && nonpic_symbol_mentioned_p (X)) +/* 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) + /* 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]; \ diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index e32d30a..f26d2b3 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -136,6 +136,12 @@ (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) @@ -211,6 +217,7 @@ ;; 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 @@ -241,7 +248,7 @@ ;; 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 @@ -6801,6 +6808,142 @@ "" "") +;; 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 |