On Sun, Sep 27, 2026 at 4:16 PM mironu <[email protected]> wrote:
>
> 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.

So at Cavium, we had patches to allow us to use a GRP instead of
rdhwr.  This was for Octeon 1 which was just a normal MIPS64r1 (not r2
which added rdhwr); we removed that hack once Octeon 2 came around
which had native rdhwr support (Octeon 3 supported it too).
This was only done for speed reasons because the Linux kernel would do
a trap and handle the rdhwr anyways.
Can you expand on why you want to allow not to use rdhwr? And the
effects on the ABI here; is __mips_read_tp documented as part of some
ABI documentation? Or did you make this up?

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