diff mbox

Enhance array types debug info. for Ada

Message ID 5406D305.1060905@adacore.com
State New
Headers show

Commit Message

Pierre-Marie de Rodat Sept. 3, 2014, 8:36 a.m. UTC
Hi!

I'm currently working on improving the debug information output for GNAT 
(the Ada frontend in GCC), which currently uses non-standard DWARF to 
describe complex types. Lately, I focused on debug information for 
arrays and the attached inter-dependent patches are an attempt to do so:

   - they enhance the existing "array_descr_info" language hook;
   - they adjust the Fortran front-end accordingly (it's the only 
array_descr_info user currently);
   - they make the Ada front-end use this hook.

Here are more details about what motivated each patch:


  1. This first patch enhances the array_descr_info language hook so 
that front-end can pass more information about array types to the DWARF 
backend:

     - Array ordering (column/row major) so that the information that 
Fortran arrays are column major ordered comes from the Fortran front-end 
and so that later GNAT can decide itself for each array type (they can 
be both column and row major ordered).

     - Bounds type: Ada arrays can be indexed by integers but also 
characters, enumerated types, etc. However it seems that the middle-end 
makes the assumption that every array index is sizetype so this 
information is needed here for accurate debug info.

     It also makes the language hook generate "GNAT descriptive type" 
attributes for array types, just as the regular array types handling in 
dwarf2out.c does.

     Finally, it makes the DWARF back-end initialize the 
"array_descr_info" structure so that new fields can be added to it later 
without affecting existing front-ends that use this hook.


  2. Currently, this language hook is enabled only when (dwarf_version 
 >= 3 || !dwarf_strict). The hook generates information that is mostly 
valid for strict DWARFv2, though. The second patch enables this language 
hook every time and instead prevents the emission for some attributes 
when needed.


  3. This one enables the array_descr_info hook in GNAT.


  4. This one enhances debug helpers in dwarf2out.c to ease location 
descriptions (DWARF expressions) bugs investigation.


  5. The array_descr_info hook has its own circuitry in dwarf2out.c to 
generate location description: add_descr_info_field. It is a duplicate 
of loc_list_from_tree and less powerful except that it handles 
"self-referencial attributes". This final patch is an attempt to merge 
these two circuitries so that this hook can generate more complex DWARF 
expressions. It also adjusts the Fortran front-end accordingly.


These patches were tested on x86_64-pc-linux-gnu. They trigger no 
regression in the GCC DejaGNU testsuite nor in the GDB one (they fix 
some failures however).

Ok for trunk?

Thank you very much for reading until this point and thank you in 
advance for your review! ;-)

Comments

Pierre-Marie de Rodat Sept. 17, 2014, 2:38 p.m. UTC | #1
Ping for https://gcc.gnu.org/ml/gcc-patches/2014-09/msg00206.html

Adding a few maintainers in copy... Thanks in advance!
Pierre-Marie de Rodat Oct. 3, 2014, 8:59 a.m. UTC | #2
On 09/17/2014 04:38 PM, Pierre-Marie de Rodat wrote:
> Ping for https://gcc.gnu.org/ml/gcc-patches/2014-09/msg00206.html
>
> Adding a few maintainers in copy... Thanks in advance!

