]>
Commit | Line | Data |
---|---|---|
1 | /* Functions for writing LTO sections. | |
2 | ||
3 | Copyright (C) 2009-2021 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 "backend.h" | |
26 | #include "rtl.h" | |
27 | #include "tree.h" | |
28 | #include "gimple.h" | |
29 | #include "cgraph.h" | |
30 | #include "data-streamer.h" | |
31 | #include "langhooks.h" | |
32 | #include "lto-compress.h" | |
33 | #include "print-tree.h" | |
34 | ||
35 | static vec<lto_out_decl_state_ptr> decl_state_stack; | |
36 | ||
37 | /* List of out decl states used by functions. We use this to | |
38 | generate the decl directory later. */ | |
39 | ||
40 | vec<lto_out_decl_state_ptr> lto_function_decl_states; | |
41 | ||
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 | ||
70 | if (streamer_dump_file) | |
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 | } | |
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 | ||
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 | } | |
108 | ||
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 | ||
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 | ||
141 | if (compression_stream) | |
142 | lto_compress_block (compression_stream, base, num_chars); | |
143 | else | |
144 | lang_hooks.lto.append_data (base, num_chars, block); | |
145 | free (block); | |
146 | block_size *= 2; | |
147 | } | |
148 | } | |
149 | ||
150 | /* Create the output block and return it. */ | |
151 | ||
152 | struct lto_simple_output_block * | |
153 | lto_create_simple_output_block (enum lto_section_type section_type) | |
154 | { | |
155 | struct lto_simple_output_block *ob | |
156 | = ((struct lto_simple_output_block *) | |
157 | xcalloc (1, sizeof (struct lto_simple_output_block))); | |
158 | ||
159 | ob->section_type = section_type; | |
160 | ob->decl_state = lto_get_out_decl_state (); | |
161 | ob->main_stream = ((struct lto_output_stream *) | |
162 | xcalloc (1, sizeof (struct lto_output_stream))); | |
163 | ||
164 | return ob; | |
165 | } | |
166 | ||
167 | ||
168 | /* Produce a simple section for one of the ipa passes. */ | |
169 | ||
170 | void | |
171 | lto_destroy_simple_output_block (struct lto_simple_output_block *ob) | |
172 | { | |
173 | char *section_name; | |
174 | struct lto_simple_header header; | |
175 | ||
176 | section_name = lto_get_section_name (ob->section_type, NULL, 0, NULL); | |
177 | lto_begin_section (section_name, !flag_wpa); | |
178 | free (section_name); | |
179 | ||
180 | /* Write the header which says how to decode the pieces of the | |
181 | t. */ | |
182 | memset (&header, 0, sizeof (struct lto_simple_header)); | |
183 | header.main_size = ob->main_stream->total_size; | |
184 | lto_write_data (&header, sizeof header); | |
185 | ||
186 | lto_write_stream (ob->main_stream); | |
187 | ||
188 | /* Put back the assembly section that was there before we started | |
189 | writing lto info. */ | |
190 | lto_end_section (); | |
191 | ||
192 | free (ob->main_stream); | |
193 | free (ob); | |
194 | } | |
195 | ||
196 | ||
197 | /* Return a new lto_out_decl_state. */ | |
198 | ||
199 | struct lto_out_decl_state * | |
200 | lto_new_out_decl_state (void) | |
201 | { | |
202 | struct lto_out_decl_state *state = XCNEW (struct lto_out_decl_state); | |
203 | int i; | |
204 | ||
205 | for (i = 0; i < LTO_N_DECL_STREAMS; i++) | |
206 | lto_init_tree_ref_encoder (&state->streams[i]); | |
207 | ||
208 | /* At WPA time we do not compress sections by default. */ | |
209 | state->compressed = !flag_wpa; | |
210 | ||
211 | return state; | |
212 | } | |
213 | ||
214 | ||
215 | /* Delete STATE and components. */ | |
216 | ||
217 | void | |
218 | lto_delete_out_decl_state (struct lto_out_decl_state *state) | |
219 | { | |
220 | int i; | |
221 | ||
222 | for (i = 0; i < LTO_N_DECL_STREAMS; i++) | |
223 | lto_destroy_tree_ref_encoder (&state->streams[i]); | |
224 | ||
225 | free (state); | |
226 | } | |
227 | ||
228 | ||
229 | /* Get the currently used lto_out_decl_state structure. */ | |
230 | ||
231 | struct lto_out_decl_state * | |
232 | lto_get_out_decl_state (void) | |
233 | { | |
234 | return decl_state_stack.last (); | |
235 | } | |
236 | ||
237 | /* Push STATE to top of out decl stack. */ | |
238 | ||
239 | void | |
240 | lto_push_out_decl_state (struct lto_out_decl_state *state) | |
241 | { | |
242 | decl_state_stack.safe_push (state); | |
243 | } | |
244 | ||
245 | /* Pop the currently used out-decl state from top of stack. */ | |
246 | ||
247 | struct lto_out_decl_state * | |
248 | lto_pop_out_decl_state (void) | |
249 | { | |
250 | return decl_state_stack.pop (); | |
251 | } | |
252 | ||
253 | /* Record STATE after it has been used in serializing the body of | |
254 | FN_DECL. STATE should no longer be used by the caller. The ownership | |
255 | of it is taken over from this point. */ | |
256 | ||
257 | void | |
258 | lto_record_function_out_decl_state (tree fn_decl, | |
259 | struct lto_out_decl_state *state) | |
260 | { | |
261 | int i; | |
262 | ||
263 | /* Strip all hash tables to save some memory. */ | |
264 | for (i = 0; i < LTO_N_DECL_STREAMS; i++) | |
265 | if (state->streams[i].tree_hash_table) | |
266 | { | |
267 | delete state->streams[i].tree_hash_table; | |
268 | state->streams[i].tree_hash_table = NULL; | |
269 | } | |
270 | state->fn_decl = fn_decl; | |
271 | lto_function_decl_states.safe_push (state); | |
272 | } |