diff mbox

PR37132 – RFC patch for generation of DWARF symbol for Fortran's namelists (DW_TAG_namelist)

Message ID 527E3C96.8030908@net-b.de
State New
Headers show

Commit Message

Tobias Burnus Nov. 9, 2013, 1:45 p.m. UTC
Hi all,

I have a problem generating DW_TAG_namelist dies in conjunction with 
USE-only association.

For a NAMELIST in a module on in a procedure (subroutine, function), one 
generates a DW_TAG_namelist which contains a list of 
DW_TAG_namelist_item. (Works, except that gdb doesn't support 
DW_TAG_namelist at all, cf. Sourceware/gdb PR fortran/15353.)

For "USE mod_name", one just generates DW_TAG_imported_module – and the 
debugger has to find the variables/namelists itself. (Also works.)

But for "USE mod_name, only: nml", one is supposed to generate a 
DW_TAG_imported_declaration.

And there I am stuck. For normal variables, the 
DW_TAG_imported_declaration refers to a DW_TAG_variable die. 
Analogously, for a namelist one would have to refer to a DW_TAG_namelist 
die. But such DW_TAG_namelist comes with a DW_TAG_namelist_item list. 
And for the latter, one needs to have the die of all variables in the 
namelist. But with use-only the symbols aren't use associate and no decl 
or die exists. (Failing call tree with the patch: gfc_trans_use_stmts -> 
dwarf2out_imported_module_or_decl_1 -> force_decl_die.)

What's the proper DWARF way of handling this? Creating a DW_TAG_namelist 
without any DW_TAG_namelist_items, relying on the debugger to pick those 
from the module? Or how is one supposed to handle it?

Would as a first step the patch be acceptable without the change in 
gfc_trans_use_stmts? Without those bits, the patch works and just 
doesn't attempt to generate the DW_TAG_imported_declaration for use-only.

* * *

Regarding the attached patch: It is based on 
http://gcc.gnu.org/ml/gcc-patches/2013-06/msg00534.html and handles
- Namelists in subroutines/functions
- Namelists in modules
- USE association without ONLY

