[v3] RISC-V: Implement TLS Descriptors.

Message ID 20231120131726.52280-1-ishitatsuyuki@gmail.com
State Unresolved
Headers
Series [v3] RISC-V: Implement TLS Descriptors. |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

Tatsuyuki Ishi Nov. 20, 2023, 1:17 p.m. UTC
  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.
---
No regression in gcc tests for rv64gc, tested alongside the binutils and
glibc implementation. Tested with --with_tls=desc.

v2: Add with_tls configuration option, and a few readability improvements.
    Added Changelog.
v3: Add documentation per Kito's suggestion.
    Fix minor issues pointed out by Kito and Jeff.
    Thanks Kito Cheng and Jeff Law for review.

I've considered gating this behind a GAS feature test, but it seems
nontrivial especially for restricting the variants available at runtime.
Since TLS descriptors is not selected by default, I've decided to leave it
ungated.

In other news, I have made some progress on binutils side, and I'll try to
update the GAS / ld patch set with relaxation included, by the end of this
month.

 gcc/config.gcc                  | 15 ++++++++++++++-
 gcc/config/riscv/riscv-opts.h   |  6 ++++++
 gcc/config/riscv/riscv-protos.h |  5 +++--
 gcc/config/riscv/riscv.cc       | 24 ++++++++++++++++++++----
 gcc/config/riscv/riscv.h        |  9 +++++++--
 gcc/config/riscv/riscv.md       | 21 ++++++++++++++++++++-
 gcc/config/riscv/riscv.opt      | 14 ++++++++++++++
 gcc/doc/install.texi            |  3 +++
 gcc/doc/invoke.texi             | 13 ++++++++++++-
 9 files changed, 99 insertions(+), 11 deletions(-)
  

Comments

Fangrui Song Nov. 21, 2023, 6:59 a.m. UTC | #1
On Mon, Nov 20, 2023 at 6:20 AM Tatsuyuki Ishi <ishitatsuyuki@gmail.com> wrote:
>
> 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.

Nit: One dash for --mtls-dialect.

> ---
> No regression in gcc tests for rv64gc, tested alongside the binutils and
> glibc implementation. Tested with --with_tls=desc.
>
> v2: Add with_tls configuration option, and a few readability improvements.
>     Added Changelog.
> v3: Add documentation per Kito's suggestion.
>     Fix minor issues pointed out by Kito and Jeff.
>     Thanks Kito Cheng and Jeff Law for review.
>
> I've considered gating this behind a GAS feature test, but it seems
> nontrivial especially for restricting the variants available at runtime.
> Since TLS descriptors is not selected by default, I've decided to leave it
> ungated.
>
> In other news, I have made some progress on binutils side, and I'll try to
> update the GAS / ld patch set with relaxation included, by the end of this
> month.

Thanks for the update.  I understand the complexity adding a runtime
test when the feature also requires binutils and rtld support.
I hope that we add a test checking assembly under
gcc/testsuite/gcc.target/riscv/tls , otherwise as a non-default test,
when this breaks, it may be difficult to figure it out.
(glibc/elf/tst-* will need a runtime test, but GCC needs to have its own.)

>  gcc/config.gcc                  | 15 ++++++++++++++-
>  gcc/config/riscv/riscv-opts.h   |  6 ++++++
>  gcc/config/riscv/riscv-protos.h |  5 +++--
>  gcc/config/riscv/riscv.cc       | 24 ++++++++++++++++++++----
>  gcc/config/riscv/riscv.h        |  9 +++++++--
>  gcc/config/riscv/riscv.md       | 21 ++++++++++++++++++++-
>  gcc/config/riscv/riscv.opt      | 14 ++++++++++++++
>  gcc/doc/install.texi            |  3 +++
>  gcc/doc/invoke.texi             | 13 ++++++++++++-
>  9 files changed, 99 insertions(+), 11 deletions(-)
>
> diff --git a/gcc/config.gcc b/gcc/config.gcc
> index 415e0e1ebc5..2c1a7179b02 100644
> --- a/gcc/config.gcc
> +++ b/gcc/config.gcc
> @@ -2434,6 +2434,7 @@ riscv*-*-linux*)
>         # 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"
> @@ -2476,6 +2477,7 @@ riscv*-*-freebsd*)
>         # 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*)
> @@ -4566,7 +4568,7 @@ case "${target}" in
>                 ;;
>
>         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 ;;
> @@ -4694,6 +4696,17 @@ case "${target}" in
>                                 ;;
>                         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
> diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h
> index 378a17699cd..db03f35430a 100644
> --- a/gcc/config/riscv/riscv-opts.h
> +++ b/gcc/config/riscv/riscv-opts.h
> @@ -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
> +};
> +