Should I enhance something in this patch set in order to make the review 
easier? Thanks!
Jakub Jelinek Oct. 3, 2014, 9:18 a.m. UTC | #3
On Wed, Sep 03, 2014 at 10:36:21AM +0200, Pierre-Marie de Rodat wrote:
> --- a/gcc/dwarf2out.c
> +++ b/gcc/dwarf2out.c
> @@ -17359,18 +17359,36 @@ static void
>  gen_descr_array_type_die (tree type, struct array_descr_info *info,
>  			  dw_die_ref context_die)
>  {
> -  dw_die_ref scope_die = scope_die_for (type, context_die);
> +  dw_die_ref scope_die;
>    dw_die_ref array_die;
>    int dim;
>  
> +  /* Instead of producing a dedicated DW_TAG_array_type DIE for this type, let
> +     the circuitry wrap the main variant with DIEs for qualifiers (for
> +     instance: DW_TAG_const_type, ...).  */
> +  if (type != TYPE_MAIN_VARIANT (type))
> +    {
> +      gen_type_die (TYPE_MAIN_VARIANT (type), context_die);
> +      return;
> +    }

I don't like this, can you explain why?  I'd say that if you only want
to see TYPE_MAIN_VARIANT here, it should be responsibility of the callers
to ensure that.

> @@ -19941,7 +19991,8 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
>    /* If this is an array type with hidden descriptor, handle it first.  */
>    if (!TREE_ASM_WRITTEN (type)
>        && lang_hooks.types.get_array_descr_info
> -      && lang_hooks.types.get_array_descr_info (type, &info)
> +      && lang_hooks.types.get_array_descr_info (type,
> +						init_array_descr_info (&info))

Just memset it to 0 instead?
> +  enum array_descr_ordering ordering;
>    tree element_type;
>    tree base_decl;
>    tree data_location;
>    tree allocated;
>    tree associated;
> +

Why the extra vertical space?
>    struct array_descr_dimen
>      {

> >From 0d683ca8c1fcf8d780928f1cd629e7a99651c9c0 Mon Sep 17 00:00:00 2001
> From: Pierre-Marie de Rodat <derodat@adacore.com>
> Date: Wed, 3 Sep 2014 09:46:25 +0200
> Subject: [PATCH 2/5] Enable the array descr language hook for all DWARF
>  versions
> 
> 	* dwarf2out.c (gen_type_die_with_usage): Enable the array lang-hook
> 	even when (dwarf_version < 3 && dwarf_strict).
> 	(gen_descr_array_die): Do not output DW_AT_data_locationn,
> 	DW_AT_associated, DW_AT_allocated and DW_AT_byte_stride DWARF
> 	attributes when (dwarf_version < 3 && dwarf_strict).

This patch sounds very wrong.  DW_OP_push_object_address is not in DWARF2
either, and that is the basis of all the fields, so there is really nothing
you can really output correctly for DWARF2.  It isn't the default on sane
targets, where GCC defaults to DWARF4 these days, so why bother?
>  #include "real.h"
>  #include "function.h"	/* For pass_by_reference.  */
> +#include "dwarf2out.h"
>  
>  #include "ada.h"
>  #include "adadecode.h"
> @@ -626,6 +627,64 @@ gnat_type_max_size (const_tree gnu_type)
>    return max_unitsize;
>  }
>  
> +/* Provide information in INFO for debug output about the TYPE array type.
> +   Return whether TYPE is handled.  */
> +
> +static bool
> +gnat_get_array_descr_info (const_tree type, struct array_descr_info *info)
> +{
> +  bool convention_fortran_p;
> +  tree index_type;
> +
> +  const_tree dimen, last_dimen;
> +  int i;
> +
> +  if (TREE_CODE (type) != ARRAY_TYPE
> +      || !TYPE_DOMAIN (type)
> +      || !TYPE_INDEX_TYPE (TYPE_DOMAIN (type)))
> +    return false;
> +
> +  /* Count how many dimentions this array has.  */
> +  for (i = 0, dimen = type; ; ++i, dimen = TREE_TYPE (dimen))
> +    if (i > 0
> +	&& (TREE_CODE (dimen) != ARRAY_TYPE
> +	    || !TYPE_MULTI_ARRAY_P (dimen)))
> +      break;
> +  info->ndimensions = i;
> +  convention_fortran_p = TYPE_CONVENTION_FORTRAN_P (type);
> +
> +  /* TODO??? For row major ordering, we probably want to emit nothing and
> +     instead specify it as the default in Dw_TAG_compile_unit.  */
> +  info->ordering = (convention_fortran_p
> +		    ? array_descr_ordering_column_major
> +		    : array_descr_ordering_row_major);
> +  info->base_decl = NULL_TREE;
> +  info->data_location = NULL_TREE;
> +  info->allocated = NULL_TREE;
> +  info->associated = NULL_TREE;
> +
> +  for (i = (convention_fortran_p ? info->ndimensions - 1 : 0),
> +       dimen = type;
> +
> +       0 <= i && i < info->ndimensions;
> +
> +       i += (convention_fortran_p ? -1 : 1),
> +       dimen = TREE_TYPE (dimen))
> +    {
> +      /* We are interested in the stored bounds for the debug info.  */
> +      index_type = TYPE_INDEX_TYPE (TYPE_DOMAIN (dimen));
> +
> +      info->dimen[i].bounds_type = index_type;
> +      info->dimen[i].lower_bound = TYPE_MIN_VALUE (index_type);
> +      info->dimen[i].upper_bound = TYPE_MAX_VALUE (index_type);
> +      last_dimen = dimen;
> +    }
> +
> +  info->element_type = TREE_TYPE (last_dimen);
> +
> +  return true;
> +}
> +
>  /* GNU_TYPE is a subtype of an integral type.  Set LOWVAL to the low bound
>     and HIGHVAL to the high bound, respectively.  */
>  
> @@ -916,6 +975,8 @@ gnat_init_ts (void)
>  #define LANG_HOOKS_TYPE_FOR_SIZE	gnat_type_for_size
>  #undef  LANG_HOOKS_TYPES_COMPATIBLE_P
>  #define LANG_HOOKS_TYPES_COMPATIBLE_P	gnat_types_compatible_p
> +#undef  LANG_HOOKS_GET_ARRAY_DESCR_INFO
> +#define LANG_HOOKS_GET_ARRAY_DESCR_INFO	gnat_get_array_descr_info
>  #undef  LANG_HOOKS_GET_SUBRANGE_BOUNDS
>  #define LANG_HOOKS_GET_SUBRANGE_BOUNDS  gnat_get_subrange_bounds
>  #undef  LANG_HOOKS_DESCRIPTIVE_TYPE
> -- 
> 2.1.0
> 

> >From 166fcbad8529818e492c57b7b9091799bf3ae72d Mon Sep 17 00:00:00 2001
> From: Pierre-Marie de Rodat <derodat@adacore.com>
> Date: Wed, 3 Sep 2014 09:46:29 +0200
> Subject: [PATCH 4/5] Add a few debug utilities for DWARF expressions
> 
> 	* dwarf2out.c (print_loc_descr): New.
> 	(print_dw_val): New.
> 	(print_attribute): New.
> 	(print_loc_descr): New.
> 	(print_die): Use print_dw_val.
> 	(debug_dwarf_loc_descr): New.
> 	* dwarf2out.h (debug_dwarf_loc_descr): New declaration.
> ---
>  gcc/dwarf2out.c | 277 +++++++++++++++++++++++++++++++++++---------------------
>  gcc/dwarf2out.h |   1 +
>  2 files changed, 176 insertions(+), 102 deletions(-)
> 
> diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
> index 78a470f..1638da4 100644
> --- a/gcc/dwarf2out.c
> +++ b/gcc/dwarf2out.c
> @@ -5337,6 +5337,172 @@ print_signature (FILE *outfile, char *sig)
>      fprintf (outfile, "%02x", sig[i] & 0xff);
>  }
>  
> +static void print_loc_descr (dw_loc_descr_ref, FILE *);
> +
> +/* Print the value associated to the VAL DWARF value node to OUTFILE.  If
> +   RECURSE, output location descriptor operations.  */
> +
> +static void
> +print_dw_val (dw_val_node *val, bool recurse, FILE *outfile)
> +{
> +  switch (val->val_class)
> +    {
> +    case dw_val_class_addr:
> +      fprintf (outfile, "address");
> +      break;
> +    case dw_val_class_offset:
> +      fprintf (outfile, "offset");
> +      break;
> +    case dw_val_class_loc:
> +      fprintf (outfile, "location descriptor");
> +      if (val->v.val_loc == NULL)
> +	fprintf (outfile, " -> <null>\n");
> +      else if (recurse)
> +	{
> +	  fprintf (outfile, ":\n");
> +	  print_indent += 4;
> +	  print_loc_descr (val->v.val_loc, outfile);
> +	  print_indent -= 4;
> +	}
> +      else
> +	fprintf (outfile, " (%p)\n", (void *) val->v.val_loc);
> +      break;
> +    case dw_val_class_loc_list:
> +      fprintf (outfile, "location list -> label:%s",
> +	       val->v.val_loc_list->ll_symbol);
> +      break;
> +    case dw_val_class_range_list:
> +      fprintf (outfile, "range list");
> +      break;
> +    case dw_val_class_const:
> +      fprintf (outfile, HOST_WIDE_INT_PRINT_DEC, val->v.val_int);
> +      break;
> +    case dw_val_class_unsigned_const:
> +      fprintf (outfile, HOST_WIDE_INT_PRINT_UNSIGNED, val->v.val_unsigned);
> +      break;
> +    case dw_val_class_const_double:
> +      fprintf (outfile, "constant ("HOST_WIDE_INT_PRINT_DEC","\
> +			HOST_WIDE_INT_PRINT_UNSIGNED")",
> +	       val->v.val_double.high,
> +	       val->v.val_double.low);
> +      break;
> +    case dw_val_class_wide_int:
> +      {
> +	int i = val->v.val_wide->get_len ();
> +	fprintf (outfile, "constant (");
> +	gcc_assert (i > 0);
> +	if (val->v.val_wide->elt (i - 1) == 0)
> +	  fprintf (outfile, "0x");
> +	fprintf (outfile, HOST_WIDE_INT_PRINT_HEX,
> +		 val->v.val_wide->elt (--i));
> +	while (--i >= 0)
> +	  fprintf (outfile, HOST_WIDE_INT_PRINT_PADDED_HEX,
> +		   val->v.val_wide->elt (i));
> +	fprintf (outfile, ")");
> +	break;
> +      }
> +    case dw_val_class_vec:
> +      fprintf (outfile, "floating-point or vector constant");
> +      break;
> +    case dw_val_class_flag:
> +      fprintf (outfile, "%u", val->v.val_flag);
> +      break;
> +    case dw_val_class_die_ref:
> +      if (val->v.val_die_ref.die != NULL)
> +	{
> +	  dw_die_ref die = val->v.val_die_ref.die;
> +
> +	  if (die->comdat_type_p)
> +	    {
> +	      fprintf (outfile, "die -> signature: ");
> +	      print_signature (outfile,
> +			       die->die_id.die_type_node->signature);
> +	    }
> +	  else if (die->die_id.die_symbol)
> +	    fprintf (outfile, "die -> label: %s", die->die_id.die_symbol);
> +	  else
> +	    fprintf (outfile, "die -> %ld", die->die_offset);
> +	  fprintf (outfile, " (%p)", (void *) die);
> +	}
> +      else
> +	fprintf (outfile, "die -> <null>");
> +      break;
> +    case dw_val_class_vms_delta:
> +      fprintf (outfile, "delta: @slotcount(%s-%s)",
> +	       val->v.val_vms_delta.lbl2, val->v.val_vms_delta.lbl1);
> +      break;
> +    case dw_val_class_lbl_id:
> +    case dw_val_class_lineptr:
> +    case dw_val_class_macptr:
> +    case dw_val_class_high_pc:
> +      fprintf (outfile, "label: %s", val->v.val_lbl_id);
> +      break;
> +    case dw_val_class_str:
> +      if (val->v.val_str->str != NULL)
> +	fprintf (outfile, "\"%s\"", val->v.val_str->str);
> +      else
> +	fprintf (outfile, "<null>");
> +      break;
> +    case dw_val_class_file:
> +      fprintf (outfile, "\"%s\" (%d)", val->v.val_file->filename,
> +	       val->v.val_file->emitted_number);
> +      break;
> +    case dw_val_class_data8:
> +      {
> +	int i;
> +
> +	for (i = 0; i < 8; i++)
> +	  fprintf (outfile, "%02x", val->v.val_data8[i]);
> +	break;
> +      }
> +    default:
> +      break;
> +    }
> +}
> +
> +/* Likewise, for a DIE attribute.  */
> +
> +static void
> +print_attribute (dw_attr_ref a, bool recurse, FILE *outfile)
> +{
> +  print_dw_val (&a->dw_attr_val, recurse, outfile);
> +}
> +
> +/* Print the list of operands in the LOC location description to OUTFILE.  This
> +   routine is a debugging aid only.  */
> +
> +static void
> +print_loc_descr (dw_loc_descr_ref loc, FILE *outfile)
> +{
> +  dw_loc_descr_ref l = loc;
> +
> +  if (loc == NULL)
> +    {
> +      print_spaces (outfile);
> +      fprintf (outfile, "<null>\n");
> +      return;
> +    }
> +
> +  for (l = loc; l != NULL; l = l->dw_loc_next)
> +    {
> +      print_spaces (outfile);
> +      fprintf (outfile, "(%p) %s",
> +	       (void *) l,
> +	       dwarf_stack_op_name (l->dw_loc_opc));
> +      if (l->dw_loc_oprnd1.val_class != dw_val_class_none)
> +	{
> +	  fprintf (outfile, " ");
> +	  print_dw_val (&l->dw_loc_oprnd1, false, outfile);
> +	}
> +      if (l->dw_loc_oprnd2.val_class != dw_val_class_none)
> +	{
> +	  fprintf (outfile, ", ");
> +	  print_dw_val (&l->dw_loc_oprnd2, false, outfile);
> +	}
> +      fprintf (outfile, "\n");
> +    }
> +}
> +
>  /* Print the information associated with a given DIE, and its children.
>     This routine is a debugging aid only.  */
>  
> @@ -5369,108 +5535,7 @@ print_die (dw_die_ref die, FILE *outfile)
>        print_spaces (outfile);
>        fprintf (outfile, "  %s: ", dwarf_attr_name (a->dw_attr));
>  
> -      switch (AT_class (a))
> -	{
> -	case dw_val_class_addr:
> -	  fprintf (outfile, "address");
> -	  break;
> -	case dw_val_class_offset:
> -	  fprintf (outfile, "offset");
> -	  break;
> -	case dw_val_class_loc:
> -	  fprintf (outfile, "location descriptor");
> -	  break;
> -	case dw_val_class_loc_list:
> -	  fprintf (outfile, "location list -> label:%s",
> -		   AT_loc_list (a)->ll_symbol);
> -	  break;
> -	case dw_val_class_range_list:
> -	  fprintf (outfile, "range list");
> -	  break;
> -	case dw_val_class_const:
> -	  fprintf (outfile, HOST_WIDE_INT_PRINT_DEC, AT_int (a));
> -	  break;
> -	case dw_val_class_unsigned_const:
> -	  fprintf (outfile, HOST_WIDE_INT_PRINT_UNSIGNED, AT_unsigned (a));
> -	  break;
> -	case dw_val_class_const_double:
> -	  fprintf (outfile, "constant ("HOST_WIDE_INT_PRINT_DEC","\
> -			    HOST_WIDE_INT_PRINT_UNSIGNED")",
> -		   a->dw_attr_val.v.val_double.high,
> -		   a->dw_attr_val.v.val_double.low);
> -	  break;
> -	case dw_val_class_wide_int:
> -	  {
> -	    int i = a->dw_attr_val.v.val_wide->get_len ();
> -	    fprintf (outfile, "constant (");
> -	    gcc_assert (i > 0);
> -	    if (a->dw_attr_val.v.val_wide->elt (i - 1) == 0)
> -	      fprintf (outfile, "0x");
> -	    fprintf (outfile, HOST_WIDE_INT_PRINT_HEX,
> -		     a->dw_attr_val.v.val_wide->elt (--i));
> -	    while (--i >= 0)
> -	      fprintf (outfile, HOST_WIDE_INT_PRINT_PADDED_HEX,
> -		       a->dw_attr_val.v.val_wide->elt (i));
> -	    fprintf (outfile, ")");
> -	    break;
> -	  }
> -	case dw_val_class_vec:
> -	  fprintf (outfile, "floating-point or vector constant");
> -	  break;
> -	case dw_val_class_flag:
> -	  fprintf (outfile, "%u", AT_flag (a));
> -	  break;
> -	case dw_val_class_die_ref:
> -	  if (AT_ref (a) != NULL)
> -	    {
> -	      if (AT_ref (a)->comdat_type_p)
> -	        {
> -		  fprintf (outfile, "die -> signature: ");
> -		  print_signature (outfile,
> -		  		   AT_ref (a)->die_id.die_type_node->signature);
> -                }
> -	      else if (AT_ref (a)->die_id.die_symbol)
> -		fprintf (outfile, "die -> label: %s",
> -		         AT_ref (a)->die_id.die_symbol);
> -	      else
> -		fprintf (outfile, "die -> %ld", AT_ref (a)->die_offset);
> -	      fprintf (outfile, " (%p)", (void *) AT_ref (a));
> -	    }
> -	  else
> -	    fprintf (outfile, "die -> <null>");
> -	  break;
> -	case dw_val_class_vms_delta:
> -	  fprintf (outfile, "delta: @slotcount(%s-%s)",
> -		   AT_vms_delta2 (a), AT_vms_delta1 (a));
> -	  break;
> -	case dw_val_class_lbl_id:
> -	case dw_val_class_lineptr:
> -	case dw_val_class_macptr:
> -	case dw_val_class_high_pc:
> -	  fprintf (outfile, "label: %s", AT_lbl (a));
> -	  break;
> -	case dw_val_class_str:
> -	  if (AT_string (a) != NULL)
> -	    fprintf (outfile, "\"%s\"", AT_string (a));
> -	  else
> -	    fprintf (outfile, "<null>");
> -	  break;
> -	case dw_val_class_file:
> -	  fprintf (outfile, "\"%s\" (%d)", AT_file (a)->filename,
> -		   AT_file (a)->emitted_number);
> -	  break;
> -	case dw_val_class_data8:
> -	  {
> -	    int i;
> -
> -            for (i = 0; i < 8; i++)
> -              fprintf (outfile, "%02x", a->dw_attr_val.v.val_data8[i]);
> -	    break;
> -          }
> -	default:
> -	  break;
> -	}
> -
> +      print_attribute (a, true, outfile);
>        fprintf (outfile, "\n");
>      }
>  
> @@ -5484,6 +5549,14 @@ print_die (dw_die_ref die, FILE *outfile)
>      fprintf (outfile, "\n");
>  }
>  
> +/* Print the list of operations in the LOC location description.  */
> +
> +DEBUG_FUNCTION void
> +debug_dwarf_loc_descr (dw_loc_descr_ref loc)
> +{
> +  print_loc_descr (loc, stderr);
> +}
> +
>  /* Print the information collected for a given DIE.  */
>  
>  DEBUG_FUNCTION void
> diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h
> index 8b03e78..fbcb70a 100644
> --- a/gcc/dwarf2out.h
> +++ b/gcc/dwarf2out.h
> @@ -254,6 +254,7 @@ extern void dwarf2out_emit_cfi (dw_cfi_ref cfi);
>  extern void debug_dwarf (void);
>  struct die_struct;
>  extern void debug_dwarf_die (struct die_struct *);
> +extern void debug_dwarf_loc_descr (dw_loc_descr_ref);
>  extern void debug (die_struct &ref);
>  extern void debug (die_struct *ptr);
>  extern void dwarf2out_set_demangle_name_func (const char *(*) (const char *));
> -- 
> 2.1.0
> 

