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
