Hi folks.
The problem here is that while streaming the DECL_NAME with
stream_read_tree() and consequently lto_output_tree(), we trigger an ICE
because we are recursing on the DFS walk:
else
{
/* This is the first time we see EXPR, write all reachable
trees to OB. */
static bool in_dfs_walk;
/* Protect against recursion which means disconnect between
what tree edges we walk in the DFS walk and what edges
we stream out. */
gcc_assert (!in_dfs_walk);
In the namelist fortran testcases, this is the first time we see the
DECL_NAMEs, so we ICE. I fixed this by outputting the DECL_NAME's
string with streamer_write_string() instead.
[I honestly wondered why we don't stream the entire NAMELIST_DECL the
same way we stream IMPORTED_DECL, all in one go, instead of piecemeal
like the present code does. But LTO is this complicated black box in my
head that I try not to think about too much...the current patch touches
as little as possible.]
This change alone fixes the problems in the PR, but I also found another
ICE now that streaming actually works: dwarf. It turns out, that the
way the CONSTRUCTOR elements in the NAMELIST_DECL are streamed, a
PARM_DECL that has been previously seen (in the function's
DECL_ARGUMENTS) will be streamed with different reference magic (or
whatever streamed references or ids are called in LTO speak). So when
we read the CONSTRUCTOR elements in the LTO read phase, we end up with
different pointers for a PARM_DECL in the constructor for the seemingly
same PARM_DECL in the function's arguments (DECL_ARGUMENTS).
I don't understand LTO very well, but I do see that using
stream_read_tree (lto_output_tree) caches the entries, so it seems like
a good fit to avoid writing two distinct items for the same PARM_DECL.
And since the constructor elements have been previously seen, we won't
hit the aforementioned DFS recursion ICE.
It'd be great if the LTO gods could illuminate this abyss (that's you
Mr. Biener ;-)), but the attached patch fixes all the LTO problems
exhibited by:
make check-fortran RUNTESTFLAGS="--target_board=unix'{-flto}'
dg.exp=*namelist*"
As an aside, we really should test some subset of the LTO tests while
testing Fortran, or this oversight will surely repeat itself on any
changes to the Fortran streamer bits.
Does this help? OK?
Aldy
commit a916bfe9fec9b62971cea769ae58d4b3467e08bd
Author: Aldy Hernandez <al...@redhat.com>
Date: Fri Jan 17 08:01:44 2014 -0800
* lto-streamer-in.c (lto_input_tree_ref): Use streamer_read_string
instead of stream_read_tree. Read in constructos with
stream_read_tree.
* lto-streamer-out.c (lto_output_tree_ref): Do not recurse on DFS
walk. Output constructors correctly.
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index df32a6b..9eec472 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -256,12 +256,12 @@ lto_input_tree_ref (struct lto_input_block *ib, struct
data_in *data_in,
result = make_node (NAMELIST_DECL);
TREE_TYPE (result) = void_type_node;
- DECL_NAME (result) = stream_read_tree (ib, data_in);
+ DECL_NAME (result) = get_identifier (streamer_read_string (data_in,
+ ib));
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);
+ tmp = stream_read_tree (ib, data_in);
gcc_assert (tmp != NULL_TREE);
CONSTRUCTOR_APPEND_ELT (nml_decls, NULL_TREE, tmp);
}
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index 5d6aed5..dc48dd4 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -260,12 +260,13 @@ lto_output_tree_ref (struct output_block *ob, tree expr)
tree value, tmp;
streamer_write_record_start (ob, LTO_namelist_decl_ref);
- stream_write_tree (ob, DECL_NAME (expr), true);
+ streamer_write_string (ob, ob->main_stream,
+ IDENTIFIER_POINTER (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);
+ stream_write_tree (ob, value, true);
break;
}