I wonder whether `enum class` can be used instead and we can get rid
of the `TLS_` prefix.
gcc/config/ already has some uses.

>  #endif /* ! GCC_RISCV_OPTS_H */
> diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
> index 472c00dc439..9b7471f7591 100644
> --- a/gcc/config/riscv/riscv-protos.h
> +++ b/gcc/config/riscv/riscv-protos.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.
>
> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> index 49062bef9fc..c158e224aaa 100644
> --- a/gcc/config/riscv/riscv.cc
> +++ b/gcc/config/riscv/riscv.cc
> @@ -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 ();
>      }
> @@ -1734,7 +1735,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 +1751,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 (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:
> diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
> index e18a0081297..faea78f5f4c 100644
> --- a/gcc/config/riscv/riscv.h
> +++ b/gcc/config/riscv/riscv.h
> @@ -59,6 +59,7 @@ extern const char *riscv_multi_lib_check (int argc, const char **argv);
>     --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 \
> @@ -68,8 +69,9 @@ extern const char *riscv_multi_lib_check (int argc, const char **argv);
>    {"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
> @@ -1122,4 +1124,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 */
> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> index b456fa6abb3..7c66c64b893 100644
> --- a/gcc/config/riscv/riscv.md
> +++ b/gcc/config/riscv/riscv.md
> @@ -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,7 @@
>     (T1_REGNUM                  6)
>     (S0_REGNUM                  8)
>     (S1_REGNUM                  9)
> +   (A0_REGNUM                  10)
>     (S2_REGNUM                  18)
>     (S3_REGNUM                  19)
>     (S4_REGNUM                  20)
> @@ -1869,6 +1870,24 @@
>    [(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: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
> diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
> index 6304efebfd5..9ba690f8497 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
> +Specify TLS dialect.
> diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi
> index e099cd0b568..6ee533c0a40 100644
> --- a/gcc/doc/install.texi
> +++ b/gcc/doc/install.texi
> @@ -1174,6 +1174,9 @@ Specify the default TLS dialect, for systems were there is a choice.
>  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
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index f2c1067ab7d..77b82c46311 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -1234,7 +1234,8 @@ See RS/6000 and PowerPC Options.
>  -mstack-protector-guard=@var{guard}  -mstack-protector-guard-reg=@var{reg}
>  -mstack-protector-guard-offset=@var{offset}
>  -mcsr-check -mno-csr-check
> --minline-atomics  -mno-inline-atomics}
> +-minline-atomics  -mno-inline-atomics
> +-mtls-dialect=desc  -mtls-dialect=trad}
>
>  @emph{RL78 Options}
>  @gccoptlist{-msim  -mmul=none  -mmul=g13  -mmul=g14  -mallregs
> @@ -29403,6 +29404,16 @@ which register to use as base register for reading the canary,
>  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
> --
> 2.42.1
>
  
Tatsuyuki Ishi Nov. 21, 2023, 7:07 a.m. UTC | #2
> On Nov 21, 2023, at 15:59, Fangrui Song <maskray@google.com> wrote:
> 
> On Mon, Nov 20, 2023 at 6:20 AM Tatsuyuki Ishi <ishitatsuyuki@gmail.com <mailto:ishitatsuyuki@gmail.com>> wrote:
>> 
>> 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.
> 
> Nit: One dash for --mtls-dialect.

Ack. Thanks.

>> ---
>> No regression in gcc tests for rv64gc, tested alongside the binutils and
>> glibc implementation. Tested with --with_tls=desc.
>> 
>> v2: Add with_tls configuration option, and a few readability improvements.
>>    Added Changelog.
>> v3: Add documentation per Kito's suggestion.
>>    Fix minor issues pointed out by Kito and Jeff.
>>    Thanks Kito Cheng and Jeff Law for review.
>> 
>> I've considered gating this behind a GAS feature test, but it seems
>> nontrivial especially for restricting the variants available at runtime.
>> Since TLS descriptors is not selected by default, I've decided to leave it
>> ungated.
>> 
>> In other news, I have made some progress on binutils side, and I'll try to
>> update the GAS / ld patch set with relaxation included, by the end of this
>> month.
> 
> Thanks for the update.  I understand the complexity adding a runtime
> test when the feature also requires binutils and rtld support.
> I hope that we add a test checking assembly under
> gcc/testsuite/gcc.target/riscv/tls , otherwise as a non-default test,
> when this breaks, it may be difficult to figure it out.
> (glibc/elf/tst-* will need a runtime test, but GCC needs to have its own.)

Checking assembly sounds reasonable.  I’ll look into it after finishing the binutils stuff.

>> gcc/config.gcc                  | 15 ++++++++++++++-
>> gcc/config/riscv/riscv-opts.h   |  6 ++++++
>> gcc/config/riscv/riscv-protos.h |  5 +++--
>> gcc/config/riscv/riscv.cc       | 24 ++++++++++++++++++++----
>> gcc/config/riscv/riscv.h        |  9 +++++++--
>> gcc/config/riscv/riscv.md       | 21 ++++++++++++++++++++-
>> gcc/config/riscv/riscv.opt      | 14 ++++++++++++++
>> gcc/doc/install.texi            |  3 +++
>> gcc/doc/invoke.texi             | 13 ++++++++++++-
>> 9 files changed, 99 insertions(+), 11 deletions(-)
>> 
>> diff --git a/gcc/config.gcc b/gcc/config.gcc
>> index 415e0e1ebc5..2c1a7179b02 100644
>> --- a/gcc/config.gcc
>> +++ b/gcc/config.gcc
>> @@ -2434,6 +2434,7 @@ riscv*-*-linux*)
>>        # 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"
>> @@ -2476,6 +2477,7 @@ riscv*-*-freebsd*)
>>        # 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*)
>> @@ -4566,7 +4568,7 @@ case "${target}" in
>>                ;;
>> 
>>        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 ;;
>> @@ -4694,6 +4696,17 @@ case "${target}" in
>>                                ;;
>>                        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
>> diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h
>> index 378a17699cd..db03f35430a 100644
>> --- a/gcc/config/riscv/riscv-opts.h
>> +++ b/gcc/config/riscv/riscv-opts.h
>> @@ -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
>> +};
>> +
> 
> I wonder whether `enum class` can be used instead and we can get rid
> of the `TLS_` prefix.
> gcc/config/ already has some uses.

