diff options
author | bwilson <bwilson@138bc75d-0d04-0410-961f-82ee72b054a4> | 2008-09-19 00:18:42 +0000 |
---|---|---|
committer | bwilson <bwilson@138bc75d-0d04-0410-961f-82ee72b054a4> | 2008-09-19 00:18:42 +0000 |
commit | c656b8fda2b22fa00e7aacf132702ddef2a140f3 (patch) | |
tree | a196eef4130a81ffbab10ca6a0aa591ab52731ad /gcc/config | |
parent | cc04a47dd74aa6268875f088eb29da97d45e6322 (diff) | |
download | gcc-c656b8fda2b22fa00e7aacf132702ddef2a140f3.tar.gz |
* configure.ac: Add HAVE_AS_TLS check for Xtensa.
* config/xtensa/predicates.md (tls_symbol_operand): New.
* config/xtensa/xtensa.c (TARGET_HAVE_TLS): Define.
(TARGET_CANNOT_FORCE_MEM): Define.
(xtensa_tls_symbol_p): New.
(xtensa_emit_move_sequence): Check for and legitimize TLS addresses.
(xtensa_legitimate_address_p): Disallow constant pool TLS references.
(xtensa_tls_module_base): New.
(xtensa_call_tls_desc): New.
(xtensa_legitimize_tls_address): New.
(xtensa_legitimize_address): Handle TLS symbols.
(xtensa_tls_referenced_p_1): New.
(xtensa_tls_referenced_p): New.
(xtensa_output_addr_const_extra): Handle UNSPEC_TPOFF and UNSPEC_DTPOFF.
(XTENSA_BUILTIN_THREAD_POINTER): New.
(XTENSA_BUILTIN_SET_THREAD_POINTER): New.
(xtensa_init_builtins): Set NOTHROW and READONLY for umulsidi3 builtin.
Add declarations for __builtin_thread_pointer and
__builtin_set_thread_pointer.
(xtensa_fold_builtin): Recognize new builtins.
(xtensa_expand_builtin): Expand new builtins.
* config/xtensa/xtensa.h (XCHAL_HAVE_THREADPTR): Define default value.
(TARGET_THREADPTR): Define.
(HAVE_AS_TLS): Define default value.
(LEGITIMATE_CONSTANT_P): Disallow TLS references.
* config/xtensa/xtensa.md (UNSPEC_TPOFF, UNSPEC_DTPOFF): New.
(UNSPEC_TLS_FUNC, UNSPEC_TLS_ARG, UNSPEC_TLS_CALL, UNSPEC_TP): New.
(UNSPECV_SET_TP): New.
(sym_TPOFF, sym_DTPOFF): New.
(load_tp, set_tp, tls_func, tls_arg, tls_call): New.
* config/xtensa/xtensa-protos.h (xtensa_tls_referenced_p): Declare.
* configure: Regenerated.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@140482 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config')
-rw-r--r-- | gcc/config/xtensa/predicates.md | 4 | ||||
-rw-r--r-- | gcc/config/xtensa/xtensa-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/xtensa/xtensa.c | 276 | ||||
-rw-r--r-- | gcc/config/xtensa/xtensa.h | 10 | ||||
-rw-r--r-- | gcc/config/xtensa/xtensa.md | 76 |
5 files changed, 338 insertions, 29 deletions
diff --git a/gcc/config/xtensa/predicates.md b/gcc/config/xtensa/predicates.md index c96f63730c4..2cb2a7d1757 100644 --- a/gcc/config/xtensa/predicates.md +++ b/gcc/config/xtensa/predicates.md @@ -166,3 +166,7 @@ (define_predicate "boolean_operator" (match_code "eq,ne")) + +(define_predicate "tls_symbol_operand" + (and (match_code "symbol_ref") + (match_test "SYMBOL_REF_TLS_MODEL (op) != 0"))) diff --git a/gcc/config/xtensa/xtensa-protos.h b/gcc/config/xtensa/xtensa-protos.h index 7ecde9baf21..0447fae0a2e 100644 --- a/gcc/config/xtensa/xtensa-protos.h +++ b/gcc/config/xtensa/xtensa-protos.h @@ -56,6 +56,7 @@ extern char *xtensa_emit_movcc (bool, bool, bool, rtx *); extern char *xtensa_emit_call (int, rtx *); extern bool xtensa_legitimate_address_p (enum machine_mode, rtx, bool); extern rtx xtensa_legitimize_address (rtx, rtx, enum machine_mode); +extern bool xtensa_tls_referenced_p (rtx); #ifdef TREE_CODE extern void init_cumulative_args (CUMULATIVE_ARGS *, int); diff --git a/gcc/config/xtensa/xtensa.c b/gcc/config/xtensa/xtensa.c index 1af9cbab450..4e7edef75a2 100644 --- a/gcc/config/xtensa/xtensa.c +++ b/gcc/config/xtensa/xtensa.c @@ -131,6 +131,7 @@ static rtx gen_float_relational (enum rtx_code, rtx, rtx); static rtx gen_conditional_move (rtx); static rtx fixup_subreg_mem (rtx); static struct machine_function * xtensa_init_machine_status (void); +static rtx xtensa_legitimize_tls_address (rtx); static bool xtensa_return_in_msb (const_tree); static void printx (FILE *, signed int); static void xtensa_function_epilogue (FILE *, HOST_WIDE_INT); @@ -219,6 +220,12 @@ static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] = #undef TARGET_SECONDARY_RELOAD #define TARGET_SECONDARY_RELOAD xtensa_secondary_reload +#undef TARGET_HAVE_TLS +#define TARGET_HAVE_TLS (TARGET_THREADPTR && HAVE_AS_TLS) + +#undef TARGET_CANNOT_FORCE_CONST_MEM +#define TARGET_CANNOT_FORCE_CONST_MEM xtensa_tls_referenced_p + struct gcc_target targetm = TARGET_INITIALIZER; @@ -469,6 +476,18 @@ constantpool_mem_p (rtx op) } +/* Return TRUE if X is a thread-local symbol. */ + +static bool +xtensa_tls_symbol_p (rtx x) +{ + if (! TARGET_HAVE_TLS) + return false; + + return GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) != 0; +} + + void xtensa_extend_reg (rtx dst, rtx src) { @@ -910,12 +929,38 @@ xtensa_split_operand_pair (rtx operands[4], enum machine_mode mode) int xtensa_emit_move_sequence (rtx *operands, enum machine_mode mode) { - if (CONSTANT_P (operands[1]) - && (GET_CODE (operands[1]) != CONST_INT - || !xtensa_simm12b (INTVAL (operands[1])))) + rtx src = operands[1]; + + if (CONSTANT_P (src) + && (GET_CODE (src) != CONST_INT || ! xtensa_simm12b (INTVAL (src)))) { - if (!TARGET_CONST16) - operands[1] = force_const_mem (SImode, operands[1]); + rtx dst = operands[0]; + + if (xtensa_tls_referenced_p (src)) + { + rtx addend = NULL; + + if (GET_CODE (src) == CONST && GET_CODE (XEXP (src, 0)) == PLUS) + { + addend = XEXP (XEXP (src, 0), 1); + src = XEXP (XEXP (src, 0), 0); + } + + src = xtensa_legitimize_tls_address (src); + if (addend) + { + src = gen_rtx_PLUS (mode, src, addend); + src = force_operand (src, dst); + } + emit_move_insn (dst, src); + return 1; + } + + if (! TARGET_CONST16) + { + src = force_const_mem (SImode, src); + operands[1] = src; + } /* PC-relative loads are always SImode, and CONST16 is only supported in the movsi pattern, so add a SUBREG for any other @@ -923,16 +968,16 @@ xtensa_emit_move_sequence (rtx *operands, enum machine_mode mode) if (mode != SImode) { - if (register_operand (operands[0], mode)) + if (register_operand (dst, mode)) { - operands[0] = simplify_gen_subreg (SImode, operands[0], mode, 0); - emit_move_insn (operands[0], operands[1]); + emit_move_insn (simplify_gen_subreg (SImode, dst, mode, 0), src); return 1; } else { - operands[1] = force_reg (SImode, operands[1]); - operands[1] = gen_lowpart_SUBREG (mode, operands[1]); + src = force_reg (SImode, src); + src = gen_lowpart_SUBREG (mode, src); + operands[1] = src; } } } @@ -1664,7 +1709,8 @@ xtensa_legitimate_address_p (enum machine_mode mode, rtx addr, bool strict) { /* Allow constant pool addresses. */ if (mode != BLKmode && GET_MODE_SIZE (mode) >= UNITS_PER_WORD - && ! TARGET_CONST16 && constantpool_address_p (addr)) + && ! TARGET_CONST16 && constantpool_address_p (addr) + && ! xtensa_tls_referenced_p (addr)) return true; while (GET_CODE (addr) == SUBREG) @@ -1709,11 +1755,97 @@ xtensa_legitimate_address_p (enum machine_mode mode, rtx addr, bool strict) } +/* Construct the SYMBOL_REF for the _TLS_MODULE_BASE_ symbol. */ + +static GTY(()) rtx xtensa_tls_module_base_symbol; + +static rtx +xtensa_tls_module_base (void) +{ + if (! xtensa_tls_module_base_symbol) + { + xtensa_tls_module_base_symbol = + gen_rtx_SYMBOL_REF (Pmode, "_TLS_MODULE_BASE_"); + SYMBOL_REF_FLAGS (xtensa_tls_module_base_symbol) + |= TLS_MODEL_GLOBAL_DYNAMIC << SYMBOL_FLAG_TLS_SHIFT; + } + + return xtensa_tls_module_base_symbol; +} + + +static rtx +xtensa_call_tls_desc (rtx sym, rtx *retp) +{ + rtx fn, arg, a10, call_insn, insns; + + start_sequence (); + fn = gen_reg_rtx (Pmode); + arg = gen_reg_rtx (Pmode); + a10 = gen_rtx_REG (Pmode, 10); + + emit_insn (gen_tls_func (fn, sym)); + emit_insn (gen_tls_arg (arg, sym)); + emit_move_insn (a10, arg); + call_insn = emit_call_insn (gen_tls_call (a10, fn, sym, const1_rtx)); + CALL_INSN_FUNCTION_USAGE (call_insn) + = gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_USE (VOIDmode, a10), + CALL_INSN_FUNCTION_USAGE (call_insn)); + insns = get_insns (); + end_sequence (); + + *retp = a10; + return insns; +} + + +static rtx +xtensa_legitimize_tls_address (rtx x) +{ + unsigned int model = SYMBOL_REF_TLS_MODEL (x); + rtx dest, tp, ret, modbase, base, addend, insns; + + dest = gen_reg_rtx (Pmode); + switch (model) + { + case TLS_MODEL_GLOBAL_DYNAMIC: + insns = xtensa_call_tls_desc (x, &ret); + emit_libcall_block (insns, dest, ret, x); + break; + + case TLS_MODEL_LOCAL_DYNAMIC: + base = gen_reg_rtx (Pmode); + modbase = xtensa_tls_module_base (); + insns = xtensa_call_tls_desc (modbase, &ret); + emit_libcall_block (insns, base, ret, modbase); + addend = force_reg (SImode, gen_sym_DTPOFF (x)); + emit_insn (gen_addsi3 (dest, base, addend)); + break; + + case TLS_MODEL_INITIAL_EXEC: + case TLS_MODEL_LOCAL_EXEC: + tp = gen_reg_rtx (SImode); + emit_insn (gen_load_tp (tp)); + addend = force_reg (SImode, gen_sym_TPOFF (x)); + emit_insn (gen_addsi3 (dest, tp, addend)); + break; + + default: + gcc_unreachable (); + } + + return dest; +} + + rtx xtensa_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode) { + if (xtensa_tls_symbol_p (x)) + return xtensa_legitimize_tls_address (x); + if (GET_CODE (x) == PLUS) { rtx plus0 = XEXP (x, 0); @@ -1745,6 +1877,46 @@ xtensa_legitimize_address (rtx x, } +/* Helper for xtensa_tls_referenced_p. */ + +static int +xtensa_tls_referenced_p_1 (rtx *x, void *data ATTRIBUTE_UNUSED) +{ + if (GET_CODE (*x) == SYMBOL_REF) + return SYMBOL_REF_TLS_MODEL (*x) != 0; + + /* Ignore TLS references that have already been legitimized. */ + if (GET_CODE (*x) == UNSPEC) + { + switch (XINT (*x, 1)) + { + case UNSPEC_TPOFF: + case UNSPEC_DTPOFF: + case UNSPEC_TLS_FUNC: + case UNSPEC_TLS_ARG: + case UNSPEC_TLS_CALL: + return -1; + default: + break; + } + } + + return 0; +} + + +/* Return TRUE if X contains any TLS symbol references. */ + +bool +xtensa_tls_referenced_p (rtx x) +{ + if (! TARGET_HAVE_TLS) + return false; + + return for_each_rtx (&x, xtensa_tls_referenced_p_1, NULL); +} + + /* Return the debugger register number to use for 'regno'. */ int @@ -2204,6 +2376,14 @@ xtensa_output_addr_const_extra (FILE *fp, rtx x) { switch (XINT (x, 1)) { + case UNSPEC_TPOFF: + output_addr_const (fp, XVECEXP (x, 0, 0)); + fputs ("@TPOFF", fp); + return true; + case UNSPEC_DTPOFF: + output_addr_const (fp, XVECEXP (x, 0, 0)); + fputs ("@DTPOFF", fp); + return true; case UNSPEC_PLT: if (flag_pic) { @@ -2760,6 +2940,8 @@ xtensa_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, enum xtensa_builtin { XTENSA_BUILTIN_UMULSIDI3, + XTENSA_BUILTIN_THREAD_POINTER, + XTENSA_BUILTIN_SET_THREAD_POINTER, XTENSA_BUILTIN_max }; @@ -2767,15 +2949,34 @@ enum xtensa_builtin static void xtensa_init_builtins (void) { - tree ftype; + tree ftype, decl; ftype = build_function_type_list (unsigned_intDI_type_node, unsigned_intSI_type_node, unsigned_intSI_type_node, NULL_TREE); - add_builtin_function ("__builtin_umulsidi3", ftype, - XTENSA_BUILTIN_UMULSIDI3, BUILT_IN_MD, - "__umulsidi3", NULL_TREE); + decl = add_builtin_function ("__builtin_umulsidi3", ftype, + XTENSA_BUILTIN_UMULSIDI3, BUILT_IN_MD, + "__umulsidi3", NULL_TREE); + TREE_NOTHROW (decl) = 1; + TREE_READONLY (decl) = 1; + + if (TARGET_THREADPTR) + { + ftype = build_function_type (ptr_type_node, void_list_node); + decl = add_builtin_function ("__builtin_thread_pointer", ftype, + XTENSA_BUILTIN_THREAD_POINTER, BUILT_IN_MD, + NULL, NULL_TREE); + TREE_READONLY (decl) = 1; + TREE_NOTHROW (decl) = 1; + + ftype = build_function_type_list (void_type_node, ptr_type_node, + NULL_TREE); + decl = add_builtin_function ("__builtin_set_thread_pointer", ftype, + XTENSA_BUILTIN_SET_THREAD_POINTER, + BUILT_IN_MD, NULL, NULL_TREE); + TREE_NOTHROW (decl) = 1; + } } @@ -2785,8 +2986,9 @@ xtensa_fold_builtin (tree fndecl, tree arglist, bool ignore ATTRIBUTE_UNUSED) unsigned int fcode = DECL_FUNCTION_CODE (fndecl); tree arg0, arg1; - if (fcode == XTENSA_BUILTIN_UMULSIDI3) + switch (fcode) { + case XTENSA_BUILTIN_UMULSIDI3: arg0 = TREE_VALUE (arglist); arg1 = TREE_VALUE (TREE_CHAIN (arglist)); if ((TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST) @@ -2794,11 +2996,17 @@ xtensa_fold_builtin (tree fndecl, tree arglist, bool ignore ATTRIBUTE_UNUSED) return fold_build2 (MULT_EXPR, unsigned_intDI_type_node, fold_convert (unsigned_intDI_type_node, arg0), fold_convert (unsigned_intDI_type_node, arg1)); - else - return NULL; + break; + + case XTENSA_BUILTIN_THREAD_POINTER: + case XTENSA_BUILTIN_SET_THREAD_POINTER: + break; + + default: + internal_error ("bad builtin code"); + break; } - internal_error ("bad builtin code"); return NULL; } @@ -2811,14 +3019,32 @@ xtensa_expand_builtin (tree exp, rtx target, { tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); unsigned int fcode = DECL_FUNCTION_CODE (fndecl); + rtx arg; + + switch (fcode) + { + case XTENSA_BUILTIN_UMULSIDI3: + /* The umulsidi3 builtin is just a mechanism to avoid calling the real + __umulsidi3 function when the Xtensa configuration can directly + implement it. If not, just call the function. */ + return expand_call (exp, target, ignore); - /* The umulsidi3 builtin is just a mechanism to avoid calling the real - __umulsidi3 function when the Xtensa configuration can directly - implement it. If not, just call the function. */ - if (fcode == XTENSA_BUILTIN_UMULSIDI3) - return expand_call (exp, target, ignore); + case XTENSA_BUILTIN_THREAD_POINTER: + if (!target || !register_operand (target, Pmode)) + target = gen_reg_rtx (Pmode); + emit_insn (gen_load_tp (target)); + return target; - internal_error ("bad builtin code"); + case XTENSA_BUILTIN_SET_THREAD_POINTER: + arg = expand_normal (CALL_EXPR_ARG (exp, 0)); + if (!register_operand (arg, Pmode)) + arg = copy_to_mode_reg (Pmode, arg); + emit_insn (gen_set_tp (arg)); + return const0_rtx; + + default: + internal_error ("bad builtin code"); + } return NULL_RTX; } diff --git a/gcc/config/xtensa/xtensa.h b/gcc/config/xtensa/xtensa.h index ab3b648ffa4..1427fd0e3da 100644 --- a/gcc/config/xtensa/xtensa.h +++ b/gcc/config/xtensa/xtensa.h @@ -51,6 +51,9 @@ extern unsigned xtensa_current_frame_size; #ifndef XCHAL_HAVE_S32C1I #define XCHAL_HAVE_S32C1I 0 #endif +#ifndef XCHAL_HAVE_THREADPTR +#define XCHAL_HAVE_THREADPTR 0 +#endif #define TARGET_BIG_ENDIAN XCHAL_HAVE_BE #define TARGET_DENSITY XCHAL_HAVE_DENSITY #define TARGET_MAC16 XCHAL_HAVE_MAC16 @@ -72,11 +75,16 @@ extern unsigned xtensa_current_frame_size; #define TARGET_RELEASE_SYNC XCHAL_HAVE_RELEASE_SYNC #define TARGET_S32C1I XCHAL_HAVE_S32C1I #define TARGET_ABSOLUTE_LITERALS XSHAL_USE_ABSOLUTE_LITERALS +#define TARGET_THREADPTR XCHAL_HAVE_THREADPTR #define TARGET_DEFAULT \ ((XCHAL_HAVE_L32R ? 0 : MASK_CONST16) | \ MASK_SERIALIZE_VOLATILE) +#ifndef HAVE_AS_TLS +#define HAVE_AS_TLS 0 +#endif + #define OVERRIDE_OPTIONS override_options () /* Reordering blocks for Xtensa is not a good idea unless the compiler @@ -791,7 +799,7 @@ typedef struct xtensa_args /* Nonzero if the constant value X is a legitimate general operand. It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ -#define LEGITIMATE_CONSTANT_P(X) 1 +#define LEGITIMATE_CONSTANT_P(X) (! xtensa_tls_referenced_p (X)) /* A C expression that is nonzero if X is a legitimate immediate operand on the target machine when generating position independent diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md index 4f831d3f22c..29119ed16bb 100644 --- a/gcc/config/xtensa/xtensa.md +++ b/gcc/config/xtensa/xtensa.md @@ -29,6 +29,12 @@ (UNSPEC_NOP 2) (UNSPEC_PLT 3) (UNSPEC_RET_ADDR 4) + (UNSPEC_TPOFF 5) + (UNSPEC_DTPOFF 6) + (UNSPEC_TLS_FUNC 7) + (UNSPEC_TLS_ARG 8) + (UNSPEC_TLS_CALL 9) + (UNSPEC_TP 10) (UNSPECV_SET_FP 1) (UNSPECV_ENTRY 2) @@ -36,6 +42,7 @@ (UNSPECV_S32RI 4) (UNSPECV_S32C1I 5) (UNSPECV_EH_RETURN 6) + (UNSPECV_SET_TP 7) ]) ;; This code iterator allows signed and unsigned widening multiplications @@ -1560,9 +1567,9 @@ }) (define_insn "call_value_internal" - [(set (match_operand 0 "register_operand" "=a") - (call (mem (match_operand:SI 1 "call_insn_operand" "nir")) - (match_operand 2 "" "i")))] + [(set (match_operand 0 "register_operand" "=a") + (call (mem (match_operand:SI 1 "call_insn_operand" "nir")) + (match_operand 2 "" "i")))] "" { return xtensa_emit_call (1, operands); @@ -1698,6 +1705,69 @@ (set_attr "length" "0")]) +;; TLS support + +(define_expand "sym_TPOFF" + [(const (unspec [(match_operand:SI 0 "" "")] UNSPEC_TPOFF))] + "" + "") + +(define_expand "sym_DTPOFF" + [(const (unspec [(match_operand:SI 0 "" "")] UNSPEC_DTPOFF))] + "" + "") + +(define_insn "load_tp" + [(set (match_operand:SI 0 "register_operand" "=a") + (unspec:SI [(const_int 0)] UNSPEC_TP))] + "TARGET_THREADPTR" + "rur\t%0, THREADPTR" + [(set_attr "type" "rsr") + (set_attr "mode" "SI") + (set_attr "length" "3")]) + +(define_insn "set_tp" + [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")] + UNSPECV_SET_TP)] + "TARGET_THREADPTR" + "wur\t%0, THREADPTR" + [(set_attr "type" "wsr") + (set_attr "mode" "SI") + (set_attr "length" "3")]) + +(define_insn "tls_func" + [(set (match_operand:SI 0 "register_operand" "=a") + (unspec:SI [(match_operand:SI 1 "tls_symbol_operand" "")] + UNSPEC_TLS_FUNC))] + "TARGET_THREADPTR && HAVE_AS_TLS" + "movi\t%0, %1@TLSFUNC" + [(set_attr "type" "load") + (set_attr "mode" "SI") + (set_attr "length" "3")]) + +(define_insn "tls_arg" + [(set (match_operand:SI 0 "register_operand" "=a") + (unspec:SI [(match_operand:SI 1 "tls_symbol_operand" "")] + UNSPEC_TLS_ARG))] + "TARGET_THREADPTR && HAVE_AS_TLS" + "movi\t%0, %1@TLSARG" + [(set_attr "type" "load") + (set_attr "mode" "SI") + (set_attr "length" "3")]) + +(define_insn "tls_call" + [(set (match_operand:SI 0 "register_operand" "=a") + (call (mem:SI (unspec:SI [(match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "tls_symbol_operand" "")] + UNSPEC_TLS_CALL)) + (match_operand 3 "" "i")))] + "TARGET_THREADPTR && HAVE_AS_TLS" + "callx8.tls %1, %2@TLSCALL" + [(set_attr "type" "call") + (set_attr "mode" "none") + (set_attr "length" "3")]) + + ;; Instructions for the Xtensa "boolean" option. (define_insn "*booltrue" |