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 : 51113 : streamer_check_handled_ts_structures (void)
46 : : {
47 : 51113 : bool handled_p[LAST_TS_ENUM];
48 : 51113 : unsigned i;
49 : :
50 : 51113 : 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 : 51113 : handled_p[TS_BASE] = true;
55 : 51113 : handled_p[TS_TYPED] = true;
56 : 51113 : handled_p[TS_COMMON] = true;
57 : 51113 : handled_p[TS_INT_CST] = true;
58 : 51113 : handled_p[TS_POLY_INT_CST] = true;
59 : 51113 : handled_p[TS_REAL_CST] = true;
60 : 51113 : handled_p[TS_FIXED_CST] = true;
61 : 51113 : handled_p[TS_VECTOR] = true;
62 : 51113 : handled_p[TS_STRING] = true;
63 : 51113 : handled_p[TS_COMPLEX] = true;
64 : 51113 : handled_p[TS_IDENTIFIER] = true;
65 : 51113 : handled_p[TS_DECL_MINIMAL] = true;
66 : 51113 : handled_p[TS_DECL_COMMON] = true;
67 : 51113 : handled_p[TS_DECL_WRTL] = true;
68 : 51113 : handled_p[TS_DECL_NON_COMMON] = true;
69 : 51113 : handled_p[TS_DECL_WITH_VIS] = true;
70 : 51113 : handled_p[TS_FIELD_DECL] = true;
71 : 51113 : handled_p[TS_VAR_DECL] = true;
72 : 51113 : handled_p[TS_PARM_DECL] = true;
73 : 51113 : handled_p[TS_LABEL_DECL] = true;
74 : 51113 : handled_p[TS_RESULT_DECL] = true;
75 : 51113 : handled_p[TS_CONST_DECL] = true;
76 : 51113 : handled_p[TS_TYPE_DECL] = true;
77 : 51113 : handled_p[TS_FUNCTION_DECL] = true;
78 : 51113 : handled_p[TS_TYPE_COMMON] = true;
79 : 51113 : handled_p[TS_TYPE_WITH_LANG_SPECIFIC] = true;
80 : 51113 : handled_p[TS_TYPE_NON_COMMON] = true;
81 : 51113 : handled_p[TS_LIST] = true;
82 : 51113 : handled_p[TS_VEC] = true;
83 : 51113 : handled_p[TS_EXP] = true;
84 : 51113 : handled_p[TS_SSA_NAME] = true;
85 : 51113 : handled_p[TS_BLOCK] = true;
86 : 51113 : handled_p[TS_BINFO] = true;
87 : 51113 : handled_p[TS_STATEMENT_LIST] = true;
88 : 51113 : handled_p[TS_CONSTRUCTOR] = true;
89 : 51113 : handled_p[TS_OMP_CLAUSE] = true;
90 : 51113 : handled_p[TS_OPTIMIZATION] = true;
91 : 51113 : handled_p[TS_TARGET_OPTION] = true;
92 : 51113 : handled_p[TS_TRANSLATION_UNIT_DECL] = true;
93 : :
94 : : /* Anything not marked above will trigger the following assertion.
95 : : If this assertion triggers, it means that there is a new TS_*
96 : : structure that should be handled by the streamer. */
97 : 2044520 : for (i = 0; i < LAST_TS_ENUM; i++)
98 : 1993407 : gcc_assert (handled_p[i]);
99 : 51113 : }
100 : :
101 : :
102 : : /* Helper for streamer_tree_cache_insert_1. Add T to CACHE->NODES at
103 : : slot IX. */
104 : :
105 : : static void
106 : 106498167 : streamer_tree_cache_add_to_node_array (struct streamer_tree_cache_d *cache,
107 : : unsigned ix, tree t, hashval_t hash)
108 : : {
109 : : /* We're either replacing an old element or appending consecutively. */
110 : 106498167 : if (cache->nodes.exists ())
111 : : {
112 : 41365816 : if (cache->nodes.length () == ix)
113 : 41214645 : cache->nodes.safe_push (t);
114 : : else
115 : 151171 : cache->nodes[ix] = t;
116 : : }
117 : 106498167 : if (cache->hashes.exists ())
118 : : {
119 : 55516023 : if (cache->hashes.length () == ix)
120 : 55516023 : cache->hashes.safe_push (hash);
121 : : else
122 : 0 : cache->hashes[ix] = hash;
123 : : }
124 : 106498167 : }
125 : :
126 : :
127 : : /* Helper for streamer_tree_cache_insert and streamer_tree_cache_insert_at.
128 : : CACHE, T, and IX_P are as in streamer_tree_cache_insert.
129 : :
130 : : If INSERT_AT_NEXT_SLOT_P is true, T is inserted at the next available
131 : : slot in the cache. Otherwise, T is inserted at the position indicated
132 : : in *IX_P.
133 : :
134 : : If T already existed in CACHE, return true. Otherwise,
135 : : return false. */
136 : :
137 : : static bool
138 : 65132351 : streamer_tree_cache_insert_1 (struct streamer_tree_cache_d *cache,
139 : : tree t, hashval_t hash, unsigned *ix_p,
140 : : bool insert_at_next_slot_p)
141 : : {
142 : 65132351 : bool existed_p;
143 : :
144 : 65132351 : gcc_assert (t);
145 : :
146 : 65132351 : unsigned int &ix = cache->node_map->get_or_insert (t, &existed_p);
147 : 65132351 : if (!existed_p)
148 : : {
149 : : /* Determine the next slot to use in the cache. */
150 : 41714360 : if (insert_at_next_slot_p)
151 : 7820551 : ix = cache->next_idx++;
152 : : else
153 : 33893809 : ix = *ix_p;
154 : :
155 : 41714360 : streamer_tree_cache_add_to_node_array (cache, ix, t, hash);
156 : : }
157 : : else
158 : : {
159 : 23417991 : if (!insert_at_next_slot_p && ix != *ix_p)
160 : : {
161 : : /* If the caller wants to insert T at a specific slot
162 : : location, and ENTRY->TO does not match *IX_P, add T to
163 : : the requested location slot. */
164 : 23417991 : ix = *ix_p;
165 : 23417991 : streamer_tree_cache_add_to_node_array (cache, ix, t, hash);
166 : : }
167 : : }
168 : :
169 : 65132351 : if (ix_p)
170 : 64879248 : *ix_p = ix;
171 : :
172 : 65132351 : return existed_p;
173 : : }
174 : :
175 : :
176 : : /* Insert tree node T in CACHE. If T already existed in the cache
177 : : return true. Otherwise, return false.
178 : :
179 : : If IX_P is non-null, update it with the index into the cache where
180 : : T has been stored. */
181 : :
182 : : bool
183 : 7820551 : streamer_tree_cache_insert (struct streamer_tree_cache_d *cache, tree t,
184 : : hashval_t hash, unsigned *ix_p)
185 : : {
186 : 7820551 : return streamer_tree_cache_insert_1 (cache, t, hash, ix_p, true);
187 : : }
188 : :
189 : :
190 : : /* Replace the tree node with T in CACHE at slot IX. */
191 : :
192 : : void
193 : 151171 : streamer_tree_cache_replace_tree (struct streamer_tree_cache_d *cache,
194 : : tree t, unsigned ix)
195 : : {
196 : 151171 : hashval_t hash = 0;
197 : 151171 : if (cache->hashes.exists ())
198 : 0 : hash = streamer_tree_cache_get_hash (cache, ix);
199 : 151171 : if (!cache->node_map)
200 : 151171 : streamer_tree_cache_add_to_node_array (cache, ix, t, hash);
201 : : else
202 : 0 : streamer_tree_cache_insert_1 (cache, t, hash, &ix, false);
203 : 151171 : }
204 : :
205 : :
206 : : /* Appends tree node T to CACHE, even if T already existed in it. */
207 : :
208 : : void
209 : 98526445 : streamer_tree_cache_append (struct streamer_tree_cache_d *cache,
210 : : tree t, hashval_t hash)
211 : : {
212 : 98526445 : unsigned ix = cache->next_idx++;
213 : 98526445 : if (!cache->node_map)
214 : 41214645 : streamer_tree_cache_add_to_node_array (cache, ix, t, hash);
215 : : else
216 : 57311800 : streamer_tree_cache_insert_1 (cache, t, hash, &ix, false);
217 : 98526445 : }
218 : :
219 : : /* Return true if tree node T exists in CACHE, otherwise false. If IX_P is
220 : : not NULL, write to *IX_P the index into the cache where T is stored
221 : : ((unsigned)-1 if T is not found). */
222 : :
223 : : bool
224 : 58112785 : streamer_tree_cache_lookup (struct streamer_tree_cache_d *cache, tree t,
225 : : unsigned *ix_p)
226 : : {
227 : 58112785 : unsigned *slot;
228 : 58112785 : bool retval;
229 : 58112785 : unsigned ix;
230 : :
231 : 58112785 : gcc_assert (t);
232 : :
233 : 58112785 : slot = cache->node_map->get (t);
234 : 58112785 : if (slot == NULL)
235 : : {
236 : : retval = false;
237 : : ix = -1;
238 : : }
239 : : else
240 : : {
241 : 38038900 : retval = true;
242 : 38038900 : ix = *slot;
243 : : }
244 : :
245 : 58112785 : if (ix_p)
246 : 36239726 : *ix_p = ix;
247 : :
248 : 58112785 : return retval;
249 : : }
250 : :
251 : :
252 : : /* Verify that NODE is in CACHE. */
253 : :
254 : : static void
255 : 4986860 : verify_common_node_recorded (struct streamer_tree_cache_d *cache, tree node)
256 : : {
257 : : /* Restrict this to flag_checking only because in general violating it is
258 : : harmless plus we never know what happens on all targets/frontend/flag(!)
259 : : combinations. */
260 : 4986860 : if (!flag_checking)
261 : : return;
262 : :
263 : 4986450 : if (cache->node_map)
264 : 3048090 : gcc_assert (streamer_tree_cache_lookup (cache, node, NULL));
265 : : else
266 : : {
267 : 1938360 : bool found = false;
268 : 1938360 : gcc_assert (cache->nodes.exists ());
269 : : /* Linear search... */
270 : 110486520 : for (unsigned i = 0; !found && i < cache->nodes.length (); ++i)
271 : 108548160 : if (cache->nodes[i] == node)
272 : 1938360 : found = true;
273 : 1938360 : gcc_assert (found);
274 : : }
275 : : }
276 : :
277 : :
278 : : /* Record NODE in CACHE. */
279 : :
280 : : static void
281 : 87270050 : record_common_node (struct streamer_tree_cache_d *cache, tree node)
282 : : {
283 : : /* If we recursively end up at nodes we do not want to preload simply don't.
284 : : ??? We'd want to verify that this doesn't happen, or alternatively
285 : : do not recurse at all. */
286 : 93752968 : if (node == char_type_node)
287 : : return;
288 : :
289 : 93752968 : gcc_checking_assert (node != boolean_type_node
290 : : && node != boolean_true_node
291 : : && node != boolean_false_node);
292 : :
293 : : /* We have to make sure to fill exactly the same number of
294 : : elements for all frontends. That can include NULL trees.
295 : : As our hash table can't deal with zero entries we'll simply stream
296 : : a random other tree. A NULL tree never will be looked up so it
297 : : doesn't matter which tree we replace it with, just to be sure
298 : : use error_mark_node. */
299 : 93752968 : if (!node)
300 : 4488174 : node = error_mark_node;
301 : :
302 : : /* This hash needs to be equal for all frontend and lto1 invocations. So
303 : : just use the position in the cache as hash value.
304 : : Small integers are used by hash_tree to record positions within scc
305 : : hash. Values are not in same range. */
306 : 93752968 : streamer_tree_cache_append (cache, node, cache->next_idx + 0xc001);
307 : :
308 : 93752968 : switch (TREE_CODE (node))
309 : : {
310 : : case ERROR_MARK:
311 : : case FIELD_DECL:
312 : : case FIXED_POINT_TYPE:
313 : : case IDENTIFIER_NODE:
314 : : case INTEGER_CST:
315 : : case INTEGER_TYPE:
316 : : case REAL_TYPE:
317 : : case TREE_LIST:
318 : : case VOID_CST:
319 : : case VOID_TYPE:
320 : : case OPAQUE_TYPE:
321 : : /* No recursive trees. */
322 : : break;
323 : 6482918 : case ARRAY_TYPE:
324 : 6482918 : case POINTER_TYPE:
325 : 6482918 : case REFERENCE_TYPE:
326 : 6482918 : record_common_node (cache, TREE_TYPE (node));
327 : 6482918 : break;
328 : 4986860 : case COMPLEX_TYPE:
329 : : /* Verify that a complex type's component type (node_type) has been
330 : : handled already (and we thus don't need to recurse here). */
331 : 4986860 : verify_common_node_recorded (cache, TREE_TYPE (node));
332 : 4986860 : break;
333 : 498686 : case RECORD_TYPE:
334 : : /* The FIELD_DECLs of structures should be shared, so that every
335 : : COMPONENT_REF uses the same tree node when referencing a field.
336 : : Pointer equality between FIELD_DECLs is used by the alias
337 : : machinery to compute overlapping component references (see
338 : : nonoverlapping_component_refs_p and
339 : : nonoverlapping_component_refs_of_decl_p). */
340 : 2493430 : for (tree f = TYPE_FIELDS (node); f; f = TREE_CHAIN (f))
341 : 1994744 : record_common_node (cache, f);
342 : : break;
343 : 0 : default:
344 : : /* Unexpected tree code. */
345 : 0 : gcc_unreachable ();
346 : : }
347 : : }
348 : :
349 : :
350 : : /* Preload common nodes into CACHE and make sure they are merged
351 : : properly according to the gimple type table. */
352 : :
353 : : static void
354 : 498686 : preload_common_nodes (struct streamer_tree_cache_d *cache)
355 : : {
356 : 498686 : unsigned i;
357 : :
358 : 9973720 : for (i = 0; i < itk_none; i++)
359 : : /* Skip itk_char. char_type_node is dependent on -f[un]signed-char. */
360 : 9475034 : if (i != itk_char)
361 : 8976348 : record_common_node (cache, integer_types[i]);
362 : :
363 : 2493430 : for (i = 0; i < stk_type_kind_last; i++)
364 : 1994744 : record_common_node (cache, sizetype_tab[i]);
365 : :
366 : 81285818 : for (i = 0; i < TI_MAX; i++)
367 : : /* Skip boolean type and constants, they are frontend dependent. */
368 : 80787132 : if (i != TI_BOOLEAN_TYPE
369 : 80787132 : && i != TI_BOOLEAN_FALSE
370 : 79789760 : && i != TI_BOOLEAN_TRUE
371 : : /* MAIN_IDENTIFIER is not always initialized by Fortran FE. */
372 : 79789760 : && i != TI_MAIN_IDENTIFIER
373 : : /* PID_TYPE is initialized only by C family front-ends. */
374 : 78792388 : && i != TI_PID_TYPE
375 : : /* Skip optimization and target option nodes; they depend on flags. */
376 : 78792388 : && i != TI_OPTIMIZATION_DEFAULT
377 : : && i != TI_OPTIMIZATION_CURRENT
378 : 77795016 : && i != TI_TARGET_OPTION_DEFAULT
379 : : && i != TI_TARGET_OPTION_CURRENT
380 : : && i != TI_CURRENT_TARGET_PRAGMA
381 : : && i != TI_CURRENT_OPTIMIZE_PRAGMA
382 : : /* SCEV state shouldn't reach the IL. */
383 : : && i != TI_CHREC_DONT_KNOW
384 : : && i != TI_CHREC_KNOWN
385 : : /* Skip va_list* related nodes if offloading. For native LTO
386 : : we want them to be merged for the stdarg pass, for offloading
387 : : they might not be identical between host and offloading target. */
388 : 74304214 : && (!lto_stream_offload_p
389 : 0 : || (i != TI_VA_LIST_TYPE
390 : : && i != TI_VA_LIST_GPR_COUNTER_FIELD
391 : 0 : && i != TI_VA_LIST_FPR_COUNTER_FIELD)))
392 : 74304214 : record_common_node (cache, global_trees[i]);
393 : 498686 : }
394 : :
395 : :
396 : : /* Create a cache of pickled nodes. */
397 : :
398 : : struct streamer_tree_cache_d *
399 : 498686 : streamer_tree_cache_create (bool with_hashes, bool with_map, bool with_vec)
400 : : {
401 : 498686 : struct streamer_tree_cache_d *cache;
402 : :
403 : 498686 : cache = XCNEW (struct streamer_tree_cache_d);
404 : :
405 : 498686 : if (with_map)
406 : 304850 : cache->node_map = new hash_map<tree, unsigned> (251);
407 : 498686 : cache->next_idx = 0;
408 : 498686 : if (with_vec)
409 : 193836 : cache->nodes.create (165);
410 : 498686 : if (with_hashes)
411 : 257771 : cache->hashes.create (165);
412 : :
413 : : /* Load all the well-known tree nodes that are always created by
414 : : the compiler on startup. This prevents writing them out
415 : : unnecessarily. */
416 : 498686 : preload_common_nodes (cache);
417 : :
418 : 498686 : return cache;
419 : : }
420 : :
421 : :
422 : : /* Delete the streamer cache C. */
423 : :
424 : : void
425 : 498686 : streamer_tree_cache_delete (struct streamer_tree_cache_d *c)
426 : : {
427 : 498686 : if (c == NULL)
428 : : return;
429 : :
430 : 803536 : delete c->node_map;
431 : 498686 : c->node_map = NULL;
432 : 498686 : c->nodes.release ();
433 : 498686 : c->hashes.release ();
434 : 498686 : free (c);
435 : : }
|