[PATCH] PR target/96347: non-delegitimized UNSPEC UNSPEC_TP (19) found in variable location

Richard Sandiford richard.sandiford@arm.com
Wed Aug 19 11:22:55 GMT 2020


Iain Buclaw via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
> 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)

Is the is_tls_mem_loc part necessary?  It looks like it's just
repeating the first part of tls_mem_loc_descriptor, and so we
could call that unconditionally instead.

I guess this raises the question: if we swapping the order for
TLS so that MEM_EXPR trumps the MEM address, why shouldn't we take
that approach more generally?  I.e. is there any reason to look at
the MEM_EXPR only when DECL_THREAD_LOCAL_P is true for the base address,
rather than for all symbolic base addresses?

Thanks,
Richard


More information about the Gcc-patches mailing list