On Wed, Aug 27, 2025 at 6:32 AM H.J. Lu <hjl.to...@gmail.com> wrote:
>
> Source operands of 2 *tls_dynamic_gnu2_call_64_di 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.  Add x86_cse_rtx_equal_p
> to compare source operands of *tls_dynamic_gnu2_call_64_di patterns and
> return true if only source operands differ and they are set from the
> same symbol.
>
> gcc/
>
>         * config/i386/i386-features.cc
>         (pass_x86_cse::x86_cse_rtx_equal_p): New.
>         (pass_x86_cse::tls_set_insn_from_symbol): Likewise.
>         (pass_x86_cse::candidate_gnu2_tls_p): Call
>         tls_set_insn_from_symbol.
>         (pass_x86_cse::x86_cse): Call x86_cse_rtx_equal_p, instead of
>         rtx_equal_p, to compare 2 values.
>
> gcc/testsuite/
>
>         * gcc.target/i386/pr121668-1b.c: New test.
>
> Signed-off-by: H.J. Lu <hjl.to...@gmail.com>
> ---
>  gcc/config/i386/i386-features.cc            | 116 +++++++++++++++-----
>  gcc/testsuite/gcc.target/i386/pr121668-1b.c |   6 +
>  2 files changed, 95 insertions(+), 27 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr121668-1b.c
>
> diff --git a/gcc/config/i386/i386-features.cc 
> b/gcc/config/i386/i386-features.cc
> index 93e20947edf..ce77e91c120 100644
> --- a/gcc/config/i386/i386-features.cc
> +++ b/gcc/config/i386/i386-features.cc
> @@ -4168,8 +4168,95 @@ private:
>    bool candidate_gnu_tls_p (rtx_insn *, attr_tls64);
>    bool candidate_gnu2_tls_p (rtx, attr_tls64);
>    bool candidate_vector_p (rtx);
> +  bool x86_cse_rtx_equal_p (const_rtx, const_rtx);
> +  rtx_insn *tls_set_insn_from_symbol (const_rtx, rtx *);
>  }; // class pass_x86_cse
>
> +/* Return true if X and Y are equal.  */
> +
> +bool
> +pass_x86_cse::x86_cse_rtx_equal_p (const_rtx x, const_rtx y)
> +{
> +  if (kind == X86_CSE_TLSDESC
> +      && GET_CODE (x) == UNSPEC
> +      && XINT (x, 1) == UNSPEC_TLSDESC
> +      && SYMBOL_REF_P (XVECEXP (x, 0, 0)))
> +    {
> +     /* Compare
> +
> +       (unspec:DI [
> +         (symbol_ref:DI ("caml_state") [flags 0x10] <var_decl 0x7fffe99d9e40 
> caml_state>)
> +         (reg:DI 100)
> +         (reg/f:DI 7 sp)
> +       ] UNSPEC_TLSDESC)
> +
> +      against
> +
> +       (unspec:DI [
> +         (symbol_ref:DI ("caml_state") [flags 0x10] <var_decl 0x7fffe99d9e40 
> caml_state>)
> +         (reg:DI 104)
> +         (reg/f:DI 7 sp)
> +       ] UNSPEC_TLSDESC)
> +
> +      If (reg:DI 100) and (reg:DI 104) are defined from the same source,
> +      they are equal.  */
> +
> +      if (GET_CODE (y) != UNSPEC
> +         || XINT (y, 1) != UNSPEC_TLSDESC
> +         || !SYMBOL_REF_P (XVECEXP (y, 0, 0))
> +         || !rtx_equal_p (XVECEXP (x, 0, 0), XVECEXP (y, 0, 0)))
> +       return false;
> +
> +      x = XVECEXP (x, 0, 1);
> +      y = XVECEXP (y, 0, 1);
> +      if (rtx_equal_p (x, y))
> +       return true;
> +
> +      rtx tls_symbol = nullptr;
> +      return (tls_set_insn_from_symbol (x, &tls_symbol)
> +             && tls_symbol
> +             && tls_set_insn_from_symbol (y, &tls_symbol));
> +    }
> +
> +  return rtx_equal_p (x, y);
> +}
> +
> +/* Return the instruction which sets REG from one symbol and store the
> +   symbol in *TLS_SYMBOL_P if *TLS_SYMBOL_P is nullptr.  */
> +
> +rtx_insn *
> +pass_x86_cse::tls_set_insn_from_symbol (const_rtx reg, rtx *tls_symol_p)
> +{
> +  rtx_insn *set_insn = nullptr;
> +  rtx tls_symbol = *tls_symol_p;
> +  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 (tls_symbol == nullptr)
> +       {
> +         if (!SYMBOL_REF_P (tls_src))
> +           return nullptr;
> +
> +         tls_symbol = tls_src;
> +         *tls_symol_p = tls_src;
> +       }
> +      else 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.  */
>
> @@ -4283,32 +4370,7 @@ pass_x86_cse::candidate_gnu2_tls_p (rtx set, 
> attr_tls64 tls64)
>
>         */
>
> -      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;
> -
> -         set_insn = DF_REF_INSN (ref);
> -         tls64 = get_attr_tls64 (set_insn);
> -         if (tls64 != TLS64_LEA)
> -           {
> -             set_insn = nullptr;
> -             break;
> -           }
> -
> -         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;
> -           }
> -       }
> -
> +      rtx_insn *set_insn = tls_set_insn_from_symbol (src, &tls_symbol);
>        if (!set_insn)
>         return false;
>
> @@ -4436,7 +4498,7 @@ pass_x86_cse::x86_cse (void)
>                     /* Non all 0s/1s vector load must be in the same
>                        basic block if it is in a recursive call.  */
>                     || !recursive_call_p)
> -               && rtx_equal_p (load->val, val))
> +               && x86_cse_rtx_equal_p (load->val, val))
Can we just record val as tls_symbol in candidate_gnu2_tls_p, and
adjust code in ix86_place_single_tls_call?
>               {
>                 /* Record instruction.  */
>                 bitmap_set_bit (load->insns, INSN_UID (insn));
> 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 } } } } */
> --
> 2.51.0
>


-- 
BR,
Hongtao

Reply via email to