1e4b17023SJohn Marino /* Miscellaneous utilities for tree streaming. Things that are used
2e4b17023SJohn Marino in both input and output are here.
3e4b17023SJohn Marino
4e4b17023SJohn Marino Copyright 2011 Free Software Foundation, Inc.
5e4b17023SJohn Marino Contributed by Diego Novillo <dnovillo@google.com>
6e4b17023SJohn Marino
7e4b17023SJohn Marino This file is part of GCC.
8e4b17023SJohn Marino
9e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify it under
10e4b17023SJohn Marino the terms of the GNU General Public License as published by the Free
11e4b17023SJohn Marino Software Foundation; either version 3, or (at your option) any later
12e4b17023SJohn Marino version.
13e4b17023SJohn Marino
14e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, but WITHOUT ANY
15e4b17023SJohn Marino WARRANTY; without even the implied warranty of MERCHANTABILITY or
16e4b17023SJohn Marino FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17e4b17023SJohn Marino for more details.
18e4b17023SJohn Marino
19e4b17023SJohn Marino You should have received a copy of the GNU General Public License
20e4b17023SJohn Marino along with GCC; see the file COPYING3. If not see
21e4b17023SJohn Marino <http://www.gnu.org/licenses/>. */
22e4b17023SJohn Marino
23e4b17023SJohn Marino #include "config.h"
24e4b17023SJohn Marino #include "system.h"
25e4b17023SJohn Marino #include "coretypes.h"
26e4b17023SJohn Marino #include "streamer-hooks.h"
27e4b17023SJohn Marino #include "tree-streamer.h"
28e4b17023SJohn Marino
29e4b17023SJohn Marino /* Check that all the TS_* structures handled by the streamer_write_* and
30e4b17023SJohn Marino streamer_read_* routines are exactly ALL the structures defined in
31e4b17023SJohn Marino treestruct.def. */
32e4b17023SJohn Marino
33e4b17023SJohn Marino void
streamer_check_handled_ts_structures(void)34e4b17023SJohn Marino streamer_check_handled_ts_structures (void)
35e4b17023SJohn Marino {
36e4b17023SJohn Marino bool handled_p[LAST_TS_ENUM];
37e4b17023SJohn Marino unsigned i;
38e4b17023SJohn Marino
39e4b17023SJohn Marino memset (&handled_p, 0, sizeof (handled_p));
40e4b17023SJohn Marino
41e4b17023SJohn Marino /* These are the TS_* structures that are either handled or
42e4b17023SJohn Marino explicitly ignored by the streamer routines. */
43e4b17023SJohn Marino handled_p[TS_BASE] = true;
44e4b17023SJohn Marino handled_p[TS_TYPED] = true;
45e4b17023SJohn Marino handled_p[TS_COMMON] = true;
46e4b17023SJohn Marino handled_p[TS_INT_CST] = true;
47e4b17023SJohn Marino handled_p[TS_REAL_CST] = true;
48e4b17023SJohn Marino handled_p[TS_FIXED_CST] = true;
49e4b17023SJohn Marino handled_p[TS_VECTOR] = true;
50e4b17023SJohn Marino handled_p[TS_STRING] = true;
51e4b17023SJohn Marino handled_p[TS_COMPLEX] = true;
52e4b17023SJohn Marino handled_p[TS_IDENTIFIER] = true;
53e4b17023SJohn Marino handled_p[TS_DECL_MINIMAL] = true;
54e4b17023SJohn Marino handled_p[TS_DECL_COMMON] = true;
55e4b17023SJohn Marino handled_p[TS_DECL_WRTL] = true;
56e4b17023SJohn Marino handled_p[TS_DECL_NON_COMMON] = true;
57e4b17023SJohn Marino handled_p[TS_DECL_WITH_VIS] = true;
58e4b17023SJohn Marino handled_p[TS_FIELD_DECL] = true;
59e4b17023SJohn Marino handled_p[TS_VAR_DECL] = true;
60e4b17023SJohn Marino handled_p[TS_PARM_DECL] = true;
61e4b17023SJohn Marino handled_p[TS_LABEL_DECL] = true;
62e4b17023SJohn Marino handled_p[TS_RESULT_DECL] = true;
63e4b17023SJohn Marino handled_p[TS_CONST_DECL] = true;
64e4b17023SJohn Marino handled_p[TS_TYPE_DECL] = true;
65e4b17023SJohn Marino handled_p[TS_FUNCTION_DECL] = true;
66e4b17023SJohn Marino handled_p[TS_TYPE_COMMON] = true;
67e4b17023SJohn Marino handled_p[TS_TYPE_WITH_LANG_SPECIFIC] = true;
68e4b17023SJohn Marino handled_p[TS_TYPE_NON_COMMON] = true;
69e4b17023SJohn Marino handled_p[TS_LIST] = true;
70e4b17023SJohn Marino handled_p[TS_VEC] = true;
71e4b17023SJohn Marino handled_p[TS_EXP] = true;
72e4b17023SJohn Marino handled_p[TS_SSA_NAME] = true;
73e4b17023SJohn Marino handled_p[TS_BLOCK] = true;
74e4b17023SJohn Marino handled_p[TS_BINFO] = true;
75e4b17023SJohn Marino handled_p[TS_STATEMENT_LIST] = true;
76e4b17023SJohn Marino handled_p[TS_CONSTRUCTOR] = true;
77e4b17023SJohn Marino handled_p[TS_OMP_CLAUSE] = true;
78e4b17023SJohn Marino handled_p[TS_OPTIMIZATION] = true;
79e4b17023SJohn Marino handled_p[TS_TARGET_OPTION] = true;
80e4b17023SJohn Marino handled_p[TS_TRANSLATION_UNIT_DECL] = true;
81e4b17023SJohn Marino
82e4b17023SJohn Marino /* Anything not marked above will trigger the following assertion.
83e4b17023SJohn Marino If this assertion triggers, it means that there is a new TS_*
84e4b17023SJohn Marino structure that should be handled by the streamer. */
85e4b17023SJohn Marino for (i = 0; i < LAST_TS_ENUM; i++)
86e4b17023SJohn Marino gcc_assert (handled_p[i]);
87e4b17023SJohn Marino }
88e4b17023SJohn Marino
89e4b17023SJohn Marino
90e4b17023SJohn Marino /* Helper for streamer_tree_cache_insert_1. Add T to CACHE->NODES at
91e4b17023SJohn Marino slot IX. */
92e4b17023SJohn Marino
93e4b17023SJohn Marino static void
streamer_tree_cache_add_to_node_array(struct streamer_tree_cache_d * cache,unsigned ix,tree t)94e4b17023SJohn Marino streamer_tree_cache_add_to_node_array (struct streamer_tree_cache_d *cache,
95e4b17023SJohn Marino unsigned ix, tree t)
96e4b17023SJohn Marino {
97e4b17023SJohn Marino /* Make sure we're either replacing an old element or
98e4b17023SJohn Marino appending consecutively. */
99e4b17023SJohn Marino gcc_assert (ix <= VEC_length (tree, cache->nodes));
100e4b17023SJohn Marino
101e4b17023SJohn Marino if (ix == VEC_length (tree, cache->nodes))
102e4b17023SJohn Marino VEC_safe_push (tree, heap, cache->nodes, t);
103e4b17023SJohn Marino else
104e4b17023SJohn Marino VEC_replace (tree, cache->nodes, ix, t);
105e4b17023SJohn Marino }
106e4b17023SJohn Marino
107e4b17023SJohn Marino
108e4b17023SJohn Marino /* Helper for streamer_tree_cache_insert and streamer_tree_cache_insert_at.
109e4b17023SJohn Marino CACHE, T, and IX_P are as in streamer_tree_cache_insert.
110e4b17023SJohn Marino
111e4b17023SJohn Marino If INSERT_AT_NEXT_SLOT_P is true, T is inserted at the next available
112e4b17023SJohn Marino slot in the cache. Otherwise, T is inserted at the position indicated
113e4b17023SJohn Marino in *IX_P.
114e4b17023SJohn Marino
115e4b17023SJohn Marino If T already existed in CACHE, return true. Otherwise,
116e4b17023SJohn Marino return false. */
117e4b17023SJohn Marino
118e4b17023SJohn Marino static bool
streamer_tree_cache_insert_1(struct streamer_tree_cache_d * cache,tree t,unsigned * ix_p,bool insert_at_next_slot_p)119e4b17023SJohn Marino streamer_tree_cache_insert_1 (struct streamer_tree_cache_d *cache,
120e4b17023SJohn Marino tree t, unsigned *ix_p,
121e4b17023SJohn Marino bool insert_at_next_slot_p)
122e4b17023SJohn Marino {
123e4b17023SJohn Marino void **slot;
124e4b17023SJohn Marino unsigned ix;
125e4b17023SJohn Marino bool existed_p;
126e4b17023SJohn Marino
127e4b17023SJohn Marino gcc_assert (t);
128e4b17023SJohn Marino
129e4b17023SJohn Marino slot = pointer_map_insert (cache->node_map, t);
130e4b17023SJohn Marino if (!*slot)
131e4b17023SJohn Marino {
132e4b17023SJohn Marino /* Determine the next slot to use in the cache. */
133e4b17023SJohn Marino if (insert_at_next_slot_p)
134e4b17023SJohn Marino ix = VEC_length (tree, cache->nodes);
135e4b17023SJohn Marino else
136e4b17023SJohn Marino ix = *ix_p;
137e4b17023SJohn Marino *slot = (void *)(size_t) (ix + 1);
138e4b17023SJohn Marino
139e4b17023SJohn Marino streamer_tree_cache_add_to_node_array (cache, ix, t);
140e4b17023SJohn Marino
141e4b17023SJohn Marino /* Indicate that the item was not present in the cache. */
142e4b17023SJohn Marino existed_p = false;
143e4b17023SJohn Marino }
144e4b17023SJohn Marino else
145e4b17023SJohn Marino {
146e4b17023SJohn Marino ix = (size_t) *slot - 1;
147e4b17023SJohn Marino
148e4b17023SJohn Marino if (!insert_at_next_slot_p && ix != *ix_p)
149e4b17023SJohn Marino {
150e4b17023SJohn Marino /* If the caller wants to insert T at a specific slot
151e4b17023SJohn Marino location, and ENTRY->TO does not match *IX_P, add T to
152e4b17023SJohn Marino the requested location slot. */
153e4b17023SJohn Marino ix = *ix_p;
154e4b17023SJohn Marino streamer_tree_cache_add_to_node_array (cache, ix, t);
155e4b17023SJohn Marino }
156e4b17023SJohn Marino
157e4b17023SJohn Marino /* Indicate that T was already in the cache. */
158e4b17023SJohn Marino existed_p = true;
159e4b17023SJohn Marino }
160e4b17023SJohn Marino
161e4b17023SJohn Marino if (ix_p)
162e4b17023SJohn Marino *ix_p = ix;
163e4b17023SJohn Marino
164e4b17023SJohn Marino return existed_p;
165e4b17023SJohn Marino }
166e4b17023SJohn Marino
167e4b17023SJohn Marino
168e4b17023SJohn Marino /* Insert tree node T in CACHE. If T already existed in the cache
169e4b17023SJohn Marino return true. Otherwise, return false.
170e4b17023SJohn Marino
171e4b17023SJohn Marino If IX_P is non-null, update it with the index into the cache where
172e4b17023SJohn Marino T has been stored. */
173e4b17023SJohn Marino
174e4b17023SJohn Marino bool
streamer_tree_cache_insert(struct streamer_tree_cache_d * cache,tree t,unsigned * ix_p)175e4b17023SJohn Marino streamer_tree_cache_insert (struct streamer_tree_cache_d *cache, tree t,
176e4b17023SJohn Marino unsigned *ix_p)
177e4b17023SJohn Marino {
178e4b17023SJohn Marino return streamer_tree_cache_insert_1 (cache, t, ix_p, true);
179e4b17023SJohn Marino }
180e4b17023SJohn Marino
181e4b17023SJohn Marino
182e4b17023SJohn Marino /* Insert tree node T in CACHE at slot IX. If T already
183e4b17023SJohn Marino existed in the cache return true. Otherwise, return false. */
184e4b17023SJohn Marino
185e4b17023SJohn Marino bool
streamer_tree_cache_insert_at(struct streamer_tree_cache_d * cache,tree t,unsigned ix)186e4b17023SJohn Marino streamer_tree_cache_insert_at (struct streamer_tree_cache_d *cache,
187e4b17023SJohn Marino tree t, unsigned ix)
188e4b17023SJohn Marino {
189e4b17023SJohn Marino return streamer_tree_cache_insert_1 (cache, t, &ix, false);
190e4b17023SJohn Marino }
191e4b17023SJohn Marino
192e4b17023SJohn Marino
193e4b17023SJohn Marino /* Appends tree node T to CACHE, even if T already existed in it. */
194e4b17023SJohn Marino
195e4b17023SJohn Marino void
streamer_tree_cache_append(struct streamer_tree_cache_d * cache,tree t)196e4b17023SJohn Marino streamer_tree_cache_append (struct streamer_tree_cache_d *cache, tree t)
197e4b17023SJohn Marino {
198e4b17023SJohn Marino unsigned ix = VEC_length (tree, cache->nodes);
199e4b17023SJohn Marino streamer_tree_cache_insert_1 (cache, t, &ix, false);
200e4b17023SJohn Marino }
201e4b17023SJohn Marino
202e4b17023SJohn Marino /* Return true if tree node T exists in CACHE, otherwise false. If IX_P is
203e4b17023SJohn Marino not NULL, write to *IX_P the index into the cache where T is stored
204e4b17023SJohn Marino ((unsigned)-1 if T is not found). */
205e4b17023SJohn Marino
206e4b17023SJohn Marino bool
streamer_tree_cache_lookup(struct streamer_tree_cache_d * cache,tree t,unsigned * ix_p)207e4b17023SJohn Marino streamer_tree_cache_lookup (struct streamer_tree_cache_d *cache, tree t,
208e4b17023SJohn Marino unsigned *ix_p)
209e4b17023SJohn Marino {
210e4b17023SJohn Marino void **slot;
211e4b17023SJohn Marino bool retval;
212e4b17023SJohn Marino unsigned ix;
213e4b17023SJohn Marino
214e4b17023SJohn Marino gcc_assert (t);
215e4b17023SJohn Marino
216e4b17023SJohn Marino slot = pointer_map_contains (cache->node_map, t);
217e4b17023SJohn Marino if (slot == NULL)
218e4b17023SJohn Marino {
219e4b17023SJohn Marino retval = false;
220e4b17023SJohn Marino ix = -1;
221e4b17023SJohn Marino }
222e4b17023SJohn Marino else
223e4b17023SJohn Marino {
224e4b17023SJohn Marino retval = true;
225e4b17023SJohn Marino ix = (size_t) *slot - 1;
226e4b17023SJohn Marino }
227e4b17023SJohn Marino
228e4b17023SJohn Marino if (ix_p)
229e4b17023SJohn Marino *ix_p = ix;
230e4b17023SJohn Marino
231e4b17023SJohn Marino return retval;
232e4b17023SJohn Marino }
233e4b17023SJohn Marino
234e4b17023SJohn Marino
235e4b17023SJohn Marino /* Return the tree node at slot IX in CACHE. */
236e4b17023SJohn Marino
237e4b17023SJohn Marino tree
streamer_tree_cache_get(struct streamer_tree_cache_d * cache,unsigned ix)238e4b17023SJohn Marino streamer_tree_cache_get (struct streamer_tree_cache_d *cache, unsigned ix)
239e4b17023SJohn Marino {
240e4b17023SJohn Marino gcc_assert (cache);
241e4b17023SJohn Marino
242e4b17023SJohn Marino /* Make sure we're not requesting something we don't have. */
243e4b17023SJohn Marino gcc_assert (ix < VEC_length (tree, cache->nodes));
244e4b17023SJohn Marino
245e4b17023SJohn Marino return VEC_index (tree, cache->nodes, ix);
246e4b17023SJohn Marino }
247e4b17023SJohn Marino
248e4b17023SJohn Marino
249e4b17023SJohn Marino /* Record NODE in CACHE. */
250e4b17023SJohn Marino
251e4b17023SJohn Marino static void
record_common_node(struct streamer_tree_cache_d * cache,tree node)252e4b17023SJohn Marino record_common_node (struct streamer_tree_cache_d *cache, tree node)
253e4b17023SJohn Marino {
254*5ce9237cSJohn Marino /* If we recursively end up at nodes we do not want to preload simply don't.
255*5ce9237cSJohn Marino ??? We'd want to verify that this doesn't happen, or alternatively
256*5ce9237cSJohn Marino do not recurse at all. */
257*5ce9237cSJohn Marino if (node == char_type_node)
258*5ce9237cSJohn Marino return;
259*5ce9237cSJohn Marino
260*5ce9237cSJohn Marino gcc_checking_assert (node != boolean_type_node
261*5ce9237cSJohn Marino && node != boolean_true_node
262*5ce9237cSJohn Marino && node != boolean_false_node);
263*5ce9237cSJohn Marino
264e4b17023SJohn Marino /* We have to make sure to fill exactly the same number of
265e4b17023SJohn Marino elements for all frontends. That can include NULL trees.
266e4b17023SJohn Marino As our hash table can't deal with zero entries we'll simply stream
267e4b17023SJohn Marino a random other tree. A NULL tree never will be looked up so it
268e4b17023SJohn Marino doesn't matter which tree we replace it with, just to be sure
269e4b17023SJohn Marino use error_mark_node. */
270e4b17023SJohn Marino if (!node)
271e4b17023SJohn Marino node = error_mark_node;
272e4b17023SJohn Marino
273e4b17023SJohn Marino streamer_tree_cache_append (cache, node);
274e4b17023SJohn Marino
275e4b17023SJohn Marino if (POINTER_TYPE_P (node)
276e4b17023SJohn Marino || TREE_CODE (node) == COMPLEX_TYPE
277e4b17023SJohn Marino || TREE_CODE (node) == ARRAY_TYPE)
278e4b17023SJohn Marino record_common_node (cache, TREE_TYPE (node));
279e4b17023SJohn Marino else if (TREE_CODE (node) == RECORD_TYPE)
280e4b17023SJohn Marino {
281e4b17023SJohn Marino /* The FIELD_DECLs of structures should be shared, so that every
282e4b17023SJohn Marino COMPONENT_REF uses the same tree node when referencing a field.
283e4b17023SJohn Marino Pointer equality between FIELD_DECLs is used by the alias
284e4b17023SJohn Marino machinery to compute overlapping memory references (See
285e4b17023SJohn Marino nonoverlapping_component_refs_p). */
286e4b17023SJohn Marino tree f;
287e4b17023SJohn Marino for (f = TYPE_FIELDS (node); f; f = TREE_CHAIN (f))
288e4b17023SJohn Marino record_common_node (cache, f);
289e4b17023SJohn Marino }
290e4b17023SJohn Marino }
291e4b17023SJohn Marino
292e4b17023SJohn Marino
293e4b17023SJohn Marino /* Preload common nodes into CACHE and make sure they are merged
294e4b17023SJohn Marino properly according to the gimple type table. */
295e4b17023SJohn Marino
296e4b17023SJohn Marino static void
preload_common_nodes(struct streamer_tree_cache_d * cache)297e4b17023SJohn Marino preload_common_nodes (struct streamer_tree_cache_d *cache)
298e4b17023SJohn Marino {
299e4b17023SJohn Marino unsigned i;
300e4b17023SJohn Marino
301e4b17023SJohn Marino for (i = 0; i < itk_none; i++)
302e4b17023SJohn Marino /* Skip itk_char. char_type_node is dependent on -f[un]signed-char. */
303e4b17023SJohn Marino if (i != itk_char)
304e4b17023SJohn Marino record_common_node (cache, integer_types[i]);
305e4b17023SJohn Marino
306e4b17023SJohn Marino for (i = 0; i < TYPE_KIND_LAST; i++)
307e4b17023SJohn Marino record_common_node (cache, sizetype_tab[i]);
308e4b17023SJohn Marino
309e4b17023SJohn Marino for (i = 0; i < TI_MAX; i++)
310e4b17023SJohn Marino /* Skip boolean type and constants, they are frontend dependent. */
311e4b17023SJohn Marino if (i != TI_BOOLEAN_TYPE
312e4b17023SJohn Marino && i != TI_BOOLEAN_FALSE
313e4b17023SJohn Marino && i != TI_BOOLEAN_TRUE)
314e4b17023SJohn Marino record_common_node (cache, global_trees[i]);
315e4b17023SJohn Marino }
316e4b17023SJohn Marino
317e4b17023SJohn Marino
318e4b17023SJohn Marino /* Create a cache of pickled nodes. */
319e4b17023SJohn Marino
320e4b17023SJohn Marino struct streamer_tree_cache_d *
streamer_tree_cache_create(void)321e4b17023SJohn Marino streamer_tree_cache_create (void)
322e4b17023SJohn Marino {
323e4b17023SJohn Marino struct streamer_tree_cache_d *cache;
324e4b17023SJohn Marino
325e4b17023SJohn Marino cache = XCNEW (struct streamer_tree_cache_d);
326e4b17023SJohn Marino
327e4b17023SJohn Marino cache->node_map = pointer_map_create ();
328e4b17023SJohn Marino
329e4b17023SJohn Marino /* Load all the well-known tree nodes that are always created by
330e4b17023SJohn Marino the compiler on startup. This prevents writing them out
331e4b17023SJohn Marino unnecessarily. */
332e4b17023SJohn Marino preload_common_nodes (cache);
333e4b17023SJohn Marino
334e4b17023SJohn Marino return cache;
335e4b17023SJohn Marino }
336e4b17023SJohn Marino
337e4b17023SJohn Marino
338e4b17023SJohn Marino /* Delete the streamer cache C. */
339e4b17023SJohn Marino
340e4b17023SJohn Marino void
streamer_tree_cache_delete(struct streamer_tree_cache_d * c)341e4b17023SJohn Marino streamer_tree_cache_delete (struct streamer_tree_cache_d *c)
342e4b17023SJohn Marino {
343e4b17023SJohn Marino if (c == NULL)
344e4b17023SJohn Marino return;
345e4b17023SJohn Marino
346e4b17023SJohn Marino pointer_map_destroy (c->node_map);
347e4b17023SJohn Marino VEC_free (tree, heap, c->nodes);
348e4b17023SJohn Marino free (c);
349e4b17023SJohn Marino }
350