--- gcc/config/i386/i386-c.c | 2 ++ gcc/config/i386/i386-protos.h | 1 + gcc/config/i386/i386.c | 39 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 1 deletion(-)
diff --git a/gcc/config/i386/i386-c.c b/gcc/config/i386/i386-c.c index 3f28f6c..e3a3012 100644 --- a/gcc/config/i386/i386-c.c +++ b/gcc/config/i386/i386-c.c @@ -589,6 +589,7 @@ ix86_target_macros (void) cpp_define (parse_in, "__SEG_FS"); cpp_define (parse_in, "__SEG_GS"); + cpp_define (parse_in, "__SEG_TLS"); } @@ -605,6 +606,7 @@ ix86_register_pragmas (void) c_register_addr_space ("__seg_fs", ADDR_SPACE_SEG_FS); c_register_addr_space ("__seg_gs", ADDR_SPACE_SEG_GS); + c_register_addr_space ("__seg_tls", ADDR_SPACE_SEG_TLS); #ifdef REGISTER_SUBTARGET_PRAGMAS REGISTER_SUBTARGET_PRAGMAS (); diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index 4e6d9ad..026b778 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -328,3 +328,4 @@ struct ix86_first_cycle_multipass_data_ const addr_space_t ADDR_SPACE_SEG_FS = 1; const addr_space_t ADDR_SPACE_SEG_GS = 2; +const addr_space_t ADDR_SPACE_SEG_TLS = 3; diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 7647090..ec19a57 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -17329,6 +17329,8 @@ ix86_print_operand_address_as (FILE *file, rtx addr, addr_space_t as) { const char *string; + if (as == ADDR_SPACE_SEG_TLS) + as = DEFAULT_TLS_SEG_REG; if (as == ADDR_SPACE_SEG_FS) string = (ASSEMBLER_DIALECT == ASM_ATT ? "%fs:" : "fs:"); else if (as == ADDR_SPACE_SEG_GS) @@ -53667,8 +53669,43 @@ ix86_operands_ok_for_move_multiple (rtx *operands, bool load, without resorting to a system call, we cannot convert a non-default address space to a default address space. Therefore we do not claim %fs or %gs are subsets of generic. + (e) However, __seg_tls uses UNSPEC_TP as the base (which itself is + stored at __seg_tls:0) so we can map between tls and generic. */ - Therefore, we need not override any of the address space hooks. */ +static bool +ix86_addr_space_subset_p (addr_space_t subset, addr_space_t superset) +{ + return (subset == superset + || (superset == ADDR_SPACE_GENERIC + && subset == ADDR_SPACE_SEG_TLS)); +} +#undef TARGET_ADDR_SPACE_SUBSET_P +#define TARGET_ADDR_SPACE_SUBSET_P ix86_addr_space_subset_p + +static rtx +ix86_addr_space_convert (rtx op, tree from_type, tree to_type) +{ + addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (from_type)); + addr_space_t to_as = TYPE_ADDR_SPACE (TREE_TYPE (to_type)); + + /* Conversion between SEG_TLS and GENERIC is handled by adding or + subtracting the thread pointer. */ + if ((from_as == ADDR_SPACE_GENERIC && to_as == ADDR_SPACE_SEG_TLS) + || (from_as == ADDR_SPACE_SEG_TLS && to_as == ADDR_SPACE_GENERIC)) + { + machine_mode mode = GET_MODE (op); + if (mode == VOIDmode) + mode = ptr_mode; + rtx tp = get_thread_pointer (mode, optimize || mode != ptr_mode); + return expand_binop (mode, (to_as == ADDR_SPACE_GENERIC + ? add_optab : sub_optab), + op, tp, NULL, 1, OPTAB_WIDEN); + } + + return op; +} +#undef TARGET_ADDR_SPACE_CONVERT +#define TARGET_ADDR_SPACE_CONVERT ix86_addr_space_convert /* Initialize the GCC target structure. */ #undef TARGET_RETURN_IN_MEMORY -- 2.4.3