1 /* Callgraph based analysis of static variables.
2 Copyright (C) 2015-2016 Free Software Foundation, Inc.
3 Contributed by Martin Liska <mliska@suse.cz>
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21 /* Interprocedural HSA pass is responsible for creation of HSA clones.
22 For all these HSA clones, we emit HSAIL instructions and pass processing
23 is terminated. */
24
25 #include "config.h"
26 #include "system.h"
27 #include "coretypes.h"
28 #include "tm.h"
29 #include "is-a.h"
30 #include "hash-set.h"
31 #include "vec.h"
32 #include "tree.h"
33 #include "tree-pass.h"
34 #include "function.h"
35 #include "basic-block.h"
36 #include "gimple.h"
37 #include "dumpfile.h"
38 #include "gimple-pretty-print.h"
39 #include "tree-streamer.h"
40 #include "stringpool.h"
41 #include "cgraph.h"
42 #include "print-tree.h"
43 #include "symbol-summary.h"
44 #include "hsa.h"
45
46 namespace {
47
48 /* If NODE is not versionable, warn about not emiting HSAIL and return false.
49 Otherwise return true. */
50
51 static bool
check_warn_node_versionable(cgraph_node * node)52 check_warn_node_versionable (cgraph_node *node)
53 {
54 if (!node->local.versionable)
55 {
56 warning_at (EXPR_LOCATION (node->decl), OPT_Whsa,
57 "could not emit HSAIL for function %s: function cannot be "
58 "cloned", node->name ());
59 return false;
60 }
61 return true;
62 }
63
64 /* The function creates HSA clones for all functions that were either
65 marked as HSA kernels or are callable HSA functions. Apart from that,
66 we redirect all edges that come from an HSA clone and end in another
67 HSA clone to connect these two functions. */
68
69 static unsigned int
process_hsa_functions(void)70 process_hsa_functions (void)
71 {
72 struct cgraph_node *node;
73
74 if (hsa_summaries == NULL)
75 hsa_summaries = new hsa_summary_t (symtab);
76
77 FOR_EACH_DEFINED_FUNCTION (node)
78 {
79 hsa_function_summary *s = hsa_summaries->get (node);
80
81 /* A linked function is skipped. */
82 if (s->m_binded_function != NULL)
83 continue;
84
85 if (s->m_kind != HSA_NONE)
86 {
87 if (!check_warn_node_versionable (node))
88 continue;
89 cgraph_node *clone
90 = node->create_virtual_clone (vec <cgraph_edge *> (),
91 NULL, NULL, "hsa");
92 TREE_PUBLIC (clone->decl) = TREE_PUBLIC (node->decl);
93
94 clone->force_output = true;
95 hsa_summaries->link_functions (clone, node, s->m_kind, false);
96
97 if (dump_file)
98 fprintf (dump_file, "Created a new HSA clone: %s, type: %s\n",
99 clone->name (),
100 s->m_kind == HSA_KERNEL ? "kernel" : "function");
101 }
102 else if (hsa_callable_function_p (node->decl))
103 {
104 if (!check_warn_node_versionable (node))
105 continue;
106 cgraph_node *clone
107 = node->create_virtual_clone (vec <cgraph_edge *> (),
108 NULL, NULL, "hsa");
109 TREE_PUBLIC (clone->decl) = TREE_PUBLIC (node->decl);
110
111 if (!cgraph_local_p (node))
112 clone->force_output = true;
113 hsa_summaries->link_functions (clone, node, HSA_FUNCTION, false);
114
115 if (dump_file)
116 fprintf (dump_file, "Created a new HSA function clone: %s\n",
117 clone->name ());
118 }
119 }
120
121 /* Redirect all edges that are between HSA clones. */
122 FOR_EACH_DEFINED_FUNCTION (node)
123 {
124 cgraph_edge *e = node->callees;
125
126 while (e)
127 {
128 hsa_function_summary *src = hsa_summaries->get (node);
129 if (src->m_kind != HSA_NONE && src->m_gpu_implementation_p)
130 {
131 hsa_function_summary *dst = hsa_summaries->get (e->callee);
132 if (dst->m_kind != HSA_NONE && !dst->m_gpu_implementation_p)
133 {
134 e->redirect_callee (dst->m_binded_function);
135 if (dump_file)
136 fprintf (dump_file,
137 "Redirecting edge to HSA function: %s->%s\n",
138 xstrdup_for_dump (e->caller->name ()),
139 xstrdup_for_dump (e->callee->name ()));
140 }
141 }
142
143 e = e->next_callee;
144 }
145 }
146
147 return 0;
148 }
149
150 /* Iterate all HSA functions and stream out HSA function summary. */
151
152 static void
ipa_hsa_write_summary(void)153 ipa_hsa_write_summary (void)
154 {
155 struct bitpack_d bp;
156 struct cgraph_node *node;
157 struct output_block *ob;
158 unsigned int count = 0;
159 lto_symtab_encoder_iterator lsei;
160 lto_symtab_encoder_t encoder;
161
162 if (!hsa_summaries)
163 return;
164
165 ob = create_output_block (LTO_section_ipa_hsa);
166 encoder = ob->decl_state->symtab_node_encoder;
167 ob->symbol = NULL;
168 for (lsei = lsei_start_function_in_partition (encoder); !lsei_end_p (lsei);
169 lsei_next_function_in_partition (&lsei))
170 {
171 node = lsei_cgraph_node (lsei);
172 hsa_function_summary *s = hsa_summaries->get (node);
173
174 if (s->m_kind != HSA_NONE)
175 count++;
176 }
177
178 streamer_write_uhwi (ob, count);
179
180 /* Process all of the functions. */
181 for (lsei = lsei_start_function_in_partition (encoder); !lsei_end_p (lsei);
182 lsei_next_function_in_partition (&lsei))
183 {
184 node = lsei_cgraph_node (lsei);
185 hsa_function_summary *s = hsa_summaries->get (node);
186
187 if (s->m_kind != HSA_NONE)
188 {
189 encoder = ob->decl_state->symtab_node_encoder;
190 int node_ref = lto_symtab_encoder_encode (encoder, node);
191 streamer_write_uhwi (ob, node_ref);
192
193 bp = bitpack_create (ob->main_stream);
194 bp_pack_value (&bp, s->m_kind, 2);
195 bp_pack_value (&bp, s->m_gpu_implementation_p, 1);
196 bp_pack_value (&bp, s->m_binded_function != NULL, 1);
197 streamer_write_bitpack (&bp);
198 if (s->m_binded_function)
199 stream_write_tree (ob, s->m_binded_function->decl, true);
200 }
201 }
202
203 streamer_write_char_stream (ob->main_stream, 0);
204 produce_asm (ob, NULL);
205 destroy_output_block (ob);
206 }
207
208 /* Read section in file FILE_DATA of length LEN with data DATA. */
209
210 static void
ipa_hsa_read_section(struct lto_file_decl_data * file_data,const char * data,size_t len)211 ipa_hsa_read_section (struct lto_file_decl_data *file_data, const char *data,
212 size_t len)
213 {
214 const struct lto_function_header *header
215 = (const struct lto_function_header *) data;
216 const int cfg_offset = sizeof (struct lto_function_header);
217 const int main_offset = cfg_offset + header->cfg_size;
218 const int string_offset = main_offset + header->main_size;
219 struct data_in *data_in;
220 unsigned int i;
221 unsigned int count;
222
223 lto_input_block ib_main ((const char *) data + main_offset,
224 header->main_size, file_data->mode_table);
225
226 data_in
227 = lto_data_in_create (file_data, (const char *) data + string_offset,
228 header->string_size, vNULL);
229 count = streamer_read_uhwi (&ib_main);
230
231 for (i = 0; i < count; i++)
232 {
233 unsigned int index;
234 struct cgraph_node *node;
235 lto_symtab_encoder_t encoder;
236
237 index = streamer_read_uhwi (&ib_main);
238 encoder = file_data->symtab_node_encoder;
239 node = dyn_cast<cgraph_node *> (lto_symtab_encoder_deref (encoder,
240 index));
241 gcc_assert (node->definition);
242 hsa_function_summary *s = hsa_summaries->get (node);
243
244 struct bitpack_d bp = streamer_read_bitpack (&ib_main);
245 s->m_kind = (hsa_function_kind) bp_unpack_value (&bp, 2);
246 s->m_gpu_implementation_p = bp_unpack_value (&bp, 1);
247 bool has_tree = bp_unpack_value (&bp, 1);
248
249 if (has_tree)
250 {
251 tree decl = stream_read_tree (&ib_main, data_in);
252 s->m_binded_function = cgraph_node::get_create (decl);
253 }
254 }
255 lto_free_section_data (file_data, LTO_section_ipa_hsa, NULL, data,
256 len);
257 lto_data_in_delete (data_in);
258 }
259
260 /* Load streamed HSA functions summary and assign the summary to a function. */
261
262 static void
ipa_hsa_read_summary(void)263 ipa_hsa_read_summary (void)
264 {
265 struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
266 struct lto_file_decl_data *file_data;
267 unsigned int j = 0;
268
269 if (hsa_summaries == NULL)
270 hsa_summaries = new hsa_summary_t (symtab);
271
272 while ((file_data = file_data_vec[j++]))
273 {
274 size_t len;
275 const char *data = lto_get_section_data (file_data, LTO_section_ipa_hsa,
276 NULL, &len);
277
278 if (data)
279 ipa_hsa_read_section (file_data, data, len);
280 }
281 }
282
283 const pass_data pass_data_ipa_hsa =
284 {
285 IPA_PASS, /* type */
286 "hsa", /* name */
287 OPTGROUP_NONE, /* optinfo_flags */
288 TV_IPA_HSA, /* tv_id */
289 0, /* properties_required */
290 0, /* properties_provided */
291 0, /* properties_destroyed */
292 0, /* todo_flags_start */
293 TODO_dump_symtab, /* todo_flags_finish */
294 };
295
296 class pass_ipa_hsa : public ipa_opt_pass_d
297 {
298 public:
pass_ipa_hsa(gcc::context * ctxt)299 pass_ipa_hsa (gcc::context *ctxt)
300 : ipa_opt_pass_d (pass_data_ipa_hsa, ctxt,
301 NULL, /* generate_summary */
302 ipa_hsa_write_summary, /* write_summary */
303 ipa_hsa_read_summary, /* read_summary */
304 ipa_hsa_write_summary, /* write_optimization_summary */
305 ipa_hsa_read_summary, /* read_optimization_summary */
306 NULL, /* stmt_fixup */
307 0, /* function_transform_todo_flags_start */
308 NULL, /* function_transform */
309 NULL) /* variable_transform */
310 {}
311
312 /* opt_pass methods: */
313 virtual bool gate (function *);
314
execute(function *)315 virtual unsigned int execute (function *) { return process_hsa_functions (); }
316
317 }; // class pass_ipa_reference
318
319 bool
gate(function *)320 pass_ipa_hsa::gate (function *)
321 {
322 return hsa_gen_requested_p ();
323 }
324
325 } // anon namespace
326
327 ipa_opt_pass_d *
make_pass_ipa_hsa(gcc::context * ctxt)328 make_pass_ipa_hsa (gcc::context *ctxt)
329 {
330 return new pass_ipa_hsa (ctxt);
331 }
332