> >From e029b9300c58a0ffbfa1b7f81381a937a60b27fd Mon Sep 17 00:00:00 2001
> From: Pierre-Marie de Rodat <derodat@adacore.com>
> Date: Wed, 3 Sep 2014 09:46:32 +0200
> Subject: [PATCH 5/5] dwarf2out.c: do not short-circuit add_bound_info in array
>  lang-hook
> 
> gcc/
> 	* dwarf2out.h (struct array_descr_info): Remove the base_decl field.
> 	* dwarf2out.c (init_array_descr_info): Update accordingly.
> 	(enum dw_scalar_form): New.
> 	(add_scalar_info): New.
> 	(loc_list_from_tree): Handle PLACEHOLDER_EXPR nodes for
> 	type-related expressions.
> 	(add_bound_info): Use add_scalar_info.
> 	(descr_info_loc): Remove.
> 	(add_descr_info_field): Remove.
> 	(gen_descr_array_type_die): Switch add_descr_info_field calls
> 	into add_scalar_info/add_bound_info ones.
> 
> gcc/ada/
> 	* gcc-interface/misc.c (gnat_get_array_descr_info): Remove base_decl
> 	initialization.
> 
> gcc/fortran/
> 	* trans-types.c (gfc_get_array_descr_info): Use PLACEHOLDER_EXPR nodes
> 	instead of VAR_DECL ones in type-related expressions.  Remove base_decl
> 	initialization.

