Hi,
With ILP32, some simple usage of TLS variables causes an unrecognizable
instruction due to needing to use SImode for loading pointers from memory.
This fixes the three (tlsie_small, tlsle_small, tlsdesc_small) patterns to
support SImode for pointers.
OK? Build and tested on aarch64-elf with no regressions.
Thanks,
Andrew Pinski
* config/aarch64/aarch64.c (aarch64_load_symref_appropriately):
Handle TLS for ILP32.
* config/aarch64/aarch64.md (tlsie_small): Change to an expand to
handle ILP32.
(tlsie_small_<mode>): New pattern.
(tlsle_small): Change to an expand to handle ILP32.
(tlsle_small_<mode>): New pattern.
(tlsdesc_small): Change to an expand to handle ILP32.
(tlsdesc_small_<mode>): New pattern.
---
gcc/ChangeLog | 12 ++++++
gcc/config/aarch64/aarch64.c | 23 ++++++++++--
gcc/config/aarch64/aarch64.md | 76 ++++++++++++++++++++++++++++++++++-------
3 files changed, 94 insertions(+), 17 deletions(-)
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index b1b4eef..a3e4532 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -628,22 +628,37 @@ aarch64_load_symref_appropriately (rtx dest, rtx imm,
case SYMBOL_SMALL_TLSDESC:
{
- rtx x0 = gen_rtx_REG (Pmode, R0_REGNUM);
+ enum machine_mode mode = GET_MODE (dest);
+ rtx x0 = gen_rtx_REG (mode, R0_REGNUM);
rtx tp;
+ gcc_assert (mode == Pmode || mode == ptr_mode);
+
emit_insn (gen_tlsdesc_small (imm));
tp = aarch64_load_tp (NULL);
- emit_insn (gen_rtx_SET (Pmode, dest, gen_rtx_PLUS (Pmode, tp, x0)));
+
+ if (mode != Pmode)
+ tp = gen_lowpart (mode, tp);
+
+ emit_insn (gen_rtx_SET (mode, dest, gen_rtx_PLUS (mode, tp, x0)));
set_unique_reg_note (get_last_insn (), REG_EQUIV, imm);
return;
}
case SYMBOL_SMALL_GOTTPREL:
{
- rtx tmp_reg = gen_reg_rtx (Pmode);
+ enum machine_mode mode = GET_MODE (dest);
+ rtx tmp_reg = gen_reg_rtx (mode);
rtx tp = aarch64_load_tp (NULL);
+
+ gcc_assert (mode == Pmode || mode == ptr_mode);
+
emit_insn (gen_tlsie_small (tmp_reg, imm));
- emit_insn (gen_rtx_SET (Pmode, dest, gen_rtx_PLUS (Pmode, tp, tmp_reg)));
+
+ if (mode != Pmode)
+ tp = gen_lowpart (mode, tp);
+
+ emit_insn (gen_rtx_SET (mode, dest, gen_rtx_PLUS (mode, tp, tmp_reg)));
set_unique_reg_note (get_last_insn (), REG_EQUIV, imm);
return;
}
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 313517f..08fcc94 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -3577,35 +3577,85 @@
[(set_attr "type" "call")
(set_attr "length" "16")])
-(define_insn "tlsie_small"
- [(set (match_operand:DI 0 "register_operand" "=r")
- (unspec:DI [(match_operand:DI 1 "aarch64_tls_ie_symref" "S")]
+(define_expand "tlsie_small"
+ [(set (match_operand 0 "register_operand" "=r")
+ (unspec [(match_operand 1 "aarch64_tls_ie_symref" "S")]
+ UNSPEC_GOTSMALLTLS))]
+ ""
+{
+ if (TARGET_ILP32)
+ {
+ operands[0] = gen_lowpart (ptr_mode, operands[0]);
+ emit_insn (gen_tlsie_small_si (operands[0], operands[1]));
+ }
+ else
+ emit_insn (gen_tlsie_small_di (operands[0], operands[1]));
+ DONE;
+})
+
+(define_insn "tlsie_small_<mode>"
+ [(set (match_operand:PTR 0 "register_operand" "=r")
+ (unspec:PTR [(match_operand 1 "aarch64_tls_ie_symref" "S")]
UNSPEC_GOTSMALLTLS))]
""
- "adrp\\t%0, %A1\;ldr\\t%0, [%0, #%L1]"
+ "adrp\\t%0, %A1\;ldr\\t%<w>0, [%0, #%L1]"
[(set_attr "type" "load1")
(set_attr "length" "8")]
)
-(define_insn "tlsle_small"
- [(set (match_operand:DI 0 "register_operand" "=r")
- (unspec:DI [(match_operand:DI 1 "register_operand" "r")
- (match_operand:DI 2 "aarch64_tls_le_symref" "S")]
+
+(define_expand "tlsle_small"
+ [(set (match_operand 0 "register_operand" "=r")
+ (unspec [(match_operand 1 "register_operand" "r")
+ (match_operand 2 "aarch64_tls_le_symref" "S")]
+ UNSPEC_GOTSMALLTLS))]
+ ""
+{
+ if (TARGET_ILP32)
+ {
+ rtx temp = gen_reg_rtx (ptr_mode);
+ operands[1] = gen_lowpart (ptr_mode, operands[1]);
+ emit_insn (gen_tlsle_small_si (temp, operands[1], operands[2]));
+ emit_move_insn (operands[0], gen_lowpart (GET_MODE (operands[0]), temp));
+ }