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