Ugh, I must say I don't like PLACEHOLDER_EXPRs at all.

	Jakub
Jakub Jelinek Oct. 3, 2014, 9:20 a.m. UTC | #4
On Fri, Oct 03, 2014 at 11:18:48AM +0200, Jakub Jelinek wrote:
> > gcc/fortran/
> > 	* trans-types.c (gfc_get_array_descr_info): Use PLACEHOLDER_EXPR nodes
> > 	instead of VAR_DECL ones in type-related expressions.  Remove base_decl
> > 	initialization.
> 
> Ugh, I must say I don't like PLACEHOLDER_EXPRs at all.

What kind of more complex expressions do you need and why?

	Jakub
Jason Merrill Oct. 3, 2014, 4:41 p.m. UTC | #5
On 09/17/2014 10:38 AM, Pierre-Marie de Rodat wrote:

Patches 1-4 are OK.

> +  bool pell_conversions = true;

I don't understand "pell".  Do you mean "strip"?

Jason
Pierre-Marie de Rodat Oct. 7, 2014, 8:08 a.m. UTC | #6
On 10/03/2014 06:41 PM, Jason Merrill wrote:
> Patches 1-4 are OK.
>
>> +  bool pell_conversions = true;
>
> I don't understand "pell".  Do you mean "strip"?

