1 /* Miscellaneous utilities for GIMPLE streaming.  Things that are used
2    in both input and output are here.
3 
4    Copyright (C) 2009-2021 Free Software Foundation, Inc.
5    Contributed by Doug Kwan <dougkwan@google.com>
6 
7 This file is part of GCC.
8 
9 GCC is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation; either version 3, or (at your option) any later
12 version.
13 
14 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17 for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with GCC; see the file COPYING3.  If not see
21 <http://www.gnu.org/licenses/>.  */
22 
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "backend.h"
27 #include "tree.h"
28 #include "gimple.h"
29 #include "tree-streamer.h"
30 #include "cgraph.h"
31 #include "lto-streamer.h"
32 #include "toplev.h"
33 #include "lto-section-names.h"
34 
35 /* Statistics gathered during LTO, WPA and LTRANS.  */
36 struct lto_stats_d lto_stats;
37 
38 const char *section_name_prefix = LTO_SECTION_NAME_PREFIX;
39 /* Set when streaming LTO for offloading compiler.  */
40 bool lto_stream_offload_p;
41 
42 FILE *streamer_dump_file;
43 
44 /* Return a string representing LTO tag TAG.  */
45 
46 const char *
lto_tag_name(enum LTO_tags tag)47 lto_tag_name (enum LTO_tags tag)
48 {
49   if (lto_tag_is_tree_code_p (tag))
50     {
51       /* For tags representing tree nodes, return the name of the
52 	 associated tree code.  */
53       return get_tree_code_name (lto_tag_to_tree_code (tag));
54     }
55 
56   if (lto_tag_is_gimple_code_p (tag))
57     {
58       /* For tags representing gimple statements, return the name of
59 	 the associated gimple code.  */
60       return gimple_code_name[lto_tag_to_gimple_code (tag)];
61     }
62 
63   switch (tag)
64     {
65     case LTO_null:
66       return "LTO_null";
67     case LTO_bb0:
68       return "LTO_bb0";
69     case LTO_bb1:
70       return "LTO_bb1";
71     case LTO_eh_region:
72       return "LTO_eh_region";
73     case LTO_function:
74       return "LTO_function";
75     case LTO_eh_table:
76       return "LTO_eh_table";
77     case LTO_ert_cleanup:
78       return "LTO_ert_cleanup";
79     case LTO_ert_try:
80       return "LTO_ert_try";
81     case LTO_ert_allowed_exceptions:
82       return "LTO_ert_allowed_exceptions";
83     case LTO_ert_must_not_throw:
84       return "LTO_ert_must_not_throw";
85     case LTO_tree_pickle_reference:
86       return "LTO_tree_pickle_reference";
87     case LTO_global_stream_ref:
88       return "LTO_global_sream_ref";
89     case LTO_ssa_name_ref:
90       return "LTO_ssa_name_ref";
91     default:
92       return "LTO_UNKNOWN";
93     }
94 }
95 
96 
97 /* Get a section name for a particular type or name.  The NAME field
98    is only used if SECTION_TYPE is LTO_section_function_body. For all
99    others it is ignored.  The callee of this function is responsible
100    to free the returned name.  */
101 
102 char *
lto_get_section_name(int section_type,const char * name,int node_order,struct lto_file_decl_data * f)103 lto_get_section_name (int section_type, const char *name,
104 		      int node_order, struct lto_file_decl_data *f)
105 {
106   const char *add;
107   char post[32];
108   const char *sep;
109   char *buffer = NULL;
110 
111   if (section_type == LTO_section_function_body)
112     {
113       gcc_assert (name != NULL);
114       if (name[0] == '*')
115 	name++;
116 
117       buffer = (char *)xmalloc (strlen (name) + 32);
118       sprintf (buffer, "%s.%d", name, node_order);
119 
120       add = buffer;
121       sep = "";
122     }
123   else if (section_type < LTO_N_SECTION_TYPES)
124     {
125       add = lto_section_name[section_type];
126       sep = ".";
127     }
128   else
129     internal_error ("bytecode stream: unexpected LTO section %s", name);
130 
131   /* Make the section name unique so that ld -r combining sections
132      doesn't confuse the reader with merged sections.
133 
134      For options don't add a ID, the option reader cannot deal with them
135      and merging should be ok here. */
136   if (section_type == LTO_section_opts)
137     strcpy (post, "");
138   else if (f != NULL)
139     sprintf (post, "." HOST_WIDE_INT_PRINT_HEX_PURE, f->id);
140   else
141     sprintf (post, "." HOST_WIDE_INT_PRINT_HEX_PURE, get_random_seed (false));
142   char *res = concat (section_name_prefix, sep, add, post, NULL);
143   if (buffer)
144     free (buffer);
145   return res;
146 }
147 
148 
149 /* Show various memory usage statistics related to LTO.  */
150 
151 void
print_lto_report(const char * s)152 print_lto_report (const char *s)
153 {
154   unsigned i;
155 
156   fprintf (stderr, "[%s] # of input files: "
157 	   HOST_WIDE_INT_PRINT_UNSIGNED "\n", s, lto_stats.num_input_files);
158 
159   fprintf (stderr, "[%s] # of input cgraph nodes: "
160 	   HOST_WIDE_INT_PRINT_UNSIGNED "\n", s,
161 	   lto_stats.num_input_cgraph_nodes);
162 
163   fprintf (stderr, "[%s] # of function bodies: "
164 	   HOST_WIDE_INT_PRINT_UNSIGNED "\n", s,
165 	   lto_stats.num_function_bodies);
166 
167   for (i = 0; i < NUM_TREE_CODES; i++)
168     if (lto_stats.num_trees[i])
169       fprintf (stderr, "[%s] # of '%s' objects read: "
170 	       HOST_WIDE_INT_PRINT_UNSIGNED "\n", s,
171 	       get_tree_code_name ((enum tree_code) i), lto_stats.num_trees[i]);
172 
173   if (flag_lto)
174     {
175       fprintf (stderr, "[%s] Compression: "
176 	       HOST_WIDE_INT_PRINT_UNSIGNED " output bytes, "
177 	       HOST_WIDE_INT_PRINT_UNSIGNED " compressed bytes", s,
178 	       lto_stats.num_output_il_bytes,
179 	       lto_stats.num_compressed_il_bytes);
180       if (lto_stats.num_output_il_bytes > 0)
181 	{
182 	  const float dividend = (float) lto_stats.num_compressed_il_bytes;
183 	  const float divisor = (float) lto_stats.num_output_il_bytes;
184 	  fprintf (stderr, " (ratio: %f)", dividend / divisor);
185 	}
186       fprintf (stderr, "\n");
187     }
188 
189   if (flag_wpa)
190     {
191       fprintf (stderr, "[%s] # of output files: "
192 	       HOST_WIDE_INT_PRINT_UNSIGNED "\n", s,
193 	       lto_stats.num_output_files);
194 
195       fprintf (stderr, "[%s] # of output symtab nodes: "
196 	       HOST_WIDE_INT_PRINT_UNSIGNED "\n", s,
197 	       lto_stats.num_output_symtab_nodes);
198 
199       fprintf (stderr, "[%s] # of output tree pickle references: "
200 	       HOST_WIDE_INT_PRINT_UNSIGNED "\n", s,
201 	       lto_stats.num_pickle_refs_output);
202       fprintf (stderr, "[%s] # of output tree bodies: "
203 	       HOST_WIDE_INT_PRINT_UNSIGNED "\n", s,
204 	       lto_stats.num_tree_bodies_output);
205 
206       fprintf (stderr, "[%s] # callgraph partitions: "
207 	       HOST_WIDE_INT_PRINT_UNSIGNED "\n", s,
208 	       lto_stats.num_cgraph_partitions);
209 
210       fprintf (stderr, "[%s] Compression: "
211 	       HOST_WIDE_INT_PRINT_UNSIGNED " input bytes, "
212 	       HOST_WIDE_INT_PRINT_UNSIGNED " uncompressed bytes", s,
213 	       lto_stats.num_input_il_bytes,
214 	       lto_stats.num_uncompressed_il_bytes);
215       if (lto_stats.num_input_il_bytes > 0)
216 	{
217 	  const float dividend = (float) lto_stats.num_uncompressed_il_bytes;
218 	  const float divisor = (float) lto_stats.num_input_il_bytes;
219 	  fprintf (stderr, " (ratio: %f)", dividend / divisor);
220 	}
221       fprintf (stderr, "\n");
222     }
223 
224   for (i = 0; i < LTO_N_SECTION_TYPES; i++)
225     fprintf (stderr, "[%s] Size of mmap'd section %s: "
226 	     HOST_WIDE_INT_PRINT_UNSIGNED " bytes\n", s,
227 	     lto_section_name[i], lto_stats.section_size[i]);
228 }
229 
230 /* Initialization common to the LTO reader and writer.  */
231 
232 void
lto_streamer_init(void)233 lto_streamer_init (void)
234 {
235   /* Check that all the TS_* handled by the reader and writer routines
236      match exactly the structures defined in treestruct.def.  When a
237      new TS_* astructure is added, the streamer should be updated to
238      handle it.  */
239   if (flag_checking)
240     streamer_check_handled_ts_structures ();
241 }
242 
243 
244 /* Gate function for all LTO streaming passes.  */
245 
246 bool
gate_lto_out(void)247 gate_lto_out (void)
248 {
249   return ((flag_generate_lto || flag_generate_offload || in_lto_p)
250 	  /* Don't bother doing anything if the program has errors.  */
251 	  && !seen_error ());
252 }
253 
254 /* Check that the version MAJOR.MINOR is the correct version number.  */
255 
256 void
lto_check_version(int major,int minor,const char * file_name)257 lto_check_version (int major, int minor, const char *file_name)
258 {
259   if (major != LTO_major_version || minor != LTO_minor_version)
260     fatal_error (input_location,
261 		 "bytecode stream in file %qs generated with LTO version "
262 		 "%d.%d instead of the expected %d.%d",
263 		 file_name,
264 		 major, minor,
265 		 LTO_major_version, LTO_minor_version);
266 }
267 
268 
269 /* Initialize all the streamer hooks used for streaming GIMPLE.  */
270 
271 void
lto_streamer_hooks_init(void)272 lto_streamer_hooks_init (void)
273 {
274   streamer_hooks_init ();
275   streamer_hooks.write_tree = lto_output_tree;
276   streamer_hooks.read_tree = lto_input_tree;
277   streamer_hooks.input_location = lto_input_location;
278   streamer_hooks.output_location = lto_output_location;
279   streamer_hooks.output_location_and_block = lto_output_location_and_block;
280 }
281