lto-streamer-out.c (struct sccs): Turn to ...
* lto-streamer-out.c (struct sccs): Turn to ... (class DFS): ... this one; refactor the DFS walk so it can be re-done on per-SCC basis. (DFS::DFS): New constructor. (DFS::~DFS): New destructor. (hash_tree): Add new MAP argument holding in-SCC hash values; remove POINTER_TYPE hashing hack. (scc_entry_compare): Rename to ... (DFS::scc_entry_compare): ... this one. (hash_scc): Rename to ... (DFS::hash_scc): ... this one; pass output_block instead of streamer_cache; work harder to get unique and stable SCC hashes. (DFS_write_tree): Rename to ... (DFS::DFS_write_tree): ... this one; add SINGLE_P parameter. (lto_output_tree): Update. Co-Authored-By: Richard Biener <rguenther@suse.de> From-SVN: r213059
This commit is contained in:
parent
770f687ddb
commit
a4b0388b24
|
@ -1,3 +1,23 @@
|
||||||
|
2014-07-25 Jan Hubicka <hubicka@ucw.cz>
|
||||||
|
Richard Biener <rguenther@suse.de>
|
||||||
|
|
||||||
|
* lto-streamer-out.c (struct sccs): Turn to ...
|
||||||
|
(class DFS): ... this one; refactor the DFS walk so it can
|
||||||
|
be re-done on per-SCC basis.
|
||||||
|
(DFS::DFS): New constructor.
|
||||||
|
(DFS::~DFS): New destructor.
|
||||||
|
(hash_tree): Add new MAP argument holding in-SCC hash values;
|
||||||
|
remove POINTER_TYPE hashing hack.
|
||||||
|
(scc_entry_compare): Rename to ...
|
||||||
|
(DFS::scc_entry_compare): ... this one.
|
||||||
|
(hash_scc): Rename to ...
|
||||||
|
(DFS::hash_scc): ... this one; pass output_block instead
|
||||||
|
of streamer_cache; work harder to get unique and stable SCC
|
||||||
|
hashes.
|
||||||
|
(DFS_write_tree): Rename to ...
|
||||||
|
(DFS::DFS_write_tree): ... this one; add SINGLE_P parameter.
|
||||||
|
(lto_output_tree): Update.
|
||||||
|
|
||||||
2014-07-25 Andi Kleen <ak@linux.intel.com>
|
2014-07-25 Andi Kleen <ak@linux.intel.com>
|
||||||
|
|
||||||
* lto-streamer-out.c (hash_tree): Convert to inchash.
|
* lto-streamer-out.c (hash_tree): Convert to inchash.
|
||||||
|
|
|
@ -440,36 +440,71 @@ lto_output_tree_1 (struct output_block *ob, tree expr, hashval_t hash,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sccs
|
class DFS
|
||||||
{
|
{
|
||||||
unsigned int dfsnum;
|
public:
|
||||||
unsigned int low;
|
DFS (struct output_block *ob, tree expr, bool ref_p, bool this_ref_p,
|
||||||
};
|
bool single_p);
|
||||||
|
~DFS ();
|
||||||
|
|
||||||
struct scc_entry
|
struct scc_entry
|
||||||
{
|
{
|
||||||
tree t;
|
tree t;
|
||||||
hashval_t hash;
|
hashval_t hash;
|
||||||
|
};
|
||||||
|
vec<scc_entry> sccstack;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct sccs
|
||||||
|
{
|
||||||
|
unsigned int dfsnum;
|
||||||
|
unsigned int low;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int scc_entry_compare (const void *, const void *);
|
||||||
|
|
||||||
|
void DFS_write_tree_body (struct output_block *ob,
|
||||||
|
tree expr, sccs *expr_state, bool ref_p,
|
||||||
|
bool single_p);
|
||||||
|
|
||||||
|
void DFS_write_tree (struct output_block *ob, sccs *from_state,
|
||||||
|
tree expr, bool ref_p, bool this_ref_p,
|
||||||
|
bool single_p);
|
||||||
|
hashval_t
|
||||||
|
hash_scc (struct output_block *ob, unsigned first, unsigned size);
|
||||||
|
|
||||||
|
unsigned int next_dfs_num;
|
||||||
|
struct pointer_map_t *sccstate;
|
||||||
|
struct obstack sccstate_obstack;
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned int next_dfs_num;
|
DFS::DFS (struct output_block *ob, tree expr, bool ref_p, bool this_ref_p,
|
||||||
static vec<scc_entry> sccstack;
|
bool single_p)
|
||||||
static struct pointer_map_t *sccstate;
|
{
|
||||||
static struct obstack sccstate_obstack;
|
sccstack.create (0);
|
||||||
|
sccstate = pointer_map_create ();
|
||||||
|
gcc_obstack_init (&sccstate_obstack);
|
||||||
|
next_dfs_num = 1;
|
||||||
|
DFS_write_tree (ob, NULL, expr, ref_p, this_ref_p, single_p);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
DFS::~DFS ()
|
||||||
DFS_write_tree (struct output_block *ob, sccs *from_state,
|
{
|
||||||
tree expr, bool ref_p, bool this_ref_p);
|
sccstack.release ();
|
||||||
|
pointer_map_destroy (sccstate);
|
||||||
|
obstack_free (&sccstate_obstack, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Handle the tree EXPR in the DFS walk with SCC state EXPR_STATE and
|
/* Handle the tree EXPR in the DFS walk with SCC state EXPR_STATE and
|
||||||
DFS recurse for all tree edges originating from it. */
|
DFS recurse for all tree edges originating from it. */
|
||||||
|
|
||||||
static void
|
void
|
||||||
DFS_write_tree_body (struct output_block *ob,
|
DFS::DFS_write_tree_body (struct output_block *ob,
|
||||||
tree expr, sccs *expr_state, bool ref_p)
|
tree expr, sccs *expr_state, bool ref_p,
|
||||||
|
bool single_p)
|
||||||
{
|
{
|
||||||
#define DFS_follow_tree_edge(DEST) \
|
#define DFS_follow_tree_edge(DEST) \
|
||||||
DFS_write_tree (ob, expr_state, DEST, ref_p, ref_p)
|
DFS_write_tree (ob, expr_state, DEST, ref_p, ref_p, single_p)
|
||||||
|
|
||||||
enum tree_code code;
|
enum tree_code code;
|
||||||
|
|
||||||
|
@ -690,18 +725,26 @@ DFS_write_tree_body (struct output_block *ob,
|
||||||
#undef DFS_follow_tree_edge
|
#undef DFS_follow_tree_edge
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return a hash value for the tree T. */
|
/* Return a hash value for the tree T.
|
||||||
|
CACHE holds hash values of trees outside current SCC. MAP, if non-NULL,
|
||||||
|
may hold hash values if trees inside current SCC. */
|
||||||
|
|
||||||
static hashval_t
|
static hashval_t
|
||||||
hash_tree (struct streamer_tree_cache_d *cache, tree t)
|
hash_tree (struct streamer_tree_cache_d *cache, hash_map<tree, hashval_t> *map, tree t)
|
||||||
{
|
{
|
||||||
inchash hstate;
|
inchash hstate;
|
||||||
|
|
||||||
#define visit(SIBLING) \
|
#define visit(SIBLING) \
|
||||||
do { \
|
do { \
|
||||||
unsigned ix; \
|
unsigned ix; \
|
||||||
if (SIBLING && streamer_tree_cache_lookup (cache, SIBLING, &ix)) \
|
if (!SIBLING) \
|
||||||
|
hstate.add_int (0); \
|
||||||
|
else if (streamer_tree_cache_lookup (cache, SIBLING, &ix)) \
|
||||||
hstate.add_int (streamer_tree_cache_get_hash (cache, ix)); \
|
hstate.add_int (streamer_tree_cache_get_hash (cache, ix)); \
|
||||||
|
else if (map) \
|
||||||
|
hstate.add_int (*map->get (SIBLING)); \
|
||||||
|
else \
|
||||||
|
hstate.add_int (1); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* Hash TS_BASE. */
|
/* Hash TS_BASE. */
|
||||||
|
@ -905,23 +948,7 @@ hash_tree (struct streamer_tree_cache_d *cache, tree t)
|
||||||
|
|
||||||
if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
|
if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
|
||||||
{
|
{
|
||||||
if (POINTER_TYPE_P (t))
|
if (code != IDENTIFIER_NODE)
|
||||||
{
|
|
||||||
/* For pointers factor in the pointed-to type recursively as
|
|
||||||
we cannot recurse through only pointers.
|
|
||||||
??? We can generalize this by keeping track of the
|
|
||||||
in-SCC edges for each tree (or arbitrarily the first
|
|
||||||
such edge) and hashing that in in a second stage
|
|
||||||
(instead of the quadratic mixing of the SCC we do now). */
|
|
||||||
hashval_t x;
|
|
||||||
unsigned ix;
|
|
||||||
if (streamer_tree_cache_lookup (cache, TREE_TYPE (t), &ix))
|
|
||||||
x = streamer_tree_cache_get_hash (cache, ix);
|
|
||||||
else
|
|
||||||
x = hash_tree (cache, TREE_TYPE (t));
|
|
||||||
hstate.merge_hash (x);
|
|
||||||
}
|
|
||||||
else if (code != IDENTIFIER_NODE)
|
|
||||||
visit (TREE_TYPE (t));
|
visit (TREE_TYPE (t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1116,8 +1143,8 @@ hash_tree (struct streamer_tree_cache_d *cache, tree t)
|
||||||
|
|
||||||
/* Compare two SCC entries by their hash value for qsorting them. */
|
/* Compare two SCC entries by their hash value for qsorting them. */
|
||||||
|
|
||||||
static int
|
int
|
||||||
scc_entry_compare (const void *p1_, const void *p2_)
|
DFS::scc_entry_compare (const void *p1_, const void *p2_)
|
||||||
{
|
{
|
||||||
const scc_entry *p1 = (const scc_entry *) p1_;
|
const scc_entry *p1 = (const scc_entry *) p1_;
|
||||||
const scc_entry *p2 = (const scc_entry *) p2_;
|
const scc_entry *p2 = (const scc_entry *) p2_;
|
||||||
|
@ -1131,40 +1158,159 @@ scc_entry_compare (const void *p1_, const void *p2_)
|
||||||
/* Return a hash value for the SCC on the SCC stack from FIRST with
|
/* Return a hash value for the SCC on the SCC stack from FIRST with
|
||||||
size SIZE. */
|
size SIZE. */
|
||||||
|
|
||||||
static hashval_t
|
hashval_t
|
||||||
hash_scc (struct streamer_tree_cache_d *cache, unsigned first, unsigned size)
|
DFS::hash_scc (struct output_block *ob,
|
||||||
|
unsigned first, unsigned size)
|
||||||
{
|
{
|
||||||
|
unsigned int last_classes = 0, iterations = 0;
|
||||||
|
|
||||||
/* Compute hash values for the SCC members. */
|
/* Compute hash values for the SCC members. */
|
||||||
for (unsigned i = 0; i < size; ++i)
|
for (unsigned i = 0; i < size; ++i)
|
||||||
sccstack[first+i].hash = hash_tree (cache, sccstack[first+i].t);
|
sccstack[first+i].hash = hash_tree (ob->writer_cache, NULL,
|
||||||
|
sccstack[first+i].t);
|
||||||
|
|
||||||
if (size == 1)
|
if (size == 1)
|
||||||
return sccstack[first].hash;
|
return sccstack[first].hash;
|
||||||
|
|
||||||
/* Sort the SCC of type, hash pairs so that when we mix in
|
/* We aim to get unique hash for every tree within SCC and compute hash value
|
||||||
all members of the SCC the hash value becomes independent on
|
of the whole SCC by combing all values together in an stable (entry point
|
||||||
the order we visited the SCC. Produce hash of the whole SCC as
|
independent) order. This guarantees that the same SCC regions within
|
||||||
combination of hashes of individual elements. Then combine that hash into
|
different translation units will get the same hash values and therefore
|
||||||
hash of each element, so othewise identically looking elements from two
|
will be merged at WPA time.
|
||||||
different SCCs are distinguished. */
|
|
||||||
|
Often the hashes are already unique. In that case we compute scc hash
|
||||||
|
by combining individual hash values in an increasing order.
|
||||||
|
|
||||||
|
If thre are duplicates we seek at least one tree with unique hash (and
|
||||||
|
pick one with minimal hash and this property). Then we obtain stable
|
||||||
|
order by DFS walk starting from this unique tree and then use index
|
||||||
|
within this order to make individual hash values unique.
|
||||||
|
|
||||||
|
If there is no tree with unique hash, we iteratively propagate the hash
|
||||||
|
values across the internal edges of SCC. This usually quickly leads
|
||||||
|
to unique hashes. Consider, for example, an SCC containing two pointers
|
||||||
|
that are identical except for type they point and assume that these
|
||||||
|
types are also part of the SCC.
|
||||||
|
The propagation will add the points-to type information into their hash
|
||||||
|
values. */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* Sort the SCC so we can easily see check for uniqueness. */
|
||||||
qsort (&sccstack[first], size, sizeof (scc_entry), scc_entry_compare);
|
qsort (&sccstack[first], size, sizeof (scc_entry), scc_entry_compare);
|
||||||
|
|
||||||
hashval_t scc_hash = sccstack[first].hash;
|
unsigned int classes = 1;
|
||||||
|
int firstunique = -1;
|
||||||
|
|
||||||
|
/* Find tree with lowest unique hash (if it exists) and compute
|
||||||
|
number of equivalence classes. */
|
||||||
|
if (sccstack[first].hash != sccstack[first+1].hash)
|
||||||
|
firstunique = 0;
|
||||||
|
for (unsigned i = 1; i < size; ++i)
|
||||||
|
if (sccstack[first+i-1].hash != sccstack[first+i].hash)
|
||||||
|
{
|
||||||
|
classes++;
|
||||||
|
if (firstunique == -1
|
||||||
|
&& (i == size - 1
|
||||||
|
|| sccstack[first+i+1].hash != sccstack[first+i].hash))
|
||||||
|
firstunique = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we found tree with unique hash; stop the iteration. */
|
||||||
|
if (firstunique != -1
|
||||||
|
/* Also terminate if we run out of iterations or if the number of
|
||||||
|
equivalence classes is no longer increasing.
|
||||||
|
For example a cyclic list of trees that are all equivalent will
|
||||||
|
never have unique entry point; we however do not build such SCCs
|
||||||
|
in our IL. */
|
||||||
|
|| classes <= last_classes || iterations > 16)
|
||||||
|
{
|
||||||
|
hashval_t scc_hash;
|
||||||
|
|
||||||
|
/* If some hashes are not unique (CLASSES != SIZE), use the DFS walk
|
||||||
|
starting from FIRSTUNIQUE to obstain stable order. */
|
||||||
|
if (classes != size && firstunique != -1)
|
||||||
|
{
|
||||||
|
hash_map <tree, hashval_t> map(size*2);
|
||||||
|
|
||||||
|
/* Store hash values into a map, so we can associate them with
|
||||||
|
reordered SCC. */
|
||||||
|
for (unsigned i = 0; i < size; ++i)
|
||||||
|
map.put (sccstack[first+i].t, sccstack[first+i].hash);
|
||||||
|
|
||||||
|
DFS again (ob, sccstack[first+firstunique].t, false, false, true);
|
||||||
|
gcc_assert (again.sccstack.length () == size);
|
||||||
|
|
||||||
|
memcpy (sccstack.address () + first,
|
||||||
|
again.sccstack.address (),
|
||||||
|
sizeof (scc_entry) * size);
|
||||||
|
|
||||||
|
/* Update hash values of individual members by hashing in the
|
||||||
|
index within the stable order. This ensures uniqueness.
|
||||||
|
Also compute the scc_hash by mixing in all hash values in the
|
||||||
|
stable order we obtained. */
|
||||||
|
sccstack[first].hash = *map.get (sccstack[first].t);
|
||||||
|
scc_hash = sccstack[first].hash;
|
||||||
|
for (unsigned i = 1; i < size; ++i)
|
||||||
|
{
|
||||||
|
sccstack[first+i].hash
|
||||||
|
= iterative_hash_hashval_t (i,
|
||||||
|
*map.get (sccstack[first+i].t));
|
||||||
|
scc_hash = iterative_hash_hashval_t (scc_hash,
|
||||||
|
sccstack[first+i].hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* If we got unique hash values for each tree, then sort already
|
||||||
|
ensured entry point independent order. Only compute the final
|
||||||
|
scc hash.
|
||||||
|
|
||||||
|
If we failed to find the unique entry point, we go by the same
|
||||||
|
route. We will eventually introduce unwanted hash conflicts. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scc_hash = sccstack[first].hash;
|
||||||
for (unsigned i = 1; i < size; ++i)
|
for (unsigned i = 1; i < size; ++i)
|
||||||
scc_hash = iterative_hash_hashval_t (scc_hash,
|
scc_hash = iterative_hash_hashval_t (scc_hash,
|
||||||
sccstack[first+i].hash);
|
sccstack[first+i].hash);
|
||||||
|
/* We can not 100% guarantee that the hash will not conflict in
|
||||||
|
in a way so the unique hash is not found. This however
|
||||||
|
should be extremely rare situation. ICE for now so possible
|
||||||
|
issues are found and evaulated. */
|
||||||
|
gcc_checking_assert (classes == size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* To avoid conflicts across SCCs iteratively hash the whole SCC
|
||||||
|
hash into the hash of each of the elements. */
|
||||||
for (unsigned i = 0; i < size; ++i)
|
for (unsigned i = 0; i < size; ++i)
|
||||||
sccstack[first+i].hash = iterative_hash_hashval_t (sccstack[first+i].hash, scc_hash);
|
sccstack[first+i].hash
|
||||||
|
= iterative_hash_hashval_t (sccstack[first+i].hash, scc_hash);
|
||||||
return scc_hash;
|
return scc_hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_classes = classes;
|
||||||
|
iterations++;
|
||||||
|
|
||||||
|
/* We failed to identify the entry point; propagate hash values across
|
||||||
|
the edges. */
|
||||||
|
{
|
||||||
|
hash_map <tree, hashval_t> map(size*2);
|
||||||
|
for (unsigned i = 0; i < size; ++i)
|
||||||
|
map.put (sccstack[first+i].t, sccstack[first+i].hash);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < size; i++)
|
||||||
|
sccstack[first+i].hash = hash_tree (ob->writer_cache, &map,
|
||||||
|
sccstack[first+i].t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* DFS walk EXPR and stream SCCs of tree bodies if they are not
|
/* DFS walk EXPR and stream SCCs of tree bodies if they are not
|
||||||
already in the streamer cache. Main routine called for
|
already in the streamer cache. Main routine called for
|
||||||
each visit of EXPR. */
|
each visit of EXPR. */
|
||||||
|
|
||||||
static void
|
void
|
||||||
DFS_write_tree (struct output_block *ob, sccs *from_state,
|
DFS::DFS_write_tree (struct output_block *ob, sccs *from_state,
|
||||||
tree expr, bool ref_p, bool this_ref_p)
|
tree expr, bool ref_p, bool this_ref_p, bool single_p)
|
||||||
{
|
{
|
||||||
unsigned ix;
|
unsigned ix;
|
||||||
sccs **slot;
|
sccs **slot;
|
||||||
|
@ -1196,10 +1342,10 @@ DFS_write_tree (struct output_block *ob, sccs *from_state,
|
||||||
;
|
;
|
||||||
else if (TREE_CODE (expr) == INTEGER_CST
|
else if (TREE_CODE (expr) == INTEGER_CST
|
||||||
&& !TREE_OVERFLOW (expr))
|
&& !TREE_OVERFLOW (expr))
|
||||||
DFS_write_tree (ob, cstate, TREE_TYPE (expr), ref_p, ref_p);
|
DFS_write_tree (ob, cstate, TREE_TYPE (expr), ref_p, ref_p, single_p);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DFS_write_tree_body (ob, expr, cstate, ref_p);
|
DFS_write_tree_body (ob, expr, cstate, ref_p, single_p);
|
||||||
|
|
||||||
/* Walk any LTO-specific edges. */
|
/* Walk any LTO-specific edges. */
|
||||||
if (DECL_P (expr)
|
if (DECL_P (expr)
|
||||||
|
@ -1209,7 +1355,7 @@ DFS_write_tree (struct output_block *ob, sccs *from_state,
|
||||||
/* Handle DECL_INITIAL for symbols. */
|
/* Handle DECL_INITIAL for symbols. */
|
||||||
tree initial = get_symbol_initial_value (ob->decl_state->symtab_node_encoder,
|
tree initial = get_symbol_initial_value (ob->decl_state->symtab_node_encoder,
|
||||||
expr);
|
expr);
|
||||||
DFS_write_tree (ob, cstate, initial, ref_p, ref_p);
|
DFS_write_tree (ob, cstate, initial, ref_p, ref_p, single_p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1219,6 +1365,11 @@ DFS_write_tree (struct output_block *ob, sccs *from_state,
|
||||||
unsigned first, size;
|
unsigned first, size;
|
||||||
tree x;
|
tree x;
|
||||||
|
|
||||||
|
/* If we are re-walking a single leaf-SCC just return and
|
||||||
|
let the caller access the sccstack. */
|
||||||
|
if (single_p)
|
||||||
|
return;
|
||||||
|
|
||||||
/* Pop the SCC and compute its size. */
|
/* Pop the SCC and compute its size. */
|
||||||
first = sccstack.length ();
|
first = sccstack.length ();
|
||||||
do
|
do
|
||||||
|
@ -1234,7 +1385,7 @@ DFS_write_tree (struct output_block *ob, sccs *from_state,
|
||||||
unsigned scc_entry_len = 0;
|
unsigned scc_entry_len = 0;
|
||||||
if (!flag_wpa)
|
if (!flag_wpa)
|
||||||
{
|
{
|
||||||
scc_hash = hash_scc (ob->writer_cache, first, size);
|
scc_hash = hash_scc (ob, first, size);
|
||||||
|
|
||||||
/* Put the entries with the least number of collisions first. */
|
/* Put the entries with the least number of collisions first. */
|
||||||
unsigned entry_start = 0;
|
unsigned entry_start = 0;
|
||||||
|
@ -1258,6 +1409,18 @@ DFS_write_tree (struct output_block *ob, sccs *from_state,
|
||||||
sccstack[first + i] = sccstack[first + entry_start + i];
|
sccstack[first + i] = sccstack[first + entry_start + i];
|
||||||
sccstack[first + entry_start + i] = tem;
|
sccstack[first + entry_start + i] = tem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (scc_entry_len == 1)
|
||||||
|
; /* We already sorted SCC deterministically in hash_scc. */
|
||||||
|
else
|
||||||
|
/* Check that we have only one SCC.
|
||||||
|
Naturally we may have conflicts if hash function is not
|
||||||
|
strong enough. Lets see how far this gets. */
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_CHECKING
|
||||||
|
gcc_unreachable ();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write LTO_tree_scc. */
|
/* Write LTO_tree_scc. */
|
||||||
|
@ -1377,13 +1540,7 @@ lto_output_tree (struct output_block *ob, tree expr,
|
||||||
/* Save ob state ... */
|
/* Save ob state ... */
|
||||||
/* let's see ... */
|
/* let's see ... */
|
||||||
in_dfs_walk = true;
|
in_dfs_walk = true;
|
||||||
sccstate = pointer_map_create ();
|
DFS (ob, expr, ref_p, this_ref_p, false);
|
||||||
gcc_obstack_init (&sccstate_obstack);
|
|
||||||
next_dfs_num = 1;
|
|
||||||
DFS_write_tree (ob, NULL, expr, ref_p, this_ref_p);
|
|
||||||
sccstack.release ();
|
|
||||||
pointer_map_destroy (sccstate);
|
|
||||||
obstack_free (&sccstate_obstack, NULL);
|
|
||||||
in_dfs_walk = false;
|
in_dfs_walk = false;
|
||||||
|
|
||||||
/* Finally append a reference to the tree we were writing.
|
/* Finally append a reference to the tree we were writing.
|
||||||
|
|
Loading…
Reference in New Issue