comparison gcc/brig/brigfrontend/brig-to-generic.cc @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 84e7813d76e9
comparison
equal deleted inserted replaced
68:561a7518be6b 111:04ced10e8804
1 /* brig2tree.cc -- brig to gcc generic/gimple tree conversion
2 Copyright (C) 2016-2017 Free Software Foundation, Inc.
3 Contributed by Pekka Jaaskelainen <pekka.jaaskelainen@parmance.com>
4 for General Processor Tech.
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3, or (at your option) any later
11 version.
12
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
21
22 #include <cassert>
23 #include <iostream>
24 #include <iomanip>
25 #include <sstream>
26
27 #include "config.h"
28 #include "system.h"
29 #include "coretypes.h"
30 #include "target.h"
31 #include "function.h"
32 #include "brig-to-generic.h"
33 #include "stringpool.h"
34 #include "tree-iterator.h"
35 #include "toplev.h"
36 #include "gimplify.h"
37 #include "gimple-expr.h"
38 #include "print-tree.h"
39 #include "hsa-brig-format.h"
40 #include "stor-layout.h"
41 #include "diagnostic-core.h"
42 #include "brig-code-entry-handler.h"
43 #include "brig-machine.h"
44 #include "brig-util.h"
45 #include "phsa.h"
46 #include "tree-pretty-print.h"
47 #include "dumpfile.h"
48 #include "profile-count.h"
49 #include "tree-cfg.h"
50 #include "errors.h"
51 #include "fold-const.h"
52 #include "cgraph.h"
53 #include "dumpfile.h"
54 #include "tree-pretty-print.h"
55
56 extern int gccbrig_verbose;
57
58 tree brig_to_generic::s_fp16_type;
59 tree brig_to_generic::s_fp32_type;
60 tree brig_to_generic::s_fp64_type;
61
62 brig_to_generic::brig_to_generic ()
63 : m_cf (NULL), m_analyzing (true), m_total_group_segment_usage (0),
64 m_brig (NULL), m_next_private_offset (0)
65 {
66 m_globals = NULL_TREE;
67
68 /* Initialize the basic REAL types.
69 This doesn't work straight away because most of the targets
70 do not support fp16 natively. Let's by default convert
71 to fp32 and back before and after each instruction (handle it as
72 a storage format only), and later add an optimization pass
73 that removes the extra converts (in case of multiple fp16 ops
74 in a row). */
75 s_fp16_type = make_node (REAL_TYPE);
76 TYPE_PRECISION (s_fp16_type) = 16;
77 TYPE_SIZE (s_fp16_type) = bitsize_int (16);
78 TYPE_SIZE_UNIT (s_fp16_type) = size_int (2);
79 SET_TYPE_ALIGN (s_fp16_type, 16);
80 layout_type (s_fp16_type);
81
82 s_fp32_type = gccbrig_tree_type_for_hsa_type (BRIG_TYPE_F32);
83 s_fp64_type = gccbrig_tree_type_for_hsa_type (BRIG_TYPE_F64);
84
85 /* TODO: (machine)query the preferred rounding mode that is set by
86 the machine by default. This can be redefined by each BRIG module
87 header. */
88 m_default_float_rounding_mode = BRIG_ROUND_FLOAT_ZERO;
89
90 m_dump_file = dump_begin (TDI_original, &m_dump_flags);
91 }
92
93 class unimplemented_entry_handler : public brig_code_entry_handler
94 {
95 public:
96 unimplemented_entry_handler (brig_to_generic &parent)
97 : brig_code_entry_handler (parent)
98 {
99 }
100
101 size_t
102 operator () (const BrigBase *base)
103 {
104 gcc_unreachable ();
105 return base->byteCount;
106 }
107 };
108
109 /* Handler for entries that can be (and are) safely skipped for the purposes
110 of GENERIC generation. */
111
112 class skipped_entry_handler : public brig_code_entry_handler
113 {
114 public:
115 skipped_entry_handler (brig_to_generic &parent)
116 : brig_code_entry_handler (parent)
117 {
118 }
119
120 size_t
121 operator () (const BrigBase *base)
122 {
123 return base->byteCount;
124 }
125 };
126
127 /* Helper struct for pairing a BrigKind and a BrigCodeEntryHandler that
128 should handle its data. */
129
130 struct code_entry_handler_info
131 {
132 BrigKind kind;
133 brig_code_entry_handler *handler;
134 };
135
136
137 /* Finds the BRIG file sections in the currently processed file. */
138
139 void
140 brig_to_generic::find_brig_sections ()
141 {
142 m_data = m_code = m_operand = NULL;
143 const BrigModuleHeader *mheader = (const BrigModuleHeader *) m_brig;
144
145 /* Find the positions of the different sections. */
146 for (uint32_t sec = 0; sec < mheader->sectionCount; ++sec)
147 {
148 uint64_t offset
149 = ((const uint64_t *) (m_brig + mheader->sectionIndex))[sec];
150
151 const BrigSectionHeader *section_header
152 = (const BrigSectionHeader *) (m_brig + offset);
153
154 std::string name ((const char *) (&section_header->name),
155 section_header->nameLength);
156
157 if (sec == BRIG_SECTION_INDEX_DATA && name == "hsa_data")
158 {
159 m_data = (const char *) section_header;
160 m_data_size = section_header->byteCount;
161 }
162 else if (sec == BRIG_SECTION_INDEX_CODE && name == "hsa_code")
163 {
164 m_code = (const char *) section_header;
165 m_code_size = section_header->byteCount;
166 }
167 else if (sec == BRIG_SECTION_INDEX_OPERAND && name == "hsa_operand")
168 {
169 m_operand = (const char *) section_header;
170 m_operand_size = section_header->byteCount;
171 }
172 else
173 {
174 gcc_unreachable ();
175 }
176 }
177
178 if (m_code == NULL)
179 gcc_unreachable ();
180 if (m_data == NULL)
181 gcc_unreachable ();
182 if (m_operand == NULL)
183 gcc_unreachable ();
184
185 }
186
187 /* Does a first pass over the given BRIG to collect data needed for the
188 actual parsing. Currently this includes only collecting the
189 group segment variable usage to support the experimental HSA PRM feature
190 where group variables can be declared also in module and function scope
191 (in addition to kernel scope).
192 */
193
194 void
195 brig_to_generic::analyze (const char *brig_blob)
196 {
197 const BrigModuleHeader *mheader = (const BrigModuleHeader *) brig_blob;
198
199 if (strncmp (mheader->identification, "HSA BRIG", 8) != 0)
200 fatal_error (UNKNOWN_LOCATION, PHSA_ERROR_PREFIX_INCOMPATIBLE_MODULE
201 "Unrecognized file format.");
202 if (mheader->brigMajor != 1 || mheader->brigMinor != 0)
203 fatal_error (UNKNOWN_LOCATION, PHSA_ERROR_PREFIX_INCOMPATIBLE_MODULE
204 "BRIG version not supported. BRIG 1.0 required.");
205
206 m_brig = brig_blob;
207
208 find_brig_sections ();
209
210 brig_directive_variable_handler var_handler (*this);
211 brig_directive_fbarrier_handler fbar_handler (*this);
212 brig_directive_function_handler func_handler (*this);
213
214 /* Need this for grabbing the module names for mangling the
215 group variable names. */
216 brig_directive_module_handler module_handler (*this);
217 skipped_entry_handler skipped_handler (*this);
218
219 const BrigSectionHeader *csection_header = (const BrigSectionHeader *) m_code;
220
221 code_entry_handler_info handlers[]
222 = {{BRIG_KIND_DIRECTIVE_VARIABLE, &var_handler},
223 {BRIG_KIND_DIRECTIVE_FBARRIER, &fbar_handler},
224 {BRIG_KIND_DIRECTIVE_KERNEL, &func_handler},
225 {BRIG_KIND_DIRECTIVE_MODULE, &module_handler},
226 {BRIG_KIND_DIRECTIVE_FUNCTION, &func_handler}};
227
228 m_analyzing = true;
229 for (size_t b = csection_header->headerByteCount; b < m_code_size;)
230 {
231 const BrigBase *entry = (const BrigBase *) (m_code + b);
232
233 brig_code_entry_handler *handler = &skipped_handler;
234
235 if (m_cf != NULL && b >= m_cf->m_brig_def->nextModuleEntry)
236 {
237 /* The function definition ended. We can just discard the place
238 holder function. */
239 m_total_group_segment_usage += m_cf->m_local_group_variables.size ();
240 delete m_cf;
241 m_cf = NULL;
242 }
243
244 /* Find a handler. */
245 for (size_t i = 0;
246 i < sizeof (handlers) / sizeof (code_entry_handler_info); ++i)
247 {
248 if (handlers[i].kind == entry->kind)
249 handler = handlers[i].handler;
250 }
251
252 int bytes_processed = (*handler) (entry);
253 if (bytes_processed == 0)
254 fatal_error (UNKNOWN_LOCATION, PHSA_ERROR_PREFIX_CORRUPTED_MODULE
255 "Element with 0 bytes.");
256 b += bytes_processed;
257 }
258
259 if (m_cf != NULL)
260 {
261 m_total_group_segment_usage += m_cf->m_local_group_variables.size ();
262 delete m_cf;
263 m_cf = NULL;
264 }
265
266 m_total_group_segment_usage += m_module_group_variables.size ();
267 m_analyzing = false;
268 }
269
270 /* Parses the given BRIG blob. */
271
272 void
273 brig_to_generic::parse (const char *brig_blob)
274 {
275 m_brig = brig_blob;
276 find_brig_sections ();
277
278 brig_basic_inst_handler inst_handler (*this);
279 brig_branch_inst_handler branch_inst_handler (*this);
280 brig_cvt_inst_handler cvt_inst_handler (*this);
281 brig_seg_inst_handler seg_inst_handler (*this);
282 brig_copy_move_inst_handler copy_move_inst_handler (*this);
283 brig_signal_inst_handler signal_inst_handler (*this);
284 brig_atomic_inst_handler atomic_inst_handler (*this);
285 brig_cmp_inst_handler cmp_inst_handler (*this);
286 brig_mem_inst_handler mem_inst_handler (*this);
287 brig_inst_mod_handler inst_mod_handler (*this);
288 brig_directive_label_handler label_handler (*this);
289 brig_directive_variable_handler var_handler (*this);
290 brig_directive_fbarrier_handler fbar_handler (*this);
291 brig_directive_comment_handler comment_handler (*this);
292 brig_directive_function_handler func_handler (*this);
293 brig_directive_control_handler control_handler (*this);
294 brig_directive_arg_block_handler arg_block_handler (*this);
295 brig_directive_module_handler module_handler (*this);
296 brig_lane_inst_handler lane_inst_handler (*this);
297 brig_queue_inst_handler queue_inst_handler (*this);
298 skipped_entry_handler skipped_handler (*this);
299 unimplemented_entry_handler unimplemented_handler (*this);
300
301 struct code_entry_handler_info
302 {
303 BrigKind kind;
304 brig_code_entry_handler *handler;
305 };
306
307 /* TODO: Convert to a hash table / map. For now, put the more common
308 entries to the top to keep the scan fast on average. */
309 code_entry_handler_info handlers[]
310 = {{BRIG_KIND_INST_BASIC, &inst_handler},
311 {BRIG_KIND_INST_CMP, &cmp_inst_handler},
312 {BRIG_KIND_INST_MEM, &mem_inst_handler},
313 {BRIG_KIND_INST_MOD, &inst_mod_handler},
314 {BRIG_KIND_INST_CVT, &cvt_inst_handler},
315 {BRIG_KIND_INST_SEG_CVT, &seg_inst_handler},
316 {BRIG_KIND_INST_SEG, &seg_inst_handler},
317 {BRIG_KIND_INST_ADDR, &copy_move_inst_handler},
318 {BRIG_KIND_INST_SOURCE_TYPE, &copy_move_inst_handler},
319 {BRIG_KIND_INST_ATOMIC, &atomic_inst_handler},
320 {BRIG_KIND_INST_SIGNAL, &signal_inst_handler},
321 {BRIG_KIND_INST_BR, &branch_inst_handler},
322 {BRIG_KIND_INST_LANE, &lane_inst_handler},
323 {BRIG_KIND_INST_QUEUE, &queue_inst_handler},
324 /* Assuming fences are not needed. FIXME: call builtins
325 when porting to a platform where they are. */
326 {BRIG_KIND_INST_MEM_FENCE, &skipped_handler},
327 {BRIG_KIND_DIRECTIVE_LABEL, &label_handler},
328 {BRIG_KIND_DIRECTIVE_VARIABLE, &var_handler},
329 {BRIG_KIND_DIRECTIVE_ARG_BLOCK_START, &arg_block_handler},
330 {BRIG_KIND_DIRECTIVE_ARG_BLOCK_END, &arg_block_handler},
331 {BRIG_KIND_DIRECTIVE_FBARRIER, &fbar_handler},
332 {BRIG_KIND_DIRECTIVE_COMMENT, &comment_handler},
333 {BRIG_KIND_DIRECTIVE_KERNEL, &func_handler},
334 {BRIG_KIND_DIRECTIVE_SIGNATURE, &func_handler},
335 {BRIG_KIND_DIRECTIVE_FUNCTION, &func_handler},
336 {BRIG_KIND_DIRECTIVE_INDIRECT_FUNCTION, &func_handler},
337 {BRIG_KIND_DIRECTIVE_MODULE, &module_handler},
338 /* Skipping debug locations for now as not needed for conformance. */
339 {BRIG_KIND_DIRECTIVE_LOC, &skipped_handler},
340 /* There are no supported pragmas at this moment. */
341 {BRIG_KIND_DIRECTIVE_PRAGMA, &skipped_handler},
342 {BRIG_KIND_DIRECTIVE_CONTROL, &control_handler},
343 {BRIG_KIND_DIRECTIVE_EXTENSION, &skipped_handler},
344 /* BRIG_KIND_NONE entries are valid anywhere. They can be used
345 for patching BRIGs before finalization. */
346 {BRIG_KIND_NONE, &skipped_handler}};
347
348 const BrigSectionHeader *csection_header = (const BrigSectionHeader *) m_code;
349
350 for (size_t b = csection_header->headerByteCount; b < m_code_size;)
351 {
352 const BrigBase *entry = (const BrigBase *) (m_code + b);
353
354 brig_code_entry_handler *handler = &unimplemented_handler;
355
356 if (m_cf != NULL && b >= m_cf->m_brig_def->nextModuleEntry)
357 finish_function (); /* The function definition ended. */
358
359 /* Find a handler. */
360 for (size_t i = 0;
361 i < sizeof (handlers) / sizeof (code_entry_handler_info); ++i)
362 {
363 if (handlers[i].kind == entry->kind)
364 handler = handlers[i].handler;
365 }
366 b += (*handler) (entry);
367 }
368
369 finish_function ();
370 }
371
372 const BrigData *
373 brig_to_generic::get_brig_data_entry (size_t entry_offset) const
374 {
375 return (const BrigData *) (m_data + entry_offset);
376 }
377
378 const BrigBase *
379 brig_to_generic::get_brig_operand_entry (size_t entry_offset) const
380 {
381 return (const BrigBase *) (m_operand + entry_offset);
382 }
383
384 const BrigBase *
385 brig_to_generic::get_brig_code_entry (size_t entry_offset) const
386 {
387 return (const BrigBase *) (m_code + entry_offset);
388 }
389
390 void
391 brig_to_generic::append_global (tree g)
392 {
393 if (m_globals == NULL_TREE)
394 {
395 m_globals = g;
396 return;
397 }
398 else
399 {
400 tree last = tree_last (m_globals);
401 TREE_CHAIN (last) = g;
402 }
403 }
404
405 tree
406 brig_to_generic::global_variable (const std::string &name) const
407 {
408 label_index::const_iterator i = m_global_variables.find (name);
409 if (i == m_global_variables.end ())
410 return NULL_TREE;
411 else
412 return (*i).second;
413 }
414
415 /* Returns a function declaration with the given name. Assumes it has been
416 created previously via a DirectiveFunction or similar. */
417
418 tree
419 brig_to_generic::function_decl (const std::string &name)
420 {
421 label_index::const_iterator i = m_function_index.find (name);
422 if (i == m_function_index.end ())
423 return NULL_TREE;
424 return (*i).second;
425 }
426
427 void
428 brig_to_generic::add_function_decl (const std::string &name, tree func_decl)
429 {
430 m_function_index[name] = func_decl;
431 }
432
433 /* Adds a GENERIC global variable VAR_DECL with the given NAME to the
434 current module. If we have generated a host def var ptr (a place holder
435 for variables that are defined by the HSA host code) for this global
436 variable definition (because there was a declaration earlier which looked
437 like it might have been a host defined variable), we now have
438 to assign its address and make it private to allow the references to
439 point to the defined variable instead. */
440
441 void
442 brig_to_generic::add_global_variable (const std::string &name, tree var_decl)
443 {
444 append_global (var_decl);
445 m_global_variables[name] = var_decl;
446
447 std::string host_def_var_name
448 = std::string (PHSA_HOST_DEF_PTR_PREFIX) + name;
449 tree host_def_var = global_variable (host_def_var_name);
450 if (host_def_var == NULL_TREE)
451 return;
452
453 tree ptype = build_pointer_type (TREE_TYPE (var_decl));
454 tree var_addr = build1 (ADDR_EXPR, ptype, var_decl);
455
456 DECL_INITIAL (host_def_var) = var_addr;
457 TREE_PUBLIC (host_def_var) = 0;
458 }
459
460 /* Adds an indirection pointer for a potential host-defined program scope
461 variable declaration. */
462
463 void
464 brig_to_generic::add_host_def_var_ptr (const std::string &name, tree var_decl)
465 {
466 std::string var_name = std::string (PHSA_HOST_DEF_PTR_PREFIX) + name;
467
468 tree name_identifier = get_identifier (var_name.c_str ());
469
470 tree ptr_var = build_decl (UNKNOWN_LOCATION, VAR_DECL, name_identifier,
471 build_pointer_type (TREE_TYPE (var_decl)));
472 DECL_EXTERNAL (ptr_var) = 0;
473 DECL_ARTIFICIAL (ptr_var) = 0;
474
475 TREE_PUBLIC (ptr_var) = 1;
476 TREE_USED (ptr_var) = 1;
477 TREE_ADDRESSABLE (ptr_var) = 1;
478 TREE_STATIC (ptr_var) = 1;
479
480 append_global (ptr_var);
481 m_global_variables[var_name] = ptr_var;
482 }
483
484 /* Produce a "mangled name" for the given brig function or kernel.
485 The mangling is used to make unique global symbol name in case of
486 module scope functions. Program scope functions are not mangled
487 (except for dropping the leading &), which makes the functions
488 directly visible for linking using the original function name. */
489
490 std::string
491 brig_to_generic::get_mangled_name
492 (const BrigDirectiveExecutable *func) const
493 {
494 /* Strip the leading &. */
495 std::string func_name = get_string (func->name).substr (1);
496 if (func->linkage == BRIG_LINKAGE_MODULE)
497 {
498 /* Mangle the module scope function names with the module name and
499 make them public so they can be queried by the HSA runtime from
500 the produced binary. Assume it's the currently processed function
501 we are always referring to. */
502 func_name = "gccbrig." + m_module_name + "." + func_name;
503 }
504 return func_name;
505 }
506
507 std::string
508 brig_to_generic::get_string (size_t entry_offset) const
509 {
510 const BrigData *data_item = get_brig_data_entry (entry_offset);
511 return std::string ((const char *) &data_item->bytes, data_item->byteCount);
512 }
513
514 /* Adapted from c-semantics.c. */
515
516 tree
517 build_stmt (enum tree_code code, ...)
518 {
519 tree ret;
520 int length, i;
521 va_list p;
522 bool side_effects;
523
524 /* This function cannot be used to construct variably-sized nodes. */
525 gcc_assert (TREE_CODE_CLASS (code) != tcc_vl_exp);
526
527 va_start (p, code);
528
529 ret = make_node (code);
530 TREE_TYPE (ret) = void_type_node;
531 length = TREE_CODE_LENGTH (code);
532
533 /* TREE_SIDE_EFFECTS will already be set for statements with
534 implicit side effects. Here we make sure it is set for other
535 expressions by checking whether the parameters have side
536 effects. */
537
538 side_effects = false;
539 for (i = 0; i < length; i++)
540 {
541 tree t = va_arg (p, tree);
542 if (t && !TYPE_P (t))
543 side_effects |= TREE_SIDE_EFFECTS (t);
544 TREE_OPERAND (ret, i) = t;
545 }
546
547 TREE_SIDE_EFFECTS (ret) |= side_effects;
548
549 va_end (p);
550 return ret;
551 }
552
553 /* BRIG regs are untyped, but GENERIC is not. We need to add implicit casts
554 in case treating the operand with an instruction with a type different
555 than the created reg var type in order to select correct instruction type
556 later on. This function creates the necessary reinterpret type cast from
557 a source variable to the destination type. In case no cast is needed to
558 the same type, SOURCE is returned directly. */
559
560 tree
561 build_reinterpret_cast (tree destination_type, tree source)
562 {
563
564 gcc_assert (source && destination_type && TREE_TYPE (source) != NULL_TREE
565 && destination_type != NULL_TREE);
566
567 tree source_type = TREE_TYPE (source);
568 if (TREE_CODE (source) == CALL_EXPR)
569 {
570 tree func_decl = TREE_OPERAND (TREE_OPERAND (source, 1), 0);
571 source_type = TREE_TYPE (TREE_TYPE (func_decl));
572 }
573
574 if (destination_type == source_type)
575 return source;
576
577 size_t src_size = int_size_in_bytes (source_type);
578 size_t dst_size = int_size_in_bytes (destination_type);
579 if (src_size == dst_size)
580 return build1 (VIEW_CONVERT_EXPR, destination_type, source);
581 else if (src_size < dst_size)
582 {
583 /* The src_size can be smaller at least with f16 scalars which are
584 stored to 32b register variables. First convert to an equivalent
585 size unsigned type, then extend to an unsigned type of the
586 target width, after which VIEW_CONVERT_EXPR can be used to
587 force to the target type. */
588 tree unsigned_temp = build1 (VIEW_CONVERT_EXPR,
589 get_unsigned_int_type (source_type),
590 source);
591 return build1 (VIEW_CONVERT_EXPR, destination_type,
592 convert (get_unsigned_int_type (destination_type),
593 unsigned_temp));
594 }
595 else
596 gcc_unreachable ();
597 return NULL_TREE;
598 }
599
600 /* Returns the finished brig_function for the given generic FUNC_DECL,
601 or NULL, if not found. */
602
603 brig_function *
604 brig_to_generic::get_finished_function (tree func_decl)
605 {
606 std::string func_name
607 = identifier_to_locale (IDENTIFIER_POINTER (DECL_NAME (func_decl)));
608 std::map<std::string, brig_function *>::iterator i
609 = m_finished_functions.find (func_name);
610 if (i != m_finished_functions.end ())
611 return (*i).second;
612 else
613 return NULL;
614 }
615
616 /* Adds a group variable to a correct book keeping structure depending
617 on its segment. */
618
619 void
620 brig_to_generic::add_group_variable (const std::string &name, size_t size,
621 size_t alignment, bool function_scope)
622 {
623 /* Module and function scope group region variables are an experimental
624 feature. We implement module scope group variables with a separate
625 book keeping inside brig_to_generic which is populated in the 'analyze()'
626 prepass. This is to ensure we know the group segment offsets when
627 processing the functions that might refer to them. */
628 if (!function_scope)
629 {
630 if (!m_module_group_variables.has_variable (name))
631 m_module_group_variables.add (name, size, alignment);
632 return;
633 }
634
635 if (!m_cf->m_local_group_variables.has_variable (name))
636 m_cf->m_local_group_variables.add (name, size, alignment);
637 }
638
639 /* Finalizes the currently handled function. Should be called before
640 setting a new function. */
641
642 void
643 brig_to_generic::finish_function ()
644 {
645 if (m_cf == NULL || m_cf->m_func_decl == NULL_TREE)
646 {
647 /* It can be a finished func declaration fingerprint, in that case we
648 don't have m_func_decl. */
649 m_cf = NULL;
650 return;
651 }
652
653 if (!m_cf->m_is_kernel)
654 {
655 tree bind_expr = m_cf->m_current_bind_expr;
656 tree stmts = BIND_EXPR_BODY (bind_expr);
657 m_cf->finish ();
658 m_cf->emit_metadata (stmts);
659 dump_function (m_dump_file, m_cf);
660 gimplify_function_tree (m_cf->m_func_decl);
661 cgraph_node::finalize_function (m_cf->m_func_decl, true);
662 }
663 else
664 /* Emit the kernel only at the very end so we can analyze the total
665 group and private memory usage. */
666 m_kernels.push_back (m_cf);
667
668 pop_cfun ();
669
670 m_finished_functions[m_cf->m_name] = m_cf;
671 m_cf = NULL;
672 }
673
674 /* Initializes a new currently handled function. */
675
676 void
677 brig_to_generic::start_function (tree f)
678 {
679 if (DECL_STRUCT_FUNCTION (f) == NULL)
680 push_struct_function (f);
681 else
682 push_cfun (DECL_STRUCT_FUNCTION (f));
683
684 m_cf->m_func_decl = f;
685 }
686
687 /* Appends a new variable to the current kernel's private segment. */
688
689 void
690 brig_to_generic::append_private_variable (const std::string &name,
691 size_t size, size_t alignment)
692 {
693 /* We need to take care of two cases of alignment with private
694 variables because of the layout where the same variable for
695 each work-item is laid out in successive addresses.
696
697 1) Ensure the first work-item's variable is in an aligned
698 offset: */
699 size_t align_padding = m_next_private_offset % alignment == 0 ?
700 0 : (alignment - m_next_private_offset % alignment);
701
702 /* 2) Each successive per-work-item copy should be aligned.
703 If the variable has wider alignment than size then we need
704 to add extra padding to ensure it. The padding must be
705 included in the size to allow per-work-item offset computation
706 to find their own aligned copy. */
707
708 size_t per_var_padding = size % alignment == 0 ?
709 0 : (alignment - size % alignment);
710 m_private_data_sizes[name] = size + per_var_padding;
711
712 m_next_private_offset += align_padding;
713 m_private_offsets[name] = m_next_private_offset;
714 m_next_private_offset += size + per_var_padding;
715 }
716
717 size_t
718 brig_to_generic::private_variable_segment_offset
719 (const std::string &name) const
720 {
721 var_offset_table::const_iterator i = m_private_offsets.find (name);
722 gcc_assert (i != m_private_offsets.end ());
723 return (*i).second;
724 }
725
726 bool
727 brig_to_generic::has_private_variable (const std::string &name) const
728 {
729 std::map<std::string, size_t>::const_iterator i
730 = m_private_data_sizes.find (name);
731 return i != m_private_data_sizes.end ();
732 }
733
734 size_t
735 brig_to_generic::private_variable_size (const std::string &name) const
736 {
737 std::map<std::string, size_t>::const_iterator i
738 = m_private_data_sizes.find (name);
739 gcc_assert (i != m_private_data_sizes.end ());
740 return (*i).second;
741 }
742
743
744 /* The size of private segment required by a single work-item executing
745 the currently processed kernel. */
746
747 size_t
748 brig_to_generic::private_segment_size () const
749 {
750 return m_next_private_offset;
751 }
752
753 /* Cached builtins indexed by name. */
754
755 typedef std::map<std::string, tree> builtin_index;
756 builtin_index builtin_cache_;
757
758 /* Build a call to a builtin function. PDECL is the builtin function to
759 call. NARGS is the number of input arguments, RETTYPE the built-in
760 functions return value type, and ... is the list of arguments passed to
761 the call with type first, then the value. */
762
763 tree
764 call_builtin (tree pdecl, int nargs, tree rettype, ...)
765 {
766 if (rettype == error_mark_node)
767 return error_mark_node;
768
769 tree *types = new tree[nargs];
770 tree *args = new tree[nargs];
771
772 va_list ap;
773 va_start (ap, rettype);
774 for (int i = 0; i < nargs; ++i)
775 {
776 types[i] = va_arg (ap, tree);
777 tree arg = va_arg (ap, tree);
778 args[i] = build_reinterpret_cast (types[i], arg);
779 if (types[i] == error_mark_node || args[i] == error_mark_node)
780 {
781 delete[] types;
782 delete[] args;
783 va_end (ap);
784 return error_mark_node;
785 }
786 }
787 va_end (ap);
788
789 tree fnptr = build_fold_addr_expr (pdecl);
790
791 tree ret = build_call_array (rettype, fnptr, nargs, args);
792
793 delete[] types;
794 delete[] args;
795
796 return ret;
797 }
798
799 /* Generate all global declarations. Should be called after the last
800 BRIG has been fed in. */
801
802 void
803 brig_to_generic::write_globals ()
804 {
805 /* Now that the whole BRIG module has been processed, build a launcher
806 and a metadata section for each built kernel. */
807 for (size_t i = 0; i < m_kernels.size (); ++i)
808 {
809 brig_function *f = m_kernels[i];
810
811 /* Finish kernels now that we know the call graphs and their barrier
812 usage. */
813 f->finish_kernel ();
814
815 dump_function (m_dump_file, f);
816 gimplify_function_tree (f->m_func_decl);
817 cgraph_node::finalize_function (f->m_func_decl, true);
818
819 f->m_descriptor.is_kernel = 1;
820 /* TODO: analyze the kernel's actual private and group segment usage
821 using call graph. Now the mem size is overly
822 pessimistic in case of multiple kernels in the same module.
823 */
824 f->m_descriptor.group_segment_size = m_total_group_segment_usage;
825 f->m_descriptor.private_segment_size = private_segment_size ();
826
827 /* The kernarg size is rounded up to a multiple of 16 according to
828 the PRM specs. */
829 f->m_descriptor.kernarg_segment_size = f->m_next_kernarg_offset;
830 if (f->m_descriptor.kernarg_segment_size % 16 > 0)
831 f->m_descriptor.kernarg_segment_size
832 += 16 - f->m_next_kernarg_offset % 16;
833 f->m_descriptor.kernarg_max_align = f->m_kernarg_max_align;
834
835 tree launcher = f->emit_launcher_and_metadata ();
836
837 append_global (launcher);
838
839 gimplify_function_tree (launcher);
840 cgraph_node::finalize_function (launcher, true);
841 pop_cfun ();
842 }
843
844 int no_globals = list_length (m_globals);
845 tree *vec = new tree[no_globals];
846
847 int i = 0;
848 tree global = m_globals;
849 while (global)
850 {
851 vec[i] = global;
852 ++i;
853 global = TREE_CHAIN (global);
854 }
855
856 wrapup_global_declarations (vec, no_globals);
857
858 delete[] vec;
859
860 }
861
862 /* Returns an type with unsigned int elements corresponding to the
863 size and element count of ORIGINAL_TYPE. */
864
865 tree
866 get_unsigned_int_type (tree original_type)
867 {
868 if (VECTOR_TYPE_P (original_type))
869 {
870 size_t esize
871 = int_size_in_bytes (TREE_TYPE (original_type)) * BITS_PER_UNIT;
872 size_t ecount = TYPE_VECTOR_SUBPARTS (original_type);
873 return build_vector_type (build_nonstandard_integer_type (esize, true),
874 ecount);
875 }
876 else
877 return build_nonstandard_integer_type (int_size_in_bytes (original_type)
878 * BITS_PER_UNIT,
879 true);
880 }
881
882 void
883 dump_function (FILE *dump_file, brig_function *f)
884 {
885 /* Dump the BRIG-specific tree IR. */
886 if (dump_file)
887 {
888 fprintf (dump_file, "\n;; Function %s", f->m_name.c_str ());
889 fprintf (dump_file, "\n;; enabled by -%s\n\n",
890 dump_flag_name (TDI_original));
891 print_generic_decl (dump_file, f->m_func_decl, 0);
892 print_generic_expr (dump_file, f->m_current_bind_expr, 0);
893 fprintf (dump_file, "\n");
894 }
895 }