On Thu, Aug 28, 2025 at 10:15 AM H.J. Lu <[email protected]> wrote:
>
> Source operands of 2 TLS_CALL patterns in
>
> (insn 10 9 11 3 (set (reg:DI 100)
>         (unspec:DI [
>                 (symbol_ref:DI ("caml_state") [flags 0x10]  <var_decl 
> 0x7fe10e1d9e40 caml_state>)
>             ] UNSPEC_TLSDESC)) "x.c":7:16 1674 {*tls_dynamic_gnu2_lea_64_di}
>      (nil))
> (insn 11 10 12 3 (parallel [
>             (set (reg:DI 99)
>                 (unspec:DI [
>                         (symbol_ref:DI ("caml_state") [flags 0x10]  <var_decl 
> 0x7fe10e1d9e40 caml_state>)
>                         (reg:DI 100)
>                         (reg/f:DI 7 sp)
>                     ] UNSPEC_TLSDESC))
>             (clobber (reg:CC 17 flags))
>         ]) "x.c":7:16 1676 {*tls_dynamic_gnu2_call_64_di}
>      (expr_list:REG_DEAD (reg:DI 100)
>         (expr_list:REG_UNUSED (reg:CC 17 flags)
>             (nil))))
>
> and
>
> (insn 19 17 20 4 (set (reg:DI 104)
>         (unspec:DI [
>                 (symbol_ref:DI ("caml_state") [flags 0x10]  <var_decl 
> 0x7fe10e1d9e40 caml_state>)
>             ] UNSPEC_TLSDESC)) "x.c":6:10 discrim 1 1674 
> {*tls_dynamic_gnu2_lea_64_di}
>      (nil))
> (insn 20 19 21 4 (parallel [
>             (set (reg:DI 103)
>                 (unspec:DI [
>                         (symbol_ref:DI ("caml_state") [flags 0x10]  <var_decl 
> 0x7fe10e1d9e40 caml_state>)
>                         (reg:DI 104)
>                         (reg/f:DI 7 sp)
>                     ] UNSPEC_TLSDESC))
>             (clobber (reg:CC 17 flags))
>         ]) "x.c":6:10 discrim 1 1676 {*tls_dynamic_gnu2_call_64_di}
>      (expr_list:REG_DEAD (reg:DI 104)
>         (expr_list:REG_UNUSED (reg:CC 17 flags)
>             (nil))))
>
> are the same even though rtx_equal_p returns false since (reg:DI 100)
> and (reg:DI 104) are set from the same symbol.  Use the UNSPEC_TLSDESC
> symbol
>
> (unspec:DI [(symbol_ref:DI ("caml_state") [flags 0x10])] UNSPEC_TLSDESC))
>
> to check if 2 TLS_CALL patterns have the same source.
>
> For TLS64_COMBINE, use both UNSPEC_TLSDESC and UNSPEC_DTPOFF unspecs to
> check if 2 TLS64_COMBINE patterns have the same source.
Ok.
>
> gcc/
>
>         PR target/121694
>         * config/i386/i386-features.cc (redundant_pattern): Add
>         tlsdesc_val.
>         (pass_x86_cse): Likewise.
>         ((pass_x86_cse::tls_set_insn_from_symbol): New member function.
>         (pass_x86_cse::candidate_gnu2_tls_p): Set tlsdesc_val.  For
>         TLS64_COMBINE, match both UNSPEC_TLSDESC and UNSPEC_DTPOFF
>         symbols.  For TLS64_CALL, match the UNSPEC_TLSDESC sumbol.
>         (pass_x86_cse::x86_cse): Initialize the tlsdesc_val field in
>         load.  Pass the tlsdesc_val field to ix86_place_single_tls_call
>         for X86_CSE_TLSDESC.
>
> gcc/testsuite/
>
>         PR target/121694
>         * gcc.target/i386/pr121668-1b.c: New test.
>         * gcc.target/i386/pr121694-1a.c: Likewise.
>         * gcc.target/i386/pr121694-1b.c: Likewise.
>
> Signed-off-by: H.J. Lu <[email protected]>
> ---
>  gcc/config/i386/i386-features.cc            | 201 ++++++++++++--------
>  gcc/testsuite/gcc.target/i386/pr121668-1b.c |   6 +
>  gcc/testsuite/gcc.target/i386/pr121694-1a.c |  19 ++
>  gcc/testsuite/gcc.target/i386/pr121694-1b.c |   6 +
>  4 files changed, 154 insertions(+), 78 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr121668-1b.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr121694-1a.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr121694-1b.c
>
> diff --git a/gcc/config/i386/i386-features.cc 
> b/gcc/config/i386/i386-features.cc
> index 93e20947edf..5440a02c442 100644
> --- a/gcc/config/i386/i386-features.cc
> +++ b/gcc/config/i386/i386-features.cc
> @@ -3103,6 +3103,8 @@ struct redundant_pattern
>    auto_bitmap insns;
>    /* The broadcast inner scalar.  */
>    rtx val;
> +  /* The actual redundant source value for UNSPEC_TLSDESC.  */
> +  rtx tlsdesc_val;
>    /* The inner scalar mode.  */
>    machine_mode mode;
>    /* The instruction which sets the inner scalar.  Nullptr if the inner
> @@ -4155,6 +4157,8 @@ public:
>  private:
>    /* The redundant source value.  */
>    rtx val;
> +  /* The actual redundant source value for UNSPEC_TLSDESC.  */
> +  rtx tlsdesc_val;
>    /* The instruction which defines the redundant value.  */
>    rtx_insn *def_insn;
>    /* Mode of the destination of the candidate redundant instruction.  */
> @@ -4168,8 +4172,36 @@ private:
>    bool candidate_gnu_tls_p (rtx_insn *, attr_tls64);
>    bool candidate_gnu2_tls_p (rtx, attr_tls64);
>    bool candidate_vector_p (rtx);
> +  rtx_insn *tls_set_insn_from_symbol (const_rtx, const_rtx);
>  }; // class pass_x86_cse
>
> +/* Return the instruction which sets REG from TLS_SYMBOL.  */
> +
> +rtx_insn *
> +pass_x86_cse::tls_set_insn_from_symbol (const_rtx reg,
> +                                       const_rtx tls_symbol)
> +{
> +  rtx_insn *set_insn = nullptr;
> +  for (df_ref ref = DF_REG_DEF_CHAIN (REGNO (reg));
> +       ref;
> +       ref = DF_REF_NEXT_REG (ref))
> +    {
> +      if (DF_REF_IS_ARTIFICIAL (ref))
> +       return nullptr;
> +
> +      set_insn = DF_REF_INSN (ref);
> +      if (get_attr_tls64 (set_insn) != TLS64_LEA)
> +       return nullptr;
> +
> +      rtx tls_set = PATTERN (set_insn);
> +      rtx tls_src = XVECEXP (SET_SRC (tls_set), 0, 0);
> +      if (!rtx_equal_p (tls_symbol, tls_src))
> +       return nullptr;
> +    }
> +
> +  return set_insn;
> +}
> +
>  /* Return true and output def_insn, val, mode, scalar_mode and kind if
>     INSN is UNSPEC_TLS_GD or UNSPEC_TLS_LD_BASE.  */
>
> @@ -4226,29 +4258,71 @@ pass_x86_cse::candidate_gnu2_tls_p (rtx set, 
> attr_tls64 tls64)
>    if (!TARGET_64BIT || !cfun->machine->tls_descriptor_call_multiple_p)
>      return false;
>
> -  /* Record GNU2 TLS CALLs for 64-bit:
> -
> -     (set (reg/f:DI 104)
> -         (plus:DI (unspec:DI [
> -                     (symbol_ref:DI ("_TLS_MODULE_BASE_") [flags 0x10])
> -                     (reg:DI 114)
> -                     (reg/f:DI 7 sp)] UNSPEC_TLSDESC)
> -                  (const:DI (unspec:DI [
> -                               (symbol_ref:DI ("e") [flags 0x1a])
> -                            ] UNSPEC_DTPOFF))))
> -
> -     (set (reg/f:DI 104)
> -         (plus:DI (unspec:DI [
> -                     (symbol_ref:DI ("_TLS_MODULE_BASE_") [flags 0x10])
> -                     (unspec:DI [
> -                        (symbol_ref:DI ("_TLS_MODULE_BASE_") [flags 0x10])
> -                     ] UNSPEC_TLSDESC)
> -                     (reg/f:DI 7 sp)] UNSPEC_TLSDESC)
> -                  (const:DI (unspec:DI [
> -                               (symbol_ref:DI ("e") [flags 0x1a])
> -                            ] UNSPEC_DTPOFF))))
> +  rtx tls_symbol;
> +  rtx_insn *set_insn;
> +  rtx src = SET_SRC (set);
> +  val = src;
> +  tlsdesc_val = src;
> +  kind = X86_CSE_TLSDESC;
>
> -     and
> +  if (tls64 == TLS64_COMBINE)
> +    {
> +      /* Record 64-bit TLS64_COMBINE:
> +
> +        (set (reg/f:DI 104)
> +             (plus:DI (unspec:DI [
> +                         (symbol_ref:DI ("_TLS_MODULE_BASE_") [flags 0x10])
> +                         (reg:DI 114)
> +                         (reg/f:DI 7 sp)] UNSPEC_TLSDESC)
> +                      (const:DI (unspec:DI [
> +                                   (symbol_ref:DI ("e") [flags 0x1a])
> +                                 ] UNSPEC_DTPOFF))))
> +
> +        (set (reg/f:DI 104)
> +             (plus:DI (unspec:DI [
> +                         (symbol_ref:DI ("_TLS_MODULE_BASE_") [flags 0x10])
> +                         (unspec:DI [
> +                            (symbol_ref:DI ("_TLS_MODULE_BASE_") [flags 
> 0x10])
> +                         ] UNSPEC_TLSDESC)
> +                         (reg/f:DI 7 sp)] UNSPEC_TLSDESC)
> +                      (const:DI (unspec:DI [
> +                                   (symbol_ref:DI ("e") [flags 0x1a])
> +                                ] UNSPEC_DTPOFF))))
> +     */
> +
> +      scalar_mode = mode = GET_MODE (src);
> +      rtx src0 = XEXP (src, 0);
> +      tls_symbol = XVECEXP (src0, 0, 0);
> +      rtx src1 = XVECEXP (src0, 0, 1);
> +      if (REG_P (src1))
> +       {
> +         set_insn = tls_set_insn_from_symbol (src1, tls_symbol);
> +         gcc_assert (set_insn);
> +       }
> +      else
> +       {
> +         set_insn = nullptr;
> +         gcc_assert (GET_CODE (src1) == UNSPEC
> +                     && XINT (src1, 1) == UNSPEC_TLSDESC
> +                     && SYMBOL_REF_P (XVECEXP (src1, 0, 0))
> +                     && rtx_equal_p (XVECEXP (src1, 0, 0), tls_symbol));
> +       }
> +
> +      /* Use TLS_SYMBOL and
> +
> +        (const:DI (unspec:DI [
> +                     (symbol_ref:DI ("e") [flags 0x1a])
> +                  ] UNSPEC_DTPOFF))
> +
> +        as VAL to check if 2 patterns have the same source.  */
> +
> +      rtvec vec = gen_rtvec (2, tls_symbol, XEXP (src, 1));
> +      val = gen_rtx_UNSPEC (mode, vec, UNSPEC_TLSDESC);
> +      def_insn = set_insn;
> +      return true;
> +    }
> +
> +  /* Record 64-bit TLS_CALL:
>
>       (set (reg:DI 101)
>           (unspec:DI [(symbol_ref:DI ("foo") [flags 0x50])
> @@ -4257,70 +4331,33 @@ pass_x86_cse::candidate_gnu2_tls_p (rtx set, 
> attr_tls64 tls64)
>
>     */
>
> -  rtx src = SET_SRC (set);
> -  val = src;
> -  if (tls64 != TLS64_CALL)
> -    src = XEXP (src, 0);
> -
> -  kind = X86_CSE_TLSDESC;
>    gcc_assert (GET_CODE (src) == UNSPEC);
> -  rtx tls_symbol = XVECEXP (src, 0, 0);
> +  tls_symbol = XVECEXP (src, 0, 0);
>    src = XVECEXP (src, 0, 1);
>    scalar_mode = mode = GET_MODE (src);
> -  if (REG_P (src))
> -    {
> -      /* All definitions of reg:DI 129 in
> -
> -        (set (reg:DI 110)
> -             (unspec:DI [(symbol_ref:DI ("foo"))
> -                         (reg:DI 129)
> -                         (reg/f:DI 7 sp)] UNSPEC_TLSDESC))
> -
> -        should have the same source as in
> +  gcc_assert (REG_P (src));
>
> -        (set (reg:DI 129)
> -             (unspec:DI [(symbol_ref:DI ("foo"))] UNSPEC_TLSDESC))
> +  /* All definitions of reg:DI 129 in
>
> -       */
> +     (set (reg:DI 110)
> +         (unspec:DI [(symbol_ref:DI ("foo"))
> +                     (reg:DI 129)
> +                     (reg/f:DI 7 sp)] UNSPEC_TLSDESC))
>
> -      df_ref ref;
> -      rtx_insn *set_insn = nullptr;
> -      for (ref = DF_REG_DEF_CHAIN (REGNO (src));
> -          ref;
> -          ref = DF_REF_NEXT_REG (ref))
> -       {
> -         if (DF_REF_IS_ARTIFICIAL (ref))
> -           break;
> +     should have the same source as in
>
> -         set_insn = DF_REF_INSN (ref);
> -         tls64 = get_attr_tls64 (set_insn);
> -         if (tls64 != TLS64_LEA)
> -           {
> -             set_insn = nullptr;
> -             break;
> -           }
> +     (set (reg:DI 129)
> +         (unspec:DI [(symbol_ref:DI ("foo"))] UNSPEC_TLSDESC))
>
> -         rtx tls_set = PATTERN (set_insn);
> -         rtx tls_src = XVECEXP (SET_SRC (tls_set), 0, 0);
> -         if (!rtx_equal_p (tls_symbol, tls_src))
> -           {
> -             set_insn = nullptr;
> -             break;
> -           }
> -       }
> -
> -      if (!set_insn)
> -       return false;
> +   */
>
> -      def_insn = set_insn;
> -    }
> -  else if (GET_CODE (src) == UNSPEC
> -          && XINT (src, 1) == UNSPEC_TLSDESC
> -          && SYMBOL_REF_P (XVECEXP (src, 0, 0)))
> -    def_insn = nullptr;
> -  else
> -    gcc_unreachable ();
> +  set_insn = tls_set_insn_from_symbol (src, tls_symbol);
> +  if (!set_insn)
> +    return false;
>
> +  /* Use TLS_SYMBOL as VAL to check if 2 patterns have the same source.  */
> +  val = tls_symbol;
> +  def_insn = set_insn;
>    return true;
>  }
>
> @@ -4395,6 +4432,8 @@ pass_x86_cse::x86_cse (void)
>           if (!set && !CALL_P (insn))
>             continue;
>
> +         tlsdesc_val = nullptr;
> +
>           attr_tls64 tls64 = get_attr_tls64 (insn);
>           switch (tls64)
>             {
> @@ -4466,6 +4505,10 @@ pass_x86_cse::x86_cse (void)
>           load = new redundant_pattern;
>
>           load->val = copy_rtx (val);
> +         if (tlsdesc_val)
> +           load->tlsdesc_val = copy_rtx (tlsdesc_val);
> +         else
> +           load->tlsdesc_val = nullptr;
>           load->mode = scalar_mode;
>           load->size = GET_MODE_SIZE (mode);
>           load->def_insn = def_insn;
> @@ -4560,7 +4603,7 @@ pass_x86_cse::x86_cse (void)
>                 {
>                 case X86_CSE_TLSDESC:
>                   ix86_place_single_tls_call (load->broadcast_reg,
> -                                             load->val,
> +                                             load->tlsdesc_val,
>                                               load->kind,
>                                               load->bbs,
>                                               updated_gnu_tls_insns,
> @@ -4606,7 +4649,9 @@ pass_x86_cse::x86_cse (void)
>                 case X86_CSE_TLS_LD_BASE:
>                 case X86_CSE_TLSDESC:
>                   ix86_place_single_tls_call (load->broadcast_reg,
> -                                             load->val,
> +                                             (load->kind == X86_CSE_TLSDESC
> +                                              ? load->tlsdesc_val
> +                                              : load->val),
>                                               load->kind,
>                                               load->bbs,
>                                               updated_gnu_tls_insns,
> diff --git a/gcc/testsuite/gcc.target/i386/pr121668-1b.c 
> b/gcc/testsuite/gcc.target/i386/pr121668-1b.c
> new file mode 100644
> index 00000000000..54a277506f8
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr121668-1b.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-options "-Og -g -fpic -fplt -mtls-dialect=gnu2" } */
> +
> +#include "pr121668-1a.c"
> +
> +/* { dg-final { scan-assembler-times "call\[ 
> \t\]\\*caml_state@TLSCALL\\(%(?:r|e)ax\\)" 1 { target { ! ia32 } } } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr121694-1a.c 
> b/gcc/testsuite/gcc.target/i386/pr121694-1a.c
> new file mode 100644
> index 00000000000..af9c6570134
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr121694-1a.c
> @@ -0,0 +1,19 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-options "-Og -fpic -fplt -mtls-dialect=gnu" } */
> +
> +extern void func1 (long *);
> +extern int func2 (void);
> +extern void func3 (void);
> +static __thread long foo;
> +static __thread long bar;
> +long
> +func (void)
> +{
> +  func1 (&foo);
> +  func1 (&bar);
> +  if (func2 ())
> +    func3 ();
> +  return foo + bar;
> +}
> +
> +/* { dg-final { scan-assembler-times "call\[ \t\]__tls_get_addr@PLT" 1 { 
> target { ! ia32 } } } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr121694-1b.c 
> b/gcc/testsuite/gcc.target/i386/pr121694-1b.c
> new file mode 100644
> index 00000000000..76ebbf7e90b
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr121694-1b.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-options "-Og -fpic -fplt -mtls-dialect=gnu2" } */
> +
> +#include "pr121694-1a.c"
> +
> +/* { dg-final { scan-assembler-times "call\[ 
> \t\]\\*_TLS_MODULE_BASE_@TLSCALL\\(%(?:r|e)ax\\)" 1 { target { ! ia32 } } } } 
> */
> --
> 2.51.0
>


-- 
BR,
Hongtao

Reply via email to