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