> On Nov 21, 2023, at 15:59, Fangrui Song <[email protected]> wrote:
>
> On Mon, Nov 20, 2023 at 6:20 AM Tatsuyuki Ishi <[email protected]
> <mailto:[email protected]>> 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
>>
>
>
> --
> 宋方睿