static GTY(()) rtx ix86_tls_index_symbol;
-#if TARGET_WIN32_TLS
static rtx
ix86_tls_index (void)
{
ix86_tls_index_symbol = gen_rtx_SYMBOL_REF (SImode, "_tls_index");
if (flag_pic)
- return gen_rtx_CONST (Pmode, gen_rtx_UNSPEC (Pmode, gen_rtvec (1, ix86_tls_index_symbol), UNSPEC_PCREL));
+ return gen_rtx_CONST (Pmode,
+ gen_rtx_UNSPEC (Pmode,
+ gen_rtvec (1, ix86_tls_index_symbol),
+ UNSPEC_PCREL));
else
return ix86_tls_index_symbol;
}
-#endif
/* Construct the SYMBOL_REF for the tls_get_addr function. */
machine_mode tp_mode = Pmode;
int type;
-#if TARGET_WIN32_TLS
- off = gen_const_mem (SImode, ix86_tls_index ());
- set_mem_alias_set (off, GOT_ALIAS_SET);
-
- tp = gen_const_mem (Pmode, GEN_INT (TARGET_64BIT ? 88 : 44));
- set_mem_addr_space (tp, DEFAULT_TLS_SEG_REG);
-
- if (TARGET_64BIT)
- off = convert_to_mode (Pmode, off, 1);
-
- base = force_reg (Pmode, off);
- tp = copy_to_mode_reg (Pmode, tp);
-
- tp = gen_const_mem (Pmode, gen_rtx_PLUS (Pmode, tp, gen_rtx_MULT (Pmode, base, GEN_INT (UNITS_PER_WORD))));
- set_mem_alias_set (tp, GOT_ALIAS_SET);
-
- base = force_reg (Pmode, tp);
+ /* Windows implements a single form of TLS. */
+ if (TARGET_WIN32_TLS)
+ {
+ /* Load the 32-bit index. */
+ rtx ind = gen_const_mem (SImode, ix86_tls_index ());
+ set_mem_alias_set (ind, GOT_ALIAS_SET);
+ if (TARGET_64BIT)
+ ind = convert_to_mode (Pmode, ind, 1);
+ ind = force_reg (Pmode, ind);
+
+ /* Add it to the thread pointer and load the base. */
+ tp = get_thread_pointer (Pmode, true);
+ rtx addr = gen_rtx_PLUS (Pmode, tp,
+ gen_rtx_MULT (Pmode, ind,
+ GEN_INT (UNITS_PER_WORD)));
+ base = gen_const_mem (Pmode, addr);
+ set_mem_alias_set (base, GOT_ALIAS_SET);
+
+ /* Add the 32-bit section-relative offset to the base. */
+ base = force_reg (Pmode, base);
+ off = gen_rtx_CONST (Pmode,
+ gen_rtx_UNSPEC (SImode,
+ gen_rtvec (1, x),
+ UNSPEC_SECREL32));
+ return gen_rtx_PLUS (Pmode, base, off);
+ }
- return gen_rtx_PLUS (Pmode, base, gen_rtx_CONST (Pmode, gen_rtx_UNSPEC (SImode, gen_rtvec (1, x), UNSPEC_SECREL32)));
-#else
/* Fall back to global dynamic model if tool chain cannot support local
dynamic. */
if (TARGET_SUN_TLS && !TARGET_64BIT
}
return dest;
-#endif
}
/* Return true if the TLS address requires insn using integer registers.
#define DEFAULT_TLS_SEG_REG \
(TARGET_64BIT ? ADDR_SPACE_SEG_FS : ADDR_SPACE_SEG_GS)
+/* The default TLS segment offset used by target. */
+#define DEFAULT_TLS_SEG_OFFSET 0
+
/* Subtargets may reset this to 1 in order to enable 96-bit long double
with the rounding mode forced to 53 bits. */
#define TARGET_96_ROUND_53_LONG_DOUBLE 0
[(set (match_dup 0)
(match_dup 1))]
{
- addr_space_t as = DEFAULT_TLS_SEG_REG;
-
- operands[1] = gen_const_mem (<MODE>mode, const0_rtx);
- set_mem_addr_space (operands[1], as);
+ operands[1] = gen_const_mem (<MODE>mode, GEN_INT (DEFAULT_TLS_SEG_OFFSET));
+ set_mem_addr_space (operands[1], DEFAULT_TLS_SEG_REG);
})
(define_insn_and_split "*load_tp_x32_zext"
[(set (match_dup 0)
(zero_extend:DI (match_dup 1)))]
{
- addr_space_t as = DEFAULT_TLS_SEG_REG;
-
- operands[1] = gen_const_mem (SImode, const0_rtx);
- set_mem_addr_space (operands[1], as);
+ operands[1] = gen_const_mem (SImode, GEN_INT (DEFAULT_TLS_SEG_OFFSET));
+ set_mem_addr_space (operands[1], DEFAULT_TLS_SEG_REG);
})
(define_insn_and_split "*add_tp_<mode>"
(plus:PTR (match_dup 1) (match_dup 2)))
(clobber (reg:CC FLAGS_REG))])]
{
- addr_space_t as = DEFAULT_TLS_SEG_REG;
-
- operands[2] = gen_const_mem (<MODE>mode, const0_rtx);
- set_mem_addr_space (operands[2], as);
+ operands[2] = gen_const_mem (<MODE>mode, GEN_INT (DEFAULT_TLS_SEG_OFFSET));
+ set_mem_addr_space (operands[2], DEFAULT_TLS_SEG_REG);
})
(define_insn_and_split "*add_tp_x32_zext"
(plus:SI (match_dup 1) (match_dup 2))))
(clobber (reg:CC FLAGS_REG))])]
{
- addr_space_t as = DEFAULT_TLS_SEG_REG;
-
- operands[2] = gen_const_mem (SImode, const0_rtx);
- set_mem_addr_space (operands[2], as);
+ operands[2] = gen_const_mem (SImode, GEN_INT (DEFAULT_TLS_SEG_OFFSET));
+ set_mem_addr_space (operands[2], DEFAULT_TLS_SEG_REG);
})
;; GNU2 TLS patterns can be split.
/* Rule out relocations that translate into 64bit constants. */
if (TARGET_64BIT && GET_CODE (op) == CONST)
{
- op = XEXP (op, 0);
- if (GET_CODE (op) == PLUS && CONST_INT_P (XEXP (op, 1)))
- op = XEXP (op, 0);
- if (GET_CODE (op) == UNSPEC
- && (XINT (op, 1) == UNSPEC_GOTOFF
- || XINT (op, 1) == UNSPEC_GOT))
+ rtx tmp = XEXP (op, 0);
+ if (GET_CODE (tmp) == PLUS && CONST_INT_P (XEXP (tmp, 1)))
+ tmp = XEXP (tmp, 0);
+ if (GET_CODE (tmp) == UNSPEC
+ && (XINT (tmp, 1) == UNSPEC_GOTOFF
+ || XINT (tmp, 1) == UNSPEC_GOT))
return false;
}
|| (GET_CODE (op) == UNSPEC
&& (XINT (op, 1) == UNSPEC_GOT
|| XINT (op, 1) == UNSPEC_GOTOFF
+ || XINT (op, 1) == UNSPEC_SECREL32
|| XINT (op, 1) == UNSPEC_PCREL
|| XINT (op, 1) == UNSPEC_GOTPCREL)))
return true;
if (SYMBOL_REF_P (op)
|| LABEL_REF_P (op))
return true;
- /* Only @GOTOFF gets offsets. */
+ /* Only @GOTOFF and @SECREL32 get offsets. */
if (GET_CODE (op) != UNSPEC
- || XINT (op, 1) != UNSPEC_GOTOFF)
+ || (XINT (op, 1) != UNSPEC_GOTOFF
+ && XINT (op, 1) != UNSPEC_SECREL32))
return false;
op = XVECEXP (op, 0, 0);
{
int nelt = XVECLEN (op, 0);
int elt, i;
-
+
if (nelt < 2)
return false;
#define TARGET_ASM_SELECT_SECTION mingw_pe_select_section
#undef DEFAULT_TLS_SEG_REG
-#define DEFAULT_TLS_SEG_REG (TARGET_64BIT ? ADDR_SPACE_SEG_GS : ADDR_SPACE_SEG_FS)
+#define DEFAULT_TLS_SEG_REG \
+ (TARGET_64BIT ? ADDR_SPACE_SEG_GS : ADDR_SPACE_SEG_FS)
+
+#undef DEFAULT_TLS_SEG_OFFSET
+#define DEFAULT_TLS_SEG_OFFSET (TARGET_64BIT ? 88 : 44)
#define HAVE_ENABLE_EXECUTE_STACK
#undef CHECK_EXECUTE_STACK_ENABLED
--- /dev/null
+/* { dg-do assemble } */
+/* { dg-require-effective-target tls } */
+/* { dg-add-options tls } */
+
+struct pixel
+{
+ unsigned int r, g, b;
+};
+
+struct line
+{
+ unsigned int length;
+ struct pixel data[16];
+};
+
+__thread struct line L;
+
+unsigned int read_r (unsigned int i)
+{
+ return i < L.length ? L.data[i].r : 0;
+}