Sounds reasonable. If others have no objections I’ll put it in a revision.

>> #endif /* ! GCC_RISCV_OPTS_H */
>> diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
>> index 472c00dc439..9b7471f7591 100644
>> --- a/gcc/config/riscv/riscv-protos.h
>> +++ b/gcc/config/riscv/riscv-protos.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.
>> 
>> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
>> index 49062bef9fc..c158e224aaa 100644
>> --- a/gcc/config/riscv/riscv.cc
>> +++ b/gcc/config/riscv/riscv.cc
>> @@ -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 ();
>>     }
>> @@ -1734,7 +1735,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 +1751,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 (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:
>> diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
>> index e18a0081297..faea78f5f4c 100644
>> --- a/gcc/config/riscv/riscv.h
>> +++ b/gcc/config/riscv/riscv.h
>> @@ -59,6 +59,7 @@ extern const char *riscv_multi_lib_check (int argc, const char **argv);
>>    --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 \
>> @@ -68,8 +69,9 @@ extern const char *riscv_multi_lib_check (int argc, const char **argv);
>>   {"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
>> @@ -1122,4 +1124,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 */
>> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
>> index b456fa6abb3..7c66c64b893 100644
>> --- a/gcc/config/riscv/riscv.md
>> +++ b/gcc/config/riscv/riscv.md
>> @@ -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,7 @@
>>    (T1_REGNUM                  6)
>>    (S0_REGNUM                  8)
>>    (S1_REGNUM                  9)
>> +   (A0_REGNUM                  10)
>>    (S2_REGNUM                  18)
>>    (S3_REGNUM                  19)
>>    (S4_REGNUM                  20)
>> @@ -1869,6 +1870,24 @@
>>   [(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: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
>> diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
>> index 6304efebfd5..9ba690f8497 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
>> +Specify TLS dialect.
>> diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi
>> index e099cd0b568..6ee533c0a40 100644
>> --- a/gcc/doc/install.texi
>> +++ b/gcc/doc/install.texi
>> @@ -1174,6 +1174,9 @@ Specify the default TLS dialect, for systems were there is a choice.
>> 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
>> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
>> index f2c1067ab7d..77b82c46311 100644
>> --- a/gcc/doc/invoke.texi
>> +++ b/gcc/doc/invoke.texi
>> @@ -1234,7 +1234,8 @@ See RS/6000 and PowerPC Options.
>> -mstack-protector-guard=@var{guard}  -mstack-protector-guard-reg=@var{reg}
>> -mstack-protector-guard-offset=@var{offset}
>> -mcsr-check -mno-csr-check
>> --minline-atomics  -mno-inline-atomics}
>> +-minline-atomics  -mno-inline-atomics
>> +-mtls-dialect=desc  -mtls-dialect=trad}
>> 
>> @emph{RL78 Options}
>> @gccoptlist{-msim  -mmul=none  -mmul=g13  -mmul=g14  -mallregs
>> @@ -29403,6 +29404,16 @@ which register to use as base register for reading the canary,
>> 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
>> --
>> 2.42.1
>> 
> 
> 
> -- 
> 宋方睿
  
Florian Weimer Nov. 23, 2023, 10:57 a.m. UTC | #3
* Tatsuyuki Ishi:

> I've considered gating this behind a GAS feature test, but it seems
> nontrivial especially for restricting the variants available at runtime.
> Since TLS descriptors is not selected by default, I've decided to leave it
> ungated.
>
> In other news, I have made some progress on binutils side, and I'll try to
> update the GAS / ld patch set with relaxation included, by the end of this
> month.

Is there a glibc patch with the run-time implementation already?

I'm curious how you are going to implement saving the vector register
file

Thanks,
Florian
  
Tatsuyuki Ishi Nov. 23, 2023, 11:34 a.m. UTC | #4
> On Nov 23, 2023, at 19:57, Florian Weimer <fweimer@redhat.com> wrote:
> 
> * Tatsuyuki Ishi:
> 
>> I've considered gating this behind a GAS feature test, but it seems
>> nontrivial especially for restricting the variants available at runtime.
>> Since TLS descriptors is not selected by default, I've decided to leave it
>> ungated.
>> 
>> In other news, I have made some progress on binutils side, and I'll try to
>> update the GAS / ld patch set with relaxation included, by the end of this
>> month.
> 
> Is there a glibc patch with the run-time implementation already?
> 
> I'm curious how you are going to implement saving the vector register
> file

There is, please see [1].  The vector register file handling is missing right
now as I’m not sure if we have agreed upon a calling convention for RVV.

In the spec, I have already specified the interaction with RVV:

> Any other registers are callee-saved. This includes any vector registers
when the vector extension is supported.

Once the calling convention is decided, I will add saving of all caller-saved
registers into the TLSDESC stub.

[1]: https://inbox.sourceware.org/libc-alpha/20230914084033.222120-1-ishitatsuyuki@gmail.com/

> Thanks,
> Florian
>
  
Florian Weimer Nov. 23, 2023, 11:40 a.m. UTC | #5
* Tatsuyuki Ishi:

> There is, please see [1].  The vector register file handling is missing right
> now as I’m not sure if we have agreed upon a calling convention for RVV.

> [1]: https://inbox.sourceware.org/libc-alpha/20230914084033.222120-1-ishitatsuyuki@gmail.com/

Thank you, I have raised my concern on the other thread.

Thanks,
Florian
  
Tatsuyuki Ishi Dec. 5, 2023, 4:49 p.m. UTC | #6
> On Nov 21, 2023, at 15:59, Fangrui Song <maskray@google.com> wrote:
> 
> On Mon, Nov 20, 2023 at 6:20 AM Tatsuyuki Ishi <ishitatsuyuki@gmail.com <mailto:ishitatsuyuki@gmail.com>> wrote:
>> 
>> 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.
> 
> Nit: One dash for --mtls-dialect.
> 
>> ---
>> No regression in gcc tests for rv64gc, tested alongside the binutils and
>> glibc implementation. Tested with --with_tls=desc.
>> 
>> v2: Add with_tls configuration option, and a few readability improvements.
>>    Added Changelog.
>> v3: Add documentation per Kito's suggestion.
>>    Fix minor issues pointed out by Kito and Jeff.
>>    Thanks Kito Cheng and Jeff Law for review.
>> 
>> I've considered gating this behind a GAS feature test, but it seems
>> nontrivial especially for restricting the variants available at runtime.
>> Since TLS descriptors is not selected by default, I've decided to leave it
>> ungated.
>> 
>> In other news, I have made some progress on binutils side, and I'll try to
>> update the GAS / ld patch set with relaxation included, by the end of this
>> month.
> 
> Thanks for the update.  I understand the complexity adding a runtime
> test when the feature also requires binutils and rtld support.
> I hope that we add a test checking assembly under
> gcc/testsuite/gcc.target/riscv/tls , otherwise as a non-default test,
> when this breaks, it may be difficult to figure it out.
> (glibc/elf/tst-* will need a runtime test, but GCC needs to have its own.)
> 
>> gcc/config.gcc                  | 15 ++++++++++++++-
>> gcc/config/riscv/riscv-opts.h   |  6 ++++++
>> gcc/config/riscv/riscv-protos.h |  5 +++--
>> gcc/config/riscv/riscv.cc       | 24 ++++++++++++++++++++----
>> gcc/config/riscv/riscv.h        |  9 +++++++--
>> gcc/config/riscv/riscv.md       | 21 ++++++++++++++++++++-
>> gcc/config/riscv/riscv.opt      | 14 ++++++++++++++
>> gcc/doc/install.texi            |  3 +++
>> gcc/doc/invoke.texi             | 13 ++++++++++++-
>> 9 files changed, 99 insertions(+), 11 deletions(-)
>> 
>> diff --git a/gcc/config.gcc b/gcc/config.gcc
>> index 415e0e1ebc5..2c1a7179b02 100644
>> --- a/gcc/config.gcc
>> +++ b/gcc/config.gcc
>> @@ -2434,6 +2434,7 @@ riscv*-*-linux*)
>>        # 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"
>> @@ -2476,6 +2477,7 @@ riscv*-*-freebsd*)
>>        # 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*)
>> @@ -4566,7 +4568,7 @@ case "${target}" in
>>                ;;
>> 
>>        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 ;;
>> @@ -4694,6 +4696,17 @@ case "${target}" in
>>                                ;;
>>                        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
>> diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h
>> index 378a17699cd..db03f35430a 100644
>> --- a/gcc/config/riscv/riscv-opts.h
>> +++ b/gcc/config/riscv/riscv-opts.h
>> @@ -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
>> +};
>> +
> 
> I wonder whether `enum class` can be used instead and we can get rid
> of the `TLS_` prefix.
> gcc/config/ already has some uses.

