This implements TLS Descriptors (TLSDESC) as specified in [1].
The 4-instruction sequence is implemented as a single RTX insn for
simplicity, but this can be revisited later if instruction scheduling or
more flexible RA is desired.
The default remains to be the traditional TLS model, but can be configured
with --with-tls={trad,desc}. The choice can be revisited once toolchain
and libc support ships.
[1]: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/373.
gcc/ChangeLog:
* config/riscv/riscv.opt: Add -mtls-dialect to configure TLS flavor.
* config.gcc: Add --with-tls configuration option to change the
default TLS flavor.
* config/riscv/riscv.h: Add TARGET_TLSDESC determined from
-mtls-dialect and with_tls defaults.
* config/riscv/riscv-opts.h: Define enum riscv_tls_type for the
two TLS flavors.
* config/riscv/riscv-protos.h: Define SYMBOL_TLSDESC symbol type.
* config/riscv/riscv.md: Add instruction sequence for TLSDESC.
* config/riscv/riscv.cc (riscv_symbol_insns): Add instruction
sequence length data for TLSDESC.
(riscv_legitimize_tls_address): Add lowering of TLSDESC.
* doc/install.texi: Document --with-tls for RISC-V.
* doc/invoke.texi: Document -mtls-dialect for RISC-V.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/tls_1.x: Add TLSDESC GD test case.
* gcc.target/riscv/tlsdesc.c: Same as above.
# Force .init_array support. The configure script cannot always
# automatically detect that GAS supports it, yet we require it.
gcc_cv_initfini_array=yes
+ with_tls=${with_tls:-trad}
;;
riscv*-*-elf* | riscv*-*-rtems*)
tm_file="elfos.h newlib-stdint.h ${tm_file} riscv/elf.h"
# Force .init_array support. The configure script cannot always
# automatically detect that GAS supports it, yet we require it.
gcc_cv_initfini_array=yes
+ with_tls=${with_tls:-trad}
;;
loongarch*-*-linux*)
;;
riscv*-*-*)
- supported_defaults="abi arch tune riscv_attribute isa_spec"
+ supported_defaults="abi arch tune riscv_attribute isa_spec tls"
case "${target}" in
riscv-* | riscv32*) xlen=32 ;;
;;
esac
fi
+ # Handle --with-tls.
+ case "$with_tls" in
+ "" \
+ | trad | desc)
+ # OK
+ ;;
+ *)
+ echo "Unknown TLS method used in --with-tls=$with_tls" 1>&2
+ exit 1
+ ;;
+ esac
# Handle --with-multilib-list.
if test "x${with_multilib_list}" != xdefault; then
#define TARGET_MAX_LMUL \
(int) (rvv_max_lmul == RVV_DYNAMIC ? RVV_M8 : rvv_max_lmul)
+/* TLS types. */
+enum riscv_tls_type {
+ TLS_TRADITIONAL,
+ TLS_DESCRIPTORS
+};
+
#endif /* ! GCC_RISCV_OPTS_H */
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.
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. */
case SYMBOL_FORCE_TO_MEM: return 3; /* AUIPC + LD + the reference. */
default: gcc_unreachable ();
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
/* 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 (gen_tlsdesc (Pmode, 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:
--with-abi is ignored if -mabi is specified.
--with-tune is ignored if -mtune or -mcpu is specified.
--with-isa-spec is ignored if -misa-spec is specified.
+ --with-tls is ignored if -mtls-dialect is specified.
But using default -march/-mtune value if -mcpu don't have valid option. */
#define OPTION_DEFAULT_SPECS \
{"arch", "%{!march=*:" \
" %{!mcpu=*:-march=%(VALUE)}" \
" %{mcpu=*:%:riscv_expand_arch_from_cpu(%* %(VALUE))}}" }, \
- {"abi", "%{!mabi=*:-mabi=%(VALUE)}" }, \
- {"isa_spec", "%{!misa-spec=*:-misa-spec=%(VALUE)}" }, \
+ {"abi", "%{!mabi=*:-mabi=%(VALUE)}" }, \
+ {"isa_spec", "%{!misa-spec=*:-misa-spec=%(VALUE)}" }, \
+ {"tls", "%{!mtls-dialect=*:-mtls-dialect=%(VALUE)}"}, \
#ifdef IN_LIBGCC2
#undef TARGET_64BIT
#define HAVE_POST_MODIFY_DISP TARGET_XTHEADMEMIDX
#define HAVE_PRE_MODIFY_DISP TARGET_XTHEADMEMIDX
+/* Check TLS Descriptors mechanism is selected. */
+#define TARGET_TLSDESC (riscv_tls_dialect == TLS_DESCRIPTORS)
+
#endif /* ! GCC_RISCV_H */
UNSPEC_TLS_LE
UNSPEC_TLS_IE
UNSPEC_TLS_GD
-
+ UNSPEC_TLSDESC
;; High part of PC-relative address.
UNSPEC_AUIPC
(set_attr "type" "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:P T0_REGNUM))]
+ "TARGET_TLSDESC"
+ {
+ 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")
+ (set_attr "length" "16")
+ (set_attr "mode" "<MODE>")])
+
(define_insn "auipc<mode>"
[(set (match_operand:P 0 "register_operand" "=r")
(unspec:P
mrvv-vector-bits=
Target RejectNegative Joined Enum(rvv_vector_bits) Var(rvv_vector_bits) Init(RVV_VECTOR_BITS_SCALABLE)
-mrvv-vector-bits=<string> Set the kind of bits for an RVV vector register.
+
+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.
For ARM targets, possible values for @var{dialect} are @code{gnu} or
@code{gnu2}, which select between the original GNU dialect and the GNU TLS
descriptor-based dialect.
+For RISC-V targets, possible values for @var{dialect} are @code{trad} or
+@code{desc}, which select between the traditional GNU dialect and the GNU TLS
+descriptor-based dialect.
@item --enable-multiarch
Specify whether to enable or disable multiarch support. The default is
-minline-atomics -mno-inline-atomics
-minline-strlen -mno-inline-strlen
-minline-strcmp -mno-inline-strcmp
--minline-strncmp -mno-inline-strncmp}
+-minline-strncmp -mno-inline-strncmp
+-mtls-dialect=desc -mtls-dialect=trad}
@emph{RL78 Options}
@gccoptlist{-msim -mmul=none -mmul=g13 -mmul=g14 -mallregs
and from what offset from that base register. There is no default
register or offset as this is entirely for use within the Linux
kernel.
+
+@opindex mtls-dialect=desc
+@item -mtls-dialect=desc
+Use TLS descriptors as the thread-local storage mechanism for dynamic accesses
+of TLS variables.
+
+@opindex mtls-dialect=trad
+@item -mtls-dialect=trad
+Use traditional TLS as the thread-local storage mechanism for dynamic accesses
+of TLS variables. This is the default.
@end table
@node RL78 Options
--- /dev/null
+extern __thread unsigned gd;
+
+unsigned get() {
+ return gd;
+}
--- /dev/null
+/* { dg-require-effective-target tls_native } */
+/* { dg-options "-O2 -fpic -mtls-dialect=desc --save-temps" } */
+/* { dg-require-effective-target fpic } */
+
+#include "tls_1.x"
+
+/* { dg-final { scan-assembler-times "auipc\t\[a-x0-9\]+,%tlsdesc_hi" 1 } } */
+/* { dg-final { scan-assembler-times "lw\t\[a-x0-9\]+,%tlsdesc_load_lo" 1 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "ld\t\[a-x0-9\]+,%tlsdesc_load_lo" 1 { target { rv64 } } } }*/
+/* { dg-final { scan-assembler-times "addi\ta0,\[a-x0-9\]+,%tlsdesc_add_lo" 1 } } */
+/* { dg-final { scan-assembler-times "jalr\tt0,\[a-x0-9\]+,%tlsdesc_call" 1 } } */
+/* { dg-final { cleanup-saved-temps } } */