111
|
1 /* Routines for saving various data types to a file stream. This deals
|
|
2 with various data types like strings, integers, enums, etc.
|
|
3
|
131
|
4 Copyright (C) 2011-2018 Free Software Foundation, Inc.
|
111
|
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
|
|
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
|
|
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
|
|
81 static unsigned
|
|
82 streamer_string_index (struct output_block *ob, const char *s, unsigned int len,
|
|
83 bool persistent)
|
|
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
|
|
92 slot = ob->string_hash_table->find_slot (&s_slot, INSERT);
|
|
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;
|
|
113 streamer_write_uhwi_stream (string_stream, len);
|
|
114 streamer_write_data_stream (string_stream, string, len);
|
|
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
|
|
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)
|
|
136 {
|
|
137 if (s)
|
|
138 streamer_write_uhwi_stream (index_stream,
|
|
139 streamer_string_index (ob, s, len, persistent));
|
|
140 else
|
|
141 streamer_write_char_stream (index_stream, 0);
|
|
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
|
|
151 streamer_write_string (struct output_block *ob,
|
|
152 struct lto_output_stream *index_stream,
|
|
153 const char *string, bool persistent)
|
|
154 {
|
|
155 if (string)
|
|
156 streamer_write_string_with_length (ob, index_stream, string,
|
|
157 strlen (string) + 1,
|
|
158 persistent);
|
|
159 else
|
|
160 streamer_write_char_stream (index_stream, 0);
|
|
161 }
|
|
162
|
|
163
|
|
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
|
|
197 /* Write a zero to the output stream. */
|
|
198
|
|
199 void
|
|
200 streamer_write_zero (struct output_block *ob)
|
|
201 {
|
|
202 streamer_write_char_stream (ob->main_stream, 0);
|
|
203 }
|
|
204
|
|
205
|
|
206 /* Write an unsigned HOST_WIDE_INT value WORK to OB->main_stream. */
|
|
207
|
|
208 void
|
|
209 streamer_write_uhwi (struct output_block *ob, unsigned HOST_WIDE_INT work)
|
|
210 {
|
|
211 streamer_write_uhwi_stream (ob->main_stream, work);
|
|
212 }
|
|
213
|
|
214
|
|
215 /* Write a HOST_WIDE_INT value WORK to OB->main_stream. */
|
|
216
|
|
217 void
|
|
218 streamer_write_hwi (struct output_block *ob, HOST_WIDE_INT work)
|
|
219 {
|
|
220 streamer_write_hwi_stream (ob->main_stream, work);
|
|
221 }
|
|
222
|
|
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 }
|
|
230
|
|
231 /* Write an unsigned HOST_WIDE_INT value WORK to OBS. */
|
|
232
|
|
233 void
|
|
234 streamer_write_uhwi_stream (struct lto_output_stream *obs,
|
|
235 unsigned HOST_WIDE_INT work)
|
|
236 {
|
|
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;
|
|
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
|
|
250 *(current_pointer++) = byte;
|
|
251 left_in_block--;
|
|
252 size++;
|
|
253 }
|
|
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;
|
|
278 }
|
|
279
|
|
280
|
|
281 /* Write a HOST_WIDE_INT value WORK to OBS. */
|
|
282
|
|
283 void
|
|
284 streamer_write_hwi_stream (struct lto_output_stream *obs, HOST_WIDE_INT work)
|
|
285 {
|
|
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;
|
|
292 do
|
|
293 {
|
|
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);
|
|
298 if (more)
|
|
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);
|
|
332 }
|
|
333 obs->current_pointer = current_pointer;
|
|
334 obs->left_in_block = left_in_block;
|
|
335 obs->total_size += size;
|
|
336 }
|
|
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 {
|
|
343 gcc_assert ((HOST_WIDE_INT) work == work);
|
|
344 streamer_write_hwi_stream (obs, work);
|
|
345 }
|
|
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
|
|
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
|