Sorry, once thing I forgot to mention about this when I posted v4.
This enum is used in the context of an .opt file, so I’ve kept it as-is in
v4 to avoid contradicting the code style.

Tatsuyuki.

>> #endif /* ! GCC_RISCV_OPTS_H */
>> diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
>> index 472c00dc439..9b7471f7591 100644
>> --- a/gcc/config/riscv/riscv-protos.h
>> +++ b/gcc/config/riscv/riscv-protos.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.
>> 
>> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
>> index 49062bef9fc..c158e224aaa 100644
>> --- a/gcc/config/riscv/riscv.cc
>> +++ b/gcc/config/riscv/riscv.cc
>> @@ -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 ();
>>     }
>> @@ -1734,7 +1735,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 +1751,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 (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:
>> diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
>> index e18a0081297..faea78f5f4c 100644
>> --- a/gcc/config/riscv/riscv.h
>> +++ b/gcc/config/riscv/riscv.h
>> @@ -59,6 +59,7 @@ extern const char *riscv_multi_lib_check (int argc, const char **argv);
>>    --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 \
>> @@ -68,8 +69,9 @@ extern const char *riscv_multi_lib_check (int argc, const char **argv);
>>   {"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
>> @@ -1122,4 +1124,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 */
>> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
>> index b456fa6abb3..7c66c64b893 100644
>> --- a/gcc/config/riscv/riscv.md
>> +++ b/gcc/config/riscv/riscv.md
>> @@ -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,7 @@
>>    (T1_REGNUM                  6)
>>    (S0_REGNUM                  8)
>>    (S1_REGNUM                  9)
>> +   (A0_REGNUM                  10)
>>    (S2_REGNUM                  18)
>>    (S3_REGNUM                  19)
>>    (S4_REGNUM                  20)
>> @@ -1869,6 +1870,24 @@
>>   [(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: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
>> diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
>> index 6304efebfd5..9ba690f8497 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
>> +Specify TLS dialect.
>> diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi
>> index e099cd0b568..6ee533c0a40 100644
>> --- a/gcc/doc/install.texi
>> +++ b/gcc/doc/install.texi
>> @@ -1174,6 +1174,9 @@ Specify the default TLS dialect, for systems were there is a choice.
>> 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
>> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
>> index f2c1067ab7d..77b82c46311 100644
>> --- a/gcc/doc/invoke.texi
>> +++ b/gcc/doc/invoke.texi
>> @@ -1234,7 +1234,8 @@ See RS/6000 and PowerPC Options.
>> -mstack-protector-guard=@var{guard}  -mstack-protector-guard-reg=@var{reg}
>> -mstack-protector-guard-offset=@var{offset}
>> -mcsr-check -mno-csr-check
>> --minline-atomics  -mno-inline-atomics}
>> +-minline-atomics  -mno-inline-atomics
>> +-mtls-dialect=desc  -mtls-dialect=trad}
>> 
>> @emph{RL78 Options}
>> @gccoptlist{-msim  -mmul=none  -mmul=g13  -mmul=g14  -mallregs
>> @@ -29403,6 +29404,16 @@ which register to use as base register for reading the canary,
>> 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
>> --
>> 2.42.1
>> 
> 
> 
> -- 
> 宋方睿
  

Patch

diff --git a/gcc/config.gcc b/gcc/config.gcc
index 415e0e1ebc5..2c1a7179b02 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -2434,6 +2434,7 @@  riscv*-*-linux*)
 	# 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"
@@ -2476,6 +2477,7 @@  riscv*-*-freebsd*)
 	# 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*)
@@ -4566,7 +4568,7 @@  case "${target}" in
 		;;
 
 	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 ;;
@@ -4694,6 +4696,17 @@  case "${target}" in
 				;;
 			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
diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h
index 378a17699cd..db03f35430a 100644
--- a/gcc/config/riscv/riscv-opts.h
+++ b/gcc/config/riscv/riscv-opts.h
@@ -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 */
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 472c00dc439..9b7471f7591 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.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.
 
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 49062bef9fc..c158e224aaa 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -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 ();
     }
