]>
Commit | Line | Data |
---|---|---|
d7f09764 DN |
1 | /* Functions for writing LTO sections. |
2 | ||
3 | Copyright (C) 2009 Free Software Foundation, Inc. | |
4 | Contributed by Kenneth Zadeck <zadeck@naturalbridge.com> | |
5 | ||
6 | This file is part of GCC. | |
7 | ||
8 | GCC is free software; you can redistribute it and/or modify it under | |
9 | the terms of the GNU General Public License as published by the Free | |
10 | Software Foundation; either version 3, or (at your option) any later | |
11 | version. | |
12 | ||
13 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 | for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with GCC; see the file COPYING3. If not see | |
20 | <http://www.gnu.org/licenses/>. */ | |
21 | ||
22 | #include "config.h" | |
23 | #include "system.h" | |
24 | #include "coretypes.h" | |
25 | #include "tm.h" | |
26 | #include "toplev.h" | |
27 | #include "tree.h" | |
28 | #include "expr.h" | |
29 | #include "params.h" | |
30 | #include "input.h" | |
d7f09764 DN |
31 | #include "hashtab.h" |
32 | #include "basic-block.h" | |
33 | #include "tree-flow.h" | |
34 | #include "tree-pass.h" | |
35 | #include "cgraph.h" | |
36 | #include "function.h" | |
37 | #include "ggc.h" | |
38 | #include "except.h" | |
39 | #include "vec.h" | |
40 | #include "pointer-set.h" | |
41 | #include "bitmap.h" | |
42 | #include "langhooks.h" | |
43 | #include "lto-streamer.h" | |
44 | #include "lto-compress.h" | |
45 | ||
46 | static VEC(lto_out_decl_state_ptr, heap) *decl_state_stack; | |
47 | ||
48 | /* List of out decl states used by functions. We use this to | |
49 | generate the decl directory later. */ | |
50 | ||
51 | VEC(lto_out_decl_state_ptr, heap) *lto_function_decl_states; | |
d7f09764 DN |
52 | /* Returns a hash code for P. */ |
53 | ||
54 | hashval_t | |
55 | lto_hash_decl_slot_node (const void *p) | |
56 | { | |
57 | const struct lto_decl_slot *ds = (const struct lto_decl_slot *) p; | |
58 | ||
59 | /* | |
60 | return (hashval_t) DECL_UID (ds->t); | |
61 | */ | |
62 | return (hashval_t) TREE_HASH (ds->t); | |
63 | } | |
64 | ||
65 | ||
66 | /* Returns nonzero if P1 and P2 are equal. */ | |
67 | ||
68 | int | |
69 | lto_eq_decl_slot_node (const void *p1, const void *p2) | |
70 | { | |
71 | const struct lto_decl_slot *ds1 = | |
72 | (const struct lto_decl_slot *) p1; | |
73 | const struct lto_decl_slot *ds2 = | |
74 | (const struct lto_decl_slot *) p2; | |
75 | ||
76 | /* | |
77 | return DECL_UID (ds1->t) == DECL_UID (ds2->t); | |
78 | */ | |
79 | return ds1->t == ds2->t; | |
80 | } | |
81 | ||
82 | ||
83 | /* Returns a hash code for P. */ | |
84 | ||
85 | hashval_t | |
86 | lto_hash_type_slot_node (const void *p) | |
87 | { | |
88 | const struct lto_decl_slot *ds = (const struct lto_decl_slot *) p; | |
89 | return (hashval_t) TYPE_UID (ds->t); | |
90 | } | |
91 | ||
92 | ||
93 | /* Returns nonzero if P1 and P2 are equal. */ | |
94 | ||
95 | int | |
96 | lto_eq_type_slot_node (const void *p1, const void *p2) | |
97 | { | |
98 | const struct lto_decl_slot *ds1 = | |
99 | (const struct lto_decl_slot *) p1; | |
100 | const struct lto_decl_slot *ds2 = | |
101 | (const struct lto_decl_slot *) p2; | |
102 | ||
103 | return TYPE_UID (ds1->t) == TYPE_UID (ds2->t); | |
104 | } | |
105 | ||
106 | /***************************************************************************** | |
107 | Output routines shared by all of the serialization passes. | |
108 | *****************************************************************************/ | |
109 | ||
110 | ||
111 | /* Flush compressed stream data function, sends NUM_CHARS from CHARS | |
112 | to the append lang hook, OPAQUE is currently always NULL. */ | |
113 | ||
114 | static void | |
115 | lto_append_data (const char *chars, unsigned int num_chars, void *opaque) | |
116 | { | |
117 | gcc_assert (opaque == NULL); | |
118 | lang_hooks.lto.append_data (chars, num_chars, opaque); | |
119 | } | |
120 | ||
121 | /* Pointer to the current compression stream. */ | |
122 | ||
123 | static struct lto_compression_stream *compression_stream = NULL; | |
124 | ||
125 | /* Begin a new output section named NAME. If COMPRESS is true, zlib compress | |
126 | the section. */ | |
127 | ||
128 | void | |
129 | lto_begin_section (const char *name, bool compress) | |
130 | { | |
131 | lang_hooks.lto.begin_section (name); | |
132 | ||
133 | /* FIXME lto: for now, suppress compression if the lang_hook that appends | |
134 | data is anything other than assembler output. The effect here is that | |
135 | we get compression of IL only in non-ltrans object files. */ | |
136 | gcc_assert (compression_stream == NULL); | |
137 | if (compress) | |
138 | compression_stream = lto_start_compression (lto_append_data, NULL); | |
139 | } | |
140 | ||
141 | ||
142 | /* End the current output section. */ | |
143 | ||
144 | void | |
145 | lto_end_section (void) | |
146 | { | |
147 | if (compression_stream) | |
148 | { | |
149 | lto_end_compression (compression_stream); | |
150 | compression_stream = NULL; | |
151 | } | |
152 | lang_hooks.lto.end_section (); | |
153 | } | |
154 | ||
155 | ||
156 | /* Write all of the chars in OBS to the assembler. Recycle the blocks | |
157 | in obs as this is being done. */ | |
158 | ||
159 | void | |
160 | lto_write_stream (struct lto_output_stream *obs) | |
161 | { | |
162 | unsigned int block_size = 1024; | |
163 | struct lto_char_ptr_base *block; | |
164 | struct lto_char_ptr_base *next_block; | |
165 | if (!obs->first_block) | |
166 | return; | |
167 | ||
168 | for (block = obs->first_block; block; block = next_block) | |
169 | { | |
170 | const char *base = ((char *)block) + sizeof (struct lto_char_ptr_base); | |
171 | unsigned int num_chars = block_size - sizeof (struct lto_char_ptr_base); | |
172 | ||
173 | /* If this is not the last block, it is full. If it is the last | |
174 | block, left_in_block indicates how many chars are unoccupied in | |
175 | this block; subtract from num_chars to obtain occupancy. */ | |
176 | next_block = (struct lto_char_ptr_base *) block->ptr; | |
177 | if (!next_block) | |
178 | num_chars -= obs->left_in_block; | |
179 | ||
180 | /* FIXME lto: WPA mode uses an ELF function as a lang_hook to append | |
181 | output data. This hook is not happy with the way that compression | |
182 | blocks up output differently to the way it's blocked here. So for | |
183 | now, we don't compress WPA output. */ | |
184 | if (compression_stream) | |
185 | { | |
186 | lto_compress_block (compression_stream, base, num_chars); | |
187 | lang_hooks.lto.append_data (NULL, 0, block); | |
188 | } | |
189 | else | |
190 | lang_hooks.lto.append_data (base, num_chars, block); | |
191 | block_size *= 2; | |
192 | } | |
193 | } | |
194 | ||
195 | ||
196 | /* Adds a new block to output stream OBS. */ | |
197 | ||
198 | static void | |
199 | append_block (struct lto_output_stream *obs) | |
200 | { | |
201 | struct lto_char_ptr_base *new_block; | |
202 | ||
203 | gcc_assert (obs->left_in_block == 0); | |
204 | ||
205 | if (obs->first_block == NULL) | |
206 | { | |
207 | /* This is the first time the stream has been written | |
208 | into. */ | |
209 | obs->block_size = 1024; | |
210 | new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size); | |
211 | obs->first_block = new_block; | |
212 | } | |
213 | else | |
214 | { | |
215 | struct lto_char_ptr_base *tptr; | |
216 | /* Get a new block that is twice as big as the last block | |
217 | and link it into the list. */ | |
218 | obs->block_size *= 2; | |
219 | new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size); | |
220 | /* The first bytes of the block are reserved as a pointer to | |
221 | the next block. Set the chain of the full block to the | |
222 | pointer to the new block. */ | |
223 | tptr = obs->current_block; | |
224 | tptr->ptr = (char *) new_block; | |
225 | } | |
226 | ||
227 | /* Set the place for the next char at the first position after the | |
228 | chain to the next block. */ | |
229 | obs->current_pointer | |
230 | = ((char *) new_block) + sizeof (struct lto_char_ptr_base); | |
231 | obs->current_block = new_block; | |
232 | /* Null out the newly allocated block's pointer to the next block. */ | |
233 | new_block->ptr = NULL; | |
234 | obs->left_in_block = obs->block_size - sizeof (struct lto_char_ptr_base); | |
235 | } | |
236 | ||
237 | ||
238 | /* Write a character to the output block. */ | |
239 | ||
240 | void | |
241 | lto_output_1_stream (struct lto_output_stream *obs, char c) | |
242 | { | |
243 | /* No space left. */ | |
244 | if (obs->left_in_block == 0) | |
245 | append_block (obs); | |
246 | ||
247 | /* Write the actual character. */ | |
248 | *obs->current_pointer = c; | |
249 | obs->current_pointer++; | |
250 | obs->total_size++; | |
251 | obs->left_in_block--; | |
252 | } | |
253 | ||
254 | ||
255 | /* Write raw DATA of length LEN to the output block OB. */ | |
256 | ||
257 | void | |
258 | lto_output_data_stream (struct lto_output_stream *obs, const void *data, | |
259 | size_t len) | |
260 | { | |
261 | while (len) | |
262 | { | |
263 | size_t copy; | |
264 | ||
265 | /* No space left. */ | |
266 | if (obs->left_in_block == 0) | |
267 | append_block (obs); | |
268 | ||
269 | /* Determine how many bytes to copy in this loop. */ | |
270 | if (len <= obs->left_in_block) | |
271 | copy = len; | |
272 | else | |
273 | copy = obs->left_in_block; | |
274 | ||
275 | /* Copy the data and do bookkeeping. */ | |
276 | memcpy (obs->current_pointer, data, copy); | |
277 | obs->current_pointer += copy; | |
278 | obs->total_size += copy; | |
279 | obs->left_in_block -= copy; | |
280 | data = (const char *) data + copy; | |
281 | len -= copy; | |
282 | } | |
283 | } | |
284 | ||
285 | ||
286 | /* Output an unsigned LEB128 quantity to OBS. */ | |
287 | ||
288 | void | |
289 | lto_output_uleb128_stream (struct lto_output_stream *obs, | |
290 | unsigned HOST_WIDE_INT work) | |
291 | { | |
292 | do | |
293 | { | |
294 | unsigned int byte = (work & 0x7f); | |
295 | work >>= 7; | |
296 | if (work != 0) | |
297 | /* More bytes to follow. */ | |
298 | byte |= 0x80; | |
299 | ||
300 | lto_output_1_stream (obs, byte); | |
301 | } | |
302 | while (work != 0); | |
303 | } | |
304 | ||
b8698a0f | 305 | /* Identical to output_uleb128_stream above except using unsigned |
d7f09764 DN |
306 | HOST_WIDEST_INT type. For efficiency on host where unsigned HOST_WIDEST_INT |
307 | is not native, we only use this if we know that HOST_WIDE_INT is not wide | |
308 | enough. */ | |
309 | ||
310 | void | |
311 | lto_output_widest_uint_uleb128_stream (struct lto_output_stream *obs, | |
312 | unsigned HOST_WIDEST_INT work) | |
313 | { | |
314 | do | |
315 | { | |
316 | unsigned int byte = (work & 0x7f); | |
317 | work >>= 7; | |
318 | if (work != 0) | |
319 | /* More bytes to follow. */ | |
320 | byte |= 0x80; | |
321 | ||
322 | lto_output_1_stream (obs, byte); | |
323 | } | |
324 | while (work != 0); | |
325 | } | |
326 | ||
327 | ||
328 | /* Output a signed LEB128 quantity. */ | |
329 | ||
330 | void | |
331 | lto_output_sleb128_stream (struct lto_output_stream *obs, HOST_WIDE_INT work) | |
332 | { | |
333 | int more, byte; | |
334 | ||
335 | do | |
336 | { | |
337 | byte = (work & 0x7f); | |
338 | /* arithmetic shift */ | |
339 | work >>= 7; | |
340 | more = !((work == 0 && (byte & 0x40) == 0) | |
341 | || (work == -1 && (byte & 0x40) != 0)); | |
342 | if (more) | |
343 | byte |= 0x80; | |
344 | ||
345 | lto_output_1_stream (obs, byte); | |
346 | } | |
347 | while (more); | |
348 | } | |
349 | ||
350 | ||
351 | /* Lookup NAME in ENCODER. If NAME is not found, create a new entry in | |
352 | ENCODER for NAME with the next available index of ENCODER, then | |
353 | print the index to OBS. True is returned if NAME was added to | |
354 | ENCODER. The resulting index is stored in THIS_INDEX. | |
355 | ||
356 | If OBS is NULL, the only action is to add NAME to the encoder. */ | |
357 | ||
358 | bool | |
359 | lto_output_decl_index (struct lto_output_stream *obs, | |
360 | struct lto_tree_ref_encoder *encoder, | |
361 | tree name, unsigned int *this_index) | |
362 | { | |
363 | void **slot; | |
364 | struct lto_decl_slot d_slot; | |
365 | int index; | |
366 | bool new_entry_p = FALSE; | |
367 | ||
368 | d_slot.t = name; | |
369 | slot = htab_find_slot (encoder->tree_hash_table, &d_slot, INSERT); | |
370 | if (*slot == NULL) | |
371 | { | |
372 | struct lto_decl_slot *new_slot | |
373 | = (struct lto_decl_slot *) xmalloc (sizeof (struct lto_decl_slot)); | |
374 | index = encoder->next_index++; | |
375 | ||
376 | new_slot->t = name; | |
377 | new_slot->slot_num = index; | |
378 | *slot = new_slot; | |
379 | VEC_safe_push (tree, heap, encoder->trees, name); | |
380 | new_entry_p = TRUE; | |
381 | } | |
382 | else | |
383 | { | |
384 | struct lto_decl_slot *old_slot = (struct lto_decl_slot *)*slot; | |
385 | index = old_slot->slot_num; | |
386 | } | |
387 | ||
388 | if (obs) | |
389 | lto_output_uleb128_stream (obs, index); | |
390 | *this_index = index; | |
391 | return new_entry_p; | |
392 | } | |
393 | ||
394 | /* Output a field DECL to OBS. */ | |
395 | ||
396 | void | |
397 | lto_output_field_decl_index (struct lto_out_decl_state *decl_state, | |
398 | struct lto_output_stream * obs, tree decl) | |
399 | { | |
400 | unsigned int index; | |
401 | lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_FIELD_DECL], | |
402 | decl, &index); | |
403 | } | |
404 | ||
405 | /* Output a function DECL to OBS. */ | |
406 | ||
407 | void | |
b8698a0f | 408 | lto_output_fn_decl_index (struct lto_out_decl_state *decl_state, |
d7f09764 DN |
409 | struct lto_output_stream * obs, tree decl) |
410 | { | |
411 | unsigned int index; | |
412 | lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_FN_DECL], | |
413 | decl, &index); | |
414 | } | |
415 | ||
416 | /* Output a namespace DECL to OBS. */ | |
417 | ||
418 | void | |
419 | lto_output_namespace_decl_index (struct lto_out_decl_state *decl_state, | |
420 | struct lto_output_stream * obs, tree decl) | |
421 | { | |
422 | unsigned int index; | |
423 | lto_output_decl_index (obs, | |
424 | &decl_state->streams[LTO_DECL_STREAM_NAMESPACE_DECL], | |
425 | decl, &index); | |
426 | } | |
427 | ||
428 | /* Output a static or extern var DECL to OBS. */ | |
429 | ||
430 | void | |
431 | lto_output_var_decl_index (struct lto_out_decl_state *decl_state, | |
432 | struct lto_output_stream * obs, tree decl) | |
433 | { | |
434 | unsigned int index; | |
435 | lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_VAR_DECL], | |
436 | decl, &index); | |
437 | } | |
438 | ||
439 | /* Output a type DECL to OBS. */ | |
440 | ||
441 | void | |
442 | lto_output_type_decl_index (struct lto_out_decl_state *decl_state, | |
443 | struct lto_output_stream * obs, tree decl) | |
444 | { | |
445 | unsigned int index; | |
446 | lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_TYPE_DECL], | |
447 | decl, &index); | |
448 | } | |
449 | ||
450 | /* Output a type REF to OBS. */ | |
451 | ||
452 | void | |
453 | lto_output_type_ref_index (struct lto_out_decl_state *decl_state, | |
454 | struct lto_output_stream *obs, tree ref) | |
455 | { | |
456 | unsigned int index; | |
457 | lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_TYPE], | |
458 | ref, &index); | |
459 | } | |
460 | ||
461 | ||
462 | /* Create the output block and return it. */ | |
463 | ||
464 | struct lto_simple_output_block * | |
465 | lto_create_simple_output_block (enum lto_section_type section_type) | |
466 | { | |
467 | struct lto_simple_output_block *ob | |
468 | = ((struct lto_simple_output_block *) | |
469 | xcalloc (1, sizeof (struct lto_simple_output_block))); | |
470 | ||
471 | ob->section_type = section_type; | |
472 | ob->decl_state = lto_get_out_decl_state (); | |
473 | ob->main_stream = ((struct lto_output_stream *) | |
474 | xcalloc (1, sizeof (struct lto_output_stream))); | |
475 | ||
476 | return ob; | |
477 | } | |
478 | ||
479 | ||
480 | /* Produce a simple section for one of the ipa passes. */ | |
481 | ||
482 | void | |
483 | lto_destroy_simple_output_block (struct lto_simple_output_block *ob) | |
484 | { | |
485 | char *section_name; | |
486 | struct lto_simple_header header; | |
487 | struct lto_output_stream *header_stream; | |
488 | ||
489 | section_name = lto_get_section_name (ob->section_type, NULL); | |
490 | lto_begin_section (section_name, !flag_wpa); | |
491 | free (section_name); | |
492 | ||
493 | /* Write the header which says how to decode the pieces of the | |
494 | t. */ | |
495 | memset (&header, 0, sizeof (struct lto_simple_header)); | |
496 | header.lto_header.major_version = LTO_major_version; | |
497 | header.lto_header.minor_version = LTO_minor_version; | |
498 | header.lto_header.section_type = LTO_section_cgraph; | |
b8698a0f | 499 | |
d7f09764 | 500 | header.compressed_size = 0; |
b8698a0f | 501 | |
d7f09764 DN |
502 | header.main_size = ob->main_stream->total_size; |
503 | ||
504 | header_stream = XCNEW (struct lto_output_stream); | |
505 | lto_output_data_stream (header_stream, &header, sizeof header); | |
506 | lto_write_stream (header_stream); | |
507 | free (header_stream); | |
508 | ||
509 | lto_write_stream (ob->main_stream); | |
510 | ||
511 | /* Put back the assembly section that was there before we started | |
512 | writing lto info. */ | |
513 | lto_end_section (); | |
514 | ||
515 | free (ob->main_stream); | |
516 | free (ob); | |
517 | } | |
518 | ||
519 | ||
520 | /* Return a new lto_out_decl_state. */ | |
521 | ||
522 | struct lto_out_decl_state * | |
523 | lto_new_out_decl_state (void) | |
524 | { | |
525 | struct lto_out_decl_state *state = XCNEW (struct lto_out_decl_state); | |
526 | int i; | |
527 | htab_hash hash_fn; | |
528 | htab_eq eq_fn; | |
529 | ||
530 | for (i = 0; i < LTO_N_DECL_STREAMS; i++) | |
531 | { | |
532 | if (i == LTO_DECL_STREAM_TYPE) | |
533 | { | |
534 | hash_fn = lto_hash_type_slot_node; | |
535 | eq_fn = lto_eq_type_slot_node; | |
536 | } | |
537 | else | |
538 | { | |
539 | hash_fn = lto_hash_decl_slot_node; | |
540 | eq_fn = lto_eq_decl_slot_node; | |
541 | } | |
542 | lto_init_tree_ref_encoder (&state->streams[i], hash_fn, eq_fn); | |
543 | } | |
544 | ||
545 | state->cgraph_node_encoder = lto_cgraph_encoder_new (); | |
2f41ecf5 | 546 | state->varpool_node_encoder = lto_varpool_encoder_new (); |
d7f09764 DN |
547 | |
548 | return state; | |
549 | } | |
550 | ||
551 | ||
552 | /* Delete STATE and components. */ | |
553 | ||
554 | void | |
555 | lto_delete_out_decl_state (struct lto_out_decl_state *state) | |
556 | { | |
557 | int i; | |
558 | ||
559 | for (i = 0; i < LTO_N_DECL_STREAMS; i++) | |
560 | lto_destroy_tree_ref_encoder (&state->streams[i]); | |
561 | ||
562 | free (state); | |
563 | } | |
564 | ||
565 | ||
566 | /* Get the currently used lto_out_decl_state structure. */ | |
567 | ||
568 | struct lto_out_decl_state * | |
569 | lto_get_out_decl_state (void) | |
570 | { | |
571 | return VEC_last (lto_out_decl_state_ptr, decl_state_stack); | |
572 | } | |
573 | ||
574 | /* Push STATE to top of out decl stack. */ | |
575 | ||
576 | void | |
577 | lto_push_out_decl_state (struct lto_out_decl_state *state) | |
578 | { | |
579 | VEC_safe_push (lto_out_decl_state_ptr, heap, decl_state_stack, state); | |
580 | } | |
581 | ||
582 | /* Pop the currently used out-decl state from top of stack. */ | |
583 | ||
584 | struct lto_out_decl_state * | |
585 | lto_pop_out_decl_state (void) | |
586 | { | |
587 | return VEC_pop (lto_out_decl_state_ptr, decl_state_stack); | |
588 | } | |
589 | ||
590 | /* Record STATE after it has been used in serializing the body of | |
591 | FN_DECL. STATE should no longer be used by the caller. The ownership | |
592 | of it is taken over from this point. */ | |
593 | ||
594 | void | |
595 | lto_record_function_out_decl_state (tree fn_decl, | |
596 | struct lto_out_decl_state *state) | |
597 | { | |
598 | int i; | |
599 | ||
600 | /* Strip all hash tables to save some memory. */ | |
601 | for (i = 0; i < LTO_N_DECL_STREAMS; i++) | |
602 | if (state->streams[i].tree_hash_table) | |
603 | { | |
604 | htab_delete (state->streams[i].tree_hash_table); | |
605 | state->streams[i].tree_hash_table = NULL; | |
606 | } | |
607 | state->fn_decl = fn_decl; | |
608 | VEC_safe_push (lto_out_decl_state_ptr, heap, lto_function_decl_states, | |
609 | state); | |
610 | } |