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

Reply via email to