It doesn't handle (see above) USE association with ONLY. (Side note: 
Namelists may not be renamed. [The namelist name appears in the file 
when doing I/O, thus, renaming doesn't make sense.])

For

    integer :: i,
    real :: r
    NAMELIST /nml/ i, r
GCC now generates the output:

  <2><238>: Abbrev Number: 11 (DW_TAG_namelist)
     <239>   DW_AT_name        : nml
     <23d>   DW_AT_sibling     : <0x24c>
  <3><241>: Abbrev Number: 12 (DW_TAG_namelist_item)
     <242>   DW_AT_namelist_items: <0x24c>
  <3><246>: Abbrev Number: 12 (DW_TAG_namelist_item)
     <247>   DW_AT_namelist_items: <0x255>
  <2><24c>: Abbrev Number: 13 (DW_TAG_variable)
     <24d>   DW_AT_name        : i
...



Test case would be (e.g. file1.f90):
   module m
      implicit none
      integer :: ii
      real :: rr
      namelist /nml/ ii, rr
   end module m

subroutine bar()
    complex :: xyz
    namelist /nml/ xyz
    write(*,nml=nml)
end subroutine bar

and as USE-er for "m" (e.g. file2.f90):
   use m, only: nml  ! Or: "use m"
   implicit none
   write(*,nml=nml)
   !   ii = 5
   end


Tobias

Comments

Cary Coutant Nov. 11, 2013, 6:18 p.m. UTC | #1
> But for "USE mod_name, only: nml", one is supposed to generate a
> DW_TAG_imported_declaration.
>
> And there I am stuck. For normal variables, the DW_TAG_imported_declaration
> refers to a DW_TAG_variable die. Analogously, for a namelist one would have
> to refer to a DW_TAG_namelist die. But such DW_TAG_namelist comes with a
> DW_TAG_namelist_item list. And for the latter, one needs to have the die of
> all variables in the namelist. But with use-only the symbols aren't use
> associate and no decl or die exists. (Failing call tree with the patch:
> gfc_trans_use_stmts -> dwarf2out_imported_module_or_decl_1 ->
> force_decl_die.)
>
> What's the proper DWARF way of handling this? Creating a DW_TAG_namelist
> without any DW_TAG_namelist_items, relying on the debugger to pick those
> from the module? Or how is one supposed to handle it?

Why wouldn't you have DIEs for the imported namelist items? I'd think
that once the compiler has processed the USE statement and imported
the namelist into the current compilation unit, it would generate DIEs
for all the imported items, and then be able to construct a
fully-populated DW_TAG_namelist DIE. (At least it would have DIEs for
all the imported items that are actually used in that module, which
should be sufficient for debugging.)

-cary
Tobias Burnus Nov. 12, 2013, 8:13 a.m. UTC | #2
Am 11.11.2013 19:18, schrieb Cary Coutant:
>> But for "USE mod_name, only: nml", one is supposed to generate a
>> DW_TAG_imported_declaration.
>>
>> And there I am stuck. For normal variables, the DW_TAG_imported_declaration
>> refers to a DW_TAG_variable die. Analogously, for a namelist one would have
>> to refer to a DW_TAG_namelist die. But such DW_TAG_namelist comes with a
>> DW_TAG_namelist_item list. And for the latter, one needs to have the die of
>> all variables in the namelist. But with use-only the symbols aren't use
>> associate and no decl or die exists. (Failing call tree with the patch:
>> gfc_trans_use_stmts -> dwarf2out_imported_module_or_decl_1 ->
>> force_decl_die.)
>>
>> What's the proper DWARF way of handling this? Creating a DW_TAG_namelist
>> without any DW_TAG_namelist_items, relying on the debugger to pick those
>> from the module? Or how is one supposed to handle it?
> Why wouldn't you have DIEs for the imported namelist items?I'd think
> that once the compiler has processed the USE statement and imported
> the namelist into the current compilation unit, it would generate DIEs
> for all the imported items, and then be able to construct a
> fully-populated DW_TAG_namelist DIE. (At least it would have DIEs for
> all the imported items that are actually used in that module, which
> should be sufficient for debugging.)

I think in most real-world cases, the module variables in the namelist 
have been imported and are available. But as shown in the example,

subroutine example()
   use mod, only: my_nml
   read(uid, my_nml)
end subroutine example

is possible and there one hasn't imported any of the module variables 
which are in namelist. Still, one might want to do:
   (gdb) print my_nml
to get something like:
   &my_nml i=6, r=8 /

One cannot simply also import, e.g., "i" as the code might have:

subroutine example()
   use mod, only: my_nml
   integer :: i            ! < Locally defined variable
   read(uid, my_nml)
   ...
end subroutine example

In that case "i" is the local variable. As written, one can create a 
decl and a die for the "i" of the module, but the question is how to 
name it.

Tobias
Cary Coutant Nov. 12, 2013, 6:26 p.m. UTC | #3
> One cannot simply also import, e.g., "i" as the code might have:
>
> subroutine example()
>   use mod, only: my_nml
>   integer :: i            ! < Locally defined variable
>   read(uid, my_nml)
>   ...
> end subroutine example
>
> In that case "i" is the local variable. As written, one can create a decl
> and a die for the "i" of the module, but the question is how to name it.

Ah, sorry, I didn't understand how the use statement works with a
namelist. I thought that when you import a namelist, it imports all
the names in that namelist individually, and that the read(...,
my_nml) was equivalent to read(..., ii, rr).

This sounds like a good question for the DWARF workgroup. Could you
forward this thread to dwarf-discuss@lists.dwarfstd.org? We have some
Fortran experts on that list, but I'm not one of them.

-cary
diff mbox

Patch

gcc/
2013-11-09  Tobias Burnus  <burnus@net-b.de>

	PR debug/37132
	* lto-streamer.h (LTO_tags): Add LTO_namelist_decl_ref.
	* tree.def (NAMELIST_DECL): Add.
	* tree.h (NAMELIST_DECL_ASSOCIATED_DECL): New macro.
	* tree.c (initialize_tree_contains_struct): Add asserts for it.
	* dwarf2out.c (gen_namelist_decl): New function.
	(gen_decl_die, dwarf2out_decl): Call it.
	* lto-streamer-in.c (lto_input_tree_ref): Handle NAMELIST_DECL.
	(lto_input_tree_ref, lto_input_tree_1): Update lto_tag_check_range
	call.
	* lto-streamer-out.c (lto_output_tree_ref): Handle NAMELIST_DECL.

gcc/fortran
2013-11-09  Tobias Burnus  <burnus@net-b.de>

	PR debug/37132
	* trans-decl.c (generate_namelist_decl, create_module_nml_decl):
	New static functions.
	(gfc_generate_module_vars, generate_local_vars): Call them.
	(gfc_trans_use_stmts): Handle namelists for debug genertion.

diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 5ef7bd2..67bf631 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -3182,6 +3182,7 @@  static inline int is_redundant_typedef (const_tree);
 static bool is_naming_typedef_decl (const_tree);
 static inline dw_die_ref get_context_die (tree);
 static void gen_namespace_die (tree, dw_die_ref);
+static void gen_namelist_decl (tree, dw_die_ref, tree);
 static dw_die_ref gen_decl_die (tree, tree, dw_die_ref);
 static dw_die_ref force_decl_die (tree);
 static dw_die_ref force_type_die (tree);
@@ -20420,6 +20421,11 @@  gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
 	gen_namespace_die (decl, context_die);
       break;
 
+    case NAMELIST_DECL:
+      gen_namelist_decl (DECL_NAME (decl), context_die,
+			 NAMELIST_DECL_ASSOCIATED_DECL (decl));
+      break;
+
     default:
       /* Probably some frontend-internal decl.  Assume we don't care.  */
       gcc_assert ((int)TREE_CODE (decl) > NUM_TREE_CODES);
@@ -20581,6 +20587,34 @@  dwarf2out_imported_module_or_decl (tree decl, tree name, tree context,
 
 }
 
+/* Output debug information for namelists.   */
+
+static void
+gen_namelist_decl (tree name, dw_die_ref scope_die, tree item_decls)
+{
+  dw_die_ref nml_die, nml_item_die, nml_item_ref_die;
+  tree value;
+  unsigned i;
+
+  if (debug_info_level <= DINFO_LEVEL_TERSE)
+    return;
+
+  gcc_assert (scope_die != NULL);
+  nml_die = new_die (DW_TAG_namelist, scope_die, NULL);
+  add_AT_string (nml_die, DW_AT_name, IDENTIFIER_POINTER (name));
+
+  FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (item_decls), i, value)
+    {
+      nml_item_ref_die = lookup_decl_die (value);
+      if (!nml_item_ref_die)
+	nml_item_ref_die = force_decl_die (value);
+
+      nml_item_die = new_die (DW_TAG_namelist_item, nml_die, NULL);
+      add_AT_die_ref (nml_item_die, DW_AT_namelist_items, nml_item_ref_die);
+    }
+}
+
+
 /* Write the debugging output for DECL.  */
 
 void
