We can't place a TLS call before a conditional jump in a basic block like

(code_label 13 11 14 4 2 (nil) [1 uses])
(note 14 13 16 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
(jump_insn 16 14 17 4 (set (pc)
        (if_then_else (le (reg:CCNO 17 flags)
                (const_int 0 [0]))
            (label_ref 27)
            (pc))) "x.c":10:21 discrim 1 1462 {*jcc}
     (expr_list:REG_DEAD (reg:CCNO 17 flags)
        (int_list:REG_BR_PROB 628353713 (nil)))
 -> 27)

since the TLS call will clobber flags register.  Instead, we should place
such call before all register setting basic blocks which dominate the
current basic block.

NB: GNU2 TLS:

(insn 66 2 5 2 (parallel [
  (set (reg:DI 116)
       (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 ("tv_cache") [flags 0x5a])
                           ] UNSPEC_DTPOFF))))
  (clobber (reg:CC 17 flags))]) 1678 {*tls_dynamic_gnu2_combine_64_di}
  (nil))

only clobbers flags register.

gcc/

        PR target/121572
        * config/i386/i386-features.cc (ix86_place_single_tls_call): Also
        search for REG_DEAD notes if flag register is alive.  Place the
        TLS call before all FLAGS_REG setting BBs for conditional jump.

gcc/testsuite/

        PR target/121572
        * gcc.target/i386/pr121572-1a.c: New test.
        * gcc.target/i386/pr121572-1b.c: Likewise.

Signed-off-by: H.J. Lu <hjl.to...@gmail.com>
---
 gcc/config/i386/i386-features.cc            | 41 ++++++++++++++++++++-
 gcc/testsuite/gcc.target/i386/pr121572-1a.c | 40 ++++++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr121572-1b.c | 18 +++++++++
 3 files changed, 98 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr121572-1a.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr121572-1b.c

diff --git a/gcc/config/i386/i386-features.cc b/gcc/config/i386/i386-features.cc
index f0bdc5c1880..7cdf98c5778 100644
--- a/gcc/config/i386/i386-features.cc
+++ b/gcc/config/i386/i386-features.cc
@@ -3748,6 +3748,7 @@ ix86_place_single_tls_call (rtx dest, rtx val, 
x86_cse_kind kind,
     bb = get_immediate_dominator (CDI_DOMINATORS,
                                  bb->loop_father->header);
 
+place_tls_call:
   rtx_insn *insn = BB_HEAD (bb);
   while (insn && !NONDEBUG_INSN_P (insn))
     {
@@ -3837,7 +3838,7 @@ ix86_place_single_tls_call (rtx dest, rtx val, 
x86_cse_kind kind,
          && bitmap_bit_p (in, i))
        bitmap_set_bit (live_caller_saved_regs, i);
 
-  if (!bitmap_empty_p (live_caller_saved_regs))
+  if (flags_live_p || !bitmap_empty_p (live_caller_saved_regs))
     {
       /* Search for REG_DEAD notes in this basic block.  */
       FOR_BB_INSNS (bb, insn)
@@ -3845,6 +3846,44 @@ ix86_place_single_tls_call (rtx dest, rtx val, 
x86_cse_kind kind,
          if (!NONDEBUG_INSN_P (insn))
            continue;
 
+         if (JUMP_P (insn))
+           {
+             /* This must be a conditional jump.  */
+             rtx label = JUMP_LABEL (insn);
+             if (label == nullptr
+                 || ANY_RETURN_P (label)
+                 || !(LABEL_P (label) || SYMBOL_REF_P (label)))
+               gcc_unreachable ();
+
+             rtx_insn *set_insn;
+             basic_block set_bb;
+             auto_bitmap set_bbs;
+
+             /* Get all BBs which define FLAGS_REG and dominate the
+                current BB from all DEFs of FLAGS_REG.  */
+             for (df_ref def = DF_REG_DEF_CHAIN (FLAGS_REG);
+                  def;
+                  def = DF_REF_NEXT_REG (def))
+               if (!DF_REF_IS_ARTIFICIAL (def)
+                   && !DF_REF_FLAGS_IS_SET (def, DF_REF_MAY_CLOBBER)
+                   && !DF_REF_FLAGS_IS_SET (def, DF_REF_MUST_CLOBBER))
+                 {
+                   set_insn = DF_REF_INSN (def);
+                   set = single_set (set_insn);
+                   gcc_assert (set);
+                   set_bb = DF_REF_BB (def);
+                   if (dominated_by_p (CDI_DOMINATORS, bb, set_bb))
+                     bitmap_set_bit (set_bbs, set_bb->index);
+                 }
+
+             /* Place the call before all FLAGS_REG setting BBs since
+                we can't place a call before nor after a conditional
+                jump.  */
+             bb = nearest_common_dominator_for_set (CDI_DOMINATORS,
+                                                    set_bbs);
+             goto place_tls_call;
+           }
+
          /* Check if FLAGS register is live.  */
          set = single_set (insn);
          if (set)
diff --git a/gcc/testsuite/gcc.target/i386/pr121572-1a.c 
b/gcc/testsuite/gcc.target/i386/pr121572-1a.c
new file mode 100644
index 00000000000..179a1a9e66c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr121572-1a.c
@@ -0,0 +1,40 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O0 -fpic -fplt -mtls-dialect=gnu" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target { ! ia32 } } 
{^\t?\.} } } */
+
+/*
+**bug:
+**.LFB[0-9]+:
+**...
+**     leaq    tv_cache@tlsld\(%rip\), %rdi
+**     call    __tls_get_addr@PLT
+**     movl    \$-1, %edi
+**     mov[l|q]        %[e|r]ax, %[e|r]bx
+**     call    val@PLT
+**...
+*/
+
+extern __thread int tv_cache __attribute__ ((visibility("hidden")));
+extern void use_cache (int);
+extern int val (int v);
+
+__attribute__((optimize(2)))
+void
+bug (void)
+{
+  int compared = val(-1);
+
+  if (compared == 0 || (compared > 0 && val(2) == 0))
+    {
+      __builtin_trap();
+    }
+
+  if (compared < 0) {
+      use_cache(tv_cache);
+      return;
+  }
+
+  use_cache(tv_cache);
+  __builtin_trap();
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr121572-1b.c 
b/gcc/testsuite/gcc.target/i386/pr121572-1b.c
new file mode 100644
index 00000000000..8a6089109f5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr121572-1b.c
@@ -0,0 +1,18 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O0 -fpic -fplt -mtls-dialect=gnu2" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target { ! ia32 } } 
{^\t?\.} } } */
+
+/*
+**bug:
+**.LFB[0-9]+:
+**...
+**     lea[l|q]        tv_cache@TLSDESC\(%rip\), %[e|r]ax
+**     movl    \$-1, %edi
+**     call    \*tv_cache@TLSCALL\(%[e|r]ax\)
+**     mov[l|q]        %[e|r]ax, %[e|r]bx
+**     call    val@PLT
+**...
+*/
+
+#include "pr121572-1a.c"
-- 
2.50.1

Reply via email to