Backport from GCC mainline.
[platform/upstream/linaro-gcc.git] / gcc / ipa-hsa.c
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
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
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
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
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
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:
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
315   virtual unsigned int execute (function *) { return process_hsa_functions (); }
316
317 }; // class pass_ipa_reference
318
319 bool
320 pass_ipa_hsa::gate (function *)
321 {
322   return hsa_gen_requested_p ();
323 }
324
325 } // anon namespace
326
327 ipa_opt_pass_d *
328 make_pass_ipa_hsa (gcc::context *ctxt)
329 {
330   return new pass_ipa_hsa (ctxt);
331 }