@@ -20701,6 +20735,9 @@  dwarf2out_decl (tree decl)
 
       break;
 
+    case NAMELIST_DECL:
+      break;
+
     default:
       return;
     }
diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index c2c736e..b615ff6 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -4140,6 +4140,37 @@  gfc_module_add_decl (struct module_htab_entry *entry, tree decl)
 
 static struct module_htab_entry *cur_module;
 
+
+/* Generate debugging symbols for namelists. This function must come after
+   generate_local_decl to ensure that the variables in the namelist are
+   already declared.  */
+
+static tree
+generate_namelist_decl (gfc_symbol * sym)
+{
+  gfc_namelist *nml;
+  tree decl;
+  vec<constructor_elt, va_gc> *nml_decls = NULL;
+
+  gcc_assert (sym->attr.flavor == FL_NAMELIST);
+  for (nml = sym->namelist; nml; nml = nml->next)
+    {
+      if (nml->sym->backend_decl == NULL_TREE)
+	{
+	  nml->sym->attr.referenced = 1;
+	  nml->sym->backend_decl = gfc_get_symbol_decl (nml->sym);
+	}
+      CONSTRUCTOR_APPEND_ELT (nml_decls, NULL_TREE, nml->sym->backend_decl);
+    }
+
+  decl = make_node (NAMELIST_DECL);
+  TREE_TYPE (decl) = void_type_node;
+  NAMELIST_DECL_ASSOCIATED_DECL (decl) = build_constructor (NULL_TREE, nml_decls);
+  DECL_NAME (decl) = get_identifier (sym->name);
+  return decl;
+}
+
+
 /* Output an initialized decl for a module variable.  */
 
 static void
@@ -4329,6 +4360,18 @@  gfc_trans_use_stmts (gfc_namespace * ns)
 		  DECL_IGNORED_P (decl) = 0;
 		  DECL_INITIAL (decl) = NULL_TREE;
 		}
+	      else if (st->n.sym->attr.flavor == FL_NAMELIST
+		       && st->n.sym->attr.use_only
+		       && st->n.sym->module
+		       && strcmp (st->n.sym->module, use_stmt->module_name)
+			  == 0)
+		{
+		  decl = generate_namelist_decl (st->n.sym);
+		  DECL_CONTEXT (decl) = entry->namespace_decl;
+		  DECL_EXTERNAL (decl) = 1;
+		  DECL_IGNORED_P (decl) = 0;
+		  DECL_INITIAL (decl) = NULL_TREE;
+		}
 	      else
 		{
 		  *slot = error_mark_node;
@@ -4606,6 +4649,21 @@  generate_coarray_init (gfc_namespace * ns __attribute((unused)))
 }
 
 
