]>
Commit | Line | Data |
---|---|---|
d7f09764 DN |
1 | /* Functions for writing LTO sections. |
2 | ||
d1e082c2 | 3 | Copyright (C) 2009-2013 Free Software Foundation, Inc. |
d7f09764 DN |
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" | |
d7f09764 DN |
26 | #include "tree.h" |
27 | #include "expr.h" | |
28 | #include "params.h" | |
29 | #include "input.h" | |
d7f09764 DN |
30 | #include "hashtab.h" |
31 | #include "basic-block.h" | |
d7f09764 DN |
32 | #include "function.h" |
33 | #include "ggc.h" | |
34 | #include "except.h" | |
35 | #include "vec.h" | |
36 | #include "pointer-set.h" | |
d7f09764 | 37 | #include "langhooks.h" |
412288f1 | 38 | #include "data-streamer.h" |
d7f09764 DN |
39 | #include "lto-streamer.h" |
40 | #include "lto-compress.h" | |
41 | ||
9771b263 | 42 | static vec<lto_out_decl_state_ptr> decl_state_stack; |
d7f09764 DN |
43 | |
44 | /* List of out decl states used by functions. We use this to | |
45 | generate the decl directory later. */ | |
46 | ||
9771b263 | 47 | vec<lto_out_decl_state_ptr> lto_function_decl_states; |
d7f09764 | 48 | |
d7f09764 DN |
49 | |
50 | /***************************************************************************** | |
51 | Output routines shared by all of the serialization passes. | |
52 | *****************************************************************************/ | |
53 | ||
54 | ||
55 | /* Flush compressed stream data function, sends NUM_CHARS from CHARS | |
56 | to the append lang hook, OPAQUE is currently always NULL. */ | |
57 | ||
58 | static void | |
59 | lto_append_data (const char *chars, unsigned int num_chars, void *opaque) | |
60 | { | |
61 | gcc_assert (opaque == NULL); | |
62 | lang_hooks.lto.append_data (chars, num_chars, opaque); | |
63 | } | |
64 | ||
65 | /* Pointer to the current compression stream. */ | |
66 | ||
67 | static struct lto_compression_stream *compression_stream = NULL; | |
68 | ||
69 | /* Begin a new output section named NAME. If COMPRESS is true, zlib compress | |
70 | the section. */ | |
71 | ||
72 | void | |
73 | lto_begin_section (const char *name, bool compress) | |
74 | { | |
75 | lang_hooks.lto.begin_section (name); | |
76 | ||
77 | /* FIXME lto: for now, suppress compression if the lang_hook that appends | |
78 | data is anything other than assembler output. The effect here is that | |
79 | we get compression of IL only in non-ltrans object files. */ | |
80 | gcc_assert (compression_stream == NULL); | |
81 | if (compress) | |
82 | compression_stream = lto_start_compression (lto_append_data, NULL); | |
83 | } | |
84 | ||
85 | ||
86 | /* End the current output section. */ | |
87 | ||
88 | void | |
89 | lto_end_section (void) | |
90 | { | |
91 | if (compression_stream) | |
92 | { | |
93 | lto_end_compression (compression_stream); | |
94 | compression_stream = NULL; | |
95 | } | |
96 | lang_hooks.lto.end_section (); | |
97 | } | |
98 | ||
99 | ||
100 | /* Write all of the chars in OBS to the assembler. Recycle the blocks | |
101 | in obs as this is being done. */ | |
102 | ||
103 | void | |
104 | lto_write_stream (struct lto_output_stream *obs) | |
105 | { | |
106 | unsigned int block_size = 1024; | |
107 | struct lto_char_ptr_base *block; | |
108 | struct lto_char_ptr_base *next_block; | |
109 | if (!obs->first_block) | |
110 | return; | |
111 | ||
112 | for (block = obs->first_block; block; block = next_block) | |
113 | { | |
114 | const char *base = ((char *)block) + sizeof (struct lto_char_ptr_base); | |
115 | unsigned int num_chars = block_size - sizeof (struct lto_char_ptr_base); | |
116 | ||
117 | /* If this is not the last block, it is full. If it is the last | |
118 | block, left_in_block indicates how many chars are unoccupied in | |
119 | this block; subtract from num_chars to obtain occupancy. */ | |
120 | next_block = (struct lto_char_ptr_base *) block->ptr; | |
121 | if (!next_block) | |
122 | num_chars -= obs->left_in_block; | |
123 | ||
124 | /* FIXME lto: WPA mode uses an ELF function as a lang_hook to append | |
125 | output data. This hook is not happy with the way that compression | |
126 | blocks up output differently to the way it's blocked here. So for | |
127 | now, we don't compress WPA output. */ | |
128 | if (compression_stream) | |
129 | { | |
130 | lto_compress_block (compression_stream, base, num_chars); | |
131 | lang_hooks.lto.append_data (NULL, 0, block); | |
132 | } | |
133 | else | |
134 | lang_hooks.lto.append_data (base, num_chars, block); | |
135 | block_size *= 2; | |
136 | } | |
137 | } | |
138 | ||
139 | ||
140 | /* Adds a new block to output stream OBS. */ | |
141 | ||
bc0fe8cb JH |
142 | void |
143 | lto_append_block (struct lto_output_stream *obs) | |
d7f09764 DN |
144 | { |
145 | struct lto_char_ptr_base *new_block; | |
146 | ||
147 | gcc_assert (obs->left_in_block == 0); | |
148 | ||
149 | if (obs->first_block == NULL) | |
150 | { | |
151 | /* This is the first time the stream has been written | |
152 | into. */ | |
153 | obs->block_size = 1024; | |
154 | new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size); | |
155 | obs->first_block = new_block; | |
156 | } | |
157 | else | |
158 | { | |
159 | struct lto_char_ptr_base *tptr; | |
160 | /* Get a new block that is twice as big as the last block | |
161 | and link it into the list. */ | |
162 | obs->block_size *= 2; | |
163 | new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size); | |
164 | /* The first bytes of the block are reserved as a pointer to | |
165 | the next block. Set the chain of the full block to the | |
166 | pointer to the new block. */ | |
167 | tptr = obs->current_block; | |
168 | tptr->ptr = (char *) new_block; | |
169 | } | |
170 | ||
171 | /* Set the place for the next char at the first position after the | |
172 | chain to the next block. */ | |
173 | obs->current_pointer | |
174 | = ((char *) new_block) + sizeof (struct lto_char_ptr_base); | |
175 | obs->current_block = new_block; | |
176 | /* Null out the newly allocated block's pointer to the next block. */ | |
177 | new_block->ptr = NULL; | |
178 | obs->left_in_block = obs->block_size - sizeof (struct lto_char_ptr_base); | |
179 | } | |
180 | ||
181 | ||
d7f09764 DN |
182 | /* Write raw DATA of length LEN to the output block OB. */ |
183 | ||
184 | void | |
185 | lto_output_data_stream (struct lto_output_stream *obs, const void *data, | |
186 | size_t len) | |
187 | { | |
188 | while (len) | |
189 | { | |
190 | size_t copy; | |
191 | ||
192 | /* No space left. */ | |
193 | if (obs->left_in_block == 0) | |
bc0fe8cb | 194 | lto_append_block (obs); |
d7f09764 DN |
195 | |
196 | /* Determine how many bytes to copy in this loop. */ | |
197 | if (len <= obs->left_in_block) | |
198 | copy = len; | |
199 | else | |
200 | copy = obs->left_in_block; | |
201 | ||
202 | /* Copy the data and do bookkeeping. */ | |
203 | memcpy (obs->current_pointer, data, copy); | |
204 | obs->current_pointer += copy; | |
205 | obs->total_size += copy; | |
206 | obs->left_in_block -= copy; | |
207 | data = (const char *) data + copy; | |
208 | len -= copy; | |
209 | } | |
210 | } | |
211 | ||
212 | ||
d7f09764 DN |
213 | /* Lookup NAME in ENCODER. If NAME is not found, create a new entry in |
214 | ENCODER for NAME with the next available index of ENCODER, then | |
215 | print the index to OBS. True is returned if NAME was added to | |
216 | ENCODER. The resulting index is stored in THIS_INDEX. | |
217 | ||
218 | If OBS is NULL, the only action is to add NAME to the encoder. */ | |
219 | ||
220 | bool | |
221 | lto_output_decl_index (struct lto_output_stream *obs, | |
222 | struct lto_tree_ref_encoder *encoder, | |
223 | tree name, unsigned int *this_index) | |
224 | { | |
7c5848b8 RB |
225 | unsigned *slot; |
226 | unsigned int index; | |
d7f09764 | 227 | bool new_entry_p = FALSE; |
7c5848b8 | 228 | bool existed_p; |
d7f09764 | 229 | |
7c5848b8 RB |
230 | slot = encoder->tree_hash_table->insert (name, &existed_p); |
231 | if (!existed_p) | |
d7f09764 | 232 | { |
d579fcda | 233 | index = encoder->trees.length (); |
7c5848b8 | 234 | *slot = index; |
9771b263 | 235 | encoder->trees.safe_push (name); |
d7f09764 DN |
236 | new_entry_p = TRUE; |
237 | } | |
238 | else | |
7c5848b8 | 239 | index = *slot; |
d7f09764 DN |
240 | |
241 | if (obs) | |
412288f1 | 242 | streamer_write_uhwi_stream (obs, index); |
d7f09764 DN |
243 | *this_index = index; |
244 | return new_entry_p; | |
245 | } | |
246 | ||
247 | /* Output a field DECL to OBS. */ | |
248 | ||
249 | void | |
250 | lto_output_field_decl_index (struct lto_out_decl_state *decl_state, | |
251 | struct lto_output_stream * obs, tree decl) | |
252 | { | |
253 | unsigned int index; | |
254 | lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_FIELD_DECL], | |
255 | decl, &index); | |
256 | } | |
257 | ||
258 | /* Output a function DECL to OBS. */ | |
259 | ||
260 | void | |
b8698a0f | 261 | lto_output_fn_decl_index (struct lto_out_decl_state *decl_state, |
d7f09764 DN |
262 | struct lto_output_stream * obs, tree decl) |
263 | { | |
264 | unsigned int index; | |
265 | lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_FN_DECL], | |
266 | decl, &index); | |
267 | } | |
268 | ||
269 | /* Output a namespace DECL to OBS. */ | |
270 | ||
271 | void | |
272 | lto_output_namespace_decl_index (struct lto_out_decl_state *decl_state, | |
273 | struct lto_output_stream * obs, tree decl) | |
274 | { | |
275 | unsigned int index; | |
276 | lto_output_decl_index (obs, | |
277 | &decl_state->streams[LTO_DECL_STREAM_NAMESPACE_DECL], | |
278 | decl, &index); | |
279 | } | |
280 | ||
281 | /* Output a static or extern var DECL to OBS. */ | |
282 | ||
283 | void | |
284 | lto_output_var_decl_index (struct lto_out_decl_state *decl_state, | |
285 | struct lto_output_stream * obs, tree decl) | |
286 | { | |
287 | unsigned int index; | |
288 | lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_VAR_DECL], | |
289 | decl, &index); | |
290 | } | |
291 | ||
292 | /* Output a type DECL to OBS. */ | |
293 | ||
294 | void | |
295 | lto_output_type_decl_index (struct lto_out_decl_state *decl_state, | |
296 | struct lto_output_stream * obs, tree decl) | |
297 | { | |
298 | unsigned int index; | |
299 | lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_TYPE_DECL], | |
300 | decl, &index); | |
301 | } | |
302 | ||
303 | /* Output a type REF to OBS. */ | |
304 | ||
305 | void | |
306 | lto_output_type_ref_index (struct lto_out_decl_state *decl_state, | |
307 | struct lto_output_stream *obs, tree ref) | |
308 | { | |
309 | unsigned int index; | |
310 | lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_TYPE], | |
311 | ref, &index); | |
312 | } | |
313 | ||
314 | ||
315 | /* Create the output block and return it. */ | |
316 | ||
317 | struct lto_simple_output_block * | |
318 | lto_create_simple_output_block (enum lto_section_type section_type) | |
319 | { | |
320 | struct lto_simple_output_block *ob | |
321 | = ((struct lto_simple_output_block *) | |
322 | xcalloc (1, sizeof (struct lto_simple_output_block))); | |
323 | ||
324 | ob->section_type = section_type; | |
325 | ob->decl_state = lto_get_out_decl_state (); | |
326 | ob->main_stream = ((struct lto_output_stream *) | |
327 | xcalloc (1, sizeof (struct lto_output_stream))); | |
328 | ||
329 | return ob; | |
330 | } | |
331 | ||
332 | ||
333 | /* Produce a simple section for one of the ipa passes. */ | |
334 | ||
335 | void | |
336 | lto_destroy_simple_output_block (struct lto_simple_output_block *ob) | |
337 | { | |
338 | char *section_name; | |
339 | struct lto_simple_header header; | |
340 | struct lto_output_stream *header_stream; | |
341 | ||
73ce4d1e | 342 | section_name = lto_get_section_name (ob->section_type, NULL, NULL); |
d7f09764 DN |
343 | lto_begin_section (section_name, !flag_wpa); |
344 | free (section_name); | |
345 | ||
346 | /* Write the header which says how to decode the pieces of the | |
347 | t. */ | |
348 | memset (&header, 0, sizeof (struct lto_simple_header)); | |
349 | header.lto_header.major_version = LTO_major_version; | |
350 | header.lto_header.minor_version = LTO_minor_version; | |
b8698a0f | 351 | |
d7f09764 | 352 | header.compressed_size = 0; |
b8698a0f | 353 | |
d7f09764 DN |
354 | header.main_size = ob->main_stream->total_size; |
355 | ||
356 | header_stream = XCNEW (struct lto_output_stream); | |
357 | lto_output_data_stream (header_stream, &header, sizeof header); | |
358 | lto_write_stream (header_stream); | |
359 | free (header_stream); | |
360 | ||
361 | lto_write_stream (ob->main_stream); | |
362 | ||
363 | /* Put back the assembly section that was there before we started | |
364 | writing lto info. */ | |
365 | lto_end_section (); | |
366 | ||
367 | free (ob->main_stream); | |
368 | free (ob); | |
369 | } | |
370 | ||
371 | ||
372 | /* Return a new lto_out_decl_state. */ | |
373 | ||
374 | struct lto_out_decl_state * | |
375 | lto_new_out_decl_state (void) | |
376 | { | |
377 | struct lto_out_decl_state *state = XCNEW (struct lto_out_decl_state); | |
378 | int i; | |
d7f09764 DN |
379 | |
380 | for (i = 0; i < LTO_N_DECL_STREAMS; i++) | |
d579fcda | 381 | lto_init_tree_ref_encoder (&state->streams[i]); |
d7f09764 | 382 | |
d7f09764 DN |
383 | return state; |
384 | } | |
385 | ||
386 | ||
387 | /* Delete STATE and components. */ | |
388 | ||
389 | void | |
390 | lto_delete_out_decl_state (struct lto_out_decl_state *state) | |
391 | { | |
392 | int i; | |
393 | ||
394 | for (i = 0; i < LTO_N_DECL_STREAMS; i++) | |
395 | lto_destroy_tree_ref_encoder (&state->streams[i]); | |
396 | ||
397 | free (state); | |
398 | } | |
399 | ||
400 | ||
401 | /* Get the currently used lto_out_decl_state structure. */ | |
402 | ||
403 | struct lto_out_decl_state * | |
404 | lto_get_out_decl_state (void) | |
405 | { | |
9771b263 | 406 | return decl_state_stack.last (); |
d7f09764 DN |
407 | } |
408 | ||
409 | /* Push STATE to top of out decl stack. */ | |
410 | ||
411 | void | |
412 | lto_push_out_decl_state (struct lto_out_decl_state *state) | |
413 | { | |
9771b263 | 414 | decl_state_stack.safe_push (state); |
d7f09764 DN |
415 | } |
416 | ||
417 | /* Pop the currently used out-decl state from top of stack. */ | |
418 | ||
419 | struct lto_out_decl_state * | |
420 | lto_pop_out_decl_state (void) | |
421 | { | |
9771b263 | 422 | return decl_state_stack.pop (); |
d7f09764 DN |
423 | } |
424 | ||
425 | /* Record STATE after it has been used in serializing the body of | |
426 | FN_DECL. STATE should no longer be used by the caller. The ownership | |
427 | of it is taken over from this point. */ | |
428 | ||
429 | void | |
430 | lto_record_function_out_decl_state (tree fn_decl, | |
431 | struct lto_out_decl_state *state) | |
432 | { | |
433 | int i; | |
434 | ||
435 | /* Strip all hash tables to save some memory. */ | |
436 | for (i = 0; i < LTO_N_DECL_STREAMS; i++) | |
437 | if (state->streams[i].tree_hash_table) | |
438 | { | |
7c5848b8 | 439 | delete state->streams[i].tree_hash_table; |
d7f09764 DN |
440 | state->streams[i].tree_hash_table = NULL; |
441 | } | |
442 | state->fn_decl = fn_decl; | |
9771b263 | 443 | lto_function_decl_states.safe_push (state); |
d7f09764 | 444 | } |