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