dwarf2out: For ppc64le IEEE quad long double, emit DW_TAG_typedef to _Float128 [PR104194]

Message ID 20220125110202.GE2646553@tucnak
State New
Headers
Series dwarf2out: For ppc64le IEEE quad long double, emit DW_TAG_typedef to _Float128 [PR104194] |

Commit Message

Jakub Jelinek Jan. 25, 2022, 11:02 a.m. UTC
  On Mon, Jan 24, 2022 at 11:26:27PM +0100, Jakub Jelinek via Gcc-patches wrote:
> Yet another short term solution might be not use DW_TAG_base_type
> for the IEEE quad long double, but instead pretend it is a DW_TAG_typedef
> with DW_AT_name "long double" to __float128 DW_TAG_base_type.
> I bet gdb would even handle it without any changes, but of course, it would
> be larger than the other proposed changes.

Here it is implemented.

Testcases I've played with are e.g.:
__ibm128 a;
long double b;
_Complex long double c;

static __attribute__((noinline)) int
foo (long double d)
{
  long double e = d + 1.0L;
  return 0;
}

int
main ()
{
  a = 1.0;
  b = 2.0;
  c = 5.0 + 6.0i;
  return foo (7.0L);
}
and
  real(kind=16) :: a
  complex(kind=16) :: b
  a = 1.0
  b = 2.0
end

Printing the values of the variables works well,
p &b or p &c shows pointer to the correct type, just
ptype b or ptype c prints _Float128 instead of
long double or complex _Float128 instead of complex long double.
Even worse in fortran where obviously _Float128 or
complex _Float128 aren't valid types, but as GDB knows them by name,
it is just ptype that is weird.

Is this ok for trunk until we get an agreement on which extension
to use (different DW_ATE_*, or DW_AT_GNU_precision or
DW_ATE_GNU_encoding_variant)?

2022-01-25  Jakub Jelinek  <jakub@redhat.com>

	PR debug/104194
	* dwarf2out.cc (long_double_as_float128): New function.
	(modified_type_die): For powerpc64le IEEE 754 quad long double
	and complex long double emit those as DW_TAG_typedef to
	_Float128 or complex _Float128 base type.



	Jakub
  

Comments

Jason Merrill Jan. 25, 2022, 7:24 p.m. UTC | #1
On 1/25/22 06:02, Jakub Jelinek wrote:
> On Mon, Jan 24, 2022 at 11:26:27PM +0100, Jakub Jelinek via Gcc-patches wrote:
>> Yet another short term solution might be not use DW_TAG_base_type
>> for the IEEE quad long double, but instead pretend it is a DW_TAG_typedef
>> with DW_AT_name "long double" to __float128 DW_TAG_base_type.
>> I bet gdb would even handle it without any changes, but of course, it would
>> be larger than the other proposed changes.
> 
> Here it is implemented.
> 
> Testcases I've played with are e.g.:
> __ibm128 a;
> long double b;
> _Complex long double c;
> 
> static __attribute__((noinline)) int
> foo (long double d)
> {
>    long double e = d + 1.0L;
>    return 0;
> }
> 
> int
> main ()
> {
>    a = 1.0;
>    b = 2.0;
>    c = 5.0 + 6.0i;
>    return foo (7.0L);
> }
> and
>    real(kind=16) :: a
>    complex(kind=16) :: b
>    a = 1.0
>    b = 2.0
> end
> 
> Printing the values of the variables works well,
> p &b or p &c shows pointer to the correct type, just
> ptype b or ptype c prints _Float128 instead of
> long double or complex _Float128 instead of complex long double.
> Even worse in fortran where obviously _Float128 or
> complex _Float128 aren't valid types, but as GDB knows them by name,
> it is just ptype that is weird.
> 
> Is this ok for trunk until we get an agreement on which extension
> to use (different DW_ATE_*, or DW_AT_GNU_precision or
> DW_ATE_GNU_encoding_variant)?
> 
> 2022-01-25  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR debug/104194
> 	* dwarf2out.cc (long_double_as_float128): New function.
> 	(modified_type_die): For powerpc64le IEEE 754 quad long double
> 	and complex long double emit those as DW_TAG_typedef to
> 	_Float128 or complex _Float128 base type.
> 
> --- gcc/dwarf2out.cc.jj	2022-01-25 05:47:53.987454934 +0100
> +++ gcc/dwarf2out.cc	2022-01-25 11:54:25.100522089 +0100
> @@ -13568,6 +13568,47 @@ qualified_die_p (dw_die_ref die, int *ma
>     return type;
>   }
>   
> +/* If TYPE is long double or complex long double that
> +   should be emitted as artificial typedef to _Float128 or
> +   complex _Float128, return the type it should be emitted as.
> +   This is done in case the target already supports 16-byte
> +   composite floating point type (ibm_extended_format).  */
> +
> +static tree
> +long_double_as_float128 (tree type)
> +{
> +  if (type != long_double_type_node
> +      && type != complex_long_double_type_node)
> +    return NULL_TREE;
> +
> +  machine_mode mode, fmode;
> +  if (TREE_CODE (type) == COMPLEX_TYPE)
> +    mode = TYPE_MODE (TREE_TYPE (type));
> +  else
> +    mode = TYPE_MODE (type);
> +  if (known_eq (GET_MODE_SIZE (mode), 16) && !MODE_COMPOSITE_P (mode))
> +    FOR_EACH_MODE_IN_CLASS (fmode, MODE_FLOAT)
> +      if (known_eq (GET_MODE_SIZE (fmode), 16)
> +          && MODE_COMPOSITE_P (fmode))
> +	{
> +	  if (type == long_double_type_node)
> +	    {
> +	      if (float128_type_node
> +		  && (TYPE_MODE (float128_type_node)
> +		      == TYPE_MODE (type)))
> +		return float128_type_node;
> +	      return NULL_TREE;
> +	    }
> +	  for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++)
> +	    if (COMPLEX_FLOATN_NX_TYPE_NODE (i) != NULL_TREE
> +		&& (TYPE_MODE (COMPLEX_FLOATN_NX_TYPE_NODE (i))
> +		    == TYPE_MODE (type)))
> +	      return COMPLEX_FLOATN_NX_TYPE_NODE (i);
> +	}

