]>
Commit | Line | Data |
---|---|---|
d7f09764 DN |
1 | /* Functions for writing LTO sections. |
2 | ||
a5544970 | 3 | Copyright (C) 2009-2019 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" | |
c7131fb2 | 25 | #include "backend.h" |
957060b5 | 26 | #include "rtl.h" |
40e23961 | 27 | #include "tree.h" |
8e9055ae | 28 | #include "gimple.h" |
957060b5 AM |
29 | #include "cgraph.h" |
30 | #include "data-streamer.h" | |
d7f09764 | 31 | #include "langhooks.h" |
d7f09764 | 32 | #include "lto-compress.h" |
b4da704c | 33 | #include "print-tree.h" |
d7f09764 | 34 | |
9771b263 | 35 | static vec<lto_out_decl_state_ptr> decl_state_stack; |
d7f09764 DN |
36 | |
37 | /* List of out decl states used by functions. We use this to | |
38 | generate the decl directory later. */ | |
39 | ||
9771b263 | 40 | vec<lto_out_decl_state_ptr> lto_function_decl_states; |
d7f09764 | 41 | |
d7f09764 DN |
42 | |
43 | /***************************************************************************** | |
44 | Output routines shared by all of the serialization passes. | |
45 | *****************************************************************************/ | |
46 | ||
47 | ||
48 | /* Flush compressed stream data function, sends NUM_CHARS from CHARS | |
49 | to the append lang hook, OPAQUE is currently always NULL. */ | |
50 | ||
51 | static void | |
52 | lto_append_data (const char *chars, unsigned int num_chars, void *opaque) | |
53 | { | |
54 | gcc_assert (opaque == NULL); | |
55 | lang_hooks.lto.append_data (chars, num_chars, opaque); | |
56 | } | |
57 | ||
58 | /* Pointer to the current compression stream. */ | |
59 | ||
60 | static struct lto_compression_stream *compression_stream = NULL; | |
61 | ||
62 | /* Begin a new output section named NAME. If COMPRESS is true, zlib compress | |
63 | the section. */ | |
64 | ||
65 | void | |
66 | lto_begin_section (const char *name, bool compress) | |
67 | { | |
68 | lang_hooks.lto.begin_section (name); | |
69 | ||
b4da704c | 70 | if (streamer_dump_file) |
aa7c78ca JH |
71 | { |
72 | if (flag_dump_unnumbered || flag_dump_noaddr) | |
73 | fprintf (streamer_dump_file, "Creating %ssection\n", | |
74 | compress ? "compressed " : ""); | |
75 | else | |
76 | fprintf (streamer_dump_file, "Creating %ssection %s\n", | |
77 | compress ? "compressed " : "", name); | |
78 | } | |
d7f09764 DN |
79 | gcc_assert (compression_stream == NULL); |
80 | if (compress) | |
81 | compression_stream = lto_start_compression (lto_append_data, NULL); | |
82 | } | |
83 | ||
84 | ||
85 | /* End the current output section. */ | |
86 | ||
87 | void | |
88 | lto_end_section (void) | |
89 | { | |
90 | if (compression_stream) | |
91 | { | |
92 | lto_end_compression (compression_stream); | |
93 | compression_stream = NULL; | |
94 | } | |
95 | lang_hooks.lto.end_section (); | |
96 | } | |
97 | ||
f6bcdb5e RB |
98 | /* Write SIZE bytes starting at DATA to the assembler. */ |
99 | ||
100 | void | |
101 | lto_write_data (const void *data, unsigned int size) | |
102 | { | |
103 | if (compression_stream) | |
104 | lto_compress_block (compression_stream, (const char *)data, size); | |
105 | else | |
106 | lang_hooks.lto.append_data ((const char *)data, size, NULL); | |
107 | } | |
d7f09764 | 108 | |
7fa658c2 JH |
109 | /* Write SIZE bytes starting at DATA to the assembler. */ |
110 | ||
111 | void | |
112 | lto_write_raw_data (const void *data, unsigned int size) | |
113 | { | |
114 | lang_hooks.lto.append_data ((const char *)data, size, NULL); | |
115 | } | |
116 | ||
d7f09764 DN |
117 | /* Write all of the chars in OBS to the assembler. Recycle the blocks |
118 | in obs as this is being done. */ | |
119 | ||
120 | void | |
121 | lto_write_stream (struct lto_output_stream *obs) | |
122 | { | |
123 | unsigned int block_size = 1024; | |
124 | struct lto_char_ptr_base *block; | |
125 | struct lto_char_ptr_base *next_block; | |
126 | if (!obs->first_block) | |
127 | return; | |
128 | ||
129 | for (block = obs->first_block; block; block = next_block) | |
130 | { | |
131 | const char *base = ((char *)block) + sizeof (struct lto_char_ptr_base); | |
132 | unsigned int num_chars = block_size - sizeof (struct lto_char_ptr_base); | |
133 | ||
134 | /* If this is not the last block, it is full. If it is the last | |
135 | block, left_in_block indicates how many chars are unoccupied in | |
136 | this block; subtract from num_chars to obtain occupancy. */ | |
137 | next_block = (struct lto_char_ptr_base *) block->ptr; | |
138 | if (!next_block) | |
139 | num_chars -= obs->left_in_block; | |
140 | ||
d7f09764 | 141 | if (compression_stream) |
f6bcdb5e | 142 | lto_compress_block (compression_stream, base, num_chars); |
d7f09764 DN |
143 | else |
144 | lang_hooks.lto.append_data (base, num_chars, block); | |
f6bcdb5e | 145 | free (block); |
d7f09764 DN |
146 | block_size *= 2; |
147 | } | |
148 | } | |
149 | ||
150 | ||
d7f09764 DN |
151 | /* Lookup NAME in ENCODER. If NAME is not found, create a new entry in |
152 | ENCODER for NAME with the next available index of ENCODER, then | |
153 | print the index to OBS. True is returned if NAME was added to | |
154 | ENCODER. The resulting index is stored in THIS_INDEX. | |
155 | ||
156 | If OBS is NULL, the only action is to add NAME to the encoder. */ | |
157 | ||
158 | bool | |
159 | lto_output_decl_index (struct lto_output_stream *obs, | |
160 | struct lto_tree_ref_encoder *encoder, | |
161 | tree name, unsigned int *this_index) | |
162 | { | |
d7f09764 | 163 | bool new_entry_p = FALSE; |
7c5848b8 | 164 | bool existed_p; |
d7f09764 | 165 | |
1eb68d2d TS |
166 | unsigned int &index |
167 | = encoder->tree_hash_table->get_or_insert (name, &existed_p); | |
7c5848b8 | 168 | if (!existed_p) |
d7f09764 | 169 | { |
d579fcda | 170 | index = encoder->trees.length (); |
b4da704c JH |
171 | if (streamer_dump_file) |
172 | { | |
173 | print_node_brief (streamer_dump_file, " Encoding indexable ", | |
174 | name, 4); | |
175 | fprintf (streamer_dump_file, " as %i \n", index); | |
176 | } | |
9771b263 | 177 | encoder->trees.safe_push (name); |
d7f09764 DN |
178 | new_entry_p = TRUE; |
179 | } | |
d7f09764 DN |
180 | |
181 | if (obs) | |
412288f1 | 182 | streamer_write_uhwi_stream (obs, index); |
d7f09764 DN |
183 | *this_index = index; |
184 | return new_entry_p; | |
185 | } | |
186 | ||
187 | /* Output a field DECL to OBS. */ | |
188 | ||
189 | void | |
190 | lto_output_field_decl_index (struct lto_out_decl_state *decl_state, | |
191 | struct lto_output_stream * obs, tree decl) | |
192 | { | |
193 | unsigned int index; | |
194 | lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_FIELD_DECL], | |
195 | decl, &index); | |
196 | } | |
197 | ||
198 | /* Output a function DECL to OBS. */ | |
199 | ||
200 | void | |
b8698a0f | 201 | lto_output_fn_decl_index (struct lto_out_decl_state *decl_state, |
d7f09764 DN |
202 | struct lto_output_stream * obs, tree decl) |
203 | { | |
204 | unsigned int index; | |
205 | lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_FN_DECL], | |
206 | decl, &index); | |
207 | } | |
208 | ||
209 | /* Output a namespace DECL to OBS. */ | |
210 | ||
211 | void | |
212 | lto_output_namespace_decl_index (struct lto_out_decl_state *decl_state, | |
213 | struct lto_output_stream * obs, tree decl) | |
214 | { | |
215 | unsigned int index; | |
216 | lto_output_decl_index (obs, | |
217 | &decl_state->streams[LTO_DECL_STREAM_NAMESPACE_DECL], | |
218 | decl, &index); | |
219 | } | |
220 | ||
221 | /* Output a static or extern var DECL to OBS. */ | |
222 | ||
223 | void | |
224 | lto_output_var_decl_index (struct lto_out_decl_state *decl_state, | |
225 | struct lto_output_stream * obs, tree decl) | |
226 | { | |
227 | unsigned int index; | |
228 | lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_VAR_DECL], | |
229 | decl, &index); | |
230 | } | |
231 | ||
232 | /* Output a type DECL to OBS. */ | |
233 | ||
234 | void | |
235 | lto_output_type_decl_index (struct lto_out_decl_state *decl_state, | |
236 | struct lto_output_stream * obs, tree decl) | |
237 | { | |
238 | unsigned int index; | |
239 | lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_TYPE_DECL], | |
240 | decl, &index); | |
241 | } | |
242 | ||
243 | /* Output a type REF to OBS. */ | |
244 | ||
245 | void | |
246 | lto_output_type_ref_index (struct lto_out_decl_state *decl_state, | |
247 | struct lto_output_stream *obs, tree ref) | |
248 | { | |
249 | unsigned int index; | |
250 | lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_TYPE], | |
251 | ref, &index); | |
252 | } | |
253 | ||
254 | ||
255 | /* Create the output block and return it. */ | |
256 | ||
257 | struct lto_simple_output_block * | |
258 | lto_create_simple_output_block (enum lto_section_type section_type) | |
259 | { | |
260 | struct lto_simple_output_block *ob | |
261 | = ((struct lto_simple_output_block *) | |
262 | xcalloc (1, sizeof (struct lto_simple_output_block))); | |
263 | ||
264 | ob->section_type = section_type; | |
265 | ob->decl_state = lto_get_out_decl_state (); | |
266 | ob->main_stream = ((struct lto_output_stream *) | |
267 | xcalloc (1, sizeof (struct lto_output_stream))); | |
268 | ||
269 | return ob; | |
270 | } | |
271 | ||
272 | ||
273 | /* Produce a simple section for one of the ipa passes. */ | |
274 | ||
275 | void | |
276 | lto_destroy_simple_output_block (struct lto_simple_output_block *ob) | |
277 | { | |
278 | char *section_name; | |
279 | struct lto_simple_header header; | |
d7f09764 | 280 | |
73ce4d1e | 281 | section_name = lto_get_section_name (ob->section_type, NULL, NULL); |
d7f09764 DN |
282 | lto_begin_section (section_name, !flag_wpa); |
283 | free (section_name); | |
284 | ||
285 | /* Write the header which says how to decode the pieces of the | |
286 | t. */ | |
287 | memset (&header, 0, sizeof (struct lto_simple_header)); | |
207c68cd RB |
288 | header.major_version = LTO_major_version; |
289 | header.minor_version = LTO_minor_version; | |
d7f09764 | 290 | header.main_size = ob->main_stream->total_size; |
f6bcdb5e | 291 | lto_write_data (&header, sizeof header); |
d7f09764 DN |
292 | |
293 | lto_write_stream (ob->main_stream); | |
294 | ||
295 | /* Put back the assembly section that was there before we started | |
296 | writing lto info. */ | |
297 | lto_end_section (); | |
298 | ||
299 | free (ob->main_stream); | |
300 | free (ob); | |
301 | } | |
302 | ||
303 | ||
304 | /* Return a new lto_out_decl_state. */ | |
305 | ||
306 | struct lto_out_decl_state * | |
307 | lto_new_out_decl_state (void) | |
308 | { | |
309 | struct lto_out_decl_state *state = XCNEW (struct lto_out_decl_state); | |
310 | int i; | |
d7f09764 DN |
311 | |
312 | for (i = 0; i < LTO_N_DECL_STREAMS; i++) | |
d579fcda | 313 | lto_init_tree_ref_encoder (&state->streams[i]); |
d7f09764 | 314 | |
7fa658c2 JH |
315 | /* At WPA time we do not compress sections by default. */ |
316 | state->compressed = !flag_wpa; | |
317 | ||
d7f09764 DN |
318 | return state; |
319 | } | |
320 | ||
321 | ||
322 | /* Delete STATE and components. */ | |
323 | ||
324 | void | |
325 | lto_delete_out_decl_state (struct lto_out_decl_state *state) | |
326 | { | |
327 | int i; | |
328 | ||
329 | for (i = 0; i < LTO_N_DECL_STREAMS; i++) | |
330 | lto_destroy_tree_ref_encoder (&state->streams[i]); | |
331 | ||
332 | free (state); | |
333 | } | |
334 | ||
335 | ||
336 | /* Get the currently used lto_out_decl_state structure. */ | |
337 | ||
338 | struct lto_out_decl_state * | |
339 | lto_get_out_decl_state (void) | |
340 | { | |
9771b263 | 341 | return decl_state_stack.last (); |
d7f09764 DN |
342 | } |
343 | ||
344 | /* Push STATE to top of out decl stack. */ | |
345 | ||
346 | void | |
347 | lto_push_out_decl_state (struct lto_out_decl_state *state) | |
348 | { | |
9771b263 | 349 | decl_state_stack.safe_push (state); |
d7f09764 DN |
350 | } |
351 | ||
352 | /* Pop the currently used out-decl state from top of stack. */ | |
353 | ||
354 | struct lto_out_decl_state * | |
355 | lto_pop_out_decl_state (void) | |
356 | { | |
9771b263 | 357 | return decl_state_stack.pop (); |
d7f09764 DN |
358 | } |
359 | ||
360 | /* Record STATE after it has been used in serializing the body of | |
361 | FN_DECL. STATE should no longer be used by the caller. The ownership | |
362 | of it is taken over from this point. */ | |
363 | ||
364 | void | |
365 | lto_record_function_out_decl_state (tree fn_decl, | |
366 | struct lto_out_decl_state *state) | |
367 | { | |
368 | int i; | |
369 | ||
370 | /* Strip all hash tables to save some memory. */ | |
371 | for (i = 0; i < LTO_N_DECL_STREAMS; i++) | |
372 | if (state->streams[i].tree_hash_table) | |
373 | { | |
7c5848b8 | 374 | delete state->streams[i].tree_hash_table; |
d7f09764 DN |
375 | state->streams[i].tree_hash_table = NULL; |
376 | } | |
377 | state->fn_decl = fn_decl; | |
9771b263 | 378 | lto_function_decl_states.safe_push (state); |
d7f09764 | 379 | } |