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.

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.
---
 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