Do we really need this loop to determine if the target supports two 
different long doubles?  This seems like a complicated way of saying
"if this is IEEE 128-bit long double and the target also supports IBM 
double double", return _Float128."

But OK.

> +
> +  return NULL_TREE;
> +}
> +
>   /* Given a pointer to an arbitrary ..._TYPE tree node, return a debugging
>      entry that chains the modifiers specified by CV_QUALS in front of the
>      given type.  REVERSE is true if the type is to be interpreted in the
> @@ -13848,7 +13889,32 @@ modified_type_die (tree type, int cv_qua
>       }
>     else if (is_base_type (type))
>       {
> -      mod_type_die = base_type_die (type, reverse);
> +      /* If a target supports long double as different floating point
> +	 modes with the same 16-byte size, use normal DW_TAG_base_type
> +	 only for the composite (ibm_extended_real_format) type and
> +	 for the other for the time being emit instead a "_Float128"
> +	 or "complex _Float128" DW_TAG_base_type and a "long double"
> +	 or "complex long double" typedef to it.  */
> +      if (tree other_type = long_double_as_float128 (type))
> +	{
> +	  dw_die_ref other_die;
> +	  if (TYPE_NAME (other_type))
> +	    other_die
> +	      = modified_type_die (other_type, TYPE_UNQUALIFIED, reverse,
> +				   context_die);
> +	  else
> +	    {
> +	      other_die = base_type_die (type, reverse);
> +	      add_child_die (comp_unit_die (), other_die);
> +	      add_name_attribute (other_die,
> +				  TREE_CODE (type) == COMPLEX_TYPE
> +				  ? "complex _Float128" : "_Float128");
> +	    }
> +	  mod_type_die = new_die_raw (DW_TAG_typedef);
> +	  add_AT_die_ref (mod_type_die, DW_AT_type, other_die);
> +	}
> +      else
> +	mod_type_die = base_type_die (type, reverse);
>   
>         /* The DIE with DW_AT_endianity is placed right after the naked DIE.  */
>         if (reverse_base_type)
> 
> 
> 	Jakub
>
  
Jakub Jelinek Jan. 25, 2022, 7:36 p.m. UTC | #2
On Tue, Jan 25, 2022 at 02:24:34PM -0500, Jason Merrill wrote:
> > +  machine_mode mode, fmode;
> > +  if (TREE_CODE (type) == COMPLEX_TYPE)
> > +    mode = TYPE_MODE (TREE_TYPE (type));
> > +  else
> > +    mode = TYPE_MODE (type);
> > +  if (known_eq (GET_MODE_SIZE (mode), 16) && !MODE_COMPOSITE_P (mode))
> > +    FOR_EACH_MODE_IN_CLASS (fmode, MODE_FLOAT)
> > +      if (known_eq (GET_MODE_SIZE (fmode), 16)
> > +          && MODE_COMPOSITE_P (fmode))
> > +	{
> > +	  if (type == long_double_type_node)
> > +	    {
> > +	      if (float128_type_node
> > +		  && (TYPE_MODE (float128_type_node)
> > +		      == TYPE_MODE (type)))
> > +		return float128_type_node;
> > +	      return NULL_TREE;
> > +	    }
> > +	  for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++)
> > +	    if (COMPLEX_FLOATN_NX_TYPE_NODE (i) != NULL_TREE
> > +		&& (TYPE_MODE (COMPLEX_FLOATN_NX_TYPE_NODE (i))
> > +		    == TYPE_MODE (type)))
> > +	      return COMPLEX_FLOATN_NX_TYPE_NODE (i);
> > +	}
> 
> Do we really need this loop to determine if the target supports two
> different long doubles?  This seems like a complicated way of saying
> "if this is IEEE 128-bit long double and the target also supports IBM double
> double", return _Float128."

