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