{
machine_mode mode = GET_MODE (dest);
rtx x0 = gen_rtx_REG (mode, R0_REGNUM);
+ rtx offset;
rtx tp;
gcc_assert (mode == Pmode || mode == ptr_mode);
- /* In ILP32, the got entry is always of SImode size. Unlike
- small GOT, the dest is fixed at reg 0. */
- if (TARGET_ILP32)
- emit_insn (gen_tlsdesc_small_si (imm));
+ if (can_create_pseudo_p ())
+ {
+ rtx reg = gen_reg_rtx (mode);
+
+ if (TARGET_ILP32)
+ emit_insn (gen_tlsdesc_small_pseudo_si (reg, imm));
+ else
+ emit_insn (gen_tlsdesc_small_pseudo_di (reg, imm));
+
+ offset = reg;
+ }
else
- emit_insn (gen_tlsdesc_small_di (imm));
+ {
+ /* In ILP32, the got entry is always of SImode size. Unlike
+ small GOT, the dest is fixed at reg 0. */
+ if (TARGET_ILP32)
+ emit_insn (gen_tlsdesc_small_si (imm));
+ else
+ emit_insn (gen_tlsdesc_small_di (imm));
+
+ offset = x0;
+ }
tp = aarch64_load_tp (NULL);
if (mode != Pmode)
tp = gen_lowpart (mode, tp);
- emit_insn (gen_rtx_SET (dest, gen_rtx_PLUS (mode, tp, x0)));
+ emit_insn (gen_rtx_SET (dest, gen_rtx_PLUS (mode, tp, offset)));
set_unique_reg_note (get_last_insn (), REG_EQUIV, imm);
return;
}
aarch64_vector_mode_p (mode)
? (GET_MODE_SIZE (mode) + UNITS_PER_VREG - 1) / UNITS_PER_VREG
: (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+ case FIXED_REG0:
case STACK_REG:
return 1;
= aarch64_tune_params.regmove_cost;
/* Caller save and pointer regs are equivalent to GENERAL_REGS. */
- if (to == CALLER_SAVE_REGS || to == POINTER_REGS)
+ if (to == CALLER_SAVE_REGS || to == POINTER_REGS || to == FIXED_REG0)
to = GENERAL_REGS;
- if (from == CALLER_SAVE_REGS || from == POINTER_REGS)
+ if (from == CALLER_SAVE_REGS || from == POINTER_REGS || from == FIXED_REG0)
from = GENERAL_REGS;
/* Moving between GPR and stack cost is the same as GP2GP. */
enum reg_class
{
NO_REGS,
+ FIXED_REG0,
CALLER_SAVE_REGS,
GENERAL_REGS,
STACK_REG,
#define REG_CLASS_NAMES \
{ \
"NO_REGS", \
+ "FIXED_REG0" \
"CALLER_SAVE_REGS", \
"GENERAL_REGS", \
"STACK_REG", \
#define REG_CLASS_CONTENTS \
{ \
{ 0x00000000, 0x00000000, 0x00000000 }, /* NO_REGS */ \
+ { 0x00000001, 0x00000000, 0x00000000 }, /* FIXED_REG0 */ \
{ 0x0007ffff, 0x00000000, 0x00000000 }, /* CALLER_SAVE_REGS */ \
{ 0x7fffffff, 0x00000000, 0x00000003 }, /* GENERAL_REGS */ \
{ 0x80000000, 0x00000000, 0x00000000 }, /* STACK_REG */ \
[(set_attr "type" "call")
(set_attr "length" "16")])
+;; The same as tlsdesc_small_<mode> with hard register hiding.
+;; The first operand is actually x0, while we wrap it under a delicated
+;; register class so that before register allocation, it's seen as pseudo
+;; register. The reason for doing this is we don't expose hard register X0
+;; as the destination of set as it will cause trouble for RTL loop iv.
+;; RTL loop iv will abort ongoing optimization once it finds there is hard reg
+;; as destination of set.
+(define_insn "tlsdesc_small_pseudo_<mode>"
+ [(set (match_operand:PTR 0 "register_operand" "=Uc0")
+ (unspec:PTR [(match_operand 1 "aarch64_valid_symref" "S")]
+ UNSPEC_TLSDESC))
+ (clobber (reg:DI LR_REGNUM))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (match_scratch:DI 2 "=r"))]
+ "TARGET_TLS_DESC"
+ "adrp\\t<w>0, %A1\;ldr\\t%<w>2, [%<w>0, #%L1]\;add\\t%<w>0, %<w>0, %L1\;.tlsdesccall\\t%1\;blr\\t%2"
+ [(set_attr "type" "call")
+ (set_attr "length" "16")])
+
(define_insn "stack_tie"
[(set (mem:BLK (scratch))
(unspec:BLK [(match_operand:DI 0 "register_operand" "rk")
(define_register_constraint "Ucs" "CALLER_SAVE_REGS"
"@internal The caller save registers.")
+(define_register_constraint "Uc0" "FIXED_REG0"
+ "@internal Represent X0/W0.")
+
(define_register_constraint "w" "FP_REGS"
"Floating point and SIMD vector registers.")
--- /dev/null
+/* { dg-do compile } */
+/* { dg-require-effective-target tls_native } */
+/* { dg-options "-O2 -fpic -fdump-rtl-loop2_invariant" } */
+/* { dg-skip-if "-mcmodel=large, no support for -fpic" { aarch64-*-* } { "-mcmodel=large" } { "" } } */
+
+int cal (int, int);
+__thread int tls_data;
+
+int
+foo (int bound)
+{
+ int i = 0;
+ int sum = 0;
+
+ for (i; i < bound; i++)
+ sum = cal (sum, tls_data);
+
+ return sum;
+}
+
+/* Insn sequences for TLS descriptor should be hoisted out of the loop. */
+/* { dg-final { scan-rtl-dump "Decided" "loop2_invariant" } } */