Hi,

On x86, a memory reference reference to a TLS address can be broken out
and stored in a register, for instance:

    movq        %fs:8+testYearsBC@tpoff, %rdx

Subsequently becomes:

    pushq       %rbp
    leaq        8+testYearsBC@tpoff, %rbp
    // later...
    movq        %fs:0(%rbp), %rdx

When it comes to representing this in Dwarf, mem_loc_descriptor is left
with the following RTL, which ix86_delegitimize_tls_address is unable to
handle as the symbol_ref has been swapped out with the temporary.

    (plus:DI (unspec:DI [
                (const_int 0 [0])
            ] UNSPEC_TP)
        (reg/f:DI 6 bp [90]))

The UNSPEC_TP expression is checked, ix86_const_not_ok_for_debug_p
returns false as it only lets through UNSPEC_GOTOFF, and finally
const_ok_for_output is either not smart enough or does not have the
information needed to recognize that UNSPEC_TP is a TLS UNSPEC that
should be ignored.  This results in informational warnings being fired
under -fchecking.

The entrypoint that triggers this warning to occur is that MEM codes are
first lowered with mem_loc_descriptor, with tls_mem_loc_descriptor only
being used if that failed.  This patch switches that around so that TLS
memory expressions first call tls_mem_loc_descriptor, and only use
mem_loc_descriptor if that fails (which may result in UNSPEC warnings).

Bootstrapped and regression tested on x86_64-linux-gnu, I do also have a
sparc64-linux-gnu build at hand, but have not yet got the results to
check for a before/after comparison.

OK for mainline?

Regards
Iain

---
gcc/ChangeLog:

        PR target/96347
        * dwarf2out.c (is_tls_mem_loc): New.
        (mem_loc_descriptor): Call tls_mem_loc_descriptor on TLS memory
        expressions, fallback to mem_loc_descriptor if unsuccessful.
        (loc_descriptor): Likewise.

gcc/testsuite/ChangeLog:

        PR target/96347
        * g++.dg/other/pr96347.C: New test.
---
 gcc/dwarf2out.c                      | 30 ++++++++++----
 gcc/testsuite/g++.dg/other/pr96347.C | 61 ++++++++++++++++++++++++++++
 2 files changed, 84 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/other/pr96347.C

diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 9deca031fc2..093ceb23c7a 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -14435,6 +14435,20 @@ is_based_loc (const_rtx rtl)
               && CONST_INT_P (XEXP (rtl, 1)))));
 }
 
+/* Return true if this MEM expression is for a TLS variable.  */
+
+static bool
+is_tls_mem_loc (rtx mem)
+{
+  tree base;
+
+  if (MEM_EXPR (mem) == NULL_TREE || !MEM_OFFSET_KNOWN_P (mem))
+    return false;
+
+  base = get_base_address (MEM_EXPR (mem));
+  return (base && VAR_P (base) && DECL_THREAD_LOCAL_P (base));
+}
+
 /* Try to handle TLS MEMs, for which mem_loc_descriptor on XEXP (mem, 0)
    failed.  */
 
@@ -15671,11 +15685,12 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
              return mem_loc_result;
          }
       }
-      mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0),
-                                          get_address_mode (rtl), mode,
-                                          VAR_INIT_STATUS_INITIALIZED);
-      if (mem_loc_result == NULL)
+      if (is_tls_mem_loc (rtl))
        mem_loc_result = tls_mem_loc_descriptor (rtl);
+      if (mem_loc_result == NULL)
+       mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0),
+                                            get_address_mode (rtl), mode,
+                                            VAR_INIT_STATUS_INITIALIZED);
       if (mem_loc_result != NULL)
        {
          if (!is_a <scalar_int_mode> (mode, &int_mode)
@@ -16631,10 +16646,11 @@ loc_descriptor (rtx rtl, machine_mode mode,
       break;
 
     case MEM:
-      loc_result = mem_loc_descriptor (XEXP (rtl, 0), get_address_mode (rtl),
-                                      GET_MODE (rtl), initialized);
-      if (loc_result == NULL)
+      if (is_tls_mem_loc (rtl))
        loc_result = tls_mem_loc_descriptor (rtl);
+      if (loc_result == NULL)
+       loc_result = mem_loc_descriptor (XEXP (rtl, 0), get_address_mode (rtl),
+                                        GET_MODE (rtl), initialized);
       if (loc_result == NULL)
        {
          rtx new_rtl = avoid_constant_pool_reference (rtl);
diff --git a/gcc/testsuite/g++.dg/other/pr96347.C 
b/gcc/testsuite/g++.dg/other/pr96347.C
new file mode 100644
index 00000000000..414d10c73de
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/pr96347.C
@@ -0,0 +1,61 @@
+/* { dg-do compile { target c++11 } } */
+/* { dg-require-effective-target tls } */
+/* { dg-options "-O2 -g -fchecking" } */
+
+struct DArray
+{
+  __SIZE_TYPE__ length;
+  int *ptr;
+};
+
+__thread DArray testYearsBC;
+
+struct FilterResult
+{
+  DArray input;
+  bool primed;
+
+  static FilterResult Dthis (FilterResult &pthis, DArray r)
+  {
+    pthis.input = r;
+    return pthis;
+  }
+
+  int front (void)
+  {
+    if (input.length == 0)
+      __builtin_abort ();
+    return input.ptr[0];
+  }
+};
+
+FilterResult filter (DArray range)
+{
+  FilterResult retval;
+  FilterResult::Dthis (retval, range);
+  return retval;
+}
+
+DArray chain (DArray rs)
+{
+  return rs;
+}
+
+struct SysTime
+{
+  static SysTime Dthis (int);
+};
+
+int main (void)
+{
+  while (1)
+    {
+      FilterResult val;
+      __builtin_memset (&val, 0, sizeof (FilterResult));
+      val = filter (chain (testYearsBC));
+      int year = val.front ();
+      (void)year;
+      SysTime::Dthis (0);
+    }
+  return 0;
+}
-- 
2.25.1

Reply via email to