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