[PATCH v2] RISC-V: Implement TLS Descriptors.

2023-09-08 Thread Tatsuyuki Ishi via Gcc-patches
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.

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.
---
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.
Thanks Kito Cheng for the review.

This contribution is made on behalf of Blue Whale Systems, which has
copyright assignment on file with the FSF.

 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 ++
 7 files changed, 84 insertions(+), 10 deletions(-)

diff --git a/gcc/config.gcc b/gcc/config.gcc
index 415e0e1ebc5..86df7b89016 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 

[PATCH] RISC-V: Implement TLS Descriptors.

2023-08-17 Thread Tatsuyuki Ishi via Gcc-patches
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(-)

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..4ff0adbbb1e 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 ();
 }
@@ -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:
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index e18a0081297..7cf1365ec08 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -1122,4 +1122,7 @@ extern void riscv_remove_unneeded_save_restore_calls 
(void);
 #define