1 /* brig2tree.cc -- brig to gcc generic/gimple tree conversion
2 Copyright (C) 2016-2018 Free Software Foundation, Inc.
3 Contributed by Pekka Jaaskelainen <pekka.jaaskelainen@parmance.com>
4 for General Processor Tech.
6 This file is part of GCC.
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
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
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/>. */
29 #include "coretypes.h"
32 #include "brig-to-generic.h"
33 #include "stringpool.h"
34 #include "tree-iterator.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"
46 #include "tree-pretty-print.h"
48 #include "profile-count.h"
51 #include "fold-const.h"
54 #include "tree-pretty-print.h"
57 extern int gccbrig_verbose
;
59 tree
brig_to_generic::s_fp16_type
;
60 tree
brig_to_generic::s_fp32_type
;
61 tree
brig_to_generic::s_fp64_type
;
63 brig_to_generic::brig_to_generic ()
64 : m_cf (NULL
), m_analyzing (true), m_total_group_segment_usage (0),
65 m_brig (NULL
), m_next_private_offset (0)
67 m_globals
= NULL_TREE
;
69 /* Initialize the basic REAL types.
70 This doesn't work straight away because most of the targets
71 do not support fp16 natively. Let's by default convert
72 to fp32 and back before and after each instruction (handle it as
73 a storage format only), and later add an optimization pass
74 that removes the extra converts (in case of multiple fp16 ops
76 s_fp16_type
= make_node (REAL_TYPE
);
77 TYPE_PRECISION (s_fp16_type
) = 16;
78 TYPE_SIZE (s_fp16_type
) = bitsize_int (16);
79 TYPE_SIZE_UNIT (s_fp16_type
) = size_int (2);
80 SET_TYPE_ALIGN (s_fp16_type
, 16);
81 layout_type (s_fp16_type
);
83 s_fp32_type
= gccbrig_tree_type_for_hsa_type (BRIG_TYPE_F32
);
84 s_fp64_type
= gccbrig_tree_type_for_hsa_type (BRIG_TYPE_F64
);
86 /* TODO: (machine)query the preferred rounding mode that is set by
87 the machine by default. This can be redefined by each BRIG module
89 m_default_float_rounding_mode
= BRIG_ROUND_FLOAT_ZERO
;
91 m_dump_file
= dump_begin (TDI_original
, &m_dump_flags
);
94 class unimplemented_entry_handler
: public brig_code_entry_handler
97 unimplemented_entry_handler (brig_to_generic
&parent
)
98 : brig_code_entry_handler (parent
)
103 operator () (const BrigBase
*base
)
106 return base
->byteCount
;
110 /* Handler for entries that can be (and are) safely skipped for the purposes
111 of GENERIC generation. */
113 class skipped_entry_handler
: public brig_code_entry_handler
116 skipped_entry_handler (brig_to_generic
&parent
)
117 : brig_code_entry_handler (parent
)
122 operator () (const BrigBase
*base
)
124 return base
->byteCount
;
128 class brig_reg_use_analyzer
: public brig_code_entry_handler
131 brig_reg_use_analyzer (brig_to_generic
&parent
)
132 : brig_code_entry_handler (parent
)
137 operator () (const BrigBase
*base
)
139 const BrigInstBase
*brig_inst
= (const BrigInstBase
*) base
;
140 analyze_operands (*brig_inst
);
141 return base
->byteCount
;
146 /* Helper struct for pairing a BrigKind and a BrigCodeEntryHandler that
147 should handle its data. */
149 struct code_entry_handler_info
152 brig_code_entry_handler
*handler
;
156 /* Finds the BRIG file sections in the currently processed file. */
159 brig_to_generic::find_brig_sections ()
161 m_data
= m_code
= m_operand
= NULL
;
162 const BrigModuleHeader
*mheader
= (const BrigModuleHeader
*) m_brig
;
164 /* Find the positions of the different sections. */
165 for (uint32_t sec
= 0; sec
< mheader
->sectionCount
; ++sec
)
168 = ((const uint64_t *) (m_brig
+ mheader
->sectionIndex
))[sec
];
170 const BrigSectionHeader
*section_header
171 = (const BrigSectionHeader
*) (m_brig
+ offset
);
173 std::string
name ((const char *) (§ion_header
->name
),
174 section_header
->nameLength
);
176 if (sec
== BRIG_SECTION_INDEX_DATA
&& name
== "hsa_data")
178 m_data
= (const char *) section_header
;
179 m_data_size
= section_header
->byteCount
;
181 else if (sec
== BRIG_SECTION_INDEX_CODE
&& name
== "hsa_code")
183 m_code
= (const char *) section_header
;
184 m_code_size
= section_header
->byteCount
;
186 else if (sec
== BRIG_SECTION_INDEX_OPERAND
&& name
== "hsa_operand")
188 m_operand
= (const char *) section_header
;
189 m_operand_size
= section_header
->byteCount
;
201 if (m_operand
== NULL
)
206 /* Does a first pass over the given BRIG to collect data needed for the
207 actual parsing. Currently this includes only collecting the
208 group segment variable usage to support the experimental HSA PRM feature
209 where group variables can be declared also in module and function scope
210 (in addition to kernel scope).
214 brig_to_generic::analyze (const char *brig_blob
)
216 const BrigModuleHeader
*mheader
= (const BrigModuleHeader
*) brig_blob
;
218 if (strncmp (mheader
->identification
, "HSA BRIG", 8) != 0)
219 fatal_error (UNKNOWN_LOCATION
, PHSA_ERROR_PREFIX_INCOMPATIBLE_MODULE
220 "Unrecognized file format.");
221 if (mheader
->brigMajor
!= 1 || mheader
->brigMinor
!= 0)
222 fatal_error (UNKNOWN_LOCATION
, PHSA_ERROR_PREFIX_INCOMPATIBLE_MODULE
223 "BRIG version not supported. BRIG 1.0 required.");
227 find_brig_sections ();
229 brig_directive_variable_handler
var_handler (*this);
230 brig_directive_fbarrier_handler
fbar_handler (*this);
231 brig_directive_function_handler
func_handler (*this);
232 brig_reg_use_analyzer
reg_use_analyzer (*this);
234 /* Need this for grabbing the module names for mangling the
235 group variable names. */
236 brig_directive_module_handler
module_handler (*this);
237 skipped_entry_handler
skipped_handler (*this);
239 const BrigSectionHeader
*csection_header
= (const BrigSectionHeader
*) m_code
;
241 code_entry_handler_info handlers
[]
242 = {{BRIG_KIND_INST_BASIC
, ®_use_analyzer
},
243 {BRIG_KIND_INST_MOD
, ®_use_analyzer
},
244 {BRIG_KIND_INST_CMP
, ®_use_analyzer
},
245 {BRIG_KIND_INST_MEM
, ®_use_analyzer
},
246 {BRIG_KIND_INST_CVT
, ®_use_analyzer
},
247 {BRIG_KIND_INST_SEG_CVT
, ®_use_analyzer
},
248 {BRIG_KIND_INST_SEG
, ®_use_analyzer
},
249 {BRIG_KIND_INST_ADDR
, ®_use_analyzer
},
250 {BRIG_KIND_INST_SOURCE_TYPE
, ®_use_analyzer
},
251 {BRIG_KIND_INST_ATOMIC
, ®_use_analyzer
},
252 {BRIG_KIND_INST_SIGNAL
, ®_use_analyzer
},
253 {BRIG_KIND_INST_BR
, ®_use_analyzer
},
254 {BRIG_KIND_INST_LANE
, ®_use_analyzer
},
255 {BRIG_KIND_INST_QUEUE
, ®_use_analyzer
},
256 {BRIG_KIND_DIRECTIVE_VARIABLE
, &var_handler
},
257 {BRIG_KIND_DIRECTIVE_FBARRIER
, &fbar_handler
},
258 {BRIG_KIND_DIRECTIVE_KERNEL
, &func_handler
},
259 {BRIG_KIND_DIRECTIVE_MODULE
, &module_handler
},
260 {BRIG_KIND_DIRECTIVE_FUNCTION
, &func_handler
}};
263 for (size_t b
= csection_header
->headerByteCount
; b
< m_code_size
;)
265 const BrigBase
*entry
= (const BrigBase
*) (m_code
+ b
);
267 brig_code_entry_handler
*handler
= &skipped_handler
;
269 if (m_cf
!= NULL
&& b
>= m_cf
->m_brig_def
->nextModuleEntry
)
271 /* The function definition ended. We can just discard the place
273 m_total_group_segment_usage
+= m_cf
->m_local_group_variables
.size ();
278 /* Find a handler. */
280 i
< sizeof (handlers
) / sizeof (code_entry_handler_info
); ++i
)
282 if (handlers
[i
].kind
== entry
->kind
)
283 handler
= handlers
[i
].handler
;
286 int bytes_processed
= (*handler
) (entry
);
287 if (bytes_processed
== 0)
288 fatal_error (UNKNOWN_LOCATION
, PHSA_ERROR_PREFIX_CORRUPTED_MODULE
289 "Element with 0 bytes.");
290 b
+= bytes_processed
;
295 m_total_group_segment_usage
+= m_cf
->m_local_group_variables
.size ();
300 m_total_group_segment_usage
+= m_module_group_variables
.size ();
304 /* Parses the given BRIG blob. */
307 brig_to_generic::parse (const char *brig_blob
)
310 find_brig_sections ();
312 brig_basic_inst_handler
inst_handler (*this);
313 brig_branch_inst_handler
branch_inst_handler (*this);
314 brig_cvt_inst_handler
cvt_inst_handler (*this);
315 brig_seg_inst_handler
seg_inst_handler (*this);
316 brig_copy_move_inst_handler
copy_move_inst_handler (*this);
317 brig_signal_inst_handler
signal_inst_handler (*this);
318 brig_atomic_inst_handler
atomic_inst_handler (*this);
319 brig_cmp_inst_handler
cmp_inst_handler (*this);
320 brig_mem_inst_handler
mem_inst_handler (*this);
321 brig_inst_mod_handler
inst_mod_handler (*this);
322 brig_directive_label_handler
label_handler (*this);
323 brig_directive_variable_handler
var_handler (*this);
324 brig_directive_fbarrier_handler
fbar_handler (*this);
325 brig_directive_comment_handler
comment_handler (*this);
326 brig_directive_function_handler
func_handler (*this);
327 brig_directive_control_handler
control_handler (*this);
328 brig_directive_arg_block_handler
arg_block_handler (*this);
329 brig_directive_module_handler
module_handler (*this);
330 brig_lane_inst_handler
lane_inst_handler (*this);
331 brig_queue_inst_handler
queue_inst_handler (*this);
332 skipped_entry_handler
skipped_handler (*this);
333 unimplemented_entry_handler
unimplemented_handler (*this);
335 struct code_entry_handler_info
338 brig_code_entry_handler
*handler
;
341 /* TODO: Convert to a hash table / map. For now, put the more common
342 entries to the top to keep the scan fast on average. */
343 code_entry_handler_info handlers
[]
344 = {{BRIG_KIND_INST_BASIC
, &inst_handler
},
345 {BRIG_KIND_INST_CMP
, &cmp_inst_handler
},
346 {BRIG_KIND_INST_MEM
, &mem_inst_handler
},
347 {BRIG_KIND_INST_MOD
, &inst_mod_handler
},
348 {BRIG_KIND_INST_CVT
, &cvt_inst_handler
},
349 {BRIG_KIND_INST_SEG_CVT
, &seg_inst_handler
},
350 {BRIG_KIND_INST_SEG
, &seg_inst_handler
},
351 {BRIG_KIND_INST_ADDR
, ©_move_inst_handler
},
352 {BRIG_KIND_INST_SOURCE_TYPE
, ©_move_inst_handler
},
353 {BRIG_KIND_INST_ATOMIC
, &atomic_inst_handler
},
354 {BRIG_KIND_INST_SIGNAL
, &signal_inst_handler
},
355 {BRIG_KIND_INST_BR
, &branch_inst_handler
},
356 {BRIG_KIND_INST_LANE
, &lane_inst_handler
},
357 {BRIG_KIND_INST_QUEUE
, &queue_inst_handler
},
358 /* Assuming fences are not needed. FIXME: call builtins
359 when porting to a platform where they are. */
360 {BRIG_KIND_INST_MEM_FENCE
, &skipped_handler
},
361 {BRIG_KIND_DIRECTIVE_LABEL
, &label_handler
},
362 {BRIG_KIND_DIRECTIVE_VARIABLE
, &var_handler
},
363 {BRIG_KIND_DIRECTIVE_ARG_BLOCK_START
, &arg_block_handler
},
364 {BRIG_KIND_DIRECTIVE_ARG_BLOCK_END
, &arg_block_handler
},
365 {BRIG_KIND_DIRECTIVE_FBARRIER
, &fbar_handler
},
366 {BRIG_KIND_DIRECTIVE_COMMENT
, &comment_handler
},
367 {BRIG_KIND_DIRECTIVE_KERNEL
, &func_handler
},
368 {BRIG_KIND_DIRECTIVE_SIGNATURE
, &func_handler
},
369 {BRIG_KIND_DIRECTIVE_FUNCTION
, &func_handler
},
370 {BRIG_KIND_DIRECTIVE_INDIRECT_FUNCTION
, &func_handler
},
371 {BRIG_KIND_DIRECTIVE_MODULE
, &module_handler
},
372 /* Skipping debug locations for now as not needed for conformance. */
373 {BRIG_KIND_DIRECTIVE_LOC
, &skipped_handler
},
374 /* There are no supported pragmas at this moment. */
375 {BRIG_KIND_DIRECTIVE_PRAGMA
, &skipped_handler
},
376 {BRIG_KIND_DIRECTIVE_CONTROL
, &control_handler
},
377 {BRIG_KIND_DIRECTIVE_EXTENSION
, &skipped_handler
},
378 /* BRIG_KIND_NONE entries are valid anywhere. They can be used
379 for patching BRIGs before finalization. */
380 {BRIG_KIND_NONE
, &skipped_handler
}};
382 const BrigSectionHeader
*csection_header
= (const BrigSectionHeader
*) m_code
;
384 for (size_t b
= csection_header
->headerByteCount
; b
< m_code_size
;)
386 const BrigBase
*entry
= (const BrigBase
*) (m_code
+ b
);
388 brig_code_entry_handler
*handler
= &unimplemented_handler
;
390 if (m_cf
!= NULL
&& b
>= m_cf
->m_brig_def
->nextModuleEntry
)
391 finish_function (); /* The function definition ended. */
393 /* Find a handler. */
395 i
< sizeof (handlers
) / sizeof (code_entry_handler_info
); ++i
)
397 if (handlers
[i
].kind
== entry
->kind
)
398 handler
= handlers
[i
].handler
;
400 b
+= (*handler
) (entry
);
407 brig_to_generic::get_brig_data_entry (size_t entry_offset
) const
409 return (const BrigData
*) (m_data
+ entry_offset
);
413 brig_to_generic::get_brig_operand_entry (size_t entry_offset
) const
415 return (const BrigBase
*) (m_operand
+ entry_offset
);
419 brig_to_generic::get_brig_code_entry (size_t entry_offset
) const
421 return (const BrigBase
*) (m_code
+ entry_offset
);
425 brig_to_generic::append_global (tree g
)
427 if (m_globals
== NULL_TREE
)
434 tree last
= tree_last (m_globals
);
435 TREE_CHAIN (last
) = g
;
440 brig_to_generic::global_variable (const std::string
&name
) const
442 label_index::const_iterator i
= m_global_variables
.find (name
);
443 if (i
== m_global_variables
.end ())
449 /* Returns a function declaration with the given name. Assumes it has been
450 created previously via a DirectiveFunction or similar. */
453 brig_to_generic::function_decl (const std::string
&name
)
455 label_index::const_iterator i
= m_function_index
.find (name
);
456 if (i
== m_function_index
.end ())
462 brig_to_generic::add_function_decl (const std::string
&name
, tree func_decl
)
464 m_function_index
[name
] = func_decl
;
467 /* Adds a GENERIC global variable VAR_DECL with the given NAME to the
468 current module. If we have generated a host def var ptr (a place holder
469 for variables that are defined by the HSA host code) for this global
470 variable definition (because there was a declaration earlier which looked
471 like it might have been a host defined variable), we now have
472 to assign its address and make it private to allow the references to
473 point to the defined variable instead. */
476 brig_to_generic::add_global_variable (const std::string
&name
, tree var_decl
)
478 append_global (var_decl
);
479 m_global_variables
[name
] = var_decl
;
481 std::string host_def_var_name
482 = std::string (PHSA_HOST_DEF_PTR_PREFIX
) + name
;
483 tree host_def_var
= global_variable (host_def_var_name
);
484 if (host_def_var
== NULL_TREE
)
487 tree ptype
= build_pointer_type (TREE_TYPE (var_decl
));
488 tree var_addr
= build1 (ADDR_EXPR
, ptype
, var_decl
);
490 DECL_INITIAL (host_def_var
) = var_addr
;
491 TREE_PUBLIC (host_def_var
) = 1;
493 set_externally_visible (host_def_var
);
496 /* Adds an indirection pointer for a potential host-defined program scope
497 variable declaration. */
500 brig_to_generic::add_host_def_var_ptr (const std::string
&name
, tree var_decl
)
502 std::string var_name
= std::string (PHSA_HOST_DEF_PTR_PREFIX
) + name
;
504 tree name_identifier
= get_identifier (var_name
.c_str ());
506 tree ptr_var
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
, name_identifier
,
507 build_pointer_type (TREE_TYPE (var_decl
)));
508 DECL_EXTERNAL (ptr_var
) = 0;
509 DECL_ARTIFICIAL (ptr_var
) = 0;
511 TREE_PUBLIC (ptr_var
) = 1;
512 TREE_USED (ptr_var
) = 1;
513 TREE_ADDRESSABLE (ptr_var
) = 1;
514 TREE_STATIC (ptr_var
) = 1;
516 set_externally_visible (ptr_var
);
518 append_global (ptr_var
);
519 m_global_variables
[var_name
] = ptr_var
;
523 brig_to_generic::add_decl_call (tree call
)
525 m_decl_call
.push_back (call
);
528 /* Produce a "mangled name" for the given brig function or kernel.
529 The mangling is used to make unique global symbol name in case of
530 module scope functions. Program scope functions are not mangled
531 (except for dropping the leading &), which makes the functions
532 directly visible for linking using the original function name. */
535 brig_to_generic::get_mangled_name
536 (const BrigDirectiveExecutable
*func
) const
538 /* Strip the leading &. */
539 std::string func_name
= get_string (func
->name
).substr (1);
540 if (func
->linkage
== BRIG_LINKAGE_MODULE
)
542 /* Mangle the module scope function names with the module name and
543 make them public so they can be queried by the HSA runtime from
544 the produced binary. Assume it's the currently processed function
545 we are always referring to. */
546 func_name
= "gccbrig." + m_module_name
+ "." + func_name
;
552 brig_to_generic::get_string (size_t entry_offset
) const
554 const BrigData
*data_item
= get_brig_data_entry (entry_offset
);
555 return std::string ((const char *) &data_item
->bytes
, data_item
->byteCount
);
558 /* Adapted from c-semantics.c. */
561 build_stmt (enum tree_code code
, ...)
568 /* This function cannot be used to construct variably-sized nodes. */
569 gcc_assert (TREE_CODE_CLASS (code
) != tcc_vl_exp
);
573 ret
= make_node (code
);
574 TREE_TYPE (ret
) = void_type_node
;
575 length
= TREE_CODE_LENGTH (code
);
577 /* TREE_SIDE_EFFECTS will already be set for statements with
578 implicit side effects. Here we make sure it is set for other
579 expressions by checking whether the parameters have side
582 side_effects
= false;
583 for (i
= 0; i
< length
; i
++)
585 tree t
= va_arg (p
, tree
);
586 if (t
&& !TYPE_P (t
))
587 side_effects
|= TREE_SIDE_EFFECTS (t
);
588 TREE_OPERAND (ret
, i
) = t
;
591 TREE_SIDE_EFFECTS (ret
) |= side_effects
;
597 /* BRIG regs are untyped, but GENERIC is not. We need to add implicit casts
598 in case treating the operand with an instruction with a type different
599 than the created reg var type in order to select correct instruction type
600 later on. This function creates the necessary reinterpret type cast from
601 a source variable to the destination type. In case no cast is needed to
602 the same type, SOURCE is returned directly.
604 In case of mismatched type sizes, casting:
605 - to narrower type the upper bits are clipped and
606 - to wider type the source value is zero extended. */
609 build_resize_convert_view (tree destination_type
, tree source
)
612 gcc_assert (source
&& destination_type
&& TREE_TYPE (source
) != NULL_TREE
613 && destination_type
!= NULL_TREE
);
615 tree source_type
= TREE_TYPE (source
);
616 if (TREE_CODE (source
) == CALL_EXPR
)
618 tree func_decl
= TREE_OPERAND (TREE_OPERAND (source
, 1), 0);
619 source_type
= TREE_TYPE (TREE_TYPE (func_decl
));
622 if (destination_type
== source_type
)
625 size_t src_size
= int_size_in_bytes (source_type
);
626 size_t dst_size
= int_size_in_bytes (destination_type
);
627 if (src_size
== dst_size
)
628 return build1 (VIEW_CONVERT_EXPR
, destination_type
, source
);
629 else /* src_size != dst_size */
631 /* The src_size can be smaller at least with f16 scalars which are
632 stored to 32b register variables. First convert to an equivalent
633 size unsigned type, then extend to an unsigned type of the
634 target width, after which VIEW_CONVERT_EXPR can be used to
635 force to the target type. */
636 tree resized
= convert (get_scalar_unsigned_int_type (destination_type
),
637 build_reinterpret_to_uint (source
));
638 gcc_assert ((size_t)int_size_in_bytes (TREE_TYPE (resized
)) == dst_size
);
639 return build_resize_convert_view (destination_type
, resized
);
643 /* Reinterprets SOURCE as a scalar unsigned int with the size
644 corresponding to the orignal. */
646 tree
build_reinterpret_to_uint (tree source
)
648 tree src_type
= TREE_TYPE (source
);
649 if (INTEGRAL_TYPE_P (src_type
) && TYPE_UNSIGNED (src_type
))
651 tree dest_type
= get_scalar_unsigned_int_type (src_type
);
652 return build1 (VIEW_CONVERT_EXPR
, dest_type
, source
);
655 /* Returns the finished brig_function for the given generic FUNC_DECL,
656 or NULL, if not found. */
659 brig_to_generic::get_finished_function (tree func_decl
)
661 std::string func_name
662 = identifier_to_locale (IDENTIFIER_POINTER (DECL_NAME (func_decl
)));
663 std::map
<std::string
, brig_function
*>::iterator i
664 = m_finished_functions
.find (func_name
);
665 if (i
!= m_finished_functions
.end ())
671 /* Adds a group variable to a correct book keeping structure depending
675 brig_to_generic::add_group_variable (const std::string
&name
, size_t size
,
676 size_t alignment
, bool function_scope
)
678 /* Module and function scope group region variables are an experimental
679 feature. We implement module scope group variables with a separate
680 book keeping inside brig_to_generic which is populated in the 'analyze()'
681 prepass. This is to ensure we know the group segment offsets when
682 processing the functions that might refer to them. */
685 if (!m_module_group_variables
.has_variable (name
))
686 m_module_group_variables
.add (name
, size
, alignment
);
690 if (!m_cf
->m_local_group_variables
.has_variable (name
))
691 m_cf
->m_local_group_variables
.add (name
, size
, alignment
);
694 /* Finalizes the currently handled function. Should be called before
695 setting a new function. */
698 brig_to_generic::finish_function ()
700 if (m_cf
== NULL
|| m_cf
->m_func_decl
== NULL_TREE
)
702 /* It can be a finished func declaration fingerprint, in that case we
703 don't have m_func_decl. */
708 if (!m_cf
->m_is_kernel
)
710 tree bind_expr
= m_cf
->m_current_bind_expr
;
711 tree stmts
= BIND_EXPR_BODY (bind_expr
);
713 m_cf
->emit_metadata (stmts
);
714 dump_function (m_dump_file
, m_cf
);
717 /* Emit the kernel only at the very end so we can analyze the total
718 group and private memory usage. */
719 m_kernels
.push_back (m_cf
);
723 m_finished_functions
[m_cf
->m_name
] = m_cf
;
727 /* Initializes a new currently handled function. */
730 brig_to_generic::start_function (tree f
)
732 if (DECL_STRUCT_FUNCTION (f
) == NULL
)
733 push_struct_function (f
);
735 push_cfun (DECL_STRUCT_FUNCTION (f
));
737 m_cf
->m_func_decl
= f
;
740 /* Appends a new variable to the current kernel's private segment. */
743 brig_to_generic::append_private_variable (const std::string
&name
,
744 size_t size
, size_t alignment
)
746 /* We need to take care of two cases of alignment with private
747 variables because of the layout where the same variable for
748 each work-item is laid out in successive addresses.
750 1) Ensure the first work-item's variable is in an aligned
752 size_t align_padding
= m_next_private_offset
% alignment
== 0 ?
753 0 : (alignment
- m_next_private_offset
% alignment
);
755 /* 2) Each successive per-work-item copy should be aligned.
756 If the variable has wider alignment than size then we need
757 to add extra padding to ensure it. The padding must be
758 included in the size to allow per-work-item offset computation
759 to find their own aligned copy. */
761 size_t per_var_padding
= size
% alignment
== 0 ?
762 0 : (alignment
- size
% alignment
);
763 m_private_data_sizes
[name
] = size
+ per_var_padding
;
765 m_next_private_offset
+= align_padding
;
766 m_private_offsets
[name
] = m_next_private_offset
;
767 m_next_private_offset
+= size
+ per_var_padding
;
771 brig_to_generic::private_variable_segment_offset
772 (const std::string
&name
) const
774 var_offset_table::const_iterator i
= m_private_offsets
.find (name
);
775 gcc_assert (i
!= m_private_offsets
.end ());
780 brig_to_generic::has_private_variable (const std::string
&name
) const
782 std::map
<std::string
, size_t>::const_iterator i
783 = m_private_data_sizes
.find (name
);
784 return i
!= m_private_data_sizes
.end ();
788 brig_to_generic::private_variable_size (const std::string
&name
) const
790 std::map
<std::string
, size_t>::const_iterator i
791 = m_private_data_sizes
.find (name
);
792 gcc_assert (i
!= m_private_data_sizes
.end ());
797 /* The size of private segment required by a single work-item executing
798 the currently processed kernel. */
801 brig_to_generic::private_segment_size () const
803 return m_next_private_offset
;
806 /* Cached builtins indexed by name. */
808 typedef std::map
<std::string
, tree
> builtin_index
;
809 builtin_index builtin_cache_
;
811 /* Build a call to a builtin function. PDECL is the builtin function to
812 call. NARGS is the number of input arguments, RETTYPE the built-in
813 functions return value type, and ... is the list of arguments passed to
814 the call with type first, then the value. */
817 call_builtin (tree pdecl
, int nargs
, tree rettype
, ...)
819 if (rettype
== error_mark_node
)
820 return error_mark_node
;
822 tree
*types
= new tree
[nargs
];
823 tree
*args
= new tree
[nargs
];
826 va_start (ap
, rettype
);
827 for (int i
= 0; i
< nargs
; ++i
)
829 types
[i
] = va_arg (ap
, tree
);
830 tree arg
= va_arg (ap
, tree
);
831 args
[i
] = build_resize_convert_view (types
[i
], arg
);
832 if (types
[i
] == error_mark_node
|| args
[i
] == error_mark_node
)
837 return error_mark_node
;
842 tree fnptr
= build_fold_addr_expr (pdecl
);
844 tree ret
= build_call_array (rettype
, fnptr
, nargs
, args
);
852 /* Generate all global declarations. Should be called after the last
853 BRIG has been fed in. */
856 brig_to_generic::write_globals ()
859 /* Replace calls to declarations with calls to definitions. Otherwise
860 inlining will fail to find the definition to inline from. */
862 for (size_t i
= 0; i
< m_decl_call
.size(); ++i
)
864 tree decl_call
= m_decl_call
.at(i
);
865 tree func_decl
= get_callee_fndecl (decl_call
);
866 brig_function
*brig_function
= get_finished_function (func_decl
);
868 if (brig_function
&& brig_function
->m_func_decl
869 && DECL_EXTERNAL (brig_function
->m_func_decl
) == 0
870 && brig_function
->m_func_decl
!= func_decl
)
873 decl_call
= CALL_EXPR_FN (decl_call
);
874 STRIP_NOPS (decl_call
);
875 if (TREE_CODE (decl_call
) == ADDR_EXPR
876 && TREE_CODE (TREE_OPERAND (decl_call
, 0)) == FUNCTION_DECL
)
877 TREE_OPERAND (decl_call
, 0) = brig_function
->m_func_decl
;
881 for (std::map
<std::string
, brig_function
*>::iterator i
882 = m_finished_functions
.begin(), e
= m_finished_functions
.end();
885 brig_function
*brig_f
= (*i
).second
;
886 if (brig_f
->m_is_kernel
)
889 /* Finalize only at this point to allow the cgraph analysis to
890 see definitions to calls to later functions. */
891 gimplify_function_tree (brig_f
->m_func_decl
);
892 cgraph_node::finalize_function (brig_f
->m_func_decl
, true);
895 /* Now that the whole BRIG module has been processed, build a launcher
896 and a metadata section for each built kernel. */
897 for (size_t i
= 0; i
< m_kernels
.size (); ++i
)
899 brig_function
*f
= m_kernels
[i
];
901 /* Finish kernels now that we know the call graphs and their barrier
905 dump_function (m_dump_file
, f
);
906 gimplify_function_tree (f
->m_func_decl
);
907 cgraph_node::finalize_function (f
->m_func_decl
, true);
909 f
->m_descriptor
.is_kernel
= 1;
910 /* TODO: analyze the kernel's actual private and group segment usage
911 using call graph. Now the mem size is overly
912 pessimistic in case of multiple kernels in the same module.
914 f
->m_descriptor
.group_segment_size
= m_total_group_segment_usage
;
915 f
->m_descriptor
.private_segment_size
= private_segment_size ();
917 /* The kernarg size is rounded up to a multiple of 16 according to
919 f
->m_descriptor
.kernarg_segment_size
= f
->m_next_kernarg_offset
;
920 if (f
->m_descriptor
.kernarg_segment_size
% 16 > 0)
921 f
->m_descriptor
.kernarg_segment_size
922 += 16 - f
->m_next_kernarg_offset
% 16;
923 f
->m_descriptor
.kernarg_max_align
= f
->m_kernarg_max_align
;
925 tree launcher
= f
->emit_launcher_and_metadata ();
927 append_global (launcher
);
931 std::string kern_name
= f
->m_name
.substr (1);
932 fprintf (m_dump_file
, "\n;; Function %s", kern_name
.c_str());
933 fprintf (m_dump_file
, "\n;; enabled by -%s\n\n",
934 dump_flag_name (TDI_original
));
935 print_generic_decl (m_dump_file
, launcher
, TDF_NONE
);
936 print_generic_expr (m_dump_file
, DECL_SAVED_TREE (launcher
),
938 fprintf (m_dump_file
, "\n");
941 gimplify_function_tree (launcher
);
942 cgraph_node::finalize_function (launcher
, true);
946 int no_globals
= list_length (m_globals
);
947 tree
*vec
= new tree
[no_globals
];
950 tree global
= m_globals
;
955 global
= TREE_CHAIN (global
);
958 wrapup_global_declarations (vec
, no_globals
);
964 /* Returns an type with unsigned int elements corresponding to the
965 size and element count of ORIGINAL_TYPE. */
968 get_unsigned_int_type (tree original_type
)
970 if (VECTOR_TYPE_P (original_type
))
973 = int_size_in_bytes (TREE_TYPE (original_type
)) * BITS_PER_UNIT
;
974 poly_uint64 ecount
= TYPE_VECTOR_SUBPARTS (original_type
);
975 return build_vector_type (build_nonstandard_integer_type (esize
, true),
979 return build_nonstandard_integer_type (int_size_in_bytes (original_type
)
984 /* Returns a type with unsigned int corresponding to the size
988 get_scalar_unsigned_int_type (tree original_type
)
990 return build_nonstandard_integer_type (int_size_in_bytes (original_type
)
991 * BITS_PER_UNIT
, true);
994 /* Set the declaration externally visible so it won't get removed by
995 whole program optimizations. */
998 set_externally_visible (tree decl
)
1000 if (!lookup_attribute ("externally_visible", DECL_ATTRIBUTES (decl
)))
1001 DECL_ATTRIBUTES (decl
) = tree_cons (get_identifier ("externally_visible"),
1002 NULL
, DECL_ATTRIBUTES (decl
));
1006 set_inline (tree decl
)
1008 if (!lookup_attribute ("inline", DECL_ATTRIBUTES (decl
)))
1009 DECL_ATTRIBUTES (decl
) = tree_cons (get_identifier ("inline"),
1010 NULL
, DECL_ATTRIBUTES (decl
));
1014 dump_function (FILE *dump_file
, brig_function
*f
)
1016 /* Dump the BRIG-specific tree IR. */
1019 fprintf (dump_file
, "\n;; Function %s", f
->m_name
.c_str ());
1020 fprintf (dump_file
, "\n;; enabled by -%s\n\n",
1021 dump_flag_name (TDI_original
));
1022 print_generic_decl (dump_file
, f
->m_func_decl
, TDF_NONE
);
1023 print_generic_expr (dump_file
, f
->m_current_bind_expr
, TDF_NONE
);
1024 fprintf (dump_file
, "\n");
1028 /* Records use of the BRIG_REG as a TYPE in the current function. */
1031 brig_to_generic::add_reg_used_as_type (const BrigOperandRegister
&brig_reg
,
1036 = m_fn_regs_use_index
[m_cf
->m_name
][gccbrig_hsa_reg_id (brig_reg
)];
1038 if (info
.m_type_refs_lookup
.count (type
))
1039 info
.m_type_refs
[info
.m_type_refs_lookup
[type
]].second
++;
1042 info
.m_type_refs
.push_back (std::make_pair (type
, 1));
1043 info
.m_type_refs_lookup
[type
] = info
.m_type_refs
.size () - 1;