Branch data Line data Source code
1 : : /* Routines for saving various data types to a file stream. This deals
2 : : with various data types like strings, integers, enums, etc.
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 "cgraph.h"
30 : : #include "data-streamer.h"
31 : : #include "value-range.h"
32 : : #include "streamer-hooks.h"
33 : :
34 : :
35 : : /* Adds a new block to output stream OBS. */
36 : :
37 : : void
38 : 705704 : lto_append_block (struct lto_output_stream *obs)
39 : : {
40 : 705704 : struct lto_char_ptr_base *new_block;
41 : :
42 : 705704 : gcc_assert (obs->left_in_block == 0);
43 : :
44 : 705704 : if (obs->first_block == NULL)
45 : : {
46 : : /* This is the first time the stream has been written
47 : : into. */
48 : 662383 : obs->block_size = 1024;
49 : 662383 : new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size);
50 : 662383 : obs->first_block = new_block;
51 : : }
52 : : else
53 : : {
54 : 43321 : struct lto_char_ptr_base *tptr;
55 : : /* Get a new block that is twice as big as the last block
56 : : and link it into the list. */
57 : 43321 : obs->block_size *= 2;
58 : 43321 : new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size);
59 : : /* The first bytes of the block are reserved as a pointer to
60 : : the next block. Set the chain of the full block to the
61 : : pointer to the new block. */
62 : 43321 : tptr = obs->current_block;
63 : 43321 : tptr->ptr = (char *) new_block;
64 : : }
65 : :
66 : : /* Set the place for the next char at the first position after the
67 : : chain to the next block. */
68 : 705704 : obs->current_pointer
69 : 705704 : = ((char *) new_block) + sizeof (struct lto_char_ptr_base);
70 : 705704 : obs->current_block = new_block;
71 : : /* Null out the newly allocated block's pointer to the next block. */
72 : 705704 : new_block->ptr = NULL;
73 : 705704 : obs->left_in_block = obs->block_size - sizeof (struct lto_char_ptr_base);
74 : 705704 : }
75 : :
76 : :
77 : : /* Return index used to reference STRING of LEN characters in the string table
78 : : in OB. The string might or might not include a trailing '\0'.
79 : : Then put the index onto the INDEX_STREAM.
80 : : When PERSISTENT is set, the string S is supposed to not change during
81 : : duration of the OB and thus OB can keep pointer into it. */
82 : :
83 : : static unsigned
84 : 2168510 : streamer_string_index (struct output_block *ob, const char *s, unsigned int len,
85 : : bool persistent)
86 : : {
87 : 2168510 : struct string_slot **slot;
88 : 2168510 : struct string_slot s_slot;
89 : :
90 : 2168510 : s_slot.s = s;
91 : 2168510 : s_slot.len = len;
92 : 2168510 : s_slot.slot_num = 0;
93 : :
94 : 2168510 : slot = ob->string_hash_table->find_slot (&s_slot, INSERT);
95 : 2168510 : if (*slot == NULL)
96 : : {
97 : 1922910 : struct lto_output_stream *string_stream = ob->string_stream;
98 : 1922910 : unsigned int start = string_stream->total_size;
99 : 1922910 : struct string_slot *new_slot = XOBNEW (&ob->obstack, struct string_slot);
100 : 1922910 : const char *string;
101 : :
102 : 1922910 : if (!persistent)
103 : : {
104 : 0 : char *tmp;
105 : 0 : string = tmp = XOBNEWVEC (&ob->obstack, char, len);
106 : 0 : memcpy (tmp, s, len);
107 : : }
108 : : else
109 : : string = s;
110 : :
111 : 1922910 : new_slot->s = string;
112 : 1922910 : new_slot->len = len;
113 : 1922910 : new_slot->slot_num = start;
114 : 1922910 : *slot = new_slot;
115 : 1922910 : streamer_write_uhwi_stream (string_stream, len);
116 : 1922910 : streamer_write_data_stream (string_stream, string, len);
117 : 1922910 : return start + 1;
118 : : }
119 : : else
120 : : {
121 : 245600 : struct string_slot *old_slot = *slot;
122 : 245600 : return old_slot->slot_num + 1;
123 : : }
124 : : }
125 : :
126 : :
127 : : /* Output STRING of LEN characters to the string table in OB. The
128 : : string might or might not include a trailing '\0'. Then put the
129 : : index onto the INDEX_STREAM.
130 : : When PERSISTENT is set, the string S is supposed to not change during
131 : : duration of the OB and thus OB can keep pointer into it. */
132 : :
133 : : void
134 : 1679413 : streamer_write_string_with_length (struct output_block *ob,
135 : : struct lto_output_stream *index_stream,
136 : : const char *s, unsigned int len,
137 : : bool persistent)
138 : : {
139 : 1679413 : if (s)
140 : 1679347 : streamer_write_uhwi_stream (index_stream,
141 : 1679347 : streamer_string_index (ob, s, len, persistent));
142 : : else
143 : 66 : streamer_write_char_stream (index_stream, 0);
144 : 1679413 : }
145 : :
146 : :
147 : : /* Output the '\0' terminated STRING to the string
148 : : table in OB. Then put the index onto the INDEX_STREAM.
149 : : When PERSISTENT is set, the string S is supposed to not change during
150 : : duration of the OB and thus OB can keep pointer into it. */
151 : :
152 : : void
153 : 1714661 : streamer_write_string (struct output_block *ob,
154 : : struct lto_output_stream *index_stream,
155 : : const char *string, bool persistent)
156 : : {
157 : 1714661 : if (string)
158 : 56635 : streamer_write_string_with_length (ob, index_stream, string,
159 : 56635 : strlen (string) + 1,
160 : : persistent);
161 : : else
162 : 1658026 : streamer_write_char_stream (index_stream, 0);
163 : 1714661 : }
164 : :
165 : :
166 : : /* Output STRING of LEN characters to the string table in OB. Then
167 : : put the index into BP.
168 : : When PERSISTENT is set, the string S is supposed to not change during
169 : : duration of the OB and thus OB can keep pointer into it. */
170 : :
171 : : void
172 : 0 : bp_pack_string_with_length (struct output_block *ob, struct bitpack_d *bp,
173 : : const char *s, unsigned int len, bool persistent)
174 : : {
175 : 0 : unsigned index = 0;
176 : 0 : if (s)
177 : 0 : index = streamer_string_index (ob, s, len, persistent);
178 : 0 : bp_pack_var_len_unsigned (bp, index);
179 : 0 : }
180 : :
181 : :
182 : : /* Output the '\0' terminated STRING to the string
183 : : table in OB. Then put the index onto the bitpack BP.
184 : : When PERSISTENT is set, the string S is supposed to not change during
185 : : duration of the OB and thus OB can keep pointer into it. */
186 : :
187 : : void
188 : 784815 : bp_pack_string (struct output_block *ob, struct bitpack_d *bp,
189 : : const char *s, bool persistent)
190 : : {
191 : 784815 : unsigned index = 0;
192 : 784815 : if (s)
193 : 489163 : index = streamer_string_index (ob, s, strlen (s) + 1, persistent);
194 : 784815 : bp_pack_var_len_unsigned (bp, index);
195 : 784815 : }
196 : :
197 : :
198 : :
199 : : /* Write a zero to the output stream. */
200 : :
201 : : void
202 : 11996847 : streamer_write_zero (struct output_block *ob)
203 : : {
204 : 11996847 : streamer_write_char_stream (ob->main_stream, 0);
205 : 11996847 : }
206 : :
207 : :
208 : : /* Write an unsigned HOST_WIDE_INT value WORK to OB->main_stream. */
209 : :
210 : : void
211 : 35084945 : streamer_write_uhwi (struct output_block *ob, unsigned HOST_WIDE_INT work)
212 : : {
213 : 35084945 : streamer_write_uhwi_stream (ob->main_stream, work);
214 : 35084945 : }
215 : :
216 : :
217 : : /* Write a HOST_WIDE_INT value WORK to OB->main_stream. */
218 : :
219 : : void
220 : 27172430 : streamer_write_hwi (struct output_block *ob, HOST_WIDE_INT work)
221 : : {
222 : 27172430 : streamer_write_hwi_stream (ob->main_stream, work);
223 : 27172430 : }
224 : :
225 : : /* Write a poly_uint64 value WORK to OB->main_stream. */
226 : :
227 : : void
228 : 0 : streamer_write_poly_uint64 (struct output_block *ob, poly_uint64 work)
229 : : {
230 : 0 : for (int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
231 : 0 : streamer_write_uhwi_stream (ob->main_stream, work.coeffs[i]);
232 : 0 : }
233 : :
234 : : /* Write a poly_int64 value WORK to OB->main_stream. */
235 : :
236 : : void
237 : 73684 : streamer_write_poly_int64 (struct output_block *ob, poly_int64 work)
238 : : {
239 : 147368 : for (int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
240 : 73684 : streamer_write_hwi_stream (ob->main_stream, work.coeffs[i]);
241 : 73684 : }
242 : :
243 : : /* Write a gcov counter value WORK to OB->main_stream. */
244 : :
245 : : void
246 : 896423 : streamer_write_gcov_count (struct output_block *ob, gcov_type work)
247 : : {
248 : 896423 : streamer_write_gcov_count_stream (ob->main_stream, work);
249 : 896423 : }
250 : :
251 : : /* Write an unsigned HOST_WIDE_INT value WORK to OBS. */
252 : :
253 : : void
254 : 90987103 : streamer_write_uhwi_stream (struct lto_output_stream *obs,
255 : : unsigned HOST_WIDE_INT work)
256 : : {
257 : 90987103 : if (obs->left_in_block == 0)
258 : 513575 : lto_append_block (obs);
259 : 90987103 : char *current_pointer = obs->current_pointer;
260 : 90987103 : unsigned int left_in_block = obs->left_in_block;
261 : 90987103 : unsigned int size = 0;
262 : 157367963 : do
263 : : {
264 : 157367963 : unsigned int byte = (work & 0x7f);
265 : 157367963 : work >>= 7;
266 : 157367963 : if (work != 0)
267 : : /* More bytes to follow. */
268 : 66391862 : byte |= 0x80;
269 : :
270 : 157367963 : *(current_pointer++) = byte;
271 : 157367963 : left_in_block--;
272 : 157367963 : size++;
273 : : }
274 : 157367963 : while (work != 0 && left_in_block > 0);
275 : 90987103 : if (work != 0)
276 : : {
277 : 11002 : obs->left_in_block = 0;
278 : 11002 : lto_append_block (obs);
279 : 11002 : current_pointer = obs->current_pointer;
280 : 11002 : left_in_block = obs->left_in_block;
281 : 32985 : do
282 : : {
283 : 32985 : unsigned int byte = (work & 0x7f);
284 : 32985 : work >>= 7;
285 : 32985 : if (work != 0)
286 : : /* More bytes to follow. */
287 : 21983 : byte |= 0x80;
288 : :
289 : 32985 : *(current_pointer++) = byte;
290 : 32985 : left_in_block--;
291 : 32985 : size++;
292 : : }
293 : 32985 : while (work != 0);
294 : : }
295 : 90987103 : obs->current_pointer = current_pointer;
296 : 90987103 : obs->left_in_block = left_in_block;
297 : 90987103 : obs->total_size += size;
298 : 90987103 : }
299 : :
300 : :
301 : : /* Write a HOST_WIDE_INT value WORK to OBS. */
302 : :
303 : : void
304 : 35051547 : streamer_write_hwi_stream (struct lto_output_stream *obs, HOST_WIDE_INT work)
305 : : {
306 : 35051547 : if (obs->left_in_block == 0)
307 : 20038 : lto_append_block (obs);
308 : 35051547 : char *current_pointer = obs->current_pointer;
309 : 35051547 : unsigned int left_in_block = obs->left_in_block;
310 : 35051547 : unsigned int size = 0;
311 : 65176131 : bool more;
312 : 65176131 : do
313 : : {
314 : 65176131 : unsigned int byte = (work & 0x7f);
315 : : /* If the lower 7-bits are sign-extended 0 or -1 we are finished. */
316 : 65176131 : work >>= 6;
317 : 65176131 : more = !(work == 0 || work == -1);
318 : 65176131 : if (more)
319 : : {
320 : : /* More bits to follow. */
321 : 30129635 : work >>= 1;
322 : 30129635 : byte |= 0x80;
323 : : }
324 : :
325 : 65176131 : *(current_pointer++) = byte;
326 : 65176131 : left_in_block--;
327 : 65176131 : size++;
328 : : }
329 : 65176131 : while (more && left_in_block > 0);
330 : 35051547 : if (more)
331 : : {
332 : 5051 : obs->left_in_block = 0;
333 : 5051 : lto_append_block (obs);
334 : 5051 : current_pointer = obs->current_pointer;
335 : 5051 : left_in_block = obs->left_in_block;
336 : 14550 : do
337 : : {
338 : 7275 : unsigned int byte = (work & 0x7f);
339 : 7275 : work >>= 6;
340 : 7275 : more = !(work == 0 || work == -1);
341 : 7275 : if (more)
342 : : {
343 : 2224 : work >>= 1;
344 : 2224 : byte |= 0x80;
345 : : }
346 : :
347 : 7275 : *(current_pointer++) = byte;
348 : 7275 : left_in_block--;
349 : 7275 : size++;
350 : : }
351 : : while (more);
352 : : }
353 : 35051547 : obs->current_pointer = current_pointer;
354 : 35051547 : obs->left_in_block = left_in_block;
355 : 35051547 : obs->total_size += size;
356 : 35051547 : }
357 : :
358 : : /* Write a GCOV counter value WORK to OBS. */
359 : :
360 : : void
361 : 2000826 : streamer_write_gcov_count_stream (struct lto_output_stream *obs, gcov_type work)
362 : : {
363 : 2000826 : gcc_assert ((HOST_WIDE_INT) work == work);
364 : 2000826 : streamer_write_hwi_stream (obs, work);
365 : 2000826 : }
366 : :
367 : : /* Write raw DATA of length LEN to the output block OB. */
368 : :
369 : : void
370 : 3321994 : streamer_write_data_stream (struct lto_output_stream *obs, const void *data,
371 : : size_t len)
372 : : {
373 : 6646396 : while (len)
374 : : {
375 : 3324402 : size_t copy;
376 : :
377 : : /* No space left. */
378 : 3324402 : if (obs->left_in_block == 0)
379 : 2847 : lto_append_block (obs);
380 : :
381 : : /* Determine how many bytes to copy in this loop. */
382 : 3324402 : if (len <= obs->left_in_block)
383 : : copy = len;
384 : : else
385 : : copy = obs->left_in_block;
386 : :
387 : : /* Copy the data and do bookkeeping. */
388 : 3324402 : memcpy (obs->current_pointer, data, copy);
389 : 3324402 : obs->current_pointer += copy;
390 : 3324402 : obs->total_size += copy;
391 : 3324402 : obs->left_in_block -= copy;
392 : 3324402 : data = (const char *) data + copy;
393 : 3324402 : len -= copy;
394 : : }
395 : 3321994 : }
396 : :
397 : : /* Write REAL_VALUE_TYPE into OB. */
398 : :
399 : : void
400 : 0 : streamer_write_real_value (struct output_block *ob, const REAL_VALUE_TYPE *r)
401 : : {
402 : 0 : bitpack_d bp = bitpack_create (ob->main_stream);
403 : 0 : bp_pack_real_value (&bp, r);
404 : 0 : streamer_write_bitpack (&bp);
405 : 0 : }
406 : :
407 : : void
408 : 434001 : streamer_write_vrange (struct output_block *ob, const vrange &v)
409 : : {
410 : 434001 : gcc_checking_assert (!v.undefined_p ());
411 : :
412 : : // Write the common fields to all vranges.
413 : 434001 : value_range_kind kind = v.m_kind;
414 : 434001 : streamer_write_enum (ob->main_stream, value_range_kind, VR_LAST, kind);
415 : 434001 : stream_write_tree (ob, v.type (), true);
416 : :
417 : 434001 : if (is_a <irange> (v))
418 : : {
419 : 229533 : const irange &r = as_a <irange> (v);
420 : 229533 : streamer_write_uhwi (ob, r.num_pairs ());
421 : 466586 : for (unsigned i = 0; i < r.num_pairs (); ++i)
422 : : {
423 : 237053 : streamer_write_wide_int (ob, r.lower_bound (i));
424 : 237054 : streamer_write_wide_int (ob, r.upper_bound (i));
425 : : }
426 : : // TODO: We could avoid streaming out the value if the mask is -1.
427 : 229533 : irange_bitmask bm = r.get_bitmask ();
428 : 229533 : streamer_write_wide_int (ob, bm.value ());
429 : 229533 : streamer_write_wide_int (ob, bm.mask ());
430 : 229533 : return;
431 : 229533 : }
432 : 204468 : if (is_a <frange> (v))
433 : : {
434 : 0 : const frange &r = as_a <frange> (v);
435 : :
436 : : // Stream out NAN bits.
437 : 0 : bitpack_d bp = bitpack_create (ob->main_stream);
438 : 0 : nan_state nan = r.get_nan_state ();
439 : 0 : bp_pack_value (&bp, nan.pos_p (), 1);
440 : 0 : bp_pack_value (&bp, nan.neg_p (), 1);
441 : 0 : streamer_write_bitpack (&bp);
442 : :
443 : : // Stream out bounds.
444 : 0 : if (kind != VR_NAN)
445 : : {
446 : 0 : REAL_VALUE_TYPE lb = r.lower_bound ();
447 : 0 : REAL_VALUE_TYPE ub = r.upper_bound ();
448 : 0 : streamer_write_real_value (ob, &lb);
449 : 0 : streamer_write_real_value (ob, &ub);
450 : : }
451 : 0 : return;
452 : : }
453 : 204468 : if (is_a <prange> (v))
454 : : {
455 : 204468 : const prange &r = as_a <prange> (v);
456 : 204468 : streamer_write_wide_int (ob, r.lower_bound ());
457 : 204468 : streamer_write_wide_int (ob, r.upper_bound ());
458 : 204468 : irange_bitmask bm = r.get_bitmask ();
459 : 204468 : streamer_write_wide_int (ob, bm.value ());
460 : 204468 : streamer_write_wide_int (ob, bm.mask ());
461 : 204468 : return;
462 : 204468 : }
463 : 0 : gcc_unreachable ();
464 : : }
465 : :
466 : : /* Emit the physical representation of wide_int VAL to output block OB. */
467 : :
468 : : void
469 : 1753218 : streamer_write_wide_int (struct output_block *ob, const wide_int &val)
470 : : {
471 : 1753218 : int len = val.get_len ();
472 : :
473 : 1753218 : streamer_write_uhwi (ob, val.get_precision ());
474 : 1753218 : streamer_write_uhwi (ob, len);
475 : 3513557 : for (int i = 0; i < len; i++)
476 : 1760339 : streamer_write_hwi (ob, val.elt (i));
477 : 1753218 : }
478 : :
479 : : /* Emit the physical representation of widest_int W to output block OB. */
480 : :
481 : : void
482 : 110539 : streamer_write_widest_int (struct output_block *ob,
483 : : const widest_int &w)
484 : : {
485 : 110539 : int len = w.get_len ();
486 : :
487 : 110539 : streamer_write_uhwi (ob, w.get_precision ());
488 : 110539 : streamer_write_uhwi (ob, len);
489 : 222220 : for (int i = 0; i < len; i++)
490 : 111681 : streamer_write_hwi (ob, w.elt (i));
491 : 110539 : }
492 : :
|