Absolutely: I though it was correct English. I replaced all occurences 
of "pell" with "strip". Updates patches will follow...

Thank you very much for your review! :-)
diff mbox

Patch

From e029b9300c58a0ffbfa1b7f81381a937a60b27fd Mon Sep 17 00:00:00 2001
From: Pierre-Marie de Rodat <derodat@adacore.com>
Date: Wed, 3 Sep 2014 09:46:32 +0200
Subject: [PATCH 5/5] dwarf2out.c: do not short-circuit add_bound_info in array
 lang-hook

gcc/
	* dwarf2out.h (struct array_descr_info): Remove the base_decl field.
	* dwarf2out.c (init_array_descr_info): Update accordingly.
	(enum dw_scalar_form): New.
	(add_scalar_info): New.
	(loc_list_from_tree): Handle PLACEHOLDER_EXPR nodes for
	type-related expressions.
	(add_bound_info): Use add_scalar_info.
	(descr_info_loc): Remove.
	(add_descr_info_field): Remove.
	(gen_descr_array_type_die): Switch add_descr_info_field calls
	into add_scalar_info/add_bound_info ones.

gcc/ada/
	* gcc-interface/misc.c (gnat_get_array_descr_info): Remove base_decl
	initialization.

gcc/fortran/
	* trans-types.c (gfc_get_array_descr_info): Use PLACEHOLDER_EXPR nodes
	instead of VAR_DECL ones in type-related expressions.  Remove base_decl
	initialization.
---
 gcc/ada/gcc-interface/misc.c |   1 -
 gcc/dwarf2out.c              | 434 ++++++++++++++++++++-----------------------
 gcc/dwarf2out.h              |   1 -
 gcc/fortran/trans-types.c    |   5 +-
 4 files changed, 203 insertions(+), 238 deletions(-)

diff --git a/gcc/ada/gcc-interface/misc.c b/gcc/ada/gcc-interface/misc.c
index 7449ef9..0661d49 100644
--- a/gcc/ada/gcc-interface/misc.c
+++ b/gcc/ada/gcc-interface/misc.c
@@ -658,7 +658,6 @@  gnat_get_array_descr_info (const_tree type, struct array_descr_info *info)
   info->ordering = (convention_fortran_p
 		    ? array_descr_ordering_column_major
 		    : array_descr_ordering_row_major);
-  info->base_decl = NULL_TREE;
   info->data_location = NULL_TREE;
   info->allocated = NULL_TREE;
   info->associated = NULL_TREE;
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 1638da4..18f46de 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -2981,6 +2981,15 @@  static bool frame_pointer_fb_offset_valid;
 
 static vec<dw_die_ref> base_types;
 
+/* Flags to represent a set of attribute classes for attributes that represent
+   a scalar value (bounds, pointers, ...).  */
+enum dw_scalar_form
+{
+  dw_scalar_form_constant = 0x01,
+  dw_scalar_form_exprloc = 0x02,
+  dw_scalar_form_reference = 0x04
+};
+
 /* Forward declarations for functions defined in this file.  */
 
 static int is_pseudo_reg (const_rtx);
@@ -3186,6 +3195,7 @@  static bool tree_add_const_value_attribute_for_decl (dw_die_ref, tree);
 static void add_name_attribute (dw_die_ref, const char *);
 static void add_gnat_descriptive_type_attribute (dw_die_ref, tree, dw_die_ref);
 static void add_comp_dir_attribute (dw_die_ref);
+static void add_scalar_info (dw_die_ref, enum dwarf_attribute, tree, int);
 static void add_bound_info (dw_die_ref, enum dwarf_attribute, tree);
 static void add_subscript_info (dw_die_ref, tree, bool);
 static void add_byte_size_attribute (dw_die_ref, tree);
@@ -14283,11 +14293,19 @@  loc_list_from_tree (tree loc, int want_address)
 
     case PLACEHOLDER_EXPR:
       /* This case involves extracting fields from an object to determine the
-	 position of other fields.  We don't try to encode this here.  The
-	 only user of this is Ada, which encodes the needed information using
-	 the names of types.  */
-      expansion_failed (loc, NULL_RTX, "PLACEHOLDER_EXPR");
-      return 0;
+	 position of other fields. It is supposed to appear only as the first
+	 operand of COMPONENT_REF nodes.  */
+      if (TREE_CODE (TREE_TYPE (loc)) == RECORD_TYPE
+	  && want_address >= 1)
+	{
+	  ret = new_loc_descr (DW_OP_push_object_address, 0, 0);
+	  have_address = 1;
+	  break;
+	}
+      else
+	expansion_failed (loc, NULL_RTX,
+			  "PLACEHOLDER_EXPR for a non-structure");
+      break;
 
     case CALL_EXPR:
       expansion_failed (loc, NULL_RTX, "CALL_EXPR");
@@ -16389,6 +16407,141 @@  add_comp_dir_attribute (dw_die_ref die)
     add_AT_string (die, DW_AT_comp_dir, wd);
 }
 
