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
