]>
Commit | Line | Data |
---|---|---|
f0efc7aa DN |
1 | /* Routines for saving various data types to a file stream. This deals |
2 | with various data types like strings, integers, enums, etc. | |
3 | ||
8d9254fc | 4 | Copyright (C) 2011-2020 Free Software Foundation, Inc. |
f0efc7aa DN |
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" | |
c7131fb2 | 26 | #include "backend.h" |
40e23961 | 27 | #include "tree.h" |
c7131fb2 | 28 | #include "gimple.h" |
c582198b | 29 | #include "cgraph.h" |
f0efc7aa DN |
30 | #include "data-streamer.h" |
31 | ||
bfa2ebe3 RB |
32 | |
33 | /* Adds a new block to output stream OBS. */ | |
34 | ||
35 | void | |
36 | lto_append_block (struct lto_output_stream *obs) | |
37 | { | |
38 | struct lto_char_ptr_base *new_block; | |
39 | ||
40 | gcc_assert (obs->left_in_block == 0); | |
41 | ||
42 | if (obs->first_block == NULL) | |
43 | { | |
44 | /* This is the first time the stream has been written | |
45 | into. */ | |
46 | obs->block_size = 1024; | |
47 | new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size); | |
48 | obs->first_block = new_block; | |
49 | } | |
50 | else | |
51 | { | |
52 | struct lto_char_ptr_base *tptr; | |
53 | /* Get a new block that is twice as big as the last block | |
54 | and link it into the list. */ | |
55 | obs->block_size *= 2; | |
56 | new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size); | |
57 | /* The first bytes of the block are reserved as a pointer to | |
58 | the next block. Set the chain of the full block to the | |
59 | pointer to the new block. */ | |
60 | tptr = obs->current_block; | |
61 | tptr->ptr = (char *) new_block; | |
62 | } | |
63 | ||
64 | /* Set the place for the next char at the first position after the | |
65 | chain to the next block. */ | |
66 | obs->current_pointer | |
67 | = ((char *) new_block) + sizeof (struct lto_char_ptr_base); | |
68 | obs->current_block = new_block; | |
69 | /* Null out the newly allocated block's pointer to the next block. */ | |
70 | new_block->ptr = NULL; | |
71 | obs->left_in_block = obs->block_size - sizeof (struct lto_char_ptr_base); | |
72 | } | |
73 | ||
74 | ||
f0efc7aa DN |
75 | /* Return index used to reference STRING of LEN characters in the string table |
76 | in OB. The string might or might not include a trailing '\0'. | |
77 | Then put the index onto the INDEX_STREAM. | |
78 | When PERSISTENT is set, the string S is supposed to not change during | |
79 | duration of the OB and thus OB can keep pointer into it. */ | |
80 | ||
4b5337e6 | 81 | static unsigned |
412288f1 DN |
82 | streamer_string_index (struct output_block *ob, const char *s, unsigned int len, |
83 | bool persistent) | |
f0efc7aa DN |
84 | { |
85 | struct string_slot **slot; | |
86 | struct string_slot s_slot; | |
87 | ||
88 | s_slot.s = s; | |
89 | s_slot.len = len; | |
90 | s_slot.slot_num = 0; | |
91 | ||
c203e8a7 | 92 | slot = ob->string_hash_table->find_slot (&s_slot, INSERT); |
f0efc7aa DN |
93 | if (*slot == NULL) |
94 | { | |
95 | struct lto_output_stream *string_stream = ob->string_stream; | |
96 | unsigned int start = string_stream->total_size; | |
97 | struct string_slot *new_slot = XOBNEW (&ob->obstack, struct string_slot); | |
98 | const char *string; | |
99 | ||
100 | if (!persistent) | |
101 | { | |
102 | char *tmp; | |
103 | string = tmp = XOBNEWVEC (&ob->obstack, char, len); | |
104 | memcpy (tmp, s, len); | |
105 | } | |
106 | else | |
107 | string = s; | |
108 | ||
109 | new_slot->s = string; | |
110 | new_slot->len = len; | |
111 | new_slot->slot_num = start; | |
112 | *slot = new_slot; | |
412288f1 | 113 | streamer_write_uhwi_stream (string_stream, len); |
bfa2ebe3 | 114 | streamer_write_data_stream (string_stream, string, len); |
f0efc7aa DN |
115 | return start + 1; |
116 | } | |
117 | else | |
118 | { | |
119 | struct string_slot *old_slot = *slot; | |
120 | return old_slot->slot_num + 1; | |
121 | } | |
122 | } | |
123 | ||
124 | ||
125 | /* Output STRING of LEN characters to the string table in OB. The | |
126 | string might or might not include a trailing '\0'. Then put the | |
127 | index onto the INDEX_STREAM. | |
128 | When PERSISTENT is set, the string S is supposed to not change during | |
129 | duration of the OB and thus OB can keep pointer into it. */ | |
130 | ||
131 | void | |
412288f1 DN |
132 | streamer_write_string_with_length (struct output_block *ob, |
133 | struct lto_output_stream *index_stream, | |
134 | const char *s, unsigned int len, | |
135 | bool persistent) | |
f0efc7aa DN |
136 | { |
137 | if (s) | |
412288f1 DN |
138 | streamer_write_uhwi_stream (index_stream, |
139 | streamer_string_index (ob, s, len, persistent)); | |
f0efc7aa | 140 | else |
412288f1 | 141 | streamer_write_char_stream (index_stream, 0); |
f0efc7aa DN |
142 | } |
143 | ||
144 | ||
145 | /* Output the '\0' terminated STRING to the string | |
146 | table in OB. Then put the index onto the INDEX_STREAM. | |
147 | When PERSISTENT is set, the string S is supposed to not change during | |
148 | duration of the OB and thus OB can keep pointer into it. */ | |
149 | ||
150 | void | |
412288f1 DN |
151 | streamer_write_string (struct output_block *ob, |
152 | struct lto_output_stream *index_stream, | |
153 | const char *string, bool persistent) | |
f0efc7aa DN |
154 | { |
155 | if (string) | |
412288f1 DN |
156 | streamer_write_string_with_length (ob, index_stream, string, |
157 | strlen (string) + 1, | |
158 | persistent); | |
f0efc7aa | 159 | else |
412288f1 | 160 | streamer_write_char_stream (index_stream, 0); |
f0efc7aa DN |
161 | } |
162 | ||
163 | ||
8135e1e6 RB |
164 | /* Output STRING of LEN characters to the string table in OB. Then |
165 | put the index into BP. | |
166 | When PERSISTENT is set, the string S is supposed to not change during | |
167 | duration of the OB and thus OB can keep pointer into it. */ | |
168 | ||
169 | void | |
170 | bp_pack_string_with_length (struct output_block *ob, struct bitpack_d *bp, | |
171 | const char *s, unsigned int len, bool persistent) | |
172 | { | |
173 | unsigned index = 0; | |
174 | if (s) | |
175 | index = streamer_string_index (ob, s, len, persistent); | |
176 | bp_pack_var_len_unsigned (bp, index); | |
177 | } | |
178 | ||
179 | ||
180 | /* Output the '\0' terminated STRING to the string | |
181 | table in OB. Then put the index onto the bitpack BP. | |
182 | When PERSISTENT is set, the string S is supposed to not change during | |
183 | duration of the OB and thus OB can keep pointer into it. */ | |
184 | ||
185 | void | |
186 | bp_pack_string (struct output_block *ob, struct bitpack_d *bp, | |
187 | const char *s, bool persistent) | |
188 | { | |
189 | unsigned index = 0; | |
190 | if (s) | |
191 | index = streamer_string_index (ob, s, strlen (s) + 1, persistent); | |
192 | bp_pack_var_len_unsigned (bp, index); | |
193 | } | |
194 | ||
195 | ||
196 | ||
f0efc7aa DN |
197 | /* Write a zero to the output stream. */ |
198 | ||
199 | void | |
412288f1 | 200 | streamer_write_zero (struct output_block *ob) |
f0efc7aa | 201 | { |
412288f1 | 202 | streamer_write_char_stream (ob->main_stream, 0); |
f0efc7aa DN |
203 | } |
204 | ||
205 | ||
412288f1 | 206 | /* Write an unsigned HOST_WIDE_INT value WORK to OB->main_stream. */ |
f0efc7aa DN |
207 | |
208 | void | |
412288f1 | 209 | streamer_write_uhwi (struct output_block *ob, unsigned HOST_WIDE_INT work) |
f0efc7aa | 210 | { |
412288f1 | 211 | streamer_write_uhwi_stream (ob->main_stream, work); |
f0efc7aa DN |
212 | } |
213 | ||
214 | ||
412288f1 | 215 | /* Write a HOST_WIDE_INT value WORK to OB->main_stream. */ |
f0efc7aa DN |
216 | |
217 | void | |
412288f1 | 218 | streamer_write_hwi (struct output_block *ob, HOST_WIDE_INT work) |
f0efc7aa | 219 | { |
412288f1 | 220 | streamer_write_hwi_stream (ob->main_stream, work); |
f0efc7aa DN |
221 | } |
222 | ||
86003645 RS |
223 | /* Write a poly_uint64 value WORK to OB->main_stream. */ |
224 | ||
225 | void | |
226 | streamer_write_poly_uint64 (struct output_block *ob, poly_uint64 work) | |
227 | { | |
228 | for (int i = 0; i < NUM_POLY_INT_COEFFS; ++i) | |
229 | streamer_write_uhwi_stream (ob->main_stream, work.coeffs[i]); | |
230 | } | |
231 | ||
89ab31c1 JH |
232 | /* Write a gcov counter value WORK to OB->main_stream. */ |
233 | ||
234 | void | |
235 | streamer_write_gcov_count (struct output_block *ob, gcov_type work) | |
236 | { | |
237 | streamer_write_gcov_count_stream (ob->main_stream, work); | |
238 | } | |
f0efc7aa | 239 | |
412288f1 | 240 | /* Write an unsigned HOST_WIDE_INT value WORK to OBS. */ |
f0efc7aa DN |
241 | |
242 | void | |
412288f1 DN |
243 | streamer_write_uhwi_stream (struct lto_output_stream *obs, |
244 | unsigned HOST_WIDE_INT work) | |
f0efc7aa | 245 | { |
a4fa02d1 RB |
246 | if (obs->left_in_block == 0) |
247 | lto_append_block (obs); | |
248 | char *current_pointer = obs->current_pointer; | |
249 | unsigned int left_in_block = obs->left_in_block; | |
250 | unsigned int size = 0; | |
f0efc7aa DN |
251 | do |
252 | { | |
253 | unsigned int byte = (work & 0x7f); | |
254 | work >>= 7; | |
255 | if (work != 0) | |
256 | /* More bytes to follow. */ | |
257 | byte |= 0x80; | |
258 | ||
a4fa02d1 RB |
259 | *(current_pointer++) = byte; |
260 | left_in_block--; | |
261 | size++; | |
f0efc7aa | 262 | } |
a4fa02d1 RB |
263 | while (work != 0 && left_in_block > 0); |
264 | if (work != 0) | |
265 | { | |
266 | obs->left_in_block = 0; | |
267 | lto_append_block (obs); | |
268 | current_pointer = obs->current_pointer; | |
269 | left_in_block = obs->left_in_block; | |
270 | do | |
271 | { | |
272 | unsigned int byte = (work & 0x7f); | |
273 | work >>= 7; | |
274 | if (work != 0) | |
275 | /* More bytes to follow. */ | |
276 | byte |= 0x80; | |
277 | ||
278 | *(current_pointer++) = byte; | |
279 | left_in_block--; | |
280 | size++; | |
281 | } | |
282 | while (work != 0); | |
283 | } | |
284 | obs->current_pointer = current_pointer; | |
285 | obs->left_in_block = left_in_block; | |
286 | obs->total_size += size; | |
f0efc7aa DN |
287 | } |
288 | ||
289 | ||
412288f1 | 290 | /* Write a HOST_WIDE_INT value WORK to OBS. */ |
f0efc7aa DN |
291 | |
292 | void | |
412288f1 | 293 | streamer_write_hwi_stream (struct lto_output_stream *obs, HOST_WIDE_INT work) |
f0efc7aa | 294 | { |
a4fa02d1 RB |
295 | if (obs->left_in_block == 0) |
296 | lto_append_block (obs); | |
297 | char *current_pointer = obs->current_pointer; | |
298 | unsigned int left_in_block = obs->left_in_block; | |
299 | unsigned int size = 0; | |
300 | bool more; | |
f0efc7aa DN |
301 | do |
302 | { | |
a4fa02d1 RB |
303 | unsigned int byte = (work & 0x7f); |
304 | /* If the lower 7-bits are sign-extended 0 or -1 we are finished. */ | |
305 | work >>= 6; | |
306 | more = !(work == 0 || work == -1); | |
f0efc7aa | 307 | if (more) |
a4fa02d1 RB |
308 | { |
309 | /* More bits to follow. */ | |
310 | work >>= 1; | |
311 | byte |= 0x80; | |
312 | } | |
313 | ||
314 | *(current_pointer++) = byte; | |
315 | left_in_block--; | |
316 | size++; | |
317 | } | |
318 | while (more && left_in_block > 0); | |
319 | if (more) | |
320 | { | |
321 | obs->left_in_block = 0; | |
322 | lto_append_block (obs); | |
323 | current_pointer = obs->current_pointer; | |
324 | left_in_block = obs->left_in_block; | |
325 | do | |
326 | { | |
327 | unsigned int byte = (work & 0x7f); | |
328 | work >>= 6; | |
329 | more = !(work == 0 || work == -1); | |
330 | if (more) | |
331 | { | |
332 | work >>= 1; | |
333 | byte |= 0x80; | |
334 | } | |
335 | ||
336 | *(current_pointer++) = byte; | |
337 | left_in_block--; | |
338 | size++; | |
339 | } | |
340 | while (more); | |
f0efc7aa | 341 | } |
a4fa02d1 RB |
342 | obs->current_pointer = current_pointer; |
343 | obs->left_in_block = left_in_block; | |
344 | obs->total_size += size; | |
f0efc7aa | 345 | } |
89ab31c1 JH |
346 | |
347 | /* Write a GCOV counter value WORK to OBS. */ | |
348 | ||
349 | void | |
350 | streamer_write_gcov_count_stream (struct lto_output_stream *obs, gcov_type work) | |
351 | { | |
89ab31c1 JH |
352 | gcc_assert ((HOST_WIDE_INT) work == work); |
353 | streamer_write_hwi_stream (obs, work); | |
354 | } | |
bfa2ebe3 RB |
355 | |
356 | /* Write raw DATA of length LEN to the output block OB. */ | |
357 | ||
358 | void | |
359 | streamer_write_data_stream (struct lto_output_stream *obs, const void *data, | |
360 | size_t len) | |
361 | { | |
362 | while (len) | |
363 | { | |
364 | size_t copy; | |
365 | ||
366 | /* No space left. */ | |
367 | if (obs->left_in_block == 0) | |
368 | lto_append_block (obs); | |
369 | ||
370 | /* Determine how many bytes to copy in this loop. */ | |
371 | if (len <= obs->left_in_block) | |
372 | copy = len; | |
373 | else | |
374 | copy = obs->left_in_block; | |
375 | ||
376 | /* Copy the data and do bookkeeping. */ | |
377 | memcpy (obs->current_pointer, data, copy); | |
378 | obs->current_pointer += copy; | |
379 | obs->total_size += copy; | |
380 | obs->left_in_block -= copy; | |
381 | data = (const char *) data + copy; | |
382 | len -= copy; | |
383 | } | |
384 | } | |
385 | ||
a73f34c2 KV |
386 | /* Emit the physical representation of wide_int VAL to output block OB. */ |
387 | ||
388 | void | |
389 | streamer_write_wide_int (struct output_block *ob, const wide_int &val) | |
390 | { | |
391 | int len = val.get_len (); | |
392 | ||
393 | streamer_write_uhwi (ob, val.get_precision ()); | |
394 | streamer_write_uhwi (ob, len); | |
395 | for (int i = 0; i < len; i++) | |
396 | streamer_write_hwi (ob, val.elt (i)); | |
397 | } | |
398 | ||
399 | /* Emit the physical representation of widest_int W to output block OB. */ | |
400 | ||
401 | void | |
402 | streamer_write_widest_int (struct output_block *ob, | |
403 | const widest_int &w) | |
404 | { | |
405 | int len = w.get_len (); | |
406 | ||
407 | streamer_write_uhwi (ob, w.get_precision ()); | |
408 | streamer_write_uhwi (ob, len); | |
409 | for (int i = 0; i < len; i++) | |
410 | streamer_write_hwi (ob, w.elt (i)); | |
411 | } | |
412 |