@@ -1734,7 +1735,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 +1751,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 (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:
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index e18a0081297..faea78f5f4c 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -59,6 +59,7 @@  extern const char *riscv_multi_lib_check (int argc, const char **argv);
    --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 \
@@ -68,8 +69,9 @@  extern const char *riscv_multi_lib_check (int argc, const char **argv);
   {"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
@@ -1122,4 +1124,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 */
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index b456fa6abb3..7c66c64b893 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -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,7 @@ 
    (T1_REGNUM			6)
    (S0_REGNUM			8)
    (S1_REGNUM			9)
+   (A0_REGNUM			10)
    (S2_REGNUM			18)
    (S3_REGNUM			19)
    (S4_REGNUM			20)
@@ -1869,6 +1870,24 @@ 
   [(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: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
diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index 6304efebfd5..9ba690f8497 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
+Specify TLS dialect.
diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi
index e099cd0b568..6ee533c0a40 100644
--- a/gcc/doc/install.texi
+++ b/gcc/doc/install.texi
@@ -1174,6 +1174,9 @@  Specify the default TLS dialect, for systems were there is a choice.
 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
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index f2c1067ab7d..77b82c46311 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -1234,7 +1234,8 @@  See RS/6000 and PowerPC Options.
 -mstack-protector-guard=@var{guard}  -mstack-protector-guard-reg=@var{reg}
 -mstack-protector-guard-offset=@var{offset}
 -mcsr-check -mno-csr-check
--minline-atomics  -mno-inline-atomics}
+-minline-atomics  -mno-inline-atomics
+-mtls-dialect=desc  -mtls-dialect=trad}
 
 @emph{RL78 Options}
 @gccoptlist{-msim  -mmul=none  -mmul=g13  -mmul=g14  -mallregs
@@ -29403,6 +29404,16 @@  which register to use as base register for reading the canary,
 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