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-2026 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 51584 : streamer_check_handled_ts_structures (void)
46 : {
47 51584 : bool handled_p[LAST_TS_ENUM];
48 51584 : unsigned i;
49 :
50 51584 : 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 51584 : handled_p[TS_BASE] = true;
55 51584 : handled_p[TS_TYPED] = true;
56 51584 : handled_p[TS_COMMON] = true;
57 51584 : handled_p[TS_INT_CST] = true;
58 51584 : handled_p[TS_POLY_INT_CST] = true;
59 51584 : handled_p[TS_REAL_CST] = true;
60 51584 : handled_p[TS_FIXED_CST] = true;
61 51584 : handled_p[TS_VECTOR] = true;
62 51584 : handled_p[TS_STRING] = true;
63 51584 : handled_p[TS_RAW_DATA_CST] = true;
64 51584 : handled_p[TS_COMPLEX] = true;
65 51584 : handled_p[TS_IDENTIFIER] = true;
66 51584 : handled_p[TS_DECL_MINIMAL] = true;
67 51584 : handled_p[TS_DECL_COMMON] = true;
68 51584 : handled_p[TS_DECL_WRTL] = true;
69 51584 : handled_p[TS_DECL_NON_COMMON] = true;
70 51584 : handled_p[TS_DECL_WITH_VIS] = true;
71 51584 : handled_p[TS_FIELD_DECL] = true;
72 51584 : handled_p[TS_VAR_DECL] = true;
73 51584 : handled_p[TS_PARM_DECL] = true;
74 51584 : handled_p[TS_LABEL_DECL] = true;
75 51584 : handled_p[TS_RESULT_DECL] = true;
76 51584 : handled_p[TS_CONST_DECL] = true;
77 51584 : handled_p[TS_TYPE_DECL] = true;
78 51584 : handled_p[TS_FUNCTION_DECL] = true;
79 51584 : handled_p[TS_TYPE_COMMON] = true;
80 51584 : handled_p[TS_TYPE_WITH_LANG_SPECIFIC] = true;
81 51584 : handled_p[TS_TYPE_NON_COMMON] = true;
82 51584 : handled_p[TS_LIST] = true;
83 51584 : handled_p[TS_VEC] = true;
84 51584 : handled_p[TS_EXP] = true;
85 51584 : handled_p[TS_SSA_NAME] = true;
86 51584 : handled_p[TS_BLOCK] = true;
87 51584 : handled_p[TS_BINFO] = true;
88 51584 : handled_p[TS_STATEMENT_LIST] = true;
89 51584 : handled_p[TS_CONSTRUCTOR] = true;
90 51584 : handled_p[TS_OMP_CLAUSE] = true;
91 51584 : handled_p[TS_OPTIMIZATION] = true;
92 51584 : handled_p[TS_TARGET_OPTION] = true;
93 51584 : 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 2114944 : for (i = 0; i < LAST_TS_ENUM; i++)
99 2063360 : gcc_assert (handled_p[i]);
100 51584 : }
101 :
102 :
103 : /* Helper for streamer_tree_cache_insert_1. Add T to CACHE->NODES at
104 : slot IX. */
105 :
106 : static void
107 109835684 : 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 109835684 : if (cache->nodes.exists ())
112 : {
113 42604253 : if (cache->nodes.length () == ix)
114 42450452 : cache->nodes.safe_push (t);
115 : else
116 153801 : cache->nodes[ix] = t;
117 : }
118 109835684 : if (cache->hashes.exists ())
119 : {
120 57637515 : if (cache->hashes.length () == ix)
121 57637515 : cache->hashes.safe_push (hash);
122 : else
123 0 : cache->hashes[ix] = hash;
124 : }
125 109835684 : }
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 67231431 : 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 67231431 : bool existed_p;
144 :
145 67231431 : gcc_assert (t);
146 :
147 67231431 : unsigned int &ix = cache->node_map->get_or_insert (t, &existed_p);
148 67231431 : if (!existed_p)
149 : {
150 : /* Determine the next slot to use in the cache. */
151 43085238 : if (insert_at_next_slot_p)
152 8134611 : ix = cache->next_idx++;
153 : else
154 34950627 : ix = *ix_p;
155 :
156 43085238 : streamer_tree_cache_add_to_node_array (cache, ix, t, hash);
157 : }
158 : else
159 : {
160 24146193 : 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 24146193 : ix = *ix_p;
166 24146193 : streamer_tree_cache_add_to_node_array (cache, ix, t, hash);
167 : }
168 : }
169 :
170 67231431 : if (ix_p)
171 66956827 : *ix_p = ix;
172 :
173 67231431 : 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 8134611 : streamer_tree_cache_insert (struct streamer_tree_cache_d *cache, tree t,
185 : hashval_t hash, unsigned *ix_p)
186 : {
187 8134611 : 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 153801 : streamer_tree_cache_replace_tree (struct streamer_tree_cache_d *cache,
195 : tree t, unsigned ix)
196 : {
197 153801 : hashval_t hash = 0;
198 153801 : if (cache->hashes.exists ())
199 0 : hash = streamer_tree_cache_get_hash (cache, ix);
200 153801 : if (!cache->node_map)
201 153801 : 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 153801 : }
205 :
206 :
207 : /* Appends tree node T to CACHE, even if T already existed in it. */
208 :
209 : void
210 101547272 : streamer_tree_cache_append (struct streamer_tree_cache_d *cache,
211 : tree t, hashval_t hash)
212 : {
213 101547272 : unsigned ix = cache->next_idx++;
214 101547272 : if (!cache->node_map)
215 42450452 : streamer_tree_cache_add_to_node_array (cache, ix, t, hash);
216 : else
217 59096820 : streamer_tree_cache_insert_1 (cache, t, hash, &ix, false);
218 101547272 : }
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 60308980 : streamer_tree_cache_lookup (struct streamer_tree_cache_d *cache, tree t,
226 : unsigned *ix_p)
227 : {
228 60308980 : unsigned *slot;
229 60308980 : bool retval;
230 60308980 : unsigned ix;
231 :
232 60308980 : gcc_assert (t);
233 :
234 60308980 : slot = cache->node_map->get (t);
235 60308980 : if (slot == NULL)
236 : {
237 : retval = false;
238 : ix = -1;
239 : }
240 : else
241 : {
242 39549681 : retval = true;
243 39549681 : ix = *slot;
244 : }
245 :
246 60308980 : if (ix_p)
247 37574834 : *ix_p = ix;
248 :
249 60308980 : return retval;
250 : }
251 :
252 :
253 : /* Verify that NODE is in CACHE. */
254 :
255 : static void
256 5133430 : 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 5133430 : if (!flag_checking)
262 : return;
263 :
264 5133050 : if (cache->node_map)
265 3143070 : gcc_assert (streamer_tree_cache_lookup (cache, node, NULL));
266 : else
267 : {
268 1989980 : bool found = false;
269 1989980 : gcc_assert (cache->nodes.exists ());
270 : /* Linear search... */
271 111637878 : for (unsigned i = 0; !found && i < cache->nodes.length (); ++i)
272 109647898 : if (cache->nodes[i] == node)
273 1989980 : found = true;
274 1989980 : gcc_assert (found);
275 : }
276 : }
277 :
278 :
279 : /* Record NODE in CACHE. */
280 :
281 : static void
282 89834993 : 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 96508452 : if (node == char_type_node)
288 : return;
289 :
290 96508444 : 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 96508444 : if (!node)
301 4620127 : 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 96508444 : streamer_tree_cache_append (cache, node, cache->next_idx + 0xc001);
308 :
309 96508444 : 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 6673459 : case ARRAY_TYPE:
325 6673459 : case POINTER_TYPE:
326 6673459 : case REFERENCE_TYPE:
327 6673459 : record_common_node (cache, TREE_TYPE (node));
328 6673459 : break;
329 5133430 : 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 5133430 : verify_common_node_recorded (cache, TREE_TYPE (node));
333 5133430 : break;
334 513335 : 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 2566675 : for (tree f = TYPE_FIELDS (node); f; f = TREE_CHAIN (f))
342 2053340 : 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 513343 : preload_common_nodes (struct streamer_tree_cache_d *cache)
356 : {
357 513343 : unsigned i;
358 :
359 10266860 : for (i = 0; i < itk_none; i++)
360 : /* Skip itk_char. char_type_node is dependent on -f[un]signed-char. */
361 9753517 : if (i != itk_char)
362 9240174 : record_common_node (cache, integer_types[i]);
363 :
364 2566715 : for (i = 0; i < stk_type_kind_last; i++)
365 2053372 : record_common_node (cache, sizetype_tab[i]);
366 :
367 83674909 : for (i = 0; i < TI_MAX; i++)
368 : /* Skip boolean type and constants, they are frontend dependent. */
369 83161566 : if (i != TI_BOOLEAN_TYPE
370 83161566 : && i != TI_BOOLEAN_FALSE
371 82134880 : && i != TI_BOOLEAN_TRUE
372 : /* MAIN_IDENTIFIER is not always initialized by Fortran FE. */
373 82134880 : && i != TI_MAIN_IDENTIFIER
374 : /* PID_TYPE is initialized only by C family front-ends. */
375 81108194 : && i != TI_PID_TYPE
376 : /* Skip optimization and target option nodes; they depend on flags. */
377 81108194 : && i != TI_OPTIMIZATION_DEFAULT
378 : && i != TI_OPTIMIZATION_CURRENT
379 80081508 : && 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 76488107 : && (!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 76488107 : record_common_node (cache, global_trees[i]);
394 513343 : }
395 :
396 :
397 : /* Create a cache of pickled nodes. */
398 :
399 : struct streamer_tree_cache_d *
400 513343 : streamer_tree_cache_create (bool with_hashes, bool with_map, bool with_vec)
401 : {
402 513343 : struct streamer_tree_cache_d *cache;
403 :
404 513343 : cache = XCNEW (struct streamer_tree_cache_d);
405 :
406 513343 : if (with_map)
407 314345 : cache->node_map = new hash_map<tree, unsigned> (251);
408 513343 : cache->next_idx = 0;
409 513343 : if (with_vec)
410 198998 : cache->nodes.create (165);
411 513343 : if (with_hashes)
412 267759 : 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 513343 : preload_common_nodes (cache);
418 :
419 513343 : return cache;
420 : }
421 :
422 :
423 : /* Delete the streamer cache C. */
424 :
425 : void
426 513343 : streamer_tree_cache_delete (struct streamer_tree_cache_d *c)
427 : {
428 513343 : if (c == NULL)
429 : return;
430 :
431 827688 : delete c->node_map;
432 513343 : c->node_map = NULL;
433 513343 : c->nodes.release ();
434 513343 : c->hashes.release ();
435 513343 : free (c);
436 : }
|