1 | /* Functions for LTO dump tool. |
2 | Copyright (C) 2018-2023 Free Software Foundation, Inc. |
3 | |
4 | This file is part of GCC. |
5 | |
6 | GCC is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free |
8 | Software Foundation; either version 3, or (at your option) any later |
9 | version. |
10 | |
11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
14 | for more details. |
15 | |
16 | You should have received a copy of the GNU General Public License |
17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ |
19 | |
20 | #include "config.h" |
21 | #include "system.h" |
22 | #include "coretypes.h" |
23 | #include "tm.h" |
24 | #include "function.h" |
25 | #include "basic-block.h" |
26 | #include "tree.h" |
27 | #include "gimple.h" |
28 | #include "cfg.h" |
29 | #include "tree-cfg.h" |
30 | #include "tree-pass.h" |
31 | #include "tree-streamer.h" |
32 | #include "cgraph.h" |
33 | #include "opts.h" |
34 | #include "debug.h" |
35 | #include "lto-partition.h" |
36 | #include "tree-pretty-print.h" |
37 | #include "lto-common.h" |
38 | |
39 | /* Stores details of symbols for dumping symbol list. */ |
40 | |
41 | class symbol_entry |
42 | { |
43 | public: |
44 | symtab_node *node; |
45 | symbol_entry (symtab_node *node_): node (node_) |
46 | {} |
47 | |
48 | virtual ~symbol_entry () |
49 | {} |
50 | |
51 | char* get_name () const |
52 | { |
53 | if (flag_lto_dump_demangle) |
54 | return xstrdup (node->name ()); |
55 | else |
56 | return xstrdup (node->asm_name ()); |
57 | } |
58 | |
59 | virtual size_t get_size () const = 0; |
60 | |
61 | virtual void dump () |
62 | { |
63 | const char *name = get_name (); |
64 | const char *type_name = node->get_symtab_type_string (); |
65 | const char *visibility = node->get_visibility_string (); |
66 | size_t sz = get_size (); |
67 | printf (format: "%s %s %4" PRIu64 " %s " , type_name, visibility, (uint64_t) sz, |
68 | name); |
69 | } |
70 | }; |
71 | |
72 | /* Stores variable specific details of symbols for dumping symbol list. */ |
73 | |
74 | class variable_entry: public symbol_entry |
75 | { |
76 | public: |
77 | variable_entry (varpool_node *node_): symbol_entry (node_) |
78 | {} |
79 | |
80 | virtual ~variable_entry () |
81 | {} |
82 | |
83 | size_t get_size () const final override |
84 | { |
85 | varpool_node *vnode = dyn_cast<varpool_node *> (p: node); |
86 | if (DECL_SIZE (vnode->decl) && tree_fits_shwi_p (DECL_SIZE (vnode->decl))) |
87 | return tree_to_shwi (DECL_SIZE (vnode->decl)); |
88 | return 0; |
89 | } |
90 | |
91 | void dump () final override |
92 | { |
93 | symbol_entry :: dump (); |
94 | varpool_node *vnode = dyn_cast<varpool_node *> (p: node); |
95 | vnode->get_constructor (); |
96 | tree value_tree = DECL_INITIAL (vnode->decl); |
97 | if (flag_lto_print_value && value_tree) |
98 | print_generic_expr (stdout, value_tree, TDF_NONE); |
99 | printf (format: "\n" ); |
100 | } |
101 | }; |
102 | |
103 | /* Stores function specific details of symbols for dumping symbol list. */ |
104 | |
105 | class function_entry: public symbol_entry |
106 | { |
107 | public: |
108 | function_entry (cgraph_node *node_): symbol_entry (node_) |
109 | {} |
110 | |
111 | virtual ~function_entry () |
112 | {} |
113 | |
114 | void dump () final override |
115 | { |
116 | symbol_entry :: dump (); |
117 | printf (format: "\n" ); |
118 | } |
119 | |
120 | size_t get_size () const final override |
121 | { |
122 | cgraph_node *cnode = dyn_cast<cgraph_node *> (p: node); |
123 | gcc_assert (cnode); |
124 | |
125 | return (cnode->definition && !cnode->thunk && !cnode->alias) |
126 | ? n_basic_blocks_for_fn (DECL_STRUCT_FUNCTION (cnode->decl)) |
127 | : 0; |
128 | } |
129 | }; |
130 | |
131 | /* Comparing symbols based on size. */ |
132 | |
133 | int size_compare (const void *a, const void *b) |
134 | { |
135 | const symbol_entry *e1 = *(const symbol_entry * const*) a; |
136 | const symbol_entry *e2 = *(const symbol_entry * const*) b; |
137 | |
138 | return e1->get_size () - e2->get_size (); |
139 | } |
140 | |
141 | /* Comparing symbols based on name. */ |
142 | |
143 | int name_compare (const void *a, const void *b) |
144 | { |
145 | const symbol_entry *e1 = *(const symbol_entry * const*) a; |
146 | const symbol_entry *e2 = *(const symbol_entry * const*) b; |
147 | |
148 | return strcmp (s1: e1->get_name (), s2: e2->get_name ()); |
149 | } |
150 | |
151 | /* Dump list of functions and their details. */ |
152 | |
153 | void dump_list_functions (void) |
154 | { |
155 | auto_vec<symbol_entry *> v; |
156 | |
157 | cgraph_node *cnode; |
158 | FOR_EACH_FUNCTION (cnode) |
159 | { |
160 | if (cnode->definition && !cnode->alias) |
161 | cnode->get_untransformed_body (); |
162 | symbol_entry *e = new function_entry (cnode); |
163 | if (!flag_lto_dump_defined || (cnode->definition && !cnode->alias)) |
164 | v.safe_push (obj: e); |
165 | } |
166 | |
167 | if (flag_lto_size_sort) |
168 | v.qsort (size_compare); |
169 | else if (flag_lto_name_sort) |
170 | v.qsort (name_compare); |
171 | if (flag_lto_reverse_sort) |
172 | v.reverse (); |
173 | |
174 | printf (format: "Type Visibility Size Name" ); |
175 | if (flag_lto_print_value) |
176 | printf (format: " Value" ); |
177 | printf (format: "\n" ); |
178 | int i=0; |
179 | symbol_entry* e; |
180 | FOR_EACH_VEC_ELT (v, i, e) |
181 | { |
182 | e->dump (); |
183 | delete e; |
184 | } |
185 | } |
186 | |
187 | /* Dump list of variables and their details. */ |
188 | |
189 | void dump_list_variables (void) |
190 | { |
191 | auto_vec<symbol_entry *> v; |
192 | |
193 | varpool_node *vnode; |
194 | FOR_EACH_VARIABLE (vnode) |
195 | { |
196 | symbol_entry *e = new variable_entry (vnode); |
197 | if (!flag_lto_dump_defined || vnode->definition) |
198 | v.safe_push (obj: e); |
199 | } |
200 | |
201 | if (flag_lto_size_sort) |
202 | v.qsort (size_compare); |
203 | else if (flag_lto_name_sort) |
204 | v.qsort (name_compare); |
205 | if (flag_lto_reverse_sort) |
206 | v.reverse (); |
207 | |
208 | printf (format: "\n" ); |
209 | int i=0; |
210 | symbol_entry* e; |
211 | FOR_EACH_VEC_ELT (v, i, e) |
212 | { |
213 | e->dump (); |
214 | delete e; |
215 | } |
216 | } |
217 | |
218 | /* Dump symbol table in graphviz format. */ |
219 | void dump_symtab_graphviz (void) |
220 | { |
221 | symtab->dump_graphviz (stdout); |
222 | } |
223 | |
224 | /* Dump symbol list. */ |
225 | |
226 | void dump_list (void) |
227 | { |
228 | dump_list_functions (); |
229 | dump_list_variables (); |
230 | } |
231 | |
232 | /* Dump specific variables and functions used in IL. */ |
233 | void dump_symbol () |
234 | { |
235 | symtab_node *node; |
236 | printf (format: "Symbol: %s\n" , flag_lto_dump_symbol); |
237 | FOR_EACH_SYMBOL (node) |
238 | { |
239 | if (!strcmp (flag_lto_dump_symbol, s2: node->name ())) |
240 | { |
241 | node->debug (); |
242 | printf (format: "\n" ); |
243 | } |
244 | } |
245 | } |
246 | |
247 | /* Dump specific gimple body of specified function. */ |
248 | void dump_body () |
249 | { |
250 | int flag = 0; |
251 | dump_flags_t flags = TDF_NONE; |
252 | if (flag_dump_level) |
253 | flags = parse_dump_option (flag_dump_level, NULL); |
254 | if (flags == TDF_ERROR) |
255 | { |
256 | error_at (input_location, "Level not found, use none, slim, blocks, vops." ); |
257 | return; |
258 | } |
259 | cgraph_node *cnode; |
260 | FOR_EACH_DEFINED_FUNCTION (cnode) |
261 | if (!cnode->alias |
262 | && !strcmp (s1: cnode->asm_name (), flag_dump_body)) |
263 | { |
264 | printf (format: "GIMPLE body of function: %s\n\n" , cnode->asm_name ()); |
265 | cnode->get_untransformed_body (); |
266 | debug_function (cnode->decl, flags); |
267 | flag = 1; |
268 | } |
269 | if (!flag) |
270 | error_at (input_location, "Function not found." ); |
271 | } |
272 | |
273 | /* List of command line options for dumping. */ |
274 | void dump_tool_help () |
275 | { |
276 | const char *msg = |
277 | "Usage: lto-dump [OPTION]... SUB_COMMAND [OPTION]...\n\n" |
278 | "LTO dump tool command line options.\n\n" |
279 | " -list [options] Dump the symbol list.\n" |
280 | " -demangle Dump the demangled output.\n" |
281 | " -defined-only Dump only the defined symbols.\n" |
282 | " -print-value Dump initial values of the variables.\n" |
283 | " -name-sort Sort the symbols alphabetically.\n" |
284 | " -size-sort Sort the symbols according to size.\n" |
285 | " -reverse-sort Dump the symbols in reverse order.\n" |
286 | " -symbol= Dump the details of specific symbol.\n" |
287 | " -objects Dump the details of LTO objects.\n" |
288 | " -callgraph Dump the callgraph in graphviz format.\n" |
289 | " -type-stats Dump statistics of tree types.\n" |
290 | " -tree-stats Dump statistics of trees.\n" |
291 | " -gimple-stats Dump statistics of GIMPLE statements.\n" |
292 | " -dump-body= Dump the specific GIMPLE body.\n" |
293 | " -dump-level= Deciding the optimization level of body.\n" |
294 | " -help Display the dump tool help.\n" ; |
295 | |
296 | fputs (s: msg, stdout); |
297 | } |
298 | |
299 | unsigned int |
300 | lto_option_lang_mask (void) |
301 | { |
302 | return CL_LTODump; |
303 | } |
304 | |
305 | /* Functions for dumping various details in LTO dump tool are called |
306 | in lto_main(). The purpose of this dump tool is to analyze the LTO |
307 | object files. */ |
308 | |
309 | void |
310 | lto_main (void) |
311 | { |
312 | quiet_flag = true; |
313 | if (flag_lto_dump_tool_help) |
314 | { |
315 | dump_tool_help (); |
316 | exit (SUCCESS_EXIT_CODE); |
317 | } |
318 | |
319 | /* LTO is called as a front end, even though it is not a front end. |
320 | Because it is called as a front end, TV_PHASE_PARSING and |
321 | TV_PARSE_GLOBAL are active, and we need to turn them off while |
322 | doing LTO. Later we turn them back on so they are active up in |
323 | toplev.cc. */ |
324 | |
325 | /* Initialize the LTO front end. */ |
326 | lto_fe_init (); |
327 | g_timer = NULL; |
328 | /* Read all the symbols and call graph from all the files in the |
329 | command line. */ |
330 | read_cgraph_and_symbols (num_in_fnames, in_fnames); |
331 | |
332 | /* Dump symbol list. */ |
333 | if (flag_lto_dump_list) |
334 | dump_list (); |
335 | else if (flag_lto_dump_symbol) |
336 | { |
337 | /* Dump specific variables and functions used in IL. */ |
338 | dump_symbol (); |
339 | } |
340 | else if (flag_lto_gimple_stats) |
341 | { |
342 | /* Dump gimple statement statistics. */ |
343 | cgraph_node *node; |
344 | FOR_EACH_DEFINED_FUNCTION (node) |
345 | if (!node->alias) |
346 | node->get_untransformed_body (); |
347 | if (!GATHER_STATISTICS) |
348 | warning_at (input_location, 0, |
349 | "Not configured with " |
350 | "%<--enable-gather-detailed-mem-stats%>." ); |
351 | else |
352 | dump_gimple_statistics (); |
353 | } |
354 | else if (flag_lto_tree_stats) |
355 | { |
356 | /* Dump tree statistics. */ |
357 | if (!GATHER_STATISTICS) |
358 | warning_at (input_location, 0, |
359 | "Not configured with " |
360 | "%<--enable-gather-detailed-mem-stats%>." ); |
361 | else |
362 | { |
363 | printf (format: "Tree statistics\n" ); |
364 | dump_tree_statistics (); |
365 | } |
366 | } |
367 | else if (flag_dump_body) |
368 | { |
369 | /* Dump specific gimple body of specified function. */ |
370 | dump_body (); |
371 | } |
372 | else if (flag_dump_callgraph) |
373 | dump_symtab_graphviz (); |
374 | else |
375 | dump_tool_help (); |
376 | |
377 | /* Exit right now. */ |
378 | exit (SUCCESS_EXIT_CODE); |
379 | } |
380 | |