Mercurial > hg > CbC > CbC_gcc
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 *) (§ion_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, ©_move_inst_handler}, | |
318 {BRIG_KIND_INST_SOURCE_TYPE, ©_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 } |