+/* Given a tree node VALUE describing a scalar attribute ATTR (i.e. a bound, a
+   pointer computation, ...), output a representation for that bound according
+   to the accepted FORMS (see enum dw_scalar_form) and add it to DIE.  */
+
+static void
+add_scalar_info (dw_die_ref die, enum dwarf_attribute attr, tree value,
+		 int forms)
+{
+  dw_die_ref ctx, decl_die;
+  dw_loc_list_ref list;
+
+  bool pell_conversions = true;
+
+  while (pell_conversions)
+    switch (TREE_CODE (value))
+      {
+      case ERROR_MARK:
+      case SAVE_EXPR:
+	return;
+
+      CASE_CONVERT:
+      case VIEW_CONVERT_EXPR:
+	value = TREE_OPERAND (value, 0);
+	break;
+
+      default:
+	pell_conversions = false;
+	break;
+      }
+
+  /* If possible and permitted, output the attribute as a constant.  */
+  if ((forms & dw_scalar_form_constant) != 0
+      && TREE_CODE (value) == INTEGER_CST)
+    {
+      unsigned int prec = simple_type_size_in_bits (TREE_TYPE (value));
+
+      /* If HOST_WIDE_INT is big enough then represent the bound as
+	 a constant value.  We need to choose a form based on
+	 whether the type is signed or unsigned.  We cannot just
+	 call add_AT_unsigned if the value itself is positive
+	 (add_AT_unsigned might add the unsigned value encoded as
+	 DW_FORM_data[1248]).  Some DWARF consumers will lookup the
+	 bounds type and then sign extend any unsigned values found
+	 for signed types.  This is needed only for
+	 DW_AT_{lower,upper}_bound, since for most other attributes,
+	 consumers will treat DW_FORM_data[1248] as unsigned values,
+	 regardless of the underlying type.  */
+      if (prec <= HOST_BITS_PER_WIDE_INT
+	       || tree_fits_uhwi_p (value))
+	{
+	  if (TYPE_UNSIGNED (TREE_TYPE (value)))
+	    add_AT_unsigned (die, attr, TREE_INT_CST_LOW (value));
+	  else
+	    add_AT_int (die, attr, TREE_INT_CST_LOW (value));
+	}
+      else
+	/* Otherwise represent the bound as an unsigned value with
+	   the precision of its type.  The precision and signedness
+	   of the type will be necessary to re-interpret it
+	   unambiguously.  */
+	add_AT_wide (die, attr, value);
+    }
+
+  /* Otherwise, if it's possible and permitted too, output a reference to
+     another DIE.  */
+  if ((forms & dw_scalar_form_reference) != 0)
+    {
+      tree decl = NULL_TREE;
+
+      /* Some type attributes reference an outer type.  For instance, the upper
+	 bound of an array may reference an embedding record (this happens in
+	 Ada).  */
+      if (TREE_CODE (value) == COMPONENT_REF
+	  && TREE_CODE (TREE_OPERAND (value, 0)) == PLACEHOLDER_EXPR
+	  && TREE_CODE (TREE_OPERAND (value, 1)) == FIELD_DECL)
+	decl = TREE_OPERAND (value, 1);
+
+      else if (TREE_CODE (value) == VAR_DECL
+	       || TREE_CODE (value) == PARM_DECL
+	       || TREE_CODE (value) == RESULT_DECL)
+	decl = value;
+
+      if (decl != NULL_TREE)
+	{
+	  dw_die_ref decl_die = lookup_decl_die (decl);
+
+	  /* ??? Can this happen, or should the variable have been bound
+	     first?  Probably it can, since I imagine that we try to create
+	     the types of parameters in the order in which they exist in
+	     the list, and won't have created a forward reference to a
+	     later parameter.  */
+	  if (decl_die != NULL)
+	    {
+	      add_AT_die_ref (die, attr, decl_die);
+	      return;
+	    }
+	}
+    }
+
+  /* Last chance: try to create a stack operation procedure to evaluate the
+     value.  Do nothing if even that is not possible or permitted.  */
+  if ((forms & dw_scalar_form_exprloc) == 0)
+    return;
+
+  list = loc_list_from_tree (value, 2);
+  if (list == NULL || single_element_loc_list_p (list))
+    {
+      /* If this attribute is not a reference nor constant, it is
+	 a DWARF expression rather than location description.  For that
+	 loc_list_from_tree (value, 0) is needed.  */
+      dw_loc_list_ref list2 = loc_list_from_tree (value, 0);
+      if (list2 && single_element_loc_list_p (list2))
+	{
+	  add_AT_loc (die, attr, list2->expr);
+	  return;
+	}
+    }
+
+  /* If that failed to give a single element location list, fall back to
+     outputting this as a reference... still if permitted.  */
+  if (list == NULL || (forms & dw_scalar_form_reference) == 0)
+    return;
+
+  if (current_function_decl == 0)
+    ctx = comp_unit_die ();
+  else
+    ctx = lookup_decl_die (current_function_decl);
+
+  decl_die = new_die (DW_TAG_variable, ctx, value);
+  add_AT_flag (decl_die, DW_AT_artificial, 1);
+  add_type_attribute (decl_die, TREE_TYPE (value), TYPE_QUAL_CONST, ctx);
+  add_AT_location_description (decl_die, DW_AT_location, list);
+  add_AT_die_ref (die, attr, decl_die);
+}
+
 /* Return the default for DW_AT_lower_bound, or -1 if there is not any
    default.  */
 
@@ -16430,121 +16583,40 @@  lower_bound_default (void)
    a representation for that bound.  */
 
 static void
