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. 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 <hjl.to...@gmail.com> --- 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