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