The MIPS backend currently uses rdhwr to access the thread pointer.
This instruction is unavailable on older MIPS processors such as the
R3900.

Add -mtp=soft to allow the MIPS backend to obtain the thread pointer
through the __mips_read_tp runtime helper instead of using rdhwr.
The default -mtp=rdhwr behavior is unchanged.

Tests cover the software thread-pointer path for normal MIPS, MIPS16,
and MIPS16 with abicalls, as well as the default rdhwr path.

I wanted to fix an RTEMS issue related to thread-local storage on
the MIPS R3900. The R3900 does not support the rdhwr instruction used by
the MIPS backend to access the thread pointer, so RTEMS currently has to
emulate it in its exception handler.

The proposed RTEMS solution is to use a software thread-pointer access
mechanism, similar to the existing ARM -mtp=soft support. This requires
the MIPS GCC backend to provide a corresponding -mtp=soft option that
generates a call to an RTEMS-provided __mips_read_tp helper.
More details here: https://gitlab.rtems.org/rtems/rtos/rtems/-/work_items/5753

gcc/ChangeLog:

        * config/mips/mips-opts.h (enum mips_thread_pointer_setting):
        Add MIPS_TP_SOFT.
        * config/mips/mips.cc (mips_expand_thread_pointer):
        Generate a call to __mips_read_tp when -mtp=soft is used.
        * config/mips/mips.opt: Add -mtp option with rdhwr and soft
        thread-pointer access methods.
        * config/mips/mips.opt.urls: Add URL for -mtp.
        * doc/invoke.texi: Document -mtp.

gcc/testsuite/ChangeLog:

        * gcc.target/mips/tls-hard-tp.c: New test.
        * gcc.target/mips/tls-soft-tp-mips16-abicalls.c: New test.
        * gcc.target/mips/tls-soft-tp-mips16.c: New test.
        * gcc.target/mips/tls-soft-tp.c: New test.
        * gcc.target/mips/mips.exp: Add tp to mips_option_groups.

Signed-off-by: Catalin Miron <[email protected]>
---
 gcc/config/mips/mips-opts.h                     |  6 ++++++
 gcc/config/mips/mips.cc                         | 17 +++++++++++++++--
 gcc/config/mips/mips.opt                        | 14 ++++++++++++++
 gcc/config/mips/mips.opt.urls                   |  3 +++
 gcc/doc/invoke.texi                             |  7 +++++++
 gcc/testsuite/gcc.target/mips/mips.exp          |  1 +
 gcc/testsuite/gcc.target/mips/tls-hard-tp.c     | 13 +++++++++++++
 .../mips/tls-soft-tp-mips16-abicalls.c          | 14 ++++++++++++++
 .../gcc.target/mips/tls-soft-tp-mips16.c        | 14 ++++++++++++++
 gcc/testsuite/gcc.target/mips/tls-soft-tp.c     | 13 +++++++++++++
 10 files changed, 100 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/mips/tls-hard-tp.c
 create mode 100644 gcc/testsuite/gcc.target/mips/tls-soft-tp-mips16-abicalls.c
 create mode 100644 gcc/testsuite/gcc.target/mips/tls-soft-tp-mips16.c
 create mode 100644 gcc/testsuite/gcc.target/mips/tls-soft-tp.c

diff --git a/gcc/config/mips/mips-opts.h b/gcc/config/mips/mips-opts.h
index d8b1b4c632c..c53fdbe4b5c 100644
--- a/gcc/config/mips/mips-opts.h
+++ b/gcc/config/mips/mips-opts.h
@@ -41,6 +41,12 @@ enum mips_r10k_cache_barrier_setting {
   R10K_CACHE_BARRIER_LOAD_STORE
 };
 
+/* Enumerates the setting of the -mtp option.  */
+enum mips_thread_pointer_setting {
+  MIPS_TP_RDHWR,
+  MIPS_TP_SOFT
+};
+
 /* No enumeration is defined to index the -march= values (entries in
    mips_cpu_info_table), with the type int being used instead, but we
    need to distinguish the special "from-abi" and "native" values.  */