The outermost if and FOR_EACH_MODE_IN_CLASS in it are checking if it is
essentially ppc64le-linux with -mabi=ieeelongdouble, i.e. whether long double
is non-composite 16-byte and the target supports at least one composite
16-byte mode.
The inner loop is because we don't have a complex_float128_type_node macro,
so it needs to be found by iteration or hardcoding which entry it is
(it iterates over those 6 entries for complex _Float{32,64,128}{,x}).

	Jakub
  

Patch

--- gcc/dwarf2out.cc.jj	2022-01-25 05:47:53.987454934 +0100
+++ gcc/dwarf2out.cc	2022-01-25 11:54:25.100522089 +0100
@@ -13568,6 +13568,47 @@  qualified_die_p (dw_die_ref die, int *ma
   return type;
 }
 
+/* If TYPE is long double or complex long double that
+   should be emitted as artificial typedef to _Float128 or
+   complex _Float128, return the type it should be emitted as.
+   This is done in case the target already supports 16-byte
+   composite floating point type (ibm_extended_format).  */
+
+static tree
+long_double_as_float128 (tree type)
+{
+  if (type != long_double_type_node
+      && type != complex_long_double_type_node)
+    return NULL_TREE;
+
+  machine_mode mode, fmode;
+  if (TREE_CODE (type) == COMPLEX_TYPE)
+    mode = TYPE_MODE (TREE_TYPE (type));
+  else
+    mode = TYPE_MODE (type);
+  if (known_eq (GET_MODE_SIZE (mode), 16) && !MODE_COMPOSITE_P (mode))
+    FOR_EACH_MODE_IN_CLASS (fmode, MODE_FLOAT)
+      if (known_eq (GET_MODE_SIZE (fmode), 16)
+          && MODE_COMPOSITE_P (fmode))
+	{
+	  if (type == long_double_type_node)
+	    {
+	      if (float128_type_node
+		  && (TYPE_MODE (float128_type_node)
+		      == TYPE_MODE (type)))
+		return float128_type_node;
+	      return NULL_TREE;
+	    }
+	  for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+	    if (COMPLEX_FLOATN_NX_TYPE_NODE (i) != NULL_TREE
+		&& (TYPE_MODE (COMPLEX_FLOATN_NX_TYPE_NODE (i))
+		    == TYPE_MODE (type)))
+	      return COMPLEX_FLOATN_NX_TYPE_NODE (i);
+	}
+
+  return NULL_TREE;
+}
+
 /* Given a pointer to an arbitrary ..._TYPE tree node, return a debugging
    entry that chains the modifiers specified by CV_QUALS in front of the
    given type.  REVERSE is true if the type is to be interpreted in the
@@ -13848,7 +13889,32 @@  modified_type_die (tree type, int cv_qua
     }
   else if (is_base_type (type))
     {
-      mod_type_die = base_type_die (type, reverse);
+      /* If a target supports long double as different floating point
+	 modes with the same 16-byte size, use normal DW_TAG_base_type
+	 only for the composite (ibm_extended_real_format) type and
+	 for the other for the time being emit instead a "_Float128"
+	 or "complex _Float128" DW_TAG_base_type and a "long double"
+	 or "complex long double" typedef to it.  */
+      if (tree other_type = long_double_as_float128 (type))
+	{
+	  dw_die_ref other_die;
+	  if (TYPE_NAME (other_type))
+	    other_die
+	      = modified_type_die (other_type, TYPE_UNQUALIFIED, reverse,
+				   context_die);
+	  else
+	    {
+	      other_die = base_type_die (type, reverse);
+	      add_child_die (comp_unit_die (), other_die);
+	      add_name_attribute (other_die,
+				  TREE_CODE (type) == COMPLEX_TYPE
+				  ? "complex _Float128" : "_Float128");
+	    }
+	  mod_type_die = new_die_raw (DW_TAG_typedef);
+	  add_AT_die_ref (mod_type_die, DW_AT_type, other_die);
+	}
+      else
+	mod_type_die = base_type_die (type, reverse);
 
       /* The DIE with DW_AT_endianity is placed right after the naked DIE.  */
       if (reverse_base_type)