+static void
+create_module_nml_decl (gfc_symbol *sym)
+{
+  if (sym->attr.flavor == FL_NAMELIST)
+    {
+      tree decl = generate_namelist_decl (sym);
+      pushdecl (decl);
+      gcc_assert (sym->ns->proc_name->attr.flavor == FL_MODULE);
+      DECL_CONTEXT (decl) = sym->ns->proc_name->backend_decl;
+      rest_of_decl_compilation (decl, 1, 0);
+      gfc_module_add_decl (cur_module, decl);
+    }
+}
+
+
 /* Generate all the required code for module variables.  */
 
 void
@@ -4624,6 +4682,7 @@  gfc_generate_module_vars (gfc_namespace * ns)
 
   /* Create decls for all the module variables.  */
   gfc_traverse_ns (ns, gfc_create_module_variable);
+  gfc_traverse_ns (ns, create_module_nml_decl);
 
   if (gfc_option.coarray == GFC_FCOARRAY_LIB && has_coarray_vars)
     generate_coarray_init (ns);
@@ -4889,10 +4948,23 @@  generate_local_decl (gfc_symbol * sym)
     sym->backend_decl = gfc_typenode_for_spec (&(sym->ts));
 }
 
+
+static void
+generate_local_nml_decl (gfc_symbol * sym)
+{
+  if (sym->attr.flavor == FL_NAMELIST && !sym->attr.use_assoc)
+    {
+      tree decl = generate_namelist_decl (sym);
+      pushdecl (decl);
+    }
+}
+
+
 static void
 generate_local_vars (gfc_namespace * ns)
 {
   gfc_traverse_ns (ns, generate_local_decl);
+  gfc_traverse_ns (ns, generate_local_nml_decl);
 }
 
 
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index d4a52a7..138852a 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -200,7 +200,7 @@  lto_input_tree_ref (struct lto_input_block *ib, struct data_in *data_in,
   unsigned HOST_WIDE_INT ix_u;
   tree result = NULL_TREE;
 
-  lto_tag_check_range (tag, LTO_field_decl_ref, LTO_global_decl_ref);
+  lto_tag_check_range (tag, LTO_field_decl_ref, LTO_namelist_decl_ref);
 
   switch (tag)
     {
@@ -244,6 +244,28 @@  lto_input_tree_ref (struct lto_input_block *ib, struct data_in *data_in,
       result = lto_file_decl_data_get_var_decl (data_in->file_data, ix_u);
       break;
 
+    case LTO_namelist_decl_ref:
+      {
+	tree tmp;
+	vec<constructor_elt, va_gc> *nml_decls = NULL;
+	unsigned i, n;
+
+	result = make_node (NAMELIST_DECL);
+	TREE_TYPE (result) = void_type_node;
+	DECL_NAME (result) = stream_read_tree (ib, data_in);
+	n = streamer_read_uhwi (ib);
+	for (i = 0; i < n; i++)
+	  {
+	    ix_u = streamer_read_uhwi (ib);
+	    tmp = lto_file_decl_data_get_var_decl (data_in->file_data, ix_u);
+	    gcc_assert (tmp != NULL_TREE);
+	    CONSTRUCTOR_APPEND_ELT (nml_decls, NULL_TREE, tmp);
+	  }
+	NAMELIST_DECL_ASSOCIATED_DECL (result) = build_constructor (NULL_TREE,
+								    nml_decls);
+	break;
+      }
+
     default:
       gcc_unreachable ();
     }
@@ -1234,7 +1256,7 @@  lto_input_tree_1 (struct lto_input_block *ib, struct data_in *data_in,
 
   if (tag == LTO_null)
     result = NULL_TREE;
-  else if (tag >= LTO_field_decl_ref && tag <= LTO_global_decl_ref)
+  else if (tag >= LTO_field_decl_ref && tag <= LTO_namelist_decl_ref)
     {
       /* If TAG is a reference to an indexable tree, the next value
 	 in IB is the index into the table where we expect to find
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index 5518623..2032e3b 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -49,6 +49,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "cfgloop.h"
 
 
+static void lto_write_tree (struct output_block*, tree, bool);
+
 /* Clear the line info stored in DATA_IN.  */
 
 static void
@@ -245,6 +247,21 @@  lto_output_tree_ref (struct output_block *ob, tree expr)
       lto_output_type_decl_index (ob->decl_state, ob->main_stream, expr);
       break;
 
+    case NAMELIST_DECL:
+      {
+	unsigned i;
+	tree value, tmp;
+
+	streamer_write_record_start (ob, LTO_namelist_decl_ref);
+	stream_write_tree (ob, DECL_NAME (expr), true);
+	tmp = NAMELIST_DECL_ASSOCIATED_DECL (expr);
+	gcc_assert (tmp != NULL_TREE);
+	streamer_write_uhwi (ob, CONSTRUCTOR_ELTS (tmp)->length());
+	FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (tmp), i, value)
+	  lto_output_var_decl_index (ob->decl_state, ob->main_stream, value);
+	break;
+      }
+
     case NAMESPACE_DECL:
       streamer_write_record_start (ob, LTO_namespace_decl_ref);
       lto_output_namespace_decl_index (ob->decl_state, ob->main_stream, expr);
diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h
index 797e92e..fb3a947 100644
--- a/gcc/lto-streamer.h
+++ b/gcc/lto-streamer.h
@@ -222,7 +222,8 @@  enum LTO_tags
   LTO_const_decl_ref,
   LTO_imported_decl_ref,
   LTO_translation_unit_decl_ref,
-  LTO_global_decl_ref,			/* Do not change.  */
+  LTO_global_decl_ref,
+  LTO_namelist_decl_ref,		/* Do not change.  */
 
   /* This tag must always be last.  */
   LTO_NUM_TAGS
diff --git a/gcc/tree.c b/gcc/tree.c
index 686a680..f5a2f44 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -540,6 +540,8 @@  initialize_tree_contains_struct (void)
   gcc_assert (tree_contains_struct[FUNCTION_DECL][TS_FUNCTION_DECL]);
   gcc_assert (tree_contains_struct[IMPORTED_DECL][TS_DECL_MINIMAL]);
   gcc_assert (tree_contains_struct[IMPORTED_DECL][TS_DECL_COMMON]);
+  gcc_assert (tree_contains_struct[NAMELIST_DECL][TS_DECL_MINIMAL]);
+  gcc_assert (tree_contains_struct[NAMELIST_DECL][TS_DECL_COMMON]);
 }
 
 
diff --git a/gcc/tree.def b/gcc/tree.def
index 399b5af..8514f7d 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -377,6 +377,16 @@  DEFTREECODE (NAMESPACE_DECL, "namespace_decl", tcc_declaration, 0)
    IMPORTED_DECL_ASSOCIATED_DECL (NODE) accesses the imported declaration.  */
 DEFTREECODE (IMPORTED_DECL, "imported_decl", tcc_declaration, 0)
 
+/* A namelist declaration.
+   The Fortran FE uses this to represent a namelist statement, e.g.:
+   NAMELIST /namelist-group-name/ namelist-group-object-list.
+   Whenever a declaration import appears in a lexical block, the BLOCK node
+   representing that lexical block in GIMPLE will contain an NAMELIST_DECL
+   node, linked via BLOCK_VARS accessor of the said BLOCK.
+   For a given NODE which code is NAMELIST_DECL,
+   NAMELIST_DECL_ASSOCIATED_DECL (NODE) accesses the imported declaration.  */
+DEFTREECODE (NAMELIST_DECL, "namelist_decl", tcc_declaration, 0)
+
 /* A translation unit.  This is not technically a declaration, since it
    can't be looked up, but it's close enough.  */
 DEFTREECODE (TRANSLATION_UNIT_DECL, "translation_unit_decl",\
diff --git a/gcc/tree.h b/gcc/tree.h
index c4b23d0..5e16b57 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2664,6 +2664,11 @@  extern vec<tree, va_gc> **decl_debug_args_insert (tree);
 #define IMPORTED_DECL_ASSOCIATED_DECL(NODE) \
 (DECL_INITIAL (IMPORTED_DECL_CHECK (NODE)))
 
+/* Getter of the symbol declaration associated with the
+   NAMELIST_DECL node.  */
+#define NAMELIST_DECL_ASSOCIATED_DECL(NODE) \
+  (DECL_INITIAL (NODE))
+
 /* A STATEMENT_LIST chains statements together in GENERIC and GIMPLE.
    To reduce overhead, the nodes containing the statements are not trees.
    This avoids the overhead of tree_common on all linked list elements.