diff --git a/gcc/config/mips/mips.cc b/gcc/config/mips/mips.cc
index e54a310b2b4..1930ea6d5c6 100644
--- a/gcc/config/mips/mips.cc
+++ b/gcc/config/mips/mips.cc
@@ -3610,6 +3610,9 @@ mips_add_offset (rtx temp, rtx reg, HOST_WIDE_INT offset)
 /* The __tls_get_attr symbol.  */
 static GTY(()) rtx mips_tls_symbol;
 
+/* The helper used to read the thread pointer in soft mode.  */
+static GTY(()) rtx mips_read_tp_symbol;
+
 /* Return an instruction sequence that calls __tls_get_addr.  SYM is
    the TLS symbol we are referencing and TYPE is the symbol type to use
    (either global dynamic or local dynamic).  V0 is an RTX for the
@@ -3646,9 +3649,19 @@ mips_call_tls_get_addr (rtx sym, enum mips_symbol_type 
type, rtx v0)
 rtx
 mips_expand_thread_pointer (rtx tp)
 {
-  rtx fn;
+  rtx fn, v0;
 
-  if (TARGET_MIPS16)
+  if (mips_thread_pointer == MIPS_TP_SOFT)
+    {
+      if (!mips_read_tp_symbol)
+       mips_read_tp_symbol = init_one_libfunc ("__mips_read_tp");
+
+      v0 = gen_rtx_REG (Pmode, GP_RETURN);
+      mips_expand_call (MIPS_CALL_NORMAL, v0, mips_read_tp_symbol,
+                       const0_rtx, NULL_RTX, false);
+      emit_move_insn (tp, v0);
+    }
+  else if (TARGET_MIPS16)
     {
       if (!mips16_rdhwr_stub)
        mips16_rdhwr_stub = new mips16_rdhwr_one_only_stub ();
diff --git a/gcc/config/mips/mips.opt b/gcc/config/mips/mips.opt
index eb14761ea27..e0fadb4e43a 100644
--- a/gcc/config/mips/mips.opt
+++ b/gcc/config/mips/mips.opt
@@ -425,6 +425,20 @@ mtune=
 Target RejectNegative Joined Var(mips_tune_option) ToLower 
Enum(mips_arch_opt_value)
 -mtune=PROCESSOR       Optimize the output for PROCESSOR.
 
+mtp=
+Target RejectNegative Joined Enum(mips_thread_pointer_setting) 
Var(mips_thread_pointer) Init(MIPS_TP_RDHWR)
+-mtp=METHOD    Specify how to access the thread pointer.
+
+Enum
+Name(mips_thread_pointer_setting) Type(enum mips_thread_pointer_setting)
+Valid arguments to -mtp=:
+
+EnumValue
+Enum(mips_thread_pointer_setting) String(rdhwr) Value(MIPS_TP_RDHWR)
+
+EnumValue
+Enum(mips_thread_pointer_setting) String(soft) Value(MIPS_TP_SOFT)
+
 mstrict-align
 Target Var(TARGET_STRICT_ALIGN) Init(0)
 Don't generate code with unaligned load store, only valid for MIPS R6.
diff --git a/gcc/config/mips/mips.opt.urls b/gcc/config/mips/mips.opt.urls
index 6287d9f1c70..1f1bbef5dc9 100644
--- a/gcc/config/mips/mips.opt.urls
+++ b/gcc/config/mips/mips.opt.urls
@@ -243,6 +243,9 @@ UrlSuffix(gcc/MIPS-Options.html#index-mmadd4)
 mtune=
 UrlSuffix(gcc/MIPS-Options.html#index-mtune-9)
 
+mtp=
+UrlSuffix(gcc/MIPS-Options.html#index-mtp)
+
 mstrict-align
 UrlSuffix(gcc/MIPS-Options.html#index-mstrict-align-3)
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index c5d17c059fd..1bbb90e43f9 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -29125,6 +29125,13 @@ particular member of that family.
 @code{_MIPS_TUNE_@var{foo}}, which work in the same way as the
 @option{-march} ones described above.
 
+@opindex mtp
+@item -mtp=@var{method}
+Specify how to access the thread pointer.  The default, @samp{rdhwr},
+uses the @code{rdhwr $3,$29} instruction.  @samp{soft} generates a call
+to @code{__mips_read_tp} instead.  The helper must return the current
+thread pointer in the normal MIPS function return register.
+
 @opindex mips1
 @item -mips1
 Equivalent to @option{-march=mips1}.
diff --git a/gcc/testsuite/gcc.target/mips/mips.exp 
b/gcc/testsuite/gcc.target/mips/mips.exp
index 9492b1dcaf8..8ded794b761 100644
--- a/gcc/testsuite/gcc.target/mips/mips.exp
+++ b/gcc/testsuite/gcc.target/mips/mips.exp
@@ -314,6 +314,7 @@ foreach option {
     code-readable
     nan
     r10k-cache-barrier
+    tp
     tune
 } {
     lappend mips_option_groups $option "-m$option=.*"
diff --git a/gcc/testsuite/gcc.target/mips/tls-hard-tp.c 
b/gcc/testsuite/gcc.target/mips/tls-hard-tp.c
new file mode 100644
index 00000000000..4b23d561b02
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/tls-hard-tp.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-march=mips32r2 -mgp32 -mno-abicalls" } */
+
+extern __thread int x __attribute__ ((tls_model ("initial-exec")));
+
+int
+foo (void)
+{
+  return x;
+}
+
+/* { dg-final { scan-assembler "rdhwr" } } */
+/* { dg-final { scan-assembler-not "__mips_read_tp" } } */
diff --git a/gcc/testsuite/gcc.target/mips/tls-soft-tp-mips16-abicalls.c 
b/gcc/testsuite/gcc.target/mips/tls-soft-tp-mips16-abicalls.c
new file mode 100644
index 00000000000..11f73026592
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/tls-soft-tp-mips16-abicalls.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=r3900 -mips16 -mtp=soft -mgp32 -mabicalls -mno-shared" 
} */
+
+extern __thread int x __attribute__ ((tls_model ("initial-exec")));
+
+int
+foo (void)
+{
+  return x;
+}
+
+/* { dg-final { scan-assembler "__mips_read_tp" } } */
+/* { dg-final { scan-assembler-not "rdhwr" } } */
+/* { dg-final { scan-assembler-not "__mips16_rdhwr" } } */
diff --git a/gcc/testsuite/gcc.target/mips/tls-soft-tp-mips16.c 
b/gcc/testsuite/gcc.target/mips/tls-soft-tp-mips16.c
new file mode 100644
index 00000000000..0efa8b37cb3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/tls-soft-tp-mips16.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=r3900 -mips16 -mtp=soft -mgp32 -mno-abicalls" } */
+
+extern __thread int x __attribute__ ((tls_model ("initial-exec")));
+
+int
+foo (void)
+{
+  return x;
+}
+
+/* { dg-final { scan-assembler "__mips_read_tp" } } */
+/* { dg-final { scan-assembler-not "rdhwr" } } */
+/* { dg-final { scan-assembler-not "__mips16_rdhwr" } } */
diff --git a/gcc/testsuite/gcc.target/mips/tls-soft-tp.c 
b/gcc/testsuite/gcc.target/mips/tls-soft-tp.c
new file mode 100644
index 00000000000..a771d431dec
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/tls-soft-tp.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-march=r3900 -mtp=soft -mgp32 -mno-abicalls" } */
+
+extern __thread int x __attribute__ ((tls_model ("initial-exec")));
+
+int
+foo (void)
+{
+  return x;
+}
+
+/* { dg-final { scan-assembler "__mips_read_tp" } } */
+/* { dg-final { scan-assembler-not "rdhwr" } } */
-- 
2.43.0

Reply via email to