Branch data Line data Source code
1 : : /* Miscellaneous utilities for tree streaming. Things that are used
2 : : in both input and output are here.
3 : :
4 : : Copyright (C) 2011-2024 Free Software Foundation, Inc.
5 : : Contributed by Diego Novillo <dnovillo@google.com>
6 : :
7 : : This file is part of GCC.
8 : :
9 : : GCC is free software; you can redistribute it and/or modify it under
10 : : the terms of the GNU General Public License as published by the Free
11 : : Software Foundation; either version 3, or (at your option) any later
12 : : version.
13 : :
14 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
15 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 : : for more details.
18 : :
19 : : You should have received a copy of the GNU General Public License
20 : : along with GCC; see the file COPYING3. If not see
21 : : <http://www.gnu.org/licenses/>. */
22 : :
23 : : #include "config.h"
24 : : #include "system.h"
25 : : #include "coretypes.h"
26 : : #include "backend.h"
27 : : #include "tree.h"
28 : : #include "gimple.h"
29 : : #include "tree-streamer.h"
30 : : #include "cgraph.h"
31 : :
32 : : /* Table indexed by machine_mode, used for 2 different purposes.
33 : : During streaming out we record there non-zero value for all modes
34 : : that were streamed out.
35 : : During streaming in, we translate the on the disk mode using this
36 : : table. For normal LTO it is set to identity, for ACCEL_COMPILER
37 : : depending on the mode_table content. */
38 : : unsigned char streamer_mode_table[MAX_MACHINE_MODE];
39 : :
40 : : /* Check that all the TS_* structures handled by the streamer_write_* and
41 : : streamer_read_* routines are exactly ALL the structures defined in
42 : : treestruct.def. */
43 : :
44 : : void
45 : 56452 : streamer_check_handled_ts_structures (void)
46 : : {
47 : 56452 : bool handled_p[LAST_TS_ENUM];
48 : 56452 : unsigned i;
49 : :
50 : 56452 : memset (&handled_p, 0, sizeof (handled_p));
51 : :
52 : : /* These are the TS_* structures that are either handled or
53 : : explicitly ignored by the streamer routines. */
54 : 56452 : handled_p[TS_BASE] = true;
55 : 56452 : handled_p[TS_TYPED] = true;
56 : 56452 : handled_p[TS_COMMON] = true;
57 : 56452 : handled_p[TS_INT_CST] = true;
58 : 56452 : handled_p[TS_POLY_INT_CST] = true;
59 : 56452 : handled_p[TS_REAL_CST] = true;
60 : 56452 : handled_p[TS_FIXED_CST] = true;
61 : 56452 : handled_p[TS_VECTOR] = true;
62 : 56452 : handled_p[TS_STRING] = true;
63 : 56452 : handled_p[TS_RAW_DATA_CST] = true;
64 : 56452 : handled_p[TS_COMPLEX] = true;
65 : 56452 : handled_p[TS_IDENTIFIER] = true;
66 : 56452 : handled_p[TS_DECL_MINIMAL] = true;
67 : 56452 : handled_p[TS_DECL_COMMON] = true;
68 : 56452 : handled_p[TS_DECL_WRTL] = true;
69 : 56452 : handled_p[TS_DECL_NON_COMMON] = true;
70 : 56452 : handled_p[TS_DECL_WITH_VIS] = true;
71 : 56452 : handled_p[TS_FIELD_DECL] = true;
72 : 56452 : handled_p[TS_VAR_DECL] = true;
73 : 56452 : handled_p[TS_PARM_DECL] = true;
74 : 56452 : handled_p[TS_LABEL_DECL] = true;
75 : 56452 : handled_p[TS_RESULT_DECL] = true;
76 : 56452 : handled_p[TS_CONST_DECL] = true;
77 : 56452 : handled_p[TS_TYPE_DECL] = true;
78 : 56452 : handled_p[TS_FUNCTION_DECL] = true;
79 : 56452 : handled_p[TS_TYPE_COMMON] = true;
80 : 56452 : handled_p[TS_TYPE_WITH_LANG_SPECIFIC] = true;
81 : 56452 : handled_p[TS_TYPE_NON_COMMON] = true;
82 : 56452 : handled_p[TS_LIST] = true;
83 : 56452 : handled_p[TS_VEC] = true;
84 : 56452 : handled_p[TS_EXP] = true;
85 : 56452 : handled_p[TS_SSA_NAME] = true;
86 : 56452 : handled_p[TS_BLOCK] = true;
87 : 56452 : handled_p[TS_BINFO] = true;
88 : 56452 : handled_p[TS_STATEMENT_LIST] = true;
89 : 56452 : handled_p[TS_CONSTRUCTOR] = true;
90 : 56452 : handled_p[TS_OMP_CLAUSE] = true;
91 : 56452 : handled_p[TS_OPTIMIZATION] = true;
92 : 56452 : handled_p[TS_TARGET_OPTION] = true;
93 : 56452 : handled_p[TS_TRANSLATION_UNIT_DECL] = true;
94 : :
95 : : /* Anything not marked above will trigger the following assertion.
96 : : If this assertion triggers, it means that there is a new TS_*
97 : : structure that should be handled by the streamer. */
98 : 2314532 : for (i = 0; i < LAST_TS_ENUM; i++)
99 : 2258080 : gcc_assert (handled_p[i]);
100 : 56452 : }
101 : :
102 : :
103 : : /* Helper for streamer_tree_cache_insert_1. Add T to CACHE->NODES at
104 : : slot IX. */
105 : :
106 : : static void
107 : 129471203 : streamer_tree_cache_add_to_node_array (struct streamer_tree_cache_d *cache,
108 : : unsigned ix, tree t, hashval_t hash)
109 : : {
110 : : /* We're either replacing an old element or appending consecutively. */
111 : 129471203 : if (cache->nodes.exists ())
112 : : {
113 : 52284312 : if (cache->nodes.length () == ix)
114 : 52115525 : cache->nodes.safe_push (t);
115 : : else
116 : 168787 : cache->nodes[ix] = t;
117 : : }
118 : 129471203 : if (cache->hashes.exists ())
119 : : {
120 : 66392196 : if (cache->hashes.length () == ix)
121 : 66392196 : cache->hashes.safe_push (hash);
122 : : else
123 : 0 : cache->hashes[ix] = hash;
124 : : }
125 : 129471203 : }
126 : :
127 : :
128 : : /* Helper for streamer_tree_cache_insert and streamer_tree_cache_insert_at.
129 : : CACHE, T, and IX_P are as in streamer_tree_cache_insert.
130 : :
131 : : If INSERT_AT_NEXT_SLOT_P is true, T is inserted at the next available
132 : : slot in the cache. Otherwise, T is inserted at the position indicated
133 : : in *IX_P.
134 : :
135 : : If T already existed in CACHE, return true. Otherwise,
136 : : return false. */
137 : :
138 : : static bool
139 : 77186891 : streamer_tree_cache_insert_1 (struct streamer_tree_cache_d *cache,
140 : : tree t, hashval_t hash, unsigned *ix_p,
141 : : bool insert_at_next_slot_p)
142 : : {
143 : 77186891 : bool existed_p;
144 : :
145 : 77186891 : gcc_assert (t);
146 : :
147 : 77186891 : unsigned int &ix = cache->node_map->get_or_insert (t, &existed_p);
148 : 77186891 : if (!existed_p)
149 : : {
150 : : /* Determine the next slot to use in the cache. */
151 : 49826170 : if (insert_at_next_slot_p)
152 : 10249303 : ix = cache->next_idx++;
153 : : else
154 : 39576867 : ix = *ix_p;
155 : :
156 : 49826170 : streamer_tree_cache_add_to_node_array (cache, ix, t, hash);
157 : : }
158 : : else
159 : : {
160 : 27360721 : if (!insert_at_next_slot_p && ix != *ix_p)
161 : : {
162 : : /* If the caller wants to insert T at a specific slot
163 : : location, and ENTRY->TO does not match *IX_P, add T to
164 : : the requested location slot. */
165 : 27360721 : ix = *ix_p;
166 : 27360721 : streamer_tree_cache_add_to_node_array (cache, ix, t, hash);
167 : : }
168 : : }
169 : :
170 : 77186891 : if (ix_p)
171 : 76928784 : *ix_p = ix;
172 : :
173 : 77186891 : return existed_p;
174 : : }
175 : :
176 : :
177 : : /* Insert tree node T in CACHE. If T already existed in the cache
178 : : return true. Otherwise, return false.
179 : :
180 : : If IX_P is non-null, update it with the index into the cache where
181 : : T has been stored. */
182 : :
183 : : bool
184 : 10249303 : streamer_tree_cache_insert (struct streamer_tree_cache_d *cache, tree t,
185 : : hashval_t hash, unsigned *ix_p)
186 : : {
187 : 10249303 : return streamer_tree_cache_insert_1 (cache, t, hash, ix_p, true);
188 : : }
189 : :
190 : :
191 : : /* Replace the tree node with T in CACHE at slot IX. */
192 : :
193 : : void
194 : 168787 : streamer_tree_cache_replace_tree (struct streamer_tree_cache_d *cache,
195 : : tree t, unsigned ix)
196 : : {
197 : 168787 : hashval_t hash = 0;
198 : 168787 : if (cache->hashes.exists ())
199 : 0 : hash = streamer_tree_cache_get_hash (cache, ix);
200 : 168787 : if (!cache->node_map)
201 : 168787 : streamer_tree_cache_add_to_node_array (cache, ix, t, hash);
202 : : else
203 : 0 : streamer_tree_cache_insert_1 (cache, t, hash, &ix, false);
204 : 168787 : }
205 : :
206 : :
207 : : /* Appends tree node T to CACHE, even if T already existed in it. */
208 : :
209 : : void
210 : 119053113 : streamer_tree_cache_append (struct streamer_tree_cache_d *cache,
211 : : tree t, hashval_t hash)
212 : : {
213 : 119053113 : unsigned ix = cache->next_idx++;
214 : 119053113 : if (!cache->node_map)
215 : 52115525 : streamer_tree_cache_add_to_node_array (cache, ix, t, hash);
216 : : else
217 : 66937588 : streamer_tree_cache_insert_1 (cache, t, hash, &ix, false);
218 : 119053113 : }
219 : :
220 : : /* Return true if tree node T exists in CACHE, otherwise false. If IX_P is
221 : : not NULL, write to *IX_P the index into the cache where T is stored
222 : : ((unsigned)-1 if T is not found). */
223 : :
224 : : bool
225 : 72169111 : streamer_tree_cache_lookup (struct streamer_tree_cache_d *cache, tree t,
226 : : unsigned *ix_p)
227 : : {
228 : 72169111 : unsigned *slot;
229 : 72169111 : bool retval;
230 : 72169111 : unsigned ix;
231 : :
232 : 72169111 : gcc_assert (t);
233 : :
234 : 72169111 : slot = cache->node_map->get (t);
235 : 72169111 : if (slot == NULL)
236 : : {
237 : : retval = false;
238 : : ix = -1;
239 : : }
240 : : else
241 : : {
242 : 46377676 : retval = true;
243 : 46377676 : ix = *slot;
244 : : }
245 : :
246 : 72169111 : if (ix_p)
247 : 44765420 : *ix_p = ix;
248 : :
249 : 72169111 : return retval;
250 : : }
251 : :
252 : :
253 : : /* Verify that NODE is in CACHE. */
254 : :
255 : : static void
256 : 5949910 : verify_common_node_recorded (struct streamer_tree_cache_d *cache, tree node)
257 : : {
258 : : /* Restrict this to flag_checking only because in general violating it is
259 : : harmless plus we never know what happens on all targets/frontend/flag(!)
260 : : combinations. */
261 : 5949910 : if (!flag_checking)
262 : : return;
263 : :
264 : 5949550 : if (cache->node_map)
265 : 3560150 : gcc_assert (streamer_tree_cache_lookup (cache, node, NULL));
266 : : else
267 : : {
268 : 2389400 : bool found = false;
269 : 2389400 : gcc_assert (cache->nodes.exists ());
270 : : /* Linear search... */
271 : 134045340 : for (unsigned i = 0; !found && i < cache->nodes.length (); ++i)
272 : 131655940 : if (cache->nodes[i] == node)
273 : 2389400 : found = true;
274 : 2389400 : gcc_assert (found);
275 : : }
276 : : }
277 : :
278 : :
279 : : /* Record NODE in CACHE. */
280 : :
281 : : static void
282 : 104123425 : record_common_node (struct streamer_tree_cache_d *cache, tree node)
283 : : {
284 : : /* If we recursively end up at nodes we do not want to preload simply don't.
285 : : ??? We'd want to verify that this doesn't happen, or alternatively
286 : : do not recurse at all. */
287 : 111858308 : if (node == char_type_node)
288 : : return;
289 : :
290 : 111858308 : gcc_checking_assert (node != boolean_type_node
291 : : && node != boolean_true_node
292 : : && node != boolean_false_node);
293 : :
294 : : /* We have to make sure to fill exactly the same number of
295 : : elements for all frontends. That can include NULL trees.
296 : : As our hash table can't deal with zero entries we'll simply stream
297 : : a random other tree. A NULL tree never will be looked up so it
298 : : doesn't matter which tree we replace it with, just to be sure
299 : : use error_mark_node. */
300 : 111858308 : if (!node)
301 : 5354919 : node = error_mark_node;
302 : :
303 : : /* This hash needs to be equal for all frontend and lto1 invocations. So
304 : : just use the position in the cache as hash value.
305 : : Small integers are used by hash_tree to record positions within scc
306 : : hash. Values are not in same range. */
307 : 111858308 : streamer_tree_cache_append (cache, node, cache->next_idx + 0xc001);
308 : :
309 : 111858308 : switch (TREE_CODE (node))
310 : : {
311 : : case ERROR_MARK:
312 : : case FIELD_DECL:
313 : : case FIXED_POINT_TYPE:
314 : : case IDENTIFIER_NODE:
315 : : case INTEGER_CST:
316 : : case INTEGER_TYPE:
317 : : case REAL_TYPE:
318 : : case TREE_LIST:
319 : : case VOID_CST:
320 : : case VOID_TYPE:
321 : : case OPAQUE_TYPE:
322 : : /* No recursive trees. */
323 : : break;
324 : 7734883 : case ARRAY_TYPE:
325 : 7734883 : case POINTER_TYPE:
326 : 7734883 : case REFERENCE_TYPE:
327 : 7734883 : record_common_node (cache, TREE_TYPE (node));
328 : 7734883 : break;
329 : 5949910 : case COMPLEX_TYPE:
330 : : /* Verify that a complex type's component type (node_type) has been
331 : : handled already (and we thus don't need to recurse here). */
332 : 5949910 : verify_common_node_recorded (cache, TREE_TYPE (node));
333 : 5949910 : break;
334 : 594991 : case RECORD_TYPE:
335 : : /* The FIELD_DECLs of structures should be shared, so that every
336 : : COMPONENT_REF uses the same tree node when referencing a field.
337 : : Pointer equality between FIELD_DECLs is used by the alias
338 : : machinery to compute overlapping component references (see
339 : : nonoverlapping_component_refs_p and
340 : : nonoverlapping_component_refs_of_decl_p). */
341 : 2974955 : for (tree f = TYPE_FIELDS (node); f; f = TREE_CHAIN (f))
342 : 2379964 : record_common_node (cache, f);
343 : : break;
344 : 0 : default:
345 : : /* Unexpected tree code. */
346 : 0 : gcc_unreachable ();
347 : : }
348 : : }
349 : :
350 : :
351 : : /* Preload common nodes into CACHE and make sure they are merged
352 : : properly according to the gimple type table. */
353 : :
354 : : static void
355 : 594991 : preload_common_nodes (struct streamer_tree_cache_d *cache)
356 : : {
357 : 594991 : unsigned i;
358 : :
359 : 11899820 : for (i = 0; i < itk_none; i++)
360 : : /* Skip itk_char. char_type_node is dependent on -f[un]signed-char. */
361 : 11304829 : if (i != itk_char)
362 : 10709838 : record_common_node (cache, integer_types[i]);
363 : :
364 : 2974955 : for (i = 0; i < stk_type_kind_last; i++)
365 : 2379964 : record_common_node (cache, sizetype_tab[i]);
366 : :
367 : 96983533 : for (i = 0; i < TI_MAX; i++)
368 : : /* Skip boolean type and constants, they are frontend dependent. */
369 : 96388542 : if (i != TI_BOOLEAN_TYPE
370 : 96388542 : && i != TI_BOOLEAN_FALSE
371 : 95198560 : && i != TI_BOOLEAN_TRUE
372 : : /* MAIN_IDENTIFIER is not always initialized by Fortran FE. */
373 : 95198560 : && i != TI_MAIN_IDENTIFIER
374 : : /* PID_TYPE is initialized only by C family front-ends. */
375 : 94008578 : && i != TI_PID_TYPE
376 : : /* Skip optimization and target option nodes; they depend on flags. */
377 : 94008578 : && i != TI_OPTIMIZATION_DEFAULT
378 : : && i != TI_OPTIMIZATION_CURRENT
379 : 92818596 : && i != TI_TARGET_OPTION_DEFAULT
380 : : && i != TI_TARGET_OPTION_CURRENT
381 : : && i != TI_CURRENT_TARGET_PRAGMA
382 : : && i != TI_CURRENT_OPTIMIZE_PRAGMA
383 : : /* SCEV state shouldn't reach the IL. */
384 : : && i != TI_CHREC_DONT_KNOW
385 : : && i != TI_CHREC_KNOWN
386 : : /* Skip va_list* related nodes if offloading. For native LTO
387 : : we want them to be merged for the stdarg pass, for offloading
388 : : they might not be identical between host and offloading target. */
389 : 88653659 : && (!lto_stream_offload_p
390 : 0 : || (i != TI_VA_LIST_TYPE
391 : : && i != TI_VA_LIST_GPR_COUNTER_FIELD
392 : 0 : && i != TI_VA_LIST_FPR_COUNTER_FIELD)))
393 : 88653659 : record_common_node (cache, global_trees[i]);
394 : 594991 : }
395 : :
396 : :
397 : : /* Create a cache of pickled nodes. */
398 : :
399 : : struct streamer_tree_cache_d *
400 : 594991 : streamer_tree_cache_create (bool with_hashes, bool with_map, bool with_vec)
401 : : {
402 : 594991 : struct streamer_tree_cache_d *cache;
403 : :
404 : 594991 : cache = XCNEW (struct streamer_tree_cache_d);
405 : :
406 : 594991 : if (with_map)
407 : 356051 : cache->node_map = new hash_map<tree, unsigned> (251);
408 : 594991 : cache->next_idx = 0;
409 : 594991 : if (with_vec)
410 : 238940 : cache->nodes.create (165);
411 : 594991 : if (with_hashes)
412 : 303177 : cache->hashes.create (165);
413 : :
414 : : /* Load all the well-known tree nodes that are always created by
415 : : the compiler on startup. This prevents writing them out
416 : : unnecessarily. */
417 : 594991 : preload_common_nodes (cache);
418 : :
419 : 594991 : return cache;
420 : : }
421 : :
422 : :
423 : : /* Delete the streamer cache C. */
424 : :
425 : : void
426 : 594991 : streamer_tree_cache_delete (struct streamer_tree_cache_d *c)
427 : : {
428 : 594991 : if (c == NULL)
429 : : return;
430 : :
431 : 951042 : delete c->node_map;
432 : 594991 : c->node_map = NULL;
433 : 594991 : c->nodes.release ();
434 : 594991 : c->hashes.release ();
435 : 594991 : free (c);
436 : : }
|