]>
Commit | Line | Data |
---|---|---|
2541503d | 1 | /* Routines for saving various data types to a file stream. This deals |
2 | with various data types like strings, integers, enums, etc. | |
3 | ||
fbd26352 | 4 | Copyright (C) 2011-2019 Free Software Foundation, Inc. |
2541503d | 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" | |
9ef16211 | 26 | #include "backend.h" |
b20a8bb4 | 27 | #include "tree.h" |
9ef16211 | 28 | #include "gimple.h" |
1140c305 | 29 | #include "cgraph.h" |
2541503d | 30 | #include "data-streamer.h" |
31 | ||
a797f9ee | 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 | ||
2541503d | 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 | ||
b5054e4c | 81 | static unsigned |
7f385784 | 82 | streamer_string_index (struct output_block *ob, const char *s, unsigned int len, |
83 | bool persistent) | |
2541503d | 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 | ||
c1f445d2 | 92 | slot = ob->string_hash_table->find_slot (&s_slot, INSERT); |
2541503d | 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; | |
7f385784 | 113 | streamer_write_uhwi_stream (string_stream, len); |
a797f9ee | 114 | streamer_write_data_stream (string_stream, string, len); |
2541503d | 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 | |
7f385784 | 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) | |
2541503d | 136 | { |
137 | if (s) | |
7f385784 | 138 | streamer_write_uhwi_stream (index_stream, |
139 | streamer_string_index (ob, s, len, persistent)); | |
2541503d | 140 | else |
7f385784 | 141 | streamer_write_char_stream (index_stream, 0); |
2541503d | 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 | |
7f385784 | 151 | streamer_write_string (struct output_block *ob, |
152 | struct lto_output_stream *index_stream, | |
153 | const char *string, bool persistent) | |
2541503d | 154 | { |
155 | if (string) | |
7f385784 | 156 | streamer_write_string_with_length (ob, index_stream, string, |
157 | strlen (string) + 1, | |
158 | persistent); | |
2541503d | 159 | else |
7f385784 | 160 | streamer_write_char_stream (index_stream, 0); |
2541503d | 161 | } |
162 | ||
163 | ||
07de37ab | 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 | ||
2541503d | 197 | /* Write a zero to the output stream. */ |
198 | ||
199 | void | |
7f385784 | 200 | streamer_write_zero (struct output_block *ob) |
2541503d | 201 | { |
7f385784 | 202 | streamer_write_char_stream (ob->main_stream, 0); |
2541503d | 203 | } |
204 | ||
205 | ||
7f385784 | 206 | /* Write an unsigned HOST_WIDE_INT value WORK to OB->main_stream. */ |
2541503d | 207 | |
208 | void | |
7f385784 | 209 | streamer_write_uhwi (struct output_block *ob, unsigned HOST_WIDE_INT work) |
2541503d | 210 | { |
7f385784 | 211 | streamer_write_uhwi_stream (ob->main_stream, work); |
2541503d | 212 | } |
213 | ||
214 | ||
7f385784 | 215 | /* Write a HOST_WIDE_INT value WORK to OB->main_stream. */ |
2541503d | 216 | |
217 | void | |
7f385784 | 218 | streamer_write_hwi (struct output_block *ob, HOST_WIDE_INT work) |
2541503d | 219 | { |
7f385784 | 220 | streamer_write_hwi_stream (ob->main_stream, work); |
2541503d | 221 | } |
222 | ||
fc44a215 | 223 | /* Write a gcov counter value WORK to OB->main_stream. */ |
224 | ||
225 | void | |
226 | streamer_write_gcov_count (struct output_block *ob, gcov_type work) | |
227 | { | |
228 | streamer_write_gcov_count_stream (ob->main_stream, work); | |
229 | } | |
2541503d | 230 | |
7f385784 | 231 | /* Write an unsigned HOST_WIDE_INT value WORK to OBS. */ |
2541503d | 232 | |
233 | void | |
7f385784 | 234 | streamer_write_uhwi_stream (struct lto_output_stream *obs, |
235 | unsigned HOST_WIDE_INT work) | |
2541503d | 236 | { |
2f5bed2a | 237 | if (obs->left_in_block == 0) |
238 | lto_append_block (obs); | |
239 | char *current_pointer = obs->current_pointer; | |
240 | unsigned int left_in_block = obs->left_in_block; | |
241 | unsigned int size = 0; | |
2541503d | 242 | do |
243 | { | |
244 | unsigned int byte = (work & 0x7f); | |
245 | work >>= 7; | |
246 | if (work != 0) | |
247 | /* More bytes to follow. */ | |
248 | byte |= 0x80; | |
249 | ||
2f5bed2a | 250 | *(current_pointer++) = byte; |
251 | left_in_block--; | |
252 | size++; | |
2541503d | 253 | } |
2f5bed2a | 254 | while (work != 0 && left_in_block > 0); |
255 | if (work != 0) | |
256 | { | |
257 | obs->left_in_block = 0; | |
258 | lto_append_block (obs); | |
259 | current_pointer = obs->current_pointer; | |
260 | left_in_block = obs->left_in_block; | |
261 | do | |
262 | { | |
263 | unsigned int byte = (work & 0x7f); | |
264 | work >>= 7; | |
265 | if (work != 0) | |
266 | /* More bytes to follow. */ | |
267 | byte |= 0x80; | |
268 | ||
269 | *(current_pointer++) = byte; | |
270 | left_in_block--; | |
271 | size++; | |
272 | } | |
273 | while (work != 0); | |
274 | } | |
275 | obs->current_pointer = current_pointer; | |
276 | obs->left_in_block = left_in_block; | |
277 | obs->total_size += size; | |
2541503d | 278 | } |
279 | ||
280 | ||
7f385784 | 281 | /* Write a HOST_WIDE_INT value WORK to OBS. */ |
2541503d | 282 | |
283 | void | |
7f385784 | 284 | streamer_write_hwi_stream (struct lto_output_stream *obs, HOST_WIDE_INT work) |
2541503d | 285 | { |
2f5bed2a | 286 | if (obs->left_in_block == 0) |
287 | lto_append_block (obs); | |
288 | char *current_pointer = obs->current_pointer; | |
289 | unsigned int left_in_block = obs->left_in_block; | |
290 | unsigned int size = 0; | |
291 | bool more; | |
2541503d | 292 | do |
293 | { | |
2f5bed2a | 294 | unsigned int byte = (work & 0x7f); |
295 | /* If the lower 7-bits are sign-extended 0 or -1 we are finished. */ | |
296 | work >>= 6; | |
297 | more = !(work == 0 || work == -1); | |
2541503d | 298 | if (more) |
2f5bed2a | 299 | { |
300 | /* More bits to follow. */ | |
301 | work >>= 1; | |
302 | byte |= 0x80; | |
303 | } | |
304 | ||
305 | *(current_pointer++) = byte; | |
306 | left_in_block--; | |
307 | size++; | |
308 | } | |
309 | while (more && left_in_block > 0); | |
310 | if (more) | |
311 | { | |
312 | obs->left_in_block = 0; | |
313 | lto_append_block (obs); | |
314 | current_pointer = obs->current_pointer; | |
315 | left_in_block = obs->left_in_block; | |
316 | do | |
317 | { | |
318 | unsigned int byte = (work & 0x7f); | |
319 | work >>= 6; | |
320 | more = !(work == 0 || work == -1); | |
321 | if (more) | |
322 | { | |
323 | work >>= 1; | |
324 | byte |= 0x80; | |
325 | } | |
326 | ||
327 | *(current_pointer++) = byte; | |
328 | left_in_block--; | |
329 | size++; | |
330 | } | |
331 | while (more); | |
2541503d | 332 | } |
2f5bed2a | 333 | obs->current_pointer = current_pointer; |
334 | obs->left_in_block = left_in_block; | |
335 | obs->total_size += size; | |
2541503d | 336 | } |
fc44a215 | 337 | |
338 | /* Write a GCOV counter value WORK to OBS. */ | |
339 | ||
340 | void | |
341 | streamer_write_gcov_count_stream (struct lto_output_stream *obs, gcov_type work) | |
342 | { | |
fc44a215 | 343 | gcc_assert ((HOST_WIDE_INT) work == work); |
344 | streamer_write_hwi_stream (obs, work); | |
345 | } | |
a797f9ee | 346 | |
347 | /* Write raw DATA of length LEN to the output block OB. */ | |
348 | ||
349 | void | |
350 | streamer_write_data_stream (struct lto_output_stream *obs, const void *data, | |
351 | size_t len) | |
352 | { | |
353 | while (len) | |
354 | { | |
355 | size_t copy; | |
356 | ||
357 | /* No space left. */ | |
358 | if (obs->left_in_block == 0) | |
359 | lto_append_block (obs); | |
360 | ||
361 | /* Determine how many bytes to copy in this loop. */ | |
362 | if (len <= obs->left_in_block) | |
363 | copy = len; | |
364 | else | |
365 | copy = obs->left_in_block; | |
366 | ||
367 | /* Copy the data and do bookkeeping. */ | |
368 | memcpy (obs->current_pointer, data, copy); | |
369 | obs->current_pointer += copy; | |
370 | obs->total_size += copy; | |
371 | obs->left_in_block -= copy; | |
372 | data = (const char *) data + copy; | |
373 | len -= copy; | |
374 | } | |
375 | } | |
376 | ||
8cf48217 | 377 | /* Emit the physical representation of wide_int VAL to output block OB. */ |
378 | ||
379 | void | |
380 | streamer_write_wide_int (struct output_block *ob, const wide_int &val) | |
381 | { | |
382 | int len = val.get_len (); | |
383 | ||
384 | streamer_write_uhwi (ob, val.get_precision ()); | |
385 | streamer_write_uhwi (ob, len); | |
386 | for (int i = 0; i < len; i++) | |
387 | streamer_write_hwi (ob, val.elt (i)); | |
388 | } | |
389 | ||
390 | /* Emit the physical representation of widest_int W to output block OB. */ | |
391 | ||
392 | void | |
393 | streamer_write_widest_int (struct output_block *ob, | |
394 | const widest_int &w) | |
395 | { | |
396 | int len = w.get_len (); | |
397 | ||
398 | streamer_write_uhwi (ob, w.get_precision ()); | |
399 | streamer_write_uhwi (ob, len); | |
400 | for (int i = 0; i < len; i++) | |
401 | streamer_write_hwi (ob, w.elt (i)); | |
402 | } | |
403 |