-add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree bound)
+add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr,
+		tree bound)
 {
-  switch (TREE_CODE (bound))
-    {
-    case ERROR_MARK:
-      return;
+  int dflt;
 
-    /* All fixed-bounds are represented by INTEGER_CST nodes.  */
-    case INTEGER_CST:
+  while (1)
+    switch (TREE_CODE (bound))
       {
-	unsigned int prec = simple_type_size_in_bits (TREE_TYPE (bound));
-	int dflt;
+      /* Pell all conversions.  */
+      CASE_CONVERT:
+      case VIEW_CONVERT_EXPR:
+	bound = TREE_OPERAND (bound, 0);
+	break;
 
-	/* Use the default if possible.  */
+      /* All fixed-bounds are represented by INTEGER_CST nodes.  Lower bounds
+	 are even omitted when they are the default.  */
+      case INTEGER_CST:
+	/* If the value for this bound is the default one, we can even omit the
+	   attribute.  */
 	if (bound_attr == DW_AT_lower_bound
 	    && tree_fits_shwi_p (bound)
 	    && (dflt = lower_bound_default ()) != -1
 	    && tree_to_shwi (bound) == dflt)
-	  ;
-
-	/* If HOST_WIDE_INT is big enough then represent the bound as
-	   a constant value.  We need to choose a form based on
-	   whether the type is signed or unsigned.  We cannot just
-	   call add_AT_unsigned if the value itself is positive
-	   (add_AT_unsigned might add the unsigned value encoded as
-	   DW_FORM_data[1248]).  Some DWARF consumers will lookup the
-	   bounds type and then sign extend any unsigned values found
-	   for signed types.  This is needed only for
-	   DW_AT_{lower,upper}_bound, since for most other attributes,
-	   consumers will treat DW_FORM_data[1248] as unsigned values,
-	   regardless of the underlying type.  */
-	else if (prec <= HOST_BITS_PER_WIDE_INT
-		 || tree_fits_uhwi_p (bound))
-	  {
-	    if (TYPE_UNSIGNED (TREE_TYPE (bound)))
-	      add_AT_unsigned (subrange_die, bound_attr,
-			       TREE_INT_CST_LOW (bound));
-	    else
-	      add_AT_int (subrange_die, bound_attr, TREE_INT_CST_LOW (bound));
-	  }
-	else
-	  /* Otherwise represent the bound as an unsigned value with
-	     the precision of its type.  The precision and signedness
-	     of the type will be necessary to re-interpret it
-	     unambiguously.  */
-	  add_AT_wide (subrange_die, bound_attr, bound);
-      }
-      break;
-
-    CASE_CONVERT:
-    case VIEW_CONVERT_EXPR:
-      add_bound_info (subrange_die, bound_attr, TREE_OPERAND (bound, 0));
-      break;
-
-    case SAVE_EXPR:
-      break;
-
-    case VAR_DECL:
-    case PARM_DECL:
-    case RESULT_DECL:
-      {
-	dw_die_ref decl_die = lookup_decl_die (bound);
-
-	/* ??? Can this happen, or should the variable have been bound
-	   first?  Probably it can, since I imagine that we try to create
-	   the types of parameters in the order in which they exist in
-	   the list, and won't have created a forward reference to a
-	   later parameter.  */
-	if (decl_die != NULL)
-	  {
-	    add_AT_die_ref (subrange_die, bound_attr, decl_die);
-	    break;
-	  }
-      }
-      /* FALLTHRU */
-
-    default:
-      {
-	/* Otherwise try to create a stack operation procedure to
-	   evaluate the value of the array bound.  */
-
-	dw_die_ref ctx, decl_die;
-	dw_loc_list_ref list;
-
-	list = loc_list_from_tree (bound, 2);
-	if (list == NULL || single_element_loc_list_p (list))
-	  {
-	    /* If DW_AT_*bound is not a reference nor constant, it is
-	       a DWARF expression rather than location description.
-	       For that loc_list_from_tree (bound, 0) is needed.
-	       If that fails to give a single element list,
-	       fall back to outputting this as a reference anyway.  */
-	    dw_loc_list_ref list2 = loc_list_from_tree (bound, 0);
-	    if (list2 && single_element_loc_list_p (list2))
-	      {
-		add_AT_loc (subrange_die, bound_attr, list2->expr);
-		break;
-	      }
-	  }
-	if (list == NULL)
-	  break;
+	  return;
 
-	if (current_function_decl == 0)
-	  ctx = comp_unit_die ();
-	else
-	  ctx = lookup_decl_die (current_function_decl);
+	/* FALLTHRU */
 
-	decl_die = new_die (DW_TAG_variable, ctx, bound);
-	add_AT_flag (decl_die, DW_AT_artificial, 1);
-	add_type_attribute (decl_die, TREE_TYPE (bound), TYPE_QUAL_CONST, ctx);
-	add_AT_location_description (decl_die, DW_AT_location, list);
-	add_AT_die_ref (subrange_die, bound_attr, decl_die);
-	break;
+      default:
+	add_scalar_info (subrange_die, bound_attr, bound,
+			 dw_scalar_form_constant
+			 | dw_scalar_form_exprloc
+			 | dw_scalar_form_reference);
+	return;
       }
-    }
 }
 
 /* Add subscript info to TYPE_DIE, describing an array TYPE, collapsing
@@ -17332,99 +17404,6 @@  gen_array_type_die (tree type, dw_die_ref context_die)
     add_pubtype (type, array_die);
 }
 
-static dw_loc_descr_ref
-descr_info_loc (tree val, tree base_decl)
-{
-  HOST_WIDE_INT size;
-  dw_loc_descr_ref loc, loc2;
-  enum dwarf_location_atom op;
-
-  if (val == base_decl)
-    return new_loc_descr (DW_OP_push_object_address, 0, 0);
-
-  switch (TREE_CODE (val))
-    {
-    CASE_CONVERT:
-      return descr_info_loc (TREE_OPERAND (val, 0), base_decl);
-    case VAR_DECL:
-      return loc_descriptor_from_tree (val, 0);
-    case INTEGER_CST:
-      if (tree_fits_shwi_p (val))
-	return int_loc_descriptor (tree_to_shwi (val));
-      break;
-    case INDIRECT_REF:
-      size = int_size_in_bytes (TREE_TYPE (val));
-      if (size < 0)
-	break;
-      loc = descr_info_loc (TREE_OPERAND (val, 0), base_decl);
-      if (!loc)
-	break;
-      if (size == DWARF2_ADDR_SIZE)
-	add_loc_descr (&loc, new_loc_descr (DW_OP_deref, 0, 0));
-      else
-	add_loc_descr (&loc, new_loc_descr (DW_OP_deref_size, size, 0));
-      return loc;
-    case POINTER_PLUS_EXPR:
-    case PLUS_EXPR:
-      if (tree_fits_uhwi_p (TREE_OPERAND (val, 1))
-	  && tree_to_uhwi (TREE_OPERAND (val, 1)) < 16384)
-	{
-	  loc = descr_info_loc (TREE_OPERAND (val, 0), base_decl);
-	  if (!loc)
-	    break;
-	  loc_descr_plus_const (&loc, tree_to_shwi (TREE_OPERAND (val, 1)));
-	}
-      else
-	{
-	  op = DW_OP_plus;
-	do_binop:
-	  loc = descr_info_loc (TREE_OPERAND (val, 0), base_decl);
-	  if (!loc)
-	    break;
-	  loc2 = descr_info_loc (TREE_OPERAND (val, 1), base_decl);
-	  if (!loc2)
-	    break;
-	  add_loc_descr (&loc, loc2);
-	  add_loc_descr (&loc2, new_loc_descr (op, 0, 0));
-	}
-      return loc;
-    case MINUS_EXPR:
-      op = DW_OP_minus;
-      goto do_binop;
-    case MULT_EXPR:
-      op = DW_OP_mul;
-      goto do_binop;
-    case EQ_EXPR:
-      op = DW_OP_eq;
-      goto do_binop;
-    case NE_EXPR:
-      op = DW_OP_ne;
-      goto do_binop;
-    default:
-      break;
-    }
-  return NULL;
-}
-
-static void
-add_descr_info_field (dw_die_ref die, enum dwarf_attribute attr,
-		      tree val, tree base_decl)
-{
-  dw_loc_descr_ref loc;
-
-  if (tree_fits_shwi_p (val))
-    {
-      add_AT_unsigned (die, attr, tree_to_shwi (val));
-      return;
-    }
-
-  loc = descr_info_loc (val, base_decl);
-  if (!loc)
-    return;
-
-  add_AT_loc (die, attr, loc);
-}
-
 /* This routine generates DIE for array with hidden descriptor, details
    are filled into *info by a langhook.  */
 
