From: Reshma Roy <[email protected]>

The DRAP register has no reaching definition on function entry, so it
never shows up in DF_LIVE_IN.  When collecting the live caller-saved
registers, additionally set DRAP's bit whenever it is live-in per
DF_LR_IN, so the hoisted TLS call is kept after the DRAP save.

PR target/126382

gcc/ChangeLog:

        * config/i386/i386-features.cc (ix86_emit_tls_call): Additional
          check to see if DRAP register is live in basic block with DF_LR_IN.

gcc/testsuite/ChangeLog:

        * gcc.target/i386/pr126382.c: New test.

---

Hi,

  This patch fix the bug reported in
  https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126382
  x86_cse uses DF_LIVE_IN to place the hoisted __tls_get_addr call, but
  the DRAP register is missing there (no reaching def on entry), so the
  call can land before the DRAP (%r10) save and clobber the by-value argument
  re-read through %r10.
  
  Fix: mark the DRAP register live when DF_LR_IN reports it, keeping
  the TLS call after the DRAP save.

  Bootstrapped and regression tested on x86_64-linux.

Thanks,
  Reshma Roy

 gcc/config/i386/i386-features.cc         |  7 +++++
 gcc/testsuite/gcc.target/i386/pr126382.c | 40 ++++++++++++++++++++++++
 2 files changed, 47 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr126382.c

diff --git a/gcc/config/i386/i386-features.cc b/gcc/config/i386/i386-features.cc
index d65b6ce7672..2c0685a0863 100644
--- a/gcc/config/i386/i386-features.cc
+++ b/gcc/config/i386/i386-features.cc
@@ -4357,6 +4357,13 @@ ix86_emit_tls_call (rtx tls_set, x86_cse_kind kind, 
basic_block bb,
                && !fixed_regs[i]
                && bitmap_bit_p (in, i))
              bitmap_set_bit (live_caller_saved_regs, i);
+         if (df_live && crtl->drap_reg)
+           {
+             /* Check if DRAP is live in this BB with DF_LR_IN.  */
+             i = REGNO (crtl->drap_reg);
+             if (bitmap_bit_p (DF_LR_IN (bb), i))
+               bitmap_set_bit (live_caller_saved_regs, i);
+           }
        }
 
       if (bitmap_empty_p (live_caller_saved_regs))
diff --git a/gcc/testsuite/gcc.target/i386/pr126382.c 
b/gcc/testsuite/gcc.target/i386/pr126382.c
new file mode 100644
index 00000000000..2ffe0074c21
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr126382.c
@@ -0,0 +1,40 @@
+/* { dg-do compile { target { *-*-linux* && lp64 } } } */
+/* { dg-options "-O3 -fPIC -march=x86-64-v4 -fno-asynchronous-unwind-tables 
-mtls-dialect=gnu" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.}  
} } */
+
+/*
+**func:
+**     pushq   %rbp
+**     movq    %rsp, %rbp
+**     pushq   %r12
+**     pushq   %r10
+**     leaq    16\(%rbp\), %r10
+**     pushq   %rbx
+**     movq    %r10, %r12
+**     subq    \$8, %rsp
+**     data16  leaq    FLA_ONE@tlsgd\(%rip\), %rdi
+**     .value  0x6666
+**     rex64
+**     call    __tls_get_addr@PLT
+**...
+*/
+
+typedef struct
+{
+   long n;
+   long m_inner;
+   long n_inner;
+   int base;
+ } FLA_Obj;
+extern __thread FLA_Obj FLA_ONE, W12;
+extern long FLA_Obj_length (FLA_Obj);
+extern void FLA_Obj_width (FLA_Obj, ...);
+void func (FLA_Obj A)
+{
+  while (FLA_Obj_length (A))
+    FLA_Obj_width (FLA_ONE);
+  FLA_Obj_width (FLA_ONE, W12);
+}
+
+/* { dg-final { scan-assembler-times "call\[ \t\]__tls_get_addr@PLT" 2 } } */
-- 
2.34.1

Reply via email to