RISC-V: Implement TLS Descriptors.
Checks
Commit Message
This implements TLS Descriptors (TLSDESC) as specified in [1].
In TLSDESC instruction sequence, the first instruction relocates against
the target TLS variable, while subsequent instructions relocates against
the address of the first. Such usage of labels are not well-supported
within GCC. Due to this, the 4-instruction sequence is implemented as a
single RTX insn.
For now, keep defaulting to the traditional TLS model, but this can be
revisited once toolchain and libc support ships.
[1]: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/373
---
No regression in binutils and gcc tests for rv64gc, tested alongside the
binutils and glibc implementation (posted at the same time). During
testing, the default TLS dialect was changed to TLSDESC.
This contribution is made on behalf of Blue Whale Systems, which has
copyright assignment on file with the FSF.
gcc/config/riscv/riscv-opts.h | 6 ++++++
gcc/config/riscv/riscv-protos.h | 5 +++--
gcc/config/riscv/riscv.cc | 34 +++++++++++++++++++++++++++++----
gcc/config/riscv/riscv.h | 3 +++
gcc/config/riscv/riscv.md | 22 ++++++++++++++++++++-
gcc/config/riscv/riscv.opt | 14 ++++++++++++++
6 files changed, 77 insertions(+), 7 deletions(-)
Comments
Hi Tatsuyuki:
Thanks your TLS desc implementation, it's looks already in good shape
now! just few minor comment :)
> @@ -121,6 +121,14 @@
> (T1_REGNUM 6)
> (S0_REGNUM 8)
> (S1_REGNUM 9)
> + (A0_REGNUM 10)
> + (A1_REGNUM 11)
> + (A2_REGNUM 12)
> + (A3_REGNUM 13)
> + (A4_REGNUM 14)
> + (A5_REGNUM 15)
> + (A6_REGNUM 16)
> + (A7_REGNUM 17)
Drop A1_REGNUM~A7_REGNUM, they seems unused.
> (S2_REGNUM 18)
> (S3_REGNUM 19)
> (S4_REGNUM 20)
> @@ -1869,6 +1877,18 @@
> [(set_attr "got" "load")
> (set_attr "mode" "<MODE>")])
>
> +(define_insn "tlsdesc<mode>"
You can add @ to the pattern name ("@tlsdesc<mode>"), then you can
simplify riscv_legitimize_tls_address like that:
@@ -1908,7 +1898,7 @@ riscv_legitimize_tls_address (rtx loc)
a0 = gen_rtx_REG (Pmode, GP_ARG_FIRST);
dest = gen_reg_rtx (Pmode);
- emit_insn (riscv_tlsdesc (loc, GEN_INT (seqno)));
+ emit_insn (gen_tlsdesc (Pmode, loc, GEN_INT (seqno)));
emit_insn (gen_add3_insn (dest, a0, tp));
seqno++;
}
> + [(set (reg:P A0_REGNUM)
> + (unspec:P
> + [(match_operand:P 0 "symbolic_operand" "")
> + (match_operand:P 1 "const_int_operand")]
> + UNSPEC_TLSDESC))
> + (clobber (reg:SI T0_REGNUM))]
> + "TARGET_TLSDESC"
> + ".LT%1: auipc\ta0, %%tlsdesc_hi(%0)\;<load>\tt0,%%tlsdesc_load_lo(.LT%1)(a0)\;addi\ta0,a0,%%tlsdesc_add_lo(.LT%1)\;jalr\tt0,t0,%%tlsdesc_call(.LT%1)"
I would suggest using return rather than single long line, like below,
that would be easier to read :
{
return ".LT%1: auipc\ta0, %%tlsdesc_hi(%0)\;"
"<load>\tt0,%%tlsdesc_load_lo(.LT%1)(a0)\;"
"addi\ta0,a0,%%tlsdesc_add_lo(.LT%1)\;"
"jalr\tt0,t0,%%tlsdesc_call(.LT%1)"
}
> + [(set_attr "type" "multi")
We need add length here, something like that: "(set_attr "length"
(const_int 16))"
> + (set_attr "mode" "<MODE>")])
> +
> (define_insn "auipc<mode>"
> [(set (match_operand:P 0 "register_operand" "=r")
> (unspec:P
> diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
> index 6304efebfd5..40b3ebf2a99 100644
> --- a/gcc/config/riscv/riscv.opt
> +++ b/gcc/config/riscv/riscv.opt
> @@ -311,3 +311,17 @@ Enum(riscv_autovec_lmul) String(m8) Value(RVV_M8)
> -param=riscv-autovec-lmul=
> Target RejectNegative Joined Enum(riscv_autovec_lmul) Var(riscv_autovec_lmul) Init(RVV_M1)
> -param=riscv-autovec-lmul=<string> Set the RVV LMUL of auto-vectorization in the RISC-V port.
> +
> +Enum
> +Name(tls_type) Type(enum riscv_tls_type)
> +The possible TLS dialects:
> +
> +EnumValue
> +Enum(tls_type) String(trad) Value(TLS_TRADITIONAL)
> +
> +EnumValue
> +Enum(tls_type) String(desc) Value(TLS_DESCRIPTORS)
> +
> +mtls-dialect=
> +Target RejectNegative Joined Enum(tls_type) Var(riscv_tls_dialect) Init(TLS_TRADITIONAL) Save
Could you add a configure option `--with-tls` to control the default
TLS dialect?
You can reference ARM:
gcc/gcc/config/arm/arm.h: grep "OPTION_DEFAULT_SPECS"
gcc/gcc/config.gcc: grep "with_tls"
> +Specify TLS dialect.
> \ No newline at end of file
> --
> 2.34.1
>
@@ -319,4 +319,10 @@ enum riscv_entity
#define TARGET_VECTOR_VLS \
(TARGET_VECTOR && riscv_autovec_preference == RVV_SCALABLE)
+/* TLS types. */
+enum riscv_tls_type {
+ TLS_TRADITIONAL,
+ TLS_DESCRIPTORS
+};
+
#endif /* ! GCC_RISCV_OPTS_H */
@@ -33,9 +33,10 @@ enum riscv_symbol_type {
SYMBOL_TLS,
SYMBOL_TLS_LE,
SYMBOL_TLS_IE,
- SYMBOL_TLS_GD
+ SYMBOL_TLS_GD,
+ SYMBOL_TLSDESC,
};
-#define NUM_SYMBOL_TYPES (SYMBOL_TLS_GD + 1)
+#define NUM_SYMBOL_TYPES (SYMBOL_TLSDESC + 1)
/* Classifies an address.
@@ -799,6 +799,7 @@ static int riscv_symbol_insns (enum riscv_symbol_type type)
case SYMBOL_ABSOLUTE: return 2; /* LUI + the reference. */
case SYMBOL_PCREL: return 2; /* AUIPC + the reference. */
case SYMBOL_TLS_LE: return 3; /* LUI + ADD TP + the reference. */
+ case SYMBOL_TLSDESC: return 6; /* 4-instruction call + ADD TP + the reference. */
case SYMBOL_GOT_DISP: return 3; /* AUIPC + LD GOT + the reference. */
default: gcc_unreachable ();
}
@@ -1601,6 +1602,16 @@ static rtx riscv_tls_add_tp_le (rtx dest, rtx base, rtx sym)
return gen_tls_add_tp_lesi (dest, base, tp, sym);
}
+/* Instruction sequence to call the TLS Descriptor resolver. */
+
+static rtx riscv_tlsdesc (rtx sym, rtx seqno)
+{
+ if (Pmode == DImode)
+ return gen_tlsdescdi (sym, seqno);
+ else
+ return gen_tlsdescsi (sym, seqno);
+}
+
/* If MODE is MAX_MACHINE_MODE, ADDR appears as a move operand, otherwise
it appears in a MEM of that mode. Return true if ADDR is a legitimate
constant in that context and can be split into high and low parts.
@@ -1734,7 +1745,7 @@ riscv_call_tls_get_addr (rtx sym, rtx result)
static rtx
riscv_legitimize_tls_address (rtx loc)
{
- rtx dest, tp, tmp;
+ rtx dest, tp, tmp, a0;
enum tls_model model = SYMBOL_REF_TLS_MODEL (loc);
#if 0
@@ -1750,9 +1761,24 @@ riscv_legitimize_tls_address (rtx loc)
/* Rely on section anchors for the optimization that LDM TLS
provides. The anchor's address is loaded with GD TLS. */
case TLS_MODEL_GLOBAL_DYNAMIC:
- tmp = gen_rtx_REG (Pmode, GP_RETURN);
- dest = gen_reg_rtx (Pmode);
- emit_libcall_block (riscv_call_tls_get_addr (loc, tmp), dest, tmp, loc);
+ if (TARGET_TLSDESC)
+ {
+ static unsigned seqno;
+ tp = gen_rtx_REG (Pmode, THREAD_POINTER_REGNUM);
+ a0 = gen_rtx_REG (Pmode, GP_ARG_FIRST);
+ dest = gen_reg_rtx (Pmode);
+
+ emit_insn (riscv_tlsdesc (loc, GEN_INT (seqno)));
+ emit_insn (gen_add3_insn (dest, a0, tp));
+ seqno++;
+ }
+ else
+ {
+ tmp = gen_rtx_REG (Pmode, GP_RETURN);
+ dest = gen_reg_rtx (Pmode);
+ emit_libcall_block (riscv_call_tls_get_addr (loc, tmp), dest, tmp,
+ loc);
+ }
break;
case TLS_MODEL_INITIAL_EXEC:
@@ -1122,4 +1122,7 @@ extern void riscv_remove_unneeded_save_restore_calls (void);
#define OPTIMIZE_MODE_SWITCHING(ENTITY) (TARGET_VECTOR)
#define NUM_MODES_FOR_MODE_SWITCHING {VXRM_MODE_NONE, riscv_vector::FRM_NONE}
+/* Check TLS Descriptors mechanism is selected. */
+#define TARGET_TLSDESC (riscv_tls_dialect == TLS_DESCRIPTORS)
+
#endif /* ! GCC_RISCV_H */
@@ -47,7 +47,7 @@
UNSPEC_TLS_LE
UNSPEC_TLS_IE
UNSPEC_TLS_GD
-
+ UNSPEC_TLSDESC
;; High part of PC-relative address.
UNSPEC_AUIPC
@@ -121,6 +121,14 @@
(T1_REGNUM 6)
(S0_REGNUM 8)
(S1_REGNUM 9)
+ (A0_REGNUM 10)
+ (A1_REGNUM 11)
+ (A2_REGNUM 12)
+ (A3_REGNUM 13)
+ (A4_REGNUM 14)
+ (A5_REGNUM 15)
+ (A6_REGNUM 16)
+ (A7_REGNUM 17)
(S2_REGNUM 18)
(S3_REGNUM 19)
(S4_REGNUM 20)
@@ -1869,6 +1877,18 @@
[(set_attr "got" "load")
(set_attr "mode" "<MODE>")])
+(define_insn "tlsdesc<mode>"
+ [(set (reg:P A0_REGNUM)
+ (unspec:P
+ [(match_operand:P 0 "symbolic_operand" "")
+ (match_operand:P 1 "const_int_operand")]
+ UNSPEC_TLSDESC))
+ (clobber (reg:SI T0_REGNUM))]
+ "TARGET_TLSDESC"
+ ".LT%1: auipc\ta0, %%tlsdesc_hi(%0)\;<load>\tt0,%%tlsdesc_load_lo(.LT%1)(a0)\;addi\ta0,a0,%%tlsdesc_add_lo(.LT%1)\;jalr\tt0,t0,%%tlsdesc_call(.LT%1)"
+ [(set_attr "type" "multi")
+ (set_attr "mode" "<MODE>")])
+
(define_insn "auipc<mode>"
[(set (match_operand:P 0 "register_operand" "=r")
(unspec:P
@@ -311,3 +311,17 @@ Enum(riscv_autovec_lmul) String(m8) Value(RVV_M8)
-param=riscv-autovec-lmul=
Target RejectNegative Joined Enum(riscv_autovec_lmul) Var(riscv_autovec_lmul) Init(RVV_M1)
-param=riscv-autovec-lmul=<string> Set the RVV LMUL of auto-vectorization in the RISC-V port.
+
+Enum
+Name(tls_type) Type(enum riscv_tls_type)
+The possible TLS dialects:
+
+EnumValue
+Enum(tls_type) String(trad) Value(TLS_TRADITIONAL)
+
+EnumValue
+Enum(tls_type) String(desc) Value(TLS_DESCRIPTORS)
+
+mtls-dialect=
+Target RejectNegative Joined Enum(tls_type) Var(riscv_tls_dialect) Init(TLS_TRADITIONAL) Save
+Specify TLS dialect.
\ No newline at end of file