@@ -17466,15 +17445,18 @@  gen_descr_array_type_die (tree type, struct array_descr_info *info,
   if (dwarf_version >= 3 || !dwarf_strict)
     {
       if (info->data_location)
-	add_descr_info_field (array_die, DW_AT_data_location,
-			      info->data_location,
-			      info->base_decl);
+	add_scalar_info (array_die, DW_AT_data_location, info->data_location,
+			 dw_scalar_form_exprloc);
       if (info->associated)
-	add_descr_info_field (array_die, DW_AT_associated, info->associated,
-			      info->base_decl);
+	add_scalar_info (array_die, DW_AT_associated, info->associated,
+			 dw_scalar_form_constant
+			 | dw_scalar_form_exprloc
+			 | dw_scalar_form_reference);
       if (info->allocated)
-	add_descr_info_field (array_die, DW_AT_allocated, info->allocated,
-			      info->base_decl);
+	add_scalar_info (array_die, DW_AT_allocated, info->allocated,
+			 dw_scalar_form_constant
+			 | dw_scalar_form_exprloc
+			 | dw_scalar_form_reference);
     }
 
   add_gnat_descriptive_type_attribute (array_die, type, context_die);
@@ -17489,30 +17471,17 @@  gen_descr_array_type_die (tree type, struct array_descr_info *info,
 			    info->dimen[dim].bounds_type, 0,
 			    context_die);
       if (info->dimen[dim].lower_bound)
-	{
-	  /* If it is the default value, omit it.  */
-	  int dflt;
-
-	  if (tree_fits_shwi_p (info->dimen[dim].lower_bound)
-	      && (dflt = lower_bound_default ()) != -1
-	      && tree_to_shwi (info->dimen[dim].lower_bound) == dflt)
-	    ;
-	  else
-	    add_descr_info_field (subrange_die, DW_AT_lower_bound,
-				  info->dimen[dim].lower_bound,
-				  info->base_decl);
-	}
+	add_bound_info (subrange_die, DW_AT_lower_bound,
+			info->dimen[dim].lower_bound);
       if (info->dimen[dim].upper_bound)
-	add_descr_info_field (subrange_die, DW_AT_upper_bound,
-			      info->dimen[dim].upper_bound,
-			      info->base_decl);
-      if (dwarf_version >= 3 || !dwarf_strict)
-	{
-	  if (info->dimen[dim].stride)
-	    add_descr_info_field (subrange_die, DW_AT_byte_stride,
-				  info->dimen[dim].stride,
-				  info->base_decl);
-	}
+	add_bound_info (subrange_die, DW_AT_upper_bound,
+			info->dimen[dim].upper_bound);
+      if ((dwarf_version >= 3 || !dwarf_strict) && info->dimen[dim].stride)
+	add_scalar_info (subrange_die, DW_AT_byte_stride,
+			 info->dimen[dim].stride,
+			 dw_scalar_form_constant
+			 | dw_scalar_form_exprloc
+			 | dw_scalar_form_reference);
     }
 
   gen_type_die (info->element_type, context_die);
@@ -19999,7 +19968,6 @@  init_array_descr_info (struct array_descr_info *info)
   info->ndimensions = 0;
   info->ordering = array_descr_ordering_default;
   info->element_type = NULL_TREE;
-  info->base_decl = NULL_TREE;
   info->data_location = NULL_TREE;
   info->allocated = NULL_TREE;
   info->associated = NULL_TREE;
diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h
index fbcb70a..42e89ae 100644
--- a/gcc/dwarf2out.h
+++ b/gcc/dwarf2out.h
@@ -274,7 +274,6 @@  struct array_descr_info
   int ndimensions;
   enum array_descr_ordering ordering;
   tree element_type;
-  tree base_decl;
   tree data_location;
   tree allocated;
   tree associated;
diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c
index 4c10bd9..d73beb9 100644
--- a/gcc/fortran/trans-types.c
+++ b/gcc/fortran/trans-types.c
@@ -3039,11 +3039,10 @@  gfc_get_array_descr_info (const_tree type, struct array_descr_info *info)
   base_decl = GFC_TYPE_ARRAY_BASE_DECL (type, indirect);
   if (!base_decl)
     {
-      base_decl = build_decl (input_location, VAR_DECL, NULL_TREE,
-			      indirect ? build_pointer_type (ptype) : ptype);
+      base_decl = build0 (PLACEHOLDER_EXPR,
+			  indirect ? build_pointer_type (ptype) : ptype);
       GFC_TYPE_ARRAY_BASE_DECL (type, indirect) = base_decl;
     }
-  info->base_decl = base_decl;
   if (indirect)
     base_decl = build1 (INDIRECT_REF, ptype, base_decl);
 
-- 
2.1.0