aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2025-08-27 19:14:13 -0700
committerH.J. Lu <hjl.tools@gmail.com>2025-08-29 05:14:02 -0700
commit62843b3453ee30f77ceb7e09769e0cea9920a2cd (patch)
tree7cd61957101c1cd5d21f91a61c7b590ba9b8f50c
parent34262b9835323907deb653d480f3847950028e35 (diff)
downloadgcc-62843b3453ee30f77ceb7e09769e0cea9920a2cd.zip
gcc-62843b3453ee30f77ceb7e09769e0cea9920a2cd.tar.gz
gcc-62843b3453ee30f77ceb7e09769e0cea9920a2cd.tar.bz2
x86-64: Improve source operand check for TLS_CALL
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.tools@gmail.com>
-rw-r--r--gcc/config/i386/i386-features.cc201
-rw-r--r--gcc/testsuite/gcc.target/i386/pr121668-1b.c6
-rw-r--r--gcc/testsuite/gcc.target/i386/pr121694-1a.c19
-rw-r--r--gcc/testsuite/gcc.target/i386/pr121694-1b.c6
4 files changed, 154 insertions, 78 deletions
diff --git a/gcc/config/i386/i386-features.cc b/gcc/config/i386/i386-features.cc
index 93e2094..5440a02 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 0000000..54a2775
--- /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 0000000..af9c657
--- /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 0000000..76ebbf7
--- /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 } } } } */