@@ -595,6 +595,7 @@ ix86_target_macros (void)
cpp_define (parse_in, "__SEG_FS");
cpp_define (parse_in, "__SEG_GS");
+ cpp_define (parse_in, "__SEG_TLS");
}
@@ -611,6 +612,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 ();
@@ -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;
@@ -17296,6 +17296,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)
@@ -53629,8 +53631,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